Stuart Russell နဲ့ Peter Norvig တို့ရဲ့ "Artificial Intelligence: A Modern Approach" စာအုပ်၊ အခန်း ၄ တွင် ရှင်းပြထားသော "Local Search Algorithms" များထဲမှ Hill-climbing algorithm သည် လက်ရှိအခြေအနေ (Current State) မှနေ၍ ပိုမိုကောင်းမွန်သော အိမ်နီးချင်းအခြေအနေ (Neighbor State) သို့ အစဉ်မပြတ် ရွေးချယ်သွားသော နည်းလမ်းဖြစ်ပါသည်။
8-Queens Problem နှင့် Hill-Climbing ပေါင်းစပ်စဉ်းစားပုံ
8-Queens ပြဿနာကို Hill-climbing ဖြင့် ဖြေရှင်းရာတွင် အောက်ပါအတိုင်း ဖွဲ့စည်း (Formulate) ပါသည်-
State Representation (အခြေအနေ ကိုယ်စားပြုပုံ):
ဘုတ်ပြားပေါ်တွင် ဘုရင်မ (Queen) ၈ ပါးလုံးကို ကော်လံ (Column) တစ်ခုလျှင် တစ်ပါးစီ ချထားသည့် ပုံစံဖြင့် စတင်ပါသည်။ ထို့ကြောင့် ကော်လံ ၈ ခုတွင် ရှိနေသော ဘုရင်မများ၏ အတန်း (Row) နေရာများကို
[0, 4, 7, 5, 2, 6, 1, 3]စသည့် 1D Array ဖြင့် ကိုယ်စားပြုနိုင်ပါသည်။Heuristic Function ($h$):
အချင်းချင်း တိုက်ခိုက်နိုင်သော (Attacking pairs) ဘုရင်မ အစုံအရေအတွက် ဖြစ်ပါသည်။ ပန်းတိုင် (Goal State) တွင် မည်သည့်ဘုရင်မမှ အချင်းချင်း မစားနိုင်ရသဖြင့် $h = 0$ ဖြစ်ရပါမည်။
Neighbor (အိမ်နီးချင်း အခြေအနေ):
ကော်လံတစ်ခုရှိ ဘုရင်မတစ်ပါးကို အခြားသော အတန်း (Row) တစ်ခုခုသို့ ရွှေ့လိုက်ခြင်းကို Neighbor ဟု သတ်မှတ်ပါသည်။ ကော်လံ ၈ ခု၊ ကော်လံတစ်ခုလျှင် ပြောင်းရွှေ့နိုင်သော အတန်း ၇ ခု ရှိသဖြင့် စုစုပေါင်း Neighbor ၅၆ ခု ($8 \times 7 = 56$) ရှိပါသည်။
Action:
လက်ရှိ $h$ တန်ဖိုးထက် ပိုနည်းသော (ပိုကောင်းသော) Neighbor ကို ရွေးချယ်သွားပါသည်။
Local Maxima ပြဿနာ နှင့် Random-Restart Hill-Climbing
Hill-climbing ၏ အဓိက အားနည်းချက်မှာ Local Maxima (သို့မဟုတ် $h$ တန်ဖိုးအရ Local Minima) တွင် ပိတ်မိတတ်ခြင်း ဖြစ်ပါသည်။ လက်ရှိအခြေအနေသည် ပန်းတိုင်ရောက်မနေသော်လည်း ($h > 0$)၊ ရွှေ့၍ရနိုင်သော အိမ်နီးချင်း ၅၆ ခုလုံး၏ $h$ တန်ဖိုးများသည် လက်ရှိတန်ဖိုးထက် ကြီးနေလျှင် သို့မဟုတ် တူညီနေလျှင် Algorithm သည် ရှေ့ဆက်မတိုးနိုင်တော့ဘဲ ရပ်တန့်သွားပါသည်။
ဤပြဿနာကို ဖြေရှင်းရန် Random-restart hill-climbing ကို အသုံးပြုပါသည်။ ၎င်း၏ အခြေခံသဘောတရားမှာ "ပိတ်မိသွားတိုင်း အသစ်ကနေ ပြန်စမည် (If at first you don't succeed, try, try again)" ဖြစ်ပါသည်။ Local Maxima တွင် ရပ်တန့်သွားတိုင်း၊ လက်ရှိအခြေအနေကို စွန့်လွှတ်ကာ ကျပန်း (Random) အခြေအနေသစ် တစ်ခုကို ဖန်တီး၍ အစမှ ပြန်လည်ရှာဖွေပါသည်။ ပန်းတိုင်ရောက်သည်အထိ ($h=0$) ဤလုပ်ငန်းစဉ်ကို အကြိမ်ကြိမ် ပြန်လုပ်သောကြောင့် 8-Queens ပြဿနာကို အမြဲတမ်း ဖြေရှင်းပေးနိုင်ပါသည်။
import random
# ==========================================
# Heuristic Function ($h$) တွက်ချက်ခြင်း
# ==========================================
def calculate_heuristic(board):
"""
ဘုတ်ပြားပေါ်ရှိ အချင်းချင်း တိုက်ခိုက်နိုင်သော ဘုရင်မ အစုံ (Attacking pairs) အရေအတွက်ကို တွက်ပါသည်။
board: 1D List (ဥပမာ - [0, 4, 7, 5, 2, 6, 1, 3] အဓိပ္ပာယ်မှာ ကော်လံ 0 တွင် အတန်း 0 ၌ ရှိသည်...)
"""
attacking_pairs = 0
n = len(board)
# ကော်လံ တစ်ခုစီရှိ ဘုရင်မများကို ကျန်ရှိသော ကော်လံများမှ ဘုရင်မများနှင့် တိုက်ရိုက် နှိုင်းယှဉ်ပါမည်
for i in range(n):
for j in range(i + 1, n):
# 1. ရေပြင်ညီ အတန်း (Same Row) တူနေသလား စစ်ဆေးခြင်း
# 2. ထောင့်ဖြတ် (Diagonal) မျဉ်းပေါ်တွင် ရှိနေသလား စစ်ဆေးခြင်း
# (ကော်လံနှစ်ခုကြား အကွာအဝေး နှင့် အတန်းနှစ်ခုကြား အကွာအဝေး တူညီနေလျှင် ထောင့်ဖြတ်မျဉ်းပေါ်တွင် ရှိသည်)
if board[i] == board[j] or abs(board[i] - board[j]) == abs(i - j):
attacking_pairs += 1
return attacking_pairs
# ==========================================
# အကောင်းဆုံး အိမ်နီးချင်း (Best Neighbor) ကို ရှာဖွေခြင်း
# ==========================================
def get_best_neighbor(board):
"""
ရွှေ့နိုင်သော အိမ်နီးချင်း ၅၆ ခုလုံးကို ဖန်တီးပြီး၊ ၎င်းတို့အနက်မှ Heuristic အနည်းဆုံး (အကောင်းဆုံး)
အခြေအနေကို ရွေးချယ်ပေးပါမည်။
"""
best_board = list(board) # လက်ရှိ Board ကို ကနဦး အကောင်းဆုံးအဖြစ် မှတ်ထားပါမည်
min_h = calculate_heuristic(board)
n = len(board)
# ကော်လံ (col) ၈ ခုလုံးကို လှည့်ပတ်စစ်ဆေးမည်
for col in range(n):
# အတန်း (row) ၈ ခုလုံးသို့ ရွှေ့ကြည့်မည်
for row in range(n):
# လက်ရှိ ရှိနေသော အတန်း မဟုတ်မှသာ ရွှေ့ကြည့်မည် (Neighbor အသစ် ဖန်တီးခြင်း)
if board[col] != row:
neighbor = list(board) # လက်ရှိ ဘုတ်ပြားကို မိတ္တူကူးပါ
neighbor[col] = row # ဘုရင်မကို အတန်းသစ်သို့ ရွှေ့ပါ
neighbor_h = calculate_heuristic(neighbor)
# အကယ်၍ Neighbor အသစ်၏ $h$ သည် လက်ရှိအနည်းဆုံး $h$ ထက် ပိုနည်းလျှင် Update လုပ်မည်
if neighbor_h < min_h:
min_h = neighbor_h
best_board = neighbor
return best_board, min_h
# ==========================================
# Standard Hill-Climbing Algorithm
# ==========================================
def hill_climbing(board):
"""
ပေးထားသော ကနဦးအခြေအနေမှ စတင်၍ Local Maxima သို့မဟုတ် Goal State ရောက်သည်အထိ ရှာဖွေမည်။
"""
current_board = board
current_h = calculate_heuristic(current_board)
while True:
# အကောင်းဆုံး Neighbor ကို ရှာပါ
neighbor_board, neighbor_h = get_best_neighbor(current_board)
# အကယ်၍ အကောင်းဆုံး Neighbor ၏ $h$ တန်ဖိုးသည် လက်ရှိ $h$ ထက် မနည်းတော့လျှင်
# (ဆိုလိုသည်မှာ ပိုမကောင်းတော့လျှင်) Local Maxima တွင် ပိတ်မိသွားပြီ ဖြစ်သဖြင့် ရပ်တန့်ပါမည်။
if neighbor_h >= current_h:
return current_board, current_h
# ပိုကောင်းသော အခြေအနေသို့ ရွှေ့ပါ
current_board = neighbor_board
current_h = neighbor_h
# ==========================================
# Random-Restart Hill-Climbing Algorithm
# ==========================================
def random_restart_hill_climbing():
"""
Hill-Climbing လုပ်ရင်း Local Maxima တွင် ပိတ်မိသွားတိုင်း၊ ကျပန်း (Random) Board အသစ်တစ်ခု
ပြန်လည်ဖန်တီး၍ Goal State ($h = 0$) ရရောက်သည်အထိ ဆက်တိုက် Restart လုပ်သွားမည့် Main Function ဖြစ်ပါသည်။
"""
restarts = 0
n = 8 # 8-Queens
while True:
# ကျပန်း ဘုတ်ပြားအသစ် တစ်ခု ဖန်တီးခြင်း (ကော်လံတစ်ခုစီအတွက် 0 မှ 7 အတွင်း ကျပန်းအတန်းတစ်ခု ရွေးခြင်း)
initial_board = [random.randint(0, n - 1) for _ in range(n)]
# Hill-Climbing ဖြင့် ဖြေရှင်းကြည့်ခြင်း
final_board, final_h = hill_climbing(initial_board)
# အကယ်၍ ဖြေရှင်းပြီးသော Board ၏ $h$ သည် 0 ဖြစ်သွားလျှင် ပြဿနာပြေလည်သွားပြီ (Goal Test အောင်မြင်သည်)
if final_h == 0:
print(f"Goal State Found! (Total Restarts: {restarts})")
return final_board
# ပိတ်မိသွားလျှင် Restart အကြိမ်ရေကို မှတ်သား၍ အပေါ်မှ `while` လှည့်ပတ်မှုအတိုင်း ပြန်လည်စတင်မည်
restarts += 1
# ==========================================
# ရလဒ်ကို ပုံဖော်ပြသရန် Function (Visualization)
# ==========================================
def print_board(board):
n = len(board)
for row in range(n):
row_str = ""
for col in range(n):
if board[col] == row:
row_str += " Q " # ဘုရင်မ ရှိသောနေရာ
else:
row_str += " . " # လွတ်နေသောနေရာ
print(row_str)
print("\nArray Representation:", board)
# Program စတင်ခြင်း
if __name__ == "__main__":
print("Running Random-Restart Hill-Climbing for 8-Queens...\n")
solution = random_restart_hill_climbing()
print("\nFinal Solution Board:")
print_board(solution)
ပရိုဂရမ်၏ အဓိက အနှစ်သာရများ
Memory အသုံးပြုမှု နည်းပါးခြင်း: State တစ်ခုလုံးကို ပြသရန် 8x8 2D Array ကြီးကို မသုံးဘဲ ကော်လံတစ်ခုလျှင် အတန်း (row index) ကိုသာ ကိုယ်စားပြုသော 1D Array (ဥပမာ
[1, 3, 5, 7, 2, 0, 6, 4]) ကို အသုံးပြုထားသောကြောင့် တွက်ချက်မှု မြန်ဆန်စေပါသည်။Steepest-Ascent:
get_best_neighborfunction တွင် Neighbor ၅၆ ခုလုံးကို လှည့်ပတ်စစ်ဆေးပြီးမှ အကောင်းဆုံးကိုသာ ရွေးချယ်သည့် အပြည့်စုံဆုံး (Steepest) နည်းလမ်းကို အသုံးပြုထားပါသည်။Completeness: သာမန် Hill-climbing သည် Local Maxima ကြောင့် ဖြေရှင်းချက် ရှာမရဘဲ ရပ်တန့်နိုင်သော်လည်း၊
random_restart_hill_climbing၏while True:loop မှ ဖြေရှင်းချက် (Goal State) မရမချင်း Random အသစ်ပြန်လုပ်ပေးနေမည်ဖြစ်၍ ပြဿနာကို အမြဲတမ်း ဖြေရှင်းပေးနိုင်မည် (Complete ဖြစ်သည်)။
