Commit 3dc5a63c authored by Nico Mack's avatar Nico Mack

Major overhaul of parameter setting and result retrieval. Variables are

no longer passed directly but are wrapped in a Declaration object,
allowing to specifiy EQUATE, INDEX and FIELD attributes.
parent c2ab505d
......@@ -14,6 +14,9 @@ EQUATIONS_ELEMENT=equations
EQUATION_ELEMENT=equation
MODE_ATTRIBUTE=mode
INVOKE_ELEMENT=invoke
INDEX_ATTRIBUTE=index
FIELD_ATTRIBUTE=field
INVOKE_ELEMENT=invoke
EPSILON_ATTRIBUTE=epsilon
EXECUTOR_ATTRIBUTE=executor
NAME_ATTRIBUTE=name
......
/Spatial$py.class
/Text$py.class
/Map$py.class
/Vector$py.class
'''
Created on Jan 8, 2018
@author: mack
'''
def ManipulateVector (V):
R = V
R[3] = 2
return R
\ No newline at end of file
......@@ -22,10 +22,13 @@ package lu.list.itis.dkd.tui.cps;
import lu.list.itis.dkd.dbc.annotation.NonNullByDefault;
import lu.list.itis.dkd.dbc.annotation.Nullable;
import lu.list.itis.dkd.tui.cps.system.Declaration;
import lu.list.itis.dkd.tui.cps.system.System;
import lu.list.itis.dkd.tui.cps.variable.Variable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
/**
......@@ -41,9 +44,9 @@ public class Phenomenon {
/** The clock which may dictate the sampling rate and advancement of the phenomenon. */
private Clock clock;
/** The independent variables characterising the system. */
private ConcurrentHashMap<String, Variable<?>> independentVariables;
private ConcurrentHashMap<String, Declaration> independentVariables;
/** The variables depending on the system and its inputs. */
private ConcurrentHashMap<String, Variable<?>> dependentVariables;
private ConcurrentHashMap<String, Declaration> dependentVariables;
/** The system computing dependent variables from input independent variables. */
private lu.list.itis.dkd.tui.cps.system.System system;
/** Field indicating whether the observation is to be driven by a clock. */
......@@ -59,11 +62,11 @@ public class Phenomenon {
* @param system
* The system computing dependent variables from input independent variables.
* @param clockDriven
* Indication whether the observation of the phenomenon is to be driven by the ticking of
* a clock or is synchronous.
* Indication whether the observation of the phenomenon is to be driven by the ticking of a
* clock or is synchronous.
*/
public Phenomenon(ConcurrentHashMap<String, Variable<?>> independentVariables,
ConcurrentHashMap<String, Variable<?>> dependentVariables,
public Phenomenon(ConcurrentHashMap<String, Declaration> independentVariables,
ConcurrentHashMap<String, Declaration> dependentVariables,
lu.list.itis.dkd.tui.cps.system.System system, boolean clockDriven) {
clock = new Clock();
this.independentVariables = independentVariables;
......@@ -74,12 +77,12 @@ public class Phenomenon {
if (clockDriven) {
clock.addListener(system);
} else {
for (Variable variable : independentVariables.values()) {
variable.addListener(system);
for (Declaration declaration : independentVariables.values()) {
declaration.getVariable().addListener(system);
}
for (Variable variable : dependentVariables.values()) {
variable.addListener(system);
for (Declaration declaration : dependentVariables.values()) {
declaration.getVariable().addListener(system);
}
}
}
......@@ -104,7 +107,12 @@ public class Phenomenon {
* @return The {@link Collection} of dependent variables.
*/
public Collection<Variable<?>> getOutputs() {
return dependentVariables.values();
List<Variable<?>> outputs = new ArrayList<>();
for (Declaration declaration : dependentVariables.values()) {
outputs.add(declaration.getVariable());
}
return outputs;
}
/**
......@@ -112,11 +120,12 @@ public class Phenomenon {
*
* @param variableName
* The name of the {@link Variable} to retrieve.
* @return The instance of the {@link Variable} or <code>null</code> if no such {@link Variable}
* was defined.
* @return The instance of the {@link Variable} or <code>null</code> if no such {@link Variable} was
* defined.
*/
public @Nullable Variable<?> getOutput(String variableName) {
return dependentVariables.get(variableName);
Declaration declaration = dependentVariables.get(variableName);
return (declaration != null) ? declaration.getVariable() : null;
}
/**
......@@ -125,7 +134,12 @@ public class Phenomenon {
* @return The value of independentVariables.
*/
public Collection<Variable<?>> getInputs() {
return independentVariables.values();
List<Variable<?>> inputs = new ArrayList<>();
for (Declaration declaration : independentVariables.values()) {
inputs.add(declaration.getVariable());
}
return inputs;
}
/**
......
/**
* Copyright Luxembourg Institute of Science and Technology, 2018. All rights reserved. If you wish
* to use this code for any purpose, please contact the author(s).
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package lu.list.itis.dkd.tui.cps.system;
import lu.list.itis.dkd.tui.cps.variable.MapVariable;
import lu.list.itis.dkd.tui.cps.variable.Variable;
import lu.list.itis.dkd.tui.cps.variable.VectorVariable;
import lu.list.itis.dkd.tui.utility.StringUtils;
import com.jgoodies.common.base.Preconditions;
/**
* Class modeling the fundamental properties for declaring variables in the context of equations.
*
* @author Nico Mack [nico.mack@list.lu]
* @since 1.5
* @version 1.0.0
*/
// ***************************************************************************
// * Class Definition *
// ***************************************************************************
public class Declaration implements Cloneable {
protected String field;
protected String equate;
protected int index;
protected Variable<?> variable;
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Constructor(s) *
// ***************************************************************************
// ---------------------------------------------------------------------------
public Declaration(Variable<?> variable) {
this.variable = variable;
this.index = -1;
}
// ---------------------------------------------------------------------------
public Declaration(Variable<?> variable, String field) {
Preconditions.checkArgument((variable instanceof MapVariable), StringUtils.build("Variable {} is not a MapVariable!", variable.getName())); //$NON-NLS-1$
this.variable = variable;
this.field = field;
this.index = -1;
}
// ---------------------------------------------------------------------------
public Declaration(Variable<?> variable, int index) {
Preconditions.checkArgument((variable instanceof VectorVariable), StringUtils.build("Variable {} is not a VectorVariable!", variable.getName())); //$NON-NLS-1$
this.variable = variable;
this.index = index;
}
// ---------------------------------------------------------------------------
public Declaration(Declaration other) {
this.variable = other.variable.clone();
this.field = other.field;
this.equate = other.equate;
this.index = other.index;
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Class Body *
// ***************************************************************************
// ---------------------------------------------------------------------------
public void setEquate(String equate) {
this.equate = equate;
}
// ---------------------------------------------------------------------------
public String getIdentifier() {
return (this.variable != null) ? this.variable.getName() : null;
}
// ---------------------------------------------------------------------------
/**
* Simple getter method for equate.
*
* @return The value of equate.
*/
// ---------------------------------------------------------------------------
public String getEquate() {
return equate;
}
// ---------------------------------------------------------------------------
/**
* Simple getter method for field.
*
* @return The value of field.
*/
// ---------------------------------------------------------------------------
public String getField() {
return field;
}
// ---------------------------------------------------------------------------
/**
* Simple getter method for index.
*
* @return The value of index.
*/
// ---------------------------------------------------------------------------
public int getIndex() {
return index;
}
// ---------------------------------------------------------------------------
/**
* Simple getter method for variable.
*
* @return The value of variable.
*/
// ---------------------------------------------------------------------------
public Variable<?> getVariable() {
return variable;
}
// ---------------------------------------------------------------------------
@Override
public Declaration clone() {
return new Declaration(this);
}
// ---------------------------------------------------------------------------
@SuppressWarnings("nls")
@Override
public String toString() {
StringBuilder renderer = new StringBuilder();
renderer.append(variable.getName());
if ((field != null) && (!field.isEmpty())) {
renderer.append("{").append(field).append("}");
} else if (index >= 0) {
renderer.append("[").append(index).append("]");
}
return renderer.toString();
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * End of Class
// ***************************************************************************
// ---------------------------------------------------------------------------
}
......@@ -62,9 +62,8 @@ public class Equation {
* @param mapping
* The mapping of variables to take into account for the equation.
* @param script
* The mathematical representation of the equation in string form. Note that the names of
* the variables in the script must coincide with the names of the variables in the
* mapping.
* The mathematical representation of the equation in string form. Note that the names of the
* variables in the script must coincide with the names of the variables in the mapping.
*/
public Equation(String name, Mapping mapping, String script) {
this.name = name;
......@@ -84,8 +83,8 @@ public class Equation {
}
/**
* Allows to isolate this equation. An isolated equation will not notify dependent equations
* when evaluation entailed changes in results.
* Allows to isolate this equation. An isolated equation will not notify dependent equations when
* evaluation entailed changes in results.
*
* @param isolateIt
*/
......@@ -98,11 +97,10 @@ public class Equation {
}
/**
* Method called to evaluate the script of the equation with the variables provided by the
* mapping.
* Method called to evaluate the script of the equation with the variables provided by the mapping.
*/
public synchronized void evaluate() {
LinkedHashSet<Variable<?>> dependentVariables;
LinkedHashSet<Declaration> dependentVariables;
String evaluationErrors;
Preconditions.checkState(scriptExecutor != null);
......@@ -110,8 +108,8 @@ public class Equation {
try {
scriptExecutor.resetExecutionErrors();
for (Variable<?> variable : lockedMapping.getIndependentVariables()) {
scriptExecutor.set(variable);
for (Declaration declaration : lockedMapping.getIndependentVariables()) {
scriptExecutor.set(declaration);
}
scriptExecutor.eval(this.script);
......@@ -126,12 +124,13 @@ public class Equation {
if (consolidated)
consolidatedListeners = new HashMap<>();
for (Variable<?> variable : dependentVariables) {
for (Declaration declaration : dependentVariables) {
Variable<?> variable = declaration.getVariable();
variable.suspendListenerNotification(consolidated);
if (consolidated)
consolidatedListeners = variable.consolidateListeners(consolidatedListeners);
try {
variable = scriptExecutor.get(variable);
variable = scriptExecutor.get(declaration);
} catch (Exception exception) {
LOGGER.error("Error while retrieving variable {}", variable.getName(), exception); //$NON-NLS-1$
}
......@@ -154,9 +153,9 @@ public class Equation {
if (evaluationErrors.length() > 0) {
LOGGER.warn("Error while evaluating equation : {}", evaluationErrors); //$NON-NLS-1$
LOGGER.warn("Script = {}", this.script); //$NON-NLS-1$
LinkedHashSet<Variable<?>> independentVariables = mapping.getIndependentVariables();
for (Variable<?> variable : independentVariables) {
LOGGER.trace("{} = {}", variable.getName(), variable.getValue()); //$NON-NLS-1$
LinkedHashSet<Declaration> independentVariables = mapping.getIndependentVariables();
for (Declaration declaration : independentVariables) {
LOGGER.trace("{} = {}", declaration, declaration.getVariable().getValue()); //$NON-NLS-1$
}
}
}
......
......@@ -30,14 +30,15 @@ import java.util.LinkedHashSet;
* Class describing the mapping between a set of input variables and an output variable. The order
* of input variables is preserved and essential when defining the equation.
*
* @author Nico Mack [nico.mack@list.lu]
* @author Eric Tobias [eric.tobias@list.lu]
* @since 1.0
* @version 1.3.1
* @version 1.5.0
*/
@NonNullByDefault
public class Mapping {
private LinkedHashSet<Variable<?>> independentVariables;
private LinkedHashSet<Variable<?>> dependentVariables;
private LinkedHashSet<Declaration> independentVariables;
private LinkedHashSet<Declaration> dependentVariables;
/**
* Constructor initialising the mapping.
......@@ -47,7 +48,7 @@ public class Mapping {
* @param dependentVariable
* The dependent variable of the mapping.
*/
public Mapping(LinkedHashSet<Variable<?>> independentVariables, LinkedHashSet<Variable<?>> dependentVariables) {
public Mapping(LinkedHashSet<Declaration> independentVariables, LinkedHashSet<Declaration> dependentVariables) {
// Preconditions.checkArgument(!independentVariables.isEmpty(), "The set of input variables
// cannot be empty."); //$NON-NLS-1$
this.independentVariables = independentVariables;
......@@ -59,7 +60,7 @@ public class Mapping {
*
* @return The value of independentVariables.
*/
public LinkedHashSet<Variable<?>> getIndependentVariables() {
public LinkedHashSet<Declaration> getIndependentVariables() {
return independentVariables;
}
......@@ -68,7 +69,7 @@ public class Mapping {
*
* @return The value of dependentVariables.
*/
public LinkedHashSet<Variable<?>> getDependentVariables() {
public LinkedHashSet<Declaration> getDependentVariables() {
return dependentVariables;
}
......@@ -79,8 +80,8 @@ public class Mapping {
StringBuilder renderer = new StringBuilder();
if (independentVariables != null) {
for (Variable<?> variable : independentVariables) {
renderer.append(separator).append(variable.getName());
for (Declaration declaration : independentVariables) {
renderer.append(separator).append(declaration);
separator = ", "; //$NON-NLS-1$
}
} else {
......@@ -91,8 +92,8 @@ public class Mapping {
separator = ""; //$NON-NLS-1$
if (dependentVariables != null) {
for (Variable<?> variable : dependentVariables) {
renderer.append(separator).append(variable.getName());
for (Declaration declaration : dependentVariables) {
renderer.append(separator).append(declaration);
separator = ", "; //$NON-NLS-1$
}
} else {
......@@ -133,61 +134,41 @@ public class Mapping {
}
/**
* Method querying whether the {@link Mapping} instance holds the {@link Variable} instance
* given as a parameter as an independent {@link Variable} instance.
* Method querying whether the {@link Mapping} instance holds the {@link Variable} instance given as
* a parameter as an independent {@link Variable} instance.
*
* @param variable
* The variable to look up.
* @return <code>True</code> if the {@link Variable} instance is an independent variable managed
* by this {@link Mapping} instance.
* @return <code>True</code> if the {@link Variable} instance is an independent variable managed by
* this {@link Mapping} instance.
*/
public boolean catersTo(Variable<?> variable) {
for (Variable<?> _variable : independentVariables) {
if (_variable.equals(variable)) {
for (Declaration declaration : independentVariables) {
if (variable.equals(declaration.getVariable())) {
return true;
}
}
return (independentVariables.contains(variable));
return false;
}
/**
* Method for locking the mapping; cloning all variables such that they may not be influenced by
* the evaluation of the equation.
* Method for locking the mapping; cloning all variables such that they may not be influenced by the
* evaluation of the equation.
*
* @return A deep copy of the {@link Mapping}.
*/
public Mapping lock() {
LinkedHashSet<Variable<?>> clonedIndependentVariables = new LinkedHashSet<>();
for (Variable<?> variable : independentVariables) {
clonedIndependentVariables.add(variable.clone());
LinkedHashSet<Declaration> clonedIndependentVariables = new LinkedHashSet<>();
for (Declaration declaration : independentVariables) {
clonedIndependentVariables.add(declaration.clone());
}
LinkedHashSet<Variable<?>> clonedDependentVariables = new LinkedHashSet<>();
LinkedHashSet<Declaration> clonedDependentVariables = new LinkedHashSet<>();
if (dependentVariables != null) {
for (Variable<?> variable : dependentVariables) {
clonedDependentVariables.add(variable.clone());
for (Declaration declaration : dependentVariables) {
clonedDependentVariables.add(declaration.clone());
}
}
return new Mapping(clonedIndependentVariables, clonedDependentVariables);
}
// /**
// * Method for updating a reference to an independent variable. The method will add the
// variable
// * to the collection of independent variables this mapping instance will contain <b>iff</b>
// the
// * mapping already mapped the variable prior to this call. <br>
// * <br>
// * <u>Note:</u> This method depends on the equality of variables being by name and unit.
// *
// * @param variable
// * The variable to update the reference for.
// * @see Variable#equals(Object)
// */
// public void updateVariableReference(Variable variable) {
// if (independentVariables.contains(variable)) {
// independentVariables.remove(variable);
// independentVariables.add(variable);
// }
// }
}
\ No newline at end of file
package lu.list.itis.dkd.tui.cps.system.executor;
import lu.list.itis.dkd.tui.cps.system.Declaration;
import lu.list.itis.dkd.tui.cps.system.Import;
import lu.list.itis.dkd.tui.cps.variable.Variable;
......@@ -39,9 +40,9 @@ abstract public class Executor {
LOGGER.warn("Imports not supported by Executor!"); //$NON-NLS-1$
}
abstract public void set(Variable<?> variable);
abstract public void set(Declaration declaration);
abstract public boolean eval(String script);
abstract public Variable<?> get(Variable<?> variable);
abstract public Variable<?> get(Declaration declaration);
}
package lu.list.itis.dkd.tui.cps.system.executor;
import lu.list.itis.dkd.tui.cps.system.Declaration;
import lu.list.itis.dkd.tui.cps.variable.Variable;
import org.slf4j.Logger;
......@@ -30,9 +31,9 @@ public class JavascriptExecutor extends Executor {
}
@Override
public void set(Variable<?> variable) {
public void set(Declaration declaration) {
// TODO Rely on ExecutorScope annotations to generalize setting of multi-value variables
Variable<?> variable = declaration.getVariable();
engine.put(variable.getName(), variable.getValue());
if (LOGGER.isInfoEnabled()) {
......@@ -59,7 +60,8 @@ public class JavascriptExecutor extends Executor {
}
@Override
public Variable<?> get(Variable<?> variable) {
public Variable<?> get(Declaration declaration) {
Variable<?> variable = declaration.getVariable();
variable.setValueFromObject(result);
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Result {} = {}", variable.getName(), result); //$NON-NLS-1$
......
package lu.list.itis.dkd.tui.cps.system.executor;
import lu.list.itis.dkd.tui.cps.system.Declaration;
import lu.list.itis.dkd.tui.cps.variable.Variable;
import org.slf4j.Logger;
......@@ -44,7 +45,8 @@ public class OctaveExecutor extends Executor {
}
@Override
public void set(Variable<?> variable) {
public void set(Declaration declaration) {
Variable<?> variable = declaration.getVariable();
Double numericValue = Double.valueOf(variable.getValue().toString());
engine.put(variable.getName(), Octave.scalar(numericValue));
if (LOGGER.isInfoEnabled()) {
......@@ -64,7 +66,8 @@ public class OctaveExecutor extends Executor {
}
@Override
public Variable<?> get(Variable<?> variable) {
public Variable<?> get(Declaration declaration) {
Variable<?> variable = declaration.getVariable();
OctaveDouble result = engine.get(OctaveDouble.class, variable.getName());
variable.setValueFromObject(result.get(1));
if (LOGGER.isInfoEnabled()) {
......
......@@ -13,9 +13,11 @@
*/
package lu.list.itis.dkd.tui.cps.system.executor;
import lu.list.itis.dkd.tui.cps.system.Declaration;
import lu.list.itis.dkd.tui.cps.variable.Variable;
import lu.list.itis.dkd.tui.cps.variable.VectorVariable;
import com.google.common.base.Strings;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.slf4j.Logger;
......@@ -158,9 +160,9 @@ public class SqlExecutor extends Executor {
// ---------------------------------------------------------------------------
/**
* replaces every occurrence of the previously specified interpolation pattern with the
* previously specified substitute. Group 1 of matching interpolation pattern will be added to
* the specified interpolation vector.
* replaces every occurrence of the previously specified interpolation pattern with the previously
* specified substitute. Group 1 of matching interpolation pattern will be added to the specified
* interpolation vector.
*
* @param query
* specifies the original string to substitute interpolation patterns in.
......@@ -170,9 +172,9 @@ public class SqlExecutor extends Executor {
* specifies whether or not to use regular (?) JDBC placeholders or positional JPA (?x)
* placeholders. Specify <code>
* true</code> for positional placeholders, <code>false</code> for regular placeholders
* @return the specified string having every occurrence of the interpolation pattern replaced by
* the substitute, and specified interpolation vector will be populated with all group
* 1's of matching interpolation patterns.
* @return the specified string having every occurrence of the interpolation pattern replaced by the
* substitute, and specified interpolation vector will be populated with all group 1's of
* matching interpolation patterns.
*/
// ---------------------------------------------------------------------------
......@@ -266,9 +268,9 @@ public class SqlExecutor extends Executor {
// ---------------------------------------------------------------------------
/**
* Converts the data in the specified SQL Result set into a collection of object arrays as they
* are normally returned by hibernate queries. Each object array represents a row of the result
* set, with columns appearing in the order they were fetched.
* Converts the data in the specified SQL Result set into a collection of object arrays as they are
* normally returned by hibernate queries. Each object array represents a row of the result set,
* with columns appearing in the order they were fetched.
*
* @param p_ResultSet
* specifies the SQL result set returned by a JDBC query.
......@@ -344,8 +346,11 @@ public class SqlExecutor extends Executor {
/** {@inheritDoc} */
@Override
public void set(Variable<?> variable) {
parameters.put(variable.getName(), variable.getValue());
public void set(Declaration declaration) {
Variable<?> variable = declaration.getVariable();
String identifier = (Strings.isNullOrEmpty(declaration.getEquate())) ? variable.getName() : declaration.getEquate();
parameters.put(identifier, variable.getValue());
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Parameter -> {} = {}", variable.getName(), variable.getValue()); //$NON-NLS-1$
}
......@@ -416,9 +421,10 @@ public class SqlExecutor extends Executor {
* @param <B>
*/
@Override
public Variable<?> get(Variable<?> variable) {
String equate = variable.getEquate();
String column = ((equate != null) && (equate.length() > 0)) ? equate : variable.getName();
public Variable<?> get(Declaration declaration) {
Variable<?> variable = declaration.getVariable();
String column = (Strings.isNullOrEmpty(declaration.getEquate())) ? variable.getName() : declaration.getEquate();
int index = columnNames.indexOf(column);
if (index >= 0) {
if (columnValues.size() > 1) {
......
......@@ -29,7 +29,7 @@ import org.eclipse.osgi.util.NLS;
*/
@SuppressWarnings({"javadoc", "nls"})
public class EquationSystemBundle extends NLS {
private static final String BUNDLE_NAME = "lu.list.itis.dkd.tui.cps.utility.equationsystem";
private static final String BUNDLE_NAME = "equationsystem";
public static String EXECUTOR_NAMESPACE;
public static String NAMESPACE_SEPARATOR;
......@@ -45,6 +45,8 @@ public class EquationSystemBundle extends NLS {
public static String EQUATION_ELEMENT;
public static String MODE_ATTRIBUTE;
public static String EQUATIONS_ELEMENT;
public static String INDEX_ATTRIBUTE;
public static String FIELD_ATTRIBUTE;
public static String INVOKE_ELEMENT;
public static String EXECUTOR_ATTRIBUTE;
public static String NAME_ATTRIBUTE;
......
......@@ -59,7 +59,7 @@ public abstract class Variable<V> implements Cloneable {
/** The unit the variable is given in. */
protected String unit;
/** An alternative source to get value of variable from */
protected String equate;
// protected String equate;
/** The listeners to notify when the variable changes value. */
protected Vector<InputChangeListener> listeners;
......@@ -198,18 +198,18 @@ public abstract class Variable<V> implements Cloneable {