Metadata-Version: 2.5
Name: vector-mtrl
Version: 0.3.0
Summary: Materials research tools for spectra and archive workflows.
Author-email: Fuzzy Labs <info@fuzzylabs.ai>
License-Expression: MPL-2.0
License-File: LICENSE
License-File: NOTICE
Requires-Python: <4.0,>=3.12
Requires-Dist: numpy>=2.5.2
Requires-Dist: pydantic>=2.13.4
Requires-Dist: rfc8785==0.1.4
Provides-Extra: excel
Requires-Dist: openpyxl>=3.1.5; extra == 'excel'
Requires-Dist: pandas>=3.0.5; extra == 'excel'
Provides-Extra: interp
Requires-Dist: scipy>=1.16; extra == 'interp'
Provides-Extra: tabular
Requires-Dist: pandas>=3.0.5; extra == 'tabular'
Description-Content-Type: text/markdown

# vector-mtrl

`mtrl` reads, checks, and writes materials data archives. It records each scientific result as an
immutable record with exact lineage.

## What you get

- Immutable committed records with stable identities and complete lineage.
- A portable physical sample identity (`sample_uid`) beside the human-facing `sample_id`.
- Scientific assertions with typed subjects, evidence links, supersession, retraction, and
  queries at any past revision.
- Machine-learning dataset preparation across archives: checkpoint state selection, in-memory
  preprocessing, grid alignment, leak-free group splits, and canonical provenance digests.
- Bounded `.mtrl` archives with an integrity manifest, external receipts, and forensic inspection.
- NumPy-only operations: identity, scale, offset, peak normalisation, zero-at-point, and linear
  resample, beside mean and median aggregates.
- Explicit analysis grids and a read-only alignment report.
- A read-only replay plan, a capability view, and a detached rerun for committed chains.
- Author disclosure that stays inert: stored environment records and passive source bundles that
  MTRL never imports or executes.
- CSV export without pandas.
- Optional extras add SciPy resampling, pandas conversion, and Excel export.

## Install

`vector-mtrl` requires Python 3.12 or newer, below Python 4. The base install depends only on
NumPy, Pydantic, and RFC 8785 canonical JSON. Create one environment and install the core:

```sh
uv venv --python 3.14
uv pip install --python .venv/bin/python vector-mtrl
```

## Quick start

Commit one synthetic spectrum, normalise it, save an archive, verify it, load it, and export
CSV. The base install alone runs every step.

### Example: Quick start

**Required install:** `vector-mtrl`

```python
from pathlib import Path
from tempfile import TemporaryDirectory

import numpy as np

from mtrl import InstrumentRun, MaterialData, Mtrl, verify_archive

application = Mtrl(sample_id="sample-01")
run = InstrumentRun(run_name="replicate-01")
axis = np.array([2000.0, 2100.0, 2200.0])
content = np.empty(axis.size, dtype=[("wavenumber", "<f8"), ("absorbance", "<f8")])
content["wavenumber"] = axis
content["absorbance"] = [0.1, 0.2, 0.3]
checkpoint = MaterialData(
    content=content,
    type="raw",
    checkpoint_name="spectrum",
)
run.add_checkpoint(checkpoint)
application.add(run)

normalised = application.transform(
    run.run_id,
    checkpoint.checkpoint_id,
    "normalise_peak",
)
print(normalised.lineage.provenance.qualified_identifier)

with TemporaryDirectory() as directory:
    archive_path = application.save(Path(directory) / "sample.mtrl")
    verification = verify_archive(archive_path)
    print(verification.structural_status.value, verification.hash_status.value)

    loaded = Mtrl.load(archive_path)
    print(loaded.sample_id, loaded.get_run(run.run_id) is not None)
    csv_path = loaded.export_checkpoint(
        run.run_id,
        normalised.checkpoint_id,
        Path(directory) / "signal.csv",
    )
    exported = np.genfromtxt(csv_path, delimiter=",", names=True)
    np.testing.assert_allclose(exported["absorbance"], [1 / 3, 2 / 3, 1])
    print(csv_path.is_file())
```

