LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
mmap3k_fit.m
1function [MMAP, EXACT] = mmap3k_fit(D0, D1, P, F, B, B2)
2% [MMAP, EXACT] = mmap3k_fit(D0, D1, P, F, B, B2)
3% Closed-form marking fit of an MMAP(3,K): a marked MAP of third order.
4%
5% The MMAP(2,K) argument does not depend on the order. Two facts carry over
6% (verified symbolically, see sage/proofs/mmap3k_marking_inverse.py):
7% 1. every per-class characteristic in which the class matrix appears exactly
8% once is LINEAR in the marking fractions, so z = nnz(D1) fractions per
9% class are determined by z characteristics through a square system;
10% 2. that system is BLOCK DIAGONAL in the classes, so one z-by-z block is
11% built once and reused for every class: the cost does not grow with K.
12%
13% What changes with the order is WHICH characteristics are needed. At order two
14% (p_c, F_c, B_c) suffice; at order three the independent set of lowest total
15% order is
16% (a,b) = (1,0), (1,1), (2,0), (3,0)
17% i.e. p_c, F_c, B_c, B_c^(2)
18% with a the backward and b the forward order of pie*A^a*D1c*A^b*1. Alternating
19% forward and backward orders does NOT stay independent at higher orders.
20%
21% The block is assembled exactly by evaluating the linear map on unit markings:
22% no finite differences and no computer algebra, since the map is linear with a
23% zero offset. This is preferred to inlining the symbolic inverse, which at
24% order three is about 5 KB of expressions and is tied to one sparsity pattern.
25%
26% The underlying MAP(3) is an input: unlike order two there is no canonical
27% inverse here that turns moments and autocorrelation into an order-3 MAP.
28%
29% Input:
30% D0, D1: the underlying MAP (any order; validated at orders two and three)
31% P: class probabilities (sum to one)
32% F: first-order forward moments
33% B: first-order backward moments
34% B2: second-order backward moments (required from order three)
35%
36% Output:
37% MMAP: the marked MAP as {D0, D1, D11, ..., D1K}
38% EXACT: true when the closed-form marking is feasible
39
40feastol = 1e-8;
41
42P = P(:); F = F(:); B = B(:);
43K = length(P);
44n = size(D0,1);
45
46[nzi, nzj] = find(D1);
47z = length(nzi);
48orders = marking_orders(n, z);
49if nargin < 6 || isempty(B2)
50 if z > 3
51 error('mmap3k_fit: order %d needs the second-order backward moments B2', n);
52 end
53 B2 = zeros(K,1);
54else
55 B2 = B2(:);
56end
57
58A = inv(-D0);
59P_emb = A * D1;
60T = (P_emb' - eye(n));
61T(n,:) = ones(1,n);
62rhs = zeros(n,1); rhs(n) = 1;
63pie = (T \ rhs)';
64
65% z-by-z block: column j is the characteristic vector of a unit marking on the
66% j-th nonzero of D1
67M = zeros(z,z);
68for jj = 1:z
69 Dc = zeros(n,n);
70 Dc(nzi(jj), nzj(jj)) = D1(nzi(jj), nzj(jj));
71 for ii = 1:z
72 a = orders(ii,1); b = orders(ii,2);
73 M(ii,jj) = pie * (A^a) * Dc * (A^b) * ones(n,1);
74 end
75end
76
77if abs(det(M)) < 1e-12 * max(1, max(abs(M(:)))^z)
78 error('mmap3k_fit: the underlying MAP is on the degenerate locus of the marking system');
79end
80
81q = zeros(z,K);
82for c = 1:K
83 y = zeros(z,1);
84 for ii = 1:z
85 a = orders(ii,1); b = orders(ii,2);
86 if a == 1 && b == 0
87 y(ii) = P(c);
88 elseif a == 1 && b == 1
89 y(ii) = P(c) * F(c);
90 elseif a == 2 && b == 0
91 y(ii) = P(c) * B(c);
92 elseif a == 3 && b == 0
93 y(ii) = P(c) * B2(c);
94 else
95 error('mmap3k_fit: no target supplied for the characteristic (a=%d, b=%d)', a, b);
96 end
97 end
98 q(:,c) = M \ y;
99end
100
101viol = max([0; -q(:); q(:)-1; abs(sum(q,2)-1)]);
102EXACT = viol <= feastol;
103
104qc = min(max(q,0),1);
105MMAP = cell(1,2+K);
106MMAP{1} = D0;
107MMAP{2} = D1;
108for c = 1:K
109 Dc = zeros(n,n);
110 for jj = 1:z
111 Dc(nzi(jj), nzj(jj)) = D1(nzi(jj), nzj(jj)) * qc(jj,c);
112 end
113 MMAP{2+c} = Dc;
114end
115
116end
117
118function orders = marking_orders(n, z)
119% (backward, forward) orders of an independent characteristic set
120if n == 2
121 orders = [1 0; 1 1; 2 0];
122elseif n == 3
123 orders = [1 0; 1 1; 2 0; 3 0];
124else
125 orders = [1 0; 1 1];
126 a = 2;
127 while size(orders,1) < n+1
128 orders = [orders; a 0]; %#ok<AGROW>
129 a = a + 1;
130 end
131end
132orders = orders(1:z,:);
133end