executable-engineering 0.1.32__py3-none-any.whl → 0.1.34__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.
@@ -5,10 +5,15 @@ from .closedoptimization_module import OptimizerClosed
5
5
  from .openoptimization_module import OptimizerOpen
6
6
  from .gradientoptimization_module import OptimizerGrad
7
7
  from .numerical_error_module import python_internal_binary, decimal_to_binary
8
- from .linearsystems_module import visual_solve_2d
8
+ from .linearsystems_module import visual_solve_2d, visualize_conditioning, visualize_matrix_norms, jacobi_step, gauss_seidel_step, sor_step, visualize_convergence_2d, create_diagonally_dominant_matrix, iter_solve, steepest_descent, conjugate_gradient, IterationTracker
9
9
 
10
10
  __all__ = [
11
11
  "visual_solve_2d",
12
+ "visualize_conditioning",
13
+ "visualize_matrix_norms",
14
+ "jacobi_step",
15
+ "gauss_seidel_step",
16
+ "sor_step, visualize_convergence_2d, create_diagonally_dominant_matrix, iter_solve, steepest_descent, conjugate_gradient, IterationTracker",
12
17
  "init_weights",
13
18
  "tanh",
14
19
  "tanh_derivative",
@@ -1,76 +1,82 @@
1
1
  import numpy as np
2
2
  import plotly.graph_objects as go
3
+ from plotly.subplots import make_subplots
3
4
  import plotly.colors as pcolors
4
5
 
5
- def visual_solve_2d(A, b, x_range=None, title="Linear System", labels=None):
6
+ def visual_solve_2d(A, b, method='exact'):
6
7
  """
7
8
  Solves and visualizes a 2D linear system Ax = b.
8
9
  Plots the lines represented by the rows of A and b, and the solution point.
9
- Falls back to the pseudoinverse for singular or non-square systems.
10
10
 
11
11
  Args:
12
12
  A: (N, 2) array-like of coefficients.
13
13
  b: (N,) array-like of constants.
14
- x_range: Tuple of (xmin, xmax) for plotting. If None, auto-calculated.
15
- title: Plot title.
16
- labels: Tuple of (x_label, y_label) for axes.
14
+ method: 'exact' (uses np.linalg.solve) or 'pseudo' (uses np.linalg.pinv).
17
15
  """
18
- if labels is None:
19
- labels = ("x", "y")
20
-
21
16
  A = np.array(A, dtype=float)
22
17
  b = np.array(b, dtype=float).flatten()
23
18
 
24
19
  if A.shape[1] != 2:
25
20
  raise ValueError("visual_solve_2d only supports 2D systems (A must have 2 columns).")
26
21
 
27
- # 1. Solve the system using the pseudoinverse
28
- # For a square, full-rank matrix, pinv is mathematically identical to the standard inverse.
29
- # For singular or non-square matrices, it finds the least-squares/minimum-norm solution.
30
- sol = np.linalg.pinv(A) @ b
22
+ # 1. Solve the system based on chosen method
23
+ sol = None
24
+ plot_star = False
31
25
 
32
- # Check if the solution is exact AND unique.
33
- # It is exact if A*x = b. It is unique if the rank of A equals the number of variables (columns).
34
- is_exact = np.allclose(A @ sol, b)
35
- is_unique = np.linalg.matrix_rank(A) == A.shape[1]
36
- is_exact_unique = is_exact and is_unique
26
+ if method == 'exact':
27
+ try:
28
+ if A.shape[0] == A.shape[1]:
29
+ sol = np.linalg.solve(A, b)
30
+ if np.allclose(A @ sol, b):
31
+ plot_star = True
32
+ sol_label = "Exact Solution"
33
+ except np.linalg.LinAlgError:
34
+ pass # No exact unique solution
35
+
36
+ elif method == 'pseudo':
37
+ sol = np.linalg.pinv(A) @ b
38
+ plot_star = True
39
+
40
+ if np.allclose(A @ sol, b):
41
+ sol_label = "Exact Solution (via Pseudoinverse)"
42
+ else:
43
+ sol_label = "Best Fit Solution"
44
+ else:
45
+ raise ValueError("method must be 'exact' or 'pseudo'")
37
46
 
38
47
  # 2. Determine plotting range
39
- if x_range is None:
48
+ if sol is not None:
40
49
  center_x = sol[0]
41
- x_range = (center_x - 10, center_x + 10)
50
+ center_y = sol[1]
51
+ else:
52
+ # Fallback if no solution is found
53
+ center_x = 10
54
+ center_y = 10
42
55
 
56
+ x_margin = 10
57
+ x_range = (center_x - x_margin, center_x + x_margin)
43
58
  x_vals = np.linspace(x_range[0], x_range[1], 100)
44
59
 
45
60
  fig = go.Figure()
46
-
47
61
  colors = pcolors.qualitative.Plotly
48
62
 
49
63
  # 3. Plot each line
50
64
  for i in range(A.shape[0]):
51
65
  a1, a2 = A[i]
52
66
  bi = b[i]
67
+ line_name = f"Row {i+1}"
53
68
 
54
69
  if np.abs(a2) > 1e-10:
55
- # y = (bi - a1*x) / a2
56
70
  y_vals = (bi - a1 * x_vals) / a2
57
- line_name = f"{a1:g}{labels[0]} + {a2:g}{labels[1]} = {bi:g}"
58
71
  fig.add_trace(go.Scatter(x=x_vals, y=y_vals, mode='lines', name=line_name, line=dict(color=colors[i % len(colors)])))
59
72
  else:
60
- # Vertical line: x = bi / a1
61
73
  if np.abs(a1) > 1e-10:
62
74
  x_val = bi / a1
63
- line_name = f"{a1:g}{labels[0]} = {bi:g}"
64
- fig.add_trace(go.Scatter(x=[x_val, x_val], y=[-100, 100], mode='lines', name=line_name, line=dict(color=colors[i % len(colors)])))
75
+ fig.add_trace(go.Scatter(x=[x_val, x_val], y=[center_y - 100, center_y + 100], mode='lines', name=line_name, line=dict(color=colors[i % len(colors)])))
65
76
 
66
- # 4. Plot solution point
67
- if is_unique:
68
- if is_exact:
69
- sol_label = "Exact Solution"
70
- else:
71
- sol_label = "Best Fit Solution"
72
-
73
- hover_text = f"{labels[0]}={sol[0]:.4g}, {labels[1]}={sol[1]:.4g}"
77
+ # 4. Plot solution point if required
78
+ if plot_star and sol is not None:
79
+ hover_text = f"x={sol[0]:.4g}, y={sol[1]:.4g}"
74
80
  fig.add_trace(go.Scatter(
75
81
  x=[sol[0]],
76
82
  y=[sol[1]],
@@ -81,15 +87,356 @@ def visual_solve_2d(A, b, x_range=None, title="Linear System", labels=None):
81
87
  hovertext=hover_text
82
88
  ))
83
89
 
84
- # Auto-adjust y-range nicely around the solution if not a vertical-only mess
90
+ # 5. Auto-adjust y-range nicely around the center
85
91
  y_margin = (x_range[1] - x_range[0]) / 2.0
92
+ yaxis_dict = dict(range=[center_y - y_margin, center_y + y_margin], scaleanchor="x", scaleratio=1)
93
+
94
+ fig.update_layout(
95
+ xaxis=dict(range=[x_range[0], x_range[1]]),
96
+ yaxis=yaxis_dict,
97
+ width=700,
98
+ height=500,
99
+ margin=dict(l=20, r=20, t=50, b=20)
100
+ )
101
+
102
+ return fig
103
+
104
+
105
+ def visualize_conditioning(A):
106
+ """
107
+ Visualizes the effect of the condition number by applying the matrix transformation
108
+ and its inverse to the unit circle.
109
+
110
+ Args:
111
+ A: (2, 2) array-like matrix
112
+ """
113
+ A = np.array(A, dtype=float)
114
+ if A.shape != (2, 2):
115
+ raise ValueError("visualize_conditioning requires a 2x2 matrix.")
116
+
117
+ # Create the unit circle
118
+ theta = np.linspace(0, 2*np.pi, 200)
119
+ circle = np.array([np.cos(theta), np.sin(theta)])
120
+
121
+ # Apply transformation A to the unit circle
122
+ transformed_A = A @ circle
123
+
124
+ # Check if invertible, if so, apply A^-1 to the unit circle
125
+ try:
126
+ A_inv = np.linalg.inv(A)
127
+ transformed_Ainv = A_inv @ circle
128
+ cond = np.linalg.cond(A)
129
+ subtitle = f"Condition Number: {cond:.2f}"
130
+ except np.linalg.LinAlgError:
131
+ transformed_Ainv = np.zeros_like(circle)
132
+ subtitle = "Matrix is singular (Condition Number: ∞)"
133
+
134
+ fig = make_subplots(
135
+ rows=1, cols=2,
136
+ subplot_titles=(f"Forward Transformation (A*x)", f"Inverse Transformation (A⁻¹*b)"),
137
+ horizontal_spacing=0.1
138
+ )
139
+
140
+ # Subplot 1: Forward transformation
141
+ fig.add_trace(go.Scatter(x=circle[0], y=circle[1], mode='lines', name='Unit Circle', line=dict(color='gray', dash='dash')), row=1, col=1)
142
+ fig.add_trace(go.Scatter(x=transformed_A[0], y=transformed_A[1], mode='lines', name='A * Circle', line=dict(color='blue')), row=1, col=1)
143
+
144
+ # Subplot 2: Inverse transformation
145
+ fig.add_trace(go.Scatter(x=circle[0], y=circle[1], mode='lines', name='Unit Circle', line=dict(color='gray', dash='dash'), showlegend=False), row=1, col=2)
146
+ fig.add_trace(go.Scatter(x=transformed_Ainv[0], y=transformed_Ainv[1], mode='lines', name='A⁻¹ * Circle', line=dict(color='red')), row=1, col=2)
147
+
148
+ # Update axes to be equal aspect ratio
149
+ max_A = np.max(np.abs(transformed_A)) * 1.1 if np.max(np.abs(transformed_A)) > 0 else 1
150
+ max_Ainv = np.max(np.abs(transformed_Ainv)) * 1.1 if np.max(np.abs(transformed_Ainv)) > 0 else 1
151
+
152
+ # Ensure they are at least 1.1 so the unit circle is visible
153
+ max_A = max(max_A, 1.1)
154
+ max_Ainv = max(max_Ainv, 1.1)
155
+
156
+ fig.update_xaxes(range=[-max_A, max_A], row=1, col=1)
157
+ fig.update_yaxes(range=[-max_A, max_A], scaleanchor="x", scaleratio=1, row=1, col=1)
158
+
159
+ fig.update_xaxes(range=[-max_Ainv, max_Ainv], row=1, col=2)
160
+ fig.update_yaxes(range=[-max_Ainv, max_Ainv], scaleanchor="x2", scaleratio=1, row=1, col=2)
86
161
 
87
162
  fig.update_layout(
88
- title=title,
89
- xaxis_title=labels[0],
90
- yaxis_title=labels[1],
91
- yaxis=dict(range=[sol[1] - y_margin, sol[1] + y_margin]),
92
- template="plotly_white"
163
+ title=f"Visualizing Matrix Distortion ({subtitle})",
164
+ width=900,
165
+ height=500,
166
+ margin=dict(l=20, r=20, t=60, b=20)
93
167
  )
94
168
 
95
169
  return fig
170
+
171
+
172
+ def visualize_matrix_norms(A):
173
+ """
174
+ Visualizes matrix norms by plotting the transformation of a unit circle
175
+ and overlaying bounding circles based on different matrix norms.
176
+
177
+ Args:
178
+ A: (2, 2) array-like matrix
179
+ """
180
+ import numpy as np
181
+ import plotly.graph_objects as go
182
+
183
+ A = np.array(A, dtype=float)
184
+ if A.shape != (2, 2):
185
+ raise ValueError("visualize_matrix_norms requires a 2x2 matrix.")
186
+
187
+ # 1. Calculate the norms
188
+ norm_2 = np.linalg.norm(A, ord=2)
189
+ norm_F = np.linalg.norm(A, ord='fro')
190
+ norm_inf = np.linalg.norm(A, ord=np.inf)
191
+
192
+ # 2. Transform the unit circle
193
+ theta = np.linspace(0, 2*np.pi, 200)
194
+ circle = np.array([np.cos(theta), np.sin(theta)])
195
+ ellipse = A @ circle
196
+
197
+ # 3. Create circles for the norms
198
+ circle_2 = norm_2 * circle
199
+ circle_F = norm_F * circle
200
+ circle_inf = norm_inf * circle
201
+
202
+ # 4. Plot!
203
+ fig = go.Figure()
204
+
205
+ # Plot the transformed ellipse
206
+ fig.add_trace(go.Scatter(x=ellipse[0], y=ellipse[1], mode='lines', name='A * Unit Circle (Ellipse)', line=dict(color='blue', width=3)))
207
+
208
+ # Plot the norm bounding circles
209
+ fig.add_trace(go.Scatter(x=circle_2[0], y=circle_2[1], mode='lines', name=f'2-Norm (Radius {norm_2:.2f})', line=dict(color='green', dash='dash')))
210
+ fig.add_trace(go.Scatter(x=circle_F[0], y=circle_F[1], mode='lines', name=f'Frobenius Norm (Radius {norm_F:.2f})', line=dict(color='orange', dash='dash')))
211
+ fig.add_trace(go.Scatter(x=circle_inf[0], y=circle_inf[1], mode='lines', name=f'Infinity Norm (Radius {norm_inf:.2f})', line=dict(color='red', dash='dash')))
212
+
213
+ # Setup axes
214
+ max_val = norm_inf * 1.1
215
+ fig.update_xaxes(range=[-max_val, max_val])
216
+ fig.update_yaxes(range=[-max_val, max_val], scaleanchor="x", scaleratio=1)
217
+ fig.update_layout(title="Matrix Norms as Bounds on Geometric Distortion", width=700, height=700)
218
+
219
+ return fig
220
+
221
+ def jacobi_step(A, b, x):
222
+ """Performs a single Jacobi iteration step."""
223
+ n = len(x)
224
+ x_new = np.zeros_like(x)
225
+ for i in range(n):
226
+ x_new[i] = (b[i] - np.dot(A[i, :i], x[:i]) - np.dot(A[i, i + 1:], x[i + 1:])) / A[i, i]
227
+ return x_new
228
+
229
+ def gauss_seidel_step(A, b, x, omega = 1):
230
+ """Performs a single Gauss-Seidel iteration step."""
231
+ n = len(x)
232
+ for i in range(n):
233
+ x[i] = (b[i] - np.dot(A[i, :i], x[:i]) - np.dot(A[i, i + 1:], x[i + 1:])) / A[i, i]
234
+ return x
235
+
236
+ def sor_step(A, b, x, omega=1.05):
237
+ """Performs a single SOR iteration step."""
238
+ n = len(x)
239
+ for i in range(n):
240
+ x[i] = (1 - omega) * x[i] + (omega / A[i, i]) * (b[i] - np.dot(A[i, :i], x[:i]) - np.dot(A[i, i + 1:], x[i + 1:]))
241
+ return x
242
+
243
+ def visualize_convergence_2d(A, b, iterations, surface_type='residual'):
244
+ """
245
+ Visualizes the convergence path of an iterative solver over a 2D contour surface.
246
+
247
+ Args:
248
+ A: (2, 2) coefficient matrix.
249
+ b: (2,) right-hand side vector.
250
+ iterations: List or array of (2,) vectors representing the guess at each step.
251
+ surface_type: 'residual' plots ||Ax - b||. 'quadratic' plots 0.5 x^T A x - b^T x.
252
+ """
253
+ import numpy as np
254
+ import plotly.graph_objects as go
255
+
256
+ A = np.array(A, dtype=float)
257
+ b = np.array(b, dtype=float).flatten()
258
+ iterations = np.array(iterations)
259
+
260
+ if A.shape != (2, 2):
261
+ raise ValueError("visualize_convergence_2d only supports 2D systems.")
262
+
263
+ try:
264
+ x_true = np.linalg.solve(A, b)
265
+ except np.linalg.LinAlgError:
266
+ x_true = np.zeros(2)
267
+
268
+ # Determine bounds
269
+ all_points = np.vstack([iterations, x_true])
270
+ min_x, max_x = np.min(all_points[:, 0]), np.max(all_points[:, 0])
271
+ min_y, max_y = np.min(all_points[:, 1]), np.max(all_points[:, 1])
272
+
273
+ # Add padding
274
+ pad_x = max((max_x - min_x) * 0.3, 0.5)
275
+ pad_y = max((max_y - min_y) * 0.3, 0.5)
276
+
277
+ x_range = np.linspace(min_x - pad_x, max_x + pad_x, 100)
278
+ y_range = np.linspace(min_y - pad_y, max_y + pad_y, 100)
279
+ X, Y = np.meshgrid(x_range, y_range)
280
+
281
+ if surface_type == 'residual':
282
+ # ||Ax - b||
283
+ Z = np.sqrt((A[0,0]*X + A[0,1]*Y - b[0])**2 + (A[1,0]*X + A[1,1]*Y - b[1])**2)
284
+ title = "Convergence Path over Residual Surface ||Ax - b||"
285
+ elif surface_type == 'quadratic':
286
+ # 0.5 x^T A x - b^T x
287
+ Z = 0.5 * (A[0,0]*X**2 + (A[0,1] + A[1,0])*X*Y + A[1,1]*Y**2) - (b[0]*X + b[1]*Y)
288
+ title = "Convergence Path over Quadratic Surface f(x)"
289
+ else:
290
+ raise ValueError("surface_type must be 'residual' or 'quadratic'")
291
+
292
+ fig = go.Figure()
293
+
294
+ # Contour plot
295
+ fig.add_trace(go.Contour(
296
+ x=x_range, y=y_range, z=Z,
297
+ colorscale='Viridis',
298
+ contours=dict(showlabels=True, labelfont=dict(size=12, color='white')),
299
+ showscale=False,
300
+ opacity=0.7
301
+ ))
302
+
303
+ # Convergence path
304
+ import numpy as np
305
+ import plotly.express as px
306
+
307
+ # We want to draw each segment with a color from the colormap
308
+ if len(iterations) > 1:
309
+ colors = px.colors.sample_colorscale('magma', np.linspace(0, 1, len(iterations)-1))
310
+ for i in range(len(iterations)-1):
311
+ fig.add_trace(go.Scatter(
312
+ x=iterations[i:i+2, 0], y=iterations[i:i+2, 1],
313
+ mode='lines',
314
+ line=dict(color=colors[i], width=3),
315
+ showlegend=False
316
+ ))
317
+
318
+ # Add a dummy trace just to show the colorbar
319
+ fig.add_trace(go.Scatter(
320
+ x=[None], y=[None],
321
+ mode='markers',
322
+ marker=dict(
323
+ size=0,
324
+ color=[0, len(iterations)-1],
325
+ colorscale='magma',
326
+ showscale=True,
327
+ colorbar=dict(title="Iteration", len=0.5, y=0.5, x=1.1)
328
+ ),
329
+ showlegend=False
330
+ ))
331
+ else:
332
+ # Just in case there is no path
333
+ fig.add_trace(go.Scatter(
334
+ x=iterations[:, 0], y=iterations[:, 1],
335
+ mode='markers',
336
+ marker=dict(size=8, color='white'),
337
+ name='Iterations'
338
+ ))
339
+
340
+
341
+
342
+ fig.update_layout(
343
+ title=title,
344
+ width=700, height=600,
345
+ xaxis_title="x₁",
346
+ yaxis_title="x₂",
347
+ yaxis=dict(scaleanchor="x", scaleratio=1),
348
+ margin=dict(l=20, r=20, t=50, b=20)
349
+ )
350
+ return fig
351
+
352
+ def create_diagonally_dominant_matrix(n):
353
+ """Creates a diagonally dominant random matrix.
354
+
355
+ Args:
356
+ n: The size of the matrix.
357
+
358
+ Returns:
359
+ A diagonally dominant random matrix.
360
+ """
361
+ import numpy as np
362
+ A = np.random.rand(n, n)
363
+ for i in range(n):
364
+ A[i, i] = np.sum(np.abs(A[i, :])) + np.random.rand()
365
+ return A
366
+
367
+ def iter_solve(A, b, method, tol=1e-6, track_history=False):
368
+ """
369
+ General wrapper function that repeatedly applies an iterative step
370
+ until the residual error falls below a tolerance.
371
+ """
372
+ import numpy as np
373
+ x = np.zeros(len(b))
374
+ max_iter = 1000
375
+
376
+ if track_history:
377
+ iterations = [x.copy()]
378
+
379
+ for i in range(max_iter):
380
+ x_new = method(A, b, x.copy())
381
+ if track_history:
382
+ iterations.append(x_new.copy())
383
+
384
+ if np.linalg.norm(A @ x_new - b) < tol:
385
+ print(f'Converged after {i+1} iterations.')
386
+ break
387
+ x = x_new.copy()
388
+
389
+ if track_history:
390
+ return x, iterations
391
+ return x
392
+
393
+ def steepest_descent(A, b, x0, tol=1e-6, max_iter=100, track_history=False):
394
+ """Solves a linear system Ax = b using the method of steepest descent."""
395
+ import numpy as np
396
+ x = x0.copy()
397
+ if track_history:
398
+ iterations = [x.copy()]
399
+
400
+ for i in range(max_iter):
401
+ r = A @ x - b
402
+ if np.linalg.norm(r) < tol:
403
+ if track_history: print(f'Converged after {i+1} iterations.')
404
+ break
405
+ alpha = np.dot(r, r) / np.dot(r, A @ r)
406
+ x = x - alpha * r
407
+ if track_history:
408
+ iterations.append(x.copy())
409
+
410
+ if track_history:
411
+ return x, iterations
412
+ return x
413
+
414
+ def conjugate_gradient(A, b, x0, tol=1e-6, track_history=False):
415
+ """Wrapper around SciPy CG to track iterations if needed."""
416
+ import numpy as np
417
+ from scipy.sparse.linalg import cg
418
+
419
+ if track_history:
420
+ iterations = [x0.copy()]
421
+ def callback(xk):
422
+ iterations.append(np.copy(xk))
423
+ solution, info = cg(A, b, x0=x0, tol=tol, callback=callback)
424
+ return solution, np.array(iterations)
425
+ else:
426
+ solution, info = cg(A, b, x0=x0, tol=tol)
427
+ return solution
428
+
429
+ class IterationTracker:
430
+ """
431
+ A clean callback tracker for native SciPy solvers (cg, gmres, etc.).
432
+ """
433
+ def __init__(self, x0=None):
434
+ import numpy as np
435
+ if x0 is not None:
436
+ self.iterations = [np.array(x0).copy()]
437
+ else:
438
+ self.iterations = []
439
+
440
+ def __call__(self, xk):
441
+ import numpy as np
442
+ self.iterations.append(np.array(xk).copy())
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: executable_engineering
3
- Version: 0.1.32
3
+ Version: 0.1.34
4
4
  Summary: Demonstrative tools for the Executable Engineering textbook
5
5
  Home-page: https://github.com/themintlab/ExecutableEngineering/tree/main/executable_engineering
6
6
  Author: Michael Welland
@@ -1,14 +1,14 @@
1
- executable_engineering/__init__.py,sha256=0sTjLvz5FL29ORVvEGVwI1pCZUBRBL-a35gk1jR06Vg,1114
1
+ executable_engineering/__init__.py,sha256=2DTTPvFi5e9Si0wGobfvaL5khJHAoCjrFYAr2q_h1DQ,1572
2
2
  executable_engineering/closedoptimization_module.py,sha256=i9KkdulyCZmriYKlx0CuUetjoMmxJm9ADWgStU3w85w,9273
3
3
  executable_engineering/closedrootfinder_module.py,sha256=ozccVABOrTiqcdkkqwAWRNo04MsDC0Z_f_tfukl3q20,5706
4
4
  executable_engineering/gradientoptimization_module.py,sha256=-2fErE9cemSEPeV9PlWOf4cF7Tr6DjilEw_NxvE-JYw,6601
5
- executable_engineering/linearsystems_module.py,sha256=Nc4Xu0UUB1NWd7si_TYYa-FuW6DaV8fBtPhAb1aGwuM,3424
5
+ executable_engineering/linearsystems_module.py,sha256=4fJyuFGUdm2FKiydDD-_vAh1O9XEH8f0puBKWkGtlqM,15101
6
6
  executable_engineering/neuralnet_module.py,sha256=Hu9QFoMyODg4RCEpHmT9zTwzjcVFYM8ZLYtbB3CbrsA,10102
7
7
  executable_engineering/numerical_error_module.py,sha256=wxfYP8u29c19I2D6MxpQV3zDMV0DpS1QUqFpp3f6eGE,1204
8
8
  executable_engineering/openoptimization_module.py,sha256=OCPyrynkTo1It50RoT7irnL72aQn6FexE_R1SfFYxlg,8590
9
9
  executable_engineering/openrootfinder_module.py,sha256=rmXDi0XdrDYdLZdPFgYCihMg_4NF1D71i6kh8Kx-V2w,5802
10
- executable_engineering-0.1.32.dist-info/licenses/LICENSE,sha256=Tg4nrt8rFhgpkPbIA8SWoCR3MlGLw0NufB8AE6-TH_o,1074
11
- executable_engineering-0.1.32.dist-info/METADATA,sha256=Uja7p1fCoy_uN5FhvHLh3Wk_489-HO3KRMtdw1QPDP8,1648
12
- executable_engineering-0.1.32.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
13
- executable_engineering-0.1.32.dist-info/top_level.txt,sha256=0U5ATV5WGTLvN9rRSjQ54TyL-ztTyXaN3FzZ_QMq4HM,23
14
- executable_engineering-0.1.32.dist-info/RECORD,,
10
+ executable_engineering-0.1.34.dist-info/licenses/LICENSE,sha256=Tg4nrt8rFhgpkPbIA8SWoCR3MlGLw0NufB8AE6-TH_o,1074
11
+ executable_engineering-0.1.34.dist-info/METADATA,sha256=ABgLWLdM0FnHXlY2BkYbVJer6d9Mb4H6nrE9VoiHkc8,1648
12
+ executable_engineering-0.1.34.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
13
+ executable_engineering-0.1.34.dist-info/top_level.txt,sha256=0U5ATV5WGTLvN9rRSjQ54TyL-ztTyXaN3FzZ_QMq4HM,23
14
+ executable_engineering-0.1.34.dist-info/RECORD,,