Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[patch] Add various example models to proper folder #259

Merged
merged 125 commits into from
May 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
125 commits
Select commit Hold shift + click to select a range
f288337
fix: sem ver up; push action is from another repo
tnelson Jan 18, 2023
4cc335c
fix: remove old forge/forge/forge/check-ex-spec
tnelson Jan 18, 2023
779651b
Merge branch 'main' into dev
tnelson Jan 18, 2023
bc864ef
Replacing where blocks with test-suite construct (#171)
sidprasad Jan 19, 2023
a252465
Typed Froglet (#154)
bennn Jan 19, 2023
33966bf
don't export unnamed tests / runs (#172)
bennn Jan 19, 2023
8a8f1b3
Property Where Syntax update (#174)
sidprasad Jan 20, 2023
bdfff3d
froglet / bsl: allow +, -> in examples (#173)
bennn Jan 20, 2023
63d8b65
bump version
bennn Jan 21, 2023
634488c
restore the syntax-local-context of example blocks (#178)
bennn Jan 24, 2023
8c1b1d2
ci: revert froglet install, forge works for both (#176)
bennn Jan 26, 2023
27ceebb
ci: use LOCAL forge, not pkg forge
bennn Jan 26, 2023
e305b90
feat: universal dylibs for minisat, minisatp, glucose
tnelson Jan 27, 2023
a3d3d86
froglet: fix internal arity error
bennn Jan 30, 2023
76b52f1
no examples in temporal mode (#179)
bennn Jan 30, 2023
9d88af7
flush logs at toplevel (#177)
bennn Jan 30, 2023
af6714e
Merge branch 'main' into dev
tnelson Jan 31, 2023
99d7453
froglet checkpoint (#185)
bennn Feb 1, 2023
41af3f8
example: quick fix for multi-line bounds
bennn Feb 6, 2023
da6b6c3
examples: use one syntax-parameterize, not N, flatten bounds later (#…
bennn Feb 6, 2023
93b6277
typed froglet checkpoint (#188)
bennn Feb 6, 2023
f57b3b4
forge/bsl: don't use 'froglet' in runtime error messages
bennn Feb 6, 2023
7142945
uncomment error tests
bennn Feb 6, 2023
e6040f6
Merge branch 'main' into dev
bennn Feb 6, 2023
cc262e3
ci: use local froglet
bennn Feb 6, 2023
a9759e5
Merge branch 'main' of github.com:tnelson/Forge into dev
bennn Feb 6, 2023
5ca6198
server: relax regexp for java version
bennn Feb 6, 2023
2dc077e
add flag to hide preds (#181)
bennn Feb 7, 2023
64d47b4
Unset _JAVA__OPTIONS in `java>=1.9?' (#193)
TsarFox Feb 10, 2023
6192e69
One pardinus (#187)
tnelson Feb 11, 2023
b7c440c
Logging: anonymize paths in error outputs, print boring string on fai…
bennn Feb 20, 2023
99d1a73
detect use of temporal operators without temporal mode
tnelson Feb 20, 2023
8d6f79a
parser: change ~literal to ~datum (#201)
bennn Feb 24, 2023
3c96f51
feat: test case for PR 201
tnelson Feb 24, 2023
96b0631
forge/bsl: allow + -> in inst blocks (#202)
bennn Mar 5, 2023
80c5248
fix: metadata transmission to sterling
tnelson Mar 8, 2023
c508424
print git branch, commit, timestamp info (#195)
bennn Mar 8, 2023
884af8a
Merge branch 'main' into dev
tnelson Mar 8, 2023
e6ae351
housekeeping: relocate OLD, consolidate
tnelson Apr 26, 2023
59e12ab
feat: updated Sterling for dev testing
tnelson Apr 26, 2023
4227997
add binary-tree vis example
tnelson Apr 26, 2023
20aaeee
static example
tnelson Apr 26, 2023
096181c
fix: faster Edge object rendering
tnelson Apr 27, 2023
d8ffaa1
add tree3 viz example
tnelson Apr 28, 2023
f2554eb
minor change to tree3
tnelson Apr 28, 2023
bbbe044
fix: CI badge
tnelson Apr 28, 2023
7ecf40b
CI badge
tnelson Apr 28, 2023
d86d588
improved tree3
tnelson Apr 28, 2023
41bbd2b
update Sterling: events, arcs, images, pictures
tnelson May 13, 2023
7b0557d
fix: sterling update
tnelson May 15, 2023
50dbec0
add do-time macro, time a few spots (#210)
bennn Jul 16, 2023
4f93c60
semanticVersion: canonize major/minor numbers (#205)
bennn Jul 16, 2023
78c6e58
Merge branch 'main' into dev
tnelson Jul 16, 2023
80d15b8
Merge branch 'main' into dev
tnelson Jul 16, 2023
6417283
Crypto DSL for Guttmanfest (#209)
tnelson Jul 16, 2023
6cc349d
minor cleanup, enable run_sterling option to carry a filename
tnelson Jul 25, 2023
f8d0f19
sending script text if provided, fix relative paths (#216)
tnelson Aug 8, 2023
4da80ae
Basic updates to AST, parsing to prep for 2024 (#217)
tnelson Jan 4, 2024
63aec6b
add: #lang forge/temporal
tnelson Jan 4, 2024
3845296
add: 5 simple examples
tnelson Jan 4, 2024
3222771
fix: f4_counter
tnelson Jan 4, 2024
11744e6
Merge branch 'main' into dev
tnelson Jan 5, 2024
005d696
Merge branch 'main' into dev
tnelson Jan 5, 2024
94dc22b
add: Mia's viz for crypto
tnelson Jan 5, 2024
14f65cd
add: GCW puzzle example, original vis script
tnelson Jan 5, 2024
0d8986b
add: network lab adaptation to Forge
tnelson Jan 5, 2024
b9937d6
fix: join on helper functions, crypto example
tnelson Jan 5, 2024
78ec163
add: reflect crypto example
tnelson Jan 6, 2024
e0a8a76
update: add note on narrowing, minimal example
tnelson Jan 9, 2024
2cff004
ABAC DSL, some fixes (#220)
tnelson Jan 15, 2024
e60501f
fix: stopgap to show an actual message if out of instances
tnelson Jan 17, 2024
3b4d827
fix: readable errors, although Sterling displays poorly
tnelson Jan 17, 2024
ec3a5b1
update: sterling
tnelson Jan 21, 2024
9654edd
fix: stop trying to reload a run_sterling file if it doesn't exist
tnelson Jan 21, 2024
1def57f
update Sterling: pre-load script
tnelson Jan 22, 2024
4c350a2
fix: consistent update outside of strict dev mode
tnelson Jan 22, 2024
1b65e03
fix: improve error in case set comprehension is used improperly
Jan 25, 2024
cc46287
Retain sytnax loc (#221)
tnelson Jan 26, 2024
d612cdf
fix: preserve stx loc when desugaring test, example
tnelson Jan 26, 2024
8af5305
Roll in better handling of some errors, propagate stxloc; beginnings …
tnelson Jan 31, 2024
5e58760
Merge branch 'main' into dev
tnelson Jan 31, 2024
e6e7be0
add: test case confirming 'no' works for piecewise insts
tnelson Feb 3, 2024
02852be
fix: source location reported for test failure
tnelson Feb 5, 2024
ddb6c3d
Fix usererror illformed block (#227)
tnelson Feb 5, 2024
c0dccb9
fix: better errors for non-field arguments to reachable
tnelson Feb 5, 2024
b9fb53f
add: improve error when reachable given too few args
tnelson Feb 6, 2024
3ad4937
Adding universal quantification to asserts (#228)
sidprasad Feb 6, 2024
a5ecf10
Merge branch 'main' into dev
tnelson Feb 6, 2024
5dcbca9
Merge branch 'main' into dev
tnelson Feb 7, 2024
81e9a78
Add improved error for piecewise bind definition (#230)
tnelson Feb 9, 2024
8b00928
Shoring up core language's ability to give a target instance to solve…
tnelson Feb 9, 2024
b7dbe6c
Error for piecewise bounds if an atom is named that isn't present in …
tnelson Feb 10, 2024
cfc6fff
If unable to open a browser for Sterling, keep running the server and…
tnelson Feb 10, 2024
be33d9f
Error if an integer literal appears which is bigger than the given bi…
tnelson Feb 10, 2024
8edd60a
fix: properly parse assertions with quantifiers inside suites
tnelson Feb 12, 2024
89ab816
Error for "detached" negative numeric constants (#235)
tnelson Feb 13, 2024
c1360c1
Sig and Field AST nodes will now properly record their use location (…
tnelson Feb 16, 2024
057529c
Quantified assert fix (#239)
sidprasad Feb 17, 2024
d879fac
Merge branch 'main' into dev
tnelson Feb 19, 2024
6544d0c
Merge branch 'main' into dev
tnelson Feb 21, 2024
ed941e1
Merge branch 'main' into dev
tnelson Feb 21, 2024
fc5d61b
Allowing multiple failing tests in a Forge run (#242)
sidprasad Feb 22, 2024
3092638
Error message if no parent sig scope, but child scopes exceed default…
tnelson Feb 23, 2024
59f2dd3
fix: sterling: show Skolem tags, empty instance box message
tnelson Feb 24, 2024
e314f80
fix: double-check runs for failing examples need de-duplicated names
tnelson Feb 24, 2024
40beae6
Fix: better handling for multiple-tests (#245)
tnelson Feb 29, 2024
5a076ee
Basic type-checking for predicate use, pred/fun syntax location use s…
tnelson Feb 29, 2024
53b2f84
Merge branch 'main' into dev
tnelson Mar 1, 2024
ad2c21a
Merge branch 'main' into dev
tnelson Mar 2, 2024
ae3e3e8
Add basic typechecking for helper functions (#248)
tnelson Mar 16, 2024
0c18686
Fix missing error check in AST for expr->intexpr conversion; add new …
tnelson Mar 17, 2024
7748834
Infer type of atoms sent from evaluator (#249)
tnelson Mar 20, 2024
1945d84
feat: clean up core display so that VSCode can highlight matches
tnelson Mar 22, 2024
a59e07a
Feat granular cores (#252)
tnelson Mar 31, 2024
06a8a0c
Merge branch 'main' into dev
tnelson Mar 31, 2024
6012024
Merge branch 'main' into dev
tnelson Apr 1, 2024
fb22636
Fix: core top-level wrapping, syntax-location at top-level in "check"…
tnelson Apr 2, 2024
d939200
Merge branch 'main' into dev
tnelson Apr 2, 2024
a92a579
Feat priming checks (#256)
k-mouline Apr 13, 2024
660f53a
feat: xor operator (macro, surface); tests (#257)
tnelson Apr 16, 2024
60b03eb
Merge branch 'main' into dev
tnelson May 31, 2024
aebb849
working on examples dir
tnelson May 31, 2024
0d00d14
add: more examples from the public repo
tnelson May 31, 2024
dd1fe11
add: Prim's
tnelson May 31, 2024
36583af
improve Prim model performance
tnelson May 31, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 23 additions & 6 deletions forge/examples/README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,26 @@
# Examples of Modeling in Forge (2023)
# Examples of Modeling in Forge

This folder contains a number of curated examples in Forge.
This folder contains a number of curated examples in Forge, from various sources. Some were previously in the [public examples repository](https://github.com/csci1710/public-examples/) for CSCI 1710 at Brown, or in the [lecture notes](https://csci1710.github.io/book/) for the class. As of June 2024, this directory is now the canonical home for them all. *Prior sources will not be kept up to date.*

For additional examples, see:
* The [CSCI 1710 public examples repo](https://github.com/csci1710/public-examples/)
* The [Forge documentation](https://csci1710.github.io/forge-documentation/)
* The [CSCI 1710 lecture notes](https://csci1710.github.io/2023/)
While many of these examples are commented more heavily, the [Forge documentation](https://csci1710.github.io/forge-documentation/) may still be useful.

## Directory Structure

* `examples/basic/` contains a set of basic examples of Forge use, taken from various demos.
* `examples/tic_tac_toe` contains a model of the game tic-tac-toe, along with a custom visualizer.
* `examples/oopsla24` contains the models used in the Forge paper to appear at OOPSLA 2024.
* `examples/musical_scales` contains a basic model of diatonic scales, with a "visualizer" that also plays the scales generated.
* `examples/unsat` contains a set of toy examples demonstrating how unsat cores work in Forge, as of Spring 2024.
* `examples/sudoku_opt_viz` contains a sequence of models to solve Sudoku, demonstrating some optimization tricks and a visualizer for game boards.
* `examples/lights_puzzle` contains a model of a common puzzle involving rings or chains of lights that must be lit via switches that alter multiple lights' state at once.
* `examples/bsearch_array` contains a model of binary search on a sorted array, along with verification of some invariants.
* `examples/bst` contains a series of models of binary search trees.
- `bst_1.frg` and `bst_2.frg` are in Relational Forge, and focus on structural invariants for trees and the BST invariant (vs. an incorrect version). `bst_3.frg` and `bst_4.frg` are in Temproal Forge and model a recursive descent on an arbitrary tree following the correct vs. incorrect invariant. Both the Relational and Temporal Forge versions have visualization scripts.

For a more advanced example, see:

* `examples/prim`, which contains a model of Prim's MST algorithm, with notes on verification.

## A Note on Visualization

Some of these examples use "old style" visualizer scripts, i.e., from 2022 and 2023. These should still work as normal, but please report any issues!
File renamed without changes.
62 changes: 62 additions & 0 deletions forge/examples/basic/buckets.frg
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#lang forge/temporal

option max_tracelength 10

/*
Water buckets puzzle:
- you have a faucet of running water
- you have empty 8, 5, and 3-liter buckets
- you must get exactly 4 liters of water into one of the buckets using these tools.

We'll solve this puzzle with Forge. To do so, we'll define the *transition system*
of the puzzle, and ask Forge to search it for a solution!

Note that "find a sequence of operations such that <a state like this> is reached"
is useful for software and hardware verification, as well...
*/

sig Bucket {
capacity: one Int,
var contents: one Int
}
one sig B8, B5, B3 extends Bucket {}

pred initial {
B8.capacity = 8
B5.capacity = 5
B3.capacity = 3
B8.contents = 0
B5.contents = 0
B3.contents = 0
}

pred fill[b: Bucket] {
b.contents' = b.capacity
all b2: Bucket - b | b2.contents' = b2.contents
}

pred empty[b: Bucket] {
b.contents' = 0
all b2: Bucket - b | b2.contents' = b2.contents
}

pred pour[from, to: Bucket] {
let moved = min[from.contents + subtract[to.capacity, to.contents]] | {
to.contents' = add[to.contents, moved]
from.contents' = subtract[from.contents, moved]
}
all b2: Bucket - (from + to) | b2.contents' = b2.contents
}

run {
initial
always {
(some b: Bucket | fill[b])
or
(some b: Bucket | empty[b])
or
(some from, to: Bucket | pour[from, to])
}
eventually {some b: Bucket | b.contents = 4}
} for 5 Int, -- bitwidth
exactly 3 Bucket -- no other buckets in the world
File renamed without changes.
File renamed without changes.
262 changes: 262 additions & 0 deletions forge/examples/bsearch_array/binarysearch.frg
Original file line number Diff line number Diff line change
@@ -0,0 +1,262 @@
#lang forge/bsl

/*
Rough model of binary search on an array of integers.

Recall: binary search (on an array) searches the array as if it embedded a tree; each step narrows
the range-to-be-searched by half.

Tim Feb 2023/2024
*/

-----------------------------------------------------------
-- Data definitions: integer arrays
-----------------------------------------------------------

// Model an array of integers as a partial function from ints to ints.
// For ease of modeling, we'll also explicitly represent the length of the array.
// Also for ease of modeling, we'll just allow one array to exist in each instance.
one sig IntArray {
elements: pfunc Int -> Int,
lastIndex: one Int
}

-- An IntArray is well-formed if this predicate returns true for it.
pred validArray[arr: IntArray] {
-- no elements before index 0
all i: Int | i < 0 implies no arr.elements[i]

-- if there's an element, either i=0 or there's something at i=1
-- also the array is sorted:
all i: Int | some arr.elements[i] implies {
i = 0 or some arr.elements[subtract[i, 1]]
arr.elements[i] >= arr.elements[subtract[i, 1]]
}
-- lastIndex reflects actual size of array
all i: Int | (no arr.elements[i] and some arr.elements[subtract[i, 1]]) implies {
arr.lastIndex = subtract[i, 1]
}
{all i: Int | no arr.elements[i]} implies
{arr.lastIndex = -1}

}

-- Helper function to get the first index of the array; will be either 0 or -1.
fun firstIndex[arr: IntArray]: one Int {
arr.lastIndex = -1 => -1 else 0
}

-----------------------------------------------------------
-- Data definitions: Binary search
-----------------------------------------------------------

-- Model the current state of a binary-search run on the array: the area to be searched
-- is everything from index [low] to index [high], inclusive of both. The [target] is
-- the value being sought, and [arr] is the entire array being searched.
sig SearchState {
arr: one IntArray, -- never changes
low: one Int, -- changes as the search runs
high: one Int, -- changes as the search runs
target: one Int -- never changes
}

-----------------------------------------------------------

-- What is an initial state of the search? There are many, depending on the actual
-- array and the actual target. But it should be a valid array, and it should start
-- with the obligation to search the entire array.
pred init[s: SearchState] {
validArray[s.arr]
s.low = firstIndex[s.arr]
s.high = s.arr.lastIndex
-- Note: we have written no constraints on the target; it may be any value
}

-----------------------------------------------------------
-- Transition predicates
-- - stepNarrow (binary search narrows the [low, high] interval)
-- - stepSucceed (binary search finishes, finding the target)
-- - stepFailed (binary search finishes, not finding the target)
-----------------------------------------------------------

pred stepNarrow[pre: SearchState, post: SearchState] {
-- mid = (low+high)/2 (rounded down)
let mid = divide[add[pre.low, pre.high], 2] | {
-- GUARD: must continue searching, this isn't the target
pre.arr.elements[mid] != pre.target
-- ACTION: narrow left or right
(pre.arr.elements[mid] < pre.target)
=> {
-- need to go higher
post.low = add[mid, 1]
post.high = pre.high
}
else {
-- need to go lower
post.low = pre.low
post.high = subtract[mid, 1]
}
-- FRAME: the array and the target never change
post.arr = pre.arr
post.target = pre.target
}
}

-----------------------------------------------------------

-- Termination condition for the search: if low > high, we should stop.
-- "Do nothing" now; the search is over.
pred stepFailed[pre: SearchState, post: SearchState] {
-- GUARD: low and high have crossed
pre.low > pre.high
-- ACTION: no change in any field
post.arr = pre.arr
post.target = pre.target
post.low = pre.low
post.high = pre.high
}
-- Termination condition for the search: if we found the element, stop.
-- "Do nothing" now; the search is over.
pred stepSucceed[pre: SearchState, post: SearchState] {
-- GUARD: mid element = target
let mid = divide[add[pre.low, pre.high], 2] |
pre.arr.elements[mid] = pre.target
-- ACTION: no change in any field
post.arr = pre.arr
post.target = pre.target
post.low = pre.low
post.high = pre.high
}

-----------------------------------------------------------

-- Make it easier to reason about the system with an overall
-- "take a step" predicate.
pred anyTransition[pre: SearchState, post: SearchState] {
stepNarrow[pre, post] or
stepFailed[pre, post] or
stepSucceed[pre, post]
}

-- We will discover that binary search breaks when the array is too big. What "too big" is
-- depends on the bitwidth Forge is using. E.g., the default of 4 bits means Forge can represent
-- the interval [-8, 7]. If low=3 and high=5, then (low+high) = (3+5) = 8, which is too big, so
-- it wraps around to -8.
-- This behavior lets us find a _real problem_. Binary search (not so) famously breaks if the
-- array is too long. See: https://ai.googleblog.com/2006/06/extra-extra-read-all-about-it-nearly.html)
pred safeArraySize[arr: IntArray] {
-- A bit conservative, but it works for the model
arr.lastIndex < divide[max[Int], 2]
-- Let's also assume the array is non-empty
arr.lastIndex >= 0
}

---------------------------------------------------------------------------------------------
-- Some "is satisfiable" tests. These test for consistency, possibility, non-vacuity.
-- If we don't include tests like this, our verification will be worthless. To see an
-- extreme example of why, consider: "A implies B" is always true if "A" is unsatisfiable,
-- regardless of what B is.
---------------------------------------------------------------------------------------------

test expect {
-- Check that it's possible to narrow on the first transition (this is the common case)
narrowFirstPossible: {
some s1,s2: SearchState | {
init[s1]
safeArraySize[s1.arr]
stepNarrow[s1, s2]
}
} for exactly 1 IntArray, exactly 2 SearchState
is sat

-- Check that we can succeed immediately (likely because the target is in the middle exactly)
doneSucceedFirstPossible: {
some s1,s2: SearchState | {
init[s1]
safeArraySize[s1.arr]
stepSucceed[s1, s2]
}
} for exactly 1 IntArray, exactly 2 SearchState
is sat
}

---------------------------------------------------------------------------------------------
-- Some assertions: these check that counterexamples don't exist, meaning they _cannot_ check
-- for consistency as the tests above do.
---------------------------------------------------------------------------------------------

pred unsafeOrNotInit[s: SearchState] {
not init[s] or not safeArraySize[s.arr]
}
-- Check: Since we start with high >= low, the failure condition can't be reached in first state
-- unless the array is unsafe.
assert all s1, s2: SearchState | stepFailed[s1, s2] is sufficient for unsafeOrNotInit[s1]
for exactly 1 IntArray, exactly 2 SearchState

-- The central invariant of binary search:
-- If the target is present, it's located between low and high
pred bsearchInvariant[s: SearchState] {

all i: Int | {
s.arr.elements[i] = s.target => {
-- This has the side effect of saying: if the target is there, we never see low>high
s.low <= i
s.high >= i

-- This is an example of how we need to _enrich_ the invariant in order to verify the property.
-- Counter-intuitively, it's easier for Forge to prove something stronger! The strengthening
-- says: low and high must be "reasonable" at all times.
s.low >= firstIndex[s.arr]
s.low <= s.arr.lastIndex
s.high >= firstIndex[s.arr]
s.high <= s.arr.lastIndex

-- Note: these _technically_ should apply if the item is missing, too. But we'd need to be
-- more careful, if we wanted to move these outside the implication, because a 1-element array
-- (low=0; high=1) would end up with low>high and depending on how we model that, high could
-- "unreasonably" become -1. (high := mid-1). So for brevity we put the enrichment here.

}
}

-- To avoid the "array is too large" problem with binary search.
safeArraySize[s.arr]

-- validArray should be preserved as well
validArray[s.arr]
}

----------------------------------------------------------------------------
-- Inductively verify that binary search preserves the (enriched) invariant.
-- Step 1: Initiation: check that init states must satisfy the invariant.
-- Step 2: Consecution: legal transitions preserve the invariant.
----------------------------------------------------------------------------

-- Step 1
pred safeSizeInit[s: SearchState] { init[s] and safeArraySize[s.arr] }
assert all s: SearchState | safeSizeInit[s] is sufficient for bsearchInvariant[s]
for exactly 1 IntArray, exactly 1 SearchState

-- Step 2
pred stepFromGoodState[s1, s2: SearchState] {
bsearchInvariant[s1]
anyTransition[s1,s2]
}
assert all s1, s2: SearchState | stepFromGoodState[s1,s2] is sufficient for bsearchInvariant[s2]
for exactly 1 IntArray, exactly 2 SearchState

-- These pass (but only after we add the enrichment).
-- To see an example, uncomment the run below.

option run_sterling "binarysearch.js"
run {
some disj s1,s2: SearchState | {
init[s1]
validArray[s1.arr]
safeArraySize[s1.arr]
anyTransition[s1, s2]
-- To make things interesting, let's see a transition where the target is present
some i: Int | s1.arr.elements[i] = s1.target
}
} for exactly 1 IntArray, exactly 2 SearchState

Loading
Loading