(** Zip the two pureCRs together, to construct a longer PureCR. NOTE: This assumes that cr1 and cr2 have the same length NOTE: If they do not, we can always ammend a CR with {0, +, 0} **)
Fixpoint zip_purecrs_eq_len
{bop: R -> R -> R}
(cr1 cr2: PureCR bop):
option (PureCR bop) :=
match (cr1, cr2) with
(** recurrence *)
| (PureCRRec r1 cr'1, PureCRRec r2 cr'2) =>
option_map (PureCRRec (bop r1 r2)) (zip_purecrs_eq_len cr'1 cr'2)
(** Base case when cr1 and cr2 have the same length *)
| (PureBR r11 r12, PureBR r21 r22) =>
Some (PureBR bop (bop r11 r21) (bop r12 r22))
| _ => None
end.
(* Define pure-sum and pure-product CRs *)
Notation PureSumCR := (PureCR plus).
Notation PureProdCR := (PureCR mult).

(** Lemma 22 *)
Lemma rewrite_pure_mul_cr_on_mul_cr: forall
`{Ring R}
(cr1 cr2: PureProdCR)
(pureout: PureProdCR)
(ZIP: zip_purecrs_eq_len cr1 cr2 = Some pureout)
(n: nat),
(cr1 # n) * (cr2 # n) = pureout # n.