Contoh Aplikasi Graph Traversal - Map Route (GPS) |
Dimulai dari user-defined root = "a", kemudian traverse sesuai urutan node: berarti b, kemudian terus maju sesuai urutan node: d, dan seterusnya sampai h. Karena di h mentok, lalu "backtrack" ke f, tapi di f tidak ada lagi edge yang bisa di tambahkan, kemudian backtrack lagi ke e, kemudian terakhir tambahkan g.
Mudah sekali kan? ... Ok, kalau sudah mengerti sekarang coba Agan coba sendiri dulu aplikasi NetworkX-nya. Kalau perlu refresh lagi pengetahuan dari post sebelumnya ini. Agan boleh search ke internet for clues (tapi ga boleh ke blog dan github saya). Coba selesaikan masing-masing (DFS & BFS) dalam waktu <30 menit (total 1 jam). Inputnya graph diatas, outputnya gambar graph spanning tree seperti di atas. If you can please let me know in the comment. Catt: nope, agan ga dapet makan siang gratis ... ?? ... saya penasaran aja ...
... Asumsi pembaca lagi ngerjain ....
~
... masih juga berasumsi yang sama ....
~
... Ceritanya masih nungguin ...
~
Ok... mari kita bahas contoh solusinya. Seperti biasa, saya akan berikan code yang tidak/kurang efisien. Saya mengharapkan Agan bisa latihan untuk meng-efisienkan code tersebut. Seperti yang dijelaskan disini, algoritma & program yang efisien sangat penting di Data Science/Big Data.
Code lengkap berikut ini saya letakkan di GitHub saya ini, dan nama filenya "BFS_NetworkX.py" dan "DFS_NetworkX.py" dengan file pendukung "my_NetworkX_lib.py" supaya BFS dan DFS-nya ndak keriting. Ok, berikut penjelasannya:
1. Menyiapkan graph awalnya:
import networkx as nx from my_NetworkX_lib import buildGraph, drawGraph # ini berdasarkan post networkX saya sebelumnya. V = ['a', 'b', 'c', 'd' , 'e', 'f', 'g', 'h'] # Untuk memudahkan kita asumsikan urutan di V ini = urutan nodes di soal. E = [('a','b'),('a','c'),('a','g'),('a','g'),('b','d'),('b','g'),('c','d'),('c','e'),('d','f'),('e','f'),('e','f'),('f','h'),('g','e')] G = buildGraph(V, E=E) # Graph di soal root = V[0] # Asumsi root = "a"Untuk bagian ini tidak perlu penjelasan, karena sudah dibahas di post sebelumnya. Bedanya hanya sekarang kita tidak punya weight di edges-nya (lebih simple/sederhana).
2. Solusi BFS:
Levels = [[root]] Vtemp = [root] # Mulai dengan mencari informasi nodes di setiap level [belum efisien] for v in V: e = G.edges(v) e = [v2 for v1,v2 in e if v2 not in Vtemp] if e: Levels.append(e) Vtemp = Vtemp + e # Mulai membangun Spanning Tree-nya BFS = buildGraph(V) for vertices in Levels: for v in vertices: e = G.edges(v) # Semua edges yang adjacent ke node v for v1, v2 in e: BFS.add_edge(v1,v2) if len(nx.cycle_basis(BFS,root))>0: BFS.remove_edge(v1,v2)
Algoritmanya simple: pertama-tama cari tau dulu ada nodes apa saja di setiap level. Kemudian tambahkan edges ke BFS sesuai dengan level tersebut. Informasinya di simpan dalam variable "Levels", jadi Levels adalah "list of lists" (i.e. Levels = [['a'], ['b','c','g'], ... dst]). Variable "Vtemp" digunakan supaya kita tidak traverse ke level di atasnya.
That's it!.... Bagian kedua program ini mirip dengan kasus Greedy kemarin. Menambahkan edge ke BFS selama tidak menimbulkan cycle. O iya, ada satu yang baru, yaitu perintah "G.edges(v)" yang akan menghasilkan (v,v2) untuk semua v2 yang adjacent/terhubung ke v. Atau dengan kata lain memberikan informasi nodes mana saja yang terhubung dengan node v.
3. Solusi DFS:
VDFS = V[:] # a copy of V by values DFS = nx.Graph() # empty graph v = VDFS[0]; del VDFS[0] stack = [root] # untuk backtrack while VDFS: # VDFS not empty DFS.add_node(v) e = G.edges(v) nextNode = [v2 for v1,v2 in e if v2 not in DFS.nodes()] if nextNode: # Not Empty nextNode.sort() # meyakinkan urutannya sesuai urutan node (abjad) DFS.add_node(nextNode[0]) DFS.add_edge(v,nextNode[0]) v = nextNode[0] stack.append(v) del VDFS[VDFS.index(v)] else: #Backtrack v = stack[-1]; del stack[-1]Bedanya dengan BFS, di DFS ini kita butuh suatu variabel untuk melakukan "BackTrack". Variabel yang saya gunakan di code ini adalah "stack". Saya gunakan variabel VDFS sebagai stopper, bahwa kita sudah men-traverse seluruh node di graph. Hati-hati ... kita tidak bisa menggunakan perintah berikut di python "VDFS=V" karena Python melakukan copy by reference (pointer) dan bukan by values (baca disini). Backtrack dilakukan di baris terakhir dengan menggunakan elemen terakhir dari variabel stack. Di dunia pemrograman biasa disebut sebagai "pop" operation. Sedangkan perintah "stack.append(v)" biasa disebut sebagai operasi "push".
4. Plot Graph solusinya:
drawGraph(G, file="GraphAwal.png", labels = True, edge_Label=False, gType = 'spring') drawGraph(BFS, file="BFS.png", labels = True, edge_Label=False, gType = 'spring') drawGraph(DFS, file="DFS.png", labels = True, edge_Label=False, gType = 'spring')Graphnya selain di plot, langsung di save ke disk (dalam bentuk PNG)... ?? ... biar handy. Ini hasilnya:
Graph Awal, BFS, & DFS. Silahkan di cek apakah hasil tersebut isomorfis dengan solusi di atas. |
That's it ... mudah kan? ... ?? ... Kalau di search di Google banyak solusi dari BFS dan DFS ini menggunakan fungsi rekursif. Agan bisa latihan dengan mencari solusi rekursifnya. O iya, hati-hati juga banyak algoritma BFS dan DFS di internet hanya sekedar untuk traversal saja, tapi belum ke spanning tree-nya. Anyway ... semakin banyak baca insya Allah akan semakin puyeng... eh salah, maksud saya semakin jelas ... ?? ...
Post selanjutnya kita coba masalah umum lain di Graph, that's it for now. Have a nice weekend Guys ... Cheers...
Depok, 07 Jan 2018
</TES>®
Tidak ada komentar:
Posting Komentar
Relevant & Respectful Comments Only.