Pldag

Struct Pldag 

Source
pub struct Pldag {
    pub nodes: IndexMap<String, Node>,
}
Expand description

A Primitive Logic Directed Acyclic Graph (PL-DAG).

The PL-DAG represents a logical system where:

  • Primitive nodes are leaf variables with bounds
  • Composite nodes represent logical constraints over other nodes
  • Each node has an associated coefficient for accumulation operations

The DAG structure ensures no cycles and enables efficient bottom-up propagation.

Fields§

§nodes: IndexMap<String, Node>

Map from node IDs to their corresponding nodes

Implementations§

Source§

impl Pldag

Source

pub fn new() -> Pldag

Creates a new empty PL-DAG.

§Returns

A new Pldag instance with no nodes

Examples found in repository?
examples/readme_example.rs (line 8)
4fn main() {
5    // Build your PL-DAG
6    // For example, we create a model of three boolean variables x, y and z.
7    // We bind them to an OR constraint.
8    let mut pldag: Pldag = Pldag::new();
9
10    // First setup the primitive variables
11    pldag.set_primitive("x".to_string(), (0, 1));
12    pldag.set_primitive("y".to_string(), (0, 1));
13    pldag.set_primitive("z".to_string(), (0, 1));
14
15    // A reference ID is returned
16    let root = pldag.set_or(vec![
17        "x".to_string(),
18        "y".to_string(),
19        "z".to_string(),
20    ]);
21
22    // 1. Validate a combination:
23    let mut inputs: IndexMap<String, Bound> = IndexMap::new();
24    let validated = pldag.propagate(&inputs);
25    // Since nothing is given, and all other variables implicitly have bounds (0, 1) from the pldag model,
26    // the root will be (0,1) since there's not enough information to evaluate the root `or` node.
27    println!("Root valid? {}", *validated.get(&root).unwrap() == (1, 1)); // This will be false
28
29    // If we however fix x to be zero, then we can check the result
30    inputs.insert("x".to_string(), (0,0));
31    let revalidated = pldag.propagate(&inputs);
32    println!("Root valid? {}", *revalidated.get(&root).unwrap() == (1, 1)); // This will be false
33
34    // However, fixing y and z to 1 will yield the root node to be true (since the root will be true if any of x, y or z is true).
35    inputs.insert("y".to_string(), (1,1));
36    inputs.insert("z".to_string(), (1,1));
37    let revalidated = pldag.propagate(&inputs);
38    println!("Root valid? {}", *revalidated.get(&root).unwrap() == (1, 1)); // This will be true
39
40    // 2. Score a configuration:
41    // We can score a configuration by setting coefficients on nodes.
42    pldag.set_coef("x".to_string(), 1.0);
43    pldag.set_coef("y".to_string(), 2.0);
44    pldag.set_coef("z".to_string(), 3.0);
45    // Add a discount value if the root is true
46    pldag.set_coef(root.clone(), -1.0);
47
48    // Use propagate_coefs to get both bounds and accumulated coefficients
49    let scores = pldag.propagate_coefs(&inputs);
50    // The result contains (bounds, coefficients) for each node
51    let root_result = scores.get(&root).unwrap();
52    println!("Root bounds: {:?}, Total score: {:?}", root_result.0, root_result.1);
53
54    // And notice what will happen if we remove the x value (i.e. x being (0,1))
55    inputs.insert("x".to_string(), (0,1));
56    let scores = pldag.propagate_coefs(&inputs);
57    // The coefficients will reflect the range of possible values
58    let root_result = scores.get(&root).unwrap();
59    println!("Root bounds: {:?}, Score range: {:?}", root_result.0, root_result.1);
60
61    // .. and if we set x to be 0, then the score will be more constrained.
62    inputs.insert("x".to_string(), (0,0));
63    let scores = pldag.propagate_coefs(&inputs);
64    let root_result = scores.get(&root).unwrap();
65    println!("Root bounds: {:?}, Score: {:?}", root_result.0, root_result.1);
66
67    // .. and if we set y and z to be 0, then the root will be 0.
68    inputs.insert("y".to_string(), (0,0));
69    inputs.insert("z".to_string(), (0,0));
70    let scores = pldag.propagate_coefs(&inputs);
71    let root_result = scores.get(&root).unwrap();
72    println!("Root bounds: {:?}, Score: {:?}", root_result.0, root_result.1);
73}
Source

