bump gscip code

This commit is contained in:
Laurent Perron
2021-07-15 18:38:39 +02:00
parent b0c79d4d4b
commit 17ea6efa50
5 changed files with 210 additions and 62 deletions

View File

@@ -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,

View File

@@ -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

View File

@@ -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

View File

@@ -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(

View File

@@ -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.