boolean_expressions/
boolean_expressions.rs

1//! Example: Boolean expression minimization
2//!
3//! This example demonstrates how to use boolean expressions with the expr! macro,
4//! method-based API, and parsing to create and minimize boolean functions.
5
6use espresso_logic::{expr, BoolExpr, Cover, ExprCover};
7
8fn main() -> std::io::Result<()> {
9    println!("=== Boolean Expression Examples ===\n");
10
11    // Example 1: Programmatic construction with expr! macro
12    println!("1. Programmatic Construction (using expr! macro):");
13    let a = BoolExpr::variable("a");
14    let b = BoolExpr::variable("b");
15    let _c = BoolExpr::variable("c");
16
17    // XOR function: a*~b + ~a*b - clean syntax!
18    let xor = expr!(a * !b + !a * b);
19    println!("   XOR = a*~b + ~a*b");
20    println!("   Variables: {:?}", xor.collect_variables());
21    let xor_cover = ExprCover::from_expr(xor);
22    println!(
23        "   Inputs: {}, Outputs: {}",
24        xor_cover.num_inputs(),
25        xor_cover.num_outputs()
26    );
27    println!();
28
29    // Example 2: Parsing from string
30    println!("2. Parsing from String:");
31    let parsed_expr = BoolExpr::parse("(a + b) * (c + d)").unwrap();
32    println!("   Expression: (a + b) * (c + d)");
33    println!("   Variables: {:?}", parsed_expr.collect_variables());
34    let parsed_cover = ExprCover::from_expr(parsed_expr);
35    println!(
36        "   Inputs: {}, Outputs: {}",
37        parsed_cover.num_inputs(),
38        parsed_cover.num_outputs()
39    );
40    println!();
41
42    // Example 3: Complex expression with negation
43    println!("3. Complex Expression with Negation:");
44    let complex = BoolExpr::parse("~(a * b) + (c * ~d)").unwrap();
45    println!("   Expression: ~(a * b) + (c * ~d)");
46    println!("   Variables: {:?}", complex.collect_variables());
47    println!();
48
49    // Example 4: Minimization
50    println!("4. Minimization Example:");
51    println!("   Original: a*b + a*b*c (redundant term)");
52
53    let a = BoolExpr::variable("a");
54    let b = BoolExpr::variable("b");
55    let c = BoolExpr::variable("c");
56    let redundant = expr!(a * b + a * b * c);
57
58    println!("   Before minimization:");
59    println!("      Variables: {:?}", redundant.collect_variables());
60
61    let mut redundant_cover = ExprCover::from_expr(redundant);
62    redundant_cover.minimize()?;
63    let minimized = redundant_cover.to_expr();
64
65    println!("   After minimization:");
66    println!("      Expression: {}", minimized);
67    println!();
68
69    // Example 5: XNOR function
70    println!("5. XNOR Function (equivalence):");
71    let a = BoolExpr::variable("a");
72    let b = BoolExpr::variable("b");
73    let xnor = expr!(a * b + !a * !b);
74
75    println!("   XNOR = a*b + ~a*~b");
76    println!("   Before minimize: {}", xnor);
77
78    let mut xnor_cover = ExprCover::from_expr(xnor);
79    xnor_cover.minimize()?;
80    let minimized_xnor = xnor_cover.to_expr();
81
82    println!("   After minimize:  {}", minimized_xnor);
83    println!();
84
85    // Example 6: Three-variable function
86    println!("6. Three-Variable Majority Function:");
87    let a = BoolExpr::variable("a");
88    let b = BoolExpr::variable("b");
89    let c = BoolExpr::variable("c");
90
91    // Majority function: true if at least 2 of 3 inputs are true
92    // For more complex expressions, the method API is clearer
93    let majority = a.and(&b).or(&b.and(&c)).or(&a.and(&c));
94    let mut majority_cover = ExprCover::from_expr(majority);
95
96    println!("   Majority = a*b + b*c + a*c");
97    println!("   Before minimize: {} cubes", majority_cover.num_cubes());
98
99    majority_cover.minimize()?;
100
101    println!("   After minimize:  {} cubes", majority_cover.num_cubes());
102    println!();
103
104    // Example 7: Converting to PLA format
105    println!("7. PLA Format Export:");
106    let a = BoolExpr::variable("a");
107    let b = BoolExpr::variable("b");
108    let simple = a.and(&b);
109    let simple_cover = ExprCover::from_expr(simple);
110
111    let pla_string = simple_cover.to_pla_string(espresso_logic::PLAType::F)?;
112    println!("   Expression: a * b");
113    println!("   PLA format:");
114    for line in pla_string.lines() {
115        println!("      {}", line);
116    }
117    println!();
118
119    // Example 8: Parsing with constants
120    println!("8. Expressions with Constants:");
121    let expr_with_const = BoolExpr::parse("a * 1 + 0 * b").unwrap();
122    println!("   Expression: a * 1 + 0 * b");
123    println!("   Variables: {:?}", expr_with_const.collect_variables());
124    println!();
125
126    // Example 9: De Morgan's laws in action
127    println!("9. De Morgan's Laws:");
128    let a = BoolExpr::variable("a");
129    let b = BoolExpr::variable("b");
130
131    let demorgan1 = expr!(!(a * b));
132    let cover1 = ExprCover::from_expr(demorgan1);
133    println!("   ~(a * b) has {} variables", cover1.num_inputs());
134
135    let demorgan2 = expr!(!(a + b));
136    let cover2 = ExprCover::from_expr(demorgan2);
137    println!("   ~(a + b) has {} variables", cover2.num_inputs());
138    println!();
139
140    // Example 10: Comparison - same logical function, different expressions
141    println!("10. Equivalent Expressions:");
142    let expr1 = BoolExpr::parse("a * b + a * c").unwrap();
143    let expr2 = BoolExpr::parse("a * (b + c)").unwrap();
144
145    let mut cover1 = ExprCover::from_expr(expr1);
146    let mut cover2 = ExprCover::from_expr(expr2);
147
148    println!("    Expression 1: a * b + a * c");
149    println!("    Expression 2: a * (b + c)");
150    println!("    Both have {} variables", cover1.num_inputs());
151
152    cover1.minimize()?;
153    cover2.minimize()?;
154
155    println!("    After minimization, they should be equivalent");
156    println!();
157
158    // Example 11: Iterating over cubes
159    println!("11. Cube Iteration:");
160    let expr = BoolExpr::parse("a * b + ~a * c").unwrap();
161    let cover = ExprCover::from_expr(expr);
162    println!("    Expression: a * b + ~a * c");
163    println!("    Cubes:");
164
165    for (i, (inputs, outputs)) in cover.cubes_iter().enumerate() {
166        print!("      Cube {}: inputs=[", i + 1);
167        for input in &inputs {
168            match input {
169                Some(true) => print!("1"),
170                Some(false) => print!("0"),
171                None => print!("-"),
172            }
173        }
174        print!("] outputs=[");
175        for output in &outputs {
176            match output {
177                Some(true) => print!("1"),
178                Some(false) => print!("0"),
179                None => print!("-"),
180            }
181        }
182        println!("]");
183    }
184    println!();
185
186    println!("=== Examples Complete ===");
187    Ok(())
188}