(* list_pred lifts a predicate on A and B to a predicate on list A and list B.  It is useful for reasoning about fold, map, etc. *)
Inductive list_pred(A B : Set)(pred : A -> B -> Prop) : list A -> list B -> Prop :=
| list_pred_nil : 
    list_pred pred nil nil
| list_pred_cons : 
    forall a1 a2 ls1 ls2,
      pred a1 a2 ->
      list_pred pred ls1 ls2 ->
      list_pred pred (a1 :: ls1) (a2 :: ls2).(* list_pred lifts a predicate on A and B to a predicate on list A and list B.  It is useful for reasoning about fold, map, etc. *)
Inductive list_pred(A B : Set)(pred : A -> B -> Prop) : list A -> list B -> Prop :=
| list_pred_nil : 
    list_pred pred nil nil
| list_pred_cons : 
    forall a1 a2 ls1 ls2,
      pred a1 a2 ->
      list_pred pred ls1 ls2 ->
      list_pred pred (a1 :: ls1) (a2 :: ls2).(* list_pred lifts a predicate on A and B to a predicate on list A and list B.  It is useful for reasoning about fold, map, etc. *)
Inductive list_pred(A B : Set)(pred : A -> B -> Prop) : list A -> list B -> Prop :=
| list_pred_nil : 
    list_pred pred nil nil
| list_pred_cons : 
    forall a1 a2 ls1 ls2,
      pred a1 a2 ->
      list_pred pred ls1 ls2 ->
      list_pred pred (a1 :: ls1) (a2 :: ls2).

Theorem NoDup_flatten_subset : forall (A : Set)(ls1 ls2 : list (list A)), list_pred (fun x y => exists n, y = firstn n x) ls1 ls2 -> NoDup (flatten ls1) -> NoDup (flatten ls2).