Skip to content

Commit

Permalink
Implemented ExtendedSignalMapper
Browse files Browse the repository at this point in the history
  • Loading branch information
MasWag committed Apr 20, 2024
1 parent 2b441d8 commit 94ebb7e
Show file tree
Hide file tree
Showing 26 changed files with 548 additions and 126 deletions.
25 changes: 25 additions & 0 deletions core/src/main/java/net/maswag/AbstractIOSignal.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package net.maswag;

import lombok.Getter;
import net.automatalib.word.Word;

@Getter
abstract public class AbstractIOSignal<I> implements IOSignal<I> {
Word<I> inputSignal, outputSignal;

public AbstractIOSignal(Word<I> inputSignal, Word<I> outputSignal) {
assert (inputSignal.size() == outputSignal.size());
this.inputSignal = inputSignal;
this.outputSignal = outputSignal;
}

@Override
public int size() {
return this.inputSignal.size();
}

@Override
public I getOutputSymbol(int i) {
return outputSignal.getSymbol(i);
}
}
23 changes: 23 additions & 0 deletions core/src/main/java/net/maswag/ContinuousNumericSUL.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package net.maswag;

import net.automatalib.word.Word;

import java.util.List;
import java.util.concurrent.ExecutionException;

/**
* Continuous-time systems under learning with numerical I/O.
*/
public interface ContinuousNumericSUL extends NumericSUL {
/**
* Execute the SUL by feeding single step input.
*
* @param inputSignal the input signal at one time step
* @return the output signal at one time step with the previous output signals
*/
@Override
ExtendedIOSignalPiece<List<Double>> step(List<Double> inputSignal);

@Override
IOContinuousSignal<List<Double>> execute(Word<List<Double>> inputSignal) throws InterruptedException, ExecutionException;
}
15 changes: 14 additions & 1 deletion core/src/main/java/net/maswag/ExtendedIOSignalPiece.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,21 @@ public class ExtendedIOSignalPiece<I> extends IOSignalPiece<I> {
*/
protected List<I> previousOutputSignals;

/**
* Constructor for the signal pieces.
*
* @param inputSignal the current step of the input signal
* @param outputSignal the current step of the output signal
* @param previousOutputSignals the output signals between the previous step and the current step
* excluding the previous step and including the current step
* @throws IllegalArgumentException if the current output signal is not the last element of previousOutputSignals
*/
public ExtendedIOSignalPiece(I inputSignal, I outputSignal, List<I> previousOutputSignals) {
super(inputSignal, outputSignal);
// The following equality must be based on the elements, not the references.
if (!outputSignal.equals(previousOutputSignals.get(previousOutputSignals.size() - 1))) {
throw new IllegalArgumentException("The current output signal must be the last element of previousOutputSignals");
}
this.previousOutputSignals = previousOutputSignals;
}

Expand All @@ -34,6 +47,6 @@ public ExtendedIOSignalPiece(I inputSignal, I outputSignal, List<I> previousOutp
*/
public ExtendedIOSignalPiece(I inputStep, ValueWithTime<I> outputSignal, Double from, Double to) {
super(inputStep, outputSignal.at(to));
this.previousOutputSignals = outputSignal.range(from, to);
this.previousOutputSignals = outputSignal.range(from, to).getValues();
}
}
12 changes: 11 additions & 1 deletion core/src/main/java/net/maswag/ExtendedSignalMapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,14 @@ public ExtendedSignalMapper() {
this.sigMap = Collections.emptyList();
}

/**
* @throws IllegalArgumentException if the given signal is not an instance of ExtendedIOSignalPiece
*/
//@ requires 0 <= index < size()
public double apply(int index, IOSignalPiece<List<Double>> concreteSignal) {
if (!(concreteSignal instanceof ExtendedIOSignalPiece)) {
throw new IllegalArgumentException("The given signal is not an instance of ExtendedIOSignalPiece");
}
return this.sigMap.get(index).apply((ExtendedIOSignalPiece<List<Double>>) concreteSignal);
}

Expand All @@ -44,8 +50,12 @@ public static ExtendedSignalMapper parse(String filename) throws IOException {
}

public static ExtendedSignalMapper parse(BufferedReader reader) {
return ExtendedSignalMapper.parse(reader.lines().collect(Collectors.toList()));
}

public static ExtendedSignalMapper parse(List<String> mapperDefinitions) {
List<Function<ExtendedIOSignalPiece<List<Double>>, Double>> rawList =
reader.lines().map(ExtendedSignalMapper::lineParse).collect(Collectors.toList());
mapperDefinitions.stream().map(ExtendedSignalMapper::lineParse).collect(Collectors.toList());

return new ExtendedSignalMapper(rawList);
}
Expand Down
103 changes: 103 additions & 0 deletions core/src/main/java/net/maswag/IOContinuousSignal.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package net.maswag;

import com.google.common.collect.Streams;
import lombok.Getter;
import net.automatalib.word.Word;
import org.apache.commons.math3.util.Pair;

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

@Getter
public class IOContinuousSignal<I> extends AbstractIOSignal<I> {
ValueWithTime<I> continuousOutputSignal;
Double signalStep;

public IOContinuousSignal(Word<I> inputSignal, Word<I> outputSignal, ValueWithTime<I> continuousOutputSignal, Double signalStep) {
super(inputSignal, outputSignal);
this.continuousOutputSignal = continuousOutputSignal;
this.signalStep = signalStep;
}

@Override
public Stream<IOSignalPiece<I>> stream() {
return Streams.zip(Streams.zip(inputSignal.stream(), outputSignal.stream(), Pair::new),
continuousOutputSignal.stream(this.signalStep),
(pair, value) -> new ExtendedIOSignalPiece<>(pair.getFirst(), pair.getSecond(), value));
}

@Override
public List<IOSignal<I>> prefixes(boolean longestFirst) {
Queue<Word<I>> inputPrefixes = new LinkedList<>(inputSignal.prefixes(longestFirst));
Queue<Word<I>> outputPrefixes = new LinkedList<>(outputSignal.prefixes(longestFirst));
List<IOSignal<I>> result = new ArrayList<>();

while (!inputPrefixes.isEmpty()) {
Word<I> inputPrefix = inputPrefixes.poll();
if (inputPrefix.isEmpty()) {
result.add(new IOContinuousSignal<>(inputPrefix,
Objects.requireNonNull(outputPrefixes.poll()),
new ValueWithTime<>(), // We use the empty values
signalStep));
} else {
// The first signal is at 0
double endTime = signalStep * (inputPrefix.size() - 1);
result.add(new IOContinuousSignal<>(inputPrefix,
Objects.requireNonNull(outputPrefixes.poll()),
continuousOutputSignal.range(Double.NEGATIVE_INFINITY, endTime),
signalStep));
}
}
return result;
}

@Override
public List<IOSignal<I>> suffixes(boolean longestFirst) {
double endTime = Double.POSITIVE_INFINITY;
Queue<Word<I>> inputSuffixes = new LinkedList<>(inputSignal.suffixes(longestFirst));
Queue<Word<I>> outputSuffixes = new LinkedList<>(outputSignal.suffixes(longestFirst));
List<IOSignal<I>> result = new ArrayList<>();

while (!inputSuffixes.isEmpty()) {
Word<I> inputSuffix = inputSuffixes.poll();
if (inputSuffix.isEmpty()) {
result.add(new IOContinuousSignal<>(inputSuffix,
Objects.requireNonNull(outputSuffixes.poll()),
new ValueWithTime<>(), // We use the empty values
signalStep));
} else {
// The first signal is at 0
double beginTime = signalStep * (inputSignal.size() - inputSuffix.size());
result.add(new IOContinuousSignal<>(inputSuffix,
Objects.requireNonNull(outputSuffixes.poll()),
continuousOutputSignal.range(beginTime, endTime),
signalStep));
}
}
return result;
}

@Override
public IOSignal<I> suffix(int suffixLen) {
double beginTime = signalStep * (inputSignal.size() - suffixLen);
return new IOContinuousSignal<>(inputSignal.suffix(suffixLen), outputSignal.suffix(suffixLen),
continuousOutputSignal.range(beginTime, Double.POSITIVE_INFINITY), signalStep);
}

@Override
public IOSignal<I> subWord(int fromIndex) {
double beginTime = signalStep * fromIndex;
return new IOContinuousSignal<>(inputSignal.subWord(fromIndex), outputSignal.subWord(fromIndex),
continuousOutputSignal.range(beginTime, Double.POSITIVE_INFINITY), signalStep);
}

/** {@inheritDoc} */
@Override
public IOSignal<I> subWord(int fromIndex, int toIndex) {
double beginTime = signalStep * fromIndex;
double endTime = signalStep * toIndex;
return new IOContinuousSignal<>(inputSignal.subWord(fromIndex, toIndex),
outputSignal.subWord(fromIndex, toIndex),
continuousOutputSignal.range(beginTime, endTime), signalStep);
}
}
62 changes: 62 additions & 0 deletions core/src/main/java/net/maswag/IODiscreteSignal.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package net.maswag;

import com.google.common.collect.Streams;
import lombok.Getter;
import net.automatalib.word.Word;

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

/**
* A discrete-time signal with both input and output values.
*/
public class IODiscreteSignal<I> extends AbstractIOSignal<I> {
public IODiscreteSignal(Word<I> inputSignal, Word<I> outputSignal) {
super(inputSignal, outputSignal);
}

@Override
public Stream<IOSignalPiece<I>> stream() {
return Streams.zip(inputSignal.stream(), outputSignal.stream(), IOSignalPiece::new);
}

@Override
public List<IOSignal<I>> prefixes(boolean longestFirst) {
Queue<Word<I>> inputPrefixes = new LinkedList<>(inputSignal.prefixes(longestFirst));
Queue<Word<I>> outputPrefixes = new LinkedList<>(outputSignal.prefixes(longestFirst));
List<IOSignal<I>> result = new ArrayList<>();

while (!inputPrefixes.isEmpty()) {
result.add(new IODiscreteSignal<>(inputPrefixes.poll(), Objects.requireNonNull(outputPrefixes.poll())));
}
return result;
}

@Override
public List<IOSignal<I>> suffixes(boolean longestFirst) {
Queue<Word<I>> inputSuffixes = new LinkedList<>(inputSignal.suffixes(longestFirst));
Queue<Word<I>> outputSuffixes = new LinkedList<>(outputSignal.suffixes(longestFirst));
List<IOSignal<I>> result = new ArrayList<>();

while (!inputSuffixes.isEmpty()) {
result.add(new IODiscreteSignal<>(inputSuffixes.poll(), Objects.requireNonNull(outputSuffixes.poll())));
}
return result;
}

@Override
public IOSignal<I> suffix(int suffixLen) {
return new IODiscreteSignal<>(inputSignal.suffix(suffixLen), outputSignal.suffix(suffixLen));
}

@Override
public IOSignal<I> subWord(int fromIndex) {
return new IODiscreteSignal<>(inputSignal.subWord(fromIndex), outputSignal.subWord(fromIndex));
}

/** {@inheritDoc} */
@Override
public IOSignal<I> subWord(int fromIndex, int toIndex) {
return new IODiscreteSignal<>(inputSignal.subWord(fromIndex, toIndex), outputSignal.subWord(fromIndex, toIndex));
}
}
96 changes: 30 additions & 66 deletions core/src/main/java/net/maswag/IOSignal.java
Original file line number Diff line number Diff line change
@@ -1,85 +1,49 @@
package net.maswag;

import com.google.common.collect.Streams;
import lombok.Getter;
import net.automatalib.word.Word;

import java.util.*;
import java.util.List;
import java.util.stream.Stream;

@Getter
public class IOSignal<I> {
Word<I> inputSignal, outputSignal;

public IOSignal(Word<I> inputSignal, Word<I> outputSignal) {
assert (inputSignal.size() == outputSignal.size());
this.inputSignal = inputSignal;
this.outputSignal = outputSignal;
}

public int size() {
return this.inputSignal.size();
}

public int length() {
/**
* A signal with both input and output values.
*/
public interface IOSignal<I> {
/**
* Returns the number of steps of the signal.
*/
int size();

/**
* Returns the number of steps of the signal.
*/
default int length() {
return size();
}

public Stream<IOSignalPiece<I>> stream() {
return Streams.zip(inputSignal.stream(), outputSignal.stream(), IOSignalPiece::new);
}
Stream<IOSignalPiece<I>> stream();

public List<IOSignal<I>> prefixes(boolean longestFirst) {
Queue<Word<I>> inputSiffixes = new LinkedList<>(inputSignal.prefixes(longestFirst));
Queue<Word<I>> outputSiffixes = new LinkedList<>(outputSignal.prefixes(longestFirst));
List<IOSignal<I>> result = new ArrayList<>();
List<IOSignal<I>> prefixes(boolean longestFirst);

while (!inputSiffixes.isEmpty()) {
result.add(new IOSignal<>(inputSiffixes.poll(), Objects.requireNonNull(outputSiffixes.poll())));
}
return result;
}
List<IOSignal<I>> suffixes(boolean longestFirst);

public List<IOSignal<I>> suffixes(boolean longestFirst) {
Queue<Word<I>> inputSuffixes = new LinkedList<>(inputSignal.suffixes(longestFirst));
Queue<Word<I>> outputSuffixes = new LinkedList<>(outputSignal.suffixes(longestFirst));
List<IOSignal<I>> result = new ArrayList<>();
IOSignal<I> suffix(int suffixLen);

while (!inputSuffixes.isEmpty()) {
result.add(new IOSignal<>(inputSuffixes.poll(), Objects.requireNonNull(outputSuffixes.poll())));
}
return result;
}
IOSignal<I> subWord(int fromIndex);

public IOSignal<I> suffix(int suffixLen) {
return new IOSignal<>(inputSignal.suffix(suffixLen), outputSignal.suffix(suffixLen));
}

public IOSignal<I> subWord(int fromIndex) {
return new IOSignal<>(inputSignal.subWord(fromIndex), outputSignal.subWord(fromIndex));
}

public IOSignal<I> subWord(int fromIndex, int toIndex) {
return new IOSignal<>(inputSignal.subWord(fromIndex, toIndex), outputSignal.subWord(fromIndex, toIndex));
}
/**
* Return a sub-signal of the signal from the given index (inclusive) to the given index (exclusive).
*/
IOSignal<I> subWord(int fromIndex, int toIndex);

public boolean isEmpty() {
/**
* Returns true if the signal is empty.
*/
default boolean isEmpty() {
return size() == 0;
}

public I getOutputSymbol(int i) {
return outputSignal.getSymbol(i);
}
I getOutputSymbol(int i);

class NumericIOSignal extends IOSignal<List<Double>> {
public NumericIOSignal(Word<List<Double>> inputSignal, Word<List<Double>> outputSignal) {
super(inputSignal, outputSignal);
}
}
net.automatalib.word.Word<I> getInputSignal();

class LogicalIOSignal extends IOSignal<Set<String>> {
public LogicalIOSignal(Word<Set<String>> inputSignal, Word<Set<String>> outputSignal) {
super(inputSignal, outputSignal);
}
}
net.automatalib.word.Word<I> getOutputSignal();
}
Loading

0 comments on commit 94ebb7e

Please sign in to comment.