Skip to content

Update ReSolve linear solver interface - #2

Open
tamar-dewilde wants to merge 19 commits into
resolve-main-devfrom
tamar/update-resolve-interface
Open

Update ReSolve linear solver interface#2
tamar-dewilde wants to merge 19 commits into
resolve-main-devfrom
tamar/update-resolve-interface

Conversation

@tamar-dewilde

@tamar-dewilde tamar-dewilde commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator

Description

Updates the Ipopt ReSolve linear solver interface to use the current ReSolve API and backend configuration.

The interface supports ReSolve KLU on CPU, CUDA, and HIP builds, with GLU on CUDA and RF and RF-FGMRES on CUDA and HIP. The update also adds multiple right hand side support, checks ReSolve operations for failures, handles host and device data synchronization explicitly, and adds regression coverage for the ReSolve solver interface.

Proposed changes

  • Use the current ReSolve backend configuration from resolve_defs.hpp instead of the legacy backend macros.
  • Require CUDA or HIP when ReSolve is configured with GPU support.
  • Require matching Ipopt and ReSolve floating point and index types.
  • Build the ReSolve solver interface when ReSolve is available instead of depending on the KLU configuration guard.
  • Initialize the KLU symbolic factorization pointer.
  • Initialize and clean up the ReSolve solver, workspace, matrix, vector, preconditioner, and FGMRES objects consistently.
  • Restrict resolve_method to methods available for the configured ReSolve backend.
  • Map resolve_tol, resolve_ordering, and resolve_halt_if_singular to the corresponding ReSolve KLU settings.
  • Remove the unsupported resolve_btf and resolve_scale options.
  • Require resolve_n_skip_refactoring to be at least one because GPU refactorization setup requires KLU factors and permutations.
  • Remove the unused factor_by_t periodic factorization logic and use the refactorization transition controlled by resolve_n_skip_refactoring.
  • Remove the unused pivot tolerance change state and SYMSOLVER_CALL_AGAIN path now that IncreaseQuality does not report unsupported quality changes as successful.
  • Update ReSolve matrix setup to use borrowed Ipopt matrix storage and check matrix and vector allocation failures.
  • Mark host matrix values as updated when Ipopt provides a new matrix and synchronize them to the device for GPU solver methods.
  • Update CUDA RF setup to use the KLU factors and permutations directly through the current ReSolve interface instead of converting the factors locally.
  • Update HIP RF setup to use the current ReSolve factor, permutation, and right hand side interface.
  • Perform the initial CUDA and HIP RF numerical refactorization after setup before using the RF solver.
  • Update RF-FGMRES setup to use ReSolve::PreconditionerLU and the current preconditioner interface.
  • Rely on ReSolve FGMRES setup to initialize the Gram-Schmidt workspace instead of setting it up separately in the HIP path.
  • Check KLU analysis, factorization, refactorization, and solve status.
  • Check CUDA GLU setup, refactorization, and solve status.
  • Check CUDA and HIP RF setup, refactorization, and solve status.
  • Check FGMRES setup, matrix reset, and solve status.
  • Check ReSolve matrix and vector allocation, copy, and synchronization operations.
  • Fix CUDA RF refactorization error handling to check the returned refactorization status.
  • Support multiple right hand sides in MultiSolve for KLU, GLU, RF, and RF-FGMRES.
  • Synchronize GPU solutions to host memory before copying them back to Ipopt.
  • Preserve the reciprocal condition number refactorization behavior while reporting it through the Ipopt Journalist.
  • Replace direct console output with Ipopt Journalist output and remove unused debugging code, matrix includes, and the unused NVML helper.
  • Return false from IncreaseQuality because dynamic quality increases are not currently implemented by the ReSolve interface.
  • Add a ReSolve solver interface regression test covering factorization reuse, multiple right hand sides, matrix value updates, and supported solver methods on CPU, CUDA, and HIP builds.

