LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
SolverLQNS.m
1classdef SolverLQNS < Solver
2 % A solver that interfaces the LQNS to LINE.
3 %
4 % Copyright (c) 2012-2026, Imperial College London
5 % All rights reserved.
6
7 methods
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);']);
22 end
23 end
24
25 function sn = getStruct(self)
26 %GETSTRUCT Retrieve the model structure
27 sn = self.model.getStruct();
28 end
29
30 function varargout = getAvg(varargin)
31 %GETAVG Proxy to getEnsembleAvg
32 [varargout{1:nargout}] = getEnsembleAvg(varargin{:});
33 end
34
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([]);
39 return
40 end
41
42 if ~isempty(self.obj)
43 avgTable = self.obj.getEnsembleAvg();
44 [QN,UN,RN,WN,AN,TN] = JLINE.arrayListToResults(avgTable);
45 else
46 [QN,UN,RN,TN,AN,WN] = getAvg(self);
47 end
48
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;
55 end
56 [QN, UN, RN, TN, AN, WN] = deal(variables{:}); % Assign the modified values back to the original variables
57
58 %%
59 lqn = self.model.getStruct;
60 Node = label(lqn.names);
61 O = length(Node);
62 NodeType = label(O,1);
63 for o = 1:O
64 switch lqn.type(o)
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'});
70 else
71 NodeType(o,1) = label({'Task'});
72 end
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'});
79 end
80 end
81 QLen = QN;
82 QT = Table(Node,QLen);
83 Util = UN;
84 UT = Table(Node,Util);
85 RespT = RN;
86 RT = Table(Node,RespT);
87 Tput = TN;
88 TT = Table(Node,Tput);
89 %SvcT = SN;
90 %ST = Table(Node,SvcT);
91 %ProcUtil = PN;
92 %PT = Table(Node,ProcUtil);
93 ResidT = WN;
94 WT = Table(Node,ResidT);
95 ArvR = AN;
96 AT = Table(Node,ArvR);
97 AvgTable = Table(Node, NodeType, QLen, Util, RespT, ResidT, ArvR, Tput);%, ProcUtil, SvcT);
98 end
99 end
100
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);
106
107 function allMethods = listValidMethods(self)
108 %LISTVALIDMETHODS List valid solving methods for LQNS
109 sn = self.model.getStruct();
110 allMethods = {
111 'default', 'lqns', 'srvn', 'exactmva', ...
112 'srvn.exactmva', 'sim', 'lqsim', 'lqnsdefault'
113 };
114 end
115 end
116
117 methods (Static)
118
119
120 function bool = isAvailable()
121 %ISAVAILABLE Check if LQNS is available on the system path
122 bool = true;
123 if ispc
124 [~, ret] = dos('lqns -V -H');
125 if contains(ret, 'not recognized', 'IgnoreCase', true)
126 bool = false;
127 return;
128 end
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.');
136 end
137 else
138 [~, ret] = unix('lqns -V -H');
139 if contains(ret, 'command not found', 'IgnoreCase', true)
140 bool = false;
141 return;
142 end
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.');
150 end
151 end
152 end
153
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({ ...
159 'Sink', ...
160 'Source', ...
161 'Queue', ...
162 'Coxian', ...
163 'Erlang', ...
164 'Exp', ...
165 'HyperExp', ...
166 'Buffer', ...
167 'Server', ...
168 'JobSink', ...
169 'RandomSource', ...
170 'ServiceTunnel', ...
171 'SchedStrategy_PS', ...
172 'SchedStrategy_FCFS', ...
173 'ClosedClass' ...
174 });
175
176 bool = true;
177 numLayers = model.getNumberOfLayers();
178 for idx = 1:numLayers
179 bool = bool && SolverFeatureSet.supports( ...
180 featSupported, featUsed{idx} ...
181 );
182 end
183 end
184
185 function options = defaultOptions()
186 %DEFAULTOPTIONS Return default options for SolverLQNS
187 options = SolverOptions('LQNS');
188 end
189
190 end
191end