/* $Id: separateWithDisjunction.cpp 694 2011-06-18 20:13:17Z stefan $
 *
 * Name:    separateWithDisjunction.cpp
 * Author:  Pietro Belotti
 * Purpose: generate cuts of disjunction
 *
 * (C) Carnegie-Mellon University, 2008. 
 * This file is licensed under the Eclipse Public License (EPL)
 */

#include "CouennePrecisions.hpp"
#include "CouenneDisjCuts.hpp"
#include "CouenneCutGenerator.hpp"
#include "CouenneProblem.hpp"

using namespace Ipopt;
using namespace Couenne;

/// generate row cuts for one side of the  disjunction
int CouenneDisjCuts::separateWithDisjunction (OsiCuts *cuts, 
					      OsiSolverInterface &si, 
					      OsiCuts &cs, 
					      const CglTreeInfo &info) const {

  if (jnlst_ -> ProduceOutput (J_VECTOR, J_DISJCUTS) && 
      ((cuts -> sizeRowCuts ()) ||
       (cuts -> sizeColCuts ()))) {

    printf ("applying unilateral cuts:\n");

    if (cuts -> sizeRowCuts ()) {
      printf ("Row\n");
      for (int i=0; i < cuts -> sizeRowCuts (); i++) cuts -> rowCutPtr (i) -> print ();
    }

    if (cuts -> sizeColCuts ()) {
      printf (" Col\n");
      for (int i=0; i < cuts -> sizeColCuts (); i++) cuts -> colCutPtr (i) -> print ();
    }
  }

  int ncols = si.getNumCols ();
  t_chg_bounds *chg = new t_chg_bounds [ncols]; // all init'd automatically to UNCHANGED
  CouenneProblem *p = couenneCG_ -> Problem ();

  p -> domain () -> push (&si);

  // apply cuts
  for (int i = cuts -> sizeColCuts (); i--;) {

    const CoinPackedVector
      &lb = cuts -> colCutPtr (i) -> lbs (),
      &ub = cuts -> colCutPtr (i) -> ubs ();

    const int 
      *lind = lb.getIndices (),
      *uind = ub.getIndices ();
 
    const double
      *lval = lb.getElements (),    *oLB = si.getColLower (),
      *uval = ub.getElements (),    *oUB = si.getColUpper ();

    for (int j=lb.getNumElements (); j--; lind++, lval++)
      if (*lval > oLB [*lind] + COUENNE_EPS) {
	p -> Lb (*lind) = *lval;
	chg [*lind].setLower (t_chg_bounds::CHANGED);
      }

    for (int j=ub.getNumElements (); j--; uind++, uval++)
      if (*uval < oUB [*uind] - COUENNE_EPS) {
	p -> Ub (*uind) = *uval;
	chg [*uind].setUpper (t_chg_bounds::CHANGED);
      }
  }

  int *changed = NULL, // will be created within sparse2dense
    nchanged = 0;

  sparse2dense (ncols, chg, changed, nchanged);

  couenneCG_ -> genRowCuts (si, *cuts, nchanged, changed, chg);

  p -> domain () -> pop ();

  delete [] chg;

  if (changed)
    free (changed);

  return COUENNE_FEASIBLE;
}
