diff --git a/src/main/java/edu/kit/provideq/toolbox/api/ComparisonDto.java b/src/main/java/edu/kit/provideq/toolbox/api/ComparisonDto.java index ad2d4ed2..44c6ff5c 100644 --- a/src/main/java/edu/kit/provideq/toolbox/api/ComparisonDto.java +++ b/src/main/java/edu/kit/provideq/toolbox/api/ComparisonDto.java @@ -1,11 +1,68 @@ package edu.kit.provideq.toolbox.api; import edu.kit.provideq.toolbox.BoundWithInfo; -import edu.kit.provideq.toolbox.Solution; -public record ComparisonDto(float comparison, BoundWithInfo bound, Solution solution) { +/** + * A DTO for a comparison between a bound and a solution. + */ +public class ComparisonDto { + private BoundDto bound; + private float comparison; + + /** + * Creates a new comparison DTO out of a comparison value and a bound. + * + * @param comparison the comparison value, e.g., the ratio of the solution to the bound + * @param bound a bound + */ + public ComparisonDto(float comparison, BoundWithInfo bound) { + this.comparison = comparison; + this.bound = new BoundDto(bound); + } + + public ComparisonDto() { + this.comparison = -1; + this.bound = null; + } + + @Override public String toString() { - return "Comparison{comparison=%f, bound=%s, solution=%s}" - .formatted(comparison, bound, solution); + return "Comparison{bound=%s, comparison=%f}" + .formatted(bound, comparison); + } + + /** + * Gets the bound of the comparison as a BoundDto. + * + * @return the bound of the comparison, e.g., the best known solution or the optimal solution + */ + public BoundDto getBound() { + return bound; + } + + public void setBound(BoundDto bound) { + this.bound = bound; } + + public void setBound(BoundWithInfo bound) { + this.bound = new BoundDto(bound); + } + + public boolean hasBound() { + return bound != null; + } + + public void setComparison(float comparison) { + this.comparison = comparison; + } + + /** + * Gets the comparison value of the comparison. + * + * @return the comparison value, e.g., the ratio of the solution to the bound. + */ + public float getComparison() { + return comparison; + } + } diff --git a/src/main/java/edu/kit/provideq/toolbox/api/EstimationRouter.java b/src/main/java/edu/kit/provideq/toolbox/api/EstimationRouter.java index 71fd772f..fdf6bc09 100644 --- a/src/main/java/edu/kit/provideq/toolbox/api/EstimationRouter.java +++ b/src/main/java/edu/kit/provideq/toolbox/api/EstimationRouter.java @@ -90,7 +90,7 @@ private Mono handleGet( Mono bound; try { problem.estimateBound(); - bound = Mono.just(new BoundDto(problem.getBound().orElseThrow())); + bound = Mono.just(problem.getBound().orElseThrow()); } catch (IllegalStateException | NoSuchElementException e) { throw new ResponseStatusException(HttpStatus.BAD_REQUEST, e.getMessage()); } @@ -114,22 +114,14 @@ private Mono handleCompare( throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Bound not estimated yet!"); } - float bound = problem.getBound().get().bound().value(); - var pattern = Pattern.compile(manager.getType().getSolutionPattern()); - var solutionMatcher = pattern.matcher(problem.getSolution().get().getSolutionData().toString()); - float solutionValue; - if (solutionMatcher.find()) { - solutionValue = Float.parseFloat(solutionMatcher.group(1)); - } else { - throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Could not parse solution value!"); + try { + problem.compareBound(); + } catch (IllegalStateException | NoSuchElementException e) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, e.getMessage()); } - float comparison = problem.getBound().get().bound().boundType().compare(bound, solutionValue); - ComparisonDto comparisonDto = new ComparisonDto( - comparison, - problem.getBound().get(), - problem.getSolution().get() - ); + var comparisonDto = problem.getBoundWithComparison(); + return ok().body(Mono.just(comparisonDto), new ParameterizedTypeReference<>() { }); } diff --git a/src/main/java/edu/kit/provideq/toolbox/api/ProblemDto.java b/src/main/java/edu/kit/provideq/toolbox/api/ProblemDto.java index 954e2f0c..23de41e3 100644 --- a/src/main/java/edu/kit/provideq/toolbox/api/ProblemDto.java +++ b/src/main/java/edu/kit/provideq/toolbox/api/ProblemDto.java @@ -17,8 +17,8 @@ public class ProblemDto { private String typeId; private InputT input; private Solution solution; - private BoundWithInfo bound; private ProblemState state; + private ComparisonDto boundWithComparison; private String solverId; private List solverSettings; private List subProblems; @@ -40,7 +40,7 @@ public static ProblemDto fromProblem( dto.typeId = problem.getType().getId(); dto.input = problem.getInput().orElse(null); dto.solution = problem.getSolution().orElse(null); - dto.bound = problem.getBound().orElse(null); + dto.boundWithComparison = problem.getBoundWithComparison().orElse(null); dto.state = problem.getState(); dto.solverId = problem.getSolver() .map(ProblemSolver::getId) @@ -70,8 +70,8 @@ public Solution getSolution() { return solution; } - public BoundWithInfo getBound() { - return bound; + public ComparisonDto getBoundWithComparison() { + return boundWithComparison; } public ProblemState getState() { @@ -107,7 +107,7 @@ public String toString() { + ", solverId=" + solverId + ", input=" + input + ", solution=" + solution - + ", value=" + bound + + ", boundWithComparison=" + boundWithComparison + ", solverSettings=" + solverSettings + ", subProblems=" + subProblems + '}'; diff --git a/src/main/java/edu/kit/provideq/toolbox/meta/Problem.java b/src/main/java/edu/kit/provideq/toolbox/meta/Problem.java index 2b8791ae..9f239f9d 100644 --- a/src/main/java/edu/kit/provideq/toolbox/meta/Problem.java +++ b/src/main/java/edu/kit/provideq/toolbox/meta/Problem.java @@ -2,6 +2,8 @@ import edu.kit.provideq.toolbox.BoundWithInfo; import edu.kit.provideq.toolbox.Solution; +import edu.kit.provideq.toolbox.api.BoundDto; +import edu.kit.provideq.toolbox.api.ComparisonDto; import edu.kit.provideq.toolbox.meta.setting.SolverSetting; import java.util.Collections; import java.util.HashSet; @@ -10,6 +12,7 @@ import java.util.Set; import java.util.UUID; import java.util.function.Consumer; +import java.util.regex.Pattern; import java.util.stream.Collectors; import reactor.core.publisher.Mono; @@ -30,7 +33,7 @@ public class Problem { private InputT input; private Solution solution; - private BoundWithInfo bound; + private final ComparisonDto boundWithComparison = new ComparisonDto(); private ProblemState state; private ProblemSolver solver; private List solverSettings; @@ -84,6 +87,10 @@ public Mono> solve() { }); } + /** + * Estimates a bound for the problem's solution. Uses the estimator provided by the problem type. + * Also sets the execution time of the estimation in the boundWithComparison object. + */ public void estimateBound() { if (this.input == null) { throw new IllegalStateException("Cannot estimate value without input!"); @@ -93,6 +100,7 @@ public void estimateBound() { if (optionalEstimator.isEmpty()) { throw new IllegalStateException("Cannot estimate value without an estimator!"); } + var estimator = optionalEstimator.get(); long start = System.currentTimeMillis(); @@ -101,7 +109,28 @@ public void estimateBound() { long finish = System.currentTimeMillis(); var executionTime = finish - start; - this.bound = new BoundWithInfo(estimatedBound, executionTime); + this.boundWithComparison.setBound(new BoundWithInfo(estimatedBound, executionTime)); + } + + /** + * Compares the current solution with the bound according to the bound type. + */ + public void compareBound() { + if (this.solution == null) { + throw new IllegalStateException("Cannot compare bound without solution!"); + } + if (!this.boundWithComparison.hasBound()) { + throw new IllegalStateException("Cannot compare bound without bound!"); + } + + var bound = this.boundWithComparison.getBound(); + var solutionData = this.solution.getSolutionData(); + + float solutionValue = getSolutionValue(solutionData); + + var comparison = bound.boundType().compare(bound.bound(), solutionValue); + + this.boundWithComparison.setComparison(comparison); } public UUID getId() { @@ -231,7 +260,23 @@ public String toString() { + '}'; } - public Optional getBound() { - return Optional.ofNullable(bound); + public Optional getBound() { + return Optional.ofNullable(boundWithComparison.getBound()); + } + + public Optional getBoundWithComparison() { + return Optional.of(boundWithComparison); + } + + private float getSolutionValue(ResultT solutionData) { + var pattern = Pattern.compile(this.type.getSolutionPattern()); + var solutionMatcher = pattern.matcher(solutionData.toString()); + float solutionValue; + if (solutionMatcher.find()) { + solutionValue = Float.parseFloat(solutionMatcher.group(1)); + } else { + throw new IllegalStateException("Solution does not match the expected pattern!"); + } + return solutionValue; } }