All Downloads are FREE. Search and download functionalities are using the official Maven repository.

main.io.github.moonlightsuite.moonlight.online.signal.TimeChain Maven / Gradle / Ivy

Go to download

MoonLight is a light-weight Java-tool for monitoring temporal, spatial and spatio-temporal properties of distributed complex systems, such as Cyber-Physical Systems and Collective Adaptive Systems.

The newest version!
/*
 * MoonLight: a light-weight framework for runtime monitoring
 * Copyright (C) 2018-2021
 *
 * See the NOTICE file distributed with this work for additional information
 * regarding copyright ownership.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.github.moonlightsuite.moonlight.online.signal;

import io.github.moonlightsuite.moonlight.core.signal.Sample;
import org.jetbrains.annotations.NotNull;

import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Stream;

/**
 * A segment chain is similar to a {@link LinkedList}, providing some
 * specific features for {@link Sample}s, like checking temporal
 * integrity constraints, a custom iterator etc.
 *
 * 

Let old and new denote the state of * this before and after some mutating operations. * Two data integrity constraints must hold on the data structure: *

    *
  • * Monotonicity invariant: * forall element: * current.getStart() < next.getStart() && * current.getStart() > prev.getStart() * *
  • *
  • * Ending condition invariant: * end > getLast().getStart() && * old.end <= new.end *
  • *
* *

* TODO: they should be enforced by mutators and trivially * satisfied at the beginning, i.e. with no segments * * * @see Sample * @param The time domain of interest, typically a {@link Number} * @param */ public class TimeChain, V> implements Iterable> { /** * Internal representation of the chain */ private final List> segments; /** * Last time instant of definition of the chain */ private final T end; /** * It defines a chain of time segments that ends at some time instant * @param end the time instant from which the segment chain is not defined. */ public TimeChain(@NotNull T end) { this.end = end; this.segments = new ArrayList<>(); } /** * It defines a chain of time segments that ends at some time instant * @param end the time instant from which the segment chain is not defined. */ public TimeChain(@NotNull Sample element, @NotNull T end) { if(end.compareTo(element.getStart()) < 0) throw new IllegalArgumentException(ENDING_COND); this.end = end; segments = new ArrayList<>(); segments.add(element); } /** * WARNING: this interface assumes the programmer is taking responsibility * about the Monotonicity of the ordered list of segments. * (This means that if the List of segments has some * wrongly-ordered segments, the TimeChain MONOTONICITY * is violated, but it will go undetected) * @param segments chain of segments, passed as list * @param end last time value of the new chain */ public TimeChain(@NotNull List> segments, @NotNull T end) { if(segments.isEmpty()) throw new IllegalArgumentException("Invalid Segment list"); if(end.compareTo(segments.get(segments.size() - 1).getStart()) < 0) throw new IllegalArgumentException(ENDING_COND); this.end = end; this.segments = new ArrayList<>(segments); } /** * Adds a segment to the TimeChain. * @param e segment to add * @return true as specified by {@link List#add(Object)} * @throws IllegalArgumentException when monotonicity * or ending condition are violated. */ public boolean add(Sample e) { if(end.compareTo(e.getStart()) > 0) { checkMonotonicity(e.getStart()); return segments.add(e); } else throw new IllegalArgumentException(ENDING_COND); } /** * Checks if monotonicity is violated at time t * @param t new time value to check */ private void checkMonotonicity(T t) { if (!segments.isEmpty() && segments.get(segments.size() - 1).getStart().compareTo(t) > 0) throw new IllegalArgumentException(MONOTONICITY); } /** * Shallow copy of the chain * @return a new TimeChain defined on the same data */ public TimeChain copy() { return new TimeChain<>(segments, end); } /** * Generates a sub-chain of the current chain. * WARNING: Similarly to {@link List#subList(int, int)}, * the new chain shares the data structure with the current one, therefore * modifications will be reflected to both. * * @param from starting segment's index of the new chain * * @param to ending segment's index of the new chain * @param end ending time of the new chain * @return a new chain on current data, defined on the provided bounds */ public TimeChain subChain(int from, int to, T end) { List> newList = this.segments.subList(from, to); return new TimeChain<>(newList, end); } public boolean isEmpty() { return segments.isEmpty(); } public void clear() { segments.clear(); } /** * Returns the last element of the chain * @return last element of the chain */ public Sample getLast() { return segments.get(segments.size() - 1); } public ChainIterator> chainIterator() { return chainIterator(0); } public ChainIterator> chainIterator(int index) { if (index < 0 || index > segments.size()) throw new IndexOutOfBoundsException("Index: " + index); return new ChainIterator<>(segments, index); } public List> toUpdates() { List> updates = new ArrayList<>(segments.size()); for(int i = 0; i < segments.size(); i++) { T uEnd = end; if(i != segments.size() - 1) uEnd = segments.get(i + 1).getStart(); Update u = new Update<>(segments.get(i).getStart(), uEnd, segments.get(i).getValue()); updates.add(u); } return updates; } @NotNull @Override public Iterator> iterator() { return segments.iterator(); } @Override public void forEach(Consumer> action) { segments.forEach(action); } @Override public Spliterator> spliterator() { return segments.spliterator(); } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof TimeChain timeChain)) return false; return segments.equals(timeChain.segments) && end.equals(timeChain.end); } @Override public int hashCode() { return Objects.hash(segments, end); } public Stream> stream() { return segments.stream(); } public T getEnd() { return end; } public List> toList() { return segments; } public int size() { return segments.size(); } public Sample getFirst() { return segments.get(0); } public T getStart() { return this.getFirst().getStart(); } public Sample get(int index) { return segments.get(index); } private static final String MONOTONICITY = "Violating monotonicity: The chain must be in monotonic time order"; private static final String ENDING_COND = "Violating ending condition: The chain must either end " + "after the last segment or after the previous ending"; @Override public String toString() { return "TimeChain{" + "segments=" + segments + ", end=" + end + '}'; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy