diff --git a/build.gradle b/build.gradle
index 6819940b26065a4c071bab12c3f47d18acadcfab..4727610ca8381ac252bcf17e600ba1a97b864226 100644
--- a/build.gradle
+++ b/build.gradle
@@ -4,3 +4,9 @@
  * This is a general purpose Gradle build.
  * Learn how to create Gradle builds at https://guides.gradle.org/creating-new-gradle-builds/
  */
+
+task benchmark(type: Exec) {
+    workingDir 'scripts'
+
+    commandLine 'python3', 'run.py', '-m'
+}
diff --git a/solutions/RelationalRAGSolution/solution.ini b/solutions/RelationalRAGSolution/solution.ini
index 0e1c2eb3b62d8f05baae9818ccfb07a55b17da01..a061164aca1db12c99f17bbdd2892a99ce144684 100644
--- a/solutions/RelationalRAGSolution/solution.ini
+++ b/solutions/RelationalRAGSolution/solution.ini
@@ -3,4 +3,4 @@ default=./gradlew installDist
 skipTests=./gradlew installDist
 
 [run]
-cmd=JAVA_OPTS="-Xms4g" build/install/RelationalRAGSolution/bin/RelationalRAGSolution
+cmd=JAVA_OPTS="-Xms4g" build/install/RelationalRAGSolution/bin/RelationalRAGSolution bdt case natural
diff --git a/solutions/RelationalRAGSolution/src/main/jastadd/Navigation.jrag b/solutions/RelationalRAGSolution/src/main/jastadd/Navigation.jrag
index d64b820e599382332e76eb0e6edcc4cc5ee8b160..4632d8f537f1af5ad1b2beed952014bde39650f4 100644
--- a/solutions/RelationalRAGSolution/src/main/jastadd/Navigation.jrag
+++ b/solutions/RelationalRAGSolution/src/main/jastadd/Navigation.jrag
@@ -21,7 +21,8 @@ aspect Navigation {
   inh ASTNode ASTNode.root();
   eq TruthTable.getPort().root() = this;
   eq TruthTable.getRow().root() = this;
-  eq TruthTable.getPortOrder().root() = this;
+  eq TruthTable.getNaturalPortOrder().root() = this;
+  eq TruthTable.getHeuristicPortOrder().root() = this;
 
   eq BDT.getTree().root() = this;
 
@@ -36,7 +37,8 @@ aspect Navigation {
   inh TruthTable Cell.containingTruthTable();
   eq TruthTable.getPort().containingTruthTable() = this;
   eq TruthTable.getRow().containingTruthTable() = this;
-  eq TruthTable.getPortOrder().containingTruthTable() = this;
+  eq TruthTable.getNaturalPortOrder().containingTruthTable() = this;
+  eq TruthTable.getHeuristicPortOrder().containingTruthTable() = this;
 
   syn List<OutputPort> TruthTable.outputPorts() {
     List<OutputPort> result = new ArrayList<>();
diff --git a/solutions/RelationalRAGSolution/src/main/jastadd/SimpleBDT.jrag b/solutions/RelationalRAGSolution/src/main/jastadd/SimpleBDT.jrag
index 67f57eb0b866de3135ecdf0f9c7de1ac576650a7..76aded5ffe3d3202981ad18854a2bb43f1dd5fa3 100644
--- a/solutions/RelationalRAGSolution/src/main/jastadd/SimpleBDT.jrag
+++ b/solutions/RelationalRAGSolution/src/main/jastadd/SimpleBDT.jrag
@@ -135,18 +135,6 @@ aspect SimpleBDT {
     return result;
   }
 
-  syn PortOrder TruthTable.getPortOrder() {
-    // a port order defines the order, in which the input ports are evaluated
-    // for the simple case, this order is defined by the list in which the ports are defined
-    PortOrder result = new PortOrder();
-    for (Port port : getPortList()) {
-      if (port.isInput()) {
-        result.addPort(port.asInput());
-      }
-    }
-    return result;
-  }
-
   public Tree TruthTable.subTree(List<InputPort> remainingPorts) {
     return null;
   }
diff --git a/solutions/RelationalRAGSolution/src/main/jastadd/TT.relast b/solutions/RelationalRAGSolution/src/main/jastadd/TT.relast
index 80c4c30c113bf3aa741bfe7dabc263762c82f9bb..564cb55487345997bfbf06de36068072cee3e0e8 100644
--- a/solutions/RelationalRAGSolution/src/main/jastadd/TT.relast
+++ b/solutions/RelationalRAGSolution/src/main/jastadd/TT.relast
@@ -1,10 +1,12 @@
 LocatedElement ::= <Location:String>;
-TruthTable:LocatedElement ::= <Name:String> Port:Port* Row:Row* /PortOrder/;
-abstract Port:LocatedElement ::= <Name:String>;
-InputPort:Port;
-OutputPort:Port;
-Row:LocatedElement ::= Cell:Cell*;
-Cell:LocatedElement ::= <Value:Boolean>;
+TruthTable : LocatedElement ::= <Name:String> Port:Port* Row:Row* /NaturalPortOrder:PortOrder/ /HeuristicPortOrder:PortOrder/ ;
+rel TruthTable.PortOrder -> PortOrder ;
+
+abstract Port : LocatedElement ::= <Name:String>;
+InputPort : Port;
+OutputPort : Port;
+Row : LocatedElement ::= Cell:Cell*;
+Cell : LocatedElement ::= <Value:Boolean>;
 PortOrder;
 
 rel PortOrder.Port* -> InputPort;
diff --git a/solutions/RelationalRAGSolution/src/main/java/de/tudresden/inf/st/ttc19/Driver.java b/solutions/RelationalRAGSolution/src/main/java/de/tudresden/inf/st/ttc19/Driver.java
index da3f1b6e5e3d34ee782a6266846836a8ad1c7a9b..fa8f61c81c6de6d3d1eb7c7bfa3a067a63d1386f 100644
--- a/solutions/RelationalRAGSolution/src/main/java/de/tudresden/inf/st/ttc19/Driver.java
+++ b/solutions/RelationalRAGSolution/src/main/java/de/tudresden/inf/st/ttc19/Driver.java
@@ -1,5 +1,6 @@
 package de.tudresden.inf.st.ttc19;
 
+import de.tudresden.inf.st.ttc19.jastadd.model.BDD;
 import de.tudresden.inf.st.ttc19.jastadd.model.BDT;
 import de.tudresden.inf.st.ttc19.jastadd.model.TruthTable;
 import de.tudresden.inf.st.ttc19.parser.TruthTableParser;
@@ -11,19 +12,116 @@ import java.io.FileInputStream;
 import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Paths;
+import java.util.Arrays;
 
 public class Driver {
 
   private static String RunIndex;
   private static String Model;
   private static String Tool;
+  private static String Computation;
+  private static String PortOrderType;
   private static long stopwatch;
+  private static SolutionHandler solutionHandler;
   private static TruthTable truthTable;
   private static String ModelPath;
 
   private static Logger logger = LogManager.getLogger(Driver.class);
 
+  private static abstract class SolutionHandler {
+    void computeSolution(TruthTable tt) {
+      stopwatch = System.nanoTime();
+      computeSolution0(tt);
+      stopwatch = System.nanoTime() - stopwatch;
+      report(BenchmarkPhase.Run);
+    }
+
+    protected abstract void computeSolution0(TruthTable tt);
+
+    void writeResult() throws IOException {
+      String result = getResultAsString();
+      try (BufferedWriter writer = Files.newBufferedWriter(Paths.get("output.xmi"))) {
+        writer.write(result);
+      }
+    }
+
+    protected abstract String getResultAsString();
+  }
+
+  private static class BDTSolutionHandler extends SolutionHandler {
+
+    BDT lastResult;
+
+    @Override
+    protected void computeSolution0(TruthTable tt) {
+      switch (Computation) {
+        case "simple":
+          lastResult = tt.simpleBDT();
+          break;
+        case "case":
+          lastResult = tt.caseBDT();
+          break;
+        default:
+          System.err.println("Invalid computation type for BDT: " + Computation);
+      }
+    }
+
+    @Override
+    protected String getResultAsString() {
+      StringBuilder sb = new StringBuilder();
+      lastResult.writeBDT(sb);
+      return sb.toString();
+    }
+  }
+
+  private static class BDDSolutionHandler extends SolutionHandler {
+
+    BDD lastResult;
+
+    @Override
+    protected void computeSolution0(TruthTable tt) {
+      switch (Computation) {
+        case "case":
+          lastResult = tt.caseBDD();
+          break;
+        case "reduction":
+          lastResult = tt.reductionOBDD();
+          break;
+        default:
+          System.err.println("Invalid computation type for BDD: " + Computation);
+      }
+    }
+
+    @Override
+    protected String getResultAsString() {
+      StringBuilder sb = new StringBuilder();
+      lastResult.writeBDD(sb);
+      return sb.toString();
+    }
+  }
+
   public static void main(String[] args) {
+    if (args.length != 3) {
+      System.err.println("Usage: java -jar Driver RESULT_TYPE COMPUTATION PORT_ORDER");
+      System.err.println("RESULT_TYPE = bdd|bdt");
+      System.err.println("COMPUTATION for bdt: simple|case. for bdd: case|reduction");
+      System.err.println("PORT_ORDER = natural|heuristic");
+      System.exit(1);
+    }
+    args = Arrays.stream(args).map(String::toLowerCase).toArray(String[]::new);
+    switch (args[0]) {
+      case "bdt":
+        solutionHandler = new BDTSolutionHandler();
+        break;
+      case "bdd":
+        solutionHandler = new BDDSolutionHandler();
+        break;
+      default:
+        System.err.println("Invalid result type: " + args[0]);
+        System.exit(1);
+    }
+    Computation = args[1];
+    PortOrderType = args[2];
     try {
       initialize();
       load();
@@ -39,6 +137,17 @@ public class Driver {
     try (final FileInputStream stream = new FileInputStream(ModelPath)) {
 
       truthTable = new TruthTableParser().parse(stream);
+      switch (PortOrderType) {
+        case "natural":
+          truthTable.setPortOrder(truthTable.getNaturalPortOrder());
+          break;
+        case "heuristic":
+          truthTable.setPortOrder(truthTable.getHeuristicPortOrder());
+          break;
+        default:
+          System.err.println("Invalid port order type: " + PortOrderType);
+          System.exit(1);
+      }
     } catch (IOException e) {
       logger.error("Unable to load model from '" + ModelPath + "'", e);
     }
@@ -60,16 +169,8 @@ public class Driver {
   }
 
   private static void run() throws IOException {
-    stopwatch = System.nanoTime();
-
-    BDT solution = truthTable.caseBDT();
-    stopwatch = System.nanoTime() - stopwatch;
-    report(BenchmarkPhase.Run);
-    StringBuilder bddBuilder = new StringBuilder();
-    solution.writeBDT(bddBuilder);
-    try (BufferedWriter writer = Files.newBufferedWriter(Paths.get("output.xmi"))) {
-      writer.write(bddBuilder.toString());
-    }
+    solutionHandler.computeSolution(truthTable);
+    solutionHandler.writeResult();
   }
 
   private static void report(BenchmarkPhase phase) {
diff --git a/solutions/RelationalRAGSolution/src/test/java/de/tudresden/inf/st/ttc19/JastAddTest.java b/solutions/RelationalRAGSolution/src/test/java/de/tudresden/inf/st/ttc19/JastAddTest.java
index 63134d1912e3c517256efc3d4b38d104921d417a..0eeb36027dae5320b25c9cca3120f44b7d2c16b1 100644
--- a/solutions/RelationalRAGSolution/src/test/java/de/tudresden/inf/st/ttc19/JastAddTest.java
+++ b/solutions/RelationalRAGSolution/src/test/java/de/tudresden/inf/st/ttc19/JastAddTest.java
@@ -2,6 +2,7 @@ package de.tudresden.inf.st.ttc19;
 
 import de.tudresden.inf.st.ttc19.jastadd.model.BDD;
 import de.tudresden.inf.st.ttc19.jastadd.model.BDT;
+import de.tudresden.inf.st.ttc19.jastadd.model.PortOrder;
 import de.tudresden.inf.st.ttc19.jastadd.model.TruthTable;
 import de.tudresden.inf.st.ttc19.parser.TruthTableParser;
 import org.apache.logging.log4j.LogManager;
@@ -14,6 +15,7 @@ import org.junit.jupiter.params.provider.MethodSource;
 import java.io.*;
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.util.function.Function;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
@@ -109,73 +111,63 @@ class JastAddTest {
   @ParameterizedTest
   @MethodSource("truthTableFiles")
   void testSimpleBDT(String pathName) throws IOException {
-    TruthTable tt = loadTruthTable(pathName);
-    File inputFile = new File(pathName);
-
-    BDT simpleBDT = tt.simpleBDT();
-
-    StringBuilder simpleBuilder = new StringBuilder();
-    simpleBDT.writeBDT(simpleBuilder);
-
-    Path outputPath = Files.createTempFile("relrag-test-simpleBDT", ".bddmodel");
-    outputPath.toFile().deleteOnExit();
-    try (BufferedWriter writer = Files.newBufferedWriter(outputPath)) {
-      writer.write(simpleBuilder.toString());
-    }
-
-    validate(inputFile.getAbsolutePath(), outputPath.toString());
+    testBDT(pathName, "relrag-test-natural-simpleBDT", TruthTable::simpleBDT, TruthTable::getNaturalPortOrder);
+    testBDT(pathName, "relrag-test-heuristic-simpleBDT", TruthTable::simpleBDT, TruthTable::getHeuristicPortOrder);
   }
 
   @ParameterizedTest
   @MethodSource("truthTableFiles")
   void testCaseBDT(String pathName) throws IOException {
-    TruthTable tt = loadTruthTable(pathName);
-    File inputFile = new File(pathName);
-
-    BDT caseBdd = tt.caseBDT();
-
-    StringBuilder bddBuilder = new StringBuilder();
-    caseBdd.writeBDT(bddBuilder);
-    Path outputPath = Files.createTempFile("relrag-test-caseBDT", ".bddmodel");
-    outputPath.toFile().deleteOnExit();
-    try (BufferedWriter writer = Files.newBufferedWriter(outputPath)) {
-      writer.write(bddBuilder.toString());
-    }
-
-    validate(inputFile.getAbsolutePath(), outputPath.toString());
+    testBDT(pathName, "relrag-test-natural-caseBDT", TruthTable::caseBDT, TruthTable::getNaturalPortOrder);
+    testBDT(pathName, "relrag-test-heuristic-caseBDT", TruthTable::caseBDT, TruthTable::getHeuristicPortOrder);
   }
 
   @ParameterizedTest
   @MethodSource("truthTableFiles")
   void testCaseBDD(String pathName) throws IOException {
+    testBDD(pathName, "relrag-test-natural-caseBDD", TruthTable::caseBDD, TruthTable::getNaturalPortOrder);
+    testBDD(pathName, "relrag-test-heuristic-caseBDD", TruthTable::caseBDD, TruthTable::getHeuristicPortOrder);
+  }
+
+  @ParameterizedTest
+  @MethodSource("truthTableFiles")
+  void testReductionOBDD(String pathName) throws IOException {
+    testBDD(pathName, "relrag-test-natural-reductionOBDD", TruthTable::reductionOBDD, TruthTable::getNaturalPortOrder);
+    testBDD(pathName, "relrag-test-heuristic-reductionOBDD", TruthTable::reductionOBDD, TruthTable::getHeuristicPortOrder);
+  }
+
+  private void testBDT(String pathName, String outputFileName,
+                       Function<TruthTable, BDT> generate, Function<TruthTable, PortOrder> portOrder)
+      throws IOException{
     TruthTable tt = loadTruthTable(pathName);
+    tt.setPortOrder(portOrder.apply(tt));
     File inputFile = new File(pathName);
 
-    BDD caseBdd = tt.caseBDD();
+    BDT caseBdt = generate.apply(tt);
 
-    StringBuilder bddBuilder = new StringBuilder();
-    caseBdd.writeBDD(bddBuilder);
-    Path outputPath = Files.createTempFile("relrag-test-caseBDD", ".bddmodel");
-    // outputPath.toFile().deleteOnExit();
+    StringBuilder bdtBuilder = new StringBuilder();
+    caseBdt.writeBDT(bdtBuilder);
+    Path outputPath = Files.createTempFile(outputFileName, ".bddmodel");
+    outputPath.toFile().deleteOnExit();
     try (BufferedWriter writer = Files.newBufferedWriter(outputPath)) {
-      writer.write(bddBuilder.toString());
+      writer.write(bdtBuilder.toString());
     }
 
-    Assertions.assertTrue(new Validator().validate(tt, caseBdd));
     validate(inputFile.getAbsolutePath(), outputPath.toString());
   }
 
-  @ParameterizedTest
-  @MethodSource("truthTableFiles")
-  void testReductionOBDD(String pathName) throws IOException {
+  private void testBDD(String pathName, String outputFileName,
+                       Function<TruthTable, BDD> generate, Function<TruthTable, PortOrder> portOrder)
+      throws IOException{
     TruthTable tt = loadTruthTable(pathName);
+    tt.setPortOrder(portOrder.apply(tt));
     File inputFile = new File(pathName);
 
-    BDD caseBdd = tt.reductionOBDD();
+    BDD caseBdd = generate.apply(tt);
 
     StringBuilder bddBuilder = new StringBuilder();
     caseBdd.writeBDD(bddBuilder);
-    Path outputPath = Files.createTempFile("relrag-test-reductionOBDD", ".bddmodel");
+    Path outputPath = Files.createTempFile(outputFileName, ".bddmodel");
     outputPath.toFile().deleteOnExit();
     try (BufferedWriter writer = Files.newBufferedWriter(outputPath)) {
       writer.write(bddBuilder.toString());