commit
39e2eee613
|
@ -0,0 +1,45 @@
|
||||||
|
package li.strolch.model.timedstate;
|
||||||
|
|
||||||
|
import li.strolch.model.timevalue.ITimeValue;
|
||||||
|
import li.strolch.model.timevalue.ITimeVariable;
|
||||||
|
import li.strolch.model.timevalue.IValue;
|
||||||
|
import li.strolch.model.timevalue.IValueChange;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A time based state characterized by a {@link IValue} object implementation.
|
||||||
|
*
|
||||||
|
* @author martin_smock
|
||||||
|
*
|
||||||
|
* @param <T>
|
||||||
|
* IValue implementation representing the state at a given time
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
public interface ITimedState<T extends IValue> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the new {@link ITimeValue} matching the value in the future
|
||||||
|
*/
|
||||||
|
ITimeValue<T> getNextMatch(final Long time, T value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the new {@link ITimeValue} matching the value in the future
|
||||||
|
*/
|
||||||
|
ITimeValue<T> getPreviousMatch(final Long time, T value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param change
|
||||||
|
* the state change to be applied
|
||||||
|
*/
|
||||||
|
void applyChange(final IValueChange<T> change);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the state at the given time
|
||||||
|
*/
|
||||||
|
ITimeValue<T> getStateAt(final Long time);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return get the states evolution in time
|
||||||
|
*/
|
||||||
|
ITimeVariable<T> getTimeEvolution();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
package li.strolch.model.timedstate;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import li.strolch.model.timevalue.ITimeValue;
|
||||||
|
import li.strolch.model.timevalue.ITimeVariable;
|
||||||
|
import li.strolch.model.timevalue.IValue;
|
||||||
|
import li.strolch.model.timevalue.IValueChange;
|
||||||
|
import li.strolch.model.timevalue.impl.TimeVariable;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author martin_smock
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
public class TimedState<T extends IValue> implements ITimedState<T> {
|
||||||
|
|
||||||
|
private ITimeVariable<T> timeVariable = new TimeVariable<T>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public ITimeValue<T> getNextMatch(final Long time, final T value) {
|
||||||
|
Collection<ITimeValue<T>> futureValues = timeVariable.getFutureValues(time);
|
||||||
|
for (ITimeValue<T> iTimeValue : futureValues) {
|
||||||
|
if (iTimeValue.getValue().matches(value)) {
|
||||||
|
return iTimeValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public ITimeValue<T> getPreviousMatch(final Long time, final T value) {
|
||||||
|
Collection<ITimeValue<T>> pastValues = timeVariable.getPastValues(time);
|
||||||
|
List<ITimeValue<T>> asList = new ArrayList<ITimeValue<T>>(pastValues);
|
||||||
|
Collections.reverse(asList);
|
||||||
|
for (ITimeValue<T> iTimeValue : asList) {
|
||||||
|
if (iTimeValue.getValue().matches(value)) {
|
||||||
|
return iTimeValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void applyChange(final IValueChange<T> change) {
|
||||||
|
timeVariable.applyChange(change);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ITimeValue<T> getStateAt(final Long time) {
|
||||||
|
return timeVariable.getValueAt(time);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ITimeVariable<T> getTimeEvolution() {
|
||||||
|
return timeVariable;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
package li.strolch.model.timevalue;
|
||||||
|
|
||||||
|
import li.strolch.model.timevalue.impl.TimeVariable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for timed value objects to be used with the {@link TimeVariable}
|
||||||
|
*
|
||||||
|
* @author martin_smock
|
||||||
|
*
|
||||||
|
* @param <T>
|
||||||
|
* the backing value of the timed value object
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
public interface ITimeValue<T extends IValue> extends Comparable<ITimeValue<T>> {
|
||||||
|
|
||||||
|
ITimeValue<T> setValue(final T value);
|
||||||
|
|
||||||
|
T getValue();
|
||||||
|
|
||||||
|
Long getTime();
|
||||||
|
|
||||||
|
ITimeValue<T> add(final T change);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
package li.strolch.model.timevalue;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A timed variable storing a ordered sequence of {@link ITimeValue} objects
|
||||||
|
* modeling a time evolution of a quantity.
|
||||||
|
*
|
||||||
|
* @author martin_smock
|
||||||
|
*
|
||||||
|
* @param <T>
|
||||||
|
* the backing value of the timed value object
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
public interface ITimeVariable<T extends IValue> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set the value at a point in time to a given time value object
|
||||||
|
*
|
||||||
|
* @param time
|
||||||
|
* the time to set the {@link IValue}
|
||||||
|
* @param value
|
||||||
|
* the {@link IValue} to set
|
||||||
|
*/
|
||||||
|
void setValueAt(final Long time, final T value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the latest {@link ITimeValue} whose time field is less or equal to
|
||||||
|
* the time given
|
||||||
|
*/
|
||||||
|
ITimeValue<T> getValueAt(final Long time);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies a {@link IValueChange} propagating the change to all future
|
||||||
|
* values starting from the time of the change.
|
||||||
|
*
|
||||||
|
* @param change
|
||||||
|
* the {@link IValueChange} to be applied
|
||||||
|
*/
|
||||||
|
void applyChange(final IValueChange<T> change);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all {@link ITimeValue} objects whose time field is greater or equal
|
||||||
|
* to the given time
|
||||||
|
*
|
||||||
|
* @param time
|
||||||
|
* the time the sequence starts with
|
||||||
|
* @return the sequence of {@link ITimeValue} objects in the future
|
||||||
|
*/
|
||||||
|
Collection<ITimeValue<T>> getFutureValues(final Long time);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all {@link ITimeValue} objects whose time field is strictly smaller
|
||||||
|
* than the given time
|
||||||
|
*
|
||||||
|
* @param time
|
||||||
|
* the time the sequence starts with
|
||||||
|
* @return the sequence of {@link ITimeValue} objects in the future
|
||||||
|
*/
|
||||||
|
Collection<ITimeValue<T>> getPastValues(final Long time);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* removes {@link ITimeValue} objects from the sequence, where the successor
|
||||||
|
* matches value. I.e considering a pair of adjacent {@link ITimeValue}
|
||||||
|
* objects in the sequence which have the same {@link IValue}, the later one
|
||||||
|
* is removed, since it contains no additional information.
|
||||||
|
*/
|
||||||
|
void compact();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
package li.strolch.model.timevalue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A value object defining some basic algebraic operations. Mathematically
|
||||||
|
* speaking {@link IValue} objects define a group with a addition operation.
|
||||||
|
*
|
||||||
|
* @author martin_smock
|
||||||
|
*
|
||||||
|
* @param <T>
|
||||||
|
* any object for which a (generalized) add operation can be defined.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface IValue<T> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the backing value
|
||||||
|
*/
|
||||||
|
T getValue();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return a value with the backing value added to the argument value
|
||||||
|
*/
|
||||||
|
IValue<T> add(T o);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true, if the backing values match.
|
||||||
|
*/
|
||||||
|
boolean matches(IValue<T> other);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the inverse value, such that add(value.getInverse()) returns the
|
||||||
|
* neutral element of the group
|
||||||
|
*/
|
||||||
|
IValue<T> getInverse();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return a copy of this
|
||||||
|
*/
|
||||||
|
IValue<T> getCopy();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
package li.strolch.model.timevalue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for operators to be used to change the values of {@link ITimeValue}
|
||||||
|
* in a {@link ITimeVariable}.
|
||||||
|
*
|
||||||
|
* @author martin_smock
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
public interface IValueChange<T extends IValue> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the time this change has to be applied
|
||||||
|
*/
|
||||||
|
Long getTime();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the value of the change
|
||||||
|
*/
|
||||||
|
T getValue();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the inverse neutralizing a change. Very useful to undo changes
|
||||||
|
* applied.
|
||||||
|
*/
|
||||||
|
IValueChange<T> getInverse();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
package li.strolch.model.timevalue.impl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper for java.util.String object defining a inverse to support algebraic
|
||||||
|
* operations.
|
||||||
|
*
|
||||||
|
* @author martin_smock
|
||||||
|
*/
|
||||||
|
public class AString {
|
||||||
|
|
||||||
|
private final String string;
|
||||||
|
private final boolean inverse;
|
||||||
|
|
||||||
|
public AString(final String string) {
|
||||||
|
this.string = string;
|
||||||
|
this.inverse = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AString(final String string, final boolean inverse) {
|
||||||
|
this.string = string;
|
||||||
|
this.inverse = inverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getString() {
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInverse() {
|
||||||
|
return inverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AString getInverse() {
|
||||||
|
return new AString(string, !inverse);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = prime * result + (inverse ? 1231 : 1237);
|
||||||
|
result = prime * result + ((string == null) ? 0 : string.hashCode());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj)
|
||||||
|
return true;
|
||||||
|
if (obj == null)
|
||||||
|
return false;
|
||||||
|
if (getClass() != obj.getClass())
|
||||||
|
return false;
|
||||||
|
AString other = (AString) obj;
|
||||||
|
if (inverse != other.inverse)
|
||||||
|
return false;
|
||||||
|
if (string == null) {
|
||||||
|
if (other.string != null)
|
||||||
|
return false;
|
||||||
|
} else if (!string.equals(other.string))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "AString [string=" + string + ", inverse=" + inverse + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,94 @@
|
||||||
|
package li.strolch.model.timevalue.impl;
|
||||||
|
|
||||||
|
import li.strolch.model.timevalue.ITimeValue;
|
||||||
|
import li.strolch.model.timevalue.IValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link IValue} implementation to work with Double valued {@link ITimeValue} objects
|
||||||
|
*
|
||||||
|
* @author martin_smock
|
||||||
|
*/
|
||||||
|
public class DoubleValue implements IValue<Double> {
|
||||||
|
|
||||||
|
public static final DoubleValue NEUTRAL = new DoubleValue(0.0d);
|
||||||
|
|
||||||
|
private Double value;
|
||||||
|
|
||||||
|
public DoubleValue(Double value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DoubleValue(double value) {
|
||||||
|
this.value = Double.valueOf(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DoubleValue(Integer value) {
|
||||||
|
this.value = this.value.doubleValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public DoubleValue(int value) {
|
||||||
|
this.value = Integer.valueOf(value).doubleValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public DoubleValue(String valueAsString) throws NumberFormatException {
|
||||||
|
this.value = Double.parseDouble(valueAsString);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DoubleValue add(Double o) {
|
||||||
|
value += o;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Double getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "DoubleValue [value=" + value + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(IValue<Double> other) {
|
||||||
|
return this.value.equals(other.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DoubleValue getInverse() {
|
||||||
|
return new DoubleValue(-getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DoubleValue getCopy(){
|
||||||
|
return new DoubleValue(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = prime * result + ((value == null) ? 0 : value.hashCode());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj)
|
||||||
|
return true;
|
||||||
|
if (obj == null)
|
||||||
|
return false;
|
||||||
|
if (getClass() != obj.getClass())
|
||||||
|
return false;
|
||||||
|
DoubleValue other = (DoubleValue) obj;
|
||||||
|
if (value == null) {
|
||||||
|
if (other.value != null)
|
||||||
|
return false;
|
||||||
|
} else if (!value.equals(other.value))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,86 @@
|
||||||
|
package li.strolch.model.timevalue.impl;
|
||||||
|
|
||||||
|
import li.strolch.model.timevalue.ITimeValue;
|
||||||
|
import li.strolch.model.timevalue.IValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link IValue} implementation to work with Integer valued {@link ITimeValue}
|
||||||
|
* objects
|
||||||
|
*
|
||||||
|
* @author martin_smock
|
||||||
|
*/
|
||||||
|
public class IntegerValue implements IValue<Integer> {
|
||||||
|
|
||||||
|
public static final IntegerValue NEUTRAL = new IntegerValue(0);
|
||||||
|
|
||||||
|
private Integer value;
|
||||||
|
|
||||||
|
public IntegerValue(Integer value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IntegerValue(int value) {
|
||||||
|
this.value = Integer.valueOf(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IntegerValue(String valueAsString) throws NumberFormatException {
|
||||||
|
this.value = Integer.parseInt(valueAsString);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IntegerValue add(Integer o) {
|
||||||
|
value += o;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(IValue<Integer> other) {
|
||||||
|
return this.value.equals(other.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IntegerValue getInverse() {
|
||||||
|
return new IntegerValue(-getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "IntegerValue [value=" + value + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IntegerValue getCopy() {
|
||||||
|
return new IntegerValue(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = prime * result + ((value == null) ? 0 : value.hashCode());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj)
|
||||||
|
return true;
|
||||||
|
if (obj == null)
|
||||||
|
return false;
|
||||||
|
if (getClass() != obj.getClass())
|
||||||
|
return false;
|
||||||
|
IntegerValue other = (IntegerValue) obj;
|
||||||
|
if (value == null) {
|
||||||
|
if (other.value != null)
|
||||||
|
return false;
|
||||||
|
} else if (!value.equals(other.value))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,86 @@
|
||||||
|
package li.strolch.model.timevalue.impl;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import li.strolch.model.timevalue.ITimeValue;
|
||||||
|
import li.strolch.model.timevalue.IValue;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link IValue} implementation to work with String valued {@link ITimeValue}
|
||||||
|
* objects. Since a java.util.String object does not define a inverse, a
|
||||||
|
* algebraic {@link AString} wrapper is used.
|
||||||
|
*
|
||||||
|
* @author martin_smock
|
||||||
|
*/
|
||||||
|
public class StringSetValue implements IValue<Set<AString>> {
|
||||||
|
|
||||||
|
private static Set<AString> neu = Collections.emptySet();
|
||||||
|
public static final IValue<Set<AString>> NEUTRAL = new StringSetValue(neu);
|
||||||
|
|
||||||
|
private Set<AString> aStrings = new HashSet<AString>();
|
||||||
|
|
||||||
|
public StringSetValue() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public StringSetValue(final Set<AString> aStrings) {
|
||||||
|
this.aStrings = aStrings;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<AString> getValue() {
|
||||||
|
return aStrings;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IValue<Set<AString>> add(Set<AString> o) {
|
||||||
|
|
||||||
|
Set<AString> toBeAdded = new HashSet<AString>(o);
|
||||||
|
|
||||||
|
for (Iterator<AString> iter1 = toBeAdded.iterator(); iter1.hasNext();) {
|
||||||
|
AString toAdd = iter1.next();
|
||||||
|
for (Iterator<AString> iter = aStrings.iterator(); iter.hasNext();) {
|
||||||
|
AString aString = iter.next();
|
||||||
|
boolean valueMatch = aString.getString().equals(toAdd.getString());
|
||||||
|
boolean compensate = (toAdd.isInverse() && !aString.isInverse())
|
||||||
|
|| (!toAdd.isInverse() && aString.isInverse());
|
||||||
|
if (valueMatch && compensate) {
|
||||||
|
iter.remove();
|
||||||
|
iter1.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
aStrings.addAll(toBeAdded);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(IValue<Set<AString>> other) {
|
||||||
|
return this.getValue().equals(other.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IValue<Set<AString>> getInverse() {
|
||||||
|
Set<AString> inverseSet = new HashSet<AString>();
|
||||||
|
for (AString as : aStrings) {
|
||||||
|
inverseSet.add(as.getInverse());
|
||||||
|
}
|
||||||
|
StringSetValue inverse = new StringSetValue();
|
||||||
|
inverse.aStrings = inverseSet;
|
||||||
|
return inverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StringSetValue getCopy() {
|
||||||
|
return new StringSetValue(aStrings);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "StringSetValue [aStrings=" + aStrings + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,90 @@
|
||||||
|
package li.strolch.model.timevalue.impl;
|
||||||
|
|
||||||
|
import li.strolch.model.timevalue.ITimeValue;
|
||||||
|
import li.strolch.model.timevalue.IValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author martin_smock
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
public class TimeValue<T extends IValue> implements ITimeValue <T> {
|
||||||
|
|
||||||
|
protected final Long time;
|
||||||
|
protected T value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param time
|
||||||
|
* @param value
|
||||||
|
*/
|
||||||
|
public TimeValue(final Long time, final T value){
|
||||||
|
this.time = time;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public T getValue() {
|
||||||
|
return (T) value.getCopy();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long getTime() {
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ITimeValue<T> setValue(final T value) {
|
||||||
|
this.value = value;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
public ITimeValue<T> add(final T change) {
|
||||||
|
this.value.add(change.getValue());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(final ITimeValue<T> arg0) {
|
||||||
|
return this.getTime().compareTo(arg0.getTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "TimeValue [time=" + time + ", value=" + value + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = prime * result + ((time == null) ? 0 : time.hashCode());
|
||||||
|
result = prime * result + ((value == null) ? 0 : value.hashCode());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj)
|
||||||
|
return true;
|
||||||
|
if (obj == null)
|
||||||
|
return false;
|
||||||
|
if (getClass() != obj.getClass())
|
||||||
|
return false;
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
TimeValue<T> other = (TimeValue<T>) obj;
|
||||||
|
if (time == null) {
|
||||||
|
if (other.time != null)
|
||||||
|
return false;
|
||||||
|
} else if (!time.equals(other.time))
|
||||||
|
return false;
|
||||||
|
if (value == null) {
|
||||||
|
if (other.value != null)
|
||||||
|
return false;
|
||||||
|
} else if (!value.equals(other.value))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,98 @@
|
||||||
|
package li.strolch.model.timevalue.impl;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.SortedSet;
|
||||||
|
import java.util.TreeSet;
|
||||||
|
|
||||||
|
import li.strolch.model.timevalue.ITimeValue;
|
||||||
|
import li.strolch.model.timevalue.ITimeVariable;
|
||||||
|
import li.strolch.model.timevalue.IValue;
|
||||||
|
import li.strolch.model.timevalue.IValueChange;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author martin_smock
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
public class TimeVariable<T extends IValue> implements ITimeVariable<T> {
|
||||||
|
|
||||||
|
public SortedSet<ITimeValue<T>> container = new TreeSet<ITimeValue<T>>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ITimeValue<T> getValueAt(final Long time) {
|
||||||
|
ITimeValue<T> tmp = null;
|
||||||
|
for (ITimeValue<T> value : container) {
|
||||||
|
if (value.getTime() <= time) {
|
||||||
|
tmp = value;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setValueAt(final Long time, final T targetValue) {
|
||||||
|
ITimeValue<T> current = getValueAt(time);
|
||||||
|
if (current != null && current.getTime().equals(time)) {
|
||||||
|
current.setValue(targetValue);
|
||||||
|
} else {
|
||||||
|
container.add(new TimeValue<T>(time, targetValue));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SortedSet<ITimeValue<T>> getFutureValues(final Long time) {
|
||||||
|
TimeValue<T> picker = new TimeValue<T>(time, null);
|
||||||
|
return new TreeSet<ITimeValue<T>>(container.tailSet(picker));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<ITimeValue<T>> getPastValues(final Long time) {
|
||||||
|
TimeValue<T> picker = new TimeValue<T>(time, null);
|
||||||
|
return new TreeSet<ITimeValue<T>>(container.headSet(picker));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void applyChange(final IValueChange<T> change) {
|
||||||
|
|
||||||
|
SortedSet<ITimeValue<T>> futureValues = getFutureValues(change.getTime());
|
||||||
|
for (ITimeValue<T> value : futureValues) {
|
||||||
|
value.add(change.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
ITimeValue<T> initialValue = getValueAt(change.getTime());
|
||||||
|
if (initialValue == null) {
|
||||||
|
ITimeValue<T> newValue = new TimeValue<T>(change.getTime(), change.getValue());
|
||||||
|
container.add(newValue);
|
||||||
|
} else if (initialValue.getTime().longValue() < change.getTime().longValue()) {
|
||||||
|
ITimeValue<T> newValue = new TimeValue<T>(change.getTime(), initialValue.getValue());
|
||||||
|
newValue.add(change.getValue());
|
||||||
|
container.add(newValue);
|
||||||
|
}
|
||||||
|
compact();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
public void compact() {
|
||||||
|
|
||||||
|
if (container.size() < 2)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Iterator<ITimeValue<T>> iterator = container.iterator();
|
||||||
|
ITimeValue<T> predecessor = iterator.next();
|
||||||
|
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
ITimeValue<T> successor = iterator.next();
|
||||||
|
if (successor.getValue().matches(predecessor.getValue())) {
|
||||||
|
iterator.remove();
|
||||||
|
} else {
|
||||||
|
predecessor = successor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,77 @@
|
||||||
|
package li.strolch.model.timevalue.impl;
|
||||||
|
|
||||||
|
import li.strolch.model.timevalue.IValue;
|
||||||
|
import li.strolch.model.timevalue.IValueChange;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author martin_smock
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
public class ValueChange<T extends IValue> implements IValueChange<T> {
|
||||||
|
|
||||||
|
protected final Long time;
|
||||||
|
protected final T value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param time
|
||||||
|
* @param value
|
||||||
|
*/
|
||||||
|
public ValueChange(final Long time, final T value) {
|
||||||
|
this.time = time;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long getTime() {
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public T getValue() {
|
||||||
|
return (T) value.getCopy();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public IValueChange<T> getInverse() {
|
||||||
|
return new ValueChange(time, value.getInverse());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj)
|
||||||
|
return true;
|
||||||
|
if (obj == null)
|
||||||
|
return false;
|
||||||
|
if (getClass() != obj.getClass())
|
||||||
|
return false;
|
||||||
|
ValueChange<?> other = (ValueChange<?>) obj;
|
||||||
|
if (time == null) {
|
||||||
|
if (other.time != null)
|
||||||
|
return false;
|
||||||
|
} else if (!time.equals(other.time))
|
||||||
|
return false;
|
||||||
|
if (value == null) {
|
||||||
|
if (other.value != null)
|
||||||
|
return false;
|
||||||
|
} else if (!value.equals(other.value))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = prime * result + ((time == null) ? 0 : time.hashCode());
|
||||||
|
result = prime * result + ((value == null) ? 0 : value.hashCode());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "ValueChange [time=" + time + ", value=" + value + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,96 @@
|
||||||
|
package li.strolch.model.timedstate;
|
||||||
|
|
||||||
|
import junit.framework.Assert;
|
||||||
|
import li.strolch.model.timedstate.ITimedState;
|
||||||
|
import li.strolch.model.timedstate.TimedState;
|
||||||
|
import li.strolch.model.timevalue.ITimeValue;
|
||||||
|
import li.strolch.model.timevalue.IValueChange;
|
||||||
|
import li.strolch.model.timevalue.impl.DoubleValue;
|
||||||
|
import li.strolch.model.timevalue.impl.ValueChange;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class TimeStateTest {
|
||||||
|
|
||||||
|
private ITimedState<DoubleValue> state = new TimedState<DoubleValue>();
|
||||||
|
|
||||||
|
final DoubleValue expectedValue1 = new DoubleValue(Double.valueOf(100D));
|
||||||
|
final DoubleValue expectedValue2 = new DoubleValue(Double.valueOf(200D));
|
||||||
|
|
||||||
|
final Long t0 = Long.valueOf(0);
|
||||||
|
final Long t10 = Long.valueOf(10);
|
||||||
|
final Long t20 = Long.valueOf(20);
|
||||||
|
final Long t30 = Long.valueOf(30);
|
||||||
|
final Long t100 = Long.valueOf(100);
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void before() {
|
||||||
|
|
||||||
|
final IValueChange<DoubleValue> change1 = new ValueChange<DoubleValue>(t10, expectedValue1);
|
||||||
|
state.applyChange(change1);
|
||||||
|
|
||||||
|
final ITimeValue<DoubleValue> stateAt9 = state.getStateAt(9L);
|
||||||
|
Assert.assertNull(stateAt9);
|
||||||
|
|
||||||
|
final ITimeValue<DoubleValue> stateAt11 = state.getStateAt(11L);
|
||||||
|
Assert.assertNotNull(stateAt11);
|
||||||
|
Assert.assertEquals(true, stateAt11.getValue().matches(expectedValue1));
|
||||||
|
|
||||||
|
final IValueChange<DoubleValue> change2 = new ValueChange<DoubleValue>(t30, expectedValue1);
|
||||||
|
state.applyChange(change2);
|
||||||
|
|
||||||
|
final ITimeValue<DoubleValue> stateAt31 = state.getStateAt(31L);
|
||||||
|
Assert.assertNotNull(stateAt31);
|
||||||
|
Assert.assertEquals(true, stateAt31.getValue().matches(expectedValue2));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetNextMatch() {
|
||||||
|
|
||||||
|
ITimeValue<DoubleValue> nextMatch = state.getNextMatch(t0, expectedValue1);
|
||||||
|
Assert.assertNotNull(nextMatch);
|
||||||
|
Assert.assertEquals(t10, nextMatch.getTime());
|
||||||
|
|
||||||
|
nextMatch = state.getNextMatch(t20, expectedValue1);
|
||||||
|
Assert.assertNull(nextMatch);
|
||||||
|
|
||||||
|
nextMatch = state.getNextMatch(t20, expectedValue2);
|
||||||
|
Assert.assertNotNull(nextMatch);
|
||||||
|
Assert.assertEquals(t30, nextMatch.getTime());
|
||||||
|
|
||||||
|
nextMatch = state.getNextMatch(t30, expectedValue2);
|
||||||
|
Assert.assertNotNull(nextMatch);
|
||||||
|
Assert.assertEquals(t30, nextMatch.getTime());
|
||||||
|
|
||||||
|
nextMatch = state.getNextMatch(t100, expectedValue1);
|
||||||
|
Assert.assertNull(nextMatch);
|
||||||
|
|
||||||
|
nextMatch = state.getNextMatch(t100, expectedValue2);
|
||||||
|
Assert.assertNull(nextMatch);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetPreviousMatch() {
|
||||||
|
|
||||||
|
ITimeValue<DoubleValue> previousMatch = state.getPreviousMatch(t100, expectedValue2);
|
||||||
|
Assert.assertNotNull(previousMatch);
|
||||||
|
Assert.assertEquals(t30, previousMatch.getTime());
|
||||||
|
|
||||||
|
previousMatch = state.getPreviousMatch(t30, expectedValue2);
|
||||||
|
Assert.assertNull(previousMatch);
|
||||||
|
|
||||||
|
previousMatch = state.getPreviousMatch(t20, expectedValue2);
|
||||||
|
Assert.assertNull(previousMatch);
|
||||||
|
|
||||||
|
previousMatch = state.getPreviousMatch(t20, expectedValue1);
|
||||||
|
Assert.assertNotNull(previousMatch);
|
||||||
|
Assert.assertEquals(t10, previousMatch.getTime());
|
||||||
|
|
||||||
|
previousMatch = state.getPreviousMatch(t10, expectedValue1);
|
||||||
|
Assert.assertNull(previousMatch);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,137 @@
|
||||||
|
package li.strolch.model.timevalue;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.SortedSet;
|
||||||
|
|
||||||
|
import junit.framework.Assert;
|
||||||
|
import li.strolch.model.timevalue.ITimeValue;
|
||||||
|
import li.strolch.model.timevalue.IValue;
|
||||||
|
import li.strolch.model.timevalue.IValueChange;
|
||||||
|
import li.strolch.model.timevalue.impl.DoubleValue;
|
||||||
|
import li.strolch.model.timevalue.impl.TimeVariable;
|
||||||
|
import li.strolch.model.timevalue.impl.ValueChange;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class FloatTimeVariableTest {
|
||||||
|
|
||||||
|
private static final Long MAX = 100L;
|
||||||
|
private static final Long STEP = 10L;
|
||||||
|
private static final Long PICK = 50L;
|
||||||
|
|
||||||
|
private TimeVariable<DoubleValue> timeVariable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set the values ascending with a difference of STEP
|
||||||
|
*/
|
||||||
|
@Before
|
||||||
|
public void init() {
|
||||||
|
timeVariable = new TimeVariable<DoubleValue>();
|
||||||
|
for (long i = 0; i < MAX; i += STEP) {
|
||||||
|
timeVariable.setValueAt(Long.valueOf(i), new DoubleValue(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetValueAt() {
|
||||||
|
ITimeValue<DoubleValue> valueAt = timeVariable.getValueAt(PICK);
|
||||||
|
Assert.assertEquals(PICK.doubleValue(), valueAt.getValue().getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test, that the future values start with the PICK time and are ascending
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testGetFutureValues() {
|
||||||
|
Collection<ITimeValue<DoubleValue>> futureValues = timeVariable.getFutureValues(PICK);
|
||||||
|
Long expectedTime = PICK;
|
||||||
|
Double expectedValue = PICK.doubleValue();
|
||||||
|
for (ITimeValue<DoubleValue> value : futureValues) {
|
||||||
|
Assert.assertEquals(expectedTime, value.getTime());
|
||||||
|
Assert.assertTrue(value.getValue().matches(new DoubleValue(expectedValue)));
|
||||||
|
expectedTime += STEP;
|
||||||
|
expectedValue += STEP.doubleValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test, that the past values time fields start with 0 and are strictly
|
||||||
|
* smaller than PICK
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testGetPastValues() {
|
||||||
|
Collection<ITimeValue<DoubleValue>> pastValues = timeVariable.getPastValues(MAX);
|
||||||
|
Long expectedTime = 0L;
|
||||||
|
Double expectedValue = expectedTime.doubleValue();
|
||||||
|
for (ITimeValue<DoubleValue> value : pastValues) {
|
||||||
|
Assert.assertEquals(expectedTime, value.getTime());
|
||||||
|
Assert.assertTrue(value.getValue().matches(new DoubleValue(expectedValue)));
|
||||||
|
expectedTime += STEP;
|
||||||
|
expectedValue += STEP.doubleValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* apply a change and check that the future values are all changed
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testApplyChange() {
|
||||||
|
|
||||||
|
DoubleValue doubleValue = new DoubleValue(STEP.doubleValue());
|
||||||
|
|
||||||
|
IValueChange<DoubleValue> change = new ValueChange<DoubleValue>(PICK, doubleValue);
|
||||||
|
timeVariable.applyChange(change);
|
||||||
|
|
||||||
|
Collection<ITimeValue<DoubleValue>> futureValues = timeVariable.getFutureValues(PICK);
|
||||||
|
Long expectedTime = PICK;
|
||||||
|
|
||||||
|
IValue<Double> expectedValue = new DoubleValue(PICK.doubleValue() + change.getValue().getValue());
|
||||||
|
|
||||||
|
for (ITimeValue<DoubleValue> value : futureValues) {
|
||||||
|
Assert.assertEquals(expectedTime, value.getTime());
|
||||||
|
Assert.assertTrue(expectedValue.matches(value.getValue()));
|
||||||
|
expectedTime += STEP;
|
||||||
|
expectedValue = expectedValue.add(STEP.doubleValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* apply a change to an empty time variable
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testApply2Change() {
|
||||||
|
|
||||||
|
timeVariable = new TimeVariable<DoubleValue>();
|
||||||
|
|
||||||
|
DoubleValue doubleValue = new DoubleValue(STEP.doubleValue());
|
||||||
|
|
||||||
|
IValueChange<DoubleValue> change = new ValueChange<DoubleValue>(PICK, doubleValue);
|
||||||
|
timeVariable.applyChange(change);
|
||||||
|
|
||||||
|
ITimeValue<DoubleValue> actual = timeVariable.getValueAt(PICK);
|
||||||
|
Assert.assertNotNull(actual);
|
||||||
|
|
||||||
|
IValue<Double> expectedValue = new DoubleValue(STEP.doubleValue());
|
||||||
|
Assert.assertEquals(true, actual.getValue().matches(expectedValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test that successors matching the values of their predecessors are
|
||||||
|
* removed
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCompact() {
|
||||||
|
|
||||||
|
timeVariable = new TimeVariable<DoubleValue>();
|
||||||
|
for (Long i = 0L; i < MAX; i += STEP) {
|
||||||
|
timeVariable.setValueAt(i, new DoubleValue(STEP.doubleValue()));
|
||||||
|
}
|
||||||
|
// call
|
||||||
|
timeVariable.compact();
|
||||||
|
// check
|
||||||
|
SortedSet<ITimeValue<DoubleValue>> futureValues = timeVariable.getFutureValues(0L);
|
||||||
|
Assert.assertEquals(1, futureValues.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,131 @@
|
||||||
|
package li.strolch.model.timevalue;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.SortedSet;
|
||||||
|
|
||||||
|
import junit.framework.Assert;
|
||||||
|
import li.strolch.model.timevalue.ITimeValue;
|
||||||
|
import li.strolch.model.timevalue.IValue;
|
||||||
|
import li.strolch.model.timevalue.IValueChange;
|
||||||
|
import li.strolch.model.timevalue.impl.IntegerValue;
|
||||||
|
import li.strolch.model.timevalue.impl.TimeVariable;
|
||||||
|
import li.strolch.model.timevalue.impl.ValueChange;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Basic tests for a {@link TimeVariable} with integer values.
|
||||||
|
*
|
||||||
|
* @author martin_smock
|
||||||
|
*/
|
||||||
|
public class IntegerTimeVariableTest {
|
||||||
|
|
||||||
|
private static final Long MAX = 100L;
|
||||||
|
private static final Integer STEP = 10;
|
||||||
|
private static final Long PICK = 50L;
|
||||||
|
|
||||||
|
private TimeVariable<IntegerValue> timeVariable;
|
||||||
|
private Map<Long, IntegerValue> expectedValues = new HashMap<Long, IntegerValue>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set the values ascending with a difference of STEP
|
||||||
|
*/
|
||||||
|
@Before
|
||||||
|
public void init() {
|
||||||
|
timeVariable = new TimeVariable<IntegerValue>();
|
||||||
|
for (int i = 0; i < MAX; i += STEP) {
|
||||||
|
IntegerValue expectedValue = new IntegerValue(i);
|
||||||
|
Long time = Long.valueOf(i);
|
||||||
|
expectedValues.put(time, expectedValue);
|
||||||
|
timeVariable.setValueAt(time, expectedValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetValueAt() {
|
||||||
|
ITimeValue<IntegerValue> valueAt = timeVariable.getValueAt(PICK);
|
||||||
|
Assert.assertEquals(expectedValues.get(PICK), valueAt.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test, that the future values start with the PICK time and are ascending
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testGetFutureValues() {
|
||||||
|
Collection<ITimeValue<IntegerValue>> futureValues = timeVariable.getFutureValues(PICK);
|
||||||
|
Long expectedTime = PICK;
|
||||||
|
Integer expectedValue = PICK.intValue();
|
||||||
|
for (ITimeValue<IntegerValue> value : futureValues) {
|
||||||
|
Assert.assertEquals(expectedTime, value.getTime());
|
||||||
|
Assert.assertTrue(value.getValue().matches(new IntegerValue(expectedValue)));
|
||||||
|
expectedTime += STEP;
|
||||||
|
expectedValue += STEP.intValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test, that the past values time fields start with 0 and are strictly
|
||||||
|
* smaller than PICK
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testGetPastValues() {
|
||||||
|
Collection<ITimeValue<IntegerValue>> pastValues = timeVariable.getPastValues(MAX);
|
||||||
|
Long expectedTime = 0L;
|
||||||
|
Integer expectedValue = expectedTime.intValue();
|
||||||
|
for (ITimeValue<IntegerValue> value : pastValues) {
|
||||||
|
Assert.assertEquals(expectedTime, value.getTime());
|
||||||
|
Assert.assertTrue(value.getValue().matches(new IntegerValue(expectedValue)));
|
||||||
|
expectedTime += STEP;
|
||||||
|
expectedValue += STEP.intValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* apply a change and check that the future values are all changed
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testApplyChange() {
|
||||||
|
|
||||||
|
IntegerValue integerValue = new IntegerValue(STEP.intValue());
|
||||||
|
|
||||||
|
IValueChange<IntegerValue> change = new ValueChange<IntegerValue>(PICK, integerValue);
|
||||||
|
timeVariable.applyChange(change);
|
||||||
|
|
||||||
|
Collection<ITimeValue<IntegerValue>> futureValues = timeVariable.getFutureValues(PICK);
|
||||||
|
Long expectedTime = PICK;
|
||||||
|
|
||||||
|
IValue<Integer> expectedValue = new IntegerValue(PICK.intValue() + change.getValue().getValue());
|
||||||
|
for (ITimeValue<IntegerValue> value : futureValues) {
|
||||||
|
Assert.assertEquals(expectedTime, value.getTime());
|
||||||
|
Assert.assertTrue(expectedValue.matches(value.getValue()));
|
||||||
|
expectedTime += STEP;
|
||||||
|
expectedValue = expectedValue.add(STEP.intValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test that successors matching the values of their predecessors are
|
||||||
|
* removed
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCompact() {
|
||||||
|
timeVariable = new TimeVariable<IntegerValue>();
|
||||||
|
for (Long i = 0L; i < MAX; i += STEP) {
|
||||||
|
timeVariable.setValueAt(i, new IntegerValue(STEP.intValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// call
|
||||||
|
timeVariable.compact();
|
||||||
|
|
||||||
|
// check
|
||||||
|
SortedSet<ITimeValue<IntegerValue>> futureValues = timeVariable.getFutureValues(0L);
|
||||||
|
Assert.assertEquals(1, futureValues.size());
|
||||||
|
|
||||||
|
ITimeValue<IntegerValue> next = futureValues.iterator().next();
|
||||||
|
Assert.assertEquals(Long.valueOf(0), next.getTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,118 @@
|
||||||
|
package li.strolch.model.timevalue;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.SortedSet;
|
||||||
|
|
||||||
|
import junit.framework.Assert;
|
||||||
|
import li.strolch.model.timevalue.ITimeValue;
|
||||||
|
import li.strolch.model.timevalue.IValue;
|
||||||
|
import li.strolch.model.timevalue.IValueChange;
|
||||||
|
import li.strolch.model.timevalue.impl.AString;
|
||||||
|
import li.strolch.model.timevalue.impl.StringSetValue;
|
||||||
|
import li.strolch.model.timevalue.impl.TimeVariable;
|
||||||
|
import li.strolch.model.timevalue.impl.ValueChange;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class StringTimeVariableTest {
|
||||||
|
|
||||||
|
private static final Long MAX = 100L;
|
||||||
|
private static final Long STEP = 10L;
|
||||||
|
private static final Long PICK = 50L;
|
||||||
|
|
||||||
|
private TimeVariable<IValue<Set<AString>>> timeVariable;
|
||||||
|
|
||||||
|
private Map<Long, StringSetValue> testSets = new HashMap<Long, StringSetValue>();
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void init() {
|
||||||
|
timeVariable = new TimeVariable<IValue<Set<AString>>>();
|
||||||
|
for (Long i = 0L; i < MAX; i += STEP) {
|
||||||
|
Set<AString> testSet = new HashSet<AString>();
|
||||||
|
StringSetValue testValue = new StringSetValue(testSet);
|
||||||
|
testSets.put(i, testValue);
|
||||||
|
testSet.add(new AString("string " + i));
|
||||||
|
timeVariable.setValueAt(i, new StringSetValue(testSet));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetValueAt() {
|
||||||
|
ITimeValue<IValue<Set<AString>>> valueAt = timeVariable.getValueAt(PICK);
|
||||||
|
Assert.assertEquals(true, valueAt.getValue().matches(testSets.get(PICK)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetFutureValues() {
|
||||||
|
Collection<ITimeValue<IValue<Set<AString>>>> futureValues = timeVariable.getFutureValues(PICK);
|
||||||
|
for (ITimeValue<IValue<Set<AString>>> iTimeValue : futureValues) {
|
||||||
|
Long time = iTimeValue.getTime();
|
||||||
|
Assert.assertEquals(true, time >= PICK);
|
||||||
|
Assert.assertNotNull(iTimeValue.getValue());
|
||||||
|
Assert.assertEquals(true, iTimeValue.getValue().matches(testSets.get(time)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetPastValues() {
|
||||||
|
Collection<ITimeValue<IValue<Set<AString>>>> pastValues = timeVariable.getPastValues(PICK);
|
||||||
|
for (ITimeValue<IValue<Set<AString>>> iTimeValue : pastValues) {
|
||||||
|
Long time = iTimeValue.getTime();
|
||||||
|
Assert.assertEquals(true, time < PICK);
|
||||||
|
Assert.assertNotNull(iTimeValue.getValue());
|
||||||
|
Assert.assertEquals(true, iTimeValue.getValue().matches(testSets.get(time)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testApplyChange() {
|
||||||
|
|
||||||
|
Set<AString> testSet = new HashSet<AString>();
|
||||||
|
testSet.add(new AString("Martin"));
|
||||||
|
StringSetValue testValue = new StringSetValue(testSet);
|
||||||
|
|
||||||
|
timeVariable = new TimeVariable<IValue<Set<AString>>>();
|
||||||
|
timeVariable.setValueAt(PICK, testValue);
|
||||||
|
|
||||||
|
IValue<Set<AString>> inverseTestValue = testValue.getInverse();
|
||||||
|
IValueChange<IValue<Set<AString>>> change = new ValueChange<IValue<Set<AString>>>(PICK, inverseTestValue);
|
||||||
|
timeVariable.applyChange(change);
|
||||||
|
|
||||||
|
// check the future values
|
||||||
|
Collection<ITimeValue<IValue<Set<AString>>>> futureValues = timeVariable.getFutureValues(0L);
|
||||||
|
for (ITimeValue<IValue<Set<AString>>> iTimeValue : futureValues) {
|
||||||
|
System.out.println("++ " + iTimeValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.assertEquals(1, futureValues.size()); // a empty one is left
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCompact() {
|
||||||
|
|
||||||
|
timeVariable = new TimeVariable<IValue<Set<AString>>>();
|
||||||
|
for (Long i = 0L; i < MAX; i += STEP) {
|
||||||
|
Set<AString> testSet = new HashSet<AString>();
|
||||||
|
StringSetValue testValue = new StringSetValue(testSet);
|
||||||
|
testSets.put(i, testValue);
|
||||||
|
testSet.add(new AString("same string"));
|
||||||
|
timeVariable.setValueAt(i, new StringSetValue(testSet));
|
||||||
|
}
|
||||||
|
|
||||||
|
SortedSet<ITimeValue<IValue<Set<AString>>>> valuesInitial = timeVariable.getFutureValues(0L);
|
||||||
|
Assert.assertEquals(true, valuesInitial.size() > 1);
|
||||||
|
|
||||||
|
timeVariable.compact();
|
||||||
|
|
||||||
|
SortedSet<ITimeValue<IValue<Set<AString>>>> valuesCompacted = timeVariable.getFutureValues(0L);
|
||||||
|
Assert.assertEquals(1, valuesCompacted.size());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
package li.strolch.model.timevalue;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import li.strolch.model.timevalue.IValue;
|
||||||
|
import li.strolch.model.timevalue.impl.AString;
|
||||||
|
import li.strolch.model.timevalue.impl.DoubleValue;
|
||||||
|
import li.strolch.model.timevalue.impl.IntegerValue;
|
||||||
|
import li.strolch.model.timevalue.impl.StringSetValue;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class ValueTests {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check, that adding the inverse results in the neutral element (=0)
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testDoubleInverse() {
|
||||||
|
DoubleValue value = new DoubleValue(10.0d);
|
||||||
|
DoubleValue inverse = value.getInverse();
|
||||||
|
assertEquals(Double.valueOf(-10.0d), inverse.getValue());
|
||||||
|
assertEquals(Double.valueOf(0), value.add(inverse.getValue())
|
||||||
|
.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check, that adding the inverse results in the neutral element (=0)
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testIntegerInverse() {
|
||||||
|
IntegerValue value = new IntegerValue(10);
|
||||||
|
IntegerValue inverse = value.getInverse();
|
||||||
|
assertEquals(Integer.valueOf(-10), inverse.getValue());
|
||||||
|
assertEquals(Integer.valueOf(0), value.add(inverse.getValue())
|
||||||
|
.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check, that adding the inverse results in the neutral element (empty Set)
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testStringSetInverse() {
|
||||||
|
Set<AString> aStrings = new HashSet<AString>();
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
aStrings.add(new AString("string " + i));
|
||||||
|
}
|
||||||
|
IValue<Set<AString>> value = new StringSetValue(aStrings);
|
||||||
|
IValue<Set<AString>> inverse = value.getInverse();
|
||||||
|
assertEquals(true, value.matches(inverse.getInverse()));
|
||||||
|
assertEquals(0, value.add(inverse.getValue()).getValue().size());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check, that the difference left is as expected
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testStringSetNearInverse() {
|
||||||
|
|
||||||
|
Set<AString> aStrings1 = new HashSet<AString>();
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
aStrings1.add(new AString("string " + i));
|
||||||
|
}
|
||||||
|
IValue<Set<AString>> value1 = new StringSetValue(aStrings1);
|
||||||
|
|
||||||
|
Set<AString> aStrings2 = new HashSet<AString>();
|
||||||
|
for (int i = 0; i < 9; i++) {
|
||||||
|
aStrings2.add(new AString("string " + i, true));
|
||||||
|
}
|
||||||
|
IValue<Set<AString>> value2 = new StringSetValue(aStrings2);
|
||||||
|
|
||||||
|
assertEquals(false, value1.matches(value2));
|
||||||
|
assertEquals(1, value1.add(value2.getValue()).getValue().size());
|
||||||
|
assertEquals(10, value1.add(value2.getInverse().getValue()).getValue()
|
||||||
|
.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue