ゴールデン街と量子物理学者
なんか鳥の唐揚げが食べたいなあ、と思ったのだ。
というのも、僕は居酒屋に滅多に行かなくなってしまったからだ。
居酒屋といえば鳥の唐揚げ。
居酒屋に一人で行く人はあまりいないと思う。僕もぼっち人間なので一人で夕飯を食べる場所を探すことが多い。
一人で夕飯を食べるということは、居酒屋に行かないということである。
でもいいのだ。ゴーデン街があるから。
居酒屋以外の場所で唐揚げを食べるとなると定食屋などに限られる。しかし最近、大戸屋はなんかちょっとオシャレな感じがして近づきにくくなってしまった。なんていうか、松屋よりもスープストック東京になってしまった感じというか。コメダ珈琲よりもスタバ寄りというか。
オシャレ大戸屋で鳥の唐揚げ定食なんか食べてるとどうも調子が狂う。
なんとなく秋葉原駅前をぶらぶらする。朝から何も食べてない。エチオピアという気分でもないし、うどんでもない。立ち食い寿司を見て「おっ」と思うが、寿司なら昨日食べたなあと思い直す。
そうしたら「昭和食堂」という店が駅前にあって、まるで往年の「神田食堂」みたいな雰囲気をかんじてフラフラと近づいていった。
昼の1時にようやく今日最初の飯を食うことになったのは、昨夜ゴールデン街で飲み過ぎたからだ。
「東京に住んでるのか?」
「ああ。君はどこから来たんだ?」
「俺はフランクフルトだ」
「アム・マイン?」
「そうだな。ハハ。確かにフランクフルトは沢山ある。ドイツで一番大きなフランクフルトだ。フランクフルト・アム・マイン。ヘッセン州の」
「そうか。俺も何度か行ったことがあるよ」
「本当かい?・・・君は仕事は何をしてるんだ?」
仕事・・・仕事か。いつも答えに詰まる。
あまり詮索されるのも面倒なので、「研究家だ」と名乗ると、男は目を丸くした。
「本当かい?実は俺も研究者なんだ」
「へえ、何の?」
「物理学だ。君は?」
「AIだ」
「そうか。AIか」
「ドイツには有名な物理学者が沢山いるよね。シュヴァルツシルトとかシュレディンガーとか」
「エルヴィン・シュレディンガーはオーストリアだ」
「そうだった。最近趣味で量子力学の計算方法を勉強してるんだ。ほら、ブラ=ケット何とかっていう・・・」
「ブラ=ケット記法?何でそんなものを君が?」
「そこに実に深い意味があるんじゃないかと考えているんだ。ブラ-ケット記法は実際にはベクトルを表現していて、量子力学の計算はほとんどが行列とベクトルの計算になる。それはAIの計算と大部分が共通しているんだ。それに、もっと興味深いのは、どちらも"ネットワーク"を題材としているところなんだ」
AIは言うまでもなく「ニューラル"ネットワーク"」を扱う。量子力学では「スピン"ネットワーク"」を扱う。ネットワークと代数幾何学は一見するとまるで無関係なものなのにネットワークの計算を扱おうとすると代数幾何学が必要になる。実に不思議だ。
そして、モデルは単純なのにそこから生まれる振る舞いは複雑怪奇で人間の想像力では追いつかないという点も、AIと量子力学の奇妙な類似点である。
「それは実に興味深い話だね。アメリカ人の、ほら、有名な物理学者で、何と言ったかな・・・多分ユダヤ人の」
「フォン・ノイマン?」
「違う。確かに彼もユダヤ人だが、誰だっけほら、あの有名な・・・」
「ファインマンか」
「そう!ファインマンだ。彼は電気回路のアナロジーでよく量子力学を説明するんだ。コンデンサとコイル、そして抵抗器の関係さ。この三つで宇宙全部を説明できるんだよ」
「本当かい?」
「本当だとも」
それから彼はつらつらと何か言っていたがだんだんと酔っ払ってきたらしく早口に磨きがかかった。僕の本が店に置いてあったので本を見せると、彼も自分の書いた本を紹介してくれた。
最後に名刺をもらうと、フランクフルトにある原子物理研究所の研究者だった。
そんなことをぼんやり思い出しながら、電気回路とスピンネットワークの関係なんて考えたこともなかったから、このアナロジーで何を説明しようとしているのか気になった。酒もあったから、頭もはっきりしていないし。定食を食べながらとりあえずChatGPTに聞いてみた。
抵抗、コンデンサ、コイルをスピンネットワークに適用したときのアナロジーを教えて
さっぱりわからん。
そもそもスピンネットワークがよくわからないのだ。
スピンネットワークについてプログラマーに説明してくれ
わかったようなわからないような。
しかしプログラマーの武器は、プログラムなら読めると言うことである。
そこでこう命じてみた。
スピンネットワークのシミュレータをPythonで書いて
import networkx as nx
import matplotlib.pyplot as plt
import random
# スピンネットワーククラスの定義
class SpinNetwork:
def __init__(self, num_nodes):
self.graph = nx.Graph()
self.num_nodes = num_nodes
self._create_nodes()
self._create_edges()
# ノードの作成
def _create_nodes(self):
for i in range(self.num_nodes):
self.graph.add_node(i, spin=random.choice([-1, 1])) # 各ノードにスピンを割り当てる(-1か1)
# エッジの作成
def _create_edges(self):
for i in range(self.num_nodes):
for j in range(i+1, self.num_nodes):
if random.random() > 0.5: # ランダムにエッジを作成
self.graph.add_edge(i, j, spin=random.choice([-1, 1])) # エッジにスピンを割り当てる
# スピンネットワークの描画
def draw_network(self):
pos = nx.spring_layout(self.graph)
edge_labels = nx.get_edge_attributes(self.graph, 'spin')
node_colors = ['red' if self.graph.nodes[node]['spin'] == 1 else 'blue' for node in self.graph.nodes]
nx.draw(self.graph, pos, with_labels=True, node_color=node_colors, node_size=700, font_color='white')
nx.draw_networkx_edge_labels(self.graph, pos, edge_labels=edge_labels)
plt.show()
# シンプルな相互作用シミュレーション(隣接ノード間でスピンの伝搬)
def simulate(self, steps):
for step in range(steps):
print(f"Step {step + 1}")
for (u, v, data) in self.graph.edges(data=True):
# 隣接するノード間でスピンが一致しない場合、エッジのスピンをノードに伝搬
if self.graph.nodes[u]['spin'] != self.graph.nodes[v]['spin']:
print(f"Node {u} and Node {v} have different spins. Updating edge.")
data['spin'] = self.graph.nodes[u]['spin']
self.draw_network()
# スピンネットワークの作成
num_nodes = 6 # ノード数
network = SpinNetwork(num_nodes)
# ネットワークの描画
network.draw_network()
# スピン相互作用のシミュレーション(5ステップ)
network.simulate(steps=5)
スピンネットワークは、どうやら僕らコンピュータ科学者がセル・オートマトンと呼んでいるものと似た動作をするらしい。
ニューラルネットワークでも、初期のホップフィールドモデルなどは似たような動作をする。こんなところにも量子力学とAIの類似性があって面白い。
スピンネットワークの動きを確認するのに丁度いい現象は何か?
イジングモデルのシミュレーションをやってみて
さっきのスピンネットワークのシミュレータでイジングモデルを作って
import networkx as nx
import matplotlib.pyplot as plt
import random
import numpy as np
# スピンネットワーククラスの定義(イジングモデル版)
class SpinNetworkIsingModel:
def __init__(self, num_nodes, temperature):
self.graph = nx.Graph()
self.num_nodes = num_nodes
self.temperature = temperature
self._create_nodes()
self._create_edges()
# ノードの作成(スピンの初期化)
def _create_nodes(self):
for i in range(self.num_nodes):
self.graph.add_node(i, spin=random.choice([-1, 1])) # 各ノードにスピンを割り当てる(-1か1)
# エッジの作成
def _create_edges(self):
for i in range(self.num_nodes):
for j in range(i + 1, self.num_nodes):
if random.random() > 0.5: # ランダムにエッジを作成
self.graph.add_edge(i, j)
# 隣接スピンと相互作用してエネルギー差を計算
def _calculate_energy(self, node):
spin_sum = 0
for neighbor in self.graph.neighbors(node):
spin_sum += self.graph.nodes[neighbor]['spin']
return -self.graph.nodes[node]['spin'] * spin_sum
# メトロポリスステップ
def _metropolis_step(self):
node = random.choice(list(self.graph.nodes)) # ランダムにノードを選択
# スピンを反転させたときのエネルギー差を計算
delta_E = 2 * self._calculate_energy(node)
# エネルギーが低下する場合、または一定確率でスピンを反転
if delta_E < 0 or random.random() < np.exp(-delta_E / self.temperature):
self.graph.nodes[node]['spin'] = -self.graph.nodes[node]['spin']
# シミュレーション
def simulate(self, steps):
for step in range(steps):
self._metropolis_step()
# ネットワークの描画
def draw_network(self):
pos = nx.spring_layout(self.graph)
node_colors = ['red' if self.graph.nodes[node]['spin'] == 1 else 'blue' for node in self.graph.nodes]
nx.draw(self.graph, pos, with_labels=True, node_color=node_colors, node_size=700, font_color='white')
plt.show()
# スピンネットワークの作成とシミュレーション
num_nodes = 10 # ノード数
temperature = 2.0 # 温度
steps = 10000 # シミュレーションステップ数
spin_network = SpinNetworkIsingModel(num_nodes, temperature)
# 初期状態のスピンネットワークの描画
print("初期状態")
spin_network.draw_network()
# シミュレーションの実行
spin_network.simulate(steps)
# シミュレーション後のスピンネットワークの描画
print("シミュレーション後")
spin_network.draw_network()
実行しろ
なるほどわからん。
同じようにエンタングルメントもシミュレーションしてみて
import matplotlib
matplotlib.use('TkAgg') # または 'Qt5Agg' など
import networkx as nx
import matplotlib.pyplot as plt
import random
# スピンネットワーククラスの定義(擬似エンタングルメント版)
class SpinNetworkEntanglementSim:
def __init__(self, num_nodes):
self.graph = nx.Graph()
self.num_nodes = num_nodes
self._create_nodes()
self._create_edges()
# ノードの作成
def _create_nodes(self):
for i in range(self.num_nodes):
self.graph.add_node(i, spin=random.choice([-1, 1])) # 各ノードにスピンを割り当てる(-1か1)
# エッジの作成
def _create_edges(self):
for i in range(self.num_nodes):
for j in range(i + 1, self.num_nodes):
if random.random() > 0.5: # ランダムにエッジを作成
self.graph.add_edge(i, j, entangled=False) # エンタングルメント状態かどうかのフラグ
# エンタングルメントを作成してエッジに反映
def entangle(self, node1, node2):
# ノード間にエッジがない場合はエッジを追加
if not self.graph.has_edge(node1, node2):
self.graph.add_edge(node1, node2, entangled=False)
# ノードがエンタングル状態としてマークされる
self.graph.edges[node1, node2]['entangled'] = True
print(f"Nodes {node1} and {node2} are now entangled.")
# エンタングルメント状態のスピンが連動して変化する
def update_entangled_spins(self, node1, node2):
if self.graph.edges[node1, node2].get('entangled'):
self.graph.nodes[node2]['spin'] = self.graph.nodes[node1]['spin']
print(f"Node {node2} spin is updated to match Node {node1}'s spin: {self.graph.nodes[node1]['spin']}")
# シミュレーション:指定したノードのスピンを変更し、エンタングルされたノードのスピンも更新
def change_spin(self, node):
self.graph.nodes[node]['spin'] = -self.graph.nodes[node]['spin'] # スピンを反転
for neighbor in self.graph.neighbors(node):
self.update_entangled_spins(node, neighbor)
# エンタングルメントを含むネットワークの描画
def draw_network(self):
pos = nx.spring_layout(self.graph)
node_colors = ['red' if self.graph.nodes[node]['spin'] == 1 else 'blue' for node in self.graph.nodes]
edge_colors = ['green' if self.graph.edges[edge].get('entangled') else 'black' for edge in self.graph.edges]
nx.draw(self.graph, pos, with_labels=True, node_color=node_colors, edge_color=edge_colors, node_size=700, font_color='white')
plt.show()
# スピンネットワークの作成と擬似エンタングルメントシミュレーション
num_nodes = 6 # ノード数
spin_network = SpinNetworkEntanglementSim(num_nodes)
# 初期状態のスピンネットワークの描画
print("初期状態")
spin_network.draw_network()
# 任意の2ノードをエンタングルさせる
spin_network.entangle(0, 1)
spin_network.entangle(2, 3)
# ノードのスピンを変更(エンタングルされたノードも連動して変化)
spin_network.change_spin(0)
spin_network.change_spin(2)
# エンタングルメント後のスピンネットワークの描画
print("エンタングルメント後")
spin_network.draw_network()
なるほどわからん。
あってるのかどうか、ナンセンスなのかどうかすらわからん。
なかなかわからない話というものはあるものだ。
とりあえずファインマン先生の教科書をもう一度読んでみることにしてこの本を注文した。