Catalog PyPI
PACKAGE EXPLORERView in registry

adalib-IFL

PyPI

ADAlib: Anti-Derivative Approximator (ADA) library for ODE forward simulation, inverse estimation, operator learning, and MPC, with the ADAlib Studio browser GUI

controllearningmachinemodelodeoperatorphysics-informedpredictivescientific
Versions collected1
Direct dependencies14From release 0.1.9
Last observed20 Oct, 19:00 UTC

README

Version 0.1.9 documentation

ADAlib (adalib-IFL)

ADAlib is a Python library built on the Anti-Derivative Approximator (ADA) representation for ordinary differential equations. One library covers four tasks: forward simulation, physics-informed inverse parameter estimation, amortized operator learning, and model predictive control (MPC) with the trained operator as a differentiable, batchable surrogate.


Install

From PyPI:

pip install adalib-IFL

or the latest version from GitHub:

pip install git+https://github.com/yooyoungwoo7/ADAF_Library.git

or from a local clone:

git clone https://github.com/yooyoungwoo7/ADAF_Library.git
cd ADAF_Library
pip install -e .

Requires Python >= 3.10 and TensorFlow >= 2.13. Tested with Python 3.13.5 and TensorFlow 2.20.0; requirements.txt pins the exact tested environment (pip install -r requirements.txt).

import adalib   # the PyPI distribution is "adalib-IFL"; the import name is "adalib"

Note: an unrelated PyPI package called adalib uses the same import name. Do not install both in the same environment.


ADAlib Studio (browser GUI)

pip install adalib-IFL also installs ADAlib Studio, a local browser workspace for all four tasks: type the governing equations, choose the settings, run, and inspect or export the results, without writing code.

adalib-studio            # or: python -m adalib_studio

The server starts and the app opens at http://127.0.0.1:8000 (the next free port if 8000 is taken). Stop it with Ctrl+C.

OptionMeaning
--port 8100serve on a specific port
--runs DIRwhere job results go (default ~/adalib-studio/runs)
--max-parallel 2jobs computed at the same time (default 1)
--no-browserdo not open the browser
--host 0.0.0.0let other computers on the network connect (default: this computer only)

