-
Notifications
You must be signed in to change notification settings - Fork 0
/
revmccormick.hpp
456 lines (363 loc) · 15.2 KB
/
revmccormick.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
#ifndef MC__REVMCCORMICK_H
#define MC__REVMCCORMICK_H
#include <vector>
#include <iostream>
#include <iomanip>
#include <stdarg.h>
#include <cassert>
#include <string>
namespace mc
{
//! @brief C++ class for RevMcCormick relaxation arithmetic for factorable function
////////////////////////////////////////////////////////////////////////
//! mc::RevMcCormick is a C++ class computing the McCormick
//! convex/concave relaxations of factorable functions on a box,
//! as well as doing reverse subgradient propagation. The template parameter
//! corresponds to the type used in the underlying interval arithmetic
//! computations.
////////////////////////////////////////////////////////////////////////
template <typename T>
class RevMcCormick
{
template <typename U> friend class RevMcCormick;
//! @brief +
template <typename U> friend RevMcCormick<U> operator+
(const RevMcCormick<U>&, const RevMcCormick<U>&);
//! @brief *
template <typename U> friend RevMcCormick<U> operator*
(const RevMcCormick<U>&, const RevMcCormick<U>&);
//template <typename U> friend RevMcCormick<U> operator*
//(const RevMcCormick<U>&, const double*);
template <typename U> friend RevMcCormick<U> operator*
(const RevMcCormick<U>&, const U&);
//! @brief output
template <typename U> friend std::ostream& operator<<
(std::ostream&, const RevMcCormick<U>&);
public:
//! @brief =
RevMcCormick<T>& operator=
(const RevMcCormick<T>& );
/** @defgroup MCCORMICK McCormick Relaxation Arithmetic for Factorable Functions
* @{
*/
//! @brief Options of mc::RevMcCormick
static struct Options
{
//! @brief Constructor
Options() :
DISPLAY_DIGITS(5)
{}
//! @brief Number of digits displayed with << operator (default=5)
unsigned int DISPLAY_DIGITS;
} options;
//! @brief Exceptions of mc::McCormick
class Exceptions
{
public:
//! @brief Enumeration type for McCormick exception handling
enum TYPE {
DIV = 1, //!< Division by zero
INV, //!< Inverse with zero in range
LOG, //!< Log with negative values in range
SQRT, //!< Square-root with nonpositive values in range
ASIN, //!< Inverse sine or cosine with values outside of \f$[-1,1]\f$ range
TAN, //!< Tangent with values outside of \f$[-\frac{\pi}{2}+k\pi,\frac{\pi}{2}+k\pi]\f$ range
CHEB, //!< Chebyshev basis function different from [-1,1] range
MULTSUB = -3, //!< Failed to propagate subgradients for a product term with Tsoukalas & Mitsos's multivariable composition result
ENVEL, //!< Failed to compute the convex or concave envelope of a univariate term
SUB //!< Inconsistent subgradient dimension between two mc::McCormick variables
};
//! @brief Constructor for error <a>ierr</a>
Exceptions(TYPE ierr) : _ierr(ierr) {}
//! @brief Inline function returning the error flag
int ierr() { return _ierr; }
//! @brief Return error description
std::string what() {
switch (_ierr) {
case DIV:
return "mc::RevMcCormick\t Division by zero";
case INV:
return "mc::RevMcCormick\t Inverse with zero in range";
case LOG:
return "mc::RevMcCormick\t Log with negative values in range";
case SQRT:
return "mc::RevMcCormick\t Square-root with nonpositive values in range";
case ASIN:
return "mc::RevMcCormick\t Inverse sine with values outside of [-1,1] range";
case TAN:
return "mc::RevMcCormick\t Tangent with values pi/2+k*pi in range";
case CHEB:
return "mc::RevMcCormick\t Chebyshev basis outside of [-1,1] range";
case MULTSUB:
return "mc::RevMcCormick\t Subgradient propagation failed";
case ENVEL:
return "mc::RevMcCormick\t Convex/concave envelope computation failed";
case SUB:
return "mc::RevMcCormick\t Inconsistent subgradient dimension";
}
return "mc::RevMcCormick\t Undocumented error";
}
private:
TYPE _ierr;
};
//! @brief Default constructor (needed to declare arrays of McCormick class)
RevMcCormick() :
_nsubbar(0), _cvsubbar(0), _ccsubbar(0)
{
}
//! @brief Constructor for a constant value <a>c</a>
RevMcCormick
(const double c) :
_nsubbar(0), _cvsubbar(0), _ccsubbar(0)
{
_MC = Op<T>::MC(c);
}
//! @brief Constructor for an McCmormick MC
RevMcCormick
(const T& MC) :
_nsubbar(0), _cvsubbar(0), _ccsubbar(0)
{
_MC = Op<T>::I1(_MC, MC);
}
//! @brief Number of reverse version of subgradient components/directions
unsigned int nsubbar() const
{
return _nsubbar;
}
//! @brief Number of subgradient components/directions
unsigned int nsub() const
{
return Op<T>::nsub(_MC);
}
//! @brief McCormick relaxations
T& MC()
{
return _MC;
}
const T& MC() const
{
return _MC;
}
//! @brief Lower bound
double l() const
{
return Op<T>::l(_MC);
}
//! @brief Upper bound
double u() const
{
return Op<T>::u(_MC);
}
//! @brief Convex bound
double cv() const
{
return Op<T>::cv(_MC);
}
//! @brief Concave bound
double cc() const
{
return Op<T>::cc(_MC);
}
//! @brief <a>i</a>th component of a subgradient of convex underestimator
double cvsub
(const unsigned int i) const
{
return Op<T>::cvsub(_MC, i);
}
//! @brief <a>i</a>th component of a subgradient of concave overestimator
double ccsub
(const unsigned int i) const
{
return Op<T>::ccsub(_MC, i);
}
//! @brief <a>i</a>th component of a reverse subgradient of convex underestimator
double cvsubbar
(const unsigned int i) const
{
return _cvsubbar[i];
}
//! @brief <a>i</a>th component of a reverse subgradient of concave overestimator
double ccsubbar
(const unsigned int i) const
{
return _ccsubbar[i];
}
//! @brief Set dimension of subgradient to <a>nsub</a>
RevMcCormick<T>& subbar
(const unsigned int nsubbar);
//! @brief Set dimension of subgradient to <a>nsub</a> and subgradient values for the convex and concave relaxations to <a>cvsub</a> and <a>ccsub</a>
RevMcCormick<T>& subbar
( const unsigned int nsubbar, const double*cvsubbar, const double*ccsubbar);
//! @brief Set dimension of subgradient to <a>nsub</a> and subgradient values
//! for the convex and concave relaxations to <a>cvsub</a> and <a>ccsub</a>
void sub
(const unsigned int nsub, const double cvsub[], const double ccsub[])
{
Op<T>::Sub(_MC, nsub, cvsub, ccsub);
}
private:
//! @brief Number of subgradient components
unsigned int _nsubbar;
//! @brief McCormick
T _MC;
//! @brief Reverse subgradient of convex underestimator
double *_cvsubbar;
//std::vector<double> _cvsubbar;
//! @brief Reverse subgradient of concave overestimator
//std::vector<double> _ccsubbar;
double *_ccsubbar;
//! @brief Copy subgradient arrays
void _subbar_copy(const RevMcCormick<T>& RevMC);
//! @brief Initialize subgradient arrays
void _subbar(const unsigned int nsubbar);
void _subbar_resize( const unsigned int nsubbar);
RevMcCormick<T>& _sum( const RevMcCormick<T>&RevMC1, const RevMcCormick<T>&RevMC2 );
RevMcCormick<T>& _mul1( const RevMcCormick<T>&RevMC1, const RevMcCormick<T>&RevMC2 );
//RevMcCormick<T>& _mul2( const RevMcCormick<T>&RevMC1, const double* tempsub);
};
////////////////////////////////////////////////////////////////////////
template <typename T> inline void
RevMcCormick<T>::_subbar_copy
(const RevMcCormick<T>& RevMC)
{
_subbar_resize( RevMC._nsubbar);
for ( unsigned int i=0; i<_nsubbar; i++ ){
_cvsubbar[i] = RevMC._cvsubbar[i];
_ccsubbar[i] = RevMC._ccsubbar[i];
}
return;
}
template <typename T> inline void
RevMcCormick<T>::_subbar_resize
( const unsigned int nsubbar )
{
_nsubbar = nsubbar;
_cvsubbar = new double[_nsubbar];
_ccsubbar = new double[_nsubbar];
}
template <typename T> inline void
RevMcCormick<T>::_subbar
(const unsigned int nsubbar)
{
_subbar_resize( nsubbar );
for ( unsigned int i=0; i<nsubbar; i++ ){
_cvsubbar[i] = _ccsubbar[i] = 0.;
}
}
template <typename T> inline RevMcCormick<T>&
RevMcCormick<T>::subbar
( const unsigned int nsubbar)
{
_subbar(nsubbar);
return *this;
}
template <typename T> inline RevMcCormick<T>&
RevMcCormick<T>::subbar
( const unsigned int nsubbar, const double*cvsubbar, const double*ccsubbar)
{
subbar( nsubbar );
for ( unsigned int i=0; i<nsubbar; i++ ){
_cvsubbar[i] = cvsubbar[i];
_ccsubbar[i] = ccsubbar[i];
}
return *this;
}
////////////////////////////////////////////////////////////////////////
template <typename T> inline RevMcCormick<T>&
RevMcCormick<T>::operator=
(const RevMcCormick<T>& RevMC)
{
_MC = RevMC._MC;
_subbar_copy(RevMC);
return *this;
}
template <typename T> inline RevMcCormick<T>&
RevMcCormick<T>::_sum
( const RevMcCormick<T>&RevMC1, const RevMcCormick<T>&RevMC2 )
{
//_MC = RevMC1._MC;
for (unsigned int i = 0; i < _nsubbar; i++) {
_cvsubbar[i] = RevMC1._cvsubbar[i] + RevMC2._cvsubbar[i];
_ccsubbar[i] = RevMC1._ccsubbar[i] + RevMC2._ccsubbar[i];
}
return *this;
}
template <typename T> inline RevMcCormick<T>&
RevMcCormick<T>::_mul1
( const RevMcCormick<T>&RevMC1, const RevMcCormick<T>&RevMC2 )
{
_cvsubbar[0] = RevMC1._cvsubbar[0] * RevMC2.cvsub(0)
+ RevMC1._cvsubbar[1] * RevMC2.ccsub(0);
_cvsubbar[1] = RevMC1._cvsubbar[1] * RevMC2.ccsub(1)
+ RevMC1._cvsubbar[0] * RevMC2.cvsub(1);
_ccsubbar[0] = RevMC1._ccsubbar[0] * RevMC2.cvsub(0)
+ RevMC1._ccsubbar[1] * RevMC2.ccsub(0);
_ccsubbar[1] = RevMC1._ccsubbar[1] * RevMC2.ccsub(1)
+ RevMC1._ccsubbar[0] * RevMC2.cvsub(1);
return *this;
}
template <typename T> inline RevMcCormick<T>
operator+
(const RevMcCormick<T>& RevMC1, const RevMcCormick<T>& RevMC2)
{
RevMcCormick<T> RevMC3;
RevMC3._subbar(RevMC1._nsubbar);
return RevMC3._sum(RevMC1,RevMC2);
}
template <typename T> inline RevMcCormick<T>
operator*
( const RevMcCormick<T>& RevMC1, const RevMcCormick<T>& RevMC2)
{
RevMcCormick<T> RevMC3;
RevMC3._subbar(RevMC1._nsubbar);
return RevMC3._mul1(RevMC1, RevMC2);
}
template <typename T> inline RevMcCormick<T>
operator*
( const RevMcCormick<T>& RevMC1, const T& MC1)
{
RevMcCormick<T> RevMC3;
RevMC3._subbar(RevMC1._nsubbar);
RevMC3._cvsubbar[0] = RevMC1._cvsubbar[0] * MC1.cvsub(0)
+ RevMC1._cvsubbar[1] * MC1.ccsub(0);
RevMC3._cvsubbar[1] = RevMC1._cvsubbar[1] * MC1.ccsub(1)
+ RevMC1._cvsubbar[0] * MC1.cvsub(1);
RevMC3._ccsubbar[0] = RevMC1._ccsubbar[0] * MC1.cvsub(0)
+ RevMC1._ccsubbar[1] * MC1.ccsub(0);
RevMC3._ccsubbar[1] = RevMC1._ccsubbar[1] * MC1.ccsub(1)
+ RevMC1._ccsubbar[0] * MC1.cvsub(1);
return RevMC3;
}
////////////////////////////////////////////////////////////////////////
template <typename T> inline std::ostream&
operator<<
(std::ostream& out, const RevMcCormick<T>& RevMC)
{
out << std::scientific << std::setprecision(RevMcCormick<T>::options.DISPLAY_DIGITS) << std::right
<< "[ " << std::setw(RevMcCormick<T>::options.DISPLAY_DIGITS + 7) << RevMC.l() << " : "
<< std::setw(RevMcCormick<T>::options.DISPLAY_DIGITS + 7) << RevMC.u()
<< " ] [ " << std::setw(RevMcCormick<T>::options.DISPLAY_DIGITS + 7) << RevMC.cv() << " : "
<< std::setw(RevMcCormick<T>::options.DISPLAY_DIGITS + 7) << RevMC.cc() << " ]";
if (RevMC.nsub()) {
out << " [ (";
for (unsigned int i = 0; i < RevMC.nsub() - 1; i++)
out << std::setw(RevMcCormick<T>::options.DISPLAY_DIGITS + 7) << RevMC.cvsub(i) << ",";
out << std::setw(RevMcCormick<T>::options.DISPLAY_DIGITS + 7) << RevMC.cvsub(RevMC.nsub() - 1) << ") : (";
for (unsigned int i = 0; i < RevMC.nsub() - 1; i++)
out << std::setw(RevMcCormick<T>::options.DISPLAY_DIGITS + 7) << RevMC.ccsub(i) << ",";
out << std::setw(RevMcCormick<T>::options.DISPLAY_DIGITS + 7) << RevMC.ccsub(RevMC.nsub() - 1) << ") ]";
}
if (RevMC.nsubbar()) {
out << " [ (";
for (unsigned int i = 0; i < RevMC.nsubbar() - 1; i++)
out << std::setw(RevMcCormick<T>::options.DISPLAY_DIGITS + 7) << RevMC.cvsubbar(i) << ",";
out << std::setw(RevMcCormick<T>::options.DISPLAY_DIGITS + 7) << RevMC.cvsubbar(RevMC.nsubbar() - 1) << ") : (";
for (unsigned int i = 0; i < RevMC.nsubbar() - 1; i++)
out << std::setw(RevMcCormick<T>::options.DISPLAY_DIGITS + 7) << RevMC.ccsubbar(i) << ",";
out << std::setw(RevMcCormick<T>::options.DISPLAY_DIGITS + 7) << RevMC.ccsubbar(RevMC.nsubbar() - 1) << ") ]";
}
return out;
}
template <typename T> typename RevMcCormick<T>::Options RevMcCormick<T>::options;
} // namespace mc
#endif