From be74318a2b269ec0c1e16981e7286679746f1a49 Mon Sep 17 00:00:00 2001 From: Mario Mulansky Date: Mon, 17 Aug 2015 11:57:53 +0200 Subject: fix #15 add test case and fix for Issue #15 closes #15 --- test/test_regression/test_regression_15.py | 78 ++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 test/test_regression/test_regression_15.py (limited to 'test/test_regression/test_regression_15.py') diff --git a/test/test_regression/test_regression_15.py b/test/test_regression/test_regression_15.py new file mode 100644 index 0000000..1ce1290 --- /dev/null +++ b/test/test_regression/test_regression_15.py @@ -0,0 +1,78 @@ +""" test_regression_15.py + +Regression test for Issue #15 + +Copyright 2015, Mario Mulansky + +Distributed under the BSD License + +""" + +import numpy as np +from numpy.testing import assert_equal, assert_almost_equal, \ + assert_array_almost_equal + +import pyspike as spk + + +def test_regression_15_isi(): + # load spike trains + spike_trains = spk.load_spike_trains_from_txt("test/SPIKE_Sync_Test.txt", + edges=[0, 4000]) + + N = len(spike_trains) + + dist_mat = spk.isi_distance_matrix(spike_trains) + assert_equal(dist_mat.shape, (N, N)) + + ind = np.arange(N/2) + dist_mat = spk.isi_distance_matrix(spike_trains, ind) + assert_equal(dist_mat.shape, (N/2, N/2)) + + ind = np.arange(N/2, N) + dist_mat = spk.isi_distance_matrix(spike_trains, ind) + assert_equal(dist_mat.shape, (N/2, N/2)) + + +def test_regression_15_spike(): + # load spike trains + spike_trains = spk.load_spike_trains_from_txt("test/SPIKE_Sync_Test.txt", + edges=[0, 4000]) + + N = len(spike_trains) + + dist_mat = spk.spike_distance_matrix(spike_trains) + assert_equal(dist_mat.shape, (N, N)) + + ind = np.arange(N/2) + dist_mat = spk.spike_distance_matrix(spike_trains, ind) + assert_equal(dist_mat.shape, (N/2, N/2)) + + ind = np.arange(N/2, N) + dist_mat = spk.spike_distance_matrix(spike_trains, ind) + assert_equal(dist_mat.shape, (N/2, N/2)) + + +def test_regression_15_sync(): + # load spike trains + spike_trains = spk.load_spike_trains_from_txt("test/SPIKE_Sync_Test.txt", + edges=[0, 4000]) + + N = len(spike_trains) + + dist_mat = spk.spike_sync_matrix(spike_trains) + assert_equal(dist_mat.shape, (N, N)) + + ind = np.arange(N/2) + dist_mat = spk.spike_sync_matrix(spike_trains, ind) + assert_equal(dist_mat.shape, (N/2, N/2)) + + ind = np.arange(N/2, N) + dist_mat = spk.spike_sync_matrix(spike_trains, ind) + assert_equal(dist_mat.shape, (N/2, N/2)) + + +if __name__ == "__main__": + test_regression_15_isi() + test_regression_15_spike() + test_regression_15_sync() -- cgit v1.2.3 From fe1f6179cce645df2511bfedae3af90167308f5f Mon Sep 17 00:00:00 2001 From: Igor Gnatenko Date: Sun, 13 Dec 2015 11:01:34 +0100 Subject: py3: division Signed-off-by: Igor Gnatenko --- pyspike/generic.py | 5 +++-- test/test_regression/test_regression_15.py | 26 ++++++++++++++------------ 2 files changed, 17 insertions(+), 14 deletions(-) (limited to 'test/test_regression/test_regression_15.py') diff --git a/pyspike/generic.py b/pyspike/generic.py index 81ae660..5ad06f1 100644 --- a/pyspike/generic.py +++ b/pyspike/generic.py @@ -7,6 +7,7 @@ Copyright 2015, Mario Mulansky Distributed under the BSD License """ +from __future__ import division import numpy as np @@ -38,14 +39,14 @@ def _generic_profile_multi(spike_trains, pair_distance_func, indices=None): L1 = len(pairs1) if L1 > 1: dist_prof1 = divide_and_conquer(pairs1[:L1//2], - pairs1[int(L1//2):]) + pairs1[L1//2:]) else: dist_prof1 = pair_distance_func(spike_trains[pairs1[0][0]], spike_trains[pairs1[0][1]]) L2 = len(pairs2) if L2 > 1: dist_prof2 = divide_and_conquer(pairs2[:L2//2], - pairs2[int(L2//2):]) + pairs2[L2//2:]) else: dist_prof2 = pair_distance_func(spike_trains[pairs2[0][0]], spike_trains[pairs2[0][1]]) diff --git a/test/test_regression/test_regression_15.py b/test/test_regression/test_regression_15.py index 1ce1290..42a39ea 100644 --- a/test/test_regression/test_regression_15.py +++ b/test/test_regression/test_regression_15.py @@ -8,6 +8,8 @@ Distributed under the BSD License """ +from __future__ import division + import numpy as np from numpy.testing import assert_equal, assert_almost_equal, \ assert_array_almost_equal @@ -25,13 +27,13 @@ def test_regression_15_isi(): dist_mat = spk.isi_distance_matrix(spike_trains) assert_equal(dist_mat.shape, (N, N)) - ind = np.arange(N/2) + ind = np.arange(N//2) dist_mat = spk.isi_distance_matrix(spike_trains, ind) - assert_equal(dist_mat.shape, (N/2, N/2)) + assert_equal(dist_mat.shape, (N//2, N//2)) - ind = np.arange(N/2, N) + ind = np.arange(N//2, N) dist_mat = spk.isi_distance_matrix(spike_trains, ind) - assert_equal(dist_mat.shape, (N/2, N/2)) + assert_equal(dist_mat.shape, (N//2, N//2)) def test_regression_15_spike(): @@ -44,13 +46,13 @@ def test_regression_15_spike(): dist_mat = spk.spike_distance_matrix(spike_trains) assert_equal(dist_mat.shape, (N, N)) - ind = np.arange(N/2) + ind = np.arange(N//2) dist_mat = spk.spike_distance_matrix(spike_trains, ind) - assert_equal(dist_mat.shape, (N/2, N/2)) + assert_equal(dist_mat.shape, (N//2, N//2)) - ind = np.arange(N/2, N) + ind = np.arange(N//2, N) dist_mat = spk.spike_distance_matrix(spike_trains, ind) - assert_equal(dist_mat.shape, (N/2, N/2)) + assert_equal(dist_mat.shape, (N//2, N//2)) def test_regression_15_sync(): @@ -63,13 +65,13 @@ def test_regression_15_sync(): dist_mat = spk.spike_sync_matrix(spike_trains) assert_equal(dist_mat.shape, (N, N)) - ind = np.arange(N/2) + ind = np.arange(N//2) dist_mat = spk.spike_sync_matrix(spike_trains, ind) - assert_equal(dist_mat.shape, (N/2, N/2)) + assert_equal(dist_mat.shape, (N//2, N//2)) - ind = np.arange(N/2, N) + ind = np.arange(N//2, N) dist_mat = spk.spike_sync_matrix(spike_trains, ind) - assert_equal(dist_mat.shape, (N/2, N/2)) + assert_equal(dist_mat.shape, (N//2, N//2)) if __name__ == "__main__": -- cgit v1.2.3 From 45d4fac7b207bb5ce98f17433a443837fce0455a Mon Sep 17 00:00:00 2001 From: Igor Gnatenko Date: Mon, 14 Dec 2015 01:53:21 +0100 Subject: tests: allow to run out-of-tree Signed-off-by: Igor Gnatenko --- test/test_distance.py | 14 ++++++++------ test/test_regression/test_regression_15.py | 12 ++++++------ test/test_spikes.py | 9 +++++---- 3 files changed, 19 insertions(+), 16 deletions(-) (limited to 'test/test_regression/test_regression_15.py') diff --git a/test/test_distance.py b/test/test_distance.py index d5bce30..d405839 100644 --- a/test/test_distance.py +++ b/test/test_distance.py @@ -17,6 +17,8 @@ from numpy.testing import assert_equal, assert_almost_equal, \ import pyspike as spk from pyspike import SpikeTrain +import os +TEST_PATH = os.path.dirname(os.path.realpath(__file__)) def test_isi(): # generate two spike trains: @@ -275,8 +277,8 @@ def test_multi_spike_sync(): expected, decimal=15) # multivariate regression test - spike_trains = spk.load_spike_trains_from_txt("test/SPIKE_Sync_Test.txt", - edges=[0, 4000]) + spike_trains = spk.load_spike_trains_from_txt( + os.path.join(TEST_PATH, "SPIKE_Sync_Test.txt"), edges=[0, 4000]) # extract all spike times spike_times = np.array([]) for st in spike_trains: @@ -352,8 +354,8 @@ def test_regression_spiky(): # multivariate check - spike_trains = spk.load_spike_trains_from_txt("test/PySpike_testdata.txt", - (0.0, 4000.0)) + spike_trains = spk.load_spike_trains_from_txt( + os.path.join(TEST_PATH, "PySpike_testdata.txt"), (0.0, 4000.0)) isi_dist = spk.isi_distance_multi(spike_trains) # get the full precision from SPIKY assert_almost_equal(isi_dist, 0.17051816816999129656, decimal=15) @@ -371,8 +373,8 @@ def test_regression_spiky(): def test_multi_variate_subsets(): - spike_trains = spk.load_spike_trains_from_txt("test/PySpike_testdata.txt", - (0.0, 4000.0)) + spike_trains = spk.load_spike_trains_from_txt( + os.path.join(TEST_PATH, "PySpike_testdata.txt"), (0.0, 4000.0)) sub_set = [1, 3, 5, 7] spike_trains_sub_set = [spike_trains[i] for i in sub_set] diff --git a/test/test_regression/test_regression_15.py b/test/test_regression/test_regression_15.py index 42a39ea..dcacae2 100644 --- a/test/test_regression/test_regression_15.py +++ b/test/test_regression/test_regression_15.py @@ -16,11 +16,13 @@ from numpy.testing import assert_equal, assert_almost_equal, \ import pyspike as spk +import os +TEST_PATH = os.path.dirname(os.path.realpath(__file__)) +TEST_DATA = os.path.join(TEST_PATH, "..", "SPIKE_Sync_Test.txt") def test_regression_15_isi(): # load spike trains - spike_trains = spk.load_spike_trains_from_txt("test/SPIKE_Sync_Test.txt", - edges=[0, 4000]) + spike_trains = spk.load_spike_trains_from_txt(TEST_DATA, edges=[0, 4000]) N = len(spike_trains) @@ -38,8 +40,7 @@ def test_regression_15_isi(): def test_regression_15_spike(): # load spike trains - spike_trains = spk.load_spike_trains_from_txt("test/SPIKE_Sync_Test.txt", - edges=[0, 4000]) + spike_trains = spk.load_spike_trains_from_txt(TEST_DATA, edges=[0, 4000]) N = len(spike_trains) @@ -57,8 +58,7 @@ def test_regression_15_spike(): def test_regression_15_sync(): # load spike trains - spike_trains = spk.load_spike_trains_from_txt("test/SPIKE_Sync_Test.txt", - edges=[0, 4000]) + spike_trains = spk.load_spike_trains_from_txt(TEST_DATA, edges=[0, 4000]) N = len(spike_trains) diff --git a/test/test_spikes.py b/test/test_spikes.py index d4eb131..609a819 100644 --- a/test/test_spikes.py +++ b/test/test_spikes.py @@ -13,10 +13,12 @@ from numpy.testing import assert_equal import pyspike as spk +import os +TEST_PATH = os.path.dirname(os.path.realpath(__file__)) +TEST_DATA = os.path.join(TEST_PATH, "PySpike_testdata.txt") def test_load_from_txt(): - spike_trains = spk.load_spike_trains_from_txt("test/PySpike_testdata.txt", - edges=(0, 4000)) + spike_trains = spk.load_spike_trains_from_txt(TEST_DATA, edges=(0, 4000)) assert len(spike_trains) == 40 # check the first spike train @@ -48,8 +50,7 @@ def check_merged_spikes(merged_spikes, spike_trains): def test_merge_spike_trains(): # first load the data - spike_trains = spk.load_spike_trains_from_txt("test/PySpike_testdata.txt", - edges=(0, 4000)) + spike_trains = spk.load_spike_trains_from_txt(TEST_DATA, edges=(0, 4000)) merged_spikes = spk.merge_spike_trains([spike_trains[0], spike_trains[1]]) # test if result is sorted -- cgit v1.2.3 From ea3709e2f4367cb539acc26ec8e05b686d6bf836 Mon Sep 17 00:00:00 2001 From: Mario Mulansky Date: Sun, 31 Jan 2016 16:40:47 +0100 Subject: generic interface for spike distance/profile spike_profile and spike_distance now have a generic interface that allows to compute bi-variate and multi-variate results with the same function. --- pyspike/isi_distance.py | 17 +++- pyspike/spike_distance.py | 124 +++++++++++++++++++++-------- test/test_generic_interfaces.py | 31 +++++++- test/test_regression/test_regression_15.py | 1 + 4 files changed, 138 insertions(+), 35 deletions(-) (limited to 'test/test_regression/test_regression_15.py') diff --git a/pyspike/isi_distance.py b/pyspike/isi_distance.py index a85028f..122e11d 100644 --- a/pyspike/isi_distance.py +++ b/pyspike/isi_distance.py @@ -14,7 +14,7 @@ from pyspike.generic import _generic_profile_multi, _generic_distance_multi, \ # isi_profile ############################################################ def isi_profile(*args, **kwargs): - """ Computes the isi-distance profile :math:`I(t)` of the two given + """ Computes the isi-distance profile :math:`I(t)` of the given spike trains. Returns the profile as a PieceWiseConstFunc object. The ISI-values are defined positive :math:`I(t)>=0`. @@ -22,8 +22,9 @@ def isi_profile(*args, **kwargs): isi_profile(st1, st2) # returns the bi-variate profile isi_profile(st1, st2, st3) # multi-variate profile of 3 spike trains + spike_trains = [st1, st2, st3, st4] # list of spike trains - isi_profile(spike_trains) # return the profile the list of spike trains + isi_profile(spike_trains) # profile of the list of spike trains isi_profile(spike_trains, indices=[0, 1]) # use only the spike trains # given by the indices @@ -108,13 +109,23 @@ def isi_profile_multi(spike_trains, indices=None): # isi_distance ############################################################ def isi_distance(*args, **kwargs): - # spike_trains, spike_train2, interval=None): """ Computes the ISI-distance :math:`D_I` of the given spike trains. The isi-distance is the integral over the isi distance profile :math:`I(t)`: .. math:: D_I = \\int_{T_0}^{T_1} I(t) dt. + + Valid call structures:: + + isi_distance(st1, st2) # returns the bi-variate distance + isi_distance(st1, st2, st3) # multi-variate distance of 3 spike trains + + spike_trains = [st1, st2, st3, st4] # list of spike trains + isi_distance(spike_trains) # distance of the list of spike trains + isi_distance(spike_trains, indices=[0, 1]) # use only the spike trains + # given by the indices + :returns: The isi-distance :math:`D_I`. :rtype: double """ diff --git a/pyspike/spike_distance.py b/pyspike/spike_distance.py index e418283..7acb959 100644 --- a/pyspike/spike_distance.py +++ b/pyspike/spike_distance.py @@ -13,7 +13,36 @@ from pyspike.generic import _generic_profile_multi, _generic_distance_multi, \ ############################################################ # spike_profile ############################################################ -def spike_profile(spike_train1, spike_train2): +def spike_profile(*args, **kwargs): + """ Computes the spike-distance profile :math:`S(t)` of the given + spike trains. Returns the profile as a PieceWiseConstLin object. The + SPIKE-values are defined positive :math:`S(t)>=0`. + + Valid call structures:: + + spike_profile(st1, st2) # returns the bi-variate profile + spike_profile(st1, st2, st3) # multi-variate profile of 3 spike trains + + spike_trains = [st1, st2, st3, st4] # list of spike trains + spike_profile(spike_trains) # profile of the list of spike trains + spike_profile(spike_trains, indices=[0, 1]) # use only the spike trains + # given by the indices + + :returns: The spike-distance profile :math:`S(t)` + :rtype: :class:`.PieceWiseConstLin` + """ + if len(args) == 1: + return spike_profile_multi(args[0], **kwargs) + elif len(args) == 2: + return spike_profile_bi(args[0], args[1]) + else: + return spike_profile_multi(args) + + +############################################################ +# spike_profile_bi +############################################################ +def spike_profile_bi(spike_train1, spike_train2): """ Computes the spike-distance profile :math:`S(t)` of the two given spike trains. Returns the profile as a PieceWiseLinFunc object. The SPIKE-values are defined positive :math:`S(t)>=0`. @@ -53,10 +82,68 @@ Falling back to slow python backend.") return PieceWiseLinFunc(times, y_starts, y_ends) +############################################################ +# 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:: = \\frac{2}{N(N-1)} \\sum_{} S^{i, j}`, + + where the sum goes over all pairs + + :param spike_trains: list of :class:`.SpikeTrain` + :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:`.PieceWiseLinFunc` + + """ + average_dist, M = _generic_profile_multi(spike_trains, spike_profile_bi, + indices) + average_dist.mul_scalar(1.0/M) # normalize + return average_dist + + ############################################################ # spike_distance ############################################################ -def spike_distance(spike_train1, spike_train2, interval=None): +def spike_distance(*args, **kwargs): + """ Computes the SPIKE-distance :math:`D_S` of the given spike trains. The + spike-distance is the integral over the spike distance profile + :math:`D(t)`: + + .. math:: D_S = \\int_{T_0}^{T_1} S(t) dt. + + + Valid call structures:: + + spike_distance(st1, st2) # returns the bi-variate distance + spike_distance(st1, st2, st3) # multi-variate distance of 3 spike trains + + spike_trains = [st1, st2, st3, st4] # list of spike trains + spike_distance(spike_trains) # distance of the list of spike trains + spike_distance(spike_trains, indices=[0, 1]) # use only the spike trains + # given by the indices + + :returns: The spike-distance :math:`D_S`. + :rtype: double + """ + + if len(args) == 1: + return spike_distance_multi(args[0], **kwargs) + elif len(args) == 2: + return spike_distance_bi(args[0], args[1], **kwargs) + else: + return spike_distance_multi(args, **kwargs) + + +############################################################ +# spike_distance_bi +############################################################ +def spike_distance_bi(spike_train1, spike_train2, interval=None): """ Computes the spike-distance :math:`D_S` of the given spike trains. The spike-distance is the integral over the spike distance profile :math:`S(t)`: @@ -86,35 +173,10 @@ def spike_distance(spike_train1, spike_train2, interval=None): spike_train1.t_end) except ImportError: # Cython backend not available: fall back to average profile - return spike_profile(spike_train1, spike_train2).avrg(interval) + return spike_profile_bi(spike_train1, spike_train2).avrg(interval) else: # some specific interval is provided: compute the whole profile - return spike_profile(spike_train1, spike_train2).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:: = \\frac{2}{N(N-1)} \\sum_{} S^{i, j}`, - - where the sum goes over all pairs - - :param spike_trains: list of :class:`.SpikeTrain` - :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:`.PieceWiseLinFunc` - - """ - average_dist, M = _generic_profile_multi(spike_trains, spike_profile, - indices) - average_dist.mul_scalar(1.0/M) # normalize - return average_dist + return spike_profile_bi(spike_train1, spike_train2).avrg(interval) ############################################################ @@ -139,7 +201,7 @@ def spike_distance_multi(spike_trains, indices=None, interval=None): :returns: The averaged multi-variate spike distance :math:`D_S`. :rtype: double """ - return _generic_distance_multi(spike_trains, spike_distance, indices, + return _generic_distance_multi(spike_trains, spike_distance_bi, indices, interval) @@ -160,5 +222,5 @@ def spike_distance_matrix(spike_trains, indices=None, interval=None): :math:`D_S^{ij}` :rtype: np.array """ - return _generic_distance_matrix(spike_trains, spike_distance, + return _generic_distance_matrix(spike_trains, spike_distance_bi, indices, interval) diff --git a/test/test_generic_interfaces.py b/test/test_generic_interfaces.py index caa9ee4..ee87be4 100644 --- a/test/test_generic_interfaces.py +++ b/test/test_generic_interfaces.py @@ -23,7 +23,12 @@ class dist_from_prof: self.prof_func = prof_func def __call__(self, *args, **kwargs): - return self.prof_func(*args, **kwargs).avrg() + if "interval" in kwargs: + # forward interval arg into avrg function + interval = kwargs.pop("interval") + return self.prof_func(*args, **kwargs).avrg(interval=interval) + else: + return self.prof_func(*args, **kwargs).avrg() def check_func(dist_func): @@ -50,6 +55,22 @@ def check_func(dist_func): isi123_ = dist_func(spike_trains, indices=[0, 1, 2]) assert_equal(isi123, isi123_) + # run the same test with an additional interval parameter + + isi12 = dist_func(t1, t2, interval=[0.0, 0.5]) + isi12_ = dist_func([t1, t2], interval=[0.0, 0.5]) + assert_equal(isi12, isi12_) + + isi12_ = dist_func(spike_trains, indices=[0, 1], interval=[0.0, 0.5]) + assert_equal(isi12, isi12_) + + isi123 = dist_func(t1, t2, t3, interval=[0.0, 0.5]) + isi123_ = dist_func([t1, t2, t3], interval=[0.0, 0.5]) + assert_equal(isi123, isi123_) + + isi123_ = dist_func(spike_trains, indices=[0, 1, 2], interval=[0.0, 0.5]) + assert_equal(isi123, isi123_) + def test_isi_profile(): check_func(dist_from_prof(spk.isi_profile)) @@ -59,6 +80,14 @@ def test_isi_distance(): check_func(spk.isi_distance) +def test_spike_profile(): + check_func(dist_from_prof(spk.spike_profile)) + + +def test_spike_distance(): + check_func(spk.spike_distance) + + if __name__ == "__main__": test_isi_profile() test_isi_distance() diff --git a/test/test_regression/test_regression_15.py b/test/test_regression/test_regression_15.py index dcacae2..54adf23 100644 --- a/test/test_regression/test_regression_15.py +++ b/test/test_regression/test_regression_15.py @@ -20,6 +20,7 @@ import os TEST_PATH = os.path.dirname(os.path.realpath(__file__)) TEST_DATA = os.path.join(TEST_PATH, "..", "SPIKE_Sync_Test.txt") + def test_regression_15_isi(): # load spike trains spike_trains = spk.load_spike_trains_from_txt(TEST_DATA, edges=[0, 4000]) -- cgit v1.2.3