Library functional_algebra.monoid_expr
This module defines concrete expressions that can be used to
represent monoid values and operations, and includes a collection
of functions that can be used to manipulate these expressions,
and a set of theorems describing these functions.
Copyright (C) 2018 Larry D. Lee Jr. <llee454@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this program. If not, see
<https://www.gnu.org/licenses/>.
Require Import Description.
Require Import base.
Require Import function.
Require Import ProofIrrelevance.
Require Import Bool.
Require Import List.
Require Import monoid.
Import Monoid.
Module MonoidExpr.
Open Scope monoid_scope.
Section Definitions.
Represents the values stored in binary trees.
Represents binary trees.
Binary trees can be used to represent
many different types of algebraic
expressions. Importantly, when flattened,
they are isomorphic with lists. Flattening,
projecting onto lists, sorting, and folding
may be used normalize ("simplify") algebraic
expressions.
Accepts a binary tree and returns true iff
the tree is a node term.
Definition BTree_is_node
: BTree -> bool
:= BTree_rec
(fun _ => bool)
(fun _ => false)
(fun _ _ _ _ => true).
: BTree -> bool
:= BTree_rec
(fun _ => bool)
(fun _ => false)
(fun _ _ _ _ => true).
Accepts a binary tree and returns true iff
the tree is a leaf term.
Definition BTree_is_leaf
: BTree -> bool
:= BTree_rec
(fun _ => bool)
(fun _ => true)
(fun _ _ _ _ => false).
: BTree -> bool
:= BTree_rec
(fun _ => bool)
(fun _ => true)
(fun _ _ _ _ => false).
Accepts a binary tree and returns true
iff the tree is right associative.
Note: right associative trees are isomorphic
to lists.
Definition BTree_is_rassoc
: BTree -> bool
:= BTree_rec
(fun _ => bool)
(fun _ => true)
(fun t _ _ f
=> BTree_is_leaf t && f).
: BTree -> bool
:= BTree_rec
(fun _ => bool)
(fun _ => true)
(fun t _ _ f
=> BTree_is_leaf t && f).
Proves that the right subtree in a right
associative binary tree is also right
associative.
Definition BTree_rassoc_thm
: forall t u : BTree, BTree_is_rassoc (node t u) = true -> BTree_is_rassoc u = true
:= fun t u H
=> proj2 (
andb_prop
(BTree_is_leaf t)
(BTree_is_rassoc u)
H).
End Definitions.
Arguments leaf {Term} x.
Arguments node {Term} t u.
Arguments BTree_is_leaf {Term} t.
Arguments BTree_is_node {Term} t.
Arguments BTree_is_rassoc {Term} t.
Arguments BTree_rassoc_thm {Term} t u H.
: forall t u : BTree, BTree_is_rassoc (node t u) = true -> BTree_is_rassoc u = true
:= fun t u H
=> proj2 (
andb_prop
(BTree_is_leaf t)
(BTree_is_rassoc u)
H).
End Definitions.
Arguments leaf {Term} x.
Arguments node {Term} t u.
Arguments BTree_is_leaf {Term} t.
Arguments BTree_is_node {Term} t.
Arguments BTree_is_rassoc {Term} t.
Arguments BTree_rassoc_thm {Term} t u H.
Represents a mapping from abstract terms
to monoid set elements.
Represents the monoid set that terms will be
projected onto.
Represents the set of terms that will be
used to represent monoid values.
Accepts a term and returns its projection
in E.
Accepts a term and returns true iff the term
represents the monoid identity element (0).
Accepts a term and proves that zero terms
evaluate to 0.
term_map_is_zero_thm : forall t, term_map_is_zero t = true -> term_map_eval t = 0
}.
Arguments term_map_eval {t} x.
Arguments term_map_is_zero {t} x.
Arguments term_map_is_zero_thm {t} t0 H.
Section Functions.
}.
Arguments term_map_eval {t} x.
Arguments term_map_is_zero {t} x.
Arguments term_map_is_zero_thm {t} t0 H.
Section Functions.
Represents an arbitrary homomorphism mapping
binary trees onto some set.
Represents the set of monoid values.
Represents the set of terms.
Accepts a term and returns true iff it is not
a zero constant term.
Maps binary trees onto monoid expressions.
Definition BTree_eval
: BTree Term -> E
:= BTree_rec Term
(fun _ => E)
(fun t => term_map_eval t)
(fun _ f _ g => f + g).
: BTree Term -> E
:= BTree_rec Term
(fun _ => E)
(fun t => term_map_eval t)
(fun _ f _ g => f + g).
Accepts two monoid expressions and returns
true iff they are denotationally equivalent -
I.E. represent the same monoid value.
Accepts two binary trees, t and u, where u is
right associative, prepends t onto u in a way
that produces a flat list.
* *
/ \ / \
* v => (t) *
/ \ / \
t u (u) v
Definition BTree_shift
: forall (t u : BTree Term), BTree_is_rassoc u = true -> { v : BTree Term | BTree_is_rassoc v = true /\ BTree_eq (node t u) v }
:= let P t u v
:= BTree_is_rassoc v = true /\ BTree_eq (node t u) v in
let T t u
:= BTree_is_rassoc u = true -> { v | P t u v } in
BTree_rec Term
(fun t => forall u, T t u)
(fun x u H
=> let v := node (leaf x) u in
exist
(P (leaf x) u)
v
(conj
(andb_true_intro
(conj
(eq_refl true : BTree_is_leaf (leaf x) = true)
H))
(eq_refl (BTree_eval v))))
(fun t f u g v H
=> let (w, H0) := g v H in
let (x, H1) := f w (proj1 H0) in
exist
(P (node t u) v)
x
(conj
(proj1 H1)
(proj2 H1
|| BTree_eval t + a = BTree_eval x @a by proj2 H0
|| a = BTree_eval x @a by <- op_is_assoc (BTree_eval t) (BTree_eval u) (BTree_eval v)))).
: forall (t u : BTree Term), BTree_is_rassoc u = true -> { v : BTree Term | BTree_is_rassoc v = true /\ BTree_eq (node t u) v }
:= let P t u v
:= BTree_is_rassoc v = true /\ BTree_eq (node t u) v in
let T t u
:= BTree_is_rassoc u = true -> { v | P t u v } in
BTree_rec Term
(fun t => forall u, T t u)
(fun x u H
=> let v := node (leaf x) u in
exist
(P (leaf x) u)
v
(conj
(andb_true_intro
(conj
(eq_refl true : BTree_is_leaf (leaf x) = true)
H))
(eq_refl (BTree_eval v))))
(fun t f u g v H
=> let (w, H0) := g v H in
let (x, H1) := f w (proj1 H0) in
exist
(P (node t u) v)
x
(conj
(proj1 H1)
(proj2 H1
|| BTree_eval t + a = BTree_eval x @a by proj2 H0
|| a = BTree_eval x @a by <- op_is_assoc (BTree_eval t) (BTree_eval u) (BTree_eval v)))).
Accepts a binary tree and returns an equivalent
tree that is right associative.
Definition BTree_rassoc
: forall t : BTree Term, { u : BTree Term | BTree_is_rassoc u = true /\ BTree_eq t u }
:= let P t u
:= BTree_is_rassoc u = true /\ BTree_eq t u in
let T t
:= { u | P t u } in
BTree_rec Term
(fun t => T t)
(fun x
=> let t := leaf x in
exist
(P t)
t
(conj
(eq_refl true : BTree_is_leaf t = true)
(eq_refl (BTree_eval t))))
(fun t _ u g
=> let (v, H) := g in
let (w, H0) := BTree_shift t v (proj1 H) in
exist
(P (node t u))
w
(conj
(proj1 H0)
(proj2 H0
|| BTree_eval t + a = BTree_eval w @a by (proj2 H)))).
: forall t : BTree Term, { u : BTree Term | BTree_is_rassoc u = true /\ BTree_eq t u }
:= let P t u
:= BTree_is_rassoc u = true /\ BTree_eq t u in
let T t
:= { u | P t u } in
BTree_rec Term
(fun t => T t)
(fun x
=> let t := leaf x in
exist
(P t)
t
(conj
(eq_refl true : BTree_is_leaf t = true)
(eq_refl (BTree_eval t))))
(fun t _ u g
=> let (v, H) := g in
let (w, H0) := BTree_shift t v (proj1 H) in
exist
(P (node t u))
w
(conj
(proj1 H0)
(proj2 H0
|| BTree_eval t + a = BTree_eval w @a by (proj2 H)))).
In the following section, we use the
isomorphism between right associative binary
trees and lists to represent monoid expressions
as lists and to use list filtering to eleminate
identity elements. This is part of a larger
effort to "simplify" momoid expressions.
Accepts a list of monoid elements and computes
their sum.
Definition list_eval
: forall xs : list Term, E
:= list_rec
(fun _ => E)
0
(fun x _ f => (term_map_eval x) + f).
: forall xs : list Term, E
:= list_rec
(fun _ => E)
0
(fun x _ f => (term_map_eval x) + f).
Accepts two term lists and asserts that they
are equivalent.
Definition list_eq : list Term -> list Term -> Prop
:= fun xs ys : list Term
=> list_eval xs = list_eval ys.
:= fun xs ys : list Term
=> list_eval xs = list_eval ys.
Accepts a right associative binary tree and
returns an equivalent list.
Definition RABTree_list
: forall t : BTree Term, BTree_is_rassoc t = true -> { xs : list Term | BTree_eval t = list_eval xs }
:= let P t xs := BTree_eval t = list_eval xs in
let T t := BTree_is_rassoc t = true -> { xs | P t xs } in
BTree_rect Term
(fun t => T t)
(fun x _
=> let xs := cons x nil in
exist
(P (leaf x))
xs
(eq_sym (op_id_r (term_map_eval x))))
(BTree_rect Term
(fun t => T t -> forall u, T u -> T (node t u))
(fun x _ u (g : T u) H
=> let H0
: BTree_is_rassoc u = true
:= BTree_rassoc_thm (leaf x) u H in
let (ys, H1) := g H0 in
let xs := cons x ys in
exist
(P (node (leaf x) u))
xs
(eq_refl ((term_map_eval x) + (BTree_eval u))
|| (term_map_eval x) + (BTree_eval u) = (term_map_eval x) + a @a by <- H1))
(fun t _ u _ _ v _ H
=> False_rec
{ xs | P (node (node t u) v) xs }
(diff_false_true H))).
: forall t : BTree Term, BTree_is_rassoc t = true -> { xs : list Term | BTree_eval t = list_eval xs }
:= let P t xs := BTree_eval t = list_eval xs in
let T t := BTree_is_rassoc t = true -> { xs | P t xs } in
BTree_rect Term
(fun t => T t)
(fun x _
=> let xs := cons x nil in
exist
(P (leaf x))
xs
(eq_sym (op_id_r (term_map_eval x))))
(BTree_rect Term
(fun t => T t -> forall u, T u -> T (node t u))
(fun x _ u (g : T u) H
=> let H0
: BTree_is_rassoc u = true
:= BTree_rassoc_thm (leaf x) u H in
let (ys, H1) := g H0 in
let xs := cons x ys in
exist
(P (node (leaf x) u))
xs
(eq_refl ((term_map_eval x) + (BTree_eval u))
|| (term_map_eval x) + (BTree_eval u) = (term_map_eval x) + a @a by <- H1))
(fun t _ u _ _ v _ H
=> False_rec
{ xs | P (node (node t u) v) xs }
(diff_false_true H))).
Accepts a list of monoid elements and filters
out the 0 (identity) elements.
Note: to define this function we must have
a way to recognize identity elements. The
original definition for monoids did not declare
0 to be a distinguished element. In part this
followed from the fact that the set of monoid
elements was not declared inductively.
While we cannot assume that models of monoids
will define their element sets inductively
(for example, note that reals are not defined
inductively), we can reasonably expect these
models to define 0 as a distinguished element.
As this is somewhat conjectural however,
we do not add this as a requirement to the
monoid specification, but instead accept the
decision procedure here.
Definition list_filter_0
: forall xs : list Term, { ys : list Term | list_eq xs ys /\ Is_true (forallb Term_is_nonzero ys) }
:= let P xs ys := list_eq xs ys /\ Is_true (forallb Term_is_nonzero ys) in
let T xs := { ys | P xs ys } in
list_rec
T
(exist
(P nil)
nil
(conj
(eq_refl E_0)
I))
(fun x
=> (sumbool_rec
(fun _ => forall xs : list Term, T xs -> T (cons x xs))
(fun (H : term_map_is_zero x = true) xs f
=> let H0
: term_map_eval x = 0
:= term_map_is_zero_thm x H in
let (ys, H1) := f in
exist
(P (cons x xs))
ys
(conj
(op_id_l (list_eval xs)
|| 0 + (list_eval xs) = a @a by <- (proj1 H1)
|| a + (list_eval xs) = list_eval ys @a by H0)
(proj2 H1)))
(fun (H : term_map_is_zero x = false) xs f
=> let (ys, H0) := f in
let zs := cons x ys in
exist
(P (cons x xs))
zs
(conj
(eq_refl (list_eval (cons x xs))
|| term_map_eval x + (list_eval xs) = term_map_eval x + a @a by <- (proj1 H0))
(Is_true_eq_left
(forallb Term_is_nonzero zs)
(andb_true_intro
(conj
(eq_refl (Term_is_nonzero x)
|| Term_is_nonzero x = negb a @a by <- H)
(Is_true_eq_true
(forallb Term_is_nonzero ys)
(proj2 H0)))))))
(bool_dec0 (term_map_is_zero x)))).
: forall xs : list Term, { ys : list Term | list_eq xs ys /\ Is_true (forallb Term_is_nonzero ys) }
:= let P xs ys := list_eq xs ys /\ Is_true (forallb Term_is_nonzero ys) in
let T xs := { ys | P xs ys } in
list_rec
T
(exist
(P nil)
nil
(conj
(eq_refl E_0)
I))
(fun x
=> (sumbool_rec
(fun _ => forall xs : list Term, T xs -> T (cons x xs))
(fun (H : term_map_is_zero x = true) xs f
=> let H0
: term_map_eval x = 0
:= term_map_is_zero_thm x H in
let (ys, H1) := f in
exist
(P (cons x xs))
ys
(conj
(op_id_l (list_eval xs)
|| 0 + (list_eval xs) = a @a by <- (proj1 H1)
|| a + (list_eval xs) = list_eval ys @a by H0)
(proj2 H1)))
(fun (H : term_map_is_zero x = false) xs f
=> let (ys, H0) := f in
let zs := cons x ys in
exist
(P (cons x xs))
zs
(conj
(eq_refl (list_eval (cons x xs))
|| term_map_eval x + (list_eval xs) = term_map_eval x + a @a by <- (proj1 H0))
(Is_true_eq_left
(forallb Term_is_nonzero zs)
(andb_true_intro
(conj
(eq_refl (Term_is_nonzero x)
|| Term_is_nonzero x = negb a @a by <- H)
(Is_true_eq_true
(forallb Term_is_nonzero ys)
(proj2 H0)))))))
(bool_dec0 (term_map_is_zero x)))).
Accepts a binary tree and returns an equivalent
terms list in which all identity elements have
been eliminated.
Definition reduce
: forall t : BTree Term, { xs : list Term | BTree_eval t = list_eval xs }
:= fun t
=> let (u, H) := BTree_rassoc t in
let (xs, H0) := RABTree_list u (proj1 H) in
let (ys, H1) := list_filter_0 xs in
exist
(fun ys => BTree_eval t = list_eval ys)
ys
((proj2 H)
|| BTree_eval t = a @a by <- H0
|| BTree_eval t = a @a by <- (proj1 H1)).
End Functions.
Section Theorems.
: forall t : BTree Term, { xs : list Term | BTree_eval t = list_eval xs }
:= fun t
=> let (u, H) := BTree_rassoc t in
let (xs, H0) := RABTree_list u (proj1 H) in
let (ys, H1) := list_filter_0 xs in
exist
(fun ys => BTree_eval t = list_eval ys)
ys
((proj2 H)
|| BTree_eval t = a @a by <- H0
|| BTree_eval t = a @a by <- (proj1 H1)).
End Functions.
Section Theorems.
Represents an arbitrary monoid.
Represents the set of monoid elements.
Represents monoid values.
Note: In the development that follows, we
will use binary trees and lists to represent
monoid expressions. We will effectively flatten
a tree and filter a list to "simplify"
a given expression.
The code that flattens
the tree representation does not need to care
whether or not the leaves in the tree represent
0 (the monoid identity element), inverses,
etc. Accordingly, distinguishing these elements
in the definition of BTree would unnecessarily
complicate the tree algorithms by adding more
recursion cases.
Instead of doing this, we
use two types to represent monoid expressions
- trees to represent "terms" (expressions
Accepts a term and returns the monoid value
that it represents.
Accepts a term and returns true iff the term
is zero.
Proves that Term_is_zero is correct.
Definition Term_is_zero_thm
: forall t, Term_is_zero t = true -> Term_eval t = 0
:= Term_ind
(fun t => Term_is_zero t = true -> Term_eval t = 0)
(fun _ => eq_refl 0)
(fun x H
=> False_ind
(Term_eval (term_const x) = 0)
(diff_false_true H)).
: forall t, Term_is_zero t = true -> Term_eval t = 0
:= Term_ind
(fun t => Term_is_zero t = true -> Term_eval t = 0)
(fun _ => eq_refl 0)
(fun x H
=> False_ind
(Term_eval (term_const x) = 0)
(diff_false_true H)).
Defines a map from Term to monoid elements.
Definition MTerm_map
: Term_map
:= term_map m Term Term_eval Term_is_zero Term_is_zero_thm.
Section Unittests.
Let map := MTerm_map.
Variables a b c d : Term.
Let BFTree_rassoc_test_0
:= proj1_sig (BTree_rassoc map (node (node (leaf a) (leaf b)) (leaf c))) =:=
node (leaf a) (node (leaf b) (leaf c)).
Let BTree_rassoc_test_1
:= proj1_sig (BTree_rassoc map (node (leaf a) (node (leaf b) (node (leaf c) (leaf d))))) =:=
node (leaf a) (node (leaf b) (node (leaf c) (leaf d))).
Let BTree_rassoc_test_2
:= proj1_sig (BTree_rassoc map (node (node (leaf a) (leaf b)) (node (leaf c) (leaf d)))) =:=
node (leaf a) (node (leaf b) (node (leaf c) (leaf d))).
End Unittests.
End Theorems.
Arguments term_0 {m}.
Arguments term_const {m} x.
End MonoidExpr.
Notation "X # Y" := (MonoidExpr.node X Y) (at level 60).
Notation "X {{+}} Y" := (MonoidExpr.node X Y) (at level 60).
Notation "{{ 0 }}" := (MonoidExpr.leaf (MonoidExpr.term_0)).
Notation "{{ X }}" := (MonoidExpr.leaf (MonoidExpr.term_const X)).
: Term_map
:= term_map m Term Term_eval Term_is_zero Term_is_zero_thm.
Section Unittests.
Let map := MTerm_map.
Variables a b c d : Term.
Let BFTree_rassoc_test_0
:= proj1_sig (BTree_rassoc map (node (node (leaf a) (leaf b)) (leaf c))) =:=
node (leaf a) (node (leaf b) (leaf c)).
Let BTree_rassoc_test_1
:= proj1_sig (BTree_rassoc map (node (leaf a) (node (leaf b) (node (leaf c) (leaf d))))) =:=
node (leaf a) (node (leaf b) (node (leaf c) (leaf d))).
Let BTree_rassoc_test_2
:= proj1_sig (BTree_rassoc map (node (node (leaf a) (leaf b)) (node (leaf c) (leaf d)))) =:=
node (leaf a) (node (leaf b) (node (leaf c) (leaf d))).
End Unittests.
End Theorems.
Arguments term_0 {m}.
Arguments term_const {m} x.
End MonoidExpr.
Notation "X # Y" := (MonoidExpr.node X Y) (at level 60).
Notation "X {{+}} Y" := (MonoidExpr.node X Y) (at level 60).
Notation "{{ 0 }}" := (MonoidExpr.leaf (MonoidExpr.term_0)).
Notation "{{ X }}" := (MonoidExpr.leaf (MonoidExpr.term_const X)).
Defines a notation that can be used to prove
that two monoid expressions are equal using
prrof by reflection.
We represent both expressions as binary trees
and reduce both trees to the same canonical
form demonstrating that their associated monoid
expressions are equivalent.
Notation "'reflect' A 'as' B ==> C 'as' D 'using' E"
:= (let x := A in
let y := C in
let t := B in
let u := D in
let r := MonoidExpr.reduce E t in
let s := MonoidExpr.reduce E u in
let v := proj1_sig r in
let w := proj1_sig s in
let H
: MonoidExpr.list_eval E v = MonoidExpr.list_eval E w
:= eq_refl (MonoidExpr.list_eval E v) : MonoidExpr.list_eval E v = MonoidExpr.list_eval E w in
let H0
: MonoidExpr.BTree_eval E t = MonoidExpr.list_eval E v
:= proj2_sig r in
let H1
: MonoidExpr.BTree_eval E u = MonoidExpr.list_eval E w
:= proj2_sig s in
let H2
: MonoidExpr.BTree_eval E t = x
:= eq_refl (MonoidExpr.BTree_eval E t) : MonoidExpr.BTree_eval E t = x in
let H3
: MonoidExpr.BTree_eval E u = y
:= eq_refl (MonoidExpr.BTree_eval E u) : MonoidExpr.BTree_eval E u = y in
H
|| a = MonoidExpr.list_eval E w @a by H0
|| a = MonoidExpr.list_eval E w @a by H2
|| x = a @a by H1
|| x = a @a by H3)
(at level 40, left associativity).
Section Unittests.
Variable m : Monoid.
Variables a b c d : E m.
Let map := MonoidExpr.MTerm_map m.
Let reflect_test_0
: (a + 0) = (0 + a)
:= reflect
(a + 0)
as ({{a}} # {{0}})
==>
(0 + a)
as ({{0}} # {{a}})
using map.
Let reflect_test_1
: (a + 0) + (0 + b) = a + b
:= reflect
((a + 0) + (0 + b))
as (({{a}} # {{0}}) # ({{0}} # {{b}}))
==>
(a + b)
as ({{a}} # {{b}})
using map.
Let reflect_test_2
: (0 + a) + b = (a + b)
:= reflect
((0 + a) + b) as (({{0}} # {{a}}) # {{b}})
==>
(a + b) as ({{a}} # {{b}})
using map.
Let reflect_test_3
: (a + b) + (c + d) = a + ((b + c) + d)
:= reflect
(a + b) + (c + d)
as (({{a}} # {{b}}) # ({{c}} # {{d}}))
==>
a + ((b + c) + d)
as ({{a}} # (({{b}} # {{c}}) # {{d}}))
using map.
Let reflect_test_4
: (a + b) + (0 + c) = (a + 0) + (b + c)
:= reflect
(a + b) + (0 + c)
as (({{a}} # {{b}}) # ({{0}} # {{c}}))
==>
(a + 0) + (b + c)
as (({{a}} # {{0}}) # ({{b}} # {{c}}))
using map.
Let reflect_test_5
: (((a + b) + c) + 0) = (((0 + a) + b) + c)
:= reflect
(((a + b) + c) + 0)
as ((({{a}} # {{b}}) # {{c}}) # {{0}})
==>
(((0 + a) + b) + c)
as ((({{0}} # {{a}}) # {{b}}) # {{c}})
using map.
End Unittests.
:= (let x := A in
let y := C in
let t := B in
let u := D in
let r := MonoidExpr.reduce E t in
let s := MonoidExpr.reduce E u in
let v := proj1_sig r in
let w := proj1_sig s in
let H
: MonoidExpr.list_eval E v = MonoidExpr.list_eval E w
:= eq_refl (MonoidExpr.list_eval E v) : MonoidExpr.list_eval E v = MonoidExpr.list_eval E w in
let H0
: MonoidExpr.BTree_eval E t = MonoidExpr.list_eval E v
:= proj2_sig r in
let H1
: MonoidExpr.BTree_eval E u = MonoidExpr.list_eval E w
:= proj2_sig s in
let H2
: MonoidExpr.BTree_eval E t = x
:= eq_refl (MonoidExpr.BTree_eval E t) : MonoidExpr.BTree_eval E t = x in
let H3
: MonoidExpr.BTree_eval E u = y
:= eq_refl (MonoidExpr.BTree_eval E u) : MonoidExpr.BTree_eval E u = y in
H
|| a = MonoidExpr.list_eval E w @a by H0
|| a = MonoidExpr.list_eval E w @a by H2
|| x = a @a by H1
|| x = a @a by H3)
(at level 40, left associativity).
Section Unittests.
Variable m : Monoid.
Variables a b c d : E m.
Let map := MonoidExpr.MTerm_map m.
Let reflect_test_0
: (a + 0) = (0 + a)
:= reflect
(a + 0)
as ({{a}} # {{0}})
==>
(0 + a)
as ({{0}} # {{a}})
using map.
Let reflect_test_1
: (a + 0) + (0 + b) = a + b
:= reflect
((a + 0) + (0 + b))
as (({{a}} # {{0}}) # ({{0}} # {{b}}))
==>
(a + b)
as ({{a}} # {{b}})
using map.
Let reflect_test_2
: (0 + a) + b = (a + b)
:= reflect
((0 + a) + b) as (({{0}} # {{a}}) # {{b}})
==>
(a + b) as ({{a}} # {{b}})
using map.
Let reflect_test_3
: (a + b) + (c + d) = a + ((b + c) + d)
:= reflect
(a + b) + (c + d)
as (({{a}} # {{b}}) # ({{c}} # {{d}}))
==>
a + ((b + c) + d)
as ({{a}} # (({{b}} # {{c}}) # {{d}}))
using map.
Let reflect_test_4
: (a + b) + (0 + c) = (a + 0) + (b + c)
:= reflect
(a + b) + (0 + c)
as (({{a}} # {{b}}) # ({{0}} # {{c}}))
==>
(a + 0) + (b + c)
as (({{a}} # {{0}}) # ({{b}} # {{c}}))
using map.
Let reflect_test_5
: (((a + b) + c) + 0) = (((0 + a) + b) + c)
:= reflect
(((a + b) + c) + 0)
as ((({{a}} # {{b}}) # {{c}}) # {{0}})
==>
(((0 + a) + b) + c)
as ((({{0}} # {{a}}) # {{b}}) # {{c}})
using map.
End Unittests.