FastLSQ 0.2.4__tar.gz → 0.2.6__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.4 → fastlsq-0.2.6}/CHANGELOG.md +37 -4
- {fastlsq-0.2.4 → fastlsq-0.2.6}/FastLSQ.egg-info/PKG-INFO +47 -11
- {fastlsq-0.2.4 → fastlsq-0.2.6}/FastLSQ.egg-info/SOURCES.txt +33 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/PKG-INFO +47 -11
- {fastlsq-0.2.4 → fastlsq-0.2.6}/README.md +46 -10
- fastlsq-0.2.6/examples/digital_twins/darcy_heat.py +583 -0
- fastlsq-0.2.6/examples/digital_twins/pendulum.py +242 -0
- fastlsq-0.2.6/examples/digital_twins/pendulum_benchmark.py +281 -0
- fastlsq-0.2.6/examples/digital_twins/plasma_wakefield.py +339 -0
- fastlsq-0.2.6/examples/digital_twins/plasma_wakefield_2D_1.py +863 -0
- fastlsq-0.2.6/examples/digital_twins/plasma_wakefield_2D_2.py +769 -0
- fastlsq-0.2.6/examples/digital_twins/plasma_wakefield_2d_3.py +818 -0
- fastlsq-0.2.6/examples/digital_twins/plasma_wakefield_parameteric.py +475 -0
- fastlsq-0.2.6/examples/digital_twins/plot_utils.py +42 -0
- fastlsq-0.2.6/examples/digital_twins/structural_health_simple.py +343 -0
- fastlsq-0.2.6/examples/digital_twins/turbulence_gravity_cooling.py +387 -0
- fastlsq-0.2.6/examples/inverse/aero_.py +362 -0
- fastlsq-0.2.6/examples/inverse/denoising_parameter_estimation.py +297 -0
- fastlsq-0.2.6/examples/inverse/elastic_wave_animation.py +300 -0
- fastlsq-0.2.6/examples/inverse/heat_from_video.py +394 -0
- fastlsq-0.2.6/examples/inverse/inverse_turbulence.py +811 -0
- fastlsq-0.2.6/examples/inverse/shape_ns.py +1426 -0
- fastlsq-0.2.6/examples/inverse/subsurface_imaging.py +547 -0
- fastlsq-0.2.6/examples/inverse/wing_optimize_simple.py +283 -0
- fastlsq-0.2.6/examples/sindy/compare_sindy_methods.py +760 -0
- fastlsq-0.2.6/examples/sindy/sindy_benchmarks.py +351 -0
- fastlsq-0.2.6/examples/sindy/sindy_differentiable.py +418 -0
- fastlsq-0.2.6/examples/sindy/sindy_minimal_diff.py +716 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/fastlsq/__init__.py +1 -1
- {fastlsq-0.2.4 → fastlsq-0.2.6}/fastlsq/linalg.py +7 -2
- {fastlsq-0.2.4 → fastlsq-0.2.6}/fastlsq/problems/linear.py +74 -34
- fastlsq-0.2.6/misc/fastlsq_teaser.png +0 -0
- fastlsq-0.2.6/misc/ideal_quadrupole.png +0 -0
- fastlsq-0.2.6/misc/inverse_heat_source.gif +0 -0
- fastlsq-0.2.6/misc/inverse_heat_source.png +0 -0
- fastlsq-0.2.6/misc/inverse_magnetostatics.png +0 -0
- fastlsq-0.2.6/misc/inverse_magnetostatics_convergence.png +0 -0
- fastlsq-0.2.6/misc/quadrupole_convergence.png +0 -0
- fastlsq-0.2.6/misc/quadrupole_optimization.png +0 -0
- fastlsq-0.2.6/misc/tutorial_nlpoisson_convergence.png +0 -0
- fastlsq-0.2.6/misc/tutorial_nlpoisson_solution.png +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/pyproject.toml +1 -1
- {fastlsq-0.2.4 → fastlsq-0.2.6}/tests/test_benchmarks_inverse.py +28 -16
- {fastlsq-0.2.4 → fastlsq-0.2.6}/tests/test_vector_basis.py +1 -1
- {fastlsq-0.2.4 → fastlsq-0.2.6}/FastLSQ.egg-info/dependency_links.txt +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/FastLSQ.egg-info/requires.txt +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/FastLSQ.egg-info/top_level.txt +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/LICENSE +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/MANIFEST.in +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/add_your_own_pde.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/benchmark_comparison.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/custom_features.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/extras/fred_sde.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/extras/fred_sde_fastlsq.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/extras/gaia_potential.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/extras/gaia_potential_fastlsq.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/extras/horizons_ephemeris.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/extras/numerai_alpha.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/extras/numerai_alpha_fastlsq.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/extras/run_all_fastlsq.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/extras/scenarios/__init__.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/extras/scenarios/_alsu_lattice.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/extras/scenarios/_common.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/extras/scenarios/run_all.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/extras/scenarios/s01_beamloss_ode.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/extras/scenarios/s01_betatron_tune.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/extras/scenarios/s01_green_fff.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/extras/scenarios/s01_hill_ivp.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/extras/scenarios/s01_observe_fit_act_simulator.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/extras/scenarios/s01_orbit_inverse.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/extras/scenarios/s01_passive_loco.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/extras/scenarios/s01_perturbed_hill.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/extras/scenarios/s01_sofb_observe_fit_act.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/extras/scenarios/s01_streaming_archive_growth.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/extras/scenarios/s01_synchrotron_ode.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/extras/scenarios/s01_tides_3months.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/extras/scenarios/s01_topoff_impulse.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/extras/scenarios/s01_visualize.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/extras/scenarios/s02_plasma_wakefield.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/extras/scenarios/s03_synchrobetatron.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/extras/scenarios/s04_sunspots.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/extras/scenarios/s05_helioseismology.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/extras/scenarios/s06_tides.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/extras/scenarios/s07_iers_earth_rotation.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/extras/scenarios/s08_mauna_loa_co2.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/extras/scenarios/s09_enso_qbo.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/extras/scenarios/s10_pulsar_timing.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/extras/scenarios/s11_modal_analysis.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/extras/scenarios/s12_mems_resonator.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/extras/scenarios/s13_variable_stars_kepler.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/extras/scenarios/s14_eeg.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/extras/scenarios/s15_circadian.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/extras/spectral_expansion.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/grad_shafranov.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/grid_inverse.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/grid_rl_control.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/grid_swing.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/gs_inverse.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/gs_rl_control.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/inverse_heat_source.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/inverse_magnetostatics.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/inverse_source_position.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/learnable_helmholtz.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/orbit_hill.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/orbit_inverse.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/orbit_rl.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/pde_discovery.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/run_all_extensions.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/run_linear.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/run_nonlinear.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/tutorial_basic.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/tutorial_nonlinear.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/examples/vector_basis_stream_vorticity.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/fastlsq/api.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/fastlsq/basis.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/fastlsq/block.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/fastlsq/device.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/fastlsq/diagnostics.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/fastlsq/export.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/fastlsq/geometry.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/fastlsq/learnable.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/fastlsq/lightning.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/fastlsq/newton.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/fastlsq/plotting.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/fastlsq/problems/__init__.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/fastlsq/problems/nonlinear.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/fastlsq/problems/regression.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/fastlsq/solvers.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/fastlsq/tuning.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/fastlsq/utils.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/fastlsq/vector.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/fastlsq/viz.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/requirements.txt +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/setup.cfg +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/tests/test_basic.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/tests/test_block.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/tests/test_derivatives.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/tests/test_device.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/tests/test_grad_shafranov.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/tests/test_grid_swing.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/tests/test_learnable.py +0 -0
- {fastlsq-0.2.4 → fastlsq-0.2.6}/tests/test_orbit_hill.py +0 -0
|
@@ -2,6 +2,35 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to FastLSQ will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [0.2.5] - 2026-06-04
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- **`Wave2D_MS` solves via `solve_linear`.** The long-time anisotropic wave
|
|
10
|
+
returned relative value error 1.0 in every configuration because its
|
|
11
|
+
`t_max = 100` time normalisation packed ~87 temporal cycles into `tau ∈ [0,1]`:
|
|
12
|
+
the PDE's second time-derivative amplifies the random-feature *representation*
|
|
13
|
+
error by `Omega²` (`Omega = pi·sqrt(1+a2)·t_max`), so the one-shot
|
|
14
|
+
least-squares collocation cannot resolve the oscillation -- even 8000 features
|
|
15
|
+
with near-hard boundary constraints stay at rel-err 1.0, because the best
|
|
16
|
+
representable solution itself carries a huge PDE residual. Reducing `t_max` to
|
|
17
|
+
`4` (~3.5 cycles) and matching the anisotropic temporal feature bandwidth to
|
|
18
|
+
`Omega` (`scale_multipliers = [1, 1, 7]`) recovers the solution to ~3e-4 at
|
|
19
|
+
900 features (`scale = 3`); the exactly-consistent `t_max²`-scaled operator is
|
|
20
|
+
unchanged. Added to the `tests/test_benchmarks_inverse.py` linear smoke test.
|
|
21
|
+
Resolves the `Wave2D_MS` [0.2.4] known issue.
|
|
22
|
+
- **`ElasticWave2D` solves via the block-stacked vector path.** The coupled
|
|
23
|
+
2-output elastic-wave problem now declares `n_outputs = 2`, assembles its
|
|
24
|
+
operator in block-stacked form (`A ∈ ℝ^{Mk×Nk}`, `b ∈ ℝ^{Mk×1}`) via
|
|
25
|
+
`block_concat`, and gains the `exact_grad` Jacobian (shape `(M, d, k)`, time
|
|
26
|
+
axis chain-ruled by `t_max`) that the error metric requires. `unpack_beta` now
|
|
27
|
+
recovers a `(N, 2)` `beta`, so `solve_linear(ElasticWave2D(), scale=5.0)`
|
|
28
|
+
recovers both components (relative value error ~7e-3 at the default
|
|
29
|
+
resolution) instead of failing to unpack the vector solution. Added to the
|
|
30
|
+
`tests/test_benchmarks_inverse.py` linear smoke test. Resolves the
|
|
31
|
+
`ElasticWave2D` [0.2.4] known issue; the `t_max²` operator scaling from
|
|
32
|
+
[0.2.2] (consistent with `Wave2D_MS`) is preserved.
|
|
33
|
+
|
|
5
34
|
## [0.2.4] - 2026-06-04
|
|
6
35
|
|
|
7
36
|
### Added
|
|
@@ -18,10 +47,14 @@ All notable changes to FastLSQ will be documented in this file.
|
|
|
18
47
|
### Known issues
|
|
19
48
|
|
|
20
49
|
- `Wave2D_MS` does not solve via `solve_linear` (relative error 1.0 in every
|
|
21
|
-
configuration tested)
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
50
|
+
configuration tested) -- a pre-existing problem-definition gap, independent of
|
|
51
|
+
the solver work, excluded from the new smoke test pending a fix. *(Fixed in
|
|
52
|
+
[0.2.5]: `t_max` reduced 100 -> 4 so the normalised-time oscillation
|
|
53
|
+
(~3.5 vs ~87 cycles) is resolvable; now covered by the smoke test.)*
|
|
54
|
+
- `ElasticWave2D` -- a 2-output vector problem whose `exact()` returns `(N, 2)`
|
|
55
|
+
-- never sets `n_outputs`, so the scalar API cannot unpack it; also excluded
|
|
56
|
+
here. *(Fixed in [0.2.5]: it now uses the block-stacked vector path and
|
|
57
|
+
is covered by the smoke test.)*
|
|
25
58
|
|
|
26
59
|
## [0.2.3] - 2026-06-04
|
|
27
60
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: FastLSQ
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.6
|
|
4
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
|
|
@@ -55,9 +55,12 @@ analytical derivative engine for random Fourier features. For sinusoidal
|
|
|
55
55
|
features `phi_j(x) = sin(W_j . x + b_j)`, every derivative of every order
|
|
56
56
|
admits an exact closed-form expression -- no automatic differentiation needed.
|
|
57
57
|
|
|
58
|
-
Linear PDEs are solved in a single least-squares step
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
Linear PDEs are solved in a single least-squares step. The random-feature
|
|
59
|
+
system is typically rank-deficient, so the solve is routed through a
|
|
60
|
+
backward-stable, auto-selected least-squares back-end (Cholesky fast-path ->
|
|
61
|
+
Householder QR -> rank-revealing SVD) that runs on CPU, CUDA, or Apple-MPS.
|
|
62
|
+
Nonlinear PDEs are solved via Newton-Raphson iteration with Tikhonov
|
|
63
|
+
regularisation, 1/sqrt(N) feature normalisation, and continuation/homotopy.
|
|
61
64
|
|
|
62
65
|
## Installation
|
|
63
66
|
|
|
@@ -68,7 +71,7 @@ pip install fastlsq
|
|
|
68
71
|
For development (includes testing and build tools):
|
|
69
72
|
|
|
70
73
|
```bash
|
|
71
|
-
git clone https://github.com/
|
|
74
|
+
git clone https://github.com/sulcantonin/FastLSQ.git
|
|
72
75
|
cd FastLSQ
|
|
73
76
|
pip install -e ".[dev]"
|
|
74
77
|
```
|
|
@@ -101,6 +104,26 @@ print(f"Converged in {result['n_iters']} iterations")
|
|
|
101
104
|
print(f"Value error: {result['metrics']['val_err']:.2e}")
|
|
102
105
|
```
|
|
103
106
|
|
|
107
|
+
### Choose a solver back-end and device
|
|
108
|
+
|
|
109
|
+
The linear solve is routed automatically, but `solve_linear` exposes the
|
|
110
|
+
back-end via `method=` (see [How it works](#how-it-works) for the routing):
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
from fastlsq import solve_linear, set_device
|
|
114
|
+
from fastlsq.problems.linear import PoissonND
|
|
115
|
+
|
|
116
|
+
# "auto" (default) -- Cholesky fast-path -> QR -> rank-revealing SVD
|
|
117
|
+
# "qr" -- Householder QR; SVD-grade accuracy at QR cost (full-rank A)
|
|
118
|
+
# "svd" -- rank-revealing truncated SVD; the rank-deficient-safe reference
|
|
119
|
+
# "cholesky" -- normal-equations Cholesky; fast, well-conditioned A only
|
|
120
|
+
# "rsvd" -- randomized SVD, O(MNk), for strongly low-rank A
|
|
121
|
+
result = solve_linear(PoissonND(), scale=5.0, method="qr")
|
|
122
|
+
|
|
123
|
+
# Device selection (CPU / CUDA / Apple-MPS), or set FASTLSQ_DEVICE=cuda
|
|
124
|
+
set_device("cuda") # the float64 default stays on CPU/CUDA; MPS is float32-only
|
|
125
|
+
```
|
|
126
|
+
|
|
104
127
|
### Use the basis directly
|
|
105
128
|
|
|
106
129
|
```python
|
|
@@ -204,9 +227,10 @@ u_yy = A @ solver.beta # (M, k): ∂²u/∂y² per com
|
|
|
204
227
|
|
|
205
228
|
Scalar problems are untouched: `n_outputs` defaults to `1`, `solver.beta` keeps
|
|
206
229
|
shape `(N, 1)`, and `predict_with_grad` returns gradient shape `(M, d)` for
|
|
207
|
-
backward compatibility (the trailing component axis is squeezed when k=1).
|
|
208
|
-
`
|
|
209
|
-
|
|
230
|
+
backward compatibility (the trailing component axis is squeezed when k=1). The
|
|
231
|
+
`Stokes2D` sketch above and [tests/test_block.py](tests/test_block.py) -- a
|
|
232
|
+
runnable `block_concat` + `unpack_beta` solve that recovers both components of a
|
|
233
|
+
k=2 system -- are the reference for the block-stacked vector path.
|
|
210
234
|
|
|
211
235
|
### Plot solutions
|
|
212
236
|
|
|
@@ -258,11 +282,15 @@ derivative engine:
|
|
|
258
282
|
| `FastLSQSolver` | Manages feature blocks; exposes `.basis` for all derivative computations |
|
|
259
283
|
| `LearnableFastLSQ` | Differentiable solver with learnable bandwidth via reparameterisation trick |
|
|
260
284
|
| `block_concat`, `pack_beta`, `unpack_beta` | Block-structured assembly helpers for vector-valued **u** (coupled systems). `solver.beta` has shape `(N, k)`; scalar problems are the k=1 case |
|
|
285
|
+
| `solve_lstsq` | Multi-back-end least-squares solve (`auto`/`qr`/`svd`/`cholesky`/`rsvd`); rank-revealing by default for the rank-deficient feature matrix |
|
|
286
|
+
| `resolve_device` / `set_device` / `get_device` | CPU / CUDA / Apple-MPS selection, dtype-aware (MPS is float32-only; factorizations fall back to CPU) |
|
|
261
287
|
|
|
262
288
|
### How it works
|
|
263
289
|
|
|
264
290
|
1. **Basis construction.** Given collocation points **x**, construct a
|
|
265
|
-
`SinusoidalBasis` with random weights W and biases b.
|
|
291
|
+
`SinusoidalBasis` with random weights W and biases b. The collocation counts
|
|
292
|
+
default to scale with the feature count
|
|
293
|
+
(`n_pde = max(3000, 3 * n_blocks * hidden_size)`, `n_bc = max(800, n_pde // 5)`).
|
|
266
294
|
|
|
267
295
|
2. **Analytical derivatives.** Exploit the cyclic derivative identity:
|
|
268
296
|
the n-th derivative of sin(z) cycles through {sin, cos, -sin, -cos}
|
|
@@ -273,8 +301,13 @@ derivative engine:
|
|
|
273
301
|
(e.g. `Op.laplacian(d=2)`) and apply it to the basis to get the system
|
|
274
302
|
matrix `A`.
|
|
275
303
|
|
|
276
|
-
4. **Linear solve.** Solve `A beta = b`
|
|
277
|
-
|
|
304
|
+
4. **Linear solve.** Solve `A beta = b` in the least-squares sense. The
|
|
305
|
+
random-feature matrix `A` is typically rank-deficient (near-duplicate
|
|
306
|
+
columns), so the default `method="auto"` starts from a Cholesky fast-path
|
|
307
|
+
(guarded by a cheap conditioning probe), falls back to backward-stable
|
|
308
|
+
Householder **QR**, and resorts to a rank-revealing **SVD** only if the QR
|
|
309
|
+
solution blows up. A Tikhonov ridge `mu` enters via the `[A; sqrt(mu) I]`
|
|
310
|
+
augmentation, not the condition-squaring normal equations.
|
|
278
311
|
|
|
279
312
|
5. **Newton iteration (nonlinear).** Linearise the PDE residual, solve
|
|
280
313
|
`J delta_beta = -R` with backtracking line search, and repeat.
|
|
@@ -336,9 +369,12 @@ See `examples/add_your_own_pde.py` for the complete tutorial.
|
|
|
336
369
|
- **Symbolic PDE operators**: Compose differential operators with `Op` (Laplacian, wave, Helmholtz, biharmonic, custom) via intuitive arithmetic; coefficients can be `nn.Parameter` for AdamW optimisation
|
|
337
370
|
- **Vector-valued solutions**: First-class support for **u**: ℝᵈ → ℝᵏ (elasticity, Stokes, Maxwell). Problems declare `n_outputs = k`; `block_concat` assembles coupled block systems; `solver.predict(x)` returns shape `(M, k)`. Scalar problems are the `k=1` case
|
|
338
371
|
- **High-level API**: Solve PDEs in one line with `solve_linear()` and `solve_nonlinear()`
|
|
372
|
+
- **Robust linear solver**: Pluggable least-squares back-ends; the default `auto` routes Cholesky -> QR -> SVD, and backward-stable QR delivers SVD-grade accuracy at QR cost on the rank-deficient random-feature system
|
|
339
373
|
- **Learnable bandwidth**: `LearnableFastLSQ` optimises the bandwidth (scalar or anisotropic) via reparameterisation
|
|
340
374
|
- **Learnable PDE coefficients**: Plug `nn.Parameter` into `Op` (e.g. Helmholtz wavenumber `k`) and optimise via AdamW; gradients flow through the prebuilt linear solve
|
|
341
375
|
- **Auto-tuning**: Automatic scale selection via grid search
|
|
376
|
+
- **Device support**: CPU / CUDA / Apple-MPS via `set_device()` or the `FASTLSQ_DEVICE` env var, dtype-aware (the float64 high-accuracy path stays on CPU/CUDA)
|
|
377
|
+
- **Adaptive collocation**: `n_pde` / `n_bc` default to feature-count-scaled values, overridable per solve
|
|
342
378
|
- **Built-in plotting**: Solution visualization, convergence plots, spectral sensitivity
|
|
343
379
|
- **Geometry samplers**: Box, ball, sphere, interval, custom samplers
|
|
344
380
|
- **Diagnostics**: Problem validation, conditioning checks, error detection
|
|
@@ -32,6 +32,17 @@ examples/run_nonlinear.py
|
|
|
32
32
|
examples/tutorial_basic.py
|
|
33
33
|
examples/tutorial_nonlinear.py
|
|
34
34
|
examples/vector_basis_stream_vorticity.py
|
|
35
|
+
examples/digital_twins/darcy_heat.py
|
|
36
|
+
examples/digital_twins/pendulum.py
|
|
37
|
+
examples/digital_twins/pendulum_benchmark.py
|
|
38
|
+
examples/digital_twins/plasma_wakefield.py
|
|
39
|
+
examples/digital_twins/plasma_wakefield_2D_1.py
|
|
40
|
+
examples/digital_twins/plasma_wakefield_2D_2.py
|
|
41
|
+
examples/digital_twins/plasma_wakefield_2d_3.py
|
|
42
|
+
examples/digital_twins/plasma_wakefield_parameteric.py
|
|
43
|
+
examples/digital_twins/plot_utils.py
|
|
44
|
+
examples/digital_twins/structural_health_simple.py
|
|
45
|
+
examples/digital_twins/turbulence_gravity_cooling.py
|
|
35
46
|
examples/extras/fred_sde.py
|
|
36
47
|
examples/extras/fred_sde_fastlsq.py
|
|
37
48
|
examples/extras/gaia_potential.py
|
|
@@ -73,6 +84,18 @@ examples/extras/scenarios/s12_mems_resonator.py
|
|
|
73
84
|
examples/extras/scenarios/s13_variable_stars_kepler.py
|
|
74
85
|
examples/extras/scenarios/s14_eeg.py
|
|
75
86
|
examples/extras/scenarios/s15_circadian.py
|
|
87
|
+
examples/inverse/aero_.py
|
|
88
|
+
examples/inverse/denoising_parameter_estimation.py
|
|
89
|
+
examples/inverse/elastic_wave_animation.py
|
|
90
|
+
examples/inverse/heat_from_video.py
|
|
91
|
+
examples/inverse/inverse_turbulence.py
|
|
92
|
+
examples/inverse/shape_ns.py
|
|
93
|
+
examples/inverse/subsurface_imaging.py
|
|
94
|
+
examples/inverse/wing_optimize_simple.py
|
|
95
|
+
examples/sindy/compare_sindy_methods.py
|
|
96
|
+
examples/sindy/sindy_benchmarks.py
|
|
97
|
+
examples/sindy/sindy_differentiable.py
|
|
98
|
+
examples/sindy/sindy_minimal_diff.py
|
|
76
99
|
fastlsq/__init__.py
|
|
77
100
|
fastlsq/api.py
|
|
78
101
|
fastlsq/basis.py
|
|
@@ -95,6 +118,16 @@ fastlsq/problems/__init__.py
|
|
|
95
118
|
fastlsq/problems/linear.py
|
|
96
119
|
fastlsq/problems/nonlinear.py
|
|
97
120
|
fastlsq/problems/regression.py
|
|
121
|
+
misc/fastlsq_teaser.png
|
|
122
|
+
misc/ideal_quadrupole.png
|
|
123
|
+
misc/inverse_heat_source.gif
|
|
124
|
+
misc/inverse_heat_source.png
|
|
125
|
+
misc/inverse_magnetostatics.png
|
|
126
|
+
misc/inverse_magnetostatics_convergence.png
|
|
127
|
+
misc/quadrupole_convergence.png
|
|
128
|
+
misc/quadrupole_optimization.png
|
|
129
|
+
misc/tutorial_nlpoisson_convergence.png
|
|
130
|
+
misc/tutorial_nlpoisson_solution.png
|
|
98
131
|
tests/test_basic.py
|
|
99
132
|
tests/test_benchmarks_inverse.py
|
|
100
133
|
tests/test_block.py
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: FastLSQ
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.6
|
|
4
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
|
|
@@ -55,9 +55,12 @@ analytical derivative engine for random Fourier features. For sinusoidal
|
|
|
55
55
|
features `phi_j(x) = sin(W_j . x + b_j)`, every derivative of every order
|
|
56
56
|
admits an exact closed-form expression -- no automatic differentiation needed.
|
|
57
57
|
|
|
58
|
-
Linear PDEs are solved in a single least-squares step
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
Linear PDEs are solved in a single least-squares step. The random-feature
|
|
59
|
+
system is typically rank-deficient, so the solve is routed through a
|
|
60
|
+
backward-stable, auto-selected least-squares back-end (Cholesky fast-path ->
|
|
61
|
+
Householder QR -> rank-revealing SVD) that runs on CPU, CUDA, or Apple-MPS.
|
|
62
|
+
Nonlinear PDEs are solved via Newton-Raphson iteration with Tikhonov
|
|
63
|
+
regularisation, 1/sqrt(N) feature normalisation, and continuation/homotopy.
|
|
61
64
|
|
|
62
65
|
## Installation
|
|
63
66
|
|
|
@@ -68,7 +71,7 @@ pip install fastlsq
|
|
|
68
71
|
For development (includes testing and build tools):
|
|
69
72
|
|
|
70
73
|
```bash
|
|
71
|
-
git clone https://github.com/
|
|
74
|
+
git clone https://github.com/sulcantonin/FastLSQ.git
|
|
72
75
|
cd FastLSQ
|
|
73
76
|
pip install -e ".[dev]"
|
|
74
77
|
```
|
|
@@ -101,6 +104,26 @@ print(f"Converged in {result['n_iters']} iterations")
|
|
|
101
104
|
print(f"Value error: {result['metrics']['val_err']:.2e}")
|
|
102
105
|
```
|
|
103
106
|
|
|
107
|
+
### Choose a solver back-end and device
|
|
108
|
+
|
|
109
|
+
The linear solve is routed automatically, but `solve_linear` exposes the
|
|
110
|
+
back-end via `method=` (see [How it works](#how-it-works) for the routing):
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
from fastlsq import solve_linear, set_device
|
|
114
|
+
from fastlsq.problems.linear import PoissonND
|
|
115
|
+
|
|
116
|
+
# "auto" (default) -- Cholesky fast-path -> QR -> rank-revealing SVD
|
|
117
|
+
# "qr" -- Householder QR; SVD-grade accuracy at QR cost (full-rank A)
|
|
118
|
+
# "svd" -- rank-revealing truncated SVD; the rank-deficient-safe reference
|
|
119
|
+
# "cholesky" -- normal-equations Cholesky; fast, well-conditioned A only
|
|
120
|
+
# "rsvd" -- randomized SVD, O(MNk), for strongly low-rank A
|
|
121
|
+
result = solve_linear(PoissonND(), scale=5.0, method="qr")
|
|
122
|
+
|
|
123
|
+
# Device selection (CPU / CUDA / Apple-MPS), or set FASTLSQ_DEVICE=cuda
|
|
124
|
+
set_device("cuda") # the float64 default stays on CPU/CUDA; MPS is float32-only
|
|
125
|
+
```
|
|
126
|
+
|
|
104
127
|
### Use the basis directly
|
|
105
128
|
|
|
106
129
|
```python
|
|
@@ -204,9 +227,10 @@ u_yy = A @ solver.beta # (M, k): ∂²u/∂y² per com
|
|
|
204
227
|
|
|
205
228
|
Scalar problems are untouched: `n_outputs` defaults to `1`, `solver.beta` keeps
|
|
206
229
|
shape `(N, 1)`, and `predict_with_grad` returns gradient shape `(M, d)` for
|
|
207
|
-
backward compatibility (the trailing component axis is squeezed when k=1).
|
|
208
|
-
`
|
|
209
|
-
|
|
230
|
+
backward compatibility (the trailing component axis is squeezed when k=1). The
|
|
231
|
+
`Stokes2D` sketch above and [tests/test_block.py](tests/test_block.py) -- a
|
|
232
|
+
runnable `block_concat` + `unpack_beta` solve that recovers both components of a
|
|
233
|
+
k=2 system -- are the reference for the block-stacked vector path.
|
|
210
234
|
|
|
211
235
|
### Plot solutions
|
|
212
236
|
|
|
@@ -258,11 +282,15 @@ derivative engine:
|
|
|
258
282
|
| `FastLSQSolver` | Manages feature blocks; exposes `.basis` for all derivative computations |
|
|
259
283
|
| `LearnableFastLSQ` | Differentiable solver with learnable bandwidth via reparameterisation trick |
|
|
260
284
|
| `block_concat`, `pack_beta`, `unpack_beta` | Block-structured assembly helpers for vector-valued **u** (coupled systems). `solver.beta` has shape `(N, k)`; scalar problems are the k=1 case |
|
|
285
|
+
| `solve_lstsq` | Multi-back-end least-squares solve (`auto`/`qr`/`svd`/`cholesky`/`rsvd`); rank-revealing by default for the rank-deficient feature matrix |
|
|
286
|
+
| `resolve_device` / `set_device` / `get_device` | CPU / CUDA / Apple-MPS selection, dtype-aware (MPS is float32-only; factorizations fall back to CPU) |
|
|
261
287
|
|
|
262
288
|
### How it works
|
|
263
289
|
|
|
264
290
|
1. **Basis construction.** Given collocation points **x**, construct a
|
|
265
|
-
`SinusoidalBasis` with random weights W and biases b.
|
|
291
|
+
`SinusoidalBasis` with random weights W and biases b. The collocation counts
|
|
292
|
+
default to scale with the feature count
|
|
293
|
+
(`n_pde = max(3000, 3 * n_blocks * hidden_size)`, `n_bc = max(800, n_pde // 5)`).
|
|
266
294
|
|
|
267
295
|
2. **Analytical derivatives.** Exploit the cyclic derivative identity:
|
|
268
296
|
the n-th derivative of sin(z) cycles through {sin, cos, -sin, -cos}
|
|
@@ -273,8 +301,13 @@ derivative engine:
|
|
|
273
301
|
(e.g. `Op.laplacian(d=2)`) and apply it to the basis to get the system
|
|
274
302
|
matrix `A`.
|
|
275
303
|
|
|
276
|
-
4. **Linear solve.** Solve `A beta = b`
|
|
277
|
-
|
|
304
|
+
4. **Linear solve.** Solve `A beta = b` in the least-squares sense. The
|
|
305
|
+
random-feature matrix `A` is typically rank-deficient (near-duplicate
|
|
306
|
+
columns), so the default `method="auto"` starts from a Cholesky fast-path
|
|
307
|
+
(guarded by a cheap conditioning probe), falls back to backward-stable
|
|
308
|
+
Householder **QR**, and resorts to a rank-revealing **SVD** only if the QR
|
|
309
|
+
solution blows up. A Tikhonov ridge `mu` enters via the `[A; sqrt(mu) I]`
|
|
310
|
+
augmentation, not the condition-squaring normal equations.
|
|
278
311
|
|
|
279
312
|
5. **Newton iteration (nonlinear).** Linearise the PDE residual, solve
|
|
280
313
|
`J delta_beta = -R` with backtracking line search, and repeat.
|
|
@@ -336,9 +369,12 @@ See `examples/add_your_own_pde.py` for the complete tutorial.
|
|
|
336
369
|
- **Symbolic PDE operators**: Compose differential operators with `Op` (Laplacian, wave, Helmholtz, biharmonic, custom) via intuitive arithmetic; coefficients can be `nn.Parameter` for AdamW optimisation
|
|
337
370
|
- **Vector-valued solutions**: First-class support for **u**: ℝᵈ → ℝᵏ (elasticity, Stokes, Maxwell). Problems declare `n_outputs = k`; `block_concat` assembles coupled block systems; `solver.predict(x)` returns shape `(M, k)`. Scalar problems are the `k=1` case
|
|
338
371
|
- **High-level API**: Solve PDEs in one line with `solve_linear()` and `solve_nonlinear()`
|
|
372
|
+
- **Robust linear solver**: Pluggable least-squares back-ends; the default `auto` routes Cholesky -> QR -> SVD, and backward-stable QR delivers SVD-grade accuracy at QR cost on the rank-deficient random-feature system
|
|
339
373
|
- **Learnable bandwidth**: `LearnableFastLSQ` optimises the bandwidth (scalar or anisotropic) via reparameterisation
|
|
340
374
|
- **Learnable PDE coefficients**: Plug `nn.Parameter` into `Op` (e.g. Helmholtz wavenumber `k`) and optimise via AdamW; gradients flow through the prebuilt linear solve
|
|
341
375
|
- **Auto-tuning**: Automatic scale selection via grid search
|
|
376
|
+
- **Device support**: CPU / CUDA / Apple-MPS via `set_device()` or the `FASTLSQ_DEVICE` env var, dtype-aware (the float64 high-accuracy path stays on CPU/CUDA)
|
|
377
|
+
- **Adaptive collocation**: `n_pde` / `n_bc` default to feature-count-scaled values, overridable per solve
|
|
342
378
|
- **Built-in plotting**: Solution visualization, convergence plots, spectral sensitivity
|
|
343
379
|
- **Geometry samplers**: Box, ball, sphere, interval, custom samplers
|
|
344
380
|
- **Diagnostics**: Problem validation, conditioning checks, error detection
|
|
@@ -14,9 +14,12 @@ analytical derivative engine for random Fourier features. For sinusoidal
|
|
|
14
14
|
features `phi_j(x) = sin(W_j . x + b_j)`, every derivative of every order
|
|
15
15
|
admits an exact closed-form expression -- no automatic differentiation needed.
|
|
16
16
|
|
|
17
|
-
Linear PDEs are solved in a single least-squares step
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
Linear PDEs are solved in a single least-squares step. The random-feature
|
|
18
|
+
system is typically rank-deficient, so the solve is routed through a
|
|
19
|
+
backward-stable, auto-selected least-squares back-end (Cholesky fast-path ->
|
|
20
|
+
Householder QR -> rank-revealing SVD) that runs on CPU, CUDA, or Apple-MPS.
|
|
21
|
+
Nonlinear PDEs are solved via Newton-Raphson iteration with Tikhonov
|
|
22
|
+
regularisation, 1/sqrt(N) feature normalisation, and continuation/homotopy.
|
|
20
23
|
|
|
21
24
|
## Installation
|
|
22
25
|
|
|
@@ -27,7 +30,7 @@ pip install fastlsq
|
|
|
27
30
|
For development (includes testing and build tools):
|
|
28
31
|
|
|
29
32
|
```bash
|
|
30
|
-
git clone https://github.com/
|
|
33
|
+
git clone https://github.com/sulcantonin/FastLSQ.git
|
|
31
34
|
cd FastLSQ
|
|
32
35
|
pip install -e ".[dev]"
|
|
33
36
|
```
|
|
@@ -60,6 +63,26 @@ print(f"Converged in {result['n_iters']} iterations")
|
|
|
60
63
|
print(f"Value error: {result['metrics']['val_err']:.2e}")
|
|
61
64
|
```
|
|
62
65
|
|
|
66
|
+
### Choose a solver back-end and device
|
|
67
|
+
|
|
68
|
+
The linear solve is routed automatically, but `solve_linear` exposes the
|
|
69
|
+
back-end via `method=` (see [How it works](#how-it-works) for the routing):
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
from fastlsq import solve_linear, set_device
|
|
73
|
+
from fastlsq.problems.linear import PoissonND
|
|
74
|
+
|
|
75
|
+
# "auto" (default) -- Cholesky fast-path -> QR -> rank-revealing SVD
|
|
76
|
+
# "qr" -- Householder QR; SVD-grade accuracy at QR cost (full-rank A)
|
|
77
|
+
# "svd" -- rank-revealing truncated SVD; the rank-deficient-safe reference
|
|
78
|
+
# "cholesky" -- normal-equations Cholesky; fast, well-conditioned A only
|
|
79
|
+
# "rsvd" -- randomized SVD, O(MNk), for strongly low-rank A
|
|
80
|
+
result = solve_linear(PoissonND(), scale=5.0, method="qr")
|
|
81
|
+
|
|
82
|
+
# Device selection (CPU / CUDA / Apple-MPS), or set FASTLSQ_DEVICE=cuda
|
|
83
|
+
set_device("cuda") # the float64 default stays on CPU/CUDA; MPS is float32-only
|
|
84
|
+
```
|
|
85
|
+
|
|
63
86
|
### Use the basis directly
|
|
64
87
|
|
|
65
88
|
```python
|
|
@@ -163,9 +186,10 @@ u_yy = A @ solver.beta # (M, k): ∂²u/∂y² per com
|
|
|
163
186
|
|
|
164
187
|
Scalar problems are untouched: `n_outputs` defaults to `1`, `solver.beta` keeps
|
|
165
188
|
shape `(N, 1)`, and `predict_with_grad` returns gradient shape `(M, d)` for
|
|
166
|
-
backward compatibility (the trailing component axis is squeezed when k=1).
|
|
167
|
-
`
|
|
168
|
-
|
|
189
|
+
backward compatibility (the trailing component axis is squeezed when k=1). The
|
|
190
|
+
`Stokes2D` sketch above and [tests/test_block.py](tests/test_block.py) -- a
|
|
191
|
+
runnable `block_concat` + `unpack_beta` solve that recovers both components of a
|
|
192
|
+
k=2 system -- are the reference for the block-stacked vector path.
|
|
169
193
|
|
|
170
194
|
### Plot solutions
|
|
171
195
|
|
|
@@ -217,11 +241,15 @@ derivative engine:
|
|
|
217
241
|
| `FastLSQSolver` | Manages feature blocks; exposes `.basis` for all derivative computations |
|
|
218
242
|
| `LearnableFastLSQ` | Differentiable solver with learnable bandwidth via reparameterisation trick |
|
|
219
243
|
| `block_concat`, `pack_beta`, `unpack_beta` | Block-structured assembly helpers for vector-valued **u** (coupled systems). `solver.beta` has shape `(N, k)`; scalar problems are the k=1 case |
|
|
244
|
+
| `solve_lstsq` | Multi-back-end least-squares solve (`auto`/`qr`/`svd`/`cholesky`/`rsvd`); rank-revealing by default for the rank-deficient feature matrix |
|
|
245
|
+
| `resolve_device` / `set_device` / `get_device` | CPU / CUDA / Apple-MPS selection, dtype-aware (MPS is float32-only; factorizations fall back to CPU) |
|
|
220
246
|
|
|
221
247
|
### How it works
|
|
222
248
|
|
|
223
249
|
1. **Basis construction.** Given collocation points **x**, construct a
|
|
224
|
-
`SinusoidalBasis` with random weights W and biases b.
|
|
250
|
+
`SinusoidalBasis` with random weights W and biases b. The collocation counts
|
|
251
|
+
default to scale with the feature count
|
|
252
|
+
(`n_pde = max(3000, 3 * n_blocks * hidden_size)`, `n_bc = max(800, n_pde // 5)`).
|
|
225
253
|
|
|
226
254
|
2. **Analytical derivatives.** Exploit the cyclic derivative identity:
|
|
227
255
|
the n-th derivative of sin(z) cycles through {sin, cos, -sin, -cos}
|
|
@@ -232,8 +260,13 @@ derivative engine:
|
|
|
232
260
|
(e.g. `Op.laplacian(d=2)`) and apply it to the basis to get the system
|
|
233
261
|
matrix `A`.
|
|
234
262
|
|
|
235
|
-
4. **Linear solve.** Solve `A beta = b`
|
|
236
|
-
|
|
263
|
+
4. **Linear solve.** Solve `A beta = b` in the least-squares sense. The
|
|
264
|
+
random-feature matrix `A` is typically rank-deficient (near-duplicate
|
|
265
|
+
columns), so the default `method="auto"` starts from a Cholesky fast-path
|
|
266
|
+
(guarded by a cheap conditioning probe), falls back to backward-stable
|
|
267
|
+
Householder **QR**, and resorts to a rank-revealing **SVD** only if the QR
|
|
268
|
+
solution blows up. A Tikhonov ridge `mu` enters via the `[A; sqrt(mu) I]`
|
|
269
|
+
augmentation, not the condition-squaring normal equations.
|
|
237
270
|
|
|
238
271
|
5. **Newton iteration (nonlinear).** Linearise the PDE residual, solve
|
|
239
272
|
`J delta_beta = -R` with backtracking line search, and repeat.
|
|
@@ -295,9 +328,12 @@ See `examples/add_your_own_pde.py` for the complete tutorial.
|
|
|
295
328
|
- **Symbolic PDE operators**: Compose differential operators with `Op` (Laplacian, wave, Helmholtz, biharmonic, custom) via intuitive arithmetic; coefficients can be `nn.Parameter` for AdamW optimisation
|
|
296
329
|
- **Vector-valued solutions**: First-class support for **u**: ℝᵈ → ℝᵏ (elasticity, Stokes, Maxwell). Problems declare `n_outputs = k`; `block_concat` assembles coupled block systems; `solver.predict(x)` returns shape `(M, k)`. Scalar problems are the `k=1` case
|
|
297
330
|
- **High-level API**: Solve PDEs in one line with `solve_linear()` and `solve_nonlinear()`
|
|
331
|
+
- **Robust linear solver**: Pluggable least-squares back-ends; the default `auto` routes Cholesky -> QR -> SVD, and backward-stable QR delivers SVD-grade accuracy at QR cost on the rank-deficient random-feature system
|
|
298
332
|
- **Learnable bandwidth**: `LearnableFastLSQ` optimises the bandwidth (scalar or anisotropic) via reparameterisation
|
|
299
333
|
- **Learnable PDE coefficients**: Plug `nn.Parameter` into `Op` (e.g. Helmholtz wavenumber `k`) and optimise via AdamW; gradients flow through the prebuilt linear solve
|
|
300
334
|
- **Auto-tuning**: Automatic scale selection via grid search
|
|
335
|
+
- **Device support**: CPU / CUDA / Apple-MPS via `set_device()` or the `FASTLSQ_DEVICE` env var, dtype-aware (the float64 high-accuracy path stays on CPU/CUDA)
|
|
336
|
+
- **Adaptive collocation**: `n_pde` / `n_bc` default to feature-count-scaled values, overridable per solve
|
|
301
337
|
- **Built-in plotting**: Solution visualization, convergence plots, spectral sensitivity
|
|
302
338
|
- **Geometry samplers**: Box, ball, sphere, interval, custom samplers
|
|
303
339
|
- **Diagnostics**: Problem validation, conditioning checks, error detection
|