FastLSQ 0.6.0__tar.gz → 0.6.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.6.0 → fastlsq-0.6.2}/CHANGELOG.md +235 -6
- fastlsq-0.6.2/CITATION.cff +53 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/FastLSQ.egg-info/PKG-INFO +65 -14
- {fastlsq-0.6.0 → fastlsq-0.6.2}/FastLSQ.egg-info/SOURCES.txt +5 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/FastLSQ.egg-info/requires.txt +1 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/MANIFEST.in +2 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/PKG-INFO +65 -14
- {fastlsq-0.6.0 → fastlsq-0.6.2}/README.md +62 -12
- fastlsq-0.6.2/examples/stealth_navigation.py +332 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/fastlsq/__init__.py +1 -1
- {fastlsq-0.6.0 → fastlsq-0.6.2}/fastlsq/api.py +5 -1
- {fastlsq-0.6.0 → fastlsq-0.6.2}/fastlsq/augment.py +101 -6
- {fastlsq-0.6.0 → fastlsq-0.6.2}/fastlsq/basis.py +10 -1
- {fastlsq-0.6.0 → fastlsq-0.6.2}/fastlsq/kernels.py +52 -5
- {fastlsq-0.6.0 → fastlsq-0.6.2}/fastlsq/learnable.py +6 -2
- {fastlsq-0.6.0 → fastlsq-0.6.2}/fastlsq/linalg.py +63 -23
- {fastlsq-0.6.0 → fastlsq-0.6.2}/fastlsq/newton.py +29 -6
- fastlsq-0.6.2/fastlsq/py.typed +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/fastlsq/solvers.py +7 -5
- {fastlsq-0.6.0 → fastlsq-0.6.2}/pyproject.toml +6 -3
- {fastlsq-0.6.0 → fastlsq-0.6.2}/requirements.txt +1 -0
- fastlsq-0.6.2/tests/test_closed_forms_property.py +323 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/tests/test_diagnostics_timing.py +4 -1
- fastlsq-0.6.2/tests/test_stealth_navigation.py +51 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/tests/test_symbol.py +7 -2
- {fastlsq-0.6.0 → fastlsq-0.6.2}/tests/test_vector_basis.py +15 -1
- {fastlsq-0.6.0 → fastlsq-0.6.2}/FastLSQ.egg-info/dependency_links.txt +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/FastLSQ.egg-info/top_level.txt +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/LICENSE +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/add_your_own_pde.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/benchmark_comparison.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/custom_features.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/extras/fred_sde.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/extras/fred_sde_fastlsq.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/extras/gaia_potential.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/extras/gaia_potential_fastlsq.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/extras/horizons_ephemeris.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/extras/numerai_alpha.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/extras/numerai_alpha_fastlsq.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/extras/run_all_fastlsq.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/extras/scenarios/__init__.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/extras/scenarios/_alsu_lattice.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/extras/scenarios/_common.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/extras/scenarios/run_all.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/extras/scenarios/s01_beamloss_ode.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/extras/scenarios/s01_betatron_tune.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/extras/scenarios/s01_green_fff.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/extras/scenarios/s01_hill_ivp.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/extras/scenarios/s01_observe_fit_act_simulator.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/extras/scenarios/s01_orbit_inverse.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/extras/scenarios/s01_passive_loco.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/extras/scenarios/s01_perturbed_hill.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/extras/scenarios/s01_sofb_observe_fit_act.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/extras/scenarios/s01_streaming_archive_growth.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/extras/scenarios/s01_synchrotron_ode.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/extras/scenarios/s01_tides_3months.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/extras/scenarios/s01_topoff_impulse.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/extras/scenarios/s01_visualize.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/extras/scenarios/s02_plasma_wakefield.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/extras/scenarios/s03_synchrobetatron.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/extras/scenarios/s04_sunspots.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/extras/scenarios/s05_helioseismology.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/extras/scenarios/s06_tides.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/extras/scenarios/s07_iers_earth_rotation.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/extras/scenarios/s08_mauna_loa_co2.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/extras/scenarios/s09_enso_qbo.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/extras/scenarios/s10_pulsar_timing.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/extras/scenarios/s11_modal_analysis.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/extras/scenarios/s12_mems_resonator.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/extras/scenarios/s13_variable_stars_kepler.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/extras/scenarios/s14_eeg.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/extras/scenarios/s15_circadian.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/extras/spectral_expansion.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/grad_shafranov.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/grid_inverse.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/grid_rl_control.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/grid_swing.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/gs_inverse.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/gs_rl_control.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/integral_equations.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/integro_differential_demo.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/inverse_heat_source.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/inverse_magnetostatics.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/inverse_source_position.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/learnable_helmholtz.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/memory_diffusion.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/orbit_hill.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/orbit_inverse.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/orbit_rl.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/pde_discovery.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/rlc_integro_differential.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/run_all_extensions.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/run_linear.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/run_nonlinear.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/sdf_domains.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/tutorial_basic.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/tutorial_nonlinear.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/examples/vector_basis_stream_vorticity.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/fastlsq/benchmark.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/fastlsq/block.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/fastlsq/device.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/fastlsq/diagnostics.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/fastlsq/export.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/fastlsq/geometry.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/fastlsq/lightning.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/fastlsq/plotting.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/fastlsq/problems/__init__.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/fastlsq/problems/integral.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/fastlsq/problems/linear.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/fastlsq/problems/nonlinear.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/fastlsq/problems/regression.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/fastlsq/tuning.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/fastlsq/utils.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/fastlsq/vector.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/fastlsq/viz.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/setup.cfg +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/tests/test_augment.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/tests/test_basic.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/tests/test_benchmarks_inverse.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/tests/test_block.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/tests/test_derivatives.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/tests/test_device.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/tests/test_geometry_sdf.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/tests/test_grad_shafranov.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/tests/test_grid_swing.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/tests/test_integral.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/tests/test_kernels.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/tests/test_learnable.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/tests/test_multi_integral.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/tests/test_orbit_hill.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/tests/test_problems_integral.py +0 -0
- {fastlsq-0.6.0 → fastlsq-0.6.2}/tests/test_projection.py +0 -0
|
@@ -2,6 +2,231 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to FastLSQ will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## Release tags
|
|
6
|
+
|
|
7
|
+
Every released version is tagged `vMAJOR.MINOR.PATCH`. The tags for 0.1.0 through
|
|
8
|
+
0.6.0 were **reconstructed in September 2026**: the project was published to PyPI for
|
|
9
|
+
its first year with only one tag (`v0.2.2`) ever created by hand.
|
|
10
|
+
|
|
11
|
+
Each tag was placed by comparing the `fastlsq/*.py` sources at every commit in the
|
|
12
|
+
repository against the sdist actually published to PyPI, not by guessing from dates.
|
|
13
|
+
Fourteen of the seventeen published releases matched a commit byte for byte. The one
|
|
14
|
+
pre-existing tag, `v0.2.2`, was left untouched and independently resolved to the same
|
|
15
|
+
commit the reconstruction chose, which is the main evidence that the method is sound.
|
|
16
|
+
|
|
17
|
+
Three tags are **approximate**, and their tag messages say so:
|
|
18
|
+
|
|
19
|
+
| Version | What is wrong | Authoritative artefact |
|
|
20
|
+
|---|---|---|
|
|
21
|
+
| 0.1.2 | The published sdist contains `fastlsq/problems/apebench.py`, which exists in no commit in this repository | `fastlsq-0.1.2.tar.gz` on PyPI |
|
|
22
|
+
| 0.1.3 | Same file, same problem | `fastlsq-0.1.3.tar.gz` on PyPI |
|
|
23
|
+
| 0.1.5 | The published `fastlsq/problems/linear.py` is ahead of every committed version of that file | `fastlsq-0.1.5.tar.gz` on PyPI |
|
|
24
|
+
|
|
25
|
+
All three were released from a working tree holding source that was never committed.
|
|
26
|
+
For those versions the sdist on PyPI is the record, not the tag.
|
|
27
|
+
|
|
28
|
+
### Zenodo archives
|
|
29
|
+
|
|
30
|
+
Every tag is archived on Zenodo under concept DOI
|
|
31
|
+
[10.5281/zenodo.22830737](https://doi.org/10.5281/zenodo.22830737).
|
|
32
|
+
|
|
33
|
+
Two things about that archive are worth knowing, because neither is obvious:
|
|
34
|
+
|
|
35
|
+
- **Zenodo reads `.zenodo.json` from the tagged commit's tree, not from `main`.**
|
|
36
|
+
No tag before 0.6.2 contained the file, so every archived version up to and
|
|
37
|
+
including 0.6.1 carries GitHub's auto-generated metadata -- the title
|
|
38
|
+
`sulcantonin/FastLSQ: FastLSQ <version>`, no ORCID, no affiliation, no keywords
|
|
39
|
+
and no link to the preprint.
|
|
40
|
+
- **Zenodo's "latest version" is the one published last, not the highest version
|
|
41
|
+
number.** The twenty releases were archived in parallel and finished out of
|
|
42
|
+
order, so the concept DOI resolved to 0.2.6 for a while. Cutting a new release is
|
|
43
|
+
what corrects it.
|
|
44
|
+
|
|
45
|
+
### Versions documented here that were never released
|
|
46
|
+
|
|
47
|
+
- **0.2.0** (dated 2026-03-01 below) was never on PyPI and `pyproject.toml` never
|
|
48
|
+
declared it. The published sequence runs 0.1.4 → 0.1.5 → 0.2.1. There is no `v0.2.0`
|
|
49
|
+
tag. The entry is kept for the history of the work, not as a release.
|
|
50
|
+
- **0.4.3** and **0.5.0** are real code milestones on `main` -- `pyproject.toml`
|
|
51
|
+
declares each -- but neither was uploaded. The published sequence runs 0.4.2
|
|
52
|
+
(2026-07-20) straight to 0.6.0 (2026-07-21). Both are tagged, and both tags say
|
|
53
|
+
`NEVER PUBLISHED TO PyPI`.
|
|
54
|
+
|
|
55
|
+
### Releases missing from this file
|
|
56
|
+
|
|
57
|
+
**0.1.1, 0.1.2, 0.1.3 and 0.1.4 were published to PyPI but have no entry below.**
|
|
58
|
+
They are tagged, and their scope can be read from the tags and the commit history, but
|
|
59
|
+
this file jumps 0.1.0 → 0.2.0 → 0.1.5 and does not describe them. Reconstructing four
|
|
60
|
+
changelog entries a year after the fact would be invention rather than record, so the
|
|
61
|
+
gap is documented here instead of filled in.
|
|
62
|
+
|
|
63
|
+
## [0.6.2] - 2026-09-18
|
|
64
|
+
|
|
65
|
+
Packaging, citation and repository metadata. **No change to `fastlsq/`** -- the
|
|
66
|
+
importable library is byte-identical to 0.6.1, and the wheel is unchanged. The
|
|
67
|
+
sdist gains one example and its test.
|
|
68
|
+
|
|
69
|
+
### Added
|
|
70
|
+
|
|
71
|
+
- **`examples/stealth_navigation.py`** -- a FastLSQ world model refit inside a
|
|
72
|
+
control loop. A drone crosses a radar interference field sensing only a
|
|
73
|
+
five-point cross at its own position; every three steps it refits a surrogate
|
|
74
|
+
over everything sensed so far (one Tikhonov least-squares solve, 6.1 ms median)
|
|
75
|
+
and steers on that surrogate's *analytic* gradient. The ablation is the
|
|
76
|
+
argument: with the gradient term off, driving straight at the goal trips the
|
|
77
|
+
detector at step 133 of an otherwise 275-step crossing.
|
|
78
|
+
|
|
79
|
+
`tests/test_stealth_navigation.py` checks the analytic gradient against finite
|
|
80
|
+
differences and asserts the ablation in both directions.
|
|
81
|
+
|
|
82
|
+
The project website quoted figures for this demo, but no script in the
|
|
83
|
+
repository produced them. Now the numbers are output rather than assertion.
|
|
84
|
+
|
|
85
|
+
- **Citation and archive metadata.** `CITATION.cff` drives GitHub's *Cite this
|
|
86
|
+
repository* widget, with `preferred-citation` pointing at the paper.
|
|
87
|
+
`.zenodo.json` describes the Zenodo deposit -- title, abstract, ORCID,
|
|
88
|
+
affiliation, keywords, and related identifiers for the preprint, the repository
|
|
89
|
+
and PyPI.
|
|
90
|
+
|
|
91
|
+
Zenodo reads `.zenodo.json` from the **tagged commit's tree**, and no earlier tag
|
|
92
|
+
contained it, so every archived version up to 0.6.1 carries GitHub's
|
|
93
|
+
auto-generated metadata instead. This is the first tag that fixes that.
|
|
94
|
+
|
|
95
|
+
- **`scripts/add_zenodo_doi.py`** writes a Zenodo concept DOI into `README.md`,
|
|
96
|
+
`CITATION.cff` and `.zenodo.json` consistently; idempotent, with a `--check` mode.
|
|
97
|
+
- **`scripts/sync_release_notes.py`** flattens Markdown tables in GitHub Release
|
|
98
|
+
bodies. Zenodo turns a release body into the archived record's description and
|
|
99
|
+
its converter does not understand tables, so a table arrives as one unreadable
|
|
100
|
+
run of pipes -- the first thing anyone following the DOI sees. `CHANGELOG.md`
|
|
101
|
+
keeps its tables, which GitHub renders correctly.
|
|
102
|
+
- **`docs/RELEASING.md`** -- the release procedure, the Zenodo behaviour worth
|
|
103
|
+
knowing in advance, and when JOSS actually requires a DOI (at acceptance, not at
|
|
104
|
+
submission).
|
|
105
|
+
|
|
106
|
+
### Changed
|
|
107
|
+
|
|
108
|
+
- The Zenodo concept DOI [10.5281/zenodo.22830737](https://doi.org/10.5281/zenodo.22830737)
|
|
109
|
+
is recorded in the README badge and citation section, and in `CITATION.cff`.
|
|
110
|
+
- `pyproject.toml` `Homepage` is now <https://fastlsq.com>; `Repository` still
|
|
111
|
+
points at GitHub, so PyPI shows both. The 0.6.1 upload predated this and shows
|
|
112
|
+
the repository as its homepage.
|
|
113
|
+
- The 0.6.0 feature table's third column is headed "Benefit".
|
|
114
|
+
|
|
115
|
+
### Removed
|
|
116
|
+
|
|
117
|
+
- **The website.** `site/` and its GitHub Pages workflow are gone: this repository
|
|
118
|
+
is the Python package, and the site is maintained separately at
|
|
119
|
+
<https://fastlsq.com>. The old copy remains recoverable from history
|
|
120
|
+
(`git checkout 8392f6e -- site/`).
|
|
121
|
+
|
|
122
|
+
## [0.6.1] - 2026-09-18
|
|
123
|
+
|
|
124
|
+
A correctness and packaging pass. No published number changes, and no API is
|
|
125
|
+
removed -- but three of the fixes below were silent wrong answers, not errors.
|
|
126
|
+
|
|
127
|
+
### Fixed -- silent wrong answers
|
|
128
|
+
|
|
129
|
+
- **kernels** -- `SeparableKernelOperator.inner_products` keyed its cache on
|
|
130
|
+
`(id(basis), n_features)`. A freed basis' address is reused by the next one, and
|
|
131
|
+
`LearnableFastLSQ.basis` builds a new basis object on every access, so a learnable fit
|
|
132
|
+
of a Fredholm problem could train on another basis' operators (measured error of the
|
|
133
|
+
assembled block 0.083 on entries of about 0.05, with no warning). The key is now the
|
|
134
|
+
storage pointer and version counter of `W` and `b`, plus a weak reference to the basis.
|
|
135
|
+
- **linalg** -- `method="qr"` on a rank-deficient matrix returned garbage with no
|
|
136
|
+
exception and no warning (`||x|| = 7e18`, residual `6e4`, where `svd` gives `59` and
|
|
137
|
+
`1e-8`). The diagonal of `R` is now tested against `rcond` and warned about.
|
|
138
|
+
- **learnable** -- `driver="gelsd"` was hard-coded, and torch accepts the rank-revealing
|
|
139
|
+
LAPACK drivers on CPU only, so the learnable path could not run off CPU. Now CPU-only.
|
|
140
|
+
|
|
141
|
+
### Fixed -- missing operators
|
|
142
|
+
|
|
143
|
+
- **augment** -- `AugmentedBasis` gained `hessian_diag`, `biharmonic`, `advection` and
|
|
144
|
+
`multi_integral`, with the closed forms for the polynomial columns.
|
|
145
|
+
`MultiIntegralOperator.apply(aug, x)` used to raise `AttributeError`, so the `Wave1D`,
|
|
146
|
+
`Wave2D_MS` and `Maxwell2D_TM` problems could not take an augmented basis at all.
|
|
147
|
+
- **basis** -- a 0-d (scalar) symbol is a constant multiplier, not an error.
|
|
148
|
+
- **solvers** -- `add_block(scale=...)` accepts a tuple or tensor of per-axis scales, not
|
|
149
|
+
just a list or ndarray.
|
|
150
|
+
- **newton** -- when no backtracked step satisfied Armijo, the loop restored `beta` and
|
|
151
|
+
then recomputed the identical step until `max_iter`, while `history` recorded the last
|
|
152
|
+
alpha tried as if the step had been taken. It now stops, records the rejection as
|
|
153
|
+
`step_size 0.0`, and tags every exit with a stop reason.
|
|
154
|
+
- **kernels** -- `from_inner_products` objects now raise a clear error from
|
|
155
|
+
`check_quadrature` and `degenerate_eigenvalues` instead of failing inside `leggauss(0)`.
|
|
156
|
+
|
|
157
|
+
### Changed -- diagnostics and documentation
|
|
158
|
+
|
|
159
|
+
- **linalg** -- `return_info` now carries `method_used`, because `"auto"` picks its
|
|
160
|
+
back-end at run time; on CPU with `mu = 0` it never runs QR (Cholesky probe, then
|
|
161
|
+
`gelsd`), which the module docstring claimed otherwise. The docstring now describes what
|
|
162
|
+
the code does.
|
|
163
|
+
- **linalg/api** -- `rank_used` is documented as what it is: a post-hoc count of singular
|
|
164
|
+
values above `rcond * sigma_max`, not the rank the back-end worked with.
|
|
165
|
+
- **newton** -- the convergence test is relative to the first residual, as the code always
|
|
166
|
+
did; the docstring said absolute.
|
|
167
|
+
- **kernels** -- `degenerate_eigenvalues` no longer runs a full quadrature for inner
|
|
168
|
+
products it discards, and its docstring no longer claims the values depend on the basis.
|
|
169
|
+
- **basis** -- the `1/sqrt(N)` normalisation convention is documented, including the
|
|
170
|
+
differing defaults of `solve_linear` and `solve_nonlinear`.
|
|
171
|
+
|
|
172
|
+
### Tests
|
|
173
|
+
|
|
174
|
+
- `test_symbol` used `np.trapz`, removed in NumPy 2, so the fractional-Laplacian check
|
|
175
|
+
against the singular-integral definition silently never ran on a current install. With
|
|
176
|
+
`np.trapezoid` the suite goes from 202 passed / 3 failed to 205 passed.
|
|
177
|
+
- New `tests/test_closed_forms_property.py`: 46 property tests checking every closed form
|
|
178
|
+
against an independent reference (autograd, Gauss-Legendre quadrature, the analytic
|
|
179
|
+
characteristic value) at random dimensions, feature counts, bandwidths and orders,
|
|
180
|
+
including the cache-invalidation regression above.
|
|
181
|
+
- `test_version` compared `fastlsq.__version__` against a hard-coded literal, so it had
|
|
182
|
+
to be edited on every release and never caught anything. It now compares
|
|
183
|
+
`__version__` against the version in `pyproject.toml`, which is the drift that can
|
|
184
|
+
actually happen.
|
|
185
|
+
- Full suite: 251 passed.
|
|
186
|
+
|
|
187
|
+
### Packaging and repository
|
|
188
|
+
|
|
189
|
+
- **`scipy` is declared as a test dependency.** Eight scripts under `examples/` use it for
|
|
190
|
+
their reference solvers, and `tests/test_grad_shafranov.py` and `tests/test_grid_swing.py`
|
|
191
|
+
import those scripts -- but `scipy` appeared only in the `battery` extra, never in `dev`
|
|
192
|
+
or `requirements.txt`. `pip install -e ".[dev]"` into a clean environment produced six
|
|
193
|
+
errors; the suite passed locally only where scipy happened to be installed for other
|
|
194
|
+
reasons. Found by the new CI on its first run.
|
|
195
|
+
- `fastlsq/py.typed` is now actually shipped. `[tool.setuptools.package-data]` had
|
|
196
|
+
declared it since 0.4.0, but the file did not exist, so the package advertised PEP 561
|
|
197
|
+
inline typing that type checkers never saw.
|
|
198
|
+
- The build requirement is `setuptools>=77.0`. `license = "MIT"` is the PEP 639 SPDX
|
|
199
|
+
expression form, which setuptools only understands from 77.0 on; the pin said `>=68.0`.
|
|
200
|
+
- Continuous integration runs the suite on Python 3.9 through 3.12 (`.github/workflows/tests.yml`).
|
|
201
|
+
- The JOSS submission draft (`paper.md`, `paper.bib`) is tracked in the repository.
|
|
202
|
+
- Two 0.5.x changelog entries advertised example scripts under `examples/inverse/` that
|
|
203
|
+
were never shipped; both entries now say so.
|
|
204
|
+
|
|
205
|
+
### Fixed -- documentation
|
|
206
|
+
|
|
207
|
+
- **The citation in `README.md` had the wrong paper title.** It read *"FastLSQ: A
|
|
208
|
+
Framework for One-Shot PDE Solving"*; the actual title of arXiv:2602.10541 is
|
|
209
|
+
*"FastLSQ: Solving PDEs in One Shot via Fourier Features with Exact Analytical
|
|
210
|
+
Derivatives"*. Anyone who copied that BibTeX block produced a wrong bibliography
|
|
211
|
+
entry. The block now matches the arXiv record and carries the DOI.
|
|
212
|
+
- `paper.bib` cited the same preprint without the `FastLSQ:` title prefix. Corrected to
|
|
213
|
+
the arXiv title, so the JOSS paper and the README agree.
|
|
214
|
+
|
|
215
|
+
### Added -- release tags and README
|
|
216
|
+
|
|
217
|
+
- Release tags for every version, and the *Release tags* section above documenting how
|
|
218
|
+
they were reconstructed, which three are approximate, and which documented versions
|
|
219
|
+
were never released.
|
|
220
|
+
- `README.md`: status badges (CI, PyPI, Python versions, licence, arXiv); the
|
|
221
|
+
dependency and optional-extras list; a **Development** section covering the test
|
|
222
|
+
suite and CI; a **Releases and versioning** section; and a pointer to the JOSS paper
|
|
223
|
+
draft.
|
|
224
|
+
|
|
225
|
+
### Changed -- README
|
|
226
|
+
|
|
227
|
+
- `README.md`: the BerkeleyLab ATAP talk link moved from above the project title, where
|
|
228
|
+
it preceded the description, into the **Paper** section with the other references.
|
|
229
|
+
|
|
5
230
|
## [0.6.0] - 2026-07-21
|
|
6
231
|
|
|
7
232
|
Completes the operator taxonomy: multi-axis integrals, separable kernels, and
|
|
@@ -10,7 +235,7 @@ Fredholm equations, with the integral-equation problems promoted into the same
|
|
|
10
235
|
|
|
11
236
|
### New features
|
|
12
237
|
|
|
13
|
-
| Feature | API |
|
|
238
|
+
| Feature | API | Benefit |
|
|
14
239
|
|---|---|---|
|
|
15
240
|
| Multi-axis integrals | `MultiIntegralOperator`, `SinusoidalBasis.multi_integral` | Integrate over any subset of axes at once, each independently definite or Volterra — area/volume functionals and mixed "definite in space, running in time" memory terms that a single-axis operator cannot express |
|
|
16
241
|
| Separable (degenerate) kernels | `SeparableKernelOperator` | `K(x,y) = Σ g_m(x) h_m(y)` assembles as a rank-`R` product `G @ C`; the inner products `C` are computed once, independent of the collocation points |
|
|
@@ -361,8 +586,10 @@ augmentation columns (§2.3).
|
|
|
361
586
|
Gauss--Hermite quadrature of the slice integral to machine precision in d = 2, 3, 4
|
|
362
587
|
(≤4e-13 observed), that autodiff of the rows wrt `c` matches finite differences, and
|
|
363
588
|
that a windowed field is recovered from its projections at several directions in one
|
|
364
|
-
LSQ.
|
|
365
|
-
|
|
589
|
+
LSQ. *(Correction, 0.6.1: this entry also announced an
|
|
590
|
+
`examples/inverse/tomography_projection.py` demonstrating the full reconstruction plus
|
|
591
|
+
the differentiable-optics gradient. That example was never shipped; the reconstruction
|
|
592
|
+
and the gradient check live in `tests/test_projection.py` instead.)*
|
|
366
593
|
|
|
367
594
|
### Scope (honest)
|
|
368
595
|
|
|
@@ -401,9 +628,11 @@ augmentation columns (§2.3).
|
|
|
401
628
|
linear-least-squares design matrix; coefficients stay differentiable so learnable
|
|
402
629
|
integral-term coefficients train through the solve. All three exported from `fastlsq`.
|
|
403
630
|
- **Examples** `examples/integro_differential_demo.py` (one-shot forward solve of
|
|
404
|
-
`u'(x) + ∫_0^x u ds = f`, rel-L2 ~3e-11)
|
|
405
|
-
`examples/inverse/inverse_memory_kernel.py`
|
|
406
|
-
noisy data via AdamW through the differentiable solve
|
|
631
|
+
`u'(x) + ∫_0^x u ds = f`, rel-L2 ~3e-11). *(Correction, 0.6.1: this entry also
|
|
632
|
+
announced an `examples/inverse/inverse_memory_kernel.py` recovering an unknown memory
|
|
633
|
+
strength λ from noisy data via AdamW through the differentiable solve. That example was
|
|
634
|
+
never shipped; gradient flow through the solve is covered by `tests/test_integral.py`.)*
|
|
635
|
+
New `tests/test_integral.py`
|
|
407
636
|
asserts ∫-then-∂ round-trips to identity, Volterra/definite match quadrature, the DC
|
|
408
637
|
guard stays finite, and gradients flow to learnable coefficients.
|
|
409
638
|
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
cff-version: 1.2.0
|
|
2
|
+
title: "FastLSQ: One-shot PDE solving via Fourier features with exact analytical derivatives"
|
|
3
|
+
message: >-
|
|
4
|
+
If you use this software, please cite the paper below. If you need to cite a
|
|
5
|
+
specific archived version of the code, use the Zenodo DOI for that version.
|
|
6
|
+
type: software
|
|
7
|
+
authors:
|
|
8
|
+
- family-names: Sulc
|
|
9
|
+
given-names: Antonin
|
|
10
|
+
orcid: "https://orcid.org/0000-0001-7767-778X"
|
|
11
|
+
affiliation: "Lawrence Berkeley National Laboratory, Berkeley, CA, United States"
|
|
12
|
+
repository-code: "https://github.com/sulcantonin/FastLSQ"
|
|
13
|
+
url: "https://fastlsq.com"
|
|
14
|
+
repository-artifact: "https://pypi.org/project/FastLSQ/"
|
|
15
|
+
abstract: >-
|
|
16
|
+
FastLSQ solves linear partial differential, integral and integro-differential
|
|
17
|
+
equations in a single least-squares call, by expanding the unknown in a basis of
|
|
18
|
+
random Fourier features whose derivatives and integrals are available in closed
|
|
19
|
+
form. Because every feature is a plane wave, a linear operator maps the basis to
|
|
20
|
+
another explicit matrix: no mesh, no automatic differentiation, no iterative
|
|
21
|
+
training. The closed-form derivatives make the fitted field a differentiable
|
|
22
|
+
surrogate whose operator factors once, so inverse problems and control loops can
|
|
23
|
+
afford thousands of forward solves.
|
|
24
|
+
keywords:
|
|
25
|
+
- partial differential equations
|
|
26
|
+
- integral equations
|
|
27
|
+
- inverse problems
|
|
28
|
+
- Fourier features
|
|
29
|
+
- least squares
|
|
30
|
+
- closed-form derivatives
|
|
31
|
+
- differentiable surrogate
|
|
32
|
+
- scientific machine learning
|
|
33
|
+
- PyTorch
|
|
34
|
+
license: MIT
|
|
35
|
+
version: 0.6.2
|
|
36
|
+
date-released: "2026-09-18"
|
|
37
|
+
|
|
38
|
+
identifiers:
|
|
39
|
+
- type: doi
|
|
40
|
+
value: 10.5281/zenodo.22830737
|
|
41
|
+
description: Concept DOI — resolves to the latest archived version
|
|
42
|
+
|
|
43
|
+
preferred-citation:
|
|
44
|
+
type: article
|
|
45
|
+
title: "FastLSQ: Solving PDEs in One Shot via Fourier Features with Exact Analytical Derivatives"
|
|
46
|
+
authors:
|
|
47
|
+
- family-names: Sulc
|
|
48
|
+
given-names: Antonin
|
|
49
|
+
orcid: "https://orcid.org/0000-0001-7767-778X"
|
|
50
|
+
year: 2026
|
|
51
|
+
doi: "10.48550/arXiv.2602.10541"
|
|
52
|
+
url: "https://arxiv.org/abs/2602.10541"
|
|
53
|
+
journal: "arXiv preprint arXiv:2602.10541"
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: FastLSQ
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.2
|
|
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
|
|
7
|
-
Project-URL: Homepage, https://
|
|
7
|
+
Project-URL: Homepage, https://fastlsq.com
|
|
8
8
|
Project-URL: Repository, https://github.com/sulcantonin/FastLSQ
|
|
9
9
|
Project-URL: Paper, https://arxiv.org/abs/2602.10541
|
|
10
10
|
Project-URL: Bug Tracker, https://github.com/sulcantonin/FastLSQ/issues
|
|
@@ -33,6 +33,7 @@ Requires-Dist: scipy>=1.10; extra == "battery"
|
|
|
33
33
|
Provides-Extra: dev
|
|
34
34
|
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
35
35
|
Requires-Dist: pandas>=2.0; extra == "dev"
|
|
36
|
+
Requires-Dist: scipy>=1.10; extra == "dev"
|
|
36
37
|
Requires-Dist: build; extra == "dev"
|
|
37
38
|
Requires-Dist: twine; extra == "dev"
|
|
38
39
|
Provides-Extra: lightning
|
|
@@ -41,8 +42,13 @@ Dynamic: license-file
|
|
|
41
42
|
|
|
42
43
|
# FastLSQ
|
|
43
44
|
|
|
44
|
-
[
|
|
45
|
-
|
|
45
|
+
[](https://github.com/sulcantonin/FastLSQ/actions/workflows/tests.yml)
|
|
46
|
+
[](https://pypi.org/project/FastLSQ/)
|
|
47
|
+
[](https://pypi.org/project/FastLSQ/)
|
|
48
|
+
[](LICENSE)
|
|
49
|
+
[](https://arxiv.org/abs/2602.10541)
|
|
50
|
+
[](https://doi.org/10.5281/zenodo.22830737)
|
|
51
|
+
[](https://fastlsq.com)
|
|
46
52
|
|
|
47
53
|
<p align="center">
|
|
48
54
|
<img src="https://raw.githubusercontent.com/sulcantonin/FastLSQ/main/misc/fastlsq_teaser.png" alt="FastLSQ method overview" width="400"/>
|
|
@@ -68,14 +74,23 @@ regularisation, 1/sqrt(N) feature normalisation, and continuation/homotopy.
|
|
|
68
74
|
pip install fastlsq
|
|
69
75
|
```
|
|
70
76
|
|
|
71
|
-
|
|
77
|
+
Requires Python 3.9+, PyTorch 2.0+, NumPy 1.24+ and Matplotlib 3.7+. There is no
|
|
78
|
+
compiled extension and no mesh library: everything runs on the PyTorch tensor stack,
|
|
79
|
+
on CPU, CUDA or Apple-MPS.
|
|
80
|
+
|
|
81
|
+
For development -- test runner, the SciPy reference solvers the example scripts
|
|
82
|
+
compare against, and the build tools:
|
|
72
83
|
|
|
73
84
|
```bash
|
|
74
85
|
git clone https://github.com/sulcantonin/FastLSQ.git
|
|
75
86
|
cd FastLSQ
|
|
76
87
|
pip install -e ".[dev]"
|
|
88
|
+
pytest tests/ # 251 tests, about 30 s on a laptop CPU
|
|
77
89
|
```
|
|
78
90
|
|
|
91
|
+
Optional extras: `.[battery]` for the battery-degradation examples (`progpy`),
|
|
92
|
+
`.[lightning]` for the PyTorch Lightning training loop.
|
|
93
|
+
|
|
79
94
|
## Quick start
|
|
80
95
|
|
|
81
96
|
### Solve a linear PDE in one line
|
|
@@ -516,26 +531,62 @@ See `examples/add_your_own_pde.py` for the complete tutorial.
|
|
|
516
531
|
- **PyTorch Lightning**: Integration for training loops
|
|
517
532
|
- **20+ benchmark problems**: Linear, nonlinear, and regression-mode PDEs
|
|
518
533
|
|
|
534
|
+
## Development
|
|
535
|
+
|
|
536
|
+
```bash
|
|
537
|
+
pip install -e ".[dev]"
|
|
538
|
+
pytest tests/
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
The suite is 251 tests and runs in about 30 seconds on a laptop CPU. Every closed
|
|
542
|
+
form -- derivative, integral, Fourier symbol, projection -- is checked against an
|
|
543
|
+
independent reference (autograd, Gauss-Legendre quadrature, or the analytic value) in
|
|
544
|
+
`tests/test_closed_forms_property.py`, so a wrong closed form fails the suite rather
|
|
545
|
+
than silently returning a plausible number.
|
|
546
|
+
|
|
547
|
+
[Continuous integration](https://github.com/sulcantonin/FastLSQ/actions/workflows/tests.yml)
|
|
548
|
+
runs the suite on Python 3.9, 3.10, 3.11 and 3.12, and separately builds the sdist and
|
|
549
|
+
wheel and checks their metadata.
|
|
550
|
+
|
|
551
|
+
## Releases and versioning
|
|
552
|
+
|
|
553
|
+
Released versions are on [PyPI](https://pypi.org/project/FastLSQ/) and tagged in this
|
|
554
|
+
repository as `vMAJOR.MINOR.PATCH`. `CHANGELOG.md` documents every release.
|
|
555
|
+
|
|
556
|
+
The tags for 0.1.0 through 0.6.0 were reconstructed after the fact, since the project
|
|
557
|
+
was published to PyPI for its first year without tagging. Each tag was matched to its
|
|
558
|
+
commit by comparing the commit's `fastlsq/*.py` sources against the sdist actually
|
|
559
|
+
published, so most are byte-for-byte exact; the three that are not say so in the tag
|
|
560
|
+
message. See the *Release tags* note at the top of `CHANGELOG.md`.
|
|
561
|
+
|
|
519
562
|
## Paper
|
|
520
563
|
|
|
521
|
-
The
|
|
564
|
+
The project site, with interactive demos, is at [fastlsq.com](https://fastlsq.com). The preprint is on [arXiv](https://arxiv.org/abs/2602.10541). A software paper for the
|
|
565
|
+
[Journal of Open Source Software](https://joss.theoj.org/) is drafted in
|
|
566
|
+
[`paper.md`](paper.md).
|
|
567
|
+
|
|
568
|
+
There is also a [BerkeleyLab ATAP talk](https://github.com/sulcantonin/FastLSQ/raw/main/presentations/ATAP_Sulc_20260324.pptx)
|
|
569
|
+
covering the method and the accelerator-physics applications.
|
|
522
570
|
|
|
523
571
|
## Citing this work
|
|
524
572
|
|
|
525
573
|
If you use FastLSQ in your research, please cite:
|
|
526
574
|
|
|
527
575
|
```bibtex
|
|
528
|
-
@misc{
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
576
|
+
@misc{sulc2026fastlsq,
|
|
577
|
+
author = {Sulc, Antonin},
|
|
578
|
+
title = {{FastLSQ}: Solving {PDEs} in One Shot via {Fourier} Features with Exact Analytical Derivatives},
|
|
579
|
+
year = {2026},
|
|
580
|
+
eprint = {2602.10541},
|
|
581
|
+
archivePrefix = {arXiv},
|
|
582
|
+
primaryClass = {math.NA},
|
|
583
|
+
doi = {10.48550/arXiv.2602.10541},
|
|
584
|
+
url = {https://arxiv.org/abs/2602.10541}
|
|
536
585
|
}
|
|
537
586
|
```
|
|
538
587
|
|
|
588
|
+
To cite a specific archived version of the code rather than the paper, use the Zenodo concept DOI [10.5281/zenodo.22830737](https://doi.org/10.5281/zenodo.22830737), which always resolves to the most recent release.
|
|
589
|
+
|
|
539
590
|
## License
|
|
540
591
|
|
|
541
592
|
This project is licensed under the MIT License -- see [LICENSE](LICENSE) for details.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
CHANGELOG.md
|
|
2
|
+
CITATION.cff
|
|
2
3
|
LICENSE
|
|
3
4
|
MANIFEST.in
|
|
4
5
|
README.md
|
|
@@ -34,6 +35,7 @@ examples/run_all_extensions.py
|
|
|
34
35
|
examples/run_linear.py
|
|
35
36
|
examples/run_nonlinear.py
|
|
36
37
|
examples/sdf_domains.py
|
|
38
|
+
examples/stealth_navigation.py
|
|
37
39
|
examples/tutorial_basic.py
|
|
38
40
|
examples/tutorial_nonlinear.py
|
|
39
41
|
examples/vector_basis_stream_vorticity.py
|
|
@@ -94,6 +96,7 @@ fastlsq/lightning.py
|
|
|
94
96
|
fastlsq/linalg.py
|
|
95
97
|
fastlsq/newton.py
|
|
96
98
|
fastlsq/plotting.py
|
|
99
|
+
fastlsq/py.typed
|
|
97
100
|
fastlsq/solvers.py
|
|
98
101
|
fastlsq/tuning.py
|
|
99
102
|
fastlsq/utils.py
|
|
@@ -108,6 +111,7 @@ tests/test_augment.py
|
|
|
108
111
|
tests/test_basic.py
|
|
109
112
|
tests/test_benchmarks_inverse.py
|
|
110
113
|
tests/test_block.py
|
|
114
|
+
tests/test_closed_forms_property.py
|
|
111
115
|
tests/test_derivatives.py
|
|
112
116
|
tests/test_device.py
|
|
113
117
|
tests/test_diagnostics_timing.py
|
|
@@ -121,5 +125,6 @@ tests/test_multi_integral.py
|
|
|
121
125
|
tests/test_orbit_hill.py
|
|
122
126
|
tests/test_problems_integral.py
|
|
123
127
|
tests/test_projection.py
|
|
128
|
+
tests/test_stealth_navigation.py
|
|
124
129
|
tests/test_symbol.py
|
|
125
130
|
tests/test_vector_basis.py
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: FastLSQ
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.2
|
|
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
|
|
7
|
-
Project-URL: Homepage, https://
|
|
7
|
+
Project-URL: Homepage, https://fastlsq.com
|
|
8
8
|
Project-URL: Repository, https://github.com/sulcantonin/FastLSQ
|
|
9
9
|
Project-URL: Paper, https://arxiv.org/abs/2602.10541
|
|
10
10
|
Project-URL: Bug Tracker, https://github.com/sulcantonin/FastLSQ/issues
|
|
@@ -33,6 +33,7 @@ Requires-Dist: scipy>=1.10; extra == "battery"
|
|
|
33
33
|
Provides-Extra: dev
|
|
34
34
|
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
35
35
|
Requires-Dist: pandas>=2.0; extra == "dev"
|
|
36
|
+
Requires-Dist: scipy>=1.10; extra == "dev"
|
|
36
37
|
Requires-Dist: build; extra == "dev"
|
|
37
38
|
Requires-Dist: twine; extra == "dev"
|
|
38
39
|
Provides-Extra: lightning
|
|
@@ -41,8 +42,13 @@ Dynamic: license-file
|
|
|
41
42
|
|
|
42
43
|
# FastLSQ
|
|
43
44
|
|
|
44
|
-
[
|
|
45
|
-
|
|
45
|
+
[](https://github.com/sulcantonin/FastLSQ/actions/workflows/tests.yml)
|
|
46
|
+
[](https://pypi.org/project/FastLSQ/)
|
|
47
|
+
[](https://pypi.org/project/FastLSQ/)
|
|
48
|
+
[](LICENSE)
|
|
49
|
+
[](https://arxiv.org/abs/2602.10541)
|
|
50
|
+
[](https://doi.org/10.5281/zenodo.22830737)
|
|
51
|
+
[](https://fastlsq.com)
|
|
46
52
|
|
|
47
53
|
<p align="center">
|
|
48
54
|
<img src="https://raw.githubusercontent.com/sulcantonin/FastLSQ/main/misc/fastlsq_teaser.png" alt="FastLSQ method overview" width="400"/>
|
|
@@ -68,14 +74,23 @@ regularisation, 1/sqrt(N) feature normalisation, and continuation/homotopy.
|
|
|
68
74
|
pip install fastlsq
|
|
69
75
|
```
|
|
70
76
|
|
|
71
|
-
|
|
77
|
+
Requires Python 3.9+, PyTorch 2.0+, NumPy 1.24+ and Matplotlib 3.7+. There is no
|
|
78
|
+
compiled extension and no mesh library: everything runs on the PyTorch tensor stack,
|
|
79
|
+
on CPU, CUDA or Apple-MPS.
|
|
80
|
+
|
|
81
|
+
For development -- test runner, the SciPy reference solvers the example scripts
|
|
82
|
+
compare against, and the build tools:
|
|
72
83
|
|
|
73
84
|
```bash
|
|
74
85
|
git clone https://github.com/sulcantonin/FastLSQ.git
|
|
75
86
|
cd FastLSQ
|
|
76
87
|
pip install -e ".[dev]"
|
|
88
|
+
pytest tests/ # 251 tests, about 30 s on a laptop CPU
|
|
77
89
|
```
|
|
78
90
|
|
|
91
|
+
Optional extras: `.[battery]` for the battery-degradation examples (`progpy`),
|
|
92
|
+
`.[lightning]` for the PyTorch Lightning training loop.
|
|
93
|
+
|
|
79
94
|
## Quick start
|
|
80
95
|
|
|
81
96
|
### Solve a linear PDE in one line
|
|
@@ -516,26 +531,62 @@ See `examples/add_your_own_pde.py` for the complete tutorial.
|
|
|
516
531
|
- **PyTorch Lightning**: Integration for training loops
|
|
517
532
|
- **20+ benchmark problems**: Linear, nonlinear, and regression-mode PDEs
|
|
518
533
|
|
|
534
|
+
## Development
|
|
535
|
+
|
|
536
|
+
```bash
|
|
537
|
+
pip install -e ".[dev]"
|
|
538
|
+
pytest tests/
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
The suite is 251 tests and runs in about 30 seconds on a laptop CPU. Every closed
|
|
542
|
+
form -- derivative, integral, Fourier symbol, projection -- is checked against an
|
|
543
|
+
independent reference (autograd, Gauss-Legendre quadrature, or the analytic value) in
|
|
544
|
+
`tests/test_closed_forms_property.py`, so a wrong closed form fails the suite rather
|
|
545
|
+
than silently returning a plausible number.
|
|
546
|
+
|
|
547
|
+
[Continuous integration](https://github.com/sulcantonin/FastLSQ/actions/workflows/tests.yml)
|
|
548
|
+
runs the suite on Python 3.9, 3.10, 3.11 and 3.12, and separately builds the sdist and
|
|
549
|
+
wheel and checks their metadata.
|
|
550
|
+
|
|
551
|
+
## Releases and versioning
|
|
552
|
+
|
|
553
|
+
Released versions are on [PyPI](https://pypi.org/project/FastLSQ/) and tagged in this
|
|
554
|
+
repository as `vMAJOR.MINOR.PATCH`. `CHANGELOG.md` documents every release.
|
|
555
|
+
|
|
556
|
+
The tags for 0.1.0 through 0.6.0 were reconstructed after the fact, since the project
|
|
557
|
+
was published to PyPI for its first year without tagging. Each tag was matched to its
|
|
558
|
+
commit by comparing the commit's `fastlsq/*.py` sources against the sdist actually
|
|
559
|
+
published, so most are byte-for-byte exact; the three that are not say so in the tag
|
|
560
|
+
message. See the *Release tags* note at the top of `CHANGELOG.md`.
|
|
561
|
+
|
|
519
562
|
## Paper
|
|
520
563
|
|
|
521
|
-
The
|
|
564
|
+
The project site, with interactive demos, is at [fastlsq.com](https://fastlsq.com). The preprint is on [arXiv](https://arxiv.org/abs/2602.10541). A software paper for the
|
|
565
|
+
[Journal of Open Source Software](https://joss.theoj.org/) is drafted in
|
|
566
|
+
[`paper.md`](paper.md).
|
|
567
|
+
|
|
568
|
+
There is also a [BerkeleyLab ATAP talk](https://github.com/sulcantonin/FastLSQ/raw/main/presentations/ATAP_Sulc_20260324.pptx)
|
|
569
|
+
covering the method and the accelerator-physics applications.
|
|
522
570
|
|
|
523
571
|
## Citing this work
|
|
524
572
|
|
|
525
573
|
If you use FastLSQ in your research, please cite:
|
|
526
574
|
|
|
527
575
|
```bibtex
|
|
528
|
-
@misc{
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
576
|
+
@misc{sulc2026fastlsq,
|
|
577
|
+
author = {Sulc, Antonin},
|
|
578
|
+
title = {{FastLSQ}: Solving {PDEs} in One Shot via {Fourier} Features with Exact Analytical Derivatives},
|
|
579
|
+
year = {2026},
|
|
580
|
+
eprint = {2602.10541},
|
|
581
|
+
archivePrefix = {arXiv},
|
|
582
|
+
primaryClass = {math.NA},
|
|
583
|
+
doi = {10.48550/arXiv.2602.10541},
|
|
584
|
+
url = {https://arxiv.org/abs/2602.10541}
|
|
536
585
|
}
|
|
537
586
|
```
|
|
538
587
|
|
|
588
|
+
To cite a specific archived version of the code rather than the paper, use the Zenodo concept DOI [10.5281/zenodo.22830737](https://doi.org/10.5281/zenodo.22830737), which always resolves to the most recent release.
|
|
589
|
+
|
|
539
590
|
## License
|
|
540
591
|
|
|
541
592
|
This project is licensed under the MIT License -- see [LICENSE](LICENSE) for details.
|