\import Algebra.Meta
\import Logic.Rewriting.ARS.Relation
\import Data.List (!!, ++, ++_nil, ++-assoc, List, nil, ::)
\import Data.Fin
\import Data.Maybe
\import Data.Shifts
\import Data.SubList
\import Data.Or
\import Function.Meta
\import Logic
\import Logic.Meta
\import Paths
\import Paths.Meta
\import Set
\import Logic.Rewriting.TRS.HRS
\import Logic.Rewriting.TRS.Linearity
\import Logic.Rewriting.TRS.MetaContexts
\import Logic.Rewriting.TRS.Substitutions
\import Logic.Rewriting.TRS.Union
\import Logic.Rewriting.TRS.Union.Colors
\import Logic.Rewriting.TRS.Union.TopLevel
\open TheoremContext

\data TopLevelColoredReduction {tc : TheoremContext}
                               (color : Color)
                               {mc : MetaContext Sort}
                               {context : List Sort}
                               {s : Sort}
                               (A B : Term env context s mc) \elim A, B
  | A, B =>
  rewrite-with-rule-colored
    (HasColoredRoot color A)
    (idx : rule-J {rules color} s)
    (substitution : MetaSubstitution env context (rule-linear-mc idx) mc)
    (left-coherence : MetaSubstitution.apply (weakening (convert-to-injected-term color (get-rule-pattern idx)) SubList.sublist-nil-free) SubList.identity substitution = A)
    (right-coherence : MetaSubstitution.apply (weakening (inject-term envs (rule-right-linear idx)) SubList.sublist-nil-free) SubList.identity substitution = B)
  | func f-A arguments-A, func f-B arguments-B =>
  rewrite-with-parameter-f-colored
    (p : f-A = f-B)
    (f-A.1 = color)
    (i : Index (domain f-A))
    (tlcr : TopLevelColoredReduction color (arguments-A i) (arguments-over-f p arguments-B i))
    (eq : \Pi (j : Index (domain f-A)) (j = i -> Empty) -> arguments-A j = arguments-over-f p arguments-B j)
  \where {
    \lemma extract-root-coloring {tc : TheoremContext} {color : Color} {mc : MetaContext Sort'} {context : List Sort} {s : Sort} {A B : Term env context s mc} (tlcr : TopLevelColoredReduction color A B) : HasColoredRoot color A
    \elim A, B, tlcr
      | A, B, rewrite-with-rule-colored h _ _ _ _ => h
      | func f-A arguments-A, func f-B arguments-B, rewrite-with-parameter-f-colored p p1 i tlcr eq => func-root p1
  }

\data OppositeColored {tc : TheoremContext} (maybe : Maybe Color) (negated : Color) : \Prop \elim maybe
  | nothing => colored-nothing
  | just color => colored-opposite (color /= negated)

\data BorderedParallelReduction
  {tc : TheoremContext}
  (global-color : Color)
  (color : Maybe Color)
  {context : List Sort'} {s : Sort'} {mc : MetaContext Sort'}
  (A B : Term env context s mc) \elim A
  | A => equal-trees (A = B)
  | func f arguments =>
  parallelization-f
    (mediator : \Pi (index : Index (domain f)) ->
        Term env (context ++ f env.!!domain index) (f env.!!sort index) mc)
    (\Pi (i : env.index-in f) -> \Sigma
      (someColor : Maybe Color)
      (OppositeColored someColor f.1)
      (BorderedParallelReduction global-color someColor (arguments i) (mediator i)))
    (SwitchingReduction global-color color (func f mediator) B)
  \where {
    \func append-tlcr
      {tc : TheoremContext}
      {global-color : Color}
      {color : Maybe Color}
      {context : List Sort'} {s : Sort'} {mc : MetaContext Sort'}
      (A B : Term env context s mc)
      (bpr : BorderedParallelReduction global-color color A B)
      (C : Term env context s mc)
      (B~>*C : Closure (TopLevelColoredReduction global-color) B C)
      : \Sigma (someColor : Maybe Color) (BorderedParallelReduction global-color someColor A C) \elim color, A, bpr
      | color, A, equal-trees idp => \case Closure.extract B~>*C \with {
        | inl eq => rewrite eq (nothing, equal-trees idp)
        | inr (inter, rd) => \case \elim B, \elim B~>*C, TopLevelColoredReduction.extract-root-coloring rd \with {
          | func _ arguments, B~>*C, func-root _ => (just global-color, parallelization-f arguments (\lam i => (nothing, colored-nothing, equal-trees idp)) (cr-rewrite B~>*C idp))
        }
      }
      | nothing, func f arguments, parallelization-f mediator _x (cr-skip idp) => (just global-color, parallelization-f mediator _x (cr-rewrite B~>*C idp))
      | just a, func f arguments, parallelization-f mediator _x (cr-rewrite t p) => (just global-color, parallelization-f mediator _x (cr-rewrite (Closure.compose (rewrite p t) B~>*C) idp))
  }

\data SwitchingReduction
  {tc : TheoremContext}
  {context : List Sort'}
  {s : Sort'}
  {mc : MetaContext Sort'}
  (global-color : Color)
  (color : Maybe Color) (A B : Term env context s mc) \elim color
  | nothing => cr-skip (A = B)
  | just color => cr-rewrite (Closure (TopLevelColoredReduction color) A B) (global-color = color)

\func TrichromaticParallelReduction
  {tc : TheoremContext} {mc : MetaContext Sort'} {context : List Sort'} {s : Sort'}
  (A B : Term env context s mc) : \Type =>
  \Sigma (global-color : Color) (color : Maybe Color) (BorderedParallelReduction global-color color A B)

\func ConfluentialSystem (env : FSignature) (rules : RuleRegistry env) : \Type =>
  \Pi {mc : MetaContext Sort} {context : List Sort} {s : Sort}
      (A B C : Term env context s mc)
      (Closure (RewriteRelation rules) A B)
      (Closure (RewriteRelation rules) A C) -> StraightJoin B C (Closure (\lam x y => \Sigma (rd : RewriteRelation rules x y) (FunctionalWitness rd)))

\data FunctionalWitness {env : FSignature} {rules : RuleRegistry env} {context : List Sort} {s : Sort} {mc : MetaContext Sort} {t u : Term env context s mc} (rd : RewriteRelation rules t u) \elim t, u, rd
  | A, B, rewrite-with-rule _ _ _ _ => rule-rewriting
  | func f-A arguments-A, func f-B arguments-B, rewrite-with-parameter-f _ _ rd _ => param-rewriting (FunctionalWitness rd)

-- | Main function for joining two BorderedParallelReductions. Performs high-level dissection of incoming types.
\func bpr-confluence
  {tc : TheoremContext} {gc1 gc2 : Color} (color1 color2 : Maybe Color) {context : List Sort'} {s : Sort'}
  {A B C : PureTerm env context s}
  (A~>B : BorderedParallelReduction gc1 color1 A B)
  (A~>C : BorderedParallelReduction gc2 color2 A C)
  (confluence : \Pi (c : Color) -> ConfluentialSystem (envs c) (rules c))
  : \Sigma (D : PureTerm env context s)
           (color3 : Maybe Color)
           (color4 : Maybe Color)
           (BorderedParallelReduction gc2 color3 B D)
           (BorderedParallelReduction gc1 color4 C D) \elim color1, color2, A, B, C, A~>B, A~>C
  | color1, color2, A, B, C, equal-trees p, rd => (C, color2, color1, rewriteI p rd, equal-trees idp)
  | color1, color2, A, B, C, rd, equal-trees p => (B, color2, color1, equal-trees idp, rewriteI p rd)
  | nothing, nothing, func f arguments, B, C, parallelization-f mediator arguments->med (cr-skip famed=B), parallelization-f mediator' arguments->med' (cr-skip famed'=C)
  =>
    \let | inner-confluences i => bpr-confluence (arguments->med i).1 (arguments->med' i).1 (arguments->med i).3 (arguments->med' i).3 confluence
         | D => func f (\lam i => (inner-confluences i).1)
         | (color-1, mediator-1, inrd-1, cwr-1) => collect-reductions-together-raw f mediator (\lam i => (inner-confluences i).1) (\lam i => ((inner-confluences i).2, (inner-confluences i).4))
         | (color-2, mediator-2, inrd-2, cwr-2) => collect-reductions-together-raw f mediator' (\lam i => (inner-confluences i).1) (\lam i => ((inner-confluences i).3, (inner-confluences i).5))
    \in (func f (\lam i => (inner-confluences i).1),
         color-1,
         color-2,
         rewriteI famed=B (parallelization-f mediator-1 inrd-1 cwr-1),
         rewriteI famed'=C (parallelization-f mediator-2 inrd-2 cwr-2))
  | nothing, just right-color, func f arguments, B, C, parallelization-f mediator arguments=>med (cr-skip p), parallelization-f mediator' arguments=>med' (cr-rewrite med'~>C gc2=right-color) =>
    \let | joined-mediators i => bpr-confluence (arguments=>med i).1 (arguments=>med' i).1 (arguments=>med i).3 (arguments=>med' i).3 confluence
         | first-level-reduct => func f (\lam i => (joined-mediators i).1)
         | (color-1, mediator-1, inrd-1, cwr-1) => collect-reductions-together-raw f mediator (\lam i => (joined-mediators i).1) (\lam i => ((joined-mediators i).2, (joined-mediators i).4))
         | (color-2, mediator-2, inrd-2, cwr-2) => collect-reductions-together-raw f mediator' (\lam i => (joined-mediators i).1) (\lam i => ((joined-mediators i).3, (joined-mediators i).5))
         | rd : BorderedParallelReduction gc2 color-1 (func f mediator) (func f (\lam i => (joined-mediators i).1)) => parallelization-f mediator-1 inrd-1 cwr-1
         | (rightmost-reduct, flr~>rr, mcl, C=>rr) => unify-top right-color gc1 f mediator' mediator-2 C med'~>C inrd-2
         | (X, c1, B=>X, c2, C=>X) => unwrap-cwr (func f mediator) C (func f mediator-2) first-level-reduct rightmost-reduct cwr-2 (rewrite gc2=right-color flr~>rr) rd C=>rr confluence
    \in (X,
         c1,
         c2,
         rewriteI p B=>X,
         C=>X)
  | just left-color, nothing, func f arguments, B, C, parallelization-f mediator arguments=>med (cr-rewrite med~>B gc1=left-color), parallelization-f mediator' arguments=>med' (cr-skip p) =>
    \let | joined-mediators i => bpr-confluence (arguments=>med i).1 (arguments=>med' i).1 (arguments=>med i).3 (arguments=>med' i).3 confluence
         | first-level-reduct => func f (\lam i => (joined-mediators i).1)
         | (color-1, mediator-1, inrd-1, cwr-1) => collect-reductions-together-raw f mediator (\lam i => (joined-mediators i).1) (\lam i => ((joined-mediators i).2, (joined-mediators i).4))
         | (color-2, mediator-2, inrd-2, cwr-2) => collect-reductions-together-raw f mediator' (\lam i => (joined-mediators i).1) (\lam i => ((joined-mediators i).3, (joined-mediators i).5))
         | (leftmost-reduct, flr~>lr, mcl, B=>lr) => unify-top left-color gc2 f mediator mediator-1 B med~>B inrd-1
         | rd : BorderedParallelReduction gc1 color-2 (func f mediator') (func f (\lam i => (joined-mediators i).1)) => parallelization-f mediator-2 inrd-2 cwr-2
         | (X, c1, C=>X, c2, B=>X) => unwrap-cwr (func f mediator') B (func f mediator-1) first-level-reduct leftmost-reduct cwr-1 (rewrite gc1=left-color flr~>lr) rd B=>lr confluence
    \in (X,
         c2,
         c1,
         B=>X,
         rewriteI p C=>X)
  | just left-color, just right-color, func f arguments, B, C, parallelization-f mediator arguments=>med (cr-rewrite med~>B gc1=left-color), parallelization-f mediator' arguments=>med' (cr-rewrite med'~>C gc2=right-color)
  => \case Closure.extract med~>B, Closure.extract med'~>C \with {
      | inl a, _ => rewriteI a (
        \let | joined-mediators i => bpr-confluence (arguments=>med i).1 (arguments=>med' i).1 (arguments=>med i).3 (arguments=>med' i).3 confluence
             | first-level-reduct => func f (\lam i => (joined-mediators i).1)
             | (color-1, mediator-1, inrd-1, cwr-1) => collect-reductions-together-raw f mediator (\lam i => (joined-mediators i).1) (\lam i => ((joined-mediators i).2, (joined-mediators i).4))
             | (color-2, mediator-2, inrd-2, cwr-2) => collect-reductions-together-raw f mediator' (\lam i => (joined-mediators i).1) (\lam i => ((joined-mediators i).3, (joined-mediators i).5))
             | rd : BorderedParallelReduction gc2 color-1 (func f mediator) (func f (\lam i => (joined-mediators i).1)) => parallelization-f mediator-1 inrd-1 cwr-1
             | (rightmost-reduct, flr~>rr, mcl, C=>rr) => unify-top right-color gc1 f mediator' mediator-2 C med'~>C inrd-2
             | (X, c1, B=>X, c2, C=>X) => unwrap-cwr (func f mediator) C (func f mediator-2) first-level-reduct rightmost-reduct cwr-2 (rewrite gc2=right-color flr~>rr) rd C=>rr confluence
        \in (X,
             c1,
             c2,
             B=>X,
             C=>X))
      | _, inl a => rewriteI a (
        \let | joined-mediators i => bpr-confluence (arguments=>med i).1 (arguments=>med' i).1 (arguments=>med i).3 (arguments=>med' i).3 confluence
             | first-level-reduct => func f (\lam i => (joined-mediators i).1)
             | (color-1, mediator-1, inrd-1, cwr-1) => collect-reductions-together-raw f mediator (\lam i => (joined-mediators i).1) (\lam i => ((joined-mediators i).2, (joined-mediators i).4))
             | (color-2, mediator-2, inrd-2, cwr-2) => collect-reductions-together-raw f mediator' (\lam i => (joined-mediators i).1) (\lam i => ((joined-mediators i).3, (joined-mediators i).5))
             | (leftmost-reduct, flr~>lr, mcl, B=>lr) => unify-top left-color gc2 f mediator mediator-1 B med~>B inrd-1
             | rd : BorderedParallelReduction gc1 color-2 (func f mediator') (func f (\lam i => (joined-mediators i).1)) => parallelization-f mediator-2 inrd-2 cwr-2
             | (X, c1, C=>X, c2, B=>X) => unwrap-cwr (func f mediator') B (func f mediator-1) first-level-reduct leftmost-reduct cwr-1 (rewrite gc1=left-color flr~>lr) rd B=>lr confluence
        \in (X,
             c2,
             c1,
             B=>X,
             C=>X))
      | inr (_, rd ), inr (_, rd') =>
        \let
          | hcl-f-left : HasColoredRoot left-color (func f mediator) => TopLevelColoredReduction.extract-root-coloring rd
          | hcl-f-right : HasColoredRoot right-color (func f mediator') => TopLevelColoredReduction.extract-root-coloring rd'
          | lcolor=rcolor : left-color = right-color => HasColoredRoot.equalize-colors left-color right-color f mediator mediator' hcl-f-left hcl-f-right
          | joined-mediators i => bpr-confluence (arguments=>med i).1 (arguments=>med' i).1 (arguments=>med i).3 (arguments=>med' i).3 confluence
          | first-level-reduct => func f (\lam i => (joined-mediators i).1)
          | (color-1, mediator-1, inrd-1, cwr-1) => collect-reductions-together-raw f mediator (\lam i => (joined-mediators i).1) (\lam i => ((joined-mediators i).2, (joined-mediators i).4))
          | (color-2, mediator-2, inrd-2, cwr-2) => collect-reductions-together-raw f mediator' (\lam i => (joined-mediators i).1) (\lam i => ((joined-mediators i).3, (joined-mediators i).5))
          | rd : BorderedParallelReduction gc2 color-1 (func f mediator) (func f (\lam i => (joined-mediators i).1)) => parallelization-f mediator-1 inrd-1 cwr-1
          | rd' : BorderedParallelReduction gc1 color-2 (func f mediator') (func f (\lam i => (joined-mediators i).1)) => parallelization-f mediator-2 inrd-2 cwr-2
          | (leftmost-reduct, flr~>lr, clr-b, B=>lr) => unify-top left-color left-color f mediator mediator-1 B med~>B (rewrite (lcolor=rcolor *> inv gc2=right-color) inrd-1)
          | (rightmost-reduct, flr~>rr, clr-c, C=>rr) => unify-top right-color right-color f mediator' mediator-2 C med'~>C (rewrite (inv lcolor=rcolor *> inv gc1=left-color) inrd-2)
          | (X, c1, B=>X, c2, C=>X) => unwrap-double-cwr B C (func f mediator-1) (func f mediator-2) first-level-reduct leftmost-reduct rightmost-reduct (rewrite (inv gc2=right-color) cwr-1) (rewrite (inv lcolor=rcolor *> inv gc1=left-color) cwr-2) (rewriteI lcolor=rcolor flr~>lr) flr~>rr (rewriteI lcolor=rcolor B=>lr) C=>rr confluence
        \in (X, c1, c2, rewrite gc2=right-color B=>X, rewrite (gc1=left-color *> lcolor=rcolor) C=>X)
    }
  \where {
    \func unwrap-cwr
      {tc : TheoremContext} {gc1 gc2 : Color} {color3 color4 : Maybe Color} {context : List Sort'} {s : Sort'}
      (T1 T2 A B C : PureTerm env context s) {color-2 : Maybe Color}
      (cwr : SwitchingReduction gc1 color-2 A B)
      (A~>*C : Closure (TopLevelColoredReduction gc2) A C)
      (T1=>B : BorderedParallelReduction gc2 color3 T1 B)
      (T2=>C : BorderedParallelReduction gc1 color4 T2 C)
      (confluence : \Pi (c : Color) -> ConfluentialSystem (envs c) (rules c))
      :
      \Sigma (X : PureTerm env context s) (c1 : Maybe Color) (BorderedParallelReduction gc2 c1 T1 X) (c2 : Maybe Color) (BorderedParallelReduction gc1 c2 T2 X)
    \elim color-2, cwr
      | nothing, cr-skip p => \let (cl-1, t1=>X) => BorderedParallelReduction.append-tlcr T1 B T1=>B C (rewriteI p A~>*C) \in (C, cl-1, t1=>X, color4, T2=>C)
      | just color, cr-rewrite A~>*B p =>
        \let | (X, B~>*X, C~>*X) => join-multicolor-tlcrs color gc2 A~>*B A~>*C confluence
             | (cl-1, t1=>X) => BorderedParallelReduction.append-tlcr T1 B T1=>B X B~>*X
             | (cl-2, t2=>X) => BorderedParallelReduction.append-tlcr T2 C T2=>C X (rewrite p C~>*X)
        \in (X, cl-1, t1=>X, cl-2, t2=>X)

    \func unwrap-double-cwr
      {tc : TheoremContext} {gc1 : Color} {color3 color4 : Maybe Color} {context : List Sort'} {s : Sort'}
      (T1 T2 A A' E B C : PureTerm env context s) {color-2 color-1 : Maybe Color}
      (cwr-1 : SwitchingReduction gc1 color-2 A E)
      (cwr-2 : SwitchingReduction gc1 color-1 A' E)
      (A~>*B : Closure (TopLevelColoredReduction gc1) A B)
      (A'~>*C : Closure (TopLevelColoredReduction gc1) A' C)
      (T1=>B : BorderedParallelReduction gc1 color3 T1 B)
      (T2=>C : BorderedParallelReduction gc1 color4 T2 C)
      (confluence : \Pi (c : Color) -> ConfluentialSystem (envs c) (rules c))
      : \Sigma (X : PureTerm env context s) (c1 : Maybe Color) (BorderedParallelReduction gc1 c1 T1 X) (c2 : Maybe Color) (BorderedParallelReduction gc1 c2 T2 X)
    \elim color-2, color-1, cwr-1, cwr-2
      | nothing, nothing, cr-skip p, cr-skip p1 =>
        \let | (X, B~>*X, C~>*X) => join-multicolor-tlcrs gc1 gc1 A~>*B (rewrite {1} (p *> inv p1) A'~>*C) confluence
             | (c1, T1=>X) => BorderedParallelReduction.append-tlcr _ _ T1=>B X B~>*X
             | (c2, T2=>X) => BorderedParallelReduction.append-tlcr _ _ T2=>C X C~>*X
        \in (X, c1, T1=>X, c2, T2=>X)
      | nothing, just color, cr-skip p, cr-rewrite A'~>*E p1 =>
        \let | (X, B~>*X, C~>*X) => join-multicolor-tlcrs gc1 gc1 (Closure.compose (transport (\lam cl => Closure (TopLevelColoredReduction cl) A' E) (inv p1) A'~>*E) (rewrite {1} (inv p) A~>*B)) A'~>*C confluence
             | (c1, T1=>X) => BorderedParallelReduction.append-tlcr _ _ T1=>B X B~>*X
             | (c2, T2=>X) => BorderedParallelReduction.append-tlcr _ _ T2=>C X C~>*X
        \in (X, c1, T1=>X, c2, T2=>X)
      | just color, nothing, cr-rewrite A~>*E p, cr-skip p1 =>
        \let | (X, B~>*X, C~>*X) => join-multicolor-tlcrs gc1 gc1 A~>*B (Closure.compose (transport (\lam cl => Closure (TopLevelColoredReduction cl) A E) (inv p) A~>*E) (rewrite {1} (inv p1) A'~>*C)) confluence
             | (c1, T1=>X) => BorderedParallelReduction.append-tlcr _ _ T1=>B X B~>*X
             | (c2, T2=>X) => BorderedParallelReduction.append-tlcr _ _ T2=>C X C~>*X
        \in (X, c1, T1=>X, c2, T2=>X)
      | just color, just color1, cr-rewrite A~>*E p, cr-rewrite A'~>*E p1 =>
        \let | (M1, B~>*M1, E~>*M1) => join-multicolor-tlcrs gc1 gc1 A~>*B (rewrite p A~>*E) confluence
             | (M2, E~>*M2, C~>*M2) => join-multicolor-tlcrs gc1 gc1 (transport (\lam cl => Closure (TopLevelColoredReduction cl) A' E) (inv p1) A'~>*E) A'~>*C confluence
             | (X, M1~>*X, M2~>*X) => join-multicolor-tlcrs gc1 gc1 E~>*M1 E~>*M2 confluence
             | (c1, T1=>X) => BorderedParallelReduction.append-tlcr _ _ T1=>B X (Closure.compose B~>*M1 M1~>*X)
             | (c2, T2=>X) => BorderedParallelReduction.append-tlcr _ _ T2=>C X (Closure.compose C~>*M2 M2~>*X)
        \in (X, c1, T1=>X, c2, T2=>X)

    \func join-multicolor-tlcrs
      {tc : TheoremContext} (color1 color2 : Color) {context : List Sort'} {s : Sort'}
      {A B C : PureTerm env context s}
      (A~>B : Closure (TopLevelColoredReduction color1) A B)
      (A~>C : Closure (TopLevelColoredReduction color2) A C)
      (confluence : \Pi (c : Color) -> ConfluentialSystem (envs c) (rules c))
      : \Sigma (X : PureTerm env context s) (Closure (TopLevelColoredReduction color2) B X) (Closure (TopLevelColoredReduction color1) C X) =>
      \case \elim color2, decideEq color1 color2, \elim A~>C \with {
        | _, yes idp, A~>C => join-tlcrs color1 A B C A~>B A~>C (confluence color1)
        | color2, no n, A~>C => \case Closure.extract A~>B, Closure.extract A~>C \with {
          | inl a, _ => rewriteI a (C, A~>C, c-trivial idp)
          | _, inl a => rewriteI a (B, c-trivial idp, A~>B)
          | inr (_, rd), inr (_, rd2) =>
            \let | a : HasColoredRoot color1 A => TopLevelColoredReduction.extract-root-coloring rd
                 | b : HasColoredRoot color2 A => TopLevelColoredReduction.extract-root-coloring rd2
            \in \case \elim A, \elim a, \elim b \with {
              | func f arguments, func-root p, func-root q => absurd (n (inv p *> q))
            }
        }
      }
  }

-- | Unifies delayed parallel reduction and top-level single-color reduction.
\func unify-top
  {tc : TheoremContext} {context : List Sort'} {s : Sort'} (color color' : Color)
  (f : symbol s)
  (arguments-A arguments-C : \Pi (index : Index (domain f)) -> PureTerm env (context ++ f env.!!domain index) (f env.!!sort index))
  (B : PureTerm env context s)
  (A~>B : Closure (TopLevelColoredReduction color) (func f arguments-A) B)
  (inner-reductions : \Pi (i : env.index-in f) ->
      \Sigma (someColor : Maybe Color)
             (OppositeColored someColor f.1)
             (BorderedParallelReduction color' someColor (arguments-A i) (arguments-over-f idp arguments-C i)))
  : \Sigma (X : PureTerm env context s)
           (Closure (TopLevelColoredReduction color) (func f arguments-C) X)
           (mcolor : Maybe Color)
           (BorderedParallelReduction color' mcolor B X) =>
  \let
    | (t, rho, t[rho]=A, root-colors) => decompose-term color (func f arguments-A)
    | (u, lu[rho]=B, t~>*u) => iterate-decomposition (Linear.convert-to-term {envs color} t) rho B (rewrite unwrap-injection t[rho]=A) A~>B root-colors
    | injected-u : Term env context s (LinearMetaContext {envs color} t) => inject-term envs u
    | (sigma, C=t[sigma], reds) => alternate-subst {_} color color' (func f arguments-C) t rho root-colors nothing colored-nothing (rewriteI (inv t[rho]=A) (parallelization-f arguments-C inner-reductions (cr-skip idp)))
    | uni-right => Closure.lift {_} {_}
        {\lam x y => \Sigma (rrd : monochrome-reduction color x y) (FunctionalWitness {envs color} {rules color} rrd)}
        {TopLevelColoredReduction color}
        (\lam trm => MetaSubstitution.apply (inject-term envs trm) SubList.sublist-nil-free sigma)
        (\lam tlcr => lift-relation color sigma tlcr.1 tlcr.2)
        (Linear.convert-to-term {envs color} t)
        u
        t~>*u
    | (mcl, uni-left) =>
      unify-left color' color injected-u SubList.sublist-nil-free rho sigma reds
  \in (MetaSubstitution.apply injected-u SubList.sublist-nil-free sigma,
       rewrite C=t[sigma] (rewriteI unwrap-injection uni-right),
       mcl,
       rewriteI lu[rho]=B uni-left)

-- | Converts a sequence of TopLevelColoredReductions to another sequence of regular RewriteRelations
\func iterate-decomposition
  {tc : TheoremContext} {context : List Sort'} {s : Sort'} {inner-mc mc : MetaContext Sort'}
  {color : Color}
  (t : Term (envs color) context s inner-mc)
  (rho : MetaSubstitution env nil inner-mc mc)
  {A : Term env context s mc}
  (B : Term env context s mc)
  (teq : MetaSubstitution.apply (inject-term envs t) SubList.sublist-nil-free rho = A)
  (A~>*B : Closure (TopLevelColoredReduction color) A B)
  (root-colors : \Pi {s : Sort'} (m : inner-mc.metaname s) -> HasExcludedColoredRoot color (rho m))
  : \Sigma
  (u : Term (envs color) context s inner-mc)
  (MetaSubstitution.apply (inject-term envs u) SubList.sublist-nil-free rho = B)
  (Closure (\lam x y => \Sigma (rd : monochrome-reduction color x y) (FunctionalWitness {envs color} {rules color} rd)) t u)
\elim A~>*B
  | c-basic A~>B =>
    \let | (u, lu[rho]=B, t~>u, fw) => decompose-along-reduction color t B rho root-colors (rewrite teq A~>B)
    \in (u, lu[rho]=B, c-basic (t~>u, fw))
  | c-connect C A->C C~>*B =>
    \let | (c, meq, rd, fw) => decompose-along-reduction color t C rho root-colors (rewrite teq A->C)
         | (u, mu, tcl) => iterate-decomposition c rho B meq C~>*B root-colors \in (u, mu, c-connect c (rd, fw) tcl)
  | c-trivial idp => (t, teq, c-trivial idp)

-- | Given rho[t] => C, generates sigma, s.t. sigma[t] = C and forall m, rho(m) => sigma(m)
\func alternate-subst
  {tc : TheoremContext} {context : List Sort'} {s : Sort'} {mc : MetaContext Sort'}
  (gc rcolor : Color)
  (C : Term env context s mc)
  (t : LinearTerm (envs gc) context s)
  (rho : MetaSubstitution env nil (LinearMetaContext {envs gc} t) mc)
  (root-colors : \Pi {s1 : Sort'} -> \Pi (m : metaname {LinearMetaContext {envs gc} t} s1) -> HasExcludedColoredRoot gc (rho m))
  (someColor : Maybe Color)
  (some-color-diff : OppositeColored someColor gc)
  (A=>C : BorderedParallelReduction rcolor someColor (MetaSubstitution.apply (convert-to-injected-term gc {context} {s} t) SubList.sublist-nil-free rho) C)
  : \Sigma (sigma : MetaSubstitution env nil (LinearMetaContext {envs gc} t) mc)
           (C = MetaSubstitution.apply (convert-to-injected-term gc {context} {s} t) SubList.sublist-nil-free sigma)
           (rho~>sigma : \Pi {s : Sort'} (m : metaname {LinearMetaContext {envs gc} t} s) ->
               \Sigma (mcolor : Maybe Color) (BorderedParallelReduction rcolor mcolor (rho m) (sigma m)))
\elim t, someColor, A=>C
  | l-func f arguments, nothing, parallelization-f mediator inner-reductions (cr-skip p) =>
    \let
      | inductive-result i => alternate-subst gc rcolor
          (mediator i) (arguments i)
          (\lam m => rho (i, m))
          (\lam {s1} m => root-colors (i, m))
          (inner-reductions i).1
          (inner-reductions i).2
          (rewrite (modular-commutation (\lam j => LinearMetaContext {envs gc} (arguments j)) i SubList.sublist-nil-free (convert-to-injected-term gc (arguments i)) rho)
              (rewrite (invariant-through-empty-subst rho SubList.sublist-nil-free (SubList.extend-right-single SubList.sublist-nil-free) (ModularMetaContext.upgrade-metavariables
                  (\lam j => LinearMetaContext {envs gc} (arguments j)) (convert-to-injected-term gc (arguments i)))) (inner-reductions i).3))
    \in (\lam {s1} mvar => (inductive-result mvar.1).1 mvar.2,
         inv p *> Term.fext
                      (\lam index => rewriteI
                          (modular-commutation (\lam j => LinearMetaContext {envs gc} (arguments j)) index (SubList.extend-right-single SubList.sublist-nil-free) (convert-to-injected-term gc (arguments index)) (\lam {s1} mvar => (inductive-result mvar.1).1 mvar.2))
                          (rewrite invariant-through-empty-subst (inductive-result index).2)),
         \lam {s1} m => (inductive-result m.1).3 m.2)
  | l-func f arguments, just color, parallelization-f mediator inner-reductions (cr-rewrite tlcr p) => \case Closure.extract tlcr \with {
    | inl a =>
      \let | induc index => alternate-subst gc rcolor (mediator index) (arguments index) (\lam m => rho (index, m)) (\lam {s1} m => root-colors (index, m)) (inner-reductions index).1 (inner-reductions index).2 (rewrite modular-commutation (rewrite trivial-sublist-contractible (inner-reductions index).3))
      \in (\lam mvar => (induc mvar.1).1 mvar.2,
           inv a *> Term.fext
                        (\lam index => rewriteI
                            (modular-commutation (\lam j => LinearMetaContext {envs gc} (arguments j)) index (SubList.extend-right-single SubList.sublist-nil-free) (convert-to-injected-term gc (arguments index)) (\lam {s1} mvar => (induc mvar.1).1 mvar.2))
                            (rewrite invariant-through-empty-subst (induc index).2)),
           \lam {s1} m => (induc m.1).3 m.2)
    | inr (_, rd) => \case \elim some-color-diff \with {
      | colored-opposite gc/=color => absurd (gc/=color (inv (HasColoredRoot.reorganize color (TopLevelColoredReduction.extract-root-coloring rd))))
    }
  }

  | l-func f arguments, someColor, equal-trees p => (rho, inv p, \lam {s1} m => (nothing, equal-trees idp))
  | l-full-metavar, someColor, rd =>
    (\lam {s1} mvar => transport (Term env context __ mc) (inv mvar) C,
     inv (plain-identity-effect C),
     \lam {s1} m => (someColor, unify-reduction rho C rd m))
  | lt-var index p, someColor, equal-trees p1 => (\lam {s1} mvar => contradiction, inv p1, \lam {s1} m => contradiction)
  \where {
    \func unify-reduction {tc : TheoremContext} {gc : Color} {someColor : Maybe Color} {context : List Sort'} {s s' : Sort'} {mc : MetaContext Sort'}
                          (rho :  MetaSubstitution env nil (SingularMetaContext s context) mc)
                          (C : Term env context s mc)
                          (bpr : BorderedParallelReduction gc someColor (Substitution.apply
                              (rho idp) (extend-substitution-left SubList.sublist-nil-free (\lam i => var i idp))) C)
                          (m : s' = s)
      : BorderedParallelReduction gc someColor (rho m)
        (transport (\lam (srt : Sort') => Term env context srt mc) (inv m) C) \elim m
      | idp => rewriteI plain-identity-effect bpr
  }

-- | Given forall m, rho(m) => sigma(m), generates s[rho] => s[sigma]
\func unify-left
  {tc : TheoremContext} {context context' : List Sort'} {sort : Sort'} {inner-mc : MetaContext Sort'}
  (gc anti-color : Color)
  (s : Term env context' sort inner-mc)

  (sublist : SubList context context')
  (rho sigma : MetaSubstitution env context inner-mc EmptyMetaContext)
  (rho~>sigma : \Pi {s : Sort'} (m : inner-mc.metaname s) ->
      \Sigma (mcolor : Maybe Color) (BorderedParallelReduction gc mcolor (rho m) (sigma m)))
  : \Sigma (mcolor : Maybe Color)
           (BorderedParallelReduction gc mcolor (MetaSubstitution.apply s sublist rho) (MetaSubstitution.apply s sublist sigma))
\elim s
  | var index p => (nothing, equal-trees idp)
  | metavar m arguments =>
    \let | main-reduction => rho~>sigma m
         | rho-subst => extend-substitution-left sublist (\lam i => MetaSubstitution.apply (arguments i) sublist rho)
         | sigma-subst => extend-substitution-left sublist (\lam i => MetaSubstitution.apply (arguments i) sublist sigma)
         | inductive i => unify-left gc anti-color (arguments i) sublist rho sigma rho~>sigma
         | target-reduction => reduction-over-substitution main-reduction.1 (rho m) (sigma m) main-reduction.2 rho-subst sigma-subst (\lam i => extend-substitutuion-left-for-parallel (\lam i => MetaSubstitution.apply (arguments i) sublist rho) (\lam i => MetaSubstitution.apply (arguments i) sublist sigma) inductive sublist i)
    \in target-reduction
  | func f arguments =>
    \let | in-indices i => unify-left gc f.1 (arguments i) (SubList.extend-right-single sublist) rho sigma rho~>sigma
         | (someColor, med, inrd, cwr) => collect-reductions-together-raw f
             (\lam i => MetaSubstitution.apply (arguments i) (SubList.extend-right-single sublist) rho)
             (\lam i => MetaSubstitution.apply (arguments i) (SubList.extend-right-single sublist) sigma)
             in-indices
    \in (someColor, parallelization-f med inrd cwr)
  \where {
    \func extend-substitutuion-left-for-parallel
      {tc : TheoremContext} {left-context right-context some-context : List Sort'}
      {gc : Color}
      (subst subst' : Substitution right-context some-context EmptyMetaContext)
      (rd' : \Pi (i : Index right-context) ->
          \Sigma (someColor : Maybe Color) (BorderedParallelReduction gc someColor (subst i) (subst' i)))
      (sublist : SubList left-context some-context)
      (index : Index (left-context ++ right-context))
      : \Sigma (someColor : Maybe Color) (BorderedParallelReduction gc someColor (extend-substitution-left sublist subst index) (extend-substitution-left sublist subst' index)) =>
      partial-fin-induction
          (\lam ind => \Sigma (someColor : Maybe Color) (BorderedParallelReduction gc someColor (extend-substitution-left sublist subst ind) (extend-substitution-left sublist subst' ind)))
          (\lam i => rewrite extend-substitution-left.on-begin (nothing, equal-trees (rewrite extend-substitution-left.on-begin idp)))
          (\lam i => \let inner => rd' i \in rewrite extend-substitution-left.on-end (rewrite extend-substitution-left.on-end (inner.1, lemma inner.1 (inv (expand-fin-right.correct i)) inner.2)))
          index
      \where {
        \func lemma {tc : TheoremContext} {context : List Sort'}
                    {gc : Color} {ms : MetaContext Sort'}
                    (someColor : Maybe Color)
                    {s s' : Sort'}
                    (p : s = s')
                    {A B : Term env context s ms}
                    (bpr : BorderedParallelReduction gc someColor A B)
          : BorderedParallelReduction gc someColor (transport (Term env context __ ms) p A) (transport (Term env context __ ms) p B) \elim p
          | idp => bpr
      }
  }

\func reduction-over-substitution {tc : TheoremContext} {context new-context : List Sort'} {s : Sort'}
                                  {gc : Color}
                                  (color : Maybe Color)
                                  (A B : PureTerm env context s)
                                  (A=>B : BorderedParallelReduction gc color A B)
                                  (subst subst' : Substitution context new-context EmptyMetaContext)
                                  (subst=>subst' : \Pi (i : Index context) -> \Sigma (someColor : Maybe Color) (BorderedParallelReduction gc someColor (subst i) (subst' i)))
  : \Sigma (mcolor : Maybe Color) (BorderedParallelReduction gc mcolor (Substitution.apply A subst) (Substitution.apply B subst')) \elim color, A, A=>B
  | color, A, equal-trees p => rewrite p (distributed-reduction-for-substitution B color _ _ subst=>subst')
  | nothing, func f arguments, parallelization-f mediator _x (cr-skip p) =>
    \let | medium-reductions i => reduction-over-substitution  (_x i).1 (arguments i) (mediator i) (_x i).3 (append-context-right subst) (append-context-right subst') (expand-reduction-right subst subst' subst=>subst')
         | (sc, med, inrd, cwr) => collect-reductions-together-raw f (\lam i => Substitution.apply (arguments i) (append-context-right subst)) (\lam i => Substitution.apply (mediator i) (append-context-right subst')) medium-reductions
    \in rewriteI p (sc, parallelization-f med inrd cwr)
  | just a, func f arguments, parallelization-f mediator _x (cr-rewrite tlcr p) =>
    \let | medium-reductions i => reduction-over-substitution (_x i).1 (arguments i) (mediator i) (_x i).3 (append-context-right subst) (append-context-right subst') (expand-reduction-right subst subst' subst=>subst')
         | (some-color, med, inrd, cwr) => collect-reductions-together-tlcr (just gc) f (\lam i => Substitution.apply (arguments i) (append-context-right subst)) (\lam i => Substitution.apply (mediator i) (append-context-right subst')) medium-reductions (Substitution.apply B subst') (cr-rewrite (rewrite p (Closure.lift (\lam t => Substitution.apply t subst') (\lam rel => tlcr-over-substitution subst' rel) (func f mediator) B tlcr)) idp)
    \in (some-color, parallelization-f med inrd cwr)

\func expand-reduction-right
  {tc : TheoremContext} {context new-context additional-context : List Sort'}
  {gc : Color}
  (subst subst' : Substitution context new-context EmptyMetaContext)
  (rd' : \Pi (i : Index context) ->
      \Sigma (someColor : Maybe Color) (BorderedParallelReduction gc someColor (subst i) (subst' i)))
  (index : Index (context ++ additional-context))
  : \Sigma (someColor : Maybe Color) (BorderedParallelReduction gc someColor (append-context-right subst index) (append-context-right subst' index)) \elim context, index
  | nil, index => (nothing, equal-trees idp)
  | :: a context, 0 => \let ind => rd' 0 \in (ind.1, bpr-over-weakening ind.1 (subst 0) (subst' 0) ind.2 (SubList.extend-right-single SubList.identity))
  | :: a context, suc index => expand-reduction-right (\lam i => subst (suc i)) (\lam i => subst' (suc i)) (\lam i => rd' (suc i)) index

\func tlcr-over-substitution {tc : TheoremContext} {context new-context : List Sort'} {s : Sort'} {mc : MetaContext Sort'}
                             {A B : Term env context s mc}
                             {color : Color}
                             (subst : Substitution context new-context mc)
                             (A~>B : TopLevelColoredReduction color A B)
  : TopLevelColoredReduction color (Substitution.apply A subst) (Substitution.apply B subst) \elim A, B, A~>B
  | A, B, rewrite-with-rule-colored h idx msubst msubst[l]=A msubst[r]=B =>
    rewrite-with-rule-colored
        (hcr-over-substitution subst h)
        idx
        (\lam m => Substitution.apply (msubst m) (append-context-right subst))
        (rewrite (inv msubst[l]=A) ((rewrite (trivial-sublist-contractible _ _)) ((rewrite (trivial-sublist-contractible {_} {context})) (rewrite (identity-sublist-contractible {_} {new-context}) (rewrite (identity-sublist-contractible {_} {context}) (rewrite {2} (append-context-right.to-nil subst) (untransport _ ++_nil ++_nil (\lam {s1 : Sort'} (m : metaname {rule-linear-mc idx} s1) => Substitution.apply (msubst m) (append-context-right subst)) _ _ _ _ _ _ (commutation (convert-to-injected-term color (get-rule-pattern idx)) subst msubst))))))))
        (rewrite (inv msubst[r]=B) ((rewrite (trivial-sublist-contractible _ _)) ((rewrite (trivial-sublist-contractible {_} {context})) (rewrite (identity-sublist-contractible {_} {new-context}) (rewrite (identity-sublist-contractible {_} {context}) (rewrite {2} (append-context-right.to-nil subst) (untransport _ ++_nil ++_nil (\lam {s1 : Sort'} (m : metaname {rule-linear-mc idx} s1) => Substitution.apply (msubst m) (append-context-right subst)) _ _ _ _ _ _ (commutation (inject-term envs (rule-right-linear idx)) subst msubst))))))))

  | func f-A arguments-A, func f-B arguments-B, rewrite-with-parameter-f-colored idp p1 i tlcr eq => rewrite-with-parameter-f-colored idp p1 i (tlcr-over-substitution (append-context-right subst) tlcr) (\lam j _x => rewrite (eq j _x) idp)
  \where {
    \func untransport {env : FSignature} {context-a context-a' context-b context-b' context-meta context-meta2 : List Sort} {s : Sort} {mc mc' : MetaContext Sort}
                      (t : Term env nil s mc)
                      (eq : context-a = context-a')
                      (eq' : context-b = context-b')
                      (ms-a : MetaSubstitution env context-meta mc mc')
                      (sl1 : SubList nil context-a)
                      (sl2 : SubList context-meta context-a)
                      (sl3 : SubList nil context-b)
                      (sl4 : SubList context-meta2 context-b)
                      (ms-b : MetaSubstitution env context-meta2 mc mc')
                      (subst : Substitution context-b context-a mc')
                      (true-eq : MetaSubstitution.apply (weakening t sl1) sl2 ms-a = Substitution.apply (MetaSubstitution.apply (weakening t sl3) sl4 ms-b) subst):
      MetaSubstitution.apply (weakening t
          (transport (SubList nil) eq sl1))
          (transport (SubList context-meta) eq sl2)
          ms-a = Substitution.apply (MetaSubstitution.apply (weakening t
          (transport (SubList nil) eq' sl3))
          (transport (SubList context-meta2) eq' sl4) ms-b)
                     (transport2 (\lam (ctx : List Sort) (ctx' : List Sort) => Substitution ctx ctx' mc') eq' eq subst) \elim eq, eq'
      | idp, idp => true-eq

    \lemma commutation {env : FSignature} {s : Sort} {aux-context core-context new-context : List Sort} {old-ms new-ms : MetaContext Sort}
                       (term : Term env aux-context s old-ms)
                       (subst : Substitution core-context new-context new-ms)
                       (metasubst : MetaSubstitution env core-context old-ms new-ms)
      :
      MetaSubstitution.apply
          (weakening term (SubList.extend-left-single SubList.identity))
          (SubList.extend-right-single SubList.identity) (\lam {s} m => Substitution.apply (metasubst m) (append-context-right subst))
        =
      Substitution.apply (MetaSubstitution.apply
          (weakening term (SubList.extend-left-single SubList.identity))
          (SubList.extend-right-single SubList.identity {aux-context}) metasubst) (append-context-right subst) \elim term
      | var index idp => inv (weakening.combine-with-append-left _ (var index idp))
      | metavar m arguments => repeat {2} (rewrite subst-comm) (cong (ext (\lam i =>
          \let inductive : (\lam j => MetaSubstitution.apply
              (weakening (arguments j) (SubList.extend-left-single SubList.identity))
              (SubList.extend-right-single SubList.identity) (\lam {s} m => Substitution.apply (metasubst m) (append-context-right subst)))
            =
          (\lam j => Substitution.apply (MetaSubstitution.apply
              (weakening (arguments j) (SubList.extend-left-single SubList.identity))
              (SubList.extend-right-single SubList.identity {aux-context}) metasubst) (append-context-right subst)) => ext (\lam j => commutation (arguments j) subst metasubst)
          \in rewrite inductive (subst-comm-different subst _ i))))
      | func f arguments => Term.fext (\lam index => \let inductive => commutation (arguments index) subst metasubst \in rewrite Transports.lb-ls-to-ls (rewrite Transports.rs-rs-to-rs (rewrite Transports.lb-ls-to-ls (rewrite Transports.rs-rs-to-rs (rewrite append-context-right.composition (inductive-step (arguments index) ++-assoc ++-assoc idp idp _ _ _ _ metasubst subst inductive))))))
      \where {
        \lemma subst-comm-different
          {env : FSignature} {context-a context-b context-c context-d : List Sort} {mc : MetaContext Sort}
          (subst : Substitution context-a context-b mc)
          (subst2 : Substitution context-c (context-a ++ context-d) mc)
          (index : Index (context-a ++ context-c))
          : Substitution.apply (append-context-right subst index) (extend-substitution-left (SubList.extend-right-single SubList.identity) (\lam j => Substitution.apply (subst2 j) (append-context-right subst)))
          = Substitution.apply (extend-substitution-left (SubList.extend-right-single SubList.identity) subst2 index) (append-context-right subst) =>
          partial-fin-induction (\lam i => Substitution.apply (append-context-right subst i) (extend-substitution-left (SubList.extend-right-single SubList.identity) (\lam j => Substitution.apply (subst2 j) (append-context-right subst)))
            = Substitution.apply (extend-substitution-left (SubList.extend-right-single SubList.identity) subst2 i) (append-context-right subst))
              (\lam i => rewrite append-context-right.on-begin (rewrite extend-substitution-left.on-begin (rewrite weakening.combine-with-extend-right (inductive-step subst i _))))
              (\lam i => rewrite append-context-right.on-end (rewrite extend-substitution-left.on-end (rewrite (weakening.combine-with-extend-left (\lam (j : Index context-c) => Substitution.apply (subst2 j) (append-context-right subst)) (var i (expand-fin-right.correct i))) (inductive-step-2 subst subst2 i (expand-fin-right.correct i)))))
              index
          \where {
            \func inductive-step-2 {env : FSignature} {context-a context-b context-c context-d : List Sort} {s : Sort} {mc : MetaContext Sort}
                                   (subst : Substitution context-a context-b mc)
                                   (subst2 : Substitution context-c (context-a ++ context-d) mc)
                                   (index : Index context-c)
                                   (eq : s = context-c !! index) :
              Substitution.apply
                  (var index eq)
                  (\lam (j : Index context-c) => Substitution.apply (subst2 j) (append-context-right subst)) =
              Substitution.apply
                  (transport (\lam (p0 : Sort) => Term env (context-a ++ context-d) p0 mc) (inv eq) (subst2 index))
                  (append-context-right subst) \elim eq
              | idp => idp

            \func inductive-step
              {env : FSignature} {context-a context-b context-c : List Sort} {s : Sort} {mc : MetaContext Sort}
              (subst : Substitution context-a context-b mc)
              (index : Index context-a)
              (eq : s = context-a !! index)
              : weakening (coe (\lam (i1 : I) => Term env context-b (inv eq @ i1) mc) (subst index) right)
                (SubList.extend-right-single SubList.identity {context-c}) =
            Substitution.apply
                (var (shift-index (SubList.extend-right-single SubList.identity) index)
                    (Shifts.proof (SubList.extend-right-single SubList.identity) index eq))
                (append-context-right subst) \elim eq
              | idp => rewrite (weakening.combine-with-append-right subst (var index idp)) idp
          }

        \lemma inductive-step
          {env : FSignature} {s : Sort} {big-context-al big-context-ar new-context term-context core-context rbig-context-al rbig-context-ar : List Sort} {old-ms new-ms : MetaContext Sort}
          (term : Term env term-context s old-ms)
          (eq : big-context-al = big-context-ar)
          (eq' : rbig-context-al = rbig-context-ar)
          (eq'' : core-context ++ term-context = rbig-context-ar)
          (eq''' : new-context ++ term-context = big-context-ar)
          (sl-term-ar : SubList term-context big-context-ar)
          (sl-new-ar : SubList new-context big-context-ar)
          (sl-term-rar : SubList term-context rbig-context-ar)
          (sl-core-rar : SubList core-context rbig-context-ar)
          (metasubst : MetaSubstitution env core-context old-ms new-ms)
          (subst : Substitution core-context new-context new-ms)
          (induction-statement : MetaSubstitution.apply
              (weakening term sl-term-ar) sl-new-ar (\lam {s} m => Substitution.apply (metasubst m) (append-context-right subst)) =
          Substitution.apply
              (MetaSubstitution.apply (weakening term sl-term-rar) sl-core-rar metasubst) (transport2 (\lam ctx1 ctx2 => \Pi (i : Index ctx1) -> Term env ctx2 (ctx1 !! i) new-ms) eq'' eq''' (append-context-right subst)))
          : MetaSubstitution.apply
            (weakening term (transport (SubList term-context) (inv eq) sl-term-ar))
            (transport (SubList new-context) (inv eq) sl-new-ar)
            (\lam {s} m => Substitution.apply (metasubst m) (append-context-right subst))
          =
        Substitution.apply
            (MetaSubstitution.apply
                (weakening term (transport (SubList term-context) (inv eq') sl-term-rar))
                (transport (SubList core-context) (inv eq') sl-core-rar) metasubst)
            (transport2 (\lam ctx ctx' => \Pi (index : Index ctx) -> Term env ctx' (ctx !! index) new-ms)
                (inv eq')
                (inv eq)
                (transport2 (\lam ctx1 ctx2 => \Pi (i : Index ctx1) -> Term env ctx2 (ctx1 !! i) new-ms) eq'' eq''' (append-context-right subst)))
        \elim eq, eq', eq'', eq'''
          | idp, idp, idp, idp => induction-statement
      }

    \lemma hcr-over-substitution {tc : TheoremContext} {context new-context : List Sort'} {s : Sort'} {mc : MetaContext Sort'}
                                 {color : Color}
                                 {A : Term env context s mc}
                                 (subst : Substitution context new-context mc)
                                 (hcr : HasColoredRoot color A)
      : HasColoredRoot color (Substitution.apply A subst) \elim A, hcr
      | func _ arguments, func-root p => func-root p
  }

\func bpr-over-weakening
  {tc : TheoremContext} {context new-context : List Sort'} {s : Sort'}
  {gc : Color}
  (someColor : Maybe Color)
  (A B : Term env context s EmptyMetaContext)
  (bpr : BorderedParallelReduction gc someColor A B)
  (sublist : SubList context new-context)
  : BorderedParallelReduction gc someColor (weakening A sublist) (weakening B sublist) \elim someColor, A, bpr
  | just a, func f arguments, parallelization-f mediator _x (cr-rewrite tlcr idp) =>
    \let inductive i => bpr-over-weakening (_x i).1 (arguments i) (mediator i) (_x i).3 (SubList.extend-right-both sublist)
    \in parallelization-f
        (\lam i => weakening (mediator i) (SubList.extend-right-both sublist))
        (\lam i => ((_x i).1, (_x i).2, inductive i))
        (cr-rewrite (Closure.lift {Term env context s EmptyMetaContext} {Term env new-context s EmptyMetaContext} {TopLevelColoredReduction a} {TopLevelColoredReduction a} (weakening __ sublist) (\lam {X} {Y} tlcr => tlcr-over-weakening a X Y tlcr sublist) (func f mediator) B tlcr) idp)
  | cl , A, equal-trees p1 => equal-trees (pmap (weakening __ sublist) p1)
  | nothing, func f arguments, parallelization-f mediator _x (cr-skip idp) =>
    \let inductive i => bpr-over-weakening (_x i).1 (arguments i) (mediator i) (_x i).3 (SubList.extend-right-both sublist)
    \in parallelization-f (\lam index => weakening (mediator index) (SubList.extend-right-both sublist)) (\lam i => ((_x i).1, (_x i).2, inductive i)) (cr-skip idp)

\func tlcr-over-weakening
  {tc : TheoremContext} {context new-context : List Sort'} {s : Sort'}
  (color : Color)
  (A B : Term env context s EmptyMetaContext)
  (tlcr : TopLevelColoredReduction color A B)
  (sublist : SubList context new-context)
  : TopLevelColoredReduction color (weakening A sublist) (weakening B sublist) =>
  \let | weakening-subst => weakening.substitution sublist
       | substed-tlcr => tlcr-over-substitution weakening-subst tlcr
  \in repeat {2} (rewrite weakening.substitution-eq) substed-tlcr

\func distributed-reduction-for-substitution {tc : TheoremContext} {context new-context : List Sort'} {s : Sort'}
                                             (A : PureTerm env context s)
                                             {gc : Color}
                                             (color : Maybe Color)
                                             (subst subst' : Substitution context new-context EmptyMetaContext)
                                             (subst=>subst' : \Pi (i : Index context) -> \Sigma (someColor : Maybe Color) (BorderedParallelReduction gc someColor (subst i) (subst' i)))
  : \Sigma (color' : Maybe Color) (BorderedParallelReduction gc color' (Substitution.apply A subst) (Substitution.apply A subst')) \elim A
  | var index p => \case \elim s, \elim p \with {
    | s, idp => subst=>subst' index
  }
  | metavar m arguments => contradiction
  | func f arguments =>
    \let | inner-reductions i => distributed-reduction-for-substitution (arguments i) {gc} color (append-context-right subst) (append-context-right subst') (expand-reduction-right subst subst' subst=>subst')
         | (sc, med, inrd, cwr) => collect-reductions-together-raw f
             (\lam index => Substitution.apply (arguments index) (append-context-right subst))
             (\lam index => Substitution.apply (arguments index) (append-context-right subst'))
             inner-reductions \in (sc, parallelization-f med inrd cwr)

\func collect-reductions-together-tlcr
  {tc : TheoremContext} {context : List Sort'} {s : Sort'} {mc : MetaContext Sort'}
  {gc : Color}
  (someColor : Maybe Color)
  (f : symbol s)
  (arguments-A arguments-B : \Pi (index : Index (domain f)) -> Term env (context ++ f env.!!domain index) (f env.!!sort index) mc)
  (tlcrs : \Pi (index : Index (domain f)) -> \Sigma (someColor : Maybe Color) (BorderedParallelReduction gc someColor (arguments-A index) (arguments-B index)))
  (C : Term env context s mc)
  (B~>*C : SwitchingReduction gc someColor (func f arguments-B) C)
  : \Sigma
  (someColor : Maybe Color)
  (mediator : \Pi (index : Index (domain f)) ->
      Term env (context ++ f env.!!domain index) (f env.!!sort index) mc)
  (\Pi (i : env.index-in f) -> \Sigma
    (someColor : Maybe Color)
    (OppositeColored someColor f.1)
    (BorderedParallelReduction gc someColor (arguments-A i) (mediator i)))
  (SwitchingReduction gc someColor (func f mediator) C) =>
  \let | common-reduction i => unfold-bpr f.1 (arguments-A i) (arguments-B i) (tlcrs i).2
       | ind-last =>
         modular-induction
             (\lam curmed => \Sigma (someColor : Maybe Color) (SwitchingReduction gc someColor (func f curmed) C))
             arguments-B
             (\lam i => (common-reduction i).1)
             (someColor, B~>*C)
             (\lam delim prev-result =>
                 \let arg-rewrite => (common-reduction delim).7
                 \in propagate-rewriting f C arguments-B (\lam i => (common-reduction i).1) delim prev-result.1 prev-result.2 (common-reduction delim).5 (common-reduction delim).6 arg-rewrite
             )
  \in (ind-last.1, \lam index => (common-reduction index).1, \lam i => ((common-reduction i).2, (common-reduction i).4, (common-reduction i).3), ind-last.2)
  \where {
    \func propagate-rewriting
      {tc : TheoremContext} {context : List Sort'} {s : Sort'} {mc : MetaContext Sort'}
      {gc : Color}
      (f : symbol s)
      (C : Term env context s mc)
      (arguments-B midterms : \Pi (index : Index (domain f)) -> Term env (context ++ f env.!!domain index) (f env.!!sort index) mc)
      (delim : Index (domain f))
      (prev-rd-cl : Maybe Color)
      (pred-rd-cwr : SwitchingReduction gc prev-rd-cl (func f (\new DArray { | at => modular-function arguments-B midterms delim })) C)
      (point-rd-cl : Maybe Color)
      (point-coherence : (point-rd-cl = nothing) `Or` (point-rd-cl = just f.1))
      (point-rd-cwr : SwitchingReduction gc point-rd-cl (midterms delim) (arguments-B delim)) :
      \Sigma (someColor : Maybe Color)
             (SwitchingReduction gc someColor (func f (\new DArray { | at => modular-function arguments-B midterms (suc delim) })) C)
    \elim prev-rd-cl, pred-rd-cwr, point-rd-cl, point-coherence, point-rd-cwr
      | nothing, cr-skip p, nothing, point-coherence, cr-skip p1
      => (nothing, cr-skip (pmap (func f) (ext (inv (modular-function.modular-bridge arguments-B midterms delim (inv p1)))) *> p))
      | nothing, cr-skip p, just color, inl (), _
      | nothing, cr-skip idp, just color, inr b, cr-rewrite ind1~>ind' idp => (just gc, cr-rewrite (upgrade-iterated-reduction f (just-injective (inv b)) arguments-B midterms delim ind1~>ind') idp)
      | just color, cr-rewrite tlcr p, nothing, point-coherence, cr-skip p1
      => (just color, cr-rewrite (rewrite (inv (modular-function.modular-bridge arguments-B midterms delim (inv p1))) tlcr) p)
      | just color, cr-rewrite before~>C idpr, just color1, inl (), _
      | just color, cr-rewrite before~>C idp, just color1, inr b, cr-rewrite ind1~>ind' idp =>
        (just gc, cr-rewrite (Closure.compose (upgrade-iterated-reduction f (just-injective (inv b)) arguments-B midterms delim ind1~>ind') before~>C) idp)

    \func upgrade-iterated-reduction
      {tc : TheoremContext} {context : List Sort'} {s : Sort'} {mc : MetaContext Sort'}
      {gc : Color}
      (f : symbol s)
      (eq : f.1 = gc)
      (arguments-A arguments-B : \Pi (index : Index (domain f)) -> Term env (context ++ f env.!!domain index) (f env.!!sort index) mc)
      (index : Index (domain f))
      (rd : Closure (TopLevelColoredReduction gc) (arguments-B index) (arguments-A index))
      : Closure (TopLevelColoredReduction gc)
        (func f (\new DArray { | at => modular-function arguments-A arguments-B (suc index) }))
        (func f (modular-function arguments-A arguments-B index)) =>
      \let | modular => modular-function arguments-A arguments-B index
           | some' => insert-term f modular index (arguments-B index)
           | mapped => Closure.lift {_} {_}
               {TopLevelColoredReduction gc {mc} {context ++ f env.!!domain index} {f env.!!sort index}}
               {TopLevelColoredReduction gc {mc} {context} {s}}
               (insert-term f modular index)
               (\lam rel => rewrite-with-parameter-f-colored idp eq index (rewrite pointed-function.at-index (rewrite pointed-function.at-index rel)) (\lam j j-not-index => rewrite (pointed-function.not-at-index modular index _ j j-not-index) (rewrite (pointed-function.not-at-index modular index _ j j-not-index) idp)))
               (arguments-B index) (arguments-A index)
               rd
      \in rewrite (modular-to-pointed-forward arguments-A arguments-B) (rewrite {2} (modular-to-pointed arguments-A arguments-B) mapped)

    \func insert-term {env : FSignature} {context : List Sort} {s : Sort} {ms : MetaContext Sort} (f : symbol s)
                      (arguments : \Pi (index : Index (domain f)) -> Term env (context ++ (f FSignature.!!domain index)) (f FSignature.!!sort index) ms)
                      (index : Index (domain f))
                      (point : Term env (context ++ (f FSignature.!!domain index)) (f FSignature.!!sort index) ms)
      : Term env context s ms => func f (pointed-function arguments index point)

    \func unfold-bpr
      {tc : TheoremContext} {context : List Sort'} {s : Sort'} {mc : MetaContext Sort'}
      {gc : Color} {someColor : Maybe Color} (required-color : Color)
      (A B : Term env context s mc)
      (bpr : BorderedParallelReduction gc someColor A B)
      : \Sigma (midterm : Term env context s mc)
               (new-color : Maybe Color)
               (bpr : BorderedParallelReduction gc new-color A midterm)
               (OppositeColored new-color required-color)
               (nc' : Maybe Color)
               ((nc' = nothing) `Or` (nc' = just required-color))
               (cwr : SwitchingReduction gc nc' midterm B)
    \elim someColor, A, bpr
      | _, A, equal-trees p => (A, nothing, equal-trees idp, colored-nothing, nothing, inl idp, cr-skip p)
      | nothing, func f arguments, parallelization-f mediator _x c => (func f mediator, nothing, parallelization-f mediator _x (cr-skip idp), colored-nothing, nothing, inl idp, c)
      | just _, func f arguments, parallelization-f mediator _x (cr-rewrite t idp) => \case decideEq gc required-color \with {
        | yes e => (func f mediator, nothing, parallelization-f mediator _x (cr-skip idp), colored-nothing, just gc, inr (pmap just e), cr-rewrite t idp)
        | no n => (B, just gc, parallelization-f mediator _x (cr-rewrite t idp), colored-opposite n, nothing, inl idp, cr-skip idp)
      }
  }

\func collect-reductions-together-raw
  {tc : TheoremContext} {context : List Sort'} {s : Sort'} {mc : MetaContext Sort'}
  {gc : Color}
  (f : symbol s)
  (arguments-A arguments-B : \Pi (index : Index (domain f)) -> Term env (context ++ f env.!!domain index) (f env.!!sort index) mc)
  (tlcrs : \Pi (index : Index (domain f)) -> \Sigma (someColor : Maybe Color) (BorderedParallelReduction gc someColor (arguments-A index) (arguments-B index)))
  : \Sigma
  (someColor : Maybe Color)
  (mediator : \Pi (index : Index (domain f)) ->
      Term env (context ++ f env.!!domain index) (f env.!!sort index) mc)
  (\Pi (i : env.index-in f) -> \Sigma
    (someColor : Maybe Color)
    (OppositeColored someColor f.1)
    (BorderedParallelReduction gc someColor (arguments-A i) (mediator i)))
  (SwitchingReduction gc someColor (func f mediator) (func f arguments-B)) =>
  collect-reductions-together-tlcr nothing f arguments-A arguments-B tlcrs (func f arguments-B) (cr-skip idp)