AI
Artificial Intelligence (IF1706)
FSTT • ISTN Jakarta • Semester Ganjil 2025/2026
Sesi 4 – Heuristik & A*

Menjelaskan konsep heuristik admissible dan consistent. Mahasiswa mengenal fungsi evaluasi f(n)=g(n)+h(n) dan mencoba mendesain heuristik sederhana. Implementasi A* dilakukan pada grid untuk mencari rute tercepat menuju tujuan.

Ulasan Materi: Heuristik yang Mudah Dipahami

Definisi & Intuisi

Heuristik adalah perkiraan biaya minimum dari suatu state ke goal. Tujuan utamanya: mengurangi jumlah node yang perlu dieksplorasi dibandingkan pencarian buta. A* menggabungkan biaya nyata yang sudah ditempuh (g(n)) dengan estimasi sisa jarak (h(n)).

  • Admissible: tidak melebih-lebihkan biaya ke goal. Secara formal, untuk semua n: h(n) ≤ h*(n) (biaya sebenarnya). → Jaminan optimal.
  • Consistent (Monoton): untuk setiap edge (n,m) dengan biaya c(n,m), berlaku h(n) ≤ c(n,m) + h(m). → Frontier A* tidak perlu direlaksasi ulang, lebih efisien.

Contoh Heuristik Grid

  • Manhattan (gerak 4-arah): h(n)=|x_g-x_n|+|y_g-y_n|.
  • Euclidean (ruang kontinu/gerak diagonal): h(n)=√((x_g-x_n)^2+(y_g-y_n)^2).

Contoh Hitungan Manual

Contoh perhitungan fungsi evaluasi f(n):

Jika biaya g(n) = 10 dan heuristik h(n) = 6, maka f(n) = g(n) + h(n) = 16.

Jika heuristik h(n) = jarak Manhattan antara node n dan goal: |x_goal - x_n| + |y_goal - y_n|.
Contoh: posisi (2,3), goal (5,7) → h(n) = |5-2| + |7-3| = 7.

A* memilih node dengan f(n) terkecil di frontier, sehingga jalur yang diperoleh optimal jika h(n) admissible (tidak melebih-lebihkan biaya sebenarnya).
Lab: A* + Eksperimen Kualitas Heuristik
A. Implementasi A*
# ====== Implementasi A* di Grid ======
import math, heapq, time, random
import networkx as nx
import matplotlib.pyplot as plt

# 1. Bangun graf grid
W, H = 10, 8
start, goal = (0,0), (H-1,W-1)
G = nx.grid_2d_graph(H, W)

random.seed(5)
remove_ratio = 0.18
edges = list(G.edges())
random.shuffle(edges)
for e in edges[:int(len(edges)*remove_ratio)]:
    G.remove_edge(*e)

# Pastikan tetap terhubung
if not nx.has_path(G, start, goal):
    for e in edges[int(len(edges)*remove_ratio)//2:]:
        G.add_edge(*e)
        if nx.has_path(G, start, goal):
            break

# 2. Definisi heuristik

def manhattan(a,b):
    (x1,y1),(x2,y2)=a,b
    return abs(x1-x2)+abs(y1-y2)

def euclidean(a,b):
    (x1,y1),(x2,y2)=a,b
    return math.sqrt((x1-x2)**2+(y1-y2)**2)

# 3. Algoritma A*

def astar(G, start, goal, h):
    pq = [(0,start)] # (f,node)
    parent={start:None}
    g_cost={start:0}
    expanded=0
    t0=time.perf_counter()

    while pq:
        f,u = heapq.heappop(pq)
        expanded += 1
        if u==goal:
            dt=time.perf_counter()-t0
            return u,parent,g_cost,expanded,dt
        for v in G.neighbors(u):
            ng=g_cost[u]+1  # biaya 1 per langkah
            if v not in g_cost or ng<g_cost[v]:
                g_cost[v]=ng
                f=ng+h(v,goal)
                heapq.heappush(pq,(f,v))
                parent[v]=u
    return None,parent,g_cost,expanded,time.perf_counter()-t0


def reconstruct(parent, goal):
    path=[]; cur=goal
    while cur is not None:
        path.append(cur)
        cur=parent.get(cur)
    return list(reversed(path))

# 4. Jalankan A* dengan dua heuristik
node_m,parent_m,g_cost_m,exp_m,tm = astar(G,start,goal,manhattan)
node_e,parent_e,g_cost_e,exp_e,te = astar(G,start,goal,euclidean)

path_m=reconstruct(parent_m,goal)
path_e=reconstruct(parent_e,goal)

print(f"Manhattan: expanded={exp_m}, waktu={tm:.5f}s, panjang={len(path_m)-1}")
print(f"Euclidean: expanded={exp_e}, waktu={te:.5f}s, panjang={len(path_e)-1}")

# 5. Visualisasi
pos={(r,c):(c,-r) for r,c in G.nodes()}
plt.figure(figsize=(6,4))
nx.draw(G,pos,node_size=60,width=1,with_labels=False)
nx.draw_networkx_nodes(G,pos,nodelist=path_m,node_size=80)
nx.draw_networkx_edges(G,pos,edgelist=list(zip(path_m,path_m[1:])),width=3)
plt.title('A* dengan heuristik Manhattan')
plt.show()

plt.figure(figsize=(6,4))
nx.draw(G,pos,node_size=60,width=1,with_labels=False)
nx.draw_networkx_nodes(G,pos,nodelist=path_e,node_size=80)
nx.draw_networkx_edges(G,pos,edgelist=list(zip(path_e,path_e[1:])),width=3)
plt.title('A* dengan heuristik Euclidean')
plt.show()

Catatan: Ubah W,H,remove_ratio,seed untuk melihat dampak pada jumlah node dieksplorasi & waktu.

B. Bandingkan dengan UCS
# ====== Perbandingan dengan UCS (biaya seragam) ======
import heapq, time, math

# UCS (Uniform-Cost Search) dengan biaya 1 per edge

def ucs(G, start, goal, cost=lambda u,v:1):
    pq=[(0,start)]  # (g,node)
    best={start:0}
    parent={start:None}
    expanded=0
    t0=time.perf_counter()
    while pq:
        g,u = heapq.heappop(pq)
        expanded+=1
        if u==goal:
            dt=time.perf_counter()-t0
            return u,parent,best,expanded,dt
        for v in G.neighbors(u):
            ng=g+cost(u,v)
            if v not in best or ng<best[v]:
                best[v]=ng
                parent[v]=u
                heapq.heappush(pq,(ng,v))
    return None,parent,best,expanded,time.perf_counter()-t0

node_u,parent_u,g_u,exp_u,tu = ucs(G,start,goal)

# Rekonstruksi path

def reconstruct(parent, goal):
    path=[]; cur=goal
    while cur is not None:
        path.append(cur)
        cur=parent.get(cur)
    return list(reversed(path))

path_u = reconstruct(parent_u, goal)

print(f"UCS : expanded={exp_u}, waktu={tu:.5f}s, panjang={len(path_u)-1}")

# Catatan: Pada graf tak berbobot, UCS setara shortest path. Bandingkan nilai expanded/waktu dengan A* di atas.
C. Kuis 4 (Cek Mandiri)
# ====== Kuis 4 (cek mandiri) ======
qs=[
  ("Fungsi evaluasi A* adalah...",{"a":"f(n)=g(n)*h(n)","b":"f(n)=g(n)+h(n)","c":"f(n)=h(n)-g(n)","d":"f(n)=g(n)/h(n)"},"b"),
  ("Heuristik disebut admissible jika...",{"a":"Tidak melebih-lebihkan biaya sebenarnya ke goal","b":"Selalu nol","c":"Tidak tergantung tujuan","d":"Melebihkan jarak agar cepat"},"a"),
  ("Heuristik konsisten berarti...",{"a":"h(n) ≤ c(n,m) + h(m) untuk setiap edge (n,m)","b":"h=0 selalu","c":"h(n) ≥ h(m)","d":"h(n) tidak bergantung graf"},"a"),
]
print('Kunci jawaban:')
for i,(_,__,ans) in enumerate(qs,1):
    print(f'Q{i}: {ans}')
Penugasan & Referensi

Tugas Koding 2: Implementasikan A* dengan dua heuristik (Manhattan & Euclidean), lalu bandingkan hasilnya dengan UCS pada graf grid yang sama. Laporkan: panjang jalur, jumlah node dieksplorasi, waktu, dan analisis singkat mengapa sebuah heuristik lebih baik/buruk pada kasus Anda.

  • Russell & Norvig (2020), bab heuristik & A*.
  • Dokumentasi networkx (shortest path, grid graphs).