CouenneSdpCuts.cpp
Go to the documentation of this file.
1 /* $Id: CouenneSdpCuts.cpp 957 2013-05-19 17:53:48Z pbelotti $
2  *
3  * Name: CouenneSdpCuts.cpp
4  * Author: Pietro Belotti
5  * Purpose: wrapper for Couenne to insert sdpcuts
6  *
7  * This file is licensed under the Eclipse Public License (EPL)
8  */
9 
10 #include "IpOptionsList.hpp"
11 
12 #include "CouenneJournalist.hpp"
13 #include "CouenneMatrix.hpp"
14 #include "CouennePSDcon.hpp"
15 #include "CouenneSdpCuts.hpp"
16 #include "CouenneProblem.hpp"
17 #include "CouenneExprVar.hpp"
18 #include "CouenneExprAux.hpp"
21 
22 #include "CoinTime.hpp"
23 
24 #include <set>
25 
26 using namespace Couenne;
27 
28 //#define DEBUG
29 
32  JnlstPtr jnlst,
34  problem_ (p),
35  doNotUse_ (false) {
36 
37  std::string s;
38 
39  options -> GetIntegerValue ("sdp_cuts_num_ev", numEigVec_, "couenne.");
40  options -> GetStringValue ("sdp_cuts_neg_ev", s, "couenne."); onlyNegEV_ = (s == "yes");
41  options -> GetStringValue ("sdp_cuts_sparsify", s, "couenne."); useSparsity_ = (s == "yes");
42  options -> GetStringValue ("sdp_cuts_fillmissing", s, "couenne."); fillMissingTerms_ = (s == "yes");
43 
44  CouenneExprMatrix *cauldron = new CouenneExprMatrix;
45 
46  // 1) Construct matrix with entries x_i, x_j
47 
48  for (std::vector <exprVar *>::iterator
49  i = p -> Variables (). begin ();
50  i != p -> Variables (). end (); ++i)
51 
52  if ((*i) -> Type () == AUX) {
53 
54  expression *image = (*i) -> Image ();
55 
57  if ((image -> code () == COU_EXPRMUL) &&
58  (image -> ArgList () [0] -> Type () != CONST) &&
59  (image -> ArgList () [1] -> Type () != CONST)) {
60 
61  int
62  index0 = image -> ArgList () [0] -> Index (),
63  index1 = image -> ArgList () [1] -> Index ();
64 
65  if ((index0 >= 0) &&
66  (index1 >= 0) &&
67  ((*i) -> Index () >= 0))
68 
69  // cauldron -> add_element (CoinMin (index0, index1),
70  // CoinMax (index0, index1), (*i));
71 
72  cauldron -> add_element (index0, index1, (*i));
73  cauldron -> add_element (index1, index0, (*i));
74  }
75 
77  if ((image -> code () == COU_EXPRPOW) &&
78  (image -> ArgList () [0] -> Type () != CONST) &&
79  (image -> ArgList () [1] -> Value () == 2.)) {
80 
81  int index0 = image -> ArgList () [0] -> Index ();
82 
83  if ( (index0 >= 0) &&
84  ((*i) -> Index () >= 0))
85 
86  cauldron -> add_element (index0, index0, (*i));
87  }
88  }
89 
90 #ifdef DEBUG
91  printf ("Cauldron so far\n");
92  cauldron -> print ();
93 #endif
94 
95  // TODO
96 
97  // 2) Block-partition it (optional), obtain matrices. Replace line
98  // below to decompose cauldron
99 
100  minors_ . push_back (cauldron);
101 
102  // 2.5) If option says so, add fictitious auxiliary variables if not there
103 
104  if (fillMissingTerms_) {
105 
106  for (std::vector <CouenneExprMatrix *>::iterator
107  i = minors_ . begin ();
108  i != minors_ . end (); ++i) {
109 
110  // First: construct (possibly sparse) index set, to check
111  // against each row (whose index set is a SUBSET, if non-proper,
112  // of varNumIndices). Do not use varIndices, as it is empty for
113  // now.
114 
115  std::set <int> varNumIndices;
116 
117  for (std::set <std::pair <int, CouenneSparseVector *>, CouenneExprMatrix::compare_pair_ind>::const_iterator
118  rowIt = (*i) -> getRows (). begin ();
119  rowIt != (*i) -> getRows (). end (); ++rowIt) {
120 
121  varNumIndices. insert (rowIt -> first);
122 
123  for (std::set <CouenneScalar *, CouenneSparseVector::compare_scalars>::const_iterator
124  elemIt = rowIt -> second -> getElements () . begin ();
125  elemIt != rowIt -> second -> getElements () . end (); ++elemIt)
126 
127  varNumIndices. insert ((*elemIt) -> getIndex ());
128  }
129 
130  // Second: check every row for elements (i,j) not in this row by
131  // parallel scanning of varNumINdices
132 
133  for (std::set <std::pair <int, CouenneSparseVector *>, CouenneExprMatrix::compare_pair_ind>::const_iterator
134  rowIt = (*i) -> getRows (). begin ();
135  rowIt != (*i) -> getRows (). end (); ++rowIt) {
136 
137  int rowInd = rowIt -> first;
138 
139  std::set <int>::iterator vniIt = varNumIndices . begin ();
140 
141  for (std::set <CouenneScalar *, CouenneSparseVector::compare_scalars>::const_iterator
142  elemIt = rowIt -> second -> getElements () . begin ();
143  elemIt != rowIt -> second -> getElements () . end (); ++elemIt) {
144 
145  int colInd = (*elemIt) -> getIndex ();
146 
147  while ((vniIt != varNumIndices . end ()) && (*vniIt < colInd)) {
148 
149  if (rowInd <= *vniIt) {
150  //printf ("missing term: %d, %d\n", rowInd, *vniIt);
151 
152  expression *image;
153 
154  if (rowInd == *vniIt) image = new exprPow (new exprClone (problem_ -> Var (rowInd)), new exprConst (2.));
155  else image = new exprMul (new exprClone (problem_ -> Var (rowInd)), new exprClone (problem_ -> Var (*vniIt)));
156 
157  exprAux *yIJ = problem_ -> addAuxiliary (image);
158 
159  // seek expression in the set
160  if (problem_ -> AuxSet () -> find (yIJ) ==
161  problem_ -> AuxSet () -> end ()) {
162 
163  // no such expression found in the set, create entry therein
164  problem_ -> Variables () . push_back (yIJ);
165  problem_ -> AuxSet () -> insert (yIJ); // insert into repetition checking structure
166  }
167 
168  (*i) -> add_element (rowInd, *vniIt, yIJ);
169  (*i) -> add_element (*vniIt, rowInd, yIJ);
170  }
171 
172  ++vniIt;
173  }
174 
175  if (vniIt == varNumIndices . end ())
176  break;
177  else ++vniIt;
178  }
179  }
180  }
181 
182  // post-rescan: update
183  //
184  // numbering_
185  // domain_
186  // commuted_
187  // optimum_
188  // integerRank_
189  // unusedOriginalsIndices_
190  //
191  // since there are new variables
192  }
193 
194  // 3) Bottom-right border each block with a row vector, a column vector,
195  // and the constant 1
196 
197  for (std::vector <CouenneExprMatrix *>::iterator
198  i = minors_ . begin ();
199  i != minors_ . end (); ++i) {
200 
201  int size = problem_ -> nVars ();
202 
203 #ifdef DEBUG
204  printf ("minor has %ld rows and %ld columns\n",
205  (*i) -> getRows () . size (),
206  (*i) -> getCols () . size ());
207 #endif
208 
209  for (std::set <std::pair <int, CouenneSparseVector *>, CouenneExprMatrix::compare_pair_ind>::const_iterator
210  j = (*i) -> getCols () . begin ();
211  j != (*i) -> getCols () . end (); ++j)
212 
213  (*i) -> varIndices () . push_back (problem_ -> Var (j -> first));
214 
215  for (std::vector <expression *>::iterator
216  j = (*i) -> varIndices () . begin ();
217  j != (*i) -> varIndices () . end (); ++j) {
218 
219  int indexVar = (*j) -> Index ();
220 #ifdef DEBUG
221  printf ("adding at [%d,%d] and viceversa\n", indexVar, size);
222 #endif
223  (*i) -> add_element (indexVar, size, *j); // note: problem_ -> Var (indexVar) == (*j)
224  (*i) -> add_element (size, indexVar, *j);
225  }
226 
227  (*i) -> add_element (size, size, new exprConst (1.));
228 
229 #ifdef DEBUG
230  (*i) -> print ();
231 #endif
232  }
233 
234  // 0) Search for X \succeq 0 constraints, if any, then add matrix to
235  // minors for each such constraint
236 
237  if (p -> ConstraintClass ("PSDcon"))
238  for (std::vector <CouenneConstraint *>::iterator
239  i = p -> ConstraintClass ("PSDcon") -> begin ();
240  i != p -> ConstraintClass ("PSDcon") -> end (); ++i) {
241 
242  CouennePSDcon *con = dynamic_cast <CouennePSDcon *> (*i);
243 
244  if (!con)
245  continue;
246 
247  minors_ . push_back (con -> getX ());
248  }
249 }
250 
251 
254 
255  for (std::vector <CouenneExprMatrix *>::iterator
256  i = minors_ . begin ();
257  i != minors_ . end (); ++i)
258 
259  delete (*i);
260 }
261 
262 
265 
266  problem_ (rhs. problem_),
267  doNotUse_ (rhs. doNotUse_),
268  numEigVec_ (rhs. numEigVec_),
269  onlyNegEV_ (rhs. onlyNegEV_),
270  useSparsity_ (rhs. useSparsity_),
271  fillMissingTerms_ (rhs. fillMissingTerms_) {
272 
273  for (std::vector <CouenneExprMatrix *>::const_iterator
274  i = rhs.minors_ . begin ();
275  i != rhs.minors_ . end (); ++i)
276 
277  minors_ . push_back (new CouenneExprMatrix (**i));
278 }
279 
280 
283 
284  problem_ = rhs. problem_;
285  doNotUse_ = rhs. doNotUse_;
286  numEigVec_ = rhs. numEigVec_;
287  onlyNegEV_ = rhs. onlyNegEV_;
288  useSparsity_ = rhs. useSparsity_;
290 
291  for (std::vector <CouenneExprMatrix *>::const_iterator
292  i = rhs.minors_ . begin ();
293  i != rhs.minors_ . end (); ++i)
294 
295  minors_ . push_back (new CouenneExprMatrix (**i));
296 
297  return *this;
298 }
299 
300 
302 CglCutGenerator *CouenneSdpCuts::clone () const
303 {return new CouenneSdpCuts (*this);}
304 
305 
308 
309  roptions -> AddLowerBoundedIntegerOption
310  ("sdp_cuts",
311  "The frequency (in terms of nodes) at which Couenne SDP cuts are generated.",
312  -99, 0,
313  "A frequency of 0 (default) means these cuts are never generated. \
314 Any positive number n instructs Couenne to generate them at every n nodes of the B&B tree. \
315 A negative number -n means that generation should be attempted at the root node, and if successful it can be repeated at every n nodes, otherwise it is stopped altogether."
316  );
317 
318  roptions -> AddLowerBoundedIntegerOption
319  ("sdp_cuts_num_ev",
320  "The number of eigenvectors of matrix X to be used to create sdp cuts.",
321  -1, -1,
322  "Set to -1 to indicate that all n eigenvectors should be used. Eigenvalues are \
323 sorted in non-decreasing order, hence selecting 1 will provide cuts on the most negative eigenvalue."
324  );
325 
326  roptions -> AddStringOption2
327  ("sdp_cuts_neg_ev",
328  "Only use negative eigenvalues to create sdp cuts.",
329  "yes",
330  "no", "use all eigenvalues regardless of their sign.",
331  "yes", "exclude all non-negative eigenvalues."
332  );
333 
335 
336  roptions -> AddStringOption2
337  ("sdp_cuts_sparsify",
338  "Make cuts sparse by greedily reducing X one column at a time before extracting eigenvectors.",
339  "no",
340  "no", "",
341  "yes", ""
342  );
343 
344  roptions -> AddStringOption2
345  ("sdp_cuts_fillmissing",
346  "Create fictitious auxiliary variables to fill non-fully dense minors. Can make a difference when Q has at least one zero term.",
347  "no",
348  "no", "Do not create auxiliaries and simply use Fourier-Motzkin to substitute a missing auxiliary y_ij with inequalities that use bounds and the definition y_ij = x_i x_j \
349 Advantage: limits the creation of auxiliaries, reformulation stays small. Default.",
350  "yes", "Create (at the beginning) auxiliaries that are linearized (through McCormick) and used within an SDP cut. This allows tighter cuts although it increases the size \
351 of the reformulation and hence of the linear relaxation."
352  );
353 
354 #if 0
355  roptions -> AddStringOption2
356  ("sdp_cuts_",
357  "",
358  "yes",
359  "no", "",
360  "yes", ""
361  );
362 #endif
363 }
CouenneProblem * problem_
pointer to problem info
Power of an expression (binary operator), with constant.
These are cuts of the form.
static void registerOptions(Ipopt::SmartPtr< Bonmin::RegisteredOptions > roptions)
Add list of options to be read from file.
bool fillMissingTerms_
If minor not fully dense, create fictitious auxiliary variables that will be used in sdp cuts only (t...
constant-type operator
virtual CglCutGenerator * clone() const
Cloning constructor.
static char * j
Definition: OSdtoa.cpp:3622
Class to represent positive semidefinite constraints //////////////////.
CouenneSdpCuts(CouenneProblem *, JnlstPtr, const Ipopt::SmartPtr< Ipopt::OptionsList >)
Constructor.
bool useSparsity_
Sparsify eigenvalues before writing inequality (default: no)
CouenneSdpCuts & operator=(const CouenneSdpCuts &)
Assignment.
fint end
Class for MINLP problems with symbolic information.
expression clone (points to another expression)
void fint fint fint fint fint fint fint fint fint fint real real real real real real real real * s
std::vector< CouenneExprMatrix * > minors_
minors on which to apply cuts
Auxiliary variable.
bool doNotUse_
after construction, true if there are enough product terms to justify application.
int numEigVec_
number of eigenvectors to be used (default: n)
Expression base class.
The in-memory representation of the variables element.
Definition: OSInstance.h:83
bool onlyNegEV_
only use negative eigenvalues (default: yes)
class for multiplications,