addEnvelope.cpp
Go to the documentation of this file.
1 /* $Id: addEnvelope.cpp 560 2011-04-17 10:01:15Z stefan $
2  *
3  * File: addEnvelope.cpp
4  * Author: Pietro Belotti, Carnegie Mellon University
5  * Purpose: Add generic envelope to convex function based on function and its derivative
6  *
7  * (C) Carnegie-Mellon University, 2006-10.
8  * This file is licensed under the Eclipse Public License (EPL)
9  */
10 
11 #include "OsiRowCut.hpp"
12 #include "CouennePrecisions.hpp"
13 #include "CouenneTypes.hpp"
14 #include "CouenneCutGenerator.hpp"
15 #include "CouenneFunTriplets.hpp"
16 #include "CouenneProblem.hpp"
17 #include "CouenneExprVar.hpp"
18 #include "CoinFinite.hpp"
19 
20 using namespace Couenne;
21 
22 void CouenneCutGenerator::addEnvelope (OsiCuts &cs, int sign,
23  unary_function f, // function to be linearized
24  unary_function fprime, // derivative of f
25  int w_ind, int x_ind,
27  t_chg_bounds *chg,
28  bool is_global) const {
29 
30  simpletriplet st (f, fprime, fprime); // don't really care about third parameter...
31  addEnvelope (cs, sign, &st, w_ind, x_ind, x, l, u, chg, is_global);
32 }
33 
34 
35 void CouenneCutGenerator::addEnvelope (OsiCuts &cs, int sign,
36  funtriplet *ft,
37  int w_ind, int x_ind,
39  t_chg_bounds *chg,
40  bool is_global) const {
41  CouNumber opp_slope = - ft -> Fp (x);
42 
43  // TODO: remove check of !firstcall_ if point is available already
44 
45  // if bounds are very close, convexify with a single line
46 
47  bool cLeft = !chg || (chg [x_ind].lower() != t_chg_bounds::UNCHANGED) || firstcall_;
48  bool cRight = !chg || (chg [x_ind].upper() != t_chg_bounds::UNCHANGED) || firstcall_;
49 
50  if (fabs (u - l) < COUENNE_EPS) {
51 
52  CouNumber x0 = 0.5 * (u+l), fp0 = ft -> Fp (x0);
53  if (cLeft || cRight)
54  createCut (cs, ft -> F(x0) - fp0 * x0, 0, w_ind, 1., x_ind, - fp0);
55  return;
56  }
57 
58  // Add tangent in any case
59 
60  if (((!firstcall_) || ((x >= l) && (x <= u)))
61  && !CoinIsnan (opp_slope)
62  && (fabs (opp_slope) < COUENNE_INFINITY)) {
63 
64  if (!(problem_ -> Var (x_ind) -> isInteger ()))
65 
66  // normal cut
67  createCut (cs, ft -> F (x) + opp_slope * x, sign, w_ind, 1.,
68  x_ind, opp_slope, -1, 0., is_global);
69 
70  else {
71 
72  // If the independent variable is integer, the envelope cut can
73  // be made tighter: it is the line through
74  //
75  // (x1,y1) = (floor (x), ft -> F (floor (x))) and
76  // (x2,y2) = (ceil (x), ft -> F (ceil (x)))
77  //
78  // therefore the inequality will be
79  //
80  // y + ax >=< b
81  //
82  // where the sign is determined by the variable sign, and since
83  // the line has equation
84  //
85  // x - x1 y - y1
86  // ------- = -------
87  // x2 - x1 y2 - y1
88  //
89  // y1 - y2 y1 - y2
90  // we have that a = ------- and b = y1 + ------- x1
91  // x2 - x1 x2 - x1
92  //
93  // Thanks to Sergey for gently encouraging me to do this :-)
94 
95  CouNumber x1, x2, y1, y2;
96 
97  if ((x1 = floor (x)) < l)
98  x1 = ceil (l - COUENNE_EPS);
99 
100  y1 = ft -> F (x1);
101 
102  x2 = ceil (x);
103 
104  if (fabs (x2-x1) < COUENNE_EPS)
105  x2 += 1.;
106 
107  y2 = ft -> F (x2);
108 
109  if ((x2 > u) ||
110  CoinIsnan (y1) || CoinIsnan (y2) ||
111  !CoinFinite (y1) || !CoinFinite (y2)) // fall back to non-integer cut
112 
113  createCut (cs, ft -> F (x) + opp_slope * x, sign, w_ind, 1.,
114  x_ind, opp_slope, -1, 0., is_global);
115 
116  else {
117 
118  CouNumber
119  slope = (y1-y2) / (x2-x1),
120  rhs = y1 + slope * x1;
121 
122  createCut (cs, rhs, sign, w_ind, 1.,
123  x_ind, slope, -1, 0., is_global);
124  }
125 
126  // TODO: if the DEPENDENT variable is integer also, in principle
127  // the cut can be made tighter, but not as simply.
128 
129  }
130  }
131 
132  // If this is the first call, add a set of cuts by dividing the
133  // interval in a grid and add a cut at each point of the grid
134 
135  if ((convtype_ == UNIFORM_GRID) || firstcall_) {
136 
137  if (cLeft || cRight) {
138  // now add tangent at each sampling point
139 
140  CouNumber
141  sample = l,
142  step = (u-l) / nSamples_;
143 
144  // printf ("[%.4f %.4f], step = %.4f, %d samples\n",
145  // l, u, step, nSamples_);
146 
147  for (int i = 0; i <= nSamples_; i++) {
148 
149  opp_slope = - ft -> Fp (sample);
150 
151  if ((fabs (opp_slope) < COUENNE_INFINITY) &&
152  (fabs (sample-x) > COUENNE_EPS)) { // do not add twice cut at current point
153 
154 
155  // same as above, check integrality of argument
156 
157  if (!(problem_ -> Var (x_ind) -> isInteger ()))
158 
159  createCut (cs, ft -> F (sample) + opp_slope * sample, sign,
160  w_ind, 1.,
161  x_ind, opp_slope,
162  -1, 0., is_global);
163  else {
164 
165  CouNumber x1, x2, y1, y2;
166 
167  if ((x1 = floor (sample)) < l)
168  x1 = ceil (l - COUENNE_EPS);
169 
170  y1 = ft -> F (x1);
171 
172  x2 = ceil (sample);
173 
174  if (fabs (x2-x1) < COUENNE_EPS)
175  x2 += 1.;
176 
177  y2 = ft -> F (x2);
178 
179  if ((x2 > u) ||
180  CoinIsnan (y1) || CoinIsnan (y2) ||
181  !CoinFinite (y1) || !CoinFinite (y2)) // fall back to non-integer cut
182 
183  createCut (cs, ft -> F (sample) + opp_slope * sample, sign, w_ind, 1.,
184  x_ind, opp_slope, -1, 0., is_global);
185  }
186  }
187 
188  // printf (" Uniform %d: ", i); cut -> print ();
189 
190  sample += step;
191  }
192  }
193  }
194  else if (convtype_ != CURRENT_ONLY) {
195 
196  CouNumber sample = x;
197 
198  if (fabs (opp_slope) < COUENNE_INFINITY)
199  createCut (cs, ft -> F (x) + opp_slope * x, sign,
200  w_ind, 1.,
201  x_ind, opp_slope,
202  -1, 0.,
203  is_global);
204  // printf (" Current tangent: "); cut -> print ();
205 
206  for (int i = 0; i <= nSamples_/2; i++) {
207 
208  sample += (x-l) / nSamples_;
209  opp_slope = - ft -> Fp (sample);
210 
211  if (fabs (opp_slope) < COUENNE_INFINITY)
212  createCut (cs, ft -> F (sample) + opp_slope * sample, sign,
213  w_ind, 1.,
214  x_ind, opp_slope,
215  -1, 0.,
216  is_global);
217  // printf (" neighbour -%d: ", i); cut -> print ();
218  }
219 
220  sample = x;
221 
222  for (int i = 0; i <= nSamples_/2; i++) {
223 
224  sample += (u-x) / nSamples_;
225  opp_slope = - ft -> Fp (sample);
226 
227  createCut (cs, ft -> F(sample) + opp_slope * sample, sign,
228  w_ind, 1.,
229  x_ind, opp_slope,
230  -1, 0.,
231  is_global);
232  // printf (" neighbour %d: ", i); cut -> print ();
233  }
234  }
235 }
bool firstcall_
True if no convexification cuts have been generated yet for this problem.
ULong x2
Definition: OSdtoa.cpp:1776
status of lower/upper bound of a variable, to be checked/modified in bound tightening ...
const char & lower() const
const char & upper() const
enum conv_type convtype_
what kind of sampling should be performed?
void addEnvelope(OsiCuts &, int, unary_function, unary_function, int, int, CouNumber, CouNumber, CouNumber, t_chg_bounds *=NULL, bool=false) const
Add general linear envelope to convex function, given its variables&#39; indices, the (univariate) functi...
Definition: addEnvelope.cpp:22
void fint fint fint real fint real real real real * f
ULong * x0
Definition: OSdtoa.cpp:1776
ULong x1
Definition: OSdtoa.cpp:1776
CouNumber(* unary_function)(CouNumber)
unary function, used in all exprUnary
int createCut(OsiCuts &, CouNumber, CouNumber, int, CouNumber, int=-1, CouNumber=0., int=-1, CouNumber=0., bool=false) const
create cut and check violation. Insert and return status
Definition: createCuts.cpp:32
#define COUENNE_EPS
double CouNumber
main number type in Couenne
#define COUENNE_INFINITY
CouenneProblem * problem_
pointer to symbolic repr. of constraint, variables, and bounds
int nSamples_
how many cuts should be added for each function?
void fint fint fint real fint real * x
bool isInteger(CouNumber x)
is this number integer?