Skip to main content

ZeroModel

ZeroModel turns scored data into deterministic, inspectable Visual Policy Map artifacts and small consumers that can operate without a model at decision time.

A VPM is a deterministic spatial view over a table of scored items. It carries values, stable row and metric identifiers, a layout recipe, view ordering, source mapping, provenance, and deterministic identity.

The package is now the clean ZeroModel 1.0 surface. There is no public zeromodel.v2 namespace: import directly from zeromodel.

Public claims are tracked in docs/claims-audit.md. Treat that file as the source of truth for what is validated, what is implemented with thin evidence, and what remains a roadmap claim.

Install

Current GitHub install:

python -m pip install "git+https://github.com/ernanhughes/zeromodel.git@main"

After the production PyPI release is cut:

python -m pip install zeromodel==1.0.12

For development:

python -m pip install -e .[dev]
python scripts/run_fast_tests.py
python -m build
python -m twine check dist/*

Release steps are documented in docs/release.md.

Core artifact

from zeromodel import LayoutRecipe, ScoreTable, build_vpm

score_table = ScoreTable(
    values=[[0.9, 0.2], [0.4, 0.8]],
    row_ids=["candidate-a", "candidate-b"],
    metric_ids=["quality", "uncertainty"],
)

recipe = LayoutRecipe.from_dict({
    "version": "vpm-layout/0",
    "name": "quality-first",
    "row_order": {
        "kind": "lexicographic",
        "keys": [{"metric_id": "quality", "direction": "desc"}],
        "tie_break": "row_id",
    },
    "column_order": {"kind": "source"},
    "normalization": {"kind": "per_metric_minmax", "clip": True},
})

artifact = build_vpm(score_table, recipe)
cell = artifact.cell(view_row=0, view_column=0)
region = artifact.region(rows=slice(0, 1), columns=slice(0, 2))

Capability surface

Capability Module
Immutable artifact kernel zeromodel.artifact
State-addressed policy lookup / sign reader zeromodel.policy_lookup
Q-policy criticality and decision-margin evidence zeromodel.policy_diagnostics
Exhaustive finite policy properties and linked verification artifacts zeromodel.policy_properties
Dense policy views over the same source table zeromodel.views
Spatially optimized view profiles zeromodel.spatial
Temporal decision manifolds zeromodel.manifold
Metric alias packing and score-table building zeromodel.metrics
PHOS sort-pack and guarded top-left concentration zeromodel.phos
Visual AND/OR/NOT/XOR/add/subtract zeromodel.compose
Baseline-vs-target differential comparison zeromodel.compare
Lossless .vpm bundle serialization zeromodel.bundle
Dependency-light PNG/SVG rendering zeromodel.render
Hierarchical pyramids zeromodel.hierarchy
Edge top-left gates zeromodel.edge
Trend-aware EDIT/RESAMPLE/ESCALATE/STOP/SPINOFF control zeromodel.controller
Before/after/held-out/regression learning traces zeromodel.learning
Model-training progress artifacts zeromodel.training
Tracker-export adapters zeromodel.adapters
Critic/evidence/policy risk artifacts zeromodel.critic

Policy lookup: signs, not directions

VPMPolicyLookup is the small 1.0 consumer behind the blog phrase “signs, not directions.” Rows are discretized runtime states, metric columns are candidate actions, and the consumer returns the winning action plus the exact VPM cell that produced it.

from zeromodel import LayoutRecipe, ScoreTable, VPMPolicyLookup, build_vpm

source = ScoreTable(
    values=[
        [1.0, 0.0, 0.0, 0.0],
        [0.0, 1.0, 0.0, 0.0],
        [0.0, 0.0, 0.0, 1.0],
    ],
    row_ids=["state:left", "state:right", "state:aligned"],
    metric_ids=["LEFT", "RIGHT", "STAY", "FIRE"],
)
recipe = LayoutRecipe.from_dict({
    "version": "vpm-layout/0",
    "name": "policy-source-order",
    "row_order": {"kind": "source", "tie_break": "row_id"},
    "column_order": {"kind": "source"},
    "normalization": {"kind": "per_metric_minmax", "clip": True},
})

artifact = build_vpm(source, recipe)
decision = VPMPolicyLookup(artifact).read("state:aligned")

assert decision.action == "FIRE"
assert decision.artifact_id == artifact.artifact_id

The demo is a tiny arcade shooter:

python examples/arcade_shooter_policy.py

It compiles a closed-world shooter policy into one VPM artifact, then replays by reading state signs from that artifact. Tests assert wave clear, random-baseline comparison, and deterministic action trace replay.

See docs/examples/sign-reader.md.

Criticality-aware verification

ZeroModel 1.0.11 can add two separate evidence metrics to a Q-bearing policy surface:

criticality     = best action value - worst action value
decision margin = best action value - second-best action value

Criticality estimates how consequential a poor choice could be. Decision margin measures how decisively the winner beats its nearest alternative. Describe the first metric as VIPER-style criticality only when the source values are Q-values or an equivalent consequence-bearing teacher signal.

from zeromodel import (
    PolicyPropertyChecker,
    PolicyPropertySpec,
    VPMPolicyLookup,
    build_vpm,
    with_q_diagnostics,
)

ACTIONS = ("LEFT", "RIGHT", "STAY", "FIRE")

enriched = with_q_diagnostics(
    source,
    action_metric_ids=ACTIONS,
)
artifact = build_vpm(enriched, recipe)

# Diagnostic metadata lets the reader safely separate actions from evidence.
reader = VPMPolicyLookup(artifact)

Evidence metrics are returned with the decision but never participate in action selection.

A finite policy property is declarative and versioned:

fire_requires_alignment = PolicyPropertySpec.from_dict({
    "id": "fire_requires_alignment",
    "version": "1",
    "assert": {
        "implies": [
            {"eq": [{"var": "winner"}, "FIRE"]},
            {"all": [
                {"eq": [{"var": "state.tank"}, {"var": "state.target"}]},
                {"eq": [{"var": "state.cooldown"}, 0]},
            ]},
        ]
    },
})

report = PolicyPropertyChecker(
    artifact,
    action_metric_ids=ACTIONS,
    evidence_metric_ids=("criticality", "decision_margin"),
).check([fire_requires_alignment])

verification_artifact = report.to_vpm()

The verification artifact points back to the exact checked policy through a provenance parent with relation verifies. Failed checks retain exact counterexample rows, candidates, evidence, and source/view coordinates.

Run the full counterexample, repair, and re-verification fixture:

python examples/criticality_verification.py \
  --output-dir docs/assets/criticality-verification

See docs/examples/criticality-verification.md and docs/research/viper-policy-compilation.md.

Dense view profiles

A source table can contain many signals at once. A view profile is a policy lens over that dense table: turn up one set of metrics and the matching rows/columns become salient without changing the source evidence.

from zeromodel import ScoreTable, ViewProfile, build_view

source = ScoreTable(
    values=[
        [0.10, 0.96, 0.05, 0.72, 0.20],
        [0.94, 0.12, 0.08, 0.18, 0.35],
        [0.24, 0.07, 0.97, 0.08, 0.78],
        [0.07, 0.18, 0.04, 0.98, 0.10],
    ],
    row_ids=["forest", "crowd", "traffic", "meadow"],
    metric_ids=["people", "trees", "cars", "grass", "risk"],
)

people_view = build_view(source, ViewProfile.from_metric("people", name="people"))
tree_view = build_view(source, ViewProfile.from_metric("trees", name="trees"))
risk_view = build_view(source, ViewProfile.from_metric("risk", name="risk"))

assert people_view.source.digest == tree_view.source.digest == risk_view.source.digest
print(people_view.cell(0, 0).row_id)  # crowd
print(tree_view.cell(0, 0).row_id)    # forest
print(risk_view.cell(0, 0).row_id)    # traffic

Positive weights make high values salient. Negative weights make low values salient.

See docs/examples/view-profiles.md and docs/research/dense-multiview-representation.md.

Spatial optimizer

The spatial optimizer derives a ViewProfile for one explicit geometric objective: concentrate high-signal mass in the top-left inspection region.

from zeromodel import ScoreTable, SpatialOptimizer, build_optimized_view, optimize_view_profile

source = ScoreTable(
    values=[
        [0.10, 0.50, 0.20],
        [0.95, 0.50, 0.25],
        [0.90, 0.50, 0.15],
        [0.05, 0.50, 0.20],
    ],
    row_ids=["background", "target_a", "target_b", "flat"],
    metric_ids=["target", "constant", "weak"],
)

optimizer = SpatialOptimizer(Kc=2, Kr=2, alpha=0.95, max_evals=40)
result = optimize_view_profile(source, name="optimized-target", optimizer=optimizer)
view = build_optimized_view(source, name="optimized-target", optimizer=optimizer)

print(result.baseline_mass, result.optimized_mass)
print(view.cell(0, 0).row_id, view.cell(0, 0).metric_id)

This does not claim the optimizer learns the correct semantic view for every task. It proves a deterministic top-left mass objective can emit a normal ViewProfile while preserving source mapping.

See docs/examples/spatial-optimizer.md and docs/research/spatial-calculus.md.

Decision manifold

A decision manifold turns a sequence of dense scored panels into optimized VPM frames, then surfaces where the spatial view changes most.

from zeromodel import ScoreTable, SpatialOptimizer, build_decision_manifold

panels = [
    ScoreTable(
        values=[[0.20, 0.60, 0.10], [1.00, 0.10, 0.10], [0.10, 0.20, 0.30]],
        row_ids=["forest", "crowd", "traffic"],
        metric_ids=["people", "trees", "risk"],
    ),
    ScoreTable(
        values=[[0.15, 0.55, 0.14], [0.25, 0.10, 0.30], [0.10, 0.18, 1.00]],
        row_ids=["forest", "crowd", "traffic"],
        metric_ids=["people", "trees", "risk"],
    ),
]

summary = build_decision_manifold(
    panels,
    optimizer=SpatialOptimizer(Kc=1, Kr=1),
    name="scene-shift",
    inflection_top_k=1,
)

print(summary.inflection_indices)
print(summary.mass_series)
print(summary.curvature_series)

This does not claim semantic cause or universal change-point discovery. It provides deterministic temporal geometry over scored panels.

See docs/examples/decision-manifold.md and docs/research/temporal-spatial-calculus.md.

PHOS and edge usage

from zeromodel import TopLeftGate, guarded_pack_artifact, write_png

packed = guarded_pack_artifact(artifact)
write_png(packed.packed, "artifact_phos.png")
result = TopLeftGate(threshold=0.75).evaluate(packed.packed)
print(result.accepted, result.score)

Learning trace usage

Tracking means a score moved. Learning means a feedback-driven change improves corrected work, transfers to held-out work, and avoids unacceptable regression.

from zeromodel import LearningObservation, build_learning_vpm

assessment = build_learning_vpm([
    LearningObservation("claim-support", before=0.42, after=0.72, split="train"),
    LearningObservation("related-claim", before=0.50, after=0.63, split="heldout"),
    LearningObservation("summary-quality", before=0.82, after=0.81, split="regression"),
])

print(assessment.learned)
learning_artifact = assessment.artifact

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

zeromodel-1.0.12.tar.gz (484.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

zeromodel-1.0.12-py3-none-any.whl (384.8 kB view details)

Uploaded Python 3

File details

Details for the file zeromodel-1.0.12.tar.gz.

File metadata

  • Download URL: zeromodel-1.0.12.tar.gz
  • Upload date:
  • Size: 484.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.4

File hashes

Hashes for zeromodel-1.0.12.tar.gz
Algorithm Hash digest
SHA256 ceed738f2fd3e82fdbcf5cf24d37139a1f90e956d92c18c5a40ee9a47617319a
MD5 0b7a92d14e2aa3ee94b2461555d66331
BLAKE2b-256 6bcef83af5168104a4c91c8bb189665a780a56ad0925a62dfe392db764fe3237

See more details on using hashes here.

File details

Details for the file zeromodel-1.0.12-py3-none-any.whl.

File metadata

  • Download URL: zeromodel-1.0.12-py3-none-any.whl
  • Upload date:
  • Size: 384.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.4

File hashes

Hashes for zeromodel-1.0.12-py3-none-any.whl
Algorithm Hash digest
SHA256 297eee437c20dc5e474e82713bee59728f1729a78546ba6a4018e39c63b8b945
MD5 07272ddc9a23e2c3f955240bb177577c
BLAKE2b-256 b9962899b7d1f0842ee6d7b429d904c67958993ec45400d9ffafd707d5561028

See more details on using hashes here.

Release history Release notifications | RSS feed

1.2.0

1 file

1.1.0

1 file

This release

1.0.12 This release

2 files

1.0.11

2 files

1.0.9

2 files

1.0.8

2 files

1.0.7

2 files

1.0.6

2 files

1.0.5

2 files

1.0.4

2 files

1.0.2

2 files

1.0.1

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page