chess-model / abc_model.py
test1978's picture
Add abc_model.py
9df07fa verified
Raw History Blame
8.85 kB
"""
abc_model.py - ABC Model with Displacement Matrices (CORRECTED FOR KAPPA)
KEY INSIGHT:
- B_i represents the DISPLACEMENT from current MB position to new position
- If MB is at (x₁, y₁) and we place piece at (x₂, y₂):
- Δx = x₂ - x₁
- Δy = y₂ - y₁
- B has right column (Δx, Δy, 1)ᵀ
Example:
- Stage 0: MB at (0, 0, 1)
- Stage 1: Place at (-1, -1) → Δ = (-1-0, -1-0) = (-1, -1)
- B₁ right column: (-1, -1, 1)ᵀ
- Stage 2: Place at (0, 0) → Δ = (0-(-1), 0-(-1)) = (1, 1)
- B₂ right column: (1, 1, 1)ᵀ ✓
Author: Chaim Duchovny
Date: January 25, 2026 (FIXED FOR KAPPA SUPPORT)
"""
import numpy as np
class ABCModelDynamic:
"""ABC Model with displacement-based B matrices."""
def __init__(self, n: int = 2, t: float = 1.0, T: float = 1.41):
"""
Initialize for 2D board.
Args:
n: Dimension (2 for 2D board)
t: Minimum distance threshold for adjacency
T: Maximum distance threshold for adjacency
"""
self.n = n
self.t = t
self.T = T
self.c0 = np.array([0.0, 0.0, 1.0])
self.B_blocks = [] # Displacement matrices
self.piece_positions = [] # Actual positions on SB
self.a_product = np.eye(3) # Accumulated product
self.delta = {} # Delta values for each piece
self.kappa = {} # Tokenized vectors for each piece (ADDED)
self.stage = 0
# MB position tracking
self.MB_current = self.c0.copy() # Current MB center
self.MB_previous = self.c0.copy() # Previous MB center
self.history = []
def create_B_displacement(self, dx: float, dy: float) -> np.ndarray:
"""
Create displacement matrix B.
Moves MB by (dx, dy) displacement.
B · current_MB = new_MB
B = [1 0 dx]
[0 1 dy]
[0 0 1]
Right column: (dx, dy, 1)ᵀ
"""
B = np.array([
[1.0, 0.0, dx],
[0.0, 1.0, dy],
[0.0, 0.0, 1.0]
])
return B
def add_piece(self, position: tuple, delta_values: tuple, kappa_vector: np.ndarray = None):
"""
Add a piece at position with delta values and optional kappa vector.
Args:
position: (x, y) tuple
delta_values: (Δ₁, Δ₂, Δ₃) tuple
kappa_vector: Tokenized feature vector (optional, defaults to delta_values)
"""
x, y = position
# Current MB position
current_MB = self.MB_current.copy()
# Calculate displacement
dx = x - current_MB[0]
dy = y - current_MB[1]
# Create displacement matrix
B_i = self.create_B_displacement(dx, dy)
# Store
idx = len(self.B_blocks)
self.B_blocks.append(B_i)
self.piece_positions.append((x, y))
# Update accumulated product: a_t = a_{t-1} · B_t
self.a_product = self.a_product @ B_i
# Track MB positions
self.MB_previous = self.MB_current.copy()
self.MB_current = self.a_product @ self.c0 # Should equal (x, y, 1)
# Store differential vector
self.delta[idx] = delta_values
# Store tokenized vector (or use delta_values as default)
if kappa_vector is None:
kappa_vector = np.array(delta_values)
self.kappa[idx] = kappa_vector
# Increment stage
self.stage += 1
# Record move
self.history.append({
'stage': self.stage,
'SB_position': (x, y),
'displacement': (dx, dy),
'B_i': B_i.copy(),
'a_t': self.a_product.copy(),
'MB_prev': self.MB_previous.copy(),
'MB_curr': self.MB_current.copy(),
'delta': delta_values,
'kappa': kappa_vector.copy()
})
def add_move(self, x: float, y: float, player: int):
"""
Convenience method: Add a move with automatic delta values.
Args:
x, y: Position coordinates
player: 1 for X (Δ₂=1.0), 2 for O (Δ₂=1.1)
"""
delta_1 = 1.0 # Occupied
delta_2 = 1.0 if player == 1 else 1.1 # Player color
delta_3 = 1.0 # Same value for all pieces
self.add_piece((x, y), (delta_1, delta_2, delta_3))
def get_board_state(self) -> str:
"""Visual board state."""
pos_map = {
(-1, 1): 0, (0, 1): 1, (1, 1): 2,
(-1, 0): 3, (0, 0): 4, (1, 0): 5,
(-1, -1): 6, (0, -1): 7, (1, -1): 8
}
board = [' '] * 9
for i, pos in enumerate(self.piece_positions):
if pos in pos_map:
player = 'X' if self.delta[i][1] == 1.0 else 'O'
board[pos_map[pos]] = player
s = f" {board[0]} | {board[1]} | {board[2]} \n"
s += "---|---|---\n"
s += f" {board[3]} | {board[4]} | {board[5]} \n"
s += "---|---|---\n"
s += f" {board[6]} | {board[7]} | {board[8]} \n"
return s
def describe_move(self, stage: int):
"""Describe a specific move."""
if stage < 1 or stage > len(self.history):
return "Invalid stage"
move = self.history[stage - 1]
desc = "=" * 70 + "\n"
desc += f"MOVE {stage}: {move['SB_position']}\n"
desc += "=" * 70 + "\n\n"
idx = stage - 1
B_i = self.B_blocks[idx]
desc += f"Mobile Board (MB) movement:\n"
desc += f" Previous MB: {move['MB_prev']}\n"
desc += f" Target (SB): {move['SB_position']}\n"
desc += f" Displacement: Δ = {move['displacement']}\n"
desc += f" New MB: {move['MB_curr']}\n\n"
desc += f"Displacement matrix B_{stage}:\n{B_i}\n"
desc += f"Right column: {B_i[:, 2]} = (Δx={move['displacement'][0]}, Δy={move['displacement'][1]}, 1)\n\n"
desc += f"Accumulated product a_{stage}:\n{move['a_t']}\n"
desc += f"Right column: {move['a_t'][:, 2]}\n\n"
desc += f"Delta values: {move['delta']}\n"
desc += f"Kappa vector: {move['kappa']}\n\n"
desc += f"Verification:\n"
desc += f" a_{stage} · c₀ = {move['a_t'] @ self.c0}\n"
desc += f" Should equal: {np.array([move['SB_position'][0], move['SB_position'][1], 1.0])}\n\n"
desc += "Board state:\n"
desc += self.get_board_state()
return desc
if __name__ == "__main__":
print("\n" + "=" * 70)
print("TIC-TAC-TOE - DISPLACEMENT-BASED B MATRICES")
print("=" * 70 + "\n")
game = ABCModelDynamic(n=2, t=1.0, T=1.41)
# Play complete game
moves = [
((-1, -1), 1), # Move 1: X at (-1,-1)
((0, 0), 2), # Move 2: O at (0,0)
((0, -1), 1), # Move 3: X at (0,-1)
((1, 0), 2), # Move 4: O at (1,0)
]
for pos, player in moves:
game.add_move(pos[0], pos[1], player)
# Show first 4 moves in detail
for i in range(1, 5):
print(game.describe_move(i))
print()
# Verification
print("=" * 70)
print("VERIFICATION")
print("=" * 70 + "\n")
print("Key property: MB position tracks piece positions on SB")
for i in range(1, len(game.history) + 1):
move = game.history[i - 1]
MB_curr = move['MB_curr']
SB_pos = move['SB_position']
matches = np.allclose(MB_curr[:2], SB_pos)
print(f"Move {i}: MB={MB_curr} SB={SB_pos} Match? {matches} {'✓' if matches else '❌'}")
print(f"\nB matrices (right columns = displacements):")
for i in range(1, len(game.history) + 1):
move = game.history[i - 1]
B_i = game.B_blocks[i - 1]
disp = move['displacement']
right_col = B_i[:, 2]
print(f" Move {i}: Δ={disp} → B right column = {right_col} ✓")
print(f"\nKappa vectors (tokenized features):")
for i in range(len(game.history)):
kappa = game.kappa[i]
print(f" Piece {i}: κ = {kappa}")
print(f"\nSpecial case - Move 2:")
move2 = game.history[1]
print(f" From (-1, -1) to (0, 0)")
print(f" Displacement: {move2['displacement']}")
print(f" B₂ right column: {game.B_blocks[1][:, 2]} = (1, 1, 1)ᵀ ✓✓✓")
print("\n✓ MB position correctly tracks SB piece positions!")
print("✓ B matrices represent displacements!")
print("✓ B₂ has right column (1, 1, 1)ᵀ as expected!")
print("✓ Kappa vectors initialized correctly!")
print("=" * 70 + "\n")