1classdef SolverLQNS < Solver
2 % A solver that interfaces the LQNS to LINE.
4 % Copyright (c) 2012-2026, Imperial College London
8 function self = SolverLQNS(model, varargin)
9 % SELF = SOLVERLQNS(MODEL, VARARGIN)
10 self@Solver(model, mfilename);
11 self.setOptions(Solver.parseOptions(varargin, self.defaultOptions));
12 if ~SolverLQNS.isAvailable() && ~self.options.config.remote
13 line_error(mfilename,[
'SolverLQNS requires the lqns and lqsim commands to be available on the system path.\n' ...
14 'You can install them from: http://www.sce.carleton.ca/rads/lqns/\n\n' ...
15 'Alternatively, use remote execution via Docker:\n' ...
16 ' 1. Pull and run: docker run -d -p 8080:8080 imperialqore/lqns-rest:latest\n' ...
17 ' 2. Configure remote execution in MATLAB:\n' ...
18 ' options = SolverOptions(@()SolverLQNS);\n' ...
19 ' options.config.remote = true;\n' ...
20 ' options.config.remote_url = ''http://localhost:8080'';\n' ...
21 ' solver = SolverLQNS(model, options);']);
25 function sn = getStruct(self)
26 %GETSTRUCT Retrieve the model structure
27 sn = self.model.getStruct();
30 function varargout = getAvg(varargin)
31 %GETAVG Proxy to getEnsembleAvg
32 [varargout{1:nargout}] = getEnsembleAvg(varargin{:});
35 function [AvgTable,QT,UT,
RT,WT,AT,TT] = getAvgTable(self)
36 % [AVGTABLE,QT,UT,
RT,WT,TT] = GETAVGTABLE()
37 if (GlobalConstants.DummyMode)
38 [AvgTable, QT, UT,
RT, TT, WT] = deal([]);
43 avgTable = self.obj.getEnsembleAvg();
44 [QN,UN,RN,WN,AN,TN] = JLINE.arrayListToResults(avgTable);
46 [QN,UN,RN,TN,AN,WN] = getAvg(self);
49 % attempt to sanitize small numerical perturbations
50 variables = {QN, UN, RN, TN, AN, WN}; % Put all variables in a cell array
51 for i = 1:length(variables)
52 rVar = round(variables{i} * 10);
53 toRound = abs(variables{i} * 10 - rVar) < GlobalConstants.CoarseTol * variables{i} * 10;
54 variables{i}(toRound) = rVar(toRound) / 10;
56 [QN, UN, RN, TN, AN, WN] = deal(variables{:}); % Assign the modified values back to the original variables
59 lqn = self.model.getStruct;
60 Node = label(lqn.names);
62 NodeType = label(O,1);
65 case LayeredNetworkElement.PROCESSOR
66 NodeType(o,1) = label({
'Processor'});
67 case LayeredNetworkElement.TASK
68 if self.model.getStruct.isref(o)
69 NodeType(o,1) = label({
'RefTask'});
71 NodeType(o,1) = label({
'Task'});
73 case LayeredNetworkElement.ENTRY
74 NodeType(o,1) = label({
'Entry'});
75 case LayeredNetworkElement.ACTIVITY
76 NodeType(o,1) = label({
'Activity'});
77 case LayeredNetworkElement.CALL
78 NodeType(o,1) = label({
'Call'});
82 QT = Table(Node,QLen);
84 UT = Table(Node,Util);
86 RT = Table(Node,RespT);
88 TT = Table(Node,Tput);
90 %ST = Table(Node,SvcT);
92 %PT = Table(Node,ProcUtil);
94 WT = Table(Node,ResidT);
96 AT = Table(Node,ArvR);
97 AvgTable = Table(Node, NodeType, QLen, Util, RespT, ResidT, ArvR, Tput);%, ProcUtil, SvcT);
101 methods % implemented in .m files
102 runtime = runAnalyzer(self, options);
103 [result, iterations] = parseXMLResults(self, filename);
104 [QN,UN,RN,TN,AN,WN] = getEnsembleAvg(self);
105 savedfname = plot(model);
107 function allMethods = listValidMethods(self)
108 %LISTVALIDMETHODS List valid solving methods
for LQNS
109 sn = self.model.getStruct();
111 'default',
'lqns',
'srvn',
'exactmva', ...
112 'srvn.exactmva',
'sim',
'lqsim',
'lqnsdefault'
120 function
bool = isAvailable()
121 %ISAVAILABLE Check
if LQNS
is available on the system path
124 [~, ret] = dos(
'lqns -V -H');
125 if contains(ret,
'not recognized',
'IgnoreCase',
true)
129 if contains(ret, 'Version 5', 'IgnoreCase', true) || ...
130 contains(ret, 'Version 4', 'IgnoreCase', true) || ...
131 contains(ret, 'Version 3', 'IgnoreCase', true) || ...
132 contains(ret, 'Version 2', 'IgnoreCase', true) || ...
133 contains(ret, 'Version 1', 'IgnoreCase', true)
134 line_warning(mfilename, ...
135 'Unsupported LQNS version. LINE requires Version 6.0 or greater.');
138 [~, ret] = unix('lqns -V -H');
139 if contains(ret, 'command not found', 'IgnoreCase', true)
143 if contains(ret, 'Version 5', 'IgnoreCase', true) || ...
144 contains(ret, 'Version 4', 'IgnoreCase', true) || ...
145 contains(ret, 'Version 3', 'IgnoreCase', true) || ...
146 contains(ret, 'Version 2', 'IgnoreCase', true) || ...
147 contains(ret, 'Version 1', 'IgnoreCase', true)
148 line_warning(mfilename, ...
149 'Unsupported LQNS version. LINE requires Version 6.0 or greater.');
154 function [
bool, featSupported] = supports(model)
155 %SUPPORTS Check if the used features are supported
156 featUsed = model.getUsedLangFeatures();
157 featSupported = SolverFeatureSet;
158 featSupported.setTrue({ ...
171 'SchedStrategy_PS', ...
172 'SchedStrategy_FCFS', ...
177 numLayers = model.getNumberOfLayers();
178 for idx = 1:numLayers
179 bool =
bool && SolverFeatureSet.supports( ...
180 featSupported, featUsed{idx} ...
185 function options = defaultOptions()
186 %DEFAULTOPTIONS Return
default options
for SolverLQNS
187 options = SolverOptions(
'LQNS');