레플리카 방법: 복제본의 수를 0으로 보낸다
평균 Z와 평균 Z²는 결합에 대한 평균을 쌍마다 따로 내어 손으로 구할 수 있었다. 그런데 실제 계를 알려 주는 것은 로그의 평균이고, 로그는 쌍마다의 인자로 쪼개지지 않는다. 합금 시료 하나의 자유에너지도, 장 첫머리 퍼셉트론의 외우기 경계도 모두 이 로그의 평균을 요구한다. 로그의 평균은 어떻게 구할까? 실마리는 평균 Z²의 계산에 있는데, 배치가 둘일 때 결합을 평균하자 두 배치가 겹침으로 묶였다. 배치가 세 개, 네 개이면 어떻게 될까?
배치 n개와 Zⁿ
Z의 n제곱은 같은 결합 아래 놓인 배치 n개 s¹, …, sⁿ에 대한 합이다. 이 배치들은 결합이라는 무작위성은 함께 나눠 갖되 스핀은 저마다 따로 움직이므로, 계를 n벌 베껴 놓은 것과 같다. 이처럼 무작위 결합은 공유하고 상태는 독립인 계의 사본을 복제본(레플리카, replica)이라 한다. 결합을 평균하면 모든 복제본 짝 (a, b)의 겹침 q_ab가 나타난다.
n = 1, 2, 3, 4이면 이 합을 스핀마다의 방향 조합별 개수로 묶어 빠짐없이 셀 수 있다. 한편 n이 1보다 작으면 결합을 뽑아 Zⁿ을 평균해도 드문 결합에 크게 휘둘리지 않는다. β = 2, 스핀 16개에서 ln(평균 Zⁿ)/(nN)을 계산해 보자. n이 1 이상인 칸은 빠짐없이 센 값이고, 1보다 작은 칸은 결합 2000개로 낸 값이다.
| n | 4 | 3 | 2 | 1 | 0.5 | 0.25 | 0.1 |
|---|---|---|---|---|---|---|---|
| ln(평균 Zⁿ)/(nN) | 3.956 | 3.072 | 2.244 | 1.631 | 1.501 | 1.465 | 1.447 |
같은 결합 2000개로 낸 스핀 하나당 ln Z의 평균, 곧 굳힌 평균은 1.436이다. n을 줄일수록 값이 굳힌 평균 1.436으로 내려가고, n = 1에서는 평균 Z의 로그와 같다. 복제본의 수를 줄이면 왜 굳힌 평균에 다가갈까?
n을 0으로 보내는 극한
표에서 복제본 수 n을 줄이자 ln(평균 Zⁿ)/(nN)이 굳힌 평균 1.436으로 내려간 이유는 간단하다. Zⁿ = e^(n ln Z)를 n이 작을 때 펼치면 1 + n ln Z + …이므로 그 평균은 1 + n × (ln Z의 평균) + …이고, 로그를 씌워 n으로 나누면 n → 0에서 ln Z의 평균만 남는다.
그런데 평균 Zⁿ을 복제본 n개의 계로 정확히 셀 수 있는 것은 n이 정수일 때뿐이고, 정수 n에서 구한 값 몇 개만으로는 n → 0의 값이 정해지지 않는다. 그래서 스핀이 많은 극한에서 평균 Zⁿ을 겹침 q_ab에 대한 식의 극값으로 적어 n에 대한 식을 먼저 얻고, 이 평균 Zⁿ의 n에 대한 식을 0으로 잇는다. 예를 들어 모든 복제본 쌍의 겹침이 같은 값 q라고 두면, 지수 안의 Σ_(a<b) q_ab²는 쌍의 수 n(n − 1)/2에 q²를 곱한 것이 된다. n(n − 1)/2는 n의 다항식이라 정수가 아닌 n에도 값이 있다. n = 0.5를 넣으면 −0.125, 곧 쌍의 수가 음수라는 기묘한 값이 나오지만, 레플리카 방법은 이런 식을 그대로 n → 0으로 잇는다. 이렇게 정수 n에서 평균 Zⁿ을 복제본 n개의 계로 계산한 뒤 n에 대한 식으로 적어 n → 0으로 이어 굳힌 평균을 얻는 절차를 레플리카 방법 (복제본의 수를 0으로 보내 로그의 평균을 얻는 계산, replica method)이라 한다. 이때 복제본들의 겹침이 어떤 모양일지에 대한 가정이 필요하고, 그 가정이 이 방법에서 가장 어려운 부분이다.
flowchart LR
A["구하려는 것<br/>ln Z의 굳힌 평균"] --> B["정수 n에서 Zⁿ<br/>= 복제본 n개의 계"]
B --> C["결합을 평균<br/>복제본이 겹침 q_ab로 끌어당김"]
C --> D["스핀이 많은 극한<br/>q_ab에 대한 극값"]
D --> E["겹침 모양을 가정<br/>(레플리카 대칭 등)"]
E --> F["n에 대한 식을<br/>n → 0으로 이음"]
F --> G["굳힌 평균<br/>= lim ln(평균 Zⁿ)/n"]
역사: 고무에서 합금으로
정수에서 계산한 식을 0으로 잇는 생각은 스핀 글래스보다 먼저 여러 곳에서 따로 나왔다. 1968년 수학자 카츠는 질량이 무작위인 진동자들을 한 줄로 이은 계를 다루면서, 정수 거듭제곱으로만 계산되는 식을 양의 실수로 이어 붙이자는 「지극히 합리적인」 추측을 강연 원고에 적었다. 맨체스터의 에드워즈는 고무를 연구하고 있었다. 고무 분자를 잇는 가교는 시료마다 무작위로 놓이지만 한 시료 안에서는 고정되어 있어, 합금처럼 로그의 평균이 필요했다. 에드워즈는 계를 n벌 베껴 놓고 n이 작을 때로 펼쳤고, 정수를 실수로 잇는 데에는 개의치 않았다. 1974년 케임브리지에서 앤더슨에게 스핀 글래스 문제를 들은 에드워즈는 젤 문제를 풀다 노트에 적어 둔 방법이 여기에 꼭 맞는다고 보았고, 앤더슨의 회고에 따르면 길어야 두 주 만에 복제본 풀이를 들고 왔다. 1975년 두 사람의 논문은 ln Z = lim (Zⁿ − 1)/n이라는 항등식에서 출발한다. 앤더슨은 그 논문 앞부분에 따로 적은 평균장 계산이 복제본이라는 낯선 수학을 검산해 주어 반가웠다고 돌아보았다.
코드: 로그의 평균과 평균의 로그
지금까지 스핀 16개로 낸 수를 그대로 돌린다. 결합을 2000번 뽑아 굳힌 평균을 내고 풀린 평균, 샘플로 낸 평균 Z의 로그, 평균 Z에서 상위 1% 결합이 차지하는 비율과 비교한다. 평균 Z²는 겹침으로 묶어 빠짐없이 세고, n이 1보다 작은 평균 Zⁿ은 샘플로 낸다.
import numpy as np
from scipy.special import logsumexp, gammaln
rng = np.random.default_rng(0)
# 스핀 16개, 모든 쌍 (i, j)에 평균 0·분산 1/N인 무작위 결합. 에너지 E(s) = −Σ_{i<j} J_ij s_i s_j
N, M = 16, 2000 # 스핀 수, 결합을 뽑는 횟수
S = 1.0 - 2 * ((np.arange(2**N)[:, None] >> np.arange(N)) & 1) # 배치 65536개
def sample_J():
J = np.triu(rng.normal(0, 1 / np.sqrt(N), (N, N)), 1)
return J + J.T
betas = (0.5, 2.0, 3.0)
lnZ = np.zeros((len(betas), M))
for m in range(M):
J = sample_J()
E = -0.5 * ((S @ J) * S).sum(1)
lnZ[:, m] = [logsumexp(-b * E) for b in betas]
k = np.arange(N + 1); q = (2 * k - N) / N # 두 복제본의 겹침 q (같은 방향인 스핀 k개)
log_count = gammaln(N + 1) - gammaln(k + 1) - gammaln(N - k + 1)
for i, b in enumerate(betas):
a = lnZ[i]
quenched = a.mean() / N # 굳힌 평균: ln Z를 먼저, 평균은 나중에
annealed = np.log(2) + b**2 * (N - 1) / (4 * N) # 풀린 평균: ln(평균 Z)는 가우스 적분으로 정확히
sampled = (logsumexp(a) - np.log(M)) / N # 샘플 2000개의 평균 Z로 낸 풀린 평균
top = np.sort(np.exp(a - a.max()))[::-1]
# 평균 Z²: 결합을 평균하면 두 복제본이 겹침 q로 묶인다 (정확한 합)
lnZ2 = 2 * N * np.log(2) + b**2 * (N - 1) / 2 - b**2 / 2 + logsumexp(log_count - N * np.log(2) + N * b**2 * q**2 / 2)
print(f"β = {b}: 굳힌 평균 {quenched:.3f}, 풀린 평균 {annealed:.3f} (샘플로 {sampled:.3f}), "
f"상위 1% 결합이 차지하는 비율 {top[:M // 100].sum() / top.sum():.2f}")
print(f" ln(평균 Z² / (평균 Z)²) = {lnZ2 - 2 * N * annealed:.2f}, (1/nN) ln(평균 Z^n): "
+ ", ".join(f"n = {n}에서 {(logsumexp(n * a) - np.log(M)) / (n * N):.3f}" for n in (0.5, 0.25, 0.1)))
# β = 0.5: 굳힌 평균 0.751, 풀린 평균 0.752 (샘플로 0.752), 상위 1% 결합이 차지하는 비율 0.01
# ln(평균 Z² / (평균 Z)²) = 0.02, (1/nN) ln(평균 Z^n): n = 0.5에서 0.752, n = 0.25에서 0.752, n = 0.1에서 0.752
# β = 2.0: 굳힌 평균 1.436, 풀린 평균 1.631 (샘플로 1.591), 상위 1% 결합이 차지하는 비율 0.62
# ln(평균 Z² / (평균 Z)²) = 19.61, (1/nN) ln(평균 Z^n): n = 0.5에서 1.501, n = 0.25에서 1.465, n = 0.1에서 1.447
# β = 3.0: 굳힌 평균 2.039, 풀린 평균 2.803 (샘플로 2.451), 상위 1% 결합이 차지하는 비율 0.93
# ln(평균 Z² / (평균 Z)²) = 57.10, (1/nN) ln(평균 Z^n): n = 0.5에서 2.244, n = 0.25에서 2.126, n = 0.1에서 2.070
역온도 3에서는 굳힌 평균 2.039, 풀린 평균 2.803, 샘플로 낸 평균 Z의 로그 2.451이 모두 다르고, n을 줄이면 ln(평균 Zⁿ)/(nN)이 굳힌 평균 쪽으로 내려간다.
문제 6. 정수에서 0으로 이어 붙이기
β = 2, 스핀 16개에서 ln(평균 Zⁿ)/(nN)을 n = 1, 2, 3, 4에서 빠짐없이 세면 1.631, 2.244, 3.072, 3.956이다. (가) 이 네 값으로 n = 0의 값을 어림하라. (나) 굳힌 평균 1.436과 비교하고, 어긋나는 이유를 설명하라.

