# HG changeset patch
# User Alpar Juttner <alpar@cs.elte.hu>
# Date 1611251917 -3600
# Node ID eba5aa390aca48b621b6c9689f90c4a53b70ce5b
# Parent  736a341e604b983e4ae9f4f47120fad0bef131c7# Parent  86a5b114a0662ff7857949add3f38c1053b2c02a
Merge #640

diff -r 736a341e604b -r eba5aa390aca cmake/FindILOG.cmake
--- a/cmake/FindILOG.cmake	Thu Jan 21 08:36:53 2021 +0100
+++ b/cmake/FindILOG.cmake	Thu Jan 21 18:58:37 2021 +0100
@@ -96,7 +96,7 @@
   SET(ILOG_LIBRARIES ${ILOG_CPLEX_LIBRARY} ${ILOG_CONCERT_LIBRARY})
   IF(CMAKE_SYSTEM_NAME STREQUAL "Linux")
     # SET(CPLEX_LIBRARIES "${CPLEX_LIBRARIES};m;pthread")
-    SET(ILOG_LIBRARIES ${ILOG_LIBRARIES} "m" "pthread")
+    SET(ILOG_LIBRARIES ${ILOG_LIBRARIES} "m" "pthread" "dl")
   ENDIF(CMAKE_SYSTEM_NAME STREQUAL "Linux")
 ENDIF(ILOG_FOUND)
 
diff -r 736a341e604b -r eba5aa390aca lemon/clp.cc
--- a/lemon/clp.cc	Thu Jan 21 08:36:53 2021 +0100
+++ b/lemon/clp.cc	Thu Jan 21 18:58:37 2021 +0100
@@ -227,14 +227,14 @@
   }
 
   ClpLp::Value ClpLp::_getCoeff(int ix, int jx) const {
-    CoinBigIndex begin = _prob->clpMatrix()->getVectorStarts()[ix];
-    CoinBigIndex end = begin + _prob->clpMatrix()->getVectorLengths()[ix];
+    CoinBigIndex begin = _prob->clpMatrix()->getVectorStarts()[jx];
+    CoinBigIndex end = begin + _prob->clpMatrix()->getVectorLengths()[jx];
 
     const int* indices = _prob->clpMatrix()->getIndices();
     const double* elements = _prob->clpMatrix()->getElements();
 
-    const int* it = std::lower_bound(indices + begin, indices + end, jx);
-    if (it != indices + end && *it == jx) {
+    const int* it = std::lower_bound(indices + begin, indices + end, ix);
+    if (it != indices + end && *it == ix) {
       return elements[it - indices];
     } else {
       return 0.0;
@@ -461,4 +461,14 @@
     }
   }
 
+   void ClpLp::_write(std::string file, std::string format) const
+  {
+    if(format == "LP")
+      _prob->writeLp(file.c_str(), "", 1e-5, 10, 5,
+                     sense()==ClpLp::MIN?1:-1,
+                     true
+                     );
+    else throw UnsupportedFormatError(format);
+  }
+ 
 } //END OF NAMESPACE LEMON
diff -r 736a341e604b -r eba5aa390aca lemon/clp.h
--- a/lemon/clp.h	Thu Jan 21 08:36:53 2021 +0100
+++ b/lemon/clp.h	Thu Jan 21 18:58:37 2021 +0100
@@ -139,6 +139,8 @@
 
     virtual void _messageLevel(MessageLevel);
 
+    void _write(std::string file, std::string format) const;
+
   public:
 
     ///Solves LP with primal simplex method.
diff -r 736a341e604b -r eba5aa390aca lemon/cplex.cc
--- a/lemon/cplex.cc	Thu Jan 21 08:36:53 2021 +0100
+++ b/lemon/cplex.cc	Thu Jan 21 18:58:37 2021 +0100
@@ -158,7 +158,7 @@
     } else {
       const char s = 'R';
       double len = ub - lb;
-      CPXaddrows(cplexEnv(), _prob, 0, 1, values.size(), &ub, &s,
+      CPXaddrows(cplexEnv(), _prob, 0, 1, values.size(), &lb, &s,
                  &rmatbeg, &indices.front(), &values.front(), 0, 0);
       CPXchgrngval(cplexEnv(), _prob, 1, &i, &len);
     }
diff -r 736a341e604b -r eba5aa390aca test/lp_test.cc
--- a/test/lp_test.cc	Thu Jan 21 08:36:53 2021 +0100
+++ b/test/lp_test.cc	Thu Jan 21 18:58:37 2021 +0100
@@ -339,6 +339,7 @@
   check(lp.objCoeff(x1)==1,"First term should be 1 in the obj function!");
   check(lp.sense() == lp.MAX,"This is a maximization!");
   check(lp.coeff(upright,x1)==1,"The coefficient in question is 1!");
+  check(lp.coeff(upright,x2)==2,"The coefficient in question is 1!");
   check(lp.colLowerBound(x1)==0,
         "The lower bound for variable x1 should be 0.");
   check(lp.colUpperBound(x1)==LpSolver::INF,
@@ -424,6 +425,34 @@
   delete lpclone;
 }
 
+template<class LP>
+void rangeConstraintTest()
+{
+  LP lp;
+  // Add two columns (variables) to the problem
+  typename LP::Col x1 = lp.addCol();
+  typename LP::Col x2 = lp.addCol();
+  // Add rows (constraints) to the problem
+  lp.addRow(x1 - 5 <= x2);
+    lp.addRow(0 <= 2 * x1 + x2 <= 25);
+  
+  // Set lower and upper bounds for the columns (variables)
+  lp.colLowerBound(x1, 0);
+  lp.colUpperBound(x2, 10);
+  
+  // Specify the objective function
+  lp.max();
+  lp.obj(5 * x1 + 3 * x2);
+  
+  // Solve the problem using the underlying LP solver
+  lp.solve();
+  // Print the results
+  check(lp.primalType() == LP::OPTIMAL, "Optimal solution is not found");
+  check(lp.primal() <= 67.501 && lp.primal() >= 67.499, "Wrong objective value");
+  check(lp.primal(x1) <= 7.501 && lp.primal(x1) >= 7.499, "Wrong value for x1");
+  check(lp.primal(x2) <= 10.001 && lp.primal(x2) >= 9.999, "Wrong value for x2");
+}
+
 int main()
 {
   LpSkeleton lp_skel;
@@ -444,6 +473,7 @@
     lpTest(lp_glpk1);
     aTest(lp_glpk2);
     cloneTest<GlpkLp>();
+    rangeConstraintTest<GlpkLp>();
   }
 #endif
 
@@ -453,6 +483,7 @@
     lpTest(lp_cplex1);
     aTest(lp_cplex2);
     cloneTest<CplexLp>();
+    rangeConstraintTest<CplexLp>();
   } catch (CplexEnv::LicenseError& error) {
     check(false, error.what());
   }
@@ -464,6 +495,7 @@
     lpTest(lp_soplex1);
     aTest(lp_soplex2);
     cloneTest<SoplexLp>();
+    rangeConstraintTest<Soplex>();
   }
 #endif
 
@@ -473,6 +505,7 @@
     lpTest(lp_clp1);
     aTest(lp_clp2);
     cloneTest<ClpLp>();
+    rangeConstraintTest<ClpLp>();
   }
 #endif
 
diff -r 736a341e604b -r eba5aa390aca test/mip_test.cc
--- a/test/mip_test.cc	Thu Jan 21 08:36:53 2021 +0100
+++ b/test/mip_test.cc	Thu Jan 21 18:58:37 2021 +0100
@@ -61,7 +61,7 @@
   }
 }
 
-void aTest(MipSolver& mip)
+void aTest(MipSolver& mip, bool solve_empty=true)
 {
   //The following example is very simple
 
@@ -80,7 +80,8 @@
   mip.max();
 
   //Unconstrained optimization
-  mip.solve();
+  if(solve_empty)
+    mip.solve();
   //Check it out!
 
   //Constraints
@@ -135,7 +136,11 @@
 #ifdef LEMON_HAVE_MIP
   {
     Mip mip1;
+#if LEMON_DEFAULT_MIP==LEMON_CBC_
+    aTest(mip1, false);
+#else
     aTest(mip1);
+#endif
     cloneTest<Mip>();
   }
 #endif
@@ -161,7 +166,7 @@
 #ifdef LEMON_HAVE_CBC
   {
     CbcMip mip1;
-    aTest(mip1);
+    aTest(mip1, false);
     cloneTest<CbcMip>();
   }
 #endif