lang.workflow
- class WorkflowActivity
Bases:
ElementA computational activity in a Workflow.
WorkflowActivity represents a stage of computation in a standalone workflow model. Unlike Activity in LayeredNetwork, it carries no call list: an external call is represented as an activity whose host demand is the law of the call response time, so that a synchronous call and a local computation compose in the same way. An asynchronous call blocks the caller for no time and is simply left out of the workflow.
Each activity has a service time distribution that can be any phase-type compatible distribution (Exp, Erlang, APH, HyperExp, etc.).
Copyright (c) 2012-2026, Imperial College London All rights reserved.
- Constructor Summary
- WorkflowActivity(workflow, name, hostDemand)
WORKFLOWACTIVITY Create a workflow activity
OBJ = WORKFLOWACTIVITY(WORKFLOW, NAME, HOSTDEMAND)
- Parameters:
workflow - Parent Workflow object
name - Activity name (string)
hostDemand - Service time distribution or numeric mean
If hostDemand is numeric, it is treated as the mean of an exponential distribution.
- Property Summary
- hostDemand
Distribution object (Exp, APH, Erlang, etc.)
- hostDemandMean
double - mean service time
- hostDemandSCV
double - squared coefficient of variation
- index
Index in the workflow’s activity list
- metadata
Optional struct for external metadata (e.g., WfCommons)
- workflow
Reference to parent Workflow
- Method Summary
- getNumberOfPhases()
GETNUMBEROFPHASES Get the number of phases
N = GETNUMBEROFPHASES(OBJ)
Returns the number of phases in the PH representation.
- getPHRepresentation()
GETPHREPRESENTATION Get the phase-type representation
[ALPHA, T] = GETPHREPRESENTATION(OBJ)
- Returns:
alpha - Initial probability vector (1 x n) T - Subgenerator matrix (n x n)
For Markovian distributions, extracts the PH representation. For other distributions, fits an APH from the first two moments.
- setHostDemand(hostDemand)
SETHOSTDEMAND Set the service time distribution
OBJ = SETHOSTDEMAND(OBJ, HOSTDEMAND)
- Parameters:
hostDemand - Distribution object or numeric mean
- setHostDemandMean(meanValue)
SETHOSTDEMANDMEAN Change the mean, preserving the shape
OBJ = SETHOSTDEMANDMEAN(OBJ, MEANVALUE)
Scales the current law in time rather than refitting it, so the SCV, the skewness and the order are preserved and the cached series-parallel tree keeps its shape. Falls back to a plain exponential when the current law has no usable mean.
- class Workflow
Bases:
ModelWorkflow - A computational workflow that can be converted to a PH distribution.
Workflow allows declaring computational workflows using the same activity graph syntax as LayeredNetwork. The workflow can then be converted to an equivalent phase-type (PH) distribution via explicit CTMC construction.
- Supported precedence patterns:
Serial: Sequential execution
AndFork/AndJoin: Parallel execution with synchronization
OrFork/OrJoin: Probabilistic branching
Loop: Geometric repetition, with the same semantics as the LayeredNetwork POST_LOOP precedence: the loop body is executed a geometric number of times of mean COUNT when COUNT>=1, and is executed at most once, with probability COUNT, when COUNT<1
A workflow whose precedence graph is series-parallel is reduced exactly, by recursive composition of the series-parallel tree; the reduction handles arbitrary nesting (a fork inside a loop, a branch of a fork that is itself a fork-join). Graphs that are not series-parallel fall back to the block-based composition, which is a heuristic.
Activities model both local computation and, when the workflow stands for an LQN entry, a synchronous call: the call is an activity whose host demand is the fitted call-response law. Asynchronous calls contribute no time and are simply omitted by the builder.
Example
wf = Workflow(‘myWorkflow’); A = wf.addActivity(‘A’, Exp.fitMean(1.0)); B = wf.addActivity(‘B’, Exp.fitMean(2.0)); wf.addPrecedence(Workflow.Serial(A, B)); ph = wf.toPH();
Copyright (c) 2012-2026, Imperial College London All rights reserved.
- Constructor Summary
- Workflow(name)
WORKFLOW Create a new Workflow instance
SELF = WORKFLOW(NAME)
- Parameters:
name - Name for the workflow
- Property Summary
- activities
Cell array of WorkflowActivity objects
- activityMap
Map from activity name to index
- precedences
Array of ActivityPrecedence objects
- Method Summary
- static AndFork(preAct, postActs)
ANDFORK Create AND-fork precedence
AP = WORKFLOW.ANDFORK(PREACT, {POSTACT1, POSTACT2, …})
- static AndJoin(preActs, postAct, quorum)
ANDJOIN Create AND-join precedence
AP = WORKFLOW.ANDJOIN({PREACT1, PREACT2, …}, POSTACT) AP = WORKFLOW.ANDJOIN({PREACT1, PREACT2, …}, POSTACT, QUORUM)
- static Loop(preAct, postActs, counts)
LOOP Create loop precedence
AP = WORKFLOW.LOOP(PREACT, {LOOPACT, ENDACT}, COUNT) AP = WORKFLOW.LOOP(PREACT, LOOPACT, ENDACT, COUNT)
- static OrFork(preAct, postActs, probs)
ORFORK Create OR-fork (probabilistic) precedence
AP = WORKFLOW.ORFORK(PREACT, {POSTACT1, POSTACT2, …}, [P1, P2, …])
- static OrJoin(preActs, postAct)
ORJOIN Create OR-join precedence
AP = WORKFLOW.ORJOIN({PREACT1, PREACT2, …}, POSTACT)
- static Serial(varargin)
SERIAL Create serial precedence
AP = WORKFLOW.SERIAL(A1, A2, …)
- static Xor(preAct, postActs, probs)
XOR Create XOR precedence (alias for OrFork)
AP = WORKFLOW.XOR(PREACT, {POSTACT1, POSTACT2, …}, [P1, P2, …])
- addActivity(name, hostDemand)
ADDACTIVITY Add an activity to the workflow
ACT = ADDACTIVITY(SELF, NAME, HOSTDEMAND)
- Parameters:
name - Activity name (string)
hostDemand - Service time distribution or numeric mean
- Returns:
act - WorkflowActivity object
- addPrecedence(prec)
ADDPRECEDENCE Add precedence constraints to the workflow
SELF = ADDPRECEDENCE(SELF, PREC)
- Parameters:
prec - ActivityPrecedence object or cell array (from Serial)
- buildCTMC()
BUILDCTMC Build the CTMC representation of the workflow
[ALPHA, T] = BUILDCTMC(SELF)
- Returns:
alpha - Initial probability vector T - Subgenerator matrix
- static composeLoopGeometric(alpha, T, count)
COMPOSELOOPGEOMETRIC Geometric repetition of a PH law
[ALPHA_OUT, T_OUT] = COMPOSELOOPGEOMETRIC(ALPHA, T, COUNT)
Implements the LayeredNetwork POST_LOOP semantics, in which the number of executions of the loop body is geometric of mean COUNT. For COUNT>=1 the body runs at least once and repeats on absorption with probability P = 1-1/COUNT, so
T_OUT = T + P/D * (-T*e)*ALPHA, ALPHA_OUT = ALPHA/D
with D = 1 - P*(1-ALPHA*e) the correction for an atom at zero in ALPHA. The order of the law is that of the body, unlike the COUNT-fold convolution COMPOSEREPEAT, and the mean is COUNT times the mean of the body in both cases.
For COUNT<1 the body is executed at most once, with probability COUNT, which is how a fractional loop count is read when the LQN activity graph is built; the skipped branch is an immediate phase, the representation of a zero-time activity used throughout this class.
- static composeMixture(alphas, Ts, probs)
COMPOSEMIXTURE Probabilistic mixture of several PH laws
[ALPHA_OUT, T_OUT] = COMPOSEMIXTURE(ALPHAS, TS, PROBS)
Block-diagonal generator whose initial vector picks branch I with probability PROBS(I). This is aph_simplify pattern 3 generalised to any number of branches.
- static composeParallel(alpha1, T1, alpha2, T2)
COMPOSEPARALLEL Parallel fork-join composition
Models two PH distributions running in parallel with synchronization at completion (AND-join). The resulting PH represents the time until BOTH activities complete (i.e., the maximum).
- State space:
States (i,j) where both are active: i=1..n1, j=1..n2
States where only activity 1 is active (2 completed): i=1..n1
States where only activity 2 is active (1 completed): j=1..n2
Absorption occurs only when both have completed.
- static composeRepeat(alpha, T, count)
COMPOSEREPEAT Repeat a PH distribution count times (convolution)
Equivalent to serial composition of the same PH count times, so COUNT is a deterministic number of executions. The POST_LOOP precedence of an activity graph is instead geometric; use COMPOSELOOPGEOMETRIC for it.
- static composeSerial(alpha1, T1, alpha2, T2)
COMPOSESERIAL Serial composition of two PH distributions
The second PH starts when the first one absorbs.
- T_serial = [T1, -T1*e*alpha2]
[0, T2 ]
- static fromWfCommons(jsonFile, options)
FROMWFCOMMONS Load a workflow from a WfCommons JSON file.
WF = WORKFLOW.FROMWFCOMMONS(JSONFILE) WF = WORKFLOW.FROMWFCOMMONS(JSONFILE, OPTIONS)
Loads a workflow trace from the WfCommons format (https://github.com/wfcommons/workflow-schema) into a LINE Workflow object for queueing analysis.
- Parameters:
jsonFile - Path to WfCommons JSON file
options - Optional struct with – .distributionType - ‘exp’ (default), ‘det’, ‘aph’, ‘hyperexp’ .defaultSCV - Default SCV for APH/HyperExp (default: 1.0) .defaultRuntime - Default runtime when missing (default: 1.0) .useExecutionData - Use execution data if available (default: true) .storeMetadata - Store WfCommons metadata (default: true)
- Returns:
wf - Workflow object
Example
wf = Workflow.fromWfCommons(‘montage-workflow.json’); ph = wf.toPH(); fprintf(‘Mean execution time: %.2fn’, ph.getMean());
- getActivity(name)
GETACTIVITY Get activity by name
ACT = GETACTIVITY(SELF, NAME)
- Parameters:
name - Activity name (string)
- Returns:
act - WorkflowActivity object
- getActivityIndex(name)
GETACTIVITYINDEX Get activity index by name
IDX = GETACTIVITYINDEX(SELF, NAME)
- static invalidateBranch(tree, k)
INVALIDATEBRANCH Invalidate a node and all its ancestors
- static isAcyclicGenerator(T)
ISACYCLICGENERATOR True if the phase graph of T has no cycle
TF = ISACYCLICGENERATOR(T)
A geometric loop over a body of two or more phases closes a cycle, so the composed law is a PH and not an APH.
- refreshPH()
REFRESHPH Recompose the workflow law after a demand change
PH = REFRESHPH(SELF)
Recomposes only the series-parallel nodes on the path from a dirty leaf to the root; nodes whose subtree is unchanged keep their cached (alpha,T). The topology is not rebuilt. When the workflow is not series-parallel this degrades to a full recomposition through the block path.
- setActivityDemand(name, hostDemand)
SETACTIVITYDEMAND Change the host demand of one activity
SELF = SETACTIVITYDEMAND(SELF, NAME, HOSTDEMAND)
Marks only that leaf dirty, so that the next TOPH/REFRESHPH recomposes the path from the leaf to the root and reuses every other cached block. This is the entry point used by iterative solvers that update call-response laws at each iteration.
- setActivityDemandMean(name, meanValue)
SETACTIVITYDEMANDMEAN Change only the mean of one activity
SELF = SETACTIVITYDEMANDMEAN(SELF, NAME, MEANVALUE)
Rescales the activity law in time, so its SCV and its whole shape are preserved. The leaf keeps its order and its initial probability vector, and the cached series-parallel tree keeps its shape.
- static spExecutionCounts(tree)
SPEXECUTIONCOUNTS Expected executions of each node per run
EXECS = SPEXECUTIONCOUNTS(TREE)
Serial and parallel children inherit the count of their parent, an OR branch is weighted by its probability, and a loop body is weighted by the loop count. This is the weight by which a layer result is split back over entries, activities and calls.
- toPH()
TOPH Convert workflow to phase-type distribution
PH = TOPH(SELF)
- Returns:
- ph - APH distribution representing the workflow execution
time, or PH when the composed generator is cyclic, which a geometric loop over a multi-phase body makes it
- validate()
VALIDATE Validate workflow structure
[ISVALID, MSG] = VALIDATE(SELF)
- Returns:
isValid - true if workflow is valid msg - Error message if invalid