Skip to content
Commits on Source (3)
0.3.3
- fix: add constant `ZERO_CUTOFF` that defines when a trace average is
treated as zero
- enh: replace asserts with raises (#15)
0.3.2
- fix: multipletau package not available when building the docs
0.3.1
......
......@@ -3,7 +3,7 @@ multipletau
|PyPI Version| |Tests Status| |Coverage Status| |Docs Status|
Multipe-tau correlation is computed on a logarithmic scale (less
Multiple-tau correlation is computed on a logarithmic scale (less
data points are computed) and is thus much faster than conventional
correlation on a linear scale such as `numpy.correlate <http://docs.scipy.org/doc/numpy/reference/generated/numpy.correlate.html>`__.
......
python-multipletau (0.3.3+ds-1) unstable; urgency=medium
* New upstream version 0.3.3+ds
-- Alexandre Mestiashvili <mestia@debian.org> Tue, 11 Dec 2018 09:47:01 +0000
python-multipletau (0.3.2+ds-1) unstable; urgency=medium
* New upstream version 0.3.2+ds
......
......@@ -29,6 +29,9 @@ Cross-correlation (NumPy)
-------------------------
.. autofunction:: correlate_numpy
Constants
---------
.. autodata:: multipletau.core.ZERO_CUTOFF
Examples
========
......
......@@ -4,7 +4,7 @@ u"""
Multipletau provides a multiple-τ algorithm for Python 2.7 and
Python 3.x with :py:mod:`numpy` as its sole dependency.
Multipe-τ correlation is computed on a logarithmic scale (less
Multiple-τ correlation is computed on a logarithmic scale (less
data points are computed) and is thus much faster than conventional
correlation on a linear scale such as :py:func:`numpy.correlate`.
......
......@@ -41,6 +41,11 @@ import warnings
__all__ = ["autocorrelate", "correlate", "correlate_numpy"]
#: Defines the cutoff when the absolute mean trace divided by the median
#: of the absolute value of the trace is treated as zero.
ZERO_CUTOFF = 1e-15
class DtypeWarning(UserWarning):
pass
......@@ -138,15 +143,18 @@ def autocorrelate(a, m=16, deltat=1, normalize=False, copy=True, dtype=None,
[ 4.00000000e+00, 2.03775000e+04],
[ 8.00000000e+00, 1.50612000e+04]])
"""
assert isinstance(copy, bool)
assert isinstance(normalize, bool)
msg = "'normalize' and 'ret_sum' must not both be true"
assert not (normalize and ret_sum), msg
if not isinstance(normalize, bool):
raise ValueError("`normalize` must be boolean!")
if not isinstance(copy, bool):
raise ValueError("`copy` must be boolean!")
if not isinstance(ret_sum, bool):
raise ValueError("`ret_sum` must be boolean!")
if normalize and ret_sum:
raise ValueError("'normalize' and 'ret_sum' must not both be True!")
compress_values = ["average", "first", "second"]
assert any(compress in s for s in compress_values), \
"Unvalid string of compress. Possible values are " + \
','.join(compress_values)
if compress not in compress_values:
raise ValueError("Invalid value for `compress`! Possible values "
"are '{}'.".format(','.join(compress_values)))
if dtype is None:
dtype = np.dtype(a[0].__class__)
......@@ -204,10 +212,12 @@ def autocorrelate(a, m=16, deltat=1, normalize=False, copy=True, dtype=None,
# We use the fluctuation of the signal around the mean
if normalize:
trace -= traceavg
assert traceavg != 0, "Cannot normalize: Average of `a` is zero!"
if np.abs(traceavg) / np.median(np.abs(trace)) < ZERO_CUTOFF:
raise ValueError("Cannot normalize: Average of `a` is zero!")
# Otherwise the following for-loop will fail:
assert N >= 2 * m, "len(a) must be larger than 2m!"
if N < 2 * m:
raise ValueError("`len(a)` must be >= `2m`!")
# Calculate autocorrelation function for first m+1 bins
# Discrete convolution of m elements
......@@ -382,22 +392,27 @@ def correlate(a, v, m=16, deltat=1, normalize=False, copy=True, dtype=None,
[ 8.00000000e+00, 1.58508000e+04]])
"""
assert isinstance(copy, bool)
assert isinstance(normalize, bool)
msg = "'normalize' and 'ret_sum' must not both be true"
assert not (normalize and ret_sum), msg
if not isinstance(normalize, bool):
raise ValueError("`normalize` must be boolean!")
if not isinstance(copy, bool):
raise ValueError("`copy` must be boolean!")
if not isinstance(ret_sum, bool):
raise ValueError("`ret_sum` must be boolean!")
if normalize and ret_sum:
raise ValueError("'normalize' and 'ret_sum' must not both be True!")
compress_values = ["average", "first", "second"]
assert any(compress in s for s in compress_values), \
"Unvalid string of compress. Possible values are " + \
','.join(compress_values)
if compress not in compress_values:
raise ValueError("Invalid value for `compress`! Possible values "
"are '{}'.".format(','.join(compress_values)))
# See `autocorrelation` for better documented code.
traceavg1 = np.average(v)
traceavg2 = np.average(a)
if normalize:
assert traceavg1 != 0, "Cannot normalize: Average of `v` is zero!"
assert traceavg2 != 0, "Cannot normalize: Average of `a` is zero!"
if np.abs(traceavg1) / np.median(np.abs(v)) < ZERO_CUTOFF:
raise ValueError("Cannot normalize: Average of `v` is zero!")
if np.abs(traceavg2) / np.median(np.abs(a)) < ZERO_CUTOFF:
raise ValueError("Cannot normalize: Average of `a` is zero!")
if dtype is None:
dtype = np.dtype(v[0].__class__)
......@@ -430,7 +445,8 @@ def correlate(a, v, m=16, deltat=1, normalize=False, copy=True, dtype=None,
trace2 = np.array(a, dtype=dtype, copy=copy)
assert trace1.shape[0] == trace2.shape[0], "`a`,`v` must have same length!"
if trace1.size != trace2.size:
raise ValueError("`a` and `v` must have same length!")
# Complex data
if dtype.kind == "c":
......@@ -467,7 +483,8 @@ def correlate(a, v, m=16, deltat=1, normalize=False, copy=True, dtype=None,
trace2 -= traceavg2
# Otherwise the following for-loop will fail:
assert N >= 2 * m, "len(a) must be larger than 2m!"
if N < 2 * m:
raise ValueError("`len(a)` must be >= `2m`!")
# Calculate autocorrelation function for first m+1 bins
for n in range(0, m + 1):
......@@ -571,7 +588,8 @@ def correlate_numpy(a, v, deltat=1, normalize=False,
ab = np.array(a, dtype=dtype, copy=copy)
vb = np.array(v, dtype=dtype, copy=copy)
assert ab.shape[0] == vb.shape[0], "`a`,`v` must have same length!"
if ab.size != vb.size:
raise ValueError("`a` and `v` must have same length!")
avg = np.average(ab)
vvg = np.average(vb)
......@@ -579,8 +597,10 @@ def correlate_numpy(a, v, deltat=1, normalize=False,
if normalize:
ab -= avg
vb -= vvg
assert avg != 0, "Cannot normalize: Average of `a` is zero!"
assert vvg != 0, "Cannot normalize: Average of `v` is zero!"
if np.abs(avg) / np.median(np.abs(ab)) < ZERO_CUTOFF:
raise ValueError("Cannot normalize: Average of `a` is zero!")
if np.abs(vvg) / np.median(np.abs(vb)) < ZERO_CUTOFF:
raise ValueError("Cannot normalize: Average of `v` is zero!")
Gd = np.correlate(ab, vb, mode="full")[len(ab) - 1:]
......
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Test correlation-autocorrelation identity"""
from __future__ import division, print_function
import numpy as np
import multipletau
from test_autocorrelate import get_sample_arrays
def test_ac():
arrs = get_sample_arrays()
try:
multipletau.autocorrelate(a=arrs[0],
copy=2)
except ValueError as e:
assert "`copy` must be boolean!" in e.args
else:
assert False
try:
multipletau.autocorrelate(a=arrs[0],
ret_sum=2)
except ValueError as e:
assert "`ret_sum` must be boolean!" in e.args
else:
assert False
try:
multipletau.autocorrelate(a=arrs[0],
normalize=2)
except ValueError as e:
assert "`normalize` must be boolean!" in e.args
else:
assert False
try:
multipletau.autocorrelate(a=arrs[0],
compress="peter")
except ValueError as e:
assert "Invalid value for `compress`!" in e.args[0]
else:
assert False
try:
multipletau.autocorrelate(a=arrs[0],
normalize=True,
ret_sum=True)
except ValueError as e:
assert "'normalize' and 'ret_sum' must not both be True!" in e.args
else:
assert False
def test_ac_trace0():
arrs = get_sample_arrays()
try:
multipletau.autocorrelate(a=arrs[0] - np.mean(arrs[0]),
normalize=True)
except ValueError as e:
assert "Cannot normalize: Average of `a` is zero!" in e.args
else:
assert False
def test_ac_tracesize():
arrs = get_sample_arrays()
try:
multipletau.autocorrelate(a=arrs[0][:31],
m=16)
except ValueError as e:
assert '`len(a)` must be >= `2m`!' in e.args
else:
assert False
def test_cc():
arrs = get_sample_arrays()
try:
multipletau.correlate(a=arrs[0], v=arrs[0],
copy=2)
except ValueError as e:
assert "`copy` must be boolean!" in e.args
else:
assert False
try:
multipletau.correlate(a=arrs[0], v=arrs[0],
ret_sum=2)
except ValueError as e:
assert "`ret_sum` must be boolean!" in e.args
else:
assert False
try:
multipletau.correlate(a=arrs[0], v=arrs[0],
normalize=2)
except ValueError as e:
assert "`normalize` must be boolean!" in e.args
else:
assert False
try:
multipletau.correlate(a=arrs[0], v=arrs[0],
compress="peter")
except ValueError as e:
assert "Invalid value for `compress`!" in e.args[0]
else:
assert False
try:
multipletau.correlate(a=arrs[0], v=arrs[0],
normalize=True,
ret_sum=True)
except ValueError as e:
assert "'normalize' and 'ret_sum' must not both be True!" in e.args
else:
assert False
def test_cc_trace0():
arrs = get_sample_arrays()
try:
multipletau.correlate(a=arrs[0] - np.mean(arrs[0]),
v=arrs[0],
normalize=True)
except ValueError as e:
assert "Cannot normalize: Average of `a` is zero!" in e.args
else:
assert False
try:
multipletau.correlate(a=arrs[0],
v=arrs[0] - np.mean(arrs[0]),
normalize=True)
except ValueError as e:
assert "Cannot normalize: Average of `v` is zero!" in e.args
else:
assert False
def test_cc_tracesize():
arrs = get_sample_arrays()
try:
multipletau.correlate(a=arrs[0][:31],
v=arrs[0][:31],
m=16)
except ValueError as e:
assert '`len(a)` must be >= `2m`!' in e.args
else:
assert False
def test_cc_samesize():
arrs = get_sample_arrays()
try:
multipletau.correlate(a=arrs[0],
v=arrs[1],
normalize=True)
except ValueError as e:
assert "`a` and `v` must have same length!" in e.args
else:
assert False
def test_numpy_cc_trace0():
arrs = get_sample_arrays()
try:
multipletau.correlate_numpy(a=arrs[0] - np.mean(arrs[0]),
v=arrs[0],
normalize=True)
except ValueError as e:
assert "Cannot normalize: Average of `a` is zero!" in e.args
else:
assert False
try:
multipletau.correlate_numpy(a=arrs[0],
v=arrs[0] - np.mean(arrs[0]),
normalize=True)
except ValueError as e:
assert "Cannot normalize: Average of `v` is zero!" in e.args
else:
assert False
def test_numpy_cc_samesize():
arrs = get_sample_arrays()
try:
multipletau.correlate_numpy(a=arrs[0],
v=arrs[1],
normalize=True)
except ValueError as e:
assert "`a` and `v` must have same length!" in e.args
else:
assert False
if __name__ == "__main__":
# Run all tests
loc = locals()
for key in list(loc.keys()):
if key.startswith("test_") and hasattr(loc[key], "__call__"):
loc[key]()