/* $Id$ */
// Copyright (C) 2003, International Business Machines
// Corporation and others.  All Rights Reserved.
// This code is licensed under the terms of the Eclipse Public License (EPL).
/*
   Authors

   John Forrest

 */
#ifndef ClpSolve_H
#define ClpSolve_H

/**
    This is a very simple class to guide algorithms.  It is used to tidy up
    passing parameters to initialSolve and maybe for output from that

*/

class CLPLIB_EXPORT ClpSolve {

public:
  /** enums for solve function */
  enum SolveType {
    useDual = 0,
    usePrimal,
    usePrimalorSprint,
    useBarrier,
    useBarrierNoCross,
    automatic,
    tryDantzigWolfe,
    tryBenders,
    notImplemented
  };
  enum PresolveType {
    presolveOn = 0,
    presolveOff,
    presolveNumber,
    presolveNumberCost
  };

  /**@name Constructors and destructor and copy */
  //@{
  /// Default constructor
  ClpSolve();
  /// Constructor when you really know what you are doing
  ClpSolve(SolveType method, PresolveType presolveType,
    int numberPasses, int options[6],
    int extraInfo[6], int independentOptions[3]);
  /// Generates code for above constructor
  void generateCpp(FILE *fp);
  /// Copy constructor.
  ClpSolve(const ClpSolve &);
  /// Assignment operator. This copies the data
  ClpSolve &operator=(const ClpSolve &rhs);
  /// Destructor
  ~ClpSolve();
  //@}

  /**@name Functions most useful to user */
  //@{
  /** Special options - bits
     0      4 - use crash (default allslack in dual, idiot in primal)
         8 - all slack basis in primal
     2      16 - switch off interrupt handling
     3      32 - do not try and make plus minus one matrix
         64 - do not use sprint even if problem looks good
      */
  /** which translation is:
         which:
         0 - startup in Dual  (nothing if basis exists).:
                      0 - no basis
       	   1 - crash
       	   2 - use initiative about idiot! but no crash
         1 - startup in Primal (nothing if basis exists):
                      0 - use initiative
       	   1 - use crash
       	   2 - use idiot and look at further info
       	   3 - use sprint and look at further info
       	   4 - use all slack
       	   5 - use initiative but no idiot
       	   6 - use initiative but no sprint
       	   7 - use initiative but no crash
                      8 - do allslack or idiot
                      9 - do allslack or sprint
       	   10 - slp before
       	   11 - no nothing and primal(0)
         2 - interrupt handling - 0 yes, 1 no (for threadsafe)
         3 - whether to make +- 1matrix - 0 yes, 1 no
         4 - for barrier
                      0 - dense cholesky
       	   1 - Wssmp allowing some long columns
       	   2 - Wssmp not allowing long columns
       	   3 - Wssmp using KKT
                      4 - Using Florida ordering
       	   8 - bit set to do scaling
       	   16 - set to be aggressive with gamma/delta?
                      32 - Use KKT
         5 - for presolve
                      1 - switch off dual stuff
         6 - extra switches
                      
     */
  void setSpecialOption(int which, int value, int extraInfo = -1);
  int getSpecialOption(int which) const;

  /// Solve types
  void setSolveType(SolveType method, int extraInfo = -1);
  SolveType getSolveType();

  // Presolve types
  void setPresolveType(PresolveType amount, int extraInfo = -1);
  PresolveType getPresolveType();
  int getPresolvePasses() const;
  /// Extra info for idiot (or sprint)
  int getExtraInfo(int which) const;
  /** Say to return at once if infeasible,
         default is to solve */
  void setInfeasibleReturn(bool trueFalse);
  inline bool infeasibleReturn() const
  {
    return independentOptions_[0] != 0;
  }
  /// Whether we want to do dual part of presolve
  inline bool doDual() const
  {
    return (independentOptions_[1] & 1) == 0;
  }
  inline void setDoDual(bool doDual_)
  {
    if (doDual_)
      independentOptions_[1] &= ~1;
    else
      independentOptions_[1] |= 1;
  }
  /// Whether we want to do singleton part of presolve
  inline bool doSingleton() const
  {
    return (independentOptions_[1] & 2) == 0;
  }
  inline void setDoSingleton(bool doSingleton_)
  {
    if (doSingleton_)
      independentOptions_[1] &= ~2;
    else
      independentOptions_[1] |= 2;
  }
  /// Whether we want to do doubleton part of presolve
  inline bool doDoubleton() const
  {
    return (independentOptions_[1] & 4) == 0;
  }
  inline void setDoDoubleton(bool doDoubleton_)
  {
    if (doDoubleton_)
      independentOptions_[1] &= ~4;
    else
      independentOptions_[1] |= 4;
  }
  /// Whether we want to do tripleton part of presolve
  inline bool doTripleton() const
  {
    return (independentOptions_[1] & 8) == 0;
  }
  inline void setDoTripleton(bool doTripleton_)
  {
    if (doTripleton_)
      independentOptions_[1] &= ~8;
    else
      independentOptions_[1] |= 8;
  }
  /// Whether we want to do tighten part of presolve
  inline bool doTighten() const
  {
    return (independentOptions_[1] & 16) == 0;
  }
  inline void setDoTighten(bool doTighten_)
  {
    if (doTighten_)
      independentOptions_[1] &= ~16;
    else
      independentOptions_[1] |= 16;
  }
  /// Whether we want to do forcing part of presolve
  inline bool doForcing() const
  {
    return (independentOptions_[1] & 32) == 0;
  }
  inline void setDoForcing(bool doForcing_)
  {
    if (doForcing_)
      independentOptions_[1] &= ~32;
    else
      independentOptions_[1] |= 32;
  }
  /// Whether we want to do impliedfree part of presolve
  inline bool doImpliedFree() const
  {
    return (independentOptions_[1] & 64) == 0;
  }
  inline void setDoImpliedFree(bool doImpliedfree)
  {
    if (doImpliedfree)
      independentOptions_[1] &= ~64;
    else
      independentOptions_[1] |= 64;
  }
  /// Whether we want to do dupcol part of presolve
  inline bool doDupcol() const
  {
    return (independentOptions_[1] & 128) == 0;
  }
  inline void setDoDupcol(bool doDupcol_)
  {
    if (doDupcol_)
      independentOptions_[1] &= ~128;
    else
      independentOptions_[1] |= 128;
  }
  /// Whether we want to do duprow part of presolve
  inline bool doDuprow() const
  {
    return (independentOptions_[1] & 256) == 0;
  }
  inline void setDoDuprow(bool doDuprow_)
  {
    if (doDuprow_)
      independentOptions_[1] &= ~256;
    else
      independentOptions_[1] |= 256;
  }
  /// Whether we want to do singleton column part of presolve
  inline bool doSingletonColumn() const
  {
    return (independentOptions_[1] & 512) == 0;
  }
  inline void setDoSingletonColumn(bool doSingleton_)
  {
    if (doSingleton_)
      independentOptions_[1] &= ~512;
    else
      independentOptions_[1] |= 512;
  }
  /// Whether we want to kill small substitutions
  inline bool doKillSmall() const
  {
    return (independentOptions_[1] & 8192) == 0;
  }
  inline void setDoKillSmall(bool doKill)
  {
    if (doKill)
      independentOptions_[1] &= ~8192;
    else
      independentOptions_[1] |= 8192;
  }
  /// Set whole group
  inline int presolveActions() const
  {
    return independentOptions_[1] & 0xffffff;
  }
  inline void setPresolveActions(int action)
  {
    independentOptions_[1] = (independentOptions_[1] & 0xff000000) | (action & 0xffffff);
  }
  /// Largest column for substitution (normally 3)
  inline int substitution() const
  {
    return independentOptions_[2];
  }
  inline void setSubstitution(int value)
  {
    independentOptions_[2] = value;
  }
  inline void setIndependentOption(int type, int value)
  {
    independentOptions_[type] = value;
  }
  inline int independentOption(int type) const
  {
    return independentOptions_[type];
  }
  //@}

  ////////////////// data //////////////////
private:
  /**@name data.
     */
  //@{
  /// Solve type
  SolveType method_;
  /// Presolve type
  PresolveType presolveType_;
  /// Amount of presolve
  int numberPasses_;
  /// Options - last is switch for OsiClp
  int options_[7];
  /// Extra information
  int extraInfo_[7];
  /** Extra algorithm dependent options
         0 - if set return from clpsolve if infeasible
         1 - To be copied over to presolve options
         2 - max substitution level
	 If Dantzig Wolfe/benders 0 is number blocks, 2 is #passes (notional)
     */
  int independentOptions_[3];
  //@}
};

/// For saving extra information to see if looping.
class CLPLIB_EXPORT ClpSimplexProgress {

public:
  /**@name Constructors and destructor and copy */
  //@{
  /// Default constructor
  ClpSimplexProgress();

  /// Constructor from model
  ClpSimplexProgress(ClpSimplex *model);

  /// Copy constructor.
  ClpSimplexProgress(const ClpSimplexProgress &);

  /// Assignment operator. This copies the data
  ClpSimplexProgress &operator=(const ClpSimplexProgress &rhs);
  /// Destructor
  ~ClpSimplexProgress();
  /// Resets as much as possible
  void reset();
  /// Fill from model
  void fillFromModel(ClpSimplex *model);

  //@}

  /**@name Check progress */
  //@{
  /** Returns -1 if okay, -n+1 (n number of times bad) if bad but action taken,
         >=0 if give up and use as problem status
     */
  int looping();
  /// Start check at beginning of whileIterating
  void startCheck();
  /// Returns cycle length in whileIterating
  int cycle(int in, int out, int wayIn, int wayOut);

