Built with Alectryon, running Coq+SerAPI v8.13.0+0.13.0. Bubbles () indicate interactive fragments: hover for details, tap to reveal contents. Use Ctrl+↑ Ctrl+↓ to navigate, Ctrl+🖱️ to focus. On Mac, use instead of Ctrl.
(******************************************************************************)
(*                                                                            *)
(*                     Generalised Hanoi Problem                              *)
(*                                                                            *)
(******************************************************************************)
(*                                                                            *)
(*      We consider a generalisation of Hanoi problem :                       *)
(*        a parameter n : the number of pegs                                  *)
(*        a parameter r : r p1 p2 tells that a disk can go from p1 -> p2      *)
(*                                                                            *)
(*    peg n             == type for pegs  (there are n pegs)                  *)
(*    disk k            == type for disks (there are k disk)                  *)
(*    configuration k n == type for hanoi configuration with                  *)
(*                         k disks and n pegs                                 *)
(*    ldisk             == the largest disk                                   *)
(*    sdisk             == the smallest disk                                  *)
(*    d1 \larger d2     == disk d1 is larger than disk d2                     *)
(*    c d               == the peg on which the disk d in the configuration c *)
(*    `c[p]             == a configuration with n disk where all the disks    *)
(*    `p[p1, p2]        == pick a peg (if possible) that is diffenent from p1 *)
(*                         and p2                                             *)
(*                         are on peg p                                       *)
(*    on_top d c        == the disk c is on top of its peg on the             *)
(*                         configuration c                                    *)
(*    rrel              == a regular relation between pegs, rrel p1 p2 is     *)
(*                         true iff peg p1 is different from peg p2           *)
(*    lrel              == a linear relation between pegs, lrel p1 p2 is      *)
(*                         true iff peg p1 is next to peg p2                  *)
(*    srel              == a star relation between pegs, srel p1 p2 is        *)
(*                         true iff p1 != p2 and p1 or p2 is the 0 peg        *)
(*    move r c1 c2      == checks if going from configuration c1              *)
(*                         to configuration c2 is a move compatible with      *)
(*                         relation r (a relation over pegs)                  *)
(*   cdisjoint c1 c2    == configurations c1 and c2 are on different pegs     *) 
(*   cmerge c1 c2       == merge a configuration c1 with m disk and a         *)
(*                         a configuration with n disks to get a configuration*) 
(*                         with m + n disk                                    *)
(*   crshift c          == right shift a configuration c with m + n disks, to *)
(*                         get a configuration with n disks taking the disks  *)
(*                         larger than m                                      *)
(*   clshift c          == right shift a configuration c with m + n disks, to *)
(*                         get a configuration with n disks taking the disks  *)
(*                         smaller than m                                     *)
(*   ↑[c]_ p            == lift a configuration by adding a largest disk on   *)
(*                         peg p. This lifting is done from the largest one   *)
(*                         so to accomodate the usual induction               *)
(*   ↓[c]               == unlift a configuration by removing the largest     *)
(*                         disk                                               *)
(*   plift i p          == lift a configuration by adding a new empty peg i   *)
(*                                                                            *)
(******************************************************************************)

