#!/bin/csh
## 
## gen_milp_app [-help] [-stage1] [-stage2] [-no-main] [-protected-vars] 
##	[-no-app-template] ##	[-no-presolve] [-labels <r-file> <c-file>] 
##	[-name <app-name>] {<lp>.mps | <lp>.lp}
##
## gen_milp_app [-help] [-stage1] [-stage2] [-no-main] [-protected-vars] 
##	[-no-app-template] [-no-presolve] [-labels <r-file> <c-file>] 
##	[-name <app-name>] <lp>.mod <lp>.dat
##

if ($#argv == 0) then
   echo "gen_milp_app [-help] [-stage1] [-stage2] [-no-main] [-protected-vars] [-no-app-template] [-no-presolve] [-labels <r-file> <c-file>] [-name <app-name>] {<lp>.mps | <lp>.lp}"
   echo "gen_milp_app [-help] [-stage1] [-stage2] [-no-main] [-protected-vars] [-no-app-template] [-no-presolve] [-labels <r-file> <c-file>] [-name <app-name>] <lp>.mod <lp>.dat"
   exit
endif

set cmd = $0
set cmd = ${cmd:t}

#
# Default values
#
@   protected_appinfo = 0
@   app_template      = 1
@   mainflag          = 1
@   presolve          = 1
@   stage1	      = 1
@   stage2	      = 1
@   newofilecpp       = 0
set elsestr           = "else"
set r_file = ""
set c_file = ""
set rc_labels = ""
set lp_file = ""
set app_label = ""
set varmap_file = ""


#
# Read in optional flags
#
@ flag = 1
while ($flag == 1)
  @ flag = 0

  if (("$1" == "-help") || ("$1" == "--help") || ("$1" == "-h")) then
  cat << HELP_END | more

  gen_milp_app


  gen_milp_app [-help] [-no-main] [-protected-vars] [-no-app-template] [-no-presolve] [-labels <r-file> <c-file>] [-name <app-name>] {<lp>.mps | <lp>.lp}

  gen_milp_app [-help] [-no-main] [-protected-vars] [-no-app-template] [-no-presolve] [-labels <r-file> <c-file>] [-name <app-name>] <lp>.mod <lp>.dat

  DESCRIPTION 
  A utility for automatically processing a ILP input file to generate an
  MILP subclass that can be used within PICO, including an Info class that
  provides a symbolic mapping of the constraint/variable names into the
  actual data used by the application.

  OPTIONS

    -help             Generates this help information

    -stage1	      Only execute the first stage of gen_milp_app, which
                      calls AMPL.

    -stage2           Only execute the second stage of gen_milp_app, which
                      calls setupMappedMILP.

    -no-main          By default, gen_milp_app includes a main() function in 
		      the <app>MILP.cpp file that automatically loads the input
		      files and runs a serial branch-and-bound algorithm. This
		      option excludes the create of main().

    -no-app-template  By default, gen_milp_app creates an application-specific 
		      instances of the MILPProblem, MILP and MILPNode classes.
		      These classes include a pointer to an appInfo object, 
		      which contains contraint/variable mappings.  This flag
		      turns off the creation of these application objects.

    -protected-vars   Specifies the value of the C/C++ macro PROTECTED_APPINFO
		      If this flag is not specified, then this macro is 0, 
		      and the symbols for the variables and arguements are
		      included in the application classes.  Otherwise, these
		      symbols need to be accessed via the info() method.
		      For example, without protection, you can access the
		      variable x's index as

			x(i)

		      and with protection you can access x's index as

			info()->x(i).

    -labels           Specifies two files that contain row labels and column
                      labels for the ILP.
    
    -no-presolve      Option used to turn of presolving in ampl

    -name 	      Names the application and files generated by 
		      gen_milp_app.  By default, if lp file is <lp>.SUFFIX,
		      then gen_milp_app creates files of the form
		      <lp>.*

  REQUIRED ARGUMENTS

    <lp>.mps	      An MPS formated file
    <lp>.lp	      An LP formated file
    <lp>.mod	      An AMPL model file
    <lp>.dat	      An AMPL data file (required if the <lp>.mod file is
		      used)

  ADDITIONAL DETAILS

  When using AMPL *.mod files, this utility extracts lines that contain
  "PICO SYMBOL" and prints out the values of these symbols for the 
  problem instance defined by the *.dat file.  For example, a *.mod file
  might contain the line:

  	# PICO SYMBOL: a b c

  to specify that the symbols 'a', 'b', and 'c' are exported for use
  by the PICO application.  In particular, these symbols will be 
  defined for the PICO application in the <lp>.map file, and the data for
  these symbols is defined in a <lp>.val file.

  FURTHER NOTES

  The makefile generated by gen_milp_app is setup to automatically include
  the main PICO makefile.  However, this only works properly if gen_milp_app
  is called from the PICO bin directory.  If a symbolic link is created to 
  gen_milp_app, then this include will not be setup properly.


HELP_END
  exit
  endif

  if ("$1" == "-stage1") then
     shift
     @ stage2 = 0
  endif

  if ("$1" == "-stage2") then
     shift
     @ stage1 = 0
  endif

  if ("$1" == "-name") then
     shift
     set app_label = $1
     shift
     @ flag = 1
  endif

  if ("$1" == "-no-presolve") then
     shift
     @ presolve = 0
     @ flag = 1
  endif

  if ("$1" == "-no-main") then
     shift
     @ mainflag = 0
     @ flag = 1
  endif

  if ("$1" == "-protected-vars") then
     shift
     @ protected_appinfo = 1
     @ flag = 1
  endif

  if ("$1" == "-no-app-template") then
     shift
     @ app_template = 0
     @ flag = 1
  endif

  if ("$1" == "-labels") then
     shift
     set r_file = $1
     shift
     set c_file = $1
     shift
     set rc_labels = "-labels $r_file $c_file"
     @ flag = 1
  endif

end

#
# Read in required arguments
#
set lp_file = $1
shift
set app_suffix = "${lp_file:e}"
if ($app_suffix == "mod") then
   set data_file = $1
   shift
endif

if ("$app_label" == "") then
   set app_label = `echo "${lp_file:r}" | sed 's/-/_/g'`
endif

set ofileh_label = "$app_label"_milp
set ofileh = "$app_label"_milp.h
set ofilecpp = "$app_label"_milp.cpp

if ($stage1 == 1) then
  if ($app_suffix == "mod") then
     cat << AMPL_END >! tmp.$cmd.$$
##
## AMPL script that creates ${app_label}.mps, ${app_label}.col,
## ${app_label}.row and ${app_label}.var
##
## The output of this script is used to create ${app_label}.val
##
#
# Read in the model and data files
#
model ${lp_file}
data  ${data_file}
#
# Tells ampl to create *.row and *.col files
#
option auxfiles rc;
#
# until the technician assignment code can handle gaps in technicians from the
# variable elimination.
#
option presolve ${presolve};
#
# Write out an *.mps file
#
write m${app_label};
#
# Print end-of-job tag
#
print "SUCCESSFUL_TERMINATION";

AMPL_END

     grep "PICO SYMBOL" $lp_file | awk '\
	BEGIN {printf "##\n## Automatically generated by gen_milp_app\n##\n";}{\
	for (i=4; i<=NF; i++) {\
	  if ($i != ":") {\
	     printf "print \"%s\";", $i;\
	     printf "csvdisplay %s;\n", $i;\
	     printf "print \";\";", $i;\
             }\
          }\
	}' >> tmp.$cmd.$$
     ampl tmp.$cmd.$$ |& grep -v AMPL >! ${app_label}.val
     #
     # Error checks
     #
     mv -f tmp.$cmd.$$ ampl_script.in
     if ( !( -e ${app_label}.mps) ) then
        echo "ERROR: gen_milp_ampl failed to generate ${app_label} using ampl\!"
        echo "ERROR: check out the ampl_script.in file for AMPL"
        exit
     endif
     set errval = `grep "SUCCESSFUL" ${app_label}.val`
     if ( "$errval" == "") then
        echo "ERROR: gen_milp_ampl called AMPL, which failed to terminate successfully\!"
        echo "ERROR: check out the ampl_script.in file for AMPL"
        exit
     else
        set errval = `grep "Error executing" ${app_label}.val`
	echo "$errval"
        if ( "$errval" != "") then
           echo "ERROR: gen_milp_ampl called AMPL, which had an error executing a command\!"
           echo "ERROR: check out the ampl_script.in file for AMPL"
           exit
        else
           grep -v SUCCESSFUL ${app_label}.val >! ${app_label}.tmp
	   mv -f ${app_label}.tmp ${app_label}.val
           echo "SUCCESSFUL TERMINATION OF AMPL"
        endif
     endif
  endif
endif

set test_file = ${app_label}.test
if ($app_suffix == "mod") then
   set varmap_file = ${app_label}.val
   set lp_file = ${app_label}.mps
   set rc_labels = "-labels ${app_label}.row ${app_label}.col"
   set r_file = ${app_label}.row
   set c_file = ${app_label}.col
endif

##
## Run setupMappedMILP to create the *.map file
##
if ($stage2 == 1) then
  \rm -f core core* >& /dev/null
  echo "running "'"'"setupMappedMILP $rc_labels $lp_file $app_label"'"'
  setupMappedMILP $rc_labels $lp_file $app_label
  echo "finished running "'"'"setupMappedMILP $rc_labels $lp_file $app_label"'"'
  if (-e core) then
     echo "ERROR: setupMappedMILP generated a core file"
     exit
  endif



if ($app_template == 1) then
   ##
   ## Generate a template application
   ##
   #
   # Generate the *.h file
   #
   if (! -e $ofileh ) then
   cat << TEMPLATE_H >! $ofileh
//
// $ofileh 
//
// A template for a user-defined MILP-based application that will be flushed 
// out using variables defined by the user.
//
// Note: this file is dynamically created by the gen_milp_app tool, but
// once it exists gen_milp_app will not over-write it.
//
#ifndef ${ofileh_label}
#define ${ofileh_label}

#define PROTECTED_APPINFO ${protected_appinfo}

#include <pico/milpNode.h>
#include <pico/lpSetupObj.h>
#include <pico/BasisArray.h>
#include <pico/BCMip.h>
#include <pico/parBCMip.h>
#include "${app_label}_info.h"
#include "${app_label}_extras.h"

using namespace std;

namespace ${app_label} {

//GLOBAL_PARAMETER(debug);

using utilib::IntVector;
using utilib::DoubleVector;
using pebbl::branchSub;
using pebbl::branching;
using pico::PicoLPSolver;
using pico::PicoLPInterface;
using pico::lpSetupObj;
using pico::BasisArray;
using pico::BCMipProblem;

//
// Problem defines an extended MILPProblem, which can incorporate 
// application-specific information (e.g. the variable-mapping information)
//
class Problem: virtual public pico::BCMipProblem
#if PROTECTED_APPINFO 
				, public MILPSymbInfo
#else
				, public MILPSymbFunctions
#endif
{
public:

  /// An empty MILP, for parallel instantiation
  Problem() 
#if !PROTECTED_APPINFO 
		: MILPSymbFunctions(&app_info)
#endif
  {
  }


  MILPProblem* newMILPProblem()
  {
	return (MILPProblem *) new Problem();
  }

  ///
  virtual ~Problem() {}

  ///
  void init_varmap(const char* varmap_values_file = NULL);

  ///
  void print_summary(ostream& os);

  ///
  Info app_info;
};


//
// MILP defines a serial branch-and-bound algorithm that is derived
// from the MILP branch-and-bound code for mixed-integer linear programming.
//
class MILP: virtual public pico::BCMip
#if PROTECTED_APPINFO 
				, public MILPSymbInfo
#else
				, public MILPSymbFunctions
#endif
{
protected:

  ///
  friend class MILPNode;

public:

  ///
  MILP() {};

  ///
  virtual ~MILP() {};

  ///
  bool setup(int& argc, char**& argv, Problem& problem_)
	{
	AppMIP = &problem_;
	infoptr = &(problem_.app_info);
	//pico::BCMip::MIP = &problem_;
	bool result =  pico::BCMip::setup(argc,argv, (BCMipProblem&)problem_);
        if (strcmp("${r_file}","") != 0)
           problem_.set_labels("${r_file}","${c_file}");
        if (strcmp("${varmap_file}","") != 0)
           problem_.init_varmap("${varmap_file}");
        ${elsestr}
           problem_.init_varmap();
	if (debug > 10) 
           problem_.test_varmap();
	return result;
	}

  ///
  //void setProblemInfo(Info* app_info = NULL)
	//{infoptr = app_info;}

  /// The application problem.
  Problem *AppMIP;

  /// 
  pico::PicoLPInterface* LP()
		{return AppMIP->lp();};

  ///
  branchSub* blankSub();

  ///
  bool haveIncumbentHeuristic() {return false;};

  ///
  //void serialPrintSolution(const char* header = "",
			     //const char* footer = "",
			     //ostream& outStream = cout);

  /// Update the incumbent from a search leaf
  //void updateIncumbent(DoubleVector& newSolution, double solutionValue);

/// Designate some variables as more important for branching than others.
/// For example, it's best to decide if you'll build a facility at all before
/// you decide its color.

//  void initializeBranchingPriorities();

};


#if defined(USING_MPI)

///
/// parMILP
///
class parMILP : virtual public pico::parBCMip, virtual public MILP
{
public:

  /// An empty constructor for a branching object
  parMILP()
	{}

  /// A destructor
  virtual ~parMILP()
	{}

  ///
  void reset(bool VBflag=true)
	{
	MILP::reset(VBflag);
	pebbl::parallelBranching::reset(false);
	}

  /// Hook to read in user-defined parameters
  //void readIn(int argc, char** argv)
	//{}

  ///
  pebbl::parallelBranchSub* blankParallelSub();

  /// Pack the branching information into a buffer
  void pack(utilib::PackBuffer& outBuffer)
	{
#if PROTECTED_APPINFO
	MILPSymbInfo::write(outBuffer);
#else
	infoptr->write(outBuffer);
#endif
	pico::parMILP::pack(outBuffer);
	}

  /// Unpack the branching information from a buffer
  void unpack(utilib::UnPackBuffer& inBuffer)
	{
#if PROTECTED_APPINFO
	MILPSymbInfo::read(inBuffer);
#else
	infoptr->read(inBuffer);
#endif
	pico::parMILP::unpack(inBuffer);
	}

  /// Compute the size of the buffer needed for a subproblem
  int spPackSize()
	{
	utilib::PackBuffer pack;
#if PROTECTED_APPINFO
	MILPSymbInfo::write(pack);
#else
	infoptr->write(pack);
#endif
	return pack.size();
	}

  void 		preprocess()
		{ pico::parBCMip::preprocess();			}
  branchSub*	blankSub()
		{ return pico::parBCMip::blankSub(); 		}
  void		MILPInit(bool initVB=true)
		{ pico::parBCMip::MILPInit(initVB);		}
  void 		printAllStatistics(ostream& os = cost)
		{ pico::parBCMip::printAllStatistics(os);	}
  void 		setup(int& argc, char**& argv, Problem& p);
 
};
#endif

//
// MILPNode
//
class MILPNode: virtual public pico::BCMipNode
#if PROTECTED_APPINFO 
				, public MILPSymbInfo
#else
				, public MILPSymbFunctions
#endif
{
public:

  ///
  MILPNode() {}

  /// Make a root node
  void MILPNodeFromMILP(MILP* master, bool initVB = true);

  /// Make a child node
  void MILPNodeAsChildOf(MILPNode* parent, bool initVB = true);

  /// Dummy destructor
  virtual ~MILPNode() {}

  /// Pointer to the global branching object
  MILP *globalPtr;

  ///
  branching* bGlobal() const
		{return globalPtr;};

  ///
  MILP *global()
		{return globalPtr;};

  /// This functionality is handy at the derived MILPNode level,
  /// but isn't used in the regular MILPNode (yet). 
  /// Sets the node (local) bounds on integer variables from
  /// an LP variable number rather than an integer variable number
  void setIntLowerBound(int lpVarNum, int newVal)
	{intLowerBounds[mip()->LPtoIntegerVar[lpVarNum]] = newVal;}

  void setIntUpperBound(int lpVarNum, int newVal)
	{intUpperBounds[mip()->LPtoIntegerVar[lpVarNum]] = newVal;}

  /// void incumbentHeuristic();       // your incumbent (quick.. calls this)

};

#if defined(USING_MPI)
/// 
/// parMILPNode
///
class parMILPNode : virtual public pico::parBCMipNode, virtual public MILPNode
{
public:

  ///
  pico::branching* bGlobal() const
	{return globalPtr;}

  /// Return a pointer to the global branching object
  parMILP* global() const
        { return globalPtr; }

  /// Return a pointer to the base class of the global branching object
  pebbl::parallelBranching* pGlobal() const
        { return globalPtr; }

  /// An empty constructor for a subproblem
  parMILPNode()
        { }

  /// A virtual destructor for a subproblem
  virtual ~parMILPNode()
        { }

  /**
   * Initialize a subproblem using a branching object
   * This method is not strictly necessary, but its use here illustrates
   * a flexible mechanism for managing the initialization of subproblems.
   * The following crude fragment illustrates some common steps needed in
   * this method.
   */
  void initialize(parMILP* master)
        {
        globalPtr = master;
        MILPNodeFromMILP( (MILP*)master );
	pico::parMILPNode::parMILPNodeFromParMILP(master,false);
        infoptr = globalPtr->infoptr;
        }

 /**
   * Initialize a subproblem as a child of a parent subproblem.
   * This method is not strictly necessary, but its use here illustrates
   * a flexible mechanism for managing the initialization of subproblems.
   * The following crude fragment illustrates some common steps needed in
   * this method.
   */
  void initialize(parMILPNode* parent)
        {
        globalPtr = parent->globalPtr;
        pico::parMILPNode::parMILPNodeAsChildOf(parent);
	infoptr = globalPtr->infoptr;
        }


  /// Pack the information in this subproblem into a buffer
  void pack(utilib::PackBuffer& outBuffer)
	{pico::parMILPNode::pack(outBuffer);}

  /// Unpack the information for this subproblem from a buffer
  void unpack(utilib::UnPackBuffer& inBuffer)
	{pico::parMILPNode::unpack(inBuffer);}

  /// Create a child subproblem of the current subproblem
  virtual parallelBranchSub* makeParallelChild(int whichChild)
        {
        parMILPNode *temp = new parMILPNode;
        temp->initialize(this);
	pico::MILPNode::childInit(temp, whichChild);
        return temp;
        }

  /// void rampUpIncumbentHeuristic(); // called during ramp-up
  /// void quickIncumbentHeuristic();  // called during parallel phase
  branchSub* makeChild(int whichChild = anyChild);

  PicoLPInterface::problemState boundComputationGuts()
                      { return pico::parBCMipNode::boundComputationGuts();}
  lpSetupObj*  makeLPSetupObj()
                      { return pico::parBCMipNode::makeLPSetupObj();  }
  bool         isWarmStart()
                      { return pico::parBCMipNode::isWarmStart();     }
  void         getBasis(BasisArray& basisBuffer) const
                      { pico::parBCMipNode::getBasis(basisBuffer); }
  bool               candidateSolution()
                      { return pico::parBCMipNode::candidateSolution();}
  void         getSolution()
                      { pico::parBCMipNode::getSolution();      }
  void         makeActiveLP()
                      { pico::parBCMipNode::makeActiveLP();     }
  int          initialBasisSize()
                      { return pico::parBCMipNode::initialBasisSize(); }
  PicoLPInterface::problemState boundingSolve()
                      { return pico::parBCMipNode::boundingSolve();}
  void         postPseudoCostInit(IntVector&initVars,
                                bool dontRemoveAllBranchChoices,
                                int& numBranches)
                      { pico::parBCMipNode::postPseudoCostInit(
                                              initVars,
                                              dontRemoveAllBranchChoices,
                                              numBranches);
                      }
  void         printMILPNode()
                      { pico::parBCMipNode::printMILPNode();}
  PicoLPInterface::problemState PCInitSolve()
                      { return pico::parBCMipNode::PCInitSolve();}
  void                noLongerActiveLP()
                      { pico::parBCMipNode::noLongerActiveLP();}
  bool                useSavedSolutionNow()
                      { return pico::parBCMipNode::useSavedSolutionNow();}
  void                setBasis()
                      { pico::parBCMipNode::setBasis();}
  void                setBounds()
                      { pico::parBCMipNode::setBounds();}
  void                setupLP(OsiSolverInterface *lp)
                      { pico::parBCMipNode::setupLP(lp);}
  bool                updatePCFromBoundingSolve()
                      { return
                        pico::parBCMipNode::updatePCFromBoundingSolve();}
  void                enumeration_effect(DoubleVector& point)
                      { pico::parBCMipNode::enumeration_effect(point);}



protected:

  /// A pointer to the global branching object
  parMILP* globalPtr;

};
#endif


#if defined(USING_MPI)
inline pebbl::parallelBranchSub* parMILP::blankParallelSub()
{
  parMILPNode* tmp = new parMILPNode();
  tmp->initialize(this);
  return (pebbl::parallelBranchSub *)tmp;
}
#endif

} // namespace ${app_label}

#endif // ifndef ${ofileh_label}

TEMPLATE_H
      endif
      #
      # Generate the *.cpp file
      #
      if (! -e $ofilecpp ) then
      @ newofilecpp = 1
      cat << TEMPLATE_CPP >! $ofilecpp
//
// $ofilecpp
//
// Customized branching class for extensions of MILP's
//
// Note: this file is dynamically created by the gen_milp_app tool, but
// once it exists gen_milp_app will not over-write it.
//

#include <strings.h>
#include "$ofileh"

using namespace utilib;

namespace ${app_label} {


branchSub *MILP::blankSub()
{
MILPNode *tmp = new MILPNode;
tmp->MILPNodeFromMILP((MILP *)this);
return (branchSub *) tmp;
}


void MILPNode::MILPNodeFromMILP(MILP *master, bool initVB)
{
globalPtr = master;
infoptr = master->infoptr;
if (initVB)
  pico::BCMipNode::BCMipNodeFromBCMip(master);
}



void MILPNode::MILPNodeAsChildOf(MILPNode* parent, bool initVB)
{
globalPtr = parent->MILPNode::globalPtr;
infoptr = parent->infoptr;
if (initVB)
  pico::BCMipNode::BCMipNodeAsChildOf(parent);
}

void Problem::init_varmap(const char* varmap_values_file)
{
if (!lp)
   EXCEPTION_MNGR(std::runtime_error, "Problem::init_varmap -- no LP is currently defined!");
BasicArray<CharString> vnames, cnames;
lp()->getVariableNames(vnames);
lp()->getRowNames(cnames);

//
// Assume that the LP name is *.<suffix>, which refers to the filename that it
// was read in from.
//
//CharString name = lp()->name();
CharString name = varmap_values_file;
char* str = (name.data() ? rindex(name.data(), '.') : 0);
if (str != NULL)
   name.resize(str - name.data());
CharString fname="";
CharString mapfile="";

info()->preprocess_ILP(name, cnames, vnames, mapfile, fname, FALSE);
if (varmap_values_file) {
   CharString tmp = varmap_values_file;
   info()->read_valfile(tmp);
   }
}

/// void MILPNode::incumbentHeuristic() {}

#if defined(USING_MPI)

branchSub * parMILPNode::makeChild(int whichChild) 
{
	return(makeParallelChild(whichChild));
}

/// void parMILPNode::rampUpIncumbentHeuristic()
/// {
///     DEBUGPR(10, ucout << "parMILPNode::rampUpIncumbentHeuristic" <<endl);
///     incumbentHeuristic();
///     pmGlobal()->rampUpIncumbentSync();
/// }
#endif

/// void parMILPNode::rampUpIncumbentHeuristic()
/// {
///     incumbentHeuristic();
/// }


} // namespace ${app_label}

TEMPLATE_CPP
   endif
   endif

   set picopath = `which gen_milp_app | sed 's%acro/bin%acro/packages/pico%g'`
   set picopath = "${picopath:h}"
   if (! (-e Makefile || -e makefile) ) then
      ln -s Makefile-${app_label} Makefile
   endif
   cat >! Makefile-${app_label} << MAKE_END
##
## Makefile generated for the MILP application.
##
all: ${app_label}_milp

${app_label}_milp:        ${app_label}_milp.o ${app_label}_info.o ${app_label}_extras.o
	\$(CXXLINK) -o ${app_label}_milp ${app_label}_milp.o ${app_label}_info.o ${app_label}_extras.o \$(LDADD) \$(LIBS)


${app_label}_extras.o: ${app_label}_extras.cpp

${app_label}_extras.cpp:
	@if [ ! -r ${app_label}_extras.cpp ]; then \
	   echo "// Note: this file is automatically generated if the user does not create it." > ${app_label}_extras.cpp; \
	   echo "#include \"${app_label}_milp.h\"" > ${app_label}_extras.cpp; \
	   echo "" >> ${app_label}_extras.cpp;\
	   echo "namespace ${app_label} {" >> ${app_label}_extras.cpp;\
	   echo "" >> ${app_label}_extras.cpp;\
	   echo "void Problem::print_summary(ostream& ) {}" >> ${app_label}_extras.cpp; \
	   echo "" >> ${app_label}_extras.cpp;\
	   echo "} // namespace ${app_label}" >> ${app_label}_extras.cpp;\
        fi

delete:
	- \$(RM) -f ${app_label}.row ${app_label}.col ${app_label}.val ${app_label}_milp.cpp ${app_label}_milp.h ${app_label}_info.h ${app_label}_info.cpp ${app_label}.map ${app_label}_milp.o ${app_label}_info.o ${app_label}_milp SunWS* *.o ${app_label}.mps ampl_script.in

include ../dummy/Makefile

clean:
	\$(RM) *.o

MAKE_END

   if ( (${mainflag} == 1) && ( ${newofilecpp} == 1 ) ) then
      #
      # Generate the *.h file
      #
      cat >> $ofilecpp << MAIN_CPP
//
// Defines a serial MILP executable
//
#if 0
#ifndef ANSI_HDRS
#include <signal.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#else
#include <csignal>
#include <cmath>
#include <cstring>
#include <cstdlib>
#endif
#if !defined(CYGWIN) && !defined(DARWIN)
#include <values.h>
#endif

#ifdef NON_ANSI
#include <iostream.h>
#include <fstream.h>
#else
#include <iostream>
#include <fstream>
#endif

#include <unistd.h>
#include <utilib/_math.h>
#include <utilib/seconds.h>
#include <utilib/paramTable.h>
#include <utilib/memdebug.h>
#include <utilib/ParameterList.h>
#include <utilib/mpiUtil.h>
#include <pico/fundamentals.h>
#include <pico/milp.h>
#include <pico/gRandom.h>
#include <pico/parMilp.h>

#ifdef ANSI_NAMESPACES
using namespace std;
#endif
using namespace utilib;



extern "C" void abort_handler(int code)
{
#if defined(USING_MPI)
MPI_Abort(MPI_COMM_WORLD,-1);
abort();
exit(0);
#endif
}


int serial(int argc, char** argv)
{
try {

    int repeat=1;
    bool rootLP=false;
    bool preprocessOnly=false;
    bool preprocessIP=false;
    bool onlyRootLP=false;
    bool saveRootBoundingInfo=false;
    int  debug=0;
    bool debug_solver_params=false;

    utilib::ParameterSet params;
    params.create_parameter("repeat",repeat,"<int>","1",
          "TODO",utilib::ParameterLowerBound<int>(1));
    params.create_parameter("debug",debug,"<int>","0",
          "TODO",utilib::ParameterLowerBound<int>(0));
    params.create_parameter("debug-solver-params",debug_solver_params,
                "<bool>","false",
                "If true, print solver parameters");
    params.create_parameter("rootLP",rootLP, "<bool>","false","TODO");
    params.create_parameter("preprocessOnly",preprocessOnly,
          "<bool>","false","TODO");
    params.create_parameter("preprocessIP",preprocessIP,
          "<bool>","false","TODO");
    params.create_parameter("onlyRootLP",onlyRootLP, "<bool>","false","TODO");
    params.create_parameter("saveRootBoundingInfo",saveRootBoundingInfo,
        "<bool>","false",
        "Output root bounding information (e.g. values of integer\n\t"
        "variables) to the file root-bounding-info.bin.");

    ParameterList plist;
    plist.register_parameters(params);
    plist.register_parameters<pico::PicoLPSolver>();
    plist.register_parameters<${app_label}::Problem>();
    plist.register_parameters<${app_label}::MILP>();
    plist.process_parameters(argc,argv,1);
    params.set_parameters(plist,false);
    if (params.get_parameter<bool>("help")) {
       plist.write_registered_parameters(ucout);
       return -1;
       }
    if (saveRootBoundingInfo && !onlyRootLP)
      EXCEPTION_MNGR(runtime_error, "saveRootBoundingInfo option can "
                     "only be used in conjunction with onlyRootLP");

    InitializeTiming();

    ${app_label}::Info app_info;
    ${app_label}::Problem problem;
    problem.set_parameters(plist,false);
    problem.infoptr = &app_info;

    problem.lp.set_parameters(plist,false);
    if (debug_solver_params) {
       ucout << "---- PicoLPSolver Parameters ----" << endl;
       problem.lp.write_parameter_values(ucout);
       ucout << endl << Flush;
       }
    problem.lp.init();
    problem.lp()->set_parameters(plist,false);
    if (debug_solver_params) {
       ucout << "---- PicoLPInterface Parameters ----" << endl;
       problem.lp()->write_parameter_values(ucout);
       ucout << endl << Flush;
       }

    BasicArray<int> listOfInts;

    //
    // for debugging, to catch transient bugs
    //
    #ifdef DEBUGGING
    for (int i=0; i< repeat; i++) {
    #endif
        // Assuming that the first argument is an MPS filename
        if (argc == 1)
           EXCEPTION_MNGR(runtime_error, "***No MPS file given as input")
        /* Remove cplex_mps_format once WH's MPS reader is fixed. */
        problem.lp()->loadProblem(argv[1], listOfInts);
#ifdef DEBUGGING
        if (debug > 2) {
          problem.lp()->write(ucout,pico::verbose_format);
          ucout << Flush;
        }
#endif
        //
        // Initializing the varmap in the problem
        //
        if (strcmp("${r_file}","") != 0)
           problem.set_labels("${r_file}","${c_file}");
        if (strcmp("${varmap_file}","") != 0)
           problem.init_varmap("${varmap_file}");
        ${elsestr}
           problem.init_varmap();
        problem.test_varmap();

        if (preprocessOnly)
          {
            problem.initialize(listOfInts, debug);
            problem.set_parameters(plist,false);
            problem.preprocess();
          } ${elsestr}
          if ((listOfInts.size() == 0) || (onlyRootLP == 1)) {
            ucout << "No integer variables... solving the LP normally."
                  << endl;

            if (preprocessIP) {
              problem.initialize(listOfInts, debug);
              problem.set_parameters(plist,false);
              problem.preprocess();
            }
            problem.lp()->solve();
            pico::PicoLPInterface::problemState solvedState = problem.lp()->state();
            if (saveRootBoundingInfo)
              {
              ofstream savedSolution("root-bounding-info.bin");
              if (savedSolution.bad())
                EXCEPTION_MNGR(runtime_error,
                                "Can't open file to save root solution");
              // May want to adjust precision here!

              savedSolution << (int)solvedState;
              // Don't let numbers run together.  This isn't a packbuffer.
              savedSolution << " ";

              if (solvedState == pico::PicoLPInterface::solved)
                {
                savedSolution << problem.lp()->getObjValue() << " ";
                // Any changes to MILPNode::getSolution() should propagate her
                DoubleVector solution(listOfInts.size());
                problem.lp()->getColSolution(solution.data(),
                                (int)solution.size(), listOfInts.data());
                savedSolution << solution << " ";
                // Any changes to the way basis information is
                // stored/retrieved should propagate here.
                pico::BasisArray basis(problem.lp()->getNumCols() +
                                                problem.lp()->getNumRows());
                problem.lp()->getBasis(basis);
                savedSolution << basis;
                }

              }
            if (solvedState == pico::PicoLPInterface::unbounded)
              { ucout << endl << "Problem is unbounded\n"; 

            } ${elsestr} if (solvedState == pico::PicoLPInterface::infeasible)
              { ucout << endl << "Problem is infeasible\n";

            } ${elsestr} if (solvedState == pico::PicoLPInterface::solved)
              {

              ucout << "\tLP value= " << problem.lp()->getObjValue() << endl;
#ifdef DEBUGGING
              if (debug > 0)
                {
                DoubleVector fullSolution(problem.lp()->getNumCols());
                problem.lp()->getColSolution(fullSolution.data());
                for (int j = 0; j < problem.lp()->getNumCols(); j++)
                  {
                    if (fullSolution[j] != 0)
                      ucout << "variable " << j << "(= " <<
                                        problem.lp()->getVariableName(j) <<
                                        "): " << fullSolution[j] << "\n";
                  }
                }
#endif
              }
            problem.lp()->reset();

          } ${elsestr} {
            //
            // Setup the MILP
            //
            problem.initialize(listOfInts, debug);
            problem.set_parameters(plist,false);
            ${app_label}::MILP *instance = new ${app_label}::MILP();
            instance->setMILPProblem(problem);
            instance->setProblemInfo(&app_info);
            instance->set_parameters(plist,false);
            instance->heurCfg.set_parameters(plist,false);
            if (debug_solver_params) {
               ucout << "---- MILP Parameters ----" << endl;
               instance->write_parameter_values(ucout);
               ucout << endl << Flush;
               }
            instance->MILPInit();
            instance->setDebug(debug);

            // This seems like only a debugging feature.
            // Not very efficient either.
#ifdef DEBUGGING
            if (rootLP) {
              if (preprocessIP)
                problem.preprocess();
              problem.lp()->solve();
              ucout << "Root LP value= " << problem.lp()->getObjValue()
                    << endl;
              problem.lp()->reset();
            }
#endif

            instance->search();

            if (instance->problemIsFeasible()) {
              ucout << endl << "Final Solution:  Value = "
                   << instance->incumbentValue << endl << endl;
            } ${elsestr} ucout << "Integer Infeasible\n";
            instance->solutionToFile();
            instance->printAllStatistics();

            delete instance;

          }

#ifdef DEBUGGING
      }
#endif

    //CommonIO::end();

  //
  // Verify the all parameters have been processed
  //
  if (plist.unused() > 0) {
     ucout << "\nWARNING: unused parameters" << endl;
     plist.write_unused_parameters(ucout);
     ucout << Flush;
     return -1;
     }
  }


  catch (const char* str)
    {
      cerr << "ERROR! Caught serialMIP exception string: "
           << str << endl;
    }

  catch (std::exception& str)
    {
      cerr << "ERROR! Caught serialMIP exception object: "
           << str.what() << endl;
    }

return 0;
}


int parallel(int argc, char** argv) 
{
#if defined(USING_MPI)
  try {

    InitializeTiming();
    uMPI::init(&argc,&argv,MPI_COMM_WORLD);

    CommonIO::begin();

    int repeat=1;
    int  debug=0;
    bool debug_solver_params=false;
    int debugSeqDigits=0;
    bool ofile=false;
    bool stallForDebug=false;

    utilib::ParameterSet params;
    params.create_parameter("repeat",repeat,"<int>","1",
          "TODO",utilib::ParameterLowerBound<int>(1));
    params.create_parameter("debug",debug,"<int>","0",
          "TODO",utilib::ParameterLowerBound<int>(0));
    params.create_parameter("debug-solver-params",debug_solver_params,
                "<bool>","false",
                "If true, print solver parameters");
    params.create_parameter("debugSeqDigits",debugSeqDigits,"<int>","0",
          "TODO",utilib::ParameterBounds<int>(0,10));
    params.create_parameter("ofile",ofile,
                "<bool>","false",
                "If true, create the output file parMIP-out");
    params.create_parameter("stallForDebug",stallForDebug,
                "<bool>","false",
                "If true, then stall the code for debugging");

    ParameterList plist;
    plist.register_parameters(params);
    plist.register_parameters<pico::PicoLPSolver>();
    plist.register_parameters<${app_label}::Problem>();
    plist.register_parameters<${app_label}::parMILP>();
    plist.process_parameters(argc,argv,1);
    params.set_parameters(plist,false);

    if ((argc > 2) || params.get_parameter<bool>("help")) 
      {
	if (uMPI::iDoIO)
	  {
	    cout << "Usage: " << argv[0] 
		 << " {--parameter=value ...} MPS-file\n";
	    if (argc > 2) {
	      cout << "Error: you may specify only one MPS file.\n"
		   << "You have specified " << argc-1 
		   << " files or some malformed parameters.\n";
	    } ${elsestr}
	      plist.write_registered_parameters(cout);
	  }
	CommonIO::end();
	uMPI::done();
	return -1;
      }

    if (debug >= 100) ucout << "Past parameter initialization" << endl;
    ucout << Flush;

    //To allow debugger to attach to a second process
    if (stallForDebug)
      {
        ucout << uMPI::rank << " " << getpid() << endl << Flush;
	if (uMPI::rank == 0) {
	   int staller;
	   cin >> staller;
	   }
	uMPI::barrier();
      } 

    if (ofile) CommonIO::set_ofile("parMIP-out");
    CommonIO::numDigits = debugSeqDigits;

    ${app_label}::Problem problem;
    problem.set_parameters(plist,false);
    problem.lp.set_parameters(plist,false);
    problem.lp.init();
    problem.lp()->set_parameters(plist,false);
    if (uMPI::iDoIO && debug_solver_params) {
       ucout << "---- PicoLPSolver Parameters ----" << endl;
       problem.lp.write_parameter_values(ucout);
       ucout << endl << Flush;
       ucout << "---- PicoLPInterface Parameters ----" << endl;
       problem.lp()->write_parameter_values(ucout);
       ucout << endl << Flush;
       ucout << "---- MILPProblem Parameters ----" << endl;
       problem.write_parameter_values(ucout);
       ucout << endl << Flush;
       }

    for(int i=0; i < repeat; i++)
      {
	pico::gRandomReSeed();
	${app_label}::parMILP * instance = new ${app_label}::parMILP;  // pool type taken from global params
	instance->setMILPProblem(problem);
        instance->set_parameters(plist,false);
	instance->heurCfg.set_parameters(plist,false);
	instance->setDebugLevel(debug);
        instance->reset();
	ucout << Flush;
        if (uMPI::iDoIO && debug_solver_params) {
           ucout << "---- parMILP Parameters ----" << endl;
           instance->write_parameter_values(ucout);
           ucout << endl << Flush;
           }

	instance->readAndBroadcast(&argc,&argv);
	instance->printConfiguration(ucout);
	instance->search();

	ucout << Flush;
	CommonIO::end_tagging();
	if (uMPI::iDoIO)
	  {
	    if (instance->problemIsFeasible()) {
	      ucout << endl << "Final Solution:  Value = " 
		    << instance->incumbentValue << endl << endl;
	    } ${elsestr} ucout << "Problem Integer Infeasible\n";
	  }
	instance->parallelSolutionToFile();
	instance->printAllStatistics(ucout);

	CommonIO::end();

	delete instance;
      }

    uMPI::done();

    //  MEMDEBUG_DUMP(ucout);
    
  }

  catch (const char* str) {
    cerr << "ERROR! Caught parMIP exception string: ";
    cerr << str << endl;
    MPI_Abort(MPI_COMM_WORLD,1);
  }

  catch (std::exception& str) {
    cerr << "ERROR! Caught parMIP exception object: ";
    cerr << str.what() << endl;
    MPI_Abort(MPI_COMM_WORLD,1);
  }
  
#endif
return 0;
}

extern void exit_fn();
#endif

int main(int argc, char** argv)
{
try {

  InitializeTiming();
  int nprocessors=1;

#ifdef USING_MPI

  uMPI::init(&argc,&argv,MPI_COMM_WORLD);
  nprocessors = uMPI::size;

  if (nprocessors > 1) {
     CommonIO::begin();
     CommonIO::setIOFlush(1);

     ${app_label}::parMILP milp;
     ${app_label}::Problem problem;
     if (milp.setup(argc,argv,problem)) {
        milp.reset();
        milp.solve();
        }
     CommonIO::end();
     }
#endif

  if (nprocessors == 1) {
     ${app_label}::MILP milp;
     ${app_label}::Problem problem;

     if (milp.setup(argc,argv,problem)) {
        milp.reset();
        milp.solve();
        }
     }

#ifdef USING_MPI
  uMPI::done();
#endif

}
STD_CATCH(;)

return 0;
}



MAIN_CPP
   endif
endif

endif		# stage2

exit





