PDLP declared scaled a2864 instance infeasible
- Dominant language
- C++
- Stars
- 14.1k
- Forks
- 2.5k
- Avg merge
- 8h 39m
- Merged PRs (30d)
- 72
Description
Version: 9.10
Language: C++
Solver: PDLP
OS: Linux
**The issue**
PDLP is declaring a scaled version of the a2864 instance from the [Mittelmann](https://plato.asu.edu/ftp/lpopt.html) library infeasible.
The instance should be feasible. This was verified by solving the instance with Gurobi that found an optimal solution.
However, after 64 iterations PDLP declared the problem infeasible.
**Relevant files**
[mps instance](https://drive.google.com/file/d/1wYPjE3spe2YzQZ0nB0wK_Y9wClYj_OGk/view)
[decoded_solve_log.json](https://github.com/user-attachments/files/22910776/decoded_solve_log.json)
[solver-output.txt](https://github.com/user-attachments/files/22910823/solver-output.txt)
**The suspected cause**
~~Inspection of the code showed that the that the objective gradient was being included in the computation of the max_dual_ray_infeasibility,~~ based on the logs it appears the algorithm stumbling across a point where the dual infeasibility (including the objective gradient) is zero and the dual objective is 1.68 * 10^{-15}. I believe there is a numerical error causing the slightly positive dual objective since it is very small (~10^{-15}). Replacing
http://github.com/google/or-tools/blob/93dafb79a0261b5211f4eb17437aeebd7f45e543/ortools/pdlp/iteration_stats.cc#L522C35-L522C66
with
result.set_dual_ray_objective(dual_ray_objective / l_inf_dual - 1e-14);
Fixed the issue and the algorithm rapidly found the optimal solution ~2624 iterations, using the command line interface, i.e.,
```bash
"$path_to_OR_tools"/build/bin/pdlp_solve --input "$path_to_instances"/"$instance_name".mps --sol_file "$path_to_solution_files"/no-polish-"$instance_name".sol --solve_log_file "$path_to_log_files"/no-polish-"$instance_name".json --params "verbosity_level: 4 num_threads: 16 termination_criteria {detailed_optimality_criteria {eps_optimal_primal_residual_absolute: 1.0e-8 eps_optimal_primal_residual_relative: 0.0 eps_optimal_dual_residual_absolute: 1.0e-8 eps_optimal_dual_residual_relative: 0.0 eps_optimal_objective_gap_absolute: 0.0 eps_optimal_objective_gap_relative: 1.0e-2} eps_primal_infeasible: 1.0e-9 eps_dual_infeasible: 1.0e-9 optimality_norm: OPTIMALITY_NORM_L_INF} use_feasibility_polishing: false handle_some_primal_gradients_on_finite_bounds_as_residuals: false"
```
**Other relevant material**
Documentation on infeasibility certificates for PDLP
https://developers.google.com/optimization/lp/pdlp_math#infeasibility_identification
**Comment on previous suspected cause**
Initially, I though that the primal infeasibility certificate was not being computed with the homogenous residuals but actually it is just being computed in a slightly confusing way (and differently from the primal certificate). In particular,
https://github.com/google/or-tools/blob/93dafb79a0261b5211f4eb17437aeebd7f45e543/ortools/pdlp/iteration_stats.cc#L505-L528
shows that the "scaled_primal_gradient" is being computed with the PrimalGradientFromObjectiveProduct function with the option use_zero_primal_objective=true. Thus this is really the scaled_homogenous_primal_gradient"
Dual infeasibility certificate computes the homogenous residuals through an option in the PrimalResidualNorms function:
https://github.com/google/or-tools/blob/93dafb79a0261b5211f4eb17437aeebd7f45e543/ortools/pdlp/iteration_stats.cc#L66-L70
https://github.com/google/or-tools/blob/93dafb79a0261b5211f4eb17437aeebd7f45e543/ortools/pdlp/iteration_stats.cc#L530-L536
I would suggest inside the ComputeInfeasibilityInformation function renaming scaled_primal_gradient to scaled_homogeneous_primal_gradient, dual_residuals to homogeneous_dual_residuals, and primal_residuals to homogeneous_primal_residuals to improve readability
Contributor guide
Assessment
This issue has not been assessed yet.