From f59593e35ce9ae39ea435b3c88950053b2864159 Mon Sep 17 00:00:00 2001 From: Kevin Kofler Date: Sat, 31 May 2025 02:08:46 +0200 Subject: [PATCH 1/6] Add scip::ObjExprhdlr class to objscip The intent is to be able to use SWIG director classes to implement expression handlers through bindings, in particular, to add support for expression handlers to JSCIP. That needs the C++ class to build upon. src/objscip/objexprhdlr.h, src/objscip/objexprhdlr.cpp: New files. C++ wrapper for expression handlers. The files contain the scip::ObjExprhdlr class and the functions SCIPincludeObjExprhdlr, SCIPfindObjExprhdlr, and SCIPgetObjExprhdlr. src/CMakeLists.txt (objscipsources): Add objscip/objexprhdlr.cpp. (objscipheaders): Add objscip/objexprhdlr.h. --- src/CMakeLists.txt | 2 + src/objscip/objexprhdlr.cpp | 541 ++++++++++++++++++++++++++++++++++++ src/objscip/objexprhdlr.h | 517 ++++++++++++++++++++++++++++++++++ 3 files changed, 1060 insertions(+) create mode 100644 src/objscip/objexprhdlr.cpp create mode 100644 src/objscip/objexprhdlr.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a572b1a059..782dc22516 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -427,6 +427,7 @@ set(objscipsources objscip/objdialog.cpp objscip/objdisp.cpp objscip/objeventhdlr.cpp + objscip/objexprhdlr.cpp objscip/objheur.cpp objscip/objiisfinder.cpp objscip/objmessagehdlr.cpp @@ -494,6 +495,7 @@ set(objscipheaders objscip/objdialog.h objscip/objdisp.h objscip/objeventhdlr.h + objscip/objexprhdlr.h objscip/objheur.h objscip/objiisfinder.h objscip/objmessagehdlr.h diff --git a/src/objscip/objexprhdlr.cpp b/src/objscip/objexprhdlr.cpp new file mode 100644 index 0000000000..b73cafc61e --- /dev/null +++ b/src/objscip/objexprhdlr.cpp @@ -0,0 +1,541 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +/* */ +/* This file is part of the program and library */ +/* SCIP --- Solving Constraint Integer Programs */ +/* */ +/* Copyright (c) 2002-2025 Zuse Institute Berlin (ZIB) */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ +/* See the License for the specific language governing permissions and */ +/* limitations under the License. */ +/* */ +/* You should have received a copy of the Apache-2.0 license */ +/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */ +/* */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/**@file objexprhdlr.cpp + * @brief C++ wrapper for expression handlers + * @author Kevin Kofler + */ + +/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/ + +#include + +#include "objexprhdlr.h" + + + + +/* + * Data structures + */ + +/** expression handler data */ +struct SCIP_ExprhdlrData +{ + scip::ObjExprhdlr* objexprhdlr; /**< expression handler object */ + SCIP_Bool deleteobject; /**< should the expression handler object be deleted when exprhdlr is freed? */ +}; + + + + +/* + * Callback methods of expression handler + */ + +extern "C" +{ + +/** copy method for expression handler plugins (called when SCIP copies plugins) */ +static +SCIP_DECL_EXPRCOPYHDLR(exprCopyhdlrObj) +{ /*lint --e{715}*/ + SCIP_EXPRHDLRDATA* exprhdlrdata; + + assert(scip != NULL); + + exprhdlrdata = SCIPexprhdlrGetData(sourceexprhdlr); + assert(exprhdlrdata != NULL); + assert(exprhdlrdata->objexprhdlr != NULL); + assert(exprhdlrdata->objexprhdlr->scip_ != scip); + + if( exprhdlrdata->objexprhdlr->iscloneable() ) + { + SCIP_Bool valid = FALSE; + scip::ObjExprhdlr* newobjexprhdlr; + newobjexprhdlr = dynamic_cast (exprhdlrdata->objexprhdlr->clone(scip, &valid)); + + if( !valid ) + return SCIP_NOMEMORY; + + /* call include method of expression handler object */ + SCIP_EXPRHDLR* targetexprhdlr; + SCIP_CALL( SCIPincludeObjExprhdlr(scip, &targetexprhdlr, newobjexprhdlr, TRUE) ); + } + + return SCIP_OKAY; +} + +/** destructor of expression handler to free user data (called when SCIP is exiting) */ +static +SCIP_DECL_EXPRFREEHDLR(exprFreehdlrObj) +{ /*lint --e{715}*/ + assert(exprhdlrdata != NULL); + assert(*exprhdlrdata != NULL); + assert((*exprhdlrdata)->objexprhdlr != NULL); + assert((*exprhdlrdata)->objexprhdlr->scip_ == scip); + + /* call virtual method of exprhdlr object */ + SCIP_CALL( (*exprhdlrdata)->objexprhdlr->scip_freehdlr(scip, exprhdlr, + exprhdlrdata) ); + + /* free exprhdlr object */ + if( (*exprhdlrdata)->deleteobject ) + delete (*exprhdlrdata)->objexprhdlr; + + /* free exprhdlr data */ + delete (*exprhdlrdata); + *exprhdlrdata = NULL; + + return SCIP_OKAY; +} + + +/** point evaluation callback of expression handler */ +static +SCIP_DECL_EXPREVAL(exprEvalObj) +{ /*lint --e{715}*/ + SCIP_EXPRHDLR* exprhdlr = SCIPexprGetHdlr(expr); + SCIP_EXPRHDLRDATA* exprhdlrdata = SCIPexprhdlrGetData(exprhdlr); + assert(exprhdlrdata != NULL); + assert(exprhdlrdata->objexprhdlr != NULL); + + /* call virtual method of exprhdlr object */ + SCIP_CALL( exprhdlrdata->objexprhdlr->scip_eval(scip, expr, val, sol) ); + + return SCIP_OKAY; +} + + +/** data copy callback of expression handler */ +static +SCIP_DECL_EXPRCOPYDATA(exprCopydataObj) +{ /*lint --e{715}*/ + SCIP_EXPRHDLRDATA* exprhdlrdata = SCIPexprhdlrGetData(targetexprhdlr); + assert(exprhdlrdata != NULL); + assert(exprhdlrdata->objexprhdlr != NULL); + + /* call virtual method of exprhdlr object */ + SCIP_CALL( exprhdlrdata->objexprhdlr->scip_copydata(targetscip, targetexprhdlr, targetexprdata, sourcescip, sourceexpr) ); + + return SCIP_OKAY; +} + + +/** data free callback of expression handler */ +static +SCIP_DECL_EXPRFREEDATA(exprFreedataObj) +{ /*lint --e{715}*/ + SCIP_EXPRHDLR* exprhdlr = SCIPexprGetHdlr(expr); + SCIP_EXPRHDLRDATA* exprhdlrdata = SCIPexprhdlrGetData(exprhdlr); + assert(exprhdlrdata != NULL); + assert(exprhdlrdata->objexprhdlr != NULL); + + /* call virtual method of exprhdlr object */ + SCIP_CALL( exprhdlrdata->objexprhdlr->scip_freedata(scip, expr) ); + + return SCIP_OKAY; +} + + +/** simplify callback of expression handler */ +static +SCIP_DECL_EXPRSIMPLIFY(exprSimplifyObj) +{ /*lint --e{715}*/ + SCIP_EXPRHDLR* exprhdlr = SCIPexprGetHdlr(expr); + SCIP_EXPRHDLRDATA* exprhdlrdata = SCIPexprhdlrGetData(exprhdlr); + assert(exprhdlrdata != NULL); + assert(exprhdlrdata->objexprhdlr != NULL); + + /* call virtual method of exprhdlr object */ + SCIP_CALL( exprhdlrdata->objexprhdlr->scip_simplify(scip, expr, + simplifiedexpr, + ownercreate, + ownercreatedata) ); + + return SCIP_OKAY; +} + + +/** compare callback of expression handler */ +static +SCIP_DECL_EXPRCOMPARE(exprCompareObj) +{ /*lint --e{715}*/ + SCIP_EXPRHDLR* exprhdlr = SCIPexprGetHdlr(expr1); + SCIP_EXPRHDLRDATA* exprhdlrdata = SCIPexprhdlrGetData(exprhdlr); + assert(exprhdlrdata != NULL); + assert(exprhdlrdata->objexprhdlr != NULL); + + /* call virtual method of exprhdlr object */ + return exprhdlrdata->objexprhdlr->scip_compare(scip, expr1, expr2); +} + + +/** print callback of expression handler */ +static +SCIP_DECL_EXPRPRINT(exprPrintObj) +{ /*lint --e{715}*/ + SCIP_EXPRHDLR* exprhdlr = SCIPexprGetHdlr(expr); + SCIP_EXPRHDLRDATA* exprhdlrdata = SCIPexprhdlrGetData(exprhdlr); + assert(exprhdlrdata != NULL); + assert(exprhdlrdata->objexprhdlr != NULL); + + /* call virtual method of exprhdlr object */ + SCIP_CALL( exprhdlrdata->objexprhdlr->scip_print(scip, expr, stage, + currentchild, + parentprecedence, file) ); + + return SCIP_OKAY; +} + + +/** parse callback of expression handler */ +static +SCIP_DECL_EXPRPARSE(exprParseObj) +{ /*lint --e{715}*/ + SCIP_EXPRHDLRDATA* exprhdlrdata = SCIPexprhdlrGetData(exprhdlr); + assert(exprhdlrdata != NULL); + assert(exprhdlrdata->objexprhdlr != NULL); + + /* call virtual method of exprhdlr object */ + SCIP_CALL( exprhdlrdata->objexprhdlr->scip_parse(scip, exprhdlr, string, + endstring, expr, success, + ownercreate, + ownercreatedata) ); + + return SCIP_OKAY; +} + + +/** backward derivative evaluation callback of expression handler */ +static +SCIP_DECL_EXPRBWDIFF(exprBwdiffObj) +{ /*lint --e{715}*/ + SCIP_EXPRHDLR* exprhdlr = SCIPexprGetHdlr(expr); + SCIP_EXPRHDLRDATA* exprhdlrdata = SCIPexprhdlrGetData(exprhdlr); + assert(exprhdlrdata != NULL); + assert(exprhdlrdata->objexprhdlr != NULL); + + /* call virtual method of exprhdlr object */ + SCIP_CALL( exprhdlrdata->objexprhdlr->scip_bwdiff(scip, expr, childidx, val) ); + + return SCIP_OKAY; +} + + +/** forward derivative evaluation callback of expression handler */ +static +SCIP_DECL_EXPRFWDIFF(exprFwdiffObj) +{ /*lint --e{715}*/ + SCIP_EXPRHDLR* exprhdlr = SCIPexprGetHdlr(expr); + SCIP_EXPRHDLRDATA* exprhdlrdata = SCIPexprhdlrGetData(exprhdlr); + assert(exprhdlrdata != NULL); + assert(exprhdlrdata->objexprhdlr != NULL); + + /* call virtual method of exprhdlr object */ + SCIP_CALL( exprhdlrdata->objexprhdlr->scip_fwdiff(scip, expr, dot, direction) ); + + return SCIP_OKAY; +} + + +/** backward over forward derivative evaluation callback of expression handler */ +static +SCIP_DECL_EXPRBWFWDIFF(exprBwfwdiffObj) +{ /*lint --e{715}*/ + SCIP_EXPRHDLR* exprhdlr = SCIPexprGetHdlr(expr); + SCIP_EXPRHDLRDATA* exprhdlrdata = SCIPexprhdlrGetData(exprhdlr); + assert(exprhdlrdata != NULL); + assert(exprhdlrdata->objexprhdlr != NULL); + + /* call virtual method of exprhdlr object */ + SCIP_CALL( exprhdlrdata->objexprhdlr->scip_bwfwdiff(scip, expr, childidx, + bardot, direction) ); + + return SCIP_OKAY; +} + + +/** interval evaluation callback of expression handler */ +static +SCIP_DECL_EXPRINTEVAL(exprIntevalObj) +{ /*lint --e{715}*/ + SCIP_EXPRHDLR* exprhdlr = SCIPexprGetHdlr(expr); + SCIP_EXPRHDLRDATA* exprhdlrdata = SCIPexprhdlrGetData(exprhdlr); + assert(exprhdlrdata != NULL); + assert(exprhdlrdata->objexprhdlr != NULL); + + /* call virtual method of exprhdlr object */ + SCIP_CALL( exprhdlrdata->objexprhdlr->scip_inteval(scip, expr, interval, + intevalvar, + intevalvardata) ); + + return SCIP_OKAY; +} + + +/** estimation callback of expression handler */ +static +SCIP_DECL_EXPRESTIMATE(exprEstimateObj) +{ /*lint --e{715}*/ + SCIP_EXPRHDLR* exprhdlr = SCIPexprGetHdlr(expr); + SCIP_EXPRHDLRDATA* exprhdlrdata = SCIPexprhdlrGetData(exprhdlr); + assert(exprhdlrdata != NULL); + assert(exprhdlrdata->objexprhdlr != NULL); + + /* call virtual method of exprhdlr object */ + SCIP_CALL( exprhdlrdata->objexprhdlr->scip_estimate(scip, expr, localbounds, + globalbounds, refpoint, + overestimate, + targetvalue, coefs, + constant, islocal, + success, branchcand) ); + + return SCIP_OKAY; +} + + +/** initial estimators callback of expression handler */ +static +SCIP_DECL_EXPRINITESTIMATES(exprInitestimatesObj) +{ /*lint --e{715}*/ + SCIP_EXPRHDLR* exprhdlr = SCIPexprGetHdlr(expr); + SCIP_EXPRHDLRDATA* exprhdlrdata = SCIPexprhdlrGetData(exprhdlr); + assert(exprhdlrdata != NULL); + assert(exprhdlrdata->objexprhdlr != NULL); + + /* call virtual method of exprhdlr object */ + SCIP_CALL( exprhdlrdata->objexprhdlr->scip_initestimates(scip, expr, bounds, + overestimate, coefs, + constant, + nreturned) ); + + return SCIP_OKAY; +} + + +/** reverse propagation callback of expression handler */ +static +SCIP_DECL_EXPRREVERSEPROP(exprReversepropObj) +{ /*lint --e{715}*/ + SCIP_EXPRHDLR* exprhdlr = SCIPexprGetHdlr(expr); + SCIP_EXPRHDLRDATA* exprhdlrdata = SCIPexprhdlrGetData(exprhdlr); + assert(exprhdlrdata != NULL); + assert(exprhdlrdata->objexprhdlr != NULL); + + /* call virtual method of exprhdlr object */ + SCIP_CALL( exprhdlrdata->objexprhdlr->scip_reverseprop(scip, expr, bounds, + childrenbounds, + infeasible) ); + + return SCIP_OKAY; +} + + +/** hash callback of expression handler */ +static +SCIP_DECL_EXPRHASH(exprHashObj) +{ /*lint --e{715}*/ + SCIP_EXPRHDLR* exprhdlr = SCIPexprGetHdlr(expr); + SCIP_EXPRHDLRDATA* exprhdlrdata = SCIPexprhdlrGetData(exprhdlr); + assert(exprhdlrdata != NULL); + assert(exprhdlrdata->objexprhdlr != NULL); + + /* call virtual method of exprhdlr object */ + SCIP_CALL( exprhdlrdata->objexprhdlr->scip_hash(scip, expr, hashkey, + childrenhashes) ); + + return SCIP_OKAY; +} + + +/** curvature callback of expression handler */ +static +SCIP_DECL_EXPRCURVATURE(exprCurvatureObj) +{ /*lint --e{715}*/ + SCIP_EXPRHDLR* exprhdlr = SCIPexprGetHdlr(expr); + SCIP_EXPRHDLRDATA* exprhdlrdata = SCIPexprhdlrGetData(exprhdlr); + assert(exprhdlrdata != NULL); + assert(exprhdlrdata->objexprhdlr != NULL); + + /* call virtual method of exprhdlr object */ + SCIP_CALL( exprhdlrdata->objexprhdlr->scip_curvature(scip, expr, + exprcurvature, success, + childcurv) ); + + return SCIP_OKAY; +} + + +/** monotonicity callback of expression handler */ +static +SCIP_DECL_EXPRMONOTONICITY(exprMonotonicityObj) +{ /*lint --e{715}*/ + SCIP_EXPRHDLR* exprhdlr = SCIPexprGetHdlr(expr); + SCIP_EXPRHDLRDATA* exprhdlrdata = SCIPexprhdlrGetData(exprhdlr); + assert(exprhdlrdata != NULL); + assert(exprhdlrdata->objexprhdlr != NULL); + + /* call virtual method of exprhdlr object */ + SCIP_CALL( exprhdlrdata->objexprhdlr->scip_monotonicity(scip, expr, childidx, + result) ); + + return SCIP_OKAY; +} + + +/** integrality callback of expression handler */ +static +SCIP_DECL_EXPRINTEGRALITY(exprIntegralityObj) +{ /*lint --e{715}*/ + SCIP_EXPRHDLR* exprhdlr = SCIPexprGetHdlr(expr); + SCIP_EXPRHDLRDATA* exprhdlrdata = SCIPexprhdlrGetData(exprhdlr); + assert(exprhdlrdata != NULL); + assert(exprhdlrdata->objexprhdlr != NULL); + + /* call virtual method of exprhdlr object */ + SCIP_CALL( exprhdlrdata->objexprhdlr->scip_integrality(scip, expr, + integrality) ); + + return SCIP_OKAY; +} + + +/** symmetry information callback of expression handler */ +static +SCIP_DECL_EXPRGETSYMDATA(exprGetsymdataObj) +{ /*lint --e{715}*/ + SCIP_EXPRHDLR* exprhdlr = SCIPexprGetHdlr(expr); + SCIP_EXPRHDLRDATA* exprhdlrdata = SCIPexprhdlrGetData(exprhdlr); + assert(exprhdlrdata != NULL); + assert(exprhdlrdata->objexprhdlr != NULL); + + /* call virtual method of exprhdlr object */ + SCIP_CALL( exprhdlrdata->objexprhdlr->scip_getsymdata(scip, expr, symdata) ); + + return SCIP_OKAY; +} +} + + +/* + * expression handler specific interface methods + */ + +/** creates the expression handler for the given expression handler object and includes it in SCIP */ +SCIP_RETCODE SCIPincludeObjExprhdlr( + SCIP* scip, /**< SCIP data structure */ + SCIP_EXPRHDLR** exprhdlr, /**< pointer to store the expression handler */ scip::ObjExprhdlr* objexprhdlr, /**< expression handler object */ + SCIP_Bool deleteobject /**< should the expression handler object be deleted when exprhdlr is freed? */ + ) +{ + SCIP_EXPRHDLRDATA* exprhdlrdata; + + assert(scip != NULL); + assert(objexprhdlr != NULL); + assert(objexprhdlr->scip_ == scip); + + /* create obj expression handler data */ + exprhdlrdata = new SCIP_EXPRHDLRDATA; + exprhdlrdata->objexprhdlr = objexprhdlr; + exprhdlrdata->deleteobject = deleteobject; + + /* include expression handler */ + SCIP_CALL( SCIPincludeExprhdlr(scip, exprhdlr, objexprhdlr->scip_name_, + objexprhdlr->scip_desc_, + objexprhdlr->scip_precedence_, exprEvalObj, + exprhdlrdata) ); /*lint !e429*/ + SCIPexprhdlrSetCopyFreeHdlr(*exprhdlr, exprCopyhdlrObj, exprFreehdlrObj); + if( objexprhdlr->scip_has_copydata_ || objexprhdlr->scip_has_freedata_ ) + SCIPexprhdlrSetCopyFreeData(*exprhdlr, + objexprhdlr->scip_has_copydata_ ? exprCopydataObj : NULL, objexprhdlr->scip_has_freedata_ ? exprFreedataObj : NULL); + if( objexprhdlr->scip_has_simplify_ ) + SCIPexprhdlrSetSimplify(*exprhdlr, exprSimplifyObj); + if( objexprhdlr->scip_has_compare_ ) + SCIPexprhdlrSetCompare(*exprhdlr, exprCompareObj); + if( objexprhdlr->scip_has_print_ ) + SCIPexprhdlrSetPrint(*exprhdlr, exprPrintObj); + if( objexprhdlr->scip_has_parse_ ) + SCIPexprhdlrSetParse(*exprhdlr, exprParseObj); + if( objexprhdlr->scip_has_bwdiff_ || objexprhdlr->scip_has_fwdiff_ + || objexprhdlr->scip_has_bwfwdiff_ ) + SCIPexprhdlrSetDiff(*exprhdlr, + objexprhdlr->scip_has_bwdiff_ ? exprBwdiffObj : NULL, + objexprhdlr->scip_has_fwdiff_ ? exprFwdiffObj : NULL, + objexprhdlr->scip_has_bwfwdiff_ ? exprBwfwdiffObj : NULL); + if( objexprhdlr->scip_has_inteval_ ) + SCIPexprhdlrSetIntEval(*exprhdlr, exprIntevalObj); + if( objexprhdlr->scip_has_estimate_ || objexprhdlr->scip_has_initestimates_ ) + SCIPexprhdlrSetEstimate(*exprhdlr, + objexprhdlr->scip_has_initestimates_ ? exprInitestimatesObj : NULL, + objexprhdlr->scip_has_estimate_ ? exprEstimateObj : NULL); + if( objexprhdlr->scip_has_reverseprop_ ) + SCIPexprhdlrSetReverseProp(*exprhdlr, exprReversepropObj); + if( objexprhdlr->scip_has_hash_ ) + SCIPexprhdlrSetHash(*exprhdlr, exprHashObj); + if( objexprhdlr->scip_has_curvature_ ) + SCIPexprhdlrSetCurvature(*exprhdlr, exprCurvatureObj); + if( objexprhdlr->scip_has_monotonicity_ ) + SCIPexprhdlrSetMonotonicity(*exprhdlr, exprMonotonicityObj); + if( objexprhdlr->scip_has_integrality_ ) + SCIPexprhdlrSetIntegrality(*exprhdlr, exprIntegralityObj); + if( objexprhdlr->scip_has_getsymdata_ ) + SCIPexprhdlrSetGetSymdata(*exprhdlr, exprGetsymdataObj); + + return SCIP_OKAY; /*lint !e429*/ +} + +/** returns the exprhdlr object of the given name, or 0 if not existing */ +scip::ObjExprhdlr* SCIPfindObjExprhdlr( + SCIP* scip, /**< SCIP data structure */ + const char* name /**< name of expression handler */ + ) +{ + SCIP_EXPRHDLR* exprhdlr; + SCIP_EXPRHDLRDATA* exprhdlrdata; + + exprhdlr = SCIPfindExprhdlr(scip, name); + if( exprhdlr == NULL ) + return 0; + + exprhdlrdata = SCIPexprhdlrGetData(exprhdlr); + assert(exprhdlrdata != NULL); + + return exprhdlrdata->objexprhdlr; +} + +/** returns the exprhdlr object for the given expression handler */ +scip::ObjExprhdlr* SCIPgetObjExprhdlr( + SCIP* scip, /**< SCIP data structure */ + SCIP_EXPRHDLR* exprhdlr /**< expression handler */ + ) +{ + SCIP_EXPRHDLRDATA* exprhdlrdata; + + assert(scip != NULL); + exprhdlrdata = SCIPexprhdlrGetData(exprhdlr); + assert(exprhdlrdata != NULL); + + return exprhdlrdata->objexprhdlr; +} diff --git a/src/objscip/objexprhdlr.h b/src/objscip/objexprhdlr.h new file mode 100644 index 0000000000..0c9ec72b1f --- /dev/null +++ b/src/objscip/objexprhdlr.h @@ -0,0 +1,517 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +/* */ +/* This file is part of the program and library */ +/* SCIP --- Solving Constraint Integer Programs */ +/* */ +/* Copyright (c) 2002-2025 Zuse Institute Berlin (ZIB) */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ +/* See the License for the specific language governing permissions and */ +/* limitations under the License. */ +/* */ +/* You should have received a copy of the Apache-2.0 license */ +/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */ +/* */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/**@file objexprhdlr.h + * @brief C++ wrapper for expression handlers + * @author Kevin Kofler + */ + +/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/ + +#ifndef __SCIP_OBJEXPRHDLR_H__ +#define __SCIP_OBJEXPRHDLR_H__ + + +#include +#include +#include + +#include "scip/scip.h" +#include "objscip/objprobcloneable.h" + +namespace scip +{ + +/** @brief C++ wrapper for expression handlers + * + * This class defines the interface for expression handlers implemented in C++. Note that there is a pure virtual + * function (which has to be implemented): the function scip_eval(). + * + * - \ref EXPRHDLR "Instructions for implementing an expression handler" + * - \ref EXPRHDLRS "List of available expression handlers" + * - \ref type_expr.h "Corresponding C interface" + */ +class ObjExprhdlr : public ObjProbCloneable +{ +public: + /*lint --e{1540}*/ + + /** SCIP data structure */ + SCIP* scip_; + + /** name of the expression handler */ + char* scip_name_; + + /** description of the expression handler */ + char* scip_desc_; + + /** precedence of expression operation relative to other expression (used for printing) */ + const unsigned int scip_precedence_; + + /** whether scip_copydata is implemented */ + const SCIP_Bool scip_has_copydata_; + + /** whether scip_freedata is implemented */ + const SCIP_Bool scip_has_freedata_; + + /** whether scip_simplify is implemented */ + const SCIP_Bool scip_has_simplify_; + + /** whether scip_compare is implemented */ + const SCIP_Bool scip_has_compare_; + + /** whether scip_print is implemented */ + const SCIP_Bool scip_has_print_; + + /** whether scip_parse is implemented */ + const SCIP_Bool scip_has_parse_; + + /** whether scip_bwdiff is implemented */ + const SCIP_Bool scip_has_bwdiff_; + + /** whether scip_fwdiff is implemented */ + const SCIP_Bool scip_has_fwdiff_; + + /** whether scip_bwfwdiff is implemented */ + const SCIP_Bool scip_has_bwfwdiff_; + + /** whether scip_inteval is implemented */ + const SCIP_Bool scip_has_inteval_; + + /** whether scip_estimate is implemented */ + const SCIP_Bool scip_has_estimate_; + + /** whether scip_initestimates is implemented */ + const SCIP_Bool scip_has_initestimates_; + + /** whether scip_reverseprop is implemented */ + const SCIP_Bool scip_has_reverseprop_; + + /** whether scip_hash is implemented */ + const SCIP_Bool scip_has_hash_; + + /** whether scip_curvature is implemented */ + const SCIP_Bool scip_has_curvature_; + + /** whether scip_monotonicity is implemented */ + const SCIP_Bool scip_has_monotonicity_; + + /** whether scip_integrality is implemented */ + const SCIP_Bool scip_has_integrality_; + + /** whether scip_getsymdata is implemented */ + const SCIP_Bool scip_has_getsymdata_; + + /** default constructor */ + ObjExprhdlr( + SCIP* scip, /**< SCIP data structure */ + const char* name, /**< name of expression handler */ + const char* desc, /**< description of expression handler */ + unsigned int precedence, /**< precedence of expression operation */ + SCIP_Bool has_copydata, /**< whether scip_copydata is implemented */ + SCIP_Bool has_freedata, /**< whether scip_freedata is implemented */ + SCIP_Bool has_simplify, /**< whether scip_simplify is implemented */ + SCIP_Bool has_compare, /**< whether scip_compare is implemented */ + SCIP_Bool has_print, /**< whether scip_print is implemented */ + SCIP_Bool has_parse, /**< whether scip_parse is implemented */ + SCIP_Bool has_bwdiff, /**< whether scip_bwdiff is implemented */ + SCIP_Bool has_fwdiff, /**< whether scip_fwdiff is implemented */ + SCIP_Bool has_bwfwdiff, /**< whether scip_bwfwdiff is implemented */ + SCIP_Bool has_inteval, /**< whether scip_inteval is implemented */ + SCIP_Bool has_estimate, /**< whether scip_estimate is implemented */ + SCIP_Bool has_initestimates, /**< whether scip_initestimates is implemented */ + SCIP_Bool has_reverseprop, /**< whether scip_reverseprop is implemented */ + SCIP_Bool has_hash, /**< whether scip_hash is implemented */ + SCIP_Bool has_curvature, /**< whether scip_curvature is implemented */ + SCIP_Bool has_monotonicity, /**< whether scip_monotonicity is implemented */ + SCIP_Bool has_integrality, /**< whether scip_integrality is implemented */ + SCIP_Bool has_getsymdata /**< whether scip_getsymdata is implemented */ + ) + : scip_(scip), + scip_name_(0), + scip_desc_(0), + scip_precedence_(precedence), + scip_has_copydata_(has_copydata), + scip_has_freedata_(has_freedata), + scip_has_simplify_(has_simplify), + scip_has_compare_(has_compare), + scip_has_print_(has_print), + scip_has_parse_(has_parse), + scip_has_bwdiff_(has_bwdiff), + scip_has_fwdiff_(has_fwdiff), + scip_has_bwfwdiff_(has_bwfwdiff), + scip_has_inteval_(has_inteval), + scip_has_estimate_(has_estimate), + scip_has_initestimates_(has_initestimates), + scip_has_reverseprop_(has_reverseprop), + scip_has_hash_(has_hash), + scip_has_curvature_(has_curvature), + scip_has_monotonicity_(has_monotonicity), + scip_has_integrality_(has_integrality), + scip_has_getsymdata_(has_getsymdata) + { + /* the macro SCIPduplicateMemoryArray does not need the first argument: */ + SCIP_CALL_ABORT( SCIPduplicateMemoryArray(scip_, &scip_name_, name, std::strlen(name)+1) ); + SCIP_CALL_ABORT( SCIPduplicateMemoryArray(scip_, &scip_desc_, desc, std::strlen(desc)+1) ); + } + + /** copy constructor */ + ObjExprhdlr(const ObjExprhdlr& o) + : ObjExprhdlr(o.scip_, o.scip_name_, o.scip_desc_, o.scip_precedence_, + o.scip_has_copydata_, o.scip_has_freedata_, + o.scip_has_simplify_, o.scip_has_compare_, + o.scip_has_print_, o.scip_has_parse_, o.scip_has_bwdiff_, + o.scip_has_fwdiff_, o.scip_has_bwfwdiff_, + o.scip_has_inteval_, o.scip_has_estimate_, + o.scip_has_initestimates_, o.scip_has_reverseprop_, + o.scip_has_hash_, o.scip_has_curvature_, + o.scip_has_monotonicity_, o.scip_has_integrality_, + o.scip_has_getsymdata_) + { + } + + /** move constructor */ + ObjExprhdlr(ObjExprhdlr&& o) + : scip_(o.scip_), + scip_name_(0), + scip_desc_(0), + scip_precedence_(o.scip_precedence_), + scip_has_copydata_(o.scip_has_copydata_), + scip_has_freedata_(o.scip_has_freedata_), + scip_has_simplify_(o.scip_has_simplify_), + scip_has_compare_(o.scip_has_compare_), + scip_has_print_(o.scip_has_print_), + scip_has_parse_(o.scip_has_parse_), + scip_has_bwdiff_(o.scip_has_bwdiff_), + scip_has_fwdiff_(o.scip_has_fwdiff_), + scip_has_bwfwdiff_(o.scip_has_bwfwdiff_), + scip_has_inteval_(o.scip_has_inteval_), + scip_has_estimate_(o.scip_has_estimate_), + scip_has_initestimates_(o.scip_has_initestimates_), + scip_has_reverseprop_(o.scip_has_reverseprop_), + scip_has_hash_(o.scip_has_hash_), + scip_has_curvature_(o.scip_has_curvature_), + scip_has_monotonicity_(o.scip_has_monotonicity_), + scip_has_integrality_(o.scip_has_integrality_), + scip_has_getsymdata_(o.scip_has_getsymdata_) + { + std::swap(scip_name_, o.scip_name_); + std::swap(scip_desc_, o.scip_desc_); + } + + /** destructor */ + virtual ~ObjExprhdlr() + { + /* the macro SCIPfreeMemoryArray does not need the first argument: */ + /*lint --e{64}*/ + SCIPfreeMemoryArray(scip_, &scip_name_); + SCIPfreeMemoryArray(scip_, &scip_desc_); + } + + /** assignment of polymorphic classes causes slicing and is therefore disabled. */ + ObjExprhdlr& operator=(const ObjExprhdlr& o) = delete; + + /** assignment of polymorphic classes causes slicing and is therefore disabled. */ + ObjExprhdlr& operator=(ObjExprhdlr&& o) = delete; + + /** destructor of expression handler to free user data (called when SCIP is exiting) + * + * @see SCIP_DECL_EXPRFREEHDLR(x) in @ref type_expr.h + */ + virtual SCIP_DECL_EXPRFREEHDLR(scip_freehdlr) + { /*lint --e{715}*/ + return SCIP_OKAY; + } + + /** point evaluation callback of expression handler + * + * @see SCIP_DECL_EXPREVAL(x) in @ref type_expr.h + */ + virtual SCIP_DECL_EXPREVAL(scip_eval) = 0; + + /** data copy callback of expression handler + * + * This method MUST be overridden if scip_has_copydata_ is TRUE. + * + * @see SCIP_DECL_EXPRCOPYDATA(x) in @ref type_expr.h + */ + virtual SCIP_DECL_EXPRCOPYDATA(scip_copydata) + { /*lint --e{715}*/ + /* This method MUST be overridden if scip_has_copydata_ is TRUE. */ + return SCIP_NOTIMPLEMENTED; + } + + /** data free callback of expression handler + * + * This method MUST be overridden if scip_has_freedata_ is TRUE. + * + * @see SCIP_DECL_EXPRFREEDATA(x) in @ref type_expr.h + */ + virtual SCIP_DECL_EXPRFREEDATA(scip_freedata) + { /*lint --e{715}*/ + /* This method MUST be overridden if scip_has_freedata_ is TRUE. */ + return SCIP_NOTIMPLEMENTED; + } + + /** simplify callback of expression handler + * + * This method MUST be overridden if scip_has_simplify_ is TRUE. + * + * @see SCIP_DECL_EXPRSIMPLIFY(x) in @ref type_expr.h + */ + virtual SCIP_DECL_EXPRSIMPLIFY(scip_simplify) + { /*lint --e{715}*/ + /* This method MUST be overridden if scip_has_simplify_ is TRUE. */ + return SCIP_NOTIMPLEMENTED; + } + + /** compare callback of expression handler + * + * This method MUST be overridden if scip_has_compare_ is TRUE. + * + * @see SCIP_DECL_EXPRCOMPARE(x) in @ref type_expr.h + */ + virtual SCIP_DECL_EXPRCOMPARE(scip_compare) + { /*lint --e{715}*/ + /* This method MUST be overridden if scip_has_compare_ is TRUE. */ + return 0; + } + + /** print callback of expression handler + * + * This method MUST be overridden if scip_has_print_ is TRUE. + * + * @see SCIP_DECL_EXPRPRINT(x) in @ref type_expr.h + */ + virtual SCIP_DECL_EXPRPRINT(scip_print) + { /*lint --e{715}*/ + /* This method MUST be overridden if scip_has_print_ is TRUE. */ + return SCIP_NOTIMPLEMENTED; + } + + /** parse callback of expression handler + * + * This method MUST be overridden if scip_has_parse_ is TRUE. + * + * @see SCIP_DECL_EXPRPARSE(x) in @ref type_expr.h + */ + virtual SCIP_DECL_EXPRPARSE(scip_parse) + { /*lint --e{715}*/ + /* This method MUST be overridden if scip_has_parse_ is TRUE. */ + return SCIP_NOTIMPLEMENTED; + } + + /** backward derivative evaluation callback of expression handler + * + * This method MUST be overridden if scip_has_bwdiff_ is TRUE. + * + * @see SCIP_DECL_EXPRBWDIFF(x) in @ref type_expr.h + */ + virtual SCIP_DECL_EXPRBWDIFF(scip_bwdiff) + { /*lint --e{715}*/ + /* This method MUST be overridden if scip_has_bwdiff_ is TRUE. */ + return SCIP_NOTIMPLEMENTED; + } + + /** forward derivative evaluation callback of expression handler + * + * This method MUST be overridden if scip_has_fwdiff_ is TRUE. + * + * @see SCIP_DECL_EXPRFWDIFF(x) in @ref type_expr.h + */ + virtual SCIP_DECL_EXPRFWDIFF(scip_fwdiff) + { /*lint --e{715}*/ + /* This method MUST be overridden if scip_has_fwdiff_ is TRUE. */ + return SCIP_NOTIMPLEMENTED; + } + + /** backward over forward derivative evaluation callback of expression handler + * + * This method MUST be overridden if scip_has_bwfwdiff_ is TRUE. + * + * @see SCIP_DECL_EXPRBWFWDIFF(x) in @ref type_expr.h + */ + virtual SCIP_DECL_EXPRBWFWDIFF(scip_bwfwdiff) + { /*lint --e{715}*/ + /* This method MUST be overridden if scip_has_bwfwdiff_ is TRUE. */ + return SCIP_NOTIMPLEMENTED; + } + + /** interval evaluation callback of expression handler + * + * This method MUST be overridden if scip_has_inteval_ is TRUE. + * + * @see SCIP_DECL_EXPRINTEVAL(x) in @ref type_expr.h + */ + virtual SCIP_DECL_EXPRINTEVAL(scip_inteval) + { /*lint --e{715}*/ + /* This method MUST be overridden if scip_has_inteval_ is TRUE. */ + return SCIP_NOTIMPLEMENTED; + } + + /** estimation callback of expression handler + * + * This method MUST be overridden if scip_has_estimate_ is TRUE. + * + * @see SCIP_DECL_EXPRESTIMATE(x) in @ref type_expr.h + */ + virtual SCIP_DECL_EXPRESTIMATE(scip_estimate) + { /*lint --e{715}*/ + /* This method MUST be overridden if scip_has_estimate_ is TRUE. */ + return SCIP_NOTIMPLEMENTED; + } + + /** initial estimators callback of expression handler + * + * This method MUST be overridden if scip_has_initestimates_ is TRUE. + * + * @see SCIP_DECL_EXPRINITESTIMATES(x) in @ref type_expr.h + */ + virtual SCIP_DECL_EXPRINITESTIMATES(scip_initestimates) + { /*lint --e{715}*/ + /* This method MUST be overridden if scip_has_initestimates_ is TRUE. */ + return SCIP_NOTIMPLEMENTED; + } + + /** reverse propagation callback of expression handler + * + * This method MUST be overridden if scip_has_reverseprop_ is TRUE. + * + * @see SCIP_DECL_EXPRREVERSEPROP(x) in @ref type_expr.h + */ + virtual SCIP_DECL_EXPRREVERSEPROP(scip_reverseprop) + { /*lint --e{715}*/ + /* This method MUST be overridden if scip_has_reverseprop_ is TRUE. */ + return SCIP_NOTIMPLEMENTED; + } + + /** hash callback of expression handler + * + * This method MUST be overridden if scip_has_hash_ is TRUE. + * + * @see SCIP_DECL_EXPRHASH(x) in @ref type_expr.h + */ + virtual SCIP_DECL_EXPRHASH(scip_hash) + { /*lint --e{715}*/ + /* This method MUST be overridden if scip_has_hash_ is TRUE. */ + return SCIP_NOTIMPLEMENTED; + } + + /** curvature callback of expression handler + * + * This method MUST be overridden if scip_has_curvature_ is TRUE. + * + * @see SCIP_DECL_EXPRCURVATURE(x) in @ref type_expr.h + */ + virtual SCIP_DECL_EXPRCURVATURE(scip_curvature) + { /*lint --e{715}*/ + /* This method MUST be overridden if scip_has_curvature_ is TRUE. */ + return SCIP_NOTIMPLEMENTED; + } + + /** monotonicity callback of expression handler + * + * This method MUST be overridden if scip_has_monotonicity_ is TRUE. + * + * @see SCIP_DECL_EXPRMONOTONICITY(x) in @ref type_expr.h + */ + virtual SCIP_DECL_EXPRMONOTONICITY(scip_monotonicity) + { /*lint --e{715}*/ + /* This method MUST be overridden if scip_has_monotonicity_ is TRUE. */ + return SCIP_NOTIMPLEMENTED; + } + + /** integrality callback of expression handler + * + * This method MUST be overridden if scip_has_integrality_ is TRUE. + * + * @see SCIP_DECL_EXPRINTEGRALITY(x) in @ref type_expr.h + */ + virtual SCIP_DECL_EXPRINTEGRALITY(scip_integrality) + { /*lint --e{715}*/ + /* This method MUST be overridden if scip_has_integrality_ is TRUE. */ + return SCIP_NOTIMPLEMENTED; + } + + /** symmetry information callback of expression handler + * + * This method MUST be overridden if scip_has_getsymdata_ is TRUE. + * + * @see SCIP_DECL_EXPRGETSYMDATA(x) in @ref type_expr.h + */ + virtual SCIP_DECL_EXPRGETSYMDATA(scip_getsymdata) + { /*lint --e{715}*/ + /* This method MUST be overridden if scip_has_getsymdata_ is TRUE. */ + return SCIP_NOTIMPLEMENTED; + } +}; + +} /* namespace scip */ + + + +/** creates the expression handler for the given expression handler object and includes it in SCIP + * + * The method should be called in one of the following ways: + * + * 1. The user is resposible of deleting the object: + * SCIP_CALL( SCIPcreate(&scip) ); + * ... + * SCIP_EXPRHDLR* cexprhdlr; + * MyExprhdlr* myexprhdlr = new MyExprhdlr(...); + * SCIP_CALL( SCIPincludeObjExprhdlr(scip, &cexprhdlr, &myexprhdlr, FALSE) ); + * ... + * SCIP_CALL( SCIPfree(&scip) ); + * delete myexprhdlr; // delete exprhdlr AFTER SCIPfree() ! + * + * 2. The object pointer is passed to SCIP and deleted by SCIP in the SCIPfree() call: + * SCIP_CALL( SCIPcreate(&scip) ); + * ... + * SCIP_EXPRHDLR* cexprhdlr; + * SCIP_CALL( SCIPincludeObjExprhdlr(scip, &cexprhdlr, new MyExprhdlr(...), TRUE) ); + * ... + * SCIP_CALL( SCIPfree(&scip) ); // destructor of MyExprhdlr is called here + */ +SCIP_EXPORT +SCIP_RETCODE SCIPincludeObjExprhdlr( + SCIP* scip, /**< SCIP data structure */ + SCIP_EXPRHDLR** exprhdlr, /**< pointer to store the expression handler */ scip::ObjExprhdlr* objconshdlr, /**< expression handler object */ + SCIP_Bool deleteobject /**< should the expression handler object be deleted when exprhdlr is freed? */ + ); + +/** returns the exprhdlr object of the given name, or 0 if not existing */ +SCIP_EXPORT +scip::ObjExprhdlr* SCIPfindObjExprhdlr( + SCIP* scip, /**< SCIP data structure */ + const char* name /**< name of expression handler */ + ); + +/** returns the exprhdlr object for the given expression handler */ +SCIP_EXPORT +scip::ObjExprhdlr* SCIPgetObjExprhdlr( + SCIP* scip, /**< SCIP data structure */ + SCIP_EXPRHDLR* exprhdlr /**< expression handler */ + ); + +#endif From 4d5aedbde6483e3c8f955a8a8caf31f1df857184 Mon Sep 17 00:00:00 2001 From: Stefan Vigerske Date: Wed, 4 Jun 2025 19:40:46 +0200 Subject: [PATCH 2/6] add objexprhdlr to Makefile --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index cfc437f1dd..db9340b91a 100644 --- a/Makefile +++ b/Makefile @@ -1130,6 +1130,7 @@ OBJSCIPLIBOBJ = objscip/objbenders.o \ objscip/objconshdlr.o \ objscip/objdialog.o \ objscip/objdisp.o \ + objscip/objexprhdlr.o \ objscip/objeventhdlr.o \ objscip/objheur.o \ objscip/objmessagehdlr.o \ From 550322fd5ee5d24a9fd905a39908385f7e4c20af Mon Sep 17 00:00:00 2001 From: Stefan Vigerske Date: Wed, 4 Jun 2025 19:41:06 +0200 Subject: [PATCH 3/6] minor updates to objexprhdlr - derive from ObjCloneable: copy doesn't get invalid if exprhdlr cannot be cloned - no need for cassert in objexprhdlr.h - linebreaks closer to SCIP style --- src/objscip/objexprhdlr.cpp | 127 +++++++++++++++--------------------- src/objscip/objexprhdlr.h | 20 +++--- 2 files changed, 61 insertions(+), 86 deletions(-) diff --git a/src/objscip/objexprhdlr.cpp b/src/objscip/objexprhdlr.cpp index b73cafc61e..0b56930ed2 100644 --- a/src/objscip/objexprhdlr.cpp +++ b/src/objscip/objexprhdlr.cpp @@ -72,16 +72,11 @@ SCIP_DECL_EXPRCOPYHDLR(exprCopyhdlrObj) if( exprhdlrdata->objexprhdlr->iscloneable() ) { - SCIP_Bool valid = FALSE; scip::ObjExprhdlr* newobjexprhdlr; - newobjexprhdlr = dynamic_cast (exprhdlrdata->objexprhdlr->clone(scip, &valid)); - - if( !valid ) - return SCIP_NOMEMORY; + newobjexprhdlr = dynamic_cast (exprhdlrdata->objexprhdlr->clone(scip)); /* call include method of expression handler object */ - SCIP_EXPRHDLR* targetexprhdlr; - SCIP_CALL( SCIPincludeObjExprhdlr(scip, &targetexprhdlr, newobjexprhdlr, TRUE) ); + SCIP_CALL( SCIPincludeObjExprhdlr(scip, newobjexprhdlr, TRUE) ); } return SCIP_OKAY; @@ -97,8 +92,7 @@ SCIP_DECL_EXPRFREEHDLR(exprFreehdlrObj) assert((*exprhdlrdata)->objexprhdlr->scip_ == scip); /* call virtual method of exprhdlr object */ - SCIP_CALL( (*exprhdlrdata)->objexprhdlr->scip_freehdlr(scip, exprhdlr, - exprhdlrdata) ); + SCIP_CALL( (*exprhdlrdata)->objexprhdlr->scip_freehdlr(scip, exprhdlr, exprhdlrdata) ); /* free exprhdlr object */ if( (*exprhdlrdata)->deleteobject ) @@ -169,10 +163,7 @@ SCIP_DECL_EXPRSIMPLIFY(exprSimplifyObj) assert(exprhdlrdata->objexprhdlr != NULL); /* call virtual method of exprhdlr object */ - SCIP_CALL( exprhdlrdata->objexprhdlr->scip_simplify(scip, expr, - simplifiedexpr, - ownercreate, - ownercreatedata) ); + SCIP_CALL( exprhdlrdata->objexprhdlr->scip_simplify(scip, expr, simplifiedexpr, ownercreate, ownercreatedata) ); return SCIP_OKAY; } @@ -202,9 +193,7 @@ SCIP_DECL_EXPRPRINT(exprPrintObj) assert(exprhdlrdata->objexprhdlr != NULL); /* call virtual method of exprhdlr object */ - SCIP_CALL( exprhdlrdata->objexprhdlr->scip_print(scip, expr, stage, - currentchild, - parentprecedence, file) ); + SCIP_CALL( exprhdlrdata->objexprhdlr->scip_print(scip, expr, stage, currentchild, parentprecedence, file) ); return SCIP_OKAY; } @@ -219,10 +208,8 @@ SCIP_DECL_EXPRPARSE(exprParseObj) assert(exprhdlrdata->objexprhdlr != NULL); /* call virtual method of exprhdlr object */ - SCIP_CALL( exprhdlrdata->objexprhdlr->scip_parse(scip, exprhdlr, string, - endstring, expr, success, - ownercreate, - ownercreatedata) ); + SCIP_CALL( exprhdlrdata->objexprhdlr->scip_parse(scip, exprhdlr, string, endstring, + expr, success, ownercreate, ownercreatedata) ); return SCIP_OKAY; } @@ -270,8 +257,7 @@ SCIP_DECL_EXPRBWFWDIFF(exprBwfwdiffObj) assert(exprhdlrdata->objexprhdlr != NULL); /* call virtual method of exprhdlr object */ - SCIP_CALL( exprhdlrdata->objexprhdlr->scip_bwfwdiff(scip, expr, childidx, - bardot, direction) ); + SCIP_CALL( exprhdlrdata->objexprhdlr->scip_bwfwdiff(scip, expr, childidx, bardot, direction) ); return SCIP_OKAY; } @@ -287,9 +273,7 @@ SCIP_DECL_EXPRINTEVAL(exprIntevalObj) assert(exprhdlrdata->objexprhdlr != NULL); /* call virtual method of exprhdlr object */ - SCIP_CALL( exprhdlrdata->objexprhdlr->scip_inteval(scip, expr, interval, - intevalvar, - intevalvardata) ); + SCIP_CALL( exprhdlrdata->objexprhdlr->scip_inteval(scip, expr, interval, intevalvar, intevalvardata) ); return SCIP_OKAY; } @@ -305,12 +289,8 @@ SCIP_DECL_EXPRESTIMATE(exprEstimateObj) assert(exprhdlrdata->objexprhdlr != NULL); /* call virtual method of exprhdlr object */ - SCIP_CALL( exprhdlrdata->objexprhdlr->scip_estimate(scip, expr, localbounds, - globalbounds, refpoint, - overestimate, - targetvalue, coefs, - constant, islocal, - success, branchcand) ); + SCIP_CALL( exprhdlrdata->objexprhdlr->scip_estimate(scip, expr, localbounds, globalbounds, + refpoint, overestimate, targetvalue, coefs, constant, islocal, success, branchcand) ); return SCIP_OKAY; } @@ -326,10 +306,8 @@ SCIP_DECL_EXPRINITESTIMATES(exprInitestimatesObj) assert(exprhdlrdata->objexprhdlr != NULL); /* call virtual method of exprhdlr object */ - SCIP_CALL( exprhdlrdata->objexprhdlr->scip_initestimates(scip, expr, bounds, - overestimate, coefs, - constant, - nreturned) ); + SCIP_CALL( exprhdlrdata->objexprhdlr->scip_initestimates(scip, expr, bounds, overestimate, + coefs, constant, nreturned) ); return SCIP_OKAY; } @@ -345,9 +323,7 @@ SCIP_DECL_EXPRREVERSEPROP(exprReversepropObj) assert(exprhdlrdata->objexprhdlr != NULL); /* call virtual method of exprhdlr object */ - SCIP_CALL( exprhdlrdata->objexprhdlr->scip_reverseprop(scip, expr, bounds, - childrenbounds, - infeasible) ); + SCIP_CALL( exprhdlrdata->objexprhdlr->scip_reverseprop(scip, expr, bounds, childrenbounds, infeasible) ); return SCIP_OKAY; } @@ -363,8 +339,7 @@ SCIP_DECL_EXPRHASH(exprHashObj) assert(exprhdlrdata->objexprhdlr != NULL); /* call virtual method of exprhdlr object */ - SCIP_CALL( exprhdlrdata->objexprhdlr->scip_hash(scip, expr, hashkey, - childrenhashes) ); + SCIP_CALL( exprhdlrdata->objexprhdlr->scip_hash(scip, expr, hashkey, childrenhashes) ); return SCIP_OKAY; } @@ -380,9 +355,7 @@ SCIP_DECL_EXPRCURVATURE(exprCurvatureObj) assert(exprhdlrdata->objexprhdlr != NULL); /* call virtual method of exprhdlr object */ - SCIP_CALL( exprhdlrdata->objexprhdlr->scip_curvature(scip, expr, - exprcurvature, success, - childcurv) ); + SCIP_CALL( exprhdlrdata->objexprhdlr->scip_curvature(scip, expr, exprcurvature, success, childcurv) ); return SCIP_OKAY; } @@ -398,8 +371,7 @@ SCIP_DECL_EXPRMONOTONICITY(exprMonotonicityObj) assert(exprhdlrdata->objexprhdlr != NULL); /* call virtual method of exprhdlr object */ - SCIP_CALL( exprhdlrdata->objexprhdlr->scip_monotonicity(scip, expr, childidx, - result) ); + SCIP_CALL( exprhdlrdata->objexprhdlr->scip_monotonicity(scip, expr, childidx, result) ); return SCIP_OKAY; } @@ -415,8 +387,7 @@ SCIP_DECL_EXPRINTEGRALITY(exprIntegralityObj) assert(exprhdlrdata->objexprhdlr != NULL); /* call virtual method of exprhdlr object */ - SCIP_CALL( exprhdlrdata->objexprhdlr->scip_integrality(scip, expr, - integrality) ); + SCIP_CALL( exprhdlrdata->objexprhdlr->scip_integrality(scip, expr, integrality) ); return SCIP_OKAY; } @@ -446,10 +417,12 @@ SCIP_DECL_EXPRGETSYMDATA(exprGetsymdataObj) /** creates the expression handler for the given expression handler object and includes it in SCIP */ SCIP_RETCODE SCIPincludeObjExprhdlr( SCIP* scip, /**< SCIP data structure */ - SCIP_EXPRHDLR** exprhdlr, /**< pointer to store the expression handler */ scip::ObjExprhdlr* objexprhdlr, /**< expression handler object */ - SCIP_Bool deleteobject /**< should the expression handler object be deleted when exprhdlr is freed? */ + scip::ObjExprhdlr* objexprhdlr, /**< expression handler object */ + SCIP_Bool deleteobject, /**< should the expression handler object be deleted when exprhdlr is freed? */ + SCIP_EXPRHDLR** cexprhdlr /**< buffer to store C plugin that corresponds to expression handler object, or 0 if not required */ ) { + SCIP_EXPRHDLR* exprhdlr; SCIP_EXPRHDLRDATA* exprhdlrdata; assert(scip != NULL); @@ -462,46 +435,48 @@ SCIP_RETCODE SCIPincludeObjExprhdlr( exprhdlrdata->deleteobject = deleteobject; /* include expression handler */ - SCIP_CALL( SCIPincludeExprhdlr(scip, exprhdlr, objexprhdlr->scip_name_, - objexprhdlr->scip_desc_, - objexprhdlr->scip_precedence_, exprEvalObj, - exprhdlrdata) ); /*lint !e429*/ - SCIPexprhdlrSetCopyFreeHdlr(*exprhdlr, exprCopyhdlrObj, exprFreehdlrObj); + SCIP_CALL( SCIPincludeExprhdlr(scip, &exprhdlr, objexprhdlr->scip_name_, objexprhdlr->scip_desc_, + objexprhdlr->scip_precedence_, exprEvalObj, exprhdlrdata) ); /*lint !e429*/ + + SCIPexprhdlrSetCopyFreeHdlr(exprhdlr, exprCopyhdlrObj, exprFreehdlrObj); if( objexprhdlr->scip_has_copydata_ || objexprhdlr->scip_has_freedata_ ) - SCIPexprhdlrSetCopyFreeData(*exprhdlr, - objexprhdlr->scip_has_copydata_ ? exprCopydataObj : NULL, objexprhdlr->scip_has_freedata_ ? exprFreedataObj : NULL); + SCIPexprhdlrSetCopyFreeData(exprhdlr, + objexprhdlr->scip_has_copydata_ ? exprCopydataObj : NULL, + objexprhdlr->scip_has_freedata_ ? exprFreedataObj : NULL); if( objexprhdlr->scip_has_simplify_ ) - SCIPexprhdlrSetSimplify(*exprhdlr, exprSimplifyObj); + SCIPexprhdlrSetSimplify(exprhdlr, exprSimplifyObj); if( objexprhdlr->scip_has_compare_ ) - SCIPexprhdlrSetCompare(*exprhdlr, exprCompareObj); + SCIPexprhdlrSetCompare(exprhdlr, exprCompareObj); if( objexprhdlr->scip_has_print_ ) - SCIPexprhdlrSetPrint(*exprhdlr, exprPrintObj); + SCIPexprhdlrSetPrint(exprhdlr, exprPrintObj); if( objexprhdlr->scip_has_parse_ ) - SCIPexprhdlrSetParse(*exprhdlr, exprParseObj); - if( objexprhdlr->scip_has_bwdiff_ || objexprhdlr->scip_has_fwdiff_ - || objexprhdlr->scip_has_bwfwdiff_ ) - SCIPexprhdlrSetDiff(*exprhdlr, - objexprhdlr->scip_has_bwdiff_ ? exprBwdiffObj : NULL, - objexprhdlr->scip_has_fwdiff_ ? exprFwdiffObj : NULL, - objexprhdlr->scip_has_bwfwdiff_ ? exprBwfwdiffObj : NULL); + SCIPexprhdlrSetParse(exprhdlr, exprParseObj); + if( objexprhdlr->scip_has_bwdiff_ || objexprhdlr->scip_has_fwdiff_ || objexprhdlr->scip_has_bwfwdiff_ ) + SCIPexprhdlrSetDiff(exprhdlr, + objexprhdlr->scip_has_bwdiff_ ? exprBwdiffObj : NULL, + objexprhdlr->scip_has_fwdiff_ ? exprFwdiffObj : NULL, + objexprhdlr->scip_has_bwfwdiff_ ? exprBwfwdiffObj : NULL); if( objexprhdlr->scip_has_inteval_ ) - SCIPexprhdlrSetIntEval(*exprhdlr, exprIntevalObj); + SCIPexprhdlrSetIntEval(exprhdlr, exprIntevalObj); if( objexprhdlr->scip_has_estimate_ || objexprhdlr->scip_has_initestimates_ ) - SCIPexprhdlrSetEstimate(*exprhdlr, - objexprhdlr->scip_has_initestimates_ ? exprInitestimatesObj : NULL, - objexprhdlr->scip_has_estimate_ ? exprEstimateObj : NULL); + SCIPexprhdlrSetEstimate(exprhdlr, + objexprhdlr->scip_has_initestimates_ ? exprInitestimatesObj : NULL, + objexprhdlr->scip_has_estimate_ ? exprEstimateObj : NULL); if( objexprhdlr->scip_has_reverseprop_ ) - SCIPexprhdlrSetReverseProp(*exprhdlr, exprReversepropObj); + SCIPexprhdlrSetReverseProp(exprhdlr, exprReversepropObj); if( objexprhdlr->scip_has_hash_ ) - SCIPexprhdlrSetHash(*exprhdlr, exprHashObj); + SCIPexprhdlrSetHash(exprhdlr, exprHashObj); if( objexprhdlr->scip_has_curvature_ ) - SCIPexprhdlrSetCurvature(*exprhdlr, exprCurvatureObj); + SCIPexprhdlrSetCurvature(exprhdlr, exprCurvatureObj); if( objexprhdlr->scip_has_monotonicity_ ) - SCIPexprhdlrSetMonotonicity(*exprhdlr, exprMonotonicityObj); + SCIPexprhdlrSetMonotonicity(exprhdlr, exprMonotonicityObj); if( objexprhdlr->scip_has_integrality_ ) - SCIPexprhdlrSetIntegrality(*exprhdlr, exprIntegralityObj); + SCIPexprhdlrSetIntegrality(exprhdlr, exprIntegralityObj); if( objexprhdlr->scip_has_getsymdata_ ) - SCIPexprhdlrSetGetSymdata(*exprhdlr, exprGetsymdataObj); + SCIPexprhdlrSetGetSymdata(exprhdlr, exprGetsymdataObj); + + if( cexprhdlr != NULL ) + *cexprhdlr = exprhdlr; return SCIP_OKAY; /*lint !e429*/ } diff --git a/src/objscip/objexprhdlr.h b/src/objscip/objexprhdlr.h index 0c9ec72b1f..8614d9d356 100644 --- a/src/objscip/objexprhdlr.h +++ b/src/objscip/objexprhdlr.h @@ -32,13 +32,11 @@ #ifndef __SCIP_OBJEXPRHDLR_H__ #define __SCIP_OBJEXPRHDLR_H__ - -#include #include #include #include "scip/scip.h" -#include "objscip/objprobcloneable.h" +#include "objscip/objcloneable.h" namespace scip { @@ -52,7 +50,7 @@ namespace scip * - \ref EXPRHDLRS "List of available expression handlers" * - \ref type_expr.h "Corresponding C interface" */ -class ObjExprhdlr : public ObjProbCloneable +class ObjExprhdlr : public ObjCloneable { public: /*lint --e{1540}*/ @@ -475,12 +473,12 @@ class ObjExprhdlr : public ObjProbCloneable * * The method should be called in one of the following ways: * - * 1. The user is resposible of deleting the object: + * 1. The user is responsible of deleting the object: * SCIP_CALL( SCIPcreate(&scip) ); * ... * SCIP_EXPRHDLR* cexprhdlr; * MyExprhdlr* myexprhdlr = new MyExprhdlr(...); - * SCIP_CALL( SCIPincludeObjExprhdlr(scip, &cexprhdlr, &myexprhdlr, FALSE) ); + * SCIP_CALL( SCIPincludeObjExprhdlr(scip, &myexprhdlr, FALSE, &cexprhdlr) ); * ... * SCIP_CALL( SCIPfree(&scip) ); * delete myexprhdlr; // delete exprhdlr AFTER SCIPfree() ! @@ -488,16 +486,18 @@ class ObjExprhdlr : public ObjProbCloneable * 2. The object pointer is passed to SCIP and deleted by SCIP in the SCIPfree() call: * SCIP_CALL( SCIPcreate(&scip) ); * ... - * SCIP_EXPRHDLR* cexprhdlr; - * SCIP_CALL( SCIPincludeObjExprhdlr(scip, &cexprhdlr, new MyExprhdlr(...), TRUE) ); + * SCIP_CALL( SCIPincludeObjExprhdlr(scip, new MyExprhdlr(...), TRUE) ); * ... * SCIP_CALL( SCIPfree(&scip) ); // destructor of MyExprhdlr is called here + * + * Further, in case 1, the C plugin counterpart for myexprhdlr is stored in cexprhdlr. */ SCIP_EXPORT SCIP_RETCODE SCIPincludeObjExprhdlr( SCIP* scip, /**< SCIP data structure */ - SCIP_EXPRHDLR** exprhdlr, /**< pointer to store the expression handler */ scip::ObjExprhdlr* objconshdlr, /**< expression handler object */ - SCIP_Bool deleteobject /**< should the expression handler object be deleted when exprhdlr is freed? */ + scip::ObjExprhdlr* objexprhdlr, /**< expression handler object */ + SCIP_Bool deleteobject, /**< should the expression handler object be deleted when exprhdlr is freed? */ + SCIP_EXPRHDLR** cexprhdlr = 0 /**< buffer to store C plugin that corresponds to expression handler object, or 0 if not required */ ); /** returns the exprhdlr object of the given name, or 0 if not existing */ From 7c52ef259a480d2895567ffc59bd581a13fe6513 Mon Sep 17 00:00:00 2001 From: Stefan Vigerske Date: Wed, 4 Jun 2025 19:45:08 +0200 Subject: [PATCH 4/6] add CHANGELOG entry --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index 8ab7a2cb21..58a0b2386b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -162,6 +162,7 @@ Interface changes - added SCIPsortDownIntIntIntReal() - SCIPconshdlrSetNeedsCons() to set whether constraint handler callbacks should also be called if there are no constraints - SCIPpropSetTimingmask() to set timing mask of a propagator +- added C++ interface for expression handlers: src/objscip/objexprhdlr.h ### Changes in preprocessor macros From 87a41b0b76f94045d183909e7ce21c36b496a1e8 Mon Sep 17 00:00:00 2001 From: Stefan Vigerske Date: Wed, 4 Jun 2025 20:24:28 +0200 Subject: [PATCH 5/6] include objexprhdlr.h in objscip.h --- src/objscip/objscip.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/objscip/objscip.h b/src/objscip/objscip.h index 2741e6fa22..20d39a92c9 100644 --- a/src/objscip/objscip.h +++ b/src/objscip/objscip.h @@ -41,6 +41,7 @@ #include "objscip/objdialog.h" #include "objscip/objdisp.h" #include "objscip/objeventhdlr.h" +#include "objscip/objexprhdlr.h" #include "objscip/objheur.h" #include "objscip/objiisfinder.h" #include "objscip/objmessagehdlr.h" From 2ec4f9ed4e932b11fe1d1fc1ded0e1d72d026c4d Mon Sep 17 00:00:00 2001 From: Stefan Vigerske Date: Wed, 4 Jun 2025 20:24:42 +0200 Subject: [PATCH 6/6] mention ObjExprhldr in howto add exprhdlrs - copied text from ObjConshdlr --- doc/xternal.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/doc/xternal.c b/doc/xternal.c index d6fd4f9ebe..b6bde2bb5f 100644 --- a/doc/xternal.c +++ b/doc/xternal.c @@ -4244,10 +4244,16 @@ * * For a complete implementation of an expression handler, take the one for exponential expressions (src/scip/expr_exp.c) as an example. * + * It is very easy to transfer the C explanation to C++; whenever a function should be implemented using the + * SCIP_DECL_EXPRHDLR... notion, reimplement the corresponding virtual member function of the abstract scip::ObjExprhdlr + * base class. + * * @section EXPRHDLR_PROPERTIES Properties of an Expression Handler * * At the top of the new file `expr_myfunc.c`, you can find the expression handler properties. * These are given as compiler defines. + * In the C++ wrapper class, you have to provide the expression handler properties by calling the constructor + * of the abstract base class scip::ObjExprhdlr from within your constructor. * The properties you have to set have the following meaning: * * \par EXPRHDLR_NAME: the name of the expression handler. @@ -4330,6 +4336,8 @@ * an operational algorithm. * They are passed to SCIP when the expression handler is created and included in SCIP via SCIPincludeExprhdlr(), * see @ref EXPRHDLR_INTERFACE. + * In the C++ wrapper class scip::ObjExprhdlr, the fundamental callback methods are virtual abstract member functions. + * You have to implement them in order to be able to construct an object of your expression handler class. * * Expression handlers have one fundamental callback, @ref EXPREVAL, that needs to be implemented. * However, expression handlers with stateful expressions (expressions that have data) need to implement also the