freealg 0.7.17__py3-none-any.whl → 0.7.18__py3-none-any.whl

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.
Files changed (52) hide show
  1. freealg/__init__.py +8 -6
  2. freealg/__version__.py +1 -1
  3. freealg/_algebraic_form/_branch_points.py +18 -18
  4. freealg/_algebraic_form/_continuation_algebraic.py +13 -13
  5. freealg/_algebraic_form/_cusp.py +15 -15
  6. freealg/_algebraic_form/_cusp_wrap.py +6 -6
  7. freealg/_algebraic_form/_decompress.py +16 -16
  8. freealg/_algebraic_form/_decompress4.py +31 -31
  9. freealg/_algebraic_form/_decompress5.py +23 -23
  10. freealg/_algebraic_form/_decompress6.py +13 -13
  11. freealg/_algebraic_form/_decompress7.py +15 -15
  12. freealg/_algebraic_form/_decompress8.py +17 -17
  13. freealg/_algebraic_form/_decompress9.py +18 -18
  14. freealg/_algebraic_form/_decompress_new.py +17 -17
  15. freealg/_algebraic_form/_decompress_new_2.py +57 -57
  16. freealg/_algebraic_form/_decompress_util.py +10 -10
  17. freealg/_algebraic_form/_decompressible.py +292 -0
  18. freealg/_algebraic_form/_edge.py +10 -10
  19. freealg/_algebraic_form/_homotopy4.py +9 -9
  20. freealg/_algebraic_form/_homotopy5.py +9 -9
  21. freealg/_algebraic_form/_support.py +19 -19
  22. freealg/_algebraic_form/algebraic_form.py +262 -468
  23. freealg/_base_form.py +401 -0
  24. freealg/_free_form/__init__.py +1 -4
  25. freealg/_free_form/_density_util.py +1 -1
  26. freealg/_free_form/_plot_util.py +3 -511
  27. freealg/_free_form/free_form.py +8 -367
  28. freealg/_util.py +59 -11
  29. freealg/distributions/__init__.py +2 -1
  30. freealg/distributions/_base_distribution.py +163 -0
  31. freealg/distributions/_chiral_block.py +137 -11
  32. freealg/distributions/_compound_poisson.py +141 -47
  33. freealg/distributions/_deformed_marchenko_pastur.py +138 -33
  34. freealg/distributions/_deformed_wigner.py +98 -9
  35. freealg/distributions/_fuss_catalan.py +269 -0
  36. freealg/distributions/_kesten_mckay.py +4 -130
  37. freealg/distributions/_marchenko_pastur.py +8 -196
  38. freealg/distributions/_meixner.py +4 -130
  39. freealg/distributions/_wachter.py +4 -130
  40. freealg/distributions/_wigner.py +10 -127
  41. freealg/visualization/__init__.py +2 -2
  42. freealg/visualization/{_rgb_hsv.py → _domain_coloring.py} +37 -29
  43. freealg/visualization/_plot_util.py +513 -0
  44. {freealg-0.7.17.dist-info → freealg-0.7.18.dist-info}/METADATA +1 -1
  45. freealg-0.7.18.dist-info/RECORD +74 -0
  46. freealg-0.7.17.dist-info/RECORD +0 -69
  47. /freealg/{_free_form/_sample.py → _sample.py} +0 -0
  48. /freealg/{_free_form/_support.py → _support.py} +0 -0
  49. {freealg-0.7.17.dist-info → freealg-0.7.18.dist-info}/WHEEL +0 -0
  50. {freealg-0.7.17.dist-info → freealg-0.7.18.dist-info}/licenses/AUTHORS.txt +0 -0
  51. {freealg-0.7.17.dist-info → freealg-0.7.18.dist-info}/licenses/LICENSE.txt +0 -0
  52. {freealg-0.7.17.dist-info → freealg-0.7.18.dist-info}/top_level.txt +0 -0
@@ -42,30 +42,30 @@ def _powers(x, deg):
42
42
  return xp
43
43
 
44
44
 
45
- def _poly_coef_in_y(zeta, a_coeffs):
45
+ def _poly_coef_in_y(zeta, coeffs):
46
46
  """
47
47
  For each zeta, compute coefficients a_j(zeta) so that
48
48
  P(zeta, y) = sum_{j=0}^s a_j(zeta) y^j
49
49
  """
