The introduction to this README is plainly written by a human to detail the experimental procedures and the ideas of our method and how we came to our conclusions. We pruposley include all experiments in this repository rather
Later sections of this README are generated by an LLM that detail the code structure.
This repository contains the scientific code and worklflow for the paper:
Deep-Koopman-KANDy: Dictionary Discovery for Deep-Koopman Operators with Kolmogorov-Arnold Networks for Dynamics
by Kevin Slote, Erik Bollt, and Jeremie Fish Clarkson Center for Complex Systems Science Clarkson University Postdam, NY, USA
This software repository contains at a top level the code needed to reproduce and run the Deep-Koopman-KANDy algorithm
The software experiments were written with Claude Opus 2.6. The agent memory is included ad the code was verified and ran indepedenty.
We include all of the experiments that follow a narrative arc of how our algorithm was developed. The first pass
of analysis included the development of the stable propogator. The code in the experiments directory with naming
conventions containing stable, unitary, or ergodic, correspond to an experiment testing which contraint on
the Koopman operator K, yeilded the best results.
Proceeding along the narative arc of how we arrived at our conclusions, we tested for model perormance and network
sparcisty eventually arriving at our bet pykan backend model lorenz_5d_third_test.py. Then we began testing across
random seeds and different ics
We then began testing against the SINDy-ae method as this was the closed model to our and given the lack of a coherent
similar benchmark of dictionary extraction and we used symbolic regression to test the quality of the learned
autoencoders.
We include numerous experiments detailing the optimal level-set-manifold extraction of the non-linear activations. Althought, the KANDy model was yeilding better results for some types of functions. This full analysis was mostly omitted from the paper.
The mathematics of our method were developed and put as readme files in the research_materials directory.
The code that produced the tables and figures in the paper are as follows
Run every command from the repository root. Scripts in experiments/ that are not listed below are development
experiments and are not needed to reproduce the paper. Tables and figures use the numbering in the camera-ready PDF.
Train these first. Each later section assumes the checkpoints below exist, and all of them are included in results/.
| Model | Checkpoint | Command |
|---|---|---|
| Lorenz [3,5,5], unpruned | results/lorenz_5d_second_test/model.pt |
python experiments/lorenz_5d_second_test.py |
| Lorenz [3,5,5], pruned (best model) | results/lorenz_5d_third_test/model_pruned_0.03.pt |
python experiments/lorenz_5d_third_test.py (needs the unpruned model) |
| Lorenz [3,8,32] stable | results/lorenz_stable/stable_8_32_model.pt |
python experiments/lorenz_stable.py |
| Standard map [32,128] stable | results/standard_map/standard_map_stable_32_128.pt |
python experiments/standard_map_stable.py |
| Arnold cat map [4,24,1024] | results/cat_map_standard/cat_map_model.pt |
python experiments/cat_map_standard.py --epochs 200 |
| Arnold cat map, Table 6 sizes | results/table_6/model_4_*.pt |
python experiments/table_6.py |
| Ikeda [2,4,4] | results/ikeda_minimal/model_seed_0.pt |
python experiments/ikeda_minimal.py |
| KS (cached data and first run) | results/ks_stable/ks_data.pt, results/ks_stable/ks_stable_model.pt |
python experiments/ks_stable.py |
| KS, wide model | results/ks_stable_wide/ks_stable_model.pt |
python experiments/ks_stable.py --epochs 500 --rollout 1 --outdir results/ks_stable_wide |
cat_map_standard.py uses the stable propagator, despite its name. It is cat_map_stable.py plus the Fourier and
latent-decay analysis. To evaluate its saved model, pass --skip-train --epochs 200; the default of 150 epochs does not
match the saved loss history and the loss plot fails.
| Figure | Content | Script | Notes |
|---|---|---|---|
| 1 | Architecture | None | Drawn by hand: docs/figs/Network.png |
| 2 | Activation manifold | None | Edited by hand: docs/figs/manifold_publication_edited.pdf |
| 3 | Lorenz attractor and observable | experiments/fig_lorenz_paper.py |
Edited by hand afterward. experiments/lorenz_paper_figures.py is a later redraw |
| 4 | Standard map phase portraits | experiments/standard_map_hero.py |
Edited by hand afterward |
| 5 | Arnold cat map rollouts | experiments/cat_map_standard.py |
Panels assembled by hand |
| 6 | Ikeda level sets | experiments/ikeda_levelset_analysis.py |
experiments/ikeda_paper_figures.py is a redraw |
| 7 | KS spacetime rollout | experiments/ks_stable.py (wide run) |
experiments/ks_paper_figures.py redraws from the saved model |
| 8 | KS NRMSE | experiments/ks_stable.py (wide run) |
experiments/ks_paper_figures.py redraws from the saved model |
The KS dispersion and foliation figures in the appendix also come from the wide ks_stable.py run.
collect_all_results.py assembles Tables 1 to 3 from saved results:
python experiments/collect_all_results.py --section 14 # Table 1
python experiments/collect_all_results.py --section 16 # Table 2
python experiments/collect_all_results.py --section 15 # Table 3Sections 1 to 13 of the same script print raw numbers from the development experiments.
| Table | Content | Scripts |
|---|---|---|
| 1 | Lorenz ablation and baselines | ablation_lorenz.py, ablation_lorenz_with_score.py, pykan_pruned_sweep.py, sindy_ae_only.py, edmd_dl_ablation.py, then section 14 |
| 2 | Best Lorenz model summary | lorenz_5d_third_test.py, lorenz_5d_best_model_plots.py, eigenmode_dictionary.py, pykan_pruned_sweep.py, then section 16 |
| 3 | Lorenz level-set decomposition | lorenz_5d_third_test.py, then section 15 (recomputed from model_pruned_0.03.pt) |
| 4 | Ikeda level-set decomposition | ikeda_minimal.py, then ikeda_levelset_analysis.py |
| 5 | Cat map error vs. horizon | table_5.py |
| 6 | Cat map model size | table_6.py |
| 7 | Diagnostic decision procedure | None (written by hand, no data) |
| 8 | Predicted vs. observed residual scales | None (predicted values are calculated by hand) |
| 9 | Lorenz Lasso sweep | pykan_pruned_sweep.py |
| 10 | Lorenz prune threshold sweep | lorenz_5d_third_test.py, pruning_stability_test.py |
| 11 to 14 | Ikeda robustness | ikeda_robustness.py |
| 15, 16 | Standard map robustness | standard_map_robustness.py |
| 17 | Prior-art benchmark | benchmark_prior_art.py |
Table 5, using the saved model:
python experiments/table_5.py --checkpoint results/cat_map_standard/cat_map_model.ptTable 6 trains any size without a checkpoint in results/table_6/ and never replaces an existing one. To train only the
two small sizes and reuse the saved large model:
python experiments/table_6.py --arch 4,16,32 4,32,64
cp results/cat_map_standard/cat_map_model.pt results/table_6/model_4_24_1024.pt
python experiments/table_6.pyThe horizon in Table 6 is the number of steps before angular MSE reaches 0.03. The epoch count for [4,32,64] was not
recorded; table_6.py uses 150.
Table 17 needs results/ks_stable/ks_data.pt and the saved Mackey-Glass data in results/mackey_glass/. It also needs
PyResDMD, which is not on PyPI.
| Result | Script |
|---|---|
| Lorenz spectral analysis (Section 4.1) | experiments/eigenmode_dictionary.py |
| Standard map singular values (Section 4.2) | experiments/standard_map_contractive.py |
| Cat map Fourier coefficients, latent decay, dictionary (Appendix D) | experiments/cat_map_standard.py |
| KS dictionary | experiments/ks_lars_recheck.py, experiments/ks_lars_geometry.py |
| KS Fourier basis test | experiments/ks_fourier_basis_test.py |
| KS lagged self-predictability | experiments/ks_stable.py |