/* $Id: ClpDualRowSteepest.cpp 2151 2015-07-09 09:23:15Z forrest $ */
// Copyright (C) 2002, International Business Machines
// Corporation and others.  All Rights Reserved.
// This code is licensed under the terms of the Eclipse Public License (EPL).

#include "CoinPragma.hpp"
#include "ClpSimplex.hpp"
#include "ClpDualRowSteepest.hpp"
#include "CoinIndexedVector.hpp"
#include "ClpFactorization.hpp"
#include "CoinHelperFunctions.hpp"
#include <cstdio>
#if defined(ABOCA_LITE) || defined(CILK_OVERLAP)
#include <cilk/cilk.h>
#endif
//#############################################################################
// Constructors / Destructor / Assignment
//#############################################################################
//#define CLP_DEBUG 4
//-------------------------------------------------------------------
// Default Constructor
//-------------------------------------------------------------------
ClpDualRowSteepest::ClpDualRowSteepest (int mode)
     : ClpDualRowPivot(),
       state_(-1),
       mode_(mode),
       persistence_(normal),
       weights_(NULL),
       infeasible_(NULL),
       alternateWeights_(NULL),
       savedWeights_(NULL),
       dubiousWeights_(NULL)
{
     type_ = 2 + 64 * mode;
}

//-------------------------------------------------------------------
// Copy constructor
//-------------------------------------------------------------------
ClpDualRowSteepest::ClpDualRowSteepest (const ClpDualRowSteepest & rhs)
     : ClpDualRowPivot(rhs)
{
     state_ = rhs.state_;
     mode_ = rhs.mode_;
     persistence_ = rhs.persistence_;
     model_ = rhs.model_;
     if ((model_ && model_->whatsChanged() & 1) != 0) {
          int number = model_->numberRows();
          if (rhs.savedWeights_)
               number = CoinMin(number, rhs.savedWeights_->capacity());
          if (rhs.infeasible_) {
               infeasible_ = new CoinIndexedVector(rhs.infeasible_);
          } else {
               infeasible_ = NULL;
          }
          if (rhs.weights_) {
               weights_ = new double[number];
               ClpDisjointCopyN(rhs.weights_, number, weights_);
          } else {
               weights_ = NULL;
          }
          if (rhs.alternateWeights_) {
               alternateWeights_ = new CoinIndexedVector(rhs.alternateWeights_);
          } else {
               alternateWeights_ = NULL;
          }
          if (rhs.savedWeights_) {
               savedWeights_ = new CoinIndexedVector(rhs.savedWeights_);
          } else {
               savedWeights_ = NULL;
          }
          if (rhs.dubiousWeights_) {
               assert(model_);
               int number = model_->numberRows();
               dubiousWeights_ = new int[number];
               ClpDisjointCopyN(rhs.dubiousWeights_, number, dubiousWeights_);
          } else {
               dubiousWeights_ = NULL;
          }
     } else {
          infeasible_ = NULL;
          weights_ = NULL;
          alternateWeights_ = NULL;
          savedWeights_ = NULL;
          dubiousWeights_ = NULL;
     }
}

//-------------------------------------------------------------------
// Destructor
//-------------------------------------------------------------------
ClpDualRowSteepest::~ClpDualRowSteepest ()
{
     delete [] weights_;
     delete [] dubiousWeights_;
     delete infeasible_;
     delete alternateWeights_;
     delete savedWeights_;
}