Every module has an AI assistant panel (right column, with your own Anthropic or OpenAI API key, set in the panel's Settings). A sentence such as "damped pendulum with gamma = 0.5 for 10 s", or a pasted picture of the equations, becomes the module's setup: the system and solver settings (Forward), the controlled system and training size (Operator), the parameters to estimate and the synthetic data (Inverse), or the plant, targets and controllers (MPC). It can also restyle any figure with full Plotly access ("remove the minor ticks", "legend under the plot", "8 x 6 cm at 600 dpi"). Answers are checked like a run request and fill the panels; you review them and press Run or Train. The run history can be ordered by time or grouped by module, and each run can be deleted.

Everything runs on your machine. The browser only shows the interface; a local FastAPI server accepts each job and starts a separate Python worker process that imports adalib and computes it. Results, logs and trained surrogates stay under the runs directory across restarts.

Troubleshooting on Windows:

  • DLL load failed ... blocked by application control policy: Windows 11 Smart App Control is blocking TensorFlow's DLLs (any TensorFlow install, not only ADAlib). Turn it off under Windows Security > App & browser control > Smart App Control settings.
  • pip install fails with a long-path error: TensorFlow's files exceed the 260-character path limit in deep folders. Create the virtual environment in a short path such as C:\Users\<you>\adalib-studio, or enable long paths.

The adalib_studio/ directory is generated from the ADAlib Studio repository; change the GUI there, not in this repository.


Feature support

FeatureUser-defined CallableODESystemBuilt-in systems
Forward✅ Fully supported✅ Supported
Operator learning✅ Physics-residual only (LPA Operator NN)✅ Supported
MPC — tracking✅ LPA Operator NN surrogate✅ Supported
MPC — economic❌ Not yet supported✅ Supported
Inverse (parameter estimation)⚠️ Works; validated on LV/Euler only⚠️ Validated on LV/Euler only

Built-in systems: cstr, triple_tank, fedbatch_bioreactor, lotka_volterra, lotka_volterra_ur, euler, damped_pendulum (see Built-in systems).

Inverse caveat: the inverse solver is validated only for lotka_volterra and euler under low noise and full observation. Inverse estimation for fedbatch_bioreactor is known to fail (the Haldane kinetics are poorly identifiable), and for cstr / triple_tank it is unverified.


Quick start

1. Forward — user-defined ODE

import adalib

def rhs(t, x, u=None, p=None):
    return [-x[0]]                    # dy/dt = -y

def rhs_tf(var_list, i, u=None, p=None):
    y, y_t = var_list[0]
    return y_t - (-y)                 # ADA-F physics residual

system  = adalib.CallableODESystem("decay", rhs, rhs_tf=rhs_tf, state_names=["y"])
options = adalib.ForwardOptions(basis="adaf", n_seg=10, epochs=5, use_lbfgs=True)
result  = adalib.run_forward(system=system, x0=[1.0], t_span=(0.0, 3.0), options=options)

t = result.solution.t   # (Nt_total,)
y = result.solution.y   # (n_state, Nt_total)

2. Operator learning — built-in system

import adalib

system  = adalib.get_system("cstr")
options = adalib.OperatorOptions(
    basis="lpa", n_train=2000, epochs=1000,
    work_dir="./runs/cstr_operator",
)
result  = adalib.run_operator(
    system=system,
    x0=[0.8, 0.5, 134.14, 130.0],
    t_span=(0.0, 0.5),
    options=options,
)

t, y = result.t, result.y          # rollout at segment boundaries
print(result.paths["work_dir"])     # all artifacts saved here

3a. MPC — built-in system (legacy backend)

import adalib

system  = adalib.get_system("cstr")
options = adalib.MPCOptions(
    mode="tracking", basis="lpa",
    target={"T_R": 136.0}, n_steps=20,
    n_train=200, epochs=300,
    work_dir="./runs/cstr_mpc",
)
result  = adalib.run_mpc(
    system=system,
    x0=[0.8, 0.5, 141.0, 141.0],
    options=options,
)

t, x, u = result.t, result.x, result.u   # closed-loop plant trajectory

3b. MPC — user-defined system (generic tracking)

import adalib

def msd_rhs(t, state, u=None, p=None):
    x, v = state
    F = u[0] if u else 0.0
    m, c, k = 1.0, 0.3, 1.5
    return [v, (F - c * v - k * x) / m]

system = adalib.CallableODESystem(
    name="mass_spring_damper",
    rhs=msd_rhs,
    state_names=["x", "v"],
    control_names=["F"],
    state_bounds={"x": (-3.0, 3.0), "v": (-4.0, 4.0)},
    control_bounds={"F": (-5.0, 5.0)},
)

options = adalib.MPCOptions(
    mode="tracking",
    controlled_variables=["x"],
    target={"x": 1.0},
    dt=0.4, horizon=5,
    tracking_weights=[10.0], control_weights=[0.05],
    n_train=400, n_val=80, generate_data=True, train_operator=True,
    epochs=100, n_steps=25,
    work_dir="./runs/msd_mpc",
)
result = adalib.run_mpc(system=system, x0=[0.0, 0.0], options=options)

t, x, u = result.t, result.x, result.u

3c. MPC — autodiff gradients / batched CEM (built-in cstr, triple_tank)

The operator surrogate is a pure TF graph (MLP → panel weights W → linear LPA basis), so the horizon-H rollout cost is exactly differentiable w.r.t. the control sequence, and B candidate sequences can be evaluated in one batched forward pass.

import adalib

# Exact dJ/du via automatic differentiation through the operator (SLSQP jac)
result = adalib.run_mpc(
    system="triple_tank", x0=[190.0, 100.0, 140.0],
    options=adalib.MPCOptions(
        target={"h3": 150.0}, horizon=5, n_steps=20,
        gradient="autodiff",          # "fd" = same cost, finite differences
        work_dir="./runs/tt_autodiff_mpc",
    ),
)
print(result.metadata["opt_ms_per_step_mean"], result.metadata["opt_nfev_mean"])

# Sampling MPC exploiting batched surrogate inference (CEM or MPPI)
result = adalib.run_mpc(
    system="triple_tank", x0=[190.0, 100.0, 140.0],
    options=adalib.MPCOptions(
        target={"h3": 150.0}, horizon=5, n_steps=20,
        optimizer="CEM", cem_samples=512, cem_iters=8,   # or optimizer="MPPI"
        work_dir="./runs/tt_cem_mpc",
    ),
)

Supported for cstr and triple_tank (tracking) and fedbatch_bioreactor (economic — same gradient / optimizer options with mode="economic"). The generic CallableODESystem MPC path also accepts gradient="autodiff", using an analytic Jacobian through the pure-numpy LPA surrogate. gradient=None + optimizer="SLSQP" (default) keeps the original loops. See examples/mpc/surrogate_mpc_showcase.py for a head-to-head comparison (FD vs autodiff vs CEM, plus a batch-throughput microbenchmark against solve_ivp).

4. Inverse — parameter estimation from observations

import adalib
import numpy as np
import tensorflow as tf

# --- Define system with unknown parameters ---------------------------------
def lv_rhs(t, x, u=None, p=None):
    prey, pred = x
    alpha, beta, gamma, delta = p["alpha"], p["beta"], p["gamma"], p["delta"]
    return [
        alpha * prey - beta * prey * pred,
        delta * prey * pred - gamma * pred,
    ]

def lv_rhs_tf(var_list, i, u=None, p=None):
    (prey, prey_t), (pred, pred_t) = var_list
    alpha = p["alpha"]; beta = p["beta"]
    gamma = p["gamma"]; delta = p["delta"]
    r1 = prey_t - (alpha * prey - beta * prey * pred)
    r2 = pred_t - (delta * prey * pred - gamma * pred)
    return tf.stack([r1, r2], axis=-1)

system = adalib.CallableODESystem(
    "lotka_volterra", lv_rhs, rhs_tf=lv_rhs_tf,
    state_names=["prey", "predator"],
)

# --- Generate synthetic observations ---------------------------------------
# (For a fair benchmark, sample observations from an independent solver such as
#  scipy.integrate.solve_ivp rather than from ADAlib's own forward solution;
#  see examples/inverse/lotka_volterra_inverse.py.)
true_p = {"alpha": 1.0, "beta": 0.1, "gamma": 1.5, "delta": 0.075}
ref    = adalib.run_forward(system, x0=[10.0, 5.0], t_span=(0.0, 15.0),
                            params=true_p,
                            options=adalib.ForwardOptions(n_seg=30))
data   = adalib.data_gen(ref, n_points=60, noise_std=0.05, seed=42)

# --- Set up inverse problem ------------------------------------------------
params = {
    "alpha": adalib.InverseParameter(0.5, lower=0.0, name="alpha"),
    "beta":  adalib.InverseParameter(0.2, lower=0.0, name="beta"),
    "gamma": 1.5,    # known — plain float
    "delta": 0.075,  # known — plain float
}

options = adalib.InverseOptions(
    n_seg=30, epochs=50, adam_lr=1e-3, adam_inner=100,
    lambda_data=10.0, lambda_physics=1.0,
    training_strategy="joint",
    normalize_data_loss=True,
)
result = adalib.run_inverse(system, x0=[10.0, 5.0], t_span=(0.0, 15.0),
                            params=params, data=data, options=options)

print(result.estimated_params)   # {"alpha": ..., "beta": ...}
result.plot(save_path="inverse_result.png")
result.plot_loss(save_path="inverse_loss.png")
result.plot_params(true_params=true_p, save_path="inverse_params.png")

Plotting results

ADALib ships publication-quality plot helpers in adalib.utils.

import matplotlib
matplotlib.use("Agg")   # headless / CI — call before importing adalib
import adalib

adalib.utils.set_adalib_plot_style()          # "sans" (default) or "serif"

Forward result

fig, axes = adalib.utils.plot_forward_result(
    result,
    reference=lambda t: np.exp(-t),    # callable, scipy OdeResult, or (t, y) tuple
    state_names=["$y$"],
    title="exponential decay",
    save_path="forward_result.png",
)

Operator rollout (single or multi-case)

fig, axes, metrics = adalib.utils.plot_operator_result(
    [r1, r2, r3],
    reference=[ref1, ref2, ref3],       # list of (t, y) tuples or scipy OdeResults
    state_names=["$C_A$", "$C_B$", "$T_R$", "$T_K$"],
    state_groups=[[0, 1], [2, 3]],      # optional grouped layout
    labels=["Case 1", "Case 2", "Case 3"],
    save_path="operator_result.png",
)
print(metrics["l2_rel"])   # shape: (n_cases, n_state)

MPC closed-loop (single or multi-IC)

fig, axes = adalib.utils.plot_mpc_result(
    all_results,                         # MPCResult or list of MPCResult
    state_names=["$C_A$", "$C_B$", "$T_R$", "$T_K$"],
    control_names=["$\\dot{Q}$"],
    target={"T_R": 136.0},               # dashed setpoint line
    labels=[f"IC {i+1}" for i in range(5)],
    save_path="mpc_result.png",
)

Result inspection

Every workflow returns a result object with built-in convenience methods.

ForwardResult

result = adalib.run_forward(system, x0=[1.0], t_span=(0.0, 3.0))

t = result.t          # result.solution.t also works
y = result.y          # result.solution.y also works

result.plot(reference=lambda t: np.exp(-t), save_path="forward.png")
result.plot(reference="solve_ivp", save_path="forward_ref.png")

t, y = result.to_arrays()
result.save_npz("forward.npz")
print(result.list_artifacts())

OperatorResult

result = adalib.run_operator(system, x0=..., options=...)

result.plot(reference="solve_ivp", save_path="operator_rollout.png")
result.inference_plot(n_cases=4, save_path="operator_inference.png")

cases = result.infer(n_cases=4)   # list of {"t", "y_op", "y_ref", "u", "x0"}
result.save_inference({"t_0": cases[0]["t"], "y_0": cases[0]["y_op"]})
print(result.list_artifacts())

MPCResult

result = adalib.run_mpc(system, x0=..., options=...)

result.plot(save_path="mpc.png")
result.operator_inference_plot(n_cases=4, reference="solve_ivp",
                               save_path="mpc_surrogate.png")

t, x, u, cost = result.to_arrays()
result.save_npz("mpc.npz")
print(result.list_artifacts())

InverseResult

result = adalib.run_inverse(system, x0=..., t_span=...,
                            params=params, data=data, options=options)

print(result.estimated_params)       # {"alpha": 0.998, "beta": 0.102, ...}
print(result.runtime_sec)            # wall-clock time

# Trajectory
t, y = result.t, result.y           # (Nt_total,) and (n_state, Nt_total)

# Plots
result.plot(save_path="trajectory.png")           # recovered vs observed
result.plot_loss(save_path="loss.png")            # total / physics / data loss curves
result.plot_params(true_params={"alpha": 1.0},    # parameter convergence
                   save_path="params.png")

# History
print(result.loss_history)           # list of total loss per step
print(result.param_history)          # dict of list, one entry per log step

t, y = result.to_arrays()
result.save_npz("inverse.npz")
result.save_all("output/")           # trajectory + loss + params plots + npz

InverseOptions reference

FieldDefaultDescription
basis"adaf"Basis type ("adaf" only for inverse)
n_seg20Number of piecewise segments
N_p5ADA-F basis order per segment
N_m100ADA-F collocation points
Nt_total1000Total time-grid points for output
gamma0.8ADA-F decay parameter
epochs5Outer passes over all segments
adam_inner200Adam steps per segment per epoch
adam_lr1e-3Adam learning rate
use_lbfgsTrueL-BFGS polish after Adam
lambda_physics1.0Physics residual loss weight
lambda_data10.0Data fit loss weight
training_strategy"joint""joint" (W+θ together) or "alternating" (W then θ)
data_prefit_steps0Adam steps fitting W only before joint training
normalize_data_lossTrueScale data loss by number of observations
normalize_physics_lossFalseScale physics loss by collocation count
warm_seg_passes1Extra passes on early segments
n_warm_segs3Number of early segments to warm-repeat
true_paramsNoneGround-truth dict for convergence plots
output_dirNoneAuto-save plots/npz here if set

Training strategy guidance:

  • "joint" (default): works well when lambda_data / lambda_physics ≤ 10.
  • "alternating": recommended when the ratio exceeds ~100 (e.g. lambda_data=500), to prevent data loss from dominating physics gradients.

InverseParameter reference

# Unconstrained
p = adalib.InverseParameter(initial=0.5, name="alpha")

# Lower bound only (softplus transform)
p = adalib.InverseParameter(initial=0.5, lower=0.0, name="alpha")

# Box-constrained (sigmoid transform)
p = adalib.InverseParameter(initial=0.5, lower=0.0, upper=2.0, name="alpha")

# Read current estimate during/after training
print(p.numpy_value)       # Python float, post-transform
print(p.constrained)       # TF tensor used inside ODE

Examples

Runnable scripts are in examples/:

Simple API (examples/simple_api/)

ScriptDescription
01_forward_example.pyForward — user-defined exponential decay
02_forward_euler_example.pyForward — built-in Euler rigid body
03_operator_example.pyOperator — CSTR (3 ICs, scipy reference)
04_mpc_example.pyMPC — CSTR tracking (5 ICs)
05_generic_tracking_mpc.pyMPC — user-defined mass-spring-damper

Forward (examples/forward/)

ScriptDescription
lotka_volterra_forward.pyLotka-Volterra forward simulation
euler_forward.pyEuler rigid body forward simulation

Operator (examples/operator/)

ScriptDescription
train_bioreactor_operator.pyOperator learning — fed-batch bioreactor

MPC (examples/mpc/)

ScriptDescription
cstr_tracking_mpc.pyTracking MPC — CSTR
triple_tank_tracking_mpc.pyTracking MPC — triple tank
bioreactor_economic_mpc.pyEconomic MPC — fed-batch bioreactor
surrogate_mpc_showcase.pyFD vs autodiff vs CEM comparison + batch-inference throughput benchmark

Inverse (examples/inverse/)

ScriptDescription
lotka_volterra_inverse.pyParameter estimation — Lotka-Volterra (α, β)
euler_inverse.pyParameter estimation — Euler body inertia

Built-in systems

Inverse legend: ✅ validated · ⚠️ unverified · ❌ known to fail.

NameStatesOperatorMPCInverse
cstrC_A, C_B, T_R, T_K✅✅ tracking⚠️
triple_tankh1, h2, h3 (cm; time in s)✅✅ tracking⚠️
fedbatch_bioreactorXs, Ss, Ps, Vs✅✅ economic❌
lotka_volterraU, R (scaled prey, predator)✅—✅
lotka_volterra_urr (prey), p (predator)———
eulerω₁, ω₂, ω₃——✅
damped_pendulumθ, ω———
print(adalib.list_systems())
# ['cstr', 'damped_pendulum', 'euler', 'fedbatch_bioreactor',
#  'lotka_volterra', 'lotka_volterra_ur', 'triple_tank']

Tests

tests/ holds runnable scripts, one per feature. Most of them train a model when executed (some for many minutes), so run them individually rather than with a bare pytest tests/:

python tests/test_adalib_forward_euler.py     # one script
pytest -q tests/test_adalib_mpc_autodiff.py   # the fast pytest suite
FileCoverage
test_adalib_forward.pyForward — user-defined system
test_adalib_forward_euler.pyForward — Euler rigid body
test_adalib_forward_lotka.pyForward — Lotka–Volterra
test_adalib_forward_pendulum.pyForward — damped pendulum
test_adalib_forward_ev_itms.pyForward — additional user-defined system
test_adalib_inverse_lv.pyInverse — Lotka–Volterra
test_adalib_inverse_euler.pyInverse — Euler rigid body
test_adalib_inverse_pendulum.pyInverse — damped pendulum
test_adalib_operator.pyOperator — CSTR (paper-size settings)
test_adalib_operator_triple_tank.pyOperator — triple tank (paper-size settings)
test_adalib_operator_speaker.pyOperator — user-defined system
test_adalib_operator_ev_itms.pyOperator — additional user-defined system
test_adalib_mpc.pyMPC workflow
test_adalib_mpc_forward.pyMPC with forward reference
test_adalib_mpc_bioreactor.pyEconomic MPC — fed-batch bioreactor
test_adalib_mpc_autodiff.pyAutodiff / CEM surrogate MPC, gradient-vs-FD consistency (pytest)

Package layout

ADAF_Library/
├── adalib/                  # the installable package
├── adalib_studio/           # ADAlib Studio GUI (generated copy; `adalib-studio` command)
│   ├── _vendor/legacy/      # vendored ADA-F / LPA / operator-MPC backend (required at runtime)
│   ├── systems/             # ODESystem, built-in systems, CallableODESystem, registry
│   ├── forward/             # ForwardSolver, ForwardOptions
│   ├── operator/            # OperatorLearner, predict_step, predict_rollout
│   ├── mpc/                 # MPCOptions, generic and surrogate MPC
│   ├── inverse/             # InverseSolver, InverseOptions, InverseParameter, data_gen
│   ├── workflows/           # run_forward, run_operator, run_mpc, run_inverse, run
│   └── utils/               # paths, metrics, plotting
├── examples/                # simple_api/, forward/, inverse/, operator/, mpc/
├── tests/                   # runnable feature scripts (see Tests)
├── docs/                    # Sphinx sources for the ReadTheDocs site
└── paper_artifacts/         # archived checkpoint + data for the paper's bioreactor results

Reproducing the paper's reported results

The defaults used in the quick-start examples above are for illustration only — they do not reproduce the accuracy reported in the paper. Each benchmark's operator was trained with a system-specific network size and training-set size (the paper's operator hyperparameter table, Appendix A):

