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

Add matrix_model.py

Browse files
Files changed (1) hide show
  1. matrix_model.py +481 -0
matrix_model.py ADDED
@@ -0,0 +1,481 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Matrix Model - TRULY FINAL CORRECTED Implementation
3
+ ABC Model with Weighted Adjacency Matrix (THREE components)
4
+
5
+ CRITICAL INSIGHT FROM abc_model.py:
6
+ - piece_positions stored as (x, y) tuples
7
+ - BUT MB_current = a_product @ c0 produces [x, y, 1] homogeneous coords
8
+ - These are the SAME locations!
9
+
10
+ For matrix computations with B matrices, we MUST use homogeneous coordinates [x, y, 1]
11
+ to match the algebraic structure.
12
+
13
+ Implements Definition from Section 6:
14
+ W[i,j](t) = A[i,j](t) βŠ™ S[i,j](t) βŠ™ F[i,j](t)
15
+
16
+ Author: Chaim Duchovny
17
+ Date: January 25, 2026 (TRULY FINAL CORRECTED)
18
+ """
19
+
20
+ import numpy as np
21
+ from typing import Tuple
22
+
23
+ class ABCModelDynamic:
24
+ """ABC Model with displacement-based B matrices."""
25
+
26
+ def __init__(self, n: int = 2, t: float = 1.0, T: float = 1.41):
27
+ """Initialize for 2D board."""
28
+ self.n = n
29
+ self.t = t
30
+ self.T = T
31
+ self.c0 = np.array([0.0, 0.0, 1.0])
32
+ self.B_blocks = []
33
+ self.piece_positions = [] # Stores (x, y) tuples
34
+ self.a_product = np.eye(3)
35
+ self.kappa = {}
36
+ self.delta = {}
37
+ self.stage = 0
38
+ self.MB_current = self.c0.copy()
39
+ self.MB_previous = self.c0.copy()
40
+ self.history = []
41
+
42
+ def create_B_displacement(self, dx: float, dy: float) -> np.ndarray:
43
+ """Create displacement matrix B."""
44
+ B = np.array([
45
+ [1.0, 0.0, dx],
46
+ [0.0, 1.0, dy],
47
+ [0.0, 0.0, 1.0]
48
+ ])
49
+ return B
50
+
51
+ def add_piece(self, position: tuple, delta_values: tuple, kappa_vector: np.ndarray = None):
52
+ """
53
+ Add a piece at position with delta values and tokenized vector.
54
+
55
+ Args:
56
+ position: (x, y) tuple - 2D coordinates from board
57
+ delta_values: (δ₁, Ξ΄β‚‚, δ₃) tuple
58
+ kappa_vector: tokenized vector ΞΊ(B_i)
59
+ """
60
+ x, y = position
61
+ current_MB = self.MB_current.copy()
62
+ dx = x - current_MB[0]
63
+ dy = y - current_MB[1]
64
+
65
+ B_i = self.create_B_displacement(dx, dy)
66
+ idx = len(self.B_blocks)
67
+
68
+ self.B_blocks.append(B_i)
69
+ self.piece_positions.append((x, y)) # Store as 2D tuple (board representation)
70
+ self.a_product = self.a_product @ B_i
71
+
72
+ self.MB_previous = self.MB_current.copy()
73
+ self.MB_current = self.a_product @ self.c0 # Homogeneous coords [x, y, 1]
74
+
75
+ self.delta[idx] = delta_values
76
+
77
+ if kappa_vector is None:
78
+ kappa_vector = np.array(delta_values)
79
+ self.kappa[idx] = kappa_vector
80
+
81
+ self.stage += 1
82
+
83
+ self.history.append({
84
+ 'stage': self.stage,
85
+ 'SB_position': (x, y),
86
+ 'displacement': (dx, dy),
87
+ 'B_i': B_i.copy(),
88
+ 'a_t': self.a_product.copy(),
89
+ 'MB_prev': self.MB_previous.copy(),
90
+ 'MB_curr': self.MB_current.copy(),
91
+ 'delta': delta_values,
92
+ 'kappa': kappa_vector.copy() if kappa_vector is not None else None
93
+ })
94
+
95
+
96
+ class WeightedMatrixABC:
97
+ """
98
+ Compute weighted adjacency matrix from ABCModelDynamic.
99
+
100
+ CRITICAL: Converts (x,y) tuples to homogeneous coords [x,y,1]
101
+ to match algebraic structure of B matrices from abc_model.py
102
+
103
+ Implements Definition from Section 6:
104
+ W[i,j](t) = A[i,j](t) βŠ™ S[i,j](t) βŠ™ F[i,j](t)
105
+ """
106
+
107
+ def __init__(self, abc_model: ABCModelDynamic, sigma: float = 1.0):
108
+ """
109
+ Initialize with ABC model instance.
110
+
111
+ Args:
112
+ abc_model: ABCModelDynamic instance
113
+ sigma: Standard deviation for Gaussian spatial kernel
114
+ """
115
+ self.abc = abc_model
116
+ self.n = abc_model.n
117
+ self.t = abc_model.t
118
+ self.T = abc_model.T
119
+ self.sigma = sigma
120
+ self.positions = None # Will store homogeneous coords [x, y, 1]
121
+ self.D = None
122
+ self.A = None
123
+ self.S = None
124
+ self.F = None
125
+ self.W = None
126
+
127
+ def compute_piece_positions(self) -> np.ndarray:
128
+ """
129
+ Extract positions from ABC model and convert to homogeneous coordinates.
130
+
131
+ In abc_model.py:
132
+ - piece_positions are (x, y) tuples
133
+ - MB_current = a_product @ c0 produces [x, y, 1]
134
+
135
+ For matrix computations, convert to homogeneous coords to match
136
+ the algebraic structure of B matrices.
137
+
138
+ Returns: Array of shape (num_pieces, 3) with homogeneous coords [x, y, 1]
139
+ """
140
+ positions = []
141
+ for pos in self.abc.piece_positions:
142
+ # pos is (x, y) from piece_positions
143
+ x, y = pos
144
+ # Convert to homogeneous coordinates to align with B matrix algebra
145
+ positions.append(np.array([x, y, 1.0]))
146
+
147
+ self.positions = np.array(positions)
148
+ return self.positions
149
+
150
+ def compute_distance_matrix(self) -> np.ndarray:
151
+ """
152
+ Compute pairwise Euclidean distances using 2D components only.
153
+
154
+ Even though positions are [x, y, 1], we compute distance using only [x, y]
155
+ D[i,j] = ||[x_i, y_i] - [x_j, y_j]||β‚‚
156
+ """
157
+ if self.positions is None:
158
+ self.compute_piece_positions()
159
+
160
+ num = len(self.positions)
161
+ D = np.zeros((num, num))
162
+
163
+ for i in range(num):
164
+ for j in range(num):
165
+ # Use only 2D coordinates for distance
166
+ pos_i = self.positions[i][:2]
167
+ pos_j = self.positions[j][:2]
168
+ D[i, j] = np.linalg.norm(pos_i - pos_j)
169
+
170
+ self.D = D
171
+ return D
172
+
173
+ def compute_adjacency_matrix(self) -> np.ndarray:
174
+ """
175
+ Compute Adjacency Matrix (Definition 6.2).
176
+
177
+ A[i,j] = 1 if:
178
+ - k ≀ D[i,j] ≀ K (grid-adjacent)
179
+ - i == j AND i is isolated (no neighbors in [k,K])
180
+
181
+ A[i,j] = 0 otherwise
182
+ """
183
+ if self.D is None:
184
+ self.compute_distance_matrix()
185
+
186
+ num = len(self.positions)
187
+ A = np.zeros((num, num))
188
+
189
+ # Identify isolated pieces
190
+ isolated = set()
191
+ for i in range(num):
192
+ has_neighbor = False
193
+ for j in range(num):
194
+ if i != j and self.t <= self.D[i, j] <= self.T:
195
+ has_neighbor = True
196
+ break
197
+ if not has_neighbor:
198
+ isolated.add(i)
199
+
200
+ # Fill adjacency matrix
201
+ for i in range(num):
202
+ for j in range(num):
203
+ # Check adjacency distance
204
+ if i != j and self.t <= self.D[i, j] <= self.T:
205
+ A[i, j] = 1.0
206
+ # Check if isolated piece
207
+ elif i == j and i in isolated:
208
+ A[i, j] = 1.0
209
+
210
+ self.A = A
211
+ return A
212
+
213
+ def compute_spatial_matrix(self) -> np.ndarray:
214
+ """
215
+ Compute Spatial Matrix (Definition 6.3).
216
+
217
+ S[i,j](t) = exp(-||c_i(t) - c_j(t)||Β² / (2σ²))
218
+
219
+ Gaussian kernel based on Euclidean distance.
220
+ """
221
+ if self.D is None:
222
+ self.compute_distance_matrix()
223
+
224
+ num = len(self.positions)
225
+ S = np.zeros((num, num))
226
+
227
+ for i in range(num):
228
+ for j in range(num):
229
+ S[i, j] = np.exp(-self.D[i, j]**2 / (2 * self.sigma**2))
230
+
231
+ self.S = S
232
+ return S
233
+
234
+ def compute_feature_matrix(self) -> np.ndarray:
235
+ """
236
+ Compute Feature Matrix (Definition 6.4).
237
+
238
+ F[i,j](t) = <ΞΊ(B_i), ΞΊ(B_j)> / (||ΞΊ(B_i)|| Β· ||ΞΊ(B_j)||)
239
+
240
+ Cosine similarity between tokenized vectors.
241
+ """
242
+ num = len(self.positions)
243
+ F = np.zeros((num, num))
244
+
245
+ # Extract tokenized vectors
246
+ kappas = []
247
+ for i in range(num):
248
+ if i in self.abc.kappa:
249
+ kappas.append(self.abc.kappa[i])
250
+ else:
251
+ # Default: use delta as feature vector
252
+ if i in self.abc.delta:
253
+ kappas.append(np.array(self.abc.delta[i]))
254
+ else:
255
+ kappas.append(np.array([1.0, 1.0, 1.0]))
256
+
257
+ # Compute cosine similarity
258
+ for i in range(num):
259
+ for j in range(num):
260
+ kappa_i = kappas[i]
261
+ kappa_j = kappas[j]
262
+
263
+ dot_product = np.dot(kappa_i, kappa_j)
264
+ norm_i = np.linalg.norm(kappa_i)
265
+ norm_j = np.linalg.norm(kappa_j)
266
+
267
+ if norm_i > 0 and norm_j > 0:
268
+ F[i, j] = dot_product / (norm_i * norm_j)
269
+ else:
270
+ F[i, j] = 0.0
271
+
272
+ self.F = F
273
+ return F
274
+
275
+ def compute_weighted_matrix(self) -> np.ndarray:
276
+ """
277
+ Compute Weighted Matrix (Definition from Section 6).
278
+
279
+ W[i,j](t) = A[i,j](t) βŠ™ S[i,j](t) βŠ™ F[i,j](t)
280
+
281
+ Returns: W - the full weighted matrix
282
+ """
283
+ if self.A is None:
284
+ self.compute_adjacency_matrix()
285
+ if self.S is None:
286
+ self.compute_spatial_matrix()
287
+ if self.F is None:
288
+ self.compute_feature_matrix()
289
+
290
+ # Hadamard product (element-wise multiplication)
291
+ W = self.A * self.S * self.F
292
+
293
+ self.W = W
294
+ return W
295
+
296
+ def compute_manhattan_distance(self, other: 'WeightedMatrixABC') -> float:
297
+ """
298
+ Compute Manhattan distance between two weighted matrices.
299
+
300
+ distance = ||W_1 - W_2||₁
301
+ """
302
+ if self.W is None:
303
+ self.compute_weighted_matrix()
304
+ if other.W is None:
305
+ other.compute_weighted_matrix()
306
+
307
+ W1 = self.W
308
+ W2 = other.W
309
+
310
+ # Pad to same size
311
+ size = max(len(W1), len(W2))
312
+ W1_padded = np.zeros((size, size))
313
+ W2_padded = np.zeros((size, size))
314
+ W1_padded[:len(W1), :len(W1)] = W1
315
+ W2_padded[:len(W2), :len(W2)] = W2
316
+
317
+ return np.linalg.norm(W1_padded - W2_padded, ord=1)
318
+
319
+
320
+ # ============================================================================
321
+ # EXAMPLE 1: Two Adjacent Pieces (matches abc_model.py format)
322
+ # ============================================================================
323
+
324
+ def example_1():
325
+ """Two adjacent pieces - exactly like abc_model.py."""
326
+ print("\n" + "="*80)
327
+ print("EXAMPLE 1: Two Adjacent Pieces")
328
+ print("="*80)
329
+
330
+ game = ABCModelDynamic(n=2, t=1.0, T=1.41)
331
+
332
+ # Add pieces exactly like abc_model.py does
333
+ game.add_piece((1.0, 0.0), (1.0, 1.0, 1.0),
334
+ kappa_vector=np.array([1.0, 1.0, 1.0]))
335
+
336
+ game.add_piece((1.0, 1.0), (1.0, 1.1, 1.0),
337
+ kappa_vector=np.array([1.0, 1.1, 1.0]))
338
+
339
+ print("\nABC Model piece_positions (as stored in abc_model.py):")
340
+ print(f" Piece 0: {game.piece_positions[0]} (tuple from board)")
341
+ print(f" Piece 1: {game.piece_positions[1]} (tuple from board)")
342
+
343
+ print("\nABC Model MB positions (homogeneous coords):")
344
+ for i, move in enumerate(game.history):
345
+ print(f" Piece {i}: MB_curr = {move['MB_curr']} (homogeneous)")
346
+
347
+ matrix = WeightedMatrixABC(game, sigma=1.0)
348
+
349
+ # Extract and convert to homogeneous coordinates
350
+ positions = matrix.compute_piece_positions()
351
+ print("\nConverted to homogeneous coordinates for matrix computations:")
352
+ print(positions)
353
+
354
+ # Distance matrix
355
+ D = matrix.compute_distance_matrix()
356
+ print("\n1. DISTANCE MATRIX D[i,j] (2D distance only):")
357
+ print(D.round(3))
358
+ print(f"\nD[0,1] = {D[0,1]:.3f} ∈ [{game.t}, {game.T}]? {game.t <= D[0,1] <= game.T} βœ“")
359
+
360
+ # Adjacency matrix
361
+ A = matrix.compute_adjacency_matrix()
362
+ print("\n2. ADJACENCY MATRIX A[i,j]:")
363
+ print(A.astype(int))
364
+
365
+ # Spatial matrix
366
+ S = matrix.compute_spatial_matrix()
367
+ print("\n3. SPATIAL MATRIX S[i,j] (Gaussian):")
368
+ print(S.round(3))
369
+
370
+ # Feature matrix
371
+ F = matrix.compute_feature_matrix()
372
+ print("\n4. FEATURE MATRIX F[i,j] (cosine similarity):")
373
+ print(F.round(3))
374
+
375
+ # Weighted matrix
376
+ W = matrix.compute_weighted_matrix()
377
+ print("\n5. WEIGHTED MATRIX W[i,j] = A βŠ™ S βŠ™ F:")
378
+ print(W.round(3))
379
+ print(f"\nW[0,1] = {A[0,1]:.0f} Γ— {S[0,1]:.3f} Γ— {F[0,1]:.3f} = {W[0,1]:.3f} βœ“")
380
+
381
+ print("\n" + "="*80)
382
+
383
+
384
+ # ============================================================================
385
+ # EXAMPLE 2: Three Pieces with Isolation
386
+ # ============================================================================
387
+
388
+ def example_2():
389
+ """Three pieces with mixed adjacency."""
390
+ print("\n" + "="*80)
391
+ print("EXAMPLE 2: Three Pieces with Isolation")
392
+ print("="*80)
393
+
394
+ game = ABCModelDynamic(n=2, t=1.0, T=1.41)
395
+
396
+ game.add_piece((0.0, 0.0), (1.0, 1.0, 1.0),
397
+ kappa_vector=np.array([1.0, 1.0, 1.0]))
398
+
399
+ game.add_piece((1.0, 0.0), (1.0, 1.0, 1.0),
400
+ kappa_vector=np.array([1.0, 1.0, 1.0]))
401
+
402
+ game.add_piece((3.0, 3.0), (1.0, 1.1, 1.0),
403
+ kappa_vector=np.array([1.0, 1.1, 1.0]))
404
+
405
+ print("\nPiece Positions (from abc_model.py storage):")
406
+ for i, pos in enumerate(game.piece_positions):
407
+ mb = game.history[i]['MB_curr']
408
+ print(f" Piece {i}: stored={pos}, MB={mb}")
409
+
410
+ matrix = WeightedMatrixABC(game, sigma=1.0)
411
+
412
+ # Distance matrix
413
+ D = matrix.compute_distance_matrix()
414
+ print("\n1. DISTANCE MATRIX D[i,j]:")
415
+ print(D.round(3))
416
+ print(f"\nD[0,1] = {D[0,1]:.3f} β†’ adjacent βœ“")
417
+ print(f"D[0,2] = {D[0,2]:.3f} β†’ isolated")
418
+ print(f"D[1,2] = {D[1,2]:.3f} β†’ isolated")
419
+
420
+ # Adjacency matrix
421
+ A = matrix.compute_adjacency_matrix()
422
+ print("\n2. ADJACENCY MATRIX A[i,j]:")
423
+ print(A.astype(int))
424
+ print(f"\nA[0,1] = {int(A[0,1])} (adjacent) βœ“")
425
+ print(f"A[2,2] = {int(A[2,2])} (isolated piece!) βœ“")
426
+
427
+ # Spatial matrix
428
+ S = matrix.compute_spatial_matrix()
429
+ print("\n3. SPATIAL MATRIX S[i,j]:")
430
+ print(S.round(3))
431
+
432
+ # Feature matrix
433
+ F = matrix.compute_feature_matrix()
434
+ print("\n4. FEATURE MATRIX F[i,j]:")
435
+ print(F.round(3))
436
+
437
+ # Weighted matrix
438
+ W = matrix.compute_weighted_matrix()
439
+ print("\n5. WEIGHTED MATRIX W[i,j] = A βŠ™ S βŠ™ F:")
440
+ print(W.round(6))
441
+ print(f"\nW[0,1] = {A[0,1]:.0f} Γ— {S[0,1]:.3f} Γ— {F[0,1]:.3f} = {W[0,1]:.3f} βœ“")
442
+ print(f"W[2,2] = {A[2,2]:.0f} Γ— {S[2,2]:.3f} Γ— {F[2,2]:.3f} = {W[2,2]:.3f} βœ“")
443
+ print(f"W[0,2] = {A[0,2]:.0f} Γ— {S[0,2]:.6f} Γ— {F[0,2]:.3f} = {W[0,2]:.6f} βœ“")
444
+
445
+ print("\n" + "="*80)
446
+
447
+
448
+ if __name__ == "__main__":
449
+ print("\n" + "="*80)
450
+ print("WEIGHTED MATRIX IMPLEMENTATION (TRULY FINAL CORRECTED)")
451
+ print("Section 6: W[i,j](t) = A[i,j] βŠ™ S[i,j] βŠ™ F[i,j]")
452
+ print("Aligned with abc_model.py: Converts (x,y) to [x,y,1] homogeneous coords")
453
+ print("="*80)
454
+
455
+ example_1()
456
+ example_2()
457
+
458
+ print("\n" + "="*80)
459
+ print("KEY ALIGNMENT WITH abc_model.py")
460
+ print("="*80)
461
+ print("""
462
+ abc_model.py structure:
463
+ - piece_positions: stored as (x, y) tuples [2D board representation]
464
+ - MB_current: calculated as a_product @ c0 = [x, y, 1] [homogeneous]
465
+ - These represent the SAME location on the board
466
+
467
+ matrix_model.py now:
468
+ - Reads piece_positions as (x, y) from abc_model
469
+ - Converts to [x, y, 1] homogeneous coordinates
470
+ - Computes distances using 2D components [x, y]
471
+ - Applies matrix algebra correctly
472
+
473
+ Result:
474
+ - Pieces treated as [x, y, 1] internally
475
+ - Positions (1.0, 0.0) β†’ [1.0, 0.0, 1.0]
476
+ - Positions (1.0, 1.0) β†’ [1.0, 1.0, 1.0]
477
+ - Matrix dimensions: num_pieces Γ— num_pieces
478
+ - Distance uses only 2D components
479
+ - Full algebraic alignment with abc_model.py
480
+ """)
481
+ print("="*80 + "\n")