色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

從數學角度思考程序與驗證正確性

jf_wN0SrCdH ? 來源:Rust語言中文社區 ? 2023-03-07 09:40 ? 次閱讀

本文旨在為沒有接觸過形式化方法的讀者提供一種新的視角看待計算機系統與算法,而非形式化方法或 TLA+ 教程因此本文的重點是如何從數學角度思考程序,不會使用大篇幅講解 TLA+ 的語法。

1

我們該如何寫出正確的程序?

程序設計的目標永遠是寫出正確的程序。隨著時間的推移,我們的程序越來越復雜,其中可能存在的錯誤也越來越多。想要寫出正確的程序,首先應該了解程序中可能出現的錯誤有哪些。

程序中會有什么樣錯誤?

我將程序中可能出現的錯誤粗略地分為兩類:簡單錯誤與邏輯錯誤。

簡單錯誤

簡單錯誤包含語義錯誤、內存錯誤等。對于這些容易分析的簡單錯誤,我們已經有很多成熟的方法與工具來避免,如編譯器、靜態分析工具、Garbage Collector 等。由于這類錯誤可以比較容易地被發現與修復,因此不是我們關注的重點。

邏輯錯誤

邏輯錯誤是程序中最難發現的錯誤,也是最難修復的錯誤,如死鎖、競態條件、數據不一致等。邏輯錯誤影響了程序的正確性、性能、可靠性等指標,通常是由于程序的設計不夠完善導致的。對于這類錯誤,我們需要從更高的層面來分析與設計程序,而非僅僅從代碼的實現細節來考慮。

我們通常會使用一些方法來避免邏輯錯誤,如:

  • 優化軟件架構設計- 在設計階段就考慮程序的正確性,避免設計出不夠完善的程序
  • 測試- 使用各種測試方法來減少程序的錯誤,但無法保證程序的完全正確
經驗不難看出,上述理論都是通過總結經驗得出的。經驗是在實踐中積累的,我們將經驗加以總結,得出指導性的原則、方法與步驟,可以幫助我們設計出更好的程序。 我們能否僅依賴于經驗?

越有經驗的人往往能想到更多的細節與可能性,設計出的系統通常更穩定。但我們不能僅僅依賴于經驗:

  • 經驗有局限性- 人類的經驗是有限且不可靠的
  • 復雜系統的行為、狀態太多- 一個復雜的系統,其行為與狀態太多,很難通過經驗來預測
  • 特定程序對正確性的要求很高- 有些程序對正確性的要求很高,如金融系統、醫療系統等,這些程序的正確性很難通過經驗來保證
  • 無法從理論上驗證正確性- 只能盡量減少錯誤的發生,但無法從理論上證明程序的正確性

綜上,我們需要一種更加嚴謹的方法,從設計上保證程序的正確性。

形式化方法

如果能夠從數學角度驗證一個程序的正確性,就可以解決上述的問題,這就是形式化方法的目標。

形式化方法基于數學,通過為系統建立數學模型,來定義系統的行為、狀態等,然后定義系統的約束條件,如安全性、活性,最終證明模型滿足系統形式規約,來驗證系統的正確性。對于有窮狀態的系統,可以使用以窮盡搜索為基礎的模型檢測,通過搜索待驗證系統模型的有窮狀態空間來檢驗該系統的行為是否具備預期屬性。對于有無窮狀態空間的系統,使用邏輯推理為基礎的演繹驗證,利用歸納法驗證系統的正確性。

本文用 TLA+ 語言作為工具來介紹形式化方法。

2

TLA+

TLA+ 的作者是在并發和分布式系統領域做出開創性貢獻的 2013 年圖靈獎獲得者,計算機科學家 Leslie Lamport。

TLA+ 是一種用于對程序和系統進行建模的高級語言——尤其是并發和分布式程序和系統。其核心思想是:精確描述事物的最佳方式是使用簡單的數學。TLA+ 及其工具可用于消除的設計錯誤,這些錯誤很難在代碼中發現并且糾正起來代價高昂。

