mirror of
https://github.com/AdaCore/why3.git
synced 2026-02-12 12:34:55 -08:00
1947 lines
58 KiB
ReStructuredText
1947 lines
58 KiB
ReStructuredText
Technical Information
|
||
=====================
|
||
|
||
.. _sec.proverdetectiondata:
|
||
|
||
Prover Detection
|
||
----------------
|
||
|
||
The data configuration for the automatic detection of installed provers
|
||
is stored in the file :file:`provers-detection-data.conf` typically located
|
||
in directory :file:`/usr/local/share/why3` after installation.
|
||
|
||
.. _sec.whyconffile:
|
||
|
||
The :file:`why3.conf` Configuration File
|
||
----------------------------------------
|
||
|
||
One can use a custom configuration file. The Why3 tools look for it in
|
||
the following order:
|
||
|
||
#. the file specified by the :option:`why3 --config` option,
|
||
|
||
#. the file specified by the environment variable :envvar:`WHY3CONFIG` if set,
|
||
|
||
#. the file :file:`$HOME/.why3.conf` (:file:`$USERPROFILE/.why3.conf` under
|
||
Windows) or, in the case of local installation, :file:`why3.conf` in the
|
||
top directory of Why3 sources.
|
||
|
||
If none of these files exist, a built-in default configuration is used.
|
||
|
||
A section begins with a header inside square brackets and ends at the
|
||
beginning of the next section. The header of a section can be a single
|
||
identifier, e.g., ``[main]``, or it can be composed by a family name and a
|
||
single family argument, e.g., ``[prover alt-ergo]``.
|
||
|
||
Sections contain associations ``key=value``. A value is either an
|
||
integer (e.g., ``-555``), a boolean (``true``, ``false``), or a string
|
||
(e.g., ``"emacs"``). Some specific keys can be attributed multiple values and
|
||
are thus allowed to occur several times inside a given section. In that
|
||
case, the relative order of these associations matters.
|
||
|
||
Extra configuration files
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
In addition to the main configuration file, Why3 commands accept the
|
||
option :option:`why3 --extra-config` to read one or more files
|
||
containing additional configuration option. It allows the user to pass
|
||
extra declarations in prover drivers, as illustrated in
|
||
:numref:`sec.userdrivers`, including declarations for
|
||
realizations, as illustrated in :numref:`sec.realizations`.
|
||
|
||
|
||
.. _sec.drivers:
|
||
|
||
Drivers for External Provers
|
||
----------------------------
|
||
|
||
Drivers for external provers are readable files from directory
|
||
``drivers``. They describe how Why3 should interact
|
||
with external provers.
|
||
|
||
Files with :file:`.drv` extension represent drivers that might be
|
||
associated to a specific solver in the :file:`why3.conf`
|
||
configuration file (see :numref:`sec.whyconffile` for more information);
|
||
files with :file:`.gen` extension are intended to be imported by
|
||
other drivers; finally, files with :file:`.aux` extension are
|
||
automatically generated from the main :file:`Makefile`.
|
||
|
||
.. graphviz:: generated/drivers-smt.dot
|
||
:caption: Driver dependencies for SMT solvers
|
||
:name: fig.drv.smt
|
||
|
||
.. graphviz:: generated/drivers-tptp.dot
|
||
:caption: Driver dependencies for TPTP solvers
|
||
:name: fig.drv.tptp
|
||
|
||
.. graphviz:: generated/drivers-coq.dot
|
||
:caption: Driver dependencies for Coq
|
||
:name: fig.drv.coq
|
||
|
||
.. graphviz:: generated/drivers-isabelle.dot
|
||
:caption: Driver dependencies for Isabelle/HOL
|
||
:name: fig.drv.isabelle
|
||
|
||
.. graphviz:: generated/drivers-pvs.dot
|
||
:caption: Driver dependencies for PVS
|
||
:name: fig.drv.pvs
|
||
|
||
The most important drivers dependencies are shown in the following
|
||
figures: :numref:`fig.drv.smt` shows the drivers files for SMT
|
||
solvers, :numref:`fig.drv.tptp` for TPTP solvers, :numref:`fig.drv.coq`
|
||
for Coq, :numref:`fig.drv.isabelle` for Isabelle/HOL,
|
||
and :numref:`fig.drv.pvs` for PVS.
|
||
|
||
.. _sec.userdrivers:
|
||
|
||
Drivers for User Theories
|
||
-------------------------
|
||
|
||
It is possible for the users to augment the system drivers with extra
|
||
information for their own declared theories. The process is
|
||
described by the following example.
|
||
|
||
First, we define a new theory in a file :file:`bvmisc.mlw`, containing
|
||
|
||
.. code-block:: whyml
|
||
|
||
theory T
|
||
use bv.BV8
|
||
use bv.BV16
|
||
function lsb BV16.t : BV8.t (** least significant bits *)
|
||
function msb BV16.t : BV8.t (** most significant bits *)
|
||
end
|
||
|
||
For such a theory, it is a good idea to declare specific translation
|
||
rules for provers that have a built-in bit-vector support, such as Z3
|
||
and CVC4 in this example. To do so, we write a extension driver file,
|
||
:file:`my.drv`, containing
|
||
|
||
.. code-block:: whyml
|
||
|
||
theory bvmisc.T
|
||
syntax function lsb "((_ extract 7 0) %1)"
|
||
syntax function msb "((_ extract 15 8) %1)"
|
||
end
|
||
|
||
Now to tell Why3 that we would like this driver extension when calling
|
||
Z3 or CVC4, we write an extra configuration file, :file:`my.conf`,
|
||
containing
|
||
|
||
.. code-block::
|
||
|
||
[prover_modifiers]
|
||
prover = "CVC4"
|
||
driver = "my.drv"
|
||
|
||
[prover_modifiers]
|
||
prover = "Z3"
|
||
driver = "my.drv"
|
||
|
||
Finally, to make the whole thing work, we have to call any Why3 command
|
||
with the additional option :option:`why3 --extra-config`, such as
|
||
|
||
::
|
||
|
||
why3 --extra-config=my.conf prove myfile.mlw
|
||
|
||
.. _sec.transformations:
|
||
|
||
Transformations
|
||
---------------
|
||
|
||
This section documents the available transformations. Note that the set
|
||
of available transformations in your own installation is given
|
||
by :why3:tool:`why3 show transformations`.
|
||
|
||
.. why3:transform:: apply
|
||
|
||
Apply an hypothesis to the goal of the task using a *modus ponens*
|
||
rule. The hypothesis should be an implication whose conclusion can be
|
||
matched with the goal. The intuitive behavior
|
||
of :why3:transform:`apply` can be translated as follows.
|
||
Given :math:`\Gamma, h: f_1 \rightarrow f_2 \vdash G: f_2`, ``apply h``
|
||
generates a new task :math:`\Gamma, h: f_1 \rightarrow f_2 \vdash G: f_1`.
|
||
|
||
In practice, the transformation also manages to instantiate some variables
|
||
with the appropriate terms.
|
||
|
||
For example, applying the transformation ``apply zero_is_even`` on the
|
||
following goal
|
||
|
||
.. code-block:: whyml
|
||
|
||
predicate is_even int
|
||
predicate is_zero int
|
||
axiom zero_is_even: forall x: int. is_zero x -> is_even x
|
||
goal G: is_even 0
|
||
|
||
produces the following goal:
|
||
|
||
.. code-block:: whyml
|
||
|
||
predicate is_even int
|
||
predicate is_zero int
|
||
axiom zero_is_even: forall x:int. is_zero x -> is_even x
|
||
goal G: is_zero 0
|
||
|
||
The transformation first matched the goal against the hypothesis and
|
||
instantiated ``x`` with ``0``. It then applied the *modus ponens* rule
|
||
to generate the new goal.
|
||
|
||
This transformation helps automated provers when they do not know
|
||
which hypothesis to use in order to prove a goal.
|
||
|
||
.. why3:transform:: apply with
|
||
|
||
Variant of :why3:transform:`apply` intended to be used in contexts
|
||
where the latter cannot infer what terms to use for variables given in
|
||
the applied hypothesis.
|
||
|
||
For example, applying the transformation ``apply transitivity`` on the
|
||
following goal
|
||
|
||
.. code-block:: whyml
|
||
|
||
axiom ac: a = c
|
||
axiom cb: c = b
|
||
axiom transitivity : forall x y z:int. x = y -> y = z -> x = z
|
||
goal G1 : a = b
|
||
|
||
raises the following error:
|
||
|
||
::
|
||
|
||
apply: Unable to infer arguments (try using "with") for: y
|
||
|
||
It means that the tool is not able to infer the right term to
|
||
instantiate symbol ``y``. In our case, the user knows that the term
|
||
``c`` should work. So, it can be specified as follows:
|
||
``apply transitivity with c``
|
||
|
||
This generates two goals which are easily provable with hypotheses
|
||
``ac`` and ``cb``.
|
||
|
||
When multiple variables are needed, they should be provided as a list
|
||
in the transformation. For the sake of the example, we complicate
|
||
the ``transitivity`` hypothesis:
|
||
|
||
.. code-block:: whyml
|
||
|
||
axiom t : forall x y z k:int. k = k -> x = y -> y = z -> x = z
|
||
|
||
A value can be provided for ``k`` as follows: ``apply t with c,0``.
|
||
|
||
.. why3:transform:: assert
|
||
|
||
Create an intermediate subgoal. This is comparable to ``assert``
|
||
written in WhyML code. Here, the intent is only to help provers by
|
||
specifying one key argument of the reasoning they should use.
|
||
|
||
Example: From a goal of the form :math:`\Gamma \vdash G`, the
|
||
transformation ``assert (n = 0)`` produces the following two
|
||
tasks: :math:`\Gamma \vdash h: n = 0` and :math:`\Gamma, h: n =
|
||
0 \vdash G`. This effectively adds ``h`` as an intermediate goal to prove.
|
||
|
||
.. why3:transform:: assert as
|
||
|
||
Same as :why3:transform:`assert`, except that a name can be given to
|
||
the new hypothesis. Example: ``assert (x = 0) as x0``.
|
||
|
||
.. why3:transform:: case
|
||
|
||
Split a goal into two subgoals, using the *excluded middle* on a given
|
||
formula. On the task :math:`\Gamma \vdash G`, the transformation
|
||
``case f`` produces two tasks: :math:`\Gamma, h: f \vdash G` and
|
||
:math:`\Gamma, h: \neg f \vdash G`.
|
||
|
||
For example, applying ``case (x = 0)`` on the following goals
|
||
|
||
.. code-block:: whyml
|
||
|
||
constant x : int
|
||
constant y : int
|
||
goal G: if x = 0 then y = 2 else y = 3
|
||
|
||
produces the following goals:
|
||
|
||
.. code-block:: whyml
|
||
|
||
constant x : int
|
||
constant y : int
|
||
axiom h : x = 0
|
||
goal G : if x = 0 then y = 2 else y = 3
|
||
|
||
.. code-block:: whyml
|
||
|
||
constant x : int
|
||
constant y : int
|
||
axiom h : not x = 0
|
||
goal G : if x = 0 then y = 2 else y = 3
|
||
|
||
The intent is again to simplify the job of automated provers by giving
|
||
them a key argument of the reasoning behind the proof of a subgoal.
|
||
|
||
.. why3:transform:: case as
|
||
|
||
Same as :why3:transform:`case`, except that a name can be given to
|
||
the new hypothesis. Example: ``case (x = 0) as x0``.
|
||
|
||
.. why3:transform:: clear_but
|
||
|
||
Remove all the hypotheses except those specified in the arguments.
|
||
This is useful when a prover fails to find relevant hypotheses in
|
||
a very large context. Example: ``clear_but h23,h25``.
|
||
|
||
.. why3:transform:: compute_hyp
|
||
|
||
Apply the transformation :why3:transform:`compute_in_goal` on the given
|
||
hypothesis.
|
||
|
||
.. why3:transform:: compute_hyp_specified
|
||
|
||
Apply the transformation :why3:transform:`compute_specified` on the
|
||
given hypothesis.
|
||
|
||
.. why3:transform:: compute_in_goal
|
||
|
||
Aggressively apply all known computation/simplification rules.
|
||
|
||
The kinds of simplification are as follows.
|
||
|
||
- Computations with built-in symbols, e.g., operations on integers, when
|
||
applied to explicit constants, are evaluated. This includes
|
||
evaluation of equality when a decision can be made (on integer
|
||
constants, on constructors of algebraic data types), Boolean
|
||
evaluation, simplification of pattern-matching/conditional
|
||
expression, extraction of record fields, and beta-reduction. At best,
|
||
these computations reduce the goal to ``true`` and the
|
||
transformations thus does not produce any sub-goal. For example, a
|
||
goal like ``6*7=42`` is solved by those transformations.
|
||
|
||
- Unfolding of definitions, as done by :why3:transform:`inline_goal`. Transformation
|
||
:why3:transform:`compute_in_goal` unfolds all definitions, including recursive
|
||
ones. For :why3:transform:`compute_specified`, the user can enable unfolding of a
|
||
specific logic symbol by attaching the meta :why3:meta:`rewrite_def` to the
|
||
symbol.
|
||
|
||
.. code-block:: whyml
|
||
|
||
function sqr (x:int) : int = x * x
|
||
meta "rewrite_def" function sqr
|
||
|
||
- Rewriting using axioms or lemmas declared as rewrite rules. When an
|
||
axiom (or a lemma) has one of the forms
|
||
|
||
.. code-block:: whyml
|
||
|
||
axiom a: forall ... t1 = t2
|
||
|
||
or
|
||
|
||
.. code-block:: whyml
|
||
|
||
axiom a: forall ... f1 <-> f2
|
||
|
||
then the user can declare
|
||
|
||
.. code-block:: whyml
|
||
|
||
meta "rewrite" prop a
|
||
|
||
to turn this axiom into a rewrite rule. Rewriting is always done from
|
||
left to right. Beware that there is no check for termination nor for
|
||
confluence of the set of rewrite rules declared.
|
||
|
||
Instead of using a meta, it is possible to declare an axiom as a rewrite
|
||
rule by adding the :why3:attribute:`[@rewrite]` attribute on the axiom name or on the
|
||
axiom itself, e.g.,
|
||
|
||
.. code-block:: whyml
|
||
|
||
axiom a [@rewrite]: forall ... t1 = t2
|
||
lemma b: [@rewrite] forall ... f1 <-> f2
|
||
|
||
The second form allows some form of local rewriting, e.g.,
|
||
|
||
.. code-block:: whyml
|
||
|
||
lemma l: forall x y. ([@rewrite] x = y) -> f x = f y
|
||
|
||
can be proved by :why3:transform:`introduce_premises` followed by
|
||
:why3:transform:`compute_specified`.
|
||
|
||
The computations performed by this transformation can take an
|
||
arbitrarily large number of steps, or even not terminate. For this
|
||
reason, the number of steps is bounded by a maximal value, which is set
|
||
by default to 1000. This value can be increased by another meta, e.g.,
|
||
|
||
.. code-block:: whyml
|
||
|
||
meta "compute_max_steps" 1_000_000
|
||
|
||
When this upper limit is reached, a warning is issued, and the
|
||
partly-reduced goal is returned as the result of the transformation.
|
||
|
||
.. why3:transform:: compute_specified
|
||
|
||
Same as :why3:transform:`compute_in_goal`, but perform rewriting using
|
||
only built-in operators and user-provided rules.
|
||
|
||
.. why3:transform:: cut
|
||
|
||
Same as :why3:transform:`assert`, but the order of the generated subgoals
|
||
is reversed.
|
||
|
||
.. why3:transform:: destruct
|
||
|
||
Eliminate the head symbol of a hypothesis.
|
||
|
||
For example, applying ``destruct h`` on the following goal
|
||
|
||
.. code-block:: whyml
|
||
|
||
constant p1 : bool
|
||
predicate p2 int
|
||
axiom h : p1 = True /\ (forall x:int. p2 x)
|
||
goal G : p2 0
|
||
|
||
removes the logical connective ``/\`` and produces
|
||
|
||
.. code-block:: whyml
|
||
|
||
constant p1 : bool
|
||
predicate p2 int
|
||
axiom h1 : p1 = True
|
||
axiom h : forall x:int. p2 x
|
||
goal G : p2 0
|
||
|
||
:why3:transform:`destruct` can be applied on the following constructions:
|
||
|
||
- ``false``, ``true``,
|
||
- ``/\``, ``\/``, ``->``, ``not``,
|
||
- ``exists``,
|
||
- ``if ... then ... else ...``,
|
||
- ``match ... with ... end``,
|
||
- (in)equality on constructors of the same type.
|
||
|
||
.. why3:transform:: destruct_rec
|
||
|
||
Recursively call :why3:transform:`destruct` on the generated
|
||
hypotheses. The recursion on implication and ``match`` stops after the
|
||
first occurrence of a different symbol.
|
||
|
||
For example, applying ``destruct_rec H`` on the following goal
|
||
|
||
.. code-block:: whyml
|
||
|
||
predicate a
|
||
predicate b
|
||
predicate c
|
||
axiom H : (a -> b) /\ (b /\ c)
|
||
goal G : false
|
||
|
||
does not destruct the implication symbol because it occurs as
|
||
a subterm of an already destructed symbol. This restriction applies
|
||
only to implication and ``match`` Other symbols are destructed
|
||
recursively. Thus, in the generated task, the second ``/\`` is
|
||
simplified:
|
||
|
||
.. code-block:: whyml
|
||
|
||
predicate a
|
||
predicate b
|
||
predicate c
|
||
axiom H2 : a -> b
|
||
axiom H1 : b
|
||
axiom H: c
|
||
goal G : false
|
||
|
||
.. why3:transform:: destruct_term
|
||
|
||
Destruct an expression according to the type of the expression. The
|
||
transformation produces all possible outcomes of a destruction of the
|
||
algebraic type.
|
||
|
||
For example, applying ``destruct_term a`` on the following goal
|
||
|
||
.. code-block:: whyml
|
||
|
||
type t = A | B int
|
||
constant a : t
|
||
goal G : a = A
|
||
|
||
produces the following two goals:
|
||
|
||
.. code-block:: whyml
|
||
|
||
type t = A | B int
|
||
constant a : t
|
||
constant x : int
|
||
axiom h : a = B x
|
||
goal G : a = A
|
||
|
||
.. code-block:: whyml
|
||
|
||
type t = A | B int
|
||
constant a : t
|
||
axiom h : a = A
|
||
goal G : a = A
|
||
|
||
The term was destructed according to all the possible outcomes in the
|
||
type. Note that, during destruction, a new constant ``x`` has been
|
||
introduced for the argument of constructor ``B``.
|
||
|
||
.. why3:transform:: destruct_term using
|
||
|
||
Same as :why3:transform:`destruct_term`, except that names can be given to
|
||
the constants that were generated.
|
||
|
||
.. why3:transform:: destruct_term_subst
|
||
|
||
Same as :why3:transform:`destruct_term`, except that it also
|
||
substitutes the created term.
|
||
|
||
.. why3:transform:: eliminate_algebraic
|
||
|
||
Replace algebraic data types by first-order definitions :cite:`paskevich09rr`.
|
||
|
||
.. why3:transform:: eliminate_builtin
|
||
|
||
Remove definitions of symbols that are declared as builtin in the
|
||
driver, with a “syntax” rule.
|
||
|
||
.. why3:transform:: eliminate_definition_func
|
||
|
||
Replace all function definitions with axioms.
|
||
|
||
.. why3:transform:: eliminate_definition_pred
|
||
|
||
Replace all predicate definitions with axioms.
|
||
|
||
.. why3:transform:: eliminate_definition
|
||
|
||
Apply both :why3:transform:`eliminate_definition_func` and
|
||
:why3:transform:`eliminate_definition_pred`.
|
||
|
||
.. why3:transform:: eliminate_if
|
||
|
||
Apply both :why3:transform:`eliminate_if_term` and :why3:transform:`eliminate_if_fmla`.
|
||
|
||
.. why3:transform:: eliminate_if_fmla
|
||
|
||
Replace formulas of the form ``if f1 then f2 else f3`` by an
|
||
equivalent formula using implications and other connectives.
|
||
|
||
.. why3:transform:: eliminate_if_term
|
||
|
||
Replace terms of the form ``if formula then t2 else t3`` by lifting
|
||
them at the level of formulas. This may introduce ``if then else``
|
||
in formulas.
|
||
|
||
.. why3:transform:: eliminate_inductive
|
||
|
||
Replace inductive predicates by (incomplete) axiomatic definitions,
|
||
construction axioms and an inversion axiom.
|
||
|
||
.. why3:transform:: eliminate_let
|
||
|
||
Apply both :why3:transform:`eliminate_let_fmla` and :why3:transform:`eliminate_let_term`.
|
||
|
||
.. why3:transform:: eliminate_let_fmla
|
||
|
||
Eliminate ``let`` by substitution, at the predicate level.
|
||
|
||
.. why3:transform:: eliminate_let_term
|
||
|
||
Eliminate ``let`` by substitution, at the term level.
|
||
|
||
.. why3:transform:: eliminate_literal
|
||
|
||
.. why3:transform:: eliminate_mutual_recursion
|
||
|
||
Replace mutually recursive definitions with axioms.
|
||
|
||
.. why3:transform:: eliminate_recursion
|
||
|
||
Replace all recursive definitions with axioms.
|
||
|
||
.. why3:transform:: encoding_smt
|
||
|
||
Encode polymorphic types into monomorphic types :cite:`conchon08smt`.
|
||
|
||
.. why3:transform:: encoding_tptp
|
||
|
||
Encode theories into unsorted logic.
|
||
|
||
.. why3:transform:: exists
|
||
|
||
Instantiate an existential quantification with a witness.
|
||
|
||
For example, applying ``exists 0`` on the following goal
|
||
|
||
.. code-block:: whyml
|
||
|
||
goal G : exists x:int. x = 0
|
||
|
||
instantiates the symbol ``x`` with ``0``. Thus, the goal becomes
|
||
|
||
.. code-block:: whyml
|
||
|
||
goal G : 0 = 0
|
||
|
||
.. why3:transform:: hide
|
||
|
||
Hide a given term, by creating a new constant equal to the term and
|
||
then replacing all occurrences of the term in the context by this
|
||
constant.
|
||
|
||
For example, applying ``hide t (1 + 1)`` on the goal
|
||
|
||
.. code-block:: whyml
|
||
|
||
constant y : int
|
||
axiom h : forall x:int. x = (1 + 1)
|
||
goal G : (y - (1 + 1)) = ((1 + 1) - (1 + 1))
|
||
|
||
replaces all the occurrences of ``(1 + 1)`` with ``t``, which gives
|
||
the following goal:
|
||
|
||
.. code-block:: whyml
|
||
|
||
constant y : int
|
||
constant t : int
|
||
axiom H : t = (1 + 1)
|
||
axiom h : forall x:int. x = t
|
||
goal G : (y - t) = (t - t)
|
||
|
||
.. why3:transform:: hide_and_clear
|
||
|
||
First apply :why3:transform:`hide` and then remove the equality
|
||
between the hidden term and the introduced constant. This means that
|
||
the hidden term completely disappears and cannot be recovered.
|
||
|
||
.. why3:transform:: induction
|
||
|
||
Perform a reasoning by induction for the current goal.
|
||
|
||
For example, applying ``induction n`` on the following goal
|
||
|
||
.. code-block:: whyml
|
||
|
||
constant n : int
|
||
predicate p int
|
||
predicate p1 int
|
||
axiom h : p1 n
|
||
goal G : p n
|
||
|
||
performs an induction on ``n`` starting at ``0``. The goal for the
|
||
base case is
|
||
|
||
.. code-block:: whyml
|
||
|
||
constant n : int
|
||
predicate p int
|
||
predicate p1 int
|
||
axiom h : p1 n
|
||
axiom Init : n <= 0
|
||
goal G : p n
|
||
|
||
while the recursive case is
|
||
|
||
.. code-block:: whyml
|
||
|
||
constant n : int
|
||
predicate p int
|
||
predicate p1 int
|
||
axiom h : p1 n
|
||
axiom Init : 0 < n
|
||
axiom Hrec : forall n1:int. n1 < n -> p1 n1 -> p n1
|
||
goal G : p n
|
||
|
||
.. why3:transform:: induction from
|
||
|
||
Same as :why3:transform:`induction`, but it starts the induction from
|
||
a given integer instead of ``0``.
|
||
|
||
.. why3:transform:: induction_arg_pr
|
||
|
||
Apply :why3:transform:`induction_pr` on the given hypothesis/goal symbol.
|
||
|
||
.. why3:transform:: induction_arg_ty_lex
|
||
|
||
Apply :why3:transform:`induction_ty_lex` on the given symbol.
|
||
|
||
.. why3:transform:: induction_pr
|
||
|
||
.. why3:transform:: induction_ty_lex
|
||
|
||
Perform structural, lexicographic induction on goals involving
|
||
universally quantified variables of algebraic data types, such as
|
||
lists, trees, etc. For instance, it transforms the following goal
|
||
|
||
.. code-block:: whyml
|
||
|
||
goal G: forall l: list 'a. length l >= 0
|
||
|
||
into this one:
|
||
|
||
.. code-block:: whyml
|
||
|
||
goal G :
|
||
forall l:list 'a.
|
||
match l with
|
||
| Nil -> length l >= 0
|
||
| Cons a l1 -> length l1 >= 0 -> length l >= 0
|
||
end
|
||
|
||
When induction can be applied to several variables, the
|
||
transformation picks one heuristically. The :why3:attribute:`[@induction]`
|
||
attribute can be used to force induction over one particular
|
||
variable, with
|
||
|
||
.. code-block:: whyml
|
||
|
||
goal G: forall l1 [@induction] l2 l3: list 'a.
|
||
l1 ++ (l2 ++ l3) = (l1 ++ l2) ++ l3
|
||
|
||
induction will be applied on ``l1``. If this attribute is attached
|
||
to several variables, a lexicographic induction is performed on
|
||
these variables, from left to right.
|
||
|
||
.. why3:transform:: inline_trivial
|
||
|
||
Expand and remove definitions of the form
|
||
|
||
.. code-block:: whyml
|
||
|
||
function f x1 ... xn = g e1 ... ek
|
||
predicate p x1 ... xn = q e1 ... ek
|
||
|
||
when each :samp:`e{i}` is either a ground term or one of the
|
||
:samp:`x{j}`, and each ``x1 ... xn`` occurs at most once in
|
||
all the :samp:`e{i}`.
|
||
|
||
The attribute :why3:attribute:`[@inline:trivial]` can be used to tag functions, so
|
||
that the transformation forcefully expands them (not using the
|
||
conditions above). This can be used to ensure that some specific
|
||
functions are inlined for automatic provers
|
||
(:why3:transform:`inline_trivial` is used in many drivers).
|
||
|
||
.. why3:transform:: inline_goal
|
||
|
||
Expand all outermost symbols of the goal that have a non-recursive
|
||
definition.
|
||
|
||
.. why3:transform:: inline_all
|
||
|
||
Expand all non-recursive definitions.
|
||
|
||
.. why3:transform:: instantiate
|
||
|
||
Generate a new hypothesis with quantified variables
|
||
replaced by the given terms.
|
||
|
||
For example, applying ``instantiate h 0, 1`` on the following goal
|
||
|
||
.. code-block:: whyml
|
||
|
||
predicate p int
|
||
axiom h : forall x:int, y:int. x <= y -> p x /\ p y
|
||
goal G : p 0
|
||
|
||
generates a new hypothesis:
|
||
|
||
.. code-block:: whyml
|
||
|
||
predicate p int
|
||
axiom h : forall x:int, y:int. x <= y -> p x /\ p y
|
||
axiom Hinst : 0 <= 1 -> p 0 /\ p 1
|
||
goal G : p 0
|
||
|
||
This is used to help automatic provers that are generally better at
|
||
working on instantiated hypothesis.
|
||
|
||
.. why3:transform:: inst_rem
|
||
|
||
Apply :why3:transform:`instantiate` then remove the original
|
||
instantiated hypothesis.
|
||
|
||
.. why3:transform:: introduce_premises
|
||
|
||
Move antecedents of implications and universal quantifications of
|
||
the goal into the premises of the task.
|
||
|
||
.. why3:transform:: intros
|
||
|
||
Introduce universal quantifiers in the context.
|
||
|
||
For example, applying ``intros n, m`` on the following goal
|
||
|
||
.. code-block:: whyml
|
||
|
||
predicate p int int int
|
||
goal G : forall x:int, y:int, z:int. p x y z
|
||
|
||
produces the following goal:
|
||
|
||
.. code-block:: whyml
|
||
|
||
predicate p int int int
|
||
constant n : int
|
||
constant m : int
|
||
goal G : forall z:int. p n m z
|
||
|
||
.. why3:transform:: intros_n
|
||
|
||
Same as :why3:transform:`intros`, but stops after the nth quantified
|
||
variable or premise.
|
||
|
||
For example, applying ``intros_n 2`` on the following goal
|
||
|
||
.. code-block:: whyml
|
||
|
||
predicate p int int int
|
||
goal G : forall x:int, y:int, z:int. p x y z
|
||
|
||
produces the following goal:
|
||
|
||
.. code-block:: whyml
|
||
|
||
predicate p int int int
|
||
constant x : int
|
||
constant y : int
|
||
goal G : forall z:int. p x y z
|
||
|
||
.. why3:transform:: inversion_arg_pr
|
||
|
||
Apply :why3:transform:`inversion_pr` on the given hypothesis/goal symbol.
|
||
|
||
.. why3:transform:: inversion_pr
|
||
|
||
.. why3:transform:: left
|
||
|
||
Remove the right part of the head disjunction of the goal.
|
||
|
||
For example, applying ``left`` on the following goal
|
||
|
||
.. code-block:: whyml
|
||
|
||
constant x : int
|
||
goal G : x = 0 \/ x = 1
|
||
|
||
produces the following goal:
|
||
|
||
.. code-block:: whyml
|
||
|
||
constant x : int
|
||
goal G : x = 0
|
||
|
||
.. why3:transform:: pose
|
||
|
||
Add a new constant equal to the given term.
|
||
|
||
For example, applying ``pose t (x + 2)`` to the following goal
|
||
|
||
.. code-block:: whyml
|
||
|
||
constant x : int
|
||
goal G : true
|
||
|
||
produces the following goal:
|
||
|
||
.. code-block:: whyml
|
||
|
||
constant x : int
|
||
constant t : int
|
||
axiom H : t = (x + 2)
|
||
goal G : true
|
||
|
||
.. why3:transform:: remove
|
||
|
||
Remove a hypothesis from the context.
|
||
|
||
For example, applying ``remove h`` on the following goal
|
||
|
||
.. code-block:: whyml
|
||
|
||
axiom h : true
|
||
goal G : true
|
||
|
||
produces the following goal:
|
||
|
||
.. code-block:: whyml
|
||
|
||
goal G : true
|
||
|
||
.. why3:transform:: remove_unused
|
||
|
||
Remove from the context all the logic symbols that are not used by the goal or the hypothesis.
|
||
|
||
The effect of that transformation can be expanded by adding dependency metas. Namely, with a declaration of the form
|
||
|
||
.. code-block:: whyml
|
||
|
||
meta "remove_unused:dependency" axiom a, function f
|
||
|
||
then occurrences of `f` in axiom `a` are not counted as occurrences
|
||
for `f`. The intended meaning is that `a` is a definitional axiom
|
||
for `f`, so when `f` is not needed in the remainder, both the axiom
|
||
and the declaration of `f` can be removed.
|
||
|
||
When there are several such definitional axioms for `f`, a meta
|
||
must be declared for each axiom. When an axiom is definitional for
|
||
several symbols at the same time, several meta must be declared as
|
||
well. The rule of thumb is that an axiom is kept as soon as at
|
||
least one of the symbols it defines is needed in the remainder,
|
||
otherwise it is discarded.
|
||
|
||
.. why3:transform:: remove_unused_keep_constant
|
||
|
||
A variant of :why3:transform:`remove_unused` above, where the constant, i.e. the nullary function symbols, are always kept.
|
||
|
||
The effect of that transformation is controllable with an additional meta of the form
|
||
|
||
.. code-block:: whyml
|
||
|
||
meta "remove_unused:remove_constant" constant f
|
||
|
||
when in that case `f` is also tried to be removed, as if it was
|
||
with the full :why3:transform:`remove_unused` transformation.
|
||
|
||
.. why3:transform:: replace
|
||
|
||
Replace a term with another one in a hypothesis or in the goal. This
|
||
generates a new goal which asks for the proof of the equality.
|
||
|
||
For example, applying ``replace (y + 1) (x + 2) in h`` on the
|
||
following goal
|
||
|
||
.. code-block:: whyml
|
||
|
||
constant x : int
|
||
constant y : int
|
||
axiom h : x >= (y + 1)
|
||
goal G : true
|
||
|
||
produces the following two goals:
|
||
|
||
.. code-block:: whyml
|
||
|
||
constant x : int
|
||
constant y : int
|
||
axiom h : x >= (x + 2)
|
||
goal G : true
|
||
|
||
.. code-block:: whyml
|
||
|
||
constant x : int
|
||
constant y : int
|
||
axiom h : x >= (y + 1)
|
||
goal G : (y + 1) = (x + 2)
|
||
|
||
It can be seen as the combination of :why3:transform:`assert`
|
||
and :why3:transform:`rewrite`.
|
||
|
||
.. why3:transform:: revert
|
||
|
||
Opposite of :why3:transform:`intros`. It takes hypotheses/constants
|
||
and quantifies them in the goal.
|
||
|
||
For example, applying ``revert x`` on the following goal
|
||
|
||
.. code-block:: whyml
|
||
|
||
constant x : int
|
||
constant y : int
|
||
axiom h : x = y
|
||
goal G : true
|
||
|
||
produces the following goal:
|
||
|
||
.. code-block:: whyml
|
||
|
||
constant y : int
|
||
goal G : forall x:int. x = y -> true
|
||
|
||
.. why3:transform:: rewrite
|
||
|
||
Rewrite using the given equality hypothesis.
|
||
|
||
For example, applying ``rewrite eq`` on the following goal
|
||
|
||
.. code-block:: whyml
|
||
|
||
function a int : bool
|
||
function b int : bool
|
||
constant y : int
|
||
axiom eq : forall x:int. not x = 0 -> a x = b x
|
||
goal G : a y = True
|
||
|
||
produces the following goal:
|
||
|
||
.. code-block:: whyml
|
||
|
||
function a int : bool
|
||
function b int : bool
|
||
constant y : int
|
||
axiom eq : forall x:int. not x = 0 -> a x = b x
|
||
goal G : b y = True
|
||
|
||
It also produces a goal for the premise of the equality hypothesis (as
|
||
would :why3:transform:`apply`):
|
||
|
||
.. code-block:: whyml
|
||
|
||
function a int : bool
|
||
function b int : bool
|
||
constant y : int
|
||
axiom eq : forall x:int. not x = 0 -> a x = b x
|
||
goal G : not y = 0
|
||
|
||
.. why3:transform:: rewrite with
|
||
|
||
Variant of :why3:transform:`rewrite` intended to be used in contexts
|
||
where the latter cannot infer what terms to use for the variables of
|
||
the given hypotheses (see also :why3:transform:`apply with`).
|
||
|
||
For example, the transformation ``rewrite eq with 0`` can be applied
|
||
to the following goal:
|
||
|
||
.. code-block:: whyml
|
||
|
||
function a int : bool
|
||
function b int : bool
|
||
constant y : int
|
||
axiom eq : forall x:int, z:int. z = 0 -> not x = 0 -> a x = b x
|
||
goal G : a y = True
|
||
|
||
Here, a value is provided for the symbol ``z``. This leads to the
|
||
following three goals. One is the rewritten one, while the other two
|
||
are for the premises of the equality hypothesis.
|
||
|
||
.. code-block:: whyml
|
||
|
||
function a int : bool
|
||
function b int : bool
|
||
constant y : int
|
||
axiom eq : forall x:int, z:int. z = 0 -> not x = 0 -> a x = b x
|
||
goal G : b y = True
|
||
|
||
.. code-block:: whyml
|
||
|
||
function a int : bool
|
||
function b int : bool
|
||
constant y : int
|
||
axiom eq : forall x:int, z:int. z = 0 -> not x = 0 -> a x = b x
|
||
goal G : 0 = 0
|
||
|
||
.. code-block:: whyml
|
||
|
||
function a int : bool
|
||
function b int : bool
|
||
constant y : int
|
||
axiom eq : forall x:int, z:int. z = 0 -> not x = 0 -> a x = b x
|
||
goal G : not y = 0
|
||
|
||
.. why3:transform:: rewrite_list
|
||
|
||
Variant of :why3:transform:`rewrite` that allows simultaneous rewriting in
|
||
a list of hypothesis/goals.
|
||
|
||
.. why3:transform:: right
|
||
|
||
Remove the left part of the head disjunction of the goal.
|
||
|
||
For example, applying ``right`` on the following goal
|
||
|
||
.. code-block:: whyml
|
||
|
||
constant x : int
|
||
goal G : x = 0 \/ x = 1
|
||
|
||
produces the following goal:
|
||
|
||
.. code-block:: whyml
|
||
|
||
constant x : int
|
||
goal G : x = 1
|
||
|
||
.. why3:transform:: simplify_array
|
||
|
||
Automatically rewrite the task using the lemma ``Select_eq`` of
|
||
theory ``map.Map``.
|
||
|
||
.. why3:transform:: simplify_formula
|
||
|
||
Reduce trivial equalities ``t=t`` to true and then simplify
|
||
propositional structure: removes ``true``, ``false``, simplifies
|
||
``f /\ f`` to ``f``, etc.
|
||
|
||
.. why3:transform:: simplify_formula_and_task
|
||
|
||
Apply :why3:transform:`simplify_formula` and remove the goal if
|
||
it is equivalent to true.
|
||
|
||
.. why3:transform:: simplify_recursive_definition
|
||
|
||
Reduce mutually recursive definitions if they are not really
|
||
mutually recursive, e.g.,
|
||
|
||
::
|
||
|
||
function f : ... = ... g ...
|
||
with g : ... = e
|
||
|
||
becomes
|
||
|
||
::
|
||
|
||
function g : ... = e
|
||
function f : ... = ... g ...
|
||
|
||
if ``f`` does not occur in ``e``.
|
||
|
||
.. why3:transform:: simplify_trivial_quantification
|
||
|
||
Simplify quantifications of the form
|
||
|
||
::
|
||
|
||
forall x, x = t -> P(x)
|
||
|
||
into
|
||
|
||
::
|
||
|
||
P(t)
|
||
|
||
when ``x`` does not occur in ``t``. More generally, this
|
||
simplification is applied whenever ``x=t`` or ``t=x``
|
||
appears in negative position.
|
||
|
||
.. why3:transform:: simplify_trivial_quantification_in_goal
|
||
|
||
Apply :why3:transform:`simplify_trivial_quantification`, but only in the goal.
|
||
|
||
.. why3:transform:: split_all
|
||
|
||
Perform both :why3:transform:`split_premise` and :why3:transform:`split_goal`.
|
||
|
||
.. why3:transform:: split_all_full
|
||
|
||
Perform both :why3:transform:`split_premise` and :why3:transform:`split_goal_full`.
|
||
|
||
.. why3:transform:: split_goal
|
||
|
||
Change conjunctive goals into the corresponding set of subgoals. In
|
||
absence of case analysis attributes, the number of subgoals
|
||
generated is linear in the size of the initial goal.
|
||
|
||
The transformation treats specially asymmetric and ``by``/``so``
|
||
connectives. Asymmetric conjunction ``A && B`` in goal position is
|
||
handled as syntactic sugar for ``A /\ (A -> B)``. The conclusion of
|
||
the first subgoal can then be used to prove the second one.
|
||
|
||
Asymmetric disjunction ``A || B`` in hypothesis position is handled
|
||
as syntactic sugar for ``A \/ ((not A) /\ B)``. In particular, a
|
||
case analysis on such hypothesis would give the negation of the
|
||
first hypothesis in the second case.
|
||
|
||
The ``by`` connective is treated as a proof indication. In
|
||
hypothesis position, ``A by B`` is treated as if it were syntactic
|
||
sugar for its regular interpretation ``A``. In goal position, it is
|
||
treated as if ``B`` was an intermediate step for proving ``A``.
|
||
``A by B`` is then replaced by ``B`` and the transformation also
|
||
generates a side-condition subgoal ``B -> A`` representing the
|
||
logical cut.
|
||
|
||
Although splitting stops at disjunctive points like symmetric
|
||
disjunction and left-hand sides of implications, the occurrences of
|
||
the ``by`` connective are not restricted. For instance:
|
||
|
||
- Splitting
|
||
|
||
::
|
||
|
||
goal G : (A by B) && C
|
||
|
||
generates the subgoals
|
||
|
||
::
|
||
|
||
goal G1 : B
|
||
goal G2 : A -> C
|
||
goal G3 : B -> A (* side-condition *)
|
||
|
||
- Splitting
|
||
|
||
::
|
||
|
||
goal G : (A by B) \/ (C by D)
|
||
|
||
generates
|
||
|
||
::
|
||
|
||
goal G1 : B \/ D
|
||
goal G2 : B -> A (* side-condition *)
|
||
goal G3 : D -> C (* side-condition *)
|
||
|
||
- Splitting
|
||
|
||
::
|
||
|
||
goal G : (A by B) || (C by D)
|
||
|
||
generates
|
||
|
||
::
|
||
|
||
goal G1 : B || D
|
||
goal G2 : B -> A (* side-condition *)
|
||
goal G3 : B || (D -> C) (* side-condition *)
|
||
|
||
Note that due to the asymmetric disjunction, the disjunction is
|
||
kept in the second side-condition subgoal.
|
||
|
||
- Splitting
|
||
|
||
::
|
||
|
||
goal G : exists x. P x by x = 42
|
||
|
||
generates
|
||
|
||
::
|
||
|
||
goal G1 : exists x. x = 42
|
||
goal G2 : forall x. x = 42 -> P x (* side-condition *)
|
||
|
||
Note that in the side-condition subgoal, the context is
|
||
universally closed.
|
||
|
||
The ``so`` connective plays a similar role in hypothesis position,
|
||
as it serves as a consequence indication. In goal position,
|
||
``A so B`` is treated as if it were syntactic sugar for its regular
|
||
interpretation ``A``. In hypothesis position, it is treated as if
|
||
both ``A`` and ``B`` were true because ``B`` is a consequence of
|
||
``A``. ``A so B`` is replaced by ``A /\ B`` and the transformation
|
||
also generates a side-condition subgoal ``A -> B`` corresponding to
|
||
the consequence relation between formula.
|
||
|
||
As with the ``by`` connective, occurrences of ``so`` are
|
||
unrestricted. Examples:
|
||
|
||
- Splitting
|
||
|
||
::
|
||
|
||
goal G : (((A so B) \/ C) -> D) && E
|
||
|
||
generates
|
||
|
||
::
|
||
|
||
goal G1 : ((A /\ B) \/ C) -> D
|
||
goal G2 : (A \/ C -> D) -> E
|
||
goal G3 : A -> B (* side-condition *)
|
||
|
||
- Splitting
|
||
|
||
::
|
||
|
||
goal G : A by exists x. P x so Q x so R x by T x
|
||
(* reads: A by (exists x. P x so (Q x so (R x by T x))) *)
|
||
|
||
generates
|
||
|
||
::
|
||
|
||
goal G1 : exists x. P x
|
||
goal G2 : forall x. P x -> Q x (* side-condition *)
|
||
goal G3 : forall x. P x -> Q x -> T x (* side-condition *)
|
||
goal G4 : forall x. P x -> Q x -> T x -> R x (* side-condition *)
|
||
goal G5 : (exists x. P x /\ Q x /\ R x) -> A (* side-condition *)
|
||
|
||
In natural language, this corresponds to the following proof
|
||
scheme for ``A``: There exists a ``x`` for which ``P`` holds.
|
||
Then, for that witness ``Q`` and ``R`` also holds. The last one
|
||
holds because ``T`` holds as well. And from those three
|
||
conditions on ``x``, we can deduce ``A``.
|
||
|
||
The transformations in the “split” family can be controlled by using
|
||
attributes on formulas.
|
||
|
||
The :why3:attribute:`[@stop_split]` attribute can be used to block the splitting
|
||
of a formula. The attribute is removed after blocking, so applying
|
||
the transformation a second time will split the formula. This is can
|
||
be used to decompose the splitting process in several steps. Also,
|
||
if a formula with this attribute is found in non-goal position, its
|
||
``by``/``so`` proof indication will be erased by the transformation.
|
||
In a sense, formulas tagged by :why3:attribute:`[@stop_split]` are handled as if
|
||
they were local lemmas.
|
||
|
||
The :why3:attribute:`[@case_split]` attribute can be used to force case analysis
|
||
on hypotheses. For instance, applying :why3:transform:`split_goal` on
|
||
|
||
::
|
||
|
||
goal G : ([@case_split] A \/ B) -> C
|
||
|
||
generates the subgoals
|
||
|
||
::
|
||
|
||
goal G1 : A -> C
|
||
goal G2 : B -> C
|
||
|
||
Without the attribute, the transformation does nothing because
|
||
undesired case analysis may easily lead to an exponential blow-up.
|
||
|
||
Note that the precise behavior of splitting transformations in
|
||
presence of the :why3:attribute:`[@case_split]` attribute is not yet specified and
|
||
is likely to change in future versions.
|
||
|
||
.. why3:transform:: split_goal_full
|
||
|
||
Behave similarly to :why3:transform:`split_goal`, but also convert the goal
|
||
to conjunctive normal form. The number of subgoals generated may be
|
||
exponential in the size of the initial goal.
|
||
|
||
.. why3:transform:: split_intro
|
||
|
||
Perform both :why3:transform:`split_goal` and :why3:transform:`introduce_premises`.
|
||
|
||
.. why3:transform:: split_premise
|
||
|
||
Replace axioms in conjunctive form by an equivalent collection of
|
||
axioms. In absence of case analysis attributes (see :why3:transform:`split_goal`
|
||
for details), the number of axiom generated per initial axiom is
|
||
linear in the size of that initial axiom.
|
||
|
||
.. why3:transform:: split_premise_full
|
||
|
||
Behave similarly to :why3:transform:`split_premise`, but also convert the axioms to
|
||
conjunctive normal form. The number of axioms generated per initial
|
||
axiom may be exponential in the size of the initial axiom.
|
||
|
||
.. why3:transform:: subst
|
||
|
||
Substitute a given constant using an equality found in the context.
|
||
The constant is removed.
|
||
|
||
For example, when applying ``subst x`` on the following goal
|
||
|
||
.. code-block:: whyml
|
||
|
||
constant x : int
|
||
constant y : int
|
||
constant z : int
|
||
axiom h : x = y + 1
|
||
axiom h1 : z = (x + y)
|
||
goal G : x = z
|
||
|
||
the transformation first finds the hypothesis ``h`` that can be used to
|
||
rewrite ``x``. Then, it replaces every occurrences of ``x`` with ``y + 1``.
|
||
Finally, it removes ``h`` and ``x``. The resulting goal is as follows:
|
||
|
||
.. code-block:: whyml
|
||
|
||
constant y : int
|
||
constant z : int
|
||
axiom h1 : z = ((y + 1) + y)
|
||
goal G : (y + 1) = z
|
||
|
||
This transformation is used to make the task more easily readable by
|
||
a human during debugging. This transformation should not help
|
||
automatic provers at all as they generally implement substitution
|
||
rules in their logic.
|
||
|
||
.. why3:transform:: subst_all
|
||
|
||
Substitute all the variables that can be substituted.
|
||
|
||
For example, applying ``subst_all`` on the following goal
|
||
|
||
.. code-block:: whyml
|
||
|
||
constant x : int
|
||
constant x1 : int
|
||
constant y : int
|
||
constant z : int
|
||
axiom h : x = (y + 1)
|
||
axiom hx1 : x = x1
|
||
axiom h1 : z = (x + y)
|
||
goal G : x = z
|
||
|
||
produces the following goal, where ``x``, ``x1``, and ``z`` have been
|
||
removed:
|
||
|
||
.. code-block:: whyml
|
||
|
||
constant y : int
|
||
goal G : (y + 1) = ((y + 1) + y)
|
||
|
||
The order in which constants are substituted is not specified.
|
||
|
||
.. why3:transform:: unfold
|
||
|
||
Unfold the definition of a logical symbol in the given hypothesis.
|
||
|
||
For example, applying ``unfold p`` on the following goal
|
||
|
||
.. code-block:: whyml
|
||
|
||
predicate p (x:int) = x <= 22
|
||
axiom h : forall x:int. p x -> p (x - 1)
|
||
goal G : p 21
|
||
|
||
produces the following goal:
|
||
|
||
.. code-block:: whyml
|
||
|
||
predicate p (x:int) = x <= 22
|
||
axiom h : forall x:int. p x -> p (x - 1)
|
||
goal G : 21 <= 22
|
||
|
||
One can also unfold in the hypothesis, using ``unfold p in h``, which
|
||
gives the following goal:
|
||
|
||
.. code-block:: whyml
|
||
|
||
predicate p (x:int) = x <= 22
|
||
axiom h : forall x:int. x <= 22 -> (x - 1) <= 22
|
||
goal G : 21 <= 22
|
||
|
||
.. why3:transform:: use_th
|
||
|
||
Import a theory inside the current context. This is used, in some rare
|
||
case, to reduced the size of the context in other goals, since
|
||
importing a theory in the WhyML code would the theory available in all
|
||
goals whereas the theory is only needed in one specific goal.
|
||
|
||
For example, applying ``use_th int.Int`` on the following goal
|
||
|
||
.. code-block:: whyml
|
||
|
||
predicate p int
|
||
goal G : p 5
|
||
|
||
imports the ``Int`` theory. So, one is able to use the addition over
|
||
integers, e.g., ``replace 5 (2 + 3)``.
|
||
|
||
Any lemma appearing in the imported theory can also be used.
|
||
|
||
Note that axioms are also imported. So, this transformation should be
|
||
used with care. We recommend to use only theories that do not contain
|
||
any axiom because this transformation could easily make the context
|
||
inconsistent.
|
||
|
||
.. _sec.strategies:
|
||
|
||
Proof Strategies
|
||
----------------
|
||
|
||
In the context of Why3, proof strategies are mechanisms that automate
|
||
the application of transformations and provers on proof tasks. These
|
||
strategies are mainly meant to be invoked in the IDE.
|
||
|
||
Strategies come into two flavours: first the so-called basic
|
||
strategies, and second a more complex mechanism allowing one to
|
||
program strategies in OCaml. Such strategies are supposed to be
|
||
programmed on top of the module `Strategy` of the Why3 API. Such
|
||
strategies can also by called goal-oriented, since programming them in
|
||
OCaml provides a way to inspect the formulas in the goal or hypothesis of the task, and apply
|
||
transformations depending on their shapes.
|
||
|
||
Below we document one of such strategy: a strategy for error
|
||
propagation in floating-point computations.
|
||
|
||
Basic Strategies
|
||
~~~~~~~~~~~~~~~~
|
||
|
||
As seen in :numref:`sec.ideref`, the IDE provides a few buttons that
|
||
trigger the run of basic proof strategies on the selected goals. Such proof
|
||
strategies can be defined using a basic assembly-style language, and put
|
||
into the Why3 configuration file. The commands of this basic language
|
||
are:
|
||
|
||
- :samp:`c {p} {t} {m}` calls the prover *p* with a time limit *t*
|
||
and memory limit *m*. On success, the strategy ends, it
|
||
continues to next line otherwise.
|
||
|
||
- :samp:`c {p1} {t1} {m1} | ... | {pk} {tk} {mk}` calls the provers *p1* to *pk* in parallel.
|
||
On success on one prover, the other provers are interrupted, and the strategy ends. It
|
||
continues to next line if none of the provers succeed.
|
||
|
||
- :samp:`t {n} {lab}` applies the transformation *n*. On success, the
|
||
strategy continues to label *lab*, and is applied to each
|
||
generated sub-goals. It continues to next line otherwise.
|
||
|
||
- :samp:`g {lab}` unconditionally jumps to label *lab*.
|
||
|
||
- :samp:`{lab}:` declares the label *lab*. The default label ``exit``
|
||
stops the program.
|
||
|
||
To exemplify this basic programming language, we give below the default
|
||
strategies that are attached to the default buttons of the IDE, assuming
|
||
that the provers Alt-Ergo 2.3.0, CVC4 1.7, and Z3 4.8.4 have been detected by
|
||
the :why3:tool:`why3 config` command.
|
||
|
||
Split_VC
|
||
is bound to the 1-line strategy
|
||
|
||
::
|
||
|
||
t split_vc exit
|
||
|
||
Auto_level_0
|
||
is bound to
|
||
|
||
::
|
||
|
||
c Z3,4.8.4, 1 1000
|
||
c Alt-Ergo,2.3.0, 1 1000
|
||
c CVC4,1.7, 1 1000
|
||
|
||
The three provers are tried for a time limit of 1 second and memory
|
||
limit of 1 Gb, each in turn. This is a perfect strategy for a first
|
||
attempt to discharge a new goal.
|
||
|
||
Auto_level_1
|
||
is bound to
|
||
|
||
::
|
||
|
||
c Z3,4.8.4, 5 1000 | Alt-Ergo,2.3.0, 5 1000 | CVC4,1.7, 5 1000
|
||
|
||
Same as Auto_level_0 but with 5 seconds instead of 1, and in parallel.
|
||
|
||
Auto_level_2
|
||
is bound to
|
||
|
||
::
|
||
|
||
start:
|
||
c Z3,4.8.4, 1 1000
|
||
c Alt-Ergo,2.3.0, 1 1000
|
||
c CVC4,1.7, 1 1000
|
||
t split_vc start
|
||
c Z3,4.8.4, 10 4000 | Alt-Ergo,2.3.0, 10 4000 | CVC4,1.7, 10 4000
|
||
|
||
The three provers are first tried for a time limit of 1 second and
|
||
memory limit of 1 Gb, each in turn. If none of them succeed, a split
|
||
is attempted. If the split works then the same strategy is retried
|
||
on each sub-goals. If the split does not succeed, the provers are
|
||
tried again with larger limits, and in parallel.
|
||
|
||
Auto_level_3
|
||
is bound to
|
||
|
||
::
|
||
|
||
start:
|
||
c Z3,4.8.4, 1 1000
|
||
c Eprover,2.0, 1 1000
|
||
c Spass,3.7, 1 1000
|
||
c Alt-Ergo,2.3.0, 1 1000
|
||
c CVC4,1.7, 1 1000
|
||
t split_vc start
|
||
c Z3,4.8.4, 5 2000 | Eprover,2.0, 5 2000 | Spass,3.7, 5 2000 | Alt-Ergo,2.3.0, 5 2000 | CVC4,1.7, 5 2000
|
||
t introduce_premises afterintro
|
||
afterintro:
|
||
t inline_goal afterinline
|
||
g trylongertime
|
||
afterinline:
|
||
t split_all_full start
|
||
trylongertime:
|
||
c Z3,4.8.4, 30 4000 | Eprover,2.0, 30 4000 | Spass,3.7, 30 4000 | Alt-Ergo,2.3.0, 30 4000 | CVC4,1.7, 30 4000
|
||
|
||
Notice that now 5 provers are used. The provers are first tried
|
||
for a time limit of 1 second and memory limit of 1 Gb, each in
|
||
turn. If none of them succeed, a split is attempted. If the split
|
||
works then the same strategy is retried on each sub-goals. If the
|
||
split does not succeed, the prover are tried again with limits of
|
||
5 s and 2 Gb, and in parallel. If all fail, we attempt the
|
||
transformation of introduction of premises in the context,
|
||
followed by an inlining of the definitions in the goals. We then
|
||
attempt a split again. If the split succeeds, we restart from the
|
||
beginning. Otherwise, provers are tried again, in parallel, with 30s and 4
|
||
Gb.
|
||
|
||
Forward propagation in floating-point computations
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
The specialized strategy ``forward_propagation`` can be used for
|
||
automatically computing and proving a rounding error on a term of type
|
||
``ufloat`` which is the type of unbounded floats as defined in the
|
||
theory `ufloat` of the standard library. More background on
|
||
forward error propagation will be available soon in an incoming research report.
|
||
|
||
The only transformations used are :
|
||
|
||
- ``assert``, to assert the existence of a forward error.
|
||
- ``apply``, to apply one of the forward propagation lemmas.
|
||
|
||
The strategy uses the following process:
|
||
|
||
1. Look at the form of the goal. If the goal has the form
|
||
``abs (to_real x -. exact_x) <=. C``, it goes to step 2, else it does nothing.
|
||
2. Look at term ``x``. There are 2 cases :
|
||
|
||
* 2.1. : ``x`` is either the result of a supported ufloat operation
|
||
(e.g. addition, multiplication) on some arguments or
|
||
the result of the application of an approximation of a supported
|
||
function (e.g. exponential) to some arguments. Then the strategy
|
||
applies recursively step 2 for each argument of the ufloat
|
||
operation/function approximation to compute their forward
|
||
error. For each forward error computed, the strategy also
|
||
generates a proof tree containing the steps to prove it. If at
|
||
least one forward error is computed, then the propagation lemma
|
||
corresponding to the ufloat operation/approximated function is
|
||
used to compute the forward error for ``x`` and ``exact_x``, and a corresponding
|
||
proof tree is generated. The root of the proof tree consists of an
|
||
assertion of the forward error computed for ``x``, and the child
|
||
node will generally be the application of the transformation
|
||
``apply`` with the propagation lemma as an argument. The
|
||
propagation lemma contains hypotheses about forward errors for the
|
||
arguments, therefore the proof trees computed for them recursively
|
||
are attached as nodes to the corresponding nodes of the tree.
|
||
|
||
* 2.2. : ``x`` is something else. Then no forward error is computed
|
||
and no proof tree is generated.
|
||
|
||
Currently, propagation lemmas exist for the following functions :
|
||
|
||
* ufloat addition, subtraction, multiplication and negation.
|
||
* ufloat approximations of ``log`` and ``exp`` functions.
|
||
* ufloat approximations of the iterated sum function (defined in stdlib module ``real.Sum``).
|
||
|
||
|
||
The following excerpt is an example of a program that can be proved using the strategy :
|
||
|
||
::
|
||
|
||
use real.RealInfix
|
||
use real.Abs
|
||
use ufloat.USingle
|
||
|
||
let ghost addition_errors_basic (a b c : usingle)
|
||
ensures {
|
||
let exact = to_real a +. to_real b +. to_real c in
|
||
let exact_abs = abs (to_real a) +. abs (to_real b) +. abs (to_real c) in
|
||
abs (to_real result -. exact) <=. 2. *. eps *. exact_abs
|
||
}
|
||
= a ++. b ++. c
|
||
|
||
To use the strategy within Why3 IDE in order to prove the program, one
|
||
must perform the following steps :
|
||
|
||
1. Apply the ``split_vc`` transformation to generate the subgoals.
|
||
2. Select the proof node of the postcondition and apply the
|
||
``forward_propagation`` strategy, either by typing the name of the
|
||
strategy in the command line or by right clicking on the proof node
|
||
and selecting the strategy.
|
||
3. The strategy will generate a proof tree. The nodes of the tree
|
||
should be easily proved using one of the ``auto`` strategies.
|
||
|
||
Note that the ``forward_propagation`` strategy can also be used when
|
||
the user has no specific forward error in mind as a way to propose a
|
||
provable bound. For instance in the example above, one could have
|
||
replaced the term ``2. *. eps *. exact_abs`` by anything in the
|
||
postcondition. The strategy would still have worked and it would have
|
||
generated an assertion about a forward error that it can prove. One
|
||
could then use this forward error in the postcondition.
|
||
|
||
For more examples of the use of the strategy, see the directory
|
||
``examples/numeric`` of the examples repository.
|
||
|
||
|
||
.. _sec.attributes:
|
||
|
||
WhyML Attributes
|
||
----------------
|
||
|
||
.. why3:attribute:: case_split
|
||
|
||
.. why3:attribute:: cfg:stackify
|
||
|
||
.. why3:attribute:: cfg:subregion_analysis
|
||
|
||
.. why3:attribute:: extraction:inline
|
||
|
||
If the name of a function is labeled with this attribute, its body
|
||
will be inlined at every call site during extraction (see
|
||
:numref:`sec.extract`). This is especially useful for trivial
|
||
wrapper functions whose only purpose is to provide a slightly
|
||
different specification from the original function.
|
||
|
||
.. why3:attribute:: extraction:likely
|
||
|
||
This attribute can be applied to a Boolean expression to indicate
|
||
whether it is likely to be true. This is used at extraction time
|
||
(see :numref:`sec.extract`), assuming the target language supports
|
||
it. For example, when extracting to C, the extracted expression
|
||
will be tagged with ``__builtin_expect``.
|
||
|
||
.. why3:attribute:: extraction:unlikely
|
||
|
||
This attribute can be applied to a Boolean expression to indicate
|
||
whether it is likely to be false. This is the opposite of
|
||
:why3:attribute:`extraction:likely`.
|
||
|
||
.. why3:attribute:: extraction:preserve_single_field
|
||
|
||
This attribute is applied to the declaration of a record type. It is used to
|
||
disable an optimization made by the preprocessing step that precedes the
|
||
invocation of extraction drivers. During this step, record types with a
|
||
single field like:
|
||
|
||
.. code-block:: whyml
|
||
|
||
type t = { a : int }
|
||
|
||
are rewritten as:
|
||
|
||
.. code-block:: whyml
|
||
|
||
type t = int
|
||
|
||
If this attribute is applied to ``t``, then this optimization is disabled.
|
||
|
||
.. why3:attribute:: induction
|
||
|
||
.. why3:attribute:: infer
|
||
|
||
.. why3:attribute:: inline:trivial
|
||
|
||
.. why3:attribute:: java:class_kind:
|
||
|
||
This attribute annotates a module. Three suffixes are allowed:
|
||
:code:`abstract`, :code:`interface` and :code:`class`. This three attributes
|
||
specify what kind of class the Java driver has to generate for the module,
|
||
either a regular or an abstract class or an interface.
|
||
|
||
.. why3:attribute:: java:constructor
|
||
|
||
This attribute is used to mark functions
|
||
|
||
.. why3:attribute:: java:exception:
|
||
|
||
If a module is annotated with the attribute
|
||
:why3:attribute:`java:exception:` *exn-class*, the Java driver translates it
|
||
into a Java exception class. The `exn-class` part of the attribute indicates
|
||
the parent class from which the generated class inherits. Actually `exn-class`
|
||
is printed out `as-is` after the `extends` specifier of the generated class.
|
||
|
||
.. why3:attribute:: java:implements:
|
||
|
||
This attribute is applied to a module. Its suffix is a coma-separated list of
|
||
identifiers of Java interfaces. From the driver point of view, the specified
|
||
interfaces are just strings of characters and are printed out `as-is` in the
|
||
generated Java code. The driver does not check if theses interfaces are
|
||
actually implemented by the module; this verification is left to the Java
|
||
compiler.
|
||
|
||
.. why3:attribute:: java:package:
|
||
|
||
If the attribute :why3:attribute:`java:package:` *some.package* annotates a module,
|
||
the Java driver creates the expected class in the package *some.package*. In
|
||
addition to the Java instruction :code:`package`, the driver follows the usual
|
||
convention by creating the :code:`.java` file in the directory
|
||
:file:`some/package/`. The directory of the package is created
|
||
relatively to the output directory specified with the option :code:`-o` (see
|
||
:ref:`sec.why3extract`).
|
||
|
||
.. why3:attribute:: java:visibility:public
|
||
|
||
.. why3:attribute:: java:visibility:package
|
||
|
||
.. why3:attribute:: java:visibility:private
|
||
|
||
By default, in the code generated by the Java driver, classes, instance
|
||
variables and methods are declared :code:`public`. The driver allows three
|
||
attributes to change this default visibility: :code:`public`,
|
||
:code:`private` and :code:`package`. Note that
|
||
visibility attributes **are not checked** by the driver.
|
||
|
||
If :why3:attribute:`java:visibility:private` is used to annotate a module, the
|
||
generated class is declared :code:`private`. Even if it is syntactically
|
||
allowed, the specification of Java language does not allow private specifier
|
||
for top-level classes.
|
||
|
||
By default, functions and types inherit the visibility attribute of the
|
||
module. For instance if a module is declared with
|
||
:why3:attribute:`java:visibility:package` then all functions, instance
|
||
variables and *Enum*-types will be declared with :code:`package` visibility.
|
||
Each element of the module can be annotated with a different visibility
|
||
attribute that replaces the default one.
|
||
|
||
Instance variables actually inherits the visibility attribute of the type that
|
||
defines them. Yet, each instance variable may have its own visibility
|
||
attribute.
|
||
|
||
|
||
.. why3:attribute:: model_trace
|
||
|
||
.. why3:attribute:: rewrite
|
||
|
||
.. why3:attribute:: stop_split
|
||
|
||
.. why3:attribute:: vc:annotation
|
||
|
||
This attribute is added by the VC generator, on the user input
|
||
formulas which become goals to prove in the resulting VC. It should
|
||
not be added manually.
|
||
|
||
.. why3:attribute:: vc:divergent
|
||
|
||
This attribute indicates whether VCs for termination should be
|
||
generated. See :numref:`sec.terminationvc` for details.
|
||
|
||
.. why3:attribute:: vc:keep_precondition
|
||
|
||
This attribute indicates whether preconditions of calls should be kept
|
||
as assumptions for the program after the call. See
|
||
:numref:`sec.keeppreconditions` for details.
|
||
|
||
|
||
.. why3:attribute:: vc:sp
|
||
|
||
This attribute, put on a WhyML expression, locally switches the VC
|
||
generator to the SP mode, for that expression. See
|
||
:numref:`sec.strongestpostconditions` for details.
|
||
|
||
.. why3:attribute:: vc:white_box
|
||
|
||
This attribute is added by the Why3 parser for contract attached to
|
||
an expression in WhyML code. Such a contract is indeed encoded by a
|
||
local function with this attribute. It is for internal use only
|
||
and should never be added manually.
|
||
|
||
.. why3:attribute:: vc:wp
|
||
|
||
This attribute, put on a WhyML expression, locally switches the VC
|
||
generator to the WP mode, for that expression. See
|
||
:numref:`sec.strongestpostconditions` for details.
|
||
|
||
|
||
.. _sec.metas:
|
||
|
||
Why3 Metas
|
||
----------
|
||
|
||
.. why3:meta:: compute_max_steps
|
||
|
||
.. why3:meta:: keep:literal
|
||
|
||
.. why3:meta:: realized_theory
|
||
|
||
.. why3:meta:: rewrite
|
||
|
||
.. why3:meta:: rewrite_def
|
||
|
||
.. why3:meta:: vc:proved_wf
|
||
|
||
Declare a hypothesis as a proof of well-foundedness of a binary
|
||
relation. See :numref:`sec.custom_wf`.
|
||
|
||
.. _sec.debug:
|
||
|
||
Debug Flags
|
||
-----------
|
||
|
||
The list of debug flags can be obtained using
|
||
:file:`why3 --list-debug-flags`. The following excerpt is the
|
||
list of flags mentioned in this manual.
|
||
|
||
.. why3:debug:: infer:loop
|
||
|
||
.. why3:debug:: infer:print_ai_result
|
||
|
||
.. why3:debug:: infer:print_cfg
|
||
|
||
.. why3:debug:: print:inferred_invs
|
||
|
||
.. why3:debug:: print:domains_loop
|
||
|
||
.. why3:debug:: stack_trace
|
||
|
||
|
||
Structure of Session Files
|
||
--------------------------
|
||
|
||
The proof session state is stored in an XML file named
|
||
:file:`{dir}/why3session.xml`, where *dir* is the directory of the
|
||
project. The XML file follows the DTD given in :file:`share/why3session.dtd`
|
||
and reproduced below.
|
||
|
||
.. literalinclude:: ../share/why3session.dtd
|
||
:language: dtd
|
||
|
||
|
||
.. _sec.jsonce:
|
||
|
||
Structure of Counterexamples
|
||
----------------------------
|
||
|
||
Generated counterexamples can be exported in JSON format.
|
||
The JSON output follows the JSON Schema given in :file:`share/ce-models.json`
|
||
and reproduced below.
|
||
|
||
.. literalinclude:: ../share/ce-models.json
|
||
:language: json
|
||
|
||
|
||
Developer Documentation
|
||
-----------------------
|
||
|
||
Updating messages for syntax errors
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
Here is the developer's recipe to update a syntax error message. We do
|
||
it on the following illustrative example.
|
||
|
||
.. code-block:: whyml
|
||
|
||
function let int : int
|
||
|
||
If such a file is passed to Why3, one obtains:
|
||
|
||
::
|
||
|
||
File "bench/parsing/bad/498_function.mlw", line 1, characters 9-12:
|
||
syntax error
|
||
|
||
The recipe given here provides a way to produce a more informative
|
||
message. It is based on handcrafted error messages provided by the
|
||
`Menhir <http://gallium.inria.fr/~fpottier/menhir/>`_ parser generator.
|
||
|
||
The first step is to call :program:`menhir` with option ``--interpret-error``
|
||
while giving as input the erroneous input, under the form of a sequence
|
||
of tokens as generated by :file:`src/parser/lexer.mll`.
|
||
|
||
.. code-block:: console
|
||
|
||
$ echo "decl_eof: FUNCTION LET" | menhir --base src/parser/parser --interpret-error src/parser/parser_common.mly src/parser/parser.mly
|
||
decl_eof: FUNCTION LET
|
||
##
|
||
## Ends in an error in state: 1113.
|
||
##
|
||
## pure_decl -> FUNCTION . function_decl list(with_logic_decl) [ VAL USE TYPE THEORY SCOPE PREDICATE MODULE META LET LEMMA INDUCTIVE IMPORT GOAL FUNCTION EXCEPTION EOF END CONSTANT COINDUCTIVE CLONE AXIOM ]
|
||
##
|
||
## The known suffix of the stack is as follows:
|
||
## FUNCTION
|
||
##
|
||
|
||
<YOUR SYNTAX ERROR MESSAGE HERE>
|
||
|
||
The text returned by that command should be appended to
|
||
:file:`src/parser/handcrafted.messages`, with of course an appropriate error
|
||
message, such as this one:
|
||
|
||
::
|
||
|
||
expected function name must be a non-reserved uncapitalized identifier (token LIDENT_NQ), found "$0"
|