Checklist

  • All tests pass (make test and make test_install). Code tested on:
    • CPU backend
    • CUDA backend
    • HIP backend
  • I have manually run the relevant examples and verified successful convergence. Code tested on:
    • CPU backend
    • CUDA backend
    • HIP backend
  • Code compiles cleanly with flags -Wall -Wpedantic -Wconversion -Wextra.
  • Regression tests were updated and run.
  • The new code is documented.
  • The ReSolve interface was tested with the current ReSolve API.
  • The feature branch is rebased with respect to the target branch.
  • I have updated CHANGELOG.md to reflect the changes in this PR.

Further comments

IncreaseQuality previously returned true without changing the ReSolve solve configuration. ReSolve provides setPivotThreshold(), but this interface does not currently define a maximum pivot tolerance or how a tolerance change should reinitialize the GPU refactorization methods. IncreaseQuality now returns false, so Ipopt falls back to its other recovery mechanisms. Should dynamic pivot tolerance updates be supported by this interface?

resolve_ordering currently exposes the KLU ordering modes, including user provided permutations. ReSolve provides setOrdering(), but its current KLU symbolic analysis does not use user provided P and Q permutations, so selecting that mode currently has no effect. Should ReSolve add support for user provided permutations, or should the ordering choices exposed by Ipopt be restricted to the modes currently supported by ReSolve?

@tamar-dewilde
tamar-dewilde requested a review from pelesh July 24, 2026 13:41
@tamar-dewilde tamar-dewilde self-assigned this Jul 24, 2026
@tamar-dewilde tamar-dewilde added the enhancement New feature or request label Jul 24, 2026
@tamar-dewilde

tamar-dewilde commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator Author

Validated against Ipopt 4778fdb and ReSolve develop at 4c325e6.

CPU

  • Ubuntu 22.04, GCC 11.4.0
  • KLU
  • ReSolve solver interface regression: passed

CUDA

  • Ubuntu 22.04, GCC 11.4.0, CUDA 12.8
  • NVIDIA RTX 2060, compute capability 7.5
  • KLU, GLU, RF, RF-FGMRES
  • ReSolve solver interface regression: passed

HIP

  • Frontier, PrgEnv-cray 8.6.0, CCE 18.0.1, ROCm 6.4.2
  • KLU, RF, RF-FGMRES
  • ReSolve solver interface regression: passed

The regression covers single and multiple right hand sides, factorization reuse, matrix value updates, and reuse after refactorization.

Full validation logs:

@tamar-dewilde

Copy link
Copy Markdown
Collaborator Author

Ipopt ReSolve Interface Review

Current status

I reviewed and updated Ipopt's ReSolve linear-solver interface against the current ReSolve API.

The original interface was written against an older version of ReSolve and no longer handled several parts of the current API correctly. The compatibility problems have now been updated, and the interface builds and runs with CPU, CUDA, and HIP.

The current implementation supports:

  • KLU on CPU
  • KLU in GPU-enabled builds
  • CUDA GLU
  • CUDA RF
  • CUDA RF with FGMRES
  • HIP RF
  • HIP RF with FGMRES
  • Multiple right-hand sides in MultiSolve()

CPU, CUDA, and HIP validation is complete for the current branch.

Files changed

The core interface changes are in:

  • src/Algorithm/LinearSolvers/IpKLUSolverInterface.cpp
  • src/Algorithm/LinearSolvers/IpReSolveSolverInterface.cpp
  • src/Algorithm/LinearSolvers/IpReSolveSolverInterface.hpp

The branch also adds a permanent ReSolve solver-interface regression test and its test-target wiring under test/.

The KLU interface change initializes the symbolic-factorization pointer so that it is not left uninitialized.

Most of the work is in the ReSolve interface.

Compatibility updates

ReSolve configuration macros

The interface now uses ReSolve's current configuration definitions:

  • RESOLVE_USE_GPU
  • RESOLVE_USE_CUDA
  • RESOLVE_USE_HIP

The previous interface used older RESOLVE_WITH_* definitions.

The header also checks that a GPU-enabled ReSolve configuration identifies either CUDA or HIP.

Type compatibility

