@@ -1914,6 +1914,9 @@ def _get_synchrony_counts(spikes, synchrony_sizes, all_unit_ids):
19141914 ----------
19151915 spikes : np.array
19161916 Structured numpy array with fields ("sample_index", "unit_index", "segment_index").
1917+ Must be ordered by segment_index and then by sample_index within each segment, as
1918+ returned by `BaseSorting.to_spike_vector()`; a spike sharing (segment_index,
1919+ sample_index) with a matching-event neighbor it is not adjacent to will not be counted as synchronous.
19171920 all_unit_ids : list or None, default: None
19181921 List of unit ids to compute the synchrony metrics. Expecting all units.
19191922 synchrony_sizes : None or np.array, default: None
@@ -1931,29 +1934,38 @@ def _get_synchrony_counts(spikes, synchrony_sizes, all_unit_ids):
19311934 """
19321935
19331936 synchrony_counts = np .zeros ((np .size (synchrony_sizes ), len (all_unit_ids )), dtype = np .int64 )
1937+ if spikes .size == 0 :
1938+ return synchrony_counts
19341939
1935- # compute the occurrence of each sample_index. Count >2 means there's synchrony
1936- _ , unique_spike_index , counts = np .unique (spikes ["sample_index" ], return_index = True , return_counts = True )
1937-
1938- min_synchrony = 2
1939- mask = counts >= min_synchrony
1940- sync_indices = unique_spike_index [mask ]
1941- sync_counts = counts [mask ]
1942-
1943- all_syncs = np .unique (sync_counts )
1944- num_bins = [np .size (synchrony_sizes [synchrony_sizes <= i ]) for i in all_syncs ]
1945-
1946- indices = {}
1947- for num_of_syncs in all_syncs :
1948- indices [num_of_syncs ] = np .flatnonzero (all_syncs == num_of_syncs )[0 ]
1949-
1950- for i , sync_index in enumerate (sync_indices ):
1951-
1952- num_of_syncs = sync_counts [i ]
1953- # Counts inclusively. E.g. if there are 3 simultaneous spikes, these are also added
1954- # to the 2 simultaneous spike bins.
1955- units_with_sync = spikes [sync_index : sync_index + num_of_syncs ]["unit_index" ]
1956- synchrony_counts [: num_bins [indices [num_of_syncs ]], units_with_sync ] += 1
1940+ sample_indices = spikes ["sample_index" ]
1941+ segment_indices = spikes ["segment_index" ]
1942+ same_segment_and_sample = (sample_indices [1 :] == sample_indices [:- 1 ]) & (
1943+ segment_indices [1 :] == segment_indices [:- 1 ]
1944+ )
1945+ synchronous_spike_mask = np .zeros (spikes .size , dtype = bool )
1946+ synchronous_spike_mask [:- 1 ] |= same_segment_and_sample
1947+ synchronous_spike_mask [1 :] |= same_segment_and_sample
1948+ if not np .any (synchronous_spike_mask ):
1949+ return synchrony_counts
1950+
1951+ synchronous_sample_indices = sample_indices [synchronous_spike_mask ]
1952+ synchronous_segment_indices = segment_indices [synchronous_spike_mask ]
1953+ synchronous_units = spikes ["unit_index" ][synchronous_spike_mask ]
1954+ synchronous_group_starts = np .empty (synchronous_units .size , dtype = bool )
1955+ synchronous_group_starts [0 ] = True
1956+ synchronous_group_starts [1 :] = (synchronous_sample_indices [1 :] != synchronous_sample_indices [:- 1 ]) | (
1957+ synchronous_segment_indices [1 :] != synchronous_segment_indices [:- 1 ]
1958+ )
1959+ synchronous_group_indices = np .cumsum (synchronous_group_starts , dtype = np .int64 ) - 1
1960+ synchronous_group_counts = np .bincount (synchronous_group_indices )
1961+
1962+ group_unit_keys = synchronous_group_indices * len (all_unit_ids ) + synchronous_units
1963+ unique_group_unit_keys = np .unique (group_unit_keys )
1964+ unique_group_indices , unique_unit_indices = np .divmod (unique_group_unit_keys , len (all_unit_ids ))
1965+ num_bins = np .searchsorted (synchrony_sizes , synchronous_group_counts [unique_group_indices ], side = "right" )
1966+ for synchrony_index in range (synchrony_sizes .size ):
1967+ units = unique_unit_indices [num_bins > synchrony_index ]
1968+ synchrony_counts [synchrony_index ] = np .bincount (units , minlength = len (all_unit_ids ))
19571969
19581970 return synchrony_counts
19591971
0 commit comments