Index: branches/HeuristicLab.Problems.GrammaticalOptimization-gkr/HeuristicLab.Problems.GrammaticalOptimization/Problems/SymbolicRegressionPoly10Problem.cs
===================================================================
--- branches/HeuristicLab.Problems.GrammaticalOptimization-gkr/HeuristicLab.Problems.GrammaticalOptimization/Problems/SymbolicRegressionPoly10Problem.cs	(revision 12391)
+++ branches/HeuristicLab.Problems.GrammaticalOptimization-gkr/HeuristicLab.Problems.GrammaticalOptimization/Problems/SymbolicRegressionPoly10Problem.cs	(revision 12893)
@@ -6,4 +6,5 @@
 using System.Linq;
 using System.Net;
+using System.Runtime.InteropServices;
 using System.Security;
 using System.Security.AccessControl;
@@ -60,9 +61,9 @@
     public string Name { get { return "SymbolicRegressionPoly10"; } }
 
-    public SymbolicRegressionPoly10Problem() {
+    public SymbolicRegressionPoly10Problem(int n = 500) {
       this.grammar = new Grammar(grammarString);
       this.TreeBasedGPGrammar = new Grammar(hlGrammarString);
 
-      this.N = 500;
+      this.N = n;
       this.x = new double[N][];
       this.y = new double[N];
@@ -99,7 +100,8 @@
     }
 
+    private static double[] erc = new double[] { 0.0, 1.0 };
     public double Evaluate(string sentence) {
       var interpreter = new ExpressionInterpreter();
-      return HeuristicLab.Common.Extensions.RSq(y, Enumerable.Range(0, N).Select(i => interpreter.Interpret(sentence, x[i])).ToArray());
+      return Math.Round(HeuristicLab.Common.Extensions.RSq(y, Enumerable.Range(0, N).Select(i => interpreter.Interpret(sentence, x[i], erc)).ToArray()), 3);
     }
 
@@ -166,5 +168,5 @@
 
 
-      if (phrase.EndsWith("E")) phrase = phrase.TrimEnd('*', '+', 'E');
+      //if (phrase.EndsWith("E")) phrase = phrase.TrimEnd('*', '+', 'E');
       //var len = 5;
       //var start = Math.Max(0, phrase.Length - len);
@@ -174,10 +176,18 @@
       //
 
-      var terms = phrase.Split('+');
-      foreach (var t in terms.Distinct()) yield return new Feature(t, 1.0);
-
-      for (int i = 0; i < terms.Length; i++) {
-        for (int j = i + 1; j < terms.Length; j++) {
-          yield return new Feature(terms[i] + " " + terms[j], 1.0);
+      //var terms = phrase.Split('+');
+      //foreach (var t in terms.Distinct()) yield return new Feature(t, 1.0);
+      //
+      //for (int i = 0; i < terms.Length; i++) {
+      //  for (int j = i + 1; j < terms.Length; j++) {
+      //    yield return new Feature(terms[i] + " " + terms[j], 1.0);
+      //  }
+      //}
+      var t = new string[] { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j" };
+      for (int t0Idx = 0; t0Idx < t.Length - 1; t0Idx++) {
+        for (int t1Idx = t0Idx; t1Idx < t.Length; t1Idx++) {
+          var a = t[t0Idx] + "*" + t[t1Idx];
+          var b = t[t1Idx] + "*" + t[t0Idx];
+          yield return new Feature(a, phrase.Contains(a) || phrase.Contains(b) ? 1 : 0);
         }
       }
@@ -225,4 +235,165 @@
     }
 
+    private static string[][] optimalTerms = new string[][]
+      {
+        new string[] { "a*b","b*a",},
+        new string[] { "c*d","d*c",},
+        new string[] { "e*f","f*e",},
+        new string[] { "a*g*i","a*i*g","g*a*i","g*i*a","i*a*g","i*g*a"},
+        new string[] { "c*j*f","c*f*j","j*c*f","j*f*c","f*c*j","f*j*c"},
+      };
+
+    private static int[][] permute5 = new int[][]
+      {
+        new int[] { 4, 3, 2, 0, 1 },
+        new int[] { 4, 3, 2, 1, 0 },
+        new int[] { 4, 3, 0, 2, 1 },
+        new int[] { 4, 3, 1, 2, 0 },
+        new int[] { 4, 3, 0, 1, 2 },
+        new int[] { 4, 3, 1, 0, 2 },
+        new int[] { 4, 2, 3, 0, 1 },
+        new int[] { 4, 2, 3, 1, 0 },
+        new int[] { 4, 0, 3, 2, 1 },
+        new int[] { 4, 1, 3, 2, 0 },
+        new int[] { 4, 0, 3, 1, 2 },
+        new int[] { 4, 1, 3, 0, 2 },
+        new int[] { 4, 2, 0, 3, 1 },
+        new int[] { 4, 2, 1, 3, 0 },
+        new int[] { 4, 0, 2, 3, 1 },
+        new int[] { 4, 1, 2, 3, 0 },
+        new int[] { 4, 0, 1, 3, 2 },
+        new int[] { 4, 1, 0, 3, 2 },
+        new int[] { 4, 2, 0, 1, 3 },
+        new int[] { 4, 2, 1, 0, 3 },
+        new int[] { 4, 0, 2, 1, 3 },
+        new int[] { 4, 1, 2, 0, 3 },
+        new int[] { 4, 0, 1, 2, 3 },
+        new int[] { 4, 1, 0, 2, 3 },
+        new int[] { 3, 4, 2, 0, 1 },
+        new int[] { 3, 4, 2, 1, 0 },
+        new int[] { 3, 4, 0, 2, 1 },
+        new int[] { 3, 4, 1, 2, 0 },
+        new int[] { 3, 4, 0, 1, 2 },
+        new int[] { 3, 4, 1, 0, 2 },
+        new int[] { 2, 4, 3, 0, 1 },
+        new int[] { 2, 4, 3, 1, 0 },
+        new int[] { 0, 4, 3, 2, 1 },
+        new int[] { 1, 4, 3, 2, 0 },
+        new int[] { 0, 4, 3, 1, 2 },
+        new int[] { 1, 4, 3, 0, 2 },
+        new int[] { 2, 4, 0, 3, 1 },
+        new int[] { 2, 4, 1, 3, 0 },
+        new int[] { 0, 4, 2, 3, 1 },
+        new int[] { 1, 4, 2, 3, 0 },
+        new int[] { 0, 4, 1, 3, 2 },
+        new int[] { 1, 4, 0, 3, 2 },
+        new int[] { 2, 4, 0, 1, 3 },
+        new int[] { 2, 4, 1, 0, 3 },
+        new int[] { 0, 4, 2, 1, 3 },
+        new int[] { 1, 4, 2, 0, 3 },
+        new int[] { 0, 4, 1, 2, 3 },
+        new int[] { 1, 4, 0, 2, 3 },
+        new int[] { 3, 2, 4, 0, 1 },
+        new int[] { 3, 2, 4, 1, 0 },
+        new int[] { 3, 0, 4, 2, 1 },
+        new int[] { 3, 1, 4, 2, 0 },
+        new int[] { 3, 0, 4, 1, 2 },
+        new int[] { 3, 1, 4, 0, 2 },
+        new int[] { 2, 3, 4, 0, 1 },
+        new int[] { 2, 3, 4, 1, 0 },
+        new int[] { 0, 3, 4, 2, 1 },
+        new int[] { 1, 3, 4, 2, 0 },
+        new int[] { 0, 3, 4, 1, 2 },
+        new int[] { 1, 3, 4, 0, 2 },
+        new int[] { 2, 0, 4, 3, 1 },
+        new int[] { 2, 1, 4, 3, 0 },
+        new int[] { 0, 2, 4, 3, 1 },
+        new int[] { 1, 2, 4, 3, 0 },
+        new int[] { 0, 1, 4, 3, 2 },
+        new int[] { 1, 0, 4, 3, 2 },
+        new int[] { 2, 0, 4, 1, 3 },
+        new int[] { 2, 1, 4, 0, 3 },
+        new int[] { 0, 2, 4, 1, 3 },
+        new int[] { 1, 2, 4, 0, 3 },
+        new int[] { 0, 1, 4, 2, 3 },
+        new int[] { 1, 0, 4, 2, 3 },
+        new int[] { 3, 2, 0, 4, 1 },
+        new int[] { 3, 2, 1, 4, 0 },
+        new int[] { 3, 0, 2, 4, 1 },
+        new int[] { 3, 1, 2, 4, 0 },
+        new int[] { 3, 0, 1, 4, 2 },
+        new int[] { 3, 1, 0, 4, 2 },
+        new int[] { 2, 3, 0, 4, 1 },
+        new int[] { 2, 3, 1, 4, 0 },
+        new int[] { 0, 3, 2, 4, 1 },
+        new int[] { 1, 3, 2, 4, 0 },
+        new int[] { 0, 3, 1, 4, 2 },
+        new int[] { 1, 3, 0, 4, 2 },
+        new int[] { 2, 0, 3, 4, 1 },
+        new int[] { 2, 1, 3, 4, 0 },
+        new int[] { 0, 2, 3, 4, 1 },
+        new int[] { 1, 2, 3, 4, 0 },
+        new int[] { 0, 1, 3, 4, 2 },
+        new int[] { 1, 0, 3, 4, 2 },
+        new int[] { 2, 0, 1, 4, 3 },
+        new int[] { 2, 1, 0, 4, 3 },
+        new int[] { 0, 2, 1, 4, 3 },
+        new int[] { 1, 2, 0, 4, 3 },
+        new int[] { 0, 1, 2, 4, 3 },
+        new int[] { 1, 0, 2, 4, 3 },
+        new int[] { 3, 2, 0, 1, 4 },
+        new int[] { 3, 2, 1, 0, 4 },
+        new int[] { 3, 0, 2, 1, 4 },
+        new int[] { 3, 1, 2, 0, 4 },
+        new int[] { 3, 0, 1, 2, 4 },
+        new int[] { 3, 1, 0, 2, 4 },
+        new int[] { 2, 3, 0, 1, 4 },
+        new int[] { 2, 3, 1, 0, 4 },
+        new int[] { 0, 3, 2, 1, 4 },
+        new int[] { 1, 3, 2, 0, 4 },
+        new int[] { 0, 3, 1, 2, 4 },
+        new int[] { 1, 3, 0, 2, 4 },
+        new int[] { 2, 0, 3, 1, 4 },
+        new int[] { 2, 1, 3, 0, 4 },
+        new int[] { 0, 2, 3, 1, 4 },
+        new int[] { 1, 2, 3, 0, 4 },
+        new int[] { 0, 1, 3, 2, 4 },
+        new int[] { 1, 0, 3, 2, 4 },
+        new int[] { 2, 0, 1, 3, 4 },
+        new int[] { 2, 1, 0, 3, 4 },
+        new int[] { 0, 2, 1, 3, 4 },
+        new int[] { 1, 2, 0, 3, 4 },
+        new int[] { 0, 1, 2, 3, 4 },
+        new int[] { 1, 0, 2, 3, 4 },
+      };
+
+
+    private static HashSet<string>[] optimalSentences;
+    static SymbolicRegressionPoly10Problem() {
+      optimalSentences = Enumerable.Range(0, 24).Select(i => new HashSet<string>()).ToArray();
+
+      foreach (var t0Idx in new[] { 0, 1 })
+        foreach (var t1Idx in new[] { 0, 1 })
+          foreach (var t2Idx in new[] { 0, 1 })
+            foreach (var t3Idx in new[] { 0, 1, 2, 3, 4, 5 })
+              foreach (var t4Idx in new[] { 0, 1, 2, 3, 4, 5 }) {
+                foreach (var p in permute5) {
+                  int[] idx = new int[] { t0Idx, t1Idx, t2Idx, t3Idx, t4Idx };
+                  optimalSentences[23].Add(string.Join("+", p.Select(pi => optimalTerms[pi][idx[pi]])));
+                }
+              }
+      for (int i = 0; i < 23; i += 2) {
+        var newElements = new HashSet<string>();
+        foreach (var sentence in optimalSentences[23]) {
+          newElements.Add(sentence.Substring(0, i) + "E");
+        }
+        foreach (var e in newElements) optimalSentences[i + 1].Add(e);
+      }
+    }
+
+    public bool IsOptimalPhrase(string phrase) {
+      return optimalSentences[phrase.Length].Contains(phrase);
+    }
+
     private void TreeToSentence(ISymbolicExpressionTreeNode treeNode, StringBuilder sb) {
       if (treeNode.SubtreeCount == 0) {