//----------------------------------------------------------------
// Assignment operator
//-------------------------------------------------------------------
ClpDualRowSteepest &
ClpDualRowSteepest::operator=(const ClpDualRowSteepest& rhs)
{
     if (this != &rhs) {
          ClpDualRowPivot::operator=(rhs);
          state_ = rhs.state_;
          mode_ = rhs.mode_;
          persistence_ = rhs.persistence_;
          model_ = rhs.model_;
          delete [] weights_;
          delete [] dubiousWeights_;
          delete infeasible_;
          delete alternateWeights_;
          delete savedWeights_;
          assert(model_);
          int number = model_->numberRows();
          if (rhs.savedWeights_)
               number = CoinMin(number, rhs.savedWeights_->capacity());
          if (rhs.infeasible_ != NULL) {
               infeasible_ = new CoinIndexedVector(rhs.infeasible_);
          } else {
               infeasible_ = NULL;
          }
          if (rhs.weights_ != NULL) {
               weights_ = new double[number];
               ClpDisjointCopyN(rhs.weights_, number, weights_);
          } else {
               weights_ = NULL;
          }
          if (rhs.alternateWeights_ != NULL) {
               alternateWeights_ = new CoinIndexedVector(rhs.alternateWeights_);
          } else {
               alternateWeights_ = NULL;
          }
          if (rhs.savedWeights_ != NULL) {
               savedWeights_ = new CoinIndexedVector(rhs.savedWeights_);
          } else {
               savedWeights_ = NULL;
          }
          if (rhs.dubiousWeights_) {
               assert(model_);
               int number = model_->numberRows();
               dubiousWeights_ = new int[number];
               ClpDisjointCopyN(rhs.dubiousWeights_, number, dubiousWeights_);
          } else {
               dubiousWeights_ = NULL;
          }
     }
     return *this;
}
// Fill most values
void
ClpDualRowSteepest::fill(const ClpDualRowSteepest& rhs)
{
     state_ = rhs.state_;
     mode_ = rhs.mode_;
     persistence_ = rhs.persistence_;
     assert (model_->numberRows() == rhs.model_->numberRows());
     model_ = rhs.model_;
     assert(model_);
     int number = model_->numberRows();
     if (rhs.savedWeights_)
          number = CoinMin(number, rhs.savedWeights_->capacity());
     if (rhs.infeasible_ != NULL) {
          if (!infeasible_)
               infeasible_ = new CoinIndexedVector(rhs.infeasible_);
          else
               *infeasible_ = *rhs.infeasible_;
     } else {
          delete infeasible_;
          infeasible_ = NULL;
     }
     if (rhs.weights_ != NULL) {
          if (!weights_)
               weights_ = new double[number];
          ClpDisjointCopyN(rhs.weights_, number, weights_);
     } else {
          delete [] weights_;
          weights_ = NULL;
     }
     if (rhs.alternateWeights_ != NULL) {
          if (!alternateWeights_)
               alternateWeights_ = new CoinIndexedVector(rhs.alternateWeights_);
          else
               *alternateWeights_ = *rhs.alternateWeights_;
     } else {
          delete alternateWeights_;
          alternateWeights_ = NULL;
     }
     if (rhs.savedWeights_ != NULL) {
          if (!savedWeights_)
               savedWeights_ = new CoinIndexedVector(rhs.savedWeights_);
          else
               *savedWeights_ = *rhs.savedWeights_;
     } else {
          delete savedWeights_;
          savedWeights_ = NULL;
     }
     if (rhs.dubiousWeights_) {
          assert(model_);
          int number = model_->numberRows();
          if (!dubiousWeights_)
               dubiousWeights_ = new int[number];
          ClpDisjointCopyN(rhs.dubiousWeights_, number, dubiousWeights_);
     } else {
          delete [] dubiousWeights_;
          dubiousWeights_ = NULL;
     }
}
// Returns pivot row, -1 if none
int
ClpDualRowSteepest::pivotRow()
{
     assert(model_);
     int i, iRow;
     double * infeas = infeasible_->denseVector();
     double largest = 0.0;
     int * index = infeasible_->getIndices();
     int number = infeasible_->getNumElements();
     const int * pivotVariable = model_->pivotVariable();
     int chosenRow = -1;
     int lastPivotRow = model_->pivotRow();
     assert (lastPivotRow < model_->numberRows());
     double tolerance = model_->currentPrimalTolerance();
     // we can't really trust infeasibilities if there is primal error
     // this coding has to mimic coding in checkPrimalSolution
     double error = CoinMin(1.0e-2, model_->largestPrimalError());
     // allow tolerance at least slightly bigger than standard
     tolerance = tolerance +  error;
     // But cap
     tolerance = CoinMin(1000.0, tolerance);
     tolerance *= tolerance; // as we are using squares
     bool toleranceChanged = false;
     double * solution = model_->solutionRegion();
     double * lower = model_->lowerRegion();
     double * upper = model_->upperRegion();
     // do last pivot row one here
     //#define CLP_DUAL_FIXED_COLUMN_MULTIPLIER 10.0
     if (lastPivotRow >= 0 && lastPivotRow < model_->numberRows()) {
#ifdef CLP_DUAL_COLUMN_MULTIPLIER
          int numberColumns = model_->numberColumns();
#endif
          int iPivot = pivotVariable[lastPivotRow];
          double value = solution[iPivot];
          double lower = model_->lower(iPivot);
          double upper = model_->upper(iPivot);
          if (value > upper + tolerance) {
               value -= upper;
               value *= value;
#ifdef CLP_DUAL_COLUMN_MULTIPLIER
               if (iPivot < numberColumns)
                    value *= CLP_DUAL_COLUMN_MULTIPLIER; // bias towards columns
#endif
               // store square in list
               if (infeas[lastPivotRow])
                    infeas[lastPivotRow] = value; // already there
               else
                    infeasible_->quickAdd(lastPivotRow, value);
          } else if (value < lower - tolerance) {
               value -= lower;
               value *= value;
#ifdef CLP_DUAL_COLUMN_MULTIPLIER
               if (iPivot < numberColumns)
                    value *= CLP_DUAL_COLUMN_MULTIPLIER; // bias towards columns
#endif
               // store square in list
               if (infeas[lastPivotRow])
                    infeas[lastPivotRow] = value; // already there
               else
                    infeasible_->add(lastPivotRow, value);
          } else {
               // feasible - was it infeasible - if so set tiny
               if (infeas[lastPivotRow])
                    infeas[lastPivotRow] = COIN_INDEXED_REALLY_TINY_ELEMENT;
          }
          number = infeasible_->getNumElements();
     }
     if(model_->numberIterations() < model_->lastBadIteration() + 200) {
          // we can't really trust infeasibilities if there is dual error
          if (model_->largestDualError() > model_->largestPrimalError()) {
               tolerance *= CoinMin(model_->largestDualError() / model_->largestPrimalError(), 1000.0);
               toleranceChanged = true;
          }
     }
     int numberWanted;
     if (mode_ < 2 ) {
          numberWanted = number + 1;
     } else if (mode_ == 2) {
          numberWanted = CoinMax(2000, number / 8);
     } else {
          int numberElements = model_->factorization()->numberElements();
          double ratio = static_cast<double> (numberElements) /
                         static_cast<double> (model_->numberRows());
          numberWanted = CoinMax(2000, number / 8);
          if (ratio < 1.0) {
               numberWanted = CoinMax(2000, number / 20);
          } else if (ratio > 10.0) {
               ratio = number * (ratio / 80.0);
               if (ratio > number)
                    numberWanted = number + 1;
               else
                    numberWanted = CoinMax(2000, static_cast<int> (ratio));
          }
     }
     if (model_->largestPrimalError() > 1.0e-3)
          numberWanted = number + 1; // be safe
     int iPass;
     // Setup two passes
     int start[4];
     start[1] = number;
     start[2] = 0;
     double dstart = static_cast<double> (number) * model_->randomNumberGenerator()->randomDouble();
     start[0] = static_cast<int> (dstart);
     start[3] = start[0];
     //double largestWeight=0.0;
     //double smallestWeight=1.0e100;
     for (iPass = 0; iPass < 2; iPass++) {
          int end = start[2*iPass+1];
          for (i = start[2*iPass]; i < end; i++) {
               iRow = index[i];
               double value = infeas[iRow];
               if (value > tolerance) {
                    //#define OUT_EQ
#ifdef OUT_EQ
                    {
                         int iSequence = pivotVariable[iRow];
                         if (upper[iSequence] == lower[iSequence])
                              value *= 2.0;
                    }
#endif
                    double weight = CoinMin(weights_[iRow], 1.0e50);
                    //largestWeight = CoinMax(largestWeight,weight);
                    //smallestWeight = CoinMin(smallestWeight,weight);
                    //double dubious = dubiousWeights_[iRow];
                    //weight *= dubious;
                    //if (value>2.0*largest*weight||(value>0.5*largest*weight&&value*largestWeight>dubious*largest*weight)) {
                    if (value > largest * weight) {
                         // make last pivot row last resort choice
                         if (iRow == lastPivotRow) {
                              if (value * 1.0e-10 < largest * weight)
                                   continue;
                              else
                                   value *= 1.0e-10;
                         }
                         int iSequence = pivotVariable[iRow];
                         if (!model_->flagged(iSequence)) {
                              //#define CLP_DEBUG 3
#ifdef CLP_DEBUG
                              double value2 = 0.0;
                              if (solution[iSequence] > upper[iSequence] + tolerance)
                                   value2 = solution[iSequence] - upper[iSequence];
                              else if (solution[iSequence] < lower[iSequence] - tolerance)
                                   value2 = solution[iSequence] - lower[iSequence];
                              assert(fabs(value2 * value2 - infeas[iRow]) < 1.0e-8 * CoinMin(value2 * value2, infeas[iRow]));
#endif
                              if (solution[iSequence] > upper[iSequence] + tolerance ||
                                        solution[iSequence] < lower[iSequence] - tolerance) {
                                   chosenRow = iRow;
                                   largest = value / weight;
                                   //largestWeight = dubious;
                              }
                         } else {
                              // just to make sure we don't exit before got something
                              numberWanted++;
                         }
                    }
                    numberWanted--;
                    if (!numberWanted)
                         break;
               }
          }
          if (!numberWanted)
               break;
     }
     //printf("smallest %g largest %g\n",smallestWeight,largestWeight);
     if (chosenRow < 0 && toleranceChanged) {
          // won't line up with checkPrimalSolution - do again
          double saveError = model_->largestDualError();
          model_->setLargestDualError(0.0);
          // can't loop
          chosenRow = pivotRow();
          model_->setLargestDualError(saveError);
     }
     if (chosenRow < 0 && lastPivotRow < 0) {
          int nLeft = 0;
          for (int i = 0; i < number; i++) {
               int iRow = index[i];
               if (fabs(infeas[iRow]) > 1.0e-50) {
                    index[nLeft++] = iRow;
               } else {
                    infeas[iRow] = 0.0;
               }
          }
          infeasible_->setNumElements(nLeft);
          model_->setNumberPrimalInfeasibilities(nLeft);
     }
     return chosenRow;
}
#if 0
static double ft_count = 0.0;
static double up_count = 0.0;
static double ft_count_in = 0.0;
static double up_count_in = 0.0;
static int xx_count = 0;
#endif
/* Updates weights and returns pivot alpha.
   Also does FT update */
double
ClpDualRowSteepest::updateWeights(CoinIndexedVector * input,
                                  CoinIndexedVector * spare,
                                  CoinIndexedVector * spare2,
                                  CoinIndexedVector * updatedColumn)
{
     //#define CLP_DEBUG 3
#if CLP_DEBUG>2
     // Very expensive debug
     {
          int numberRows = model_->numberRows();
          CoinIndexedVector * temp = new CoinIndexedVector();
          temp->reserve(numberRows +
                        model_->factorization()->maximumPivots());
          double * array = alternateWeights_->denseVector();
          int * which = alternateWeights_->getIndices();
          alternateWeights_->clear();
          int i;
          for (i = 0; i < numberRows; i++) {
               double value = 0.0;
               array[i] = 1.0;
               which[0] = i;
               alternateWeights_->setNumElements(1);
               model_->factorization()->updateColumnTranspose(temp,
                         alternateWeights_);
               int number = alternateWeights_->getNumElements();
               int j;
               for (j = 0; j < number; j++) {
                    int iRow = which[j];
                    value += array[iRow] * array[iRow];
                    array[iRow] = 0.0;
               }
               alternateWeights_->setNumElements(0);
               double w = CoinMax(weights_[i], value) * .1;
               if (fabs(weights_[i] - value) > w) {
                    printf("%d old %g, true %g\n", i, weights_[i], value);
                    weights_[i] = value; // to reduce printout
               }
               //else
               //printf("%d matches %g\n",i,value);
          }
          delete temp;
     }
#endif
     assert (input->packedMode());
     if (!updatedColumn->packedMode()) {
          // I think this means empty
#ifdef COIN_DEVELOP
          printf("updatedColumn not packed mode ClpDualRowSteepest::updateWeights\n");
#endif
          return 0.0;
     }
     double alpha = 0.0;
     if (!model_->factorization()->networkBasis()) {
          // clear other region
          alternateWeights_->clear();
          double norm = 0.0;
          int i;
          double * work = input->denseVector();
          int numberNonZero = input->getNumElements();
          int * which = input->getIndices();
          double * work2 = spare->denseVector();
          int * which2 = spare->getIndices();
          // ftran
          //permute and move indices into index array
          //also compute norm
          //int *regionIndex = alternateWeights_->getIndices (  );
          const int *permute = model_->factorization()->permute();
          //double * region = alternateWeights_->denseVector();
          if (permute) {
               for ( i = 0; i < numberNonZero; i ++ ) {
                    int iRow = which[i];
                    double value = work[i];
                    norm += value * value;
                    iRow = permute[iRow];
                    work2[iRow] = value;
                    which2[i] = iRow;
               }
          } else {
               for ( i = 0; i < numberNonZero; i ++ ) {
                    int iRow = which[i];
                    double value = work[i];
                    norm += value * value;
                    //iRow = permute[iRow];
                    work2[iRow] = value;
                    which2[i] = iRow;
               }
          }
          spare->setNumElements ( numberNonZero );
          // Do FT update
#if 0
          ft_count_in += updatedColumn->getNumElements();
          up_count_in += spare->getNumElements();
#endif
          if (permute || true) {
#if CLP_DEBUG>2
               printf("REGION before %d els\n", spare->getNumElements());
               spare->print();
#endif
               model_->factorization()->updateTwoColumnsFT(spare2, updatedColumn,
                         spare, permute != NULL);
#if CLP_DEBUG>2
               printf("REGION after %d els\n", spare->getNumElements());
               spare->print();
#endif
          } else {
               // Leave as old way
               model_->factorization()->updateColumnFT(spare2, updatedColumn);
               model_->factorization()->updateColumn(spare2, spare, false);
          }
#undef CLP_DEBUG
#if 0
          ft_count += updatedColumn->getNumElements();
          up_count += spare->getNumElements();
          xx_count++;
          if ((xx_count % 1000) == 0)
               printf("zz %d ft %g up %g (in %g %g)\n", xx_count, ft_count, up_count,
                      ft_count_in, up_count_in);
#endif
          numberNonZero = spare->getNumElements();
          // alternateWeights_ should still be empty
          int pivotRow = model_->pivotRow();
#ifdef CLP_DEBUG
          if ( model_->logLevel (  ) > 4  &&
                    fabs(norm - weights_[pivotRow]) > 1.0e-3 * (1.0 + norm))
               printf("on row %d, true weight %g, old %g\n",
                      pivotRow, sqrt(norm), sqrt(weights_[pivotRow]));
#endif
          // could re-initialize here (could be expensive)
          norm /= model_->alpha() * model_->alpha();
          assert(model_->alpha());
          assert(norm);
          // pivot element
          alpha = 0.0;
          double multiplier = 2.0 / model_->alpha();
          // look at updated column
          work = updatedColumn->denseVector();
          numberNonZero = updatedColumn->getNumElements();
          which = updatedColumn->getIndices();

          int nSave = 0;
          double * work3 = alternateWeights_->denseVector();
          int * which3 = alternateWeights_->getIndices();
          const int * pivotColumn = model_->factorization()->pivotColumn();
          for (i = 0; i < numberNonZero; i++) {
               int iRow = which[i];
               double theta = work[i];
               if (iRow == pivotRow)
                    alpha = theta;
               double devex = weights_[iRow];
               work3[nSave] = devex; // save old
               which3[nSave++] = iRow;
               // transform to match spare
               int jRow = permute ? pivotColumn[iRow] : iRow;
               double value = work2[jRow];
               devex +=  theta * (theta * norm + value * multiplier);
               if (devex < DEVEX_TRY_NORM)
                    devex = DEVEX_TRY_NORM;
               weights_[iRow] = devex;
          }
          alternateWeights_->setPackedMode(true);
          alternateWeights_->setNumElements(nSave);
          if (norm < DEVEX_TRY_NORM)
               norm = DEVEX_TRY_NORM;
          // Try this to make less likely will happen again and stop cycling
          //norm *= 1.02;
          weights_[pivotRow] = norm;
          spare->clear();
#ifdef CLP_DEBUG
          spare->checkClear();
#endif
     } else {
          // Do FT update
          model_->factorization()->updateColumnFT(spare, updatedColumn);
          // clear other region
          alternateWeights_->clear();
          double norm = 0.0;
          int i;
          double * work = input->denseVector();
          int number = input->getNumElements();
          int * which = input->getIndices();
          double * work2 = spare->denseVector();
          int * which2 = spare->getIndices();
          for (i = 0; i < number; i++) {
               int iRow = which[i];
               double value = work[i];
               norm += value * value;
               work2[iRow] = value;
               which2[i] = iRow;
          }
          spare->setNumElements(number);
          // ftran
#ifndef NDEBUG
          alternateWeights_->checkClear();
#endif
          model_->factorization()->updateColumn(alternateWeights_, spare);
          // alternateWeights_ should still be empty
#ifndef NDEBUG
          alternateWeights_->checkClear();
#endif
          int pivotRow = model_->pivotRow();
#ifdef CLP_DEBUG
          if ( model_->logLevel (  ) > 4  &&
                    fabs(norm - weights_[pivotRow]) > 1.0e-3 * (1.0 + norm))
               printf("on row %d, true weight %g, old %g\n",
                      pivotRow, sqrt(norm), sqrt(weights_[pivotRow]));
#endif
          // could re-initialize here (could be expensive)
          norm /= model_->alpha() * model_->alpha();

          assert(norm);
          //if (norm < DEVEX_TRY_NORM)
          //norm = DEVEX_TRY_NORM;
          // pivot element
          alpha = 0.0;
          double multiplier = 2.0 / model_->alpha();
          // look at updated column
          work = updatedColumn->denseVector();
          number = updatedColumn->getNumElements();
          which = updatedColumn->getIndices();

          int nSave = 0;
          double * work3 = alternateWeights_->denseVector();
          int * which3 = alternateWeights_->getIndices();
          for (i = 0; i < number; i++) {
               int iRow = which[i];
               double theta = work[i];
               if (iRow == pivotRow)
                    alpha = theta;
               double devex = weights_[iRow];
               work3[nSave] = devex; // save old
               which3[nSave++] = iRow;
               double value = work2[iRow];
               devex +=  theta * (theta * norm + value * multiplier);
               if (devex < DEVEX_TRY_NORM)
                    devex = DEVEX_TRY_NORM;
               weights_[iRow] = devex;
          }
          if (!alpha) {
               // error - but carry on
               alpha = 1.0e-50;
          }
          alternateWeights_->setPackedMode(true);
          alternateWeights_->setNumElements(nSave);
          if (norm < DEVEX_TRY_NORM)
               norm = DEVEX_TRY_NORM;
          weights_[pivotRow] = norm;
          spare->clear();
     }
#ifdef CLP_DEBUG
     spare->checkClear();
#endif
     return alpha;
}