使用 TLA+ 編寫的 specification 并不是真正的工程代碼,無法用在生產環境中,因為 TLA+ 的目標是在系統設計階段就發現并解決邏輯錯誤。在 TLA+ 中,我們將程序抽象為有窮狀態的數學模型,通常是狀態機,然后利用 TLC Model Checker 窮盡程序所有可能到達的狀態并驗證其正確性。

下面通過兩個簡單的例子介紹 TLA+。這兩個例子均來自 TLA+ 作者的 Leslie Lamport's The TLA+ Video Course。本文的目標是為沒有接觸過形式化方法的讀者提供一種新的視角看待計算機系統與算法,而不是 TLA+ 教程,因此不會過多介紹 TLA+ 的語法與工具的使用。

簡單的例子

TLA+ 可以讓我們使用簡單的數學抽象系統模型,主要是集合論與布爾邏輯。在抽象的過程中,我們要舍棄很多實現細節,僅關注程序的邏輯本身。

下面是一個簡單的 C 語言程序,我們嘗試將其抽象為一個 TLA+ 程序:

inti;
voidmain(){
i=someNumber();//someNumber()用來得到一個0到1000之間的數字
i=i+1;
}
狀態抽象

我們需要將這個程序抽象為一個個獨立的狀態。很顯然,對于這個簡單的程序,各狀態之間的不同點只有i的值。假設i在初始化后的默認值是 0,且某次運行這個程序時someNumber()返回了 42,那么這個程序存在的狀態轉換關系就是:

[i : 0] -> [i : 42] -> [i : 43]

這之中有三個狀態,每個狀態間的區別均為i的值不同。

這樣看似完成了抽象,但是這個抽象還是有問題的。假設在另一次運行中,someNumber()返回了 43,那么這個程序的狀態轉換關系就是:

[i : 0] -> [i : 43] -> [i : 44]

這與之前的抽象不符,因為兩次運行的狀態轉換關系不同。這是因為我們沒有考慮到someNumber()的返回值。

程序的"狀態"是指程序運行完成各個階段后的時間點,而不是程序運行的過程。因此,每個狀態都是獨立的,且狀態之間的轉換都是原子的。這與傳統的編程有很大的區別,因為傳統的編程是面向過程的,而 TLA+ 是面向狀態的。我們只在乎目前程序運行到了什么狀態,因此可以引入一個變量pc來表示程序運行到了哪個階段,這樣我們就可以清晰地表示程序的次態關系:

inti;
voidmain(){
i=someNumber();//pc="start"
i=i+1;//pc="middle"
}//pc="done"
這樣,我們不需要再考慮i的值,只需要考慮pc的值即可:

[pc : start] -> [pc : middle] -> [pc : done]

狀態編寫

i的初始值為 0,pc的初始值為start,我們可以把次態關系寫成:

cd616484-bc7d-11ed-bfe3-dac502259ad0.png

其中,對于變量i,它的下一個狀態表示為i',這是 TLA+ 中定義變量狀態轉換的方式。i' ∈ 0..1000代表i在下一個狀態的值是 0 到 1000 之間的一個數,也就是someNumber()0..1000代表集合{0,1,...,1000}是布爾邏輯中的邏輯與,可以認為意為"并且"。最終程序運行完成,不會再有下一個狀態,因此表示為FALSE

在 TLA+ 中,我們編寫的是一個個狀態。因此,并非是"因為pc = start所以i' ∈ 0..1000",事實上兩者的關系是并列的:**在這個狀態中,pc的值是start并且i下一個狀態的值∈ 0..1000**。有了這樣的思想,我們可以將上面的抽象改寫為:

cd74c10a-bc7d-11ed-bfe3-dac502259ad0.png

在其中用到了"或"連接兩個狀態,我們可以用布爾邏輯中的邏輯或來表示。這樣,我們就可以清晰地表示出程序的狀態轉換關系了。為了美觀,在 TLA+ 中,首句前也可以補上相同的布爾邏輯符號:

cd88f710-bc7d-11ed-bfe3-dac502259ad0.png

我們最終得到了這個簡單程序在初始狀態后的兩個狀態,下面我們將初始狀態補全,并按照 TLA+ 語言的要求補全整個 specification:

cd9c59ea-bc7d-11ed-bfe3-dac502259ad0.png

  • EXTENDS用于引入其他 specification 中定義的 module,這里引入了標準庫中的Integers,主要用在i' ∈ 0..1000上。
  • VARIABLES用于定義變量,這里定義了ipc
  • Init用于定義初始狀態,這里定義了i = 0pc = "start"
  • Next用于定義狀態轉換關系。
這樣我們就得到了一個完整的 TLA+ specification。后面就可以使用 TLC Model Checker 來檢查模型了,不過這不屬于本文的范圍。對于簡單的系統,用 TLA+ 建模并不能帶來很多好處。一般來說,只有在設計很復雜、很關鍵、很靠經驗預測的系統時,TLA+ 才會被使用。并發與分布式系統是 TLA+ 通常被使用的領域。下面我們就來看一個分布式系統算法的例子:Two-Phase Commit。 Two-Phase Commit

二階段提交(英語:Two-phase Commit)是指在計算機網絡以及數據庫領域內,為了使基于分布式系統架構下的所有節點在進行事務提交時保持一致性而設計的一種算法。通常,二階段提交也被稱為是一種協議(Protocol)。在分布式系統中,每個節點雖然可以知曉自己的操作時成功或者失敗,卻無法知道其他節點的操作的成功或失敗。當一個事務跨越多個節點時,為了保持事務的ACID特性,需要引入一個作為協調者的組件來統一掌控所有節點(稱作參與者)的操作結果并最終指示這些節點是否要把操作結果進行真正的提交(比如將更新后的數據寫入磁盤等等)。因此,二階段提交的算法思路可以概括為:參與者將操作成敗通知協調者,再由協調者根據所有參與者的反饋情報決定各參與者是否要提交操作還是中止操作。——Two-Phase Commit (Wikipedia)

Leslie Lamport's The TLA+ Video Course中,Lamport 以這樣的方式類比解釋 Two-Phase Commit:

cdbddd18-bc7d-11ed-bfe3-dac502259ad0.png

在婚禮上,牧師是協調者,新郎和新娘是參與者。當新郎和新娘都同意婚事時,牧師才會正式宣布婚事。如果有一方不同意,牧師就會中止婚事:

  1. 牧師問新郎:你是否同意這件婚事?
  2. 新郎回答:我同意(prepared)。
  3. 牧師問新娘:你是否同意這件婚事?
  4. 新娘回答:我同意(prepared)。
  5. 牧師宣布:婚事正式成立(committed)。

如果其中有一方不同意,牧師就會中止(abort)婚事。

在數據庫中,Transaction Manager 是協調者(牧師)。當 Transaction Manager 詢問所有參與者 Resource Managers (新郎 / 新娘)時,如果所有 Resource Managers 都同意提交事務,Transaction Manager 就會把事務提交。如果有一方不同意,Transaction Manager 就會中止事務。

Two-Phase Commit 的詳細介紹與流程可以在Wikipedia上找到。

首先我們來定義一些常量與變量以及其初始狀態:


cdd8ae68-bc7d-11ed-bfe3-dac502259ad0.png

  • 常量RM是所有 Resource Manager 標識的集合,例如可以設為集合{"r1", "r2", "r3"}
  • 變量rmState用于記錄每個 Resource Manager 的狀態,用rmState[r]表示r的狀態,有workingpreparedcommittedaborted四種狀態,每個RM的初始狀態均為working
  • 變量tmState用于記錄 Transaction Manager 的狀態,有initcommittedaborted三種狀態,初始狀態為init
  • 變量tmPrepared用于記錄已經準備好(處于prepared狀態)的 Resource Manager,初始值是一個空集。
  • 變量msgs作為消息池,用于記錄所有正在傳輸的消息,初始值是一個空集。

下面我們來定義系統做可能發生的動作。

cdecb1f6-bc7d-11ed-bfe3-dac502259ad0.png

  • TLA+ 中可以用上述方式定義類似于其它編程語言中"函數"概念的表達式,這樣就無需對每一個 Resource Manager 都定義一個表達式了。
  • [type → "prepare", rm → r]是一個 TLA+ 中的 record,類似于其它編程語言中的 struct。
  • UNCHANGED ?rmState, tmState, msgs?表示這個動作不會改變rmStatetmStatemsgs這三個變量的值。在 TLA+ 中,每一個變量的值是否改變都需要顯式地聲明。

TM的狀態為init,且在消息池中存在來自rPrepared消息,tmPrepared在下一個狀態的值會是tmPrepared{r}的并集。

cdffdb0a-bc7d-11ed-bfe3-dac502259ad0.png上面的兩個動作分別是 Transaction Manager 進行 Commit 與 Abort。

ce104e22-bc7d-11ed-bfe3-dac502259ad0.png

上述 4 個 Resource Manager 動作分別是 Resource Manager 選擇 Prepare 與 Abort,以及處理由 Transaction Manager 決定的 Commit 與 Abort。

其中,存在語法如rmState' = [rmState except ![r] = "prepared"],意為"在下一個狀態中,rmState[r]的值變為prepared,其它部分不變"。

如果我們用形如rmState[r]' = "prepared"的形式來表示,我們并沒有顯式地說明rmState的其它部分在下一個狀態的值,因此是不正確的。

TLA+ 與我們通常編寫的程序不同,是數學。在編程中,我們會使用到數組,而在 TLA+ 中,我們使用函數來表達類似的概念,數組的下標組成的集合就是函數的定義域。

編寫完系統可能存在的所有動作后,我們就可以開始歸納系統的狀態轉換了:

ce279424-bc7d-11ed-bfe3-dac502259ad0.png

其中,我們使用存在量詞?r ∈ RM來表示"對于集合RM的任意元素r,都存在這種行為"。TLA+ 的狀態轉換是原子的,因此在一個狀態中這個"或"分支內只會有一個r被選擇,這可以類比為編程語言中的for r in RM,但在本質上不同。

至此,對系統的建模就完成了。下面我們需要編寫系統的約束條件:

ce3e1640-bc7d-11ed-bfe3-dac502259ad0.png

在約束條件TypeOK中,我們將每個變量的可能值都進行了限制。其中的[RM → {"working","prepared", "committed", "aborted"}]是類似于將集合RM與集合{"working", "prepared", "committed", "aborted"}做笛卡爾積的操作,但得到的是一個由 record 組成的集合:
{
[r1|->"working",r2|->"working"],
[r1|->"working",r2|->"prepared"],
[r1|->"working",r2|->"committed"],
...
[r1|->"aborted",r2|->"committed"],
[r1|->"aborted",r2|->"aborted"]
}
TypeOK中我們用到了上面定義的集合Messages。定義Messages時,我們使用了語法:[type: {"Prepared"}, rm: RM]。這種語法也是對{"Prepared"}RM做類似笛卡爾積的操作,但得到的也是一個 record 集合:

{
[type|->"Prepared",rm|->r1],
[type|->"Prepared",rm|->r2],
...
}

最后的約束條件Consistent用于保證系統的一致性:在任意時刻,系統中不可能存在兩個 Resource Managers 分別處于committedabort狀態。

最終,我們將約束條件作為不變量,與系統模型一起交給 TLC Model Checker 進行驗證,就可以證明系統的正確性。

3

總結

通過上面的兩個例子,我們初步了解形式化方法的思想。TLA+ 是為了驗證分布式系統而設計的,但其思想可以應用到的領域遠不止分布式系統。在編寫程序時,如果我們能夠不僅僅考慮代碼層面的內容,而是從更高的層面,從數學角度去思考,就能夠寫出更加健壯的程序。如果你對 TLA+ 感興趣,可以參考Leslie Lamport's The TLA+ Video Course - YouTubeLearn TLA+

