Dear all, Please be informed that, due to an important technical maintenance, the Gitlab server (git.list.lu) will not be available on Thursday April 22nd, from 9 A.M. to 1 P.M. (Luxembourg Time Zone). Thank you for your understanding.

Commit 0dbde05f authored by Nico Mack's avatar Nico Mack

Extended cps engine to handle octave, python and javascript engines

parent 3614648c
......@@ -50,9 +50,25 @@
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>dk.ange</groupId>
<groupId>maven2.dk.ange</groupId>
<artifactId>javaoctave</artifactId>
<version>0.6.4</version>
</dependency>
<dependency>
<groupId>org.python</groupId>
<artifactId>jython-standalone</artifactId>
<version>2.7.1b3</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>Kenai</id>
<name>Kenai</name>
<url>https://svn.kenai.com/svn/javaoctave~maven-repository</url>
</repository>
</repositories>
</project>
\ No newline at end of file
......@@ -22,15 +22,16 @@ package lu.list.itis.dkd.tui.cps.system;
import lu.list.itis.dkd.dbc.annotation.NonNullByDefault;
import lu.list.itis.dkd.dbc.annotation.Nullable;
import lu.list.itis.dkd.tui.cps.system.executor.Executor;
import lu.list.itis.dkd.tui.cps.variable.Variable;
import com.google.common.base.Preconditions;
import java.util.LinkedHashSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.script.ScriptEngine;
import javax.script.ScriptException;
/**
* Class modelling a mathematical equation that is evaluated by an engine.
......@@ -44,9 +45,12 @@ public class Equation {
private Mapping mapping;
private Mapping lockedMapping;
@Nullable
private ScriptEngine scriptEngine;
// private ScriptEngine scriptEngine;
private Executor scriptExecutor;
private String script;
private static Logger LOGGER = Logger.getLogger(Equation.class.getSimpleName());
/**
* Constructor
*
......@@ -77,11 +81,49 @@ public class Equation {
* mapping.
*/
public void evaluate() {
Preconditions.checkState(scriptEngine != null);
// Preconditions.checkState(scriptEngine != null);
// try {
// mapping.getDependentVariable().setValue(scriptEngine.eval(replaceVariables()));
// } catch (ScriptException e) {
// Logger.getLogger(Equation.class.getSimpleName()).log(Level.SEVERE, "Exception while
// executing script!", e); //$NON-NLS-1$
// }
LinkedHashSet<Variable> dependentVariables;
String evaluationErrors;
Preconditions.checkState(scriptExecutor != null);
try {
mapping.getDependentVariable().setValue(scriptEngine.eval(replaceVariables()));
} catch (ScriptException e) {
Logger.getLogger(Equation.class.getSimpleName()).log(Level.SEVERE, "Exception while executing script!", e); //$NON-NLS-1$
scriptExecutor.resetExecutionErrors();
for (Variable variable : lockedMapping.getIndependentVariables()) {
scriptExecutor.set(variable);
}
scriptExecutor.eval(this.script);
} catch (Exception exception) {
LOGGER.log(Level.SEVERE, "Error while evaluating script " + this.script, exception); //$NON-NLS-1$
}
dependentVariables = mapping.getDependentVariables();
for (Variable variable : dependentVariables) {
try {
variable = scriptExecutor.get(variable);
} catch (Exception exception) {
LOGGER.log(Level.SEVERE, "Error while retrieving variable " + variable.getName(), exception); //$NON-NLS-1$
}
}
evaluationErrors = scriptExecutor.getExecutionErrors();
if (evaluationErrors.length() > 0) {
LOGGER.log(Level.WARNING, "Error while evaluating equation :" + evaluationErrors); //$NON-NLS-1$
LOGGER.log(Level.WARNING, "Script =" + this.script); //$NON-NLS-1$
LinkedHashSet<Variable> independentVariables = mapping.getIndependentVariables();
for (Variable variable : independentVariables) {
LOGGER.log(Level.INFO, variable.getName() + " = " + variable.getValue()); //$NON-NLS-1$
}
}
}
......@@ -90,17 +132,20 @@ public class Equation {
*
* @return The formula with variables replaced by their values, ready for evaluation.
*/
private String replaceVariables() {
String result = new String(script);
for (Variable variable : lockedMapping.getIndependentVariables()) {
result = result.replaceAll(variable.getName(), variable.getValue().toString());
}
result = result.replaceAll(lockedMapping.getDependentVariable().getName(), lockedMapping.getDependentVariable().getValue().toString());
assert result != null;
return result;
}
// private String replaceVariables() {
// String result = new String(script);
//
// for (Variable variable : lockedMapping.getIndependentVariables()) {
// result = result.replaceAll(variable.getName(), variable.getValue().toString());
// }
//
// for (Variable variable : lockedMapping.getDependentVariables()) {
// result = result.replaceAll(variable.getName(), variable.getValue().toString());
// }
//
// assert result != null;
// return result;
// }
/**
* Method for setting the script engine to use.
......@@ -108,8 +153,17 @@ public class Equation {
* @param engine
* The {@link ScriptEngine} instance to use for evaluating the scripted formulas.
*/
public void setScriptEngine(ScriptEngine engine) {
scriptEngine = engine;
// public void setScriptEngine(ScriptEngine engine) {
// scriptEngine = engine;
// }
/**
* Method for setting the script engine to use.
*
* @param engine
* The {@link ScriptEngine} instance to use for evaluating the scripted formulas.
*/
public void setExecutor(Executor executor) {
this.scriptExecutor = executor;
}
/**
......
......@@ -22,10 +22,10 @@ package lu.list.itis.dkd.tui.cps.system;
import lu.list.itis.dkd.dbc.annotation.NonNullByDefault;
import lu.list.itis.dkd.tui.cps.Phenomenon;
import lu.list.itis.dkd.tui.cps.system.executor.Executor;
import lu.list.itis.dkd.tui.cps.utility.Externalization;
import lu.list.itis.dkd.tui.cps.variable.BooleanVariable;
import lu.list.itis.dkd.tui.cps.variable.Variable;
import lu.list.itis.dkd.tui.cps.variable.tangible.TangibleNumericalVariable;
import com.google.common.base.Strings;
......@@ -41,6 +41,7 @@ import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
......@@ -60,7 +61,9 @@ import java.util.regex.Pattern;
*/
@NonNullByDefault
public class EquationSystemBuilder {
private Properties properties;
private Document equationDocument;
private Executor scriptExecutor;
private ConcurrentHashMap<String, Variable> independentVariables;
private ConcurrentHashMap<String, Variable> dependentVariables;
......@@ -70,6 +73,7 @@ public class EquationSystemBuilder {
// TODO Refactor to use Multimaps
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, LinearEquationSystem> equations;
......@@ -81,7 +85,10 @@ public class EquationSystemBuilder {
/**
* Constructor initializing all fields.
*/
public EquationSystemBuilder() {
public EquationSystemBuilder(Properties properties) {
this.properties = properties;
this.scriptExecutor = this.instantiateExecutor(properties);
independentVariables = new ConcurrentHashMap<String, Variable>();
dependentVariables = new ConcurrentHashMap<String, Variable>();
......@@ -90,12 +97,50 @@ public class EquationSystemBuilder {
parameterDependencies = new ConcurrentHashMap<String, List<String>>();
resultDependencies = new ConcurrentHashMap<String, List<String>>();
equationImports = new ConcurrentHashMap<String, List<Import>>();
equationParameters = new ConcurrentHashMap<String, List<String>>();
equationResults = new ConcurrentHashMap<String, List<String>>();
equations = new ConcurrentHashMap<String, LinearEquationSystem>();
phenomena = new ConcurrentHashMap<String, Phenomenon>();
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Primitives *
// ***************************************************************************
// ---------------------------------------------------------------------------
private Executor instantiateExecutor(Properties properties) {
Executor executor = null;
String executorClass = properties.getProperty(Externalization.EXECUTOR_CLASS);
try {
executor = (Executor) Class.forName(executorClass)
.getConstructor(Properties.class)
.newInstance(properties);
} catch (Exception exception) {
logger.log(Level.SEVERE, "Failed to instantiate executor class " + executorClass + "!", exception); //$NON-NLS-1$ //$NON-NLS-2$
}
return executor;
}
// ---------------------------------------------------------------------------
private Variable instantiateVariable(Properties properties, String name, String unit, double value) {
Variable variable = null;
String variableClass = properties.getProperty(Externalization.VARIABLE_CLASS);
try {
variable = (Variable) Class.forName(variableClass)
.getConstructor(String.class, String.class, double.class)
.newInstance(name, unit, value);
} catch (Exception exception) {
logger.log(Level.SEVERE, "Failed to instantiate variable class " + variableClass + "!", exception); //$NON-NLS-1$ //$NON-NLS-2$
}
return variable;
}
/**
* Checks whether the specified equation creates a dependency cycle. Dependency cycles occur
......@@ -156,12 +201,12 @@ public class EquationSystemBuilder {
if (Strings.isNullOrEmpty(unit))
unit = output.getAttributeValue(Externalization.UNIT_ELEMENT);
if (Strings.isNullOrEmpty(unit))
unit = "";
unit = Variable.NO_UNIT;
if (Strings.isNullOrEmpty(name)) {
throw new EquationSystemException("For each output the name needs to be defined!"); //$NON-NLS-1$
}
addVariable(outputVariables, name, unit);
addVariable(outputVariables, name, unit, "");
}
}
......@@ -169,6 +214,7 @@ public class EquationSystemBuilder {
private void extractEquations(List<Element> equationElements) throws EquationSystemException {
// First pass to gather all Parameters and Results and to determine dependencies
for (Element equation : equationElements) {
extractImports(equation);
addDependencies(equation);
}
......@@ -186,7 +232,28 @@ public class EquationSystemBuilder {
}
}
private void extractImports(Element equation) {
String equationName;
List<Element> importDeclarations;
List<Import> imports;
equationName = equation.getAttributeValue(Externalization.NAME_ELEMENT);
if (Strings.isNullOrEmpty(equationName))
equationName = equation.getAttributeValue(Externalization.NAME_ELEMENT);
Element importsTag = equation.getChild(Externalization.IMPORTS_ELEMENT);
if (importsTag != null) {
imports = new ArrayList<Import>();
importDeclarations = importsTag.getChildren(Externalization.IMPORT_ELEMENT);
for (Element declaration : importDeclarations) {
String function = declaration.getAttributeValue(Externalization.FUNCTION_ATTRIBUTE);
String from = declaration.getAttributeValue(Externalization.FROM_ATTRIBUTE);
imports.add(new Import(function, from));
}
this.equationImports.put(equationName, imports);
}
}
private void addParameterDependencies(Element equation) {
String equationName = equation.getChildText(Externalization.NAME_ELEMENT);
......@@ -205,7 +272,7 @@ public class EquationSystemBuilder {
if (Strings.isNullOrEmpty(parameterUnit))
parameterUnit = parameter.getAttributeValue(Externalization.UNIT_ELEMENT);
if (Strings.isNullOrEmpty(parameterUnit))
parameterUnit = "";
parameterUnit = Variable.NO_UNIT;
_equationParameters.add(parameterName);
......@@ -218,7 +285,7 @@ public class EquationSystemBuilder {
}
if (!dependentVariables.containsKey(parameterName) && !independentVariables.containsKey(parameterName)) {
addVariable(independentVariables, parameterName, parameterUnit);
addVariable(independentVariables, parameterName, parameterUnit, "");
}
}
equationParameters.put(equationName, _equationParameters);
......@@ -237,18 +304,28 @@ public class EquationSystemBuilder {
* @param unit
* The name of the unit the variable will carry.
*/
private void addVariable(Map<String, Variable> map, String name, String unit) {
switch (unit) {
case "boolean": //$NON-NLS-1$
map.put(name, new BooleanVariable(name, false));
break;
default:
map.put(name, new TangibleNumericalVariable(name, unit, 0));
break;
private void addVariable(Map<String, Variable> map, String name, String unit, String equate) {
Variable newVariable;
if (unit != null) {
switch (unit) {
case "boolean": //$NON-NLS-1$
newVariable = new BooleanVariable(name, false);
newVariable.setEquate(equate);
map.put(name, newVariable);
break;
default:
newVariable = instantiateVariable(properties, name, unit, 0);
newVariable.setEquate(equate);
map.put(name, newVariable);
break;
}
} else {
newVariable = instantiateVariable(properties, name, unit, 0);
newVariable.setEquate(equate);
map.put(name, newVariable);
}
}
private void addResultDependencies(Element equation) {
String equationName = equation.getChildText(Externalization.NAME_ELEMENT);
if (Strings.isNullOrEmpty(equationName))
......@@ -267,6 +344,10 @@ public class EquationSystemBuilder {
if (Strings.isNullOrEmpty(resultUnit))
resultUnit = result.getAttributeValue(Externalization.UNIT_ELEMENT);
String equate = result.getChildText(Externalization.EQUATE_ATTRIBUTE);
if (Strings.isNullOrEmpty(equate))
equate = result.getAttributeValue(Externalization.EQUATE_ATTRIBUTE);
_equationResults.add(resultName);
if (resultDependencies.containsKey(resultName)) {
......@@ -278,10 +359,13 @@ public class EquationSystemBuilder {
}
if (!dependentVariables.containsKey(resultName)) {
Variable output = null;
if (outputVariables.containsKey(resultName)) {
dependentVariables.put(resultName, outputVariables.get(resultName));
output = outputVariables.get(resultName);
output.setEquate(equate);
dependentVariables.put(resultName, output);
} else {
addVariable(dependentVariables, resultName, resultUnit);
addVariable(dependentVariables, resultName, resultUnit, equate);
}
}
if (this.independentVariables.containsKey(resultName)) {
......@@ -294,7 +378,7 @@ public class EquationSystemBuilder {
}
private void addDependencies(Element equation) throws EquationSystemException {
String periodicity = equation.getChildText(Externalization.PERIODIC_ELEMENT);
String periodicity = equation.getAttributeValue(Externalization.PERIODIC_ATTRIBUTE);
boolean periodic = false;
if (!Strings.isNullOrEmpty(periodicity)) {
......@@ -314,8 +398,6 @@ public class EquationSystemBuilder {
}
}
private void createEquations(Element equation) throws EquationSystemException {
String equationName = equation.getChildText(Externalization.NAME_ELEMENT);
if (Strings.isNullOrEmpty(equationName))
......@@ -324,7 +406,7 @@ public class EquationSystemBuilder {
LinkedHashSet<Variable> equationInputs = new LinkedHashSet<>();
LinkedHashSet<Variable> equationOutputs = new LinkedHashSet<>();
boolean lockToNesting = true;
String periodicity = equation.getChildText(Externalization.PERIODIC_ELEMENT);
String periodicity = equation.getAttributeValue(Externalization.PERIODIC_ATTRIBUTE);
boolean periodic = false;
if (!Strings.isNullOrEmpty(periodicity)) {
......@@ -357,13 +439,13 @@ public class EquationSystemBuilder {
}
}
final List<Mapping> inputOutputMappings = new ArrayList<>();
for (Variable output : equationOutputs) {
inputOutputMappings.add(new Mapping(equationInputs, output));
}
String script = equation.getChildText(Externalization.INVOKE_ELEMENT);
Mapping variableMapping = new Mapping(equationInputs, equationOutputs);
final LinearEquationSystem equationSystem = new LinearEquationSystem(lockToNesting);
inputOutputMappings.forEach(mapping -> equationSystem.addEquation(new Equation(mapping, equation.getChildText(Externalization.INVOKE_ELEMENT))));
Equation newEquation = new Equation(variableMapping, script);
newEquation.setExecutor(this.scriptExecutor);
equationSystem.addEquation(newEquation);
if (!periodic) {
for (Variable parameter : equationInputs) {
......@@ -390,6 +472,11 @@ public class EquationSystemBuilder {
LinearEquationSystem equation;
for (String equationName : this.equations.keySet()) {
if (equationImports.containsKey(equationName)) {
this.scriptExecutor.resolve(equationImports.get(equationName));
}
equation = this.equations.get(equationName);
for (String identifier : this.equationParameters.get(equationName)) {
if (this.resultDependencies.containsKey(identifier)) {
......@@ -412,6 +499,12 @@ public class EquationSystemBuilder {
}
}
}
for (String phenomenonName : this.phenomena.keySet()) {
if (equationImports.containsKey(phenomenonName)) {
this.scriptExecutor.resolve(equationImports.get(phenomenonName));
}
}
}
/**
......@@ -481,6 +574,11 @@ public class EquationSystemBuilder {
return outputVariables;
}
public Map<String, Phenomenon> getPhenomena() {
return this.phenomena;
}
/**
* Simple getter method for returning all equations held by this instance.
......
package lu.list.itis.dkd.tui.cps.system;
public class Import
{
private String function;
private String from;
public Import (String function, String from)
{
this.function = function;
this.from = from;
}
public String getFunction()
{
return function;
}
public void setFunction(String function)
{
this.function = function;
}
public String getFrom()
{
return from;
}
public void setFrom(String from)
{
this.from = from;
}
}
......@@ -28,9 +28,6 @@ import com.google.common.base.Preconditions;
import java.util.concurrent.ConcurrentHashMap;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
/**
* Class implementing a system of linear equations. The class holds a number of equations and
* defines the engine that evaluates the equations. The class may be driven by a clock react to
......@@ -43,7 +40,7 @@ import javax.script.ScriptEngineManager;
@NonNullByDefault
public class LinearEquationSystem extends System {
private ConcurrentHashMap<Mapping, Equation> equations;
private ScriptEngine scriptEngine;
// private ScriptEngine scriptEngine;
/**
* Constructor issuing a super call and initialising the map of equations.
......@@ -57,9 +54,9 @@ public class LinearEquationSystem extends System {
public LinearEquationSystem(boolean lockToNesting) {
super();
equations = new ConcurrentHashMap<>();
scriptEngine = new ScriptEngineManager().getEngineByName("js"); //$NON-NLS-1$
// scriptEngine = new ScriptEngineManager().getEngineByName("js"); //$NON-NLS-1$
this.lockSystemForNesting = lockToNesting;
assert scriptEngine != null : "Script engine cannot be null;"; //$NON-NLS-1$
// assert scriptEngine != null : "Script engine cannot be null;"; //$NON-NLS-1$
}
/**
......@@ -70,7 +67,7 @@ public class LinearEquationSystem extends System {
* @return An instance of the equation map for chain-calling.
*/
public ConcurrentHashMap<Mapping, Equation> addEquation(Equation equation) {
equation.setScriptEngine(scriptEngine);
// equation.setScriptEngine(scriptEngine);
equations.put(equation.getMapping(), equation);
return equations;
}
......
......@@ -24,7 +24,6 @@ import lu.list.itis.dkd.dbc.annotation.NonNullByDefault;
import lu.list.itis.dkd.dbc.annotation.Nullable;
import lu.list.itis.dkd.tui.cps.variable.Variable;
import java.util.Collection;
import java.util.LinkedHashSet;
/**
......@@ -37,8 +36,8 @@ import java.util.LinkedHashSet;
*/
@NonNullByDefault
public class Mapping {
private Collection<Variable> independentVariables;
private Variable dependentVariable;
private LinkedHashSet<Variable> independentVariables;
private LinkedHashSet<Variable> dependentVariables;
/**
* Constructor initialising the mapping.
......@@ -48,11 +47,11 @@ public class Mapping {
* @param dependentVariable
* The dependent variable of the mapping.
*/
public Mapping(Collection<Variable> independentVariables, Variable dependentVariable) {
public Mapping(LinkedHashSet<Variable> independentVariables, LinkedHashSet<Variable> dependentVariables) {
// Preconditions.checkArgument(!independentVariables.isEmpty(), "The set of input variables
// cannot be empty."); //$NON-NLS-1$
this.independentVariables = independentVariables;
this.dependentVariable = dependentVariable;
this.dependentVariables = dependentVariables;
}
/**
......@@ -60,17 +59,17 @@ public class Mapping {
*
* @return The value of independentVariables.
*/
public Collection<Variable> getIndependentVariables() {
public LinkedHashSet<Variable> getIndependentVariables() {
return independentVariables;
}
/**
* Simple getter method for dependentVariable.
* Simple getter method for dependentVariables.
*
* @return The value of dependentVariable.
* @return The value of dependentVariables.
*/
public Variable getDependentVariable() {