diff --git a/include/mp/flat/constr_2_expr.h b/include/mp/flat/constr_2_expr.h index aa627ce94..8a534f6d9 100644 --- a/include/mp/flat/constr_2_expr.h +++ b/include/mp/flat/constr_2_expr.h @@ -231,9 +231,9 @@ class Constraints2Expr { MPCD( GetVarProperFlags() )); MPD( GetModelAPI() ).PassInitExprGetter( [this](int i_res_var, void* pexpr) { - assert( !MPCD( IsProperVar(i_res_var) ) ); // is an expression - MPD( GetInitExpression(i_res_var) ).StoreSolverExpression( - MPD(GetModelAPI()), i_res_var, pexpr); + auto cloc = MPD( GetInitExpression(i_res_var) ); + cloc.StoreSolverExpression( + MPD(GetModelAPI()), pexpr); }); } @@ -298,23 +298,23 @@ class Constraints2Expr { int exprResVar = -1; if (exprTerm.GetArguments().is_variable()) { exprResVar = exprTerm.GetArguments().get_representing_variable(); - assert( !MPCD( IsProperVar(exprResVar) ) ); // is an expr + // assert( !MPCD( IsProperVar(exprResVar) ) ); // is an expr } else { assert( !exprTerm.GetArguments().empty() ); // has more terms, or coef != 1.0 - exprTerm.SetContext( // Context is compulsory + exprTerm.AddContext( // Context is compulsory rng.lb() > MPCD( PracticallyMinusInf() ) // Should not need to propagate ? (rng.ub() < MPCD( PracticallyInf() ) ? Context::CTX_MIX : Context::CTX_POS) : Context::CTX_NEG); exprResVar = MPD( AssignResultVar2Args(std::move(exprTerm)) ); - if (!MPCD(VarHasMarking(exprResVar))) // mark as expr if new - MPD( MarkAsExpression(exprResVar) ); - /// Exists and marked a variable - else if (MPCD( IsProperVar(exprResVar) )) { // Not an expression after all - lt.add_term(1.0, exprResVar); - exprResVar = -1; // no expression - lt.sort_terms(); - } + } + if (!MPCD(VarHasMarking(exprResVar))) // mark as expr if new + MPD( MarkAsExpression(exprResVar) ); + /// Exists and marked a variable + else if (MPCD( IsProperVar(exprResVar) )) { // Not an expression after all + lt.add_term(1.0, exprResVar); + exprResVar = -1; // no expression + lt.sort_terms(); } // else, stays as -1 NLConstraint nlc{lt, exprResVar, rng, false}; // no sorting MPD( AddConstraint( std::move(nlc) ) ); @@ -330,7 +330,7 @@ class Constraints2Expr { int exprResVar = -1; if (lt_in_expr.is_variable() && qobj.GetQPTerms().empty()) { exprResVar = lt_in_expr.get_representing_variable(); - assert( !MPCD( IsProperVar(exprResVar) ) ); // is an expr + // assert( !MPCD( IsProperVar(exprResVar) ) ); // is an expr } else { // We need a new expression // Set up AutoLink auto obj_src = // source value node for this obj @@ -343,18 +343,18 @@ class Constraints2Expr { exprResVar = MPD( AssignResultVar2Args( QuadraticFunctionalConstraint { {{lt_in_expr, std::move(qobj.GetQPTerms())}, 1.0} } ) ); - MPD( SetInitExprContext(exprResVar, // Context is compulsory + MPD( AddInitExprContext(exprResVar, // Context is compulsory obj::MAX==qobj.obj_sense_true() // no need to propagate ? Context::CTX_POS : Context::CTX_NEG) ); - if ( !MPCD(VarHasMarking(exprResVar) )) // mark as expr if new - MPD( MarkAsExpression(exprResVar) ); - if ( !MPCD( GetModelAPI() ).AcceptsNLObj() ) // But as var if NLObj not accepted - MPD( MarkAsResultVar(exprResVar) ); - if ( MPCD( IsProperVar(exprResVar) ) ) { // Not an expression after all - lt_varsonly.add_term(1.0, exprResVar); - exprResVar = -1; // no expression - lt_varsonly.sort_terms(); - } + } + if ( !MPCD(VarHasMarking(exprResVar) )) // mark as expr if new + MPD( MarkAsExpression(exprResVar) ); + if ( !MPCD( GetModelAPI() ).AcceptsNLObj() ) // But as var if NLObj not accepted + MPD( MarkAsResultVar(exprResVar) ); + if ( MPCD( IsProperVar(exprResVar) ) ) { // Not an expression after all + lt_varsonly.add_term(1.0, exprResVar); + exprResVar = -1; // no expression + lt_varsonly.sort_terms(); } qobj.GetLinTerms() = lt_varsonly; if (exprResVar>=0) @@ -391,7 +391,7 @@ class Constraints2Expr { /// Split linterms into pure-var and expressions /// @return the expressions part - LinTerms SplitLinTerms(const LinTerms& ltin, LinTerms lt_out_vars) { + LinTerms SplitLinTerms(const LinTerms& ltin, LinTerms& lt_out_vars) { LinTerms result; int nvars=0; for (int v: ltin.vars()) @@ -481,7 +481,8 @@ class Constraints2Expr { auto alscope = MPD( MakeAutoLinker( con, i ) ); // link from \a con auto resvar = con.GetResultVar(); if (MPCD( is_fixed(resvar) ) // "root" context - && MPCD( fixed_value(resvar) )) { // static logical constraint + && MPCD( fixed_value(resvar) ) + && con.GetContext().HasPositive()) { // static logical constraint MPD( AddConstraint(NLLogical(resvar)) ); } else { // A (half-)reified function constraint diff --git a/include/mp/flat/constr_base.h b/include/mp/flat/constr_base.h index 941017c82..833b6ae24 100644 --- a/include/mp/flat/constr_base.h +++ b/include/mp/flat/constr_base.h @@ -37,7 +37,7 @@ class BasicConstraint { /// Set context, if meaningful void SetContext(Context ) const { MP_RAISE("Setting context for static constraint"); } /// Add (merge) context, if meaningful - void AddContext(Context ) const { MP_RAISE("Setting context for static constraint"); } + void AddContext(Context ) const { MP_RAISE("Adding context for static constraint"); } /// Has result var (is functional)? bool HasResultVar() const { return false; } /// For functional constraints, result variable index diff --git a/include/mp/flat/constr_keeper.h b/include/mp/flat/constr_keeper.h index cf063bce9..f4e2329ca 100644 --- a/include/mp/flat/constr_keeper.h +++ b/include/mp/flat/constr_keeper.h @@ -79,6 +79,10 @@ class ConstraintKeeper final Context GetContext(int i) const override { assert(check_index(i)); return cons_[i].GetCon().GetContext(); } + /// Add context of contraint \a i + void AddContext(int i, Context ctx) override + { assert(check_index(i)); cons_[i].GetCon().AddContext(ctx); } + /// Set context of contraint \a i void SetContext(int i, Context ctx) override { assert(check_index(i)); cons_[i].GetCon().SetContext(ctx); } diff --git a/include/mp/flat/converter.h b/include/mp/flat/converter.h index 26b6238ee..a25f551f6 100644 --- a/include/mp/flat/converter.h +++ b/include/mp/flat/converter.h @@ -897,7 +897,13 @@ class FlatConverter : ie.GetCK()->SetContext(ie.GetIndex(), ctx); } - /// Get the init expression pointer. + /// Add func expr context + void AddInitExprContext(int var, Context ctx) { + auto ie = GetInitExpression(var); + ie.GetCK()->AddContext(ie.GetIndex(), ctx); + } + + /// Get the init expression pointer. /// @return nullptr if no init expr or not this type template const ConType* GetInitExpressionOfType(int var) { diff --git a/include/mp/flat/converter_model.h b/include/mp/flat/converter_model.h index eac266b43..861c61876 100644 --- a/include/mp/flat/converter_model.h +++ b/include/mp/flat/converter_model.h @@ -399,11 +399,11 @@ class FlatModel // Convert names to c-str if needed for (const std::string& s : var_names_storage_) var_names_.push_back(s.c_str()); - backend.AddVariables({ var_lb_, var_ub_, var_type_, var_names_ }); + backend.AddVariables({ var_lb_subm_, var_ub_subm_, var_type_, var_names_ }); } else { - backend.AddVariables({ var_lb_, var_ub_, var_type_ }); + backend.AddVariables({ var_lb_subm_, var_ub_subm_, var_type_ }); } - ExportVars(0, var_lb_, var_ub_, var_type_, + ExportVars(0, var_lb_subm_, var_ub_subm_, var_type_, "Updated model information."); } diff --git a/include/mp/flat/item_keeper.h b/include/mp/flat/item_keeper.h index 03e3fb940..b3399a8e2 100644 --- a/include/mp/flat/item_keeper.h +++ b/include/mp/flat/item_keeper.h @@ -35,6 +35,9 @@ class BasicConstraintKeeper { /// Get context of contraint \a i virtual Context GetContext(int i) const = 0; + /// Add context of contraint \a i + virtual void AddContext(int i, Context ctx) = 0; + /// Set context of contraint \a i virtual void SetContext(int i, Context ctx) = 0; @@ -255,8 +258,8 @@ struct ConstraintLocationHelper { /// Store native expression for result index \a i. void StoreSolverExpression( - BasicFlatModelAPI& be, int i, void* pexpr) const - { GetCK()->StoreSolverExpression(be, i, pexpr); } + BasicFlatModelAPI& be, void* pexpr) const + { GetCK()->StoreSolverExpression(be, GetIndex(), pexpr); } /// Get Keeper ConstraintKeeper* GetCK() const { assert(HasId()); return pck_; } diff --git a/include/mp/flat/nl_expr/model_api_base.h b/include/mp/flat/nl_expr/model_api_base.h index b32b61b89..e89509636 100644 --- a/include/mp/flat/nl_expr/model_api_base.h +++ b/include/mp/flat/nl_expr/model_api_base.h @@ -100,7 +100,7 @@ class BasicExprModelAPI ? nlc.ExprIndex() : -1; if (i_expr<0) return MPD( GetZeroExpression() ); - return GetInitExpression(i_expr); + return GetPureInitExpression(i_expr); } /// Get NLConstraint's lower bound @@ -123,7 +123,7 @@ class BasicExprModelAPI template ExprType GetExpression(const NLReification& nll) { assert( nll.GetResultVar()>=0 ); - return GetInitExpression(nll.GetResultVar()); + return GetPureInitExpression(nll.GetResultVar()); } /// Get the variable of an \a NLReification. @@ -185,9 +185,9 @@ class BasicExprModelAPI ////////////////////// INTERNAL //////////////////////// - /// Get InitExpression(). - /// Solver expression for the given implicit variable, - /// or for the given independent variable. +private: + /// Get Expr for a variable, if proper/explicit, + /// or for the InitExpression(). Expr GetInitExpression(int i_expr) { assert(i_expr < is_expr_stored_.size()); assert(i_expr < expr_stored_.size()); @@ -202,11 +202,37 @@ class BasicExprModelAPI return expr_stored_[i_expr]; // ............... } + /// Get Expr for the InitExpression(). + /// Solver expression for the given variable's init expression. + /// This is called for NLConstraint + /// and for NLReification. For them, during result explicification, + /// the result is marked as variable, + /// but we still need the expression. + /// We have to trust that the init expression is accepted. + /// @note GetInitExpression(\a i_expr) might still return + /// the Expr for the result variable \a i_expr. + Expr GetPureInitExpression(int i_expr) { + assert(i_expr < is_expr_stored_.size()); + assert(i_expr < expr_stored_.size()); + assert(i_expr < is_init_expr_retrieved_.size()); + assert(!is_init_expr_retrieved_[i_expr]); // not twice explicified + if (IsVarProper(i_expr)) { + is_init_expr_retrieved_[i_expr] = true; // is being explicified + Expr result; + get_init_expr_(i_expr, &result); + return result; + } + return GetInitExpression(i_expr); // standard case + } + + +public: /// Pass vector of var proper flags void PassVarProperFlags(std::vector isvp) { is_var_proper_ = std::move(isvp); is_expr_stored_.resize(is_var_proper_.size()); // allocate expr_stored_.resize(is_var_proper_.size()); + is_init_expr_retrieved_.resize(is_var_proper_.size()); } /// Is var proper? @@ -225,8 +251,9 @@ class BasicExprModelAPI private: std::vector is_var_proper_; - std::vector is_expr_stored_; + std::vector is_expr_stored_; // actual Expr's of the result var or the init expressions std::vector expr_stored_; + std::vector is_init_expr_retrieved_; InitExprGetterType get_init_expr_; }; diff --git a/solvers/scipmp/scipmpcommon.cc b/solvers/scipmp/scipmpcommon.cc index 0b2bb82e0..7a6a3ab19 100644 --- a/solvers/scipmp/scipmpcommon.cc +++ b/solvers/scipmp/scipmpcommon.cc @@ -11,24 +11,26 @@ SCIP_DECL_PROBDELORIG(probdataDelOrigNl) for( i = 0; i < (*probdata)->nlinconss; ++i ) { - SCIP_CALL( SCIPreleaseCons(scip, &(*probdata)->linconss[i]) ); + SCIP_CCALL( SCIPreleaseCons(scip, &(*probdata)->linconss[i]) ); } for (auto& pnlc: (*probdata)->nlconss) - SCIP_CALL( SCIPreleaseCons(scip, &pnlc) ); + SCIP_CCALL( SCIPreleaseCons(scip, &pnlc) ); for( i = 0; i < (*probdata)->nvars; ++i ) { - SCIP_CCALL( SCIPreleaseVar(scip, &(*probdata)->vars[i]) ); if ((*probdata)->var_exprs[i]) - SCIP_CALL( SCIPreleaseExpr(scip, &(*probdata)->var_exprs[i]) ); + SCIP_CCALL( SCIPreleaseExpr(scip, &(*probdata)->var_exprs[i]) ); + SCIP_CCALL( SCIPreleaseVar(scip, &(*probdata)->vars[i]) ); } if ((*probdata)->dummyexpr) - SCIP_CALL( SCIPreleaseExpr(scip, &(*probdata)->dummyexpr) ); + SCIP_CCALL( SCIPreleaseExpr(scip, &(*probdata)->dummyexpr) ); SCIPfreeBlockMemoryArray(scip, &(*probdata)->vars, (*probdata)->nvars); + SCIPsetMessagehdlrQuiet(scip, true); // Spurious warnings and failure in Debug build + SCIPfreeMemory(scip, probdata); return SCIP_OKAY; diff --git a/solvers/scipmp/scipmpmodelapi.h b/solvers/scipmp/scipmpmodelapi.h index 98b2feaca..f49b74e9f 100644 --- a/solvers/scipmp/scipmpmodelapi.h +++ b/solvers/scipmp/scipmpmodelapi.h @@ -66,6 +66,10 @@ class ScipModelAPI : /// NLLogical, NLEquivalence, NLImpl, NLRimpl, and NLObjective. ACCEPT_EXPRESSION_INTERFACE(AcceptedButNotRecommended); + /// Whether accepts NLObjective. + /// No, as of SCIP 9.1. + static int AcceptsNLObj() { return 0; } + /// Once expressions are supported, need the following /// helper methods. ///