1717#include " io/HighsIO.h" // For pdlpLogging
1818#include " pdlp/cupdlp/cupdlp.h" // For pdlpLogging
1919
20+ // Helper function to compute the score
21+ static double compute_score (double beta, double primal_feas, double dual_feas, double duality_gap) {
22+ return std::sqrt (beta * primal_feas * primal_feas +
23+ dual_feas * dual_feas / beta +
24+ duality_gap * duality_gap);
25+ }
26+
2027// Initializes the restart scheme with parameters and initial results
2128void RestartScheme::Initialize (const SolverResults& results) {
2229 strategy_ = params_->restart_strategy ;
@@ -28,34 +35,16 @@ void RestartScheme::Initialize(const SolverResults& results) {
2835 // in the paper, primal weight is the ω:
2936 // ω = √β
3037 beta_ = params_->omega * params_->omega ;
31-
32- last_restart_iter_ = 0 ;
33- last_restart_score_ = std::numeric_limits<double >::infinity ();
34- last_candidate_score_ = std::numeric_limits<double >::infinity ();
35- }
36-
37- // Computes a weighted score to evaluate solution quality
38- double RestartScheme::ComputeRestartScore (const SolverResults& results) {
39- double weight_squared = beta_;
40- double primal_feas_sq =
41- results.primal_feasibility * results.primal_feasibility ;
42- double dual_feas_sq = results.dual_feasibility * results.dual_feasibility ;
43- double gap_sq = results.duality_gap * results.duality_gap ;
44-
45- // debugPdlpRestarScoretLog(debug_pdlp_log_file_, weight_squared,
46- // results.primal_feasibility, results.dual_feasibility, results.duality_gap);
47-
48- return std::sqrt (weight_squared * primal_feas_sq +
49- dual_feas_sq / weight_squared + gap_sq);
5038}
5139
40+ /*
5241// Main logic to check if a restart is needed
5342RestartInfo RestartScheme::Check(int current_iter,
5443 const SolverResults& current_results,
5544 const SolverResults& average_results) {
5645 RestartInfo info;
5746
58- if (current_iter = = last_restart_iter_) {
47+ if (current_iter < = last_restart_iter_) {
5948 double current_score = ComputeRestartScore(current_results);
6049 last_restart_score_ = current_score;
6150 last_candidate_score_ = current_score;
@@ -77,8 +66,8 @@ RestartInfo RestartScheme::Check(int current_iter,
7766 case RestartStrategy::ADAPTIVE_RESTART: {
7867 double current_score = ComputeRestartScore(current_results);
7968 double average_score = ComputeRestartScore(average_results);
80- debugPdlpRestartLog (debug_pdlp_log_file_, current_iter, current_score,
81- average_score);
69+ // debugPdlpRestartLog(debug_pdlp_log_file_, current_iter, current_score,
70+ // average_score);
8271
8372 // Choose the best candidate (current vs. average) based on the score
8473 double candidate_score = std::min(current_score, average_score);
@@ -133,3 +122,88 @@ RestartInfo RestartScheme::Check(int current_iter,
133122
134123 return info;
135124}
125+ */
126+
127+ RestartInfo RestartScheme::Check (int current_iter,
128+ const SolverResults& current_results,
129+ const SolverResults& average_results) {
130+ if (strategy_ != RestartStrategy::ADAPTIVE_RESTART) {
131+ if (strategy_ == RestartStrategy::FIXED_RESTART &&
132+ current_iter - last_restart_iter_ >= fixed_restart_interval_) {
133+ return RestartInfo (true , true );
134+ }
135+ return RestartInfo (false , false ); // ✨ Corrected return
136+ }
137+
138+ // Base Case: First check after a restart. Initialize state and exit.
139+ if (current_iter == last_restart_iter_) {
140+ primal_feas_last_restart_ = current_results.primal_feasibility ;
141+ dual_feas_last_restart_ = current_results.dual_feasibility ;
142+ duality_gap_last_restart_ = current_results.duality_gap ;
143+
144+ primal_feas_last_candidate_ = current_results.primal_feasibility ;
145+ dual_feas_last_candidate_ = current_results.dual_feasibility ;
146+ duality_gap_last_candidate_ = current_results.duality_gap ;
147+
148+ return {false , false };
149+ }
150+
151+ // 1. Calculate scores and determine the best candidate
152+ double mu_current = compute_score (beta_, current_results.primal_feasibility ,
153+ current_results.dual_feasibility , current_results.duality_gap );
154+ double mu_average = compute_score (beta_, average_results.primal_feasibility ,
155+ average_results.dual_feasibility , average_results.duality_gap );
156+ debugPdlpRestartLog (debug_pdlp_log_file_, current_iter, mu_current,
157+ mu_average);
158+ double candidate_score;
159+ bool restart_to_average;
160+ if (mu_current < mu_average) {
161+ candidate_score = mu_current;
162+ restart_to_average = false ;
163+ } else {
164+ candidate_score = mu_average;
165+ restart_to_average = true ;
166+ }
167+
168+ // 2. Check the three restart conditions in order
169+ bool should_restart = false ;
170+ PDHG_restart_choice restart_choice_for_logic = PDHG_NO_RESTART;
171+
172+ if ((current_iter - last_restart_iter_) >= 0.36 * current_iter) {
173+ // Condition 1: Artificial Restart
174+ should_restart = true ;
175+ } else {
176+ double mu_last_restart = compute_score (beta_, primal_feas_last_restart_,
177+ dual_feas_last_restart_, duality_gap_last_restart_);
178+
179+ if (candidate_score < sufficient_decay_factor_ * mu_last_restart) {
180+ // Condition 2: Sufficient Decay
181+ should_restart = true ;
182+ } else {
183+ double mu_last_candidate = compute_score (beta_, primal_feas_last_candidate_,
184+ dual_feas_last_candidate_, duality_gap_last_candidate_);
185+
186+ if (candidate_score < necessary_decay_factor_ * mu_last_restart && candidate_score > mu_last_candidate) {
187+ // Condition 3: Necessary Decay
188+ should_restart = true ;
189+ }
190+ }
191+ }
192+
193+ // 3. ALWAYS update the "last candidate" metrics for the next check
194+ if (restart_to_average) {
195+ primal_feas_last_candidate_ = average_results.primal_feasibility ;
196+ dual_feas_last_candidate_ = average_results.dual_feasibility ;
197+ duality_gap_last_candidate_ = average_results.duality_gap ;
198+ } else {
199+ primal_feas_last_candidate_ = current_results.primal_feasibility ;
200+ dual_feas_last_candidate_ = current_results.dual_feasibility ;
201+ duality_gap_last_candidate_ = current_results.duality_gap ;
202+ }
203+
204+ // NOTE: Your main solver loop is responsible for calling `SetLastRestartIter(current_iter)`
205+ // when it receives `should_restart = true`. This function does not modify that state directly,
206+ // it only determines if it *should* happen.
207+
208+ return RestartInfo (should_restart, restart_to_average);
209+ }
0 commit comments