test1978 commited on
Commit
9df07fa
·
verified ·
1 Parent(s): c2b5eda

Add abc_model.py

Browse files
Files changed (1) hide show
  1. abc_model.py +262 -0
abc_model.py ADDED
@@ -0,0 +1,262 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ abc_model.py - ABC Model with Displacement Matrices (CORRECTED FOR KAPPA)
3
+
4
+ KEY INSIGHT:
5
+ - B_i represents the DISPLACEMENT from current MB position to new position
6
+ - If MB is at (x₁, y₁) and we place piece at (x₂, y₂):
7
+ - Δx = x₂ - x₁
8
+ - Δy = y₂ - y₁
9
+ - B has right column (Δx, Δy, 1)ᵀ
10
+
11
+ Example:
12
+ - Stage 0: MB at (0, 0, 1)
13
+ - Stage 1: Place at (-1, -1) → Δ = (-1-0, -1-0) = (-1, -1)
14
+ - B₁ right column: (-1, -1, 1)ᵀ
15
+ - Stage 2: Place at (0, 0) → Δ = (0-(-1), 0-(-1)) = (1, 1)
16
+ - B₂ right column: (1, 1, 1)ᵀ ✓
17
+
18
+ Author: Chaim Duchovny
19
+ Date: January 25, 2026 (FIXED FOR KAPPA SUPPORT)
20
+ """
21
+
22
+ import numpy as np
23
+
24
+ class ABCModelDynamic:
25
+ """ABC Model with displacement-based B matrices."""
26
+
27
+ def __init__(self, n: int = 2, t: float = 1.0, T: float = 1.41):
28
+ """
29
+ Initialize for 2D board.
30
+
31
+ Args:
32
+ n: Dimension (2 for 2D board)
33
+ t: Minimum distance threshold for adjacency
34
+ T: Maximum distance threshold for adjacency
35
+ """
36
+ self.n = n
37
+ self.t = t
38
+ self.T = T
39
+ self.c0 = np.array([0.0, 0.0, 1.0])
40
+ self.B_blocks = [] # Displacement matrices
41
+ self.piece_positions = [] # Actual positions on SB
42
+ self.a_product = np.eye(3) # Accumulated product
43
+ self.delta = {} # Delta values for each piece
44
+ self.kappa = {} # Tokenized vectors for each piece (ADDED)
45
+ self.stage = 0
46
+
47
+ # MB position tracking
48
+ self.MB_current = self.c0.copy() # Current MB center
49
+ self.MB_previous = self.c0.copy() # Previous MB center
50
+ self.history = []
51
+
52
+ def create_B_displacement(self, dx: float, dy: float) -> np.ndarray:
53
+ """
54
+ Create displacement matrix B.
55
+
56
+ Moves MB by (dx, dy) displacement.
57
+
58
+ B · current_MB = new_MB
59
+
60
+ B = [1 0 dx]
61
+ [0 1 dy]
62
+ [0 0 1]
63
+
64
+ Right column: (dx, dy, 1)ᵀ
65
+ """
66
+ B = np.array([
67
+ [1.0, 0.0, dx],
68
+ [0.0, 1.0, dy],
69
+ [0.0, 0.0, 1.0]
70
+ ])
71
+ return B
72
+
73
+ def add_piece(self, position: tuple, delta_values: tuple, kappa_vector: np.ndarray = None):
74
+ """
75
+ Add a piece at position with delta values and optional kappa vector.
76
+
77
+ Args:
78
+ position: (x, y) tuple
79
+ delta_values: (Δ₁, Δ₂, Δ₃) tuple
80
+ kappa_vector: Tokenized feature vector (optional, defaults to delta_values)
81
+ """
82
+ x, y = position
83
+
84
+ # Current MB position
85
+ current_MB = self.MB_current.copy()
86
+
87
+ # Calculate displacement
88
+ dx = x - current_MB[0]
89
+ dy = y - current_MB[1]
90
+
91
+ # Create displacement matrix
92
+ B_i = self.create_B_displacement(dx, dy)
93
+
94
+ # Store
95
+ idx = len(self.B_blocks)
96
+ self.B_blocks.append(B_i)
97
+ self.piece_positions.append((x, y))
98
+
99
+ # Update accumulated product: a_t = a_{t-1} · B_t
100
+ self.a_product = self.a_product @ B_i
101
+
102
+ # Track MB positions
103
+ self.MB_previous = self.MB_current.copy()
104
+ self.MB_current = self.a_product @ self.c0 # Should equal (x, y, 1)
105
+
106
+ # Store differential vector
107
+ self.delta[idx] = delta_values
108
+
109
+ # Store tokenized vector (or use delta_values as default)
110
+ if kappa_vector is None:
111
+ kappa_vector = np.array(delta_values)
112
+ self.kappa[idx] = kappa_vector
113
+
114
+ # Increment stage
115
+ self.stage += 1
116
+
117
+ # Record move
118
+ self.history.append({
119
+ 'stage': self.stage,
120
+ 'SB_position': (x, y),
121
+ 'displacement': (dx, dy),
122
+ 'B_i': B_i.copy(),
123
+ 'a_t': self.a_product.copy(),
124
+ 'MB_prev': self.MB_previous.copy(),
125
+ 'MB_curr': self.MB_current.copy(),
126
+ 'delta': delta_values,
127
+ 'kappa': kappa_vector.copy()
128
+ })
129
+
130
+ def add_move(self, x: float, y: float, player: int):
131
+ """
132
+ Convenience method: Add a move with automatic delta values.
133
+
134
+ Args:
135
+ x, y: Position coordinates
136
+ player: 1 for X (Δ₂=1.0), 2 for O (Δ₂=1.1)
137
+ """
138
+ delta_1 = 1.0 # Occupied
139
+ delta_2 = 1.0 if player == 1 else 1.1 # Player color
140
+ delta_3 = 1.0 # Same value for all pieces
141
+
142
+ self.add_piece((x, y), (delta_1, delta_2, delta_3))
143
+
144
+ def get_board_state(self) -> str:
145
+ """Visual board state."""
146
+ pos_map = {
147
+ (-1, 1): 0, (0, 1): 1, (1, 1): 2,
148
+ (-1, 0): 3, (0, 0): 4, (1, 0): 5,
149
+ (-1, -1): 6, (0, -1): 7, (1, -1): 8
150
+ }
151
+
152
+ board = [' '] * 9
153
+ for i, pos in enumerate(self.piece_positions):
154
+ if pos in pos_map:
155
+ player = 'X' if self.delta[i][1] == 1.0 else 'O'
156
+ board[pos_map[pos]] = player
157
+
158
+ s = f" {board[0]} | {board[1]} | {board[2]} \n"
159
+ s += "---|---|---\n"
160
+ s += f" {board[3]} | {board[4]} | {board[5]} \n"
161
+ s += "---|---|---\n"
162
+ s += f" {board[6]} | {board[7]} | {board[8]} \n"
163
+ return s
164
+
165
+ def describe_move(self, stage: int):
166
+ """Describe a specific move."""
167
+ if stage < 1 or stage > len(self.history):
168
+ return "Invalid stage"
169
+
170
+ move = self.history[stage - 1]
171
+ desc = "=" * 70 + "\n"
172
+ desc += f"MOVE {stage}: {move['SB_position']}\n"
173
+ desc += "=" * 70 + "\n\n"
174
+
175
+ idx = stage - 1
176
+ B_i = self.B_blocks[idx]
177
+
178
+ desc += f"Mobile Board (MB) movement:\n"
179
+ desc += f" Previous MB: {move['MB_prev']}\n"
180
+ desc += f" Target (SB): {move['SB_position']}\n"
181
+ desc += f" Displacement: Δ = {move['displacement']}\n"
182
+ desc += f" New MB: {move['MB_curr']}\n\n"
183
+
184
+ desc += f"Displacement matrix B_{stage}:\n{B_i}\n"
185
+ desc += f"Right column: {B_i[:, 2]} = (Δx={move['displacement'][0]}, Δy={move['displacement'][1]}, 1)\n\n"
186
+
187
+ desc += f"Accumulated product a_{stage}:\n{move['a_t']}\n"
188
+ desc += f"Right column: {move['a_t'][:, 2]}\n\n"
189
+
190
+ desc += f"Delta values: {move['delta']}\n"
191
+ desc += f"Kappa vector: {move['kappa']}\n\n"
192
+
193
+ desc += f"Verification:\n"
194
+ desc += f" a_{stage} · c₀ = {move['a_t'] @ self.c0}\n"
195
+ desc += f" Should equal: {np.array([move['SB_position'][0], move['SB_position'][1], 1.0])}\n\n"
196
+
197
+ desc += "Board state:\n"
198
+ desc += self.get_board_state()
199
+
200
+ return desc
201
+
202
+
203
+ if __name__ == "__main__":
204
+ print("\n" + "=" * 70)
205
+ print("TIC-TAC-TOE - DISPLACEMENT-BASED B MATRICES")
206
+ print("=" * 70 + "\n")
207
+
208
+ game = ABCModelDynamic(n=2, t=1.0, T=1.41)
209
+
210
+ # Play complete game
211
+ moves = [
212
+ ((-1, -1), 1), # Move 1: X at (-1,-1)
213
+ ((0, 0), 2), # Move 2: O at (0,0)
214
+ ((0, -1), 1), # Move 3: X at (0,-1)
215
+ ((1, 0), 2), # Move 4: O at (1,0)
216
+ ]
217
+
218
+ for pos, player in moves:
219
+ game.add_move(pos[0], pos[1], player)
220
+
221
+ # Show first 4 moves in detail
222
+ for i in range(1, 5):
223
+ print(game.describe_move(i))
224
+ print()
225
+
226
+ # Verification
227
+ print("=" * 70)
228
+ print("VERIFICATION")
229
+ print("=" * 70 + "\n")
230
+
231
+ print("Key property: MB position tracks piece positions on SB")
232
+ for i in range(1, len(game.history) + 1):
233
+ move = game.history[i - 1]
234
+ MB_curr = move['MB_curr']
235
+ SB_pos = move['SB_position']
236
+ matches = np.allclose(MB_curr[:2], SB_pos)
237
+ print(f"Move {i}: MB={MB_curr} SB={SB_pos} Match? {matches} {'✓' if matches else '❌'}")
238
+
239
+ print(f"\nB matrices (right columns = displacements):")
240
+ for i in range(1, len(game.history) + 1):
241
+ move = game.history[i - 1]
242
+ B_i = game.B_blocks[i - 1]
243
+ disp = move['displacement']
244
+ right_col = B_i[:, 2]
245
+ print(f" Move {i}: Δ={disp} → B right column = {right_col} ✓")
246
+
247
+ print(f"\nKappa vectors (tokenized features):")
248
+ for i in range(len(game.history)):
249
+ kappa = game.kappa[i]
250
+ print(f" Piece {i}: κ = {kappa}")
251
+
252
+ print(f"\nSpecial case - Move 2:")
253
+ move2 = game.history[1]
254
+ print(f" From (-1, -1) to (0, 0)")
255
+ print(f" Displacement: {move2['displacement']}")
256
+ print(f" B₂ right column: {game.B_blocks[1][:, 2]} = (1, 1, 1)ᵀ ✓✓✓")
257
+
258
+ print("\n✓ MB position correctly tracks SB piece positions!")
259
+ print("✓ B matrices represent displacements!")
260
+ print("✓ B₂ has right column (1, 1, 1)ᵀ as expected!")
261
+ print("✓ Kappa vectors initialized correctly!")
262
+ print("=" * 70 + "\n")