AHTI-NEXIFORM-1.0.0 / tests /test_release.py
PureOne's picture
AHTI / NEXIFORM 1.0.0 public research release (metadata-fixed)
638b37e verified
Raw History Blame Contribute Delete
11.3 kB
import unittest
from itertools import combinations
import numpy as np
import sympy as s
from ahti.core import (HodgeModel, closest_vector, ResourceLimit, integer_affine_solve,
constrained_quantize, simplicial_complex, smith_verified)
from ahti.moments import encode,decode,signed_permutations,match_face
from ahti.geometry import tetrahedral_operators,jacobian,no_flip_certificate,monotonicity_certificate
Q=s.Rational
class ExactAlgebra(unittest.TestCase):
def test_three_way_decomposition(self):
B=s.Matrix([2,0,0,0]); C=s.Matrix([[0,2,1,1]])
V=s.Matrix([[1,2,0,0],[0,1,1,0],[0,0,1,1],[0,0,0,1]])
model=HodgeModel.build(B,C,V.T*V+s.eye(4))
a=s.Matrix([Q(1,2),Q(2,3),Q(-3,5),Q(7,11)])
e,h,l=model.split(a)
self.assertEqual(e+h+l,a)
self.assertEqual(model.norm2(a),sum(model.norm2(x) for x in (e,h,l)))
self.assertEqual(C*h,s.zeros(1,1))
self.assertEqual(B.T*model.W*h,s.zeros(1,1))
def test_reject_noncomplex(self):
with self.assertRaises(ValueError): HodgeModel.build(s.eye(2),s.eye(2))
def test_reject_bad_metric_and_float(self):
with self.assertRaises(ValueError): HodgeModel.build(s.zeros(2,0),s.zeros(0,2),s.diag(1,-1))
with self.assertRaises(ValueError): HodgeModel.build(s.Matrix([[1.0]]),s.zeros(0,1))
def test_saturated_integer_kernel(self):
model=HodgeModel.build(s.zeros(3,0),s.Matrix([[2,1,1]]))
z=s.Matrix([0,1,-1])
result=model.repair(z,'integral')
self.assertEqual(result['cost'],0)
self.assertEqual(model.integral_lattice()['free_rank'],2)
def test_torsion_is_not_lost(self):
model=HodgeModel.build(s.diag(-2,-2,0),s.zeros(0,3))
lattice=model.integral_lattice()
self.assertEqual(lattice['torsion'],[2,2])
self.assertEqual(lattice['free_rank'],1)
result=model.repair(s.Matrix([Q(1,3),Q(1,4),Q(7,5)]),'integral')
self.assertEqual(result['cost'],Q(4,25))
self.assertEqual(result['repaired'],s.Matrix([Q(1,3),Q(1,4),1]))
def test_exact_projection_ignores_torsion_in_real_target(self):
model=HodgeModel.build(s.Matrix([[-2]]),s.zeros(0,1))
result=model.repair(s.Matrix([Q(1,3)]),'exact')
self.assertEqual(result['cost'],0)
self.assertEqual(model.integral_lattice()['torsion'],[2])
def test_local_and_global_costs_add(self):
model=HodgeModel.build(s.zeros(3,0),s.Matrix([[1,1,0]]))
a=s.Matrix([Q(2,5),Q(1,5),Q(7,5)])
result=model.repair(a,'integral')
lattice=model.integral_lattice()['harmonic_basis']
e,h,l=model.split(a)
cvp=closest_vector(h,lattice,model.W)
self.assertEqual(result['cost'],model.norm2(l)+cvp['cost'])
def test_cvp_ties(self):
result=closest_vector(s.Matrix([Q(1,2)]),s.eye(1))
self.assertEqual(result['ties'],[(0,),(1,)])
self.assertEqual(result['cost'],Q(1,4))
def test_oblique_cvp_against_larger_enumeration(self):
L=s.Matrix([[1,Q(3,5)],[0,Q(4,5)]])
for i in range(-5,6):
h=s.Matrix([Q(i,7),Q(2*i+1,9)])
result=closest_vector(h,L)
brute=min(((h-L*s.Matrix([k,j])).dot(h-L*s.Matrix([k,j])))
for k in range(-6,7) for j in range(-6,7))
self.assertEqual(result['cost'],brute)
def test_resource_limit_is_not_a_certificate(self):
with self.assertRaises(ResourceLimit):
closest_vector(s.Matrix([Q(1,2),Q(1,2)]),s.eye(2),max_candidates=1)
def test_integer_affine_solutions(self):
A=s.Matrix([[2,4,0],[0,0,3]]); c=s.Matrix([6,9])
k,V=integer_affine_solve(A,c)
self.assertEqual(A*k,c);self.assertEqual(A*V,s.zeros(A.rows,V.cols))
with self.assertRaises(ValueError):integer_affine_solve(s.Matrix([[2]]),s.Matrix([1]))
def test_smith_transformations(self):
for A in (s.Matrix([[2,1,1]]),s.diag(2,6,0),s.zeros(0,3),s.zeros(3,0)):
d,u,v=smith_verified(A)
self.assertEqual(d,u*A*v)
self.assertEqual(abs(u.det()),1);self.assertEqual(abs(v.det()),1)
def test_boundary_quantization(self):
B=s.Matrix([[-1,1,0],[0,-1,1],[1,0,-1]])
model=HodgeModel.build(B,s.zeros(0,3))
a=s.Matrix([Q(1,5),Q(2,5),Q(2,5)])
M=s.Matrix([[1,0,0],[0,1,0]]);N=s.zeros(2,1);d=s.Matrix([0,0])
out=constrained_quantize(model,a,M,N,d)
self.assertEqual(M*out['u']+N*out['k'],d)
Z=model.integral_lattice()['integer_representatives']
self.assertEqual(B*out['u']+Z*out['k'],out['repaired'])
brute=[]
for k in range(-5,6):
x=B[:,2];y=a-Z*s.Matrix([k])
t=(x.T*y)[0]/(x.T*x)[0]
brute.append((y-x*t).dot(y-x*t))
self.assertEqual(out['cost'],min(brute))
def test_boundary_impossible_integer_constraint(self):
model=HodgeModel.build(s.zeros(1,1),s.zeros(0,1))
with self.assertRaises(ValueError):
constrained_quantize(model,s.Matrix([0]),s.zeros(1,1),s.Matrix([[2]]),s.Matrix([1]))
def test_flat_simplicial_connection(self):
R=s.Matrix([[0,-1,0],[1,0,0],[0,0,1]])
gauges=[s.eye(3),R,R*R]
edges=[(0,1),(0,2),(1,2)]
transports={(i,j):gauges[i]*gauges[j].T for i,j in edges}
B,C=simplicial_complex(3,edges,[(0,1,2)],transports)
self.assertEqual(C*B,s.zeros(3,9))
model=HodgeModel.build(B,C)
self.assertEqual(model.PH.rank(),0)
def test_reject_curved_triangle(self):
R=s.diag(-1,-1,1)
with self.assertRaises(ValueError):
simplicial_complex(3,[(0,1),(0,2),(1,2)],[(0,1,2)],{(0,1):R})
class Geometry(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.X=s.Matrix([[0,0,0],[1,0,0],[0,1,0],[0,0,1],[0,0,-1]])
cls.ops=tetrahedral_operators(cls.X,[(0,1,2,3),(0,1,2,4)])
cls.model=HodgeModel.build(cls.ops['B'],cls.ops['C'],cls.ops['W'])
cls.u=s.Matrix([v for row in cls.X.tolist() for v in row])
cls.a=cls.ops['B']*cls.u
def test_reconstruction(self):
for E in self.ops['reconstruction']:
self.assertEqual(jacobian(E,self.a),s.eye(3))
def test_geometric_weight_identity(self):
rhs=sum(mu*sum(x*x for x in jacobian(E,self.a))
for mu,E in zip(self.ops['volumes'],self.ops['reconstruction']))
self.assertEqual(self.model.norm2(self.a),rhs)
def test_noisy_repair_and_orientation(self):
noisy=self.a.copy();noisy[0]+=Q(1,100)
out=self.model.repair(noisy,'exact')
self.assertGreater(out['cost'],0)
self.assertEqual(self.ops['C']*out['repaired'],s.zeros(self.ops['C'].rows,1))
for E in self.ops['reconstruction']:
cert=no_flip_certificate(s.eye(3),jacobian(E,out['repaired']))
self.assertTrue(cert['verified'])
def test_certificate_rejects_flip(self):
self.assertFalse(no_flip_certificate(s.eye(3),s.diag(-1,1,1))['verified'])
def test_certificate_is_sufficient_not_necessary(self):
self.assertFalse(no_flip_certificate(s.eye(3),2*s.eye(3))['verified'])
self.assertTrue(monotonicity_certificate(s.eye(3),2*s.eye(3))['verified'])
def test_accretive_shear(self):
J=s.Matrix([[1,2,0],[-2,1,0],[0,0,1]])
self.assertTrue(monotonicity_certificate(s.eye(3),J,Q(1,2))['verified'])
self.assertGreater(J.det(),0)
def test_degenerate_tetra_rejected(self):
with self.assertRaises(ValueError):
tetrahedral_operators([[0,0,0],[1,0,0],[0,1,0],[1,1,0]],[(0,1,2,3)])
class Moments(unittest.TestCase):
def test_group_sizes(self):
self.assertEqual(len(signed_permutations()),48)
self.assertEqual(len(signed_permutations(True)),24)
def test_decoder_80_frames(self):
rng=np.random.default_rng(20261005)
for _ in range(80):
U,_=np.linalg.qr(rng.normal(size=(3,3)))
V,_=np.linalg.qr(rng.normal(size=(3,3)))
J=U@np.diag(np.exp(rng.uniform(-.6,.6,3)))@V.T
moments=encode(J)
out=decode(**moments)
error=min(np.linalg.norm(out['J']-R@J) for R in signed_permutations())
self.assertLess(error,1e-8)
self.assertEqual(out['contractions'],13)
def test_inconsistent_sixth_moment_rejected(self):
m=encode(np.eye(3));m['L6'][0,0,0,0,0,0]+=.1
with self.assertRaises(ValueError):decode(**m)
def test_singular_frame_rejected(self):
with self.assertRaises(ValueError):decode(**encode(np.diag([1.,1.,0.])))
def test_invalid_fourth_moment_rejected(self):
m=encode(np.eye(3));m['L4'][0,0,0,0]+=.1
with self.assertRaises(ValueError):decode(m['L2'],m['L4'])
def test_unique_proper_face_match(self):
E=np.array([[1.,0.],[0.,1.],[0.,0.]])
R=np.array([[0,-1,0],[1,0,0],[0,0,1]])
out=match_face(np.eye(3),R,E)
self.assertEqual(out['matching_count_within_tolerance'],1)
self.assertTrue(np.array_equal(out['R'],R))
both=match_face(np.eye(3),R,E,proper=False)
self.assertEqual(both['matching_count_within_tolerance'],2)
class ExactTensorAdapter(unittest.TestCase):
def test_rational_tensor_witness(self):
from ahti.moments import exact_moments,decode_rational
J=s.Matrix([[1,Q(1,3),0],[0,2,Q(1,5)],[Q(1,7),0,1]])
m=exact_moments(J)
out=decode_rational(**m)
self.assertEqual(exact_moments(out['J']),m)
self.assertEqual(out['status'],'exact_rational_moment_witness')
def test_frame_to_coordinate_adapter(self):
from ahti.geometry import compile_ordinary_frames
X=[[0,0,0],[1,0,0],[0,1,0],[0,0,1],[0,0,-1]]
R=s.Matrix([[0,-1,0],[1,0,0],[0,0,1]])
out=compile_ordinary_frames(X,[(0,1,2,3),(0,1,2,4)],[s.eye(3),R])
self.assertEqual(out['period_obstruction'],s.zeros(out['a'].rows,1))
self.assertEqual(out['model'].repair(out['a'])['cost'],0)
def test_incompatible_face_rejected(self):
from ahti.geometry import compile_ordinary_frames
X=[[0,0,0],[1,0,0],[0,1,0],[0,0,1],[0,0,-1]]
with self.assertRaises(ValueError):
compile_ordinary_frames(X,[(0,1,2,3),(0,1,2,4)],[s.eye(3),s.diag(2,1,1)])
class IntrinsicMetric(unittest.TestCase):
def test_exact_pullback_metric(self):
from ahti.moments import exact_moment_metric
out=exact_moment_metric(s.Matrix([[1,Q(1,3),0],[0,2,Q(1,5)],[0,0,1]]))
D,G=out['differential'],out['ambient_semidefinite_metric']
v=s.Matrix([Q(i-4,7) for i in range(9)])
self.assertEqual((D*v).T*G*(D*v),v.T*v)
def test_quotient_distance_scale_equivariance(self):
from ahti.moments import exact_quotient_distance2
J=s.eye(3);K=s.Matrix([[1,1,0],[0,1,0],[0,0,2]])
a=exact_quotient_distance2(J,K)['squared_distance']
b=exact_quotient_distance2(3*J,3*K)['squared_distance']
self.assertEqual(b,9*a)
def test_quotient_distance_zero_on_same_orbit(self):
from ahti.moments import exact_quotient_distance2
R=s.Matrix([[0,-1,0],[1,0,0],[0,0,1]])
self.assertEqual(exact_quotient_distance2(s.eye(3),R)['squared_distance'],0)
if __name__=='__main__':unittest.main(verbosity=2)