Skip to content

Commit

Permalink
feat: Support getting score calculation count and speed for SolverJob
Browse files Browse the repository at this point in the history
Closes #621.
  • Loading branch information
Christopher-Chianelli authored and triceo committed Feb 16, 2024
1 parent ffec10e commit fb946aa
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 13 deletions.
Expand Up @@ -85,4 +85,24 @@ public interface SolverJob<Solution_, ProblemId_> {
*/
Duration getSolvingDuration();

/**
* Return the number of score calculations since the last start.
* If it hasn't started yet, it returns 0.
* If it hasn't ended yet, it returns the number of score calculations so far.
* If it has ended already, it returns the total number of score calculations that occurred during solving.
*
* @return the number of score calculations that had occurred during solving since the last (re)start, at least 0
*/
long getScoreCalculationCount();

/**
* Return the average number of score calculations per second since the last start.
* If it hasn't started yet, it returns 0.
* If it hasn't ended yet, it returns the average number of score calculations per second so far.
* If it has ended already, it returns the average number of score calculations per second during solving.
*
* @return the average number of score calculations per second that had occurred during solving
* since the last (re)start, at least 0
*/
long getScoreCalculationSpeed();
}
Expand Up @@ -103,6 +103,14 @@ public long getTimeMillisSpent() {
return endingSystemTimeMillis - startingSystemTimeMillis;
}

public long getScoreCalculationCount() {
return solverScope.getScoreCalculationCount();
}

public long getScoreCalculationSpeed() {
return SolverScope.getScoreCalculationSpeed(getScoreCalculationCount(), getTimeMillisSpent());
}

@Override
public boolean isSolving() {
return solving.get();
Expand Down
Expand Up @@ -208,18 +208,17 @@ public Solution_ getFinalBestSolution() throws InterruptedException, ExecutionEx

@Override
public Duration getSolvingDuration() {
SolverScope<Solution_> solverScope = solver.getSolverScope();
Long startingSystemTimeMillis = solverScope.getStartingSystemTimeMillis();
if (startingSystemTimeMillis == null) {
// The solver hasn't started yet
return Duration.ZERO;
}
Long endingSystemTimeMillis = solverScope.getEndingSystemTimeMillis();
if (endingSystemTimeMillis == null) {
// The solver hasn't ended yet
endingSystemTimeMillis = System.currentTimeMillis();
}
return Duration.ofMillis(endingSystemTimeMillis - startingSystemTimeMillis);
return Duration.ofMillis(solver.getTimeMillisSpent());
}

@Override
public long getScoreCalculationCount() {
return solver.getScoreCalculationCount();
}

@Override
public long getScoreCalculationSpeed() {
return solver.getScoreCalculationSpeed();
}

public Termination<Solution_> getSolverTermination() {
Expand Down
Expand Up @@ -229,8 +229,12 @@ public long getTimeMillisSpent() {
*/
public long getScoreCalculationSpeed() {
long timeMillisSpent = getTimeMillisSpent();
return getScoreCalculationSpeed(getScoreCalculationCount(), timeMillisSpent);
}

public static long getScoreCalculationSpeed(long scoreCalculationCount, long timeMillisSpent) {
// Avoid divide by zero exception on a fast CPU
return getScoreCalculationCount() * 1000L / (timeMillisSpent == 0L ? 1L : timeMillisSpent);
return scoreCalculationCount * 1000L / (timeMillisSpent == 0L ? 1L : timeMillisSpent);
}

public void setWorkingSolutionFromBestSolution() {
Expand Down
Expand Up @@ -292,6 +292,35 @@ void solveWithOverride() {
assertThat(solverJob.getSolverTermination().calculateSolverTimeGradient(solverScope)).isEqualTo(0.5);
}

@Test
void testScoreCalculationCountForFinishedJob() throws ExecutionException, InterruptedException {
// Terminate after exactly 5 score calculations
var terminationConfig = new TerminationConfig()
.withScoreCalculationCountLimit(5L);
var solverConfig = PlannerTestUtils
.buildSolverConfig(TestdataSolution.class, TestdataEntity.class)
.withTerminationConfig(terminationConfig);

solverManager = SolverManager
.create(solverConfig, new SolverManagerConfig());

var problem = PlannerTestUtils.generateTestdataSolution("s1");
var solverJob = (DefaultSolverJob<TestdataSolution, Long>) solverManager.solveBuilder()
.withProblemId(2L)
.withProblem(problem)
.run();

solverJob.getFinalBestSolution();
assertThat(solverJob.getScoreCalculationCount()).isEqualTo(5L);

// Score calculation speed and solve duration are non-deterministic.
// On an exceptionally fast machine, getSolvingDuration() can return Duration.ZERO.
// On an exceptionally slow machine, getScoreCalculationSpeed() can be 0 due to flooring
// (i.e. by taking more than 5 seconds to finish solving).
assertThat(solverJob.getSolvingDuration()).isGreaterThanOrEqualTo(Duration.ZERO);
assertThat(solverJob.getScoreCalculationSpeed()).isGreaterThanOrEqualTo(0L);
}

@Test
void testSolveBuilderForExistingSolvingMethods() {
SolverJobBuilder<TestdataSolution, Long> solverJobBuilder = mock(SolverJobBuilder.class);
Expand Down

0 comments on commit fb946aa

Please sign in to comment.