Repository navigation
CI: close test-guard bypasses found by independent review - #832
Merged
Merged
Conversation
…SRMNodes reset clears its spike window IzhikevichNodes sized its parameters by the n argument (None when only shape is given) and never reshaped them; CSRMNodes contracted with 'i,kij->kj'. Both now work for any shape; one-dimensional results are bit-identical (goldens conv2d_if_izh and csrm_window trial 0 unchanged). CSRMNodes.reset_state_variables now zeroes last_spikes, which changes results after a reset (csrm_window golden regenerated with that reason). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…with one channel
LocalConnection.compute dropped the batch dimension in its final view.
MaxPool{1,2,3}d multiplied a missing decay (None) and squeeze()d away a channel
of size 1; a missing decay now means plain spike counts, and the firing-rate
buffer follows the spike tensor's shape. Results that ran before are unchanged
(goldens pass). Reproducers kept as test_fixed_bug_stays_fixed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…; NetworkMonitor reset; tuple target shapes - MCC_LearningRule bounded sparse weights into a new tensor that only the rule held, so DiehlAndCook2015(sparse=True) never learned; the bound and the sparse normalisation now write in place. At batch 1 sparse and dense learn bit-identical weights without norm (test_sparse_dc2015_learns_like_dense); with norm they differ by summation order (max 6.0e-8). - MulticompartmentConnection.compute applies per-sample sparse weight copies ([batch, src, tgt]) with bmm; one copy keeps the old arithmetic. - NetworkMonitor.reset_state_variables looked connections up in layers. - [batch] + target.shape failed for tuple shapes. Results change: DiehlAndCook2015(sparse=True) now learns. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…work with batch > 1 - LearningRule.reset_state_variables deletes the tensors a rule creates on its first update (_step_state); AbstractConnection.reset_state_variables forwards to the rule. Reset then equals a freshly built network (invariant tests for mstdp_mstdpet and rules_mix now pass). Results change after a reset with learning on: goldens mstdp_mstdpet(_dt05), rules_mix(_dt05) regenerated, trial 0 bit-identical. - Rmax and MCC_learning.MSTDPET keep per-sample state and reduce the update over the batch, as MSTDP does. Batch 1 is bit-identical to the old formula (TestMccMstdpetBatched, goldens); batch 2 with sum equals the sum of single samples to summation order. Op counts at batch 1: MCC MSTDPET 24 -> 27, Rmax 24 -> 26 (regenerated with reason). API snapshot: +1 method. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
) Adopted from #813 (head 53dd2e3) by AHMETHAKANBEZIR1, reviewed with the bindsnet-pr-review skill (sandboxed canaries, fail-then-pass, API, timing); Hananel adopted it as accountable author because the PR says no human reviewed it. MeanFieldConnection.normalize scales w in place by norm over the absolute weight sum (a shared scalar counted once per target), instead of assigning a plain tensor to the Parameter (TypeError on every call). Co-Authored-By: Hananel Hazan <hananel@hazan.org.il> Co-Authored-By: OpenAI Codex <codex@openai.com>
Adopted from #815 (head 49c57f8) by AHMETHAKANBEZIR1, reviewed with the bindsnet-pr-review skill; Hananel adopted it as accountable author because the PR says no human reviewed it. Connection.compute_window re-creates s_w when the batch size changes, and reset_state_variables clears it for CSRM targets. Co-Authored-By: Hananel Hazan <hananel@hazan.org.il> Co-Authored-By: OpenAI Codex <codex@openai.com>
meanfield_norm and csrm_window goldens regenerated (both used to record a crash). Invariant xfails removed: reset-equals-fresh for csrm_window and meanfield_norm, round trip and batch for meanfield_norm. Still open: the CSRM spike window is not in the state_dict (round trip). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ction drives CSRMNodes - Connection.s_w is a registered buffer, so state_dict saves it; a load adopts a saved window or drops one the saved state lacked (_load_window). The csrm_window round-trip invariant now passes; golden regenerated (adds s_w, no value changed). - MulticompartmentConnection.compute_window read s_w and self.w, neither of which it has, so MCC into CSRMNodes always raised. It now keeps a window of its own outputs (pipeline runs once per step), resized on a batch change, cleared on reset, saved in the state_dict. With static weights it matches a Connection bit for bit (test_multicompartment_into_csrm_matches_connection). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…_decay - compute() took the mean over the whole batch, so one sample's input depended on the others; it now uses each sample's own mean (batch 1 bit-identical: goldens pass without the weight_decay change). - weight_decay was passed by position into AbstractConnection's reduction slot and ignored; it is now passed by name. Results change for anyone who set weight_decay on a MeanFieldConnection (golden meanfield_decay regenerated with that reason). - Two #813 test lines expected the batch-wide mean (0.75); corrected to the per-sample means. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…on features at batch > 1, sparse weight bounds - topology_features.MeanField never called the base constructor (no name) and had no initial value; it now has an optional name, a placeholder value, and a per-sample mean ([batch, src, tgt], applied per sample by compute). - Sub-features (Normalization, Updating) get no-op prime_feature, update, normalize and reset_state_variables, which MulticompartmentConnection calls on every pipeline entry; both now work in the constructor and in Network.run. - AdaptationBaseSynapsHistory/OtherSynaps: a synapse is active when its pre-synaptic neuron spiked in any sample (the mask is shared connectivity); batch 1 gives the same values. - Sparse weights with wmin/wmax: Connection.__init__ bounds a dense copy, LearningRule.update bounds in place via a dense copy, and WeightDependentPostPre/DiehlAndCook compute their factors from a dense view. PostPre, WeightDependentPostPre and DiehlAndCook on a bounded SparseConnection learn bit-identical weights to the dense Connection. - Test workarounds for these bugs removed (batch-1-only sets, broken pairs, tuple-shape and sparse-bound special cases). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…mpartmentConnection feature values in the state_dict - MulticompartmentConnection saves its pipeline feature values as feature.<name> and loads them in place, so DiehlAndCook2015 can be saved and restored (the last four strict xfails in test_invariants.py now pass; dc2015 goldens regenerated: new keys, no value changed). - Every KNOWN_BUGS entry is fixed: the dict becomes FIXED_BUGS (reproducers that must keep running); the empty xfail machinery in test_invariants.py and the batch-1, no-learning-check and sub-feature workarounds in test_all_classes.py are removed, so those classes run at batch 2 with full checks. - CONTRIBUTING, PR template and bindsnet/learning/README.md updated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Network (reviewer B): - MulticompartmentConnection state_dict: refuses to save duplicate feature names (they shared one key, and loading put one feature's value into the other); checks shape and sparse layout on load (copy_ broadcast a wrong-shaped tensor silently); saves the adaptation features' mask, spike buffer and counter (only value was saved). - An Updating sub-feature drives its parent's learning; the connection's update skips that parent (it learned twice per step). - A sub-feature whose parent is not in the pipeline is refused at construction (it failed later with an unclear TypeError). insert_pipeline had list.insert's arguments swapped. - Connection.compute_window and MaxPool resets create state on the spikes' device (CUDA device mismatch, also on master). - Docstrings state how the two CSRM windows differ once weights learn. Learning rules (reviewer A): - MCC_learning.DiehlAndCook crashed on sparse weights (twin of the learning.py fix). Sparse MCC weight copies now all get the batch's shared update in PostPre, DiehlAndCook and MSTDPET (as MSTDP did), so sparse equals dense; the default squeeze reduction means a sum over a larger batch, as in the fused dense path (_reduce_batch, _add_to_feature). - Docs: per-sample reward shape [batch, 1, 1]; reset keeps the reduction chosen at construction. CHANGELOG: checkpoint compatibility (strict=False for old checkpoints), new state shapes, sparse and Updating semantics. Each fix has a test that fails on ce98f93 and passes here. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…), docs Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this changes and why
An independent review of the test guards from #828 and #830 found ways a pull request could pass every required check while breaking results. The worst case: one commit halved the leak of
LIFNodes. It also added a rootpytest.inithat skipstest/regression, and a fake "bug test" that only checks which folder it runs from. It passedbuild,bug-test,weakened-testsand the coverage floor. This PR closes the holes. I replayed each of the reviewer's attacks against the new scripts to check.This branch is stacked on #831, because both change
test/regression/op_counts.json. Merge #831 first; this PR's diff then shrinks to the CI changes.Changes
buildand the 3.11/3.12 jobs runpytest -c pyproject.toml --cov-config=pyproject.toml, so apytest.ini,setup.cfg,tox.inior.coveragerccannot change what runs. Replayed: with the plantedpytest.ini, CI's command still runs the goldens, and 16 of 17 fail.weakened-tests(.github/scripts/weakened_tests.py):pytest --collect-onlyon the base and the head, and flags every test id that disappears. That coversdel test_x,__test__ = False, a shortened parameter list, and a conftest that deselects tests.--no-renames, so a renamed test file is no longer invisible.allclose,isclose,approx);assert ... or True,except AssertionError, an earlyreturn);pyproject.toml,pytest.ini,.pytest.ini,tox.ini,setup.cfg,.coveragerc,test/regression/networks.pyandtest/regression/cpu_pins.py, and torch version changes inpoetry.lock.bug-test(.github/scripts/fails_before_fix.py):--baseand--headare resolved to commit ids first, so the documented local command,--base master --head HEAD, now gives the same answer as CI.CIset) instead of skipping when torch's version differs from the stored files. So a torch upgrade must regenerate them in the same PR.networks.deterministic()also checks thatMKL_CBWRandATEN_CPU_CAPABILITYhold the pinned values.conn_postpre_mean. It runsPostPrewithreduction=torch.meanat batch 4 and dt 0.5, which exercises the general update path. Adtfactor added there passed every test before; nowtest_golden[conn_postpre_mean]fails.forward()of everyNodesclass; before, onlyLIFNodeswas counted. Check: an extra copy inIFNodes.forwardfails both IFNodes workloads.benchfails on large slowdowns. It now fails when a workload's median time ratio is above 2× the base, with the lower end of the 95% interval above 1.5, or when the tool errors. That catches slow pure-Python code, which the operation counts cannot see. The no-change calibration never exceeded 1.12 in any round. It also now takes its base asHEAD^1.networkandlearninghad floors.test/,pyproject.toml,poetry.lockand the pytest and coverage config files.Settings to change after merge (repository settings, not code)
benchto the required checks.tests-changed-oklabel, keeps applying after a contributor pushes new commits.Checklist
pytest -c pyproject.toml: 641 passed locally; coverage floors pass.op_counts.json(54 workloads, with a reason) and a new goldenconn_postpre_mean. This needstests-changed-ok.🤖 Generated with Claude Code