Skip to content

Commit

Permalink
Added SLSQP minimizer and fixed unittests (#34)
Browse files Browse the repository at this point in the history
* Added SLSQP minimizer and fixed unittests

* Added SLSQP minimizer to unittests

* increased speeds by 33% setting n_workers=1

* Cleaned up speed_test.ipynb

* PEP8

* bump version

Co-authored-by: Daniel Scott <info@synapseproduction.com>
Co-authored-by: Joshua Nielsen <Joshwani@users.noreply.github.com>
  • Loading branch information
3 people authored Oct 15, 2020
1 parent fc51d11 commit 05764bb
Show file tree
Hide file tree
Showing 4 changed files with 17 additions and 17 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ filter_conditions_config = [

# compute the confidence indicator
res = lppls_model.mp_compute_indicator(
workers=8,
workers=1,
window_size=120,
smallest_window_size=30,
increment=5,
Expand Down
6 changes: 4 additions & 2 deletions lppls/lppls.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,17 +210,19 @@ def mp_compute_indicator(self, workers, window_size=80, smallest_window_size=20,
obs_copy_len = len(obs_copy[0, :]) - window_size

func = self._func_compute_indicator

func_arg_map = [(
obs_copy[:, i:window_size + i], # obs
i, # n_iter
window_size, # window_size
smallest_window_size, # smallest_window_size
increment, # increment
max_searches, # max_searches
max_searches, # max_searches
filter_conditions_config,
) for i in range(obs_copy_len)]

pool = multiprocessing.Pool(processes=workers)

result = pool.map(func, func_arg_map)
pool.close()

Expand All @@ -240,7 +242,7 @@ def _func_compute_indicator(self, args):
obs_shrinking_slice = obs[:, j * increment:window_size + n_iter]

# fit the model to the data and get back the params
tc, m, w, a, b, c, c1, c2 = self.fit(obs_shrinking_slice, max_searches, minimizer='Nelder-Mead')
tc, m, w, a, b, c, c1, c2 = self.fit(obs_shrinking_slice, max_searches, minimizer='SLSQP')

first = obs_shrinking_slice[0][0]
last = obs_shrinking_slice[0][-1]
Expand Down
22 changes: 10 additions & 12 deletions lppls/tests/test_lppls.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@
def data():
return data_loader.sp500()


@pytest.fixture
def observations(data):
time_ = np.linspace(0, len(data) - 1, len(data))
price = [p for p in data['Adj Close']]
return np.array([time_, price])


@pytest.fixture
def lppls_model(observations):
"""Returns a model instance"""
Expand All @@ -40,7 +42,7 @@ def test_minimize(observations, lppls_model):
# Testing the minimizer is slow test but vital for confidence as dependencies are updated.
# Test that the minimizer is giving expected results
seed = [1346.2379633747132, 0.25299669770427197, 9.202480294316384]
tc, m, w, a, b, c, c1, c2 = lppls_model.minimize(observations, seed, "Nelder-Mead")
tc, m, w, a, b, c, c1, c2 = lppls_model.minimize(observations, seed, "SLSQP")

# Test that coefficients were successfully saved to object memory (self.coef_)
for coef in ["tc", "m", "w", "a", "b", "c", "c1", "c2"]:
Expand All @@ -49,12 +51,7 @@ def test_minimize(observations, lppls_model):
# Test that the minimizer function is raising an UnboundedError when solving the linear params fails.
with pytest.raises(np.linalg.LinAlgError):
seed = [np.nan, np.nan, np.nan]
lppls_model.minimize(observations, seed, "Nelder-Mead")

# # Test that numpy.linalg.LinAlgError is raised when non-linear minimization fails.
# with pytest.raises(np.linalg.LinAlgError):
# seed = [1.28337021e+03, 5.20824525e-01, 1.26182622e+01]
# lppls_model.minimize(observations, seed, "Nelder-Mead")
lppls_model.minimize(observations, seed, "SLSQP")


def test_fit(observations, lppls_model):
Expand All @@ -64,7 +61,7 @@ def test_fit(observations, lppls_model):
MAX_SEARCHES = 25

# fit the model to the data and get back the params
tc, m, w, a, b, c, c1, c2 = lppls_model.fit(observations, MAX_SEARCHES, minimizer='Nelder-Mead')
lppls_model.fit(observations, MAX_SEARCHES, minimizer='SLSQP')


def test__get_tc_bounds(observations, lppls_model):
Expand All @@ -76,15 +73,16 @@ def test__get_tc_bounds(observations, lppls_model):


def test_matrix_equation(observations, lppls_model):
# Test that the linear params are generated in an expected way.
# Test that the linear params are generated in an expected way (10-decimal precision)

# Case 1, expected values
tc, m, w = 1341.3258583124998, 0.28623183559375, 6.620224900062501
lin_vals = lppls_model.matrix_equation(observations, tc, m, w)
assert lin_vals == [4022.6602773956506, -285.82229531206656, -5.534444109995974, 10.151437800554937]
assert (np.round(lin_vals, 10) == np.round(
[4022.6602773956506, -285.82229531206656, -5.534444109995974, 10.151437800554937], 10)).all()

# Case 2, expected values
tc, m, w = 1344.1378622083332, 0.2704276238124999, 6.796222699041667
lin_vals = lppls_model.matrix_equation(observations, tc, m, w)
assert lin_vals == [4123.919805408301, -333.7726805698412, -12.107142946248267, -1.8589644488871784]

assert (np.round(lin_vals, 10) == np.round(
[4123.919805408301, -333.7726805698412, -12.107142946248267, -1.8589644488871784], 10)).all()
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
long_description = fh.read()

setuptools.setup(name='lppls',
version='0.4.3',
version='0.4.4',
description='A Python module for fitting the LPPLS model to data.',
packages=['lppls'],
author='Josh Nielsen',
Expand All @@ -16,4 +16,4 @@
zip_safe=False,
include_package_data=True,
package_data={'': ['data/*.csv']},
)
)

0 comments on commit 05764bb

Please sign in to comment.