#if ABOCA_LITE
typedef struct {
  double tolerance;
  double primalRatio;
  double changeObj;
  const double * cost;
  double * solution;
  const double * lower;
  const double * upper;
  double * work;
  int * which;
  double * infeas;
  const int * pivotVariable;
  int numberAdded;
  int numberToDo;
#ifdef CLP_DUAL_COLUMN_MULTIPLIER
  int numberColumns;
#endif
} update_primals;
static void
updatePrimalBit(update_primals & info)
{
  int numberAdded = 0;
  double tolerance = info.tolerance;
  double primalRatio = info.primalRatio;
  double changeObj=0.0;
  const double * COIN_RESTRICT costModel = info.cost;
  const double * COIN_RESTRICT lowerModel = info.lower;
  const double * COIN_RESTRICT upperModel = info.upper;
  double * COIN_RESTRICT solution = info.solution;
  double * COIN_RESTRICT infeas = info.infeas;
  const int * COIN_RESTRICT pivotVariable = info.pivotVariable;
  double * COIN_RESTRICT work = info.work;
  int number = info.numberToDo;
  int * COIN_RESTRICT which = info.which;
#ifdef CLP_DUAL_COLUMN_MULTIPLIER
  int numberColumns = info.numberColumns;
#endif
  for (int i = 0; i < number; i++) {
    int iRow = which[i];
    int iPivot = pivotVariable[iRow];
    double value = solution[iPivot];
    double cost = costModel[iPivot];
    double change = primalRatio * work[i];
    work[i] = 0.0;
    value -= change;
    changeObj -= change * cost;
    double lower = lowerModel[iPivot];
    double upper = upperModel[iPivot];
    solution[iPivot] = value;
    if (value < lower - tolerance) {
      value -= lower;
      value *= value;
#ifdef CLP_DUAL_COLUMN_MULTIPLIER
      if (iPivot < numberColumns)
	value *= CLP_DUAL_COLUMN_MULTIPLIER; // bias towards columns
#endif
#ifdef CLP_DUAL_FIXED_COLUMN_MULTIPLIER
      if (lower == upper)
	value *= CLP_DUAL_FIXED_COLUMN_MULTIPLIER; // bias towards taking out fixed variables
#endif
      // store square in list
      if (!infeas[iRow]) 
	which[numberAdded++]=iRow;
      infeas[iRow] = value;
    } else if (value > upper + tolerance) {
      value -= upper;
      value *= value;
#ifdef CLP_DUAL_COLUMN_MULTIPLIER
      if (iPivot < numberColumns)
	value *= CLP_DUAL_COLUMN_MULTIPLIER; // bias towards columns
#endif
#ifdef CLP_DUAL_FIXED_COLUMN_MULTIPLIER
      if (lower == upper)
	value *= CLP_DUAL_FIXED_COLUMN_MULTIPLIER; // bias towards taking out fixed variables
#endif
      // store square in list
      if (!infeas[iRow]) 
	which[numberAdded++]=iRow;
      infeas[iRow] = value;
    } else {
      // feasible - was it infeasible - if so set tiny
      if (infeas[iRow])
	infeas[iRow] = COIN_INDEXED_REALLY_TINY_ELEMENT;
    }
  }
  info.numberAdded = numberAdded;
  info.changeObj = changeObj;
}
#endif
/* Updates primal solution (and maybe list of candidates)
   Uses input vector which it deletes
   Computes change in objective function
*/
void
ClpDualRowSteepest::updatePrimalSolution(
     CoinIndexedVector * primalUpdate,
     double primalRatio,
     double & objectiveChange)
{
     double * COIN_RESTRICT work = primalUpdate->denseVector();
     int number = primalUpdate->getNumElements();
     int * COIN_RESTRICT which = primalUpdate->getIndices();
     int i;
     double changeObj = 0.0;
     double tolerance = model_->currentPrimalTolerance();
     const int * COIN_RESTRICT pivotVariable = model_->pivotVariable();
     double * COIN_RESTRICT infeas = infeasible_->denseVector();
     double * COIN_RESTRICT solution = model_->solutionRegion();
     const double * COIN_RESTRICT costModel = model_->costRegion();
     const double * COIN_RESTRICT lowerModel = model_->lowerRegion();
     const double * COIN_RESTRICT upperModel = model_->upperRegion();
#ifdef CLP_DUAL_COLUMN_MULTIPLIER
     int numberColumns = model_->numberColumns();
#endif
     if (primalUpdate->packedMode()) {
#if ABOCA_LITE == 0 
          for (i = 0; i < number; i++) {
               int iRow = which[i];
               int iPivot = pivotVariable[iRow];
               double value = solution[iPivot];
               double cost = costModel[iPivot];
               double change = primalRatio * work[i];
               work[i] = 0.0;
               value -= change;
               changeObj -= change * cost;
               double lower = lowerModel[iPivot];
               double upper = upperModel[iPivot];
               solution[iPivot] = value;
               if (value < lower - tolerance) {
                    value -= lower;
                    value *= value;
#ifdef CLP_DUAL_COLUMN_MULTIPLIER
                    if (iPivot < numberColumns)
                         value *= CLP_DUAL_COLUMN_MULTIPLIER; // bias towards columns
#endif
#ifdef CLP_DUAL_FIXED_COLUMN_MULTIPLIER
                    if (lower == upper)
                         value *= CLP_DUAL_FIXED_COLUMN_MULTIPLIER; // bias towards taking out fixed variables
#endif
                    // store square in list
                    if (infeas[iRow])
                         infeas[iRow] = value; // already there
                    else
                         infeasible_->quickAdd(iRow, value);
               } else if (value > upper + tolerance) {
                    value -= upper;
                    value *= value;
#ifdef CLP_DUAL_COLUMN_MULTIPLIER
                    if (iPivot < numberColumns)
                         value *= CLP_DUAL_COLUMN_MULTIPLIER; // bias towards columns
#endif
#ifdef CLP_DUAL_FIXED_COLUMN_MULTIPLIER
                    if (lower == upper)
                         value *= CLP_DUAL_FIXED_COLUMN_MULTIPLIER; // bias towards taking out fixed variables
#endif
                    // store square in list
                    if (infeas[iRow])
                         infeas[iRow] = value; // already there
                    else
                         infeasible_->quickAdd(iRow, value);
               } else {
                    // feasible - was it infeasible - if so set tiny
                    if (infeas[iRow])
                         infeas[iRow] = COIN_INDEXED_REALLY_TINY_ELEMENT;
               }
          }
#else
	       update_primals info[ABOCA_LITE];
	       int chunk = (number+ABOCA_LITE-1)/ABOCA_LITE;
	       int n=0;
	       for (i=0;i<ABOCA_LITE;i++) {
		 info[i].primalRatio=primalRatio;
		 info[i].tolerance=tolerance;
		 info[i].cost = costModel;
		 info[i].solution = solution;
		 info[i].lower = lowerModel;
		 info[i].upper = upperModel;
		 info[i].infeas = infeas;
		 info[i].pivotVariable = pivotVariable;
		 info[i].which=which+n;
		 info[i].work=work+n;
		 info[i].numberToDo=CoinMin(chunk,number-n);
#ifdef CLP_DUAL_COLUMN_MULTIPLIER
		 info.numberColumns = numberColumns;
#endif
		 n += chunk;
	       }
	       for (i=0;i<ABOCA_LITE;i++) {
		 cilk_spawn updatePrimalBit(info[i]);
		 //updatePrimalBit(info[i]);
	       }
	       cilk_sync;
	       n=infeasible_->getNumElements();
	       int * COIN_RESTRICT index = infeasible_->getIndices();
	       for (i=0;i<ABOCA_LITE;i++) {
		 int numberAdded=info[i].numberAdded;
		 int * which=info[i].which;
		 for (int j=0;j<numberAdded;j++) 
		   index[n++]=which[j];
		 changeObj += info[i].changeObj;
	       }
	       infeasible_->setNumElements(n);
#endif
     } else {
          for (i = 0; i < number; i++) {
               int iRow = which[i];
               int iPivot = pivotVariable[iRow];
               double value = solution[iPivot];
               double cost = costModel[iPivot];
               double change = primalRatio * work[iRow];
               value -= change;
               changeObj -= change * cost;
               double lower = lowerModel[iPivot];
               double upper = upperModel[iPivot];
               solution[iPivot] = value;
               if (value < lower - tolerance) {
                    value -= lower;
                    value *= value;
#ifdef CLP_DUAL_COLUMN_MULTIPLIER
                    if (iPivot < numberColumns)
                         value *= CLP_DUAL_COLUMN_MULTIPLIER; // bias towards columns
#endif
#ifdef CLP_DUAL_FIXED_COLUMN_MULTIPLIER
                    if (lower == upper)
                         value *= CLP_DUAL_FIXED_COLUMN_MULTIPLIER; // bias towards taking out fixed variables
#endif
                    // store square in list
                    if (infeas[iRow])
                         infeas[iRow] = value; // already there
                    else
                         infeasible_->quickAdd(iRow, value);
               } else if (value > upper + tolerance) {
                    value -= upper;
                    value *= value;
#ifdef CLP_DUAL_COLUMN_MULTIPLIER
                    if (iPivot < numberColumns)
                         value *= CLP_DUAL_COLUMN_MULTIPLIER; // bias towards columns
#endif
#ifdef CLP_DUAL_FIXED_COLUMN_MULTIPLIER
                    if (lower == upper)
                         value *= CLP_DUAL_FIXED_COLUMN_MULTIPLIER; // bias towards taking out fixed variables
#endif
                    // store square in list
                    if (infeas[iRow])
                         infeas[iRow] = value; // already there
                    else
                         infeasible_->quickAdd(iRow, value);
               } else {
                    // feasible - was it infeasible - if so set tiny
                    if (infeas[iRow])
                         infeas[iRow] = COIN_INDEXED_REALLY_TINY_ELEMENT;
               }
               work[iRow] = 0.0;
          }
     }
     // Do pivot row
     {
          int iRow = model_->pivotRow();
          // feasible - was it infeasible - if so set tiny
          //assert (infeas[iRow]);
          if (infeas[iRow])
               infeas[iRow] = COIN_INDEXED_REALLY_TINY_ELEMENT;
     }
     primalUpdate->setNumElements(0);
     objectiveChange += changeObj;
}
/* Saves any weights round factorization as pivot rows may change
   1) before factorization
   2) after factorization
   3) just redo infeasibilities
   4) as 2 but restore weights from previous snapshot
   5) for strong branching - initialize to 1 , infeasibilities
   6) scale back
   7) for strong branching - initialize full weights , infeasibilities
*/
void
ClpDualRowSteepest::saveWeights(ClpSimplex * model, int mode)
{
     // alternateWeights_ is defined as indexed but is treated oddly
     model_ = model;
     int numberRows = model_->numberRows();
     int numberColumns = model_->numberColumns();
     const int * pivotVariable = model_->pivotVariable();
     int i;
     if (mode == 1) {
          if(weights_) {
               // Check if size has changed
               if (infeasible_->capacity() == numberRows) {
                    alternateWeights_->clear();
                    // change from row numbers to sequence numbers
                    int * which = alternateWeights_->getIndices();
                    for (i = 0; i < numberRows; i++) {
                         int iPivot = pivotVariable[i];
                         which[i] = iPivot;
                    }
                    state_ = 1;
		    // clear marker on savedWeights_
		    assert (savedWeights_);
		    if (savedWeights_->packedMode()) {
		      savedWeights_->setPackedMode(false);
		      savedWeights_->setNumElements(0);
		    }
               } else {
                    // size has changed - clear everything
                    delete [] weights_;
                    weights_ = NULL;
                    delete [] dubiousWeights_;
                    dubiousWeights_ = NULL;
                    delete infeasible_;
                    infeasible_ = NULL;
                    delete alternateWeights_;
                    alternateWeights_ = NULL;
                    delete savedWeights_;
                    savedWeights_ = NULL;
                    state_ = -1;
               }
          }
     } else if (mode == 2 || mode == 4 || mode >= 5) {
          // restore
          if (!weights_ || state_ == -1 || mode == 5 || mode == 7) {
               // initialize weights
               delete [] weights_;
               delete alternateWeights_;
               weights_ = new double[numberRows];
	       // initialize to 1.0 (can we do better?)
	       for (i = 0; i < numberRows; i++) {
		 weights_[i] = 1.0;
	       }
               alternateWeights_ = new CoinIndexedVector();
               // enough space so can use it for factorization
               alternateWeights_->reserve(numberRows +
                                          model_->factorization()->maximumPivots());
               if (mode_ != 1 || mode == 5) {
               } else {
                    CoinIndexedVector * temp = new CoinIndexedVector();
                    temp->reserve(numberRows +
                                  model_->factorization()->maximumPivots());
                    double * array = alternateWeights_->denseVector();
                    int * which = alternateWeights_->getIndices();
		    int firstRow=0;
		    int lastRow=numberRows;
		    if (mode==7) {
		      // use info passed in
		      firstRow=model->spareIntArray_[0];
		      lastRow=model->spareIntArray_[1];
		    }
                    for (i = firstRow; i < lastRow; i++) {
                         double value = 0.0;
                         array[0] = 1.0;
                         which[0] = i;
                         alternateWeights_->setNumElements(1);
                         alternateWeights_->setPackedMode(true);
                         model_->factorization()->updateColumnTranspose(temp,
                                   alternateWeights_);
                         int number = alternateWeights_->getNumElements();
                         int j;
                         for (j = 0; j < number; j++) {
                              value += array[j] * array[j];
                              array[j] = 0.0;
                         }
                         alternateWeights_->setNumElements(0);
                         weights_[i] = value;
                    }
                    delete temp;
               }
               // create saved weights (not really indexedvector)
               savedWeights_ = new CoinIndexedVector();
               savedWeights_->reserve(numberRows);
	       for (int i=0;i<model_->numberRows();i++)
		 savedWeights_->denseVector()[i]=1.0;

               double * array = savedWeights_->denseVector();
               int * which = savedWeights_->getIndices();
               for (int i = 0; i < numberRows; i++) {
                    array[i] = weights_[i];
                    which[i] = pivotVariable[i];
               }
	       if (mode==7) {
		 savedWeights_->setNumElements(numberRows); //flag as special
		 savedWeights_->setPackedMode(true);
	       }
          } else if (mode != 6) {
               int * which = alternateWeights_->getIndices();
               CoinIndexedVector * rowArray3 = model_->rowArray(3);
               rowArray3->clear();
               int * back = rowArray3->getIndices();
               // In case something went wrong
               for (i = 0; i < numberRows + numberColumns; i++)
                    back[i] = -1;
               if (mode != 4) {
                    // save
                    CoinMemcpyN(which,	numberRows, savedWeights_->getIndices());
                    CoinMemcpyN(weights_,	numberRows, savedWeights_->denseVector());
               } else {
                    // restore
                    //memcpy(which,savedWeights_->getIndices(),
                    //     numberRows*sizeof(int));
                    //memcpy(weights_,savedWeights_->denseVector(),
                    //     numberRows*sizeof(double));
                    which = savedWeights_->getIndices();
               }
               // restore (a bit slow - but only every re-factorization)
               double * array = savedWeights_->denseVector();
               for (i = 0; i < numberRows; i++) {
                    int iSeq = which[i];
                    back[iSeq] = i;
               }
	       int firstRow=0;
	       int lastRow=numberRows;
	       if (mode==7) {
		 // use info passed in
		 firstRow=model->spareIntArray_[0];
		 lastRow=model->spareIntArray_[1];
	       }
               for (i = firstRow; i < lastRow; i++) {
                    int iPivot = pivotVariable[i];
                    iPivot = back[iPivot];
                    if (iPivot >= 0) {
                         weights_[i] = array[iPivot];
                         if (weights_[i] < DEVEX_TRY_NORM)
                              weights_[i] = DEVEX_TRY_NORM; // may need to check more
                    } else {
                         // odd
                         weights_[i] = 1.0;
			 //printf("bad pivot row %d (%d->%d) iPivot %d\n",i,firstRow,lastRow,iPivot);
                    }
               }
#if 0
	       printf("mode %d mode_ %d state_ %d\n",mode,mode_,state_);
	       if (!model_->numberIterations()) {
		 for (int k=0;k<numberRows;k+=10)
		   printf("%d %g ",k,weights_[k]);
		 printf("\n");
	       }
#endif
          } else {
               // mode 6 - scale back weights as primal errors
               double primalError = model_->largestPrimalError();
               double allowed ;
               if (primalError > 1.0e3)
                    allowed = 10.0;
               else if (primalError > 1.0e2)
                    allowed = 50.0;
               else if (primalError > 1.0e1)
                    allowed = 100.0;
               else
                    allowed = 1000.0;
               double allowedInv = 1.0 / allowed;
               for (i = 0; i < numberRows; i++) {
                    double value = weights_[i];
                    if (value < allowedInv)
                         value = allowedInv;
                    else if (value > allowed)
                         value = allowed;
                    weights_[i] = allowed;
               }
          }
          state_ = 0;
          // set up infeasibilities
          if (!infeasible_) {
               infeasible_ = new CoinIndexedVector();
               infeasible_->reserve(numberRows);
          }
     }
     if (mode >= 2) {
          // Get dubious weights
          //if (!dubiousWeights_)
          //dubiousWeights_=new int[numberRows];
          //model_->factorization()->getWeights(dubiousWeights_);
          infeasible_->clear();
          int iRow;
          const int * pivotVariable = model_->pivotVariable();
          double tolerance = model_->currentPrimalTolerance();
          for (iRow = 0; iRow < numberRows; iRow++) {
               int iPivot = pivotVariable[iRow];
               double value = model_->solution(iPivot);
               double lower = model_->lower(iPivot);
               double upper = model_->upper(iPivot);
               if (value < lower - tolerance) {
                    value -= lower;
                    value *= value;
#ifdef CLP_DUAL_COLUMN_MULTIPLIER
                    if (iPivot < numberColumns)
                         value *= CLP_DUAL_COLUMN_MULTIPLIER; // bias towards columns
#endif
#ifdef CLP_DUAL_FIXED_COLUMN_MULTIPLIER
                    if (lower == upper)
                         value *= CLP_DUAL_FIXED_COLUMN_MULTIPLIER; // bias towards taking out fixed variables
#endif
                    // store square in list
                    infeasible_->quickAdd(iRow, value);
               } else if (value > upper + tolerance) {
                    value -= upper;
                    value *= value;
#ifdef CLP_DUAL_COLUMN_MULTIPLIER
                    if (iPivot < numberColumns)
                         value *= CLP_DUAL_COLUMN_MULTIPLIER; // bias towards columns
#endif
#ifdef CLP_DUAL_FIXED_COLUMN_MULTIPLIER
                    if (lower == upper)
                         value *= CLP_DUAL_FIXED_COLUMN_MULTIPLIER; // bias towards taking out fixed variables
#endif
                    // store square in list
                    infeasible_->quickAdd(iRow, value);
               }
          }
     }
     // see where coming from
     if (mode==2&&!model->numberIterations()) {
       int options=model->specialOptions();
       if ((options&16384)!=0&&true) {
	 // fast of some sort - could be clever???
	 // for now initialize
	 if ((options&524288)!=0&&false) {
	   // fathom 
	   for (int i = 0; i < numberRows; i++) 
	     weights_[i] = 1.0;
	 } else if (true) {
	   // strong
	   for (int i = 0; i < numberRows; i++) 
	     weights_[i] = 1.0;
	 }
       }
     }
}
// Pass in saved weights
void 
ClpDualRowSteepest::passInSavedWeights(const CoinIndexedVector * saved)
{
  delete savedWeights_;
  savedWeights_=new CoinIndexedVector(*saved);
}
// Gets rid of last update
void
ClpDualRowSteepest::unrollWeights()
{
     double * saved = alternateWeights_->denseVector();
     int number = alternateWeights_->getNumElements();
     int * which = alternateWeights_->getIndices();
     int i;
     if (alternateWeights_->packedMode()) {
          for (i = 0; i < number; i++) {
               int iRow = which[i];
               weights_[iRow] = saved[i];
               saved[i] = 0.0;
          }
     } else {
          for (i = 0; i < number; i++) {
               int iRow = which[i];
               weights_[iRow] = saved[iRow];
               saved[iRow] = 0.0;
          }
     }
     alternateWeights_->setNumElements(0);
}
//-------------------------------------------------------------------
// Clone
//-------------------------------------------------------------------
ClpDualRowPivot * ClpDualRowSteepest::clone(bool CopyData) const
{
     if (CopyData) {
          return new ClpDualRowSteepest(*this);
     } else {
          return new ClpDualRowSteepest();
     }
}
// Gets rid of all arrays
void
ClpDualRowSteepest::clearArrays()
{
     if (persistence_ == normal) {
          delete [] weights_;
          weights_ = NULL;
          delete [] dubiousWeights_;
          dubiousWeights_ = NULL;
          delete infeasible_;
          infeasible_ = NULL;
          delete alternateWeights_;
          alternateWeights_ = NULL;
          delete savedWeights_;
          savedWeights_ = NULL;
     }
     state_ = -1;
}
// Returns true if would not find any row
bool
ClpDualRowSteepest::looksOptimal() const
{
     int iRow;
     const int * pivotVariable = model_->pivotVariable();
     double tolerance = model_->currentPrimalTolerance();
     // we can't really trust infeasibilities if there is primal error
     // this coding has to mimic coding in checkPrimalSolution
     double error = CoinMin(1.0e-2, model_->largestPrimalError());
     // allow tolerance at least slightly bigger than standard
     tolerance = tolerance +  error;
     // But cap
     tolerance = CoinMin(1000.0, tolerance);
     int numberRows = model_->numberRows();
     int numberInfeasible = 0;
     for (iRow = 0; iRow < numberRows; iRow++) {
          int iPivot = pivotVariable[iRow];
          double value = model_->solution(iPivot);
          double lower = model_->lower(iPivot);
          double upper = model_->upper(iPivot);
          if (value < lower - tolerance) {
               numberInfeasible++;
          } else if (value > upper + tolerance) {
               numberInfeasible++;
          }
     }
     return (numberInfeasible == 0);
}
// Called when maximum pivots changes
void
ClpDualRowSteepest::maximumPivotsChanged()
{
     if (alternateWeights_ &&
               alternateWeights_->capacity() != model_->numberRows() +
               model_->factorization()->maximumPivots()) {
          delete alternateWeights_;
          alternateWeights_ = new CoinIndexedVector();
          // enough space so can use it for factorization
          alternateWeights_->reserve(model_->numberRows() +
                                     model_->factorization()->maximumPivots());
     }
}

