Skip to content

Warm start after changing row range #38

@TendTo

Description

@TendTo

In my use case, I need to solve the same LP problem many times, enabling and disabling the same constraints as required.
I noticed that more often than not the results after a previous solve were incorrect, as if they were stuck in the previous basis.

In fact, forcing a refresh with clearBasis between each solve fixes the issue, but that means having a cold start every time.
I was wondering if this behaviour is intended or something is going wrong within the internals of the solver.

The following is minimal snippet to reproduce the problem.
I have just started investigating it, so I probably missed something.

#include "soplex.h"

#include <iostream>

using namespace soplex;

void check_and_print_solution(SoPlex &soplex, int expected) {
  SPxSolver::Status stat;
  DVectorRational prim(2);
  DVectorRational dual(1);

  stat = soplex.optimize();
  if (stat != SPxSolver::OPTIMAL || soplex.objValueRational() != expected) {
    throw std::runtime_error((std::stringstream{}
                              << "SoPlex returned with status "
                              << std::to_string(stat) << " and objective value "
                              << soplex.objValueRational() << " instead of "
                              << expected)
                                 .str());
  }

  soplex.getPrimalRational(prim);
  soplex.getDualRational(dual);
  std::cout << "LP solved to optimality.\n";
  std::cout << "Objective value is " << soplex.objValueRational() << ".\n";
  std::cout << "Primal solution is [" << prim[0] << ", " << prim[1] << "].\n";
  std::cout << "Dual solution is [" << dual[0] << "].\n";
}

void test_rational() {
  SoPlex mysoplex;

  /* set parameters for exact solving */
  mysoplex.setIntParam(SoPlex::READMODE, SoPlex::READMODE_RATIONAL);
  mysoplex.setIntParam(SoPlex::SOLVEMODE, SoPlex::SOLVEMODE_RATIONAL);
  mysoplex.setIntParam(SoPlex::CHECKMODE, SoPlex::CHECKMODE_RATIONAL);
  mysoplex.setIntParam(SoPlex::SYNCMODE, SoPlex::SYNCMODE_AUTO);
  mysoplex.setIntParam(SoPlex::SIMPLIFIER, SoPlex::SIMPLIFIER_OFF);
  mysoplex.setRealParam(SoPlex::FEASTOL, 0.0);
  mysoplex.setRealParam(SoPlex::OPTTOL, 0.0);

  /* set the objective sense (MAXIMIZE) */
  mysoplex.setIntParam(SoPlex::OBJSENSE, SoPlex::OBJSENSE_MAXIMIZE);

  /* we first add variables (the integer data is converted to type Rational) */
  mysoplex.addColRational(LPColRational(0, DSVectorRational(), infinity, 0)); // 0 <= x0        | 0 coeff
  mysoplex.addColRational(LPColRational(1, DSVectorRational(), 1, 0));        // 0 <= x1 <= 1   | 1 coeff

  /* then constraints one by one (here we show how Rationals can be used
   * directly) */
  DSVectorRational row1(2);
  row1.add(0, 1);
  row1.add(1, 1);
  mysoplex.addRowRational(LPRowRational(-infinity, row1, infinity)); // C0: x0 + x1 <= infinity

  // Maximize
  //   obj: 1 x1
  // Subject To
  //  C0 : 1 x0 + 1 x1 <= infinity
  // Bounds
  //   x1 <= 1
  // End

  check_and_print_solution(mysoplex, 1);

  // Maximize
  //   obj: 1 x1
  // Subject To
  //  C0 : 1 x0 + 1 x1 <= 0
  // Bounds
  //   x1 <= 1
  // End

  // Enable C0
  mysoplex.changeRangeRational(0, -infinity, 0); // C0: x0 + x1 <= 0
  check_and_print_solution(mysoplex, 0);

  // Maximize
  //   obj: 1 x1
  // Subject To
  //  C0 : 1 x0 + 1 x1 <= infinity
  // Bounds
  //   x1 <= 1
  // End

  // Disable C0 again
  mysoplex.changeRangeRational(0, -infinity, infinity); // C0: x0 + x1 <= infinity

  // mysoplex.clearBasis(); // Adding this fixes the issue, but it's very expensive, especially for repeated solves
  //
  // mysoplex.syncLPRational(); // Gets ignored because of SYNCMODE_AUTO
  //
  // mysoplex._syncLPRational(); // Does nothing
  //
  // mysoplex._solver.reLoad();  // Does nothing
  //
  // mysoplex._hasBasis = false; // Solve the issue, but requires private access and still expensive

  // ERROR: we don't get 1 anymore (like in the original problem), but 0 (like the last one)
  check_and_print_solution(mysoplex, 1); }

int main() {
  test_rational();
  return 0;
}

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions