The proposed methodologies allow to split complex goals as multiple simpler goals. This is an applica- tion of the “Divide and conquer” approach that suits well SMT solvers as they perform better on smaller goals. This approach is in fact close to the one applied in the first place by SMT solvers to achieve their verification. The specific shape of our generated goal makes plausible that no SMT solver inner strategy implements the provided methodologies.
For our work, we used Why3 in its 0.83 version. In more recent versions (0.85), other transformations are available. These new transformations may allow for a more efficient process.
Verification methodology process interest for BlockLibrary instance verification
Sub-goals obtained through the applications of our methodology can be fed to SMT solvers that may prove them. If this is not a success, then the sub-goals may still be too complex for an SMT solver to solve. In this case, there are three general solutions available to assess the correctness of the goal: a) we give more time and memory to the SMT solver to achieve the proof. This may succeed as computing power plays an important role in the success of SMT solving; b) we try to verify the negation of the goal. The verification of this goal will then show that the original goal is false; and c) we use a proof assistant that may allow to discharge some goals and even finish the proof.
If none of these three techniques provides a positive answer, the transformation methodology applica- tion or the proof assistant results may provide a discrepancy information on the specification that we can use as verification feedback:
• Discrepancy informations might be provided by some SMT solvers in the form of counter examples but it is not always possible depending on the toolset.
• The application of the transformations is generating simpler goals, these goals may be simple enough for the toolset user to detect discrepancies in the specification and then guess a correction to apply on the specification.
• Proof assistants feedbacks are based on the knowledge the human doing the proof have regarding the proof result such as a missing hypothesis that may be linked to missing informations (such as missing invariants for example) on the block specification or a false assumption caused by a faulty specification. The human operator can then provide the necessary feedbacks and correct the block specification accordingly.
Verification feedbacks should be expressed on the BlockLibrary instance specification allowing to correct it accordingly, one must ensure a tight integration of this feedback in the tooling and especially in the BlockLibrary editor environment.
We target to provide an automation of this feedback mechanism but timing constraints made this im- possible. According to our experiments, it looks possible to provide it but the development work for this task is not small and thus needs a consequent timing investment.
7.8 Semantics verification through SMT solving
WhyML modules generated from a BlockLibrary instance contains the definition for a function ex- tracted from a Signature instance. We have provided in Figure 7.31 the specification of a MinMax block BlockMode and its translation as a WhyML function with its contract. Here, we will tackle the verification of this function through the verification of its contract correctness.
7.8.1 Hoare triple verification
This verification targets to show that if the pre-conditions expressed on the function contract of the compute_MinOutScalarMultipleInputsScalars function are satisfied then the provided func- tion implementation will satisfy the provided post-conditions. For this function, there is only one post- condition: the output is smaller or equals to any input.
7.8. SEMANTICS VERIFICATION THROUGH SMT SOLVING
goal WP_parameter_compute_MinOutScalarMultipleInputsScalars :
2 forall nbInputs:int, in1:list (tInPortGroup real), functionParam: minMaxFunction.
nbInputs >= 1 /\ length in1 = nbInputs /\ nbInputs > 1 /\ functionParam = Min -> (let o = length in1 - 1 in
(1 > o ->
(forall out:real. out = value_inpg (nth 0 in1) ->
7 (forall i0:int. 0 <= i0 /\ i0 < length in1 ->
value_inpg (nth i0 in1) >=. out ))) /\ (1 <= o ->
(forall res:real. forall out:real. out = res ->
(forall i0:int. 0 <= i0 /\ i0 < length in1 ->
12 value_inpg (nth i0 in1) >=. out ))))
Listing 7.38: Weakest pre-condition for the compute_MinOutScalarMultipleInputsScalars semantics
From the function contract and specification, the Why3 tool computes a WP producing a proof obliga- tion. Its successful verification implies that the function post-condition is verified according to the func- tion code and its pre-conditions. The WP computed for this BlockMode semantics function is provided in Listing 7.38. In this WP, we clearly distinguish the pre-conditions (line 3), two cases are then given: one where in1 is small enough (1 > o) for the loop not to be computed and the other case where in1 is big enough for the loop to be computed (l <= o). For each of these cases the WP expresses that the computed code must imply the function post-condition.
The first case is trivially verified as its pre-condition is false (the length of in1 cannot be smaller than 1). Regarding the second case the provided pre-conditions are not sufficient to allow the verification. The use of SMT solvers provides the same result. The impossibility to prove this contract is not a surprise as the function code contains a loop and no loop invariant is provided to characterise it.
Verification of function code containing loops is usually done using both loop variants and loop in- variants. The loop variant provides a condition expressing the finite nature of the loop and the invariants express properties ensured before, during and after the execution of the loop. Using WhyML for loops, it is not required to provide a loop variant as it is directly inferred from the loop declaration. We thus only need to provide the loop invariant.
7.8.2 Adding loop invariants for the verification
The loop invariant that needs to be provided must ensure that at each step of the loop, the actual res value is smaller than all the values of input ports that have already been compared. We provide the correct BlockMode semantics phase function code with the loop invariant in line 7 of Listing 7.39.
definition bal = compute_MinOutScalarMultipleInputsScalars {
postcondition ocl {
3 In1 ->forAll(i| i.value >= Out.value) }
var res = In1 [0]. value;
for (var i = 1; i < (size(In1)); i = i + 1){
invariant { In1 ->subSequence (0,i-1) ->forAll(e| res <= e.value) }
8 if (res > In1[i]. value){ res = In1[i]. value; }
}
Out.value = res; 13 }
Listing 7.39: Compute semantics phase with loop invariant
Providing loop invariants for the verification of code containing loop constructs requires the ability for the language to support annotation writing. We added the support for the writing of simple annotations in the BAL language loop constructs. Loop invariant annotations body is expressed with OCL. It is advised to use this language as it allows to express quantified expressions that are usually required in loop invariants. Technical difficulties linked to the language scoping mechanism provided by the XText platform made impossible to achieve in time the development of the transformation of BAL invariants as loop invariants