Longest Common Subsequence (LCS)


Dalam aplikasi biologi sering diperlukan pembandingan DNA dari dua (atau lebih) organisme yang berbeda. Seuntai DNA terdiri dari serangkaian molekul yang disebut basis. Basis yang mungkin adalah adenin, guanin, citosin, dan timin. Keempat basis DNA ini dapat dituliskan dengan notasi huruf {A, C, G, T}.

Contoh, DNA suatu organisme misalnya S1 = ACCGGTCGAGTGCGCGGAAGCCGGCCGAA, dan DNA untuk organisme lain  misalnya S2 = GTCGTTCGGAATGCCGTTGCTCTGTAAA. Salah satu alasan membandingkan untaian dua DNA ini adalah untuk menentukan “kemiripan” kedua untaian tersebut sebagai ukuran kedekatan antara kedua organisme tersebut.

Untuk mengukur kemiripan untaian S1 dan S2 adalah dengan menemukan untaian ketiga yaitu S3 sebagai untaian terpanjang dari kedua untaian, dimana basis di S3 muncul di setiap S1 dan S2. Semakin panjang untaian S3 yang ditemukan maka S1 dan S2 semakin mirip.

S1 = ACCGGTCGAGTGCGCGGAAGCCGGCCGAA

S2 = GTCGTTCGGAATGCCGTTGCTCTGTAAA

S3 = GTCGTCGGAAGCCGGCCGAA

Masalah kemiripan ini dikenal dengan istilah subsekuens bersama terpanjang (Longest Common Subsequence (LCS)). Algoritma untuk LCS telah dipelajari untuk waktu yang lama dan sekarang telah menjadi bagian penting dari ilmu komputer. Aplikasinya dipakai secara luas, tidak hanya terbatas pada lingkup ilmu komputer seperti pengenalan pola (Lu dan Fu 1978), namun juga di bidang biologi seperti yang sudah dipaparkan sebelumnya.

Definisi LCS

Subsekuens string X adalah sekumpulan karakter yang ada pada X yang urutan kemunculannya sama. Secara formal dapat didefinisikan sebagai berikut: sekuens Z = ⟨z1, z2, … , zk⟩ adalah subsekuens dari X = ⟨x1, x2, … , xm⟩, jika terdapat urutan menaik ⟨i1, i2, … , ik⟩ yang merupakan indeks X untuk semua j = 1, 2, 3, … , k, yang memenuhi xi j = zj. Contoh, Z = ⟨B, C, D, B⟩ adalah subsekuens dari X = ⟨A, B, C, B, D, A, B⟩, dengan sekuens indeks ⟨2, 3, 5, 7⟩.

Subsekuens bersama dari dua sekuens adalah subsekuens yang terdapat pada kedua sekuens tersebut. Misal X = ⟨A, B, C, B, D, A, B⟩ dan Y = ⟨B, D, C, A, B, A⟩, maka sekuens ⟨B, C, A⟩ adalah  subsekuens bersama dari X dan Y. Tetapi bukan merupakan sekuens bersama terpanjang (LCS) dari X dan Y karena panjang sekuens 3, karena masih terdapat sekuens ⟨B, C, B, A⟩ dengan panjang 4. ⟨B, C, B, A⟩ adalah subsekuens bersama terpanjang antara X dan Y, karena tidak ada lagi subsekuens bersama yang panjangnya 5.

Pada masalah subsekuen bersama terpanjang (LCS), diberikan dua sekuens X = ⟨x1, x2, … , xm⟩  dan Y = ⟨y1, y2, … , yn⟩ dan bermaksud untuk menemukan panjang maksimum dari subsekuens terpanjang X dan Y. Tulisan ini menunjukkan bagaimana cara menyelesaikan masalah LCS  secara efisien dengan menggunakan pemrograman dinamis.

Metode Brute Force

Salah satu pendekatan untuk memecahkan masalah LCS adalah brute force. Semua subsekuens X akan dibangkitkan dan masing-masing subsekuens akan diperiksa apakah subsekuens tersebut juga merupakan subsekuens dari Y.

Langkah-langkah brute force:

  1. Bangkitkan semua subsekuens untuk Xm dan Yn
  2. Cari sekuens yang sama
  3. Ambil yang terpanjang

Contoh:

Xm = ⟨A, T, G