pub fn transitive_dependencies(&self) -> HashMap<ID, HashSet<ID>>

Computes the transitive dependency closure for all nodes.

For each node in the DAG, this method calculates all nodes that can be reached by following dependency edges (the set of all descendants).

§Returns

A map from each node ID to the set of all node IDs it transitively depends on

Source

pub fn primitive_combinations(&self) -> impl Iterator<Item = HashMap<ID, i64>>

Generates all possible combinations of primitive variable assignments.

Enumerates the Cartesian product of all primitive variable bounds, yielding every possible complete assignment of values to primitive variables.

§Returns

An iterator over all possible variable assignments as HashMaps

Source

pub fn propagate(&self, assignment: &Assignment) -> Assignment

Propagates bounds through the DAG bottom-up.

Starting from the given variable assignments, this method computes bounds for all composite nodes by propagating constraints upward through the DAG.

§Arguments
  • assignment - Initial assignment of bounds to variables
§Returns

Complete assignment including bounds for all reachable nodes

Examples found in repository?
examples/readme_example.rs (line 24)
4fn main() {
5    // Build your PL-DAG
6    // For example, we create a model of three boolean variables x, y and z.
7    // We bind them to an OR constraint.
8    let mut pldag: Pldag = Pldag::new();
9
10    // First setup the primitive variables
11    pldag.set_primitive("x".to_string(), (0, 1));
12    pldag.set_primitive("y".to_string(), (0, 1));
13    pldag.set_primitive("z".to_string(), (0, 1));
14
15    // A reference ID is returned
16    let root = pldag.set_or(vec![
17        "x".to_string(),
18        "y".to_string(),
19        "z".to_string(),
20    ]);
21
22    // 1. Validate a combination:
23    let mut inputs: IndexMap<String, Bound> = IndexMap::new();
24    let validated = pldag.propagate(&inputs);
25    // Since nothing is given, and all other variables implicitly have bounds (0, 1) from the pldag model,
26    // the root will be (0,1) since there's not enough information to evaluate the root `or` node.
27    println!("Root valid? {}", *validated.get(&root).unwrap() == (1, 1)); // This will be false
28
29    // If we however fix x to be zero, then we can check the result
30    inputs.insert("x".to_string(), (0,0));
31    let revalidated = pldag.propagate(&inputs);
32    println!("Root valid? {}", *revalidated.get(&root).unwrap() == (1, 1)); // This will be false
33
34    // However, fixing y and z to 1 will yield the root node to be true (since the root will be true if any of x, y or z is true).
35    inputs.insert("y".to_string(), (1,1));
36    inputs.insert("z".to_string(), (1,1));
37    let revalidated = pldag.propagate(&inputs);
38    println!("Root valid? {}", *revalidated.get(&root).unwrap() == (1, 1)); // This will be true
39
40    // 2. Score a configuration:
41    // We can score a configuration by setting coefficients on nodes.
42    pldag.set_coef("x".to_string(), 1.0);
43    pldag.set_coef("y".to_string(), 2.0);
44    pldag.set_coef("z".to_string(), 3.0);
45    // Add a discount value if the root is true
46    pldag.set_coef(root.clone(), -1.0);
47
48    // Use propagate_coefs to get both bounds and accumulated coefficients
49    let scores = pldag.propagate_coefs(&inputs);
50    // The result contains (bounds, coefficients) for each node
51    let root_result = scores.get(&root).unwrap();
52    println!("Root bounds: {:?}, Total score: {:?}", root_result.0, root_result.1);
53
54    // And notice what will happen if we remove the x value (i.e. x being (0,1))
55    inputs.insert("x".to_string(), (0,1));
56    let scores = pldag.propagate_coefs(&inputs);
57    // The coefficients will reflect the range of possible values
58    let root_result = scores.get(&root).unwrap();
59    println!("Root bounds: {:?}, Score range: {:?}", root_result.0, root_result.1);
60
61    // .. and if we set x to be 0, then the score will be more constrained.
62    inputs.insert("x".to_string(), (0,0));
63    let scores = pldag.propagate_coefs(&inputs);
64    let root_result = scores.get(&root).unwrap();
65    println!("Root bounds: {:?}, Score: {:?}", root_result.0, root_result.1);
66
67    // .. and if we set y and z to be 0, then the root will be 0.
68    inputs.insert("y".to_string(), (0,0));
69    inputs.insert("z".to_string(), (0,0));
70    let scores = pldag.propagate_coefs(&inputs);
71    let root_result = scores.get(&root).unwrap();
72    println!("Root bounds: {:?}, Score: {:?}", root_result.0, root_result.1);
73}
Source

