Integrations Guide (v0.6.0 SCM)¶
This guide explains how to integrate ZeroProofML’s Signed Common Meadow (SCM) semantics with common ML stacks.
The key contract in v0.6.0:
- Use ⊥ (and/or a boolean mask) to represent singular/domain-error states.
- Keep the payload numeric and treat the mask as the “special value” channel.
Installing backends¶
ZeroProofML keeps backends optional.
From PyPI:
pip install "zeroproofml[torch]" # PyTorch integration
pip install "zeroproofml[jax]" # JAX integration
From a repo checkout:
pip install -e ".[torch]" # PyTorch integration
pip install -e ".[jax]" # JAX integration
You can also run a minimal integration check without pytest:
.venv/bin/python scripts/smoke_integrations.py
Python / NumPy¶
Ingesting external floats¶
Use the IEEE bridge to collapse NaN/Inf to ⊥ at the boundary:
from zeroproofml.utils.ieee_bridge import from_ieee
v = from_ieee(float("inf")) # -> ⊥
Vectorised arithmetic (payload + mask)¶
Use the scm_*_numpy helpers in zeroproofml.scm.ops:
import numpy as np
from zeroproofml.scm.ops import scm_mul_numpy
payload = np.array([1.0, 2.0, 3.0])
mask = np.array([False, True, False]) # mark ⊥
out, out_mask = scm_mul_numpy(payload, payload, mask, mask)
PyTorch¶
SCM rational heads¶
SCMRationalLayer returns an explicit bottom mask:
import torch
from zeroproofml.layers import SCMRationalLayer
layer = SCMRationalLayer(3, 2) # degrees (P, Q)
y, bottom = layer(torch.randn(128))
Use bottom for:
- coverage metrics (1 - bottom.float().mean())
- inference decoding (NaN sentinel or explicit rejection)
- rejection loss inputs (zeroproofml.losses.rejection_loss)
Loss wiring pattern¶
Most training loops follow:
1) model returns (y, bottom_mask) (or projective tuple outputs)
2) compute fit loss on decoded values
3) add SCM regularisers (margin/sign/rejection) using zeroproofml.losses.SCMTrainingLoss
JAX¶
The v0.6.0 core provides vectorised SCM ops for JAX via scm_*_jax (payload + mask).
Projective tuple tooling is implemented in zeroproofml.autodiff.projective for the conceptual contract; for high-performance JAX training, treat it as a reference implementation and port the same mask/threshold logic into your JIT-ed code.
Export / tooling¶
⊥is exported as IEEENaNby default (zeroproofml.utils.ieee_bridge) so standard tooling can ignore/reject invalid predictions.- Keep raw
bottom_maskalongside payloads if you need to distinguish “model refused” vs “numerically NaN” in downstream systems.
Minimal bundle service decision¶
A minimal REST service around validated ONNX bundles is worthwhile as an
optional integration surface for non-ROS consumers, but it should stay a thin
adapter over load_onnx_runtime_bundle(...) and remain outside the base install
dependencies. gRPC is deferred until a concrete deployment needs binary tensor
transport, streaming, or a maintained protobuf contract. See
docs/29_rest_grpc_bundle_service_decision.md.
Triton-style inference-server decision¶
Triton or a similar inference server is useful as a downstream deployment
recipe after the ONNX Runtime bundle path is stable, but it should not become a
first-party runtime path or base dependency yet. A future recipe should convert
validated bundles into a model-repository layout, preserve metadata.json as
the strict-inference semantic sidecar, and smoke-test decoded,
bottom_mask, and gap_mask parity against load_onnx_runtime_bundle(...).
Add Triton containers, CI, or client code only after a deployment needs dynamic
batching, multi-model hosting, GPU scheduling, standardized server metrics, or
an existing Triton/KServe-compatible serving platform. See
docs/30_triton_inference_server_decision.md.
ROS 2 beta companion path¶
The planned first-party ROS 2 beta stays in this repository under
integrations/ros2/ as an optional companion workspace. The root
pyproject.toml stays ROS-free; colcon / ament metadata, launch files, and
ROS-specific tests live under that workspace instead. See
docs/26_ros2_repo_layout_decision.md for the recorded layout decision. The
bootstrap src/zeroproofml_ros/ package is an ament_python bridge that
currently re-exports the stable Python strict-inference and ONNX runtime
surfaces so the first ROS node can reuse them directly. The companion workspace
now also ships the ROS-only zeroproofml_msgs package at
src/zeroproofml_msgs/ with
msg/StrictInferenceResult.msg, carrying flattened decoded payloads, merged
bottom_mask / gap_mask, bundle and schema metadata, threshold metadata,
and optional stable provenance slots (fault_mask +
semantic_bottom_mask or bottom_provenance). The recorded bundle-loading
decision for that first node is params-first: the node should take a startup
bundle_dir ROS parameter and defer any reload service until a later
lifecycle-managed path exists. The first implementation now lives at
integrations/ros2/src/zeroproofml_ros/zeroproofml_ros/strict_inference_node.py
as the strict_inference_node entry point: it subscribes to
std_msgs/msg/Float64MultiArray, publishes
zeroproofml_msgs/msg/StrictInferenceResult, and emits
diagnostic_msgs/msg/DiagnosticArray summaries while reusing the root ONNX
runtime helpers. It also publishes a standard
std_msgs/msg/Float64MultiArray telemetry vector on telemetry_topic for
Foxglove/PlotJuggler-style plots; the vector follows
VISUALIZATION_TELEMETRY_FIELDS, covering batch mask counts, running mask
rates, explicit per-batch bottom/gap/provenance rates, n_updates, and
fallback metrics including fallback_rate, fault_fallback_rate,
semantic_fallback_rate, plus routing counts/rates with missing optional
fields as NaN. If the loaded bundle records
fallback_policy_id="route_to_analytic_solver", those diagnostics also expose
fallback-routing counts/rates plus provenance-aware route-vs-reject fields when
available. For named exports outside the live ROS graph, the same ROS package
also exposes build_visualization_telemetry_row(...) and
write_visualization_telemetry_csv(...), which flatten those telemetry fields
into the stable VISUALIZATION_TELEMETRY_EXPORT_FIELDS CSV order for
PlotJuggler or other CSV-based tooling. The same ROS package exposes
build_workspace_heatmap_marker_overlay(...) and
build_workspace_heatmap_marker_array_message(...) so summaries from
plot_workspace_rate_heatmaps(...) can be published as RViz
visualization_msgs/msg/MarkerArray CUBE_LIST overlays for RR-style
workspace debugging. For per-sample spatial interpretation in the RR IK path,
build_rr_ik_result_marker_overlay(...) and
build_rr_ik_result_marker_array_message(...) render the current arm pose,
requested displacement, and accepted end-effector solution as RViz markers
from a strict-inference result payload. The strict-inference input/result topics accept a qos_preset
parameter: low_latency_control uses keep-last depth 1, best-effort, volatile
QoS for control loops, and offline_batch_replay uses keep-last depth 1000,
reliable, volatile QoS for deterministic rosbag or batch replay. For
deployments that need lifecycle orchestration, the same package
now also provides
integrations/ros2/src/zeroproofml_ros/zeroproofml_ros/lifecycle_strict_inference_node.py
as the lifecycle_strict_inference_node entry point; it keeps the same strict
inference bundle/message contract while moving bundle loading to
on_configure and gating input processing on lifecycle activation. See
docs/27_ros2_bundle_loading_decision.md. For the first domain-specific launch
path, integrations/ros2/src/zeroproofml_ros/launch/rr_ik_strict_inference.launch.py
plus config/rr_ik_strict_inference.yaml wire the reference robotics RR IK
bundle onto /rr_ik/strict_inference/* topics, including
/rr_ik/strict_inference/telemetry, and
zeroproofml_ros.rr_ik_demo provides a deterministic one-sample smoke run for
that same bundle contract. The companion
rr_ik_strict_inference_graph.launch.py example composes the strict-inference
node with a one-shot RR IK sample publisher plus result and telemetry echo
subscribers, giving a concrete small graph that users can replace with their
own planner, controller, rosbag replay, Foxglove, PlotJuggler, or monitoring
nodes. The companion package also includes the non-robotics
offline launch path
integrations/ros2/src/zeroproofml_ros/launch/dose_offline_batch.launch.py
with config/dose_offline_batch.yaml and
demo/dose_offline_batch_input.yaml, defaulting DOSE-style batch replay to
offline_batch_replay QoS on /dose/offline_batch/* topics, including
/dose/offline_batch/telemetry. For middleware
stability, the first beta currently
validates only rmw_cyclonedds_cpp (CycloneDDS) via the launch default,
package dependency, container images, and CI jobs; widening to a second RMW is
deferred until that Humble/Jazzy path is stable. See
docs/28_ros2_rmw_selection_decision.md. For reproducible ROS environments, the companion
workspace now also ships integrations/ros2/containers/manifest.json plus
ros2_humble_cpu.Dockerfile and ros2_jazzy_cpu.Dockerfile, covering
Humble/Jammy and Jazzy/Noble CPU images that preinstall onnxruntime, the root
zeroproofml checkout, and a built colcon workspace overlay. Treat any ROS 2
Kilted usage as experimental/manual-only until the existing Humble/Jazzy
coverage is stable; it is not part of the shipped container manifest or CI
matrix yet.