LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
MNetwork.m
1classdef MNetwork < Model
2 % An extended queueing network model.
3 %
4 % Copyright (c) 2012-2026, Imperial College London
5 % All rights reserved.
6
7 properties (Access=private)
8 enableChecks;
9 hasState;
10 logPath;
11 usedFeatures; % structure of booleans listing the used classes
12 % it must be accessed via getUsedLangFeatures that updates
13 % the Distribution classes dynamically
14 end
15
16 properties (Hidden)
17 obj; % empty
18 sn;
19 csMatrix;
20 hasStruct;
21 allowReplace;
22 end
23
24 properties (Hidden)
25 handles;
26 sourceidx; % cached value
27 sinkidx; % cached value
28 end
29
30 properties
31 classes;
32 items;
33 stations;
34 nodes;
35 connections;
36 regions;
37 end
38
39 methods % get methods
40 nodes = getNodes(self)
41 sa = getStruct(self, structType, wantState) % get abritrary representation
42 used = getUsedLangFeatures(self) % get used features
43 ft = getForkJoins(self, rt) % get fork-join pairs
44 [chainsObj,chainsMatrix] = getChains(self, rt) % get chain table
45 [rt,rtNodes,connections,chains,rtNodesByClass,rtNodesByStation] = getRoutingMatrix(self, arvRates) % get routing matrix
46 [Q,U,R,T,A,W] = getAvgHandles(self)
47 Q = getAvgQLenHandles(self);
48 U = getAvgUtilHandles(self);
49 R = getAvgRespTHandles(self);
50 T = getAvgTputHandles(self);
51 A = getAvgArvRHandles(self);
52 W = getAvgResidTHandles(self);
53 [Qt,Ut,Tt] = getTranHandles(self)
54 connections = getConnectionMatrix(self);
55 [absorbingStations, absorbingIdxs] = getAbsorbingStations(self) % get absorbing stations
56 info = getReducibilityInfo(self) % get reducibility analysis
57 end
58
59 methods % ergodicity analysis methods
60 [isErg, info] = isRoutingErgodic(self, P) % check if routing is ergodic
61 P = makeErgodic(self, targetNode) % generate ergodic routing matrix
62 end
63
64 methods % link, reset, refresh methods
65 self = link(self, P)
66 self = relink(self, P)
67 [loggerBefore,loggerAfter] = linkAndLog(self, nodes, classes, P, wantLogger, logPath)
68 sanitize(self);
69
70 reset(self, resetState)
71 resetHandles(self)
72 resetModel(self, resetState)
73 nodes = resetNetwork(self, deleteCSnodes)
74 resetStruct(self)
75
76 refreshStruct(self, hard);
77 [rates, scv, hasRateChanged, hasSCVChanged] = refreshRates(self, statSet, classSet);
78 [ph, mu, phi, phases] = refresProcessPhases(self, statSet, classSet);
79 proctypes = refreshProcessTypes(self);
80 [rt, rtfun, rtnodes] = refreshRoutingMatrix(self, rates);
81 [lt] = refreshLST(self, statSet, classSet);
82 sync = refreshSync(self);
83 classprio = refreshPriorities(self);
84 [sched, schedparam] = refreshScheduling(self);
85 [rates, scv, mu, phi, phases] = refreshProcesses(self, statSet, classSet);
86 [chains, visits, rt] = refreshChains(self, propagate)
87 [cap, classcap] = refreshCapacity(self);
88 nvars = refreshLocalVars(self);
89 end
90
91 % PUBLIC METHODS
92 methods (Access=public)
93
94 %Constructor
95 function self = MNetwork(modelName, varargin)
96 % SELF = NETWORK(MODELNAME)
97 self@Model(modelName);
98 self.nodes = {};
99 self.stations = {};
100 self.classes = {};
101 self.connections = [];
102 initUsedFeatures(self);
103 self.sn = [];
104 self.hasState = false;
105 self.logPath = '';
106 self.items = {};
107 self.regions = {};
108 self.sourceidx = [];
109 self.sinkidx = [];
110 self.setChecks(true);
111 self.hasStruct = false;
112 self.allowReplace = false;
113 end
114
115 setInitialized(self, bool);
116
117 function self = setChecks(self, bool)
118 self.enableChecks = bool;
119 end
120
121 P = getLinkedRoutingMatrix(self)
122
123 function logPath = getLogPath(self)
124 % LOGPATH = GETLOGPATH()
125
126 logPath = self.logPath;
127 end
128
129 function setLogPath(self, logPath)
130 % SETLOGPATH(LOGPATH)
131
132 self.logPath = logPath;
133 end
134
135 bool = hasInitState(self)
136
137 function [M,R] = getSize(self)
138 % [M,R] = GETSIZE()
139
140 M = self.getNumberOfNodes;
141 R = self.getNumberOfClasses;
142 end
143
144 function bool = hasOpenClasses(self)
145 % BOOL = HASOPENCLASSES()
146
147 bool = any(isinf(getNumberOfJobs(self)));
148 end
149
150 function bool = hasClassSwitching(self)
151 % BOOL = HASCLASSSWITCHING()
152
153 bool = any(cellfun(@(c) isa(c,'ClassSwitch'), self.nodes));
154 end
155
156 function bool = hasFork(self)
157 % BOOL = HASFORK()
158
159 bool = any(cellfun(@(c) isa(c,'Fork'), self.nodes));
160 end
161
162 function bool = hasJoin(self)
163 % BOOL = HASJOIN()
164
165 bool = any(cellfun(@(c) isa(c,'Join'), self.nodes));
166 end
167
168 function bool = hasClosedClasses(self)
169 % BOOL = HASCLOSEDCLASSES()
170
171 bool = any(isfinite(getNumberOfJobs(self)));
172 end
173
174 function bool = isMatlabNative(self)
175 % BOOL = ISMATLABNATIVE()
176 %
177 % Returns true for MATLAB native (MNetwork) implementation
178
179 bool = true;
180 end
181
182 function bool = isJavaNative(self)
183 % BOOL = ISJAVANATIVE()
184 %
185 % Returns false for MATLAB native (MNetwork) implementation
186
187 bool = false;
188 end
189
190 function index = getIndexOpenClasses(self)
191 % INDEX = GETINDEXOPENCLASSES()
192
193 index = find(isinf(getNumberOfJobs(self)))';
194 end
195
196 function index = getIndexClosedClasses(self)
197 % INDEX = GETINDEXCLOSEDCLASSES()
198
199 index = find(isfinite(getNumberOfJobs(self)))';
200 end
201
202 function classes = getClasses(self)
203 classes= self.classes;
204 end
205
206 chain = getClassChain(self, className)
207 c = getClassChainIndex(self, className)
208 classNames = getClassNames(self)
209
210 nodeNames = getNodeNames(self)
211 nodeTypes = getNodeTypes(self)
212
213 P = initRoutingMatrix(self)
214
215 ind = getNodeIndex(self, name)
216 lldScaling = getLimitedLoadDependence(self)
217 lcdScaling = getLimitedClassDependence(self)
218
219 function stationIndex = getStationIndex(self, name)
220 % STATIONINDEX = GETSTATIONINDEX(NAME)
221
222 if isa(name,'Node')
223 node = name;
224 name = node.getName();
225 end
226 stationIndex = find(cellfun(@(c) strcmp(c,name),self.getStationNames));
227 end
228
229 function statefulIndex = getStatefulNodeIndex(self, name)
230 % STATEFULINDEX = GETSTATEFULNODEINDEX(NAME)
231
232 if isa(name,'Node')
233 node = name;
234 name = node.getName();
235 end
236 statefulIndex = find(cellfun(@(c) strcmp(c,name),self.getStatefulNodeNames));
237 end
238
239 function classIndex = getClassIndex(self, name)
240 % CLASSINDEX = GETCLASSINDEX(NAME)
241 if isa(name,'JobClass')
242 jobclass = name;
243 name = jobclass.getName();
244 end
245 classIndex = find(cellfun(@(c) strcmp(c,name),self.getClassNames));
246 end
247
248 function stationnames = getStationNames(self)
249 % STATIONNAMES = GETSTATIONNAMES()
250
251 if self.hasStruct
252 nodenames = self.sn.nodenames;
253 isstation = self.sn.isstation;
254 stationnames = {nodenames{isstation}}';
255 else
256 stationnames = {};
257 for i=self.getStationIndexes
258 stationnames{end+1,1} = self.nodes{i}.name;
259 end
260 end
261 end
262
263 function nodes = getNodeByName(self, name)
264 % NODES = GETNODEBYNAME(SELF, NAME)
265 idx = findstring(self.getNodeNames,name);
266 if idx > 0
267 nodes = self.nodes{idx};
268 else
269 nodes = NaN;
270 end
271 end
272
273 function station = getStationByName(self, name)
274 % STATION = GETSTATIONBYNAME(SELF, NAME)
275 idx = findstring(self.getStationNames,name);
276 if idx > 0
277 station = self.stations{idx};
278 else
279 station = NaN;
280 end
281 end
282
283 function class = getClassByName(self, name)
284 % CLASS = GETCLASSBYNAME(SELF, NAME)
285 idx = findstring(self.getClassNames,name);
286 if idx > 0
287 class = self.classes{idx};
288 else
289 class = NaN;
290 end
291 end
292
293 function nodes = getNodeByIndex(self, idx)
294 % NODES = GETNODEBYINDEX(SELF, NAME)
295 if idx > 0
296 nodes = self.nodes{idx};
297 else
298 nodes = NaN;
299 end
300 end
301
302 function station = getStationByIndex(self, idx)
303 % STATION = GETSTATIONBYINDEX(SELF, NAME)
304 if idx > 0
305 station = self.stations{idx};
306 else
307 station = NaN;
308 end
309 end
310
311 function class = getClassByIndex(self, idx)
312 % CLASS = GETCLASSBYINDEX(SELF, NAME)
313 if idx > 0
314 class = self.classes{idx};
315 else
316 class = NaN;
317 end
318 end
319
320 function [infGen, eventFilt, ev] = getGenerator(self, varargin)
321 line_warning(mfilename,'Results will not be cached. Use SolverCTMC(model,...).getGenerator(...) instead.\n');
322 [infGen, eventFilt, ev] = SolverCTMC(self).getGenerator(varargin{:});
323 end
324
325 function [stateSpace,nodeStateSpace] = getStateSpace(self, varargin)
326 line_warning(mfilename,'Results will not be cached. Use SolverCTMC(model,...).getStateSpace(...) instead.\n');
327 [stateSpace,nodeStateSpace] = SolverCTMC(self).getStateSpace(varargin{:});
328 end
329
330 function summary(self)
331 % SUMMARY()
332 for i=1:self.getNumberOfClasses
333 self.classes{i}.summary();
334 if i<self.getNumberOfClasses
335 line_printf('\n');
336 end
337 end
338 for i=1:self.getNumberOfNodes
339 self.nodes{i}.summary();
340 end
341 line_printf('\n<strong>Routing matrix</strong>:');
342 self.printRoutingMatrix
343 line_printf('\n<strong>Product-form parameters</strong>:');
344 [arvRates,servDemands,nJobs,thinkTimes,ldScalings,nServers]= getProductFormParameters(self);
345 line_printf('\nArrival rates: %s',mat2str(arvRates,6));
346 line_printf('\nService demands: %s',mat2str(servDemands,6));
347 line_printf('\nNumber of jobs: %s',mat2str(nJobs));
348 line_printf('\nThink times: %s',mat2str(thinkTimes,6));
349 line_printf('\nLoad-dependent scalings: %s',mat2str(ldScalings,6));
350 line_printf('\nNumber of servers: %s\n',mat2str(nServers));
351 line_printf('\n<strong>Chains</strong>:');
352 end
353
354 function [D,Z] = getDemands(self)
355 % [D,Z]= GETDEMANDS()
356 %
357 % Outputs:
358 % D: service demands
359 % Z: think times
360
361 [~,D,~,Z,~,~] = sn_get_product_form_params(self.getStruct);
362 end
363
364 function [lambda,D,N,Z,mu,S]= getProductFormParameters(self)
365 % [LAMBDA,D,N,Z,MU,S]= GETPRODUCTFORMPARAMETERS()
366 %
367 % Outputs:
368 % LAMBDA: arrival rates for open classes
369 % D: service demands
370 % N: population vector for closed classes
371 % Z: think times
372 % mu: load-dependent rates
373 % S: number of servers
374
375 % mu also returns max(S) elements after population |N| as this is
376 % required by MVALDMX
377
378 [lambda,D,N,Z,mu,S] = sn_get_product_form_params(self.getStruct);
379 end
380
381 function [lambda,D,N,Z,mu,S]= getProductFormChainParameters(self)
382 % [LAMBDA,D,N,Z,MU,S]= GETPRODUCTFORMCHAINPARAMETERS()
383 %
384 % Outputs:
385 % LAMBDA: arrival rates for open classes
386 % D: service demands
387 % N: population vector for closed classes
388 % Z: think times
389 % mu: load-dependent rates
390 % S: number of servers
391
392 % mu also returns max(S) elements after population |N| as this is
393 % required by MVALDMX
394
395 [lambda,D,N,Z,mu,S]= sn_get_product_form_chain_params(self.getStruct);
396 end
397
398 function statefulnodes = getStatefulNodes(self)
399 statefulnodes = {};
400 for i=1:self.getNumberOfNodes
401 if self.nodes{i}.isStateful
402 statefulnodes{end+1,1} = self.nodes{i};
403 end
404 end
405 end
406
407 function statefulnames = getStatefulNodeNames(self)
408 % STATEFULNAMES = GETSTATEFULNODENAMES()
409
410 statefulnames = {};
411 for i=1:self.getNumberOfNodes
412 if self.nodes{i}.isStateful
413 statefulnames{end+1,1} = self.nodes{i}.name;
414 end
415 end
416 end
417
418 function M = getNumberOfNodes(self)
419 % M = GETNUMBEROFNODES()
420
421 M = length(self.nodes);
422 end
423
424 function S = getNumberOfStatefulNodes(self)
425 % S = GETNUMBEROFSTATEFULNODES()
426
427 S = sum(cellisa(self.nodes,'StatefulNode'));
428 end
429
430 function M = getNumberOfStations(self)
431 % M = GETNUMBEROFSTATIONS()
432
433 M = length(self.stations);
434 end
435
436 function R = getNumberOfClasses(self)
437 % R = GETNUMBEROFCLASSES()
438
439 R = length(self.classes);
440 end
441
442 function C = getNumberOfChains(self)
443 % C = GETNUMBEROFCHAINS()
444
445 sn = self.getStruct;
446 C = sn.nchains;
447 end
448
449 function Dchain = getDemandsChain(self)
450 % DCHAIN = GETDEMANDSCHAIN()
451 sn_get_demands_chain(self.getStruct);
452 end
453
454 function self = setUsedLangFeature(self,className)
455 % SELF = SETUSEDLANGFEATURE(SELF,CLASSNAME)
456
457 self.usedFeatures.setTrue(className);
458 end
459
460 %% Add the components to the model
461 addJobClass(self, customerClass);
462 bool = addNode(self, node);
463 fcr = addRegion(self, nodes);
464 addLink(self, nodeA, nodeB);
465 addLinks(self, nodeList);
466 addItemSet(self, itemSet);
467
468 node = getSource(self);
469 node = getSink(self);
470
471 function list = getStationIndexes(self)
472 % LIST = GETSTATIONINDEXES()
473
474 if self.hasStruct
475 list = find(self.sn.isstation)';
476 else
477 % returns the ids of nodes that are stations
478 list = find(cellisa(self.nodes, 'Station'))';
479 end
480 end
481
482 function list = getIndexStatefulNodes(self)
483 % LIST = GETINDEXSTATEFULNODES()
484
485 % returns the ids of nodes that are stations
486 list = find(cellisa(self.nodes, 'StatefulNode'))';
487 end
488
489 index = getIndexSourceStation(self);
490 index = getIndexSourceNode(self);
491 index = getIndexSinkNode(self);
492
493 N = getNumberOfJobs(self);
494 refstat = getReferenceStations(self);
495 refclass = getReferenceClasses(self);
496 sched = getStationScheduling(self);
497 S = getStationServers(self);
498 S = getStatefulServers(self);
499
500 jsimwView(self)
501 jsimgView(self)
502 function view(self)
503 jsimgView(self);
504 end
505
506 function islld = isLimitedLoadDependent(self)
507 islld = isempty(self.getStruct().lldscaling);
508 end
509
510 function [isvalid] = isStateValid(self)
511 % [ISVALID] = ISSTATEVALID()
512
513 isvalid = sn_is_state_valid(self.getStruct);
514 end
515
516 [state, priorStateSpace, stateSpace] = getState(self) % get initial state
517
518 initFromAvgTableQLen(self, AvgTable)
519 initFromAvgQLen(self, AvgQLen)
520 initDefault(self, nodes)
521
522 initFromMarginal(self, n, options) % n(i,r) : number of jobs of class r in node or station i (autodetected)
523 initFromMarginalAndRunning(self, n, s, options) % n(i,r) : number of jobs of class r in node or station i (autodetected)
524 initFromMarginalAndStarted(self, n, s, options) % n(i,r) : number of jobs of class r in node or station i (autodetected)
525
526 [H,G] = getGraph(self)
527
528 function mask = getClassSwitchingMask(self)
529 % MASK = GETCLASSSWITCHINGMASK()
530
531 mask = self.getStruct.csmask;
532 end
533
534 function printRoutingMatrix(self, onlyclass)
535 % PRINTROUTINGMATRIX()
536 if nargin==1
537 sn_print_routing_matrix(self.getStruct);
538 else
539 sn_print_routing_matrix(self.getStruct, onlyclass);
540 end
541 end
542 end
543
544 % Private methods
545 methods (Access = protected)
546
547 function out = getModelNameExtension(self)
548 % OUT = GETMODELNAMEEXTENSION()
549
550 out = [getModelName(self), ['.', self.fileFormat]];
551 end
552
553 function self = initUsedFeatures(self)
554 % SELF = INITUSEDFEATURES()
555
556 % The list includes all classes but Model and Hidden or
557 % Constant or Abstract or Solvers
558 self.usedFeatures = SolverFeatureSet;
559 end
560 end
561
562 methods(Access = protected)
563 % Override copyElement method:
564 function clone = copyElement(self)
565 % CLONE = COPYELEMENT()
566
567 % Make a shallow copy of all properties
568 clone = copyElement@Copyable(self);
569 % Make a deep copy of each handle
570 for i=1:length(self.classes)
571 clone.classes{i} = self.classes{i}.copy;
572 end
573 % Make a deep copy of each handle
574 for i=1:length(self.nodes)
575 clone.nodes{i} = self.nodes{i}.copy;
576 if isa(clone.nodes{i},'Station')
577 clone.stations{i} = clone.nodes{i};
578 end
579 clone.connections = self.connections;
580 end
581 end
582 end
583
584 methods % wrappers
585 function bool = hasFCFS(self)
586 % BOOL = HASFCFS()
587
588 bool = sn_has_fcfs(self.getStruct);
589 end
590
591 function bool = hasHomogeneousScheduling(self, strategy)
592 % BOOL = HASHOMOGENEOUSSCHEDULING(STRATEGY)
593
594 bool = sn_has_homogeneous_scheduling(self.getStruct, strategy);
595 end
596
597 function bool = hasDPS(self)
598 % BOOL = HASDPS()
599
600 bool = sn_has_dps(self.getStruct);
601 end
602
603 function bool = hasGPS(self)
604 % BOOL = HASGPS()
605
606 bool = sn_has_gps(self.getStruct);
607 end
608
609 function bool = hasINF(self)
610 % BOOL = HASINF()
611
612 bool = sn_has_inf(self.getStruct);
613 end
614
615 function bool = hasPS(self)
616 % BOOL = HASPS()
617
618 bool = sn_has_ps(self.getStruct);
619 end
620
621 function bool = hasSIRO(self)
622 % BOOL = HASSIRO()
623
624 bool = sn_has_siro(self.getStruct);
625 end
626
627 function bool = hasHOL(self)
628 % BOOL = HASHOL()
629
630 bool = sn_has_hol(self.getStruct);
631 end
632
633 function bool = hasLCFS(self)
634 % BOOL = HASLCFS()
635
636 bool = sn_has_lcfs(self.getStruct);
637 end
638
639 function bool = hasLCFSPR(self)
640 % BOOL = HASLCFSPR()
641
642 bool = sn_has_lcfs_pr(self.getStruct);
643 end
644
645 function bool = hasSEPT(self)
646 % BOOL = HASSEPT()
647
648 bool = sn_has_sept(self.getStruct);
649 end
650
651 function bool = hasLEPT(self)
652 % BOOL = HASLEPT()
653
654 bool = sn_has_lept(self.getStruct);
655 end
656
657 function bool = hasSJF(self)
658 % BOOL = HASSJF()
659
660 bool = sn_has_sjf(self.getStruct);
661 end
662
663 function bool = hasLJF(self)
664 % BOOL = HASLJF()
665
666 bool = sn_has_ljf(self.getStruct);
667 end
668
669 function bool = hasMultiClassFCFS(self)
670 % BOOL = HASMULTICLASSFCFS()
671
672 bool = sn_has_multi_class_fcfs(self.getStruct);
673 end
674
675 function bool = hasMultiClassHeterFCFS(self)
676 % BOOL = HASMULTICLASSFCFS()
677
678 bool = sn_has_multi_class_heter_fcfs(self.getStruct);
679 end
680
681 function bool = hasMultiServer(self)
682 % BOOL = HASMULTISERVER()
683
684 bool = sn_has_multi_server(self.getStruct);
685 end
686
687 function bool = hasSingleChain(self)
688 % BOOL = HASSINGLECHAIN()
689
690 bool = sn_has_single_chain(self.getStruct);
691 end
692
693 function bool = hasMultiChain(self)
694 % BOOL = HASMULTICHAIN()
695
696 bool = sn_has_multi_chain(self.getStruct);
697 end
698
699 function bool = hasSingleClass(self)
700 % BOOL = HASSINGLECLASS()
701
702 bool = sn_has_single_class(self.getStruct);
703 end
704
705 function bool = hasMultiClass(self)
706 % BOOL = HASMULTICLASS()
707
708 bool = sn_has_multi_class(self.getStruct);
709 end
710 end
711
712 methods
713 function bool = hasProductFormSolution(self)
714 % BOOL = HASPRODUCTFORMSOLUTION()
715 bool = sn_has_product_form(self.getStruct);
716 end
717
718 function plot(self)
719 % PLOT()
720 [~,H] = self.getGraph;
721 H.Nodes.Name=strrep(H.Nodes.Name,'_','\_');
722 h=plot(H,'EdgeLabel',H.Edges.Weight,'Layout','Layered');
723 highlight(h,self.getNodeTypes==3,'NodeColor','r'); % class-switch nodes
724 end
725
726 function varargout = getMarkedCTMC( varargin )
727 [varargout{1:nargout}] = getCTMC( varargin{:} );
728 end
729
730 function mctmc = getCTMC(self, par1, par2)
731 if nargin<2
732 options = SolverCTMC.defaultOptions;
733 elseif ischar(par1)
734 options = SolverCTMC.defaultOptions;
735 options.(par1) = par2;
736 options.cache = false;
737 elseif isstruct(par1)
738 options = par1;
739 end
740 solver = SolverCTMC(self,options);
741 [infGen, eventFilt, ev] = solver.getInfGen();
742 mctmc = MarkedMarkovProcess(infGen, eventFilt, ev, true);
743 mctmc.setStateSpace(solver.getStateSpace);
744 end
745 end
746
747 methods (Static)
748
749 function model = tandemPs(lambda,D)
750 % MODEL = TANDEMPS(LAMBDA,D)
751
752 model = Network.tandemPsInf(lambda,D,[]);
753 end
754
755 function model = tandemPsInf(lambda,D,Z)
756 % MODEL = TANDEMPSINF(LAMBDA,D,Z)
757
758 if nargin<3%~exist('Z','var')
759 Z = [];
760 end
761 M = size(D,1);
762 Mz = size(Z,1);
763 strategy = {};
764 for i=1:Mz
765 strategy{i} = SchedStrategy.INF;
766 end
767 for i=1:M
768 strategy{Mz+i} = SchedStrategy.PS;
769 end
770 model = Network.tandem(lambda,[Z;D],strategy);
771 end
772
773 function model = tandemFcfs(lambda,D)
774 % MODEL = TANDEMFCFS(LAMBDA,D)
775
776 model = Network.tandemFcfsInf(lambda,D,[]);
777 end
778
779 function model = tandemFcfsInf(lambda,D,Z)
780 % MODEL = TANDEMFCFSINF(LAMBDA,D,Z)
781
782 if nargin<3%~exist('Z','var')
783 Z = [];
784 end
785 M = size(D,1);
786 Mz = size(Z,1);
787 strategy = {};
788 for i=1:Mz
789 strategy{i} = SchedStrategy.INF;
790 end
791 for i=1:M
792 strategy{Mz+i} = SchedStrategy.FCFS;
793 end
794 model = Network.tandem(lambda,[Z;D],strategy);
795 end
796
797 function model = tandem(lambda,D,strategy)
798 % MODEL = TANDEM(LAMBDA,S,STRATEGY)
799
800 % D(i,r) - mean service demand of class r at station i, equal
801 % to mean service time since the topology is linear
802 % lambda(r) - number of jobs of class r
803 % station(i) - scheduling strategy at station i
804 model = Network('Model');
805 [M,R] = size(D);
806 node{1} = Source(model, 'Source');
807 for i=1:M
808 switch SchedStrategy.toId(strategy{i})
809 case SchedStrategy.INF
810 node{end+1} = Delay(model, ['Station',num2str(i)]);
811 otherwise
812 node{end+1} = Queue(model, ['Station',num2str(i)], strategy{i});
813 end
814 end
815 node{end+1} = Sink(model, 'Sink');
816 P = cellzeros(R,R,M+2,M+2);
817 for r=1:R
818 jobclass{r} = OpenClass(model, ['Class',num2str(r)], 0);
819 P{r,r} = circul(length(node)); P{r}(end,:) = 0;
820 end
821 for r=1:R
822 node{1}.setArrival(jobclass{r}, Exp.fitMean(1/lambda(r)));
823 for i=1:M
824 node{1+i}.setService(jobclass{r}, Exp.fitMean(D(i,r)));
825 end
826 end
827 model.link(P);
828 end
829
830 function model = cyclicPs(N,D)
831 % MODEL = CYCLICPS(N,D)
832 M = size(D,1);
833 if nargin<4
834 S = ones(M,1);
835 end
836 model = Network.cyclicPsInf(N,D,[],S);
837 end
838
839 function model = cyclicPsInf(N,D,Z,S)
840 % MODEL = CYCLICPSINF(N,D,Z,S)
841 if nargin<3
842 Z = [];
843 end
844 M = size(D,1);
845 if nargin<4
846 S = ones(M,1);
847 end
848 Mz = size(Z,1);
849 strategy = cell(M+Mz,1);
850 for i=1:Mz
851 strategy{i} = SchedStrategy.INF;
852 end
853 for i=1:M
854 strategy{Mz+i} = SchedStrategy.PS;
855 end
856 model = Network.cyclic(N,[Z;D],strategy,[Inf*ones(size(Z,1),1);S]);
857 end
858
859 function model = cyclicFcfs(N,D,S)
860 % MODEL = CYCLICFCFS(N,D,S)
861 M = size(D,1);
862 if nargin<4
863 S = ones(M,1);
864 end
865 model = Network.cyclicFcfsInf(N,D,[],S);
866 end
867
868 function model = cyclicFcfsInf(N,D,Z,S)
869 % MODEL = CYCLICFCFSINF(N,D,Z,S)
870
871 if nargin<3%~exist('Z','var')
872 Z = [];
873 end
874 M = size(D,1);
875 if nargin<4
876 S = ones(M,1);
877 end
878
879 Mz = size(Z,1);
880 strategy = {};
881 for i=1:Mz
882 strategy{i} = SchedStrategy.INF;
883 end
884 for i=1:M
885 strategy{Mz+i} = SchedStrategy.FCFS;
886 end
887 model = Network.cyclic(N,[Z;D],strategy,[Inf*ones(size(Z,1),1);S]);
888 end
889
890 function model = cyclic(N,D,strategy,S)
891 % MODEL = CYCLIC(N,D,STRATEGY,S)
892
893 % L(i,r) - demand of class r at station i
894 % N(r) - number of jobs of class r
895 % strategy(i) - scheduling strategy at station i
896 % S(i) - number of servers at station i
897 model = Network('Model');
898 [M,R] = size(D);
899 node = cell(M,1);
900 nQ = 0; nD = 0;
901 for ist=1:M
902 switch SchedStrategy.toId(strategy{ist})
903 case SchedStrategy.INF
904 nD = nD + 1;
905 node{ist} = Delay(model, ['Delay',num2str(nD)]);
906 otherwise
907 nQ = nQ + 1;
908 node{ist} = Queue(model, ['Queue',num2str(nQ)], strategy{ist});
909 node{ist}.setNumberOfServers(S(ist));
910 end
911 end
912 P = cellzeros(R,M);
913 jobclass = cell(R,1);
914 for r=1:R
915 jobclass{r} = ClosedClass(model, ['Class',num2str(r)], N(r), node{1}, 0);
916 P{r,r} = circul(M);
917 end
918 for ist=1:M
919 for r=1:R
920 node{ist}.setService(jobclass{r}, Exp.fitMean(D(ist,r)));
921 end
922 end
923 model.link(P);
924 end
925
926 function P = serialRouting(varargin)
927 % P = SERIALROUTING(VARARGIN)
928
929 if length(varargin)==1
930 varargin = varargin{1};
931 end
932 model = varargin{1}.model;
933 P = zeros(model.getNumberOfNodes);
934 for i=1:length(varargin)-1
935 P(varargin{i},varargin{i+1})=1;
936 end
937 if ~isa(varargin{end},'Sink')
938 P(varargin{end},varargin{1})=1;
939 end
940 P = P ./ repmat(sum(P,2),1,length(P));
941 P(isnan(P)) = 0;
942 end
943
944 function printInfGen(Q,SS)
945 % PRINTINFGEN(Q,SS)
946 SolverCTMC.printInfGen(Q,SS);
947 end
948
949 function printEventFilt(sync,D,SS,myevents)
950 % PRINTEVENTFILT(SYNC,D,SS,MYEVENTS)
951 SolverCTMC.printEventFilt(sync,D,SS,myevents);
952 end
953
954 end
955end
Definition mmt.m:92