Skip to content

Add dense-array-base representation handle to ProbeGroup#425

Open
h-mayorquin wants to merge 6 commits intoSpikeInterface:mainfrom
h-mayorquin:dense_array_handle
Open

Add dense-array-base representation handle to ProbeGroup#425
h-mayorquin wants to merge 6 commits intoSpikeInterface:mainfrom
h-mayorquin:dense_array_handle

Conversation

@h-mayorquin
Copy link
Copy Markdown
Collaborator

@h-mayorquin h-mayorquin commented Apr 19, 2026

Coming here from #420

This PR adds a private _build_contact_vector() method on ProbeGroup. The method returns a dense channel-ordered numpy array derived from the current device_channel_indices:

>>> probegroup._build_contact_vector()
array([(0,  0.,  0., '0', 'front'),
       (0, 20.,  0., '0', 'front'),
       (0,  0., 20., '1', 'back'),
       (0, 20., 20., '1', 'back')],
      dtype=[('probe_index', '<i8'), ('x', '<f8'), ('y', '<f8'), ('shank_ids', '<U64'), ('contact_sides', '<U8')])

It contains only the subset of state SpikeInterface actually needs in channel order: probe_index, x, y, z, shank_ids, and contact_sides. Fields that are not available on the ProbeGroup are not included in the representation. The method is private by convention: it is intended for integration with downstream libraries (notably SpikeInterface), and its fields and dtype may evolve with consumer requirements, so user code should not depend on it directly.

This PR enables a middle way between the old contact_vector workflow we are currently using in SpikeInterface and the full array-backed rewrite of ProbeGroup proposed in #420. #420 changes the identity of ProbeGroup itself to become an array-backed backend; this PR keeps the scope smaller and adds a private method that returns only what SpikeInterface needs. The coupling between probeinterface and SpikeInterface now lives in one small surface (_build_contact_vector()) instead of being spread through the whole ProbeGroup class, so the two libraries can evolve together without requiring larger changes on either side. This provides the probeinterface-side handle needed for the SpikeInterface #4465 direction, where the recording holds a ProbeGroup object directly and recovers the channel-facing behavior through this handle on demand.

Three technical points:

  • SpikeInterface integration. The method computes fresh from each probe's current device_channel_indices. Consumers call probegroup._build_contact_vector() and get a view reflecting the probegroup's current state: no cache to keep in sync, no invalidation rules, no probe-level vs probegroup-level distinction. If a consumer needs to avoid repeated recomputation in a hot loop, it can cache the result at the call site where it knows the lifetime.

  • Private to make it flexible. The method is private because its fields and dtype are tailored to SpikeInterface's current needs and will evolve with them. As a private method, the handle can grow, shrink, or change shape without becoming a public-API break. This mechanism is for SpikeInterface and for power users who know the contract, so let's keep it private.

  • No serialization format change. The method has no in-memory state; it computes fresh from each probe's own device_channel_indices, which already round-trip through probe serialization. So this PR needs no format version bump and no new way to encode channel order in the JSON/dict representation. The existing per-probe serialization is sufficient. Because the method derives from device_channel_indices rather than replacing it, a consumer could also preserve the user-provided wiring as provenance and still obtain a channel-ordered view.

The companion SpikeInterface PR illustrates the implementation of this.

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