50
50
  zeta = numpy.asarray(zeta, dtype=numpy.complex128).ravel()
51
- deg_z = int(a_coeffs.shape[0] - 1)
52
- s = int(a_coeffs.shape[1] - 1)
51
+ deg_z = int(coeffs.shape[0] - 1)
52
+ s = int(coeffs.shape[1] - 1)
53
53
 
54
54
  zp = _powers(zeta, deg_z)
55
55
  a = numpy.empty((zeta.size, s + 1), dtype=numpy.complex128)
56
56
  for j in range(s + 1):
57
- a[:, j] = zp @ a_coeffs[:, j]
57
+ a[:, j] = zp @ coeffs[:, j]
58
58
  return a
59
59
 
60
60
 
61
- def _poly_coef_in_y_dzeta(zeta, a_coeffs):
61
+ def _poly_coef_in_y_dzeta(zeta, coeffs):
62
62
  """
63
63
  For each zeta, compute coefficients da_j/dzeta(zeta) so that
64
64
  d/dzeta P(zeta, y) = sum_{j=0}^s (da_j/dzeta)(zeta) y^j
65
65
  """
66
66
  zeta = numpy.asarray(zeta, dtype=numpy.complex128).ravel()
67
- deg_z = int(a_coeffs.shape[0] - 1)
68
- s = int(a_coeffs.shape[1] - 1)
67
+ deg_z = int(coeffs.shape[0] - 1)
68
+ s = int(coeffs.shape[1] - 1)
69
69
 
70
70
  if deg_z <= 0:
71
71
  return numpy.zeros((zeta.size, s + 1), dtype=numpy.complex128)
@@ -74,7 +74,7 @@ def _poly_coef_in_y_dzeta(zeta, a_coeffs):
74
74
  zp = _powers(zeta, deg_z - 1) # up to zeta^(deg_z-1)
75
75
  da = numpy.empty((zeta.size, s + 1), dtype=numpy.complex128)
76
76
  for j in range(s + 1):
77
- col = a_coeffs[:, j]
77
+ col = coeffs[:, j]
78
78
  # sum_{i=1..deg_z} i*c_{i,j} zeta^(i-1)
79
79
  # build weighted coefficients for zp @ ...
80
80
  w = numpy.arange(deg_z + 1, dtype=numpy.complex128) * col
@@ -82,7 +82,7 @@ def _poly_coef_in_y_dzeta(zeta, a_coeffs):
82
82
  return da
83
83
 
84
84
 
85
- def _eval_P_and_partials(zeta, y, a_coeffs):
85
+ def _eval_P_and_partials(zeta, y, coeffs):
86
86
  """
87
87
  Evaluate P(zeta,y), P_zeta(zeta,y), P_y(zeta,y).
88
88
 
@@ -92,8 +92,8 @@ def _eval_P_and_partials(zeta, y, a_coeffs):
92
92
  zeta = numpy.asarray(zeta, dtype=numpy.complex128).ravel()
93
93
  y = numpy.asarray(y, dtype=numpy.complex128).ravel()
94
94
 
95
- a = _poly_coef_in_y(zeta, a_coeffs) # (n, s+1)
96
- da = _poly_coef_in_y_dzeta(zeta, a_coeffs) # (n, s+1)
95
+ a = _poly_coef_in_y(zeta, coeffs) # (n, s+1)
96
+ da = _poly_coef_in_y_dzeta(zeta, coeffs) # (n, s+1)
97
97
 
98
98
  s = int(a.shape[1] - 1)
99
99
  # powers of y up to s
@@ -120,7 +120,7 @@ def _eval_P_and_partials(zeta, y, a_coeffs):
120
120
  # 2x2 complex Newton step
121
121
  # =======================
122
122
 
123
- def _newton_2x2(z, tau, zeta0, y0, a_coeffs, max_iter, tol,
123
+ def _newton_2x2(z, tau, zeta0, y0, coeffs, max_iter, tol,
124
124
  armijo, min_lam, w_min, enforce_imag=True):
125
125
  """
126
126
  Solve for (zeta,y) at given (z,tau) using damped Newton on the 2x2 complex
