From ca490cf482b9fc6056ccbf6b5669bdac413f98dc Mon Sep 17 00:00:00 2001
From: Marcel Kronfeld
Date: Mon, 19 Oct 2009 10:04:05 +0000
Subject: [PATCH] New GP node and help-file for GenericConstraint.
---
resources/GenericConstraint.html | 56 +++++++++++++
.../codings/gp/AbstractGPNode.java | 31 +++++++-
.../go/individuals/codings/gp/GPNodeAbs.java | 79 +++++++++++++++++++
3 files changed, 165 insertions(+), 1 deletion(-)
create mode 100644 resources/GenericConstraint.html
create mode 100644 src/eva2/server/go/individuals/codings/gp/GPNodeAbs.java
diff --git a/resources/GenericConstraint.html b/resources/GenericConstraint.html
new file mode 100644
index 00000000..179b1f43
--- /dev/null
+++ b/resources/GenericConstraint.html
@@ -0,0 +1,56 @@
+
+
+Generic Constraints
+
+
+Generic Constraints
+
+
+To represent generic constraints on real-valued functions, this class can parse
+String expressions in prefix notation of the form:
+
+<expr> ::= <constant-operator> | <functional-operator> "(" <arguments> ")"
+<arguments> ::= <expr> | <expr> "," <arguments>
+
+
+
+Setting the constraint string:
+Constant operators have an arity of zero. Examples are:
+(pi,0) (X,0) (1.0,0)
+
+Functional operators have an arity greater zero. Examples are:
+ (sum,1) (prod,1) (abs,1) (sin,1) (pow2,1) (pow3,1) (sqrt,1) (neg,1) (cos,1) (exp,1)
+ (+,2) (-,2) (/,2) (*,2)
+
+
+Additionally, any numerical strings can also be used; they are parsed to numeric constants. The literal n
+is parsed to the current number of problem dimensions.
+Notice that only the sum and prod operators may receive the literal X as input, standing
+for the full solution vector. Access to single solution components is possible by writing x0...x9
+for a problem with 10 dimensions.
+
+
+
+Thus you may write +(-(5,sum(X)),+sin(/(x0,pi)))
+and select 'lessEqZero' as relation to require valid solutions to fulfill 5-sum(X)+sin(x0/pi)<=0.
+
+
+
+Typical relations concerning constraints allow for g(x)<=0, g(x)==0, or g(x)>=0 for
+constraint g. Notice that equal-to-zero constraints are converted to g(x)==0 <=> |g(x)-epsilon|<=0 for
+customizable small values of epsilon.
+
+
+
+The handling method defines how EvA 2 copes with the constraint. Simplest variant is an
+additive penalty which is scaled by the penalty factor and then added directly to the fitness
+of an individual. This will work for any optimization strategy, but results will depend on
+the selection of penalty factors. Multiplicative penalty works analogously with the difference of
+being multiplied with the raw fitness.
+In the variant called specific tag, the constraint violation is stored in an extra field of any
+individual and may be regarded by the optimization strategy. However, not all strategies provide
+simple mechanisms of incorporating this specific tag.
+
+
+
+
\ No newline at end of file
diff --git a/src/eva2/server/go/individuals/codings/gp/AbstractGPNode.java b/src/eva2/server/go/individuals/codings/gp/AbstractGPNode.java
index b8a6aec1..e8c10b7a 100644
--- a/src/eva2/server/go/individuals/codings/gp/AbstractGPNode.java
+++ b/src/eva2/server/go/individuals/codings/gp/AbstractGPNode.java
@@ -1,6 +1,7 @@
package eva2.server.go.individuals.codings.gp;
+import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Vector;
@@ -10,6 +11,7 @@ import eva2.server.go.problems.GPFunctionProblem;
import eva2.server.go.problems.InterfaceProgramProblem;
import eva2.tools.Mathematics;
import eva2.tools.Pair;
+import eva2.tools.ReflectPackage;
/** This gives an abstract node, with default functionality for get and set methods.
@@ -271,10 +273,37 @@ public abstract class AbstractGPNode implements InterfaceProgram, java.io.Serial
test("-(*(x1,x2),*(5,*(x3,x4)))", solG13);
test("+(pow3(x0),+(pow3(x1),1))", solG13);
System.out.println("" + Math.exp(Mathematics.product(solG13)));
+ test("+(sum(x),abs(sin(*(x0,x3))))", solG5);
+ test("-(abs(sum(x)),*(abs(-7.5),n))", solG5);
- test("-(sum(x),*(7.5,n))", solG5);
+ System.out.println(createNodeList());
}
+ /**
+ * Print all operator identifiers with arities.
+ *
+ * @return
+ */
+ public static String createNodeList() {
+ String ret = new String();
+
+ Class> cls = AbstractGPNode.class;
+ Class>[] nodes = ReflectPackage.getAssignableClassesInPackage(cls.getPackage().getName(), AbstractGPNode.class, true, false);
+ for (Class> c : nodes) {
+ if (Modifier.isAbstract(c.getModifiers()) || c.isInterface()) continue;
+ AbstractGPNode node;
+ try {
+ node = (AbstractGPNode)c.newInstance();
+ ret = ret + " (" + node.getOpIdentifier() + "," + node.getArity() + ")";
+ } catch (InstantiationException e) {
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ }
+ }
+ return ret;
+ }
+
public static void test(String constr, double[] pos) {
AbstractGPNode node = AbstractGPNode.parseFromString(constr);
GPFunctionProblem func = new GPFunctionProblem(node, null, pos.length, 0., 0.);
diff --git a/src/eva2/server/go/individuals/codings/gp/GPNodeAbs.java b/src/eva2/server/go/individuals/codings/gp/GPNodeAbs.java
new file mode 100644
index 00000000..d3d8a7f4
--- /dev/null
+++ b/src/eva2/server/go/individuals/codings/gp/GPNodeAbs.java
@@ -0,0 +1,79 @@
+package eva2.server.go.individuals.codings.gp;
+
+import eva2.server.go.problems.InterfaceProgramProblem;
+
+
+/**
+ * A node for retrieving the absolute value
+ *
+ */
+public class GPNodeAbs extends AbstractGPNode implements java.io.Serializable {
+
+ public GPNodeAbs() {
+ }
+ public GPNodeAbs(GPNodeAbs node) {
+ this.m_Depth = node.m_Depth;
+ this.m_Parent = node.m_Parent;
+ this.m_Nodes = new AbstractGPNode[node.m_Nodes.length];
+ for (int i = 0; i < node.m_Nodes.length; i++) this.m_Nodes[i] = (AbstractGPNode) node.m_Nodes[i].clone();
+ }
+
+ /** This method allows you to determine wehter or not two subtrees
+ * are actually the same.
+ * @param obj The other subtree.
+ * @return boolean if equal true else false.
+ */
+ public boolean equals(Object obj) {
+ if (obj instanceof GPNodeAbs) {
+ GPNodeAbs node = (GPNodeAbs)obj;
+ if (this.m_Nodes.length != node.m_Nodes.length) return false;
+ for (int i = 0; i < this.m_Nodes.length; i++) {
+ if (!this.m_Nodes[i].equals(node.m_Nodes[i])) return false;
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /** This method will be used to identify the node in the GPAreaEditor
+ * @return The name.
+ */
+ public String getName() {
+ return "Abs";
+ }
+
+ /** This method allows you to clone the Nodes
+ * @return the clone
+ */
+ public Object clone() {
+ return (Object) new GPNodeAbs(this);
+ }
+
+ /** This method will return the current arity
+ * @return Arity.
+ */
+ public int getArity() {
+ return 1;
+ }
+
+ /** This method will evaluate a given node
+ * @param environment
+ */
+ public Object evaluate(InterfaceProgramProblem environment) {
+ Object tmpObj;
+ double result = 0;
+
+ tmpObj = this.m_Nodes[0].evaluate(environment);
+ if (tmpObj instanceof Double) result += ((Double)tmpObj).doubleValue();
+ Double ret = new Double(result);
+
+ if (ret<0) return -ret;
+ else return ret;
+ }
+
+ @Override
+ public String getOpIdentifier() {
+ return "abs";
+ }
+}