From be9eeb2e48115134b93ec0cd9035d97117bd019e Mon Sep 17 00:00:00 2001 From: Mario Mulansky Date: Tue, 3 Feb 2015 10:45:32 +0100 Subject: split distance.py into 3 separate modules --- pyspike/__init__.py | 14 +- pyspike/distances.py | 507 ---------------------------------------------- pyspike/generic.py | 83 ++++++++ pyspike/isi_distance.py | 132 ++++++++++++ pyspike/spike_distance.py | 135 ++++++++++++ pyspike/spike_sync.py | 136 +++++++++++++ 6 files changed, 494 insertions(+), 513 deletions(-) delete mode 100644 pyspike/distances.py create mode 100644 pyspike/generic.py create mode 100644 pyspike/isi_distance.py create mode 100644 pyspike/spike_distance.py create mode 100644 pyspike/spike_sync.py diff --git a/pyspike/__init__.py b/pyspike/__init__.py index f480964..1c2efbc 100644 --- a/pyspike/__init__.py +++ b/pyspike/__init__.py @@ -4,18 +4,20 @@ Copyright 2014, Mario Mulansky Distributed under the BSD License """ -__all__ = ["distances", "spikes", "PieceWiseConstFunc", "PieceWiseLinFunc", +__all__ = ["isi_distance", "spike_distance", "spike_sync", + "spikes", "PieceWiseConstFunc", "PieceWiseLinFunc", "DiscreteFunc"] from PieceWiseConstFunc import PieceWiseConstFunc from PieceWiseLinFunc import PieceWiseLinFunc from DiscreteFunc import DiscreteFunc -from distances import isi_profile, isi_distance, \ - spike_profile, spike_distance, \ - spike_sync_profile, spike_sync, \ - isi_profile_multi, isi_distance_multi, isi_distance_matrix, \ - spike_profile_multi, spike_distance_multi, spike_distance_matrix, \ +from isi_distance import isi_profile, isi_distance, isi_profile_multi,\ + isi_distance_multi, isi_distance_matrix +from spike_distance import spike_profile, spike_distance, spike_profile_multi,\ + spike_distance_multi, spike_distance_matrix +from spike_sync import spike_sync_profile, spike_sync,\ spike_sync_profile_multi, spike_sync_multi, spike_sync_matrix + from spikes import add_auxiliary_spikes, load_spike_trains_from_txt, \ spike_train_from_string, merge_spike_trains, generate_poisson_spikes diff --git a/pyspike/distances.py b/pyspike/distances.py deleted file mode 100644 index 9077871..0000000 --- a/pyspike/distances.py +++ /dev/null @@ -1,507 +0,0 @@ -""" distances.py - -Module containing several functions to compute spike distances - -Copyright 2014, Mario Mulansky - -Distributed under the BSD License -""" - -import numpy as np -import threading -from functools import partial - -from pyspike import PieceWiseConstFunc, PieceWiseLinFunc, DiscreteFunc - - -############################################################ -# isi_profile -############################################################ -def isi_profile(spikes1, spikes2): - """ Computes the isi-distance profile :math:`S_{isi}(t)` of the two given - spike trains. Retruns the profile as a PieceWiseConstFunc object. The S_isi - values are defined positive S_isi(t)>=0. The spike trains are expected - to have auxiliary spikes at the beginning and end of the interval. Use the - function add_auxiliary_spikes to add those spikes to the spike train. - - :param spikes1: ordered array of spike times with auxiliary spikes. - :param spikes2: ordered array of spike times with auxiliary spikes. - :returns: The isi-distance profile :math:`S_{isi}(t)` - :rtype: :class:`pyspike.function.PieceWiseConstFunc` - - """ - # check for auxiliary spikes - first and last spikes should be identical - assert spikes1[0] == spikes2[0], \ - "Given spike trains seems not to have auxiliary spikes!" - assert spikes1[-1] == spikes2[-1], \ - "Given spike trains seems not to have auxiliary spikes!" - - # load cython implementation - try: - from cython_distance import isi_distance_cython as isi_distance_impl - except ImportError: - print("Warning: isi_distance_cython not found. Make sure that PySpike \ -is installed by running\n 'python setup.py build_ext --inplace'!\n \ -Falling back to slow python backend.") - # use python backend - from python_backend import isi_distance_python as isi_distance_impl - - times, values = isi_distance_impl(spikes1, spikes2) - return PieceWiseConstFunc(times, values) - - -############################################################ -# isi_distance -############################################################ -def isi_distance(spikes1, spikes2, interval=None): - """ Computes the isi-distance I of the given spike trains. The - isi-distance is the integral over the isi distance profile - :math:`S_{isi}(t)`: - - .. math:: I = \int_{T_0}^{T_1} S_{isi}(t) dt. - - :param spikes1: ordered array of spike times with auxiliary spikes. - :param spikes2: ordered array of spike times with auxiliary spikes. - :param interval: averaging interval given as a pair of floats (T0, T1), - if None the average over the whole function is computed. - :type interval: Pair of floats or None. - :returns: The isi-distance I. - :rtype: double - """ - return isi_profile(spikes1, spikes2).avrg(interval) - - -############################################################ -# spike_profile -############################################################ -def spike_profile(spikes1, spikes2): - """ Computes the spike-distance profile S_spike(t) of the two given spike - trains. Returns the profile as a PieceWiseLinFunc object. The S_spike - values are defined positive S_spike(t)>=0. The spike trains are expected to - have auxiliary spikes at the beginning and end of the interval. Use the - function add_auxiliary_spikes to add those spikes to the spike train. - - :param spikes1: ordered array of spike times with auxiliary spikes. - :param spikes2: ordered array of spike times with auxiliary spikes. - :returns: The spike-distance profile :math:`S_{spike}(t)`. - :rtype: :class:`pyspike.function.PieceWiseLinFunc` - - """ - # check for auxiliary spikes - first and last spikes should be identical - assert spikes1[0] == spikes2[0], \ - "Given spike trains seems not to have auxiliary spikes!" - assert spikes1[-1] == spikes2[-1], \ - "Given spike trains seems not to have auxiliary spikes!" - - # cython implementation - try: - from cython_distance import spike_distance_cython \ - as spike_distance_impl - except ImportError: - print("Warning: spike_distance_cython not found. Make sure that \ -PySpike is installed by running\n 'python setup.py build_ext --inplace'!\n \ -Falling back to slow python backend.") - # use python backend - from python_backend import spike_distance_python as spike_distance_impl - - times, y_starts, y_ends = spike_distance_impl(spikes1, spikes2) - return PieceWiseLinFunc(times, y_starts, y_ends) - - -############################################################ -# spike_distance -############################################################ -def spike_distance(spikes1, spikes2, interval=None): - """ Computes the spike-distance S of the given spike trains. The - spike-distance is the integral over the isi distance profile S_spike(t): - - .. math:: S = \int_{T_0}^{T_1} S_{spike}(t) dt. - - :param spikes1: ordered array of spike times with auxiliary spikes. - :param spikes2: ordered array of spike times with auxiliary spikes. - :param interval: averaging interval given as a pair of floats (T0, T1), - if None the average over the whole function is computed. - :type interval: Pair of floats or None. - :returns: The spike-distance. - :rtype: double - - """ - return spike_profile(spikes1, spikes2).avrg(interval) - - -############################################################ -# spike_sync_profile -############################################################ -def spike_sync_profile(spikes1, spikes2): - """ Computes the spike-synchronization profile S_sync(t) of the two given - spike trains. Returns the profile as a DiscreteFunction object. The S_sync - values are either 1 or 0, indicating the presence or absence of a - coincidence. The spike trains are expected to have auxiliary spikes at the - beginning and end of the interval. Use the function add_auxiliary_spikes to - add those spikes to the spike train. - - :param spikes1: ordered array of spike times with auxiliary spikes. - :param spikes2: ordered array of spike times with auxiliary spikes. - :returns: The spike-distance profile :math:`S_{sync}(t)`. - :rtype: :class:`pyspike.function.DiscreteFunction` - - """ - - # cython implementation - try: - from cython_distance import coincidence_cython \ - as coincidence_impl - except ImportError: - print("Warning: spike_distance_cython not found. Make sure that \ -PySpike is installed by running\n 'python setup.py build_ext --inplace'!\n \ -Falling back to slow python backend.") - # use python backend - from python_backend import coincidence_python \ - as coincidence_impl - - times, coincidences, multiplicity = coincidence_impl(spikes1, spikes2) - - return DiscreteFunc(times, coincidences, multiplicity) - - -############################################################ -# spike_sync -############################################################ -def spike_sync(spikes1, spikes2, interval=None): - """ Computes the spike synchronization value SYNC of the given spike - trains. The spike synchronization value is the computed as the total number - of coincidences divided by the total number of spikes: - - .. math:: SYNC = \sum_n C_n / N. - - :param spikes1: ordered array of spike times with auxiliary spikes. - :param spikes2: ordered array of spike times with auxiliary spikes. - :param interval: averaging interval given as a pair of floats (T0, T1), - if None the average over the whole function is computed. - :type interval: Pair of floats or None. - :returns: The spike synchronization value. - :rtype: double - """ - return spike_sync_profile(spikes1, spikes2).avrg(interval) - - -############################################################ -# _generic_profile_multi -############################################################ -def _generic_profile_multi(spike_trains, pair_distance_func, indices=None): - """ Internal implementation detail, don't call this function directly, - use isi_profile_multi or spike_profile_multi instead. - - Computes the multi-variate distance for a set of spike-trains using the - pair_dist_func to compute pair-wise distances. That is it computes the - average distance of all pairs of spike-trains: - :math:`S(t) = 2/((N(N-1)) sum_{} S_{i,j}`, - where the sum goes over all pairs . - Args: - - spike_trains: list of spike trains - - pair_distance_func: function computing the distance of two spike trains - - indices: list of indices defining which spike trains to use, - if None all given spike trains are used (default=None) - Returns: - - The averaged multi-variate distance of all pairs - """ - if indices is None: - indices = np.arange(len(spike_trains)) - indices = np.array(indices) - # check validity of indices - assert (indices < len(spike_trains)).all() and (indices >= 0).all(), \ - "Invalid index list." - # generate a list of possible index pairs - pairs = [(indices[i], j) for i in range(len(indices)) - for j in indices[i+1:]] - # start with first pair - (i, j) = pairs[0] - average_dist = pair_distance_func(spike_trains[i], spike_trains[j]) - for (i, j) in pairs[1:]: - current_dist = pair_distance_func(spike_trains[i], spike_trains[j]) - average_dist.add(current_dist) # add to the average - return average_dist, len(pairs) - - -############################################################ -# multi_distance_par -############################################################ -def _multi_distance_par(spike_trains, pair_distance_func, indices=None): - """ parallel implementation of the multi-distance. Not currently used as - it does not improve the performance. - """ - - num_threads = 2 - lock = threading.Lock() - - def run(spike_trains, index_pairs, average_dist): - (i, j) = index_pairs[0] - # print(i,j) - this_avrg = pair_distance_func(spike_trains[i], spike_trains[j]) - for (i, j) in index_pairs[1:]: - # print(i,j) - current_dist = pair_distance_func(spike_trains[i], spike_trains[j]) - this_avrg.add(current_dist) - with lock: - average_dist.add(this_avrg) - - if indices is None: - indices = np.arange(len(spike_trains)) - indices = np.array(indices) - # check validity of indices - assert (indices < len(spike_trains)).all() and (indices >= 0).all(), \ - "Invalid index list." - # generate a list of possible index pairs - pairs = [(indices[i], j) for i in range(len(indices)) - for j in indices[i+1:]] - num_pairs = len(pairs) - - # start with first pair - (i, j) = pairs[0] - average_dist = pair_distance_func(spike_trains[i], spike_trains[j]) - # remove the one we already computed - pairs = pairs[1:] - # distribute the rest into num_threads pieces - clustered_pairs = [pairs[n::num_threads] for n in xrange(num_threads)] - - threads = [] - for pairs in clustered_pairs: - t = threading.Thread(target=run, args=(spike_trains, pairs, - average_dist)) - threads.append(t) - t.start() - for t in threads: - t.join() - average_dist.mul_scalar(1.0/num_pairs) # normalize - return average_dist - - -############################################################ -# isi_profile_multi -############################################################ -def isi_profile_multi(spike_trains, indices=None): - """ computes the multi-variate isi distance profile for a set of spike - trains. That is the average isi-distance of all pairs of spike-trains: - S_isi(t) = 2/((N(N-1)) sum_{} S_{isi}^{i,j}, - where the sum goes over all pairs - - :param spike_trains: list of spike trains - :param indices: list of indices defining which spike trains to use, - if None all given spike trains are used (default=None) - :type state: list or None - :returns: The averaged isi profile :math:`(t)` - :rtype: :class:`pyspike.function.PieceWiseConstFunc` - """ - average_dist, M = _generic_profile_multi(spike_trains, isi_profile, - indices) - average_dist.mul_scalar(1.0/M) # normalize - return average_dist - - -############################################################ -# isi_distance_multi -############################################################ -def isi_distance_multi(spike_trains, indices=None, interval=None): - """ computes the multi-variate isi-distance for a set of spike-trains. - That is the time average of the multi-variate spike profile: - I = \int_0^T 2/((N(N-1)) sum_{} S_{isi}^{i,j}, - where the sum goes over all pairs - - :param spike_trains: list of spike trains - :param indices: list of indices defining which spike trains to use, - if None all given spike trains are used (default=None) - :param interval: averaging interval given as a pair of floats, if None - the average over the whole function is computed. - :type interval: Pair of floats or None. - :returns: The time-averaged isi distance :math:`I` - :rtype: double - """ - return isi_profile_multi(spike_trains, indices).avrg(interval) - - -############################################################ -# spike_profile_multi -############################################################ -def spike_profile_multi(spike_trains, indices=None): - """ Computes the multi-variate spike distance profile for a set of spike - trains. That is the average spike-distance of all pairs of spike-trains: - :math:`S_spike(t) = 2/((N(N-1)) sum_{} S_{spike}^{i, j}`, - where the sum goes over all pairs - - :param spike_trains: list of spike trains - :param indices: list of indices defining which spike trains to use, - if None all given spike trains are used (default=None) - :type indices: list or None - :returns: The averaged spike profile :math:`(t)` - :rtype: :class:`pyspike.function.PieceWiseLinFunc` - - """ - average_dist, M = _generic_profile_multi(spike_trains, spike_profile, - indices) - average_dist.mul_scalar(1.0/M) # normalize - return average_dist - - -############################################################ -# spike_distance_multi -############################################################ -def spike_distance_multi(spike_trains, indices=None, interval=None): - """ Computes the multi-variate spike distance for a set of spike trains. - That is the time average of the multi-variate spike profile: - S_{spike} = \int_0^T 2/((N(N-1)) sum_{} S_{spike}^{i, j} dt - where the sum goes over all pairs - - :param spike_trains: list of spike trains - :param indices: list of indices defining which spike trains to use, - if None all given spike trains are used (default=None) - :type indices: list or None - :param interval: averaging interval given as a pair of floats, if None - the average over the whole function is computed. - :type interval: Pair of floats or None. - :returns: The averaged spike distance S. - :rtype: double - """ - return spike_profile_multi(spike_trains, indices).avrg(interval) - - -############################################################ -# spike_profile_multi -############################################################ -def spike_sync_profile_multi(spike_trains, indices=None): - """ Computes the multi-variate spike synchronization profile for a set of - spike trains. For each spike in the set of spike trains, the multi-variate - profile is defined as the number of coincidences divided by the number of - spike trains pairs involving the spike train of containing this spike, - which is the number of spike trains minus one (N-1). - - :param spike_trains: list of spike trains - :param indices: list of indices defining which spike trains to use, - if None all given spike trains are used (default=None) - :type indices: list or None - :returns: The multi-variate spike sync profile :math:`(t)` - :rtype: :class:`pyspike.function.DiscreteFunction` - - """ - prof_func = partial(spike_sync_profile) - average_dist, M = _generic_profile_multi(spike_trains, prof_func, - indices) - # average_dist.mul_scalar(1.0/M) # no normalization here! - return average_dist - - -############################################################ -# spike_distance_multi -############################################################ -def spike_sync_multi(spike_trains, indices=None, interval=None): - """ Computes the multi-variate spike synchronization value for a set of - spike trains. - - :param spike_trains: list of spike trains - :param indices: list of indices defining which spike trains to use, - if None all given spike trains are used (default=None) - :type indices: list or None - :param interval: averaging interval given as a pair of floats, if None - the average over the whole function is computed. - :type interval: Pair of floats or None. - :returns: The multi-variate spike synchronization value SYNC. - :rtype: double - """ - return spike_sync_profile_multi(spike_trains, indices).avrg(interval) - - -############################################################ -# generic_distance_matrix -############################################################ -def _generic_distance_matrix(spike_trains, dist_function, - indices=None, interval=None): - """ Internal implementation detail. Don't use this function directly. - Instead use isi_distance_matrix or spike_distance_matrix. - Computes the time averaged distance of all pairs of spike-trains. - Args: - - spike_trains: list of spike trains - - indices: list of indices defining which spike-trains to use - if None all given spike-trains are used (default=None) - Return: - - a 2D array of size len(indices)*len(indices) containing the average - pair-wise distance - """ - if indices is None: - indices = np.arange(len(spike_trains)) - indices = np.array(indices) - # check validity of indices - assert (indices < len(spike_trains)).all() and (indices >= 0).all(), \ - "Invalid index list." - # generate a list of possible index pairs - pairs = [(indices[i], j) for i in range(len(indices)) - for j in indices[i+1:]] - - distance_matrix = np.zeros((len(indices), len(indices))) - for i, j in pairs: - d = dist_function(spike_trains[i], spike_trains[j], interval) - distance_matrix[i, j] = d - distance_matrix[j, i] = d - return distance_matrix - - -############################################################ -# isi_distance_matrix -############################################################ -def isi_distance_matrix(spike_trains, indices=None, interval=None): - """ Computes the time averaged isi-distance of all pairs of spike-trains. - - :param spike_trains: list of spike trains - :param indices: list of indices defining which spike trains to use, - if None all given spike trains are used (default=None) - :type indices: list or None - :param interval: averaging interval given as a pair of floats, if None - the average over the whole function is computed. - :type interval: Pair of floats or None. - :returns: 2D array with the pair wise time average isi distances - :math:`I_{ij}` - :rtype: np.array - """ - return _generic_distance_matrix(spike_trains, isi_distance, - indices, interval) - - -############################################################ -# spike_distance_matrix -############################################################ -def spike_distance_matrix(spike_trains, indices=None, interval=None): - """ Computes the time averaged spike-distance of all pairs of spike-trains. - - :param spike_trains: list of spike trains - :param indices: list of indices defining which spike trains to use, - if None all given spike trains are used (default=None) - :type indices: list or None - :param interval: averaging interval given as a pair of floats, if None - the average over the whole function is computed. - :type interval: Pair of floats or None. - :returns: 2D array with the pair wise time average spike distances - :math:`S_{ij}` - :rtype: np.array - """ - return _generic_distance_matrix(spike_trains, spike_distance, - indices, interval) - - -############################################################ -# spike_sync_matrix -############################################################ -def spike_sync_matrix(spike_trains, indices=None, interval=None): - """ Computes the overall spike-synchronization value of all pairs of - spike-trains. - - :param spike_trains: list of spike trains - :param indices: list of indices defining which spike trains to use, - if None all given spike trains are used (default=None) - :type indices: list or None - :param interval: averaging interval given as a pair of floats, if None - the average over the whole function is computed. - :type interval: Pair of floats or None. - :returns: 2D array with the pair wise time spike synchronization values - :math:`SYNC_{ij}` - :rtype: np.array - """ - return _generic_distance_matrix(spike_trains, spike_sync, - indices, interval) diff --git a/pyspike/generic.py b/pyspike/generic.py new file mode 100644 index 0000000..4f278d2 --- /dev/null +++ b/pyspike/generic.py @@ -0,0 +1,83 @@ +""" + +Generic functions to compute multi-variate profiles and distance matrices. + +Copyright 2015, Mario Mulansky + +Distributed under the BSD License +""" + + +import numpy as np + + +############################################################ +# _generic_profile_multi +############################################################ +def _generic_profile_multi(spike_trains, pair_distance_func, indices=None): + """ Internal implementation detail, don't call this function directly, + use isi_profile_multi or spike_profile_multi instead. + + Computes the multi-variate distance for a set of spike-trains using the + pair_dist_func to compute pair-wise distances. That is it computes the + average distance of all pairs of spike-trains: + :math:`S(t) = 2/((N(N-1)) sum_{} S_{i,j}`, + where the sum goes over all pairs . + Args: + - spike_trains: list of spike trains + - pair_distance_func: function computing the distance of two spike trains + - indices: list of indices defining which spike trains to use, + if None all given spike trains are used (default=None) + Returns: + - The averaged multi-variate distance of all pairs + """ + if indices is None: + indices = np.arange(len(spike_trains)) + indices = np.array(indices) + # check validity of indices + assert (indices < len(spike_trains)).all() and (indices >= 0).all(), \ + "Invalid index list." + # generate a list of possible index pairs + pairs = [(indices[i], j) for i in range(len(indices)) + for j in indices[i+1:]] + # start with first pair + (i, j) = pairs[0] + average_dist = pair_distance_func(spike_trains[i], spike_trains[j]) + for (i, j) in pairs[1:]: + current_dist = pair_distance_func(spike_trains[i], spike_trains[j]) + average_dist.add(current_dist) # add to the average + return average_dist, len(pairs) + + +############################################################ +# generic_distance_matrix +############################################################ +def _generic_distance_matrix(spike_trains, dist_function, + indices=None, interval=None): + """ Internal implementation detail. Don't use this function directly. + Instead use isi_distance_matrix or spike_distance_matrix. + Computes the time averaged distance of all pairs of spike-trains. + Args: + - spike_trains: list of spike trains + - indices: list of indices defining which spike-trains to use + if None all given spike-trains are used (default=None) + Return: + - a 2D array of size len(indices)*len(indices) containing the average + pair-wise distance + """ + if indices is None: + indices = np.arange(len(spike_trains)) + indices = np.array(indices) + # check validity of indices + assert (indices < len(spike_trains)).all() and (indices >= 0).all(), \ + "Invalid index list." + # generate a list of possible index pairs + pairs = [(indices[i], j) for i in range(len(indices)) + for j in indices[i+1:]] + + distance_matrix = np.zeros((len(indices), len(indices))) + for i, j in pairs: + d = dist_function(spike_trains[i], spike_trains[j], interval) + distance_matrix[i, j] = d + distance_matrix[j, i] = d + return distance_matrix diff --git a/pyspike/isi_distance.py b/pyspike/isi_distance.py new file mode 100644 index 0000000..745d280 --- /dev/null +++ b/pyspike/isi_distance.py @@ -0,0 +1,132 @@ +""" + +Module containing several functions to compute the ISI profiles and distances + +Copyright 2014-2015, Mario Mulansky + +Distributed under the BSD License +""" + +from pyspike import PieceWiseConstFunc +from pyspike.generic import _generic_profile_multi, _generic_distance_matrix + + +############################################################ +# isi_profile +############################################################ +def isi_profile(spikes1, spikes2): + """ Computes the isi-distance profile :math:`S_{isi}(t)` of the two given + spike trains. Retruns the profile as a PieceWiseConstFunc object. The S_isi + values are defined positive S_isi(t)>=0. The spike trains are expected + to have auxiliary spikes at the beginning and end of the interval. Use the + function add_auxiliary_spikes to add those spikes to the spike train. + + :param spikes1: ordered array of spike times with auxiliary spikes. + :param spikes2: ordered array of spike times with auxiliary spikes. + :returns: The isi-distance profile :math:`S_{isi}(t)` + :rtype: :class:`pyspike.function.PieceWiseConstFunc` + + """ + # check for auxiliary spikes - first and last spikes should be identical + assert spikes1[0] == spikes2[0], \ + "Given spike trains seems not to have auxiliary spikes!" + assert spikes1[-1] == spikes2[-1], \ + "Given spike trains seems not to have auxiliary spikes!" + + # load cython implementation + try: + from cython_distance import isi_distance_cython as isi_distance_impl + except ImportError: + print("Warning: isi_distance_cython not found. Make sure that PySpike \ +is installed by running\n 'python setup.py build_ext --inplace'!\n \ +Falling back to slow python backend.") + # use python backend + from python_backend import isi_distance_python as isi_distance_impl + + times, values = isi_distance_impl(spikes1, spikes2) + return PieceWiseConstFunc(times, values) + + +############################################################ +# isi_distance +############################################################ +def isi_distance(spikes1, spikes2, interval=None): + """ Computes the isi-distance I of the given spike trains. The + isi-distance is the integral over the isi distance profile + :math:`S_{isi}(t)`: + + .. math:: I = \int_{T_0}^{T_1} S_{isi}(t) dt. + + :param spikes1: ordered array of spike times with auxiliary spikes. + :param spikes2: ordered array of spike times with auxiliary spikes. + :param interval: averaging interval given as a pair of floats (T0, T1), + if None the average over the whole function is computed. + :type interval: Pair of floats or None. + :returns: The isi-distance I. + :rtype: double + """ + return isi_profile(spikes1, spikes2).avrg(interval) + + +############################################################ +# isi_profile_multi +############################################################ +def isi_profile_multi(spike_trains, indices=None): + """ computes the multi-variate isi distance profile for a set of spike + trains. That is the average isi-distance of all pairs of spike-trains: + S_isi(t) = 2/((N(N-1)) sum_{} S_{isi}^{i,j}, + where the sum goes over all pairs + + :param spike_trains: list of spike trains + :param indices: list of indices defining which spike trains to use, + if None all given spike trains are used (default=None) + :type state: list or None + :returns: The averaged isi profile :math:`(t)` + :rtype: :class:`pyspike.function.PieceWiseConstFunc` + """ + average_dist, M = _generic_profile_multi(spike_trains, isi_profile, + indices) + average_dist.mul_scalar(1.0/M) # normalize + return average_dist + + +############################################################ +# isi_distance_multi +############################################################ +def isi_distance_multi(spike_trains, indices=None, interval=None): + """ computes the multi-variate isi-distance for a set of spike-trains. + That is the time average of the multi-variate spike profile: + I = \int_0^T 2/((N(N-1)) sum_{} S_{isi}^{i,j}, + where the sum goes over all pairs + + :param spike_trains: list of spike trains + :param indices: list of indices defining which spike trains to use, + if None all given spike trains are used (default=None) + :param interval: averaging interval given as a pair of floats, if None + the average over the whole function is computed. + :type interval: Pair of floats or None. + :returns: The time-averaged isi distance :math:`I` + :rtype: double + """ + return isi_profile_multi(spike_trains, indices).avrg(interval) + + +############################################################ +# isi_distance_matrix +############################################################ +def isi_distance_matrix(spike_trains, indices=None, interval=None): + """ Computes the time averaged isi-distance of all pairs of spike-trains. + + :param spike_trains: list of spike trains + :param indices: list of indices defining which spike trains to use, + if None all given spike trains are used (default=None) + :type indices: list or None + :param interval: averaging interval given as a pair of floats, if None + the average over the whole function is computed. + :type interval: Pair of floats or None. + :returns: 2D array with the pair wise time average isi distances + :math:`I_{ij}` + :rtype: np.array + """ + return _generic_distance_matrix(spike_trains, isi_distance, + indices, interval) diff --git a/pyspike/spike_distance.py b/pyspike/spike_distance.py new file mode 100644 index 0000000..2c989a4 --- /dev/null +++ b/pyspike/spike_distance.py @@ -0,0 +1,135 @@ +""" + +Module containing several functions to compute SPIKE profiles and distances + +Copyright 2014-2015, Mario Mulansky + +Distributed under the BSD License +""" + +from pyspike import PieceWiseLinFunc +from pyspike.generic import _generic_profile_multi, _generic_distance_matrix + + +############################################################ +# spike_profile +############################################################ +def spike_profile(spikes1, spikes2): + """ Computes the spike-distance profile S_spike(t) of the two given spike + trains. Returns the profile as a PieceWiseLinFunc object. The S_spike + values are defined positive S_spike(t)>=0. The spike trains are expected to + have auxiliary spikes at the beginning and end of the interval. Use the + function add_auxiliary_spikes to add those spikes to the spike train. + + :param spikes1: ordered array of spike times with auxiliary spikes. + :param spikes2: ordered array of spike times with auxiliary spikes. + :returns: The spike-distance profile :math:`S_{spike}(t)`. + :rtype: :class:`pyspike.function.PieceWiseLinFunc` + + """ + # check for auxiliary spikes - first and last spikes should be identical + assert spikes1[0] == spikes2[0], \ + "Given spike trains seems not to have auxiliary spikes!" + assert spikes1[-1] == spikes2[-1], \ + "Given spike trains seems not to have auxiliary spikes!" + + # cython implementation + try: + from cython_distance import spike_distance_cython \ + as spike_distance_impl + except ImportError: + print("Warning: spike_distance_cython not found. Make sure that \ +PySpike is installed by running\n 'python setup.py build_ext --inplace'!\n \ +Falling back to slow python backend.") + # use python backend + from python_backend import spike_distance_python as spike_distance_impl + + times, y_starts, y_ends = spike_distance_impl(spikes1, spikes2) + return PieceWiseLinFunc(times, y_starts, y_ends) + + +############################################################ +# spike_distance +############################################################ +def spike_distance(spikes1, spikes2, interval=None): + """ Computes the spike-distance S of the given spike trains. The + spike-distance is the integral over the isi distance profile S_spike(t): + + .. math:: S = \int_{T_0}^{T_1} S_{spike}(t) dt. + + :param spikes1: ordered array of spike times with auxiliary spikes. + :param spikes2: ordered array of spike times with auxiliary spikes. + :param interval: averaging interval given as a pair of floats (T0, T1), + if None the average over the whole function is computed. + :type interval: Pair of floats or None. + :returns: The spike-distance. + :rtype: double + + """ + return spike_profile(spikes1, spikes2).avrg(interval) + + +############################################################ +# spike_profile_multi +############################################################ +def spike_profile_multi(spike_trains, indices=None): + """ Computes the multi-variate spike distance profile for a set of spike + trains. That is the average spike-distance of all pairs of spike-trains: + :math:`S_spike(t) = 2/((N(N-1)) sum_{} S_{spike}^{i, j}`, + where the sum goes over all pairs + + :param spike_trains: list of spike trains + :param indices: list of indices defining which spike trains to use, + if None all given spike trains are used (default=None) + :type indices: list or None + :returns: The averaged spike profile :math:`(t)` + :rtype: :class:`pyspike.function.PieceWiseLinFunc` + + """ + average_dist, M = _generic_profile_multi(spike_trains, spike_profile, + indices) + average_dist.mul_scalar(1.0/M) # normalize + return average_dist + + +############################################################ +# spike_distance_multi +############################################################ +def spike_distance_multi(spike_trains, indices=None, interval=None): + """ Computes the multi-variate spike distance for a set of spike trains. + That is the time average of the multi-variate spike profile: + S_{spike} = \int_0^T 2/((N(N-1)) sum_{} S_{spike}^{i, j} dt + where the sum goes over all pairs + + :param spike_trains: list of spike trains + :param indices: list of indices defining which spike trains to use, + if None all given spike trains are used (default=None) + :type indices: list or None + :param interval: averaging interval given as a pair of floats, if None + the average over the whole function is computed. + :type interval: Pair of floats or None. + :returns: The averaged spike distance S. + :rtype: double + """ + return spike_profile_multi(spike_trains, indices).avrg(interval) + + +############################################################ +# spike_distance_matrix +############################################################ +def spike_distance_matrix(spike_trains, indices=None, interval=None): + """ Computes the time averaged spike-distance of all pairs of spike-trains. + + :param spike_trains: list of spike trains + :param indices: list of indices defining which spike trains to use, + if None all given spike trains are used (default=None) + :type indices: list or None + :param interval: averaging interval given as a pair of floats, if None + the average over the whole function is computed. + :type interval: Pair of floats or None. + :returns: 2D array with the pair wise time average spike distances + :math:`S_{ij}` + :rtype: np.array + """ + return _generic_distance_matrix(spike_trains, spike_distance, + indices, interval) diff --git a/pyspike/spike_sync.py b/pyspike/spike_sync.py new file mode 100644 index 0000000..f7cbe1d --- /dev/null +++ b/pyspike/spike_sync.py @@ -0,0 +1,136 @@ +""" + +Module containing several functions to compute SPIKE-Synchronization profiles +and distances + +Copyright 2014-2015, Mario Mulansky + +Distributed under the BSD License +""" + +from functools import partial +from pyspike import DiscreteFunc +from pyspike.generic import _generic_profile_multi, _generic_distance_matrix + + +############################################################ +# spike_sync_profile +############################################################ +def spike_sync_profile(spikes1, spikes2): + """ Computes the spike-synchronization profile S_sync(t) of the two given + spike trains. Returns the profile as a DiscreteFunction object. The S_sync + values are either 1 or 0, indicating the presence or absence of a + coincidence. The spike trains are expected to have auxiliary spikes at the + beginning and end of the interval. Use the function add_auxiliary_spikes to + add those spikes to the spike train. + + :param spikes1: ordered array of spike times with auxiliary spikes. + :param spikes2: ordered array of spike times with auxiliary spikes. + :returns: The spike-distance profile :math:`S_{sync}(t)`. + :rtype: :class:`pyspike.function.DiscreteFunction` + + """ + + # cython implementation + try: + from cython_distance import coincidence_cython \ + as coincidence_impl + except ImportError: + print("Warning: spike_distance_cython not found. Make sure that \ +PySpike is installed by running\n 'python setup.py build_ext --inplace'!\n \ +Falling back to slow python backend.") + # use python backend + from python_backend import coincidence_python \ + as coincidence_impl + + times, coincidences, multiplicity = coincidence_impl(spikes1, spikes2) + + return DiscreteFunc(times, coincidences, multiplicity) + + +############################################################ +# spike_sync +############################################################ +def spike_sync(spikes1, spikes2, interval=None): + """ Computes the spike synchronization value SYNC of the given spike + trains. The spike synchronization value is the computed as the total number + of coincidences divided by the total number of spikes: + + .. math:: SYNC = \sum_n C_n / N. + + :param spikes1: ordered array of spike times with auxiliary spikes. + :param spikes2: ordered array of spike times with auxiliary spikes. + :param interval: averaging interval given as a pair of floats (T0, T1), + if None the average over the whole function is computed. + :type interval: Pair of floats or None. + :returns: The spike synchronization value. + :rtype: double + """ + return spike_sync_profile(spikes1, spikes2).avrg(interval) + + +############################################################ +# spike_sync_profile_multi +############################################################ +def spike_sync_profile_multi(spike_trains, indices=None): + """ Computes the multi-variate spike synchronization profile for a set of + spike trains. For each spike in the set of spike trains, the multi-variate + profile is defined as the number of coincidences divided by the number of + spike trains pairs involving the spike train of containing this spike, + which is the number of spike trains minus one (N-1). + + :param spike_trains: list of spike trains + :param indices: list of indices defining which spike trains to use, + if None all given spike trains are used (default=None) + :type indices: list or None + :returns: The multi-variate spike sync profile :math:`(t)` + :rtype: :class:`pyspike.function.DiscreteFunction` + + """ + prof_func = partial(spike_sync_profile) + average_dist, M = _generic_profile_multi(spike_trains, prof_func, + indices) + # average_dist.mul_scalar(1.0/M) # no normalization here! + return average_dist + + +############################################################ +# spike_distance_multi +############################################################ +def spike_sync_multi(spike_trains, indices=None, interval=None): + """ Computes the multi-variate spike synchronization value for a set of + spike trains. + + :param spike_trains: list of spike trains + :param indices: list of indices defining which spike trains to use, + if None all given spike trains are used (default=None) + :type indices: list or None + :param interval: averaging interval given as a pair of floats, if None + the average over the whole function is computed. + :type interval: Pair of floats or None. + :returns: The multi-variate spike synchronization value SYNC. + :rtype: double + """ + return spike_sync_profile_multi(spike_trains, indices).avrg(interval) + + +############################################################ +# spike_sync_matrix +############################################################ +def spike_sync_matrix(spike_trains, indices=None, interval=None): + """ Computes the overall spike-synchronization value of all pairs of + spike-trains. + + :param spike_trains: list of spike trains + :param indices: list of indices defining which spike trains to use, + if None all given spike trains are used (default=None) + :type indices: list or None + :param interval: averaging interval given as a pair of floats, if None + the average over the whole function is computed. + :type interval: Pair of floats or None. + :returns: 2D array with the pair wise time spike synchronization values + :math:`SYNC_{ij}` + :rtype: np.array + """ + return _generic_distance_matrix(spike_trains, spike_sync, + indices, interval) -- cgit v1.2.3