Skip to content

Commit 38acbc3

Browse files
authored
Merge pull request #1539 from NASA-AMMOS/bug/inf-loop-in-search
fix for infinite loop when time range is less than 20 micros
2 parents 51018bb + 41428d2 commit 38acbc3

File tree

1 file changed

+36
-4
lines changed

1 file changed

+36
-4
lines changed

scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/EquationSolvingAlgorithms.java

+36-4
Original file line numberDiff line numberDiff line change
@@ -127,25 +127,56 @@ private IteratingResult nextValueAt(
127127
final int maxIteration)
128128
throws ExceededMaxIterationException, SchedulingInterruptedException
129129
{
130+
// the number of possible values may be less than the number of iterations, so stop after all have been visited.
131+
long numTimepoints = minus(minus(max.in(Duration.MICROSECONDS), min.in(Duration.MICROSECONDS)), 1);
132+
long maxIters = Long.min(maxIteration, numTimepoints);
130133
var cur = init;
131-
int i = 0;
134+
long i = 0;
132135
do {
133136
//we should not come back to previously visited values
134137
if (!history.alreadyVisited(cur) && cur.between(min, max)) {
135138
i++;
136139
try {
137140
final var value = function.valueAt(cur, history);
138-
return new IteratingResult(new FunctionCoordinate<>(cur, value), i);
141+
return new IteratingResult(new FunctionCoordinate<>(cur, value), ((Long)i).intValue());
139142
} catch (DiscontinuityException e) {
140143
//nothing, keep iterating
141144
}
142145
}
143146
cur = chooseRandomX(min, max);
144-
//if min == max, another call to random will have no effect and thus we should exit
145-
} while(i < maxIteration && !min.isEqualTo(max));
147+
//if all timepoints have been visited, another call to random will have no effect and thus we should exit
148+
} while(i < maxIters);
146149
throw new ExceededMaxIterationException();
147150
}
148151

152+
/**
153+
* Addition of longs with safety from overflow
154+
*/
155+
private static long plus(final long rd1, final long rd2 ) {
156+
long result;
157+
// check for overflow
158+
if ( rd1 >= 0 && Long.MAX_VALUE - rd1 <= rd2 ) {
159+
result = Long.MAX_VALUE;
160+
} else if ( rd1 < 0 && Long.MIN_VALUE - rd1 >= rd2 ) {
161+
result = Long.MIN_VALUE;
162+
} else {
163+
result = rd1 + rd2;
164+
}
165+
return result;
166+
}
167+
168+
/**
169+
* Subtraction of longs with safety from overflow
170+
*/
171+
private static long minus(final long rd1, final long rd2 ) {
172+
long result;
173+
// use plus, but don't risk trying to negate +/-inf
174+
if ( rd2 == Long.MAX_VALUE ) result = plus( rd1, Long.MIN_VALUE );
175+
else if ( rd2 == Long.MIN_VALUE ) result = plus( rd1, Long.MAX_VALUE );
176+
else result = plus(rd1, -rd2);
177+
return result;
178+
}
179+
149180
/**
150181
* Solves x s.t. f(x) = y by transforming it to the equivalent rootfinding problem x s.t. f(x) - y = 0
151182
* @param f the function
@@ -182,6 +213,7 @@ public RootFindingResult<Duration, Metadata> findRoot(
182213
public Duration valueAt(final Duration x, final History<Duration, Metadata> history)
183214
throws EquationSolvingAlgorithms.DiscontinuityException, SchedulingInterruptedException
184215
{
216+
// don't add value to history -- it breaks things
185217
return f.valueAt(x, history).minus(y);
186218
}
187219
};

0 commit comments

Comments
 (0)