{"id":41703506,"url":"https://github.com/pflow-xyz/pflow-rs","last_synced_at":"2026-03-09T06:03:11.139Z","repository":{"id":339313622,"uuid":"1160928981","full_name":"pflow-xyz/pflow-rs","owner":"pflow-xyz","description":"Petri net modeling with ODE simulation and token model DSL — Rust port of go-pflow","archived":false,"fork":false,"pushed_at":"2026-02-26T15:59:41.000Z","size":901,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-26T20:26:34.812Z","etag":null,"topics":["dsl","ode-solver","petri-net","proc-macro","rust","state-machine","token-model"],"latest_commit_sha":null,"homepage":"https://pflow.xyz","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pflow-xyz.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-18T14:38:27.000Z","updated_at":"2026-02-26T16:04:31.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/pflow-xyz/pflow-rs","commit_stats":null,"previous_names":["pflow-xyz/pflow-rs"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/pflow-xyz/pflow-rs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pflow-xyz%2Fpflow-rs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pflow-xyz%2Fpflow-rs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pflow-xyz%2Fpflow-rs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pflow-xyz%2Fpflow-rs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pflow-xyz","download_url":"https://codeload.github.com/pflow-xyz/pflow-rs/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pflow-xyz%2Fpflow-rs/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30284632,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-09T02:57:19.223Z","status":"ssl_error","status_checked_at":"2026-03-09T02:56:26.373Z","response_time":61,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dsl","ode-solver","petri-net","proc-macro","rust","state-machine","token-model"],"created_at":"2026-01-24T21:05:02.006Z","updated_at":"2026-03-09T06:03:11.101Z","avatar_url":"https://github.com/pflow-xyz.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# pflow-rs\n\nRust port of [go-pflow](https://github.com/pflow-xyz/go-pflow) — Petri net modeling with ODE simulation and token model DSL.\n\n**Paper:** [Incidence Reduction: Extracting Exact Strategic Values from Game Topologies via Petri Net ODE Equilibrium](https://github.com/pflow-xyz/pflow-rs/releases/latest/download/integer-reduction-draft.pdf)\n\n## Crates\n\n| Crate | Description |\n|-------|-------------|\n| `pflow-core` | Petri net types (Place, Transition, Arc), fluent Builder API, state map utilities |\n| `pflow-solver` | ODE solvers (Tsit5, RK45, RK4, Euler, Heun, Midpoint, BS32), implicit methods, equilibrium detection |\n| `pflow-tokenmodel` | Token model schema, snapshot, runtime execution, validation, content-addressed identity |\n| `pflow-dsl` | S-expression DSL: lexer, parser, interpreter, builder, codegen |\n| `pflow-macros` | `schema!` proc macro — compile-time DSL parsing with zero runtime overhead |\n| `pflow-zk` | ZK proof traits (`PetriProver`), `IncidenceMatrix` extraction, `fire_transition()` |\n| `pflow-zk-arkworks` | Groth16 prover over BN254 with Poseidon hashing (structural R1CS) |\n| `pflow-zk-risc0` | risc0 zkVM STARK prover (simulation mode default; real proofs with `prove` feature) |\n| `pflow` | Umbrella crate re-exporting all of the above |\n\n## Quick Start\n\n```rust\nuse pflow::*;\n\n// Build an SIR epidemic model\nlet (net, rates) = PetriNet::build()\n    .sir(999.0, 1.0, 0.0)\n    .with_rates(1.0);\n\n// Solve to equilibrium\nlet state = net.set_state(None);\nlet prob = Problem::new(net, state, [0.0, 100.0], rates);\nlet (final_state, reached) = find_equilibrium(\u0026prob);\n\nassert!(reached);\n// S + I + R = 1000 (conserved)\n```\n\n## Petri Net Builder\n\n```rust\nuse pflow_core::PetriNet;\n\nlet net = PetriNet::build()\n    .place(\"A\", 10.0)\n    .place(\"B\", 0.0)\n    .transition(\"t1\")\n    .arc(\"A\", \"t1\", 1.0)\n    .arc(\"t1\", \"B\", 1.0)\n    .done();\n```\n\nChain helper for linear sequences:\n\n```rust\nlet net = PetriNet::build()\n    .chain(1.0, \u0026[\"start\", \"t1\", \"middle\", \"t2\", \"end\"])\n    .done();\n```\n\n## ODE Solver\n\nSeven explicit Runge-Kutta methods plus implicit solvers for stiff systems:\n\n```rust\nuse pflow_solver::*;\n\nlet prob = Problem::new(net, state, [0.0, 100.0], rates);\n\n// Explicit (adaptive step size)\nlet sol = solve(\u0026prob, \u0026methods::tsit5(), \u0026Options::default_opts());\n\n// Implicit (stiff systems)\nlet sol = implicit::implicit_euler(\u0026prob, \u0026Options::stiff());\nlet sol = implicit::trbdf2(\u0026prob, \u0026Options::stiff());\n\n// Auto-detect stiffness\nlet sol = implicit::solve_implicit(\u0026prob, \u0026Options::default_opts());\n```\n\n**Solver presets:**\n\n| Preset | Use Case |\n|--------|----------|\n| `Options::default_opts()` | General purpose |\n| `Options::fast()` | Game AI, interactive (~10x faster) |\n| `Options::accurate()` | Research, publishing |\n| `Options::game_ai()` | Move evaluation |\n| `Options::epidemic()` | SIR/SEIR models |\n\n## Token Model DSL\n\nDefine token model schemas using an S-expression DSL. The `schema!` macro parses and validates the DSL at compile time — syntax errors become compiler errors, and the generated code constructs the `Schema` directly with zero runtime parsing.\n\n```rust\nuse pflow::schema;\n\nlet s = schema!(r#\"\n(schema ERC-020\n  (version v1.0.0)\n  (states\n    (state balances :type map[address]uint256 :exported)\n    (state totalSupply :type uint256)\n  )\n  (actions\n    (action transfer :guard {balances[from] \u003e= amount})\n  )\n  (arcs\n    (arc balances -\u003e transfer :keys (from))\n    (arc transfer -\u003e balances :keys (to))\n  )\n  (constraints\n    (constraint conservation {sum(balances) == totalSupply})\n  )\n)\n\"#);\n\nassert_eq!(s.name, \"ERC-020\");\nassert_eq!(s.actions[0].guard, \"balances[from] \u003e= amount\");\n```\n\nInvalid DSL is caught at compile time:\n\n```rust\n// This won't compile:\nlet s = schema!(r#\"(bad input)\"#);\n// error: DSL parse error: expected symbol \"schema\", got \"bad\"\n```\n\n### DSL Syntax Reference\n\n```scheme\n(schema \u003cname\u003e\n  (version \u003cversion\u003e)\n\n  (states\n    (state \u003cid\u003e :kind token :initial \u003cn\u003e)          ; token state with initial count\n    (state \u003cid\u003e :type \u003ctype\u003e :exported)             ; data state, exported\n  )\n\n  (actions\n    (action \u003cid\u003e)                                    ; simple action\n    (action \u003cid\u003e :guard {\u003cexpr\u003e})                    ; guarded action\n  )\n\n  (arcs\n    (arc \u003csource\u003e -\u003e \u003ctarget\u003e)                       ; simple arc\n    (arc \u003csource\u003e -\u003e \u003ctarget\u003e :keys (\u003ck1\u003e \u003ck2\u003e))     ; arc with map keys\n    (arc \u003csource\u003e -\u003e \u003ctarget\u003e :value \u003cbinding\u003e)       ; arc with value binding\n  )\n\n  (constraints\n    (constraint \u003cid\u003e {\u003cexpr\u003e})                       ; invariant constraint\n  )\n)\n```\n\n### Alternative: Fluent Builder\n\nFor dynamic schema construction, use the builder API directly:\n\n```rust\nuse pflow_dsl::Builder;\n\nlet schema = Builder::new(\"ERC-020\")\n    .data(\"balances\", \"map[address]uint256\").exported()\n    .data(\"totalSupply\", \"uint256\")\n    .action(\"transfer\").guard(\"balances[from] \u003e= amount\")\n    .flow(\"balances\", \"transfer\").keys(\u0026[\"from\"])\n    .flow(\"transfer\", \"balances\").keys(\u0026[\"to\"])\n    .constraint(\"conservation\", \"sum(balances) == totalSupply\")\n    .must_schema();\n```\n\n### Runtime Parsing\n\nFor DSL strings loaded at runtime (e.g. from files):\n\n```rust\nuse pflow_dsl::parse_schema;\n\nlet schema = parse_schema(\u0026dsl_string).unwrap();\n```\n\n## Content-Addressed Identity\n\nSchemas produce deterministic content identifiers (CIDs) via SHA-256. Insertion order doesn't matter — schemas with the same structure always produce the same hash.\n\n```rust\nuse pflow::schema;\n\nlet s = schema!(r#\"(schema counter\n  (states (state count :kind token :initial 5))\n  (actions (action inc))\n  (arcs (arc inc -\u003e count))\n)\"#);\n\n// Full CID (includes name/version)\nlet cid = s.cid();           // \"cid:a1b2c3...\"\n\n// Structural fingerprint (ignores name/version)\nlet idh = s.identity_hash(); // \"idh:d4e5f6...\"\n\n// Compare schemas\nassert!(s.equal(\u0026s));                // same CID\nassert!(s.structurally_equal(\u0026s));   // same structure\n```\n\n## Runtime Execution\n\n```rust\nuse pflow_tokenmodel::{Runtime, Bindings};\nuse serde_json::Value;\n\nlet mut rt = Runtime::new(schema);\n\n// Set initial balance\nrt.snapshot.set_data_map_value(\"balances\", \"alice\", Value::Number(1000.into()));\n\n// Execute a transfer\nlet mut bindings = Bindings::new();\nbindings.insert(\"from\".into(), Value::String(\"alice\".into()));\nbindings.insert(\"to\".into(), Value::String(\"bob\".into()));\nbindings.insert(\"amount\".into(), Value::Number(250.into()));\n\nrt.execute_with_bindings(\"transfer\", \u0026bindings).unwrap();\n// alice: 750, bob: 250\n```\n\n## State Utilities\n\n```rust\nuse pflow_core::stateutil;\n\nlet state = /* ... */;\nlet updated = stateutil::apply(\u0026state, \u0026updates);\nlet total = stateutil::sum(\u0026state);\nlet changes = stateutil::diff(\u0026before, \u0026after);\nlet history = stateutil::filter(\u0026state, |k| k.starts_with('_'));\n```\n\n## Code Generation\n\nGenerate Rust source from DSL definitions:\n\n```rust\nuse pflow_dsl::generate_rust_from_dsl;\n\nlet code = generate_rust_from_dsl(dsl_input, \"mymodule\", \"make_schema\").unwrap();\n// Outputs a Rust function that constructs the schema\n```\n\n## ZK Proofs\n\nTwo contrasting strategies prove the same statement — \"transition T is enabled and transforms marking M into M'\":\n\n- **arkworks (structural R1CS)**: compiles net topology into Groth16 constraints over BN254 with Poseidon hashing. Constant 128-byte proofs, sub-millisecond verification.\n- **risc0 (zkVM STARK)**: wraps transition logic in a RISC-V guest program. No trusted setup, but larger proofs and slower proving.\n\n```rust\nuse pflow_zk::{IncidenceMatrix, PetriProver, TransitionWitness, fire_transition};\nuse pflow_zk_arkworks::ArkworksProver;\n\nlet net = PetriNet::build().sir(999.0, 1.0, 0.0).done();\nlet matrix = IncidenceMatrix::from_petri_net(\u0026net);\n\nlet mut prover = ArkworksProver::new(matrix.clone());\nprover.setup().unwrap();\n\nlet pre = matrix.initial_marking(\u0026net);\nlet post = fire_transition(\u0026matrix, \u0026pre, 0).unwrap();\nlet witness = TransitionWitness { pre_marking: pre, transition_id: 0, post_marking: post };\n\nlet proof = prover.prove(\u0026witness).unwrap();\nassert!(prover.verify(\u0026proof).unwrap());\nassert_eq!(proof.metrics.proof_size_bytes, 128);\n```\n\n### Benchmarks\n\nHead-to-head comparison using NxN tic-tac-toe nets (3n² places, 2n² transitions):\n\n```\ncargo run --example zk_compare -p pflow --features zk-arkworks,zk-risc0-prove --release\n```\n\n| Model | System | Places | Trans | Setup | Prove | Verify | Proof Size |\n|-------|--------|--------|-------|-------|-------|--------|------------|\n| SIR | groth16-bn254 | 3 | 2 | 26ms | 18ms | 1.0ms | 128B |\n| SIR | risc0 | 3 | 2 | 0ms | 3.0s | 9.5ms | 217KB |\n| TTT 3x3 | groth16-bn254 | 27 | 18 | 67ms | 78ms | 0.8ms | 128B |\n| TTT 3x3 | risc0 | 27 | 18 | 0ms | 6.1s | 10ms | 239KB |\n| TTT 5x5 | groth16-bn254 | 75 | 50 | 176ms | 189ms | 0.8ms | 128B |\n| TTT 5x5 | risc0 | 75 | 50 | 0ms | 12.1s | 11ms | 250KB |\n| TTT 10x10 | groth16-bn254 | 300 | 200 | 654ms | 709ms | 0.9ms | 128B |\n| TTT 10x10 | risc0 | 300 | 200 | 0ms | 51.8s | 13ms | 275KB |\n| TTT 20x20 | groth16-bn254 | 1200 | 800 | 2.6s | 2.8s | 0.9ms | 128B |\n| TTT 20x20 | risc0 | 1200 | 800 | 0ms | 2m47s | 48ms | 1.05MB |\n| TTT 40x40 | groth16-bn254 | 4800 | 3200 | 11.1s | 11.4s | 0.9ms | 128B |\n| TTT 40x40 | risc0 | 4800 | 3200 | 0ms | 10m55s | 160ms | 3.5MB |\n\nAt 4800 places / 3200 transitions: arkworks proves **57x faster**, verifies **178x faster**, with proofs **28,000x smaller**. Groth16 verification and proof size remain constant regardless of net size. risc0 trades performance for no trusted setup and simpler guest programming.\n\n### Feature Flags\n\n```toml\npflow = { features = [\"zk-arkworks\"] }       # Groth16 prover\npflow = { features = [\"zk-risc0\"] }          # risc0 simulation mode\npflow = { features = [\"zk-risc0-prove\"] }    # risc0 real STARK proofs (requires cargo risczero install)\n```\n\n## Dependencies\n\nMinimal external dependencies:\n\n- `serde`, `serde_json` — serialization\n- `sha2`, `hex` — content-addressed identity\n- `thiserror` — error types\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpflow-xyz%2Fpflow-rs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpflow-xyz%2Fpflow-rs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpflow-xyz%2Fpflow-rs/lists"}