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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: regdiff
3
- Version: 3.6.1
3
+ Version: 3.7
4
4
  Summary: Regularized differentiation of time-series as numpy ndarrays
5
5
  Requires-Dist: numpy>=2.5.4
6
6
  Requires-Dist: scipy>=1.18.1
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "regdiff"
3
- version = "3.6.1"
3
+ version = "3.7"
4
4
  description = "Regularized differentiation of time-series as numpy ndarrays"
5
5
  requires-python = ">=3.14"
6
6
  dependencies = [
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "regdiff"
3
- version = "3.6.1"
3
+ version = "3.7"
4
4
  description = "Regularized differentiation of time-series as numpy ndarrays"
5
5
  requires-python = ">=3.14"
6
6
  dependencies = [
@@ -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 or list of ndarrays
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, list):
125
- if len(u0) == n:
126
- u = np.asarray(u0, copy=True) * dx / data_st_dev
127
- elif len(u0) == 2 * n:
128
- u = np.asarray(u0[:n], copy=True) * dx / data_st_dev
129
- v = np.asarray(u0[n:], copy=True) * (dx**2) / data_st_dev
130
- elif len(u0) == 2 and len(u0[0]) == n and len(u0[1]) == n:
131
- u = np.asarray(u0[0], copy=True) * dx / data_st_dev
132
- v = np.asarray(u0[1], copy=True) * (dx**2) / data_st_dev
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 = np.asarray(u0[:, 0], copy=True) * dx / data_st_dev
139
- v = np.asarray(u0[:, 1], copy=True) * (dx**2) / data_st_dev
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
- data_comp = data[1:] - ofst_1
148
- a_tp_b = np.matvec(a_tp, data_comp)
149
- if diag:
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
- print(
168
- f"u, iteration {iter + 1}: cost: {cost_n}, relative change: {npl.norm(s) / npl.norm(u)}"
169
- )
170
- u_cost.append(cost_n)
171
- if iter >= min_iter and npl.norm(s) / npl.norm(u) < delta_norm_tol:
172
- if diag:
173
- print("u, delta norm tolerance reached")
174
- break
175
- if (
176
- prev_cost
177
- and iter >= min_iter
178
- and (prev_cost - cost_n) / prev_cost < delta_cost_tol
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("u, relative cost tolerance reached")
182
- break
183
- prev_cost = cost_n
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(finite_diff(v), ord=1)
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(finite_diff(v), 2) + ep))
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(finite_diff(v), ord=1)
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
- u = u * data_st_dev / dx
240
- return u, v
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