Skip to content

Commit

Permalink
Merge pull request #1371 from NASA-AMMOS/performance/intervalmap
Browse files Browse the repository at this point in the history
Performance/intervalmap
  • Loading branch information
dandelany authored Mar 29, 2024
2 parents 0b65676 + 1cd8714 commit e57d756
Show file tree
Hide file tree
Showing 10 changed files with 397 additions and 149 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,14 @@ public Windows notEqualTo(final DiscreteProfile other) {
@Override
public Windows changePoints() {
final var result = IntervalMap.<Boolean>builder().set(this.profilePieces.map($ -> false));
for (int i = 0; i < this.profilePieces.size(); i++) {
final var segment = this.profilePieces.get(i);
if (i == 0) {
for (final var segment : profilePieces) {
if (segment == profilePieces.first()) {
if (!segment.interval().contains(Duration.MIN_VALUE)) {
result.unset(Interval.at(segment.interval().start));
}
} else {
final var previousSegment = this.profilePieces.get(i-1);
if (Interval.meets(previousSegment.interval(), segment.interval())) {
final var previousSegment = this.profilePieces.segments().lower(segment);
if (previousSegment != null && Interval.meets(previousSegment.interval(), segment.interval())) {
if (!previousSegment.value().equals(segment.value())) {
result.set(Interval.at(segment.interval().start), true);
}
Expand All @@ -83,15 +82,16 @@ public Windows changePoints() {

public Windows transitions(final SerializedValue oldState, final SerializedValue newState) {
final var result = IntervalMap.<Boolean>builder().set(this.profilePieces.map($ -> false));
for (int i = 0; i < this.profilePieces.size(); i++) {
final var segment = this.profilePieces.get(i);
if (i == 0) {
for (final var segment : profilePieces) {
//for (int i = 0; i < this.profilePieces.size(); i++) {
//final var segment = this.profilePieces.get(i);
if (segment == profilePieces.first()) {
if (segment.value().equals(newState) && !segment.interval().contains(Duration.MIN_VALUE)) {
result.unset(Interval.at(segment.interval().start));
}
} else {
final var previousSegment = this.profilePieces.get(i-1);
if (Interval.meets(previousSegment.interval(), segment.interval())) {
final var previousSegment = this.profilePieces.segments().lower(segment);
if (previousSegment != null && Interval.meets(previousSegment.interval(), segment.interval())) {
if (previousSegment.value().equals(oldState) && segment.value().equals(newState)) {
result.set(Interval.at(segment.interval().start), true);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
/**
* A linear equation in point-slope form.
*/
public final class LinearEquation {
public final class LinearEquation implements Comparable<LinearEquation> {
public final Duration initialTime;
public final double initialValue;
public final double rate;
Expand Down Expand Up @@ -185,4 +185,12 @@ public boolean equals(final Object obj) {
public int hashCode() {
return Objects.hash(this.initialValue, this.initialTime, this.rate);
}

@Override
public int compareTo(final LinearEquation o) {
int c = Double.compare(this.valueAt(Duration.ZERO), o.valueAt(Duration.ZERO));
if (c != 0) return c;
c = Double.compare(this.valueAt(Duration.MINUTE), o.valueAt(Duration.MINUTE));
return c;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -106,17 +106,16 @@ private Windows getWindowsSatisfying(final LinearProfile other, final BiFunction
@Override
public Windows changePoints() {
final var result = IntervalMap.<Boolean>builder().set(this.profilePieces.map(LinearEquation::changing));
for (int i = 0; i < this.profilePieces.size(); i++) {
final var segment = this.profilePieces.get(i);
for (final var segment : profilePieces) {
final var startTime = segment.interval().start;
if (i == 0) {
if (segment == profilePieces.first()) {
if (!segment.interval().contains(Duration.MIN_VALUE)) {
result.unset(Interval.at(startTime));
}
} else {
final var previousSegment = this.profilePieces.get(i-1);
final var previousSegment = this.profilePieces.segments().lower(segment);

if (Interval.meets(previousSegment.interval(), segment.interval())) {
if (previousSegment != null && Interval.meets(previousSegment.interval(), segment.interval())) {
if (previousSegment.value().valueAt(startTime) != segment.value().valueAt(startTime)) {
result.set(Interval.at(startTime), true);
}
Expand All @@ -133,7 +132,7 @@ public Windows changePoints() {
@Override
public boolean isConstant() {
return profilePieces.isEmpty() ||
(profilePieces.size() == 1 && !profilePieces.get(0).value().changing());
(profilePieces.size() == 1 && !profilePieces.first().value().changing());
}

/** Assigns a default value to all gaps in the profile. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import gov.nasa.jpl.aerie.merlin.protocol.types.Duration;
import org.apache.commons.lang3.tuple.Pair;

import java.util.Comparator;
import java.util.Objects;

import static gov.nasa.jpl.aerie.constraints.time.Interval.Inclusivity.Exclusive;
Expand Down Expand Up @@ -277,7 +278,10 @@ public boolean adjacent(Interval x){

@Override
public int compareTo(final Interval o) {
return start.compareTo(o.start);
int c = compareStarts(o);
if (c != 0) return c;
c = compareEnds(o);
return c;
}

public static int compareStartToStart(final Interval x, final Interval y) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,54 @@ public static Interval strictUpperBoundsOf(final Interval x) {
);
}

/**
* Whether the start of one interval is before the start of another. This assumes that the intervals are both
* non-empty but does not check.
* @param x the first interval
* @param y the second interval
* @return whether the start of x is before the start of y
*/
public static boolean startBeforeStart(Interval x, Interval y) {
return x.start.shorterThan(y.start) ||
(x.start.isEqualTo(y.start) && (x.includesStart() && !y.includesStart()));
}

/**
* Whether the end of one interval is before the start of another. This assumes that the intervals are both
* non-empty but does not check.
* @param x the first interval
* @param y the second interval
* @return whether the end of x is before the start of y
*/
public static boolean endBeforeStart(Interval x, Interval y) {
return x.end.shorterThan(y.start) ||
(x.end.isEqualTo(y.start) && (!x.includesEnd() || !y.includesStart()));
}

/**
* Whether the end of one interval is before the end of another. This assumes that the intervals are both
* non-empty but does not check.
* @param x the first interval
* @param y the second interval
* @return whether the end of x is before the end of y
*/
public static boolean endBeforeEnd(Interval x, Interval y) {
return x.end.shorterThan(y.end) ||
(x.end.isEqualTo(y.end) && (!x.includesEnd() && y.includesEnd()));
}

/**
* Whether the start of one interval is before the end of another. This assumes that the intervals are both
* non-empty but does not check.
* @param x the first interval
* @param y the second interval
* @return whether the start of x is before the end of y
*/
public static boolean startBeforeEnd(Interval x, Interval y) {
return x.start.shorterThan(y.end);
}


/**
* Whether any point is contained in both operands.
*
Expand All @@ -110,7 +158,8 @@ public static Interval strictUpperBoundsOf(final Interval x) {
* @return whether the operands overlap
*/
static boolean overlaps(Interval x, Interval y) {
return !isEmpty(intersect(x, y));
if (x.isEmpty() || y.isEmpty()) return false;
return !endBeforeStart(x, y) && !endBeforeStart(y, x);
}

/**
Expand All @@ -121,9 +170,8 @@ static boolean overlaps(Interval x, Interval y) {
* @return whether `outer` contains every point in `inner`
*/
static boolean contains(Interval outer, Interval inner) {
// If `inner` doesn't overlap with the complement of `outer`,
// then `inner` must exist entirely within `outer`.
return !(overlaps(inner, strictUpperBoundsOf(outer)) || overlaps(inner, strictLowerBoundsOf(outer)));
if (outer.isEmpty() || inner.isEmpty()) return false;
return !startBeforeStart(inner, outer) && !endBeforeEnd(outer, inner);
}

/**
Expand Down Expand Up @@ -158,7 +206,8 @@ static boolean equals(Interval x, Interval y) {
* @return whether the start point of x is before all points in y
*/
static boolean startsBefore(Interval x, Interval y) {
return strictlyContains(strictLowerBoundsOf(y), strictLowerBoundsOf(x));
if (x.isEmpty() || y.isEmpty()) return false;
return startBeforeStart(x, y);
}

/**
Expand All @@ -169,7 +218,8 @@ static boolean startsBefore(Interval x, Interval y) {
* @return whether the end point of x is after all points in y
*/
static boolean endsAfter(Interval x, Interval y) {
return strictlyContains(strictUpperBoundsOf(y), strictUpperBoundsOf(x));
if (x.isEmpty() || y.isEmpty()) return false;
return endBeforeEnd(y, x);
}

/**
Expand Down Expand Up @@ -213,7 +263,9 @@ static boolean startsStrictlyAfter(Interval x, Interval y) {
* @return whether the end point of x is strictly before all points in y
*/
static boolean endsStrictlyBefore(Interval x, Interval y) {
return !isEmpty(intersect(strictUpperBoundsOf(x), strictLowerBoundsOf(y)));
if (x.isEmpty() || y.isEmpty()) return false;
return x.end.shorterThan(y.start) ||
(x.end.isEqualTo(y.start) && (!x.includesEnd() && !y.includesStart()));
}

/**
Expand All @@ -224,7 +276,8 @@ static boolean endsStrictlyBefore(Interval x, Interval y) {
* @return whether x ends when y begins, with no overlap and no gap
*/
static boolean meets(Interval x, Interval y) {
return equals(strictUpperBoundsOf(x), strictUpperBoundsOf(strictLowerBoundsOf(y)));
if (x.isEmpty() || y.isEmpty()) return false;
return x.end.isEqualTo(y.start) && (x.endInclusivity != y.startInclusivity);
}

/**
Expand Down
Loading

0 comments on commit e57d756

Please sign in to comment.