1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
//! # pldag — Primitive Logic Directed Acyclic Graphs
//!
//! `pldag` lets you build, evaluate, and reason about boolean logic expressed
//! as a DAG of primitive variables and linear-combination constraints.
//!
//! It is useful for modelling configuration rules, feature flags with
//! dependencies, product configurators, or any domain where the question
//! _"given these inputs, which outputs are forced to true / false / unknown?"_
//! must be answered repeatedly and quickly.
//!
//! ## Concepts
//!
//! - **[`Pldag`]** — the editable model. Add primitive variables and logical
//! constraints (AND, OR, XOR, NOT, at-least, at-most, equal, …). Backed by
//! a pluggable async [`NodeStoreTrait`] so the same model can live in memory
//! or in a database.
//! - **[`CompiledDag`]** — a compact, immutable, indexed snapshot of a `Pldag`,
//! produced by [`Pldag::dag`]. Optimised for fast propagation.
//! - **Propagation** — given assignments for some variables,
//! [`CompiledDag::propagate`] tightens the bounds of every reachable node.
//! For hot loops, [`CompiledDag::propagate_with_scratch`] reuses buffers via
//! a [`Scratch`].
//! - **Polyhedra** — [`SparsePolyhedron`] and [`DensePolyhedron`] turn the DAG
//! into a system of linear inequalities suitable for ILP solvers.
//!
//! ## Quick start
//!
//! ```no_run
//! use pldag::{Pldag, Scratch};
//!
//! # async fn run() -> Result<(), Box<dyn std::error::Error>> {
//! let model = Pldag::new();
//! model.set_primitive("a", (0, 1)).await?;
//! model.set_primitive("b", (0, 1)).await?;
//! let root = model.set_and(vec!["a", "b"]).await?;
//!
//! // Compile once, propagate many times.
//! let dag = model.dag().await?;
//! let mut scratch = Scratch::new();
//!
//! let result = dag.propagate_with_scratch(
//! [("a", (1, 1)), ("b", (1, 1))],
//! &mut scratch,
//! )?;
//! assert_eq!(result.get(&root).unwrap(), &(1, 1));
//! # Ok(())
//! # }
//! ```
//!
//! ## Errors
//!
//! Fallible operations return one of two precise result types:
//!
//! - [`ComputeResult<T>`] — pure in-memory operations on a [`CompiledDag`]
//! (propagation, tightening, ranks, polyhedron conversion). Errors are
//! modelled by [`ComputeError`].
//! - [`ModelResult<T>`] — operations that read or mutate the model's storage
//! (`set_*`, `delete_node`, `dag`, `sub_dag`, `get_node`). Errors are
//! modelled by [`ModelError`], which wraps backend-level [`StorageError`]s.
//!
//! The two enums are disjoint: no variant is shared, so each function signature
//! precisely describes its failure modes.
pub use ;
pub use ;
pub use ;