116 lines
6.3 KiB
Python
116 lines
6.3 KiB
Python
import copy
|
|
import unittest
|
|
import numpy as np
|
|
import engineering_inputs as e
|
|
|
|
|
|
def inputs():
|
|
return dict(tick=np.array([0, 4, 5, 17, 18, 18, 19, 499, 500, 999], np.int32),
|
|
neuron_idx=np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 166699], np.int32))
|
|
|
|
|
|
def spec():
|
|
return dict(name='unchanged', kind='fullgraph', steps=1000, dt_ms=.1, duration_ms=100.,
|
|
apl_delay_steps=18, record_history=False, training=False,
|
|
model={'threshold_mv': -45, 'w_syn_mv_per_anatomical_synapse': .275},
|
|
apl={'gain': .01}, budget_root='/project/old', output_budget_bytes=2048,
|
|
graph_dir='/project/frozen-graph', seed=1073741825)
|
|
|
|
|
|
class ExactInputs(unittest.TestCase):
|
|
def test_exact_boundaries_reconstruct_all_requests(self):
|
|
original = inputs()
|
|
intervals = [(0, 5), (5, 18), (18, 19), (19, 500), (500, 1000)]
|
|
parts = [e.slice_requests(original, 1000, *span) for span in intervals]
|
|
report = e.verify_partition(original, 1000, intervals, parts)
|
|
self.assertTrue(report['complete'])
|
|
self.assertEqual(parts[2]['tick'].tolist(), [0, 0])
|
|
self.assertEqual(parts[-1]['tick'].tolist(), [0, 499])
|
|
self.assertEqual(report['random_draws'], 0)
|
|
for value in parts:
|
|
for key in original:
|
|
self.assertFalse(np.shares_memory(original[key], value[key]))
|
|
|
|
def test_empty_intervals_are_explicit_not_lost(self):
|
|
original = inputs()
|
|
intervals = [(0, 20), (20, 499), (499, 1000)]
|
|
parts = [e.slice_requests(original, 1000, *span) for span in intervals]
|
|
self.assertEqual(len(parts[1]['tick']), 0)
|
|
self.assertTrue(e.verify_partition(original, 1000, intervals, parts)['complete'])
|
|
|
|
def test_bad_requests_never_silently_fixed(self):
|
|
for mut in ('dtype', 'duplicate', 'order', 'bounds', 'shape', 'extra'):
|
|
req = inputs()
|
|
if mut == 'dtype': req['tick'] = req['tick'].astype(np.int64)
|
|
elif mut == 'duplicate': req['tick'][1], req['neuron_idx'][1] = 0, 1
|
|
elif mut == 'order': req['tick'][1] = 10
|
|
elif mut == 'bounds': req['neuron_idx'][-1] = 166700
|
|
elif mut == 'shape': req['tick'] = req['tick'][:-1]
|
|
else: req['seed'] = 1
|
|
with self.subTest(mut=mut), self.assertRaises(ValueError):
|
|
e.slice_requests(req, 1000, 0, 1000)
|
|
|
|
def test_partition_gap_overlap_changed_input_and_missing_tail_rejected(self):
|
|
req = inputs()
|
|
spans = [(0, 500), (500, 1000)]
|
|
parts = [e.slice_requests(req, 1000, *x) for x in spans]
|
|
for bad in ([(0, 500), (501, 1000)], [(0, 500), (499, 1000)], [(0, 500)]):
|
|
with self.assertRaises(ValueError):
|
|
e.verify_partition(req, 1000, bad, parts[:len(bad)])
|
|
parts[0]['neuron_idx'][0] = 123
|
|
with self.assertRaisesRegex(ValueError, 'changes actual requests'):
|
|
e.verify_partition(req, 1000, spans, parts)
|
|
|
|
def test_fresh_prefix_and_continued_specs_preserve_original(self):
|
|
original = spec()
|
|
before = copy.deepcopy(original)
|
|
for start, stop, parent in ((0, 1000, None), (0, 18, None), (18, 19, 'a' * 64)):
|
|
derived, audit = e.derive_spec(original, start=start, stop=stop, budget_root='/project/new',
|
|
output_budget_bytes=8 * 1024**3, parent_sha=parent)
|
|
self.assertEqual(original, before)
|
|
self.assertEqual(derived['model'], original['model'])
|
|
self.assertEqual(derived['apl'], original['apl'])
|
|
self.assertIsNot(derived['model'], original['model'])
|
|
self.assertEqual(derived['max_steps'], 1000)
|
|
self.assertEqual(derived['steps'], stop - start)
|
|
self.assertTrue(audit['all_other_fields_unchanged'])
|
|
if start: self.assertEqual(derived['global_tick_offset'], start)
|
|
|
|
def test_invalid_continuation_root_and_duration_rejected(self):
|
|
for root in ('/project/old/sub', '/project', 'relative', '/project/../old', '//project/old', '//project/new'):
|
|
with self.assertRaises(ValueError):
|
|
e.derive_spec(spec(), start=0, stop=1000, budget_root=root, output_budget_bytes=10)
|
|
for start, stop, parent in ((1, 20, None), (0, 10, 'a'*64), (True, 10, None), (0, 1001, None)):
|
|
with self.assertRaises(ValueError):
|
|
e.derive_spec(spec(), start=start, stop=stop, budget_root='/project/new', output_budget_bytes=10, parent_sha=parent)
|
|
original = spec(); original['duration_ms'] = 1.
|
|
with self.assertRaises(ValueError):
|
|
e.derive_spec(original, start=0, stop=10, budget_root='/project/new', output_budget_bytes=10)
|
|
|
|
def test_original_clock_type_and_no_within_trial_update_match_runtime(self):
|
|
for key, value in (('apl_delay_steps', 18.), ('apl_delay_steps', True),
|
|
('within_trial_weight_updates', True), ('budget_root', '//project/old')):
|
|
original = spec(); original[key] = value
|
|
with self.subTest(key=key, value=value), self.assertRaises(ValueError):
|
|
e.derive_spec(original, start=0, stop=10, budget_root='/project/new', output_budget_bytes=10)
|
|
|
|
def test_overlay_is_declaration_translation_not_self_authorized_learned(self):
|
|
original = dict(schema='phase4am-overlay-v1', overlay_name='zero', training=False, fixed_for_whole_trial=True,
|
|
overlay_sha256='b'*64, mask_path='/project/mask.npy', mask_sha256=e.MASK_SHA,
|
|
base_candidate_path='/project/base.npy', base_candidate_sha256='c'*64,
|
|
aj_model_dir='/project/apl-timing-lab-v1', old_extra_field='preserved in original only')
|
|
before = copy.deepcopy(original)
|
|
result = e.adapt_overlay_manifest(original, '/project/overlay.py')
|
|
self.assertEqual(original, before)
|
|
self.assertEqual(result['schema'], 'phase4an-overlay-v1')
|
|
self.assertNotIn('old_extra_field', result)
|
|
self.assertEqual(result['overlay_sha256'], original['overlay_sha256'])
|
|
for key, val in (('overlay_name', 'learned'), ('mask_sha256', 'd'*64), ('training', True), ('base_candidate_path', 'local')):
|
|
bad = dict(original); bad[key] = val
|
|
with self.subTest(key=key), self.assertRaises(ValueError):
|
|
e.adapt_overlay_manifest(bad, '/project/overlay.py')
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|