Gauss's Identity: 1 + … + n = n(n+1)/2
Proof by induction:
Start at some point (in this case one). Then show that if we know it's true for one, that implies it's true for two. And if it's true for two, that implies it's true for three, and so on.
Base case: 1: 1 = 1(1+1)/2
Inductive hypothesis: Assume 1 + … + k = k(k+1)/2.
Now we want to prove that 1 + … + k + k+1 = (k+1)((k+1)+1)/2
substitute k(k+1)/2 for 1 + … + k in 1 + … + k + k+1
k(k+1)/2 + k+1
k(k+1)/2 + 2(k+1)/2
(k+1)(k+2)/2
From last class, we have a model for descent down a binary search tree, where we either find an element if it's there, or we find Empty if it is not there.
fact vs. predicate in Alloy: facts are universally true (Alloy will never give you an instance that does not make the fact true). predicates are not necessarily true (unless you put them in a run statement or in a fact)
When you're modeling, you describe the shape of worlds and behaviors you care about. In properties/predicates, you describe what you want to be true about the instances.
The program/model defined either in code or in a model is separate from your intuition/expectations/what you want to happen.
This distinction is especially important in modeling because you don't want to add your intuitions/expectations into the model itself.
Now we want to model things like add, remove, etc. from our binary tree.
Our model right now produces only one binary tree. How is that a problem?
In order to reason about add
, we need to change our sigs to allow multiple trees.
abstract sig Node {}
sig Empty extends Node {}
sig Data extends Node {
num : Int,
left : Node,
right : Node
}
In our model so far, we have no sig for a tree. Implicitly, the whole world was one tree, because every possible node was part of one tree.
sig Tree {
nodes : set Node,
root: lone nodes, //root is one (or zero) Node from set nodes
lefts : nodes -> nodes,
rights : nodes -> nodes
}
Modeling choice: remove the distinction between Empty nodes and Data nodes.
Implicitly, a node has empty children if there is nothing in the lefts or rights relation specifying its children.
This change is good for simplicity (and also performance).
Now we have to change the predicate btree:
pred btree[t : Tree] {
// everything in the tree is reachable from the root of the tree
t.nodes in t.root.*(t.lefts + t.rights)
all n : t.nodes | {
// no cycles
n not in n.^(t.lefts + t.rights)
// at most one parent
lone n.~(t.lefts + t.rights)
// distinct children if any
no t.lefts[n] & t.rights[n]
}
}
In the visualizer, Alloy doesn't really know how to show relations with more than two columns. Instead, you can project over Tree, and then it will show your a more helpful visualization of each tree.