solvers.TR

transform_method(method)

[TOKEN, STRATEGY] = TRANSFORM_METHOD(METHOD)

Normalise an options.config.transform method name onto one TRANSFORMSOLVE dispatches on, and return the strategy function that implements it. A transformation rewrites the model into one or more subproblems, solves those with a real solver, and maps the metrics back onto the original classes and stations.

‘none’ no transformation; the caller solves its own model directly. ‘chains’ collapse every chain onto a single class

(ModelAdapter.aggregateChains) and map the chain metrics back through alpha (sn_deaggregate_chain_results). Single pass, and EXACT on a product-form model.

‘lc’ load concealment (Birman-Kogan Algorithm 2): chain aggregation,

then a Gauss-Seidel sweep in which chain l is solved on its own against the residual capacity the other chains leave it. The first ITERATED strategy. Note that SolverNC’s ‘lc’ METHOD method name is a different thing: it selects the pfqn_bklc KERNEL, which stays the fast path and is untouched by this.

An unrecognised token is an error rather than a silent ‘none’, because a mistyped transform that quietly solved the untransformed model would report a plausible number for the wrong problem.

METHOD NAME is the canonical name, recorded on the result so the reported method names the transformation. STRATEGY is the phase-dispatched function handle, empty for ‘none’.

NOT every transformation in the tree is reachable here. The fork-join tag augmentation (solver_tr_fjtag_analyzer) is selected STRUCTURALLY, from the presence of a Fork or Join node, and never by a token; the fork-join fixed point keeps its own options.config.fork_join. See _kb/05-solvers-overview.md.

See also TRANSFORMSOLVE, LQN_LN_METHOD.

Copyright (c) 2012-2026, Imperial College London All rights reserved.

solver_tr_lc_analyzer(self, phase, varargin)

VARARGOUT = SOLVER_TR_LC_ANALYZER(SELF, PHASE, VARARGIN)

LOAD CONCEALMENT as a model transformation, and the first ITERATED strategy of TRANSFORMSOLVE.

Birman and Kogan (Stochastic Models 8(3):543-563, 1992), Algorithm 2. The saddle point analysis of their Corollary 2 shows that chain l may be solved on its own provided every station is slowed by the residual capacity the other chains leave it,

A_i = 1 - sum_{k != l} L(i,k) * X_k,

so that chain l sees the concealed demand L(i,l)/A_i. Sweeping the chains in Gauss-Seidel order and iterating to a fixed point is the algorithm.

WHAT THIS ADDS OVER THE KERNEL. PFQN_BKLC solves each single-chain subproblem on a DEMAND VECTOR, with the inner solve hard-wired to pfqn_mva or pfqn_bkue. Here the subproblem is a real single-class Network, so the inner solve is the CALLER’S OWN solver: the same decomposition can be evaluated with CTMC, SSA or Fluid, which is what makes the concealment approximation measurable rather than merely asserted.

IT IS NOT A STRICTLY BETTER LC, and must not be described as one. The kernel sees only L; ModelAdapter.aggregateChains refits the chain service law to two moments. On a product-form model the two coincide; off it they are different approximations of the same quantity.

THE TOLERANCE IS FIXED AT 1e-10 AND IS NOT options.iter_tol. That is a PARITY requirement, not a quality knob: a looser tolerance stops the sweep at a different iteration in each codebase, which is how MATLAB and python came to report 0.99843 and 0.9835 for the same model.

Phases: ‘expand’, ‘couple’ (Gauss-Seidel, one chain at a time), ‘converged’, ‘lift’.

See also TRANSFORMSOLVE, PFQN_BKLC, SOLVER_TR_CHAINS_ANALYZER.

Copyright (c) 2012-2026, Imperial College London All rights reserved.

solver_tr_fjtag_analyzer(self, phase, varargin)

VARARGOUT = SOLVER_TR_FJTAG_ANALYZER(SELF, PHASE, …)

Fork-join TAG AUGMENTATION as a solver-agnostic model transformation.

ModelAdapter.fjtag rewrites the model into an exact tag-augmented struct in which every (fork, class, branch, tag) carries its own transient closed class and a join fires only once all siblings of one tag are buffered. The struct it returns is solved by the CALLER’S OWN analyzer, unchanged, and the auxiliary columns are folded back afterwards by SN_FJ_FOLDBACK.

Both halves used to be written out inside @SolverCTMC/runAnalyzer.m and @SolverSSA/runAnalyzer.m, including the sn_orig/Korig bookkeeping and the per-sibling join response time, so a fix to one never reached the other. They live here once.

This transformation has NO callback seam: the transformed struct is solved INLINE by the rest of the caller’s analyzer rather than by a nested solver, so the caller invokes the two phases itself instead of handing control to a driver. That is the difference between it and @NetworkSolver/fjFixedPoint.m.

Phase dispatch, following the SolverENV analyzer convention:

[snAug, ctx] = solver_tr_fjtag_analyzer(self, ‘expand’, sn, options)

SN is the untransformed struct. SNAUG is the tag-augmented struct to solve; CTX carries what the lift needs and is opaque to the caller.

[QN,UN,RN,TN,AN,CN,XN] = solver_tr_fjtag_analyzer(self, ‘lift’, ctx, …

QN,UN,RN,TN,CN,XN, T)

Fold the auxiliary classes back onto the original ones and derive the arrival rates in the ORIGINAL station/class coordinates. T is the throughput handle matrix from GETAVGTPUTHANDLES.

Copyright (c) 2012-2026, Imperial College London All rights reserved.

solver_tr_chains_analyzer(self, phase, varargin)

VARARGOUT = SOLVER_TR_CHAINS_ANALYZER(SELF, PHASE, VARARGIN)

Chain-aggregation strategy for TRANSFORMSOLVE. Collapses every chain onto a single class, solves that model with the CALLER’S OWN solver, and maps the chain metrics back onto the classes.

WHY THIS EXISTS. The state space of a multiclass model grows with the per-class populations, so a model with several classes in one chain can be intractable while the same model with one class per chain is not. ModelAdapter.aggregateChains builds the collapsed model and sn_deaggregate_chain_results maps its metrics back through alpha, the per-station share of the chain’s visits each class carries.

WHAT IS TRADED. The aggregation is EXACT on a product-form model: the chain is the unit MVA and convolution already solve in, and the deaggregation is the same alpha-weighted split those solvers apply. It is an APPROXIMATION otherwise, because one aggregate service law, fitted to the alpha-weighted first two moments, replaces the per-class ones. A caller who needs the exact multiclass answer must leave the transform off and pay the state space.

Phases: ‘expand’ builds the single aggregated submodel, ‘lift’ deaggregates. The transformation is SINGLE PASS: one solve of the aggregate determines the answer, so ctx.iterated stays false and no coupling or convergence phase is implemented.

See also TRANSFORMSOLVE, TRANSFORM_METHOD, SN_DEAGGREGATE_CHAIN_RESULTS.

Copyright (c) 2012-2026, Imperial College London All rights reserved.