As I'm new to alloy, this is most likely a simple question. I've been through the on-line tutorials and am now reading the Software Abstractions, revised edition. On page 34 there is an example at the bottom of the page:
r' = {b:B, a:A, c:C | a->b->c in r}
where the text says that this defines a new relation of B->A->C. I don't see how an explicit order for r' is achieved by this statement.
It's the property of set comprehension
{a: A | somePredicate1[a]} is of type A and returns a set containing all atoms for which somePredicate1 holds;
{a: A, b: B | somePredicate2[a, b]} is of type A->B and returns a relation containing all a->b tuples for which somePredicate2 holds;
and so on
The syntax of set comprehension basically consists of two parts (1) type declaration (before the | character), and (2) predicate which must hold for every element in the returned set.
Related
I had previously asked where the Winery types are indexed. I noticed that in the serialization for the schema for Bool, which is [4,6], the 4 is the version number, and 6 is the index of SBool in SchemaP. I verified the hypothesis using other "primitive" types like Integer (serialization: 16), Double (18), Text (20). Also, [Bool] will be SVector SBool, serialized to [4,2,6], which makes sense: the 2 is for SVector, the 6 is for SBool.
But SchemaP also contains constructors that I don't intuitively see how are used: SFix, SVar, STag and SLet. What are they, and which type would I need to construct the schema for, to see them used? Why is SLet at the end, but SFix at the beginning?
SFix looks like a µ quantifier for a recursive type. The type µx. T is the type T where x refers to the whole type µx. T. For example, a list data List a = Nil | Cons a (List a) can be represented as L(a) = µr. 1 + a × r, where the recursive occurrence of the type is replaced with the variable r. You could probably see this with a recursive user-defined type like data BinTree a = Leaf | Branch a (BinTree a) (BinTree a).
This encoding doesn’t explicitly include a variable name, because the next constructor SVar specifies that “SVar n refers to the nth innermost fixpoint”, where n is an Int in the synonym type Schema = SchemaP Int. This is a De Bruijn index. If you had some nested recursive types like µx. µy. … = SFix (SFix …), then the inner variable would be referenced as SVar 0 and the outer one as SVar 1 within the body …. This “relative” notation means you can freely reorganise terms without worrying about having to rename variables for capture-avoiding substitution.
SLet is a let binding, and since it’s specified as SLet !(SchemaP a) !(SchemaP a), I presume that SLet e1 e2 is akin to let x = e1 in e2, where the variable is again implicit. So I suspect this may be a deficiency of the docs, and SVar can also refer to Let-bound variables. I don’t know how they use this constructor, but it could be used to make sharing explicit in the schema.
Finally, STag appears to be a way to attach extra “tag” metadata within the schema, in some way that’s specific to the library.
The ordering of these constructors might be maintained for compatibility with earlier versions, so adding new constructors at the end would avoid disturbing the encoding, and I figure the STag and SLet constructors at the end were simply added later.
Are these two equivalent:
r: A -> B
r: A set -> set B
That is, is set the default multiplicity?
If yes, then I will quibble with the definition of the arrow operator in the Software Abstractions book. The book says on page 55:
The arrow product (or just product) p->q of two relations p and q is
the relation you get by taking every combination of a tuple from p and
a tuple from q and concatenating them.
I interpret that definition to mean the only valid instance for p->q is one that has every possible combination of tuples from p with tuples from q. But that's not right (I think). Any instance containing mappings between p and q is valid. For example, on page 56 is this example,
Name = {(N0), (N1)}
Addr = {(D0), (D1)}
The book says this is a valid relation for Name->Addr
{(N0, D0), (N0, D1), (N1, D0), (N1, D1)}
But that's not the only valid relation, right? For example, this is a valid relation:
{(N0, D0), (N1, D1)}
Is that right?
The declaration r : A->B means r is a subset of A->B. The expression A->B has just one value, which is the cross product of A and B. The declaration results in a set of possible values for r, which would include both the example given in the book that you cite, and the example that you ask about.
/*
sig a {
}
sig b {
}
*/
pred rel_test(r : univ -> univ) {
# r = 1
}
run {
some r : univ -> univ {
rel_test [r]
}
} for 2
Running this small test, $r contains one element in every generated instance. When sig a and sig b are uncommented, however, the first instance is this:
In my explanation, $r has 9 tuples here and still, the predicate which asks for a one tuple relation succeeds. Where am I wrong?
An auxiliary question: are these two declarations equivalent?
pred rel_test(r : univ -> univ)
pred rel_test(r : set univ -> univ)
The problem is that with the Forbid Overflow option set to No the integer semantics in Alloy is wrap around, and with the default scope of 3 (bits), then indeed 9=1, as you can confirm in the evaluator.
With the signatures a and b commented the biggest relation that can be generated with scope 2 has 4 tuples (since the max size of univ is 2), so the problem does not occur.
It also does not occur in the latest build because I believe it comes with the Forbid Overflow option set to Yes by default, and with that option the semantics of integers rules out instances where overflows occur, precisely the case when you compute the size of the relation with 9 tuples. More details about this alternative integer semantics can be found in the paper "Preventing arithmetic overflows in Alloy" by Aleksandar Milicevic and Daniel Jackson.
On the main question: what version of Alloy are you using? I'm unable to replicate the behavior you describe (using Alloy 4.2 of 22 Feb 2015 on OS X 10.6.8).
On the auxiliary question: it appears so. (The language reference is not quite as explicit as one might wish, but it begins one part of its discussion of multiplicities with "If the right-hand expression denotes a unary relation ..." and (in what I take to be the context so defined) "the default multiplicity is one"; the conditional would make no sense if the default multiplicity were always one.
On the other hand, the same interpretive logic would lead to the conclusion that the language reference believes that unary multiplicity keywords are only allowed before expressions denoting unary relations (which would appear to make r: set univ -> univ ungrammatical). But Alloy accepts the expression and parses it as set (univ -> univ). (The alternative parse, (set univ) -> univ, would be very hard to assign a meaning to.)
Consider the following simple variant of the Address Book example
sig Name, Addr {}
sig Book { addr : Name -> Addr } // no lone on Addr
pred show(b:Book) { some n : Name | #addr[b,n] > 1 }
run show for exactly 2 Book, exactly 2 Addr, exactly 2 Name
In some model instances, I can get the following results in the evaluator
all b:Book | show[b]
--> yields false
some b:Book | show[b]
--> yields true
show[Book]
--> yields true
If show was a relation, then one might expect to get an answer like: { true, false }. Given that it is a predicate, a single Boolean value is returned. I would have expected show[Book] to be a shorthand for the universally quantified expression above it. Instead, it seems to be using existential quantification to fold the results. Anyone know what might be the rational for this, or have another explanation for the meaning of show[Book]?
(I'm not sure I have the correct words for this, so bear with me if this seems fuzzy.)
Bear in mind that all expressions in Alloy that denote individuals denote sets of individuals, and that there is no distinction available in the language between 'individual X' and 'the singleton set whose member is the individual X'. ([Later addendum:] In the terms more usually used: the general rule in Alloy's logic is that all values are relations. Binary relations are sets of pairs, n-ary relations sets of n-tuples, sets are unary relations, and scalars are singleton sets. See the discussion in sec. 3.2.2 of Software Abstractions, or the slide "Everything's a relation" in the Alloy Analyzer 4 tutorial by Greg Dennis and Rob Seater.)
Given the declaration you give of the 'show' predicate, it's easy to expect that the argument of 'show' should be a single Book -- or more correctly, a singleton set of Book --, and then to expect further that if the argument is not actually a singleton set (as in the expression show[Book] here) then the system will coerce it to being a singleton set, or interpret it with some sort of implicit existential or universal quantification. But in the declaration pred show(b:Book) ..., the expression b:Book just names an object b which will be a set of objects in the signature Book. (To require that b be a singleton set, write pred show(one b: Book) ....) The expression which constitutes the body of show is evaluated for b = Book just as readily as for b = Book$0.
The appearance of existential quantification is a consequence of the way the dot operator at the heart of the expression addr[b,n] (or equivalently n.(b.addr) is defined. Actually, if you experiment you'll find that show[Book] is true whenever there is any name for which the set of all books contains a mapping to two different addresses, even in cases where an existential interpretation would fail. Try adding this to your model, for example:
pred hmmmm { show[Book] and no b: Book | show[b] }
run hmmmm for exactly 2 Book, exactly 2 Addr, exactly 2 Name
Atom: The Atom is the datatype used to describe Atomic Sentences or propositions. These are basically
represented as a string.
Literal: Literals correspond to either atoms or negations of atoms. In this implementation each literal
is represented as a pair consisting of a boolean value, indicating the polarity of the Atom, and the
actual Atom. Thus, the literal ‘P’ is represented as (True,"P") whereas its negation ‘-P’ as
(False,"P").
2
Clause: A Clause is a disjunction of literals, for example PvQvRv-S. In this implementation this
is represented as a list of Literals. So the last clause would be [(True,"P"), (True,"Q"),
(True,"R"),(False,"S")].
Formula: A Formula is a conjunction of clauses, for example (P vQ)^(RvP v-Q)^(-P v-R).
This is the CNF form of a propositional formula. In this implementation this is represented as a list of
Clauses, so it is a list of lists of Literals. Our above example formula would be [[(True,"P"),
(True,"Q")], [(True,"R"), (True,"P"), (False,"Q")], [(False, "P"),
(False,"P")]].
Model: A (partial) Model is a (partial) assignment of truth values to the Atoms in a Formula. In this
implementation this is a list of (Atom, Bool) pairs, ie. the Atoms with their assignments. So in the
above example of type Formula if we assigned true to P and false to Q then our model would be
[("P", True),("Q", False)]
Ok so I wrote and update function
update :: Node -> [Node]
It takes in a Node and returns a list of the Nodes
that result from assigning True to an unassigned atom in one case and False in the other (ie. a case
split). The list returned has two nodes as elements. One node contains the formula
with an atom assigned True and the model updated with this assignment, and the other contains
the formula with the atom assigned False and the model updated to show this. The lists of unassigned
atoms of each node are also updated accordingly. This function makes use of an
assign function to make the assignments. It also uses the chooseAtom function to
select the literal to assign.
update :: Node -> [Node]
update (formula, (atoms, model)) = [(assign (chooseAtom atoms, True) formula, (remove (chooseAtom atoms) atoms, ((chooseAtom atoms,True)) `insert` model)) , (assign (chooseAtom atoms, False) formula, (remove (chooseAtom atoms) atoms, ((chooseAtom atoms, False) `insert` model)) )]
Now I have to do the same thing but this time I must implement a variable selection heuristic.this should replace the chooseAtom and I'm supposed to write a function update2 using it
type Atom = String
type Literal = (Bool,Atom)
type Clause = [Literal]
type Formula = [Clause]
type Model = [(Atom, Bool)]
type Node = (Formula, ([Atom], Model))
update2 :: Node -> [Node]
update2 = undefined
So my question is how can I create a heurestic and to implement it into the update2 function ,that shoud behave identical to the update function ?
If I understand the question correctly, you're asking how to implement additional selection rules in resolution systems for propositional logic. Presumably, you're constructing a tree of formulas gotten by assigning truth-values to literals until either (a) all possible combinations of assignments to literals have been tried or (b) box (the empty clause) has been derived.
Assuming the function chooseAtom implements a selection rule, you can parameterize the function update over an arbitrary selection rule r by giving update an additional parameter and replacing the occurrence of chooseAtom in update by r. Since chooseAtom implements a selection rule, passing that selection rule to the parameter r gives the desired result. If you provide an implementation of chooseAtom and the function you intend to replace it, it would be easier to verify that your implementation is correct.
Hopefully this is helpful. However, it's unclear exactly what's being asked. In particular, you're asking for a "variable selection rule." However, it looks like you're implementing a resolution system for propositional logic. In general, selection rules and variables are associated with resolution for predicate logic.