Skip to content

Guards, Inhibitors, and Capacity ​

Real systems operate under conditional rules and physical constraints: waiting rooms have limited seats, connection pools reject calls when exhausted, and batch tasks wait for prerequisites. Jupiter provides three mechanisms to model these constraints: guard conditions, inhibitor arcs, and capacity places.


Guard Conditions ​

A guard is a boolean expression evaluated on a transition. In addition to requiring sufficient tokens across all input places, the transition's guard expression must evaluate to true for the transition to fire.

Syntax ​

Guards inspect the instantaneous token count of places:

#Queue < 3
#Slots > 0
#IdleServers = 0

The # prefix followed by the place name (#PlaceName) retrieves the exact number of tokens in that place at the moment of evaluation.

Available Operators ​

TypeOperatorsMeaning
Comparison>, >=, <, <=, =, !=Greater, greater/equal, less, less/equal, equal, not equal
LogicalAND, OR, NOTConjunction, disjunction, and negation

Group expressions using parentheses:

(#Queue > 0) AND (#Worker = 0)
(#Slots > 0) AND NOT (#Maintenance > 0)
#Queue < MAX_CAPACITY

When to use guards ​

  • Multi-place conditions: When decisions depend on multiple places at once ((#Queue > 0) AND (#PowerOk > 0)).
  • Batch processing thresholds: Transitions that only fire when a minimum batch size is met (#Queue >= BATCH_SIZE).
  • Load-based routing: Splitting flows dynamically:
    • Transition A: #Queue > 10 (overflow path)
    • Transition B: #Queue <= 10 (normal path)

Avoid logical gaps

When splitting flows with guards, ensure all possible values are covered. If Transition A checks #Queue > 10 and Transition B checks #Queue < 10, the exact case #Queue = 10 has no valid path, permanently freezing tokens.


Inhibitor Arcs ​

An inhibitor arc prevents a transition from firing as long as the connected place holds tokens.

  • Visual symbol: A line terminating with a small circle (bubble) instead of an arrow.
  • Zero token consumption: It checks the presence of tokens without consuming them when the transition fires.

Multiplicity on Inhibitors ​

With multiplicity 1 (default), the inhibitor blocks firing if the place has 1 or more tokens.

With multiplicity $N$, it blocks firing only when the place holds $N$ or more tokens.

Inhibitor vs. Guard ​

For basic thresholds, both approaches produce identical simulation results:

ApproachImplementationMean queueThroughput
Inhibitor arc (weight 3)Visual arc with circle0.3550.0968
Guard #Queue < 3Expression inside transition0.3550.0968

Prefer inhibitor arcs for simple rules

Inhibitor arcs are directly visible on the canvas diagram. Anyone reviewing the model immediately understands the constraint. Guards remain hidden inside transition properties and can easily be overlooked.


Limiting Capacity with Slots ​

Real queues have finite capacity: 20 buffer slots, 50 seats, or 10 database connections.

The "One Token Per Slot" Pattern ​

To constrain capacity, add a place (e.g., Slots) initialized with the total capacity limit:

  1. The arrival transition consumes 1 token from Slots.
  2. The completion transition returns 1 token to Slots.
  3. When Slots reaches 0, the arrival transition loses its enabling condition and cannot fire until an item finishes and departs.
json
{
  "modelName": "Fila com sala de espera limitada",
  "definitions": [
    { "name": "TEMPO_ENTRE_CHEGADAS", "type": "DOUBLE", "value": "10" },
    { "name": "TEMPO_DE_ATENDIMENTO", "type": "DOUBLE", "value": "5" },
    { "name": "VAGAS", "type": "INTEGER", "value": "3" }
  ],
  "places": [
    { "name": "Vagas",         "initialMarking": 3, "stringMarking": "VAGAS", "initialStringMarking": "VAGAS" },
    { "name": "Fila",          "initialMarking": 0, "stringMarking": "0",     "initialStringMarking": "0" },
    { "name": "Atendente",     "initialMarking": 1, "stringMarking": "1",     "initialStringMarking": "1" },
    { "name": "EmAtendimento", "initialMarking": 0, "stringMarking": "0",     "initialStringMarking": "0" }
  ],
  "rewardMeasures": [
    { "name": "cheio_pct",   "expression": "P{#Vagas = 0} * 100" },
    { "name": "vazao",       "expression": "E{#EmAtendimento} / TEMPO_DE_ATENDIMENTO" },
    { "name": "no_sistema",  "expression": "E{#Fila} + E{#EmAtendimento}" },
    { "name": "vagas_livres","expression": "E{#Vagas}" }
  ],
  "transitions": [
    { "name": "Chegada", "type": "TIMED", "firingPolicy": "SINGLE_SERVER",
      "raceType": "RACE_WITH_ENABLING_MEMORY", "priority": 1,
      "distribution": { "type": "exponential", "parameters": { "Mean delay": "TEMPO_ENTRE_CHEGADAS" } },
      "inputArcs":  [{ "type": "INPUT",  "place": "Vagas", "multiplicity": 1 }],
      "outputArcs": [{ "type": "OUTPUT", "place": "Fila",  "multiplicity": 1 }],
      "inhibitorArcs": [] },
    { "name": "Inicio", "type": "IMMEDIATE", "firingPolicy": "SINGLE_SERVER",
      "raceType": "RACE_WITH_ENABLING_MEMORY", "priority": 1, "weight": 1,
      "inputArcs":  [{ "type": "INPUT", "place": "Fila", "multiplicity": 1 },
                     { "type": "INPUT", "place": "Atendente", "multiplicity": 1 }],
      "outputArcs": [{ "type": "OUTPUT", "place": "EmAtendimento", "multiplicity": 1 }],
      "inhibitorArcs": [] },
    { "name": "Fim", "type": "TIMED", "firingPolicy": "INFINITY_SERVER",
      "raceType": "RACE_WITH_ENABLING_MEMORY", "priority": 1,
      "distribution": { "type": "exponential", "parameters": { "Mean delay": "TEMPO_DE_ATENDIMENTO" } },
      "inputArcs":  [{ "type": "INPUT",  "place": "EmAtendimento", "multiplicity": 1 }],
      "outputArcs": [{ "type": "OUTPUT", "place": "Atendente", "multiplicity": 1 },
                     { "type": "OUTPUT", "place": "Vagas",     "multiplicity": 1 }],
      "inhibitorArcs": [] }
  ]
}

Exact timing of token return

A capacity token must return to Slots only when an item completes service and leaves the system. Returning it early allows the queue to overflow.

Trade-off Between Response Time and Rejections ​

Evaluating capacity on a queue with arrivals every 10 minutes and 5-minute service:

Slots% Time fullThroughputItems in systemResponse time
133.4%0.0670.335.0 min
214.3%0.0860.576.6 min
36.7%0.0930.737.9 min
51.6%0.0980.919.3 min
100.1%0.1001.0010.0 min

Three core insights:

  1. Low capacity degrades throughput: With only 1 slot, the system rejects 33% of arrivals and throughput drops from 0.10 to 0.067 items/min.
  2. Diminishing returns: Increasing from 1 to 3 slots drops rejections from 33.4% to 6.7%. Beyond 5 slots, gains are minimal.
  3. A short queue does not mean good service: With 1 slot, response time is only 5 minutes — but that is because a third of the workload was discarded!

Next steps ​

Learn how to configure multi-server concurrency in Parallelism and Servers.