Propositional Logic Directed Acyclic Graph (PL‑DAG)
A PL-DAG is a directed acyclic graph where each leaf defines a discrete integer domain (e.g., x ∈ [-5, 3]) and each internal node defines a linear inequality over its predecessors. The graph therefore represents a structured system of discrete constraints, allowing arbitrary compositions of integer ranges and linear relations while naturally sharing repeated sub-expressions.
PL-DAGs are especially well suited for describing and solving discrete optimization problems—problems where you want to make the best possible choice under a set of rules. Typical examples include:
-
Choosing the best product configuration given technical constraints
-
Optimizing costs or performance while respecting limits
-
Selecting combinations of components that must work together
-
Modeling resource limits, capacities, or integer-valued decisions
-
Exploring what combinations of values are feasible or optimal
Because the PL-DAG breaks everything into small, reusable pieces, it becomes easy to build complex models from simple parts and to solve them with efficient algorithms.
✨ Key Features
| Area | What you get |
|---|---|
| Modelling | Build Boolean/linear constraint systems in a single graph representation. |
| Analysis | Fast bound‑propagation (propagate*). |
| Export | to_sparse_polyhedron() generates a polyhedral ILP model ready for any solver. |
| 🧩 Optional solver | Turn on the glpk feature to link against GLPK and solve in‑process. |
Install
1 — Modelling‑only (MIT licence)
This pulls no GPL code; you can ship the resulting binary under any licence compatible with MIT.
2 — Modelling + in‑process GLPK solver (GPL v3+ applies)
Enabling the glpk feature links to the GNU Linear Programming Kit (GLPK). If you distribute a binary built with this feature you must meet the requirements of the GPL‑3.0‑or‑later.
Heads‑up: Leaving the feature off keeps all code MIT‑licensed. The choice is completely under your control at
cargo buildtime.
Core Routines
Analysis & Propagation
propagate
Propagates bounds bottom‑up through the DAG and returns a map of node → bound ((min, max)).
propagate_default
;
Convenience method that propagates using default bounds of all primitive variables.
Building the Model
Primitive Variables
;
Create primitive (leaf) variables with specified bounds. set_primitives creates multiple variables with the same bounds.
Linear Constraints
Creates a general linear inequality: sum(coeff_i * var_i) + bias >= 0.
set_atleast: Creates sum(variables) >= value
set_atmost: Creates sum(variables) <= value
set_equal: Creates sum(variables) == value
Logical Constraints
Standard logical operations:
set_and: ALL variables must be trueset_or: AT LEAST ONE variable must be trueset_not: NONE of the variables can be trueset_xor: EXACTLY ONE variable must be trueset_nand: NOT ALL variables can be trueset_nor: NONE of the variables can be trueset_xnor: EVEN NUMBER of variables must be true (including zero)
set_imply: Creates condition → consequence (implication)
set_equiv: Creates lhs ↔ rhs (equivalence/biconditional)
Export & Solving
to_sparse_polyhedron
;
Emits a sparse polyhedral representation suitable for ILP solvers (GLPK, CPLEX, Gurobi, …).
SparsePolyhedron implements serde::Serialize, so you can ship it over HTTP to a remote solver service if you prefer.
solve (Optional GLPK Feature)
;
Solves integer linear programming problems using GLPK. Takes multiple objective functions, fixed variable assumptions, and returns optimal assignments.
Quick Example
use IndexMap;
use ;
// Build a simple OR‑of‑three model
let mut pldag = new;
pldag.set_primitive;
pldag.set_primitive;
pldag.set_primitive;
let root = pldag.set_or;
// Validate a combination
let validated = pldag.propagate_default.unwrap;
println!;
3. Solving with GLPK (Optional Feature)
When the glpk feature is enabled, you can solve optimization problems directly:
use HashMap;
use ;
// Build a simple problem: maximize x + 2y + 3z subject to x ∨ y ∨ z
let mut pldag = new;
pldag.set_primitive;
pldag.set_primitive;
pldag.set_primitive;
let root = pldag.set_or;
// Set up the objective function: maximize x + 2y + 3z
let mut objective = new;
objective.insert;
objective.insert;
objective.insert;
// Constraints: require that the OR constraint is satisfied
let mut assumptions = new;
assumptions.insert; // root must be true
// Solve the optimization problem
let solutions = pldag.solve;
if let Some = &solutions else
This example demonstrates:
- Problem setup: Creating boolean variables and logical constraints
- Objective function: Defining what to optimize (maximize x + 2y + 3z)
- Assumptions: Fixing certain variables or constraints (root must be true)
- Solving: Using GLPK to find the optimal solution
- Result interpretation: Extracting variable values from the solution
Notes
- All
set_*functions accept any iterable type that can be converted to strings via theToStringtrait, providing maximum flexibility.
License
- Library code: MIT (permissive).
- Optional solver: If you build with
--features glpk, you link against GLPK, which is GPL‑3.0‑or‑later. Distributing such a binary triggers the GPL’s obligations.
You choose the trade‑off: leave the feature off for a fully permissive dependency tree, or enable it for a batteries‑included ILP solver.
Enjoy building and evaluating logical models with PL‑DAG! 🎉