“在 SPARK Ada 中接受挑战”- 后置条件下的总和鬼函数有意外行为

2024-01-02

我正在 SPARK Ada 中编写一个软件,它需要后置条件来验证函数返回值是否等于数组的求和值。在证明函数所在的文件后,我不断收到一个错误,该错误并没有完全加起来,没有双关语的意图(我将发布代码的屏幕截图以便更好地查看)。大小为 10 的数组中允许的唯一可接受的值是 0 或 1。


在下面的例子中(并且反对其他答案 https://stackoverflow.com/a/57171268),我将计算部分和的 Ghost 函数分离到一个通用的 Ghost 包中SPARK_Fold。从这个包中我使用了 Ghost 函数Sum_Acc证明求和循环Calc_ST。套餐Example可以使用 GNAT CE 2020 进行证明,证明级别设置为 1。

基础方法的学分:AdaCore 博客文章 https://blog.adacore.com/taking-on-a-challenge-in-spark.

示例.ads

with SPARK_Fold;

package Example with SPARK_Mode is
 
   subtype EEG_Reading_Index is Integer range 0 .. Integer'Last - 1;   
   subtype EEG_Reading       is Integer range 0 .. 1;
   
   type EEG_Readings is array (EEG_Reading_Index range <>) of EEG_Reading;
     
   package Sum_EEG_Readings is
     new SPARK_Fold.Sum
       (Index_Type  => EEG_Reading_Index,
        Element_In  => EEG_Reading,
        List_Type   => EEG_Readings,
        Element_Out => Natural);
   
   function Calc_ST (EEG : EEG_Readings) return Natural with
     Pre  => EEG'Length > 0,
     Post => Calc_ST'Result = Sum_EEG_Readings.Sum_Acc (EEG) (EEG'Last);   

end Example;

示例.adb(这里只是照常计算总和)。

