Skip to content

Commit 2394676

Browse files
committed
better optimization and comments
1 parent e92abc0 commit 2394676

3 files changed

Lines changed: 11 additions & 5 deletions

File tree

pynumdiff/optimize/_optimize.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from hashlib import sha1
99
from tqdm import tqdm
1010

11-
from ..utils import evaluate
11+
from ..utils import evaluate, utility
1212
from ..finite_difference import finitediff, first_order, second_order, fourth_order
1313
from ..smooth_finite_difference import kerneldiff, mediandiff, meandiff, gaussiandiff, friedrichsdiff, butterdiff
1414
from ..polynomial_fit import polydiff, savgoldiff, splinediff
@@ -157,8 +157,12 @@ def _objective_function(point, func, x, dt, singleton_params, categorical_params
157157
elif metric == 'error_correlation':
158158
ec = evaluate.error_correlation(dxdt_truth, dxdt_hat, padding=padding)
159159
cache[key] = ec; return ec
160-
else: # then minimize (RMSE(x_hat - x) || sqrt{2*Mean(Huber((x_hat- x)/sigma, M))}*sigma) + gamma*TV(dxdt_hat)
161-
# rubust_rme(,inf) = rmse(), so just use the simpler function in that case
160+
else: # then minimize L(Phi) = (RMSE(trapz(dxdt_hat) + c - x) || sqrt{2*Mean(Huber((trapz(dxdt_hat) + c - x)/sigma, M))}*sigma) + gamma*TV(dxdt_hat)
161+
# It seems like we should be able to use x_hat rather than the trapz integral of dxdt_hat + constant, but the latter is more reliable,
162+
# because it accounts for the accuracy of the derivative directly, not through the generating algorithm's smooth signal estimate.
163+
rec_x_hat = utility.integrate_dxdt_hat(dxdt_hat, dt)
164+
rec_x_hat += utility.estimate_integration_constant(x, rec_x_hat, M=huberM)
165+
# rubust_rme(,M=inf) = rmse(), so just use the simpler function if M=inf
162166
cost = evaluate.rmse(x, x_hat, padding=padding) if huberM == float('inf') else evaluate.robust_rme(x, x_hat, padding=padding, M=huberM)
163167
cost += tvgamma*evaluate.total_variation(dxdt_hat, padding=padding)
164168
cache[key] = cost; return cost

pynumdiff/tests/test_optimize.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ def test_targeting_rmse_vs_tvgamma_loss():
3232
x_hat, dxdt_hat = splinediff(x, dt, **params_loss)
3333
loss_rmse = rmse(dxdt_truth, dxdt_hat)
3434

35-
assert val_rmse < loss_rmse < 1.1*val_rmse # This exact bound might break if using a different diff method or data series, but the point is they should be close
35+
assert val_rmse <= loss_rmse < 1.1*val_rmse # This exact bound might break if using a different diff method or data series, but the point is they should be close
3636

3737

3838
def test_search_space_updates_applied():

pynumdiff/utils/utility.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,9 @@ def integrate_dxdt_hat(dxdt_hat, _t):
117117

118118
def estimate_integration_constant(x, x_hat, M=6):
119119
"""Integration leaves an unknown integration constant. This function finds a best fit integration
120-
constant given x and x_hat (the integral of dxdt_hat) by optimizing :math:`\\min_c ||x - \\hat{x} + c||_2`.
120+
constant to correct the DC of :code:`x_hat` (the integral of dxdt_hat) by optimizing
121+
:math:`\\min_c J(x - \\hat{x} + c)`, where :math:`J` is the Huber loss function or the :math:`\\ell_1`
122+
or :math:`\\ell_2` norm.
121123
122124
:param np.array[float] x: timeseries of measurements
123125
:param np.array[float] x_hat: smoothed estimate of x

0 commit comments

Comments
 (0)