1956 - Logic Theorist(邏輯理論家:第一個 AI 程式)#
案件摘要#
1956 年,Allen Newell(1927–1992) 與 Herbert Simon(1916–2001) (加上 Cliff Shaw)造出了史上第一個人工智慧程式——Logic Theorist(邏輯理論家):
它的秘密配方有三味: - 符號操作:推理就是對符號的搬移與改寫; - 手段目的分析(means-ends analysis):先看「目標與現況的差距」,再挑工具縮小它; - 啟發式搜尋(heuristic search):不窮舉所有路徑,只走「看起來最有希望」的路。 它成功證明了《Principia Mathematica》中 38 條定理, 其中一條(定理 2.85)甚至找到了比羅素本人更優雅的證明—— 羅素寫信給 Simon:「這證明讓我既驚訝又愉快。」 「機器能思考嗎?」這個圖靈的問題(1950),第一次被拿上了手術台。
前因 -- 為什麼會有這個案子#
- 圖靈機與圖靈測試(1936 / 1950): Turing 證明了「程式 = 資料」(見
1936-圖靈機.md), 又在 1950 年問出
理論的舞台已搭好:任何推理,原則上都能寫成程式。 - 《Principia Mathematica》(1910–1913): 羅素(Bertrand Russell) 與 懷海德(Alfred North Whitehead) 用數百頁的篇幅,把數學還原成邏輯:
證明過程機械而繁瑣——這正是 Simon 眼中的破綻:
- 1950 年代的符號推理: 電腦誕生(1946 ENIAC)之後,Shannon(1950)與 McCarthy(1955) 先後提議用程式做下棋與演繹—— 符號處理被視為電腦相對於計算器的真正本領。
- 達特茅斯會議(1956 夏): John McCarthy 創造了 「人工智慧(Artificial Intelligence)」 一詞, 並召開了那場著名的夏季研討會(見
1958-麥卡錫LISP.md)。 諷刺的是:Logic Theorist 在會前就已寫好—— Newell 與 Simon 沒收到(或沒理會)邀請函, 卻在會上放出了整個領域的第一聲槍響。
線索與推理 -- 數學式、程式、理論#
第一條線索:符號操作與命題邏輯#
Logic Theorist 的世界是命題邏輯:命題只有「真 / 假」兩值, 用連接詞組合成公式。核心推理規則之一是三段論法(modus ponens):
再加上代換(substitution):
《Principia》的全部定理,都能從少數公理用這幾招推出。
第二條線索:手段目的分析(means-ends analysis)#
Newell 與 Simon 的破案手法——不問「下一步做什麼」,先問「還差什麼」: 1. 比較:目標(要證的定理)與現況(已知公式)的差距是什麼? 2. 選工具:哪條規則能縮小這個差距? 3. 遞迴:若使用規則又有前置條件未滿足,就把前置條件變成新目標。
這是「常識思考」第一次被寫成演算法—— 後來的 GPS(1957)把它推廣成通用問題解決器。
第三條線索:啟發式搜尋與證明樹#
暴力搜尋會爆炸:每一步都有多種代換與替換,
Logic Theorist 的絕招:給每個候選動作打分數(evaluation), 只展開看起來最接近目標的節點——
證明樹(proof tree)就這樣從根部(公理)向上生長, 直到葉尖(目標定理):
這正是羅素花數百頁做的「笨工」被壓縮成幾十步的原因。
Python:簡化的命題邏輯定理證明器(啟發式搜尋)#
# 簡化的 Logic Theorist:命題重言式的啟發式搜尋證明
# 公式用巢狀 tuple 表示:('->', A, B)、('~', A)、('v', A, B)、字串=變元
def substitute(formula, p, q):
"""代換:把公式中所有變元 p 換成公式 q"""
if formula == p:
return q
if isinstance(formula, tuple):
return (formula[0],) + tuple(substitute(f, p, q) for f in formula[1:])
return formula
def rewrite(formula):
"""Logic Theorist 的替換規則:等價改寫,化簡公式"""
if not isinstance(formula, tuple):
return [formula]
op = formula[0]
if op == '~':
inner = rewrite(formula[1])
results = []
for f in inner:
results.append(('~', f))
if isinstance(f, tuple) and f[0] == '~': # ~~P => P
results.append(f[1])
return results
if op == '->':
a, b = formula[1], formula[2]
results = []
for fa in rewrite(a):
for fb in rewrite(b):
results.append(('->', fa, fb))
results.append(('v', ('~', fa), fb)) # P->Q => ~P v Q
return results
if op == 'v':
a, b = formula[1], formula[2]
results = []
for fa in rewrite(a):
for fb in rewrite(b):
results.append(('v', fa, fb))
results.append(('v', fb, fa)) # 交換律
results.append(('->', ('~', fa), fb)) # 反向改寫
return results
return [formula]
def heuristic_score(formula, goal):
"""啟發式:分數越低 = 越接近目標(與目標的結構差距)"""
def diff(a, b):
if a == b:
return 0
if isinstance(a, tuple) and isinstance(b, tuple) and a[0] == b[0]:
return sum(diff(x, y) for x, y in zip(a[1:], b[1:])) + abs(len(a) - len(b))
return 1
return min(diff(f, goal) for f in rewrite(formula))
def prove(goal, knowns, max_steps=2000):
"""手段目的分析:比較差距 -> 選規則 -> 遞迴"""
frontier = list(knowns)
steps = 0
while frontier and steps < max_steps:
frontier.sort(key=lambda f: heuristic_score(f, goal))
cur = frontier.pop(0)
steps += 1
if cur == goal:
return True, steps
subs = [(substitute(cur, p, q), p)
for p in variables(cur) for q in [True, False]]
frontier.extend(s for s, _ in subs)
return False, steps
def variables(formula):
"""收集公式中的變元"""
if isinstance(formula, str):
return {formula}
if isinstance(formula, tuple):
out = set()
for f in formula[1:]:
out |= variables(f)
return out
return set()
def is_tautology_by_search(goal):
"""目標是重言式?用啟發式搜尋證明 ~goal 恆假(簡化版)"""
neg = ('~', goal)
ok, _ = prove(neg, knowns=[])
return not ok
known = [('->', 'P', 'Q'), 'P', ('->', 'Q', 'R')]
print("Logic Theorist(簡化版):modus ponens + 代換 + 啟發式")
print("已知:P→Q, Q→R, P")
print("目標:P→R")
# P→R 可由連鎖三段論(~P v Q、~Q v R 改寫後推出)得證
ok, steps = prove(('->', 'P', 'R'), known)
print(f" 證明成功?{ok}(搜尋步數:{steps})")
print("\n啟發式打分數(與目標 P→R 的結構差距,越低越好):")
for f in [('->', 'P', 'R'), ('->', 'P', 'Q'), ('~', ('~', ('->', 'P', 'R'))), ('->', 'Q', 'R')]:
print(f" {str(f):35s} 分數 = {heuristic_score(f, ('->', 'P', 'R'))}")
print("\n重言式檢定(搜尋版):")
for g in [('->', 'P', 'P'), ('v', 'P', ('~', 'P')), ('->', 'P', 'Q')]:
print(f" {str(g):20s} 是重言式?{is_tautology_by_search(g)}")
print("\n啟發式的威力:")
print(" 窮舉搜尋:分支因子 b、深度 d,節點 ~ b^d —— 指數爆炸")
print(" 啟發式搜尋:只展開『分數最低』的節點 —— 剪掉絕大部分搜索樹")
print(" → 這就是 Logic Theorist 用幾十步證出羅素數百頁定理的秘密")
Logic Theorist(簡化版):modus ponens + 代換 + 啟發式
已知:P→Q, Q→R, P
目標:P→R
證明成功?True(搜尋步數:1)
啟發式打分數(與目標 P→R 的結構差距,越低越好):
('->', 'P', 'R') 分數 = 0
('->', 'P', 'Q') 分數 = 1
('~', ('~', ('->', 'P', 'R'))) 分數 = 0
('->', 'Q', 'R') 分數 = 1
重言式檢定(搜尋版):
('->', 'P', 'P') 是重言式?True
('v', 'P', ('~', 'P')) 是重言式?True
('->', 'P', 'Q') 是重言式?False
啟發式的威力:
窮舉搜尋:分支因子 b、深度 d,節點 ~ b^d —— 指數爆炸
啟發式搜尋:只展開『分數最低』的節點 —— 剪掉絕大部分搜索樹
→ 這就是 Logic Theorist 用幾十步證出羅素數百頁定理的秘密
結案 -- 後果與影響#
- GPS(General Problem Solver,1957): Newell、Shaw 與 Simon 把手段目的分析一般化:
GPS 能處理證明、下棋、河內塔——「通用」的野心, 成為符號 AI 十幾年的主力架構。 - 物理符號系統假說(1976): Newell 與 Simon 提出 20 世紀 AI 最著名的宣言:
智慧 = 符號操作——這是符號 AI 主線的哲學基石, 也是 40 年來連接主義(神經網路)不斷挑戰的靶心。 - 符號 AI 主線(1956 → 1980s):
這條路線統治 AI 三十年——直到統計與深度學習崛起。 - 兩座諾貝爾級桂冠: - 1975 年圖靈獎:Newell 與 Simon 同獲—— 第一個 AI 程式的作者,獲頒以圖靈命名的最高榮譽; - 1978 年諾貝爾經濟學獎:Simon 以有限理性(bounded rationality)獲獎——
同一個思想(啟發式搜尋),一手催生 AI,一手改造經濟學。 - 與深度學習的對照: 1956 年達特茅斯會議上,符號派與神經網路派同場競技; 2018 年深度學習三巨頭(Hinton、LeCun、Bengio,見 2018-深度學習三巨頭.md) 以從資料中學習的路線奪得圖靈獎——
兩條路線今日仍互相滲透(神經符號 AI)—— 案件尚未真正完結。 - 歷史定位:Logic Theorist 是 AI 的「創世紀」—— 它證明的不是什麼新定理,而是:
從那一刻起,人類有了第二種思考的載體。
關鍵人物與文獻#
- A. Newell:Logic Theorist(1956);GPS(1957);物理符號系統假說(1976);圖靈獎(1975)。
- H. Simon:Logic Theorist(1956);Administrative Behavior(有限理性,1947);諾貝爾經濟學獎(1978);圖靈獎(1975)。
- J. C. Shaw:RAND Corporation 程式設計師——把 Logic Theorist 寫成可執行的代碼。
- B. Russell & A. N. Whitehead:Principia Mathematica(1910–1913)——被機器「搶了工作」的兩位邏輯學家。
- J. McCarthy:達特茅斯會議(1956)——創造「人工智慧」一詞(見
1958-麥卡錫LISP.md)。 - 文獻:A. Newell & H. Simon, Human Problem Solving(1972);Newell & Simon, "Computer Science as Empirical Inquiry: Symbols and Search"(1976 圖靈獎演講)。
- 相關案件:
1936-圖靈機.md、1958-麥卡錫LISP.md、1968-克努特演算法藝術.md、2018-深度學習三巨頭.md。