Skip to content

Commit 2eab055

Browse files
committed
Update equalsWithIdMap
The method now accounts for the existence of multiple activities that are identical sans ids
1 parent cfcb123 commit 2eab055

1 file changed

Lines changed: 58 additions & 17 deletions

File tree

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

Lines changed: 58 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,15 @@
99
import gov.nasa.jpl.aerie.types.ActivityDirective;
1010
import gov.nasa.jpl.aerie.types.ActivityDirectiveId;
1111

12+
import java.util.ArrayList;
1213
import java.util.Collection;
1314
import java.util.HashMap;
1415
import java.util.HashSet;
16+
import java.util.List;
1517
import java.util.Map;
1618
import java.util.Optional;
1719
import java.util.Set;
1820
import java.util.function.Supplier;
19-
import java.util.stream.Collectors;
2021

2122
public interface SimulationFacade {
2223
void setInitialSimResults(SimulationData simulationData);
@@ -82,28 +83,68 @@ public boolean equals(Object other){
8283
* `map` contains a mapping between *only the IDs that are different* between the two plans.
8384
*/
8485
public Optional<Map<ActivityDirectiveId, ActivityDirectiveId>> equalsWithIdMap(PlanSimCorrespondence other) {
86+
// If the simulations have a different amount of directives, they must not be equal
87+
if(directiveIdActivityDirectiveMap.size() != other.directiveIdActivityDirectiveMap.size()) {
88+
return Optional.empty();
89+
}
90+
91+
// Build the maps of directives -> ids from the ids -> directives map
92+
// Because multiple activities on a plan can be identical sans id, the inverted maps to a list of ids
93+
final var thisInverted = new HashMap<ActivityDirective, List<ActivityDirectiveId>>(directiveIdActivityDirectiveMap.size());
94+
directiveIdActivityDirectiveMap.forEach(
95+
(key, value) -> {
96+
thisInverted.putIfAbsent(value, new ArrayList<>());
97+
thisInverted.get(value).add(key);
98+
});
99+
100+
final var otherInverted = new HashMap<ActivityDirective, List<ActivityDirectiveId>>(other.directiveIdActivityDirectiveMap.size());
101+
other.directiveIdActivityDirectiveMap.forEach(
102+
(key, value) -> {
103+
otherInverted.putIfAbsent(value, new ArrayList<>());
104+
otherInverted.get(value).add(key);
105+
});
106+
107+
// If these maps have different sizes, then the simulations must not be equal
108+
if(thisInverted.size() != otherInverted.size()) {
109+
return Optional.empty();
110+
}
111+
112+
// Check every entry for equality while building up the return mapping
85113
final var result = new HashMap<ActivityDirectiveId, ActivityDirectiveId>();
86-
final var thisInverse = directiveIdActivityDirectiveMap.entrySet()
87-
.stream()
88-
.collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey));
89-
final var otherInverse = other.directiveIdActivityDirectiveMap.entrySet()
90-
.stream()
91-
.collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey));
92-
for (var entry : thisInverse.entrySet()) {
93-
final var otherId = otherInverse.remove(entry.getKey());
94-
if (otherId == null) {
114+
for (final var entry : thisInverted.entrySet()) {
115+
// Check that at least one instance of this directive is on the other plan
116+
if(!otherInverted.containsKey(entry.getKey())){
117+
return Optional.empty();
118+
}
119+
120+
final var thisIds = entry.getValue();
121+
final var otherIds = otherInverted.get(entry.getKey());
122+
123+
// Check that there is the same number of instances of this directive on the other plan
124+
if (thisIds.size() != otherIds.size()) {
95125
return Optional.empty();
96126
}
97-
if (!otherId.equals(entry.getValue())) {
98-
result.put(entry.getValue(), otherId);
127+
128+
// If the directive is unique (the most common case), then the two ids can be directly compared
129+
if(thisIds.size() == 1) {
130+
if(!thisIds.getFirst().equals(otherIds.getFirst())) {
131+
result.put(thisIds.getFirst(), otherIds.getFirst());
132+
}
133+
continue;
99134
}
100-
}
101135

102-
if (otherInverse.isEmpty()) {
103-
return Optional.of(result);
104-
} else {
105-
return Optional.empty();
136+
// Filter out the ids that are on both lists, as this method does not provide a mapping for ids that have not changed
137+
final List<ActivityDirectiveId> toRemove = thisIds.stream().filter(otherIds::contains).toList();
138+
thisIds.removeAll(toRemove);
139+
otherIds.removeAll(toRemove);
140+
141+
// Add the remaining mappings to the result
142+
for(int i = 0; i < thisIds.size(); ++i) {
143+
result.put(thisIds.get(i), otherIds.get(i));
144+
}
106145
}
146+
147+
return Optional.of(result);
107148
}
108149
}
109150
}

0 commit comments

Comments
 (0)