API reference¶
Auto-generated from the source docstrings.
Estimator¶
jax_ibart.ibart.IBart ¶
Iterative BART descriptor discovery.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
backend
|
('bart', 'diff')
|
Selection backend; see :mod: |
"bart"
|
schedule
|
tuple of {"u", "b"}
|
Feature-engineering steps to interleave with selection. |
DEFAULT_SCHEDULE
|
max_dim
|
int
|
Maximum size of the final descriptor (l0 best-subset). |
3
|
n_keep
|
int
|
Candidates passed from LASSO screening into the l0 search. |
10
|
score
|
('bic', 'cv')
|
Selection score for the l0 best-subset. |
"bic"
|
seed
|
int
|
PRNG seed for the (functional) selection randomness. |
0
|
unary_ops
|
list of :class:`~jax_ibart.operators.Operator`
|
Operator sets for the |
None
|
binary_ops
|
list of :class:`~jax_ibart.operators.Operator`
|
Operator sets for the |
None
|
carry_selected
|
bool
|
If True, each screen's survivors are unioned with everything kept by
earlier screens, and that union feeds the next engineering step and the
final LASSO/l0 stage. This is what the R iBART package does
( |
False
|
Attributes (after fit)
descriptors_ : list[sympy.Expr]
The selected descriptors (symbolic, interpretable).
coef_ : np.ndarray
OLS coefficients [intercept, *slopes] aligned with descriptors_.
history_ : list[dict]
One record per pipeline stage, {"stage", "generated", "kept"}: the
pool size after feature engineering and after screening. Shows the
grow-then-prune rhythm that keeps iBART tractable.
pool_ : engineer.Pool
The final screened descriptor pool that the LASSO/l0 stage chose from.
Source code in src/jax_ibart/ibart.py
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 | |
get_params ¶
get_params(deep=True)
Constructor kwargs, for cloning a fresh unfitted estimator.
Source code in src/jax_ibart/ibart.py
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | |
set_params ¶
set_params(**params)
Update constructor kwargs (scikit-learn style); returns self.
Source code in src/jax_ibart/ibart.py
126 127 128 129 130 131 132 133 134 135 | |
clone ¶
clone()
A fresh, unfitted copy with the same configuration.
Source code in src/jax_ibart/ibart.py
137 138 139 | |
fit ¶
fit(X, y, feature_names=None, units=None)
Fit iBART.
feature_names defaults to the columns of a pandas DataFrame X,
or x0, x1, .... Names become the symbols in the discovered
expressions.
units (optional): an (n_features, n_dims) integer unit-exponent
matrix. When given, descriptors that are dimensionally inconsistent
(e.g. summing two different units) are never generated.
The fit always runs JAX in float32, even if 64-bit mode is enabled globally (some libraries, e.g. discopt, enable it on import), so results do not depend on what else is imported. The final regression is float64.
Source code in src/jax_ibart/ibart.py
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 | |
transform ¶
transform(X)
Evaluate the selected descriptors on raw primary features X.
Returns the (n, k) design matrix the final linear model uses.
Source code in src/jax_ibart/ibart.py
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 | |
predict ¶
predict(X)
Predict y for raw primary features X.
The symbolic descriptors are evaluated as written, so operators such as
log and sqrt give NaN outside their real domain (the training
pipeline evaluates them on |x|).
Source code in src/jax_ibart/ibart.py
295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 | |
expression ¶
expression(digits=4)
The fitted model as a single symbolic expression.
Coefficients are rounded to digits significant figures for display
(pass digits=None for full precision).
Source code in src/jax_ibart/ibart.py
314 315 316 317 318 319 320 321 322 323 324 | |
to_discopt ¶
to_discopt(m, x=None, **kwargs)
Add this model to a discopt optimization model.
Returns (x, y): the input variables by feature name and a variable
constrained to equal the prediction. Keyword arguments are passed on;
see :func:jax_ibart.export.to_discopt.
Source code in src/jax_ibart/ibart.py
326 327 328 329 330 331 332 333 334 335 | |
latex ¶
latex(lhs='y', digits=4)
The fitted model as a LaTeX string, e.g. y = -0.099 BVS Hfo + ....
Source code in src/jax_ibart/ibart.py
337 338 339 | |
to_html ¶
to_html(lhs='y', digits=4)
An HTML snippet rendering the model (MathJax/KaTeX delimiters).
Source code in src/jax_ibart/ibart.py
341 342 343 | |
Selection backends¶
jax_ibart.selection.make_selector ¶
make_selector(backend='bart', **kwargs)
Factory: "bart" -> BART-G.SE (faithful), "diff" -> differentiable.
Source code in src/jax_ibart/selection.py
247 248 249 250 251 252 253 | |
jax_ibart.selection.BartGSESelector ¶
Faithful BART-G.SE screening backend (default).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n_perm
|
int
|
Number of label permutations for the null distribution of inclusion proportions. |
50
|
alpha
|
float
|
Simultaneous coverage level for the global standard-error (G.SE) threshold. Larger alpha lowers the threshold and keeps more descriptors. This is the key knob: the PAN criterion wants intermediate screening to tolerate false positives but never drop a true building block (no false negatives), so a permissive (larger) alpha is correct for iBART's interleaved screening. An over-conservative alpha over-prunes; on catalysis (the R-iBART oracle cross-check) alpha=0.05 screened out the Hfo/Oxv coupling, while alpha=0.25 selects descriptors built on the published abs(Hfo/Oxv). Default 0.10; use ~0.2-0.25 for the most faithful reproduction. (Clean, well-separated problems are insensitive to alpha; it matters on collinear, high-dimensional screens.) |
0.1
|
n_tree
|
int
|
BART ensemble size and MCMC schedule (passed through to |
50
|
n_draw
|
int
|
BART ensemble size and MCMC schedule (passed through to |
50
|
n_burn
|
int
|
BART ensemble size and MCMC schedule (passed through to |
50
|
Source code in src/jax_ibart/selection.py
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 | |
select ¶
select(X, y, *, key)
BART-G.SE screening (Bleich et al. 2014, Global SE rule).
Returns a boolean keep-mask over the columns of X (n, d). A column
is kept if its observed inclusion proportion exceeds a permutation-null
threshold mu_j + g * sd_j with a single global multiplier g
calibrated for simultaneous (1-alpha) coverage.
Source code in src/jax_ibart/selection.py
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 | |
jax_ibart.selection.DiffSelector ¶
Differentiable end-to-end screening backend.
Replaces the discrete BART importance with a sparse-gated neural importance
model (hard-concrete L0 gates, Louizos et al. 2018; see
:mod:jax_ibart._diffscreen) so the whole selection step admits gradients.
Acceptance gate: keep the true drivers on the synthetic fixtures and agree
with :class:BartGSESelector (PAN: no false negatives).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
steps
|
training hyperparameters for the gated MLP.
|
|
1500
|
lr
|
training hyperparameters for the gated MLP.
|
|
1500
|
l0
|
training hyperparameters for the gated MLP.
|
|
1500
|
hidden
|
training hyperparameters for the gated MLP.
|
|
1500
|
threshold
|
float
|
Keep features whose learned gate-open probability exceeds this. Kept low to over-select (PAN-safe: tolerate false positives, avoid false negatives). |
0.5
|
min_keep
|
int
|
Always keep at least this many top-importance features (never empties the pool). |
2
|
Source code in src/jax_ibart/selection.py
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 | |
Feature engineering¶
jax_ibart.engineer.Pool
dataclass
¶
A descriptor pool: numeric columns paired with symbolic provenance.
units is optional. When present it has shape (d, n_dims): row j is the
integer unit-exponent vector of column j. When None, dimensional analysis is
disabled and no unit filtering is done.
Source code in src/jax_ibart/engineer.py
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | |
jax_ibart.engineer.from_primary ¶
from_primary(X, names, units=None)
Build the initial pool from primary features and their symbols.
Numeric columns are float32: this is the dtype bartz consumes, and global
jax_enable_x64 must stay off (it breaks bartz's MCMC). Higher-precision
work (final LASSO/OLS) happens host-side in numpy, not in JAX traces.
units (optional) is (d, n_dims): the unit-exponent vector per feature.
Source code in src/jax_ibart/engineer.py
42 43 44 45 46 47 48 49 50 51 52 53 | |
jax_ibart.engineer.apply_unary ¶
apply_unary(pool, ops, corr_max_d=10000)
Apply unary operators to every column.
Vectorized: each operator is evaluated on all valid columns in one batched
JAX call (op.fn broadcasts over the (n, k) slice), and unit vectors are
transformed with a single array op. The symbolic provenance is built in a
host-side loop (SymPy is not vectorizable). corr_max_d is forwarded to
:func:clean (set 0 to keep collinear columns, e.g. for implicit discovery).
Source code in src/jax_ibart/engineer.py
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | |
jax_ibart.engineer.apply_binary ¶
apply_binary(pool, ops, corr_max_d=10000)
Apply binary operators to all column pairs.
Vectorized over pairs: index arrays (I, J) select the operands, op.fn
evaluates all pairs at once via broadcasting (the O(d^2) blowup that is the
prime JAX/GPU target), and the unit filter is a vectorized numpy mask.
Source code in src/jax_ibart/engineer.py
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | |
jax_ibart.engineer.clean ¶
clean(pool, corr_thresh=1 - 1e-08, corr_max_d=10000)
Drop invalid (NaN/inf), near-constant, and duplicate/collinear columns.
All numeric decisions are made in float64 (host-side numpy), even though the columns are stored f32 for the bartz pipeline: collinearity/rank judgements on small-n, highly correlated engineered descriptors are exactly where f32's ~7 digits are not enough. The returned pool keeps the original f32 columns; only the keep/drop choices use f64.
Source code in src/jax_ibart/engineer.py
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 | |
Operators¶
jax_ibart.operators.Operator
dataclass
¶
Source code in src/jax_ibart/operators.py
68 69 70 71 72 73 74 75 76 | |
jax_ibart.operators.default_unary ¶
default_unary()
The O1 set used in the catalysis study (Liu et al. 2022).
Source code in src/jax_ibart/operators.py
211 212 213 214 215 | |
jax_ibart.operators.default_binary ¶
default_binary()
The O2 set used in the catalysis study (Liu et al. 2022).
Source code in src/jax_ibart/operators.py
218 219 220 | |
Final parametric stage¶
jax_ibart.sparsify.ols ¶
ols(X, y)
Ordinary least squares with an intercept, in float64.
Returns (coef, rss) where coef is [intercept, *slopes] and
rss is the residual sum of squares.
Source code in src/jax_ibart/sparsify.py
63 64 65 66 67 68 69 70 71 72 73 | |
jax_ibart.sparsify.lasso_screen ¶
lasso_screen(X, y, n_keep=10)
Return indices of up to n_keep descriptors ranked by LASSO entry.
Features are standardized for ranking only. Variables are ordered by
absolute standardized coefficient at the cross-validated LASSO solution;
any shortfall is filled by univariate correlation so exactly
min(n_keep, d) indices come back.
Source code in src/jax_ibart/sparsify.py
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | |
jax_ibart.sparsify.l0_best_subset ¶
l0_best_subset(X, y, max_dim=3, score='bic')
Exhaustive l0: best OLS subset up to max_dim columns.
Returns (indices, coef) where indices are column positions into
X and coef is the OLS coefficient vector [intercept, *slopes]
for that subset (f64).
Source code in src/jax_ibart/sparsify.py
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 | |
Uncertainty quantification¶
jax_ibart.uncertainty.conformal_intervals ¶
conformal_intervals(factory, X, y, feature_names, units=None, alpha=0.1, cal_frac=0.3, seed=0)
Split-conformal prediction intervals around an iBART fit.
The estimator (selection + final model) is fit on a proper-training split
and scored on a disjoint calibration split, so the residual quantile is an
honest, post-selection-valid calibration. Returns a :class:ConformalModel.
Source code in src/jax_ibart/uncertainty.py
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 | |
jax_ibart.uncertainty.empirical_coverage ¶
empirical_coverage(conformal, X_test, y_test)
Fraction of test points whose true y falls inside the conformal interval.
Source code in src/jax_ibart/uncertainty.py
154 155 156 157 158 | |
jax_ibart.uncertainty.ols_intervals ¶
ols_intervals(model, X_train, y_train, X_new=None, alpha=0.1)
OLS coefficient SEs/CIs and Gaussian prediction intervals.
OPTIMISTIC: conditions on model.descriptors_ and ignores that they were
selected from data, so coverage is below nominal. Use
:func:conformal_intervals for honest intervals.
Source code in src/jax_ibart/uncertainty.py
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | |
jax_ibart.uncertainty.selection_stability ¶
selection_stability(factory, X, y, feature_names, units=None, n_boot=25, seed=0)
Bootstrap inclusion frequencies for descriptors and primary features.
Refits the whole pipeline on n_boot bootstrap resamples and records how
often each descriptor (by canonical form) and each primary feature is
selected. Frequencies near 1 are stable signals; low frequencies are
selection noise.
Source code in src/jax_ibart/uncertainty.py
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 | |
jax_ibart.uncertainty.repeated_split_rmse ¶
repeated_split_rmse(factory, X, y, feature_names, units=None, n_splits=20, test_frac=0.25, seed=0)
Out-of-sample RMSE over n_splits random train/test partitions.
Source code in src/jax_ibart/uncertainty.py
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 | |
jax_ibart.uncertainty.bart_posterior_intervals ¶
bart_posterior_intervals(model, X_train, y_train, X_new, alpha=0.1, n_tree=50, n_draw=500, n_burn=500, seed=0)
Posterior predictive intervals from a BART fit on the selected descriptors.
Propagates BART's function-value posterior and the error-scale posterior
(sigma) to a predictive interval at X_new. Conditional on the selected
descriptors (it does not propagate selection uncertainty -- use
:func:selection_stability for that). Requires bartz.
Source code in src/jax_ibart/uncertainty.py
248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 | |
Optimization (discopt export)¶
jax_ibart.export.to_discopt ¶
to_discopt(model, m, x=None, *, bounds='data', domain=True, X_ref=None, name='y', y_bounds='auto')
Add a fitted iBART model to a discopt model.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model
|
IBart
|
A fitted model. |
required |
m
|
Model
|
The optimization model to add variables and constraints to. |
required |
x
|
dict or sequence
|
The inputs. A dict maps feature names to discopt expressions; a
sequence (list, array, or a vector variable) is indexed in
|
None
|
bounds
|
"data", tuple of arrays, or None
|
Bounds for created variables: |
'data'
|
domain
|
bool
|
Add the domain constraints described in the module docstring. |
True
|
X_ref
|
array
|
Reference data for bounds and domain constraints; defaults to the
training |
None
|
name
|
str
|
Name of the prediction variable (must be unique in |
'y'
|
y_bounds
|
"auto", (lb, ub), or None
|
Bounds for the prediction variable. |
'auto'
|
Returns:
| Name | Type | Description |
|---|---|---|
x |
dict[str, Expression]
|
The inputs the model uses, by feature name. |
y |
Variable
|
The model prediction, constrained to equal
|
Examples:
>>> import discopt.modeling as dm
>>> m = dm.Model("design")
>>> x, y = to_discopt(fitted, m)
>>> m.maximize(y)
>>> res = m.solve()
>>> {k: float(res.value(v)) for k, v in x.items()}
Source code in src/jax_ibart/export.py
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 | |
Datasets¶
jax_ibart.datasets.load_metal_support ¶
load_metal_support()
Load the M-S single-atom catalysis dataset.
Returns (X, y, feature_names, units):
X-- 91 x 59 primary-feature matrix.y-- 91 metal/oxide binding energies (eV).feature_names-- the 59 feature names.units-- 59 x 12 integer unit-exponent matrix (row per feature, column per base dimension), for the dimensional-analysis filter. Pass it toIBart.fit(..., units=units)to drop unit-inconsistent descriptors.
This is the exact catalysis dataset shipped with the R iBART package
(converted from the R package's data/catalysis.rda), so results are directly comparable.
Notable features for the published descriptor abs(Hfo/Oxv):
Hfo (oxide formation enthalpy) and Oxv (oxygen vacancy energy); both
carry unit eV.
Source code in src/jax_ibart/datasets.py
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | |
jax_ibart.datasets.load_reaction ¶
load_reaction()
Load the example batch-reactor kinetics dataset.
Returns (C, dCdt, species, batch):
C-- (n, 4) measured concentrations [CA, CB, CC, CD].dCdt-- (n, 4) time derivatives, estimated by central finite differences within each batch (the mole-balance RHS targets).species-- ["CA", "CB", "CC", "CD"].batch-- (n,) batch index of each row.
Synthetic data from a liquid-phase batch reactor with A+B->C (bimolecular)
and C->D (first order); see scripts/make_reaction_data.py. Use it to
rediscover the mole-balance RHS (e.g. with
jax_ibart.dynamics.discover_ode(C, t=None, species, dXdt=dCdt,
screen="bart")).
Source code in src/jax_ibart/datasets.py
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | |
Dynamical systems¶
jax_ibart.dynamics.discover_ode ¶
discover_ode(X_t, t, feature_names, degree=2, max_terms=3, units=None, dXdt=None, coef_threshold=0.001, screen=None, seed=0)
Discover dx_i/dt = f_i(x) by sparse regression on a polynomial library.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
X_t
|
(n_time, n_state) trajectory samples.
|
|
required |
t
|
(n_time,) time stamps.
|
|
required |
feature_names
|
names of the state variables.
|
|
required |
degree
|
polynomial library degree (<=2 here).
|
|
2
|
max_terms
|
max non-zero terms per equation (l0 best subset).
|
|
3
|
units
|
optional (n_state, n_dims) unit-exponent matrix.
|
|
None
|
dXdt
|
optional precomputed derivatives; if None, central finite differences.
|
(For multi-trajectory data, compute derivatives per trajectory and pass the stacked array here.) |
None
|
screen
|
None or "bart". With "bart", a BART-G.SE nonparametric screen prunes
|
the library against each derivative before the l0 search, i.e. BART finds
which terms enter each mole-balance RHS. Needs |
None
|
Returns:
| Type | Description |
|---|---|
DiscoveredSystem
|
|
Source code in src/jax_ibart/dynamics.py
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 | |
jax_ibart.dynamics.implicit_constraints ¶
implicit_constraints(X, feature_names, degree=2, units=None, tol=0.01)
PROTOTYPE: find algebraic constraints g(x) ~ 0 (the DAE algebraic part).
A differential-algebraic system couples dynamics dx/dt = f with algebraic constraints 0 = g(x, z). Discovering g is an implicit problem: find a sparse coefficient vector xi != 0 with Theta(x) @ xi ~ 0, i.e. a vector in (or near) the null space of the library matrix. This is NOT the regress-on-a- target problem iBART/SINDy solve, which is why it needs separate machinery.
This prototype: 1. builds the iBART library Theta (with the unit filter), 2. standardizes columns and takes the SVD, 3. returns the smallest right-singular vector as the leading candidate constraint, with its normalized residual ||Theta xi|| / ||Theta||.
A production DAE module (the "something special to develop") would add: - sparse null-space selection (only a few terms active), e.g. SINDy-PI's per-term implicit regressions or sparse-null-space algorithms, instead of the dense smallest singular vector; - a weak / integral formulation to handle noise and avoid derivatives (Messenger & Bortz 2021); - separation of differential vs algebraic relations and DAE index/ consistency handling.
See docs/references.md (Mangan et al. 2016; Kaheman et al. 2020; Messenger & Bortz 2021).
Returns a dict with the candidate constraint expression, its coefficient vector over the library terms, and the residual (smaller = closer to an exact constraint).
Source code in src/jax_ibart/dynamics.py
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 | |
jax_ibart.dynamics.finite_difference ¶
finite_difference(X_t, t)
Central finite-difference time derivatives of a trajectory.
X_t is (n_time, n_state); t is (n_time,). Returns dX/dt with the same
shape (forward/backward differences at the endpoints). For noisy data prefer
a smoothing or weak/integral formulation (see docs/references.md); this is
the clean-data baseline.
Source code in src/jax_ibart/dynamics.py
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | |