【Kind2(基于SMT的自动模型检查器)学习笔记】基本语法

Kind2使用方法

  • 官网网址https://kind2-mc.github.io/kind2/

  • 编译器网址https://kind.cs.uiowa.edu/app/

  • 英文说明书网址https://kind.cs.uiowa.edu/kind2_user_doc/

  • 讲解kind2的一篇不错的论文https://link.springer.com/chapter/10.1007%2F978-3-319-41540-6_29

  • 编译器界面
    在这里插入图片描述
    在这里插入图片描述

    • 界面说明:
      • 中间黑色区域为编辑区,用于编写代码
      • 左侧是kind2的例子,点击后相关代码会显示到编辑器内
      • 右侧是约束求解器的配置,默认为Z3求解器
    • 按钮说明:
      • Load:从本地加载代码文件到编辑器,文件一般为lus格式
      • Download:将编辑器内的代码下载到本地
      • Check:检查代码是否有效(也就是在允许的输入内,是否能计算出正常的结果)
      • Simulate:编译代码(如果代码中有输入输出,则会弹出输入输出界面,并且该按钮会变成Hide Table,同时无法再对编辑区内的代码进行修改
      • Hide Tabe:隐藏运行界面,只有当代码中有输入输出时,点击Simulate按钮才会出现此按钮,此时不可再对编辑区内的代码进行修改
      • ☀:Simulate右侧的发光的小太阳是调整编辑区颜色,底色可黑可白,代码颜色也会随之改变
      • Run:运行代码,根据每列的不同输入分别执行代码求解不同结果,默认为10列
      • Reset:清空输入输出
      • Time:表示时刻表,程序会从Time = 0开始一直执行到Time的最后时刻

第一个简单的例子

问题描述:将不同时刻的X的状态赋给Y

代码:

node First( X : int ) returns ( Y : int );
let
  Y = X ;
tel

Simulate执行结果:

  • 先输入一些X的值
    在这里插入图片描述
  • 然后点击“Run”,即可看到Y在不同时刻的状态
    在这里插入图片描述

基础语法解释:

  • node表示定义一个结点,后面跟结点名First(与我们平时所说的函数有些类似,需要了解形式化的LTL和CTL后,才会对结点、时刻、状态有更好的了解)
  • 结点名First后面跟一对括号,括号里面是(状态名:状态类型),非必填,多个变量用英文分号进行分割,如(X : int ; U: int)
  • 结点名后面的括号后面跟一个returns,returns后面跟一对括号,括号里面的变量为(状态名:状态类型),非必填,多个变量用英文分号进行分割,如(X : int ; U: int)。最后面加一个分号,千万不要忘
  • let和tel之间写该结点的所要实现的功能
  • Y = X表示将状态X的状态值赋给状态Y

pre的用法

问题描述:获取状态X前一时刻的状态值赋给状态Y

代码:

node PreValue( X: bool ) returns ( Y: bool );
let
  Y = pre X;
tel

Simulate执行结果:
在这里插入图片描述

var 定义一个变量

问题描述:在结点中定义一个布尔变量

代码:

node abs(x:real;y: real) returns();
var equal_value: bool;
let
   equal_value = y = x;
tel

Simulate执行结果:
在这里插入图片描述

  • var表示定义一个变量,格式为:var 变量名 : 变量类型
  • real表示实数变量,bool表示布尔变量
  • equal_value = y = x这段代码,先执行y = x,如果相等,结果为true,如果不等,结果为false,然后将结果赋值给equal_value

const 定义一个常量

问题描述:在结点中定义一个常量

代码:

node equal(x:real;y: real) returns(result : bool);
const equal_value = true;
let
   result = x = y ;
tel

Simulate执行结果:
在这里插入图片描述

常量只有在定义的时候可以赋值,其余时候不可赋值

if判断语句的使用

问题描述:状态a的值为false时,c的值为1.0;a的值为true时,如果b的值为true,则c的值为2.0;否则,c的值为3.0

代码:

node judge(a: bool;b: bool) returns (c: real ) ;
let
  c = if a then 1.0
         else if b then 2.0
         else 3.0 ;
tel

Simulate执行结果:
在这里插入图片描述

求绝对值

问题描述:求一个数的绝对值,并验证求取结果是否有效

代码:

node abs(x:real) returns(y: real);
var Absolute: bool;
let
   y = if (x >= 0.0) then x else -x;
   Absolute = y >= 0.0;
tel

Simulate执行结果:
在这里插入图片描述

  • Absolute存储验证结果,在进行Check时会对Absolute的值进行检查

mod用法

问题描述:判断输入数值的奇偶

代码:

node Even(N: int) returns (B: bool);
let
  B = (N mod 2 = 0);
tel

Simulate执行结果:
在这里插入图片描述

–%PROPERTY验证求绝对值的代码

问题描述:用–%PROPERTY验证求绝对值的代码是否有效

代码:

node abs(x:real) returns(y: real);
var Absolute: bool;
let
   y = if (x >= 0.0) then x else -x;
   Absolute = y >= 0.0;
   --%PROPERTY Absolute;
tel

Check验证结果:
在这里插入图片描述

  • --%PROPERTY Absolute; 用于验证Absolute的结果是否为true;
    • 如果Absolute的结果为true,我们可以在Properties界面中点击结点名abs看到Answer后面的值为valid
    • 如果Absolute的结果为false,我们可以在Properties界面中点击结点名abs看到Answer后面的值为falsifiable
  • 不同的约束求解器,会以不同的方式进行显示,上述结果为Z3求解器的结果,可以在右侧的smt_solver处进行选择
  • 除了--%PROPERTY Absolute;还可以使用check Absolute;来进行验证,效果是一样的。
  • –%PROPERTY后面除了直接跟变量外,也可也先跟一对引号,引号里面写上这个检查的名称,然后再跟变量,例如:–%PROPERTY “Absolute的检测” Absolute;
  • 如果仅仅是为了验证,我们也可也将node改为function,但每次Check完之后,都无法再进行编辑,因此一般不用function,看到带function的例子知道就行,但function我们在创建一个新的类型时会用到。

check验证求绝对值的代码

问题描述:不使用–%PROPERTY,而是用check验证求绝对值的代码是否有效

代码:

node abs(x:real) returns(y: real);
var Absolute: bool;
let
   y = if (x >= 0.0) then x else -x;
   Absolute = y >= 0.0;
   
   check Absolute;
   
tel

Check验证结果:
在这里插入图片描述

check和–%PROPERTY作用相同

=>的用法

问题描述:用=>验证求绝对值的代码是否有效,当输入的数值大于零时,求取的绝对值结果也应该大于零

代码:

-- 子结点
node s (Q:int) returns (X: int);
let
  X = if (Q >= 0) then Q else -Q;
tel

-- 主结点
node abs_2(Input:int) returns (OK: bool);
let
-- 主结点中调用子结点并将结果赋值给OK
  OK = (s(Input) >= 0);

--%PROPERTY Input > 0 => s(Input) > 0 ;
tel

Check执行结果:

在这里插入图片描述

=>的格式为:–%PROPERTY 约束条件 => 验证等式,在约束条件成立的情况下,验证等式有效时,Answer的值为valid,验证等式非法时,Answer的值为falsifiable

Answer的值为falsifiable的情况:将验证的约束条件由Input > 0改为Input >= 0时

代码:

-- 子结点
node s (Q:int) returns (X: int);
let
  X = if (Q >= 0) then Q else -Q;
tel

-- 主结点
node abs_2(Input:int) returns (OK: bool);
let
-- 主结点中调用子结点并将结果赋值给OK
  OK = (s(Input) >= 0);

--%PROPERTY Input >= 0 => s(Input) > 0 ;
tel

Check执行结果:

在这里插入图片描述

因为此时输入的状态Input的状态值可能等于0,而要验证的Input绝对值结果要大于零,所以此时验证等式为不成立的情况,Answer的值为falsifiable

结点的调用

问题描述:子结点对状态值进行绝对值处理,主结点调用子结点,验证数值是否大于零

代码:

-- 子结点
node s (Q:int) returns (X: int);
let
  X = if (Q >= 0) then Q else -Q;
tel

-- 主结点
node abs_2(Input:int) returns (OK: bool);
let
-- 主结点中调用子结点并将结果赋值给OK
  OK = (s(Input) >= 0);

--%PROPERTY OK;
tel

Simulate执行结果:
在这里插入图片描述

结点的调用补充说明

问题描述:如果定义了两个结点,但没有相互调用,则运行界面只显示第二个结点的运行界面

代码:

-- 第一个结点
node s (Q:int) returns (X: int);
let
  X = if (Q >= 0) then Q else -Q;
--%PROPERTY X > 1;
tel

-- 第二个结点
node abs_2(Input:int) returns (OK: bool);
let
-- 直接对OK赋值为true
  OK = true;

--%PROPERTY OK;
tel

Simulate执行结果:

在这里插入图片描述

  • 结点调用时,主结点和子结点的顺序不影响代码执行
  • 结点间如果没有调用,运行界面只显示最后一个结点的运行情况
  • 未被调用的结点不会进行Check,也就是点击Check后,第一个结点内的–%PROPERTY X > 1;不会进行验证

%MAIN 主结点的手动选择

问题描述:定义多个结点时,希望将第一个结点作为主结点,需要借助–%MAIN;实现

代码:

-- 第一个结点
node s (Q:int) returns (X: int);
let
  X = if (Q >= 0) then Q else -Q;
--%MAIN;
--%PROPERTY X > 1;
tel

-- 第二个结点
node abs_2(Input:int) returns (OK: bool);
let
-- 直接对OK赋值为true
  OK = true;

--%PROPERTY OK;
tel

Simulate执行结果:

在这里插入图片描述

使用–%MAIN;是请注意,后面的分号一定不要忘了,如果没加分号,则表示为注释

-> 的使用

问题描述:X = A -> 10表示状态X当前时刻的状态值赋值为A,以后时刻的状态值赋值为 -> 后面的值10

代码:

node s1 (A:int) returns (X : int ; Y : int ; Z : int ; K : int ; J : int ; AA : int);
let
  X =  A -> 10;
  Y =  A -> 20;
  Z =  A -> 10 -> 30;
  K =  pre (A -> 10) ;
  J =  60 -> pre (A -> 10) ;
  AA = A;
tel

Simulate执行结果:
在这里插入图片描述

  • 代码中的X = A -> B,表示X当前状态值为A,以后时刻的状态值为B,序列为:A,B,B,B…
  • 代码中的K = pre (A -> B),表示X当前状态值为0,下一时刻的状态值为A,以后时刻的状态值为B,序列为:0,A,B,B,B…(其实就是将A -> B的序列A,B,B,B…向后移了一位,第一位补零)
  • 代码中的J = C- > pre (A -> B),表示J当前状态值为AC,下一时刻的状态值为A,以后时刻的状态值为B,序列为:C,A,B,B,B…

assert的使用

问题描述:输入的整形I的值必须不小于零

-- 如果I大于等于零,返回I+2,否则返回I+X
node N(I, X: int) returns (Z: int);
let
  Z = if I >= 0 then I + 2 else I + X;
tel


node ReqN(I, X1, X2: int) returns (P: bool);
let
-- 要求I的值不小于零
  assert I >= 0; 
-- 判断输入不同的X值和相同的I值,判断结果是否相同
-- 因为要求I必须大于等于零,所以调用结点N的时候,结果为I + 2
-- 所以结点N(I,X1)的结果和结点N(I,X2)的结果应该都相同
  P =  N(I,X1) = N(I,X2);

-- 验证此时N(I,X1)是否等于N(I,X2)
-- 如果没有加条件I >= 0,那肯定是不相等的
-- 但既然加了I >= 0这个条件,那应该就是相等的了
-- 所以我们用Check验证一下P的值是否为真
--%PROPERTY P;
tel

Simulate执行结果:

  • 输入不小于零的值时,Logs内的显示无异常

在这里插入图片描述

  • 一旦有一个数小于零后,Logs内便会提示:error: Transition relation not satisfiable

在这里插入图片描述

Check验证结果:
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

print_Hyon

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值