Ltac hypInv :=
      try (match goal with
          | [H: Some _ = Some _ |-_ ] => inversion H; clear H; subst
      end); try pairInv.Fixpoint lookupIndex (A : Set)(eqd : eq_dec A)(ls : list A)(a : A) def :=
  match ls with
    | nil => def
    | a' :: ls' =>
      if (eqd a a') then O else S (lookupIndex eqd ls' a def)
  end.

(* Specifications: *)
Lemma nth_lookupIndex : forall (A : Set)(eqd : eq_dec A)(ls : list A) n (a a': A), In a ls -> nth (lookupIndex eqd ls a n ) ls a' = a.
Theorem map_ext_in : forall (A B : Set)(ls : list A)(f1 f2 : A -> B), (forall a, In a ls -> f1 a = f2 a) -> map f1 ls = map f2 ls.
Lemma nth_map_In : forall (A B : Set)(ls : list A)(f : A -> B) i defa defb, i < length ls -> nth i (map f ls) defa = f (nth i ls defb).
Lemma removePresent_In : forall (A : Set)(eqd : eq_dec A)(ls1 ls2 : list A) a, In a ls2 -> (~ In a ls1) -> In a (removePresent eqd ls1 ls2).
Lemma lookupIndex_lt_length : forall (A : Set)(eqd : eq_dec A)(ls : list A) a def, In a ls -> lookupIndex eqd ls a def < length ls.
Lemma skipn_app : forall (A : Set)(ls1 ls2 : list A), skipn (length ls1) (ls1 ++ ls2) = ls2.
Lemma fold_add_init_nat_h : forall (A : Set)(f : A -> nat)(ls : list A)(init1 init2 : nat), (fold_left (fun acc a => acc + (f a))%nat ls (init1 + init2) = init1 + fold_left (fun acc a => acc + (f a))%nat ls init2)%nat.
Lemma fold_add_init_nat : forall (A : Set)(f : A -> nat)(ls : list A)(init : nat), (fold_left (fun acc a => acc + (f a))%nat ls init = init + fold_left (fun acc a => acc + (f a))%nat ls O)%nat.
Lemma length_flatten : forall (A : Set)(ls : list (list A)), length (flatten ls) = fold_left (fun acc a => (acc + (length a))%nat) ls O.
Lemma fold_left_map_eq : forall (A B C : Set)(ls : list A)(f1 : A -> B)(f2 : C -> B -> C)(init : C), fold_left (fun acc b => f2 acc b) (map f1 ls) init = fold_left (fun acc a => f2 acc (f1 a)) ls init.
Lemma fold_add_nat_Permutation : forall (A : Set)(f : A -> nat)(ls1 ls2 : list A), Permutation ls1 ls2 -> fold_left (fun acc a => acc + (f a))%nat ls1 O = fold_left (fun acc a => acc + (f a))%nat ls2 O.
Lemma intersect_NoDup : forall (A : Set)(eqd : eq_dec A)(ls1 ls2 : list A), NoDup ls2 -> NoDup (intersect eqd ls1 ls2).
Lemma intersect_comm_Permutation : forall (A : Set)(eqd : eq_dec A)(ls1 ls2 : list A), NoDup ls1 -> NoDup ls2 -> Permutation (intersect eqd ls1 ls2) (intersect eqd ls2 ls1).
Lemma fold_add_nat_filter_partition : forall (A : Set)(P : A -> bool)(f : A -> nat)(ls : list A), fold_left (fun acc a => acc + (f a))%nat ls O = (plus (fold_left (fun acc a => acc + (f a))%nat (filter P ls) O) (fold_left (fun acc a => acc + (f a))%nat (filter (fun a => negb (P a)) ls) O) ).
Lemma fold_left_add_removePresent : forall (B : Set)(eqd : eq_dec B)(f : B -> nat)(ls u : list B), NoDup ls -> NoDup u -> fold_left (fun acc b => (acc + (f b))%nat) (removePresent eqd u ls) O = minus (fold_left (fun acc b => (acc + (f b))%nat) ls O) (fold_left (fun acc b => (acc + (f b))%nat) (intersect eqd ls u) O).
Lemma fold_add_nat_0 : forall (A : Set)(ls : list A)(f : A -> nat), (forall a, In a ls -> f a = O) -> fold_left (fun acc a => acc + (f a))%nat ls O = O.
Lemma map_snd_zip : forall (A B : Set)(lsa : list A)(lsb : list B), length lsa = length lsb -> map (fun p => snd p) (zip lsa lsb) = lsb.
Theorem Permutation_flatten : forall (A : Set)(ls1 ls2 : list (list A)), Permutation ls1 ls2 -> Permutation (flatten ls1) (flatten ls2).
Theorem zip_map_eq : forall (A B C : Set)(ls : list A)(f1 : A -> B)(f2 : A -> C), zip (map f1 ls) (map f2 ls) = map (fun a => (f1 a, f2 a)) ls.
Theorem removePresent_in_only_if : forall (A : Set)(eqd : eq_dec A)(u ls : list A) a, In a (removePresent eqd u ls) -> In a ls.
Theorem removePresent_correct : forall (A : Set)(eqd : eq_dec A)(u ls : list A) a, In a u -> In a (removePresent eqd u ls) -> False.
Theorem removePresent_NoDup : forall (A : Set)(eqd : eq_dec A)(u ls : list A), NoDup ls -> NoDup (removePresent eqd u ls).
Theorem removePresent_correct2 : forall (A : Set)(eqd : eq_dec A)(u ls : list A) a, (~In a u) -> In a ls -> In a (removePresent eqd u ls).