Expressing rules in B-Method - model-checking

I'm writing some specifications of a system in B-method. I have the following variables which are subsets of a general set:
First Notation:
a :={x,y,z,v}
b :={x,y,z}
I want to state a rule that whenever something exists in set "b", it also exists in set "a" which helps writing the above specifications as the following:
second Notation:
a :={v}
b :={x,y,z}
Explanation of second notation: I want the machine to infer that a :={x,y,z,v} from a :={v}, b :={x,y,z}, and the rule.
How can I express the rule so I avoid the first notation and instead write the second notation?
I tried the following but it didn't work
INITIALISATION
a :={v} &
b :={x,y,z}
ASSERTIONS
!x.(x:b => x:a)

First of all, the predicate !x.(x:b => x:a) can be more easily expressed just by b<:a.
It's not clear to me what exactly you want to express: Should b always be a subset of a or just in the initialisation?
If always, the INVARIANT would be the correct location for that. ASSERTIONS are similar but should be an implication by the other invariants.
But then you must explicitly ensure that in your initialisation.
Another point which is unclear to me is what you mean by "infer". Do you just not want to specify the details?
An initialisation where you assign a set with one element more than b could look like the following (assuming that a and b contain elements of S):
INITIALISATION
ANY v,s
WHERE
v:S
& s<:S
THEN
a := s\/{v}
|| b := s
END
(Disclaimer: I haven't actually tested it.)
If a should always be larger than b, you could add something like v/:s.
Your description does not make it clear what exactly you want to achieve.
Another approach would use the "becomes such substitution" (but in my opinion it is less readable):
INITIALISATION
a,b :( a:S & b:S &
b={x,y,z} &
#x.( x:S & a=b\/{x} ))

First, and foremost, the B machine does not infer anything by itself. It provides a language where the user can express properties and a mechanism that generates proof obligations that must be successfully processed by the prover (automatically or with human assistance) to guarantee that the properties hold.
In your example, if you want to express that every element of set bb is always an element of set aa, then as observed by danielp, just write
bb <: aa
Next, if you want to write that aa apossesses an element that is not in bb, then you can express it as
aa /= bb & not(aa = {})
or as
#(elem).(elem : S & elem : bb & not(elem : aa))
If you rather want to express that the specific value vv is in aa but not in bb, then the following applies
vv : bb & not(vv : aa)
These expressions may be used at several locations of the B machine, depending whether you want to assert properties on parameters, constants or variables.
For instance, say you have a machine with two variables va and vb, where both are sets of elements of a given set s1, and that you want they are initialized in such a way that every element of vb is also an element of va, and that there exists an element of va that is not in vb. Observe first that this means that vb is a strict subset of va.
INITIALISATION
ANY inia, inib WHERE
inia <: s1 & inib <: s2 & inib <<: inia
THEN
va := inia || vb := inib
END

Related

AQL to validate path to node

We're required to have some AQL that validates a specific path to an entity. The current solution performs very poorly, due to needing to scan whole collections.
e.g. here we have 3 entity 'types': a, b, c (though they are all in a single collection) and specific edge collections between them and we want to establish whether or not there is a connection between _key "123" and _key "234" that goes exactly through a -> b -> c.
FOR a IN entities FILTER e._key == "123"
FOR b IN 1..1 OUTBOUND e edges_a_to_b
FOR c IN 1..1 INBOUND e_1 edges_c_to_b
FILTER e_2._key == "234"
...
This can fan out very quickly!
We have another solution, where we use SHORTEST PATH and specify the appropriate DIRECTION and edge collections which is much faster (>100times). But worry that this approach does not satisfy quite our general case... the order of the edges is not enforced, and we may have to go through the same edge collection more than once, which we cannot do with that syntax.
Is there another way, possibly involving paths in the traversal?
Thanks!
Dan.
If i understand correctly you always know the exact path that is required between your two vertices.
So to take your example a -> b -> c, a valid result will have:
path.vertices == [a, b, c]
So we can use this path to filter on it, which only works if you use a single traversal step instead of multiple ones.
So what we try to du is the following pattern:
FOR c,e, path IN <pathlength> <direction> <start> <edge-collections>
FILTER path.vertices[0] == a // This needs to be formulated correctly
FILTER path.vertices[1] == b // This needs to be formulated correctly
FILTER path.vertices[2] == c // This needs to be formulated correctly
LIMIT 1 // We only net exactly one path, so limit 1 is enough
[...]
So with this hint is it possible to write the query in the following way:
FOR a IN entities
FILTER a._key == "123"
FOR c, e, path IN 2 OUTBOUND a edges_a_to_b, INBOUND edges_b_to_c
FILTER path.vertices[1] == /* whatever identifies b e.g. vertices[1].type == "b" */
FILTER path.vertices[2]._key == "234"
LIMIT 1 /* This will stop as soon as the first match is found, so very important! */
/* [...] */
This will allow the optimizer to apply the filter conditions as early as possible, und will (almost) use the same algorithm as the shortest path implementation.
The trick is to use one traversal instead of multiples to save internal overhead and allow for better optimization.
Also take into account that it might be better to search in the opposite direction:
e.g. instead of a -> b -> c check for c <- b <- a which might be faster.
This depends on the amount of edges per each node.
I assume a doctor has many surgeries, but a single patient most likely has only a small amount of surgeries so it is better to start at the patient and check backwards instead of starting at the doctor and check forwards.
Please let me know it this helps already, otherwise we can talk about more details and see if we can find some further optimizations.
Disclaimer: I am part of the Core-Dev team at ArangoDB

Find union of two variable-name scalars

I have a Stata program that outputs a local scalar of space-separated variable names.
I have to run the program twice on two samples (same dta) and store the union (intersection - variable names appearing in both scalars) as a new space-separated local scalar (for input to another program).
I can't figure out how to split (per spaces) and or test the occurrences of variable names in each.
Stata has a bunch of extended macro functions to use on lists that you can find with help macrolists, where you can see that A & B returns the intersection of A and B. If A="a b c d" and B="b c f g", then A & B = "b c".
This allows you to do something like this:
clear
scalar l1="vara varb varc"
scalar l2="varc vard vare"
local l1 = scalar(l1)
local l2 = scalar(l2)
local inter: list l1 & l2
scalar inter="`inter'"
scalar list inter
You convert the scalars to locals, get their union, and convert that into a scalar. It is probably easier to just modify your code to use locals rather than scalars so you don't have to deal with conversions.
I am not sure I perfectly understand your question, if this is not the appropriate answer, please add an example for us to work with.
Here is the code that checks two space-separated macros and gets their intersection, even if it's not the most elegant, unless your macros are huge it should still be quite fast.
local list1 first list here
local list2 list two here
local intersection
foreach l1 in `list1' {
foreach l2 in `list2' {
// if they overlap, add to the intersection macro
if "`l1'" == "`l2'" {
local intersection `intersection' `l1'
}
}
}
mac list // show the macros stored currently in the do file

Alloy - Dealing with unbounded universal quantifiers

Good afternoon,
I've been experiencing an issue with Alloy when dealing with unbounded universal quantifiers. As explained in Daniel Jackson's book 'Software Abstractions' (Section 5.3 'Unbounded Universal Quantifiers'), Alloy has a subtle limitation regarding universal quantifiers and assertion checking. Alloy produces spurious counterexamples in some cases, such as the next one to check that sets are closed under union (shown in the aforementioned book):
sig Set {
elements: set Element
}
sig Element {}
assert Closed {
all s0, s1: Set | some s2: Set |
s2.elements = s0.elements + s1.elements
}
check Closed for 3
Producing a counterexample such as:
Set = {(S0),(S1)}
Element = {(E0),(E1)}
s0 = {(S0)}
s1 = {(S1)}
elements = {(S0,E0), (S1,E1)}
where the analyser didn't populate Set with enough values (a missing Set atom, S2, containing the union of S0 and S1).
Two solutions to this general problem are suggested then in the book:
1) Declaring a generator axiom to force Alloy to generate all possible instances.
For example:
fact SetGenerator{
some s: Set | no s.elements
all s: Set, e: Element |
some s': Set | s'.elements = s.elements + e
}
This solution, however, produces a scope explosion and may also lead to inconsistencies.
2) Omitting the generator axiom and using the bounded-universal form for constraints. That is, quantified variable's bounding expression doesn't mention the names of generated signatures. However, not every assertion can be expressed in such a form.
My question is: is there any specific rule to choose any of these solutions? It isn't clear to me from the book.
Thanks.
No, there's no specific rule (or at least none that I've come up with). In practice, this doesn't arise very often, so I would deal with each case as it comes up. Do you have a particular example in mind?
Also, bear in mind that sometimes you can formulate your problem with a higher order quantifier (ie a quantifier over a set or relation) and in that case you can use Alloy*, an extension of Alloy that supports higher order analysis.

Is "set" the default multiplicity?

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.

Is there a way to pass a parameter into a NATURAL subroutine?

I am new to the NATURAL programming language. I am trying to find a way that I can pass one parameter to a subroutine just like in C++ or Java. Right now I have to move everything to another variable and call the method. Thus is cumbersome and is a lot more code to write.
Question: Can a Natural Program Sub-Routine have a parameter list like in C++ or Java?
D = passVariable1
PERFORM FLIP-DATE
A = D
END-SUBROUTINE
newVariable = A
Code:
DEFINE SUBROUTINE FLIP-DATE
#A = #D
#B = #E
#C = #F
RESET #NMM #NDD #NCCYY
END-SUBROUTINE
What I would like to do.
Code:
DEFINE SUBROUTINE FLIP-DATE(A,B,C,D,E,F) <-- is this possible somehow?
#A = #D
#B = #E
#C = #F
RESET #NMM #NDD #NCCYY
END-SUBROUTINE
The parameter data area (PDA) is a special verision of the local data area (LDA), that is used in function, external subroutine, or helproutine objects. You can either define parameters inline like
DEFINE DATA
PARAMETER
1 #A(N2)
1 #B(N2)
1 #C(N2)
1 #D(N2)
1 #E(N2)
1 #F(N2)
LOCAL
your local variables
END-DEFINE
…
Alternatively you can also create a separate source object, similar to an external LDA.
DEFINE DATA
PARAMETER USING pda
LOCAL
your local variables
END-DEFINE
…
Note that you cannot use parameters with an internal subroutine.
I suggest you start reading the Natural documentation on Software AG's web site, especially the "First Steps" manual, if you've never worked with this powerful language before.
parameter-data-area can be used to pass the data to sub programs and routines.

Resources