如何在 Ada 中对 2D 数组类型作为参数的函数进行算术合约运算

How to perform arithmetic contract operations on function taking in 2D array type as parameter in Ada

提问人:Simple_tech 提问时间:7/10/2019 最后编辑:Simple_tech 更新时间:8/1/2019 访问量:156

问:

  1. 我有一个函数,应该返回找到的岛屿计数。

  2. 我将这个函数命名为 Count_Islands 它接受一个参数 Map 类型的Map_Array,其中 Map 是 Islands 数组。

  3. Islands 是一种枚举器类型,其中包含 Land、Water。

  4. 我在 .ads 中有函数规范,正文在 。亚行

  5. 我现在面临的问题是如何证明我的函数 Count_Islands'Result 将小于 (X * Y)

  6. 我试过了: with post => Count_Islands'Result < X * Y -- 每当我运行证明我得到的一切时: medium: post条件可能 失败无法证明Count_Islands'的结果< X * Y

.ads 中的函数:

function Count_Islands(Map_Array : Map) 
    return Integer with Pre => Map_Array'Length /= 0, 
                        Post => Count_Islands'Result < X * Y;

.adb 中的函数:

function Count_Islands(Map_Array : Map) return Integer
   is
      Visited_Array : Visited := (others => (others=> False));
      Count : Integer := 0;
   begin
      if (Map_Array'Length = 0)then
         return 0;
      end if;
      for i in X_Range loop
         for j in Y_Range loop
            if (Map_Array(i, j) = Land and then not Visited_Array(i,j)) then
               Visited_Array := Visit_Islands(Map_Array, i, j,Visited_Array);
               Count := Count + 1;
            end if;
         end loop;
      end loop;
      return Count;
   end Count_Islands;

例如,在 4 * 5 的矩阵中,即我的 X = 4 和 Y = 5

我希望发现 Islands(Lands) 的输出结果为 1,小于 4 * 5。但是GNATproven无法证明我的初始代码来分析这一点,使用Post => Count_Islands'Result < X * Y;

有没有更好的方法来证明这个算术?感谢您的帮助。

ADA 代码-合同 gaps-and-islands spark-ada

评论

0赞 7/26/2019
示例不够完整,无法猜测。X 和 Y 与 X_Range 和 Y_Range有什么关系?问题可能出在那里,或者出在<与<=上。
0赞 Simple_tech 7/28/2019
@Brian它们是相关的。感谢您的关注。

答:

1赞 DeeDee 7/11/2019 #1

由于这个例子不完整,我冒昧地对它做了一些改动。您可以通过添加循环不变量来证明后置条件。以下程序在 GNAT CE 2019 中证明:

main.adb

procedure Main with SPARK_Mode is

   --  Limit the range of the array indices in order to prevent 
   --  problems with overflow, i.e.:
   --
   --     Pos'Last * Pos'Last <= Natural'Last
   --
   --  Hence, as Natural'Last = 2**31 - 1,
   --
   --     Pos'Last <= Sqrt (2**31 - 1) =approx. 46340
   --
   --  If Pos'Last >= 46341, then overflow problems might occur. 

   subtype Pos is Positive range 1 .. 46340;

   type Map_Item is (Water, Land);

   type Map is
     array (Pos range <>, Pos range <>) of Map_Item;

   type Visited is
     array (Pos range <>, Pos range <>) of Boolean;


   function Count_Islands (Map_Array : Map) return Natural with
     Post => Count_Islands'Result <= Map_Array'Length (1) * Map_Array'Length (2);


   -------------------
   -- Count_Islands --
   -------------------

   function Count_Islands (Map_Array : Map) return Natural is

      Visited_Array : Visited (Map_Array'Range (1), Map_Array'Range (2)) :=
        (others => (others => False));

      Count : Natural := 0;

   begin

      for I in Map_Array'Range (1) loop

         pragma Loop_Invariant
           (Count <= (I - Map_Array'First (1)) * Map_Array'Length (2));

         for J in Map_Array'Range (2) loop            

            pragma Loop_Invariant
              (Count - Count'Loop_Entry <= J - Map_Array'First (2));

            if Map_Array(I, J) = Land and then not Visited_Array(I, J) then
               Visited_Array (I, J) := True;   --  Simplified
               Count := Count + 1;
            end if;

         end loop;

      end loop;      

      return Count;

   end Count_Islands;

begin
   null;
end Main;

评论

1赞 DeeDee 7/12/2019
@AspMVCAda,我回顾了我的示例,并得出结论,您实际上不需要幻影变量。您只需要两个循环不变量。请参阅更新后的答案。