solvers.UQ
- class UQ
Bases:
EnsembleSolverUQ Solver wrapper for models with Prior distributions
UQ detects Prior distributions in a model, expands the model into a family of concrete networks (one per Prior alternative), solves each using the specified solver, and aggregates results using prior probabilities as weights.
@brief Solver wrapper for Bayesian-style uncertainty analysis
Key characteristics: - Detects and expands Prior distributions in models - Orchestrates multiple solver runs - Aggregates results with prior-weighted expectations - Provides posterior distribution access - Reports the support-only (interval) range through getInterval, which
ignores the weights and keeps only the endpoints of each Prior
Example: @code model = Network(‘UncertainService’); source = Source(model, ‘Source’); queue = Queue(model, ‘Queue’, SchedStrategy.FCFS); sink = Sink(model, ‘Sink’);
class = OpenClass(model, ‘Jobs’); source.setArrival(class, Exp(1.0)); queue.setService(class, Prior({Exp(1), Exp(2)}, [0.5, 0.5]));
model.link(model.serialRouting(source, queue, sink));
post = UQ(model, @SolverMVA); avgTable = post.getAvgTable(); % Prior-weighted expectations postTable = post.getPosteriorTable(); % Per-alternative results postDist = post.getPosteriorDist(‘R’, queue, class); % Response time distribution ival = post.getIntervalTable(); % Support-only range, no weights @endcode
Copyright (c) 2012-2026, Imperial College London All rights reserved.
- Constructor Summary
- UQ(model, solverFactory, varargin)
UQ Create a UQ solver wrapper
@brief Creates a UQ wrapper for uncertainty analysis @param model Network model (may contain Prior distributions) @param solverFactory Function handle: @(m) SolverXXX(m) or solver class name @param varargin Optional solver options @return self UQ instance
- Property Summary
- MaxDesignPoints
Cap on the tensor-product design size. A design point is one full solver run, so this bounds the cost of a quadrature design over several Priors; beyond it the Monte Carlo design is the right tool.
- aggregatedResult
Prior-weighted aggregate metrics
- design
.weight and .dists (one per Prior)
- Type:
Struct array of design points
- originalModel
Reference to original model with Prior
- priorInfo
Struct array with Prior detection info, one entry per Prior
- solverFactory
@(model) SolverXXX(model)
- Type:
Function handle to create solvers
- Method Summary
- aggregateResults()
AGGREGATERESULTS Compute prior-weighted aggregate metrics
- analyze(it, e)
ANALYZE Run solver for ensemble model e
@param it Iteration number @param e Ensemble model index @return result Solver result structure @return runtime Solver execution time
- buildDesign()
BUILDDESIGN Reduce the detected Priors to weighted design points
Each design point assigns one concrete Distribution to every Prior in the model and carries the weight of that joint assignment. Discrete and quadrature designs take the tensor product of the per-Prior alternatives, so their weights are the products of the marginal weights: this is the product-density case of the joint f(theta_1,…,theta_l) in Trivedi and Bobbio (2017), Eq. (3.67), and assumes the Priors are independent. Monte Carlo instead draws all Priors jointly, so its cost is independent of the number of Priors.
- converged(it)
CONVERGED Check convergence
UQ converges after the first iteration (it >= 1).
- static defaultOptions()
DEFAULTOPTIONS Return default options
- detectPriors()
DETECTPRIORS Find Prior distributions in the model
Scans all nodes for Prior distributions and stores location info. Currently supports only a single Prior in the model.
- finish()
FINISH Finalization (no-op for UQ)
- getAvg(varargin)
GETAVG Return prior-weighted average metrics
Returns aggregated metrics weighted by prior probabilities.
- getAvgTable(varargin)
GETAVGTABLE Return prior-weighted average table
Returns a table of aggregated metrics weighted by prior probabilities. The result recorder captures the returned table together with the solver that produced it – see LineResultRecorder. Recording an ensemble here rather than in the member solver it delegates to is what keeps an AUTO/LN/ENV/UQ answer from being filed under the member’s name.
- getAvgTable_impl(varargin)
GETAVGTABLE_IMPL Implementation of GETAVGTABLE; see the wrapper above.
- getCredibleInterval(metric, station, class, level)
CI = GETCREDIBLEINTERVAL(METRIC, STATION, CLASS, LEVEL) Equal-tailed credible interval from the weighted empirical CDF.
@param metric Metric name (‘Q’,’U’,’R’,’T’,’A’,’W’) @param station Station object or index @param class Class object or index @param level Coverage level in (0,1), default 0.95 @return ci Two-element vector [lower, upper]
- getEnsembleAvg()
GETENSEMBLEAVG Get per-model average metrics
Returns cell arrays with metrics from each ensemble model.
- static getFeatureSet()
GETFEATURESET Return supported features
- getInterval()
IVAL = GETINTERVAL() Range of every metric over the support of the Priors.
This drops the weights and keeps only the endpoints, which is the epistemic case in which the modeller can bound a parameter but not distribute it. Two regimes, distinguished by ival.exact:
- exact = true The model is a single-class closed product-form
network with load-independent single-server queues and delays, so pfqn_mva_interval returns the exact hull of MVA over the whole demand box by the monotonicity of Luthi and Haring (1998). No ensemble run is needed and the interval is attained, not sampled.
- exact = false Fallback: the range across the design points
that were actually solved. For a discrete Prior this is again exact, because the design visits the whole support; for a continuous one it is an INNER approximation of the true range, since a quadrature node is not an endpoint of the support. It is therefore not an enclosure.
The interval is conditional on the true parameters lying inside the Prior supports. It is not a bound on the exact solution of the network and must not be composed with SolverBA brackets.
- @return ival Struct with fields Q, U, R, T, W of size
nstations x nclasses x 2, the trailing index selecting the lower and the upper endpoint, plus X and Rtot (1 x 2, exact path only), exact (logical) and method (char).
- getIntervalTable()
ITABLE = GETINTERVALTABLE() Tabular form of getInterval, two columns per metric.
- getMoments(metric, station, class)
[M, V] = GETMOMENTS(METRIC, STATION, CLASS) Weighted mean and variance of a metric over the design.
The mean is the unconditional expectation of Trivedi and Bobbio (2017), Eq. (3.68); the variance is the second moment of the same weighting, as derived for the cold-standby case in their Sec. 8.5.1. Both are exact for a discrete Prior and quadrature- or sample-approximate for a continuous one.
@param metric Metric name (‘Q’,’U’,’R’,’T’,’A’,’W’) @param station Station object or index @param class Class object or index @return m Weighted mean @return v Weighted variance
- getNumAlternatives()
N = GETNUMALTERNATIVES() Return number of design points (1 if no Prior)
- getNumberOfModels()
E = GETNUMBEROFMODELS() Return number of ensemble models (design points)
Overrides EnsembleSolver to return count based on the design, since ensemble is not populated until init().
- getPosteriorDist(metric, station, class)
GETPOSTERIORDIST Return empirical distribution of a metric
Returns an EmpiricalCDF object representing the posterior distribution of the specified metric across Prior alternatives.
@param metric Metric name: ‘Q’, ‘U’, ‘R’, ‘T’, ‘A’, ‘W’ @param station Station node or station index @param class JobClass object or class index @return empDist EmpiricalCDF object
- getPosteriorTable()
GETPOSTERIORTABLE Return table with per-alternative results
Returns a table showing metrics for each Prior alternative along with its probability.
- getProbabilities()
PROBS = GETPROBABILITIES() Return vector of design-point weights
- getSamples(metric, station, class)
[VALS, W] = GETSAMPLES(METRIC, STATION, CLASS) Per-design-point metric values and their weights.
- getStruct()
GETSTRUCT Return model structure
Returns the structure of the original model.
- getUQMethod()
METHOD = GETUQMETHOD() Resolve the discretization method from the solver options.
‘default’ keeps the historical behaviour: discrete Priors are expanded as given, continuous Priors are discretized by quadrature. The name table is RESOLVEUQMETHOD, shared with the gate so the two cannot disagree on a method name.
- getUQNodes()
N = GETUQNODES() Number of nodes per continuous Prior, from options.samples.
- hasPriorDistribution()
HASPRIOR = HASPRIORDISTRIBUTION() Return true if model contains a Prior distribution
- init()
INIT Initialize the UQ solver
Expands the model into a family of concrete models, one for each Prior alternative.
- intervalByMVA()
IVAL = INTERVALBYMVA() Exact hull through pfqn_mva_interval. The demand box is the nominal demand vector with the prior-carrying stations widened to the range of mean service times over the Prior support.
- intervalBySampling()
IVAL = INTERVALBYSAMPLING() Range of each metric across the design points that were solved.
- iterate(varargin)
ITERATE Run the ensemble, narrating the run on the console
Solver console: UQ drives an ensemble of alternative models and does not pass through runAnalyzerChecks. Every entry point (runAnalyzer, getAvg, getAvgTable) reaches the analysis through iterate, so the run is opened here. The guard must live until this function returns.
- listValidMethods()
LISTVALIDMETHODS Return valid methods
- static modelHasPrior(model)
TF = MODELHASPRIOR(MODEL) True when the model carries an uncertain parameter, i.e. when a service or arrival process is a Prior and the model therefore expands into one instance per design point. SolverAUTO asks the same question through this method, so the constructor’s routing and this gate cannot disagree.
- post(it)
POST Post-iteration operations
Aggregates results from all ensemble models using prior weights.
- pre(it)
PRE Pre-iteration operations (no-op for UQ) UQ only needs a single iteration
- static priorMeanRange(prior, n)
[LO, UP] = PRIORMEANRANGE(PRIOR, N) Range of the mean of a Prior over its alternatives.
Exact for a discrete Prior, whose alternatives are the support. A continuous Prior is first discretized on N quadrature nodes, so the range is that of the discretized support: an unbounded parameter density is never reached at its tails.
- qualifiesForIntervalMVA()
[OK, WHY] = QUALIFIESFORINTERVALMVA() Whether the monotonicity theorems behind pfqn_mva_interval hold for this model. WHY names the first violated condition.
- resolveClassIndex(class)
K = RESOLVECLASSINDEX(CLASS) Accept a JobClass object or a numeric index.
- resolveStationIndex(station)
IST = RESOLVESTATIONINDEX(STATION) Accept a Station object or a numeric index.
- static resolveUQMethod(name)
METHOD = RESOLVEUQMETHOD(NAME) The design a method name selects: ‘default’, ‘discrete’ and ‘quadrature’ are the tensor-product (quadrature) design, and ‘montecarlo’ the sampled one. One table for getUQMethod and the gate, so the two cannot disagree on a name.
- runAnalyzer(options)
RUNANALYZER Run the UQ analysis
@param options Solver options (optional) @return runtime Total runtime in seconds
- static supports(model)
SUPPORTS Check if model is supported
A MODEL WITH NO UNCERTAIN PARAMETER IS NOT A UQ MODEL. This returned true unconditionally, which made UQ claim every model in the language: SolverAUTO.listValidMethods offered every ‘uq.*’ method name on an ordinary network, whose posterior is a single design point equal to the point estimate the inner solver already returns. The JAR (SolverUQ.supports -> detectPrior() != null) and native python (hasPriorDistribution) have always gated it this way, so this closes an m/j/p divergence rather than tightening a rule the other two share.
The feature set stays the answer to a DIFFERENT question and is returned unchanged: what UQ itself consumes is the Prior, while every other feature is the INNER solver’s to accept or refuse, on a model from which the Prior has already been removed.
- supportsModelMethod(method)
[BOOL, REASON] = SUPPORTSMODELMETHOD(METHOD)
UQ’s refusal IN ITS OWN WORDS, which the base gate cannot supply here. That one falls back to SUPPORTS(MODEL), which answers with a bare logical, and a caller left to reconstruct a reason from the feature set gets a list of every feature the model uses: this class’s set declares the Prior UQ ITSELF consumes, every other feature being the inner solver’s to accept (see SUPPORTS), so comparing it against a model answers a question nobody asked.
The rule is the one SUPPORTS states: a model with no uncertain parameter is not a UQ model. On top of it, the tensor-product design of the discrete/quadrature methods must fit MaxDesignPoints, a rule buildDesign used to state alone on the run path; ‘montecarlo’ has no such cap.
- tensorDesignRefusal(counts)
[OK, REASON] = TENSORDESIGNREFUSAL(COUNTS) Whether the tensor-product design of the discrete/quadrature methods fits MaxDesignPoints. COUNTS, the per-Prior alternative counts, is derived from the Priors when omitted. Asked by supportsModelMethod, so model.help refuses ‘quadrature’ on a model whose Priors multiply out past the cap and still offers ‘montecarlo’, and by buildDesign, so the run raises the same sentence.
- static unrankIndex(i, counts)
IDX = UNRANKINDEX(I, COUNTS) Map the linear index I in 1..prod(COUNTS) to a subscript vector over a mixed-radix grid, first coordinate varying fastest.