Implementation of build features F1–F3 from the sprint scope
(05_Srikanth_sprint_scope.docx), backed by the proofs in
PDCE_Research_Document_R1-R3.pdf and PDCE_Research_R1-R3.md.
A self-contained engine for systems that run in repeating, multi-phase stochastic cycles. It delivers three coupled, proven guarantees and exposes each as one API feature:
| Feature | API | Research result | Guarantee |
|---|---|---|---|
| F1 | pdce.dynamics.run |
R1 | Colored Stochastic Petri Net — bounded, live, convergent |
| F2 | pdce.control.act |
R2 | Active-inference selection = descent on the supplied objective |
| F3 | pdce.consistency.check |
R3 | Variational consistency guard with a detection bound |
pdce.dynamicsis an alias forpdce.cspn, matching the §5 naming.
The controller treats the objective as opaque (§4.2): it consumes only the scalar value and gradient through the interface, never the objective's meaning. The consistency guard runs ahead of any state-propagating action (§6/§7). The engine is deterministic given the same inputs and seed.
The Engine.run_coupled() method wires all three as three coupled pieces
over the running process: each CSPN phase transition (F1) triggers a guarded
control step (F2+F3).
- R1 ↔ R2: the CSPN's stable marking (stationary π, Theorem 3.8) is the operating point the controller drives toward; the controller's fixed point ∇J = 0 (Theorem 4.1) coincides with it — one gradient, not two competing dynamics (Remark 4.3).
- R3 → R2:
consistency.checkprecedescontrol.act; a flagged configuration blocks propagation and surfaces the implicated schema element for repair. - R1 ↔ R3: boundedness makes RS(M₀) finite, so the ELBO and its detection bound are well-defined on the markings the system can actually reach.
pdce/
__init__.py dynamics = cspn alias (§5 naming), exports
contract.py §6 interface records + Objective / ModularDecomposition
cspn.py F1 — CSPN model, Gillespie sim, boundedness/liveness/convergence
control.py F2 — EFE = steepest admissible descent (Theorem 4.1)
consistency.py F3 — ELBO score, log-evidence-ratio test, threshold calibration
engine.py wires F1+F2+F3: guard-ahead-of-act, run_coupled, seeded determinism
app.py FastAPI service exposing F1, F2, F3, and run_coupled as REST endpoints
fixtures/
quadratic.py §4.5 published R2 contract fixture (d=4 quadratic, A=diag(4,3,2,1))
injection.py §5.5 published R3 contract fixture (valid gen + violation injection)
tests/ contract-conformance tests for F1, F2, F3 and the engine
The PDCE engine is fully exposed as a RESTful service via FastAPI. It provides individual endpoints for F1, F2, and F3, plus a coupled endpoint that wires all three together over the running process.
Run the Server:
uvicorn app:app --reload --port 8000- Swagger UI: http://localhost:8000/docs
- Documentation: See
PDCE_API_Implementation.mdfor full request/response schemas, failure modes, and architectural details.
pip install -r requirements.txt
python -m pytest -q # 42 contract-conformance tests
python demo.py # end-to-end multi-module runimport numpy as np
from pdce import dynamics, control, consistency
from pdce.contract import CallableObjective, ModularDecomposition
# F1 — run the cyclic CSPN, get trajectory + diagnostics + convergence
net = dynamics.cyclic_net(K=3, n_mod=2, rates=[1.0, 2.0, 4.0])
traj = dynamics.run(net, horizon=200, seed=0)
traj.bounded, traj.live, traj.converged # -> (True, True, True)
traj.spectral_gap # -> positive (Theorem 3.8)
traj.stationary_distribution # -> {marking: probability}
# F2 — next objective-reducing move (action + predicted delta)
J = lambda x: 0.5 * float(x @ np.diag([4,3,2,1]) @ x)
gJ = lambda x: np.diag([4,3,2,1]) @ x
obj = CallableObjective(J, gJ)
rec = control.act(np.ones(4), obj, ModularDecomposition.trivial(4), eta=0.1)
rec.action, rec.predicted_delta # Delta s(a*) = -eta grad J
# F3 — score a configuration for consistency
from pdce.consistency import GaussianField, Schema
schema = Schema([GaussianField("timeout", mean=30, sigma=2, tau=2)])
out = consistency.check(schema, {"timeout": 31.0}, theta=0.0)
out.p_violation, out.element, out.confidence
# F1+F2+F3 coupled — three pieces wired over the running process
from pdce.engine import Engine
eng = Engine(
objective=obj, schema=schema,
decomposition=ModularDecomposition.trivial(4),
config_from_state=lambda x: {"timeout": float(x[0])},
net=net, theta=1e6, eta=0.1, seed=0,
)
steps, traj = eng.run_coupled(np.ones(4), horizon=50)See pdce/*.py docstrings for the equation-by-equation crosswalk to the
research document (Appendix B symbol-to-code map).