Skip to content

Multihop (effective) connectivity clustering in cf_cosine_plot - #59

Merged
jefferis merged 1 commit into
masterfrom
feature/multihop-connectivity
Jul 17, 2026
Merged

Multihop (effective) connectivity clustering in cf_cosine_plot#59
jefferis merged 1 commit into
masterfrom
feature/multihop-connectivity

Conversation

@jefferis

Copy link
Copy Markdown
Contributor

Adds multihop ("effective") connectivity clustering: instead of clustering neurons by their direct partners, cluster them by their effective connectivity onto n-th order partners reached through intermediate interneuron layers, following Schlegel et al. 2021 (10.7554/eLife.62576).

Important

Depends on natverse/coconat#12 (effective_connectivity() / grouping_matrix()).
be37446 temporarily pins the coconat Remote to that feature branch so CI can install it — revert that commit once coconat#12 merges.

API

cf_cosine_plot(ids, ..., nhops = 0, min_frac = 0.005, remove_query = FALSE)
  • nhops = number of intermediate interneuron layers. nhops=0 (default) is the existing direct-partner behaviour; nhops=1 is the paper's "one-hop" (2nd-order partners); nhops=2 is 3rd-order. The docs carry the order↔hops mapping, since the conventions disagree.
  • min_frac = per-type fractional threshold (scalar or one value per hop), applied at every hop including the terminal one.
  • remove_query = exclude query neurons from partners at every hop.
  • threshold is unchanged: a single per-neuron-pair absolute synapse cut applied at each hop's fetch.

How it works

Per dataset (effective connectivity is computed within a dataset, since interneurons are dataset-local):

  1. Fetch partners (absolute threshold) and input-normalise the hop with coconat::colScaleM (inputs to every postsynaptic cell sum to 1).
  2. Advance a running query×frontier matrix one hop at a time via coconat::effective_connectivity(list(running, step), normalise = FALSE), which aligns partners by name so dead-end paths become zero.
  3. Between hops, prune each intermediate layer to types receiving ≥ min_frac effective input, then fetch the next hop only from the survivors. This prune-before-fetch is what bounds the walk — hop 2 from an unpruned interneuron set is the thing to avoid.
  4. Group only the terminal layer to types and feed the result through the existing cosine/heatmap machinery as a synthetic partner table; match_types runs on that terminal type layer.

Two design points worth noting for review:

  • Grouping is as late as possible. Intermediate layers are grouped to type only as a selection criterion for pruning — the surviving neurons are carried forward at full resolution — so the per-neuron input normalisation is never compromised. Terminal grouping is safe to apply early by associativity ((A1n·A2n)·G == A1n·(A2n·G)).
  • multi_cosine_matrix now passes standardise_input = FALSE. This is safe because cf_partners has already standardised the data by that point, and it's required for the synthetic effective table (whose partner side holds cell types, not integer64 ids).

nhops=0 reproduces prior behaviour exactly.

Testing

  • tests/testthat/test-multihop.R — 15 offline assertions with a mocked cf_partners over a synthetic network: hand-computed one-hop values, frontier pruning, remove_query, the melt shape, and an nhops=2 dead-end case (an interneuron with no onward partners) covering name-based alignment.
  • Full existing suite green; the live cosine tests confirm the nhops=0 path still works through the modified multi_cosine_matrix.
  • Live smoke test on cf_ids(hemibrain="/type:LAL00.+"): nhops=0 and nhops=1 both give valid 15×15 matrices over the same neuron set (mean off-diagonal cosine 0.10 → 0.21, as expected once connectivity flows through shared interneurons).

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

🤖 Generated with Claude Code

@jefferis
jefferis force-pushed the feature/multihop-connectivity branch from be37446 to 121b46f Compare July 17, 2026 07:22
New nhops/min_frac/remove_query arguments cluster neurons by their
effective connectivity onto n-th order partners reached through
intermediate interneuron layers, following Schlegel et al. 2021.

Per dataset the walk fetches partners and input-normalises each hop
(coconat::colScaleM), then advances a running query x frontier matrix one
hop at a time via coconat::effective_connectivity(normalise=FALSE), which
aligns partners by name so dead-end paths become zero. Between hops each
intermediate layer is pruned to types receiving >= min_frac effective
input (grouping-as-selection via coconat::grouping_matrix, keeping neurons
at full resolution) before the next fetch, which bounds the walk. The
terminal layer is grouped to types and fed through the existing
cosine/heatmap machinery as a synthetic partner table, with match_types
applied on that type layer. nhops=0 reproduces prior behaviour.

Offline tests with a mocked cf_partners in tests/testthat/test-multihop.R.
@jefferis
jefferis force-pushed the feature/multihop-connectivity branch from 121b46f to a294f6f Compare July 17, 2026 12:50
@jefferis
jefferis merged commit d292b44 into master Jul 17, 2026
3 checks passed
@jefferis
jefferis deleted the feature/multihop-connectivity branch July 17, 2026 17:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant