5#ifndef LINE_API_MAM_MAP_OPTIM_DIST_H
6#define LINE_API_MAM_MAP_OPTIM_DIST_H
84namespace optdistdetail {
91 for (std::size_t j = 0; j < A.
cols(); ++j)
92 for (std::size_t i = 0; i < A.
rows(); ++i) v[c++] = A(i, j);
98Matrix<T> unvec(
const std::vector<T>& v, std::size_t n) {
101 for (std::size_t j = 0; j < n; ++j)
102 for (std::size_t i = 0; i < n; ++i) A(i, j) = v[c++];
114Matrix<T> mkron(
const Matrix<T>& A,
const Matrix<T>& B) {
115 const std::size_t ar = A.rows(), ac = A.cols(), br = B.rows(), bc = B.cols();
116 Matrix<T> K(ar * br, ac * bc, num_traits<T>::from_int(0));
117 for (std::size_t i = 0; i < ar; ++i)
118 for (std::size_t j = 0; j < ac; ++j)
119 for (std::size_t k = 0; k < br; ++k)
120 for (std::size_t l = 0; l < bc; ++l)
121 K(i * br + k, j * bc + l) = A(i, j) * B(k, l);
127Matrix<T> neg_row_sums(
const Matrix<T>& M) {
128 Matrix<T> v(M.rows(), 1, num_traits<T>::from_int(0));
129 for (std::size_t i = 0; i < M.rows(); ++i) {
130 T s = num_traits<T>::from_int(0);
131 for (std::size_t j = 0; j < M.cols(); ++j) s += M(i, j);
144void build_constraints(
const Matrix<T>& B0,
const std::vector<T>& alB, Matrix<T>* Aeq,
145 std::vector<T>* beq) {
146 const std::size_t n = B0.rows();
147 const T zero = num_traits<T>::from_int(0), one = num_traits<T>::from_int(1);
149 Matrix<T> negB0(n, n, zero);
150 for (std::size_t i = 0; i < n; ++i)
151 for (std::size_t j = 0; j < n; ++j) negB0(i, j) = -B0(i, j);
153 Matrix<T> negB0T(n, n, zero);
154 for (std::size_t i = 0; i < n; ++i)
155 for (std::size_t j = 0; j < n; ++j) negB0T(i, j) = negB0(j, i);
156 const std::vector<T> row =
solve(negB0T, alB);
158 Matrix<T> rowM(1, n, zero);
159 for (std::size_t j = 0; j < n; ++j) rowM(0, j) = row[j];
160 Matrix<T> I(n, n, zero);
161 for (std::size_t i = 0; i < n; ++i) I(i, i) = one;
162 Matrix<T> ones1(1, n, one);
164 const Matrix<T> top = mkron(I, rowM);
165 const Matrix<T> bot = mkron(ones1, I);
167 for (std::size_t i = 0; i < n; ++i)
168 for (std::size_t j = 0; j < n * n; ++j) {
169 (*Aeq)(i, j) = top(i, j);
170 (*Aeq)(n + i, j) = bot(i, j);
172 const Matrix<T> b = neg_row_sums(B0);
173 beq->assign(2 * n, zero);
174 for (std::size_t i = 0; i < n; ++i) {
176 (*beq)[n + i] = b(i, 0);
181template <
class T,
class F>
182std::vector<T> constrained_min(F f,
const Matrix<T>& Aeq,
const std::vector<T>& beq,
183 const std::vector<T>& x0,
const T& lo) {
184 const std::size_t m = x0.size();
185 auto h = [&Aeq, &beq, m](
const std::vector<T>& x) {
186 std::vector<T> r(Aeq.rows(), num_traits<T>::from_int(0));
187 for (std::size_t i = 0; i < Aeq.rows(); ++i) {
189 for (std::size_t j = 0; j < m; ++j) s += Aeq(i, j) * x[j];
194 auto g = [](
const std::vector<T>&) {
return std::vector<T>(); };
195 std::vector<Bound<T>> bounds(m);
196 for (std::size_t j = 0; j < m; ++j) {
197 bounds[j].has_lo =
true;
200 return auglag(f, h, g, x0, bounds).x;
216 const std::vector<T>& alB,
unsigned L) {
217 using namespace optdistdetail;
219 const std::size_t n = B0.
rows();
220 if (n == 0 || B0.
cols() != n)
throw InputError(
"map_optim_dist: B0 must be square");
221 if (alB.size() != n)
throw InputError(
"map_optim_dist: alB has the wrong length");
222 if (alA.size() != a.
D0.rows())
throw InputError(
"map_optim_dist: alA has the wrong length");
223 if (L == 0)
throw InputError(
"map_optim_dist: at least one lag is required");
229 build_constraints(B0, alB, &Aeq, &beq);
236 const std::size_t na = a.
D0.rows();
237 Matrix<T> A0t(na, na, zero), B0t(n, n, zero);
238 for (std::size_t i = 0; i < na; ++i)
239 for (std::size_t j = 0; j < na; ++j) A0t(i, j) = a.
D0(j, i);
240 for (std::size_t i = 0; i < n; ++i)
241 for (std::size_t j = 0; j < n; ++j) B0t(i, j) = B0(j, i);
243 Matrix<T> alAc(na, 1, zero), alBc(n, 1, zero);
244 for (std::size_t i = 0; i < na; ++i) alAc(i, 0) = alA[i];
245 for (std::size_t i = 0; i < n; ++i) alBc(i, 0) = alB[i];
246 const Matrix<T> av = neg_row_sums(a.
D0), bv = neg_row_sums(B0);
250 for (std::size_t i = 0; i < u.
rows(); ++i)
251 for (std::size_t j = 0; j < v.rows(); ++j) M(i, j) = u(i, 0) * v(j, 0);
265 const std::vector<T> vA1 = vec(a.
D1);
268 std::vector<T> lin(n * n, zero);
269 for (std::size_t j = 0; j < n * n; ++j) {
271 for (std::size_t i = 0; i < vA1.size(); ++i) s += vA1[i] * HAB(i, j);
275 for (std::size_t i = 0; i < vA1.size(); ++i)
276 for (std::size_t j = 0; j < vA1.size(); ++j) cst += vA1[i] * HAA(i, j) * vA1[j];
278 auto quad = [&H, &lin, cst, zero](
const std::vector<T>& x) {
280 for (std::size_t i = 0; i < x.size(); ++i) {
282 for (std::size_t j = 0; j < x.size(); ++j) row += H(i, j) * x[j];
291 std::vector<T> x0(n * n, lo);
293 for (std::size_t i = 0; i < n; ++i)
294 for (std::size_t j = 0; j < n; ++j)
298 const std::vector<T> sol = constrained_min(quad, Aeq, beq, x0, lo);
299 out.
B1 = unvec(sol, n);
306 auto obj = [&a, &B0, &alA, &alB, L, n](
const std::vector<T>& x) {
314 for (std::size_t i = 0; i < n; ++i)
315 for (std::size_t j = 0; j < n; ++j)
317 const std::vector<T> sol = constrained_min(obj, Aeq, beq, vec(seed), lo);
318 out.
B1 = unvec(sol, n);
334 const Matrix<T>& B0,
const std::vector<T>& alB) {
335 using namespace optdistdetail;
337 const std::size_t n = B0.
rows();
338 if (n == 0 || B0.
cols() != n)
throw InputError(
"map_optim_dist_acf: B0 must be square");
339 if (alB.size() != n)
throw InputError(
"map_optim_dist_acf: alB has the wrong length");
340 if (alA.size() != a.
D0.rows())
throw InputError(
"map_optim_dist_acf: alA has the wrong length");
346 build_constraints(B0, alB, &Aeq, &beq);
348 auto obj = [&a, &B0, &alA, &alB, n](
const std::vector<T>& x) {
356 for (std::size_t i = 0; i < n; ++i)
357 for (std::size_t j = 0; j < n; ++j)
361 const std::vector<T> sol = constrained_min(obj, Aeq, beq, vec(seed), lo);
362 out.
B1 = unvec(sol, n);
Augmented Lagrangian method for equality- and inequality-constrained minimization,...
The exception types the port throws.
LU factorization with partial pivoting, templated on the number type.
Analytic distances between continuous-time MAPs.
Markovian arrival process descriptors: stationary vectors, rate, moments, autocorrelation and the ind...
Dense matrix and non-owning view.
MapOptimDist< T > map_optim_dist(const Map< T > &a, const std::vector< T > &alA, const Matrix< T > &B0, const std::vector< T > &alB, unsigned L)
Fit B1 minimizing the lag-L joint-density distance to a, with B0 fixed.
T map_dist_acf(const Map< T > &a, const Map< T > &b, const std::vector< T > &alA, const std::vector< T > &alB)
Squared L2 distance between the two autocorrelation functions (map_dist_acf.m).
MapOptimDist< T > map_optim_dist_acf(const Map< T > &a, const std::vector< T > &alA, const Matrix< T > &B0, const std::vector< T > &alB)
Fit B1 minimizing the AUTOCORRELATION distance to a, with B0 fixed.
T map_dist(const Map< T > &a, const Map< T > &b, unsigned L, const std::vector< T > &alA, const std::vector< T > &alB)
Squared L2 distance between the two joint densities up to lag L (map_dist.m).
AugLagResult< T > auglag(F f, H h, G g, const std::vector< T > &x0, const std::vector< Bound< T > > &bounds, const AugLagOptions< T > &opt)
Augmented Lagrangian with a scalar objective and a simplex inner solver.
Matrix< T > lyap_solve(const Matrix< T > &A, const Matrix< T > &B, const Matrix< T > &C)
MATLAB lyap(A,B,C) solves A X + X B + C = 0, i.e.
std::vector< T > solve(const Matrix< T > &A, const std::vector< T > &b)
Convenience: solve Ax = b, leaving A and b untouched.
Number-type abstraction for the templated API port.
What an optimizing distance fit returns.
Matrix< T > B1
the fitted D1
bool global
true only on the convex lag-1 path
A MAP as the pair of matrices (D0, D1).
The Sylvester equation A X + X B = C, and MATLAB's lyap(A,B,C).