FastLSQ 0.1.5__tar.gz → 0.2.2__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.
- fastlsq-0.2.2/CHANGELOG.md +249 -0
- {fastlsq-0.1.5 → fastlsq-0.2.2/FastLSQ.egg-info}/PKG-INFO +11 -10
- fastlsq-0.2.2/FastLSQ.egg-info/SOURCES.txt +106 -0
- {fastlsq-0.1.5 → fastlsq-0.2.2}/MANIFEST.in +0 -1
- {fastlsq-0.1.5/FastLSQ.egg-info → fastlsq-0.2.2}/PKG-INFO +11 -10
- {fastlsq-0.1.5 → fastlsq-0.2.2}/README.md +3 -3
- fastlsq-0.2.2/examples/extras/fred_sde.py +262 -0
- fastlsq-0.2.2/examples/extras/fred_sde_fastlsq.py +329 -0
- fastlsq-0.2.2/examples/extras/gaia_potential.py +183 -0
- fastlsq-0.2.2/examples/extras/gaia_potential_fastlsq.py +397 -0
- fastlsq-0.2.2/examples/extras/horizons_ephemeris.py +319 -0
- fastlsq-0.2.2/examples/extras/numerai_alpha.py +214 -0
- fastlsq-0.2.2/examples/extras/numerai_alpha_fastlsq.py +374 -0
- fastlsq-0.2.2/examples/extras/run_all_fastlsq.py +107 -0
- fastlsq-0.2.2/examples/extras/scenarios/__init__.py +0 -0
- fastlsq-0.2.2/examples/extras/scenarios/_alsu_lattice.py +196 -0
- fastlsq-0.2.2/examples/extras/scenarios/_common.py +164 -0
- fastlsq-0.2.2/examples/extras/scenarios/run_all.py +70 -0
- fastlsq-0.2.2/examples/extras/scenarios/s01_beamloss_ode.py +340 -0
- fastlsq-0.2.2/examples/extras/scenarios/s01_betatron_tune.py +448 -0
- fastlsq-0.2.2/examples/extras/scenarios/s01_green_fff.py +262 -0
- fastlsq-0.2.2/examples/extras/scenarios/s01_hill_ivp.py +263 -0
- fastlsq-0.2.2/examples/extras/scenarios/s01_observe_fit_act_simulator.py +353 -0
- fastlsq-0.2.2/examples/extras/scenarios/s01_orbit_inverse.py +332 -0
- fastlsq-0.2.2/examples/extras/scenarios/s01_passive_loco.py +246 -0
- fastlsq-0.2.2/examples/extras/scenarios/s01_perturbed_hill.py +247 -0
- fastlsq-0.2.2/examples/extras/scenarios/s01_sofb_observe_fit_act.py +619 -0
- fastlsq-0.2.2/examples/extras/scenarios/s01_streaming_archive_growth.py +310 -0
- fastlsq-0.2.2/examples/extras/scenarios/s01_synchrotron_ode.py +335 -0
- fastlsq-0.2.2/examples/extras/scenarios/s01_tides_3months.py +257 -0
- fastlsq-0.2.2/examples/extras/scenarios/s01_topoff_impulse.py +375 -0
- fastlsq-0.2.2/examples/extras/scenarios/s01_visualize.py +400 -0
- fastlsq-0.2.2/examples/extras/scenarios/s02_plasma_wakefield.py +99 -0
- fastlsq-0.2.2/examples/extras/scenarios/s03_synchrobetatron.py +75 -0
- fastlsq-0.2.2/examples/extras/scenarios/s04_sunspots.py +116 -0
- fastlsq-0.2.2/examples/extras/scenarios/s05_helioseismology.py +105 -0
- fastlsq-0.2.2/examples/extras/scenarios/s06_tides.py +122 -0
- fastlsq-0.2.2/examples/extras/scenarios/s07_iers_earth_rotation.py +97 -0
- fastlsq-0.2.2/examples/extras/scenarios/s08_mauna_loa_co2.py +96 -0
- fastlsq-0.2.2/examples/extras/scenarios/s09_enso_qbo.py +131 -0
- fastlsq-0.2.2/examples/extras/scenarios/s10_pulsar_timing.py +99 -0
- fastlsq-0.2.2/examples/extras/scenarios/s11_modal_analysis.py +109 -0
- fastlsq-0.2.2/examples/extras/scenarios/s12_mems_resonator.py +150 -0
- fastlsq-0.2.2/examples/extras/scenarios/s13_variable_stars_kepler.py +111 -0
- fastlsq-0.2.2/examples/extras/scenarios/s14_eeg.py +94 -0
- fastlsq-0.2.2/examples/extras/scenarios/s15_circadian.py +130 -0
- fastlsq-0.2.2/examples/extras/spectral_expansion.py +96 -0
- fastlsq-0.2.2/examples/grad_shafranov.py +186 -0
- fastlsq-0.2.2/examples/grid_inverse.py +74 -0
- fastlsq-0.2.2/examples/grid_rl_control.py +128 -0
- fastlsq-0.2.2/examples/grid_swing.py +130 -0
- fastlsq-0.2.2/examples/gs_inverse.py +127 -0
- fastlsq-0.2.2/examples/gs_rl_control.py +182 -0
- fastlsq-0.2.2/examples/orbit_hill.py +212 -0
- fastlsq-0.2.2/examples/orbit_inverse.py +98 -0
- fastlsq-0.2.2/examples/orbit_rl.py +154 -0
- fastlsq-0.2.2/examples/vector_basis_stream_vorticity.py +146 -0
- {fastlsq-0.1.5 → fastlsq-0.2.2}/fastlsq/__init__.py +12 -1
- {fastlsq-0.1.5 → fastlsq-0.2.2}/fastlsq/api.py +17 -10
- {fastlsq-0.1.5 → fastlsq-0.2.2}/fastlsq/basis.py +51 -9
- fastlsq-0.2.2/fastlsq/device.py +130 -0
- {fastlsq-0.1.5 → fastlsq-0.2.2}/fastlsq/export.py +4 -1
- {fastlsq-0.1.5 → fastlsq-0.2.2}/fastlsq/geometry.py +16 -16
- {fastlsq-0.1.5 → fastlsq-0.2.2}/fastlsq/learnable.py +117 -69
- fastlsq-0.2.2/fastlsq/linalg.py +137 -0
- {fastlsq-0.1.5 → fastlsq-0.2.2}/fastlsq/newton.py +10 -4
- {fastlsq-0.1.5 → fastlsq-0.2.2}/fastlsq/problems/__init__.py +6 -4
- {fastlsq-0.1.5 → fastlsq-0.2.2}/fastlsq/problems/linear.py +29 -55
- {fastlsq-0.1.5 → fastlsq-0.2.2}/fastlsq/problems/nonlinear.py +20 -20
- {fastlsq-0.1.5 → fastlsq-0.2.2}/fastlsq/problems/regression.py +38 -38
- {fastlsq-0.1.5 → fastlsq-0.2.2}/fastlsq/solvers.py +7 -7
- {fastlsq-0.1.5 → fastlsq-0.2.2}/fastlsq/tuning.py +12 -5
- {fastlsq-0.1.5 → fastlsq-0.2.2}/fastlsq/utils.py +8 -2
- fastlsq-0.2.2/fastlsq/vector.py +412 -0
- fastlsq-0.2.2/fastlsq/viz.py +456 -0
- {fastlsq-0.1.5 → fastlsq-0.2.2}/pyproject.toml +8 -7
- fastlsq-0.2.2/tests/test_block.py +68 -0
- fastlsq-0.2.2/tests/test_derivatives.py +209 -0
- fastlsq-0.2.2/tests/test_device.py +43 -0
- fastlsq-0.2.2/tests/test_grad_shafranov.py +41 -0
- fastlsq-0.2.2/tests/test_grid_swing.py +40 -0
- fastlsq-0.2.2/tests/test_learnable.py +98 -0
- fastlsq-0.2.2/tests/test_orbit_hill.py +42 -0
- fastlsq-0.2.2/tests/test_vector_basis.py +220 -0
- fastlsq-0.1.5/CHANGELOG.md +0 -141
- fastlsq-0.1.5/FastLSQ.egg-info/SOURCES.txt +0 -77
- fastlsq-0.1.5/examples/digital_twins/darcy_heat.py +0 -583
- fastlsq-0.1.5/examples/digital_twins/pendulum.py +0 -242
- fastlsq-0.1.5/examples/digital_twins/pendulum_benchmark.py +0 -281
- fastlsq-0.1.5/examples/digital_twins/plasma_wakefield.py +0 -339
- fastlsq-0.1.5/examples/digital_twins/plasma_wakefield_2D_1.py +0 -863
- fastlsq-0.1.5/examples/digital_twins/plasma_wakefield_2D_2.py +0 -769
- fastlsq-0.1.5/examples/digital_twins/plasma_wakefield_2d_3.py +0 -818
- fastlsq-0.1.5/examples/digital_twins/plasma_wakefield_parameteric.py +0 -475
- fastlsq-0.1.5/examples/digital_twins/plot_utils.py +0 -42
- fastlsq-0.1.5/examples/digital_twins/structural_health_simple.py +0 -343
- fastlsq-0.1.5/examples/digital_twins/turbulence_gravity_cooling.py +0 -387
- fastlsq-0.1.5/examples/inverse/aero_.py +0 -362
- fastlsq-0.1.5/examples/inverse/denoising_parameter_estimation.py +0 -297
- fastlsq-0.1.5/examples/inverse/elastic_wave_animation.py +0 -300
- fastlsq-0.1.5/examples/inverse/heat_from_video.py +0 -394
- fastlsq-0.1.5/examples/inverse/inverse_turbulence.py +0 -811
- fastlsq-0.1.5/examples/inverse/shape_ns.py +0 -1426
- fastlsq-0.1.5/examples/inverse/subsurface_imaging.py +0 -547
- fastlsq-0.1.5/examples/inverse/wing_optimize_simple.py +0 -283
- fastlsq-0.1.5/examples/sindy/compare_sindy_methods.py +0 -760
- fastlsq-0.1.5/examples/sindy/sindy_benchmarks.py +0 -351
- fastlsq-0.1.5/examples/sindy/sindy_differentiable.py +0 -418
- fastlsq-0.1.5/examples/sindy/sindy_minimal_diff.py +0 -716
- fastlsq-0.1.5/fastlsq/linalg.py +0 -34
- fastlsq-0.1.5/misc/fastlsq_teaser.png +0 -0
- fastlsq-0.1.5/misc/ideal_quadrupole.png +0 -0
- fastlsq-0.1.5/misc/inverse_heat_source.gif +0 -0
- fastlsq-0.1.5/misc/inverse_heat_source.png +0 -0
- fastlsq-0.1.5/misc/inverse_magnetostatics.png +0 -0
- fastlsq-0.1.5/misc/inverse_magnetostatics_convergence.png +0 -0
- fastlsq-0.1.5/misc/quadrupole_convergence.png +0 -0
- fastlsq-0.1.5/misc/quadrupole_optimization.png +0 -0
- fastlsq-0.1.5/misc/tutorial_nlpoisson_convergence.png +0 -0
- fastlsq-0.1.5/misc/tutorial_nlpoisson_solution.png +0 -0
- {fastlsq-0.1.5 → fastlsq-0.2.2}/FastLSQ.egg-info/dependency_links.txt +0 -0
- {fastlsq-0.1.5 → fastlsq-0.2.2}/FastLSQ.egg-info/requires.txt +0 -0
- {fastlsq-0.1.5 → fastlsq-0.2.2}/FastLSQ.egg-info/top_level.txt +0 -0
- {fastlsq-0.1.5 → fastlsq-0.2.2}/LICENSE +0 -0
- {fastlsq-0.1.5 → fastlsq-0.2.2}/examples/add_your_own_pde.py +0 -0
- {fastlsq-0.1.5 → fastlsq-0.2.2}/examples/benchmark_comparison.py +0 -0
- {fastlsq-0.1.5 → fastlsq-0.2.2}/examples/custom_features.py +0 -0
- {fastlsq-0.1.5 → fastlsq-0.2.2}/examples/inverse_heat_source.py +0 -0
- {fastlsq-0.1.5 → fastlsq-0.2.2}/examples/inverse_magnetostatics.py +0 -0
- {fastlsq-0.1.5 → fastlsq-0.2.2}/examples/inverse_source_position.py +0 -0
- {fastlsq-0.1.5 → fastlsq-0.2.2}/examples/learnable_helmholtz.py +0 -0
- {fastlsq-0.1.5 → fastlsq-0.2.2}/examples/pde_discovery.py +0 -0
- {fastlsq-0.1.5 → fastlsq-0.2.2}/examples/run_all_extensions.py +0 -0
- {fastlsq-0.1.5 → fastlsq-0.2.2}/examples/run_linear.py +0 -0
- {fastlsq-0.1.5 → fastlsq-0.2.2}/examples/run_nonlinear.py +0 -0
- {fastlsq-0.1.5 → fastlsq-0.2.2}/examples/tutorial_basic.py +0 -0
- {fastlsq-0.1.5 → fastlsq-0.2.2}/examples/tutorial_nonlinear.py +0 -0
- {fastlsq-0.1.5 → fastlsq-0.2.2}/fastlsq/block.py +0 -0
- {fastlsq-0.1.5 → fastlsq-0.2.2}/fastlsq/diagnostics.py +0 -0
- {fastlsq-0.1.5 → fastlsq-0.2.2}/fastlsq/lightning.py +0 -0
- {fastlsq-0.1.5 → fastlsq-0.2.2}/fastlsq/plotting.py +0 -0
- {fastlsq-0.1.5 → fastlsq-0.2.2}/requirements.txt +0 -0
- {fastlsq-0.1.5 → fastlsq-0.2.2}/setup.cfg +0 -0
- {fastlsq-0.1.5 → fastlsq-0.2.2}/tests/test_basic.py +0 -0
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to FastLSQ will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## [0.2.2] - 2026-06-03
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- **Learnable bandwidth now trains.** `LearnableFastLSQ.solve_inner` replaced the
|
|
10
|
+
backprop-through-`torch.linalg.svd` inner solve (which returned NaN gradients
|
|
11
|
+
w.r.t. the bandwidth on the clustered singular values of random-feature
|
|
12
|
+
matrices) with the SVD-based `gelsd` rank-revealing least-squares driver, so
|
|
13
|
+
`train_bandwidth` / `fit` no longer stall at step 0.
|
|
14
|
+
- **Default-solve accuracy.** Tightened the `_auto_solve` Cholesky-acceptance
|
|
15
|
+
probe from `rcond**0.5` to `rcond**0.25`, so `method="auto"` falls back to SVD
|
|
16
|
+
before the normal-equations Cholesky loses half its float64 digits
|
|
17
|
+
(cond(A) ~ 1e7 previously returned a ~1e-3-accurate answer).
|
|
18
|
+
- **Newton convergence and robustness.** The stop test now combines a *relative*
|
|
19
|
+
residual criterion (`res_norm < tol_res * R0`) with the relative solution
|
|
20
|
+
change (`||Δu||/||u|| < tol_du`); the previous unreachable absolute residual
|
|
21
|
+
tolerance forced every nonlinear solve to run the full `max_iter`. The
|
|
22
|
+
backtracking line search keeps the previous iterate when no step satisfies
|
|
23
|
+
Armijo instead of committing a worse point. `solve_nonlinear` default
|
|
24
|
+
tolerances loosened to `tol_res=1e-8`, `tol_du=1e-10`.
|
|
25
|
+
- **Continuation guard.** `solve_nonlinear` no longer raises `TypeError` when a
|
|
26
|
+
problem sets `use_continuation=True` without a `nu_target`.
|
|
27
|
+
- **Regression problems solvable via the public API.** Their `get_train_data`
|
|
28
|
+
now accepts the `n_pde`/`n_bc` signature used by `solve_linear`,
|
|
29
|
+
`auto_select_scale`, and `check_problem` (was `n_samples`, raising
|
|
30
|
+
`TypeError`); `auto_select_scale` now raises when every trial fails instead of
|
|
31
|
+
silently returning the first scale.
|
|
32
|
+
- **Float32 inputs.** `SinusoidalBasis.cache` promotes inputs to the basis
|
|
33
|
+
dtype/device, so float32 collocation points no longer raise `float != double`.
|
|
34
|
+
- **Checkpoint reload.** `load_checkpoint` passes `weights_only=False`, fixing
|
|
35
|
+
`UnpicklingError` on torch >= 2.6 (checkpoints store NumPy arrays).
|
|
36
|
+
- **Vector per-component scale.** `VectorFastLSQSolver.add_block` accepts a NumPy
|
|
37
|
+
array of per-component bandwidths (previously list/tuple only, silently
|
|
38
|
+
misread as per-dimension).
|
|
39
|
+
- **ElasticWave2D operator.** Scaled the spatial and cross terms by `t_max²`
|
|
40
|
+
(time normalisation), consistent with `Wave2D_MS`.
|
|
41
|
+
|
|
42
|
+
### Changed
|
|
43
|
+
|
|
44
|
+
- Problem modules (`nonlinear.py`, `regression.py`) resolve the device via the
|
|
45
|
+
live `get_device()` rather than an import-time snapshot.
|
|
46
|
+
- Packaging: the source distribution no longer ships the `misc/` images (the
|
|
47
|
+
sdist was ~14 MB); project URLs point to `github.com/sulcantonin/FastLSQ`;
|
|
48
|
+
README images use absolute URLs so they render on PyPI.
|
|
49
|
+
`examples/orbit_hill.py` solves via rank-revealing `lstsq` rather than a
|
|
50
|
+
normal-equations Cholesky.
|
|
51
|
+
|
|
52
|
+
## [0.2.1] - 2026-06-02
|
|
53
|
+
|
|
54
|
+
### Added
|
|
55
|
+
|
|
56
|
+
- **Device abstraction** (`fastlsq/device.py`): `resolve_device`, `set_device`,
|
|
57
|
+
`get_device`, `device_info` for CPU / CUDA / Apple-MPS. dtype-aware -- MPS is
|
|
58
|
+
auto-selected only for float32 (it has no float64), so the default float64
|
|
59
|
+
high-accuracy regime stays on CPU/CUDA. Override with `set_device(...)` or the
|
|
60
|
+
`FASTLSQ_DEVICE` environment variable; internal tensor creation respects the
|
|
61
|
+
active device at call time.
|
|
62
|
+
- **Pluggable linear solver** `solve_lstsq(..., method=...)`:
|
|
63
|
+
- `"svd"` -- rank-revealing truncated SVD (LAPACK `gelsd` fast path on CPU);
|
|
64
|
+
- `"cholesky"` -- fast normal-equations solve for well-conditioned systems;
|
|
65
|
+
- `"rsvd"` -- torch-native randomized SVD (`O(MNk)`) for strongly low-rank `A`;
|
|
66
|
+
- `"auto"` (default) -- Cholesky with a cheap conditioning probe, falling back
|
|
67
|
+
to SVD when ill-conditioned (recovers the fast path without losing accuracy).
|
|
68
|
+
MPS factorizations run on CPU (no robust `svd`/`lstsq` there) and move back.
|
|
69
|
+
- **Working anisotropic Sigma = L Lᵀ learner**: `LearnableFastLSQ` (diagonal &
|
|
70
|
+
cholesky modes) now converges -- `solve_inner` uses a differentiable
|
|
71
|
+
*rank-revealing* solve, the Cholesky factor is log-parameterized (clamped,
|
|
72
|
+
positive-definite), and `train_bandwidth` is robust (gradient clipping,
|
|
73
|
+
best-iterate restore, graceful SVD/gradient-failure handling). Chainable
|
|
74
|
+
`LearnableFastLSQ.fit(problem, ...)` for one-line learn-then-predict.
|
|
75
|
+
- **Vector-valued solutions (`u: ℝᵈ → ℝᵏ`)**: first-class support for coupled and
|
|
76
|
+
decoupled multi-output PDEs via the new `fastlsq.block` module. Problems opt in
|
|
77
|
+
with `self.n_outputs = k`; `solver.beta` is `(N, k)` and `solver.predict(x)`
|
|
78
|
+
returns `(M, k)` (scalar `k=1` is bit-for-bit unchanged). `block_concat`
|
|
79
|
+
assembles a nested list of blocks (`None` = zero block); `pack_beta` /
|
|
80
|
+
`unpack_beta` convert between `(N, k)` and the block-stacked `(N*k, 1)` solve.
|
|
81
|
+
The block-stacked LSQ is solved by the rank-revealing solver, and the
|
|
82
|
+
Σ-learner computes its loss on the flat `_beta_flat` so it stays correct for
|
|
83
|
+
`k>1`.
|
|
84
|
+
- **Learnable operator coefficients**: `Op` accepts `nn.Parameter` (and tensors)
|
|
85
|
+
as coefficients, e.g. `Op.laplacian(d=2) + k**2 * Op.identity(d=2)` with
|
|
86
|
+
`k = nn.Parameter(...)`; gradients flow through the prebuilt linear solve.
|
|
87
|
+
|
|
88
|
+
### Changed
|
|
89
|
+
|
|
90
|
+
- `solve_lstsq` defaults to the rank-revealing / `auto` solve instead of forming
|
|
91
|
+
the normal equations -- several orders of magnitude more accurate on the
|
|
92
|
+
rank-deficient random-feature systems (at a higher, still one-shot, cost).
|
|
93
|
+
- `solve_linear` is one-shot: the bandwidth-learning hyper-parameters live on
|
|
94
|
+
`LearnableFastLSQ.fit()` / `train_bandwidth`, not the solve signature.
|
|
95
|
+
- Packaging: `requires-python` lowered to `>=3.9` (+3.9 classifier); description
|
|
96
|
+
updated.
|
|
97
|
+
|
|
98
|
+
### Fixed
|
|
99
|
+
|
|
100
|
+
- The previously dead `LearnableFastLSQ(mode="cholesky")` path, which diverged
|
|
101
|
+
from an unstable inner `torch.linalg.lstsq` and an unconstrained `L`.
|
|
102
|
+
|
|
103
|
+
## [0.1.5] - 2026-05-25
|
|
104
|
+
|
|
105
|
+
### Added
|
|
106
|
+
|
|
107
|
+
- **Vector-valued features**: new `VectorBasis` and `VectorFastLSQSolver`
|
|
108
|
+
(`fastlsq/vector.py`) for solving coupled systems where the unknown is a
|
|
109
|
+
vector field `u(x) = (u_1, ..., u_K)`. Use cases include
|
|
110
|
+
streamfunction-vorticity NS `(psi, omega)`, incompressible NS primitive
|
|
111
|
+
variables `(u, v, p)`, multi-species transport, MHD, etc.
|
|
112
|
+
|
|
113
|
+
- `VectorBasis.random(input_dim, n_features, sigma, n_components, sigmas=...)`
|
|
114
|
+
creates K independent random-Fourier `SinusoidalBasis`es; per-component
|
|
115
|
+
bandwidth can be tuned via `sigmas`.
|
|
116
|
+
- Stacked evaluators: `evaluate(x) -> (M, K, N)`, `gradient -> (M, K, d, N)`,
|
|
117
|
+
`laplacian`, `hessian_diag`, `derivative(alpha)`.
|
|
118
|
+
- Block-diagonal assembly helpers (`block_diag_evaluate`,
|
|
119
|
+
`block_diag_laplacian`, `block_diag_derivative`) for systems whose
|
|
120
|
+
rows are independent per component.
|
|
121
|
+
- Coefficient packing utilities (`stack_betas`, `unstack_beta`,
|
|
122
|
+
`predict`) accept per-component lists, stacked columns, or
|
|
123
|
+
`(N, K)` matrices interchangeably.
|
|
124
|
+
- `VectorFastLSQSolver(input_dim, n_components, normalize=True)` is the
|
|
125
|
+
multi-component counterpart of `FastLSQSolver`; `add_block(scale=...)`
|
|
126
|
+
accepts either a scalar or a list of K scalars for per-component
|
|
127
|
+
bandwidth.
|
|
128
|
+
- `component(k)` / `component_solver(k)` give direct access to the k-th
|
|
129
|
+
scalar basis / solver for ad-hoc per-component work.
|
|
130
|
+
|
|
131
|
+
### Other
|
|
132
|
+
|
|
133
|
+
- Synchronised `pyproject.toml`, `fastlsq.__version__`, and CHANGELOG (the
|
|
134
|
+
package source had drifted to `__version__ = "0.1.0"` against
|
|
135
|
+
`pyproject.toml = "0.1.4"`; both now read `"0.1.5"`).
|
|
136
|
+
|
|
137
|
+
## [0.2.0] - 2026-03-01
|
|
138
|
+
|
|
139
|
+
### Added
|
|
140
|
+
|
|
141
|
+
#### SinusoidalBasis -- analytical derivative engine (new foundation)
|
|
142
|
+
- `SinusoidalBasis` class: evaluates arbitrary-order mixed partial derivatives
|
|
143
|
+
of sinusoidal features in O(1) via the cyclic derivative identity
|
|
144
|
+
- `BasisCache`: pre-computes sin(Z)/cos(Z) once, reuses across all derivative
|
|
145
|
+
evaluations at the same points
|
|
146
|
+
- `DiffOperator` / `Op`: symbolic linear differential operators that compose
|
|
147
|
+
via `+`, `-`, scalar `*`. Factory methods: `Op.laplacian()`,
|
|
148
|
+
`Op.partial()`, `Op.identity()`, `Op.biharmonic()`, `Op.gradient_component()`
|
|
149
|
+
- `FeatureBasis`: adapter wrapping non-sinusoidal solvers (e.g. PIELMSolver
|
|
150
|
+
with tanh) into the same basis interface
|
|
151
|
+
|
|
152
|
+
#### Learnable bandwidth
|
|
153
|
+
- `LearnableFastLSQ`: PyTorch `nn.Module` with learnable bandwidth via
|
|
154
|
+
reparameterisation trick (scalar, diagonal, or full Cholesky modes)
|
|
155
|
+
- `train_bandwidth()`: hybrid training loop (inner exact solve + outer AdamW
|
|
156
|
+
on bandwidth parameters)
|
|
157
|
+
|
|
158
|
+
#### PDE discovery example
|
|
159
|
+
- `examples/pde_discovery.py`: sparse regression (SINDy-style) using
|
|
160
|
+
analytical derivatives from `SinusoidalBasis` as the dictionary
|
|
161
|
+
|
|
162
|
+
### Changed
|
|
163
|
+
|
|
164
|
+
#### Architecture: basis-centric API (breaking)
|
|
165
|
+
- **`solver.basis`** is now the single entry point for all feature and
|
|
166
|
+
derivative computations. Every solver exposes a `.basis` property
|
|
167
|
+
(`SinusoidalBasis` for FastLSQ, `FeatureBasis` for PIELM).
|
|
168
|
+
- All problem classes (`linear.py`, `nonlinear.py`, `regression.py`) rewritten
|
|
169
|
+
to use `solver.basis.evaluate()`, `.gradient()`, `.hessian_diag()`,
|
|
170
|
+
`.laplacian()`, and `.cache()` instead of tuple unpacking.
|
|
171
|
+
- `FastLSQSolver.predict()`, `.predict_with_grad()`, `.predict_with_laplacian()`
|
|
172
|
+
delegate directly to `self.basis`.
|
|
173
|
+
- `PIELMSolver` now exposes `.basis` (via `FeatureBasis` adapter) so problem
|
|
174
|
+
classes work identically for both solver types.
|
|
175
|
+
- `newton.py`: uses `solver.basis.evaluate()` for convergence metrics.
|
|
176
|
+
|
|
177
|
+
#### Examples rewritten
|
|
178
|
+
- `add_your_own_pde.py`: shows `Op`-based PDE definition only
|
|
179
|
+
- `custom_features.py`: shows cosine features via phase shift only
|
|
180
|
+
|
|
181
|
+
### Removed
|
|
182
|
+
- `get_features()` method removed from public API (all solvers, all problems)
|
|
183
|
+
- `SinusoidalBasis.get_features()` legacy tuple interface removed
|
|
184
|
+
- `CustomFeatureSolver` subclass pattern removed
|
|
185
|
+
- Legacy `build()` patterns using `(H, dH, ddH)` tuple unpacking
|
|
186
|
+
|
|
187
|
+
### Fixed
|
|
188
|
+
- Missing `sample_ball` import in `tests/test_basic.py`
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
## [0.1.0] - 2026-02-12
|
|
192
|
+
|
|
193
|
+
### Added
|
|
194
|
+
|
|
195
|
+
#### High-level API
|
|
196
|
+
- `solve_linear()` - One-line function to solve linear PDEs
|
|
197
|
+
- `solve_nonlinear()` - One-line function to solve nonlinear PDEs via Newton-Raphson
|
|
198
|
+
- Automatic scale selection via `auto_select_scale()`
|
|
199
|
+
|
|
200
|
+
#### Plotting & Visualization
|
|
201
|
+
- `plot_solution_1d()` - Plot 1D solutions with exact comparison
|
|
202
|
+
- `plot_solution_2d_slice()` - Plot 2D solutions as 1D slices
|
|
203
|
+
- `plot_solution_2d_contour()` - Contour plots for 2D solutions
|
|
204
|
+
- `plot_convergence()` - Newton iteration convergence plots
|
|
205
|
+
- `plot_spectral_sensitivity()` - Error vs scale analysis
|
|
206
|
+
|
|
207
|
+
#### Geometry & Sampling
|
|
208
|
+
- `sample_box()` - Uniform sampling from hypercubes
|
|
209
|
+
- `sample_ball()` - Uniform sampling from balls
|
|
210
|
+
- `sample_sphere()` - Uniform sampling from sphere surfaces
|
|
211
|
+
- `sample_interval()` - 1D interval sampling
|
|
212
|
+
- `sample_boundary_box()` - Boundary point generation for boxes
|
|
213
|
+
- `get_sampler()` - Get sampler by name
|
|
214
|
+
|
|
215
|
+
#### Diagnostics & Error Handling
|
|
216
|
+
- `check_problem()` - Validate problem definitions (shapes, gradients, data)
|
|
217
|
+
- `check_solver_conditioning()` - Check linear system conditioning
|
|
218
|
+
- `suggest_scale()` - Heuristic scale suggestions
|
|
219
|
+
|
|
220
|
+
#### Export & Interoperability
|
|
221
|
+
- `to_numpy()` - Convert predictions to NumPy arrays
|
|
222
|
+
- `to_dict()` / `from_dict()` - Serialize/deserialize solver state
|
|
223
|
+
- `save_checkpoint()` / `load_checkpoint()` - Save/load solver checkpoints
|
|
224
|
+
- `FastLSQModule` - PyTorch Lightning integration (optional)
|
|
225
|
+
|
|
226
|
+
#### Documentation & Examples
|
|
227
|
+
- `examples/tutorial_basic.py` - Basic linear PDE tutorial
|
|
228
|
+
- `examples/tutorial_nonlinear.py` - Nonlinear PDE tutorial
|
|
229
|
+
- `examples/add_your_own_pde.py` - Guide for adding custom PDEs
|
|
230
|
+
- `examples/custom_features.py` - Extensibility example
|
|
231
|
+
- Comprehensive README with usage examples
|
|
232
|
+
|
|
233
|
+
#### Infrastructure
|
|
234
|
+
- `benchmarks/run_all.py` - Reproducible benchmark suite
|
|
235
|
+
- `tests/test_basic.py` - Basic test suite
|
|
236
|
+
- `.github/workflows/ci.yml` - GitHub Actions CI/CD
|
|
237
|
+
- `CHANGELOG.md` - This file
|
|
238
|
+
|
|
239
|
+
### Changed
|
|
240
|
+
|
|
241
|
+
- Restructured codebase from 2 monolithic files into a proper Python package
|
|
242
|
+
- Unified `FastLSQSolver` with optional normalization parameter
|
|
243
|
+
- Removed code duplication (Bratu, NL-Helmholtz regression inherit from nonlinear versions)
|
|
244
|
+
- Removed non-scientific content (emojis, casual language)
|
|
245
|
+
|
|
246
|
+
### Fixed
|
|
247
|
+
|
|
248
|
+
- Fixed missing `solve_lstsq` import in linear solver (was only defined in nonlinear file)
|
|
249
|
+
- Improved error messages and diagnostics
|
|
@@ -1,25 +1,26 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: FastLSQ
|
|
3
|
-
Version: 0.
|
|
4
|
-
Summary:
|
|
3
|
+
Version: 0.2.2
|
|
4
|
+
Summary: One-shot PDE solving via Fourier features with exact analytical derivatives; rank-revealing solvers, learnable anisotropic bandwidth, and CPU/CUDA/MPS support
|
|
5
5
|
Author: Antonin Sulc
|
|
6
6
|
License-Expression: MIT
|
|
7
|
-
Project-URL: Homepage, https://github.com/
|
|
8
|
-
Project-URL: Repository, https://github.com/
|
|
7
|
+
Project-URL: Homepage, https://github.com/sulcantonin/FastLSQ
|
|
8
|
+
Project-URL: Repository, https://github.com/sulcantonin/FastLSQ
|
|
9
9
|
Project-URL: Paper, https://arxiv.org/abs/2602.10541
|
|
10
|
-
Project-URL: Bug Tracker, https://github.com/
|
|
11
|
-
Project-URL: Changelog, https://github.com/
|
|
10
|
+
Project-URL: Bug Tracker, https://github.com/sulcantonin/FastLSQ/issues
|
|
11
|
+
Project-URL: Changelog, https://github.com/sulcantonin/FastLSQ/blob/main/CHANGELOG.md
|
|
12
12
|
Keywords: pde,partial-differential-equations,fourier-features,least-squares,scientific-computing,neural-network,physics-informed,newton-raphson
|
|
13
13
|
Classifier: Development Status :: 4 - Beta
|
|
14
14
|
Classifier: Intended Audience :: Science/Research
|
|
15
15
|
Classifier: Operating System :: OS Independent
|
|
16
16
|
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
18
|
Classifier: Programming Language :: Python :: 3.10
|
|
18
19
|
Classifier: Programming Language :: Python :: 3.11
|
|
19
20
|
Classifier: Programming Language :: Python :: 3.12
|
|
20
21
|
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
21
22
|
Classifier: Topic :: Scientific/Engineering :: Physics
|
|
22
|
-
Requires-Python: >=3.
|
|
23
|
+
Requires-Python: >=3.9
|
|
23
24
|
Description-Content-Type: text/markdown
|
|
24
25
|
License-File: LICENSE
|
|
25
26
|
Requires-Dist: torch>=2.0
|
|
@@ -44,7 +45,7 @@ Dynamic: license-file
|
|
|
44
45
|
|
|
45
46
|
|
|
46
47
|
<p align="center">
|
|
47
|
-
<img src="misc/fastlsq_teaser.png" alt="FastLSQ method overview" width="400"/>
|
|
48
|
+
<img src="https://raw.githubusercontent.com/sulcantonin/FastLSQ/main/misc/fastlsq_teaser.png" alt="FastLSQ method overview" width="400"/>
|
|
48
49
|
</p>
|
|
49
50
|
|
|
50
51
|
**Solving PDEs in one shot via Fourier features with exact analytical derivatives.**
|
|
@@ -234,8 +235,8 @@ python examples/learnable_helmholtz.py
|
|
|
234
235
|
The analytical derivatives enable gradients through the pre-factored solve, making inverse problems tractable. Example: recovering 4 anisotropic Gaussian heat sources (24 parameters) from 4 sparse sensors. The heat equation is solved in space-time; L-BFGS-B optimises source positions and shapes to match sensor time-series. *(Click image for animation.)*
|
|
235
236
|
|
|
236
237
|
<p align="center">
|
|
237
|
-
<a href="misc/inverse_heat_source.gif">
|
|
238
|
-
<img src="misc/inverse_heat_source.png" alt="Inverse heat source localisation" width="700"/>
|
|
238
|
+
<a href="https://raw.githubusercontent.com/sulcantonin/FastLSQ/main/misc/inverse_heat_source.gif">
|
|
239
|
+
<img src="https://raw.githubusercontent.com/sulcantonin/FastLSQ/main/misc/inverse_heat_source.png" alt="Inverse heat source localisation" width="700"/>
|
|
239
240
|
</a>
|
|
240
241
|
</p>
|
|
241
242
|
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
CHANGELOG.md
|
|
2
|
+
LICENSE
|
|
3
|
+
MANIFEST.in
|
|
4
|
+
README.md
|
|
5
|
+
pyproject.toml
|
|
6
|
+
requirements.txt
|
|
7
|
+
FastLSQ.egg-info/PKG-INFO
|
|
8
|
+
FastLSQ.egg-info/SOURCES.txt
|
|
9
|
+
FastLSQ.egg-info/dependency_links.txt
|
|
10
|
+
FastLSQ.egg-info/requires.txt
|
|
11
|
+
FastLSQ.egg-info/top_level.txt
|
|
12
|
+
examples/add_your_own_pde.py
|
|
13
|
+
examples/benchmark_comparison.py
|
|
14
|
+
examples/custom_features.py
|
|
15
|
+
examples/grad_shafranov.py
|
|
16
|
+
examples/grid_inverse.py
|
|
17
|
+
examples/grid_rl_control.py
|
|
18
|
+
examples/grid_swing.py
|
|
19
|
+
examples/gs_inverse.py
|
|
20
|
+
examples/gs_rl_control.py
|
|
21
|
+
examples/inverse_heat_source.py
|
|
22
|
+
examples/inverse_magnetostatics.py
|
|
23
|
+
examples/inverse_source_position.py
|
|
24
|
+
examples/learnable_helmholtz.py
|
|
25
|
+
examples/orbit_hill.py
|
|
26
|
+
examples/orbit_inverse.py
|
|
27
|
+
examples/orbit_rl.py
|
|
28
|
+
examples/pde_discovery.py
|
|
29
|
+
examples/run_all_extensions.py
|
|
30
|
+
examples/run_linear.py
|
|
31
|
+
examples/run_nonlinear.py
|
|
32
|
+
examples/tutorial_basic.py
|
|
33
|
+
examples/tutorial_nonlinear.py
|
|
34
|
+
examples/vector_basis_stream_vorticity.py
|
|
35
|
+
examples/extras/fred_sde.py
|
|
36
|
+
examples/extras/fred_sde_fastlsq.py
|
|
37
|
+
examples/extras/gaia_potential.py
|
|
38
|
+
examples/extras/gaia_potential_fastlsq.py
|
|
39
|
+
examples/extras/horizons_ephemeris.py
|
|
40
|
+
examples/extras/numerai_alpha.py
|
|
41
|
+
examples/extras/numerai_alpha_fastlsq.py
|
|
42
|
+
examples/extras/run_all_fastlsq.py
|
|
43
|
+
examples/extras/spectral_expansion.py
|
|
44
|
+
examples/extras/scenarios/__init__.py
|
|
45
|
+
examples/extras/scenarios/_alsu_lattice.py
|
|
46
|
+
examples/extras/scenarios/_common.py
|
|
47
|
+
examples/extras/scenarios/run_all.py
|
|
48
|
+
examples/extras/scenarios/s01_beamloss_ode.py
|
|
49
|
+
examples/extras/scenarios/s01_betatron_tune.py
|
|
50
|
+
examples/extras/scenarios/s01_green_fff.py
|
|
51
|
+
examples/extras/scenarios/s01_hill_ivp.py
|
|
52
|
+
examples/extras/scenarios/s01_observe_fit_act_simulator.py
|
|
53
|
+
examples/extras/scenarios/s01_orbit_inverse.py
|
|
54
|
+
examples/extras/scenarios/s01_passive_loco.py
|
|
55
|
+
examples/extras/scenarios/s01_perturbed_hill.py
|
|
56
|
+
examples/extras/scenarios/s01_sofb_observe_fit_act.py
|
|
57
|
+
examples/extras/scenarios/s01_streaming_archive_growth.py
|
|
58
|
+
examples/extras/scenarios/s01_synchrotron_ode.py
|
|
59
|
+
examples/extras/scenarios/s01_tides_3months.py
|
|
60
|
+
examples/extras/scenarios/s01_topoff_impulse.py
|
|
61
|
+
examples/extras/scenarios/s01_visualize.py
|
|
62
|
+
examples/extras/scenarios/s02_plasma_wakefield.py
|
|
63
|
+
examples/extras/scenarios/s03_synchrobetatron.py
|
|
64
|
+
examples/extras/scenarios/s04_sunspots.py
|
|
65
|
+
examples/extras/scenarios/s05_helioseismology.py
|
|
66
|
+
examples/extras/scenarios/s06_tides.py
|
|
67
|
+
examples/extras/scenarios/s07_iers_earth_rotation.py
|
|
68
|
+
examples/extras/scenarios/s08_mauna_loa_co2.py
|
|
69
|
+
examples/extras/scenarios/s09_enso_qbo.py
|
|
70
|
+
examples/extras/scenarios/s10_pulsar_timing.py
|
|
71
|
+
examples/extras/scenarios/s11_modal_analysis.py
|
|
72
|
+
examples/extras/scenarios/s12_mems_resonator.py
|
|
73
|
+
examples/extras/scenarios/s13_variable_stars_kepler.py
|
|
74
|
+
examples/extras/scenarios/s14_eeg.py
|
|
75
|
+
examples/extras/scenarios/s15_circadian.py
|
|
76
|
+
fastlsq/__init__.py
|
|
77
|
+
fastlsq/api.py
|
|
78
|
+
fastlsq/basis.py
|
|
79
|
+
fastlsq/block.py
|
|
80
|
+
fastlsq/device.py
|
|
81
|
+
fastlsq/diagnostics.py
|
|
82
|
+
fastlsq/export.py
|
|
83
|
+
fastlsq/geometry.py
|
|
84
|
+
fastlsq/learnable.py
|
|
85
|
+
fastlsq/lightning.py
|
|
86
|
+
fastlsq/linalg.py
|
|
87
|
+
fastlsq/newton.py
|
|
88
|
+
fastlsq/plotting.py
|
|
89
|
+
fastlsq/solvers.py
|
|
90
|
+
fastlsq/tuning.py
|
|
91
|
+
fastlsq/utils.py
|
|
92
|
+
fastlsq/vector.py
|
|
93
|
+
fastlsq/viz.py
|
|
94
|
+
fastlsq/problems/__init__.py
|
|
95
|
+
fastlsq/problems/linear.py
|
|
96
|
+
fastlsq/problems/nonlinear.py
|
|
97
|
+
fastlsq/problems/regression.py
|
|
98
|
+
tests/test_basic.py
|
|
99
|
+
tests/test_block.py
|
|
100
|
+
tests/test_derivatives.py
|
|
101
|
+
tests/test_device.py
|
|
102
|
+
tests/test_grad_shafranov.py
|
|
103
|
+
tests/test_grid_swing.py
|
|
104
|
+
tests/test_learnable.py
|
|
105
|
+
tests/test_orbit_hill.py
|
|
106
|
+
tests/test_vector_basis.py
|
|
@@ -1,25 +1,26 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: FastLSQ
|
|
3
|
-
Version: 0.
|
|
4
|
-
Summary:
|
|
3
|
+
Version: 0.2.2
|
|
4
|
+
Summary: One-shot PDE solving via Fourier features with exact analytical derivatives; rank-revealing solvers, learnable anisotropic bandwidth, and CPU/CUDA/MPS support
|
|
5
5
|
Author: Antonin Sulc
|
|
6
6
|
License-Expression: MIT
|
|
7
|
-
Project-URL: Homepage, https://github.com/
|
|
8
|
-
Project-URL: Repository, https://github.com/
|
|
7
|
+
Project-URL: Homepage, https://github.com/sulcantonin/FastLSQ
|
|
8
|
+
Project-URL: Repository, https://github.com/sulcantonin/FastLSQ
|
|
9
9
|
Project-URL: Paper, https://arxiv.org/abs/2602.10541
|
|
10
|
-
Project-URL: Bug Tracker, https://github.com/
|
|
11
|
-
Project-URL: Changelog, https://github.com/
|
|
10
|
+
Project-URL: Bug Tracker, https://github.com/sulcantonin/FastLSQ/issues
|
|
11
|
+
Project-URL: Changelog, https://github.com/sulcantonin/FastLSQ/blob/main/CHANGELOG.md
|
|
12
12
|
Keywords: pde,partial-differential-equations,fourier-features,least-squares,scientific-computing,neural-network,physics-informed,newton-raphson
|
|
13
13
|
Classifier: Development Status :: 4 - Beta
|
|
14
14
|
Classifier: Intended Audience :: Science/Research
|
|
15
15
|
Classifier: Operating System :: OS Independent
|
|
16
16
|
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
18
|
Classifier: Programming Language :: Python :: 3.10
|
|
18
19
|
Classifier: Programming Language :: Python :: 3.11
|
|
19
20
|
Classifier: Programming Language :: Python :: 3.12
|
|
20
21
|
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
21
22
|
Classifier: Topic :: Scientific/Engineering :: Physics
|
|
22
|
-
Requires-Python: >=3.
|
|
23
|
+
Requires-Python: >=3.9
|
|
23
24
|
Description-Content-Type: text/markdown
|
|
24
25
|
License-File: LICENSE
|
|
25
26
|
Requires-Dist: torch>=2.0
|
|
@@ -44,7 +45,7 @@ Dynamic: license-file
|
|
|
44
45
|
|
|
45
46
|
|
|
46
47
|
<p align="center">
|
|
47
|
-
<img src="misc/fastlsq_teaser.png" alt="FastLSQ method overview" width="400"/>
|
|
48
|
+
<img src="https://raw.githubusercontent.com/sulcantonin/FastLSQ/main/misc/fastlsq_teaser.png" alt="FastLSQ method overview" width="400"/>
|
|
48
49
|
</p>
|
|
49
50
|
|
|
50
51
|
**Solving PDEs in one shot via Fourier features with exact analytical derivatives.**
|
|
@@ -234,8 +235,8 @@ python examples/learnable_helmholtz.py
|
|
|
234
235
|
The analytical derivatives enable gradients through the pre-factored solve, making inverse problems tractable. Example: recovering 4 anisotropic Gaussian heat sources (24 parameters) from 4 sparse sensors. The heat equation is solved in space-time; L-BFGS-B optimises source positions and shapes to match sensor time-series. *(Click image for animation.)*
|
|
235
236
|
|
|
236
237
|
<p align="center">
|
|
237
|
-
<a href="misc/inverse_heat_source.gif">
|
|
238
|
-
<img src="misc/inverse_heat_source.png" alt="Inverse heat source localisation" width="700"/>
|
|
238
|
+
<a href="https://raw.githubusercontent.com/sulcantonin/FastLSQ/main/misc/inverse_heat_source.gif">
|
|
239
|
+
<img src="https://raw.githubusercontent.com/sulcantonin/FastLSQ/main/misc/inverse_heat_source.png" alt="Inverse heat source localisation" width="700"/>
|
|
239
240
|
</a>
|
|
240
241
|
</p>
|
|
241
242
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
<p align="center">
|
|
7
|
-
<img src="misc/fastlsq_teaser.png" alt="FastLSQ method overview" width="400"/>
|
|
7
|
+
<img src="https://raw.githubusercontent.com/sulcantonin/FastLSQ/main/misc/fastlsq_teaser.png" alt="FastLSQ method overview" width="400"/>
|
|
8
8
|
</p>
|
|
9
9
|
|
|
10
10
|
**Solving PDEs in one shot via Fourier features with exact analytical derivatives.**
|
|
@@ -194,8 +194,8 @@ python examples/learnable_helmholtz.py
|
|
|
194
194
|
The analytical derivatives enable gradients through the pre-factored solve, making inverse problems tractable. Example: recovering 4 anisotropic Gaussian heat sources (24 parameters) from 4 sparse sensors. The heat equation is solved in space-time; L-BFGS-B optimises source positions and shapes to match sensor time-series. *(Click image for animation.)*
|
|
195
195
|
|
|
196
196
|
<p align="center">
|
|
197
|
-
<a href="misc/inverse_heat_source.gif">
|
|
198
|
-
<img src="misc/inverse_heat_source.png" alt="Inverse heat source localisation" width="700"/>
|
|
197
|
+
<a href="https://raw.githubusercontent.com/sulcantonin/FastLSQ/main/misc/inverse_heat_source.gif">
|
|
198
|
+
<img src="https://raw.githubusercontent.com/sulcantonin/FastLSQ/main/misc/inverse_heat_source.png" alt="Inverse heat source localisation" width="700"/>
|
|
199
199
|
</a>
|
|
200
200
|
</p>
|
|
201
201
|
|