| 2532 | } |
| 2533 | |
| 2534 | bool HighsMipSolverData::checkLimits(int64_t nodeOffset) const { |
| 2535 | const HighsOptions& options = *mipsolver.options_mip_; |
| 2536 | |
| 2537 | // This MIP instance may have been terminated |
| 2538 | if (terminatorActive()) |
| 2539 | if (this->terminatorTerminated()) return true; |
| 2540 | |
| 2541 | // Possible user interrupt |
| 2542 | if (!mipsolver.submip && !parallelLockActive() && |
| 2543 | mipsolver.callback_->user_callback) { |
| 2544 | mipsolver.callback_->clearHighsCallbackOutput(); |
| 2545 | if (interruptFromCallbackWithData(kCallbackMipInterrupt, |
| 2546 | mipsolver.solution_objective_, |
| 2547 | "MIP check limits")) { |
| 2548 | if (mipsolver.modelstatus_ == HighsModelStatus::kNotset) { |
| 2549 | highsLogDev(options.log_options, HighsLogType::kInfo, |
| 2550 | "User interrupt\n"); |
| 2551 | mipsolver.modelstatus_ = HighsModelStatus::kInterrupt; |
| 2552 | } |
| 2553 | return true; |
| 2554 | } |
| 2555 | } |
| 2556 | // Possible termination due to objective being at least as good as |
| 2557 | // the target value |
| 2558 | if (!mipsolver.submip && mipsolver.solution_objective_ < kHighsInf && |
| 2559 | options.objective_target > -kHighsInf) { |
| 2560 | // Note: |
| 2561 | // |
| 2562 | // Whether the sense is ObjSense::kMinimize or |
| 2563 | // ObjSense::kMaximize, the undefined value of |
| 2564 | // mipsolver.solution_objective_ is kHighsInf, and the default |
| 2565 | // target value is -kHighsInf, so had to rule out these cases in |
| 2566 | // the conditional statement above. |
| 2567 | // |
| 2568 | // mipsolver.solution_objective_ is the actual objective of the |
| 2569 | // MIP - including the offset, and independent of objective sense |
| 2570 | // |
| 2571 | // The target is reached if the objective is below (above) the |
| 2572 | // target value when minimizing (maximizing). |
| 2573 | const int int_sense = int(this->mipsolver.orig_model_->sense_); |
| 2574 | const bool reached_objective_target = |
| 2575 | int_sense * mipsolver.solution_objective_ < |
| 2576 | int_sense * options.objective_target; |
| 2577 | if (reached_objective_target) { |
| 2578 | if (mipsolver.modelstatus_ == HighsModelStatus::kNotset) { |
| 2579 | highsLogDev(options.log_options, HighsLogType::kInfo, |
| 2580 | "Reached objective target\n"); |
| 2581 | mipsolver.modelstatus_ = HighsModelStatus::kObjectiveTarget; |
| 2582 | } |
| 2583 | return true; |
| 2584 | } |
| 2585 | } |
| 2586 | |
| 2587 | if (options.mip_max_nodes != kHighsIInf && |
| 2588 | num_nodes + nodeOffset >= options.mip_max_nodes) { |
| 2589 | if (mipsolver.modelstatus_ == HighsModelStatus::kNotset) { |
| 2590 | highsLogDev(options.log_options, HighsLogType::kInfo, |
| 2591 | "Reached node limit\n"); |
nothing calls this directly
no test coverage detected