test1978 commited on
Commit
1b5ebf0
·
verified ·
1 Parent(s): 7556a03

Migrate to load(ctx)/get_move(state, fen, player) contract

Browse files
Files changed (1) hide show
  1. chess_mcvs.py +70 -21
chess_mcvs.py CHANGED
@@ -1,15 +1,15 @@
1
- # chess_mcvs.py
2
  """
3
  chess_mcvs.py - Full implementation analogous to breakthrough_mcvs.py
4
 
5
  Features:
6
  - Chess game logic using python-chess (full rules)
7
- - Fixed 64×64 padded weighted adjacency matrix (Hilbert-ordered pieces)
8
  - Piece-specific kappa values
9
  - Queen-only promotions for flat 4096 policy head compatibility
10
  - Policy and Value CNNs (lightweight with pooling for feasibility)
11
  - HilbertOrderedZoneDatabase with add methods and proper k-NN zone score
12
- - MCVSSearcher (guided λ-PUCT with policy/value/zone)
13
  - UCTSearcher (baseline)
14
  - train_networks function
15
  - Ready for chess_mcvs_vs_uct.py tournament
@@ -97,13 +97,13 @@ class ABCModelDynamic:
97
 
98
  Moves MB by (dx, dy) displacement.
99
 
100
- B · current_MB = new_MB
101
 
102
  B = [1 0 dx]
103
  [0 1 dy]
104
  [0 0 1]
105
 
106
- Right column: (dx, dy, 1)ᵀ
107
  """
108
  B = np.array([
109
  [1.0, 0.0, dx],
@@ -118,7 +118,7 @@ class ABCModelDynamic:
118
 
119
  Args:
120
  position: (x, y) tuple
121
- delta_values: (Δ₁, Δ₂, Δ₃) tuple
122
  kappa_vector: Tokenized feature vector (optional, defaults to delta_values)
123
  """
124
  x, y = position
@@ -138,7 +138,7 @@ class ABCModelDynamic:
138
  self.B_blocks.append(B_i)
139
  self.piece_positions.append((x, y))
140
 
141
- # Update accumulated product: a_t = a_{t-1} · B_t
142
  self.a_product = self.a_product @ B_i
143
 
144
  # Track MB positions
@@ -175,7 +175,7 @@ class ABCModelDynamic:
175
 
176
  Args:
177
  x, y: Position coordinates
178
- player: 1 for X (Δ₂=1.0), 2 for O (Δ₂=1.1)
179
  """
180
  delta_1 = 1.0 # Occupied
181
  delta_2 = 1.0 if player == 1 else 1.1 # Player color
@@ -220,10 +220,10 @@ class ABCModelDynamic:
220
  desc += f"Mobile Board (MB) movement:\n"
221
  desc += f" Previous MB: {move['MB_prev']}\n"
222
  desc += f" Target (SB): {move['SB_position']}\n"
223
- desc += f" Displacement: Δ = {move['displacement']}\n"
224
  desc += f" New MB: {move['MB_curr']}\n\n"
225
  desc += f"Displacement matrix B_{stage}:\n{B_i}\n"
226
- desc += f"Right column: {B_i[:, 2]} = (Δx={move['displacement'][0]}, Δy={move['displacement'][1]}, 1)\n\n"
227
 
228
  desc += f"Accumulated product a_{stage}:\n{move['a_t']}\n"
229
  desc += f"Right column: {move['a_t'][:, 2]}\n\n"
@@ -232,7 +232,7 @@ class ABCModelDynamic:
232
  desc += f"Kappa vector: {move['kappa']}\n\n"
233
 
234
  desc += f"Verification:\n"
235
- desc += f" a_{stage} · c₀ = {move['a_t'] @ self.c0}\n"
236
  desc += f" Should equal: {np.array([move['SB_position'][0], move['SB_position'][1], 1.0])}\n\n"
237
 
238
  desc += "Board state:\n"
@@ -249,7 +249,7 @@ class WeightedMatrixABC:
249
  to match algebraic structure of B matrices from abc_model.py
250
 
251
  Implements Definition from Section 6:
252
- W[i,j](t) = A[i,j](t) ⊙ S[i,j](t) ⊙ F[i,j](t)
253
  """
254
 
255
  def __init__(self, abc_model: ABCModelDynamic, sigma: float = 1.0):
@@ -300,7 +300,7 @@ class WeightedMatrixABC:
300
  Compute pairwise Euclidean distances using 2D components only.
301
 
302
  Even though positions are [x, y, 1], we compute distance using only [x, y]
303
- D[i,j] = ||[x_i, y_i] - [x_j, y_j]||₂
304
  """
305
  if self.positions is None:
306
  self.compute_piece_positions()
@@ -323,7 +323,7 @@ class WeightedMatrixABC:
323
  Compute Adjacency Matrix (Definition 6.2).
324
 
325
  A[i,j] = 1 if:
326
- - k ≤ D[i,j] ≤ K (grid-adjacent)
327
  - i == j AND i is isolated (no neighbors in [k,K])
328
 
329
  A[i,j] = 0 otherwise
@@ -362,7 +362,7 @@ class WeightedMatrixABC:
362
  """
363
  Compute Spatial Matrix (Definition 6.3).
364
 
365
- S[i,j](t) = exp(-||c_i(t) - c_j(t)||² / (2σ²))
366
 
367
  Gaussian kernel based on Euclidean distance.
368
  """
@@ -383,7 +383,7 @@ class WeightedMatrixABC:
383
  """
384
  Compute Feature Matrix (Definition 6.4).
385
 
386
- F[i,j](t) = <κ(B_i), κ(B_j)> / (||κ(B_i)|| · ||κ(B_j)||)
387
 
388
  Cosine similarity between tokenized vectors.
389
  """
@@ -424,7 +424,7 @@ class WeightedMatrixABC:
424
  """
425
  Compute Weighted Matrix (Definition from Section 6).
426
 
427
- W[i,j](t) = A[i,j](t) ⊙ S[i,j](t) ⊙ F[i,j](t)
428
 
429
  Returns: W - the full weighted matrix
430
  """
@@ -445,7 +445,7 @@ class WeightedMatrixABC:
445
  """
446
  Compute Manhattan distance between two weighted matrices.
447
 
448
- distance = ||W_1 - W_2||₁
449
  """
450
  if self.W is None:
451
  self.compute_weighted_matrix()
@@ -753,10 +753,10 @@ class HilbertOrderedZoneDatabase:
753
  )
754
 
755
  new_sizes = (len(self.winning_matrices), len(self.losing_matrices), len(self.draw_matrices))
756
- print(f"Pruned: W {old_sizes}→{new_sizes}, L {old_sizes}→{new_sizes}, D {old_sizes}→{new_sizes}")
757
 
758
  def compute_zone_score(self, W: np.ndarray, k: int = 5, beta: float = 0.5) -> float:
759
- """Compute zone guidance score Z(x(t), a) ∈ [-1, 1]."""
760
  if W.shape != (64, 64):
761
  return 0.0
762
 
@@ -1133,4 +1133,53 @@ class UCTSearcher:
1133
  return visits, simulations
1134
 
1135
  if __name__ == "__main__":
1136
- print("chess_mcvs.py loaded successfully")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # chess_mcvs.py
2
  """
3
  chess_mcvs.py - Full implementation analogous to breakthrough_mcvs.py
4
 
5
  Features:
6
  - Chess game logic using python-chess (full rules)
7
+ - Fixed 64�64 padded weighted adjacency matrix (Hilbert-ordered pieces)
8
  - Piece-specific kappa values
9
  - Queen-only promotions for flat 4096 policy head compatibility
10
  - Policy and Value CNNs (lightweight with pooling for feasibility)
11
  - HilbertOrderedZoneDatabase with add methods and proper k-NN zone score
12
+ - MCVSSearcher (guided ?-PUCT with policy/value/zone)
13
  - UCTSearcher (baseline)
14
  - train_networks function
15
  - Ready for chess_mcvs_vs_uct.py tournament
 
97
 
98
  Moves MB by (dx, dy) displacement.
99
 
100
+ B � current_MB = new_MB
101
 
102
  B = [1 0 dx]
103
  [0 1 dy]
104
  [0 0 1]
105
 
106
+ Right column: (dx, dy, 1)?
107
  """
108
  B = np.array([
109
  [1.0, 0.0, dx],
 
118
 
119
  Args:
120
  position: (x, y) tuple
121
+ delta_values: (??, ??, ??) tuple
122
  kappa_vector: Tokenized feature vector (optional, defaults to delta_values)
123
  """
124
  x, y = position
 
138
  self.B_blocks.append(B_i)
139
  self.piece_positions.append((x, y))
140
 
141
+ # Update accumulated product: a_t = a_{t-1} � B_t
142
  self.a_product = self.a_product @ B_i
143
 
144
  # Track MB positions
 
175
 
176
  Args:
177
  x, y: Position coordinates
178
+ player: 1 for X (??=1.0), 2 for O (??=1.1)
179
  """
180
  delta_1 = 1.0 # Occupied
181
  delta_2 = 1.0 if player == 1 else 1.1 # Player color
 
220
  desc += f"Mobile Board (MB) movement:\n"
221
  desc += f" Previous MB: {move['MB_prev']}\n"
222
  desc += f" Target (SB): {move['SB_position']}\n"
223
+ desc += f" Displacement: ? = {move['displacement']}\n"
224
  desc += f" New MB: {move['MB_curr']}\n\n"
225
  desc += f"Displacement matrix B_{stage}:\n{B_i}\n"
226
+ desc += f"Right column: {B_i[:, 2]} = (?x={move['displacement'][0]}, ?y={move['displacement'][1]}, 1)\n\n"
227
 
228
  desc += f"Accumulated product a_{stage}:\n{move['a_t']}\n"
229
  desc += f"Right column: {move['a_t'][:, 2]}\n\n"
 
232
  desc += f"Kappa vector: {move['kappa']}\n\n"
233
 
234
  desc += f"Verification:\n"
235
+ desc += f" a_{stage} � c? = {move['a_t'] @ self.c0}\n"
236
  desc += f" Should equal: {np.array([move['SB_position'][0], move['SB_position'][1], 1.0])}\n\n"
237
 
238
  desc += "Board state:\n"
 
249
  to match algebraic structure of B matrices from abc_model.py
250
 
251
  Implements Definition from Section 6:
252
+ W[i,j](t) = A[i,j](t) ? S[i,j](t) ? F[i,j](t)
253
  """
254
 
255
  def __init__(self, abc_model: ABCModelDynamic, sigma: float = 1.0):
 
300
  Compute pairwise Euclidean distances using 2D components only.
301
 
302
  Even though positions are [x, y, 1], we compute distance using only [x, y]
303
+ D[i,j] = ||[x_i, y_i] - [x_j, y_j]||?
304
  """
305
  if self.positions is None:
306
  self.compute_piece_positions()
 
323
  Compute Adjacency Matrix (Definition 6.2).
324
 
325
  A[i,j] = 1 if:
326
+ - k ? D[i,j] ? K (grid-adjacent)
327
  - i == j AND i is isolated (no neighbors in [k,K])
328
 
329
  A[i,j] = 0 otherwise
 
362
  """
363
  Compute Spatial Matrix (Definition 6.3).
364
 
365
+ S[i,j](t) = exp(-||c_i(t) - c_j(t)||� / (2?�))
366
 
367
  Gaussian kernel based on Euclidean distance.
368
  """
 
383
  """
384
  Compute Feature Matrix (Definition 6.4).
385
 
386
+ F[i,j](t) = <?(B_i), ?(B_j)> / (||?(B_i)|| � ||?(B_j)||)
387
 
388
  Cosine similarity between tokenized vectors.
389
  """
 
424
  """
425
  Compute Weighted Matrix (Definition from Section 6).
426
 
427
+ W[i,j](t) = A[i,j](t) ? S[i,j](t) ? F[i,j](t)
428
 
429
  Returns: W - the full weighted matrix
430
  """
 
445
  """
446
  Compute Manhattan distance between two weighted matrices.
447
 
448
+ distance = ||W_1 - W_2||?
449
  """
450
  if self.W is None:
451
  self.compute_weighted_matrix()
 
753
  )
754
 
755
  new_sizes = (len(self.winning_matrices), len(self.losing_matrices), len(self.draw_matrices))
756
+ print(f"Pruned: W {old_sizes}?{new_sizes}, L {old_sizes}?{new_sizes}, D {old_sizes}?{new_sizes}")
757
 
758
  def compute_zone_score(self, W: np.ndarray, k: int = 5, beta: float = 0.5) -> float:
759
+ """Compute zone guidance score Z(x(t), a) ? [-1, 1]."""
760
  if W.shape != (64, 64):
761
  return 0.0
762
 
 
1133
  return visits, simulations
1134
 
1135
  if __name__ == "__main__":
1136
+ print("chess_mcvs.py loaded successfully")
1137
+
1138
+
1139
+ def load(ctx):
1140
+ """Platform contract: read the zone db from ctx.data_dir ourselves."""
1141
+ from pathlib import Path
1142
+
1143
+ search_dirs = [d for d in (ctx.data_dir, ctx.model_dir) if d is not None]
1144
+ npz_path = None
1145
+ for d in search_dirs:
1146
+ candidates = sorted(Path(d).rglob("*.npz"))
1147
+ if candidates:
1148
+ npz_path = candidates[0]
1149
+ break
1150
+ if npz_path is None:
1151
+ raise FileNotFoundError(
1152
+ "no zone-db .npz file found under data_dir or model_dir — "
1153
+ "this model requires one to function"
1154
+ )
1155
+ return HilbertOrderedZoneDatabase(filepath=str(npz_path))
1156
+
1157
+
1158
+ def get_move(state, fen: str, player: str, time_budget: float = 2.0) -> str:
1159
+ import chess as _chess
1160
+ import json
1161
+ from pathlib import Path
1162
+
1163
+ config_path = Path(__file__).parent / "config_model.json"
1164
+ config = json.loads(config_path.read_text()) if config_path.exists() else {}
1165
+
1166
+ game = Chess()
1167
+ game.board = _chess.Board(fen)
1168
+ zone_db = state
1169
+ searcher = MCVSSearcher(
1170
+ policy_net=None,
1171
+ value_net=None,
1172
+ zone_db=zone_db,
1173
+ use_nets=False,
1174
+ lambda_zone=0.0 if zone_db is None else float(config.get("lambda_zone", 1.0)),
1175
+ k_zone=int(config.get("k_zone", 5)),
1176
+ cpuct=float(config.get("cpuct", 1.5)),
1177
+ dirichlet_alpha=float(config.get("dirichlet_alpha", 0.3)),
1178
+ )
1179
+ time_budget = float(config.get("time_per_move", 2.0))
1180
+ visit_counts, _ = searcher.search_with_time_budget(game, time_budget)
1181
+ if not visit_counts:
1182
+ legal = game.get_legal_moves()
1183
+ return legal[0].uci() if legal else ""
1184
+ best_move = max(visit_counts, key=visit_counts.get)
1185
+ return best_move.uci()