Skip to content

[FEA] cuopt-java: wrap MIP user callbacks (cuOptSetMIP{Get,Set}SolutionCallback) #1204

@rgsl888prabhu

Description

@rgsl888prabhu

Is your feature request related to a problem? Please describe.

The C API exposes user callback hooks for MIP solves:

  • cuOptSetMIPGetSolutionCallback (cpp/include/cuopt/linear_programming/cuopt_c.h:747) — invoked by the solver to deliver incumbent solutions to the user.
  • cuOptSetMIPSetSolutionCallback (cpp/include/cuopt/linear_programming/cuopt_c.h:765) — invoked by the solver to ask the user to inject a candidate solution.

Both are not yet wrapped by cuopt-java (PR #1192). They're listed in the post-merge work in temp/cuopt-java-RESUME.md.

Describe the solution you'd like

A Java API exposed via SolverSettings (or Problem) that lets the user register two callbacks:

@FunctionalInterface
public interface MIPGetSolutionCallback {
    void onSolution(double[] primal);
}

@FunctionalInterface
public interface MIPSetSolutionCallback {
    boolean provideSolution(double[] outPrimal);   // returns true if a solution was written
}

settings.setMIPGetSolutionCallback(primal -> { ... });
settings.setMIPSetSolutionCallback(out -> { populate(out); return true; });

Implementation: FFM upcall stubs created with Linker.upcallStub(...) bound to a per-solve Arena. On invocation, copy the native cuopt_float_t* buffer into a Java double[], call the user lambda, and (for Set callbacks) copy back.

Describe alternatives you've considered

  • Skip in v1 — current state. Acceptable, but customers coming from Gurobi/CPLEX expect callback hooks for warm-start injection and incumbent monitoring.
  • JNI bridge — heavier mechanism; FFM upcalls are the right tool now.

Additional context

Benchmark first. FFM upcall overhead (Java ↔ native round-trip) is non-trivial — typically reported in the 100s of nanoseconds per call. In a tight MIP B&B loop with frequent incumbents, this could dominate. Acceptance criteria:

  1. Microbenchmark a no-op upcall (empty Java callback returning immediately) under JMH. Measure round-trip cost.
  2. Compare against a representative MIP solve's incumbent-frequency profile (likely <1 callback per second in most problems, but could be hundreds per second in degenerate cases).
  3. If overhead is >100 µs per invocation OR causes >5% wall-clock regression on a representative benchmark, expose the callback behind a feature flag or refactor to batch deliveries.

Related issues:

Metadata

Metadata

Assignees

Labels

awaiting responseThis expects a response from maintainer or contributor depending on who requested in last comment.feature requestNew feature or request

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions