Finite-state CTL model checking with replayable witnesses and counterexamples
Dependencies
| 能力 | 说明 |
|---|---|
| CTL 检查 | 支持 EX、AX、EF、AF、EG、AG、E[p U q]、A[p U q] |
| 结果解释 | 对支持的公式返回有限路径或带循环入口的路径;也可输出 JSON |
| 图形导出 | 将模型导出为 Graphviz DOT,并标红见证或反例路径 |
| 建模方式 | 从 JSON、状态 ID 与转移,或带预算的转换函数构建有限图 |
| 运行目标 | 核心库通过 wasm、wasm-gc、js、native 检查;命令行示例使用 native |
moon run --target native cmd/main -- examples/buggy.json 'AG !double_charge'FAIL: AG !double_charge
states=4 satisfying=1
counterexample (shortest path):
new
--charge--> charged_once
--retry_without_idempotency--> charged_twicemoon run --target native cmd/main -- examples/fixed.json 'AG !double_charge'
moon run --target native cmd/main -- examples/fixed.json 'AF completed'moon run --target native cmd/main -- --suite examples/buggy.json examples/payment.suitemoon run --target native cmd/main -- --dot examples/buggy.json 'AG !double_charge' > buggy.dotmoon run --target native cmd/main -- --json examples/buggy.json 'AF completed'let states : Array[@moonctl.State] = [
{ id: "new", labels: [] },
{ id: "done", labels: ["completed"] },
]
let edges : Array[@moonctl.Edge] = [
{ from: 0, to: 1, action: "finish" },
]
let model = match @moonctl.Model::new(states, edges, initial=0) {
Ok(m) => m
Err(_) => abort("invalid model")
}
let property = @moonctl.parse("EF completed")
let report = @moonctl.check(model, property)
assert_true(report.holds())///|
let states : Array[@moonctl.State] = [
{ id: "queued", labels: [], },
{ id: "done", labels: ["completed"], },
]
///|
let edges : Array[@moonctl.NamedEdge] = [
{ from: "queued", to: "done", action: "finish", },
]
///|
let model = @moonctl.Model::from_named(states, edges, "queued")let result = @moonctl.explore(
initial,
state => transitions_from(state),
max_states=1000,
max_edges=5000,
)
match result {
Ok(Complete(model)) => {
let report = @moonctl.check(model, @moonctl.parse("AG !double_charge"))
println("holds=\{report.holds()}")
}
Ok(Incomplete(limit, states, edges)) =>
println("incomplete: \{Repr(limit)}, \{states} states, \{edges} edges")
Err(error) => println("invalid exploration: \{Repr(error)}")
}{
"initial": 0,
"states": [
{"id": "new", "labels": ["safe"]},
{"id": "charged", "labels": ["safe"]}
],
"edges": [
{"from": 0, "to": 1, "action": "charge"}
]
}| 公式 | 含义 |
|---|---|
| p, true, false | 原子命题与布尔常量 |
| !p, p & q, p \| q | 否定、合取、析取 |
| EX p, AX p | 存在 / 所有下一状态满足 p |
| EF p, AF p | 存在 / 所有路径最终到达 p |
| EG p, AG p | 存在 / 所有路径始终满足 p |
| E[p U q], A[p U q] | 存在 / 所有路径保持 p 直到 q |
moon check --target all --deny-warn
moon build --target all
moon test --target wasm-gc --deny-warn
moon test --target native --deny-warn
moon run --target wasm-gc examples/explorepub(all) suberror ModelJsonError {
InvalidJson
MissingField(String)
WrongType(String)
InvalidGraph(ModelError)
} derive(Debug)pub(all) suberror ParseError {
UnexpectedEnd
UnexpectedToken(String)
ExpectedToken(String)
InvalidCharacter(Char)
} derive(Debug)pub(all) enum ExploreError {
InvalidBudget(Int, Int)
ConflictingState(String)
InvalidExploredGraph(ModelError)
} derive(Debug)pub(all) enum ModelError {
EmptyStates
InvalidInitial(Int)
DuplicateState(String)
InvalidEdge(Int, Int)
} derive(Debug)pub(all) enum NamedModelError {
DuplicateName(String)
UnknownState(String)
InvalidModel(ModelError)
} derive(Debug)fn explore(initial : State, next : (State) -> Array[Transition], max_states~ : Int, max_edges~ : Int) -> Result[Exploration, ExploreError]Install
Download zipFinite-state CTL model checking with replayable witnesses and counterexamples
Dependencies