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