synthphonia/forward/enumeration/
mod.rs

1use enum_dispatch::enum_dispatch;
2use itertools::Itertools;
3
4
5
6// pub mod simple;
7// use simple::*;
8
9use crate::{expr::{cfg::ProdRule, ops::{Op1, Op1Enum, Op2, Op2Enum, Op3, Op3Enum}, Expr}, galloc::AllocForAny};
10use ext_trait::extension;
11use super::executor::Executor;
12
13
14/// An enumerator for a specific production rule.
15pub trait Enumerator1 : Op1 {
16    #[inline(always)]
17    fn enumerate(&self, this: &'static Op1Enum, exec: &'static Executor, opnt: [usize; 1]) -> Result<(), ()> {
18        enumerate1(self, this, exec, opnt)
19    }
20}
21#[inline(always)]
22
23pub fn enumerate1(s: &impl Op1, this: &'static Op1Enum, exec: &'static Executor, opnt: [usize; 1]) -> Result<(), ()> {
24    if exec.size() <= s.cost() { return Ok(()); }
25    for (e, v) in exec.data[opnt[0]].size.get_all(exec.size() - s.cost()) {
26        let expr = Expr::Op1(this, e);
27        if let (true, value) = s.try_eval(*v) {
28            exec.enum_expr(expr, value)?;
29        }
30    }
31    Ok(())
32}
33
34/// An enumerator for a specific production rule.
35pub trait Enumerator2 : Op2 {
36    #[inline(always)]
37    fn enumerate(&self, this: &'static Op2Enum, exec: &'static Executor, nt: [usize; 2]) -> Result<(), ()> {
38        enumerate2(self, this, exec, nt)
39    }
40}
41#[inline(always)]
42pub fn enumerate2(s: &impl Op2, this: &'static Op2Enum, exec: &'static Executor, nt: [usize; 2]) -> Result<(), ()> {
43    if exec.size() <= s.cost() { return Ok(()); }
44    let total = exec.size() - s.cost();
45    for (i, (e1, v1)) in exec.data[nt[0]].size.get_all_under(total) {
46        for (e2, v2) in exec.data[nt[1]].size.get_all(total - i) {
47            let expr = Expr::Op2(this, e1, e2);
48            if let (true, value) = s.try_eval(*v1, *v2) {
49                exec.enum_expr(expr, value)?;
50            }
51        }
52    }
53    Ok(())
54}
55
56/// An enumerator for a specific production rule.
57pub trait Enumerator3 : Op3 {
58    #[inline(always)]
59    fn enumerate(&self, this: &'static Op3Enum, exec: &'static Executor, nt: [usize; 3]) -> Result<(), ()> {
60        enumerate3(self, this, exec, nt)
61    }
62}
63#[inline(always)]
64pub fn enumerate3(s: &impl Op3, this: &'static Op3Enum, exec: &'static Executor, nt: [usize; 3]) -> Result<(), ()> {
65    if exec.size() < s.cost() { return Ok(()); }
66    let total = exec.size() - s.cost();
67    for (i, (e1, v1)) in exec.data[nt[0]].size.get_all_under(total) {
68        for (j, (e2, v2)) in exec.data[nt[1]].size.get_all_under(total - i) {
69            for (e3, v3) in exec.data[nt[2]].size.get_all(total - i - j) {
70                let expr = Expr::Op3(this, e1, e2, e3);
71                if let (true, value) = s.try_eval(*v1, *v2, *v3) {
72                    exec.enum_expr(expr, value)?;
73                }
74            }
75        } 
76    }
77    Ok(())
78}
79
80impl Enumerator1 for Op1Enum {
81    #[inline]
82    fn enumerate(&self, this: &'static Op1Enum, exec: &'static Executor, opnt: [usize; 1]) -> Result<(), ()> {
83        macro_rules! _do {($($op:ident)*) => {$(
84            if let Self::$op(a) = self {
85                return a.enumerate(this, exec, opnt);
86            }
87        )*};}
88        crate::for_all_op1!();
89        panic!()
90    }
91}
92
93impl Enumerator2 for Op2Enum {
94    #[inline]
95    fn enumerate(&self, this: &'static Op2Enum, exec: &'static Executor, opnt: [usize; 2]) -> Result<(), ()> {
96        macro_rules! _do {($($op:ident)*) => {$(
97            if let Self::$op(a) = self {
98                return a.enumerate(this, exec, opnt);
99            }
100        )*};}
101        crate::for_all_op2!();
102        panic!()
103    }
104}
105
106impl Enumerator3 for Op3Enum {
107    #[inline]
108    fn enumerate(&self, this: &'static Op3Enum, exec: &'static Executor, opnt: [usize; 3]) -> Result<(), ()> {
109        macro_rules! _do {($($op:ident)*) => {$(
110            if let Self::$op(a) = self {
111                return a.enumerate(this, exec, opnt);
112            }
113        )*};}
114        crate::for_all_op3!();
115        panic!()
116    }
117}
118
119#[extension(pub trait ProdRuleEnumerateExt)]
120impl ProdRule {
121    /// Extend production rule with the ability to enumerate.
122    fn enumerate(&self, exec: &'static Executor) -> Result<(), ()> {
123        match self {
124            ProdRule::Const(c) => {
125                if exec.size() == 1 {
126                    exec.enum_expr(Expr::Const(*c), c.value(exec.ctx.len()))?;
127                }
128                Ok(())
129            }
130            ProdRule::Var(v) => {
131                if exec.size() == 1 {
132                    exec.enum_expr(Expr::Var(*v), *exec.ctx.get(*v).unwrap())?;
133                }
134                Ok(())
135            }
136            ProdRule::Op1(op1, nt1) => {
137                op1.enumerate(op1, exec, [*nt1])
138            }
139            ProdRule::Op2(op2, nt1, nt2) => {
140                op2.enumerate(op2, exec, [*nt1, *nt2])
141            }
142            ProdRule::Op3(op3, nt1, nt2, nt3) => {
143                op3.enumerate(op3, exec, [*nt1, *nt2, *nt3])
144            }
145            ProdRule::Nt(_) => todo!(),
146        }
147    }
148}
149
150
151// #[derive(From, Into, Deref)]
152// pub struct EnumerationCfg(Vec<Vec<EnumeratorEnum>>);
153
154// impl EnumerationCfg {
155//     pub fn from_cfg(cfg: & Cfg, ctx: &Context) -> Self {
156//         cfg.iter().enumerate().map(|(i,x)| {
157//             // if x.ty == Type::Bool && !cfg.condition_search { return Vec::new(); }
158//             let first = EnumeratorEnum::from(TextObjEnumerator(i));
159//             let mut v = vec![first];
160//             v.append(&mut x.rules.iter().map(|r| EnumeratorEnum::from_rule(r.clone(), cfg, ctx)).collect_vec());
161//             v
162//     }).collect_vec().into()
163//     }
164//     pub fn enumerate(&self, data: &[Data], size: usize, nt: usize, mut f: impl EnumFn) -> Result<(), ()> {
165//         this.0[nt].iter().try_for_each(|e| e.enumerate(data, size, &mut f))
166//     }
167// }
168
169
170// #[enum_dispatch]
171// pub trait Enumerator {
172//     fn enumerate(&self, data: &[Data], size: usize, f: impl EnumFn) -> Result<(), ()>;
173// }
174
175
176
177// #[enum_dispatch(Enumerator)]
178// pub enum EnumeratorEnum { NoEnumerator, TextObjEnumerator, Single, Enumerator1, Enumerator2, Enumerator3 }
179
180// impl EnumeratorEnum {
181//     fn from_rule(value: ProdRule, graph: &Cfg, ctx: &Context) -> Self {
182//         match value {
183//             ProdRule::Const(c) => {
184//                 Single::new(Expr::Const(c), c.value(ctx.len()), 1).into()
185//             }
186//             ProdRule::Var(v) => {
187//                 if v >= 0 { return NoEnumerator.into(); }
188//                 Single::new(Expr::Var(v), ctx.get(v).unwrap().clone(), 1).into()
189//             }
190//             ProdRule::Op1(op1, nt1) => {
191//                 // if op1.name().ends_with(".parse") { return NoEnumerator.into(); }
192//                 // if op1.name().ends_with(".fmt") { return NoEnumerator.into(); }
193//                 Enumerator1::new(op1.clone(), nt1, op1.cost()).into()
194//             }
195//             ProdRule::Op2(op2, nt1, nt2) => {
196//                 if cfg.get_bool("condsearchonly").unwrap_or(false) && !graph.condition_search {
197//                     return NoEnumerator.into();
198//                 }
199//                 Enumerator2::new(op2.clone(), (nt1, nt2), op2.cost()).into()
200//             }
201//             ProdRule::Op3(op3, nt1, nt2, nt3) => {
202//                 if let Op3Enum::Ite(_) = op3 {
203//                     return NoEnumerator.into();
204//                 }
205//                 Enumerator3::new(op3, (nt1, nt2, nt3), get_opsize(cfg, graph.condition_search)).into()
206//             }
207//             ProdRule::Nt(_, _) => todo!(),
208//         }
209//     }
210// }
211
212// fn get_opsize(cfg: Config, cond_search: bool) -> usize {
213//     if cond_search {
214//         cfg.get_i64("cond_opsize").unwrap_or(get_opsize(cfg, false) as i64) as usize
215//     } else {
216//         cfg.get_i64("opsize").unwrap_or(1) as usize
217//     }
218// }