pub fn propagate_default(&self) -> Assignment

Propagates bounds using default primitive variable bounds.

Convenience method that calls propagate with the default bounds of all primitive variables as defined in the DAG.

§Returns

Complete assignment with bounds for all nodes

Source

pub fn propagate_many_coefs( &self, assignments: Vec<&Assignment>, ) -> Vec<ValuedAssignment>

Propagates bounds and accumulates coefficients for multiple assignments.

For each input assignment, this method:

  1. Propagates bounds through the DAG
  2. Accumulates coefficients where each parent’s coefficient is the sum of its children’s coefficients plus its own coefficient
§Arguments
  • assignments - Vector of assignments to process
§Returns

Vector of valued assignments, each containing bounds and accumulated coefficients

Source

pub fn propagate_coefs(&self, assignment: &Assignment) -> ValuedAssignment

Propagates bounds and accumulates coefficients for a single assignment.

Convenience method that calls propagate_many_coefs with a single assignment.

§Arguments
  • assignment - The assignment to propagate
§Returns

A valued assignment containing bounds and accumulated coefficients for all nodes

§Panics

Panics if no assignments are returned (should not happen under normal circumstances)

Examples found in repository?
examples/readme_example.rs (line 49)
4fn main() {
5    // Build your PL-DAG
6    // For example, we create a model of three boolean variables x, y and z.
7    // We bind them to an OR constraint.
8    let mut pldag: Pldag = Pldag::new();
9
10    // First setup the primitive variables
11    pldag.set_primitive("x".to_string(), (0, 1));
12    pldag.set_primitive("y".to_string(), (0, 1));
13    pldag.set_primitive("z".to_string(), (0, 1));
14
15    // A reference ID is returned
16    let root = pldag.set_or(vec![
17        "x".to_string(),
18        "y".to_string(),
19        "z".to_string(),
20    ]);
21
22    // 1. Validate a combination:
23    let mut inputs: IndexMap<String, Bound> = IndexMap::new();
24    let validated = pldag.propagate(&inputs);
25    // Since nothing is given, and all other variables implicitly have bounds (0, 1) from the pldag model,
26    // the root will be (0,1) since there's not enough information to evaluate the root `or` node.
27    println!("Root valid? {}", *validated.get(&root).unwrap() == (1, 1)); // This will be false
28
29    // If we however fix x to be zero, then we can check the result
30    inputs.insert("x".to_string(), (0,0));
31    let revalidated = pldag.propagate(&inputs);
32    println!("Root valid? {}", *revalidated.get(&root).unwrap() == (1, 1)); // This will be false
33
34    // However, fixing y and z to 1 will yield the root node to be true (since the root will be true if any of x, y or z is true).
35    inputs.insert("y".to_string(), (1,1));
36    inputs.insert("z".to_string(), (1,1));
37    let revalidated = pldag.propagate(&inputs);
38    println!("Root valid? {}", *revalidated.get(&root).unwrap() == (1, 1)); // This will be true
39
40    // 2. Score a configuration:
41    // We can score a configuration by setting coefficients on nodes.
42    pldag.set_coef("x".to_string(), 1.0);
43    pldag.set_coef("y".to_string(), 2.0);
44    pldag.set_coef("z".to_string(), 3.0);
45    // Add a discount value if the root is true
46    pldag.set_coef(root.clone(), -1.0);
47
48    // Use propagate_coefs to get both bounds and accumulated coefficients
49    let scores = pldag.propagate_coefs(&inputs);
50    // The result contains (bounds, coefficients) for each node
51    let root_result = scores.get(&root).unwrap();
52    println!("Root bounds: {:?}, Total score: {:?}", root_result.0, root_result.1);
53
54    // And notice what will happen if we remove the x value (i.e. x being (0,1))
55    inputs.insert("x".to_string(), (0,1));
56    let scores = pldag.propagate_coefs(&inputs);
57    // The coefficients will reflect the range of possible values
58    let root_result = scores.get(&root).unwrap();
59    println!("Root bounds: {:?}, Score range: {:?}", root_result.0, root_result.1);
60
61    // .. and if we set x to be 0, then the score will be more constrained.
62    inputs.insert("x".to_string(), (0,0));
63    let scores = pldag.propagate_coefs(&inputs);
64    let root_result = scores.get(&root).unwrap();
65    println!("Root bounds: {:?}, Score: {:?}", root_result.0, root_result.1);
66
67    // .. and if we set y and z to be 0, then the root will be 0.
68    inputs.insert("y".to_string(), (0,0));
69    inputs.insert("z".to_string(), (0,0));
70    let scores = pldag.propagate_coefs(&inputs);
71    let root_result = scores.get(&root).unwrap();
72    println!("Root bounds: {:?}, Score: {:?}", root_result.0, root_result.1);
73}
Source

