// $Id: CglTreeInfo.hpp 1201 2014-03-07 17:24:04Z forrest $
// Copyright (C) 2000, International Business Machines
// Corporation and others.  All Rights Reserved.
// This code is licensed under the terms of the Eclipse Public License (EPL).

#ifndef CglTreeInfo_H
#define CglTreeInfo_H

#include "OsiCuts.hpp"
#include "OsiSolverInterface.hpp"
#include "CoinHelperFunctions.hpp"
class CglStored;
/** Information about where the cut generator is invoked from. */

class CglTreeInfo {
public:
  /// The level of the search tree node 
  int level;
  /** How many times the cut generator was already invoked in this search tree
      node */
  int pass;
  /** The number of rows in the original formulation. Some generators may not
      want to consider already generated rows when generating new ones. */
  int formulation_rows;
  /** Options 
      1 - treat costed integers as important
      2 - switch off some stuff as variables semi-integer
      4 - set global cut flag if at root node
      8 - set global cut flag if at root node and first pass
      16 - set global cut flag and make cuts globally valid
      32 - last round of cuts did nothing - maybe be more aggressive
      64 - in preprocessing stage
      128 - looks like solution
      256 - want alternate cuts
      512 - in sub tree (i.e. parent model)
      1024 - in must call again mode or after everything mode
  */
  int options;
  /// Set true if in tree (to avoid ambiguity at first branch)
  bool inTree;
  /** Replacement array.  Before Branch and Cut it may be beneficial to strengthen rows
      rather than adding cuts.  If this array is not NULL then the cut generator can
      place a pointer to the stronger cut in this array which is number of rows in size.

      A null (i.e. zero elements and free rhs) cut indicates that the row is useless 
      and can be removed.

      The calling function can then replace those rows.
  */
  OsiRowCut ** strengthenRow;
  /// Optional pointer to thread specific random number generator
  CoinThreadRandom * randomNumberGenerator;
  /// Default constructor 
  CglTreeInfo ();
 
  /// Copy constructor 
  CglTreeInfo (
    const CglTreeInfo &);
  /// Clone
  virtual CglTreeInfo * clone() const;

  /// Assignment operator 
  CglTreeInfo &
    operator=(
    const CglTreeInfo& rhs);
  
  /// Destructor 
  virtual
    ~CglTreeInfo ();
  /// Take action if cut generator can fix a variable (toValue -1 for down, +1 for up)
  virtual bool fixes(int , int , int ,bool) {return false;}
  /** Initalizes fixing arrays etc - returns >0 if we want to save info
      0 if we don't and -1 if is to be used */
  virtual int initializeFixing(const OsiSolverInterface * ) {return 0;}
  
};

/** Derived class to pick up probing info. */
typedef struct {
  //unsigned int oneFixed:1; //  nonzero if variable to 1 fixes all
  //unsigned int sequence:31; //  variable (in matrix) (but also see cliqueRow_)
  unsigned int fixes;
} CliqueEntry;

class CglTreeProbingInfo : public CglTreeInfo {
public:
  /// Default constructor 
  CglTreeProbingInfo ();
  /// Constructor from model
  CglTreeProbingInfo (const OsiSolverInterface * model);
 
  /// Copy constructor 
  CglTreeProbingInfo (
    const CglTreeProbingInfo &);
  /// Clone
  virtual CglTreeInfo * clone() const;

  /// Assignment operator 
  CglTreeProbingInfo &
    operator=(
    const CglTreeProbingInfo& rhs);
  
  /// Destructor 
  virtual
    ~CglTreeProbingInfo ();
  OsiSolverInterface * analyze(const OsiSolverInterface & si, int createSolver=0,
			       int numberExtraCliques=0,const int * starts=NULL,
			       const CliqueEntry * entries=NULL,const char * type=NULL);
  /** Take action if cut generator can fix a variable 
      (toValue -1 for down, +1 for up)
      Returns true if still room, false if not  */
  virtual bool fixes(int variable, int toValue, int fixedVariable,bool fixedToLower);
  /** Initalizes fixing arrays etc - returns >0 if we want to save info
      0 if we don't and -1 if is to be used */
  virtual int initializeFixing(const OsiSolverInterface * model) ;
  /// Fix entries in a solver using implications
  int fixColumns(OsiSolverInterface & si) const;
  /// Fix entries in a solver using implications for one variable
  int fixColumns(int iColumn, int value, OsiSolverInterface & si) const;
  /// Packs down entries
  int packDown();
  /// Generate cuts from implications
  void generateCuts(const OsiSolverInterface & si, OsiCuts & cs,
		    const CglTreeInfo info) const;
  /// Entries for fixing variables
  inline CliqueEntry * fixEntries()
  { convert(); return fixEntry_;}
  /// Starts of integer variable going to zero
  inline int * toZero()
  { convert(); return toZero_;}
  /// Starts of integer variable going to one
  inline int * toOne()
  { convert(); return toOne_;}
  /// List of 0-1 integer variables
  inline int * integerVariable() const
  { return integerVariable_;}
  /// Backward look up
  inline int * backward() const
  { return backward_;}
  /// Number of variables
  inline int numberVariables() const
  { return numberVariables_;}
  /// Number of 0-1 variables
  inline int numberIntegers() const
  { return numberIntegers_;}
private:
  /// Converts to ordered
  void convert();
protected:
  /// Entries for fixing variables
  CliqueEntry * fixEntry_;
  /// Starts of integer variable going to zero
  int * toZero_;
  /// Starts of integer variable going to one
  int * toOne_;
  /// List of 0-1 integer variables
  int * integerVariable_;
  /// Backward look up
  int * backward_;
  /// Entries for fixing variable when collecting
  int * fixingEntry_;
  /// Number of variables
  int numberVariables_;
  /// Number of 0-1 variables
  int numberIntegers_;
  /// Maximum number in fixEntry_
  int maximumEntries_;
  /// Number entries in fixingEntry_ (and fixEntry_) or -2 if correct style
  int numberEntries_;
};
inline int sequenceInCliqueEntry(const CliqueEntry & cEntry)
{ return cEntry.fixes&0x7fffffff;}
inline void setSequenceInCliqueEntry(CliqueEntry & cEntry,int sequence)
{ cEntry.fixes = sequence|(cEntry.fixes&0x80000000);}
inline bool oneFixesInCliqueEntry(const CliqueEntry & cEntry)
{ return (cEntry.fixes&0x80000000)!=0;}
inline void setOneFixesInCliqueEntry(CliqueEntry & cEntry,bool oneFixes)
{ cEntry.fixes = (oneFixes ? 0x80000000 : 0)|(cEntry.fixes&0x7fffffff);}

#endif
