// Copyright (C) 2002, International Business Machines
// Corporation and others.  All Rights Reserved.

#include <stdio.h>

#include <assert.h>
#include <iostream>

#include "CoinHelperFunctions.hpp"
#include "CoinPresolveMatrix.hpp"

#if PRESOLVE_DEBUG || PRESOLVE_CONSISTENCY
#include "CoinPresolvePsdebug.hpp"
#endif

/*! \file

  This file contains methods for CoinPostsolveMatrix, the object used during
  postsolve transformations.
*/

/*
  Constructor and destructor for CoinPostsolveMatrix.
*/

/*
  Default constructor

  Postpone allocation of space until we actually load the object.
*/

CoinPostsolveMatrix::CoinPostsolveMatrix
  (int ncols_alloc, int nrows_alloc, CoinBigIndex nelems_alloc)

  : CoinPrePostsolveMatrix(ncols_alloc,nrows_alloc,nelems_alloc),
    free_list_(0),
    maxlink_(nelems_alloc),
    link_(0),
    cdone_(0),
    rdone_(0)

{ /* nothing to do here */ 

  return ; }

/*
  Destructor
*/

CoinPostsolveMatrix::~CoinPostsolveMatrix()

{ delete[] link_ ;

  delete[] cdone_ ;
  delete[] rdone_ ;

  return ; }

/*
  This routine loads a CoinPostsolveMatrix object from a CoinPresolveMatrix
  object. The CoinPresolveMatrix object will be stripped, its components
  transferred to the CoinPostsolveMatrix object, and the empty shell of the
  CoinPresolveObject will be destroyed.

  The routine expects an empty CoinPostsolveMatrix object, and will leak
  any memory already allocated.
*/

void
CoinPostsolveMatrix::assignPresolveToPostsolve (CoinPresolveMatrix *&preObj)

{
/*
  Start with simple data --- allocated and current size.
*/
  ncols0_ = preObj->ncols0_ ;
  nrows0_ = preObj->nrows0_ ;
  nelems0_ = preObj->nelems0_ ;
  bulk0_ = preObj->bulk0_ ;

  ncols_ = preObj->ncols_ ;
  nrows_ = preObj->nrows_ ;
  nelems_ = preObj->nelems_ ;
/*
  Now bring over the column-major matrix and other problem data.
*/
  mcstrt_ = preObj->mcstrt_ ;
  preObj->mcstrt_ = 0 ;
  hincol_ = preObj->hincol_ ;
  preObj->hincol_ = 0 ;
  hrow_ = preObj->hrow_ ;
  preObj->hrow_ = 0 ;
  colels_ = preObj->colels_ ;
  preObj->colels_ = 0 ;

  cost_ = preObj->cost_ ;
  preObj->cost_ = 0 ;
  originalOffset_ = preObj->originalOffset_ ;
  clo_ = preObj->clo_ ;
  preObj->clo_ = 0 ;
  cup_ = preObj->cup_ ;
  preObj->cup_ = 0 ;
  rlo_ = preObj->rlo_ ;
  preObj->rlo_ = 0 ;
  rup_ = preObj->rup_ ;
  preObj->rup_ = 0 ;

  originalColumn_ = preObj->originalColumn_ ;
  preObj->originalColumn_ = 0 ;
  originalRow_ = preObj->originalRow_ ;
  preObj->originalRow_ = 0 ;

  ztolzb_ = preObj->ztolzb_ ;
  ztoldj_ = preObj->ztoldj_ ;
  maxmin_ = preObj->maxmin_ ;
/*
  Now the problem solution. Often this will be empty, but that's not a problem.
*/
  sol_ = preObj->sol_ ;
  preObj->sol_ = 0 ;
  rowduals_ = preObj->rowduals_ ;
  preObj->rowduals_ = 0 ;
  acts_ = preObj->acts_ ;
  preObj->acts_ = 0 ;
  rcosts_ = preObj->rcosts_ ;
  preObj->rcosts_ = 0 ;
  colstat_ = preObj->colstat_ ;
  preObj->colstat_ = 0 ;
  rowstat_ = preObj->rowstat_ ;
  preObj->rowstat_ = 0 ;
/*
  The CoinPostsolveMatrix comes with messages and a handler, but replace them
  with the versions from the CoinPresolveObject, in case they've been
  customized. Let preObj believe it's no longer responsible for the handler.
*/
  if (defaultHandler_ == true)
    delete handler_ ;
  handler_ = preObj->handler_ ;
  preObj->defaultHandler_ = false ;
  messages_ = preObj->messages_ ;
/*
  Initialise the postsolve portions of this object. Which amounts to setting
  up the thread links to match the column-major matrix representation. This
  would be trivial except that the presolve matrix is loosely packed. We can
  either compress the matrix, or record the existing free space pattern. Bet
  that the latter is more efficient. Remember that mcstrt_[ncols_] actually
  points to the end of the bulk storage area, so when we process the last
  column in the bulk storage area, we'll add the free space block at the end
  of bulk storage to the free list.

  We need to allow for a 0x0 matrix here --- a pathological case, but it slips
  in when (for example) confirming a solution in an ILP code.
*/
  free_list_ = NO_LINK ;
  maxlink_ = bulk0_ ;
  link_ = new CoinBigIndex [maxlink_] ;

  if (ncols_ > 0)
  { CoinBigIndex minkcs = -1 ;
    for (int j = 0 ; j < ncols_ ; j++)
    { CoinBigIndex kcs = mcstrt_[j] ;
      int lenj = hincol_[j] ;
      assert(lenj > 0) ;
      CoinBigIndex kce = kcs+lenj-1 ;
      CoinBigIndex k ;

      for (k = kcs ; k < kce ; k++)
      { link_[k] = k+1 ; }
      link_[k++] = NO_LINK ;

      if (preObj->clink_[j].pre == NO_LINK)
      { minkcs = kcs ; }
      int nxtj = preObj->clink_[j].suc ;
      assert(nxtj >= 0 && nxtj <= ncols_) ;
      CoinBigIndex nxtcs = mcstrt_[nxtj] ;
      for ( ; k < nxtcs ; k++)
      { link_[k] = free_list_ ;
	free_list_ = k ; } }

    assert(minkcs >= 0) ;
    if (minkcs > 0)
    { for (CoinBigIndex k = 0 ; k < minkcs ; k++)
      { link_[k] = free_list_ ;
	free_list_ = k ; } } }
  else
  { for (CoinBigIndex k = 0 ; k < maxlink_ ; k++)
    { link_[k] = free_list_ ;
      free_list_ = k ; } }
/*
  That's it, preObj can die now.
*/
  delete preObj ;
  preObj = 0 ;

# if PRESOLVE_DEBUG || PRESOLVE_CONSISTENCY
/*
  These are used to track the action of postsolve transforms during debugging.
*/
  cdone_ = new char [ncols0_] ;
  CoinFillN(cdone_,ncols_,PRESENT_IN_REDUCED) ;
  CoinZeroN(cdone_+ncols_,ncols0_-ncols_) ;
  rdone_ = new char [nrows0_] ;
  CoinFillN(rdone_,nrows_,PRESENT_IN_REDUCED) ;
  CoinZeroN(rdone_+nrows_,nrows0_-nrows_) ;
# endif

# if PRESOLVE_CONSISTENCY
  presolve_check_free_list(this,true) ;
  presolve_check_threads(this) ;
# endif

  return ; }
