Himpunan unik di Python

Sebelum ini, saya sempat menulis tentang cara membuat fungsi pembanding sendiri untuk keperluan pembuatan himpunan unik. Singkatnya, di bahasa Java, Scala, dan mungkin bahasa lain yang jalan di atas JVM, kita perlu mengimplementasikan ulang method hashCode dan equals. Setelah menulis itu, saya sempat berpikir bagaimana cara melakukannya di Python?

Yang ingin saya lakukan adalah jika saya memiliki beberapa objek penampung nilai, saya ingin membuat mereka unik (katakanlah dengan memasukkannya ke dalam set). Jadi jika ada lebih dari satu objek yang bernilai sama, hanya satu di antara mereka saja yang diambil. Sisanya bisa dibuang karena saya tidak memerlukannya.

Katakanlah saya memiliki kelas seperti berikut.

class M(object):
    def __init__(self, posisi, asam_amino):
        self.posisi = posisi
        self.asam_amino = asam_amino

    def __repr__(self):
        return "%s%s" % (self.posisi, self.asam_amino)

Lalu saya membuat beberapa objek dari kelas tersebut.

mutasi = [ M(1, "a"), M(2, "b"), M(1, "c"), M(3, "b"), M(1, "a") ]

Mari kita coba panggil fungsi set

>>> print mutasi
[1a, 2b, 1c, 3b, 1a]
>>> print set(mutasi)
set([3b, 1c, 1a, 1a, 2b])

Seperti yang sudah diduga, fungsi set belum berhasil menghapus nilai ganda.

Setelah ngubek2 sana sini, ternyata di Python kita juga harus mengimplementasikan dua buah method yang sama (versi Python tentunya)! Kedua method tersebut adalah __eq__ dan __hash__. Kedua method ini dapat diimplementasikan ulang seperti berikut.

    def __eq__(self, o):
        if not isinstance(o, M):
            return False
        return self.posisi == o.posisi \
               and self.asam_amino == o.asam_amino

    def __hash__(self):
        return hash((self.posisi, self.asam_amino))

Mari kita coba lagi sekarang.

>>> mutasi = [ M(1, "a"), M(2, "b"), M(1, "c"), M(3, "b"), M(1, "a") ]
>>> print mutasi
[1a, 2b, 1c, 3b, 1a]
>>> print set(mutasi)
set([1c, 1a, 2b, 3b])

Klopt!

Kode lengkap dapat dilihat di https://gist.github.com/fajran/5744836

Himpunan unik di Scala

Katakanlah saya memiliki sebuah List dari angka seperti berikut

val list = List(1, 2, 3, 4, 2, 3, 4)

Jika saya ingin membuatnya tidak berisi angka berulang, saya bisa panggil method distinct dari List tersebut.

scala> val list = List(1, 2, 3, 4, 2, 3, 4)
list: List[Int] = List(1, 2, 3, 4, 2, 3, 4)

scala> list.distinct
res1: List[Int] = List(1, 2, 3, 4)

Nah bagaimana jika isi List adalah objek dari kelas buatan sendiri?

Pertama, mari kita coba gunakan case class. Katakanlah saya butuh menyimpan dua buah nilai yaitu posisi: Int dan asamAmino: String yang menyatakan sebuah mutasi gen seperti berikut.

case class M1(val posisi: Int, val asamAmino: String)

Mari kita uji apakah distinct bisa bekerja sesuai harapan.

scala> case class M1(val posisi: Int, val asamAmino: String)
defined class M1

scala> val list = List(M1(1, "a"), M1(2, "b"), M1(1, "c"), M1(3, "b"), M1(1, "a"))
list: List[M1] = List(M1(1,a), M1(2,b), M1(1,c), M1(3,b), M1(1,a))

scala> list.distinct
res2: List[M1] = List(M1(1,a), M1(2,b), M1(1,c), M1(3,b))

Terlihat masih oke.. Bagaimana kalau pakai class biasa?

scala> class M2(val posisi: Int, val asamAmino: String) {
     | override def toString() = "%d%s".format(posisi, asamAmino)
     | }
defined class M2

scala> val list = List(new M2(1, "a"), new M2(2, "b"), new M2(1, "c"), new M2(3, "b"), new M2(1, "a"))
list: List[M2] = List(1a, 2b, 1c, 3b, 1a)

scala> list.distinct
res3: List[M2] = List(1a, 2b, 1c, 3b, 1a)

Wah tidak bekerja sesuai harapan ternyata 🙁 Mutasi 1a masih berjumlah ganda. Mungkin karena si Scala atau Java tidak tahu cara mengecek dengan benar apakah dua buah objek M2 itu bernilai sama atau tidak. Kalau yang dibandingkan hanyalah alamat memori, tentu saja akan berbeda semua.

Setelah ngubek2 internet, akhirnya saya mendapatkan sebuah petunjuk di StackOverflow.com. Pada saat pengecekan kesamaan nilai, Scala menggunakan dua buah method untuk mencari tahu apakah dua buah objek bernilai sama atau tidak. Dua method tersebut adalah hashCode dan equals. Nilai hashCode akan dibandingkan terlebih dahulu dan jika sama, maka method equals akan dipanggil agar si objek membandingkan sendiri dengan objek lain apakah mereka bernilai sama atau tidak.

Berbekal dari informasi tersebut, kita bisa ubah si kelas M2 menjadi seperti berikut.

class M3(val posisi: Int, val asamAmino: String) {
  override def toString() = "%d%s".format(posisi, asamAmino)

  override def hashCode = posisi

  override def equals(other: Any) =
    if (other.isInstanceOf[M3]) {
      val m = other.asInstanceOf[M3]
      m.posisi == posisi && m.asamAmino == asamAmino
    } else false
}

Untuk hashCode, agar sederhana saya samakan saja nilainya dengan nilai posisi. Pada saat pemangilan equals, nilai posisi dan asamAmino akan dibandingkan untuk memutuskan apakah dua buah mutasi bernilai sama atau tidak.

Mari kita coba lagi..

scala> val list = List(new M3(1, "a"), new M3(2, "b"), new M3(1, "c"), new M3(3, "b"), new M3(1, "a"))
list: List[M3] = List(1a, 2b, 1c, 3b, 1a)

scala> list.distinct
res0: List[M3] = List(1a, 2b, 1c, 3b)

Hore berhasil!

Mengapa saya ngga memakai case class saja sehingga tidak perlu repot2 mengimplementasikan hashCode dan equals? Karena dalam kasus yang saya hadapi, kelas mutasi ini berada dalam wilayah bahasa Java! Yap, saya sedang mencampur2 kode Java dan Scala.

Mari kita ubah si kelas mutasi menjadi bahasa Java lalu digunakan dari Scala.

public class M4 {
  private int posisi;
  private String asamAmino;

  public M4(int posisi, String asamAmino) {
    this.posisi = posisi;
    this.asamAmino = asamAmino;
  }

  public int getPosisi() {
    return posisi;
  }

  public String getAsamAmino() {
    return asamAmino;
  }

  @Override
  public int hashCode() {
    return posisi;
  }

  @Override
  public boolean equals(Object other) {
    if (other instanceof M4) {
      M4 m = (M4)other;
      return posisi == m.getPosisi() && asamAmino.equals(m.getAsamAmino());
    }
    return false;
  }

  @Override
  public String toString() {
    return posisi + asamAmino;
  }
}

Wah kodenya jadi bengkak ya? 😀 Silakan lihat kode lengkap dapat dilihat di https://gist.github.com/fajran/5718827

Log of Debian/Ubuntu packages

I have a plan to do a little research about packages in Debian and/or Ubuntu repositories. For this, I think I need a preferably complete log of packages that coming in and out of the repositories.

A friend of mine pointed me the following two mailing list archives where Debian and Ubuntu seem to be logging the packages.

If somebody knows the other sources, or if the above sources are unsuitable for the purpose I am looking for, please let me know 🙂

Alur aplikasi OpenGL (dan WebGL?)

Aplikasi OpenGL (dan sepertinya aplikasi berbasis grafis lainnya) memiliki sebuah alur kerja yang bisa saya bilang cukup standar. Dimulai dengan melakukan persiapan, lalu ada sebuah perulangan utama, dan diakhiri dengan rutin bersih-bersih sebelum aplikasi selesai dieksekusi. Pada perulangan utama ini, operasi yang terjadi secara umum bisa dikelompokkan menjadi tiga: baca input (mouse, keyboard, dll), proses, dan gambar.

Main Loop

Pada tahapan membaca input, seluruh masukan dari keyboard, mouse, dan sumber lainnya akan ditangkap dan digunakan untuk mengubah kondisi yang sedang dipantau. Misalnya jika tombol spasi ditekan, maka si aplikasi harus membuat pesawat dalam game mengeluarkan tembakan.

Setelah ini, semua pemrosesan akan dilakukan. Misalnya peluru yang ditembakkan mesti sampai di pojok kanan atas layar dalam waktu 1 detik. Maka perlu dihitung dimana dan kapan saja gambar peluru harus diletakkan di layar.

Pada tahapan menggambar, gambar peluru yang telah dibaca dari berkas akan disalin ke layar. Gambar akan diletakkan pada posisi yang telah dihitung sebelumnya. Begitu pula untuk objek-objek lain yang perlu digambar di layar.

Seberapa cepat perulangan utama yang menjalankan 3 tahapan di atas ini harus dijalankan? Dengan kata lain, berapa gambar yang harus dibuat setiap detiknya? Semakin banyak gambar yang dibuat setiap detiknya, akan semakin halus pergerakan animasi yang dibuat. Namun dengan demikian, proses yang dikerjakan tidak boleh berlangsung terlalu lama karena tentunya dapat menunda tahapan menggambar yang efeknya akan mengurangi jumlah gambar yang dibuat tiap detiknya.

Monitor yang ada sekarang umumnya dapat menggambar 60 kali setiap detiknya (60 frame per second atau 60 Hz). Bagaimana kalau kita targetkan agar aplikasi dapat mengikuti kecepatan monitor? Mari kita hitung. Jika dalam 1 detik kita harus menggambar 60 gambar, berarti 1 gambar harus dibuat dalam waktu 1/60 detik atau sekitar 16 milidetik (16 ms)! Membaca input, melakukan pemrosesan data, dan menggambar semuanya harus terjadi dalam waktu 16ms saja agar kita bisa meraih kecepatan menggambar 60 gambar per detik!

Apakah 60 fps adalah angka yang harus selalu dicapai? Tergantung.. semakin cepat, animasi akan semakin halus. Namun jika aplikasi yang kita buat tidak sering menampilkan aplikasi, maka batasan kecepatan penggambaran ini bisa kita perlonggar. Tuk perbandingan, film umumnya hanya memiliki 24 gambar setiap detiknya alias 24 fps.

Memulai WebGL

Setelah sebelumnya kita berkenalan sedikit dengan WebGL, mari kita mulai membuat aplikasi WebGL. Pastikan dulu browser yang Anda gunakan mendukung WebGL agar Anda dapat melihat hasil yang diharapkan.

Jika semua sudah siap, mari kita buka teks editor dan masukkan kode berikut ini.

<canvas id="canvas" width="640" height="480">WebGL tidak didukung</canvas>

Kode di atas akan membuat sebuah area gambar yang akan dijadikan tempat menggambar gambar 3 dimensi dengan WebGL.

Persiapan dari sisi HTML sudah cukup, sekarang mari beralih ke dunia Javascript untuk mengendalikan WebGL.

Pertama, dapatkan referensi ke area gambar <canvas> yang kita buat sebelumnya.

<script type="text/javascript">

var canvas = document.getElementById('canvas');

Setelah itu, ambil pengendali WebGL dari area gambar tadi.

var gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');

Mengapa mencoba mengambil dua hal berbeda (webgl dan experimental-webgl)? Sampai saat ini, WebGL masih bersifat eksperimental sehingga beberapa browser masih belum menjadikannya hal yang “udah pasti ada”. Maka dari itu, browser2 ini menggunakan nama experimental-webgl sebagai identifikasi pengendali WebGL.

Nilai yang dihasilkan dapat kita gunakan untuk mengecek apakah browser yang dipakai mendukung WebGL atau tidak.

if (!gl) {
  alert('WebGL tidak didukung');
}

Jika nilai keluaran tidak dievaluasi menjadi true, maka bisa diambil kesimpulan si browser tidak mendukung WebGL.

Setelah mendapatkan referensi ke pengendali WebGL, kita sudah bisa memanggil fungsi-fungsi WebGL. Sebagai contoh, fungsi untuk menghapus area gambar dengan warna tertentu.

if (gl) {
  // hapus layar
  gl.clearColor(1.0, 0.5, 0.0, 1.0); // warna oranye
  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
}

</script>

Jika sukses, area gambar yang dibuat seharusnya akan berwarna oranye seperti berikut.

Memulai WebGL

Selamat, aplikasi WebGL super sederhana sudah jadi! 😀

Kode lengkap dari tutorial kali ini dapat dilihat di http://fajran.github.io/webgl-tutorial/01-memulai-webgl/index.html. Seluruh kode sumber tutorial WebGL ini akan tersedia di https://github.com/fajran/webgl-tutorial.

Pengenalan WebGL

Mari kita mulai ngoprek2 WebGL 😀 Mudah2an ini beneran menjadi satu set tutorial xD

Apa itu WebGL? Singkatnya WebGL adalah OpenGL yang hidup di dalam browser. OpenGL sendiri adalah satu set API yang dapat dipakai untuk membuat gambar 3 dimensi (termasuk juga 2 dimensi). Proses penggambaran yang menggunakan OpenGL biasanya akan “dibantu” dengan perangkat keras grafis (GPU) sehingga prosesnya akan jauh lebih cepat.

Kalau OpenGL aslinya adalah satu set API untuk bahasa C, maka WebGL, berhubung dia hidup di dalam browser, adalah API untuk Javascript. WebGL ini merupakan kelanjutan dari Canvas API yang hanya menyediakan fasilitas menggambar gambar 2 dimensi.