pub fn propagate_coefs_default(&self) -> ValuedAssignment

Propagates bounds and coefficients using default primitive bounds.

Convenience method that calls propagate_coefs with the default bounds of all primitive variables.

§Returns

A valued assignment with bounds and coefficients for all nodes

Source

pub fn get_objective(&self) -> IndexMap<String, f64>

Retrieves the objective function coefficients from all primitive nodes.

Collects the coefficients of all primitive (leaf) nodes in the DAG, which represent the objective function values for ILP optimization. Composite nodes are excluded from the result.

§Returns

A map from primitive variable names to their objective coefficients

Source

pub fn to_sparse_polyhedron( &self, double_binding: bool, integer_constraints: bool, fixed_constraints: bool, ) -> SparsePolyhedron

Converts the PL-DAG to a sparse polyhedron for ILP solving.

Transforms the logical constraints in the DAG into a system of linear inequalities suitable for integer linear programming solvers.

§Arguments
  • double_binding - If true, creates bidirectional implications for composite nodes
  • integer_constraints - If true, adds bounds constraints for integer variables
  • fixed_constraints - If true, adds equality constraints for fixed primitive variables
§Returns

A SparsePolyhedron representing the DAG constraints

Source

pub fn to_sparse_polyhedron_default(&self) -> SparsePolyhedron

Converts the PL-DAG to a sparse polyhedron with default settings.

Convenience method that calls to_sparse_polyhedron with all options enabled: double_binding=true, integer_constraints=true, fixed_constraints=true.

§Returns

A SparsePolyhedron with full constraint encoding

Source

pub fn to_dense_polyhedron( &self, double_binding: bool, integer_constraints: bool, fixed_constraints: bool, ) -> DensePolyhedron

Converts the PL-DAG to a dense polyhedron.

§Arguments
  • double_binding - If true, creates bidirectional implications
  • integer_constraints - If true, adds integer bounds constraints
  • fixed_constraints - If true, adds fixed variable constraints
§Returns

A DensePolyhedron representing the DAG constraints

Source

pub fn to_dense_polyhedron_default(&self) -> DensePolyhedron

Converts the PL-DAG to a dense polyhedron with default settings.

§Returns

A DensePolyhedron with all constraint options enabled

Source

pub fn set_coef(&mut self, id: ID, coefficient: f64)

Sets the coefficient for a specific node.

Updates the coefficient value associated with the given node ID. If the node doesn’t exist, this method has no effect.

§Arguments
  • id - The node ID to update
  • coefficient - The new coefficient value