`Mtrl.add()` commits a detached copy, so later changes to your arrays cannot alter the record.
Every mutation, including the transform above, creates one new revision.

## Guides

The expanded guides ship in the source archive under `docs/user/`. Download the archive for a
release from https://pypi.org/project/vector-mtrl/#files, then read:

- `docs/user/start-here/` for the seven-lesson tutorial path: installation, first records,
  the save, load, verify loop, fields and units, transforms, corrections, aggregates, and
  exports.
- `docs/user/concepts/` for the ideas underneath, in plain language.
- `docs/user/how-to/` for task guides: replacements, resampling, mixed-resolution alignment,
  replay, receipts, forensic inspection, disclosure, registry control, missing extras,
  scientific assertions, external evidence, and machine-learning datasets.
- `docs/user/reference.md` for every public route, the stable typed imports, the exact
  package-root export list, registry names, format features, and the archive safety contract.

## Scientific assertions and machine-learning datasets

`Mtrl.assign_sample_uid()` gives a container a portable physical sample identity, a UUIDv7
string that stays separate from the `sample_id` label. The `mtrl.assertions` module then
records typed property claims about the sample, one run, or one exact record:

- `SubjectRef` names the subject, and `EvidenceRef` links local records, local source files,
  or exact records in other archives.
- `Mtrl.assert_property()` and `Mtrl.assert_properties()` commit claims in one atomic revision.
- `Mtrl.supersede_assertion()` and `Mtrl.retract_assertion()` change a claim and keep every
  prior version in the audit history.
- `Mtrl.list_assertions(as_of_revision=...)` reads the claim state at any past revision.
- `resolve_external_evidence()` checks cross-archive evidence offline against the archives you
  supply. Loading an archive never opens another archive.

The `mtrl.ml` package prepares training and evaluation datasets across saved archives with
`build_ml_dataset()` and `DatasetSpec`:

- `FeatureChannelSpec` selects committed checkpoint states and runs governed operations in
  memory; `GridAlignmentSpec` aligns heterogeneous spectra onto one coordinate grid.
- `TargetSpec` extracts labels or values from active assertions, and `FilterSpec` removes
  duplicate sources and excluded runs with machine-readable reasons.
- `MLDataset.split_grouped()` partitions rows by `sample_uid` or another group without
  leakage, and the provenance manifest holds one canonical `dataset_digest`.
- `MLDataset.to_sklearn()` needs no scikit-learn. `to_torch_dataset()`, `to_tf_dataset()`, and
  `log_to_mlflow()` load their frameworks lazily, and `to_pandas()` needs the `tabular` extra.

The base install imports `mtrl.assertions` and `mtrl.ml` without SciPy, pandas, or any external
ML framework. Read `docs/user/how-to/record-scientific-assertions.md` and
`docs/user/how-to/prepare-an-ml-dataset.md` for runnable examples of both workflows.

## Archive and provenance limits

MTRL reads `.mtrl` archives inside configured size and member limits, and it validates paths,
entries, JSON, references, payloads, and integrity before it returns data. It does not extract
archive files.

Archive content does not install packages, does not import operation code, does not change a
registry, does not execute stored source, and does not change committed records directly.
Committed records are immutable: use `Mtrl` methods to create a new record version or change the
active view.

New archives require integrity coverage. Keep a receipt outside the archive if you need to
detect a complete rewrite. A receipt has no signature, so send it through a separate trusted
channel. `forensic_inspect()` reports damaged archive facts, but it does not return damaged data
for normal analysis. MTRL verifies digests and never verifies your execution environment:
environment records are author claims, not checked facts.

## Licence

The core is licensed under the MPL-2.0. Read the licence text in `LICENSE` and the inherited
notices in `NOTICE`, both included in this distribution. The upstream licence reference is
https://www.mozilla.org/en-US/MPL/2.0/.
