From 58b99cf8a8c498113f5fdeb46f982369b95b7442 Mon Sep 17 00:00:00 2001 From: nickp Date: Sun, 3 Sep 2023 16:06:55 +0200 Subject: [PATCH 01/18] Initial draft for generated documentation --- .../toolbox/api/MetaSolverSettingsRouter.java | 47 ++++- .../kit/provideq/toolbox/api/SolveRouter.java | 164 ++++++++++++++++-- .../provideq/toolbox/api/SolversRouter.java | 55 ++++-- .../toolbox/api/SubRoutineRouter.java | 68 ++++++-- .../featuremodel/ExtendedUvlFeatureModel.java | 39 +++++ .../anomaly/dead/DeadFeatureMetaSolver.java | 6 + .../voidmodel/VoidFeatureMetaSolver.java | 6 + .../toolbox/maxcut/MetaSolverMaxCut.java | 33 ++++ .../kit/provideq/toolbox/meta/MetaSolver.java | 4 + .../provideq/toolbox/sat/MetaSolverSat.java | 8 + 10 files changed, 379 insertions(+), 51 deletions(-) create mode 100644 src/main/java/edu/kit/provideq/toolbox/featuremodel/ExtendedUvlFeatureModel.java diff --git a/src/main/java/edu/kit/provideq/toolbox/api/MetaSolverSettingsRouter.java b/src/main/java/edu/kit/provideq/toolbox/api/MetaSolverSettingsRouter.java index db4304a7..0eafe1bf 100644 --- a/src/main/java/edu/kit/provideq/toolbox/api/MetaSolverSettingsRouter.java +++ b/src/main/java/edu/kit/provideq/toolbox/api/MetaSolverSettingsRouter.java @@ -8,10 +8,13 @@ import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; import static org.springframework.web.reactive.function.server.ServerResponse.ok; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import edu.kit.provideq.toolbox.MetaSolverProvider; import edu.kit.provideq.toolbox.meta.MetaSolver; import edu.kit.provideq.toolbox.meta.ProblemType; import edu.kit.provideq.toolbox.meta.setting.MetaSolverSetting; +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; @@ -51,18 +54,46 @@ private RouterFunction defineMetaSolverSettingsRouteForMetaSolve return route().GET( getRouteForProblemType(problemType), req -> handleMetaSolverSettingsRouteForMetaSolver(metaSolver), - ops -> ops + ops -> handleMetaSolverSettingsRouteDocumentation(ops, metaSolver) + ).build(); + } + + private void handleMetaSolverSettingsRouteDocumentation( + Builder ops, MetaSolver metaSolver) { + var problemType = metaSolver.getProblemType(); + ops .operationId(getRouteForProblemType(problemType)) .tag(problemType.getId()) - .response(responseBuilder() - .responseCode(String.valueOf(HttpStatus.OK.value())) - .content(contentBuilder() + .response(getResponseOk(metaSolver)) + .response(getResponseNotFound()); + } + + private static org.springdoc.core.fn.builders.apiresponse.Builder getResponseOk( + MetaSolver metaSolver) { + String example; + try { + example = new ObjectMapper().writeValueAsString(metaSolver.getSettings()); + } catch (JsonProcessingException e) { + example = "Error: example could not be parsed"; + } + + return responseBuilder() + .responseCode(String.valueOf(HttpStatus.OK.value())) + .content(contentBuilder() .mediaType(APPLICATION_JSON_VALUE) + .example(org.springdoc.core.fn.builders.exampleobject.Builder + .exampleOjectBuilder() + .name(metaSolver.getProblemType().getId()) + .value(example)) .array(arraySchemaBuilder().schema( - schemaBuilder().implementation(MetaSolverSetting.class))) - ) - ) - ).build(); + schemaBuilder().implementation(MetaSolverSetting.class)) + ) + ); + } + + private static org.springdoc.core.fn.builders.apiresponse.Builder getResponseNotFound() { + return responseBuilder() + .responseCode(String.valueOf(HttpStatus.NOT_FOUND.value())); } private Mono handleMetaSolverSettingsRouteForMetaSolver( diff --git a/src/main/java/edu/kit/provideq/toolbox/api/SolveRouter.java b/src/main/java/edu/kit/provideq/toolbox/api/SolveRouter.java index 54b7c370..18c0a37a 100644 --- a/src/main/java/edu/kit/provideq/toolbox/api/SolveRouter.java +++ b/src/main/java/edu/kit/provideq/toolbox/api/SolveRouter.java @@ -1,6 +1,7 @@ package edu.kit.provideq.toolbox.api; import static org.springdoc.core.fn.builders.apiresponse.Builder.responseBuilder; +import static org.springdoc.core.fn.builders.arrayschema.Builder.arraySchemaBuilder; 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.requestbody.Builder.requestBodyBuilder; @@ -11,12 +12,19 @@ import static org.springframework.web.reactive.function.server.RequestPredicates.accept; import static org.springframework.web.reactive.function.server.ServerResponse.ok; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import edu.kit.provideq.toolbox.MetaSolverProvider; import edu.kit.provideq.toolbox.Solution; import edu.kit.provideq.toolbox.SolveRequest; import edu.kit.provideq.toolbox.meta.MetaSolver; +import edu.kit.provideq.toolbox.meta.ProblemSolver; import edu.kit.provideq.toolbox.meta.ProblemType; +import edu.kit.provideq.toolbox.meta.SubRoutineDefinition; import io.swagger.v3.oas.annotations.enums.ParameterIn; +import java.util.function.Consumer; +import java.util.stream.Collectors; +import org.springdoc.core.fn.builders.operation.Builder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.ParameterizedTypeReference; @@ -57,26 +65,11 @@ RouterFunction getSolveRoutes() { } private RouterFunction defineRouteForMetaSolver(MetaSolver metaSolver) { - var problemType = metaSolver.getProblemType(); return route().POST( - getSolveRouteForProblemType(problemType), + getSolveRouteForProblemType(metaSolver.getProblemType()), accept(APPLICATION_JSON), req -> handleRouteForMetaSolver(metaSolver, req), - ops -> ops - .operationId(getSolveRouteForProblemType(problemType)) - .tag(problemType.getId()) - .requestBody(requestBodyBuilder() - .content(contentBuilder() - .schema(schemaBuilder().implementation( - metaSolver.getProblemType().getRequestType())) - .mediaType(APPLICATION_JSON_VALUE) - ) - .required(true) - ) - .response(responseBuilder() - .responseCode(String.valueOf(HttpStatus.OK.value())) - .implementation(Solution.class) - ) + ops -> handleRouteDocumentation(metaSolver, ops) ).build(); } @@ -141,6 +134,143 @@ private Mono handleSolutionRouteForMetaSolver(MetaSolver metaSolver, Builder ops) { + var problemType = metaSolver.getProblemType(); + ops + .operationId(getSolveRouteForProblemType(problemType)) + .tag(problemType.getId()) + .requestBody(requestBodyBuilder() + .content(getRequestContent(metaSolver)) + .required(true)) + .response(getResponseOk(metaSolver)) + .response(getResponseNotFound()); + } + + private static org.springdoc.core.fn.builders.apiresponse.Builder getResponseOk( + MetaSolver metaSolver) { + return responseBuilder() + .responseCode(String.valueOf(HttpStatus.OK.value())) + .content(contentBuilder() + .mediaType(APPLICATION_JSON_VALUE) + .example(getExampleSolved(metaSolver)) + .example(getExampleInvalid(metaSolver)) + .array(arraySchemaBuilder().schema( + schemaBuilder().implementation(Solution.class)))); + } + + private static org.springdoc.core.fn.builders.exampleobject.Builder getExampleSolved( + MetaSolver metaSolver) { + return getExampleOk( + "Solved", + metaSolver, + solution -> { + solution.setSolutionData("Solution data to solve the problem"); + solution.complete(); + }); + } + + private static org.springdoc.core.fn.builders.exampleobject.Builder getExampleInvalid( + MetaSolver metaSolver) { + return getExampleOk( + "Error", + metaSolver, + solution -> { + solution.setDebugData("Some error occurred"); + solution.abort(); + }); + } + + private static org.springdoc.core.fn.builders.exampleobject.Builder getExampleOk( + String exampleName, + MetaSolver metaSolver, + Consumer> solutionModifier) { + // Prepare a solved solution with some example data + var solvedSolution = new Solution(42); + solvedSolution.setExecutionMilliseconds(42); + metaSolver.getAllSolvers().stream() + .findFirst() + .ifPresent(solver -> solvedSolution.setSolverName(solver.getName())); + solutionModifier.accept(solvedSolution); + + // Convert the solution to a string + String solvedSolutionString; + try { + solvedSolutionString = new ObjectMapper().writeValueAsString(solvedSolution); + } catch (JsonProcessingException e) { + solvedSolutionString = "Error: example could not be parsed"; + } + + // Build the example + return org.springdoc.core.fn.builders.exampleobject.Builder + .exampleOjectBuilder() + .name(exampleName) + .description("The problem was solved successfully.") + .value(solvedSolutionString); + } + + private static org.springdoc.core.fn.builders.apiresponse.Builder getResponseNotFound() { + return responseBuilder() + .responseCode(String.valueOf(HttpStatus.NOT_FOUND.value())); + } + + private org.springdoc.core.fn.builders.content.Builder getRequestContent( + MetaSolver metaSolver) { + String content = metaSolver.getExampleProblems() + .stream().findFirst() + .map(e -> { + if (e instanceof String) { + return (String) e; + } + + try { + return new ObjectMapper().writeValueAsString(e); + } catch (JsonProcessingException exception) { + return "Error: example could not be parsed"; + } + }) + .orElse("Error: no example available"); + + var request = new SolveRequest(); + request.requestContent = content; + request.requestedMetaSolverSettings = metaSolver.getSettings(); + + metaSolver.getAllSolvers().stream() + .findFirst() + .ifPresentOrElse(solver -> { + request.requestedSolverId = solver.getId(); + request.requestedSubSolveRequests = solver.getSubRoutines().stream() + .collect(Collectors.toMap( + SubRoutineDefinition::type, + subRoutine -> { + var subSolveRequest = new SolveRequest<>(); + + subSolveRequest.requestedSolverId = metaSolverProvider + .getMetaSolver(subRoutine.type()) + .getAllSolvers().stream() + .findFirst() + .map(ProblemSolver::getId) + .orElse(""); + return subSolveRequest; + })); + }, () -> request.requestedSolverId = "Error: no solver found"); + + String requestString; + try { + requestString = new ObjectMapper().writeValueAsString(request); + } catch (JsonProcessingException exception) { + requestString = "Error: no example available"; + } + + var problemType = metaSolver.getProblemType(); + return contentBuilder() + .example(org.springdoc.core.fn.builders.exampleobject.Builder.exampleOjectBuilder() + .name(problemType.getId()) + .value(requestString)) + .schema(schemaBuilder().implementation( + problemType.getRequestType())) + .mediaType(APPLICATION_JSON_VALUE); + } + private String getSolveRouteForProblemType(ProblemType type) { return "/solve/" + type.getId(); } 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 a9bc93a4..09786aec 100644 --- a/src/main/java/edu/kit/provideq/toolbox/api/SolversRouter.java +++ b/src/main/java/edu/kit/provideq/toolbox/api/SolversRouter.java @@ -8,10 +8,14 @@ import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; import static org.springframework.web.reactive.function.server.ServerResponse.ok; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import edu.kit.provideq.toolbox.MetaSolverProvider; import edu.kit.provideq.toolbox.ProblemSolverInfo; import edu.kit.provideq.toolbox.meta.MetaSolver; import edu.kit.provideq.toolbox.meta.ProblemType; +import java.util.List; +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; @@ -52,29 +56,52 @@ private RouterFunction defineSolversRouteForMetaSolver( return route().GET( getSolversRouteForProblemType(problemType), req -> handleSolversRouteForMetaSolver(metaSolver), - ops -> ops - .operationId(getSolversRouteForProblemType(problemType)) - .tag(problemType.getId()) - .response(responseBuilder() - .responseCode(String.valueOf(HttpStatus.OK.value())) - .content(contentBuilder() - .mediaType(APPLICATION_JSON_VALUE) - .array(arraySchemaBuilder().schema( - schemaBuilder().implementation(ProblemSolverInfo.class))) - ) - ) + ops -> handleSolversRouteDocumentation(ops, metaSolver) ).build(); } private Mono handleSolversRouteForMetaSolver(MetaSolver metaSolver) { - var solvers = metaSolver.getAllSolvers().stream() - .map(solver -> new ProblemSolverInfo(solver.getId(), solver.getName())) - .toList(); + var solvers = getAllSolverInfos(metaSolver); return ok().body(Mono.just(solvers), new ParameterizedTypeReference<>() { }); } + private static List getAllSolverInfos(MetaSolver metaSolver) { + return metaSolver.getAllSolvers().stream() + .map(solver -> new ProblemSolverInfo(solver.getId(), solver.getName())) + .toList(); + } + + private void handleSolversRouteDocumentation(Builder ops, MetaSolver metaSolver) { + ops + .operationId(getSolversRouteForProblemType(metaSolver.getProblemType())) + .tag(metaSolver.getProblemType().getId()) + .response(responseBuilder() + .responseCode(String.valueOf(HttpStatus.OK.value())) + .content(getOkResponseContent(metaSolver)) + ); + } + + private static org.springdoc.core.fn.builders.content.Builder getOkResponseContent( + MetaSolver metaSolver) { + var allSolvers = getAllSolverInfos(metaSolver); + String example; + try { + example = new ObjectMapper().writeValueAsString(allSolvers); + } catch (JsonProcessingException e) { + example = "Error: solvers could not be parsed"; + } + + return contentBuilder() + .mediaType(APPLICATION_JSON_VALUE) + .example(org.springdoc.core.fn.builders.exampleobject.Builder.exampleOjectBuilder() + .name(metaSolver.getProblemType().getId()) + .value(example)) + .array(arraySchemaBuilder().schema( + schemaBuilder().implementation(ProblemSolverInfo.class))); + } + private String getSolversRouteForProblemType(ProblemType type) { return "/solvers/" + type.getId(); } diff --git a/src/main/java/edu/kit/provideq/toolbox/api/SubRoutineRouter.java b/src/main/java/edu/kit/provideq/toolbox/api/SubRoutineRouter.java index 8e56cc4b..94112d87 100644 --- a/src/main/java/edu/kit/provideq/toolbox/api/SubRoutineRouter.java +++ b/src/main/java/edu/kit/provideq/toolbox/api/SubRoutineRouter.java @@ -9,12 +9,15 @@ import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; import static org.springframework.web.reactive.function.server.ServerResponse.ok; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import edu.kit.provideq.toolbox.MetaSolverProvider; import edu.kit.provideq.toolbox.meta.MetaSolver; import edu.kit.provideq.toolbox.meta.ProblemSolver; import edu.kit.provideq.toolbox.meta.ProblemType; import edu.kit.provideq.toolbox.meta.SubRoutineDefinition; import io.swagger.v3.oas.annotations.enums.ParameterIn; +import org.springdoc.core.fn.builders.content.Builder; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -57,18 +60,7 @@ private RouterFunction defineSubRoutineRouteForMetaSolver( return route().GET( getSubRoutinesRouteForProblemType(problemType), req -> handleSubRoutineRouteForMetaSolver(metaSolver, req), - ops -> ops - .operationId(getSubRoutinesRouteForProblemType(problemType)) - .parameter(parameterBuilder().in(ParameterIn.QUERY).name("id")) - .tag(problemType.getId()) - .response(responseBuilder() - .responseCode(String.valueOf(HttpStatus.OK.value())) - .content(contentBuilder() - .mediaType(APPLICATION_JSON_VALUE) - .array(arraySchemaBuilder().schema( - schemaBuilder().implementation(SubRoutineDefinition.class))) - ) - ) + ops -> handleSubRoutineRouteDocumentation(metaSolver, ops) ).build(); } @@ -84,6 +76,58 @@ private Mono handleSubRoutineRouteForMetaSolver(MetaSolver metaSolver, org.springdoc.core.fn.builders.operation.Builder ops) { + ProblemType problemType = metaSolver.getProblemType(); + ops.operationId(getSubRoutinesRouteForProblemType(problemType)) + .parameter(getParameterBuilder(metaSolver)) + .tag(problemType.getId()) + .response(responseBuilder() + .responseCode(String.valueOf(HttpStatus.OK.value())) + .content(getOkResponseContent(metaSolver))) + .response(responseBuilder() + .responseCode(String.valueOf(HttpStatus.NOT_FOUND.value()))); + } + + private static org.springdoc.core.fn.builders.parameter.Builder + getParameterBuilder(MetaSolver metaSolver) { + return parameterBuilder() + .in(ParameterIn.QUERY) + .name("id") + .description("The id of the solver to get the sub-routines from." + + " Use the endpoint GET /solvers/" + metaSolver.getProblemType().getId() + + " to get a list of available solver ids.") + .required(true) + .example(metaSolver + .getAllSolvers().stream() + .findFirst() + .map(ProblemSolver::getId) + .orElse("Error: no solver found")); + } + + private static Builder getOkResponseContent(MetaSolver metaSolver) { + String example = metaSolver + .getAllSolvers().stream() + .findFirst() + .map(solver -> { + var subRoutines = solver.getSubRoutines(); + try { + return new ObjectMapper().writeValueAsString(subRoutines); + } catch (JsonProcessingException e) { + return "Error: example could not be parsed"; + } + }) + .orElse("Error: no solver found"); + + return contentBuilder() + .mediaType(APPLICATION_JSON_VALUE) + .example(org.springdoc.core.fn.builders.exampleobject.Builder.exampleOjectBuilder() + .name(metaSolver.getProblemType().getId()) + .value(example)) + .array(arraySchemaBuilder().schema( + schemaBuilder().implementation(SubRoutineDefinition.class))); + } + private String getSubRoutinesRouteForProblemType(ProblemType type) { return "/sub-routines/" + type.getId(); } diff --git a/src/main/java/edu/kit/provideq/toolbox/featuremodel/ExtendedUvlFeatureModel.java b/src/main/java/edu/kit/provideq/toolbox/featuremodel/ExtendedUvlFeatureModel.java new file mode 100644 index 00000000..c3e383e0 --- /dev/null +++ b/src/main/java/edu/kit/provideq/toolbox/featuremodel/ExtendedUvlFeatureModel.java @@ -0,0 +1,39 @@ +package edu.kit.provideq.toolbox.featuremodel; + +import java.util.List; + +public class ExtendedUvlFeatureModel { + public static List getExamples() { + return List.of(""" + namespace Sandwich + + features + Sandwich {extended__} \s + mandatory + Bread \s + alternative + "Full Grain" {Calories 203, Price 1.99, Organic true} + Flatbread {Calories 90, Price 0.79, Organic true} + Toast {Calories 250, Price 0.99, Organic false} + optional + Cheese \s + optional + Gouda \s + alternative + Sprinkled {Fat {value 35, unit "g"}} + Slice {Fat {value 35, unit "g"}} + Cheddar + "Cream Cheese" + Meat \s + or + "Salami" {Producer "Farmer Bob"} + Ham {Producer "Farmer Sam"} + "Chicken Breast" {Producer "Farmer Sam"} + Vegetables \s + optional + "Cucumber" + Tomatoes + Lettuce + """); + } +} diff --git a/src/main/java/edu/kit/provideq/toolbox/featuremodel/anomaly/dead/DeadFeatureMetaSolver.java b/src/main/java/edu/kit/provideq/toolbox/featuremodel/anomaly/dead/DeadFeatureMetaSolver.java index e100718a..5a3a51dc 100644 --- a/src/main/java/edu/kit/provideq/toolbox/featuremodel/anomaly/dead/DeadFeatureMetaSolver.java +++ b/src/main/java/edu/kit/provideq/toolbox/featuremodel/anomaly/dead/DeadFeatureMetaSolver.java @@ -1,5 +1,6 @@ package edu.kit.provideq.toolbox.featuremodel.anomaly.dead; +import edu.kit.provideq.toolbox.featuremodel.ExtendedUvlFeatureModel; import edu.kit.provideq.toolbox.meta.MetaSolver; import edu.kit.provideq.toolbox.meta.Problem; import edu.kit.provideq.toolbox.meta.ProblemSolver; @@ -24,4 +25,9 @@ public ProblemSolver findSolver(Problem problem, // we only have one solver at this point return getAllSolvers().stream().findAny().orElseThrow(); } + + @Override + public List getExampleProblems() { + return ExtendedUvlFeatureModel.getExamples(); + } } diff --git a/src/main/java/edu/kit/provideq/toolbox/featuremodel/anomaly/voidmodel/VoidFeatureMetaSolver.java b/src/main/java/edu/kit/provideq/toolbox/featuremodel/anomaly/voidmodel/VoidFeatureMetaSolver.java index bdac824c..1fa177bd 100644 --- a/src/main/java/edu/kit/provideq/toolbox/featuremodel/anomaly/voidmodel/VoidFeatureMetaSolver.java +++ b/src/main/java/edu/kit/provideq/toolbox/featuremodel/anomaly/voidmodel/VoidFeatureMetaSolver.java @@ -1,5 +1,6 @@ package edu.kit.provideq.toolbox.featuremodel.anomaly.voidmodel; +import edu.kit.provideq.toolbox.featuremodel.ExtendedUvlFeatureModel; import edu.kit.provideq.toolbox.meta.MetaSolver; import edu.kit.provideq.toolbox.meta.Problem; import edu.kit.provideq.toolbox.meta.ProblemSolver; @@ -24,4 +25,9 @@ public ProblemSolver findSolver(Problem problem, // we only have one solver at this point return getAllSolvers().stream().findAny().orElseThrow(); } + + @Override + public List getExampleProblems() { + return ExtendedUvlFeatureModel.getExamples(); + } } diff --git a/src/main/java/edu/kit/provideq/toolbox/maxcut/MetaSolverMaxCut.java b/src/main/java/edu/kit/provideq/toolbox/maxcut/MetaSolverMaxCut.java index 2b8a921f..7988b9ae 100644 --- a/src/main/java/edu/kit/provideq/toolbox/maxcut/MetaSolverMaxCut.java +++ b/src/main/java/edu/kit/provideq/toolbox/maxcut/MetaSolverMaxCut.java @@ -33,4 +33,37 @@ public MaxCutSolver findSolver( List metaSolverSettings) { return (new ArrayList<>(this.solvers)).get((new Random()).nextInt(this.solvers.size())); } + + @Override + public List getExampleProblems() { + return List.of(""" + graph [ + id 42 + node [ + id 1 + label "1" + ] + node [ + id 2 + label "2" + ] + node [ + id 3 + label "3" + ] + edge [ + source 1 + target 2 + ] + edge [ + source 2 + target 3 + ] + edge [ + source 3 + target 1 + ] + ]""" + ); + } } diff --git a/src/main/java/edu/kit/provideq/toolbox/meta/MetaSolver.java b/src/main/java/edu/kit/provideq/toolbox/meta/MetaSolver.java index ab6be8b9..9568561b 100644 --- a/src/main/java/edu/kit/provideq/toolbox/meta/MetaSolver.java +++ b/src/main/java/edu/kit/provideq/toolbox/meta/MetaSolver.java @@ -125,4 +125,8 @@ public Solution solve(SolveRequest request) { return solution; } + + public List getExampleProblems() { + return List.of(); + } } diff --git a/src/main/java/edu/kit/provideq/toolbox/sat/MetaSolverSat.java b/src/main/java/edu/kit/provideq/toolbox/sat/MetaSolverSat.java index 9cdfa142..caef6ab1 100644 --- a/src/main/java/edu/kit/provideq/toolbox/sat/MetaSolverSat.java +++ b/src/main/java/edu/kit/provideq/toolbox/sat/MetaSolverSat.java @@ -30,4 +30,12 @@ public SatSolver findSolver(Problem problem, List met // todo add decision return (new ArrayList<>(this.solvers)).get((new Random()).nextInt(this.solvers.size())); } + + @Override + public List getExampleProblems() { + return List.of( + "a and b", + "a and b or c" + ); + } } From 584df087b754e2000961fa5956040722001db9cf Mon Sep 17 00:00:00 2001 From: nickp Date: Sun, 3 Sep 2023 16:15:33 +0200 Subject: [PATCH 02/18] Adjust tests to automatically use all solvers --- .../api/FeatureModelAnomalySolverTest.java | 23 +++++++++++++------ .../toolbox/api/MaxCutSolversTest.java | 15 +++++++----- .../provideq/toolbox/api/SatSolverTest.java | 13 +++++++---- 3 files changed, 34 insertions(+), 17 deletions(-) diff --git a/src/test/java/edu/kit/provideq/toolbox/api/FeatureModelAnomalySolverTest.java b/src/test/java/edu/kit/provideq/toolbox/api/FeatureModelAnomalySolverTest.java index 47b51689..91e48585 100644 --- a/src/test/java/edu/kit/provideq/toolbox/api/FeatureModelAnomalySolverTest.java +++ b/src/test/java/edu/kit/provideq/toolbox/api/FeatureModelAnomalySolverTest.java @@ -19,6 +19,7 @@ import edu.kit.provideq.toolbox.sat.MetaSolverSat; import edu.kit.provideq.toolbox.sat.solvers.GamsSatSolver; import java.util.stream.Stream; +import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -30,6 +31,7 @@ import org.springframework.test.web.reactive.server.WebTestClient; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) @WebFluxTest @Import(value = { SolveRouter.class, @@ -48,13 +50,20 @@ class FeatureModelAnomalySolverTest { @Autowired private WebTestClient client; - static Stream provideAnomalySolverIds() { - return Stream.of( - Arguments.of(SatBasedVoidFeatureSolver.class, - ProblemType.FEATURE_MODEL_ANOMALY_VOID, SOLVED), - Arguments.of(SatBasedDeadFeatureSolver.class, - ProblemType.FEATURE_MODEL_ANOMALY_DEAD, SOLVED) - ); + @Autowired + private VoidFeatureMetaSolver voidMetaSolver; + + @Autowired + private DeadFeatureMetaSolver deadFeatureMetaSolver; + + Stream provideAnomalySolverIds() { + return Stream.concat( + voidMetaSolver.getAllSolvers() + .stream() + .map(x -> Arguments.of(x.getClass().getName(), ProblemType.FEATURE_MODEL_ANOMALY_VOID, SOLVED)), + deadFeatureMetaSolver.getAllSolvers() + .stream() + .map(x -> Arguments.of(x.getClass().getName(), ProblemType.FEATURE_MODEL_ANOMALY_DEAD, SOLVED))); } @ParameterizedTest diff --git a/src/test/java/edu/kit/provideq/toolbox/api/MaxCutSolversTest.java b/src/test/java/edu/kit/provideq/toolbox/api/MaxCutSolversTest.java index 25e73607..df150aa4 100644 --- a/src/test/java/edu/kit/provideq/toolbox/api/MaxCutSolversTest.java +++ b/src/test/java/edu/kit/provideq/toolbox/api/MaxCutSolversTest.java @@ -17,6 +17,7 @@ import java.time.Duration; import java.util.stream.Stream; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import org.springframework.beans.factory.annotation.Autowired; @@ -26,6 +27,7 @@ import org.springframework.http.MediaType; import org.springframework.test.web.reactive.server.WebTestClient; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) @WebFluxTest @Import(value = { SolveRouter.class, @@ -44,6 +46,9 @@ class MaxCutSolversTest { @Autowired private WebTestClient client; + @Autowired + private MetaSolverMaxCut metaSolverMaxCut; + @BeforeEach void beforeEach() { this.client = this.client.mutate() @@ -51,12 +56,10 @@ void beforeEach() { .build(); } - static Stream provideMaxCutSolverIds() { - return Stream.of( - GamsMaxCutSolver.class.getName(), - QiskitMaxCutSolver.class.getName(), - CirqMaxCutSolver.class.getName() - ); + Stream provideMaxCutSolverIds() { + return metaSolverMaxCut.getAllSolvers() + .stream() + .map(x -> x.getClass().getName()); } @ParameterizedTest diff --git a/src/test/java/edu/kit/provideq/toolbox/api/SatSolverTest.java b/src/test/java/edu/kit/provideq/toolbox/api/SatSolverTest.java index 38d1adb0..c68fc19b 100644 --- a/src/test/java/edu/kit/provideq/toolbox/api/SatSolverTest.java +++ b/src/test/java/edu/kit/provideq/toolbox/api/SatSolverTest.java @@ -12,6 +12,7 @@ import edu.kit.provideq.toolbox.sat.SolveSatRequest; import edu.kit.provideq.toolbox.sat.solvers.GamsSatSolver; import java.util.stream.Stream; +import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import org.springframework.beans.factory.annotation.Autowired; @@ -21,6 +22,7 @@ import org.springframework.http.MediaType; import org.springframework.test.web.reactive.server.WebTestClient; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) @WebFluxTest @Import(value = { SolveRouter.class, @@ -35,10 +37,13 @@ class SatSolverTest { @Autowired private WebTestClient client; - static Stream provideSatSolverIds() { - return Stream.of( - GamsSatSolver.class.getName() - ); + @Autowired + private MetaSolverSat metaSolverSat; + + Stream provideSatSolverIds() { + return metaSolverSat.getAllSolvers() + .stream() + .map(x -> x.getClass().getName()); } @ParameterizedTest From 4c06aaf4ec52906ab0e2246b506b0d8268011f10 Mon Sep 17 00:00:00 2001 From: nickp Date: Sun, 3 Sep 2023 16:35:27 +0200 Subject: [PATCH 03/18] Use example content in tests --- .../api/FeatureModelAnomalySolverTest.java | 69 ++++++++----------- .../toolbox/api/MaxCutSolversTest.java | 48 ++++--------- .../provideq/toolbox/api/SatSolverTest.java | 20 ++++-- 3 files changed, 57 insertions(+), 80 deletions(-) diff --git a/src/test/java/edu/kit/provideq/toolbox/api/FeatureModelAnomalySolverTest.java b/src/test/java/edu/kit/provideq/toolbox/api/FeatureModelAnomalySolverTest.java index 91e48585..7cde2d27 100644 --- a/src/test/java/edu/kit/provideq/toolbox/api/FeatureModelAnomalySolverTest.java +++ b/src/test/java/edu/kit/provideq/toolbox/api/FeatureModelAnomalySolverTest.java @@ -3,6 +3,7 @@ import static edu.kit.provideq.toolbox.SolutionStatus.SOLVED; import static org.hamcrest.Matchers.is; +import com.google.common.collect.Lists; import edu.kit.provideq.toolbox.GamsProcessRunner; import edu.kit.provideq.toolbox.MetaSolverProvider; import edu.kit.provideq.toolbox.ResourceProvider; @@ -56,55 +57,41 @@ class FeatureModelAnomalySolverTest { @Autowired private DeadFeatureMetaSolver deadFeatureMetaSolver; - Stream provideAnomalySolverIds() { - return Stream.concat( - voidMetaSolver.getAllSolvers() - .stream() - .map(x -> Arguments.of(x.getClass().getName(), ProblemType.FEATURE_MODEL_ANOMALY_VOID, SOLVED)), - deadFeatureMetaSolver.getAllSolvers() - .stream() - .map(x -> Arguments.of(x.getClass().getName(), ProblemType.FEATURE_MODEL_ANOMALY_DEAD, SOLVED))); + Stream provideArguments() { + // Void arguments + var voidSolvers = voidMetaSolver.getAllSolvers() + .stream() + .map(x -> x.getClass().getName()) + .toList(); + var voidProblems = voidMetaSolver.getExampleProblems(); + + var voidArguments = Lists.cartesianProduct(voidSolvers, voidProblems).stream() + .map(list -> Arguments.of(list.get(0), ProblemType.FEATURE_MODEL_ANOMALY_VOID, SOLVED, list.get(1))); + + // Dead arguments + var deadSolvers = deadFeatureMetaSolver.getAllSolvers() + .stream() + .map(x -> x.getClass().getName()) + .toList(); + var deadProblems = deadFeatureMetaSolver.getExampleProblems(); + + var deadArguments = Lists.cartesianProduct(deadSolvers, deadProblems).stream() + .map(list -> Arguments.of(list.get(0), ProblemType.FEATURE_MODEL_ANOMALY_DEAD, SOLVED, list.get(1))); + + // Return combined stream + return Stream.concat(voidArguments, deadArguments) ; } @ParameterizedTest - @MethodSource("provideAnomalySolverIds") + @MethodSource("provideArguments") void testFeatureModelAnomalySolver( Class> solver, ProblemType anomalyType, - SolutionStatus expectedStatus) { + SolutionStatus expectedStatus, + String content) { var req = new SolveFeatureModelRequest(); req.requestedSolverId = solver.getName(); - req.requestContent = """ - namespace Sandwich - - features - Sandwich {extended__} \s - mandatory - Bread \s - alternative - "Full Grain" {Calories 203, Price 1.99, Organic true} - Flatbread {Calories 90, Price 0.79, Organic true} - Toast {Calories 250, Price 0.99, Organic false} - optional - Cheese \s - optional - Gouda \s - alternative - Sprinkled {Fat {value 35, unit "g"}} - Slice {Fat {value 35, unit "g"}} - Cheddar - "Cream Cheese" - Meat \s - or - "Salami" {Producer "Farmer Bob"} - Ham {Producer "Farmer Sam"} - "Chicken Breast" {Producer "Farmer Sam"} - Vegetables \s - optional - "Cucumber" - Tomatoes - Lettuce - """; + req.requestContent = content; var response = client.post() .uri("/solve/" + anomalyType.getId()) diff --git a/src/test/java/edu/kit/provideq/toolbox/api/MaxCutSolversTest.java b/src/test/java/edu/kit/provideq/toolbox/api/MaxCutSolversTest.java index df150aa4..f56b24f7 100644 --- a/src/test/java/edu/kit/provideq/toolbox/api/MaxCutSolversTest.java +++ b/src/test/java/edu/kit/provideq/toolbox/api/MaxCutSolversTest.java @@ -3,6 +3,7 @@ import static edu.kit.provideq.toolbox.SolutionStatus.SOLVED; import static org.hamcrest.Matchers.is; +import com.google.common.collect.Lists; import edu.kit.provideq.toolbox.GamsProcessRunner; import edu.kit.provideq.toolbox.MetaSolverProvider; import edu.kit.provideq.toolbox.PythonProcessRunner; @@ -15,10 +16,12 @@ import edu.kit.provideq.toolbox.maxcut.solvers.GamsMaxCutSolver; import edu.kit.provideq.toolbox.maxcut.solvers.QiskitMaxCutSolver; import java.time.Duration; +import java.util.List; import java.util.stream.Stream; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest; @@ -56,45 +59,24 @@ void beforeEach() { .build(); } - Stream provideMaxCutSolverIds() { - return metaSolverMaxCut.getAllSolvers() + Stream provideArguments() { + var solvers = metaSolverMaxCut.getAllSolvers() .stream() - .map(x -> x.getClass().getName()); + .map(x -> x.getClass().getName()) + .toList(); + + var problems = metaSolverMaxCut.getExampleProblems(); + + return Lists.cartesianProduct(solvers, problems).stream() + .map(list -> Arguments.of(list.get(0), list.get(1))); } @ParameterizedTest - @MethodSource("provideMaxCutSolverIds") - void testMaxCutSolver(String solverId) { + @MethodSource("provideArguments") + void testMaxCutSolver(String solverId, String content) { var req = new SolveMaxCutRequest(); req.requestedSolverId = solverId; - req.requestContent = """ - graph [ - id 42 - node [ - id 1 - label "1" - ] - node [ - id 2 - label "2" - ] - node [ - id 3 - label "3" - ] - edge [ - source 1 - target 2 - ] - edge [ - source 2 - target 3 - ] - edge [ - source 3 - target 1 - ] - ]"""; + req.requestContent = content; var response = client.post() .uri("/solve/max-cut") diff --git a/src/test/java/edu/kit/provideq/toolbox/api/SatSolverTest.java b/src/test/java/edu/kit/provideq/toolbox/api/SatSolverTest.java index c68fc19b..72a58f99 100644 --- a/src/test/java/edu/kit/provideq/toolbox/api/SatSolverTest.java +++ b/src/test/java/edu/kit/provideq/toolbox/api/SatSolverTest.java @@ -3,6 +3,7 @@ import static edu.kit.provideq.toolbox.SolutionStatus.SOLVED; import static org.hamcrest.Matchers.is; +import com.google.common.collect.Lists; import edu.kit.provideq.toolbox.GamsProcessRunner; import edu.kit.provideq.toolbox.MetaSolverProvider; import edu.kit.provideq.toolbox.ResourceProvider; @@ -14,6 +15,7 @@ import java.util.stream.Stream; import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest; @@ -40,18 +42,24 @@ class SatSolverTest { @Autowired private MetaSolverSat metaSolverSat; - Stream provideSatSolverIds() { - return metaSolverSat.getAllSolvers() + Stream provideArguments() { + var solvers = metaSolverSat.getAllSolvers() .stream() - .map(x -> x.getClass().getName()); + .map(x -> x.getClass().getName()) + .toList(); + + var problems = metaSolverSat.getExampleProblems(); + + return Lists.cartesianProduct(solvers, problems).stream() + .map(list -> Arguments.of(list.get(0), list.get(1))); } @ParameterizedTest - @MethodSource("provideSatSolverIds") - void testSatSolver(String solverId) { + @MethodSource("provideArguments") + void testSatSolver(String solverId, String content) { var req = new SolveSatRequest(); req.requestedSolverId = solverId; - req.requestContent = "a and b"; + req.requestContent = content; var response = client.post() .uri("/solve/sat") From 894c8cf406d0c202d4bd0bf86b1f3e6af535dc61 Mon Sep 17 00:00:00 2001 From: nickp Date: Sun, 3 Sep 2023 16:56:24 +0200 Subject: [PATCH 04/18] Add endpoint descriptions --- .../kit/provideq/toolbox/api/MetaSolverSettingsRouter.java | 3 +++ src/main/java/edu/kit/provideq/toolbox/api/SolveRouter.java | 3 +++ .../java/edu/kit/provideq/toolbox/api/SolversRouter.java | 2 ++ .../java/edu/kit/provideq/toolbox/api/SubRoutineRouter.java | 5 +++++ 4 files changed, 13 insertions(+) diff --git a/src/main/java/edu/kit/provideq/toolbox/api/MetaSolverSettingsRouter.java b/src/main/java/edu/kit/provideq/toolbox/api/MetaSolverSettingsRouter.java index 0eafe1bf..fca2aa35 100644 --- a/src/main/java/edu/kit/provideq/toolbox/api/MetaSolverSettingsRouter.java +++ b/src/main/java/edu/kit/provideq/toolbox/api/MetaSolverSettingsRouter.java @@ -64,6 +64,9 @@ private void handleMetaSolverSettingsRouteDocumentation( ops .operationId(getRouteForProblemType(problemType)) .tag(problemType.getId()) + .description(("Returns the selection of settings available for of the " + + problemType.getId() + " meta-solver. Settings can be used to configure" + + " what the meat solver considers to choose the best solver.")) .response(getResponseOk(metaSolver)) .response(getResponseNotFound()); } diff --git a/src/main/java/edu/kit/provideq/toolbox/api/SolveRouter.java b/src/main/java/edu/kit/provideq/toolbox/api/SolveRouter.java index 18c0a37a..5e8c9734 100644 --- a/src/main/java/edu/kit/provideq/toolbox/api/SolveRouter.java +++ b/src/main/java/edu/kit/provideq/toolbox/api/SolveRouter.java @@ -139,6 +139,9 @@ private void handleRouteDocumentation(MetaSolver metaSolver, Builder op ops .operationId(getSolveRouteForProblemType(problemType)) .tag(problemType.getId()) + .description("Solves a " + problemType.getId() + " problem. To solve the problem, " + + "either the meta-solver will choose the best available solver," + + "or a specific solver selected in the request will be used.") .requestBody(requestBodyBuilder() .content(getRequestContent(metaSolver)) .required(true)) 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 09786aec..f61a2fdb 100644 --- a/src/main/java/edu/kit/provideq/toolbox/api/SolversRouter.java +++ b/src/main/java/edu/kit/provideq/toolbox/api/SolversRouter.java @@ -77,6 +77,8 @@ private void handleSolversRouteDocumentation(Builder ops, MetaSolver me ops .operationId(getSolversRouteForProblemType(metaSolver.getProblemType())) .tag(metaSolver.getProblemType().getId()) + .description("Returns a list of solvers available to solve the " + + metaSolver.getProblemType().getId() + " problem type.") .response(responseBuilder() .responseCode(String.valueOf(HttpStatus.OK.value())) .content(getOkResponseContent(metaSolver)) diff --git a/src/main/java/edu/kit/provideq/toolbox/api/SubRoutineRouter.java b/src/main/java/edu/kit/provideq/toolbox/api/SubRoutineRouter.java index 94112d87..780267cd 100644 --- a/src/main/java/edu/kit/provideq/toolbox/api/SubRoutineRouter.java +++ b/src/main/java/edu/kit/provideq/toolbox/api/SubRoutineRouter.java @@ -82,6 +82,11 @@ private void handleSubRoutineRouteDocumentation( ops.operationId(getSubRoutinesRouteForProblemType(problemType)) .parameter(getParameterBuilder(metaSolver)) .tag(problemType.getId()) + .description("Returns the sub-routines available for the given solver id of type " + + problemType.getId() + ". " + + "Sub-routines are used in some solvers to solve sub-problems. " + + "Passing a sub-routine in a solve request will ensure that" + + " the desired sub-routine is used in the calculation.") .response(responseBuilder() .responseCode(String.valueOf(HttpStatus.OK.value())) .content(getOkResponseContent(metaSolver))) From 053a6ef5f514dc63ac85f8fcf0d55a0f188d41af Mon Sep 17 00:00:00 2001 From: nickp Date: Fri, 8 Sep 2023 22:41:53 +0200 Subject: [PATCH 05/18] Checkstyle fix --- .../toolbox/api/FeatureModelAnomalySolverTest.java | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/test/java/edu/kit/provideq/toolbox/api/FeatureModelAnomalySolverTest.java b/src/test/java/edu/kit/provideq/toolbox/api/FeatureModelAnomalySolverTest.java index 7cde2d27..2e8af38d 100644 --- a/src/test/java/edu/kit/provideq/toolbox/api/FeatureModelAnomalySolverTest.java +++ b/src/test/java/edu/kit/provideq/toolbox/api/FeatureModelAnomalySolverTest.java @@ -66,7 +66,11 @@ Stream provideArguments() { var voidProblems = voidMetaSolver.getExampleProblems(); var voidArguments = Lists.cartesianProduct(voidSolvers, voidProblems).stream() - .map(list -> Arguments.of(list.get(0), ProblemType.FEATURE_MODEL_ANOMALY_VOID, SOLVED, list.get(1))); + .map(list -> Arguments.of( + list.get(0), + ProblemType.FEATURE_MODEL_ANOMALY_VOID, + SOLVED, + list.get(1))); // Dead arguments var deadSolvers = deadFeatureMetaSolver.getAllSolvers() @@ -76,10 +80,14 @@ Stream provideArguments() { var deadProblems = deadFeatureMetaSolver.getExampleProblems(); var deadArguments = Lists.cartesianProduct(deadSolvers, deadProblems).stream() - .map(list -> Arguments.of(list.get(0), ProblemType.FEATURE_MODEL_ANOMALY_DEAD, SOLVED, list.get(1))); + .map(list -> Arguments.of( + list.get(0), + ProblemType.FEATURE_MODEL_ANOMALY_DEAD, + SOLVED, + list.get(1))); // Return combined stream - return Stream.concat(voidArguments, deadArguments) ; + return Stream.concat(voidArguments, deadArguments); } @ParameterizedTest From 0bae94226ab574fa5f5027a482dd1f93e2e59a14 Mon Sep 17 00:00:00 2001 From: nickp Date: Mon, 11 Sep 2023 12:18:12 +0200 Subject: [PATCH 06/18] Make getExampleProblems abstract --- src/main/java/edu/kit/provideq/toolbox/meta/MetaSolver.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/edu/kit/provideq/toolbox/meta/MetaSolver.java b/src/main/java/edu/kit/provideq/toolbox/meta/MetaSolver.java index 9568561b..83c2ff85 100644 --- a/src/main/java/edu/kit/provideq/toolbox/meta/MetaSolver.java +++ b/src/main/java/edu/kit/provideq/toolbox/meta/MetaSolver.java @@ -126,7 +126,5 @@ public Solution solve(SolveRequest request) { return solution; } - public List getExampleProblems() { - return List.of(); - } + public abstract List getExampleProblems(); } From 66bd29b07da5d46d7fce99dd28d7401cb3fb3eb1 Mon Sep 17 00:00:00 2001 From: nickp Date: Mon, 11 Sep 2023 12:21:14 +0200 Subject: [PATCH 07/18] Remove unnecessary 404's --- .../provideq/toolbox/api/MetaSolverSettingsRouter.java | 8 +------- .../java/edu/kit/provideq/toolbox/api/SolveRouter.java | 8 +------- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/src/main/java/edu/kit/provideq/toolbox/api/MetaSolverSettingsRouter.java b/src/main/java/edu/kit/provideq/toolbox/api/MetaSolverSettingsRouter.java index fca2aa35..034982f4 100644 --- a/src/main/java/edu/kit/provideq/toolbox/api/MetaSolverSettingsRouter.java +++ b/src/main/java/edu/kit/provideq/toolbox/api/MetaSolverSettingsRouter.java @@ -67,8 +67,7 @@ private void handleMetaSolverSettingsRouteDocumentation( .description(("Returns the selection of settings available for of the " + problemType.getId() + " meta-solver. Settings can be used to configure" + " what the meat solver considers to choose the best solver.")) - .response(getResponseOk(metaSolver)) - .response(getResponseNotFound()); + .response(getResponseOk(metaSolver)); } private static org.springdoc.core.fn.builders.apiresponse.Builder getResponseOk( @@ -94,11 +93,6 @@ private static org.springdoc.core.fn.builders.apiresponse.Builder getResponseOk( ); } - private static org.springdoc.core.fn.builders.apiresponse.Builder getResponseNotFound() { - return responseBuilder() - .responseCode(String.valueOf(HttpStatus.NOT_FOUND.value())); - } - private Mono handleMetaSolverSettingsRouteForMetaSolver( MetaSolver metaSolver) { return ok().body(Mono.just(metaSolver.getSettings()), new ParameterizedTypeReference<>() { diff --git a/src/main/java/edu/kit/provideq/toolbox/api/SolveRouter.java b/src/main/java/edu/kit/provideq/toolbox/api/SolveRouter.java index 5e8c9734..9ea9c9b0 100644 --- a/src/main/java/edu/kit/provideq/toolbox/api/SolveRouter.java +++ b/src/main/java/edu/kit/provideq/toolbox/api/SolveRouter.java @@ -145,8 +145,7 @@ private void handleRouteDocumentation(MetaSolver metaSolver, Builder op .requestBody(requestBodyBuilder() .content(getRequestContent(metaSolver)) .required(true)) - .response(getResponseOk(metaSolver)) - .response(getResponseNotFound()); + .response(getResponseOk(metaSolver)); } private static org.springdoc.core.fn.builders.apiresponse.Builder getResponseOk( @@ -211,11 +210,6 @@ private static org.springdoc.core.fn.builders.exampleobject.Builder getExampleOk .value(solvedSolutionString); } - private static org.springdoc.core.fn.builders.apiresponse.Builder getResponseNotFound() { - return responseBuilder() - .responseCode(String.valueOf(HttpStatus.NOT_FOUND.value())); - } - private org.springdoc.core.fn.builders.content.Builder getRequestContent( MetaSolver metaSolver) { String content = metaSolver.getExampleProblems() From d9bde5fc628030feb44fc63a70b0c97f1f9f3cb9 Mon Sep 17 00:00:00 2001 From: nickp Date: Mon, 11 Sep 2023 12:42:06 +0200 Subject: [PATCH 08/18] Replace error strings with exceptions --- .../toolbox/api/MetaSolverSettingsRouter.java | 2 +- .../edu/kit/provideq/toolbox/api/SolveRouter.java | 12 +++++++----- .../edu/kit/provideq/toolbox/api/SolversRouter.java | 2 +- .../kit/provideq/toolbox/api/SubRoutineRouter.java | 6 +++--- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/main/java/edu/kit/provideq/toolbox/api/MetaSolverSettingsRouter.java b/src/main/java/edu/kit/provideq/toolbox/api/MetaSolverSettingsRouter.java index 034982f4..65d1c237 100644 --- a/src/main/java/edu/kit/provideq/toolbox/api/MetaSolverSettingsRouter.java +++ b/src/main/java/edu/kit/provideq/toolbox/api/MetaSolverSettingsRouter.java @@ -76,7 +76,7 @@ private static org.springdoc.core.fn.builders.apiresponse.Builder getResponseOk( try { example = new ObjectMapper().writeValueAsString(metaSolver.getSettings()); } catch (JsonProcessingException e) { - example = "Error: example could not be parsed"; + throw new RuntimeException("example could not be parsed", e); } return responseBuilder() diff --git a/src/main/java/edu/kit/provideq/toolbox/api/SolveRouter.java b/src/main/java/edu/kit/provideq/toolbox/api/SolveRouter.java index 9ea9c9b0..3029f8c2 100644 --- a/src/main/java/edu/kit/provideq/toolbox/api/SolveRouter.java +++ b/src/main/java/edu/kit/provideq/toolbox/api/SolveRouter.java @@ -199,7 +199,7 @@ private static org.springdoc.core.fn.builders.exampleobject.Builder getExampleOk try { solvedSolutionString = new ObjectMapper().writeValueAsString(solvedSolution); } catch (JsonProcessingException e) { - solvedSolutionString = "Error: example could not be parsed"; + throw new RuntimeException("example could not be parsed", e); } // Build the example @@ -222,10 +222,10 @@ private org.springdoc.core.fn.builders.content.Builder getRequestContent( try { return new ObjectMapper().writeValueAsString(e); } catch (JsonProcessingException exception) { - return "Error: example could not be parsed"; + throw new RuntimeException("example could not be parsed", exception); } }) - .orElse("Error: no example available"); + .orElseThrow(() -> new RuntimeException("no example available")); var request = new SolveRequest(); request.requestContent = content; @@ -249,13 +249,15 @@ private org.springdoc.core.fn.builders.content.Builder getRequestContent( .orElse(""); return subSolveRequest; })); - }, () -> request.requestedSolverId = "Error: no solver found"); + }, () -> { + throw new RuntimeException("no solver found"); + }); String requestString; try { requestString = new ObjectMapper().writeValueAsString(request); } catch (JsonProcessingException exception) { - requestString = "Error: no example available"; + throw new RuntimeException("no example available", exception); } var problemType = metaSolver.getProblemType(); 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 f61a2fdb..3530e6f4 100644 --- a/src/main/java/edu/kit/provideq/toolbox/api/SolversRouter.java +++ b/src/main/java/edu/kit/provideq/toolbox/api/SolversRouter.java @@ -92,7 +92,7 @@ private static org.springdoc.core.fn.builders.content.Builder getOkResponseConte try { example = new ObjectMapper().writeValueAsString(allSolvers); } catch (JsonProcessingException e) { - example = "Error: solvers could not be parsed"; + throw new RuntimeException("solvers could not be parsed", e); } return contentBuilder() diff --git a/src/main/java/edu/kit/provideq/toolbox/api/SubRoutineRouter.java b/src/main/java/edu/kit/provideq/toolbox/api/SubRoutineRouter.java index 780267cd..817420ed 100644 --- a/src/main/java/edu/kit/provideq/toolbox/api/SubRoutineRouter.java +++ b/src/main/java/edu/kit/provideq/toolbox/api/SubRoutineRouter.java @@ -107,7 +107,7 @@ private void handleSubRoutineRouteDocumentation( .getAllSolvers().stream() .findFirst() .map(ProblemSolver::getId) - .orElse("Error: no solver found")); + .orElseThrow(() -> new RuntimeException("No solver found"))); } private static Builder getOkResponseContent(MetaSolver metaSolver) { @@ -119,10 +119,10 @@ private static Builder getOkResponseContent(MetaSolver metaSolver) { try { return new ObjectMapper().writeValueAsString(subRoutines); } catch (JsonProcessingException e) { - return "Error: example could not be parsed"; + throw new RuntimeException("example could not be parsed", e); } }) - .orElse("Error: no solver found"); + .orElseThrow(() -> new RuntimeException("no solver found")); return contentBuilder() .mediaType(APPLICATION_JSON_VALUE) From 77fe3ca0cf6b25a1c73130e6c00603679227ce0e Mon Sep 17 00:00:00 2001 From: nickp Date: Mon, 11 Sep 2023 14:24:45 +0200 Subject: [PATCH 09/18] Simplify argument creation --- .../toolbox/meta/MetaSolverHelper.java | 20 +++++++++++ .../api/FeatureModelAnomalySolverTest.java | 36 ++++++------------- .../toolbox/api/MaxCutSolversTest.java | 11 ++---- .../provideq/toolbox/api/SatSolverTest.java | 10 ++---- 4 files changed, 34 insertions(+), 43 deletions(-) create mode 100644 src/main/java/edu/kit/provideq/toolbox/meta/MetaSolverHelper.java diff --git a/src/main/java/edu/kit/provideq/toolbox/meta/MetaSolverHelper.java b/src/main/java/edu/kit/provideq/toolbox/meta/MetaSolverHelper.java new file mode 100644 index 00000000..7dc014d5 --- /dev/null +++ b/src/main/java/edu/kit/provideq/toolbox/meta/MetaSolverHelper.java @@ -0,0 +1,20 @@ +package edu.kit.provideq.toolbox.meta; + +import com.google.common.collect.Lists; +import java.util.List; +import java.util.stream.Stream; + +public class MetaSolverHelper { + public static Stream> getAllArgumentCombinations(MetaSolver metaSolver) { + // Convert all solvers to their solver id + var solvers = metaSolver.getAllSolvers().stream() + .map(x -> x.getClass().getName()) + .toList(); + + // Get all example problems + var problems = metaSolver.getExampleProblems(); + + // Return all combinations + return Lists.cartesianProduct(solvers, problems).stream(); + } +} diff --git a/src/test/java/edu/kit/provideq/toolbox/api/FeatureModelAnomalySolverTest.java b/src/test/java/edu/kit/provideq/toolbox/api/FeatureModelAnomalySolverTest.java index 2e8af38d..c855a09a 100644 --- a/src/test/java/edu/kit/provideq/toolbox/api/FeatureModelAnomalySolverTest.java +++ b/src/test/java/edu/kit/provideq/toolbox/api/FeatureModelAnomalySolverTest.java @@ -3,7 +3,6 @@ import static edu.kit.provideq.toolbox.SolutionStatus.SOLVED; import static org.hamcrest.Matchers.is; -import com.google.common.collect.Lists; import edu.kit.provideq.toolbox.GamsProcessRunner; import edu.kit.provideq.toolbox.MetaSolverProvider; import edu.kit.provideq.toolbox.ResourceProvider; @@ -15,6 +14,8 @@ import edu.kit.provideq.toolbox.featuremodel.anomaly.dead.SatBasedDeadFeatureSolver; import edu.kit.provideq.toolbox.featuremodel.anomaly.voidmodel.SatBasedVoidFeatureSolver; import edu.kit.provideq.toolbox.featuremodel.anomaly.voidmodel.VoidFeatureMetaSolver; +import edu.kit.provideq.toolbox.meta.MetaSolver; +import edu.kit.provideq.toolbox.meta.MetaSolverHelper; import edu.kit.provideq.toolbox.meta.ProblemSolver; import edu.kit.provideq.toolbox.meta.ProblemType; import edu.kit.provideq.toolbox.sat.MetaSolverSat; @@ -58,36 +59,19 @@ class FeatureModelAnomalySolverTest { private DeadFeatureMetaSolver deadFeatureMetaSolver; Stream provideArguments() { - // Void arguments - var voidSolvers = voidMetaSolver.getAllSolvers() - .stream() - .map(x -> x.getClass().getName()) - .toList(); - var voidProblems = voidMetaSolver.getExampleProblems(); - - var voidArguments = Lists.cartesianProduct(voidSolvers, voidProblems).stream() - .map(list -> Arguments.of( - list.get(0), - ProblemType.FEATURE_MODEL_ANOMALY_VOID, - SOLVED, - list.get(1))); - - // Dead arguments - var deadSolvers = deadFeatureMetaSolver.getAllSolvers() - .stream() - .map(x -> x.getClass().getName()) - .toList(); - var deadProblems = deadFeatureMetaSolver.getExampleProblems(); + // Return combined stream + return Stream.concat( + getArguments(voidMetaSolver, ProblemType.FEATURE_MODEL_ANOMALY_VOID), + getArguments(deadFeatureMetaSolver, ProblemType.FEATURE_MODEL_ANOMALY_DEAD)); + } - var deadArguments = Lists.cartesianProduct(deadSolvers, deadProblems).stream() + static Stream getArguments(MetaSolver metaSolver, ProblemType problemType) { + return MetaSolverHelper.getAllArgumentCombinations(metaSolver) .map(list -> Arguments.of( list.get(0), - ProblemType.FEATURE_MODEL_ANOMALY_DEAD, + problemType, SOLVED, list.get(1))); - - // Return combined stream - return Stream.concat(voidArguments, deadArguments); } @ParameterizedTest diff --git a/src/test/java/edu/kit/provideq/toolbox/api/MaxCutSolversTest.java b/src/test/java/edu/kit/provideq/toolbox/api/MaxCutSolversTest.java index f56b24f7..d5df1ffb 100644 --- a/src/test/java/edu/kit/provideq/toolbox/api/MaxCutSolversTest.java +++ b/src/test/java/edu/kit/provideq/toolbox/api/MaxCutSolversTest.java @@ -15,8 +15,8 @@ import edu.kit.provideq.toolbox.maxcut.solvers.CirqMaxCutSolver; import edu.kit.provideq.toolbox.maxcut.solvers.GamsMaxCutSolver; import edu.kit.provideq.toolbox.maxcut.solvers.QiskitMaxCutSolver; +import edu.kit.provideq.toolbox.meta.MetaSolverHelper; import java.time.Duration; -import java.util.List; import java.util.stream.Stream; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.TestInstance; @@ -60,14 +60,7 @@ void beforeEach() { } Stream provideArguments() { - var solvers = metaSolverMaxCut.getAllSolvers() - .stream() - .map(x -> x.getClass().getName()) - .toList(); - - var problems = metaSolverMaxCut.getExampleProblems(); - - return Lists.cartesianProduct(solvers, problems).stream() + return MetaSolverHelper.getAllArgumentCombinations(metaSolverMaxCut) .map(list -> Arguments.of(list.get(0), list.get(1))); } diff --git a/src/test/java/edu/kit/provideq/toolbox/api/SatSolverTest.java b/src/test/java/edu/kit/provideq/toolbox/api/SatSolverTest.java index 72a58f99..13aa5f9d 100644 --- a/src/test/java/edu/kit/provideq/toolbox/api/SatSolverTest.java +++ b/src/test/java/edu/kit/provideq/toolbox/api/SatSolverTest.java @@ -9,6 +9,7 @@ import edu.kit.provideq.toolbox.ResourceProvider; import edu.kit.provideq.toolbox.Solution; import edu.kit.provideq.toolbox.SubRoutinePool; +import edu.kit.provideq.toolbox.meta.MetaSolverHelper; import edu.kit.provideq.toolbox.sat.MetaSolverSat; import edu.kit.provideq.toolbox.sat.SolveSatRequest; import edu.kit.provideq.toolbox.sat.solvers.GamsSatSolver; @@ -43,14 +44,7 @@ class SatSolverTest { private MetaSolverSat metaSolverSat; Stream provideArguments() { - var solvers = metaSolverSat.getAllSolvers() - .stream() - .map(x -> x.getClass().getName()) - .toList(); - - var problems = metaSolverSat.getExampleProblems(); - - return Lists.cartesianProduct(solvers, problems).stream() + return MetaSolverHelper.getAllArgumentCombinations(metaSolverSat) .map(list -> Arguments.of(list.get(0), list.get(1))); } From ab8ec9ea0bfe2d87f114ae352ae52cfcfea74fd8 Mon Sep 17 00:00:00 2001 From: nickp Date: Mon, 11 Sep 2023 14:35:49 +0200 Subject: [PATCH 10/18] Move utility function to read streams to ResourceProvider --- .../kit/provideq/toolbox/ProcessRunner.java | 15 +---- .../provideq/toolbox/ResourceProvider.java | 61 +++++++++++++++++-- 2 files changed, 59 insertions(+), 17 deletions(-) diff --git a/src/main/java/edu/kit/provideq/toolbox/ProcessRunner.java b/src/main/java/edu/kit/provideq/toolbox/ProcessRunner.java index 7709c47f..b7c26b4e 100644 --- a/src/main/java/edu/kit/provideq/toolbox/ProcessRunner.java +++ b/src/main/java/edu/kit/provideq/toolbox/ProcessRunner.java @@ -178,7 +178,8 @@ public ProcessResult run(ProblemType problemType, long solutionId, String proble try { Process process = processBuilder.start(); - processOutput = readStream(process.inputReader()) + readStream(process.errorReader()); + processOutput = resourceProvider.readStream(process.inputReader()) + + resourceProvider.readStream(process.errorReader()); processExitCode = process.waitFor(); } catch (IOException | InterruptedException e) { @@ -221,18 +222,6 @@ private void addCommand(String command) { processBuilder.command(existingCommands); } - private String readStream(BufferedReader reader) throws IOException { - var inputBuilder = new StringBuilder(); - var line = reader.readLine(); - while (line != null) { - inputBuilder.append(line).append('\n'); - line = reader.readLine(); - } - reader.close(); - - return inputBuilder.toString(); - } - protected static ProcessBuilder createGenericProcessBuilder( String directory, String executableName, diff --git a/src/main/java/edu/kit/provideq/toolbox/ResourceProvider.java b/src/main/java/edu/kit/provideq/toolbox/ResourceProvider.java index 0f06ab47..a1ac30d7 100644 --- a/src/main/java/edu/kit/provideq/toolbox/ResourceProvider.java +++ b/src/main/java/edu/kit/provideq/toolbox/ResourceProvider.java @@ -1,13 +1,17 @@ package edu.kit.provideq.toolbox; import edu.kit.provideq.toolbox.meta.ProblemType; +import java.io.BufferedReader; import java.io.File; import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.stereotype.Component; @@ -60,6 +64,58 @@ public File getProblemDirectory(ProblemType problemType, long solutionId) throws return dir.toFile(); } + /** + * Reads the input stream of a {@link BufferedReader} into a string. + * + * @param reader reader to read from + * @return full string of the input stream + * @throws IOException when the input stream couldn't be read + */ + public String readStream(BufferedReader reader) throws IOException { + var inputBuilder = new StringBuilder(); + + // Process first line manually to avoid adding a newline at the beginning + var line = reader.readLine(); + if (line != null) { + inputBuilder.append(line); + } + + line = reader.readLine(); + while (line != null) { + inputBuilder.append('\n').append(line); + line = reader.readLine(); + } + reader.close(); + + return inputBuilder.toString(); + } + + /** + * Reads the input stream of an {@link InputStream} into a string. + * + * @param stream stream to read from + * @return full string of the input stream + * @throws IOException when the input stream couldn't be read + */ + public String readStream(InputStream stream) throws IOException { + return readStream(new BufferedReader(new InputStreamReader(stream))); + } + + /** + * Reads the resource at the specified resource path into a string. + * + * @param resourcePath path that points to the requested resource + * @return full string of the data inside the resource + * @throws IOException when the resource is not available or couldn't be read + */ + public String readResourceString(String resourcePath) throws IOException { + Resource resource = resourceLoader.getResource("classpath:" + resourcePath); + + try (var reader = new BufferedReader(new InputStreamReader(resource.getInputStream()))) { + return readStream(reader); + } + } + /** * Returns the resource at the specified resource path. * @@ -68,11 +124,8 @@ public File getProblemDirectory(ProblemType problemType, long solutionId) throws * @throws IOException when the resource is not available */ public File getResource(String resourcePath) throws IOException { - return getRootFile(resourcePath); - - /* removed as long as we're not using resources directly Resource resource = resourceLoader.getResource("classpath:" + resourcePath); - return resource.getFile();*/ + return resource.getFile(); } /** From d94b5df1913c3e2f9a3f21b1afd33fae525690da Mon Sep 17 00:00:00 2001 From: nickp Date: Mon, 11 Sep 2023 15:22:21 +0200 Subject: [PATCH 11/18] Move example data to files in resources --- .../provideq/toolbox/ResourceProvider.java | 15 ++++++ .../featuremodel/ExtendedUvlFeatureModel.java | 39 -------------- .../anomaly/dead/DeadFeatureMetaSolver.java | 21 ++++++-- .../voidmodel/VoidFeatureMetaSolver.java | 21 ++++++-- .../toolbox/maxcut/MetaSolverMaxCut.java | 51 +++++++------------ .../provideq/toolbox/sat/MetaSolverSat.java | 20 ++++++-- src/main/resources/application.properties | 5 ++ .../resources/examples/feature-model/sandwich | 29 +++++++++++ .../examples/max-cut/3-nodes-3-edges.txt | 27 ++++++++++ src/main/resources/examples/sat/simple-and-or | 1 + .../resources/examples/sat/simple-and.txt | 1 + 11 files changed, 147 insertions(+), 83 deletions(-) delete mode 100644 src/main/java/edu/kit/provideq/toolbox/featuremodel/ExtendedUvlFeatureModel.java create mode 100644 src/main/resources/examples/feature-model/sandwich create mode 100644 src/main/resources/examples/max-cut/3-nodes-3-edges.txt create mode 100644 src/main/resources/examples/sat/simple-and-or create mode 100644 src/main/resources/examples/sat/simple-and.txt diff --git a/src/main/java/edu/kit/provideq/toolbox/ResourceProvider.java b/src/main/java/edu/kit/provideq/toolbox/ResourceProvider.java index a1ac30d7..acc71158 100644 --- a/src/main/java/edu/kit/provideq/toolbox/ResourceProvider.java +++ b/src/main/java/edu/kit/provideq/toolbox/ResourceProvider.java @@ -9,6 +9,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.io.Resource; @@ -64,6 +65,20 @@ public File getProblemDirectory(ProblemType problemType, long solutionId) throws return dir.toFile(); } + public List getExampleProblems(String examplesDirectoryPath) throws IOException { + // Reading the directory yields all names of the files in the directory, one per line + return readResourceString(examplesDirectoryPath) + .lines() + .map(file -> { + try { + return readResourceString(examplesDirectoryPath + "/" + file); + } catch (Exception e) { + return null; + } + }) + .toList(); + } + /** * Reads the input stream of a {@link BufferedReader} into a string. * diff --git a/src/main/java/edu/kit/provideq/toolbox/featuremodel/ExtendedUvlFeatureModel.java b/src/main/java/edu/kit/provideq/toolbox/featuremodel/ExtendedUvlFeatureModel.java deleted file mode 100644 index c3e383e0..00000000 --- a/src/main/java/edu/kit/provideq/toolbox/featuremodel/ExtendedUvlFeatureModel.java +++ /dev/null @@ -1,39 +0,0 @@ -package edu.kit.provideq.toolbox.featuremodel; - -import java.util.List; - -public class ExtendedUvlFeatureModel { - public static List getExamples() { - return List.of(""" - namespace Sandwich - - features - Sandwich {extended__} \s - mandatory - Bread \s - alternative - "Full Grain" {Calories 203, Price 1.99, Organic true} - Flatbread {Calories 90, Price 0.79, Organic true} - Toast {Calories 250, Price 0.99, Organic false} - optional - Cheese \s - optional - Gouda \s - alternative - Sprinkled {Fat {value 35, unit "g"}} - Slice {Fat {value 35, unit "g"}} - Cheddar - "Cream Cheese" - Meat \s - or - "Salami" {Producer "Farmer Bob"} - Ham {Producer "Farmer Sam"} - "Chicken Breast" {Producer "Farmer Sam"} - Vegetables \s - optional - "Cucumber" - Tomatoes - Lettuce - """); - } -} diff --git a/src/main/java/edu/kit/provideq/toolbox/featuremodel/anomaly/dead/DeadFeatureMetaSolver.java b/src/main/java/edu/kit/provideq/toolbox/featuremodel/anomaly/dead/DeadFeatureMetaSolver.java index 5a3a51dc..1b68e78c 100644 --- a/src/main/java/edu/kit/provideq/toolbox/featuremodel/anomaly/dead/DeadFeatureMetaSolver.java +++ b/src/main/java/edu/kit/provideq/toolbox/featuremodel/anomaly/dead/DeadFeatureMetaSolver.java @@ -1,12 +1,14 @@ package edu.kit.provideq.toolbox.featuremodel.anomaly.dead; -import edu.kit.provideq.toolbox.featuremodel.ExtendedUvlFeatureModel; +import edu.kit.provideq.toolbox.ResourceProvider; import edu.kit.provideq.toolbox.meta.MetaSolver; import edu.kit.provideq.toolbox.meta.Problem; import edu.kit.provideq.toolbox.meta.ProblemSolver; import edu.kit.provideq.toolbox.meta.ProblemType; import edu.kit.provideq.toolbox.meta.setting.MetaSolverSetting; import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; /** @@ -15,8 +17,17 @@ @Component public class DeadFeatureMetaSolver extends MetaSolver> { - public DeadFeatureMetaSolver(SatBasedDeadFeatureSolver solver) { + private final String examplesDirectoryPath; + private final ResourceProvider resourceProvider; + + @Autowired + public DeadFeatureMetaSolver( + @Value("${examples.directory.feature-model}") String examplesDirectoryPath, + ResourceProvider resourceProvider, + SatBasedDeadFeatureSolver solver) { super(ProblemType.FEATURE_MODEL_ANOMALY_DEAD, solver); + this.examplesDirectoryPath = examplesDirectoryPath; + this.resourceProvider = resourceProvider; } @Override @@ -28,6 +39,10 @@ public ProblemSolver findSolver(Problem problem, @Override public List getExampleProblems() { - return ExtendedUvlFeatureModel.getExamples(); + try { + return resourceProvider.getExampleProblems(examplesDirectoryPath); + } catch (Exception e) { + return List.of(); + } } } diff --git a/src/main/java/edu/kit/provideq/toolbox/featuremodel/anomaly/voidmodel/VoidFeatureMetaSolver.java b/src/main/java/edu/kit/provideq/toolbox/featuremodel/anomaly/voidmodel/VoidFeatureMetaSolver.java index 1fa177bd..6b9f00e0 100644 --- a/src/main/java/edu/kit/provideq/toolbox/featuremodel/anomaly/voidmodel/VoidFeatureMetaSolver.java +++ b/src/main/java/edu/kit/provideq/toolbox/featuremodel/anomaly/voidmodel/VoidFeatureMetaSolver.java @@ -1,12 +1,14 @@ package edu.kit.provideq.toolbox.featuremodel.anomaly.voidmodel; -import edu.kit.provideq.toolbox.featuremodel.ExtendedUvlFeatureModel; +import edu.kit.provideq.toolbox.ResourceProvider; import edu.kit.provideq.toolbox.meta.MetaSolver; import edu.kit.provideq.toolbox.meta.Problem; import edu.kit.provideq.toolbox.meta.ProblemSolver; import edu.kit.provideq.toolbox.meta.ProblemType; import edu.kit.provideq.toolbox.meta.setting.MetaSolverSetting; import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; /** @@ -15,8 +17,17 @@ @Component public class VoidFeatureMetaSolver extends MetaSolver> { - public VoidFeatureMetaSolver(SatBasedVoidFeatureSolver solver) { + private final String examplesDirectoryPath; + private final ResourceProvider resourceProvider; + + @Autowired + public VoidFeatureMetaSolver( + @Value("${examples.directory.feature-model}") String examplesDirectoryPath, + ResourceProvider resourceProvider, + SatBasedVoidFeatureSolver solver) { super(ProblemType.FEATURE_MODEL_ANOMALY_VOID, solver); + this.examplesDirectoryPath = examplesDirectoryPath; + this.resourceProvider = resourceProvider; } @Override @@ -28,6 +39,10 @@ public ProblemSolver findSolver(Problem problem, @Override public List getExampleProblems() { - return ExtendedUvlFeatureModel.getExamples(); + try { + return resourceProvider.getExampleProblems(examplesDirectoryPath); + } catch (Exception e) { + return List.of(); + } } } diff --git a/src/main/java/edu/kit/provideq/toolbox/maxcut/MetaSolverMaxCut.java b/src/main/java/edu/kit/provideq/toolbox/maxcut/MetaSolverMaxCut.java index 7988b9ae..774443fd 100644 --- a/src/main/java/edu/kit/provideq/toolbox/maxcut/MetaSolverMaxCut.java +++ b/src/main/java/edu/kit/provideq/toolbox/maxcut/MetaSolverMaxCut.java @@ -1,5 +1,6 @@ package edu.kit.provideq.toolbox.maxcut; +import edu.kit.provideq.toolbox.ResourceProvider; import edu.kit.provideq.toolbox.maxcut.solvers.CirqMaxCutSolver; import edu.kit.provideq.toolbox.maxcut.solvers.GamsMaxCutSolver; import edu.kit.provideq.toolbox.maxcut.solvers.MaxCutSolver; @@ -12,6 +13,7 @@ import java.util.List; import java.util.Random; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; /** @@ -19,12 +21,19 @@ */ @Component public class MetaSolverMaxCut extends MetaSolver { + private final String examplesDirectoryPath; + private final ResourceProvider resourceProvider; @Autowired - public MetaSolverMaxCut(QiskitMaxCutSolver qiskitSolver, - GamsMaxCutSolver gamsSolver, - CirqMaxCutSolver cirqSolver) { - super(ProblemType.MAX_CUT, qiskitSolver, gamsSolver, cirqSolver); + public MetaSolverMaxCut( + @Value("${examples.directory.max-cut}") String examplesDirectoryPath, + ResourceProvider resourceProvider, + QiskitMaxCutSolver qiskitMaxCutSolver, + GamsMaxCutSolver gamsMaxCutSolver, + CirqMaxCutSolver cirqMaxCutSolver) { + super(ProblemType.MAX_CUT, qiskitMaxCutSolver, gamsMaxCutSolver, cirqMaxCutSolver); + this.examplesDirectoryPath = examplesDirectoryPath; + this.resourceProvider = resourceProvider; } @Override @@ -36,34 +45,10 @@ public MaxCutSolver findSolver( @Override public List getExampleProblems() { - return List.of(""" - graph [ - id 42 - node [ - id 1 - label "1" - ] - node [ - id 2 - label "2" - ] - node [ - id 3 - label "3" - ] - edge [ - source 1 - target 2 - ] - edge [ - source 2 - target 3 - ] - edge [ - source 3 - target 1 - ] - ]""" - ); + try { + return resourceProvider.getExampleProblems(examplesDirectoryPath); + } catch (Exception e) { + return List.of(); + } } } diff --git a/src/main/java/edu/kit/provideq/toolbox/sat/MetaSolverSat.java b/src/main/java/edu/kit/provideq/toolbox/sat/MetaSolverSat.java index caef6ab1..0faa212d 100644 --- a/src/main/java/edu/kit/provideq/toolbox/sat/MetaSolverSat.java +++ b/src/main/java/edu/kit/provideq/toolbox/sat/MetaSolverSat.java @@ -1,5 +1,6 @@ package edu.kit.provideq.toolbox.sat; +import edu.kit.provideq.toolbox.ResourceProvider; import edu.kit.provideq.toolbox.format.cnf.dimacs.DimacsCnfSolution; import edu.kit.provideq.toolbox.meta.MetaSolver; import edu.kit.provideq.toolbox.meta.Problem; @@ -11,6 +12,7 @@ import java.util.List; import java.util.Random; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; /** @@ -18,11 +20,18 @@ */ @Component public class MetaSolverSat extends MetaSolver { + private final String examplesDirectoryPath; + private final ResourceProvider resourceProvider; @Autowired - public MetaSolverSat(GamsSatSolver gamsSatSolver) { + public MetaSolverSat( + @Value("${examples.directory.sat}") String examplesDirectoryPath, + ResourceProvider resourceProvider, + GamsSatSolver gamsSatSolver) { super(ProblemType.SAT, gamsSatSolver); //TODO: register more SAT Solvers + this.examplesDirectoryPath = examplesDirectoryPath; + this.resourceProvider = resourceProvider; } @Override @@ -33,9 +42,10 @@ public SatSolver findSolver(Problem problem, List met @Override public List getExampleProblems() { - return List.of( - "a and b", - "a and b or c" - ); + try { + return resourceProvider.getExampleProblems(examplesDirectoryPath); + } catch (Exception e) { + return List.of(); + } } } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 15543c50..a179b8b9 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -10,4 +10,9 @@ qiskit.directory.max-cut=${qiskit.directory}/max-cut cirq.directory=cirq cirq.directory.max-cut=${cirq.directory}/max-cut +examples.directory=examples +examples.directory.max-cut=${examples.directory}/max-cut +examples.directory.sat=${examples.directory}/sat +examples.directory.feature-model=${examples.directory}/feature-model + springdoc.swagger-ui.path=/ diff --git a/src/main/resources/examples/feature-model/sandwich b/src/main/resources/examples/feature-model/sandwich new file mode 100644 index 00000000..cdd25827 --- /dev/null +++ b/src/main/resources/examples/feature-model/sandwich @@ -0,0 +1,29 @@ +namespace Sandwich + +features + Sandwich {extended__} + mandatory + Bread + alternative + "Full Grain" {Calories 203, Price 1.99, Organic true} + Flatbread {Calories 90, Price 0.79, Organic true} + Toast {Calories 250, Price 0.99, Organic false} + optional + Cheese + optional + Gouda + alternative + Sprinkled {Fat {value 35, unit "g"}} + Slice {Fat {value 35, unit "g"}} + Cheddar + "Cream Cheese" + Meat + or + "Salami" {Producer "Farmer Bob"} + Ham {Producer "Farmer Sam"} + "Chicken Breast" {Producer "Farmer Sam"} + Vegetables + optional + "Cucumber" + Tomatoes + Lettuce \ No newline at end of file diff --git a/src/main/resources/examples/max-cut/3-nodes-3-edges.txt b/src/main/resources/examples/max-cut/3-nodes-3-edges.txt new file mode 100644 index 00000000..f1db0b36 --- /dev/null +++ b/src/main/resources/examples/max-cut/3-nodes-3-edges.txt @@ -0,0 +1,27 @@ +graph [ + id 42 + node [ + id 1 + label "1" + ] + node [ + id 2 + label "2" + ] + node [ + id 3 + label "3" + ] + edge [ + source 1 + target 2 + ] + edge [ + source 2 + target 3 + ] + edge [ + source 3 + target 1 + ] +] \ No newline at end of file diff --git a/src/main/resources/examples/sat/simple-and-or b/src/main/resources/examples/sat/simple-and-or new file mode 100644 index 00000000..983819f9 --- /dev/null +++ b/src/main/resources/examples/sat/simple-and-or @@ -0,0 +1 @@ +a and b or c \ No newline at end of file diff --git a/src/main/resources/examples/sat/simple-and.txt b/src/main/resources/examples/sat/simple-and.txt new file mode 100644 index 00000000..9832407e --- /dev/null +++ b/src/main/resources/examples/sat/simple-and.txt @@ -0,0 +1 @@ +a and b \ No newline at end of file From c89faaed73cd69cfe3103ce65f0dabfd1e793fb2 Mon Sep 17 00:00:00 2001 From: Max Schweikart Date: Sun, 10 Sep 2023 15:14:58 +0200 Subject: [PATCH 12/18] refactor: use ids for ProblemType serialization instead of enum names --- src/main/java/edu/kit/provideq/toolbox/meta/ProblemType.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/edu/kit/provideq/toolbox/meta/ProblemType.java b/src/main/java/edu/kit/provideq/toolbox/meta/ProblemType.java index 00ca4498..49d081b4 100644 --- a/src/main/java/edu/kit/provideq/toolbox/meta/ProblemType.java +++ b/src/main/java/edu/kit/provideq/toolbox/meta/ProblemType.java @@ -1,5 +1,6 @@ package edu.kit.provideq.toolbox.meta; +import com.fasterxml.jackson.annotation.JsonValue; import edu.kit.provideq.toolbox.SolveRequest; import edu.kit.provideq.toolbox.featuremodel.SolveFeatureModelRequest; import edu.kit.provideq.toolbox.maxcut.SolveMaxCutRequest; @@ -50,6 +51,7 @@ public enum ProblemType { /** * Returns a unique identifier for this problem type. */ + @JsonValue public String getId() { return id; } From 52b69080f5104d385dff515b1c2575d5cc21b444 Mon Sep 17 00:00:00 2001 From: nickp Date: Mon, 11 Sep 2023 16:30:35 +0200 Subject: [PATCH 13/18] Change SubRoutineDefinition to just use ProblemType --- .../toolbox/meta/SubRoutineDefinition.java | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/main/java/edu/kit/provideq/toolbox/meta/SubRoutineDefinition.java b/src/main/java/edu/kit/provideq/toolbox/meta/SubRoutineDefinition.java index 7597252f..f1350958 100644 --- a/src/main/java/edu/kit/provideq/toolbox/meta/SubRoutineDefinition.java +++ b/src/main/java/edu/kit/provideq/toolbox/meta/SubRoutineDefinition.java @@ -4,21 +4,10 @@ * A sub-routine definition describes which problem type needs to be solved by a sub-routine and why * it needs to be solved. * - * @param problemTypeId {@link ProblemType#getId() id} of the problem type that needs to be solved + * @param type {@link ProblemType} that needs to be solved * by this sub-routine. * @param description description of the sub-routine call to provide information where and why it is * needed. - * @see #SubRoutineDefinition(ProblemType, String) */ -public record SubRoutineDefinition(String problemTypeId, String description) { - /** - * Creates a sub-routine definition for a given problem type with a given description. - * - * @param type problem type that needs to be solved by this sub-routine. - * @param description description of the sub-routine call to provide information where and why it - * is needed. - */ - public SubRoutineDefinition(ProblemType type, String description) { - this(type.getId(), description); - } +public record SubRoutineDefinition(ProblemType type, String description) { } From 365f1356559ce907dcb2bcf7f36b57927e14fef1 Mon Sep 17 00:00:00 2001 From: nickp Date: Wed, 13 Sep 2023 11:05:43 +0200 Subject: [PATCH 14/18] Change generic in solve request to object --- .../kit/provideq/toolbox/api/SolveRouter.java | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/src/main/java/edu/kit/provideq/toolbox/api/SolveRouter.java b/src/main/java/edu/kit/provideq/toolbox/api/SolveRouter.java index 3029f8c2..18fded04 100644 --- a/src/main/java/edu/kit/provideq/toolbox/api/SolveRouter.java +++ b/src/main/java/edu/kit/provideq/toolbox/api/SolveRouter.java @@ -212,22 +212,11 @@ private static org.springdoc.core.fn.builders.exampleobject.Builder getExampleOk private org.springdoc.core.fn.builders.content.Builder getRequestContent( MetaSolver metaSolver) { - String content = metaSolver.getExampleProblems() - .stream().findFirst() - .map(e -> { - if (e instanceof String) { - return (String) e; - } - - try { - return new ObjectMapper().writeValueAsString(e); - } catch (JsonProcessingException exception) { - throw new RuntimeException("example could not be parsed", exception); - } - }) + Object content = metaSolver.getExampleProblems().stream() + .findFirst() .orElseThrow(() -> new RuntimeException("no example available")); - var request = new SolveRequest(); + var request = new SolveRequest<>(); request.requestContent = content; request.requestedMetaSolverSettings = metaSolver.getSettings(); From b98f3349d5d5081422be48b927b5ddb9c51a0910 Mon Sep 17 00:00:00 2001 From: nickp Date: Wed, 13 Sep 2023 11:11:34 +0200 Subject: [PATCH 15/18] Throw exception when no example problem is available --- .../featuremodel/anomaly/dead/DeadFeatureMetaSolver.java | 2 +- .../featuremodel/anomaly/voidmodel/VoidFeatureMetaSolver.java | 2 +- .../java/edu/kit/provideq/toolbox/maxcut/MetaSolverMaxCut.java | 2 +- src/main/java/edu/kit/provideq/toolbox/sat/MetaSolverSat.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/edu/kit/provideq/toolbox/featuremodel/anomaly/dead/DeadFeatureMetaSolver.java b/src/main/java/edu/kit/provideq/toolbox/featuremodel/anomaly/dead/DeadFeatureMetaSolver.java index 1b68e78c..2e6cad78 100644 --- a/src/main/java/edu/kit/provideq/toolbox/featuremodel/anomaly/dead/DeadFeatureMetaSolver.java +++ b/src/main/java/edu/kit/provideq/toolbox/featuremodel/anomaly/dead/DeadFeatureMetaSolver.java @@ -42,7 +42,7 @@ public List getExampleProblems() { try { return resourceProvider.getExampleProblems(examplesDirectoryPath); } catch (Exception e) { - return List.of(); + throw new RuntimeException("Could not load example problems", e); } } } diff --git a/src/main/java/edu/kit/provideq/toolbox/featuremodel/anomaly/voidmodel/VoidFeatureMetaSolver.java b/src/main/java/edu/kit/provideq/toolbox/featuremodel/anomaly/voidmodel/VoidFeatureMetaSolver.java index 6b9f00e0..f24deff8 100644 --- a/src/main/java/edu/kit/provideq/toolbox/featuremodel/anomaly/voidmodel/VoidFeatureMetaSolver.java +++ b/src/main/java/edu/kit/provideq/toolbox/featuremodel/anomaly/voidmodel/VoidFeatureMetaSolver.java @@ -42,7 +42,7 @@ public List getExampleProblems() { try { return resourceProvider.getExampleProblems(examplesDirectoryPath); } catch (Exception e) { - return List.of(); + throw new RuntimeException("Could not load example problems", e); } } } diff --git a/src/main/java/edu/kit/provideq/toolbox/maxcut/MetaSolverMaxCut.java b/src/main/java/edu/kit/provideq/toolbox/maxcut/MetaSolverMaxCut.java index 774443fd..934a564d 100644 --- a/src/main/java/edu/kit/provideq/toolbox/maxcut/MetaSolverMaxCut.java +++ b/src/main/java/edu/kit/provideq/toolbox/maxcut/MetaSolverMaxCut.java @@ -48,7 +48,7 @@ public List getExampleProblems() { try { return resourceProvider.getExampleProblems(examplesDirectoryPath); } catch (Exception e) { - return List.of(); + throw new RuntimeException("Could not load example problems", e); } } } diff --git a/src/main/java/edu/kit/provideq/toolbox/sat/MetaSolverSat.java b/src/main/java/edu/kit/provideq/toolbox/sat/MetaSolverSat.java index 0faa212d..34b199c5 100644 --- a/src/main/java/edu/kit/provideq/toolbox/sat/MetaSolverSat.java +++ b/src/main/java/edu/kit/provideq/toolbox/sat/MetaSolverSat.java @@ -45,7 +45,7 @@ public List getExampleProblems() { try { return resourceProvider.getExampleProblems(examplesDirectoryPath); } catch (Exception e) { - return List.of(); + throw new RuntimeException("Could not load example problems", e); } } } From 608b8df51f9254af4e07c050891e1eefceb40a55 Mon Sep 17 00:00:00 2001 From: nickp Date: Wed, 13 Sep 2023 11:13:05 +0200 Subject: [PATCH 16/18] Move MetaSolverHelper class to testing --- .../java/edu/kit/provideq/toolbox}/MetaSolverHelper.java | 3 ++- .../provideq/toolbox/api/FeatureModelAnomalySolverTest.java | 2 +- .../java/edu/kit/provideq/toolbox/api/MaxCutSolversTest.java | 3 +-- src/test/java/edu/kit/provideq/toolbox/api/SatSolverTest.java | 3 +-- 4 files changed, 5 insertions(+), 6 deletions(-) rename src/{main/java/edu/kit/provideq/toolbox/meta => test/java/edu/kit/provideq/toolbox}/MetaSolverHelper.java (87%) diff --git a/src/main/java/edu/kit/provideq/toolbox/meta/MetaSolverHelper.java b/src/test/java/edu/kit/provideq/toolbox/MetaSolverHelper.java similarity index 87% rename from src/main/java/edu/kit/provideq/toolbox/meta/MetaSolverHelper.java rename to src/test/java/edu/kit/provideq/toolbox/MetaSolverHelper.java index 7dc014d5..046bdbd3 100644 --- a/src/main/java/edu/kit/provideq/toolbox/meta/MetaSolverHelper.java +++ b/src/test/java/edu/kit/provideq/toolbox/MetaSolverHelper.java @@ -1,6 +1,7 @@ -package edu.kit.provideq.toolbox.meta; +package edu.kit.provideq.toolbox; import com.google.common.collect.Lists; +import edu.kit.provideq.toolbox.meta.MetaSolver; import java.util.List; import java.util.stream.Stream; diff --git a/src/test/java/edu/kit/provideq/toolbox/api/FeatureModelAnomalySolverTest.java b/src/test/java/edu/kit/provideq/toolbox/api/FeatureModelAnomalySolverTest.java index c855a09a..6e5b1258 100644 --- a/src/test/java/edu/kit/provideq/toolbox/api/FeatureModelAnomalySolverTest.java +++ b/src/test/java/edu/kit/provideq/toolbox/api/FeatureModelAnomalySolverTest.java @@ -15,7 +15,7 @@ import edu.kit.provideq.toolbox.featuremodel.anomaly.voidmodel.SatBasedVoidFeatureSolver; import edu.kit.provideq.toolbox.featuremodel.anomaly.voidmodel.VoidFeatureMetaSolver; import edu.kit.provideq.toolbox.meta.MetaSolver; -import edu.kit.provideq.toolbox.meta.MetaSolverHelper; +import edu.kit.provideq.toolbox.MetaSolverHelper; import edu.kit.provideq.toolbox.meta.ProblemSolver; import edu.kit.provideq.toolbox.meta.ProblemType; import edu.kit.provideq.toolbox.sat.MetaSolverSat; diff --git a/src/test/java/edu/kit/provideq/toolbox/api/MaxCutSolversTest.java b/src/test/java/edu/kit/provideq/toolbox/api/MaxCutSolversTest.java index d5df1ffb..4cefe3d7 100644 --- a/src/test/java/edu/kit/provideq/toolbox/api/MaxCutSolversTest.java +++ b/src/test/java/edu/kit/provideq/toolbox/api/MaxCutSolversTest.java @@ -3,7 +3,6 @@ import static edu.kit.provideq.toolbox.SolutionStatus.SOLVED; import static org.hamcrest.Matchers.is; -import com.google.common.collect.Lists; import edu.kit.provideq.toolbox.GamsProcessRunner; import edu.kit.provideq.toolbox.MetaSolverProvider; import edu.kit.provideq.toolbox.PythonProcessRunner; @@ -15,7 +14,7 @@ import edu.kit.provideq.toolbox.maxcut.solvers.CirqMaxCutSolver; import edu.kit.provideq.toolbox.maxcut.solvers.GamsMaxCutSolver; import edu.kit.provideq.toolbox.maxcut.solvers.QiskitMaxCutSolver; -import edu.kit.provideq.toolbox.meta.MetaSolverHelper; +import edu.kit.provideq.toolbox.MetaSolverHelper; import java.time.Duration; import java.util.stream.Stream; import org.junit.jupiter.api.BeforeEach; diff --git a/src/test/java/edu/kit/provideq/toolbox/api/SatSolverTest.java b/src/test/java/edu/kit/provideq/toolbox/api/SatSolverTest.java index 13aa5f9d..22bcd8a9 100644 --- a/src/test/java/edu/kit/provideq/toolbox/api/SatSolverTest.java +++ b/src/test/java/edu/kit/provideq/toolbox/api/SatSolverTest.java @@ -3,13 +3,12 @@ import static edu.kit.provideq.toolbox.SolutionStatus.SOLVED; import static org.hamcrest.Matchers.is; -import com.google.common.collect.Lists; import edu.kit.provideq.toolbox.GamsProcessRunner; import edu.kit.provideq.toolbox.MetaSolverProvider; import edu.kit.provideq.toolbox.ResourceProvider; import edu.kit.provideq.toolbox.Solution; import edu.kit.provideq.toolbox.SubRoutinePool; -import edu.kit.provideq.toolbox.meta.MetaSolverHelper; +import edu.kit.provideq.toolbox.MetaSolverHelper; import edu.kit.provideq.toolbox.sat.MetaSolverSat; import edu.kit.provideq.toolbox.sat.SolveSatRequest; import edu.kit.provideq.toolbox.sat.solvers.GamsSatSolver; From e1a1b5df82e9e93c4a8d7f1da0440b1a654fd9fe Mon Sep 17 00:00:00 2001 From: nickp Date: Wed, 13 Sep 2023 11:17:08 +0200 Subject: [PATCH 17/18] Add txt extension to all example files --- .../resources/examples/feature-model/{sandwich => sandwich.txt} | 0 .../resources/examples/sat/{simple-and-or => simple-and-or.txt} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/main/resources/examples/feature-model/{sandwich => sandwich.txt} (100%) rename src/main/resources/examples/sat/{simple-and-or => simple-and-or.txt} (100%) diff --git a/src/main/resources/examples/feature-model/sandwich b/src/main/resources/examples/feature-model/sandwich.txt similarity index 100% rename from src/main/resources/examples/feature-model/sandwich rename to src/main/resources/examples/feature-model/sandwich.txt diff --git a/src/main/resources/examples/sat/simple-and-or b/src/main/resources/examples/sat/simple-and-or.txt similarity index 100% rename from src/main/resources/examples/sat/simple-and-or rename to src/main/resources/examples/sat/simple-and-or.txt From cddff4c5a4fe410e6535d23402eff34810987b55 Mon Sep 17 00:00:00 2001 From: nickp Date: Wed, 13 Sep 2023 11:27:15 +0200 Subject: [PATCH 18/18] Reorder imports --- .../kit/provideq/toolbox/api/FeatureModelAnomalySolverTest.java | 2 +- .../java/edu/kit/provideq/toolbox/api/MaxCutSolversTest.java | 2 +- src/test/java/edu/kit/provideq/toolbox/api/SatSolverTest.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/java/edu/kit/provideq/toolbox/api/FeatureModelAnomalySolverTest.java b/src/test/java/edu/kit/provideq/toolbox/api/FeatureModelAnomalySolverTest.java index 6e5b1258..8983702e 100644 --- a/src/test/java/edu/kit/provideq/toolbox/api/FeatureModelAnomalySolverTest.java +++ b/src/test/java/edu/kit/provideq/toolbox/api/FeatureModelAnomalySolverTest.java @@ -4,6 +4,7 @@ import static org.hamcrest.Matchers.is; import edu.kit.provideq.toolbox.GamsProcessRunner; +import edu.kit.provideq.toolbox.MetaSolverHelper; import edu.kit.provideq.toolbox.MetaSolverProvider; import edu.kit.provideq.toolbox.ResourceProvider; import edu.kit.provideq.toolbox.Solution; @@ -15,7 +16,6 @@ import edu.kit.provideq.toolbox.featuremodel.anomaly.voidmodel.SatBasedVoidFeatureSolver; import edu.kit.provideq.toolbox.featuremodel.anomaly.voidmodel.VoidFeatureMetaSolver; import edu.kit.provideq.toolbox.meta.MetaSolver; -import edu.kit.provideq.toolbox.MetaSolverHelper; import edu.kit.provideq.toolbox.meta.ProblemSolver; import edu.kit.provideq.toolbox.meta.ProblemType; import edu.kit.provideq.toolbox.sat.MetaSolverSat; diff --git a/src/test/java/edu/kit/provideq/toolbox/api/MaxCutSolversTest.java b/src/test/java/edu/kit/provideq/toolbox/api/MaxCutSolversTest.java index 4cefe3d7..45b2a269 100644 --- a/src/test/java/edu/kit/provideq/toolbox/api/MaxCutSolversTest.java +++ b/src/test/java/edu/kit/provideq/toolbox/api/MaxCutSolversTest.java @@ -4,6 +4,7 @@ import static org.hamcrest.Matchers.is; import edu.kit.provideq.toolbox.GamsProcessRunner; +import edu.kit.provideq.toolbox.MetaSolverHelper; import edu.kit.provideq.toolbox.MetaSolverProvider; import edu.kit.provideq.toolbox.PythonProcessRunner; import edu.kit.provideq.toolbox.ResourceProvider; @@ -14,7 +15,6 @@ import edu.kit.provideq.toolbox.maxcut.solvers.CirqMaxCutSolver; import edu.kit.provideq.toolbox.maxcut.solvers.GamsMaxCutSolver; import edu.kit.provideq.toolbox.maxcut.solvers.QiskitMaxCutSolver; -import edu.kit.provideq.toolbox.MetaSolverHelper; import java.time.Duration; import java.util.stream.Stream; import org.junit.jupiter.api.BeforeEach; diff --git a/src/test/java/edu/kit/provideq/toolbox/api/SatSolverTest.java b/src/test/java/edu/kit/provideq/toolbox/api/SatSolverTest.java index 22bcd8a9..9af6e499 100644 --- a/src/test/java/edu/kit/provideq/toolbox/api/SatSolverTest.java +++ b/src/test/java/edu/kit/provideq/toolbox/api/SatSolverTest.java @@ -4,11 +4,11 @@ import static org.hamcrest.Matchers.is; import edu.kit.provideq.toolbox.GamsProcessRunner; +import edu.kit.provideq.toolbox.MetaSolverHelper; import edu.kit.provideq.toolbox.MetaSolverProvider; import edu.kit.provideq.toolbox.ResourceProvider; import edu.kit.provideq.toolbox.Solution; import edu.kit.provideq.toolbox.SubRoutinePool; -import edu.kit.provideq.toolbox.MetaSolverHelper; import edu.kit.provideq.toolbox.sat.MetaSolverSat; import edu.kit.provideq.toolbox.sat.SolveSatRequest; import edu.kit.provideq.toolbox.sat.solvers.GamsSatSolver;