From 2d2641870fabcf3864b2ec2123836b2978f7146d Mon Sep 17 00:00:00 2001 From: ekulos-code Date: Thu, 23 Jul 2026 14:50:10 +0200 Subject: [PATCH 1/5] Add solver characteristics based on theoretical paper concepts --- .../edu/kit/provideq/toolbox/ProblemSolverInfo.java | 12 ++++++++++-- .../edu/kit/provideq/toolbox/api/SolversRouter.java | 2 +- .../processing/solvers/MoveToExecutionSolver.java | 6 ++++++ .../processing/solvers/MoveToMitigationSolver.java | 6 ++++++ .../processing/solvers/MoveToOptimizationSolver.java | 6 ++++++ .../solvers/optimization/OptimizationSolver.java | 6 ++++++ .../anomaly/dead/SatBasedDeadFeatureSolver.java | 6 ++++++ .../anomaly/voidmodel/SatBasedVoidFeatureSolver.java | 6 ++++++ .../edu/kit/provideq/toolbox/meta/ProblemSolver.java | 9 +++++++++ .../provideq/toolbox/meta/SolverCharacteristic.java | 7 +++++++ .../toolbox/sat/solvers/QrispExactGroverSolver.java | 6 ++++++ .../provideq/toolbox/tsp/solvers/QuboTspSolver.java | 6 ++++++ .../solvers/GamsUnsplittableMcfQuboSolver.java | 6 ++++++ .../toolbox/vrp/clusterer/KmeansClusterer.java | 6 ++++++ .../toolbox/vrp/clusterer/TwoPhaseClusterer.java | 6 ++++++ .../vrp/solvers/ClusterAndSolveVrpSolver.java | 6 ++++++ 16 files changed, 99 insertions(+), 3 deletions(-) create mode 100644 src/main/java/edu/kit/provideq/toolbox/meta/SolverCharacteristic.java diff --git a/src/main/java/edu/kit/provideq/toolbox/ProblemSolverInfo.java b/src/main/java/edu/kit/provideq/toolbox/ProblemSolverInfo.java index 72f0b170..b588e2a8 100644 --- a/src/main/java/edu/kit/provideq/toolbox/ProblemSolverInfo.java +++ b/src/main/java/edu/kit/provideq/toolbox/ProblemSolverInfo.java @@ -1,5 +1,13 @@ package edu.kit.provideq.toolbox; -public record ProblemSolverInfo(String id, String name, String description) { +import edu.kit.provideq.toolbox.meta.SolverCharacteristic; +import java.util.List; -} \ No newline at end of file +public record ProblemSolverInfo( + String id, + String name, + String description, + List characteristics +) { + +} diff --git a/src/main/java/edu/kit/provideq/toolbox/api/SolversRouter.java b/src/main/java/edu/kit/provideq/toolbox/api/SolversRouter.java index 7c174b4d..36c00bd7 100644 --- a/src/main/java/edu/kit/provideq/toolbox/api/SolversRouter.java +++ b/src/main/java/edu/kit/provideq/toolbox/api/SolversRouter.java @@ -66,7 +66,7 @@ private Mono handleSolversRouteForManager(ProblemManager m private static List getAllSolverInfos(ProblemManager manager) { return manager.getSolvers().stream() .map(solver -> new ProblemSolverInfo(solver.getId(), solver.getName(), - solver.getDescription())) + solver.getDescription(), solver.getCharacteristics())) .toList(); } diff --git a/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solvers/MoveToExecutionSolver.java b/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solvers/MoveToExecutionSolver.java index 20906aa5..a00d1bb2 100644 --- a/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solvers/MoveToExecutionSolver.java +++ b/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solvers/MoveToExecutionSolver.java @@ -3,6 +3,7 @@ import edu.kit.provideq.toolbox.Solution; import edu.kit.provideq.toolbox.circuit.processing.solvers.executor.ExecutionResult; import edu.kit.provideq.toolbox.circuit.processing.solvers.executor.ExecutorConfiguration; +import edu.kit.provideq.toolbox.meta.SolverCharacteristic; import edu.kit.provideq.toolbox.meta.SolvingProperties; import edu.kit.provideq.toolbox.meta.SubRoutineDefinition; import edu.kit.provideq.toolbox.meta.SubRoutineResolver; @@ -29,6 +30,11 @@ public String getDescription() { return "Move QASM input to the executors"; } + @Override + public List getCharacteristics() { + return List.of(SolverCharacteristic.REFORMULATION); + } + @Override public List> getSubRoutines() { return List.of(EXECUTOR_SUBROUTINE); diff --git a/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solvers/MoveToMitigationSolver.java b/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solvers/MoveToMitigationSolver.java index 6e0133c9..dd86de34 100644 --- a/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solvers/MoveToMitigationSolver.java +++ b/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solvers/MoveToMitigationSolver.java @@ -2,6 +2,7 @@ import edu.kit.provideq.toolbox.Solution; import edu.kit.provideq.toolbox.circuit.processing.solvers.mitigation.ErrorMitigationConfiguration; +import edu.kit.provideq.toolbox.meta.SolverCharacteristic; import edu.kit.provideq.toolbox.meta.SolvingProperties; import edu.kit.provideq.toolbox.meta.SubRoutineDefinition; import edu.kit.provideq.toolbox.meta.SubRoutineResolver; @@ -28,6 +29,11 @@ public String getDescription() { return "Move QASM input to the error mitigators"; } + @Override + public List getCharacteristics() { + return List.of(SolverCharacteristic.REFORMULATION); + } + @Override public List> getSubRoutines() { return List.of(MITIGATOR_SUBROUTINE); diff --git a/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solvers/MoveToOptimizationSolver.java b/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solvers/MoveToOptimizationSolver.java index 235c943d..91c2c770 100644 --- a/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solvers/MoveToOptimizationSolver.java +++ b/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solvers/MoveToOptimizationSolver.java @@ -2,6 +2,7 @@ import edu.kit.provideq.toolbox.Solution; import edu.kit.provideq.toolbox.circuit.processing.solvers.optimization.OptimizationConfiguration; +import edu.kit.provideq.toolbox.meta.SolverCharacteristic; import edu.kit.provideq.toolbox.meta.SolvingProperties; import edu.kit.provideq.toolbox.meta.SubRoutineDefinition; import edu.kit.provideq.toolbox.meta.SubRoutineResolver; @@ -28,6 +29,11 @@ public String getDescription() { return "Move QASM input to the optimizers"; } + @Override + public List getCharacteristics() { + return List.of(SolverCharacteristic.REFORMULATION); + } + @Override public List> getSubRoutines() { return List.of(OPTIMIZER_SUBROUTINE); diff --git a/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solvers/optimization/OptimizationSolver.java b/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solvers/optimization/OptimizationSolver.java index 5106a296..312a418a 100644 --- a/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solvers/optimization/OptimizationSolver.java +++ b/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solvers/optimization/OptimizationSolver.java @@ -4,6 +4,7 @@ import edu.kit.provideq.toolbox.circuit.processing.solvers.CircuitProcessingSolver; import edu.kit.provideq.toolbox.meta.ProblemSolver; import edu.kit.provideq.toolbox.meta.ProblemType; +import edu.kit.provideq.toolbox.meta.SolverCharacteristic; import edu.kit.provideq.toolbox.meta.SolvingProperties; import edu.kit.provideq.toolbox.meta.SubRoutineDefinition; import edu.kit.provideq.toolbox.meta.SubRoutineResolver; @@ -57,6 +58,11 @@ public String getDescription() { + "Tket compilation passes (e.g. removing redundancies)."; } + @Override + public List getCharacteristics() { + return List.of(SolverCharacteristic.REFORMULATION); + } + @Override public List> getSubRoutines() { return List.of(CircuitProcessingSolver.CIRCUIT_PROCESSING_SUBROUTINE); diff --git a/src/main/java/edu/kit/provideq/toolbox/featuremodel/anomaly/dead/SatBasedDeadFeatureSolver.java b/src/main/java/edu/kit/provideq/toolbox/featuremodel/anomaly/dead/SatBasedDeadFeatureSolver.java index 03408b50..0fdc72f1 100644 --- a/src/main/java/edu/kit/provideq/toolbox/featuremodel/anomaly/dead/SatBasedDeadFeatureSolver.java +++ b/src/main/java/edu/kit/provideq/toolbox/featuremodel/anomaly/dead/SatBasedDeadFeatureSolver.java @@ -8,6 +8,7 @@ import edu.kit.provideq.toolbox.format.cnf.dimacs.Variable; import edu.kit.provideq.toolbox.meta.ProblemSolver; import edu.kit.provideq.toolbox.meta.ProblemType; +import edu.kit.provideq.toolbox.meta.SolverCharacteristic; import edu.kit.provideq.toolbox.meta.SolvingProperties; import edu.kit.provideq.toolbox.meta.SubRoutineDefinition; import edu.kit.provideq.toolbox.meta.SubRoutineResolver; @@ -45,6 +46,11 @@ public String getDescription() { + " It uses a SAT solver to solve each formula per feature."; } + @Override + public List getCharacteristics() { + return List.of(SolverCharacteristic.DECOMPOSITION); + } + @Override public List> getSubRoutines() { return List.of(SAT_SUBROUTINE); diff --git a/src/main/java/edu/kit/provideq/toolbox/featuremodel/anomaly/voidmodel/SatBasedVoidFeatureSolver.java b/src/main/java/edu/kit/provideq/toolbox/featuremodel/anomaly/voidmodel/SatBasedVoidFeatureSolver.java index 2e4fbc8c..3b080ea9 100644 --- a/src/main/java/edu/kit/provideq/toolbox/featuremodel/anomaly/voidmodel/SatBasedVoidFeatureSolver.java +++ b/src/main/java/edu/kit/provideq/toolbox/featuremodel/anomaly/voidmodel/SatBasedVoidFeatureSolver.java @@ -6,6 +6,7 @@ import edu.kit.provideq.toolbox.format.cnf.dimacs.DimacsCnfSolution; import edu.kit.provideq.toolbox.meta.ProblemSolver; import edu.kit.provideq.toolbox.meta.ProblemType; +import edu.kit.provideq.toolbox.meta.SolverCharacteristic; import edu.kit.provideq.toolbox.meta.SolvingProperties; import edu.kit.provideq.toolbox.meta.SubRoutineDefinition; import edu.kit.provideq.toolbox.meta.SubRoutineResolver; @@ -37,6 +38,11 @@ public String getName() { return List.of(SAT_SUBROUTINE); } + @Override + public List getCharacteristics() { + return List.of(SolverCharacteristic.REFORMULATION); + } + @Override public String getDescription() { return "This solver builds SAT formulae to determine void features in a feature model. " diff --git a/src/main/java/edu/kit/provideq/toolbox/meta/ProblemSolver.java b/src/main/java/edu/kit/provideq/toolbox/meta/ProblemSolver.java index 5fe7e803..ea1b394d 100644 --- a/src/main/java/edu/kit/provideq/toolbox/meta/ProblemSolver.java +++ b/src/main/java/edu/kit/provideq/toolbox/meta/ProblemSolver.java @@ -36,6 +36,15 @@ default String getId() { */ String getDescription(); + /** + * Return the list of characteristics for the solver. + * + * @return list of characteristics + */ + default List getCharacteristics() { + return List.of(SolverCharacteristic.SOLVE); + } + /** * Returns the sub problems used to solver this problem. * diff --git a/src/main/java/edu/kit/provideq/toolbox/meta/SolverCharacteristic.java b/src/main/java/edu/kit/provideq/toolbox/meta/SolverCharacteristic.java new file mode 100644 index 00000000..6f19e061 --- /dev/null +++ b/src/main/java/edu/kit/provideq/toolbox/meta/SolverCharacteristic.java @@ -0,0 +1,7 @@ +package edu.kit.provideq.toolbox.meta; + +public enum SolverCharacteristic { + SOLVE, + REFORMULATION, + DECOMPOSITION +} diff --git a/src/main/java/edu/kit/provideq/toolbox/sat/solvers/QrispExactGroverSolver.java b/src/main/java/edu/kit/provideq/toolbox/sat/solvers/QrispExactGroverSolver.java index 03202439..31b4567a 100644 --- a/src/main/java/edu/kit/provideq/toolbox/sat/solvers/QrispExactGroverSolver.java +++ b/src/main/java/edu/kit/provideq/toolbox/sat/solvers/QrispExactGroverSolver.java @@ -4,6 +4,7 @@ import edu.kit.provideq.toolbox.exception.ConversionException; import edu.kit.provideq.toolbox.format.cnf.dimacs.DimacsCnf; import edu.kit.provideq.toolbox.format.cnf.dimacs.DimacsCnfSolution; +import edu.kit.provideq.toolbox.meta.SolverCharacteristic; import edu.kit.provideq.toolbox.meta.SolvingProperties; import edu.kit.provideq.toolbox.meta.SubRoutineDefinition; import edu.kit.provideq.toolbox.meta.SubRoutineResolver; @@ -57,6 +58,11 @@ public String getDescription() { + "from the SharpSAT solver."; } + @Override + public List getCharacteristics() { + return List.of(SolverCharacteristic.SOLVE); + } + @Override public List> getSubRoutines() { return List.of(SHARPSAT_SUBROUTINE); diff --git a/src/main/java/edu/kit/provideq/toolbox/tsp/solvers/QuboTspSolver.java b/src/main/java/edu/kit/provideq/toolbox/tsp/solvers/QuboTspSolver.java index 548f851c..4040fd66 100644 --- a/src/main/java/edu/kit/provideq/toolbox/tsp/solvers/QuboTspSolver.java +++ b/src/main/java/edu/kit/provideq/toolbox/tsp/solvers/QuboTspSolver.java @@ -2,6 +2,7 @@ import edu.kit.provideq.toolbox.ResourceProvider; import edu.kit.provideq.toolbox.Solution; +import edu.kit.provideq.toolbox.meta.SolverCharacteristic; import edu.kit.provideq.toolbox.meta.SolvingProperties; import edu.kit.provideq.toolbox.meta.SubRoutineDefinition; import edu.kit.provideq.toolbox.meta.SubRoutineResolver; @@ -60,6 +61,11 @@ public String getDescription() { + "with a QUBO solver."; } + @Override + public List getCharacteristics() { + return List.of(SolverCharacteristic.REFORMULATION); + } + @Override public List> getSubRoutines() { return List.of(QUBO_SUBROUTINE); diff --git a/src/main/java/edu/kit/provideq/toolbox/unsplittablemcf/solvers/GamsUnsplittableMcfQuboSolver.java b/src/main/java/edu/kit/provideq/toolbox/unsplittablemcf/solvers/GamsUnsplittableMcfQuboSolver.java index f1abc5af..00ecced1 100644 --- a/src/main/java/edu/kit/provideq/toolbox/unsplittablemcf/solvers/GamsUnsplittableMcfQuboSolver.java +++ b/src/main/java/edu/kit/provideq/toolbox/unsplittablemcf/solvers/GamsUnsplittableMcfQuboSolver.java @@ -1,6 +1,7 @@ package edu.kit.provideq.toolbox.unsplittablemcf.solvers; import edu.kit.provideq.toolbox.Solution; +import edu.kit.provideq.toolbox.meta.SolverCharacteristic; import edu.kit.provideq.toolbox.meta.SolvingProperties; import edu.kit.provideq.toolbox.meta.SubRoutineDefinition; import edu.kit.provideq.toolbox.meta.SubRoutineResolver; @@ -57,6 +58,11 @@ public String getDescription() { + "QUBO problem and solving with a QUBO solver."; } + @Override + public List getCharacteristics() { + return List.of(SolverCharacteristic.REFORMULATION); + } + @Override public List> getSubRoutines() { return List.of(QUBO_SUBROUTINE); diff --git a/src/main/java/edu/kit/provideq/toolbox/vrp/clusterer/KmeansClusterer.java b/src/main/java/edu/kit/provideq/toolbox/vrp/clusterer/KmeansClusterer.java index feb944f8..68cb83b4 100644 --- a/src/main/java/edu/kit/provideq/toolbox/vrp/clusterer/KmeansClusterer.java +++ b/src/main/java/edu/kit/provideq/toolbox/vrp/clusterer/KmeansClusterer.java @@ -2,6 +2,7 @@ import edu.kit.provideq.toolbox.Solution; +import edu.kit.provideq.toolbox.meta.SolverCharacteristic; import edu.kit.provideq.toolbox.meta.SolvingProperties; import edu.kit.provideq.toolbox.meta.SubRoutineDefinition; import edu.kit.provideq.toolbox.meta.SubRoutineResolver; @@ -50,6 +51,11 @@ public String getDescription() { return "Clusters a VRP problem into a set of VRP problems using k-means clustering."; } + @Override + public List getCharacteristics() { + return List.of(SolverCharacteristic.DECOMPOSITION); + } + @Override public List> getSubRoutines() { return List.of(VRP_SUBROUTINE); diff --git a/src/main/java/edu/kit/provideq/toolbox/vrp/clusterer/TwoPhaseClusterer.java b/src/main/java/edu/kit/provideq/toolbox/vrp/clusterer/TwoPhaseClusterer.java index 86581db2..a53f6d71 100644 --- a/src/main/java/edu/kit/provideq/toolbox/vrp/clusterer/TwoPhaseClusterer.java +++ b/src/main/java/edu/kit/provideq/toolbox/vrp/clusterer/TwoPhaseClusterer.java @@ -1,6 +1,7 @@ package edu.kit.provideq.toolbox.vrp.clusterer; import edu.kit.provideq.toolbox.Solution; +import edu.kit.provideq.toolbox.meta.SolverCharacteristic; import edu.kit.provideq.toolbox.meta.SolvingProperties; import edu.kit.provideq.toolbox.meta.SubRoutineDefinition; import edu.kit.provideq.toolbox.meta.SubRoutineResolver; @@ -32,6 +33,11 @@ public TwoPhaseClusterer( super(binaryPath, context); } + @Override + public List getCharacteristics() { + return List.of(SolverCharacteristic.DECOMPOSITION); + } + @Override public List> getSubRoutines() { return List.of(TSP_SUBROUTINE); diff --git a/src/main/java/edu/kit/provideq/toolbox/vrp/solvers/ClusterAndSolveVrpSolver.java b/src/main/java/edu/kit/provideq/toolbox/vrp/solvers/ClusterAndSolveVrpSolver.java index 9b35fdb2..b9a71a25 100644 --- a/src/main/java/edu/kit/provideq/toolbox/vrp/solvers/ClusterAndSolveVrpSolver.java +++ b/src/main/java/edu/kit/provideq/toolbox/vrp/solvers/ClusterAndSolveVrpSolver.java @@ -1,6 +1,7 @@ package edu.kit.provideq.toolbox.vrp.solvers; import edu.kit.provideq.toolbox.Solution; +import edu.kit.provideq.toolbox.meta.SolverCharacteristic; import edu.kit.provideq.toolbox.meta.SolvingProperties; import edu.kit.provideq.toolbox.meta.SubRoutineDefinition; import edu.kit.provideq.toolbox.meta.SubRoutineResolver; @@ -29,6 +30,11 @@ public String getDescription() { + "first."; } + @Override + public List getCharacteristics() { + return List.of(SolverCharacteristic.REFORMULATION); + } + @Override public List> getSubRoutines() { return List.of(CLUSTER_SUBROUTINE); From 2890b45d164c598afb5d4df6d3f72680411f3aaa Mon Sep 17 00:00:00 2001 From: ekulos-code Date: Wed, 5 Aug 2026 11:21:32 +0200 Subject: [PATCH 2/5] Add preliminary attributes for each solver --- .../provideq/toolbox/ProblemSolverInfo.java | 5 +-- .../solvers/MoveToExecutionSolver.java | 7 ++-- .../solvers/MoveToMitigationSolver.java | 7 ++-- .../solvers/MoveToOptimizationSolver.java | 7 ++-- .../solvers/executor/ExecutionSolver.java | 9 ++++ .../optimization/OptimizationSolver.java | 11 +++-- .../dead/SatBasedDeadFeatureSolver.java | 19 +++++---- .../voidmodel/SatBasedVoidFeatureSolver.java | 14 ++++--- .../solvers/PythonKnapsackSolver.java | 8 ++++ .../maxcut/solvers/GamsMaxCutSolver.java | 8 ++++ .../provideq/toolbox/meta/ProblemSolver.java | 4 +- .../provideq/toolbox/meta/RuleProperty.java | 28 +++++++++++++ ...olverCharacteristic.java => RuleType.java} | 5 ++- .../toolbox/meta/SolverCharacteristics.java | 41 +++++++++++++++++++ .../toolbox/qubo/solvers/DwaveQuboSolver.java | 8 ++++ .../toolbox/qubo/solvers/GamsQuboSolver.java | 8 ++++ .../qubo/solvers/QiskitQuboSolver.java | 8 ++++ .../toolbox/qubo/solvers/QrispQuboSolver.java | 8 ++++ .../qubo/solvers/QuantagoniaQuboSolver.java | 8 ++++ .../toolbox/sat/solvers/GamsSatSolver.java | 8 ++++ .../sat/solvers/QrispExactGroverSolver.java | 8 ++-- .../solvers/PythonBruteForceSolver.java | 8 ++++ .../toolbox/tsp/solvers/LkhTspSolver.java | 8 ++++ .../toolbox/tsp/solvers/QuboTspSolver.java | 11 +++-- .../GamsUnsplittableMcfClassicalSolver.java | 8 ++++ .../GamsUnsplittableMcfQuboSolver.java | 11 +++-- .../vrp/clusterer/KmeansClusterer.java | 10 +++-- .../vrp/clusterer/TwoPhaseClusterer.java | 10 +++-- .../vrp/solvers/ClusterAndSolveVrpSolver.java | 7 ++-- 29 files changed, 252 insertions(+), 50 deletions(-) create mode 100644 src/main/java/edu/kit/provideq/toolbox/meta/RuleProperty.java rename src/main/java/edu/kit/provideq/toolbox/meta/{SolverCharacteristic.java => RuleType.java} (56%) create mode 100644 src/main/java/edu/kit/provideq/toolbox/meta/SolverCharacteristics.java diff --git a/src/main/java/edu/kit/provideq/toolbox/ProblemSolverInfo.java b/src/main/java/edu/kit/provideq/toolbox/ProblemSolverInfo.java index b588e2a8..fed2454c 100644 --- a/src/main/java/edu/kit/provideq/toolbox/ProblemSolverInfo.java +++ b/src/main/java/edu/kit/provideq/toolbox/ProblemSolverInfo.java @@ -1,13 +1,12 @@ package edu.kit.provideq.toolbox; -import edu.kit.provideq.toolbox.meta.SolverCharacteristic; -import java.util.List; +import edu.kit.provideq.toolbox.meta.SolverCharacteristics; public record ProblemSolverInfo( String id, String name, String description, - List characteristics + SolverCharacteristics characteristics ) { } diff --git a/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solvers/MoveToExecutionSolver.java b/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solvers/MoveToExecutionSolver.java index a00d1bb2..bf99aef0 100644 --- a/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solvers/MoveToExecutionSolver.java +++ b/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solvers/MoveToExecutionSolver.java @@ -3,7 +3,8 @@ import edu.kit.provideq.toolbox.Solution; import edu.kit.provideq.toolbox.circuit.processing.solvers.executor.ExecutionResult; import edu.kit.provideq.toolbox.circuit.processing.solvers.executor.ExecutorConfiguration; -import edu.kit.provideq.toolbox.meta.SolverCharacteristic; +import edu.kit.provideq.toolbox.meta.RuleType; +import edu.kit.provideq.toolbox.meta.SolverCharacteristics; import edu.kit.provideq.toolbox.meta.SolvingProperties; import edu.kit.provideq.toolbox.meta.SubRoutineDefinition; import edu.kit.provideq.toolbox.meta.SubRoutineResolver; @@ -31,8 +32,8 @@ public String getDescription() { } @Override - public List getCharacteristics() { - return List.of(SolverCharacteristic.REFORMULATION); + public SolverCharacteristics getCharacteristics() { + return SolverCharacteristics.of(RuleType.DELEGATION); } @Override diff --git a/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solvers/MoveToMitigationSolver.java b/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solvers/MoveToMitigationSolver.java index dd86de34..d91a0522 100644 --- a/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solvers/MoveToMitigationSolver.java +++ b/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solvers/MoveToMitigationSolver.java @@ -2,7 +2,8 @@ import edu.kit.provideq.toolbox.Solution; import edu.kit.provideq.toolbox.circuit.processing.solvers.mitigation.ErrorMitigationConfiguration; -import edu.kit.provideq.toolbox.meta.SolverCharacteristic; +import edu.kit.provideq.toolbox.meta.RuleType; +import edu.kit.provideq.toolbox.meta.SolverCharacteristics; import edu.kit.provideq.toolbox.meta.SolvingProperties; import edu.kit.provideq.toolbox.meta.SubRoutineDefinition; import edu.kit.provideq.toolbox.meta.SubRoutineResolver; @@ -30,8 +31,8 @@ public String getDescription() { } @Override - public List getCharacteristics() { - return List.of(SolverCharacteristic.REFORMULATION); + public SolverCharacteristics getCharacteristics() { + return SolverCharacteristics.of(RuleType.DELEGATION); } @Override diff --git a/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solvers/MoveToOptimizationSolver.java b/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solvers/MoveToOptimizationSolver.java index 91c2c770..c9e4a4f3 100644 --- a/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solvers/MoveToOptimizationSolver.java +++ b/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solvers/MoveToOptimizationSolver.java @@ -2,7 +2,8 @@ import edu.kit.provideq.toolbox.Solution; import edu.kit.provideq.toolbox.circuit.processing.solvers.optimization.OptimizationConfiguration; -import edu.kit.provideq.toolbox.meta.SolverCharacteristic; +import edu.kit.provideq.toolbox.meta.RuleType; +import edu.kit.provideq.toolbox.meta.SolverCharacteristics; import edu.kit.provideq.toolbox.meta.SolvingProperties; import edu.kit.provideq.toolbox.meta.SubRoutineDefinition; import edu.kit.provideq.toolbox.meta.SubRoutineResolver; @@ -30,8 +31,8 @@ public String getDescription() { } @Override - public List getCharacteristics() { - return List.of(SolverCharacteristic.REFORMULATION); + public SolverCharacteristics getCharacteristics() { + return SolverCharacteristics.of(RuleType.DELEGATION); } @Override diff --git a/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solvers/executor/ExecutionSolver.java b/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solvers/executor/ExecutionSolver.java index 894c776d..98814a4b 100644 --- a/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solvers/executor/ExecutionSolver.java +++ b/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solvers/executor/ExecutionSolver.java @@ -3,6 +3,9 @@ import edu.kit.provideq.toolbox.Solution; import edu.kit.provideq.toolbox.meta.ProblemSolver; import edu.kit.provideq.toolbox.meta.ProblemType; +import edu.kit.provideq.toolbox.meta.RuleProperty; +import edu.kit.provideq.toolbox.meta.RuleType; +import edu.kit.provideq.toolbox.meta.SolverCharacteristics; import edu.kit.provideq.toolbox.meta.SolvingProperties; import edu.kit.provideq.toolbox.meta.SubRoutineResolver; import edu.kit.provideq.toolbox.meta.setting.SolverSetting; @@ -50,6 +53,12 @@ public String getDescription() { return "Execute an OpenQASM circuit"; } + @Override + public SolverCharacteristics getCharacteristics() { + // TODO: valid only holds true for noise free simulation, add additional executor, splitting noisy and noise free + return SolverCharacteristics.of(RuleType.SOLVE, RuleProperty.VALID); + } + @Override public List getSolverSettings() { return List.of( diff --git a/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solvers/optimization/OptimizationSolver.java b/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solvers/optimization/OptimizationSolver.java index 312a418a..d9ecafd0 100644 --- a/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solvers/optimization/OptimizationSolver.java +++ b/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solvers/optimization/OptimizationSolver.java @@ -4,7 +4,9 @@ import edu.kit.provideq.toolbox.circuit.processing.solvers.CircuitProcessingSolver; import edu.kit.provideq.toolbox.meta.ProblemSolver; import edu.kit.provideq.toolbox.meta.ProblemType; -import edu.kit.provideq.toolbox.meta.SolverCharacteristic; +import edu.kit.provideq.toolbox.meta.RuleProperty; +import edu.kit.provideq.toolbox.meta.RuleType; +import edu.kit.provideq.toolbox.meta.SolverCharacteristics; import edu.kit.provideq.toolbox.meta.SolvingProperties; import edu.kit.provideq.toolbox.meta.SubRoutineDefinition; import edu.kit.provideq.toolbox.meta.SubRoutineResolver; @@ -54,13 +56,14 @@ public String getName() { @Override public String getDescription() { - return "Transform the given circuit into an optimized but equivalent circuit using" + return "Transform the given circuit into an optimized but equivalent circuit using " + "Tket compilation passes (e.g. removing redundancies)."; } @Override - public List getCharacteristics() { - return List.of(SolverCharacteristic.REFORMULATION); + public SolverCharacteristics getCharacteristics() { + return SolverCharacteristics.of(RuleType.REFORMULATION, RuleProperty.STRONGLY_CONSTRAINT_PRESERVING, + RuleProperty.OPTIMAL_SOLUTION_PRESERVING); } @Override diff --git a/src/main/java/edu/kit/provideq/toolbox/featuremodel/anomaly/dead/SatBasedDeadFeatureSolver.java b/src/main/java/edu/kit/provideq/toolbox/featuremodel/anomaly/dead/SatBasedDeadFeatureSolver.java index 0fdc72f1..8e67334b 100644 --- a/src/main/java/edu/kit/provideq/toolbox/featuremodel/anomaly/dead/SatBasedDeadFeatureSolver.java +++ b/src/main/java/edu/kit/provideq/toolbox/featuremodel/anomaly/dead/SatBasedDeadFeatureSolver.java @@ -8,19 +8,22 @@ import edu.kit.provideq.toolbox.format.cnf.dimacs.Variable; import edu.kit.provideq.toolbox.meta.ProblemSolver; import edu.kit.provideq.toolbox.meta.ProblemType; -import edu.kit.provideq.toolbox.meta.SolverCharacteristic; +import edu.kit.provideq.toolbox.meta.RuleProperty; +import edu.kit.provideq.toolbox.meta.RuleType; +import edu.kit.provideq.toolbox.meta.SolverCharacteristics; import edu.kit.provideq.toolbox.meta.SolvingProperties; import edu.kit.provideq.toolbox.meta.SubRoutineDefinition; import edu.kit.provideq.toolbox.meta.SubRoutineResolver; import edu.kit.provideq.toolbox.sat.SatConfiguration; -import java.util.ArrayList; -import java.util.List; import org.springframework.stereotype.Component; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.util.function.Tuple2; import reactor.util.function.Tuples; +import java.util.ArrayList; +import java.util.List; + /** * This problem solver solves the {@link DeadFeatureConfiguration#FEATURE_MODEL_ANOMALY_DEAD} * problem by building {@link SatConfiguration#SAT} formulae that are solved by a corresponding @@ -47,8 +50,10 @@ public String getDescription() { } @Override - public List getCharacteristics() { - return List.of(SolverCharacteristic.DECOMPOSITION); + public SolverCharacteristics getCharacteristics() { + return SolverCharacteristics.of( + RuleType.DECOMPOSITION, RuleProperty.STRONGLY_CONSTRAINT_PRESERVING, + RuleProperty.OPTIMAL_SOLUTION_PRESERVING); } @Override @@ -98,7 +103,7 @@ private Mono> checkDeadFeatures( return Flux.fromIterable(dimacsCnf.getVariables()) .flatMap(feature -> checkFeatureDead(dimacsCnf, feature, subRoutineResolver) - .map(isVoid -> Tuples.of(feature, isVoid))) + .map(isVoid -> Tuples.of(feature, isVoid))) .collectMap(Tuple2::getT1, Tuple2::getT2) .map(featureIsVoidMap -> { var stringBuilder = new StringBuilder(); @@ -129,7 +134,7 @@ private Mono> checkDeadFeatures( * * @param subRoutineResolver used to evaluate a SAT formula for the check. * @return the solution of the given {@code feature}. - * Use {@link DimacsCnfSolution#isVoid()} to check the feature. + * Use {@link DimacsCnfSolution#isVoid()} to check the feature. */ private static Mono checkFeatureDead( DimacsCnf cnf, diff --git a/src/main/java/edu/kit/provideq/toolbox/featuremodel/anomaly/voidmodel/SatBasedVoidFeatureSolver.java b/src/main/java/edu/kit/provideq/toolbox/featuremodel/anomaly/voidmodel/SatBasedVoidFeatureSolver.java index 3b080ea9..b9f5e418 100644 --- a/src/main/java/edu/kit/provideq/toolbox/featuremodel/anomaly/voidmodel/SatBasedVoidFeatureSolver.java +++ b/src/main/java/edu/kit/provideq/toolbox/featuremodel/anomaly/voidmodel/SatBasedVoidFeatureSolver.java @@ -6,15 +6,18 @@ import edu.kit.provideq.toolbox.format.cnf.dimacs.DimacsCnfSolution; import edu.kit.provideq.toolbox.meta.ProblemSolver; import edu.kit.provideq.toolbox.meta.ProblemType; -import edu.kit.provideq.toolbox.meta.SolverCharacteristic; +import edu.kit.provideq.toolbox.meta.RuleProperty; +import edu.kit.provideq.toolbox.meta.RuleType; +import edu.kit.provideq.toolbox.meta.SolverCharacteristics; import edu.kit.provideq.toolbox.meta.SolvingProperties; import edu.kit.provideq.toolbox.meta.SubRoutineDefinition; import edu.kit.provideq.toolbox.meta.SubRoutineResolver; import edu.kit.provideq.toolbox.sat.SatConfiguration; -import java.util.List; import org.springframework.stereotype.Component; import reactor.core.publisher.Mono; +import java.util.List; + /** * This problem solver solves the {@link VoidModelConfiguration#FEATURE_MODEL_ANOMALY_VOID} problem * by building {@link SatConfiguration#SAT} formula that is solved by a corresponding solver. @@ -39,8 +42,9 @@ public String getName() { } @Override - public List getCharacteristics() { - return List.of(SolverCharacteristic.REFORMULATION); + public SolverCharacteristics getCharacteristics() { + return SolverCharacteristics.of(RuleType.REFORMULATION, RuleProperty.STRONGLY_CONSTRAINT_PRESERVING, + RuleProperty.OPTIMAL_SOLUTION_PRESERVING); } @Override @@ -90,7 +94,7 @@ private Mono> checkVoidFeatureModel( solution.setSolutionData(dimacsCnfSolution.isVoid() ? "The feature model is a void feature model. The configuration is never valid." : "The feature model has valid configurations, for example: \n" - + dimacsCnfSolution.toHumanReadableString()); + + dimacsCnfSolution.toHumanReadableString()); solution.complete(); return solution; diff --git a/src/main/java/edu/kit/provideq/toolbox/knapsack/solvers/PythonKnapsackSolver.java b/src/main/java/edu/kit/provideq/toolbox/knapsack/solvers/PythonKnapsackSolver.java index 20905e36..a6f396a7 100644 --- a/src/main/java/edu/kit/provideq/toolbox/knapsack/solvers/PythonKnapsackSolver.java +++ b/src/main/java/edu/kit/provideq/toolbox/knapsack/solvers/PythonKnapsackSolver.java @@ -2,6 +2,9 @@ import edu.kit.provideq.toolbox.Solution; import edu.kit.provideq.toolbox.knapsack.KnapsackConfiguration; +import edu.kit.provideq.toolbox.meta.RuleProperty; +import edu.kit.provideq.toolbox.meta.RuleType; +import edu.kit.provideq.toolbox.meta.SolverCharacteristics; import edu.kit.provideq.toolbox.meta.SolvingProperties; import edu.kit.provideq.toolbox.meta.SubRoutineResolver; import edu.kit.provideq.toolbox.process.ProcessRunner; @@ -42,6 +45,11 @@ public String getDescription() { + "branch and search algorithm."; } + @Override + public SolverCharacteristics getCharacteristics() { + return SolverCharacteristics.of(RuleType.SOLVE, RuleProperty.EXACT, RuleProperty.VALID); + } + @Override public Mono> solve( String input, diff --git a/src/main/java/edu/kit/provideq/toolbox/maxcut/solvers/GamsMaxCutSolver.java b/src/main/java/edu/kit/provideq/toolbox/maxcut/solvers/GamsMaxCutSolver.java index 0726eac2..91efb151 100644 --- a/src/main/java/edu/kit/provideq/toolbox/maxcut/solvers/GamsMaxCutSolver.java +++ b/src/main/java/edu/kit/provideq/toolbox/maxcut/solvers/GamsMaxCutSolver.java @@ -2,6 +2,9 @@ import edu.kit.provideq.toolbox.Solution; import edu.kit.provideq.toolbox.maxcut.MaxCutConfiguration; +import edu.kit.provideq.toolbox.meta.RuleProperty; +import edu.kit.provideq.toolbox.meta.RuleType; +import edu.kit.provideq.toolbox.meta.SolverCharacteristics; import edu.kit.provideq.toolbox.meta.SolvingProperties; import edu.kit.provideq.toolbox.meta.SubRoutineResolver; import edu.kit.provideq.toolbox.process.GamsProcessRunner; @@ -39,6 +42,11 @@ public String getDescription() { + " starting point for the QUBO algorithm."; } + @Override + public SolverCharacteristics getCharacteristics() { + return SolverCharacteristics.of(RuleType.SOLVE, RuleProperty.VALID); + } + @Override public Mono> solve( String input, diff --git a/src/main/java/edu/kit/provideq/toolbox/meta/ProblemSolver.java b/src/main/java/edu/kit/provideq/toolbox/meta/ProblemSolver.java index ea1b394d..6e0c0984 100644 --- a/src/main/java/edu/kit/provideq/toolbox/meta/ProblemSolver.java +++ b/src/main/java/edu/kit/provideq/toolbox/meta/ProblemSolver.java @@ -41,8 +41,8 @@ default String getId() { * * @return list of characteristics */ - default List getCharacteristics() { - return List.of(SolverCharacteristic.SOLVE); + default SolverCharacteristics getCharacteristics() { + return SolverCharacteristics.of(RuleType.SOLVE); } /** diff --git a/src/main/java/edu/kit/provideq/toolbox/meta/RuleProperty.java b/src/main/java/edu/kit/provideq/toolbox/meta/RuleProperty.java new file mode 100644 index 00000000..99762bd4 --- /dev/null +++ b/src/main/java/edu/kit/provideq/toolbox/meta/RuleProperty.java @@ -0,0 +1,28 @@ +package edu.kit.provideq.toolbox.meta; + +import java.util.Set; + +public enum RuleProperty { + EXACT(RuleType.SOLVE), + VALID(RuleType.SOLVE), + STRONGLY_CONSTRAINT_PRESERVING( + RuleType.REFORMULATION, RuleType.DECOMPOSITION, RuleType.DELEGATION), + WEAKLY_CONSTRAINT_PRESERVING( + RuleType.REFORMULATION, RuleType.DECOMPOSITION, RuleType.DELEGATION), + OPTIMAL_SOLUTION_PRESERVING( + RuleType.REFORMULATION, RuleType.DECOMPOSITION, RuleType.DELEGATION); + + private final Set applicableTo; + + RuleProperty(RuleType... applicableTo) { + this.applicableTo = Set.of(applicableTo); + } + + public Set getApplicableTo() { + return applicableTo; + } + + public boolean isApplicableTo(RuleType ruleType) { + return applicableTo.contains(ruleType); + } +} diff --git a/src/main/java/edu/kit/provideq/toolbox/meta/SolverCharacteristic.java b/src/main/java/edu/kit/provideq/toolbox/meta/RuleType.java similarity index 56% rename from src/main/java/edu/kit/provideq/toolbox/meta/SolverCharacteristic.java rename to src/main/java/edu/kit/provideq/toolbox/meta/RuleType.java index 6f19e061..98494c31 100644 --- a/src/main/java/edu/kit/provideq/toolbox/meta/SolverCharacteristic.java +++ b/src/main/java/edu/kit/provideq/toolbox/meta/RuleType.java @@ -1,7 +1,8 @@ package edu.kit.provideq.toolbox.meta; -public enum SolverCharacteristic { +public enum RuleType { SOLVE, REFORMULATION, - DECOMPOSITION + DECOMPOSITION, + DELEGATION } diff --git a/src/main/java/edu/kit/provideq/toolbox/meta/SolverCharacteristics.java b/src/main/java/edu/kit/provideq/toolbox/meta/SolverCharacteristics.java new file mode 100644 index 00000000..894f9501 --- /dev/null +++ b/src/main/java/edu/kit/provideq/toolbox/meta/SolverCharacteristics.java @@ -0,0 +1,41 @@ +package edu.kit.provideq.toolbox.meta; + +import java.util.Collection; +import java.util.Collections; +import java.util.EnumSet; +import java.util.Set; + +public record SolverCharacteristics( + Set types, + Set properties +) { + public SolverCharacteristics { + if (types == null || types.isEmpty()) { + throw new IllegalArgumentException("A solver must declare at least one rule type"); + } + + types = immutableCopy(types, RuleType.class); + properties = immutableCopy(properties, RuleProperty.class); + + for (var property : properties) { + if (types.stream().noneMatch(property::isApplicableTo)) { + throw new IllegalArgumentException( + "Property " + property + " not defined for rule types " + types + + ", only applies to " + property.getApplicableTo()); + } + } + } + + public static SolverCharacteristics of(RuleType type, RuleProperty... properties) { + return new SolverCharacteristics(Set.of(type), Set.of(properties)); + } + + private static > Set immutableCopy( + Collection values, Class enumClass) { + var copy = EnumSet.noneOf(enumClass); + if (values != null) { + copy.addAll(values); + } + return Collections.unmodifiableSet(copy); + } +} diff --git a/src/main/java/edu/kit/provideq/toolbox/qubo/solvers/DwaveQuboSolver.java b/src/main/java/edu/kit/provideq/toolbox/qubo/solvers/DwaveQuboSolver.java index dc445dd0..20d72fe8 100644 --- a/src/main/java/edu/kit/provideq/toolbox/qubo/solvers/DwaveQuboSolver.java +++ b/src/main/java/edu/kit/provideq/toolbox/qubo/solvers/DwaveQuboSolver.java @@ -1,6 +1,9 @@ package edu.kit.provideq.toolbox.qubo.solvers; import edu.kit.provideq.toolbox.Solution; +import edu.kit.provideq.toolbox.meta.RuleProperty; +import edu.kit.provideq.toolbox.meta.RuleType; +import edu.kit.provideq.toolbox.meta.SolverCharacteristics; import edu.kit.provideq.toolbox.meta.SolvingProperties; import edu.kit.provideq.toolbox.meta.SubRoutineResolver; import edu.kit.provideq.toolbox.meta.setting.SolverSetting; @@ -76,6 +79,11 @@ public String getDescription() { return "Solves the QUBO problem using a D-Wave Quantum Annealer."; } + @Override + public SolverCharacteristics getCharacteristics() { + return SolverCharacteristics.of(RuleType.SOLVE, RuleProperty.VALID); + } + @Override public List getSolverSettings() { return List.of( diff --git a/src/main/java/edu/kit/provideq/toolbox/qubo/solvers/GamsQuboSolver.java b/src/main/java/edu/kit/provideq/toolbox/qubo/solvers/GamsQuboSolver.java index 960195df..179d23f9 100644 --- a/src/main/java/edu/kit/provideq/toolbox/qubo/solvers/GamsQuboSolver.java +++ b/src/main/java/edu/kit/provideq/toolbox/qubo/solvers/GamsQuboSolver.java @@ -1,6 +1,9 @@ package edu.kit.provideq.toolbox.qubo.solvers; import edu.kit.provideq.toolbox.Solution; +import edu.kit.provideq.toolbox.meta.RuleProperty; +import edu.kit.provideq.toolbox.meta.RuleType; +import edu.kit.provideq.toolbox.meta.SolverCharacteristics; import edu.kit.provideq.toolbox.meta.SolvingProperties; import edu.kit.provideq.toolbox.meta.SubRoutineResolver; import edu.kit.provideq.toolbox.process.ProcessRunner; @@ -42,6 +45,11 @@ public String getDescription() { + "which is then solved with CPLEX. Implementation is done in GAMS"; } + @Override + public SolverCharacteristics getCharacteristics() { + return SolverCharacteristics.of(RuleType.SOLVE, RuleProperty.VALID); + } + @Override public Mono> solve( String input, diff --git a/src/main/java/edu/kit/provideq/toolbox/qubo/solvers/QiskitQuboSolver.java b/src/main/java/edu/kit/provideq/toolbox/qubo/solvers/QiskitQuboSolver.java index 78858b3d..547c8c08 100644 --- a/src/main/java/edu/kit/provideq/toolbox/qubo/solvers/QiskitQuboSolver.java +++ b/src/main/java/edu/kit/provideq/toolbox/qubo/solvers/QiskitQuboSolver.java @@ -1,6 +1,9 @@ package edu.kit.provideq.toolbox.qubo.solvers; import edu.kit.provideq.toolbox.Solution; +import edu.kit.provideq.toolbox.meta.RuleProperty; +import edu.kit.provideq.toolbox.meta.RuleType; +import edu.kit.provideq.toolbox.meta.SolverCharacteristics; import edu.kit.provideq.toolbox.meta.SolvingProperties; import edu.kit.provideq.toolbox.meta.SubRoutineResolver; import edu.kit.provideq.toolbox.process.ProcessRunner; @@ -41,6 +44,11 @@ public String getDescription() { return "Solves QUBOs using the Qiskit QAOA implementation."; } + @Override + public SolverCharacteristics getCharacteristics() { + return SolverCharacteristics.of(RuleType.SOLVE, RuleProperty.VALID); + } + @Override public Mono> solve( String input, diff --git a/src/main/java/edu/kit/provideq/toolbox/qubo/solvers/QrispQuboSolver.java b/src/main/java/edu/kit/provideq/toolbox/qubo/solvers/QrispQuboSolver.java index f4e8ef16..1b83ec20 100644 --- a/src/main/java/edu/kit/provideq/toolbox/qubo/solvers/QrispQuboSolver.java +++ b/src/main/java/edu/kit/provideq/toolbox/qubo/solvers/QrispQuboSolver.java @@ -1,6 +1,9 @@ package edu.kit.provideq.toolbox.qubo.solvers; import edu.kit.provideq.toolbox.Solution; +import edu.kit.provideq.toolbox.meta.RuleProperty; +import edu.kit.provideq.toolbox.meta.RuleType; +import edu.kit.provideq.toolbox.meta.SolverCharacteristics; import edu.kit.provideq.toolbox.meta.SolvingProperties; import edu.kit.provideq.toolbox.meta.SubRoutineResolver; import edu.kit.provideq.toolbox.meta.setting.SolverSetting; @@ -47,6 +50,11 @@ public String getDescription() { return "A solver for QUBOs using the Qrisp QAOA implementation."; } + @Override + public SolverCharacteristics getCharacteristics() { + return SolverCharacteristics.of(RuleType.SOLVE, RuleProperty.VALID); + } + @Override public List getSolverSettings() { return List.of( diff --git a/src/main/java/edu/kit/provideq/toolbox/qubo/solvers/QuantagoniaQuboSolver.java b/src/main/java/edu/kit/provideq/toolbox/qubo/solvers/QuantagoniaQuboSolver.java index 6a8d44cf..b1bfdef9 100644 --- a/src/main/java/edu/kit/provideq/toolbox/qubo/solvers/QuantagoniaQuboSolver.java +++ b/src/main/java/edu/kit/provideq/toolbox/qubo/solvers/QuantagoniaQuboSolver.java @@ -9,6 +9,9 @@ import edu.kit.provideq.toolbox.integration.planqk.PlanQkApi.ProblemProperties; import edu.kit.provideq.toolbox.integration.planqk.PlanQkApi.ResultProperties; import edu.kit.provideq.toolbox.integration.planqk.PlanQkApi.StatusProperties; +import edu.kit.provideq.toolbox.meta.RuleProperty; +import edu.kit.provideq.toolbox.meta.RuleType; +import edu.kit.provideq.toolbox.meta.SolverCharacteristics; import edu.kit.provideq.toolbox.meta.SolvingProperties; import edu.kit.provideq.toolbox.meta.SubRoutineResolver; import edu.kit.provideq.toolbox.meta.setting.SolverSetting; @@ -43,6 +46,11 @@ public String getDescription() { return "This solver uses Quantagonia’s HybridSolver to solve QUBO problems via PlanQK"; } + @Override + public SolverCharacteristics getCharacteristics() { + return SolverCharacteristics.of(RuleType.SOLVE, RuleProperty.VALID); + } + @Override public List getSolverSettings() { return List.of( diff --git a/src/main/java/edu/kit/provideq/toolbox/sat/solvers/GamsSatSolver.java b/src/main/java/edu/kit/provideq/toolbox/sat/solvers/GamsSatSolver.java index 290994aa..04659a4c 100644 --- a/src/main/java/edu/kit/provideq/toolbox/sat/solvers/GamsSatSolver.java +++ b/src/main/java/edu/kit/provideq/toolbox/sat/solvers/GamsSatSolver.java @@ -4,6 +4,9 @@ import edu.kit.provideq.toolbox.exception.ConversionException; import edu.kit.provideq.toolbox.format.cnf.dimacs.DimacsCnf; import edu.kit.provideq.toolbox.format.cnf.dimacs.DimacsCnfSolution; +import edu.kit.provideq.toolbox.meta.RuleProperty; +import edu.kit.provideq.toolbox.meta.RuleType; +import edu.kit.provideq.toolbox.meta.SolverCharacteristics; import edu.kit.provideq.toolbox.meta.SolvingProperties; import edu.kit.provideq.toolbox.meta.SubRoutineResolver; import edu.kit.provideq.toolbox.process.GamsProcessRunner; @@ -42,6 +45,11 @@ public String getDescription() { return "Solves SAT problems using GAMS as a Mixed Integer Programming problem."; } + @Override + public SolverCharacteristics getCharacteristics() { + return SolverCharacteristics.of(RuleType.SOLVE, RuleProperty.EXACT, RuleProperty.VALID); + } + @Override public Mono> solve( String input, diff --git a/src/main/java/edu/kit/provideq/toolbox/sat/solvers/QrispExactGroverSolver.java b/src/main/java/edu/kit/provideq/toolbox/sat/solvers/QrispExactGroverSolver.java index 31b4567a..2c611b6f 100644 --- a/src/main/java/edu/kit/provideq/toolbox/sat/solvers/QrispExactGroverSolver.java +++ b/src/main/java/edu/kit/provideq/toolbox/sat/solvers/QrispExactGroverSolver.java @@ -4,7 +4,9 @@ import edu.kit.provideq.toolbox.exception.ConversionException; import edu.kit.provideq.toolbox.format.cnf.dimacs.DimacsCnf; import edu.kit.provideq.toolbox.format.cnf.dimacs.DimacsCnfSolution; -import edu.kit.provideq.toolbox.meta.SolverCharacteristic; +import edu.kit.provideq.toolbox.meta.RuleProperty; +import edu.kit.provideq.toolbox.meta.RuleType; +import edu.kit.provideq.toolbox.meta.SolverCharacteristics; import edu.kit.provideq.toolbox.meta.SolvingProperties; import edu.kit.provideq.toolbox.meta.SubRoutineDefinition; import edu.kit.provideq.toolbox.meta.SubRoutineResolver; @@ -59,8 +61,8 @@ public String getDescription() { } @Override - public List getCharacteristics() { - return List.of(SolverCharacteristic.SOLVE); + public SolverCharacteristics getCharacteristics() { + return SolverCharacteristics.of(RuleType.SOLVE, RuleProperty.EXACT, RuleProperty.VALID); } @Override diff --git a/src/main/java/edu/kit/provideq/toolbox/sharpsat/solvers/PythonBruteForceSolver.java b/src/main/java/edu/kit/provideq/toolbox/sharpsat/solvers/PythonBruteForceSolver.java index 4e0fb85a..1836f36d 100644 --- a/src/main/java/edu/kit/provideq/toolbox/sharpsat/solvers/PythonBruteForceSolver.java +++ b/src/main/java/edu/kit/provideq/toolbox/sharpsat/solvers/PythonBruteForceSolver.java @@ -3,6 +3,9 @@ import edu.kit.provideq.toolbox.Solution; import edu.kit.provideq.toolbox.exception.ConversionException; import edu.kit.provideq.toolbox.format.cnf.dimacs.DimacsCnf; +import edu.kit.provideq.toolbox.meta.RuleProperty; +import edu.kit.provideq.toolbox.meta.RuleType; +import edu.kit.provideq.toolbox.meta.SolverCharacteristics; import edu.kit.provideq.toolbox.meta.SolvingProperties; import edu.kit.provideq.toolbox.meta.SubRoutineResolver; import edu.kit.provideq.toolbox.process.ProcessResult; @@ -54,6 +57,11 @@ public String getDescription() { return "Sat solution counter in python using naive bruteforce approach"; } + @Override + public SolverCharacteristics getCharacteristics() { + return SolverCharacteristics.of(RuleType.SOLVE, RuleProperty.EXACT, RuleProperty.VALID); + } + /** * Solves a given problem instance, current status and final results as well as debug information * is stored in the provided {@link Solution} object. diff --git a/src/main/java/edu/kit/provideq/toolbox/tsp/solvers/LkhTspSolver.java b/src/main/java/edu/kit/provideq/toolbox/tsp/solvers/LkhTspSolver.java index 25818f2f..232b1179 100644 --- a/src/main/java/edu/kit/provideq/toolbox/tsp/solvers/LkhTspSolver.java +++ b/src/main/java/edu/kit/provideq/toolbox/tsp/solvers/LkhTspSolver.java @@ -1,6 +1,9 @@ package edu.kit.provideq.toolbox.tsp.solvers; import edu.kit.provideq.toolbox.Solution; +import edu.kit.provideq.toolbox.meta.RuleProperty; +import edu.kit.provideq.toolbox.meta.RuleType; +import edu.kit.provideq.toolbox.meta.SolverCharacteristics; import edu.kit.provideq.toolbox.meta.SolvingProperties; import edu.kit.provideq.toolbox.meta.SubRoutineResolver; import edu.kit.provideq.toolbox.process.ProcessRunner; @@ -43,6 +46,11 @@ public String getDescription() { return "Solver for the TSP Problem using the LKH-3 heuristics."; } + @Override + public SolverCharacteristics getCharacteristics() { + return SolverCharacteristics.of(RuleType.SOLVE, RuleProperty.VALID); + } + @Override public Mono> solve( String input, diff --git a/src/main/java/edu/kit/provideq/toolbox/tsp/solvers/QuboTspSolver.java b/src/main/java/edu/kit/provideq/toolbox/tsp/solvers/QuboTspSolver.java index 4040fd66..5f86517b 100644 --- a/src/main/java/edu/kit/provideq/toolbox/tsp/solvers/QuboTspSolver.java +++ b/src/main/java/edu/kit/provideq/toolbox/tsp/solvers/QuboTspSolver.java @@ -2,7 +2,9 @@ import edu.kit.provideq.toolbox.ResourceProvider; import edu.kit.provideq.toolbox.Solution; -import edu.kit.provideq.toolbox.meta.SolverCharacteristic; +import edu.kit.provideq.toolbox.meta.RuleProperty; +import edu.kit.provideq.toolbox.meta.RuleType; +import edu.kit.provideq.toolbox.meta.SolverCharacteristics; import edu.kit.provideq.toolbox.meta.SolvingProperties; import edu.kit.provideq.toolbox.meta.SubRoutineDefinition; import edu.kit.provideq.toolbox.meta.SubRoutineResolver; @@ -62,8 +64,11 @@ public String getDescription() { } @Override - public List getCharacteristics() { - return List.of(SolverCharacteristic.REFORMULATION); + public SolverCharacteristics getCharacteristics() { + return SolverCharacteristics.of( + RuleType.REFORMULATION, + RuleProperty.WEAKLY_CONSTRAINT_PRESERVING, + RuleProperty.OPTIMAL_SOLUTION_PRESERVING); } @Override diff --git a/src/main/java/edu/kit/provideq/toolbox/unsplittablemcf/solvers/GamsUnsplittableMcfClassicalSolver.java b/src/main/java/edu/kit/provideq/toolbox/unsplittablemcf/solvers/GamsUnsplittableMcfClassicalSolver.java index 6e298aca..58b76210 100644 --- a/src/main/java/edu/kit/provideq/toolbox/unsplittablemcf/solvers/GamsUnsplittableMcfClassicalSolver.java +++ b/src/main/java/edu/kit/provideq/toolbox/unsplittablemcf/solvers/GamsUnsplittableMcfClassicalSolver.java @@ -1,6 +1,9 @@ package edu.kit.provideq.toolbox.unsplittablemcf.solvers; import edu.kit.provideq.toolbox.Solution; +import edu.kit.provideq.toolbox.meta.RuleProperty; +import edu.kit.provideq.toolbox.meta.RuleType; +import edu.kit.provideq.toolbox.meta.SolverCharacteristics; import edu.kit.provideq.toolbox.meta.SolvingProperties; import edu.kit.provideq.toolbox.meta.SubRoutineResolver; import edu.kit.provideq.toolbox.process.ProcessRunner; @@ -44,6 +47,11 @@ public String getDescription() { + "delay and slack penalties."; } + @Override + public SolverCharacteristics getCharacteristics() { + return SolverCharacteristics.of(RuleType.SOLVE, RuleProperty.VALID); + } + @Override public Mono> solve( String input, diff --git a/src/main/java/edu/kit/provideq/toolbox/unsplittablemcf/solvers/GamsUnsplittableMcfQuboSolver.java b/src/main/java/edu/kit/provideq/toolbox/unsplittablemcf/solvers/GamsUnsplittableMcfQuboSolver.java index 00ecced1..dbf0ee69 100644 --- a/src/main/java/edu/kit/provideq/toolbox/unsplittablemcf/solvers/GamsUnsplittableMcfQuboSolver.java +++ b/src/main/java/edu/kit/provideq/toolbox/unsplittablemcf/solvers/GamsUnsplittableMcfQuboSolver.java @@ -1,7 +1,9 @@ package edu.kit.provideq.toolbox.unsplittablemcf.solvers; import edu.kit.provideq.toolbox.Solution; -import edu.kit.provideq.toolbox.meta.SolverCharacteristic; +import edu.kit.provideq.toolbox.meta.RuleProperty; +import edu.kit.provideq.toolbox.meta.RuleType; +import edu.kit.provideq.toolbox.meta.SolverCharacteristics; import edu.kit.provideq.toolbox.meta.SolvingProperties; import edu.kit.provideq.toolbox.meta.SubRoutineDefinition; import edu.kit.provideq.toolbox.meta.SubRoutineResolver; @@ -59,8 +61,11 @@ public String getDescription() { } @Override - public List getCharacteristics() { - return List.of(SolverCharacteristic.REFORMULATION); + public SolverCharacteristics getCharacteristics() { + return SolverCharacteristics.of( + RuleType.REFORMULATION, + RuleProperty.WEAKLY_CONSTRAINT_PRESERVING, + RuleProperty.OPTIMAL_SOLUTION_PRESERVING); } @Override diff --git a/src/main/java/edu/kit/provideq/toolbox/vrp/clusterer/KmeansClusterer.java b/src/main/java/edu/kit/provideq/toolbox/vrp/clusterer/KmeansClusterer.java index 68cb83b4..9e7bfe7b 100644 --- a/src/main/java/edu/kit/provideq/toolbox/vrp/clusterer/KmeansClusterer.java +++ b/src/main/java/edu/kit/provideq/toolbox/vrp/clusterer/KmeansClusterer.java @@ -2,7 +2,9 @@ import edu.kit.provideq.toolbox.Solution; -import edu.kit.provideq.toolbox.meta.SolverCharacteristic; +import edu.kit.provideq.toolbox.meta.RuleProperty; +import edu.kit.provideq.toolbox.meta.RuleType; +import edu.kit.provideq.toolbox.meta.SolverCharacteristics; import edu.kit.provideq.toolbox.meta.SolvingProperties; import edu.kit.provideq.toolbox.meta.SubRoutineDefinition; import edu.kit.provideq.toolbox.meta.SubRoutineResolver; @@ -52,8 +54,10 @@ public String getDescription() { } @Override - public List getCharacteristics() { - return List.of(SolverCharacteristic.DECOMPOSITION); + public SolverCharacteristics getCharacteristics() { + return SolverCharacteristics.of( + RuleType.DECOMPOSITION, + RuleProperty.STRONGLY_CONSTRAINT_PRESERVING); } @Override diff --git a/src/main/java/edu/kit/provideq/toolbox/vrp/clusterer/TwoPhaseClusterer.java b/src/main/java/edu/kit/provideq/toolbox/vrp/clusterer/TwoPhaseClusterer.java index a53f6d71..0be452cb 100644 --- a/src/main/java/edu/kit/provideq/toolbox/vrp/clusterer/TwoPhaseClusterer.java +++ b/src/main/java/edu/kit/provideq/toolbox/vrp/clusterer/TwoPhaseClusterer.java @@ -1,7 +1,9 @@ package edu.kit.provideq.toolbox.vrp.clusterer; import edu.kit.provideq.toolbox.Solution; -import edu.kit.provideq.toolbox.meta.SolverCharacteristic; +import edu.kit.provideq.toolbox.meta.RuleProperty; +import edu.kit.provideq.toolbox.meta.RuleType; +import edu.kit.provideq.toolbox.meta.SolverCharacteristics; import edu.kit.provideq.toolbox.meta.SolvingProperties; import edu.kit.provideq.toolbox.meta.SubRoutineDefinition; import edu.kit.provideq.toolbox.meta.SubRoutineResolver; @@ -34,8 +36,10 @@ public TwoPhaseClusterer( } @Override - public List getCharacteristics() { - return List.of(SolverCharacteristic.DECOMPOSITION); + public SolverCharacteristics getCharacteristics() { + return SolverCharacteristics.of( + RuleType.DECOMPOSITION, + RuleProperty.STRONGLY_CONSTRAINT_PRESERVING); } @Override diff --git a/src/main/java/edu/kit/provideq/toolbox/vrp/solvers/ClusterAndSolveVrpSolver.java b/src/main/java/edu/kit/provideq/toolbox/vrp/solvers/ClusterAndSolveVrpSolver.java index b9a71a25..0917faed 100644 --- a/src/main/java/edu/kit/provideq/toolbox/vrp/solvers/ClusterAndSolveVrpSolver.java +++ b/src/main/java/edu/kit/provideq/toolbox/vrp/solvers/ClusterAndSolveVrpSolver.java @@ -1,7 +1,8 @@ package edu.kit.provideq.toolbox.vrp.solvers; import edu.kit.provideq.toolbox.Solution; -import edu.kit.provideq.toolbox.meta.SolverCharacteristic; +import edu.kit.provideq.toolbox.meta.RuleType; +import edu.kit.provideq.toolbox.meta.SolverCharacteristics; import edu.kit.provideq.toolbox.meta.SolvingProperties; import edu.kit.provideq.toolbox.meta.SubRoutineDefinition; import edu.kit.provideq.toolbox.meta.SubRoutineResolver; @@ -31,8 +32,8 @@ public String getDescription() { } @Override - public List getCharacteristics() { - return List.of(SolverCharacteristic.REFORMULATION); + public SolverCharacteristics getCharacteristics() { + return SolverCharacteristics.of(RuleType.DELEGATION); } @Override From 50306dabf36e41c3b7b50aeb68a3a9c05caae5f1 Mon Sep 17 00:00:00 2001 From: ekulos-code Date: Thu, 17 Sep 2026 15:36:55 +0200 Subject: [PATCH 3/5] Add correctness check, strategy endpoint --- .gitignore | 1 + .../kit/provideq/toolbox/api/StrategyDto.java | 16 ++++ .../provideq/toolbox/api/StrategyRouter.java | 89 +++++++++++++++++++ .../solvers/executor/ExecutionSolver.java | 3 +- .../optimization/OptimizationSolver.java | 4 +- .../dead/SatBasedDeadFeatureSolver.java | 7 +- .../voidmodel/SatBasedVoidFeatureSolver.java | 7 +- .../provideq/toolbox/meta/SubProblems.java | 5 +- .../meta/strategy/CorrectnessVerdict.java | 7 ++ .../meta/strategy/CorrectnessViolation.java | 11 +++ .../meta/strategy/StrategyCorrectness.java | 49 ++++++++++ .../toolbox/meta/strategy/StrategyStep.java | 57 ++++++++++++ 12 files changed, 245 insertions(+), 11 deletions(-) create mode 100644 src/main/java/edu/kit/provideq/toolbox/api/StrategyDto.java create mode 100644 src/main/java/edu/kit/provideq/toolbox/api/StrategyRouter.java create mode 100644 src/main/java/edu/kit/provideq/toolbox/meta/strategy/CorrectnessVerdict.java create mode 100644 src/main/java/edu/kit/provideq/toolbox/meta/strategy/CorrectnessViolation.java create mode 100644 src/main/java/edu/kit/provideq/toolbox/meta/strategy/StrategyCorrectness.java create mode 100644 src/main/java/edu/kit/provideq/toolbox/meta/strategy/StrategyStep.java diff --git a/.gitignore b/.gitignore index f20019d1..86e341b3 100644 --- a/.gitignore +++ b/.gitignore @@ -43,6 +43,7 @@ out/ ### virtual envs and python ### venv/ +.venv/ __pycache__/ ### ProvideQ toolbox-server ### diff --git a/src/main/java/edu/kit/provideq/toolbox/api/StrategyDto.java b/src/main/java/edu/kit/provideq/toolbox/api/StrategyDto.java new file mode 100644 index 00000000..44355769 --- /dev/null +++ b/src/main/java/edu/kit/provideq/toolbox/api/StrategyDto.java @@ -0,0 +1,16 @@ +package edu.kit.provideq.toolbox.api; + +import edu.kit.provideq.toolbox.meta.Problem; +import edu.kit.provideq.toolbox.meta.strategy.StrategyCorrectness; +import edu.kit.provideq.toolbox.meta.strategy.StrategyStep; +import java.util.List; + +public record StrategyDto( + List steps, + StrategyCorrectness correctness +) { + public static StrategyDto fromProblem(Problem problem) { + var steps = StrategyStep.collect(problem); + return new StrategyDto(steps, StrategyCorrectness.evaluate(steps)); + } +} diff --git a/src/main/java/edu/kit/provideq/toolbox/api/StrategyRouter.java b/src/main/java/edu/kit/provideq/toolbox/api/StrategyRouter.java new file mode 100644 index 00000000..7fc530b1 --- /dev/null +++ b/src/main/java/edu/kit/provideq/toolbox/api/StrategyRouter.java @@ -0,0 +1,89 @@ +package edu.kit.provideq.toolbox.api; + +import static org.springdoc.core.fn.builders.apiresponse.Builder.responseBuilder; +import static org.springdoc.core.fn.builders.content.Builder.contentBuilder; +import static org.springdoc.core.fn.builders.parameter.Builder.parameterBuilder; +import static org.springdoc.core.fn.builders.schema.Builder.schemaBuilder; +import static org.springdoc.webflux.core.fn.SpringdocRouteBuilder.route; +import static org.springframework.http.MediaType.APPLICATION_JSON; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; +import static org.springframework.web.reactive.function.server.RequestPredicates.accept; +import static org.springframework.web.reactive.function.server.ServerResponse.ok; + +import edu.kit.provideq.toolbox.meta.ProblemManager; +import edu.kit.provideq.toolbox.meta.ProblemManagerProvider; +import edu.kit.provideq.toolbox.meta.ProblemType; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import org.springdoc.core.fn.builders.operation.Builder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpStatus; +import org.springframework.web.reactive.config.EnableWebFlux; +import org.springframework.web.reactive.function.server.RouterFunction; +import org.springframework.web.reactive.function.server.ServerRequest; +import org.springframework.web.reactive.function.server.ServerResponse; +import reactor.core.publisher.Mono; + +@Configuration +@EnableWebFlux +public class StrategyRouter { + public static final String PROBLEM_ID_PARAM_NAME = "problemId"; + private ProblemManagerProvider managerProvider; + + @Bean + RouterFunction getStrategyRoutes() { + return managerProvider.getProblemManagers().stream() + .map(this::defineGetRoute) + .reduce(RouterFunction::and) + .orElseThrow(); + } + + private RouterFunction defineGetRoute(ProblemManager manager) { + return route().GET( + getStrategyRouteForProblemType(manager.getType()), + accept(APPLICATION_JSON), + req -> handleGet(manager, req), + ops -> handleGetDocumentation(manager, ops) + ).build(); + } + + private Mono handleGet( + ProblemManager manager, + ServerRequest req + ) { + var problemId = req.pathVariable(PROBLEM_ID_PARAM_NAME); + var problem = RouterUtility.findProblemOrThrow(manager, problemId); + var strategyDto = StrategyDto.fromProblem(problem); + + return ok().body(Mono.just(strategyDto), new ParameterizedTypeReference<>() { + }); + } + + private void handleGetDocumentation(ProblemManager manager, Builder ops) { + ProblemType problemType = manager.getType(); + ops + .operationId(getStrategyRouteForProblemType(problemType)) + .tag(problemType.getId()) + .description("Returns the meta-solver strategy configured for the given problem, meaning " + + "the sequence of transformation rules composed by the problem and its sub-problems, " + + "together with the correctness verdict that can be made about it.") + .parameter(parameterBuilder().in(ParameterIn.PATH).name(PROBLEM_ID_PARAM_NAME)) + .response(responseBuilder() + .responseCode(String.valueOf(HttpStatus.OK.value())) + .content(contentBuilder() + .mediaType(APPLICATION_JSON_VALUE) + .schema(schemaBuilder().implementation(StrategyDto.class))) + ); + } + + private String getStrategyRouteForProblemType(ProblemType type) { + return "/problems/%s/{%s}/strategy".formatted(type.getId(), PROBLEM_ID_PARAM_NAME); + } + + @Autowired + void setManagerProvider(ProblemManagerProvider managerProvider) { + this.managerProvider = managerProvider; + } +} diff --git a/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solvers/executor/ExecutionSolver.java b/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solvers/executor/ExecutionSolver.java index 98814a4b..b4d3dabb 100644 --- a/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solvers/executor/ExecutionSolver.java +++ b/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solvers/executor/ExecutionSolver.java @@ -55,7 +55,8 @@ public String getDescription() { @Override public SolverCharacteristics getCharacteristics() { - // TODO: valid only holds true for noise free simulation, add additional executor, splitting noisy and noise free + // TODO: valid only holds true for noise free simulation, add additional executor, + // splitting noisy and noise free return SolverCharacteristics.of(RuleType.SOLVE, RuleProperty.VALID); } diff --git a/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solvers/optimization/OptimizationSolver.java b/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solvers/optimization/OptimizationSolver.java index d9ecafd0..c0e305ef 100644 --- a/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solvers/optimization/OptimizationSolver.java +++ b/src/main/java/edu/kit/provideq/toolbox/circuit/processing/solvers/optimization/OptimizationSolver.java @@ -62,7 +62,9 @@ public String getDescription() { @Override public SolverCharacteristics getCharacteristics() { - return SolverCharacteristics.of(RuleType.REFORMULATION, RuleProperty.STRONGLY_CONSTRAINT_PRESERVING, + return SolverCharacteristics.of( + RuleType.REFORMULATION, + RuleProperty.STRONGLY_CONSTRAINT_PRESERVING, RuleProperty.OPTIMAL_SOLUTION_PRESERVING); } diff --git a/src/main/java/edu/kit/provideq/toolbox/featuremodel/anomaly/dead/SatBasedDeadFeatureSolver.java b/src/main/java/edu/kit/provideq/toolbox/featuremodel/anomaly/dead/SatBasedDeadFeatureSolver.java index 8e67334b..d05151b8 100644 --- a/src/main/java/edu/kit/provideq/toolbox/featuremodel/anomaly/dead/SatBasedDeadFeatureSolver.java +++ b/src/main/java/edu/kit/provideq/toolbox/featuremodel/anomaly/dead/SatBasedDeadFeatureSolver.java @@ -15,15 +15,14 @@ import edu.kit.provideq.toolbox.meta.SubRoutineDefinition; import edu.kit.provideq.toolbox.meta.SubRoutineResolver; import edu.kit.provideq.toolbox.sat.SatConfiguration; +import java.util.ArrayList; +import java.util.List; import org.springframework.stereotype.Component; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.util.function.Tuple2; import reactor.util.function.Tuples; -import java.util.ArrayList; -import java.util.List; - /** * This problem solver solves the {@link DeadFeatureConfiguration#FEATURE_MODEL_ANOMALY_DEAD} * problem by building {@link SatConfiguration#SAT} formulae that are solved by a corresponding @@ -134,7 +133,7 @@ private Mono> checkDeadFeatures( * * @param subRoutineResolver used to evaluate a SAT formula for the check. * @return the solution of the given {@code feature}. - * Use {@link DimacsCnfSolution#isVoid()} to check the feature. + * Use {@link DimacsCnfSolution#isVoid()} to check the feature. */ private static Mono checkFeatureDead( DimacsCnf cnf, diff --git a/src/main/java/edu/kit/provideq/toolbox/featuremodel/anomaly/voidmodel/SatBasedVoidFeatureSolver.java b/src/main/java/edu/kit/provideq/toolbox/featuremodel/anomaly/voidmodel/SatBasedVoidFeatureSolver.java index b9f5e418..6094af37 100644 --- a/src/main/java/edu/kit/provideq/toolbox/featuremodel/anomaly/voidmodel/SatBasedVoidFeatureSolver.java +++ b/src/main/java/edu/kit/provideq/toolbox/featuremodel/anomaly/voidmodel/SatBasedVoidFeatureSolver.java @@ -13,11 +13,10 @@ import edu.kit.provideq.toolbox.meta.SubRoutineDefinition; import edu.kit.provideq.toolbox.meta.SubRoutineResolver; import edu.kit.provideq.toolbox.sat.SatConfiguration; +import java.util.List; import org.springframework.stereotype.Component; import reactor.core.publisher.Mono; -import java.util.List; - /** * This problem solver solves the {@link VoidModelConfiguration#FEATURE_MODEL_ANOMALY_VOID} problem * by building {@link SatConfiguration#SAT} formula that is solved by a corresponding solver. @@ -43,7 +42,9 @@ public String getName() { @Override public SolverCharacteristics getCharacteristics() { - return SolverCharacteristics.of(RuleType.REFORMULATION, RuleProperty.STRONGLY_CONSTRAINT_PRESERVING, + return SolverCharacteristics.of( + RuleType.REFORMULATION, + RuleProperty.STRONGLY_CONSTRAINT_PRESERVING, RuleProperty.OPTIMAL_SOLUTION_PRESERVING); } diff --git a/src/main/java/edu/kit/provideq/toolbox/meta/SubProblems.java b/src/main/java/edu/kit/provideq/toolbox/meta/SubProblems.java index ad9c5eb8..189f4bd8 100644 --- a/src/main/java/edu/kit/provideq/toolbox/meta/SubProblems.java +++ b/src/main/java/edu/kit/provideq/toolbox/meta/SubProblems.java @@ -5,6 +5,7 @@ import java.util.Collection; import java.util.Collections; import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.List; import java.util.Optional; import java.util.Set; @@ -71,14 +72,14 @@ public SubProblems( } /** - * Returns all sub-problems related to a given sub-routine. + * Returns all sub-problems related to a given sub-routine, in the order they were created in. */ public Set> getProblems( SubRoutineDefinition subRoutineDefinition) { var optionalEntry = findEntry(subRoutineDefinition); return optionalEntry - .map(entry -> (Set>) new HashSet<>(entry.problems)) + .map(entry -> (Set>) new LinkedHashSet<>(entry.problems)) .orElse(Collections.emptySet()); } diff --git a/src/main/java/edu/kit/provideq/toolbox/meta/strategy/CorrectnessVerdict.java b/src/main/java/edu/kit/provideq/toolbox/meta/strategy/CorrectnessVerdict.java new file mode 100644 index 00000000..1b2a2287 --- /dev/null +++ b/src/main/java/edu/kit/provideq/toolbox/meta/strategy/CorrectnessVerdict.java @@ -0,0 +1,7 @@ +package edu.kit.provideq.toolbox.meta.strategy; + +public enum CorrectnessVerdict { + CORRECT, + INCORRECT, + UNDETERMINED +} diff --git a/src/main/java/edu/kit/provideq/toolbox/meta/strategy/CorrectnessViolation.java b/src/main/java/edu/kit/provideq/toolbox/meta/strategy/CorrectnessViolation.java new file mode 100644 index 00000000..ea0ba5d5 --- /dev/null +++ b/src/main/java/edu/kit/provideq/toolbox/meta/strategy/CorrectnessViolation.java @@ -0,0 +1,11 @@ +package edu.kit.provideq.toolbox.meta.strategy; + +import edu.kit.provideq.toolbox.meta.RuleProperty; +import edu.kit.provideq.toolbox.meta.RuleType; + +public record CorrectnessViolation( + String problemId, + RuleType ruleType, + RuleProperty requiredProperty +) { +} diff --git a/src/main/java/edu/kit/provideq/toolbox/meta/strategy/StrategyCorrectness.java b/src/main/java/edu/kit/provideq/toolbox/meta/strategy/StrategyCorrectness.java new file mode 100644 index 00000000..0739af10 --- /dev/null +++ b/src/main/java/edu/kit/provideq/toolbox/meta/strategy/StrategyCorrectness.java @@ -0,0 +1,49 @@ +package edu.kit.provideq.toolbox.meta.strategy; + +import edu.kit.provideq.toolbox.meta.RuleProperty; +import edu.kit.provideq.toolbox.meta.RuleType; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public record StrategyCorrectness( + CorrectnessVerdict verdict, + List violations +) { + private static final Map REQUIRED_PROPERTIES = Map.of( + RuleType.SOLVE, RuleProperty.VALID, + RuleType.REFORMULATION, RuleProperty.STRONGLY_CONSTRAINT_PRESERVING, + RuleType.DECOMPOSITION, RuleProperty.STRONGLY_CONSTRAINT_PRESERVING + ); + + public static StrategyCorrectness evaluate(List steps) { + var violations = new ArrayList(); + var hasUnknownRules = false; + + for (var step : steps) { + if (!step.isConfigured()) { + hasUnknownRules = true; + continue; + } + + var characteristics = step.characteristics(); + for (var ruleType : characteristics.types()) { + var requiredProperty = REQUIRED_PROPERTIES.get(ruleType); + if (requiredProperty != null && !characteristics.properties().contains(requiredProperty)) { + violations.add(new CorrectnessViolation(step.problemId(), ruleType, requiredProperty)); + } + } + } + + CorrectnessVerdict verdict; + if (!violations.isEmpty()) { + verdict = CorrectnessVerdict.INCORRECT; + } else if (hasUnknownRules) { + verdict = CorrectnessVerdict.UNDETERMINED; + } else { + verdict = CorrectnessVerdict.CORRECT; + } + + return new StrategyCorrectness(verdict, List.copyOf(violations)); + } +} diff --git a/src/main/java/edu/kit/provideq/toolbox/meta/strategy/StrategyStep.java b/src/main/java/edu/kit/provideq/toolbox/meta/strategy/StrategyStep.java new file mode 100644 index 00000000..c70bbb9b --- /dev/null +++ b/src/main/java/edu/kit/provideq/toolbox/meta/strategy/StrategyStep.java @@ -0,0 +1,57 @@ +package edu.kit.provideq.toolbox.meta.strategy; + +import edu.kit.provideq.toolbox.meta.Problem; +import edu.kit.provideq.toolbox.meta.SolverCharacteristics; +import java.util.ArrayList; +import java.util.List; + +/** + * A single transformation rule of a meta-solver strategy, a problem and the solver applied to it + * A step without a problem id stands for a sub-routine that hasn't been called yet + */ +public record StrategyStep( + String problemId, + String problemTypeId, + int depth, + String solverName, + SolverCharacteristics characteristics +) { + /** + * Flattens strategy formed by a problem and its sub-problems into pre-order + * so every step directly follows its parent + */ + public static List collect(Problem problem) { + var steps = new ArrayList(); + collect(problem, 0, steps); + return steps; + } + + private static void collect(Problem problem, int depth, List steps) { + var solver = problem.getSolver().orElse(null); + + steps.add(new StrategyStep( + problem.getId().toString(), + problem.getType().getId(), + depth, + solver == null ? null : solver.getName(), + solver == null ? null : solver.getCharacteristics())); + + if (solver == null) { + return; + } + + for (var subRoutine : solver.getSubRoutines()) { + var subProblems = problem.getSubProblems(subRoutine); + if (subProblems.isEmpty()) { + steps.add(new StrategyStep(null, subRoutine.type().getId(), depth + 1, null, null)); + } + for (var subProblem : subProblems) { + collect(subProblem, depth + 1, steps); + } + } + } + + public boolean isConfigured() { + return characteristics != null; + } +} From 521ed819a21c56310f572a9e184f54bea71184d4 Mon Sep 17 00:00:00 2001 From: ekulos-code Date: Sat, 26 Sep 2026 03:55:34 +0200 Subject: [PATCH 4/5] Add guarded QuboTspSolver runs --- .../edu/kit/provideq/toolbox/Solution.java | 11 ++ .../provideq/toolbox/meta/guard/Guard.java | 142 ++++++++++++++++++ .../toolbox/meta/guard/SolutionGuard.java | 8 + .../toolbox/tsp/TspSolutionGuard.java | 103 +++++++++++++ .../toolbox/tsp/solvers/QuboTspSolver.java | 74 ++++++--- 5 files changed, 316 insertions(+), 22 deletions(-) create mode 100644 src/main/java/edu/kit/provideq/toolbox/meta/guard/Guard.java create mode 100644 src/main/java/edu/kit/provideq/toolbox/meta/guard/SolutionGuard.java create mode 100644 src/main/java/edu/kit/provideq/toolbox/tsp/TspSolutionGuard.java diff --git a/src/main/java/edu/kit/provideq/toolbox/Solution.java b/src/main/java/edu/kit/provideq/toolbox/Solution.java index cb55ac3a..ea5961bc 100644 --- a/src/main/java/edu/kit/provideq/toolbox/Solution.java +++ b/src/main/java/edu/kit/provideq/toolbox/Solution.java @@ -21,6 +21,7 @@ public class Solution { private String debugData; private String solverName; private long executionMilliseconds; + private String guardRejection; /** * Internal constructor, used for de-serialization. @@ -57,6 +58,7 @@ public static Solution from( result.metaData = source.metaData; result.debugData = source.debugData; result.executionMilliseconds = source.executionMilliseconds; + result.guardRejection = source.guardRejection; result.solutionData = source.solutionData == null ? null : mapper.apply(source.solutionData); return result; } @@ -96,6 +98,7 @@ public Solution toStringSolution(@NotNull Function stringSele stringSolution.debugData = debugData; stringSolution.solverName = solverName; stringSolution.executionMilliseconds = executionMilliseconds; + stringSolution.guardRejection = guardRejection; return stringSolution; } @@ -166,6 +169,14 @@ public void setExecutionMilliseconds(long executionMilliseconds) { this.executionMilliseconds = executionMilliseconds; } + public String getGuardRejection() { + return guardRejection; + } + + public void rejectByGuard(String reason) { + this.guardRejection = reason; + } + @Override public boolean equals(Object obj) { if (obj == this) { diff --git a/src/main/java/edu/kit/provideq/toolbox/meta/guard/Guard.java b/src/main/java/edu/kit/provideq/toolbox/meta/guard/Guard.java new file mode 100644 index 00000000..63102ab0 --- /dev/null +++ b/src/main/java/edu/kit/provideq/toolbox/meta/guard/Guard.java @@ -0,0 +1,142 @@ +package edu.kit.provideq.toolbox.meta.guard; + +import edu.kit.provideq.toolbox.Solution; +import edu.kit.provideq.toolbox.meta.SolvingProperties; +import edu.kit.provideq.toolbox.meta.setting.SolverSetting; +import edu.kit.provideq.toolbox.meta.setting.basic.BooleanSetting; +import edu.kit.provideq.toolbox.meta.setting.basic.IntegerSetting; +import java.util.List; +import java.util.Optional; +import java.util.function.Supplier; +import reactor.core.publisher.Mono; + +public final class Guard { + public static final String SETTING_NAME = "Guarded"; + public static final String RETRIES_SETTING_NAME = "Guard Retries"; + private static final int MAX_RETRIES = 100; + + private Guard() { + } + + public record Configuration(boolean enabled, int retries) { + public static final Configuration DISABLED = new Configuration(false, 0); + } + + public record Attempt(ResultT result, String error, List> sources) { + public static Attempt of(ResultT result, Solution... sources) { + return new Attempt<>(result, null, List.of(sources)); + } + + public static Attempt failed(String error, Solution... sources) { + return new Attempt<>(null, error, List.of(sources)); + } + + private Optional findFailure() { + if (error != null) { + return Optional.of(error); + } + if (result == null) { + return Optional.of("The solver produced no result."); + } + return Optional.empty(); + } + } + + public static List createSettings( + String description, + boolean defaultEnabled, + int defaultRetries + ) { + return List.of( + new BooleanSetting(SETTING_NAME, description, defaultEnabled), + new IntegerSetting( + RETRIES_SETTING_NAME, + "How often the sub-routines are started again when the guard rejects a result", + 0, + MAX_RETRIES, + defaultRetries) + ); + } + + public static Configuration readConfiguration( + SolvingProperties properties, + boolean defaultEnabled, + int defaultRetries + ) { + var enabled = properties.getSetting(SETTING_NAME) + .map(BooleanSetting::getState) + .orElse(defaultEnabled); + var retries = properties.getSetting(RETRIES_SETTING_NAME) + .map(IntegerSetting::getValue) + .orElse(defaultRetries); + return new Configuration(enabled, retries); + } + + public static Mono> solve( + Solution solution, + ProblemT problem, + SolutionGuard guard, + Configuration configuration, + Supplier>> attempt + ) { + if (!configuration.enabled()) { + return attempt.get().map(result -> complete(solution, result)); + } + + return retry(solution, problem, guard, configuration.retries(), attempt, + 0, new StringBuilder()); + } + + private static Solution complete( + Solution solution, + Attempt attempt + ) { + var failure = attempt.findFailure(); + if (failure.isPresent()) { + solution.setDebugData(failure.get()); + solution.abort(); + } else { + solution.setSolutionData(attempt.result()); + solution.complete(); + } + return solution; + } + + private static Mono> retry( + Solution solution, + ProblemT problem, + SolutionGuard guard, + int retries, + Supplier>> attempt, + int attemptIndex, + StringBuilder rejections + ) { + return attempt.get().flatMap(result -> { + Optional violation = result.findFailure() + .or(() -> guard.findViolation(problem, result.result())); + + if (violation.isEmpty()) { + solution.setSolutionData(result.result()); + if (!rejections.isEmpty()) { + solution.setDebugData(rejections.toString()); + } + solution.complete(); + return Mono.just(solution); + } + + result.sources().forEach(source -> source.rejectByGuard(violation.get())); + rejections.append("Guard rejected attempt ").append(attemptIndex + 1).append(": ") + .append(violation.get()).append('\n'); + + if (attemptIndex >= retries) { + rejections.append("No valid solution found after ").append(attemptIndex + 1) + .append(" attempt(s)."); + solution.setDebugData(rejections.toString()); + solution.abort(); + return Mono.just(solution); + } + + return retry(solution, problem, guard, retries, attempt, attemptIndex + 1, rejections); + }); + } +} diff --git a/src/main/java/edu/kit/provideq/toolbox/meta/guard/SolutionGuard.java b/src/main/java/edu/kit/provideq/toolbox/meta/guard/SolutionGuard.java new file mode 100644 index 00000000..5250bbd8 --- /dev/null +++ b/src/main/java/edu/kit/provideq/toolbox/meta/guard/SolutionGuard.java @@ -0,0 +1,8 @@ +package edu.kit.provideq.toolbox.meta.guard; + +import java.util.Optional; + +@FunctionalInterface +public interface SolutionGuard { + Optional findViolation(ProblemT problem, ResultT solution); +} diff --git a/src/main/java/edu/kit/provideq/toolbox/tsp/TspSolutionGuard.java b/src/main/java/edu/kit/provideq/toolbox/tsp/TspSolutionGuard.java new file mode 100644 index 00000000..a5611272 --- /dev/null +++ b/src/main/java/edu/kit/provideq/toolbox/tsp/TspSolutionGuard.java @@ -0,0 +1,103 @@ +package edu.kit.provideq.toolbox.tsp; + +import edu.kit.provideq.toolbox.meta.guard.SolutionGuard; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.regex.Pattern; + +public final class TspSolutionGuard { + private static final Pattern DIMENSION_PATTERN = + Pattern.compile("(?im)^\\s*DIMENSION\\s*:\\s*(\\d+)\\s*$"); + private static final Pattern TOUR_SECTION_PATTERN = + Pattern.compile("(?im)^\\s*TOUR_SECTION\\s*:?\\s*$"); + private static final String ROUTE_END = "-1"; + private static final String EOF = "EOF"; + + public static final SolutionGuard INSTANCE = TspSolutionGuard::findViolation; + + private TspSolutionGuard() { + } + + public static boolean isValid(String problem, String solution) { + return findViolation(problem, solution).isEmpty(); + } + + public static Optional findViolation(String problem, String solution) { + if (solution == null || solution.isBlank()) { + return Optional.of("The solution is empty."); + } + + var dimensionMatcher = DIMENSION_PATTERN.matcher(problem); + if (!dimensionMatcher.find()) { + return Optional.of("The problem does not declare a DIMENSION."); + } + final int dimension = Integer.parseInt(dimensionMatcher.group(1)); + + var tourSectionMatcher = TOUR_SECTION_PATTERN.matcher(solution); + if (!tourSectionMatcher.find()) { + return Optional.of("The solution does not contain a TOUR_SECTION."); + } + + List> routes; + try { + routes = parseRoutes(solution.substring(tourSectionMatcher.end())); + } catch (NumberFormatException e) { + return Optional.of("The TOUR_SECTION contains a non-integer entry: " + e.getMessage()); + } + + if (routes.size() != 1) { + return Optional.of("Expected exactly one route, but found " + routes.size() + "."); + } + + var route = routes.get(0); + var visited = new boolean[dimension + 1]; + for (int node : route) { + if (node < 1 || node > dimension) { + return Optional.of("Node " + node + " does not exist, nodes range from 1 to " + + dimension + "."); + } + if (visited[node]) { + return Optional.of("Node " + node + " is visited more than once."); + } + visited[node] = true; + } + + var missing = new ArrayList(); + for (int node = 1; node <= dimension; node++) { + if (!visited[node]) { + missing.add(node); + } + } + if (!missing.isEmpty()) { + return Optional.of("Nodes " + missing + " are not visited."); + } + + return Optional.empty(); + } + + private static List> parseRoutes(String tourSection) { + var routes = new ArrayList>(); + var currentRoute = new ArrayList(); + + for (var token : tourSection.trim().split("\\s+")) { + if (token.isEmpty() || token.equals(EOF)) { + break; + } + if (token.equals(ROUTE_END)) { + if (currentRoute.isEmpty()) { + break; + } + routes.add(currentRoute); + currentRoute = new ArrayList<>(); + continue; + } + currentRoute.add(Integer.parseInt(token)); + } + + if (!currentRoute.isEmpty()) { + routes.add(currentRoute); + } + return routes; + } +} diff --git a/src/main/java/edu/kit/provideq/toolbox/tsp/solvers/QuboTspSolver.java b/src/main/java/edu/kit/provideq/toolbox/tsp/solvers/QuboTspSolver.java index 5f86517b..193e5702 100644 --- a/src/main/java/edu/kit/provideq/toolbox/tsp/solvers/QuboTspSolver.java +++ b/src/main/java/edu/kit/provideq/toolbox/tsp/solvers/QuboTspSolver.java @@ -8,14 +8,18 @@ import edu.kit.provideq.toolbox.meta.SolvingProperties; import edu.kit.provideq.toolbox.meta.SubRoutineDefinition; import edu.kit.provideq.toolbox.meta.SubRoutineResolver; +import edu.kit.provideq.toolbox.meta.guard.Guard; +import edu.kit.provideq.toolbox.meta.setting.SolverSetting; import edu.kit.provideq.toolbox.process.DefaultProcessRunner; import edu.kit.provideq.toolbox.process.ProcessRunner; import edu.kit.provideq.toolbox.qubo.QuboConfiguration; +import edu.kit.provideq.toolbox.tsp.TspSolutionGuard; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.List; import java.util.Optional; +import java.util.UUID; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.ApplicationContext; @@ -35,6 +39,9 @@ public class QuboTspSolver extends TspSolver { true ); + private static final boolean DEFAULT_GUARDED = false; + private static final int DEFAULT_GUARD_RETRIES = 3; + private final ApplicationContext context; private final String binaryPath; private ResourceProvider resourceProvider; @@ -90,19 +97,31 @@ private String getProblemDirectory(Solution solutionObject) { return problemDirectoryPath; } + @Override + public List getSolverSettings() { + return Guard.createSettings( + "Check that the reconstructed tour visits every node exactly once. " + + "Invalid or missing tours are rejected instead of being returned.", + DEFAULT_GUARDED, + DEFAULT_GUARD_RETRIES); + } + @Override public Mono> solve( String input, SubRoutineResolver resolver, SolvingProperties properties ) { + var guardConfiguration = + Guard.readConfiguration(properties, DEFAULT_GUARDED, DEFAULT_GUARD_RETRIES); + var solution = new Solution<>(this); // change "TYPE" keyword from "TSP" to "CVRP" // add capacity declaration of "0" (is ignored later) // this is theoretically wrong, but needed for Lucas' QUBO converter to work String typeRegex = "(?i)\\btype\\s*:\\s*tsp\\b"; - input = input.replaceAll(typeRegex, "TYPE : CVRP\nCAPACITY : 0"); + String vrpInput = input.replaceAll(typeRegex, "TYPE : CVRP\nCAPACITY : 0"); // translate into qubo in lp-file format with rust vrp meta solver var processResult = context @@ -114,7 +133,7 @@ public Mono> solve( "simulated", "--transform-only" ) - .writeInputFile(input, "problem.vrp") + .writeInputFile(vrpInput, "problem.vrp") .readOutputFile("problem.lp") .run(getProblemType(), solution.getId()); @@ -133,25 +152,39 @@ public Mono> solve( } Path quboSolutionFilePath = Path.of(problemDirectoryPath, "problem.bin"); - String finalInput = input; - return resolver.runSubRoutine(QUBO_SUBROUTINE, output.get()) + return Guard.solve( + solution, + input, + TspSolutionGuard.INSTANCE, + guardConfiguration, + () -> solveAndReconstruct( + resolver, output.get(), vrpInput, quboSolutionFilePath, solution.getId())); + } + + private Mono> solveAndReconstruct( + SubRoutineResolver resolver, + String qubo, + String vrpInput, + Path quboSolutionFilePath, + UUID solutionId + ) { + return resolver.runSubRoutine(QUBO_SUBROUTINE, qubo) .publishOn(Schedulers.boundedElastic()) //avoids block from Files.writeString() in try/catch .map(subRoutineSolution -> { if (subRoutineSolution.getSolutionData() == null || subRoutineSolution.getSolutionData().isEmpty()) { - solution.setDebugData("Unable to process at least one Subroutine, " - + "because its SolutionData does not exist"); - solution.abort(); - return solution; + return Guard.Attempt.failed( + "Unable to process at least one Subroutine, " + + "because its SolutionData does not exist", + subRoutineSolution); } try { Files.writeString(quboSolutionFilePath, subRoutineSolution.getSolutionData()); } catch (IOException e) { - solution.setDebugData( - "Failed to write qubo solution file with path: " + quboSolutionFilePath); - solution.abort(); - return solution; + return Guard.Attempt.failed( + "Failed to write qubo solution file with path: " + quboSolutionFilePath, + subRoutineSolution); } var processRetransformResult = context @@ -163,21 +196,18 @@ public Mono> solve( "simulated", "--qubo-solution", quboSolutionFilePath.toString() ) - .writeInputFile(finalInput, "problem.vrp") + .writeInputFile(vrpInput, "problem.vrp") .readOutputFile("problem.sol") - .run(getProblemType(), solution.getId()); + .run(getProblemType(), solutionId); if (!processRetransformResult.success()) { - solution.setDebugData( - processRetransformResult.errorOutput().orElse("Unable to retransform result.")); - solution.abort(); - return solution; + return Guard.Attempt.failed( + processRetransformResult.errorOutput().orElse("Unable to retransform result."), + subRoutineSolution); } - solution.setSolutionData(processRetransformResult.output().orElse("Empty Solution")); - solution.complete(); - - return solution; + return Guard.Attempt.of( + processRetransformResult.output().orElse("Empty Solution"), subRoutineSolution); }); } } From b16d34d2382c8f74a24199738689d87a647b706a Mon Sep 17 00:00:00 2001 From: ekulos-code Date: Wed, 7 Oct 2026 19:22:25 +0200 Subject: [PATCH 5/5] Fix checkstyle --- .../edu/kit/provideq/toolbox/meta/strategy/StrategyStep.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/edu/kit/provideq/toolbox/meta/strategy/StrategyStep.java b/src/main/java/edu/kit/provideq/toolbox/meta/strategy/StrategyStep.java index c70bbb9b..afa8baaf 100644 --- a/src/main/java/edu/kit/provideq/toolbox/meta/strategy/StrategyStep.java +++ b/src/main/java/edu/kit/provideq/toolbox/meta/strategy/StrategyStep.java @@ -7,7 +7,7 @@ /** * A single transformation rule of a meta-solver strategy, a problem and the solver applied to it - * A step without a problem id stands for a sub-routine that hasn't been called yet + * A step without a problem id stands for a sub-routine that hasn't been called yet. */ public record StrategyStep( String problemId, @@ -18,7 +18,7 @@ public record StrategyStep( ) { /** * Flattens strategy formed by a problem and its sub-problems into pre-order - * so every step directly follows its parent + * so every step directly follows its parent. */ public static List collect(Problem problem) { var steps = new ArrayList();