Skip to content

Commit d8ed081

Browse files
lemmyclaude
andcommitted
Factor the TLC concerns out of btree into MCbtree
Keeping the datastructure and the definitions that exist only to make model checking finite in one module left no way to tell which was which. btree.tla is now the algorithm alone, MCbtree.tla the model. Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: Markus Alexander Kuppe <github.com@lemmster.de>
1 parent 9126be8 commit d8ed081

4 files changed

Lines changed: 52 additions & 23 deletions

File tree

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,15 @@ CONSTANTS
2020
Vals = {x,y,z}
2121

2222
MaxOccupancy = 2
23+
24+
CONSTANTS
2325
MaxNode = 8
2426
MaxKey = 4
2527

28+
CONSTANTS
29+
Keys <- MCKeys
30+
Nodes <- MCNodes
31+
2632
\* PROPERTY
2733
\* Refinement
2834

specifications/btree/MCbtree.tla

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
---- MODULE MCbtree ----
2+
\* The B-tree in btree.tla draws keys from an unbounded domain and allocates
3+
\* nodes from an unbounded pool. This module bounds both, so that TLC has a
4+
\* finite state space, and reports when a bound was the binding constraint.
5+
EXTENDS btree
6+
7+
CONSTANTS MaxKey,
8+
MaxNode
9+
10+
\* With no key at all, no request action is ever enabled and the tree never
11+
\* leaves its initial state.
12+
ASSUME KeyDomainIsNonEmpty == MaxKey \in Nat \ {0}
13+
14+
\* Only that the bound is a number: btree's NodePoolIsNonEmpty already rules out
15+
\* an empty pool.
16+
ASSUME NodeBoundIsNat == MaxNode \in Nat
17+
18+
MCKeys == 1..MaxKey
19+
MCNodes == 1..MaxNode
20+
21+
\* The tree allocates a node whenever a split needs one, so running out means
22+
\* MaxNode was too small for the keys this model inserts, not that the tree
23+
\* misbehaved. This is a statement about the model, not a property of the
24+
\* B-tree, which is why it lives here and not in btree.tla.
25+
FreeNodesRemain == \E n \in Nodes : IsFree(n)
26+
27+
====

specifications/btree/btree.tla

Lines changed: 12 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
\* Note: deletes have not been implemented
22
---- MODULE btree ----
3-
EXTENDS TLC,
4-
Naturals,
3+
EXTENDS Naturals,
54
FiniteSets,
6-
Sequences
5+
Sequences,
6+
Relation
77

88
CONSTANTS Vals,
9-
MaxKey,
10-
MaxNode,
9+
Keys,
10+
Nodes,
1111
MaxOccupancy,
1212

1313
\* states
@@ -26,27 +26,19 @@ CONSTANTS Vals,
2626
\* Assumptions the algorithm imposes
2727
\*
2828

29+
\* All the tree does with a key is compare it: ChildNodeFor descends by
30+
\* comparing a key against the ones a node holds, and PivotOf splits a node's
31+
\* keys into a smaller and a larger half. A strict total order is therefore
32+
\* everything the algorithm needs of the key domain, which it does not bound.
33+
ASSUME KeysAreOrdered == IsStrictlyTotallyOrderedUnder(<, Keys)
34+
2935
\* MaxOccupancy is the branching factor. Below 2, PivotOf leaves one side of
3036
\* every split empty, and IsFree reports the emptied in-tree leaf as free for
3137
\* ChooseFreeNode to hand out a second time.
3238
ASSUME MaxOccupancyPermitsSplitting == MaxOccupancy \in Nat /\ MaxOccupancy >= 2
3339

3440
\* Even the empty tree is a root node, which Init takes from the free nodes.
35-
ASSUME NodePoolIsNonEmpty == MaxNode \in Nat \ {0}
36-
37-
\*
38-
\* Assumptions only model checking imposes
39-
\*
40-
\* The algorithm bounds neither the key domain nor the node pool. MaxKey and
41-
\* MaxNode exist to keep Keys, Nodes and the domains of childOf and valOf
42-
\* finite, which is also why exhausting the pool is reported by FreeNodesRemain,
43-
\* as a model too small rather than a defect in the tree.
44-
45-
\* With no key, no request action is ever enabled and TLC deadlocks on Init.
46-
ASSUME KeyDomainIsNonEmpty == MaxKey \in Nat \ {0}
47-
48-
Keys == 1..MaxKey
49-
Nodes == 1..MaxNode
41+
ASSUME NodePoolIsNonEmpty == Nodes # {}
5042

5143
NIL == CHOOSE x : x \notin Nodes
5244
MISSING == CHOOSE v : v \notin Vals
@@ -335,6 +327,5 @@ KeyOrderPreserved == \A n \in Inners : (\A k \in keysOf[n] : (\A kc \in keysOf[c
335327
LeavesCantHaveLast == \A n \in Leaves : lastOf[n] = NIL
336328
KeysInLeavesAreUnique ==
337329
\A n1, n2 \in Leaves : ((keysOf[n1] \intersect keysOf[n2]) # {}) => n1=n2
338-
FreeNodesRemain == \E n \in Nodes : IsFree(n)
339330

340331
====

specifications/btree/manifest.json

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,20 @@
1111
{
1212
"path": "specifications/btree/btree.tla",
1313
"features": [],
14+
"models": []
15+
},
16+
{
17+
"path": "specifications/btree/MCbtree.tla",
18+
"features": [],
1419
"models": [
1520
{
16-
"path": "specifications/btree/btree.cfg",
21+
"path": "specifications/btree/MCbtree.cfg",
1722
"runtime": "00:00:15",
1823
"mode": "exhaustive search",
1924
"result": "success",
2025
"distinctStates": 374727,
2126
"totalStates": 2820091,
22-
"stateDepth": 40
27+
"stateDepth": 38
2328
}
2429
]
2530
},

0 commit comments

Comments
 (0)