Skip to content

Commit 3e73eab

Browse files
authored
Merge branch 'branch-25.10' into dual-simplex-update-basis
2 parents 7b92818 + 93e10b7 commit 3e73eab

File tree

16 files changed

+153
-172
lines changed

16 files changed

+153
-172
lines changed

README.md

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,6 @@ Development wheels are available as nightlies, please update `--extra-index-url`
7373
pip install --pre \
7474
--extra-index-url=https://pypi.nvidia.com \
7575
--extra-index-url=https://pypi.anaconda.org/rapidsai-wheels-nightly/simple/ \
76-
nvidia-cuda-runtime-cu12=12.9.* \
7776
cuopt-server-cu12==25.10.* cuopt-sh-client==25.10.*
7877
```
7978

@@ -82,7 +81,6 @@ For CUDA 13.x:
8281
```bash
8382
pip install \
8483
--extra-index-url=https://pypi.nvidia.com \
85-
nvidia-cuda-runtime==13.0.* \
8684
cuopt-server-cu13==25.10.* cuopt-sh-client==25.10.*
8785
```
8886

@@ -91,7 +89,6 @@ Development wheels are available as nightlies, please update `--extra-index-url`
9189
pip install --pre \
9290
--extra-index-url=https://pypi.nvidia.com \
9391
--extra-index-url=https://pypi.anaconda.org/rapidsai-wheels-nightly/simple/ \
94-
nvidia-cuda-runtime==13.0.* \
9592
cuopt-server-cu13==25.10.* cuopt-sh-client==25.10.*
9693
```
9794

@@ -115,13 +112,13 @@ Users can pull the cuOpt container from the NVIDIA container registry.
115112

116113
```bash
117114
# For CUDA 12.x
118-
docker pull nvidia/cuopt:latest-cuda12.9-py312
115+
docker pull nvidia/cuopt:latest-cuda12.9-py3.13
119116

120117
# For CUDA 13.x
121-
docker pull nvidia/cuopt:latest-cuda13.0-py312
118+
docker pull nvidia/cuopt:latest-cuda13.0-py3.13
122119
```
123120

124-
Note: The ``latest`` tag is the latest stable release of cuOpt. If you want to use a specific version, you can use the ``<version>-cuda12.9-py312`` or ``<version>-cuda13.0-py312`` tag. For example, to use cuOpt 25.5.0, you can use the ``25.5.0-cuda12.8-py312`` or ``25.5.0-cuda13.0-py312`` tag. Please refer to `cuOpt dockerhub page <https://hub.docker.com/r/nvidia/cuopt>`_ for the list of available tags.
121+
Note: The ``latest`` tag is the latest stable release of cuOpt. If you want to use a specific version, you can use the ``<version>-cuda12.9-py3.13`` or ``<version>-cuda13.0-py3.13`` tag. For example, to use cuOpt 25.10.0, you can use the ``25.10.0-cuda12.9-py3.13`` or ``25.10.0-cuda13.0-py3.13`` tag. Please refer to `cuOpt dockerhub page <https://hub.docker.com/r/nvidia/cuopt/tags>`_ for the list of available tags.
125122

