Skip to content

Commit

Permalink
Violations timeline
Browse files Browse the repository at this point in the history
  • Loading branch information
JoelCourtney committed Mar 28, 2024
1 parent 3ee1792 commit 4d1500f
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package gov.nasa.jpl.aerie.constraints

/** An activity ID, referencing either a directive or instance. */
sealed interface ActivityId {
/***/ data class InstanceId(/***/ val id: Long): ActivityId
/***/ data class DirectiveId(/***/ val id: Long): ActivityId
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package gov.nasa.jpl.aerie.constraints

import gov.nasa.jpl.aerie.timeline.Interval
import gov.nasa.jpl.aerie.timeline.payloads.IntervalLike

/** A single violation of a constraint. */
data class Violation(
/** Interval on which the violation occurs. */
override val interval: Interval,

/** List of associated activities (directives or instances) that are related to the violation. */
val ids: List<ActivityId> = listOf()
) : IntervalLike<Violation> {

override fun withNewInterval(i: Interval) = Violation(i, ids)

/** Constructs a violation on the same interval with a different list of ids. */
fun withNewIds(vararg id: ActivityId) = Violation(interval, id.asList())

/** Constructs a violation on the same interval with a different list of ids. */
fun withNewIds(ids: List<ActivityId>) = Violation(interval, ids)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package gov.nasa.jpl.aerie.constraints

import gov.nasa.jpl.aerie.constraints.ActivityId.DirectiveId
import gov.nasa.jpl.aerie.constraints.ActivityId.InstanceId
import gov.nasa.jpl.aerie.constraints.Violations.Companion.getActivityId
import gov.nasa.jpl.aerie.timeline.BaseTimeline
import gov.nasa.jpl.aerie.timeline.BoundsTransformer
import gov.nasa.jpl.aerie.timeline.Timeline
import gov.nasa.jpl.aerie.timeline.collections.Instances
import gov.nasa.jpl.aerie.timeline.collections.Intervals
import gov.nasa.jpl.aerie.timeline.collections.Windows
import gov.nasa.jpl.aerie.timeline.collections.profiles.Real
import gov.nasa.jpl.aerie.timeline.ops.*
import gov.nasa.jpl.aerie.timeline.ops.coalesce.CoalesceNoOp
import gov.nasa.jpl.aerie.timeline.payloads.IntervalLike
import gov.nasa.jpl.aerie.timeline.payloads.activities.Activity
import gov.nasa.jpl.aerie.timeline.payloads.activities.Directive
import gov.nasa.jpl.aerie.timeline.payloads.activities.Instance
import gov.nasa.jpl.aerie.timeline.util.preprocessList

/** A timeline of [Violations][Violation]. */
data class Violations(private val timeline: Timeline<Violation, Violations>):
Timeline<Violation, Violations> by timeline,
ParallelOps<Violation, Violations>,
NonZeroDurationOps<Violation, Violations>,
CoalesceNoOp<Violation, Violations>
{
constructor(vararg violation: Violation): this(violation.asList())
constructor(violations: List<Violation>): this(BaseTimeline(::Violations, preprocessList(violations, null)))

/**
* Maps the list of associated activity ids on each violation.
*
* @param f a function which takes a [Violation] and returns a new list of ids.
*/
fun mapIds(f: (Violation) -> List<ActivityId>) = unsafeMap(BoundsTransformer.IDENTITY, false) { it.withNewIds(f(it)) }

/***/ companion object {
/** Creates a [Violations] object that violates when this profile equals a given value. */
@JvmStatic fun <V: Any> SerialConstantOps<V, *>.violateOn(v: V) = isolateEqualTo(v).violations()

/** Creates a [Violations] object that violates when this profile equals a given value. */
@JvmStatic fun Real.violateOn(n: Number) = equalTo(n).violateOn(true)

/**
* Creates a [Violations] object that violates on every object in the timeline.
*
* If the object is an activity, it will record the directive or instance id.
*/
@JvmStatic fun <I: IntervalLike<I>> ParallelOps<I, *>.violations() =
unsafeMap(::Violations, BoundsTransformer.IDENTITY, false) {
Violation(
it.interval,
listOfNotNull(it.getActivityId())
)
}

/** Creates a [Violations] object that violates inside each interval. */
@JvmStatic fun Windows.violateInside() = unsafeCast(::Intervals).violations()
/** Creates a [Violations] object that violates outside each interval. */
@JvmStatic fun Windows.violateOutside() = complement().violateInside()

/**
* Creates a [Violations] object from two timelines, that violates whenever they have overlap.
*
* If either object is an activity, it will record the directive or instance id.
*/
@JvmStatic infix fun <V: IntervalLike<V>, W: IntervalLike<W>> GeneralOps<V, *>.mutex(other: GeneralOps<W, *>) =
unsafeMap2(::Violations, other) { l, r, i -> Violation(
i,
listOfNotNull(
l.getActivityId(),
r.getActivityId()
)
)}

private fun <V: IntervalLike<V>> V.getActivityId() = when (this) {
is Instance<*> -> InstanceId(id)
is Directive<*> -> DirectiveId(id)
else -> null
}
}
}


0 comments on commit 4d1500f

Please sign in to comment.