Yn = ⟨T, C, G

Bangkitkan semua subsekuens Xm:

X0 = ⟨ ⟩

X1 = ⟨A⟩, ⟨T⟩, ⟨G

X2 = ⟨A, T⟩, ⟨T, G⟩, ⟨A, G

X3 = ⟨A, T, G⟩                           … diperoleh 23 = 8 subsekuens

Bangkitkan semua subsekuens Yn:

Y0 = ⟨ ⟩

Y1 = ⟨T⟩, ⟨C⟩, ⟨G

Y2 = ⟨T, C⟩, ⟨C, G⟩, ⟨T, G

Y3 = ⟨T, C, G⟩                           … diperoleh 23 = 8 subsekuens

Cari sekuens bersama Xm dan Y:

⟨ ⟩, ⟨T⟩, ⟨G⟩, ⟨T, G⟩                            … dilakukan (maksimal) 4!/2!2 = 20 perbandingan

Pilih sekuens bersama terpanjang (LCS) Xm dan Yn:

T, G⟩                                                    … dilakukan (maksimal) 23 = 8 kali

Kompleksitas worst-case untuk penyelesaian masalah LCS dengan brute force, dengan asumsi m = n adalah:

T(n)      = Tgenerate_subsequence_X + Tgenerate_subsequence_Y + Tfind_common_subsequence + Tfind_longest_common_subsequence

= 2n + 2n + (2n)!/n!2 + 2n

= 3.2n + (2n)!/n!2                      … 4n/(n+1)  ≤  (2n)!/n!2  ≤  4n, untuk n < 1

= O(4n)

Teorema Substruktur Optimal

Misalnya X = ⟨x1, x2, … , xm⟩  dan Y = ⟨y1, y2, … , yn⟩ adalah sekuens, dan Z = ⟨z1, z2, … , zk⟩ adalah suatu LCS dari X dan Y.

  1. Jika xm = yn, maka zk = xm = yn dan Zk-1 adalah suatu LCS dari Xm-1 dan Yn-1.
  2. Jika xmyn, maka zkxm mengimplikasikan bahwa Z adalah suatu LCS dari Xm-1 dan Y
  3. Jika xmyn, maka zkyn mengimplikasikan bahwa Z adalah suatu LCS dari X dan Yn-1

Metode Rekursif

Jika akan menguji satu atau dua subproblem dimana terdapat suatu LCS dari X = ⟨x1, x2, … , xm⟩  dan Y = ⟨y1, y2, … , yn⟩. Jika  xm = yn ,perlu menemukan LCS dari Xm-1 dan Yn-1. Dengan melampirkan xm = yn pada LCS ini dengan menemukan LCS dari X dan Y. jika xmyn, kemudian harus memecahkan 2 subproblem yaitu mendapatkan sebuah LCS dari xm-1 dan Y dan LCS dari X dan yn-1. Mana saja dari LCS yang lebih panjang adalah LCS dari X dan Y. karena kasus ini menyeleksi semua kemungkinan, maka solusi subproblem yang optimum harus ada sebagai sebuah LCS dari X dan Y.

Untuk menemukan LCS dari X dan Y, harus mendapat LCS dari x dan yn-1 dan xm-1 dan y. tetapi setiap masalah subproblem ini mempunyai masalah dalam menemukan LCS dari xm-1 dan yn-1. Banyak lagi subproblem yang lain yang terdiri dari bagian subroblem lainnya.

Seperti masalah rantai matrik multiplikatif, solusi recursive LCS meliputi menetapkan pengulangan dari solusi yang optimum. Contoh  ini definisikan  c[i, j] adalah panjang LCS pada barisan deret xi dan  yi. Jika kedua i=0 atau j=0, satu dari deret memiliki panjang 0, maka LCS mempunyai panjang 0

Perhatikan rumus rekursif berikut, suatu kondisi masalah membatasi subproblem yang sedang di pertimbangkan. Ketika xi dan yi harus mempertimbangkan subproblem yang menemukan suatu LCS dari xi-1 dan yn-1. Jika tidak, cari  dua subproblem menemukan suatu LCS dari xi dan yi-1  dan dari xi-1 dan yi. Dalam menemukan sebuah LCS bukan hanya algoritma pemrograman dinamis yang mengabaikan subproblem berdasarkan kondisi pada masalah.

LCS Rec (𝑋𝑚,, 𝑌𝑛,)
If 𝑋𝑚, = 𝑌𝑛,
Z = (LCS Rec (𝑋𝑚−1,, 𝑌𝑛−1,), 𝑍𝑘,)
Maxlenght (LCS Rec ( 𝑋𝑚−1,,Y)), or (LCS Rec (X, 𝑌𝑛−1,))

Metode Pemrograman Dinamis

Dari persamaan di atas, dapat dibuat algoritme rekursif dengan waktu eksponensial untuk menghitung panjang sebuah LCS dari dua sekuens. Karena masalah LCS hanya memiliki Θ(mn) sub-masalah berbeda, kita dapat menggunakan pemrograman dinamis untuk menghitung solusi secara bottom up.

Prosedur LCS-Length mengambil dua sekuens X = ⟨x1, x2, … , xm⟩  dan Y = ⟨y1, y2, … , yn⟩ sebagai masukan. Nilai c[i, j] disimpan dalam tabel c[0…m, 0…n], dan menghitung isinya dalam urutan baris. (Prosedur mengisi baris pertama c dari kiri ke kanan, kemudian baris kedua, dan seterusnya.) Prosedur juga menyimpan tabel b[1…m, 1…n] untuk membantu dalam konstruksi solusi optimal. Tentu saja, b[i, j] menunjuk pada isi tabel yang bersesuaian dengan solusi sub-masalah optimal  yang dipilih saat menghitung c[i, j]. Prosedur mengembalikan tabel b dan c; dengan c[m, n] berisi panjang LCS dari X dan Y.

LCS-Length (X, Y)

m = X.length

n = Y.length

let b[1…m, 1…n] and c[0…m, 0…n] be new tables

for i = 1 to m

c[i, 0] = 0

for j = 1 to n

c[0, j] = 0

for i = 1 to m

           for j = 1 to n

                  if xi == yj

                 c[i, j] = c[i – 1, j – 1] + 1

                 b[i, j] = “↖”

                  elseif c[i – 1, j] ≥ c[i, j – 1]

                  c[i, j] = c[i – 1, j]

                  b[i, j] = “↑”

                 else

                c[i, j] = c[i, j – 1]

                b[i, j] = “←”

return c and b

Gambar 1 menunjukkan tabel yang dihasilkan oleh LCS-Length untuk sekuens X = ⟨A, B, C, B, D, A, B⟩ dan Y = ⟨B, D, C, A, B⟩. Waktu eksekusi prosedur ini adalah Θ(mn), karena setiap isi tabel membutuhkan waktu Θ(1) untuk menghitungnya.

Konstruksi LCS

Tabel b yang dikembalikan oleh LCS-Length membuat kita lebih cepat dalam mengkonstruksi sebuah LCS dari X = ⟨x1, x2, … , xm⟩  dan Y = ⟨y1, y2, … , yn⟩. Kita mulai dari b[m, n] dan menelusuri tabel dengan mengikuti arah panah. Setiap kita temui tanda “↖” pada isi b[i, j], itu artinya bahwa xi = yj adalah elemen LCS yang ditemukan oleh LCS-Length. Dengan metode ini, kita temukan elemen-elemen LCS dalam urutan terbalik. Prosedur rekursif berikut ini mencetak LCS dari X dan Y dalam urutan yang benar. Pemanggilan pertama ialah Print-LCS(b, X, X.length, Y.length).

Print-LCS(b, X, i, j)

if i == 0 or j == 0

return

if b[i, j] == “↖”

Print-LCS(b, X, i – 1, j – 1)

print xi

elseif b[i, j] == “↑”

Print-LCS(b, X, i – 1, j)

else

Print-LCS(b, X, i , j – 1)

Untuk tabel b pada Gambar 1, prosedur ini akan mencetak BCBA. Prosedur ini memakan waktu O(m + n), karena salah satu i atau j akan berkurang pada tiap panggilan rekursif.

Cormen, Thomas H. Introduction to Algorithm Third Edition. MIT Press, United States of America. 2009.

S. Lu and K. Fu, A sentence-to-sentence clustering procedure for pattern analysis, Transactions on Systems, Man, and Cybernetics, 8 (1978), 381-389.

Satu pemikiran pada “Longest Common Subsequence (LCS)

Tinggalkan komentar