1
$\begingroup$

I am a solver beginner, would like to ask you how to call the solver to achieve second-level recording, as documented in many articles, as shown below.enter image description hereenter image description here

$\endgroup$

1 Answer 1

2
$\begingroup$

SCIP is based on a plugin-architecture, see this video for an introduction.

In your case you are interested in Event Handlers:

While solving a constraint integer program, SCIP drops thousands of events such as SCIP_EVENTTYPE_VARFIXED (a complete list of all events is given in type_event.h). These events can be caught and used to do something after a certain event happens. [...] To be able to catch an event it is necessary to write an event handler which defines what to do after a certain event was caught.

SCIP_EVENTTYPE_BESTSOLFOUND is probably the event you will need to catch.

Within the event-handler you are free to do whatever you want (could write to DB, could even do some nested SCIP solving in theory) as long as you respect SCIPs API, which usually means: respecting what you are allowed to call in this moment. Example:

SCIP_DECL_EVENTEXEC(EventhdlrNewSol::scip_exec)
{
    SCIP_SOL* sol = SCIPgetBestSol(scip);
    SCIPgetSolOrigObj(scip,sol)
    // write to file or something to keep a record
}

Above we used and should make sure, that we are allowed to call SCIPgetBestSol + SCIPgetSolOrigObj, let's check: Docs

enter image description here

There is a slightly more complex example in the official sources: https://github.com/scipopt/scip/tree/master/examples/TSP/src.

Given that example, i might mention, that you probably want to add a class-member to your event-handler class to track the root-time (solve started when) and init it within the constructor. This makes it available in your SCIP_DECL_EVENTEXEC to get a time-delta later when needed. You could also do file-IO (e.g. opening and keeping a file-handle available) or other stuff like this.

So a small adaption of the original example migh look like (C++):

  /** C++ wrapper object for event handlers */
  class EventhdlrNewSol : public scip::ObjEventhdlr
  {

     // OUR data
     std::chrono::time_point<std::chrono::high_resolution_clock> root_time;

  public:
     /** default constructor */
     EventhdlrNewSol(
        SCIP* scip
        )
        : ObjEventhdlr(scip, "newsol","event handler for new solutions in TSP")
     {
        // we assume callback setup-time is approximately solve start-time
        root_time = std::chrono::high_resolution_clock::now();
     }
     

Edit: SCIP also has SCIPsolGetTime() which allows us to skip manual time-tracking as shown above (which is still a nice small demo of the OOP-style things you can do).


Above describes the native SCIP tooling (C or C++). If you are using Python or something else, consider the toolings documentation. In general howewer, the rules to play by with are the same.


Alternative

For your use-case, it might also be sufficient to parse the ouput as SCIP is afaik complete (enough) in it's stdout-based logging irt. incumbents + time. This feels a bit hacky, but might get the job done too.

$\endgroup$
4
  • $\begingroup$ Thanks for your answer, may I give some more concrete questions. In the pictures, the number of test datasets are usually 100, and most of related papers said that their solving time is 1-1000 seconds and average primal gap or objective. I have tried to use event handlers, like SCIPgetBestSol and so on. However, I get a series results of primal gap, but I can't average them, because their corresponding time of different instance is different and I don't know how to record the information by seconds. In addition, I use pyscipopt to operate it. Could you give some experience about these. $\endgroup$
    – Paul
    May 20 at 1:37
  • $\begingroup$ If you pick the right event, there is all the information you need. A BestSolFound event is always an improvement leading to a strictly monotonic function.If we assume, that there are no missed events we got perfect information (in compressed form). Each event is a point on the graph. You can then, within a small script, post-caclulate all your points you need. Don't do it during execution. Postprocess. With our assumptions, every point in the graph is defined by the last value to the left (aka x-parallel lines through points i bounded by i+1). Then averaging is easy. Make sense? $\endgroup$
    – sascha
    May 20 at 1:47
  • $\begingroup$ Aka if you found the first sol of value 11 after 3 secs, 8 after 13 secs and 5 after 20 secs, f(x in [3, 13)]) = 11, f(x in [13, 20) = 8 and so on. (the absence of improvement events means the function is still (piecewise-)constant). $\endgroup$
    – sascha
    May 20 at 1:49
  • $\begingroup$ Yes, I can understand this! Thank you very much. I had similar ideas, but I can't guarantee that it is correct. Because there is no similar experience! Maybe, the BestSolFound is enough, thank you again. I will try it again. $\endgroup$
    – Paul
    May 20 at 2:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.