4

我們的項目:Xline

TLA+被廣泛用于分布式系統算法的研究和開發中。在我們的項目Xline中,TLA+被用來在設計階段驗證共識算法的正確性。

Xline是一個用于元數據管理的分布式KV存儲。我們在Xline中使用CURP協議(https://www.usenix.org/system/files/nsdi19-park.pdf)的修改版作為共識協議,TLA+將被用于其正確性驗證中。

如果你想了解更多關于Xline的信息,請參考我們的Github:https://github.com/datenlord/Xline


審核編輯 :李倩


聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 算法
    +關注

    關注

    23

    文章

    4628

    瀏覽量

    93186
  • 程序
    +關注

    關注

    117

    文章

    3795

    瀏覽量

    81289
  • 架構設計
    +關注

    關注

    0

    文章

    32

    瀏覽量

    6968

原文標題:從數學角度思考程序與驗證正確性

文章出處:【微信號:Rust語言中文社區,微信公眾號:Rust語言中文社區】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    一種新型半自動驗證流程 SoC連通性的正確性

    設計中的邏輯模塊之間的連接是否正確,例如:模塊 B1 上的輸出 A 是否正確連接到模塊 B2 上的輸入 A''。這常常是很困難的驗證任務。設計包含數以千計的導線,這些導線的正確性可能都
    的頭像 發表于 12-22 15:54 ?2509次閱讀
    一種新型半自動<b class='flag-5'>驗證</b>流程 SoC連通性的<b class='flag-5'>正確性</b>

    基于SMT的并發程序驗證中約束求解問題

    本質上講,要驗證一個程序正確性,需要驗證程序中所有執行都正確。對并發
    的頭像 發表于 02-02 09:25 ?2313次閱讀
    基于SMT的并發<b class='flag-5'>程序驗證</b>中約束求解問題

    ADS5282如何通過其他方式驗證寄存器寫入的正確性

    word. 測試結果: (1)差分數據對N端無變化 (2)差分P端輸出300多mv電壓,差分N端輸出100多mv電壓 另外,ADS5282是只寫芯片,如何通過其他方式驗證寄存器寫入的正確性
    發表于 11-18 08:33

    沒有實驗設備的條件下,如何首先驗證程序正確性

    沒有實驗設備,也就是說沒有傳感器,數據采集卡等,如何首先驗證程序正確性?謝謝!
    發表于 06-04 16:04

    架構的角度看如何寫好代碼 + 我的思考

    架構漫談(八):架構的角度看如何寫好代碼 + 我的思考
    發表于 06-18 06:16

    ACRN 之InterruptWindow功能正確性形式化驗證

    重磅推薦|ACRN 之InterruptWindow功能正確性形式化驗證
    發表于 06-18 16:04

    如何去測試CAN接口通訊功能的正確性

    如何去測試CAN接口通訊功能的正確性呢?怎樣去設計驅動控制板的CAN通訊接口部分呢?
    發表于 11-09 07:30

    疊加原理的驗證

    疊加原理的驗證 一、實驗目的驗證線性電路疊加原理的正確性,加深對線性電路的疊加和齊次的認識和理解。二、原理說
    發表于 09-24 09:30 ?3.5w次閱讀
    疊加原理的<b class='flag-5'>驗證</b>

    驗證了LCL型濾波器參數設計及光伏并入配電網的逆變器電壓控制策略的正確性

    濾波器的原理入手,對單L型和LCL型濾波器原理進行對比分析,在設計方法上,對比傳統的分步設計法,本文選擇了基于粒子群算法的新型LCL型濾波器的參數設計方法,最后通過仿真分析驗證了LCL型濾波器的參數設計及所研究的光伏并入配電網的逆變器電壓控制策略的
    的頭像 發表于 01-17 16:00 ?8511次閱讀
    <b class='flag-5'>驗證</b>了LCL型濾波器參數設計及光伏并入配電網的逆變器電壓控制策略的<b class='flag-5'>正確性</b>

    工程師和數學家的區別在哪

    工程師追求的是結果的正確性,而數學家要的是過程的正確性。 過程可以不夠準確,但是可以用一些其他的辦法來保證結果的正確性
    的頭像 發表于 03-31 10:34 ?3403次閱讀

    如何驗證區塊鏈開發程序驗證程序正確性

    智能合約是一種自我執行的工具,它的增長是隨著區塊鏈的興起而出現的。隨著這項技術的采用,這些金融工具的實際存款額不斷增加,同時它們的復雜也嚴重升級。這種情況會周期性地導致代價高昂的bug和漏洞,從而為更嚴格的程序分析方法帶來光明。
    發表于 06-25 10:55 ?4190次閱讀
    如何<b class='flag-5'>驗證</b>區塊鏈開發<b class='flag-5'>程序</b>和<b class='flag-5'>驗證</b><b class='flag-5'>程序</b>的<b class='flag-5'>正確性</b>

    如何檢查系統集成的正確性

    和交互進行驗證。 v?裝配程序和裝配工具是可用的,并在開始裝配之前進行驗證。 v?在開始驗證之前,VV程序和工具是可用的并經過
    的頭像 發表于 02-13 13:49 ?2147次閱讀
    如何檢查系統集成的<b class='flag-5'>正確性</b>?

    通過靜態時序分析驗證設計的正確性

      傳統的電路設計分析方法是僅僅采用動態仿真的方法來驗證設計的正確性。隨著集成電路的發展,這一驗證方法就成為了大規模復雜的設計驗證時的瓶頸。
    的頭像 發表于 11-28 15:26 ?1027次閱讀

    基于形式驗證的高效RISC-V處理器驗證方法

    隨著RISC-V處理器的快速發展,如何保證其正確性成為了一個重要的問題。傳統的測試方法只能覆蓋一部分錯誤情況,而且無法完全保證處理器的正確性。因此,基于形式驗證的方法成為了一個非常有前途的方法,可以更加全面地
    的頭像 發表于 06-02 10:35 ?1435次閱讀

    如何使用Verilog語言進行仿真驗證

    仿真驗證主要作用是搭建一個測試平臺,測試和驗證程序設計的正確性驗證設計是否實現了我們所預期的功能。其結構如下圖所示。
    的頭像 發表于 10-02 16:29 ?1890次閱讀
    如何使用Verilog語言進行仿真<b class='flag-5'>驗證</b>
    主站蜘蛛池模板: 成人18视频在线| 97超视频在线观看| 99RE6这里只有精品国产AV| 黄色a三级三级三级免费看| 玩弄放荡人妻一区二区三区| 俄罗斯一级毛片aaaa| 肉耽高h一受n攻| 纯肉无码AV在线看免费看| 人妻换人妻AA视频| 边做边爱播放3免费观看| 日本人69xxx| 国产成人免费片在线视频观看 | 欧美猛男gaygayxxgv| 99久久免费精品| 日本不卡不码高清免费| 丹麦1o一19sex性hdhd| 色色噜一噜| 国产色欲一区二区精品久久呦| 亚洲精品久久一区二区三区四区| 国内精品视频在线播放一区| 亚洲日韩一区精品射精| 久久久97丨国产人妻熟女| 97影院理论午夜伦不卡偷| 欧美日韩看看2015永久免费| 草莓视频在线看免费高清观看 | 色播成人影院| 国内极度色诱视频网站| 一级毛片在线免费视频| 免费果冻传媒在线完整观看| 芭乐草莓樱桃丝瓜18岁大全| 十九禁啊啪射视频在线观看| 国产综合18久久久久久软件| 中文字幕不卡免费高清视频| 人妻超级精品碰碰在线97视频| 国产午夜小视频| 中文国产乱码在线人妻一区二区 | 日韩高清在线亚洲专区| 国产偷国产偷亚州清高APP| 在线观看国产区| 琪琪电影午夜理论片77网| 国产精品无码人妻在线|