regdiff 3.6.1__tar.gz → 3.7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .regdiff import matrix_anti_diff, matrix_diff, reg_diff # noqa: F401
|
|
@@ -4,16 +4,6 @@ import scipy as sp
|
|
|
4
4
|
|
|
5
5
|
# NOTE - all matrix/vector operations are called using np.matvel/np.subtract, etc. Only scalars should multiply ndarrays.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
def finite_diff(x):
|
|
9
|
-
"""take the finite difference of the input vector. Performs no validation.
|
|
10
|
-
:param np.ndarray(x): data to take the finite difference of -- 1-dimensional array of length n
|
|
11
|
-
|
|
12
|
-
:return: diff(x) -- 1 dimensional array of length n-1
|
|
13
|
-
"""
|
|
14
|
-
return np.subtract(x[1:], x[:-1])
|
|
15
|
-
|
|
16
|
-
|
|
17
7
|
def matrix_diff(n, dx=1.0):
|
|
18
8
|
"""return the matrix representations of the first-order central finite first difference, first-order central second
|
|
19
9
|
finite difference, and simple finite difference for a specified size and delta x increment.
|
|
@@ -80,6 +70,7 @@ def reg_diff(
|
|
|
80
70
|
delta_cost_tol=1e-6,
|
|
81
71
|
delta_norm_tol=1e-6,
|
|
82
72
|
ep=1e-8,
|
|
73
|
+
skip_first_deriv=False,
|
|
83
74
|
diag=False,
|
|
84
75
|
):
|
|
85
76
|
"""differentation function that takes a vector of position data and returns the first and second derivatives, evaluated using TV-regularized differentiation.
|
|
@@ -87,12 +78,13 @@ def reg_diff(
|
|
|
87
78
|
:param alpha: the regularization coefficient for the first derivative
|
|
88
79
|
:param alpha2: the regularization coeffiient for the second derivative. If left blank only the first derivative will be calculated.
|
|
89
80
|
:param dx: the time step for the data
|
|
90
|
-
:param u0: an initial guess for the derivative(s) as an ndarray
|
|
81
|
+
:param u0: an initial guess for the derivative(s) as an ndarray
|
|
91
82
|
:param min_iter: minimal number of iterations to calculate before returning. Default value 5.
|
|
92
83
|
:param max_iter: maximum number of iterations to calculate before returning. Default value is 1000000.
|
|
93
84
|
:param delta_cost_tol: relative delta cost to reach iteratively before returning (applies to both derivatives). Default value is 1e-6.
|
|
94
85
|
:param delta_norm_tol: relative delta norm of step to reach iteratively before returning (applies to both derivatives). Default value is 1e-6.
|
|
95
86
|
:param ep: epsilon to use to smooth the absolute value function. Devault value is 1e-8
|
|
87
|
+
:param skip_first_deriv: if True, use the value of u0 for the first derivative and do not calculate it
|
|
96
88
|
:param diag: if True, prints diagnostic information during execution. Default False.
|
|
97
89
|
|
|
98
90
|
:return: u -- the first derivative
|
|
@@ -120,23 +112,25 @@ def reg_diff(
|
|
|
120
112
|
# bunch of code for handling an input u0
|
|
121
113
|
u = None
|
|
122
114
|
v = None
|
|
115
|
+
if u0 is None and skip_first_deriv:
|
|
116
|
+
raise RuntimeError("If first derivative should be skipped, one should be provided")
|
|
123
117
|
if u0 is not None:
|
|
124
|
-
if isinstance(u0,
|
|
125
|
-
if
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
elif
|
|
131
|
-
u =
|
|
132
|
-
v =
|
|
133
|
-
elif isinstance(u0, np.ndarray):
|
|
134
|
-
if u0.shape[0] == 2 and u0.shape[1] == n:
|
|
135
|
-
u = np.asarray(u0[0, :], copy=True) * dx / data_st_dev
|
|
136
|
-
v = np.asarray(u0[1, :], copy=True) * (dx**2) / data_st_dev
|
|
118
|
+
if isinstance(u0, np.ndarray):
|
|
119
|
+
if u0.ndim == 1:
|
|
120
|
+
if len(u0) == n:
|
|
121
|
+
u = u0 * dx / data_st_dev
|
|
122
|
+
else:
|
|
123
|
+
raise ValueError("Expected a first-derivative u0 tensor that is the same size as the data tensor")
|
|
124
|
+
elif u0.shape[0] == 2 and u0.shape[1] == n:
|
|
125
|
+
u = u0[0] * dx / data_st_dev
|
|
126
|
+
v = u0[1] * (dx**2) / data_st_dev
|
|
137
127
|
elif u0.shape[1] == 2 and u0.shape[0] == n:
|
|
138
|
-
u =
|
|
139
|
-
v =
|
|
128
|
+
u = u0[:, 0] * dx / data_st_dev
|
|
129
|
+
v = u0[:, 1] * (dx**2) / data_st_dev
|
|
130
|
+
else:
|
|
131
|
+
raise ValueError("Bad u0 tensor size")
|
|
132
|
+
else:
|
|
133
|
+
raise ValueError("u0 should be an ndarray")
|
|
140
134
|
if not isinstance(u, np.ndarray):
|
|
141
135
|
u = np.matvec(diff, data)
|
|
142
136
|
if not isinstance(v, np.ndarray) and second_deriv:
|
|
@@ -144,43 +138,44 @@ def reg_diff(
|
|
|
144
138
|
|
|
145
139
|
# start calculating u
|
|
146
140
|
ofst_1 = data[0]
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
u_cost = [
|
|
151
|
-
npl.norm(np.subtract(sp.integrate.cumulative_trapezoid(u), data_comp))
|
|
152
|
-
+ alpha * npl.norm(finite_diff(u), ord=1)
|
|
153
|
-
]
|
|
154
|
-
prev_cost = None
|
|
155
|
-
for iter in range(max_iter):
|
|
156
|
-
c = np.reciprocal(np.sqrt(np.power(finite_diff(u), 2) + ep))
|
|
157
|
-
En = np.diag(c)
|
|
158
|
-
Ln = np.matmul(np.matmul(d_tp, En), d)
|
|
159
|
-
gn = np.add(np.subtract(np.matvec(a_tp_a, u), a_tp_b), alpha * np.matvec(Ln, u))
|
|
160
|
-
Hn = np.add(a_tp_a, alpha * Ln)
|
|
161
|
-
s = npl.solve(Hn, gn)
|
|
162
|
-
u = np.subtract(u, s)
|
|
163
|
-
cost_n = npl.norm(
|
|
164
|
-
np.subtract(sp.integrate.cumulative_trapezoid(u), data_comp)
|
|
165
|
-
) + alpha * npl.norm(finite_diff(u), ord=1)
|
|
141
|
+
if not skip_first_deriv:
|
|
142
|
+
data_comp = data[1:] - ofst_1
|
|
143
|
+
a_tp_b = np.matvec(a_tp, data_comp)
|
|
166
144
|
if diag:
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
145
|
+
u_cost = [
|
|
146
|
+
npl.norm(np.subtract(sp.integrate.cumulative_trapezoid(u), data_comp))
|
|
147
|
+
+ alpha * npl.norm(np.diff(u), ord=1)
|
|
148
|
+
]
|
|
149
|
+
prev_cost = None
|
|
150
|
+
for iter in range(max_iter):
|
|
151
|
+
c = np.reciprocal(np.sqrt(np.power(np.diff(u), 2) + ep))
|
|
152
|
+
En = np.diag(c)
|
|
153
|
+
Ln = np.matmul(np.matmul(d_tp, En), d)
|
|
154
|
+
gn = np.add(np.subtract(np.matvec(a_tp_a, u), a_tp_b), alpha * np.matvec(Ln, u))
|
|
155
|
+
Hn = np.add(a_tp_a, alpha * Ln)
|
|
156
|
+
s = npl.solve(Hn, gn)
|
|
157
|
+
u = np.subtract(u, s)
|
|
158
|
+
cost_n = npl.norm(
|
|
159
|
+
np.subtract(sp.integrate.cumulative_trapezoid(u), data_comp)
|
|
160
|
+
) + alpha * npl.norm(np.diff(u), ord=1)
|
|
180
161
|
if diag:
|
|
181
|
-
print(
|
|
182
|
-
|
|
183
|
-
|
|
162
|
+
print(
|
|
163
|
+
f"u, iteration {iter + 1}: cost: {cost_n}, relative change: {npl.norm(s) / npl.norm(u)}"
|
|
164
|
+
)
|
|
165
|
+
u_cost.append(cost_n)
|
|
166
|
+
if iter >= min_iter and npl.norm(s) / npl.norm(u) < delta_norm_tol:
|
|
167
|
+
if diag:
|
|
168
|
+
print("u, delta norm tolerance reached")
|
|
169
|
+
break
|
|
170
|
+
if (
|
|
171
|
+
prev_cost
|
|
172
|
+
and iter >= min_iter
|
|
173
|
+
and (prev_cost - cost_n) / prev_cost < delta_cost_tol
|
|
174
|
+
):
|
|
175
|
+
if diag:
|
|
176
|
+
print("u, relative cost tolerance reached")
|
|
177
|
+
break
|
|
178
|
+
prev_cost = cost_n
|
|
184
179
|
|
|
185
180
|
if second_deriv:
|
|
186
181
|
ofst_2 = u[0]
|
|
@@ -196,11 +191,11 @@ def reg_diff(
|
|
|
196
191
|
data_comp,
|
|
197
192
|
)
|
|
198
193
|
)
|
|
199
|
-
+ alpha2 * npl.norm(
|
|
194
|
+
+ alpha2 * npl.norm(np.diff(v), ord=1)
|
|
200
195
|
]
|
|
201
196
|
prev_cost = None
|
|
202
197
|
for iter in range(max_iter):
|
|
203
|
-
c = np.reciprocal(np.sqrt(np.power(
|
|
198
|
+
c = np.reciprocal(np.sqrt(np.power(np.diff(v), 2) + ep))
|
|
204
199
|
En = np.diag(c)
|
|
205
200
|
Ln = np.matmul(np.matmul(d_tp, En), d)
|
|
206
201
|
gn = np.add(
|
|
@@ -216,7 +211,7 @@ def reg_diff(
|
|
|
216
211
|
),
|
|
217
212
|
data_comp,
|
|
218
213
|
)
|
|
219
|
-
) + alpha2 * npl.norm(
|
|
214
|
+
) + alpha2 * npl.norm(np.diff(v), ord=1)
|
|
220
215
|
if diag:
|
|
221
216
|
print(
|
|
222
217
|
f"v, iteration {iter + 1}: cost: {cost_n}, relative change: {npl.norm(s) / npl.norm(v)}"
|
|
@@ -236,5 +231,10 @@ def reg_diff(
|
|
|
236
231
|
break
|
|
237
232
|
prev_cost = cost_n
|
|
238
233
|
v = v * data_st_dev / (dx**2)
|
|
239
|
-
|
|
240
|
-
|
|
234
|
+
returns = []
|
|
235
|
+
if not skip_first_deriv:
|
|
236
|
+
u = u * data_st_dev / dx
|
|
237
|
+
returns.append(u)
|
|
238
|
+
if second_deriv:
|
|
239
|
+
returns.append(v)
|
|
240
|
+
return (*returns,)
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
from .regdiff import finite_diff, matrix_anti_diff, matrix_diff, reg_diff # noqa: F401
|