Notation "[ rel _ _ | _ ]" was already used in scope fun_scope. [notation-overridden,parsing]
Notation "[ rel _ _ : _ | _ ]" was already used in scope fun_scope. [notation-overridden,parsing]
Notation "[ rel _ _ in _ & _ | _ ]" was already used in scope fun_scope. [notation-overridden,parsing]
Notation "[ rel _ _ in _ & _ ]" was already used in scope fun_scope. [notation-overridden,parsing]
Notation "[ rel _ _ in _ | _ ]" was already used in scope fun_scope. [notation-overridden,parsing]
Notation "[ rel _ _ in _ ]" was already used in scope fun_scope. [notation-overridden,parsing]
Notation "_ + _" was already used in scope nat_scope. [notation-overridden,parsing]
Notation "_ - _" was already used in scope nat_scope. [notation-overridden,parsing]
Notation "_ <= _" was already used in scope nat_scope. [notation-overridden,parsing]
Notation "_ < _" was already used in scope nat_scope. [notation-overridden,parsing]
Notation "_ >= _" was already used in scope nat_scope. [notation-overridden,parsing]
Notation "_ > _" was already used in scope nat_scope. [notation-overridden,parsing]
Notation "_ <= _ <= _" was already used in scope nat_scope. [notation-overridden,parsing]
Notation "_ < _ <= _" was already used in scope nat_scope. [notation-overridden,parsing]
Notation "_ <= _ < _" was already used in scope nat_scope. [notation-overridden,parsing]
Notation "_ < _ < _" was already used in scope nat_scope. [notation-overridden,parsing]
Notation "_ * _" was already used in scope nat_scope. [notation-overridden,parsing]
From hanoi Require Import extra gdist. Set Implicit Arguments. Unset Strict Implicit. Unset Printing Implicit Defensive. Section GHanoi. Variable q : nat. (******************************************************************************) (* The pegs are the elements of 'I_q *) (******************************************************************************) Definition peg := 'I_q. Variable r : rel peg. Hypothesis irH : irreflexive r. Hypothesis symH : symmetric r. Section Disk. (******************************************************************************) (* The disks are represented with the element of 'I_n with *) (* the idea that disk d1 is larger than disk d2 is d2 <= d1. *) (******************************************************************************) Variable n : nat. Definition disk := 'I_n. Definition mk_disk m (H : m < n) : disk := Ordinal H. (******************************************************************************) (* Given a configuration c, the disks on the peg p can be reconstructed by *) (* the list in decreasing order of the disk d such that c d = p *) (******************************************************************************) Definition configuration := {ffun disk -> peg}. (* A perfect configuration is one where all the pegs are on a single peg p *) Definition perfect p : configuration := [ffun d => p]. End Disk. Arguments perfect [n]. Local Notation "`c[ p ] " := (perfect p) (format "`c[ p ]", at level 5). (* The smallest disk *) Definition sdisk {n} : disk n.+1 := ord0.
q:nat
r:rel peg
irH:irreflexive r
symH:symmetric r
d:disk 1

d = sdisk
2
by apply/val_eqP; case: d => [] []. Qed.
5678
c1, c2:configuration 1

(c1 == c2) = (c1 sdisk == c2 sdisk)
d
f
c1 sdisk = c2 sdisk -> c1 = c2
by move=> H; apply/ffunP=> i; rewrite [i]disk1_all. Qed. (* The largest disk *) Definition ldisk {n} : disk n.+1 := ord_max. (******************************************************************************) (* The disk d is on top of peg (c d) *) (******************************************************************************) Definition on_top n (d : disk n) (c : configuration n) := [forall d1 : disk n, (c d == c d1) ==> (d <= d1)].
5678
n:nat
d:disk n
c:configuration n

reflect (forall d1 : ordinal_finType n, c d = c d1 -> d <= d1) (on_top d c)
18
56781b1c1d
H:forall x : ordinal_finType n, (c d == c x) ==> (d <= x)
d1:ordinal_finType n
cdEcd1:c d = c d1

d <= d1
56781b1c1d
H:forall d1 : ordinal_finType n, c d = c d1 -> d <= d1
25
(c d == c d1) ==> (d <= d1)
2a
2c
by apply/implyP=> /eqP /H. Qed. (******************************************************************************) (* A move is a relation between two configurations c1 c2: *) (* there must exist a disk d1, that is the only one that has changed of *) (* peg (c1 d1 != c2 d1) that is on top of c1 and c2 *) (******************************************************************************) Definition move {n} : rel (configuration n) := [rel c1 c2 | [exists d1 : disk n, [&& r ((c1 : configuration n) d1) (c2 d1), [forall d2, (d1 != d2) ==> (c1 d2 == c2 d2)], on_top d1 c1 & on_top d1 c2]]].
56781b
c1, c2:configuration n

reflect (exists d1 : ordinal_finType n, [/\ r (c1 d1) (c2 d1), forall d2 : ordinal_finType n, d1 != d2 -> c1 d2 = c2 d2, on_top d1 c1 & on_top d1 c2]) (move c1 c2)
31
56781b34
d:ordinal_finType n
H1:r (c1 d) (c2 d)
H2:forall x : ordinal_finType n, (d != x) ==> (c1 x == c2 x)
H3:on_top d c1
H4:on_top d c2

[/\ r (c1 d) (c2 d), forall d2 : ordinal_finType n, d != d2 -> c1 d2 = c2 d2, on_top d c1 & on_top d c2]
56781b343b3c
H2:forall d2 : ordinal_finType n, d != d2 -> c1 d2 = c2 d2
3e3f
[&& r (c1 d) (c2 d), [forall d2, (d != d2) ==> (c1 d2 == c2 d2)], on_top d c1 & on_top d c2]
43
45
56781b343b3c443e3f25
H:d != d1

c1 d1 == c2 d1
by rewrite H2. Qed.
56781b3b34

move c1 c2 -> c1 d != c2 d -> on_top d c1
50
56781b3b3425
H1:r (c1 d1) (c2 d1)
H2:forall d2 : ordinal_finType n, d1 != d2 -> c1 d2 = c2 d2
H3:on_top d1 c1
H4:on_top d1 c2
H5:c1 d != c2 d

on_top d c1
58
d = d1
56781b3b3425595a5b5c5d4d

false
by case/eqP: H5; apply: H2; rewrite eq_sym. Qed.
52
move c1 c2 -> c1 d != c2 d -> on_top d c2
69
58
on_top d c2
60
63 by case/eqP: H5; apply: H2; rewrite eq_sym. Qed. (* this holds if r is symmetric *)
33
move c1 c2 = move c2 c1
73
by apply/moveP/moveP=> [] [d [H1 H2 H3 H4]]; exists d; split; rewrite 1?symH 1?eq_sym // => e dDe; apply/sym_equal/H2. Qed. (* In a move, the disk that moves accomodates r *)
56781b1c34

move c1 c2 -> c1 d != c2 d -> r (c1 d) (c2 d)
78
56781b1c3425595a5b5c
c1dDc2d:c1 d <> c2 d

r (c1 d) (c2 d)
by have [/eqP<-|/H2] := boolP (d1 == d). Qed. (* In a move, only one disk moves *)
56781b
d1, d2:disk n
34

move c1 c2 -> c1 d1 != c2 d1 -> d1 != d2 -> c1 d2 = c2 d2
84
56781b8734
d3:ordinal_finType n
H1:r (c1 d3) (c2 d3)
H2:forall d2 : ordinal_finType n, d3 != d2 -> c1 d2 = c2 d2
H3:on_top d3 c1
H4:on_top d3 c2
c1d1Dc2d1:c1 d1 != c2 d1
d1Dd2:d1 != d2

c1 d2 = c2 d2
56781b87348e8f9091929394
d3Dd1:d3 != d1

95
56781b87348e8f9091929394
d3Ed1:d3 = d1
95
9d
95
by apply: H2; rewrite d3Ed1. Qed.
56781b
d, d1:disk n
34

move c1 c2 -> c1 d != c2 d -> d1 < d -> c1 d1 != c1 d
a3
56781ba634
c1Mc2:move c1 c2
c1Dc2:c1 d != c2 d

c1 d = c1 d1 -> d <= d1
by have /on_topP := move_on_topl c1Mc2 c1Dc2; apply. Qed.
a5
move c1 c2 -> c1 d != c2 d -> d1 <= d -> c1 d1 != c2 d
b1
56781ba634adae
dLd1:d1 < d

c1 d1 != c2 d
b8
d != d1
b8
~~ (d <= d1) -> c2 d != c2 d1
b8
c1
b8
c2 d = c2 d1 -> d <= d1
by have /on_topP := move_on_topr c1Mc2 c1Dc2; apply. Qed.
a5
move c1 c2 -> c1 d != c2 d -> d1 < d -> c2 d1 != c2 d
ca
ac
c8
by have /on_topP := move_on_topr c1Mc2 c1Dc2; apply. Qed.
a5
move c1 c2 -> c1 d != c2 d -> d1 <= d -> c2 d1 != c1 d
d2
ac
c2 d != c1 d
b8
c2 d1 != c1 d
b8
dc
b8
d1 != d
b8
~~ (d <= d1) -> c1 d != c1 d1
b8
e6
b8
af
have /on_topP := move_on_topl c1Mc2 c1Dc2; apply. Qed. (* configuration on different pegs *) Definition cdisjoint m n (c1 : configuration m) (c2 : configuration n) := [forall i, [forall j, c1 i != c2 j]].
5678
m, n:nat
c1:configuration m
c2:configuration n

reflect (forall (i : ordinal_finType m) (j : ordinal_finType n), c1 i != c2 j) (cdisjoint c1 c2)
ee
5678f1f2f3
H:forall x : ordinal_finType m, [forall j, c1 x != c2 j]
i:ordinal_finType m
j:ordinal_finType n

c1 i != c2 j
5678f1f2f3
H:forall (i : ordinal_finType m) (j : ordinal_finType n), c1 i != c2 j
fb
[forall j, c1 i != c2 j]
100
102
by apply/forallP=> j; apply: H. Qed. (* merging two configurations : c1 for the small disks, c2 for the big ones *) Definition cmerge m n (c1 : configuration m) (c2 : configuration n) := [ffun i => match tsplit i with inl j => c1 j | inr j => c2 j end]. (* right shifting a configuration : taking the disks smaller than n *) Definition crshift m n (c : configuration (m + n)) : configuration n := [ffun i => c (trshift m i)]. (* left shifting a configuration : taking the disks larger than n *) Definition clshift m n (c : configuration (m + n)) : configuration m := [ffun i => c (tlshift n i)]. (* Sanity check *)
5678f1
c:configuration (m + n)

cmerge (clshift c) (crshift c) = c
107
5678f110a
i:ordinal_finType (m + n)

match tsplit i with | inl j => clshift c j | inr j => crshift c j end = c i
by case: tsplitP => [] j iE; rewrite !ffunE /=; congr fun_of_fin; apply/val_eqP/eqP. Qed.
5678
k, m:nat
x:'I_k

tsplit (tlshift m x) = inl x
114
5678117118
j:'I_m
jE:x + m = j

inr j = inl x
5678117
x, k1:'I_k
x + m == k1 + m -> inl k1 = inl x
124
126
5678117125
H:x = k1

inl k1 = inl x
by congr (inl _); apply: val_inj. Qed.
116
tsplit (trshift m x) = inr x
131
5678117
x, j:'I_k
jE:x = j

inr j = inr x
5678117118
k1:'I_m
xE:x = k1 + k
inl k1 = inr x
13e
141
by have := ltn_ord x; rewrite xE ltnNge leq_addl. Qed.
5678f1
x:'I_n
f2f3

on_top (trshift m x) (cmerge c1 c2) = on_top x c2
146
148
(forall d1 : ordinal_finType (m + n), cmerge c1 c2 (trshift m x) = cmerge c1 c2 d1 -> trshift m x <= d1) -> forall d1 : ordinal_finType n, c2 x = c2 d1 -> x <= d1
148
(forall d1 : ordinal_finType n, c2 x = c2 d1 -> x <= d1) -> forall d1 : ordinal_finType (m + n), cmerge c1 c2 (trshift m x) = cmerge c1 c2 d1 -> trshift m x <= d1
5678f1149f2f3
Hx:forall d1 : ordinal_finType (m + n), cmerge c1 c2 (trshift m x) = cmerge c1 c2 d1 -> trshift m x <= d1
d2:ordinal_finType n
cxEcd2:c2 x = c2 d2

x <= d2
150
156
(cmerge c1 c2 (trshift m x) = cmerge c1 c2 (trshift m d2) -> trshift m x <= trshift m d2) -> x <= d2
150
148
152
5678f1149f2f3
H:forall d1 : ordinal_finType n, c2 x = c2 d1 -> x <= d1
d:ordinal_finType (m + n)

c2 x = match tsplit d with | inl j => c1 j | inr j => c2 j end -> x <= d
5678f1149f2f3166167
j:'I_n
H1:c2 x = c2 j

x <= j
5678f1149f2f3166167
k:'I_m
x <= k + n
172
174
by apply: leq_trans (ltnW _) (leq_addl _ _). Qed.
5678f11d
c1, c2:configuration m

move (cmerge c c1) (cmerge c c2) = move c1 c2
179
5678f11d17c
d1:ordinal_finType m
H1d1:r (c1 d1) (c2 d1)
H2d1:forall d2 : ordinal_finType m, d1 != d2 -> c1 d2 = c2 d2
H3d1:on_top d1 c1
H4d1:on_top d1 c2

exists d1 : ordinal_finType (n + m), [/\ r (cmerge c c1 d1) (cmerge c c2 d1), forall d2 : ordinal_finType (n + m), d1 != d2 -> cmerge c c1 d2 = cmerge c c2 d2, on_top d1 (cmerge c c1) & on_top d1 (cmerge c c2)]
5678f11d17c
d1:ordinal_finType (n + m)
H1d1:r (cmerge c c1 d1) (cmerge c c2 d1)
H2d1:forall d2 : ordinal_finType (n + m), d1 != d2 -> cmerge c c1 d2 = cmerge c c2 d2
H3d1:on_top d1 (cmerge c c1)
H4d1:on_top d1 (cmerge c c2)
exists d1 : ordinal_finType m, [/\ r (c1 d1) (c2 d1), forall d2 : ordinal_finType m, d1 != d2 -> c1 d2 = c2 d2, on_top d1 c1 & on_top d1 c2]
182
r (cmerge c c1 (trshift n d1)) (cmerge c c2 (trshift n d1))
182
forall d2 : ordinal_finType (n + m), trshift n d1 != d2 -> cmerge c c1 d2 = cmerge c c2 d2
18a
182
198
189
5678f11d17c183184185186187
d2:ordinal_finType (n + m)
173
d2E:d2 = k
H:trshift n d1 != d2

c1 k = c2 k
189
5678f11d17c1831841861871a01731a1

trshift n k == d2
189
18b
exists d1 : ordinal_finType m, [/\ r (c1 d1) (c2 d1), forall d2 : ordinal_finType m, d1 != d2 -> c1 d2 = c2 d2, on_top d1 c1 & on_top d1 c2]
5678f11d17c18c18e18f190

r match tsplit d1 with | inl j => c j | inr j => c1 j end match tsplit d1 with | inl j => c j | inr j => c2 j end -> exists d1 : ordinal_finType m, [/\ r (c1 d1) (c2 d1), forall d2 : ordinal_finType m, d1 != d2 -> c1 d2 = c2 d2, on_top d1 c1 & on_top d1 c2]
5678f11d17c18c18e18f19011f
jE:d1 = j
H1x:r (c1 j) (c2 j)

1ac
5678f11d17c18c18e18f19011f1b61b7
d1E:trshift n j = d1

1ac
5678f11d17c18c18e11f1b61b71bc
H3d1:on_top (trshift n j) (cmerge c c1)
H4d1:on_top (trshift n j) (cmerge c c2)

1ac
1c0
forall d2 : ordinal_finType m, j != d2 -> c1 d2 = c2 d2
5678f11d17c18c18e11f1b61b71bc1c11c2
d2:ordinal_finType m
kDd2:j != d2

95
1ca
(d1 != trshift n d2 -> cmerge c c1 (trshift n d2) = cmerge c c2 (trshift n d2)) -> c1 d2 = c2 d2
5678f11d17c18c18e11f1b61b71bc1c11c21cb1cc
H:d1 != trshift n d2 -> c1 d2 = c2 d2

95
1ca
d1 != trshift n d2
5678f11d17c18c18e11f1b61b71bc1c11c21cb

d1 == d2 -> j == d2
by rewrite jE. Qed.
5678f1f2f3
cs:seq (configuration n)

path move (cmerge c1 c2) [seq cmerge c1 c | c <- cs] = path move c2 cs
1e0
by elim: cs c2 => //= c3 cs IH c2; rewrite move_merger IH. Qed.
5678f1
c:configuration m
34

connect move c1 c2 -> connect move (cmerge c c1) (cmerge c c2)
1e7
5678f11ea34
x:seq (finfun_finType (ordinal_finType n) (ordinal_finType q))
Hp:path move (cmerge c c1) [seq cmerge c c0 | c0 <- x]
Hl:c2 = last c1 x

connect move (cmerge c c1) (cmerge c c2)
1f0
cmerge c c2 = last (cmerge c c1) [seq cmerge c c0 | c0 <- x]
by rewrite Hl [RHS]last_map. Qed. (* this should be equality *)
1e9
connect move c1 c2 -> `d[cmerge c c1, cmerge c c2]_move <= `d[c1, c2]_move
1fa
5678f11ea34
p1:seq (finfun_finType (ordinal_finType n) (ordinal_finType q))
p1H:gpath move c1 c2 p1

`d[cmerge c c1, cmerge c c2]_move <= `d[c1, c2]_move
201
`d[cmerge c c1, cmerge c c2]_move <= size [seq cmerge c i | i <- p1]
201
last (cmerge c c1) [seq cmerge c i | i <- p1] = cmerge c c2
by rewrite [LHS]last_map (gpath_last p1H). Qed.
5678f1f2f3
d:disk m

cdisjoint c1 c2 -> on_top d c1 -> on_top (tlshift n d) (cmerge c1 c2)
20e
5678f1f2f3211
c1Dc2:cdisjoint c1 c2
dTc:forall d1 : ordinal_finType m, c1 d = c1 d1 -> d <= d1
d1:ordinal_finType (m + n)

cmerge c1 c2 (tlshift n d) = cmerge c1 c2 d1 -> tlshift n d <= d1
217
c1 d = match tsplit d1 with | inl j => c1 j | inr j => c2 j end -> d + n <= d1
5678f1f2f321121821921a11f
c1dc1j:c1 d = c1 j

d + n <= j + n
5678f1f2f321121821921a16d
c1dc1j:c1 d = c2 j
d + n <= j
228
22a
by have /cdisjointP/(_ d j)/eqP[] := c1Dc2. Qed.
5678f1f2f3
d:'I_m

on_top (tlshift n d) (cmerge c1 c2) -> on_top d c1
22f
5678f1f2f3232
dTc:forall d1 : ordinal_finType (m + n), cmerge c1 c2 (tlshift n d) = cmerge c1 c2 d1 -> tlshift n d <= d1
183
Hc:c1 d = c1 d1

27
238
(cmerge c1 c2 (tlshift n d) = cmerge c1 c2 (tlshift n d1) -> tlshift n d <= tlshift n d1) -> d <= d1
by rewrite !ffunE !tsplit_tlshift /= leq_add2r; apply. Qed.
5678f117c1d

move (cmerge c1 c) (cmerge c2 c) -> move c1 c2
240
5678f117c1d
x:ordinal_finType (m + n)
H1x:r (cmerge c1 c x) (cmerge c2 c x)
H2x:forall d2 : ordinal_finType (m + n), x != d2 -> cmerge c1 c d2 = cmerge c2 c d2
H3x:on_top x (cmerge c1 c)
H4x:on_top x (cmerge c2 c)

1ac
5678f117c1d24924b24c24d

r match tsplit x with | inl j => c1 j | inr j => c j end match tsplit x with | inl j => c2 j | inr j => c j end -> exists d1 : ordinal_finType m, [/\ r (c1 d1) (c2 d1), forall d2 : ordinal_finType m, d1 != d2 -> c1 d2 = c2 d2, on_top d1 c1 & on_top d1 c2]
5678f117c1d24924b24c24d173
kE:x = k + n
J1x:r (c1 k) (c2 k)

1ac
5678f117c1d24924b24c24d173257258
xE:tlshift n k = x

1ac
5678f117c1d24924b17325725825d
H3x:on_top (tlshift n k) (cmerge c1 c)
H4x:on_top (tlshift n k) (cmerge c2 c)

1ac
261
forall d2 : ordinal_finType m, k != d2 -> c1 d2 = c2 d2
5678f117c1d24924b17325725825d2622631cb
kDd2:k != d2

95
26b
(x != tlshift n d2 -> cmerge c1 c (tlshift n d2) = cmerge c2 c (tlshift n d2)) -> c1 d2 = c2 d2
5678f117c1d24924b17325725825d2622631cb26c
H:x != tlshift n d2 -> c1 d2 = c2 d2

95
26b
x != tlshift n d2
5678f117c1d24924b17325725825d2622631cb

x == d2 + n -> k == d2
by rewrite kE eqn_add2r. Qed.
242
cdisjoint c1 c -> cdisjoint c2 c -> move c1 c2 -> move (cmerge c1 c) (cmerge c2 c)
280
5678f117c1d
c1Dc:cdisjoint c1 c
c2Dc:cdisjoint c2 c
x:ordinal_finType m
H1x:r (c1 x) (c2 x)
H2x:forall d2 : ordinal_finType m, x != d2 -> c1 d2 = c2 d2
H3x:on_top x c1
H4x:on_top x c2

exists d1 : ordinal_finType (m + n), [/\ r (cmerge c1 c d1) (cmerge c2 c d1), forall d2 : ordinal_finType (m + n), d1 != d2 -> cmerge c1 c d2 = cmerge c2 c d2, on_top d1 (cmerge c1 c) & on_top d1 (cmerge c2 c)]
287
r (cmerge c1 c (tlshift n x)) (cmerge c2 c (tlshift n x))
287
forall d2 : ordinal_finType (m + n), tlshift n x != d2 -> cmerge c1 c d2 = cmerge c2 c d2
287
296
5678f117c1d28828928a28b28c28d28e
d2:ordinal_finType (m + n)
173
d2E:d2 = k + n
H:tlshift n x != d2

1a3
5678f117c1d28828928a28b28d28e29e17329f

tlshift n k == d2
by apply/eqP/val_eqP/eqP. Qed.
5678f1f2f3
cs:seq (configuration m)

path move (cmerge c1 c2) [seq cmerge i c2 | i <- cs] -> path move c1 cs
2a7
by elim: cs c1 => //= c3 cs IH c1 /andP[/move_mergel-> /IH]. Qed.
2a9
all ((cdisjoint (n:=n))^~ c2) (c1 :: cs) -> path move c1 cs -> path move (cmerge c1 c2) [seq cmerge i c2 | i <- cs]
2ae
5678f1f3
c3:configuration m
2aa
IH:forall c1 : configuration m, cdisjoint c1 c2 && all ((cdisjoint (n:=n))^~ c2) cs -> path move c1 cs -> path move (cmerge c1 c2) [seq cmerge i c2 | i <- cs]
f2218
c3Dc2:cdisjoint c3 c2
Dcs:all ((cdisjoint (n:=n))^~ c2) cs

cdisjoint c3 c2 && all ((cdisjoint (n:=n))^~ c2) cs
by rewrite c3Dc2. Qed.
5678f110a
d:disk (m + n)

on_top d c -> match tsplit d with | inl d1 => on_top d1 (clshift c) | inr d2 => on_top d2 (crshift c) end
2bc
2be
on_top (tunsplit (tsplit d)) c -> match tsplit d with | inl d1 => on_top d1 (clshift c) | inr d2 => on_top d2 (crshift c) end
5678f110a2bf16d
dE:d = j
dT:forall d1 : 'I_(m + n), c (trshift m j) = c d1 -> j <= d1
25
H:c (trshift m j) = c (trshift m d1)

j <= d1
5678f110a2bf11f
dE:d = j + n
dT:forall d1 : 'I_(m + n), c (tlshift n j) = c d1 -> j + n <= d1
183
H:c (tlshift n j) = c (tlshift n d1)
2cd
2d0
2cd
by have /= := dT _ H; rewrite leq_add2r. Qed.
5678f1
c1, c2:configuration (m + n)

move c1 c2 -> clshift c1 != clshift c2 -> move (clshift c1) (clshift c2)
2d8
5678f12db249

[/\ r (c1 x) (c2 x), forall d2 : ordinal_finType (m + n), x != d2 -> c1 d2 = c2 d2, on_top x c1 & on_top x c2] -> clshift c1 != clshift c2 -> move (clshift c1) (clshift c2)
2e1
[/\ r (c1 (tunsplit (tsplit x))) (c2 (tunsplit (tsplit x))), forall d2 : ordinal_finType (m + n), tunsplit (tsplit x) != d2 -> c1 d2 = c2 d2, on_top (tunsplit (tsplit x)) c1 & on_top (tunsplit (tsplit x)) c2] -> clshift c1 != clshift c2 -> move (clshift c1) (clshift c2)
2e1
(on_top x c1 -> match tsplit x with | inl d1 => on_top d1 (clshift c1) | inr d2 => on_top d2 (crshift c1) end) -> [/\ r (c1 (tunsplit (tsplit x))) (c2 (tunsplit (tsplit x))), forall d2 : ordinal_finType (m + n), tunsplit (tsplit x) != d2 -> c1 d2 = c2 d2, on_top (tunsplit (tsplit x)) c1 & on_top (tunsplit (tsplit x)) c2] -> clshift c1 != clshift c2 -> move (clshift c1) (clshift c2)
2e1
(on_top x c2 -> match tsplit x with | inl d1 => on_top d1 (clshift c2) | inr d2 => on_top d2 (crshift c2) end) -> (on_top x c1 -> match tsplit x with | inl d1 => on_top d1 (clshift c1) | inr d2 => on_top d2 (crshift c1) end) -> [/\ r (c1 (tunsplit (tsplit x))) (c2 (tunsplit (tsplit x))), forall d2 : ordinal_finType (m + n), tunsplit (tsplit x) != d2 -> c1 d2 = c2 d2, on_top (tunsplit (tsplit x)) c1 & on_top (tunsplit (tsplit x)) c2] -> clshift c1 != clshift c2 -> move (clshift c1) (clshift c2)
5678f12db24916d
xE:x = j
c2H:on_top x c2 -> on_top j (crshift c2)
c1H:on_top x c1 -> on_top j (crshift c1)
H1j:r (c1 (trshift m j)) (c2 (trshift m j))
H2j:forall d2 : 'I_(m + n), trshift m j != d2 -> c1 d2 = c2 d2
H3j:on_top (trshift m j) c1
H4j:on_top (trshift m j) c2
c1Dc2:clshift c1 != clshift c2

move (clshift c1) (clshift c2)
5678f12db249173
xE:x = k + n
c2H:on_top x c2 -> on_top k (clshift c2)
c1H:on_top x c1 -> on_top k (clshift c1)
H1k:r (c1 (tlshift n k)) (c2 (tlshift n k))
H2k:forall d2 : 'I_(m + n), tlshift n k != d2 -> c1 d2 = c2 d2
H3k:on_top (tlshift n k) c1
H4k:on_top (tlshift n k) c2
2fa
2fb
5678f12db24916d2f32f42f52f62f72f82f9fb

clshift c1 i = clshift c2 i
2fc
309
c1 (tlshift n i) = c2 (tlshift n i)
2fc
309
~~ (j <= i + n) || ~~ (i + n <= j)
2fc
2fe
2fb
5678f12db2491732ff3003013023033043052fa1cb26c

c1 (tlshift n d2) = c2 (tlshift n d2)
2fe
on_top k (clshift c1)
2fe
on_top k (clshift c2)
317
5678f12db2491732ff3003013023043052fa1cb26c

tlshift n k != tlshift n d2
31b
2fe
31d
31e
327
5678f12db2491732ff3003023033043052fa

x = tlshift n k
329
2fe
31f
5678f12db2491732ff3013023033043052fa

32f
by apply/val_eqP/eqP => /=. Qed.
2da
move c1 c2 -> crshift c1 != crshift c2 -> move (crshift c1) (crshift c2)
338
2e1
[/\ r (c1 x) (c2 x), forall d2 : ordinal_finType (m + n), x != d2 -> c1 d2 = c2 d2, on_top x c1 & on_top x c2] -> crshift c1 != crshift c2 -> move (crshift c1) (crshift c2)
2e1
[/\ r (c1 (tunsplit (tsplit x))) (c2 (tunsplit (tsplit x))), forall d2 : ordinal_finType (m + n), tunsplit (tsplit x) != d2 -> c1 d2 = c2 d2, on_top (tunsplit (tsplit x)) c1 & on_top (tunsplit (tsplit x)) c2] -> crshift c1 != crshift c2 -> move (crshift c1) (crshift c2)
2e1
(on_top x c1 -> match tsplit x with | inl d1 => on_top d1 (clshift c1) | inr d2 => on_top d2 (crshift c1) end) -> [/\ r (c1 (tunsplit (tsplit x))) (c2 (tunsplit (tsplit x))), forall d2 : ordinal_finType (m + n), tunsplit (tsplit x) != d2 -> c1 d2 = c2 d2, on_top (tunsplit (tsplit x)) c1 & on_top (tunsplit (tsplit x)) c2] -> crshift c1 != crshift c2 -> move (crshift c1) (crshift c2)
2e1
(on_top x c2 -> match tsplit x with | inl d1 => on_top d1 (clshift c2) | inr d2 => on_top d2 (crshift c2) end) -> (on_top x c1 -> match tsplit x with | inl d1 => on_top d1 (clshift c1) | inr d2 => on_top d2 (crshift c1) end) -> [/\ r (c1 (tunsplit (tsplit x))) (c2 (tunsplit (tsplit x))), forall d2 : ordinal_finType (m + n), tunsplit (tsplit x) != d2 -> c1 d2 = c2 d2, on_top (tunsplit (tsplit x)) c1 & on_top (tunsplit (tsplit x)) c2] -> crshift c1 != crshift c2 -> move (crshift c1) (crshift c2)
5678f12db2491732ff300301302303304305
c1Dc2:crshift c1 != crshift c2

move (crshift c1) (crshift c2)
5678f12db24916d2f32f42f52f62f72f82f9350
351
5678f12db2491732ff300301302303304305
i:ordinal_finType n

crshift c1 i = crshift c2 i
352
358
c1 (trshift m i) = c2 (trshift m i)
352
358
~~ (k + n <= i) || ~~ (i <= k + n)
352
354
351
5678f12db24916d2f32f42f52f62f72f82f93501581cc

c1 (trshift m d2) = c2 (trshift m d2)
354
on_top j (crshift c1)
354
on_top j (crshift c2)
367
354
36d
36e
372
5678f12db24916d2f32f42f62f72f82f9350

x = trshift m j
374
354
36f
5678f12db24916d2f32f52f62f72f82f9350

37a
by apply/val_eqP/eqP => /=. Qed. Fixpoint rm_rep (A : eqType) (a : A) (s : seq A) := if s is b :: s1 then if a == b then rm_rep b s1 else b :: rm_rep b s1 else [::].
5678
A:eqType
a:A
s:seq A

subseq (rm_rep a s) s
383
5678386
b:A
388
IH:forall a : A, subseq (rm_rep a s) s
387

subseq (rm_rep a (b :: s)) (b :: s)
38e
subseq (rm_rep b s) (b :: s)
38e
subseq (b :: rm_rep b s) (b :: s)
38e
398
by rewrite /= eqxx IH. Qed.
385
{subset rm_rep a s <= s}
39d
by apply/mem_subseq/subseq_rm_rep. Qed.
385
size (rm_rep a s) <= size s
3a2
by apply/size_subseq/subseq_rm_rep. Qed.
5678386
a, b:A
388

size (rm_rep b s) <= size (rm_rep a (b :: s))
3a7
by rewrite /=; case: (_ == _) => //=. Qed.
5678
A:finType
387
s1:{set A}
s2:seq A

{subset s1 <= s2} -> a \notin s1 -> #|s1| <= size (rm_rep a s2)
3ae
56783b13b2387
aS:{subset s1 <= [::]}

#|s1| <= 0
56783b138f3b3
IH:forall (s1 : {set A}) (a : A), {subset s1 <= s2} -> a \notin s1 -> #|s1| <= size (rm_rep a s2)
3b2387
s1S:{subset s1 <= b :: s2}
aNIs1:a \notin s1
#|s1| <= size (if a == b then rm_rep b s2 else b :: rm_rep b s2)
56783b13b23873ba
i:A

(i \in s1) = (i \in set0)
3bc
3be
3c2
56783b138f3b33bf3b23873c03c1
aEb:a = b

#|s1| <= size (rm_rep b s2)
56783b138f3b33bf3b23873c03c1
aDb:a <> b
#|s1| <= size (b :: rm_rep b s2)
56783b138f3b33b23873c03c13d0

{subset s1 <= s2}
3d2
56783b138f3b33b23873c03c13d03c7
is1:i \in s1

(i == b) || (i \in s2) -> i \in s1 -> i \in s2
3d2
3d4
3d6
56783b138f3b33bf3b23873c03c13d5
bNIs1:b \notin s1

#|s1| <= (size (rm_rep b s2)).+1
56783b138f3b33bf3b23873c03c13d5
bIs1:b \in s1
3ea
3e8
3db
3eb
56783b138f3b33bf3b23873c03c13d53e93c73e0

3e1
3eb
3ed
3ea
3ed
#|s1 :\ b| <= size (rm_rep b s2)
56783b138f3b33b23873c03c13d53ee3c7

i \in s1 :\ b -> i \in s2
56783b138f3b33b23873c03c13d53ee
b \notin s1 :\ b
404
405
by rewrite !inE eqxx. Qed.
385
last a (rm_rep a s) = last a s
40a
by elim: s a => //= b l IH a; case: (_ =P _) => /= [->|_]; apply: IH. Qed.
5678386387
s1, s2:seq A

rm_rep a (s1 ++ s2) = rm_rep a s1 ++ rm_rep (last a s1) s2
40f
567838638f
s1:seq A
IH:forall (s2 : seq A) (a : A), rm_rep a (s1 ++ s2) = rm_rep a s1 ++ rm_rep (last a s1) s2
3b3387

(if a == b then rm_rep b (s1 ++ s2) else b :: rm_rep b (s1 ++ s2)) = (if a == b then rm_rep b s1 else b :: rm_rep b s1) ++ rm_rep (last b s1) s2
567838638f41941a3b33873d5

b :: rm_rep b (s1 ++ s2) = b :: rm_rep b s1 ++ rm_rep (last b s1) s2
by congr (_ :: _); apply: IH. Qed.
56783863aa
s:seq_predType A

b != a -> b \in s -> b \in rm_rep a s
422
5678386
b, c:A
388
IH:forall a : A, b != a -> b \in s -> b \in rm_rep a s
387
bDa:b != a

(b == c) || (b \in s) -> b \in (if a == c then rm_rep c s else c :: rm_rep c s)
42b
b \in (if a == b then rm_rep b s else b :: rm_rep b s)
567838642c38842d38742e
bDc:b != c
bIs:b \in s
b \in (if a == c then rm_rep c s else c :: rm_rep c s)
436
439
by have := IH _ bDc bIs; case: (_ == _); rewrite // inE orbC => ->. Qed.
5678f110a
cs:seq (configuration (m + n))

path move c cs -> path move (clshift c) (rm_rep (clshift c) [seq clshift i | i <- cs])
43e
5678f1
c1:configuration (m + n)
441
IH:forall c : configuration (m + n), path move c cs -> path move (clshift c) (rm_rep (clshift c) [seq clshift i | i <- cs])
10a
cMc1:move c c1
c1Pcs:path move c1 cs

path move (clshift c) (if clshift c == clshift c1 then rm_rep (clshift c1) [seq clshift i | i <- cs] else clshift c1 :: rm_rep (clshift c1) [seq clshift i | i <- cs])
5678f144844144910a44a44b
cDc1:clshift c != clshift c1

move (clshift c) (clshift c1) && path move (clshift c1) (rm_rep (clshift c1) [seq clshift i | i <- cs])
by rewrite move_clshift //=; apply: IH. Qed.
440
path move c cs -> path move (crshift c) (rm_rep (crshift c) [seq crshift i | i <- cs])
454
5678f1448441
IH:forall c : configuration (m + n), path move c cs -> path move (crshift c) (rm_rep (crshift c) [seq crshift i | i <- cs])
10a44a44b

path move (crshift c) (if crshift c == crshift c1 then rm_rep (crshift c1) [seq crshift i | i <- cs] else crshift c1 :: rm_rep (crshift c1) [seq crshift i | i <- cs])
5678f144844145c10a44a44b
cDc1:crshift c != crshift c1

move (crshift c) (crshift c1) && path move (crshift c1) (rm_rep (crshift c1) [seq crshift i | i <- cs])
by rewrite move_crshift //=; apply: IH. Qed.
440
path move c cs -> size cs = size (rm_rep (clshift c) [seq clshift i | i <- cs]) + size (rm_rep (crshift c) [seq crshift i | i <- cs])
465
5678f1448441
IH:forall c : configuration (m + n), path move c cs -> size cs = size (rm_rep (clshift c) [seq clshift i | i <- cs]) + size (rm_rep (crshift c) [seq crshift i | i <- cs])
10a167
d2H:r (c d) (c1 d)
d2H1:forall d2 : ordinal_finType (m + n), d != d2 -> c d2 = c1 d2
d2H2:on_top d c
d2H3:on_top d c1
44b

(size cs).+1 = size (if clshift c == clshift c1 then rm_rep (clshift c1) [seq clshift i | i <- cs] else clshift c1 :: rm_rep (clshift c1) [seq clshift i | i <- cs]) + size (if crshift c == crshift c1 then rm_rep (crshift c1) [seq crshift i | i <- cs] else crshift c1 :: rm_rep (crshift c1) [seq crshift i | i <- cs])
5678f144844146d10a16746e46f47047144b16d2ca

472
5678f144844146d10a16746e46f47047144b173
dE:d = k + n
472
476
clshift c == clshift c1
476
(size cs).+1 = size (rm_rep (clshift c1) [seq clshift i | i <- cs]) + size (if crshift c == crshift c1 then rm_rep (crshift c1) [seq crshift i | i <- cs] else crshift c1 :: rm_rep (crshift c1) [seq crshift i | i <- cs])
478
5678f144844146d10a16746e46f47047144b16d2cafb

c (tlshift n i) = c1 (tlshift n i)
47f
5678f144844146d10a16746e47047144b16d2cafb

d == i + n -> False
47f
476
481
477
476
crshift c != crshift c1
476
(size cs).+1 = size (rm_rep (clshift c1) [seq clshift i | i <- cs]) + (size (rm_rep (crshift c1) [seq crshift i | i <- cs])).+1
478
5678f144844146d10a16746e46f47047144b16d2ca
cE:c (trshift m j) = c1 (trshift m j)

False
493
5678f144844146d10a16746f47047144b16d2ca49a

c d = c1 d
493
476
495
477
476
size cs = size (rm_rep (clshift c1) [seq clshift i | i <- cs]) + size (rm_rep (crshift c1) [seq crshift i | i <- cs])
477
479
472
479
clshift c != clshift c1
479
(size cs).+1 = (size (rm_rep (clshift c1) [seq clshift i | i <- cs])).+1 + size (if crshift c == crshift c1 then rm_rep (crshift c1) [seq crshift i | i <- cs] else crshift c1 :: rm_rep (crshift c1) [seq crshift i | i <- cs])
5678f144844146d10a16746e46f47047144b17347a
cE:c (tlshift n k) = c1 (tlshift n k)

49b
4af
5678f144844146d10a16746f47047144b17347a4b6

4a0
4af
479
4b1
479
crshift c == crshift c1
479
(size cs).+1 = (size (rm_rep (clshift c1) [seq clshift i | i <- cs])).+1 + size (rm_rep (crshift c1) [seq crshift i | i <- cs])
5678f144844146d10a16746e46f47047144b17347a359

c (trshift m i) = c1 (trshift m i)
4c2
5678f144844146d10a16746e47047144b17347a359

d == i -> False
4c2
479
4c4
479
size cs = (fix add (n m : nat) {struct n} : nat := match n with | 0 => m | p.+1 => (add p m).+1 end) (size (rm_rep (clshift c1) [seq clshift i | i <- cs])) (size (rm_rep (crshift c1) [seq crshift i | i <- cs]))
by apply: IH. Qed.
5678
n, m:nat
2db

connect move c1 c2 -> `d[clshift c1, clshift c2]_move <= `d[c1, c2]_move
4d7
56784da2db
p:seq (finfun_finType (ordinal_finType (m + n)) (ordinal_finType q))
pH:gpath move c1 c2 p

`d[clshift c1, clshift c2]_move <= `d[c1, c2]_move
4e0
size (rm_rep (clshift c1) [seq clshift i | i <- p]) <= size [seq clshift i | i <- p] -> `d[clshift c1, clshift c2]_move <= `d[c1, c2]_move
4e0
`d[clshift c1, clshift c2]_move <= size (rm_rep (clshift c1) [seq clshift i | i <- p])
4e0
last (clshift c1) (rm_rep (clshift c1) [seq clshift i | i <- p]) = clshift c2
by rewrite last_rm_rep last_map (gpath_last pH). Qed.
4d9
connect move c1 c2 -> `d[crshift c1, crshift c2]_move <= `d[c1, c2]_move
4f1
4e0
`d[crshift c1, crshift c2]_move <= `d[c1, c2]_move
4e0
size (rm_rep (crshift c1) [seq crshift i | i <- p]) <= size [seq crshift i | i <- p] -> `d[crshift c1, crshift c2]_move <= `d[c1, c2]_move
4e0
`d[crshift c1, crshift c2]_move <= size (rm_rep (crshift c1) [seq crshift i | i <- p])
4e0
last (crshift c1) (rm_rep (crshift c1) [seq crshift i | i <- p]) = crshift c2
by rewrite last_rm_rep last_map (gpath_last pH). Qed.
4d9
connect move c1 c2 -> `d[clshift c1, clshift c2]_move + `d[crshift c1, crshift c2]_move <= `d[c1, c2]_move
506
4e0
`d[clshift c1, clshift c2]_move + `d[crshift c1, crshift c2]_move <= `d[c1, c2]_move
4e0
`d[clshift c1, clshift c2]_move + `d[crshift c1, crshift c2]_move <= size (rm_rep (clshift c1) [seq clshift i | i <- p]) + size (rm_rep (crshift c1) [seq crshift i | i <- p])
4ea
4e0500
4ee514
4fe
501 by rewrite last_rm_rep last_map (gpath_last pH). Qed. Definition cliftrn m n p (c : configuration n) : configuration (m + n) := cmerge `c[p] c. Definition cliftr n : _ -> _ -> configuration n.+1 := @cliftrn 1 n. Notation " ↑[ c ]_ p" := (cliftr p c) (at level 5, format "↑[ c ]_ p"). Definition cliftln m n p (c : configuration m) : configuration (m + n) := cmerge c `c[p]. Definition cliftl n c p : configuration (n + 1) := (@cliftln n 1 c p).
56781b
p:peg
1d

↑[c]_p ldisk = p
51a
56781b51d1d16d
nE:n = j

c j = p
56781b51d1d
t:'I_1
n = t + n -> `c[p] t = p
528
52a
by rewrite ffunE. Qed.
56784da51d1491d

on_top (trshift m x) (cliftrn m p c) = on_top x c
52f
exact: on_top_merger. Qed.
56784da51d34

move (cliftrn m p c1) (cliftrn m p c2) = move c1 c2
535
exact: move_merger. Qed.
56784da51d1d1e3

path move (cliftrn m p c) [seq cliftrn m p i | i <- cs] = path move c cs
53b
exact: path_merger. Qed.
537
connect move c1 c2 -> connect move (cliftrn m p c1) (cliftrn m p c2)
541
exact: connect_merger. Qed.
537
connect move c1 c2 -> `d[cliftrn m p c1, cliftrn m p c2]_move <= `d[c1, c2]_move
546
exact: gdist_merger. Qed.
56781b51d34

move ↑[c1]_p ↑[c2]_p = move c1 c2
54b
by exact: move_liftrn 1 p c1 c2. Qed.
56781b51d

↑[`c[p]]_p = `c[p]
551
56781b51d
i:ordinal_finType n.+1

match tsplit i with | inl j => `c[p] j | inr j => `c[p] j end = p
by case: tsplitP => [j|k]; rewrite !ffunE. Qed. Definition cunliftr {n} (c : configuration n.+1) : configuration n := @crshift 1 n c. Notation " ↓[ c ]" := (cunliftr c) (at level 5, format "↓[ c ]").
553
cancel (cliftr p) (cunliftr : configuration n.+1 -> configuration n)
55d
by move=> c; apply/ffunP => i; rewrite !ffunE tsplit_trshift. Qed.
56781b
c:configuration n.+1

↑[↓[c]]_(c ldisk) = c
562
56781b56555a

match tsplit i with | inl j => `c[c ldisk] j | inr j => ↓[c] j end = c i
56781b56555a
j:'I_1
iE:i = j + n

n = i
by rewrite iE; case: (j) => [] []. Qed.
553
injective (cliftr p)
575
by move=> c1 c2 c1Ec2; rewrite -[c1](cliftrK p) c1Ec2 cliftrK. Qed.
5678
T1, T2:eqType
f:T1 -> T2
s1, s2:seq T1

injective f -> ([seq f i | i <- s1] == [seq f i | i <- s2]) = (s1 == s2)
57a
567857d57e
a:T1
s1:seq T1
IH:forall s2 : seq T1, injective f -> ([seq f i | i <- s1] == [seq f i | i <- s2]) = (s1 == s2)
b:T1
s2:seq T1
fInj:injective f

(f a :: [seq f i | i <- s1] == f b :: [seq f i | i <- s2]) = (a :: s1 == b :: s2)
585
(f a == f b) && (s1 == s2) = (a == b) && (s1 == s2)
585
a <> b -> (f a == f b) && (s1 == s2) = false && (s1 == s2)
by case: (f a =P f b) => [/fInj|//]. Qed.
56781b51d
cs1, cs2:seq (configuration n)

([seq ↑[i]_p | i <- cs1] == [seq ↑[i]_p | i <- cs2]) = (cs1 == cs2)
596
by apply/map_eqr/cliftr_inj. Qed.
553
↓[`c[p]] = `c[p]
59d
by apply/ffunP => i; rewrite !ffunE. Qed.
56781b56551d

s2f ([set i | c i == p] :\ ord_max) = s2f [set i | ↓[c] i == p]
5a2
56781b56551d
i:nat_choiceType

(i \in s2f ([set i | c i == p] :\ ord_max)) = (i \in s2f [set i | ↓[c] i == p])
56781b56551d5ab
j:'I_n.+1

j \in [set i | c i == p] :\ ord_max -> i = j -> exists2 x : 'I_n, x \in [set i | ↓[c] i == p] & i = x
56781b56551d5ab16d
j \in [set i | ↓[c] i == p] -> i = j -> exists2 x : 'I_n.+1, x \in [set i | c i == p] :\ ord_max & i = x
56781b56551d5ab5b1
jDn:j != ord_max
cjEp:c j = p
jEi:i = j

exists2 x : 'I_n, x \in [set i | ↓[c] i == p] & i = x
5b3
5ba
j < n
56781b56551d5ab5b15bb5bc5bd
jLn:j < n
5be
5b4
56781b56551d5ab5b15bc5bd
jDn:j != n

5c2
5c3
5c5
5be
5b3
5c5
c (trshift 1 (Ordinal jLn)) = p
5b3
5b5
5b6
56781b56551d5ab16d
cjEp:c (trshift 1 j) = p
iEj:i = j

trshift 1 j \in [set i | c i == p] :\ ord_max
by rewrite !inE cjEp -val_eqE //= neq_ltn ltn_ord /=. Qed.
56781b565
s:seq peg

codom c \subset s -> codom ↓[c] \subset s
5de
56781b5655e1
H:codom c \subset s
i:ordinal_finType q
fc

↓[c] j \in s
by rewrite ffunE; apply: (subsetP H); apply: codom_f. Qed.
56781b
c1, c2:configuration n.+1

move c1 c2 -> c1 ldisk != c2 ldisk -> ↓[c1] = ↓[c2]
5ec
56781b5efad
c10Dc20:c1 ldisk != c2 ldisk

↓[c1] = ↓[c2]
56781b5efad5f6359

c1 (trshift 1 i) = c2 (trshift 1 i)
56781b5ef359

ldisk != trshift 1 i
600
n != i
by rewrite eqn_leq negb_and -ltnNge ltn_ord. Qed.
5ee
c1 ldisk = c2 ldisk -> move ↓[c1] ↓[c2] = move c1 c2
607
by move=> c1lEc2l; rewrite -(@move_liftr _ (c1 ldisk)) {2}c1lEc2l !cunliftrK. Qed.
56781b1d1e3

path move (last c cs) (rev (belast c cs)) = path move c cs
60c
by rewrite rev_path; apply: eq_path => c1 c2; exact: move_sym. Qed.
56781b51d1d1e3

path move ↑[c]_p [seq ↑[i]_p | i <- cs] = path move c cs
612
by apply: (@path_merger 1). Qed.
54d
connect move c1 c2 -> connect move ↑[c1]_p ↑[c2]_p
618
by apply: (@connect_merger 1). Qed.
54d
connect move c1 c2 -> `d[↑[c1]_p, ↑[c2]_p]_move <= `d[c1, c2]_move
61d
by apply: (@gdist_merger 1). Qed.
56781b565
cs:seq (configuration n.+1)

(forall c1 : finfun_eqType (ordinal_finType n.+1) (ordinal_eqType q), c1 \in cs -> c1 ldisk = c ldisk) -> path move ↓[c] [seq ↓[i] | i <- cs] = path move c cs
622
56781b565625
H:forall c1 : finfun_eqType (ordinal_finType n.+1) (ordinal_eqType q), c1 \in cs -> c1 ldisk = c ldisk

path move ↓[c] [seq ↓[i] | i <- cs] = path move c cs
62b
path move ↑[↓[c]]_(c ldisk) [seq ↑[i]_(c ldisk) | i <- [seq ↓[i] | i <- cs]] = path move c cs
62b
path move c [seq ([eta cliftr (c ldisk)] \o [eta cunliftr]) i | i <- cs] = path move c cs
62b
[seq ([eta cliftr (c ldisk)] \o [eta cunliftr]) i | i <- cs] = cs
56781b
c, a:configuration n.+1
625
IH:(forall c1 : {ffun 'I_n.+1 -> 'I_q}, c1 \in cs -> c1 ldisk = c ldisk) -> [seq ([eta cliftr (c ldisk)] \o [eta cunliftr]) i | i <- cs] = cs
H:forall c1 : {ffun 'I_n.+1 -> 'I_q}, c1 \in a :: cs -> c1 ldisk = c ldisk

↑[↓[a]]_(c ldisk) :: [seq ([eta cliftr (c ldisk)] \o [eta cunliftr]) i | i <- cs] = a :: cs
63d
↑[↓[a]]_(a ldisk) :: [seq ([eta cliftr (c ldisk)] \o [eta cunliftr]) i | i <- cs] = a :: cs
63d
a \in a :: cs
63d
648
by rewrite inE eqxx. Qed.
624
path move c cs -> path move ↓[c] (rm_rep ↓[c] [seq ↓[i] | i <- cs])
64d
by move=> H; apply: path_crshift. Qed.
5ee
connect move c1 c2 -> `d[↓[c1], ↓[c2]]_move <= `d[c1, c2]_move
652
by move=> H; apply: gdist_crshift. Qed.
5ee
irreflexive r -> connect move c1 c2 -> c1 ldisk = c2 ldisk -> `d[c1, c2]_move = `d[↓[c1], ↓[c2]]_move
657
56781b5ef
ir:irreflexive r
c1Cc2:connect move c1 c2
c1Ec2:c1 ldisk = c2 ldisk

`d[c1, c2]_move <= `d[↓[c1], ↓[c2]]_move
65e
`d[↑[↓[c1]]_(c1 ldisk), ↑[↓[c2]]_(c1 ldisk)]_move <= `d[↓[c1], ↓[c2]]_move
65e
connect move ↓[c1] ↓[c2]
56781b5ef65f661
p:seq (finfun_finType (ordinal_finType n.+1) (ordinal_finType q))
pH:path move c1 p
c2E:c2 = last c1 p

66a
66e
path move ↓[c1] (rm_rep ↓[c1] [seq ↓[i] | i <- p])
66e
↓[c2] = last ↓[c1] (rm_rep ↓[c1] [seq ↓[i] | i <- p])
66e
678
by rewrite last_rm_rep c2E last_map. Qed.
5678f151d

cliftrn m p `c[p] = `c[p]
67d
by apply/ffunP => i; rewrite !ffunE; case: tsplitP => j; rewrite !ffunE. Qed. (* case distinction that depends if the largest disk has move *) (* if it has not moved, we get the path on the unlifted configuration *) (* uf it has moved, we get the decomposition till the first move *) Inductive pathS_spec (n : nat) (c : configuration n.+1) (cs : seq (configuration n.+1)) : forall (b : bool), Type := pathS_specW : forall (p := c ldisk) (c1 := ↓[c]) (cs1 := [seq ↓[i] | i <- cs]), cs = [seq ↑[i]_p | i <- cs1] -> path move c1 cs1 -> pathS_spec c cs true | pathS_spec_move : forall (p1 := c ldisk) p2 cs1 cs2 (c1 := ↓[c]) (c2 := ↑[last c1 cs1]_p2), p1 != p2 -> r p1 p2 -> cs = [seq ↑[i]_p1 | i <- cs1] ++ c2 :: cs2 -> path move c1 cs1 -> move ↑[last c1 cs1]_p1 c2 -> path move c2 cs2 -> pathS_spec c cs true | pathS_spec_false : pathS_spec c cs false. (* Inversion theorem on a path for disk n.+1 *)
624
pathS_spec c cs (path move c cs)
683
56781b565625
Hp:path move c cs

pathS_spec c cs true
56781b56562568b
f:=fun c1 : configuration n.+1 => c1 ldisk != c ldisk:configuration n.+1 -> bool

68c
56781b56562568b691
Hn:{in cs, forall x : finfun_eqType (ordinal_finType n.+1) (ordinal_eqType q), ~~ f x}

68c
56781b56562568b691
Hh:has f cs
68c
695
cs = [seq ↑[i]_(c ldisk) | i <- [seq ↓[i] | i <- cs]]
56781b56562568b691696
csE:cs = [seq ↑[i]_(c ldisk) | i <- [seq ↓[i] | i <- cs]]
68c
698
695
[seq x | x <- cs] = [seq ([eta cliftr (c ldisk)] \o [eta cunliftr]) i | i <- cs]
69f
56781b56562568b691696
x:finfun_eqType (ordinal_finType n.+1) (ordinal_eqType q)

x = ↑[↓[x]]_(x ldisk)
69f
6a1
68c
697
695
path move ↓[c] [seq ↓[i] | i <- cs]
697
699
68c
56781b56562568b69169a
n1:=find f cs:nat
lc1:=nth c cs n1:configuration n.+1

68c
56781b56562568b69169a6bb6bc
p1:=c ldisk:(fun=> peg) ldisk
p2:=lc1 ldisk:(fun=> peg) ldisk

68c
6c0
p1 != p2
56781b56562568b69169a6bb6bc6c16c2
p1Dp2:p1 != p2
68c
6c9
68c
56781b56562568b69169a6bb6bc6c16c26ca
c1:=↓[c]:configuration n

68c
56781b56562568b69169a6bb6bc6c16c26ca6d2
lcs1:=take n1 cs:seq (configuration n.+1)
cs2:=drop n1.+1 cs:seq (configuration n.+1)

68c
56781b56562568b69169a6bb6bc6c16c26ca6d26d76d8
slcs1:size lcs1 = n1

68c
56781b56562568b69169a6bb6bc6c16c26ca6d26d76d86dd
c2:finfun_eqType (ordinal_finType n.+1) (ordinal_eqType q)

c2 \in lcs1 -> c2 ldisk = p1
56781b56562568b69169a6bb6bc6c16c26ca6d26d76d86dd
Plcs1:forall c2 : finfun_eqType (ordinal_finType n.+1) (ordinal_eqType q), c2 \in lcs1 -> c2 ldisk = p1
68c
56781b56562568b69169a6bb6bc6c16c26ca6d26d76d86dd6e2
c2Ilcs1p:c2 \in lcs1

6e3
6e4
6eb
~~ f (nth c cs (index c2 lcs1)) -> c2 ldisk = p1
6e4
6eb
nth c cs (index c2 lcs1) ldisk = c ldisk -> c2 ldisk = p1
6e4
6e6
68c
56781b56562568b69169a6bb6bc6c16c26ca6d26d76d86dd6e7
cs1:=[seq ↓[i] | i <- lcs1]:seq (configuration n)

68c
6fb
lcs1 = [seq ↑[i]_p1 | i <- cs1]
56781b56562568b69169a6bb6bc6c16c26ca6d26d76d86dd6e76fc
lcs1E:lcs1 = [seq ↑[i]_p1 | i <- cs1]
68c
6fb
[seq x | x <- lcs1] = [seq ([eta cliftr p1] \o cunliftr) i | i <- lcs1]
701
56781b56562568b69169a6bb6bc6c16c26ca6d26d76d86dd6e76fc6ab
H:x ldisk = p1

x = ([eta cliftr p1] \o cunliftr) x
701
703
68c
703
cs = [seq ↑[i]_p1 | i <- cs1] ++ lc1 :: cs2
56781b56562568b69169a6bb6bc6c16c26ca6d26d76d86dd6e76fc704
csE:cs = [seq ↑[i]_p1 | i <- cs1] ++ lc1 :: cs2
68c
718
68c
718
move (last c lcs1) lc1
56781b56562568b69169a6bb6bc6c16c26ca6d26d76d86dd6e76fc704719
Hm:move (last c lcs1) lc1
68c
723
68c
723
lc1 = ↑[last c1 cs1]_p2
56781b56562568b69169a6bb6bc6c16c26ca6d26d76d86dd6e76fc704719724
lc1E:lc1 = ↑[last c1 cs1]_p2
68c
723
lc1 = ↑[last c1 cs1]_(lc1 ldisk)
72c
723
last c lcs1 ldisk != lc1 ldisk
56781b56562568b69169a6bb6bc6c16c26ca6d26d76d86dd6e76fc704719724
Hd:last c lcs1 ldisk != lc1 ldisk
733
72d
56781b56562568b69169a6bb6bc6c16c26ca6d26d76d86dd6fc704719724
a:configuration n.+1
l:seq (configuration n.+1)

last a l \in a :: l
738
73a
733
72c
73a
↑[↓[lc1]]_(lc1 ldisk) = ↑[↓[last c lcs1]]_(lc1 ldisk)
72c
73a
↓[lc1] = ↓[last c lcs1]
72c
56781b56562568b69169a6bb6bc6c16c26ca6d26d76d86dd6e76fc70471972473b359

lc1 (trshift 1 i) = last c lcs1 (trshift 1 i)
72c
751
601
72c
751
605
72c
72e
68c
72e
move ↑[last c1 cs1]_p1 ↑[last c1 cs1]_p2
56781b56562568b69169a6bb6bc6c16c26ca6d26d76d86dd6e76fc70471972472f
Hm1:move ↑[last c1 cs1]_p1 ↑[last c1 cs1]_p2
68c
72e
↑[last ↓[c] cs1]_p1 = last c lcs1
72e
move (last c lcs1) ↑[last c1 cs1]_p2
761
72e
76a
760
762
68c
762
r (c ldisk) p2
762
cs = [seq ↑[i]_(c ldisk) | i <- cs1] ++ ↑[last ↓[c] cs1]_p2 :: ?Goal
762
path move ↓[c] cs1
762
path move ↑[last ↓[c] cs1]_p2 ?Goal
772
762
(↑[last c1 cs1]_p1 ldisk != ↑[last c1 cs1]_p2 ldisk -> r (↑[last c1 cs1]_p1 ldisk) (↑[last c1 cs1]_p2 ldisk)) -> r (c ldisk) p2
775
762
777
77877a
782
762
779
762
path move ↑[last ↓[c] cs1]_p2 cs2
787
762
path move c lcs1
789
762
78b
762
path move lc1 cs2
by move: Hp; rewrite csE cat_path /= => /and3P[]. Qed. (* we can restrict a path from n.+1 to n by removing all the moves of the *) (* largest disk *)
624
path move c cs -> {cs' : seq (configuration n) | [/\ path move ↓[c] cs', last ↓[c] cs' = ↓[last c cs] & size cs' <= size cs ?= iff (cs == [seq ↑[i]_(c ldisk) | i <- cs'])]}
799
564
{cs' : seq (configuration n) | [/\ path move ↓[c] cs', last ↓[c] cs' = ↓[c] & size cs' <= 0 ?= iff ([::] == [seq ↑[i]_(c ldisk) | i <- cs'])]}
56781b
c1:configuration n.+1
625
IH:forall c : configuration n.+1, path move c cs -> {cs' : seq (configuration n) | [/\ path move ↓[c] cs', last ↓[c] cs' = ↓[last c cs] & size cs' <= size cs ?= iff (cs == [seq ↑[i]_ (c ldisk) | i <- cs'])]}
56544a
cs1:seq (configuration n)
c1Pcs1:path move ↓[c1] cs1
lccs1Mlc1cs:last ↓[c1] cs1 = ↓[last c1 cs]
S:size cs1 <= size cs ?= iff (cs == [seq ↑[i]_(c1 ldisk) | i <- cs1])
{cs' : seq (configuration n) | [/\ path move ↓[c] cs', last ↓[c] cs' = ↓[last c1 cs] & size cs' <= (size cs).+1 ?= iff (c1 :: cs == [seq ↑[i]_(c ldisk) | i <- cs'])]}
7a3
7aa
56781b7a46257a556544a7a67a77a87a9
c1dEcd:c ldisk = c1 ldisk

7aa
56781b7a46257a556544a7a67a77a87a9
c1dDcd:c ldisk != c1 ldisk
7aa
7b1
move ↓[c] ↓[c1] && path move ↓[c1] cs1
7b1
(size cs1).+1 <= (size cs).+1 ?= iff (c1 :: cs == ↑[↓[c1]]_ (c ldisk) :: [ seq ↑[i]_ (c ldisk) | i <- cs1])
7b4
7b1
(size cs1).+1 <= (size cs).+1 ?= iff (c1 :: cs == ↑[↓[c1]]_(c ldisk) :: [seq ↑[i]_(c ldisk) | i <- cs1])
7b3
7b5
7aa
7b5
{cs' : seq (configuration n) | [/\ path move ↓[c1] cs', last ↓[c1] cs' = ↓[last c1 cs] & size cs' <= (size cs).+1 ?= iff (c1 :: cs == [seq ↑[i]_(c ldisk) | i <- cs'])]}
7b5
size cs1 <= (size cs).+1 ?= iff (c1 :: cs == [seq ↑[i]_(c ldisk) | i <- cs1])
56781b7a46257a556544a7a67a77a87a97b6
H:c1 :: cs = [seq ↑[i]_(c ldisk) | i <- cs1]

size cs1 == (size cs).+1
by rewrite -[_.+1]/(size (c1 :: cs)) H size_map. Qed. (* we can restrict a path from n.+1 to n *)
56781b565
c1:finfun_eqType (ordinal_finType n.+1) (ordinal_eqType q)
625

path move c cs -> c1 \in cs -> c1 ldisk != c ldisk -> {cs' : seq (configuration n) | [/\ path move ↓[c] cs', last ↓[c] cs' = ↓[last c cs] & size cs' < size cs]}
7d4
56781b5657d7625
cPcs:path move c cs
c1Ics:c1 \in cs
c1dDcd:c1 ldisk != c ldisk

{cs' : seq (configuration n) | [/\ path move ↓[c] cs', last ↓[c] cs' = ↓[last c cs] & size cs' < size cs]}
56781b5657d76257de7df7e07a6
H1:path move ↓[c] cs1
H2:last ↓[c] cs1 = ↓[last c cs]
H3:size cs1 <= size cs ?= iff (cs == [seq ↑[i]_(c ldisk) | i <- cs1])

7e1
7e5
size cs1 < size cs
56781b5657d76257de7df7e07a67e67e7
cs1Ecs:cs = [seq ↑[i]_(c ldisk) | i <- cs1]

size cs1 == size cs -> size cs1 < size cs
56781b5657d76257de7df7a67e67e77f1

c1 ldisk = c ldisk
56781b5657d76257de7a67e67e77f1
x:finfun_eqType (ordinal_finType n) (ordinal_eqType q)
xIcs1:x \in cs1

↑[x]_(c ldisk) ldisk = c ldisk
by rewrite cliftr_ldisk. Qed. (* connect is symmetric *) (* there should be a shorter proof since move n is symmetric *)
56781b

connect_sym move
800
56781b
c1, c2:finfun_finType (ordinal_finType n) (ordinal_finType q)

connect move c1 c2 = connect move c2 c1
56781b809
p:seq (finfun_finType (ordinal_finType n) (ordinal_finType q))
H1:path move c1 p
H2:c2 = last c1 p

exists2 p : seq (finfun_finType (ordinal_finType n) (ordinal_finType q)), path move c2 p & c1 = last c2 p
56781b80980f
H1:path move c2 p
H2:c1 = last c2 p
exists2 p : seq (finfun_finType (ordinal_finType n) (ordinal_finType q)), path move c1 p & c2 = last c1 p
80e
c1 = last c2 (rev (belast c1 p))
813
815
818
815
c2 = last c1 (rev (belast c2 p))
by case: (p) H2 => [->//|c3 p1 _]; rewrite rev_cons last_rcons. Qed. End GHanoi. Arguments perfect {q n}. Arguments cunliftr {q n}. Notation " ↑[ c ]_ p" := (cliftr p c) (at level 5, format "↑[ c ]_ p"). Notation " ↓[ c ]" := (cunliftr c) (at level 5, format "↓[ c ]"). Notation "`c[ p ] " := (perfect p) (format "`c[ p ]", at level 5). Notation "`c[ p , n ] " := ((perfect p) : configuration _ n) (format "`c[ p , n ]", at level 5).
k:nat
9
c:configuration k 1

on_top d c
825
by apply/on_topP=> [] [] [] //=; case: d => [] []. Qed.
n, k:nat
p1, p2:peg k

(`c[p1 , n.+1] == `c[p2]) = (p1 == p2)
82d
830831
cp1Ecp2:`c[p1] = `c[p2]

p1 = p2
837
`c[p1] sdisk = p2
by rewrite cp1Ecp2 ffunE. Qed. Section PLift. Variables n q : nat. Variables i : disk q.+1. Variable r1 : rel (disk q). Variable r2 : rel (disk q.+1). Let p := lift i. Hypothesis r2Rr1 : forall i j, r2 (p i) (p j) = r1 i j. Definition plift (c : configuration q n) : configuration q.+1 n := [ffun j => p (c j)].
n, q:nat
i:disk q.+1
r1:rel (disk q)
r2:rel (disk q.+1)
p:=lift i:'I_q.+1.-1 -> 'I_q.+1
r2Rr1:forall i j : 'I_q.+1.-1, r2 (p i) (p j) = r1 i j
c1:configuration q n
x:disk n

on_top x (plift c1) = on_top x c1
83f
842843844845846847848849
H:forall d1 : ordinal_finType n, plift c1 x = plift c1 d1 -> x <= d1
3b
H2:c1 x = c1 d

p (c1 x) = p (c1 d)
842843844845846847848849
H:forall d1 : ordinal_finType n, c1 x = c1 d1 -> x <= d1
3b
H2:p (c1 x) = p (c1 d)
c1 x = c1 d
855
858
by apply: lift_inj H2. Qed.
842843844845846847
c1, c2:configuration q n

move r2 (plift c1) (plift c2) = move r1 c1 c2
85d
842843844845846847860
x:ordinal_finType n
H1x:r2 (plift c1 x) (plift c2 x)
H2x:forall d2 : ordinal_finType n, x != d2 -> plift c1 d2 = plift c2 d2
H3x:on_top x (plift c1)
H4x:on_top x (plift c2)

r1 (c1 x) (c2 x)
866
forall d2 : ordinal_finType n, x != d2 -> c1 d2 = c2 d2
866
on_top x c1
866
on_top x c2
842843844845846847860867
H1x:r1 (c1 x) (c2 x)
H2x:forall d2 : ordinal_finType n, x != d2 -> c1 d2 = c2 d2
28d28e
r2 (plift c1 x) (plift c2 x)
875
forall d2 : ordinal_finType n, x != d2 -> plift c1 d2 = plift c2 d2
875
on_top x (plift c1)
875
on_top x (plift c2)
864
866
86f
87087287487987b87d
881
866
871
87287487987b87d
886
866
873
87487987b87d
88b
875
878
87987b87d
890
875
87a
87b87d
895
875
87c
87d
89a
875
87e
by rewrite plift_on_top. Qed.
842843844845846847848
cs:seq (configuration q n)

path (move r2) (plift c1) [seq plift i | i <- cs] = path (move r1) c1 cs
8a2
842843844845846847
c2:configuration q n
8a5
IH:forall c1 : configuration q n, path (move r2) (plift c1) [seq plift i | i <- cs] = path (move r1) c1 cs
848

move r2 (plift c1) (plift c2) && path (move r2) (plift c2) [seq plift i | i <- cs] = move r1 c1 c2 && path (move r1) c2 cs
by rewrite plift_move IH. Qed.
85f
connect (move r1) c1 c2 -> `d[plift c1, plift c2]_(move r2) <= `d[c1, c2]_(move r1)
8b0
842843844845846847860202
p1H:gpath (move r1) c1 c2 p1

`d[plift c1, plift c2]_(move r2) <= `d[c1, c2]_(move r1)
8b7
`d[plift c1, plift c2]_(move r2) <= size [seq plift i | i <- p1]
8b7
last (plift c1) [seq plift i | i <- p1] = plift c2
by rewrite last_map (gpath_last p1H). Qed.
842843844845846847
p1:peg q

plift `c[p1] = `c[lift i p1]
8c3
by apply/ffunP => j; rewrite !ffunE. Qed.
842843844845846847
m:nat
c:configuration q n

cdisjoint (plift c) `c[i , m]
8ca
8428438448458468478cd8ce
i1:ordinal_finType n
j1:ordinal_finType m

bump i (c i1) != i
by rewrite eq_sym neq_bump. Qed. End PLift. Section Crlift. Variable q : nat. Variable p : peg q.+1. Variable r1 : rel (disk q). Variable r2 : rel (disk q.+1). Hypothesis r2Irr : irreflexive r2. Hypothesis r1Rr2 : forall i j : disk q, r1 i j = r2 (lift p i) (lift p j).
5
p:peg q.+1
844845
r2Irr:irreflexive r2
r1Rr2:forall i j : disk q, r1 i j = r2 (lift p i) (lift p j)
f1
c1, c2:configuration q m

move r2 (cliftln n p (plift p c1)) (cliftln n p (plift p c2)) = move r1 c1 c2
8d9
58dc8448458dd8def18df
H:move r1 c1 c2

move r2 (cliftln n p (plift p c1)) (cliftln n p (plift p c2))
58dc8448458dd8def18df
H:move r2 (cliftln n p (plift p c1)) (cliftln n p (plift p c2))
move r1 c1 c2
8e5
cdisjoint (plift p c1) `c[p]
8e5
cdisjoint (plift p c2) `c[p]
8e5
move r2 (plift p c1) (plift p c2)
8e9
8ee
8e5
8f3
8f48e9
8f8
8e5
8f5
8e8
8ea
8ec
8ea
move r2 (plift p c1) (plift p c2) -> move r1 c1 c2
by rewrite (@plift_move _ _ _ r1). Qed.
58dc8448458dd8def1
c:configuration q m
cs:seq (configuration q m)

path (move r2) (cliftln n p (plift p c)) [seq (cliftln n p \o plift p) i | i <- cs] = path (move r1) c cs
907
by elim: cs c => //= c1 cs1 IH c; rewrite move_liftln IH. Qed.
8db
connect (move r1) c1 c2 -> connect (move r2) (cliftln n p (plift p c1)) (cliftln n p (plift p c2))
90f
58dc8448458dd8def18df
x:seq (finfun_finType (ordinal_finType m) (ordinal_finType q))
Hp:path (move r2) (cliftln n p (plift p c1)) [seq (cliftln n p \o plift p) i | i <- x]
1f3

connect (move r2) (cliftln n p (plift p c1)) (cliftln n p (plift p c2))
916
cliftln n p (plift p c2) = last (cliftln n p (plift p c1)) [seq (cliftln n p \o plift p) i | i <- x]
by rewrite Hl [RHS]last_map. Qed.
8db
connect (move r1) c1 c2 -> `d[cliftln n p (plift p c1), cliftln n p (plift p c2)]_ (move r2) <= `d[c1, c2]_(move r1)
91f
58dc8448458dd8def18df
p1:seq (finfun_finType (ordinal_finType m) (ordinal_finType q))
8b8

`d[cliftln n p (plift p c1), cliftln n p (plift p c2)]_ (move r2) <= `d[c1, c2]_(move r1)
926
`d[cliftln n p (plift p c1), cliftln n p (plift p c2)]_ (move r2) <= size [seq (cliftln n p \o plift p) i | i <- p1]
926
last (cliftln n p (plift p c1)) [seq (cliftln n p \o plift p) i | i <- p1] = cliftln n p (plift p c2)
by rewrite [LHS]last_map (gpath_last p1H). Qed.
58dc8448458dd8de4da
p1:peg q.+1

cliftln n p `c[p1] = cliftrn m p1 `c[p]
932
by []. Qed. End Crlift. (******************************************************************************) (* Other peg *) (******************************************************************************) Definition opeg n (p1 p2 : peg n) := odflt (if p1 <= p2 then p1 else p2) [pick i | (i != p1) && (i != p2)].
1b
p1, p2:peg n

opeg p1 p2 = opeg p2 p1
939
1b93c
H:p1 = p2

odflt p1 [pick i | i != p1 & i != p2] = odflt p2 [pick i | i != p2 & i != p1]
942
839
by apply/val_eqP/eqP. Qed.
1b
p1, p2:peg n.+3

opeg p1 p2 != p1
949
1b94c
HD:(fun i : ordinal_finType n.+3 => (i != p1) && (i != p2)) =1 xpred0

odflt (if p1 <= p2 then p1 else p2) None != p1
1b94c953
p3, p4:peg n.+3

(p3 == p4) = (val p3 == val p4)
1b94c953
D:forall p3 p4 : peg n.+3, (p3 == p4) = (val p3 == val p4)
954
95d
954
95d
(inord 2 != p1) && (inord 2 != p2) = false -> (inord 1 != p1) && (inord 1 != p2) = false -> (sdisk != p1) && (sdisk != p2) = false -> odflt (if p1 <= p2 then p1 else p2) None != p1
95d
(2 != p1) && (2 != p2) = false -> (1 != p1) && (1 != p2) = false -> (0 != p1) && (0 != p2) = false -> (if p1 <= p2 then p1 else p2) != p1
by case: {HD}p1 => [] [|[|[|p1 Hp1]]] /=; case: p2 => [] [|[|[|p2 Hp2]]]. Qed.
94b
opeg p1 p2 != p2
96b
952
odflt (if p1 <= p2 then p1 else p2) None != p2
957
95d972
95d
972
95d
(inord 2 != p1) && (inord 2 != p2) = false -> (inord 1 != p1) && (inord 1 != p2) = false -> (sdisk != p1) && (sdisk != p2) = false -> odflt (if p1 <= p2 then p1 else p2) None != p2
95d
(2 != p1) && (2 != p2) = false -> (1 != p1) && (1 != p2) = false -> (0 != p1) && (0 != p2) = false -> (if p1 <= p2 then p1 else p2) != p2
by case: {HD}p1 => [] [|[|[|p1 Hp1]]] /=; case: p2 => [] [|[|[|p2 Hp2]]]. Qed. Notation "`p[ p1 , p2 ] " := (opeg p1 p2) (format "`p[ p1 , p2 ]", at level 5).
q, n:nat
hrel:rel (peg q)
p1, p2:peg q
p3:ordinal_eqType q

hrel p1 p2 -> p1 != p3 -> p2 != p3 -> move hrel ↑[`c[p3 , n]]_p1 ↑[`c[p3]]_p2
983
986987988989
p1Rp2:hrel p1 p2
p1Dp3:p1 != p3
p2Dp3:p2 != p3

move hrel ↑[`c[p3 , n]]_p1 ↑[`c[p3]]_p2
98f
cdisjoint `c[p1] `c[p3]
98f
cdisjoint `c[p2] `c[p3]
98f
move hrel `c[p1] `c[p2]
995
98f
99a
99b
99f
98f
99c
98f
hrel (`c[p1] ldisk) (`c[p2] ldisk)
98f
forall d2 : ordinal_finType 1, ldisk != d2 -> `c[p1] d2 = `c[p2] d2
98f
9ac
by case => [] []. Qed.
985
irreflexive hrel -> hrel p1 p2 -> p1 != p3 -> p2 != p3 -> `d[↑[`c[p3 , n]]_p1, ↑[`c[p3]]_p2]_(move hrel) = 1
9b1
986987988989
hirr:irreflexive hrel
990991992

`d[↑[`c[p3 , n]]_p1, ↑[`c[p3]]_p2]_(move hrel) = 1
9b8
`d[↑[`c[p3]]_p1, ↑[`c[p3]]_p2]_(move hrel) <= 1
9b8
0 < `d[↑[`c[p3]]_p1, ↑[`c[p3]]_p2]_(move hrel)
9b8
`d[↑[`c[p3]]_p1, ↑[`c[p3]]_p2]_(move hrel) <= size [:: ↑[`c[p3 , n]]_p2]
9bf
9b8
move hrel ↑[`c[p3]]_p1 ↑[`c[p3]]_p2 && true
9bf
9b8
9c1
9869879889899b9990991992
E:`d[↑[`c[p3]]_p1, ↑[`c[p3]]_p2]_(move hrel) = 0

0 < 0
9869879889899b9990991992
E:↑[`c[p3]]_p1 = ↑[`c[p3]]_p2

9d2
9d6
↑[`c[p3]]_p1 ldisk = p1 -> 0 < 0
9869879889899b99909919929d7
p2Ep1:p2 = p1

9d2
by have := hirr p1; rewrite -{2}p2Ep1 p1Rp2. Qed. (*****************************************************************************) (* Regular relation *) (*****************************************************************************) Section Rrel. Variable n : nat. Definition rrel : rel (peg n) := [rel x y | x != y].
1b

irreflexive rrel
by move=> x; apply/eqP. Qed.
9e4
symmetric rrel
by move=> x y; rewrite /rrel /= eq_sym. Qed. Definition rmove m : rel (configuration n m) := move rrel. End Rrel. Section Srel. Variable n : nat. Definition srel : rel (peg n) := [rel x y : peg n | (x != y) && (x * y == 0)].
9e4
irreflexive srel
by move=> x; apply/idP/negP; rewrite negb_and eqxx. Qed.
9e4
symmetric srel
by move=> x y; rewrite /srel /= mulnC eq_sym. Qed. Definition smove m : rel (configuration n m) := move srel. End Srel. (******************************************************************************) (* Linear relation *) (******************************************************************************) Section Lrel. Variable n : nat. Definition lrel : rel (peg n) := [rel x y : peg n | (x.+1 == y) || (y.+1 == x)].
9e4
irreflexive lrel
9f3
by move=> k; rewrite /lrel /= (gtn_eqF (leqnn _)). Qed.
9e4
symmetric lrel
9f8
by move=> x y; rewrite /lrel /= orbC. Qed. Definition lmove m : rel (configuration n m) := move lrel. End Lrel. Arguments rmove {n m}. Arguments lmove {n m}. Arguments smove {n m}.
p, n:nat
c1, c2:configuration p.+3 n

connect rmove c1 c2
9fd
p:nat
c1, c2:configuration p.+3 0

a02
a00
IH:forall c1 c2 : configuration p.+3 n, connect rmove c1 c2
c1, c2:configuration p.+3 n.+1
a02
a07
c1 = c2
a0a
a0c
a02
a0c
connect rmove ↑[↓[c1]]_(c1 ldisk) ↑[↓[c2]]_(c2 ldisk)
a00a0da0e
p1:=c1 ldisk:(fun=> peg p.+3) ldisk
p2:=c2 ldisk:(fun=> peg p.+3) ldisk

connect rmove ↑[↓[c1]]_p1 ↑[↓[c2]]_p2
a1d
connect rmove ↑[↓[c1]]_p1 ↑[↓[c2]]_p1
a00a0da0ea1ea1f6ca
a20
a27
a20
a00a0da0ea1ea1f6ca
p3:=`p[p1, p2]:peg p.+3

a20
a2e
connect rmove ↑[↓[c1]]_p1 ↑[`c[p3]]_p1
a2e
connect rmove ↑[`c[p3]]_p1 ↑[↓[c2]]_p2
a2e
connect (move (rrel (n:=p.+3))) ↓[c1] `c[p3]
a34
a2e
a36
a2e
connect rmove ↑[`c[p3]]_p2 ↑[↓[c2]]_p2
a2e
connect rmove ↑[`c[p3]]_p1 ↑[`c[p3]]_p2
a2e
connect (move (rrel (n:=p.+3))) `c[p3] ↓[c2]
a42
a2e
a44
a2e
rmove ↑[`c[p3]]_p1 ↑[`c[p3]]_p2
a2e
p1 != p3
a2e
p2 != p3
a2e
a56
rewrite eq_sym; apply: opegDr. Qed.
9ff
`d[c1, c2]_rmove <= (2 ^ n).-1
a5b
a07
`d[c1, c2]_rmove <= (2 ^ 0).-1
a00
IH:forall c1 c2 : configuration p.+3 n, `d[c1, c2]_rmove <= (2 ^ n).-1
a0e
`d[c1, c2]_rmove <= (2 ^ n.+1).-1
a11a63
a65
a67
a65
`d[↑[↓[c1]]_(c1 ldisk), ↑[↓[c2]]_(c2 ldisk)]_rmove <= (2 ^ n.+1).-1
a00a66a0ea1ea1f

`d[↑[↓[c1]]_p1, ↑[↓[c2]]_p2]_rmove <= (2 ^ n.+1).-1
a74
`d[↑[↓[c1]]_p1, ↑[↓[c2]]_p1]_rmove <= (2 ^ n.+1).-1
a00a66a0ea1ea1f6ca
a75
a74
`d[↑[↓[c1]]_p1, ↑[↓[c2]]_p1]_rmove <= ?Goal0
a74
?Goal0 <= (2 ^ n.+1).-1
a7b
a74
connect (move (rrel (n:=p.+3))) ↓[c1] ↓[c2]
a74
`d[↓[c1], ↓[c2]]_(move (rrel (n:=p.+3))) <= (2 ^ n.+1).-1
a7b
a74
a8a
a7a
a74
(2 ^ n).-1 <= (2 ^ n.+1).-1
a7a
a74
2 ^ n <= 2 ^ n.+1
a7a
a7c
a75
a00a66a0ea1ea1f6caa2f

a75
a9c
`d[↑[↓[c1]]_p1, ↑[↓[c2]]_p2]_rmove <= ?Goal
a9c
?Goal <= (2 ^ n.+1).-1
a9c
`d[↑[↓[c1]]_p1, ↑[`c[p3]]_p1]_rmove + `d[↑[`c[p3]]_p1, ↑[↓[c2]]_p2]_rmove <= (2 ^ n.+1).-1
a9c
`d[↑[↓[c1]]_p1, ↑[`c[p3]]_p1]_rmove + `d[↑[`c[p3]]_p1, ↑[↓[c2]]_p2]_rmove <= (2 ^ n + 2 ^ n).-1
a00a66a0ea1ea1f6caa2f
tnP:0 < 2 ^ n

aab
aaf
`d[↑[↓[c1]]_p1, ↑[`c[p3]]_p1]_rmove + `d[↑[`c[p3]]_p1, ↑[↓[c2]]_p2]_rmove <= (2 ^ n).-1 + (2 ^ n).-1.+1
aaf
`d[↑[↓[c1]]_p1, ↑[`c[p3]]_p1]_rmove <= (2 ^ n).-1
aaf
`d[↑[`c[p3]]_p1, ↑[↓[c2]]_p2]_rmove <= (2 ^ n).-1.+1
aaf
`d[↑[↓[c1]]_p1, ↑[`c[p3]]_p1]_rmove <= ?Goal0
aaf
?Goal0 <= (2 ^ n).-1
aba
aaf
a3a
aaf
`d[↓[c1], `c[p3]]_(move (rrel (n:=p.+3))) <= (2 ^ n).-1
aba
aaf
ac8
ab9
aaf
abb
aaf
`d[↑[`c[p3]]_p1, ↑[↓[c2]]_p2]_rmove <= ?Goal
aaf
?Goal <= (2 ^ n).-1.+1
aaf
`d[↑[`c[p3]]_p1, ↑[`c[p3]]_p2]_rmove + `d[↑[`c[p3]]_p2, ↑[↓[c2]]_p2]_rmove <= (2 ^ n).-1.+1
aaf
irreflexive (rrel (n:=p.+3))
aafa53
aafa56
aaf
`d[↑[`c[p3]]_p2, ↑[↓[c2]]_p2]_rmove <= (2 ^ n).-1
adb
aaf
a53
ae0ae1
ae5
aaf
a56
ae1
aea
aaf
ae2
aaf
`d[↑[`c[p3]]_p2, ↑[↓[c2]]_p2]_rmove <= ?Goal
aaf
?Goal <= (2 ^ n).-1
aaf
a48
aaf
`d[`c[p3], ↓[c2]]_(move (rrel (n:=p.+3))) <= (2 ^ n).-1
aaf
afd
by apply: IH. Qed. Definition sorted (s : seq nat) := forall i j, i < size s -> j < size s -> (nth 0 s i < nth 0 s j) = (i < j).
a:nat
s:seq nat

sorted (a :: s) -> sorted s
b02
by move=> H i j iH jH; rewrite -[in RHS]ltnS -[in RHS]H. Qed.
i, j:nat

sorted (iota i j)
b0a
i, j, i1, j1:nat
i1Lj:i1 < j
j1Lj:j1 < j

(nth 0 (iota i j) i1 < nth 0 (iota i j) j1) = (i1 < j1)
by rewrite !nth_iota // ltn_add2l. Qed.
a, b:nat
b06

sorted [:: a, b & s] -> sorted (a :: s)
b19
b1cb06
Hs:sorted [:: a, b & s]
j:nat
iH:0 < size (a :: s)
jH:j.+1 < size (a :: s)

(a < nth 0 s j) = (0 < j.+1)
b1cb06b23
i:nat
iH:i.+1 < size (a :: s)
jH:0 < size (a :: s)
(nth 0 s i < a) = (i.+1 < 0)
b1cb06b23b0db2cb26
(nth 0 s i < nth 0 s j) = (i.+1 < j.+1)
b20
b2a
b2e
b2f
b34
b30
b31
by rewrite (Hs i.+2 j.+2). Qed.
b06
p:pred nat

sorted s -> sorted [seq x <- s | p x]
b3c
b06b3fb05
s1:seq nat
b2b

sorted (a :: s1) -> i < size [seq x <- s1 | p x] -> a < nth 0 [seq x <- s1 | p x] i
b06b3f
F:forall (a : nat) (s1 : seq nat) (i : nat), sorted (a :: s1) -> i < size [seq x <- s1 | p x] -> a < nth 0 [seq x <- s1 | p x] i
b40
b06b3fb1cb46
IH:forall i : nat, sorted (a :: s1) -> i < size [seq x <- s1 | p x] -> a < nth 0 [seq x <- s1 | p x] i
b2b
abS:sorted [:: a, b & s1]

i < size (if p b then b :: [seq x <- s1 | p x] else [seq x <- s1 | p x]) -> a < nth 0 (if p b then b :: [seq x <- s1 | p x] else [seq x <- s1 | p x]) i
b48
b06b3fb1cb46b50b2bb51
pbT:p b

i < size (b :: [seq x <- s1 | p x]) -> a < nth 0 (b :: [seq x <- s1 | p x]) i
b06b3fb1cb46b50b2bb51
pbF:~~ p b
i < size [seq x <- s1 | p x] -> a < nth 0 [seq x <- s1 | p x] i
b49
b06b3fb1cb46b50b51b57
i1:nat
sH:i1.+1 < (size [seq x <- s1 | p x]).+1

a < nth 0 [seq x <- s1 | p x] i1
b59
b06b3fb1cb46b51b57b62b63

sorted (a :: s1)
b59
b5b
b5d
b48
b06b3fb1cb46b2bb51b5c

b69
b48
b4a
b40
b3fb4bb05b06
IH:sorted s -> sorted [seq x <- s | p x]
aS:sorted (a :: s)

sorted (if p a then a :: [seq x <- s | p x] else [seq x <- s | p x])
b3fb4bb05b06b78b79
sS:sorted s

b7a
b3fb4bb05b06b78b79b7f
paT:p a

sorted (a :: [seq x <- s | p x])
b3fb4bb05b06b78b79b7fb84
iH, jH:0 < size (a :: [seq x <- s | p x])

(a < a) = (0 < 0)
b3fb4bb05b06b78b79b7fb84b24
iH:0 < size (a :: [seq x <- s | p x])
jH:j.+1 < size (a :: [seq x <- s | p x])
(a < nth 0 [seq x <- s | p x] j) = (0 < j.+1)
b3fb4bb05b06b78b79b7fb84b2b
iH:i.+1 < size (a :: [seq x <- s | p x])
jH:0 < size (a :: [seq x <- s | p x])
(nth 0 [seq x <- s | p x] i < a) = (i.+1 < 0)
b3fb4bb05b06b78b79b7fb84b0db94b90
(nth 0 [seq x <- s | p x] i < nth 0 [seq x <- s | p x] j) = (i.+1 < j.+1)
b87
b8e
b91
b92b97
b9c
b93
b96
b97
ba1
b98
b99
by rewrite ltnS (IH sS). Qed.
8cd

enum 'I_m.+1 = [seq inord i | i <- iota 0 m.+1]
ba9
bab
enum 'I_m.+1 = [seq ([eta inord] \o nat_of_ord (n:=m.+1)) i | i <- ord_enum m.+1]
bab
ord_enum m.+1 = [seq ([eta inord] \o nat_of_ord (n:=m.+1)) i | i <- ord_enum m.+1]
8cd
a:'I_m.+1
l:seq 'I_m.+1

a :: l = inord a :: l
by rewrite inord_val. Qed. (* To be reworked ! *)
8cd
s:{set 'I_m}
i, j:'I_#|s|

(enum_val i < enum_val j) = (i < j)
bbe
s:{set 'I_0}

forall i j : 'I_#|s|, (enum_val i < enum_val j) = (i < j)
8cd
s:{set 'I_m.+1}
bc2
bc3
bc8
forall i j : 'I_#|set0|, (enum_val i < enum_val j) = (i < j)
bc8
s = set0
bcc
bc98cd
H:m < #|set0|
j:'I_#|set0|

49b
bd3
bc8
bd5
bcb
bcd
bc3
bcd
j < size (enum s) -> i < size (enum s) -> (enum_val i < enum_val j) = (i < j)
8cdbcebc2
iL:j < size [seq x <- [seq inord i | i <- iota 0 m.+1] | mem s x]
jL:i < size [seq x <- [seq inord i | i <- iota 0 m.+1] | mem s x]

(nth (enum_default i) [seq x <- [seq inord i | i <- iota 0 m.+1] | mem s x] i < nth (enum_default j) [seq x <- [seq inord i | i <- iota 0 m.+1] | mem s x] j) = (i < j)
be9
(nth 0 [seq i | i <- [seq inord i | i <- iota 0 m.+1] & mem s i] i < nth (enum_default j) [seq x <- [seq inord i | i <- iota 0 m.+1] | mem s x] j) = (i < j)
be9
(nth 0 [seq i | i <- [seq inord i | i <- iota 0 m.+1] & mem s i] i < nth 0 [seq i | i <- [seq inord i | i <- iota 0 m.+1] & mem s i] j) = (i < j)
8cdbcebc2beabeb
k1, k2:nat

k1 + k2 <= m.+1 -> [seq i | i <- [seq inord i0 | i0 <- iota k1 k2] & mem s i] = [seq i0 <- iota k1 k2 | mem s (inord i0)]
8cdbcebc2beabeb
F:forall k1 k2 : nat, k1 + k2 <= m.+1 -> [seq i | i <- [seq inord i0 | i0 <- iota k1 k2] & mem s i] = [seq i0 <- iota k1 k2 | mem s (inord i0)]
bf4
8cdbcebc2beabeb
k2:nat
IH:forall k1 : nat, k1 + k2 <= m.+1 -> [seq i | i <- [seq inord i0 | i0 <- iota k1 k2] & i \in s] = [seq i0 <- iota k1 k2 | inord i0 \in s]
k1:nat
k1k2Lm:k1 + k2.+1 <= m.+1

[seq i | i <- if inord k1 \in s then inord k1 :: [seq i <- [seq inord i0 | i0 <- iota k1.+1 k2] | i \in s] else [seq i <- [seq inord i0 | i0 <- iota k1.+1 k2] | i \in s]] = (if inord k1 \in s then k1 :: [seq i0 <- iota k1.+1 k2 | inord i0 \in s] else [seq i0 <- iota k1.+1 k2 | inord i0 \in s])
bfb
c02
inord k1 :: [seq i | i <- [seq inord i0 | i0 <- iota k1.+1 k2] & i \in s] = k1 :: [seq i0 <- iota k1.+1 k2 | inord i0 \in s]
c02
[seq i | i <- [seq inord i0 | i0 <- iota k1.+1 k2] & i \in s] = [seq i0 <- iota k1.+1 k2 | inord i0 \in s]
bfc
c02
k1 :: [seq i | i <- [seq inord i0 | i0 <- iota k1.+1 k2] & i \in s] = k1 :: [seq i0 <- iota k1.+1 k2 | inord i0 \in s]
c02
k1 < m.+1
c0dbfc
c02
k1.+1 + k2 <= m.+1
c13
c02
c15
c0c
c02
c0e
bfb
8cdbcebc2beabeb
k2, k1:nat
c06

c19
bfb
bfd
bf4
bfd
(nth 0 [seq i0 <- iota 0 m.+1 | mem s (inord i0)] i < nth 0 [seq i0 <- iota 0 m.+1 | mem s (inord i0)] j) = (i < j)
bfd
j < size [seq i0 <- iota 0 m.+1 | mem s (inord i0)]
bfd
j < size [seq i0 <- iota 0 m.+1 | mem s (inord i0)] -> (nth 0 [seq i0 <- iota 0 m.+1 | mem s (inord i0)] i < nth 0 [seq i0 <- iota 0 m.+1 | mem s (inord i0)] j) = (i < j)
bfd
c32
bfd
i < size [seq i0 <- iota 0 m.+1 | mem s (inord i0)] -> j < size [seq i0 <- iota 0 m.+1 | mem s (inord i0)] -> (nth 0 [seq i0 <- iota 0 m.+1 | mem s (inord i0)] i < nth 0 [seq i0 <- iota 0 m.+1 | mem s (inord i0)] j) = (i < j)
bfd
sorted (iota 0 m.+1)
by apply: sorted_iota. Qed. Section ISetd. (* Number of disks *) Variable n : nat. (* Subset of disks *) Variable sd : {set disk n}. (* Number of pegs *) Variable k : nat. (* relations on peg *) Variable rel : rel (peg k). Definition cset (c : configuration k n) : configuration k #|sd| := [ffun i => c (enum_val i)].
1b
sd:{set disk n}
828
rel:ssrbool.rel (peg k)
c:configuration k n
3b
dIsd:d \in sd

on_top d c -> on_top (enum_rank_in dIsd d) (cset c)
c3f
1bc42828c43c443bc45
dO:forall d1 : ordinal_finType n, c d = c d1 -> d <= d1

on_top (enum_rank_in dIsd d) (cset c)
1bc42828c43c443bc45c4c
d1:'I_#|[eta sd]|
H:cset c (enum_rank_in dIsd d) = cset c d1

enum_rank_in dIsd d <= d1
1bc42828c43c443bc45c4cc52c53
dDd1:enum_rank_in dIsd d != d1

enum_rank_in dIsd d < d1
c58
enum_val d1 \in sd
c58
d < enum_val d1
c58
c61
c58
(d != enum_val d1) && (d <= enum_val d1)
1bc42828c43c443bc45c4cc52c53c59
dEd1:d = enum_val d1

~~ true && (d <= enum_val d1)
1bc42828c43c443bc45c4cc52c53c59
dDd1':d != enum_val d1
d <= enum_val d1
c71
c73
1bc42828c43c443bc45c4cc52c59c72
H:c d = c (enum_val d1)

c73
by apply: dO. Qed.
1bc42828c43
c1, c2:configuration k n

move rel c1 c2 -> cset c1 != cset c2 -> move rel (cset c1) (cset c2)
c7d
1bc42828c43c803b
dH1:rel (c1 d) (c2 d)
dH2:forall d2 : ordinal_finType n, d != d2 -> c1 d2 = c2 d2
dH3:on_top d c1
dH4:on_top d c2
c1Dc2:cset c1 != cset c2

move rel (cset c1) (cset c2)
1bc42828c43c803bc87c88c89c8ac8b
dNIsd:d \notin sd

c8c
1bc42828c43c803bc87
dH2:forall d2 : ordinal_finType n, d != d2 -> c1 d2 = c2 d2
c89c8ac8bc45
c8c
1bc42828c43c803bc87c88c89c8ac91

cset c1 = cset c2
c92
1bc42828c43c803bc87c88c89c8ac91
i:ordinal_finType #|sd|

c1 (enum_val i) = c2 (enum_val i)
c92
1bc42828c43c803bc87c89c8ac91c9f

d != enum_val i
c92
1bc42828c43c803bc87c89c8ac9f

enum_val i \in sd
1bc42828c43c803bc87c88c89c8ac8bc45
c8c
cad
c8c
cad
rel (cset c1 (enum_rank_in dIsd d)) (cset c2 (enum_rank_in dIsd d))
c94
forall d2 : 'I_#|sd|, enum_rank_in dIsd d != d2 -> cset c1 d2 = cset c2 d2
c94
on_top (enum_rank_in dIsd d) (cset c1)
c94
on_top (enum_rank_in dIsd d) (cset c2)
cb2
cad
cb7
cb8cba
cbe
1bc42828c43c803bc87c88c89c8ac8bc45
d2:'I_#|sd|
dDd2:enum_rank_in dIsd d != d2

cset c1 d2 = cset c2 d2
cc0
cc5
c1 (enum_val d2) = c2 (enum_val d2)
cc0
1bc42828c43c803bc87c89c8ac8bc45cc6cc7

d != enum_val d2
cc0
cd0
enum_val (enum_rank_in dIsd d) != enum_val d2
cc0
cad
cb9
cba
cd7
cad
cbb
by apply: on_top_cset. Qed.
1bc42828c43c44
cs:seq (configuration k n)

path (move rel) c cs -> path (move rel) (cset c) (rm_rep (cset c) [seq cset i | i <- cs])
cdf
1bc42828c43
c1:configuration k n
ce2
IH:forall c : configuration k n, path (move rel) c cs -> path (move rel) (cset c) (rm_rep (cset c) [seq cset i | i <- cs])
c44
cMc1:move rel c c1
c1Pcs:path (move rel) c1 cs

path (move rel) (cset c) (if cset c == cset c1 then rm_rep (cset c1) [seq cset i | i <- cs] else cset c1 :: rm_rep (cset c1) [seq cset i | i <- cs])
1bc42828c43ce9ce2ceac44cebcec
cDc1:cset c != cset c1

move rel (cset c) (cset c1) && path (move rel) (cset c1) (rm_rep (cset c1) [seq cset i | i <- cs])
by rewrite move_cset => //=; first by apply: IH; rewrite ?c2V. Qed.
1bc42828c43c80ce2

last c1 cs = c2 -> path (move rel) c1 cs -> `d[cset c1, cset c2]_(move rel) <= size cs
cf5
1bc42828c43c80ce2
cL:last c1 cs = c2
cPcs:path (move rel) c1 cs

`d[cset c1, cset c2]_(move rel) <= size cs
cfd
size (rm_rep (cset c1) [seq cset i | i <- cs]) <= size [seq cset i | i <- cs] -> `d[cset c1, cset c2]_(move rel) <= size cs
cfd
`d[cset c1, cset c2]_(move rel) <= size (rm_rep (cset c1) [seq cset i | i <- cs])
cfd
last (cset c1) (rm_rep (cset c1) [seq cset i | i <- cs]) = cset c2
by rewrite last_rm_rep last_map cL. Qed.
1bc42828c43
c1, c2:finfun_finType (ordinal_finType n) (ordinal_finType k)
cs:seq (finfun_finType (ordinal_finType n) (ordinal_finType k))

gpath (move rel) c1 c2 cs -> `d[cset c1, cset c2]_(move rel) <= `d[c1, c2]_(move rel)
d0e
1bc42828c43d11d12
gH:gpath (move rel) c1 c2 cs

`d[cset c1, cset c2]_(move rel) <= `d[c1, c2]_(move rel)
d18
path (move rel) c1 cs
by apply: gpath_path gH. Qed. End ISetd. Arguments gpath [T]. Section CSet. (* Number of disks *) Variable n : nat. (* cut limit *) Variable t : nat. Variable tLn : t <= n. (* Number of pegs *) Variable k : nat. (* relations on peg *) Variable rel : rel (peg k). Hypothesis irH : irreflexive rel. Definition ccut (c : configuration k n) : configuration k t := [ffun i => c (widen_ord tLn i)].
n, t:nat
tLn:t <= n
828c43
irH:irreflexive rel
1c
dLt:d < t

widen_ord tLn (Ordinal dLt) = d
d20
by apply: val_inj. Qed.
d23d24828c43d25c44
s:seq (peg k)

codom c \subset s -> codom (ccut c) \subset s
d2a
d23d24828c43d25c44d2d5e8
i:ordinal_finType k
j:ordinal_finType t

ccut c j \in s
by rewrite ffunE; apply: (subsetP H); apply: codom_f. Qed.
d23d24828c43d25c44
p:disk k

s2f ([set i | c i == p] :&: isO n t) = s2f [set i | ccut c i == p]
d38
d23d24828c43d25c44d3bb2b

(i \in s2f ([set i | c i == p] :&: isO n t)) = (i \in s2f [set i | ccut c i == p])
d23d24828c43d25c44d3bb2b16d

(c j == p) && (j < t) -> i = j -> exists2 x : 'I_t, x \in [set i | ccut c i == p] & i = x
d23d24828c43d25c44d3bb2b
j:'I_t
ccut c j == p -> i = j -> exists2 x : 'I_n, x \in [set i | c i == p] :&: isO n t & i = x
d23d24828c43d25c44d3bb2b16d
cjEp:c j == p
jLt:j < t

exists2 x : 'I_t, x \in [set i | ccut c i == p] & j = x
d48
d4a
d4c
d23d24828c43d25c44d3bb2bd4b
cjEp:c (widen_ord tLn j) == p

widen_ord tLn j \in [set i | c i == p] :&: isO n t
by rewrite !inE /= cjEp /=. Qed.
d23d24828c43d25c441c
dLr:d < t

on_top d c -> on_top (Ordinal dLr) (ccut c)
d5e
d23d24828c43d25c441cd61c4c

on_top (Ordinal dLr) (ccut c)
d23d24828c43d25c441cd61c4c
d1:'I_t
H:ccut c (Ordinal dLr) = ccut c d1

27
d23d24828c43d25c441cd61c4cd6dd6e
dDd1:d != d1

d < d1
d72
27
d72
c d = c (widen_ord tLn d1)
by move: H; rewrite !ffunE ordinalK. Qed.
d23d24828c43d25c80

move rel c1 c2 -> ccut c1 != ccut c2 -> move rel (ccut c1) (ccut c2)
d7d
d23d24828c43d25c803bc87c88c89c8a
c1Dc2:ccut c1 != ccut c2

move rel (ccut c1) (ccut c2)
d23d24828c43d25c803bc87c88c89c8ad86
dLt:t <= d

d87
d23d24828c43d25c803bc87c95c89c8ad86
tLd:d < t
d87
d23d24828c43d25c803bc87c88c89c8ad8c

ccut c1 = ccut c2
d23d24828c43d25c803bc87c88c89c8ad86d90
d87
d23d24828c43d25c803bc87c88c89c8ad8c
i:ordinal_finType t

c1 (widen_ord tLn i) = c2 (widen_ord tLn i)
d96
d23d24828c43d25c803bc87c89c8ad8cd9d

d != widen_ord tLn i
d96
d98
d87
d98
rel (ccut c1 (Ordinal tLd)) (ccut c2 (Ordinal tLd))
d8f
forall d2 : 'I_t, Ordinal tLd != d2 -> ccut c1 d2 = ccut c2 d2
d8f
on_top (Ordinal tLd) (ccut c1)
d8f
on_top (Ordinal tLd) (ccut c2)
da8
d98
dad
daedb0
db4
d23d24828c43d25c803bc87c88c89c8ad86d90
d2:'I_t
dDd2:d != d2

c1 (widen_ord tLn d2) = c2 (widen_ord tLn d2)
db6
d98
daf
db0
dc0
d98
db1
by apply: on_top_cut. Qed.
d23d24828c43d25c44ce2

path (move rel) c cs -> path (move rel) (ccut c) (rm_rep (ccut c) [seq ccut i | i <- cs])
dc8
d23d24828c43d25ce9ce2
IH:forall c : configuration k n, path (move rel) c cs -> path (move rel) (ccut c) (rm_rep (ccut c) [seq ccut i | i <- cs])
c44cebcec

path (move rel) (ccut c) (if ccut c == ccut c1 then rm_rep (ccut c1) [seq ccut i | i <- cs] else ccut c1 :: rm_rep (ccut c1) [seq ccut i | i <- cs])
d23d24828c43d25ce9ce2dd1c44cebcec
cDc1:ccut c != ccut c1

move rel (ccut c) (ccut c1) && path (move rel) (ccut c1) (rm_rep (ccut c1) [seq ccut i | i <- cs])
by rewrite move_cut => //=; first by apply: IH; rewrite ?c2V. Qed.
d23d24828c43d25c80ce2

last c1 cs = c2 -> path (move rel) c1 cs -> `d[ccut c1, ccut c2]_(move rel) <= size cs
dda
d23d24828c43d25c80ce2cfecff

`d[ccut c1, ccut c2]_(move rel) <= size cs
de2
size (rm_rep (ccut c1) [seq ccut i | i <- cs]) <= size [seq ccut i | i <- cs] -> `d[ccut c1, ccut c2]_(move rel) <= size cs
de2
`d[ccut c1, ccut c2]_(move rel) <= size (rm_rep (ccut c1) [seq ccut i | i <- cs])
de2
last (ccut c1) (rm_rep (ccut c1) [seq ccut i | i <- cs]) = ccut c2
by rewrite last_rm_rep last_map cL. Qed.
d23d24828c43d25d11d12

gpath (move rel) c1 c2 cs -> `d[ccut c1, ccut c2]_(move rel) <= `d[c1, c2]_(move rel)
df1
d23d24828c43d25d11d12d19

`d[ccut c1, ccut c2]_(move rel) <= `d[c1, c2]_(move rel)
df9
d1e
by apply: gpath_path gH. Qed.
d23d24828c43d25b2b

i < n - t -> i + t < n
dff
by move=> iLnt; rewrite -(subnK tLn) ltn_add2r. Qed. Definition tuc_ord (i : disk (n - t)) : disk n := Ordinal (tuc_subproof (ltn_ord i)).
e01
i < n -> t <= i -> i - t < n - t
e05
d23d24828c43d25b2b
iLn:i < n
tLi:t <= i

t < n
by apply: leq_ltn_trans iLn. Qed. Definition otuc (i : disk n) (tLi : t <= i) : disk (n - t) := Ordinal (otuc_subproof (ltn_ord i) tLi).
d23d24828c43d251c
tLd:t <= d

tuc_ord (otuc tLd) = d
e11
by apply: val_inj; rewrite /= subnK. Qed. Definition ctuc (c : configuration k n) : configuration k (n - t) := [ffun i => c (tuc_ord i)].
d23d24828c43d25c441c
dLr:t <= d

on_top d c -> on_top (otuc dLr) (ctuc c)
e18
d23d24828c43d25c441ce1bc4c

on_top (otuc dLr) (ctuc c)
d23d24828c43d25c441ce1bc4c
d1:'I_(n - t)
H:ctuc c (otuc dLr) = ctuc c d1

d - t <= d1
d23d24828c43d25c441ce1bc4ce27e28
dDd1:d - t != d1

d - t < d1
e2d
d <= d1 + t
e2d
c d = c (tuc_ord d1)
by move: H; rewrite !ffunE otucK. Qed.
d7f
move rel c1 c2 -> ctuc c1 != ctuc c2 -> move rel (ctuc c1) (ctuc c2)
e39
d23d24828c43d25c803bc87c88c89c8a
c1Dc2:ctuc c1 != ctuc c2

move rel (ctuc c1) (ctuc c2)
d23d24828c43d25c803bc87c88c89c8ae41d90

e42
d23d24828c43d25c803bc87c95c89c8ae41d8c
e42
d23d24828c43d25c803bc87c88c89c8ad90

ctuc c1 = ctuc c2
d23d24828c43d25c803bc87c88c89c8ae41d8c
e42
d23d24828c43d25c803bc87c88c89c8ad90
i:ordinal_finType (n - t)

c1 (tuc_ord i) = c2 (tuc_ord i)
e4f
d23d24828c43d25c803bc87c89c8ad90e56

d != tuc_ord i
e4f
e51
e42
e51
rel (ctuc c1 (otuc dLt)) (ctuc c2 (otuc dLt))
e49
forall d2 : 'I_(n - t), otuc dLt != d2 -> ctuc c1 d2 = ctuc c2 d2
e49
on_top (otuc dLt) (ctuc c1)
e49
on_top (otuc dLt) (ctuc c2)
e61
e51
e66
e67e69
e6d
d23d24828c43d25c803bc87c88c89c8ae41d8c
d2:'I_(n - t)
dDd2:d - t != d2

c1 (tuc_ord d2) = c2 (tuc_ord d2)
e6f
e51
e68
e69
e79
e51
e6a
by apply: on_top_tuc. Qed.
dca
path (move rel) c cs -> path (move rel) (ctuc c) (rm_rep (ctuc c) [seq ctuc i | i <- cs])
e81
d23d24828c43d25ce9ce2
IH:forall c : configuration k n, path (move rel) c cs -> path (move rel) (ctuc c) (rm_rep (ctuc c) [seq ctuc i | i <- cs])
c44cebcec

path (move rel) (ctuc c) (if ctuc c == ctuc c1 then rm_rep (ctuc c1) [seq ctuc i | i <- cs] else ctuc c1 :: rm_rep (ctuc c1) [seq ctuc i | i <- cs])
d23d24828c43d25ce9ce2e89c44cebcec
cDc1:ctuc c != ctuc c1

move rel (ctuc c) (ctuc c1) && path (move rel) (ctuc c1) (rm_rep (ctuc c1) [seq ctuc i | i <- cs])
by rewrite move_tuc => //=; first by apply: IH; rewrite ?c2V. Qed.
ddc
last c1 cs = c2 -> path (move rel) c1 cs -> `d[ctuc c1, ctuc c2]_(move rel) <= size cs
e92
de2
`d[ctuc c1, ctuc c2]_(move rel) <= size cs
de2
size (rm_rep (ctuc c1) [seq ctuc i | i <- cs]) <= size [seq ctuc i | i <- cs] -> `d[ctuc c1, ctuc c2]_(move rel) <= size cs
de2
`d[ctuc c1, ctuc c2]_(move rel) <= size (rm_rep (ctuc c1) [seq ctuc i | i <- cs])
de2
last (ctuc c1) (rm_rep (ctuc c1) [seq ctuc i | i <- cs]) = ctuc c2
by rewrite last_rm_rep last_map cL. Qed.
df3
gpath (move rel) c1 c2 cs -> `d[ctuc c1, ctuc c2]_(move rel) <= `d[c1, c2]_(move rel)
ea7
df9
`d[ctuc c1, ctuc c2]_(move rel) <= `d[c1, c2]_(move rel)
dfc
by apply: gpath_path gH. Qed.
dca
path (move rel) c cs -> size cs = size (rm_rep (ccut c) [seq ccut i | i <- cs]) + size (rm_rep (ctuc c) [seq ctuc i | i <- cs])
eb1
d23d24828c43d25ce9ce2
IH:forall c : configuration k n, path (move rel) c cs -> size cs = size (rm_rep (ccut c) [seq ccut i | i <- cs]) + size (rm_rep (ctuc c) [seq ctuc i | i <- cs])
c443b
dH1:rel (c d) (c1 d)
dH2:forall d2 : ordinal_finType n, d != d2 -> c d2 = c1 d2
dH3:on_top d c
dH4:on_top d c1
cec

(size cs).+1 = size (if ccut c == ccut c1 then rm_rep (ccut c1) [seq ccut i | i <- cs] else ccut c1 :: rm_rep (ccut c1) [seq ccut i | i <- cs]) + size (if ctuc c == ctuc c1 then rm_rep (ctuc c1) [seq ctuc i | i <- cs] else ctuc c1 :: rm_rep (ctuc c1) [seq ctuc i | i <- cs])
eb8
c d != c1 d
d23d24828c43d25ce9ce2eb9c443beba
dH2:forall d2 : ordinal_finType n, d != d2 -> c d2 = c1 d2
ebcebdcec
cdDc1d:c d != c1 d
ebe
d23d24828c43d25ce9ce2eb9c443bebaebbebcebdcecec7

ebe
d23d24828c43d25ce9ce2eb9c443bebaebbebcebdcecec7d26

ebe
d23d24828c43d25ce9ce2eb9c443bebaec6ebcebdcecec7e14
ebe
ecf
ccut c != ccut c1
d23d24828c43d25ce9ce2eb9c443bebaec6ebcebdcecec7d26
(size cs).+1 = (size (rm_rep (ccut c1) [seq ccut i | i <- cs]) + size (if ctuc c == ctuc c1 then rm_rep (ctuc c1) [seq ctuc i | i <- cs] else ctuc c1 :: rm_rep (ctuc c1) [seq ctuc i | i <- cs])).+1
ed1
ecf
ccut c (Ordinal dLt) = ccut c1 (Ordinal dLt) -> False
ed7
ecf
eda
ed0
ecf
ctuc c == ctuc c1
ed9
(size cs).+1 = (size (rm_rep (ccut c1) [seq ccut i | i <- cs]) + size (rm_rep (ctuc c1) [seq ctuc i | i <- cs])).+1
ed1
d23d24828c43d25ce9ce2eb9c443bebaebbebcebdcecec7d26e56

e5c
ee6
eec
val d == val (tuc_ord i) -> False
ee6
ecf
ee8
ed0
d23d24828c43d25ce9ce2eb9c443bebaebbebcebdcecec7e14

ebe
ef7
ccut c == ccut c1
ed2
(size cs).+1 = size (rm_rep (ccut c1) [seq ccut i | i <- cs]) + size (if ctuc c == ctuc c1 then rm_rep (ctuc c1) [seq ctuc i | i <- cs] else ctuc c1 :: rm_rep (ctuc c1) [seq ctuc i | i <- cs])
d23d24828c43d25ce9ce2eb9c443bebaebbebcebdcecec7e14d9d

da3
efc
ef7
efe
ef7
ctuc c != ctuc c1
ed2
(size cs).+1 = size (rm_rep (ccut c1) [seq ccut i | i <- cs]) + (size (rm_rep (ctuc c1) [seq ctuc i | i <- cs])).+1
ef7
ctuc c (otuc tLd) == ctuc c1 (otuc tLd) -> False
f0a
ef7
f0c
by rewrite addnS; congr (_.+1); apply: IH. Qed.
ddc
last c1 cs = c2 -> path (move rel) c1 cs -> `d[ccut c1, ccut c2]_(move rel) + `d[ctuc c1, ctuc c2]_(move rel) <= size cs
f15
de2
`d[ccut c1, ccut c2]_(move rel) + `d[ctuc c1, ctuc c2]_(move rel) <= size cs
de2
`d[ccut c1, ccut c2]_(move rel) + `d[ctuc c1, ctuc c2]_(move rel) <= size (rm_rep (ccut c1) [seq ccut i | i <- cs]) + size (rm_rep (ctuc c1) [seq ctuc i | i <- cs])
dea
de2ea1
deef23
e9f
ea2 by rewrite last_rm_rep last_map cL. Qed.
df3
gpath (move rel) c1 c2 cs -> `d[ccut c1, ccut c2]_(move rel) + `d[ctuc c1, ctuc c2]_(move rel) <= `d[c1, c2]_(move rel)
f29
df9
`d[ccut c1, ccut c2]_(move rel) + `d[ctuc c1, ctuc c2]_(move rel) <= `d[c1, c2]_(move rel)
df9
f1c
dfc
by apply: gpath_path gH. Qed. End CSet. Section ISet. (* Number of disks *) Variable n : nat. (* Subset of disks *) Variable sd : {set disk n}. (* Number of pegs *) Variable k : nat. (* Subset of pegs *) Variable sp : {set peg k}. (* The subset is non empty *) Variable p0 : peg k. Variable p0Isp : p0 \in sp. (* relations on peg *) Variable rel1 : rel (peg k). Variable rel2 : rel (peg #|sp|). Hypothesis rel_compat : forall p1 p2, p1 \in sp -> p2 \in sp -> rel1 p1 p2 -> rel2 (enum_rank_in p0Isp p1) (enum_rank_in p0Isp p2). (* Valid conf : disk in sd are on pegs in sp *) Definition cvalid (c : configuration k n) := [forall i, (i \in sd) ==> (c i \in sp)].
1bc42828
sp:{set peg k}
p0:peg k
p0Isp:p0 \in sp
rel1:rel (peg k)
rel2:rel (peg #|sp|)
rel_compat:forall p1 p2 : ordinal_finType k, p1 \in sp -> p2 \in sp -> rel1 p1 p2 -> rel2 (enum_rank_in p0Isp p1) (enum_rank_in p0Isp p2)
c44

reflect (forall i : ordinal_finType n, i \in sd -> c i \in sp) (cvalid c)
f36
1bc42828f39f3af3bf3cf3df3ec44
H:forall i : ordinal_finType n, i \in sd -> c i \in sp
3b

(d \in sd) ==> (c d \in sp)
by apply/implyP/H. Qed. Definition cset2 (c : configuration k n) : configuration #|sp| #|sd| := [ffun i => enum_rank_in p0Isp (c (enum_val i))].
1bc42828f39f3af3bf3cf3df3ec443bc45

cvalid c -> on_top d c -> on_top (enum_rank_in dIsd d) (cset2 c)
f48
1bc42828f39f3af3bf3cf3df3ec443bc45
cV:forall i : ordinal_finType n, i \in sd -> c i \in sp
c4c

on_top (enum_rank_in dIsd d) (cset2 c)
1bc42828f39f3af3bf3cf3df3ec443bc45f51c4cc52
H:cset2 c (enum_rank_in dIsd d) = cset2 c d1

c54
1bc42828f39f3af3bf3cf3df3ec443bc45f51c4cc52f57c59

c5a
f5b
c5e
f5bc61
f5b
c61
f5b
c68
1bc42828f39f3af3bf3cf3df3ec443bc45f51c4cc52f57c59c6d

c6e
1bc42828f39f3af3bf3cf3df3ec443bc45f51c4cc52f57c59c72
c73
f6d
c73
1bc42828f39f3af3bf3cf3df3ec443bc45f51c4cc52c59c72
H:enum_rank_in p0Isp (c d) = enum_rank_in p0Isp (c (enum_val d1))

c73
1bc42828f39f3af3bf3cf3df3ec443bc45f51c52c59c72f75

c d = c (enum_val d1)
f79
c d \in sp
f79
c (enum_val d1) \in sp
f79
f81
by apply/cV/enum_valP. Qed.
1bc42828f39f3af3bf3cf3df3ec80

all cvalid [:: c1; c2] -> move rel1 c1 c2 -> cset2 c1 != cset2 c2 -> move rel2 (cset2 c1) (cset2 c2)
f86
f88
[&& cvalid c1, cvalid c2 & true] -> move rel1 c1 c2 -> cset2 c1 != cset2 c2 -> move rel2 (cset2 c1) (cset2 c2)
1bc42828f39f3af3bf3cf3df3ec80
c1V:cvalid c1
c2V:cvalid c2
3b
dH1:rel1 (c1 d) (c2 d)
c95c89c8a
c1Dc2:cset2 c1 != cset2 c2

move rel2 (cset2 c1) (cset2 c2)
1bc42828f39f3af3bf3cf3df3ec80f93f943bf95c95c89c8af96c91

f97
1bc42828f39f3af3bf3cf3df3ec80f93f943bf95c95c89c8af96c45
f97
1bc42828f39f3af3bf3cf3df3ec80f93f943bf95c95c89c8ac91

cset2 c1 = cset2 c2
f9c
1bc42828f39f3af3bf3cf3df3ec80f93f943bf95c95c89c8ac91c9f

enum_rank_in p0Isp (c1 (enum_val i)) = enum_rank_in p0Isp (c2 (enum_val i))
f9c
fa7
enum_val (enum_rank_in p0Isp (c1 (enum_val i))) = enum_val (enum_rank_in p0Isp (c2 (enum_val i)))
f9c
fa7
ca0
f9c
1bc42828f39f3af3bf3cf3df3ec80f93f943bf95c89c8ac91c9f

ca5
f9c
1bc42828f39f3af3bf3cf3df3ec80f93f943bf95c89c8ac9f

caa
f9c
f9e
f97
f9e
rel2 (cset2 c1 (enum_rank_in dIsd d)) (cset2 c2 (enum_rank_in dIsd d))
f9e
forall d2 : 'I_#|sd|, enum_rank_in dIsd d != d2 -> cset2 c1 d2 = cset2 c2 d2
f9e
on_top (enum_rank_in dIsd d) (cset2 c1)
f9e
on_top (enum_rank_in dIsd d) (cset2 c2)
fbc
f9e
rel2 (enum_rank_in p0Isp (c1 d)) (enum_rank_in p0Isp (c2 d))
fbf
f9e
fc1
fc2fc4
fcc
1bc42828f39f3af3bf3cf3df3ec80f93f943bf95c95c89c8af96c45cc6cc7

cset2 c1 d2 = cset2 c2 d2
fce
fd3
enum_rank_in p0Isp (c1 (enum_val d2)) = enum_rank_in p0Isp (c2 (enum_val d2))
fce
fd3
ccc
fce
1bc42828f39f3af3bf3cf3df3ec80f93f943bf95c89c8af96c45cc6cc7

cd1
fce
fdf
cd5
fce
f9e
fc3
fc4
fe4
f9e
fc5
by apply: on_top_cset2. Qed.
1bc42828f39f3af3bf3cf3df3ec44ce2

all cvalid (c :: cs) -> path (move rel1) c cs -> path (move rel2) (cset2 c) (rm_rep (cset2 c) [seq cset2 i | i <- cs])
fec
1bc42828f39f3af3bf3cf3df3ece9ce2
IH:forall c : configuration k n, cvalid c && all cvalid cs -> path (move rel1) c cs -> path (move rel2) (cset2 c) (rm_rep (cset2 c) [seq cset2 i | i <- cs])
c44
c1V:cvalid c
c2V:cvalid c1
c3V:all cvalid cs
cMc1:move rel1 c c1
c1Pcs:path (move rel1) c1 cs

path (move rel2) (cset2 c) (if cset2 c == cset2 c1 then rm_rep (cset2 c1) [seq cset2 i | i <- cs] else cset2 c1 :: rm_rep (cset2 c1) [seq cset2 i | i <- cs])
1bc42828f39f3af3bf3cf3df3ece9ce2ff5c44ff6ff7ff8ff9ffa
cDc1:cset2 c != cset2 c1

move rel2 (cset2 c) (cset2 c1) && path (move rel2) (cset2 c1) (rm_rep (cset2 c1) [seq cset2 i | i <- cs])
fff
[&& cvalid c, cvalid c1 & true]
by rewrite c1V c2V. Qed.
1bc42828f39f3af3bf3cf3df3ec80ce2

all cvalid (c1 :: cs) -> last c1 cs = c2 -> path (move rel1) c1 cs -> `d[cset2 c1, cset2 c2]_(move rel2) <= size cs
1007
1bc42828f39f3af3bf3cf3df3ec80ce2
cV:all cvalid (c1 :: cs)
cfe
cPcs:path (move rel1) c1 cs

`d[cset2 c1, cset2 c2]_(move rel2) <= size cs
100f
size (rm_rep (cset2 c1) [seq cset2 i | i <- cs]) <= size [seq cset2 i | i <- cs] -> `d[cset2 c1, cset2 c2]_(move rel2) <= size cs
100f
`d[cset2 c1, cset2 c2]_(move rel2) <= size (rm_rep (cset2 c1) [seq cset2 i | i <- cs])
100f
last (cset2 c1) (rm_rep (cset2 c1) [seq cset2 i | i <- cs]) = cset2 c2
by rewrite last_rm_rep last_map cL. Qed.
1bc42828f39f3af3bf3cf3df3ece9
c2:finfun_finType (ordinal_finType n) (ordinal_finType k)
ce2

all cvalid (c1 :: cs) -> gpath (move rel1) c1 c2 cs -> `d[cset2 c1, cset2 c2]_(move rel2) <= `d[c1, c2]_(move rel1)
1020
1bc42828f39f3af3bf3cf3df3ece91023ce21010
gH:gpath (move rel1) c1 c2 cs

`d[cset2 c1, cset2 c2]_(move rel2) <= `d[c1, c2]_(move rel1)
1029
path (move rel1) c1 cs
by apply: gpath_path gH. Qed. End ISet. Section ISet2. (* Number of disks *) Variable n : nat. (* Subset of disks *) Variable sd : {set disk n}. (* Number of pegs *) Variable k : nat. (* Subsets of pegs *) Variables sp1 sp2 : {set peg k}. (* The subsets are non empty *) Variable p1 p2 : peg k. Variable p1Isp1 : p1 \in sp1. Variable p2Isp2 : p2 \in sp2. (* relations on peg *) Variable rel1 : rel (peg k). Variable rel2 : rel (peg #|sp1|). Variable rel3 : rel (peg #|sp2|). Hypothesis irH : irreflexive rel1. Hypothesis rel2_compat : forall pi pj, pi \in sp1 -> pj \in sp1 -> rel1 pi pj -> rel2 (enum_rank_in p1Isp1 pi) (enum_rank_in p1Isp1 pj). Hypothesis rel3_compat : forall pi pj, pi \in sp2 -> pj \in sp2 -> rel1 pi pj -> rel3 (enum_rank_in p2Isp2 pi) (enum_rank_in p2Isp2 pj).
1bc42828
sp1, sp2:{set peg k}
831
p1Isp1:p1 \in sp1
p2Isp2:p2 \in sp2
f3c
rel2:rel (peg #|sp1|)
rel3:rel (peg #|sp2|)
irH:irreflexive rel1
rel2_compat:forall pi pj : ordinal_finType k, pi \in sp1 -> pj \in sp1 -> rel1 pi pj -> rel2 (enum_rank_in p1Isp1 pi) (enum_rank_in p1Isp1 pj)
rel3_compat:forall pi pj : ordinal_finType k, pi \in sp2 -> pj \in sp2 -> rel1 pi pj -> rel3 (enum_rank_in p2Isp2 pi) (enum_rank_in p2Isp2 pj)
c44ce2

all (cvalid sd sp1) (c :: cs) -> all (cvalid (~: sd) sp2) (c :: cs) -> path (move rel1) c cs -> size cs = size (rm_rep (cset2 sd p1Isp1 c) [seq cset2 sd p1Isp1 i | i <- cs]) + size (rm_rep (cset2 (~: sd) p2Isp2 c) [seq cset2 (~: sd) p2Isp2 i | i <- cs])
1031
1bc42828103483110351036f3c103710381039103a103bce9ce2
IH:forall c : configuration k n, cvalid sd sp1 c && all (cvalid sd sp1) cs -> cvalid (~: sd) sp2 c && all (cvalid (~: sd) sp2) cs -> path (move rel1) c cs -> size cs = size (rm_rep (cset2 sd p1Isp1 c) [seq cset2 sd p1Isp1 i | i <- cs]) + size (rm_rep (cset2 (~: sd) p2Isp2 c) [seq cset2 (~: sd) p2Isp2 i | i <- cs])
c44
c1V1:cvalid sd sp1 c
c2V1:cvalid sd sp1 c1
c3V1:all (cvalid sd sp1) cs
c1V2:cvalid (~: sd) sp2 c
c2V2:cvalid (~: sd) sp2 c1
c3V2:all (cvalid (~: sd) sp2) cs
3b
dH1:rel1 (c d) (c1 d)
ec6ebcebdffa

(size cs).+1 = size (if cset2 sd p1Isp1 c == cset2 sd p1Isp1 c1 then rm_rep (cset2 sd p1Isp1 c1) [seq cset2 sd p1Isp1 i | i <- cs] else cset2 sd p1Isp1 c1 :: rm_rep (cset2 sd p1Isp1 c1) [seq cset2 sd p1Isp1 i | i <- cs]) + size (if cset2 (~: sd) p2Isp2 c == cset2 (~: sd) p2Isp2 c1 then rm_rep (cset2 (~: sd) p2Isp2 c1) [seq cset2 (~: sd) p2Isp2 i | i <- cs] else cset2 (~: sd) p2Isp2 c1 :: rm_rep (cset2 (~: sd) p2Isp2 c1) [seq cset2 (~: sd) p2Isp2 i | i <- cs])
1041
ec2
1bc42828103483110351036f3c103710381039103a103bce9ce21042c441043104410451046104710483b1049ec6ebcebdffaec7
104a
1050
104a
1bc42828103483110351036f3c103710381039103a103bce9ce21042c441043104410451046104710483b1049ec6ebcebdffaec7c45

104a
1bc42828103483110351036f3c103710381039103a103bce9ce21042c441043104410451046104710483b1049ec6ebcebdffaec7c91
104a
1057
cset2 sd p1Isp1 c != cset2 sd p1Isp1 c1
1057
(size cs).+1 = (size (rm_rep (cset2 sd p1Isp1 c1) [seq cset2 sd p1Isp1 i | i <- cs]) + size (if cset2 (~: sd) p2Isp2 c == cset2 (~: sd) p2Isp2 c1 then rm_rep (cset2 (~: sd) p2Isp2 c1) [seq cset2 (~: sd) p2Isp2 i | i <- cs] else cset2 (~: sd) p2Isp2 c1 :: rm_rep (cset2 (~: sd) p2Isp2 c1) [seq cset2 (~: sd) p2Isp2 i | i <- cs])).+1
1059
1057
cset2 sd p1Isp1 c (enum_rank_in dIsd d) = cset2 sd p1Isp1 c1 (enum_rank_in dIsd d) -> False
105f
1bc42828103483110351036f3c103710381039103a103bce9ce21042c441043104410451046104710483b1049ec6ebcebdffaec7c45
H:c d \in sp1 -> c1 d \in sp1 -> c d = c1 d

49b
105f
1bc42828103483110351036f3c103710381039103a103bce9ce21042c441043104410451046104710483b1049ec6ebcebdffac45

c1 d \in sp1
105f
1057
1061
1058
1057
cset2 (~: sd) p2Isp2 c == cset2 (~: sd) p2Isp2 c1
1057
(size cs).+1 = (size (rm_rep (cset2 sd p1Isp1 c1) [seq cset2 sd p1Isp1 i | i <- cs]) + size (rm_rep (cset2 (~: sd) p2Isp2 c1) [seq cset2 (~: sd) p2Isp2 i | i <- cs])).+1
1059
1bc42828103483110351036f3c103710381039103a103bce9ce21042c441043104410451046104710483b1049ec6ebcebdffaec7c45
i:ordinal_finType #|~: sd|

ca5
1077
107d
enum_val i \notin sd -> d != enum_val i
1077
1057
1079
1058
105a
104a
105a
cset2 sd p1Isp1 c == cset2 sd p1Isp1 c1
105a
(size cs).+1 = size (rm_rep (cset2 sd p1Isp1 c1) [seq cset2 sd p1Isp1 i | i <- cs]) + size (if cset2 (~: sd) p2Isp2 c == cset2 (~: sd) p2Isp2 c1 then rm_rep (cset2 (~: sd) p2Isp2 c1) [seq cset2 (~: sd) p2Isp2 i | i <- cs] else cset2 (~: sd) p2Isp2 c1 :: rm_rep (cset2 (~: sd) p2Isp2 c1) [seq cset2 (~: sd) p2Isp2 i | i <- cs])
1bc42828103483110351036f3c103710381039103a103bce9ce21042c441043104410451046104710483b1049ec6ebcebdffaec7c91c9f

ca5
108d
1bc42828103483110351036f3c103710381039103a103bce9ce21042c441043104410451046104710483b1049ec6ebcebdffaec7c9f

caa
108d
105a
108f
1bc42828103483110351036f3c103710381039103a103bce9ce21042c441043104410451046104710483b1049ec6ebcebdffaec7c91
dd:d \in ~: sd

108f
109e
cset2 (~: sd) p2Isp2 c != cset2 (~: sd) p2Isp2 c1
109e
(size cs).+1 = size (rm_rep (cset2 sd p1Isp1 c1) [seq cset2 sd p1Isp1 i | i <- cs]) + (size (rm_rep (cset2 (~: sd) p2Isp2 c1) [seq cset2 (~: sd) p2Isp2 i | i <- cs])).+1
109e
cset2 (~: sd) p2Isp2 c (enum_rank_in dd d) = cset2 (~: sd) p2Isp2 c1 (enum_rank_in dd d) -> False
10a4
1bc42828103483110351036f3c103710381039103a103bce9ce21042c441043104410451046104710483b1049ec6ebcebdffaec7c91109f
H:c d \in sp2 -> c1 d \in sp2 -> c d = c1 d

49b
10a4
1bc42828103483110351036f3c103710381039103a103bce9ce21042c441043104410451046104710483b1049ec6ebcebdffac91109f

c d \in sp2
10b3
c1 d \in sp2
10a5
10b3
10b7
10a4
109e
10a6
by rewrite addnS; congr (_.+1); apply: IH; rewrite ?c2V1 ?c2V2. Qed.
1bc42828103483110351036f3c103710381039103a103bc80ce2

all (cvalid sd sp1) (c1 :: cs) -> all (cvalid (~: sd) sp2) (c1 :: cs) -> last c1 cs = c2 -> path (move rel1) c1 cs -> `d[cset2 sd p1Isp1 c1, cset2 sd p1Isp1 c2]_(move rel2) + `d[cset2 (~: sd) p2Isp2 c1, cset2 (~: sd) p2Isp2 c2]_ (move rel3) <= size cs
10bf
1bc42828103483110351036f3c103710381039103a103bc80ce2
cV1:all (cvalid sd sp1) (c1 :: cs)
cV2:all (cvalid (~: sd) sp2) (c1 :: cs)
cfe1011

`d[cset2 sd p1Isp1 c1, cset2 sd p1Isp1 c2]_(move rel2) + `d[cset2 (~: sd) p2Isp2 c1, cset2 (~: sd) p2Isp2 c2]_ (move rel3) <= size cs
10c7
`d[cset2 sd p1Isp1 c1, cset2 sd p1Isp1 c2]_(move rel2) + `d[cset2 (~: sd) p2Isp2 c1, cset2 (~: sd) p2Isp2 c2]_ (move rel3) <= size (rm_rep (cset2 sd p1Isp1 c1) [seq cset2 sd p1Isp1 i | i <- cs]) + size (rm_rep (cset2 (~: sd) p2Isp2 c1) [seq cset2 (~: sd) p2Isp2 i | i <- cs])
10c7
`d[cset2 sd p1Isp1 c1, cset2 sd p1Isp1 c2]_(move rel2) <= size (rm_rep (cset2 sd p1Isp1 c1) [seq cset2 sd p1Isp1 i | i <- cs])
10c7
`d[cset2 (~: sd) p2Isp2 c1, cset2 (~: sd) p2Isp2 c2]_ (move rel3) <= size (rm_rep (cset2 (~: sd) p2Isp2 c1) [seq cset2 (~: sd) p2Isp2 i | i <- cs])
10c7
last (cset2 sd p1Isp1 c1) (rm_rep (cset2 sd p1Isp1 c1) [seq cset2 sd p1Isp1 i | i <- cs]) = cset2 sd p1Isp1 c2
10d3
10c7
`d[cset2 (~: sd) p2Isp2 c1, cset2 (~: sd) p2Isp2 c2]_ (move rel3) <= size (rm_rep (cset2 (~: sd) p2Isp2 c1) [seq cset2 (~: sd) p2Isp2 i | i <- cs])
10c7
last (cset2 (~: sd) p2Isp2 c1) (rm_rep (cset2 (~: sd) p2Isp2 c1) [seq cset2 (~: sd) p2Isp2 i | i <- cs]) = cset2 (~: sd) p2Isp2 c2
by rewrite last_rm_rep last_map cL. Qed.
1bc42828103483110351036f3c103710381039103a103bce91023ce2

all (cvalid sd sp1) (c1 :: cs) -> all (cvalid (~: sd) sp2) (c1 :: cs) -> gpath (move rel1) c1 c2 cs -> `d[cset2 sd p1Isp1 c1, cset2 sd p1Isp1 c2]_(move rel2) + `d[cset2 (~: sd) p2Isp2 c1, cset2 (~: sd) p2Isp2 c2]_ (move rel3) <= `d[c1, c2]_(move rel1)
10e3
1bc42828103483110351036f3c103710381039103a103bce91023ce210c810c9102a

`d[cset2 sd p1Isp1 c1, cset2 sd p1Isp1 c2]_(move rel2) + `d[cset2 (~: sd) p2Isp2 c1, cset2 (~: sd) p2Isp2 c2]_ (move rel3) <= `d[c1, c2]_(move rel1)
10eb
10ca
10eb
102f
by apply: gpath_path gH. Qed. End ISet2.