Spaces:
Runtime error
Runtime error
| """ | |
| LOGOS Fractal-Galois Engine (Advanced Implementation) | |
| Quadtree-based interpreter with GF(4) arithmetic core | |
| For hierarchical 16K → 512B decomposition | |
| """ | |
| import numpy as np | |
| from enum import Enum | |
| import logging | |
| class GF4: | |
| """Galois Field GF(4) operations on 2-bit pairs""" | |
| # GF(4) addition table (XOR-like) | |
| ADD_TABLE = [ | |
| [0, 1, 2, 3], # 00 + {00,01,10,11} | |
| [1, 0, 3, 2], # 01 + {00,01,10,11} | |
| [2, 3, 0, 1], # 10 + {00,01,10,11} | |
| [3, 2, 1, 0] # 11 + {00,01,10,11} | |
| ] | |
| # GF(4) multiplication table | |
| MUL_TABLE = [ | |
| [0, 0, 0, 0], # 00 * {00,01,10,11} | |
| [0, 1, 2, 3], # 01 * {00,01,10,11} | |
| [0, 2, 3, 1], # 10 * {00,01,10,11} | |
| [0, 3, 1, 2] # 11 * {00,01,10,11} | |
| ] | |
| def add(a, b): | |
| """GF(4) addition (XOR for change deltas)""" | |
| return GF4.ADD_TABLE[a][b] | |
| def multiply(a, b): | |
| """GF(4) multiplication (for dissolution/scaling)""" | |
| return GF4.MUL_TABLE[a][b] | |
| def dissolve_atom(current_state_vector, input_vector, heat_coefficient): | |
| """ | |
| Dissolve atom using GF(4) vector math | |
| Simulates "Heat" modifying "Structure" | |
| Args: | |
| current_state_vector: List of 2-bit values (current state) | |
| input_vector: List of 2-bit values (input delta) | |
| heat_coefficient: 2-bit value (heat intensity) | |
| Returns: | |
| New state vector after dissolution | |
| """ | |
| result = [] | |
| for cs, iv in zip(current_state_vector, input_vector): | |
| # Multiply input by heat coefficient (scaling) | |
| scaled_input = GF4.multiply(iv, heat_coefficient) | |
| # Add to current state (change delta) | |
| new_state = GF4.add(cs, scaled_input) | |
| result.append(new_state) | |
| return result | |
| class Quadrant(Enum): | |
| """Quadtree quadrants""" | |
| TL = 0 # Top-Left | |
| TR = 1 # Top-Right | |
| BL = 2 # Bottom-Left | |
| BR = 3 # Bottom-Right | |
| class ContextAction(Enum): | |
| """Binary context control bits""" | |
| PERSIST = 0 # 00: Update heat_state only (reinforce structure) | |
| CHANGE_1 = 1 # 01: Trigger dissolution | |
| CHANGE_2 = 2 # 10: Trigger dissolution | |
| RESET = 3 # 11: Clear node (dissolve to null) | |
| class FractalQuadTreeNode: | |
| """Node in the Fractal Quadtree""" | |
| def __init__(self, depth, parent=None): | |
| self.depth = depth # 0=Root/16K, 1=4K, 2=1K, 3=256B, 4=Atom/512B | |
| self.parent = parent | |
| # Node state | |
| self.matrix_key = None # Hex RGB Matrix signature (Structure) | |
| self.heat_state = 0 # Current entropy/dissolution level (Delta) [0-3] | |
| # Children (for non-leaf nodes) | |
| self.children = [None, None, None, None] # TL, TR, BL, BR | |
| # Leaf node data (for depth 4 / Atom level) | |
| self.atom_data = None | |
| def get_quadrant(self, quadrant): | |
| """Get or create child node for quadrant""" | |
| if self.children[quadrant.value] is None: | |
| self.children[quadrant.value] = FractalQuadTreeNode( | |
| self.depth + 1, | |
| parent=self | |
| ) | |
| return self.children[quadrant.value] | |
| def is_leaf(self): | |
| """Check if node is at atom level (depth 4)""" | |
| return self.depth >= 4 | |
| class LogosFractalEngine: | |
| """ | |
| Fractal-Galois Interpreter | |
| Processes 512-byte atoms into hierarchical Quadtree | |
| Resolves visuals via GF(4) vector math | |
| """ | |
| def __init__(self, min_bucket_size=64): | |
| """ | |
| Initialize Fractal Engine | |
| Args: | |
| min_bucket_size: Minimum bucket size in pixels (termination condition) | |
| """ | |
| self.root = FractalQuadTreeNode(depth=0) | |
| self.min_bucket_size = min_bucket_size | |
| self.logger = logging.getLogger('LogosFractalEngine') | |
| def resolve_fractal_address(self, heat_code_int, canvas_size): | |
| """ | |
| Decode 32-bit heat code to spatial ZoneRect via quadtree descent | |
| Logic: | |
| - Read 32 bits as 16 levels of 2-bit pairs (MSB to LSB) | |
| - Each pair selects a quadrant (00=TL, 01=TR, 10=BL, 11=BR) | |
| - Traverse quadtree by subdividing canvas recursively | |
| - Stop when bucket_size reached or stop sequence detected | |
| Args: | |
| heat_code_int: Integer representation of 4-byte heat code | |
| canvas_size: (width, height) tuple of canvas dimensions | |
| Returns: | |
| ZoneRect: (x, y, width, height) defining target region for 512B atom | |
| """ | |
| canvas_width, canvas_height = canvas_size | |
| # Initialize current rect to full canvas | |
| x = 0.0 | |
| y = 0.0 | |
| w = float(canvas_width) | |
| h = float(canvas_height) | |
| # Process 32 bits as 16 levels of 2-bit pairs (MSB first) | |
| # Bits 31-30 = Level 1, Bits 29-28 = Level 2, ..., Bits 1-0 = Level 16 | |
| for level in range(16): | |
| # Extract 2-bit pair for this level (MSB to LSB) | |
| bit_offset = 31 - (level * 2) | |
| quadrant_bits = (heat_code_int >> bit_offset) & 0b11 | |
| # Check for stop sequence (0000 at end - all zeros means stop early) | |
| if quadrant_bits == 0 and level > 8: # Only stop if we've descended reasonably | |
| # Check if next few bits are also zero (stop sequence) | |
| if level < 15: | |
| next_bits = (heat_code_int >> (bit_offset - 2)) & 0b11 | |
| if next_bits == 0: | |
| break # Stop sequence detected | |
| # Branch based on quadrant selection | |
| # 00 = Top-Left, 01 = Top-Right, 10 = Bottom-Left, 11 = Bottom-Right | |
| if quadrant_bits == 0b00: # Top-Left | |
| # No translation, just subdivide | |
| w /= 2.0 | |
| h /= 2.0 | |
| elif quadrant_bits == 0b01: # Top-Right | |
| x += w / 2.0 | |
| w /= 2.0 | |
| h /= 2.0 | |
| elif quadrant_bits == 0b10: # Bottom-Left | |
| y += h / 2.0 | |
| w /= 2.0 | |
| h /= 2.0 | |
| elif quadrant_bits == 0b11: # Bottom-Right | |
| x += w / 2.0 | |
| y += h / 2.0 | |
| w /= 2.0 | |
| h /= 2.0 | |
| # Termination: Stop when region is small enough for bucket | |
| if w <= self.min_bucket_size or h <= self.min_bucket_size: | |
| break | |
| # Ensure we have at least minimum bucket size | |
| w = max(w, self.min_bucket_size) | |
| h = max(h, self.min_bucket_size) | |
| # Clamp to canvas bounds | |
| x = max(0, min(x, canvas_width - 1)) | |
| y = max(0, min(y, canvas_height - 1)) | |
| w = min(w, canvas_width - x) | |
| h = min(h, canvas_height - y) | |
| # Convert to integers for pixel coordinates | |
| zone_rect = (int(x), int(y), int(w), int(h)) | |
| return zone_rect | |
| def fractal_to_bucket_coords(self, heat_code_int, num_buckets_x, num_buckets_y): | |
| """ | |
| Convert fractal address to discrete bucket coordinates | |
| This is a helper that uses fractal addressing but returns bucket indices | |
| Useful for integration with bucket-based display interpreter | |
| Args: | |
| heat_code_int: Integer representation of 4-byte heat code | |
| num_buckets_x: Number of buckets in X direction | |
| num_buckets_y: Number of buckets in Y direction | |
| Returns: | |
| (bucket_x, bucket_y): Bucket indices | |
| """ | |
| # Use fractal addressing to get zone rect | |
| # Assume a normalized canvas (1.0 x 1.0) for bucket space | |
| zone_rect = self.resolve_fractal_address(heat_code_int, (1.0, 1.0)) | |
| # Convert zone center to bucket coordinates | |
| zone_x, zone_y, zone_w, zone_h = zone_rect | |
| center_x = zone_x + (zone_w / 2.0) | |
| center_y = zone_y + (zone_h / 2.0) | |
| # Map to bucket indices | |
| bucket_x = int(center_x * num_buckets_x) % num_buckets_x | |
| bucket_y = int(center_y * num_buckets_y) % num_buckets_y | |
| return (bucket_x, bucket_y) | |
| def navigate_quadtree_path(self, hex_header): | |
| """ | |
| Navigate quadtree path from hex header | |
| Algorithm: Convert Hex to Binary, group into 2-bit pairs | |
| Each pair (00, 01, 10, 11) selects a Quadrant (TL, TR, BL, BR) | |
| Args: | |
| hex_header: 8-character hex string (4 bytes = 32 bits = 16 quadrants) | |
| Returns: | |
| List of quadrants (path from root to target node) | |
| """ | |
| # Convert hex to integer | |
| header_int = int(hex_header, 16) | |
| # Extract 2-bit pairs (each pair = one level of quadtree) | |
| # Extract 2-bit pairs (each pair = one level of quadtree) | |
| # MUST iterate MSB to LSB to match calculate_heat_code | |
| path = [] | |
| for i in range(16): # 32 bits / 2 = 16 levels | |
| shift = 30 - (i * 2) | |
| pair = (header_int >> shift) & 0b11 | |
| path.append(Quadrant(pair)) | |
| return path | |
| def process_atom(self, hex_header, wave_payload): | |
| """ | |
| Process 512-byte atom through fractal quadtree | |
| Args: | |
| hex_header: 8-character hex string (4 bytes) | |
| wave_payload: 508 bytes | |
| """ | |
| # Step A: Navigational Parse | |
| path = self.navigate_quadtree_path(hex_header) | |
| # Navigate to target node | |
| node = self.root | |
| for quadrant in path[:4]: # Use first 4 levels (depth 0-3) | |
| if not node.is_leaf(): | |
| node = node.get_quadrant(quadrant) | |
| # Step B: Context Action (Binary Context) | |
| # Extract control bits from first 2 bits of payload | |
| if len(wave_payload) > 0: | |
| control_bits = (wave_payload[0] >> 6) & 0b11 | |
| action = ContextAction(control_bits) | |
| # Remaining payload (after control bits) | |
| data_payload = wave_payload[1:] if len(wave_payload) > 1 else b'' | |
| if action == ContextAction.PERSIST: | |
| # Update heat_state only (reinforce structure) | |
| node.heat_state = (node.heat_state + 1) % 4 | |
| elif action in [ContextAction.CHANGE_1, ContextAction.CHANGE_2]: | |
| # Trigger GF(4) dissolution | |
| current_vector = self._extract_state_vector(node) | |
| input_vector = self._payload_to_vector(data_payload) | |
| heat_coeff = node.heat_state | |
| new_vector = GF4.dissolve_atom(current_vector, input_vector, heat_coeff) | |
| node.matrix_key = self._vector_to_matrix(new_vector) | |
| node.heat_state = (node.heat_state + 1) % 4 | |
| elif action == ContextAction.RESET: | |
| # Clear node | |
| node.matrix_key = None | |
| node.heat_state = 0 | |
| node.atom_data = None | |
| # Store atom data at leaf | |
| if node.is_leaf(): | |
| node.atom_data = data_payload | |
| def _extract_state_vector(self, node): | |
| """Extract 2-bit state vector from node""" | |
| if node.matrix_key is None: | |
| return [0] * 16 # Default zero vector | |
| # Convert matrix key to vector (simplified) | |
| return [(node.matrix_key >> (i * 2)) & 0b11 for i in range(16)] | |
| def _payload_to_vector(self, payload): | |
| """Convert payload bytes to 2-bit vector""" | |
| if not payload: | |
| return [0] * 16 | |
| # Extract 2-bit pairs from first bytes | |
| vector = [] | |
| for byte in payload[:8]: # 8 bytes = 16 pairs | |
| vector.append((byte >> 6) & 0b11) | |
| vector.append((byte >> 4) & 0b11) | |
| vector.append((byte >> 2) & 0b11) | |
| vector.append(byte & 0b11) | |
| return vector[:16] | |
| def _vector_to_matrix(self, vector): | |
| """Convert 2-bit vector to matrix key (integer)""" | |
| key = 0 | |
| for i, val in enumerate(vector[:16]): | |
| key |= (val << (i * 2)) | |
| return key | |
| def draw_viewport(self, viewport_size): | |
| """ | |
| Render viewport from quadtree | |
| Args: | |
| viewport_size: (width, height) tuple | |
| Returns: | |
| numpy array (H, W, 3) RGB image | |
| """ | |
| width, height = viewport_size | |
| image = np.zeros((height, width, 3), dtype=np.uint8) | |
| self._render_node(self.root, image, 0, 0, width, height) | |
| return image | |
| def _render_node(self, node, image, x, y, w, h): | |
| """Recursively render quadtree node""" | |
| if node is None: | |
| return | |
| if node.is_leaf(): | |
| # Leaf node: render based on matrix_key and heat_state | |
| if node.matrix_key is not None: | |
| color = self._matrix_key_to_color(node.matrix_key, node.heat_state) | |
| image[y:y+h, x:x+w] = color | |
| else: | |
| # Non-leaf: recurse into children or render block | |
| if any(child is not None for child in node.children): | |
| # Has children: recurse | |
| hw, hh = w // 2, h // 2 | |
| self._render_node(node.children[0], image, x, y, hw, hh) # TL | |
| self._render_node(node.children[1], image, x + hw, y, w - hw, hh) # TR | |
| self._render_node(node.children[2], image, x, y + hh, hw, h - hh) # BL | |
| self._render_node(node.children[3], image, x + hw, y + hh, w - hw, h - hh) # BR | |
| else: | |
| # No children: render geometric block | |
| color = self._matrix_key_to_color(node.matrix_key, node.heat_state) if node.matrix_key else [0, 0, 0] | |
| image[y:y+h, x:x+w] = color | |
| def _matrix_key_to_color(self, matrix_key, heat_state): | |
| """Convert matrix key and heat state to RGB color""" | |
| # Extract RGB from matrix key | |
| r = ((matrix_key >> 0) & 0xFF) % 256 | |
| g = ((matrix_key >> 8) & 0xFF) % 256 | |
| b = ((matrix_key >> 16) & 0xFF) % 256 | |
| # Apply heat_state intensity scaling | |
| intensity = (heat_state + 1) / 4.0 | |
| r = int(r * intensity) | |
| g = int(g * intensity) | |
| b = int(b * intensity) | |
| return [r, g, b] | |