Compile-time checks now confirm that Ipopt and ReSolve use compatible real and index types.

This prevents the interface from silently passing matrix and vector storage between libraries built with incompatible types.

Method availability

InitializeImpl() now checks whether the requested resolve_method exists in the current build.

Examples:

  • klu is available in CPU and GPU-enabled builds.
  • glu is only available with CUDA.
  • rf and rf_fgmres require GPU support.

An unavailable method now causes initialization to fail instead of reaching an uninitialized solver path later.

Initialization and ownership

The interface now initializes its solver, workspace, matrix, vector, handler, and preconditioner pointers.

The destructor deletes:

  • KLU
  • GLU when CUDA is enabled
  • RF
  • FGMRES
  • the RF preconditioner
  • Gram-Schmidt
  • matrix and vector handlers
  • CPU and GPU workspaces
  • matrix and vector objects
  • interface-owned matrix values

KLU now keeps CPU-backed handlers when resolve_method=klu. A GPU-enabled build no longer creates GPU handlers and overwrites the KLU handlers.

The interface also checks allocation and setup return values for:

  • matrix data
  • host and device vectors
  • KLU setup
  • RF setup
  • FGMRES setup
  • preconditioner attachment

Matrix storage and synchronization

Ipopt owns the CSR row and column arrays passed into the interface. The ReSolve matrix borrows those arrays, while the interface owns the numerical-value array.

When Ipopt provides updated matrix values, the interface marks the host matrix data as current before synchronizing it to the GPU.

GPU matrix and vector storage is allocated explicitly before it is used.

GPU solutions are synchronized back to host memory before they are copied into Ipopt's RHS storage.

KLU factor handling

The old interface treated KLU's extracted factors as CSC matrices and converted them back to CSR before RF setup.

Current ReSolve provides the factors through its sparse-matrix interface. The updated code now passes those factors directly into CUDA or HIP RF setup.

The interface checks that the L factor, U factor, and P and Q permutations are all available before attempting RF setup.

FGMRES integration

The old interface called the removed setupPreconditioner() API.

The current implementation now:

  1. Creates a PreconditionerLU backed by the RF solver.
  2. Attaches it with setPreconditioner().
  3. Calls setup(A_) when the RF solver is initialized.
  4. Calls resetMatrix(A_) before later FGMRES solves.
  5. Checks all returned status values.

The preconditioner is owned by the interface and deleted during destruction.

Error handling

The updated interface now returns an Ipopt solver error when the following operations fail:

  • matrix allocation or synchronization
  • vector allocation or copying
  • KLU setup, factorization, refactorization, or solve
  • GLU setup, refactorization, or solve
  • RF setup, refactorization, or solve
  • FGMRES setup, matrix reset, or solve
  • solution synchronization or copy-back

Previously, several of these failures were printed and execution continued until MultiSolve() returned success.

CUDA GLU and KLU refactorization failures now return SYMSOLVER_FATAL_ERROR instead of continuing with potentially stale factors.

Refactorization interval validation

The interface uses initial KLU solves to create the factors and permutations needed to set up GLU or RF.

Because of this, resolve_n_skip_refactoring must be at least one.

The option documentation now explains this restriction, and initialization rejects values below one.

This prevents a value of zero from skipping KLU setup and entering a GPU solve path with an uninitialized solver.

Multiple RHS support

MultiSolve() previously operated only on the first RHS even when Ipopt supplied nrhs > 1.

The updated implementation now loops over every RHS for:

  • KLU
  • CUDA GLU
  • CUDA RF
  • CUDA RF with FGMRES
  • HIP RF
  • HIP RF with FGMRES

For each RHS, the interface:

  1. Selects the correct block using rhs_vals + irhs * ndim_.
  2. Copies that RHS into ReSolve.
  3. Runs the selected solve.
  4. Synchronizes GPU results to the host when needed.
  5. Saves the solution in temporary storage.

After all solves finish, the complete solution array is copied back to Ipopt.

Temporary solution storage is necessary because RF setup, particularly the HIP setup path, may still need the original RHS data. Writing each result directly over rhs_vals could otherwise destroy input needed later in the same call.

