Skip to content

Commit

Permalink
Make latest/earliest choice for start time instantiation configurable
Browse files Browse the repository at this point in the history
  • Loading branch information
adrienmaillard committed Aug 22, 2024
1 parent 6495db8 commit f94f50b
Show file tree
Hide file tree
Showing 9 changed files with 80 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,10 @@ public Iterator<Segment<V>> iterator() {
return this.segments.iterator();
}

public Iterator<Segment<V>> reverseIterator() {
return this.segments.descendingIterator();
}

/** Creates an iterable over the Intervals where this map is equal to a value */
public Iterable<Interval> iterateEqualTo(final V value) {
return () -> this.segments
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -657,6 +657,10 @@ public Iterable<Interval> iterateEqualTo(final boolean value) {
return segments.iterateEqualTo(value);
}

public Iterator<Segment<Boolean>> reverseIterator() {
return segments.reverseIterator();
}

/** Delegated to {@link IntervalMap#stream} */
public Stream<Segment<Boolean>> stream() {
return segments.stream();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import gov.nasa.jpl.aerie.constraints.model.EvaluationEnvironment;
import gov.nasa.jpl.aerie.constraints.time.Windows;
import gov.nasa.jpl.aerie.scheduler.goals.Goal;
import gov.nasa.jpl.aerie.scheduler.solver.ScheduleAt;

/**
* describes an issue in a plan whereby a desired activity instance is absent
Expand All @@ -23,6 +24,8 @@ public MissingActivityConflict(
super(goal, environment);
}

public abstract ScheduleAt scheduleAt();

/**
* {@inheritDoc}
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import gov.nasa.jpl.aerie.constraints.time.Windows;
import gov.nasa.jpl.aerie.scheduler.goals.ActivityExistentialGoal;
import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivity;
import gov.nasa.jpl.aerie.scheduler.solver.ScheduleAt;

/**
* describes an issue in a plan caused by a specific activity instance missing
Expand Down Expand Up @@ -44,6 +45,11 @@ public String toString() {
return "Empty conflict";
}

@Override
public ScheduleAt scheduleAt() {
return ScheduleAt.EARLIEST;
}

/**
* {@inheritDoc}
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import gov.nasa.jpl.aerie.scheduler.constraints.activities.ActivityExpression;
import gov.nasa.jpl.aerie.scheduler.goals.ActivityTemplateGoal;
import gov.nasa.jpl.aerie.scheduler.goals.Goal;
import gov.nasa.jpl.aerie.scheduler.solver.ScheduleAt;

import java.util.Optional;

Expand Down Expand Up @@ -36,7 +37,8 @@ public MissingActivityTemplateConflict(
int cardinality,
Optional<ActivityDirectiveId> anchorIdTo,
Optional<Boolean> anchorToStart,
Optional<Duration> totalDuration)
Optional<Duration> totalDuration,
ScheduleAt scheduleAtEarliest)
{
super(goal, evaluationEnvironment);

Expand All @@ -50,6 +52,7 @@ public MissingActivityTemplateConflict(
this.anchorIdTo = anchorIdTo;
this.anchorToStart = anchorToStart;
this.totalDuration = totalDuration;
this.scheduleAt = scheduleAtEarliest;
}

//the number of times the activity needs to be inserted
Expand All @@ -67,6 +70,8 @@ public Optional<Boolean> getAnchorToStart() {
//the desired total duration over the number of activities needed
Optional<Duration> totalDuration;

ScheduleAt scheduleAt;

public int getCardinality(){
return cardinality;
}
Expand All @@ -75,6 +80,11 @@ public Optional<Duration> getTotalDuration(){
return totalDuration;
}

@Override
public ScheduleAt scheduleAt() {
return scheduleAt;
}

/**
* {@inheritDoc}
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import gov.nasa.jpl.aerie.scheduler.constraints.activities.ActivityExpression;
import gov.nasa.jpl.aerie.scheduler.model.Plan;
import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivity;
import gov.nasa.jpl.aerie.scheduler.solver.ScheduleAt;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -205,7 +206,8 @@ public Collection<Conflict> getConflicts(
nbToSchedule,
Optional.empty(),
Optional.empty(),
durToSchedule.isPositive() ? Optional.of(durToSchedule) : Optional.empty()));
durToSchedule.isPositive() ? Optional.of(durToSchedule) : Optional.empty(),
ScheduleAt.EARLIEST));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import gov.nasa.jpl.aerie.scheduler.model.PersistentTimeAnchor;
import gov.nasa.jpl.aerie.scheduler.model.Plan;
import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivity;
import gov.nasa.jpl.aerie.scheduler.solver.ScheduleAt;

import java.util.ArrayList;
import java.util.HashMap;
Expand Down Expand Up @@ -305,7 +306,8 @@ public java.util.Collection<Conflict> getConflicts(
1,
anchorValue,
Optional.of(this.persistentAnchor.equals(PersistentTimeAnchor.START)),
Optional.empty()
Optional.empty(),
ScheduleAt.EARLIEST
));
} else {
final var actsToAssociate = missingActAssociationsWithAnchor.isEmpty() ? missingActAssociationsWithoutAnchor : missingActAssociationsWithAnchor;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.*;
import java.util.stream.Collectors;

import static com.google.common.base.Preconditions.checkNotNull;
Expand Down Expand Up @@ -503,7 +496,7 @@ private void satisfyGoalGeneral(Goal goal) throws SchedulingInterruptedException
} else if (missing instanceof MissingAssociationConflict missingAssociationConflict) {
conflictSolverReturn = solveMissingAssociationConflict(missingAssociationConflict, goal);
} else if(!analysisOnly && missing instanceof MissingActivityNetworkConflict missingActivityNetworkConflict){
conflictSolverReturn = solveActivityNetworkConflict(missingActivityNetworkConflict, goal);
conflictSolverReturn = solveActivityNetworkConflict(missingActivityNetworkConflict, goal, ScheduleAt.EARLIEST);
} else if(!analysisOnly && missing instanceof MissingRecurrenceConflict missingRecurrenceConflict){
conflictSolverReturn = solveMissingRecurrenceConflict(missingRecurrenceConflict, goal);
}
Expand Down Expand Up @@ -661,7 +654,8 @@ private Optional<MissingActivityNetworkConflict> makeActivityNetworkConflict(

private ConflictSolverResult solveActivityNetworkConflict(
final MissingActivityNetworkConflict missingActivityNetworkConflict,
final Goal goal
final Goal goal,
final ScheduleAt scheduleAt
) throws SchedulingInterruptedException
{
var satisfaction = ConflictSatisfaction.NOT_SAT;
Expand Down Expand Up @@ -694,7 +688,8 @@ private ConflictSolverResult solveActivityNetworkConflict(
1,
Optional.empty(),
Optional.of(true),
Optional.empty());
Optional.empty(),
scheduleAt);
final var satisfactionOfThisSubConflict = solveActivityTemplateConflict(derivedActivityTemplateConflict, goal, true);
if(satisfactionOfThisSubConflict.satisfaction() == ConflictSatisfaction.SAT){
//apply constraints to network
Expand Down Expand Up @@ -996,7 +991,8 @@ private Optional<SchedulingActivity> getBestNewActivity(MissingActivityConflict
missingTemplate,
goal.getName() + "_" + java.util.UUID.randomUUID(),
startWindows,
missing.getEvaluationEnvironment());
missing.getEvaluationEnvironment(),
missing.scheduleAt());
if(act.isPresent()){
if (missingTemplate.getAnchorId().isPresent()) {
final SchedulingActivity predecessor = plan.getActivitiesById().get(missingTemplate.getAnchorId().get());
Expand Down Expand Up @@ -1158,25 +1154,36 @@ private Windows narrowGlobalConstraints(
final MissingActivityTemplateConflict missingConflict,
final String name,
final Windows windows,
final EvaluationEnvironment evaluationEnvironment) throws SchedulingInterruptedException
final EvaluationEnvironment evaluationEnvironment,
final ScheduleAt scheduleAt) throws SchedulingInterruptedException
{
//REVIEW: how to properly export any flexibility to instance?
logger.info("Trying to create one activity, will loop through possible windows");
for (var window : windows.iterateEqualTo(true)) {
logger.info("Trying in window " + window);
var activity = instantiateActivity(missingConflict.getActTemplate(), name, window, missingConflict.getEvaluationEnvironment());
if (activity.isPresent()) {
return activity;
var iterator = scheduleAt == ScheduleAt.EARLIEST ? windows.iterator() : windows.reverseIterator();
while(iterator.hasNext()) {
final var segment = iterator.next();
if(segment.value()) {
logger.info("Trying in window " + segment.interval());
var activity = instantiateActivity(
missingConflict.getActTemplate(),
name,
segment.interval(),
missingConflict.getEvaluationEnvironment(),
scheduleAt);
if (activity.isPresent()) {
return activity;
}
}
}
}
return Optional.empty();
}

private Optional<SchedulingActivity> instantiateActivity(
final ActivityExpression activityExpression,
final String name,
final Interval interval,
final EvaluationEnvironment evaluationEnvironment
final EvaluationEnvironment evaluationEnvironment,
final ScheduleAt scheduleAt
) throws SchedulingInterruptedException {
final var planningHorizon = this.problem.getPlanningHorizon();
final var envelopes = new ArrayList<Interval>();
Expand Down Expand Up @@ -1242,15 +1249,15 @@ public Duration valueAt(Duration start, final EquationSolvingAlgorithms.History<
}

};
return rootFindingHelper(f, history, solved);
return rootFindingHelper(f, history, solved, scheduleAt);
//CASE 2: activity has a controllable duration
} else if (activityExpression.type().getDurationType() instanceof DurationType.Controllable dt) {
//select earliest start time, STN guarantees satisfiability
final var earliestStart = solved.start().start;
final var start = scheduleAt == ScheduleAt.EARLIEST ? solved.start().start : solved.start().end;
final var instantiatedArguments = SchedulingActivity.instantiateArguments(
activityExpression.arguments(),
earliestStart,
getLatestSimResultsUpTo(earliestStart, resourceNames).constraintsResults(),
start,
getLatestSimResultsUpTo(start, resourceNames).constraintsResults(),
evaluationEnvironment,
activityExpression.type());

Expand All @@ -1274,7 +1281,7 @@ public Duration valueAt(Duration start, final EquationSolvingAlgorithms.History<
return Optional.of(SchedulingActivity.of(
idGenerator.next(),
activityExpression.type(),
earliestStart,
start,
setActivityDuration,
instantiatedArguments,
null,
Expand All @@ -1288,17 +1295,17 @@ public Duration valueAt(Duration start, final EquationSolvingAlgorithms.History<
return Optional.empty();
}

final var earliestStart = solved.start().start;
final var start = scheduleAt == ScheduleAt.EARLIEST ? solved.start().start : solved.start().end;
// TODO: When scheduling is allowed to create activities with anchors, this constructor should pull from an expanded creation template
return Optional.of(SchedulingActivity.of(
idGenerator.next(),
activityExpression.type(),
earliestStart,
start,
dt.duration(),
SchedulingActivity.instantiateArguments(
activityExpression.arguments(),
earliestStart,
getLatestSimResultsUpTo(earliestStart, resourceNames).constraintsResults(),
start,
getLatestSimResultsUpTo(start, resourceNames).constraintsResults(),
evaluationEnvironment,
activityExpression.type()),
null,
Expand Down Expand Up @@ -1341,7 +1348,7 @@ public Duration valueAt(final Duration start, final EquationSolvingAlgorithms.Hi
}
};

return rootFindingHelper(f, history, solved);
return rootFindingHelper(f, history, solved, scheduleAt);
} else {
throw new UnsupportedOperationException("Unsupported duration type found: " + activityExpression.type().getDurationType());
}
Expand All @@ -1350,7 +1357,8 @@ public Duration valueAt(final Duration start, final EquationSolvingAlgorithms.Hi
private Optional<SchedulingActivity> rootFindingHelper(
final EquationSolvingAlgorithms.Function<Duration, ActivityMetadata> f,
final HistoryWithActivity history,
final TaskNetworkAdapter.TNActData solved
final TaskNetworkAdapter.TNActData solved,
final ScheduleAt scheduleAt
) throws SchedulingInterruptedException {
try {
var endInterval = solved.end();
Expand All @@ -1363,7 +1371,7 @@ private Optional<SchedulingActivity> rootFindingHelper(
.findRoot(
f,
history,
startInterval.start,
scheduleAt == ScheduleAt.EARLIEST ? startInterval.start : startInterval.end,
endInterval.start.plus(durationHalfEndInterval),
durationHalfEndInterval,
durationHalfEndInterval,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package gov.nasa.jpl.aerie.scheduler.solver;

public enum ScheduleAt {
EARLIEST,
LATEST
}

0 comments on commit f94f50b

Please sign in to comment.