package body Example with SPARK_Mode is

   -------------
   -- Calc_ST --
   -------------
   
   function Calc_ST (EEG : EEG_Readings) return Natural is
      Result : Natural := EEG (EEG'First);
   begin      
      for I in EEG'First + 1 .. EEG'Last loop
         
         pragma Loop_Invariant
           (Result = Sum_EEG_Readings.Sum_Acc (EEG) (I - 1));
         
         Result := Result + EEG (I);
        
      end loop;      
      return Result;      
   end Calc_ST;

end Example;

火花折叠.广告(通用帮助包)

package SPARK_Fold with Ghost is
   
   --  Based on the blog post:
   --     https://blog.adacore.com/taking-on-a-challenge-in-spark
   
   ---------
   -- Sum --
   ---------
   
   generic
      type Index_Type  is range <>;
      type Element_In  is range <>;
      type List_Type   is array (Index_Type range <>) of Element_In;
      type Element_Out is range <>;
   package Sum with Ghost is
      
      type Partial_Sums is array (Index_Type range <>) of Element_Out;   
   
      function Sum_Acc (L : List_Type) return Partial_Sums with 
        Ghost,
        Pre  =>  (L'Length > 0),
        Post =>  (Sum_Acc'Result'Length = L'Length) 
        and then (Sum_Acc'Result'First  = L'First) 
        and then (for all I in L'First .. L'Last =>
                    abs (Sum_Acc'Result (I)) <= Element_Out (I - L'First + 1) * Element_Out (Element_In'Last))
        and then (Sum_Acc'Result (L'First) = Element_Out (L (L'First)))
        and then (for all I in L'First + 1 .. L'Last =>
                    Sum_Acc'Result (I) = Sum_Acc'Result (I - 1) + Element_Out (L (I)));
      
   end Sum;
   
   -----------
   -- Count --
   -----------
   
   generic
      type Index_Type is range <>;
      type Element    is range <>;
      type List_Type  is array (Index_Type range <>) of Element;
      with function Choose (X : Element) return Boolean;
      --  Count the number of elements for which Choose returns True.
   package Count with Ghost is
      
      type Partial_Counts is array (Index_Type range <>) of Natural;
      
      function Count_Acc (L : List_Type) return Partial_Counts with 
        Ghost,
        Pre  =>  (L'Length > 0),
        Post =>  (Count_Acc'Result'Length = L'Length)
        and then (Count_Acc'Result'First  = L'First)
        and then (for all I in L'First .. L'Last =>
                    Count_Acc'Result (I) <= Natural (I) - Natural (L'First) + 1) 
        and then (Count_Acc'Result (L'First) = (if Choose (L (L'First)) then 1 else 0)) 
        and then (for all I in L'First + 1 .. L'Last =>
                    Count_Acc'Result (I) = Count_Acc'Result (I - 1) + (if Choose (L (I)) then 1 else 0));
      
   end Count;

end SPARK_Fold;

Spark_fold.adb

package body SPARK_Fold is

   ---------
   -- Sum --
   ---------
   
   package body Sum is
      
      function Sum_Acc (L : List_Type) return Partial_Sums is
         Result : Partial_Sums (L'Range) := (others => 0);
      begin
      
         Result (L'First) := Element_Out (L (L'First));
      
         for Index in L'First + 1 .. L'Last loop
      
            --  Head equal.
            pragma Loop_Invariant
              (Result (L'First) = Element_Out (L (L'First)));
         
            --  Tail equal.
            pragma Loop_Invariant
              (for all I in L'First + 1 .. Index - 1 =>
                 Result (I) = Result (I - 1) + Element_Out (L (I))); 
         
            --  Result within bounds.
            pragma Loop_Invariant
              (for all I in L'First .. Index - 1 =>
                  abs (Result (I)) <= Element_Out (I - L'First + 1) * Element_Out (Element_In'Last));
               
            Result (Index) := Result (Index - 1) + Element_Out (L (Index));
      
         end loop;
      
         return Result;
      
      end Sum_Acc;
      
   end Sum;
     
   -----------
   -- Count --
   -----------
     
   package body Count is
      
      function Count_Acc (L : List_Type) return Partial_Counts is
         Result : Partial_Counts (L'Range) := (others => 0);
      begin
      
         if Choose (L (L'First)) then
            Result (L'First) := 1;
         else
            Result (L'First) := 0;
         end if;
      
         for Index in L'First + 1 .. L'Last loop
      
            --  Head equal.
            pragma Loop_Invariant
              (Result (L'First) = (if Choose (L (L'First)) then 1 else 0));
         
            --  Tail equal.
            pragma Loop_Invariant
              (for all I in L'First + 1 .. Index - 1 =>
                 Result (I) = Result (I - 1) + (if Choose (L (I)) then 1 else 0)); 
         
            --  Bounds.
            pragma Loop_Invariant 
              (for all I in L'First .. Index - 1 =>
                 Result (I) <= Natural (I) - Natural (L'First) + 1);
               
            if Choose (L (Index)) then
               Result (Index) := Result (Index - 1) + 1;
            else
               Result (Index) := Result (Index - 1) + 0;
            end if;
               
         end loop;
      
         return Result;
      
      end Count_Acc;
      
   end Count;

end SPARK_Fold;
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

“在 SPARK Ada 中接受挑战”- 后置条件下的总和鬼函数有意外行为 的相关文章

  • Ada 中的自定义“图像属性”?

    所以我有一件事 type Thing is new record elements end record 我有一个将其字符串化的函数 function ToString t Thing returns string 我希望能够告诉 Ada
  • 谁能告诉我 pragma 语句的用法

    谁能告诉我 C 和 Ada 中 pragma 的使用 如果可能的话请提供一些例子 C99 中有 3 个标准编译指示 pragma STDC FP CONTRACT on off switch pragma STDC FENV ACCESS
  • “在此上下文中需要子类型标记”到底是什么?

    I get Subtype mark required in this context at 子类型掩码到底是什么 为什么它在这里抱怨 main adb Open Route Route 1 3 others gt new Location
  • Ada 95:修改字典程序的输出

    我找到了这本词典作者 William Whitaker 在互联网上 我喜欢它的解析能力 但输出不适合我 问题 对我来说是挑战 给定输入形式 例如 audiam 程序将返回以下输出 纯文本 audi am V 4 1 PRES ACTIVE
  • Ada:gnat gprbuild 如何链接到库中?

    在我正在处理的这个多语言 GPRBuild 项目中 我有一些 C 库文件 a 我需要链接到我的可执行文件中 是否有 gpr 属性告诉它链接什么或无论如何将 l L 开关传递给链接器 或者甚至更好 Project my library is
  • 是否可以声明具有无限上限的 Ada 范围?

    我想在 Ada 中声明记录类型的速度范围 下面的方法行不通 但是有没有办法让它工作呢 Speed in knots range 0 to unlimited Speed float Range 0 0 unlimited 我只想要这个数字的
  • 如何检查一个元素是否属于一种子类型或另一种子类型?

    刚刚了解了 Ada 中的枚举和类型 决定写一个小程序来练习 with Ada Text IO use Ada Text IO with Ada Integer Text IO use Ada Integer Text IO procedur
  • 如何从 Ada 源构建可从 C++ 代码调用的静态库?

    我需要使用一堆用 Ada 编写的代码构建一个静态库 可以从用 C C 编写的代码中调用这些代码 我通过互联网搜索并了解了一些知识gnatmake gnatbind and gnatlink 但仍然无法正确完成工作 另外 我读到有些工具依赖于
  • 为什么字符串需要用初始值初始化?

    我有一根绳子lx String我想稍后在代码中设置该值 但出现错误unconstrained subtype not allowed need initialization provide initial value or explicit
  • 在 Ada 中实现具有访问类型的抽象函数

    我有一个名为 Statements 的包 其中包含一个名为 Statement 的抽象类型和一个名为execute 的抽象函数 在另一个包中 我有一个CompoundStatement 类型 它是一个Statement 类型 它实现了exe
  • 如何阻止控制台窗口立即关闭 | GNAT-GPS

    我有 Ada 程序 可以使用 GNAT GPS 完美运行和编译 当我运行其 exe 文件并提供用户输入时 该 exe 会立即关闭 而不是说 按任意键继续 我在网上搜索了很多 但我只找到了与使用 system pause 的 c c visu
  • SPARK 整数溢出检查

    我有以下程序 procedure Main with SPARK Mode is F array 0 10 of Integer 0 1 others gt 0 begin for I in 2 F Last loop F I F I 1
  • ADA 文件名与包名称

    我继承了一个 ADA 程序 其中源文件名和包文件名不遵循默认命名约定 ADA 对我来说是新的 所以我可能会错过一些简单的东西 但我在 GNAT Pro 用户指南中看不到它 这个类似的问题 https stackoverflow com qu
  • 从 Ada 访问 c 常量

    我有一个带有这样类型定义的头文件 ifndef SETSIZE define SETSIZE 32 endif typedef struct set unsigned array SETSIZE set t 要使用相应的 C 函数 我需要在
  • 确定 Ravenscar 程序中堆栈使用情况的最佳实践

    我正在使用 Ravenscar 子集编写一个 Ada 程序 因此 我知道执行时正在运行的任务数量 该代码是由 gcc 编译的 fstack check https gcc gnu org onlinedocs gnat ugn Stack
  • Ada95 中的线程和信号量

    如何在 Ada95 中使用线程 我可以使用哪些函数来创建 销毁 停止和启动它们 我如何在这种语言中使用信号量 并发性内置于该语言中 因此您可以为任务 即线程 和受保护对象 即比信号量 互斥体 条件变量更强大 使用特定的 Ada 语法 这使得
  • 使用 GtkAda 发出信号

    我担心的是我创建了一个回调函数 它应该显示Gtk Entry当我们点击Gtk Button但当我点击按钮时什么也没有发生 我不明白 File ads Package Test is Type T Test is record Contene
  • 创建不兼容的数字子类型

    在 Ada 中 可以创建不兼容的等效数字类型 type Integer 1 is range 1 10 type Integer 2 is range 1 10 A Integer 1 8 B Integer 2 A illegal 这可以
  • Ada 的命令行参数

    我正在编写一个 Ada 程序 该程序应该对字母字符进行大小写转换 该程序使用 1 2 或 3 个命令行参数 我几乎已经把事情写下来了 但我不知道如何进行论证 命令行参数是 单个字符指定是否要进行大写转换或小写转换 应用于输入 U 或 u 表
  • 对于匿名访问类型重载运算符“=”?

    我正在读巴恩斯那本出色的 艾达 一书 这是第 11 7 节中用于深度比较链表的代码示例 type Cell is record Next access Cell Value Integer end record function L R a

随机推荐