The ReLang Handbook
Everything you need to model, simulate, verify and train Reconfigurable Probabilistic Automata. From your first state to advanced PDL formulae.
What is ReLang?
ReLang is the modelling language of the RePA Tool. It lets you describe a probabilistic system as a set of states connected by transitions, each carrying a probability weight. On top of that you can add hyper-edges (rules) that dynamically change those weights at runtime — making the system reconfigurable.
Probabilistic
Every outgoing transition from a state carries a weight. Together they sum to 1.
Reconfigurable
Hyper-edges allow transitions to activate, deactivate, or modify each other's weights live.
Guarded
Any edge can carry an if (condition) guard evaluated at runtime.
Verifiable
Full PDL and probabilistic PCTL verification built in, with animation playback.
File Structure
A .Re / .rta file is plain text. The order of declarations is flexible — but the recommended layout is shown below.
// 1. Optional model name (stripped by the engine) name MyModel // 2. Global settings paradigm probabilistic calibration normalize training laplace // 3. Variable declarations int counter = 0 float rate = 0.5 bool flag = false // 4. Initial state init start // 5. Transitions start ---> end : doIt (1.0) // 6. Hyper-edges (rules) doIt ->> doIt : selfBuff (0.8)
Global Settings
paradigm
Controls how weights are interpreted.
| Value | Description |
|---|---|
| probabilistic | Weights are probabilities; outgoing edges from a state must sum to 1 (default). |
| fuzzy | Weights are membership degrees [0,1]; no normalisation enforced. Rule effects use min/max logic. |
calibration
How remaining probability is redistributed when a rule changes a weight.
| Value | Behaviour |
|---|---|
| normalize | All other active edges are scaled proportionally so the total remains 1 (default). |
| proportional | The remainder is shared in proportion to the unmodified edges' original weights. |
| equal | The remainder is shared equally across unmodified edges. |
| revise_equal | The remainder/excess is shared equally across all active edges, including the modified one. |
training
Activates statistical learning from event sequences.
training // Laplace smoothing (default) training laplace // Explicit Laplace training aggregation arith (0.9) // Aggregation with lambda
Transitions & Edges
A transition moves the system from one state to another when fired. The canonical syntax is:
Arrow styles
| Arrow | Meaning |
|---|---|
| ---> | Standard transition (shorthand, auto-ID = label) |
| -transId-> | Transition with an explicit transId distinct from the label |
| -transId-> | Same as above with named identifier for referencing |
s0 -step-> s1 : myLabel, the edge has transId = step and label = myLabel. Using ---> makes both equal. The label is what rules target; the transId is used for Cytoscape IDs.
Basic examples
// Minimal: no weight → defaults to 1.0, then normalised s0 ---> s1 : go // Explicit weight s0 ---> s1 : go (0.7) s0 ---> s2 : stay (0.3) // With named transId s0 -t1-> s1 : myAction (0.5) // Starts disabled (inactive until a rule enables it) s0 ---> s1 : secret (0.5) disabled // Self-loop s0 ---> s0 : idle (1.0)
Weights
Weights are floating-point values in [0.0, 1.0]. The engine automatically normalises outgoing active edges from a state at load time so they sum to 1. If you provide unnormalised values (e.g. all edges with weight 1.0), the engine will divide them evenly.
Aggregation types
Used when a hyper-edge modifies a weight. The aggregation determines how the new weight is computed from the trigger weight wS, the rule weight wR, and the target's current weight wT.
| Keyword | Formula | Effect |
|---|---|---|
| arith | (wS + wR + wT) / 3 | Average — gentle (default) |
| prod | wS × wR × wT | Product — strong suppression |
| max | max(wS, wR, wT) | Takes the maximum — buff-dominant |
| min | min(wS, wR, wT) | Takes the minimum — debuff-dominant |
| geom | (wS × wR × wT)^(1/3) | Geometric mean — balanced |
// Edge declared with aggregation keyword s0 ---> s1 : boost (0.8) max // Rule also carries its own aggregation boost ->> otherAction : buffRule (0.9) prod
Hyper-Edges (Rules)
Rules are edges between labels, not states. When the source label fires, the rule's effect is applied to the target label.
| Arrow | Name | Effect |
|---|---|---|
| ->> | Activation / Buff | Applies aggregation to increase the target edge's weight, or activates a disabled edge. |
| --! | Negation / Debuff | Applies aggregation to decrease the target edge's weight, or deactivates an active edge. |
| --x | Negation (alias) | Same as --! |
Syntax
// Every time 'like' fires, it increases 'watchAgain' weight like ->> watchAgain : like_boost (0.9) max // Every time 'skip' fires, it suppresses 'watchAgain' skip --! watchAgain : skip_debuff (0.1) prod // Rule only fires if a variable condition is met login ->> premiumOffer : showOffer (0.8) if (userTier >= 2) // Rule that also updates a variable purchase ->> upsell : upsellRule (0.7) if (cart > 0) then { revenue' := revenue + 1 } // Short form — no explicit rule label (auto-generated) eventA --! eventA (0.05)
a ->> b and b ->> c, firing a will cascade through b and reach c. The engine detects cycles and stops.
Variables & Types
Scalar types
int count = 0 // integer, default 0 int level[0..10] = 1 // bounded integer [min..max] float ratio = 0.5 float prob[0.0..1.0] = 1.0 bool isActive = false
Arrays
// Static array int[] scores = [10, 20, 30] // Dynamic array (grows when you assign to index == length) dyn int[] log = [] // Dynamic with max size dyn int[] recent [max=5] = [] // keeps only last 5 items // Access in an expression x' := scores[1] // x = 20 // Write with ArrayAssign scores[0]' := 99 // scores becomes [99, 20, 30]
Conditions (Guards)
A guard is an if (...) clause attached to any edge or rule. The transition only fires if the condition is true in the current state.
Comparison operators
| Operator | Meaning |
|---|---|
| == | Equal (also accepted as =) |
| != | Not equal |
| < | Less than |
| <= | Less than or equal |
| > | Greater than |
| >= | Greater than or equal |
Logical connectives
| Keyword | Symbol | Meaning |
|---|---|---|
| AND | && | Both conditions must hold |
| OR | || | At least one must hold |
Weight check
You can guard on the current probability of an edge using P(label) or F(label):
// Fire only if 'attack' has probability >= 0.6 idle ---> alert : warn if (P(attack) >= 0.6) // Fire only if the failure probability F(action) is low idle ---> safe : proceed if (F(fail) < 0.1)
Examples
// Simple guard s0 ---> s1 : step if (counter < 5) // Compound guard s0 ---> s2 : jump if (flag == true AND score >= 10) // Guard with then-block s0 ---> s1 : advance if (n < 3) then { n' := n + 1 }
Updates (Side Effects)
When a transition fires, it can update variables. Updates appear in a then { ... } block, or inline for a single assignment.
Assignment
// Inline (no then-block needed for a single statement) s0 ---> s1 : pay total' := total + 10 // then-block for multiple statements s0 ---> s1 : buy then { balance' := balance - 5 items' := items + 1 } // Nested if inside then s0 ---> s1 : check then { if (score > 50) then { grade' := 1 } }
Math expressions
| Operator | Meaning |
|---|---|
| + | Addition |
| - | Subtraction |
| * | Multiplication |
| / | Integer or float division |
Print statement
print(counter) // prints value to browser console print(score * 2) // expression is evaluated first
Functions
You can define reusable functions and call them inside expressions or updates.
// Define a function def clamp(x, lo, hi) { if (x < lo) then { return lo } if (x > hi) then { return hi } return x } // Use in an update s0 ---> s1 : adjust then { volume' := clamp(volume + 10, 0, 100) } // foreach loop (works on arrays) def sumArr(arr) { total' := 0 foreach (item in arr) { total' := total + item } return total }
Modules — aut
The aut keyword creates a named sub-automaton. State and label names inside are automatically prefixed, so there are no name collisions between modules.
aut RobotA { init idle idle ---> working : start (1.0) working ---> idle : stop (1.0) } aut RobotB { init idle idle ---> busy : start (1.0) busy ---> idle : done (1.0) } // Cross-module rule: RobotA's 'start' enables RobotB's 'start' RobotA.start ->> RobotB.start : sync (0.8)
PDL Verification
The PDL (Probabilistic Dynamic Logic) verifier checks logical properties of your model starting from any state. Results include a boolean verdict or a quantitative probability.
Propositional connectives
State & condition propositions
counter == 3 // variable condition
flag == true
Modal operators
| Formula | Meaning |
|---|---|
| <> φ | Diamond: some next state satisfies φ |
| [] φ | Box: all next states satisfy φ |
| <α> φ | After program α there exists a state satisfying φ |
| [α] φ | After program α all reachable states satisfy φ |
PDL programs (α)
| Syntax | Meaning |
|---|---|
| actionName | Fire this action once |
| a ; b | Sequence: fire a then b |
| a + b | Choice: fire a or b |
| a* | Kleene star: repeat a zero or more times |
Probabilistic path operators
| Formula | Meaning |
|---|---|
| { P>=0.9 [ F φ ] } | Probability of eventually reaching φ is ≥ 0.9 |
| { P=? [ F φ ] } | What is the exact probability of eventually reaching φ? |
| { P=? [ G φ ] } | What is the probability of φ holding globally? |
| { P=? [ X φ ] } | Probability of φ at the next step |
| { P=? [ X X φ ] } | Probability of φ after exactly 2 steps |
| { P=? [ φ U ψ ] } | Probability that φ holds until ψ is reached |
| { P=? <α> φ } | Probability of reaching φ after program α |
PDL examples
// Can we reach state 'win'? <> win // Is it true that every next step goes to 'safe'? [] safe // After firing 'attack', can we reach 'dead'? <attack> dead // No matter how we fire 'move', we stay in 'valid'? [move*] valid
// What is the probability of eventually reaching 'goal'? P=? [ F goal ] // Is the probability of failing globally below 5%? P<0.05 [ G !fail ] // Probability of reaching 'win' within exactly 3 steps P=? [ X X X win ] // Probability that 'idle' holds until 'working' is reached P=? [ idle U working ]
// After firing 'a' then 'b', is 'target' reachable? <a ; b> target // After choosing between 'left' or 'right', reach 'exit' <left + right> exit // After any number of 'loop' firings, is 'done' reachable? <loop*> done // Probability of reaching 'end' via the sequence P=? <step ; step ; step> end
// Is the variable counter == 5 eventually reachable? P=? [ F counter == 5 ] // Does every reachable state keep score >= 0? [] score >= 0 // Combination: in state 'end' with total > 100 end && total > 100 // Is there a path where flag becomes true? P=? [ F flag == true ]
PCTL / PRISM Export Advanced
RePA can export your model to PRISM-compatible DTMC format and evaluate PCTL properties directly from the PCTL tab. The PRISM property language is a superset of what you type in the PDL panel.
PCTL syntax reference
| Syntax | Meaning |
|---|---|
| P=? [ F s=3 ] | Probability of reaching state ID 3 |
| P>=0.9 [ F goal ] | Is probability of reaching goal ≥ 0.9? |
| P=? [ G safe ] | Probability of always being in safe |
| P=? [ X s=2 ] | Probability of next state being 2 |
| P=? [ a U b ] | Probability of a holding until b |
| action_act=1 | Tests if action is currently enabled (in PRISM export) |
| action_act=0 | Tests if action is currently disabled |
PCTL property file example
// What is the probability of eventually reaching 'Delivered'? P=? [ F Delivered ] // Is it almost certain we avoid 'Crashed'? P>=0.99 [ G !Crashed ] // Is it always the case that 'go_work' can be activated? P=? [ F go_work_act=1 ] // Probability of reaching success in exactly 2 steps P=? [ X X success ]
.pm model, then paste your .pctl properties into PRISM for full model checking. Alternatively, the built-in PCTL tab runs properties directly without leaving the browser.
Path Optimizer
The Path tab in the bottom panel uses a best-first search to find either the most probable or least probable path to a target.
| Option | Values |
|---|---|
| Search Type | Reach State — pick a destination state. Variable Value — find when a variable equals a given integer. |
| Criterion | Max Probability (most likely path) or Min Probability (rarest path). |
Results show the sequence of labels fired and the cumulative probability of that path.
Statistical Training
Feed event-log data to the model and its weights will be updated automatically using empirical frequency or aggregation rules.
Input format
Each line is one session. Events within a session are comma-separated label names.
// File: sessions.txt buy, checkout, pay browse, buy, browse, exit login, buy, pay
Training modes
| Mode | Behaviour |
|---|---|
| laplace | Bayesian frequency estimation. Each firing of an edge increments a counter; weight = hits / total, with a Laplace prior of 50 virtual samples to avoid cold-start extremes. |
| aggregation arith (λ) | Each firing applies the aggregation formula to update the weight. λ controls the learning rate. |
Persistent vs reset mode
By default each session in the file is replayed from the initial state (reset). If your model uses persistent mode, the state carries over between sessions.
Sync weights to editor
After training, click Sync Weights → Editor to write the learned weights back into your source code. You can then save and re-use the calibrated model.
Complete Model Examples
1. Simple two-state loop
A minimal model: one initial state, one transition out and one back, with a self-activating rule.
init s0 s0 ---> s1 : a s1 ---> s0 : b // Every time 'a' fires it deactivates itself a --! a : offA
2. Vending machine with dynamic stock
int stock = 3 init Idle Idle ---> Selecting : insertCoin Selecting ---> Idle : buyItem (0.7) if (stock > 0) then { stock' := stock - 1 } Selecting ---> Idle : cancel (0.3) // When stock reaches 0, buyItem disables itself buyItem --! buyItem : outOfStock (0.1) if (stock == 0)
3. Recommendation algorithm
calibration proportional init Feed Feed ---> Watch : watch Watch ---> Watch : like Watch ---> Feed : dontLike Watch ---> Feed : refresh disabled Feed ---> List : watchLike disabled List ---> Watch : watch2 // Rules watch ->> dontLike : wd like --! dontLike : ld like ->> refresh : lr like ->> watchLike : lw dontLike --! watchLike : dw
4. Biased coin over time
calibration proportional int flips = 0 int side = 0 init toss toss ---> toss : heads (0.5) if (flips < 10) then { flips' := flips + 1 side' := 0 } toss ---> toss : tails (0.5) if (flips < 10) then { flips' := flips + 1 side' := 1 } // Bias: each heads makes the next heads more likely heads ->> heads : bias (0.9) max
5. Drone delivery with failure recovery
init Home Home ---> Flying : launch (1.0) Flying ---> Delivered : success (0.8) Flying ---> Crashed : fail (0.2) Delivered ---> Home : return (1.0) // On failure, recovery re-enables the return path fail ->> return (1.0) // Useful PDL queries for this model: // What is the probability of eventual delivery? { P=? [ F Delivered ] } // Can we always recover from a crash? [] !Crashed || <> Home
6. Multi-module robotic system
aut ArmA { init rest rest ---> grip : pickup (0.9) grip ---> rest : drop (1.0) } aut ArmB { init rest rest ---> place : insert (1.0) disabled place ---> rest : release (1.0) } // ArmA's drop enables ArmB's insert ArmA.drop ->> ArmB.insert : handoff (1.0) // ArmB's release disables insert again ArmB.release --! ArmB.insert : reset (1.0)
Quick Reference Card
Declaration keywords
| Keyword | Example | Meaning |
|---|---|---|
| name | name MyModel | Model identifier (optional) |
| paradigm | paradigm fuzzy | probabilistic or fuzzy |
| calibration | calibration equal | normalize / equal / proportional |
| training | training laplace | Enable statistical learning |
| init | init s0 | Set initial state |
| int | int x = 0 | Integer variable |
| float | float r = 0.5 | Float variable |
| bool | bool ok = true | Boolean variable |
| dyn int[] | dyn int[] q = [] | Dynamic array |
| def | def f(x) { ... } | Function definition |
| aut | aut Worker { ... } | Module / sub-automaton |
Edge arrows
| Arrow | Type | Usage |
|---|---|---|
| ---> | Standard | Simple transition |
| -id-> | Named | Transition with explicit transId |
| ->> | Rule ON | Hyper-edge: activate / buff target |
| --! | Rule OFF | Hyper-edge: deactivate / debuff target |
| --x | Rule OFF | Alias for --! |
PDL formula cheatsheet
| Formula | Reads as |
|---|---|
| <> φ | Some next state satisfies φ |
| [] φ | All next states satisfy φ |
| <a> φ | Fire a, then some state satisfies φ |
| [a] φ | Fire a, then all states satisfy φ |
| <a*> φ | Fire a zero or more times to reach φ |
| { P=? [ F φ ] } | Probability of eventually reaching φ |
| { P=? [ G φ ] } | Probability of φ holding always |
| { P=? [ X φ ] } | Probability of φ at next step |
| { P=? [ φ U ψ ] } | Probability of φ until ψ |
| { P>=0.9 [ F φ ] } | Is prob of reaching φ at least 90%? |