bump gscip code
This commit is contained in:
@@ -785,8 +785,8 @@ absl::StatusOr<GScipResult> GScip::Solve(
|
||||
// handler.
|
||||
using internal::CaptureMessageHandlerPtr;
|
||||
using internal::MessageHandlerPtr;
|
||||
MessageHandlerPtr previous_handler = CaptureMessageHandlerPtr(nullptr);
|
||||
MessageHandlerPtr new_handler = CaptureMessageHandlerPtr(nullptr);
|
||||
MessageHandlerPtr previous_handler;
|
||||
MessageHandlerPtr new_handler;
|
||||
if (message_handler != nullptr) {
|
||||
previous_handler = CaptureMessageHandlerPtr(SCIPgetMessagehdlr(scip_));
|
||||
ASSIGN_OR_RETURN(new_handler,
|
||||
|
||||
@@ -13,8 +13,10 @@
|
||||
|
||||
#include "ortools/gscip/gscip_event_handler.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "ortools/base/logging.h"
|
||||
#include "ortools/gscip/gscip.h"
|
||||
#include "ortools/linear_solver/scip_helper_macros.h"
|
||||
@@ -36,13 +38,12 @@ static SCIP_DECL_EVENTEXEC(EventExec) {
|
||||
CHECK_NE(eventhdlr, nullptr);
|
||||
CHECK_NE(event, nullptr);
|
||||
|
||||
SCIP_EVENTHDLRDATA* event_handler_data = SCIPeventhdlrGetData(eventhdlr);
|
||||
SCIP_EVENTHDLRDATA* const event_handler_data =
|
||||
SCIPeventhdlrGetData(eventhdlr);
|
||||
CHECK_NE(event_handler_data, nullptr);
|
||||
operations_research::GScipEventHandler* handler = event_handler_data->handler;
|
||||
handler->Execute(operations_research::GScipEventHandlerContext(
|
||||
event_handler_data->gscip, SCIPeventGetType(event)));
|
||||
|
||||
return SCIP_OKAY;
|
||||
return event_handler_data->handler->Execute(
|
||||
{event_handler_data->gscip, SCIPeventGetType(event)});
|
||||
}
|
||||
|
||||
static SCIP_DECL_EVENTINIT(EventInit) {
|
||||
@@ -50,15 +51,25 @@ static SCIP_DECL_EVENTINIT(EventInit) {
|
||||
CHECK_NE(scip, nullptr);
|
||||
CHECK_NE(eventhdlr, nullptr);
|
||||
|
||||
SCIP_EVENTHDLRDATA* event_handler_data = SCIPeventhdlrGetData(eventhdlr);
|
||||
SCIP_EVENTHDLRDATA* const event_handler_data =
|
||||
SCIPeventhdlrGetData(eventhdlr);
|
||||
CHECK_NE(event_handler_data, nullptr);
|
||||
operations_research::GScipEventHandler* handler = event_handler_data->handler;
|
||||
for (const SCIP_EVENTTYPE event_type :
|
||||
handler->description().events_to_catch_from_start) {
|
||||
SCIP_CALL(SCIPcatchEvent(scip, event_type, eventhdlr, nullptr, nullptr));
|
||||
}
|
||||
|
||||
return SCIP_OKAY;
|
||||
return event_handler_data->handler->Init(event_handler_data->gscip);
|
||||
}
|
||||
|
||||
static SCIP_DECL_EVENTEXIT(EventExit) {
|
||||
VLOG(3) << "EventExit";
|
||||
CHECK_NE(scip, nullptr);
|
||||
CHECK_NE(eventhdlr, nullptr);
|
||||
|
||||
SCIP_EVENTHDLRDATA* const event_handler_data =
|
||||
SCIPeventhdlrGetData(eventhdlr);
|
||||
CHECK_NE(event_handler_data, nullptr);
|
||||
|
||||
SCIP_CALL(DropAllEvents(*event_handler_data->handler));
|
||||
|
||||
return event_handler_data->handler->Exit(event_handler_data->gscip);
|
||||
}
|
||||
|
||||
static SCIP_DECL_EVENTFREE(EventFree) {
|
||||
@@ -66,30 +77,65 @@ static SCIP_DECL_EVENTFREE(EventFree) {
|
||||
CHECK_NE(scip, nullptr);
|
||||
CHECK_NE(eventhdlr, nullptr);
|
||||
|
||||
SCIP_EVENTHDLRDATA* event_handler_data = SCIPeventhdlrGetData(eventhdlr);
|
||||
SCIP_EVENTHDLRDATA* const event_handler_data =
|
||||
SCIPeventhdlrGetData(eventhdlr);
|
||||
CHECK_NE(event_handler_data, nullptr);
|
||||
|
||||
delete event_handler_data;
|
||||
SCIPeventhdlrSetData(eventhdlr, nullptr);
|
||||
|
||||
return SCIP_OKAY;
|
||||
}
|
||||
|
||||
namespace operations_research {
|
||||
|
||||
void RegisterGScipEventHandler(GScip* scip, GScipEventHandler* handler) {
|
||||
void GScipEventHandler::Register(GScip* const gscip) {
|
||||
CHECK_EQ(gscip_, nullptr) << "Already registered.";
|
||||
CHECK_EQ(event_handler_, nullptr);
|
||||
|
||||
gscip_ = gscip;
|
||||
|
||||
// event_handler_data is freed in EventFree.
|
||||
SCIP_EVENTHDLRDATA* event_handler_data = new SCIP_EVENTHDLRDATA;
|
||||
event_handler_data->gscip = scip;
|
||||
event_handler_data->handler = handler;
|
||||
SCIP_EVENTHDLR* event_handler = nullptr;
|
||||
SCIP_EVENTHDLRDATA* const event_handler_data = new SCIP_EVENTHDLRDATA;
|
||||
event_handler_data->gscip = gscip;
|
||||
event_handler_data->handler = this;
|
||||
|
||||
CHECK_OK(SCIP_TO_STATUS(SCIPincludeEventhdlrBasic(
|
||||
scip->scip(), &event_handler, handler->description().name.c_str(),
|
||||
handler->description().description.c_str(), EventExec,
|
||||
event_handler_data)));
|
||||
CHECK_NE(event_handler, nullptr);
|
||||
gscip->scip(), &event_handler_, description_.name.c_str(),
|
||||
description_.description.c_str(), EventExec, event_handler_data)));
|
||||
CHECK_NE(event_handler_, nullptr);
|
||||
|
||||
CHECK_OK(SCIP_TO_STATUS(
|
||||
SCIPsetEventhdlrInit(scip->scip(), event_handler, EventInit)));
|
||||
SCIPsetEventhdlrInit(gscip->scip(), event_handler_, EventInit)));
|
||||
CHECK_OK(SCIP_TO_STATUS(
|
||||
SCIPsetEventhdlrFree(scip->scip(), event_handler, EventFree)));
|
||||
SCIPsetEventhdlrExit(gscip->scip(), event_handler_, EventExit)));
|
||||
CHECK_OK(SCIP_TO_STATUS(
|
||||
SCIPsetEventhdlrFree(gscip->scip(), event_handler_, EventFree)));
|
||||
}
|
||||
|
||||
SCIP_RETCODE GScipEventHandler::CatchEvent(const SCIP_EVENTTYPE event_type) {
|
||||
int filter_pos = -1;
|
||||
|
||||
SCIP_CALL(SCIPcatchEvent(gscip_->scip(), event_type, event_handler_,
|
||||
/*eventdata=*/nullptr, &filter_pos));
|
||||
CHECK_GE(filter_pos, 0);
|
||||
|
||||
caught_events_.emplace_back(event_type, filter_pos);
|
||||
|
||||
return SCIP_OKAY;
|
||||
}
|
||||
|
||||
SCIP_RETCODE DropAllEvents(GScipEventHandler& handler) {
|
||||
for (const GScipEventHandler::CaughtEvent& caught_event :
|
||||
handler.caught_events_) {
|
||||
SCIP_CALL(SCIPdropEvent(handler.gscip_->scip(), caught_event.event_type,
|
||||
handler.event_handler_,
|
||||
/*eventdata=*/nullptr, caught_event.filter_pos));
|
||||
}
|
||||
|
||||
handler.caught_events_.clear();
|
||||
|
||||
return SCIP_OKAY;
|
||||
}
|
||||
|
||||
} // namespace operations_research
|
||||
|
||||
@@ -35,16 +35,6 @@ struct GScipEventHandlerDescription {
|
||||
|
||||
// See CONSHDLR_DESC in SCIP documentation above.
|
||||
std::string description;
|
||||
|
||||
// These are "general" events to be added via SCIPcatchEvent in the EVENTINIT
|
||||
// callback, not "Var" or "Row" events. See scip/type_event.h for the list of
|
||||
// possible events.
|
||||
std::vector<SCIP_EVENTTYPE> events_to_catch_from_start;
|
||||
|
||||
// TODO(user,user): Support Var and Row events.
|
||||
|
||||
// TODO(user,user): Support registering events in the EVENTINITSOL
|
||||
// callback, which would cause them to be trapped only after presolve.
|
||||
};
|
||||
|
||||
// Passed by value. This is a lightweight interface to the callback context and
|
||||
@@ -66,28 +56,137 @@ class GScipEventHandlerContext {
|
||||
// queried within an event handler.
|
||||
|
||||
private:
|
||||
GScip* gscip_;
|
||||
SCIP_EVENTTYPE event_type_;
|
||||
GScip* const gscip_;
|
||||
const SCIP_EVENTTYPE event_type_;
|
||||
};
|
||||
|
||||
// Inherit from this to implement the callback.
|
||||
// Inherit from this to implement the callback and override Init() to call
|
||||
// CatchEvent() for the events you want to listen to.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// class MyHandler : public GScipEventHandler {
|
||||
// public:
|
||||
// MyHandler()
|
||||
// : GScipEventHandler({
|
||||
// .name = "my handler", .description = "something"}) {}
|
||||
//
|
||||
// SCIP_RETCODE Init(GScip* const gscip) override {
|
||||
// SCIP_CALL(CatchEvent(SCIP_EVENTTYPE_SOLFOUND));
|
||||
// return SCIP_OKAY;
|
||||
// }
|
||||
//
|
||||
// SCIP_RETCODE Execute(const GScipEventHandlerContext context) override {
|
||||
// ...
|
||||
// return SCIP_OKAY;
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// std::unique_ptr<GScip> gscip = ...;
|
||||
//
|
||||
// MyHandler handler;
|
||||
// handler.Register(gscip.get());
|
||||
//
|
||||
class GScipEventHandler {
|
||||
public:
|
||||
explicit GScipEventHandler(const GScipEventHandlerDescription& description)
|
||||
: description_(description) {}
|
||||
virtual ~GScipEventHandler() {}
|
||||
const GScipEventHandlerDescription& description() const {
|
||||
return description_;
|
||||
|
||||
virtual ~GScipEventHandler() = default;
|
||||
|
||||
// Registers this event handler to the given GScip.
|
||||
//
|
||||
// This function CHECKs that this handler has not been previously registered.
|
||||
//
|
||||
// The given GScip won't own this handler but will keep a pointer to it that
|
||||
// will be used during the solve.
|
||||
void Register(GScip* gscip);
|
||||
|
||||
// Initialization of the event handler. Called after the problem was
|
||||
// transformed.
|
||||
//
|
||||
// The implementation should use the CatchEvent() method to register to global
|
||||
// events.
|
||||
//
|
||||
// Return SCIP_OKAY, or use SCIP_CALL macro to wraps SCIP calls to properly
|
||||
// propagate errors.
|
||||
virtual SCIP_RETCODE Init(GScip* gscip) { return SCIP_OKAY; }
|
||||
|
||||
// Called when a caught event is emitted.
|
||||
//
|
||||
// Return SCIP_OKAY, or use SCIP_CALL macro to wraps SCIP calls to properly
|
||||
// propagate errors.
|
||||
virtual SCIP_RETCODE Execute(GScipEventHandlerContext context) {
|
||||
return SCIP_OKAY;
|
||||
}
|
||||
|
||||
virtual void Execute(GScipEventHandlerContext context) = 0;
|
||||
// Deinitialization of the event handler.
|
||||
//
|
||||
// Called before the transformed problem is freed and after all the events
|
||||
// specified in CatchEvent() have been dropped (thus there is no need to
|
||||
// implement this function to drop these events since this would have already
|
||||
// been done).
|
||||
//
|
||||
// Return SCIP_OKAY, or use SCIP_CALL macro to wraps SCIP calls to properly
|
||||
// propagate errors.
|
||||
virtual SCIP_RETCODE Exit(GScip* gscip) { return SCIP_OKAY; }
|
||||
|
||||
protected:
|
||||
// Catches a global event (i.e. not a variable or row depedent one) based on
|
||||
// the input event_type mask.
|
||||
//
|
||||
// This method must only be called after the problem is transformed; typically
|
||||
// it is called in the Init() virtual method.
|
||||
//
|
||||
// Caught events will be automatically dropped when the handler will be called
|
||||
// on EXIT (before calling the corresponding Exit() member function).
|
||||
//
|
||||
// See scip/type_event.h for the list of possible events. This function
|
||||
// corresponds to SCIPcatchEvent().
|
||||
//
|
||||
// TODO(user,user): Support Var and Row events.
|
||||
//
|
||||
// TODO(user,user): Support registering events in the EVENTINITSOL
|
||||
// callback, which would cause them to be trapped only after presolve.
|
||||
SCIP_RETCODE CatchEvent(SCIP_EVENTTYPE event_type);
|
||||
|
||||
private:
|
||||
GScipEventHandlerDescription description_;
|
||||
};
|
||||
struct CaughtEvent {
|
||||
CaughtEvent(const SCIP_EVENTTYPE event_type, const int filter_pos)
|
||||
: event_type(event_type), filter_pos(filter_pos) {}
|
||||
|
||||
// Handler is not owned but held.
|
||||
void RegisterGScipEventHandler(GScip* scip, GScipEventHandler* handler);
|
||||
// The event_type mask for this catch.
|
||||
SCIP_EVENTTYPE event_type;
|
||||
|
||||
// The key used by SCIP to identify this catch with SCIPdropEvent(). Using
|
||||
// this key prevents SCIP from having to do a look up to find the catch and
|
||||
// helps when there are duplicates.
|
||||
//
|
||||
// It is the index of the data associated to the catch in the array SCIP
|
||||
// uses as storage (this index is stable, even after other catch added
|
||||
// previously are removed, since SCIP maintains a free-list of removed items
|
||||
// instead of renumbering all elements).
|
||||
int filter_pos;
|
||||
};
|
||||
|
||||
// Calls SCIPdropEvent() for all events in caught_events_ and clear this
|
||||
// collection.
|
||||
//
|
||||
// This is not a member function since it needs to be visible to the SCIP Exit
|
||||
// callback function.
|
||||
friend SCIP_RETCODE DropAllEvents(GScipEventHandler& handler);
|
||||
|
||||
const GScipEventHandlerDescription description_;
|
||||
|
||||
// Pointer to GScip set by Register();
|
||||
GScip* gscip_ = nullptr;
|
||||
|
||||
// Pointer to the event handler registered on SCIP.
|
||||
SCIP_EVENTHDLR* event_handler_ = nullptr;
|
||||
|
||||
// Caught events via CatchEvent().
|
||||
std::vector<CaughtEvent> caught_events_;
|
||||
};
|
||||
|
||||
} // namespace operations_research
|
||||
|
||||
|
||||
@@ -104,25 +104,19 @@ void SCIPMessageHandlerWarning(SCIP_MESSAGEHDLR* const handler, FILE*,
|
||||
message);
|
||||
}
|
||||
|
||||
// Release the input message handler.
|
||||
//
|
||||
// This function is a wrapper around SCIPmessagehdlrRelease which, in addition
|
||||
// to releasing the handler, also resets the pointer to it, thus has a pointer
|
||||
// on pointer argument. We can't use that as a deleter for a unique_ptr as in
|
||||
// MessageHandlerPtr since we need a function that a pointer argument.
|
||||
void ReleaseSCIPMessageHandler(SCIP_MESSAGEHDLR* handler) {
|
||||
} // namespace
|
||||
|
||||
void ReleaseSCIPMessageHandler::operator()(SCIP_MESSAGEHDLR* handler) const {
|
||||
if (handler != nullptr) {
|
||||
CHECK_EQ(SCIPmessagehdlrRelease(&handler), SCIP_OKAY);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
MessageHandlerPtr CaptureMessageHandlerPtr(SCIP_MESSAGEHDLR* const handler) {
|
||||
if (handler != nullptr) {
|
||||
SCIPmessagehdlrCapture(handler);
|
||||
}
|
||||
return {handler, ReleaseSCIPMessageHandler};
|
||||
return MessageHandlerPtr(handler);
|
||||
}
|
||||
|
||||
absl::StatusOr<MessageHandlerPtr> MakeSCIPMessageHandler(
|
||||
@@ -146,7 +140,7 @@ absl::StatusOr<MessageHandlerPtr> MakeSCIPMessageHandler(
|
||||
// the unique_ptr since the ownership has been transferred to SCIP.
|
||||
data.release();
|
||||
|
||||
return MessageHandlerPtr{message_handler, ReleaseSCIPMessageHandler};
|
||||
return MessageHandlerPtr(message_handler);
|
||||
}
|
||||
|
||||
ScopedSCIPMessageHandlerDisabler::ScopedSCIPMessageHandlerDisabler(
|
||||
|
||||
@@ -38,12 +38,21 @@ using GScipMessageHandler =
|
||||
|
||||
namespace internal {
|
||||
|
||||
// Functor that releases the input message handler if not nullptr. It is used as
|
||||
// the deleter for the MessageHandlerPtr unique_ptr.
|
||||
//
|
||||
// It is a wrapper around SCIPmessagehdlrRelease.
|
||||
struct ReleaseSCIPMessageHandler {
|
||||
void operator()(SCIP_MESSAGEHDLR* handler) const;
|
||||
};
|
||||
|
||||
// A unique_ptr that releases a SCIP message handler when destroyed.
|
||||
//
|
||||
// Use CaptureMessageHandlerPtr() to create values of this type, capturing their
|
||||
// input.
|
||||
// Use CaptureMessageHandlerPtr() to create to capture an existing message
|
||||
// handler and creates this automatic pointer that will released it on
|
||||
// destruction.
|
||||
using MessageHandlerPtr =
|
||||
std::unique_ptr<SCIP_MESSAGEHDLR, void (*)(SCIP_MESSAGEHDLR*)>;
|
||||
std::unique_ptr<SCIP_MESSAGEHDLR, ReleaseSCIPMessageHandler>;
|
||||
|
||||
// Captures the input handler and returns a unique pointer that will release it
|
||||
// when destroyed.
|
||||
|
||||
Reference in New Issue
Block a user