170 lines
9.0 KiB
Python
170 lines
9.0 KiB
Python
"""Synthetic array-only comparator tests: no backend or scientific inputs."""
|
|
from pathlib import Path
|
|
import copy
|
|
import sys
|
|
import unittest
|
|
|
|
import numpy as np
|
|
|
|
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
|
import compare_timing as compare
|
|
|
|
|
|
def traces(delay, steps, width=3):
|
|
generated = np.arange(steps * width, dtype=np.float32).reshape(steps, width) * np.float32(.125)
|
|
full = np.concatenate((np.zeros((delay, width), dtype=np.float32), generated))
|
|
return generated, full[:steps].copy(), full[steps:].copy()
|
|
|
|
|
|
def sequence_result(generated, applied, pending, delay):
|
|
checks, differences = {}, {}
|
|
compare._timing_sequence_checks(generated, applied, pending, delay, 'test', checks, differences)
|
|
return checks, differences
|
|
|
|
|
|
def metadata_run(delay, steps, cpu=False):
|
|
generated, applied, pending = traces(delay, steps, 4064)
|
|
state = np.tile(np.array([.25, 1.125], np.float32), (steps, 1))
|
|
timing = dict(apl_delay_steps=delay, steps=steps, pending_generated_count=min(steps, delay),
|
|
generated_rows=steps, applied_generated_rows=max(steps-delay, 0), pending_shape=[delay, 4064],
|
|
pending_initial_zero_prefix=max(delay-steps, 0),
|
|
pending_application_tick_start=steps, pending_application_tick_stop_exclusive=steps+delay,
|
|
pending_generated_tick_start=max(steps-delay, 0), pending_generated_tick_stop_exclusive=steps,
|
|
pending_raw_sha256=compare.raw_hash(pending, '<f4'),
|
|
final_apl_state_float32=state[-1].tolist(),
|
|
final_apl_state_u32_bits=state[-1].view(np.uint32).tolist(), final_apl_state_nonzero=True,
|
|
brain_tail_advanced=False, future_apl_decay_or_feedback_generated=False,
|
|
finite_generated_sequence_only=True, closed_loop_branch_integrals_claimed_equal=False,
|
|
biological_delay_measurement_claimed=False, brain_steps_after_window=0,
|
|
APL_generation_steps_after_window=0, future_generated_decay_tail_included=False)
|
|
summary = dict(apl_timing=copy.deepcopy(timing), pending_generated_count=min(steps, delay),
|
|
pending_initial_zero_prefix=max(delay-steps, 0), pending_tail_shape=[delay, 4064],
|
|
future_generated_decay_tail_included=False, APL_worker_ticks=steps)
|
|
return dict(apl={'inhibition': generated, 'applied': applied, 'state': state}, pending=pending,
|
|
timing=timing, summary=summary)
|
|
|
|
|
|
class TimingComparisonTests(unittest.TestCase):
|
|
def test_delay_zero_and_18_partition(self):
|
|
for delay in (0, 18):
|
|
for steps in (1, 7, 18, 19, 54):
|
|
with self.subTest(delay=delay, steps=steps):
|
|
checks, differences = sequence_result(*traces(delay, steps), delay)
|
|
self.assertTrue(all(checks.values()), differences)
|
|
|
|
def test_one_tick_shift_rejected_independently(self):
|
|
generated, applied, pending = traces(18, 40)
|
|
applied[18:] = generated[1:23]
|
|
checks, _ = sequence_result(generated, applied, pending, 18)
|
|
self.assertFalse(checks['test.fixed_delay_applied.bitwise_exact'])
|
|
|
|
def test_pending_wrong_chronology_rejected(self):
|
|
generated, applied, pending = traces(18, 40)
|
|
checks, _ = sequence_result(generated, applied, pending[::-1].copy(), 18)
|
|
self.assertFalse(checks['test.fixed_delay_pending.bitwise_exact'])
|
|
|
|
def test_initial_zero_must_be_positive_bits(self):
|
|
generated, applied, pending = traces(18, 4)
|
|
pending.view(np.uint32)[0, 0] = 0x80000000
|
|
checks, _ = sequence_result(generated, applied, pending, 18)
|
|
self.assertFalse(checks['test.fixed_delay_pending.bitwise_exact'])
|
|
generated, applied, pending = traces(18, 22)
|
|
applied.view(np.uint32)[0, 0] = 0x80000000
|
|
checks, _ = sequence_result(generated, applied, pending, 18)
|
|
self.assertFalse(checks['test.fixed_delay_applied.bitwise_exact'])
|
|
|
|
def test_generated_signed_zero_preserved(self):
|
|
generated, applied, pending = traces(0, 1)
|
|
generated.view(np.uint32)[0, 0] = 0x80000000
|
|
applied[:] = generated
|
|
checks, _ = sequence_result(generated, applied, pending, 0)
|
|
self.assertTrue(all(checks.values()))
|
|
applied.view(np.uint32)[0, 0] = 0
|
|
checks, _ = sequence_result(generated, applied, pending, 0)
|
|
self.assertFalse(checks['test.fixed_delay_applied.bitwise_exact'])
|
|
|
|
def test_schema_and_delay_fail_closed(self):
|
|
generated, applied, pending = traces(18, 4)
|
|
for delay in (True, 1, 18.0):
|
|
with self.assertRaises(ValueError):
|
|
sequence_result(generated, applied, pending, delay)
|
|
with self.assertRaises(ValueError):
|
|
sequence_result(generated.astype(np.float64), applied, pending, 18)
|
|
with self.assertRaises(ValueError):
|
|
sequence_result(generated, applied, pending[-4:], 18)
|
|
|
|
def test_nonfinite_or_negative_generated_fails_even_if_shift_matches(self):
|
|
for value in (np.inf, np.nan, -1):
|
|
generated, applied, pending = traces(0, 2)
|
|
generated[0, 0] = value
|
|
applied[:] = generated
|
|
checks, _ = sequence_result(generated, applied, pending, 0)
|
|
self.assertFalse(checks['test.timing_finite_nonnegative'])
|
|
|
|
def test_both_backend_metadata_valid(self):
|
|
for role in ('gpu', 'cpu', 'first_gpu', 'second_gpu'):
|
|
for delay, steps in ((0, 25), (18, 7), (18, 25)):
|
|
run = metadata_run(delay, steps, cpu=role == 'cpu')
|
|
checks = {}
|
|
compare._timing_metadata_checks(run, role, delay, steps, checks)
|
|
self.assertTrue(all(checks.values()), checks)
|
|
|
|
def test_metadata_rejects_wrong_count_tail_advance_and_final_state(self):
|
|
for role in ('gpu', 'cpu'):
|
|
for change in ('count', 'tail', 'final', 'prefix', 'hash'):
|
|
run = metadata_run(18, 25, cpu=role == 'cpu')
|
|
if change == 'count':
|
|
run['timing']['pending_generated_count'] = 17
|
|
elif change == 'tail':
|
|
run['timing']['brain_steps_after_window' if role == 'cpu' else 'brain_tail_advanced'] = 1
|
|
elif change == 'final':
|
|
run['timing']['final_apl_state_u32_bits'][0] += 1
|
|
elif change == 'prefix':
|
|
run['timing']['pending_initial_zero_prefix'] = False
|
|
else:
|
|
run['timing']['pending_raw_sha256'] = '0' * 64
|
|
checks = {}
|
|
compare._timing_metadata_checks(run, role, 18, 25, checks)
|
|
self.assertFalse(all(checks.values()), (role, change))
|
|
|
|
def test_g_write_uses_applied_and_is_unconditional_during_ref(self):
|
|
nodes, kc = np.array([10, 12], np.int32), np.array([10], np.int32)
|
|
v = np.full((3, 2), -.06, np.float64)
|
|
ref = np.array([[22, 0], [21, 0], [20, 0]], np.int32)
|
|
before = np.array([[0, -.001], [-0., .001], [.002, -.003]], np.float64)
|
|
applied = np.array([[.25], [0], [1]], np.float32)
|
|
after = before.copy()
|
|
after[:, 0] -= applied[:, 0].astype(np.float64) * np.float64(.001)
|
|
run = dict(pre={'v': v, 'g': before, 'ref': ref}, histories={'v': v.copy(), 'g': after, 'ref': ref.copy()},
|
|
apl={'applied': applied, 'inhibition': np.full((3, 1), 99, np.float32)})
|
|
checks, differences = {}, {}
|
|
compare._check_apl_application(run, 'test', nodes, kc, checks, differences)
|
|
self.assertTrue(all(checks.values()), differences)
|
|
run['histories']['g'] = before.copy() # Hypothetical refractory guard must fail.
|
|
checks, differences = {}, {}
|
|
compare._check_apl_application(run, 'test', nodes, kc, checks, differences)
|
|
self.assertFalse(checks['test.apl_unconditional_g_write.bitwise_exact'])
|
|
|
|
def test_pair_comparison_includes_applied_and_pending(self):
|
|
def output():
|
|
generated, applied, pending = traces(18, 20)
|
|
return dict(state={'step': np.empty(0, np.int32), 'neuron_idx': np.empty(0, np.int32),
|
|
'counts': np.zeros(1, np.int32), 'ref': np.zeros(1, np.int32),
|
|
'v': np.zeros(1, np.float64), 'g': np.zeros(1, np.float64)},
|
|
apl={'drive': np.zeros((20, 2), np.float32), 'state': np.zeros((20, 2), np.float32),
|
|
'inhibition': np.pad(generated, ((0, 0), (0, 4061))),
|
|
'applied': np.pad(applied, ((0, 0), (0, 4061)))},
|
|
pending=np.pad(pending, ((0, 0), (0, 4061))),
|
|
hashes=[], queues=[], requests=[], component={}, histories={}, pre={})
|
|
left, right = output(), output()
|
|
right['apl']['applied'][0, 0] = 1
|
|
right['pending'][0, 0] += 1
|
|
checks, differences = {}, {}
|
|
compare._pair_outputs(left, right, checks, differences, 1, 20, False)
|
|
self.assertFalse(checks['apl.applied.bitwise_exact'])
|
|
self.assertFalse(checks['apl.pending.bitwise_exact'])
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|