Examples found in repository?
examples/readme_example.rs (line 42)
4fn main() {
5    // Build your PL-DAG
6    // For example, we create a model of three boolean variables x, y and z.
7    // We bind them to an OR constraint.
8    let mut pldag: Pldag = Pldag::new();
9
10    // First setup the primitive variables
11    pldag.set_primitive("x".to_string(), (0, 1));
12    pldag.set_primitive("y".to_string(), (0, 1));
13    pldag.set_primitive("z".to_string(), (0, 1));
14
15    // A reference ID is returned
16    let root = pldag.set_or(vec![
17        "x".to_string(),
18        "y".to_string(),
19        "z".to_string(),
20    ]);
21
22    // 1. Validate a combination:
23    let mut inputs: IndexMap<String, Bound> = IndexMap::new();
24    let validated = pldag.propagate(&inputs);
25    // Since nothing is given, and all other variables implicitly have bounds (0, 1) from the pldag model,
26    // the root will be (0,1) since there's not enough information to evaluate the root `or` node.
27    println!("Root valid? {}", *validated.get(&root).unwrap() == (1, 1)); // This will be false
28
29    // If we however fix x to be zero, then we can check the result
30    inputs.insert("x".to_string(), (0,0));
31    let revalidated = pldag.propagate(&inputs);
32    println!("Root valid? {}", *revalidated.get(&root).unwrap() == (1, 1)); // This will be false
33
34    // However, fixing y and z to 1 will yield the root node to be true (since the root will be true if any of x, y or z is true).
35    inputs.insert("y".to_string(), (1,1));
36    inputs.insert("z".to_string(), (1,1));
37    let revalidated = pldag.propagate(&inputs);
38    println!("Root valid? {}", *revalidated.get(&root).unwrap() == (1, 1)); // This will be true
39
40    // 2. Score a configuration:
41    // We can score a configuration by setting coefficients on nodes.
42    pldag.set_coef("x".to_string(), 1.0);
43    pldag.set_coef("y".to_string(), 2.0);
44    pldag.set_coef("z".to_string(), 3.0);
45    // Add a discount value if the root is true
46    pldag.set_coef(root.clone(), -1.0);
47
48    // Use propagate_coefs to get both bounds and accumulated coefficients
49    let scores = pldag.propagate_coefs(&inputs);
50    // The result contains (bounds, coefficients) for each node
51    let root_result = scores.get(&root).unwrap();
52    println!("Root bounds: {:?}, Total score: {:?}", root_result.0, root_result.1);
53
54    // And notice what will happen if we remove the x value (i.e. x being (0,1))
55    inputs.insert("x".to_string(), (0,1));
56    let scores = pldag.propagate_coefs(&inputs);
57    // The coefficients will reflect the range of possible values
58    let root_result = scores.get(&root).unwrap();
59    println!("Root bounds: {:?}, Score range: {:?}", root_result.0, root_result.1);
60
61    // .. and if we set x to be 0, then the score will be more constrained.
62    inputs.insert("x".to_string(), (0,0));
63    let scores = pldag.propagate_coefs(&inputs);
64    let root_result = scores.get(&root).unwrap();
65    println!("Root bounds: {:?}, Score: {:?}", root_result.0, root_result.1);
66
67    // .. and if we set y and z to be 0, then the root will be 0.
68    inputs.insert("y".to_string(), (0,0));
69    inputs.insert("z".to_string(), (0,0));
70    let scores = pldag.propagate_coefs(&inputs);
71    let root_result = scores.get(&root).unwrap();
72    println!("Root bounds: {:?}, Score: {:?}", root_result.0, root_result.1);
73}
Source

pub fn get_coef(&self, id: &ID) -> f64

Retrieves the coefficient for a specific node.

§Arguments
  • id - The node ID to query
§Returns

The coefficient value for the node, or 0.0 if the node doesn’t exist

Source

pub fn set_primitive(&mut self, id: ID, bound: Bound)

Creates a primitive (leaf) variable with the specified bounds.

Primitive variables represent the base variables in the DAG and have no dependencies on other nodes.

§Arguments
  • id - Unique identifier for the variable
  • bound - The allowed range (min, max) for this variable