SystemN_pn_seghiddenn_layersn_trainepochsbatch_size
Lotka–Volterra212025634,0002,000128
Triple-tank2010128320,0002,000128
CSTR2425192320,0002,000256
Fed-batch bioreactor3050128350,0002,000128

To reproduce, e.g., the CSTR operator accuracy, pass these explicitly rather than relying on the quick-start defaults:

import adalib

system  = adalib.get_system("cstr")
options = adalib.OperatorOptions(
    basis="lpa",
    n_train=20000, n_val=4000,
    hidden=192, n_layers=3,
    epochs=2000, batch_size=256,
    work_dir="./runs/cstr_operator_paper",
)
result = adalib.run_operator(
    system=system,
    x0=[0.8, 0.5, 134.14, 130.0],
    t_span=(0.0, 0.5),
    options=options,
)

n_seg comes from the built-in system's segmentation, not from OperatorOptions. Complete runnable scripts at these sizes exist for the CSTR (tests/test_adalib_operator.py) and the triple tank (tests/test_adalib_operator_triple_tank.py). Training at these sizes takes much longer than the quick-start defaults.

The archived checkpoint, training configuration, and evaluation data behind the paper's fed-batch bioreactor results are in paper_artifacts/bioreactor_fig7_checkpoint/; see that directory's README for the exact reproduction steps. The current FedBatchBioreactor sampling ranges differ from the archived run, so retraining with the row above does not reproduce those numbers exactly.

