Christian Helbling
unread,Feb 9, 2021, 5:06:25 PM2/9/21Sign in to reply to author
Sign in to forward
You do not have permission to delete messages in this group
Sign in to report message
Either email addresses are anonymous for this group or you need the view member email addresses permission to view the original message
to juggling-interchange-format
Hi
As promised my thoughts about repetition and symmetries.
Be prepared, its gonna be long :)
And thanks a lot for your code, Lukas!
Looking forward to look into it.
First of all, I think repetition should be a feature rather than the default.
The reason for that is, that a complete show routine (or a part of it) could
already be written in jif using only jugglers, limbs and throws as properties.
A default repetition of that - i.e. jumping from the last catch time to time 0 -
seems unnatural to me as all the props from the end time would need to teleport
back instantly to where they started.
To enable repetition, we have to provide at least the period as a parameter.
Without any relabeling mechanism, this period can get really big and a lot of
throws need to be provided until all the limbs, props and jugglers are in their
starting configuration again. This can be seen by the current passist code
generating 36 throws from the 4-handed 975.
This is not handy for a lot of applications.
We want to have the natural period which is the siteswap/prechac length, the length
of a manipulation sequence until juggler relabeling, etc.
I suggest the following format for specifying repetition:
"repetition": {
"period": .. ,
"limbPermutation": [..],
"propPermutation": [..],
"jugglerPermutation": [..], # disputed :)
# .. more repetition features like rotation and translation of juggler positions
}
If a repetition is specified, only the period is mandatory (I think it cannot be guessed).
The rest should have sensible defaults (to be discussed).
Permutations are given as an array.
for example, [2, 0, 1] is short for
0 becomes 2
1 becomes 0
2 becomes 1
Let's look at a simple example: (6x,4)*
Without props the verbose version is this:
"period": 4,
"throws": [
{ "time": 0, "duration": 6, "from": 0, "to": 1, "label": "6x" },
{ "time": 0, "duration": 4, "from": 1, "to": 1, "label": "4" },
{ "time": 2, "duration": 6, "from": 1, "to": 0, "label": "6x" },
{ "time": 2, "duration": 4, "from": 0, "to": 0, "label": "4" }
]
Specifying that left and right should be swapped at every repetition we arrive at:
"throws": [
{ "time": 0, "duration": 6, "from": 0, "to": 1, "label": "6x" },
{ "time": 0, "duration": 4, "from": 1, "to": 1, "label": "4" },
],
"repetition": {
"period": 2,
"limbPermutation": [ 1, 0], # swapping left/right
}
If we take props into account, the verbose version is even longer:
"period": 12,
"throws": [
{ "time": 0, "duration": 6, "from": 0, "to": 1, "label": "6x", "prop": 0 },
{ "time": 0, "duration": 4, "from": 1, "to": 1, "label": "4", "prop": 1 },
{ "time": 2, "duration": 6, "from": 1, "to": 0, "label": "6x", "prop": 2 },
{ "time": 2, "duration": 4, "from": 0, "to": 0, "label": "4", "prop": 3 },
{ "time": 4, "duration": 6, "from": 0, "to": 1, "label": "6x", "prop": 4 },
{ "time": 4, "duration": 4, "from": 1, "to": 1, "label": "4", "prop": 1 },
{ "time": 6, "duration": 6, "from": 1, "to": 0, "label": "6x", "prop": 0 },
{ "time": 6, "duration": 4, "from": 0, "to": 0, "label": "4", "prop": 3 },
{ "time": 8, "duration": 6, "from": 0, "to": 1, "label": "6x", "prop": 2 },
{ "time": 8, "duration": 4, "from": 1, "to": 1, "label": "4", "prop": 1 },
{ "time": 10, "duration": 6, "from": 1, "to": 0, "label": "6x", "prop": 4 },
{ "time": 10, "duration": 4, "from": 0, "to": 0, "label": "4", "prop": 3 },
],
For a period of 2 we get the following prop transitions:
0 => 2
1 => 3
2 => 4
3 => 1
4 => 0
which can be compactly stored as the permutation [ 2, 3, 4, 1, 0 ], giving us:
"throws": [
{ "time": 0, "duration": 6, "from": 0, "to": 1, "label": "6x", "prop": 0 },
{ "time": 0, "duration": 4, "from": 1, "to": 1, "label": "4", "prop": 1 },
],
"repetition": {
"period": 2,
"limbPermutation": [ 1, 0], # exchanging left/right
"propPermutation": [ 2, 3, 4, 1, 0 ]
}
A quick note on props:
Many applications like causal diagram editors or jif generators won't care about
props and prop permutations at all. They should not need to specify them.
Luckily, they can be filled in by code.
If we include a few rules how this prop-filling code should behave, we can
probably arrive at deterministic prop ids.
"What reasons do we have to specifiy props in jif at all then?", you ask.
Well, if we have a lot of multiplexes, the prop-filling code might not
do what we want to express.
Another example, 4-handed 975 aka holy grail:
verbose version:
"period": 36,
"throws": [
{ "time": 0, "duration": 9, "from": 0, "to": 1, "label": "9", "prop": 0 },
{ "time": 1, "duration": 7, "from": 1, "to": 0, "label": "7", "prop": 1 },
{ "time": 2, "duration": 5, "from": 2, "to": 3, "label": "5", "prop": 2 },
{ "time": 3, "duration": 9, "from": 3, "to": 0, "label": "9", "prop": 3 },
{ "time": 4, "duration": 7, "from": 0, "to": 3, "label": "7", "prop": 4 },
{ "time": 5, "duration": 5, "from": 1, "to": 2, "label": "5", "prop": 5 },
{ "time": 6, "duration": 9, "from": 2, "to": 3, "label": "9", "prop": 6 },
{ "time": 7, "duration": 7, "from": 3, "to": 2, "label": "7", "prop": 2 },
{ "time": 8, "duration": 5, "from": 0, "to": 1, "label": "5", "prop": 1 },
{ "time": 9, "duration": 9, "from": 1, "to": 2, "label": "9", "prop": 0 },
{ "time": 10, "duration": 7, "from": 2, "to": 1, "label": "7", "prop": 5 },
{ "time": 11, "duration": 5, "from": 3, "to": 0, "label": "5", "prop": 4 },
{ "time": 12, "duration": 9, "from": 0, "to": 1, "label": "9", "prop": 3 },
{ "time": 13, "duration": 7, "from": 1, "to": 0, "label": "7", "prop": 1 },
{ "time": 14, "duration": 5, "from": 2, "to": 3, "label": "5", "prop": 2 },
{ "time": 15, "duration": 9, "from": 3, "to": 0, "label": "9", "prop": 6 },
{ "time": 16, "duration": 7, "from": 0, "to": 3, "label": "7", "prop": 4 },
{ "time": 17, "duration": 5, "from": 1, "to": 2, "label": "5", "prop": 5 },
{ "time": 18, "duration": 9, "from": 2, "to": 3, "label": "9", "prop": 0 },
{ "time": 19, "duration": 7, "from": 3, "to": 2, "label": "7", "prop": 2 },
{ "time": 20, "duration": 5, "from": 0, "to": 1, "label": "5", "prop": 1 },
{ "time": 21, "duration": 9, "from": 1, "to": 2, "label": "9", "prop": 3 },
{ "time": 22, "duration": 7, "from": 2, "to": 1, "label": "7", "prop": 5 },
{ "time": 23, "duration": 5, "from": 3, "to": 0, "label": "5", "prop": 4 },
{ "time": 24, "duration": 9, "from": 0, "to": 1, "label": "9", "prop": 6 },
{ "time": 25, "duration": 7, "from": 1, "to": 0, "label": "7", "prop": 1 },
{ "time": 26, "duration": 5, "from": 2, "to": 3, "label": "5", "prop": 2 },
{ "time": 27, "duration": 9, "from": 3, "to": 0, "label": "9", "prop": 0 },
{ "time": 28, "duration": 7, "from": 0, "to": 3, "label": "7", "prop": 4 },
{ "time": 29, "duration": 5, "from": 1, "to": 2, "label": "5", "prop": 5 },
{ "time": 30, "duration": 9, "from": 2, "to": 3, "label": "9", "prop": 3 },
{ "time": 31, "duration": 7, "from": 3, "to": 2, "label": "7", "prop": 2 },
{ "time": 32, "duration": 5, "from": 0, "to": 1, "label": "5", "prop": 1 },
{ "time": 33, "duration": 9, "from": 1, "to": 2, "label": "9", "prop": 6 },
{ "time": 34, "duration": 7, "from": 2, "to": 1, "label": "7", "prop": 5 },
{ "time": 35, "duration": 5, "from": 3, "to": 0, "label": "5", "prop": 4 }
]
the limbs shift through by one: 0 => 3 => 2 => 1 => 0
for the props, it helps to look at the orbits:
900 (3 props) (0->3->6->0)
075 (4 props) (1->4->2->5->1)
thus we arrive at the following compact jif:
"throws": [
{ "time": 0, "duration": 9, "from": 0, "to": 1, "label": "9", "prop": 0 },
{ "time": 1, "duration": 7, "from": 1, "to": 0, "label": "7", "prop": 1 },
{ "time": 2, "duration": 5, "from": 2, "to": 3, "label": "5", "prop": 2 }
],
"repetition": {
"period": 3,
"limbPermutation": [ 3, 0, 1, 2 ],
"propPermutation": [ 3, 4, 5, 6, 2, 1, 0 ]
}
Last one - swinging door:
"jugglers": [
{ "name": "A" },
{ "name": "B" }
],
"limbs": [
{ "juggler": 0, "type": "right hand" },
{ "juggler": 0, "type": "left hand" },
{ "juggler": 1, "type": "right hand" },
{ "juggler": 1, "type": "left hand" }
],
"throws": [
{ "time": 0, "duration": 4, "from": 0, "to": 3, "label": "4p straigt A->B", "prop": 0 },
{ "time": 0, "duration": 4, "from": 2, "to": 1, "label": "4p straigt B->A", "prop": 1 },
{ "time": 0, "duration": 4, "from": 1, "to": 0, "label": "4x A", "prop": 2 },
{ "time": 0, "duration": 4, "from": 3, "to": 2, "label": "4x B", "prop": 3 }
],
"repetition": {
"period": 2,
"limbPermutation": [ 1, 0, 3, 2 ], # exchanging left/right
"propPermutation": [ 4, 5, 6, 7, 3, 2, 0, 1 ]
}
We still need to check, if this approach works for the rest of our use-cases.
Manipulation patterns are quite interesting here.
jugglerPermutation seem quite natural for that.
This is the "becomes" property in lukas's examples, and also the lines like
A => B => C => M on manipulation workshop sheets.
As already stated on this list, limbPermutation is powerful enough
to fix the from/to of the throws.
Having both at the same time sure looks messy somehow.
In what order are they applied?
Why whould we need them both?
A simple reason to have an additional limbPermutation
in a manipulation pattern cold be an additional right/left swap,
in which case the order of applying the permutations wouldnt' matter.
But there could be valid reasons for more complicated limbPermutations.
Lets see what else an explicit or implicit jugglerPermutation would do exactly.
If we have:
"jugglers": [
{ "name": "Alice", "label": "A" },
{ "name": "Bob", "label": "B" }
{ "name": "Charlie", "label": "C" }
{ "name": "Mallory", "label": "M" }
],
"limbs": [
{ "juggler": 0, "type": "right hand" },
{ "juggler": 0, "type": "left hand" },
{ "juggler": 1, "type": "right hand" },
{ "juggler": 1, "type": "left hand" }
{ "juggler": 2, "type": "right hand" },
{ "juggler": 2, "type": "left hand" },
{ "juggler": 3, "type": "right hand" },
{ "juggler": 3, "type": "left hand" }
],
"repetition": {
"period": 6,
"jugglerPermutation": [ 1, 2, 3, 0 ], # A => B => C => M, explicity specified or implicit through limbPermutation
}
At time 6 Alice will stay Alice but gets the label B.
Her position will not jump somewhere else, but her movement
instructions for the second round change to B's instructions.
( it is not yet discussed how to represent movement instructions yet,
I can imagine something like
"movements": [
{"time": .., "duration": .., "juggler": .., ..movement instructions},
..
]
but I have not given much thought about that yet,
please discuss this in another thread :)
)
Alice inherits Bobs throws and catches, which can technicaly be done
by either permuting limbs (from/to of any throw point to a different limb)
or by permuting the jugglers (juggler of any limb points to a different juggler).
If we would go by the second option, right after time 6 we would get this:
"jugglers": [
{ "name": "Mallory", "label": "A" }
{ "name": "Alice", "label": "B" },
{ "name": "Bob", "label": "C" }
{ "name": "Charlie", "label": "M" }
],
with limbs staying the same.
So the jugglers array is permuted, except for the labels that stay at the same place.
This is a bit weird (but neccessary) and not covered directly if we would only have limbPermutation.
If there is an additional limbPermutation,
the limbs array is permuted as well.
for example,
"limbPermutation": [ 1, 0, 3, 2, 5, 4 ],
would yield:
"limbs": [
{ "juggler": 0, "type": "left hand" },
{ "juggler": 0, "type": "right hand" },
{ "juggler": 1, "type": "left hand" }
{ "juggler": 1, "type": "right hand" },
{ "juggler": 2, "type": "left hand" },
{ "juggler": 2, "type": "right hand" },
{ "juggler": 3, "type": "left hand" }
{ "juggler": 3, "type": "right hand" },
],
This way limbPermutation could live alongside jugglerPermutation, with a clearly defined
behavior but we would usually only need one of them.
But what about throws across repetition bounaries?
If we look at the first throw of the holy grail example,
{ "time": 0, "duration": 9, "from": 0, "to": 1, "label": "9", "prop": 0 },
we see that we evaluated the to-limb at time 0, that is at the throw time.
Let's say we use the same rule (evaulating at throw time) for going from limb to juggler.
Depending if by juggler we mean the juggler by name or the juggler by label,
we have Aiden's or Ed's notation.
I forgot which one is which, and I'm not sure which one we should prefer. Lukas?
In either case, an animator would have to schedule a throw of the involved prop
and be able to calculate the landing destination in advance.
@Co:
Thanks for the idea of different periods. I'll have to think about that.
Cheers
Christian