2026年9月26日土曜日

HPR-LP-CがCuoptよりも速そう

 plato.asu.edu/ftp/lpfeas.html

によるとHPR-LP-Cが1位になっていました。

GitHub - PolyU-IOR/HPR-LP-C: HPR-LP-C: A C implementation of the Halpern Peaceman--Rachford (HPR) method for solving linear programming (LP) problems on GPUs. · GitHub

COPT Barrier Solverの評価ライセンスがもうすぐ終わるので、後継を考察しておきます。GPUを使うことを前提にすれば、First Order系の進歩が著しいので、可能性が出てきました。前にPDLP-CのCPU版を見たときは、使えないと判断しましたが、精度向上と速度向上により将来の可能性は高まりました。Cuoptのライブラリを使っているとWindows Portが実質的に困難ですが、その点は問題なさそうです。


<PDLP-Cとの違い>

2つをリポジトリで確認した結果をまとめます。cuPDLP-Cの実質的な後継であるcuPDLPx(MIT Lu Lab)も、比較のために並べておきます。

項目HPR-LP-CcuPDLP-C(参考)cuPDLPx
アルゴリズムHalpern Peaceman–Rachford(HPR)PDHG+適応ステップ+KKTリスタートHalpern PDHG+PID制御の重み調整
既定の精度1e-61e-4(primal / dual / gap それぞれ)1e-4程度
実行不能・非有界の判定なし(OPTIMAL / 時間制限 / 反復制限 / エラーのみ)あり(INFEASIBLE / UNBOUNDED)あり
初期解(warm start)なし公開APIにはなしあり(set_start_values)
presolveGPU-Presolver-C(folding付き)またはPSLPHiGHSのpresolvePSLP
GPUなしでの実行不可CPU版をビルドできる不可(AMD GPU / ROCmには対応)
高速化の工夫行列構造に合わせた専用SpMVカーネル、CUDA Graph、反復中の行・列の縮約cuSPARSEの標準的な呼び出しcuSPARSE / hipSPARSE
バッチ求解あり(行列Aが共通の問題群)なしなし
制約の書き方AL ≤ Ax ≤ AU(範囲制約をそのまま書ける)Ax=b と Gx≥h(範囲制約は変換が必要)l ≤ Ax ≤ u
外部依存CUDAとzlibのみHiGHS 1.6とCUDA 12.3CUDA(またはROCm)
Windows未対応(forkなどの修正が必要)_WIN32 分岐が一部にあり、比較的移しやすい未確認
開発状況活発(v0.1.3、2026年)2024年12月で更新停止活発(2026年9月まで更新)
ライセンスMITMITApache 2.0


<Windows Portの可能性>

結論から言うと、Windowsへのポートは可能で、ポート不能な箇所は見当たりませんでした。リポジトリ(main、全41コミットの履歴を含む)を確認しましたが、cuOptのライブラリは使われていません(cuopt / RAFT / RMM への参照はゼロ)。依存しているのは CUDA Toolkit 標準の cuSPARSE・cuBLAS・cuSOLVER・Thrust/CUB と、同梱の PSLP、GPU-Presolver-C、zlib、HDF5(任意)だけです。これらはすべてWindows版があります。

cuOptを使っていたら、確かに厳しいところでした。cuOptは公式にはLinux専用なので(Windowsで動かすにはWSL2経由)、ネイティブ移植の障害になっていたはずです。

ただしLinux前提の書き方をしている箇所がいくつかあり、手を入れる必要があります。

要修正(コード)

  • src/presolve/pslp_integration.cpp:いちばん大きな作業です。PSLPのpresolveを fork() と pipe() で子プロセスに隔離して実行し、waitpid で後始末しています(<unistd.h>, <sys/wait.h>)。直し方は2通りです。
    • 簡単な方法:同じプロセス内で直接呼ぶ。隔離はなくなるので、PSLPがクラッシュすると全体が落ちます。
    • 同じ挙動を保つ方法:CreateProcess と匿名パイプで作り直す。ただし fork はメモリを丸ごと引き継ぐので、Windowsでは入力モデルをシリアライズして子プロセスに渡す処理が必要になります。
  • GPU-Presolver-C/.../presolve_structs.hpp:__builtin_huge_val() がGCC拡張です。std::numeric_limits<double>::infinity() に置き換えれば済みます。
  • PSLP本体:_WIN32 分岐が最初からあるので、Timer と thread はそのまま通ります。

要修正(ビルド系)

  • CMakeLists.txt:g++-12/11 を探してホストコンパイラにし、-Xcompiler -fPIC や -D_GLIBCXX_USE_CXX11_ABI=0、-O3 -w といったGCC専用フラグを付けています。MSVC(Visual Studio)用の分岐が必要です。
  • GPUアーキテクチャの自動検出:scripts/detect_cuda_arch.sh をbashで呼んでいます。Windowsでは -DCMAKE_CUDA_ARCHITECTURES=89 のように明示的に指定するのが簡単です。
  • Makefile:Linux専用なので、CMakeだけを使います。
  • zlib / HDF5:vcpkgで入れられます。HDF5はなくてもビルドできます。

確認が必要な点

  • CUDA 13.3以上では実験的API cusparseSpMVOp が使われます。Windows版cuSPARSEにこのAPIがあるかは確認していません。もしなくても、旧来の cusparseSpMV に切り替わる仕組みがあるので、ビルドは通るはずです。
  • CUDA Graph、cuSPARSE、cuBLASなどはWindowsでも普通に動きます。
  • READMEの動作要件は「Linux x86-64」としか書かれていません。Windowsはテストされていないので、動作確認は自分でやる必要があります。

作業量の目安としては、ビルド系の修正と fork の置き換えがほとんどで、数百行程度の変更で収まると思います。まず動かしたいだけなら、WSL2上でLinux版をそのままビルドするのが一番早いです(GPUもそのまま使えます)。


0 件のコメント:

コメントを投稿