Ada Tutorial(3)SPARK2——Post condition + Loop Invariant 后置条件 + 循环不变量

news2024/7/6 20:08:48

文章目录

  • divmod
    • 循环不变量 v.s. 后置条件
    • 扩展思考

divmod

-- divmod.adb
package body DivMod with SPARK_Mode is

   procedure DivMod(X : Positive; N : Positive; K : out Natural; Remainder : out Natural)
   is
      Y : Natural := X;
   begin
      K := 0;
      while Y >= N loop
         Y := Y - N;
         K := K + 1;
      end loop;
      Remainder := Y;
   end DivMod;


end DivMod;
--divmod.ads

package DivMod with SPARK_Mode is

   procedure DivMod(X : in Positive; N : in Positive; K : out Natural;
                    Remainder : out Natural);

end DivMod;
--main.adb

with Ada.Integer_Text_IO;
use Ada.Integer_Text_IO;
with Ada.Text_IO;
use Ada.Text_IO;
with DivMod;


procedure Main with SPARK_Mode is
   K : Natural;
   R : Natural;
   X : Integer;
   N : Integer;
begin
   Put_Line("Compute the result and remainder of X/N, via repeated subtraction.");
   Put_Line("The result and remainder are numbers K and R where X = K * N + R and R < N");
   Put("Enter a positive integer for X: ");
   Get(X);
   Put("Enter a positive integer for N: ");
   Get(N);
   if (X > 0 and N > 0) then
      DivMod.DivMod(X,N,K,R);
      Put("K: "); Put(K); New_Line;
      Put("R: "); Put(R); New_Line;

      -- assert that the result is correct
      pragma Assert (X = K * N + R and R < N);

      -- SPARK needs some help to conclude that X/N = K.
      -- We derive that final result step-by-step

      -- firstly K is not greater than X/N
      pragma Assert (K * N <= X);
      pragma Assert (X/N >= K);

      -- secondly K is not lower than X/N
      pragma Assert (if K < Integer'Last and then Integer'Last / N > K + 1 then
                        N * (K + 1) > X);
      pragma Assert (X/N <= K);

      -- therefore K is exactly equal to X/N
      pragma Assert (X/N = K);
   else
      Put_Line("X and N must both be positive. Exiting.");
   end if;
end Main;

问题:Now run the SPARK prover: SPARK → Prove All. You will see that the provided main.adb contains a number of pragma Assert statements. These are assertions that the SPARK prover tries to prove always hold.
You will see that the assertion X = K * N + R and R < N in main.adb cannot be proved. (You
may also see potential problems reported in the DivMod package, but we will come to those later.)
This is because the DivMod procedure has no contract (pre/postcondition annotations), so the SPARK prover cannot tell anything about K and R after it is called.
在这里插入图片描述
问题:Add a postcondition annotation to the DivMod procedure in divmod.ads to allow the failing assert to be proved. Hint: this postcondition should state what is true about K and R in terms of X and N, after DivMod returns.

  • 上述问题的原因就是:我们在 main.adb 中使用了 assert,但是由于在 divmod.ads 中我们没有使用 post 来向程序发布 X = K * N + Remainder 这个关系,所以在 main.adb 中经过 assert 的时候就没法满足,因此我们只需要在 divmod.adb 中加入这个 post condition 即可
package DivMod with SPARK_Mode is
   procedure DivMod(X : in Positive; N : in Positive; K : out Natural;
                    Remainder : out Natural) with
   Post=> (X = K * N + Remainder);
end DivMod;

在这里插入图片描述

  • 上述问题解决

  • 你可以将 post condition 的作用看成:向程序显示地声明某个 procedure 或者 function 的执行结果,以便 SPARK 进行检查

问题: Now run the SPARK Prover again. Now the assertions in main.adb should be able to be proved, using the contract on DivMod. However, the SPARK prover cannot actually prove that the contract holds.
It also cannot prove that the loop in DivMod won’t cause integer overflow.
在这里插入图片描述

To help it prove these, we need to add a suitable loop invariant annotation for the while-loop in DivMod. To work out what the invariant should say, you can add print statements to this loop to get it to print out the values of Y and K each time through the loop. Then look for a relationship that always holds between Y, K, N and X.
Once you have figured out the invariant, add an appropriate annotation to the while-loop: pragma Loop Invariant (. . . your invariant goes here . . .);

package body DivMod with SPARK_Mode is
   procedure DivMod(X : Positive; N : Positive; K : out Natural; Remainder : out Natural)
   is
      Y : Natural := X;
   begin
      K := 0;
      while Y >= N loop
         Y := Y - N;
         K := K + 1;
         pragma Loop_Invariant (Y <= X);
         pragma Loop_Invariant (Y + N * K = X);
      end loop;
      Remainder := Y;
   end DivMod;
end DivMod;

循环不变量 v.s. 后置条件

