## Sparse regression (SINDy)

### Dependencies
```
numpy==1.23.5
pysindy==1.7.5
h5py==3.8.0
tqdm==4.64.1
scikit-learn==1.6.1
scipy==1.10.1
```

### Data generation
Run the notebooks under the `data_gen` folder to generate data for the Boussinesq equation and the reaction-diffusion system.

### Boussinesq equation
```
# PySINDy (original & extended function library): see sindy_boussinesq.ipynb
# SI (ours)
python sparse_regression.py --dataset boussinesq --data_path ../data/boussinesq/boussinesq_1_dt_1e-3.h5
```

### 2D Reaction-Diffusion system
#### Default parameterization (Results in Table 1)
Use the argument `--n_runs` to specify the number of random trials. The script below sets it to 1 for quick experimentation. We used `--n_runs 100` in our experiments. The same applies to all following experiments.
```
# PySINDy
python wsindy_rd.py -D ../data/ReacDiff2D/rd_noise0.0005.h5 --n_runs 1 --lib original --noise 0.0 --n_timesteps 20
# PySINDy*
python wsindy_rd.py -D ../data/ReacDiff2D/rd_noise0.0005.h5 --n_runs 1 --lib extended --noise 0.0 --n_timesteps 20
# SI (ours)
python sparse_regression.py --dataset reac_diff --data_path ../data/ReacDiff2D/rd_noise0.0005.h5 --subsample 0.1
# SI-aligned (ours)
python wsindy_rd.py -D ../data/ReacDiff2D/rd_noise0.0005.h5 --n_runs 10 --lib original --noise 0.0 -S --n_timesteps 20
```

#### Noisy data (Figure 3 (left))

Use the argument `--noise` to control the level of noise added to the data. We used [0.01, 0.015, 0.02, 0.025, 0.03, 0.04, 0.05] for different levels of noise in our experiments.

Also, use `-K` to specify the number of test functions used in Weak SINDy. The default value is 1000. We also tried `-K 100` in our experiments.
```
# Example: 2% noise
# SINDy
python wsindy_rd.py -D ../data/ReacDiff2D/rd.h5 --n_runs 1 --noise 0.02 -K 1000
# SI (ours)
python wsindy_rd.py -D ../data/ReacDiff2D/rd.h5 --n_runs 1 --noise 0.02 -S -K 1000
```

#### Symmetry breaking (unequal diffusivities) (Figure 3 center)
Use the argument `-D` to specify which dataset to use. Each dataset corresponds to a governing equation with a different value for the symmetry breaking parameter $\epsilon$, as specified in the file name `rd_sb1_eps{value}`. Available values are [-0.03, -0.02, -0.01, 0.01, 0.02, 0.03].
```
# Example: symmetry breaking parameter eps=0.01
# SINDy
python wsindy_rd.py -D ../data/ReacDiff2D/rd_sb1_eps0.01.h5 --n_runs 1 --n_timesteps 50
# SI
python wsindy_rd.py -D ../data/ReacDiff2D/rd_sb1_eps0.01.h5 --n_runs 1 --n_timesteps 50 -S
# SI-relaxed
python wsindy_rd.py -D ../data/ReacDiff2D/rd_sb1_eps0.01.h5 --n_runs 1 --n_timesteps 50 -SS
```

#### Symmetry breaking (external forcing) (Figure 3 right)
Use the argument `-D` to specify which dataset to use. Each dataset corresponds to a governing equation with a different value for the symmetry breaking parameter $\epsilon$, as specified in the file name `rd_sb2_eps{value}`. Available values are [0.10, 0.15, 0.20].

```
# Example: symmetry breaking parameter eps=0.10
# SINDy
python wsindy_rd.py -D ../data/ReacDiff2D/rd_sb2_eps0.10.h5 --n_runs 1
# SI
python wsindy_rd.py -D ../data/ReacDiff2D/rd_sb2_eps0.10.h5 --n_runs 1 -S --seq_thres_method constrained
# SI-relaxed
python wsindy_rd.py -D ../data/ReacDiff2D/rd_sb2_eps0.10.h5 --n_runs 1 -SS --seq_thres_method constrained
```