Sampai saat ini, belum semua browser mendukung WebGL. Dukungan yang disediakan juga sering bergantung dengan GPU dan driver yang dipakai. Hal ini tidak selalu berarti pengguna GPU tipe lama tidak bisa menikmati WebGL karena implementasi prosedur gambar 3 dimensi bisa saja dilakukan tanpa bantuan perangkat keras, walau efeknya proses akan berjalan lebih lambat. Pendekatan ini diambil oleh Chromium/Google Chrome yang juga menyediakan implementasi WebGL yang hanya menggunakan peranti lunak.

Untuk mencari tahu apakah browser yang Anda pakai saat ini dapat menampilkan WebGL atau tidak, kunjungi saja halaman berikut ini.

http://get.webgl.org/

Jika WebGL didukung, Anda akan menjumpai tampilan seperti berikut. Perhatikan juga ada sebuah animasi kubus berputar di halaman tersebut.

Screen Shot 2013-05-28 at 8.32.57 PM

Apakah browser yang Anda gunakan mendukung WebGL?

Backup Blog

Selain menggabung sekian blog jadi satu, kemarin saya juga memindahkan tempat si blog berada. Sebelumnya, 3 dari 4 blog yang saya gabung ada di Dreamhost namun blog ini ada di sebuah VPS mungil murah meriah 😀 Satu hal yang jujur saja saya khawatirkan adalah masalah realibilitas dari si VPS sehingga kali ini saya memikirkan mengenai backup. Sebelumnya saya cukup percaya sama om Google dan Dreamhost tuk menjaga data saya.

Setelah memikirkan beberapa strategi backup, akhirnya saya memilih tuk membackup data saya ke layanan lain yang mudah2an bisa saya percayai: BitBucket! 😀

Ada dua hal dari blog ini yang saya rasa perlu saya backup: database yang dipakai dan juga instalasi WordPress (termasuk berkas-berkas yang saya upload via WordPress). Strategi backup saya adalah dengan memasukkan semuanya ke dalam repositori Git dan mengirimnya ke BitBucket. Untung saja BitBucket menyediakan repositori privat yang gratis dan dapat memiliki kapasitas tak terbatas. Klop!

Strategi sudah dipilih, sekarang saatnya membuat langkah konkrit. Untuk database, saya dapat menjalankan mysqldump agar isi database disimpan ke berkas. Saya juga menggunakan opsi --skip-extended-insert agar satu buah record ditulis menjadi satu baris. Andai opsi ini tidak dimasukkan, maka satu baris dalam berkas SQL yang dihasilkan dapat mengandung banyak data sekaligus. Dengan membuat satu entry satu baris, ukuran berkas SQL yang dihasilkan memang bertambah besar namun Git akan dapat melacak perubahan dengan lebih efisien. Untuk berkas instalasi, tidak ada perlakuan khusus agar Git dapat memasukkan semuanya dengan baik.

Setelah coba-coba, inilah kira2 skrip yang saya pakai. Saya jalankan skrip berikut di direktori induk dari direktori instalasi WordPress, secara berkala melalui crontab.

#!/bin/sh

set -x

cd `dirname $0`

mysqldump -h HOST -u USER --password=PASSWORD \
          --skip-extended-insert DATABASE > data.sql

git add data.sql
git commit -m "Database backup"

git add www
git commit -m "WordPress backup"

git push origin master

Tentunya sebelum ini saya sudah persiapkan direktori kerja lokal Git dan juga repositori Git di BitBucket. Kunci SSH tanpa password juga saya gunakan agar operasi push dapat bekerja di belakang layar.

Blogger to WordPress

When I merged all of my scattered blogs few days ago, I tried to import my blog posts from Blogger to this WordPress installation. My first shot was to use WordPress’ own Blogger Importer but apparently the result was not so good (I think). Some texts were garbled and gone. For example, the iframe tag from SoundCloud in my post about OS X’ Text-To-Speech “Improvisation” was eaten by either the converter script or WordPress. Either way, it didn’t work flawlessly and I had to find out another way to export the posts.

Then I realized that Blogger provides a tool to download all of our blog posts, including comments (and I assume the pages as well, but I didn’t test it since I don’t have pages). I tried this out and got a machine readable XML file. Wohoo!

WordPress has it’s own way to do data migration between WordPress blogs. The good thing is it’s also an XML file! If somehow I can convert the XML file from Blogger to the one that WordPress uses, everything should be set 😀

A couple hours later, I got this very simple converter script. It may not be efficient and it also has several hardcoded values (check the categories part) but it suits what I wanted 😀

https://gist.github.com/fajran/5659455

Have fun!