open_hypergraphs/lax/var/
operators.rs

1use crate::lax::hypergraph::Hyperedge;
2use crate::lax::open_hypergraph::OpenHypergraph;
3
4use super::var::*;
5
6use std::cell::RefCell;
7use std::ops::*;
8use std::rc::Rc;
9
10/// A general helper for constructing `n → 1` maps
11pub fn operation<O: Clone, A: HasVar>(
12    // TODO: generalise to something which borrows a mutable OpenHypergraph?
13    builder: &Rc<RefCell<OpenHypergraph<O, A>>>,
14    vars: &[Var<O, A>],
15    result_label: O,
16    op: A,
17) -> Var<O, A> {
18    let mut nodes = Vec::with_capacity(vars.len());
19    for v in vars {
20        nodes.push(v.new_target());
21    }
22
23    let v = Var::new(builder.clone(), result_label);
24    let v_source = v.new_source();
25
26    let mut term = builder.borrow_mut();
27    let _ = term.new_edge(
28        op,
29        Hyperedge {
30            sources: nodes,
31            targets: vec![v_source],
32        },
33    );
34
35    v
36}
37
38/// Vars can be added when the underlying signature has an operation for 'addition'.
39pub trait HasAdd<O, A> {
40    fn add(lhs_type: O, rhs_type: O) -> (O, A);
41}
42
43impl<O: Clone, A: HasVar + HasAdd<O, A>> Add for Var<O, A> {
44    type Output = Var<O, A>;
45
46    fn add(self, rhs: Self) -> Self::Output {
47        // only difference between impls
48        let (result_label, op) = A::add(self.label.clone(), rhs.label.clone());
49        operation(&self.state.clone(), &[self, rhs], result_label, op)
50    }
51}
52
53/// Vars can be added when the underlying signature has an operation for 'addition'.
54pub trait HasBitXor<O, A> {
55    fn bitxor(lhs_type: O, rhs_type: O) -> (O, A);
56}
57
58impl<O: Clone, A: HasVar + HasBitXor<O, A>> BitXor for Var<O, A> {
59    type Output = Var<O, A>;
60
61    fn bitxor(self, rhs: Self) -> Self::Output {
62        // only difference between impls
63        let (result_label, op) = A::bitxor(self.label.clone(), rhs.label.clone());
64        operation(&self.state.clone(), &[self, rhs], result_label, op)
65    }
66}
67
68// Macro to reduce boilerplate for binary operators
69macro_rules! define_binary_op {
70    ($trait_name:ident, $fn_name:ident, $has_trait_name:ident) => {
71        #[doc = r" Vars support this operator when the underlying signature has the appropriate operation."]
72        pub trait $has_trait_name<O, A> {
73            fn $fn_name(lhs_type: O, rhs_type: O) -> (O, A);
74        }
75
76        impl<O: Clone, A: HasVar + $has_trait_name<O, A>> $trait_name for Var<O, A> {
77            type Output = Var<O, A>;
78
79            fn $fn_name(self, rhs: Self) -> Self::Output {
80                let (result_label, op) = A::$fn_name(self.label.clone(), rhs.label.clone());
81                //binop(self, rhs, result_label, op)
82                operation(&self.state.clone(), &[self, rhs], result_label, op)
83            }
84        }
85    };
86}
87
88// Macro to reduce boilerplate for unary operators
89macro_rules! define_unary_op {
90    ($trait_name:ident, $fn_name:ident, $has_trait_name:ident) => {
91        #[doc = r" Vars support this unary operator when the underlying signature has the appropriate operation."]
92        pub trait $has_trait_name<O, A> {
93            fn $fn_name(operand_type: O) -> (O, A);
94        }
95
96        impl<O: Clone, A: HasVar + $has_trait_name<O, A>> $trait_name for Var<O, A> {
97            type Output = Var<O, A>;
98
99            fn $fn_name(self) -> Self::Output {
100                let (result_label, op) = A::$fn_name(self.label.clone());
101                operation(&self.state.clone(), &[self], result_label, op)
102            }
103        }
104    };
105}
106
107//define_binary_op!(BitXor, bitand, HasBitXor); // hand-written
108define_binary_op!(BitAnd, bitand, HasBitAnd);
109define_binary_op!(BitOr, bitor, HasBitOr);
110define_binary_op!(Shl, shl, HasShl);
111define_binary_op!(Shr, shr, HasShr);
112define_unary_op!(Not, not, HasNot);
113
114//define_binary_op!(Add, add, HasAdd); // hand-written
115define_binary_op!(Mul, mul, HasMul);
116define_binary_op!(Sub, sub, HasSub);
117define_binary_op!(Div, div, HasDiv);
118define_unary_op!(Neg, neg, HasNeg);