optimizer/
optimizer.rs

1use std::fmt::Display;
2
3use logify::{
4    ExpressionBuilder, logic,
5    opt::{Mergeable, OptimizerConfig, SetRelation},
6};
7
8// Geographical locations
9#[derive(PartialEq, Hash, Clone, Debug)]
10enum Geo {
11    USA,
12    California,
13    Texas,
14    France,
15    Paris,
16}
17
18impl Display for Geo {
19    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
20        let loc = match self {
21            Geo::USA => "USA",
22            Geo::California => "California",
23            Geo::Texas => "Texas",
24            Geo::France => "France",
25            Geo::Paris => "Paris",
26        };
27        write!(f, "{}", loc)
28    }
29}
30
31// Define the relationships
32struct GeoMerger;
33
34impl Mergeable<Geo> for GeoMerger {
35    fn get_relation(&mut self, a: &Geo, b: &Geo) -> SetRelation {
36        // mark subset as inside of, and superset as contains
37        match (a, b) {
38            (Geo::California, Geo::USA) => SetRelation::Subset,
39            (Geo::Texas, Geo::USA) => SetRelation::Subset,
40            (Geo::Paris, Geo::France) => SetRelation::Subset,
41
42            (Geo::USA, Geo::California) => SetRelation::Superset,
43
44            (Geo::Texas, Geo::France) => SetRelation::Disjoint,
45            (Geo::France, Geo::Texas) => SetRelation::Disjoint,
46
47            // ... (omitted other cases and inverses for brevity)
48            _ => SetRelation::Trivial,
49        }
50    }
51}
52
53fn main() {
54    let mut config = OptimizerConfig {
55        merger: GeoMerger,
56        merger_depth: 2,
57        max_iterations: 0,
58    };
59
60    // Example 1. California is inside of USA, so it will be redacted
61    {
62        let builder = ExpressionBuilder::new();
63        let rule = logic!(
64            builder,
65            any![{ Geo::California }, { Geo::USA }, { Geo::Paris }]
66        );
67        builder.add_root(rule);
68
69        let mut expr = builder.build();
70
71        let root = expr.roots().next().unwrap();
72        println!("1. Before: {}", expr.to_string(root));
73
74        expr.optimize(&mut config);
75
76        let new_root = expr.roots().next().unwrap();
77        println!("1. After:  {}", expr.to_string(new_root));
78    }
79    println!();
80
81    // Example 2. Texas and France are disjoint, so the result is EMPTY
82    {
83        let builder = ExpressionBuilder::new();
84        let rule = logic!(builder, all![{ Geo::Texas }, { Geo::France }]);
85        builder.add_root(rule);
86
87        let mut expr = builder.build();
88
89        let root = expr.roots().next().unwrap();
90        println!("2. Before: {}", expr.to_string(root));
91
92        expr.optimize(&mut config);
93
94        let new_root = expr.roots().next().unwrap();
95        println!("2. After:  {}", expr.to_string(new_root));
96    }
97    println!();
98
99    // Example 3. California and Texas are both within the USA, so USA is redundant
100    {
101        let builder = ExpressionBuilder::new();
102        let rule = logic!(
103            builder,
104            all![any![{ Geo::California }, { Geo::Texas }], { Geo::USA }]
105        );
106        builder.add_root(rule);
107
108        let mut expr = builder.build();
109
110        let root = expr.roots().next().unwrap();
111        println!("3. Before: {}", expr.to_string(root));
112
113        expr.optimize(&mut config);
114
115        let new_root = expr.roots().next().unwrap();
116        println!("3. After:  {}", expr.to_string(new_root));
117    }
118}