Dear users, Please note that, from Monday, August 16, 2019, RSA keys shorter than 2048bit will no longer be accepted for security reasons. Please update your keys as needed before this date. If you need assistance with regard to this process, please contact sia@list.lu

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;
}
/**
......
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() {
return dependentVariable;
public LinkedHashSet<Variable> getDependentVariables() {
return dependentVariables;
}
/** {@inheritDoc} */
......@@ -84,7 +83,14 @@ public class Mapping {
separator = ", "; //$NON-NLS-1$
}
renderer.append(" => ").append(dependentVariable.getName()); //$NON-NLS-1$
renderer.append(" => "); //$NON-NLS-1$
separator = ""; //$NON-NLS-1$
for (Variable variable : dependentVariables) {
renderer.append(separator).append(variable.getName());
separator = ", "; //$NON-NLS-1$
}
return renderer.toString();
}
......@@ -143,12 +149,16 @@ public class Mapping {
* @return A deep copy of the {@link Mapping}.
*/
public Mapping lock() {
LinkedHashSet<Variable> clones = new LinkedHashSet<>();
LinkedHashSet<Variable> clonedIndependentVariables = new LinkedHashSet<>();
for (Variable variable : independentVariables) {
clones.add(variable.clone());
clonedIndependentVariables.add(variable.clone());
}
LinkedHashSet<Variable> clonedDependentVariables = new LinkedHashSet<>();
for (Variable variable : dependentVariables) {
clonedDependentVariables.add(variable.clone());
}
return new Mapping(clones, dependentVariable.clone());
return new Mapping(clonedIndependentVariables, clonedDependentVariables);
}
// /**
......
/**
* Copyright Luxembourg Institute of Science and Technology, 2016.
*
* This file is part of TULIP.
*
* TULIP is licensed under a dual-licensing scheme. For non-commercial purposes, the LGPL version 3,
* as stated below, is applicable. For all commercial purposes TULIP is licensed under a LIST
* proprietary license. Please contact LIST at tto@list.lu to obtain a commercial license.
*
* For all non-commercial purposes, TULIP is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, version 3 of the License.
*
* TULIP is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with TULIP. If
* not, see <http://www.gnu.org/licenses/lgpl-3.0.html>.
*/
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.variable.Variable;
import com.google.common.base.Preconditions;
import java.io.CharArrayWriter;
import java.util.LinkedHashSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.script.ScriptEngine;
import dk.ange.octave.OctaveEngine;
import dk.ange.octave.type.Octave;
import dk.ange.octave.type.OctaveDouble;
/**
* @author Nico Mack [nico.mack@list.lu]
* @since 1.1
* @version 1.3.0
*/
@NonNullByDefault
public class OctaveEquation extends Equation {
private OctaveMapping mapping, lockedMapping;
@Nullable
private String script;
private OctaveEngine scriptEngine;
private CharArrayWriter engineErrors;
private static final Logger logger = Logger.getLogger(OctaveEquation.class.getSimpleName());
/**
* Constructor
*
* @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.
*/
public OctaveEquation(OctaveMapping mapping, String script) {
super(mapping, script);
this.mapping = mapping;
this.lockedMapping = mapping;
this.script = script;
this.engineErrors = new CharArrayWriter();
}
/**
* Method called to evaluate the script of the equation with the variables provided by the
* mapping.
*/
@Override
public synchronized void evaluate() {
LinkedHashSet<Variable> dependentVariables;
String evaluationErrors;
Preconditions.checkState(scriptEngine != null);
try {
engineErrors.reset();
scriptEngine.setErrorWriter(engineErrors);
initParameters();
scriptEngine.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 {
OctaveDouble result = scriptEngine.get(OctaveDouble.class, variable.getName());
variable.setValue(result.get(1));
} catch (Exception exception) {
logger.log(Level.SEVERE, "Error while retrieving variable " + variable.getName(), //$NON-NLS-1$
exception);
}
}
evaluationErrors = engineErrors.toString();
if (evaluationErrors.length() > 0) {
logger.log(Level.WARNING, "Error while evaluating equation :" + evaluationErrors); //$NON-NLS-1$
}
}
/**
* Method used to replace variables with their actual values in the formula.
*/
private void initParameters() {
for (Variable variable : lockedMapping.getIndependentVariables()) {
Double numericValue = Double.valueOf(variable.getValue().toString());
if (isNegative(numericValue)) {
numericValue *= -1d;
}
scriptEngine.put(variable.getName(), Octave.scalar(numericValue));
}
}
private static boolean isNegative(double _double) {
return Double.doubleToRawLongBits(_double) < 0;
}
/**
* Method for setting the script engine to use.
*
* @param engine
* The {@link ScriptEngine} instance to use for evaluating the scripted formulas.
*/
public void setScriptEngine(OctaveEngine engine) {
scriptEngine = engine;
}
}
\ No newline at end of file
/**
* Copyright Luxembourg Institute of Science and Technology, 2016.
*
* This file is part of TULIP.
*
* TULIP is licensed under a dual-licensing scheme. For non-commercial purposes, the LGPL version 3,
* as stated below, is applicable. For all commercial purposes TULIP is licensed under a LIST
* proprietary license. Please contact LIST at tto@list.lu to obtain a commercial license.
*
* For all non-commercial purposes, TULIP is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, version 3 of the License.
*
* TULIP is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with TULIP. If
* not, see <http://www.gnu.org/licenses/lgpl-3.0.html>.
*/
package lu.list.itis.dkd.tui.cps.system;
import lu.list.itis.dkd.tui.cps.variable.Variable;
import com.google.common.base.Preconditions;
import java.util.Collection;
import java.util.LinkedHashSet;
/**
*
* @author Nico Mack [nico.mack@list.lu]
* @since 1.1
* @version 1.3.1
*/
public class OctaveMapping extends Mapping {
private LinkedHashSet<Variable> dependentVariables;
/**
*
* @param independentVariables
* @param dependentVariables
*/
public OctaveMapping(LinkedHashSet<Variable> independentVariables, LinkedHashSet<Variable> dependentVariables) {
super(independentVariables, null);
Preconditions.checkArgument(!dependentVariables.isEmpty(), "The set of output variables cannot be empty."); //$NON-NLS-1$
this.dependentVariables = dependentVariables;
}
/**
* Simple getter method for dependentVariable.
*
* @return The value of dependentVariable.
*/
public LinkedHashSet<Variable> getDependentVariables() {
return dependentVariables;
}
@Override
public String toString() {
String separator = ""; //$NON-NLS-1$
StringBuilder renderer = new StringBuilder();
Collection<Variable> independentVariables = super.getIndependentVariables();
for (Variable variable : independentVariables) {
renderer.append(separator).append(variable.getName());
separator = ", "; //$NON-NLS-1$
}
renderer.append(" => "); //$NON-NLS-1$
separator = ""; //$NON-NLS-1$
for (Variable variable : dependentVariables) {
renderer.append(separator).append(variable.getName());
separator = ", "; //$NON-NLS-1$
}
return renderer.toString();
}
/**
* 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}.
*/
@Override
public synchronized Mapping lock() {
Collection<Variable> independentVariables = super.getIndependentVariables();
LinkedHashSet<Variable> clonedIndependentVariables = new LinkedHashSet<>();
for (Variable variable : independentVariables) {
clonedIndependentVariables.add(variable.clone());
}
LinkedHashSet<Variable> clonedDependentVariables = new LinkedHashSet<>();
for (Variable variable : dependentVariables) {
clonedDependentVariables.add(variable.clone());
}
return new OctaveMapping(clonedIndependentVariables, clonedDependentVariables);
}
}
\ No newline at end of file
package lu.list.itis.dkd.tui.cps.system.executor;
import lu.list.itis.dkd.tui.cps.system.Import;
import lu.list.itis.dkd.tui.cps.variable.Variable;
import java.io.CharArrayWriter;
import java.util.List;
import java.util.Properties;
import java.util.logging.Logger;
abstract public class Executor {
protected CharArrayWriter executionErrors;
private static Logger LOGGER = Logger.getLogger(Executor.class.getSimpleName());
public Executor() {
executionErrors = new CharArrayWriter();
}
@SuppressWarnings("unused")
public Executor(Properties properties) {
executionErrors = new CharArrayWriter();
}
public String getExecutionErrors() {
return executionErrors.toString();
}
public void resetExecutionErrors() {
executionErrors.reset();
}
@SuppressWarnings("unused")
public void resolve(List<Import> imports) {
LOGGER.warning("Imports not supported by Executor!"); //$NON-NLS-1$
}
abstract public void set(Variable variable);
abstract public boolean eval(String script);
abstract public Variable get(Variable variable);
}
package lu.list.itis.dkd.tui.cps.system.executor;
import lu.list.itis.dkd.tui.cps.variable.Variable;
import java.util.Properties;
import java.util.logging.Logger;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
public class JavascriptExecutor extends Executor {
private ScriptEngine engine;
private Object result;
private static Logger LOGGER = Logger.getLogger(JavascriptExecutor.class.getSimpleName());
public JavascriptExecutor() {
engine = new ScriptEngineManager().getEngineByName("js"); //$NON-NLS-1$
}
public JavascriptExecutor(Properties properties) {
super(properties);
engine = new ScriptEngineManager().getEngineByName("js"); //$NON-NLS-1$
}
@Override
public void set(Variable variable) {
Double numericValue = Double.valueOf(variable.getValue().toString());
engine.put(variable.getName(), numericValue);
}
@Override
public boolean eval(String script) {
try {
result = engine.eval(script);
} catch (ScriptException exception) {
this.executionErrors.append(exception.toString());
return false;
}
return true;
}
@Override
public Variable get(Variable variable) {
variable.setValue(result);
return variable;
}
}
package lu.list.itis.dkd.tui.cps.system.executor;
import lu.list.itis.dkd.tui.cps.variable.Variable;
import java.io.File;
import java.util.Properties;
import dk.ange.octave.OctaveEngine;
import dk.ange.octave.OctaveEngineFactory;
import dk.ange.octave.type.Octave;
import dk.ange.octave.type.OctaveDouble;
public class OctaveExecutor extends Executor {
private OctaveEngine engine;
private static final String SCRIPT_ENGINE_EXECUTABLE = "octave.executable"; //$NON-NLS-1$
private static final String SCRIPT_ENGINE_WORKING_DIR = "octave.workingDir"; //$NON-NLS-1$
// private static Logger LOGGER = Logger.getLogger(OctaveExecutor.class.getSimpleName());
public OctaveExecutor(Properties properties) {
super(properties);
OctaveEngineFactory engineFactory = new OctaveEngineFactory();
engineFactory.setOctaveProgram(new File(properties.getProperty(SCRIPT_ENGINE_EXECUTABLE, "/opt/local/bin/octave"))); //$NON-NLS-1$
engineFactory.setWorkingDir(new File(properties.getProperty(SCRIPT_ENGINE_WORKING_DIR, "octave"))); //$NON-NLS-1$
engine = engineFactory.getScriptEngine();
engine.setErrorWriter(this.executionErrors);
}
@Override
public void set(Variable variable) {
Double numericValue = Double.valueOf(variable.getValue().toString());
engine.put(variable.getName(), Octave.scalar(numericValue));
}
@Override
public boolean eval(String script) {