File size: 8,464 Bytes
32d978d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 | """
Geometry System — Core Knowledge of Geometry
Implements innate geometric/spatial reasoning:
1. Spatial relations: left, right, above, below, inside, outside
2. Distance metrics with smooth deformations (Distortable Canvas integration)
3. Surface layout representations (navigable surfaces)
4. Shape primitives for recognition
Boosted by the Distortable Canvas paper: images as smooth functions
on elastic 2D canvas with deformation fields.
Reference: Spelke & Lee (2012), oneandtrulyone Distortable Canvas paper
Author: Algorembrant, Rembrant Oyangoren Albeos (2026)
"""
import numpy as np
from scipy.ndimage import gaussian_filter
class GeometrySystem:
"""
Innate spatial and geometric reasoning.
Provides core geometric computations including spatial relations,
smooth deformation fields (from Distortable Canvas), and surface
layout representations for navigation and object reasoning.
"""
def __init__(self, canvas_resolution: int = 28):
"""
Args:
canvas_resolution: Default canvas size for deformation operations.
"""
self.canvas_resolution = canvas_resolution
# ----- Spatial Relations (innate categorical distinctions) -----
def spatial_relation(self, pos_a: np.ndarray, pos_b: np.ndarray) -> dict:
"""
Compute innate categorical spatial relations between two positions.
Infants distinguish these before learning language labels for them.
Args:
pos_a: Reference position (ndarray, at least 2D).
pos_b: Target position.
Returns:
Dict with boolean spatial relations and continuous distances.
"""
a = np.asarray(pos_a, dtype=np.float64)
b = np.asarray(pos_b, dtype=np.float64)
diff = b - a
relations = {
'distance': float(np.linalg.norm(diff)),
'direction': diff / (np.linalg.norm(diff) + 1e-8),
}
if len(diff) >= 2:
relations['right_of'] = bool(diff[0] > 0)
relations['left_of'] = bool(diff[0] < 0)
relations['above'] = bool(diff[1] < 0) # Assuming y-axis points down (image coords)
relations['below'] = bool(diff[1] > 0)
return relations
def is_inside(self, point: np.ndarray, bbox_min: np.ndarray,
bbox_max: np.ndarray) -> bool:
"""
Check if a point is inside a bounding region.
Containment is a core geometric concept — infants reason about
"inside" and "outside" from very early on.
"""
p = np.asarray(point, dtype=np.float64)
return bool(np.all(p >= bbox_min) and np.all(p <= bbox_max))
# ----- Smooth Deformation Fields (Distortable Canvas) -----
def create_deformation_field(self, shape: tuple[int, int],
smoothness: float = 3.0,
magnitude: float = 2.0) -> tuple[np.ndarray, np.ndarray]:
"""
Create a smooth random deformation field.
From the Distortable Canvas paper: images live on an elastic 2D canvas
that can be smoothly warped. The deformation field u(x,y), v(x,y) defines
how each pixel coordinate shifts.
Args:
shape: (H, W) shape of the canvas.
smoothness: Gaussian sigma for smoothness regularization.
Higher = smoother/more rigid deformation.
magnitude: Maximum displacement magnitude.
Returns:
Tuple of (u_field, v_field), each of shape (H, W).
"""
H, W = shape
# Random initial displacements
u = np.random.randn(H, W) * magnitude
v = np.random.randn(H, W) * magnitude
# Smooth with Gaussian filter (biological smoothness constraint)
u = gaussian_filter(u, sigma=smoothness)
v = gaussian_filter(v, sigma=smoothness)
return u, v
def apply_deformation(self, image: np.ndarray,
u_field: np.ndarray,
v_field: np.ndarray) -> np.ndarray:
"""
Apply a smooth deformation field to an image.
This is the core operation from the Distortable Canvas paper:
warp the canvas to align one image to another.
Args:
image: 2D image array (H, W).
u_field: Horizontal displacement field (H, W).
v_field: Vertical displacement field (H, W).
Returns:
Warped image.
"""
H, W = image.shape[:2]
# Create coordinate grids
y_coords, x_coords = np.mgrid[0:H, 0:W].astype(np.float64)
# Apply deformation
new_x = x_coords + u_field
new_y = y_coords + v_field
# Clamp to valid range
new_x = np.clip(new_x, 0, W - 1)
new_y = np.clip(new_y, 0, H - 1)
# Bilinear interpolation
x0 = np.floor(new_x).astype(int)
x1 = np.minimum(x0 + 1, W - 1)
y0 = np.floor(new_y).astype(int)
y1 = np.minimum(y0 + 1, H - 1)
wx = new_x - x0
wy = new_y - y0
result = (image[y0, x0] * (1 - wx) * (1 - wy) +
image[y1, x0] * (1 - wx) * wy +
image[y0, x1] * wx * (1 - wy) +
image[y1, x1] * wx * wy)
return result
def canvas_distance(self, u_field: np.ndarray, v_field: np.ndarray) -> float:
"""
Compute the canvas distortion energy (from Distortable Canvas paper).
This measures how much geometric warping is needed. The Jacobian
penalty ensures the deformation is smooth and doesn't tear/fold.
Energy = sum of squared gradients of the deformation field.
"""
# Gradient of deformation field (Jacobian components)
du_dx = np.gradient(u_field, axis=1)
du_dy = np.gradient(u_field, axis=0)
dv_dx = np.gradient(v_field, axis=1)
dv_dy = np.gradient(v_field, axis=0)
# Frobenius norm of the Jacobian of the displacement
jacobian_energy = np.sum(du_dx**2 + du_dy**2 + dv_dx**2 + dv_dy**2)
return float(jacobian_energy)
def color_distance(self, image1: np.ndarray, image2: np.ndarray) -> float:
"""
Pixel-wise intensity distance between two images.
From Distortable Canvas: the "color distortion" component
of the dual distance metric.
"""
return float(np.sum((image1.astype(np.float64) - image2.astype(np.float64))**2))
def dual_distance(self, image1: np.ndarray, image2: np.ndarray,
u_field: np.ndarray, v_field: np.ndarray,
lambda_weight: float = 0.1) -> float:
"""
Compute the dual distance from the Distortable Canvas paper.
dual_distance = color_distance + lambda * canvas_distance
This balances pixel-level similarity against geometric warping cost.
"""
# Warp image1 toward image2
warped = self.apply_deformation(image1, u_field, v_field)
color_dist = self.color_distance(warped, image2)
canvas_dist = self.canvas_distance(u_field, v_field)
return color_dist + lambda_weight * canvas_dist
# ----- Shape Primitives -----
def compute_centroid(self, points: np.ndarray) -> np.ndarray:
"""Compute the centroid (center of mass) of a set of points."""
return np.mean(points, axis=0)
def compute_extent(self, points: np.ndarray) -> dict:
"""Compute spatial extent (bounding box, spread) of a point set."""
mins = np.min(points, axis=0)
maxs = np.max(points, axis=0)
return {
'min': mins,
'max': maxs,
'extent': maxs - mins,
'center': (mins + maxs) / 2.0
}
def angular_relation(self, center: np.ndarray, point: np.ndarray) -> float:
"""
Compute the angle from center to point (in radians).
Used for encoding relative angular position.
"""
diff = np.asarray(point, dtype=np.float64) - np.asarray(center, dtype=np.float64)
return float(np.arctan2(diff[1], diff[0]))
|