poi/
lib.rs

1#![deny(missing_docs)]
2#![doc = include_str!("../README.md")]
3
4use std::sync::Arc;
5
6use self::Expr::*;
7use self::Op::*;
8use self::Value::*;
9use self::Knowledge::*;
10use self::Symbol::*;
11
12pub use val::*;
13pub use expr::*;
14pub use op::Op;
15pub use sym::*;
16pub use standard_library::*;
17pub use parsing::*;
18pub use knowledge::*;
19
20mod val;
21mod expr;
22mod op;
23mod sym;
24mod knowledge;
25mod standard_library;
26mod parsing;
27mod arity;
28mod matrix;
29
30/// Used to global import enum variants.
31pub mod prelude {
32    pub use super::*;
33    pub use super::Expr::*;
34    pub use super::Op::*;
35    pub use super::Value::*;
36    pub use super::Knowledge::*;
37    pub use super::Symbol::*;
38}
39
40impl Into<Expr> for bool {
41    fn into(self) -> Expr {Ret(Bool(self))}
42}
43
44impl Into<Expr> for f64 {
45    fn into(self) -> Expr {Ret(F64(self))}
46}
47
48impl<T, U> Into<Expr> for (T, U)
49    where T: Into<Expr>, U: Into<Expr>
50{
51    fn into(self) -> Expr {Tup(vec![self.0.into(), self.1.into()])}
52}
53
54impl<T0, T1, T2> Into<Expr> for (T0, T1, T2)
55    where T0: Into<Expr>, T1: Into<Expr>, T2: Into<Expr>
56{
57    fn into(self) -> Expr {Tup(vec![self.0.into(), self.1.into(), self.2.into()])}
58}
59
60impl Expr {
61    /// Returns available equivalences of the expression, using a knowledge base.
62    pub fn equivalences(&self, knowledge: &[Knowledge]) -> Vec<(Expr, usize)> {
63        let mut ctx = Context {vars: vec![]};
64        let mut res = vec![];
65        for i in 0..knowledge.len() {
66            if let Eqv(a, b) | EqvEval(a, b) = &knowledge[i] {
67                if ctx.bind(a, self) {
68                    let expr = match ctx.substitute(b) {
69                        Ok(expr) => expr,
70                        Err(_) => {
71                            // Silence errors since the equivalence might not be relevant.
72                            // This should probably be handled better.
73                            ctx.vars.clear();
74                            continue;
75                        }
76                    };
77                    res.push((expr, i));
78                    ctx.vars.clear();
79                } else if ctx.bind(b, self) {
80                    let expr = match ctx.substitute(a) {
81                        Ok(expr) => expr,
82                        Err(_) => {
83                            // Silence errors since not all variables can be bound.
84                            // This should probably be handled better.
85                            ctx.vars.clear();
86                            continue;
87                        }
88                    };
89                    res.push((expr, i));
90                    ctx.vars.clear();
91                }
92            }
93        }
94
95        match self {
96            Sym(_) | Ret(_) => {}
97            EOp(op, a, b) => {
98                for (ea, i) in a.equivalences(knowledge).into_iter() {
99                    res.push((EOp(*op, Box::new(ea), b.clone()), i));
100                }
101                for (eb, i) in b.equivalences(knowledge).into_iter() {
102                    res.push((EOp(*op, a.clone(), Box::new(eb)), i));
103                }
104            }
105            Tup(items) | List(items) => {
106                for i in 0..items.len() {
107                    for (expr, j) in items[i].equivalences(knowledge).into_iter() {
108                        let mut new_items: Vec<Expr> = items[0..i].into();
109                        new_items.push(expr);
110                        new_items.extend(items[i+1..].iter().map(|n| n.clone()));
111                        if let Tup(_) = self {
112                            res.push((Tup(new_items), j));
113                        } else if let List(_) = self {
114                            res.push((List(new_items), j));
115                        }
116                    }
117                }
118            }
119        }
120
121        res
122    }
123
124    /// Returns `true` if expressions contains NaN (not a number).
125    pub fn contains_nan(&self) -> bool {
126        match self {
127            Sym(_) => false,
128            Ret(F64(v)) => v.is_nan(),
129            Ret(_) => false,
130            EOp(_, a, b) => a.contains_nan() || b.contains_nan(),
131            Tup(items) | List(items) => items.iter().any(|n| n.contains_nan()),
132        }
133    }
134
135    /// Evaluate an expression using a knowledge base.
136    ///
137    /// This combines reductions and inlining of all symbols.
138    pub fn eval(&self, knowledge: &[Knowledge]) -> Result<Expr, Error> {
139        let mut me = self.clone();
140        while !me.contains_nan() {
141            let expr = me.reduce_eval_all(knowledge, true).inline_all(knowledge)?;
142            if expr == me {break};
143            me = expr;
144        }
145        Ok(me)
146    }
147
148    /// Reduces an expression using a knowledge base, until it can not be reduces further.
149    pub fn reduce_all(&self, knowledge: &[Knowledge]) -> Expr {
150        self.reduce_eval_all(knowledge, false)
151    }
152
153    /// Reduces an expression using a knowledge base, until it can not be reduces further.
154    pub fn reduce_eval_all(&self, knowledge: &[Knowledge], eval: bool) -> Expr {
155        let mut me = self.clone();
156        while let Ok((expr, _)) = me.reduce_eval(knowledge, eval) {me = expr}
157        me
158    }
159
160    /// Reduces expression one step using a knowledge base.
161    pub fn reduce(&self, knowledge: &[Knowledge]) -> Result<(Expr, usize), Error> {
162        self.reduce_eval(knowledge, false)
163    }
164
165    /// Reduces expression one step using a knowledge base.
166    ///
167    /// When `eval` is set to `true`, the `EqvEval` variants are reduced.
168    pub fn reduce_eval(&self, knowledge: &[Knowledge], eval: bool) -> Result<(Expr, usize), Error> {
169        let mut ctx = Context {vars: vec![]};
170        let mut me: Result<(Expr, usize), Error> = Err(Error::NoReductionRule);
171        for i in 0..knowledge.len() {
172            if eval {
173                if let Red(a, b) | EqvEval(a, b) = &knowledge[i] {
174                    if ctx.bind(a, self) {
175                        me = match ctx.substitute(b) {
176                            Ok(expr) => Ok((expr, i)),
177                            Err(err) => Err(err),
178                        };
179                        break;
180                    }
181                }
182            } else {
183                if let Red(a, b) = &knowledge[i] {
184                    if ctx.bind(a, self) {
185                        me = match ctx.substitute(b) {
186                            Ok(expr) => Ok((expr, i)),
187                            Err(err) => Err(err),
188                        };
189                        break;
190                    }
191                }
192            }
193        }
194
195        match self {
196            EOp(op, a, b) => {
197                // Do not reduce sub-expressions containing type judgements in the parent,
198                // to avoid infinite expansion in rules introducing type judgements.
199                //
200                // Type judgements might still be used in pattern matching and binding of variables.
201                //
202                // For example, `a : T => ...` is still valid.
203                if let Type = op {
204                    // Make an exception for lists, in order to evaluate items of the list.
205                    if let List(_) = **a {} else {return me}
206                }
207
208                if let Ok((a, i)) = a.reduce_eval(knowledge, eval) {
209                    // Prefer the reduction that matches the first rule.
210                    if let Ok((expr, j)) = me {if j < i {return Ok((expr, j))}};
211                    return Ok((EOp(*op, Box::new(a), b.clone()), i));
212                }
213                if let Ok((b, i)) = b.reduce_eval(knowledge, eval) {
214                    // Prefer the reduction that matches the first rule.
215                    if let Ok((expr, j)) = me {if j < i {return Ok((expr, j))}};
216                    return Ok((EOp(*op, a.clone(), Box::new(b)), i));
217                }
218            }
219            Tup(a) | List(a) => {
220                let mut res = vec![];
221                for i in 0..a.len() {
222                    if let Ok((n, j)) = a[i].reduce_eval(knowledge, eval) {
223                        // Prefer the reduction that matches the first rule.
224                        if let Ok((expr, k)) = me {if k < j {return Ok((expr, k))}};
225                        res.push(n);
226                        res.extend(a[i+1..].iter().map(|n| n.clone()));
227                        if let Tup(_) = self {
228                            return Ok((Tup(res), j));
229                        } else if let List(_) = self {
230                            return Ok((List(res), j));
231                        } else {
232                            unreachable!();
233                        }
234                    } else {
235                        res.push(a[i].clone());
236                    }
237                }
238            }
239            _ => {}
240        }
241
242        me
243    }
244
245    /// Inlines all symbols using a knowledge base.
246    ///
247    /// Ignores missing definitions in domain constraints.
248    pub fn inline_all(&self, knowledge: &[Knowledge]) -> Result<Expr, Error> {
249        match self {
250            Sym(a) => {
251                for i in 0..knowledge.len() {
252                    if let Def(b, c) = &knowledge[i] {
253                        if b == a {
254                            return Ok(c.clone());
255                        }
256                    }
257                }
258                Err(Error::NoDefinition)
259            }
260            Ret(_) => Ok(self.clone()),
261            EOp(op, a, b) => {
262                if let Constrain = op {
263                    let a = a.inline_all(knowledge)?;
264                    match b.inline_all(knowledge) {
265                        Err(Error::NoDefinition) => Ok(a),
266                        Err(err) => Err(err),
267                        Ok(b) => Ok(constr(a, b)),
268                    }
269                } else {
270                    match (a.inline_all(knowledge), b.inline_all(knowledge)) {
271                        (Ok(a), Ok(b)) => Ok(EOp(
272                            *op,
273                            Box::new(a),
274                            Box::new(b)
275                        )),
276                        (Ok(a), Err(_)) => Ok(EOp(
277                            *op,
278                            Box::new(a),
279                            b.clone()
280                        )),
281                        (Err(_), Ok(b)) => Ok(EOp(
282                            *op,
283                            a.clone(),
284                            Box::new(b)
285                        )),
286                        (err, _) => err,
287                    }
288                }
289            }
290            Tup(a) => {
291                let mut res = vec![];
292                for i in 0..a.len() {
293                    res.push(a[i].inline_all(knowledge)?);
294                }
295                Ok(Tup(res))
296            }
297            List(a) => {
298                let mut res = vec![];
299                for i in 0..a.len() {
300                    res.push(a[i].inline_all(knowledge)?);
301                }
302                Ok(List(res))
303            }
304        }
305    }
306
307    /// Inline a symbol using a knowledge base.
308    pub fn inline(&self, sym: &Symbol, knowledge: &[Knowledge]) -> Result<Expr, Error> {
309        match self {
310            Sym(a) if a == sym => {
311                for i in 0..knowledge.len() {
312                    if let Def(b, c) = &knowledge[i] {
313                        if b == a {
314                            return Ok(c.clone());
315                        }
316                    }
317                }
318                Err(Error::NoDefinition)
319            }
320            Sym(_) | Ret(_) => Ok(self.clone()),
321            EOp(op, a, b) => {
322                Ok(EOp(
323                    *op,
324                    Box::new(a.inline(sym, knowledge)?),
325                    Box::new(b.inline(sym, knowledge)?)
326                ))
327            }
328            Tup(a) => {
329                let mut res = vec![];
330                for i in 0..a.len() {
331                    res.push(a[i].inline(sym, knowledge)?);
332                }
333                Ok(Tup(res))
334            }
335            List(a) => {
336                let mut res = vec![];
337                for i in 0..a.len() {
338                    res.push(a[i].inline(sym, knowledge)?);
339                }
340                Ok(List(res))
341            }
342        }
343    }
344
345    /// Returns `true` if a function has any constraints, `false` if there are none constraints.
346    ///
347    /// This is used in the following rules in the standard library, using `no_constr`:
348    ///
349    /// - `∀(f:!{}) => \true`
350    /// - `f:!{}([x..]) => f{(: vec)}(x)`
351    /// - `f:!{}(a)(a) <=> f{eq}(a)(a)`
352    ///
353    /// For example, to detect whether it is safe to insert a new constraint.
354    /// This check is important because a constraint refers to one or more arguments.
355    /// By introducing a new constraint that refers incorrectly to its argument,
356    /// it leads to unsoundness.
357    ///
358    /// A function has none constraints if it is applied enough times to cover existing constraints.
359    /// This means the total arity of constraints is less or equal than the total arity of arguments.
360    ///
361    /// To avoid unsoundness under uncertain edge cases, this function should return `true`.
362    /// This is because the `no_constr` check fails to pattern match, which is safe,
363    /// since inactive rules do not introduce unsoundness.
364    ///
365    /// Unfinished: This function requires analysis and unit testing.
366    pub fn has_constraint(&self, arity_args: usize) -> bool {
367        match self {
368            EOp(Constrain, f, a) => {
369                if let Some(arity) = a.arity() {
370                    if arity > arity_args {true}
371                    else {f.has_constraint(arity_args - arity)}
372                } else {
373                    true
374                }
375            }
376            EOp(Compose, a, b) => b.has_constraint(arity_args) || a.has_constraint(0),
377            EOp(Apply, f, _) => f.has_constraint(arity_args + 1),
378            Sym(_) => false,
379            Ret(_) => false,
380            _ => true
381        }
382    }
383
384    /// Returns `true` if expression is substitution.
385    pub fn is_substitution(&self) -> bool {
386        self.sub_is_substitution(3)
387    }
388
389    fn sub_is_substitution(&self, args: usize) -> bool {
390        match self {
391            EOp(Apply, f, _) if args > 0 => f.sub_is_substitution(args - 1),
392            Sym(Subst) if args == 0 => true,
393            _ => false,
394        }
395    }
396
397    /// Returns `true` if expression has non-constant type judgement.
398    pub fn has_non_constant_type_judgement(&self) -> bool {
399        match self {
400            EOp(Type, _, b) if **b == Sym(RetType) => false,
401            EOp(Type, _, _) => true,
402            _ => false
403        }
404    }
405}
406
407/// Stores variables bound by context.
408pub struct Context {
409    /// Contains the variables in the context.
410    pub vars: Vec<(Arc<String>, Expr)>,
411}
412
413impl Context {
414    /// Binds patterns of a `name` expression to a `value` expression.
415    pub fn bind(&mut self, name: &Expr, value: &Expr) -> bool {
416        match (name, value) {
417            (Sym(NoSubstVar(_)), v) if v.is_substitution() => {
418                self.vars.clear();
419                false
420            }
421            (Sym(NoConstrVar(_)), v) if v.has_constraint(0) => {
422                self.vars.clear();
423                false
424            }
425            (Sym(Var(_)), Tup(_)) | (Sym(NoConstrVar(_)), Tup(_)) => {
426                self.vars.clear();
427                false
428            }
429            // Do not pattern match variables to type judgements,
430            // since the type judgements might imply exceptions to default rules.
431            // Constant type judgements are treated as normal.
432            (Sym(Var(_)), v) if v.has_non_constant_type_judgement() => {
433                self.vars.clear();
434                false
435            }
436            (Sym(Var(name)), x) |
437            (Sym(NoConstrVar(name)), x) |
438            (Sym(NoSubstVar(name)), x) => {
439                for i in (0..self.vars.len()).rev() {
440                    if &self.vars[i].0 == name {
441                        if &self.vars[i].1 == x {
442                            break
443                        } else {
444                            self.vars.clear();
445                            return false;
446                        }
447                    }
448                }
449                self.vars.push((name.clone(), x.clone()));
450                true
451            }
452            (Sym(ArityVar(name, n)), x) if x.arity() == Some(*n) => {
453                for i in (0..self.vars.len()).rev() {
454                    if &self.vars[i].0 == name {
455                        if &self.vars[i].1 == x {
456                            break
457                        } else {
458                            self.vars.clear();
459                            return false;
460                        }
461                    }
462                }
463                self.vars.push((name.clone(), x.clone()));
464                true
465            }
466            // `x!>y` means `x` does not occur in expression `y`.
467            // This is used by rules for partial derivatives.
468            (Sym(NotInVarName(name, y)), x) => {
469                // Returns a list of names in expression.
470                fn get_names(expr: &Expr, ret: &mut Vec<Arc<String>>) {
471                    match expr {
472                        Sym(Var(y)) => ret.push(y.clone()),
473                        Sym(y) if y.arity().is_some() => {}
474                        Ret(_) => {}
475                        Tup(list) | List(list) => {
476                            for x in list {
477                                get_names(x, ret);
478                            }
479                        }
480                        EOp(Apply, a, b) => {
481                            get_names(a, ret);
482                            get_names(b, ret);
483                        }
484                        // TODO: Handle other cases.
485                        _ => {}
486                        // x => panic!("not-in-var: {:?}", x),
487                    }
488                }
489                // Returns `true` if expression contains some variable `x`.
490                fn contains(expr: &Expr, x: &Arc<String>) -> bool {
491                    match expr {
492                        Sym(Var(y)) => return x == y,
493                        Sym(y) if y.arity().is_some() => return false,
494                        Ret(_) => return false,
495                        Tup(list) | List(list) => return list.iter().any(|expr| contains(expr, x)),
496                        EOp(Apply, a, b) => return contains(a, x) || contains(b, x),
497                        // TODO: Handle other cases.
498                        _ => {}
499                        // x => panic!("not-in-var: {:?}", x),
500                    }
501                    true
502                }
503
504                let mut names = vec![];
505                get_names(x, &mut names);
506                for i in (0..self.vars.len()).rev() {
507                    // Match against previous occurences of same variable.
508                    if &self.vars[i].0 == name {
509                        if &self.vars[i].1 == x {continue}
510                        else {
511                            self.vars.clear();
512                            return false;
513                        }
514                    } else if &self.vars[i].0 == y {
515                        // It is sufficient that at least one name is missing,
516                        // to prove that no term can be constructed that matches the derivative.
517                        if names.iter().any(|name| {
518                            !contains(&self.vars[i].1, name)
519                        }) {continue}
520                        else {
521                            self.vars.clear();
522                            return false;
523                        }
524                    }
525                }
526                self.vars.push((name.clone(), x.clone()));
527                true
528            }
529            (Sym(NotRetVar(_)), Ret(_)) | (Sym(NotRetVar(_)), Tup(_)) => {
530                self.vars.clear();
531                false
532            }
533            (Sym(NotRetVar(name)), _) => {
534                for i in (0..self.vars.len()).rev() {
535                    if &self.vars[i].0 == name {
536                        if &self.vars[i].1 == value {
537                            break
538                        } else {
539                            self.vars.clear();
540                            return false;
541                        }
542                    }
543                }
544                self.vars.push((name.clone(), value.clone()));
545                true
546            }
547            (Sym(RetVar(name)), Ret(_)) => {
548                for i in (0..self.vars.len()).rev() {
549                    if &self.vars[i].0 == name {
550                        if &self.vars[i].1 == value {
551                            break
552                        } else {
553                            self.vars.clear();
554                            return false;
555                        }
556                    }
557                }
558                self.vars.push((name.clone(), value.clone()));
559                true
560            }
561            (Sym(RetIntVar(name)), Ret(F64(x))) if x % 1.0 == 0.0 => {
562                for i in (0..self.vars.len()).rev() {
563                    if &self.vars[i].0 == name {
564                        if &self.vars[i].1 == value {
565                            break
566                        } else {
567                            self.vars.clear();
568                            return false;
569                        }
570                    }
571                }
572                self.vars.push((name.clone(), value.clone()));
573                true
574            }
575            (Sym(RetPosVar(name)), Ret(F64(x))) if *x >= 0.0 => {
576                for i in (0..self.vars.len()).rev() {
577                    if &self.vars[i].0 == name {
578                        if &self.vars[i].1 == value {
579                            break
580                        } else {
581                            self.vars.clear();
582                            return false;
583                        }
584                    }
585                }
586                self.vars.push((name.clone(), value.clone()));
587                true
588            }
589            (Sym(RetStrictPosVar(name)), Ret(F64(x))) if *x > 0.0 => {
590                for i in (0..self.vars.len()).rev() {
591                    if &self.vars[i].0 == name {
592                        if &self.vars[i].1 == value {
593                            break
594                        } else {
595                            self.vars.clear();
596                            return false;
597                        }
598                    }
599                }
600                self.vars.push((name.clone(), value.clone()));
601                true
602            }
603            (Sym(RetNegVar(name)), Ret(F64(x))) if *x < 0.0 => {
604                for i in (0..self.vars.len()).rev() {
605                    if &self.vars[i].0 == name {
606                        if &self.vars[i].1 == value {
607                            break
608                        } else {
609                            self.vars.clear();
610                            return false;
611                        }
612                    }
613                }
614                self.vars.push((name.clone(), Ret(F64(x.abs()))));
615                true
616            }
617            (Sym(Singleton(name)), List(x)) if x.len() == 1 => {
618                self.vars.push((name.clone(), x[0].clone()));
619                true
620            }
621            (Sym(ListVar(name)), List(_)) => {
622                self.vars.push((name.clone(), value.clone()));
623                true
624            }
625            (Sym(HeadTailTup(head, tail)), Tup(list)) |
626            (Sym(HeadTailList(head, tail)), List(list)) => {
627                if list.len() < 2 {return false};
628
629                let r = self.bind(head, &list[0]);
630                let b: Expr = if let (Sym(HeadTailTup(_, _)), Tup(_)) = (name, value) {
631                    if list[1..].len() == 1 {
632                        list[1].clone()
633                    } else {
634                        Tup(list[1..].into())
635                    }
636                } else {
637                    List(list[1..].into())
638                };
639
640                if r {
641                    if let Sym(Var(tail)) = &**tail {
642                        for i in (0..self.vars.len()).rev() {
643                            if &self.vars[i].0 == tail {
644                                if &self.vars[i].1 == &b {
645                                    break
646                                } else {
647                                    self.vars.clear();
648                                    return false;
649                                }
650                            }
651                        }
652                        self.vars.push((tail.clone(), b));
653                        true
654                    } else {
655                        self.vars.clear();
656                        false
657                    }
658                } else {
659                    self.vars.clear();
660                    false
661                }
662            }
663            (Sym(Any), _) => true,
664            (Sym(a), Sym(b)) if a == b => true,
665            (Ret(a), Ret(b)) if a == b => true,
666            (EOp(op1, a1, b1), EOp(op2, a2, b2)) if op1 == op2 => {
667                let r = self.bind(a1, a2) && self.bind(b1, b2);
668                if !r {self.vars.clear()};
669                r
670            }
671            (Tup(a), Tup(b)) if a.len() == b.len() => {
672                let mut all = true;
673                for i in 0..a.len() {
674                    let r = self.bind(&a[i], &b[i]);
675                    if !r {
676                        all = false;
677                        break;
678                    }
679                }
680                if !all {self.vars.clear()};
681                all
682            }
683            (List(a), List(b)) if a.len() == b.len() => {
684                let mut all = true;
685                for i in 0..a.len() {
686                    let r = self.bind(&a[i], &b[i]);
687                    if !r {
688                        all = false;
689                        break;
690                    }
691                }
692                if !all {self.vars.clear()};
693                all
694            }
695            _ => {
696                self.vars.clear();
697                false
698            }
699        }
700    }
701
702    /// Substitute free occurences of variables in context.
703    ///
704    /// This is used on the right side in a reduction rule.
705    pub fn substitute(&self, x: &Expr) -> Result<Expr, Error> {
706        match x {
707            // Don't synthesize `_`.
708            Sym(Any) => Err(Error::InvalidComputation),
709            Sym(NoSubstVar(_)) => Err(Error::InvalidComputation),
710            Sym(RetNegVar(_)) => Err(Error::InvalidComputation),
711            Sym(Var(name)) | Sym(ArityVar(name, _)) => {
712                for i in (0..self.vars.len()).rev() {
713                    if &self.vars[i].0 == name {
714                        return Ok(self.vars[i].1.clone())
715                    }
716                }
717                Err(Error::CouldNotFind(name.clone()))
718            }
719            Sym(UnopRetVar(a, f)) => {
720                let mut av: Option<Expr> = None;
721                for i in (0..self.vars.len()).rev() {
722                    if &self.vars[i].0 == a {
723                        av = Some(self.vars[i].1.clone());
724                    }
725                }
726                match av {
727                    Some(Ret(F64(a))) => {
728                        Ok(match **f {
729                            Even => Ret(Bool(a.round() % 2.0 == 0.0)),
730                            Odd => Ret(Bool(a.round() % 2.0 == 1.0)),
731                            Neg => Ret(F64(-a)),
732                            Inc => Ret(F64(a + 1.0)),
733                            Reci => if a == 0.0 {
734                                return Err(Error::InvalidComputation)
735                            } else {
736                                Ret(F64(a.recip()))
737                            },
738                            Abs => Ret(F64(a.abs())),
739                            Prob => Ret(Bool(a >= 0.0 && a <= 1.0)),
740                            Probl => Ret(Bool(a >= 0.0 && a < 1.0)),
741                            Probr => Ret(Bool(a > 0.0 && a <= 1.0)),
742                            Probm => Ret(Bool(a > 0.0 && a < 1.0)),
743                            Sqrt => Ret(F64(a.sqrt())),
744                            Ln => Ret(F64(a.ln())),
745                            Log2 => Ret(F64(a.log2())),
746                            Log10 => Ret(F64(a.log10())),
747                            Exp => Ret(F64(a.exp())),
748                            Sin => Ret(F64(a.sin())),
749                            Asin => Ret(F64(a.asin())),
750                            Cos => Ret(F64(a.cos())),
751                            Acos => Ret(F64(a.acos())),
752                            Tan => Ret(F64(a.tan())),
753                            Atan => Ret(F64(a.atan())),
754                            TypeOf => Sym(F64Type),
755                            _ => return Err(Error::InvalidComputation),
756                        })
757                    }
758                    Some(List(a)) => {
759                        Ok(match **f {
760                            Len => Ret(F64(a.len() as f64)),
761                            Dim => matrix::dim(&a)?,
762                            Transpose => matrix::transpose(&a)?,
763                            IsSquareMat => matrix::is_square_mat(&a)?,
764                            _ => return Err(Error::InvalidComputation),
765                        })
766                    }
767                    Some(a) => {
768                        Ok(match **f {
769                            Arity => {
770                                if let Some(n) = a.arity() {Ret(F64(n as f64))}
771                                else {return Err(Error::InvalidComputation)}
772                            }
773                            _ => return Err(Error::InvalidComputation),
774                        })
775                    }
776                    _ => Err(Error::CouldNotFind(a.clone())),
777                }
778            }
779            Sym(BinopRetVar(a, b, f)) => {
780                let mut av: Option<Expr> = None;
781                let mut bv: Option<Expr> = None;
782                for i in (0..self.vars.len()).rev() {
783                    if &self.vars[i].0 == a {
784                        av = Some(self.vars[i].1.clone());
785                    }
786                    if &self.vars[i].0 == b {
787                        bv = Some(self.vars[i].1.clone());
788                    }
789                }
790                match (av, bv) {
791                    (Some(Ret(a)), Some(Ret(b))) if **f == Eq => Ok(Ret(Bool(a == b))),
792                    (Some(Ret(F64(a))), Some(Ret(F64(b)))) => {
793                        Ok(Ret(F64(match **f {
794                            Lt => return Ok(Ret(Bool(a < b))),
795                            Le => return Ok(Ret(Bool(a <= b))),
796                            Gt => return Ok(Ret(Bool(a > b))),
797                            Ge => return Ok(Ret(Bool(a >= b))),
798                            Add => a + b,
799                            Sub => a - b,
800                            Mul => a * b,
801                            Pow => a.powf(b),
802                            Rem => if b == 0.0 {
803                                return Err(Error::InvalidComputation)
804                            } else {
805                                a % b
806                            }
807                            Div => if b == 0.0 {
808                                return Err(Error::InvalidComputation)
809                            } else {
810                                a / b
811                            }
812                            Max2 => if a >= b {a} else {b},
813                            Min2 => if a <= b {a} else {b},
814                            Base if b >= 0.0 && b < a => {
815                                let mut r = vec![Ret(F64(0.0)); a as usize];
816                                r[b as usize] = Ret(F64(1.0));
817                                return Ok(List(r))
818                            }
819                            Atan2 => return Ok(Ret(F64(a.atan2(b)))),
820                            _ => return Err(Error::InvalidComputation),
821                        })))
822                    }
823                    (Some(Ret(F64(a))), Some(List(b))) => {
824                        Ok(match **f {
825                            Item if a >= 0.0 && a < b.len() as f64 =>
826                                b[a as usize].clone(),
827                            Col if a >= 0.0 => matrix::col(a, &b)?,
828                            _ => return Err(Error::InvalidComputation),
829                        })
830                    }
831                    (Some(List(a)), Some(List(b))) => {
832                        Ok(match **f {
833                            Concat => {
834                                let mut a = a.clone();
835                                a.extend(b.iter().map(|n| n.clone()));
836                                List(a)
837                            }
838                            MulMat => matrix::mul_mat(&a, &b)?,
839                            _ => return Err(Error::InvalidComputation),
840                        })
841                    }
842                    (Some(List(a)), Some(b)) => {
843                        Ok(match **f {
844                            Push => {
845                                let mut a = a.clone();
846                                a.push(b);
847                                List(a)
848                            }
849                            PushFront => {
850                                let mut a = a.clone();
851                                a.insert(0, b);
852                                List(a)
853                            }
854                            _ => return Err(Error::InvalidComputation),
855                        })
856                    }
857                    (av, _) => {
858                        if av.is_none() {
859                            Err(Error::CouldNotFind(a.clone()))
860                        } else {
861                            Err(Error::CouldNotFind(b.clone()))
862                        }
863                    }
864                }
865            }
866            Sym(TernopRetVar(a, b, c, f)) => {
867                let mut av: Option<Expr> = None;
868                let mut bv: Option<Expr> = None;
869                let mut cv: Option<Expr> = None;
870                for i in (0..self.vars.len()).rev() {
871                    if &self.vars[i].0 == a {
872                        av = Some(self.vars[i].1.clone());
873                    }
874                    if &self.vars[i].0 == b {
875                        bv = Some(self.vars[i].1.clone());
876                    }
877                    if &self.vars[i].0 == c {
878                        cv = Some(self.vars[i].1.clone());
879                    }
880                }
881                match (av, bv, cv) {
882                    (Some(Ret(F64(a))), Some(Ret(F64(b))), Some(Ret(F64(c)))) => {
883                        Ok(match **f {
884                            Range => if c >= a && c <= b {Ret(Bool(true))}
885                                     else {Ret(Bool(false))},
886                            Rangel => if c >= a && c < b {Ret(Bool(true))}
887                                      else {Ret(Bool(false))},
888                            Ranger => if c > a && c <= b {Ret(Bool(true))}
889                                      else {Ret(Bool(false))},
890                            Rangem => if c > a && c < b {Ret(Bool(true))}
891                                      else {Ret(Bool(false))},
892                            _ => return Err(Error::InvalidComputation)
893                        })
894                    }
895                    (av, bv, _) => {
896                        if av.is_none() {
897                            Err(Error::CouldNotFind(a.clone()))
898                        } else if bv.is_none() {
899                            Err(Error::CouldNotFind(b.clone()))
900                        } else {
901                            Err(Error::CouldNotFind(c.clone()))
902                        }
903                    }
904                }
905            }
906            Sym(_) | Ret(_) => Ok(x.clone()),
907            EOp(op, a, b) => {
908                Ok(EOp(*op, Box::new(self.substitute(a)?), Box::new(self.substitute(b)?)))
909            }
910            Tup(a) => {
911                let mut res = vec![];
912                for i in 0..a.len() {
913                    res.push(self.substitute(&a[i])?);
914                }
915                Ok(Tup(res))
916            }
917            List(a) => {
918                let mut res = vec![];
919                for i in 0..a.len() {
920                    res.push(self.substitute(&a[i])?);
921                }
922                Ok(List(res))
923            }
924        }
925    }
926}
927
928/// Represents an error.
929#[derive(Debug, PartialEq)]
930pub enum Error {
931    /// Invalid function for computing something from left side of expression to right side.
932    InvalidComputation,
933    /// There was no defintion of the symbol.
934    NoDefinition,
935    /// There was no matching reduction rule.
936    NoReductionRule,
937    /// Could not find variable.
938    CouldNotFind(Arc<String>),
939}
940
941impl Into<Expr> for Symbol {
942    fn into(self) -> Expr {Sym(self)}
943}
944
945impl Into<Expr> for &'static str {
946    fn into(self) -> Expr {Sym(self.into())}
947}
948
949impl Into<Symbol> for &'static str {
950    fn into(self) -> Symbol {Symbol::from(Arc::new(self.into()))}
951}
952
953/// A function applied to one argument.
954pub fn app<A: Into<Expr>, B: Into<Expr>>(a: A, b: B) -> Expr {
955    EOp(Apply, Box::new(a.into()), Box::new(b.into()))
956}
957
958/// A function applied to two arguments.
959pub fn app2<A: Into<Expr>, B: Into<Expr>, C: Into<Expr>>(a: A, b: B, c: C) -> Expr {
960    app(app(a, b), c)
961}
962
963/// A function applied to three arguments.
964pub fn app3<A: Into<Expr>, B: Into<Expr>, C: Into<Expr>, D: Into<Expr>>(
965    a: A, b: B, c: C, d: D
966) -> Expr {
967    app2(app(a, b), c, d)
968}
969
970/// A function composition.
971pub fn comp<A: Into<Expr>, B: Into<Expr>>(a: A, b: B) -> Expr {
972    EOp(Compose, Box::new(a.into()), Box::new(b.into()))
973}
974
975/// A normal path expression.
976pub fn path<A: Into<Expr>, B: Into<Expr>>(a: A, b: B) -> Expr {
977    EOp(Path, Box::new(a.into()), Box::new(b.into()))
978}
979
980/// A function domain constraint.
981pub fn constr<A: Into<Expr>, B: Into<Expr>>(a: A, b: B) -> Expr {
982    EOp(Constrain, Box::new(a.into()), Box::new(b.into()))
983}
984
985/// A function domain constraint with two arguments.
986pub fn constr2<A: Into<Expr>, B: Into<Expr>, C: Into<Expr>>(a: A, b: B, c: C) -> Expr {
987    constr(constr(a, b), c)
988}
989
990/// A type judgement.
991pub fn typ<A: Into<Expr>, B: Into<Expr>>(a: A, b: B) -> Expr {
992    EOp(Type, Box::new(a.into()), Box::new(b.into()))
993}
994
995/// An `if` expression.
996pub fn _if<A: Into<Expr>, B: Into<Expr>>(a: A, b: B) -> Expr {app(app(If, a), b)}
997
998/// A head-tail pattern match on a tuple.
999pub fn head_tail_tup<A: Into<Expr>, B: Into<Expr>>(a: A, b: B) -> Expr {
1000    HeadTailTup(Box::new(a.into()), Box::new(b.into())).into()
1001}
1002
1003/// A head-tail pattern match on a list.
1004pub fn head_tail_list<A: Into<Expr>, B: Into<Expr>>(a: A, b: B) -> Expr {
1005    HeadTailList(Box::new(a.into()), Box::new(b.into())).into()
1006}
1007
1008/// A function variable with arity (number of arguments).
1009pub fn arity_var<A: Into<String>>(a: A, n: usize) -> Expr {Sym(ArityVar(Arc::new(a.into()), n))}
1010
1011/// A list variable.
1012pub fn list_var<A: Into<String>>(a: A) -> Expr {Sym(ListVar(Arc::new(a.into())))}
1013
1014/// A list variable of length 1.
1015pub fn singleton<A: Into<String>>(a: A) -> Expr {Sym(Singleton(Arc::new(a.into())))}
1016
1017/// A value variable.
1018pub fn ret_var<A: Into<String>>(a: A) -> Expr {Sym(RetVar(Arc::new(a.into())))}
1019
1020/// A value variable that is an integer.
1021pub fn ret_int_var<A: Into<String>>(a: A) -> Expr {Sym(RetIntVar(Arc::new(a.into())))}
1022
1023/// A value variable that is positive or zero.
1024pub fn ret_pos_var<A: Into<String>>(a: A) -> Expr {Sym(RetPosVar(Arc::new(a.into())))}
1025
1026/// A value variable that is strictly positive (non-zero).
1027pub fn ret_strict_pos_var<A: Into<String>>(a: A) -> Expr {Sym(RetStrictPosVar(Arc::new(a.into())))}
1028
1029/// A value variable that is negative and non-zero.
1030///
1031/// Binds to its positive value.
1032pub fn ret_neg_var<A: Into<String>>(a: A) -> Expr {Sym(RetNegVar(Arc::new(a.into())))}
1033
1034/// A variable that is not a value variable.
1035pub fn not_ret_var<A: Into<String>>(a: A) -> Expr {Sym(NotRetVar(Arc::new(a.into())))}
1036
1037/// A variable of the type value `a : \`.
1038pub fn ret_type_var<A: Into<String>>(a: A) -> Expr {
1039    EOp(Type, Box::new(Sym(Var(Arc::new(a.into())))), Box::new(Sym(RetType)))
1040}
1041
1042/// Compute a binary function.
1043pub fn binop_ret_var<A: Into<String>, B: Into<String>, F: Into<Symbol>>(a: A, b: B, f: F) -> Expr {
1044    Sym(BinopRetVar(Arc::new(a.into()), Arc::new(b.into()), Box::new(f.into())))
1045}
1046
1047/// Compute a ternary function.
1048pub fn ternop_ret_var<A: Into<String>, B: Into<String>, C: Into<String>, F: Into<Symbol>>(
1049    a: A, b: B, c: C, f: F
1050) -> Expr {
1051    Sym(TernopRetVar(Arc::new(a.into()), Arc::new(b.into()), Arc::new(c.into()), Box::new(f.into())))
1052}
1053
1054/// Compute a unary function.
1055pub fn unop_ret_var<A: Into<String>, F: Into<Symbol>>(a: A, f: F) -> Expr {
1056    Sym(UnopRetVar(Arc::new(a.into()), Box::new(f.into())))
1057}
1058
1059/// A function without domain constraints.
1060pub fn no_constr<A: Into<String>>(a: A) -> Expr {
1061    Sym(NoConstrVar(Arc::new(a.into())))
1062}
1063
1064/// A 2D vector.
1065pub fn vec2<A: Into<Expr>, B: Into<Expr>>(a: A, b: B) -> Expr {List(vec![a.into(), b.into()])}
1066
1067/// A 4D vector.
1068pub fn vec4<X: Into<Expr>, Y: Into<Expr>, Z: Into<Expr>, W: Into<Expr>>(
1069    x: X, y: Y, z: Z, w: W
1070) -> Expr {
1071    List(vec![x.into(), y.into(), z.into(), w.into()])
1072}
1073
1074/// A quaternion.
1075pub fn quat<X: Into<Expr>, Y: Into<Expr>, Z: Into<Expr>, W: Into<Expr>>(
1076    x: X, y: Y, z: Z, w: W
1077) -> Expr {
1078    typ(List(vec![x.into(), y.into(), z.into(), w.into()]), QuatType)
1079}
1080
1081/// Knowledge about a component-wise operation on vectors.
1082pub fn vec_op<S: Into<Symbol>>(s: S) -> Knowledge {
1083    let s = s.into();
1084    Red(app(constr(app(constr(s.clone(), app(Rty, VecType)), "x"), app(Rty, VecType)), "y"),
1085        app2(app(VecOp, s), "x", "y"))
1086}
1087
1088/// Knowledge about a concrete binary operation `f(x : \, y : \) => f(x)(y) : \`.
1089pub fn concrete_op<S: Into<Symbol>>(s: S) -> Knowledge {
1090    let s = s.into();
1091    Red(app2(s.clone(), ret_type_var("x"), ret_type_var("y")), typ(app2(s, "x", "y"), RetType))
1092}
1093
1094/// Knowledge about a commuative binary operator.
1095pub fn commutative<S: Into<Symbol>>(s: S) -> Knowledge {
1096    let s = s.into();
1097    let a: Expr = "a".into();
1098    let b: Expr = "b".into();
1099    Eqv(app(app(s.clone(), a.clone()), b.clone()), app(app(s, b), a))
1100}
1101
1102/// Knowledge about an associative binary operator.
1103pub fn associative<S: Into<Symbol>>(s: S) -> Knowledge {
1104    let s = s.into();
1105    let a: Expr = "a".into();
1106    let b: Expr = "b".into();
1107    let c: Expr = "c".into();
1108    Eqv(app(app(s.clone(), a.clone()), app(app(s.clone(), b.clone()), c.clone())),
1109        app(app(s.clone(), app(app(s, a), b)), c))
1110}
1111
1112/// Knowledge about a distributive relationship.
1113pub fn distributive<M: Into<Symbol>, A: Into<Symbol>>(mul: M, add: A) -> Knowledge {
1114    let mul = mul.into();
1115    let add = add.into();
1116    let a: Expr = "a".into();
1117    let b: Expr = "b".into();
1118    let c: Expr = "c".into();
1119    Eqv(app(app(mul.clone(), a.clone()), app(app(add.clone(), b.clone()), c.clone())),
1120        app(app(add, app(app(mul.clone(), a.clone()), b)), app(app(mul, a), c)))
1121}
1122
1123#[cfg(test)]
1124mod tests {
1125    use super::*;
1126
1127    #[test]
1128    fn apply_not() {
1129        let ref std = std();
1130        let a = app(Not, true);
1131        let a = a.inline(&Not, std).unwrap();
1132        let a = a.reduce(std).unwrap().0;
1133        assert_eq!(a, false.into());
1134
1135        let a = app(Not, false);
1136        let a = a.inline(&Not, std).unwrap();
1137        let a = a.reduce(std).unwrap().0;
1138        assert_eq!(a, true.into());
1139    }
1140
1141    #[test]
1142    fn comp_not_not() {
1143        let ref std = std();
1144        let a = comp(Not, Not);
1145        let a = a.reduce(std).unwrap().0;
1146        assert_eq!(a, Idb.into());
1147    }
1148
1149    #[test]
1150    fn path_not_not() {
1151        let ref std = std();
1152        let a = path(Not, Not);
1153        let a = a.reduce(std).unwrap().0;
1154        assert_eq!(a, Not.into());
1155    }
1156
1157    #[test]
1158    fn comp_id() {
1159        let ref std = std();
1160
1161        let a = comp(Not, Id);
1162        let a = a.reduce(std).unwrap().0;
1163        assert_eq!(a, Not.into());
1164
1165        let a = comp(Id, Not);
1166        let a = a.reduce(std).unwrap().0;
1167        assert_eq!(a, Not.into());
1168    }
1169
1170    #[test]
1171    fn path_not_id() {
1172        let ref std = std();
1173        let a = path(Not, Id);
1174        let a = a.reduce(std).unwrap().0;
1175        assert_eq!(a, Not.into());
1176    }
1177
1178    #[test]
1179    fn constraints() {
1180        let f: Expr = "f".into();
1181        assert_eq!(f.has_constraint(0), false);
1182        let f: Expr = app(Not, false);
1183        assert_eq!(f.has_constraint(0), false);
1184        let f: Expr = constr(Not, true);
1185        assert_eq!(f.has_constraint(0), true);
1186        let f: Expr = And.into();
1187        assert_eq!(f.has_constraint(0), false);
1188        let f: Expr = constr(And, Eqb);
1189        assert_eq!(f.has_constraint(0), true);
1190        let f: Expr = constr(And, Not);
1191        assert_eq!(f.has_constraint(0), true);
1192        let f: Expr = app(constr(And, Not), "x");
1193        assert_eq!(f.has_constraint(0), false);
1194        let f: Expr = app(constr(And, Eqb), "x");
1195        assert_eq!(f.has_constraint(0), true);
1196        let f: Expr = app(And, false);
1197        assert_eq!(f.has_constraint(0), false);
1198        // `sum{(: vec)}`
1199        let f: Expr = constr(Sum, app(Rty, VecType));
1200        assert_eq!(f.has_constraint(0), true);
1201        // `add{(>= 0)}`
1202        let f: Expr = constr(Add, app(Rge, 0.0));
1203        assert_eq!(f.has_constraint(0), true);
1204        let f: Expr = comp(Not, Not);
1205        assert_eq!(f.has_constraint(0), false);
1206        // `(not . not){not}`
1207        let f: Expr = constr(comp(Not, Not), true);
1208        assert_eq!(f.has_constraint(0), true);
1209        // `not{not} . not`
1210        let f: Expr = comp(constr(Not, Not), Not);
1211        assert_eq!(f.has_constraint(0), true);
1212        // `not . not{not}`
1213        let f: Expr = comp(Not, constr(Not, Not));
1214        assert_eq!(f.has_constraint(0), true);
1215        let f: Expr = true.into();
1216        assert_eq!(f.has_constraint(0), false);
1217    }
1218
1219    #[test]
1220    fn eval_var() {
1221        let def = &[Def("x".into(), 0.0.into())];
1222        let f: Expr = "x".into();
1223        assert_eq!(f.eval(def).unwrap(), Ret(F64(0.0)));
1224
1225        let mut def = std();
1226        def.push(Def("x".into(), 2.0.into()));
1227        let f: Expr = app2(Add, 1.0, "x");
1228        assert_eq!(f.eval(&def).unwrap(), Ret(F64(3.0)));
1229
1230        let mut def = std();
1231        def.push(Def("x".into(), 0.0.into()));
1232        let f: Expr = app("sin", "x");
1233        assert_eq!(f.eval(&def).unwrap(), Ret(F64(0.0)));
1234    }
1235}