1 
2 /* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
3 
4 /*
5  *  Main authors:
6  *     Gleb Belov <gleb.belov@monash.edu>
7  */
8 
9 /* This Source Code Form is subject to the terms of the Mozilla Public
10  * License, v. 2.0. If a copy of the MPL was not distributed with this
11  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
12 
13 #pragma once
14 
15 #include <minizinc/solver_config.hh>
16 #include <minizinc/solver_instance_base.hh>
17 #include <minizinc/solvers/MIP/MIP_wrap.hh>
18 // CMakeLists.txt needs OSICBC_HOME defined
19 // #include <coin/CoinPackedVector.hpp>
20 // #include <coin/CoinPackedMatrix.hpp>
21 // #include <coin/CoinShallowPackedVector.hpp>
22 // #include <coin/CoinTime.hpp>
23 // #include <coin/OsiSolverInterface.hpp>
24 //  #include <coin/OsiCbcSolverInterface.hpp>
25 #include <coin/CbcModel.hpp>
26 #include <coin/OsiClpSolverInterface.hpp>
27 // #include <coin/CbcSolver.hpp>
28 
29 class MIPosicbcWrapper : public MIPWrapper {
30   //     OsiCbcSolverInterface osi;   // deprecated in Cbc 2.9.6
31   OsiClpSolverInterface _osi;
32   //     CoinPackedMatrix* matrix = 0;
33   int _error;
34   std::string _osicbcBuffer;  // [CBC_MESSAGEBUFSIZE];
35                               //     string          osicbc_status_buffer; // [CBC_MESSAGEBUFSIZE];
36 
37   std::vector<double> _x;
38 
39   // To add constraints:
40   //     vector<int> rowStarts, columns;
41   std::vector<CoinPackedVector> _rows;
42   std::vector<double>  // element,
43       _rowlb, _rowub;
44 
45   std::unordered_map<VarId, double> _warmstart;  // this accumulates warmstart infos
46 
47 public:
48   class FactoryOptions {
49   public:
50     // NOLINTNEXTLINE(readability-convert-member-functions-to-static)
processOption(int & i,std::vector<std::string> & argv,const std::string & workingDir)51     bool processOption(int& i, std::vector<std::string>& argv, const std::string& workingDir) {
52       return false;
53     }
54   };
55 
56   class Options : public MiniZinc::SolverInstanceBase::Options {
57   public:
58     int nThreads = 1;
59     std::string sExportModel;
60     int nTimeout = 0;
61     long int nSolLimit = -1;
62     double nWorkMemLimit = -1;
63     std::string sReadParams;
64     std::string sWriteParams;
65     bool flagIntermediate = false;
66 
67     double absGap = -1;
68     double relGap = 1e-8;
69     double intTol = 1e-8;
70     double objDiff = 1.0;
71 
72     std::vector<std::string> cbcCmdOptions;
73 
74     std::unordered_map<std::string, std::string> extraParams;
75 
76     bool processOption(int& i, std::vector<std::string>& argv,
77                        const std::string& workingDir = std::string());
78     static void printHelp(std::ostream& os);
79   };
80 
81 private:
82   Options* _options = nullptr;
83 
84 public:
MIPosicbcWrapper(FactoryOptions & factoryOpt,Options * opt)85   MIPosicbcWrapper(FactoryOptions& factoryOpt, Options* opt) : _options(opt) { openOSICBC(); }
~MIPosicbcWrapper()86   ~MIPosicbcWrapper() override { closeOSICBC(); }
87 
88   static std::string getDescription(FactoryOptions& factoryOpt,
89                                     MiniZinc::SolverInstanceBase::Options* opt = nullptr);
90   static std::string getVersion(FactoryOptions& factoryOpt,
91                                 MiniZinc::SolverInstanceBase::Options* opt = nullptr);
92   static std::string getId();
93   static std::string getName();
94   static std::vector<std::string> getTags();
95   static std::vector<std::string> getStdFlags();
getRequiredFlags(FactoryOptions & factoryOpt)96   static std::vector<std::string> getRequiredFlags(FactoryOptions& factoryOpt) { return {}; };
getFactoryFlags()97   static std::vector<std::string> getFactoryFlags() { return {}; };
98 
99   static std::vector<MiniZinc::SolverConfig::ExtraFlag> getExtraFlags(FactoryOptions& factoryOpt);
100 
101   void printVersion(std::ostream&);
102   void printHelp(std::ostream&);
103   //       Statistics& getStatistics() { return _statistics; }
104 
105   //      IloConstraintArray *userCuts, *lazyConstraints;
106 
107   /// derived should overload and call the ancestor
108   //     virtual void cleanup();
openOSICBC()109   void openOSICBC() {}
closeOSICBC()110   void closeOSICBC() {}
111 
112   /// actual adding new variables to the solver
113   void doAddVars(size_t n, double* obj, double* lb, double* ub, VarType* vt,
114                  std::string* names) override;
115 
addPhase1Vars()116   void addPhase1Vars() override {
117     if (fVerbose) {
118       std::cerr << "  MIPosicbcWrapper: delaying physical addition of variables..." << std::endl;
119     }
120   }
121 
122   /// adding a linear constraint
123   void addRow(int nnz, int* rmatind, double* rmatval, LinConType sense, double rhs,
124               int mask = MaskConsType_Normal, const std::string& rowName = "") override;
125   /// adding an implication
126   //     virtual void addImpl() = 0;
127 
128   bool addWarmStart(const std::vector<VarId>& vars, const std::vector<double>& vals) override;
129 
130   void setObjSense(int s) override;  // +/-1 for max/min
131 
getInfBound()132   double getInfBound() override { return _osi.getInfinity(); }
133 
getNCols()134   int getNCols() override {
135     int nc = _osi.getNumCols();
136     return nc != 0 ? nc : static_cast<int>(colLB.size());
137   }
getNColsModel()138   int getNColsModel() override { return _osi.getNumCols(); }
getNRows()139   int getNRows() override {
140     if (!_rowlb.empty()) {
141       return _rowlb.size();
142     }
143     return _osi.getNumRows();
144   }
145 
146   //     void setObjUB(double ub) { objUB = ub; }
147   //     void addQPUniform(double c) { qpu = c; } // also sets problem type to MIQP unless c=0
148 
149   void solve() override;
150 
151   /// OUTPUT:
getValues()152   const double* getValues() override { return output.x; }
getObjValue()153   double getObjValue() override { return output.objVal; }
getBestBound()154   double getBestBound() override { return output.bestBound; }
getCPUTime()155   double getCPUTime() override { return output.dCPUTime; }
156 
getStatus()157   Status getStatus() override { return output.status; }
getStatusName()158   std::string getStatusName() override { return output.statusName; }
159 
getNNodes()160   int getNNodes() override { return output.nNodes; }
getNOpen()161   int getNOpen() override { return output.nOpenNodes; }
162 
163   //     virtual int getNNodes() = 0;
164   //     virtual double getTime() = 0;
165 
166 protected:
167   //     OsiSolverInterface& getOsiSolver() { return osi; }
168 
169   void wrapAssert(bool cond, const std::string& msg, bool fTerm = true);
170 
171   /// Need to consider the 100 status codes in OSICBC and change with every version? TODO
172   Status convertStatus(CbcModel* pModel);
173   Status convertStatus();
174 };
175