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

main.io.github.moonlightsuite.moonlight.online.algorithms.Signals 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.algorithms;

import io.github.moonlightsuite.moonlight.core.signal.Sample;
import io.github.moonlightsuite.moonlight.online.signal.*;

import java.util.function.BiPredicate;

/**
 * Algorithms for basic signal primitives, precisely
 * 
    *
  • {@link #refine} for refining a signal given an update
  • *
  • {@link #refineChain} for refining a signal * given a sequence of updates *
  • *
  • {@link #select} for selecting a fragment of a signal * given some bounds *
  • *
*/ public class Signals { private Signals() {} // hidden constructor public static boolean refineChain(TimeChain s, TimeChain updates, BiPredicate refinable) { ChainIterator> utr = updates.chainIterator(); ChainIterator> itr = s.chainIterator(); Sample current = itr.next(); V prevV = current.getValue(); // Default when no previous value exists if(utr.hasNext()) { Update u = nextUpdate(utr, updates.getEnd()); while (true) { if (stillRefining(itr, current, u, refinable, prevV, s.getEnd())) { // Save the "next" as the new "current". prevV = current.getValue(); current = itr.next(); } else if (utr.hasNext()) { u = nextUpdate(utr, updates.getEnd()); current = itr.previous(); if (itr.hasPrevious()) current = itr.previous(); prevV = itr.tryPeekPrevious(current).getValue(); } else break; } } return itr.noEffects(); } public static boolean refine(TimeChain s, Update u, BiPredicate refinable) { ChainIterator> itr = s.chainIterator(); Sample current = itr.next(); V prevV = current.getValue(); // Default when no previous value exists while (stillRefining(itr, current, u, refinable, prevV, s.getEnd())) { // Save the "next" as the new "current". prevV = current.getValue(); current = itr.next(); } return itr.noEffects(); } private static Update nextUpdate(ChainIterator> itr, double end) { Sample fst = itr.next(); Double sEnd = itr.hasNext() ? itr.peekNext().getStart() : end; return new Update<>(fst.getStart(), sEnd, fst.getValue()); } /** * Signals initialization * * @param itr segment iterator * @param curr current segment * @param u update data * @return true when the update won't affect the signal anymore, * false otherwise. */ private static boolean stillRefining( ChainIterator> itr, Sample curr, Update u, BiPredicate refinable, V prevV, double lastT) { // Current segment unpacking double t = curr.getStart(); V v = curr.getValue(); double tNext = itr.hasNext() ? itr.peekNext().getStart() : lastT; // Update unpacking double from = u.getStart(); double to = u.getEnd(); V vNew = u.getValue(); return !doRefine(itr, from, to, vNew, t, tNext, v, prevV, refinable); } /** * Refinement logic. * @return true when the update has been completely processed. */ public static boolean doRefine( ChainIterator> itr, double from, double to, V vNew, // update double t, double tNext, V v, // current segment V prevV, // previous value BiPredicate refinable) { processUpdate(itr, from, to, vNew, t, tNext, v, prevV, refinable); // General Sub-case - to < tNext: // This means the current segment contains the end of the // area to update. Therefore, we must add a segment for the // last (not to be changed) part of the segment. // From now on the signal will not change. if(to < tNext && t != to) { add(itr, to, v); return true; } if(t == from && itr.hasNext() && itr.peekNext().getValue().equals(vNew)) { itr.next(); remove(itr); itr.previous(); } // Case 4 - t >= to: // The current segment is beyond the update horizon, // from now on, the signal will not change. return t >= to; } private static void processUpdate( ChainIterator> itr, double from, double to, V vNew, // update double t, double tNext, V v, // current segment V prevV, // previous value BiPredicate refinable) { // Case 1 - `from` in (t, tNext): // This means the update starts in the current segment if(t < from && tNext > from && refinable.test(v, vNew)) { add(itr, from, vNew); } // Case 2 - from == t: // This means the current segment starts exactly at // update time, therefore, its value must be updated if(t == from && !v.equals(vNew)) { update(itr, t, v, vNew, refinable, prevV); } // Case 3 - t in (from, to): // This means the current segment starts within the update // horizon and must therefore be updated if(t > from && t < to && refinable.test(v, vNew) && !v.equals(vNew)) { remove(itr); } } /** * Method for checking whether the provided interval refines the current * one, and to update it accordingly. * @param itr iterator of the signal segments * @param t current time instant * @param v current value * @param vNew new value from the update * @param refinable boolean predicate that tells whether it is refinable * @param prevV the value of the previous segment of the chain */ private static void update(ChainIterator> itr, double t, V v, V vNew, BiPredicate refinable, V prevV) { boolean isRefinable = refinable.test(v, vNew); if(isRefinable && prevV.equals(vNew)) { remove(itr); } else if (isRefinable) { Sample s = new TimeSegment<>(t, vNew); itr.set(s); } else { throw new UnsupportedOperationException("Refining interval: " + vNew + " is wider than " + "the original:" + v); } } /** * Removes the last object seen by the iterator. * Note that the iterator is one step ahead, so we have to bring it back * first. * @param itr iterator to update */ private static void remove(ChainIterator> itr) { itr.previous(); itr.remove(); } private static void add(ChainIterator> itr, Double start, V vNew) { if(itr.hasPrevious() && !itr.peekPrevious().getValue().equals(vNew)) { itr.add(new TimeSegment<>(start, vNew)); } if(itr.hasNext() && itr.peekNext().getValue().equals(vNew)) { itr.next(); remove(itr); if(itr.hasPrevious()) itr.previous(); } } /** * Selects a fragment of the given {@code TimeChain} * @param segments original chain of segments * @param from first time of interest for the caller * @param to last time of interest for the caller * @param Time domain of the chain * @param value domain of the chain * @return a sub-chain of the input signal */ public static , V> TimeChain select(TimeChain segments, T from, T to) { if(from.compareTo(to) > 0) throw new UnsupportedOperationException("Illegal selection span"); int start = 0; int end = 1; ChainIterator> itr = segments.chainIterator(); do { Sample current = itr.next(); // We went too far, the last returned is the last one useful if(current.getStart().compareTo(to) > 0) { end = itr.previousIndex(); break; } // current is before/at `from`, so it's the last useful index if(current.getStart().compareTo(from) <= 0) start = itr.previousIndex(); // Last segment, this is necessarily the last interesting one. if(itr.tryPeekNext(current).equals(current)) end = itr.previousIndex() + 1; } while(itr.hasNext()); return segments.subChain(start, end, to); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy