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$
}
}
}
......
......@@ -46,6 +46,7 @@ import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
......@@ -79,8 +80,8 @@ public class EquationSystemBuilder {
private ConcurrentHashMap<String, List<String>> parameterDependencies;
private ConcurrentHashMap<String, List<String>> resultDependencies;
private ConcurrentHashMap<String, List<Import>> equationImports;
private ConcurrentHashMap<String, List<String>> equationParameters;
private ConcurrentHashMap<String, List<String>> equationResults;
private ConcurrentHashMap<String, List<Declaration>> equationParameters;
private ConcurrentHashMap<String, List<Declaration>> equationResults;
private ConcurrentHashMap<String, LinearEquationSystem> equations;
private ConcurrentHashMap<String, Phenomenon> phenomena;
......@@ -280,6 +281,12 @@ public class EquationSystemBuilder {
attribute = this.getAttribute(element, EquationSystemBundle.EQUATE_ATTRIBUTE);
attributes.put(EquationSystemBundle.EQUATE_ATTRIBUTE, attribute);
attribute = this.getAttribute(element, EquationSystemBundle.INDEX_ATTRIBUTE);
attributes.put(EquationSystemBundle.INDEX_ATTRIBUTE, attribute);
attribute = this.getAttribute(element, EquationSystemBundle.FIELD_ATTRIBUTE);
attributes.put(EquationSystemBundle.FIELD_ATTRIBUTE, attribute);
attribute = this.getAttribute(element, EquationSystemBundle.DECIMALS_ATTRIBUTE);
attributes.put(EquationSystemBundle.DECIMALS_ATTRIBUTE, attribute);
......@@ -320,9 +327,9 @@ public class EquationSystemBuilder {
if (!Strings.isNullOrEmpty(attributes.get(EquationSystemBundle.EPSILON_ATTRIBUTE)))
numericVariable.setEpsilon(StringUtils.getDoubleValue(attributes.get(EquationSystemBundle.EPSILON_ATTRIBUTE)));
if (!Strings.isNullOrEmpty(attributes.get(EquationSystemBundle.EQUATE_ATTRIBUTE)))
numericVariable.setEquate(attributes.get(EquationSystemBundle.EQUATE_ATTRIBUTE));
//
// if (!Strings.isNullOrEmpty(attributes.get(EquationSystemBundle.EQUATE_ATTRIBUTE)))
// numericVariable.setEquate(attributes.get(EquationSystemBundle.EQUATE_ATTRIBUTE));
if (!Strings.isNullOrEmpty(attributes.get(EquationSystemBundle.DECIMALS_ATTRIBUTE)))
numericVariable.setNumberOfDecimals(StringUtils.getIntegerValue(attributes.get(EquationSystemBundle.DECIMALS_ATTRIBUTE)));
......@@ -336,6 +343,65 @@ public class EquationSystemBuilder {
return variable;
}
// ---------------------------------------------------------------------------
private Variable<?> getIndependentVariable(HashMap<String, String> attributes) {
String identifier = attributes.get(EquationSystemBundle.NAME_ATTRIBUTE);
if (independentVariables.containsKey(identifier)) {
return independentVariables.get(identifier);
}
if (dependentVariables.containsKey(identifier)) {
return dependentVariables.get(identifier);
}
Variable<?> independent = this.createVariable(attributes);
independentVariables.put(identifier, independent);
return independent;
}
// ---------------------------------------------------------------------------
private Variable<?> getDependentVariable(HashMap<String, String> attributes) {
String identifier = attributes.get(EquationSystemBundle.NAME_ATTRIBUTE);
Variable<?> dependent = null;
if (dependentVariables.containsKey(identifier)) {
dependent = dependentVariables.get(identifier);
} else {
dependent = (outputVariables.containsKey(identifier)) ? outputVariables.get(identifier) : this.createVariable(attributes);
dependentVariables.put(identifier, dependent);
}
return dependent;
}
// ---------------------------------------------------------------------------
private Declaration buildDeclaration(Variable<?> variable, Map<String, String> attributes) throws EquationSystemException {
Declaration declaration;
String field = attributes.get(EquationSystemBundle.FIELD_ATTRIBUTE);
String index = attributes.get(EquationSystemBundle.INDEX_ATTRIBUTE);
if ((field != null) && !field.isEmpty()) {
declaration = new Declaration(variable, field);
} else if ((index != null) && !index.isEmpty()) {
Integer numericIndex = StringUtils.getIntegerValue(index);
if (numericIndex == null) {
String message = StringUtils.build("Index {} specified for variable {} is not an integer!", index, variable.getName()); //$NON-NLS-1$
LOGGER.error(message);
throw new EquationSystemException(message);
}
declaration = new Declaration(variable, numericIndex);
} else {
declaration = new Declaration(variable);
}
String equate = attributes.get(EquationSystemBundle.EQUATE_ATTRIBUTE);
declaration.setEquate(equate);
return declaration;
}
// ---------------------------------------------------------------------------
/**
* Checks whether the specified equation creates a dependency cycle. Dependency cycles occur when
......@@ -353,14 +419,15 @@ public class EquationSystemBuilder {
String equationName = this.getAttribute(equation, EquationSystemBundle.NAME_ATTRIBUTE);
boolean dependencyCycle = false;
for (String parameter : equationParameters.get(equationName)) {
if (resultDependencies.containsKey(parameter)) {
List<String> dependencies = resultDependencies.get(parameter);
for (Declaration parameter : equationParameters.get(equationName)) {
String identifier = parameter.getIdentifier();
if (resultDependencies.containsKey(identifier)) {
List<String> dependencies = resultDependencies.get(identifier);
for (String dependency : dependencies) {
for (String dependencyParameter : equationParameters.get(dependency)) {
List<String> parameterDependencies = resultDependencies.get(dependencyParameter);
if (parameterDependencies != null) {
dependencyCycle |= parameterDependencies.contains(equationName);
for (Declaration result : equationParameters.get(dependency)) {
List<String> dependentEquations = resultDependencies.get(result.getIdentifier());
if (dependentEquations != null) {
dependencyCycle |= dependentEquations.contains(equationName);
}
}
}
......@@ -453,18 +520,24 @@ public class EquationSystemBuilder {
// ---------------------------------------------------------------------------
private void addParameterDependencies(Element equation) {
private void addParameterDependencies(Element equation) throws EquationSystemException {
String equationName = this.getAttribute(equation, EquationSystemBundle.NAME_ATTRIBUTE);
List<Element> parameters = equation.getChild(EquationSystemBundle.PARAMETERS_ELEMENT).getChildren(EquationSystemBundle.PARAMETER_ELEMENT);
List<String> _equationParameters = new ArrayList<>();
List<Declaration> declarations = new ArrayList<>();
HashMap<String, String> parameterAttributes;
for (Element parameter : parameters) {
parameterAttributes = this.extractAttributesForVariables(parameter);
String identifier = parameterAttributes.get(EquationSystemBundle.NAME_ATTRIBUTE);
_equationParameters.add(identifier);
Variable<?> variable = this.getIndependentVariable(parameterAttributes);
if (variable != null) {
Declaration declaration = this.buildDeclaration(variable, parameterAttributes);
declarations.add(declaration);
} else {
String message = StringUtils.build("Undefined parameter {} encountered! Check equation file!", identifier); //$NON-NLS-1$
LOGGER.error(message);
throw new EquationSystemException(message);
}
if (parameterDependencies.containsKey(identifier)) {
parameterDependencies.get(identifier).add(equationName);
......@@ -473,29 +546,32 @@ public class EquationSystemBuilder {
dependencies.add(equationName);
parameterDependencies.put(identifier, dependencies);
}
if (!dependentVariables.containsKey(identifier) && !independentVariables.containsKey(identifier)) {
independentVariables.put(identifier, this.createVariable(parameterAttributes));
}
}
equationParameters.put(equationName, _equationParameters);
equationParameters.put(equationName, declarations);
}
// ---------------------------------------------------------------------------
private void addResultDependencies(Element equation) {
private void addResultDependencies(Element equation) throws EquationSystemException {
String equationName = this.getAttribute(equation, EquationSystemBundle.NAME_ATTRIBUTE);
List<Element> results = equation.getChild(EquationSystemBundle.RESULTS_ELEMENT).getChildren(EquationSystemBundle.RESULT_ELEMENT);
List<String> _equationResults = new ArrayList<>();
List<Declaration> declarations = new ArrayList<>();
HashMap<String, String> resultAttributes;
for (Element result : results) {
resultAttributes = this.extractAttributesForVariables(result);
String identifier = resultAttributes.get(EquationSystemBundle.NAME_ATTRIBUTE);
_equationResults.add(identifier);
Variable<?> variable = this.getDependentVariable(resultAttributes);
if (variable != null) {
Declaration declaration = this.buildDeclaration(variable, resultAttributes);
declarations.add(declaration);
} else {
String message = StringUtils.build("Undefined result {} encountered! Check equation file!", identifier); //$NON-NLS-1$
LOGGER.error(message);
throw new EquationSystemException(message);
}
if (resultDependencies.containsKey(identifier)) {
resultDependencies.get(identifier).add(equationName);
......@@ -505,21 +581,11 @@ public class EquationSystemBuilder {
resultDependencies.put(identifier, dependencies);
}
if (!dependentVariables.containsKey(identifier)) {
Variable<?> output = null;
if (outputVariables.containsKey(identifier)) {
output = outputVariables.get(identifier);
output.setEquate(resultAttributes.get(EquationSystemBundle.EQUATE_ATTRIBUTE));
dependentVariables.put(identifier, output);
} else {
dependentVariables.put(identifier, this.createVariable(resultAttributes));
}
}
if (this.independentVariables.containsKey(identifier)) {
this.independentVariables.remove(identifier);
}
}
equationResults.put(equationName, _equationResults);
equationResults.put(equationName, declarations);
}
// ---------------------------------------------------------------------------
......@@ -550,8 +616,8 @@ public class EquationSystemBuilder {
private void createEquations(Element equation) throws EquationSystemException {
String equationName = this.getAttribute(equation, EquationSystemBundle.NAME_ATTRIBUTE);
LinkedHashSet<Variable<?>> equationInputs = new LinkedHashSet<>();
LinkedHashSet<Variable<?>> equationOutputs = new LinkedHashSet<>();
LinkedHashSet<Declaration> equationInputs = new LinkedHashSet<>();
LinkedHashSet<Declaration> equationOutputs = new LinkedHashSet<>();
boolean lockToNesting = true;
String periodicity = equation.getAttributeValue(EquationSystemBundle.PERIODIC_ATTRIBUTE);
......@@ -569,29 +635,31 @@ public class EquationSystemBuilder {
isolated = EquationSystemBundle.ISOLATED_VALUE.equals(mode);
}
for (String identifier : equationParameters.get(equationName)) {
for (Declaration declaration : equationParameters.get(equationName)) {
String identifier = declaration.getIdentifier();
if (independentVariables.containsKey(identifier)) {
equationInputs.add(independentVariables.get(identifier));
equationInputs.add(declaration);
lockToNesting &= true;
} else if (dependentVariables.containsKey(identifier)) {
equationInputs.add(dependentVariables.get(identifier));
equationInputs.add(declaration);
lockToNesting = false;
} else {
StringBuilder message = new StringBuilder("Undefined parameter " + identifier + " encountered! Check equation file!"); //$NON-NLS-1$ //$NON-NLS-2$
LOGGER.error(message.toString());
throw new EquationSystemException(message.toString());
String message = StringUtils.build("Undefined parameter {} encountered! Check equation file!", identifier); //$NON-NLS-1$
LOGGER.error(message);
throw new EquationSystemException(message);
}
}
LOGGER.info("Locking of nested Equations is {} for equation {}", (lockToNesting) ? "Enabled" : "Disabled", equationName); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
for (String identifier : equationResults.get(equationName)) {
for (Declaration declaration : equationResults.get(equationName)) {
String identifier = declaration.getIdentifier();
if (dependentVariables.containsKey(identifier)) {
equationOutputs.add(dependentVariables.get(identifier));
equationOutputs.add(declaration);
} else {