Forward simulation (Euler rigid body). The paper's 1,500-parameter configuration is ForwardOptions(basis="adaf", N_p=10, n_seg=50, N_m=100, Nt_total=2500, gamma=0.9, epochs=5, adam_inner=100, use_lbfgs=True); see also examples/forward/euler_forward.py. The forward scripts in tests/ use smaller quick-start settings.

Known limitations in v0.1.0

  • Generic operator learning (run_operator(CallableODESystem, …)) trains physics-residual only — same philosophy as the built-in systems, no reference trajectory is generated or fit against (adalib/mpc/ _generic_mpc.py: _sample_inputs + _train_lpa_operator_physics). The physics target is evaluated via system.rhs(); a fully-vectorized numpy call is attempted first (fast), falling back to a per-sample Python loop with a one-time warning if the RHS uses scalar-only ops (float(u), math.exp, builtin min/max on arrays) — use np.exp/np.minimum/ np.maximum instead for the fast path. Override the per-state residual normalization via opts.res_scale={"state_name": scale} if needed.
  • Generic economic MPC: economic MPC is only supported for the built-in fedbatch_bioreactor system. Custom-system economic MPC is planned.
  • Generic tracking MPC still uses LPA Operator NN (N_p=8, max_order=6) with trajectory MSE loss (data-driven, not physics residual) — unlike generic Operator learning above, this has not yet been migrated to the physics-only pipeline. Override hyperparameters via opts.lpa_n_panels, opts.lpa_max_order, opts.lpa_nt_seg if needed.
  • Thread safety: operator and built-in MPC workflows use process-global configuration variables (PROBLEM, BASIS). Do not run two such workflows with different systems concurrently in the same process.
  • Generated artifacts (datasets, checkpoints, plots) are written to options.work_dir and are not shipped with the package; each user generates them on first run.

License

Released under the MIT License (see LICENSE). The vendored backend in adalib/_vendor/legacy/ is covered by THIRD_PARTY_NOTICES.md.

Downloads & popularity

Awaiting observations

No metric observations yet

Download counts and popularity will appear here as the collector receives them.

Versions 1

Collected releases
VersionPublishedDirect dependenciesOpen version
0.1.912 Oct 202614

Package advisories

0
No matching advisories collected

This describes our collected data; it is not a security assessment.

Repository

PENDING
yooyoungwoo7/adaf_library

Shared repository data · GitHub

License detected in repository
Not collected

Metadata history

Meaningful changes
Current collected state Current

Observed since 20 Oct, 19:00 UTC

No superseded metadata states collected. Unchanged observations do not create new revisions.

Record identity

package:74d2046846ef75d944909b33ee1ff23b4beb08bbfca53996d541453439ee3888