循环不变量和后置条件(postcondition)都是用于验证程序正确性的关键工具,但它们在具体用途上有一些区别。

  • 循环不变量: 这是一个在循环的每一次迭代开始和结束时都保持为真的条件。循环不变量是在循环的过程中不断保持的一个条件或属性,它可以帮助我们理解循环的行为,保证循环的正确性。循环不变量通常会设计为捕获关于正在进行的计算的一些关键信息。
  • 后置条件(postcondition): 这是一个过程或函数结束时必须满足的条件。它描述了程序在执行后的预期状态。后置条件通常与前置条件(precondition,即程序开始前的状态)以及程序的实际操作一起使用,以证明程序的正确性。

在某种程度上,你可以认为循环不变量在循环的上下文中类似于后置条件, 因为它描述了每次循环迭代结束时的预期状态。但是,它们在语义上是不同的:后置条件描述的是程序结束时的状态,而循环不变量描述的是循环的每次迭代。

在形式化方法和程序验证中,通常会同时使用循环不变量和前置/后置条件,以帮助保证程序的正确性。

Now re-run the SPARK prover. If your invariant is correct, you should find that the SPARK prover does not report any problems. You have proved the correctness of your first program. Congratulations!

扩展思考

问题: If you have time: Look at the assert statements in main.adb more closely. The final one asserts that X / N = K, i.e. that K does in fact hold the result of performing integer division on X by N.
Try commenting out each of the assert statements above and re-running the SPARK prover for each. You should find that when one of these assertions is commented out, one of the following assertions cannot be proved.
This means that, to prove that following assertion, the SPARK prover first needs to know that the preceding one holds, i.e. it cannot derive the following assertion in one go but it needs some help: we first have to tell it to derive the intermediate assertion and, only then, can it derive the subsequent one. This can sometimes happen with automated provers like the SPARK prover. Using intermediate assertions like this can be a useful way, therefore, helping to derive extra facts that cannot be inferred automatically.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/638628.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MySQL 日期与时间函数

一、获取日期、时间 函数用法CURDATE()&#xff0c;CURRENT_DATE()返回当前日期&#xff0c;只包含年、月、日CURTIME() &#xff0c; CURRENT_TIME()返回当前时间&#xff0c;只包含时、分、秒NOW() &#xff0c; SYSDATE()&#xff0c;CURRENT_TIMESTAMP() &#xff0c; LOC…

为什么企业和品牌一定要创建百度百科词条呢?

在企业和品牌宣传推广方面&#xff0c;百度百科作为一个权威的知识平台&#xff0c;早已成为了宣传阶段非常重要的一环。本文伯乐网络传媒将从以下几个方面探讨为什么企业和品牌一定要创建百度百科词条。 一、提升企业和品牌知名度 在信息时代&#xff0c;信息的获取渠道变得更…

PySpark简单使用(零)

介绍 Spark是Apache基金会旗下的顶级开源项目&#xff0c;用于对海量数据进行大规模分布式计算。PySpark是Spark的Python实现&#xff0c;是Spark为Python开发者提供的编程入口&#xff0c;用于以Python代码完成Spark任务的开发PySpark不仅可以作为Python第三方库使用&#xf…

【深入浅出 Spring Security(九)】解决跨域问题和 Axios 所需配置

跨域 一、SpringMVC 跨域的解决方案CrossOrigin&#xff08;注解的方式解决&#xff09;addCorsMappings&#xff08;实现WebMvcConfigurer接口&#xff0c;重写方法&#xff09; 二、Spring Security 跨域的解决方案前后端跨域测试&#xff08;前端相关配置&#xff09; 啥是跨…

计算机提示“找不到vcruntime140.dll,无法继续执行代码可”以这样子修复

首先&#xff0c;对于那些不熟悉的人来说&#xff0c;vcruntime140.dll是一个关键文件&#xff0c;用于在Windows操作系统上运行使用C语言编写的大型应用程序。如果你正在运行或安装这样的应用程序&#xff0c;但找不到vcruntime140.dll文件&#xff0c;那么你的应用程序可能无…

word插入图片为何无法显示?

word是我们常用的软件&#xff0c;在使用过程中&#xff0c;我们难免会遇到这样或那样的问题&#xff0c;解决问题的思路我认为首先要找出原因&#xff0c;然后再想办法解决才是最好的方案。 如果在 Word 文档中插入的图片无法显示&#xff0c;可能是以下原因之一&#xff1a;…

安装ORB-SLAM2纯记录(caffe)

ubuntu20.04 显卡配置3050TI 显卡驱动&#xff1a; NVIDIA-SMI 525.116.04 Driver Version: 525.116.04 cuda:Cuda compilation tools, release 11.0, V11.0.221 eigen:3.4.0 opencv 3.4.9 opencv下载链接 pangolin :高翔SLAM十四讲中的 没有安装最新版本 安装pangolin时候出…

有趣的图(二)(56)

小朋友们好&#xff0c;大朋友们好&#xff01; 我是猫妹&#xff0c;一名爱上Python编程的小学生。 和猫妹学Python&#xff0c;一起趣味学编程。 今日主题 咱们书接上回&#xff0c;上次学了图的基本概念&#xff0c;你都学会了吗&#xff1f; 咱们今天要学习内容如下&a…

