Section Update2Rel.
Variables A B : Type.
Variable R : relation A.
Hypothesis A_eq_dec : forall x y : A, {x = y} + {x <> y}.
Hypothesis R_dec : forall x y : A, {R x y} + {~ R x y}.
Proof using.
intros.
induction ns; simpl in *; [ intuition | idtac ].
break_if; simpl in *.
- break_or_hyp; auto.
concludes.
break_and.
auto.
- concludes.
break_and.
auto.
Qed.
Proof using.
intros.
induction ns; simpl in *; [ intuition | idtac ].
break_if.
- break_or_hyp.
* left; auto.
* concludes.
right; auto.
- break_or_hyp.
* intuition.
* concludes.
assumption.
Qed.
Proof using.
induction ns; intros; auto.
assert (H_neq: a <> n).
intro.
subst.
auto with datatypes.
assert (H_not_in: ~ In n ns).
intro.
intuition auto with datatypes.
simpl.
break_if; auto.
simpl.
intro.
break_or_hyp; auto.
intuition eauto.
Qed.
Proof using.
intros.
induction ns; auto.
invc_NoDup.
concludes.
simpl in *.
break_if; auto.
apply NoDup_cons; auto.
apply not_in_not_in_filter_rel.
assumption.
Qed.
Proof using.
induction ns0; intros; simpl in *.
- break_if; auto.
find_apply_lem_hyp irreflexive_R.
intuition.
- break_if; auto.
find_higher_order_rewrite.
trivial.
Qed.
Proof using.
intros f g h n n' l.
generalize f g; clear f g.
induction l; auto.
intros.
simpl in *.
break_let.
destruct a.
find_injection.
set (f' := update2 _ _ _ _ _).
set (g' := update2 _ _ _ _ _).
rewrite (IHl f' g'); auto.
unfold f', g', update2.
break_if; auto.
break_and.
subst.
find_rewrite.
trivial.
Qed.
Proof using.
induction l; intros; auto.
destruct a.
apply IHl.
unfold update2.
break_if; auto.
break_and.
subst.
apply in_or_app.
left.
assumption.
Qed.
Proof using.
induction l; intros; auto.
destruct a.
simpl.
apply IHl.
unfold update2.
break_if; auto.
break_and; subst.
destruct (f n' n); auto.
find_apply_lem_hyp hd_error_some_nil.
intuition.
Qed.
Proof using.
intros.
revert f.
induction ns; intros; auto.
destruct a.
simpl in *.
rewrite IHns.
unfold update2.
break_if; auto.
break_and; subst.
intuition.
Qed.
Proof using.
intros.
revert f.
induction l; intros; auto.
simpl in *.
break_let.
destruct a.
find_injection.
rewrite IHl; unfold update2.
- break_if.
* break_and; subst.
simpl in *.
contradict H.
left.
trivial.
* intros.
trivial.
- intro.
contradict H.
right.
assumption.
Qed.
Proof using.
induction l1; intros; auto.
simpl.
break_let.
destruct a.
find_injection.
rewrite IHl1.
trivial.
Qed.
Proof using.
intros.
assert (H_eq: update2 A_eq_dec f h n ms h h' =  f h h').
unfold update2.
break_if; auto.
break_and; subst.
intuition.
rewrite (collate_f_eq _ _ _ _ _ _ H_eq).
trivial.
Qed.
Proof using.
intros.
rewrite collate_app.
revert f.
induction l1; intros; simpl in *; auto.
break_let.
rewrite IHl1.
- destruct a.
find_injection.
simpl in *.
assert (H_neq: a0 <> h').
intro.
contradict H.
left.
trivial.
rewrite collate_neq_update2; trivial.
- intro.
contradict H.
right.
trivial.
Qed.
Proof using.
intros.
rewrite collate_app.
revert f.
induction l2; intros; simpl in *; auto.
break_let.
subst_max.
simpl in *.
assert (H_neq: a0 <> h'); auto.
rewrite collate_neq_update2; auto.
Qed.
Proof using.
intros h h' l1 l2 f m H_in.
apply functional_extensionality; intro from.
apply functional_extensionality; intro to.
case (A_eq_dec h' from); intro H_dec.
- rewrite <- H_dec.
case (A_eq_dec h to); intro H_dec'.
* rewrite <- H_dec'.
rewrite collate_not_in.
+ subst.
rewrite collate_not_in; auto.
intro.
contradict H_in.
rewrite map_app.
apply in_or_app.
left.
assumption.
+ intro.
contradict H_in.
rewrite map_app.
apply in_or_app.
left.
assumption.
* rewrite collate_neq_update2; auto.
rewrite collate_app.
rewrite collate_app.
simpl.
rewrite collate_neq_update2; auto.
- rewrite collate_neq; auto.
rewrite collate_neq; auto.
unfold update2.
break_if; auto.
break_and; subst.
intuition.
Qed.
Proof using.
intros h f l.
revert h f.
induction l.
- intros.
find_apply_lem_hyp Permutation_nil.
subst.
trivial.
- intros.
destruct a.
simpl in *.
invc_NoDup.
assert (H_in': In (a, b) ((a, b) :: l)).
left.
trivial.
pose proof (Permutation_in _ H0 H_in') as H_pm'.
apply in_split in H_pm'.
break_exists; subst.
find_apply_lem_hyp Permutation_cons_app_inv.
pose proof (IHl h (update2 A_eq_dec f h a (f h a ++ [b])) _ H4 H0) as IHl'.
rewrite IHl'.
rewrite collate_not_in_mid; auto.
intro.
assert (H_pm': Permutation (map (fun nm : A * B => fst nm) l) (map (fun nm : A * B => fst nm) (x ++ x0))).
apply Permutation_map_fst.
trivial.
contradict H3.
revert H.
apply Permutation_in.
apply Permutation_sym.
trivial.
Qed.
Proof using.
intros m n h ns f H_adj.
revert f.
induction ns; intros; auto.
simpl.
break_if; simpl; auto.
rewrite IHns.
unfold update2.
break_if; auto.
break_and; subst.
intuition.
Qed.
Proof using.
intros.
generalize dependent f.
induction dsts.
- auto.
- simpl; intros f H_coll.
eapply IHdsts in H_coll.
destruct (A_eq_dec from a), (A_eq_dec a0 b); subst.
+ rewrite update2_same in *.
find_eapply_lem_hyp in_app_or; break_or_hyp.
* assumption.
* exfalso;
find_eapply_lem_hyp in_inv; break_or_hyp; exfalso; auto.
+ rewrite update2_diff2 in *; auto.
+ rewrite update2_diff1 in *; auto.
+ rewrite update2_diff1 in *; auto.
Qed.
Proof using.
intros m n h ns f.
revert f.
induction ns; intros; auto.
simpl in *.
break_if; simpl.
- rewrite IHns.
* unfold update2.
break_if; auto.
break_and; subst.
contradict H.
left.
trivial.
* intro.
contradict H.
right.
assumption.
- rewrite IHns; auto.
Qed.
Proof using.
intros m n h ns f ns' H_in.
apply collate_map2snd_not_in.
intro.
find_apply_lem_hyp in_remove_all_was_in.
intuition.
Qed.
Proof using.
intros m n h ns f ns' H_in H_adj.
revert f.
induction ns; intros; [ contradict H | idtac ].
invc_NoDup.
simpl in *.
break_or_hyp.
- pose proof (remove_all_cons A_eq_dec ns' n ns) as H_ra.
break_or_hyp; break_and; intuition.
find_rewrite.
simpl.
break_if; intuition.
simpl.
rewrite collate_map2snd_not_in_remove_all; auto.
unfold update2.
break_if; auto.
intuition.
- assert (H_neq: a <> n).
intro.
subst.
intuition.
pose proof (remove_all_cons A_eq_dec ns' a ns) as H_ra.
break_or_hyp; break_and.
* find_rewrite.
rewrite IHns; auto.
* find_rewrite.
simpl.
break_if; auto.
simpl.
rewrite IHns; auto.
unfold update2.
break_if; auto.
break_and.
subst.
intuition.
Qed.
Proof using.
intros m n h ns f ns'.
revert f.
induction ns; intros.
- rewrite remove_all_nil.
trivial.
- pose proof (remove_all_cons A_eq_dec ns' a ns) as H_ra.
break_or_hyp; break_and; find_rewrite.
* rewrite IHns; trivial.
* simpl.
break_if.
+ simpl.
rewrite IHns; simpl; auto.
unfold update2.
break_if; auto.
break_and; subst.
intuition.
+ rewrite IHns; trivial.
Qed.
Proof using.
intros a n h ns f H_adj H_in.
simpl.
break_if; intuition.
clear r.
revert f n h H_in H_adj.
induction ns; intros; simpl.
- unfold update2.
break_if; auto.
intuition.
- assert (H_in': ~ In n ns).
intro.
contradict H_in.
right.
trivial.
assert (H_neq: n <> a0).
intro.
subst.
contradict H_in.
left.
trivial.
simpl in *.
break_if.
* simpl.
unfold update2 at 3.
break_if; intuition eauto.
pose proof (IHns f) as IH'.
rewrite collate_map2snd_not_in; auto.
unfold update2.
break_if; intuition eauto.
break_if; auto.
intuition.
* rewrite IHns; auto.
Qed.
Proof using.
induction ns; intros; auto.
assert (H_in': ~ In n ns).
intro.
contradict H.
right.
trivial.
assert (H_neq: n <> a).
intro.
subst.
contradict H.
left.
trivial.
simpl in *.
break_if; auto.
simpl in *.
assert (H_eq_f: update2 A_eq_dec f h a (f h a ++ [a0]) h n = f h n).
unfold update2.
break_if; auto.
break_and; subst.
intuition.
rewrite (collate_f_eq _ _ _ _ _ _ H_eq_f) in H0.
apply IHns; auto.
Qed.
Proof using.
intros.
induction ns; intros; auto.
simpl in *.
break_if.
- simpl.
intro.
break_or_hyp.
* find_injection.
contradict H.
left.
trivial.
* contradict H1.
apply IHns.
intro.
contradict H.
right.
assumption.
- apply IHns.
intro.
contradict H.
right.
assumption.
Qed.
Proof using.
intros.
induction ns.
- apply NoDup_nil.
- invc_NoDup.
concludes.
simpl.
break_if; auto.
simpl.
apply NoDup_cons; auto.
apply not_in_map2snd.
assumption.
Qed.
Proof using.
intros.
induction ns; intros; simpl in *; intuition.
break_if.
- simpl in *.
break_or_hyp; intuition eauto.
- apply IHns.
assumption.
Qed.
Proof using.
intros m.
induction ns; intros; simpl in *; [ intuition | idtac ].
break_if; simpl in *.
- break_or_hyp.
* find_injection; auto.
* find_apply_hyp_hyp.
break_and.
auto.
- find_apply_hyp_hyp.
break_and.
auto.
Qed.
Proof using.
induction ns; intros; auto.
assert (H_neq: a <> from).
intro.
subst.
contradict H.
left.
trivial.
assert (H_in': ~ In from ns).
intro.
contradict H.
right.
assumption.
simpl.
rewrite IHns; auto.
unfold update2.
break_if; auto.
break_and; subst.
intuition.
Qed.
Proof using.
intros.
generalize dependent f.
induction ns.
- auto.
- intros.
simpl.
eapply IHns; eauto.
destruct (A_eq_dec a a0), (A_eq_dec to b); subst.
+ rewrite update2_eq; auto using in_or_app.
+ rewrite update2_diff2; auto using in_or_app.
+ rewrite update2_diff1; auto using in_or_app.
+ rewrite update2_diff1; auto using in_or_app.
Qed.
Proof using.
induction ns; intros; auto.
simpl in *.
rewrite IHns; auto.
unfold update2.
break_if; auto.
break_and; subst.
intuition.
Qed.
Proof using.
induction ns; intros; simpl in *; [ intuition | idtac ].
invc_NoDup.
break_or_hyp.
- rewrite collate_ls_not_in; auto.
unfold update2.
break_if; auto.
break_or_hyp; intuition.
- assert (H_neq: a <> from).
intro.
find_rewrite.
auto.
rewrite IHns; auto.
unfold update2.
break_if; auto.
break_and; subst.
intuition.
Qed.
Proof using.
intros.
rewrite collate_ls_NoDup_in; auto.
- apply NoDup_filter_rel.
apply NoDup_remove_all.
assumption.
- apply related_filter_rel.
apply in_remove_all_preserve; auto.
assumption.
Qed.
Proof using.
induction ns; intros; simpl in *; auto.
set (f' := update2 _ _ _ _ _).
set (g' := update2 _ _ _ _ _).
rewrite (IHns f' g'); auto.
unfold f', g', update2.
break_if; auto.
break_and.
subst.
find_rewrite.
trivial.
Qed.
Proof using.
intros.
assert (H_eq: update2 A_eq_dec f n h ms h' h = f h' h).
unfold update2.
break_if; auto.
break_and.
subst.
intuition.
rewrite (collate_ls_f_eq _ _ _ _ _ _ _ H_eq).
trivial.
Qed.

Lemma collate_ls_cases :
forall s (f : A -> A -> list B) to m a b,
collate_ls A_eq_dec s f to m a b = f a b \/
exists l,
(forall x, In x l -> x = m) /\
collate_ls A_eq_dec s f to m a b = f a b ++ l.