Beispiel #1
0
void shortOrHelpOne (CoinParamVec &paramVec,
		     int matchNdx, std::string name, int numQuery)

{ int i ;
  int numParams = static_cast<int>(paramVec.size()) ;
  int lclNdx = -1 ;
/*
  For a short match, we need to look up the parameter again. This should find
  a short match, given the conditions where this routine is called. But be
  prepared to find a full match.
  
  If matchNdx >= 0, just use the index we're handed.
*/
  if (matchNdx < 0) 
  { int match = 0 ;
    for (i = 0 ; i < numParams ; i++)
    { CoinParam *param =  paramVec[i] ;
      if (param == 0) continue ;
      int match = param->matches(name) ;
      if (match != 0)
      { lclNdx = i ;
	break ; } }

    assert (lclNdx >= 0) ;

    if (match == 1)
    { std::cout
	<< "Match for '" << name << "': "
	<< paramVec[matchNdx]->matchName() << "." ; }
    else
    { std::cout
      << "Short match for '" << name << "'; possible completion: "
      << paramVec[lclNdx]->matchName() << "." ; } }
  else
  { assert(matchNdx >= 0 && matchNdx < static_cast<int>(paramVec.size())) ;
    std::cout << "Match for `" << name << "': "
	      << paramVec[matchNdx]->matchName() ;
    lclNdx = matchNdx ; }
/*
  Print some help, if there was a `?' in the name. `??' gets the long help.
*/
  if (numQuery > 0)
  { std::cout << std::endl ;
    if (numQuery == 1)
    { std::cout << paramVec[lclNdx]->shortHelp() ; }
    else
    { paramVec[lclNdx]->printLongHelp() ; } }
  std::cout << std::endl ;

  return ; }
Beispiel #2
0
void shortOrHelpMany (CoinParamVec &paramVec, std::string name, int numQuery)

{ int numParams = static_cast<int>(paramVec.size()) ;
/*
  Scan the parameter list. For each match, print just the name, or the name
  and short help.
*/
  int lineLen = 0 ;
  bool printed = false ;
  for (int i = 0 ; i < numParams ; i++)
  { CoinParam *param = paramVec[i] ;
    if (param == 0) continue ;
    int match = param->matches(name) ;
    if (match > 0)
    { std::string nme = param->matchName() ;
      int len = static_cast<int>(nme.length()) ;
      if (numQuery >= 2) 
      { std::cout << nme << " : " << param->shortHelp() ;
	std::cout << std::endl ; }
      else
      { lineLen += 2+len ;
	if (lineLen > 80)
	{ std::cout << std::endl ;
	  lineLen = 2+len ; }
	std::cout << "  " << nme ;
	printed = true ; } } }

  if (printed)
  { std::cout << std::endl ; }

  return ; }
Beispiel #3
0
int matchParam (const CoinParamVec &paramVec, std::string name,
		int &matchNdx, int &shortCnt)

{ 
  int vecLen = static_cast<int>(paramVec.size()) ;
  int matchCnt = 0 ;

  matchNdx = -1 ;
  shortCnt = 0 ;

  for (int i = 0 ; i < vecLen  ; i++)
  { CoinParam *param =  paramVec[i] ;
    if (param == 0) continue ;
    int match = paramVec[i]->matches(name) ;
    if (match == 1)
    { matchNdx = i ;
      matchCnt++ ;
      if (name == "?")
      { matchCnt = 1 ;
	break ; } }
    else
    { shortCnt += match>>1 ; } }

  return (matchCnt) ;
}
Beispiel #4
0
int lookupParam (std::string name, CoinParamVec &paramVec,
		 int *matchCntp, int *shortCntp, int *queryCntp)

{
  int retval = -3 ;

  if (matchCntp != 0)
  { *matchCntp = 0 ; }
  if (shortCntp != 0)
  { *shortCntp = 0 ; }
  if (queryCntp != 0)
  { *queryCntp = 0 ; }
/*
  Is there anything here at all? 
*/
  if (name.length() == 0)
  { return (retval) ; }
/*
  Scan the parameter name to see if it ends in one or more `?' characters. If
  so, take it as a request to return a list of parameters that match name up
  to the first `?'.  The strings '?' and '???' are considered to be valid
  parameter names (short and long help, respectively) and are handled as
  special cases: If the whole string is `?'s, one and three are commands as
  is, while 2 and 4 or more are queries about `?' or `???'.
*/
  int numQuery = 0 ;
  { int length = static_cast<int>(name.length()) ;
    int i ;
    for (i = length-1 ; i >= 0 && name[i] == '?' ; i--)
    { numQuery++ ; }
    if (numQuery == length)
    { switch (length)
      { case 1:
	case 3:
	{ numQuery = 0 ;
	  break ; }
	case 2:
	{ numQuery -= 1 ;
	  break ; }
        default:
	{ numQuery -= 3 ;
	  break ; } } }
    name = name.substr(0,length-numQuery) ;
    if (queryCntp != 0)
    { *queryCntp = numQuery ; } }
/*
  See if we can match the parameter name. On return, matchNdx is set to the
  last match satisfying the minimal match criteria, or -1 if there's no
  match.  matchCnt is the number of matches satisfying the minimum match
  length, and shortCnt is possible matches that were short of the minimum
  match length,
*/
  int matchNdx = -1 ;
  int shortCnt = 0 ;
  int matchCnt = CoinParamUtils::matchParam(paramVec,name,matchNdx,shortCnt) ;
/*
  Set up return values before we get into further processing.
*/
  if (matchCntp != 0)
  { *matchCntp = matchCnt ; }
  if (shortCntp != 0)
  { *shortCntp = shortCnt ; }
  if (numQuery > 0)
  { retval = -1 ; }
  else
  { if (matchCnt+shortCnt == 0)
    { retval = -3 ; }
    else
    if (matchCnt > 1)
    { retval = -4 ; }
    else
    { retval = -2 ; } }
/*
  No matches? Nothing more to be done here.
*/
  if (matchCnt+shortCnt == 0)
  { return (retval) ; }
/*
  A unique match and no `?' in the name says we have our parameter. Return
  the result.
*/
  if (matchCnt == 1 && shortCnt == 0 && numQuery == 0)
  { assert (matchNdx >= 0 && matchNdx < static_cast<int>(paramVec.size())) ;
    return (matchNdx) ; }
/*
  A single match? There are two possibilities:
    * The string specified is shorter than the match length requested by the
      parameter. (Useful for avoiding inadvertent execution of commands that
      the client might regret.)
    * The string specified contained a `?', in which case we print the help.
      The match may or may not be short.
*/
  if (matchCnt+shortCnt == 1)
  { CoinParamUtils::shortOrHelpOne(paramVec,matchNdx,name,numQuery) ;
    return (retval) ; }
/*
  The final case: multiple matches. Most commonly this will be multiple short
  matches. If we have multiple matches satisfying the minimal length
  criteria, we have a configuration problem.  The other question is whether
  the user wanted help information. Two question marks gets short help.
*/
  if (matchCnt > 1)
  { std::cout
    << "Configuration error! `" << name
    <<"' was fully matched " << matchCnt << " times!"
    << std::endl ; }
  std::cout
    << "Multiple matches for `" << name << "'; possible completions:"
    << std::endl ;
  CoinParamUtils::shortOrHelpMany(paramVec,name,numQuery) ;

  return (retval) ; }