Examples found in repository?
examples/readme_example.rs (line 11)
4fn main() {
5    // Build your PL-DAG
6    // For example, we create a model of three boolean variables x, y and z.
7    // We bind them to an OR constraint.
8    let mut pldag: Pldag = Pldag::new();
9
10    // First setup the primitive variables
11    pldag.set_primitive("x".to_string(), (0, 1));
12    pldag.set_primitive("y".to_string(), (0, 1));
13    pldag.set_primitive("z".to_string(), (0, 1));
14
15    // A reference ID is returned
16    let root = pldag.set_or(vec![
17        "x".to_string(),
18        "y".to_string(),
19        "z".to_string(),
20    ]);
21
22    // 1. Validate a combination:
23    let mut inputs: IndexMap<String, Bound> = IndexMap::new();
24    let validated = pldag.propagate(&inputs);
25    // Since nothing is given, and all other variables implicitly have bounds (0, 1) from the pldag model,
26    // the root will be (0,1) since there's not enough information to evaluate the root `or` node.
27    println!("Root valid? {}", *validated.get(&root).unwrap() == (1, 1)); // This will be false
28
29    // If we however fix x to be zero, then we can check the result
30    inputs.insert("x".to_string(), (0,0));
31    let revalidated = pldag.propagate(&inputs);
32    println!("Root valid? {}", *revalidated.get(&root).unwrap() == (1, 1)); // This will be false
33
34    // However, fixing y and z to 1 will yield the root node to be true (since the root will be true if any of x, y or z is true).
35    inputs.insert("y".to_string(), (1,1));
36    inputs.insert("z".to_string(), (1,1));
37    let revalidated = pldag.propagate(&inputs);
38    println!("Root valid? {}", *revalidated.get(&root).unwrap() == (1, 1)); // This will be true
39
40    // 2. Score a configuration:
41    // We can score a configuration by setting coefficients on nodes.
42    pldag.set_coef("x".to_string(), 1.0);
43    pldag.set_coef("y".to_string(), 2.0);
44    pldag.set_coef("z".to_string(), 3.0);
45    // Add a discount value if the root is true
46    pldag.set_coef(root.clone(), -1.0);
47
48    // Use propagate_coefs to get both bounds and accumulated coefficients
49    let scores = pldag.propagate_coefs(&inputs);
50    // The result contains (bounds, coefficients) for each node
51    let root_result = scores.get(&root).unwrap();
52    println!("Root bounds: {:?}, Total score: {:?}", root_result.0, root_result.1);
53
54    // And notice what will happen if we remove the x value (i.e. x being (0,1))
55    inputs.insert("x".to_string(), (0,1));
56    let scores = pldag.propagate_coefs(&inputs);
57    // The coefficients will reflect the range of possible values
58    let root_result = scores.get(&root).unwrap();
59    println!("Root bounds: {:?}, Score range: {:?}", root_result.0, root_result.1);
60
61    // .. and if we set x to be 0, then the score will be more constrained.
62    inputs.insert("x".to_string(), (0,0));
63    let scores = pldag.propagate_coefs(&inputs);
64    let root_result = scores.get(&root).unwrap();
65    println!("Root bounds: {:?}, Score: {:?}", root_result.0, root_result.1);
66
67    // .. and if we set y and z to be 0, then the root will be 0.
68    inputs.insert("y".to_string(), (0,0));
69    inputs.insert("z".to_string(), (0,0));
70    let scores = pldag.propagate_coefs(&inputs);
71    let root_result = scores.get(&root).unwrap();
72    println!("Root bounds: {:?}, Score: {:?}", root_result.0, root_result.1);
73}
Source

pub fn set_primitives(&mut self, ids: Vec<ID>, bound: Bound)

Creates multiple primitive variables with the same bounds.

Convenience method to create several primitive variables at once. Duplicate IDs are automatically filtered out.

§Arguments
  • ids - Vector of unique identifiers for the variables
  • bound - The common bound to apply to all variables
Source

pub fn set_gelineq( &mut self, coefficient_variables: Vec<Coefficient>, bias: i64, ) -> ID

Creates a general linear inequality constraint.

