1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
;;; Copyright (c) 2026 Nicholas Vermeulen
;;; SPDX-License-Identifier: AGPL-3.0-or-later
;; anneal.lisp — seeded simulated annealing / hill-climb with an exhaustive
;; optimum ORACLE on tiny discrete domains. Pure Lisp, zero interpreter changes.
;;
;; Every accept/reject is recorded as data in a trajectory log. The KEY
;; verification is not "SA found the optimum" — SA is NEVER called optimal.
;; Instead: check-exhaustive (or a full enumeration helper) recovers the true
;; minimum cost over a declared finite set (4-city TSP / tiny subset-sum), and
;; SA under a fixed seed returns a FIXED cost C that can be cross-checked
;; (C ≥ oracle-min always; equality is luck, not a claim).
;;
;; CLAIM DISCIPLINE:
;; SA "found cost C under seed S"
;; oracle "is the minimum over the declared finite set"
;; NEVER "SA is optimal", "converged", or "global minimum via annealing".
;; ── Seeded LCG ────────────────────────────────────────────────────────────
;; ── Trajectory log entry: (step T cost accepted? move) ────────────────────
;; Public runners return (list final-state final-cost log).
;; Metropolis accept: always if dE≤0; else if u < exp(-dE/T).
;; ⚠️ exp is libm — used only inside a boolean decision, never printed.
;; Generic SA: state, cost-fn, neighbor-fn, T0, cool, steps.
;; neighbor-fn: state -> (list new-state move-tag)
;; Hill-climb: only accept improving (or equal) moves; no temperature.
;; ── 4-city TSP ────────────────────────────────────────────────────────────
;; Cities 0..3; tour is a permutation list starting with fixed city 0
;; (reduce symmetry). Distance matrix as nested lists; dist i j = (nth (nth D i) j).
;; All tours: permutations of {1,2,3} prefixed with 0.
;; Exhaustive optimum oracle: min cost over all tours in the declared set.
;; Neighbor: swap two random positions in the tour (not index 0 — keep start fixed).
;; ── Tiny subset-sum (optional second oracle domain) ───────────────────────
;; State = bit mask as list of 0/1 of length n; cost = |sum selected - target|.
;; Enumerate all 2^n bit vectors (n small).
;; ── Exhaustive verification over the REAL tour domain ─────────────────────
;; The oracle's minimum is a true lower bound: EVERY tour in the declared set
;; costs at least it — check-exhaustive over the actual tours, so a
;; refutation would name the offending tour.
;; Claiming a bound one above the oracle minimum must be refused — and the
;; witnesses are exactly the OPTIMAL tours (the refutation names them).
;; For a SYMMETRIC distance matrix, reversing a tour (start pinned at 0)
;; leaves its cost unchanged — proven over every tour in the set.