HiGHS icon indicating copy to clipboard operation
HiGHS copied to clipboard

Warm start provokes solver failure

Open amigalemming opened this issue 1 year ago • 2 comments

I have an example, where a warm restarted solver fails, whereas with one warm start less, it succeeds:

$ cat warmstart-incorrect.c
#include "interfaces/highs_c_api.h"

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <math.h>

int main ()
{
  {
    const double col_cost[7] =
      { 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000 };
    const double col_lower[7] =
      { -69.000, -47.000, -91.000, -73.000, -50.000, -89.000, -94.000 };
    const double col_upper[7] =
      { 74.000, 86.000, 101.000, 85.000, 61.000, 64.000, 68.000 };
    const double row_lower[0] = { };
    const double row_upper[0] = { };
    const int a_start[1] = { 0 };
    const int a_index[0] = { };
    const double a_value[0] = { };
    void *highs = Highs_create ();
    printf ("%p = Highs_create()\n", highs);
    Highs_setBoolOptionValue (highs, "output_flag", 0);
    int run_status = Highs_passLp (highs,
                                   7, 0, 0,
                                   kHighsMatrixFormatRowwise,
                                   kHighsObjSenseMaximize,
                                   0, col_cost,
                                   col_lower, col_upper, row_lower, row_upper,
                                   a_start, a_index, a_value);
    assert (run_status == kHighsStatusOk);
    {
      const double col_cost[7] =
        { 10.000, 0.000, 0.000, -4.000, 0.000, 0.000, 0.000 };
      const double row_lower[5] =
        { -1000000000000000000000000000000.000, -126.000,
        -1000000000000000000000000000000.000, 9.000, -85.000
      };
      const double row_upper[5] =
        { 15.000, -88.000, 7.000, 1000000000000000000000000000000.000,
        -47.000
      };
      const HighsInt a_start[5] = { 0, 3, 7, 9, 10 };
      const HighsInt a_index[13] = { 3, 5, 6, 1, 3, 4, 5, 3, 4, 1, 0, 4, 6 };
      const double a_value[13] =
        { -3.000, -7.000, 6.000, -7.000, -10.000, 1.000, -6.000, -3.000,
        -3.000, 8.000, 1.000, 9.000, -10.000
      };
      Highs_addRows (highs, 5, row_lower, row_upper, 13, a_start, a_index,
                     a_value);
      Highs_changeColsCostByRange (highs, 0, 6, col_cost);
    }
#ifdef PROVOKE_FAILURE
    {
      Highs_setStringOptionValue (highs, "solver", "simplex");
      Highs_changeObjectiveSense (highs, kHighsObjSenseMinimize);
      assert (Highs_run (highs) == kHighsStatusOk);
      printf ("model_status %d, objective %.4f\n",
              Highs_getModelStatus (highs), Highs_getObjectiveValue (highs));
      assert (Highs_getModelStatus (highs) == kHighsModelStatusOptimal);
      double col_value[7], col_dual[7];
      double row_value[5], row_dual[5];
      Highs_getSolution (highs, col_value, col_dual, row_value, row_dual);
    }
#endif
    {
      const double col_cost[7] =
        { 0.000, 0.000, 0.000, 0.000, 0.000, 2.000, 0.000 };
      const double row_lower[1] = { -1000000000000000000000000000000.000 };
      const double row_upper[1] = { -848.688 };
      const HighsInt a_start[1] = { 0 };
      const HighsInt a_index[2] = { 0, 3 };
      const double a_value[2] = { 10.000, -4.000 };
      Highs_addRows (highs, 1,
                     row_lower, row_upper, 2, a_start, a_index, a_value);
      Highs_changeColsCostByRange (highs, 0, 6, col_cost);
    }
    {
      Highs_setStringOptionValue (highs, "solver", "simplex");
      Highs_changeObjectiveSense (highs, kHighsObjSenseMinimize);
      assert (Highs_run (highs) == kHighsStatusOk);
      printf ("model_status %d, objective %.4f\n",
              Highs_getModelStatus (highs), Highs_getObjectiveValue (highs));
      assert (Highs_getModelStatus (highs) == kHighsModelStatusOptimal);
      double col_value[7], col_dual[7];
      double row_value[6], row_dual[6];
      Highs_getSolution (highs, col_value, col_dual, row_value, row_dual);
    }
    {
      const double col_cost[7] =
        { 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, -7.000 };
      const double row_lower[1] = { -1000000000000000000000000000000.000 };
      const double row_upper[1] = { -106.866 };
      const HighsInt a_start[1] = { 0 };
      const HighsInt a_index[1] = { 5 };
      const double a_value[1] = { 2.000 };
      Highs_addRows (highs, 1,
                     row_lower, row_upper, 1, a_start, a_index, a_value);
      Highs_changeColsCostByRange (highs, 0, 6, col_cost);
    }
    {
      Highs_setStringOptionValue (highs, "solver", "simplex");
      Highs_changeObjectiveSense (highs, kHighsObjSenseMinimize);
      assert (Highs_run (highs) == kHighsStatusOk);
      printf ("model_status %d, objective %.4f\n",
              Highs_getModelStatus (highs), Highs_getObjectiveValue (highs));
      assert (Highs_getModelStatus (highs) == kHighsModelStatusOptimal);
      double col_value[7], col_dual[7];
      double row_value[7], row_dual[7];
      Highs_getSolution (highs, col_value, col_dual, row_value, row_dual);
    }
    Highs_destroy (highs);
  }
  return 0;
}

$ gcc -Wall -owarmstart-incorrect warmstart-incorrect.c $(pkg-config --cflags --libs highs)
$ ./warmstart-incorrect
0x1af1150 = Highs_create()
model_status 7, objective -106.8759
model_status 7, objective 280.0174

$ gcc -DPROVOKE_FAILURE -Wall -owarmstart-incorrect warmstart-incorrect.c $(pkg-config --cflags --libs highs)
$ ./warmstart-incorrect
0x104f150 = Highs_create()
model_status 7, objective -848.6980
model_status 7, objective -106.8759
warmstart-incorrect: warmstart-incorrect.c:105: main: Assertion `Highs_run (highs) == kHighsStatusOk' failed.
Aborted

Observed using latest commit 003f8e5ded5ef1064ecf901cc9089f63b05b566c.

amigalemming avatar Jan 06 '24 18:01 amigalemming

The simplex solver is concerned about a risk of cycling, so has not made the final basis change required to get an optimal solution. I'll look at this in more detail in due course - I've no time now.

jajhall avatar Jan 07 '24 15:01 jajhall

Rather more useful for debugging is issue-1561.c.txt

jajhall avatar Jan 08 '24 11:01 jajhall