Creates a constraint of the form: sum(coeff_i * var_i) + bias >= 0. The constraint is automatically assigned a unique ID based on its content.

§Arguments
  • coefficient_variables - Vector of (variable_id, coefficient) pairs
  • bias - Constant bias term
§Returns

The unique ID assigned to this constraint

Source

pub fn set_atleast(&mut self, references: Vec<ID>, value: i64) -> ID

Creates an “at least” constraint: sum(variables) >= value.

§Arguments
  • references - Vector of variable IDs to sum
  • value - Minimum required sum
§Returns

The unique ID assigned to this constraint

Source

pub fn set_atmost(&mut self, references: Vec<ID>, value: i64) -> ID

Creates an “at most” constraint: sum(variables) <= value.

§Arguments
  • references - Vector of variable IDs to sum
  • value - Maximum allowed sum
§Returns

The unique ID assigned to this constraint

Source

pub fn set_equal(&mut self, references: Vec<ID>, value: i64) -> ID

Creates an equality constraint: sum(variables) == value.

Implemented as the conjunction of “at least” and “at most” constraints.

§Arguments
  • references - Vector of variable IDs to sum
  • value - Required exact sum
§Returns

The unique ID assigned to this constraint

Source

pub fn set_and(&mut self, references: Vec<ID>) -> ID

Creates a logical AND constraint.

Returns true if and only if ALL referenced variables are true. Implemented as: sum(variables) >= count(variables).

§Arguments
  • references - Vector of variable IDs to AND together
§Returns

The unique ID assigned to this constraint

Source

pub fn set_or(&mut self, references: Vec<ID>) -> ID

Creates a logical OR constraint.

Returns true if AT LEAST ONE of the referenced variables is true. Implemented as: sum(variables) >= 1.

§Arguments
  • references - Vector of variable IDs to OR together
§Returns

The unique ID assigned to this constraint

Examples found in repository?
examples/readme_example.rs (lines 16-20)
4fn main() {
5    // Build your PL-DAG
6    // For example, we create a model of three boolean variables x, y and z.
7    // We bind them to an OR constraint.
8    let mut pldag: Pldag = Pldag::new();
9
10    // First setup the primitive variables
11    pldag.set_primitive("x".to_string(), (0, 1));
12    pldag.set_primitive("y".to_string(), (0, 1));
13    pldag.set_primitive("z".to_string(), (0, 1));
14
15    // A reference ID is returned
16    let root = pldag.set_or(vec![
17        "x".to_string(),
18        "y".to_string(),
19        "z".to_string(),
20    ]);
21
22    // 1. Validate a combination:
23    let mut inputs: IndexMap<String, Bound> = IndexMap::new();
24    let validated = pldag.propagate(&inputs);
25    // Since nothing is given, and all other variables implicitly have bounds (0, 1) from the pldag model,
26    // the root will be (0,1) since there's not enough information to evaluate the root `or` node.
27    println!("Root valid? {}", *validated.get(&root).unwrap() == (1, 1)); // This will be false
28
29    // If we however fix x to be zero, then we can check the result
30    inputs.insert("x".to_string(), (0,0));
31    let revalidated = pldag.propagate(&inputs);
32    println!("Root valid? {}", *revalidated.get(&root).unwrap() == (1, 1)); // This will be false
33
34    // However, fixing y and z to 1 will yield the root node to be true (since the root will be true if any of x, y or z is true).
35    inputs.insert("y".to_string(), (1,1));
36    inputs.insert("z".to_string(), (1,1));
37    let revalidated = pldag.propagate(&inputs);
38    println!("Root valid? {}", *revalidated.get(&root).unwrap() == (1, 1)); // This will be true
39
40    // 2. Score a configuration:
41    // We can score a configuration by setting coefficients on nodes.
42    pldag.set_coef("x".to_string(), 1.0);
43    pldag.set_coef("y".to_string(), 2.0);
44    pldag.set_coef("z".to_string(), 3.0);
45    // Add a discount value if the root is true
46    pldag.set_coef(root.clone(), -1.0);
47
48    // Use propagate_coefs to get both bounds and accumulated coefficients
49    let scores = pldag.propagate_coefs(&inputs);
50    // The result contains (bounds, coefficients) for each node
51    let root_result = scores.get(&root).unwrap();
52    println!("Root bounds: {:?}, Total score: {:?}", root_result.0, root_result.1);
53
54    // And notice what will happen if we remove the x value (i.e. x being (0,1))
55    inputs.insert("x".to_string(), (0,1));
56    let scores = pldag.propagate_coefs(&inputs);
57    // The coefficients will reflect the range of possible values
58    let root_result = scores.get(&root).unwrap();
59    println!("Root bounds: {:?}, Score range: {:?}", root_result.0, root_result.1);
60
61    // .. and if we set x to be 0, then the score will be more constrained.
62    inputs.insert("x".to_string(), (0,0));
63    let scores = pldag.propagate_coefs(&inputs);
64    let root_result = scores.get(&root).unwrap();
65    println!("Root bounds: {:?}, Score: {:?}", root_result.0, root_result.1);
66
67    // .. and if we set y and z to be 0, then the root will be 0.
68    inputs.insert("y".to_string(), (0,0));
69    inputs.insert("z".to_string(), (0,0));
70    let scores = pldag.propagate_coefs(&inputs);
71    let root_result = scores.get(&root).unwrap();
72    println!("Root bounds: {:?}, Score: {:?}", root_result.0, root_result.1);
73}
Source

pub fn set_nand(&mut self, references: Vec<ID>) -> ID

Creates a logical NAND constraint.

Returns true if NOT ALL of the referenced variables are true. Implemented as: sum(variables) <= count(variables) - 1.

§Arguments
  • references - Vector of variable IDs to NAND together
§Returns

The unique ID assigned to this constraint

Source

pub fn set_nor(&mut self, references: Vec<ID>) -> ID

Creates a logical NOR constraint.

Returns true if NONE of the referenced variables are true. Implemented as: sum(variables) <= 0.

§Arguments
  • references - Vector of variable IDs to NOR together
§Returns

The unique ID assigned to this constraint

Source

pub fn set_not(&mut self, references: Vec<ID>) -> ID

Creates a logical NOT constraint.

Returns true if NONE of the referenced variables are true. Functionally equivalent to NOR. Implemented as: sum(variables) <= 0.

§Arguments
  • references - Vector of variable IDs to negate
§Returns

The unique ID assigned to this constraint

Source

pub fn set_xor(&mut self, references: Vec<ID>) -> ID

Creates a logical XOR constraint.

Returns true if EXACTLY ONE of the referenced variables is true. Implemented as the conjunction of OR and “at most 1” constraints.

§Arguments
  • references - Vector of variable IDs to XOR together
§Returns

The unique ID assigned to this constraint

Source

pub fn set_xnor(&mut self, references: Vec<ID>) -> ID

Creates a logical XNOR constraint.

Returns true if an EVEN NUMBER of the referenced variables are true (including zero). Implemented as: (sum >= 2) OR (sum <= 0).

§Arguments
  • references - Vector of variable IDs to XNOR together
§Returns

The unique ID assigned to this constraint

Source

pub fn set_imply(&mut self, condition: ID, consequence: ID) -> ID

Creates a logical IMPLICATION constraint: condition -> consequence.

Returns true if the condition is false OR the consequence is true. Implemented as: NOT(condition) OR consequence.

§Arguments
  • condition - The condition variable ID
  • consequence - The consequence variable ID
§Returns

The unique ID assigned to this constraint

Source

pub fn set_equiv(&mut self, lhs: ID, rhs: ID) -> ID

Creates a logical EQUIVALENCE constraint: lhs <-> rhs.

Returns true if both variables have the same truth value. Implemented as: (lhs -> rhs) AND (rhs -> lhs).

§Arguments
  • lhs - The left-hand side variable ID
  • rhs - The right-hand side variable ID
§Returns

The unique ID assigned to this constraint

Auto Trait Implementations§

§

impl Freeze for Pldag

§

impl RefUnwindSafe for Pldag

§

impl Send for Pldag

§

impl Sync for Pldag

§

impl Unpin for Pldag

§

impl UnwindSafe for Pldag

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.