  /// Returns previous objective (if -1) - current if (0)
  double lastObjective(int back = 1) const;
  /// Set real primal infeasibility and move back
  void setInfeasibility(double value);
  /// Returns real primal infeasibility (if -1) - current if (0)
  double lastInfeasibility(int back = 1) const;
  /// Returns number of primal infeasibilities (if -1) - current if (0)
  int numberInfeasibilities(int back = 1) const;
  /// Modify objective e.g. if dual infeasible in dual
  void modifyObjective(double value);
  /// Returns previous iteration number (if -1) - current if (0)
  int lastIterationNumber(int back = 1) const;
  /// clears all iteration numbers (to switch off panic)
  void clearIterationNumbers();
  /// Odd state
  inline void newOddState()
  {
    oddState_ = -oddState_ - 1;
  }
  inline void endOddState()
  {
    oddState_ = abs(oddState_);
  }
  inline void clearOddState()
  {
    oddState_ = 0;
  }
  inline int oddState() const
  {
    return oddState_;
  }
  /// number of bad times
  inline int badTimes() const
  {
    return numberBadTimes_;
  }
  inline void clearBadTimes()
  {
    numberBadTimes_ = 0;
  }
  /// number of really bad times
  inline int reallyBadTimes() const
  {
    return numberReallyBadTimes_;
  }
  inline void incrementReallyBadTimes()
  {
    numberReallyBadTimes_++;
  }
  /// number of times flagged
  inline int timesFlagged() const
  {
    return numberTimesFlagged_;
  }
  inline void clearTimesFlagged()
  {
    numberTimesFlagged_ = 0;
  }
  inline void incrementTimesFlagged()
  {
    numberTimesFlagged_++;
  }

  //@}
  /**@name Data  */
#define CLP_PROGRESS 5
  //#define CLP_PROGRESS_WEIGHT 10
  //@{
  /// Objective values
  double objective_[CLP_PROGRESS];
  /// Sum of infeasibilities for algorithm
  double infeasibility_[CLP_PROGRESS];
  /// Sum of real primal infeasibilities for primal
  double realInfeasibility_[CLP_PROGRESS];
#ifdef CLP_PROGRESS_WEIGHT
  /// Objective values for weights
  double objectiveWeight_[CLP_PROGRESS_WEIGHT];
  /// Sum of infeasibilities for algorithm for weights
  double infeasibilityWeight_[CLP_PROGRESS_WEIGHT];
  /// Sum of real primal infeasibilities for primal for weights
  double realInfeasibilityWeight_[CLP_PROGRESS_WEIGHT];
  /// Drop  for weights
  double drop_;
  /// Best? for weights
  double best_;
#endif
  /// Initial weight for weights
  double initialWeight_;
#define CLP_CYCLE 12
  /// For cycle checking
  //double obj_[CLP_CYCLE];
  int in_[CLP_CYCLE];
  int out_[CLP_CYCLE];
  char way_[CLP_CYCLE];
  /// Pointer back to model so we can get information
  ClpSimplex *model_;
  /// Number of infeasibilities
  int numberInfeasibilities_[CLP_PROGRESS];
  /// Iteration number at which occurred
  int iterationNumber_[CLP_PROGRESS];
#ifdef CLP_PROGRESS_WEIGHT
  /// Number of infeasibilities for weights
  int numberInfeasibilitiesWeight_[CLP_PROGRESS_WEIGHT];
  /// Iteration number at which occurred for weights
  int iterationNumberWeight_[CLP_PROGRESS_WEIGHT];
#endif
  /// Number of times checked (so won't stop too early)
  int numberTimes_;
  /// Number of times it looked like loop
  int numberBadTimes_;
  /// Number really bad times
  int numberReallyBadTimes_;
  /// Number of times no iterations as flagged
  int numberTimesFlagged_;
  /// If things are in an odd state
  int oddState_;
  //@}
};

#include "ClpConfig.h"
#if CLP_HAS_ABC
#include "AbcCommon.hpp"
/// For saving extra information to see if looping.
class CLPLIB_EXPORT AbcSimplexProgress : public ClpSimplexProgress {

public:
  /**@name Constructors and destructor and copy */
  //@{
  /// Default constructor
  AbcSimplexProgress();

  /// Constructor from model
  AbcSimplexProgress(ClpSimplex *model);

  /// Copy constructor.
  AbcSimplexProgress(const AbcSimplexProgress &);

  /// Assignment operator. This copies the data
  AbcSimplexProgress &operator=(const AbcSimplexProgress &rhs);
  /// Destructor
  ~AbcSimplexProgress();

  //@}

  /**@name Check progress */
  //@{
  /** Returns -1 if okay, -n+1 (n number of times bad) if bad but action taken,
         >=0 if give up and use as problem status
     */
  int looping();

  //@}
  /**@name Data  */
  //@}
};
#endif
#endif

/* vi: softtabstop=2 shiftwidth=2 expandtab tabstop=2
*/
