executable-engineering 0.1.35__py3-none-any.whl → 0.1.38__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,9 +5,11 @@ 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, 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
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, discretise_poisson, spai
9
9
 
10
10
  __all__ = [
11
+ "discretise_poisson",
12
+ "spai",
11
13
  "visual_solve_2d",
12
14
  "visualize_conditioning",
13
15
  "visualize_matrix_norms",
@@ -430,13 +430,105 @@ class IterationTracker:
430
430
  """
431
431
  A clean callback tracker for native SciPy solvers (cg, gmres, etc.).
432
432
  """
433
- def __init__(self, x0=None):
433
+ def __init__(self, x0=None, A=None, b=None, print_residual=False):
434
434
  import numpy as np
435
435
  if x0 is not None:
436
436
  self.iterations = [np.array(x0).copy()]
437
437
  else:
438
438
  self.iterations = []
439
+
440
+ self.residuals = []
441
+ self.A = A
442
+ self.b = b
443
+ self.print_residual = print_residual
444
+ self.step = 0
445
+
446
+ if A is not None and b is not None and x0 is not None:
447
+ x_arr = np.array(x0)
448
+ res = np.linalg.norm(A @ x_arr - b)
449
+ self.residuals.append(res)
450
+ if self.print_residual:
451
+ guess_str = np.array2string(x_arr, precision=4, separator=', ', suppress_small=True)
452
+ print(f"Step {self.step}: Guess = {guess_str}, Residual = {res:.4e}")
439
453
 
440
454
  def __call__(self, xk):
441
455
  import numpy as np
442
- self.iterations.append(np.array(xk).copy())
456
+ self.step += 1
457
+
458
+ # Check if xk is a scalar (i.e. callback_type='pr_norm' in GMRES)
459
+ if np.isscalar(xk) or (isinstance(xk, np.ndarray) and xk.size == 1):
460
+ res = float(np.squeeze(xk))
461
+ self.residuals.append(res)
462
+ if self.print_residual:
463
+ print(f"Step {self.step}: Residual = {res:.4e} (Guess vector xk not computed by SciPy GMRES)")
464
+ else:
465
+ # xk is a vector (i.e. from CG)
466
+ x = np.array(xk).copy()
467
+ self.iterations.append(x)
468
+ if self.A is not None and self.b is not None:
469
+ res = np.linalg.norm(self.A @ x - self.b)
470
+ self.residuals.append(res)
471
+ if self.print_residual:
472
+ guess_str = np.array2string(x, precision=4, separator=', ', suppress_small=True)
473
+ print(f"Step {self.step}: Guess = {guess_str}, Residual = {res:.4e}")
474
+
475
+
476
+ def discretise_poisson(N, Q):
477
+ """Generate the matrix and rhs associated with the discrete Poisson operator."""
478
+ import numpy as np
479
+ from scipy.sparse import coo_matrix
480
+
481
+ nelements = 5 * N**2 - 16 * N + 16
482
+
483
+ row_ind = np.empty(nelements, dtype=np.float64)
484
+ col_ind = np.empty(nelements, dtype=np.float64)
485
+ data = np.empty(nelements, dtype=np.float64)
486
+
487
+ f = np.empty(N * N, dtype=np.float64)
488
+
489
+ count = 0
490
+ for j in range(N):
491
+ for i in range(N):
492
+ if i == 0 or i == N - 1 or j == 0 or j == N - 1:
493
+ row_ind[count] = col_ind[count] = j * N + i
494
+ data[count] = 1
495
+ f[j * N + i] = 0
496
+ count += 1
497
+
498
+ else:
499
+ row_ind[count : count + 5] = j * N + i
500
+ col_ind[count] = j * N + i
501
+ col_ind[count + 1] = j * N + i + 1
502
+ col_ind[count + 2] = j * N + i - 1
503
+ col_ind[count + 3] = (j + 1) * N + i
504
+ col_ind[count + 4] = (j - 1) * N + i
505
+
506
+ data[count] = 4 * (N - 1)**2
507
+ data[count + 1 : count + 5] = - (N - 1)**2
508
+ f[j * N + i] = Q
509
+
510
+ count += 5
511
+
512
+ return coo_matrix((data, (row_ind, col_ind)), shape=(N**2, N**2)).tocsr(), f
513
+
514
+ def spai(A, m):
515
+ """Perform m step of the SPAI iteration."""
516
+ import numpy as np
517
+ from scipy.sparse import identity
518
+ from scipy.sparse.linalg import onenormest
519
+
520
+ n = A.shape[0]
521
+
522
+ ident = identity(n, format='csr')
523
+ alpha = 2 / onenormest(A @ A.T)
524
+ M = alpha * A
525
+
526
+ for index in range(m):
527
+ C = A @ M
528
+ G = ident - C
529
+ AG = A @ G
530
+ trace = (G.T @ AG).diagonal().sum()
531
+ alpha = trace / np.linalg.norm(AG.data)**2
532
+ M = M + alpha * G
533
+
534
+ return M
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: executable_engineering
3
- Version: 0.1.35
3
+ Version: 0.1.38
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=GiYYijxAfiee44SRLXjMsFCa3xOPWtUx0tnlWm4G6TM,1596
1
+ executable_engineering/__init__.py,sha256=TbE18BDMSDAqyHnJI0XQXMIcM6bXQv8ebV3rWijyVP0,1656
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=4fJyuFGUdm2FKiydDD-_vAh1O9XEH8f0puBKWkGtlqM,15101
5
+ executable_engineering/linearsystems_module.py,sha256=w6UkwZu80gUz5bAIWY47xJbwaEVzR9tCcIBkMsKjIRk,18356
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.35.dist-info/licenses/LICENSE,sha256=Tg4nrt8rFhgpkPbIA8SWoCR3MlGLw0NufB8AE6-TH_o,1074
11
- executable_engineering-0.1.35.dist-info/METADATA,sha256=g6kHizAHnhfStOWrQIt53yY59SAdmTmiojVJ2hTvA1I,1648
12
- executable_engineering-0.1.35.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
13
- executable_engineering-0.1.35.dist-info/top_level.txt,sha256=0U5ATV5WGTLvN9rRSjQ54TyL-ztTyXaN3FzZ_QMq4HM,23
14
- executable_engineering-0.1.35.dist-info/RECORD,,
10
+ executable_engineering-0.1.38.dist-info/licenses/LICENSE,sha256=Tg4nrt8rFhgpkPbIA8SWoCR3MlGLw0NufB8AE6-TH_o,1074
11
+ executable_engineering-0.1.38.dist-info/METADATA,sha256=541f1AVAklhM94uez2A7obug_jOUPVS5eZMdGoQrWlI,1648
12
+ executable_engineering-0.1.38.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
13
+ executable_engineering-0.1.38.dist-info/top_level.txt,sha256=0U5ATV5WGTLvN9rRSjQ54TyL-ztTyXaN3FzZ_QMq4HM,23
14
+ executable_engineering-0.1.38.dist-info/RECORD,,