LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
runAnalyzer.m
1function runtime = runAnalyzer(self, options)
2% RUNTIME = RUN()
3% Run the solver
4
5tic;
6if nargin<2
7 options = self.getOptions;
8end
9line_debug(options, 'LQNS: starting (method=%s, multiserver=%s)', options.method, options.config.multiserver);
10
11% Resolve the execution backend before choosing the temp dir. options.config.container:
12% '' -> native binary; fall back to Docker only if lqns is missing
13% 'auto'/true-> prefer Docker when a local imperialqore/lqns image exists
14% '<image>' -> use the named image if present locally
15% Docker sidesteps the MATLAB libstdc++/GLIBCXX clash noted below and pins a
16% reproducible lqns version, so tests opt into 'auto'.
17dockerImage = '';
18useRemote = isfield(options.config, 'remote') && options.config.remote;
19if isunix && ~useRemote
20 reqContainer = '';
21 if isfield(options.config, 'container')
22 reqContainer = options.config.container;
23 end
24 if isempty(reqContainer) && ~SolverLQNS.hasLocalBinary()
25 % Native lqns absent: transparently fall back to a Docker image.
26 reqContainer = 'auto';
27 end
28 if ~isempty(reqContainer)
29 dockerImage = SolverLQNS.getDockerImage(reqContainer);
30 end
31end
32
33% Snap-confined Docker cannot bind-mount the system temp dir; stage the model
34% under HOME when dispatching through Docker so the volume mount is visible.
35dirpath = lineTempName('lqns', ~isempty(dockerImage));
36filename = [dirpath,filesep,'model.lqnx'];
37self.model.writeXML(filename);
38
39%self.runAnalyzerChecks(options);
40Solver.resetRandomGeneratorSeed(options.seed);
41
42if options.verbose
43 %verbose = '-v';
44 verbose = '';
45else
46 verbose = '-a -w';
47end
48
49multiserver_praqma = '';
50switch options.method
51 case 'lqsim'
52 %no-op
53 otherwise
54 switch options.config.multiserver
55 case 'conway'
56 multiserver_praqma='-Pmultiserver=conway';
57 case 'rolia'
58 multiserver_praqma='-Pmultiserver=rolia';
59 case 'zhou'
60 multiserver_praqma='-Pmultiserver=zhou';
61 case 'suri'
62 multiserver_praqma='-Pmultiserver=suri';
63 case 'reiser'
64 multiserver_praqma='-Pmultiserver=reiser';
65 case 'schmidt'
66 multiserver_praqma='-Pmultiserver=schmidt';
67 case 'default'
68 multiserver_praqma='-Pmultiserver=rolia';
69 end
70end
71
72if isunix
73 % switch options.method
74 % case {'default','lqns'}
75 % cmd=['lqns ',verbose,' ',multiserver_praqma,' --iteration-limit=',num2str(options.iter_max),' -Pstop-on-message-loss=false -x ',filename]);
76 % case {'srvn'}
77 % cmd=['lqns ',verbose,' ',multiserver_praqma,' --iteration-limit=',num2str(options.iter_max),' -Playering=srvn -Pstop-on-message-loss=false -x ',filename]);
78 % case {'exactmva'}
79 % cmd=['lqns ',verbose,' ',multiserver_praqma,' --iteration-limit=',num2str(options.iter_max),' -Pmva=exact -Pstop-on-message-loss=false -x ',filename]);
80 % case {'srvnexact'}
81 % cmd=['lqns ',verbose,' ',multiserver_praqma,' --iteration-limit=',num2str(options.iter_max),' -Playering=srvn -Pmva=exact -Pstop-on-message-loss=false -x ',filename]);
82 % case {'sim','lqsim'}
83 % cmd=['lqsim ',verbose,' ',multiserver_praqma,' -A ',num2str(options.samples),',3 -Pstop-on-message-loss=false -x ',filename]);
84 % case {'lqnsdefault'}
85 % cmd=['lqns ',verbose,' ',multiserver_praqma,' -x ',filename]);
86 % otherwise
87 % cmd=['lqns ',verbose,' ',multiserver_praqma,' --iteration-limit=',num2str(options.iter_max),' -Pstop-on-message-loss=false -x ',filename]);
88 % end
89
90 % --iteration-limit seems faulty as of 6.2.27
91 if options.verbose
92 switch options.method
93 case {'default','lqns'}
94 cmd=['lqns ',verbose,' ',multiserver_praqma,' -Pstop-on-message-loss=false -x ',filename];
95 case {'srvn'}
96 cmd=['lqns ',verbose,' ',multiserver_praqma,' -Playering=srvn -Pstop-on-message-loss=false -x ',filename];
97 case {'exactmva'}
98 cmd=['lqns ',verbose,' ',multiserver_praqma,' -Pmva=exact -Pstop-on-message-loss=false -x ',filename];
99 case {'srvn.exactmva'}
100 cmd=['lqns ',verbose,' ',multiserver_praqma,' -Playering=srvn -Pmva=exact -Pstop-on-message-loss=false -x ',filename];
101 case {'sim','lqsim'}
102 cmd=['lqsim ',verbose,' ',multiserver_praqma,' -A ',num2str(options.samples),',3 -Pstop-on-message-loss=false -x ',filename];
103 case {'lqnsdefault'}
104 cmd=['lqns ',verbose,' ',multiserver_praqma,' -x ',filename];
105 otherwise
106 cmd=['lqns ',verbose,' ',multiserver_praqma,' -Pstop-on-message-loss=false -x ',filename];
107 end
108 else
109 switch options.method
110 case {'default','lqns'}
111 cmd=['lqns ',verbose,' ',multiserver_praqma,' -Pstop-on-message-loss=false -x ',filename,' 2>&1'];
112 case {'srvn'}
113 cmd=['lqns ',verbose,' ',multiserver_praqma,' -Playering=srvn -Pstop-on-message-loss=false -x ',filename,' 2>&1'];
114 case {'exactmva'}
115 cmd=['lqns ',verbose,' ',multiserver_praqma,' -Pmva=exact -Pstop-on-message-loss=false -x ',filename,' 2>&1'];
116 case {'srvn.exactmva'}
117 cmd=['lqns ',verbose,' ',multiserver_praqma,' -Playering=srvn -Pmva=exact -Pstop-on-message-loss=false -x ',filename,' 2>&1'];
118 case {'sim','lqsim'}
119 cmd=['lqsim ',verbose,' ',multiserver_praqma,' -A ',num2str(options.samples),' -Pstop-on-message-loss=false -x ',filename,' 2>&1'];
120 case {'lqnsdefault'}
121 cmd=['lqns ',verbose,' ',multiserver_praqma,' -x ',filename,' 2>&1'];
122 otherwise
123 cmd=['lqns ',verbose,' ',multiserver_praqma,' -Pstop-on-message-loss=false -x ',filename,' 2>&1'];
124 end
125 end
126else
127 switch options.method
128 % case {'default','lqns'}
129 % cmd=['lqns ',verbose,' ',multiserver_praqma,' -i ',num2str(options.iter_max),' -Pstop-on-message-loss=false -x ',filename]);
130 % case {'srvn'}
131 % cmd=['lqns ',verbose,' ',multiserver_praqma,' -i ',num2str(options.iter_max),' -Playering=srvn -Pstop-on-message-loss=false -x ',filename]);
132 % case {'exactmva'}
133 % cmd=['lqns ',verbose,' ',multiserver_praqma,' -i ',num2str(options.iter_max),' -Pmva=exact -Pstop-on-message-loss=false -x ',filename]);
134 % case {'srvnexact'}
135 % cmd=['lqns ',verbose,' ',multiserver_praqma,' -i ',num2str(options.iter_max),' -Playering=srvn -Pmva=exact -Pstop-on-message-loss=false -x ',filename]);
136 % case {'sim','lqsim'}
137 % cmd=['lqsim ',verbose,' ',multiserver_praqma,' -A ',num2str(options.samples),',3 -Pstop-on-message-loss=false -x ',filename]);
138 % case {'lqnsdefault'}
139 % cmd=['lqns ',verbose,' ',multiserver_praqma,' -x ',filename]);
140 % otherwise
141 % cmd=['lqns ',verbose,' ',multiserver_praqma,' -i ',num2str(options.iter_max),' -Pstop-on-message-loss=false -x ',filename]);
142 case {'default','lqns'}
143 cmd=['lqns ',verbose,' ',multiserver_praqma,' -Pstop-on-message-loss=false -x ',filename];
144 case {'srvn'}
145 cmd=['lqns ',verbose,' ',multiserver_praqma,' -Playering=srvn -Pstop-on-message-loss=false -x ',filename];
146 case {'exactmva'}
147 cmd=['lqns ',verbose,' ',multiserver_praqma,' -Pmva=exact -Pstop-on-message-loss=false -x ',filename];
148 case {'srvn.exactmva'}
149 cmd=['lqns ',verbose,' ',multiserver_praqma,' -Playering=srvn -Pmva=exact -Pstop-on-message-loss=false -x ',filename];
150 case {'sim','lqsim'}
151 %cmd=['lqsim ',verbose,' ',multiserver_praqma,' -Pstop-on-message-loss=false -x ',filename];
152 cmd=['lqsim ',verbose,' ',multiserver_praqma,' -A ',num2str(options.samples),' -Pstop-on-message-loss=false -x ',filename];
153 case {'lqnsdefault'}
154 cmd=['lqns ',verbose,' ',multiserver_praqma,' -x ',filename];
155 otherwise
156 cmd=['lqns ',verbose,' ',multiserver_praqma,' -Pstop-on-message-loss=false -x ',filename];
157 end
158end
159if ~isempty(dockerImage)
160 % Rewrite the local invocation to run inside the container. The temp dir
161 % is bind-mounted at the same absolute path so the model/result file paths
162 % embedded in cmd resolve unchanged; --user matches the host uid/gid so the
163 % .lqxo output stays host-owned and rmdir cleanup succeeds. The image's
164 % 'lqns' is a REST wrapper, so call the real 'lqns.original' binary.
165 [~, hostUid] = unix('id -u'); hostUid = strtrim(hostUid);
166 [~, hostGid] = unix('id -g'); hostGid = strtrim(hostGid);
167 dockerPrefix = ['docker run --rm --user ', hostUid, ':', hostGid, ...
168 ' -v ', dirpath, ':', dirpath, ' -w ', dirpath, ' ', dockerImage, ' '];
169 if strncmp(cmd, 'lqns ', 5)
170 cmd = [dockerPrefix, 'lqns.original ', cmd(6:end)];
171 elseif strncmp(cmd, 'lqsim ', 6)
172 cmd = [dockerPrefix, 'lqsim ', cmd(7:end)];
173 end
174end
175
176if options.verbose
177% line_printf('\nLQNS model: %s',filename);
178 line_printf('\nLQNS command: %s\n',cmd);
179end
180
181% Check for remote execution
182if useRemote
183 line_debug(options, 'LQNS: using remote execution at %s', options.config.remote_url);
184 if options.verbose
185 line_printf('\nUsing remote LQNS at: %s\n', options.config.remote_url);
186 end
187 self.runRemoteLQNS(filename, options);
188else
189 line_debug(options, 'LQNS: using local execution, command: %s', cmd);
190 % Local execution.
191 %
192 % MATLAB prepends its bundled runtime libraries to LD_LIBRARY_PATH before
193 % spawning child processes. Its libstdc++ (e.g. GLIBCXX_3.4.28 in R2024a)
194 % is older than the one lqns/lqsim require (GLIBCXX_3.4.29+), so the
195 % binaries abort with a "version `GLIBCXX_...' not found" error before
196 % writing their .lqxo output. That later surfaces as a FileNotFoundException
197 % in parseXMLResults. Strip LD_LIBRARY_PATH for the child so it resolves the
198 % system libstdc++ instead of MATLAB's.
199 if isunix && isempty(dockerImage)
200 cmd = ['env -u LD_LIBRARY_PATH ', cmd];
201 end
202 system(cmd);
203end
204self.parseXMLResults(filename);
205
206if ~options.keep
207 rmdir(dirpath,'s');
208end
209runtime = toc;
210end
Definition Station.m:245