@@ -136,7 +136,7 @@ def _newton_2x2(z, tau, zeta0, y0, a_coeffs, max_iter, tol,
136
136
  def F(zeta_, y_):
137
137
  P, Pz, Py = _eval_P_and_partials(numpy.array([zeta_]),
138
138
  numpy.array([y_]),
139
- a_coeffs)
139
+ coeffs)
140
140
  P = P[0]
141
141
  Pz = Pz[0]
142
142
  Py = Py[0]
@@ -211,7 +211,7 @@ def _newton_2x2(z, tau, zeta0, y0, a_coeffs, max_iter, tol,
211
211
  # Public entrypoint
212
212
  # =================
213
213
 
214
- def decompress_newton(z_query, t_all, a_coeffs, w0_list=None,
214
+ def decompress_newton(z_query, t_all, coeffs, w0_list=None,
215
215
  max_iter=50, tol=1e-12,
216
216
  armijo=1e-4, min_lam=1e-6, w_min=1e-14,
217
217
  sweep=True, verbose=False, **kwargs):
@@ -224,7 +224,7 @@ def decompress_newton(z_query, t_all, a_coeffs, w0_list=None,
224
224
  t_all : array_like (float)
225
225
  Time grid including t=0, increasing.
226
226
 
227
- a_coeffs : ndarray
227
+ coeffs : ndarray
228
228
  Coefficient matrix for P(z,m) in monomial basis (deg_z+1, s+1)
229
229
 
230
230
  w0_list : array_like (complex), optional
@@ -331,7 +331,7 @@ def decompress_newton(z_query, t_all, a_coeffs, w0_list=None,
331
331
 
332
332
  # Solve
333
333
  zeta, y, okj, _ = _newton_2x2(
334
- z, tau, zeta0, y0, a_coeffs,
334
+ z, tau, zeta0, y0, coeffs,
335
335
  max_iter=max_iter, tol=tol,
336
336
  armijo=armijo, min_lam=min_lam, w_min=w_min,
337
337
  enforce_imag=True
@@ -345,7 +345,7 @@ def decompress_newton(z_query, t_all, a_coeffs, w0_list=None,
345
345
  zeta0b = z + (tau - 1.0) / y_safe0b
346
346
 
347
347
  zeta, y, okj, _ = _newton_2x2(
348
- z, tau, zeta0b, y0b, a_coeffs,
348
+ z, tau, zeta0b, y0b, coeffs,
349
349
  max_iter=max_iter, tol=tol,
350
350
  armijo=armijo, min_lam=min_lam, w_min=w_min,
351
351
  enforce_imag=True
@@ -28,34 +28,34 @@ def _poly_powers(z, deg):
28
28
  return zp
29
29
 
30
30
 
31
- def _eval_P_dP(z, m, a_coeffs):
31
+ def _eval_P_dP(z, m, coeffs):
32
32
  """
33
- Evaluate P(z,m), dP/dz, dP/dm for polynomial coefficients a_coeffs.
33
+ Evaluate P(z,m), dP/dz, dP/dm for polynomial coefficients coeffs.
34
34
 
35
- a_coeffs has shape (deg_z+1, s+1), where
35
+ coeffs has shape (deg_z+1, s+1), where
36
36
  P(z,m) = sum_{j=0}^s a_j(z) m^j
37
- a_j(z) = sum_{i=0}^{deg_z} a_coeffs[i,j] z^i
37
+ a_j(z) = sum_{i=0}^{deg_z} coeffs[i,j] z^i
38
38
  """
39
39
  z = numpy.asarray(z, dtype=complex).ravel()
40
40
  m = numpy.asarray(m, dtype=complex).ravel()
41
41
 
42
- deg_z = int(a_coeffs.shape[0] - 1)
43
- s = int(a_coeffs.shape[1] - 1)
42
+ deg_z = int(coeffs.shape[0] - 1)
43
+ s = int(coeffs.shape[1] - 1)
44
44
 
45
45
  zp = _poly_powers(z, deg_z) # (n, deg_z+1)
46
46
  # a_j(z) for all j
47
- a = zp @ a_coeffs # (n, s+1)
47
+ a = zp @ coeffs # (n, s+1)
48
48
 
49
49
  # derivative a_j'(z)
50
50
  if deg_z >= 1:
51
51
  # coeffs multiplied by power index
52
52
  idx = numpy.arange(deg_z + 1, dtype=float)
53
- a_coeffs_dz = a_coeffs * idx[:, None]
53
+ coeffs_dz = coeffs * idx[:, None]
54
54
  # powers z^{i-1}: shift zp right
55
55
  zp_m1 = numpy.zeros_like(zp)
56
56
  zp_m1[:, 0] = 0.0
57
57
  zp_m1[:, 1:] = zp[:, :-1]
58
- a_dz = zp_m1 @ a_coeffs_dz # (n, s+1)
58
+ a_dz = zp_m1 @ coeffs_dz # (n, s+1)
59
59
  else:
60
60
  a_dz = numpy.zeros_like(a)
61
61
 
@@ -87,7 +87,7 @@ def _eval_P_dP(z, m, a_coeffs):
87
87
  # 2x2 complex Newton (correct)
88
88
  # ===========================
89
89
 
90
- def _newton_corrector(z_fixed, tau, a_coeffs, zeta0, y0,
90
+ def _newton_corrector(z_fixed, tau, coeffs, zeta0, y0,
91
91
  max_iter=50, tol=1e-12,
92
92
  armijo=1e-4, min_lam=1e-6):
93
93
  """
@@ -103,7 +103,7 @@ def _newton_corrector(z_fixed, tau, a_coeffs, zeta0, y0,
103
103
  eps_y = 0.0
104
104
 
105
105
  for it in range(int(max_iter)):
106
- P, Pz, Py = _eval_P_dP(numpy.array([zeta]), numpy.array([y]), a_coeffs)
106
+ P, Pz, Py = _eval_P_dP(numpy.array([zeta]), numpy.array([y]), coeffs)
107
107
  F1 = P[0]
108
108
  F2 = zeta - (tau - 1.0) / (y + eps_y) - z_fixed
109
109
 
@@ -139,7 +139,7 @@ def _newton_corrector(z_fixed, tau, a_coeffs, zeta0, y0,
139
139
  zeta_try = zeta + lam * dzeta
140
140
  y_try = y + lam * dy
141
141
 
142
- P_try, _, _ = _eval_P_dP(numpy.array([zeta_try]), numpy.array([y_try]), a_coeffs)
142
+ P_try, _, _ = _eval_P_dP(numpy.array([zeta_try]), numpy.array([y_try]), coeffs)
143
143
  F1_try = P_try[0]
144
144
  F2_try = zeta_try - (tau - 1.0) / (y_try + eps_y) - z_fixed
145
145
  norm_try = max(abs(F1_try), abs(F2_try))
@@ -163,7 +163,7 @@ def _newton_corrector(z_fixed, tau, a_coeffs, zeta0, y0,
163
163
  # predictor step (tangent ODE)
164
164
  # ===========================
165
165
 
166
- def _predictor_step(z_fixed, tau0, tau1, a_coeffs, zeta0, y0):
166
+ def _predictor_step(z_fixed, tau0, tau1, coeffs, zeta0, y0):
167
167
  """
168
168
  One explicit Euler predictor from tau0 to tau1 along the sheet.
169
169
 
@@ -175,7 +175,7 @@ def _predictor_step(z_fixed, tau0, tau1, a_coeffs, zeta0, y0):
175
175
  if dtau == 0.0:
176
176
  return zeta0, y0
177
177
 
178
- P, Pz, Py = _eval_P_dP(numpy.array([zeta0]), numpy.array([y0]), a_coeffs)
178
+ P, Pz, Py = _eval_P_dP(numpy.array([zeta0]), numpy.array([y0]), coeffs)
179
179
  Pz = Pz[0]
180
180
  Py = Py[0]
181
181
 
@@ -202,7 +202,7 @@ def _predictor_step(z_fixed, tau0, tau1, a_coeffs, zeta0, y0):
202
202
  # decompress newton
203
203
  # =================
204
204
 
205
- def decompress_newton(z_query, t, a_coeffs, w0_list=None,
205
+ def decompress_newton(z_query, t, coeffs, w0_list=None,
206
206
  max_iter=50, tol=1e-12,
207
207
  armijo=1e-4, min_lam=1e-6,
208
208
  w_min=1e-14,
@@ -219,7 +219,7 @@ def decompress_newton(z_query, t, a_coeffs, w0_list=None,
219
219
  Query points z = x + i*delta (typically slightly above real axis).
220
220
  t : array_like (n_t,)
221
221
  Time grid (must be sorted increasing; should include 0).
222
- a_coeffs : ndarray
222
+ coeffs : ndarray
223
223
  Polynomial coefficients of P(z,m)=0 as in AlgebraicForm.fit.
224
224
  w0_list : array_like (n_z,)
225
225
  Initial condition m(t=0, z_query) on the physical branch.
@@ -312,7 +312,7 @@ def decompress_newton(z_query, t, a_coeffs, w0_list=None,
312
312
 
313
313
  # Predictor from a_tau to b_tau
314
314
  zeta_pred, y_pred = _predictor_step(
315
- z_query[j], a_tau, b_tau, a_coeffs, a_zeta, a_y
315
+ z_query[j], a_tau, b_tau, coeffs, a_zeta, a_y
316
316
  )
317
317
 
318
318
  # Guard tiny y_pred
@@ -321,7 +321,7 @@ def decompress_newton(z_query, t, a_coeffs, w0_list=None,
321
321
 
322
322
  # Corrector at b_tau
323
323
  zeta_corr, y_corr, ok1, _ = _newton_corrector(
324
- z_fixed=z_query[j], tau=b_tau, a_coeffs=a_coeffs,
324
+ z_fixed=z_query[j], tau=b_tau, coeffs=coeffs,
325
325
  zeta0=zeta_pred, y0=y_pred,
326
326
  max_iter=max_iter, tol=tol, armijo=armijo, min_lam=min_lam
327
327
  )
@@ -54,19 +54,19 @@ def build_time_grid(sizes, n0, min_n_times=0):
54
54
  # eval P partials
55
55
  # ===============
56
56
 
57
- def eval_P_partials(z, m, a_coeffs):
57
+ def eval_P_partials(z, m, coeffs):
58
58
  """
59
59
  Evaluate P(z,m) and partials dP/dz, dP/dm.
60
60
 
61
- P is represented by a_coeffs in the monomial basis:
61
+ P is represented by coeffs in the monomial basis:
62
62
  P(z,m) = sum_{j=0..s} a_j(z) m^j
63
- a_j(z) = sum_{i=0..deg_z} a_coeffs[i,j] z^i
63
+ a_j(z) = sum_{i=0..deg_z} coeffs[i,j] z^i
64
64
  """
65
65
  z = numpy.asarray(z, dtype=complex)
66
66
  m = numpy.asarray(m, dtype=complex)
67
67
 
68
- deg_z = int(a_coeffs.shape[0] - 1)
69
- s = int(a_coeffs.shape[1] - 1)
68
+ deg_z = int(coeffs.shape[0] - 1)
69
+ s = int(coeffs.shape[1] - 1)
70
70
 
71
71
  # Scalar fast path
72
72
  if (z.ndim == 0) and (m.ndim == 0):
@@ -77,7 +77,7 @@ def eval_P_partials(z, m, a_coeffs):
77
77
  ap = numpy.empty(s + 1, dtype=complex)
78
78
 
79
79
  for j in range(s + 1):
80
- c = a_coeffs[:, j]
80
+ c = coeffs[:, j]
81
81
 
82
82
  val = 0.0 + 0.0j
83
83
  for i in range(deg_z, -1, -1):
@@ -119,10 +119,10 @@ def eval_P_partials(z, m, a_coeffs):
119
119
  Pm = numpy.zeros(zz.size, dtype=complex)
120
120
 
121
121
  for j in range(s + 1):
122
- aj = zp @ a_coeffs[:, j]
122
+ aj = zp @ coeffs[:, j]
123
123
  P += aj * mp[:, j]
124
124
 
125
- ajp = dzp @ a_coeffs[:, j]
125
+ ajp = dzp @ coeffs[:, j]
126
126
  Pz += ajp * mp[:, j]
127
127
 
128
128
  if j >= 1:
@@ -135,7 +135,7 @@ def eval_P_partials(z, m, a_coeffs):
135
135
  # Newton for one (z,t) pair
136
136
  # =========================
137
137
 
138
- def _newton_one(z, t, a_coeffs, w0, max_iter=50, tol=1e-12,
138
+ def _newton_one(z, t, coeffs, w0, max_iter=50, tol=1e-12,
139
139
  armijo=1e-4, min_lam=1e-6, w_min=1e-14):
140
140
  """
141
141
  Solve F_t(z,w)=0 at a single (t,z) by damped Newton.
@@ -155,7 +155,7 @@ def _newton_one(z, t, a_coeffs, w0, max_iter=50, tol=1e-12,
155
155
  return numpy.nan + 1j * numpy.nan, numpy.nan + 1j * numpy.nan
156
156
  zeta = z + beta / w_val
157
157
  y = tau * w_val
158
- P, Pz, Py = eval_P_partials(zeta, y, a_coeffs)
158
+ P, Pz, Py = eval_P_partials(zeta, y, coeffs)
159
159
  dF = (-beta / (w_val * w_val)) * Pz + tau * Py
160
160
  return P, dF
161
161
 
@@ -240,7 +240,7 @@ def _newton_one(z, t, a_coeffs, w0, max_iter=50, tol=1e-12,
240
240
  def decompress_newton(
241
241
  z_query,
242
242
  t_all,
243
- a_coeffs,
243
+ coeffs,
244
244
  w0_list=None,
245
245
  max_iter=50,
246
246
  tol=1e-12,
@@ -310,7 +310,7 @@ def decompress_newton(
310
310
 
311
311
  # Initial anchor solve at first time
312
312
  w_anchor_prev, ok_anchor_prev = _newton_one(
313
- z_anchor, float(t_all[0]), a_coeffs, -1.0 / z_anchor,
313
+ z_anchor, float(t_all[0]), coeffs, -1.0 / z_anchor,
314
314
  max_iter=max_iter, tol=homotopy_tol,
315
315
  armijo=armijo, min_lam=min_lam, w_min=w_min)
316
316
  if not ok_anchor_prev:
@@ -338,7 +338,7 @@ def decompress_newton(
338
338
  z_next = z_anchor + (z_target - z_anchor) * s_next
339
339
 
340
340
  w_next, ok_next = _newton_one(
341
- z_next, t, a_coeffs, w_curr,
341
+ z_next, t, coeffs, w_curr,
342
342
  max_iter=max_iter, tol=homotopy_tol,
343
343
  armijo=armijo, min_lam=min_lam, w_min=w_min)
344
344
 
@@ -369,7 +369,7 @@ def decompress_newton(
369
369
  if use_homotopy:
370
370
  # Continue anchor in time
371
371
  w_anchor, ok_anchor = _newton_one(
372
- z_anchor, t, a_coeffs, w_anchor_prev,
372
+ z_anchor, t, coeffs, w_anchor_prev,
373
373
  max_iter=max_iter, tol=homotopy_tol,
374
374
  armijo=armijo, min_lam=min_lam, w_min=w_min)
375
375
  if ok_anchor:
@@ -387,7 +387,7 @@ def decompress_newton(
387
387
 
388
388
  # Fallback: direct Newton from previous time
389
389
  w_d, ok_d = _newton_one(
390
- zq[j], t, a_coeffs, w_prev_time[j],
390
+ zq[j], t, coeffs, w_prev_time[j],
391
391
  max_iter=max_iter, tol=tol,
392
392
  armijo=armijo, min_lam=min_lam, w_min=w_min)
393
393
  if ok_d:
@@ -404,7 +404,7 @@ def decompress_newton(
404
404
  else:
405
405
  w0 = Wk[j - 1] if okk[j - 1] else w_prev_time[j]
406
406
  w_sol, ok_sol = _newton_one(
407
- zq[j], t, a_coeffs, w0,
407
+ zq[j], t, coeffs, w0,
408
408
  max_iter=max_iter, tol=tol,
409
409
  armijo=armijo, min_lam=min_lam, w_min=w_min)
410
410
  Wk[j] = w_sol
@@ -413,7 +413,7 @@ def decompress_newton(
413
413
  else:
414
414
  for j in range(n_z):
415
415
  w_sol, ok_sol = _newton_one(
416
- zq[j], t, a_coeffs, w_prev_time[j],
416
+ zq[j], t, coeffs, w_prev_time[j],
417
417
  max_iter=max_iter, tol=tol,
418
418
  armijo=armijo, min_lam=min_lam, w_min=w_min)
419
419
  Wk[j] = w_sol