Section ListArray.
Variable D R : Set.
Hypothesis D_EqDec : EqDec D.
Definition Array := list (D * R).
Fixpoint arrayLookup(ls : list (D * R)) d :=
match ls with
| nil => None
| (d', r') :: ls' =>
if (eqb d d')
then Some r'
else (arrayLookup ls' d)
end.
Definition arrayEquiv(arr1 arr2 : Array) :=
forall d,
(arrayLookup arr1 d) = (arrayLookup arr2 d).
Definition arrayLookupDef(ls : list (D * R)) d def :=
match arrayLookup ls d with
| None => def
| Some r => r
end.
Definition arrayUpdate (arr_opt : option Array) d r_opt :=
let arr := match arr_opt with
| None => nil
| Some arr => arr
end in
match r_opt with
| None => arr
| Some r =>
(d, r) :: arr
end.
induction ls; intuition; simpl in *.
rewrite eqb_refl.
trivial.
case_eq (eqb d a0); intuition;
rewrite H0 in H.
discriminate.
eauto.
Qed.
induction ls; intuition; simpl in *.
case_eq (eqb d a0); intuition;
rewrite H0 in H.
discriminate.
case_eq (eqb d' d); intuition.
rewrite eqb_leibniz in H1.
subst.
case_eq (eqb d a0); intuition.
rewrite eqb_leibniz in H1.
subst.
rewrite eqb_refl in H0.
discriminate.
eapply arrayLookup_app_some_eq.
trivial.
specialize (IHls d d').
case_eq (eqb d' a0); intuition.
rewrite H1 in IHls.
eapply IHls.
trivial.
Qed.
induction ls; intuition; simpl in *.
case_eq (eqb d' d); intuition.
rewrite eqb_leibniz in H0.
subst.
intuition.
case_eq (eqb d' a0); intuition.
Qed.
induction ls; intuition; simpl in *.
discriminate.
case_eq (eqb d a0); intuition.
rewrite H0 in H.
inversion H; clear H; subst.
rewrite eqb_leibniz in H0. subst.
case_eq (eqb d' a0); intuition.
eapply arrayLookup_app_ne.
intuition.
subst.
rewrite eqb_refl in H.
discriminate.
rewrite H0 in H.
case_eq (eqb d' a0); intuition.
eapply IHls; eauto.
Qed.
intuition.
unfold arrayUpdate.
destruct arr.
simpl.
rewrite eqb_refl.
trivial.
simpl.
rewrite eqb_refl.
trivial.
Qed.
intuition.
unfold arrayUpdate.
simpl.
case_eq (eqb p2 p1); intuition.
rewrite eqb_leibniz in H0.
subst.
intuition.
Qed.
intuition.
unfold arrayUpdate.
simpl.
case_eq (eqb p2 p1); intuition.
rewrite eqb_leibniz in H0.
subst.
intuition.
Qed.
End ListArray.
(* Some notation for array lookups *)
Notation "f '#' i " := (arrayLookup _ f i) (at level 70) : array_scope.
Local Open Scope array_scope.
(* A special case for array lookup when the range is lists -- returns nil instead of None when not found.  This is useful for multidimensional arrays. *)
Definition arrayLookupList(A B : Set)(eqd : EqDec A)(ls : list (A * (list B)))(a : A) :=
match (arrayLookup _ ls a) with
| None => nil
| Some ls => ls
end.
induction arr; intuition; simpl in *.
discriminate.
case_eq (eqb a a0); intuition;
rewrite H0 in *.
inversion H; clear H; subst.
rewrite eqb_leibniz in H0.
subst.
intuition.
right.
eapply IHarr.
eauto.
Qed.
induction arr; intuition; simpl in *.
case_eq (eqb a a0); intuition.
rewrite eqb_leibniz in H0.
subst.
intuition.
Qed.
Fixpoint arrayLookupOpt(A B : Set)(eqd : EqDec A)(ls : list (option (A * B)))(a : A) :=
match ls with
| nil => None
| o :: ls' =>
match o with
| None => arrayLookupOpt _ ls' a
| Some (a', b') =>
if (eqb a a') then (Some b') else (arrayLookupOpt _ ls' a)
end
end.
induction 1; intuition; simpl in *.
trivial.
destruct a1.
destruct a2.
destruct p.
simpl in *.
intuition.
subst.
destruct p0. simpl in *.
case_eq (eqb a a0); intuition.
econstructor.
intuition.
eapply IHlist_pred.
destruct p.
case_eq (eqb a a0); intuition.
subst.
eapply IHlist_pred.
Qed.
induction ls; intuition; simpl in *.
destruct a.
destruct p.
simpl.
case_eq (eqb a0 a); intuition.
eapply IHls.
Qed.
induction ls1; intuition; simpl in *.
discriminate.
case_eq (eqb a a0); intuition.
rewrite H0 in H.
trivial.
rewrite H0 in H.
eauto.
Qed.
induction ls1; intuition; simpl in *.
case_eq (eqb a a0); intuition;
rewrite H0 in H.
discriminate.
eauto.
Qed.
induction ls; intuition; simpl in *.
unfold arrayLookupList.
simpl.
case_eq (eqb a a0); intuition.
specialize (X (a0, b)).
intuition.
eapply IHls; intuition.
Qed.
induction ls; intuition; simpl in *.
discriminate.
case_eq (eqb a a0); intuition;
rewrite H0 in H.
inversion H; clear H; subst.
rewrite eqb_leibniz in H0.
subst.
intuition.
right.
eauto.
Qed.
induction 1; intros; simpl in *.
intuition.
discriminate.
destruct a1.
destruct a2.
destruct H.
simpl in *.
subst.
intuition.
case_eq (eqb v a0); intuition.
rewrite H4 in H3.
inversion H3; clear H3; subst.
econstructor; eauto.
rewrite H4 in H3.
edestruct H.
eauto.
intuition.
case_eq (eqb v a0); intuition.
rewrite H4 in H3.
discriminate.
rewrite H4 in H3.
eauto.
Qed.
induction ls; intuition; simpl in *.
intuition.
remember (split ls) as z.
destruct z.
intuition.
pairInv.
simpl in *.
inversion H0; clear H0; subst.
rewrite eqb_refl.
trivial.
simpl in *.
inversion H0; clear H0; subst.
case_eq (eqb a a0); intuition.
rewrite eqb_leibniz in H.
subst.
eapply in_split_l in H1.
rewrite <- Heqz in H1.
simpl in *.
intuition.
Qed.
induction ls; intuition; simpl in *.
remember (split ls) as z.
destruct z.
simpl in *.
intuition; subst.
rewrite eqb_refl in H.
discriminate.
destruct (eqb a a0).
discriminate.
eauto.
Qed.
induction ls; intuition; simpl in *.
case_eq (eqbPair eqda eqdb (a0, b1) (a, b0)); intuition.
exfalso.
unfold eqbPair in *.
simpl in *.
apply andb_true_iff in H0.
intuition.
rewrite eqb_leibniz in H1.
subst.
eapply H.
left.
reflexivity.
trivial.
eauto.
Qed.
induction keys; intuition; simpl in *.
inversion H; clear H; subst.
simpl.
trivial.
inversion H; clear H; subst.
intuition.
simpl.
case_eq (arrayLookup (pair_EqDec eqda eqdb) a2 (a0, b)); intuition.
rewrite  arrayLookup_pair_None in H0.
discriminate.
intuition.
subst.
eapply H.
symmetry.
eapply H3.
trivial.
rewrite arrayLookup_app_None; trivial.
eauto.
Qed.

Theorem arrayLookup_flatten_eq :
forall (A B C : Set)(eqda : EqDec A)(eqdb : EqDec B)(ls : list (list (A * B * C))) keys a b,
list_pred (fun a b => forall x, In x b -> fst (fst x) = a) keys ls ->
NoDup keys ->
arrayLookup _ (flatten ls) (a, b) =
arrayLookup _ (arrayLookupList _ (combine keys ls) a) (a, b).