How can I design a Decision node with three outgoing edges and else guard?
what I'd like is - 3 outgoing edges from decision node 'test?'
#startuml
start
:dd;
if (test?) then (a)
:A;
else if (b)
:B;
else (c)
:C;
endif
:wertz;
:dewe;
end
#enduml
For that you can use several else allowed by the 'old' syntax of activities :
#startuml
(*) --> if "" then
--> [[priority = 1]] "A"
else
--> [[priority = 2]] "B"
else
--> [[else]] "C"
endif
#enduml
Note it is not possible to directly use ]] nor \]], both producing a syntax error, so I had to use ] to close the bracket
this is another solution proposed in the PlantUML Q&A:
#startuml
start
switch (test?)
case ( condition A )
:Text 1;
case ( condition B )
:Text 2;
case ( condition C )
:Text 3;
case ( condition D )
:Text 4;
endswitch
stop
#enduml
A similar requirement for "Switch or multiple else branches" was discussed in the PlantUML Q&A, and they suggested the following approach which also worked for me:
#startuml
start
if (condition A) then (yes)
:Text 1;
elseif (condition B) then (yes)
:Text 2;
stop
elseif (condition C) then (yes)
:Text 3;
elseif (condition D) then (yes)
:Text 4;
else (nothing)
:Text else;
endif
stop
#enduml
Related
The Problem
I'm playing around with TLA+, and thought I'd write the following clearly false specification in PlusCal:
---- MODULE transfer ----
EXTENDS Naturals, TLC, Sequences
(* --algorithm transfer
\* Simple algorithm:
\* 1. Start with a shared-memory list with one element.
\* 2. A process adds arbitrary numbers of elements to the list.
\* 3. Another process removes arbitrary numbers of elements from the list,
\* but only if the list has more than one item in it. This check is
\* applied just before trying to removing an element.
\* Is it true that the list will always have a length of 1?
\* You would expect this to be false, since the adder process can add more elements
\* than the remover process can consume.
variables stack = <<0>>
process Adder = 0
begin
AddElement:
stack := Append(stack, Len(stack));
either goto AddElement
or skip
end either;
end process;
process Remover = 1
begin
RemoveElement:
\* Pop from the front of the stack
if Len(stack) > 1 then
stack := Tail(stack);
end if;
either goto RemoveElement
or skip
end either;
end process;
end algorithm *)
IsStackAlwaysUnitLength == Len(stack) = 1
====
After checking IsStackAlwaysUnitLength as one of the temporal properties to report on, I expected TLA+ to mark this property as failed.
However, all states passed! Why is it not failing?
Debugging Attempts
On debugging with print statements, I noticed the following odd behaviour:
process Adder = 0
begin
AddElement:
print stack;
print "Adder applied!";
stack := Append(stack, Len(stack));
print stack;
print "Adder task complete!";
\* Force
either goto AddElement
or skip
end either;
end process;
process Remover = 1
begin
RemoveElement:
\* Pop from the front of the stack
print stack;
print "Remover applied!";
if Len(stack) > 1 then
stack := Tail(stack);
print stack;
print "Remover task complete!";
else
print "Remover task complete!";
end if;
either goto RemoveElement
or skip
end either;
end process;
yields in the debugging panel
<<0>>
"Adder applied!"
<<0>>
"Adder task complete!"
<<0>>
<<0>>
"Remover applied!"
"Remover applied!"
"Remover task complete!"
"Remover task complete!"
<<0>>
"Adder applied!"
<<0>>
"Adder task complete!"
I'm unsure why stack := Append(stack, Len(stack)); and stack := Tail(stack); are not updating the global stack variable.
Full TLA Specification Generated
---- MODULE transfer ----
EXTENDS Naturals, TLC, Sequences
(* --algorithm transfer
variables stack = <<0>>
process Adder = 0
begin
AddElement:
stack := Append(stack, Len(stack));
either goto AddElement
or skip
end either;
end process;
process Remover = 1
begin
RemoveElement:
\* Pop from the front of the stack
if Len(stack) > 1 then
stack := Tail(stack);
end if;
either goto RemoveElement
or skip
end either;
end process;
end algorithm *)
\* BEGIN TRANSLATION
VARIABLES stack, pc
vars == << stack, pc >>
ProcSet == {0} \cup {1}
Init == (* Global variables *)
/\ stack = <<0>>
/\ pc = [self \in ProcSet |-> CASE self = 0 -> "AddElement"
[] self = 1 -> "RemoveElement"]
AddElement == /\ pc[0] = "AddElement"
/\ stack' = [stack EXCEPT ![0] = Append(stack, Len(stack))]
/\ \/ /\ pc' = [pc EXCEPT ![0] = "AddElement"]
\/ /\ TRUE
/\ pc' = [pc EXCEPT ![0] = "Done"]
Adder == AddElement
RemoveElement == /\ pc[1] = "RemoveElement"
/\ IF Len(stack) > 1
THEN /\ stack' = [stack EXCEPT ![1] = Tail(stack)]
ELSE /\ TRUE
/\ stack' = stack
/\ \/ /\ pc' = [pc EXCEPT ![1] = "RemoveElement"]
\/ /\ TRUE
/\ pc' = [pc EXCEPT ![1] = "Done"]
Remover == RemoveElement
Next == Adder \/ Remover
\/ (* Disjunct to prevent deadlock on termination *)
((\A self \in ProcSet: pc[self] = "Done") /\ UNCHANGED vars)
Spec == Init /\ [][Next]_vars
Termination == <>(\A self \in ProcSet: pc[self] = "Done")
\* END TRANSLATION
IsStackAlwaysUnitLength == Len(stack) = 1
====
Congratulations, you've hit a PlusCal bug! And also an edge case that's not a bug but still unintuitive. Let's start with the bug.
Sometimes when using PlusCal we want to have multiple processes share labels. We do this with a procedure. In order to make it all work the PlusCal translator adds an extra bookkeeping variable called stack. Normally, if the user defines a variable foo that conflicts with a generated variable foo, the translation renames one to foo_. In this case, since there was no conflict, there wasn't any renaming.* The bug is that the translator got confused and translated the variable as if it was supposed to be the bookkeeping stack. You can see this as it turned the append into
stack' = [stack EXCEPT ![0] = Append(stack, Len(stack))]
When it should just be
stack' = Append(stack, Len(stack))
You can fix this by renaming stack to mystack. That should get the spec behaving properly. But it will still pass: that's because you put IsStackAlwaysUnitLength as a property and not an invariant. As a temporal property, IsStackAlwaysUnitLength is true if it's true in the initial state. As an invariant, IsStackAlwaysUnitLength is true if it's true in all states.** YOu can get the spec to fail properly by changing IsStackAlwaysUnitLength from a temporal property to an invariant in the "what is the model" page.
*Actually in this case the translator won't rename stack if you add a procedure, it just throws an error. But that's still fail-safe.
**This is because TLC (the model checker) treats the invariant P as the temporal property []P. It's syntactic sugar, basically.
I am working on a promela model that is fairly simple. Using two different modules, it acts as a crosswalk/Traffic light. The first module is the traffic light that outputs the current signal (green, red, yellow, pending). This module also receives as an input a signal called "pedestrian" which acts as an indicator that there are pedestrians wanting to cross. The second module acts as the crosswalk. It receives output signals from the traffic light module (green, yellow, green). It outputs the pedestrian signal to the traffic light module. This module simply defines whether the pedestrian(s) is crossing, waiting or not present. My issue is that once the count value goes to 60, a timeout occurs. I believe the statement "SigG_out ! 1" is causing the error but I do not know why. I have attached the image of the trace I receive from the command line. I am completely new to Spin and Promela and so I am not sure how to use the information form the trace to find my issue in the code. Any help is greatly appreciated.
Here is the code for the complete model:
mtype = {red, green, yellow, pending, none, crossing, waiting};
mtype traffic_mode;
mtype crosswalk_mode;
int count;
chan pedestrian_chan = [0] of {byte};
chan sigR_chan = [0] of {byte};
chan sigG_chan = [0] of {byte};
chan sigY_chan = [0] of {byte};
ltl l1 {!<> (pedestrian_chan[0] == 1) && (traffic_mode == green || traffic_mode == yellow || traffic_mode == pending)}
ltl l2 {[]<> (pedestrian_chan[0] == 1) -> crosswalk_mode == crossing }
proctype traffic_controller(chan pedestrian_in, sigR_out, sigG_out, sigY_out)
{
do
::if
::(traffic_mode == red) ->
count = count + 1;
if
::(count >= 60) ->
sigG_out ! 1;
count = 0;
traffic_mode = green;
:: else -> skip;
fi
::(traffic_mode == green) ->
if
::(count < 60) ->
count = count + 1;
::(pedestrian_in == 1 & count < 60) ->
count = count + 1;
traffic_mode = pending;
::(pedestrian_in == 1 & count >= 60)
count = 0;
traffic_mode = yellow;
fi
::(traffic_mode == pending) ->
count = count + 1;
if
::(count >= 60) ->
sigY_out ! 1;
count = 0;
traffic_mode = yellow;
::else -> skip;
fi
::(traffic_mode == yellow) ->
count = count + 1;
if
::(count >= 5) ->
sigR_out ! 1;
count = 0;
traffic_mode = red;
:: else -> skip;
fi
fi
od
}
proctype crosswalk(chan sigR_in, sigG_in, sigY_in, pedestrian_out)
{
do
::if
::(crosswalk_mode == crossing) ->
if
::(sigG_in == 1) -> crosswalk_mode = none;
fi
::(crosswalk_mode == none) ->
if
:: (1 == 1) -> crosswalk_mode = none
:: (1 == 1) ->
pedestrian_out ! 1
crosswalk_mode = waiting
fi
::(crosswalk_mode == waiting) ->
if
::(sigR_in == 1) -> crosswalk_mode = crossing;
fi
fi
od
}
init
{
count = 0;
traffic_mode = red;
crosswalk_mode = crossing;
atomic
{
run traffic_controller(pedestrian_chan, sigR_chan, sigG_chan, sigY_chan);
run crosswalk(sigR_chan, sigG_chan, sigY_chan, pedestrian_chan);
}
}
You are using channels incorrectly, this line in particular I wouldn't even know how to interpret it:
:: (sigG_in == 1) ->
Your channels are synchronous, which means that whenever a process sends something on one side, another process must listen on the other end of the channel in order to deliver the message. Otherwise, the process blocks until when the situation changes. Your channels are synchronous because you declared them of size 0.
To read from a channel, you need to use the proper syntax:
int some_var;
...
some_channel?some_var;
// here some_var contains value received through some_channel
It seems to be a bit pointless to use three different channels to send different signals. What about using three different values?
mtype = { RED, GREEN, YELLOW };
chan c = [0] of { mtype };
...
c!RED
...
// (some other process)
...
mtype var;
c?var;
// here var contains RED
...
The following Groovy code prints a range of numbers from 1 to 5.
(1..5).each {println it}
However, when I forget to add the parenthesis, and do this:
1..5.each { println it}
It prints only 5
Why is this legal Groovy syntax? I would expect this to either behave as the (1..5) version or to throw an exception saying that I have forgotten the parenthesis.
5.each has priority over 1..5 in the Groovy parser. It works because it is doing something like this:
ret = 5.each { println it }
range = 1..ret
assert range == [1, 2, 3, 4, 5]
The return of each is the collection itself
The .-Operator has a higher precedence in groovy than .. Source:
Operator Overloading
The precedence heirarchy of the operators, some of which we haven't looked at yet, is, from highest to lowest:
$(scope escape)
new ()(parentheses)
[](subscripting) ()(method call) {}(closable block) [](list/map)
. ?. *. (dots)
~ ! $ ()(cast type)
**(power)
++(pre/post) --(pre/post) +(unary) -(unary)
* / %
+(binary) -(binary)
<< >> >>> .. ..<
< <= > >= instanceof in as
== != <=>
&
^
|
&&
||
?:
= **= *= /= %= += -= <<= >>= >>>= &= ^= |=
I m trying this code:
enum SideType
{
Vex;
Cav;
Plano;
}
function drawLense(aLeftType:SideType){
switch (aLeftType)
{
case Cav:
leftCenter = -aRadius - d * 0.5;
case Vex:
leftCenter = -Math.cos(( -90 + offset) * Math.PI / 180) * aRadius-d*0.5;
case Plano:return ;
case Cav, Vex:
points1= drawCurve(1, -90 + offset + trim, 180 - offset * 2 - (trim * 2), leftCenter, aRadius);
_LB = points1[0];
_LA = points1[1];
}
}
But I get an error when compile:
characters 8-16 : This pattern is unused
So, it pointing at case Cav, Vex:
How can I check Cav or Vex in the case above?
EDIT
I found that if I removed case Cav & Case Vex, then case Cav, Vex will work, but this is not what I want, can't I repeat the pattern usage in an or experision?
like (case Cav||Vex)?
case (Cav || Vex) would result into:
src/com/optics/components/Lense.hx:343: characters 8-38 : Case expression must be a constant value or a pattern, not an arbitrary expression
There are only 3 choices for the value of aLeftType, either Vex, Cav, or Plano.
var aLeftType = Vex;
switch (aLeftType)
{
case Cav:
// If aLeftType is `Cav`, run this line.
case Vex:
// If aLeftType is `Vex`, run this line.
case Plano:
// If aLeftType is `Plano`, run this line.
case Cav, Vex:
// If aLeftType is `Vex` or `Plano`, run this line...
// But the first 2 cases already covered `Vex` and `Plano`,
// so it will never be reached.
}
So really, the code of the 4th case will never be run. It is similar to:
if (a == 1) {
trace("a is 1");
} else if (a == 1) {
trace("a is really 1"); // This can never be reached.
}
That means, you have to think again want do you really want to do.
Usually when you want to make the same thing in different situation, you make a function for that :)
function drawLense(aLeftType:SideType){
switch (aLeftType)
{
case Cav:
leftCenter = -aRadius - d * 0.5;
functionCalledIfCavOrVex();
case Vex:
leftCenter = -Math.cos(( -90 + offset) * Math.PI / 180) * aRadius-d*0.5;
functionCalledIfCavOrVex();
case Plano:return ;
}
}
function functionCalledIfCavOrVex(/*...*/){
points1= drawCurve(1, -90 + offset + trim, 180 - offset * 2 - (trim * 2), leftCenter, aRadius);
_LB = points1[0];
_LA = points1[1];
}
Short answer: no way currently, you can only match one enum option in one place(not counting guarded options). So, duplicate your code for each enum option and live a happy life(this code will be also easier to read) or use a seconds switch(which might be shorter and easier in some more complex cases).
try:
case Cav | Vex:
trace("cav or vex");
Hope it helps.
I have a menu option with two options: add and substract. When I choose one it runs ok but the program closes. I would like to know how to make it go back to the menu after an operation ends to select another one
package main
import (
"fmt"
)
func main() {
var n1, n2, s, r float64
var op, ns int
fmt.Println("\n\tWelcome")
fmt.Println("Chose an option")
fmt.Println("1.-Add")
fmt.Println("2.-Substract")
fmt.Scan(&op)
if op == 1 {
fmt.Printf("\n\tAdd")
fmt.Printf("\nHow many numbers you add? ")
fmt.Scan(&ns)
if ns <= 1 {
fmt.Print("You can not add just a number")
} else {
for i := 0; i < ns; i++ {
fmt.Printf("\nType the number %d: ", i+1)
fmt.Scan(&n1)
s += n1
}
fmt.Println("\nThe sum is: ", s)
//How to return to the menu?
}
} else if op == 2 {
fmt.Printf("\n\tSubtraction")
fmt.Printf("\nType the first number: ")
fmt.Scan(&n1)
fmt.Printf("\nType the second number: ")
fmt.Scan(&n2)
r = n1 - n2
fmt.Println("\nSubstraction is: ", r)
}
}
Just wrap the whole thing in
for {
}
Use break to exit the loop or continue to go back to the top.
It's hard to tell exactly without seeing your code, but I may assume you should use operator for ;; {} and put inside your menu with the appropriate if/else statements.