diff --git a/src/core/de.evoal.core.api/pom.xml b/src/core/de.evoal.core.api/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..0945a3481c98ccd5cb99382341e8aa3f03ebde5a
--- /dev/null
+++ b/src/core/de.evoal.core.api/pom.xml
@@ -0,0 +1,100 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+
+	<parent>
+		<groupId>de.evoal.core</groupId>
+		<artifactId>releng.parent</artifactId>
+		<version>0.9.0-SNAPSHOT</version>
+
+		<relativePath>../de.evoal.core.releng.parent</relativePath>
+	</parent>
+
+	<artifactId>core.api</artifactId>
+	<name>EvoAl - Core - API</name>
+
+	<dependencies>
+		<!-- Include dependencies of EvoAl platform -->
+		<!-- CDI APIs -->
+		<dependency>
+			<groupId>jakarta.enterprise</groupId>
+			<artifactId>jakarta.enterprise.cdi-api</artifactId>
+			<scope>provided</scope>
+		</dependency>
+
+		<!-- JSON API -->
+		<dependency>
+			<groupId>com.fasterxml.jackson.core</groupId>
+			<artifactId>jackson-databind</artifactId>
+			<version>${jackson.version}</version>
+		</dependency>
+
+		<!-- Logging API -->
+		<dependency>
+			<groupId>org.slf4j</groupId>
+			<artifactId>slf4j-api</artifactId>
+			<scope>provided</scope>
+		</dependency>
+
+		<dependency>
+			<groupId>org.apache.deltaspike.core</groupId>
+			<artifactId>deltaspike-core-api</artifactId>
+			<version>${deltaspike.version}</version>
+		</dependency>
+
+		<!-- TODO DO we want this dependency here? -->
+		<dependency>
+			<groupId>io.jenetics</groupId>
+			<artifactId>jenetics</artifactId>
+			<version>${jenetics.version}</version>
+		</dependency>
+
+		<dependency>
+			<groupId>de.evoal.languages</groupId>
+			<artifactId>de.evoal.languages.model.dl</artifactId>
+			<version>${evoal.languages.version}</version>
+			<scope>provided</scope>
+		</dependency>
+
+		<dependency>
+			<groupId>de.evoal.languages</groupId>
+			<artifactId>de.evoal.languages.model.instance</artifactId>
+			<version>${evoal.languages.version}</version>
+			<scope>provided</scope>
+		</dependency>
+
+		<dependency>
+			<groupId>de.evoal.languages</groupId>
+			<artifactId>de.evoal.languages.model.el</artifactId>
+			<version>${evoal.languages.version}</version>
+			<scope>provided</scope>
+		</dependency>
+
+		<dependency>
+			<groupId>org.eclipse.emf</groupId>
+			<artifactId>org.eclipse.emf.common</artifactId>
+			<scope>provided</scope>
+		</dependency>
+
+		<dependency>
+			<groupId>org.eclipse.emf</groupId>
+			<artifactId>org.eclipse.emf.ecore</artifactId>
+			<scope>provided</scope>
+		</dependency>
+
+
+		<!-- Math stuff -->
+		<dependency>
+			<groupId>org.apache.commons</groupId>
+			<artifactId>commons-math3</artifactId>
+			<version>3.6.1</version>
+		</dependency>
+
+		<dependency>
+			<groupId>com.github.haifengl</groupId>
+			<artifactId>smile-math</artifactId>
+			<version>${smile.version}</version>
+		</dependency>
+	</dependencies>
+</project>
diff --git a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/board/Blackboard.java b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/board/Blackboard.java
new file mode 100644
index 0000000000000000000000000000000000000000..0bf4d944e3e52a8d7fa8b77b849cd98c607fb867
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/board/Blackboard.java
@@ -0,0 +1,111 @@
+package de.evoal.core.api.board;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.event.Event;
+
+import lombok.NonNull;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.inject.Inject;
+import java.util.EnumMap;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * The blackboard is a large map of {@link BlackboardEntry} to arbitrary objects.
+ * For each entry change the blackboard will fire an event parametrized with the
+ * entry that was changed. The board is application-scoped to allow every one to
+ * access it if necessary.
+ */
+@Slf4j
+@ApplicationScoped
+public class Blackboard {
+
+    /**
+     * The internal map.
+     */
+    private final Map<String, Object> board = new HashMap<>();
+
+    /**
+     * Means to fire events if necessary.
+     */
+    @Inject
+    private Event<BlackboardEntry> entryEvent;
+
+    /**
+     * Setup a clean blackboard
+     */
+    public Blackboard() {
+        board.put("EVALUATION", "none");
+    }
+
+    /**
+     * Fetches a value from the board.
+     *
+     * @param entry The element to fetch.
+     * @param <T> The element's type.
+     * @return The stored object.
+     *
+     * @throws IllegalStateException iff the entry is {@code null}.
+     */
+    public <T> @NonNull T get(final BlackboardEntry entry) {
+        return get(entry.getLabel());
+    }
+
+    /**
+     * Fetches a value from the board.
+     *
+     * @param entry The element to fetch.
+     * @param <T> The element's type.
+     * @return The stored object.
+     *
+     * @throws IllegalStateException iff the entry is {@code null}.
+     */
+    public <T> @NonNull T get(final String entry) {
+        final T value = (T) board.get(entry);
+
+        if(value == null) {
+            throw new IllegalStateException("Value of " + entry + " is null.");
+        }
+
+        return value;
+    }
+
+    /**
+     * Binds an entry to a new value. A call to this function will trigger an
+     * CDI event with the passed {@code entry} to inform consumers of that
+     * entry.
+     *
+     * @param entry The entry to bind.
+     * @param element The element to bind.
+     */
+    public void bind(final String entry, final Object element) {
+        log.info("Binding entry {} to {}.", entry, element);
+
+        board.put(entry.toString(), element);
+        entryEvent.fire(BlackboardEntry.of(entry));
+    }
+
+    /**
+     * Parses all arguments from the passed command line arguments.
+     *
+     * @param args The command line arguments.
+     */
+    public void readArguments(final String[] args) {
+        for(String arg : args) {
+            if(!arg.startsWith("-B")) {
+                continue;
+            }
+
+            log.info("Setting blackboard entry from argument: '{}'.", arg);
+
+            arg = arg.substring(2);
+            final int colonIndex = arg.indexOf('=');
+
+            final String entry = arg.substring(0, colonIndex);
+            final String value = arg.substring(colonIndex + 1);
+
+            bind(entry, value);
+        }
+    }
+}
diff --git a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/board/BlackboardEntry.java b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/board/BlackboardEntry.java
new file mode 100644
index 0000000000000000000000000000000000000000..fa81233b3d83a16ddd6bd55966f8803a601ab1a4
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/board/BlackboardEntry.java
@@ -0,0 +1,100 @@
+package de.evoal.core.api.board;
+
+public final class BlackboardEntry {
+
+    public static final String TARGET_PROPERTIES = "TARGET_PROPERTIES";
+    public static final String TARGET_PROPERTIES_SOURCE = "TARGET_PROPERTIES_SOURCE";
+
+    /**
+     * Folder containing the constraint validation models.
+     */
+    public static final String CONSTRAINT_VALIDATION_FOLDER = "CONSTRAINT_VALIDATION_FOLDER";
+
+    /**
+     * Chooses the evaluation kind.
+     */
+    public static final String EVALUATION = "EVALUATION";
+
+    /**
+     * Number of evaluation runs.
+     */
+    public static final String EVALUATION_ITERATIONS = "EVALUATION_ITERATIONS";
+
+    /**
+     * The evaluation run number.
+     */
+    public static final String EVALUATION_RUN = "EVALUATION_RUN";
+
+    /**
+     * The actual output folder for the evaluation.
+     */
+    public static final String EVALUATION_OUTPUT_FOLDER = "EVALUATION_OUTPUT_FOLDER";
+
+    /**
+     * Configuration file containing the configuration fot the standard fitness function.
+     */
+    public static final String FITNESS_STANDARD_FUNCTION_FILE = "FITNESS_STANDARD_FUNCTION_FILE";
+
+    /**
+     * The heuristic configuration.
+     */
+    public static final String EA_CONFIGURATION = "EA_CONFIGURATION";
+
+    /**
+     * The file containing the ea configuration.
+     */
+    public static final String EA_CONFIGURATION_FILE = "EA_CONFIGURATION_FILE";
+
+    /**
+     * File containing the machine learning file.
+     */
+    public static final String MACHINE_LEARNING_FILE = "MACHINE_LEARNING_FILE";
+
+    /**
+     * Name of the main to run.
+     */
+    public static final String MAIN = "core:main";
+
+    /**
+     * The trained predictive function
+     */
+    public static final String PREDICTIVE_FUNCTION = "PREDICTIVE_FUNCTION";
+
+    /**
+     * The predictive configuration to use
+     */
+    public static final String PREDICTIVE_FUNCTION_CONFIGURATION = "PREDICTIVE_FUNCTION_CONFIGURATION";
+
+    /**
+     * File containing the predictive function file.
+     */
+    public static final String PREDICTIVE_FUNCTION_FILE = "PREDICTIVE_FUNCTION_FILE";
+
+    /**
+     * Targets.
+     */
+    public static final String TARGET_POINTS = "TARGET_POINTS";
+
+    /**
+     * File containing targets for evaluation.
+     */
+    public static final String TARGETS_FILE = "TARGETS_FILE";
+
+    /**
+     * File containing the training points.
+     */
+    public static final String TRAINING_POINT_FILE = "TRAINING_POINT_FILE";
+    private final String label;
+
+    private BlackboardEntry(final String label) {
+        this.label = label;
+    }
+
+    public String getLabel() {
+        return label;
+    }
+
+    public static BlackboardEntry of(final String label) {
+        return new BlackboardEntry(label);
+    }
+}
diff --git a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/board/package-info.java b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/board/package-info.java
new file mode 100644
index 0000000000000000000000000000000000000000..33f1fc58b1c9504a52e4915fdba07565977b7435
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/board/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * The blackboard used to exchange data between different parts of the system.
+ */
+package de.evoal.core.api.board;
\ No newline at end of file
diff --git a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/cdi/BeanFactory.java b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/cdi/BeanFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..f7b90f120d4dde3fbaa37e2c66aa561d22c9d80c
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/cdi/BeanFactory.java
@@ -0,0 +1,63 @@
+package de.evoal.core.api.cdi;
+
+import de.evoal.core.api.utils.Requirements;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.deltaspike.core.api.provider.BeanProvider;
+
+import javax.enterprise.inject.spi.Bean;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * Deltaspike wrapper for reducing dependencies in extension.
+ */
+@Slf4j
+public final class BeanFactory {
+    private BeanFactory() {
+    }
+
+    public static <T> T create(final Class<T> type) {
+        Requirements.requireNotNull(type);
+
+        log.info("Creating bean of type {}.", type);
+        try {
+            return BeanProvider.getContextualReference(type);
+        } catch(final IllegalStateException e) {
+            log.error("Failed to create contextual reference of type '{}'.", type);
+            final Set<Bean<T>> beans = BeanProvider.getBeanDefinitions(type, true, true);
+
+            final String existingBeans = beans.stream().map(Bean::getName).collect(Collectors.joining(", "));
+            log.error("  existing beans are: {}", existingBeans);
+
+            throw e;
+        }
+    }
+
+    /**
+     * Returns an instance of the given {@code type} and the given {@code name}.
+     * If necessary, the instance is created.
+     *
+     * @param name Name of the instance.
+     * @param type Type of the instance
+     * @param <T> The actual type
+     * @return A valid instance
+     */
+    public static <T> T create(final String name, final Class<T> type) {
+        Requirements.requireNotNull(name);
+        Requirements.requireNotNull(type);
+
+        log.info("Creating bean of type {} with name {}.", type, name);
+
+        try {
+            return BeanProvider.getContextualReference(name, false, type);
+        } catch(final IllegalStateException e) {
+            log.error("Failed to create contextual reference of type '{}' with name '{}'.", type, name);
+            final Set<Bean<T>> beans = BeanProvider.getBeanDefinitions(type, true, true);
+
+            final String existingBeans = beans.stream().map(Bean::getName).collect(Collectors.joining(", "));
+            log.error("  existing beans are: {}", existingBeans);
+
+            throw e;
+        }
+    }
+}
diff --git a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/cdi/BlackboardValue.java b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/cdi/BlackboardValue.java
new file mode 100644
index 0000000000000000000000000000000000000000..4fe58e33e180663553e00501f0d860311cf78f33
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/cdi/BlackboardValue.java
@@ -0,0 +1,22 @@
+package de.evoal.core.api.cdi;
+
+import de.evoal.core.api.board.BlackboardEntry;
+
+import javax.enterprise.util.Nonbinding;
+
+import javax.inject.Qualifier;
+import java.lang.annotation.*;
+
+/**
+ * Annotation to let the framework inject an entry from the blackboard.
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Qualifier
+@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
+public @interface BlackboardValue {
+    /**
+     * @return The entry to inject.
+     */
+    public @Nonbinding String value();
+}
diff --git a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/cdi/ConfigurationValue.java b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/cdi/ConfigurationValue.java
new file mode 100644
index 0000000000000000000000000000000000000000..38e2d7c927092e728e806723b291bdb4c7ea8985
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/cdi/ConfigurationValue.java
@@ -0,0 +1,41 @@
+package de.evoal.core.api.cdi;
+
+import de.evoal.core.api.board.BlackboardEntry;
+
+import javax.enterprise.util.Nonbinding;
+
+import javax.inject.Qualifier;
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Annotation for injecting values from the configuration. You can annotate an
+ *   attribute or a parameter in a CDI life-cycle method with this annotation
+ *   to tell the framework that you want some information from a blackboard
+ *   configuration:
+ *
+ *   <pre>
+ *     @Inject
+ *     @ConfigurationValue(entry = BlackboardEntry.EA_CONFIGURATION, access = "algorithm.fitness.exponent")
+ *     private double exponent;
+ *   </pre>
+ *
+ *   This example will load the ea configuration from the blackboard and search
+ *   for the attribute {@code algorithm}. Afterwards, it looks up the attributes
+ *   {@code fitness} and {@code exponent}.
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Qualifier
+public @interface ConfigurationValue {
+    /**
+     * @return The blackboard entry to use for the lookup.
+     */
+    public String entry();
+
+    /**
+     * @return The access path.
+     */
+    public @Nonbinding String access();
+}
diff --git a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/cdi/MainClass.java b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/cdi/MainClass.java
new file mode 100644
index 0000000000000000000000000000000000000000..27cbbf65793326a5b31880b220fbdc3a841051e5
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/cdi/MainClass.java
@@ -0,0 +1,13 @@
+package de.evoal.core.api.cdi;
+
+/**
+ * Base interface for all main classes. A main class must be annotated using the
+ * {@link javax.inject.Named} annotation, which can be used on the command line
+ * to select the main class to execute.
+ */
+public interface MainClass {
+    /**
+     * Run the main.
+     */
+    public void run();
+}
diff --git a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/cdi/package-info.java b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/cdi/package-info.java
new file mode 100644
index 0000000000000000000000000000000000000000..f50f885eb9888dfdac798d743d57a98d97d78b58
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/cdi/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * All CDI-related functionality.
+ */
+package de.evoal.core.api.cdi;
\ No newline at end of file
diff --git a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/codec/CustomCodec.java b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/codec/CustomCodec.java
new file mode 100644
index 0000000000000000000000000000000000000000..fac1ddb75eb736abc32aaa157d3b98b5a5ce6491
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/codec/CustomCodec.java
@@ -0,0 +1,21 @@
+package de.evoal.core.api.ea.codec;
+
+import de.evoal.core.api.properties.Properties;
+import io.jenetics.Gene;
+import io.jenetics.Genotype;
+import io.jenetics.engine.Codec;
+
+/**
+ * A custom codec for our properties.
+ *
+ * @param <G> The gene type.
+ */
+public interface CustomCodec<G extends Gene<?, G>> extends Codec<Properties, G> {
+    /**
+     * Encodes an individual according to the codes into a genotype.
+     *
+     * @param p The individual to code.
+     * @return The generated (non-null) genotype.
+     */
+    public Genotype<G> encode(final Properties p);
+}
diff --git a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/constraints/model/Constraint.java b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/constraints/model/Constraint.java
new file mode 100644
index 0000000000000000000000000000000000000000..02154607254620aecf3aba37ead9261d32497fe7
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/constraints/model/Constraint.java
@@ -0,0 +1,52 @@
+package de.evoal.core.api.ea.constraints.model;
+
+import de.evoal.core.api.properties.Properties;
+import de.evoal.core.api.properties.PropertySpecification;
+import lombok.Data;
+
+import java.util.List;
+import java.util.function.Function;
+
+/**
+ * A single evaluable constraint. A constraint ca be applied to an individual
+ * (properties) and produces a {@link ConstraintResult} in return.
+ */
+@Data
+public class Constraint {
+    /**
+     * Type of the constraint
+     */
+    private ConstraintType constraintType;
+
+    /**
+     * Handling group for this constraint
+     */
+    private String group;
+
+    /**
+     * The applicable constraint function.
+     */
+    private Function<Properties, Double> function;
+
+    /**
+     * List of used properties.
+     */
+    private List<PropertySpecification> usedProperties;
+
+    /**
+     * Applies the constraint {@link #function} to the given individual {@code properties}.
+     *
+     * @param properties The individual to check.
+     * @return The result of the constraint's evaluation.
+     */
+    public ConstraintResult apply(final Properties properties) {
+        final ConstraintResult result = new ConstraintResult();
+
+        result.setConstraint(this);
+        result.setComparisonDifference(function.apply(properties));
+        result.getUsedProperties().addAll(usedProperties);
+        result.setType(getConstraintType());
+
+        return result;
+    }
+}
diff --git a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/constraints/model/ConstraintResult.java b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/constraints/model/ConstraintResult.java
new file mode 100644
index 0000000000000000000000000000000000000000..af43503062aeec3e5fb0249957816daab9dd1477
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/constraints/model/ConstraintResult.java
@@ -0,0 +1,33 @@
+package de.evoal.core.api.ea.constraints.model;
+
+import de.evoal.core.api.properties.PropertySpecification;
+import lombok.Data;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * The result of a constraint comparison.
+ */
+@Data
+public class ConstraintResult {
+    /**
+     * The applied constraint.
+     */
+    private Constraint constraint;
+
+    /**
+     * Type of the constraint.
+     */
+    private ConstraintType type;
+
+    /**
+     * The calculated difference.
+     */
+    private double comparisonDifference = 0.0;
+
+    /**
+     * A list of used properties to calculate the constraint result.
+     */
+    private final List<PropertySpecification> usedProperties = new ArrayList<>();
+}
diff --git a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/constraints/model/ConstraintType.java b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/constraints/model/ConstraintType.java
new file mode 100644
index 0000000000000000000000000000000000000000..3ed3568a2d911de0ddeba80054377d8b4d1f31c8
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/constraints/model/ConstraintType.java
@@ -0,0 +1,10 @@
+package de.evoal.core.api.ea.constraints.model;
+
+/**
+ * Type of the constraint. A constraint can either be an equality constraint
+ *   or an inequality constraint.
+ */
+public enum ConstraintType {
+    Equality,
+    Inequality
+}
diff --git a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/constraints/model/Constraints.java b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/constraints/model/Constraints.java
new file mode 100644
index 0000000000000000000000000000000000000000..9f33b621be70f558e9bd539b1c43afcd9d472974
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/constraints/model/Constraints.java
@@ -0,0 +1,33 @@
+package de.evoal.core.api.ea.constraints.model;
+
+import de.evoal.core.api.properties.Properties;
+import javax.enterprise.inject.Vetoed;
+
+import lombok.Data;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * A collection of constraints that are applicable to an individual.
+ */
+@Data @Vetoed
+public class Constraints {
+    /**
+     * The actual list of constraints.
+     */
+    private final List<Constraint> constraints = new ArrayList<>();
+
+    /**
+     * Applies the constraints to the given properties and produces the results.
+     *
+     * @param properties Properties to use
+     * @return A non-null list of constraint results.
+     */
+    public List<ConstraintResult> apply(final Properties properties) {
+        return constraints.stream()
+                .map(c -> c.apply(properties))
+                .collect(Collectors.toList());
+    }
+}
diff --git a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/constraints/model/package-info.java b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/constraints/model/package-info.java
new file mode 100644
index 0000000000000000000000000000000000000000..31b616e2623cae00c5072441414b7a0b35d99250
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/constraints/model/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * The constraint model that can be used by implementing extensions.
+ */
+package de.evoal.core.api.ea.constraints.model;
\ No newline at end of file
diff --git a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/constraints/package-info.java b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/constraints/package-info.java
new file mode 100644
index 0000000000000000000000000000000000000000..77b586b44bffab64e59bd74a25afd22b9bd55dc2
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/constraints/package-info.java
@@ -0,0 +1,5 @@
+/**
+ * This package contains everything that has to do with constraints of
+ *   genotypes or individuals.
+ */
+package de.evoal.core.api.ea.constraints;
\ No newline at end of file
diff --git a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/constraints/strategies/CalculationResult.java b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/constraints/strategies/CalculationResult.java
new file mode 100644
index 0000000000000000000000000000000000000000..2c72effcd0d5a723b4fbebc0896b1918397559e9
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/constraints/strategies/CalculationResult.java
@@ -0,0 +1,42 @@
+package de.evoal.core.api.ea.constraints.strategies;
+
+import de.evoal.core.api.ea.constraints.model.ConstraintResult;
+import lombok.Data;
+
+/**
+ * The calculation result checks if the applied constraint was successful or
+ * not.
+ */
+@Data
+public class CalculationResult {
+    /**
+     * The final result of the constraint evaluation.
+     */
+    private final ConstraintResult result;
+
+    /**
+     * If the evaluation is successful.
+     */
+    private final boolean successful;
+
+    public CalculationResult(final ConstraintResult result) {
+        this.result = result;
+        this.successful = isSuccessful(result);
+    }
+
+    /**
+     * Was the application successful?
+     */
+    public static boolean isSuccessful(final ConstraintResult result) {
+        switch (result.getType()) {
+            case Equality:
+                return result.getComparisonDifference() == 0.0;
+
+            case Inequality:
+                return result.getComparisonDifference() > 0.0;
+
+            default:
+                throw new IllegalStateException("Unhandled constraint type: " + result.getType());
+        }
+    }
+}
diff --git a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/constraints/strategies/HandlingStrategy.java b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/constraints/strategies/HandlingStrategy.java
new file mode 100644
index 0000000000000000000000000000000000000000..3a0687c18a99c947255ec7a360d0fbca6ca18145
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/constraints/strategies/HandlingStrategy.java
@@ -0,0 +1,8 @@
+package de.evoal.core.api.ea.constraints.strategies;
+
+/**
+ * A constraint handling strategy. The actual implementation decides what to do with
+ *   the {@link CalculationResult}.
+ */
+public interface HandlingStrategy {
+}
diff --git a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/constraints/strategies/fitness/MalusForFitnessStrategy.java b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/constraints/strategies/fitness/MalusForFitnessStrategy.java
new file mode 100644
index 0000000000000000000000000000000000000000..8da60569df1af67c5502bb65bf7449563a044392
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/constraints/strategies/fitness/MalusForFitnessStrategy.java
@@ -0,0 +1,47 @@
+package de.evoal.core.api.ea.constraints.strategies.fitness;
+
+import de.evoal.core.api.ea.constraints.strategies.HandlingStrategy;
+import de.evoal.core.api.ea.constraints.strategies.fitness.internal.ChainFunction;
+import de.evoal.core.api.ea.constraints.strategies.fitness.internal.IdentityFunction;
+import de.evoal.core.api.properties.Properties;
+
+/**
+ * Class for applying the configured malus functions to given properties candidate.
+ */
+public class MalusForFitnessStrategy implements HandlingStrategy {
+    private final MalusFunction[] malusConversions;
+
+    /**
+     * Constructor of the class.
+     * @param size Number of malus functions to apply by this strategy.
+     */
+    public MalusForFitnessStrategy(final int size) {
+        malusConversions = new MalusFunction[size];
+
+        for(int index = 0; index < size; ++index) {
+            malusConversions[index] = new IdentityFunction();
+        }
+    }
+
+    /**
+     * Adds a {@code MalusFunction} for the given property index.
+     *
+     * @param propertyIndex Index of the property.
+     * @param malusFunction The {@code MalusFunction} to apply
+     */
+    public void add(final int propertyIndex, final MalusFunction malusFunction) {
+        malusConversions[propertyIndex] = new ChainFunction(malusConversions[propertyIndex], malusFunction);
+    }
+
+    /**
+     * Applies the malus functions.
+     *
+     * @param candidate The individual.
+     * @param fitnessValues The calculated fitness values.
+     */
+    public void apply(final Properties candidate, double[] fitnessValues) {
+        for(int index = 0; index < fitnessValues.length; ++index) {
+            fitnessValues[index] = malusConversions[index].apply(candidate, fitnessValues[index]);
+        }
+    }
+}
diff --git a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/constraints/strategies/fitness/MalusFunction.java b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/constraints/strategies/fitness/MalusFunction.java
new file mode 100644
index 0000000000000000000000000000000000000000..d1d78bd6d8ecfad32450ef6cd2bbaec320a88a6b
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/constraints/strategies/fitness/MalusFunction.java
@@ -0,0 +1,18 @@
+package de.evoal.core.api.ea.constraints.strategies.fitness;
+
+import de.evoal.core.api.properties.Properties;
+
+/**
+ * Base interface for a malus function.
+ */
+@FunctionalInterface
+public interface MalusFunction {
+    /**
+     * Applies the malus function and calculates the adjusted fitness value.
+     *
+     * @param properties The individual.
+     * @param fitnessValue The current fitness value.
+     * @return The adapted fitness value.
+     */
+    public double apply(final Properties properties, final double fitnessValue);
+}
diff --git a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/constraints/strategies/fitness/internal/ChainFunction.java b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/constraints/strategies/fitness/internal/ChainFunction.java
new file mode 100644
index 0000000000000000000000000000000000000000..f16ef1f672f98499c62d30770dc3c329cfec4f29
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/constraints/strategies/fitness/internal/ChainFunction.java
@@ -0,0 +1,21 @@
+package de.evoal.core.api.ea.constraints.strategies.fitness.internal;
+
+import de.evoal.core.api.ea.constraints.strategies.fitness.MalusFunction;
+import de.evoal.core.api.properties.Properties;
+
+public class ChainFunction implements MalusFunction {
+    private final MalusFunction child;
+    private final MalusFunction strategy;
+
+    public ChainFunction(final MalusFunction child, final MalusFunction strategy) {
+        this.child = child;
+        this.strategy = strategy;
+    }
+
+    @Override
+    public double apply(final Properties properties, final double fitnessValue) {
+        double adaptedFitnessValue = child.apply(properties, fitnessValue);
+
+        return strategy.apply(properties, adaptedFitnessValue);
+    }
+}
diff --git a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/constraints/strategies/fitness/internal/IdentityFunction.java b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/constraints/strategies/fitness/internal/IdentityFunction.java
new file mode 100644
index 0000000000000000000000000000000000000000..8ca05256c3ef8af8855ce4c3beaabb38dad91b0c
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/constraints/strategies/fitness/internal/IdentityFunction.java
@@ -0,0 +1,11 @@
+package de.evoal.core.api.ea.constraints.strategies.fitness.internal;
+
+import de.evoal.core.api.ea.constraints.strategies.fitness.MalusFunction;
+import de.evoal.core.api.properties.Properties;
+
+public class IdentityFunction implements MalusFunction {
+    @Override
+    public double apply(final Properties properties, final double fitnessValue) {
+        return fitnessValue;
+    }
+}
diff --git a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/constraints/strategies/fitness/internal/package-info.java b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/constraints/strategies/fitness/internal/package-info.java
new file mode 100644
index 0000000000000000000000000000000000000000..cc59a125f9fee7dc504421da26d3cd79c5246ceb
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/constraints/strategies/fitness/internal/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Internal classes that are not inteded for usage by clients.
+ */
+package de.evoal.core.api.ea.constraints.strategies.fitness.internal;
\ No newline at end of file
diff --git a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/constraints/strategies/fitness/package-info.java b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/constraints/strategies/fitness/package-info.java
new file mode 100644
index 0000000000000000000000000000000000000000..9ead63b4869bf58610ae0ebfec29bbef32124180
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/constraints/strategies/fitness/package-info.java
@@ -0,0 +1,7 @@
+/**
+ * The malus for fitness strategy applies a malus function to the fitness value
+ *   that may take the constraint result into consideration. The general idea of
+ *   this strategy is to reduce the fitness based on the calculated constraint
+ *   difference.
+ */
+package de.evoal.core.api.ea.constraints.strategies.fitness;
\ No newline at end of file
diff --git a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/fitness/FitnessBase.java b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/fitness/FitnessBase.java
new file mode 100644
index 0000000000000000000000000000000000000000..1f562237f6bcd94889dfdecac12b538cb7b2fd8c
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/fitness/FitnessBase.java
@@ -0,0 +1,57 @@
+package de.evoal.core.api.ea.fitness;
+
+import de.evoal.core.api.ea.constraints.strategies.fitness.MalusForFitnessStrategy;
+import de.evoal.core.api.ea.fitness.type.FitnessConverter;
+import de.evoal.core.api.board.BlackboardEntry;
+import de.evoal.core.api.cdi.BlackboardValue;
+import de.evoal.core.api.ea.fitness.type.FitnessType;
+import de.evoal.core.api.properties.Properties;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+/**
+ * Base class for fitness functions that allows manipulating the calculated fitness
+ *   values (in case of multi-optimization problems) based on, e.g., constraint
+ *   violations.
+ */
+public abstract class FitnessBase implements FitnessEvaluator {
+    @Inject @Named("depending")
+    private FitnessConverter converter;
+
+    @Inject
+    private MalusForFitnessStrategy malus;
+
+    /**
+     * The surrogate function used.
+     */
+    //@Inject
+    // TODO protected SurrogateFunction surrogate;
+
+    /**
+     * The property values we are looking for.
+     */
+    @Inject
+    @BlackboardValue(BlackboardEntry.TARGET_PROPERTIES)
+    protected Properties targetVector;
+
+    /**
+     * The actual fitness function we are wrapping.
+     */
+    protected abstract double [] _fitness(final Properties candidate);
+
+    /**
+     * Calculates the fitness of the given candidate.
+     *
+     * @param candidate The possible candidate individual.
+     * @return The calculated fitness value.
+     */
+    @Override
+    public final FitnessType evaluate(final Properties candidate) {
+        final double [] fitnessValues = _fitness(candidate);
+
+        malus.apply(candidate, fitnessValues);
+
+        return converter.convert(fitnessValues);
+    }
+}
diff --git a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/fitness/FitnessEvaluator.java b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/fitness/FitnessEvaluator.java
new file mode 100644
index 0000000000000000000000000000000000000000..1f234b10dd2204b70df24976048dada47290d95b
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/fitness/FitnessEvaluator.java
@@ -0,0 +1,23 @@
+package de.evoal.core.api.ea.fitness;
+
+import de.evoal.core.api.ea.fitness.type.FitnessType;
+import de.evoal.core.api.properties.Properties;
+
+import java.util.function.Function;
+
+/**
+ * A fitness evaluator calculates the fitness for a given individual.
+ */
+public interface FitnessEvaluator extends Function<Properties, FitnessType> {
+    /**
+     * Calculates the fitness value of the given individual.
+     */
+    public FitnessType evaluate(final Properties individual);
+
+    /**
+     * See {@link #evaluate(Properties)}.
+     */
+    default FitnessType apply(final Properties individual) {
+        return evaluate(individual);
+    }
+}
diff --git a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/fitness/package-info.java b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/fitness/package-info.java
new file mode 100644
index 0000000000000000000000000000000000000000..0a81b12d924f5f6638ea7aaea5bc043899b451de
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/fitness/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * API package for fitness calculators.
+ */
+package de.evoal.core.api.ea.fitness;
\ No newline at end of file
diff --git a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/fitness/type/FitnessConverter.java b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/fitness/type/FitnessConverter.java
new file mode 100644
index 0000000000000000000000000000000000000000..2cd6d599bf462c1b7a5ae292eb0b84996ffd4b97
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/fitness/type/FitnessConverter.java
@@ -0,0 +1,14 @@
+package de.evoal.core.api.ea.fitness.type;
+
+/**
+ * Converter base for creating FitnessType's from distance arrays.
+ */
+public interface FitnessConverter {
+    /**
+     * Creates a fitness type instance for the given fitness values.
+     *
+     * @param fitnessValues The calculated fitness values to convert.
+     * @return The calculated FitnessType.
+     */
+    public FitnessType convert(final double [] fitnessValues);
+}
diff --git a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/fitness/type/FitnessType.java b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/fitness/type/FitnessType.java
new file mode 100644
index 0000000000000000000000000000000000000000..d3e894bfa7ca2b1b891fedb79845d2ac18b7e0f4
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/fitness/type/FitnessType.java
@@ -0,0 +1,11 @@
+package de.evoal.core.api.ea.fitness.type;
+
+/**
+ * The fitness type of the heuristic search.
+ */
+public interface FitnessType extends Comparable<FitnessType> {
+    /**
+     * @return All fitness values
+     */
+    public double[] getFitnessValues();
+}
diff --git a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/package-info.java b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/package-info.java
new file mode 100644
index 0000000000000000000000000000000000000000..a3ac75c03170a0588590326a18c540ea6b860a98
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/ea/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Base package for all classes that are related to the evolutionary algorithm.
+ */
+package de.evoal.core.api.ea;
\ No newline at end of file
diff --git a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/properties/Properties.java b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/properties/Properties.java
new file mode 100644
index 0000000000000000000000000000000000000000..ad55de2c2e3995b4136bc6e4917cd2bc8d700131
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/properties/Properties.java
@@ -0,0 +1,139 @@
+package de.evoal.core.api.properties;
+
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Objects;
+
+public class Properties {
+    private final PropertiesSpecification specification;
+
+    private final double[] values;
+
+    public Properties(final PropertiesSpecification specification) {
+        this.specification = specification;
+        this.values = new double[specification.properties.size()];
+    }
+
+    public Properties(final PropertiesSpecification specification, final double[] data) {
+        this(specification);
+
+        System.arraycopy(data, 0, this.values, 0, data.length);
+    }
+
+    public Properties(final Properties other) {
+        this(other.specification, other.values);
+    }
+
+    public static Properties create(final PropertiesSpecification spec, final Properties source) {
+        final Properties result = new Properties(spec);
+
+        for(final PropertySpecification ps : spec.getProperties()) {
+            result.put(ps, source.get(ps));
+        }
+
+        return result;
+    }
+
+    public double get(int i) {
+        return values[i];
+    }
+
+    public double get(final PropertySpecification spec) {
+        return values[specification.indexOf(spec)];
+    }
+
+    public PropertiesSpecification getSpecification() {
+        return specification;
+    }
+
+    public double[] getValues() {
+        return values;
+    }
+
+    public final double put(final PropertySpecification property, double d) {
+        final Integer index = specification.indices.get(property);
+
+        if(index == null) {
+            throw new IllegalStateException("Property is not registered.");
+        }
+
+        return put(index, d);
+    }
+
+    public final double put(final int index, double d) {
+        return values[index] = d;
+    }
+
+    public void set(final int index, final double value) {
+        values[index] = value;
+    }
+
+    public int size() {
+        return values.length;
+    }
+
+    public String toString() {
+        boolean notFirst = false;
+
+        final StringBuilder builder = new StringBuilder();
+        builder.append("<");
+
+        for(int i = 0; i < values.length; ++i) {
+            if(notFirst) {
+                builder.append(", ");
+            } else {
+                notFirst = true;
+            }
+
+            builder.append(specification.properties.get(i));
+            builder.append(" -> ");
+            builder.append(values[i]);
+        }
+
+        builder.append(">");
+
+        return builder.toString();
+    }
+
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime * result + Arrays.hashCode(values);
+		result = prime * result + Objects.hash(specification);
+		return result;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (this == obj)
+			return true;
+		if (obj == null)
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		Properties other = (Properties) obj;
+		return Objects.equals(specification, other.specification) && Arrays.equals(values, other.values);
+	}
+
+    public boolean contains(final PropertiesSpecification otherSpec) {
+        return specification.contains(otherSpec);
+    }
+
+    public Properties putAll(final Properties properties) {
+        for(final PropertySpecification spec : getSpecification().getProperties()) {
+            put(spec, properties.get(spec));
+        }
+
+        return this;
+    }
+
+
+    public Properties putAll(final Map<String, Double> values) {
+        for(final PropertySpecification spec : getSpecification().getProperties()) {
+            put(spec, values.get(spec.name()));
+        }
+
+        return this;
+    }
+}
diff --git a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/properties/PropertiesPair.java b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/properties/PropertiesPair.java
new file mode 100644
index 0000000000000000000000000000000000000000..d7c4c641489ae197b41628cb9f2edd7b0b7154af
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/properties/PropertiesPair.java
@@ -0,0 +1,16 @@
+package de.evoal.core.api.properties;
+
+import org.apache.commons.math3.util.Pair;
+
+/**
+ * A pair of properties.
+ */
+public class PropertiesPair extends Pair<Properties, Properties> {
+    public PropertiesPair(Properties properties, Properties properties2) {
+        super(properties, properties2);
+    }
+
+    public PropertiesPair(Pair<? extends Properties, ? extends Properties> entry) {
+        super(entry);
+    }
+}
diff --git a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/properties/PropertiesSpecification.java b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/properties/PropertiesSpecification.java
new file mode 100644
index 0000000000000000000000000000000000000000..3cd82ef459206dda885e79bad403ea36d2ef5a7c
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/properties/PropertiesSpecification.java
@@ -0,0 +1,117 @@
+package de.evoal.core.api.properties;
+
+import java.util.*;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+public class PropertiesSpecification {
+	public static class Builder {
+		private final Set<PropertySpecification> properties = new TreeSet<>();
+
+		public Builder() {
+		}
+
+		/*
+		public Builder add(final PropertySpecification property) {
+			properties.add(property);
+
+			return this;
+		}
+
+		public Builder add(final String propertyName) {
+			add(new PropertySpecification(propertyName));
+
+			return this;
+		}
+		*/
+
+		public Builder add(final Stream<String> names) {
+			names.forEach(n -> properties.add(new PropertySpecification(n)));
+
+			return this;
+		}
+
+		public Builder add(final PropertiesSpecification specification) {
+			properties.addAll(specification.getProperties());
+
+			return this;
+		}
+
+		public PropertiesSpecification build() {
+			return new PropertiesSpecification(properties);
+		}
+	}
+
+	Map<PropertySpecification, Integer> indices = new HashMap<>();
+
+	final List<PropertySpecification> properties;
+
+	public PropertiesSpecification(final Collection<PropertySpecification> properties) {
+		this.properties = new ArrayList<>(properties);
+
+		for(int i = 0; i < this.properties.size(); ++i) {
+			indices.put(this.properties.get(i), i);
+		}
+	}
+
+	public PropertiesSpecification(final PropertySpecification property) {
+		properties = new ArrayList<>();
+		properties.add(property);
+
+		for(int i = 0; i < properties.size(); ++i) {
+			indices.put(properties.get(i), i);
+		}
+	}
+
+	public PropertiesSpecification(final PropertiesSpecification other) {
+		this(other.properties);
+	}
+
+	public static Builder builder() {
+		return new Builder();
+	}
+
+	public boolean contains(final PropertiesSpecification spec) {
+		return spec.properties
+				.stream()
+				.allMatch(indices::containsKey);
+	}
+
+	public boolean contains(final PropertySpecification spec) {
+		return this.indices.containsKey(spec);
+	}
+
+	public List<PropertySpecification> getProperties() {
+		return Collections.unmodifiableList(properties);
+	}
+
+	public int indexOf(final PropertySpecification spec) {
+		return indices.get(spec);
+	}
+
+	public int size() {
+		return properties.size();
+	}
+
+	public String toString() {
+		return "PropertiesSpecification ["
+				+ properties
+					.stream()
+					.map(PropertySpecification::name)
+					.collect(Collectors.joining(","))
+				+ "]";
+	}
+
+	@Override
+	public boolean equals(Object o) {
+		if (this == o) return true;
+		if (o == null || getClass() != o.getClass()) return false;
+		PropertiesSpecification that = (PropertiesSpecification) o;
+		return properties.equals(that.properties);
+	}
+
+	@Override
+	public int hashCode() {
+		return Objects.hash(properties);
+	}
+}
diff --git a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/properties/PropertySpecification.java b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/properties/PropertySpecification.java
new file mode 100644
index 0000000000000000000000000000000000000000..f18a2c2c08a8e279dc513c25253dd2dc7771002c
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/properties/PropertySpecification.java
@@ -0,0 +1,33 @@
+package de.evoal.core.api.properties;
+
+import lombok.NonNull;
+
+import java.util.Objects;
+
+/**
+ * A property of the input or output domain is a simple label.
+ */
+public record PropertySpecification(@NonNull String name) implements Comparable {
+	@Override
+	public boolean equals(Object obj) {
+		if (this == obj)
+			return true;
+		if (obj == null)
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		PropertySpecification other = (PropertySpecification) obj;
+		return Objects.equals(name, other.name);
+	}
+
+
+	@Override
+	public String toString() {
+		return "PropertySpecification [name=" + name + "]";
+	}
+
+	@Override
+	public int compareTo(final Object other) {
+		return name.compareTo(((PropertySpecification)other).name());
+	}
+}
diff --git a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/properties/io/PropertiesReader.java b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/properties/io/PropertiesReader.java
new file mode 100644
index 0000000000000000000000000000000000000000..4ad4c7d44b34bb28a5db2bc330c7a6856b47e372
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/properties/io/PropertiesReader.java
@@ -0,0 +1,102 @@
+package de.evoal.core.api.properties.io;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonToken;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import de.evoal.core.api.properties.Properties;
+import de.evoal.core.api.properties.PropertiesSpecification;
+import de.evoal.core.api.utils.Requirements;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.TreeMap;
+
+@Slf4j
+public class PropertiesReader implements AutoCloseable, Iterator<Properties> {
+
+    private final JsonParser jsonParser;
+
+    public PropertiesReader(final File inputFile) throws IOException {
+        final ObjectMapper mapper = new ObjectMapper();
+        jsonParser = mapper.createParser(inputFile);
+        jsonParser.nextToken();
+        assertStartArray();
+    }
+
+    private Properties readProperties() throws IOException {
+        assertStartArray();
+
+        final Map<String, Double> entries = new TreeMap<>();
+        while(!JsonToken.END_ARRAY.equals(jsonParser.currentToken())) {
+            Requirements.requireEqual(jsonParser.currentToken(), JsonToken.START_OBJECT);
+
+            String name = null;
+            double value = 0.0;
+
+            while(!JsonToken.END_OBJECT.equals(jsonParser.currentToken())) {
+                final String fieldName = jsonParser.nextFieldName();
+
+                if("name".equals(fieldName)) {
+                    name = jsonParser.nextTextValue();
+                } else if("value".equals(fieldName)) {
+                    final JsonToken token = jsonParser.nextValue();
+                    assert(token == JsonToken.VALUE_NUMBER_FLOAT);
+                    value = jsonParser.getDoubleValue();
+                }
+            }
+            assertEndObject();
+
+            entries.put(name, value);
+        }
+
+        assertEndArray();
+
+        final PropertiesSpecification spec = PropertiesSpecification.builder()
+                                                                    .add(entries.keySet().stream())
+                                                                    .build();
+
+        return new Properties(spec).putAll(entries);
+    }
+
+    private void assertEndArray() throws IOException {
+        Requirements.requireEqual(jsonParser.currentToken(), JsonToken.END_ARRAY);
+        jsonParser.nextToken();
+    }
+
+
+    private void assertEndObject() throws IOException {
+        Requirements.requireEqual(jsonParser.currentToken(), JsonToken.END_OBJECT);
+        jsonParser.nextToken();
+    }
+
+
+    private void assertStartArray() throws IOException {
+        Requirements.requireEqual(jsonParser.currentToken(), JsonToken.START_ARRAY);
+        jsonParser.nextToken();
+    }
+
+    private void assertStartObject() throws IOException {
+        Requirements.requireEqual(jsonParser.currentToken(), JsonToken.START_OBJECT);
+        jsonParser.nextToken();
+    }
+
+    @Override
+    public void close() throws Exception {
+        jsonParser.close();
+    }
+
+    @Override
+    public boolean hasNext() {
+        return !JsonToken.END_ARRAY.equals(jsonParser.currentToken());
+    }
+
+    @Override
+    @SneakyThrows(IOException.class)
+    public Properties next() {
+        return readProperties();
+    }
+}
diff --git a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/properties/io/PropertiesWriter.java b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/properties/io/PropertiesWriter.java
index 54386ce3d46ce1fedde1e573b0d76c9ad4dbffa4..ce615e5be640652850f75d4455ddaf2c5f6c46e7 100644
--- a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/properties/io/PropertiesWriter.java
+++ b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/properties/io/PropertiesWriter.java
@@ -1,9 +1,9 @@
-package de.evoal.core.api.model.io;
+package de.evoal.core.api.properties.io;
 
 import com.fasterxml.jackson.core.JsonGenerator;
 import com.fasterxml.jackson.databind.ObjectMapper;
-import de.evoal.core.api.model.Properties;
-import de.evoal.core.api.model.PropertySpecification;
+import de.evoal.core.api.properties.Properties;
+import de.evoal.core.api.properties.PropertySpecification;
 import lombok.SneakyThrows;
 
 import java.io.File;
diff --git a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/properties/stream/FileBasedPropertiesStreamSupplier.java b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/properties/stream/FileBasedPropertiesStreamSupplier.java
new file mode 100644
index 0000000000000000000000000000000000000000..3a0e7b235a62ef884553f34ec380d2f041a4054a
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/properties/stream/FileBasedPropertiesStreamSupplier.java
@@ -0,0 +1,34 @@
+package de.evoal.core.api.properties.stream;
+
+import de.evoal.core.api.properties.io.PropertiesReader;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.File;
+import java.util.Collections;
+
+/**
+ * A simple {@see PropertiesFactory} that works on JSON-stored list of {@see Properties}.
+ */
+@Slf4j
+public class FileBasedPropertiesStreamSupplier extends PropertiesBasedPropertiesStreamSupplier {
+
+    /**
+     * Creates a new {@see PropertiesFactory} based on the given filename.
+     *
+     * @param filename The file to read.
+     */
+    public FileBasedPropertiesStreamSupplier(final File filename) {
+        super(Collections.emptyList());
+        log.info("Creating properties stream for {}.", filename);
+
+        try(final PropertiesReader reader = new PropertiesReader(filename)) {
+            while(reader.hasNext()) {
+                properties.add(reader.next());
+            }
+        } catch (final Exception e) {
+            log.error("Failed to read properties from {}.", filename, e);
+        }
+
+        log.info("Successfully fetched {} properties from  {}.", properties.size(), filename);
+    }
+}
diff --git a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/properties/stream/PropertiesBasedPropertiesPairStreamSupplier.java b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/properties/stream/PropertiesBasedPropertiesPairStreamSupplier.java
new file mode 100644
index 0000000000000000000000000000000000000000..bc3dd61f0592259a80c368ec96763a43cfac0fc0
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/properties/stream/PropertiesBasedPropertiesPairStreamSupplier.java
@@ -0,0 +1,44 @@
+package de.evoal.core.api.properties.stream;
+
+import de.evoal.core.api.properties.Properties;
+import de.evoal.core.api.properties.PropertiesPair;
+import de.evoal.core.api.properties.PropertiesSpecification;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.stream.Stream;
+
+/**
+ * A supplier for a stream of training coordinates.
+ */
+@Slf4j
+public class PropertiesBasedPropertiesPairStreamSupplier implements PropertiesPairStreamSupplier {
+    private final PropertiesStreamSupplier supplier;
+    private final PropertiesSpecification source;
+    private final PropertiesSpecification target;
+
+    public PropertiesBasedPropertiesPairStreamSupplier(final PropertiesStreamSupplier supplier, final PropertiesSpecification source, final PropertiesSpecification target) {
+        this.supplier = supplier;
+        this.source = source;
+        this.target = target;
+    }
+
+    @Override
+    public Stream<PropertiesPair> get() {
+        log.info("Creating properties pairs stream: {} -> {}", source, target);
+        final PropertiesSpecification merged = PropertiesSpecification
+                .builder()
+                .add(source)
+                .add(target)
+                .build();
+
+        return supplier.apply(merged)
+                       .map(this::toPair);
+    }
+
+    private PropertiesPair toPair(final Properties properties) {
+        return new PropertiesPair(
+                new Properties(source).putAll(properties),
+                new Properties(target).putAll(properties)
+        );
+    }
+}
diff --git a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/properties/stream/PropertiesBasedPropertiesStreamSupplier.java b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/properties/stream/PropertiesBasedPropertiesStreamSupplier.java
new file mode 100644
index 0000000000000000000000000000000000000000..f69a76b988e84834d5093bda9df4b6e400a0e8d7
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/properties/stream/PropertiesBasedPropertiesStreamSupplier.java
@@ -0,0 +1,34 @@
+package de.evoal.core.api.properties.stream;
+
+import de.evoal.core.api.properties.Properties;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Stream;
+
+/**
+ * A supplier of a stream of {@see Properties} based on a list of {@see Properties}.
+ */
+@Slf4j
+public class PropertiesBasedPropertiesStreamSupplier implements PropertiesStreamSupplier {
+    /**
+     * The raw collection to stream
+     */
+    protected final List<Properties> properties;
+
+    /**
+     * Creates a new {@see PropertiesStreamSupplier} that is based on a collection of {@see Properties} and a required
+     *   {@see PropertiesSpecification}.
+     *
+     * @param properties The collection of properties to stream.
+     */
+    public PropertiesBasedPropertiesStreamSupplier(final List<Properties> properties) {
+        this.properties = new ArrayList<>(properties);
+    }
+
+    @Override
+    public Stream<Properties> get() {
+        return properties.stream();
+    }
+}
diff --git a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/properties/stream/PropertiesPairStreamSupplier.java b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/properties/stream/PropertiesPairStreamSupplier.java
new file mode 100644
index 0000000000000000000000000000000000000000..b597aef3d198990036dcd3fd9eae01e06b652ede
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/properties/stream/PropertiesPairStreamSupplier.java
@@ -0,0 +1,14 @@
+package de.evoal.core.api.properties.stream;
+
+import de.evoal.core.api.properties.PropertiesPair;
+import de.evoal.core.api.properties.PropertiesSpecification;
+
+import java.util.function.BiFunction;
+import java.util.function.Supplier;
+import java.util.stream.Stream;
+
+/**
+ * A supplier of a stream of pairs of properties. Supplier can be reused.
+ */
+public interface PropertiesPairStreamSupplier extends Supplier<Stream<PropertiesPair>> {
+}
diff --git a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/properties/stream/PropertiesStreamSupplier.java b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/properties/stream/PropertiesStreamSupplier.java
new file mode 100644
index 0000000000000000000000000000000000000000..448ecb623fcf76e39ae33c1508bf6aed225d3810
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/properties/stream/PropertiesStreamSupplier.java
@@ -0,0 +1,18 @@
+package de.evoal.core.api.properties.stream;
+
+import de.evoal.core.api.properties.Properties;
+import de.evoal.core.api.properties.PropertiesSpecification;
+
+import java.util.function.Function;
+import java.util.function.Supplier;
+import java.util.stream.Stream;
+
+/**
+ * A supplier of a stream of properties. The supplier can be reused and can be asked for
+ *   the properties conforming to a {@link PropertiesSpecification}.
+ */
+public interface PropertiesStreamSupplier extends Supplier<Stream<Properties>>, Function<PropertiesSpecification, Stream<Properties>> {
+    default  Stream<Properties> apply(final PropertiesSpecification specification) {
+        return get().filter(p -> p.contains(specification));
+    }
+}
diff --git a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/statistics/Column.java b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/statistics/Column.java
new file mode 100644
index 0000000000000000000000000000000000000000..8c88921717efc28f8472a009e519173f13ee0b24
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/statistics/Column.java
@@ -0,0 +1,24 @@
+package de.evoal.core.api.statistics;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.Getter;
+
+/**
+ * Specification of a statistics column
+ */
+@AllArgsConstructor
+@Data
+public class Column {
+    /**
+     * Name of the column.
+     */
+    @Getter
+    private String name;
+
+    /**
+     * Type of the column.
+     */
+    @Getter
+    private ColumnType type;
+}
diff --git a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/statistics/ColumnType.java b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/statistics/ColumnType.java
new file mode 100644
index 0000000000000000000000000000000000000000..f1b8511d2e74aacb3b3946df22b93546add9c081
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/statistics/ColumnType.java
@@ -0,0 +1,11 @@
+package de.evoal.core.api.statistics;
+
+/**
+ * Possible column types.
+ */
+public enum ColumnType {
+    Double,
+    Enum,
+    Integer,
+    String,
+}
diff --git a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/statistics/StatisticsWriter.java b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/statistics/StatisticsWriter.java
new file mode 100644
index 0000000000000000000000000000000000000000..29586f7637b9fe8f22706e068461424bd725949b
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/statistics/StatisticsWriter.java
@@ -0,0 +1,33 @@
+package de.evoal.core.api.statistics;
+
+import de.evoal.core.api.ea.fitness.type.FitnessType;
+import de.evoal.languages.model.instance.Instance;
+import io.jenetics.engine.EvolutionResult;
+
+/**
+ * Evaluation-specific data writer for evaluation results. The information
+ * may be individual-, generation-, or run-specific and may be specific to
+ * a certain technique under investigation. What all writer have in common
+ * is the table-like structure of data (think of a CSV file).
+ *
+ * The framework will call {@link #init(Instance)} once before the evolutionary
+ * algorithm starts. While the EA runs, it will call {@link #add(EvolutionResult)}
+ * for each generation of individuals. When the EA terminated, the framework calls
+ * {@link #write()} once to force a serialization of the data.
+ */
+public interface StatisticsWriter {
+    /**
+     * Adds a evaluation result to the statistics.
+     */
+    public void add(final EvolutionResult<?, FitnessType> result);
+
+    /**
+     * Passes the writer configuration.
+     */
+    public StatisticsWriter init(final Instance configuration);
+
+    /**
+     * Write the statistics since the run is completed.
+     */
+    public void write();
+}
diff --git a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/statistics/Writer.java b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/statistics/Writer.java
new file mode 100644
index 0000000000000000000000000000000000000000..0a1c31895ab74ea4ca0015e9ff4880ce14f1c142
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/statistics/Writer.java
@@ -0,0 +1,25 @@
+package de.evoal.core.api.statistics;
+
+/**
+ * Base interface for all statistics writer.
+ */
+public interface Writer {
+
+    /**
+     * Writes a record.
+     *
+     * @param data An array containing all the data of the record (in the order specified).
+     * @throws WriterException Will be thrown if there is some problem while writing.
+     */
+    void addRecord(final Object[] data) throws WriterException;
+
+    /**
+     * Closes the writer.
+     */
+    void close();
+
+    /**
+     * Flushes the contents to the disk.
+     */
+    void flush();
+}
diff --git a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/statistics/WriterContext.java b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/statistics/WriterContext.java
new file mode 100644
index 0000000000000000000000000000000000000000..2b417785b384b1d78ff0526eef0a67c3e4241285
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/statistics/WriterContext.java
@@ -0,0 +1,60 @@
+package de.evoal.core.api.statistics;
+
+import javax.enterprise.context.ApplicationScoped;
+import java.util.*;
+
+/**
+ * Writer context for injecting columns into a writer.
+ */
+@ApplicationScoped
+public class WriterContext {
+    /**
+     * List of columns to prepend to a newly created writer.
+     */
+    protected List<Column> columns = new LinkedList<>();
+
+    /**
+     * Bindings of columns to their values.
+     */
+    protected Map<Column, Object> values = new HashMap<>();
+
+    /**
+     * Adds a new column to the context.
+     *
+     * @param column The column to add.
+     */
+    public void addColumn(final Column column) {
+        if(!columns.contains(column)) {
+            columns.add(column);
+        }
+    }
+
+    /**
+     * Binds a column to a value.
+     *
+     * @param column The column to bind.
+     * @param value The value to bind.
+     */
+    public void bindColumn(final Column column, final Object value) {
+        values.put(column, value);
+    }
+
+    public int size() {
+        return columns.size();
+    }
+
+    /**
+     * @return A unmodifiable list of columns.
+     */
+    public List<Column> getColumns() {
+        return Collections.unmodifiableList(columns);
+    }
+
+    /**
+     * @param column The column to lookup.
+     * @return Returns the value for the column.
+     */
+    public Object get(final Column column) {
+        return values.get(column);
+    }
+}
diff --git a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/statistics/WriterException.java b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/statistics/WriterException.java
new file mode 100644
index 0000000000000000000000000000000000000000..62f74d95c03867b8f5e29d9296ed5dd1ec1b639c
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/statistics/WriterException.java
@@ -0,0 +1,10 @@
+package de.evoal.core.api.statistics;
+
+/**
+ * Exception for signaling errors while writing.
+ */
+public class WriterException extends Exception {
+    public WriterException(final String msg, final Throwable e) {
+        super(msg, e);
+    }
+}
diff --git a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/statistics/WriterStrategy.java b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/statistics/WriterStrategy.java
new file mode 100644
index 0000000000000000000000000000000000000000..0c6a46270cf99a10a27c71cd7a52d3ce2b2b1897
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/statistics/WriterStrategy.java
@@ -0,0 +1,35 @@
+package de.evoal.core.api.statistics;
+
+import javax.inject.Inject;
+import java.util.List;
+
+/**
+ * Base class for writer strategies (different serializing backends). A strategy
+ * can decide to reuse files, to store them in different formats, and so on.
+ */
+public abstract class WriterStrategy {
+    /**
+     * Context of the writer.
+     */
+    @Inject
+    protected WriterContext context;
+
+    /**
+     * Creates a writer for the given name and the given header.
+     *
+     * @param name Name of the output.
+     * @param header Header of the output.
+     * @return A non-null writer.
+     *
+     * @throws WriterException If there is some problem with creating the writer.
+     */
+    public abstract Writer create(final String name, final List<Column> header) throws WriterException;
+
+    /**
+     * Closes the writer.
+     *
+     * @param writer The writer to close.
+     * @throws WriterException when there is an error during closing.
+     */
+    public abstract void close(Writer writer) throws WriterException;
+}
diff --git a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/statistics/package-info.java b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/statistics/package-info.java
new file mode 100644
index 0000000000000000000000000000000000000000..87bd9222827c21571fdc8c6984face331dc6e4eb
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/statistics/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * This package contains all API functionality necessary to implement
+ * custom {@link de.evoal.core.api.statistics.StatisticsWriter} and to add
+ * custom {@link de.evoal.core.api.statistics.WriterStrategy}.
+ */
+package de.evoal.core.api.statistics;
\ No newline at end of file
diff --git a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/utils/ConstantSwitch.java b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/utils/ConstantSwitch.java
new file mode 100644
index 0000000000000000000000000000000000000000..7c7fcb5b7d47c13288c692f0c7c3d07341c0c310
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/utils/ConstantSwitch.java
@@ -0,0 +1,129 @@
+package de.evoal.core.api.utils;
+
+import de.evoal.languages.model.el.*;
+import de.evoal.languages.model.el.util.ELSwitch;
+
+
+import java.util.Objects;
+
+public class ConstantSwitch extends ELSwitch<Object> {
+    private ConstantSwitch() {
+    }
+
+    @Override
+    public Object caseOrExpression(final OrExpression object) {
+        Requirements.requireSize(object.getSubExpressions(), 1);
+
+        return this.doSwitch(object.getSubExpressions().get(0));
+    }
+
+    @Override
+    public Object caseXorExpression(XorExpression object) {
+        Requirements.requireSize(object.getSubExpressions(), 1);
+
+        return this.doSwitch(object.getSubExpressions().get(0));
+    }
+
+    @Override
+    public Object caseAndExpression(AndExpression object) {
+        Requirements.requireSize(object.getSubExpressions(), 1);
+
+        return this.doSwitch(object.getSubExpressions().get(0));
+    }
+
+    @Override
+    public Object caseNotExpression(NotExpression object) {
+        return this.doSwitch(object.getOperand());
+    }
+
+    @Override
+    public Object caseComparisonExpression(ComparisonExpression object) {
+        Requirements.requireSize(object.getComparison(), 0);
+
+        return this.doSwitch(object.getLeftOperand());
+    }
+
+    @Override
+    public Object caseAddOrSubtractExpression(final AddOrSubtractExpression object) {
+        Requirements.requireSize(object.getOperators(), 0);
+
+        return this.doSwitch(object.getLeftOperand());
+    }
+
+    @Override
+    public Object caseMultiplyDivideModuloExpression(MultiplyDivideModuloExpression object) {
+        Requirements.requireSize(object.getOperators(), 0);
+
+        return this.doSwitch(object.getLeftOperand());
+    }
+
+    @Override
+    public Object casePowerOfExpression(PowerOfExpression object) {
+        Requirements.requireNull(object.getRightOperand());
+
+        return this.doSwitch(object.getLeftOperand());
+    }
+
+    @Override
+    public Object caseUnaryAddOrSubtractExpression(UnaryAddOrSubtractExpression object) {
+        Requirements.requireSize(object.getOperators(), 0);
+
+        Object Object = this.doSwitch(object.getSubExpression());
+
+        /*
+        for(final AddOrSubtractOperator aso : object.getOperators()) {
+            if(AddOrSubtractOperator.ADD.equals(aso)) {
+                continue;
+            }
+
+            if(Object instanceof Integer) {
+                Object = Math.negateExact(Object.intValue());
+            } else if(Object instanceof Double) {
+                Object = -Object.doubleValue();
+            }
+        }
+         */
+
+        return Object;
+    }
+    /*
+        @Override
+        public Object caseCallOrLiteralOrReferenceOrParantheses(CallOrLiteralOrReferenceOrParantheses object) {
+            return super.caseCallOrLiteralOrReferenceOrParantheses(object);
+        }
+    */
+
+    @Override
+    public Object caseIntegerLiteral(final IntegerLiteral object) {
+        return object.getValue();
+    }
+
+    @Override
+    public Object caseDoubleLiteral(final DoubleLiteral object) {
+        return object.getValue();
+    }
+
+    @Override
+    public Object caseStringLiteral(StringLiteral object) {
+        return object.getValue();
+    }
+
+    @Override
+    public Object caseBooleanLiteral(BooleanLiteral object) {
+        return object.isValue();
+    }
+
+    @Override
+    public Object caseCall(final Call object) {
+        throw new IllegalStateException("Searching for Object but found a call.");
+    }
+
+    @Override
+    public Object caseParantheses(Parantheses object) {
+        return this.doSwitch(object.getSubExpression());
+    }
+
+    public static Object findConstant(final Expression expression) {
+        return new ConstantSwitch().doSwitch(expression);
+    }
+}
diff --git a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/utils/LanguageHelper.java b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/utils/LanguageHelper.java
new file mode 100644
index 0000000000000000000000000000000000000000..513106d74eb9f2bce165271b1858d38048778d43
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/utils/LanguageHelper.java
@@ -0,0 +1,86 @@
+package de.evoal.core.api.utils;
+
+import de.evoal.languages.model.el.*;
+import de.evoal.languages.model.instance.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Helper class for processing eal files.
+ */
+public final class LanguageHelper {
+    /**
+     * Logger instance
+     */
+    private static final Logger log = LoggerFactory.getLogger(LanguageHelper.class);
+
+    /**
+     * Private constructor for avoiding instances of this class.
+     */
+    private LanguageHelper() {
+    }
+
+    public static <T> T lookup(final Instance instance, final String path) {
+        log.debug("Locking up '{}':", path);
+
+        final String [] parts = path.split("\\.");
+
+        Object current = instance;
+
+        for(final String part : parts) {
+            try {
+                if(!(current instanceof Instance)) {
+                    log.error("Failed to lookup part '{}' of path '{}'.", part, path);
+                    throw new IllegalStateException("EA configuration is not valid.");
+                }
+
+                boolean foundAttribute = false;
+                for(final Attribute attr : ((Instance)current).getAttributes()) {
+                    final NameOrMisc nom = attr.getName();
+
+                    if(nom instanceof Misc && ((Misc)nom).getName().equals(part)) {
+                        current =  attr.getValue();
+                        foundAttribute = true;
+                        break;
+                    } else if(nom instanceof Name && ((Name)nom).getName().getName().equals(part)) {
+                        current =  attr.getValue();
+                        foundAttribute = true;
+                        break;
+                    }
+                }
+
+                if(!foundAttribute && "name".equals(part)) {
+                    current = ((Instance)current).getName().getName();
+                    foundAttribute = true;
+                }
+
+                if(!foundAttribute) {
+                    log.error("Failed to lookup part '{}' of path '{}'. Returning null.", part, path);
+                    return null;
+                }
+            } catch(final NullPointerException e) {
+                log.error("Failed to lookup part '{}' of path '{}'.", part, path);
+                throw e;
+            }
+        }
+
+        if(current instanceof LiteralValue) {
+            Literal literal = ((LiteralValue)current).getLiteral();
+
+            if(literal instanceof StringLiteral) {
+                current = ((StringLiteral)literal).getValue();
+            } else if(literal instanceof IntegerLiteral) {
+                current = ((IntegerLiteral)literal).getValue();
+            } else if(literal instanceof DoubleLiteral) {
+                current = ((DoubleLiteral)literal).getValue();
+            } else if(literal instanceof BooleanLiteral) {
+                current = ((BooleanLiteral)literal).isValue();
+            }
+        }
+
+        log.debug("Mapping " + path + " to " + current + " of type " + current.getClass());
+
+        return (T) current;
+    }
+
+}
diff --git a/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/utils/Requirements.java b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/utils/Requirements.java
new file mode 100644
index 0000000000000000000000000000000000000000..b608b1e5aca7bf7532c8eef2c98a86c6c3c971b5
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/java/de/evoal/core/api/utils/Requirements.java
@@ -0,0 +1,225 @@
+package de.evoal.core.api.utils;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Class for checking requirements of values, e.g., of parameters.
+ */
+public final class Requirements {
+    private Requirements() {
+    }
+
+    /**
+     * Requires the value to be {@code false}.
+     *
+     * @param value Value to check.
+     * @throws IllegalArgumentException iff the passed {@code value} is {@code true}.
+     */
+    public static void requireFalse(final boolean value) {
+        if(value) {
+            throw new IllegalArgumentException("Value expected to be false.");
+        }
+    }
+
+    /**
+     * Requires the arrays to be present and of same size.
+     *
+     * @param a The first array.
+     * @param b The second array.
+     *
+     * @throws NullPointerException iff either {@code a} or {@code b} is {@code null}.
+     * @throws IllegalArgumentException iff the size of {@code a} and {@code b} differ.
+     */
+    public static void requireSameSize(final double [] a, final double [] b) {
+        Objects.requireNonNull(a, "Array is not allowed to be null");
+        Objects.requireNonNull(b, "Array is not allowed to be null");
+
+        if(a.length != b.length) {
+            throw new IllegalArgumentException("Arrays are expected to have the same size: " + a.length + " -- " + b.length);
+        }
+    }
+
+    /**
+     * Requires the collections to be present and of same size.
+     *
+     * @param a The first collection.
+     * @param b The second collection.
+     *
+     * @throws NullPointerException iff either {@code a} or {@code b} is {@code null}.
+     * @throws IllegalArgumentException iff the size of {@code a} and {@code b} differ.
+     */
+    public static void requireSameSize(final Collection<?> a, final Collection<?> b) {
+        Objects.requireNonNull(a, "Collection is not allowed to be null");
+        Objects.requireNonNull(b, "Collection is not allowed to be null");
+
+        if(a.size() != b.size()) {
+            throw new IllegalArgumentException("Collections are expected to have the same size: " + a.size() + " -- " + b.size());
+        }
+    }
+
+    /**
+     * Requires the collection {@code collection} to be present and of size {@code size}.
+     *
+     * @param collection The collection to check.
+     * @param size The required size.
+     *
+     * @throws NullPointerException iff either {@code a} or {@code b} is {@code null}.
+     * @throws IllegalArgumentException iff the size of {@code a} and {@code b} differ.
+     */
+    public static void requireSize(final Collection<?> collection, final int size) {
+        Objects.requireNonNull(collection, "Collection is not allowed to be null");
+
+        if(collection.size() != size) {
+            throw new IllegalArgumentException("Collections is expected to have size (" + size + "): " + collection.size());
+        }
+    }
+
+    /**
+     * Requires the collection {@code collection} to be present and of size {@code size}.
+     *
+     * @param collection The collection to check.
+     * @param size The required size.
+     *
+     * @throws NullPointerException iff either {@code a} or {@code b} is {@code null}.
+     * @throws IllegalArgumentException iff the size of {@code a} and {@code b} differ.
+     */
+    public static void requireSizeGreaterThean(final Collection<?> collection, final int size) {
+        Objects.requireNonNull(collection, "Collection is not allowed to be null");
+
+        if(collection.size() <= size) {
+            throw new IllegalArgumentException("Collections expected size size (" + size + ") is not met: " + collection.size());
+        }
+    }
+
+    /**
+     * Requires the collection {@code collection} to be present but empty.
+     *
+     * @param collection The collection to check.
+     *
+     * @throws NullPointerException iff {@code collection}  is {@code null}.
+     * @throws IllegalArgumentException iff the size of {@code collection} is greater than 0.
+     */
+    public static void requireEmpty(final Collection<?> collection) {
+        Objects.requireNonNull(collection, "Collection is not allowed to be null");
+
+        if(!collection.isEmpty()) {
+            throw new IllegalArgumentException("Collections is expected to have size (0): " + collection.size());
+        }
+    }
+
+    /**
+     * Requires the parameters to be equal.
+     *
+     * @param a The first value to check.
+     * @param b The second value to check.
+     *
+     * @throws IllegalArgumentException iff the values are not equal.
+     */
+    public static void requireEqual(final Object a, final Object b) {
+        if(!Objects.equals(a, b)) {
+            throw new IllegalArgumentException("Values are not equal: " + a + " != " + b);
+        }
+    }
+    /**
+     * Requires the parameters to have the same value.
+     *
+     * @param a The first value to check.
+     * @param b The second value to check.
+     *
+     * @throws IllegalArgumentException iff the values are not equal.
+     */
+    public static void requireEqual(final long a, final long b) {
+        if(a != b) {
+            throw new IllegalArgumentException("Values are not equal: " + a + " != " + b);
+        }
+    }
+
+    /**
+     * Requires the object to exist.
+     *
+     * @param object The object to check.
+     *
+     * @throws NullPointerException iff {@code object} is {@code null}.
+     */
+    public static void requireNotNull(final Object object) {
+        Objects.requireNonNull(object, "Object is not allowed to be null");
+    }
+
+    /**
+     * Requires the object to be null.
+     *
+     * @param object The object to check.
+     *
+     * @throws IllegalArgumentException iff {@code object} is not {@code null}.
+     */
+    public static void requireNull(final Object object) {
+        if(object != null) {
+            throw new IllegalArgumentException("Object is required to be null");
+        }
+    }
+
+    /**
+     * Requires {@code object} to be of type {@code type}
+     *
+     * @param object The object to check
+     * @param type The required type.
+     *
+     * @throws NullPointerException iff either {@code list} or {@code type} is {@code null}.
+     * @throws IllegalArgumentException iff the object is not of the required type.
+     */
+    private static void requireType(final Object object, final Class<?> type) {
+        Objects.requireNonNull(type, "Type is not allowed to be null");
+
+        if(!type.isAssignableFrom(object.getClass())) {
+            throw new IllegalArgumentException("Object of type " + object.getClass() + " is not assignable to type " + type.getClass());
+        }
+    }
+
+    /**
+     * Requires the object in {@code list} at {@code index} to be of type {@code type}.
+     *
+     * @param list The hosting list.
+     * @param index The index of the element to check.
+     * @param type The required type.
+     *
+     * @throws NullPointerException iff either {@code list} or {@code type} is {@code null}.
+     * @throws IllegalArgumentException iff the object is not of the required type.
+     */
+    public static void requireType(final List<Object> list, final int index, final Class<?> type) {
+        Objects.requireNonNull(list, "List is not allowed to be null");
+
+        requireType(list.get(index), type);
+    }
+
+    /**
+     * Requires the passed value to be a probability.
+     *
+     * @param value The value to check.
+     * @return The probability itself for further usage.
+     *
+     * @throws IllegalArgumentException Iff the passed value is not a probability.
+     */
+    public static double requireProbability(final double value) {
+        if(value < 0.0 || value > 0.0) {
+            throw new IllegalArgumentException("Passed value is not a probability: " + value);
+        }
+
+        return value;
+    }
+
+    /**
+     * Requires the value to be positive.
+     *
+     * @param value The value to check.
+     * @return {@code p} itself for further usage.
+     */
+    public static double nonNegative(final double value) {
+        if(value < 0.0) {
+            throw new IllegalArgumentException("Passed value is negative: " + value);
+        }
+
+        return value;
+    }
+}
diff --git a/src/core/de.evoal.core.api/src/main/java/module-info.java b/src/core/de.evoal.core.api/src/main/java/module-info.java
new file mode 100644
index 0000000000000000000000000000000000000000..c41205f1c06e6322b823d2f7690a371b6b4a355c
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/java/module-info.java
@@ -0,0 +1,38 @@
+open module de.evoal.core.api {
+    requires java.base;
+
+    requires jakarta.enterprise.cdi.api;
+    requires jakarta.inject.api;
+    requires deltaspike.core.api;
+
+    requires lombok;
+
+    requires org.slf4j;
+
+    requires io.jenetics.base;
+    requires commons.math3;
+    requires smile.math;
+
+    requires com.fasterxml.jackson.databind;
+
+    requires org.eclipse.emf.common;
+    requires org.eclipse.emf.ecore;
+
+    requires de.evoal.languages.model.dl;
+    requires de.evoal.languages.model.el;
+    requires de.evoal.languages.model.instance;
+
+    exports de.evoal.core.api.board;
+    exports de.evoal.core.api.cdi;
+    exports de.evoal.core.api.ea.codec;
+    exports de.evoal.core.api.ea.constraints.model;
+    exports de.evoal.core.api.ea.constraints.strategies;
+    exports de.evoal.core.api.ea.constraints.strategies.fitness;
+    exports de.evoal.core.api.ea.fitness;
+    exports de.evoal.core.api.ea.fitness.type;
+    exports de.evoal.core.api.properties;
+    exports de.evoal.core.api.properties.io;
+    exports de.evoal.core.api.properties.stream;
+    exports de.evoal.core.api.statistics;
+    exports de.evoal.core.api.utils;
+}
\ No newline at end of file
diff --git a/src/core/de.evoal.core.api/src/main/resources/META-INF/MANIFEST.MF b/src/core/de.evoal.core.api/src/main/resources/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000000000000000000000000000000000..348f1bdd38a493271cf17f9cb618d65ca1ef08be
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/resources/META-INF/MANIFEST.MF
@@ -0,0 +1 @@
+Manifest-Version: 1.0
\ No newline at end of file
diff --git a/src/core/de.evoal.core.api/src/main/resources/META-INF/beans.xml b/src/core/de.evoal.core.api/src/main/resources/META-INF/beans.xml
new file mode 100644
index 0000000000000000000000000000000000000000..848dca3b29cc3f1f9879d2c86d586612e5d8b3e7
--- /dev/null
+++ b/src/core/de.evoal.core.api/src/main/resources/META-INF/beans.xml
@@ -0,0 +1,6 @@
+<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd"
+       bean-discovery-mode="annotated"
+       version="2.0">
+</beans>
\ No newline at end of file
diff --git a/src/core/de.evoal.core.main/pom.xml b/src/core/de.evoal.core.main/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..57992e00fb4ddd828a37034807049236f0331f3c
--- /dev/null
+++ b/src/core/de.evoal.core.main/pom.xml
@@ -0,0 +1,283 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+
+	<parent>
+		<groupId>de.evoal.core</groupId>
+		<artifactId>releng.parent</artifactId>
+		<version>0.9.0-SNAPSHOT</version>
+
+		<relativePath>../de.evoal.core.releng.parent</relativePath>
+	</parent>
+
+	<artifactId>core.main</artifactId>
+	<name>EvoAl - Core - Main</name>
+
+	<properties>
+		<javax.activation.version>1.2.0</javax.activation.version>
+
+		<!-- DeltaSpike uses this version in its documentation. Newer version didn't work for some reasons. -->
+		<weld.version>3.1.9.Final</weld.version>
+	</properties>
+
+	<dependencies>
+		<!-- Weld for CDI (@runtime) -->
+		<dependency>
+			<groupId>org.jboss.weld.se</groupId>
+			<artifactId>weld-se-core</artifactId>
+			<version>${weld.version}</version>
+		</dependency>
+
+		<!--  Jandex results in a NPE at the moment -->
+		<dependency>
+			<groupId>org.jboss</groupId>
+			<artifactId>jandex</artifactId>
+			<version>2.4.1.Final</version>
+			<scope>runtime</scope>
+		</dependency>
+
+		<!-- logback for logging (@runtime) -->
+		<dependency>
+			<groupId>ch.qos.logback</groupId>
+			<artifactId>logback-classic</artifactId>
+			<version>1.4.0</version>
+			<scope>runtime</scope>
+		</dependency>
+
+		<!-- deltaspike -->
+		<dependency>
+			<groupId>org.apache.deltaspike.core</groupId>
+			<artifactId>deltaspike-core-api</artifactId>
+			<version>${deltaspike.version}</version>
+		</dependency>
+
+		<dependency>
+			<groupId>org.apache.deltaspike.cdictrl</groupId>
+			<artifactId>deltaspike-cdictrl-api</artifactId>
+			<version>${deltaspike.version}</version>
+		</dependency>
+
+		<dependency>
+			<groupId>org.apache.deltaspike.cdictrl</groupId>
+			<artifactId>deltaspike-cdictrl-weld</artifactId>
+			<version>${deltaspike.version}</version>
+		</dependency>
+
+		<dependency>
+			<groupId>org.apache.deltaspike.core</groupId>
+			<artifactId>deltaspike-core-impl</artifactId>
+			<version>${deltaspike.version}</version>
+			<scope>runtime</scope>
+		</dependency>
+
+		<!-- Include dependencies of parent -->
+		<!-- CDI APIs -->
+		<dependency>
+			<groupId>jakarta.enterprise</groupId>
+			<artifactId>jakarta.enterprise.cdi-api</artifactId>
+			<scope>provided</scope>
+		</dependency>
+
+		<dependency>
+			<groupId>javax.annotation</groupId>
+			<artifactId>javax.annotation-api</artifactId>
+			<scope>runtime</scope>
+		</dependency>
+
+		<!-- Logging API -->
+		<dependency>
+			<groupId>org.slf4j</groupId>
+			<artifactId>slf4j-api</artifactId>
+			<scope>compile</scope>
+		</dependency>
+
+		<!-- CSV IO -->
+		<dependency>
+			<groupId>org.apache.commons</groupId>
+			<artifactId>commons-csv</artifactId>
+			<version>1.8</version>
+		</dependency>
+
+		<dependency>
+			<groupId>${project.groupId}</groupId>
+			<artifactId>core.api</artifactId>
+		</dependency>
+<!--
+		<dependency>
+			<groupId>org.mariuszgromada.math</groupId>
+			<artifactId>MathParser.org-mXparser</artifactId>
+			<version>4.4.2</version>
+		</dependency>
+-->
+		<!-- dependencies to language models -->
+		<dependency>
+			<groupId>de.evoal.languages</groupId>
+			<artifactId>de.evoal.languages.model.ddl</artifactId>
+			<version>${evoal.languages.version}</version>
+		</dependency>
+
+		<dependency>
+			<groupId>de.evoal.languages</groupId>
+			<artifactId>de.evoal.languages.model.dl</artifactId>
+			<version>${evoal.languages.version}</version>
+		</dependency>
+
+		<dependency>
+			<groupId>de.evoal.languages</groupId>
+			<artifactId>de.evoal.languages.model.eal</artifactId>
+			<version>${evoal.languages.version}</version>
+		</dependency>
+
+		<dependency>
+			<groupId>de.evoal.languages</groupId>
+			<artifactId>de.evoal.languages.model.el</artifactId>
+			<version>${evoal.languages.version}</version>
+		</dependency>
+
+		<dependency>
+			<groupId>de.evoal.languages</groupId>
+			<artifactId>de.evoal.languages.model.instance</artifactId>
+			<version>${evoal.languages.version}</version>
+		</dependency>
+
+		<dependency>
+			<groupId>de.evoal.languages</groupId>
+			<artifactId>de.evoal.languages.model.mll</artifactId>
+			<version>${evoal.languages.version}</version>
+		</dependency>
+
+		<!-- dependencies to DSLs -->
+		<dependency>
+			<groupId>de.evoal.languages</groupId>
+			<artifactId>de.evoal.languages.model.ddl.dsl</artifactId>
+			<version>${evoal.languages.version}</version>
+			<scope>runtime</scope>
+		</dependency>
+
+		<dependency>
+			<groupId>de.evoal.languages</groupId>
+			<artifactId>de.evoal.languages.model.dl.dsl</artifactId>
+			<version>${evoal.languages.version}</version>
+		</dependency>
+
+		<dependency>
+			<groupId>de.evoal.languages</groupId>
+			<artifactId>de.evoal.languages.model.eal.dsl</artifactId>
+			<version>${evoal.languages.version}</version>
+		</dependency>
+
+		<dependency>
+			<groupId>de.evoal.languages</groupId>
+			<artifactId>de.evoal.languages.model.el.dsl</artifactId>
+			<version>${evoal.languages.version}</version>
+		</dependency>
+
+		<dependency>
+			<groupId>de.evoal.languages</groupId>
+			<artifactId>de.evoal.languages.model.instance.dsl</artifactId>
+			<version>${evoal.languages.version}</version>
+			<scope>runtime</scope>
+		</dependency>
+
+		<dependency>
+			<groupId>de.evoal.languages</groupId>
+			<artifactId>de.evoal.languages.model.mll.dsl</artifactId>
+			<version>${evoal.languages.version}</version>
+			<scope>runtime</scope>
+		</dependency>
+
+		<!-- Xtext -->
+		<dependency>
+			<groupId>org.eclipse.emf</groupId>
+			<artifactId>org.eclipse.emf.ecore</artifactId>
+			<scope>compile</scope>
+		</dependency>
+
+		<dependency>
+			<groupId>org.eclipse.emf</groupId>
+			<artifactId>org.eclipse.emf.common</artifactId>
+			<scope>compile</scope>
+		</dependency>
+
+		<dependency>
+			<groupId>org.eclipse.xtext</groupId>
+			<artifactId>org.eclipse.xtext</artifactId>
+			<scope>compile</scope>
+		</dependency>
+
+		<!-- Printing tables to the console -->
+		<!--
+		<dependency>
+			<groupId>de.vandermeer</groupId>
+			<artifactId>asciitable</artifactId>
+			<version>0.3.2</version>
+		</dependency>
+		-->
+
+		<dependency>
+			<groupId>io.jenetics</groupId>
+			<artifactId>jenetics.ext</artifactId>
+			<version>${jenetics.version}</version>
+		</dependency>
+
+		<dependency>
+			<groupId>org.decimal4j</groupId>
+			<artifactId>decimal4j</artifactId>
+			<version>1.0.3</version>
+			<scope>compile</scope>
+		</dependency>
+
+
+		<!-- XML IO -->
+		<dependency>
+			<groupId>${project.groupId}</groupId>
+			<artifactId>generator.main</artifactId>
+			<version>${project.version}</version>
+		</dependency>
+	</dependencies>
+
+	<build>
+		<plugins>
+			<plugin>
+				<artifactId>maven-dependency-plugin</artifactId>
+				<executions>
+					<execution>
+						<phase>package</phase>
+						<goals>
+							<goal>copy-dependencies</goal>
+						</goals>
+						<configuration>
+							<outputDirectory>${project.build.directory}/modules</outputDirectory>
+						</configuration>
+					</execution>
+				</executions>
+			</plugin>
+
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-jar-plugin</artifactId>
+				<configuration>
+					<archive>
+						<manifest>
+							<mainClass>de.evoal.core.main.Evoal</mainClass>
+							<addClasspath>true</addClasspath>
+							<classpathPrefix>modules/</classpathPrefix>
+						</manifest>
+					</archive>
+				</configuration>
+			</plugin>
+
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-compiler-plugin</artifactId>
+				<configuration>
+					<compilerArgs>
+						<arg>--add-exports</arg>
+						<arg>io.jenetics.base/io.jenetics.internal.math=de.evoal.core.main</arg>
+					</compilerArgs>
+				</configuration>
+			</plugin>
+		</plugins>
+	</build>
+</project>
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/Evoal.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/Evoal.java
new file mode 100644
index 0000000000000000000000000000000000000000..36da25acf27caadb7298e88598495d96c9b488a4
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/Evoal.java
@@ -0,0 +1,65 @@
+package de.evoal.core.main;
+
+import de.evoal.core.api.board.Blackboard;
+import de.evoal.core.api.board.BlackboardEntry;
+import de.evoal.core.api.cdi.MainClass;
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.inject.spi.Bean;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.deltaspike.cdise.api.CdiContainer;
+import org.apache.deltaspike.cdise.api.CdiContainerLoader;
+import org.apache.deltaspike.core.api.provider.BeanProvider;
+
+import java.util.Set;
+
+/**
+ * Main class for EvoAl. The concrete runtime behaviour depends on the used blackboard
+ *   configuration.
+ */
+@Slf4j
+public final class Evoal {
+    public static void main(final String ... args) {
+        log.info("Starting up EvoAl");
+
+        log.info("Booting CDI container");
+        final CdiContainer cdiContainer = CdiContainerLoader.getCdiContainer();
+        cdiContainer.boot();
+        cdiContainer.getContextControl().startContext(ApplicationScoped.class);
+
+        log.info("Setting up black board");
+        final Blackboard board = BeanProvider.getContextualReference(Blackboard.class);
+        board.readArguments(args);
+
+        log.info("Fetching main class and handing over control");
+        try {
+            final String mainName = board.get(BlackboardEntry.MAIN);
+            MainClass main = null;
+
+            try {
+                main = BeanProvider.getContextualReference(mainName, false, MainClass.class);
+            } catch(final Throwable e) {
+                logMainError();
+                System.exit(1);
+            }
+
+            main.run();
+        } catch (final Throwable e) {
+            log.error("Main class threw an exception.", e);
+        }
+
+        log.info("Shutting down CDI container");
+        cdiContainer.shutdown();
+    }
+
+    private static void logMainError() {
+        log.error("Name of main class was not set. Please specify the main class via command line (-BMAIN=<name>).");
+        Set<Bean<MainClass>> beans = BeanProvider.getBeanDefinitions(MainClass.class, true, true);
+        log.error("  possible names are:");
+
+        for(final Bean<MainClass> bean : beans) {
+            log.error("    {}", bean.getName());
+        }
+
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/cdi/producer/BlackboardValueProducer.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/cdi/producer/BlackboardValueProducer.java
new file mode 100644
index 0000000000000000000000000000000000000000..7b2bda9d70b0974eca43722b3f4de8b8c074ad26
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/cdi/producer/BlackboardValueProducer.java
@@ -0,0 +1,75 @@
+package de.evoal.core.main.cdi.producer;
+
+import de.evoal.core.api.cdi.BlackboardValue;
+import de.evoal.core.api.board.Blackboard;
+import de.evoal.core.api.board.BlackboardEntry;
+import de.evoal.core.api.properties.Properties;
+import de.evoal.core.api.properties.PropertiesSpecification;
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.inject.Produces;
+import javax.enterprise.inject.spi.InjectionPoint;
+
+import java.io.File;
+import java.util.Map;
+
+@ApplicationScoped
+public class BlackboardValueProducer {
+    @Produces
+    @BlackboardValue(BlackboardEntry.EA_CONFIGURATION)
+    public Integer injectIntegerValue(final InjectionPoint ip, final Blackboard board) {
+        final BlackboardValue value = ip.getAnnotated().getAnnotation(BlackboardValue.class);
+        final Object result = board.get(value.value());
+
+        if(result instanceof Number) {
+            return ((Number)result).intValue();
+        } else if(result instanceof String) {
+            return Integer.parseInt((String)result);
+        }
+
+        throw new IllegalArgumentException("Unable to handle type " + result.getClass());
+    }
+
+    @Produces
+    @BlackboardValue(BlackboardEntry.EA_CONFIGURATION)
+    public String injectStringValue(final InjectionPoint ip, final Blackboard board) {
+        final BlackboardValue value = ip.getAnnotated().getAnnotation(BlackboardValue.class);
+
+        return castValue(board.get(value.value()));
+    }
+
+    @Produces
+    @BlackboardValue(BlackboardEntry.EA_CONFIGURATION)
+    public File injectFileValue(final InjectionPoint ip, final Blackboard board) {
+        final BlackboardValue value = ip.getAnnotated().getAnnotation(BlackboardValue.class);
+
+        return castValue(board.get(value.value()));
+    }
+
+    @Produces
+    @BlackboardValue(BlackboardEntry.EA_CONFIGURATION)
+    public Map<String, Object> injectMapValue(final InjectionPoint ip, final Blackboard board) {
+        final BlackboardValue value = ip.getAnnotated().getAnnotation(BlackboardValue.class);
+
+        return castValue(board.get(value.value()));
+    }
+
+    @Produces
+    @BlackboardValue(BlackboardEntry.EA_CONFIGURATION)
+    public PropertiesSpecification injectPropertiesSpecification(final InjectionPoint ip, final Blackboard board) {
+        final BlackboardValue value = ip.getAnnotated().getAnnotation(BlackboardValue.class);
+
+        return castValue(board.get(value.value()));
+    }
+
+    @Produces
+    @BlackboardValue(BlackboardEntry.EA_CONFIGURATION)
+    public Properties injectProperties(final InjectionPoint ip, final Blackboard board) {
+        final BlackboardValue value = ip.getAnnotated().getAnnotation(BlackboardValue.class);
+
+        return castValue(board.get(value.value()));
+    }
+
+    private <T> T castValue(final Object object) {
+        return (T) object;
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/cdi/producer/DataConstraintProducer.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/cdi/producer/DataConstraintProducer.java
new file mode 100644
index 0000000000000000000000000000000000000000..b05e66bdaedc353cbf172b36aad3788c1934c098
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/cdi/producer/DataConstraintProducer.java
@@ -0,0 +1,58 @@
+package de.evoal.core.main.cdi.producer;
+
+import de.evoal.languages.model.ddl.DataDescriptionModel;
+import de.evoal.languages.model.eal.DataReference;
+import de.evoal.languages.model.eal.EAModel;
+import de.evoal.languages.model.el.Expression;
+import org.eclipse.emf.common.util.TreeIterator;
+import org.eclipse.emf.ecore.EObject;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.context.Dependent;
+import javax.enterprise.inject.Produces;
+import javax.inject.Named;
+import java.util.Collection;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.StreamSupport;
+
+@ApplicationScoped
+public class DataConstraintProducer {
+    @Produces @Dependent @Named("data-constraints")
+    public Collection<Expression> produceDataInformation(final EAModel model) {
+        final TreeIterator<EObject> iterator = model.eAllContents();
+        Iterable<EObject> iterable = () -> iterator;
+
+        // collect all expressions associated to the data definitions directly
+        Set<Expression> result = StreamSupport.stream(iterable.spliterator(), false)
+                                              .filter(DataReference.class::isInstance)
+                                              .map(DataReference.class::cast)
+                                              .map(DataReference::getDefinition)
+                                              .flatMap(d -> d.getConstraints().stream())
+                                              .collect(Collectors.toSet());
+
+        // collect all expressions associated to the files
+        final TreeIterator<EObject> iterator2 = model.eAllContents();
+        iterable = () -> iterator2;
+        StreamSupport.stream(iterable.spliterator(), false)
+                     .filter(DataReference.class::isInstance)
+                     .map(DataConstraintProducer::findModel)
+                     .filter(Objects::nonNull)
+                     .distinct()
+                     .flatMap(m -> m.getConstraints().stream())
+                     .forEach(result::add);
+
+        return result;
+    }
+
+    private static DataDescriptionModel findModel(final EObject reference) {
+        EObject current = reference;
+
+        while(current != null && !(current instanceof DataDescriptionModel)) {
+            current = current.eContainer();
+        }
+
+        return (DataDescriptionModel)current;
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/cdi/producer/EvolutionaryAlgorithmModelLoader.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/cdi/producer/EvolutionaryAlgorithmModelLoader.java
new file mode 100644
index 0000000000000000000000000000000000000000..31c00400c3e0ad4968e8a322859181f6b3d81bfe
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/cdi/producer/EvolutionaryAlgorithmModelLoader.java
@@ -0,0 +1,109 @@
+package de.evoal.core.main.cdi.producer;
+
+import com.google.inject.Injector;
+import de.evoal.core.api.board.Blackboard;
+import de.evoal.core.api.board.BlackboardEntry;
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.context.Dependent;
+import javax.enterprise.event.Observes;
+import javax.enterprise.inject.Produces;
+
+import de.evoal.languages.model.dl.dsl.DefinitionLanguageStandaloneSetup;
+import de.evoal.languages.model.eal.EAModel;
+import de.evoal.languages.model.eal.dsl.EvolutionaryAlgorithmLanguageStandaloneSetup;
+import de.evoal.languages.model.dl.impl.DlPackageImpl;
+import de.evoal.languages.model.eal.impl.EALPackageImpl;
+import de.evoal.languages.model.el.dsl.ExpressionLanguageStandaloneSetup;
+import de.evoal.languages.model.el.impl.ELPackageImpl;
+import lombok.extern.slf4j.Slf4j;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.xtext.resource.XtextResource;
+import org.eclipse.xtext.resource.XtextResourceSet;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import java.io.File;
+
+@ApplicationScoped
+@Slf4j
+public class EvolutionaryAlgorithmModelLoader {
+    @Inject
+    private Blackboard board;
+    private EAModel model;
+
+    public void load(final @Observes BlackboardEntry entry) {
+        if(!BlackboardEntry.EA_CONFIGURATION_FILE.equals(entry)) {
+            return;
+        }
+
+        final String configurationFileName = board.get(BlackboardEntry.EA_CONFIGURATION_FILE);
+        log.info("Loading evolutionary algorithm configuration from {}.",  configurationFileName);
+
+        final File configurationFile = new File(configurationFileName);
+        if(!configurationFile.exists() || ! configurationFile.canRead()) {
+            log.error("Unable to read evolutionary algorithm configuration file '{}'", configurationFileName);
+            throw new IllegalArgumentException("Unable to read evolutionary algorithm configuration file: " + configurationFileName);
+        }
+
+
+        initializeEMF();
+
+        final Injector ealInjector = new EvolutionaryAlgorithmLanguageStandaloneSetup().createInjectorAndDoEMFRegistration();
+        // do not remove the following line even if the injector is not used. Otherwise, parsing eal files breaks.
+        final Injector idlInjector = new DefinitionLanguageStandaloneSetup().createInjectorAndDoEMFRegistration();
+
+        final XtextResourceSet resourceSet = ealInjector.getInstance(XtextResourceSet.class);
+        resourceSet.addLoadOption(XtextResource.OPTION_RESOLVE_ALL, Boolean.TRUE);
+        resourceSet.addLoadOption(XtextResource.OPTION_ENCODING, "UTF-8");
+
+        try {
+            log.info("Continue by loading the EAL file.");
+            final URI modelURI = URI.createFileURI(configurationFile.getAbsolutePath());
+
+            log.info("Loading ea model from URI {}.", modelURI);
+
+            final Resource resource = resourceSet.getResource(modelURI, true);
+            resource.load(resourceSet.getLoadOptions());
+            if(!resource.getErrors().isEmpty()) {
+                for(Resource.Diagnostic diagnostic : resource.getErrors()) {
+                    log.error("Error while processing rule '{}': {}", configurationFile, diagnostic);
+                }
+            }
+            if(!resource.getWarnings().isEmpty()) {
+                for(Resource.Diagnostic diagnostic : resource.getWarnings()) {
+                    log.error("Warning while processing rule '{}': {}", configurationFile, diagnostic);
+                }
+            }
+
+            model = (EAModel) resource.getContents().get(0);
+            board.bind(BlackboardEntry.EA_CONFIGURATION, model);
+        } catch (final Exception e) {
+            log.error("Unable to evolutionary algorithm configuration file '{}'.", configurationFile, e);
+         }
+    }
+
+    /**
+     * Initialize the model packages and perform the parser setup.
+     */
+    private void initializeEMF() {
+        EALPackageImpl.init();
+        DlPackageImpl.init();
+        EALPackageImpl.init();
+
+        /*
+        if (!EPackage.Registry.INSTANCE.containsKey("https://www.evoal.de/languages/idl/1.0.0")) {
+            EPackage.Registry.INSTANCE.put("https://www.evoal.de/languages/idl/1.0.0", DlPackage.eINSTANCE);
+        }
+*/
+        ExpressionLanguageStandaloneSetup.doSetup();
+        DefinitionLanguageStandaloneSetup.doSetup();
+        EvolutionaryAlgorithmLanguageStandaloneSetup.doSetup();
+    }
+
+    @Produces
+    @Dependent
+    public EAModel getConfiguration() {
+        return model;
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/constraint/ConstraintProducer.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/constraint/ConstraintProducer.java
new file mode 100644
index 0000000000000000000000000000000000000000..85a97988ccf7de33ca93962f96a33f2a4d86ddd0
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/constraint/ConstraintProducer.java
@@ -0,0 +1,69 @@
+package de.evoal.core.main.ddl.constraint;
+
+import de.evoal.core.api.ea.constraints.model.Constraint;
+import de.evoal.core.api.ea.constraints.model.Constraints;
+import de.evoal.core.api.ea.codec.CustomCodec;
+import de.evoal.core.api.properties.PropertiesSpecification;
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.inject.Produces;
+
+import de.evoal.core.main.ddl.constraint.ast.ConditionConverter;
+import de.evoal.core.main.ddl.el.ElHelper;
+import de.evoal.languages.model.ddl.FunctionName;
+import de.evoal.languages.model.el.Call;
+import de.evoal.languages.model.el.Expression;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.inject.Named;
+
+import java.util.Collection;
+import java.util.Objects;
+import java.util.Optional;
+
+@ApplicationScoped
+@Slf4j
+public class ConstraintProducer {
+    private PropertiesSpecification specification;
+
+    @Produces
+    @ApplicationScoped
+    public Constraints create(final @Named("data-constraints") Collection<Expression> constraints,
+                              final CustomCodec codec) {
+        this.specification = specification;
+
+        final Constraints result = new Constraints();
+
+        constraints.stream()
+                   .map(ElHelper::findCall)
+                   .filter(Objects::nonNull)
+                   .map(Call.class::cast)
+                   .filter(c -> "constraint".equals(((FunctionName)c.getFunction()).getDefinition().getName()))
+                   .map(this::convert)
+                   .filter(Optional::isPresent)
+                   .map(Optional::get)
+                   .forEach(result.getConstraints()::add);
+
+        log.info("Loaded {} constraints.", result.getConstraints().size());
+
+        return result;
+    }
+
+    private Optional<Constraint> convert(final Call constraint) {
+        if(constraint.getParameters().size() != 2) {
+            log.error("Constraint has more than two parameters. Skipping.");
+            return Optional.empty();
+        }
+
+        final Constraint result = new Constraint();
+        result.setGroup(ElHelper.findString(constraint.getParameters().get(1)));
+
+        final ConditionConverter converter = new ConditionConverter(specification);
+        converter.doSwitch(constraint.getParameters().get(0));
+
+        result.setFunction(converter.getFunction());
+        result.setUsedProperties(converter.getUsedProperties());
+        result.setConstraintType(converter.getType());
+
+        return Optional.of(result);
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/constraint/ast/ConditionConverter.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/constraint/ast/ConditionConverter.java
new file mode 100644
index 0000000000000000000000000000000000000000..8c7ae6fcd883baf02f287c70f2b3f8184bb6d445
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/constraint/ast/ConditionConverter.java
@@ -0,0 +1,253 @@
+package de.evoal.core.main.ddl.constraint.ast;
+
+import de.evoal.core.api.utils.Requirements;
+import de.evoal.core.api.ea.constraints.model.ConstraintType;
+import de.evoal.core.api.properties.Properties;
+import de.evoal.core.api.properties.PropertiesSpecification;
+import de.evoal.core.api.properties.PropertySpecification;
+import de.evoal.languages.model.eal.DataReference;
+import de.evoal.languages.model.el.*;
+import de.evoal.languages.model.el.util.ELSwitch;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.Function;
+
+public class ConditionConverter extends ELSwitch<Object> {
+    private Function<Properties, Double> function;
+    private final List<PropertySpecification> usedProperties = new ArrayList<>();
+    private final PropertiesSpecification specification;
+    private ConstraintType type;
+
+    public ConditionConverter(final PropertiesSpecification specification) {
+        this.specification = specification;
+    }
+
+    @Override
+    public Object caseOrExpression(OrExpression object) {
+        Requirements.requireSize(object.getSubExpressions(), 1);
+
+        doSwitch(object.getSubExpressions().get(0));
+
+        return null;
+    }
+
+    @Override
+    public Object caseXorExpression(XorExpression object) {
+        Requirements.requireSize(object.getSubExpressions(), 1);
+
+        doSwitch(object.getSubExpressions().get(0));
+
+        return null;
+    }
+
+    @Override
+    public Object caseAndExpression(AndExpression object) {
+        Requirements.requireSize(object.getSubExpressions(), 1);
+
+        doSwitch(object.getSubExpressions().get(0));
+
+        return null;
+    }
+
+    @Override
+    public Object caseNotExpression(NotExpression object) {
+        Requirements.requireFalse(object.isNegated());
+
+        doSwitch(object.getOperand());
+
+        return null;
+    }
+
+    @Override
+    public Object caseComparisonExpression(ComparisonExpression object) {
+        Requirements.requireSize(object.getComparison(), 1);
+
+        final Function<Properties, Double> leftValue = (Function<Properties, Double>) doSwitch(object.getLeftOperand());
+        final Function<Properties, Double> rightValue = (Function<Properties, Double>) doSwitch(object.getComparison().get(0).getSubExpression());
+
+        switch (object.getComparison().get(0).getOperator()) {
+            case EQUAL:
+            case GREATER_EQUAL:
+            case GREATER_THAN: {
+                function = properties -> leftValue.apply(properties) - rightValue.apply(properties);
+                break;
+            }
+            case LESS_EQUAL:
+            case LESS_THAN:
+            {
+                function = properties -> rightValue.apply(properties) - leftValue.apply(properties);
+                break;
+            }
+            case UNEQUAL: {
+                throw new IllegalArgumentException("Unequal is not allowed");
+            }
+        }
+
+        switch (object.getComparison().get(0).getOperator()) {
+            case EQUAL:
+                type = ConstraintType.Equality;
+                break;
+
+            case GREATER_EQUAL:
+            case GREATER_THAN:
+            case LESS_EQUAL:
+            case LESS_THAN:
+                type = ConstraintType.Inequality;
+                break;
+
+            case UNEQUAL: {
+                throw new IllegalArgumentException("Unequal is not allowed");
+            }
+        }
+
+        return null;
+    }
+
+    @Override
+    public Object caseAddOrSubtractExpression(final AddOrSubtractExpression object) {
+        Function<Properties, Double> value = (Function<Properties, Double>) doSwitch(object.getLeftOperand());
+
+        for(int i = 0; i < object.getOperators().size(); ++i) {
+            final AddOrSubtractOperator operator = object.getOperators().get(i);
+            final Function<Properties, Double> rOp = (Function<Properties, Double>) doSwitch(object.getOperands().get(i));
+
+            switch (operator) {
+                case ADD: {
+                    final Function<Properties, Double> lOp = value;
+                    value = properties -> lOp.apply(properties) + rOp.apply(properties);
+                    break;
+                }
+
+                case SUBTRACT: {
+                    final Function<Properties, Double> lOp = value;
+                    value = properties -> lOp.apply(properties) - rOp.apply(properties);
+                    break;
+                }
+            }
+        }
+        return value;
+    }
+
+    @Override
+    public Object caseMultiplyDivideModuloExpression(MultiplyDivideModuloExpression object) {
+        Function<Properties, Double> value = (Function<Properties, Double>) doSwitch(object.getLeftOperand());
+
+        for(int i = 0; i < object.getOperators().size(); ++i) {
+            final MultiplyDivideModuloOperator operator = object.getOperators().get(i);
+            final Function<Properties, Double> rOp = (Function<Properties, Double>) doSwitch(object.getOperands().get(i));
+
+            switch (operator) {
+                case DIVIDE: {
+                    final Function<Properties, Double> lOp = value;
+                    value = properties -> lOp.apply(properties) / rOp.apply(properties);
+                    break;
+                }
+
+                case MODULO: {
+                    final Function<Properties, Double> lOp = value;
+                    value = properties -> lOp.apply(properties) % rOp.apply(properties);
+                    break;
+                }
+
+                case MULTIPLY: {
+                    final Function<Properties, Double> lOp = value;
+                    value = properties -> lOp.apply(properties) * rOp.apply(properties);
+                    break;
+                }
+            }
+        }
+        return value;
+    }
+
+    @Override
+    public Object casePowerOfExpression(PowerOfExpression object) {
+        Function<Properties, Double> value = (Function<Properties, Double>) doSwitch(object.getLeftOperand());
+
+        if(object.getRightOperand() != null) {
+            final Function<Properties, Double> lOp = value;
+            final Function<Properties, Double> rOp = (Function<Properties, Double>) doSwitch(object.getRightOperand());
+
+            value = properties -> Math.pow(lOp.apply(properties), rOp.apply(properties));
+        }
+        return value;
+    }
+
+    @Override
+    public Object caseUnaryAddOrSubtractExpression(UnaryAddOrSubtractExpression object) {
+        Function<Properties, Double> value = (Function<Properties, Double>) doSwitch(object.getSubExpression());
+
+        for(final AddOrSubtractOperator operator : object.getOperators()) {
+            switch (operator) {
+                case ADD: {
+                    value = value;
+                    break;
+                }
+
+                case SUBTRACT: {
+                    final Function<Properties, Double> lOp = value;
+                    value = properties -> -lOp.apply(properties);
+                    break;
+                }
+            }
+        }
+        return value;    }
+
+    @Override
+    public Object caseIntegerLiteral(final IntegerLiteral object) {
+        return (Function<Properties, Double>) properties -> (double)object.getValue();
+    }
+
+    @Override
+    public Object caseDoubleLiteral(final DoubleLiteral object) {
+        return (Function<Properties, Double>) properties -> object.getValue();
+    }
+
+    @Override
+    public Object caseStringLiteral(final StringLiteral object) {
+        return (Function<Properties, Double>) properties -> Double.parseDouble(object.getValue());
+    }
+
+    @Override
+    public Object caseValueReference(final ValueReference object) {
+        if(!(object instanceof DataReference)) {
+            throw new IllegalStateException("Value reference is not a data reference.");
+        }
+
+        final DataReference reference = (DataReference)object;
+        final String propertyName = reference.getDefinition().getName();
+        final int propertyIndex = specification.indexOf(new PropertySpecification(propertyName));
+
+        usedProperties.add(specification.getProperties().get(propertyIndex));
+
+        return (Function<Properties, Double>) properties -> properties.get(propertyIndex);
+    }
+
+    @Override
+    public Object caseBooleanLiteral(final BooleanLiteral object) {
+        throw new IllegalArgumentException("Boolean values are not supported");
+    }
+
+    @Override
+    public Object caseCall(Call object) {
+        throw new IllegalArgumentException("Calls are not supported");
+    }
+
+    @Override
+    public Object caseParantheses(final Parantheses object) {
+        return doSwitch(object.getSubExpression());
+    }
+
+    public Function<Properties, Double> getFunction() {
+        return function;
+    }
+
+    public List<PropertySpecification> getUsedProperties() {
+        return Collections.unmodifiableList(usedProperties);
+    }
+
+    public ConstraintType getType() {
+        return type;
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/constraint/strategies/CalculationFactory.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/constraint/strategies/CalculationFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..2956d3cc2f28dbd9509d5d9941d971018e1d03fe
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/constraint/strategies/CalculationFactory.java
@@ -0,0 +1,34 @@
+package de.evoal.core.main.ddl.constraint.strategies;
+
+import de.evoal.core.api.ea.constraints.model.Constraint;
+import de.evoal.core.api.board.BlackboardEntry;
+import de.evoal.core.api.cdi.ConfigurationValue;
+import javax.enterprise.context.ApplicationScoped;
+
+import de.evoal.core.api.utils.LanguageHelper;
+import de.evoal.languages.model.instance.Instance;
+import org.apache.deltaspike.core.api.provider.BeanProvider;
+
+import javax.inject.Inject;
+
+@ApplicationScoped
+public class CalculationFactory {
+    private final Instance handlerConfigurations;
+
+    @Inject
+    public CalculationFactory(final @ConfigurationValue(entry = BlackboardEntry.EA_CONFIGURATION, access = "algorithm.constraint_handling") Instance handlerConfiguration) {
+        handlerConfigurations = handlerConfiguration;
+    }
+
+    public CalculationStrategy create(final Constraint constraint) {
+        final Instance handlerConfig = LanguageHelper.lookup(handlerConfigurations, constraint.getGroup());
+        final Instance calculationConfig = LanguageHelper.lookup(handlerConfigurations, "calculation");
+
+        final String calculationName = LanguageHelper.lookup(calculationConfig, "name");
+
+        final CalculationStrategy strategy = BeanProvider.getContextualReference(calculationName, false, CalculationStrategy.class);
+        strategy.init(constraint, calculationConfig);
+
+        return strategy;
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/constraint/strategies/CalculationStrategy.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/constraint/strategies/CalculationStrategy.java
new file mode 100644
index 0000000000000000000000000000000000000000..6b68a19ff92e0312efb249695825cb73e87268b0
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/constraint/strategies/CalculationStrategy.java
@@ -0,0 +1,29 @@
+package de.evoal.core.main.ddl.constraint.strategies;
+
+import de.evoal.core.api.ea.constraints.strategies.CalculationResult;
+import de.evoal.core.api.ea.constraints.model.Constraint;
+import de.evoal.core.api.properties.Properties;
+import de.evoal.languages.model.instance.Instance;
+import lombok.NonNull;
+
+/**
+ * A calculation strategy calculates the final difference of a {@link Constraint}.
+ *   The actual implementations can modify the result of the constraint evaluation it its own will.
+ */
+public interface CalculationStrategy {
+    /**
+     * Calculates the constraint handling result for the given {@code properties}.
+     *
+     * @param properties Properties of an individual to check.
+     * @return A non-null non-empty list of constraint handling results.
+     */
+    public @NonNull CalculationResult calculate(final Properties properties);
+
+    /**
+     * Initialises the strategy with the constraint and the calculation configuration.
+     *
+     * @param constraint The corresponding constraint.
+     * @param configuration The handler configuration.
+     */
+    void init(final Constraint constraint, final Instance configuration);
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/constraint/strategies/calculations/NormalCalculation.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/constraint/strategies/calculations/NormalCalculation.java
new file mode 100644
index 0000000000000000000000000000000000000000..e9092ae4299b06c1d419a877ccbc5ce7dd62b24e
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/constraint/strategies/calculations/NormalCalculation.java
@@ -0,0 +1,30 @@
+package de.evoal.core.main.ddl.constraint.strategies.calculations;
+
+import de.evoal.core.api.ea.constraints.model.Constraint;
+import de.evoal.core.api.ea.constraints.strategies.CalculationResult;
+import de.evoal.core.main.ddl.constraint.strategies.CalculationStrategy;
+import de.evoal.core.api.properties.Properties;
+import javax.enterprise.context.Dependent;
+
+import de.evoal.languages.model.instance.Instance;
+import lombok.NonNull;
+
+import javax.inject.Named;
+
+@Dependent
+@Named("normal")
+public class NormalCalculation implements CalculationStrategy {
+    private Instance configuration;
+    private Constraint constraint;
+
+    @Override
+    public @NonNull CalculationResult calculate(final Properties properties) {
+        return new CalculationResult(constraint.apply(properties));
+    }
+
+    @Override
+    public void init(final Constraint constraint, final Instance configuration) {
+        this.configuration = configuration;
+        this.constraint = constraint;
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/constraint/strategies/calculations/StandardDeviationCalculation.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/constraint/strategies/calculations/StandardDeviationCalculation.java
new file mode 100644
index 0000000000000000000000000000000000000000..694f792d4e6bfa853361bd3b195a6ec66d169324
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/constraint/strategies/calculations/StandardDeviationCalculation.java
@@ -0,0 +1,106 @@
+package de.evoal.core.main.ddl.constraint.strategies.calculations;
+
+import de.evoal.core.api.ea.constraints.model.Constraint;
+import de.evoal.core.api.ea.constraints.model.ConstraintResult;
+import de.evoal.core.api.ea.constraints.strategies.CalculationResult;
+import de.evoal.core.api.utils.LanguageHelper;
+import de.evoal.core.main.ddl.constraint.strategies.CalculationStrategy;
+import de.evoal.core.api.properties.Properties;
+import de.evoal.core.api.properties.PropertiesSpecification;
+import de.evoal.core.api.properties.PropertySpecification;
+import javax.enterprise.context.Dependent;
+
+import de.evoal.core.main.ddl.deviation.model.Deviations;
+import de.evoal.languages.model.instance.Instance;
+import lombok.NonNull;
+import org.apache.commons.math3.util.Pair;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Dependent
+@Named("standard-deviation")
+public class StandardDeviationCalculation implements CalculationStrategy {
+    @Inject
+    private Deviations deviations;
+
+    @Inject @Named("source-properties-specification")
+    private PropertiesSpecification source;
+
+    private Instance configuration;
+    private Constraint constraint;
+    private double factor;
+    private List<Pair<Integer, Double>> allowedDeviations;
+
+    @Override
+    public @NonNull CalculationResult calculate(final Properties properties) {
+        return new CalculationResult(calculateMinimalDifference(0, new HashMap<>(), properties));
+    }
+
+    private ConstraintResult calculateMinimalDifference(final int index, final Map<Integer, Double> differences, final Properties properties) {
+        if(index == allowedDeviations.size()) {
+            final Properties adaptedProperties = new Properties(properties);
+
+            for(final Map.Entry<Integer, Double> entry : differences.entrySet()) {
+                final Integer propIndex = entry.getKey();
+                final double value = adaptedProperties.get(propIndex) + entry.getValue();
+                adaptedProperties.put(propIndex, value);
+            }
+
+            return constraint.apply(adaptedProperties);
+        }
+
+        final Pair<Integer, Double> deviation = allowedDeviations.get(index);
+
+        // no deviation
+        differences.put(deviation.getFirst(), 0.0);
+        ConstraintResult minimalResult = calculateMinimalDifference(index + 1, differences, properties);
+
+        if(CalculationResult.isSuccessful(minimalResult) || deviation.getSecond() == 0.0) {
+            return minimalResult;
+        }
+
+        // - deviation
+        {
+            differences.put(deviation.getFirst(), -deviation.getSecond() * factor);
+            ConstraintResult result = calculateMinimalDifference(index + 1, differences, properties);
+
+            if(CalculationResult.isSuccessful(result)) {
+                return result;
+            } else if(Math.abs(result.getComparisonDifference()) < Math.abs(minimalResult.getComparisonDifference())) {
+                minimalResult = result;
+            }
+        }
+
+        // + deviation
+        {
+            differences.put(deviation.getFirst(), deviation.getSecond() * factor);
+            ConstraintResult result = calculateMinimalDifference(index + 1, differences, properties);
+
+            if(CalculationResult.isSuccessful(result)) {
+                return result;
+            } else if(Math.abs(result.getComparisonDifference()) < Math.abs(minimalResult.getComparisonDifference())) {
+                minimalResult = result;
+            }
+
+            return minimalResult;
+        }
+    }
+
+    @Override
+    public void init(final Constraint constraint, final Instance configuration) {
+        this.configuration = configuration;
+        this.constraint = constraint;
+        this.factor = LanguageHelper.lookup(configuration, "factor");
+
+        final List<PropertySpecification> sourceProperties = constraint.getUsedProperties();
+
+        allowedDeviations = sourceProperties
+                .stream()
+                .map(ps -> new Pair<PropertySpecification, Optional<Double>>(ps, deviations.find(ps)))
+                .map(p -> new Pair<Integer, Double>(source.indexOf(p.getFirst()), p.getSecond().orElse(0.0)))
+                .collect(Collectors.toList());
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/constraint/strategies/constraint/JeneticsConstraintProducer.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/constraint/strategies/constraint/JeneticsConstraintProducer.java
new file mode 100644
index 0000000000000000000000000000000000000000..a150880392266591fe3c8b0bc7b0ec66e858cc0e
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/constraint/strategies/constraint/JeneticsConstraintProducer.java
@@ -0,0 +1,42 @@
+package de.evoal.core.main.ddl.constraint.strategies.constraint;
+
+import de.evoal.core.api.ea.constraints.model.Constraint;
+import de.evoal.core.api.ea.constraints.model.Constraints;
+import de.evoal.core.main.ddl.constraint.strategies.CalculationFactory;
+import de.evoal.core.api.board.BlackboardEntry;
+import de.evoal.core.api.cdi.ConfigurationValue;
+import de.evoal.core.api.ea.codec.CustomCodec;
+import de.evoal.core.main.ddl.constraint.utils.ConfigurationUtils;
+import de.evoal.languages.model.instance.Attribute;
+import de.evoal.languages.model.instance.Instance;
+import de.evoal.languages.model.instance.Misc;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.inject.Produces;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+@ApplicationScoped
+public class JeneticsConstraintProducer {
+    @Produces
+    public List<io.jenetics.engine.Constraint> create(
+            final @ConfigurationValue(entry = BlackboardEntry.EA_CONFIGURATION, access = "algorithm.constraint_handling") Instance handlerConfiguration,
+            final Constraints constraints,
+            final CustomCodec codec,
+            final CalculationFactory factory) {
+        // collect group information to handle
+        final List<Attribute> groups = ConfigurationUtils.findByHandlerName(handlerConfiguration, "killAtBirth");
+        final Set<String> allGroups = groups.stream().map(e -> ((Misc)e.getName()).getName()).collect(Collectors.toSet());
+        final List<Constraint> listOfConstraints = constraints.getConstraints();
+
+        final List<io.jenetics.engine.Constraint> result = listOfConstraints
+                    .stream()
+                    .filter(c -> allGroups.contains(c.getGroup()))
+                    .map(factory::create)
+                    .map(s -> new JeneticsConstraintStrategy(s, codec, new RandomGenotypeStrategy()))
+                    .collect(Collectors.toList());
+
+        return result;
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/constraint/strategies/constraint/JeneticsConstraintStrategy.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/constraint/strategies/constraint/JeneticsConstraintStrategy.java
new file mode 100644
index 0000000000000000000000000000000000000000..795b7ba177d75d58317665644cf7b49146cdb858
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/constraint/strategies/constraint/JeneticsConstraintStrategy.java
@@ -0,0 +1,36 @@
+package de.evoal.core.main.ddl.constraint.strategies.constraint;
+
+import de.evoal.core.main.ddl.constraint.strategies.CalculationStrategy;
+import de.evoal.core.api.ea.constraints.strategies.HandlingStrategy;
+import de.evoal.core.api.ea.codec.CustomCodec;
+import de.evoal.core.api.properties.Properties;
+import io.jenetics.Gene;
+import io.jenetics.Phenotype;
+
+public class JeneticsConstraintStrategy<
+        G extends Gene<?, G>,
+        C extends Comparable<? super C>
+        > implements io.jenetics.engine.Constraint<G, C>, HandlingStrategy {
+
+    private final CalculationStrategy calculation;
+    private final CustomCodec<G> codec;
+    private final RepairStrategy repair;
+
+    public JeneticsConstraintStrategy(final CalculationStrategy calculation, final CustomCodec<G> codec, final RepairStrategy repair) {
+        this.calculation = calculation;
+        this.codec = codec;
+        this.repair = repair;
+    }
+
+    @Override
+    public boolean test(final Phenotype<G, C> individual) {
+        final Properties properties = codec.decode(individual.genotype());
+
+        return calculation.calculate(properties).isSuccessful();
+    }
+
+    @Override
+    public Phenotype<G, C> repair(final Phenotype<G, C> individual, final long generation) {
+        return repair.apply(individual, generation);
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/constraint/strategies/constraint/RandomGenotypeStrategy.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/constraint/strategies/constraint/RandomGenotypeStrategy.java
new file mode 100644
index 0000000000000000000000000000000000000000..e0659a82dbf31b1c5008c81a140282b0f9f78f70
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/constraint/strategies/constraint/RandomGenotypeStrategy.java
@@ -0,0 +1,14 @@
+package de.evoal.core.main.ddl.constraint.strategies.constraint;
+
+import io.jenetics.Gene;
+import io.jenetics.Genotype;
+import io.jenetics.Phenotype;
+
+public class RandomGenotypeStrategy<G extends Gene<?, G>, C extends Comparable<? super C>> implements RepairStrategy<G, C> {
+    @Override
+    public Phenotype apply(final Phenotype<G, C> individual, long generation) {
+        final Genotype<G> newInstance = individual.genotype().newInstance();
+
+        return Phenotype.of(newInstance, generation);
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/constraint/strategies/constraint/RepairStrategy.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/constraint/strategies/constraint/RepairStrategy.java
new file mode 100644
index 0000000000000000000000000000000000000000..2fe93245476d30087c88958d203bc092d64ab3dd
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/constraint/strategies/constraint/RepairStrategy.java
@@ -0,0 +1,8 @@
+package de.evoal.core.main.ddl.constraint.strategies.constraint;
+
+import io.jenetics.Gene;
+import io.jenetics.Phenotype;
+
+public interface RepairStrategy<G extends Gene<?, G>, C extends Comparable<? super C>> {
+     public Phenotype<G,C> apply(Phenotype<G,C> individual, long generation);
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/constraint/strategies/fitness/MalusFunctionProducer.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/constraint/strategies/fitness/MalusFunctionProducer.java
new file mode 100644
index 0000000000000000000000000000000000000000..e2ca15700c632bab98fe46bba5a9ed44bbdcd930
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/constraint/strategies/fitness/MalusFunctionProducer.java
@@ -0,0 +1,90 @@
+package de.evoal.core.main.ddl.constraint.strategies.fitness;
+
+import de.evoal.core.api.ea.constraints.model.Constraint;
+import de.evoal.core.api.ea.constraints.model.Constraints;
+import de.evoal.core.api.ea.constraints.strategies.fitness.MalusForFitnessStrategy;
+import de.evoal.core.api.ea.constraints.strategies.fitness.MalusFunction;
+import de.evoal.core.main.ddl.constraint.strategies.fitness.internal.MalusForFitnessFunction;
+import de.evoal.core.api.utils.LanguageHelper;
+import de.evoal.core.main.ddl.constraint.strategies.CalculationFactory;
+import de.evoal.core.main.ddl.constraint.strategies.CalculationStrategy;
+import de.evoal.core.api.board.BlackboardEntry;
+import de.evoal.core.api.cdi.ConfigurationValue;
+import de.evoal.core.api.properties.PropertiesSpecification;
+import de.evoal.core.api.properties.PropertySpecification;
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.inject.Produces;
+
+import de.evoal.core.main.ddl.constraint.utils.ConfigurationUtils;
+import de.evoal.languages.model.instance.Attribute;
+import de.evoal.languages.model.instance.Instance;
+import de.evoal.languages.model.instance.Misc;
+import org.apache.commons.math3.util.Pair;
+
+import javax.inject.Named;
+import java.util.*;
+
+@ApplicationScoped
+public class MalusFunctionProducer {
+    @ApplicationScoped @Produces
+    public MalusForFitnessStrategy create(
+            final @ConfigurationValue(entry = BlackboardEntry.EA_CONFIGURATION, access = "algorithm.constraint_handling") Instance handlerConfiguration,
+            final Constraints constraints,
+            final @Named("source-properties-specification") PropertiesSpecification source,
+            final @Named("output-dependencies") PropertiesDependencies dependencies,
+            final @Named("target-properties-specification") PropertiesSpecification target,
+            final CalculationFactory factory) {
+        final MalusForFitnessStrategy resultingFunction = new MalusForFitnessStrategy(target.size());
+
+        // collect group information to handle
+        final List<Attribute> groups = ConfigurationUtils.findByHandlerName(handlerConfiguration, "malusForFitness");
+
+        // collect all constraints for each index (of the appropriate groups)
+        final List<List<Pair<Constraint, Attribute>>> constraintsForIndex = new ArrayList<>(source.size());
+        for(int index = 0; index < source.size(); ++index) {
+            constraintsForIndex.add(new ArrayList<>());
+        }
+
+        for(final Constraint constraint : constraints.getConstraints()) {
+            final String group = constraint.getGroup();
+
+            for(final Attribute info : groups) {
+                if(((Misc)info.getName()).getName().equals(group)) {
+                    for(final PropertySpecification ps : constraint.getUsedProperties()) {
+                        final int index = source.indexOf(ps);
+                        constraintsForIndex.get(index).add(new Pair<>(constraint, info));
+                    }
+                }
+            }
+        }
+
+        // build MalusFunctionParts
+        for(int index = 0; index < target.size(); ++index) {
+            final Set<Constraint> applied  = new HashSet<>();
+
+            for(final PropertySpecification ips : dependencies.get(target.getProperties().get(index))) {
+                final int ipsIndex = source.indexOf(ips);
+
+                for(final Pair<Constraint, Attribute> pair : constraintsForIndex.get(ipsIndex)) {
+                    final Constraint constraint = pair.getFirst();
+                    final Attribute configuration = pair.getSecond();
+
+                    // prevent constraints from being applied multiple times per fitness value
+                    if(applied.contains(constraint)) {
+                        continue;
+                    }
+                    applied.add(constraint);
+
+                    final CalculationStrategy calculation = factory.create(constraint);
+
+                    final String handlerName = LanguageHelper.lookup((Instance) configuration.getValue(), "name");
+
+                    final MalusFunction strategy = new MalusForFitnessFunction(constraint, LanguageHelper.lookup((Instance)configuration.getValue(), "handling"), index) ;
+                    resultingFunction.add(index, strategy);
+               }
+            }
+        }
+
+        return resultingFunction;
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/constraint/strategies/fitness/PropertiesDependencies.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/constraint/strategies/fitness/PropertiesDependencies.java
new file mode 100644
index 0000000000000000000000000000000000000000..15802d29829c39ffca662555defbca5b03133378
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/constraint/strategies/fitness/PropertiesDependencies.java
@@ -0,0 +1,27 @@
+package de.evoal.core.main.ddl.constraint.strategies.fitness;
+
+import de.evoal.core.api.properties.PropertiesSpecification;
+import de.evoal.core.api.properties.PropertySpecification;
+
+import java.util.*;
+
+/**
+ * Small utility class for calculating the dependencies between input and output dependencies.
+ */
+public class PropertiesDependencies {
+    private final Map<PropertySpecification, Set<PropertySpecification>> dependencies = new HashMap<>();
+
+    public PropertiesDependencies(final PropertiesSpecification specification) {
+        for(final PropertySpecification ps : specification.getProperties()) {
+            dependencies.put(ps, new HashSet<>());
+        }
+    }
+
+    public void add(final PropertySpecification target, final PropertiesSpecification deps) {
+        dependencies.get(target).addAll(deps.getProperties());
+    }
+
+    public Set<PropertySpecification> get(final PropertySpecification specification) {
+        return dependencies.get(specification);
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/constraint/strategies/fitness/internal/MalusForFitnessFunction.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/constraint/strategies/fitness/internal/MalusForFitnessFunction.java
new file mode 100644
index 0000000000000000000000000000000000000000..f49486f735a90345e28bd21a4092330653bf096d
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/constraint/strategies/fitness/internal/MalusForFitnessFunction.java
@@ -0,0 +1,25 @@
+package de.evoal.core.main.ddl.constraint.strategies.fitness.internal;
+
+import de.evoal.core.api.ea.constraints.model.Constraint;
+import de.evoal.core.api.ea.constraints.model.ConstraintResult;
+import de.evoal.core.api.ea.constraints.strategies.fitness.MalusFunction;
+import de.evoal.core.api.properties.Properties;
+import de.evoal.core.api.utils.LanguageHelper;
+import de.evoal.languages.model.instance.Instance;
+
+public class MalusForFitnessFunction implements MalusFunction {
+    private final Constraint constraint;
+    private final double smoothing;
+
+    public MalusForFitnessFunction(final Constraint constraint, final Instance configuration, final int index) {
+        this.constraint = constraint;
+        smoothing = LanguageHelper.lookup(configuration, "smoothing");
+    }
+
+    @Override
+    public double apply(final Properties properties, double fitnessValue) {
+        final ConstraintResult result = constraint.apply(properties);
+
+        return fitnessValue - smoothing * Math.abs(result.getComparisonDifference());
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/constraint/utils/ConfigurationUtils.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/constraint/utils/ConfigurationUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..acc5648eece616021fa5f8e86e756d0f23cf870c
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/constraint/utils/ConfigurationUtils.java
@@ -0,0 +1,28 @@
+package de.evoal.core.main.ddl.constraint.utils;
+
+import de.evoal.core.api.utils.LanguageHelper;
+import de.evoal.languages.model.instance.Attribute;
+import de.evoal.languages.model.instance.Instance;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public final class ConfigurationUtils {
+    private ConfigurationUtils() {
+    }
+
+    public static List<Attribute> findByHandlerName(Instance configuration, final String name) {
+        final List<Attribute> result = new ArrayList<>();
+
+        for(final Attribute attribute : configuration.getAttributes()) {
+            final Instance handlerConfiguration = LanguageHelper.lookup((Instance)attribute.getValue(), "handling");
+            final String handlerName = LanguageHelper.lookup(handlerConfiguration, "name");
+
+            if(name.equals(handlerName)) {
+                result.add(attribute);
+            }
+        }
+
+        return result;
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/correlation/CorrelationsProducer.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/correlation/CorrelationsProducer.java
new file mode 100644
index 0000000000000000000000000000000000000000..ca3373bc7903bb03ea6621435957df0377e22d17
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/correlation/CorrelationsProducer.java
@@ -0,0 +1,83 @@
+package de.evoal.core.main.ddl.correlation;
+
+import de.evoal.core.api.ea.codec.CustomCodec;
+import de.evoal.core.api.properties.PropertiesSpecification;
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.inject.Produces;
+
+import de.evoal.core.main.ea.functions.correlation.model.Correlation;
+import de.evoal.core.main.ea.functions.correlation.model.Correlations;
+import de.evoal.core.main.ea.functions.correlation.model.RangedCorrelation;
+import de.evoal.core.main.ddl.correlation.el.AstHelper;
+import de.evoal.core.main.ddl.el.ElHelper;
+import de.evoal.languages.model.el.Call;
+import de.evoal.languages.model.el.Expression;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.inject.Named;
+
+import java.util.Collection;
+import java.util.Objects;
+import java.util.Optional;
+
+/**
+ * Extracts all correlations from the DVL AST.
+ */
+@ApplicationScoped
+@Slf4j
+public class CorrelationsProducer {
+
+    private CustomCodec codec;
+
+    private PropertiesSpecification specification;
+
+    @Produces
+    @ApplicationScoped
+    public Correlations createCorrelations(final @Named("data-constraints") Collection<Expression> expressions,
+                                           final @Named("source-properties-specification") PropertiesSpecification specification,
+                                           final CustomCodec codec) {
+        this.codec = codec;
+        this.specification = specification;
+        final Correlations correlations = new Correlations(codec);
+
+        expressions.stream()
+                .map(ElHelper::findCall)
+                .filter(Objects::nonNull)
+                .map(Call.class::cast)
+                .filter(c -> "connection".equals(((de.evoal.languages.model.ddl.FunctionName)c.getFunction()).getDefinition().getName()))
+                .map(c -> convert(c))
+                .filter(Optional::isPresent)
+                .map(Optional::get)
+                .forEach(correlations.getCorrelations()::add);
+
+        log.info("Loaded {} correlations.", correlations.getCorrelations().size());
+
+        return correlations;
+    }
+
+    private Optional<Correlation> convert(final Call constraint) {
+        if(constraint.getParameters().size() == 3) {
+            final Correlation result = new Correlation();
+            result.setChromosomeOne(AstHelper.findChromosomeIndex(specification, constraint.getParameters().get(0)));
+            result.setChromosomeTwo(AstHelper.findChromosomeIndex(specification, constraint.getParameters().get(1)));
+            result.setCorrelationFactor(ElHelper.findNumber(constraint.getParameters().get(2)).doubleValue());
+            result.setCodec(codec);
+
+            return Optional.of(result);
+        } else if(constraint.getParameters().size() == 5) {
+            final RangedCorrelation result = new RangedCorrelation();
+            result.setChromosomeOne(AstHelper.findChromosomeIndex(specification, constraint.getParameters().get(0)));
+            result.setChromosomeTwo(AstHelper.findChromosomeIndex(specification, constraint.getParameters().get(2)));
+            result.setCorrelationFactor(ElHelper.findNumber(constraint.getParameters().get(4)).doubleValue());
+            result.setCodec(codec);
+
+            result.setChromosomeOneRange(AstHelper.findRange(constraint.getParameters().get(1)));
+            result.setChromosomeTwoRange(AstHelper.findRange(constraint.getParameters().get(3)));
+
+            return Optional.of(result);
+        } else {
+            log.error("connection constraint has wrong number of parameters: {}", constraint.getParameters().size());
+            return Optional.empty();
+        }
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/correlation/el/AstHelper.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/correlation/el/AstHelper.java
new file mode 100644
index 0000000000000000000000000000000000000000..c0b4c88601856b234808101806e1023b1dcfca9c
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/correlation/el/AstHelper.java
@@ -0,0 +1,22 @@
+package de.evoal.core.main.ddl.correlation.el;
+
+import de.evoal.core.api.properties.PropertiesSpecification;
+import de.evoal.core.api.properties.PropertySpecification;
+import de.evoal.core.main.ea.functions.correlation.model.Range;
+import de.evoal.core.main.ddl.el.StringSwitch;
+import de.evoal.languages.model.el.Expression;
+
+public final class AstHelper {
+    private AstHelper() {
+    }
+
+    public static Range findRange(final Expression expression) {
+        return new RangeSwitch().doSwitch(expression);
+    }
+
+    public static int findChromosomeIndex(final PropertiesSpecification specification, final Expression expression) {
+        final String name = new StringSwitch().doSwitch(expression);
+
+        return specification.indexOf(new PropertySpecification(name));
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/correlation/el/RangeSwitch.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/correlation/el/RangeSwitch.java
new file mode 100644
index 0000000000000000000000000000000000000000..58fc1b0c7d729304dfc34abda3975adf31cf392b
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/correlation/el/RangeSwitch.java
@@ -0,0 +1,121 @@
+package de.evoal.core.main.ddl.correlation.el;
+
+import de.evoal.core.main.ea.functions.correlation.model.Range;
+import de.evoal.core.main.ddl.el.ElHelper;
+import de.evoal.languages.model.el.*;
+import de.evoal.languages.model.el.util.ELSwitch;
+
+import java.util.Objects;
+
+public class RangeSwitch extends ELSwitch<Range> {
+    @Override
+    public Range caseOrExpression(final OrExpression object) {
+        Objects.equals(object.getSubExpressions().size(), 1);
+
+        return this.doSwitch(object.getSubExpressions().get(0));
+    }
+
+    @Override
+    public Range caseXorExpression(final XorExpression object) {
+        Objects.equals(object.getSubExpressions().size(), 1);
+
+        return this.doSwitch(object.getSubExpressions().get(0));
+    }
+
+    @Override
+    public Range caseAndExpression(final AndExpression object) {
+        Objects.equals(object.getSubExpressions().size(), 1);
+
+        return this.doSwitch(object.getSubExpressions().get(0));
+    }
+
+    @Override
+    public Range caseNotExpression(final NotExpression object) {
+        return this.doSwitch(object.getOperand());
+    }
+
+    @Override
+    public Range caseComparisonExpression(final ComparisonExpression object) {
+        Objects.equals(object.getComparison().size(), 0);
+
+        return this.doSwitch(object.getLeftOperand());
+    }
+
+    @Override
+    public Range caseAddOrSubtractExpression(final AddOrSubtractExpression object) {
+        Objects.equals(object.getOperators().size(), 0);
+
+        return this.doSwitch(object.getLeftOperand());
+    }
+
+    @Override
+    public Range caseMultiplyDivideModuloExpression(MultiplyDivideModuloExpression object) {
+        Objects.equals(object.getOperators().size(), 0);
+
+        return this.doSwitch(object.getLeftOperand());
+    }
+
+    @Override
+    public Range casePowerOfExpression(PowerOfExpression object) {
+        Objects.isNull(object.getRightOperand());
+
+        return this.doSwitch(object.getLeftOperand());
+    }
+
+    @Override
+    public Range caseUnaryAddOrSubtractExpression(UnaryAddOrSubtractExpression object) {
+        Objects.equals(object.getOperators().size(), 0);
+
+        return this.doSwitch(object.getSubExpression());
+    }
+    /*
+        @Override
+        public Range caseCallOrLiteralOrReferenceOrParantheses(CallOrLiteralOrReferenceOrParantheses object) {
+            return super.caseCallOrLiteralOrReferenceOrParantheses(object);
+        }
+    */
+
+    @Override
+    public Range caseIntegerLiteral(final IntegerLiteral object) {
+        throw new IllegalStateException("Searching for Range but found a integer literal.");
+    }
+
+    @Override
+    public Range caseDoubleLiteral(final DoubleLiteral object) {
+        throw new IllegalStateException("Searching for range but found a double literal.");
+    }
+
+    @Override
+    public Range caseStringLiteral(StringLiteral object) {
+        throw new IllegalStateException("Searching for Range but found a string literal.");
+    }
+
+    @Override
+    public Range caseBooleanLiteral(BooleanLiteral object) {
+        throw new IllegalStateException("Searching for Range but found a boolean literal.");
+    }
+
+    @Override
+    public Range caseCall(final Call object) {
+        final de.evoal.languages.model.eal.FunctionName calledFunction = (de.evoal.languages.model.eal.FunctionName)object.getFunction();
+        if(!"range".equals(calledFunction.getDefinition().getName())) {
+            throw new IllegalStateException("Searching for range but found: " + calledFunction.getDefinition().getName());
+        }
+
+        Objects.equals(object.getParameters().size(), 2);
+
+        final Number lowerBound = ElHelper.findNumber(object.getParameters().get(0));
+        final Number upperBound = ElHelper.findNumber(object.getParameters().get(1));
+
+        final Range result = new Range();
+        result.setLower(lowerBound.doubleValue());
+        result.setUpper(upperBound.doubleValue());
+
+        return result;
+    }
+
+    @Override
+    public Range caseParantheses(Parantheses object) {
+        return this.doSwitch(object.getSubExpression());
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/deviation/DeviationProducer.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/deviation/DeviationProducer.java
new file mode 100644
index 0000000000000000000000000000000000000000..de27c15b3221fbd283e253c8da3fc6176a1279c7
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/deviation/DeviationProducer.java
@@ -0,0 +1,67 @@
+package de.evoal.core.main.ddl.deviation;
+
+import de.evoal.core.main.ddl.deviation.model.Deviation;
+import de.evoal.core.main.ddl.deviation.model.Deviations;
+import de.evoal.core.main.ddl.el.ElHelper;
+import de.evoal.core.api.ea.codec.CustomCodec;
+import de.evoal.core.api.properties.PropertiesSpecification;
+import de.evoal.core.api.properties.PropertySpecification;
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.inject.Produces;
+
+import javax.inject.Named;
+
+import de.evoal.languages.model.el.Call;
+import de.evoal.languages.model.el.Expression;
+import de.evoal.languages.model.el.FunctionName;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.Collection;
+import java.util.Objects;
+import java.util.Optional;
+
+@ApplicationScoped
+@Slf4j
+public class DeviationProducer {
+    private PropertiesSpecification specification;
+
+    @Produces
+    @ApplicationScoped
+    public Deviations create(
+            final @Named("data-constraints") Collection<Expression> expressions,
+            final CustomCodec codec) {
+        this.specification = specification;
+        final Deviations deviations = new Deviations(specification);
+
+        expressions.stream()
+                   .map(ElHelper::findCall)
+                   .filter(Objects::nonNull)
+                   .map(Call.class::cast)
+                   .filter(c -> "standardDeviation".equals(((de.evoal.languages.model.ddl.FunctionName)c.getFunction()).getDefinition().getName()))
+                   .map(c -> convert(c))
+                   .filter(Optional::isPresent)
+                   .map(Optional::get)
+                   .forEach(deviations::add);
+
+        return deviations;
+    }
+
+    private Optional<Deviation> convert(final Call constraint) {
+        if(constraint.getParameters().size() != 1) {
+            log.error("Deviation has more than two parameters. Skipping.");
+            return Optional.empty();
+        }
+
+        final String propertyName = ElHelper.findValueReference(constraint.getParameters().get(0));
+        final double deviation = ElHelper.findNumber(constraint.getParameters().get(1)).doubleValue();
+
+        final PropertySpecification spec = new PropertySpecification(propertyName);
+
+        final Deviation result = new Deviation();
+        result.setSpecification(spec);
+        result.setIndex(specification.indexOf(spec));
+        result.setDeviation(deviation);
+
+        return Optional.of(result);
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/deviation/model/Deviation.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/deviation/model/Deviation.java
new file mode 100644
index 0000000000000000000000000000000000000000..115c44720da024aec5eb29a0fa5c93db67365c93
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/deviation/model/Deviation.java
@@ -0,0 +1,22 @@
+package de.evoal.core.main.ddl.deviation.model;
+
+import de.evoal.core.api.properties.PropertySpecification;
+import lombok.Data;
+
+@Data
+public class Deviation {
+    /**
+     * The configured deviation value.
+     */
+    private double deviation;
+
+    /**
+     * Index of the property.
+     */
+    private int index;
+
+    /**
+     * The property specification of the used property.
+     */
+    private PropertySpecification specification;
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/deviation/model/Deviations.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/deviation/model/Deviations.java
new file mode 100644
index 0000000000000000000000000000000000000000..654308b9e9d445f18c9cf87ca13fef613b0cc85f
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/deviation/model/Deviations.java
@@ -0,0 +1,33 @@
+package de.evoal.core.main.ddl.deviation.model;
+
+import de.evoal.core.api.properties.PropertiesSpecification;
+import de.evoal.core.api.properties.PropertySpecification;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+public class Deviations {
+    private final PropertiesSpecification specification;
+
+    private List<Optional<Double>> standardDeviations = new ArrayList<>();
+
+    public Deviations(final PropertiesSpecification specification) {
+        this.specification = specification;
+        for(int i = 0; i < specification.size(); ++i) {
+            standardDeviations.add(Optional.empty());
+        }
+    }
+
+    public void add(final Deviation deviation) {
+        standardDeviations.set(deviation.getIndex(), Optional.of(deviation.getDeviation()));
+    }
+
+    public Optional<Double> find(final int propertyIndex) {
+        return standardDeviations.get(propertyIndex);
+    }
+
+    public Optional<Double> find(final PropertySpecification spec) {
+        return standardDeviations.get(specification.indexOf(spec));
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/el/CallSwitch.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/el/CallSwitch.java
new file mode 100644
index 0000000000000000000000000000000000000000..8f44f7185e13d6d87832be3207fa47af9360f83d
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/el/CallSwitch.java
@@ -0,0 +1,84 @@
+package de.evoal.core.main.ddl.el;
+
+import de.evoal.languages.model.el.*;
+import de.evoal.languages.model.el.util.ELSwitch;
+
+import java.util.Objects;
+
+public class CallSwitch extends ELSwitch<Call> {
+    @Override
+    public Call caseOrExpression(final OrExpression object) {
+        Objects.equals(object.getSubExpressions().size(), 1);
+
+        return this.doSwitch(object.getSubExpressions().get(0));
+    }
+
+    @Override
+    public Call caseXorExpression(XorExpression object) {
+        Objects.equals(object.getSubExpressions().size(), 1);
+
+        return this.doSwitch(object.getSubExpressions().get(0));
+    }
+
+    @Override
+    public Call caseAndExpression(AndExpression object) {
+        Objects.equals(object.getSubExpressions().size(), 1);
+
+        return this.doSwitch(object.getSubExpressions().get(0));
+    }
+
+    @Override
+    public Call caseNotExpression(NotExpression object) {
+        return this.doSwitch(object.getOperand());
+    }
+
+    @Override
+    public Call caseComparisonExpression(ComparisonExpression object) {
+        Objects.equals(object.getComparison().size(), 0);
+
+        return this.doSwitch(object.getLeftOperand());
+    }
+
+    @Override
+    public Call caseAddOrSubtractExpression(AddOrSubtractExpression object) {
+        Objects.equals(object.getOperators().size(), 0);
+
+        return this.doSwitch(object.getLeftOperand());
+    }
+
+    @Override
+    public Call caseMultiplyDivideModuloExpression(MultiplyDivideModuloExpression object) {
+        Objects.equals(object.getOperators().size(), 0);
+
+        return this.doSwitch(object.getLeftOperand());
+    }
+
+    @Override
+    public Call casePowerOfExpression(PowerOfExpression object) {
+        Objects.isNull(object.getRightOperand());
+
+        return this.doSwitch(object.getLeftOperand());
+    }
+
+    @Override
+    public Call caseUnaryAddOrSubtractExpression(UnaryAddOrSubtractExpression object) {
+        Objects.equals(object.getOperators().size(), 0);
+
+        return this.doSwitch(object.getSubExpression());
+    }
+    /*
+        @Override
+        public String caseCallOrLiteralOrReferenceOrParantheses(CallOrLiteralOrReferenceOrParantheses object) {
+            return super.caseCallOrLiteralOrReferenceOrParantheses(object);
+        }
+    */
+
+    @Override
+    public Call caseParantheses(Parantheses object) {
+        return this.doSwitch(object.getSubExpression());
+    }
+
+    public Call caseCall(Call object) {
+        return object;
+    }
+}
\ No newline at end of file
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/el/ElHelper.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/el/ElHelper.java
new file mode 100644
index 0000000000000000000000000000000000000000..344a04e1b0221d651e9a4181377d57a5e1084fb8
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/el/ElHelper.java
@@ -0,0 +1,25 @@
+package de.evoal.core.main.ddl.el;
+
+import de.evoal.languages.model.el.Call;
+import de.evoal.languages.model.el.Expression;
+
+public final class ElHelper {
+    private ElHelper() {
+    }
+
+    public static Number findNumber(final Expression expression) {
+        return new NumberSwitch().doSwitch(expression);
+    }
+
+    public static String findString(final Expression expression) {
+        return new StringSwitch().doSwitch(expression);
+    }
+
+    public static String findValueReference(final Expression expression) {
+        return new ValueReferenceSwitch().doSwitch(expression);
+    }
+
+    public static Call findCall(final Expression expression) {
+        return new CallSwitch().doSwitch(expression);
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/el/NumberSwitch.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/el/NumberSwitch.java
new file mode 100644
index 0000000000000000000000000000000000000000..18e788f51d4c3a49a77f26c422bbab9bfd254d9d
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/el/NumberSwitch.java
@@ -0,0 +1,119 @@
+package de.evoal.core.main.ddl.el;
+
+import de.evoal.languages.model.el.*;
+import de.evoal.languages.model.el.util.ELSwitch;
+
+import java.util.Objects;
+
+public class NumberSwitch extends ELSwitch<Number> {
+    @Override
+    public Number caseOrExpression(final OrExpression object) {
+        Objects.equals(object.getSubExpressions().size(), 1);
+
+        return this.doSwitch(object.getSubExpressions().get(0));
+    }
+
+    @Override
+    public Number caseXorExpression(XorExpression object) {
+        Objects.equals(object.getSubExpressions().size(), 1);
+
+        return this.doSwitch(object.getSubExpressions().get(0));
+    }
+
+    @Override
+    public Number caseAndExpression(AndExpression object) {
+        Objects.equals(object.getSubExpressions().size(), 1);
+
+        return this.doSwitch(object.getSubExpressions().get(0));
+    }
+
+    @Override
+    public Number caseNotExpression(NotExpression object) {
+        return this.doSwitch(object.getOperand());
+    }
+
+    @Override
+    public Number caseComparisonExpression(ComparisonExpression object) {
+        Objects.equals(object.getComparison().size(), 0);
+
+        return this.doSwitch(object.getLeftOperand());
+    }
+
+    @Override
+    public Number caseAddOrSubtractExpression(final AddOrSubtractExpression object) {
+        Objects.equals(object.getOperators().size(), 0);
+
+        return this.doSwitch(object.getLeftOperand());
+    }
+
+    @Override
+    public Number caseMultiplyDivideModuloExpression(MultiplyDivideModuloExpression object) {
+        Objects.equals(object.getOperators().size(), 0);
+
+        return this.doSwitch(object.getLeftOperand());
+    }
+
+    @Override
+    public Number casePowerOfExpression(PowerOfExpression object) {
+        Objects.isNull(object.getRightOperand());
+
+        return this.doSwitch(object.getLeftOperand());
+    }
+
+    @Override
+    public Number caseUnaryAddOrSubtractExpression(UnaryAddOrSubtractExpression object) {
+        Objects.equals(object.getOperators().size(), 0);
+
+        Number number = this.doSwitch(object.getSubExpression());
+
+        for(final AddOrSubtractOperator aso : object.getOperators()) {
+            if(AddOrSubtractOperator.ADD.equals(aso)) {
+                continue;
+            }
+
+            if(number instanceof Integer) {
+                number = Math.negateExact(number.intValue());
+            } else if(number instanceof Double) {
+                number = -number.doubleValue();
+            }
+        }
+
+        return number;
+    }
+    /*
+        @Override
+        public Number caseCallOrLiteralOrReferenceOrParantheses(CallOrLiteralOrReferenceOrParantheses object) {
+            return super.caseCallOrLiteralOrReferenceOrParantheses(object);
+        }
+    */
+
+    @Override
+    public Number caseIntegerLiteral(final IntegerLiteral object) {
+        return object.getValue();
+    }
+
+    @Override
+    public Number caseDoubleLiteral(final DoubleLiteral object) {
+        return object.getValue();
+    }
+
+    @Override
+    public Number caseStringLiteral(StringLiteral object) {
+        throw new IllegalStateException("Searching for number but found a string literal.");
+    }
+
+    @Override
+    public Number caseBooleanLiteral(BooleanLiteral object) {
+        throw new IllegalStateException("Searching for number but found a boolean literal.");
+    }
+
+    @Override
+    public Number caseCall(final Call object) {
+        throw new IllegalStateException("Searching for number but found a call.");
+    }
+
+    @Override
+    public Number caseParantheses(Parantheses object) {
+        return this.doSwitch(object.getSubExpression());
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/el/StringSwitch.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/el/StringSwitch.java
new file mode 100644
index 0000000000000000000000000000000000000000..cc010449181148bb422b75e3dddb999e1031383e
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/el/StringSwitch.java
@@ -0,0 +1,105 @@
+package de.evoal.core.main.ddl.el;
+
+import de.evoal.languages.model.el.*;
+import de.evoal.languages.model.el.util.ELSwitch;
+
+import java.util.Objects;
+
+public class StringSwitch extends ELSwitch<String> {
+    @Override
+    public String caseOrExpression(final OrExpression object) {
+        Objects.equals(object.getSubExpressions().size(), 1);
+
+        return this.doSwitch(object.getSubExpressions().get(0));
+    }
+
+    @Override
+    public String caseXorExpression(final XorExpression object) {
+        Objects.equals(object.getSubExpressions().size(), 1);
+
+        return this.doSwitch(object.getSubExpressions().get(0));
+    }
+
+    @Override
+    public String caseAndExpression(final AndExpression object) {
+        Objects.equals(object.getSubExpressions().size(), 1);
+
+        return this.doSwitch(object.getSubExpressions().get(0));
+    }
+
+    @Override
+    public String caseNotExpression(final NotExpression object) {
+        return this.doSwitch(object.getOperand());
+    }
+
+    @Override
+    public String caseComparisonExpression(final ComparisonExpression object) {
+        Objects.equals(object.getComparison().size(), 0);
+
+        return this.doSwitch(object.getLeftOperand());
+    }
+
+    @Override
+    public String caseAddOrSubtractExpression(AddOrSubtractExpression object) {
+        Objects.equals(object.getOperators().size(), 0);
+
+        return this.doSwitch(object.getLeftOperand());
+    }
+
+    @Override
+    public String caseMultiplyDivideModuloExpression(MultiplyDivideModuloExpression object) {
+        Objects.equals(object.getOperators().size(), 0);
+
+        return this.doSwitch(object.getLeftOperand());
+    }
+
+    @Override
+    public String casePowerOfExpression(PowerOfExpression object) {
+        Objects.isNull(object.getRightOperand());
+
+        return this.doSwitch(object.getLeftOperand());
+    }
+
+    @Override
+    public String caseUnaryAddOrSubtractExpression(UnaryAddOrSubtractExpression object) {
+        Objects.equals(object.getOperators().size(), 0);
+
+        return this.doSwitch(object.getSubExpression());
+    }
+    /*
+        @Override
+        public String caseCallOrLiteralOrReferenceOrParantheses(CallOrLiteralOrReferenceOrParantheses object) {
+            return super.caseCallOrLiteralOrReferenceOrParantheses(object);
+        }
+    */
+
+    @Override
+    public String caseIntegerLiteral(final IntegerLiteral object) {
+        throw new IllegalStateException("Searching for String but found a integer literal.");
+    }
+
+    @Override
+    public String caseDoubleLiteral(final DoubleLiteral object) {
+        throw new IllegalStateException("Searching for String but found a double literal.");
+    }
+
+    @Override
+    public String caseStringLiteral(StringLiteral object) {
+        return object.getValue();
+    }
+
+    @Override
+    public String caseBooleanLiteral(BooleanLiteral object) {
+        throw new IllegalStateException("Searching for String but found a boolean literal.");
+    }
+
+    @Override
+    public String caseCall(final Call object) {
+        throw new IllegalStateException("Searching for String but found a call.");
+    }
+
+    @Override
+    public String caseParantheses(Parantheses object) {
+        return this.doSwitch(object.getSubExpression());
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/el/ValueReferenceSwitch.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/el/ValueReferenceSwitch.java
new file mode 100644
index 0000000000000000000000000000000000000000..c8f08541c24bf5e3ae2bd8a5e1edc4c7cac2f504
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ddl/el/ValueReferenceSwitch.java
@@ -0,0 +1,116 @@
+package de.evoal.core.main.ddl.el;
+
+import de.evoal.languages.model.eal.DataReference;
+import de.evoal.languages.model.el.*;
+import de.evoal.languages.model.el.util.ELSwitch;
+
+import java.util.Objects;
+
+public class ValueReferenceSwitch extends ELSwitch<String> {
+    @Override
+    public String caseOrExpression(final OrExpression object) {
+        Objects.equals(object.getSubExpressions().size(), 1);
+
+        return this.doSwitch(object.getSubExpressions().get(0));
+    }
+
+    @Override
+    public String caseXorExpression(XorExpression object) {
+        Objects.equals(object.getSubExpressions().size(), 1);
+
+        return this.doSwitch(object.getSubExpressions().get(0));
+    }
+
+    @Override
+    public String caseAndExpression(AndExpression object) {
+        Objects.equals(object.getSubExpressions().size(), 1);
+
+        return this.doSwitch(object.getSubExpressions().get(0));
+    }
+
+    @Override
+    public String caseNotExpression(NotExpression object) {
+        return this.doSwitch(object.getOperand());
+    }
+
+    @Override
+    public String caseComparisonExpression(ComparisonExpression object) {
+        Objects.equals(object.getComparison().size(), 0);
+
+        return this.doSwitch(object.getLeftOperand());
+    }
+
+    @Override
+    public String caseAddOrSubtractExpression(AddOrSubtractExpression object) {
+        Objects.equals(object.getOperators().size(), 0);
+
+        return this.doSwitch(object.getLeftOperand());
+    }
+
+    @Override
+    public String caseMultiplyDivideModuloExpression(MultiplyDivideModuloExpression object) {
+        Objects.equals(object.getOperators().size(), 0);
+
+        return this.doSwitch(object.getLeftOperand());
+    }
+
+    @Override
+    public String casePowerOfExpression(PowerOfExpression object) {
+        Objects.isNull(object.getRightOperand());
+
+        return this.doSwitch(object.getLeftOperand());
+    }
+
+    @Override
+    public String caseUnaryAddOrSubtractExpression(UnaryAddOrSubtractExpression object) {
+        Objects.equals(object.getOperators().size(), 0);
+
+        return this.doSwitch(object.getSubExpression());
+    }
+    /*
+        @Override
+        public String caseCallOrLiteralOrReferenceOrParantheses(CallOrLiteralOrReferenceOrParantheses object) {
+            return super.caseCallOrLiteralOrReferenceOrParantheses(object);
+        }
+    */
+
+    @Override
+    public String caseIntegerLiteral(final IntegerLiteral object) {
+        throw new IllegalStateException("Searching for a value reference but found a integer literal.");
+    }
+
+    @Override
+    public String caseDoubleLiteral(final DoubleLiteral object) {
+        throw new IllegalStateException("Searching for a value reference but found a double literal.");
+    }
+
+    @Override
+    public String caseStringLiteral(StringLiteral object) {
+        throw new IllegalStateException("Searching for a value reference but found a string literal.");
+    }
+
+    @Override
+    public String caseBooleanLiteral(BooleanLiteral object) {
+        throw new IllegalStateException("Searching for a value reference but found a boolean literal.");
+    }
+
+    @Override
+    public String caseCall(final Call object) {
+        throw new IllegalStateException("Searching for a value reference but found a call.");
+    }
+
+    @Override
+    public String caseParantheses(Parantheses object) {
+        return this.doSwitch(object.getSubExpression());
+    }
+
+    @Override
+    public String caseValueReference(final ValueReference object) {
+        if(!(object instanceof DataReference)) {
+            throw new IllegalStateException("Value reference is not a data reference.");
+        }
+
+        final DataReference reference = (DataReference)object;
+        return reference.getDefinition().getName();
+    }
+}
\ No newline at end of file
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/AltererFactory.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/AltererFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..26927ebf0828c35d89b75bf8ec173f6635430291
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/AltererFactory.java
@@ -0,0 +1,195 @@
+package de.evoal.core.main.ea.alterer;
+
+import java.util.function.BiFunction;
+
+import de.evoal.core.main.ea.alterer.internal.MeanCorrelationAlterer;
+import de.evoal.core.main.ea.alterer.crossover.*;
+import de.evoal.core.main.ea.functions.correlation.model.Correlations;
+import de.evoal.languages.model.instance.Instance;
+import de.evoal.core.api.utils.LanguageHelper;
+import de.evoal.core.main.ea.alterer.mutator.SingleBitFlipCorrelationMutator;
+import de.evoal.core.main.ea.alterer.mutator.SingleBitFlipMutator;
+import de.evoal.core.main.ea.alterer.mutator.SwapCorrelationMutator;
+import de.evoal.core.api.ea.fitness.type.FitnessType;
+import io.jenetics.*;
+import io.jenetics.util.Mean;
+import javax.enterprise.context.ApplicationScoped;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.inject.Inject;
+
+@ApplicationScoped
+@Slf4j
+public class AltererFactory {
+
+	@Inject
+	private Correlations correlations;
+
+	@Inject
+	private BiFunction<Double, Double, Alterer> factory;
+
+	/**
+	 * Creates an alterer based on the heuristic configuration.
+	 *
+	 * Blackboard slots used:
+	 * <ul>
+	 *   <li>None</li>
+	 * </ul>
+	 */
+	public <G extends Gene<?, G>> Alterer<G, FitnessType> create(final Instance config) {
+		final String name = LanguageHelper.lookup(config, "name");
+
+		log.info("Creating alterer with name '{}'.", name);
+
+		switch(name) {
+			//case "CompositeAlterer": return createCompositeAlterer(config);
+			case "mean_alterer": return createMeanAlterer(config);
+			case "correlation_mean_alterer": return (Alterer<G, FitnessType>) createCorrelationMeanAlterer(config);
+			case "partial_matched_alterer": return createPartiallyMatchedAlterer(config);
+			case "correlation_partial_matched_alterer": return createCorrelationPartiallyMatchedAlterer(config);
+
+			case "gaussian_mutator": return createGaussianMutator(config);
+			case "correlation_gaussian_mutator": return createGaussianCorrelationMutator(config);
+			case "swap_mutator": return createSwapMutator(config);
+			case "correlation_swap_mutator": return createCorrelationSwapMutator(config);
+			case "bit_flip_mutator": return createBitFlipMutator(config);
+			case "correlation_bit_flip_mutator": return createCorrelationBitFlipMutator(config);
+
+//			case "IntermediateCrossover": return createIntermediateCrossover(config);
+			case "line_crossover": return createLineCrossover(config);
+			case "correlation_line_crossover": return createCorrelationLineCrossover(config);
+			case "multi_point_crossover": return createMultiPointCrossover(config);
+			case "correlation_multi_point_crossover": return createCorrelationMultiPointCrossover(config);
+			case "single_point_crossover": return createSinglePointCrossover(config);
+			case "correlation_single_point_crossover": return createCorrelationSinglePointCrossover(config);
+			case "uniform_crossover": return createUniformCrossover(config);
+			case "correlation_uniform_crossover": return createCorrelationUniformCrossover(config);
+		}
+		throw new IllegalStateException("Selector '" + name + "' is unknown.");
+	}
+
+	private <G extends Gene<?, G>> Alterer<G, FitnessType> createUniformCrossover(final Instance config) {
+		final Double crossoverProbability = LanguageHelper.lookup(config, "crossover_probability");
+		final Double swapProbability = LanguageHelper.lookup(config,"swap_probability");
+
+		return new UniformCrossover<>(crossoverProbability, swapProbability);
+	}
+
+	private <G extends Gene<?, G>> Alterer<G, FitnessType> createCorrelationUniformCrossover(final Instance config) {
+		final Double crossoverProbability = LanguageHelper.lookup(config, "crossover_probability");
+		final Double swapProbability = LanguageHelper.lookup(config,"swap_probability");
+		
+		return new UniformCorrelationCrossover(crossoverProbability, swapProbability, correlations);
+	}
+
+	private <G extends Gene<?, G>> Alterer<G, FitnessType> createBitFlipMutator (final Instance config) {
+		final Double probability = LanguageHelper.lookup(config, "probability");
+
+		return new SingleBitFlipMutator(probability);
+	}
+
+	private <G extends Gene<?, G>> Alterer<G, FitnessType> createCorrelationBitFlipMutator (final Instance config) {
+		final Double probability = LanguageHelper.lookup(config, "probability");
+		final Double threshold = LanguageHelper.lookup(config, "threshold");
+
+		return new SingleBitFlipCorrelationMutator(probability, threshold, correlations);
+	}
+
+	private <G extends Gene<?, G>> Alterer<G, FitnessType> createSwapMutator (final Instance config) {
+		final Double probability = LanguageHelper.lookup(config, "probability");
+
+		return new SwapMutator<>(probability);
+	}
+
+	private <G extends Gene<?, G>> Alterer<G, FitnessType> createCorrelationSwapMutator (final Instance config) {
+		final Double probability = LanguageHelper.lookup(config, "probability");
+		final Double threshold = LanguageHelper.lookup(config, "threshold");
+
+		return new SwapCorrelationMutator<>(probability, threshold, correlations);
+	}
+
+	private <G extends Gene<?, G>> Alterer<G, FitnessType> createSinglePointCrossover(final Instance config) {
+		final Double probability = LanguageHelper.lookup(config, "probability");
+
+		return new SinglePointCrossover<>(probability);
+	}
+
+	private <G extends Gene<?, G>> Alterer<G, FitnessType> createCorrelationSinglePointCrossover(final Instance config) {
+		final Double probability = LanguageHelper.lookup(config, "probability");
+
+		return new SinglePointCorrelationCrossover(probability, correlations);
+	}
+
+	private <G extends Gene<?, G>> Alterer<G, FitnessType> createPartiallyMatchedAlterer(final Instance config) {
+		final Double probability = LanguageHelper.lookup(config, "probability");
+
+		return (Alterer<G, FitnessType>) new PartiallyMatchedCrossover(probability);
+	}
+
+	private <G extends Gene<?, G>> Alterer<G, FitnessType> createCorrelationPartiallyMatchedAlterer(final Instance config) {
+		final Double probability = LanguageHelper.lookup(config, "probability");
+
+		return (Alterer<G, FitnessType>) new PartiallyMatchedCorrelationCrossover<G, FitnessType>(probability, correlations);
+	}
+
+	private <G extends Gene<?, G>> Alterer<G, FitnessType> createMultiPointCrossover(final Instance config) {
+		final Double probability = LanguageHelper.lookup(config, "probability");
+		final Integer count = LanguageHelper.lookup(config, "count");
+
+		return new MultiPointCrossover<>(probability, count);
+	}
+
+	private <G extends Gene<?, G>> Alterer<G, FitnessType> createCorrelationMultiPointCrossover(final Instance config) {
+		final Double probability = LanguageHelper.lookup(config, "probability");
+		final Integer count = LanguageHelper.lookup(config, "count");
+
+		return new MultiPointCorrelationCrossover<>(probability, count, correlations);
+	}
+
+	private <G extends Gene<?, G>> Alterer<G, FitnessType> createMeanAlterer(final Instance config) {
+		final Double probability = LanguageHelper.lookup(config, "probability");
+
+		return  (Alterer<G, FitnessType>) new MeanAlterer(probability);
+	}
+
+	private <G extends NumericGene<?, G> & Mean<G>> Alterer<G, FitnessType> createCorrelationMeanAlterer(final Instance config) {
+		final Double probability = LanguageHelper.lookup(config, "probability");
+
+		return  (Alterer<G, FitnessType>) new MeanCorrelationAlterer<G, FitnessType>(probability, correlations);
+	}
+
+	private <G extends Gene<?, G>> Alterer<G, FitnessType> createLineCrossover(final Instance config) {
+		final Double probability = LanguageHelper.lookup(config, "probability");
+		final Double position = LanguageHelper.lookup(config, "position");
+
+		return new LineCrossover(probability, position);
+	}
+
+	private <G extends Gene<?, G>> Alterer<G, FitnessType> createCorrelationLineCrossover(final Instance config) {
+		final Double probability = LanguageHelper.lookup(config, "probability");
+		final Double position = LanguageHelper.lookup(config, "position");
+
+		return new LineCorrelationCrossover(probability, position, correlations);
+	}
+
+	private <G extends Gene<?, G>> Alterer<G, FitnessType> createIntermediateCrossover(final Instance config) {
+		throw new IllegalStateException("Unsupported alterer.");
+	}
+
+	private <G extends Gene<?,G>> Alterer<G, FitnessType> createGaussianMutator(final Instance config) {
+		final Double probability = LanguageHelper.lookup(config, "probability");
+		
+		return  new GaussianMutator(probability);
+	}
+
+	private <G extends Gene<?, G>> Alterer<G, FitnessType> createGaussianCorrelationMutator(final Instance config) {
+		final Double probability = LanguageHelper.lookup(config, "probability");
+		final Double threshold = LanguageHelper.lookup(config, "threshold");
+
+		return factory.apply(probability, threshold);
+	}
+
+	private <G extends Gene<?, G>> Alterer<G, FitnessType> createCompositeAlterer(final Instance config) {
+		throw new IllegalStateException("Unsupported alterer.");
+	}
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/crossover/CorrelationCrossover.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/crossover/CorrelationCrossover.java
new file mode 100644
index 0000000000000000000000000000000000000000..c5748e3c755ac5c2af2393cc03f3dff2f0ba8143
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/crossover/CorrelationCrossover.java
@@ -0,0 +1,106 @@
+package de.evoal.core.main.ea.alterer.crossover;
+
+import de.evoal.core.main.ea.functions.correlation.model.Correlation;
+import de.evoal.core.main.ea.functions.correlation.model.Correlations;
+import io.jenetics.*;
+import io.jenetics.util.MSeq;
+import io.jenetics.util.RandomRegistry;
+
+import java.util.random.RandomGenerator;
+
+import static java.lang.Math.min;
+
+public abstract class CorrelationCrossover<
+        G extends Gene<?, G>,
+        C extends Comparable<? super C>,
+        M extends CorrelationCrossoverMemento<M>
+        >
+        extends Recombinator<G, C> {
+
+    private final Correlations<G> correlations;
+
+    /**
+     * Constructs an alterer with a given recombination probability.
+     *
+     * @param probability the recombination probability
+     * @throws IllegalArgumentException if the {@code probability} is not in the
+     *          valid range of {@code [0, 1]}
+     */
+    protected CorrelationCrossover(final double probability, final Correlations correlations) {
+        super(probability, 2);
+        
+        this.correlations = correlations;
+    }
+
+    @Override
+    protected final int recombine(
+            final MSeq<Phenotype<G, C>> population,
+            final int[] individuals,
+            final long generation
+    ) {
+        assert individuals.length == 2 : "Required order of 2";
+        final RandomGenerator random = RandomRegistry.random();
+
+        final var pt1 = population.get(individuals[0]);
+        final var pt2 = population.get(individuals[1]);
+        final var gt1 = pt1.genotype();
+        final var gt2 = pt2.genotype();
+
+        //Choosing the Chromosome index for crossover.
+        final int chIndex = random.nextInt(min(gt1.length(), gt2.length()));
+        final int rootIndex = correlations.findCorrelationRoot(gt1, chIndex);
+
+        final var c1 = MSeq.of(gt1);
+        final var c2 = MSeq.of(gt2);
+
+        final var memento = newCrossoverMemento();
+
+        final var correlationOrder = crossover(gt1, gt2, c1, c2, rootIndex, memento);
+
+        //Creating two new Phenotypes and exchanging it with the old.
+        population.set(
+                individuals[0],
+                Phenotype.of(Genotype.of(c1), generation)
+        );
+        population.set(
+                individuals[1],
+                Phenotype.of(Genotype.of(c2), generation)
+        );
+
+        return correlationOrder;
+    }
+
+    private int crossover(final Genotype<G> gt1, final Genotype<G> gt2, final MSeq<Chromosome<G>> c1, final MSeq<Chromosome<G>> c2, final int chIndex, final M memento) {
+        final var genes1 = MSeq.of(c1.get(chIndex));
+        final var genes2 = MSeq.of(c2.get(chIndex));
+
+        int correlationOrder = crossover(memento, genes1, genes2);
+
+        c1.set(chIndex, c1.get(chIndex).newInstance(genes1.toISeq()));
+        c2.set(chIndex, c2.get(chIndex).newInstance(genes2.toISeq()));
+
+        for(final Correlation correlation : correlations.find(gt1, chIndex)) {
+            final int targetIndex = correlation.getChromosomeTwo();
+
+            correlationOrder += crossover(gt1, gt2, c1, c2, targetIndex, newCrossoverMemento().apply(memento, correlation)); // sum up correlations
+        }
+
+        return correlationOrder;
+    }
+
+    /**
+     * @return A valid and initialized crossover memento.
+     */
+    protected abstract M newCrossoverMemento();
+
+    /**
+     * Template method which performs the crossover. The arguments given are
+     * mutable non null arrays of the same length.
+     *
+     * @oaram memento the crossover memento to be applied
+     * @param that the genes of the first chromosome
+     * @param other the genes of the other chromosome
+     * @return the number of altered genes
+     */
+    protected abstract int crossover(final M memento, final MSeq<G> that, final MSeq<G> other);
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/crossover/CorrelationCrossoverMemento.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/crossover/CorrelationCrossoverMemento.java
new file mode 100644
index 0000000000000000000000000000000000000000..929b221040152b4265d780b6016b9ce2b77f2995
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/crossover/CorrelationCrossoverMemento.java
@@ -0,0 +1,11 @@
+package de.evoal.core.main.ea.alterer.crossover;
+
+import de.evoal.core.main.ea.functions.correlation.model.Correlation;
+
+public interface CorrelationCrossoverMemento<T extends CorrelationCrossoverMemento<T>> {
+
+    /**
+     * Applies the given memento with according to the correlation to this memento.
+     */
+    public T apply(final T memento, final Correlation correlation);
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/crossover/LineCorrelationCrossover.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/crossover/LineCorrelationCrossover.java
new file mode 100644
index 0000000000000000000000000000000000000000..a044d67736bd3cea7c90ed15c8be74f51f504ab4
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/crossover/LineCorrelationCrossover.java
@@ -0,0 +1,82 @@
+package de.evoal.core.main.ea.alterer.crossover;
+
+import de.evoal.core.api.utils.Requirements;
+import de.evoal.core.main.ea.functions.correlation.model.Correlations;
+import io.jenetics.NumericGene;
+import io.jenetics.util.MSeq;
+
+import static java.lang.Math.min;
+import static java.lang.String.format;
+
+public class LineCorrelationCrossover<
+        G extends NumericGene<?, G>,
+        C extends Comparable<? super C>
+        > extends CorrelationCrossover<G, C, LineCorrelationCrossoverMemento> {
+    private final double _p;
+
+    /**
+     * Creates a new linear-crossover with the given recombination
+     * probability and the line-scaling factor <em>p</em>.
+     *
+     * @param probability the recombination probability.
+     * @param p defines the possible location of the recombined chromosomes. If
+     *        <em>p</em> = 0 then the children will be located along the line
+     *        within the hypercube between the two points. If <em>p</em> &gt; 0
+     *        then the children may be located anywhere on the line, even
+     *        somewhat outside of the hypercube.
+     * @throws IllegalArgumentException if the {@code probability} is not in the
+     *         valid range of {@code [0, 1]} or if {@code p} is smaller then zero
+     */
+    public LineCorrelationCrossover(final double probability, final double p, final Correlations correlations) {
+        super(probability, correlations);
+        _p = Requirements.nonNegative(p);
+    }
+
+    /**
+     * Creates a new linear-crossover with the given recombination
+     * probability. The parameter <em>p</em> is set to zero, which restricts the
+     * recombined chromosomes within the hypercube of the selected chromosomes
+     * (vectors).
+     *
+     * @param probability the recombination probability.
+     * @throws IllegalArgumentException if the {@code probability} is not in the
+     *         valid range of {@code [0, 1]}
+     */
+    public LineCorrelationCrossover(final double probability, final Correlations correlations) {
+        this(probability, 0, correlations);
+    }
+
+    @Override
+    protected int crossover(final LineCorrelationCrossoverMemento memento, final MSeq<G> v, final MSeq<G> w) {
+        final double min = v.get(0).min().doubleValue();
+        final double max = v.get(0).max().doubleValue();
+
+
+        boolean changed = false;
+        for (int i = 0, n = min(v.length(), w.length()); i < n; ++i) {
+            final double vi = v.get(i).doubleValue();
+            final double wi = w.get(i).doubleValue();
+
+            final double t = memento.getA() * vi + (1 - memento.getA()) * wi;
+            final double s = memento.getB() * wi + (1 - memento.getB()) * vi;
+
+            if (t >= min && s >= min && t < max && s < max) {
+                v.set(i, v.get(i).newInstance(t));
+                w.set(i, w.get(i).newInstance(s));
+                changed = true;
+            }
+        }
+
+        return changed ? 2 : 0;
+    }
+
+    @Override
+    public String toString() {
+        return format("%s[p=%f]", getClass().getSimpleName(), _probability);
+    }
+
+    @Override
+    protected LineCorrelationCrossoverMemento newCrossoverMemento() {
+        return new LineCorrelationCrossoverMemento(_p);
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/crossover/LineCorrelationCrossoverMemento.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/crossover/LineCorrelationCrossoverMemento.java
new file mode 100644
index 0000000000000000000000000000000000000000..3ddd0104a2322b2b0a7ace35e6faccf74dd82b05
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/crossover/LineCorrelationCrossoverMemento.java
@@ -0,0 +1,24 @@
+package de.evoal.core.main.ea.alterer.crossover;
+
+import de.evoal.core.main.ea.functions.correlation.model.Correlation;
+import io.jenetics.util.RandomRegistry;
+import lombok.Data;
+
+import java.util.random.RandomGenerator;
+
+@Data
+public class LineCorrelationCrossoverMemento implements CorrelationCrossoverMemento<LineCorrelationCrossoverMemento> {
+    private double a;
+    private double b;
+
+    public LineCorrelationCrossoverMemento(final double probability) {
+        final RandomGenerator random = RandomRegistry.random();
+        random.nextDouble(-probability, 1 + probability);
+        random.nextDouble(-probability, 1 + probability);
+    }
+
+    @Override
+    public LineCorrelationCrossoverMemento apply(LineCorrelationCrossoverMemento memento, Correlation correlation) {
+        return this;
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/crossover/MultiPointCorrelationCrossover.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/crossover/MultiPointCorrelationCrossover.java
new file mode 100644
index 0000000000000000000000000000000000000000..b829f6dfab02fcd31a5fda7c26fd72aa88ba9beb
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/crossover/MultiPointCorrelationCrossover.java
@@ -0,0 +1,114 @@
+package de.evoal.core.main.ea.alterer.crossover;
+
+import de.evoal.core.main.ea.functions.correlation.model.Correlations;
+import io.jenetics.Gene;
+import io.jenetics.util.MSeq;
+
+import static java.lang.Math.min;
+import static java.lang.String.format;
+
+public class MultiPointCorrelationCrossover<
+        G extends Gene<?, G>,
+        C extends Comparable<? super C>,
+        M extends MultiPointCorrelationCrossoverMemento<M>
+        > extends CorrelationCrossover<G, C, M> {
+    private final int _n;
+
+    /**
+     * Create a new crossover instance.
+     *
+     * @param probability the recombination probability.
+     * @param n the number of crossover points.
+     * @throws IllegalArgumentException if the {@code probability} is not in the
+     *         valid range of {@code [0, 1]} or {@code n &lt; 1}.
+     */
+    public MultiPointCorrelationCrossover(final double probability, final int n, final Correlations correlations) {
+        super(probability, correlations);
+        if (n < 1) {
+            throw new IllegalArgumentException(format(
+                    "n must be at least 1 but was %d.", n
+            ));
+        }
+        _n = n;
+    }
+
+    /**
+     * Create a new crossover instance with two crossover points.
+     *
+     * @param probability the recombination probability.
+     * @throws IllegalArgumentException if the {@code probability} is not in the
+     *         valid range of {@code [0, 1]}.
+     */
+    public MultiPointCorrelationCrossover(final double probability, final Correlations correlations) {
+        this(probability, 2, correlations);
+    }
+
+    /**
+     * Create a new crossover instance with default crossover probability of
+     * 0.05.
+     *
+     * @param n the number of crossover points.
+     * @throws IllegalArgumentException if {@code n &lt; 1}.
+     */
+    public MultiPointCorrelationCrossover(final int n, final Correlations correlations) {
+        this(0.05, n, correlations);
+    }
+
+    /**
+     * Create a new crossover instance with two crossover points and crossover
+     * probability 0.05.
+     */
+    public MultiPointCorrelationCrossover(final Correlations correlations) {
+        this(0.05, 2, correlations);
+    }
+
+    /**
+     * Return the number of crossover points.
+     *
+     * @return the number of crossover points.
+     */
+    public int crossoverPointCount() {
+        return _n;
+    }
+
+    @Override
+    protected int crossover(final M memento, final MSeq<G> that, final MSeq<G> other) {
+        assert that.length() == other.length();
+
+        final int[] points = memento.getCrossoverPoints(that.length(), other.length(), _n);
+
+        crossover(that, other, points);
+        return 2;
+    }
+
+    @Override
+    protected M newCrossoverMemento() {
+        return (M)new MultiPointCorrelationCrossoverMemento();
+    }
+
+    // Package private for testing purpose.
+    static <T> void crossover(
+            final MSeq<T> that,
+            final MSeq<T> other,
+            final int[] indexes
+    ) {
+
+        for (int i = 0; i < indexes.length - 1; i += 2) {
+            final int start = indexes[i];
+            final int end = indexes[i + 1];
+            that.swap(start, end, other, start);
+        }
+        if (indexes.length%2 == 1) {
+            final int index = indexes[indexes.length - 1];
+            that.swap(index, min(that.length(), other.length()), other, index);
+        }
+    }
+
+    @Override
+    public String toString() {
+        return format(
+                "%s[p=%f, n=%d]",
+                getClass().getSimpleName(), _probability, _n
+        );
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/crossover/MultiPointCorrelationCrossoverMemento.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/crossover/MultiPointCorrelationCrossoverMemento.java
new file mode 100644
index 0000000000000000000000000000000000000000..1bdf0e05649590e1b82e6e4b5eb5b704cb28cffe
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/crossover/MultiPointCorrelationCrossoverMemento.java
@@ -0,0 +1,30 @@
+package de.evoal.core.main.ea.alterer.crossover;
+
+import de.evoal.core.main.ea.functions.correlation.model.Correlation;
+import io.jenetics.internal.math.Subset;
+import io.jenetics.util.RandomRegistry;
+
+import java.util.random.RandomGenerator;
+
+import static java.lang.Math.min;
+
+public class MultiPointCorrelationCrossoverMemento<T extends MultiPointCorrelationCrossoverMemento<T>> implements CorrelationCrossoverMemento<T> {
+    private int[] points = null;
+
+    public int[] getCrossoverPoints(final int thatLength, final int otherLength, final int count) {
+        if(points == null) {
+            final int n = min(thatLength, otherLength);
+            final int k = min(n, count);
+
+            final RandomGenerator random = RandomRegistry.random();
+            points = k > 0 ? Subset.next(n, k, random) : new int[0];
+        }
+
+        return points;
+    }
+
+    @Override
+    public T apply(final T memento, final Correlation correlation) {
+        return (T)this;
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/crossover/PartiallyMatchedCorrelationCrossover.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/crossover/PartiallyMatchedCorrelationCrossover.java
new file mode 100644
index 0000000000000000000000000000000000000000..66977b3bdcc2b8a678711c9e6ffd607ab28c841e
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/crossover/PartiallyMatchedCorrelationCrossover.java
@@ -0,0 +1,73 @@
+package de.evoal.core.main.ea.alterer.crossover;
+
+import de.evoal.core.main.ea.functions.correlation.model.Correlations;
+import io.jenetics.EnumGene;
+import io.jenetics.util.MSeq;
+
+import static java.lang.String.format;
+
+public class PartiallyMatchedCorrelationCrossover<
+        T,
+        C extends Comparable<? super C>
+> extends CorrelationCrossover<EnumGene<T>, C, PartiallyMatchedCorrelationCrossoverMemento>
+{
+
+    public PartiallyMatchedCorrelationCrossover(final double probability, final Correlations correlations) {
+        super(probability, correlations);
+    }
+
+    @Override
+    protected PartiallyMatchedCorrelationCrossoverMemento newCrossoverMemento() {
+        return new PartiallyMatchedCorrelationCrossoverMemento();
+    }
+
+    @Override
+    protected int crossover(
+            final PartiallyMatchedCorrelationCrossoverMemento memento,
+            final MSeq<EnumGene<T>> that,
+            final MSeq<EnumGene<T>> other
+    ) {
+        if (that.length() != other.length()) {
+            throw new IllegalArgumentException(format(
+                    "Required chromosomes with same length: %s != %s",
+                    that.length(), other.length()
+            ));
+        }
+
+        if (that.length() >= 2) {
+            final int[] points = memento.getCrossoverPoints(that.length());
+
+            that.swap(points[0], points[1], other, points[0]);
+            repair(that, other, points[0], points[1]);
+            repair(other, that, points[0], points[1]);
+        }
+
+        return 1;
+    }
+
+    private static <T> void repair(
+            final MSeq<T> that, final MSeq<T> other,
+            final int begin, final int end
+    ) {
+        for (int i = 0; i < begin; ++i) {
+            int index = that.indexOf(that.get(i), begin, end);
+            while (index != -1) {
+                that.set(i, other.get(index));
+                index = that.indexOf(that.get(i), begin, end);
+            }
+        }
+        for (int i = end, n = that.length(); i < n; ++i) {
+            int index = that.indexOf(that.get(i), begin, end);
+            while (index != -1) {
+                that.set(i, other.get(index));
+                index = that.indexOf(that.get(i), begin, end);
+            }
+        }
+    }
+
+    @Override
+    public String toString() {
+        return format("%s[p=%f]", getClass().getSimpleName(), _probability);
+    }
+
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/crossover/PartiallyMatchedCorrelationCrossoverMemento.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/crossover/PartiallyMatchedCorrelationCrossoverMemento.java
new file mode 100644
index 0000000000000000000000000000000000000000..84615c0a4373c413a7956bc8fc0ba07c46aa7d9f
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/crossover/PartiallyMatchedCorrelationCrossoverMemento.java
@@ -0,0 +1,28 @@
+package de.evoal.core.main.ea.alterer.crossover;
+
+import de.evoal.core.main.ea.functions.correlation.model.Correlation;
+import io.jenetics.internal.math.Subset;
+import io.jenetics.util.RandomRegistry;
+
+import java.util.Random;
+import java.util.random.RandomGenerator;
+
+import static java.lang.Math.min;
+
+public class PartiallyMatchedCorrelationCrossoverMemento implements CorrelationCrossoverMemento<PartiallyMatchedCorrelationCrossoverMemento> {
+    private int[] points = null;
+
+    public int[] getCrossoverPoints(final int thatLength) {
+        if(points == null) {
+            final RandomGenerator random = RandomRegistry.random();
+            points = Subset.next(thatLength, 2, random);
+        }
+
+        return points;
+    }
+
+    @Override
+    public PartiallyMatchedCorrelationCrossoverMemento apply(PartiallyMatchedCorrelationCrossoverMemento memento, Correlation correlation) {
+        return this;
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/crossover/SinglePointCorrelationCrossover.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/crossover/SinglePointCorrelationCrossover.java
new file mode 100644
index 0000000000000000000000000000000000000000..42957f149aebabf7745ea41b361befadf82547a8
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/crossover/SinglePointCorrelationCrossover.java
@@ -0,0 +1,57 @@
+package de.evoal.core.main.ea.alterer.crossover;
+
+import de.evoal.core.main.ea.functions.correlation.model.Correlations;
+import io.jenetics.Gene;
+import io.jenetics.util.MSeq;
+
+
+import static java.lang.String.format;
+
+public class SinglePointCorrelationCrossover<
+        A,
+        G extends Gene<A, G>,
+        C extends Comparable<? super C>
+> extends MultiPointCorrelationCrossover<G, C, SinglePointCorrelationCrossoverMemento>  {
+
+    /**
+     * Constructs an alterer with a given recombination probability.
+     *
+     * @param probability the crossover probability.
+     * @throws IllegalArgumentException if the {@code probability} is not in the
+     *         valid range of {@code [0, 1]}.
+     */
+    public SinglePointCorrelationCrossover(final double probability, final Correlations correlations) {
+        super(probability, 1, correlations);
+    }
+
+    @Override
+    protected int crossover(final SinglePointCorrelationCrossoverMemento memento, final MSeq<G> that, final MSeq<G> other) {
+        final int index = memento.getIndex(that.length(), other.length());
+
+        if(SinglePointCorrelationCrossoverMemento.BetterChromsome.FIRST.equals(memento.getSelect())) {
+            copy(other, that, index, that.length() - index, index);
+        } else {
+            copy(that, other, index, that.length() - index, index);
+        }
+
+        return that.length() - index;
+    }
+
+    private void copy(final MSeq<G> source, final MSeq<G> target, final int start, int size, int index) {
+        for(int i = 0; i < size; ++i) {
+            final G gene = source.get(start + i);
+            final A allele = gene.allele();
+            target.set(index + i, gene.newInstance(allele ));
+        }
+    }
+
+    @Override
+    protected SinglePointCorrelationCrossoverMemento newCrossoverMemento() {
+        return new SinglePointCorrelationCrossoverMemento();
+    }
+
+    @Override
+    public String toString() {
+        return format("%s[p=%f]", getClass().getSimpleName(), _probability);
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/crossover/SinglePointCorrelationCrossoverMemento.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/crossover/SinglePointCorrelationCrossoverMemento.java
new file mode 100644
index 0000000000000000000000000000000000000000..53ee1d9aff828f5a989d937594e441a1db9afb2a
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/crossover/SinglePointCorrelationCrossoverMemento.java
@@ -0,0 +1,53 @@
+package de.evoal.core.main.ea.alterer.crossover;
+
+import de.evoal.core.main.ea.functions.correlation.model.Correlation;
+import io.jenetics.util.RandomRegistry;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Random;
+import java.util.random.RandomGenerator;
+
+import static java.lang.Math.min;
+
+public class SinglePointCorrelationCrossoverMemento extends MultiPointCorrelationCrossoverMemento<SinglePointCorrelationCrossoverMemento> {
+    public enum BetterChromsome {
+        FIRST,
+        SECOND
+    }
+
+    private int index = -1;
+
+    @Getter @Setter
+    private BetterChromsome select = BetterChromsome.FIRST;
+
+    public int getIndex(final int thatLength, final int otherLength) {
+        if(index == -1) {
+            final RandomGenerator random = RandomRegistry.random();
+
+            index = random.nextInt(min(thatLength, otherLength));
+        }
+
+        return index;
+    }
+
+
+    @Override
+    public SinglePointCorrelationCrossoverMemento apply(final SinglePointCorrelationCrossoverMemento other, final Correlation correlation) {
+        final double correlationValue = correlation.getCorrelationFactor();
+        final SinglePointCorrelationCrossoverMemento result = new SinglePointCorrelationCrossoverMemento();
+        result.index = other.index;
+
+        if(BetterChromsome.FIRST.equals(other.select) && correlationValue >= 0) {
+            result.select = BetterChromsome.FIRST;
+        } else if(BetterChromsome.FIRST.equals(other.select) && correlationValue < 0) {
+            result.select = BetterChromsome.SECOND;
+        } else if(BetterChromsome.SECOND.equals(other.select) && correlationValue >= 0) {
+            result.select = BetterChromsome.SECOND;
+        } else if(BetterChromsome.SECOND.equals(other.select) && correlationValue < 0) {
+            result.select = BetterChromsome.FIRST;
+        }
+
+        return result;
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/crossover/UniformCorrelationCrossover.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/crossover/UniformCorrelationCrossover.java
new file mode 100644
index 0000000000000000000000000000000000000000..18a6ddd84dca859e95ca58f1bfd3f17ecdf96a79
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/crossover/UniformCorrelationCrossover.java
@@ -0,0 +1,68 @@
+package de.evoal.core.main.ea.alterer.crossover;
+
+import de.evoal.core.api.utils.Requirements;
+import de.evoal.core.main.ea.functions.correlation.model.Correlations;
+import io.jenetics.Gene;
+import io.jenetics.util.MSeq;
+
+import static java.lang.Math.min;
+
+public class UniformCorrelationCrossover<
+        A,
+        G extends Gene<A, G>,
+        C extends Comparable<? super C>
+        > extends  CorrelationCrossover<G, C, UniformCorrelationCrossoverMemento> {
+    private final double _swapProbability;
+
+    /**
+     * Create a new universal crossover instance.
+     *
+     * @param crossoverProbability the recombination probability as defined in
+     *        {@link CorrelationCrossover#CorrelationCrossover(double, Correlations)} . This is the probability that
+     *        a given individual is selected for crossover.
+     * @param swapProbability the probability for swapping a given gene of
+     *         a chromosome
+     * @throws IllegalArgumentException if the probabilities are not in the
+     *         valid range of {@code [0, 1]}
+     */
+    public UniformCorrelationCrossover(
+            final double crossoverProbability,
+            final double swapProbability,
+            final Correlations correlations
+    ) {
+        super(crossoverProbability, correlations);
+
+        Requirements.requireProbability(swapProbability);
+        _swapProbability = swapProbability;
+    }
+
+    @Override
+    protected UniformCorrelationCrossoverMemento newCrossoverMemento() {
+        return new UniformCorrelationCrossoverMemento();
+    }
+
+    @Override
+    protected int crossover(final UniformCorrelationCrossoverMemento memento, final MSeq<G> that, final MSeq<G> other) {
+        final int length = min(that.length(), other.length());
+
+        final int [] indices = memento.getCrossoverPoints(length, _swapProbability);
+
+        for(int index : indices) {
+            if (UniformCorrelationCrossoverMemento.BetterChromsome.FIRST.equals(memento.getSelect())) {
+                copy(other, that, index);
+            } else {
+                copy(that, other, index);
+            }
+        }
+
+        return indices.length;
+    }
+
+    private void copy(final MSeq<G> source, final MSeq<G> target, final int index) {
+        final G gene = source.get(index);
+        final A allele = gene.allele();
+        final G copy = gene.newInstance(allele);
+
+        target.set(index, copy);
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/crossover/UniformCorrelationCrossoverMemento.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/crossover/UniformCorrelationCrossoverMemento.java
new file mode 100644
index 0000000000000000000000000000000000000000..4fe2316e26afa1ca7f113f21aa3e0663c3e626e8
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/crossover/UniformCorrelationCrossoverMemento.java
@@ -0,0 +1,53 @@
+package de.evoal.core.main.ea.alterer.crossover;
+
+import de.evoal.core.main.ea.functions.correlation.model.Correlation;
+import io.jenetics.util.RandomRegistry;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.random.RandomGenerator;
+
+import static io.jenetics.internal.math.Randoms.indexes;
+
+public class UniformCorrelationCrossoverMemento implements CorrelationCrossoverMemento<UniformCorrelationCrossoverMemento> {
+
+    public enum BetterChromsome {
+        FIRST,
+        SECOND
+    }
+
+    private int[] points = null;
+
+    @Getter
+    @Setter
+    private BetterChromsome select = BetterChromsome.FIRST;
+
+    public int[] getCrossoverPoints(final int thatLength, final double probability) {
+        if(points == null) {
+            final RandomGenerator random = RandomRegistry.random();
+            points = indexes(random, thatLength, probability).toArray();
+        }
+
+        return points;
+    }
+
+
+    @Override
+    public UniformCorrelationCrossoverMemento apply(final UniformCorrelationCrossoverMemento other, final Correlation correlation) {
+        final double correlationValue = correlation.getCorrelationFactor();
+        final UniformCorrelationCrossoverMemento result = new UniformCorrelationCrossoverMemento();
+        result.points = other.points;
+
+        if(UniformCorrelationCrossoverMemento.BetterChromsome.FIRST.equals(other.select) && correlationValue >= 0) {
+            result.select = UniformCorrelationCrossoverMemento.BetterChromsome.FIRST;
+        } else if(UniformCorrelationCrossoverMemento.BetterChromsome.FIRST.equals(other.select) && correlationValue < 0) {
+            result.select = UniformCorrelationCrossoverMemento.BetterChromsome.SECOND;
+        } else if(UniformCorrelationCrossoverMemento.BetterChromsome.SECOND.equals(other.select) && correlationValue >= 0) {
+            result.select = UniformCorrelationCrossoverMemento.BetterChromsome.SECOND;
+        } else if(UniformCorrelationCrossoverMemento.BetterChromsome.SECOND.equals(other.select) && correlationValue < 0) {
+            result.select = UniformCorrelationCrossoverMemento.BetterChromsome.FIRST;
+        }
+
+        return result;
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/internal/AbstractCorrelationAlterer.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/internal/AbstractCorrelationAlterer.java
new file mode 100644
index 0000000000000000000000000000000000000000..ec6b6646247e49cf6e1a2c0d348e14ab8d452d48
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/internal/AbstractCorrelationAlterer.java
@@ -0,0 +1,21 @@
+package de.evoal.core.main.ea.alterer.internal;
+
+import io.jenetics.AbstractAlterer;
+import io.jenetics.Gene;
+
+public abstract class AbstractCorrelationAlterer<
+        G extends Gene<?, G>,
+        C extends Comparable<? super C>
+>
+        extends AbstractAlterer<G, C> {
+    /**
+     * Constructs an alterer with a given recombination probability.
+     *
+     * @param probability The recombination probability.
+     * @throws IllegalArgumentException if the {@code probability} is not in the
+     *                                  valid range of {@code [0, 1]}.
+     */
+    protected AbstractCorrelationAlterer(double probability) {
+        super(probability);
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/internal/CorrelationCombineAlterer.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/internal/CorrelationCombineAlterer.java
new file mode 100644
index 0000000000000000000000000000000000000000..0ce3b1c205171223b18207effc725772c8de727c
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/internal/CorrelationCombineAlterer.java
@@ -0,0 +1,137 @@
+package de.evoal.core.main.ea.alterer.internal;
+
+import de.evoal.core.main.ea.functions.correlation.model.Correlation;
+import de.evoal.core.main.ea.functions.correlation.model.Correlations;
+import io.jenetics.*;
+import io.jenetics.util.BaseSeq;
+import io.jenetics.util.MSeq;
+import io.jenetics.util.RandomRegistry;
+
+import java.util.function.BinaryOperator;
+import java.util.random.RandomGenerator;
+
+import static java.lang.Math.min;
+import static java.lang.String.format;
+import static java.util.Objects.requireNonNull;
+
+public abstract class CorrelationCombineAlterer<
+        G extends NumericGene<?, G>,
+        C extends Comparable<? super C>
+        >
+        extends CorrelationRecombinator<G, C>
+{
+
+    private final BinaryOperator<G> _combiner;
+    private final Correlations<G> correlations;
+
+    /**
+     * Create a new combiner alterer with the given arguments.
+     *
+     * @param combiner the function used for combining two genes
+     * @param probability The recombination probability.
+     * @throws IllegalArgumentException if the {@code probability} is not in the
+     *         valid range of {@code [0, 1]}
+     * @throws NullPointerException if the given {@code combiner} is {@code null}
+     */
+    public CorrelationCombineAlterer(
+            final BinaryOperator<G> combiner,
+            final double probability,
+            final Correlations correlations
+    ) {
+        super(probability, 2);
+        _combiner = requireNonNull(combiner);
+        
+        this.correlations = correlations;
+    }
+
+    /**
+     * Create a new combiner alterer with the given arguments.
+     *
+     * @param combiner the function used for combining two genes
+     * @throws IllegalArgumentException if the {@code probability} is not in the
+     *         valid range of {@code [0, 1]}
+     * @throws NullPointerException if the given {@code combiner} is {@code null}
+     */
+    public CorrelationCombineAlterer(final BinaryOperator<G> combiner, final Correlations correlations) {
+        this(combiner, DEFAULT_ALTER_PROBABILITY, correlations );
+    }
+
+    /**
+     * Return the combiner function, used by {@code this} alterer.
+     *
+     * @return the combiner function, used by {@code this} alterer
+     */
+    public BinaryOperator<G> combiner() {
+        return _combiner;
+    }
+
+    @Override
+    protected int recombine(
+            final MSeq<Phenotype<G, C>> population,
+            final int[] individuals,
+            final long generation
+    ) {
+        final RandomGenerator random = RandomRegistry.random();
+
+        final Phenotype<G, C> pt1 = population.get(individuals[0]);
+        final Phenotype<G, C> pt2 = population.get(individuals[1]);
+        final Genotype<G> gt1 = pt1.genotype();
+        final Genotype<G> gt2 = pt2.genotype();
+
+        // choosing a random Chromosome index for crossover.
+        final int randomIndex = random.nextInt(min(gt1.length(), gt2.length()));
+
+        // track the correlations to the first index to handle
+        final int rootIndex = correlations.findCorrelationRoot(gt1, randomIndex);
+
+        return recombine(population, individuals[0], generation, gt1, gt2, rootIndex);
+    }
+
+    private int recombine(final MSeq<Phenotype<G, C>> population, final int individual, final long generation, final Genotype<G> gt1, final Genotype<G> gt2, final int index) {
+        final MSeq<Chromosome<G>> c1 = MSeq.of(gt1);
+        final Chromosome<G> chromosome1 = c1.get(index);
+        final double chromosomeValue1 = getValue(gt1, index);
+
+        // Calculate the mean value of the gene array.
+        final MSeq<G> mean = combine(chromosome1, gt2.get(index), _combiner);
+
+        c1.set(index, c1.get(index).newInstance(mean.toISeq()));
+        population.set(individual, Phenotype.of(Genotype.of(c1), generation));
+
+        int result = 1;
+        for(final Correlation correlation : correlations.find(gt1, index)) {
+            final int index2 = correlation.getChromosomeTwo();
+            final double chromosomeValue2 = getValue(gt1, index2);
+
+            if(!correlation.matchesTarget(index2, chromosomeValue2)) {
+                continue;
+            }
+
+            result += recombine(population, individual, generation, gt1, gt2, index2);
+        }
+
+        return result;
+    }
+
+    private static <G extends Gene<?, G>>
+    MSeq<G> combine(
+            final BaseSeq<G> a,
+            final BaseSeq<G> b,
+            final BinaryOperator<G> combiner
+    ) {
+        final MSeq<G> result = MSeq.ofLength(a.length());
+        for (int i = a.length(); --i >= 0;) {
+            result.set(i, combiner.apply(a.get(i), b.get(i)));
+        }
+        return result;
+    }
+
+    private double getValue(final Genotype<G> genotype, final int index) {
+        return genotype.get(index).gene().doubleValue();
+    }
+
+    @Override
+    public String toString() {
+        return format("%s[p=%f]", getClass().getSimpleName(), _probability);
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/internal/CorrelationRecombinator.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/internal/CorrelationRecombinator.java
new file mode 100644
index 0000000000000000000000000000000000000000..0b05bb86bd62a4181114209d0f0bb5d6f41f9885
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/internal/CorrelationRecombinator.java
@@ -0,0 +1,113 @@
+package de.evoal.core.main.ea.alterer.internal;
+
+import io.jenetics.AltererResult;
+import io.jenetics.Gene;
+import io.jenetics.Phenotype;
+import io.jenetics.internal.math.Subset;
+import io.jenetics.util.MSeq;
+import io.jenetics.util.RandomRegistry;
+import io.jenetics.util.Seq;
+
+import java.util.random.RandomGenerator;
+
+import static io.jenetics.internal.math.Randoms.indexes;
+import static java.lang.String.format;
+
+public abstract class CorrelationRecombinator<
+        G extends Gene<?, G>,
+        C extends Comparable<? super C>
+        >
+        extends AbstractCorrelationAlterer<G, C> {
+    private final int _order;
+
+    /**
+     * Constructs an alterer with a given recombination probability.
+     *
+     * @param probability The recombination probability.
+     * @param order the number of individuals involved in the
+     *        {@link #recombine(MSeq, int[], long)} step
+     * @throws IllegalArgumentException if the {@code probability} is not in the
+     *         valid range of {@code [0, 1]} or the given {@code order} is
+     *         smaller than two.
+     */
+    protected CorrelationRecombinator(final double probability, final int order) {
+        super(probability);
+        if (order < 2) {
+            throw new IllegalArgumentException(format(
+                    "Order must be greater than one, but was %d.", order
+            ));
+        }
+        _order = order;
+    }
+
+    /**
+     * Return the number of individuals involved in the
+     * {@link #recombine(MSeq, int[], long)} step.
+     *
+     * @return the number of individuals involved in the recombination step.
+     */
+    public int order() {
+        return _order;
+    }
+
+    @Override
+    public AltererResult<G, C> alter(
+            final Seq<Phenotype<G, C>> population,
+            final long generation
+    ) {
+        final AltererResult<G, C> result;
+        if (population.size() >= 2) {
+            final RandomGenerator random = RandomRegistry.random();
+            final int order = Math.min(_order, population.size());
+
+            final MSeq<Phenotype<G, C>> pop = MSeq.of(population);
+            final int count = indexes(random, population.size(), _probability)
+                    .mapToObj(i -> individuals(i, population.size(), order, random))
+                    .mapToInt(ind -> recombine(pop, ind, generation))
+                    .sum();
+
+            result = new AltererResult(pop.toISeq(), count);
+        } else {
+            result = new AltererResult(population.asISeq());
+        }
+
+        return result;
+    }
+
+    static int[] individuals(
+            final int index,
+            final int size,
+            final int order,
+            final RandomGenerator random
+    ) {
+        final int[] ind = Subset.next(size, order, random);
+
+        // Find the correct slot for the "master" individual.
+        // This prevents duplicate index entries.
+        int i = 0;
+        while (ind[i] < index && i < ind.length - 1) {
+            ++i;
+        }
+        ind[i] = index;
+
+        return ind;
+    }
+
+    /**
+     * Recombination template method. This method is called 0 to n times. It is
+     * guaranteed that this method is only called by one thread.
+     *
+     * @param population the population to recombine
+     * @param individuals the array with the indexes of the individuals which
+     *        are involved in the <i>recombination</i> step. The length of the
+     *        array is {@link #order()}. The first individual is the
+     *        <i>primary</i> individual.
+     * @param generation the current generation.
+     * @return the number of genes that has been altered.
+     */
+    protected abstract int recombine(
+            final MSeq<Phenotype<G, C>> population,
+            final int[] individuals,
+            final long generation
+    );
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/internal/MeanCorrelationAlterer.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/internal/MeanCorrelationAlterer.java
new file mode 100644
index 0000000000000000000000000000000000000000..d8f44559188c7e4ffb59af2fd2d5be47c32c025b
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/internal/MeanCorrelationAlterer.java
@@ -0,0 +1,31 @@
+package de.evoal.core.main.ea.alterer.internal;
+
+import de.evoal.core.main.ea.functions.correlation.model.Correlations;
+import io.jenetics.*;
+import io.jenetics.util.Mean;
+
+public class MeanCorrelationAlterer<
+        G extends NumericGene<?, G> & Mean<G>,
+        C extends Comparable<? super C>
+> extends CorrelationCombineAlterer<G, C> {
+
+    /**
+     * Constructs an alterer with a given recombination probability.
+     *
+     * @param probability the crossover probability.
+     * @throws IllegalArgumentException if the {@code probability} is not in the
+     *         valid range of {@code [0, 1]}.
+     */
+    public MeanCorrelationAlterer(final double probability, final Correlations correlations) {
+        super((x,y) -> (G)((Mean)x).mean(y), probability, correlations);
+    }
+
+    /**
+     * Create a new alterer with alter probability of {@code 0.05}.
+     */
+    public MeanCorrelationAlterer(final Correlations correlations) {
+        this(0.05, correlations);
+    }
+
+}
+
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/mutator/CorrelationMutator.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/mutator/CorrelationMutator.java
new file mode 100644
index 0000000000000000000000000000000000000000..186e7b94c4b413e55415bd43c0f8547cbc320ab0
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/mutator/CorrelationMutator.java
@@ -0,0 +1,220 @@
+package de.evoal.core.main.ea.alterer.mutator;
+
+import de.evoal.core.main.ea.alterer.internal.AbstractCorrelationAlterer;
+import de.evoal.core.main.ea.functions.correlation.model.Correlation;
+import de.evoal.core.main.ea.functions.correlation.model.Correlations;
+import io.jenetics.*;
+import io.jenetics.internal.math.Probabilities;
+import io.jenetics.util.ISeq;
+import io.jenetics.util.RandomRegistry;
+import io.jenetics.util.Seq;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.random.RandomGenerator;
+
+import static java.lang.Math.pow;
+import static java.lang.String.format;
+
+public abstract class CorrelationMutator<
+        G extends Gene<?, G>,
+        C extends Comparable<? super C>,
+        CC extends CorrelationMutatorMemento
+>
+        extends AbstractCorrelationAlterer<G, C> {
+
+    protected final double threshold;
+    private final Correlations<G> correlations;
+
+    /**
+     * Construct a Mutation object which a given mutation probability.
+     *
+     * @param probability Mutation probability. The given probability is
+     *         divided by the number of chromosomes of the genotype to form
+     *         the concrete mutation probability.
+     * @param threshold Threshold value for strong and weak relations.
+     * @throws IllegalArgumentException if the {@code probability} is not in the
+     *          valid range of {@code [0, 1]}.
+     */
+    protected CorrelationMutator(final double probability, final double threshold, final Correlations correlations) {
+        super(probability);
+        
+        this.correlations = correlations;
+        this.threshold = threshold;
+    }
+
+    /**
+     * Concrete implementation of the alter method. It uses the following
+     * mutation methods: {@link #mutate(Phenotype, long, double, RandomGenerator)},
+     * {@link #mutate(Genotype, double, RandomGenerator)},
+     * {@link #mutate(Chromosome, double, CC, RandomGenerator)}, {@link #mutate(Gene, CC, RandomGenerator)},
+     * in this specific order.
+     *
+     * @see #mutate(Phenotype, long, double, RandomGenerator)
+     * @see #mutate(Genotype, double, RandomGenerator)
+     * @see #mutate(Chromosome, double, CC, RandomGenerator)
+     * @see #mutate(Gene, CC, RandomGenerator)
+     */
+    @Override
+    public AltererResult<G, C> alter(
+            final Seq<Phenotype<G, C>> population,
+            final long generation
+    ) {
+        assert population != null : "Not null is guaranteed from base class.";
+
+        final RandomGenerator random = RandomRegistry.random();
+        final double p = pow(_probability, 1.0/3.0);
+        final int P = Probabilities.toInt(p);
+
+        final Seq<MutatorResult<Phenotype<G, C>>> result = population
+                .map(pt -> random.nextInt() < P
+                        ? mutate(pt, generation, p, random)
+                        : new MutatorResult(pt, 0));
+
+        return new AltererResult(
+                result.map(MutatorResult::result).asISeq(),
+                result.stream().mapToInt(MutatorResult::mutations).sum()
+        );
+    }
+
+    /**
+     * Mutates the given phenotype.
+     *
+     * @see #mutate(Genotype, double, RandomGenerator)
+     * @see #mutate(Chromosome, double, CC, RandomGenerator)
+     * @see #mutate(Gene, CC, RandomGenerator)
+     *
+     * @param phenotype the phenotype to mutate
+     * @param generation the actual generation
+     * @param p the mutation probability for the underlying genetic objects
+     * @param random the random engine used for the phenotype mutation
+     * @return the mutation result
+     */
+    protected MutatorResult<Phenotype<G, C>> mutate(
+            final Phenotype<G, C> phenotype,
+            final long generation,
+            final double p,
+            final RandomGenerator random
+    ) {
+        final MutatorResult<Genotype<G>> result = mutate(phenotype.genotype(), p, random);
+
+        return new MutatorResult(Phenotype.of(result.result(), generation), result.mutations());
+    }
+
+    /**
+     * Mutates the given genotype.
+     *
+     * @see #mutate(Chromosome, double, CC, RandomGenerator)
+     * @see #mutate(Gene, CC, RandomGenerator)
+     *
+     * @param genotype the genotype to mutate
+     * @param p the mutation probability for the underlying genetic objects
+     * @param random the random engine used for the genotype mutation
+     * @return the mutation result
+     */
+    protected MutatorResult<Genotype<G>> mutate(
+            final Genotype<G> genotype,
+            final double p,
+            final RandomGenerator random
+    ) {
+        final int P = Probabilities.toInt(p);
+        final long count = genotype.stream().count();
+        final CC [] contexts = createContextArray((int)count);
+        final List<MutatorResult<Chromosome<G>>> results = new ArrayList<>((int)count);
+
+        for(int i = 0; i < count; ++i) {
+            final Chromosome<G> chromosome = genotype.get(i);
+            final boolean shouldMutate = random.nextInt() < P;
+
+            if(!shouldMutate) {
+                results.add(new MutatorResult(chromosome, 0));
+            } else {
+                final CC context = contexts[i];
+                final MutatorResult<Chromosome<G>> mutatorResult = mutate(chromosome, p, context, random);
+                propagateCorrelationInfo(contexts, genotype, i);
+
+                results.add(mutatorResult);
+            }
+        }
+
+        final ISeq<MutatorResult<Chromosome<G>>> result = results.stream().collect(ISeq.toISeq());
+
+        return new MutatorResult(
+                Genotype.of(result.map(MutatorResult::result)),
+                result.stream().mapToInt(MutatorResult::mutations).sum()
+        );
+    }
+
+    protected void propagateCorrelationInfo(final CC [] contexts, final Genotype<G> genotype, final int i) {
+        final CC context = contexts[i];
+
+        for(final Correlation correlation : this.correlations.find(genotype, i)) {
+            final int targetIndex = Math.max(correlation.getChromosomeOne(), correlation.getChromosomeTwo());
+
+            contexts[targetIndex].apply(context, correlation);
+            propagateCorrelationInfo(contexts, genotype, targetIndex);
+        }
+    }
+
+    /**
+     * Creates an array of uninitialized contexts.
+     * @param count Size of array.
+     * @return A newly created array.
+     */
+    protected abstract CC[] createContextArray(final int count);
+
+    /**
+     * Mutates the given chromosome.
+     *
+     * @see #mutate(Gene, CC, RandomGenerator)
+     *
+     * @param chromosome the chromosome to mutate
+     * @param p the mutation probability for the underlying genetic objects
+     * @param context the context of the mutation. Should be modified.
+     * @param random the random engine used for the genotype mutation
+     * @return the mutation result
+     */
+    protected MutatorResult<Chromosome<G>> mutate(
+            final Chromosome<G> chromosome,
+            final double p,
+            final CC context,
+            final RandomGenerator random
+    ) {
+        final int P = Probabilities.toInt(p);
+
+        final ISeq<MutatorResult<G>> result = chromosome.stream()
+                .map(gene -> random.nextInt() < P
+                        ? new MutatorResult<G>(mutate(gene, context, random), 1)
+                        : new MutatorResult<G>(gene, 0))
+                .collect(ISeq.toISeq());
+
+        return new MutatorResult(
+                chromosome.newInstance(result.map(MutatorResult::result)),
+                result.stream().mapToInt(MutatorResult::mutations).sum()
+        );
+    }
+
+    /**
+     * Mutates the given gene.
+     *
+     * @param gene the gene to mutate
+     * @param context the context for mutation. The parameter should be modified
+     * @param random the random engine used for the genotype mutation‚
+     * @return the mutation result
+     */
+    protected G mutate(final G gene, final CC context, final RandomGenerator random) {
+        return gene.newInstance();
+    }
+
+    /**
+     * Creates an uninitialized context.
+     *
+     * @return an uninitialized context
+     */
+    protected abstract CC uninitializedContext();
+
+    @Override
+    public String toString() {
+        return format("%s[p=%f]", getClass().getSimpleName(), _probability);
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/mutator/CorrelationMutatorFactory.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/mutator/CorrelationMutatorFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..25b3c926ecfca732df4661812c144d695a91d454
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/mutator/CorrelationMutatorFactory.java
@@ -0,0 +1,25 @@
+package de.evoal.core.main.ea.alterer.mutator;
+
+import de.evoal.core.api.board.Blackboard;
+import de.evoal.core.main.ea.functions.correlation.model.Correlations;
+import io.jenetics.Alterer;
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.inject.Produces;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.inject.Inject;
+import java.util.function.BiFunction;
+
+@ApplicationScoped
+public final class CorrelationMutatorFactory {
+    private final static Logger log = LoggerFactory.getLogger(CorrelationMutatorFactory.class);
+
+    @Inject
+    private Blackboard board;
+
+    @Produces
+    public BiFunction<Double, Double, Alterer> create(final Correlations correlations) {
+        return (probability, threshold) -> new GaussianCorrelationMutator(probability, threshold, correlations);
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/mutator/CorrelationMutatorMemento.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/mutator/CorrelationMutatorMemento.java
new file mode 100644
index 0000000000000000000000000000000000000000..e7a7eee4a74fe817ed7dfdf126a2bbd4af3b4a1b
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/mutator/CorrelationMutatorMemento.java
@@ -0,0 +1,12 @@
+package de.evoal.core.main.ea.alterer.mutator;
+
+
+import de.evoal.core.main.ea.functions.correlation.model.Correlation;
+
+/**
+ * Memento to preserve the state of correlation-aware mutator.
+ * @param <CC>
+ */
+public interface CorrelationMutatorMemento<CC extends CorrelationMutatorMemento> {
+    public void apply(final CC context, Correlation correlation);
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/mutator/GaussianCorrelationMutator.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/mutator/GaussianCorrelationMutator.java
new file mode 100644
index 0000000000000000000000000000000000000000..66c1b3050dbdcba41979249d73d56763b7412670
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/mutator/GaussianCorrelationMutator.java
@@ -0,0 +1,57 @@
+package de.evoal.core.main.ea.alterer.mutator;
+
+import de.evoal.core.main.ea.functions.correlation.model.Correlations;
+import io.jenetics.NumericGene;
+
+import java.util.random.RandomGenerator;
+
+import static io.jenetics.internal.math.Basics.clamp;
+import static java.lang.Math.nextDown;
+import static java.lang.String.format;
+
+public class GaussianCorrelationMutator<
+        G extends NumericGene<?, G>,
+        C extends Comparable<? super C>>
+        extends CorrelationMutator<G, C, GaussianCorrelationMutatorMemento> {
+
+    public GaussianCorrelationMutator(final double probability, final double threshold, final Correlations correlations) {
+        super(probability, threshold, correlations);
+    }
+
+    @Override
+    protected GaussianCorrelationMutatorMemento[] createContextArray(final int count) {
+        final GaussianCorrelationMutatorMemento[] result = new GaussianCorrelationMutatorMemento[count];
+
+        for(int i = 0; i < count; ++i) {
+            result[i] = uninitializedContext();
+        }
+
+        return result;
+    }
+
+    @Override
+    protected G mutate(final G gene, final GaussianCorrelationMutatorMemento context, final RandomGenerator random) {
+        return mutate0(gene, context, random);
+    }
+
+    private G mutate0(final G gene, final GaussianCorrelationMutatorMemento context, final RandomGenerator random) {
+        final double min = gene.min().doubleValue();
+        final double max = gene.max().doubleValue();
+        final double std = (max - min)*0.25;
+
+        final double value = gene.doubleValue();
+        final double gaussian = context.getGaussian();
+
+        return gene.newInstance(clamp(gaussian*std + value, min, nextDown(max)));
+    }
+
+    @Override
+    public String toString() {
+        return format("%s[p=%f]", getClass().getSimpleName(), _probability);
+    }
+
+    @Override
+    protected GaussianCorrelationMutatorMemento uninitializedContext() {
+        return new GaussianCorrelationMutatorMemento(threshold);
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/mutator/GaussianCorrelationMutatorMemento.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/mutator/GaussianCorrelationMutatorMemento.java
new file mode 100644
index 0000000000000000000000000000000000000000..15a4c49cff89e42fd8ed9cbd425c32d296eec560
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/mutator/GaussianCorrelationMutatorMemento.java
@@ -0,0 +1,35 @@
+package de.evoal.core.main.ea.alterer.mutator;
+
+import de.evoal.core.main.ea.functions.correlation.model.Correlation;
+import lombok.Data;
+
+import java.util.Random;
+
+@Data
+public final class GaussianCorrelationMutatorMemento implements CorrelationMutatorMemento<GaussianCorrelationMutatorMemento> {
+    /**
+     * Random gaussian value for altering value.
+     */
+    private double gaussian = new Random().nextGaussian();
+
+    private final double threshold;
+
+    public GaussianCorrelationMutatorMemento(final double threshold) {
+        this.threshold = threshold;
+    }
+
+    @Override
+    public void apply(final GaussianCorrelationMutatorMemento context, final Correlation correlation) {
+        final double correlationFactor = correlation.getCorrelationFactor();
+
+        if(correlationFactor >= threshold) {
+            gaussian = context.getGaussian();
+        } else if(correlationFactor >= 0.0) {
+            gaussian = (context.getGaussian() + gaussian) / 2.0;
+        } else if(correlationFactor > -threshold) {
+            gaussian = (-context.getGaussian() + gaussian) / 2.0;
+        } else {
+            gaussian = -context.getGaussian();
+        }
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/mutator/SingleBitFlipCorrelationMutator.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/mutator/SingleBitFlipCorrelationMutator.java
new file mode 100644
index 0000000000000000000000000000000000000000..5eddb9e06a6a33e308b815e6df88f5d41b0a5d01
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/mutator/SingleBitFlipCorrelationMutator.java
@@ -0,0 +1,117 @@
+package de.evoal.core.main.ea.alterer.mutator;
+
+import de.evoal.core.main.ea.functions.correlation.model.Correlations;
+import io.jenetics.*;
+import io.jenetics.util.MSeq;
+
+import java.util.Random;
+import java.util.random.RandomGenerator;
+
+public class SingleBitFlipCorrelationMutator<
+        C extends Comparable<? super C>
+        >
+        extends CorrelationMutator<BitGene, C, SingleBitFlipCorrelationMutatorMemento>
+{
+
+    /**
+     * Constructs an alterer with a given filip probability.
+     *
+     * @param probability the flip probability.
+     * @throws IllegalArgumentException if the {@code probability} is not in the
+     *          valid range of {@code [0, 1]}.
+     */
+    public SingleBitFlipCorrelationMutator(final double probability, final double threshold, final Correlations correlations) {
+        super(probability, threshold, correlations);
+    }
+
+    @Override
+    protected SingleBitFlipCorrelationMutatorMemento[] createContextArray(final int count) {
+        final SingleBitFlipCorrelationMutatorMemento[] result = new SingleBitFlipCorrelationMutatorMemento[count];
+
+        for(int i = 0; i < count; ++i) {
+            result[i] = uninitializedContext();
+        }
+
+        return result;
+    }
+
+    /**
+     * Flips a random gene in the .
+     */
+    @Override
+    protected MutatorResult<Chromosome<BitGene>> mutate(final Chromosome<BitGene> chromosome,
+                                                        final double p,
+                                                        final SingleBitFlipCorrelationMutatorMemento memento,
+                                                        final RandomGenerator random) {
+        final MSeq<BitGene> genes = MSeq.of(chromosome);
+
+        int index = memento.getIndex(random, genes.length(), p);
+        SingleBitFlipCorrelationMutatorMemento.FlipDirection direction = SingleBitFlipCorrelationMutatorMemento.FlipDirection.UNSET;
+        boolean newBit = false;
+
+        switch(memento.getDirection()) {
+            case UNSET: {
+                newBit = !genes.get(index).bit();
+                direction = SingleBitFlipCorrelationMutatorMemento.FlipDirection.from(newBit);
+                break;
+            }
+
+            case SINGLE_FLIP_UP: {
+                newBit = true;
+                direction = SingleBitFlipCorrelationMutatorMemento.FlipDirection.UP;
+                break;
+            }
+
+            case SINGLE_FLIP_DOWN: {
+                newBit = false;
+                direction = SingleBitFlipCorrelationMutatorMemento.FlipDirection.DOWN;
+                break;
+            }
+
+            case TRANSITIVE_UP: {
+                index = findNearestIndex(genes, index, false);
+                newBit = true;
+                direction = SingleBitFlipCorrelationMutatorMemento.FlipDirection.UP;
+            }
+
+            case TRANSITIVE_DOWN: {
+                index = findNearestIndex(genes, index, true);
+                newBit = false;
+                direction = SingleBitFlipCorrelationMutatorMemento.FlipDirection.DOWN;
+            }
+        }
+
+        genes.set(index, BitGene.of(newBit));
+        memento.setDirection(direction);
+
+        return new MutatorResult(
+                chromosome.newInstance(genes.toISeq()),
+                1
+        );
+    }
+
+    private int findNearestIndex(final MSeq<BitGene> genes, final int starting, final boolean value) {
+        if(genes.get(starting).bit() == value) {
+            return starting;
+        }
+
+        for(int i = 1; i < genes.length(); ++i) {
+            final int upperIndex = Math.min(starting + i, genes.length() - 1);
+            if(genes.get(upperIndex).bit() == value) {
+                return upperIndex;
+            }
+
+            final int lowerIndex = Math.max(starting - i, 0);
+            if(genes.get(lowerIndex).bit() == value) {
+                return lowerIndex;
+            }
+        }
+
+        return starting;
+    }
+
+    @Override
+    protected SingleBitFlipCorrelationMutatorMemento uninitializedContext() {
+        return new SingleBitFlipCorrelationMutatorMemento(threshold);
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/mutator/SingleBitFlipCorrelationMutatorMemento.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/mutator/SingleBitFlipCorrelationMutatorMemento.java
new file mode 100644
index 0000000000000000000000000000000000000000..a1fa9d382f041b219e7646cf84b5f5ee60f35a1c
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/mutator/SingleBitFlipCorrelationMutatorMemento.java
@@ -0,0 +1,70 @@
+package de.evoal.core.main.ea.alterer.mutator;
+
+import de.evoal.core.main.ea.functions.correlation.model.Correlation;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Random;
+import java.util.random.RandomGenerator;
+
+public class SingleBitFlipCorrelationMutatorMemento implements CorrelationMutatorMemento<SingleBitFlipCorrelationMutatorMemento> {
+
+    public enum FlipDirection {
+        DOWN,
+        NOTHING,
+        SINGLE_FLIP_UP,
+        SINGLE_FLIP_DOWN,
+        TRANSITIVE_UP,
+        TRANSITIVE_DOWN,
+        UNSET,
+        UP;
+
+        public static FlipDirection from(final boolean value) {
+            return value ? UP : DOWN;
+        }
+    }
+
+    private int index = -1;
+
+    private final double threshold;
+
+    @Getter @Setter
+    private FlipDirection direction = FlipDirection.UNSET;
+
+    public SingleBitFlipCorrelationMutatorMemento(final double threshold) {
+        this.threshold = threshold;
+    }
+
+    public int getIndex(final RandomGenerator random, final int length, final double probability) {
+        if(index == -1) {
+            index = random.nextInt(0, length);
+        }
+
+        return index;
+    }
+
+    @Override
+    public void apply(final SingleBitFlipCorrelationMutatorMemento context, final Correlation correlation) {
+        final double correlationFactor = correlation.getCorrelationFactor();
+        final FlipDirection direction = context.getDirection();
+
+        if(correlationFactor >= threshold && FlipDirection.UP.equals(direction)) {
+            this.direction = FlipDirection.TRANSITIVE_UP;
+        } else if(correlationFactor >= threshold && FlipDirection.DOWN.equals(direction)) {
+            this.direction = FlipDirection.TRANSITIVE_DOWN;
+        } else if(correlationFactor >= 0 && FlipDirection.UP.equals(direction)) {
+            this.direction = FlipDirection.SINGLE_FLIP_UP;
+        } else if(correlationFactor >= 0 && FlipDirection.DOWN.equals(direction)) {
+            this.direction = FlipDirection.SINGLE_FLIP_DOWN;
+        } else if(correlationFactor > -threshold && FlipDirection.UP.equals(direction)) {
+            this.direction = FlipDirection.SINGLE_FLIP_DOWN;
+        } else if(correlationFactor > -threshold && FlipDirection.DOWN.equals(direction)) {
+            this.direction = FlipDirection.SINGLE_FLIP_UP;
+        } else if(correlationFactor <= -threshold && FlipDirection.UP.equals(direction)) {
+            this.direction = FlipDirection.TRANSITIVE_DOWN;
+        } else if(correlationFactor <= -threshold && FlipDirection.DOWN.equals(direction)) {
+            this.direction = FlipDirection.TRANSITIVE_UP;
+        }
+
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/mutator/SingleBitFlipMutator.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/mutator/SingleBitFlipMutator.java
new file mode 100644
index 0000000000000000000000000000000000000000..aa03b14f1477fce7f0ecab66e6d3ab56a12498a5
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/mutator/SingleBitFlipMutator.java
@@ -0,0 +1,57 @@
+package de.evoal.core.main.ea.alterer.mutator;
+
+import io.jenetics.*;
+import io.jenetics.util.MSeq;
+
+import java.util.Random;
+import java.util.random.RandomGenerator;
+
+
+public class SingleBitFlipMutator<
+        C extends Comparable<? super C>
+        >
+        extends Mutator<BitGene, C>
+{
+
+    /**
+     * Constructs an alterer with a given filip probability.
+     *
+     * @param probability the flip probability.
+     * @throws IllegalArgumentException if the {@code probability} is not in the
+     *          valid range of {@code [0, 1]}.
+     */
+    public SingleBitFlipMutator(final double probability) {
+        super(probability);
+    }
+
+    /**
+     * Default constructor, with default mutation probability
+     * ({@link AbstractAlterer#DEFAULT_ALTER_PROBABILITY}).
+     */
+    public SingleBitFlipMutator() {
+        this(DEFAULT_ALTER_PROBABILITY);
+    }
+
+    /**
+     * Flips a random gene in the .
+     */
+    @Override
+    protected MutatorResult<Chromosome<BitGene>> mutate(
+            final Chromosome<BitGene> chromosome,
+            final double p,
+            final RandomGenerator random
+    ) {
+        final MSeq<BitGene> genes = MSeq.of(chromosome);
+
+        final int index = random.nextInt();
+
+        final BitGene gene = genes.get(index);
+        genes.set(index, BitGene.of(!gene.bit()));
+
+        return new MutatorResult(
+                chromosome.newInstance(genes.toISeq()),
+                1
+        );
+    }
+
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/mutator/SwapCorrelationMutator.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/mutator/SwapCorrelationMutator.java
new file mode 100644
index 0000000000000000000000000000000000000000..7f3dfc111edf9bafbd210db37b59cd303f1e739e
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/mutator/SwapCorrelationMutator.java
@@ -0,0 +1,63 @@
+package de.evoal.core.main.ea.alterer.mutator;
+
+import de.evoal.core.main.ea.functions.correlation.model.Correlations;
+import io.jenetics.Chromosome;
+import io.jenetics.Gene;
+import io.jenetics.MutatorResult;
+import io.jenetics.util.MSeq;
+
+import java.util.Arrays;
+import java.util.random.RandomGenerator;
+
+public class SwapCorrelationMutator<
+        G extends Gene<?, G>,
+        C extends Comparable<? super C>
+        > extends CorrelationMutator<G, C, SwapCorrelationMutatorMemento> {
+
+    public SwapCorrelationMutator(final double probability, final double threshold, final Correlations correlations) {
+        super(probability, threshold, correlations);
+    }
+
+    @Override
+    protected SwapCorrelationMutatorMemento[] createContextArray(final int count) {
+        final SwapCorrelationMutatorMemento[] result = new SwapCorrelationMutatorMemento[count];
+
+        for(int i = 0; i < count; ++i) {
+            result[i] = uninitializedContext();
+        }
+
+        return result;
+    }
+
+    @Override
+    protected MutatorResult<Chromosome<G>> mutate(
+            final Chromosome<G> chromosome,
+            final double p,
+            final SwapCorrelationMutatorMemento memento,
+            final RandomGenerator random
+    ) {
+        final MutatorResult<Chromosome<G>> result;
+        if (chromosome.length() > 1) {
+            final MSeq<G> genes = MSeq.of(chromosome);
+            final int [][] swaps = memento.getIndices(random, genes.length(), p);
+
+            final int mutations = (int) Arrays.stream(swaps)
+                    .peek(i -> genes.swap(i[0], i[1]))
+                    .count();
+            result = new MutatorResult(
+                    chromosome.newInstance(genes.toISeq()),
+                    mutations
+            );
+        } else {
+            result = new MutatorResult(chromosome, 0);
+        }
+
+        return result;
+
+    }
+
+    @Override
+    protected SwapCorrelationMutatorMemento uninitializedContext() {
+        return new SwapCorrelationMutatorMemento();
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/mutator/SwapCorrelationMutatorMemento.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/mutator/SwapCorrelationMutatorMemento.java
new file mode 100644
index 0000000000000000000000000000000000000000..b8e71b71fe6489ee150adb7705651fdb0ed93436
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/alterer/mutator/SwapCorrelationMutatorMemento.java
@@ -0,0 +1,24 @@
+package de.evoal.core.main.ea.alterer.mutator;
+
+import de.evoal.core.main.ea.functions.correlation.model.Correlation;
+
+import java.util.Random;
+import java.util.random.RandomGenerator;
+
+import static io.jenetics.internal.math.Randoms.indexes;
+
+public class SwapCorrelationMutatorMemento implements CorrelationMutatorMemento<SwapCorrelationMutatorMemento> {
+    private int [][] indices = null;
+
+    public int [][] getIndices(final RandomGenerator random, final int length, final double probability) {
+        if(indices == null) {
+            indices = indexes(random, length, probability).mapToObj(i -> new int[] {i, random.nextInt(length)}).toArray(i -> new int [i][]);
+        }
+
+        return indices;
+    }
+
+    @Override
+    public void apply(final SwapCorrelationMutatorMemento context, final Correlation correlation) {
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/functions/correlation/model/Correlation.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/functions/correlation/model/Correlation.java
new file mode 100644
index 0000000000000000000000000000000000000000..450f855557b82a12672fbd3b88429313ec2ea66a
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/functions/correlation/model/Correlation.java
@@ -0,0 +1,38 @@
+package de.evoal.core.main.ea.functions.correlation.model;
+
+import de.evoal.core.api.ea.codec.CustomCodec;
+import lombok.Data;
+
+/**
+ * Base class for correlations. Represents a correlation between two chromosomes.
+ */
+@Data
+public class Correlation {
+    /**
+     * Index of first chromosome.
+     */
+    private int chromosomeOne;
+
+    /**
+     * Index of second chromosome.
+     */
+    private int chromosomeTwo;
+
+    /**
+     * Codec for encoding and decoding between domain and ea values.
+     */
+    private CustomCodec codec;
+
+    /**
+     * Correlation factor
+     */
+    private double correlationFactor;
+
+    public boolean matchesSource(int chromosomeIndex, double chromosomeValue) {
+        return chromosomeOne == chromosomeIndex;
+    }
+
+    public boolean matchesTarget(int chromosomeIndex, double chromosomeValue) {
+        return chromosomeTwo == chromosomeIndex;
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/functions/correlation/model/Correlations.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/functions/correlation/model/Correlations.java
new file mode 100644
index 0000000000000000000000000000000000000000..bd199bba1b1d14c24efe7d3de0bdfd16fa56f127
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/functions/correlation/model/Correlations.java
@@ -0,0 +1,62 @@
+package de.evoal.core.main.ea.functions.correlation.model;
+
+import de.evoal.core.api.ea.codec.CustomCodec;
+import de.evoal.core.api.properties.Properties;
+import io.jenetics.Gene;
+import io.jenetics.Genotype;
+import lombok.Data;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Root class for all existing correlations.
+ */
+@Data
+public class Correlations<G extends Gene<?, G>> {
+    /**
+     * Codec for encoding and decoding between domain and ea values.
+     */
+    private CustomCodec<G> codec;
+
+    /**
+     * The concrete list of all correlations.
+     */
+    private final List<Correlation> correlations = new ArrayList<>();
+
+    public Correlations(final CustomCodec<G> codec) {
+        this.codec = codec;
+    }
+
+    public List<Correlation> find(final Genotype<G> genotype, final int chromosomeIndex) {
+        final Properties properties = codec.decode(genotype);
+
+        return correlations.stream()
+                           .filter(c -> c.matchesSource(chromosomeIndex, properties.get(chromosomeIndex)))
+                           .collect(Collectors.toList());
+    }
+
+    public int findCorrelationRoot(final Genotype<G> genotype, final int chromosomeIndex) {
+        final Properties properties = codec.decode(genotype);
+
+        final double chromosomeValue = properties.get(chromosomeIndex);
+
+        for(final Correlation correlation : correlations) {
+            if(!correlation.matchesTarget(chromosomeIndex, chromosomeValue)) {
+                continue;
+            }
+
+            final int sourceIndex = correlation.getChromosomeOne();
+            final double sourceValue = properties.get(sourceIndex);
+
+            if(!correlation.matchesSource(sourceIndex, sourceValue)) {
+                continue;
+            }
+
+            return findCorrelationRoot(genotype, sourceIndex);
+        }
+
+        return chromosomeIndex;
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/functions/correlation/model/Range.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/functions/correlation/model/Range.java
new file mode 100644
index 0000000000000000000000000000000000000000..6b71bad7b9cecd2d3f3bce17e50592877e86b959
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/functions/correlation/model/Range.java
@@ -0,0 +1,17 @@
+package de.evoal.core.main.ea.functions.correlation.model;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@AllArgsConstructor
+@Data
+@NoArgsConstructor
+public class Range {
+    private double lower;
+    private double upper;
+
+    public boolean includes(double chromosomeValue) {
+        return lower <= chromosomeValue && chromosomeValue <= upper;
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/functions/correlation/model/RangedCorrelation.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/functions/correlation/model/RangedCorrelation.java
new file mode 100644
index 0000000000000000000000000000000000000000..e4dc2468f61454425e55cbfc5254bfa9856117a7
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/ea/functions/correlation/model/RangedCorrelation.java
@@ -0,0 +1,34 @@
+package de.evoal.core.main.ea.functions.correlation.model;
+
+import lombok.Data;
+
+@Data
+public class RangedCorrelation extends Correlation {
+    /**
+     * Boundaries of first chromosome value.
+     */
+    private Range chromosomeOneRange;
+
+    /**
+     * Boundaries of second chromosome value.
+     */
+    private Range chromosomeTwoRange;
+
+    @Override
+    public boolean matchesSource(int chromosomeIndex, double chromosomeValue) {
+        if(!super.matchesSource(chromosomeIndex, chromosomeValue)) {
+            return false;
+        }
+
+        return getChromosomeOneRange().includes(chromosomeValue);
+    }
+
+    @Override
+    public boolean matchesTarget(int chromosomeIndex, double chromosomeValue) {
+        if(!super.matchesTarget(chromosomeIndex, chromosomeValue)) {
+            return false;
+        }
+
+        return getChromosomeTwoRange().includes(chromosomeValue);
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/search/HeuristicSearch.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/search/HeuristicSearch.java
new file mode 100644
index 0000000000000000000000000000000000000000..63e6718c42b8969ca83a8cb4f38d83476d285ed0
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/search/HeuristicSearch.java
@@ -0,0 +1,169 @@
+package de.evoal.core.main.search;
+
+import java.io.File;
+import java.time.Duration;
+import java.util.*;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.function.Function;
+
+import de.evoal.core.api.board.BlackboardEntry;
+import de.evoal.core.api.board.Blackboard;
+import de.evoal.core.api.cdi.BlackboardValue;
+import de.evoal.core.api.cdi.ConfigurationValue;
+import de.evoal.core.main.ea.alterer.AltererFactory;
+import de.evoal.core.api.utils.LanguageHelper;
+import de.evoal.core.api.ea.codec.CustomCodec;
+import de.evoal.core.api.ea.fitness.type.FitnessType;
+
+import de.evoal.core.api.ea.fitness.FitnessEvaluator;
+import de.evoal.core.api.statistics.StatisticsWriter;
+import de.evoal.languages.model.eal.EAModel;
+import de.evoal.languages.model.instance.Array;
+import de.evoal.languages.model.instance.Attribute;
+import de.evoal.languages.model.instance.Name;
+import de.evoal.languages.model.instance.Value;
+import io.jenetics.*;
+import io.jenetics.engine.*;
+import io.jenetics.stat.MinMax;
+import io.jenetics.util.Factory;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.enterprise.inject.Instance;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+@Slf4j
+public class HeuristicSearch<G extends Gene<?, G>> {
+	@Inject
+	private Blackboard board;
+
+	/**
+	 * Location for storing the output.
+	 */
+	@Inject
+	@BlackboardValue(BlackboardEntry.EVALUATION_OUTPUT_FOLDER)
+	private File outputDirectory;
+
+	/**
+	 * The actual run
+	 */
+	@Inject
+	@BlackboardValue(BlackboardEntry.EVALUATION_RUN)
+	private String run;
+
+	@Inject
+	@ConfigurationValue(entry = BlackboardEntry.EA_CONFIGURATION, access = "algorithm.number_of_generations")
+	private int numberOfGenerations = 100;
+
+	@Inject
+	@ConfigurationValue(entry = BlackboardEntry.EA_CONFIGURATION, access = "algorithm.size_of_population")
+	private int sizeOfPopulation = 100;
+
+	@Inject
+	@ConfigurationValue(entry = BlackboardEntry.EA_CONFIGURATION, access = "algorithm.maximum_age")
+	private int maximumAge = 100;
+
+	private final Map<String, List<Alterer<G, FitnessType>>> alterers = new HashMap<>();
+
+	@Inject
+	private CustomCodec encoding;
+
+	private final ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
+
+	@Inject
+	@Named("evaluator")
+	private FitnessEvaluator fitnessEvaluator;
+
+	@Inject @Named("offspring")
+	private Selector offspringSelector;
+
+	@Inject @Named("statistics")
+	private StatisticsWriter statistics;
+
+	@Inject @Named("survivor")
+	private Selector survivorSelector;
+
+	@Inject
+	private AltererFactory factory;
+
+	@Inject
+	private Instance<List<Constraint>> constraints;
+
+
+	@Inject
+	private Function<Engine, EvolutionStream> initalStreamFactory;
+
+	public void run() {
+		setup();
+
+        final Factory<Genotype<G>> gtf = encoding.encoding();
+
+		final Constraint<G, FitnessType> constraint = new ListConstraint(constraints.get());
+
+        final Engine<G, FitnessType> engine= Engine.builder(this.fitnessEvaluator, encoding)
+											.alterers(flattenAltererMap())
+											.offspringSelector(this.offspringSelector)
+											.survivorsSelector(this.survivorSelector)
+											.optimize(Optimize.MAXIMUM)
+											.populationSize(sizeOfPopulation)
+											.constraint(constraint)
+											.maximalPhenotypeAge(maximumAge)
+											.executor(executor)
+											.build();
+        
+        EvolutionStatistics<FitnessType, MinMax<FitnessType>> statistics = EvolutionStatistics.ofComparable();
+		EvolutionStream<G, FitnessType> initialStream = initalStreamFactory.apply(engine);
+
+        final EvolutionResult<G, FitnessType> result
+        		=  initialStream.limit(Limits.byFixedGeneration(numberOfGenerations))
+        						.limit(Limits.byExecutionTime(Duration.ofMinutes(5)))
+//		        				.parallel()
+		        				.peek(this.statistics::add)
+		                		.peek(statistics)
+        						.collect(EvolutionResult.toBestEvolutionResult());
+		this.statistics.write();
+
+		System.out.println(statistics);
+
+        executor.shutdownNow();
+	}
+
+	private void setup() {
+		final EAModel configuration = board.get(BlackboardEntry.EA_CONFIGURATION);
+
+		final de.evoal.languages.model.instance.Instance alterers = LanguageHelper.lookup(configuration.getInstance(), "algorithm.alterers");
+
+		for(final Attribute category: alterers.getAttributes()) {
+			final String name = ((Name)category.getName()).getName().getName();
+			log.info("Processing alterer category '{}'.", name);
+
+			final Array array = (Array) category.getValue();
+
+			for(final Value alterer : array.getValues()) {
+				this.alterers
+						.computeIfAbsent(name, k -> new ArrayList<>())
+						.add(factory.create((de.evoal.languages.model.instance.Instance)alterer));
+			}
+		}
+
+
+	}
+
+	private Alterer<G, FitnessType> flattenAltererMap() {
+		Alterer<G, FitnessType> result = null;
+
+		for(final Map.Entry<String, List<Alterer<G, FitnessType>>> entry : alterers.entrySet()) {
+			for(final Alterer<G, FitnessType> e : entry.getValue()) {
+				if(result == null) {
+					result = e;
+				} else {
+					result = Alterer.of(result, e);
+				}
+			}
+		}
+
+		return result;
+	}
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/search/HeuristicSearchEvaluation.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/search/HeuristicSearchEvaluation.java
new file mode 100644
index 0000000000000000000000000000000000000000..ff621367b0d6c3dd245bc7db121c089d9eedee8a
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/search/HeuristicSearchEvaluation.java
@@ -0,0 +1,129 @@
+package de.evoal.core.main.search;
+
+import de.evoal.core.api.board.BlackboardEntry;
+import de.evoal.core.api.cdi.BlackboardValue;
+import de.evoal.core.api.cdi.MainClass;
+import de.evoal.core.api.properties.Properties;
+import de.evoal.core.api.properties.PropertiesPair;
+import de.evoal.core.api.board.Blackboard;
+import javax.enterprise.context.ApplicationScoped;
+
+import de.evoal.core.api.statistics.Column;
+import de.evoal.core.api.statistics.ColumnType;
+import de.evoal.core.api.statistics.WriterContext;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.math3.util.Pair;
+import org.apache.deltaspike.core.api.provider.BeanProvider;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import java.io.File;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+@Slf4j
+@Named("evaluation")
+@ApplicationScoped
+public class HeuristicSearchEvaluation implements MainClass {
+    @Inject
+    private Blackboard board;
+
+    @Inject
+    private WriterContext context;
+
+    @Inject
+    @BlackboardValue(BlackboardEntry.EA_CONFIGURATION_FILE)
+    private String heuristicFile;
+
+    @Inject
+    @BlackboardValue(BlackboardEntry.EVALUATION_ITERATIONS)
+    private int iterations;
+
+    private File outputBaseDir;
+
+    @Inject
+    @BlackboardValue(BlackboardEntry.PREDICTIVE_FUNCTION_FILE)
+    private String predictiveFile;
+
+    @Inject
+    @BlackboardValue(BlackboardEntry.TRAINING_POINT_FILE)
+    private String pointsFile;
+
+    private List<Pair<Properties, Properties>> targets;
+
+    @Inject
+    @BlackboardValue(BlackboardEntry.TARGETS_FILE)
+    private String targetFile;
+
+    @Inject
+    @Named("target-stream")
+    private Stream<PropertiesPair> targetStream;
+
+    private Column targetColumn;
+    private Column runColumn;
+
+    @Override
+    public void run() {
+        log.info("Running heuristic search evaluation with the following configuartion:");
+        log.info("  predictive function loaded from ({}/{})", predictiveFile, pointsFile);
+        log.info("  target points loaded from ({})", targetFile);
+        log.info("  heuristic configuration loaded from ({})", heuristicFile);
+        log.info("  running {} iterations.", iterations);
+
+        /* prepare output directory */
+        this.outputBaseDir = new File(board.<String>get(BlackboardEntry.EVALUATION_OUTPUT_FOLDER));
+
+        targets = targetStream.collect(Collectors.toList());
+
+        log.info("Processing {} targets during evaluation.", targets.size());
+
+        final long startTime = System.currentTimeMillis();
+        process();
+        final long endTime = System.currentTimeMillis();
+
+        System.err.println("Calculation of heuristic search took in average " + (endTime - startTime)/iterations + " ms.");
+    }
+
+    private void process() {
+        targetColumn = HeuristicSearchUtils.addColumn(context,"target", ColumnType.Integer, 0);
+        runColumn = HeuristicSearchUtils.addColumn(context,"run", ColumnType.Integer, 0);
+
+        targets.forEach(this::processTarget);
+    }
+
+    private int targetIndex = 0;
+    private void processTarget(final Pair<Properties, Properties> target) {
+        final int targetIndex = this.targetIndex++;
+        final int targetLength = calculateFigures(targets.size());
+        final int runLength = calculateFigures(iterations);
+
+        context.bindColumn(targetColumn, targetIndex);
+
+        board.bind(BlackboardEntry.TARGET_PROPERTIES_SOURCE, target.getFirst());
+        board.bind(BlackboardEntry.TARGET_PROPERTIES, target.getSecond());
+        board.bind(BlackboardEntry.EVALUATION_OUTPUT_FOLDER, outputBaseDir);
+
+        log.info("Evaluating with target {} -> {}.", targetIndex, target);
+
+        for (int i = 0; i < iterations; ++i) {
+            log.info("Running {}/{}", i, iterations);
+            final String run = convertToString(i, runLength);
+            board.bind(BlackboardEntry.EVALUATION_RUN, run);
+            context.bindColumn(runColumn, i);
+
+            final HeuristicSearch<?> search = new HeuristicSearch<>();
+            BeanProvider.injectFields(search);
+            search.run();
+        }
+    }
+
+    private String convertToString(final int targetIndex, final int length) {
+        return String.format("%0" + Math.max(length, 1) + "d", targetIndex);
+    }
+
+    private int calculateFigures(final int number) {
+        return (int)(Math.log10(number));
+    }
+}
+
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/search/HeuristicSearchMain.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/search/HeuristicSearchMain.java
new file mode 100644
index 0000000000000000000000000000000000000000..e1f1da1c3aecf39e621f9a12d3ce216872b974b8
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/search/HeuristicSearchMain.java
@@ -0,0 +1,57 @@
+package de.evoal.core.main.search;
+
+import de.evoal.core.api.board.Blackboard;
+import de.evoal.core.api.board.BlackboardEntry;
+import de.evoal.core.api.cdi.BeanFactory;
+import de.evoal.core.api.cdi.MainClass;
+import de.evoal.core.api.properties.Properties;
+import javax.enterprise.context.ApplicationScoped;
+
+import de.evoal.core.api.statistics.ColumnType;
+import de.evoal.core.api.statistics.WriterContext;
+import org.apache.commons.math3.util.Pair;
+import org.apache.deltaspike.core.api.provider.BeanProvider;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import java.io.File;
+import java.util.stream.Stream;
+
+@Named("heuristic-search")
+@ApplicationScoped
+public class HeuristicSearchMain implements MainClass {
+	@Inject
+	private Blackboard board;
+
+	@Inject
+	private WriterContext context;
+
+	@Override
+	public void run() {
+		final String predictiveFileName = board.get(BlackboardEntry.PREDICTIVE_FUNCTION_FILE);
+		final String heuristicFileName = board.get(BlackboardEntry.EA_CONFIGURATION_FILE);
+
+		final File outputBaseDir = HeuristicSearchUtils.calculateOutputBaseDir(new File(predictiveFileName), new File(heuristicFileName));
+
+		HeuristicSearchUtils.addColumn(context,"target", ColumnType.Integer, 0);
+		HeuristicSearchUtils.addColumn(context,"run", ColumnType.Integer, 0);
+
+		board.bind(BlackboardEntry.EVALUATION_OUTPUT_FOLDER, outputBaseDir);
+		board.bind(BlackboardEntry.EVALUATION_RUN, "0");
+
+		final Stream<Pair<Properties, Properties>> targets = (Stream<Pair<Properties, Properties>>)BeanProvider.getContextualReference("target-stream");
+		setTarget(targets, board);
+
+		BeanFactory.create(HeuristicSearch.class)
+				   .run();
+	}
+
+	private static void setTarget(final Stream<Pair<Properties, Properties>> targets, final Blackboard board) {
+		final Pair<Properties, Properties> targetProperties =
+					targets.findFirst()
+						   .orElseThrow(() -> {throw new IllegalStateException("No target point found");});
+
+		board.bind(BlackboardEntry.TARGET_PROPERTIES_SOURCE, targetProperties.getFirst());
+		board.bind(BlackboardEntry.TARGET_PROPERTIES, targetProperties.getSecond());
+	}
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/search/HeuristicSearchUtils.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/search/HeuristicSearchUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..1c996ea81cce78dec212a8a349d4d6abc40c44b1
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/search/HeuristicSearchUtils.java
@@ -0,0 +1,36 @@
+package de.evoal.core.main.search;
+
+import de.evoal.core.api.statistics.Column;
+import de.evoal.core.api.statistics.ColumnType;
+import de.evoal.core.api.statistics.WriterContext;
+import lombok.extern.slf4j.Slf4j;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+
+/**
+ * Helper functions for loading stuff for heuristic search.
+ */
+@Slf4j
+public final class HeuristicSearchUtils {
+    private HeuristicSearchUtils(){
+    }
+
+    public static Column addColumn(final WriterContext context, final String name, final ColumnType type, final Object value) {
+        final Column col = new Column(name, type);
+        context.addColumn(col);
+        context.bindColumn(col, value);
+
+        return col;
+    }
+
+    public static File calculateOutputBaseDir(final File predictiveFile, final File heuristicFile) {
+        String outputDirname = predictiveFile.toString();
+        outputDirname = outputDirname.split("\\.")[0];
+        outputDirname = outputDirname.replace("input/", "output/");
+        final File outputDir = new File(outputDirname);
+
+        return new File(outputDir, heuristicFile.getName().split("\\.")[0]);
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/search/ListConstraint.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/search/ListConstraint.java
new file mode 100644
index 0000000000000000000000000000000000000000..dd0cded2efd4a62aa2963eae6a9d4516f8386110
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/search/ListConstraint.java
@@ -0,0 +1,32 @@
+package de.evoal.core.main.search;
+
+import de.evoal.core.api.ea.fitness.type.FitnessType;
+import io.jenetics.Gene;
+import io.jenetics.Phenotype;
+import io.jenetics.engine.Constraint;
+
+import java.util.List;
+
+public class ListConstraint<G extends Gene<?, G>> implements Constraint<G, FitnessType> {
+    private final List<Constraint<G, FitnessType>> constraints;
+
+    public ListConstraint(final List<Constraint<G, FitnessType>> constraints) {
+        this.constraints = constraints;
+    }
+
+    @Override
+    public boolean test(final Phenotype<G, FitnessType> individual) {
+        return constraints.stream().allMatch(c -> c.test(individual));
+    }
+
+    @Override
+    public Phenotype<G, FitnessType> repair(Phenotype<G, FitnessType> individual, long generation) {
+        Phenotype<G, FitnessType> phenotype = individual;
+
+        for(final Constraint<G, FitnessType> c : constraints) {
+            phenotype = c.repair(phenotype, generation);
+        }
+
+        return phenotype;
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/statistics/StatisticsFactory.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/statistics/StatisticsFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..864d339020fd4ac3b5c65042162ebca1def89a89
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/statistics/StatisticsFactory.java
@@ -0,0 +1,35 @@
+package de.evoal.core.main.statistics;
+
+import de.evoal.core.api.board.BlackboardEntry;
+import de.evoal.core.api.cdi.ConfigurationValue;
+import de.evoal.core.api.statistics.StatisticsWriter;
+import de.evoal.core.api.utils.Requirements;
+import de.evoal.languages.model.instance.Array;
+import de.evoal.languages.model.instance.Instance;
+import de.evoal.core.main.statistics.internal.MultipleStatisticsWriter;
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.inject.Produces;
+
+import org.apache.commons.math3.util.Pair;
+import org.apache.deltaspike.core.api.provider.BeanProvider;
+
+import javax.inject.Named;
+
+@ApplicationScoped
+public class StatisticsFactory {
+    @Produces
+    @Named("statistics")
+    public StatisticsWriter create(final @ConfigurationValue(entry = BlackboardEntry.EA_CONFIGURATION, access = "statistics") Instance instance) {
+        Requirements.requireSize(instance.getAttributes(), 1);
+        final Array array = (Array)instance.getAttributes().get(0).getValue();
+
+        final StatisticsWriter [] writers = array.getValues()
+                                                 .stream()
+                                                 .map(Instance.class::cast)
+                                                 .map(i -> new Pair<>(BeanProvider.getContextualReference(i.getName().getName(), false, StatisticsWriter.class), i))
+                                                 .map(p -> p.getFirst().init(p.getSecond()))
+                                                 .toArray(i -> new StatisticsWriter[i]);
+
+        return new MultipleStatisticsWriter(writers);
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/statistics/constraint/ConstraintStatistics.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/statistics/constraint/ConstraintStatistics.java
new file mode 100644
index 0000000000000000000000000000000000000000..dbbd336ad6f74ff2699c13609a0aae0a96cad1cc
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/statistics/constraint/ConstraintStatistics.java
@@ -0,0 +1,143 @@
+package de.evoal.core.main.statistics.constraint;
+
+import de.evoal.core.api.statistics.*;
+import de.evoal.core.main.ddl.constraint.strategies.CalculationFactory;
+import de.evoal.core.main.ddl.constraint.strategies.CalculationStrategy;
+import de.evoal.languages.model.instance.Instance;
+import de.evoal.core.api.ea.codec.CustomCodec;
+import de.evoal.core.api.ea.constraints.model.ConstraintResult;
+import de.evoal.core.api.ea.constraints.model.Constraints;
+import de.evoal.core.api.ea.constraints.strategies.CalculationResult;
+import de.evoal.core.api.ea.fitness.type.FitnessType;
+import de.evoal.core.api.properties.Properties;
+import io.jenetics.Phenotype;
+import io.jenetics.engine.EvolutionResult;
+import io.jenetics.util.ISeq;
+import javax.annotation.PostConstruct;
+import javax.enterprise.context.Dependent;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import java.util.ArrayList;
+import java.util.DoubleSummaryStatistics;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Small helper class for collecting and writing the generation-based statistics.
+ */
+@Slf4j
+@Named("constraint-statistics")
+@Dependent
+public class ConstraintStatistics implements StatisticsWriter {
+    private final static int NUMBER_OF_STATISTICS_PER_CONSTRAINT = 5;
+
+    private final List<Column> columns = new ArrayList<>();
+
+    @Inject
+    private CalculationFactory factory;
+
+    @Inject
+    private Constraints constraints;
+
+    @Inject
+    private CustomCodec codec;
+
+    private CalculationStrategy[] calculators;
+
+    private long endTime;
+
+    private long startTime;
+
+    @Inject
+    private WriterStrategy strategy;
+
+    private Writer writer;
+
+    @PostConstruct @SneakyThrows(WriterException.class)
+    private void init() {
+        startTime = System.currentTimeMillis();
+
+        createColumns();
+
+        writer = strategy.create("constraint-statistics", columns);
+
+        calculators = constraints.getConstraints()
+                .stream()
+                .map(factory::create)
+                .toArray(CalculationStrategy[]::new);
+    }
+
+    private void createColumns() {
+        columns.add(new Column("generation", ColumnType.Integer));
+
+        for(int i = 0; i < constraints.getConstraints().size(); ++i) {
+            columns.add(new Column("violatingIndividuals_" + i, ColumnType.Integer));
+            columns.add(new Column("sumOfDifferences_" + i, ColumnType.Double));
+            columns.add(new Column("minOfDifferences_" + i, ColumnType.Double));
+            columns.add(new Column("avgOfDifferences_" + i, ColumnType.Double));
+            columns.add(new Column("maxOfDifferences_" + i, ColumnType.Double));
+        }
+    }
+
+    private Object[] toData(final long generation, final ISeq<Phenotype<?, FitnessType>> population) {
+        final Object [] data = new Object[1 + constraints.getConstraints().size() * NUMBER_OF_STATISTICS_PER_CONSTRAINT];
+
+        data[0] = generation;
+
+        for(int index = 0; index < calculators.length; ++index) {
+            final CalculationStrategy strategy = calculators[index];
+
+            final List<CalculationResult> calculationResults =
+                population.stream()
+                        .map(Phenotype::genotype)
+                        .map(g -> (Properties)codec.decode(g))
+                        .map(strategy::calculate)
+                        .collect(Collectors.toList());
+
+            final long invalid = calculationResults
+                    .stream()
+                    .filter(r -> !r.isSuccessful())
+                    .count();
+
+            final DoubleSummaryStatistics statistics =
+                calculationResults
+                        .stream()
+                        .filter(r -> !r.isSuccessful())
+                        .map(CalculationResult::getResult)
+                        .mapToDouble(ConstraintResult::getComparisonDifference)
+                        .summaryStatistics();
+
+            data[1 + index * NUMBER_OF_STATISTICS_PER_CONSTRAINT + 0] = invalid;
+            data[1 + index * NUMBER_OF_STATISTICS_PER_CONSTRAINT + 1] = statistics.getSum();
+            data[1 + index * NUMBER_OF_STATISTICS_PER_CONSTRAINT + 2] = statistics.getMin();
+            data[1 + index * NUMBER_OF_STATISTICS_PER_CONSTRAINT + 3] = statistics.getAverage();
+            data[1 + index * NUMBER_OF_STATISTICS_PER_CONSTRAINT + 4] = statistics.getMax();
+        }
+
+        return data;
+    }
+
+    @SneakyThrows(WriterException.class)
+    public void add(final EvolutionResult<?, FitnessType> evolutionResult) {
+        final ISeq<Phenotype<?, FitnessType>> population = (ISeq<Phenotype<?, FitnessType>>)(Object)evolutionResult.population();
+
+        writer.addRecord(toData(evolutionResult.generation(), population));
+    }
+
+    @Override
+    public StatisticsWriter init(Instance configuration) {
+        return this;
+    }
+
+    public void write() {
+        endTime = System.currentTimeMillis();
+        try {
+            strategy.close(writer);
+        } catch (final WriterException e) {
+            log.error("Failed to write statistics:", e);
+        }
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/statistics/fitness/FitnessStatistics.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/statistics/fitness/FitnessStatistics.java
new file mode 100644
index 0000000000000000000000000000000000000000..1dd91a28fa915a90531de9672e1d644f32da917d
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/statistics/fitness/FitnessStatistics.java
@@ -0,0 +1,90 @@
+package de.evoal.core.main.statistics.fitness;
+
+import de.evoal.core.api.statistics.*;
+import de.evoal.languages.model.instance.Instance;
+import de.evoal.core.api.ea.fitness.type.FitnessType;
+import de.evoal.core.api.properties.PropertiesSpecification;
+import io.jenetics.Phenotype;
+import io.jenetics.engine.EvolutionResult;
+import io.jenetics.util.ISeq;
+import javax.annotation.PostConstruct;
+import javax.enterprise.context.Dependent;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Small helper class for collecting and writing the generation-based statistics.
+ */
+@Slf4j
+@Named("fitness-per-individual")
+@Dependent
+public class FitnessStatistics implements StatisticsWriter {
+    @Inject @Named("target-properties-specification")
+    private PropertiesSpecification targetSpecification;
+
+    @Inject
+    private WriterStrategy strategy;
+
+    private Writer writer;
+
+    @PostConstruct
+    @SneakyThrows(WriterException.class)
+    private void init() {
+        createWriter();
+    }
+
+    @Override
+    public StatisticsWriter init(Instance configuration) {
+        return this;
+    }
+
+    private void createWriter() throws WriterException {
+        final List<Column> columns = new LinkedList<>();
+
+        columns.add(new Column("generation", ColumnType.Integer));
+        columns.add(new Column("index", ColumnType.Integer));
+
+        for(int i = 0; i < targetSpecification.size(); ++i) {
+            columns.add(new Column("fitness-value-" + targetSpecification.getProperties().get(i).name(), ColumnType.Double));
+        }
+
+        writer = strategy.create("fitness-by-individual", columns);
+    }
+
+    private Object[] dataOfPhenotype(final int index, final long generation, Phenotype<?, FitnessType> phenotype) {
+        final Object [] data = new Object[2 + targetSpecification.size()];
+
+        data[0] = generation;
+        data[1] = index;
+
+        final double [] fitnessValues = phenotype.fitness().getFitnessValues();
+
+        for(int i = 0; i < fitnessValues.length; ++i) {
+            data[2 + i] = fitnessValues[i];
+        }
+
+        return data;
+    }
+
+    @SneakyThrows(WriterException.class)
+    public void add(final EvolutionResult<?, FitnessType> evolutionResult) {
+        final ISeq<Phenotype<?, FitnessType>> population = (ISeq<Phenotype<?, FitnessType>>)(Object)evolutionResult.population();
+
+        for(int i = 0; i < population.size(); ++i) {
+            writer.addRecord(dataOfPhenotype(i, evolutionResult.generation(), population.get(i)));
+        }
+    }
+
+    public void write() {
+        try {
+            strategy.close(writer);
+        } catch (final WriterException e) {
+            log.error("Failed to write statistics:", e);
+        }
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/statistics/individuals/IndividualStatistics.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/statistics/individuals/IndividualStatistics.java
new file mode 100644
index 0000000000000000000000000000000000000000..6179819c72cb238a35f29c2ac1b7f1e48be2f156
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/statistics/individuals/IndividualStatistics.java
@@ -0,0 +1,104 @@
+package de.evoal.core.main.statistics.individuals;
+
+import de.evoal.core.api.statistics.*;
+import de.evoal.languages.model.instance.Instance;
+import de.evoal.core.api.ea.codec.CustomCodec;
+import de.evoal.core.api.ea.fitness.type.FitnessType;
+import de.evoal.core.api.properties.Properties;
+import de.evoal.core.api.properties.PropertiesSpecification;
+import io.jenetics.Genotype;
+import io.jenetics.Phenotype;
+import io.jenetics.engine.EvolutionResult;
+import io.jenetics.util.ISeq;
+import javax.annotation.PostConstruct;
+import javax.enterprise.context.Dependent;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Small helper class for collecting and writing the generation-based statistics.
+ */
+@Slf4j
+@Named("individuals")
+@Dependent
+public class IndividualStatistics implements StatisticsWriter {
+    /**
+     * Encoding for converting between ea and domain.
+     */
+    @Inject
+    private CustomCodec encoding;
+
+    @Inject @Named("source-properties-specification")
+    private PropertiesSpecification sourceSpecification;
+
+    @Inject
+    private WriterStrategy strategy;
+
+    private Writer writer;
+
+    @PostConstruct
+    @SneakyThrows(WriterException.class)
+    private void init() {
+        createWriter();
+    }
+
+    @Override
+    public StatisticsWriter init(Instance configuration) {
+        return this;
+    }
+
+    private void createWriter() throws WriterException {
+        final List<Column> columns = new ArrayList<>();
+
+        columns.add(new Column("generation", ColumnType.Integer));
+        columns.add(new Column("index", ColumnType.Integer));
+        columns.add(new Column("individual", ColumnType.String));
+        columns.add(new Column("age", ColumnType.Integer));
+
+        for(int i = 0; i < sourceSpecification.size(); ++i) {
+            columns.add(new Column(sourceSpecification.getProperties().get(i).name(), ColumnType.Double));
+        }
+
+        writer = strategy.create("individuals", columns);
+    }
+
+    private Object[] dataOfPhenotype(final int index, final long generation, Phenotype<?, FitnessType> phenotype) {
+        final Object [] data = new Object[4 + sourceSpecification.size()];
+
+        final Genotype<?> genotype = phenotype.genotype();
+        final Properties individual = (Properties) encoding.decode(genotype);
+
+        data[0] = generation;
+        data[1] = index;
+        data[2] = individual.toString();
+        data[3] = phenotype.age(generation);
+
+        for(int i = 0; i < individual.size(); ++i) {
+            data[4 + i] = individual.getValues()[i];
+        }
+
+        return data;
+    }
+
+    @SneakyThrows(WriterException.class)
+    public void add(final EvolutionResult<?, FitnessType> evolutionResult) {
+        final ISeq<Phenotype<?, FitnessType>> population = (ISeq<Phenotype<?, FitnessType>>)(Object)evolutionResult.population();
+
+        for(int i = 0; i < population.size(); ++i) {
+            writer.addRecord(dataOfPhenotype(i, evolutionResult.generation(), population.get(i)));
+        }
+    }
+
+    public void write() {
+        try {
+            strategy.close(writer);
+        } catch (final WriterException e) {
+            log.error("Failed to write statistics:", e);
+        }
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/statistics/internal/MultipleStatisticsWriter.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/statistics/internal/MultipleStatisticsWriter.java
new file mode 100644
index 0000000000000000000000000000000000000000..0b08abaaccf281ae08ef6d846f0280110928257e
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/statistics/internal/MultipleStatisticsWriter.java
@@ -0,0 +1,31 @@
+package de.evoal.core.main.statistics.internal;
+
+import de.evoal.languages.model.instance.Instance;
+import de.evoal.core.api.statistics.StatisticsWriter;
+import de.evoal.core.api.ea.fitness.type.FitnessType;
+import io.jenetics.engine.EvolutionResult;
+
+import java.util.Arrays;
+
+public class MultipleStatisticsWriter implements StatisticsWriter {
+    private final StatisticsWriter[] writers;
+
+    public MultipleStatisticsWriter(final StatisticsWriter ... writers) {
+        this.writers = writers;
+    }
+
+    @Override
+    public void add(final EvolutionResult<?, FitnessType> evolutionResult) {
+        Arrays.stream(writers).forEach(w -> w.add(evolutionResult));
+    }
+
+    @Override
+    public StatisticsWriter init(Instance configuration) {
+        return this;
+    }
+
+    @Override
+    public void write() {
+        Arrays.stream(writers).forEach(StatisticsWriter::write);
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/statistics/nop/NopStatistics.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/statistics/nop/NopStatistics.java
new file mode 100644
index 0000000000000000000000000000000000000000..e0756ab82805db61dc82e657a27f3b80847ba2b7
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/statistics/nop/NopStatistics.java
@@ -0,0 +1,26 @@
+package de.evoal.core.main.statistics.nop;
+
+import de.evoal.languages.model.instance.Instance;
+import de.evoal.core.api.statistics.StatisticsWriter;
+import de.evoal.core.api.ea.fitness.type.FitnessType;
+import io.jenetics.engine.EvolutionResult;
+import javax.enterprise.context.Dependent;
+
+import javax.inject.Named;
+
+@Named("none")
+@Dependent
+public class NopStatistics implements StatisticsWriter {
+    @Override
+    public void add(final EvolutionResult<?, FitnessType> evolutionResult) {
+    }
+
+    @Override
+    public StatisticsWriter init(Instance configuration) {
+        return this;
+    }
+
+    @Override
+    public void write() {
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/statistics/rangeCorrelated/GenerationStatisticsWriter.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/statistics/rangeCorrelated/GenerationStatisticsWriter.java
new file mode 100644
index 0000000000000000000000000000000000000000..1ae8f06375ffb7fe274a5062e79b05aada938c2b
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/statistics/rangeCorrelated/GenerationStatisticsWriter.java
@@ -0,0 +1,193 @@
+package de.evoal.core.main.statistics.rangeCorrelated;
+
+import de.evoal.core.api.statistics.*;
+import de.evoal.core.api.ea.fitness.type.FitnessType;
+import de.evoal.core.api.ea.codec.CustomCodec;
+import de.evoal.core.api.properties.Properties;
+import de.evoal.core.main.ea.functions.correlation.model.Correlation;
+import de.evoal.core.main.ea.functions.correlation.model.Correlations;
+import de.evoal.core.main.ea.functions.correlation.model.RangedCorrelation;
+import de.evoal.languages.model.instance.Instance;
+import io.jenetics.Genotype;
+import io.jenetics.engine.EvolutionResult;
+import java.util.*;
+import javax.annotation.PostConstruct;
+import javax.enterprise.context.Dependent;
+import javax.inject.Inject;
+import javax.inject.Named;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.math3.util.Pair;
+
+
+/**
+ * Small helper class for collecting and writing the generation-based statistics.
+ */
+@Slf4j
+@Named("range-correlated")
+@Dependent
+public class GenerationStatisticsWriter implements StatisticsWriter {
+    /**
+     * Encoding for converting between ea and domain.
+     */
+    @Inject
+    private CustomCodec encoding;
+
+    @Inject @Named("genotype-limits")
+    private List<Pair<Double, Double>> limits;
+
+    @Inject
+    private Correlations correlations;
+
+    private List<Hypercube> hypercubeDefinitions;
+
+    private List<Hypercube> initialGenerationCubes;
+
+    @Inject
+    private WriterStrategy strategy;
+
+    private Writer writer;
+
+    /**
+     * Creates a new GenerationStatistics instance.
+     */
+    @PostConstruct
+    @SneakyThrows(WriterException.class)
+    public void init() {
+        final List<PropertyRange> rangesOfProperties = extractPropertyRangesFromCorrelations();
+        
+        hypercubeDefinitions = generateHypercubesFromRanges(rangesOfProperties, limits.size());
+
+        createWriter();
+    }
+
+    private void createWriter() throws WriterException {
+        final List<Column> columns = new LinkedList<>();
+
+        columns.add(new Column("generation", ColumnType.Integer));
+
+        for(int i = 0; i < hypercubeDefinitions.size(); ++i) {
+            columns.add(new Column("hypercube-" + (i+1), ColumnType.Double));
+        }
+
+        writer = strategy.create("hypercube-correlation-distances", columns);
+    }
+
+    private List<PropertyRange> extractPropertyRangesFromCorrelations() {
+        final List<PropertyRange> result = new ArrayList<>();
+
+        final List<Correlation> allTheCorrelations = correlations.getCorrelations();
+
+        allTheCorrelations
+                .stream()
+                .filter(RangedCorrelation.class::isInstance)
+                .map(RangedCorrelation.class::cast)
+                .forEach(rc -> {
+                    result.add(new PropertyRange(rc.getChromosomeOne(), rc.getChromosomeOneRange()));
+                    result.add(new PropertyRange(rc.getChromosomeTwo(), rc.getChromosomeTwoRange()));
+                });
+
+        return result;
+    }
+
+    @Override
+    public void add(final EvolutionResult<?, FitnessType> evolutionResult) {
+        if(evolutionResult.generation() == 1) {
+            initialGenerationCubes = fillHypercubes(evolutionResult);
+        }
+
+        final List<Hypercube> currentCubes = fillHypercubes(evolutionResult);
+    	double[] arrayOfDistances = new double[initialGenerationCubes.size()];
+    	for(int i=0; i< arrayOfDistances.length; i++) {
+   			arrayOfDistances[i] = currentCubes.get(i).computeSquaredDistanceToCovarianceMatrix(initialGenerationCubes.get(i));
+    	}
+
+    	Object[] data = new Object[1+ arrayOfDistances.length + 1];
+    	data[0] = evolutionResult.generation();
+    	double sum = 0.0;
+    	for(int i = 0; i < arrayOfDistances.length; i++) {
+    		data[i+1] = arrayOfDistances[i];
+    		sum += arrayOfDistances[i];
+    	}
+    	data[arrayOfDistances.length + 1] = sum;
+    	try {
+			writer.addRecord(data);
+		} catch (Exception e) {
+			log.error("The csv printing didn't work in generation {}", evolutionResult.generation(), e);
+		}
+    }
+    
+    private List<Hypercube> fillHypercubes(final EvolutionResult<?, FitnessType> evolutionResult){
+    	List<Hypercube> currentGeneration = new ArrayList<>();
+    	for(int j = 0; j < hypercubeDefinitions.size(); j++) {
+    		Hypercube hypercube = new Hypercube(hypercubeDefinitions.get(j));
+    		for(int i= 0; i < evolutionResult.population().asList().size(); i++) {
+                final Genotype<?> genotype = evolutionResult.population().asList().get(i).genotype();
+                final Properties domainValues = (Properties) encoding.decode(genotype);
+
+                hypercube.addDataPoint(domainValues);
+        	}
+    		currentGeneration.add(hypercube); 
+    	}
+    	return currentGeneration;
+    }
+
+    public void write() {
+        try {
+            strategy.close(writer);
+        } catch (final WriterException e) {
+            log.error("Failed to write statistics:", e);
+        }
+    }
+    
+    /**
+     * This methods builds all hypercubes resulting from the given ranges of the dvl. It need only be performed once., 
+     * @param listOfRanges
+     * @return
+     */
+    public List<Hypercube> generateHypercubesFromRanges(final List<PropertyRange> listOfRanges, final int dimensions){
+
+    	List<SortedSet<Double>> listOfBoundaries = new ArrayList<>(dimensions);
+    	for(int i=0; i<dimensions; i++) {
+    		final SortedSet<Double> boundaries = new TreeSet<>();
+            boundaries.add(limits.get(i).getFirst());
+            boundaries.add(limits.get(i).getSecond());
+
+            listOfBoundaries.add(boundaries);
+    	}
+
+    	//sorts every range into the correct dimension and sorts the interval values afterwards. 
+    	for(int j = 0; j < listOfRanges.size(); j++) {
+    		PropertyRange currentRange = listOfRanges.get(j);
+    		listOfBoundaries.get(currentRange.getIndexOfChromosome()).add(currentRange.getLower());
+    		listOfBoundaries.get(currentRange.getIndexOfChromosome()).add(currentRange.getUpper());
+    	}
+    	
+    	//we should have a list of sorted double values for each dimension now, containing all values existing in the dvl ranges
+        final List<Hypercube> hypercubes = new ArrayList<>();
+    	addVariationsOfNextDimension(dimensions, 0, new HypercubeBuilder(dimensions), listOfBoundaries, hypercubes);
+
+        return hypercubes;
+    }
+    
+    private void addVariationsOfNextDimension(int dimensions, int indexOfNextDimension, HypercubeBuilder builder, List<SortedSet<Double>> listOfBoundaries, final List<Hypercube> result){
+        if(indexOfNextDimension == dimensions) {
+            result.add(builder.build());
+            return;
+        }
+
+        final List<Double> boundaries = new ArrayList<>(listOfBoundaries.get(indexOfNextDimension));
+
+        for(int i = 0; i < boundaries.size() - 1; ++i) {
+            final HypercubeBuilder next = new HypercubeBuilder(builder);
+            next.append(boundaries.get(i), boundaries.get(i + 1));
+
+            addVariationsOfNextDimension(dimensions, indexOfNextDimension +  1, next, listOfBoundaries, result);
+        }
+    }
+
+    @Override
+    public StatisticsWriter init(Instance configuration) {
+        return this;
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/statistics/rangeCorrelated/Hypercube.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/statistics/rangeCorrelated/Hypercube.java
new file mode 100644
index 0000000000000000000000000000000000000000..a34fb9a534b1972fdab3ff9f6a407d19ba9c7e6b
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/statistics/rangeCorrelated/Hypercube.java
@@ -0,0 +1,106 @@
+package de.evoal.core.main.statistics.rangeCorrelated;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import de.evoal.core.main.ea.functions.correlation.model.Range;
+import de.evoal.core.api.properties.Properties;
+
+import smile.math.matrix.Matrix;
+
+public class Hypercube {
+	private final int dimensions;
+	private final Range[] definition;
+	private final List<Properties> data = new ArrayList<>();
+
+	public Hypercube(final Hypercube other) {
+		this.dimensions = other.dimensions;
+		this.definition = other.definition;
+	}
+	
+	public Hypercube(Range[] definition) {
+		this.definition = definition;
+		this.dimensions = definition.length;
+	}
+	
+	public Hypercube(final Range[] definition, int dimensions) {
+		if(definition.length != dimensions) {
+			throw new IllegalStateException("Hypercubedefinition does not match number of dimensions.");
+		}
+		
+		else {
+			this.definition = definition;
+			this.dimensions = dimensions;
+		}
+	}
+	
+	public boolean check(Properties dataPoint) {
+		if(dataPoint.size()!= dimensions) {
+			throw new IllegalStateException("Given dataPoint does not have the same number of dimensions as the hypercube");
+		}
+		
+		else {
+			for(int i=0; i< dataPoint.size(); i++) {
+				if(!definition[i].includes(dataPoint.get(i))){
+					return false;
+				}
+			}
+			return true;
+		}
+	}
+	
+	public void addDataPoint(final Properties dataPoint) {
+		if(check(dataPoint)) {
+			data.add(dataPoint);			
+		}
+	}
+	
+	public Matrix computeCovarianceMatrix(){
+		final int dimensions = this.dimensions;
+        final int dataSize = data.size();
+
+        if(dataSize == 0) {
+        	return new Matrix(dimensions, dimensions);
+		}
+
+        final double [] means = new double[dimensions];
+        for(int i=0; i< dataSize; i++) {
+        	for(int j=0; j< dimensions; j++) {
+        		means[j] = means[j] + data.get(i).get(j)/(double)data.size();
+        	}
+        }
+
+
+        final Matrix covarianceMatrix = new Matrix(dimensions, dimensions);
+        for(int x = 0; x < dimensions; ++x) {
+            for(int y = 0; y < dimensions; ++y) {
+                double value = 0.0;
+                for(int t = 0; t < dataSize; ++t) {
+                    value += ((data.get(t).get(x) - means[x])*(data.get(t).get(y) - means[y]));
+                }
+                value = value / dataSize;
+                covarianceMatrix.set(x, y, value);
+            }
+        }
+
+        return covarianceMatrix;
+	}
+	
+	public double computeSquaredDistanceToCovarianceMatrix(Hypercube other) {
+		Matrix otherCovariance = other.computeCovarianceMatrix();
+		Matrix thisCovariance = this.computeCovarianceMatrix();
+		
+		Matrix difference = thisCovariance.sub(otherCovariance); 
+		difference.mul(difference);
+		return difference.sum();
+		
+	}
+	
+	public boolean equals(Hypercube other) {
+		return  this.definition.equals(other.definition);
+	}
+	
+	public boolean contentEquals(Hypercube other) {
+		return this.definition.equals(other.definition) && this.data.equals(other.data); 
+	}
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/statistics/rangeCorrelated/HypercubeBuilder.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/statistics/rangeCorrelated/HypercubeBuilder.java
new file mode 100644
index 0000000000000000000000000000000000000000..9ac150c063f8ab02967af3f860ea07d4ba59f71e
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/statistics/rangeCorrelated/HypercubeBuilder.java
@@ -0,0 +1,32 @@
+package de.evoal.core.main.statistics.rangeCorrelated;
+
+import de.evoal.core.main.ea.functions.correlation.model.Range;
+
+import java.util.LinkedList;
+import java.util.List;
+
+public class HypercubeBuilder {
+	private final int dimensions;
+	private final List<Range> intervals = new LinkedList<>();
+	
+	public HypercubeBuilder(int dimensions) {
+		this.dimensions = dimensions; 
+	}
+	
+	public HypercubeBuilder(final HypercubeBuilder halfbuiltCube) {
+		this.dimensions = halfbuiltCube.dimensions;
+		this.intervals.addAll(halfbuiltCube.intervals);
+	}
+
+	public Hypercube build() {
+		if(intervals.size() == dimensions) {
+			return new Hypercube(intervals.toArray(new Range [dimensions]), dimensions);
+		}
+
+		else throw new IllegalStateException("Intervallist is not yet complete.");
+	}
+
+	public void append(final double lower, final double upper) {
+		intervals.add(new Range(lower, upper));
+	}
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/statistics/rangeCorrelated/Interval.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/statistics/rangeCorrelated/Interval.java
new file mode 100644
index 0000000000000000000000000000000000000000..a7fae3887a601c20d603619b1cfd2dc9b6e469b8
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/statistics/rangeCorrelated/Interval.java
@@ -0,0 +1,15 @@
+package de.evoal.core.main.statistics.rangeCorrelated;
+
+public class Interval {
+	private double lowerBound;
+	private double upperBound;
+	
+	public boolean check(double value) {
+		return (lowerBound <= value && value <= upperBound);
+	}
+	
+	public Interval(double lowerBound, double upperBound) {
+		this.lowerBound = lowerBound;
+		this.upperBound = upperBound;
+	}
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/statistics/rangeCorrelated/PropertyRange.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/statistics/rangeCorrelated/PropertyRange.java
new file mode 100644
index 0000000000000000000000000000000000000000..269e082d399ca2db479bf60ffc66a59fe154fcb0
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/statistics/rangeCorrelated/PropertyRange.java
@@ -0,0 +1,29 @@
+package de.evoal.core.main.statistics.rangeCorrelated;
+
+import de.evoal.core.main.ea.functions.correlation.model.Range;
+
+public class PropertyRange {
+	// TODO FIXME AND SO ON
+
+
+	private final int indexOfChromosome;
+	private final Range range;
+
+	public PropertyRange(final int indexOfChromosome, final Range range) {
+		this.indexOfChromosome = indexOfChromosome;
+		this.range = range;
+	}
+
+	public int getIndexOfChromosome() {
+		return indexOfChromosome;
+	}
+
+	public double getLower() {
+		return range.getLower();
+	}
+
+	public double getUpper() {
+		return range.getUpper();
+	}
+}
+
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/statistics/rangeCorrelated/Range.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/statistics/rangeCorrelated/Range.java
new file mode 100644
index 0000000000000000000000000000000000000000..80bc27dfb95b9f5c661eb129bbfb4d4b9bf370dc
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/statistics/rangeCorrelated/Range.java
@@ -0,0 +1,3 @@
+package de.evoal.core.main.statistics.rangeCorrelated;
+
+record Range(double lower, double upper) {}
\ No newline at end of file
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/statistics/writer/csv/CsvStrategy.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/statistics/writer/csv/CsvStrategy.java
new file mode 100644
index 0000000000000000000000000000000000000000..cc12027222fa579c14c331e7e7ea3e1d312cad2f
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/statistics/writer/csv/CsvStrategy.java
@@ -0,0 +1,49 @@
+package de.evoal.core.main.statistics.writer.csv;
+
+import de.evoal.core.api.board.BlackboardEntry;
+import de.evoal.core.api.cdi.BlackboardValue;
+import de.evoal.core.api.statistics.Column;
+import de.evoal.core.api.statistics.Writer;
+import de.evoal.core.api.statistics.WriterException;
+import de.evoal.core.api.statistics.WriterStrategy;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
+import javax.inject.Named;
+import java.io.File;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@ApplicationScoped
+@Named("csv")
+public class CsvStrategy extends WriterStrategy {
+    @Inject @BlackboardValue(BlackboardEntry.EVALUATION_OUTPUT_FOLDER)
+    private File outputFolder;
+
+    private final Map<String, CsvWriter> writerMap = new HashMap<>();
+
+    @Override
+    public void close(final Writer writer) {
+        writer.flush();
+    }
+
+    @Override
+    public Writer create(final String name, final List<Column> header) throws WriterException {
+        if(writerMap.containsKey(name)) {
+            return writerMap.get(name);
+        }
+
+        final File csvFile = new File(outputFolder, name + ".csv");
+        csvFile.getParentFile().mkdirs();
+
+        final CsvWriter writer = new CsvWriter(csvFile, context, header);
+        writerMap.put(name, writer);
+
+        return writer;
+    }
+
+    protected void finalize() {
+        writerMap.values().forEach(Writer::close);
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/statistics/writer/csv/CsvWriter.java b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/statistics/writer/csv/CsvWriter.java
new file mode 100644
index 0000000000000000000000000000000000000000..9560ed8056db8278febed2caf13815f034c06eeb
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/de/evoal/core/main/statistics/writer/csv/CsvWriter.java
@@ -0,0 +1,84 @@
+package de.evoal.core.main.statistics.writer.csv;
+
+import de.evoal.core.api.statistics.Column;
+import de.evoal.core.api.statistics.Writer;
+import de.evoal.core.api.statistics.WriterContext;
+import de.evoal.core.api.statistics.WriterException;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVPrinter;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.List;
+
+@Slf4j
+public class CsvWriter implements Writer {
+
+    private final CSVPrinter csvPrinter;
+    private final FileWriter csvWriter;
+    private final WriterContext context;
+
+    public CsvWriter(final File filename, final WriterContext context, final List<Column> header) throws WriterException {
+        try {
+            final String[] fileHeader = new String[context.size() + header.size()];
+
+            int i = 0;
+            for(final Column column : context.getColumns()) {
+                fileHeader[i++] = column.getName();
+            }
+
+            for(final Column column : header) {
+                fileHeader[i++] = column.getName();
+            }
+
+            csvWriter = new FileWriter(filename);
+            csvPrinter = new CSVPrinter(csvWriter,
+                    CSVFormat.DEFAULT
+                            .withHeader(fileHeader));
+
+            this.context = context;
+        } catch(final IOException e) {
+            throw new WriterException("Unable to open CSV file: " + filename, e);
+        }
+    }
+
+    @Override
+    public void addRecord(final Object[] data) throws WriterException {
+        System.err.println("Adding data to file.");
+        try {
+            for(final Column column : context.getColumns()) {
+                csvPrinter.print(context.get(column));
+            }
+
+            for(final Object obj : data) {
+                csvPrinter.print(obj);
+            }
+
+            csvPrinter.println();
+        } catch(final IOException e) {
+            throw new WriterException("Unable to write CSV file.", e);
+        }
+    }
+
+    @Override
+    public void close() {
+        try {
+            csvPrinter.close();
+            csvWriter.close();
+        } catch (final IOException e) {
+            log.error("Failed to close CSV file.", e);
+        }
+    }
+
+    @Override
+    public void flush() {
+        try {
+            csvPrinter.flush();
+            csvWriter.flush();
+        } catch (final IOException e) {
+            log.error("Failed to close CSV file.", e);
+        }
+    }
+}
diff --git a/src/core/de.evoal.core.main/src/main/java/module-info.java b/src/core/de.evoal.core.main/src/main/java/module-info.java
new file mode 100644
index 0000000000000000000000000000000000000000..46cf1d7e58f7fc5a744ba3428d1315c19fdfbe86
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/java/module-info.java
@@ -0,0 +1,59 @@
+module de.evoal.core.main {
+    requires jakarta.enterprise.cdi.api;
+    requires jakarta.inject.api;
+
+    requires java.annotation;
+    requires java.base;
+
+    requires lombok;
+    requires org.slf4j;
+
+    requires weld.se.core;
+    requires deltaspike.cdictrl.api;
+    requires deltaspike.cdictrl.weld;
+    requires deltaspike.core.api;
+
+    requires org.eclipse.emf.common;
+    requires org.eclipse.emf.ecore;
+    requires org.eclipse.xtext;
+
+    requires io.jenetics.base;
+    requires commons.math3;
+    requires commons.csv;
+    requires smile.math;
+
+    requires com.fasterxml.jackson.databind;
+    requires io.jenetics.ext;
+    requires decimal4j;
+    requires guice;
+
+    requires de.evoal.languages.model.dl.dsl;
+    requires de.evoal.languages.model.dl;
+    requires de.evoal.languages.model.eal;
+    requires de.evoal.languages.model.eal.dsl;
+    requires de.evoal.languages.model.el;
+    requires de.evoal.languages.model.el.dsl;
+    requires de.evoal.languages.model.instance;
+
+    requires de.evoal.core.api;
+    requires de.evoal.languages.model.ddl;
+
+    opens de.evoal.core.main.cdi.producer to weld.core.impl;
+    opens de.evoal.core.main.ddl.correlation to weld.core.impl;
+    opens de.evoal.core.main.ddl.constraint to weld.core.impl;
+    opens de.evoal.core.main.ddl.constraint.strategies to weld.core.impl;
+    opens de.evoal.core.main.ddl.constraint.strategies.calculations to weld.core.impl;
+    opens de.evoal.core.main.ddl.constraint.strategies.constraint to weld.core.impl;
+    opens de.evoal.core.main.ddl.constraint.strategies.fitness to weld.core.impl;
+    opens de.evoal.core.main.ddl.deviation to weld.core.impl;
+    opens de.evoal.core.main.ea.alterer to weld.core.impl;
+    opens de.evoal.core.main.ea.alterer.mutator to weld.core.impl;
+    opens de.evoal.core.main.search to weld.core.impl;
+    opens de.evoal.core.main.statistics to weld.core.impl;
+    opens de.evoal.core.main.statistics.constraint to weld.core.impl;
+    opens de.evoal.core.main.statistics.fitness to weld.core.impl;
+    opens de.evoal.core.main.statistics.individuals to weld.core.impl;
+    opens de.evoal.core.main.statistics.nop to weld.core.impl;
+    opens de.evoal.core.main.statistics.rangeCorrelated to weld.core.impl;
+    opens de.evoal.core.main.statistics.writer.csv to weld.core.impl;
+}
diff --git a/src/core/de.evoal.core.main/src/main/resources/META-INF/MANIFEST.MF b/src/core/de.evoal.core.main/src/main/resources/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000000000000000000000000000000000..9d885be534121a9f146924f4832955dfe2ee2d4b
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/resources/META-INF/MANIFEST.MF
@@ -0,0 +1 @@
+Manifest-Version: 1.0
diff --git a/src/core/de.evoal.core.main/src/main/resources/META-INF/beans.xml b/src/core/de.evoal.core.main/src/main/resources/META-INF/beans.xml
new file mode 100644
index 0000000000000000000000000000000000000000..36964de4bdc1dbcbbf02c9552692e62804947dc3
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/resources/META-INF/beans.xml
@@ -0,0 +1,11 @@
+<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd"
+       bean-discovery-mode="annotated"
+       version="2.0">
+    <scan>
+        <exclude name="org.apache.deltaspike.core.impl.throttling.ThrottledInterceptor" />
+        <exclude name="org.apache.deltaspike.core.impl.scope.window.DefaultWindowContextQuotaHandler" />
+        <exclude name="org.apache.deltaspike.core.impl.scope.window.WindowBeanHolder" />
+    </scan>
+</beans>
\ No newline at end of file
diff --git a/src/core/de.evoal.core.main/src/main/resources/logback.xml b/src/core/de.evoal.core.main/src/main/resources/logback.xml
new file mode 100644
index 0000000000000000000000000000000000000000..94e55be2c26acd3500962d34eaa3d74732293502
--- /dev/null
+++ b/src/core/de.evoal.core.main/src/main/resources/logback.xml
@@ -0,0 +1,13 @@
+<configuration>
+  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+    <encoder>
+      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
+    </encoder>
+  </appender>
+
+  <logger name="de.evoal" level="INFO" />
+
+  <root level="WARN">
+    <appender-ref ref="STDOUT" />
+  </root>
+</configuration>
\ No newline at end of file
diff --git a/src/core/de.evoal.core.releng.parent/pom.xml b/src/core/de.evoal.core.releng.parent/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a23b50a98035af19b390de40a3740e6390deb177
--- /dev/null
+++ b/src/core/de.evoal.core.releng.parent/pom.xml
@@ -0,0 +1,211 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>de.evoal.core</groupId>
+    <artifactId>releng.parent</artifactId>
+    <version>0.9.0-SNAPSHOT</version>
+    <packaging>pom</packaging>
+
+    <name>EvoAl - Core - Parent</name>
+
+    <properties>
+        <maven.compiler.source>17</maven.compiler.source>
+        <maven.compiler.target>17</maven.compiler.target>
+
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+
+        <deltaspike.version>1.9.6</deltaspike.version>
+        <evoal.languages.version>1.0.0-SNAPSHOT</evoal.languages.version>
+        <jackson.version>2.13.4</jackson.version>
+        <jenetics.version>7.1.0</jenetics.version>
+        <lombok.version>1.18.24</lombok.version>
+        <slf4j.api.version>2.0.0</slf4j.api.version>
+        <smile.version>2.6.0</smile.version>
+    </properties>
+
+    <modules>
+        <module>../de.evoal.core.api</module>
+        <module>../de.evoal.core.main</module>
+        <module>../de.evoal.generator.main</module>
+        <module>../de.evoal.surrogate.api</module>
+        <module>../de.evoal.surrogate.simple</module>
+        <module>../de.evoal.surrogate.svr</module>
+<!--        <module>../de.evoal.surrogate.neural</module> -->
+    </modules>
+
+    <dependencies>
+        <!-- CDI APIs -->
+        <dependency>
+            <groupId>jakarta.inject</groupId>
+            <artifactId>jakarta.inject-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>jakarta.enterprise</groupId>
+            <artifactId>jakarta.enterprise.cdi-api</artifactId>
+            <version>2.0.2</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <!-- Logging API -->
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+            <version>${slf4j.api.version}</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <!-- Prevent me from typing -->
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+
+    <dependencyManagement>
+        <dependencies>
+            <!-- CDI APIs -->
+            <dependency>
+                <groupId>jakarta.inject</groupId>
+                <artifactId>jakarta.inject-api</artifactId>
+                <version>1.0</version>
+            </dependency>
+
+            <dependency>
+                <groupId>jakarta.enterprise</groupId>
+                <artifactId>jakarta.enterprise.cdi-api</artifactId>
+                <version>2.0.2</version>
+            </dependency>
+
+            <dependency>
+                <groupId>javax.annotation</groupId>
+                <artifactId>javax.annotation-api</artifactId>
+                <version>1.3.2</version>
+            </dependency>
+            
+            <!-- Logging API -->
+            <dependency>
+                <groupId>org.slf4j</groupId>
+                <artifactId>slf4j-api</artifactId>
+                <version>${slf4j.api.version}</version>
+            </dependency>
+
+            <!-- Prevent me from typing -->
+            <dependency>
+                <groupId>org.projectlombok</groupId>
+                <artifactId>lombok</artifactId>
+                <version>${lombok.version}</version>
+                <scope>provided</scope>
+            </dependency>
+
+            <!-- Xtext -->
+            <dependency>
+                <groupId>org.eclipse.emf</groupId>
+                <artifactId>org.eclipse.emf.ecore</artifactId>
+                <version>2.25.0</version>
+                <scope>provided</scope>
+            </dependency>
+
+            <dependency>
+                <groupId>org.eclipse.emf</groupId>
+                <artifactId>org.eclipse.emf.common</artifactId>
+                <version>2.25.0</version>
+                <scope>provided</scope>
+            </dependency>
+
+            <dependency>
+                <groupId>org.eclipse.xtext</groupId>
+                <artifactId>org.eclipse.xtext</artifactId>
+                <version>2.25.0</version>
+                <scope>provided</scope>
+            </dependency>
+
+            <dependency>
+                <groupId>org.antlr</groupId>
+                <artifactId>antlr-runtime</artifactId>
+                <version>3.2</version>
+            </dependency>
+
+
+            <!--
+
+                        <!- - Unit Testing - ->
+                        <dependency>
+                            <groupId>org.junit.jupiter</groupId>
+                            <artifactId>junit-jupiter-api</artifactId>
+                            <version>5.8.2</version>
+                            <scope>test</scope>
+                        </dependency>
+                    -->
+
+            <dependency>
+                <groupId>de.evoal.core</groupId>
+                <artifactId>core.api</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <version>3.2.2</version>
+            </plugin>
+        </plugins>
+
+        <pluginManagement>
+            <plugins>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-compiler-plugin</artifactId>
+                    <version>3.10.1</version>
+                    <configuration>
+                        <forceJavacCompilerUse>true</forceJavacCompilerUse>
+                        <annotationProcessorPaths>
+                            <path>
+                                <groupId>org.projectlombok</groupId>
+                                <artifactId>lombok</artifactId>
+                                <version>${lombok.version}</version>
+                            </path>
+                        </annotationProcessorPaths>
+                    </configuration>
+                </plugin>
+            </plugins>
+        </pluginManagement>
+    </build>
+
+    <distributionManagement>
+        <repository>
+            <id>gitlab-maven</id>
+            <name>Stable Releases</name>
+            <url>${env.CI_API_V4_URL}/projects/${env.CI_PROJECT_ID}/packages/maven</url>
+        </repository>
+
+        <snapshotRepository>
+            <id>gitlab-maven</id>
+            <name>Internal Snapshots</name>
+            <url>${env.CI_API_V4_URL}/projects/${env.CI_PROJECT_ID}/packages/maven</url>
+        </snapshotRepository>
+    </distributionManagement>
+
+    <repositories>
+        <repository>
+            <id>evoal-artifacts</id>
+            <name>EvoAl - Artifacts</name>
+            <url>https://gitlab.informatik.uni-bremen.de/api/v4/projects/30380/packages/maven</url>
+            <releases>
+                <enabled>true</enabled>
+            </releases>
+            <snapshots>
+                <enabled>true</enabled>
+            </snapshots>
+        </repository>
+    </repositories>
+
+</project>
diff --git a/src/core/de.evoal.generator.main/pom.xml b/src/core/de.evoal.generator.main/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..7aeb1b9c2886ebda93009835e03d4b7b1f040cbc
--- /dev/null
+++ b/src/core/de.evoal.generator.main/pom.xml
@@ -0,0 +1,138 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+
+	<parent>
+		<groupId>de.evoal.core</groupId>
+		<artifactId>releng.parent</artifactId>
+		<version>0.9.0-SNAPSHOT</version>
+
+		<relativePath>../de.evoal.core.releng.parent</relativePath>
+	</parent>
+
+	<artifactId>generator.main</artifactId>
+	<name>EvoAl - Generator - Main</name>
+
+	<dependencies>
+		<dependency>
+			<groupId>${project.groupId}</groupId>
+			<artifactId>core.api</artifactId>
+			<scope>provided</scope>
+		</dependency>
+
+		<!-- DSL dependencies -->
+		<!-- Xtext -->
+		<dependency>
+			<groupId>org.eclipse.emf</groupId>
+			<artifactId>org.eclipse.emf.ecore</artifactId>
+		</dependency>
+
+		<dependency>
+			<groupId>org.eclipse.emf</groupId>
+			<artifactId>org.eclipse.emf.common</artifactId>
+		</dependency>
+
+		<dependency>
+			<groupId>org.eclipse.xtext</groupId>
+			<artifactId>org.eclipse.xtext</artifactId>
+		</dependency>
+
+		<!-- Math libraries -->
+		<dependency>
+			<groupId>org.apache.commons</groupId>
+			<artifactId>commons-math3</artifactId>
+			<version>3.6.1</version>
+		</dependency>
+
+		<dependency>
+			<groupId>de.evoal.languages</groupId>
+			<artifactId>de.evoal.languages.model.ddl</artifactId>
+			<version>${evoal.languages.version}</version>
+		</dependency>
+
+		<dependency>
+			<groupId>de.evoal.languages</groupId>
+			<artifactId>de.evoal.languages.model.dl</artifactId>
+			<version>${evoal.languages.version}</version>
+		</dependency>
+
+		<dependency>
+			<groupId>de.evoal.languages</groupId>
+			<artifactId>de.evoal.languages.model.el</artifactId>
+			<version>${evoal.languages.version}</version>
+		</dependency>
+
+		<dependency>
+			<groupId>de.evoal.languages</groupId>
+			<artifactId>de.evoal.languages.model.generator</artifactId>
+			<version>${evoal.languages.version}</version>
+		</dependency>
+
+		<dependency>
+			<groupId>de.evoal.languages</groupId>
+			<artifactId>de.evoal.languages.model.instance</artifactId>
+			<version>${evoal.languages.version}</version>
+		</dependency>
+
+		<dependency>
+			<groupId>de.evoal.languages</groupId>
+			<artifactId>de.evoal.languages.model.ddl.dsl</artifactId>
+			<version>${evoal.languages.version}</version>
+		</dependency>
+
+		<dependency>
+			<groupId>de.evoal.languages</groupId>
+			<artifactId>de.evoal.languages.model.dl.dsl</artifactId>
+			<version>${evoal.languages.version}</version>
+		</dependency>
+
+		<dependency>
+			<groupId>de.evoal.languages</groupId>
+			<artifactId>de.evoal.languages.model.el.dsl</artifactId>
+			<version>${evoal.languages.version}</version>
+		</dependency>
+
+		<dependency>
+			<groupId>de.evoal.languages</groupId>
+			<artifactId>de.evoal.languages.model.generator.dsl</artifactId>
+			<version>${evoal.languages.version}</version>
+		</dependency>
+	</dependencies>
+
+	<build>
+		<plugins>
+			<plugin>
+				<artifactId>maven-dependency-plugin</artifactId>
+				<executions>
+					<execution>
+						<phase>package</phase>
+						<goals>
+							<goal>copy-dependencies</goal>
+						</goals>
+						<configuration>
+							<outputDirectory>${project.build.directory}/${project.artifactId}-dependencies</outputDirectory>
+							<includeScope>runtime</includeScope>
+							<excludeScope>provided</excludeScope>
+							<excludeTransitive>true</excludeTransitive>
+						</configuration>
+					</execution>
+				</executions>
+			</plugin>
+
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-jar-plugin</artifactId>
+				<configuration>
+					<archive>
+						<manifestFile>src/main/resources/META-INF/MANIFEST.MF</manifestFile>
+						<manifest>
+							<addClasspath>true</addClasspath>
+							<classpathPrefix>${project.artifactId}-dependencies/</classpathPrefix>
+						</manifest>
+					</archive>
+				</configuration>
+			</plugin>
+		</plugins>
+	</build>
+</project>
diff --git a/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/api/AbstractGeneratorFunction.java b/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/api/AbstractGeneratorFunction.java
new file mode 100644
index 0000000000000000000000000000000000000000..a685db2967ae81ad43ef9011b7362f7db3b0b3c8
--- /dev/null
+++ b/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/api/AbstractGeneratorFunction.java
@@ -0,0 +1,70 @@
+package de.evoal.generator.api;
+
+import de.evoal.core.api.properties.Properties;
+import de.evoal.core.api.properties.PropertiesSpecification;
+import de.evoal.core.api.properties.PropertySpecification;
+import de.evoal.languages.model.ddl.DataDescription;
+import de.evoal.languages.model.generator.Step;
+import de.evoal.languages.model.instance.DataReference;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.List;
+
+@Slf4j
+public abstract class AbstractGeneratorFunction implements GeneratorFunction {
+
+    protected Step configuration;
+
+    /**
+     * The properties the generator function writes.
+     */
+    protected PropertiesSpecification writeSpecification;
+
+    /**
+     * The properties the generator function reads.
+     */
+    protected PropertiesSpecification readSpecification;
+
+    @Override
+    public GeneratorFunction init(final Step configuration) {
+        this.configuration = configuration;
+
+        writeSpecification = createSpecification(configuration.getWrites());
+        readSpecification = createSpecification(configuration.getReads());
+
+        log.info("Reading {}", readSpecification);
+        log.info("Writing {}", writeSpecification);
+
+        return this;
+    }
+
+    private static PropertiesSpecification createSpecification(final List<DataReference> references) {
+        final PropertiesSpecification.Builder builder = PropertiesSpecification.builder();
+
+        builder.add(references.stream()
+                              .map(DataReference::getDefinition)
+                              .map(DataDescription::getName));
+
+        return builder.build();
+    }
+
+    /**
+     * Merges the properties' specification with the write-specicfication of this
+     *   generator function, creates a new properties instance according to the new
+     *   specification and copies all property values.
+     */
+    protected Properties mergeAndCopy(final Properties properties) {
+        final PropertiesSpecification specification =
+                PropertiesSpecification.builder()
+                                       .add(properties.getSpecification())
+                                       .add(writeSpecification)
+                                       .build();
+
+        final Properties result = new Properties(specification);
+        for(final PropertySpecification ps : properties.getSpecification().getProperties()) {
+            result.put(ps, properties.get(ps));
+        }
+
+        return result;
+    }
+}
diff --git a/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/api/GeneratorBlackboardEntry.java b/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/api/GeneratorBlackboardEntry.java
new file mode 100644
index 0000000000000000000000000000000000000000..1430b3747ff62e05158e8782ae7cb11c66884792
--- /dev/null
+++ b/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/api/GeneratorBlackboardEntry.java
@@ -0,0 +1,15 @@
+package de.evoal.generator.api;
+
+public final class GeneratorBlackboardEntry {
+    /**
+     * Loaded generator configuration.
+     */
+    public static final String GENERATOR_CONFIGURATION = "generator:configuration";
+
+    /**
+     * Configuration file for the data generator.
+     */
+    public static final String GENERATOR_CONFIGURATION_FILE = "generator:configuration-file";
+
+    private GeneratorBlackboardEntry() {}
+}
diff --git a/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/api/GeneratorFunction.java b/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/api/GeneratorFunction.java
new file mode 100644
index 0000000000000000000000000000000000000000..fa25d8fd24ce733402983e352d92a5a545f5f3db
--- /dev/null
+++ b/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/api/GeneratorFunction.java
@@ -0,0 +1,15 @@
+package de.evoal.generator.api;
+
+
+import de.evoal.core.api.properties.Properties;
+import de.evoal.languages.model.generator.Step;
+
+/**
+ * Interface for all generator functions. A generator function is a named CDI
+ *   component with a pre-defined life-cycle.
+ */
+public interface GeneratorFunction {
+    GeneratorFunction init(final Step configuration);
+
+    public Properties apply(final Properties in);
+}
diff --git a/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/DataGenerator.java b/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/DataGenerator.java
new file mode 100644
index 0000000000000000000000000000000000000000..2dee16b414624cffc8d23f2c3343213809ed0486
--- /dev/null
+++ b/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/DataGenerator.java
@@ -0,0 +1,74 @@
+package de.evoal.generator.main;
+
+import java.io.*;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import de.evoal.core.api.cdi.BlackboardValue;
+import de.evoal.core.api.cdi.MainClass;
+import de.evoal.generator.api.*;
+import de.evoal.generator.main.generators.GeneratorFactory;
+import de.evoal.generator.main.internal.Pipeline;
+import de.evoal.generator.main.internal.StatementExecutor;
+import de.evoal.languages.model.generator.Configuration;
+import de.evoal.languages.model.generator.PipelineDefinition;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Main class for EvoAl's data generator.
+ */
+@ApplicationScoped
+@Named("data-generator")
+public class DataGenerator implements MainClass {
+
+	/**
+	 * Logger instance
+	 */
+	private final static Logger log = LoggerFactory.getLogger(DataGenerator.class);
+
+	@Inject
+	@BlackboardValue(GeneratorBlackboardEntry.GENERATOR_CONFIGURATION)
+	private Configuration configuration;
+
+	@Inject
+	private GeneratorFactory factory;
+
+	@Override
+	public void run() {
+		log.info("Starting data generation.");
+
+		final Map<String, Pipeline> pipelineTable = createPipelines();
+
+		new StatementExecutor(pipelineTable)
+				.execute(configuration.getStatements());
+
+		log.info("Finished data generation.");
+	}
+
+	private Map<String, Pipeline> createPipelines() {
+		final Map<String, Pipeline> result = new HashMap<>();
+
+		for(final PipelineDefinition definition : configuration.getPipelines()) {
+			final String pipelineName = definition.getName();
+
+			log.info("Creating pipeline '{}'.", pipelineName);
+
+			final Pipeline pipeline = new Pipeline(pipelineName,
+												   definition.getSteps()
+															 .stream()
+															 .map(factory::create)
+															 .collect(Collectors.toList()));
+
+			result.put(pipelineName, pipeline);
+		}
+
+		return result;
+	}
+}
diff --git a/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/benchmarks/Ackley.java b/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/benchmarks/Ackley.java
new file mode 100644
index 0000000000000000000000000000000000000000..6cca3ee9d8f15408bd3ce24089b7880848227ca5
--- /dev/null
+++ b/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/benchmarks/Ackley.java
@@ -0,0 +1,57 @@
+package de.evoal.generator.main.benchmarks;
+
+import de.evoal.core.api.properties.Properties;
+import de.evoal.core.api.properties.PropertySpecification;
+import de.evoal.generator.api.AbstractGeneratorFunction;
+import de.evoal.generator.api.GeneratorFunction;
+import de.evoal.generator.main.utils.ELHelper;
+import de.evoal.languages.model.generator.Step;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.enterprise.context.Dependent;
+import javax.inject.Named;
+
+@Dependent
+@Named("ackley")
+@Slf4j
+public class Ackley extends AbstractGeneratorFunction {
+    private double a = 20;
+
+    private double b = 0.2;
+
+    private double c = 6.283185307179586;
+
+    @Override
+    public Properties apply(final Properties in) {
+        final Properties result = mergeAndCopy(in);
+
+        final double n = readSpecification.size();
+
+        double sum1 = 0.0;
+        double sum2 = 0.0;
+
+        for(final PropertySpecification ps : readSpecification.getProperties()) {
+            double read_i = in.get(ps);
+
+        	sum1 += Math.pow(read_i, 2.0);
+        	sum2 += Math.cos(c * read_i);
+        }
+
+        double value = -a * Math.exp(-b * Math.sqrt((1 / n) * sum1)) - Math.exp((1 / n) * sum2) + a + Math.E;
+
+        result.put(writeSpecification.getProperties().get(0), value);
+
+        return result;
+    }
+
+    @Override
+    public GeneratorFunction init(final Step configuration) {
+        super.init(configuration);
+
+        a = ELHelper.readDouble(configuration.getInstance(), "a");
+        b = ELHelper.readDouble(configuration.getInstance(), "b");
+        c = ELHelper.readDouble(configuration.getInstance(), "c");
+
+        return this;
+    }
+}
diff --git a/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/benchmarks/Rastrigin.java b/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/benchmarks/Rastrigin.java
new file mode 100644
index 0000000000000000000000000000000000000000..c5538d06ed427fe8a72fe0cc14f574337ca53e0e
--- /dev/null
+++ b/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/benchmarks/Rastrigin.java
@@ -0,0 +1,45 @@
+package de.evoal.generator.main.benchmarks;
+
+import de.evoal.core.api.properties.Properties;
+import de.evoal.core.api.properties.PropertySpecification;
+import de.evoal.generator.api.AbstractGeneratorFunction;
+import de.evoal.generator.api.GeneratorFunction;
+import de.evoal.languages.model.el.DoubleLiteral;
+import de.evoal.languages.model.generator.Step;
+import de.evoal.languages.model.instance.LiteralValue;
+
+import javax.enterprise.context.Dependent;
+import javax.inject.Named;
+
+@Dependent
+@Named("rastrigin")
+public class Rastrigin extends AbstractGeneratorFunction {
+    private double a;
+
+    @Override
+    public Properties apply(final Properties in) {
+        final Properties result = mergeAndCopy(in);
+
+        final double n = readSpecification.size();
+        double value = a * n;
+
+        for(final PropertySpecification ps : readSpecification.getProperties()) {
+            double read_i = in.get(ps);
+
+            value += (Math.pow(read_i, 2.0) - a * Math.cos(2 * Math.PI * read_i));
+        }
+
+        result.put(writeSpecification.getProperties().get(0), value);
+
+        return result;
+    }
+
+    @Override
+    public GeneratorFunction init(final Step configuration) {
+        super.init(configuration);
+
+        a = ((DoubleLiteral)((LiteralValue)configuration.getInstance().findAttribute("a").getValue()).getLiteral()).getValue();
+
+        return this;
+    }
+}
diff --git a/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/benchmarks/Rosenbrock.java b/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/benchmarks/Rosenbrock.java
new file mode 100644
index 0000000000000000000000000000000000000000..9e1b291fd2087d1a9ef485449537986b0ff2f0a9
--- /dev/null
+++ b/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/benchmarks/Rosenbrock.java
@@ -0,0 +1,34 @@
+package de.evoal.generator.main.benchmarks;
+
+import de.evoal.core.api.properties.Properties;
+import de.evoal.core.api.properties.PropertySpecification;
+import de.evoal.generator.api.AbstractGeneratorFunction;
+
+import javax.enterprise.context.Dependent;
+import javax.inject.Named;
+
+@Dependent
+@Named("rosenbrock")
+public class Rosenbrock extends AbstractGeneratorFunction {
+    @Override
+    public Properties apply(final Properties in) {
+        final Properties result = mergeAndCopy(in);
+
+        final double n = readSpecification.size();
+        double value = 0.0;
+
+        for(int i = 0; i < readSpecification.getProperties().size() - 1; ++i) {
+            final PropertySpecification ps_i = readSpecification.getProperties().get(i);
+            final PropertySpecification ps_n = readSpecification.getProperties().get(i+1);
+
+            double read_i = in.get(ps_i);
+            double read_n = in.get(ps_n);
+
+            value += 100 * Math.pow((Math.pow(read_i,  2.0) - read_n), 2.0) + Math.pow(1 - read_i, 2.0);
+        }
+
+        result.put(writeSpecification.getProperties().get(0), value);
+
+        return result;
+    }
+}
diff --git a/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/benchmarks/WeightedSphere.java b/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/benchmarks/WeightedSphere.java
new file mode 100644
index 0000000000000000000000000000000000000000..f59a161383b96902909a6adc4f114984ca9be41f
--- /dev/null
+++ b/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/benchmarks/WeightedSphere.java
@@ -0,0 +1,31 @@
+package de.evoal.generator.main.benchmarks;
+
+import de.evoal.core.api.properties.Properties;
+import de.evoal.core.api.properties.PropertySpecification;
+import de.evoal.generator.api.AbstractGeneratorFunction;
+
+import javax.enterprise.context.Dependent;
+import javax.inject.Named;
+
+@Dependent
+@Named("weighted-sphere")
+public class WeightedSphere extends AbstractGeneratorFunction {
+    @Override
+    public Properties apply(final Properties in) {
+        final Properties result = mergeAndCopy(in);
+
+        final double n = readSpecification.size();
+        double value = 0.0;
+        int counter = 0;
+
+        for(final PropertySpecification ps : readSpecification.getProperties()) {
+            double read_i = in.get(ps);
+
+            value += Math.pow(read_i, 2.0)  * Math.pow(counter++, 2.0);
+        }
+
+        result.put(writeSpecification.getProperties().get(0), value);
+
+        return result;
+    }
+}
diff --git a/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/cdi/GeneratorConfigurationProducer.java b/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/cdi/GeneratorConfigurationProducer.java
new file mode 100644
index 0000000000000000000000000000000000000000..db9f87b33fbcd8b753da26aa53d780b35c3e6ba5
--- /dev/null
+++ b/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/cdi/GeneratorConfigurationProducer.java
@@ -0,0 +1,127 @@
+package de.evoal.generator.main.cdi;
+
+import com.google.inject.Injector;
+
+import de.evoal.core.api.board.Blackboard;
+import de.evoal.core.api.board.BlackboardEntry;
+import de.evoal.core.api.cdi.BlackboardValue;
+import de.evoal.generator.api.GeneratorBlackboardEntry;
+import de.evoal.languages.model.ddl.dsl.DataDescriptionLanguageStandaloneSetup;
+import de.evoal.languages.model.ddl.impl.DdlPackageImpl;
+import de.evoal.languages.model.dl.dsl.DefinitionLanguageStandaloneSetup;
+import de.evoal.languages.model.dl.impl.DlPackageImpl;
+import de.evoal.languages.model.el.dsl.ExpressionLanguageStandaloneSetup;
+import de.evoal.languages.model.el.impl.ELPackageImpl;
+import de.evoal.languages.model.generator.dsl.GeneratorDSLStandaloneSetup;
+import de.evoal.languages.model.generator.Configuration;
+import de.evoal.languages.model.generator.impl.GeneratorPackageImpl;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.event.Observes;
+import javax.enterprise.inject.Produces;
+import javax.enterprise.inject.spi.InjectionPoint;
+import java.io.File;
+import java.util.Optional;
+
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.xtext.resource.XtextResource;
+import org.eclipse.xtext.resource.XtextResourceSet;
+
+@ApplicationScoped
+@Slf4j
+public class GeneratorConfigurationProducer {
+    public void loadModel(final @Observes BlackboardEntry value, final Blackboard board) {
+        if(!GeneratorBlackboardEntry.GENERATOR_CONFIGURATION_FILE.equals(value.getLabel())) {
+            return;
+        }
+
+        final String configurationFile = board.get(value.getLabel());
+
+        log.info("Using generator configuration from '{}'.", configurationFile);
+
+        initializeEMF();
+
+        final File file = new File(configurationFile);
+
+        if(!file.isFile()) {
+            log.info("Configured generator configuration is a folder.");
+            throw  new IllegalArgumentException("Please specify a generator file.");
+        }
+
+        if(!file.canRead()) {
+            log.info("Configured generator configuration cannot be read.");
+            throw  new IllegalArgumentException("Please specify a readable genrator file.");
+        }
+
+        final Configuration configuration = read(file).get();
+        board.bind(GeneratorBlackboardEntry.GENERATOR_CONFIGURATION, configuration);
+    }
+
+    /**
+     * Initialize the model packages and perform the parser setup.
+     */
+    private void initializeEMF() {
+        DdlPackageImpl.init();
+        ELPackageImpl.init();
+        DlPackageImpl.init();
+        GeneratorPackageImpl.init();
+
+        DataDescriptionLanguageStandaloneSetup.doSetup();
+        ExpressionLanguageStandaloneSetup.doSetup();
+        DefinitionLanguageStandaloneSetup.doSetup();
+        GeneratorDSLStandaloneSetup.doSetup();
+    }
+
+    /**
+     * Parses the given generator file and returns the corresponding model.
+     *
+     * @param modelFile The model file to read.
+     * @return The data validation model or an empty optional.
+     */
+    private Optional<Configuration> read(final File modelFile) {
+        log.info("Reading model file {}.", modelFile);
+
+        final Injector injector = new GeneratorDSLStandaloneSetup().createInjectorAndDoEMFRegistration();
+        final XtextResourceSet resourceSet = injector.getInstance(XtextResourceSet.class);
+        resourceSet.addLoadOption(XtextResource.OPTION_RESOLVE_ALL, Boolean.TRUE);
+        resourceSet.addLoadOption(XtextResource.OPTION_ENCODING, "UTF-8");
+
+        try {
+            final URI modelURI = URI.createFileURI(modelFile.getAbsolutePath());
+            final Resource resource = resourceSet.getResource(modelURI, true);
+            resource.load(resourceSet.getLoadOptions());
+
+            if(!resource.getErrors().isEmpty()) {
+                for(Resource.Diagnostic diagnostic : resource.getErrors()) {
+                    log.error("Error while processing rule '{}': {}", modelFile, diagnostic);
+                }
+            }
+
+            if(!resource.getWarnings().isEmpty()) {
+                for(Resource.Diagnostic diagnostic : resource.getWarnings()) {
+                    log.error("Warning while processing rule '{}': {}", modelFile, diagnostic);
+                }
+            }
+
+            return Optional.of((Configuration) resource.getContents().get(0));
+        } catch (final Exception e) {
+            log.error("Unable to to generator file '{}'.", modelFile, e);
+            return Optional.empty();
+        }
+    }
+
+    @Produces
+    @BlackboardValue(GeneratorBlackboardEntry.GENERATOR_CONFIGURATION)
+    public Configuration injectIntegerValue(final InjectionPoint ip, final Blackboard board) {
+        final BlackboardValue value = ip.getAnnotated().getAnnotation(BlackboardValue.class);
+        final Object result = board.get(value.value());
+
+        if(result instanceof Configuration) {
+            return (Configuration)result;
+        }
+
+        throw new IllegalArgumentException("Unable to handle type " + result.getClass());
+    }
+}
diff --git a/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/functions/ConstantFunction.java b/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/functions/ConstantFunction.java
new file mode 100644
index 0000000000000000000000000000000000000000..a6d0834c852131370a8ee968614adb821e136a0b
--- /dev/null
+++ b/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/functions/ConstantFunction.java
@@ -0,0 +1,45 @@
+package de.evoal.generator.main.functions;
+
+import de.evoal.core.api.properties.Properties;
+import de.evoal.generator.api.AbstractGeneratorFunction;
+import de.evoal.generator.api.GeneratorFunction;
+import de.evoal.languages.model.el.DoubleLiteral;
+import de.evoal.languages.model.generator.Step;
+import de.evoal.languages.model.instance.Array;
+import de.evoal.languages.model.instance.LiteralValue;
+
+import javax.enterprise.context.Dependent;
+import javax.inject.Named;
+
+@Dependent
+@Named("constants")
+public class ConstantFunction extends AbstractGeneratorFunction {
+	private double [] constants = {};
+
+	public Properties apply(final Properties in) {
+		final Properties result = mergeAndCopy(in);
+
+		for(int i = 0; i < constants.length; ++i) {
+			result.put(writeSpecification.getProperties().get(i), constants[i]);
+		}
+
+		return result;
+	}
+
+	@Override
+	public GeneratorFunction init(final Step configuration) {
+		super.init(configuration);
+
+		final Array constantsArray = (Array)configuration.getInstance().findAttribute("constants").getValue();
+
+		constants = constantsArray.getValues()
+								  .stream()
+								  .map(LiteralValue.class::cast)
+								  .map(LiteralValue::getLiteral)
+								  .map(DoubleLiteral.class::cast)
+								  .mapToDouble(DoubleLiteral::getValue)
+								  .toArray();
+
+		return this;
+	}
+}
diff --git a/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/functions/NormalNoiseFunction.java b/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/functions/NormalNoiseFunction.java
new file mode 100644
index 0000000000000000000000000000000000000000..f6e176c61518ed49fddff8f2e32f6ea2643612b9
--- /dev/null
+++ b/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/functions/NormalNoiseFunction.java
@@ -0,0 +1,53 @@
+package de.evoal.generator.main.functions;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import de.evoal.core.api.properties.Properties;
+import de.evoal.core.api.properties.PropertySpecification;
+import de.evoal.generator.api.AbstractGeneratorFunction;
+import de.evoal.generator.api.GeneratorFunction;
+import de.evoal.generator.main.utils.ELHelper;
+import de.evoal.languages.model.generator.Step;
+import org.apache.commons.math3.distribution.NormalDistribution;
+import org.apache.commons.math3.distribution.RealDistribution;
+
+import javax.enterprise.context.Dependent;
+import javax.inject.Named;
+
+@Dependent
+@Named("normally-distributed-noise")
+public class NormalNoiseFunction extends AbstractGeneratorFunction {
+
+	/**
+	 * The different distributions to apply.
+	 */
+	private List<RealDistribution> distributions = new ArrayList<>();
+
+	public GeneratorFunction init(final Step configuration) {
+		super.init(configuration);
+
+		ELHelper.readDistributions(configuration.getInstance(), "distributions")
+				.stream()
+				.map(d -> new NormalDistribution(d.μ(), d.σ()))
+				.forEach(distributions::add);
+
+		return this;
+	}
+
+	@Override
+	public Properties apply(final Properties in) {
+		final Properties result = mergeAndCopy(in);
+		final int dimension = writeSpecification.size();
+
+		for(int i = 0; i < dimension; ++i) {
+			final PropertySpecification ps = writeSpecification.getProperties().get(i);
+
+			double value = result.get(ps) + distributions.get(i).sample();
+
+			result.put(ps, value);
+		}
+
+		return result;
+	}
+}
diff --git a/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/generators/GeneratorFactory.java b/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/generators/GeneratorFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..88af80bd36735ef6ca21252dd38c31ab82a4b77f
--- /dev/null
+++ b/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/generators/GeneratorFactory.java
@@ -0,0 +1,17 @@
+package de.evoal.generator.main.generators;
+
+import de.evoal.core.api.cdi.BeanFactory;
+import de.evoal.generator.api.GeneratorFunction;
+import de.evoal.languages.model.generator.Step;
+
+import javax.enterprise.context.ApplicationScoped;
+
+@ApplicationScoped
+public class GeneratorFactory {
+    public GeneratorFunction create(final Step configuration) {
+        final String functionName = configuration.getInstance().getName().getName();
+
+        return BeanFactory.create(functionName, GeneratorFunction.class)
+                          .init(configuration);
+    }
+}
diff --git a/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/generators/MultivariateNormalDistribution.java b/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/generators/MultivariateNormalDistribution.java
new file mode 100644
index 0000000000000000000000000000000000000000..a32c2e66264e5b4f40788b581017e70d07073839
--- /dev/null
+++ b/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/generators/MultivariateNormalDistribution.java
@@ -0,0 +1,56 @@
+package de.evoal.generator.main.generators;
+
+import de.evoal.generator.api.GeneratorFunction;
+import de.evoal.languages.model.el.DoubleLiteral;
+import de.evoal.languages.model.generator.Step;
+import de.evoal.languages.model.instance.*;
+import de.evoal.languages.model.instance.impl.InstanceImpl;
+import lombok.NonNull;
+
+import javax.enterprise.context.Dependent;
+import javax.inject.Named;
+
+@Named("multivariate-normal-distribution")
+@Dependent
+public class MultivariateNormalDistribution extends MultivariateRealDistributionBase {
+
+    @Override
+    public GeneratorFunction init(final Step configuration) {
+        super.init(configuration);
+
+        double [] means = readMeans(configuration.getInstance());
+        double [][] covariance = readCovariance(configuration.getInstance());
+
+        setDistribution(new org.apache.commons.math3.distribution.MultivariateNormalDistribution(means, covariance));
+
+        return this;
+    }
+
+    private double[][] readCovariance(final @NonNull Instance instance) {
+        final Array array = (Array) instance.findAttribute("covariances")
+                                            .getValue();
+
+        return array.getValues()
+                .stream()
+                .map(Array.class::cast)
+                .map(this::readArray)
+                .toArray(i -> new double[i][]);
+    }
+
+    private double []readArray(final @NonNull Array value) {
+        return value.getValues()
+                    .stream()
+                    .mapToDouble(this::readDouble)
+                    .toArray();
+    }
+
+    private double readDouble(final Value value) {
+        return ((DoubleLiteral)((LiteralValue)value).getLiteral()).getValue();
+    }
+
+    private double[] readMeans(final @NonNull Instance instance) {
+        final Attribute meansAttribute = instance.findAttribute("means");
+
+        return readArray((Array)meansAttribute.getValue());
+    }
+}
diff --git a/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/generators/MultivariateRealDistributionBase.java b/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/generators/MultivariateRealDistributionBase.java
new file mode 100644
index 0000000000000000000000000000000000000000..43cc9847e4e51f24dcd5927d9caa76fc324548d8
--- /dev/null
+++ b/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/generators/MultivariateRealDistributionBase.java
@@ -0,0 +1,30 @@
+package de.evoal.generator.main.generators;
+
+import de.evoal.core.api.properties.Properties;
+import de.evoal.core.api.properties.PropertySpecification;
+import de.evoal.generator.api.AbstractGeneratorFunction;
+import lombok.AccessLevel;
+import lombok.Setter;
+import org.apache.commons.math3.distribution.MultivariateRealDistribution;
+
+import java.util.List;
+
+public abstract class MultivariateRealDistributionBase extends AbstractGeneratorFunction {
+    @Setter(AccessLevel.PROTECTED)
+    private MultivariateRealDistribution distribution;
+
+    @Override
+    public Properties apply(final Properties in) {
+        final Properties result = mergeAndCopy(in);
+        final List<PropertySpecification> specifications = writeSpecification.getProperties();
+        final int dimension = specifications.size();
+
+        final double [] values = distribution.sample();
+
+        for(int i = 0; i < dimension; ++i) {
+            result.put(specifications.get(i), values[i]);
+        }
+
+        return result;
+    }
+}
diff --git a/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/generators/MultivariateUniformDistribution.java b/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/generators/MultivariateUniformDistribution.java
new file mode 100644
index 0000000000000000000000000000000000000000..db6d82ad5bc4f157c96f054a1dec8f8ff11310cb
--- /dev/null
+++ b/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/generators/MultivariateUniformDistribution.java
@@ -0,0 +1,50 @@
+package de.evoal.generator.main.generators;
+
+import de.evoal.generator.api.GeneratorFunction;
+import de.evoal.languages.model.el.DoubleLiteral;
+import de.evoal.languages.model.generator.Step;
+import de.evoal.languages.model.instance.Array;
+import de.evoal.languages.model.instance.Instance;
+import de.evoal.languages.model.instance.LiteralValue;
+
+import javax.inject.Named;
+import java.util.List;
+import java.util.stream.Collectors;
+
+//@Named("multivariate-uniform-distribution")
+public class MultivariateUniformDistribution extends MultivariateRealDistributionBase {
+    private record Range(double lowerBound, double upperBound) {
+    }
+
+    @Override
+    public GeneratorFunction init(final Step configuration) {
+        super.init(configuration);
+
+        final List<Range> ranges = readRanges(configuration);
+
+        double [] lhs = ranges.stream().mapToDouble(Range::lowerBound).toArray();
+        double [] rhs = ranges.stream().mapToDouble(Range::upperBound).toArray();
+
+       // setDistribution(new org.apache.commons.math3.distribution.MultivariateRealDistribution(lhs, rhs));
+
+        return this;
+    }
+
+    private List<Range> readRanges(final Step configuration) {
+        final Array ranges = (Array)configuration.getInstance().findAttribute("ranges");
+        return ranges.getValues()
+                     .stream()
+                     .map(Instance.class::cast)
+                     .map(this::readRange)
+                     .collect(Collectors.toUnmodifiableList());
+    }
+
+    public Range readRange(final Instance value) {
+        return new Range(readDouble(value, "lower-bound"), readDouble(value, "upper-bound"));
+    }
+
+    private double readDouble(final Instance value, final String name) {
+        return ((DoubleLiteral)((LiteralValue)value.findAttribute(name)).getLiteral()).getValue();
+    }
+
+}
diff --git a/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/generators/NormalDistribution.java b/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/generators/NormalDistribution.java
new file mode 100644
index 0000000000000000000000000000000000000000..cebb3812d840ab9bf8266ff9da2d1449b9857be4
--- /dev/null
+++ b/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/generators/NormalDistribution.java
@@ -0,0 +1,28 @@
+package de.evoal.generator.main.generators;
+
+import de.evoal.generator.api.GeneratorFunction;
+import de.evoal.languages.model.el.DoubleLiteral;
+import de.evoal.languages.model.generator.Step;
+import de.evoal.languages.model.instance.LiteralValue;
+
+import javax.enterprise.context.Dependent;
+import javax.inject.Named;
+
+@Dependent
+@Named("normal-distribution")
+public class NormalDistribution extends RealDistributionBase {
+
+    @Override
+    public GeneratorFunction init(final Step configuration) {
+        super.init(configuration);
+
+        double μ = ((DoubleLiteral)((LiteralValue)configuration.getInstance().findAttribute("μ").getValue()).getLiteral()).getValue();
+        double σ = ((DoubleLiteral)((LiteralValue)configuration.getInstance().findAttribute("σ").getValue()).getLiteral()).getValue();
+
+        for(int i = 0; i < writeSpecification.getProperties().size(); ++i) {
+            getDistributions().add(new org.apache.commons.math3.distribution.NormalDistribution(μ, σ));
+        }
+
+        return this;
+    }
+}
diff --git a/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/generators/RealDistributionBase.java b/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/generators/RealDistributionBase.java
new file mode 100644
index 0000000000000000000000000000000000000000..8ca008a339d1814d973c365350667515e8a900d0
--- /dev/null
+++ b/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/generators/RealDistributionBase.java
@@ -0,0 +1,29 @@
+package de.evoal.generator.main.generators;
+
+import de.evoal.core.api.properties.Properties;
+import de.evoal.core.api.properties.PropertySpecification;
+import de.evoal.generator.api.AbstractGeneratorFunction;
+import lombok.AccessLevel;
+import lombok.Getter;
+import org.apache.commons.math3.distribution.RealDistribution;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public abstract class RealDistributionBase extends AbstractGeneratorFunction {
+    @Getter(AccessLevel.PROTECTED)
+    private List<RealDistribution> distributions = new ArrayList<>();
+
+    @Override
+    public Properties apply(final Properties in) {
+        final Properties result = mergeAndCopy(in);
+        final List<PropertySpecification> specifications = writeSpecification.getProperties();
+        final int dimension = specifications.size();
+
+        for(int i = 0; i < dimension; ++i) {
+            result.put(specifications.get(i), distributions.get(i).sample());
+        }
+
+        return result;
+    }
+}
diff --git a/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/generators/UniformDistribution.java b/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/generators/UniformDistribution.java
new file mode 100644
index 0000000000000000000000000000000000000000..fa01b96fb9c6fa073f151a76ca28e723eb710b85
--- /dev/null
+++ b/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/generators/UniformDistribution.java
@@ -0,0 +1,28 @@
+package de.evoal.generator.main.generators;
+
+import de.evoal.generator.api.GeneratorFunction;
+import de.evoal.languages.model.el.DoubleLiteral;
+import de.evoal.languages.model.generator.Step;
+import de.evoal.languages.model.instance.LiteralValue;
+import org.apache.commons.math3.distribution.UniformRealDistribution;
+
+import javax.enterprise.context.Dependent;
+import javax.inject.Named;
+
+@Dependent
+@Named("uniform-distribution")
+public class UniformDistribution extends RealDistributionBase {
+
+	public GeneratorFunction init(final Step configuration) {
+		super.init(configuration);
+
+		Object ranges = ((DoubleLiteral)((LiteralValue)configuration.getInstance().findAttribute("μ").getValue()).getLiteral()).getValue();
+		if(true) throw new IllegalStateException("Not yet implemented.");
+
+		for(int i = 0; i < writeSpecification.getProperties().size(); ++i) {
+			getDistributions().add(new UniformRealDistribution(-1.0, 1.0));
+		}
+
+		return this;
+	}
+}
diff --git a/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/internal/Pipeline.java b/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/internal/Pipeline.java
new file mode 100644
index 0000000000000000000000000000000000000000..6dbdae8f2f5207f5eaa9159bbeb5eb0bc865158b
--- /dev/null
+++ b/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/internal/Pipeline.java
@@ -0,0 +1,19 @@
+package de.evoal.generator.main.internal;
+
+import de.evoal.generator.api.GeneratorFunction;
+import lombok.Getter;
+
+import java.util.List;
+
+public class Pipeline {
+    @Getter
+    private final String name;
+
+    @Getter
+    private final List<GeneratorFunction> steps;
+
+    public Pipeline(final String name, final List<GeneratorFunction> steps) {
+        this.name = name;
+        this.steps = steps;
+    }
+}
diff --git a/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/internal/StatementExecutor.java b/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/internal/StatementExecutor.java
new file mode 100644
index 0000000000000000000000000000000000000000..47ed93c6e35d76dcd6b36da213670c06883a4c87
--- /dev/null
+++ b/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/internal/StatementExecutor.java
@@ -0,0 +1,168 @@
+package de.evoal.generator.main.internal;
+
+import de.evoal.core.api.properties.Properties;
+import de.evoal.core.api.properties.PropertiesSpecification;
+import de.evoal.core.api.properties.io.PropertiesWriter;
+import de.evoal.generator.api.GeneratorFunction;
+import de.evoal.languages.model.generator.*;
+import de.evoal.languages.model.generator.util.GeneratorSwitch;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.File;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+@Slf4j
+public class StatementExecutor extends GeneratorSwitch<Object> {
+
+    /**
+     * Variable pattern
+     */
+    private final Pattern varPattern = Pattern.compile("\\$\\{[^}]*}");
+
+    private final Map<String, Pipeline> pipelineTable;
+
+    private SymbolTable symbols;
+
+    public StatementExecutor(final Map<String, Pipeline> pipelineTable) {
+        this.pipelineTable = pipelineTable;
+
+        this.symbols = new SymbolTable(null, (Map<String, Object>)(Map<String, ?>)pipelineTable);
+    }
+
+    public void execute(final List<Statement> statements) {
+        statements.forEach(this::doSwitch);
+    }
+
+    @Override
+    public Object caseForStatement(final ForStatement forLoop) {
+        final String varName = forLoop.getName();
+
+        final SymbolTable currentSymbols = this.symbols;
+
+        final Stream<?> loopElements = (Stream<?>)doSwitch(forLoop.getRange());
+        loopElements.forEach(e -> {
+            this.symbols = new SymbolTable(currentSymbols);
+            this.symbols.bind(varName, e);
+
+            execute(forLoop.getStatements());
+
+            this.symbols = currentSymbols;
+        });
+
+        return null;
+    }
+
+    @Override
+    public Object caseCounterRange(final CounterRange range) {
+        final boolean reverse = range.getStart() > range.getEnd();
+        final int min = Math.min(range.getStart(), range.getEnd());
+        final int max = Math.max(range.getStart(), range.getEnd());
+        final int count = max - min;
+
+        Stream<Integer> values = IntStream.rangeClosed(0, count)
+                                          .boxed();
+
+        if(reverse) {
+            values = values.map(i -> max - i);
+        } else {
+            values = values.map(i -> min + i);
+        }
+
+        return values;
+    }
+
+    @Override
+    public Object casePipelineArray(final PipelineArray range) {
+        if(range.getReferences().isEmpty()) {
+            return new ArrayList<>(pipelineTable.values()).stream();
+        }
+
+        return range.getReferences()
+                    .stream()
+                    .map(this::doSwitch)
+                    .filter(Objects::nonNull);
+    }
+
+    @Override
+    public Object casePipelineDefinitionReference(final PipelineDefinitionReference reference) {
+        final String name = reference.getPipeline().getName();
+
+        return symbols.get(name);
+    }
+
+    @Override
+    public Object caseVariableReference(final VariableReference reference) {
+        final String name = reference.getLoop().getName();
+
+        return symbols.get(name);
+    }
+
+    @Override
+    public Object caseApplyStatement(final ApplyStatement stmt) {
+        final int count = stmt.getCount();
+        final List<Pipeline> pipelines =
+                stmt.getPipelines()
+                     .stream()
+                     .map(this::doSwitch)
+                     .filter(Objects::nonNull)
+                     .filter(Pipeline.class::isInstance)
+                     .map(Pipeline.class::cast)
+                     .collect(Collectors.toUnmodifiableList());
+
+        String filename = stmt.getFile();
+
+        final Matcher matcher = varPattern.matcher(filename);
+
+        final Set<String> vars = new HashSet<>();
+        while(matcher.find()) {
+            vars.add(filename.substring(matcher.start() + 2, matcher.end() - 1));
+        }
+
+        for(final String var : vars) {
+            String replacement = null;
+
+            Object value = symbols.get(var);
+            if(value instanceof Integer) {
+                replacement = value.toString();
+            } else if(value instanceof Pipeline) {
+                replacement = ((Pipeline)value).getName();
+            }
+
+            if(replacement == null) {
+                log.warn("Unable to replace ${{}}", var);
+                continue;
+            }
+
+            filename = filename.replace("${" + var + "}", replacement);
+        }
+
+        log.info("Writing {}", filename);
+
+        final PropertiesSpecification specification = PropertiesSpecification.builder().build();
+        final Properties emptyProperties = new Properties(specification);
+
+        Stream<Properties> stream = Stream.generate(() -> emptyProperties);
+
+        for(final Pipeline pipe : pipelines) {
+            for(final GeneratorFunction function : pipe.getSteps()) {
+                stream = stream.map(function::apply);
+            }
+        }
+
+        new File(filename).getParentFile().mkdirs();
+
+        try(final PropertiesWriter writer = new PropertiesWriter(new File(filename))) {
+            stream.limit(count)
+                  .forEach(writer::addProperties);
+        } catch (final Exception e) {
+            log.error("Failed to write properties to file '{}'.", filename);
+        }
+
+        return null;
+    }
+}
diff --git a/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/internal/SymbolTable.java b/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/internal/SymbolTable.java
new file mode 100644
index 0000000000000000000000000000000000000000..3570303e78729ba0448f2b5518f500f631b3e405
--- /dev/null
+++ b/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/internal/SymbolTable.java
@@ -0,0 +1,60 @@
+package de.evoal.generator.main.internal;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class SymbolTable {
+    /**
+     * If we have an outer scope.
+     */
+    private final SymbolTable parent;
+
+    /**
+     * The symbols
+     */
+    private final Map<String, Object> symbols = new HashMap<>();
+
+    public SymbolTable(final SymbolTable parent) {
+        this.parent = parent;
+    }
+
+    public SymbolTable(final SymbolTable parent, final Map<String, Object> symbols) {
+        this.parent = parent;
+        this.symbols.putAll(symbols);
+    }
+
+    public void bind(final String name, final Object obj) {
+        symbols.put(name, obj);
+    }
+
+    public Object get(final String name) {
+        if(symbols.containsKey(name)) {
+            return symbols.get(name);
+        }
+
+        if(parent != null) {
+            return parent.get(name);
+        }
+
+        return null;
+    }
+
+    /**
+     * @return All visible (non-hidden variable bindings.
+     */
+    public Map<String, Object> getVariables() {
+        Map<String, Object> variables = new HashMap<>();
+        
+        collectVariables(variables);
+
+        return variables;
+    }
+
+    private void collectVariables(final Map<String, Object> entries) {
+        if(parent != null) {
+            parent.collectVariables(entries);
+        }
+
+        entries.putAll(symbols);
+    }
+}
diff --git a/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/utils/ELHelper.java b/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/utils/ELHelper.java
new file mode 100644
index 0000000000000000000000000000000000000000..17aac76bcef8eb9e04fa0ffd5b31b1f54598b3e8
--- /dev/null
+++ b/src/core/de.evoal.generator.main/src/main/java/de/evoal/generator/main/utils/ELHelper.java
@@ -0,0 +1,36 @@
+package de.evoal.generator.main.utils;
+
+import de.evoal.languages.model.el.DoubleLiteral;
+import de.evoal.languages.model.instance.Array;
+import de.evoal.languages.model.instance.Instance;
+import de.evoal.languages.model.instance.LiteralValue;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+public final class ELHelper {
+    private ELHelper() {}
+
+    public record Distribution(double μ, double σ) {}
+
+    public static double readDouble(final Instance instance, final String name) {
+        return ((DoubleLiteral)((LiteralValue)instance.findAttribute(name).getValue()).getLiteral()).getValue();
+    }
+
+    public static List<Distribution> readDistributions(final Instance instance, final String name) {
+        final Array array = (Array)instance.findAttribute(name).getValue();
+
+        return array.getValues()
+                .stream()
+                .map(Instance.class::cast)
+                .map(ELHelper::readDistribution)
+                .collect(Collectors.toUnmodifiableList());
+    }
+
+    private static Distribution readDistribution(final Instance instance) {
+        final double μ = ELHelper.readDouble(instance, "μ");
+        final double σ = ELHelper.readDouble(instance, "σ");
+
+        return new Distribution(μ, σ);
+    }
+}
diff --git a/src/core/de.evoal.generator.main/src/main/java/module-info.java b/src/core/de.evoal.generator.main/src/main/java/module-info.java
new file mode 100644
index 0000000000000000000000000000000000000000..0f7d69ea9124a12777f4e3a5142566ed5bfe4548
--- /dev/null
+++ b/src/core/de.evoal.generator.main/src/main/java/module-info.java
@@ -0,0 +1,35 @@
+module de.evoal.generator.main {
+    requires java.base;
+
+    requires lombok;
+
+    requires org.slf4j;
+
+    requires jakarta.inject.api;
+    requires jakarta.enterprise.cdi.api;
+
+    requires org.eclipse.emf.common;
+    requires org.eclipse.emf.ecore;
+    requires org.eclipse.xtext;
+
+    requires de.evoal.languages.model.ddl;
+    requires de.evoal.languages.model.dl;
+    requires de.evoal.languages.model.el;
+    requires de.evoal.languages.model.generator;
+    requires de.evoal.languages.model.instance;
+
+    requires de.evoal.languages.model.ddl.dsl;
+    requires de.evoal.languages.model.dl.dsl;
+    requires de.evoal.languages.model.el.dsl;
+    requires de.evoal.languages.model.generator.dsl;
+
+    requires de.evoal.core.api;
+    requires guice;
+    requires commons.math3;
+
+    opens de.evoal.generator.main;
+    opens de.evoal.generator.main.benchmarks;
+    opens de.evoal.generator.main.cdi;
+    opens de.evoal.generator.main.functions;
+    opens de.evoal.generator.main.generators;
+}
diff --git a/src/core/de.evoal.generator.main/src/main/resources/META-INF/MANIFEST.MF b/src/core/de.evoal.generator.main/src/main/resources/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000000000000000000000000000000000..9d885be534121a9f146924f4832955dfe2ee2d4b
--- /dev/null
+++ b/src/core/de.evoal.generator.main/src/main/resources/META-INF/MANIFEST.MF
@@ -0,0 +1 @@
+Manifest-Version: 1.0
diff --git a/src/core/de.evoal.generator.main/src/main/resources/META-INF/beans.xml b/src/core/de.evoal.generator.main/src/main/resources/META-INF/beans.xml
new file mode 100644
index 0000000000000000000000000000000000000000..848dca3b29cc3f1f9879d2c86d586612e5d8b3e7
--- /dev/null
+++ b/src/core/de.evoal.generator.main/src/main/resources/META-INF/beans.xml
@@ -0,0 +1,6 @@
+<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd"
+       bean-discovery-mode="annotated"
+       version="2.0">
+</beans>
\ No newline at end of file
diff --git a/src/core/de.evoal.surrogate.api/pom.xml b/src/core/de.evoal.surrogate.api/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..42110b7233ce2b0a9c42b70cfe59c5521f6ed77e
--- /dev/null
+++ b/src/core/de.evoal.surrogate.api/pom.xml
@@ -0,0 +1,137 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+
+	<parent>
+		<groupId>de.evoal.core</groupId>
+		<artifactId>releng.parent</artifactId>
+		<version>0.9.0-SNAPSHOT</version>
+
+		<relativePath>../de.evoal.core.releng.parent</relativePath>
+	</parent>
+
+	<artifactId>surrogate.api</artifactId>
+	<name>EvoAl - Surrogate - API</name>
+
+	<dependencies>
+		<dependency>
+			<groupId>${project.groupId}</groupId>
+			<artifactId>core.api</artifactId>
+			<scope>provided</scope>
+		</dependency>
+
+		<!-- DSL dependencies -->
+		<!-- Xtext -->
+		<dependency>
+			<groupId>org.eclipse.emf</groupId>
+			<artifactId>org.eclipse.emf.ecore</artifactId>
+		</dependency>
+
+		<dependency>
+			<groupId>org.eclipse.emf</groupId>
+			<artifactId>org.eclipse.emf.common</artifactId>
+		</dependency>
+
+		<dependency>
+			<groupId>org.eclipse.xtext</groupId>
+			<artifactId>org.eclipse.xtext</artifactId>
+		</dependency>
+
+		<dependency>
+			<groupId>de.evoal.languages</groupId>
+			<artifactId>de.evoal.languages.model.ddl</artifactId>
+			<version>${evoal.languages.version}</version>
+		</dependency>
+
+		<dependency>
+			<groupId>de.evoal.languages</groupId>
+			<artifactId>de.evoal.languages.model.dl</artifactId>
+			<version>${evoal.languages.version}</version>
+		</dependency>
+
+		<dependency>
+			<groupId>de.evoal.languages</groupId>
+			<artifactId>de.evoal.languages.model.el</artifactId>
+			<version>${evoal.languages.version}</version>
+		</dependency>
+
+		<dependency>
+			<groupId>de.evoal.languages</groupId>
+			<artifactId>de.evoal.languages.model.instance</artifactId>
+			<version>${evoal.languages.version}</version>
+		</dependency>
+
+		<dependency>
+			<groupId>de.evoal.languages</groupId>
+			<artifactId>de.evoal.languages.model.mll</artifactId>
+			<version>${evoal.languages.version}</version>
+		</dependency>
+
+		<dependency>
+			<groupId>de.evoal.languages</groupId>
+			<artifactId>de.evoal.languages.model.ddl.dsl</artifactId>
+			<version>${evoal.languages.version}</version>
+		</dependency>
+
+		<dependency>
+			<groupId>de.evoal.languages</groupId>
+			<artifactId>de.evoal.languages.model.dl.dsl</artifactId>
+			<version>${evoal.languages.version}</version>
+		</dependency>
+
+		<dependency>
+			<groupId>de.evoal.languages</groupId>
+			<artifactId>de.evoal.languages.model.el.dsl</artifactId>
+			<version>${evoal.languages.version}</version>
+		</dependency>
+
+		<dependency>
+			<groupId>de.evoal.languages</groupId>
+			<artifactId>de.evoal.languages.model.instance.dsl</artifactId>
+			<version>${evoal.languages.version}</version>
+		</dependency>
+
+		<dependency>
+			<groupId>de.evoal.languages</groupId>
+			<artifactId>de.evoal.languages.model.mll.dsl</artifactId>
+			<version>${evoal.languages.version}</version>
+		</dependency>
+	</dependencies>
+
+	<build>
+		<plugins>
+			<plugin>
+				<artifactId>maven-dependency-plugin</artifactId>
+				<executions>
+					<execution>
+						<phase>package</phase>
+						<goals>
+							<goal>copy-dependencies</goal>
+						</goals>
+						<configuration>
+							<outputDirectory>${project.build.directory}/${project.artifactId}-dependencies</outputDirectory>
+							<includeScope>runtime</includeScope>
+							<excludeScope>provided</excludeScope>
+							<excludeTransitive>true</excludeTransitive>
+						</configuration>
+					</execution>
+				</executions>
+			</plugin>
+
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-jar-plugin</artifactId>
+				<configuration>
+					<archive>
+						<manifestFile>src/main/resources/META-INF/MANIFEST.MF</manifestFile>
+						<manifest>
+							<addClasspath>true</addClasspath>
+							<classpathPrefix>${project.artifactId}-dependencies/</classpathPrefix>
+						</manifest>
+					</archive>
+				</configuration>
+			</plugin>
+		</plugins>
+	</build>
+</project>
diff --git a/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/api/SurrogateBlackboardEntry.java b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/api/SurrogateBlackboardEntry.java
new file mode 100644
index 0000000000000000000000000000000000000000..eddfbc21cca16a15cd8123e14b525e4047be088f
--- /dev/null
+++ b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/api/SurrogateBlackboardEntry.java
@@ -0,0 +1,15 @@
+package de.evoal.surrogate.api;
+
+public final class SurrogateBlackboardEntry {
+    /**
+     * Loaded generator configuration.
+     */
+    public static final String SURROGATE_CONFIGURATION = "surrogate:configuration";
+
+    /**
+     * Configuration file for the data generator.
+     */
+    public static final String SURROGATE_CONFIGURATION_FILE = "surrogate:configuration-file";
+
+    private SurrogateBlackboardEntry() {}
+}
diff --git a/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/api/SurrogateInformationCalculator.java b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/api/SurrogateInformationCalculator.java
new file mode 100644
index 0000000000000000000000000000000000000000..fdf52f48423995ea0388db5ebd5c7bda034fcf6c
--- /dev/null
+++ b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/api/SurrogateInformationCalculator.java
@@ -0,0 +1,28 @@
+package de.evoal.surrogate.api;
+
+import de.evoal.core.api.properties.stream.PropertiesStreamSupplier;
+import de.evoal.languages.model.mll.DefinedFunctionName;
+import de.evoal.surrogate.api.function.SurrogateFunction;
+import de.evoal.surrogate.api.configuration.SurrogateConfiguration;
+
+import java.util.List;
+
+/**
+ * Calculates information on the calculated surrogate, such as cross validation
+ *   values, goodness of fit, and so on.
+ */
+public interface SurrogateInformationCalculator {
+    /**
+     * Configures the calculator with the given parameters.
+     *
+     * @param function
+     * @param config
+     * @param parameters
+     */
+    public void configure(final SurrogateFunction function, final SurrogateConfiguration config, final List<Object> parameters, final PropertiesStreamSupplier trainingData);
+
+    /**
+     * Executes the calculation.
+     */
+    public void execute();
+}
diff --git a/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/api/configuration/FunctionCombinerConfiguration.java b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/api/configuration/FunctionCombinerConfiguration.java
new file mode 100644
index 0000000000000000000000000000000000000000..ca98326d8a4ff4a650cb15d308c5e5534a1f4005
--- /dev/null
+++ b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/api/configuration/FunctionCombinerConfiguration.java
@@ -0,0 +1,86 @@
+package de.evoal.surrogate.api.configuration;
+
+import de.evoal.languages.model.ddl.DataDescription;
+import de.evoal.languages.model.mll.PartialSurrogateFunctionDefinition;
+import de.evoal.languages.model.mll.SurrogateLayerDefinition;
+import de.evoal.surrogate.api.function.FunctionCombiner;
+import lombok.Data;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Configuration of a {@link FunctionCombiner}.
+ */
+@Data
+public class FunctionCombinerConfiguration {
+    /**
+     * List of functions within this mapping.
+     */
+    private List<PartialFunctionConfiguration> functions = new ArrayList<>();
+
+    /**
+     * Configuration of required properties
+     */
+    private final List<String> inputDimensions = new ArrayList<>();
+
+    /**
+     * Name of the mapping.
+     */
+    private String name;
+
+    /**
+     * Configuration of generated properties
+     */
+    private final List<String> outputDimensions = new ArrayList<>();
+
+    public static FunctionCombinerConfiguration from(final SurrogateLayerDefinition definition) {
+        final FunctionCombinerConfiguration configuration = new FunctionCombinerConfiguration();
+        configuration.setName(definition.getName());
+
+        final List<String> inputs =
+                definition.getFunctions()
+                          .stream()
+                          .map(PartialSurrogateFunctionDefinition::getInputs)
+                          .flatMap(l -> l.stream().map(DataDescription::getName))
+                          .distinct()
+                          .collect(Collectors.toList());
+
+        final List<String> outputs =
+                definition.getFunctions()
+                        .stream()
+                        .map(PartialSurrogateFunctionDefinition::getOutputs)
+                        .flatMap(l -> l.stream().map(DataDescription::getName))
+                        .distinct()
+                        .collect(Collectors.toList());
+
+        configuration.getInputDimensions().addAll(inputs);
+        configuration.getOutputDimensions().addAll(outputs);
+
+        definition.getFunctions()
+                .stream()
+                .map(PartialFunctionConfiguration::from)
+                .forEach(configuration.functions::add);
+
+        return configuration;
+    }
+
+    public static FunctionCombinerConfiguration from(final FunctionCombinerConfiguration config) {
+        final FunctionCombinerConfiguration configuration = new FunctionCombinerConfiguration();
+        configuration.setName(config.getName());
+
+        configuration.getInputDimensions()
+                     .addAll(config.getInputDimensions());
+        configuration.getOutputDimensions()
+                     .addAll(config.getOutputDimensions());
+
+        config.getFunctions()
+                .stream()
+                .map(PartialFunctionConfiguration::from)
+                .forEach(configuration.functions::add);
+
+        return configuration;
+    }
+}
+
diff --git a/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/api/configuration/Parameter.java b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/api/configuration/Parameter.java
new file mode 100644
index 0000000000000000000000000000000000000000..fb49269b268f858217f1f2907d2164f6b8723a0e
--- /dev/null
+++ b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/api/configuration/Parameter.java
@@ -0,0 +1,41 @@
+package de.evoal.surrogate.api.configuration;
+
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import de.evoal.languages.model.instance.LiteralValue;
+import de.evoal.languages.model.instance.Name;
+import de.evoal.surrogate.main.jackson.ReflectiveDeserializer;
+import de.evoal.surrogate.main.jackson.ReflectiveSerializer;
+import de.evoal.languages.model.instance.Attribute;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@AllArgsConstructor
+@Builder
+@Data
+@NoArgsConstructor
+public class Parameter {
+	private String name;
+
+	@JsonDeserialize(using = ReflectiveDeserializer.class)
+	@JsonSerialize(using = ReflectiveSerializer.class)
+	private Object value;
+
+	public static Parameter from(final Attribute attribute) {
+		final Parameter parameter = new Parameter();
+		parameter.setName(((Name)attribute.getName()).getName().getName());
+		parameter.setValue(((LiteralValue)attribute.getValue()).getLiteral().getValue());
+
+		return parameter;
+	}
+
+	public static Parameter from(final Parameter config) {
+		final Parameter parameter = new Parameter();
+		parameter.setName(config.getName());
+		parameter.setValue(config.getValue());
+
+		return parameter;
+	}
+}
diff --git a/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/api/configuration/PartialFunctionConfiguration.java b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/api/configuration/PartialFunctionConfiguration.java
new file mode 100644
index 0000000000000000000000000000000000000000..6ebc0c1e5f37a9d828fa34fdcfe6e690cea2a67d
--- /dev/null
+++ b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/api/configuration/PartialFunctionConfiguration.java
@@ -0,0 +1,105 @@
+package de.evoal.surrogate.api.configuration;
+
+import de.evoal.languages.model.ddl.DataDescription;
+import de.evoal.languages.model.mll.PartialSurrogateFunctionDefinition;
+import de.evoal.surrogate.api.function.PartialSurrogateFunction;
+import lombok.Data;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * Configuration of a {@link PartialSurrogateFunction}.
+ */
+@Data
+public class PartialFunctionConfiguration {
+	/**
+	 * List of required input dimensions
+	 */
+	private final List<String> inputDimensions = new ArrayList<>();
+
+	/**
+	 * Name of the function to use.
+
+	 */
+	private String name;
+
+	/**
+	 * List of calculated properties.
+	 */
+	private final List<String> outputDimensions = new ArrayList<>();
+
+	/**
+	 * Function-specific configuration parameters.
+	 */
+	private final List<Parameter> parameters = new ArrayList<>();
+
+	/**
+	 * The precalculated state of the function.
+	 */
+	private final List<Parameter> state = new ArrayList<>();
+
+	/**
+	 * Parameters of outputs
+	 */
+	private final Map<String, List<Parameter>> outputParameters = new HashMap<>();
+
+	public void addOutputParameter(final String name, final Parameter parameter) {
+		List<Parameter> content = outputParameters.get(name);
+
+		if(content == null) {
+			content = new ArrayList<>();
+			content.add(parameter);
+			outputParameters.put(name, content);
+		} else {
+			content.add(parameter);
+		}
+	}
+
+	public static PartialFunctionConfiguration from(final PartialSurrogateFunctionDefinition definition) {
+		final PartialFunctionConfiguration configuration = new PartialFunctionConfiguration();
+		configuration.setName(definition.getName().getName());
+
+		final List<String> inputs =
+				definition.getInputs()
+  						  .stream()
+						  .map(DataDescription::getName)
+						  .collect(Collectors.toList());
+
+		final List<String> outputs =
+				definition.getOutputs()
+						  .stream()
+						  .map(DataDescription::getName)
+						  .collect(Collectors.toList());
+
+		configuration.getInputDimensions().addAll(inputs);
+		configuration.getOutputDimensions().addAll(outputs);
+
+		definition.getParameters()
+				  .stream()
+				  .map(Parameter::from)
+				  .forEach(p -> configuration.getParameters().add(p));
+
+		return configuration;
+	}
+
+	public static PartialFunctionConfiguration from(final PartialFunctionConfiguration config) {
+		final PartialFunctionConfiguration configuration = new PartialFunctionConfiguration();
+		configuration.setName(config.getName());
+
+		configuration.getInputDimensions()
+					 .addAll(config.getInputDimensions());
+		configuration.getOutputDimensions()
+					 .addAll(config.getOutputDimensions());
+
+		config.getParameters()
+			  .stream()
+			  .map(Parameter::from)
+			  .forEach(p -> configuration.getParameters().add(p));
+
+		return configuration;
+	}
+}
diff --git a/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/api/configuration/SurrogateConfiguration.java b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/api/configuration/SurrogateConfiguration.java
new file mode 100644
index 0000000000000000000000000000000000000000..2224b0f31ab15f51164b958f9f0a643456254b84
--- /dev/null
+++ b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/api/configuration/SurrogateConfiguration.java
@@ -0,0 +1,60 @@
+package de.evoal.surrogate.api.configuration;
+
+import de.evoal.languages.model.mll.SurrogateDefinition;
+import de.evoal.surrogate.api.function.SurrogateFunction;
+import lombok.Data;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Configuration of a {@link SurrogateFunction}.
+ */
+@Data
+public class SurrogateConfiguration {
+	/**
+	 * List of mappings. At least one.
+	 */
+	private final List<FunctionCombinerConfiguration> mappings = new ArrayList<>();
+
+	/**
+	 * Parameters of outputs
+	 */
+	private final Map<String, List<Parameter>> outputParameters = new HashMap<>();
+
+	public void addOutputParameter(final String name, final Parameter parameter) {
+		List<Parameter> content = outputParameters.get(name);
+
+		if(content == null) {
+			content = new ArrayList<>();
+			content.add(parameter);
+			outputParameters.put(name, content);
+		} else {
+			content.add(parameter);
+		}
+	}
+
+	public static SurrogateConfiguration from(final SurrogateDefinition definition) {
+		final SurrogateConfiguration configuration = new SurrogateConfiguration();
+
+		definition.getLayers()
+				  .stream()
+				  .map(FunctionCombinerConfiguration::from)
+				  .forEach(configuration.mappings::add);
+
+		return configuration;
+    }
+
+	public static SurrogateConfiguration from(final SurrogateConfiguration original) {
+		final SurrogateConfiguration configuration = new SurrogateConfiguration();
+
+		original.getMappings()
+				.stream()
+				.map(FunctionCombinerConfiguration::from)
+				.forEach(configuration.mappings::add);
+
+		return configuration;
+	}
+}
diff --git a/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/api/function/AbstractPartialSurrogateFunction.java b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/api/function/AbstractPartialSurrogateFunction.java
new file mode 100644
index 0000000000000000000000000000000000000000..53067ddee58a8f3bce764dd1bed25a69208e6b2f
--- /dev/null
+++ b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/api/function/AbstractPartialSurrogateFunction.java
@@ -0,0 +1,52 @@
+package de.evoal.surrogate.api.function;
+
+import java.util.List;
+
+import de.evoal.surrogate.api.configuration.Parameter;
+import de.evoal.surrogate.api.configuration.PartialFunctionConfiguration;
+import de.evoal.core.api.properties.PropertiesSpecification;
+
+/**
+ * Base class for regression functions storing the input and output properties.
+ */
+public abstract class AbstractPartialSurrogateFunction implements PartialSurrogateFunction {
+	protected static void addParameter(final String name, final Object value, final List<Parameter> parameters) {
+		final Parameter parameter = Parameter.builder()
+				.name(name)
+				.value(value)
+				.build();
+
+		parameters.add(parameter);
+	}
+
+	private final PropertiesSpecification input;
+	private final PropertiesSpecification output;
+	private final PartialFunctionConfiguration configuration;
+	private final List<Parameter> parameters;
+
+	public AbstractPartialSurrogateFunction(final PartialFunctionConfiguration configuration, final List<Parameter> functionParameters, final PropertiesSpecification input, final PropertiesSpecification output) {
+		this.configuration = configuration;
+		this.parameters = functionParameters;
+		this.input = input;
+		this.output = output;
+	}
+
+	@Override
+	public PropertiesSpecification getUsedProperties() {
+		return input;
+	}
+
+	@Override
+	public PropertiesSpecification getOutputProperty() {
+		return output;
+	}
+
+	@Override
+	public List<Parameter> getParameters() {
+		return parameters;
+	}
+
+	public PartialFunctionConfiguration getConfiguration() {
+		return configuration;
+	}
+}
diff --git a/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/api/function/AbstractPartialSurrogateFunctionFactory.java b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/api/function/AbstractPartialSurrogateFunctionFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..aac2b1254fc893e1c83f7811b315dcf002e41795
--- /dev/null
+++ b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/api/function/AbstractPartialSurrogateFunctionFactory.java
@@ -0,0 +1,36 @@
+package de.evoal.surrogate.api.function;
+
+import java.util.List;
+
+import de.evoal.core.api.properties.stream.PropertiesBasedPropertiesPairStreamSupplier;
+import de.evoal.core.api.properties.stream.PropertiesPairStreamSupplier;
+import de.evoal.core.api.properties.stream.PropertiesStreamSupplier;
+import de.evoal.surrogate.api.configuration.PartialFunctionConfiguration;
+import de.evoal.surrogate.api.configuration.Parameter;
+import de.evoal.core.api.properties.PropertiesSpecification;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * Base class for regression factories.
+ */
+@Slf4j
+public abstract class AbstractPartialSurrogateFunctionFactory implements PartialSurrogateFunctionFactory {
+	protected abstract PartialSurrogateFunction calculateRegression(final PartialFunctionConfiguration configuration, final List<Parameter> parameters, final PropertiesSpecification actualInput, final PropertiesSpecification requiredInput, PropertiesSpecification producedOutput, final PropertiesPairStreamSupplier provider);
+
+	@Override
+	public final PartialSurrogateFunction create(final PartialFunctionConfiguration configuration, final PropertiesSpecification actualInput, final PropertiesSpecification requiredInput, final PropertiesSpecification producedOutput, final PropertiesStreamSupplier training) {
+		if(configuration.getState().isEmpty()) {
+			final PropertiesPairStreamSupplier provider = new PropertiesBasedPropertiesPairStreamSupplier(training, requiredInput, producedOutput);
+			final PartialSurrogateFunction function = calculateRegression(configuration, configuration.getParameters(), actualInput, requiredInput, producedOutput, provider);
+			
+			configuration.getState()
+					     .addAll(function.getParameters());
+
+			return function;	
+		} else {
+			return restoreRegression(configuration, actualInput, requiredInput, producedOutput);
+		}
+	}
+
+	protected abstract PartialSurrogateFunction restoreRegression(final PartialFunctionConfiguration configuration, final PropertiesSpecification actualInput, final PropertiesSpecification requiredInput, final PropertiesSpecification producedOutput);
+}
diff --git a/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/api/function/FunctionCombiner.java b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/api/function/FunctionCombiner.java
new file mode 100644
index 0000000000000000000000000000000000000000..92bf820abd42cffa947fd392371d9fd3b9dbc42e
--- /dev/null
+++ b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/api/function/FunctionCombiner.java
@@ -0,0 +1,81 @@
+package de.evoal.surrogate.api.function;
+
+import de.evoal.core.api.properties.Properties;
+import de.evoal.core.api.properties.PropertiesSpecification;
+import de.evoal.core.api.properties.PropertySpecification;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This class takes several {@link PartialSurrogateFunction} and combines them to a
+ * single mapping function. Each partial surrogate function may take a subset of the
+ * input properties and generate a subset of the output properties.
+ */
+public class FunctionCombiner implements MappingFunction {
+	/**
+	 * Specification of the input vector.
+	 */
+	private final PropertiesSpecification inputSpecification;
+
+	/**
+	 * Specification of the output vector.
+	 */
+	private final PropertiesSpecification outputSpecification;
+
+	/**
+	 * All regression functions for calculating the output.
+	 */
+	private final List<PartialSurrogateFunction> functions;
+
+	/**
+	 * A map storing the indices of all property specifications in the output properties.
+	 */
+	private final Map<PropertySpecification, Integer> indices = new HashMap<>();
+
+	public FunctionCombiner(final List<PartialSurrogateFunction> functions, final PropertiesSpecification input, final PropertiesSpecification output) {
+		this.inputSpecification = input;
+		this.outputSpecification = output;
+
+		for(final PartialSurrogateFunction function : functions) {
+			for(final PropertySpecification specification : function.getOutputProperty().getProperties())   {
+				indices.put(specification, outputSpecification.indexOf(specification));
+			}
+		}
+
+		this.functions = functions;
+	}
+
+	@Override
+	public Properties apply(final Properties input) {
+		final Properties output = new Properties(outputSpecification);
+
+		for(final PartialSurrogateFunction entry : functions) {
+			final double [] values = entry.apply(input);
+
+			for(int index = 0; index < values.length; ++index) {
+				output.set(indices.get(entry.getOutputProperty().getProperties().get(index)), values[index]);
+			}
+		}
+
+		return output;
+	}
+
+	@Override
+	public PropertiesSpecification getInputSpecification() {
+		return inputSpecification;
+	}
+
+	/**
+	 * This function gives access to
+	 */
+	public PartialSurrogateFunction[] getFunctions() {
+		return functions.toArray(new PartialSurrogateFunction[functions.size()]);
+	}
+
+	@Override
+	public PropertiesSpecification getOutputSpecification() {
+		return outputSpecification;
+	}
+}
diff --git a/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/api/function/MappingFunction.java b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/api/function/MappingFunction.java
new file mode 100644
index 0000000000000000000000000000000000000000..f45fd19de1933b7e58f587b0b86edff4981b7b74
--- /dev/null
+++ b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/api/function/MappingFunction.java
@@ -0,0 +1,26 @@
+package de.evoal.surrogate.api.function;
+
+import de.evoal.core.api.properties.Properties;
+import de.evoal.core.api.properties.PropertiesSpecification;
+
+/**
+ * General interface of a functions. It receives some input properties that
+ * adhere to the input properties specification and calculates some
+ * properties based on the input that adheres to the output properties specification.
+ */
+public interface MappingFunction {
+	/**
+	 * Applies the mapping function.
+	 */
+	public Properties apply(final Properties input);
+
+	/**
+	 * @return An empty input vector with all property headers set.
+	 */
+	public PropertiesSpecification getInputSpecification();
+
+	/**
+	 * @return An empty output vector with all property headers set.
+	 */
+	public PropertiesSpecification getOutputSpecification();
+}
diff --git a/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/api/function/PartialSurrogateFunction.java b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/api/function/PartialSurrogateFunction.java
new file mode 100644
index 0000000000000000000000000000000000000000..b94e0de6c7922ff0628698719ff6c441dbbb6ef1
--- /dev/null
+++ b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/api/function/PartialSurrogateFunction.java
@@ -0,0 +1,44 @@
+package de.evoal.surrogate.api.function;
+
+import java.util.Collection;
+
+import de.evoal.surrogate.api.configuration.PartialFunctionConfiguration;
+import de.evoal.surrogate.api.configuration.Parameter;
+import de.evoal.core.api.properties.Properties;
+import de.evoal.core.api.properties.PropertiesSpecification;
+
+/**
+ * A partial surrogate function calculates only specific properties. Several
+ * parallel or chained partial surrogate function make up the complete surrogate
+ * function.
+ */
+public interface PartialSurrogateFunction {
+	/**
+	 * Applies the regression to {@code input} and returns the calculated
+	 *   value.
+	 *
+	 * @param input The input properties for the regression.
+	 * @return The calculated value.
+	 */
+	public double  [] apply(final Properties input);
+
+	/**
+	 * @return The generated property.
+	 */
+	public PropertiesSpecification getOutputProperty();
+
+	/**
+	 * @return A collection of parameters to restore the regression function.
+	 */
+	public Collection<? extends Parameter> getParameters();
+
+	/**
+	 * @return An empty properties vector containing all consumed properties.
+	 */
+	public PropertiesSpecification getUsedProperties();
+
+	/**
+	 * @return The configuration object.
+	 */
+	public PartialFunctionConfiguration getConfiguration();
+}
diff --git a/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/api/function/PartialSurrogateFunctionFactory.java b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/api/function/PartialSurrogateFunctionFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..132895b4b4f0763068b79a0a17627b1d8c3acb83
--- /dev/null
+++ b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/api/function/PartialSurrogateFunctionFactory.java
@@ -0,0 +1,28 @@
+package de.evoal.surrogate.api.function;
+
+import de.evoal.core.api.properties.stream.PropertiesStreamSupplier;
+import de.evoal.core.api.properties.Properties;
+import de.evoal.core.api.properties.PropertiesSpecification;
+import de.evoal.surrogate.api.configuration.PartialFunctionConfiguration;
+
+import java.util.stream.Stream;
+
+/**
+ * Factory for creating regression functions.
+ */
+public interface PartialSurrogateFunctionFactory {
+	/**
+	 * Method for creating a regression function.
+	 * 
+	 * @param configuration Regression configuration.
+	 * @param actualInput The input properties vector that will be passed to the
+	 * 						regression function when it is applied
+	 * 						{@link PartialSurrogateFunction#apply(Properties)}.
+	 * @param requiredInput The properties that the regression function has to consume.
+	 * @param producedOutput  The property that the regression function has to produce.
+	 * @param training Training data with target values.
+	 *
+	 * @return The resulting regression function.
+	 */
+	public PartialSurrogateFunction create(final PartialFunctionConfiguration configuration, final PropertiesSpecification actualInput, final PropertiesSpecification requiredInput, final PropertiesSpecification producedOutput, final PropertiesStreamSupplier training);
+}
diff --git a/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/api/function/SurrogateFunction.java b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/api/function/SurrogateFunction.java
new file mode 100644
index 0000000000000000000000000000000000000000..13233e1bd622a0211a36e6aa2e4cec61036e2421
--- /dev/null
+++ b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/api/function/SurrogateFunction.java
@@ -0,0 +1,60 @@
+package de.evoal.surrogate.api.function;
+
+import de.evoal.core.api.properties.Properties;
+import de.evoal.core.api.properties.PropertiesSpecification;
+import lombok.Data;
+import lombok.NonNull;
+
+import java.util.List;
+
+/**
+ * A surrogate function replaces the actual function used in the optimization
+ * if the actual function is too expensive to calculate or even unknown. A
+ * surrogate function transforms input properties into output properties
+ * according to a known oder learned function.
+ *
+ * A surrogate function may consist of several chained combined functions (c.f.,
+ * {@link FunctionCombiner}. The surrogate function then takes the input and
+ * calculates an output' using a combined function. The output' is then used
+ * as input for the next combined function in the chain. The output of the last
+ * combined function is the result of the surrogate function.
+ */
+@Data
+public final class SurrogateFunction implements MappingFunction {
+	/**
+	 * The chain of property mappings.
+	 */
+	private final List<FunctionCombiner> mappings;
+
+	/**
+	 * Property specification of the input of the complete surrogate function.
+	 */
+	private final PropertiesSpecification inputSpecification;
+
+	/**
+	 * Property specification of the output of the complete surrogate function.
+	 */
+	private final PropertiesSpecification outputSpecification;
+
+	/**
+	 * Creates a new surrogate function for the combined functions.
+	 *
+	 * @param mappings The chain of combined functions.
+	 */
+	public SurrogateFunction(final @NonNull List<FunctionCombiner> mappings) {
+		this.mappings = mappings;
+		this.inputSpecification = mappings.get(0).getInputSpecification();
+		this.outputSpecification = mappings.get(mappings.size() - 1).getOutputSpecification();
+	}
+
+	@Override
+	public Properties apply(final Properties input) {
+		Properties current = input;
+
+		for(final MappingFunction function : mappings) {
+			current = function.apply(current);
+		}
+
+		return current;
+	}
+}
diff --git a/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/api/function/package-info.java b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/api/function/package-info.java
new file mode 100644
index 0000000000000000000000000000000000000000..e5482784f0f48a9a6ada8584c2ce472deac94164
--- /dev/null
+++ b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/api/function/package-info.java
@@ -0,0 +1 @@
+package de.evoal.surrogate.api.function;
\ No newline at end of file
diff --git a/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/api/training/TrainingDataManager.java b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/api/training/TrainingDataManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..1e8507b3fbb2352be8a24897d3aeac2f8dced994
--- /dev/null
+++ b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/api/training/TrainingDataManager.java
@@ -0,0 +1,16 @@
+package de.evoal.surrogate.api.training;
+
+import de.evoal.core.api.properties.stream.FileBasedPropertiesStreamSupplier;
+import de.evoal.core.api.properties.stream.PropertiesStreamSupplier;
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.enterprise.context.ApplicationScoped;
+
+@ApplicationScoped
+public class TrainingDataManager {
+
+    @Getter
+    @Setter
+    private PropertiesStreamSupplier trainingStream;
+}
diff --git a/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/SurrogateMain.java b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/SurrogateMain.java
new file mode 100644
index 0000000000000000000000000000000000000000..396244943d507e06a56ef6c9a90717f221f0eb4e
--- /dev/null
+++ b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/SurrogateMain.java
@@ -0,0 +1,47 @@
+package de.evoal.surrogate.main;
+
+import de.evoal.core.api.cdi.BeanFactory;
+import de.evoal.core.api.cdi.BlackboardValue;
+import de.evoal.core.api.cdi.MainClass;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import de.evoal.languages.model.mll.MachineLearningConfiguration;
+import de.evoal.surrogate.api.SurrogateBlackboardEntry;
+import de.evoal.surrogate.main.internal.StatementExecutor;
+import de.evoal.surrogate.main.internal.SymbolTable;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * Program for pre-calculating regressions to minimize runtime overhead of
+ *   recalculating them.
+ */
+@Slf4j
+@Named("surrogate-training")
+@ApplicationScoped
+public class SurrogateMain implements MainClass {
+
+    @Inject
+    @BlackboardValue(SurrogateBlackboardEntry.SURROGATE_CONFIGURATION)
+    private MachineLearningConfiguration mlConfiguration;
+
+    @Override
+    public void run() {
+        log.info("Training surrogate models and measuring GOF values.");
+
+        final SymbolTable globalTable = new SymbolTable(null);
+        mlConfiguration.getDefinitions()
+                        .stream()
+                        .forEach(def -> globalTable.put(def.getName(), def));
+
+        final StatementExecutor executor = BeanFactory.create(StatementExecutor.class);
+        executor.setSymbolTable(globalTable);
+
+        mlConfiguration.getStatements()
+                       .forEach(executor::evaluate);
+
+        log.info("Finished surrogate model training.");
+    }
+}
diff --git a/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/cdi/IOProducer.java b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/cdi/IOProducer.java
new file mode 100644
index 0000000000000000000000000000000000000000..bc1b51d72d06c3e9115f5682a6cda5fd1e735a81
--- /dev/null
+++ b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/cdi/IOProducer.java
@@ -0,0 +1,56 @@
+package de.evoal.surrogate.main.cdi;
+
+import java.io.*;
+import java.util.function.BiConsumer;
+import java.util.function.Function;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.inject.Produces;
+import javax.inject.Named;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import de.evoal.surrogate.api.configuration.SurrogateConfiguration;
+import lombok.NonNull;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * Loader for different files necessary to train a prediction and load/store
+ *   its state.
+ */
+@ApplicationScoped
+@Slf4j
+public class IOProducer {
+
+	@Produces
+	@Named("surrogate-loader")
+	public Function<@NonNull File, @NonNull SurrogateConfiguration> createSurrogateLoader() {
+		return (file) -> loadPredictiveConfiguration(file);
+	}
+
+	@Produces
+	@Named("surrogate-writer")
+	public BiConsumer<@NonNull SurrogateConfiguration, @NonNull File> createSurrogateWriter() {
+		return (config, file) -> storePredictiveConfiguration(config, file);
+	}
+
+	private static SurrogateConfiguration loadPredictiveConfiguration(final File file) {
+		log.info("Loading predictive configuration from {}.", file);
+		try(final InputStream is = new FileInputStream(file)) {
+			return new ObjectMapper().readValue(is, SurrogateConfiguration.class);
+		} catch (final IOException e) {
+			log.error("Failed to load predictive configuration from {}.", file, e);
+
+			throw new IllegalStateException("Failed to load predictive configuration from " + file);
+		}
+	}
+
+	private static void storePredictiveConfiguration(final SurrogateConfiguration config, final File file) {
+		log.info("Storing predictive configuration to {}.", file);
+
+		try {
+			new ObjectMapper().writerWithDefaultPrettyPrinter().writeValue(file, config);
+		} catch (IOException e) {
+			log.error("Failed to store configuration to {}", file, e);
+		}
+	}
+}
diff --git a/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/cdi/MLLConfigurationProducer.java b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/cdi/MLLConfigurationProducer.java
new file mode 100644
index 0000000000000000000000000000000000000000..a17d773fd40e4b0abda5f09579efd44fc674abe2
--- /dev/null
+++ b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/cdi/MLLConfigurationProducer.java
@@ -0,0 +1,126 @@
+package de.evoal.surrogate.main.cdi;
+
+import com.google.inject.Injector;
+import de.evoal.core.api.board.Blackboard;
+import de.evoal.core.api.board.BlackboardEntry;
+import de.evoal.core.api.cdi.BlackboardValue;
+import de.evoal.languages.model.ddl.dsl.DataDescriptionLanguageStandaloneSetup;
+import de.evoal.languages.model.ddl.impl.DdlPackageImpl;
+import de.evoal.languages.model.dl.dsl.DefinitionLanguageStandaloneSetup;
+import de.evoal.languages.model.dl.impl.DlPackageImpl;
+import de.evoal.languages.model.el.dsl.ExpressionLanguageStandaloneSetup;
+import de.evoal.languages.model.el.impl.ELPackageImpl;
+import de.evoal.languages.model.mll.dsl.MachineLearningLanguageStandaloneSetup;
+import de.evoal.languages.model.mll.MachineLearningConfiguration;
+import de.evoal.languages.model.mll.impl.MllPackageImpl;
+import de.evoal.surrogate.api.SurrogateBlackboardEntry;
+import lombok.extern.slf4j.Slf4j;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.xtext.resource.XtextResource;
+import org.eclipse.xtext.resource.XtextResourceSet;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.context.Dependent;
+import javax.enterprise.event.Observes;
+import javax.enterprise.inject.Produces;
+import javax.enterprise.inject.spi.InjectionPoint;
+import java.io.File;
+import java.util.Optional;
+
+@ApplicationScoped
+@Slf4j
+public class MLLConfigurationProducer {
+    public void loadModel(final @Observes BlackboardEntry value, final Blackboard board) {
+        if(!SurrogateBlackboardEntry.SURROGATE_CONFIGURATION_FILE.equals(value.getLabel())) {
+            return;
+        }
+
+        final String configurationFile = board.get(value.getLabel());
+
+        log.info("Using surrogate configuration from '{}'.", configurationFile);
+
+        initializeEMF();
+
+        final File file = new File(configurationFile);
+
+        if(!file.isFile()) {
+            log.info("Configured surrogate configuration is a folder.");
+            throw  new IllegalArgumentException("Please specify a surrogate file.");
+        }
+
+        if(!file.canRead()) {
+            log.info("Configured surrogate configuration cannot be read.");
+            throw  new IllegalArgumentException("Please specify a readable surrogate file.");
+        }
+
+        final MachineLearningConfiguration configuration = read(file).get();
+        board.bind(SurrogateBlackboardEntry.SURROGATE_CONFIGURATION, configuration);
+    }
+
+    /**
+     * Initialize the model packages and perform the parser setup.
+     */
+    private void initializeEMF() {
+        DdlPackageImpl.init();
+        ELPackageImpl.init();
+        DlPackageImpl.init();
+        MllPackageImpl.init();
+
+        DataDescriptionLanguageStandaloneSetup.doSetup();
+        ExpressionLanguageStandaloneSetup.doSetup();
+        DefinitionLanguageStandaloneSetup.doSetup();
+        MachineLearningLanguageStandaloneSetup.doSetup();
+    }
+
+    /**
+     * Parses the given generator file and returns the corresponding model.
+     *
+     * @param modelFile The model file to read.
+     * @return The data validation model or an empty optional.
+     */
+    private Optional<MachineLearningConfiguration> read(final File modelFile) {
+        log.info("Reading model file {}.", modelFile);
+
+        final Injector injector = new MachineLearningLanguageStandaloneSetup().createInjectorAndDoEMFRegistration();
+        final XtextResourceSet resourceSet = injector.getInstance(XtextResourceSet.class);
+        resourceSet.addLoadOption(XtextResource.OPTION_RESOLVE_ALL, Boolean.TRUE);
+        resourceSet.addLoadOption(XtextResource.OPTION_ENCODING, "UTF-8");
+
+        try {
+            final URI modelURI = URI.createFileURI(modelFile.getAbsolutePath());
+            final Resource resource = resourceSet.getResource(modelURI, true);
+            resource.load(resourceSet.getLoadOptions());
+
+            if(!resource.getErrors().isEmpty()) {
+                for(Resource.Diagnostic diagnostic : resource.getErrors()) {
+                    log.error("Error while processing rule '{}': {}", modelFile, diagnostic);
+                }
+            }
+
+            if(!resource.getWarnings().isEmpty()) {
+                for(Resource.Diagnostic diagnostic : resource.getWarnings()) {
+                    log.error("Warning while processing rule '{}': {}", modelFile, diagnostic);
+                }
+            }
+
+            return Optional.of((MachineLearningConfiguration) resource.getContents().get(0));
+        } catch (final Exception e) {
+            log.error("Unable to to generator file '{}'.", modelFile, e);
+            return Optional.empty();
+        }
+    }
+
+    @Produces @Dependent
+    @BlackboardValue(SurrogateBlackboardEntry.SURROGATE_CONFIGURATION)
+    public MachineLearningConfiguration injectMachineLearningConfiguration(final InjectionPoint ip, final Blackboard board) {
+        final BlackboardValue value = ip.getAnnotated().getAnnotation(BlackboardValue.class);
+        final Object result = board.get(value.value());
+
+        if(result instanceof MachineLearningConfiguration) {
+            return (MachineLearningConfiguration)result;
+        }
+
+        throw new IllegalArgumentException("Unable to handle type " + result.getClass());
+    }
+}
diff --git a/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/gof/cross/CrossValidationCalculator.java b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/gof/cross/CrossValidationCalculator.java
new file mode 100644
index 0000000000000000000000000000000000000000..32d660a553363b59496352831e2596dad2be388f
--- /dev/null
+++ b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/gof/cross/CrossValidationCalculator.java
@@ -0,0 +1,197 @@
+package de.evoal.surrogate.main.gof.cross;
+
+import de.evoal.core.api.properties.Properties;
+import de.evoal.core.api.properties.PropertiesSpecification;
+import de.evoal.core.api.properties.PropertySpecification;
+import de.evoal.core.api.properties.stream.PropertiesStreamSupplier;
+import de.evoal.core.api.utils.Requirements;
+import de.evoal.surrogate.api.SurrogateInformationCalculator;
+import de.evoal.surrogate.api.configuration.FunctionCombinerConfiguration;
+import de.evoal.surrogate.api.configuration.PartialFunctionConfiguration;
+import de.evoal.surrogate.api.configuration.SurrogateConfiguration;
+import de.evoal.surrogate.api.function.PartialSurrogateFunction;
+import de.evoal.surrogate.api.function.SurrogateFunction;
+import de.evoal.surrogate.main.internal.SurrogateFactory;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.math3.stat.descriptive.moment.Mean;
+import org.apache.commons.math3.stat.descriptive.moment.StandardDeviation;
+
+import javax.enterprise.context.Dependent;
+import javax.inject.Named;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Calculates cross validation values.
+ */
+@Dependent
+@Named("cross-validation")
+@Slf4j
+public class CrossValidationCalculator implements SurrogateInformationCalculator {
+
+	/**
+	 * The surrogate function to use.
+	 */
+	private SurrogateFunction function;
+
+	/**
+	 * The number of groups for the validation.
+	 */
+	private int k = 1;
+
+	/**
+	 * The surrogate configuration for adding the calculated values
+	 */
+	private SurrogateConfiguration originalConfiguration;
+
+	/**
+	 * The training data used
+ 	 */
+	private CrossValidationPropertiesStreamSupplier trainingSupplier;
+
+	@Override
+	public void execute() {
+ 		log.info("calculating of {}-fold cross validation of surrogate function :", k);
+
+		for(int i = 0; i < originalConfiguration.getMappings().size(); ++i) {
+			final SurrogateConfiguration trainingConfiguration = SurrogateConfiguration.from(originalConfiguration);
+
+			final FunctionCombinerConfiguration originalMapping = originalConfiguration.getMappings().get(i);
+			final FunctionCombinerConfiguration trainingMapping = trainingConfiguration.getMappings().get(i);
+
+			validateMapping(originalMapping, trainingMapping);
+		}
+	}
+
+	private void validateMapping(final FunctionCombinerConfiguration originalMapping, final FunctionCombinerConfiguration trainingMapping) {
+		log.info("Calculating cross validation for mapping {}.", originalMapping.getName());
+		final int rowLength = originalMapping.getOutputDimensions().size() + 2;
+
+		//final AsciiTable table = new AsciiTable();
+		//table.addRule();
+		//final Object [] cvLabels = originalMapping.getOutputDimensions().toArray();
+		//final Object [] header = new String [rowLength];
+		//header[0] = "";
+		//header[rowLength - 1] = "Summe";
+		//System.arraycopy(cvLabels, 0, header, 1, cvLabels.length);
+		//table.addRow(header);
+		//table.addRule();
+
+		// detail list for all input target
+		double [][] data = new double[rowLength - 1][k];
+
+		final PropertiesSpecification mappingInput = PropertiesSpecification.builder()
+																			.add(originalMapping.getInputDimensions().stream())
+																			.build();
+		final PropertiesSpecification mappingOutput = PropertiesSpecification.builder()
+																			 .add(originalMapping.getOutputDimensions().stream())
+																			 .build();
+
+		final PropertiesSpecification [] fInputs = new PropertiesSpecification [originalMapping.getFunctions().size()];
+		final PropertiesSpecification [] fOutputs = new PropertiesSpecification[originalMapping.getFunctions().size()];
+
+		for(int partition = 1; partition <= k; ++partition) {
+			trainingSupplier.setPartition(partition);
+
+			//final Object[] tableData = new Object[rowLength];
+			//tableData[0] = "Partition " + partition;
+
+			for(int func = 0; func < originalMapping.getFunctions().size(); ++func) {
+				final PartialFunctionConfiguration fConfig = PartialFunctionConfiguration.from(trainingMapping.getFunctions()
+																			.get(func));
+
+				final PropertiesSpecification fInput = PropertiesSpecification.builder()
+																			  .add(fConfig.getInputDimensions().stream())
+																			  .build();
+				final PropertiesSpecification fOutput = PropertiesSpecification.builder()
+																			   .add(fConfig.getOutputDimensions().stream())
+																			   .build();
+
+
+				final PartialSurrogateFunction mapping = SurrogateFactory.create(fConfig, fInput, fOutput, trainingSupplier);
+
+				// sum of prediction errors in this partition for each output property
+				final double[] correctness = new double[fOutput.size()];
+				trainingSupplier.getValidationStream()
+								.get()
+						  		.forEach(source -> {
+									final Properties predicted = new Properties(fOutput, mapping.apply(source));
+									final Properties calculated = Properties.create(fOutput, source);
+
+									for (int cvi = 0; cvi < calculated.size(); ++cvi) {
+										//correctness[cvi] = correctness[cvi] + Math.abs((calculated.get(cvi) - predicted.get(cvi)) / calculated.get(cvi));
+										correctness[cvi] = correctness[cvi] + Math.abs(calculated.get(cvi) - predicted.get(cvi));
+									}
+								});
+
+				// relate cumulative errors to partition size (number of test candidates)
+				for (int i = 0; i < correctness.length; ++i) {
+					correctness[i] = correctness[i] / trainingSupplier.getValidationStream().get().count();
+				}
+
+				for (int i = 0; i < correctness.length; ++i) {
+					// copy cumulative error to output table
+					//tableData[1 + mappingOutput.indexOf(fOutput.getProperties().get(i))] = String.format("%.4f", correctness[i]);
+					// copy cumulative error to data table
+					data[mappingOutput.indexOf(fOutput.getProperties().get(i))][partition - 1] = correctness[i];
+				}
+			}
+
+			// calculate sum of errors for partition
+			final int pi = partition;
+			data[data.length - 1][partition - 1] = Arrays.stream(data).mapToDouble(a -> a[pi - 1]).sum();
+			//data[correctness.length][partition] = Arrays.stream(correctness).sum();
+			//tableData[data.length] = String.format("%.4f", data[data.length - 1][partition]);
+
+			//table.addRow(tableData);
+		}
+
+		//table.addRule();
+
+		// calculate last row
+		// Object [] tableData = new Object[rowLength];
+		//tableData[0] = "Ø / s";
+		for(int i = 0; i < data.length; ++i) {
+			double avg = new Mean().evaluate(data[i]);
+			double sd = new StandardDeviation().evaluate(data[i]);
+
+			//tableData[i+1] = String.format("%.4f / %.4f", avg, sd);
+
+			if(i != data.length - 1) {
+				attach(originalMapping,
+				       mappingOutput.getProperties().get(i),
+					   new CrossValidationData(k, avg, k, sd));
+			}
+		}
+		//table.addRow(tableData);
+		//table.addRule();
+		//System.out.println(table.render(140));
+	}
+
+	private void attach(final FunctionCombinerConfiguration config, final PropertySpecification propertySpecification, final CrossValidationData data) {
+		for(final PartialFunctionConfiguration fConfig : config.getFunctions()) {
+			if(fConfig.getOutputDimensions().contains(propertySpecification.name())) {
+				data.attachTo(fConfig, propertySpecification.name());
+				break;
+			}
+		}
+	}
+
+	@Override
+	public String toString() {
+		return "cross validation";
+	}
+
+	@Override
+	public void configure(final SurrogateFunction function, final SurrogateConfiguration config, final List<Object> parameters, final PropertiesStreamSupplier trainingData) {
+		Requirements.requireSize(parameters, 1);
+		Requirements.requireType(parameters, 0, Integer.class);
+		Requirements.requireNotNull(function);
+		Requirements.requireNotNull(config);
+
+		k = (Integer)parameters.get(0);
+		this.function = function;
+		this.originalConfiguration = config;
+		trainingSupplier = new CrossValidationPropertiesStreamSupplier(trainingData, k);
+	}
+}
diff --git a/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/gof/cross/CrossValidationData.java b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/gof/cross/CrossValidationData.java
new file mode 100644
index 0000000000000000000000000000000000000000..ee120c7dffac2a11836144ab1abacc4b32fb2132
--- /dev/null
+++ b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/gof/cross/CrossValidationData.java
@@ -0,0 +1,42 @@
+package de.evoal.surrogate.main.gof.cross;
+
+import de.evoal.surrogate.api.configuration.Parameter;
+import de.evoal.surrogate.api.configuration.PartialFunctionConfiguration;
+
+public class CrossValidationData {
+    private final int k;
+    private final double mean;
+    private final int partitionSize;
+    private final double sd;
+
+    public CrossValidationData(final int k, final double mean, final int partitionSize, final double sd) {
+        this.k = k;
+        this.mean = mean;
+        this.partitionSize = partitionSize;
+        this.sd = sd;
+    }
+
+    public double getMean() {
+        return mean;
+    }
+
+    public double getSd() {
+        return sd;
+    }
+
+    public void attachTo(final PartialFunctionConfiguration regression, final String outputName) {
+        attach(regression, outputName, "cross-validation-k", k);
+        attach(regression, outputName, "cross-validation-mean", mean);
+        attach(regression, outputName, "cross-validation-partition-size", partitionSize);
+        attach(regression, outputName, "cross-validation-sd", sd);
+    }
+
+    private void attach(final PartialFunctionConfiguration regression, final String output, final String name, final Object value) {
+        final Parameter parameter = Parameter.builder()
+                                             .name(name)
+                                             .value(value)
+                                             .build();
+
+        regression.addOutputParameter(output, parameter);
+    }
+}
diff --git a/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/gof/cross/CrossValidationPropertiesStreamSupplier.java b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/gof/cross/CrossValidationPropertiesStreamSupplier.java
new file mode 100644
index 0000000000000000000000000000000000000000..8f9f049139efb3075999c1e2c1ce325d9d17148b
--- /dev/null
+++ b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/gof/cross/CrossValidationPropertiesStreamSupplier.java
@@ -0,0 +1,102 @@
+package de.evoal.surrogate.main.gof.cross;
+
+import de.evoal.core.api.properties.Properties;
+import de.evoal.core.api.properties.stream.PropertiesStreamSupplier;
+import lombok.Setter;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.Arrays;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.stream.Stream;
+
+/**
+ * A stream supplier that leaves out a part of the training data.
+ */
+@Slf4j
+public class CrossValidationPropertiesStreamSupplier implements PropertiesStreamSupplier {
+
+    /**
+     * Numbers of partitions to generate.
+     */
+    private final int k;
+
+    /**
+     * Partition to leave out.
+     */
+    @Setter
+    private int partition;
+
+    /**
+     * The training data to split.
+     */
+    private final PropertiesStreamSupplier trainingData;
+
+    private final long traingDataCount;
+
+    CrossValidationPropertiesStreamSupplier(final PropertiesStreamSupplier trainingData, final int k) {
+        this.trainingData = trainingData;
+        this.k = k;
+        this.traingDataCount = trainingData.get().count();
+    }
+
+    @Override
+    public Stream<Properties> get() {
+        final long partitionRest = traingDataCount % k;
+
+        // calculate each partition size
+        final long partitionSizes[] = new long[k];
+        for(int i = 0; i < k; ++i) {
+            partitionSizes[i] = traingDataCount / k + (i < partitionRest ? 1 : 0);
+        }
+
+        // calculate counts
+        final long before = Arrays.stream(partitionSizes)
+                                  .limit(partition - 1)
+                                  .sum();
+        final long skip = partitionSizes[partition - 1];
+
+        log.info("Streaming partition #{}. Properties before: {}. Properties to skip: {}.", partition, before, skip);
+
+        final AtomicLong counter = new AtomicLong(0);
+
+        return trainingData.get()
+                           .filter(p -> {
+                                long c = counter.incrementAndGet();
+
+                                return c <= before || c > before + skip;
+                            });
+    }
+
+    public PropertiesStreamSupplier getValidationStream() {
+        return new PropertiesStreamSupplier() {
+            @Override
+            public Stream<Properties> get() {
+                final long partitionRest = traingDataCount % k;
+
+                // calculate each partition size
+                final long partitionSizes[] = new long[k];
+                for(int i = 0; i < k; ++i) {
+                    partitionSizes[i] = traingDataCount / k + (i < partitionRest ? 1 : 0);
+                }
+
+                // calculate counts
+                final long before = Arrays.stream(partitionSizes)
+                        .limit(partition - 1)
+                        .sum();
+                final long count = partitionSizes[partition - 1];
+
+
+                log.info("Streaming validation partition #{}. Properties before: {}. Properties to stream: {}.", partition, before, count);
+
+                final AtomicLong counter = new AtomicLong(0);
+
+                return trainingData.get()
+                        .filter(p -> {
+                            long c = counter.incrementAndGet();
+
+                            return c > before || c <= before + count;
+                        });
+            }
+        };
+    }
+}
diff --git a/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/gof/rsquare/RSquareCalculator.java b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/gof/rsquare/RSquareCalculator.java
new file mode 100644
index 0000000000000000000000000000000000000000..deda8dce092b4664d93b68af481bc3a13b098e07
--- /dev/null
+++ b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/gof/rsquare/RSquareCalculator.java
@@ -0,0 +1,125 @@
+package de.evoal.surrogate.main.gof.rsquare;
+
+import de.evoal.core.api.properties.Properties;
+import de.evoal.core.api.properties.stream.PropertiesBasedPropertiesPairStreamSupplier;
+import de.evoal.core.api.properties.stream.PropertiesPairStreamSupplier;
+import de.evoal.core.api.properties.stream.PropertiesStreamSupplier;
+import de.evoal.core.api.utils.Requirements;
+import de.evoal.surrogate.api.SurrogateInformationCalculator;
+import de.evoal.surrogate.api.configuration.Parameter;
+import de.evoal.surrogate.api.configuration.SurrogateConfiguration;
+import de.evoal.surrogate.api.function.SurrogateFunction;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.math3.stat.descriptive.moment.Mean;
+import org.apache.commons.math3.stat.descriptive.moment.StandardDeviation;
+import org.apache.commons.math3.util.Pair;
+
+import javax.enterprise.context.Dependent;
+import javax.inject.Named;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Calculates cross validation values.
+ */
+@Dependent
+@Named("R²")
+@Slf4j
+public class RSquareCalculator implements SurrogateInformationCalculator {
+
+	/**
+	 * Surrogate configuration for attaching the calculated r² value.
+	 */
+	private SurrogateConfiguration config;
+
+	/**
+	 * The actual surrogate function.
+	 */
+	private SurrogateFunction function;
+
+	/**
+	 * Supplier for the trainings data.
+	 */
+	private PropertiesStreamSupplier trainingData;
+
+	@Override
+	public void execute() {
+		log.info("calculating r² of surrogate function.");
+
+		final PropertiesPairStreamSupplier pairStream = new PropertiesBasedPropertiesPairStreamSupplier(trainingData, function.getInputSpecification(), function.getOutputSpecification());
+
+		final double [][] yValues = pairStream.get()
+											  .map(Pair::getSecond)
+				   							  .map(Properties::getValues)
+											  .toArray(size -> new double[size][]);
+
+		final double [] means = new double [yValues[0].length];
+		for(int i = 0; i < means.length; ++i) {
+			final int j = i;
+			means[i] = new Mean().evaluate(Arrays.stream(yValues)
+							 					 .mapToDouble(a -> a[j])
+							 					 .toArray());
+		}
+
+		final double [] sds = new double [yValues[0].length];
+		for(int i = 0; i < sds.length; ++i) {
+			final int j = i;
+			sds[i] = new StandardDeviation().evaluate(Arrays.stream(yValues)
+															  .mapToDouble(a -> a[j])
+															  .toArray());
+		}
+
+		final double [][] errors =
+				pairStream.get()
+						.map(pair -> {
+							final Properties input = pair.getFirst();
+							final Properties calculated = function.apply(input);
+
+							double [] values = new double[calculated.size()];
+							System.arraycopy(calculated.getValues(), 0, values, 0, values.length);
+
+							for(int i = 0; i < values.length; ++i) {
+								values[i] = Math.pow(pair.getSecond().get(i) - values[i], 2);
+							}
+
+							return values;
+						}).toArray(size -> new double [size][]);
+
+		for(int y = 0; y < errors[0].length; ++y) {
+			double error = 0.0;
+
+			for(int x = 0; x < errors.length; ++x) {
+				error += errors[x][y];
+			}
+
+			final double unexplainedVariation = error;
+			final double totalVariation = Math.pow(sds[y], 2) * yValues.length;
+			final double rSquare = 1 - unexplainedVariation / totalVariation;
+
+			log.info("unexplained variation: '{}', total variation: {}, rSquare: {}", unexplainedVariation, totalVariation, rSquare);
+
+			final Parameter goodnessOfFit = Parameter.builder()
+					.name("r²")
+					.value(rSquare)
+					.build();
+
+			config.addOutputParameter(function.getOutputSpecification().getProperties().get(y).name(), goodnessOfFit);
+		}
+	}
+
+	@Override
+	public String toString() {
+		return "r²";
+	}
+
+	@Override
+	public void configure(final SurrogateFunction function, final SurrogateConfiguration config, final List<Object> parameters, final PropertiesStreamSupplier trainingData) {
+		Requirements.requireEmpty(parameters);
+		Requirements.requireNotNull(function);
+		Requirements.requireNotNull(config);
+
+		this.function = function;
+		this.config = config;
+		this.trainingData = trainingData;
+	}
+}
diff --git a/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/gof/rsquare/RSquareData.java b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/gof/rsquare/RSquareData.java
new file mode 100644
index 0000000000000000000000000000000000000000..846ceba8453257648d832477bc7886f9a7870a51
--- /dev/null
+++ b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/gof/rsquare/RSquareData.java
@@ -0,0 +1,26 @@
+package de.evoal.surrogate.main.gof.rsquare;
+
+import de.evoal.surrogate.api.configuration.Parameter;
+import de.evoal.surrogate.api.configuration.PartialFunctionConfiguration;
+import lombok.Data;
+
+@Data
+public class RSquareData {
+    private final double value;
+
+    public RSquareData(final double value) {
+        this.value = value;
+    }
+    public void attachTo(final PartialFunctionConfiguration regression, final String outputName) {
+        attach(regression, outputName, "r²", value);
+    }
+
+    private void attach(final PartialFunctionConfiguration regression, final String output, final String name, final Object value) {
+        final Parameter parameter = Parameter.builder()
+                                             .name(name)
+                                             .value(value)
+                                             .build();
+
+        regression.addOutputParameter(output, parameter);
+    }
+}
diff --git a/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/internal/StatementExecutor.java b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/internal/StatementExecutor.java
new file mode 100644
index 0000000000000000000000000000000000000000..a6309e87a5c3b70ab46faa0a6d3bb5d415291467
--- /dev/null
+++ b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/internal/StatementExecutor.java
@@ -0,0 +1,209 @@
+package de.evoal.surrogate.main.internal;
+
+import de.evoal.core.api.cdi.BeanFactory;
+import de.evoal.core.api.utils.ConstantSwitch;
+import de.evoal.languages.model.el.Call;
+import de.evoal.languages.model.el.StringLiteral;
+import de.evoal.languages.model.mll.*;
+import de.evoal.languages.model.mll.util.MllSwitch;
+import de.evoal.surrogate.api.SurrogateInformationCalculator;
+import de.evoal.surrogate.api.configuration.SurrogateConfiguration;
+import de.evoal.core.api.properties.stream.FileBasedPropertiesStreamSupplier;
+import de.evoal.surrogate.api.function.SurrogateFunction;
+import de.evoal.surrogate.api.training.TrainingDataManager;
+import lombok.NonNull;
+import lombok.Setter;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.enterprise.context.Dependent;
+import javax.inject.Inject;
+import javax.inject.Named;
+import java.io.File;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.function.BiConsumer;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+@Dependent
+@Slf4j
+public class StatementExecutor extends MllSwitch<Object> {
+
+    private SurrogateConfiguration config;
+
+    private SurrogateDefinition definition;
+
+    private SurrogateFunction function;
+
+    @Setter
+    private SymbolTable symbolTable = new SymbolTable(null);
+
+    @Inject
+    private TrainingDataManager manager;
+
+
+    /**
+     * Variable pattern
+     */
+    private final static Pattern varPattern = Pattern.compile("\\$\\{[^}]*}");
+
+    @Inject
+    @Named("surrogate-writer")
+    private BiConsumer<@NonNull SurrogateConfiguration, @NonNull File> surrogateWriter;
+
+    public void evaluate(final Statement statement) {
+        doSwitch(statement);
+    }
+
+    @Override
+    public Object caseCallStatement(final CallStatement call) {
+        log.info("Have to call stuff: {}", call.getCall().getFunction());
+
+        return null;
+    }
+
+    @Override
+    public Object caseBlockStatement(final BlockStatement block) {
+        block.getStatements()
+             .forEach(this::evaluate);
+
+        return null;
+    }
+
+    @Override
+    public Object casePredictStatement(final PredictStatement predict) {
+        final File input = calculateFilename(predict.getTrainingData());
+        final File output = calculateFilename(predict.getModelFilename());
+        final SurrogateDefinition definition = predict.getSurrogate();
+
+        apply(definition, input, output, predict.getStatements());
+
+        return null;
+    }
+
+    private void apply(final SurrogateDefinition definition, final File input, final File output, final List<CallStatement> statements) {
+        log.info("Applying {} to {}.", definition.getName(), input);
+
+        final long startTime = System.currentTimeMillis();
+        manager.setTrainingStream(new FileBasedPropertiesStreamSupplier(input));
+        this.definition = definition;
+        this.config = SurrogateConfiguration.from(definition);
+
+        log.info("Training surrogate function.");
+        this.function = new SurrogateFactory(config, manager.getTrainingStream()).create();
+
+        final long endTime = System.currentTimeMillis();
+        log.info("Calculation of surrogate took " + (endTime - startTime) + " ms.");
+
+        statements.forEach(this::handleGoodnessOfFitCall);
+
+        saveTrainedSurrogateFunctionFunction(output);
+    }
+
+    private void handleGoodnessOfFitCall(final CallStatement statement) {
+        final Call call = statement.getCall();
+        final DefinedFunctionName function = (DefinedFunctionName)call.getFunction();
+        log.info("Handling call of {} ...", function.getDefinition().getName());
+
+        log.info("Creating GOF instance.");
+        final SurrogateInformationCalculator calculator = BeanFactory.create(function.getDefinition().getName(), SurrogateInformationCalculator.class);
+
+        log.info("Calculating parameter values.");
+        final List<Object> parameters = call.getParameters()
+                .stream()
+                .map(ConstantSwitch::findConstant)
+                .collect(Collectors.toList());
+
+        log.info("Configuring GOF instance.");
+        calculator.configure(this.function, config, parameters, manager.getTrainingStream());
+
+        log.info("Calling GOF instance.");
+        final long startTime = System.currentTimeMillis();
+        calculator.execute();
+        final long endTime = System.currentTimeMillis();
+
+        log.info("Calculation of {} took {} ms.", function.getDefinition().getName(), (endTime - startTime));
+    }
+
+    private File calculateFilename(String filename) {
+        final Matcher matcher = varPattern.matcher(filename);
+
+        final Set<String> vars = new HashSet<>();
+        while(matcher.find()) {
+            vars.add(filename.substring(matcher.start() + 2, matcher.end() - 1));
+        }
+
+        for(final String var : vars) {
+            String replacement = null;
+
+            Object value = symbolTable.get(var);
+            if(value instanceof Integer) {
+                replacement = value.toString();
+            } else if(value instanceof String) {
+                replacement = (String)value;
+            }
+
+            if(replacement == null) {
+                log.warn("Unable to replace ${{}}", var);
+                continue;
+            }
+
+            filename = filename.replace("${" + var + "}", replacement);
+        }
+
+        return new File(filename);
+    }
+
+    @Override
+    public Object caseForStatement(final ForStatement loop) {
+        final Stream<?> elements = (Stream<?>) doSwitch(loop.getRange());
+
+        elements.forEach(element -> {
+            final SymbolTable scopedTable = new SymbolTable(symbolTable);
+            scopedTable.put(loop.getName(), element);
+
+            final StatementExecutor executor = BeanFactory.create(StatementExecutor.class);
+            executor.setSymbolTable(scopedTable);
+            loop.getStatements()
+                .forEach(executor::evaluate);
+        });
+
+        return null;
+    }
+
+    @Override
+    public Object caseCounterRange(final CounterRange range) {
+        final boolean reverse = range.getStart() > range.getEnd();
+        final int min = Math.min(range.getStart(), range.getEnd());
+        final int max = Math.max(range.getStart(), range.getEnd());
+        final int count = max - min;
+
+        Stream<Integer> values = IntStream.rangeClosed(0, count)
+                .boxed();
+
+        if(reverse) {
+            values = values.map(i -> max - i);
+        } else {
+            values = values.map(i -> min + i);
+        }
+
+        return values;
+    }
+
+    @Override
+    public Object caseStringLiteralRange(final StringLiteralRange range) {
+        return range.getElements()
+                    .stream()
+                    .map(StringLiteral::getValue);
+    }
+
+    private void saveTrainedSurrogateFunctionFunction(final File outputFilename) {
+        log.info("Storing pre-calculated predictive functions to '{}' ...", outputFilename);
+        surrogateWriter.accept(config, outputFilename);
+        log.info("Storing file was successful.");
+    }
+}
diff --git a/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/internal/SurrogateFactory.java b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/internal/SurrogateFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..330c9da8cd2438e804449fac27c97f5070faeedf
--- /dev/null
+++ b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/internal/SurrogateFactory.java
@@ -0,0 +1,110 @@
+package de.evoal.surrogate.main.internal;
+
+import java.util.*;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import de.evoal.core.api.cdi.BeanFactory;
+import de.evoal.core.api.properties.stream.PropertiesStreamSupplier;
+import de.evoal.surrogate.api.configuration.FunctionCombinerConfiguration;
+import de.evoal.surrogate.api.configuration.PartialFunctionConfiguration;
+import de.evoal.surrogate.api.configuration.SurrogateConfiguration;
+import de.evoal.surrogate.api.function.FunctionCombiner;
+import de.evoal.surrogate.api.function.PartialSurrogateFunction;
+import de.evoal.surrogate.api.function.PartialSurrogateFunctionFactory;
+import de.evoal.surrogate.api.function.SurrogateFunction;
+import lombok.Getter;
+import lombok.NonNull;
+import lombok.extern.slf4j.Slf4j;
+
+import de.evoal.core.api.properties.PropertiesSpecification;
+
+/**
+ * Factory class for predictive functions.
+ */
+@Slf4j
+public final class SurrogateFactory {
+
+	/**
+	 * Name of the predictive file
+	 */
+	@Getter
+	private final SurrogateConfiguration config;
+
+	/**
+	 * Training points used
+	 */
+	private final PropertiesStreamSupplier factory;
+
+	public static SurrogateFunction create(final @NonNull SurrogateConfiguration config, final PropertiesStreamSupplier trainingPoints) {
+		final List<FunctionCombiner> functions =
+				config.getMappings()
+						  .stream()
+						  .map(layer -> createLayerFunction(layer, trainingPoints))
+						  .collect(Collectors.toList());
+
+		return new SurrogateFunction(functions);
+	}
+
+	private static FunctionCombiner createLayerFunction(final FunctionCombinerConfiguration config, final PropertiesStreamSupplier trainingPoints) {
+		log.info("Creating mapping function for level {}.", config.getName());
+
+		final List<PartialFunctionConfiguration> subConfiguration = config.getFunctions();
+
+		// map source values to properties
+		final PropertiesSpecification sourceSpecification =
+				createProperties(subConfiguration.stream()
+												 .flatMap(psf -> psf.getInputDimensions().stream()));
+
+		// map source values to properties
+		final PropertiesSpecification targetSpecification =
+				createProperties(subConfiguration.stream()
+												 .flatMap(psf -> psf.getOutputDimensions().stream()));
+
+		final List<PartialSurrogateFunction> subFunctions = createFunctions(subConfiguration, sourceSpecification, targetSpecification, trainingPoints);
+
+		return new FunctionCombiner(subFunctions, sourceSpecification, targetSpecification);
+	}
+
+	private static List<PartialSurrogateFunction> createFunctions(final List<PartialFunctionConfiguration> configurations, final PropertiesSpecification source, final PropertiesSpecification target, final PropertiesStreamSupplier trainingPoints) {
+		// create regression functions from configuration
+		final List<PartialSurrogateFunction> functions = new ArrayList<>(configurations.size());
+
+		for(final PartialFunctionConfiguration config : configurations) {
+			functions.add(create(config, source, target, trainingPoints));
+		}
+		
+		return functions;
+	}
+
+	public static PartialSurrogateFunction create(final PartialFunctionConfiguration config, final PropertiesSpecification source, final PropertiesSpecification target, final PropertiesStreamSupplier trainingPoints) {
+		log.info("Calculating mapping function '{}'.", config.getName());
+		final PropertiesSpecification functionTargetSpecification =
+				PropertiesSpecification.builder()
+									   .add(config.getOutputDimensions().stream())
+									   .build();
+
+		final PropertiesSpecification functionSourceSpecification =
+				PropertiesSpecification.builder()
+						.add(config.getInputDimensions().stream())
+						.build();
+
+		final PartialSurrogateFunctionFactory factory = BeanFactory.create(config.getName(), PartialSurrogateFunctionFactory.class);
+		return factory.create(config, source, functionSourceSpecification, functionTargetSpecification, trainingPoints);
+	}
+
+	private static PropertiesSpecification createProperties(final Stream<String> descriptors) {
+		return PropertiesSpecification.builder()
+									  .add(descriptors)
+									  .build();
+	}
+
+	public SurrogateFactory(final SurrogateConfiguration config, final PropertiesStreamSupplier factory) {
+		this.config = config;
+		this.factory = factory;
+	}
+
+	public SurrogateFunction create() {
+		return create(config, factory);
+	}
+}
diff --git a/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/internal/SymbolTable.java b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/internal/SymbolTable.java
new file mode 100644
index 0000000000000000000000000000000000000000..d6d4cb061236cded28a324831e10b770e27b497a
--- /dev/null
+++ b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/internal/SymbolTable.java
@@ -0,0 +1,29 @@
+package de.evoal.surrogate.main.internal;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class SymbolTable {
+    private final SymbolTable parentTable;
+    private Map<String, Object> bindings = new HashMap<>();
+
+    public SymbolTable(final SymbolTable symbolTable) {
+        this.parentTable = symbolTable;
+    }
+
+    public void put(final String name, final Object value) {
+        this.bindings.put(name, value);
+    }
+
+    public Object get(final String name) {
+        if(bindings.containsKey(name)) {
+            return bindings.get(name);
+        }
+
+        if(parentTable != null) {
+            return parentTable.get(name);
+        }
+
+        return null;
+    }
+}
diff --git a/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/jackson/ReflectiveDeserializer.java b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/jackson/ReflectiveDeserializer.java
new file mode 100644
index 0000000000000000000000000000000000000000..0659f9ccb3d3b7e022dbb2977beada82b639689f
--- /dev/null
+++ b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/jackson/ReflectiveDeserializer.java
@@ -0,0 +1,252 @@
+package de.evoal.surrogate.main.jackson;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.JsonToken;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
+import smile.math.matrix.Matrix;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class ReflectiveDeserializer extends StdDeserializer<Object> {
+    protected ReflectiveDeserializer() {
+        super(Object.class);
+    }
+
+    @Override
+    public Object deserialize(final JsonParser parser, final DeserializationContext context) throws IOException, JsonProcessingException {
+        return readObject(parser);
+    }
+
+    private Object readObject(final JsonParser parser) throws IOException, JsonProcessingException {
+        assertTokenTypeAndAdvance(parser, JsonToken.START_OBJECT);
+
+        final JsonToken nextValue = parser.nextValue();
+        assertFieldName(parser.getCurrentName(), "type");
+
+        Object value = null;
+        final String type = parser.getValueAsString();
+        switch (type) {
+            case "string":
+                value = getStringValue(parser);
+                break;
+
+            case "double":
+                value = getDoubleValue(parser);
+                break;
+
+            case "integer":
+                value = getIntegerValue(parser);
+                break;
+
+            case "array(double)":
+                value = getDoubleArrayValue(parser);
+                break;
+
+            case "array(array(double))":
+                value = getDoubleArrayArrayValue(parser);
+                break;
+
+            case "matrix":
+                value = getMatrixValue(parser);
+                break;
+
+            case "dict":
+                value = getDictValue(parser);
+                break;
+
+            case "array":
+                value = getArrayValue(parser);
+                break;
+
+            default:
+                System.err.println("Unsupported type: " + type);
+                throw new IllegalArgumentException();
+        }
+
+        while(!parser.hasToken(JsonToken.END_OBJECT)) {
+            parser.nextToken();
+        }
+
+        return value;
+    }
+
+    private Object getDictValue(final JsonParser parser) throws IOException {
+        final Map<String, Object> dict = new HashMap<>();
+
+        parser.nextValue();
+        assertTokenTypeAndAdvance(parser, JsonToken.START_OBJECT);
+
+        while(!JsonToken.END_OBJECT.equals(parser.getCurrentToken())) {
+            final String name = parser.getCurrentName();
+            parser.nextToken();
+            final Object value = readObject(parser);
+            parser.nextToken();
+
+            dict.put(name, value);
+        }
+
+        parser.nextToken();
+        return dict;
+    }
+
+    private List<Object> getArrayValue(final JsonParser parser) throws IOException {
+        final List<Object> result = new ArrayList<>();
+
+        parser.nextValue();
+        assertTokenTypeAndAdvance(parser, JsonToken.START_ARRAY);
+
+        while(!JsonToken.END_ARRAY.equals(parser.getCurrentToken())) {
+            final Object value = readObject(parser);
+            parser.nextToken();
+
+            result.add(value);
+        }
+
+        parser.nextToken();
+        return result;
+    }
+
+    private Object getDoubleArrayValue(final JsonParser parser) throws IOException {
+        parser.nextValue();
+        assertFieldName(parser.getCurrentName(), "size");
+        final int size = parser.getValueAsInt();
+
+        parser.nextValue();
+        assertFieldName(parser.getCurrentName(), "value");
+
+        parser.nextToken();
+
+        final double [] result = new double[size];
+        for(int i = 0; i < size; ++i) {
+            parser.nextValue();
+            result[i] = parser.getValueAsDouble();
+        }
+        assertArrayEnd(parser);
+
+        return result;
+    }
+
+    private Object getDoubleArrayArrayValue(final JsonParser parser) throws IOException {
+        parser.nextValue();
+        assertFieldName(parser.getCurrentName(), "size-1");
+        final int size1 = parser.getValueAsInt();
+
+        parser.nextValue();
+        assertFieldName(parser.getCurrentName(), "size-2");
+        final int size2 = parser.getValueAsInt();
+
+        parser.nextValue();
+        assertFieldName(parser.getCurrentName(), "value");
+
+        parser.nextToken();
+
+        final double [][] result = new double[size1][size2];
+        for(int i = 0; i < size1; ++i) {
+            for(int j = 0; j < size2; ++j) {
+                parser.nextValue();
+                result[i][j] = parser.getValueAsDouble();
+            }
+        }
+        assertArrayEnd(parser);
+
+        return result;
+    }
+
+    private Object getMatrixValue(final JsonParser parser) throws IOException {
+        parser.nextValue();
+        assertFieldName(parser.getCurrentName(), "nrows");
+        final int nrows = parser.getValueAsInt();
+
+        parser.nextValue();
+        assertFieldName(parser.getCurrentName(), "ncols");
+        final int ncols = parser.getValueAsInt();
+
+        parser.nextValue();
+        assertFieldName(parser.getCurrentName(), "value");
+
+        parser.nextToken();
+
+        final Matrix result = new Matrix(nrows, ncols);
+        for(int i = 0; i < nrows; ++i) {
+            for(int j = 0; j < ncols; ++j) {
+                parser.nextValue();
+                result.set(i, j, parser.getValueAsDouble());
+            }
+        }
+        assertArrayEnd(parser);
+
+        return result;
+    }
+
+    private void assertArrayStart(final JsonParser parser) throws IOException {
+        assertTokenTypeAndAdvance(parser, JsonToken.START_ARRAY);
+    }
+
+    private void assertArrayEnd(final JsonParser parser) throws IOException {
+        assertTokenTypeAndAdvance(parser, JsonToken.END_ARRAY);
+    }
+
+    private Object getStringValue(final JsonParser parser) throws IOException {
+        parser.nextValue();
+        assertFieldName(parser.getCurrentName(), "value");
+
+        return parser.getValueAsString();
+    }
+
+    private Object getDoubleValue(final JsonParser parser) throws IOException {
+        final JsonToken nextValue = parser.nextValue();
+        assertFieldName(parser.getCurrentName(), "value");
+
+        return parser.getValueAsDouble();
+    }
+
+    private Object getIntegerValue(final JsonParser parser) throws IOException {
+        final JsonToken nextValue = parser.nextValue();
+        assertFieldName(parser.getCurrentName(), "value");
+
+        return parser.getValueAsInt();
+    }
+
+    private void assertFieldName(final String actual, final String expected) {
+        if(!expected.equals(actual)) {
+            throw new IllegalStateException("Expected field name " + expected + " but got " + actual);
+        }
+    }
+
+    private String getStringAndAdvance(final JsonParser parser) throws IOException {
+        if(!JsonToken.VALUE_STRING.equals(parser.getCurrentToken())) {
+            throw new IllegalStateException("Expected token " + JsonToken.VALUE_STRING + " got " + parser.getCurrentToken());
+        }
+
+        final String value = parser.getText();
+
+        parser.nextToken();
+
+        return value;
+    }
+
+    private void assertFieldAndAdvance(final JsonParser parser, final String name) throws IOException {
+        if(!JsonToken.FIELD_NAME.equals(parser.getCurrentToken())) {
+            throw new IllegalStateException("Expected token " + JsonToken.FIELD_NAME + " got " + parser.getCurrentToken());
+        }
+
+        if(!name.equals(parser.getText())) {
+            throw new IllegalStateException("Expected field " + name + " got " + parser.getText());
+        }
+
+        parser.nextToken();
+    }
+
+    private void assertTokenTypeAndAdvance(final JsonParser parser, final JsonToken token) throws IOException {
+        if(!token.equals(parser.getCurrentToken())) {
+            throw new IllegalStateException("Expected token " + token + " got " + parser.getCurrentToken());
+        }
+        parser.nextToken();
+    }
+}
diff --git a/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/jackson/ReflectiveSerializer.java b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/jackson/ReflectiveSerializer.java
new file mode 100644
index 0000000000000000000000000000000000000000..b249e7efe69182147c5cc36bd762433973b7d827
--- /dev/null
+++ b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/jackson/ReflectiveSerializer.java
@@ -0,0 +1,130 @@
+package de.evoal.surrogate.main.jackson;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+import smile.math.matrix.Matrix;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+public class ReflectiveSerializer extends StdSerializer<Object> {
+    protected ReflectiveSerializer() {
+        super(Object.class);
+    }
+
+    @Override
+    public void serialize(final Object o, final JsonGenerator jsonGenerator, final SerializerProvider serializerProvider) throws IOException {
+        if(o instanceof Double) {
+            serializeDouble((Double) o, jsonGenerator);
+        } else if(o instanceof Integer) {
+            serializeInteger((Integer)o, jsonGenerator);
+        } else if(o instanceof String) {
+            serializeString((String)o, jsonGenerator);
+        } else if(o instanceof double [][]) {
+            serializeArray((double[][])o, jsonGenerator);
+        } else if(o instanceof double []) {
+            serializeArray((double[])o, jsonGenerator);
+        } else if(o instanceof Matrix) {
+            serializeArray((Matrix)o, jsonGenerator);
+        } else if(o instanceof List) {
+            serializeList((List<?>)o, jsonGenerator, serializerProvider);
+        }  else if(o instanceof Map) {
+            serializeMap((Map<String, ?>)o, jsonGenerator, serializerProvider);
+        }
+    }
+
+    private void serializeDouble(final Double o, final JsonGenerator jsonGenerator) throws IOException {
+        jsonGenerator.writeStartObject();
+        jsonGenerator.writeStringField("type", "double");
+        jsonGenerator.writeNumberField("value", o);
+        jsonGenerator.writeEndObject();
+    }
+
+    private void serializeInteger(final Integer o, final JsonGenerator jsonGenerator) throws IOException {
+        jsonGenerator.writeStartObject();
+        jsonGenerator.writeStringField("type", "integer");
+        jsonGenerator.writeNumberField("value", o);
+        jsonGenerator.writeEndObject();
+    }
+
+    private void serializeString(final String o, final JsonGenerator jsonGenerator) throws IOException {
+        jsonGenerator.writeStartObject();
+        jsonGenerator.writeStringField("type", "string");
+        jsonGenerator.writeStringField("value", o);
+        jsonGenerator.writeEndObject();
+    }
+
+    private void serializeArray(final double [] o, final JsonGenerator jsonGenerator) throws IOException {
+        jsonGenerator.writeStartObject();
+        jsonGenerator.writeStringField("type", "array(double)");
+        jsonGenerator.writeNumberField("size", o.length);
+        jsonGenerator.writeFieldName("value");
+        jsonGenerator.writeArray(o, 0, o.length);
+        jsonGenerator.writeEndObject();
+    }
+
+    private void serializeArray(final double [][] o, final JsonGenerator jsonGenerator) throws IOException {
+        if(o.length == 0) {
+            System.err.println("Here we are");
+        }
+
+        jsonGenerator.writeStartObject();
+        jsonGenerator.writeStringField("type", "array(array(double))");
+        jsonGenerator.writeNumberField("size-1", o.length);
+        jsonGenerator.writeNumberField("size-2", o.length == 0 ? 0 : o[0].length);
+        jsonGenerator.writeFieldName("value");
+        jsonGenerator.writeStartArray(o.length);
+        for(int i = 0; i < o.length; ++i) {
+            for(int j = 0; j < o[i].length; ++j) {
+                jsonGenerator.writeNumber(o[i][j]);
+            }
+        }
+        jsonGenerator.writeEndArray();
+        jsonGenerator.writeEndObject();
+    }
+
+    private void serializeArray(final Matrix o, final JsonGenerator jsonGenerator) throws IOException {
+        final int nrows = o.nrows();
+        final int ncols = o.ncols();
+
+        jsonGenerator.writeStartObject();
+        jsonGenerator.writeStringField("type", "matrix");
+
+        jsonGenerator.writeNumberField("nrows", nrows);
+        jsonGenerator.writeNumberField("ncols", ncols);
+        jsonGenerator.writeFieldName("value");
+        jsonGenerator.writeStartArray(nrows * ncols);
+        for(int i = 0; i < nrows; ++i) {
+            for(int j = 0; j < ncols; ++j) {
+                jsonGenerator.writeNumber(o.get(i, j));
+            }
+        }
+        jsonGenerator.writeEndArray();
+        jsonGenerator.writeEndObject();
+    }
+
+    private void serializeList(final List<?> list, final JsonGenerator generator, final SerializerProvider provider) throws IOException {
+        generator.writeStartArray();
+
+        boolean first = true;
+        for(final Object child : list) {
+            serialize(child, generator, provider);
+        }
+
+        generator.writeEndArray();
+    }
+
+    private void serializeMap(final Map<String, ?> map, final JsonGenerator generator, final SerializerProvider provider) throws IOException {
+        generator.writeStartObject();
+
+        boolean first = true;
+        for(final Map.Entry<String, ?> child : map.entrySet()) {
+            generator.writeFieldName(child.getKey());
+            serialize(child.getValue(), generator, provider);
+        }
+
+        generator.writeEndObject();
+    }
+}
diff --git a/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/jackson/package-info.java b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/jackson/package-info.java
new file mode 100644
index 0000000000000000000000000000000000000000..175cdda8003adff740178e683f732da19ac06cfa
--- /dev/null
+++ b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/jackson/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Classes that helps (de-)serializing a surrogate function to JSON using Jackson.
+ */
+package de.evoal.surrogate.main.jackson;
\ No newline at end of file
diff --git a/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/statistics/correlated/GenerationStatisticsWriter.java b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/statistics/correlated/GenerationStatisticsWriter.java
new file mode 100644
index 0000000000000000000000000000000000000000..1e5d6823724dee69a104b3935d6a5cd0cca72271
--- /dev/null
+++ b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/statistics/correlated/GenerationStatisticsWriter.java
@@ -0,0 +1,314 @@
+package de.evoal.surrogate.main.statistics.correlated;
+
+import de.evoal.core.api.statistics.*;
+import de.evoal.core.api.utils.LanguageHelper;
+import de.evoal.languages.model.instance.Instance;
+import de.evoal.core.api.board.BlackboardEntry;
+import de.evoal.core.api.cdi.ConfigurationValue;
+import de.evoal.core.api.ea.fitness.type.FitnessType;
+import de.evoal.core.api.ea.codec.CustomCodec;
+import de.evoal.core.api.properties.Properties;
+import de.evoal.core.api.properties.PropertiesSpecification;
+import de.evoal.surrogate.api.training.TrainingDataManager;
+import io.jenetics.Genotype;
+import io.jenetics.engine.EvolutionResult;
+import io.jenetics.util.ISeq;
+import javax.annotation.PostConstruct;
+import javax.enterprise.context.Dependent;
+import lombok.extern.slf4j.Slf4j;
+
+import org.apache.commons.math3.util.Pair;
+import smile.math.matrix.Matrix;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Provider;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * Small helper class for collecting and writing the generation-based statistics.
+ */
+@Slf4j
+@Named("correlated")
+@Dependent
+public class GenerationStatisticsWriter implements StatisticsWriter {
+    /**
+     * List of all existing fitness functions.
+     */
+    private List<Function<Properties, FitnessType>> functions;
+
+    /**
+     * List of all function names
+     */
+    @Inject @Named("function-names")
+    private List<String> functionNames;
+
+    /**
+     * Encoding for converting between ea and domain.
+     */
+    @Inject
+    private CustomCodec encoding;
+
+    private long startTime;
+
+    private EvolutionResult<?, FitnessType> generationWithBestIndividual;
+    private long endTime;
+
+    @Inject
+    private Provider<Function<Properties, FitnessType>> fitnessFactory;
+
+    @Inject @ConfigurationValue(entry = BlackboardEntry.EA_CONFIGURATION, access = "algorithm.fitness")
+    private Instance config;
+
+    @Inject
+    private TrainingDataManager manager;
+
+    @Inject @Named("source-properties-specification")
+    private PropertiesSpecification sourceSpec;
+
+    @Inject @Named("target-properties-specification")
+    private PropertiesSpecification targetSpec;
+    private List<Properties> sourceTrainingPoints;
+
+    /**
+     * Creates a new GenerationStatistics instance.
+     */
+
+    @Inject
+    private WriterStrategy strategy;
+
+    @PostConstruct
+    public void init() {
+        final String selectedFunctionName = LanguageHelper.lookup(config, "name");
+
+        startTime = System.currentTimeMillis();
+        // create fitness functions for comparison
+        this.functionNames.sort((a, b) -> {
+            if(selectedFunctionName.equals(a)) {
+                return Integer.MIN_VALUE;
+            } else if(selectedFunctionName.equals(b)) {
+                return Integer.MAX_VALUE;
+            } else {
+                return String.CASE_INSENSITIVE_ORDER.compare(a, b);
+            }
+        });
+        this.functions = functionNames.stream()
+                .map(name -> {
+                    setFitnessType(config, name);
+                    return fitnessFactory.get();
+                })
+                .collect(Collectors.toList());
+
+        // restore fitness function
+        setFitnessType(config, selectedFunctionName);
+    }
+
+    @Override
+    public StatisticsWriter init(Instance configuration) {
+        return this;
+    }
+
+    private Matrix calculateCovarianceMatrix(final Matrix data) {
+        final int dimensions = data.nrows();
+        final int dataSize = data.ncols();
+        final double [] means = data.rowMeans();
+
+        final Matrix covarianceMatrix = new Matrix(dimensions, dimensions);
+        for(int x = 0; x < dimensions; ++x) {
+            for(int y = 0; y < dimensions; ++y) {
+                double value = 0.0;
+                for(int t = 0; t < dataSize; ++t) {
+                    value += ((data.get(x, t) - means[x])*(data.get(y, t) - means[y]));
+                }
+                value = value / dataSize;
+                covarianceMatrix.set(x, y, value);
+            }
+        }
+
+        return covarianceMatrix;
+    }
+
+    private void calculateCovariance(final Properties candidate, final Object[] data, final int index) {
+        final int dimensions = sourceSpec.size();
+        final int trainingsSize = sourceTrainingPoints.size();
+        final int onTheFlySize = trainingsSize + 1;
+
+        final Matrix trainingsMatrix = new Matrix(dimensions, trainingsSize);
+        final Matrix onTheFlyMatrix = new Matrix(dimensions, onTheFlySize);
+
+        // calculate covariance matrix for trainings data
+        for(int t = 0; t < trainingsSize; t++) {
+            for(int d = 0; d < dimensions; ++d) {
+                final double value = sourceTrainingPoints
+                                            .get(t)
+                                            .get(d);
+                trainingsMatrix.set(d, t, value);
+                onTheFlyMatrix.set(d, t, value);
+            }
+        }
+
+        for(int d = 0; d < dimensions; ++d) {
+            onTheFlyMatrix.set(d, onTheFlySize - 1, candidate.get(d));
+        }
+
+        final Matrix trainingsCovarianceMatrix = calculateCovarianceMatrix(trainingsMatrix);
+
+        {
+            final Matrix onTheFlyCovarianceMatrix = calculateCovarianceMatrix(onTheFlyMatrix);
+            calculateDifference(new Matrix(trainingsCovarianceMatrix.toArray()), onTheFlyCovarianceMatrix, data, index);
+        }
+
+        {
+            final Matrix bestGenerationMatrix = createBestGenerationMatrix();
+            final Matrix bestGenerationCovariance = calculateCovarianceMatrix(bestGenerationMatrix);
+            calculateDifference(new Matrix(trainingsCovarianceMatrix.toArray()), bestGenerationCovariance, data, index +  dimensions * dimensions + 2);
+        }
+    }
+
+    private Matrix createBestGenerationMatrix() {
+        final ISeq<Genotype<?>> genotypes = (ISeq<Genotype<?>>)(Object)generationWithBestIndividual.genotypes();
+
+        final int dimensions = sourceSpec.size();
+        final int size = genotypes.size();
+
+        final Matrix result = new Matrix(dimensions, size);
+
+        for(int i = 0; i < size; ++i) {
+            final Genotype<?> genotype = genotypes.get(i);
+            final Properties individual = (Properties) encoding.decode(genotype);
+
+            final double [] data = individual.getValues();
+
+            for(int j = 0; j < data.length; ++j) {
+                result.set(i, j, data[j]);
+            }
+        }
+
+        return result;
+    }
+
+    private void calculateDifference(final Matrix matrix1, final Matrix matrix2, final Object [] data, final int start) {
+        final Matrix differenceMatrix = matrix1.sub(matrix2);
+        double sumOfAbs = 0.0;
+        double sumOfSquares = 0.0;
+
+        for(int x = 0; x < differenceMatrix.nrows(); ++x) {
+            for (int y = 0; y < differenceMatrix.ncols(); ++y) {
+                data[start + x * differenceMatrix.nrows() + y] = differenceMatrix.get(x,y);
+                sumOfAbs += Math.abs(differenceMatrix.get(x, y));
+                sumOfSquares += (Math.pow(differenceMatrix.get(x, y), 2));
+            }
+        }
+
+        data[start + differenceMatrix.nrows() * differenceMatrix.ncols()] = sumOfAbs;
+        data[start + differenceMatrix.nrows() * differenceMatrix.ncols() + 1] = sumOfSquares;
+    }
+
+    private Writer createWriter() throws WriterException {
+        final List<Column> columns = new ArrayList<>();
+
+        columns.add(new Column("generation", ColumnType.Integer));
+        columns.add(new Column("individual", ColumnType.String));
+        columns.add(new Column("age", ColumnType.Integer));
+
+        final int nmrOfFunctions = functionNames.size();
+        for (int i = 0; i < nmrOfFunctions; ++i) {
+            columns.add(new Column(functionNames.get(i), ColumnType.Double));
+        }
+
+        for (int x = 0; x < sourceSpec.size(); ++x) {
+            for (int y = 0; y < sourceSpec.size(); ++y) {
+                columns.add(new Column("ind. difference(" + x + "/" + y + ")", ColumnType.Double));
+            }
+        }
+        columns.add(new Column("sum(abs(ind. difference))", ColumnType.Double));
+        columns.add(new Column("sum(sqr(ind. difference))", ColumnType.Double));
+
+        for (int x = 0; x < sourceSpec.size(); ++x) {
+            for (int y = 0; y < sourceSpec.size(); ++y) {
+                columns.add(new Column("pop. difference(" + x + "/" + y + ")", ColumnType.Double));
+            }
+        }
+        columns.add(new Column("sum(abs(pop. difference))", ColumnType.Double));
+        columns.add(new Column("sum(sqr(pop. difference))", ColumnType.Double));
+
+        columns.add(new Column("time", ColumnType.Integer));
+
+        return strategy.create("best-individual-statistics", columns);
+    }
+
+    private Object[] dataOfBest() {
+        fetchTrainingData();
+
+        final Object [] data = new Object[3 + functionNames.size() + (int)Math.pow(sourceSpec.size(), 2) + 2 + (int)Math.pow(sourceSpec.size(), 2) + 2 + 1];
+
+        final Genotype<?> genotype = generationWithBestIndividual.bestPhenotype().genotype();
+        final Properties individual = (Properties) encoding.decode(genotype);
+
+        data[0] = generationWithBestIndividual.generation();
+        data[1] = Arrays.toString(individual.getValues());
+        data[2] = generationWithBestIndividual.bestPhenotype().age(generationWithBestIndividual.generation());
+
+        final Properties candidate = (Properties) encoding.decode(generationWithBestIndividual.bestPhenotype().genotype());
+
+        for(int i = 0; i < functions.size(); ++i) {
+            final FitnessType fitness = functions.get(i).apply(candidate);
+            data[3 + i] = fitness.getFitnessValues()[0];
+            throw new IllegalArgumentException("fix me");
+        }
+
+        calculateCovariance(candidate, data, 3 + functions.size());
+
+        data[data.length - 1] = endTime - startTime;
+
+        return data;
+    }
+
+    private void fetchTrainingData() {
+        final PropertiesSpecification spec = PropertiesSpecification.builder()
+                                                                    .add(sourceSpec)
+                                                                    .add(targetSpec)
+                                                                    .build();
+
+        sourceTrainingPoints = manager.getTrainingStream()
+                                      .apply(spec)
+                                      .collect(Collectors.toList());
+    }
+
+    /**
+     * Changes the fitness type entry in the given config object.
+     */
+    private static void setFitnessType(final Instance config, final String name) {
+        //config.put("name", name);
+        throw new IllegalStateException("We have to change the actual fitness type by looking up the correct definition.");
+    }
+
+    public void add(final EvolutionResult<?, FitnessType> evolutionResult) {
+        updateBestGeneration(evolutionResult);
+    }
+
+    private void updateBestGeneration(final EvolutionResult<?, FitnessType> generation) {
+        if(generationWithBestIndividual == null) {
+            generationWithBestIndividual = generation;
+        } else if(generationWithBestIndividual.bestFitness().compareTo(generation.bestFitness()) <= 0) {
+            generationWithBestIndividual = generation;
+        }
+    }
+
+    public void write() {
+        endTime = System.currentTimeMillis();
+        try {
+            final Writer writer = createWriter();
+
+            writer.addRecord(dataOfBest());
+
+            writer.close();
+        } catch (final WriterException e) {
+            log.error("Failed to write statistics:", e);
+        }
+    }
+}
diff --git a/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/statistics/surrogate/SurrogateStatistics.java b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/statistics/surrogate/SurrogateStatistics.java
new file mode 100644
index 0000000000000000000000000000000000000000..0bfd4e0288ce050cfa39bc87b54fc8d421f4e861
--- /dev/null
+++ b/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/main/statistics/surrogate/SurrogateStatistics.java
@@ -0,0 +1,109 @@
+package de.evoal.surrogate.main.statistics.surrogate;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.annotation.PostConstruct;
+import javax.enterprise.context.Dependent;
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import de.evoal.core.api.statistics.*;
+import de.evoal.core.api.ea.codec.CustomCodec;
+import de.evoal.core.api.ea.fitness.type.FitnessType;
+import de.evoal.core.api.properties.Properties;
+import de.evoal.core.api.properties.PropertiesSpecification;
+import de.evoal.languages.model.instance.Instance;
+import de.evoal.surrogate.api.function.SurrogateFunction;
+import io.jenetics.Genotype;
+import io.jenetics.Phenotype;
+import io.jenetics.engine.EvolutionResult;
+import io.jenetics.util.ISeq;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * Small helper class for collecting and writing the generation-based statistics.
+ */
+@Slf4j
+@Named("prediction-per-individual")
+@Dependent
+public class SurrogateStatistics implements StatisticsWriter {
+    /**
+     * The predictive function used.
+     */
+    @Inject
+    protected SurrogateFunction predictive;
+
+    /**
+     * Encoding for converting between ea and domain.
+     */
+    @Inject
+    private CustomCodec encoding;
+
+    @Inject @Named("target-properties-specification")
+    private PropertiesSpecification targetSpecification;
+
+    @Inject
+    private WriterStrategy strategy;
+
+    private Writer writer;
+
+    @PostConstruct
+    @SneakyThrows(WriterException.class)
+    private void init() {
+        createWriter();
+    }
+
+    @Override
+    public StatisticsWriter init(Instance configuration) {
+        return this;
+    }
+
+    private void createWriter() throws WriterException {
+        final List<Column> columns = new LinkedList<>();
+
+        columns.add(new Column("generation", ColumnType.Integer));
+        columns.add(new Column("index", ColumnType.Integer));
+
+        for(int i = 0; i < targetSpecification.size(); ++i) {
+            columns.add(new Column(targetSpecification.getProperties().get(i).name(), ColumnType.Double));
+        }
+
+        writer = strategy.create("prediction-by-individual", columns);
+    }
+
+    private Object[] dataOfPhenotype(final int index, final long generation, Phenotype<?, FitnessType> phenotype) {
+        final Object [] data = new Object[2 + targetSpecification.size()];
+
+        data[0] = generation;
+        data[1] = index;
+
+        final Genotype<?> genotype = phenotype.genotype();
+        final Properties individual = (Properties) encoding.decode(genotype);
+        final Properties predicted = predictive.apply(individual);
+
+        for(int i = 0; i < predicted.size(); ++i) {
+            data[2 + i] = predicted.getValues()[i];
+        }
+
+        return data;
+    }
+
+    @SneakyThrows(WriterException.class)
+    public void add(final EvolutionResult<?, FitnessType> evolutionResult) {
+        final ISeq<Phenotype<?, FitnessType>> population = (ISeq<Phenotype<?, FitnessType>>)(Object)evolutionResult.population();
+
+        for(int i = 0; i < population.size(); ++i) {
+            writer.addRecord(dataOfPhenotype(i, evolutionResult.generation(), population.get(i)));
+        }
+    }
+
+    public void write() {
+        try {
+            strategy.close(writer);
+        } catch (final WriterException e) {
+            log.error("Failed to write statistics:", e);
+        }
+    }
+}
diff --git a/src/core/de.evoal.surrogate.api/src/main/java/module-info.java b/src/core/de.evoal.surrogate.api/src/main/java/module-info.java
new file mode 100644
index 0000000000000000000000000000000000000000..87b54c6f417d3ddb87c6427eaab8fac2e8fbd6ee
--- /dev/null
+++ b/src/core/de.evoal.surrogate.api/src/main/java/module-info.java
@@ -0,0 +1,46 @@
+module de.evoal.surrogate.api {
+    requires jakarta.inject.api;
+    requires jakarta.enterprise.cdi.api;
+
+    requires java.annotation;
+
+    requires lombok;
+
+    requires org.slf4j;
+
+    requires org.eclipse.emf.ecore;
+    requires org.eclipse.emf.common;
+    requires guice;
+    requires org.eclipse.xtext;
+    requires com.fasterxml.jackson.databind;
+    requires smile.math;
+    requires commons.math3;
+    requires io.jenetics.base;
+
+
+    requires de.evoal.core.api;
+    requires de.evoal.languages.model.ddl;
+    requires de.evoal.languages.model.dl;
+    requires de.evoal.languages.model.el;
+    requires de.evoal.languages.model.mll;
+    requires de.evoal.languages.model.ddl.dsl;
+    requires de.evoal.languages.model.dl.dsl;
+    requires de.evoal.languages.model.el.dsl;
+    requires de.evoal.languages.model.mll.dsl;
+    requires de.evoal.languages.model.instance;
+
+    exports de.evoal.surrogate.api;
+    exports de.evoal.surrogate.api.function;
+    exports de.evoal.surrogate.api.configuration;
+
+    // open packages for CDI
+    opens de.evoal.surrogate.api.training to weld.core.impl;
+    opens de.evoal.surrogate.main to weld.core.impl;
+    opens de.evoal.surrogate.main.cdi to weld.core.impl;
+    opens de.evoal.surrogate.main.internal to weld.core.impl;
+    opens de.evoal.surrogate.main.jackson to weld.core.impl;
+    opens de.evoal.surrogate.main.gof.cross to weld.core.impl;
+    opens de.evoal.surrogate.main.gof.rsquare to weld.core.impl;
+    opens de.evoal.surrogate.main.statistics.correlated to weld.core.impl;
+    opens de.evoal.surrogate.main.statistics.surrogate to weld.core.impl;
+}
\ No newline at end of file
diff --git a/src/core/de.evoal.surrogate.api/src/main/resources/META-INF/MANIFEST.MF b/src/core/de.evoal.surrogate.api/src/main/resources/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000000000000000000000000000000000..9d885be534121a9f146924f4832955dfe2ee2d4b
--- /dev/null
+++ b/src/core/de.evoal.surrogate.api/src/main/resources/META-INF/MANIFEST.MF
@@ -0,0 +1 @@
+Manifest-Version: 1.0
diff --git a/src/core/de.evoal.surrogate.api/src/main/resources/META-INF/beans.xml b/src/core/de.evoal.surrogate.api/src/main/resources/META-INF/beans.xml
new file mode 100644
index 0000000000000000000000000000000000000000..848dca3b29cc3f1f9879d2c86d586612e5d8b3e7
--- /dev/null
+++ b/src/core/de.evoal.surrogate.api/src/main/resources/META-INF/beans.xml
@@ -0,0 +1,6 @@
+<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd"
+       bean-discovery-mode="annotated"
+       version="2.0">
+</beans>
\ No newline at end of file
diff --git a/src/core/de.evoal.surrogate.simple/pom.xml b/src/core/de.evoal.surrogate.simple/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..578b14b1c7df714bd63d828a41c871061c37f5ba
--- /dev/null
+++ b/src/core/de.evoal.surrogate.simple/pom.xml
@@ -0,0 +1,72 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+
+	<parent>
+		<groupId>de.evoal.core</groupId>
+		<artifactId>releng.parent</artifactId>
+		<version>0.9.0-SNAPSHOT</version>
+
+		<relativePath>../de.evoal.core.releng.parent</relativePath>
+	</parent>
+
+	<artifactId>surrogate.simple</artifactId>
+	<name>EvoAl - Surrogate - Simple</name>
+
+	<dependencies>
+		<dependency>
+			<groupId>${project.groupId}</groupId>
+			<artifactId>core.api</artifactId>
+			<scope>provided</scope>
+		</dependency>
+
+		<dependency>
+			<groupId>${project.groupId}</groupId>
+			<artifactId>surrogate.api</artifactId>
+			<version>${project.version}</version>
+			<scope>provided</scope>
+		</dependency>
+
+		<dependency>
+			<groupId>org.apache.commons</groupId>
+			<artifactId>commons-math3</artifactId>
+			<version>3.6.1</version>
+		</dependency>
+	</dependencies>
+
+	<build>
+		<plugins>
+			<plugin>
+				<artifactId>maven-dependency-plugin</artifactId>
+				<executions>
+					<execution>
+						<phase>package</phase>
+						<goals>
+							<goal>copy-dependencies</goal>
+						</goals>
+						<configuration>
+							<outputDirectory>${project.build.directory}/${project.artifactId}-dependencies</outputDirectory>
+							<includeScope>runtime</includeScope>
+							<excludeScope>provided</excludeScope>
+							<excludeTransitive>true</excludeTransitive>
+						</configuration>
+					</execution>
+				</executions>
+			</plugin>
+
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-jar-plugin</artifactId>
+				<configuration>
+					<archive>
+						<manifest>
+							<addClasspath>true</addClasspath>
+							<classpathPrefix>${project.artifactId}-dependencies/</classpathPrefix>
+						</manifest>
+					</archive>
+				</configuration>
+			</plugin>
+		</plugins>
+	</build>
+</project>
diff --git a/src/core/de.evoal.surrogate.simple/src/main/java/de/evoal/surrogate/simple/identity/IdentityFunction.java b/src/core/de.evoal.surrogate.simple/src/main/java/de/evoal/surrogate/simple/identity/IdentityFunction.java
new file mode 100644
index 0000000000000000000000000000000000000000..b04cccc2407f8fcf5a7a3e9084020f91325baf2d
--- /dev/null
+++ b/src/core/de.evoal.surrogate.simple/src/main/java/de/evoal/surrogate/simple/identity/IdentityFunction.java
@@ -0,0 +1,29 @@
+package de.evoal.surrogate.simple.identity;
+
+import java.util.Collections;
+
+import de.evoal.core.api.properties.Properties;
+import de.evoal.core.api.properties.PropertiesSpecification;
+import de.evoal.core.api.properties.PropertySpecification;
+import de.evoal.surrogate.api.configuration.PartialFunctionConfiguration;
+import de.evoal.surrogate.api.function.AbstractPartialSurrogateFunction;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class IdentityFunction extends AbstractPartialSurrogateFunction {
+
+	private final int propertyIndex;
+
+	public IdentityFunction(final PartialFunctionConfiguration configuration, final PropertiesSpecification input, final PropertiesSpecification actualInput, final PropertiesSpecification output) {
+		super(configuration, Collections.emptyList(), input, output);
+
+		log.info("Using identity mapping from {} to {}.", input, output);
+
+		final PropertySpecification inputProperty = input.getProperties().get(0);
+		propertyIndex = actualInput.indexOf(inputProperty);
+	}
+
+	public double [] apply(final Properties input) {
+		return new double[] {input.get(propertyIndex)};
+	}
+}
diff --git a/src/core/de.evoal.surrogate.simple/src/main/java/de/evoal/surrogate/simple/identity/IdentityFunctionFactory.java b/src/core/de.evoal.surrogate.simple/src/main/java/de/evoal/surrogate/simple/identity/IdentityFunctionFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..7fa982894bb28aef6c61e45db3f80902c156204b
--- /dev/null
+++ b/src/core/de.evoal.surrogate.simple/src/main/java/de/evoal/surrogate/simple/identity/IdentityFunctionFactory.java
@@ -0,0 +1,27 @@
+package de.evoal.surrogate.simple.identity;
+
+import java.util.List;
+
+import de.evoal.core.api.properties.PropertiesSpecification;
+import de.evoal.core.api.properties.stream.PropertiesPairStreamSupplier;
+import de.evoal.surrogate.api.configuration.Parameter;
+import de.evoal.surrogate.api.configuration.PartialFunctionConfiguration;
+import de.evoal.surrogate.api.function.AbstractPartialSurrogateFunctionFactory;
+import de.evoal.surrogate.api.function.PartialSurrogateFunction;
+
+import javax.enterprise.context.Dependent;
+import javax.inject.Named;
+
+@Dependent
+@Named("identity")
+public final class IdentityFunctionFactory extends AbstractPartialSurrogateFunctionFactory {
+	@Override
+	protected PartialSurrogateFunction calculateRegression(final PartialFunctionConfiguration configuration, final List<Parameter> parameters, final PropertiesSpecification actualInput, final PropertiesSpecification requiredInput, final PropertiesSpecification producedOutput, final PropertiesPairStreamSupplier provider) {
+		return new IdentityFunction(configuration, requiredInput, actualInput, producedOutput);
+	}
+
+	@Override
+	protected PartialSurrogateFunction restoreRegression(final PartialFunctionConfiguration configuration, final PropertiesSpecification actualInput, final PropertiesSpecification requiredInput, final PropertiesSpecification producedOutput) {
+		return new IdentityFunction(configuration, requiredInput, actualInput, producedOutput);
+	}
+}
diff --git a/src/core/de.evoal.surrogate.simple/src/main/java/de/evoal/surrogate/simple/linear/LinearFunction.java b/src/core/de.evoal.surrogate.simple/src/main/java/de/evoal/surrogate/simple/linear/LinearFunction.java
new file mode 100644
index 0000000000000000000000000000000000000000..0db00afcc0587bf3090a077f030e02dd25557f56
--- /dev/null
+++ b/src/core/de.evoal.surrogate.simple/src/main/java/de/evoal/surrogate/simple/linear/LinearFunction.java
@@ -0,0 +1,86 @@
+package de.evoal.surrogate.simple.linear;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.function.Function;
+
+import de.evoal.core.api.properties.Properties;
+import de.evoal.surrogate.api.configuration.Parameter;
+import de.evoal.surrogate.api.configuration.PartialFunctionConfiguration;
+import de.evoal.surrogate.api.function.AbstractPartialSurrogateFunction;
+
+import de.evoal.core.api.properties.PropertiesSpecification;
+import de.evoal.core.api.properties.PropertySpecification;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.math3.stat.regression.SimpleRegression;
+
+@Slf4j
+public class LinearFunction extends AbstractPartialSurrogateFunction {
+	/**
+	 * Name of the intercept parameter.
+	 */
+	private static final String INTERCEPT_PARAMETER_NAME = "intercept";
+
+	/**
+	 * Name of the r square parameter.
+	 */
+	private static final String R_SQUARE_PARAMETER_NAME = "r²";
+
+	/**
+	 * Name of the slope parameter.
+	 */
+	private static final String SLOPE_PARAMETER_NAME = "slope";
+
+	/**
+	 * Turns an Apache simple regression into a parameter set.
+	 */
+	public static List<Parameter> toParameters(final SimpleRegression regression) {
+		final List<Parameter> result = new LinkedList<>();
+		
+		addParameter(INTERCEPT_PARAMETER_NAME, regression.getIntercept(), result);
+		addParameter(SLOPE_PARAMETER_NAME, regression.getSlope(), result);
+		addParameter(R_SQUARE_PARAMETER_NAME, regression.getRSquare(), result);
+
+		return result;
+	}
+
+	/**
+	 * Actual function for prediction.
+	 */
+	private final Function<Properties, Double> regression;
+
+	public LinearFunction(final PartialFunctionConfiguration configuration, final List<Parameter> functionParameters, final PropertiesSpecification input, final PropertiesSpecification actualInput, final PropertiesSpecification output) {
+		super(configuration, functionParameters, input, output);
+		
+		final double slope = getSlope();
+		final double intercept = getIntercept();
+
+		log.info("Using linear regression f(x) = {} * x + {}.", slope, intercept);
+
+
+		final PropertySpecification inputProperty = input.getProperties().get(0);
+		final int propertyIndex = actualInput.indexOf(inputProperty);
+		
+		this.regression = vector -> intercept + slope * vector.get(propertyIndex);
+	}
+
+	public double [] apply(final Properties input) {
+		return new double [] {regression.apply(input)};
+	}
+
+	private double getIntercept() {
+		return (double)getParameters().stream()
+				 .filter(p -> INTERCEPT_PARAMETER_NAME.equals(p.getName()))
+				 .findFirst()
+				 .get()
+				 .getValue();
+	}
+
+	private double getSlope() {
+		return (double)getParameters().stream()
+				 .filter(p -> SLOPE_PARAMETER_NAME.equals(p.getName()))
+				 .findFirst()
+				 .get()
+				 .getValue();
+	}
+}
diff --git a/src/core/de.evoal.surrogate.simple/src/main/java/de/evoal/surrogate/simple/linear/LinearFunctionFactory.java b/src/core/de.evoal.surrogate.simple/src/main/java/de/evoal/surrogate/simple/linear/LinearFunctionFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..8e961f5b4023d26726851af25ff95fc745435c24
--- /dev/null
+++ b/src/core/de.evoal.surrogate.simple/src/main/java/de/evoal/surrogate/simple/linear/LinearFunctionFactory.java
@@ -0,0 +1,45 @@
+package de.evoal.surrogate.simple.linear;
+
+
+import de.evoal.core.api.properties.stream.PropertiesPairStreamSupplier;
+import de.evoal.surrogate.api.configuration.Parameter;
+import de.evoal.surrogate.api.configuration.PartialFunctionConfiguration;
+import de.evoal.surrogate.api.function.AbstractPartialSurrogateFunctionFactory;
+import de.evoal.surrogate.api.function.PartialSurrogateFunction;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.math3.stat.regression.SimpleRegression;
+
+import de.evoal.core.api.properties.PropertiesSpecification;
+
+import javax.enterprise.context.Dependent;
+import javax.inject.Named;
+import java.util.List;
+
+@Dependent
+@Named("linear-regression")
+@Slf4j
+public class LinearFunctionFactory extends AbstractPartialSurrogateFunctionFactory {
+
+	@Override
+	public PartialSurrogateFunction calculateRegression(final PartialFunctionConfiguration configuration, final List<Parameter> parameters, final PropertiesSpecification actualInput, final PropertiesSpecification requiredInput, final PropertiesSpecification producedOutput, final PropertiesPairStreamSupplier provider) {
+		log.info("Calculate linear mapping from {} to {}.", requiredInput, producedOutput);
+
+		assert requiredInput.getProperties().size() == 1;
+		assert producedOutput.getProperties().size() == 1;
+
+		final SimpleRegression regression = new SimpleRegression(true);
+
+		provider.get()
+				.forEach(coordinate -> {
+					log.info("Mapping - ({}) to ({}).", coordinate.getFirst(), coordinate.getSecond());
+					regression.addData(coordinate.getFirst().get(0), coordinate.getSecond().get(0));
+				});
+
+		return new LinearFunction(configuration, LinearFunction.toParameters(regression), requiredInput, actualInput, producedOutput);
+	}
+
+	@Override
+	protected PartialSurrogateFunction restoreRegression(final PartialFunctionConfiguration configuration, final PropertiesSpecification actualInput, final PropertiesSpecification requiredInput, final PropertiesSpecification producedOutput) {
+		return new LinearFunction(configuration, configuration.getState(), requiredInput, actualInput, producedOutput);
+	}
+}
diff --git a/src/core/de.evoal.surrogate.simple/src/main/java/de/evoal/surrogate/simple/quadratic/SimpleQuadraticFunction.java b/src/core/de.evoal.surrogate.simple/src/main/java/de/evoal/surrogate/simple/quadratic/SimpleQuadraticFunction.java
new file mode 100644
index 0000000000000000000000000000000000000000..455e4598398b28b05d56dfed8c074c8236769d96
--- /dev/null
+++ b/src/core/de.evoal.surrogate.simple/src/main/java/de/evoal/surrogate/simple/quadratic/SimpleQuadraticFunction.java
@@ -0,0 +1,85 @@
+package de.evoal.surrogate.simple.quadratic;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.function.Function;
+
+import de.evoal.surrogate.api.configuration.Parameter;
+import de.evoal.surrogate.api.configuration.PartialFunctionConfiguration;
+import de.evoal.surrogate.api.function.AbstractPartialSurrogateFunction;
+import de.evoal.core.api.properties.Properties;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.math3.stat.regression.SimpleRegression;
+
+import de.evoal.core.api.properties.PropertiesSpecification;
+import de.evoal.core.api.properties.PropertySpecification;
+
+@Slf4j
+public class SimpleQuadraticFunction extends AbstractPartialSurrogateFunction {
+	/**
+	 * Name of the intercept parameter.
+	 */
+	private static final String INTERCEPT_PARAMETER_NAME = "intercept";
+
+	/**
+	 * Name of the r square parameter.
+	 */
+	private static final String R_SQUARE_PARAMETER_NAME = "r²";
+
+	/**
+	 * Name of the slope parameter.
+	 */
+	private static final String SLOPE_PARAMETER_NAME = "slope";
+
+	/**
+	 * Turns an Apache simple regression into a parameter set.
+	 */
+	public static List<Parameter> toParameters(final SimpleRegression regression) {
+		final List<Parameter> result = new LinkedList<>();
+		
+		addParameter(INTERCEPT_PARAMETER_NAME, regression.getIntercept(), result);
+		addParameter(SLOPE_PARAMETER_NAME, regression.getSlope(), result);
+		addParameter(R_SQUARE_PARAMETER_NAME, regression.getRSquare(), result);
+
+		return result;
+	}
+
+	/**
+	 * Actual function for prediction.
+	 */
+	private final Function<Properties, Double> regression;
+
+	public SimpleQuadraticFunction(final PartialFunctionConfiguration configuration, final List<Parameter> functionParameters, final PropertiesSpecification input, final PropertiesSpecification actualInput, final PropertiesSpecification output) {
+		super(configuration, functionParameters, input, output);
+		
+		final double slope = getSlope();
+		final double intercept = getIntercept();
+
+		log.info("Using quadratic regression f(x) = {} * x^2 + {}.", slope, intercept);
+
+		final PropertySpecification inputProperty = input.getProperties().get(0);
+		final int propertyIndex = actualInput.indexOf(inputProperty);
+		
+		this.regression = vector -> intercept + slope * vector.get(propertyIndex);
+	}
+
+	public double [] apply(final Properties input) {
+		return new double [] {regression.apply(input)};
+	}
+
+	private double getIntercept() {
+		return (double)getParameters().stream()
+				 .filter(p -> INTERCEPT_PARAMETER_NAME.equals(p.getName()))
+				 .findFirst()
+				 .get()
+				 .getValue();
+	}
+
+	private double getSlope() {
+		return (double)getParameters().stream()
+				 .filter(p -> SLOPE_PARAMETER_NAME.equals(p.getName()))
+				 .findFirst()
+				 .get()
+				 .getValue();
+	}
+}
diff --git a/src/core/de.evoal.surrogate.simple/src/main/java/de/evoal/surrogate/simple/quadratic/SimpleQuadraticFunctionFactory.java b/src/core/de.evoal.surrogate.simple/src/main/java/de/evoal/surrogate/simple/quadratic/SimpleQuadraticFunctionFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..63e673d0b05e98b4964bd0cef592293fa570dbd7
--- /dev/null
+++ b/src/core/de.evoal.surrogate.simple/src/main/java/de/evoal/surrogate/simple/quadratic/SimpleQuadraticFunctionFactory.java
@@ -0,0 +1,46 @@
+package de.evoal.surrogate.simple.quadratic;
+
+import java.util.List;
+
+import de.evoal.core.api.properties.stream.PropertiesPairStreamSupplier;
+import de.evoal.surrogate.api.configuration.Parameter;
+import de.evoal.surrogate.api.configuration.PartialFunctionConfiguration;
+import de.evoal.surrogate.api.function.AbstractPartialSurrogateFunctionFactory;
+import de.evoal.surrogate.api.function.PartialSurrogateFunction;
+import de.evoal.surrogate.simple.linear.LinearFunction;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.math3.stat.regression.SimpleRegression;
+
+import de.evoal.core.api.properties.PropertiesSpecification;
+
+import javax.enterprise.context.Dependent;
+import javax.inject.Named;
+
+@Dependent
+@Named("simple-quadratic-regression")
+@Slf4j
+public final class SimpleQuadraticFunctionFactory extends AbstractPartialSurrogateFunctionFactory {
+
+	@Override
+	public PartialSurrogateFunction calculateRegression(final PartialFunctionConfiguration configuration, final List<Parameter> parameters, final PropertiesSpecification actualInput, final PropertiesSpecification requiredInput, final PropertiesSpecification producedOutput, final PropertiesPairStreamSupplier provider) {
+		log.info("Calculate linear mapping from {} to {}.", requiredInput, producedOutput);
+
+		assert requiredInput.getProperties().size() == 1;
+		assert producedOutput.getProperties().size() == 1;
+
+		final SimpleRegression regression = new SimpleRegression(true);
+
+		provider.get()
+				.forEach(coordinate -> {
+					log.info("Mapping - ({}) to ({}).", coordinate.getFirst(), coordinate.getSecond());
+					regression.addData(Math.pow(coordinate.getFirst().get(0), 2), coordinate.getSecond().get(0));
+				});
+
+		return new SimpleQuadraticFunction(configuration, LinearFunction.toParameters(regression), requiredInput, actualInput, producedOutput);
+	}
+
+	@Override
+	protected PartialSurrogateFunction restoreRegression(final PartialFunctionConfiguration configuration, final PropertiesSpecification actualInput, final PropertiesSpecification requiredInput, final PropertiesSpecification producedOutput) {
+		return new SimpleQuadraticFunction(configuration, configuration.getState(), requiredInput, actualInput, producedOutput);
+	}
+}
diff --git a/src/core/de.evoal.surrogate.simple/src/main/java/module-info.java b/src/core/de.evoal.surrogate.simple/src/main/java/module-info.java
index 6b1b1700a4b16236c31bcf6ae4eba99c53c37bb5..687edd5606914791fc8a1505ed37ba44cca7b01c 100644
--- a/src/core/de.evoal.surrogate.simple/src/main/java/module-info.java
+++ b/src/core/de.evoal.surrogate.simple/src/main/java/module-info.java
@@ -1,2 +1,9 @@
-module $MODULE_NAME$ {
+module de.evoal.surrogate.simple {
+    requires commons.math3;
+    requires jakarta.enterprise.cdi.api;
+    requires lombok;
+    requires org.slf4j;
+
+    requires de.evoal.core.api;
+    requires de.evoal.surrogate.api;
 }
\ No newline at end of file
diff --git a/src/core/de.evoal.surrogate.svr/pom.xml b/src/core/de.evoal.surrogate.svr/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..223ec3187e17099b33c2aba693f9f5425620a349
--- /dev/null
+++ b/src/core/de.evoal.surrogate.svr/pom.xml
@@ -0,0 +1,72 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+
+	<parent>
+		<groupId>de.evoal.core</groupId>
+		<artifactId>releng.parent</artifactId>
+		<version>0.9.0-SNAPSHOT</version>
+
+		<relativePath>../de.evoal.core.releng.parent</relativePath>
+	</parent>
+
+	<artifactId>surrogate.svr</artifactId>
+	<name>EvoAl - Surrogate - SVR</name>
+
+	<dependencies>
+		<dependency>
+			<groupId>${project.groupId}</groupId>
+			<artifactId>core.api</artifactId>
+			<scope>provided</scope>
+		</dependency>
+
+		<dependency>
+			<groupId>${project.groupId}</groupId>
+			<artifactId>surrogate.api</artifactId>
+			<version>${project.version}</version>
+			<scope>provided</scope>
+		</dependency>
+
+		<dependency>
+			<groupId>com.github.haifengl</groupId>
+			<artifactId>smile-core</artifactId>
+			<version>${smile.version}</version>
+		</dependency>
+	</dependencies>
+
+	<build>
+		<plugins>
+			<plugin>
+				<artifactId>maven-dependency-plugin</artifactId>
+				<executions>
+					<execution>
+						<phase>package</phase>
+						<goals>
+							<goal>copy-dependencies</goal>
+						</goals>
+						<configuration>
+							<outputDirectory>${project.build.directory}/${project.artifactId}-dependencies</outputDirectory>
+							<includeScope>runtime</includeScope>
+							<excludeScope>provided</excludeScope>
+							<excludeTransitive>true</excludeTransitive>
+						</configuration>
+					</execution>
+				</executions>
+			</plugin>
+
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-jar-plugin</artifactId>
+				<configuration>
+					<archive>
+						<manifest>
+							<addClasspath>true</addClasspath>
+							<classpathPrefix>${project.artifactId}-dependencies/</classpathPrefix>
+						</manifest>
+					</archive>
+				</configuration>
+			</plugin>
+		</plugins>
+	</build>
+</project>
diff --git a/src/core/de.evoal.surrogate.svr/src/main/java/de/evoal/surrogate/svr/GaussianKernelSVRFunctionFactory.java b/src/core/de.evoal.surrogate.svr/src/main/java/de/evoal/surrogate/svr/GaussianKernelSVRFunctionFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..b58d9b6e23d2cf0e4cd990b68308f78d3fa36dd4
--- /dev/null
+++ b/src/core/de.evoal.surrogate.svr/src/main/java/de/evoal/surrogate/svr/GaussianKernelSVRFunctionFactory.java
@@ -0,0 +1,46 @@
+package de.evoal.surrogate.svr;
+
+import de.evoal.core.api.properties.PropertiesSpecification;
+import de.evoal.core.api.properties.stream.PropertiesPairStreamSupplier;
+import de.evoal.core.api.utils.Requirements;
+import de.evoal.surrogate.api.configuration.Parameter;
+import de.evoal.surrogate.api.configuration.PartialFunctionConfiguration;
+import de.evoal.surrogate.api.function.AbstractPartialSurrogateFunctionFactory;
+import de.evoal.surrogate.api.function.PartialSurrogateFunction;
+import lombok.extern.slf4j.Slf4j;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import smile.math.kernel.MercerKernel;
+import smile.regression.KernelMachine;
+import smile.regression.SVR;
+
+import javax.enterprise.context.Dependent;
+import javax.inject.Named;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@Dependent
+@Named("gaussian-svr")
+@Slf4j
+public class GaussianKernelSVRFunctionFactory extends KernelBasedSVRFunctionFactory {
+	public GaussianKernelSVRFunctionFactory() {
+		super(KernelHelper::toGaussianKernel);
+	}
+
+	@Override
+	protected PartialSurrogateFunction restoreRegression(final PartialFunctionConfiguration configuration, final PropertiesSpecification actualInput, final PropertiesSpecification requiredInput, final PropertiesSpecification producedOutput) {
+		final KernelMachine<double []> regression = KernelHelper.fromParameters(configuration.getParameters(), configuration.getState());
+
+		final double margin = configuration.getParameters()
+										   .stream()
+										   .filter(p -> KernelHelper.SOFT_MARGIN_PARAMETER.equals(p.getName()))
+										   .map(Parameter::getValue)
+										   .map(Double.class::cast)
+										   .findFirst()
+										   .orElse(0.1);
+
+		return new KernelBasedSVRFunction(configuration, regression, requiredInput, actualInput, producedOutput, margin);
+	}
+}
diff --git a/src/core/de.evoal.surrogate.svr/src/main/java/de/evoal/surrogate/svr/KernelBasedSVRFunction.java b/src/core/de.evoal.surrogate.svr/src/main/java/de/evoal/surrogate/svr/KernelBasedSVRFunction.java
new file mode 100644
index 0000000000000000000000000000000000000000..877a5391a63c4a2b30023c2a9016abf0e7fcaff8
--- /dev/null
+++ b/src/core/de.evoal.surrogate.svr/src/main/java/de/evoal/surrogate/svr/KernelBasedSVRFunction.java
@@ -0,0 +1,51 @@
+package de.evoal.surrogate.svr;
+
+import de.evoal.core.api.properties.Properties;
+import de.evoal.core.api.properties.PropertiesSpecification;
+import de.evoal.surrogate.api.configuration.PartialFunctionConfiguration;
+import de.evoal.surrogate.api.function.AbstractPartialSurrogateFunction;
+
+import smile.regression.KernelMachine;
+
+public class KernelBasedSVRFunction extends AbstractPartialSurrogateFunction {
+
+	/**
+	 * Indices of input data
+	 */
+	private final int[] indices;
+
+	/**
+	 * Actual SVR
+	 */
+	private final KernelMachine<double []> regression;
+
+	private final double gamma;
+
+	public KernelBasedSVRFunction(final PartialFunctionConfiguration configuration, final KernelMachine<double []> regression, final PropertiesSpecification input, final PropertiesSpecification actualInput, final PropertiesSpecification output, final double gamma) {
+		super(configuration, KernelHelper.toParameters(regression), input, output);
+		
+		this.indices = input.getProperties().stream().mapToInt(p -> actualInput.indexOf(p)).toArray();
+
+		this.regression = regression;
+		this.gamma = gamma;
+	}
+
+	@Override
+	public double [] apply(final Properties input) {
+		final double [] data = new double[indices.length];
+
+		for(int i = 0; i < data.length; ++i) {
+			data[i] = input.get(indices[i]);
+		}
+
+		return new double [] {regression.predict(data)};
+	}
+
+	public KernelMachine<double []> getRegression() {
+		return regression;
+	}
+
+	public double getGamma() {
+		return gamma;
+	}
+}
diff --git a/src/core/de.evoal.surrogate.svr/src/main/java/de/evoal/surrogate/svr/KernelBasedSVRFunctionFactory.java b/src/core/de.evoal.surrogate.svr/src/main/java/de/evoal/surrogate/svr/KernelBasedSVRFunctionFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..c091422329ffcf18bf23c1f3133d1e8f7cd09c44
--- /dev/null
+++ b/src/core/de.evoal.surrogate.svr/src/main/java/de/evoal/surrogate/svr/KernelBasedSVRFunctionFactory.java
@@ -0,0 +1,64 @@
+package de.evoal.surrogate.svr;
+
+import de.evoal.core.api.properties.PropertiesSpecification;
+import de.evoal.core.api.properties.stream.PropertiesPairStreamSupplier;
+import de.evoal.core.api.utils.Requirements;
+import de.evoal.surrogate.api.configuration.Parameter;
+import de.evoal.surrogate.api.configuration.PartialFunctionConfiguration;
+import de.evoal.surrogate.api.function.AbstractPartialSurrogateFunctionFactory;
+import de.evoal.surrogate.api.function.PartialSurrogateFunction;
+import lombok.extern.slf4j.Slf4j;
+import smile.math.kernel.MercerKernel;
+import smile.regression.KernelMachine;
+import smile.regression.SVR;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+@Slf4j
+public abstract class KernelBasedSVRFunctionFactory extends AbstractPartialSurrogateFunctionFactory {
+	/**
+	 * Function to create the SVR kernel.
+	 */
+	private final Function<Map<String, Object>, MercerKernel<double[]>> toKernel;
+
+	public KernelBasedSVRFunctionFactory(final Function<Map<String, Object>, MercerKernel<double []>> toKernel) {
+		this.toKernel = toKernel;
+	}
+
+	@Override
+	protected PartialSurrogateFunction calculateRegression(final PartialFunctionConfiguration configuration, List<Parameter> parameters, PropertiesSpecification actualInput, PropertiesSpecification requiredInput, PropertiesSpecification producedOutput, PropertiesPairStreamSupplier provider) {
+		log.info("Calculate SVR surrogate from {} to {}.", requiredInput, producedOutput);
+
+		Requirements.requireSizeGreaterThean(requiredInput.getProperties(), 0);
+		Requirements.requireSize(producedOutput.getProperties(), 1);
+
+		final List<double []> sources = new ArrayList<>();
+		final List<Double> targets = new ArrayList<>();
+
+		provider.get()
+				.forEach(p -> {
+					sources.add(p.getFirst().getValues());
+					targets.add(p.getSecond().get(0));
+				});
+
+		log.info("Using {} points for regression.", sources.size());
+
+		double [][] sourceArray = sources.toArray(new double [][] {});
+		double [] targetArray = targets.stream().mapToDouble(Double.class::cast).toArray();
+
+		final Map<String, Object> params = parameters.stream()
+				.collect(Collectors.toMap(Parameter::getName, Parameter::getValue));
+
+		final double epsilon = (double)params.get(KernelHelper.EPSILON_PARAMETER);
+		final double margin = (double)params.get(KernelHelper.SOFT_MARGIN_PARAMETER);
+		final double tolerance = (double)params.get(KernelHelper.TOLERANCE_PARAMETER);
+
+		final KernelMachine<double []> regression = SVR.fit(sourceArray, targetArray, toKernel.apply(params), epsilon, margin, tolerance);
+
+		return new KernelBasedSVRFunction(configuration, regression, requiredInput, actualInput, producedOutput, margin);
+	}
+}
diff --git a/src/core/de.evoal.surrogate.svr/src/main/java/de/evoal/surrogate/svr/KernelHelper.java b/src/core/de.evoal.surrogate.svr/src/main/java/de/evoal/surrogate/svr/KernelHelper.java
new file mode 100644
index 0000000000000000000000000000000000000000..fc82572f771eeaf60da1a930c9be0a2bb9248e75
--- /dev/null
+++ b/src/core/de.evoal.surrogate.svr/src/main/java/de/evoal/surrogate/svr/KernelHelper.java
@@ -0,0 +1,175 @@
+package de.evoal.surrogate.svr;
+
+import java.lang.reflect.Field;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import de.evoal.surrogate.api.configuration.Parameter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import smile.math.kernel.*;
+import smile.regression.KernelMachine;
+import smile.regression.Regression;
+
+public final class KernelHelper {
+	private static final String DEGREE_PARAMETER = "degree";
+
+	public static final String EPSILON_PARAMETER = "ε";
+
+	private static final String SCALE_PARAMETER = "scale";
+
+	private static final String OFFSET_PARAMETER = "offset";
+
+	private static final String SIGMA_PARAMETER = "σ";
+
+	public static final String SOFT_MARGIN_PARAMETER = "soft-margin";
+
+	public static final String TOLERANCE_PARAMETER = "tolerance";
+
+	private static final String KERNEL_PARAMETER = "kernel";
+
+	/**
+	 * Logger instance
+	 */
+	private final static Logger log = LoggerFactory.getLogger(KernelHelper.class);
+
+	private KernelHelper() {
+	}
+
+	private static void addParameter(final String name, final Object value, final List<Parameter> parameters) {
+		final Parameter parameter = Parameter.builder()
+				.name(name)
+				.value(value)
+				.build();
+
+		parameters.add(parameter);
+	}
+	
+	public static Map<String, Object> toMap(final List<Parameter> parameters) {
+		return parameters.stream()
+						 .collect(Collectors.toMap(Parameter::getName, Parameter::getValue));
+	}
+
+	public static KernelMachine<double []> fromParameters(final List<Parameter> parameters, final List<Parameter> kernelParameters) {
+		final Map<String, Object> kernelParameterMap = toMap(kernelParameters);
+
+		final MercerKernel<double []> kernel = toKernel(toMap(parameters));
+		final double[][] instances =(double[][]) kernelParameterMap.get("instances");
+		final double[] weight = (double[]) kernelParameterMap.get("weights");
+		final double b = (double)kernelParameterMap.get("intercept");
+		
+		return new KernelMachine<>(kernel, instances, weight, b);
+	}
+
+	public static MercerKernel<double []> toGaussianKernel(final Map<String, Object> parameters) {
+		log.info("  Using kernel 'gaussian'");
+		final double sigma = (double) parameters.get(SIGMA_PARAMETER);
+		log.info("    parameter σ={}.", sigma);
+
+		return new GaussianKernel(sigma);
+	}
+
+	public static MercerKernel<double []> toKernel(final Map<String, Object> parameters) {
+		log.info("  Using kernel '{}'", parameters.get(KERNEL_PARAMETER));
+
+		switch((String)parameters.get(KERNEL_PARAMETER)) {
+		case "gaussian": {
+			final double sigma = (double)parameters.get(SIGMA_PARAMETER);
+
+			log.info("    parameter σ={}.", sigma);
+
+			return new GaussianKernel(sigma);
+		}
+
+		case "hellinger": {
+			return new HellingerKernel();
+		}
+		
+		case "hyperbolic-tangent": {
+			final double scale = (double)parameters.get(SCALE_PARAMETER);
+			final double offset = (double)parameters.get(OFFSET_PARAMETER);
+			
+			log.info("    parameter scale is {} and offset is {}.", scale, offset);
+			
+			return new HyperbolicTangentKernel(scale, offset);
+		}
+
+		case "laplacian": {
+			final double sigma = (double)parameters.get(SIGMA_PARAMETER);
+
+			log.info("    parameter sigma is {}.", sigma);
+
+			return new LaplacianKernel(sigma);
+		}
+
+		case "linear": {
+			return new LinearKernel();
+		}
+
+		case "pearson": {
+			final double omega = (double)parameters.get("omega");
+			final double sigma = (double)parameters.get(SIGMA_PARAMETER);
+			
+			log.info("    parameter ω={} and σ={}.", omega, sigma);
+
+			return new PearsonKernel(omega, sigma);
+		}
+
+		case "polynomial": {
+			final int degree = (int)parameters.get(DEGREE_PARAMETER);
+			final double scale = (double)parameters.get(SCALE_PARAMETER);
+			final double offset = (double)parameters.get(OFFSET_PARAMETER);
+			
+			log.info("    parameter degeree is {}, scale is {}, and offset is {}.", degree, scale, offset);
+
+			return new PolynomialKernel(degree, scale, offset);
+		}
+
+		case "thin-plate-spline": {
+			final double sigma = (double)parameters.get(SIGMA_PARAMETER);
+
+			log.info("    parameter σ={}.", sigma);
+
+			return new ThinPlateSplineKernel(sigma);
+		}
+		}
+		 
+
+		throw new IllegalArgumentException("The kernel " + parameters.get(KERNEL_PARAMETER) + " is not supported.");
+	}
+
+	public static List<Parameter> toParameters(final Regression<double[]> regression) {
+		final KernelMachine<double []> machine = (KernelMachine<double[]>)regression;
+		
+		final List<Parameter> result = new LinkedList<>();
+		addParameter("weights", machine.weights(), result);
+		addParameter("intercept", machine.intercept(), result);
+		addParameter("instances", machine.instances(), result);
+
+		return result;
+	}
+
+	private void logRegressionParameters(final Regression<double[]> c) {
+		try {
+			final Field bField = smile.base.svm.KernelMachine.class.getDeclaredField("b");
+			final Field wField = smile.base.svm.KernelMachine.class.getDeclaredField("w");
+
+			bField.setAccessible(true);
+			wField.setAccessible(true);
+
+			final double b = bField.getDouble(c);
+			final double [] w = (double [])wField.get(c);
+
+			log.info("Parameters of kernel are b = {} and w = {}.", b, Arrays.toString(w));
+		} catch(final NoSuchFieldException e) {
+			log.error("Cannot determine the model parameters: Unable to read model of SVR.", e);
+		} catch (final IllegalArgumentException e) {
+			log.error("Cannot determine the model parameters: ", e);
+		} catch (IllegalAccessException e) {
+			log.error("Cannot determine the model parameters: ", e);
+		}
+	}}
diff --git a/src/core/de.evoal.surrogate.svr/src/main/java/de/evoal/surrogate/svr/ReflectionHelper.java b/src/core/de.evoal.surrogate.svr/src/main/java/de/evoal/surrogate/svr/ReflectionHelper.java
new file mode 100644
index 0000000000000000000000000000000000000000..e22a780712fa25a69c39f24e64e53e604b54deee
--- /dev/null
+++ b/src/core/de.evoal.surrogate.svr/src/main/java/de/evoal/surrogate/svr/ReflectionHelper.java
@@ -0,0 +1,34 @@
+package de.evoal.surrogate.svr;
+
+import java.lang.reflect.Field;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class ReflectionHelper {
+	/**
+	 * Logger instance
+	 */
+	private final static Logger log = LoggerFactory.getLogger(ReflectionHelper.class);
+
+	private ReflectionHelper() {
+	}
+
+	public static Object getField(final Object object, final String name) {
+		try {
+			final Field field = object.getClass().getDeclaredField(name);
+
+			field.setAccessible(true);
+			
+			return field.get(object);
+		} catch(final NoSuchFieldException e) {
+			log.error("Cannot determine the model parameters: Unable to read model of SVR.", e);
+		} catch (final IllegalArgumentException e) {
+			log.error("Cannot determine the model parameters: ", e);
+		} catch (IllegalAccessException e) {
+			log.error("Cannot determine the model parameters: ", e);
+		}
+		
+		throw new IllegalStateException();
+	}
+}
diff --git a/src/core/de.evoal.surrogate.svr/src/main/java/de/evoal/surrogate/svr/package-info.java b/src/core/de.evoal.surrogate.svr/src/main/java/de/evoal/surrogate/svr/package-info.java
new file mode 100644
index 0000000000000000000000000000000000000000..522538e6a73be4fbdc9624024a5040fc6310ea6d
--- /dev/null
+++ b/src/core/de.evoal.surrogate.svr/src/main/java/de/evoal/surrogate/svr/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Package for a kernel-based SVR using smile.
+ */
+package de.evoal.surrogate.svr;
\ No newline at end of file
diff --git a/src/core/de.evoal.surrogate.svr/src/main/java/module-info.java b/src/core/de.evoal.surrogate.svr/src/main/java/module-info.java
new file mode 100644
index 0000000000000000000000000000000000000000..f395b1f9ff1738ef791fe5b0e700cc53b08d0364
--- /dev/null
+++ b/src/core/de.evoal.surrogate.svr/src/main/java/module-info.java
@@ -0,0 +1,14 @@
+module de.evoal.surrogate.svr {
+    requires commons.math3;
+    requires jakarta.enterprise.cdi.api;
+    requires lombok;
+    requires org.slf4j;
+
+    requires de.evoal.core.api;
+    requires de.evoal.surrogate.api;
+    requires smile.core;
+    requires smile.math;
+    requires jakarta.inject.api;
+
+    opens de.evoal.surrogate.svr;
+}
\ No newline at end of file