why3doc index index
[ABF20] Michael Albert, Mathilde Bouvel, and Valentin Féray. Two first-order logics of permutations. Journal of Combinatorial Theory, Series A, 171:105158, April 2020. [https://arxiv.org/abs/1808.05459v2](https://arxiv.org/abs/1808.05459v2).
[Gio20] A. Giorgetti. Formalisation et vérification de théories de permutations. Research report RR-1715 (in French), UBFC (Université de Bourgogne Franche-Comté) and FEMTO-ST, 17 pages, December 2020. [https://hal.archives-ouvertes.fr/hal-03033416](https://hal.archives-ouvertes.fr/hal-03033416).
[Gio21] A. Giorgetti. Théories de permutations avec Why3. In JFLA 2021, 8 pages, April 2021. [http://jfla.inria.fr/jfla2021.html](http://jfla.inria.fr/jfla2021.html).
module Relation type t type u predicate rel t u end module Determinism (* or PartialFunction *) clone export Relation axiom Deter : forall x:t. forall y z:u. rel x y -> rel x z -> y = z end module Functionality clone export Determinism with axiom Deter axiom Total : forall x:t. exists y:u. rel x y end module Injectivity clone export Relation axiom Injec : forall x y:t. forall a:u. rel x a -> rel y a -> x = y end module Surjectivity clone export Relation axiom Surjec : forall y:u. exists x:t. rel x y end module Bijectivity clone export Functionality with axiom Deter, axiom Total clone export Injectivity with type t = t, type u = u, predicate rel = rel, axiom Injec clone export Surjectivity with type t = t, type u = u, predicate rel = rel, axiom Surjec end module MapRelation use map.Map type t type u predicate map_rel (m: map t u) (x:t) (y:u) = (m[x] = y)
Binary relation associated to any map, as its graph.
constant m: map t u
Let m
be any map.
predicate m_graph (x:t) (y:u) = map_rel m x y
Let m_graph
be its associated binary relation.
clone export Functionality with type t = t, type u = u, predicate rel = m_graph
The graph of any map is a deterministic and total binary relation.
end
ModelTOOB
and other modules(* Injectivity, surjectivity and bijectivity for any maps, more general than module `MapInjection` in map.mlw in stdlib. *) module MapInjSurjBij use map.Map predicate injective (m: map 'a 'b) = forall i j: 'a. m[i] = m[j] -> i = j
injective m
is true when m
is an injection
predicate surjective (m: map 'a 'b) = forall j: 'b. exists i: 'a. m[i] = j
surjective m
is true when m
is a surjection
predicate bijective (m: map 'a 'b) = injective m /\ surjective m (* TODO: add more, by analogy with `MapInjection`. *) end
module NumOfExt use int.Int use int.NumOf lemma Numof_no_add: forall p : int -> bool, a b c: int. a <= b < c -> not p b -> numof p a c = numof p a b + numof p (b+1) c
More general than Numof_left_no_add
in the stdlib.
end
module Interval use int.Int val constant low : int (* lower interval endpoint *) val constant up : int (* upper interval endpoint *) axiom Nonempty : low <= up type bint = { to_int: int } invariant { low <= to_int <= up } by { to_int = low }
Type for the interval of all integers between low
and up
included.
let constant low_bint : bint = { to_int = low } meta coercion function to_int axiom Extensionality : forall i j:bint. to_int i = to_int j -> i = j
This property holds for records without invariant, but cannot be proved here.
We admit it. It entails Trichotomy
.
let (=) (i j: bint) : bool = to_int i = to_int j let predicate lt_bint (i j: bint) = to_int i < to_int j clone relations.TotalStrictOrder with type t = bint, predicate rel = lt_bint
lt_bint
is a strict total order. Trichotomy
is a consequence of axiom Extensionality
.
let function of_int (i:int) : bint requires { low <= i <= up } ensures { result.to_int = i } = { to_int = i }
Constructor of bint
inhabitants.
lemma of_int_quasi_inj : forall i j: int. low <= i <= up -> low <= j <= up -> of_int i = of_int j -> i = j lemma of_intK: forall i:bint. of_int (to_int i) = i use int.NumOf let function numof_bint (p: bint -> bool) (a b: bint) : int = numof (fun (i:int) -> low <= i <= up && p (of_int i)) a.to_int b.to_int
numof_bint p a b
is the number of integers n such that a
<= n < b
and p n
holds.
end
module TOOB type t predicate rel t t
rel
is R in [ABF20].
clone export Bijectivity with type t = t, type u = t, predicate rel = rel, axiom . end
Hereafter we only consider models where permutations are endomaps on the
type bint
satisfying the predicate MapInjSurjBij.bijective
.
module ModelTOOB use map.Map use Interval use MapInjSurjBij val constant sigma : map bint bint axiom sigma_bij : bijective sigma
Permutation model.
clone MapRelation with type t = bint, type u = bint, constant m = sigma, axiom Deter, axiom Total
Provides map_rel
and the properties that the graph of sigma
is deterministic and total.
predicate rel_sigma (i j: bint) = map_rel sigma i j
Relation associated to the permutation sigma
.
clone TOOB with type t = bint, predicate rel = rel_sigma
The pair (bint
,rel_sigma
) forms a (permutation) model of TOOB.
Axioms Deter
and Injec
are automatically proved with Alt-Ergo.
Axiom Total
is proved by Z3.
Axiom Surjec
is interactively proved with inline_all; CVC4 1.6.
end module Proposition2 use map.Map use Interval use MapInjSurjBij type a predicate rel a a clone TOOB with type t = a, predicate rel = rel, axiom .
A model of TOOB is a pair (a
,rel
) satisfying all axioms of TOOB.
function a2bint a : bint function bint2a bint : a clone functions.Bijective with type t = a, type u = bint, function t2u = a2bint, function u2t = bint2a, axiom Cancel, axiom Right.Cancel
The property that a
is finite is specified by the existence of a pair of mutually
inverse bijections with bint
.
predicate map_rel (m: map 'a 'b) (x: 'a) (y: 'b) = (m[x] = y)
Binary relation associated to any map, as its graph.
predicate isomorphic (sigma : map bint bint) = exists f: map a bint. bijective f /\ forall x y:a. rel x y <-> map_rel sigma (f x) (f y)
(isomorphic sigma)
holds iff (a
,rel
) and (bint
,map_rel sigma
) are isomorphic.
lemma ex_rel_permut : exists rel_permut : map bint bint. forall i j:bint. rel_permut[i] = j <-> rel (bint2a i) (bint2a j)
Key lemma for the proof of Proposition 2, proved with Coq.
lemma Proposition2 : exists sigma: map bint bint. bijective sigma /\ isomorphic sigma
[ABF20, Proposition 2]. Not proved with Auto Level 3. Proved interactively with Why3.
end
module TOTO type t (* type of positions and values *) predicate ltP t t (* strict total order on positions *) predicate ltV t t (* strict total order on values *) clone export relations.TotalStrictOrder with type t = t, predicate rel = ltP, axiom . clone relations.TotalStrictOrder as V with type t = t, predicate rel = ltV, axiom . end
module MapGraph use int.Int use map.Map use Interval constant m : map bint bint type arrow = { source : bint; target : bint } invariant { target = m[source] } by { source = low_bint; target = m[low_bint] }
Type for (i,m
(i)), for low
<= i <= up
.
axiom Extensionality: forall a b:arrow. a.source = b.source /\ a.target = b.target -> a = b
Extensionality of logical equality on arrow
. This axiom is necessary to
prove Trichotomy
.
let (=) (a b: arrow) : bool = a.source = b.source && a.target = b.target let predicate lt_source (a b: arrow) = lt_bint a.source b.source
Strict total order on type arrow
.
clone export relations.TotalStrictOrder with type t = arrow, predicate rel = lt_source lemma Source_inj: forall a b:arrow. a.source = b.source -> a = b
The source
field determines the value of the target
field.
end
module ModelTOTO use int.Int use map.Map use Interval use MapInjSurjBij constant sigma : map bint bint axiom sigma_bij : bijective sigma clone MapGraph with constant m = sigma, axiom Extensionality (* provides type arrow, etc *) let predicate ltP_sigma (a b: arrow) = lt_bint a.source b.source let predicate ltV_sigma (a b: arrow) = lt_bint a.target b.target clone TOTO with type t = arrow, predicate ltP = ltP_sigma, predicate ltV = ltV_sigma end
Hereafter we abandon the objectives of fidelity to [ABF20] and universality of logic with any support set,
and we focus on types int
and bint
. Thus we get shorter definitions and computable predicates and functions.
module STOI type t val predicate lt t t clone export relations.TotalStrictOrder with type t = t, predicate rel = lt, axiom . clone export relations.Irreflexive with type t = t, predicate rel = lt
Provides the property Strict
that simplifies the Coq proof for rank
injectivity.
Similar to the following lemma:
lemma Strict : forall i:bint. not (lt i i)
end
size
]module Gio20proposition5 (* [Gio20, Proposition 5] *) use int.Int use map.Map use MapInjSurjBij val constant size : int clone export Interval with val low = one, val up = size, axiom .
Defines bint
as a type for the interval [one
..size
]. 1 <= size
is assumed.
val constant sigma : map bint bint axiom sigma_bij : bijective sigma let predicate lt_sigma (i j: bint) = lt_bint (sigma i) (sigma j) clone export STOI with type t = bint, val lt = lt_sigma
The pair ([one
..size
],lt_sigma
) is a (permutation) model of STOI.
end
low
..up
]module ModelSTOI (* [Gio21, Section 4, Paragraph 2] *) use map.Map use MapInjSurjBij clone export Interval with axiom .
Defines bint
as a type for the interval [low
..up
]. low
<= up
is assumed.
val constant sigma : map bint bint axiom sigma_bij : bijective sigma let predicate lt_map (m: map bint bint) (i j: bint) = lt_bint m[i] m[j] let predicate lt_sigma (i j: bint) = lt_map sigma i j clone export relations.TotalStrictOrder with type t = bint, predicate rel = lt_sigma
The pair ([low
..up
],lt_sigma
) is a (permutation) model of STOI.
end
[ABF20] defines a rank function to associate a permutation to any model of TOTO, composed of two strict
total orders. Here we associate a rank function to any strict total order on bint
. Its type requires
a proof that its range is bint
. Then we prove (with Coq) that rank lt
is injective for any strict
total order lt
. Surjectivity is more difficult to prove. We implement a candidate for an inverse
function (not in [ABF20]). This implementation goes through a constructive definition of the minimum
and maximum of a strict total order on bint
, and of a function succ
.
module Rank use ref.Ref use int.Int use int.NumOf use map.Map use NumOfExt use MapInjSurjBij clone export Interval with axiom .
All that follows is defined for the clones of low
, up
and bint
introduced here.
predicate trans (rel : 'a -> 'a -> bool) = forall x y z:'a. rel x y -> rel y z -> rel x z predicate asymm (rel : 'a -> 'a -> bool) = forall x y:'a. rel x y -> not rel y x predicate partialStrictOrder (rel : 'a -> 'a -> bool) = trans rel /\ asymm rel predicate trichotomy (rel : 'a -> 'a -> bool) = forall x y:'a. rel x y \/ rel y x \/ x = y predicate totalStrictOrder (rel : 'a -> 'a -> bool) = partialStrictOrder rel /\ trichotomy rel lemma irrefl : forall lt : 'a -> 'a -> bool. asymm lt -> forall a:'a. lt a a = false
An asymmetric relation lt
is irreflexive. Helps the proofs of numof_max
and rank'vc
.
let predicate lt_int (lt : bint -> bint -> bool) (a:bint) (j:int) = low <= j <= up && lt (of_int j) a lemma numof_max : forall lt : bint -> bint -> bool. asymm lt -> forall a:bint. numof (lt_int lt a) low (up+1) <= up - low
Consequence of irreflexivity of lt
and lemma Numof_no_add
.
let predicate lt_map (m: map bint bint) (i j:bint) = lt_bint m[i] m[j] lemma lt_map_bij_sto: forall sigma : map bint bint. bijective sigma -> totalStrictOrder (fun i -> fun j -> lt_map sigma i j)
The image of a bijective application by lt_map
is a total strict order.
Similar to ModelSTOI but with Boolean functions instead of predicates.
let function rank (lt : bint -> bint -> bool) (a:bint) : bint requires { totalStrictOrder lt } = of_int ((numof (lt_int lt a) low (up+1)) + low)
rank'vc
is about the range of rank
.
The lower bound is a consequence of lemma int.NumOf.Numof_bounds.
The upper bound is a consequence of numof_max
.
lemma rank_lt_inj: forall lt : bint -> bint -> bool. totalStrictOrder lt -> injective (rank lt)
If lt
is a strict total order then rank lt
is injective.
predicate is_max_left (lt : bint -> bint -> bool) (m:bint) (i:int) = forall j. low <= j <= i -> lt (of_int j) m \/ of_int j = m
(is_max_left lt m i)
iff m
is the maximum of lt
on [of_int low
..of_int i
].
predicate is_max (lt : bint -> bint -> bool) (m:bint) = is_max_left lt m up
(is_max lt m)
iff m
is the maximum of lt
on bint
.
let function max (lt : bint -> bint -> bool) : bint requires { totalStrictOrder lt } ensures { is_max lt result } = let ref m = of_int low in for i = low+1 to up do invariant { low+1 <= i <= up+1 } invariant { is_max_left lt m (i-1) } let j = of_int i in if lt m j then m := j done; m
max lt
is the maximal number for lt
.
lemma max_is_max : forall lt : bint -> bint -> bool. totalStrictOrder lt -> forall a. a = max lt <-> is_max lt a predicate is_succ_left (lt : bint -> bint -> bool) (a b:bint) (i:int) = lt a b /\ forall j. low <= j <= i -> let c = of_int j in not (lt a c && lt c b) predicate is_succ (lt : bint -> bint -> bool) (a b:bint) = is_succ_left lt a b up let succ (lt : bint -> bint -> bool) (a:bint) : bint requires { totalStrictOrder lt } requires { a <> max lt } ensures { is_succ lt a result } = let ref i = low in while i <= up && not (lt a (of_int i)) do (* the first loop searches some (of_int i) greater than a *) invariant { low <= i <= up+1 } invariant { forall j. low <= j < i -> not (lt a (of_int j)) } variant { up - i } i := i+1 done; let ref b = of_int i in (* candidate for (succ a) *) i := i+1; while i <= up do (* the second loop improves this (of_int i) greater than a *) invariant { low <= i <= up+1 } invariant { is_succ_left lt a b (i-1) } variant { up - i } let k = of_int i in if lt a k && lt k b then b := k; i := i+1 done; b
Proved with 'Auto Level 3'.
predicate is_min_left (lt : bint -> bint -> bool) (m:bint) (i:int) = forall j. low <= j <= i -> lt m (of_int j) \/ m = of_int j
(is_min_left lt m i)
iff m
is the minimum of lt
on [of_int low
..of_int i
].
predicate is_min (lt : bint -> bint -> bool) (m:bint) = is_min_left lt m up
(is_min lt m)
iff m
is the minimum of lt
on bint
.
let function min (lt : bint -> bint -> bool) : bint requires { totalStrictOrder lt } ensures { is_min lt result } = let ref m = of_int low in for i = low+1 to up do invariant { low+1 <= i <= up+1 } invariant { is_min_left lt m (i-1) } let j = of_int i in if lt j m then m := j done; m
min lt
is the minimal number for lt
.
let function unrank (lt : bint -> bint -> bool) (i:bint) : bint requires { totalStrictOrder lt } = let ref k = i.to_int in let ref j = min lt in while not (j = max lt) && k > low do variant { k+1-low } j := succ lt j; k := k-1 done; j lemma rank_ltK: forall lt. totalStrictOrder lt -> forall i. rank lt (unrank lt i) = i
rank lt
is the left inverse of unrank lt
. Tested in the module Tests' below.
lemma unrank_ltK: forall lt. totalStrictOrder lt -> forall i. unrank lt (rank lt i) = i
unrank lt
is the left inverse of rank lt
. Automatically proved with Alt-Ergo.
Also interactively deduced in Coq from lemmas rank_ltK and rank_lt_inj.
lemma lt_mapK: forall lt. totalStrictOrder lt -> lt_map (rank lt) = lt lemma Proposition1: forall lt. totalStrictOrder lt -> exists sigma. bijective sigma /\ lt_map sigma = lt
Proposition 1 in [Gio21].
end
module Tests use int.Int use array.Array (* Enumerative testing tool *) use Enum.Permutation use SCheck.Test use SCheck.SCheck use SCheck.SCheck_runner let constant size : int = 6 clone export Rank with val low = one, val up = size, axiom . let function array_sto (a:{array int}) : bint -> bint -> bool requires { a.length = size /\ is_permut a } ensures { totalStrictOrder result } = fun x -> fun y -> a[x.to_int-one] < a[y.to_int-one] (* `-one` because `a` is on [0..n-1] whereas `bint` is [`one`..`size`] *)
Strict total order associated to any permutation stored in an array of integers.
let function rank_cancel lt : bool requires { totalStrictOrder lt } = for i = one to size do let j = of_int i in if not (rank lt (unrank lt j) = j) then return false done; true let rank_cancel_array (a:array int) : bool requires { a.length = size /\ is_permut a } = rank_cancel (array_sto a)
Tested function.
let function rank_cancel_test = SCheck_runner.run_tests (Test.make SCheck.(permut_of_size size) rank_cancel_array)
Enumerative test of rank_ltK.
end
Generated by why3doc 1.4.0