Created
November 3, 2015 00:11
-
-
Save vst/a2c6d4599ad0f965ef03 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import org.moeaframework.core.Algorithm; | |
import org.moeaframework.core.Solution; | |
import org.moeaframework.core.spi.AlgorithmFactory; | |
import org.moeaframework.core.variable.Grammar; | |
import org.moeaframework.problem.AbstractProblem; | |
import org.moeaframework.util.grammar.ContextFreeGrammar; | |
import org.moeaframework.util.grammar.Parser; | |
import org.renjin.sexp.SEXP; | |
import javax.script.ScriptEngine; | |
import javax.script.ScriptEngineManager; | |
import javax.script.ScriptException; | |
import java.io.IOException; | |
import java.io.StringReader; | |
import java.util.Properties; | |
/** | |
* Demonstrates how to use MOEA Framework and Renjin to evolve an R program. | |
* | |
* <p> | |
* This simple application requires MOEA and Renjin. These dependencies | |
* can be specified in the POM file as follows: | |
* </p> | |
* | |
* <pre> | |
* <dependency> | |
* <groupId>org.moeaframework</groupId> | |
* <artifactId>moeaframework</artifactId> | |
* <version>2.6</version> | |
* </dependency> | |
* <dependency> | |
* <groupId>org.renjin</groupId> | |
* <artifactId>renjin-script-engine</artifactId> | |
* <version>0.7.0-RC7</version> | |
* </dependency> | |
* </pre> | |
*/ | |
public class SampleRenjinGRE extends AbstractProblem { | |
/** | |
* Defines the grammar of the problem. | |
*/ | |
private final ContextFreeGrammar grammar; | |
/** | |
* Defines a Renjin-based scripting engine to be used for evaluating candidates. | |
*/ | |
private final ScriptEngine engine = new ScriptEngineManager().getEngineByName("Renjin"); | |
/** | |
* Prepares the evolution environment. | |
*/ | |
public SampleRenjinGRE() throws IOException, ScriptException { | |
// Call the super with `number of variables = 1` and `number of objectives = 1`: | |
super(1, 1); | |
// Define a silly grammar: | |
this.grammar = Parser.load(new StringReader("<expr> ::= (<expr> <op> <expr>) | <value>\n" + | |
"<op> ::= + | * | - | /\n" + | |
"<value> ::= x")); | |
// Define some data: | |
this.engine.eval(String.format("mdata <- data.frame(x=1:10, y=(1:10)^5 + 1:10)")); | |
} | |
/** | |
* Consumes a candidate solution and evaluates the objective function score. | |
* | |
* @param solution The candidate solution. | |
*/ | |
public void evaluate(Solution solution) { | |
// Get a string representation of the candidate solution: | |
final String program = this.grammar.build(((Grammar) solution.getVariable(0)).toArray()); | |
// Is the program null? (Why would it be, right? But, there is a reason. Explanation on demand...) | |
if (program == null) { | |
// Penalize without mercy! | |
solution.setObjective(0, Double.POSITIVE_INFINITY); | |
// We are done here, move on: | |
return; | |
} | |
// Define the expression which will evaluate to the objective score: | |
final String expression = String.format("sum(abs((function (x) {%s})(mdata$x) - mdata$y))", program); | |
try { | |
// Evaluate the candidate program on the data and compute the distance to the actual values: | |
final SEXP exp = (SEXP) engine.eval(expression); | |
// Get the real number value: | |
final double result = exp.asReal(); | |
// Is the number naughty? | |
if (!Double.isNaN(result)) { | |
// Set the objective score: | |
solution.setObjective(0, exp.asReal()); | |
} | |
else { | |
// Oops!... Punish: | |
solution.setObjective(0, Double.POSITIVE_INFINITY); | |
} | |
} | |
catch (ScriptException e) { | |
// Something has gone wrong. Wrong must be punished: | |
solution.setObjective(0, Double.POSITIVE_INFINITY); | |
e.printStackTrace(); | |
} | |
} | |
/** | |
* Defines the problem solution representation. | |
* | |
* @return A new solution for the problem. | |
*/ | |
public Solution newSolution() { | |
final Solution solution = new Solution(1, 1); | |
solution.setVariable(0, new Grammar(20)); | |
return solution; | |
} | |
/** | |
* Returns the grammar of the problem. | |
* | |
* @return The grammar of the problem. | |
*/ | |
public ContextFreeGrammar getGrammar() { | |
return this.grammar; | |
} | |
/** | |
* Provides the entry point of the sample application. | |
* | |
* @param args Command line arguments. | |
* @throws IOException I/O Exception. | |
* @throws ScriptException Script engine exception. | |
*/ | |
public static void main (String[] args) throws IOException, ScriptException { | |
// Define the maximum number of generations: | |
final int maxGenerations = 100; | |
// Declare algorithm properties: | |
final Properties properties = new Properties(); | |
// Set the population size: | |
properties.setProperty("populationSize", "300"); | |
// Initialize the problem: | |
final SampleRenjinGRE problem = new SampleRenjinGRE(); | |
// Initialize the algorithm: | |
final Algorithm algorithm = AlgorithmFactory.getInstance().getAlgorithm("NSGAII", properties, problem); | |
// Define the iteration counter: | |
int generation = 1; | |
// Iterate over the generations: | |
while (generation <= maxGenerations) { | |
// Run a generation: | |
algorithm.step(); | |
// Get the result as of now: | |
final Solution result = algorithm.getResult().get(0); | |
// Get the string representation: | |
final String repr = problem.getGrammar().build(((Grammar) result.getVariable(0)).toArray()); | |
// Get the score: | |
final double score = result.getObjective(0); | |
// Calculate the percentage of done task: | |
final double completed = 100.0 * generation / maxGenerations; | |
// Increment the iteration counter: | |
generation++; | |
// Notify: | |
System.out.println(String.format("[%%%3.0f] %.2f %s", completed, score, repr)); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment