api.wfn
- class WorkflowNet
Bases:
ModelWorkflowNet - A Workflow Net (WF-net) model for performance analysis.
A WF-net (van der Aalst, 1997/98) is a Petri net with exactly one source place i (no incoming arcs), exactly one sink place o (no outgoing arcs), and every place and transition on a directed path from i to o. A case is one token put in i; it is complete when one token reaches o.
WorkflowNet does not have a solver of its own. It checks that the net is a WF-net and that it is sound, and then either analyses one case exactly or compiles the net into an ordinary Network:
validate() structural WF-net conditions checkSoundness(k) k-soundness on the reachability graph getCycleTime() exact phase-type law of the case duration of one
case without contention (any sound net, PH timing)
- getCycleTimeAnalysis() moments, CDF, percentiles, expected firings per
transition and expected token-time per place
getResourceLoads(lambda) per-resource load of an open stream of cases toWorkflow() equivalent Workflow, for block-structured nets toNetwork(‘forkjoin’) fork-join queueing network, block-structured nets toNetwork(‘spn’) stochastic Petri net with a case-counter place,
any sound net
- getCaseMetrics(solver) case throughput, WIP, cycle time and resource
utilisation from a solver of a compiled network
TIMING. A timed transition fires after a phase-type delay (Exp, Erlang, HyperExp, Coxian, Cox2, APH, PH) under race semantics with enabling memory: a transition disabled by a conflicting firing loses its progress. An immediate transition fires in zero time; among the enabled immediate transitions only those of the highest priority fire, chosen with probability proportional to their weights.
SEMANTICS OF THE TWO NETWORK TARGETS WITH MANY CASES. The fork-join target keeps case identity, since LINE joins only synchronise siblings of the same job. The SPN target uses uncoloured tokens, so an AND-join may pair tokens of different cases; its case-counter place gives the mean number of cases in the system and, by Little’s law, the exact mean cycle time under that semantics. Percentiles are not available from it.
Example
wfn = WorkflowNet(‘SimpleWFN’); i = wfn.addPlace(‘i’); p = wfn.addPlace(‘p’); o = wfn.addPlace(‘o’); t1 = wfn.addTransition(‘Task1’, Exp(1.0)); t2 = wfn.addTransition(‘Task2’, Exp(2.0)); wfn.addArc(i, t1); wfn.addArc(t1, p); wfn.addArc(p, t2); wfn.addArc(t2, o); [isSound, report] = wfn.checkSoundness(); ph = wfn.getCycleTime(); % hypoexponential, mean 1.5
Copyright (c) 2012-2026, Imperial College London All rights reserved.
- Constructor Summary
- WorkflowNet(name)
WorkflowNet Create a new WorkflowNet instance
SELF = WorkflowNet(NAME)
- Property Summary
- arcs
Cell array of WFNArc objects
- arrivalProcess
Interarrival distribution of cases (open analysis), or []
- closedCases
Number of concurrent cases (closed analysis), 0 = open
- places
Cell array of WFNPlace objects
- resources
Cell array of WFNResource objects
- sinkPlace
Sink place o, set by validate() if not given
- sourcePlace
Source place i, set by validate() if not given
- stateCap
Largest reachability graph explored before giving up
- transitions
Cell array of WFNTransition objects
- Method Summary
- addArc(source, target, weight)
ADDARC Add an arc from a place to a transition or vice versa
ARC = ADDARC(SELF, SOURCE, TARGET, WEIGHT)
SOURCE and TARGET are WFNPlace/WFNTransition objects of this net or their names; WEIGHT is a positive integer (default 1).
- addPlace(name, initialMarking)
ADDPLACE Add a place to the workflow net
PLACE = ADDPLACE(SELF, NAME, INITIALMARKING)
INITIALMARKING is informational: the analyses always start from k tokens in the source place, as WF-net soundness does.
- addTransition(name, distribution, timing, servers, priority, weight)
ADDTRANSITION Add a transition to the workflow net
TRANSITION = ADDTRANSITION(SELF, NAME, DISTRIBUTION, TIMING, SERVERS, PRIORITY, WEIGHT)
- Parameters:
name - Transition name
distribution - Firing-time distribution (default Exp(1)) – Immediate distribution makes the transition immediate
timing - TimingStrategy.TIMED or TimingStrategy.IMMEDIATE
servers - Concurrent firings allowed (default Inf, i.e. no – contention unless a resource is assigned)
priority - Firing priority of an immediate transition (default 1)
weight - Firing weight of an immediate transition (default 1)
- checkSoundness(k, stateCap)
CHECKSOUNDNESS Decide k-soundness on the reachability graph
[ISSOUND, REPORT] = CHECKSOUNDNESS(SELF, K, STATECAP)
From the marking with K tokens in the source (default 1) the net is k-sound when (1) the final marking, K tokens in the sink, is reachable from every reachable marking (option to complete), (2) no reachable marking puts K tokens in the sink together with other tokens (proper completion) and (3) every transition fires in some reachable marking (no dead transitions). The untimed net is explored, as soundness is a property of the net, not of its timing. A marking that strictly covers one of its ancestors proves the net unbounded, hence unsound. If STATECAP markings (default: the stateCap property) are explored first, the verdict is ‘unknown’, never ‘sound’.
REPORT fields: k, verdict (‘sound’,’unsound’,’unknown’), stateSpaceSize, deadlocks, noOptionToComplete, improperCompletion (cell arrays of markings, as row vectors over places), deadTransitions (names), unbounded, unboundedWitness, unboundedOrTooLarge, witnesses (readable one-line descriptions).
- static formatReport(report)
FORMATREPORT One-line summary of a soundness report
- static fromNetwork(model)
FROMNETWORK Create a WorkflowNet from a LINE Petri net
NET = FROMNETWORK(MODEL) copies the places, the transitions and their arcs of a single-class Network made of Place and Transition nodes. A transition must have exactly one mode and no inhibitor arcs or firing-rate dependence, since a WF-net transition has one firing rule. The result is validated.
- static fromPNML(filename, netName)
FROMPNML Create a WorkflowNet from a PNML file
NET = FROMPNML(FILENAME, NETNAME) reads the net with pnml_load and converts it with fromNetwork; the source and sink are found from the structure. A file from another tool is untimed and reads with every transition exponential at rate 1 (see pnml_load).
- getCaseMetrics(solver)
GETCASEMETRICS Case-level metrics from a solver of a compiled net
METRICS = GETCASEMETRICS(SELF, SOLVER), with SOLVER built on the network returned by the last toNetwork call, returns a struct:
target, mode - ‘forkjoin’/’spn’, ‘open’/’closed’ throughput - cases completed per unit time wip - mean number of cases in the system cycleTime - mean case cycle time (Little’s law) resources - table: resource, servers, utilisation tasks - table: task, mean response time at its
station (forkjoin) or tokens in service (spn)
places - table of mean tokens per place (spn only)
- getCycleTime()
GETCYCLETIME Exact case cycle time of one case without contention
PH = GETCYCLETIME(SELF)
The reachability graph of the timed net from one token in the source becomes an absorbing CTMC whose absorbing state is the final marking; immediate transitions are folded out of it, so the case duration is exactly phase-type for any sound net with phase-type timing, series-parallel or not. Requires 1-soundness.
- getCycleTimeAnalysis()
GETCYCLETIMEANALYSIS Full single-case analysis
- AN = GETCYCLETIMEANALYSIS(SELF) returns a struct with fields
ph - PH law of the case duration mean, variance, scv, moments (first three raw moments) cdf - function handle t -> P(duration <= t) percentile - function handle q in (0,1) -> q-quantile zeroTimeProb - probability that a case completes in zero time firings - table of expected firings per transition placeTime - table of expected token-time per place numStates - number of tangible transient states
- getIncidence()
GETINCIDENCE Input and output arc weights, places x transitions
- getPlace(name)
GETPLACE Get a place by name
- getResourceLoads(lambda)
GETRESOURCELOADS Per-resource load of an open stream of cases
LOADS = GETRESOURCELOADS(SELF, LAMBDA) returns a table with one row per resource and per task with a finite server count: the offered load LAMBDA * sum_t E[firings of t] * E[time of t] divided by the servers, using the expected firings of one case. The open system is stable only if every load is below 1. LAMBDA defaults to the rate of the arrival process.
- getTransition(name)
GETTRANSITION Get a transition by name
- isBlockStructured()
ISBLOCKSTRUCTURED True if the net reduces to a process tree
The net is reduced by five rules until nothing applies: fold a single-input single-output transition between two places into a place, fold a single-input single-output place between two transitions into a transition, merge parallel places (AND block), merge parallel transitions (XOR block, choices resolved by immediate transitions of equal priority, in proportion to their weights) and absorb a self-loop transition (geometric loop). It is block-structured if it reduces to one place.
- savePNML(filename)
SAVEPNML Write the net to PNML with one token in the source
SAVEPNML(SELF, FILENAME) builds the plain Petri net (no case counter, no resources) and writes it with pnml_save, so that WorkflowNet.fromPNML reads it back with its timing.
- setArrivalProcess(process, param)
SETARRIVALPROCESS Set the stream of cases for open analysis
SETARRIVALPROCESS(SELF, ‘poisson’, RATE) SETARRIVALPROCESS(SELF, ‘map’, MAPOBJ) SETARRIVALPROCESS(SELF, DIST) any interarrival distribution SETARRIVALPROCESS(SELF, ‘none’) clears it
- setClosedCases(k)
SETCLOSEDCASES Set k concurrent cases (closed analysis); 0 = open
- setResource(transition, name, servers, scheduling)
SETRESOURCE Assign a shared resource to a timed transition
RESOURCE = SETRESOURCE(SELF, TRANSITION, NAME, SERVERS, SCHEDULING)
A resource is shared by every task that names it and by every case. Calling it again with an existing NAME reuses that resource; SERVERS and SCHEDULING, when given, update it.
- setSink(place)
SETSINK Declare the sink place (checked by validate)
- setSource(place)
SETSOURCE Declare the source place (checked by validate)
- setStateCap(cap)
SETSTATECAP Set the largest state space explored by the analyses
- toNetwork(target, varargin)
TONETWORK Compile the workflow net to a LINE Network
NETWORK = TONETWORK(SELF, TARGET, ‘checkSoundness’, TF)
- TARGET:
- ‘forkjoin’ - block-structured nets. AND-split -> Fork, AND-join
-> Join, XOR and loops -> probabilistic routing, a task -> Delay (no contention), a Queue of its own (finite servers) or the Queue of its resource. Tasks sharing a resource are told apart by class. Solvers: MVA (fork-join approximations), JMT, LDES.
- ‘spn’ - any sound net, as a stochastic Petri net with a
case-counter place. A task on a resource becomes an immediate acquire followed by the timed task, which releases the resource; waiting tasks take a free server in random order, in proportion to their weights, whatever the resource scheduling (the fork-join target honours it). Its transitions create and destroy tokens (an AND-split makes two of one), which SolverSSA and SolverLDES simulate; SolverCTMC and SolverJMT do not support that.
Open analysis (setArrivalProcess) gives a Source and a Sink; closed analysis (setClosedCases(k)) recirculates k cases through a zero-time restart. The soundness gate (k-soundness, k the number of closed cases or 1) is on by default; pass ‘checkSoundness’, false to skip it on nets too large to explore.
- toWorkflow()
TOWORKFLOW Equivalent Workflow of a block-structured net
WORKFLOW = TOWORKFLOW(SELF) maps each timed transition to an activity with its distribution and each block to the Workflow precedence of the same meaning. Immediate transitions take no time and disappear; where a fork or join needs an anchor that the net does not provide, an Immediate activity named wfn_aux_<n> is added. Workflow.Loop executes its body a geometric number of times >= 1, so a loop with work on its return path is refused. Workflow models an Immediate activity at rate GlobalConstants.Immediate, so its toPH() agrees with getCycleTime() up to that rate, not to machine precision.
- validate()
VALIDATE Check the structural WF-net conditions
VALIDATE(SELF) requires exactly one place without incoming arcs (the source i), exactly one place without outgoing arcs (the sink o), and every place and transition on a directed path from i to o, which is strong connectivity once the arc o -> i is added. A declared source or sink must be that place. On success sourcePlace and sinkPlace are set; on failure a LINE:input:Model error names the offending nodes.
- class WFNTransition
Bases:
handleWFNTransition - A transition in a Workflow Net.
WFNTransition represents a transition in a workflow net, which can consume tokens from input places and produce tokens to output places. A transition can be timed (with a service time distribution) or immediate (fires instantly when enabled).
- Properties:
name - Transition name distribution - Service time distribution (for timed transitions) timing - Timing strategy (TIMED or IMMEDIATE) servers - Number of servers priority - Firing priority weight - Firing weight (for probabilistic choices) index - Internal index workflowNet - Parent WorkflowNet resource - Assigned WFNResource (if any) workflowActivity - Corresponding WorkflowActivity (if compiled to Workflow) networkTransition - Corresponding Transition in compiled Network (if any)
Copyright (c) 2012-2026, Imperial College London All rights reserved.
- Constructor Summary
- WFNTransition(workflowNet, name, distribution, timing, servers, priority, weight)
WFNTransition Create a new WFNTransition
SELF = WFNTransition(WORKFLOWNET, NAME, DISTRIBUTION, TIMING, SERVERS, PRIORITY, WEIGHT)
- Property Summary
- distribution
- index
- name
- priority
- servers
- timing
- weight
- workflowNet
- Method Summary
- isImmediate()
ISIMMEDIATE Check if transition is immediate
TF = ISIMMEDIATE(SELF)
- isTimed()
ISTIMED Check if transition is timed
TF = ISTIMED(SELF)
- setDistribution(distribution)
SETDISTRIBUTION Set the service time distribution
SETDISTRIBUTION(SELF, DISTRIBUTION)
- setPriority(priority)
SETPRIORITY Set the firing priority
SETPRIORITY(SELF, PRIORITY)
- setServers(servers)
SETSERVERS Set the number of servers
SETSERVERS(SELF, SERVERS)
- setTiming(timing)
SETTIMING Set the timing strategy
SETTIMING(SELF, TIMING)
- setWeight(weight)
SETWEIGHT Set the firing weight
SETWEIGHT(SELF, WEIGHT)
- class WFNResource
Bases:
handleWFNResource - A shared resource in a Workflow Net.
WFNResource represents a shared resource that can be assigned to transitions. When a transition requires a resource, it can only fire if the resource has available servers.
- Properties:
name - Resource name servers - Number of servers scheduling - Scheduling strategy
Copyright (c) 2012-2026, Imperial College London All rights reserved.
- Constructor Summary
- WFNResource(name, servers, scheduling)
WFNResource Create a new WFNResource
SELF = WFNResource(NAME, SERVERS, SCHEDULING)
- Property Summary
- name
- scheduling
- servers
- Method Summary
- setName(name)
SETNAME Set the resource name
SETNAME(SELF, NAME)
- setScheduling(scheduling)
SETSCHEDULING Set the scheduling strategy
SETSCHEDULING(SELF, SCHEDULING)
- setServers(servers)
SETSERVERS Set the number of servers
SETSERVERS(SELF, SERVERS)
- class WFNArc
Bases:
handleWFNArc - An arc in a Workflow Net.
WFNArc represents a directed arc between a place and a transition, or between a transition and a place. Arcs have a weight (multiplicity).
- Properties:
source - Source node (WFNPlace or WFNTransition) target - Target node (WFNPlace or WFNTransition) weight - Arc weight/multiplicity workflowNet - Parent WorkflowNet
Copyright (c) 2012-2026, Imperial College London All rights reserved.
- class WFNPlace
Bases:
handleWFNPlace - A place in a Workflow Net.
WFNPlace represents a place in a workflow net, which can hold tokens that enable transitions to fire.
- Properties:
name - Place name initialMarking - Initial token count index - Internal index workflowNet - Parent WorkflowNet networkPlace - Corresponding Place in compiled Network (if any)
Copyright (c) 2012-2026, Imperial College London All rights reserved.
- Constructor Summary
- WFNPlace(workflowNet, name, initialMarking)
WFNPlace Create a new WFNPlace
SELF = WFNPlace(WORKFLOWNET, NAME, INITIALMARKING)
- Property Summary
- index
- initialMarking
- name
- workflowNet
- Method Summary
- setInitialMarking(marking)
SETINITIALMARKING Set the initial marking
SETINITIALMARKING(SELF, MARKING)