通过Appium Desktop实现录制功能并导出自动化脚本

1、我们进入下面这个界面 图中红色标记1为 “top by coordinates” 按钮&#xff0c; 这是一种通过坐标定位元素的方式。 图中红色标记2为 “Start Recording” 按钮&#xff0c; 选中表示处理录制状态。 2、点击“top by coordinates” 按钮&#xff0c;再点击 “Start Recor…

vue3基础知识的简单应用

vue3基础知识的简单应用 vue3基础知识的简单应用运行结果 vue3基础知识的简单应用 父组件代码 <template><div class"home"><img alt"Vue logo" src"../assets/logo.png"><HelloWorld msg"Welcome to Your Vue.js A…

linux opencv4.2静态库编译及链接

1. 编译静态库 拉取opencv源码&#xff1a; https://github.com/opencv/opencv.git进入源码根目录&#xff0c;在platforms/linux目录下创建编译脚本build_linux.sh cd platforms/linux vi build_linux.sh脚本里配置cmake编译参数&#xff0c;这里编译静态库需要将 -DBUILD_S…

华为OD机试真题 JavaScript 实现【勾股数元组】【2022Q4 100分】,附详细解题思路

一、题目描述 如果三个正整数A、B、C ,ABC则为勾股数 如果ABC之间两两互质&#xff0c;即A与B&#xff0c;A与C&#xff0c;B与C均互质没有公约数&#xff0c; 则称 其为勾股数元组。 请求出给定n~m范围内所有的勾股数元组。 二、输入描述 起始范围 1 < n < 10000 n &…

[数据结构初阶]单链表

顾名思义&#xff0c;单链表就是一个相邻节点用一个单向指针串起来&#xff0c;形成一种链式结构&#xff0c;那怎么将这些节点连结起来方便管理呢&#xff1f; 目录 单链表定义 申请空间 创建节点 打印链表 尾插 尾删 头插 头删 查找 插入 删除 pos后删除 pos位置删除…

Python 接口测试之接口关键字封装

引言 我们使用RF做UI自动化测试的时候&#xff0c;使用的是关键字驱动。同样&#xff0c;Python做接口自动化测试的时候&#xff0c;也可以使用关键字驱动。但是这里并不是叫关键字驱动&#xff0c;而是叫数据驱动。而接口测试的关键字是什么呢&#xff1f; 我们数据驱动的载体…

知识图谱实战应用15-知识图谱在生物基因学上的应用,实现基因与疾病关联查询

大家好,我是微学AI,今天给大家介绍一下知识图谱实战应用15-知识图谱在生物基因学上的应用,实现基因与疾病关联查询。知识图谱在生物基因学中的应用非常广泛,可以帮助研究人员更好地理解和发现基因与疾病之间的关联关系,并推进相关领域的发展。 目录 引言知识图谱简介生物…

Linux之命令别名---alias

Linux之命令别名 定义 别名是命令的快捷方式。为那些需要经常执行&#xff0c;但需要很长时间输入的长命令创建快捷方式很有用 语法格式 alias 别名’原命令 -选项/参数’ 基本用法 查看设置的别名 [redhat8alocalhost ~]$ alias 删除别名 [redhat8alocalhost ~]$ unalia…

你见过的这里都有,开源Web性能测试工具集合

1、JMeter。这个也不用多介绍&#xff0c;基本属于做过Web性能测试都会接触的工具。Apache旗下的开源项目&#xff0c;属于一个Java桌面应用程序。优势是开源免费&#xff0c;扩展能力强。自身性能是硬伤。 2、Locust。Web性能测试的蝗药师&#xff0c;开源免费&#xff0c;并发…

C语言解决任意一个整数分解,逆序输出

C语言解决任意一个整数分解,逆序输出 输入&#xff1a;1234 输出&#xff1a;1 2 3 4 思路&#xff1a; 对于任意一个整数num, &#xff08;1&#xff09;num%10就可以得到其个位数的数字&#xff0c;例如&#xff1a;1234%104 &#xff08;2&#xff09;num/10就可以获取到这个…

【SQL】sqladvisor

文章目录 概述架构流程产品特点安装部署使用帮助输出命令行传参调用配置文件传参调用测试一:对小表进行测试测试二&#xff1a;对大表有索引测试测试三&#xff1a;对大表无索引进行测试测试四&#xff1a;多条SQL同时分析&#xff1a; 来源 概述 SQLAdvisor是由美团点评公司技…

AntDB 企业增强特性介绍——分布式集群下强一致备份恢复技术

AntDB 使用 barman 实现数据的备份和恢复&#xff0c;但是集群节点部署在多台主机上&#xff0c;每个节点单独备份和恢复。多台服务器时钟不同步的情况下同时备份后&#xff0c; 无法真正实现基于时间点的数据完全和不完全恢复。AntDB 提供基于时间点的全局一致性备份恢复。 A…