LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
pas_swap2order.m
1function H = pas_swap2order(swap, listRate, N0)
2% H = PAS_SWAP2ORDER(SWAP, LISTRATE, N0)
3%
4% Derive the GLOBAL placement-order DAG H of a closed two-station pass-and-swap
5% (P&S) tandem 1->2->1 directly from its swap graph, for use with PFQN_PAS_IS.
6%
7% With a non-empty swap graph the ordered-state chain is reducible (Comte &
8% Dorsman, 2021, arXiv:2009.12299): the recurrent communicating class is the set
9% of splits (c_{1..k}; c_{ell..k+1}) of the orderings c that are the linear
10% extensions of a single placement partial order on the classes (their Prop.).
11% PFQN_PAS_IS samples those orderings from H, so it needs exactly this global
12% order -- NOT the per-queue posets of PAS_SWAP2PREC (which, combined pairwise
13% in the exact convolution PFQN_PASNC, encode the same information differently
14% and are individually over-constrained for the single-order IS formulation).
15%
16% The placement order is a class-level property, independent of the per-class
17% multiplicity, so it is extracted from the minimal single-job-per-class
18% instance (N0 = ones(1,R)): enumerate the reachable communicating class from
19% the all-in-queue-1 initial state; each reachable state (l1;l2) exposes the
20% full ordering c = [l1, reverse(l2)] in D; then set H(i,j)=1 iff class i
21% precedes class j in EVERY c in D (forced precedence). Incomparable pairs are
22% left 0 (antichain). The result is valid for any population N.
23%
25% swap - (R x R) swap graph, or cell {G1,G2} of the two per-queue graphs;
26% G(a,b)~=0 means class a chases class b. Empty/all-zero => plain
27% OI: H = 0 (every ordering feasible).
28% listRate - cell {1 x 2} of OI microstate rate functions; listRate{m}(c) is
29% the total service rate of queue m on the ordered prefix c. Used
30% to prune zero-rate (non-head) completions.
31% N0 - (1 x R) minimal probing population; defaults to ones(1,R).
32%
33% Returns:
34% H - (R x R) global placement-order DAG; H(i,j)=1 iff i must precede j.
35%
36% See also PFQN_PAS_IS, PAS_PLACEMENT, PFQN_PASNC.
37%
38% Copyright (c) 2012-2026, Imperial College London
39% All rights reserved.
40
41M = 2;
42if ~iscell(swap), swap = repmat({swap}, 1, M); end
43if nargin < 3 || isempty(N0)
44 R = size(swap{1}, 1);
45 N0 = ones(1, R);
46end
47R = numel(N0);
48
49if (isempty(swap{1}) || ~any(swap{1}(:) ~= 0)) && ...
50 (isempty(swap{2}) || ~any(swap{2}(:) ~= 0))
51 H = zeros(R, R); % pure OI: no placement constraint
52 return
53end
54
55% minimal single-job-per-class initial placement, all jobs at queue 1
56initState = [];
57for r = 1:R, initState = [initState, repmat(r, 1, N0(r))]; end %#ok<AGROW>
58init = {initState, []};
59
60% breadth-first enumeration of the reachable (communicating) class
61key = containers.Map('KeyType', 'char', 'ValueType', 'logical');
62classStates = {}; frontier = {init}; key(pas_enc(init)) = true;
63while ~isempty(frontier)
64 st = frontier{end}; frontier(end) = [];
65 classStates{end+1} = st; %#ok<AGROW>
66 for m = 1:M
67 c = st{m}; next = mod(m, M) + 1;
68 for p = 1:numel(c)
69 % Marginal OI completion rate of the p-th customer. The empty-prefix
70 % rate is 0 by definition (no jobs -> no service); some svcRateFun
71 % handles return a nonzero constant on [], so guard p==1 explicitly.
72 if p == 1
73 prevRate = 0;
74 else
75 prevRate = listRate{m}(c(1:p-1));
76 end
77 rate = listRate{m}(c(1:p)) - prevRate;
78 if rate <= 1e-12, continue; end
79 [cnew, dep] = pas_swap_local(c, p, swap{m});
80 stn = st; stn{m} = cnew; stn{next} = [st{next}, dep];
81 k = pas_enc(stn);
82 if ~isKey(key, k), key(k) = true; frontier{end+1} = stn; end %#ok<AGROW>
83 end
84 end
85end
86
87% full orderings D: every reachable state (l1;l2) exposes c = [l1, reverse(l2)]
88Dmap = containers.Map('KeyType', 'char', 'ValueType', 'logical');
89D = {};
90for s = 1:numel(classStates)
91 c = [classStates{s}{1}, fliplr(classStates{s}{2})];
92 kc = sprintf('%d,', c);
93 if ~isKey(Dmap, kc), Dmap(kc) = true; D{end+1} = c; end %#ok<AGROW>
94end
95
96% forced precedence: i precedes j iff in every c in D, every copy of i is older
97% than every copy of j (position-wise), whenever both are present.
98H = false(R);
99for a = 1:R
100 for b = 1:R
101 if a == b, continue; end
102 both = false; forced = true;
103 for s = 1:numel(D)
104 c = D{s};
105 pa = find(c == a); pb = find(c == b);
106 if isempty(pa) || isempty(pb), continue; end
107 both = true;
108 if ~(max(pa) < min(pb)), forced = false; break; end
109 end
110 H(a, b) = both && forced;
111 end
112end
113H = double(H);
114end
115
116% ------------------------------------------------------------------------
117function s = pas_enc(st)
118parts = cell(1, numel(st));
119for m = 1:numel(st), parts{m} = sprintf('%d,', st{m}); end
120s = strjoin(parts, '|');
121end
122
123function [cnew, dep] = pas_swap_local(c, p, G)
124n = numel(c); chain = p; moving = c(p); cur = p;
125while true
126 q = -1;
127 for j = cur+1:n, if ~isempty(G) && G(moving, c(j)) ~= 0, q = j; break; end; end
128 if q == -1, break; end
129 chain(end+1) = q; moving = c(q); cur = q; %#ok<AGROW>
130end
131dep = c(chain(end)); tmp = c;
132for i = 1:numel(chain)-1, tmp(chain(i+1)) = c(chain(i)); end
133tmp(chain(1)) = []; cnew = tmp;
134end
Definition Station.m:245