Open
Description
Inconsistent Optimization Support Across Solvers
Description
The optimization API in JavaSMT has inconsistent implementation across different solvers, leading to unpredictable behavior when applications switch between solver backends. Currently, only Z3 and MathSAT5 (via OptiMathSAT) properly support optimization capabilities, while other solvers simply throw exceptions without providing alternative functionality.
Observed Issues
Evidence in Implementation Code:
Z3 provides full implementation:
// In Z3SolverContext.java
public OptimizationProverEnvironment newOptimizationProverEnvironment0(
Set<ProverOptions> options) {
Z3SolverContext.ExtraOptions extraOptions = new Z3SolverContext.ExtraOptions(config);
return new Z3OptimizationProver(
creator,
logger,
(Z3FormulaManager) getFormulaManager(),
options,
ImmutableMap.<String, Object>builder()
.put(OPT_ENGINE_CONFIG_KEY, extraOptions.optimizationEngine)
.put(OPT_PRIORITY_CONFIG_KEY, extraOptions.objectivePrioritizationMode)
.build(),
logfile,
shutdownNotifier);
}
While other solvers throw exceptions:
// In YicesSolverContext.java
protected OptimizationProverEnvironment newOptimizationProverEnvironment0(
Set<ProverOptions> options) {
throw new UnsupportedOperationException("Yices does not support optimization");
}
// In SMTInterpolSolverContext.java
public OptimizationProverEnvironment newOptimizationProverEnvironment0(
Set<ProverOptions> options) {
throw new UnsupportedOperationException("SMTInterpol does not support optimization");
}
// In PrincessSolverContext.java
public OptimizationProverEnvironment newOptimizationProverEnvironment0(
Set<ProverOptions> pOptions) {
throw new UnsupportedOperationException("Princess does not support optimization");
}
Test Code Shows Special Handling:
Tests must skip optimization tests for most solvers:
// In OptimizationTest.java
@Before
public void skipUnsupportedSolvers() {
requireOptimization();
}
// In SolverBasedTest0.java
protected final void requireOptimization() {
try {
context.newOptimizationProverEnvironment().close();
} catch (UnsupportedOperationException e) {
assume()
.withMessage("Solver %s does not support optimization", solverToUse())
.that(e)
.isNull();
}
}
Even between supported solvers, behavior differs:
// From OptimizationTest.java - MathSAT5 specific workaround
if (solverToUse() == Solvers.MATHSAT5) {
// see https://github.com/sosy-lab/java-smt/issues/233
assume()
.withMessage("OptiMathSAT 1.7.2 has a bug with switching objectives")
.that(context.getVersion())
.doesNotContain("MathSAT5 version 1.7.2");
assume()
.withMessage("OptiMathSAT 1.7.3 has a bug with switching objectives")
.that(context.getVersion())
.doesNotContain("MathSAT5 version 1.7.3");
}
// Different precision handling between solvers
// OptiMathSAT5 has at least an epsilon of 1/1000000. It does not allow larger values.
assume()
.withMessage("Solver %s does not support large epsilons", solverToUse())
.that(solver)
.isNotEqualTo(Solvers.MATHSAT5);
Impact
- Applications using optimization features cannot easily switch between solvers
- Code must handle UnsupportedOperationExceptions and provide fallbacks
- Optimization functionality is effectively limited to Z3 in many cases
- Testing is incomplete due to varying solver capabilities