Skip to content

Commit 799788b

Browse files
committed
fix initialize step size for adaptive step size
1 parent ddecb9d commit 799788b

File tree

3 files changed

+95
-55
lines changed

3 files changed

+95
-55
lines changed

highs/pdlp/hipdlp/pdhg.cc

Lines changed: 90 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -343,19 +343,15 @@ PostSolveRetcode PDLPSolver::postprocess(HighsSolution& solution) {
343343

344344
void PDLPSolver::solve(std::vector<double>& x, std::vector<double>& y) {
345345
Timer solver_timer;
346-
347346
const HighsLp& lp = lp_;
348347

349348
debug_pdlp_log_file_ = fopen("HiPDLP.log", "w");
350349
assert(debug_pdlp_log_file_);
351350

352351
// --- 0. Using PowerMethod to estimate the largest eigenvalue ---
353-
const double op_norm_sq = PowerMethod();
354-
stepsize_ =
355-
InitializeStepSizesPowerMethod(op_norm_sq);
356-
const double fixed_eta = 0.99 / sqrt(op_norm_sq);
352+
InitializeStepSizes();
353+
357354
PrimalDualParams working_params = params_;
358-
359355
working_params.omega = std::sqrt(stepsize_.dual_step / stepsize_.primal_step);
360356
working_params.eta = std::sqrt(stepsize_.primal_step * stepsize_.dual_step);
361357
current_eta_ = working_params.eta;
@@ -386,7 +382,7 @@ void PDLPSolver::solve(std::vector<double>& x, std::vector<double>& y) {
386382
ratio_last_two_step_sizes_ = 1.0;
387383
bool using_malitsky_averaging =
388384
(params_.step_size_strategy == StepSizeStrategy::MALITSKY_POCK);
389-
bool primal_average_initialized = false;
385+
bool primal_average_initialized = false;
390386

391387
// Initialize vectors for matrix-vector products
392388
std::vector<double> Ax_avg(lp.num_row_, 0.0);
@@ -534,7 +530,7 @@ void PDLPSolver::solve(std::vector<double>& x, std::vector<double>& y) {
534530
break;
535531

536532
case StepSizeStrategy::ADAPTIVE:
537-
UpdateIteratesAdaptive(iter);
533+
UpdateIteratesAdaptive();
538534
break;
539535

540536
case StepSizeStrategy::MALITSKY_POCK:
@@ -1170,62 +1166,101 @@ void AdaptiveLinesearchParams::initialise() {
11701166
// SECTION 4: Step Update Methods (from step.cc)
11711167
// =============================================================================
11721168

1173-
StepSizeConfig PDLPSolver::InitializeStepSizesPowerMethod(double op_norm_sq) {
1174-
StepSizeConfig config;
1175-
config.power_method_lambda = op_norm_sq;
1176-
double cost_norm = linalg::compute_cost_norm(lp_, 2.0);
1177-
double rhs_norm = linalg::compute_rhs_norm(lp_, 2.0);
1169+
void PDLPSolver::InitializeStepSizes() {
1170+
double cost_norm_sq = linalg::vector_norm_squared(lp_.col_cost_);
1171+
double rhs_norm_sq = linalg::vector_norm_squared(lp_.row_lower_);
11781172

1179-
highsLogUser(params_.log_options_, HighsLogType::kInfo,
1180-
"Cost norm: %g, RHS norm: %g\n", cost_norm, rhs_norm);
1181-
config.beta = cost_norm * cost_norm / (rhs_norm * rhs_norm + 1e-10);
1182-
1183-
const double safety_factor = 0.8;
1184-
double base_step = safety_factor / std::sqrt(op_norm_sq);
1173+
if (std::min(cost_norm_sq, rhs_norm_sq) > 1e-6) {
1174+
stepsize_.beta = cost_norm_sq / rhs_norm_sq;
1175+
} else {
1176+
stepsize_.beta = 1.0;
1177+
}
11851178

1186-
config.primal_step = base_step / std::sqrt(config.beta);
1187-
config.dual_step = base_step * std::sqrt(config.beta);
1188-
return config;
1179+
// Initialize step sizes based on strategy
1180+
if (params_.step_size_strategy == StepSizeStrategy::FIXED) {
1181+
// Use power method for fixed step size
1182+
const double op_norm_sq = PowerMethod();
1183+
stepsize_.power_method_lambda = op_norm_sq;
1184+
1185+
const double safety_factor = 0.8;
1186+
double base_step = safety_factor / std::sqrt(op_norm_sq);
1187+
1188+
stepsize_.primal_step = base_step / std::sqrt(stepsize_.beta);
1189+
stepsize_.dual_step = base_step * std::sqrt(stepsize_.beta);
1190+
1191+
highsLogUser(params_.log_options_, HighsLogType::kInfo,
1192+
"Initial step sizes from power method lambda = %g: primal = %g; dual = %g\n",
1193+
op_norm_sq, stepsize_.primal_step, stepsize_.dual_step);
1194+
} else {
1195+
// Use matrix infinity norm for adaptive step size
1196+
// Compute infinity norm of matrix elements
1197+
double mat_elem_norm_inf = 0.0;
1198+
const HighsSparseMatrix& matrix = lp_.a_matrix_;
1199+
for (int i = 0; i < matrix.numNz(); ++i) {
1200+
mat_elem_norm_inf = std::max(mat_elem_norm_inf, std::abs(matrix.value_[i]));
1201+
}
1202+
1203+
if (mat_elem_norm_inf < 1e-10) {
1204+
mat_elem_norm_inf = 1.0; // Avoid division by zero
1205+
}
1206+
1207+
// Initialize step sizes using infinity norm
1208+
stepsize_.primal_step = (1.0 / mat_elem_norm_inf) / std::sqrt(stepsize_.beta);
1209+
stepsize_.dual_step = stepsize_.primal_step * stepsize_.beta;
1210+
1211+
highsLogUser(params_.log_options_, HighsLogType::kInfo,
1212+
"Initial step sizes from matrix inf-norm = %g: primal = %g; dual = %g\n",
1213+
mat_elem_norm_inf, stepsize_.primal_step, stepsize_.dual_step);
1214+
}
11891215
}
11901216

1191-
std::vector<double> PDLPSolver::UpdateX() {
1217+
std::vector<double> PDLPSolver::UpdateX(double primal_step) {
11921218
std::vector<double> x_new(lp_.num_col_);
11931219
debug_pdlp_data_.aty_norm = linalg::vector_norm(ATy_cache_);
11941220
for (HighsInt i = 0; i < lp_.num_col_; i++) {
11951221
double gradient = lp_.col_cost_[i] - ATy_cache_[i];
1196-
x_new[i] = linalg::project_box(x_current_[i] - stepsize_.primal_step * gradient,
1222+
x_new[i] = linalg::project_box(x_current_[i] - primal_step * gradient,
11971223
lp_.col_lower_[i], lp_.col_upper_[i]);
11981224
}
11991225
return x_new;
12001226
}
12011227

1202-
std::vector<double> PDLPSolver::UpdateY() {
1228+
std::vector<double> PDLPSolver::UpdateY(double dual_step) {
12031229
std::vector<double> y_new(lp_.num_row_);
12041230
for (HighsInt j = 0; j < lp_.num_row_; j++) {
12051231
double extr_ax = 2 * Ax_next_[j] - Ax_cache_[j];
12061232
bool is_equality = (lp_.row_lower_[j] == lp_.row_upper_[j]);
12071233
double q = lp_.row_lower_[j];
1208-
double dual_update = y_current_[j] + stepsize_.dual_step * (q - extr_ax);
1234+
double dual_update = y_current_[j] + dual_step * (q - extr_ax);
12091235
y_new[j] = is_equality ? dual_update : linalg::project_non_negative(dual_update);
12101236
}
12111237
return y_new;
12121238
}
12131239

12141240
void PDLPSolver::UpdateIteratesFixed() {
1215-
x_next_ = UpdateX();
1241+
x_next_ = UpdateX(stepsize_.primal_step);
12161242
linalg::Ax(lp_, x_next_, Ax_next_);
1217-
y_next_ = UpdateY();
1243+
y_next_ = UpdateY(stepsize_.dual_step);
12181244
}
12191245

1220-
void PDLPSolver::UpdateIteratesAdaptive(int& step_size_iter_count) {
1246+
void PDLPSolver::UpdateIteratesAdaptive() {
12211247
const double MIN_ETA = 1e-6;
12221248
const double MAX_ETA = 1.0;
12231249

12241250
bool accepted_step = false;
12251251
int inner_iterations = 0;
12261252
int num_rejected_steps = 0;
12271253

1228-
while (!accepted_step) {
1254+
double dStepSizeUpdate = std::sqrt(stepsize_.primal_step *
1255+
stepsize_.dual_step);
1256+
1257+
// Compute candidate solution
1258+
std::vector<double> x_candidate(lp_.num_col_);
1259+
std::vector<double> y_candidate(lp_.num_row_);
1260+
std::vector<double> ax_candidate(lp_.num_row_);
1261+
std::vector<double> aty_candidate(lp_.num_col_);
1262+
while (!accepted_step) {
1263+
stepsize_.step_size_iter++; //nStepSizeIter
12291264
inner_iterations++;
12301265

12311266
if (inner_iterations >= 60) {
@@ -1235,18 +1270,16 @@ while (!accepted_step) {
12351270
break;
12361271
}
12371272

1238-
// Compute candidate solution
1239-
std::vector<double> x_candidate(lp_.num_col_);
1240-
std::vector<double> y_candidate(lp_.num_row_);
1241-
std::vector<double> ax_candidate(lp_.num_row_);
1242-
std::vector<double> aty_candidate(lp_.num_col_);
1273+
// Calculate step sizes for this iteration
1274+
double primal_step_update = dStepSizeUpdate / std::sqrt(stepsize_.beta);
1275+
double dual_step_update = dStepSizeUpdate * std::sqrt(stepsize_.beta);
12431276

12441277
// Primal update
1245-
x_candidate = UpdateX();
1278+
x_candidate = UpdateX(primal_step_update);
12461279
linalg::Ax(lp_, x_candidate, ax_candidate);
12471280

12481281
// Dual update
1249-
y_candidate = UpdateY();
1282+
y_candidate = UpdateY(dual_step_update);
12501283
linalg::ATy(lp_, y_candidate, aty_candidate);
12511284

12521285
// Compute deltas
@@ -1265,11 +1298,13 @@ while (!accepted_step) {
12651298
}
12661299

12671300
// Check numerical stability
1301+
/*
12681302
if (!CheckNumericalStability(delta_x, delta_y)) {
12691303
std::cerr << "Numerical instability detected" << std::endl;
1270-
current_eta_ *= 0.5; // Drastically reduce step size
1304+
dStepSizeUpdate *= 0.5; // Drastically reduce step size
12711305
continue;
12721306
}
1307+
*/
12731308

12741309
// Compute movement and nonlinearity
12751310
double movement = ComputeMovement(delta_x, delta_y);
@@ -1278,7 +1313,7 @@ while (!accepted_step) {
12781313

12791314
// Compute step size limit
12801315
double step_size_limit = (nonlinearity > 1e-12)
1281-
? (movement / (2.0 * nonlinearity))
1316+
? (movement / (1.0 * nonlinearity))
12821317
: // in cupdlp-c, the factor is 1
12831318
std::numeric_limits<double>::infinity();
12841319

@@ -1288,12 +1323,7 @@ while (!accepted_step) {
12881323
= %g\n", int(inner_iterations), current_eta, movement, nonlinearity.
12891324
step_size_limit);
12901325
*/
1291-
if (current_eta_ <= step_size_limit) {
1292-
// Accept the step
1293-
x_next_ = x_candidate;
1294-
y_next_ = y_candidate;
1295-
Ax_next_ = ax_candidate;
1296-
ATy_cache_ = aty_candidate;
1326+
if (dStepSizeUpdate <= step_size_limit) {
12971327
accepted_step = true;
12981328
} else {
12991329
num_rejected_steps++;
@@ -1303,21 +1333,31 @@ while (!accepted_step) {
13031333
double first_term =
13041334
(std::isinf(step_size_limit))
13051335
? step_size_limit
1306-
: (1.0 - std::pow(step_size_iter_count + 1.0,
1336+
: (1.0 - std::pow(stepsize_.step_size_iter + 1.0,
13071337
-params_.adaptive_linesearch_params
13081338
.step_size_reduction_exponent)) *
13091339
step_size_limit;
13101340

13111341
double second_term =
13121342
(1.0 +
13131343
std::pow(
1314-
step_size_iter_count + 1.0,
1344+
stepsize_.step_size_iter + 1.0,
13151345
-params_.adaptive_linesearch_params.step_size_growth_exponent)) *
1316-
current_eta_;
1346+
dStepSizeUpdate;
13171347

1318-
current_eta_ = std::min(first_term, second_term);
1319-
current_eta_ = std::max(MIN_ETA, std::min(MAX_ETA, current_eta_));
1348+
dStepSizeUpdate = std::min(first_term, second_term);
1349+
//current_eta_ = std::max(MIN_ETA, std::min(MAX_ETA, current_eta_));
13201350
}
1351+
1352+
x_next_ = x_candidate;
1353+
y_next_ = y_candidate;
1354+
Ax_next_ = ax_candidate;
1355+
ATy_next_ = aty_candidate;
1356+
1357+
current_eta_ = dStepSizeUpdate;
1358+
stepsize_.primal_step = dStepSizeUpdate / std::sqrt(stepsize_.beta);
1359+
std::cout << "new primal step: " << stepsize_.primal_step << std::endl;
1360+
stepsize_.dual_step = dStepSizeUpdate * std::sqrt(stepsize_.beta);
13211361
}
13221362

13231363
bool PDLPSolver::UpdateIteratesMalitskyPock(

highs/pdlp/hipdlp/pdhg.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,11 @@ class PDLPSolver {
6868
double PowerMethod();
6969

7070
// --- Step Update Methods (previously in Step) ---
71-
StepSizeConfig InitializeStepSizesPowerMethod(double op_norm_sq);
72-
std::vector<double> UpdateX();
73-
std::vector<double> UpdateY();
71+
void InitializeStepSizes();
72+
std::vector<double> UpdateX(double primal_step);
73+
std::vector<double> UpdateY(double dual_step);
7474
void UpdateIteratesFixed();
75-
void UpdateIteratesAdaptive(int& step_size_iter_count);
75+
void UpdateIteratesAdaptive();
7676
bool UpdateIteratesMalitskyPock(bool first_malitsky_iteration);
7777

7878
// --- Step Size Helper Methods (previously in PdlpStep) ---

highs/pdlp/hipdlp/restart.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ class RestartScheme {
6060
};
6161
void SetLastRestartIter(int iter) { last_restart_iter_ = iter; };
6262

63-
// State for adaptive restart
63+
// State for adaptive restart
6464
//dPrimalFeasLastRestart = primal_feas_last_restart_
6565
//dDualFeasLastRestart = dual_feas_last_restart_;
6666
//dDualityGapLastRestart = duality_gap_last_restart_;

0 commit comments

Comments
 (0)