Beispiel #5
0
void addCbcOsiParams (int &numberParameters, CoinParamVec &parameters,
                      OsiSolverInterface *osi)
{
    CbcOsiParam *param ;
    OsiHintParam key ;
    bool sense ;
    OsiHintStrength strength ;
    int ival ;
    double dval ;

    param = new CbcOsiParam(CbcOsiParam::KEEPNAMES,
                            "keepN!ames", "Whether to keep row and column names on import.",
                            "off", 1) ;
    param->appendKwd("on") ;
    param->setPushFunc(pushCbcOsiKwd) ;
    param->setObj(osi) ;
    param->setLongHelp(
        "Row and column names are human-friendly, but maintaining names takes up space and time. Specifying -keepnames off >before< importing a problem will discard any name information."
    ) ;
    parameters.push_back(param) ;


    (void) osi->getIntParam(OsiMaxNumIteration, ival) ;
    param = new CbcOsiParam(CbcOsiParam::MAXITERATION,
                            "maxIt!erations", "Iteration limit for OSI solver.",
                            0, COIN_INT_MAX, ival) ;
    param->setPushFunc(pushCbcOsiInt) ;
    param->setObj(osi) ;
    param->setLongHelp(
        "Limits the number of iterations the OSI solver can perform when solving a problem."
    ) ;
    parameters.push_back(param) ;


    (void) osi->getIntParam(OsiMaxNumIterationHotStart, ival) ;
    param = new CbcOsiParam(CbcOsiParam::MAXHOTITS,
                            "hot!StartMaxIts", "Iteration limit for OSI solver hot start.",
                            0, COIN_INT_MAX, ival) ;
    param->setPushFunc(pushCbcOsiInt) ;
    param->setObj(osi) ;
    param->setLongHelp(
        "Limits the number of iterations the OSI solver can perform when solving a problem from a hot start. In the context of cbc, this limits the number of iterations expended on each LP during strong branching."
    ) ;
    parameters.push_back(param) ;

    /*
      Simplified to on/off for OsiSolverInterface, where it goes in as a hint.
    */
    (void) osi->getHintParam(OsiDoPresolveInInitial, sense, strength) ;
    if (sense == true) {
        ival = 1 ;
    } else {
        ival = 0 ;
    }
    param = new CbcOsiParam(CbcOsiParam::PRESOLVE,
                            "presolve", "Whether to presolve problem", "off", ival) ;
    param->appendKwd("on") ;
    param->setPushFunc(pushCbcOsiHint) ;
    param->setObj(osi) ;
    param->setLongHelp(
        "Presolve analyzes the model to find such things as redundant constraints, constraints which fix some variables, constraints which can be transformed into bounds, etc.  For the initial solve of any problem this is worth doing unless you know that it will have no effect."
    ) ;
    parameters.push_back(param) ;


    param = new CbcOsiParam(CbcOsiParam::PRIMALTOLERANCE,
                            "primalT!olerance",
                            "For an optimal solution no primal infeasibility may exceed this value",
                            1.0e-20, 1.0e12) ;
    param->setPushFunc(pushCbcOsiDbl) ;
    param->setObj(osi) ;
    param ->setLongHelp(
        "Normally the default tolerance is fine, but you may want to increase it a bit if a primal run seems to be having a hard time"
    ) ;
    parameters.push_back(param) ;

    /*
      Simplified for OsiSolverInterface, which just takes a hint.
    */
    (void) osi->getHintParam(OsiDoScale, sense, strength) ;
    if (sense == true) {
        ival = 1 ;
    } else {
        ival = 0 ;
    }
    param = new CbcOsiParam(CbcOsiParam::SCALING,
                            "scal!ing", "Whether to scale problem", "off", ival) ;
    param ->appendKwd("on") ;
    param->setPushFunc(pushCbcOsiHint) ;
    param->setObj(osi) ;
    param ->setLongHelp(
        "Scaling can help in solving problems which might otherwise fail because of lack of accuracy.  It can also reduce the number of iterations.  It is not applied if the range of elements is small.  When unscaled it is possible that there may be small primal and/or infeasibilities."
    ) ;
    parameters.push_back(param) ;

    ival = osi->messageHandler()->logLevel() ;
    param = new CbcOsiParam(CbcOsiParam::SOLVERLOGLEVEL,
                            "slog!Level", "Level of detail in Solver output", -1, 63, ival) ;
    param->setPushFunc(pushCbcOsiLogLevel) ;
    param->setObj(osi) ;
    param ->setLongHelp(
        "If 0 then there should be no output in normal circumstances. 1 is probably the best value for most uses, while 2 and 3 give more information."
    ) ;
    parameters.push_back(param) ;

    numberParameters = parameters.size() ;
    assert (numberParameters <= parameters.capacity()) ;

}
Beispiel #6
0
int main (int argc, const char *argv[])
{
    /*
      This interior block contains all memory allocation; useful for debugging.
    */
    {
        double time1 = CoinCpuTime() ;
        double time2 ;
        /*
          Try and get all the various i/o to come out in order. Synchronise with C
          stdio and make stderr and stdout unbuffered.
        */
        std::ios::sync_with_stdio() ;
        setbuf(stderr, 0) ;
        setbuf(stdout, 0) ;
        /*
          The constructor for ctlBlk establishes the default values for cbc-generic
          parameters. A little more work is required to create the vector of available
          solvers and set the default.
        */
        CbcGenCtlBlk ctlBlk ;
        ctlBlk.setMessages() ;
        ctlBlk.setLogLevel(1) ;
        OsiSolverInterface *dfltSolver = CbcGenSolvers::setupSolvers() ;
        ctlBlk.dfltSolver_ = dfltSolver ;
        assert (ctlBlk.dfltSolver_) ;
        /*
          Now we can begin to initialise the parameter vector. Create a vector of the
          proper size, then load up the parameters that are relevant to the main
          program (specifically, values held in ctlBlk and actions evoked from the
          main program).
        */
        int numParams = 0 ;
        CoinParamVec paramVec ;
        paramVec.reserve(CbcOsiParam::CBCOSI_LASTPARAM) ;
        ctlBlk.paramVec_ = &paramVec ;
        ctlBlk.genParams_.first_ = numParams ;
        CbcGenParamUtils::addCbcGenParams(numParams, paramVec, &ctlBlk) ;
        ctlBlk.genParams_.last_ = numParams - 1 ;
        /*
          Establish a CbcModel object with the default lp solver. Install any defaults
          that are available from ctlBlk.
        */
        CbcModel *model = new CbcModel(*dfltSolver) ;
        ctlBlk.model_ = model ;
        model->messageHandler()->setLogLevel(1) ;
        model->setNumberStrong(ctlBlk.chooseStrong_.numStrong_) ;
        model->setNumberBeforeTrust(ctlBlk.chooseStrong_.numBeforeTrust_) ;
        CbcCbcParamUtils::setCbcModelDefaults(model) ;
        OsiSolverInterface *osi = model->solver() ;
        /*
          Set up the remaining classes of parameters, taking defaults from the CbcModel
          and OsiSolverInterface objects we've set up. There are parameters that
          belong to CbcModel (CbcCbcParam) and to the underlying OsiSolverInterface
          (CbcOsiParam).
        */
        ctlBlk.cbcParams_.first_ = numParams ;
        CbcCbcParamUtils::addCbcCbcParams(numParams, paramVec, model) ;
        ctlBlk.cbcParams_.last_ = numParams - 1 ;
        ctlBlk.osiParams_.first_ = numParams ;
        CbcOsiParamUtils::addCbcOsiParams(numParams, paramVec, osi) ;
        ctlBlk.osiParams_.last_ = numParams - 1 ;
        /*
          Initialise the vector that tracks parameters that have been changed by user
          command.
        */
        ctlBlk.setByUser_.resize(CbcOsiParam::CBCOSI_LASTPARAM, false) ;
        /*
          The main command parsing loop. Call getCommand to get the next parameter.
          (The user will be prompted in interactive mode.) If we find something,
          proceed to process it.

          If we don't find anything, behaviour depends on what we've seen so far:

          * An empty command/parameter and no history of previous success gets a
            brief message. If we're in interactive mode, allow the user to try again,
            otherwise quit.

          * An empty command/parameter in interactive mode with some history of
            successful commands is ignored. Iterate and try again.

          * An empty command/parameter when we're not interactive is taken
            as the end of commands. If we have a good model, force branchAndBound.
            (This is one aspect of giving the expected behaviour for
            `cbc-generic [parameters] foo.mps'.)
        */
        bool keepParsing = true ;
        bool forceImport = false ;
        std::string forceImportFile = "" ;
        std::string prompt = "cbcGen: " ;
        std::string pfx = "" ;
        while (keepParsing) {
            std::string paramName = CoinParamUtils::getCommand(argc, argv, prompt, &pfx);
            if (paramName.length() == 0) {
                if (ctlBlk.paramsProcessed_ == 0) {
                    if (CoinParamUtils::isInteractive()) {
                        std::cout
                            << "Type `?' or `help' for usage and command keywords."
                            << " Type `quit' to quit." ;
                    } else {
                        std::cout
                            << "Type `cbc-generic -help' for usage and parameter keywords." ;
                        keepParsing = false ;
                    }
                    std::cout << std::endl ;
                } else if (!CoinParamUtils::isInteractive()) {
                    keepParsing = false ;
                    if (ctlBlk.goodModel_ == true &&
                            ctlBlk.bab_.majorStatus_ == CbcGenCtlBlk::BACNotRun) {
                        paramName = "branchAndCut" ;
                        pfx = "-" ;
                    }
                }
            }
            if (paramName == "") {
                continue ;
            }
            /*
              Do we have a parameter we recognise? In command line mode, if there was no
              prefix (either `-' or `--'), the user didn't intend this as a command
              keyword.
            */
            int matchNdx ;
            if (!CoinParamUtils::isCommandLine() || pfx == "-" || pfx == "--") {
                matchNdx = CoinParamUtils::lookupParam(paramName, paramVec) ;
            } else {
                matchNdx = -3 ;
            }
            std::cout
                << "Command is `" << paramName
                << "', pfx `" << pfx
                << "', match = " << matchNdx << std::endl ;
            /*
              If matchNdx is positive, we have a unique parameter match and we can get on
              with processing. If the return value is negative, and we're not
              interactive, quit. If we're interactive, react as appropriate:
                -1: There was a `?' in the command string. Prompt again.
                -2: No `?', and one or more short matches. Prompt again.
                -3: No `?', but we didn't match anything either. If we're in command line
            	mode, and there was no `-' or `--' prefix, try forcing `import' (but
            	just once, eh). This is the other piece required to get `cbc-generic
            	[parameters] foo.mps' to work as expected.) In interactive mode,
            	we'll require the user to say `import'.  Interactive mode and no
            	history of successful commands gets the help message.
                -4: Configuration error, offer `report to maintainers' message.
            */
            if (matchNdx < 0) {
                if (matchNdx == -3) {
                    if (CoinParamUtils::isCommandLine() && pfx == "") {
                        if (!forceImport) {
                            forceImportFile = paramName ;
                            paramName = "import" ;
                            matchNdx = CoinParamUtils::lookupParam(paramName, paramVec) ;
                            forceImport = true ;
                        } else {
                            std::cout << "No commands matched `" << paramName << "'."
                                      << std::endl ;
                        }
                    } else {
                        std::cout << "No commands matched `" << paramName << "'."
                                  << std::endl ;
                        if (ctlBlk.paramsProcessed_ == 0) {
                            std::cout
                                << "Type `?' or `help' for usage and command keywords."
                                << " Type `quit' to quit." << std::endl ;
                        }
                    }
                } else if (matchNdx == -4) {
                    std::cout
                        << "Please report this error by filing a ticket at "
                        << "https://projects.coin-or.org/Cbc/wiki."
                        << std::endl ;
                }
            }
            if (matchNdx < 0) {
                keepParsing = CoinParamUtils::isInteractive() ;
                continue ;
            }
            CoinParam *param = paramVec[matchNdx] ;
            ctlBlk.paramsProcessed_++ ;
            /*
              Depending on the type, we may need a parameter. For keyword parameters, check
              that the keyword is recognised --- setKwdVal will quietly fail on a bad
              keyword.
            */
            CoinParam::CoinParamType type = param->type() ;
            int valid = 0 ;
            switch (type) {
            case CoinParam::coinParamAct: {
                break ;
            }
            case CoinParam::coinParamInt: {
                int ival = CoinParamUtils::getIntField(argc, argv, &valid) ;
                if (valid == 0) {
                    param->setIntVal(ival) ;
                }
                break ;
            }
            case CoinParam::coinParamDbl: {
                double dval = CoinParamUtils::getDoubleField(argc, argv, &valid) ;
                if (valid == 0) {
                    param->setDblVal(dval) ;
                }
                break ;
            }
            case CoinParam::coinParamStr: {
                if (forceImport) {
                    param->setStrVal(forceImportFile) ;
                } else {
                    const std::string tmp =
                        CoinParamUtils::getStringField(argc, argv, &valid) ;
                    if (valid == 0) {
                        param->setStrVal(tmp) ;
                    }
                }
                break ;
            }
            case CoinParam::coinParamKwd: {
                const std::string tmp =
                    CoinParamUtils::getStringField(argc, argv, &valid) ;
                if (valid == 0) {
                    param->setKwdVal(tmp) ;
                    if (param->kwdVal() != tmp) {
                        std::cout
                            << "Unrecognised keyword `" << tmp << "' for parameter "
                            << param->name() << std::endl ;
                        param->printKwds() ;
                        std::cout << std::endl ;
                        valid = 1 ;
                    }
                }
                break ;
            }
            default: {
                assert (false) ;
                break ;
            }
            }
            /*
              Deal with missing or incorrect values.

              If valid came back as 2, we're short a parameter. This is interpreted as a
              request to tell the user the current value.  If valid came back as 1, we
              had some sort of parse error. Print an error message.
            */
            if (valid != 0) {
                switch (valid) {
                case 1: {
                    std::cout
                        << "Could not parse the value given for parameter `"
                        << param->name() << "'." << std::endl ;
                    break ;
                }
                case 2: {
                    std::cout
                        << "Current value of " << param->name() << " parameter is `"
                        << *param << "'." << std::endl ;
                    break ;
                }
                default: {
                    std::cout
                        << "Parse status is " << valid
                        << "; this indicates internal confusion." << std::endl
                        << "Please report this error by filing a ticket at "
                        << "https://projects.coin-or.org/Cbc/wiki."
                        << std::endl ;
                }
                }
                keepParsing = CoinParamUtils::isInteractive() ;
                continue ;
            }
            /*
              Ok, call the parameter's push function to do the heavy lifting. Push and pull
              functions return 0 for success, 1 for non-fatal error, -1 for fatal error.
            */
            if (param->pushFunc() == 0) {
                std::cout << "Parameter `" << param->name()
                          << "' is not implemented." << std::endl ;
            } else {
                int retval = (param->pushFunc())(param) ;
                markAsSetByUser(ctlBlk, param) ;
                if (retval < 0) {
                    keepParsing = false ;
                }
            }
        }
        /*
          End of loop to parse and execute parameter actions. Time to do cleanup.
          The destructor for CbcGenCtlBlk will delete anything with a non-null pointer,
          so we need to be careful that the default solver is deleted only once.
        */
        ctlBlk.dfltSolver_ = 0 ;
        CbcGenSolvers::deleteSolvers() ;
        for (int i = 0 ; i < paramVec.size() ; i++) {
            if (paramVec[i] != 0) delete paramVec[i] ;
        }
    }
    /*
      End of memory allocation block. There should be no allocated objects at
      this point.
    */
    return (0) ;
}