SCIP Doxygen Documentation
Loading...
Searching...
No Matches
expr_trig.c
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2/* */
3/* This file is part of the program and library */
4/* SCIP --- Solving Constraint Integer Programs */
5/* */
6/* Copyright (c) 2002-2026 Zuse Institute Berlin (ZIB) */
7/* */
8/* Licensed under the Apache License, Version 2.0 (the "License"); */
9/* you may not use this file except in compliance with the License. */
10/* You may obtain a copy of the License at */
11/* */
12/* http://www.apache.org/licenses/LICENSE-2.0 */
13/* */
14/* Unless required by applicable law or agreed to in writing, software */
15/* distributed under the License is distributed on an "AS IS" BASIS, */
16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17/* See the License for the specific language governing permissions and */
18/* limitations under the License. */
19/* */
20/* You should have received a copy of the Apache-2.0 license */
21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
22/* */
23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24
25/**@file expr_trig.c
26 * @ingroup DEFPLUGINS_EXPR
27 * @brief handler for sine and cosine expressions
28 * @author Fabian Wegscheider
29 *
30 * The estimator/separator code always computes underestimators for sin(x).
31 * For overestimators of cos(x), we first reduce to underestimators of sin(x).
32 *
33 * Overestimator for sin(x):
34 * Assume that a*y+b <= sin(y) for y in [-ub,-lb].
35 * Then we have a*(-y)-b >= -sin(y) = sin(-y) for y in [-ub,-lb].
36 * Thus, a*x-b >= sin(x) for x in [lb,ub].
37 *
38 * Underestimator for cos(x):
39 * Assume that a*y+b <= sin(y) for y in [lb+pi/2,ub+pi/2].
40 * Then we have a*(x+pi/2) + b <= sin(x+pi/2) = cos(x) for x in [lb,ub].
41 * Thus, a*x + (b+a*pi/2) <= cos(x) for x in [lb,ub].
42 *
43 * Overestimator for cos(x):
44 * Assume that a*z+b <= sin(z) for z in [-(ub+pi/2),-(lb+pi/2)].
45 * Then, a*y-b >= sin(y) for y in [lb+pi/2,ub+pi/2].
46 * Then, a*x-b+a*pi/2 >= cos(x) for x in [lb,ub].
47 */
48
49/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
50
51#define _USE_MATH_DEFINES /* to get M_PI on Windows */ /*lint !750 */
52
53#include <math.h>
54#include "scip/expr_trig.h"
55#include "scip/expr_value.h"
56
57/* fundamental expression handler properties */
58#define SINEXPRHDLR_NAME "sin"
59#define SINEXPRHDLR_DESC "sine expression"
60#define SINEXPRHDLR_PRECEDENCE 91000
61#define SINEXPRHDLR_HASHKEY SCIPcalcFibHash(82457.0)
62
63#define COSEXPRHDLR_NAME "cos"
64#define COSEXPRHDLR_DESC "cosine expression"
65#define COSEXPRHDLR_PRECEDENCE 92000
66#define COSEXPRHDLR_HASHKEY SCIPcalcFibHash(82463.0)
67
68#define MAXCHILDABSVAL 1e+6 /**< maximum absolute value that is accepted for propagation */
69#define NEWTON_NITERATIONS 100
70#define NEWTON_PRECISION 1e-12
71
72/*
73 * Local methods
74 */
75
76/** evaluates the function a*x + b - sin(x) for some coefficient a and constant b at a given point p
77 *
78 * the constants a and b are expected to be stored in that order in params
79 */
80static
82{ /*lint --e{715}*/
83 assert(params != NULL);
84 assert(nparams == 2);
85
86 return params[0]*point + params[1] - sin(point);
87}
88
89/** evaluates the derivative of a*x + b - sin(x) for some coefficient a and constant b at a given point p
90 *
91 * the constants a and b are expected to be stored in that order in params
92 */
93static
95{ /*lint --e{715}*/
96 assert(params != NULL);
97 assert(nparams == 2);
98
99 return params[0] - cos(point);
100}
101
102/** evaluates the function sin(x) + (alpha - x)*cos(x) - sin(alpha) for some constant alpha at a given point p
103 *
104 * the constant alpha is expected to be stored in params
105 */
106static
108{ /*lint --e{715}*/
109 assert(params != NULL);
110 assert(nparams == 1);
111
112 return sin(point) + (params[0] - point) * cos(point) - sin(params[0]);
113}
114
115/** evaluates the derivative of sin(x) + (alpha - x)*cos(x) - sin(alpha) for some constant alpha at a given point p
116 *
117 * the constant alpha is expected to be stored in params
118 */
119static
121{ /*lint --e{715}*/
122 assert(params != NULL);
123 assert(nparams == 1);
124
125 return (point - params[0]) * sin(point);
126}
127
128/** helper function to compute the secant if it is a valid underestimator
129 *
130 * returns true if the estimator was computed successfully
131 */
132static
134 SCIP* scip, /**< SCIP data structure */
135 SCIP_Real* lincoef, /**< buffer to store linear coefficient of secant */
136 SCIP_Real* linconst, /**< buffer to store linear constant of secant */
137 SCIP_Real lb, /**< lower bound of argument variable */
138 SCIP_Real ub /**< upper bound of argument variable */
139 )
140{
141 assert(scip != NULL);
142 assert(lincoef != NULL);
143 assert(linconst != NULL);
144 assert(lb < ub);
145
146 /* if range is too big, secant is not underestimating */
147 if( ub - lb >= M_PI )
148 return FALSE;
149
150 /* if bounds are not within positive bay, secant is not underestimating */
151 if( sin(lb) < 0.0 || sin(ub) < 0.0 || (sin(lb) == 0.0 && cos(lb) < 0.0) )
152 return FALSE;
153
154 *lincoef = (sin(ub) - sin(lb)) / (ub - lb);
155 *linconst = sin(ub) - (*lincoef) * ub;
156
157 return TRUE;
158}
159
160/** helper function to compute the tangent at lower bound if it is underestimating
161 *
162 * returns true if the underestimator was computed successfully
163 */
164static
166 SCIP* scip, /**< SCIP data structure */
167 SCIP_Real* lincoef, /**< buffer to store linear coefficient of tangent */
168 SCIP_Real* linconst, /**< buffer to store linear constant of tangent */
169 SCIP_Real lb /**< lower bound of argument variable */
170 )
171{
172 assert(scip != NULL);
173 assert(lincoef != NULL);
174 assert(linconst != NULL);
175
176 if( SCIPisInfinity(scip, -lb) )
177 return FALSE;
178
179 /* left tangent is only underestimating in [pi, 1.5*pi) *2kpi */
180 if( sin(lb) > 0.0 || cos(lb) >= 0.0 )
181 return FALSE;
182
183 *lincoef = cos(lb);
184 *linconst = sin(lb) - (*lincoef) * lb;
185
186 return TRUE;
187}
188
189/* TODO: fix this, more cases can be considered, see at unit test
190 * the underestimating of the tangents depends not only on the ub but also on the lower bound.
191 * right now, this function is only checking whether the tangent underestimates independently of the lower bound!
192 */
193/** helper function to compute the tangent at upper bound if it is an underestimator
194 *
195 * returns true if the underestimator was computed successfully
196 */
197static
199 SCIP* scip, /**< SCIP data structure */
200 SCIP_Real* lincoef, /**< buffer to store linear coefficient of tangent */
201 SCIP_Real* linconst, /**< buffer to store linear constant of tangent */
202 SCIP_Real ub /**< upper bound of argument variable */
203 )
204{
205 assert(scip != NULL);
206 assert(lincoef != NULL);
207 assert(linconst != NULL);
208
209 if( SCIPisInfinity(scip, ub) )
210 return FALSE;
211
212 /* right tangent is only underestimating in (1.5*pi, 2*pi] *2kpi */
213 if( sin(ub) > 0.0 || cos(ub) <= 0.0 )
214 return FALSE;
215
216 *lincoef = cos(ub);
217 *linconst = sin(ub) - (*lincoef) * ub;
218
219 return TRUE;
220}
221
222/** helper function to compute the tangent at solution point if it is an underestimator
223 *
224 * returns true if the underestimator was computed successfully
225 */
226static
228 SCIP* scip, /**< SCIP data structure */
229 SCIP_Real* lincoef, /**< buffer to store linear coefficient of tangent */
230 SCIP_Real* linconst, /**< buffer to store linear constant of tangent */
231 SCIP_Real lb, /**< lower bound of argument variable */
232 SCIP_Real ub, /**< upper bound of argument variable */
233 SCIP_Real solpoint /**< solution point to be separated */
234 )
235{
236 SCIP_Real params[2];
237 SCIP_Real startingpoints[3];
238 SCIP_Real solpointmodpi;
239 SCIP_Real intersection;
240 int i;
241
242 assert(scip != NULL);
243 assert(lincoef != NULL);
244 assert(linconst != NULL);
245
246 /* tangent is only underestimating in negative bay */
247 if( sin(solpoint) > 0.0 )
248 return FALSE;
249
250 /* compute solution point mod pi */
251 solpointmodpi = fmod(solpoint, M_PI);
252 if( solpoint < 0.0 )
253 solpointmodpi += M_PI;
254
255 /* if the point is too far away from the bounds or is at a multiple of pi, then tangent is not underestimating */
256 if( SCIPisGE(scip, solpoint - lb, 2*M_PI) || SCIPisGE(scip, ub - solpoint, 2*M_PI)
257 || SCIPisZero(scip, solpointmodpi) )
258 return FALSE;
259
260 params[0] = cos(solpoint);
261 params[1] = sin(solpoint) - params[0] * solpoint;
262
263 /* choose starting points for Newton procedure */
264 if( SCIPisGT(scip, solpointmodpi, M_PI_2) )
265 {
266 startingpoints[0] = solpoint + (M_PI - solpointmodpi) + M_PI_2;
267 startingpoints[1] = startingpoints[0] + M_PI_2;
268 startingpoints[2] = startingpoints[1] + M_PI_2;
269 }
270 else
271 {
272 startingpoints[0] = solpoint - solpointmodpi - M_PI_2;
273 startingpoints[1] = startingpoints[0] - M_PI_2;
274 startingpoints[2] = startingpoints[1] - M_PI_2;
275 }
276
277 /* use Newton procedure to test if cut is valid */
278 for( i = 0; i < 3; ++i )
279 {
280 intersection = SCIPcalcRootNewton(function1, derivative1, params, 2, startingpoints[i], NEWTON_PRECISION,
282
283 if( intersection != SCIP_INVALID && !SCIPisEQ(scip, intersection, solpoint) ) /*lint !e777*/
284 break;
285 }
286
287 /* if Newton failed or intersection point lies within bounds, underestimator is not valid */
288 if( intersection == SCIP_INVALID || (intersection >= lb && intersection <= ub) ) /*lint !e777*/
289 return FALSE;
290
291 *lincoef = params[0];
292 *linconst = params[1];
293
294 return TRUE;
295}
296
297/** helper function to compute the secant between lower bound and some point of the graph such that it underestimates
298 *
299 * returns true if the underestimator was computed successfully
300 */
301static
303 SCIP* scip, /**< SCIP data structure */
304 SCIP_Real* lincoef, /**< buffer to store linear coefficient of tangent */
305 SCIP_Real* linconst, /**< buffer to store linear constant of tangent */
306 SCIP_Real lb, /**< lower bound of argument variable */
307 SCIP_Real ub /**< upper bound of argument variable */
308 )
309{
310 SCIP_Real lbmodpi;
311 SCIP_Real tangentpoint;
312 SCIP_Real startingpoint;
313
314 assert(scip != NULL);
315 assert(lincoef != NULL);
316 assert(linconst != NULL);
317 assert(lb < ub);
318
319 if( SCIPisInfinity(scip, -lb) )
320 return FALSE;
321
322 /* compute shifted bounds for case evaluation */
323 lbmodpi = fmod(lb, M_PI);
324 if( lb < 0.0 )
325 lbmodpi += M_PI;
326
327 /* choose starting point for Newton procedure */
328 if( cos(lb) < 0.0 )
329 {
330 /* in [pi/2,pi] underestimating doesn't work; otherwise, take the midpoint of possible area */
331 if( SCIPisLE(scip, sin(lb), 0.0) )
332 return FALSE;
333 else
334 startingpoint = lb + 1.25*M_PI - lbmodpi;
335 }
336 else
337 {
338 /* in ascending area, take the midpoint of the possible area in descending part */
339 /* for lb < 0 but close to zero, we may have sin(lb) = 0 but lbmodpi = pi, which gives a starting point too close to lb
340 * but for sin(lb) around 0 we know that the tangent point needs to be in [lb+pi,lb+pi+pi/2]
341 */
342 if( SCIPisZero(scip, sin(lb)) )
343 startingpoint = lb + 1.25*M_PI;
344 else if( sin(lb) < 0.0 )
345 startingpoint = lb + 2.25*M_PI - lbmodpi;
346 else
347 startingpoint = lb + 1.25*M_PI - lbmodpi;
348 }
349
350 /* use Newton procedure to find the point where the tangent intersects sine at lower bound */
351 tangentpoint = SCIPcalcRootNewton(function2, derivative2, &lb, 1, startingpoint, NEWTON_PRECISION,
353
354 /* if Newton procedure failed, no cut is added */
355 if( tangentpoint == SCIP_INVALID ) /*lint !e777*/
356 return FALSE;
357
358 /* if the computed point lies outside the bounds, it is shifted to upper bound */
359 if( SCIPisGE(scip, tangentpoint, ub) )
360 {
361 tangentpoint = ub;
362
363 /* check whether affine function is still underestimating */
364 if( SCIPisLE(scip, sin(0.5 * (ub + lb)), sin(lb) + 0.5*(sin(ub) - sin(lb))) )
365 return FALSE;
366 }
367
368 if( SCIPisEQ(scip, tangentpoint, lb) ) /*lint !e777 */
369 return FALSE;
370
371 /* compute secant between lower bound and connection point */
372 *lincoef = (sin(tangentpoint) - sin(lb)) / (tangentpoint - lb);
373 *linconst = sin(lb) - (*lincoef) * lb;
374
375 /* if the bounds are too close to each other, it's possible that the underestimator is not valid */
376 if( *lincoef >= cos(lb) )
377 return FALSE;
378
379 SCIPdebugMsg(scip, "left secant: %g + %g*x <= sin(x) on [%g,%g]\n", *linconst, *lincoef, lb, ub);
380
381 return TRUE;
382}
383
384/** helper function to compute the secant between upper bound and some point of the graph such that it underestimates
385 *
386 * returns true if the underestimator was computed successfully
387 */
388static
390 SCIP* scip, /**< SCIP data structure */
391 SCIP_Real* lincoef, /**< buffer to store linear coefficient of tangent */
392 SCIP_Real* linconst, /**< buffer to store linear constant of tangent */
393 SCIP_Real lb, /**< lower bound of argument variable */
394 SCIP_Real ub /**< upper bound of argument variable */
395 )
396{
397 SCIP_Real ubmodpi;
398 SCIP_Real tangentpoint;
399 SCIP_Real startingpoint;
400
401 assert(scip != NULL);
402 assert(lincoef != NULL);
403 assert(linconst != NULL);
404 assert(lb < ub);
405
406 if( SCIPisInfinity(scip, ub) )
407 return FALSE;
408
409 /* compute shifted bounds for case evaluation */
410 ubmodpi = fmod(ub, M_PI);
411 if( ub < 0.0 )
412 ubmodpi += M_PI;
413
414 /* choose starting point for Newton procedure */
415 if( cos(ub) > 0.0 )
416 {
417 /* in [3*pi/2,2*pi] underestimating doesn't work; otherwise, take the midpoint of possible area */
418 if( SCIPisLE(scip, sin(ub), 0.0) )
419 return FALSE;
420 else
421 startingpoint = ub - M_PI_4 - ubmodpi;
422 }
423 else
424 {
425 /* in descending area, take the midpoint of the possible area in ascending part */
426 /* for ub < 0 but close to zero, we may have sin(ub) = 0 but ubmodpi = pi, which gives a starting point too close to ub
427 * but for sin(ub) around 0 we know that the tangent point needs to be in [ub-(pi+pi/2),ub-pi]
428 */
429 if( SCIPisZero(scip, sin(ub)) )
430 startingpoint = ub - 1.25*M_PI;
431 else if( sin(ub) < 0.0 )
432 startingpoint = ub - 1.25*M_PI - ubmodpi;
433 else
434 startingpoint = ub - M_PI_4 - ubmodpi;
435 }
436
437 /* use Newton procedure to find the point where the tangent intersects sine at lower bound */
438 tangentpoint = SCIPcalcRootNewton(function2, derivative2, &ub, 1, startingpoint, NEWTON_PRECISION,
440
441 /* if Newton procedure failed, no underestimator is found */
442 if( tangentpoint == SCIP_INVALID ) /*lint !e777*/
443 return FALSE;
444
445 /* if the computed point lies outside the bounds, it is shifted to upper bound */
446 if( SCIPisLE(scip, tangentpoint, lb) )
447 {
448 tangentpoint = lb;
449
450 /* check whether affine function is still underestimating */
451 if( SCIPisLE(scip, sin(0.5 * (ub + lb)), sin(lb) + 0.5*(sin(ub) - sin(lb))) )
452 return FALSE;
453 }
454
455 if( SCIPisEQ(scip, tangentpoint, ub) ) /*lint !e777 */
456 return FALSE;
457
458 /* compute secant between lower bound and connection point */
459 *lincoef = (sin(tangentpoint) - sin(ub)) / (tangentpoint - ub);
460 *linconst = sin(ub) - (*lincoef) * ub;
461
462 /* if the bounds are to close to each other, it's possible that the underestimator is not valid */
463 if( *lincoef <= cos(lb) )
464 return FALSE;
465
466 return TRUE;
467}
468
469/** helper function to compute the new interval for child in reverse propagation */
470static
472 SCIP* scip, /**< SCIP data structure */
473 SCIP_INTERVAL parentbounds, /**< bounds for sine expression */
474 SCIP_INTERVAL childbounds, /**< bounds for child expression */
475 SCIP_INTERVAL* newbounds /**< buffer to store new child bounds */
476 )
477{
478 SCIP_Real newinf = childbounds.inf;
479 SCIP_Real newsup = childbounds.sup;
480
481 /* if the absolute values of the bounds are too large, skip reverse propagation
482 * TODO: if bounds are close but too large, shift them to [0,2pi] and do the computation there
483 */
484 if( ABS(newinf) > MAXCHILDABSVAL || ABS(newsup) > MAXCHILDABSVAL )
485 {
486 SCIPintervalSetBounds(newbounds, newinf, newsup);
487 return SCIP_OKAY;
488 }
489
490 if( !SCIPisInfinity(scip, -newinf) )
491 {
492 /* l(x) and u(x) are lower/upper bound of child, l(s) and u(s) are lower/upper bound of sin expr
493 *
494 * if sin(l(x)) < l(s), we are looking for k minimal s.t. a + 2k*pi > l(x) where a = asin(l(s))
495 * then the new lower bound is a + 2k*pi
496 */
497 if( SCIPisLT(scip, sin(newinf), parentbounds.inf) )
498 {
499 SCIP_Real a = asin(parentbounds.inf);
500 int k = (int) ceil((newinf - a) / (2.0*M_PI));
501 newinf = a + 2.0*M_PI * k;
502 }
503
504 /* if sin(l(x)) > u(s), we are looking for k minimal s.t. pi - a + 2k*pi > l(x) where a = asin(u(s))
505 * then the new lower bound is pi - a + 2k*pi
506 */
507 else if( SCIPisGT(scip, sin(newinf), parentbounds.sup) )
508 {
509 SCIP_Real a = asin(parentbounds.sup);
510 int k = (int) ceil((newinf + a) / (2.0*M_PI) - 0.5);
511 newinf = M_PI * (2.0*k + 1.0) - a;
512 }
513
514 assert(newinf >= childbounds.inf);
515 assert(SCIPisFeasGE(scip, sin(newinf), parentbounds.inf));
516 assert(SCIPisFeasLE(scip, sin(newinf), parentbounds.sup));
517 }
518
519 if( !SCIPisInfinity(scip, newsup) )
520 {
521 /* if sin(u(x)) > u(s), we are looking for k minimal s.t. a + 2k*pi > u(x) - 2*pi where a = asin(u(s))
522 * then the new upper bound is a + 2k*pi
523 */
524 if ( SCIPisGT(scip, sin(newsup), parentbounds.sup) )
525 {
526 SCIP_Real a = asin(parentbounds.sup);
527 int k = (int) ceil((newsup - a ) / (2.0*M_PI)) - 1;
528 newsup = a + 2.0*M_PI * k;
529 }
530
531 /* if sin(u(x)) < l(s), we are looking for k minimal s.t. pi - a + 2k*pi > l(x) - 2*pi where a = asin(l(s))
532 * then the new upper bound is pi - a + 2k*pi
533 */
534 if( SCIPisLT(scip, sin(newsup), parentbounds.inf) )
535 {
536 SCIP_Real a = asin(parentbounds.inf);
537 int k = (int) ceil((newsup + a) / (2.0*M_PI) - 0.5) - 1;
538 newsup = M_PI * (2.0*k + 1.0) - a;
539 }
540
541 assert(newsup <= childbounds.sup);
542 assert(SCIPisFeasGE(scip, sin(newsup), parentbounds.inf));
543 assert(SCIPisFeasLE(scip, sin(newsup), parentbounds.sup));
544 }
545
546 /* if the new interval is invalid, the old one was already invalid */
547 if( newinf <= newsup )
548 SCIPintervalSetBounds(newbounds, newinf, newsup);
549 else
550 SCIPintervalSetEmpty(newbounds);
551
552 return SCIP_OKAY;
553}
554
555/** helper function to compute coefficients and constant term of a linear estimator at a given point
556 *
557 * The function will try to compute the following estimators in that order:
558 * - soltangent: tangent at specified refpoint
559 * - secant: secant between the points (lb,sin(lb)) and (ub,sin(ub))
560 * - left secant: secant between lower bound and some point of the graph
561 * - right secant: secant between upper bound and some point of the graph
562 *
563 * They are ordered such that a successful computation for one of them cannot be improved by following ones in terms
564 * of value at the reference point.
565 */
566static
568 SCIP* scip, /**< SCIP data structure */
569 SCIP_EXPR* expr, /**< sin or cos expression */
570 SCIP_Real* lincoef, /**< buffer to store the linear coefficient */
571 SCIP_Real* linconst, /**< buffer to store the constant term */
572 SCIP_Real refpoint, /**< point at which to underestimate (can be SCIP_INVALID) */
573 SCIP_Real childlb, /**< lower bound of child variable */
574 SCIP_Real childub, /**< upper bound of child variable */
575 SCIP_Bool underestimate /**< whether the estimator should be underestimating */
576 )
577{
578 SCIP_Bool success;
579 SCIP_Bool iscos;
580
581 assert(scip != NULL);
582 assert(expr != NULL);
583 assert(SCIPexprGetNChildren(expr) == 1);
584 assert(strcmp(SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), "sin") == 0
585 || strcmp(SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), "cos") == 0);
586 assert(SCIPisLE(scip, childlb, childub));
587
588 /* if child is essentially constant, then there should be no point in estimation */
589 if( SCIPisEQ(scip, childlb, childub) ) /* @todo maybe return a constant estimator? */
590 return FALSE;
591
592 iscos = strcmp(SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), "cos") == 0;
593
594 /* for cos expressions, the bounds have to be shifted before and after computation */
595 if( iscos )
596 {
597 childlb += M_PI_2;
598 childub += M_PI_2;
599 refpoint += M_PI_2;
600 }
601
602 if( !underestimate )
603 {
604 SCIP_Real tmp = childlb;
605 childlb = -childub;
606 childub = -tmp;
607 refpoint *= -1;
608 }
609
610 /* try out tangent at solution point */
611 success = computeSolTangentSin(scip, lincoef, linconst, childlb, childub, refpoint);
612
613 /* otherwise, try out secant */
614 if( !success )
615 success = computeSecantSin(scip, lincoef, linconst, childlb, childub);
616
617 /* otherwise, try left secant */
618 if( !success )
619 success = computeLeftSecantSin(scip, lincoef, linconst, childlb, childub);
620
621 /* otherwise, try right secant */
622 if( !success )
623 success = computeRightSecantSin(scip, lincoef, linconst, childlb, childub);
624
625 if( !success )
626 return FALSE;
627
628 /* for overestimators, mirror back */
629 if( !underestimate )
630 (*linconst) *= -1.0;
631
632 /* for cos expressions, shift back */
633 if( iscos )
634 (*linconst) += (*lincoef) * M_PI_2;
635
636 return TRUE;
637}
638
639/** helper function to create initial cuts for sine and cosine separation
640 *
641 * The following 5 cuts can be generated:
642 * - secant: secant between the bounds (lb,sin(lb)) and (ub,sin(ub))
643 * - left/right secant: secant between lower/upper bound and some point of the graph
644 * - left/right tangent: tangents at the lower/upper bounds
645 */
646static
648 SCIP* scip, /**< SCIP data structure */
649 SCIP_EXPR* expr, /**< sin or cos expression */
650 SCIP_Real childlb, /**< lower bound of child variable */
651 SCIP_Real childub, /**< upper bound of child variable */
652 SCIP_Bool underestimate, /**< whether the cuts should be underestimating */
653 SCIP_Real** coefs, /**< buffer to store coefficients of computed estimators */
654 SCIP_Real* constant, /**< buffer to store constant of computed estimators */
655 int* nreturned /**< buffer to store number of estimators that have been computed */
656 )
657{
658 SCIP_Bool iscos;
659 int i;
660
661 assert(scip != NULL);
662 assert(expr != NULL);
663 assert(SCIPexprGetNChildren(expr) == 1);
664 assert(strcmp(SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), "sin") == 0 || strcmp(SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), "cos") == 0);
665 assert(SCIPisLE(scip, childlb, childub));
666
667 /* caller must ensure that variable is not already fixed */
668 assert(!SCIPisEQ(scip, childlb, childub));
669
670 *nreturned = 0;
671
672 /* for cos expressions, the bounds have to be shifted before and after computation */
673 iscos = strcmp(SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), "cos") == 0;
674 if( iscos )
675 {
676 childlb += M_PI_2;
677 childub += M_PI_2;
678 }
679
680 /*
681 * Compute all initial cuts
682 * For each linear equation z = a*x + b with bounds [lb,ub] the parameters can be computed by:
683 *
684 * a = cos(x^) and b = sin(x^) - a * x^ where x^ is any known point in [lb,ub]
685 *
686 * and the resulting cut is a*x + b <=/>= z depending on over-/underestimation
687 */
688
689 if( ! underestimate )
690 {
691 SCIP_Real aux;
692 aux = childlb;
693 childlb = -childub;
694 childub = -aux;
695 }
696
697 /* if we can generate a secant between the bounds, then we have convex (concave) hull */
698 if( computeSecantSin(scip, coefs[*nreturned], &constant[*nreturned], childlb, childub) )
699 (*nreturned)++;
700 else
701 {
702 /* try generating a secant between lb (ub) and some point < ub (> lb); otherwise try with tangent at lb (ub)*/
703 if( computeLeftSecantSin(scip, coefs[*nreturned], &constant[*nreturned], childlb, childub) )
704 (*nreturned)++;
705 else if( computeLeftTangentSin(scip, coefs[*nreturned], &constant[*nreturned], childlb) )
706 (*nreturned)++;
707
708 /* try generating a secant between ub (lb) and some point > lb (< ub); otherwise try with tangent at ub (lb)*/
709 if( computeRightSecantSin(scip, coefs[*nreturned], &constant[*nreturned], childlb, childub) )
710 (*nreturned)++;
711 else if( computeRightTangentSin(scip, coefs[*nreturned], &constant[*nreturned], childub) )
712 (*nreturned)++;
713 }
714
715 /* for cos expressions, the estimator needs to be shifted back to match original bounds */
716 for( i = 0; i < *nreturned; ++i )
717 {
718 if( ! underestimate )
719 constant[i] *= -1.0;
720
721 if( iscos)
722 {
723 constant[i] += coefs[i][0] * M_PI_2;
724 }
725 }
726
727 return SCIP_OKAY;
728}
729
730/* helper function that computes the curvature of a sine expression for given bounds and curvature of child */
731static
733 SCIP_EXPRCURV childcurvature, /**< curvature of child */
734 SCIP_Real lb, /**< lower bound of child */
735 SCIP_Real ub /**< upper bound of child */
736 )
737{
738 SCIP_Real lbsin = sin(lb);
739 SCIP_Real ubsin = sin(ub);
740 SCIP_Real lbcos = cos(lb);
741 SCIP_Real ubcos = cos(ub);
742
743 /* curvature can only be determined if bounds lie within one bay*/
744 if( (ub - lb <= M_PI) && (lbsin * ubsin >= 0.0) )
745 {
746 /* special case that both sin(ub) and sin(lb) are 0 (i.e. ub - lb = pi) */
747 if( lbsin == 0.0 && ubsin == 0.0 )
748 {
749 if( childcurvature == SCIP_EXPRCURV_LINEAR )
750 return (fmod(lb, 2.0*M_PI) == 0.0) ? SCIP_EXPRCURV_CONCAVE : SCIP_EXPRCURV_CONVEX;
751 }
752
753 /* if sine is monotone on the interval, the curvature depends on the child curvature and on the segment */
754 else if( lbcos * ubcos >= 0.0 )
755 {
756 /* on [0, pi/2], sine is concave iff child is concave */
757 if( lbsin >= 0.0 && lbcos >= 0.0 && ((int)(childcurvature & SCIP_EXPRCURV_CONCAVE) != 0))
759
760 /* on [pi/2, pi], sine is concave iff child is convex */
761 if( lbsin >= 0.0 && lbcos <= 0.0 && ((int)(childcurvature & SCIP_EXPRCURV_CONVEX) != 0))
763
764 /* on [pi, 3pi/2], sine is convex iff child is concave */
765 if( lbsin <= 0.0 && lbcos <= 0.0 && ((int)(childcurvature & SCIP_EXPRCURV_CONCAVE) != 0))
767
768 /* on [3pi/2, 2pi], sine is convex iff child is convex */
769 if( lbsin <= 0.0 && lbcos >= 0.0 && ((int)(childcurvature & SCIP_EXPRCURV_CONVEX) != 0))
771 }
772
773 /* otherwise, we can only say something if the child is linear */
774 else if( childcurvature == SCIP_EXPRCURV_LINEAR )
775 return (lbsin >= 0.0 && ubsin >= 0.0) ? SCIP_EXPRCURV_CONCAVE : SCIP_EXPRCURV_CONVEX;
776 }
777
779}
780
781/*
782 * Callback methods of expression handler
783 */
784
785/** expression handler copy callback */
786static
788{ /*lint --e{715}*/
790
791 return SCIP_OKAY;
792}
793
794/** simplifies a sine expression
795 *
796 * Evaluates the sine value function when its child is a value expression.
797 *
798 * TODO: add further simplifications
799 */
800static
802{ /*lint --e{715}*/
803 SCIP_EXPR* child;
804
805 assert(scip != NULL);
806 assert(expr != NULL);
807 assert(simplifiedexpr != NULL);
808 assert(SCIPexprGetNChildren(expr) == 1);
809
810 child = SCIPexprGetChildren(expr)[0];
811 assert(child != NULL);
812
813 /* check for value expression */
814 if( SCIPisExprValue(scip, child) )
815 {
816 SCIP_CALL( SCIPcreateExprValue(scip, simplifiedexpr, sin(SCIPgetValueExprValue(child)), ownercreate,
817 ownercreatedata) );
818 }
819 else
820 {
821 *simplifiedexpr = expr;
822
823 /* we have to capture it, since it must simulate a "normal" simplified call in which a new expression is created */
824 SCIPcaptureExpr(*simplifiedexpr);
825 }
826
827 return SCIP_OKAY;
828}
829
830/** expression parse callback */
831static
833{ /*lint --e{715}*/
834 SCIP_EXPR* childexpr;
835
836 assert(expr != NULL);
837
838 /* parse child expression from remaining string */
839 SCIP_CALL( SCIPparseExpr(scip, &childexpr, string, endstring, ownercreate, ownercreatedata) );
840 assert(childexpr != NULL);
841
842 /* create sine expression */
843 SCIP_CALL( SCIPcreateExprSin(scip, expr, childexpr, ownercreate, ownercreatedata) );
844 assert(*expr != NULL);
845
846 /* release child expression since it has been captured by the sine expression */
847 SCIP_CALL( SCIPreleaseExpr(scip, &childexpr) );
848
849 *success = TRUE;
850
851 return SCIP_OKAY;
852}
853
854/** expression (point-) evaluation callback */
855static
857{ /*lint --e{715}*/
858 assert(expr != NULL);
859 assert(SCIPexprGetNChildren(expr) == 1);
860 assert(SCIPexprGetEvalValue(SCIPexprGetChildren(expr)[0]) != SCIP_INVALID); /*lint !e777*/
861
862 *val = sin(SCIPexprGetEvalValue(SCIPexprGetChildren(expr)[0]));
863
864 return SCIP_OKAY;
865}
866
867/** expression derivative evaluation callback */
868static
870{ /*lint --e{715}*/
871 SCIP_EXPR* child;
872
873 assert(expr != NULL);
874 assert(childidx == 0);
875 assert(SCIPexprGetEvalValue(expr) != SCIP_INVALID); /*lint !e777*/
876
877 child = SCIPexprGetChildren(expr)[0];
878 assert(child != NULL);
879 assert(strcmp(SCIPexprhdlrGetName(SCIPexprGetHdlr(child)), "val") != 0);
880
881 *val = cos(SCIPexprGetEvalValue(child));
882
883 return SCIP_OKAY;
884}
885
886/** derivative evaluation callback
887 *
888 * Computes <gradient, children.dot>, that is, cos(child) dot(child).
889 */
890static
892{ /*lint --e{715}*/
893 SCIP_EXPR* child;
894
895 assert(expr != NULL);
896 assert(SCIPexprGetEvalValue(expr) != SCIP_INVALID); /*lint !e777*/
897
898 child = SCIPexprGetChildren(expr)[0];
899 assert(child != NULL);
900 assert(strcmp(SCIPexprhdlrGetName(SCIPexprGetHdlr(child)), "val") != 0);
901 assert(SCIPexprGetDot(child) != SCIP_INVALID); /*lint !e777*/
902
903 *dot = cos(SCIPexprGetEvalValue(child)) * SCIPexprGetDot(child);
904
905 return SCIP_OKAY;
906}
907
908/** expression backward forward derivative evaluation callback
909 *
910 * Computes partial/partial child ( <gradient, children.dot> ), that is, -sin(child) dot(child).
911 */
912static
914{ /*lint --e{715}*/
915 SCIP_EXPR* child;
916
917 assert(expr != NULL);
918 assert(SCIPexprGetEvalValue(expr) != SCIP_INVALID); /*lint !e777*/
919 assert(childidx == 0);
920
921 child = SCIPexprGetChildren(expr)[0];
922 assert(child != NULL);
923 assert(strcmp(SCIPexprhdlrGetName(SCIPexprGetHdlr(child)), "val") != 0);
924 assert(SCIPexprGetDot(child) != SCIP_INVALID); /*lint !e777*/
925
926 *bardot = -sin(SCIPexprGetEvalValue(child)) * SCIPexprGetDot(child);
927
928 return SCIP_OKAY;
929}
930
931/** expression interval evaluation callback */
932static
934{ /*lint --e{715}*/
935 SCIP_INTERVAL childinterval;
936
937 assert(expr != NULL);
938 assert(SCIPexprGetNChildren(expr) == 1);
939
940 childinterval = SCIPexprGetActivity(SCIPexprGetChildren(expr)[0]);
941
942 if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, childinterval) )
943 SCIPintervalSetEmpty(interval);
944 else
945 SCIPintervalSin(SCIP_INTERVAL_INFINITY, interval, childinterval);
946
947 return SCIP_OKAY;
948}
949
950/** separation initialization callback */
951static
953{ /*lint --e{715}*/
954 SCIP_Real childlb;
955 SCIP_Real childub;
956
957 childlb = bounds[0].inf;
958 childub = bounds[0].sup;
959
960 /* no need for cut if child is fixed */
961 if( SCIPisRelEQ(scip, childlb, childub) )
962 return SCIP_OKAY;
963
964 /* compute cuts */
965 SCIP_CALL( computeInitialCutsTrig(scip, expr, childlb, childub, ! overestimate, coefs, constant, nreturned) );
966
967 return SCIP_OKAY;
968}
969
970/** expression estimator callback */
971static
973{ /*lint --e{715}*/
974 assert(scip != NULL);
975 assert(expr != NULL);
976 assert(SCIPexprGetNChildren(expr) == 1);
977 assert(coefs != NULL);
978 assert(constant != NULL);
979 assert(islocal != NULL);
980 assert(branchcand != NULL);
981 assert(*branchcand == TRUE);
982 assert(success != NULL);
983
985
986 *success = computeEstimatorsTrig(scip, expr, coefs, constant, refpoint[0], localbounds[0].inf,
987 localbounds[0].sup, ! overestimate);
988 *islocal = TRUE; /* TODO there are cases where cuts would be globally valid */
989
990 return SCIP_OKAY;
991}
992
993/** expression reverse propagation callback */
994static
996{ /*lint --e{715}*/
997 assert(scip != NULL);
998 assert(expr != NULL);
999 assert(SCIPexprGetNChildren(expr) == 1);
1000 assert(SCIPintervalGetInf(bounds) >= -1.0);
1001 assert(SCIPintervalGetSup(bounds) <= 1.0);
1002
1003 /* compute the new child interval */
1004 SCIP_CALL( computeRevPropIntervalSin(scip, bounds, childrenbounds[0], childrenbounds) );
1005
1006 return SCIP_OKAY;
1007}
1008
1009/** sine hash callback */
1010static
1012{ /*lint --e{715}*/
1013 assert(scip != NULL);
1014 assert(expr != NULL);
1015 assert(SCIPexprGetNChildren(expr) == 1);
1016 assert(hashkey != NULL);
1017 assert(childrenhashes != NULL);
1018
1019 *hashkey = SINEXPRHDLR_HASHKEY;
1020 *hashkey ^= childrenhashes[0];
1021
1022 return SCIP_OKAY;
1023}
1024
1025/** expression curvature detection callback */
1026static
1028{ /*lint --e{715}*/
1029 SCIP_EXPR* child;
1030 SCIP_INTERVAL childinterval;
1031
1032 assert(scip != NULL);
1033 assert(expr != NULL);
1034 assert(childcurv != NULL);
1035 assert(success != NULL);
1036 assert(SCIPexprGetNChildren(expr) == 1);
1037
1038 child = SCIPexprGetChildren(expr)[0];
1039 assert(child != NULL);
1041 childinterval = SCIPexprGetActivity(child);
1042
1043 /* TODO rewrite SCIPcomputeCurvatureSin so it provides the reverse operation */
1044 *success = TRUE;
1045 if( computeCurvatureSin(SCIP_EXPRCURV_CONVEX, childinterval.inf, childinterval.sup) == exprcurvature )
1046 *childcurv = SCIP_EXPRCURV_CONVEX;
1047 else if( computeCurvatureSin(SCIP_EXPRCURV_CONCAVE, childinterval.inf, childinterval.sup) == exprcurvature )
1048 *childcurv = SCIP_EXPRCURV_CONCAVE;
1049 if( computeCurvatureSin(SCIP_EXPRCURV_LINEAR, childinterval.inf, childinterval.sup) == exprcurvature )
1050 *childcurv = SCIP_EXPRCURV_LINEAR;
1051 else
1052 *success = FALSE;
1053
1054 return SCIP_OKAY;
1055}
1056
1057/** expression monotonicity detection callback */
1058static
1060{ /*lint --e{715}*/
1061 SCIP_INTERVAL interval;
1062 SCIP_Real inf;
1063 SCIP_Real sup;
1064 int k;
1065
1066 assert(scip != NULL);
1067 assert(expr != NULL);
1068 assert(result != NULL);
1069 assert(childidx == 0);
1070
1071 assert(SCIPexprGetChildren(expr)[0] != NULL);
1073 interval = SCIPexprGetActivity(SCIPexprGetChildren(expr)[0]);
1074
1076 inf = SCIPintervalGetInf(interval);
1077 sup = SCIPintervalGetSup(interval);
1078
1079 /* expression is not monotone because the interval is too large */
1080 if( SCIPisGT(scip, sup - inf, M_PI) )
1081 return SCIP_OKAY;
1082
1083 /* compute k s.t. PI * (2k+1) / 2 <= interval.inf <= PI * (2k+3) / 2 */
1084 k = (int)floor(inf/M_PI - 0.5);
1085 assert(SCIPisLE(scip, M_PI * (2.0*k + 1.0) / 2.0, inf));
1086 assert(SCIPisGE(scip, M_PI * (2.0*k + 3.0) / 2.0, inf));
1087
1088 /* check whether [inf,sup] are contained in an interval for which the sine function is monotone */
1089 if( SCIPisLE(scip, sup, M_PI * (2.0*k + 3.0) / 2.0) )
1090 *result = ((k % 2 + 2) % 2) == 1 ? SCIP_MONOTONE_INC : SCIP_MONOTONE_DEC;
1091
1092 return SCIP_OKAY;
1093}
1094
1095
1096/** expression handler copy callback */
1097static
1099{ /*lint --e{715}*/
1101
1102 return SCIP_OKAY;
1103}
1104
1105/** simplifies a cosine expression
1106 *
1107 * Evaluates the cosine value function when its child is a value expression.
1108 *
1109 * TODO: add further simplifications
1110 */
1111static
1113{ /*lint --e{715}*/
1114 SCIP_EXPR* child;
1115
1116 assert(scip != NULL);
1117 assert(expr != NULL);
1118 assert(simplifiedexpr != NULL);
1119 assert(SCIPexprGetNChildren(expr) == 1);
1120
1121 child = SCIPexprGetChildren(expr)[0];
1122 assert(child != NULL);
1123
1124 /* check for value expression */
1125 if( SCIPisExprValue(scip, child) )
1126 {
1127 SCIP_CALL( SCIPcreateExprValue(scip, simplifiedexpr, cos(SCIPgetValueExprValue(child)), ownercreate,
1128 ownercreatedata) );
1129 }
1130 else
1131 {
1132 *simplifiedexpr = expr;
1133
1134 /* we have to capture it, since it must simulate a "normal" simplified call in which a new expression is created */
1135 SCIPcaptureExpr(*simplifiedexpr);
1136 }
1137
1138 return SCIP_OKAY;
1139}
1140
1141/** expression parse callback */
1142static
1144{ /*lint --e{715}*/
1145 SCIP_EXPR* childexpr;
1146
1147 assert(expr != NULL);
1148
1149 /* parse child expression from remaining string */
1150 SCIP_CALL( SCIPparseExpr(scip, &childexpr, string, endstring, ownercreate, ownercreatedata) );
1151 assert(childexpr != NULL);
1152
1153 /* create cosine expression */
1154 SCIP_CALL( SCIPcreateExprCos(scip, expr, childexpr, ownercreate, ownercreatedata) );
1155 assert(*expr != NULL);
1156
1157 /* release child expression since it has been captured by the cosine expression */
1158 SCIP_CALL( SCIPreleaseExpr(scip, &childexpr) );
1159
1160 *success = TRUE;
1161
1162 return SCIP_OKAY;
1163}
1164
1165/** expression (point-) evaluation callback */
1166static
1168{ /*lint --e{715}*/
1169 assert(expr != NULL);
1170 assert(SCIPexprGetNChildren(expr) == 1);
1171 assert(SCIPexprGetEvalValue(SCIPexprGetChildren(expr)[0]) != SCIP_INVALID); /*lint !e777*/
1172
1173 *val = cos(SCIPexprGetEvalValue(SCIPexprGetChildren(expr)[0]));
1174
1175 return SCIP_OKAY;
1176}
1177
1178/** expression derivative evaluation callback */
1179static
1181{ /*lint --e{715}*/
1182 SCIP_EXPR* child;
1183
1184 assert(expr != NULL);
1185 assert(childidx == 0);
1186 assert(SCIPexprGetEvalValue(expr) != SCIP_INVALID); /*lint !e777*/
1187
1188 child = SCIPexprGetChildren(expr)[0];
1189 assert(child != NULL);
1190 assert(strcmp(SCIPexprhdlrGetName(SCIPexprGetHdlr(child)), "val") != 0);
1191
1192 *val = -sin(SCIPexprGetEvalValue(child));
1193
1194 return SCIP_OKAY;
1195}
1196
1197/** expression interval evaluation callback */
1198static
1200{ /*lint --e{715}*/
1201 SCIP_INTERVAL childinterval;
1202
1203 assert(expr != NULL);
1204 assert(SCIPexprGetNChildren(expr) == 1);
1205
1206 childinterval = SCIPexprGetActivity(SCIPexprGetChildren(expr)[0]);
1207
1208 if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, childinterval) )
1209 SCIPintervalSetEmpty(interval);
1210 else
1211 SCIPintervalCos(SCIP_INTERVAL_INFINITY, interval, childinterval);
1212
1213 return SCIP_OKAY;
1214}
1215
1216/** separation initialization callback */
1217static
1219{
1220 SCIP_Real childlb;
1221 SCIP_Real childub;
1222
1223 childlb = bounds[0].inf;
1224 childub = bounds[0].sup;
1225
1226 /* no need for cut if child is fixed */
1227 if( SCIPisRelEQ(scip, childlb, childub) )
1228 return SCIP_OKAY;
1229
1230 /* compute cuts */
1231 SCIP_CALL( computeInitialCutsTrig(scip, expr, childlb, childub, ! overestimate, coefs, constant, nreturned) );
1232
1233 return SCIP_OKAY;
1234}
1235
1236/** expression estimator callback */
1237static
1239{ /*lint --e{715}*/
1240 assert(scip != NULL);
1241 assert(expr != NULL);
1242 assert(SCIPexprGetNChildren(expr) == 1);
1243 assert(coefs != NULL);
1244 assert(constant != NULL);
1245 assert(islocal != NULL);
1246 assert(branchcand != NULL);
1247 assert(*branchcand == TRUE);
1248 assert(success != NULL);
1249
1251
1252 *success = computeEstimatorsTrig(scip, expr, coefs, constant, refpoint[0], localbounds[0].inf,
1253 localbounds[0].sup, ! overestimate);
1254 *islocal = TRUE; /* TODO there are cases where cuts would be globally valid */
1255
1256 return SCIP_OKAY;
1257}
1258
1259/** expression reverse propagation callback */
1260static
1262{ /*lint --e{715}*/
1263 SCIP_INTERVAL newbounds;
1264
1265 assert(scip != NULL);
1266 assert(expr != NULL);
1267 assert(SCIPexprGetNChildren(expr) == 1);
1268 /* bounds should have been intersected with activity, which is within [-1,1] */
1269 assert(SCIPintervalGetInf(bounds) >= -1.0);
1270 assert(SCIPintervalGetSup(bounds) <= 1.0);
1271
1272 /* get the child interval */
1273 newbounds = childrenbounds[0];
1274
1275 /* shift child interval to match sine */
1276 SCIPintervalAddScalar(SCIP_INTERVAL_INFINITY, &newbounds, newbounds, M_PI_2); /* TODO use bounds on Pi/2 instead of approximation of Pi/2 */
1277
1278 /* compute the new child interval */
1279 SCIP_CALL( computeRevPropIntervalSin(scip, bounds, newbounds, &newbounds) );
1280
1282 {
1283 *infeasible = TRUE;
1284 return SCIP_OKAY;
1285 }
1286
1287 /* shift the new interval back */
1288 SCIPintervalAddScalar(SCIP_INTERVAL_INFINITY, &childrenbounds[0], newbounds, -M_PI_2); /* TODO use bounds on Pi/2 instead of approximation of Pi/2 */
1289
1290 return SCIP_OKAY;
1291}
1292
1293/** cosine hash callback */
1294static
1296{ /*lint --e{715}*/
1297 assert(scip != NULL);
1298 assert(expr != NULL);
1299 assert(SCIPexprGetNChildren(expr) == 1);
1300 assert(hashkey != NULL);
1301 assert(childrenhashes != NULL);
1302
1303 *hashkey = COSEXPRHDLR_HASHKEY;
1304 *hashkey ^= childrenhashes[0];
1305
1306 return SCIP_OKAY;
1307}
1308
1309/** expression curvature detection callback */
1310static
1312{ /*lint --e{715}*/
1313 SCIP_EXPR* child;
1314 SCIP_INTERVAL childinterval;
1315
1316 assert(scip != NULL);
1317 assert(expr != NULL);
1318 assert(exprcurvature != SCIP_EXPRCURV_UNKNOWN);
1319 assert(childcurv != NULL);
1320 assert(success != NULL);
1321 assert(SCIPexprGetNChildren(expr) == 1);
1322
1323 child = SCIPexprGetChildren(expr)[0];
1324 assert(child != NULL);
1326 childinterval = SCIPexprGetActivity(child);
1327
1328 /* TODO rewrite SCIPcomputeCurvatureSin so it provides the reverse operation */
1329 *success = TRUE;
1330 if( computeCurvatureSin(SCIP_EXPRCURV_CONCAVE, childinterval.inf + M_PI_2, childinterval.sup + M_PI_2) == exprcurvature )
1331 *childcurv = SCIP_EXPRCURV_CONCAVE;
1332 else if( computeCurvatureSin(SCIP_EXPRCURV_CONVEX, childinterval.inf + M_PI_2, childinterval.sup + M_PI_2) == exprcurvature )
1333 *childcurv = SCIP_EXPRCURV_CONVEX;
1334 else if( computeCurvatureSin(SCIP_EXPRCURV_LINEAR, childinterval.inf + M_PI_2, childinterval.sup + M_PI_2) == exprcurvature )
1335 *childcurv = SCIP_EXPRCURV_LINEAR;
1336 else
1337 *success = FALSE;
1338
1339 return SCIP_OKAY;
1340}
1341
1342/** expression monotonicity detection callback */
1343static
1345{ /*lint --e{715}*/
1346 SCIP_INTERVAL interval;
1347 SCIP_Real inf;
1348 SCIP_Real sup;
1349 int k;
1350
1351 assert(scip != NULL);
1352 assert(expr != NULL);
1353 assert(result != NULL);
1354 assert(childidx == 0);
1355
1356 assert(SCIPexprGetChildren(expr)[0] != NULL);
1358 interval = SCIPexprGetActivity(SCIPexprGetChildren(expr)[0]);
1359
1361 inf = SCIPintervalGetInf(interval);
1362 sup = SCIPintervalGetSup(interval);
1363
1364 /* expression is not monotone because the interval is too large */
1365 if( SCIPisGT(scip, sup - inf, M_PI) )
1366 return SCIP_OKAY;
1367
1368 /* compute k s.t. PI * k <= interval.inf <= PI * (k+1) */
1369 k = (int)floor(inf/M_PI);
1370 assert(SCIPisLE(scip, M_PI * k, inf));
1371 assert(SCIPisGE(scip, M_PI * (k+1), inf));
1372
1373 /* check whether [inf,sup] are contained in an interval for which the cosine function is monotone */
1374 if( SCIPisLE(scip, sup, M_PI * (k+1)) )
1375 *result = ((k % 2 + 2) % 2) == 0 ? SCIP_MONOTONE_DEC : SCIP_MONOTONE_INC;
1376
1377 return SCIP_OKAY;
1378}
1379
1380/** creates the handler for sin expressions and includes it into SCIP */
1382 SCIP* scip /**< SCIP data structure */
1383 )
1384{
1385 SCIP_EXPRHDLR* exprhdlr;
1386
1387 /* include expression handler */
1389 assert(exprhdlr != NULL);
1390
1391 SCIPexprhdlrSetCopyFreeHdlr(exprhdlr, copyhdlrSin, NULL);
1392 SCIPexprhdlrSetSimplify(exprhdlr, simplifySin);
1393 SCIPexprhdlrSetParse(exprhdlr, parseSin);
1394 SCIPexprhdlrSetIntEval(exprhdlr, intevalSin);
1395 SCIPexprhdlrSetEstimate(exprhdlr, initEstimatesSin, estimateSin);
1396 SCIPexprhdlrSetReverseProp(exprhdlr, reversepropSin);
1397 SCIPexprhdlrSetHash(exprhdlr, hashSin);
1398 SCIPexprhdlrSetDiff(exprhdlr, bwdiffSin, fwdiffSin, bwfwdiffSin);
1399 SCIPexprhdlrSetCurvature(exprhdlr, curvatureSin);
1400 SCIPexprhdlrSetMonotonicity(exprhdlr, monotonicitySin);
1401
1402 return SCIP_OKAY;
1403}
1404
1405/** creates the handler for cos expressions and includes it SCIP */
1407 SCIP* scip /**< SCIP data structure */
1408 )
1409{
1410 SCIP_EXPRHDLR* exprhdlr;
1411
1412 /* include expression handler */
1414 assert(exprhdlr != NULL);
1415
1416 SCIPexprhdlrSetCopyFreeHdlr(exprhdlr, copyhdlrCos, NULL);
1417 SCIPexprhdlrSetSimplify(exprhdlr, simplifyCos);
1418 SCIPexprhdlrSetParse(exprhdlr, parseCos);
1419 SCIPexprhdlrSetIntEval(exprhdlr, intevalCos);
1420 SCIPexprhdlrSetEstimate(exprhdlr, initEstimatesCos, estimateCos);
1421 SCIPexprhdlrSetReverseProp(exprhdlr, reversepropCos);
1422 SCIPexprhdlrSetHash(exprhdlr, hashCos);
1423 SCIPexprhdlrSetDiff(exprhdlr, bwdiffCos, NULL, NULL);
1424 SCIPexprhdlrSetCurvature(exprhdlr, curvatureCos);
1425 SCIPexprhdlrSetMonotonicity(exprhdlr, monotonicityCos);
1426
1427 return SCIP_OKAY;
1428}
1429
1430/** creates a sin expression */
1432 SCIP* scip, /**< SCIP data structure */
1433 SCIP_EXPR** expr, /**< pointer where to store expression */
1434 SCIP_EXPR* child, /**< single child */
1435 SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), /**< function to call to create ownerdata */
1436 void* ownercreatedata /**< data to pass to ownercreate */
1437 )
1438{
1439 assert(expr != NULL);
1440 assert(child != NULL);
1442
1443 SCIP_CALL( SCIPcreateExpr(scip, expr, SCIPfindExprhdlr(scip, SINEXPRHDLR_NAME), NULL, 1, &child, ownercreate,
1444 ownercreatedata) );
1445
1446 return SCIP_OKAY;
1447}
1448
1449
1450/** creates a cos expression */
1452 SCIP* scip, /**< SCIP data structure */
1453 SCIP_EXPR** expr, /**< pointer where to store expression */
1454 SCIP_EXPR* child, /**< single child */
1455 SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), /**< function to call to create ownerdata */
1456 void* ownercreatedata /**< data to pass to ownercreate */
1457 )
1458{
1459 assert(expr != NULL);
1460 assert(child != NULL);
1462
1463 SCIP_CALL( SCIPcreateExpr(scip, expr, SCIPfindExprhdlr(scip, COSEXPRHDLR_NAME), NULL, 1, &child, ownercreate,
1464 ownercreatedata) );
1465
1466 return SCIP_OKAY;
1467}
1468
1469/** indicates whether expression is of sine-type */ /*lint -e{715}*/
1471 SCIP* scip, /**< SCIP data structure */
1472 SCIP_EXPR* expr /**< expression */
1473 )
1474{ /*lint --e{715}*/
1475 assert(expr != NULL);
1476
1477 return strcmp(SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), SINEXPRHDLR_NAME) == 0;
1478}
1479
1480/** indicates whether expression is of cosine-type */ /*lint -e{715}*/
1482 SCIP* scip, /**< SCIP data structure */
1483 SCIP_EXPR* expr /**< expression */
1484 )
1485{ /*lint --e{715}*/
1486 assert(expr != NULL);
1487
1488 return strcmp(SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), COSEXPRHDLR_NAME) == 0;
1489}
SCIP_VAR * a
#define NULL
Definition def.h:257
#define SCIP_INVALID
Definition def.h:187
#define SCIP_INTERVAL_INFINITY
Definition def.h:189
#define SCIP_Bool
Definition def.h:100
#define SCIP_STRINGEQ(name, reference, retcode)
Definition def.h:454
#define SCIP_Real
Definition def.h:165
#define ABS(x)
Definition def.h:225
#define TRUE
Definition def.h:102
#define FALSE
Definition def.h:103
#define SCIP_CALL(x)
Definition def.h:364
static SCIP_Bool computeEstimatorsTrig(SCIP *scip, SCIP_EXPR *expr, SCIP_Real *lincoef, SCIP_Real *linconst, SCIP_Real refpoint, SCIP_Real childlb, SCIP_Real childub, SCIP_Bool underestimate)
Definition expr_trig.c:567
#define COSEXPRHDLR_NAME
Definition expr_trig.c:63
static SCIP_Bool computeRightSecantSin(SCIP *scip, SCIP_Real *lincoef, SCIP_Real *linconst, SCIP_Real lb, SCIP_Real ub)
Definition expr_trig.c:389
#define SINEXPRHDLR_PRECEDENCE
Definition expr_trig.c:60
static SCIP_RETCODE computeRevPropIntervalSin(SCIP *scip, SCIP_INTERVAL parentbounds, SCIP_INTERVAL childbounds, SCIP_INTERVAL *newbounds)
Definition expr_trig.c:471
#define SINEXPRHDLR_HASHKEY
Definition expr_trig.c:61
static SCIP_EXPRCURV computeCurvatureSin(SCIP_EXPRCURV childcurvature, SCIP_Real lb, SCIP_Real ub)
Definition expr_trig.c:732
#define COSEXPRHDLR_HASHKEY
Definition expr_trig.c:66
#define SINEXPRHDLR_DESC
Definition expr_trig.c:59
#define COSEXPRHDLR_DESC
Definition expr_trig.c:64
#define NEWTON_NITERATIONS
Definition expr_trig.c:69
static SCIP_Bool computeLeftSecantSin(SCIP *scip, SCIP_Real *lincoef, SCIP_Real *linconst, SCIP_Real lb, SCIP_Real ub)
Definition expr_trig.c:302
#define MAXCHILDABSVAL
Definition expr_trig.c:68
static SCIP_RETCODE computeInitialCutsTrig(SCIP *scip, SCIP_EXPR *expr, SCIP_Real childlb, SCIP_Real childub, SCIP_Bool underestimate, SCIP_Real **coefs, SCIP_Real *constant, int *nreturned)
Definition expr_trig.c:647
static SCIP_Bool computeSecantSin(SCIP *scip, SCIP_Real *lincoef, SCIP_Real *linconst, SCIP_Real lb, SCIP_Real ub)
Definition expr_trig.c:133
#define COSEXPRHDLR_PRECEDENCE
Definition expr_trig.c:65
#define SINEXPRHDLR_NAME
Definition expr_trig.c:58
#define NEWTON_PRECISION
Definition expr_trig.c:70
static SCIP_Bool computeRightTangentSin(SCIP *scip, SCIP_Real *lincoef, SCIP_Real *linconst, SCIP_Real ub)
Definition expr_trig.c:198
static SCIP_Bool computeLeftTangentSin(SCIP *scip, SCIP_Real *lincoef, SCIP_Real *linconst, SCIP_Real lb)
Definition expr_trig.c:165
static SCIP_Bool computeSolTangentSin(SCIP *scip, SCIP_Real *lincoef, SCIP_Real *linconst, SCIP_Real lb, SCIP_Real ub, SCIP_Real solpoint)
Definition expr_trig.c:227
handler for sin expressions
constant value expression handler
SCIP_RETCODE SCIPcreateExprSin(SCIP *scip, SCIP_EXPR **expr, SCIP_EXPR *child, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition expr_trig.c:1431
SCIP_RETCODE SCIPcreateExprCos(SCIP *scip, SCIP_EXPR **expr, SCIP_EXPR *child, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition expr_trig.c:1451
SCIP_Bool SCIPisExprCos(SCIP *scip, SCIP_EXPR *expr)
Definition expr_trig.c:1481
SCIP_Bool SCIPisExprSin(SCIP *scip, SCIP_EXPR *expr)
Definition expr_trig.c:1470
SCIP_RETCODE SCIPcreateExprValue(SCIP *scip, SCIP_EXPR **expr, SCIP_Real value, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition expr_value.c:274
SCIP_RETCODE SCIPincludeExprhdlrCos(SCIP *scip)
Definition expr_trig.c:1406
SCIP_RETCODE SCIPincludeExprhdlrSin(SCIP *scip)
Definition expr_trig.c:1381
#define SCIPdebugMsg
SCIP_Real SCIPcalcRootNewton(SCIP_DECL_NEWTONEVAL((*function)), SCIP_DECL_NEWTONEVAL((*derivative)), SCIP_Real *params, int nparams, SCIP_Real x, SCIP_Real eps, int k)
Definition misc.c:10082
const char * SCIPexprhdlrGetName(SCIP_EXPRHDLR *exprhdlr)
Definition expr.c:545
void SCIPexprhdlrSetCurvature(SCIP_EXPRHDLR *exprhdlr,)
Definition expr.c:418
void SCIPexprhdlrSetParse(SCIP_EXPRHDLR *exprhdlr,)
Definition expr.c:407
void SCIPexprhdlrSetIntEval(SCIP_EXPRHDLR *exprhdlr,)
Definition expr.c:488
void SCIPexprhdlrSetMonotonicity(SCIP_EXPRHDLR *exprhdlr,)
Definition expr.c:429
void SCIPexprhdlrSetReverseProp(SCIP_EXPRHDLR *exprhdlr,)
Definition expr.c:510
void SCIPexprhdlrSetHash(SCIP_EXPRHDLR *exprhdlr,)
Definition expr.c:451
SCIP_RETCODE SCIPincludeExprhdlr(SCIP *scip, SCIP_EXPRHDLR **exprhdlr, const char *name, const char *desc, unsigned int precedence, SCIP_DECL_EXPREVAL((*eval)), SCIP_EXPRHDLRDATA *data)
Definition scip_expr.c:847
void SCIPexprhdlrSetSimplify(SCIP_EXPRHDLR *exprhdlr,)
Definition expr.c:499
void SCIPexprhdlrSetDiff(SCIP_EXPRHDLR *exprhdlr, SCIP_DECL_EXPRBWDIFF((*bwdiff)), SCIP_DECL_EXPRFWDIFF((*fwdiff)),)
Definition expr.c:473
void SCIPexprhdlrSetCopyFreeHdlr(SCIP_EXPRHDLR *exprhdlr, SCIP_DECL_EXPRCOPYHDLR((*copyhdlr)),)
Definition expr.c:370
SCIP_EXPRHDLR * SCIPfindExprhdlr(SCIP *scip, const char *name)
Definition scip_expr.c:894
void SCIPexprhdlrSetEstimate(SCIP_EXPRHDLR *exprhdlr, SCIP_DECL_EXPRINITESTIMATES((*initestimates)),)
Definition expr.c:532
SCIP_RETCODE SCIPcreateExpr(SCIP *scip, SCIP_EXPR **expr, SCIP_EXPRHDLR *exprhdlr, SCIP_EXPRDATA *exprdata, int nchildren, SCIP_EXPR **children, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition scip_expr.c:1000
int SCIPexprGetNChildren(SCIP_EXPR *expr)
Definition expr.c:3872
SCIP_Bool SCIPisExprValue(SCIP *scip, SCIP_EXPR *expr)
Definition scip_expr.c:1468
SCIP_RETCODE SCIPreleaseExpr(SCIP *scip, SCIP_EXPR **expr)
Definition scip_expr.c:1443
SCIP_Real SCIPexprGetDot(SCIP_EXPR *expr)
Definition expr.c:3986
SCIP_RETCODE SCIPparseExpr(SCIP *scip, SCIP_EXPR **expr, const char *exprstr, const char **finalpos, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition scip_expr.c:1406
SCIP_Real SCIPgetValueExprValue(SCIP_EXPR *expr)
Definition expr_value.c:298
SCIP_Real SCIPexprGetEvalValue(SCIP_EXPR *expr)
Definition expr.c:3946
SCIP_EXPR ** SCIPexprGetChildren(SCIP_EXPR *expr)
Definition expr.c:3882
SCIP_INTERVAL SCIPexprGetActivity(SCIP_EXPR *expr)
Definition expr.c:4028
void SCIPcaptureExpr(SCIP_EXPR *expr)
Definition scip_expr.c:1435
SCIP_RETCODE SCIPevalExprActivity(SCIP *scip, SCIP_EXPR *expr)
Definition scip_expr.c:1742
SCIP_EXPRHDLR * SCIPexprGetHdlr(SCIP_EXPR *expr)
Definition expr.c:3895
SCIP_Real SCIPintervalGetInf(SCIP_INTERVAL interval)
void SCIPintervalCos(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
SCIP_Bool SCIPintervalIsEmpty(SCIP_Real infinity, SCIP_INTERVAL operand)
void SCIPintervalSin(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
void SCIPintervalSetBounds(SCIP_INTERVAL *resultant, SCIP_Real inf, SCIP_Real sup)
struct SCIP_Interval SCIP_INTERVAL
void SCIPintervalAddScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
SCIP_Real SCIPintervalGetSup(SCIP_INTERVAL interval)
void SCIPintervalSetEmpty(SCIP_INTERVAL *resultant)
SCIP_Bool SCIPisRelEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
return SCIP_OKAY
assert(minobj< SCIPgetCutoffbound(scip))
#define M_PI
Definition pricer_rpa.c:97
SCIP_Real sup
SCIP_Real inf
struct SCIP_Expr SCIP_EXPR
Definition type_expr.h:55
#define SCIP_DECL_EXPR_OWNERCREATE(x)
Definition type_expr.h:143
#define SCIP_DECL_EXPRREVERSEPROP(x)
Definition type_expr.h:659
#define SCIP_DECL_EXPRINITESTIMATES(x)
Definition type_expr.h:610
#define SCIP_DECL_EXPRBWFWDIFF(x)
Definition type_expr.h:522
#define SCIP_DECL_EXPRCURVATURE(x)
Definition type_expr.h:340
SCIP_EXPRCURV
Definition type_expr.h:61
@ SCIP_EXPRCURV_CONVEX
Definition type_expr.h:63
@ SCIP_EXPRCURV_LINEAR
Definition type_expr.h:65
@ SCIP_EXPRCURV_UNKNOWN
Definition type_expr.h:62
@ SCIP_EXPRCURV_CONCAVE
Definition type_expr.h:64
#define SCIP_DECL_EXPRPARSE(x)
Definition type_expr.h:312
#define SCIP_DECL_EXPRBWDIFF(x)
Definition type_expr.h:451
#define SCIP_DECL_EXPRINTEVAL(x)
Definition type_expr.h:541
#define SCIP_DECL_EXPRMONOTONICITY(x)
Definition type_expr.h:358
@ SCIP_MONOTONE_UNKNOWN
Definition type_expr.h:71
@ SCIP_MONOTONE_INC
Definition type_expr.h:72
@ SCIP_MONOTONE_DEC
Definition type_expr.h:73
struct SCIP_Exprhdlr SCIP_EXPRHDLR
Definition type_expr.h:194
#define SCIP_DECL_EXPRSIMPLIFY(x)
Definition type_expr.h:634
#define SCIP_DECL_EXPREVAL(x)
Definition type_expr.h:428
#define SCIP_DECL_EXPRFWDIFF(x)
Definition type_expr.h:482
#define SCIP_DECL_EXPRHASH(x)
Definition type_expr.h:393
#define SCIP_DECL_EXPRCOPYHDLR(x)
Definition type_expr.h:210
#define SCIP_DECL_EXPRESTIMATE(x)
Definition type_expr.h:577
#define SCIP_DECL_NEWTONEVAL(x)
Definition type_misc.h:206
@ SCIP_INVALIDCALL
enum SCIP_Retcode SCIP_RETCODE
struct Scip SCIP
Definition type_scip.h:39