287 using detail::VarKind;
288 using detail::VarMap;
293 const std::size_t n = model.
num_vars();
296 std::vector<VarMap> vmap(n);
297 std::vector<T> fixed_value(n, zero);
298 std::vector<T> offset(n, zero);
300 for (std::size_t j = 0; j < n; ++j) {
302 if (!lf && !uf && model.
lower(j) == model.
upper(j)) {
303 vmap[j].kind = VarKind::Fixed;
304 fixed_value[j] = model.
lower(j);
305 offset[j] = model.
lower(j);
306 }
else if (!lf && !uf && model.
upper(j) < model.
lower(j)) {
311 vmap[j].kind = VarKind::ShiftUp;
313 offset[j] = model.
lower(j);
315 vmap[j].kind = VarKind::ShiftDown;
317 offset[j] = model.
upper(j);
319 vmap[j].kind = VarKind::Free;
328 std::vector<std::vector<std::size_t>> le_cols, eq_cols;
329 std::vector<std::vector<T>> le_vals, eq_vals;
330 std::vector<T> le_rhs, eq_rhs;
332 for (std::size_t i = 0; i < model.
num_rows(); ++i) {
335 std::vector<std::size_t> cs;
339 const std::size_t j = model.
col_at(k);
340 const T a = model.
val_at(k);
341 if (vmap[j].kind == VarKind::Fixed) {
342 const T contrib = a * fixed_value[j];
346 if (offset[j] != zero) {
347 const T contrib = a * offset[j];
350 if (vmap[j].kind == VarKind::ShiftUp) {
351 cs.push_back(vmap[j].pos);
353 }
else if (vmap[j].kind == VarKind::ShiftDown) {
354 cs.push_back(vmap[j].pos);
358 cs.push_back(vmap[j].pos);
360 cs.push_back(vmap[j].neg);
366 for (std::size_t k = 0; k < vs.size(); ++k) {
374 eq_cols.push_back(cs);
375 eq_vals.push_back(vs);
378 le_cols.push_back(cs);
379 le_vals.push_back(vs);
385 for (std::size_t j = 0; j < n; ++j) {
386 if (vmap[j].kind == VarKind::ShiftUp && !model.
upper_is_free(j)) {
387 const T span = model.
upper(j) - model.
lower(j);
388 le_cols.push_back(std::vector<std::size_t>(1, vmap[j].pos));
389 le_vals.push_back(std::vector<T>(1, one));
390 le_rhs.push_back(span);
391 }
else if (vmap[j].kind == VarKind::ShiftDown && !model.
lower_is_free(j)) {
392 const T span = model.
upper(j) - model.
lower(j);
393 le_cols.push_back(std::vector<std::size_t>(1, vmap[j].pos));
394 le_vals.push_back(std::vector<T>(1, one));
395 le_rhs.push_back(span);
399 const std::size_t n_le = le_rhs.size();
400 const std::size_t n_eq = eq_rhs.size();
401 std::size_t m = n_le + n_eq;
402 const std::size_t n_struct = ny + n_le;
405 std::vector<T> cy(n_struct, zero);
407 for (std::size_t j = 0; j < n; ++j) {
408 const T cj = model.
costs()[j];
409 if (cj == zero)
continue;
410 if (vmap[j].kind == VarKind::Fixed) {
411 const T contrib = cj * fixed_value[j];
412 const_obj += contrib;
415 if (offset[j] != zero) {
416 const T contrib = cj * offset[j];
417 const_obj += contrib;
419 if (vmap[j].kind == VarKind::ShiftUp) {
420 cy[vmap[j].pos] += cj;
421 }
else if (vmap[j].kind == VarKind::ShiftDown) {
422 cy[vmap[j].pos] -= cj;
424 cy[vmap[j].pos] += cj;
425 cy[vmap[j].neg] -= cj;
429 for (std::size_t k = 0; k < cy.size(); ++k) {
436 const std::size_t ncol1 = n_struct + m;
437 std::vector<T> tab(m * (ncol1 + 1), zero);
438 const std::size_t stride1 = ncol1 + 1;
439 for (std::size_t i = 0; i < n_le; ++i) {
440 for (std::size_t k = 0; k < le_cols[i].size(); ++k)
441 tab[i * stride1 + le_cols[i][k]] += le_vals[i][k];
442 tab[i * stride1 + ny + i] = one;
443 tab[i * stride1 + ncol1] = le_rhs[i];
445 for (std::size_t i = 0; i < n_eq; ++i) {
446 const std::size_t r = n_le + i;
447 for (std::size_t k = 0; k < eq_cols[i].size(); ++k)
448 tab[r * stride1 + eq_cols[i][k]] += eq_vals[i][k];
449 tab[r * stride1 + ncol1] = eq_rhs[i];
452 for (std::size_t i = 0; i < m; ++i) {
453 if (tab[i * stride1 + ncol1] < zero) {
454 for (std::size_t j = 0; j <= ncol1; ++j) {
455 const T nv = -tab[i * stride1 + j];
456 tab[i * stride1 + j] = nv;
459 tab[i * stride1 + n_struct + i] = one;
462 std::vector<std::size_t> basis(m);
463 for (std::size_t i = 0; i < m; ++i) basis[i] = n_struct + i;
465 std::size_t iter_cap = max_iterations;
467 const std::size_t base = (m + 1) * (ncol1 + 1);
468 iter_cap = base < 100000 ? 100000 : base * 20;
470 std::size_t iters = 0;
476 static void apply(std::vector<T>& tb, std::size_t stride, std::size_t rows, std::size_t row,
478 const T piv = tb[row * stride + col];
480 for (std::size_t j = 0; j < stride; ++j) {
481 const T nv = tb[row * stride + j] * inv;
482 tb[row * stride + j] = nv;
485 for (std::size_t i = 0; i < rows; ++i) {
486 if (i == row)
continue;
487 const T f = tb[i * stride + col];
488 if (f == T())
continue;
489 for (std::size_t j = 0; j < stride; ++j) {
490 const T nv = tb[i * stride + j] - f * tb[row * stride + j];
491 tb[i * stride + j] = nv;
493 tb[i * stride + col] = T();
500 std::vector<T> c1(ncol1, zero);
501 for (std::size_t i = 0; i < m; ++i) c1[n_struct + i] = -one;
502 bool unbounded =
false;
504 if (++iters > iter_cap) {
510 std::size_t enter = ncol1;
511 for (std::size_t j = 0; j < ncol1; ++j) {
513 for (std::size_t i = 0; i < m; ++i) {
514 const T cb = c1[basis[i]];
515 if (cb == zero)
continue;
516 const T contrib = cb * tab[i * stride1 + j];
524 if (enter == ncol1)
break;
525 std::size_t leave = m;
526 T best_num = zero, best_den = one;
527 for (std::size_t i = 0; i < m; ++i) {
528 const T a = tab[i * stride1 + enter];
529 if (!(a > tol))
continue;
530 const T rr = tab[i * stride1 + ncol1];
536 const T lhs = rr * best_den;
537 const T rhs2 = best_num * a;
538 if (lhs < rhs2 || (lhs == rhs2 && basis[i] < basis[leave])) {
549 Pivot::apply(tab, stride1, m, leave, enter);
550 basis[leave] = enter;
559 for (std::size_t i = 0; i < m; ++i)
560 if (basis[i] >= n_struct) infeas += tab[i * stride1 + ncol1];
567 std::vector<char> drop(m, 0);
568 for (std::size_t i = 0; i < m; ++i) {
569 if (basis[i] < n_struct)
continue;
570 std::size_t piv = n_struct;
571 for (std::size_t j = 0; j < n_struct; ++j) {
572 const T a = tab[i * stride1 + j];
573 if (a > tol || a < -tol) {
578 if (piv == n_struct) {
581 Pivot::apply(tab, stride1, m, i, piv);
586 const std::size_t stride2 = n_struct + 1;
588 std::vector<std::size_t> basis2;
589 tab2.reserve(m * stride2);
590 for (std::size_t i = 0; i < m; ++i) {
591 if (drop[i])
continue;
592 for (std::size_t j = 0; j < n_struct; ++j) tab2.push_back(tab[i * stride1 + j]);
593 tab2.push_back(tab[i * stride1 + ncol1]);
594 basis2.push_back(basis[i]);
602 const std::size_t stride = n_struct + 1;
603 bool unbounded =
false;
605 if (++iters > iter_cap) {
610 std::size_t enter = n_struct;
611 for (std::size_t j = 0; j < n_struct; ++j) {
613 for (std::size_t i = 0; i < m; ++i) {
614 const T cb = cy[basis[i]];
615 if (cb == zero)
continue;
616 const T contrib = cb * tab[i * stride + j];
624 if (enter == n_struct)
break;
625 std::size_t leave = m;
626 T best_num = zero, best_den = one;
627 for (std::size_t i = 0; i < m; ++i) {
628 const T a = tab[i * stride + enter];
629 if (!(a > tol))
continue;
630 const T rr = tab[i * stride + n_struct];
636 const T lhs = rr * best_den;
637 const T rhs2 = best_num * a;
638 if (lhs < rhs2 || (lhs == rhs2 && basis[i] < basis[leave])) {
649 Pivot::apply(tab, stride, m, leave, enter);
650 basis[leave] = enter;
661 std::vector<T> y(n_struct, zero);
662 for (std::size_t i = 0; i < m; ++i)
663 if (basis[i] < n_struct) y[basis[i]] = tab[i * stride + n_struct];
665 sol.
x.assign(n, zero);
666 for (std::size_t j = 0; j < n; ++j) {
667 switch (vmap[j].kind) {
668 case VarKind::Fixed: sol.
x[j] = fixed_value[j];
break;
669 case VarKind::ShiftUp: sol.
x[j] = offset[j] + y[vmap[j].pos];
break;
670 case VarKind::ShiftDown: sol.
x[j] = offset[j] - y[vmap[j].pos];
break;
671 default: sol.
x[j] = y[vmap[j].pos] - y[vmap[j].neg];
break;
675 for (std::size_t j = 0; j < n; ++j) {
676 const T cj = model.
costs()[j];
677 if (cj == zero)
continue;
678 const T contrib = cj * sol.
x[j];