Library permutations


Require Import Setoid.

Require Import basics.
Require Import categories.
Require Import preord.
Require Import sets.
Require Import finsets.
Require Import atoms.

Require Import List.

Support and finite permutations

The supported record equips types with an operation to get a finite set of atoms; this finite set is called the "support." This record contains no axioms about the support, but is inteded to be used with nominal types, as defined in nominal.v. We define supported here because it is convenient to have notation for the support of a finite permuatation and disjointness of support before we can define the nominal types.
When x is an element of a supported type, we write x for the support of x, and when y is also an element of a possibly different supported type, we write xy to mean that the support of x and y are disjoint.
Module Support.
  Record supported :=
  Supported
  { carrier :> Type
  ; support : carrier -> finset atom
  }.

  Definition disjoint (A B:supported) (a:A) (b:B) :=
    forall v, v support A a -> v support B b -> False.
End Support.


Notation supported := Support.supported.
Notation Supported := Support.Supported.
Notation "‖ x ‖" := (Support.support _ x) (at level 20, format "‖ x ‖").
Notation "a ♯ b" := (Support.disjoint _ _ a b)
   (at level 25, no associativity, format "a ♯ b").

Canonical Structure atom_supp :=
  Supported atom (fun x => x::nil).

Definition concat A := fold_right (@app A) nil.

Notation "'fresh' '[' x , .. , z ']'" :=
  (fresh_atom (concat atom
   (cons (Support.support _ x) .. (cons (Support.support _ z) nil) ..))).

Here we define finitely supported permuatations of atoms. Such permutations play an important role in the developement of nominal types. The support of a permutation is a finite set that contains all the atoms not fixed by the permutation. Note: the support may be larger than necessary; that is, it may contain atoms that are nonetheless fixed by the permutation. In other words, for a permutation p every atom v is either in the support of p or else p v = v; but it is possible that v may both be in the support of p and also that p v = v.
Permutations form a groupoid category (with a single object; hence a group). When p and q are permuatations, we write p q for the composition, and p⁻¹ represents the inverse permuatation. u v is the permuatation that swaps atoms u and v.
Because we only deal with the finitely supported permutations, we can prove interesting "swap induction" principles, where the inductive step must only consider only swapping of two variables. These induction principles witness the fact that every finitely supported permutation is equivelant to a finite composition of swappings.
Module Perm.

Record perm (A B:unit) :=
  Perm
  { f : atom -> atom
  ; g : atom -> atom
  ; support : finset atom
  ; gf : forall x, g (f x) = x
  ; fg : forall x, f (g x) = x
  ; support_axiom : forall v, v support \/ f v = v
  }.

Canonical Structure perm_support (A B:unit) : supported :=
  Supported (perm A B) (@support A B).

Program Definition eq_mixin (A B:unit) : Eq.mixin_of (perm A B) :=
  Eq.Mixin (perm A B) (fun a b => forall x, f a x = f b x) _ _ _.
Solve Obligations using intuition eauto.

Canonical Structure eq (A B:unit) : Eq.type :=
  Eq.Pack (perm A B) (eq_mixin A B).

Definition ident A : perm A A :=
  Perm A A (fun x => x) (fun x => x) nil
  (fun x => Logic.eq_refl x)
  (fun x => Logic.eq_refl x)
  (fun x => or_intror (Logic.eq_refl x)).

Program Definition compose A B C (p1:perm B C) (p2:perm A B) : perm A C :=
  Perm A C
       (fun x => f p1 (f p2 x))
       (fun x => g p2 (g p1 x))
       (p1 ++ p2)
       _ _ _.

Definition comp_mixin : Comp.mixin_of unit perm
  := Comp.Mixin unit perm ident compose.

Canonical Structure comp : Comp.type :=
  Comp.Pack unit perm comp_mixin.

Lemma category_axioms : Category.axioms unit perm eq_mixin comp_mixin.

Canonical Structure PERM : category
  := Category unit perm eq_mixin comp_mixin category_axioms.

Program Definition inv A B (p:perm A B) : perm B A:=
  Perm B A (g p) (f p) (support p) (fg p) (gf p) _.

Lemma inv_id1 : forall A B (p:perm A B),
  p (inv A B p) id(B).

Lemma inv_id2 : forall A B (p:perm A B),
  inv A B p p id(A).

Program Definition groupoid_mixin
  := Groupoid.Mixin
       unit perm
       eq_mixin
       comp_mixin
       inv _.

Definition groupoid :=
  Groupoid
       unit perm
       eq_mixin
       comp_mixin
       category_axioms
       groupoid_mixin.

Lemma f_inj : forall (p:perm tt tt) x y,
  f p x = f p y -> x = y.

Lemma g_inj : forall (p:perm tt tt) x y,
  g p x = g p y -> x = y.

Program Definition swap (x y:atom) : perm tt tt :=
  Perm tt tt
       (fun z => if string_dec x z then y
                   else if string_dec y z then x else z)
       (fun z => if string_dec x z then y
                   else if string_dec y z then x else z)
       (x::y::nil)
       _ _ _.

Lemma swap_swap (p q:atom) :
  swap p q swap q p.

Lemma assoc (f g h : perm tt tt) :
  f (g h) (f g) h.

Lemma swap_self_inv p q :
  swap p q swap p q id(tt).

Lemma swap_same_id p :
  swap p p id(tt).

Lemma swap_swizzle (p q r:atom)
  (Hrp : r <> p) (Hrq : r <> q) (Hpq : p <> q) :
  swap p r swap r q
  swap r q swap p q.

Lemma support_perm (p:perm tt tt) (v:atom) :
  v support p <-> f p v support p.

Lemma support_perm' (p:perm tt tt) (v:atom) :
  v support p <-> f (inv tt tt p) v support p.

End Perm.

Canonical Structure Perm.eq.
Canonical Structure Perm.comp.
Canonical Structure Perm.perm_support.
Canonical Structure Perm.PERM.
Canonical Structure Perm.groupoid.

Notation perm := (Perm.perm tt tt).
Notation PERM := Perm.PERM.
Coercion Perm.f : Perm.perm >-> Funclass.

Notation "u ⇋ v" := (Perm.swap u v) (at level 20, no associativity).

Permutations with disjoint support commute.
Lemma perm_commute (p q:perm) :
  pq -> p q q p.

Swappings commute with any permutation by applying the permuatation to the swapped atoms.
Lemma swap_commute u w (p:perm) :
  (p u p w) p p (u w).

Lemma swap_commute' u w (p:perm) :
  (u w) p p (p⁻¹ u p⁻¹ w).

Here we prove the swapping induction principles. The first decomposes a permutation on the left; the second decomposes on the right.
These induction principles are proved by induction on the size of the support set of a permutation. At each step we can reduce the support by applying a swap.
Require Import Arith.

Lemma swap_induction (P:perm -> Prop) :
  (forall p p', p p' -> P p -> P p') ->
  P id ->
  (forall u v (p:perm), p u = u -> u <> v -> P p -> P (u v p)) ->
  forall p, P p.

Lemma swap_induction' (P:perm -> Prop) :
  (forall p p', p p' -> P p -> P p') ->
  P id ->
  (forall u v (p:perm), p u = u -> u <> v -> P p -> P (p u v)) ->
  forall p, P p.