主頁 > .NET開發 > 如何在SPARK中為遞回函式制定前、后條件?

如何在SPARK中為遞回函式制定前、后條件?

2021-10-17 00:11:47 .NET開發

我正在將我在Dafny中做的一個練習翻譯成SPARK,在這個練習中,人們用一個尾部遞回函式來驗證一個遞回的函式。Dafny的源代碼(有刪減,因為它可能仍然被用于類):

函式Sum(n:nat):nat 遞減n { if n==0 then n else n Sum(n-1) } 方法 ComputeSum(n:nat) 回傳 (s:nat) 確保s == Sum(n) { s := 0; // ...審查... }

到目前為止,我在SPARK中得到的東西:

function Sum (n : in Natural) return Natural 是 開始 如果n=0,那么 回傳n。 否則 回傳 n Sum(n - 1)。 end if; 結束Sum。 函式 ComputeSum(n : in Natural) 回傳 Natural 與 Post => ComputeSum'Result = Sum(n) 是 s : 自然 :=0。 開始 回傳s。 結束 ComputeSum。

我似乎無法弄清楚如何表達decreases n條件(現在我想起來可能有點奇怪......但幾年前我因為這個問題被打分,所以我有什么資格評判,問題仍然是如何完成它)。因此,我得到了可能溢位和/或無限遞回的警告。

我猜想有一個前置或后置條件需要添加。我嘗試了Pre => n <= 1,這顯然不會溢位,但我仍然得到了警告。在此基礎上添加Post => Sum'Result <= n**n,使警告消失,但該條件得到 "postcondition might fail "警告,這是不對的,但估計驗證器無法分辨。這也不是我應該檢查的運算式,但我似乎無法理解我在尋找的其他Post。可能是與遞回運算式非常接近的東西,但我的嘗試都沒有成功。一定是遺漏了某些語言結構......

那么,我如何才能在一個人的身上找到 "遞回運算式"?

那么,我怎樣才能表達遞回約束呢?


編輯1:

按照這個SO答案這個SPARK檔案部分的鏈接,我嘗試這樣做:

function Sum (n : in Natural) return Natural
是
  (如果n = 0,那么0,否則n   Sum(n - 1))
    與
      Pre => (n in 0 ... 2)。
      Contract_Cases => (n = 0 => Sum'Result = 0,
                         n >= 1 => Sum'Result = n   Sum(n - 1))。)
      Subprogram_Variant => (Decreases => n)。

但是從SPARK得到這些警告:

spark.adb:32:30: medium: overflow check might fail [reason for check: result of addition must fit in a 32-bits machine integer][#0] 。 spark.adb:36:56: 警告:在其后置條件中呼叫 "Sum "將導致無限遞回。

uj5u.com熱心網友回復:

如果你想證明某個尾部遞回求和函式的結果等于某個值N的給定遞回求和函式的結果,那么原則上,只需要定義遞回函式(作為運算式函式)而沒有任何后置條件就足夠了。然后你只需要在尾部遞回函式的后置條件中提到遞回(運算式)函式(注意,在 Dafny 中也沒有對遞回函式的后置條件(ensures))。

然而,由于SPARK的主要目標之一是證明不存在運行時錯誤,你必須證明溢位不會發生,并且由于這個原因,你確實需要一個遞回函式的后置條件。正如 @Jeffrey Carter 已經在評論中建議的那樣,這種后置條件的合理選擇是 算術級數的顯式求和公式

Sum (N) = N * (1   N) / 2

這個選擇實際上是非常有吸引力的,因為有了這個公式,我們現在還可以根據一個眾所周知的計算一系列自然數之和的數學明確運算式來對遞回函式本身進行功能驗證。

不幸的是,使用這個公式原樣只能讓你走到一半。在SPARK中(也包括Ada),前置條件和后置條件是可以選擇執行的(參見RM 11.4.2和SPARK參考指南中的5.11.1部分),因此本身必須是沒有任何運行時錯誤。因此,按原樣使用該公式只能讓你證明任何正數都不會發生溢位,直到

max N s.

max N s.t. N * (1   N) <= Integer'Last <-> N = 46340

在后置條件中,乘法也不允許溢位(注意,Natural'Last = Integer'Last = 2**31-1)。

為了解決這個問題,你需要利用Ada 202x標準庫中引入的大整數包(另見RM A.5.6;這個包已經包含在GNAT CE 2021和GNAT FSF 11.2中)。大整數是無界的,用這些整數進行的計算絕不會溢位。使用這些整數,我們可以證明任何正數都不會發生溢位,直到

max N s.

max N s.t. N * (1   N) / 2 <= Natural'Last <-> N = 65535 = 2**16 - 1

下面的例子說明了這些整數在后置條件中的用法。

一些最后的注釋:

  • Subprogram_Variant方面只需要證明一個遞回子程式最終會終止。這樣的終止證明必須通過向函式添加注解來明確要求(也顯示在下面的例子中,并在評論中由@egilhh指出的SPARK檔案中討論)。然而,對于你最初的目的來說,Subprogram_Variant方面是不需要的:證明某個尾部遞回求和函式的結果等于某個值N的特定遞回求和函式的結果。

  • 要編譯一個使用新的Ada 202x標準庫中的函式的程式,使用編譯器選項-gnat2020

  • 雖然我使用子型別來約束N的允許值范圍,但你也可以使用一個前提條件。這不應該有任何區別。然而,在SPARK(也包括Ada)中,一般認為盡可能使用(子)型別來表達約束是一種最佳做法。

  • 將反例視為可能的線索而不是事實。它們可能有意義,也可能沒有意義。反例是由一些求解器選擇性地生成的,可能沒有意義。參見SPARK用戶指南中的7.2.6節

main.adb

用Ada.Numerics.Big_Numbers.Big_Integers;

帶有SPARK_Mode的程序Main是
   
   包BI重命名Ada.Numerics.Big_Numbers.Big_Integers。
   使用型別BI.Valid_Big_Integer。
   
   -- 轉換函式。
   function To_Big (Arg : Integer) return BI.Valid_Big_Integer 重命名BI.To_Big_Integer。
   function To_Int (Arg : BI.Valid_Big_Integer) return Integer 重命名BI.To_Integer。
      
   子型別Domain是自然范圍0 ... 2**16 - 1。
   
   函式 Sum (N : Domain) 回傳 Natural 是
     (如果N=0則為0,否則N Sum(N-1))
       與
         Post => Sum'Result = To_Int (To_Big (N) * (1   To_Big (N)) / 2),
         Subprogram_Variant => (Decreases => N);
   
   -- 要求證明Sum對所有可能的N值都會終止。
   pragma Annotate (GNATprove, Terminating, Sum);
   
開始
   null。
結束主。

輸出(gnatprove)

$ gnatprove -Pdefault.gpr --output=oneline --report=all --level=1-prover=z3
第2階段:生成全球合同 ...
第2階段:流程分析和證明 ...
main.adb:13:13: 資訊:子程式 "Sum "將終止,終止注釋已被證明。
main.adb:14:30: 資訊:溢位檢查已證明
main.adb:14:32: 資訊:子程式變體已被證明
main.adb:14:39: 資訊:范圍檢查已證明
main.adb:16:18: 資訊:后置條件已證明
main.adb:16:31: 資訊:范圍檢查已證明。
main.adb:16:53: 資訊: 謂詞檢查已證明
main.adb:16:69: 資訊:證明了除法檢查。
main.adb:16:71: 資訊: 謂詞檢查已證明
摘要登錄[...]/gnatprove.out

補充說明(針對評論)

因此,你可以將后置條件添加為遞回函式,但這對證明不存在溢位沒有幫助;你仍然必須對函式結果提供一些上限,以便說服驗證者,運算式N Sum (N - 1)不會導致溢位。

為了檢查加法程序中是否存在溢位,驗證者將考慮Sum根據其規范可能回傳的所有可能的值,并查看這些值中是否至少有一個可能導致加法溢位。在后置條件中沒有明確的約束,Sum可能根據其回傳型別,回傳Natural'Range范圍內的任何值。這個范圍包括Natural'Last,這個值肯定會導致溢位。因此,驗證器將報告說加法可能溢位。事實上,Sum在其允許的輸入值下從未回傳該值,這與此無關(這就是為什么它報告might)。因此,我們需要一個關于回傳值的更精確的上限值。

如果精確的上界不可用,那么你通常會退回到一個更保守的邊界,例如,在這種情況下,N * N(或者使用飽和數學,如SPARK用戶手冊中的斐波那契例子所示,5.2.7節,但是這種方法改變你的函式,可能不可取)。

這里有一個替代的例子:

example.ads

package Example的SPARK_Mode是

   子型別Domain是自然范圍0 ... 2**15。

   函式Sum (N : Domain) 回傳Natural
     with Post => 
       Sum'Result = (if N = 0 then 0 else N   Sum (N - 1)) and
       Sum'Result <= N * N; -- 保守的上界,如果封閉形式的
                              -- 遞回函式的封閉形式的解將
                              --不存在。
結束示例。

example.adb

帶有SPARK_Mode的package body Example是

   函式 Sum (N : Domain) 回傳 Natural 是
   開始
      如果N=0,那么
         回傳N。
      否則
         回傳 N   Sum (N - 1)。
      end if;
   結束Sum。

結束示例。

output (gnatprove)

$ gnatprove -Pdefault.gpr --output=oneline --report=all
第2階段:生成全球合同 ...
第2階段:流程分析和證明 ...
example.adb:8:19: 資訊:溢位檢查已被證明
example.adb:8:28: 資訊:范圍檢查已證明
example.adb:7:08: 資訊:后置條件被證明。
example.adds:7:45: 資訊:溢位檢查已證明
example.adds:7:54: 資訊:范圍檢查已證明
摘要登錄[...]/gnatprove.out

uj5u.com熱心網友回復:

我找到了一些有時能起作用的東西,我認為這對于關閉標題問題來說已經足夠了:

函式Sum(sum)()()

function Sum (n : in Natural) return Natural
是
  (如果n = 0,那么0,否則n   Sum(n - 1))
    與
      Pre => (n in 0 ... 10), -- 與--prover=z3一起作業,不是Default (CVC4)
      -- Pre => (n in 0 ... 100), -- 不作業 -- "溢位檢查可能失敗,例如當n = 2時"
      Subprogram_Variant => (Decreases => n),
      Post => ((n = 0 and then Sum'Result = 0)
               或(n > 0然后Sum'Result = n   Sum(n - 1)))。
      -- Contract_Cases => (n = 0 => Sum'Result = 0,
      -- n > 0 => Sum'Result = n   Sum(n - 1)); -- 警告:在其后置條件中呼叫 "Sum "會導致無限遞回。
      -- Contract_Cases => (n = 0 => Sum'Result = 0,
      -- n > 0 => n   Sum(n - 1) = Sum'Result); -- 有效
      -- Contract_Cases => (n = 0 => Sum'Result = 0。
      -- n > 0 => Sum'Result = n * (n   1) / 2); -- 有效,并對高n給出了良好的溢位反例,但并不是真正的遞回

GNAT Studio中的命令列呼叫(Ctrl Alt F),--counterproof=on和--prover=z3是我對它的補充:

gnatprove -P%PP -j0 %X --output=oneline --ide-progress-bar --level=0 -u %fp --counterexamples=on --prover=z3

心得體會:

  • Subprogram_Variant => (Decreases => n)需要告訴驗證器每次遞回呼叫的n次遞減,就像Dafny版本一樣。
      對于類似的合同,作業方式不一致,見注釋Contract_Cases
  • 默認的驗證器(CVC4)失敗,使用Z3成功。
  • 失敗時的反證沒有意義。
  • n = 20 ... 100的范圍內呈現為反證,但在0 ... 10的范圍內沒有。
  • 可能與SPARK用戶指南中的這一提及有關。然而,請注意,由于反例總是只使用CVC4驗證器生成的,它只能解釋為什么這個驗證器不能證明這個屬性。
  • 在改變所需的選項之間進行清理,例如,--驗證器。

    轉載請註明出處,本文鏈接:https://www.uj5u.com/net/319303.html

    標籤:

    上一篇:遞回查找并將其作為一個陣列加入

    下一篇:遞回陣列.push()的問題

  • 標籤雲
    其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

    熱門瀏覽
    • WebAPI簡介

      Web體系結構: 有三個核心:資源(resource),URL(統一資源識別符號)和表示 他們的關系是這樣的:一個資源由一個URL進行標識,HTTP客戶端使用URL定位資源,表示是從資源回傳資料,媒體型別是資源回傳的資料格式。 接下來我們說下HTTP. HTTP協議的系統是一種無狀態的方式,使用請求/ ......

      uj5u.com 2020-09-09 22:07:47 more
    • asp.net core 3.1 入口:Program.cs中的Main函式

      本文分析Program.cs 中Main()函式中代碼的運行順序分析asp.net core程式的啟動,重點不是剖析原始碼,而是理清程式開始時執行的順序。到呼叫了哪些實體,哪些法方。asp.net core 3.1 的程式入口在專案Program.cs檔案里,如下。ususing System; us ......

      uj5u.com 2020-09-09 22:07:49 more
    • asp.net網站作為websocket服務端的應用該如何寫

      最近被websocket的一個問題困擾了很久,有一個需求是在web網站中搭建websocket服務。客戶端通過網頁與服務器建立連接,然后服務器根據ip給客戶端網頁發送資訊。 其實,這個需求并不難,只是剛開始對websocket的內容不太了解。上網搜索了一下,有通過asp.net core 實作的、有 ......

      uj5u.com 2020-09-09 22:08:02 more
    • ASP.NET 開源匯入匯出庫Magicodes.IE Docker中使用

      Magicodes.IE在Docker中使用 更新歷史 2019.02.13 【Nuget】版本更新到2.0.2 【匯入】修復單列匯入的Bug,單元測驗“OneColumnImporter_Test”。問題見(https://github.com/dotnetcore/Magicodes.IE/is ......

      uj5u.com 2020-09-09 22:08:05 more
    • 在webform中使用ajax

      如果你用過Asp.net webform, 說明你也算是.NET 開發的老兵了。WEBform應該是2011 2013左右,當時還用visual studio 2005、 visual studio 2008。后來基本都用的是MVC。 如果是新開發的專案,估計沒人會用webform技術。但是有些舊版 ......

      uj5u.com 2020-09-09 22:08:50 more
    • iis添加asp.net網站,訪問提示:由于擴展配置問題而無法提供您請求的

      今天在iis服務器配置asp.net網站,遇到一個問題,記錄一下: 問題:由于擴展配置問題而無法提供您請求的頁面。如果該頁面是腳本,請添加處理程式。如果應下載檔案,請添加 MIME 映射。 WindowServer2012服務器,添加角色安裝完.netframework和iis之后,運行aspx頁面 ......

      uj5u.com 2020-09-09 22:10:00 more
    • WebAPI-處理架構

      帶著問題去思考,大家好! 問題1:HTTP請求和回傳相應的HTTP回應資訊之間發生了什么? 1:首先是最底層,托管層,位于WebAPI和底層HTTP堆疊之間 2:其次是 訊息處理程式管道層,這里比如日志和快取。OWIN的參考是將訊息處理程式管道的一些功能下移到堆疊下端的OWIN中間件了。 3:控制器處理 ......

      uj5u.com 2020-09-09 22:11:13 more
    • 微信門戶開發框架-使用指導說明書

      微信門戶應用管理系統,采用基于 MVC + Bootstrap + Ajax + Enterprise Library的技術路線,界面層采用Boostrap + Metronic組合的前端框架,資料訪問層支持Oracle、SQLServer、MySQL、PostgreSQL等資料庫。框架以MVC5,... ......

      uj5u.com 2020-09-09 22:15:18 more
    • WebAPI-HTTP編程模型

      帶著問題去思考,大家好!它是什么?它包含什么?它能干什么? 訊息 HTTP編程模型的核心就是訊息抽象,表示為:HttPRequestMessage,HttpResponseMessage.用于客戶端和服務端之間交換請求和回應訊息。 HttpMethod類包含了一組靜態屬性: private stat ......

      uj5u.com 2020-09-09 22:15:23 more
    • 部署WebApi隨筆

      一、跨域 NuGet參考Microsoft.AspNet.WebApi.Cors WebApiConfig.cs中配置: // Web API 配置和服務 config.EnableCors(new EnableCorsAttribute("*", "*", "*")); 二、清除默認回傳XML格式 ......

      uj5u.com 2020-09-09 22:15:48 more
    最新发布
    • C#多執行緒學習(二) 如何操縱一個執行緒

      <a href="https://www.cnblogs.com/x-zhi/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2943582/20220801082530.png" alt="" /></...

      uj5u.com 2023-04-19 09:17:20 more
    • C#多執行緒學習(二) 如何操縱一個執行緒

      C#多執行緒學習(二) 如何操縱一個執行緒 執行緒學習第一篇:C#多執行緒學習(一) 多執行緒的相關概念 下面我們就動手來創建一個執行緒,使用Thread類創建執行緒時,只需提供執行緒入口即可。(執行緒入口使程式知道該讓這個執行緒干什么事) 在C#中,執行緒入口是通過ThreadStart代理(delegate)來提供的 ......

      uj5u.com 2023-04-19 09:16:49 more
    • 記一次 .NET某醫療器械清洗系統 卡死分析

      <a href="https://www.cnblogs.com/huangxincheng/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/214741/20200614104537.png" alt="" /&g...

      uj5u.com 2023-04-18 08:39:04 more
    • 記一次 .NET某醫療器械清洗系統 卡死分析

      一:背景 1. 講故事 前段時間協助訓練營里的一位朋友分析了一個程式卡死的問題,回過頭來看這個案例比較經典,這篇稍微整理一下供后來者少踩坑吧。 二:WinDbg 分析 1. 為什么會卡死 因為是表單程式,理所當然就是看主執行緒此時正在做什么? 可以用 ~0s ; k 看一下便知。 0:000> k # ......

      uj5u.com 2023-04-18 08:33:10 more
    • SignalR, No Connection with that ID,IIS

      <a href="https://www.cnblogs.com/smartstar/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/u36196.jpg" alt="" /></a>...

      uj5u.com 2023-03-30 17:21:52 more
    • 一次對pool的誤用導致的.net頻繁gc的診斷分析

      <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

      uj5u.com 2023-03-28 10:15:33 more
    • 一次對pool的誤用導致的.net頻繁gc的診斷分析

      <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

      uj5u.com 2023-03-28 10:13:31 more
    • C#遍歷指定檔案夾中所有檔案的3種方法

      <a href="https://www.cnblogs.com/xbhp/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/957602/20230310105611.png" alt="" /></a&...

      uj5u.com 2023-03-27 14:46:55 more
    • C#/VB.NET:如何將PDF轉為PDF/A

      <a href="https://www.cnblogs.com/Carina-baby/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2859233/20220427162558.png" alt="" />...

      uj5u.com 2023-03-27 14:46:35 more
    • 武裝你的WEBAPI-OData聚合查詢

      <a href="https://www.cnblogs.com/podolski/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/616093/20140323000327.png" alt="" /><...

      uj5u.com 2023-03-27 14:46:16 more