The existing direct copy-back path remains in place when nrhs == 1.

Validation completed

CPU

The CPU build completed successfully.

The standard Ipopt test target passed:

  • C++ example
  • C example
  • Fortran example
  • EmptyNLP
  • GetCurr

The targeted KLU example reached:

EXIT: Optimal Solution Found.
f(x*) = 17.014

CUDA

The CUDA build completed successfully.

The standard Ipopt test target passed.

The following targeted ReSolve configurations all reached an optimal solution:

  • KLU
  • GLU
  • RF
  • RF with FGMRES

Each produced:

EXIT: Optimal Solution Found.
f(x*) = 17.014

Permanent ReSolve regression test

The temporary multiple-RHS validation hook has been replaced by a permanent test/resolve_multirhs.cpp regression executable that runs from the standard Ipopt test target whenever ReSolve is enabled.

For each solver method available in the configured build, the test checks:

  1. A baseline solve with nrhs=1.
  2. A solve with two distinct right-hand sides using the existing factorization.
  3. A numerical matrix-value update with the same sparsity structure and two right-hand sides.
  4. A repeated solve that reuses the updated factorization.
  5. That IncreaseQuality() returns false because dynamic quality increases are not implemented by this interface.

The methods exercised by each build are:

Build Methods
CPU KLU
CUDA KLU, GLU, RF, RF-FGMRES
HIP KLU, RF, RF-FGMRES

Option and quality handling

The remaining option and quality-control questions have been resolved:

  • resolve_n_skip_refactoring is registered with a minimum value of one because GPU refactorization setup requires KLU factors and permutations.
  • resolve_btf and resolve_scale were removed because the current ReSolve KLU interface does not support the behavior those options advertised.
  • IncreaseQuality() now returns false.
  • The unused pivtol_changed_ state and unreachable pivot-tolerance refactorization path were removed.
  • The unused periodic factor_by_t factorization path was removed in favor of the transition controlled by resolve_n_skip_refactoring.

Final platform validation

The final CPU, CUDA, and HIP validation used:

  • Ipopt commit 4778fdb007872e809e9ee074721fd9bbe5151689
  • ReSolve commit 4c325e6e4e065d73f83d7be394dbfd4f81cf4431
Build Standard Ipopt tests ReSolve regression test Result
CPU Passed Passed with KLU CPU_VALIDATION_EXIT=0
CUDA Passed Passed with KLU, GLU, RF, and RF-FGMRES CUDA_VALIDATION_EXIT=0
HIP on Frontier Passed Passed with KLU, RF, and RF-FGMRES HIP_VALIDATION_EXIT=0

The standard test runs passed the C++, C, Fortran, EmptyNLP, and GetCurr tests. The permanent ReSolve regression test also passed in all three builds.

Final cleanup completed

The final branch also:

  • checks CUDA GLU setup failures and propagates them to Ipopt;
  • performs the initial CUDA and HIP RF numerical refactorization after setup before RF or RF-FGMRES is used;
  • retains explicit host and device matrix and vector synchronization;
  • replaces direct console output with Ipopt Journalist output;
  • removes unused debugging code and interface state; and
  • compiles cleanly after the final warning cleanup.

Current assessment

The ReSolve interface update is implemented and validated across CPU, CUDA, and HIP.

The completed work covers:

  • current ReSolve configuration and solver APIs;
  • Ipopt and ReSolve type compatibility;
  • backend-specific method availability;
  • resource initialization, ownership, and cleanup;
  • KLU, GLU, RF, and RF-FGMRES setup and error propagation;
  • current KLU factor and permutation handling;
  • explicit host and device synchronization;
  • multiple-right-hand-side support;
  • matrix-value updates and repeated solver reuse; and
  • permanent regression coverage in the Ipopt test target.

The branch has been pushed, and pull request #2 is open against resolve-main-dev. No implementation or platform-validation work remains before review; the remaining work is maintainer review and any changes requested during that process.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant