1 /* $Id$
2 *
3 * Name: exprGroup.cpp
4 * Author: Pietro Belotti
5 * Purpose: implementation of some methods for exprGroup
6 *
7 * (C) Carnegie-Mellon University, 2006-10.
8 * This file is licensed under the Eclipse Public License (EPL)
9 */
10
11 #include "CouenneExprConst.hpp"
12 #include "CouenneExprVar.hpp"
13 #include "CouenneExprGroup.hpp"
14 #include "CouenneExprClone.hpp"
15 #include "CouenneExprMul.hpp"
16 #include "CouenneDepGraph.hpp"
17 #include "CouenneProblem.hpp"
18
19 #include <cassert>
20
21 using namespace Couenne;
22
23 namespace Couenne {
24 class Domain;
25 }
26
27 // eliminates elements with zero coefficients
cleanZeros(std::vector<std::pair<exprVar *,CouNumber>> & lcoeff)28 void cleanZeros (std::vector <std::pair <exprVar *, CouNumber> > &lcoeff) {
29
30 std::vector <std::pair <exprVar *, CouNumber> >::iterator i = lcoeff.begin ();
31
32 int ind = 0;
33 size_t size = lcoeff.size ();
34
35 while (size-- > 0) {
36 if (i -> second == 0.) { // or equivalently, i -> second == -0.
37 lcoeff.erase (i);
38 i = lcoeff.begin () + ind;
39 } else {
40 ++i;
41 ++ind;
42 }
43 }
44 }
45
46
47
48 /// Generalized (static) constructor: check parameters and return a
49 /// constant, a single variable, or a real exprGroup
genExprGroup(CouNumber c0,std::vector<std::pair<exprVar *,CouNumber>> & lcoeff,expression ** al,int n)50 expression *exprGroup::genExprGroup (CouNumber c0,
51 std::vector <std::pair <exprVar *, CouNumber> > &lcoeff,
52 expression **al,
53 int n) {
54 size_t nl = lcoeff.size ();
55 expression *ret = NULL;
56
57 cleanZeros (lcoeff);
58
59 // a constant
60 if ((n==0) && (nl==0))
61 ret = new exprConst (c0); // a constant auxiliary? FIX!
62
63 else if ((n==0) && (fabs (c0) < COUENNE_EPS) && (nl==1)) { // a linear monomial, cx
64
65 if (fabs (lcoeff[0]. second - 1) < COUENNE_EPS)
66 ret = new exprClone (lcoeff[0]. first);
67 else ret = new exprMul (new exprConst (lcoeff[0]. second), new exprClone (lcoeff[0]. first));
68
69 } else ret = new exprGroup (c0, lcoeff, al, n);
70
71 return ret;
72 }
73
74
75 /// Constructor
exprGroup(CouNumber c0,std::vector<std::pair<exprVar *,CouNumber>> & lcoeff,expression ** al,int n)76 exprGroup::exprGroup (CouNumber c0,
77 std::vector <std::pair <exprVar *, CouNumber> > &lcoeff,
78 expression **al,
79 int n):
80 exprSum (al, n),
81 lcoeff_ (lcoeff),
82 c0_ (c0) {
83
84 cleanZeros (lcoeff_);
85 }
86
87
88 /// copy constructor
exprGroup(const exprGroup & src,Domain * d)89 exprGroup::exprGroup (const exprGroup &src, Domain *d):
90 exprSum (src.clonearglist (d), src.nargs_),
91 c0_ (src.c0_) {
92
93 for (lincoeff::iterator i = src.lcoeff_.begin (); i != src.lcoeff_.end (); ++i)
94
95 lcoeff_ . push_back (std::pair <exprVar *, CouNumber>
96 //(dynamic_cast <exprVar *> (i -> first -> clone (d)), i -> second));
97 (new exprVar (i -> first -> Index (), d), i -> second));
98 }
99
100
101 /// Destructor -- check if there are exprBounds and delete them
~exprGroup()102 exprGroup::~exprGroup () {
103
104 for (lincoeff::iterator i = lcoeff_.begin (); i != lcoeff_.end (); ++i) {
105 enum expr_type code = i -> first -> code ();
106 if ((code == COU_EXPRLBOUND) ||
107 (code == COU_EXPRUBOUND))
108 delete i -> first;
109 }
110 }
111
112
113 /// I/O
print(std::ostream & out,bool descend) const114 void exprGroup::print (std::ostream &out, bool descend) const {
115
116 //if (code () == COU_EXPRGROUP)
117 if (lcoeff_.size () > 0)
118 out << '(';
119
120 bool nzNL = nargs_ && ((nargs_ > 1) ||
121 ((*arglist_) -> Type () != CONST) ||
122 (fabs ((*arglist_) -> Value ()) > COUENNE_EPS));
123
124 if (nzNL)
125 exprSum::print (out, descend);
126
127 if (c0_ > 0.) {if (nzNL) out << '+'; out << c0_;}
128 else if (c0_ < - 0.) out << c0_;
129
130 for (size_t n = lcoeff_.size (), i=0; n--; i++) {
131
132 CouNumber coeff = lcoeff_ [i]. second;
133
134 if (coeff > 0.) { if (i || (c0_ != 0.) || nzNL) out << '+'; if (coeff != 1.) out << coeff << "*";}
135 else if (coeff < - 0.) { out << '-'; if (coeff != -1.) out << -coeff << "*";}
136
137 lcoeff_ [i]. first -> print (out, descend);
138 if (!((i + 1) % MAX_ARG_LINE) && n)
139 out << std::endl;
140 }
141
142 //if (code () == COU_EXPRGROUP)
143 if (lcoeff_.size () > 0)
144 out << ')';
145 }
146
147
148 /// differentiation
differentiate(int index)149 expression *exprGroup::differentiate (int index) {
150
151 expression **arglist = new expression * [nargs_ + 1];
152
153 CouNumber totlin=0;
154
155 for (lincoeff::iterator el = lcoeff_.begin (); el != lcoeff_.end (); ++el)
156 if (el -> first -> Index () == index)
157 totlin += el -> second;
158
159 int nargs = 0;
160
161 if (fabs (totlin) > COUENNE_EPS)
162 arglist [nargs++] = new exprConst (totlin);
163
164 for (int i = 0; i < nargs_; i++)
165 if (arglist_ [i] -> dependsOn (&index, 1))
166 arglist [nargs++] = arglist_ [i] -> differentiate (index);
167
168 if ((nargs == 0) ||
169 ((nargs == 1) && (fabs (totlin) > COUENNE_EPS))) {
170 delete [] arglist;
171 return new exprConst (totlin);
172 }
173 else return new exprSum (arglist, nargs);
174 }
175
176
177 /// get a measure of "how linear" the expression is:
Linearity()178 int exprGroup::Linearity () {
179
180 int
181 nllin = exprSum::Linearity (), // linearity of nonlinear part
182 llin = (lcoeff_.size () == 0) ? // linear part
183 ((fabs (c0_) < COUENNE_EPS) ? ZERO : CONSTANT) :
184 LINEAR;
185
186 return (llin > nllin) ? llin : nllin;
187 }
188
189
190 /// compare affine terms
compare(exprGroup & e)191 int exprGroup::compare (exprGroup &e) {
192
193 // !!! why?
194
195 //int sum = exprSum::compare (e);
196
197 //if (sum != 0)
198 //return sum;
199
200 if (c0_ < e.c0_ - COUENNE_EPS) return -1;
201 if (c0_ > e.c0_ + COUENNE_EPS) return 1;
202
203 if (lcoeff_.size () < e.lcoeff_.size ()) return -1;
204 if (lcoeff_.size () > e.lcoeff_.size ()) return 1;
205
206 for (lincoeff::iterator
207 el1 = lcoeff_.begin (),
208 el2 = e.lcoeff_.begin ();
209 el1 != lcoeff_.end ();
210 ++el1, ++el2) {
211
212 int
213 ind1 = el1 -> first -> Index (),
214 ind2 = el2 -> first -> Index ();
215
216 CouNumber
217 coe1 = el1 -> second,
218 coe2 = el2 -> second;
219
220 if (ind1 < ind2) return -1;
221 if (ind1 > ind2) return 1;
222
223 if (coe1 < coe2 - COUENNE_EPS) return -1;
224 if (coe1 > coe2 + COUENNE_EPS) return 1;
225 }
226
227 return 0;
228 }
229
230
231 /// used in rank-based branching variable choice
232
rank()233 int exprGroup::rank () {
234
235 int maxrank = exprOp::rank ();
236
237 if (maxrank < 0)
238 maxrank = 0;
239
240 for (lincoeff::iterator el = lcoeff_.begin (); el != lcoeff_.end (); ++el) {
241
242 int r = el -> first -> rank ();
243 if (r > maxrank)
244 maxrank = r;
245 }
246
247 return maxrank;
248 }
249
250
251 /// update dependence set with index of this variable
fillDepSet(std::set<DepNode *,compNode> * dep,DepGraph * g)252 void exprGroup::fillDepSet (std::set <DepNode *, compNode> *dep, DepGraph *g) {
253
254 exprOp::fillDepSet (dep, g);
255
256 for (lincoeff::iterator el = lcoeff_.begin (); el != lcoeff_.end (); ++el)
257 dep -> insert (g -> lookup (el -> first -> Index ()));
258 }
259
260
261 /// fill in the set with all indices of variables appearing in the
262 /// expression
DepList(std::set<int> & deplist,enum dig_type type)263 int exprGroup::DepList (std::set <int> &deplist,
264 enum dig_type type) {
265
266 int deps = exprOp::DepList (deplist, type);
267
268 for (lincoeff::iterator el = lcoeff_.begin (); el != lcoeff_.end (); ++el) {
269
270 /*printf ("before [");
271 el -> first -> print ();
272 printf ("]: {");
273 for (std::set <int>::iterator i=deplist.begin (); i != deplist.end(); ++i)
274 printf ("%d ", *i);*/
275
276 deps += el -> first -> DepList (deplist, type);
277
278 /*printf ("}, after: {");
279 for (std::set <int>::iterator i=deplist.begin (); i != deplist.end(); ++i)
280 printf ("%d ", *i);
281 printf ("}\n");*/
282 }
283
284 return deps;
285 }
286
287
288 /// is this linear term integer?
isInteger()289 bool exprGroup::isInteger () {
290
291 if (!(::isInteger (c0_)) ||
292 !(exprOp::isInteger ()))
293 return false;
294
295 for (lincoeff::iterator el = lcoeff_.begin (); el != lcoeff_.end (); ++el) {
296
297 CouNumber coe = el -> second;
298
299 bool
300 intCoe = ::isInteger (coe),
301 intVar = el -> first -> isInteger ();
302
303 if (intCoe && intVar)
304 continue;
305
306 CouNumber
307 lb = el -> first -> lb (),
308 ub = el -> first -> ub ();
309
310 // check var fixed and product is integer
311 if ((fabs (lb - ub) < COUENNE_EPS) &&
312 (::isInteger (lb * coe) ||
313 (intCoe && ::isInteger (lb))))
314 continue;
315
316 return false;
317 }
318
319 return true;
320 }
321
322
323 /// replace variable x with new (aux) w
replace(exprVar * x,exprVar * w)324 void exprGroup::replace (exprVar *x, exprVar *w) {
325
326 exprOp::replace (x, w);
327
328 int
329 xind = x -> Index (),
330 wind = w -> Index ();
331
332 // find occurrences of x and w in vector of variabls
333
334 lincoeff::iterator x_occur = lcoeff_.begin ();
335
336 // Do not assume index vector is sorted in ascending order
337 // w.r.t. (*iterator) -> first () -> Index()
338 while ((x_occur != lcoeff_.end ()) &&
339 (x_occur -> first -> Index () != xind))
340 ++x_occur;
341
342 if (x_occur == lcoeff_ .end ()) // not found, bail out
343 return;
344
345 if (xind == wind)
346 x_occur -> first = w;
347 else { // replacing two variables, not the features of one
348
349 lincoeff::iterator w_occur = lcoeff_.begin ();
350
351 // Do not assume index vector is sorted in ascending order
352 // w.r.t. (*iterator) -> first () -> Index()
353 while ((w_occur != lcoeff_.end ()) &&
354 (w_occur -> first -> Index () != wind))
355 ++w_occur;
356
357 if (w_occur == lcoeff_ . end ()) // not found w, simply substitute
358 x_occur -> first = w;
359 else {
360 if ((w_occur -> second += x_occur -> second) == 0.) { // add coefficients
361 lcoeff_.erase (w_occur); // if they cancel out, delete w as well
362
363 // under Microsoft, x_occur may have been invalidated by removing w_occur from lcoeff_, so we search for it again
364 for( x_occur = lcoeff_.begin (); x_occur -> first -> Index () != xind; ++x_occur )
365 assert(x_occur != lcoeff_ .end ()); // it was found before, so it should be still found
366 }
367 lcoeff_.erase (x_occur); // delete entry of x
368 }
369 }
370 }
371
372
373 /// return l-2 norm of gradient at given point. Not needed for now, as
374 /// we only use it with nonlinear operators
gradientNorm(const double * x)375 CouNumber exprGroup::gradientNorm (const double *x) {
376
377 CouNumber retval = 0;
378
379 for (lincoeff::iterator el = lcoeff_.begin (); el != lcoeff_.end (); ++el)
380 retval += el -> second * el -> second;
381
382 return sqrt (retval);
383 }
384
385
386 /// Redirect variables to proper variable vector
realign(const CouenneProblem * p)387 void exprGroup::realign (const CouenneProblem *p) {
388
389 for (lincoeff::iterator el = lcoeff_.begin (); el != lcoeff_.end (); ++el) {
390
391 exprVar *var = el -> first;
392
393 if (((var -> Type () == VAR) ||
394 (var -> Type () == AUX)) &&
395 (var -> Original () != p -> Var (var -> Index ()))) {
396
397 expression *trash = var;
398 el -> first = p -> Var (var -> Index ());
399 delete trash;
400 }
401 }
402 }
403
404
405 /// simplification
simplify()406 expression *exprGroup::simplify () {
407 exprOp::simplify ();
408 //if (lcoeff_. size () <= 0) // this is just a constant
409 //return new exprConst (c0_);
410 //else
411 return NULL;
412 }
413
414