Skip to content

First stab at C API for PDHG primitive #168

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 7 commits into
base: branch-25.08
Choose a base branch
from

Conversation

chris-maes
Copy link
Contributor

Adds a primitive for computing iterations of PDHG

Checklist

  • I am familiar with the Contributing Guidelines.
  • Testing
    • New or existing tests cover these changes
    • Added tests
    • Created an issue to follow-up
    • NA
  • Documentation
    • The documentation is up to date with these changes
    • Added new documentation
    • NA

Copy link

copy-pr-bot bot commented Jul 1, 2025

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@anandhkb anandhkb added this to the 25.08 milestone Jul 1, 2025
@chris-maes
Copy link
Contributor Author

The test_pdhg function should produce the same primal and dual solution vectors as the following MATLAB script that performs basic PDHG on the linear program

minimize      c'*x
subject to    G * x >= h, A* x == b, l <= x <= u

This was tested on the afiro_pdhg.mps problem---it converges in roughly 15000 PDHG iterations without scaling, adaptive step size, or restarts.

function [x, y]=pdhg(c, G, h, A, b, l, u)

K = [G; A];
norm_K = normest(K);

step_size = 0.9 / norm_K;
primal_weight = 1;
primal_step_size = step_size / primal_weight;
dual_step_size = step_size * primal_weight;

fprintf('m %d n %d\n', size(K, 1), size(K, 2));
fprintf('|| K ||_2 %.12e\n', norm_K);
fprintf('step size %e\n', step_size);
fprintf('primal step size %e\n', primal_step_size);
fprintf('dual step size %e\n', dual_step_size);

iter_max = 15000;

q = [h; b];

[m, n] = size(K);

x = zeros(n, 1);
y = zeros(m, 1);

y_upper = inf(m, 1);
y_lower = -inf(m, 1);
y_lower(1:size(G, 1)) = 0;

iter = 0;
while iter < iter_max
   x_prime = project(x - primal_step_size*(c - K'*y), l, u);
   y_prime = project(y + dual_step_size*(q - K*(2.0*x_prime - x)), y_lower, y_upper);
   x = x_prime;
   y = y_prime;
   iter = iter + 1;
   if  mod(iter, 1000) == 0
    fprintf('%5d %.6f\n', iter, c'*x);
   end
end

end

function out = project(in, lower, upper)
  out = max(min(in, upper), lower);
  assert(all(out >= lower));
  assert(all(out <= upper));
end

@chris-maes chris-maes self-assigned this Jul 2, 2025
@chris-maes
Copy link
Contributor Author

You can test this PR on afiro_pdhg.mps by running the c_api.test_pdhg unit test. The output is shown below

cuopt$ ./cpp/build/tests/linear_programming/C_API_TEST --gtest_filter=*test_pdhg 
Running main() from gmock_main.cc
Note: Google Test filter = *test_pdhg
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from c_api
[ RUN      ] c_api.test_pdhg
primal_weight: 1.00e+00
norm_A_2: 6.707038384060e+00
step_size: 1.341873936697e-01
primal_step: 1.341873936697e-01
dual_step: 1.341873936697e-01
PDHG dimensions: 32 variables, 27 constraints
15000 PDHG iterations in 0.2616 seconds
After 15000 PDHG iterations
primal solution: [79.9998, 25.4995, 54.5002, 0, 44.3167, 0, 0, 0, 0, 0, 0, 0, 18.2139, 0, 0, 500, 475.92, 24.0798, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 339.943, 13.3633, 0, 0, ]
dual solution: [0.628394, 0, 0.344453, 0.228508, 0, 0, 0, 0.204174, 0.204279, 0.202488, 0.943097, 0, 0.874658, 0.342943, 0, 0, 0, 0, 0, 0, 0.087082, 0.628356, 0, 0.943162, 0, 0, 0, ]
Objective value: -464.753294
[       OK ] c_api.test_pdhg (614 ms)
[----------] 1 test from c_api (614 ms total)

[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (614 ms total)
[  PASSED  ] 1 test.

@tmckayus tmckayus modified the milestones: 25.08, 25.10 Jul 29, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants