Class SolverNC

Direct Known Subclasses:
NC

public class SolverNC extends NetworkSolver
Solver for Normalizing Constant (NC) method applied to closed queueing networks.

SolverNC implements the normalizing constant approach for computing exact performance measures of closed product-form queueing networks. The normalizing constant G(N) represents the partition function that ensures steady-state probabilities sum to one.

Key NC solver capabilities:

  • Exact normalizing constant computation
  • Convolution algorithm implementation
  • Load-dependent service station support
  • Cache-enabled queueing network analysis
  • Joint and marginal probability computation
  • State probability aggregation methods

The solver supports various computation methods including standard convolution, tree convolution, and specialized algorithms for cache networks and load-dependent stations. Results include exact performance metrics and state probabilities.

Since:
1.0
See Also:
  • Constructor Details

  • Method Details

    • supportsExactSensitivity

      public boolean supportsExactSensitivity()
      The normalizing-constant solver is exact on the same product-form class that pfqn_sens differentiates, so getSensitivityTable uses the analytic branch.
      Overrides:
      supportsExactSensitivity in class NetworkSolver
      Returns:
      true
    • hasRetrievalCache

      public static boolean hasRetrievalCache(NetworkStruct sn)
      True if the model contains a Cache equipped with a delayed-hit retrieval system.
    • defaultOptions

      public static SolverOptions defaultOptions()
    • getFeatureSet

      public static FeatureSet getFeatureSet()
      Returns the feature set supported by the NC solver
      Returns:
      - the feature set supported by the NC solver
    • getProb

      public Double getProb(Node node, Matrix state)
    • getProbAggr

      public Double getProbAggr(Node node, Matrix state_a)
      Get aggregated probability for a specific node and state
      Parameters:
      node - The node to compute probability for
      state_a - The aggregated state (optional, uses current state if null)
      Returns:
      The aggregated probability value
    • getProbAggr

      public Double getProbAggr(Node node)
      Get aggregated probability for a specific node using current state
      Parameters:
      node - The node to compute probability for
      Returns:
      The aggregated probability value
    • getProbMarg

      public Ret.ProbabilityResult getProbMarg(int ist, int jobclass, Matrix state_m)
      Marginal queue-length distribution at a station, routing the CLI's (station, class) call to the exact procomom/enumeration path in getProbMarg(Node). The class index is not used: NC returns the per-station total-jobs marginal.
      Overrides:
      getProbMarg in class NetworkSolver
      Parameters:
      ist - station index
      jobclass - class index (unused; marginal is over total jobs)
      state_m - optional state (unused)
      Returns:
      the exact marginal probability distribution
    • getProbMarg

      public Ret.ProbabilityResult getProbMarg(Node node)
    • getProbNormConstAggr

      public Ret.ProbabilityResult getProbNormConstAggr()
      Get the log normalization constant for aggregated probabilities
      Overrides:
      getProbNormConstAggr in class NetworkSolver
      Returns:
      The log normalization constant
      Throws:
      IllegalAccessException - if analysis fails
    • getProbSys

      public Ret.ProbabilityResult getProbSys()
      Get system-wide joint probability
      Overrides:
      getProbSys in class NetworkSolver
      Returns:
      The joint probability value
    • getProbSysAggr

      public Ret.ProbabilityResult getProbSysAggr()
      Get aggregated system-wide joint probability
      Overrides:
      getProbSysAggr in class NetworkSolver
      Returns:
      The aggregated joint probability value
    • getProbSysMarg

      public Ret.ProbabilityResult getProbSysMarg(Matrix nvec)
      Joint probability that station i holds nvec(i) jobs IN TOTAL, all classes summed out.

      Compare with getProbSysAggr(), which fixes the PER-CLASS population of every station and is a product form; each value returned here is the sum of that one over every per-class table with these row sums. Compare also with getProbMarg, which is the one-station marginal of this law. The quantity is a permanent of the demand matrix replicated once per job (Ryser 1963), so it needs no enumeration of that fibre.

      Overrides:
      getProbSysMarg in class NetworkSolver
      Parameters:
      nvec - per-station total job counts, summing to the closed population
      Returns:
      the joint probability and its logarithm
    • getProbSysMarg

      public Ret.ProbabilityResult getProbSysMarg(Matrix nvec, String engine)
      Joint probability of the per-station total queue lengths, evaluated with a chosen permanent engine.
      Overrides:
      getProbSysMarg in class NetworkSolver
      Parameters:
      nvec - per-station total job counts
      engine - "exact" (default), "spm", "bethe", "heur", "huberlaw" or "adapart". Only "exact" is exact; the others are refused on a demand matrix with a structural zero rather than having it floored, since they need full support.
      Returns:
      the joint probability and its logarithm
    • getStruct

      public NetworkStruct getStruct()
    • setStruct

      public void setStruct(NetworkStruct sn)
    • runAnalyzer

      public void runAnalyzer() throws IllegalAccessException
      Description copied from class: Solver
      Executes the solver algorithm to analyze the model. This abstract method must be implemented by concrete solver classes.
      Specified by:
      runAnalyzer in class Solver
      Throws:
      IllegalAccessException - if access to required resources is denied
    • getNormalizingConstant

      public SolverNC.NormalizingConstantResult getNormalizingConstant() throws IllegalAccessException
      Get the normalizing constant and its logarithm
      Returns:
      NormalizingConstantResult containing the normalizing constant and its logarithm
      Throws:
      IllegalAccessException - if analysis fails
    • listValidMethods

      public String[] listValidMethods()
      List all valid solution methods for this solver
      Returns:
      array of valid method names
    • meOpen

      public NCResult meOpen()
      Maximum Entropy algorithm for Open Queueing Networks. Applies the ME algorithm from Kouvatsos (1994) to the model. Only supports open queueing networks (no closed classes).
      Returns:
      NCResult containing ME algorithm results
    • memUnsupportedReason

      public static String memUnsupportedReason(NetworkStruct sn)
      Returns null when the Maximum Entropy Method (Kouvatsos 1994) supports the features of the model described by sn (node types, class switching, scheduling, source presence); otherwise a message describing the first unsupported feature. Open/closed class membership is checked separately on the model; this overload assumes the open-network variant.
    • memUnsupportedReason

      public static String memUnsupportedReason(NetworkStruct sn, boolean closed)
      Returns null when the Maximum Entropy Method (Kouvatsos 1994) supports the features of the model described by sn; otherwise a message describing the first unsupported feature. Open models (Section 3.2) allow Source, Queue, Delay and Sink nodes with GE/GE/1, GE/GE/c and GE/GE/inf building blocks; closed models (Section 3.3) allow Queue and Delay nodes with G/G/1 and G/G/inf building blocks only, so finite multiserver stations are rejected.
    • memUnsupportedReason

      public static String memUnsupportedReason(NetworkStruct sn, boolean hasOpen, boolean hasClosed)
      Feature check for the Maximum Entropy Method given the class composition of the model: hasOpen/hasClosed flag the presence of open and closed classes (both true for mixed models). Returns null when supported, otherwise the first unsupported feature found.
    • memBufferSize

      public static double memBufferSize(NetworkStruct sn, int ist)
      Physical buffer size of a station in jobs, in service included: the tighter of the station capacity and the sum of the per-class capacities, infinite when the station is unbounded.

      Only a buffer that can actually BIND is reported. refreshCapacity derives a FINITE classcap (the chain population) for EVERY closed model, so a plain finiteness test would report a buffer at every station of every closed model; a capacity at least as large as the total population can never refuse a job and is returned as infinite. The population sum is infinite as soon as one class is open, so any finite capacity reachable by an open class binds.

      Parameters:
      sn - network structure
      ist - station index
      Returns:
      buffer size in jobs
    • memDropRule

      public static DropStrategy memDropRule(NetworkStruct sn, int ist)
      Drop rule declared at a station for the first class, defaulting to Drop, which is what refreshCapacity assigns to a finite buffer reachable by an open class.
      Parameters:
      sn - network structure
      ist - station index
      Returns:
      the drop strategy in force at the station
    • memHasFiniteBuffers

      public static boolean memHasFiniteBuffers(NetworkStruct sn)
      True when the model is a single-class open network carrying a finite buffer that MEM represents explicitly, as a censored GE/GE/c/0;N queue. Callers use it to bypass the product-form capacity gate, which exists because the other NC methods have no representation of a buffer.
      Parameters:
      sn - network structure
      Returns:
      true when the finite-buffer MEM path applies
    • meClosed

      public NCResult meClosed()
      Maximum Entropy algorithm for Closed Queueing Networks (Kouvatsos 1994, Section 3.3): pseudo-open decomposition followed by a convolution over the population lattice, iterated on the flow (work rate) equations.
      Returns:
      NCResult containing the closed ME algorithm results
    • meClosed

      public NCResult meClosed(MeOqnOptions meOptions)
      Maximum Entropy algorithm for Closed Queueing Networks with custom options (Kouvatsos 1994, Section 3.3).
      Parameters:
      meOptions - options for the ME algorithm
      Returns:
      NCResult containing the closed ME algorithm results
    • meMixed

      public NCResult meMixed()
      Maximum Entropy algorithm for Mixed Queueing Networks: composition of the open (Section 3.2) and closed (Section 3.3) algorithms with product-form-style conditioning.
      Returns:
      NCResult containing the mixed ME algorithm results
    • meMixed

      public NCResult meMixed(MeOqnOptions meOptions)
      Maximum Entropy algorithm for Mixed Queueing Networks with custom options.
      Parameters:
      meOptions - options for the ME algorithm
      Returns:
      NCResult containing the mixed ME algorithm results
    • meOpen

      public NCResult meOpen(MeOqnOptions meOptions)
      Maximum Entropy algorithm for Open Queueing Networks with custom options. Applies the ME algorithm from Kouvatsos (1994) to the model. Only supports open queueing networks (no closed classes).
      Parameters:
      meOptions - Options for the ME algorithm
      Returns:
      NCResult containing ME algorithm results
    • sample

      public Object sample(Node node, int numEvents)
      Sample node state trajectory
      Parameters:
      node - The node to sample
      numEvents - Number of samples to generate
      Returns:
      Sample result containing state trajectory
    • sample

      public Object sample(Node node)
      Sample node state trajectory with default number of samples
      Parameters:
      node - The node to sample
      Returns:
      Sample result containing state trajectory
    • supports

      public boolean supports(Network model)
      Checks whether the given model is supported by the NC solver
      Overrides:
      supports in class Solver
      Parameters:
      model - - the network model
      Returns:
      - true if the model is supported, false otherwise
    • memFiniteBufferPath

      public static boolean memFiniteBufferPath(NetworkStruct sn, SolverOptions options)
      True when method='mem' has been requested on a model whose finite buffers MEM carries explicitly. Callers use it to skip the product-form capacity gate, which exists only because the other NC methods cannot represent a buffer.
      Parameters:
      sn - network structure
      options - solver options, whose method selects MEM
      Returns:
      true when the finite-buffer MEM path applies
    • resolveMethod

      public String resolveMethod(SolverOptions options)
      Feature-driven resolution of method='default': an open network with non-Markovian (non-unit SCV) variability within the MEM feature set is solved by the Maximum Entropy Method by default, since the normalizing-constant path would silently exponentialize it. Mirrors the dispatch in runAnalyzer and the MATLAB/Python SolverNC.resolveMethod.
      Overrides:
      resolveMethod in class Solver
      Parameters:
      options - the solver options
      Returns:
      the concrete method name
    • methodFeatureSet

      public static FeatureSet methodFeatureSet(String method)
      Per-method feature deltas applied to the base NC envelope. ONLY THE RESTRICTIONS A FEATURE NAME CAN CARRY LIVE HERE. A feature set declares what the method ACCEPTS, so it can refuse a model for HAVING a construct and never for lacking one: "closed population only" and "no think time" are expressible by dropping OpenClass and SchedStrategy_INF, while "requires a cache" or "requires a loss network" are not and belong to ncMethodRefusal(jline.lang.NetworkStruct, java.lang.String, jline.solvers.SolverOptions), which supportsModelMethod consults next. Mirrors the MATLAB/python SolverNC.getMethodFeatureSet and the C++ nc_feature_set.
      Parameters:
      method - the concrete method name
      Returns:
      the per-method FeatureSet
    • getMethodFeatureSet

      public FeatureSet getMethodFeatureSet(String method)
      Description copied from class: Solver
      Per-method feature set, or null to signal "this solver does not diverge per method" (the coarse supports(model) is then used, preserving any structural checks it carries). Divergent solvers (e.g. MVA, MAM, NC) override this to return the base envelope with per-method deltas applied.
      Overrides:
      getMethodFeatureSet in class Solver
      Parameters:
      method - the concrete method name
      Returns:
      the per-method FeatureSet, or null
    • ncMethodRefusal

      public static String ncMethodRefusal(NetworkStruct sn, String method, SolverOptions options)
      May METHOD run on this model? Empty string when it may, otherwise the reason it may not, in the words the analyzer refuses with. ONE PREDICATE, TWO CALLERS. runAnalyzer asks it once, ahead of the dispatch, and turns a non-empty answer into an error; supportsModelMethod(java.lang.String) asks it so that Network.findSolver never offers a (solver, method) pair that would raise, and so that SolverAUTO never delegates to one. Two copies of these rules is precisely how the report and the run drift apart, which is the failure this method exists to prevent, so a new rule goes here and not at a call site. Only what the feature registry cannot name lives here; see methodFeatureSet(java.lang.String) for the rules that do have a feature name.
      Parameters:
      sn - the network struct
      method - the concrete method name
      options - the solver options, read for the discrete-time route only
      Returns:
      empty string if the method may run, else the offending reason
    • ncMethodRefusal

      public static String ncMethodRefusal(NetworkStruct sn, String method, SolverOptions options, boolean forReport)
      The same predicate, told WHICH QUESTION IS BEING ASKED. For two method names the two questions have different answers:
      • forReport = true -- "should model.help() offer this pair?" A pair that comes back as a table of zeros must not be offered, so the answer is no.
      • forReport = false -- "what does the reference DO when asked for it by name?" For "mmint2" and "gleint" outside their shape the reference deliberately WARNS AND RETURNS A ZERO TABLE (pfqn_nc.m, case {'mmint2','gleint'}: lG = [] and return, unconditionally), and a caller who names the method keeps that answer.

      THE ASYMMETRY IS A RULING, NOT AN OVERSIGHT (2026-07-25, reaffirmed when this gate was added): the report answers "should this be offered" and the run answers "what does the reference do". "comomld" is NOT in that bucket -- Pfqn_comomrm_ld raises "The solver accepts at most a single queueing station." natively -- so it is refused on both paths.

      Parameters:
      sn - the network struct
      method - the concrete method name
      options - the solver options, read for the discrete-time route only
      forReport - true when the caller is the report, false when it is the run
      Returns:
      empty string if the method may run, else the offending reason
    • ncLossnKind

      public static int ncLossnKind(NetworkStruct sn)
      The loss-network verdict: 0 for neither, 1 for the shape without the DROP rule, 2 for the loss network Solver_nc_lossn_analyzer solves. The shape is an OPEN model with a single finite capacity region whose only member is an infinite server. It is a LOSS network when the admission rule DROPS every class: a region of that shape under WAITQ (or any blocking rule) holds the arrival back instead of discarding it, which keeps the job in the region while it waits and is a queueing phenomenon the Erlang loss model has no state for. The two verdicts are separate because they have different remedies -- switching the rule to DROP makes the first solvable here, while a region on queueing stations needs a solver that carries the region as state.
      Parameters:
      sn - the network struct
      Returns:
      0, 1 or 2 as above
    • ncIsNormalUsage

      public static boolean ncIsNormalUsage(NetworkStruct sn)
      Is the closed model in NORMAL USAGE, the domain of the Mitra-McKenna PANACEA asymptotic expansion (J. ACM 33(3), 1986)? Normal usage asks that every queueing centre absorb the load the think stations offer it: with rho_j0 = Ztot(j) the aggregate think demand of chain j, r_ij = L_ij / rho_j0 and mu_i(Ntot) the saturation rate, alpha_i = 1 - (sum_j N_j r_ij) / mu_i(Ntot) > 0 at every centre i. Outside it the {phi(n)} series DIVERGES, which is why Pfqn_panaceald returns NaN there and Pfqn_ncld turns that NaN into a refusal. It is a property of the demands and not of a declared construct, so it has no feature-registry name. The rates are the ones Solver_ncld would build: 1 for an ordinary single server, min(n,c) for a finite multiserver (the conversion runAnalyzer performs on the "panald" arm), and the declared lldscaling row when the model sets one. An infinite server is a think station and feeds Ztot.
      Parameters:
      sn - the network struct
      Returns:
      true when the expansion applies
    • supportsModelMethod

      public String supportsModelMethod(String method)
      Method-aware gate. MEM (Kouvatsos maximum entropy) has structural applicability rules beyond a flat feature set (open-only, Source/Queue/ Delay/Sink, non-priority scheduling); delegate to memUnsupportedReason, which returns a precise reason (null when supported). All other NC methods use the coarse product-form feature gate.
      Overrides:
      supportsModelMethod in class Solver
      Parameters:
      method - the concrete method name
      Returns:
      empty string if supported, else the offending reason
    • supportsModelMethod

      public String supportsModelMethod(String method, boolean forReport)
      The same gate, told WHICH QUESTION IS BEING ASKED. The report asks "should this pair be offered" and the run asks "what does the reference do"; they differ only for "mmint2"/"gleint", which the reference performs by name and answers with a zero table. See ncMethodRefusal(NetworkStruct, String, SolverOptions, boolean).

      The distinction has to be plumbed because the shared runAnalyzerChecks gate lives on the RUN path yet reaches this method through the same one-argument call findSolver makes, so there is no other way to tell the two callers apart.

      Parameters:
      method - the concrete method name
      forReport - true when the caller is the report, false when it is the run
      Returns:
      empty string if supported, else the offending reason
    • exactnessReason

      public static String exactnessReason(Network model, String method)
      Product-form precondition of the normalizing-constant methods, the same rule runAnalyzer enforces at solve time. Only "exact", "is" and "panald" require it -- the other methods fall back to Seidmann's comom on a non-product-form model -- and "is" on a pass-and-swap model is exempt (Pfqn_pas_is). Product form has no registry feature name, so the check cannot live in getMethodFeatureSet.
      Parameters:
      model - the network model
      method - the concrete method name
      Returns:
      empty string if the method may run, else the offending reason
    • isStochasticMethod

      public boolean isStochasticMethod(String method)
      NC is deterministic except for the Monte Carlo integration methods (mci/imci), logistic sampling (ls), and the sampling method, whose estimates depend on the random seed. Method names are tokenized so that runtime-resolved names such as "default/imci" and prefixed names such as "nc.ls" classify correctly.
      Overrides:
      isStochasticMethod in class Solver
      Parameters:
      method - the method name to classify
      Returns:
      true if the method returns stochastic estimates
    • supportsModel

      public static boolean supportsModel(Network model)
      Static method to check whether the given model is supported by the NC solver. This allows checking support without creating a solver instance.
      Parameters:
      model - - the network model
      Returns:
      - true if the model is supported, false otherwise
    • getCdfRespTFirstProbe

      public Matrix getCdfRespTFirstProbe()
      First-probe-time summary of the response time CDF, one scalar per station and class. NOT A DISTRIBUTION. This was called getCdfRespT(AvgHandle...) and was renamed because that name made it an OVERLOAD of the base NetworkSolver.getCdfRespT(AvgHandle) rather than an override -- varargs erases to AvgHandle[], so one handle reached the base implementation and zero handles reached this class, two implementations behind one name selected by argument count. For the CDF itself, one (T x 2) matrix of [F(t) t] per station and class as MATLAB's cell array carries, call getCdfRespT() and read its cdfData.
      Returns:
      first-probe-time CDF summary, indexed by station and class
    • getCdfRespT

      public Ret.DistributionResult getCdfRespT()
      Get the response time CDF at FCFS and delay stations. cdfData is indexed [station][class], each entry a (T x 2) matrix of [F(t) t], matching MATLAB's RD cell array and the layout SolverJMT fills. Entries are null where the pair has no distribution. This used to compute the curves and DISCARD them, returning the empty structure initializeCdfData allocates.
      Overrides:
      getCdfRespT in class NetworkSolver
      Returns:
      the response time distributions, station by class
    • getCdfRespT

      public Ret.DistributionResult getCdfRespT(AvgHandle R)
      Response time CDF, ignoring the handle argument as the reference does. THIS GENUINELY OVERRIDES NetworkSolver.getCdfRespT(AvgHandle). Before it existed, SolverNC declared only a varargs method, which erases to AvgHandle[] and therefore did NOT override the base: a caller passing one handle silently received the base class's EXPONENTIAL FIT of the mean response time, while a caller passing none received this class's exact law. Both returned plausible numbers, so nothing looked wrong. The two now agree because both delegate to computeCdfRespT().
      Overrides:
      getCdfRespT in class NetworkSolver
      Parameters:
      R - response time handles, unused -- the CDF is computed at every station and class, as MATLAB's getCdfRespT.m does
      Returns:
      the response time distributions, station by class
    • getAvgBusyPeriod

      public double[] getAvgBusyPeriod(int[] stations, int[] orders)
      Mean duration of the busy period of order n for the subnetwork made of the given stations, that is the time from the instant a job entering the subnetwork finds n-1 jobs in it up to the next instant when fewer than n remain.

      H. Daduna, "Busy Periods for Subnetworks in Stochastic Networks: Mean Value Analysis", J. ACM 35(3), 1988. The result is exact on the single-chain product-form class and, by the insensitivity of Section 5 of that paper, depends on the service processes only through their mean rates.

      The Java twin of MATLAB's @SolverNC/getAvgBusyPeriod.m and of solver_nc_busyp in the C++ port, which this follows step for step. It had no Java spelling until now, so -a busyperiod on the CLI and every lang="java" caller had to fall back to SolverLDES, i.e. to a simulation of a quantity there is a transform for.

      Parameters:
      stations - zero-based STATION indexes forming the subnetwork; a non-empty proper subset of the stations
      orders - busy period orders, 1 <= n <= population for a closed model
      Returns:
      one mean duration per requested order
    • getAvgBusyPeriod

      public double getAvgBusyPeriod(int[] stations, int order)
      Single-order form of getAvgBusyPeriod(int[], int[]).