네 점을 지나는 3차 다항식을 맞추고 n = 0을 넣었어요. 1.395예요. 1.436과 0.04 차이면 레플리카 방법 별거 아니네요.

나는 1, 2, 3 세 점으로 2차식을 맞췄는데 1.234가 나왔어. 1과 2 두 점을 직선으로 이으면 1.018이고. 어떤 점을 쓰느냐에 따라 1.0에서 1.4까지 흔들려.

그럼 β = 3에서도 해 볼게요. 3차식으로 1.397… 굳힌 평균은 2.04쯤인데요? 이건 완전히 틀렸어요.

애초에 정수에서의 값으로는 n = 0의 값이 정해지지 않아. 정수에서 0이 되는 sin(πn)을 아무 계수로 곱해 더해도 정수 값은 그대로잖아.

그래요. 레플리카 방법은 정수 몇 개를 잇는 게 아니에요. 스핀이 많은 극한에서 평균 Zⁿ을 겹침에 대한 식의 극값으로 적어 n에 대한 식을 먼저 얻고, 이 n의 식을 0으로 보내요. n의 식 자체가 복제본들의 겹침 모양에 대한 가정에 달려 있다는 게 문제고요.

스핀 수를 무한대로 보내는 극한과 n을 0으로 보내는 극한의 순서를 바꾸는 거네요. 해석학에서는 그러면 안 되는 예를 잔뜩 배웠는데요.

사울리스, 앤더슨, 파머도 1977년 논문에서 바로 그 점, 극한 순서를 부적절하게 바꾼 것이 잘못된 해의 원인이라고 지적했어요. 이 계산이 수학적으로 옳다는 증명은 2006년에야 끝났고, 그동안 물리학자들은 시뮬레이션과 비교하며 이 방법을 썼어요.