(** * Permutations modulo p. *)
Fixpoint permmod (p : nat) (l1 : Zlist) {struct l1} :
Zlist -> Prop :=
fun l2 : Zlist =>
match l1 with
| Nil => l2 = Nil Z
| Cons x t =>
exists y : Z, inlist Z y l2 /\ Mod x y p /\ permmod p t (zdrop y l2)
end.

(* Specifications: *)
Lemma permmod_nil : forall p : nat, permmod p (Nil Z) (Nil Z).
Lemma permmod_drop :
forall (p : nat) (x1 x2 : Z) (l1 l2 : Zlist),
Mod x1 x2 p ->
inlist Z x1 l1 ->
inlist Z x2 l2 -> permmod p (zdrop x1 l1) (zdrop x2 l2) -> permmod p l1 l2.
Lemma permmod_drop_cons :
forall (p : nat) (x1 x2 : Z) (t1 l2 : Zlist),
Mod x1 x2 p ->
inlist Z x2 l2 -> permmod p t1 (zdrop x2 l2) -> permmod p (Cons Z x1 t1) l2.
Lemma permmod_cons_extend :
forall (p : nat) (x1 x2 : Z) (l1 l2 : Zlist),
permmod p l1 l2 -> Mod x1 x2 p -> permmod p (Cons Z x1 l1) (Cons Z x2 l2).
Lemma permmod_length :
forall (p : nat) (l1 l2 : Zlist),
permmod p l1 l2 -> length Z l1 = length Z l2.
Lemma permmod_refl : forall (p : nat) (l : Zlist), permmod p l l.
Lemma permmod_sym :
forall (p : nat) (l1 l2 : Zlist), permmod p l1 l2 -> permmod p l2 l1.
Lemma permmod_product :
forall (l0 l1 : Zlist) (p : nat),
permmod p l0 l1 -> Mod (zproduct l0) (zproduct l1) p.
Lemma allex_permmod :
forall (p : nat) (l0 l1 : Zlist),
length Z l0 = length Z l1 ->
(forall x0 : Z,
inlist Z x0 l0 ->
exists x1 : Z,
inlist Z x1 l1 /\ Mod x0 x1 p /\ permmod p (zdrop x0 l0) (zdrop x1 l1)) ->
permmod p l0 l1.
Lemma permmod_allex :
forall (p : nat) (l0 l1 : Zlist),
permmod p l0 l1 ->
forall x : Z,
inlist Z x l0 ->
exists y : Z,
inlist Z y l1 /\ Mod x y p /\ permmod p (zdrop x l0) (zdrop y l1).
Lemma permmod_trans1 :
forall (n p : nat) (l0 l1 l2 : Zlist),
length Z l0 = n ->
length Z l1 = n ->
length Z l2 = n -> permmod p l0 l1 -> permmod p l1 l2 -> permmod p l0 l2.
Lemma permmod_trans :
forall (p : nat) (l0 l1 l2 : Zlist),
permmod p l0 l1 -> permmod p l1 l2 -> permmod p l0 l2.
Lemma permmod_drop_drop1 :
forall (n p : nat) (x y : Z) (l : Zlist),
n = length Z l ->
Mod x y p ->
inlist Z x l -> inlist Z y l -> permmod p (zdrop x l) (zdrop y l).
Lemma permmod_drop_drop :
forall (p : nat) (x y : Z) (l : Zlist),
Mod x y p ->
inlist Z x l -> inlist Z y l -> permmod p (zdrop x l) (zdrop y l).
Lemma permmod_drop_rev :
forall (p : nat) (l0 l1 : Zlist) (x0 x1 : Z),
Mod x0 x1 p ->
inlist Z x0 l0 ->
inlist Z x1 l1 -> permmod p l0 l1 -> permmod p (zdrop x0 l0) (zdrop x1 l1).
Lemma nodoubles_allex_permmod1 :
forall (n p : nat) (l0 l1 : Zlist),
n = length Z l0 ->
n = length Z l1 ->
Prime p ->
length Z l0 = length Z l1 ->
nodoubles p l0 -> allex p l0 l1 -> permmod p l0 l1.
Lemma nodoubles_allex_permmod :
forall (p : nat) (l0 l1 : Zlist),
Prime p ->
length Z l0 = length Z l1 ->
nodoubles p l0 -> allex p l0 l1 -> permmod p l0 l1.
Lemma until_mapmult_permmod :
forall (p : nat) (a : Z),
Prime p ->
~ Mod a 0 p -> permmod p (until (pred p)) (mapmult a (until (pred p))).