1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright (C) 2002-2020 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not visit scip.zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15
16 /**@file expr.c
17 * @ingroup OTHER_CFILES
18 * @brief functions for algebraic expressions
19 * @author Ksenia Bestuzheva
20 * @author Benjamin Mueller
21 * @author Felipe Serrano
22 * @author Stefan Vigerske
23 */
24
25 #include <assert.h>
26 #include <ctype.h>
27
28 #include "scip/expr.h"
29 #include "scip/struct_expr.h"
30 #include "scip/pub_misc.h"
31 #include "scip/clock.h"
32 #include "scip/set.h"
33 #include "scip/pub_var.h"
34 #include "scip/sol.h"
35 #include "scip/tree.h"
36 #include "scip/struct_set.h"
37 #include "scip/struct_stat.h"
38 #include "scip/nlpi_ipopt.h" /* for LAPACK */
39
40 /*lint -e440*/
41 /*lint -e441*/
42 /*lint -e777*/
43
44 /*
45 * Data structures
46 */
47
48 /** printing to file data */
49 struct SCIP_ExprPrintData
50 {
51 FILE* file; /**< file to print to */
52 SCIP_EXPRITER* iterator; /**< iterator to use */
53 SCIP_Bool closefile; /**< whether file need to be closed when finished printing */
54 SCIP_HASHMAP* leaveexprs; /**< hashmap storing leave (no children) expressions */
55 SCIP_EXPRPRINT_WHAT whattoprint; /**< flags that indicate what to print for each expression */
56 };
57
58 /*
59 * Local methods
60 */
61
62 /** frees an expression */
63 static
64 SCIP_RETCODE freeExpr(
65 BMS_BLKMEM* blkmem, /**< block memory */
66 SCIP_EXPR** expr /**< pointer to free the expression */
67 )
68 {
69 assert(expr != NULL);
70 assert(*expr != NULL);
71 assert((*expr)->nuses == 1);
72 assert((*expr)->quaddata == NULL);
73 assert((*expr)->ownerdata == NULL);
74
75 /* free children array, if any */
76 BMSfreeBlockMemoryArrayNull(blkmem, &(*expr)->children, (*expr)->childrensize);
77
78 BMSfreeBlockMemory(blkmem, expr);
79 assert(*expr == NULL);
80
81 return SCIP_OKAY;
82 }
83
84 /*
85 * quadratic representation of expression
86 */
87
88 /** first time seen quadratically and
89 * seen before linearly --> --nlinterms; assign 2; ++nquadterms
90 * not seen before linearly --> assing 1; ++nquadterms
91 *
92 * seen before --> assign += 1
93 */
94 static
95 SCIP_RETCODE quadDetectProcessExpr(
96 SCIP_EXPR* expr, /**< the expression */
97 SCIP_HASHMAP* seenexpr, /**< hash map */
98 int* nquadterms, /**< number of quadratic terms */
99 int* nlinterms /**< number of linear terms */
100 )
101 {
102 if( SCIPhashmapExists(seenexpr, (void*)expr) )
103 {
104 int nseen = SCIPhashmapGetImageInt(seenexpr, (void*)expr);
105
106 if( nseen < 0 )
107 {
108 /* only seen linearly before */
109 assert(nseen == -1);
110
111 --*nlinterms;
112 ++*nquadterms;
113 SCIP_CALL( SCIPhashmapSetImageInt(seenexpr, (void*)expr, 2) );
114 }
115 else
116 {
117 assert(nseen > 0);
118 SCIP_CALL( SCIPhashmapSetImageInt(seenexpr, (void*)expr, nseen + 1) );
119 }
120 }
121 else
122 {
123 ++*nquadterms;
124 SCIP_CALL( SCIPhashmapInsertInt(seenexpr, (void*)expr, 1) );
125 }
126
127 return SCIP_OKAY;
128 }
129
130 /** returns a quadexprterm that contains the expr
131 *
132 * it either finds one that already exists or creates a new one
133 */
134 static
135 SCIP_RETCODE quadDetectGetQuadexprterm(
136 BMS_BLKMEM* blkmem, /**< block memory */
137 SCIP_EXPR* expr, /**< the expression */
138 SCIP_HASHMAP* expr2idx, /**< map: expr to index in quadexpr->quadexprterms */
139 SCIP_HASHMAP* seenexpr, /**< map: expr to number of times it was seen */
140 SCIP_QUADEXPR* quadexpr, /**< data of quadratic representation of expression */
141 SCIP_QUADEXPR_QUADTERM** quadexprterm /**< buffer to store quadexprterm */
142 )
143 {
144 assert(expr != NULL);
145 assert(expr2idx != NULL);
146 assert(quadexpr != NULL);
147 assert(quadexprterm != NULL);
148
149 if( SCIPhashmapExists(expr2idx, (void*)expr) )
150 {
151 *quadexprterm = &quadexpr->quadexprterms[SCIPhashmapGetImageInt(expr2idx, (void*)expr)];
152 assert((*quadexprterm)->expr == expr);
153 }
154 else
155 {
156 SCIP_CALL( SCIPhashmapInsertInt(expr2idx, expr, quadexpr->nquadexprs) );
157 *quadexprterm = &quadexpr->quadexprterms[quadexpr->nquadexprs];
158 ++quadexpr->nquadexprs;
159
160 (*quadexprterm)->expr = expr;
161 (*quadexprterm)->sqrcoef = 0.0;
162 (*quadexprterm)->sqrexpr = NULL;
163 (*quadexprterm)->lincoef = 0.0;
164 (*quadexprterm)->nadjbilin = 0;
165 (*quadexprterm)->adjbilinsize = SCIPhashmapGetImageInt(seenexpr, (void*)expr);
166 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*quadexprterm)->adjbilin, (*quadexprterm)->adjbilinsize) );
167 }
168
169 return SCIP_OKAY;
170 }
171
172
173 /** evaluate and forward-differentiate expression
174 *
175 * also initializes derivative and bardot to 0.0
176 */
177 static
178 SCIP_RETCODE evalAndDiff(
179 SCIP_SET* set, /**< global SCIP settings */
180 SCIP_STAT* stat, /**< dynamic problem statistics */
181 BMS_BLKMEM* blkmem, /**< block memory */
182 SCIP_EXPR* expr, /**< expression to be evaluated */
183 SCIP_SOL* sol, /**< solution to be evaluated */
184 SCIP_Longint soltag, /**< tag that uniquely identifies the solution (with its values), or 0. */
185 SCIP_SOL* direction /**< direction for directional derivative */
186 )
187 {
188 SCIP_EXPRITER* it;
189
190 assert(set != NULL);
191 assert(stat != NULL);
192 assert(blkmem != NULL);
193 assert(expr != NULL);
194
195 /* assume we'll get a domain error, so we don't have to get this expr back if we abort the iteration
196 * if there is no domain error, then we will overwrite the evalvalue in the last leaveexpr stage
197 */
198 expr->evalvalue = SCIP_INVALID;
199 expr->evaltag = soltag;
200 expr->dot = SCIP_INVALID;
201
202 /* start a new difftag */
203 ++stat->exprlastdifftag;
204
205 SCIP_CALL( SCIPexpriterCreate(stat, blkmem, &it) );
206 SCIP_CALL( SCIPexpriterInit(it, expr, SCIP_EXPRITER_DFS, TRUE) );
207 SCIPexpriterSetStagesDFS(it, SCIP_EXPRITER_LEAVEEXPR);
208
209 for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
210 {
211 /* evaluate expression only if necessary */
212 if( soltag == 0 || expr->evaltag != soltag )
213 {
214 SCIP_CALL( SCIPexprhdlrEvalExpr(expr->exprhdlr, set, NULL, expr, &expr->evalvalue, NULL, sol) );
215
216 expr->evaltag = soltag;
217 }
218
219 if( expr->evalvalue == SCIP_INVALID )
220 break;
221
222 if( expr->difftag != stat->exprlastdifftag )
223 {
224 /* compute forward diff */
225 SCIP_CALL( SCIPexprhdlrFwDiffExpr(expr->exprhdlr, set, expr, &expr->dot, direction) );
226
227 if( expr->dot == SCIP_INVALID )
228 break;
229
230 expr->derivative = 0.0;
231 expr->bardot = 0.0;
232 expr->difftag = stat->exprlastdifftag;
233 }
234 }
235
236 SCIPexpriterFree(&it);
237
238 return SCIP_OKAY;
239 }
240
241
242 /*
243 * Public methods
244 */
245
246 /** create expression handler */
247 SCIP_RETCODE SCIPexprhdlrCreate(
248 BMS_BLKMEM* blkmem, /**< block memory */
249 SCIP_EXPRHDLR** exprhdlr, /**< buffer where to store created expression handler */
250 const char* name, /**< name of expression handler (must not be NULL) */
251 const char* desc, /**< description of expression handler (can be NULL) */
252 unsigned int precedence, /**< precedence of expression operation (used for printing) */
253 SCIP_DECL_EXPREVAL((*eval)), /**< point evaluation callback (must not be NULL) */
254 SCIP_EXPRHDLRDATA* data /**< data of expression handler (can be NULL) */
255 )
256 {
257 assert(exprhdlr != NULL);
258 assert(name != NULL);
259
260 SCIP_ALLOC( BMSallocClearBlockMemory(blkmem, exprhdlr) );
261
262 SCIP_ALLOC( BMSduplicateMemoryArray(&(*exprhdlr)->name, name, strlen(name)+1) );
263 if( desc != NULL )
264 {
265 SCIP_ALLOC( BMSduplicateMemoryArray(&(*exprhdlr)->desc, desc, strlen(desc)+1) );
266 }
267
268 (*exprhdlr)->precedence = precedence;
269 (*exprhdlr)->eval = eval;
270 (*exprhdlr)->data = data;
271
272 /* create clocks */
273 SCIP_CALL( SCIPclockCreate(&(*exprhdlr)->estimatetime, SCIP_CLOCKTYPE_DEFAULT) );
274 SCIP_CALL( SCIPclockCreate(&(*exprhdlr)->intevaltime, SCIP_CLOCKTYPE_DEFAULT) );
275 SCIP_CALL( SCIPclockCreate(&(*exprhdlr)->proptime, SCIP_CLOCKTYPE_DEFAULT) );
276 SCIP_CALL( SCIPclockCreate(&(*exprhdlr)->simplifytime, SCIP_CLOCKTYPE_DEFAULT) );
277
278 return SCIP_OKAY;
279 }
280
281 /** frees expression handler */
282 SCIP_RETCODE SCIPexprhdlrFree(
283 SCIP_EXPRHDLR** exprhdlr, /**< pointer to expression handler to be freed */
284 SCIP_SET* set, /**< global SCIP settings */
285 BMS_BLKMEM* blkmem /**< block memory */
286 )
287 {
288 if( (*exprhdlr)->freehdlr != NULL )
289 {
290 SCIP_CALL( (*exprhdlr)->freehdlr(set->scip, *exprhdlr, &(*exprhdlr)->data) );
291 }
292
293 /* free clocks */
294 SCIPclockFree(&(*exprhdlr)->simplifytime);
295 SCIPclockFree(&(*exprhdlr)->intevaltime);
296 SCIPclockFree(&(*exprhdlr)->proptime);
297 SCIPclockFree(&(*exprhdlr)->estimatetime);
298
299 BMSfreeMemoryArrayNull(&(*exprhdlr)->desc);
300 BMSfreeMemoryArray(&(*exprhdlr)->name);
301
302 BMSfreeBlockMemory(blkmem, exprhdlr);
303
304 return SCIP_OKAY;
305 }
306
307 /**@addtogroup PublicExprHandlerMethods
308 * @{
309 */
310
311 /** set the expression handler callbacks to copy and free an expression handler */
312 void SCIPexprhdlrSetCopyFreeHdlr(
313 SCIP_EXPRHDLR* exprhdlr, /**< expression handler */
314 SCIP_DECL_EXPRCOPYHDLR((*copyhdlr)), /**< handler copy callback (can be NULL) */
315 SCIP_DECL_EXPRFREEHDLR((*freehdlr)) /**< handler free callback (can be NULL) */
316 )
317 {
318 assert(exprhdlr != NULL);
319
320 exprhdlr->copyhdlr = copyhdlr;
321 exprhdlr->freehdlr = freehdlr;
322 }
323
324 /** set the expression handler callbacks to copy and free expression data */
325 void SCIPexprhdlrSetCopyFreeData(
326 SCIP_EXPRHDLR* exprhdlr, /**< expression handler */
327 SCIP_DECL_EXPRCOPYDATA((*copydata)), /**< expression data copy callback (can be NULL for expressions
328 without data) */
329 SCIP_DECL_EXPRFREEDATA((*freedata)) /**< expression data free callback (can be NULL if data does not
330 need to be freed) */
331 )
332 { /*lint --e{715}*/
333 assert(exprhdlr != NULL);
334
335 exprhdlr->copydata = copydata;
336 exprhdlr->freedata = freedata;
337 }
338
339 /** set the print callback of an expression handler */
340 void SCIPexprhdlrSetPrint(
341 SCIP_EXPRHDLR* exprhdlr, /**< expression handler */
342 SCIP_DECL_EXPRPRINT((*print)) /**< print callback (can be NULL) */
343 )
344 {
345 assert(exprhdlr != NULL);
346
347 exprhdlr->print = print;
348 }
349
350 /** set the parse callback of an expression handler */
351 void SCIPexprhdlrSetParse(
352 SCIP_EXPRHDLR* exprhdlr, /**< expression handler */
353 SCIP_DECL_EXPRPARSE((*parse)) /**< parse callback (can be NULL) */
354 )
355 {
356 assert(exprhdlr != NULL);
357
358 exprhdlr->parse = parse;
359 }
360
361 /** set the curvature detection callback of an expression handler */
362 void SCIPexprhdlrSetCurvature(
363 SCIP_EXPRHDLR* exprhdlr, /**< expression handler */
364 SCIP_DECL_EXPRCURVATURE((*curvature)) /**< curvature detection callback (can be NULL) */
365 )
366 {
367 assert(exprhdlr != NULL);
368
369 exprhdlr->curvature = curvature;
370 }
371
372 /** set the monotonicity detection callback of an expression handler */
373 void SCIPexprhdlrSetMonotonicity(
374 SCIP_EXPRHDLR* exprhdlr, /**< expression handler */
375 SCIP_DECL_EXPRMONOTONICITY((*monotonicity)) /**< monotonicity detection callback (can be NULL) */
376 )
377 {
378 assert(exprhdlr != NULL);
379
380 exprhdlr->monotonicity = monotonicity;
381 }
382
383 /** set the integrality detection callback of an expression handler */
384 void SCIPexprhdlrSetIntegrality(
385 SCIP_EXPRHDLR* exprhdlr, /**< expression handler */
386 SCIP_DECL_EXPRINTEGRALITY((*integrality)) /**< integrality detection callback (can be NULL) */
387 )
388 {
389 assert(exprhdlr != NULL);
390
391 exprhdlr->integrality = integrality;
392 }
393
394 /** set the hash callback of an expression handler */
395 void SCIPexprhdlrSetHash(
396 SCIP_EXPRHDLR* exprhdlr, /**< expression handler */
397 SCIP_DECL_EXPRHASH((*hash)) /**< hash callback (can be NULL) */
398 )
399 {
400 assert(exprhdlr != NULL);
401
402 exprhdlr->hash = hash;
403 }
404
405 /** set the compare callback of an expression handler */
406 void SCIPexprhdlrSetCompare(
407 SCIP_EXPRHDLR* exprhdlr, /**< expression handler */
408 SCIP_DECL_EXPRCOMPARE((*compare)) /**< compare callback (can be NULL) */
409 )
410 {
411 assert(exprhdlr != NULL);
412
413 exprhdlr->compare = compare;
414 }
415
416 /** set differentiation callbacks of an expression handler */
417 void SCIPexprhdlrSetDiff(
418 SCIP_EXPRHDLR* exprhdlr, /**< expression handler */
419 SCIP_DECL_EXPRBWDIFF((*bwdiff)), /**< backward derivative evaluation callback (can be NULL) */
420 SCIP_DECL_EXPRFWDIFF((*fwdiff)), /**< forward derivative evaluation callback (can be NULL) */
421 SCIP_DECL_EXPRBWFWDIFF((*bwfwdiff)) /**< backward-forward derivative evaluation callback (can be NULL) */
422 )
423 {
424 assert(exprhdlr != NULL);
425
426 exprhdlr->bwdiff = bwdiff;
427 exprhdlr->fwdiff = fwdiff;
428 exprhdlr->bwfwdiff = bwfwdiff;
429 }
430
431 /** set the interval evaluation callback of an expression handler */
432 void SCIPexprhdlrSetIntEval(
433 SCIP_EXPRHDLR* exprhdlr, /**< expression handler */
434 SCIP_DECL_EXPRINTEVAL((*inteval)) /**< interval evaluation callback (can be NULL) */
435 )
436 {
437 assert(exprhdlr != NULL);
438
439 exprhdlr->inteval = inteval;
440 }
441
442 /** set the simplify callback of an expression handler */
443 void SCIPexprhdlrSetSimplify(
444 SCIP_EXPRHDLR* exprhdlr, /**< expression handler */
445 SCIP_DECL_EXPRSIMPLIFY((*simplify)) /**< simplify callback (can be NULL) */
446 )
447 {
448 assert(exprhdlr != NULL);
449
450 exprhdlr->simplify = simplify;
451 }
452
453 /** set the reverse propagation callback of an expression handler */
454 void SCIPexprhdlrSetReverseProp(
455 SCIP_EXPRHDLR* exprhdlr, /**< expression handler */
456 SCIP_DECL_EXPRREVERSEPROP((*reverseprop)) /**< reverse propagation callback (can be NULL) */
457 )
458 {
459 assert(exprhdlr != NULL);
460
461 exprhdlr->reverseprop = reverseprop;
462 }
463
464 /** set the estimation callbacks of an expression handler */
465 void SCIPexprhdlrSetEstimate(
466 SCIP_EXPRHDLR* exprhdlr, /**< expression handler */
467 SCIP_DECL_EXPRINITESTIMATES((*initestimates)), /**< initial estimators callback (can be NULL) */
468 SCIP_DECL_EXPRESTIMATE((*estimate)) /**< estimator callback (can be NULL) */
469 )
470 {
471 assert(exprhdlr != NULL);
472
473 exprhdlr->initestimates = initestimates;
474 exprhdlr->estimate = estimate;
475 }
476
477 /** gives the name of an expression handler */
478 const char* SCIPexprhdlrGetName(
479 SCIP_EXPRHDLR* exprhdlr /**< expression handler */
480 )
481 {
482 assert(exprhdlr != NULL);
483
484 return exprhdlr->name;
485 }
486
487 /** gives the description of an expression handler (can be NULL) */
488 const char* SCIPexprhdlrGetDescription(
489 SCIP_EXPRHDLR* exprhdlr /**< expression handler */
490 )
491 {
492 assert(exprhdlr != NULL);
493
494 return exprhdlr->desc;
495 }
496
497 /** gives the precedence of an expression handler */
498 unsigned int SCIPexprhdlrGetPrecedence(
499 SCIP_EXPRHDLR* exprhdlr /**< expression handler */
500 )
501 {
502 assert(exprhdlr != NULL);
503
504 return exprhdlr->precedence;
505 }
506
507 /** gives the data of an expression handler */
508 SCIP_EXPRHDLRDATA* SCIPexprhdlrGetData(
509 SCIP_EXPRHDLR* exprhdlr /**< expression handler */
510 )
511 {
512 assert(exprhdlr != NULL);
513
514 return exprhdlr->data;
515 }
516
517 /** returns whether expression handler implements the print callback */
518 SCIP_Bool SCIPexprhdlrHasPrint(
519 SCIP_EXPRHDLR* exprhdlr /**< expression handler */
520 )
521 {
522 assert(exprhdlr != NULL);
523
524 return exprhdlr->print != NULL;
525 }
526
527 /** returns whether expression handler implements the backward differentiation callback */
528 SCIP_Bool SCIPexprhdlrHasBwdiff(
529 SCIP_EXPRHDLR* exprhdlr /**< expression handler */
530 )
531 {
532 assert(exprhdlr != NULL);
533
534 return exprhdlr->bwdiff != NULL;
535 }
536
537 /** returns whether expression handler implements the forward differentiation callback */
538 SCIP_Bool SCIPexprhdlrHasFwdiff(
539 SCIP_EXPRHDLR* exprhdlr /**< expression handler */
540 )
541 {
542 assert(exprhdlr != NULL);
543
544 return exprhdlr->fwdiff != NULL;
545 }
546
547 /** returns whether expression handler implements the interval evaluation callback */
548 SCIP_Bool SCIPexprhdlrHasIntEval(
549 SCIP_EXPRHDLR* exprhdlr /**< expression handler */
550 )
551 {
552 assert(exprhdlr != NULL);
553
554 return exprhdlr->inteval != NULL;
555 }
556
557 /** returns whether expression handler implements the estimator callback */
558 SCIP_Bool SCIPexprhdlrHasEstimate(
559 SCIP_EXPRHDLR* exprhdlr /**< expression handler */
560 )
561 {
562 assert(exprhdlr != NULL);
563
564 return exprhdlr->estimate != NULL;
565 }
566
567 /** returns whether expression handler implements the initial estimators callback */
568 SCIP_Bool SCIPexprhdlrHasInitEstimates(
569 SCIP_EXPRHDLR* exprhdlr /**< expression handler */
570 )
571 {
572 assert(exprhdlr != NULL);
573
574 return exprhdlr->initestimates != NULL;
575 }
576
577 /** returns whether expression handler implements the simplification callback */
578 SCIP_Bool SCIPexprhdlrHasSimplify(
579 SCIP_EXPRHDLR* exprhdlr /**< expression handler */
580 )
581 {
582 assert(exprhdlr != NULL);
583
584 return exprhdlr->simplify != NULL;
585 }
586
587 /** returns whether expression handler implements the curvature callback */
588 SCIP_Bool SCIPexprhdlrHasCurvature(
589 SCIP_EXPRHDLR* exprhdlr /**< expression handler */
590 )
591 {
592 assert(exprhdlr != NULL);
593
594 return exprhdlr->curvature != NULL;
595 }
596
597 /** returns whether expression handler implements the monotonicity callback */
598 SCIP_Bool SCIPexprhdlrHasMonotonicity(
599 SCIP_EXPRHDLR* exprhdlr /**< expression handler */
600 )
601 {
602 assert(exprhdlr != NULL);
603
604 return exprhdlr->monotonicity != NULL;
605 }
606
607 /** returns whether expression handler implements the reverse propagation callback */
608 SCIP_Bool SCIPexprhdlrHasReverseProp(
609 SCIP_EXPRHDLR* exprhdlr /**< expression handler */
610 )
611 {
612 assert(exprhdlr != NULL);
613
614 return exprhdlr->reverseprop != NULL;
615 }
616
617 /** compares two expression handler w.r.t. their name */
618 SCIP_DECL_SORTPTRCOMP(SCIPexprhdlrComp)
619 {
620 return strcmp(((SCIP_EXPRHDLR*)elem1)->name, ((SCIP_EXPRHDLR*)elem2)->name);
621 }
622
623 /** gets number of times an expression has been created with given expression handler */
624 unsigned int SCIPexprhdlrGetNCreated(
625 SCIP_EXPRHDLR* exprhdlr /**< expression handler */
626 )
627 {
628 assert(exprhdlr != NULL);
629
630 return exprhdlr->ncreated;
631 }
632
633 /** gets number of times the interval evaluation callback was called */
634 SCIP_Longint SCIPexprhdlrGetNIntevalCalls(
635 SCIP_EXPRHDLR* exprhdlr /**< expression handler */
636 )
637 {
638 assert(exprhdlr != NULL);
639
640 return exprhdlr->nintevalcalls;
641 }
642
643 /** gets time spend in interval evaluation callback */
644 SCIP_Real SCIPexprhdlrGetIntevalTime(
645 SCIP_EXPRHDLR* exprhdlr /**< expression handler */
646 )
647 {
648 assert(exprhdlr != NULL);
649
650 return SCIPclockGetTime(exprhdlr->intevaltime);
651 }
652
653 /** gets number of times the reverse propagation callback was called */
654 SCIP_Longint SCIPexprhdlrGetNReversepropCalls(
655 SCIP_EXPRHDLR* exprhdlr /**< expression handler */
656 )
657 {
658 assert(exprhdlr != NULL);
659
660 return exprhdlr->npropcalls;
661 }
662
663 /** gets time spend in reverse propagation callback */
664 SCIP_Real SCIPexprhdlrGetReversepropTime(
665 SCIP_EXPRHDLR* exprhdlr /**< expression handler */
666 )
667 {
668 assert(exprhdlr != NULL);
669
670 return SCIPclockGetTime(exprhdlr->proptime);
671 }
672
673 /** gets number of times an empty interval was found in reverse propagation */
674 SCIP_Longint SCIPexprhdlrGetNCutoffs(
675 SCIP_EXPRHDLR* exprhdlr /**< expression handler */
676 )
677 {
678 assert(exprhdlr != NULL);
679
680 return exprhdlr->ncutoffs;
681 }
682
683 /** gets number of times a bound reduction was found in reverse propagation (and accepted by caller) */
684 SCIP_Longint SCIPexprhdlrGetNDomainReductions(
685 SCIP_EXPRHDLR* exprhdlr /**< expression handler */
686 )
687 {
688 assert(exprhdlr != NULL);
689
690 return exprhdlr->ndomreds;
691 }
692
693 /** increments the domain reductions count of an expression handler */
694 void SCIPexprhdlrIncrementNDomainReductions(
695 SCIP_EXPRHDLR* exprhdlr, /**< expression handler */
696 int nreductions /**< number of reductions to add to counter */
697 )
698 {
699 assert(exprhdlr != NULL);
700 assert(nreductions >= 0);
701
702 exprhdlr->ndomreds += nreductions;
703 }
704
705 /** gets number of times the estimation callback was called */
706 SCIP_Longint SCIPexprhdlrGetNEstimateCalls(
707 SCIP_EXPRHDLR* exprhdlr /**< expression handler */
708 )
709 {
710 assert(exprhdlr != NULL);
711
712 return exprhdlr->nestimatecalls;
713 }
714
715 /** gets time spend in estimation callback */
716 SCIP_Real SCIPexprhdlrGetEstimateTime(
717 SCIP_EXPRHDLR* exprhdlr /**< expression handler */
718 )
719 {
720 assert(exprhdlr != NULL);
721
722 return SCIPclockGetTime(exprhdlr->estimatetime);
723 }
724
725 /** gets number of times branching candidates reported by of this expression handler were used to
726 * assemble branching candidates
727 *
728 * that is, how often did we consider branching on a child of this expression
729 */
730 SCIP_Longint SCIPexprhdlrGetNBranchings(
731 SCIP_EXPRHDLR* exprhdlr /**< expression handler */
732 )
733 {
734 assert(exprhdlr != NULL);
735
736 return exprhdlr->nbranchscores;
737 }
738
739 /** increments the branching candidates count of an expression handler */
740 void SCIPexprhdlrIncrementNBranchings(
741 SCIP_EXPRHDLR* exprhdlr /**< expression handler */
742 )
743 {
744 assert(exprhdlr != NULL);
745
746 ++exprhdlr->nbranchscores;
747 }
748
749 /** gets number of times the simplify callback was called */
750 SCIP_Longint SCIPexprhdlrGetNSimplifyCalls(
751 SCIP_EXPRHDLR* exprhdlr /**< expression handler */
752 )
753 {
754 assert(exprhdlr != NULL);
755
756 return exprhdlr->nsimplifycalls;
757 }
758
759 /** gets time spend in simplify callback */
760 SCIP_Real SCIPexprhdlrGetSimplifyTime(
761 SCIP_EXPRHDLR* exprhdlr /**< expression handler */
762 )
763 {
764 assert(exprhdlr != NULL);
765
766 return SCIPclockGetTime(exprhdlr->simplifytime);
767 }
768
769 /** gets number of times the simplify callback found a simplification */
770 SCIP_Longint SCIPexprhdlrGetNSimplifications(
771 SCIP_EXPRHDLR* exprhdlr /**< expression handler */
772 )
773 {
774 assert(exprhdlr != NULL);
775
776 return exprhdlr->nsimplified;
777 }
778
779 /** @} */
780
781 /** copies the given expression handler to a new scip */
782 SCIP_RETCODE SCIPexprhdlrCopyInclude(
783 SCIP_EXPRHDLR* exprhdlr, /**< expression handler */
784 SCIP_SET* targetset /**< SCIP_SET of SCIP to copy to */
785 )
786 {
787 assert(exprhdlr != NULL);
788 assert(targetset != NULL);
789 assert(targetset->scip != NULL);
790
791 if( exprhdlr->copyhdlr != NULL )
792 {
793 SCIPsetDebugMsg(targetset, "including expression handler <%s> in subscip %p\n",
794 SCIPexprhdlrGetName(exprhdlr), (void*)targetset->scip);
795 SCIP_CALL( exprhdlr->copyhdlr(targetset->scip, exprhdlr) );
796 }
797 else
798 {
799 SCIPsetDebugMsg(targetset, "expression handler <%s> cannot be copied to subscip %p due "
800 "to missing copyhdlr callback\n", SCIPexprhdlrGetName(exprhdlr), (void*)targetset->scip);
801 }
802
803 return SCIP_OKAY;
804 }
805
806 /** initialization of expression handler (resets statistics) */
807 void SCIPexprhdlrInit(
808 SCIP_EXPRHDLR* exprhdlr, /**< expression handler */
809 SCIP_SET* set /**< global SCIP settings */
810 )
811 {
812 assert(exprhdlr != NULL);
813
814 if( set->misc_resetstat )
815 {
816 exprhdlr->ncreated = 0;
817 exprhdlr->nestimatecalls = 0;
818 exprhdlr->nintevalcalls = 0;
819 exprhdlr->npropcalls = 0;
820 exprhdlr->ncutoffs = 0;
821 exprhdlr->ndomreds = 0;
822 exprhdlr->nbranchscores = 0;
823 exprhdlr->nsimplifycalls = 0;
824 exprhdlr->nsimplified = 0;
825
826 SCIPclockReset(exprhdlr->estimatetime);
827 SCIPclockReset(exprhdlr->intevaltime);
828 SCIPclockReset(exprhdlr->proptime);
829 SCIPclockReset(exprhdlr->simplifytime);
830 }
831 }
832
833 /** calls the print callback of an expression handler
834 *
835 * The method prints an expression.
836 * It is called while iterating over the expression graph at different stages.
837 *
838 * @see SCIP_DECL_EXPRPRINT
839 */
840 SCIP_RETCODE SCIPexprhdlrPrintExpr(
841 SCIP_EXPRHDLR* exprhdlr, /**< expression handler */
842 SCIP_SET* set, /**< global SCIP settings */
843 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
844 SCIP_EXPR* expr, /**< expression */
845 SCIP_EXPRITER_STAGE stage, /**< stage of expression iteration */
846 int currentchild, /**< index of current child if in stage visitingchild or visitedchild */
847 unsigned int parentprecedence, /**< precedence of parent */
848 FILE* file /**< the file to print to */
849 )
850 {
851 assert(exprhdlr != NULL);
852 assert(set != NULL);
853 assert(expr != NULL);
854 assert(expr->exprhdlr == exprhdlr);
855 assert(messagehdlr != NULL);
856
857 if( SCIPexprhdlrHasPrint(exprhdlr) )
858 {
859 SCIP_CALL( exprhdlr->print(set->scip, expr, stage, currentchild, parentprecedence, file) );
860 }
861 else
862 {
863 /* default: <hdlrname>(<child1>, <child2>, ...) */
864 switch( stage )
865 {
866 case SCIP_EXPRITER_ENTEREXPR :
867 {
868 SCIPmessageFPrintInfo(messagehdlr, file, "%s", SCIPexprhdlrGetName(expr->exprhdlr));
869 if( expr->nchildren > 0 )
870 {
871 SCIPmessageFPrintInfo(messagehdlr, file, "(");
872 }
873 break;
874 }
875
876 case SCIP_EXPRITER_VISITEDCHILD :
877 {
878 assert(currentchild >= 0);
879 assert(currentchild < expr->nchildren);
880 if( currentchild < expr->nchildren-1 )
881 {
882 SCIPmessageFPrintInfo(messagehdlr, file, ", ");
883 }
884 else
885 {
886 SCIPmessageFPrintInfo(messagehdlr, file, ")");
887 }
888
889 break;
890 }
891
892 case SCIP_EXPRITER_VISITINGCHILD :
893 case SCIP_EXPRITER_LEAVEEXPR :
894 default:
895 break;
896 }
897 }
898
899 return SCIP_OKAY;
900 }
901
902 /** calls the parse callback of an expression handler
903 *
904 * The method parses an expression.
905 * It should be called when parsing an expression and an operator with the expr handler name is found.
906 *
907 * @see SCIP_DECL_EXPRPARSE
908 */
909 SCIP_RETCODE SCIPexprhdlrParseExpr(
910 SCIP_EXPRHDLR* exprhdlr, /**< expression handler */
911 SCIP_SET* set, /**< global SCIP settings */
912 const char* string, /**< string containing expression to be parse */
913 const char** endstring, /**< buffer to store the position of string after parsing */
914 SCIP_EXPR** expr, /**< buffer to store the parsed expression */
915 SCIP_Bool* success, /**< buffer to store whether the parsing was successful or not */
916 SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), /**< function to call on expression copy to create ownerdata */
917 void* ownercreatedata /**< data to pass to ownercreate */
918 )
919 {
920 assert(exprhdlr != NULL);
921 assert(set != NULL);
922 assert(expr != NULL);
923
924 *expr = NULL;
925
926 if( exprhdlr->parse == NULL )
927 {
928 /* TODO we could just look for a comma separated list of operands and try to initialize the expr with this one?
929 * That would be sufficient for sin, cos, exp, log, abs, for example.
930 */
931 SCIPdebugMessage("Expression handler <%s> has no parsing method.\n", SCIPexprhdlrGetName(exprhdlr));
932 *success = FALSE;
933 return SCIP_OKAY;
934 }
935
936 /* give control to exprhdlr's parser */
937 SCIP_CALL( exprhdlr->parse(set->scip, exprhdlr, string, endstring, expr, success, ownercreate, ownercreatedata) );
938
939 assert(*success || (*expr == NULL));
940
941 return SCIP_OKAY;
942 }
943
944 /** calls the curvature check callback of an expression handler
945 *
946 * @see SCIP_DECL_EXPRCURVATURE
947 */
948 SCIP_RETCODE SCIPexprhdlrCurvatureExpr(
949 SCIP_EXPRHDLR* exprhdlr, /**< expression handler */
950 SCIP_SET* set, /**< global SCIP settings */
951 SCIP_EXPR* expr, /**< expression to check the curvature for */
952 SCIP_EXPRCURV exprcurvature, /**< desired curvature of this expression */
953 SCIP_Bool* success, /**< buffer to store whether the desired curvature be obtained */
954 SCIP_EXPRCURV* childcurv /**< array to store required curvature for each child */
955 )
956 {
957 assert(exprhdlr != NULL);
958 assert(set != NULL);
959 assert(expr != NULL);
960 assert(expr->exprhdlr == exprhdlr);
961 assert(success != NULL);
962
963 *success = FALSE;
964
|
(1) Event cond_true: |
Condition "exprhdlr->curvature != NULL", taking true branch. |
965 if( exprhdlr->curvature != NULL )
966 {
|
(2) Event callee_ptr_arith: |
Performing pointer arithmetic on "childcurv" in callee "*exprhdlr->curvature". (The function pointer resolves to "curvatureSum".) [details] |
967 SCIP_CALL( exprhdlr->curvature(set->scip, expr, exprcurvature, success, childcurv) );
968 }
969
970 return SCIP_OKAY;
971 }
972
973 /** calls the monotonicity check callback of an expression handler
974 *
975 * @see SCIP_DECL_EXPRMONOTONICITY
976 */
977 SCIP_RETCODE SCIPexprhdlrMonotonicityExpr(
978 SCIP_EXPRHDLR* exprhdlr, /**< expression handler */
979 SCIP_SET* set, /**< global SCIP settings */
980 SCIP_EXPR* expr, /**< expression to check the monotonicity for */
981 int childidx, /**< index of the considered child expression */
982 SCIP_MONOTONE* result /**< buffer to store the monotonicity */
983 )
984 {
985 assert(exprhdlr != NULL);
986 assert(set != NULL);
987 assert(expr != NULL);
988 assert(expr->exprhdlr == exprhdlr);
989 assert(result != NULL);
990
991 *result = SCIP_MONOTONE_UNKNOWN;
992
993 /* check whether the expression handler implements the monotonicity callback */
994 if( exprhdlr->monotonicity != NULL )
995 {
996 SCIP_CALL( exprhdlr->monotonicity(set->scip, expr, childidx, result) );
997 }
998
999 return SCIP_OKAY;
1000 }
1001
1002 /** calls the integrality check callback of an expression handler
1003 *
1004 * @see SCIP_DECL_EXPRINTEGRALITY
1005 */
1006 SCIP_RETCODE SCIPexprhdlrIntegralityExpr(
1007 SCIP_EXPRHDLR* exprhdlr, /**< expression handler */
1008 SCIP_SET* set, /**< global SCIP settings */
1009 SCIP_EXPR* expr, /**< expression to check integrality for */
1010 SCIP_Bool* isintegral /**< buffer to store whether expression is integral */
1011 )
1012 {
1013 assert(exprhdlr != NULL);
1014 assert(set != NULL);
1015 assert(expr != NULL);
1016 assert(expr->exprhdlr == exprhdlr);
1017 assert(isintegral != NULL);
1018
1019 *isintegral = FALSE;
1020
1021 /* check whether the expression handler implements the monotonicity callback */
1022 if( exprhdlr->integrality != NULL )
1023 {
1024 SCIP_CALL( exprhdlr->integrality(set->scip, expr, isintegral) );
1025 }
1026
1027 return SCIP_OKAY;
1028 }
1029
1030 /** calls the hash callback of an expression handler
1031 *
1032 * The method hashes an expression by taking the hashes of its children into account.
1033 *
1034 * @see SCIP_DECL_EXPRHASH
1035 */
1036 SCIP_RETCODE SCIPexprhdlrHashExpr(
1037 SCIP_EXPRHDLR* exprhdlr, /**< expression handler */
1038 SCIP_SET* set, /**< global SCIP settings */
1039 SCIP_EXPR* expr, /**< expression to be hashed */
1040 unsigned int* hashkey, /**< buffer to store the hash value */
1041 unsigned int* childrenhashes /**< array with hash values of children */
1042 )
1043 {
1044 assert(exprhdlr != NULL);
1045 assert(set != NULL);
1046 assert(expr != NULL);
1047 assert(expr->exprhdlr == exprhdlr);
1048 assert(hashkey != NULL);
1049 assert(childrenhashes != NULL || expr->nchildren == 0);
1050
1051 if( expr->exprhdlr->hash != NULL )
1052 {
1053 SCIP_CALL( expr->exprhdlr->hash(set->scip, expr, hashkey, childrenhashes) );
1054 }
1055 else
1056 {
1057 int i;
1058
1059 /* compute initial hash from expression handler name if callback is not implemented
1060 * this can lead to more collisions and thus a larger number of expensive expression compare calls
1061 */
1062 *hashkey = 0;
1063 for( i = 0; expr->exprhdlr->name[i] != '\0'; i++ )
1064 *hashkey += (unsigned int) expr->exprhdlr->name[i]; /*lint !e571*/
1065
1066 *hashkey = SCIPcalcFibHash((SCIP_Real)*hashkey);
1067
1068 /* now make use of the hashkeys of the children */
1069 for( i = 0; i < expr->nchildren; ++i )
1070 *hashkey ^= childrenhashes[i];
1071 }
1072
1073 return SCIP_OKAY;
1074 }
1075
1076 /** calls the compare callback of an expression handler
1077 *
1078 * The method receives two expressions, expr1 and expr2, and returns
1079 * - -1 if expr1 < expr2,
1080 * - 0 if expr1 = expr2,
1081 * - 1 if expr1 > expr2.
1082 *
1083 * @see SCIP_DECL_EXPRCOMPARE
1084 */
1085 int SCIPexprhdlrCompareExpr(
1086 SCIP_SET* set, /**< global SCIP settings */
1087 SCIP_EXPR* expr1, /**< first expression in comparison */
1088 SCIP_EXPR* expr2 /**< second expression in comparison */
1089 )
1090 {
1091 int i;
1092
1093 assert(expr1 != NULL);
1094 assert(expr2 != NULL);
1095 assert(expr1->exprhdlr == expr2->exprhdlr);
1096
1097 if( expr1->exprhdlr->compare != NULL )
1098 {
1099 /* enforces OR1-OR4 */
1100 return expr1->exprhdlr->compare(set->scip, expr1, expr2);
1101 }
1102
1103 /* enforces OR5: default comparison method of expressions of the same type:
1104 * expr1 < expr2 if and only if expr1_i = expr2_i for all i < k and expr1_k < expr2_k.
1105 * if there is no such k, use number of children to decide
1106 * if number of children is equal, both expressions are equal
1107 * @note: Warning, this method doesn't know about expression data. So if your expressions have special data,
1108 * you must implement the compare callback: SCIP_DECL_EXPRCOMPARE
1109 */
1110 for( i = 0; i < expr1->nchildren && i < expr2->nchildren; ++i )
1111 {
1112 int compareresult = SCIPexprCompare(set, expr1->children[i], expr2->children[i]);
1113 if( compareresult != 0 )
1114 return compareresult;
1115 }
1116
1117 return expr1->nchildren == expr2->nchildren ? 0 : expr1->nchildren < expr2->nchildren ? -1 : 1;
1118 }
1119
1120 /** calls the evaluation callback of an expression handler
1121 *
1122 * The method evaluates an expression by taking the values of its children into account.
1123 *
1124 * Further, allows to evaluate w.r.t. given expression and children values instead of those stored in children expressions.
1125 *
1126 * @see SCIP_DECL_EXPREVAL
1127 */
1128 SCIP_RETCODE SCIPexprhdlrEvalExpr(
1129 SCIP_EXPRHDLR* exprhdlr, /**< expression handler */
1130 SCIP_SET* set, /**< global SCIP settings */
1131 BMS_BUFMEM* bufmem, /**< buffer memory, can be NULL if childrenvals is NULL */
1132 SCIP_EXPR* expr, /**< expression to be evaluated */
1133 SCIP_Real* val, /**< buffer to store value of expression */
1134 SCIP_Real* childrenvals, /**< values for children, or NULL if values stored in children should be used */
1135 SCIP_SOL* sol /**< solution that is evaluated (can be NULL) */
1136 )
1137 {
1138 SCIP_Real* origvals = NULL;
1139
1140 assert(exprhdlr != NULL);
1141 assert(set != NULL);
1142 assert(expr != NULL);
1143 assert(expr->exprhdlr == exprhdlr);
1144 assert(exprhdlr->eval != NULL);
1145 assert(val != NULL);
1146
1147 /* temporarily overwrite the evalvalue in all children with values from childrenvals */
1148 if( childrenvals != NULL && expr->nchildren > 0 )
1149 {
1150 int c;
1151
1152 assert(bufmem != NULL);
1153
1154 SCIP_ALLOC( BMSallocBufferMemoryArray(bufmem, &origvals, expr->nchildren) );
1155
1156 for( c = 0; c < expr->nchildren; ++c )
1157 {
1158 origvals[c] = expr->children[c]->evalvalue;
1159 expr->children[c]->evalvalue = childrenvals[c];
1160 }
1161 }
1162
1163 /* call expression eval callback */
1164 SCIP_CALL( exprhdlr->eval(set->scip, expr, val, sol) );
1165
1166 /* if there was some evaluation error (e.g., overflow) that hasn't been caught yet, then do so now */
1167 if( !SCIPisFinite(*val) )
1168 *val = SCIP_INVALID;
1169
1170 /* restore original evalvalues in children */
1171 if( origvals != NULL )
1172 {
1173 int c;
1174 for( c = 0; c < expr->nchildren; ++c )
1175 expr->children[c]->evalvalue = origvals[c];
1176
1177 BMSfreeBufferMemoryArray(bufmem, &origvals);
1178 }
1179
1180 return SCIP_OKAY;
1181 }
1182
1183 /** calls the backward derivative evaluation callback of an expression handler
1184 *
1185 * The method should compute the partial derivative of expr w.r.t its child at childidx.
1186 * That is, it returns
1187 * \f[
1188 * \frac{\partial \text{expr}}{\partial \text{child}_{\text{childidx}}}
1189 * \f]
1190 *
1191 * Further, allows to differentiate w.r.t. given expression and children values instead of those stored in children expressions.
1192 *
1193 * @see SCIP_DECL_EXPRBWDIFF
1194 */
1195 SCIP_RETCODE SCIPexprhdlrBwDiffExpr(
1196 SCIP_EXPRHDLR* exprhdlr, /**< expression handler */
1197 SCIP_SET* set, /**< global SCIP settings */
1198 BMS_BUFMEM* bufmem, /**< buffer memory, can be NULL if childrenvals is NULL */
1199 SCIP_EXPR* expr, /**< expression to be differentiated */
1200 int childidx, /**< index of the child */
1201 SCIP_Real* derivative, /**< buffer to store the partial derivative w.r.t. the i-th children */
1202 SCIP_Real* childrenvals, /**< values for children, or NULL if values stored in children should be used */
1203 SCIP_Real exprval /**< value for expression, used only if childrenvals is not NULL */
1204 )
1205 {
1206 SCIP_Real* origchildrenvals;
1207 SCIP_Real origexprval;
1208 int c;
1209
1210 assert(exprhdlr != NULL);
1211 assert(set != NULL);
1212 assert(expr != NULL);
1213 assert(expr->exprhdlr == exprhdlr);
1214 assert(derivative != NULL);
1215
1216 if( exprhdlr->bwdiff == NULL )
1217 {
1218 *derivative = SCIP_INVALID;
1219 return SCIP_OKAY;
1220 }
1221
1222 if( childrenvals != NULL )
1223 {
1224 /* temporarily overwrite the evalvalue in all children and expr with values from childrenvals and exprval, resp. */
1225 if( expr->nchildren > 0 )
1226 {
1227 assert(bufmem != NULL);
1228 SCIP_ALLOC( BMSallocBufferMemoryArray(bufmem, &origchildrenvals, expr->nchildren) );
1229
1230 for( c = 0; c < expr->nchildren; ++c )
1231 {
1232 origchildrenvals[c] = expr->children[c]->evalvalue;
1233 expr->children[c]->evalvalue = childrenvals[c];
1234 }
1235 }
1236
1237 origexprval = expr->evalvalue;
1238 expr->evalvalue = exprval;
1239 }
1240
1241 SCIP_CALL( expr->exprhdlr->bwdiff(set->scip, expr, childidx, derivative) );
1242
1243 /* if there was some evaluation error (e.g., overflow) that hasn't been caught yet, then do so now */
1244 if( !SCIPisFinite(*derivative) )
1245 *derivative = SCIP_INVALID;
1246
1247 /* restore original evalvalues in children */
1248 if( childrenvals != NULL )
1249 {
1250 if( expr->nchildren > 0 )
1251 {
1252 for( c = 0; c < expr->nchildren; ++c )
1253 expr->children[c]->evalvalue = origchildrenvals[c]; /*lint !e644*/
1254
1255 BMSfreeBufferMemoryArray(bufmem, &origchildrenvals);
1256 }
1257
1258 expr->evalvalue = origexprval; /*lint !e644*/
1259 }
1260
1261 return SCIP_OKAY;
1262 }
1263
1264 /** calls the forward differentiation callback of an expression handler
1265 *
1266 * @see SCIP_DECL_EXPRFWDIFF
1267 */
1268 SCIP_RETCODE SCIPexprhdlrFwDiffExpr(
1269 SCIP_EXPRHDLR* exprhdlr, /**< expression handler */
1270 SCIP_SET* set, /**< global SCIP settings */
1271 SCIP_EXPR* expr, /**< expression to be differentiated */
1272 SCIP_Real* dot, /**< buffer to store derivative value */
1273 SCIP_SOL* direction /**< direction of the derivative (useful only for var expressions) */
1274 )
1275 {
1276 assert(exprhdlr != NULL);
1277 assert(set != NULL);
1278 assert(expr != NULL);
1279 assert(expr->exprhdlr == exprhdlr);
1280 assert(dot != NULL);
1281
1282 if( exprhdlr->fwdiff == NULL )
1283 {
1284 *dot = SCIP_INVALID;
1285 return SCIP_OKAY;
1286 }
1287
1288 SCIP_CALL( exprhdlr->fwdiff(set->scip, expr, dot, direction) );
1289
1290 /* if there was some evaluation error (e.g., overflow) that hasn't been caught yet, then do so now */
1291 if( !SCIPisFinite(*dot) )
1292 *dot = SCIP_INVALID;
1293
1294 return SCIP_OKAY;
1295 }
1296
1297 /** calls the evaluation and forward-differentiation callback of an expression handler
1298 *
1299 * The method evaluates an expression by taking the values of its children into account.
1300 * The method differentiates an expression by taking the values and directional derivatives of its children into account.
1301 *
1302 * Further, allows to evaluate and differentiate w.r.t. given values for children instead of those stored in children expressions.
1303 *
1304 * It probably doesn't make sense to call this function for a variable-expression if sol and/or direction are not given.
1305 *
1306 * @see SCIP_DECL_EXPREVAL
1307 * @see SCIP_DECL_EXPRFWDIFF
1308 */
1309 SCIP_RETCODE SCIPexprhdlrEvalFwDiffExpr(
1310 SCIP_EXPRHDLR* exprhdlr, /**< expression handler */
1311 SCIP_SET* set, /**< global SCIP settings */
1312 BMS_BUFMEM* bufmem, /**< buffer memory, can be NULL if childrenvals is NULL */
1313 SCIP_EXPR* expr, /**< expression to be evaluated */
1314 SCIP_Real* val, /**< buffer to store value of expression */
1315 SCIP_Real* dot, /**< buffer to store derivative value */
1316 SCIP_Real* childrenvals, /**< values for children, or NULL if values stored in children should
1317 be used */
1318 SCIP_SOL* sol, /**< solution that is evaluated (can be NULL) */
1319 SCIP_Real* childrendirs, /**< directional derivatives for children, or NULL if dot-values stored
1320 in children should be used */
1321 SCIP_SOL* direction /**< direction of the derivative (useful only for var expressions, can
1322 be NULL if childrendirs is given) */
1323 )
1324 {
1325 SCIP_Real origval;
1326 SCIP_Real* origvals = NULL;
1327 SCIP_Real* origdots = NULL;
1328
1329 assert(exprhdlr != NULL);
1330 assert(set != NULL);
1331 assert(expr != NULL);
1332 assert(expr->exprhdlr == exprhdlr);
1333 assert(exprhdlr->eval != NULL);
1334 assert(val != NULL);
1335 assert(dot != NULL);
1336
1337 /* temporarily overwrite the evalvalue in all children with values from childrenvals */
1338 if( childrenvals != NULL && expr->nchildren > 0 )
1339 {
1340 int c;
1341
1342 assert(bufmem != NULL);
1343
1344 SCIP_ALLOC( BMSallocBufferMemoryArray(bufmem, &origvals, expr->nchildren) );
1345
1346 for( c = 0; c < expr->nchildren; ++c )
1347 {
1348 origvals[c] = expr->children[c]->evalvalue;
1349 expr->children[c]->evalvalue = childrenvals[c];
1350 }
1351 }
1352
1353 /* temporarily overwrite the dot in all children with values from childrendirs */
1354 if( childrendirs != NULL && expr->nchildren > 0 )
1355 {
1356 int c;
1357
1358 assert(bufmem != NULL);
1359
1360 SCIP_ALLOC( BMSallocBufferMemoryArray(bufmem, &origdots, expr->nchildren) );
1361
1362 for( c = 0; c < expr->nchildren; ++c )
1363 {
1364 origdots[c] = expr->children[c]->dot;
1365 expr->children[c]->dot = childrendirs[c];
1366 }
1367 }
1368
1369 /* remember original value */
1370 origval = expr->evalvalue;
1371
1372 /* call expression eval callback */
1373 SCIP_CALL( exprhdlr->eval(set->scip, expr, val, sol) );
1374
1375 /* if there was some evaluation error (e.g., overflow) that hasn't been caught yet, then do so now */
1376 if( !SCIPisFinite(*val) )
1377 *val = SCIP_INVALID;
1378
1379 /* temporarily overwrite evalvalue of expr, since some exprhdlr (e.g., product) access this value in fwdiff */
1380 expr->evalvalue = *val;
1381
1382 /* call forward-differentiation callback (if available) */
1383 SCIP_CALL( SCIPexprhdlrFwDiffExpr(exprhdlr, set, expr, dot, direction) );
1384
1385 /* restore original value */
1386 expr->evalvalue = origval;
1387
1388 /* restore original dots in children */
1389 if( origdots != NULL )
1390 {
1391 int c;
1392 for( c = 0; c < expr->nchildren; ++c )
1393 expr->children[c]->dot = origdots[c];
1394
1395 BMSfreeBufferMemoryArray(bufmem, &origdots);
1396 }
1397
1398 /* restore original evalvalues in children */
1399 if( origvals != NULL )
1400 {
1401 int c;
1402 for( c = 0; c < expr->nchildren; ++c )
1403 expr->children[c]->evalvalue = origvals[c];
1404
1405 BMSfreeBufferMemoryArray(bufmem, &origvals);
1406 }
1407
1408 return SCIP_OKAY;
1409 }
1410
1411 /** calls the evaluation callback for Hessian directions (backward over forward) of an expression handler
1412 *
1413 * @see SCIP_DECL_EXPRBWFWDIFF
1414 */
1415 SCIP_RETCODE SCIPexprhdlrBwFwDiffExpr(
1416 SCIP_EXPRHDLR* exprhdlr, /**< expression handler */
1417 SCIP_SET* set, /**< global SCIP settings */
1418 SCIP_EXPR* expr, /**< expression to be differentiated */
1419 int childidx, /**< index of the child */
1420 SCIP_Real* bardot, /**< buffer to store derivative value */
1421 SCIP_SOL* direction /**< direction of the derivative (useful only for var expressions) */
1422 )
1423 {
1424 assert(exprhdlr != NULL);
1425 assert(set != NULL);
1426 assert(expr != NULL);
1427 assert(expr->exprhdlr == exprhdlr);
1428 assert(childidx >= 0);
1429 assert(childidx < expr->nchildren);
1430 assert(bardot != NULL);
1431
1432 if( exprhdlr->bwfwdiff == NULL )
1433 {
1434 *bardot = SCIP_INVALID;
1435 return SCIP_OKAY;
1436 }
1437
1438 SCIP_CALL( expr->exprhdlr->bwfwdiff(set->scip, expr, childidx, bardot, direction) );
1439
1440 /* if there was some evaluation error (e.g., overflow) that hasn't been caught yet, then do so now */
1441 if( !SCIPisFinite(*bardot) )
1442 *bardot = SCIP_INVALID;
1443
1444 return SCIP_OKAY;
1445 }
1446
1447 /** calls the interval evaluation callback of an expression handler
1448 *
1449 * @see SCIP_DECL_EXPRINTEVAL
1450 */
1451 SCIP_RETCODE SCIPexprhdlrIntEvalExpr(
1452 SCIP_EXPRHDLR* exprhdlr, /**< expression handler */
1453 SCIP_SET* set, /**< global SCIP settings */
1454 SCIP_EXPR* expr, /**< expression to be evaluated */
1455 SCIP_INTERVAL* interval, /**< buffer where to store interval */
1456 SCIP_DECL_EXPR_INTEVALVAR((*intevalvar)), /**< callback to be called when interval-evaluating a variable */
1457 void* intevalvardata /**< data to be passed to intevalvar callback */
1458 )
1459 {
1460 assert(exprhdlr != NULL);
1461 assert(set != NULL);
1462 assert(expr != NULL);
1463 assert(expr->exprhdlr == exprhdlr);
1464 assert(interval != NULL);
1465
1466 if( exprhdlr->inteval != NULL )
1467 {
1468 SCIPclockStart(exprhdlr->intevaltime, set);
1469 SCIP_CALL( exprhdlr->inteval(set->scip, expr, interval, intevalvar, intevalvardata) );
1470 SCIPclockStop(exprhdlr->intevaltime, set);
1471
1472 ++exprhdlr->nintevalcalls;
1473 }
1474
1475 return SCIP_OKAY;
1476 }
1477
1478 /** calls the estimator callback of an expression handler
1479 *
1480 * @see SCIP_DECL_EXPRESTIMATE
1481 */
1482 SCIP_RETCODE SCIPexprhdlrEstimateExpr(
1483 SCIP_EXPRHDLR* exprhdlr, /**< expression handler */
1484 SCIP_SET* set, /**< global SCIP settings */
1485 SCIP_EXPR* expr, /**< expression to be estimated */
1486 SCIP_INTERVAL* localbounds, /**< current bounds for children */
1487 SCIP_INTERVAL* globalbounds, /**< global bounds for children */
1488 SCIP_Real* refpoint, /**< children values for the reference point where to estimate */
1489 SCIP_Bool overestimate, /**< whether the expression needs to be over- or underestimated */
1490 SCIP_Real targetvalue, /**< a value that the estimator shall exceed, can be +/-infinity */
1491 SCIP_Real* coefs, /**< array to store coefficients of estimator */
1492 SCIP_Real* constant, /**< buffer to store constant part of estimator */
1493 SCIP_Bool* islocal, /**< buffer to store whether estimator is valid locally only */
1494 SCIP_Bool* success, /**< buffer to indicate whether an estimator could be computed */
1495 SCIP_Bool* branchcand /**< array to indicate which children (not) to consider for branching */
1496 )
1497 {
1498 assert(exprhdlr != NULL);
1499 assert(set != NULL);
1500 assert(expr != NULL);
1501 assert(expr->exprhdlr == exprhdlr);
1502 assert(coefs != NULL);
1503 assert(islocal != NULL);
1504 assert(success != NULL);
1505
1506 *success = FALSE;
1507
1508 if( exprhdlr->estimate != NULL )
1509 {
1510 SCIPclockStart(exprhdlr->estimatetime, set);
1511 SCIP_CALL( exprhdlr->estimate(set->scip, expr, localbounds, globalbounds, refpoint, overestimate, targetvalue,
1512 coefs, constant, islocal, success, branchcand) );
1513 SCIPclockStop(exprhdlr->estimatetime, set);
1514
1515 /* update statistics */
1516 ++exprhdlr->nestimatecalls;
1517 }
1518
1519 return SCIP_OKAY;
1520 }
1521
1522 /** calls the intitial estimators callback of an expression handler
1523 *
1524 * @see SCIP_DECL_EXPRINITESTIMATES
1525 */
1526 SCIP_RETCODE SCIPexprhdlrInitEstimatesExpr(
1527 SCIP_EXPRHDLR* exprhdlr, /**< expression handler */
1528 SCIP_SET* set, /**< global SCIP settings */
1529 SCIP_EXPR* expr, /**< expression to be estimated */
1530 SCIP_INTERVAL* bounds, /**< bounds for children */
1531 SCIP_Bool overestimate, /**< whether the expression shall be overestimated or underestimated */
1532 SCIP_Real* coefs[SCIP_EXPR_MAXINITESTIMATES], /**< buffer to store coefficients of computed estimators */
1533 SCIP_Real constant[SCIP_EXPR_MAXINITESTIMATES], /**< buffer to store constant of computed estimators */
1534 int* nreturned /**< buffer to store number of estimators that have been computed */
1535 )
1536 {
1537 assert(exprhdlr != NULL);
1538 assert(set != NULL);
1539 assert(expr != NULL);
1540 assert(expr->exprhdlr == exprhdlr);
1541 assert(nreturned != NULL);
1542
1543 *nreturned = 0;
1544
1545 if( exprhdlr->initestimates )
1546 {
1547 SCIPclockStart(expr->exprhdlr->estimatetime, set);
1548 SCIP_CALL( exprhdlr->initestimates(set->scip, expr, bounds, overestimate, coefs, constant, nreturned) );
1549 SCIPclockStop(expr->exprhdlr->estimatetime, set);
1550
1551 ++exprhdlr->nestimatecalls;
1552 }
1553
1554 return SCIP_OKAY;
1555 }
1556
1557 /** calls the simplification callback of an expression handler
1558 *
1559 * @see SCIP_DECL_EXPRSIMPLIFY
1560 */
1561 SCIP_RETCODE SCIPexprhdlrSimplifyExpr(
1562 SCIP_EXPRHDLR* exprhdlr, /**< expression handler */
1563 SCIP_SET* set, /**< global SCIP settings */
1564 SCIP_EXPR* expr, /**< expression to simplify */
1565 SCIP_EXPR** simplifiedexpr, /**< buffer to store the simplified expression */
1566 SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), /**< function to call on expression copy to create ownerdata */
1567 void* ownercreatedata /**< data to pass to ownercreate */
1568 )
1569 {
1570 assert(exprhdlr != NULL);
1571 assert(set != NULL);
1572 assert(expr != NULL);
1573 assert(expr->exprhdlr == exprhdlr);
1574 assert(simplifiedexpr != NULL);
1575
1576 if( exprhdlr->simplify != NULL )
1577 {
1578 SCIPclockStart(expr->exprhdlr->simplifytime, set);
1579 SCIP_CALL( exprhdlr->simplify(set->scip, expr, simplifiedexpr, ownercreate, ownercreatedata) );
1580 SCIPclockStop(expr->exprhdlr->simplifytime, set);
1581
1582 /* update statistics */
1583 ++exprhdlr->nsimplifycalls;
1584 if( expr != *simplifiedexpr )
1585 ++exprhdlr->nsimplified;
1586 }
1587 else
1588 {
1589 *simplifiedexpr = expr;
1590
1591 /* if an expression handler doesn't implement simplify, we assume that it is already simplified
1592 * we have to capture it, since it must simulate a "normal" simplified call in which a new expression is created
1593 */
1594 SCIPexprCapture(expr);
1595 }
1596
1597 return SCIP_OKAY;
1598 }
1599
1600 /** calls the reverse propagation callback of an expression handler
1601 *
1602 * The method propagates given bounds over the children of an expression.
1603 *
1604 * @see SCIP_DECL_EXPRREVERSEPROP
1605 */
1606 SCIP_RETCODE SCIPexprhdlrReversePropExpr(
1607 SCIP_EXPRHDLR* exprhdlr, /**< expression handler */
1608 SCIP_SET* set, /**< global SCIP settings */
1609 SCIP_EXPR* expr, /**< expression to propagate */
1610 SCIP_INTERVAL bounds, /**< the bounds on the expression that should be propagated */
1611 SCIP_INTERVAL* childrenbounds, /**< array to store computed bounds for children, initialized with
1612 current activity */
1613 SCIP_Bool* infeasible /**< buffer to store whether a children bounds were propagated to
1614 an empty interval */
1615 )
1616 {
1617 assert(exprhdlr != NULL);
1618 assert(set != NULL);
1619 assert(expr != NULL);
1620 assert(expr->exprhdlr == exprhdlr);
1621 assert(childrenbounds != NULL || expr->nchildren == 0);
1622 assert(infeasible != NULL);
1623
1624 *infeasible = FALSE;
1625
1626 if( exprhdlr->reverseprop != NULL )
1627 {
1628 SCIPclockStart(exprhdlr->proptime, set);
1629 SCIP_CALL( exprhdlr->reverseprop(set->scip, expr, bounds, childrenbounds, infeasible) );
1630 SCIPclockStop(exprhdlr->proptime, set);
1631
1632 /* update statistics */
1633 if( *infeasible )
1634 ++expr->exprhdlr->ncutoffs;
1635 ++expr->exprhdlr->npropcalls;
1636 }
1637
1638 return SCIP_OKAY;
1639 }
1640
1641 /**@name Expression Methods */
1642 /**@{ */
1643
1644 /* from expr.h */
1645
1646 /** creates and captures an expression with given expression data and children */
1647 SCIP_RETCODE SCIPexprCreate(
1648 SCIP_SET* set, /**< global SCIP settings */
1649 BMS_BLKMEM* blkmem, /**< block memory */
1650 SCIP_EXPR** expr, /**< pointer where to store expression */
1651 SCIP_EXPRHDLR* exprhdlr, /**< expression handler */
1652 SCIP_EXPRDATA* exprdata, /**< expression data (expression assumes ownership) */
1653 int nchildren, /**< number of children */
1654 SCIP_EXPR** children, /**< children (can be NULL if nchildren is 0) */
1655 SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), /**< function to call to create ownerdata */
1656 void* ownercreatedata /**< data to pass to ownercreate */
1657 )
1658 {
1659 int c;
1660
1661 assert(set != NULL);
1662 assert(blkmem != NULL);
1663 assert(expr != NULL);
1664 assert(exprhdlr != NULL);
1665 assert(children != NULL || nchildren == 0);
1666 assert(exprdata == NULL || exprhdlr->copydata != NULL); /* copydata must be available if there is expression data */
1667 assert(exprdata == NULL || exprhdlr->freedata != NULL); /* freedata must be available if there is expression data */
1668
1669 SCIP_ALLOC( BMSallocClearBlockMemory(blkmem, expr) );
1670
1671 (*expr)->exprhdlr = exprhdlr;
1672 (*expr)->exprdata = exprdata;
1673 (*expr)->activitytag = -1; /* to be less than initial domchgcount */
1674 (*expr)->curvature = SCIP_EXPRCURV_UNKNOWN;
1675
1676 /* initialize activity to entire interval */
1677 SCIPintervalSetEntire(SCIP_INTERVAL_INFINITY, &(*expr)->activity);
1678
1679 if( nchildren > 0 )
1680 {
1681 SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*expr)->children, children, nchildren) );
1682 (*expr)->nchildren = nchildren;
1683 (*expr)->childrensize = nchildren;
1684
1685 for( c = 0; c < nchildren; ++c )
1686 SCIPexprCapture((*expr)->children[c]);
1687 }
1688
1689 SCIPexprCapture(*expr);
1690
1691 ++exprhdlr->ncreated;
1692
1693 /* initializes the ownerdata */
1694 if( ownercreate != NULL )
1695 {
1696 SCIP_CALL( ownercreate(set->scip, *expr, &(*expr)->ownerdata, &(*expr)->ownerfree, &(*expr)->ownerprint,
1697 &(*expr)->ownerevalactivity, ownercreatedata) );
1698 }
1699
1700 return SCIP_OKAY;
1701 }
1702
1703 /** appends child to the children list of expr */
1704 SCIP_RETCODE SCIPexprAppendChild(
1705 SCIP_SET* set, /**< global SCIP settings */
1706 BMS_BLKMEM* blkmem, /**< block memory */
1707 SCIP_EXPR* expr, /**< expression */
1708 SCIP_EXPR* child /**< expression to be appended */
1709 )
1710 {
1711 assert(set != NULL);
1712 assert(blkmem != NULL);
1713 assert(child != NULL);
1714 assert(expr->nchildren <= expr->childrensize);
1715
1716 if( expr->nchildren == expr->childrensize )
1717 {
1718 expr->childrensize = SCIPsetCalcMemGrowSize(set, expr->nchildren+1);
1719 SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, expr->nchildren, expr->childrensize) );
1720 }
1721
1722 expr->children[expr->nchildren] = child;
1723 ++expr->nchildren;
1724
1725 /* capture child */
1726 SCIPexprCapture(child);
1727
1728 return SCIP_OKAY;
1729 }
1730
1731 /** overwrites/replaces a child of an expressions
1732 *
1733 * @note the old child is released and the newchild is captured, unless they are the same (=same pointer)
1734 */
1735 SCIP_RETCODE SCIPexprReplaceChild(
1736 SCIP_SET* set, /**< global SCIP settings */
1737 SCIP_STAT* stat, /**< dynamic problem statistics */
1738 BMS_BLKMEM* blkmem, /**< block memory */
1739 SCIP_EXPR* expr, /**< expression where a child is going to be replaced */
1740 int childidx, /**< index of child being replaced */
1741 SCIP_EXPR* newchild /**< the new child */
1742 )
1743 {
1744 assert(set != NULL);
1745 assert(blkmem != NULL);
1746 assert(expr != NULL);
1747 assert(newchild != NULL);
1748 assert(childidx >= 0);
1749 assert(childidx < expr->nchildren);
1750
1751 /* do nothing if child is not changing */
1752 if( newchild == expr->children[childidx] )
1753 return SCIP_OKAY;
1754
1755 /* capture new child (do this before releasing the old child in case there are equal */
1756 SCIPexprCapture(newchild);
1757
1758 SCIP_CALL( SCIPexprRelease(set, stat, blkmem, &(expr->children[childidx])) );
1759 expr->children[childidx] = newchild;
1760
1761 return SCIP_OKAY;
1762 }
1763
1764 /** remove all children of expr */
1765 SCIP_RETCODE SCIPexprRemoveChildren(
1766 SCIP_SET* set, /**< global SCIP settings */
1767 SCIP_STAT* stat, /**< dynamic problem statistics */
1768 BMS_BLKMEM* blkmem, /**< block memory */
1769 SCIP_EXPR* expr /**< expression */
1770 )
1771 {
1772 int c;
1773
1774 assert(set != NULL);
1775 assert(blkmem != NULL);
1776 assert(expr != NULL);
1777
1778 for( c = 0; c < expr->nchildren; ++c )
1779 {
1780 assert(expr->children[c] != NULL);
1781 SCIP_CALL( SCIPexprRelease(set, stat, blkmem, &(expr->children[c])) );
1782 }
1783
1784 expr->nchildren = 0;
1785
1786 return SCIP_OKAY;
1787 }
1788
1789 /** copies an expression including subexpressions
1790 *
1791 * @note If copying fails due to an expression handler not being available in the targetscip, then *targetexpr will be set to NULL.
1792 *
1793 * For all or some expressions, a mapping to an existing expression can be specified via the mapexpr callback.
1794 * The mapped expression (including its children) will not be copied in this case and its ownerdata will not be touched.
1795 * If, however, the mapexpr callback returns NULL for the targetexpr, then the expr will be copied in the usual way.
1796 */
1797 SCIP_RETCODE SCIPexprCopy(
1798 SCIP_SET* set, /**< global SCIP settings */
1799 SCIP_STAT* stat, /**< dynamic problem statistics */
1800 BMS_BLKMEM* blkmem, /**< block memory */
1801 SCIP_SET* targetset, /**< global SCIP settings data structure where target expression will live */
1802 SCIP_STAT* targetstat, /**< dynamic problem statistics in target SCIP */
1803 BMS_BLKMEM* targetblkmem, /**< block memory in target SCIP */
1804 SCIP_EXPR* sourceexpr, /**< expression to be copied */
1805 SCIP_EXPR** targetexpr, /**< buffer to store pointer to copy of source expression */
1806 SCIP_DECL_EXPR_MAPEXPR((*mapexpr)), /**< expression mapping function, or NULL for creating new expressions */
1807 void* mapexprdata, /**< data of expression mapping function */
1808 SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), /**< function to call on expression copy to create ownerdata */
1809 void* ownercreatedata /**< data to pass to ownercreate */
1810 )
1811 {
1812 SCIP_EXPRITER* it;
1813 SCIP_EXPRITER_USERDATA expriteruserdata;
1814 SCIP_EXPR* expr;
1815 SCIP* sourcescip = set->scip; /* SCIP data structure corresponding to source expression */
1816 SCIP* targetscip = targetset->scip; /* SCIP data structure where target expression will live */
1817
1818 assert(set != NULL);
1819 assert(stat != NULL);
1820 assert(blkmem != NULL);
1821 assert(targetset != NULL);
1822 assert(sourceexpr != NULL);
1823 assert(targetexpr != NULL);
1824 assert(sourcescip != NULL);
1825 assert(targetscip != NULL);
1826
1827 SCIP_CALL( SCIPexpriterCreate(stat, blkmem, &it) );
1828 SCIP_CALL( SCIPexpriterInit(it, sourceexpr, SCIP_EXPRITER_DFS, TRUE) ); /*TODO use FALSE, i.e., don't duplicate common subexpr? */
1829 SCIPexpriterSetStagesDFS(it, SCIP_EXPRITER_ENTEREXPR | SCIP_EXPRITER_VISITEDCHILD);
1830
1831 expr = sourceexpr;
1832 while( !SCIPexpriterIsEnd(it) )
1833 {
1834 switch( SCIPexpriterGetStageDFS(it) )
1835 {
1836 case SCIP_EXPRITER_ENTEREXPR :
1837 {
1838 /* create expr that will hold the copy */
1839 SCIP_EXPRHDLR* targetexprhdlr;
1840 SCIP_EXPRDATA* targetexprdata;
1841 SCIP_EXPR* exprcopy = NULL;
1842
1843 if( mapexpr != NULL )
1844 {
1845 SCIP_CALL( mapexpr(targetscip, &exprcopy, sourcescip, expr, ownercreate, ownercreatedata, mapexprdata) );
1846 if( exprcopy != NULL )
1847 {
1848 /* map callback gave us an expression to use for the copy */
1849 /* store targetexpr */
1850 expriteruserdata.ptrval = exprcopy;
1851 SCIPexpriterSetCurrentUserData(it, expriteruserdata);
1852
1853 /* skip subexpression (assume that exprcopy is a complete copy) and continue */
1854 expr = SCIPexpriterSkipDFS(it);
1855 continue;
1856 }
1857 }
1858
1859 /* get the exprhdlr of the target scip */
1860 if( targetscip != sourcescip )
1861 {
1862 targetexprhdlr = SCIPsetFindExprhdlr(targetset, expr->exprhdlr->name);
1863
1864 if( targetexprhdlr == NULL )
1865 {
1866 /* expression handler not in target scip (probably did not have a copy callback) -> abort */
1867 expriteruserdata.ptrval = NULL;
1868 SCIPexpriterSetCurrentUserData(it, expriteruserdata);
1869
1870 expr = SCIPexpriterSkipDFS(it);
1871 continue;
1872 }
1873 }
1874 else
1875 {
1876 targetexprhdlr = expr->exprhdlr;
1877 }
1878 assert(targetexprhdlr != NULL);
1879
1880 /* copy expression data */
1881 if( expr->exprdata != NULL )
1882 {
1883 assert(expr->exprhdlr->copydata != NULL);
1884 SCIP_CALL( expr->exprhdlr->copydata(targetscip, targetexprhdlr, &targetexprdata, sourcescip, expr) );
1885 }
1886 else
1887 {
1888 targetexprdata = NULL;
1889 }
1890
1891 /* create in targetexpr an expression of the same type as expr, but without children for now */
1892 SCIP_CALL( SCIPexprCreate(targetset, targetblkmem, &exprcopy, targetexprhdlr, targetexprdata, 0, NULL,
1893 ownercreate, ownercreatedata) );
1894
1895 /* store targetexpr */
1896 expriteruserdata.ptrval = exprcopy;
1897 SCIPexpriterSetCurrentUserData(it, expriteruserdata);
1898
1899 break;
1900 }
1901
1902 case SCIP_EXPRITER_VISITEDCHILD :
1903 {
1904 /* just visited child so a copy of himself should be available; append it */
1905 SCIP_EXPR* exprcopy;
1906 SCIP_EXPR* childcopy;
1907
1908 exprcopy = (SCIP_EXPR*)SCIPexpriterGetCurrentUserData(it).ptrval;
1909
1910 /* get copy of child */
1911 childcopy = (SCIP_EXPR*)SCIPexpriterGetChildUserDataDFS(it).ptrval;
1912 if( childcopy == NULL )
1913 {
1914 /* abort */
1915 /* release exprcopy (should free also the already copied children) */
1916 SCIP_CALL( SCIPexprRelease(targetset, targetstat, targetblkmem, (SCIP_EXPR**)&exprcopy) );
1917
1918 expriteruserdata.ptrval = NULL;
1919 SCIPexpriterSetCurrentUserData(it, expriteruserdata);
1920
1921 expr = SCIPexpriterSkipDFS(it);
1922 continue;
1923 }
1924
1925 /* append child to exprcopy */
1926 SCIP_CALL( SCIPexprAppendChild(targetset, targetblkmem, exprcopy, childcopy) );
1927
1928 /* release childcopy (still captured by exprcopy) */
1929 SCIP_CALL( SCIPexprRelease(targetset, targetstat, targetblkmem, &childcopy) );
1930
1931 break;
1932 }
1933
1934 default:
1935 /* we should never be called in this stage */
1936 SCIPABORT();
1937 break;
1938 }
1939
1940 expr = SCIPexpriterGetNext(it);
1941 }
1942
1943 /* the target expression should be stored in the userdata of the sourceexpr (can be NULL if aborted) */
1944 *targetexpr = (SCIP_EXPR*)SCIPexpriterGetExprUserData(it, sourceexpr).ptrval;
1945
1946 SCIPexpriterFree(&it);
1947
1948 return SCIP_OKAY;
1949 }
1950
1951 /** duplicates the given expression without its children */
1952 SCIP_RETCODE SCIPexprDuplicateShallow(
1953 SCIP_SET* set, /**< global SCIP settings */
1954 BMS_BLKMEM* blkmem, /**< block memory */
1955 SCIP_EXPR* expr, /**< original expression */
1956 SCIP_EXPR** copyexpr, /**< buffer to store (shallow) duplicate of expr */
1957 SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), /**< function to call on expression copy to create ownerdata */
1958 void* ownercreatedata /**< data to pass to ownercreate */
1959 )
1960 {
1961 SCIP_EXPRDATA* exprdatacopy = NULL;
1962
1963 assert(set != NULL);
1964 assert(blkmem != NULL);
1965 assert(expr != NULL);
1966 assert(copyexpr != NULL);
1967
1968 /* copy expression data */
1969 if( expr->exprdata != NULL )
1970 {
1971 assert(expr->exprhdlr->copydata != NULL);
1972 SCIP_CALL( expr->exprhdlr->copydata(set->scip, expr->exprhdlr, &exprdatacopy, set->scip, expr) );
1973 }
1974
1975 /* create expression with same handler and copied data, but without children */
1976 SCIP_CALL( SCIPexprCreate(set, blkmem, copyexpr, expr->exprhdlr, exprdatacopy, 0, NULL, ownercreate,
1977 ownercreatedata) );
1978
1979 return SCIP_OKAY;
1980 }
1981
1982 /** captures an expression (increments usage count) */
1983 void SCIPexprCapture(
1984 SCIP_EXPR* expr /**< expression */
1985 )
1986 {
1987 assert(expr != NULL);
1988
1989 ++expr->nuses;
1990 }
1991
1992 /** releases an expression (decrements usage count and possibly frees expression) */
1993 SCIP_RETCODE SCIPexprRelease(
1994 SCIP_SET* set, /**< global SCIP settings */
1995 SCIP_STAT* stat, /**< dynamic problem statistics */
1996 BMS_BLKMEM* blkmem, /**< block memory */
1997 SCIP_EXPR** rootexpr /**< pointer to expression */
1998 )
1999 {
2000 SCIP_EXPRITER* it;
2001 SCIP_EXPR* expr;
2002
2003 assert(rootexpr != NULL);
2004 assert(*rootexpr != NULL);
2005 assert((*rootexpr)->nuses > 0);
2006
2007 if( (*rootexpr)->nuses > 1 )
2008 {
2009 --(*rootexpr)->nuses;
2010 *rootexpr = NULL;
2011
2012 return SCIP_OKAY;
2013 }
2014
2015 /* handle the root expr separately: free ownerdata, quaddata, and exprdata first */
2016
2017 /* call ownerfree callback, if given
2018 * we intentially call this also if ownerdata is NULL, so owner can be notified without storing data
2019 */
2020 if( (*rootexpr)->ownerfree != NULL )
2021 {
2022 SCIP_CALL( (*rootexpr)->ownerfree(set->scip, *rootexpr, &(*rootexpr)->ownerdata) );
2023 assert((*rootexpr)->ownerdata == NULL);
2024 }
2025
2026 /* free quadratic info */
2027 SCIPexprFreeQuadratic(blkmem, *rootexpr);
2028
2029 /* free expression data */
2030 if( (*rootexpr)->exprdata != NULL )
2031 {
2032 assert((*rootexpr)->exprhdlr->freedata != NULL);
2033 SCIP_CALL( (*rootexpr)->exprhdlr->freedata(set->scip, *rootexpr) );
2034 }
2035
2036 /* now release and free children, where no longer in use */
2037 SCIP_CALL( SCIPexpriterCreate(stat, blkmem, &it) );
2038 SCIP_CALL( SCIPexpriterInit(it, *rootexpr, SCIP_EXPRITER_DFS, TRUE) );
2039 SCIPexpriterSetStagesDFS(it, SCIP_EXPRITER_VISITINGCHILD | SCIP_EXPRITER_VISITEDCHILD);
2040 for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it) ; )
2041 {
2042 /* expression should be used by its parent and maybe by the iterator (only the root!)
2043 * in VISITEDCHILD we assert that expression is only used by its parent
2044 */
2045 assert(expr != NULL);
2046 assert(0 <= expr->nuses && expr->nuses <= 2);
2047
2048 switch( SCIPexpriterGetStageDFS(it) )
2049 {
2050 case SCIP_EXPRITER_VISITINGCHILD :
2051 {
2052 /* check whether a child needs to be visited (nuses == 1)
2053 * if not, then we still have to release it
2054 */
2055 SCIP_EXPR* child;
2056
2057 child = SCIPexpriterGetChildExprDFS(it);
2058 if( child->nuses > 1 )
2059 {
2060 /* child is not going to be freed: just release it */
2061 SCIP_CALL( SCIPexprRelease(set, stat, blkmem, &child) );
2062 expr = SCIPexpriterSkipDFS(it);
2063 continue;
2064 }
2065
2066 assert(child->nuses == 1);
2067
2068 /* free child's quaddata, ownerdata, and exprdata when entering child */
2069 if( child->ownerfree != NULL )
2070 {
2071 SCIP_CALL( child->ownerfree(set->scip, child, &child->ownerdata) );
2072 assert(child->ownerdata == NULL);
2073 }
2074
2075 /* free quadratic info */
2076 SCIPexprFreeQuadratic(blkmem, child);
2077
2078 /* free expression data */
2079 if( child->exprdata != NULL )
2080 {
2081 assert(child->exprhdlr->freedata != NULL);
2082 SCIP_CALL( child->exprhdlr->freedata(set->scip, child) );
2083 assert(child->exprdata == NULL);
2084 }
2085
2086 break;
2087 }
2088
2089 case SCIP_EXPRITER_VISITEDCHILD :
2090 {
2091 /* free child after visiting it */
2092 SCIP_EXPR* child;
2093
2094 child = SCIPexpriterGetChildExprDFS(it);
2095 /* child should only be used by its parent */
2096 assert(child->nuses == 1);
2097
2098 /* child should have no data associated */
2099 assert(child->exprdata == NULL);
2100
2101 /* free child expression */
2102 SCIP_CALL( freeExpr(blkmem, &child) );
2103 expr->children[SCIPexpriterGetChildIdxDFS(it)] = NULL;
2104
2105 break;
2106 }
2107
2108 default:
2109 SCIPABORT(); /* we should never be called in this stage */
2110 break;
2111 }
2112
2113 expr = SCIPexpriterGetNext(it);
2114 }
2115
2116 SCIPexpriterFree(&it);
2117
2118 /* handle the root expr separately: free its children and itself here */
2119 SCIP_CALL( freeExpr(blkmem, rootexpr) );
2120
2121 return SCIP_OKAY;
2122 }
2123
2124 /** returns whether an expression is a variable expression */
2125 SCIP_Bool SCIPexprIsVar(
2126 SCIP_SET* set, /**< global SCIP settings */
2127 SCIP_EXPR* expr /**< expression */
2128 )
2129 {
2130 assert(set != NULL);
2131 assert(expr != NULL);
2132
2133 return expr->exprhdlr == set->exprhdlrvar;
2134 }
2135
2136 /** returns whether an expression is a value expression */
2137 SCIP_Bool SCIPexprIsValue(
2138 SCIP_SET* set, /**< global SCIP settings */
2139 SCIP_EXPR* expr /**< expression */
2140 )
2141 {
2142 assert(set != NULL);
2143 assert(expr != NULL);
2144
2145 return expr->exprhdlr == set->exprhdlrval;
2146 }
2147
2148 /** returns whether an expression is a sum expression */
2149 SCIP_Bool SCIPexprIsSum(
2150 SCIP_SET* set, /**< global SCIP settings */
2151 SCIP_EXPR* expr /**< expression */
2152 )
2153 {
2154 assert(set != NULL);
2155 assert(expr != NULL);
2156
2157 return expr->exprhdlr == set->exprhdlrsum;
2158 }
2159
2160 /** returns whether an expression is a product expression */
2161 SCIP_Bool SCIPexprIsProduct(
2162 SCIP_SET* set, /**< global SCIP settings */
2163 SCIP_EXPR* expr /**< expression */
2164 )
2165 {
2166 assert(set != NULL);
2167 assert(expr != NULL);
2168
2169 return expr->exprhdlr == set->exprhdlrproduct;
2170 }
2171
2172 /** returns whether an expression is a power expression */
2173 SCIP_Bool SCIPexprIsPower(
2174 SCIP_SET* set, /**< global SCIP settings */
2175 SCIP_EXPR* expr /**< expression */
2176 )
2177 {
2178 assert(set != NULL);
2179 assert(expr != NULL);
2180
2181 return expr->exprhdlr == set->exprhdlrpow;
2182 }
2183
2184 /** print an expression as info-message */
2185 SCIP_RETCODE SCIPexprPrint(
2186 SCIP_SET* set, /**< global SCIP settings */
2187 SCIP_STAT* stat, /**< dynamic problem statistics */
2188 BMS_BLKMEM* blkmem, /**< block memory */
2189 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
2190 FILE* file, /**< file to print to, or NULL for stdout */
2191 SCIP_EXPR* expr /**< expression to be printed */
2192 )
2193 {
2194 SCIP_EXPRITER* it;
2195 SCIP_EXPRITER_STAGE stage;
2196 int currentchild;
2197 unsigned int parentprecedence;
2198
2199 assert(set != NULL);
2200 assert(blkmem != NULL);
2201 assert(expr != NULL);
2202
2203 SCIP_CALL( SCIPexpriterCreate(stat, blkmem, &it) );
2204 SCIP_CALL( SCIPexpriterInit(it, expr, SCIP_EXPRITER_DFS, TRUE) );
2205 SCIPexpriterSetStagesDFS(it, SCIP_EXPRITER_ALLSTAGES);
2206
2207 while( !SCIPexpriterIsEnd(it) )
2208 {
2209 assert(expr->exprhdlr != NULL);
2210 stage = SCIPexpriterGetStageDFS(it);
2211
2212 if( stage == SCIP_EXPRITER_VISITEDCHILD || stage == SCIP_EXPRITER_VISITINGCHILD )
2213 currentchild = SCIPexpriterGetChildIdxDFS(it);
2214 else
2215 currentchild = -1;
2216
2217 if( SCIPexpriterGetParentDFS(it) != NULL )
2218 parentprecedence = SCIPexprhdlrGetPrecedence(SCIPexprGetHdlr(SCIPexpriterGetParentDFS(it)));
2219 else
2220 parentprecedence = 0;
2221
2222 SCIP_CALL( SCIPexprhdlrPrintExpr(expr->exprhdlr, set, messagehdlr, expr, stage, currentchild,
2223 parentprecedence, file) );
2224
2225 expr = SCIPexpriterGetNext(it);
2226 }
2227
2228 SCIPexpriterFree(&it);
2229
2230 return SCIP_OKAY;
2231 }
2232
2233 /** initializes printing of expressions in dot format to a give FILE* pointer */
2234 SCIP_RETCODE SCIPexprPrintDotInit(
2235 SCIP_SET* set, /**< global SCIP settings */
2236 SCIP_STAT* stat, /**< dynamic problem statistics */
2237 BMS_BLKMEM* blkmem, /**< block memory */
2238 SCIP_EXPRPRINTDATA** printdata, /**< buffer to store dot printing data */
2239 FILE* file, /**< file to print to, or NULL for stdout */
2240 SCIP_EXPRPRINT_WHAT whattoprint /**< info on what to print for each expression */
2241 )
2242 {
2243 assert(set != NULL);
2244 assert(stat != NULL);
2245 assert(blkmem != NULL);
2246 assert(printdata != NULL);
2247
2248 if( file == NULL )
2249 file = stdout;
2250
2251 SCIP_ALLOC( BMSallocBlockMemory(blkmem, printdata) );
2252
2253 (*printdata)->file = file;
2254 SCIP_CALL( SCIPexpriterCreate(stat, blkmem, &(*printdata)->iterator) );
2255 (*printdata)->closefile = FALSE;
2256 (*printdata)->whattoprint = whattoprint;
2257 SCIP_CALL( SCIPhashmapCreate(&(*printdata)->leaveexprs, blkmem, 100) );
2258
2259 fputs("strict digraph exprgraph {\n", file);
2260 fputs("node [fontcolor=white, style=filled, rankdir=LR]\n", file);
2261
2262 return SCIP_OKAY;
2263 }
2264
2265 /** initializes printing of expressions in dot format to a file with given filename */
2266 SCIP_RETCODE SCIPexprPrintDotInit2(
2267 SCIP_SET* set, /**< global SCIP settings */
2268 SCIP_STAT* stat, /**< dynamic problem statistics */
2269 BMS_BLKMEM* blkmem, /**< block memory */
2270 SCIP_EXPRPRINTDATA** printdata, /**< buffer to store dot printing data */
2271 const char* filename, /**< name of file to print to */
2272 SCIP_EXPRPRINT_WHAT whattoprint /**< info on what to print for each expression */
2273 )
2274 {
2275 FILE* f;
2276
2277 assert(set != NULL);
2278 assert(stat != NULL);
2279 assert(blkmem != NULL);
2280 assert(printdata != NULL);
2281 assert(filename != NULL);
2282
2283 f = fopen(filename, "w");
2284 if( f == NULL )
2285 {
2286 SCIPerrorMessage("could not open file <%s> for writing\n", filename); /* error code would be in errno */
2287 return SCIP_FILECREATEERROR;
2288 }
2289
2290 SCIP_CALL( SCIPexprPrintDotInit(set, stat, blkmem, printdata, f, whattoprint) );
2291 (*printdata)->closefile = TRUE;
2292
2293 return SCIP_OKAY;
2294 } /*lint !e429*/
2295
2296 /** main part of printing an expression in dot format */
2297 SCIP_RETCODE SCIPexprPrintDot(
2298 SCIP_SET* set, /**< global SCIP settings */
2299 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
2300 SCIP_EXPRPRINTDATA* printdata, /**< data as initialized by \ref SCIPprintExprDotInit() */
2301 SCIP_EXPR* expr /**< expression to be printed */
2302 )
2303 {
2304 SCIP_Real color;
2305 int c;
2306
2307 assert(set != NULL);
2308 assert(printdata != NULL);
2309 assert(expr != NULL);
2310 assert(expr->exprhdlr != NULL);
2311
2312 SCIP_CALL( SCIPexpriterInit(printdata->iterator, expr, SCIP_EXPRITER_DFS, FALSE) );
2313
2314 while( !SCIPexpriterIsEnd(printdata->iterator) )
2315 {
2316 /* print expression as dot node */
2317
2318 if( expr->nchildren == 0 )
2319 {
2320 SCIP_CALL( SCIPhashmapInsert(printdata->leaveexprs, (void*)expr, NULL) );
2321 }
2322
2323 /* make up some color from the expression type (it's name) */
2324 color = 0.0;
2325 for( c = 0; expr->exprhdlr->name[c] != '\0'; ++c )
2326 color += (tolower(expr->exprhdlr->name[c]) - 'a') / 26.0;
2327 color = SCIPsetFrac(set, color);
2328 fprintf(printdata->file, "n%p [fillcolor=\"%g,%g,%g\", label=\"", (void*)expr, color, color, color);
2329
2330 if( printdata->whattoprint & SCIP_EXPRPRINT_EXPRHDLR )
2331 {
2332 fprintf(printdata->file, "%s\\n", expr->exprhdlr->name);
2333 }
2334
2335 if( printdata->whattoprint & SCIP_EXPRPRINT_EXPRSTRING )
2336 {
2337 SCIP_CALL( SCIPexprhdlrPrintExpr(expr->exprhdlr, set, messagehdlr, expr, SCIP_EXPRITER_ENTEREXPR, -1, 0,
2338 printdata->file) );
2339 for( c = 0; c < expr->nchildren; ++c )
2340 {
2341 SCIP_CALL( SCIPexprhdlrPrintExpr(expr->exprhdlr, set, messagehdlr, expr, SCIP_EXPRITER_VISITINGCHILD,
2342 c, 0, printdata->file) );
2343 fprintf(printdata->file, "c%d", c);
2344 SCIP_CALL( SCIPexprhdlrPrintExpr(expr->exprhdlr, set, messagehdlr, expr, SCIP_EXPRITER_VISITEDCHILD,
2345 c, 0, printdata->file) );
2346 }
2347 SCIP_CALL( SCIPexprhdlrPrintExpr(expr->exprhdlr, set, messagehdlr, expr, SCIP_EXPRITER_LEAVEEXPR, -1, 0,
2348 printdata->file) );
2349
2350 fputs("\\n", printdata->file);
2351 }
2352
2353 if( printdata->whattoprint & SCIP_EXPRPRINT_NUSES )
2354 {
2355 /* print number of uses */
2356 fprintf(printdata->file, "%d uses\\n", expr->nuses);
2357 }
2358
2359 if( printdata->whattoprint & SCIP_EXPRPRINT_OWNER )
2360 {
2361 /* print ownerdata */
2362 if( expr->ownerprint != NULL )
2363 {
2364 SCIP_CALL( expr->ownerprint(set->scip, printdata->file, expr, expr->ownerdata) );
2365 }
2366 else if( expr->ownerdata != NULL )
2367 {
2368 fprintf(printdata->file, "owner=%p\\n", (void*)expr->ownerdata);
2369 }
2370 }
2371
2372 if( printdata->whattoprint & SCIP_EXPRPRINT_EVALVALUE )
2373 {
2374 /* print eval value */
2375 fprintf(printdata->file, "val=%g", expr->evalvalue);
2376
2377 if( (printdata->whattoprint & SCIP_EXPRPRINT_EVALTAG) == SCIP_EXPRPRINT_EVALTAG )
2378 {
2379 /* print also eval tag */
2380 fprintf(printdata->file, " (%" SCIP_LONGINT_FORMAT ")", expr->evaltag);
2381 }
2382 fputs("\\n", printdata->file);
2383 }
2384
2385 if( printdata->whattoprint & SCIP_EXPRPRINT_ACTIVITY )
2386 {
2387 /* print activity */
2388 fprintf(printdata->file, "[%g,%g]", expr->activity.inf, expr->activity.sup);
2389
2390 if( (printdata->whattoprint & SCIP_EXPRPRINT_ACTIVITYTAG) == SCIP_EXPRPRINT_ACTIVITYTAG )
2391 {
2392 /* print also activity eval tag */
2393 fprintf(printdata->file, " (%" SCIP_LONGINT_FORMAT ")", expr->activitytag);
2394 }
2395 fputs("\\n", printdata->file);
2396 }
2397
2398 fputs("\"]\n", printdata->file); /* end of label and end of node */
2399
2400 /* add edges from expr to its children */
2401 for( c = 0; c < expr->nchildren; ++c )
2402 fprintf(printdata->file, "n%p -> n%p [label=\"c%d\"]\n", (void*)expr, (void*)expr->children[c], c);
2403
2404 expr = SCIPexpriterGetNext(printdata->iterator);
2405 }
2406
2407 return SCIP_OKAY;
2408 }
2409
2410 /** finishes printing of expressions in dot format */
2411 SCIP_RETCODE SCIPexprPrintDotFinal(
2412 SCIP_SET* set, /**< global SCIP settings */
2413 SCIP_STAT* stat, /**< dynamic problem statistics */
2414 BMS_BLKMEM* blkmem, /**< block memory */
2415 SCIP_EXPRPRINTDATA** printdata /**< buffer where dot printing data has been stored */
2416 )
2417 {
2418 SCIP_EXPR* expr;
2419 SCIP_HASHMAPENTRY* entry;
2420 FILE* file;
2421 int i;
2422
2423 assert(set != NULL);
2424 assert(stat != NULL);
2425 assert(blkmem != NULL);
2426 assert(printdata != NULL);
2427 assert(*printdata != NULL);
2428
2429 file = (*printdata)->file;
2430 assert(file != NULL);
2431
2432 /* iterate through all entries of the map */
2433 fputs("{rank=same;", file);
2434 for( i = 0; i < SCIPhashmapGetNEntries((*printdata)->leaveexprs); ++i )
2435 {
2436 entry = SCIPhashmapGetEntry((*printdata)->leaveexprs, i);
2437
2438 if( entry != NULL )
2439 {
2440 expr = (SCIP_EXPR*) SCIPhashmapEntryGetOrigin(entry);
2441 assert(expr != NULL);
2442 assert(expr->nchildren == 0);
2443
2444 fprintf(file, " n%p", (void*)expr);
2445 }
2446 }
2447 fprintf(file, "}\n");
2448
2449 fprintf(file, "}\n");
2450
2451 SCIPhashmapFree(&(*printdata)->leaveexprs);
2452
2453 SCIPexpriterFree(&(*printdata)->iterator);
2454
2455 if( (*printdata)->closefile )
2456 fclose((*printdata)->file);
2457
2458 BMSfreeBlockMemory(blkmem, printdata);
2459
2460 return SCIP_OKAY;
2461 }
2462
2463 /** prints structure of an expression a la Maple's dismantle */
2464 SCIP_RETCODE SCIPexprDismantle(
2465 SCIP_SET* set, /**< global SCIP settings */
2466 SCIP_STAT* stat, /**< dynamic problem statistics */
2467 BMS_BLKMEM* blkmem, /**< block memory */
2468 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
2469 FILE* file, /**< file to print to, or NULL for stdout */
2470 SCIP_EXPR* expr /**< expression to dismantle */
2471 )
2472 {
2473 SCIP_EXPRITER* it;
2474 int depth = -1;
2475
2476 assert(set != NULL);
2477 assert(stat != NULL);
2478 assert(blkmem != NULL);
2479 assert(messagehdlr != NULL);
2480 assert(expr != NULL);
2481
2482 SCIP_CALL( SCIPexpriterCreate(stat, blkmem, &it) );
2483 SCIP_CALL( SCIPexpriterInit(it, expr, SCIP_EXPRITER_DFS, TRUE) );
2484 SCIPexpriterSetStagesDFS(it, SCIP_EXPRITER_ENTEREXPR | SCIP_EXPRITER_VISITINGCHILD | SCIP_EXPRITER_LEAVEEXPR);
2485
2486 for( ; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
2487 {
2488 switch( SCIPexpriterGetStageDFS(it) )
2489 {
2490 case SCIP_EXPRITER_ENTEREXPR:
2491 {
2492 int nspaces;
2493
2494 ++depth;
2495 nspaces = 3 * depth;
2496
2497 /* use depth of expression to align output */
2498 SCIPmessageFPrintInfo(messagehdlr, file, "%*s[%s]: ", nspaces, "", expr->exprhdlr->name);
2499
2500 if( SCIPexprIsVar(set, expr) )
2501 {
2502 SCIP_VAR* var;
2503
2504 var = SCIPgetVarExprVar(expr);
2505 SCIPmessageFPrintInfo(messagehdlr, file, "%s in [%g, %g]", SCIPvarGetName(var), SCIPvarGetLbLocal(var),
2506 SCIPvarGetUbLocal(var));
2507 }
2508 else if( SCIPexprIsSum(set, expr) )
2509 SCIPmessageFPrintInfo(messagehdlr, file, "%g", SCIPgetConstantExprSum(expr));
2510 else if( SCIPexprIsProduct(set, expr) )
2511 SCIPmessageFPrintInfo(messagehdlr, file, "%g", SCIPgetCoefExprProduct(expr));
2512 else if( SCIPexprIsValue(set, expr) )
2513 SCIPmessageFPrintInfo(messagehdlr, file, "%g", SCIPgetValueExprValue(expr));
2514 else if( SCIPexprIsPower(set, expr) || strcmp(expr->exprhdlr->name, "signpower") == 0)
2515 SCIPmessageFPrintInfo(messagehdlr, file, "%g", SCIPgetExponentExprPow(expr));
2516
2517 SCIPmessageFPrintInfo(messagehdlr, file, "\n");
2518
2519 if( expr->ownerprint != NULL )
2520 {
2521 SCIPmessageFPrintInfo(messagehdlr, file, "%*s ", nspaces, "");
2522 SCIP_CALL( expr->ownerprint(set->scip, file, expr, expr->ownerdata) );
2523 }
2524
2525 break;
2526 }
2527
2528 case SCIP_EXPRITER_VISITINGCHILD:
2529 {
2530 int nspaces = 3 * depth;
2531
2532 if( SCIPexprIsSum(set, expr) )
2533 {
2534 SCIPmessageFPrintInfo(messagehdlr, file, "%*s ", nspaces, "");
2535 SCIPmessageFPrintInfo(messagehdlr, file, "[coef]: %g\n", SCIPgetCoefsExprSum(expr)[SCIPexpriterGetChildIdxDFS(it)]);
2536 }
2537
2538 break;
2539 }
2540
2541 case SCIP_EXPRITER_LEAVEEXPR:
2542 {
2543 --depth;
2544 break;
2545 }
2546
2547 default:
2548 /* shouldn't be here */
2549 SCIPABORT();
2550 break;
2551 }
2552 }
2553
2554 SCIPexpriterFree(&it);
2555
2556 return SCIP_OKAY;
2557 }
2558
2559 /** evaluate an expression in a point
2560 *
2561 * Iterates over expressions to also evaluate children, if necessary.
2562 * Value can be received via SCIPexprGetEvalValue().
2563 * If an evaluation error (division by zero, ...) occurs, this value will
2564 * be set to SCIP_INVALID.
2565 *
2566 * If a nonzero \p soltag is passed, then only (sub)expressions are
2567 * reevaluated that have a different solution tag. If a soltag of 0
2568 * is passed, then subexpressions are always reevaluated.
2569 * The tag is stored together with the value and can be received via
2570 * SCIPexprGetEvalTag().
2571 */
2572 SCIP_RETCODE SCIPexprEval(
2573 SCIP_SET* set, /**< global SCIP settings */
2574 SCIP_STAT* stat, /**< dynamic problem statistics */
2575 BMS_BLKMEM* blkmem, /**< block memory */
2576 SCIP_EXPR* expr, /**< expression to be evaluated */
2577 SCIP_SOL* sol, /**< solution to be evaluated */
2578 SCIP_Longint soltag /**< tag that uniquely identifies the solution (with its values), or 0. */
2579 )
2580 {
2581 SCIP_EXPRITER* it;
2582
2583 assert(set != NULL);
2584 assert(stat != NULL);
2585 assert(blkmem != NULL);
2586 assert(expr != NULL);
2587
2588 /* if value is up-to-date, then nothing to do */
2589 if( soltag != 0 && expr->evaltag == soltag )
2590 return SCIP_OKAY;
2591
2592 /* assume we'll get a domain error, so we don't have to get this expr back if we abort the iteration
2593 * if there is no domain error, then we will overwrite the evalvalue in the last leaveexpr stage
2594 */
2595 expr->evalvalue = SCIP_INVALID;
2596 expr->evaltag = soltag;
2597
2598 SCIP_CALL( SCIPexpriterCreate(stat, blkmem, &it) );
2599 SCIP_CALL( SCIPexpriterInit(it, expr, SCIP_EXPRITER_DFS, TRUE) );
2600 SCIPexpriterSetStagesDFS(it, SCIP_EXPRITER_VISITINGCHILD | SCIP_EXPRITER_LEAVEEXPR);
2601
2602 while( !SCIPexpriterIsEnd(it) )
2603 {
2604 switch( SCIPexpriterGetStageDFS(it) )
2605 {
2606 case SCIP_EXPRITER_VISITINGCHILD :
2607 {
2608 SCIP_EXPR* child;
2609
2610 if( soltag == 0 )
2611 break;
2612
2613 /* check whether child has been evaluated for that solution already */
2614 child = SCIPexpriterGetChildExprDFS(it);
2615 if( soltag == child->evaltag )
2616 {
2617 if( child->evalvalue == SCIP_INVALID )
2618 goto TERMINATE;
2619
2620 /* skip this child
2621 * this already returns the next one, so continue with loop
2622 */
2623 expr = SCIPexpriterSkipDFS(it);
2624 continue;
2625 }
2626
2627 break;
2628 }
2629
2630 case SCIP_EXPRITER_LEAVEEXPR :
2631 {
2632 SCIP_CALL( SCIPexprhdlrEvalExpr(expr->exprhdlr, set, NULL , expr, &expr->evalvalue, NULL, sol) );
2633 expr->evaltag = soltag;
2634
2635 if( expr->evalvalue == SCIP_INVALID )
2636 goto TERMINATE;
2637
2638 break;
2639 }
2640
2641 default :
2642 /* we should never be here */
2643 SCIPABORT();
2644 break;
2645 }
2646
2647 expr = SCIPexpriterGetNext(it);
2648 }
2649
2650 TERMINATE:
2651 SCIPexpriterFree(&it);
2652
2653 return SCIP_OKAY;
2654 }
2655
2656 /** evaluates gradient of an expression for a given point
2657 *
2658 * Initiates an expression walk to also evaluate children, if necessary.
2659 * Value can be received via SCIPgetExprPartialDiffNonlinear().
2660 * If an error (division by zero, ...) occurs, this value will
2661 * be set to SCIP_INVALID.
2662 */
2663 SCIP_RETCODE SCIPexprEvalGradient(
2664 SCIP_SET* set, /**< global SCIP settings */
2665 SCIP_STAT* stat, /**< dynamic problem statistics */
2666 BMS_BLKMEM* blkmem, /**< block memory */
2667 SCIP_EXPR* rootexpr, /**< expression to be evaluated */
2668 SCIP_SOL* sol, /**< solution to be evaluated (NULL for the current LP solution) */
2669 SCIP_Longint soltag /**< tag that uniquely identifies the solution (with its values), or 0. */
2670 )
2671 {
2672 SCIP_EXPRITER* it;
2673 SCIP_EXPR* expr;
2674 SCIP_EXPR* child;
2675 SCIP_Real derivative;
2676 SCIP_Longint difftag;
2677
2678 assert(set != NULL);
2679 assert(stat != NULL);
2680 assert(blkmem != NULL);
2681 assert(rootexpr != NULL);
2682
2683 /* ensure expression is evaluated */
2684 SCIP_CALL( SCIPexprEval(set, stat, blkmem, rootexpr, sol, soltag) );
2685
2686 /* check if expression could not be evaluated */
2687 if( SCIPexprGetEvalValue(rootexpr) == SCIP_INVALID )
2688 {
2689 rootexpr->derivative = SCIP_INVALID;
2690 return SCIP_OKAY;
2691 }
2692
2693 if( SCIPexprIsValue(set, rootexpr) )
2694 {
2695 rootexpr->derivative = 0.0;
2696 return SCIP_OKAY;
2697 }
2698
2699 difftag = ++(stat->exprlastdifftag);
2700
2701 rootexpr->derivative = 1.0;
2702 rootexpr->difftag = difftag;
2703
2704 SCIP_CALL( SCIPexpriterCreate(stat, blkmem, &it) );
2705 SCIP_CALL( SCIPexpriterInit(it, rootexpr, SCIP_EXPRITER_DFS, TRUE) );
2706 SCIPexpriterSetStagesDFS(it, SCIP_EXPRITER_VISITINGCHILD);
2707
2708 for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
2709 {
2710 assert(expr->evalvalue != SCIP_INVALID);
2711
2712 child = SCIPexpriterGetChildExprDFS(it);
2713 assert(child != NULL);
2714
2715 /* reset the value of the partial derivative w.r.t. a variable expression if we see it for the first time */
2716 if( child->difftag != difftag && SCIPexprIsVar(set, child) )
2717 child->derivative = 0.0;
2718
2719 /* update differentiation tag of the child */
2720 child->difftag = difftag;
2721
2722 /* call backward differentiation callback */
2723 if( SCIPexprIsValue(set, child) )
2724 {
2725 derivative = 0.0;
2726 }
2727 else
2728 {
2729 derivative = SCIP_INVALID;
2730 SCIP_CALL( SCIPexprhdlrBwDiffExpr(expr->exprhdlr, set, NULL, expr, SCIPexpriterGetChildIdxDFS(it),
2731 &derivative, NULL, 0.0) );
2732
2733 if( derivative == SCIP_INVALID )
2734 {
2735 rootexpr->derivative = SCIP_INVALID;
2736 break;
2737 }
2738 }
2739
2740 /* update partial derivative stored in the child expression
2741 * for a variable, we have to sum up the partial derivatives of the root w.r.t. this variable over all parents
2742 * for other intermediate expressions, we only store the partial derivative of the root w.r.t. this expression
2743 */
2744 if( !SCIPexprIsVar(set, child) )
2745 child->derivative = expr->derivative * derivative;
2746 else
2747 child->derivative += expr->derivative * derivative;
2748 }
2749
2750 SCIPexpriterFree(&it);
2751
2752 return SCIP_OKAY;
2753 }
2754
2755 /** evaluates Hessian-vector product of an expression for a given point and direction
2756 *
2757 * Evaluates children, if necessary.
2758 * Value can be received via SCIPgetExprPartialDiffGradientDirNonlinear()
2759 * If an error (division by zero, ...) occurs, this value will
2760 * be set to SCIP_INVALID.
2761 */
2762 SCIP_RETCODE SCIPexprEvalHessianDir(
2763 SCIP_SET* set, /**< global SCIP settings */
2764 SCIP_STAT* stat, /**< dynamic problem statistics */
2765 BMS_BLKMEM* blkmem, /**< block memory */
2766 SCIP_EXPR* rootexpr, /**< expression to be evaluated */
2767 SCIP_SOL* sol, /**< solution to be evaluated (NULL for the current LP solution) */
2768 SCIP_Longint soltag, /**< tag that uniquely identifies the solution (with its values), or 0. */
2769 SCIP_SOL* direction /**< direction */
2770 )
2771 {
2772 SCIP_EXPRITER* it;
2773 SCIP_EXPR* expr;
2774 SCIP_EXPR* child;
2775 SCIP_Real derivative;
2776 SCIP_Real hessiandir;
2777
2778 assert(set != NULL);
2779 assert(stat != NULL);
2780 assert(blkmem != NULL);
2781 assert(rootexpr != NULL);
2782
2783 if( SCIPexprIsValue(set, rootexpr) )
2784 {
2785 rootexpr->dot = 0.0;
2786 rootexpr->bardot = 0.0;
2787 return SCIP_OKAY;
2788 }
2789
2790 /* evaluate expression and directional derivative */
2791 SCIP_CALL( evalAndDiff(set, stat, blkmem, rootexpr, sol, soltag, direction) );
2792
2793 if( rootexpr->evalvalue == SCIP_INVALID )
2794 {
2795 rootexpr->derivative = SCIP_INVALID;
2796 rootexpr->bardot = SCIP_INVALID;
2797 return SCIP_OKAY;
2798 }
2799
2800 rootexpr->derivative = 1.0;
2801
2802 SCIP_CALL( SCIPexpriterCreate(stat, blkmem, &it) );
2803 SCIP_CALL( SCIPexpriterInit(it, rootexpr, SCIP_EXPRITER_DFS, TRUE) );
2804 SCIPexpriterSetStagesDFS(it, SCIP_EXPRITER_VISITINGCHILD);
2805
2806 /* compute reverse diff and bardots: i.e. hessian times direction */
2807 for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
2808 {
2809 assert(expr->evalvalue != SCIP_INVALID);
2810
2811 child = SCIPexpriterGetChildExprDFS(it);
2812 assert(child != NULL);
2813
2814 /* call backward and forward-backward differentiation callback */
2815 if( SCIPexprIsValue(set, child) )
2816 {
2817 derivative = 0.0;
2818 hessiandir = 0.0;
2819 }
2820 else
2821 {
2822 derivative = SCIP_INVALID;
2823 hessiandir = SCIP_INVALID;
2824 SCIP_CALL( SCIPexprhdlrBwDiffExpr(expr->exprhdlr, set, NULL, expr, SCIPexpriterGetChildIdxDFS(it),
2825 &derivative, NULL, SCIP_INVALID) );
2826 SCIP_CALL( SCIPexprhdlrBwFwDiffExpr(expr->exprhdlr, set, expr, SCIPexpriterGetChildIdxDFS(it),
2827 &hessiandir, NULL) );
2828
2829 if( derivative == SCIP_INVALID || hessiandir == SCIP_INVALID )
2830 {
2831 rootexpr->derivative = SCIP_INVALID;
2832 rootexpr->bardot = SCIP_INVALID;
2833 break;
2834 }
2835 }
2836
2837 /* update partial derivative and hessian stored in the child expression
2838 * for a variable, we have to sum up the partial derivatives of the root w.r.t. this variable over all parents
2839 * for other intermediate expressions, we only store the partial derivative of the root w.r.t. this expression
2840 */
2841 if( !SCIPexprIsVar(set, child) )
2842 {
2843 child->derivative = expr->derivative * derivative;
2844 child->bardot = expr->bardot * derivative + expr->derivative * hessiandir;
2845 }
2846 else
2847 {
2848 child->derivative += expr->derivative * derivative;
2849 child->bardot += expr->bardot * derivative + expr->derivative * hessiandir;
2850 }
2851 }
2852
2853 SCIPexpriterFree(&it);
2854
2855 return SCIP_OKAY;
2856 }
2857
2858 /** possibly reevaluates and then returns the activity of the expression
2859 *
2860 * Reevaluate activity if currently stored is no longer uptodate.
2861 * If the expr owner provided a evalactivity-callback, then call this.
2862 * Otherwise, loop over descendants and compare activitytag with stat's domchgcount, i.e.,
2863 * whether some bound was changed since last evaluation, to check whether exprhdlrs INTEVAL should be called.
2864 *
2865 * @note If expression is set to be integral, then activities are tightened to integral values.
2866 * Thus, ensure that the integrality information is valid (if set to TRUE; the default (FALSE) is always ok).
2867 */
2868 SCIP_RETCODE SCIPexprEvalActivity(
2869 SCIP_SET* set, /**< global SCIP settings */
2870 SCIP_STAT* stat, /**< dynamic problem statistics */
2871 BMS_BLKMEM* blkmem, /**< block memory */
2872 SCIP_EXPR* rootexpr /**< expression */
2873 )
2874 {
2875 SCIP_EXPRITER* it;
2876 SCIP_EXPR* expr;
2877
2878 assert(set != NULL);
2879 assert(stat != NULL);
2880 assert(blkmem != NULL);
2881 assert(rootexpr != NULL);
2882
2883 if( rootexpr->ownerevalactivity != NULL )
2884 {
2885 /* call owner callback for activity-eval */
2886 SCIP_CALL( rootexpr->ownerevalactivity(set->scip, rootexpr, rootexpr->ownerdata) );
2887
2888 return SCIP_OKAY;
2889 }
2890
2891 /* fallback if no callback is given */
2892
2893 assert(rootexpr->activitytag <= stat->domchgcount);
2894
2895 /* if value is up-to-date, then nothing to do */
2896 if( rootexpr->activitytag == stat->domchgcount )
2897 {
2898 #ifdef DEBUG_PROP
2899 SCIPsetDebugMsg(set, "activitytag of root expr equals domchgcount (%u), skip evalactivity\n", stat->domchgcount);
2900 #endif
2901
2902 return SCIP_OKAY;
2903 }
2904
2905 SCIP_CALL( SCIPexpriterCreate(stat, blkmem, &it) );
2906 SCIP_CALL( SCIPexpriterInit(it, rootexpr, SCIP_EXPRITER_DFS, TRUE) );
2907 SCIPexpriterSetStagesDFS(it, SCIP_EXPRITER_VISITINGCHILD | SCIP_EXPRITER_LEAVEEXPR);
2908
2909 for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); )
2910 {
2911 switch( SCIPexpriterGetStageDFS(it) )
2912 {
2913 case SCIP_EXPRITER_VISITINGCHILD :
2914 {
2915 /* skip child if it has been evaluated already */
2916 SCIP_EXPR* child;
2917
2918 child = SCIPexpriterGetChildExprDFS(it);
2919 if( child->activitytag == stat->domchgcount )
2920 {
2921 expr = SCIPexpriterSkipDFS(it);
2922 continue;
2923 }
2924
2925 break;
2926 }
2927
2928 case SCIP_EXPRITER_LEAVEEXPR :
2929 {
2930 /* we should not have entered this expression if its activity was already uptodate */
2931 assert(expr->activitytag < stat->domchgcount);
2932
2933 /* reset activity to entire if invalid, so we can use it as starting point below */
2934 SCIPintervalSetEntire(SCIP_INTERVAL_INFINITY, &expr->activity);
2935
2936 #ifdef DEBUG_PROP
2937 SCIPsetDebugMsg(set, "interval evaluation of expr %p ", (void*)expr);
2938 SCIP_CALL( SCIPprintExpr(set->scip, expr, NULL) );
2939 SCIPsetDebugMsgPrint(set, "\n");
2940 #endif
2941
2942 /* call the inteval callback of the exprhdlr */
2943 SCIP_CALL( SCIPexprhdlrIntEvalExpr(expr->exprhdlr, set, expr, &expr->activity, NULL, NULL) );
2944 #ifdef DEBUG_PROP
2945 SCIPsetDebugMsg(set, " exprhdlr <%s>::inteval = [%.20g, %.20g]", expr->exprhdlr->name, expr->activity.inf,
2946 expr->activity.sup);
2947 #endif
2948
2949 /* if expression is integral, then we try to tighten the interval bounds a bit
2950 * this should undo the addition of some unnecessary safety added by use of nextafter() in interval
2951 * arithmetics, e.g., when doing pow() it would be ok to use ceil() and floor(), but for safety we
2952 * use SCIPceil and SCIPfloor for now the default intevalVar does not relax variables, so can omit
2953 * expressions without children (constants should be ok, too)
2954 */
2955 if( expr->isintegral && expr->nchildren > 0 )
2956 {
2957 if( expr->activity.inf > -SCIP_INTERVAL_INFINITY )
2958 expr->activity.inf = SCIPsetCeil(set, expr->activity.inf);
2959 if( expr->activity.sup < SCIP_INTERVAL_INFINITY )
2960 expr->activity.sup = SCIPsetFloor(set, expr->activity.sup);
2961 #ifdef DEBUG_PROP
2962 SCIPsetDebugMsg(set, " applying integrality: [%.20g, %.20g]\n", expr->activity.inf, expr->activity.sup);
2963 #endif
2964 }
2965
2966 /* mark activity as empty if either the lower/upper bound is above/below +/- SCIPinfinity()
2967 * TODO this is a problem if dual-presolve fixed a variable to +/- infinity
2968 */
2969 if( SCIPsetIsInfinity(set, expr->activity.inf) || SCIPsetIsInfinity(set, -expr->activity.sup) )
2970 {
2971 SCIPsetDebugMsg(set, "treat activity [%g,%g] as empty as beyond infinity\n", expr->activity.inf, expr->activity.sup);
2972 SCIPintervalSetEmpty(&expr->activity);
2973 }
2974
2975 /* remember that activity is uptodate now */
2976 expr->activitytag = stat->domchgcount;
2977
2978 break;
2979 }
2980
2981 default:
2982 /* you should never be here */
2983 SCIPABORT();
2984 break;
2985 }
2986
2987 expr = SCIPexpriterGetNext(it);
2988 }
2989
2990 SCIPexpriterFree(&it);
2991
2992 return SCIP_OKAY;
2993 }
2994
2995 /** compare expressions
2996 *
2997 * @return -1, 0 or 1 if expr1 <, =, > expr2, respectively
2998 * @note The given expressions are assumed to be simplified.
2999 */
3000 int SCIPexprCompare(
3001 SCIP_SET* set, /**< global SCIP settings */
3002 SCIP_EXPR* expr1, /**< first expression */
3003 SCIP_EXPR* expr2 /**< second expression */
3004 )
3005 {
3006 SCIP_EXPRHDLR* exprhdlr1;
3007 SCIP_EXPRHDLR* exprhdlr2;
3008 int retval;
3009
3010 exprhdlr1 = expr1->exprhdlr;
3011 exprhdlr2 = expr2->exprhdlr;
3012
3013 /* expressions are of the same kind/type; use compare callback or default method */
3014 if( exprhdlr1 == exprhdlr2 )
3015 return SCIPexprhdlrCompareExpr(set, expr1, expr2);
3016
3017 /* expressions are of different kind/type */
3018 /* enforces OR6 */
3019 if( SCIPexprIsValue(set, expr1) )
3020 {
3021 return -1;
3022 }
3023 /* enforces OR12 */
3024 if( SCIPexprIsValue(set, expr2) )
3025 return -SCIPexprCompare(set, expr2, expr1);
3026
3027 /* enforces OR7 */
3028 if( SCIPexprIsSum(set, expr1) )
3029 {
3030 int compareresult;
3031 int nchildren;
3032
3033 nchildren = expr1->nchildren;
3034 compareresult = SCIPexprCompare(set, expr1->children[nchildren-1], expr2);
3035
3036 if( compareresult != 0 )
3037 return compareresult;
3038
3039 /* "base" of the largest expression of the sum is equal to expr2, coefficient might tell us that
3040 * expr2 is larger */
3041 if( SCIPgetCoefsExprSum(expr1)[nchildren-1] < 1.0 )
3042 return -1;
3043
3044 /* largest expression of sum is larger or equal than expr2 => expr1 > expr2 */
3045 return 1;
3046 }
3047 /* enforces OR12 */
3048 if( SCIPexprIsSum(set, expr2) )
3049 return -SCIPexprCompare(set, expr2, expr1);
3050
3051 /* enforces OR8 */
3052 if( SCIPexprIsProduct(set, expr1) )
3053 {
3054 int compareresult;
3055 int nchildren;
3056
3057 nchildren = expr1->nchildren;
3058 compareresult = SCIPexprCompare(set, expr1->children[nchildren-1], expr2);
3059
3060 if( compareresult != 0 )
3061 return compareresult;
3062
3063 /* largest expression of product is larger or equal than expr2 => expr1 > expr2 */
3064 return 1;
3065 }
3066 /* enforces OR12 */
3067 if( SCIPexprIsProduct(set, expr2) )
3068 return -SCIPexprCompare(set, expr2, expr1);
3069
3070 /* enforces OR9 */
3071 if( SCIPexprIsPower(set, expr1) )
3072 {
3073 int compareresult;
3074
3075 compareresult = SCIPexprCompare(set, expr1->children[0], expr2);
3076
3077 if( compareresult != 0 )
3078 return compareresult;
3079
3080 /* base equal to expr2, exponent might tell us that expr2 is larger */
3081 if( SCIPgetExponentExprPow(expr1) < 1.0 )
3082 return -1;
3083
3084 /* power expression is larger => expr1 > expr2 */
3085 return 1;
3086 }
3087 /* enforces OR12 */
3088 if( SCIPexprIsPower(set, expr2) )
3089 return -SCIPexprCompare(set, expr2, expr1);
3090
3091 /* enforces OR10 */
3092 if( SCIPexprIsVar(set, expr1) )
3093 return -1;
3094 /* enforces OR12 */
3095 if( SCIPexprIsVar(set, expr2) )
3096 return -SCIPexprCompare(set, expr2, expr1);
3097
3098 /* enforces OR11 */
3099 retval = strcmp(SCIPexprhdlrGetName(exprhdlr1), SCIPexprhdlrGetName(exprhdlr2));
3100 return retval == 0 ? 0 : retval < 0 ? -1 : 1;
3101 }
3102
3103 /** simplifies an expression
3104 *
3105 * @see SCIPsimplifyExpr
3106 */
3107 SCIP_RETCODE SCIPexprSimplify(
3108 SCIP_SET* set, /**< global SCIP settings */
3109 SCIP_STAT* stat, /**< dynamic problem statistics */
3110 BMS_BLKMEM* blkmem, /**< block memory */
3111 SCIP_EXPR* rootexpr, /**< expression to be simplified */
3112 SCIP_EXPR** simplified, /**< buffer to store simplified expression */
3113 SCIP_Bool* changed, /**< buffer to store if rootexpr actually changed */
3114 SCIP_Bool* infeasible, /**< buffer to store whether infeasibility has been detected */
3115 SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), /**< function to call to create ownerdata */
3116 void* ownercreatedata /**< data to pass to ownercreate */
3117 )
3118 {
3119 SCIP_EXPR* expr;
3120 SCIP_EXPRITER* it;
3121
3122 assert(rootexpr != NULL);
3123 assert(simplified != NULL);
3124 assert(changed != NULL);
3125 assert(infeasible != NULL);
3126
3127 /* simplify bottom up
3128 * when leaving an expression it simplifies it and stores the simplified expr in its iterators expression data
3129 * after the child was visited, it is replaced with the simplified expr
3130 */
3131 SCIP_CALL( SCIPexpriterCreate(stat, blkmem, &it) );
3132 SCIP_CALL( SCIPexpriterInit(it, rootexpr, SCIP_EXPRITER_DFS, TRUE) ); /* TODO can we set allowrevisited to FALSE?*/
3133 SCIPexpriterSetStagesDFS(it, SCIP_EXPRITER_VISITEDCHILD | SCIP_EXPRITER_LEAVEEXPR);
3134
3135 *changed = FALSE;
3136 *infeasible = FALSE;
3137 for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
3138 {
3139 switch( SCIPexpriterGetStageDFS(it) )
3140 {
3141 case SCIP_EXPRITER_VISITEDCHILD:
3142 {
3143 SCIP_EXPR* newchild;
3144 SCIP_EXPR* child;
3145
3146 newchild = (SCIP_EXPR*)SCIPexpriterGetChildUserDataDFS(it).ptrval;
3147 child = SCIPexpriterGetChildExprDFS(it);
3148 assert(newchild != NULL);
3149
3150 /* if child got simplified, replace it with the new child */
3151 if( newchild != child )
3152 {
3153 SCIP_CALL( SCIPexprReplaceChild(set, stat, blkmem, expr, SCIPexpriterGetChildIdxDFS(it), newchild) );
3154 }
3155
3156 /* we do not need to hold newchild anymore */
3157 SCIP_CALL( SCIPexprRelease(set, stat, blkmem, &newchild) );
3158
3159 break;
3160 }
3161
3162 case SCIP_EXPRITER_LEAVEEXPR:
3163 {
3164 SCIP_EXPR* refexpr = NULL;
3165 SCIP_EXPRITER_USERDATA iterdata;
3166
3167 /* TODO we should do constant folding (handle that all children are value-expressions) here in a generic way
3168 * instead of reimplementing it in every handler
3169 */
3170
3171 /* use simplification of expression handlers */
3172 SCIP_CALL( SCIPexprhdlrSimplifyExpr(expr->exprhdlr, set, expr, &refexpr, ownercreate, ownercreatedata) );
3173 assert(refexpr != NULL);
3174 if( expr != refexpr )
3175 *changed = TRUE;
3176
3177 iterdata.ptrval = (void*) refexpr;
3178 SCIPexpriterSetCurrentUserData(it, iterdata);
3179
3180 break;
3181 }
3182
3183 default:
3184 SCIPABORT(); /* we should never be called in this stage */
3185 break;
3186 }
3187 }
3188
3189 *simplified = (SCIP_EXPR*)SCIPexpriterGetExprUserData(it, rootexpr).ptrval;
3190 assert(*simplified != NULL);
3191
3192 SCIPexpriterFree(&it);
3193
3194 return SCIP_OKAY;
3195 }
3196
3197 /** checks whether an expression is quadratic
3198 *
3199 * An expression is quadratic if it is either a power expression with exponent 2.0, a product of two expressions,
3200 * or a sum of terms where at least one is a square or a product of two.
3201 *
3202 * Use \ref SCIPexprGetQuadraticData to get data about the representation as quadratic.
3203 */
3204 SCIP_RETCODE SCIPexprCheckQuadratic(
3205 SCIP_SET* set, /**< global SCIP settings */
3206 BMS_BLKMEM* blkmem, /**< block memory */
3207 SCIP_EXPR* expr, /**< expression */
3208 SCIP_Bool* isquadratic /**< buffer to store result */
3209 )
3210 {
3211 SCIP_HASHMAP* expr2idx;
3212 SCIP_HASHMAP* seenexpr = NULL;
3213 int nquadterms = 0;
3214 int nlinterms = 0;
3215 int nbilinterms = 0;
3216 int c;
3217
3218 assert(set != NULL);
3219 assert(blkmem != NULL);
3220 assert(expr != NULL);
3221 assert(isquadratic != NULL);
3222
3223 if( expr->quadchecked )
3224 {
3225 *isquadratic = expr->quaddata != NULL;
3226 return SCIP_OKAY;
3227 }
3228 assert(expr->quaddata == NULL);
3229
3230 expr->quadchecked = TRUE;
3231 *isquadratic = FALSE;
3232
3233 /* check if expression is a quadratic expression */
3234 SCIPsetDebugMsg(set, "checking if expr %p is quadratic\n", (void*)expr);
3235
3236 /* handle single square term */
3237 if( SCIPexprIsPower(set, expr) && SCIPgetExponentExprPow(expr) == 2.0 )
3238 {
3239 SCIPsetDebugMsg(set, "expr %p looks like square: fill data structures\n", (void*)expr);
3240 SCIP_ALLOC( BMSallocClearBlockMemory(blkmem, &expr->quaddata) );
3241
3242 expr->quaddata->nquadexprs = 1;
3243 SCIP_ALLOC( BMSallocClearBlockMemoryArray(blkmem, &expr->quaddata->quadexprterms, 1) );
3244 expr->quaddata->quadexprterms[0].expr = expr->children[0];
3245 expr->quaddata->quadexprterms[0].sqrcoef = 1.0;
3246
3247 expr->quaddata->allexprsarevars = SCIPexprIsVar(set, expr->quaddata->quadexprterms[0].expr);
3248
3249 *isquadratic = TRUE;
3250 return SCIP_OKAY;
3251 }
3252
3253 /* handle single bilinear term */
3254 if( SCIPexprIsProduct(set, expr) && SCIPexprGetNChildren(expr) == 2 )
3255 {
3256 SCIPsetDebugMsg(set, "expr %p looks like bilinear product: fill data structures\n", (void*)expr);
3257 SCIP_ALLOC( BMSallocClearBlockMemory(blkmem, &expr->quaddata) );
3258 expr->quaddata->nquadexprs = 2;
3259
3260 SCIP_ALLOC( BMSallocClearBlockMemoryArray(blkmem, &expr->quaddata->quadexprterms, 2) );
3261 expr->quaddata->quadexprterms[0].expr = SCIPexprGetChildren(expr)[0];
3262 expr->quaddata->quadexprterms[0].nadjbilin = 1;
3263 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &expr->quaddata->quadexprterms[0].adjbilin, 1) );
3264 expr->quaddata->quadexprterms[0].adjbilin[0] = 0;
3265
3266 expr->quaddata->quadexprterms[1].expr = SCIPexprGetChildren(expr)[1];
3267 expr->quaddata->quadexprterms[1].nadjbilin = 1;
3268 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &expr->quaddata->quadexprterms[1].adjbilin, 1) );
3269 expr->quaddata->quadexprterms[1].adjbilin[0] = 0;
3270
3271 expr->quaddata->nbilinexprterms = 1;
3272 SCIP_ALLOC( BMSallocClearBlockMemoryArray(blkmem, &expr->quaddata->bilinexprterms, 1) );
3273 expr->quaddata->bilinexprterms[0].expr1 = SCIPexprGetChildren(expr)[1];
3274 expr->quaddata->bilinexprterms[0].expr2 = SCIPexprGetChildren(expr)[0];
3275 expr->quaddata->bilinexprterms[0].coef = 1.0;
3276
3277 expr->quaddata->allexprsarevars = SCIPexprIsVar(set, expr->quaddata->quadexprterms[0].expr)
3278 && SCIPexprIsVar(set, expr->quaddata->quadexprterms[1].expr);
3279
3280 *isquadratic = TRUE;
3281 return SCIP_OKAY;
3282 }
3283
3284 /* neither a sum, nor a square, nor a bilinear term */
3285 if( !SCIPexprIsSum(set, expr) )
3286 return SCIP_OKAY;
3287
3288 SCIP_CALL( SCIPhashmapCreate(&seenexpr, blkmem, 2*SCIPexprGetNChildren(expr)) );
3289 for( c = 0; c < SCIPexprGetNChildren(expr); ++c )
3290 {
3291 SCIP_EXPR* child;
3292
3293 child = SCIPexprGetChildren(expr)[c];
3294 assert(child != NULL);
3295
3296 if( SCIPexprIsPower(set, child) && SCIPgetExponentExprPow(child) == 2.0 ) /* quadratic term */
3297 {
3298 SCIP_CALL( quadDetectProcessExpr(SCIPexprGetChildren(child)[0], seenexpr, &nquadterms, &nlinterms) );
3299 }
3300 else if( SCIPexprIsProduct(set, child) && SCIPexprGetNChildren(child) == 2 ) /* bilinear term */
3301 {
3302 ++nbilinterms;
3303 SCIP_CALL( quadDetectProcessExpr(SCIPexprGetChildren(child)[0], seenexpr, &nquadterms, &nlinterms) );
3304 SCIP_CALL( quadDetectProcessExpr(SCIPexprGetChildren(child)[1], seenexpr, &nquadterms, &nlinterms) );
3305 }
3306 else
3307 {
3308 /* first time seen linearly --> assign -1; ++nlinterms
3309 * not first time --> assign +=1;
3310 */
3311 if( SCIPhashmapExists(seenexpr, (void*)child) )
3312 {
3313 assert(SCIPhashmapGetImageInt(seenexpr, (void*)child) > 0);
3314
3315 SCIP_CALL( SCIPhashmapSetImageInt(seenexpr, (void*)child, SCIPhashmapGetImageInt(seenexpr, (void*)child) + 1) );
3316 }
3317 else
3318 {
3319 ++nlinterms;
3320 SCIP_CALL( SCIPhashmapInsertInt(seenexpr, (void*)child, -1) );
3321 }
3322 }
3323 }
3324
3325 if( nquadterms == 0 )
3326 {
3327 /* only linear sum */
3328 SCIPhashmapFree(&seenexpr);
3329 return SCIP_OKAY;
3330 }
3331
3332 SCIPsetDebugMsg(set, "expr %p looks quadratic: fill data structures\n", (void*)expr);
3333
3334 /* expr2idx maps expressions to indices; if index > 0, it is its index in the linexprs array, otherwise -index-1 is
3335 * its index in the quadexprterms array
3336 */
3337 SCIP_CALL( SCIPhashmapCreate(&expr2idx, blkmem, nquadterms + nlinterms) );
3338
3339 /* allocate memory, etc */
3340 SCIP_ALLOC( BMSallocClearBlockMemory(blkmem, &expr->quaddata) );
3341 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &expr->quaddata->quadexprterms, nquadterms) );
3342 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &expr->quaddata->linexprs, nlinterms) );
3343 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &expr->quaddata->lincoefs, nlinterms) );
3344 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &expr->quaddata->bilinexprterms, nbilinterms) );
3345
3346 expr->quaddata->constant = SCIPgetConstantExprSum(expr);
3347
3348 expr->quaddata->allexprsarevars = TRUE;
3349 /* for every term of the sum-expr */
3350 for( c = 0; c < SCIPexprGetNChildren(expr); ++c )
3351 {
3352 SCIP_EXPR* child;
3353 SCIP_Real coef;
3354
3355 child = SCIPexprGetChildren(expr)[c];
3356 coef = SCIPgetCoefsExprSum(expr)[c];
3357
3358 assert(child != NULL);
3359 assert(coef != 0.0);
3360
3361 if( SCIPexprIsPower(set, child) && SCIPgetExponentExprPow(child) == 2.0 ) /* quadratic term */
3362 {
3363 SCIP_QUADEXPR_QUADTERM* quadexprterm;
3364 assert(SCIPexprGetNChildren(child) == 1);
3365
3366 child = SCIPexprGetChildren(child)[0];
3367 assert(SCIPhashmapGetImageInt(seenexpr, (void *)child) > 0);
3368
3369 SCIP_CALL( quadDetectGetQuadexprterm(blkmem, child, expr2idx, seenexpr, expr->quaddata, &quadexprterm) );
3370 assert(quadexprterm->expr == child);
3371 quadexprterm->sqrcoef = coef;
3372 quadexprterm->sqrexpr = SCIPexprGetChildren(expr)[c];
3373
3374 if( expr->quaddata->allexprsarevars )
3375 expr->quaddata->allexprsarevars = SCIPexprIsVar(set, quadexprterm->expr);
3376 }
3377 else if( SCIPexprIsProduct(set, child) && SCIPexprGetNChildren(child) == 2 ) /* bilinear term */
3378 {
3379 SCIP_QUADEXPR_BILINTERM* bilinexprterm;
3380 SCIP_QUADEXPR_QUADTERM* quadexprterm;
3381 SCIP_EXPR* expr1;
3382 SCIP_EXPR* expr2;
3383
3384 assert(SCIPgetCoefExprProduct(child) == 1.0);
3385
3386 expr1 = SCIPexprGetChildren(child)[0];
3387 expr2 = SCIPexprGetChildren(child)[1];
3388 assert(expr1 != NULL && expr2 != NULL);
3389
3390 bilinexprterm = &expr->quaddata->bilinexprterms[expr->quaddata->nbilinexprterms];
3391
3392 bilinexprterm->coef = coef;
3393 if( SCIPhashmapGetImageInt(seenexpr, (void*)expr1) >= SCIPhashmapGetImageInt(seenexpr, (void*)expr2) )
3394 {
3395 bilinexprterm->expr1 = expr1;
3396 bilinexprterm->expr2 = expr2;
3397 }
3398 else
3399 {
3400 bilinexprterm->expr1 = expr2;
3401 bilinexprterm->expr2 = expr1;
3402 }
3403 bilinexprterm->prodexpr = child;
3404
3405 SCIP_CALL( quadDetectGetQuadexprterm(blkmem, expr1, expr2idx, seenexpr, expr->quaddata, &quadexprterm) );
3406 assert(quadexprterm->expr == expr1);
3407 quadexprterm->adjbilin[quadexprterm->nadjbilin] = expr->quaddata->nbilinexprterms;
3408 ++quadexprterm->nadjbilin;
3409
3410 if( expr->quaddata->allexprsarevars )
3411 expr->quaddata->allexprsarevars = SCIPexprIsVar(set, quadexprterm->expr);
3412
3413 SCIP_CALL( quadDetectGetQuadexprterm(blkmem, expr2, expr2idx, seenexpr, expr->quaddata, &quadexprterm) );
3414 assert(quadexprterm->expr == expr2);
3415 quadexprterm->adjbilin[quadexprterm->nadjbilin] = expr->quaddata->nbilinexprterms;
3416 ++quadexprterm->nadjbilin;
3417
3418 if( expr->quaddata->allexprsarevars )
3419 expr->quaddata->allexprsarevars = SCIPexprIsVar(set, quadexprterm->expr);
3420
3421 ++expr->quaddata->nbilinexprterms;
3422
3423 /* store position of second factor in quadexprterms */
3424 bilinexprterm->pos2 = SCIPhashmapGetImageInt(expr2idx, (void*)bilinexprterm->expr2);
3425 }
3426 else /* linear term */
3427 {
3428 if( SCIPhashmapGetImageInt(seenexpr, (void*)child) < 0 )
3429 {
3430 assert(SCIPhashmapGetImageInt(seenexpr, (void*)child) == -1);
3431
3432 /* expression only appears linearly */
3433 expr->quaddata->linexprs[expr->quaddata->nlinexprs] = child;
3434 expr->quaddata->lincoefs[expr->quaddata->nlinexprs] = coef;
3435 expr->quaddata->nlinexprs++;
3436
3437 if( expr->quaddata->allexprsarevars )
3438 expr->quaddata->allexprsarevars = SCIPexprIsVar(set, child);
3439 }
3440 else
3441 {
3442 /* expression appears non-linearly: set lin coef */
3443 SCIP_QUADEXPR_QUADTERM* quadexprterm;
3444 assert(SCIPhashmapGetImageInt(seenexpr, (void*)child) > 0);
3445
3446 SCIP_CALL( quadDetectGetQuadexprterm(blkmem, child, expr2idx, seenexpr, expr->quaddata, &quadexprterm) );
3447 assert(quadexprterm->expr == child);
3448 quadexprterm->lincoef = coef;
3449
3450 if( expr->quaddata->allexprsarevars )
3451 expr->quaddata->allexprsarevars = SCIPexprIsVar(set, quadexprterm->expr);
3452 }
3453 }
3454 }
3455 assert(expr->quaddata->nquadexprs == nquadterms);
3456 assert(expr->quaddata->nlinexprs == nlinterms);
3457 assert(expr->quaddata->nbilinexprterms == nbilinterms);
3458
3459 SCIPhashmapFree(&seenexpr);
3460 SCIPhashmapFree(&expr2idx);
3461
3462 *isquadratic = TRUE;
3463
3464 return SCIP_OKAY;
3465 }
3466
3467 /** frees information on quadratic representation of an expression
3468 *
3469 * Reverts SCIPexprCheckQuadratic().
3470 * Before doing changes to an expression, it can be useful to call this function.
3471 */
3472 void SCIPexprFreeQuadratic(
3473 BMS_BLKMEM* blkmem, /**< block memory */
3474 SCIP_EXPR* expr /**< expression */
3475 )
3476 {
3477 int i;
3478 int n;
3479
3480 assert(blkmem != NULL);
3481 assert(expr != NULL);
3482
3483 expr->quadchecked = FALSE;
3484
3485 if( expr->quaddata == NULL )
3486 return;
3487
3488 n = expr->quaddata->nquadexprs;
3489
3490 BMSfreeBlockMemoryArrayNull(blkmem, &expr->quaddata->linexprs, expr->quaddata->nlinexprs);
3491 BMSfreeBlockMemoryArrayNull(blkmem, &expr->quaddata->lincoefs, expr->quaddata->nlinexprs);
3492 BMSfreeBlockMemoryArrayNull(blkmem, &expr->quaddata->bilinexprterms, expr->quaddata->nbilinexprterms);
3493 BMSfreeBlockMemoryArrayNull(blkmem, &expr->quaddata->eigenvalues, n);
3494 BMSfreeBlockMemoryArrayNull(blkmem, &expr->quaddata->eigenvectors, n * n); /*lint !e647*/
3495
3496 for( i = 0; i < n; ++i )
3497 {
3498 BMSfreeBlockMemoryArrayNull(blkmem, &expr->quaddata->quadexprterms[i].adjbilin,
3499 expr->quaddata->quadexprterms[i].adjbilinsize);
3500 }
3501 BMSfreeBlockMemoryArrayNull(blkmem, &expr->quaddata->quadexprterms, n);
3502
3503 BMSfreeBlockMemory(blkmem, &expr->quaddata);
3504 }
3505
3506 /** Checks the curvature of the quadratic function stored in quaddata
3507 *
3508 * For this, it builds the matrix Q of quadratic coefficients and computes its eigenvalues using LAPACK.
3509 * If Q is
3510 * - semidefinite positive -> curv is set to convex,
3511 * - semidefinite negative -> curv is set to concave,
3512 * - otherwise -> curv is set to unknown.
3513 *
3514 * If `assumevarfixed` is given and some expressions in quadratic terms correspond to variables present in
3515 * this hashmap, then the corresponding rows and columns are ignored in the matrix Q.
3516 */
3517 SCIP_RETCODE SCIPexprComputeQuadraticCurvature(
3518 SCIP_SET* set, /**< global SCIP settings */
3519 BMS_BLKMEM* blkmem, /**< block memory */
3520 BMS_BUFMEM* bufmem, /**< buffer memory */
3521 SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
3522 SCIP_EXPR* expr, /**< quadratic expression */
3523 SCIP_EXPRCURV* curv, /**< pointer to store the curvature of quadratics */
3524 SCIP_HASHMAP* assumevarfixed, /**< hashmap containing variables that should be assumed to be fixed, or NULL */
3525 SCIP_Bool storeeigeninfo /**< whether the eigenvalues and eigenvectors should be stored */
3526 )
3527 {
3528 SCIP_QUADEXPR* quaddata;
3529 SCIP_HASHMAP* expr2matrix;
3530 double* matrix;
3531 double* alleigval;
3532 int nvars;
3533 int nn;
3534 int n;
3535 int i;
3536
3537 assert(set != NULL);
3538 assert(blkmem != NULL);
3539 assert(bufmem != NULL);
3540 assert(messagehdlr != NULL);
3541 assert(expr != NULL);
3542 assert(curv != NULL);
3543
3544 quaddata = expr->quaddata;
3545 assert(quaddata != NULL);
3546
3547 /* do not store eigen information if we are not considering full matrix */
3548 if( assumevarfixed != NULL )
3549 storeeigeninfo = FALSE;
3550
3551 if( quaddata->eigeninfostored || (quaddata->curvaturechecked && !storeeigeninfo) )
3552 {
3553 *curv = quaddata->curvature;
3554 /* if we are convex or concave on the full set of variables, then we will also be so on a subset */
3555 if( assumevarfixed == NULL || quaddata->curvature != SCIP_EXPRCURV_UNKNOWN )
3556 return SCIP_OKAY;
3557 }
3558 assert(quaddata->curvature == SCIP_EXPRCURV_UNKNOWN || assumevarfixed != NULL
3559 || (storeeigeninfo && !quaddata->eigeninfostored));
3560
3561 *curv = SCIP_EXPRCURV_UNKNOWN;
3562
3563 n = quaddata->nquadexprs;
3564
3565 /* do not check curvature if nn will be too large
3566 * we want nn * sizeof(real) to fit into an unsigned int, so n must be <= sqrt(unit_max/sizeof(real))
3567 * sqrt(2*214748364/8) = 7327.1475350234
3568 */
3569 if( n > 7000 )
3570 {
3571 SCIPmessageFPrintVerbInfo(messagehdlr, set->disp_verblevel, SCIP_VERBLEVEL_FULL, NULL,
3572 "number of quadratic variables is too large (%d) to check the curvature\n", n);
3573 return SCIP_OKAY;
3574 }
3575
3576 /* TODO do some simple tests first; like diagonal entries don't change sign, etc */
3577
3578 if( !SCIPisIpoptAvailableIpopt() )
3579 return SCIP_OKAY;
3580
3581 nn = n * n;
3582 assert(nn > 0);
3583 assert((unsigned)nn < UINT_MAX / sizeof(SCIP_Real));
3584
3585 if( storeeigeninfo )
3586 {
3587 SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &quaddata->eigenvalues, n));
3588 SCIP_ALLOC( BMSallocClearBlockMemoryArray(blkmem, &quaddata->eigenvectors, nn));
3589
3590 alleigval = quaddata->eigenvalues;
3591 matrix = quaddata->eigenvectors;
3592 }
3593 else
3594 {
3595 SCIP_ALLOC( BMSallocBufferMemoryArray(bufmem, &alleigval, n) );
3596 SCIP_ALLOC( BMSallocClearBufferMemoryArray(bufmem, &matrix, nn) );
3597 }
3598
3599 SCIP_CALL( SCIPhashmapCreate(&expr2matrix, blkmem, n) );
3600
3601 /* fill matrix's diagonal */
3602 nvars = 0;
3603 for( i = 0; i < n; ++i )
3604 {
3605 SCIP_QUADEXPR_QUADTERM quadexprterm;
3606
3607 quadexprterm = quaddata->quadexprterms[i];
3608
3609 assert(!SCIPhashmapExists(expr2matrix, (void*)quadexprterm.expr));
3610
3611 /* skip expr if it is a variable mentioned in assumevarfixed */
3612 if( assumevarfixed != NULL && SCIPexprIsVar(set, quadexprterm.expr)
3613 && SCIPhashmapExists(assumevarfixed, (void*)SCIPgetVarExprVar(quadexprterm.expr)) )
3614 continue;
3615
3616 if( quadexprterm.sqrcoef == 0.0 && ! storeeigeninfo )
3617 {
3618 assert(quadexprterm.nadjbilin > 0);
3619 /* SCIPdebugMsg(scip, "var <%s> appears in bilinear term but is not squared
3620 * --> indefinite quadratic\n", SCIPvarGetName(quadexprterm.var)); */
3621 goto CLEANUP;
3622 }
3623
3624 matrix[nvars * n + nvars] = quadexprterm.sqrcoef;
3625
3626 /* remember row of variable in matrix */
3627 SCIP_CALL( SCIPhashmapInsert(expr2matrix, (void *)quadexprterm.expr, (void *)(size_t)nvars) );
3628 nvars++;
3629 }
3630
3631 /* fill matrix's upper-diagonal */
3632 for( i = 0; i < quaddata->nbilinexprterms; ++i )
3633 {
3634 SCIP_QUADEXPR_BILINTERM bilinexprterm;
3635 int col;
3636 int row;
3637
3638 bilinexprterm = quaddata->bilinexprterms[i];
3639
3640 /* each factor should have been added to expr2matrix unless it corresponds to a variable mentioned in assumevarfixed */
3641 assert(SCIPhashmapExists(expr2matrix, (void*)bilinexprterm.expr1)
3642 || (assumevarfixed != NULL && SCIPexprIsVar(set, bilinexprterm.expr1)
3643 && SCIPhashmapExists(assumevarfixed, (void*)SCIPgetVarExprVar(bilinexprterm.expr1))));
3644 assert(SCIPhashmapExists(expr2matrix, (void*)bilinexprterm.expr2)
3645 || (assumevarfixed != NULL && SCIPexprIsVar(set, bilinexprterm.expr2)
3646 && SCIPhashmapExists(assumevarfixed, (void*)SCIPgetVarExprVar(bilinexprterm.expr2))));
3647
3648 /* skip bilinear terms where at least one of the factors should be assumed to be fixed
3649 * (i.e., not present in expr2matrix map) */
3650 if( !SCIPhashmapExists(expr2matrix, (void*)bilinexprterm.expr1)
3651 || !SCIPhashmapExists(expr2matrix, (void*)bilinexprterm.expr2) )
3652 continue;
3653
3654 row = (int)(size_t)SCIPhashmapGetImage(expr2matrix, bilinexprterm.expr1);
3655 col = (int)(size_t)SCIPhashmapGetImage(expr2matrix, bilinexprterm.expr2);
3656
3657 assert(row != col);
3658
3659 if( row < col )
3660 matrix[row * n + col] = bilinexprterm.coef / 2.0;
3661 else
3662 matrix[col * n + row] = bilinexprterm.coef / 2.0;
3663 }
3664
3665 /* compute eigenvalues */
3666 if( SCIPcallLapackDsyevIpopt(storeeigeninfo, n, matrix, alleigval) != SCIP_OKAY )
3667 {
3668 SCIPmessagePrintWarning(messagehdlr, "Failed to compute eigenvalues of quadratic coefficient "
3669 "matrix --> don't know curvature\n");
3670 goto CLEANUP;
3671 }
3672
3673 /* check convexity */
3674 if( !SCIPsetIsNegative(set, alleigval[0]) )
3675 *curv = SCIP_EXPRCURV_CONVEX;
3676 else if( !SCIPsetIsPositive(set, alleigval[n-1]) )
3677 *curv = SCIP_EXPRCURV_CONCAVE;
3678
3679 CLEANUP:
3680 SCIPhashmapFree(&expr2matrix);
3681
3682 if( !storeeigeninfo )
3683 {
3684 BMSfreeBufferMemoryArray(bufmem, &matrix);
3685 BMSfreeBufferMemoryArray(bufmem, &alleigval);
3686 }
3687 else
3688 {
3689 assert(!quaddata->eigeninfostored);
3690 quaddata->eigeninfostored = TRUE;
3691 }
3692
3693 /* if checked convexity on full Q matrix, then remember it
3694 * if indefinite on submatrix, then it will also be indefinite on full matrix, so can remember that, too */
3695 if( assumevarfixed == NULL || *curv == SCIP_EXPRCURV_UNKNOWN )
3696 {
3697 quaddata->curvature = *curv;
3698 quaddata->curvaturechecked = TRUE;
3699 }
3700
3701 return SCIP_OKAY;
3702 }
3703
3704
3705 /* from pub_expr.h */
3706
3707 /** gets the number of times the expression is currently captured */
3708 int SCIPexprGetNUses(
3709 SCIP_EXPR* expr /**< expression */
3710 )
3711 {
3712 assert(expr != NULL);
3713
3714 return expr->nuses;
3715 }
3716
3717 /** gives the number of children of an expression */
3718 int SCIPexprGetNChildren(
3719 SCIP_EXPR* expr /**< expression */
3720 )
3721 {
3722 assert(expr != NULL);
3723
3724 return expr->nchildren;
3725 }
3726
3727 /** gives the children of an expression (can be NULL if no children) */
3728 SCIP_EXPR** SCIPexprGetChildren(
3729 SCIP_EXPR* expr /**< expression */
3730 )
3731 {
3732 assert(expr != NULL);
3733
3734 return expr->children;
3735 }
3736
3737 /** gets the expression handler of an expression
3738 *
3739 * This identifies the type of the expression (sum, variable, ...).
3740 */
3741 SCIP_EXPRHDLR* SCIPexprGetHdlr(
3742 SCIP_EXPR* expr /**< expression */
3743 )
3744 {
3745 assert(expr != NULL);
3746
3747 return expr->exprhdlr;
3748 }
3749
3750 /** gets the expression data of an expression */
3751 SCIP_EXPRDATA* SCIPexprGetData(
3752 SCIP_EXPR* expr /**< expression */
3753 )
3754 {
3755 assert(expr != NULL);
3756
3757 return expr->exprdata;
3758 }
3759
3760 /** sets the expression data of an expression
3761 *
3762 * The pointer to possible old data is overwritten and the
3763 * freedata-callback is not called before.
3764 * This function is intended to be used by expression handler only.
3765 */
3766 void SCIPexprSetData(
3767 SCIP_EXPR* expr, /**< expression */
3768 SCIP_EXPRDATA* exprdata /**< expression data to be set (can be NULL) */
3769 )
3770 {
3771 assert(expr != NULL);
3772 assert(exprdata == NULL || expr->exprhdlr->copydata != NULL); /* copydata must be available if there is expression data */
3773 assert(exprdata == NULL || expr->exprhdlr->freedata != NULL); /* freedata must be available if there is expression data */
3774
3775 expr->exprdata = exprdata;
3776 }
3777
3778 /** gets the data that the owner of an expression has stored in an expression */
3779 SCIP_EXPR_OWNERDATA* SCIPexprGetOwnerData(
3780 SCIP_EXPR* expr /**< expression */
3781 )
3782 {
3783 assert(expr != NULL);
3784
3785 return expr->ownerdata;
3786 }
3787
3788 /** gives the value from the last evaluation of an expression (or SCIP_INVALID if there was an eval error)
3789 *
3790 * @see SCIPevalExpr
3791 */
3792 SCIP_Real SCIPexprGetEvalValue(
3793 SCIP_EXPR* expr /**< expression */
3794 )
3795 {
3796 assert(expr != NULL);
3797
3798 return expr->evalvalue;
3799 }
3800
3801 /** gives the evaluation tag from the last evaluation, or 0
3802 *
3803 * @see SCIPevalExpr
3804 */
3805 SCIP_Longint SCIPexprGetEvalTag(
3806 SCIP_EXPR* expr /**< expression */
3807 )
3808 {
3809 assert(expr != NULL);
3810
3811 return expr->evaltag;
3812 }
3813
3814 /** returns the derivative stored in an expression (or SCIP_INVALID if there was an evaluation error)
3815 *
3816 * @see SCIPevalExprGradient
3817 */
3818 SCIP_Real SCIPexprGetDerivative(
3819 SCIP_EXPR* expr /**< expression */
3820 )
3821 {
3822 assert(expr != NULL);
3823
3824 return expr->derivative;
3825 }
3826
3827 /** gives the value of directional derivative from the last evaluation of a directional derivative of
3828 * expression (or SCIP_INVALID if there was an error)
3829 *
3830 * @see SCIPevalExprHessianDir
3831 */
3832 SCIP_Real SCIPexprGetDot(
3833 SCIP_EXPR* expr /**< expression */
3834 )
3835 {
3836 assert(expr != NULL);
3837
3838 return expr->dot;
3839 }
3840
3841 /** gives the value of directional derivative from the last evaluation of a directional derivative of
3842 * derivative of root (or SCIP_INVALID if there was an error)
3843 *
3844 * @see SCIPevalExprHessianDir
3845 */
3846 SCIP_Real SCIPexprGetBardot(
3847 SCIP_EXPR* expr /**< expression */
3848 )
3849 {
3850 assert(expr != NULL);
3851
3852 return expr->bardot;
3853 }
3854
3855 /** returns the difftag stored in an expression
3856 *
3857 * can be used to check whether partial derivative value is valid
3858 *
3859 * @see SCIPevalExprGradient
3860 */
3861 SCIP_Longint SCIPexprGetDiffTag(
3862 SCIP_EXPR* expr /**< expression */
3863 )
3864 {
3865 assert(expr != NULL);
3866
3867 return expr->difftag;
3868 }
3869
3870 /** returns the activity that is currently stored for an expression
3871 *
3872 * @see SCIPevalExprActivity
3873 */
3874 SCIP_INTERVAL SCIPexprGetActivity(
3875 SCIP_EXPR* expr /**< expression */
3876 )
3877 {
3878 assert(expr != NULL);
3879
3880 return expr->activity;
3881 }
3882
3883 /** returns the tag associated with the activity of the expression
3884 *
3885 * It can depend on the owner of the expression how to interpret this tag.
3886 * SCIPevalExprActivity() compares with `stat->domchgcount`.
3887 *
3888 * @see SCIPevalExprActivity
3889 */
3890 SCIP_Longint SCIPexprGetActivityTag(
3891 SCIP_EXPR* expr /**< expression */
3892 )
3893 {
3894 assert(expr != NULL);
3895
3896 return expr->activitytag;
3897 }
3898
3899 /** set the activity with tag for an expression */
3900 void SCIPexprSetActivity(
3901 SCIP_EXPR* expr, /**< expression */
3902 SCIP_INTERVAL activity, /**< new activity */
3903 SCIP_Longint activitytag /**< tag associated with activity */
3904 )
3905 {
3906 assert(expr != NULL);
3907
3908 expr->activity = activity;
3909 expr->activitytag = activitytag;
3910 }
3911
3912 /** returns the curvature of an expression
3913 *
3914 * @note Call SCIPcomputeExprCurvature() before calling this function.
3915 */
3916 SCIP_EXPRCURV SCIPexprGetCurvature(
3917 SCIP_EXPR* expr /**< expression */
3918 )
3919 {
3920 assert(expr != NULL);
3921
3922 return expr->curvature;
3923 }
3924
3925 /** sets the curvature of an expression */
3926 void SCIPexprSetCurvature(
3927 SCIP_EXPR* expr, /**< expression */
3928 SCIP_EXPRCURV curvature /**< curvature of the expression */
3929 )
3930 {
3931 assert(expr != NULL);
3932
3933 expr->curvature = curvature;
3934 }
3935
3936 /** returns whether an expression is integral */
3937 SCIP_Bool SCIPexprIsIntegral(
3938 SCIP_EXPR* expr /**< expression */
3939 )
3940 {
3941 assert(expr != NULL);
3942
3943 return expr->isintegral;
3944 }
3945
3946 /** sets the integrality flag of an expression */
3947 void SCIPexprSetIntegrality(
3948 SCIP_EXPR* expr, /**< expression */
3949 SCIP_Bool isintegral /**< integrality of the expression */
3950 )
3951 {
3952 assert(expr != NULL);
3953
3954 expr->isintegral = isintegral;
3955 }
3956
3957 /** gives the coefficients and expressions that define a quadratic expression
3958 *
3959 * It can return the constant part, the number, arguments, and coefficients of the purely linear part
3960 * and the number of quadratic terms and bilinear terms.
3961 * Note that for arguments that appear in the quadratic part, a linear coefficient is
3962 * stored with the quadratic term.
3963 * Use SCIPexprGetQuadraticQuadTerm() and SCIPexprGetQuadraticBilinTerm()
3964 * to access the data for a quadratic or bilinear term.
3965 *
3966 * It can also return the eigenvalues and the eigenvectors of the matrix \f$Q\f$ when the quadratic is written
3967 * as \f$x^T Q x + b^T x + c^T y + d\f$, where \f$c^T y\f$ defines the purely linear part.
3968 * Note, however, that to have access to them one needs to call SCIPcomputeExprQuadraticCurvature()
3969 * with `storeeigeninfo=TRUE`. If the eigen information was not stored or it failed to be computed,
3970 * `eigenvalues` and `eigenvectors` will be set to NULL.
3971 *
3972 * This function returns pointers to internal data in linexprs and lincoefs.
3973 * The user must not change this data.
3974 */
3975 void SCIPexprGetQuadraticData(
3976 SCIP_EXPR* expr, /**< quadratic expression */
3977 SCIP_Real* constant, /**< buffer to store constant term, or NULL */
3978 int* nlinexprs, /**< buffer to store number of expressions that appear linearly, or NULL */
3979 SCIP_EXPR*** linexprs, /**< buffer to store pointer to array of expressions that appear linearly,
3980 or NULL */
3981 SCIP_Real** lincoefs, /**< buffer to store pointer to array of coefficients of expressions that
3982 appear linearly, or NULL */
3983 int* nquadexprs, /**< buffer to store number of expressions in quadratic terms, or NULL */
3984 int* nbilinexprs, /**< buffer to store number of bilinear expressions terms, or NULL */
3985 SCIP_Real** eigenvalues, /**< buffer to store pointer to array of eigenvalues of Q, or NULL */
3986 SCIP_Real** eigenvectors /**< buffer to store pointer to array of eigenvectors of Q, or NULL */
3987 )
3988 {
3989 SCIP_QUADEXPR* quaddata;
3990
3991 assert(expr != NULL);
3992
3993 quaddata = expr->quaddata;
3994 assert(quaddata != NULL);
3995
3996 if( constant != NULL )
3997 *constant = quaddata->constant;
3998 if( nlinexprs != NULL )
3999 *nlinexprs = quaddata->nlinexprs;
4000 if( linexprs != NULL )
4001 *linexprs = quaddata->linexprs;
4002 if( lincoefs != NULL )
4003 *lincoefs = quaddata->lincoefs;
4004 if( nquadexprs != NULL )
4005 *nquadexprs = quaddata->nquadexprs;
4006 if( nbilinexprs != NULL )
4007 *nbilinexprs = quaddata->nbilinexprterms;
4008 if( eigenvalues != NULL )
4009 *eigenvalues = quaddata->eigenvalues;
4010 if( eigenvectors != NULL )
4011 *eigenvectors = quaddata->eigenvectors;
4012 }
4013
4014 /** gives the data of a quadratic expression term
4015 *
4016 * For a term \f$a \cdot \text{expr}^2 + b \cdot \text{expr} + \sum_i (c_i \cdot \text{expr} \cdot \text{otherexpr}_i)\f$, returns
4017 * `expr`, \f$a\f$, \f$b\f$, the number of summands, and indices of bilinear terms in the quadratic expressions `bilinexprterms`.
4018 *
4019 * This function returns pointers to internal data in adjbilin.
4020 * The user must not change this data.
4021 */
4022 void SCIPexprGetQuadraticQuadTerm(
4023 SCIP_EXPR* quadexpr, /**< quadratic expression */
4024 int termidx, /**< index of quadratic term */
4025 SCIP_EXPR** expr, /**< buffer to store pointer to argument expression (the 'x') of this term,
4026 or NULL */
4027 SCIP_Real* lincoef, /**< buffer to store linear coefficient of variable, or NULL */
4028 SCIP_Real* sqrcoef, /**< buffer to store square coefficient of variable, or NULL */
4029 int* nadjbilin, /**< buffer to store number of bilinear terms this variable is involved in,
4030 or NULL */
4031 int** adjbilin, /**< buffer to store pointer to indices of associated bilinear terms, or NULL */
4032 SCIP_EXPR** sqrexpr /**< buffer to store pointer to square expression (the 'x^2') of this term
4033 or NULL if no square expression, or NULL */
4034 )
4035 {
4036 SCIP_QUADEXPR_QUADTERM* quadexprterm;
4037
4038 assert(quadexpr != NULL);
4039 assert(quadexpr->quaddata != NULL);
4040 assert(quadexpr->quaddata->quadexprterms != NULL);
4041 assert(termidx >= 0);
4042 assert(termidx < quadexpr->quaddata->nquadexprs);
4043
4044 quadexprterm = &quadexpr->quaddata->quadexprterms[termidx];
4045
4046 if( expr != NULL )
4047 *expr = quadexprterm->expr;
4048 if( lincoef != NULL )
4049 *lincoef = quadexprterm->lincoef;
4050 if( sqrcoef != NULL )
4051 *sqrcoef = quadexprterm->sqrcoef;
4052 if( nadjbilin != NULL )
4053 *nadjbilin = quadexprterm->nadjbilin;
4054 if( adjbilin != NULL )
4055 *adjbilin = quadexprterm->adjbilin;
4056 if( sqrexpr != NULL )
4057 *sqrexpr = quadexprterm->sqrexpr;
4058 }
4059
4060 /** gives the data of a bilinear expression term
4061 *
4062 * For a term a*expr1*expr2, returns expr1, expr2, a, and
4063 * the position of the quadratic expression term that uses expr2 in the quadratic expressions `quadexprterms`.
4064 */
4065 void SCIPexprGetQuadraticBilinTerm(
4066 SCIP_EXPR* expr, /**< quadratic expression */
4067 int termidx, /**< index of bilinear term */
4068 SCIP_EXPR** expr1, /**< buffer to store first factor, or NULL */
4069 SCIP_EXPR** expr2, /**< buffer to store second factor, or NULL */
4070 SCIP_Real* coef, /**< buffer to coefficient, or NULL */
4071 int* pos2, /**< buffer to position of expr2 in quadexprterms array of quadratic
4072 expression, or NULL */
4073 SCIP_EXPR** prodexpr /**< buffer to store pointer to expression that is product if first
4074 and second factor, or NULL */
4075 )
4076 {
4077 SCIP_QUADEXPR_BILINTERM* bilinexprterm;
4078
4079 assert(expr != NULL);
4080 assert(expr->quaddata != NULL);
4081 assert(expr->quaddata->bilinexprterms != NULL);
4082 assert(termidx >= 0);
4083 assert(termidx < expr->quaddata->nbilinexprterms);
4084
4085 bilinexprterm = &expr->quaddata->bilinexprterms[termidx];
4086
4087 if( expr1 != NULL )
4088 *expr1 = bilinexprterm->expr1;
4089 if( expr2 != NULL )
4090 *expr2 = bilinexprterm->expr2;
4091 if( coef != NULL )
4092 *coef = bilinexprterm->coef;
4093 if( pos2 != NULL )
4094 *pos2 = bilinexprterm->pos2;
4095 if( prodexpr != NULL )
4096 *prodexpr = bilinexprterm->prodexpr;
4097 }
4098
4099 /** returns whether all expressions that are used in a quadratic expression are variable expressions
4100 *
4101 * @return TRUE iff all `linexprs` and `quadexprterms[.].expr` are variable expressions
4102 */
4103 SCIP_Bool SCIPexprAreQuadraticExprsVariables(
4104 SCIP_EXPR* expr /**< quadratic expression */
4105 )
4106 {
4107 assert(expr != NULL);
4108 assert(expr->quaddata != NULL);
4109
4110 return expr->quaddata->allexprsarevars;
4111 }
4112
4113 /**@} */
4114