126123
More information about the cuOpt container can be found [here](https://docs.nvidia.com/cuopt/user-guide/latest/cuopt-server/quick-start.html#container-from-docker-hub).
127124

@@ -143,3 +140,4 @@ Review the [CONTRIBUTING.md](CONTRIBUTING.md) file for information on how to con
143140
- [Examples and Notebooks](https://github.com/NVIDIA/cuopt-examples)
144141
- [Test cuopt with NVIDIA Launchable](https://brev.nvidia.com/launchable/deploy?launchableID=env-2qIG6yjGKDtdMSjXHcuZX12mDNJ): Examples notebooks are pulled and hosted on [NVIDIA Launchable](https://docs.nvidia.com/brev/latest/).
145142
- [Test cuopt on Google Colab](https://colab.research.google.com/github/nvidia/cuopt-examples/): Examples notebooks can be opened in Google Colab. Please note that you need to choose a `Runtime` as `GPU` in order to run the notebooks.
143+
- [cuOpt Examples and Tutorial Videos](https://docs.nvidia.com/cuopt/user-guide/latest/resources.html#cuopt-examples-and-tutorials-videos)

ci/docker/Dockerfile

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,7 @@ RUN \
6262
--extra-index-url https://pypi.anaconda.org/rapidsai-wheels-nightly/simple \
6363
--no-cache-dir \
6464
"cuopt-server-${cuda_suffix}==${CUOPT_VER}" \
65-
"cuopt-sh-client==${CUOPT_VER}" \
66-
"cuda-toolkit[cudart]==${cuda_major_minor}.*" \
67-
${nvidia_cuda_runtime_pkg} && \
65+
"cuopt-sh-client==${CUOPT_VER}" && \
6866
python -m pip list
6967

7068
# Remove gcc to save space, gcc was required for building psutils

cpp/src/linear_programming/pdlp.cu

Lines changed: 25 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -253,22 +253,14 @@ void pdlp_solver_t<i_t, f_t>::set_initial_dual_solution(
253253
initial_dual_.data(), initial_dual_solution.data(), initial_dual_solution.size(), stream_view_);
254254
}
255255

256-
static bool time_limit_reached(const std::chrono::high_resolution_clock::time_point& start_time,
257-
double seconds)
258-
{
259-
auto current_time = std::chrono::high_resolution_clock::now();
260-
auto elapsed =
261-
std::chrono::duration_cast<std::chrono::milliseconds>(current_time - start_time).count();
262-
263-
return elapsed >= (seconds * 1000.0);
264-
}
256+
static bool time_limit_reached(const timer_t& timer) { return timer.check_time_limit(); }
265257

266258
template <typename i_t, typename f_t>
267259
std::optional<optimization_problem_solution_t<i_t, f_t>> pdlp_solver_t<i_t, f_t>::check_limits(
268-
const std::chrono::high_resolution_clock::time_point& start_time)
260+
const timer_t& timer)
269261
{
270262
// Check for time limit
271-
if (time_limit_reached(start_time, settings_.time_limit)) {
263+
if (time_limit_reached(timer)) {
272264
if (settings_.save_best_primal_so_far) {
273265
#ifdef PDLP_VERBOSE_MODE
274266
RAFT_CUDA_TRY(cudaDeviceSynchronize());
@@ -491,14 +483,10 @@ pdlp_warm_start_data_t<i_t, f_t> pdlp_solver_t<i_t, f_t>::get_filled_warmed_star
491483
}
492484

493485
template <typename i_t, typename f_t>
494-
void pdlp_solver_t<i_t, f_t>::print_termination_criteria(
495-
const std::chrono::high_resolution_clock::time_point& start_time, bool is_average)
486+
void pdlp_solver_t<i_t, f_t>::print_termination_criteria(const timer_t& timer, bool is_average)
496487
{
497488
if (!inside_mip_) {
498-
const auto current_time = std::chrono::high_resolution_clock::now();
499-
const f_t elapsed =
500-
std::chrono::duration_cast<std::chrono::milliseconds>(current_time - start_time).count() /
501-
1000.0;
489+
auto elapsed = timer.elapsed_time();
502490
if (is_average) {
503491
average_termination_strategy_.print_termination_criteria(total_pdlp_iterations_, elapsed);
504492
} else {
@@ -509,13 +497,13 @@ void pdlp_solver_t<i_t, f_t>::print_termination_criteria(
509497

510498
template <typename i_t, typename f_t>
511499
void pdlp_solver_t<i_t, f_t>::print_final_termination_criteria(
512-
const std::chrono::high_resolution_clock::time_point& start_time,
500+
const timer_t& timer,
513501
const convergence_information_t<i_t, f_t>& convergence_information,
514502
const pdlp_termination_status_t& termination_status,
515503
bool is_average)
516504
{
517505
if (!inside_mip_) {
518-
print_termination_criteria(start_time, is_average);
506+
print_termination_criteria(timer, is_average);
519507
CUOPT_LOG_INFO(
520508
"LP Solver status: %s",
521509
optimization_problem_solution_t<i_t, f_t>::get_termination_status_string(termination_status)
@@ -538,7 +526,7 @@ void pdlp_solver_t<i_t, f_t>::print_final_termination_criteria(
538526

539527
template <typename i_t, typename f_t>
540528
std::optional<optimization_problem_solution_t<i_t, f_t>> pdlp_solver_t<i_t, f_t>::check_termination(
541-
const std::chrono::high_resolution_clock::time_point& start_time)
529+
const timer_t& timer)
542530
{
543531
raft::common::nvtx::range fun_scope("Check termination");
544532

@@ -580,8 +568,8 @@ std::optional<optimization_problem_solution_t<i_t, f_t>> pdlp_solver_t<i_t, f_t>
580568
// enough) We still need to check iteration and time limit prior without breaking the logic below
581569
// of first checking termination before the limit
582570
if (total_pdlp_iterations_ <= 1) {
583-
print_termination_criteria(start_time);
584-
return check_limits(start_time);
571+
print_termination_criteria(timer);
572+
return check_limits(timer);
585573
}
586574

587575
// First check for pdlp_termination_reason_t::Optimality and handle the first primal feasible case
@@ -654,9 +642,8 @@ std::optional<optimization_problem_solution_t<i_t, f_t>> pdlp_solver_t<i_t, f_t>
654642
std::cout << "Optimal. End total number of iteration current=" << internal_solver_iterations_
655643
<< std::endl;
656644
#endif
657-
print_final_termination_criteria(start_time,
658-
current_termination_strategy_.get_convergence_information(),
659-
termination_current);
645+
print_final_termination_criteria(
646+
timer, current_termination_strategy_.get_convergence_information(), termination_current);
660647
return current_termination_strategy_.fill_return_problem_solution(
661648
internal_solver_iterations_,
662649
pdhg_solver_,
@@ -669,7 +656,7 @@ std::optional<optimization_problem_solution_t<i_t, f_t>> pdlp_solver_t<i_t, f_t>
669656
std::cout << "Optimal. End total number of iteration average=" << internal_solver_iterations_
670657
<< std::endl;
671658
#endif
672-
print_final_termination_criteria(start_time,
659+
print_final_termination_criteria(timer,
673660
average_termination_strategy_.get_convergence_information(),
674661
termination_average,
675662
true);
@@ -689,7 +676,7 @@ std::optional<optimization_problem_solution_t<i_t, f_t>> pdlp_solver_t<i_t, f_t>
689676
std::cout << "Optimal. End total number of iteration average=" << internal_solver_iterations_
690677
<< std::endl;
691678
#endif
692-
print_final_termination_criteria(start_time,
679+
print_final_termination_criteria(timer,
693680
average_termination_strategy_.get_convergence_information(),
694681
termination_average,
695682
true);
@@ -707,7 +694,7 @@ std::optional<optimization_problem_solution_t<i_t, f_t>> pdlp_solver_t<i_t, f_t>
707694
<< std::endl;
708695
#endif
709696
print_final_termination_criteria(
710-
start_time, current_termination_strategy_.get_convergence_information(), termination_current);
697+
timer, current_termination_strategy_.get_convergence_information(), termination_current);
711698
return current_termination_strategy_.fill_return_problem_solution(
712699
internal_solver_iterations_,
713700
pdhg_solver_,
@@ -729,9 +716,8 @@ std::optional<optimization_problem_solution_t<i_t, f_t>> pdlp_solver_t<i_t, f_t>
729716
std::cout << "Current Infeasible. End total number of iteration current="
730717
<< internal_solver_iterations_ << std::endl;
731718
#endif
732-
print_final_termination_criteria(start_time,
733-
current_termination_strategy_.get_convergence_information(),
734-
termination_current);
719+
print_final_termination_criteria(
720+
timer, current_termination_strategy_.get_convergence_information(), termination_current);
735721
return current_termination_strategy_.fill_return_problem_solution(
736722
internal_solver_iterations_,
737723
pdhg_solver_,
@@ -745,7 +731,7 @@ std::optional<optimization_problem_solution_t<i_t, f_t>> pdlp_solver_t<i_t, f_t>
745731
std::cout << "Average Infeasible. End total number of iteration current="
746732
<< internal_solver_iterations_ << std::endl;
747733
#endif
748-
print_final_termination_criteria(start_time,
734+
print_final_termination_criteria(timer,
749735
average_termination_strategy_.get_convergence_information(),
750736
termination_average,
751737
true);
@@ -765,9 +751,8 @@ std::optional<optimization_problem_solution_t<i_t, f_t>> pdlp_solver_t<i_t, f_t>
765751
std::cout << "Infeasible. End total number of iteration current="
766752
<< internal_solver_iterations_ << std::endl;
767753
#endif
768-
print_final_termination_criteria(start_time,
769-
current_termination_strategy_.get_convergence_information(),
770-
termination_current);
754+
print_final_termination_criteria(
755+
timer, current_termination_strategy_.get_convergence_information(), termination_current);
771756
return current_termination_strategy_.fill_return_problem_solution(
772757
internal_solver_iterations_,
773758
pdhg_solver_,
@@ -785,7 +770,7 @@ std::optional<optimization_problem_solution_t<i_t, f_t>> pdlp_solver_t<i_t, f_t>
785770
<< internal_solver_iterations_ << std::endl;
786771
#endif
787772
print_final_termination_criteria(
788-
start_time, current_termination_strategy_.get_convergence_information(), termination_current);
773+
timer, current_termination_strategy_.get_convergence_information(), termination_current);
789774
return optimization_problem_solution_t<i_t, f_t>{pdlp_termination_status_t::NumericalError,
790775
stream_view_};
791776
}
@@ -797,10 +782,10 @@ std::optional<optimization_problem_solution_t<i_t, f_t>> pdlp_solver_t<i_t, f_t>
797782
average_termination_strategy_,
798783
termination_current,
799784
termination_average);
800-
if (total_pdlp_iterations_ % 1000 == 0) { print_termination_criteria(start_time); }
785+
if (total_pdlp_iterations_ % 1000 == 0) { print_termination_criteria(timer); }
801786

802787
// No reason to terminate
803-
return check_limits(start_time);
788+
return check_limits(timer);
804789
}
805790

806791
template <typename f_t>
@@ -983,8 +968,7 @@ void pdlp_solver_t<i_t, f_t>::update_primal_dual_solutions(
983968
}
984969

985970
template <typename i_t, typename f_t>
986-
optimization_problem_solution_t<i_t, f_t> pdlp_solver_t<i_t, f_t>::run_solver(
987-
const std::chrono::high_resolution_clock::time_point& start_time)
971+
optimization_problem_solution_t<i_t, f_t> pdlp_solver_t<i_t, f_t>::run_solver(const timer_t& timer)
988972
{
989973
bool verbose;
990974
#ifdef PDLP_VERBOSE_MODE
@@ -1139,8 +1123,7 @@ optimization_problem_solution_t<i_t, f_t> pdlp_solver_t<i_t, f_t>::run_solver(
11391123
pdhg_solver_.get_dual_solution());
11401124

11411125
// Check for termination
1142-
std::optional<optimization_problem_solution_t<i_t, f_t>> solution =
1143-
check_termination(start_time);
1126+
std::optional<optimization_problem_solution_t<i_t, f_t>> solution = check_termination(timer);
11441127

11451128
if (solution.has_value()) { return std::move(solution.value()); }
11461129

cpp/src/linear_programming/pdlp.cuh

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929

3030
#include <mip/problem/problem.cuh>
3131

32+
#include <utilities/timer.hpp>
33+
3234
#include <raft/core/handle.hpp>
3335

3436
#include <rmm/device_scalar.hpp>
@@ -68,8 +70,7 @@ class pdlp_solver_t {
6870
pdlp_solver_settings_t<i_t, f_t> const& settings = pdlp_solver_settings_t<i_t, f_t>{},
6971
bool is_batch_mode = false);
7072

71-
optimization_problem_solution_t<i_t, f_t> run_solver(
72-
const std::chrono::high_resolution_clock::time_point& start_time);
73+
optimization_problem_solution_t<i_t, f_t> run_solver(const timer_t& timer);
7374

7475
f_t get_primal_weight_h() const;
7576
f_t get_step_size_h() const;
@@ -99,19 +100,16 @@ class pdlp_solver_t {
99100
void set_inside_mip(bool inside_mip);
100101

101102
private:
102-
void print_termination_criteria(const std::chrono::high_resolution_clock::time_point& start_time,
103-
bool is_average = false);
103+
void print_termination_criteria(const timer_t& timer, bool is_average = false);
104104
void print_final_termination_criteria(
105-
const std::chrono::high_resolution_clock::time_point& start_time,
105+
const timer_t& timer,
106106
const convergence_information_t<i_t, f_t>& convergence_information,
107107
const pdlp_termination_status_t& termination_status,
108108
bool is_average = false);
109109
void compute_initial_step_size();
110110
void compute_initial_primal_weight();
111-
std::optional<optimization_problem_solution_t<i_t, f_t>> check_termination(
112-
const std::chrono::high_resolution_clock::time_point& start_time);
113-
std::optional<optimization_problem_solution_t<i_t, f_t>> check_limits(
114-
const std::chrono::high_resolution_clock::time_point& start_time);
111+
std::optional<optimization_problem_solution_t<i_t, f_t>> check_termination(const timer_t& timer);
112+
std::optional<optimization_problem_solution_t<i_t, f_t>> check_limits(const timer_t& timer);
115113
void record_best_primal_so_far(const detail::pdlp_termination_strategy_t<i_t, f_t>& current,
116114
const detail::pdlp_termination_strategy_t<i_t, f_t>& average,
117115
const pdlp_termination_status_t& termination_current,
@@ -212,7 +210,6 @@ class pdlp_solver_t {
212210
// Only used if save_best_primal_so_far is toggeled
213211
optimization_problem_solution_t<i_t, f_t> best_primal_solution_so_far;
214212
primal_quality_adapter_t best_primal_quality_so_far_;
215-
216213
// Flag to indicate if solver is being called from MIP. No logging is done in this case.
217214
bool inside_mip_{false};
218215
};

0 commit comments

Comments
 (0)