How to rearrange blocks in a UML state diagram - uml

I just created a state diagram and right now I am struggling with the positions of the blocks. My goal is to have States 1,2,4,5 in a "down"-row and state 3 at the right from state 1.
See my UML code and the attached screenshot for the current (left) and wanted (right) design
UML Code:
#startuml diagramStackO
scale 400 width
[*] -down-> State1
State1 -down-> State2
State1 -right-> State3
State2 -up-> State3
State2 -down-> State4
State4 --> State5
State5 --> [*]
#enduml
Screenshot (left: current right: what it should look like)

My first advice would be to just ignore it and move on... Tweaking diagrams in PlantUML to get them "just right", even for little things, can take up a lot of time.
However, as someone who spends way too much time in getting their diagrams just right, there are two things that come to mind.
Using ortho
The first one is to just add skinparam linetype ortho. This is the least work but also gives the least improvment:
#startuml
skinparam linetype ortho
[*] -down-> State1
State1 -down-> State2
State1 -right-> State3
State2 -up-> State3
State2 -down-> State4
State4 --> State5
State5 --> [*]
#enduml
Using a hidden container
The other is adding a hidden container which a bit more work, but not too much, I think.
To get the vertical alignment that you want, the states need to be grouped together:
All we need to do now is hide the container:
The code I used to achieve this effect is:
#startuml
skinparam {
shadowing false
state {
BackgroundColor<<HIDDEN>> hidden
BorderColor<<HIDDEN>> hidden
}
}
state " " as _ <<HIDDEN>> {
state State1
state State2
state State4
state State5
}
[*] -down-> State1
State1 -down-> State2
State1 -right-> State3
State2 -right-> State3
State2 -down-> State4
State4 --> State5
State5 --> [*]
#enduml

Related

Why are multiple Alloy declarations not equivalent to nested Alloy declarations?

Page 293 of Software Abstractions says that these two are equivalent:
all x: X, y: Y | F
all x: X | all y: Y | F
but these two are not equivalent:
one x: X, y: Y | F
one x: X | one y: Y | F
Why are the latter two not equivalent?
I learn best with concrete examples, so let’s take a concrete example.
Last week I took a cruise to Alaska. At dinner I was seated with five other people. One of the couples (Jason and Denise) were celebrating their 25th (silver) wedding anniversary.
I created an Alloy model of the people at the dining table. The model specifies that there is one m: man, w: woman couple for which m's wife is w, w's husband is m, and m and w are celebrating a silver anniversary:
one m: Man, w: Woman |
m.wife = w and
w.husband = m and
m.anniversary = Silver and
w.anniversary = Silver
The instances that the Alloy Analyzer generated are what I expected.
Then I modified the expression to use nested expressions:
one m: Man |
one w: Woman |
m.wife = w and
w.husband = m and
m.anniversary = Silver and
w.anniversary = Silver
The Alloy Analyzer generated the same instances!
Next, I wrote an assertion, asserting that the two versions are equivalent:
Version1 iff Version2
The Alloy Analyzer returned: No counterexamples found!
Below is my model. Why are the two versions equivalent? Is there a small tweak that I could make to the model to show a difference between the nested version and the non-nested version?
Alloy Model of Roger's Dining Table on the Cruise to Alaska
abstract sig Man {
wife: lone Woman,
anniversary: lone Anniversary
}
one sig Roger extends Man {}
one sig Jason extends Man {}
abstract sig Woman {
husband: lone Man,
anniversary: lone Anniversary
}
one sig Faye extends Woman {}
one sig Nina extends Woman {}
one sig Claudia extends Woman {}
one sig Denise extends Woman {}
abstract sig Anniversary {}
one sig Silver extends Anniversary {}
pred v1_One_couple_celebrating_25th_wedding_anniversary {
one m: Man, w: Woman | m.wife = w and w.husband = m and
m.anniversary = Silver and w.anniversary = Silver }
pred v2_One_couple_celebrating_25th_wedding_anniversary {
one m: Man |
one w: Woman |
m.wife = w and w.husband = m and
m.anniversary = Silver and w.anniversary = Silver }
assert Both_versions_are_identical {
v1_One_couple_celebrating_25th_wedding_anniversary
iff
v2_One_couple_celebrating_25th_wedding_anniversary
}
check Both_versions_are_identical
You may run these examples to see the difference:
sig Man {}
sig Woman {
// married is a relation Woman set -> set Man
married : set Man
}
// there is exactly one married couple
run { one w : Woman, m : Man | w->m in married } for 5
// there is exactly one woman that has exactly one husband;
// apart from that, several men may share a wife, and vice-versa
run { one w : Woman | one m : Man | w->m in married } for 5
The predicate is too constraining for there to be a difference.
The difference between the nested version and the non-nested version can be seen if the example is modified a bit: Allow each man to be married to a set of women:
sig Man {
wives: set Woman
}
Loosen the constraint to this: w in m.wives
Here is the new, non-nested version:
one m: Man, w: Woman |
w in m.wives and
w.husband = m and
w.anniversary = Silver
That says there is exactly one m: Man, w: Woman for which w is one of m's wives, w's husband is m, and m and w are celebrating a silver anniversary.
Here’s one of the instances that the Alloy Analyzer generates: Man1 has wives Woman1 and Woman2. Woman1 has husband Man1. Likewise, Woman2 has husband Man1. Woman1 is celebrating a 25th wedding anniversary with her husband (Man1).
Here is the nested version:
one m: Man |
one w: Woman |
w in m.wives and
w.husband = m and
w.anniversary = Silver
That says there is exactly one m: Man for which the constraint is true, where the constraint is this: there is one woman for which the woman is the man’s wife and they have been married 25 years. There can be another man for which the constraint is true.
Here’s one of the instances that the Alloy Analyzer generates: Man1 has wives Woman0 and Woman1. Man1 and Woman1 have been married 25 years. Man2 has wife Woman2. They have been married 25 years.
Below is the Alloy model.
Alloy Model of Men Married to Multiple Wives
sig Man {
wives: set Woman
}
sig Woman {
husband: lone Man,
anniversary: lone Anniversary
}
abstract sig Anniversary {}
one sig Silver extends Anniversary {}
pred v1_One_couple_celebrating_25th_wedding_anniversary {
one m: Man, w: Woman | w in m.wives and w.husband = m and
w.anniversary = Silver
}
pred v2_One_couple_celebrating_25th_wedding_anniversary {
one m: Man |
one w: Woman |
w in m.wives and w.husband = m and w.anniversary = Silver
}
assert Both_versions_are_identical {
v1_One_couple_celebrating_25th_wedding_anniversary
iff
v2_One_couple_celebrating_25th_wedding_anniversary
}
check Both_versions_are_identical

How do relation multiplicities work?

I'm using this simple model and the evaluator to study relation multiplicities. The evaluator dialogue demonstrates a situation that I find puzzling.
sig A {}
sig B {}
pred show {}
run show
Evaluator dialogue:
univ
{A$0, A$1, B$0, B$1, B$2}
B->A
{B$0->A$0, B$0->A$1, B$1->A$0, B$1->A$1, B$2->A$0, B$2->A$1}
B lone -> A
{B$0->A$0, B$0->A$1, B$1->A$0, B$1->A$1, B$2->A$0, B$2->A$1}
// Although the two relations seem to be identical,
B->A in B->A
true
// but
B->A in B lone -> A
false
What makes the two products different in answering 'B->A in B->A' and 'B->A in B lone -> A'?

Can the type checker help me out here? With type families, maybe?

So I'm writing this little soccer game for some time now, and there's one thing that bugs me from the very beginning. The game follows the Yampa Arcade pattern, so there's a sum type for the "objects" in the game:
data ObjState = Ball Id Pos Velo
| Player Id Team Number Pos Velo
| Game Id Score
Objects react to messages, so there's another sum type:
data Msg = BallMsg BM
| PlayerMsg PM
| GameMsg GM
data BM = Gained | Lost
data PM = GoTo Position | Shoot
data GM = GoalScored | BallOutOfBounds
The Yampa framework relies on so-called signal functions. In our case, there are signal functions for ball, player and game behaviour. Crudely simplified:
ballObj, playerObj, gameObj :: (Time -> (GameInput, [Msg]))
-> (Time -> (ObjState, [(Id, Msg)]))
So e.g. ballObj takes a function that yields the GameInput (key strokes, game state, ...) and a list of messages specifically for the ball at any given time, and returns a function that yields the ball's state and it's messages to other objects (ball, game, players) at any given time. In Yampa, the type signature actually looks a little nicer:
ballObj, playerObj, gameObj :: SF (GameInput, [Msg]) (ObjState, [(Id, Msg)])
This uniform type signature is important for the Yampa framework: (again, very crudely simplified) it builds a big signal function from a list of 11 + 11 (players) + 1 (ball) + 1 (game) signal functions with the same type (via dpSwitch) that it then runs (via reactimate).
So now, what bugs me: It only makes sense to send a BallMsg to a Ball, or a PlayerMsg to a Player. If ever someone sends for instance a GameMsg to a Ball, the program will crash. Isn't there a way to get the type checker in position to avoid this? I recently read this nice Pokemon post on type families, and it seems like there is some analogy. So maybe this might be a starting point:
class Receiver a where
Msg a :: *
putAddress :: Msg a -> a -> Msg a
data BallObj = ...
data GameObj = ...
data PlayerObj = ...
instance Receiver BallObj where
Msg BallObj = Gained | Lost
(...)
Now, the SF function might look something like this:
forall b . (Receiver a, Receiver b) => SF (GameInput, [Msg a]) (a, [(b, Msg b)])
Will this get me anywhere?
Skimming the yampa arcade paper it seems like you have a route function drawn from their example.
My suggestion would be you alter route so it doesn't take a single list of objects, but instead a single game object, a single ball object, and a collection of player objects. Then have
data BallMsg = ...
data PlayerMsg = ...
data GameMsg = ...
data AnyMsg = ABallMsg BallMsg
| APlayerMsg PlayerMsg
| AGameMsg GameMsg
Now route works on a uniform AnyMsg but it dispatches them to the right destination depending on their contents.
Straight from the first glance one major problem with your design stands out: you unite completely different entities Ball, Player and Game under a single type. If you need a union type over those entities, go the same way you have with the messages by making them separate types, i.e.:
data AnyObject = AnyObjectBall Ball
| AnyObjectPlayer Player
| AnyObjectGame Game
This way you'll be able to express both the specific functions (Ball -> BallMsg -> ...) and general ones (AnyObject -> AnyMsg -> ...).
But if I understand your problem correctly, I think I have a solution for you which does not require union types:
class Signal object message where
signal :: SF (GameInput, [message]) (object, [(Id, message)])
data Ball = Ball Id Pos Velo
data BallMsg = BallMsgGained | BallMsgLost
instance Signal Ball BallMsg where
-- ...
-- so on for Player and Game

How to align blocks in PlantUML class diagrams?

I am using PlantUML to make simple class diagrams and the tool is awesome, but I couldn't find any way to align classes with each other except putting them into packages or using relationships like Alice -left-* Bob. What I need is something like:
#startuml
class Bob
class Alice
class Dan
**Dan aligned Alice: horizontally**
'or using a grid?
**Bob at grid (2, 3)**
#enduml
Is there a way?
UPDATES Aug.08.2019
From Rotsiser's comment, by combining changing the length of lines with together keyword, it can align elements
#startuml
class A
A ..> B
C ---> B
D ...> B
together {
class E
class F
class G
}
E ----> B
#enduml
OUTDATED
You are able to align elements by changing the number of line's character, such as '-', '.', and so on.
#startuml
class A
A ..> B
C ---> B
D ...> B
E ----> B
F ----> B
G ----> B
#enduml
Using a -[hidden] relation can do the job :
#startuml
class Bob
class Alice
class Dan
class Foo
class Bar
class Foobar
Bob -[hidden] Alice
Bar -[hidden] Foobar
#enduml
No, there's no way to do that, sorry :( The idea behind PlantUML is that you should not care too much about the layout rendering.
Actually, early versions of PlantUML use to align classes, but it was an issue: When there were many unrelated classes, diagrams tended to be very large and very thin. So a patch was added to organize classes in a square.
How many classes do you want to have in your diagram? Sure it would be possible to disable the organizing patch for e.g. 3 to 5 classes. You could post a suggestion to the forum to see what other users think about it.
Here is a solution.
The documentation:
"It is also possible to change arrow direction by adding left, right, up or down keywords inside the arrow:"
#startuml
foo -left-> dummyLeft
foo -right-> dummyRight
foo -up-> dummyUp
foo -down-> dummyDown
#enduml
To your question:
#startuml
class Bob
class Alice
class Dan
Alice -left[hidden]-> Bob
Alice -right[hidden]-> Dan
#enduml
It may also be useful:
#startuml
class Bob
class Alice
class Dan
Bob -right-|> Alice
Alice -right-> Dan
interface Friend
Dan -up..> Friend
interface Person
Friend -left-> Person
interface Object
Person -down-> Object
interface Native
Object -right-> Native
#enduml
You don't need a hidden package, use the together keyword:
together {
class A
class B
}
A cleaner approach is to put them in a hidden package, which is more logical.
#startuml
skinparam shadowing false
skinparam package<<Layout>> {
borderColor Transparent
backgroundColor Transparent
fontColor Transparent
stereotypeFontColor Transparent
}
package x <<Layout>>{
class A
class B
}
A .. D
B .. C
C .. D
A1 .. D1
B1 .. C1
C1 .. D1
#end

How can one express that a relationship must not be cyclic?

Consider a upgrades relationship:
I need to make sure that upgrades cannot be circular. How can I do that in Alloy?
It is sufficient to enforce transitivity and antireflexivity.
fact {
no a: Item | a in a.upgrades
}
fact{
all a,b,c: Item |
a in b.upgrades and b in c.upgrades implies
a in c.upgrades
}
From your example, I infer that the upgrades relation is not intended to be transitive: in the example, a diamond sword upgrades a stone sword, and a stone sword upgrades a wooden sword, but the pair WoodSword -> DiamondSword is not in the upgrades relation.
So what you want to say is something like
fact upgrades_acyclic {
no x : univ | x in x.^upgrades
}
Some modelers prefer the more succinct formulation in terms of relations:
fact upgrades_acyclic { no ^upgrades & iden }

Resources