From 6102892aeee6c9776cf83d02c93e732ff29e84d3 Mon Sep 17 00:00:00 2001
From: "Bernhard J. Berger" <bernhard.berger@uni-bremen.de>
Date: Fri, 3 Feb 2023 11:59:58 +0100
Subject: [PATCH] Towards ARFF support (#8).

---
 ci/create-release.sh                          |   2 +-
 src/core/de.evoal.core.arff/pom.xml           |  27 ++++
 .../core/arff/cdi/ArffBlackboardEntry.java    |  21 ++++
 .../core/arff/io/ArffPropertiesReader.java    | 117 ++++++++++++++++++
 .../core/arff/io/ArffPropertiesWriter.java    |  34 +++++
 .../de/evoal/core/arff/main/ConvertArff.java  | 112 +++++++++++++++++
 .../core/arff/main/ExtractDataDefinition.java |  98 +++++++++++++++
 .../src/main/java/module-info.java            |  21 ++++
 .../src/main/resources/META-INF/MANIFEST.MF   |   1 +
 .../src/main/resources/META-INF/beans.xml     |   6 +
 .../properties/PropertiesSpecification.java   |  16 ++-
 .../core/api/utils}/ConverterFunctions.java   |   2 +-
 src/core/de.evoal.releng.parent/pom.xml       |   3 +
 .../simple/identity/IdentityFunction.java     |   2 +-
 .../simple/linear/LinearFunction.java         |   2 +-
 .../quadratic/SimpleQuadraticFunction.java    |   2 +-
 .../surrogate/svr/KernelBasedSVRFunction.java |   2 +-
 17 files changed, 461 insertions(+), 7 deletions(-)
 create mode 100644 src/core/de.evoal.core.arff/pom.xml
 create mode 100644 src/core/de.evoal.core.arff/src/main/java/de/evoal/core/arff/cdi/ArffBlackboardEntry.java
 create mode 100644 src/core/de.evoal.core.arff/src/main/java/de/evoal/core/arff/io/ArffPropertiesReader.java
 create mode 100644 src/core/de.evoal.core.arff/src/main/java/de/evoal/core/arff/io/ArffPropertiesWriter.java
 create mode 100644 src/core/de.evoal.core.arff/src/main/java/de/evoal/core/arff/main/ConvertArff.java
 create mode 100644 src/core/de.evoal.core.arff/src/main/java/de/evoal/core/arff/main/ExtractDataDefinition.java
 create mode 100644 src/core/de.evoal.core.arff/src/main/java/module-info.java
 create mode 100644 src/core/de.evoal.core.arff/src/main/resources/META-INF/MANIFEST.MF
 create mode 100644 src/core/de.evoal.core.arff/src/main/resources/META-INF/beans.xml
 rename src/core/{de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/api/function => de.evoal.core/src/main/java/de/evoal/core/api/utils}/ConverterFunctions.java (98%)

diff --git a/ci/create-release.sh b/ci/create-release.sh
index d80d3b59..f50f4e78 100755
--- a/ci/create-release.sh
+++ b/ci/create-release.sh
@@ -2,7 +2,7 @@
 
 set -e -x
 
-RELEASE_PLUGINS="generator.main surrogate.api surrogate.simple surrogate.svr approximative.density"
+RELEASE_PLUGINS="generator.main surrogate.api surrogate.simple surrogate.svr approximative.density core.arff"
 
 
 mkdir -p evoal/plugins
diff --git a/src/core/de.evoal.core.arff/pom.xml b/src/core/de.evoal.core.arff/pom.xml
new file mode 100644
index 00000000..78baba99
--- /dev/null
+++ b/src/core/de.evoal.core.arff/pom.xml
@@ -0,0 +1,27 @@
+<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</groupId>
+		<artifactId>core.plugin</artifactId>
+		<version>0.9.0-SNAPSHOT</version>
+	</parent>
+
+	<artifactId>core.arff</artifactId>
+	<name>EvoAl - Core - ARFF support</name>
+
+	<dependencies>
+		<dependency>
+			<groupId>nz.ac.waikato.cms.weka</groupId>
+			<artifactId>weka-stable</artifactId>
+			<version>3.8.6</version>
+		</dependency>
+
+		<dependency>
+			<groupId>org.junit.jupiter</groupId>
+			<artifactId>junit-jupiter</artifactId>
+		</dependency>
+	</dependencies>
+</project>
diff --git a/src/core/de.evoal.core.arff/src/main/java/de/evoal/core/arff/cdi/ArffBlackboardEntry.java b/src/core/de.evoal.core.arff/src/main/java/de/evoal/core/arff/cdi/ArffBlackboardEntry.java
new file mode 100644
index 00000000..f8634c46
--- /dev/null
+++ b/src/core/de.evoal.core.arff/src/main/java/de/evoal/core/arff/cdi/ArffBlackboardEntry.java
@@ -0,0 +1,21 @@
+package de.evoal.core.arff.cdi;
+
+public final class ArffBlackboardEntry {
+    /**
+     * The arff file to read.
+     */
+    public static final String ARFF_INPUT = "arff:arff-input";
+
+
+    /**
+     * An DDL specification for converting an arff file into JSON.
+     */
+    public static final String DDL_SPECIFICATION = "arff:ddl-specification";
+
+    /**
+     * Output file for either a DDL or an JSON file (depending on the use case).
+     */
+    public static final String OUTPUT_FILE = "arff:output";
+
+    private ArffBlackboardEntry() {}
+}
diff --git a/src/core/de.evoal.core.arff/src/main/java/de/evoal/core/arff/io/ArffPropertiesReader.java b/src/core/de.evoal.core.arff/src/main/java/de/evoal/core/arff/io/ArffPropertiesReader.java
new file mode 100644
index 00000000..9c8ec368
--- /dev/null
+++ b/src/core/de.evoal.core.arff/src/main/java/de/evoal/core/arff/io/ArffPropertiesReader.java
@@ -0,0 +1,117 @@
+package de.evoal.core.arff.io;
+
+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.io.PropertiesReader;
+import de.evoal.core.api.utils.EvoalIOException;
+import de.evoal.languages.model.ddl.RepresentationType;
+import lombok.extern.slf4j.Slf4j;
+import weka.core.Attribute;
+import weka.core.Instance;
+import weka.core.Instances;
+import weka.core.converters.ConverterUtils;
+
+import javax.enterprise.context.Dependent;
+import javax.inject.Named;
+import java.io.File;
+
+@Slf4j
+@Dependent
+@Named("arff-reader")
+public class ArffPropertiesReader implements PropertiesReader {
+    private static interface TriFunction<S,T,U,R> {
+        /**
+         * Applies this function to the given arguments.
+         *
+         * @param s the first function argument
+         * @param t the second function argument
+         * @param u the third function argument
+         * @return the function result
+         */
+        R apply(S s, T t, U u);
+    }
+
+    private Instances data;
+
+    private int index = 0;
+    private PropertiesSpecification specification;
+
+    private TriFunction<Instance, PropertiesSpecification, PropertiesSpecification.Builder, Properties> toProperties = (instance, template, builder) -> new Properties(builder.build());
+
+    @Override
+    public PropertiesReader init(final File inputFile, final PropertiesSpecification specification) throws EvoalIOException {
+        log.info("Creating ARFF properties reader for {}.", specification);
+
+        try {
+            this.specification = specification;
+
+            final ConverterUtils.DataSource arffSource = new ConverterUtils.DataSource(inputFile.toString());
+            this.data = arffSource.getDataSet();
+
+            createMapping(arffSource.getStructure());
+        } catch (final Exception e) {
+            log.error("Failed to load arff file '{}'.", inputFile, e);
+            throw new EvoalIOException("Failed to load arff file: " + inputFile, e);
+        }
+
+        return this;
+    }
+
+    private void createMapping(final Instances structure) {
+        log.info("Mapping ARFF attributes to properties specification.");
+        final int size = structure.numAttributes();
+
+        for(int i = 0; i < size; ++i) {
+            final Attribute attr = structure.attribute(i);
+
+            if(!specification.contains(attr.name())) {
+                log.info("Skipping attribute '{}'.", attr.name());
+                continue;
+            }
+
+            final PropertySpecification pSpec = specification.find(attr.name());
+            final RepresentationType rType = pSpec.type().getRepresentation();
+            final TriFunction<Instance, PropertiesSpecification, PropertiesSpecification.Builder, Properties> decoratee = toProperties;
+            final int index = i;
+
+            if(RepresentationType.REAL.equals(rType)) {
+                toProperties = (instance, template, builder) -> {
+                    // add current specification to builder and let the chain complete it
+                    builder.add(pSpec);
+                    final Properties properties = decoratee.apply(instance, template, builder);
+
+                    // set value and return
+                    properties.put(pSpec, instance.toDoubleArray()[index]);
+                    return properties;
+                };
+            } else if(RepresentationType.INTEGER.equals(rType)) {
+                toProperties = (instance, template, builder) -> {
+                    // add current specification to builder and let the chain complete it
+                    builder.add(pSpec);
+                    final Properties properties = decoratee.apply(instance, template, builder);
+
+                    // set value and return
+                    properties.put(pSpec, (int)instance.toDoubleArray()[index]);
+                    return properties;
+                };
+            } else {
+                throw new RuntimeException("Not yet supported: " + rType);
+            }
+        }
+    }
+
+    @Override
+    public void close() throws Exception {
+    }
+
+    @Override
+    public boolean hasNext() {
+        return index < data.size();
+    }
+
+    @Override
+    public Properties next() {
+        return toProperties.apply(data.get(index++), specification, PropertiesSpecification.builder());
+    }
+}
diff --git a/src/core/de.evoal.core.arff/src/main/java/de/evoal/core/arff/io/ArffPropertiesWriter.java b/src/core/de.evoal.core.arff/src/main/java/de/evoal/core/arff/io/ArffPropertiesWriter.java
new file mode 100644
index 00000000..8eac81f3
--- /dev/null
+++ b/src/core/de.evoal.core.arff/src/main/java/de/evoal/core/arff/io/ArffPropertiesWriter.java
@@ -0,0 +1,34 @@
+package de.evoal.core.arff.io;
+
+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.core.api.utils.EvoalIOException;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.enterprise.context.Dependent;
+import javax.inject.Named;
+import java.io.File;
+import java.io.FileOutputStream;
+
+@Slf4j
+@Dependent
+@Named("json-writer")
+public class ArffPropertiesWriter implements PropertiesWriter {
+    private FileOutputStream outputStream;
+
+    @Override
+    public PropertiesWriter init(final File outputFile, final PropertiesSpecification specification) throws EvoalIOException {
+
+        return this;
+    }
+
+    @Override
+    public void add(final Properties properties) throws EvoalIOException {
+
+    }
+
+    @Override
+    public void close() throws Exception {
+    }
+}
diff --git a/src/core/de.evoal.core.arff/src/main/java/de/evoal/core/arff/main/ConvertArff.java b/src/core/de.evoal.core.arff/src/main/java/de/evoal/core/arff/main/ConvertArff.java
new file mode 100644
index 00000000..5bd4243c
--- /dev/null
+++ b/src/core/de.evoal.core.arff/src/main/java/de/evoal/core/arff/main/ConvertArff.java
@@ -0,0 +1,112 @@
+package de.evoal.core.arff.main;
+
+import com.google.inject.Injector;
+import de.evoal.core.api.cdi.BlackboardValue;
+import de.evoal.core.api.cdi.MainClass;
+import de.evoal.core.api.properties.PropertiesSpecification;
+import de.evoal.core.api.properties.io.PropertiesIOFactory;
+import de.evoal.core.api.properties.io.PropertiesReader;
+import de.evoal.core.api.properties.io.PropertiesWriter;
+import de.evoal.core.arff.cdi.ArffBlackboardEntry;
+import de.evoal.languages.model.ddl.DataDescriptionModel;
+import de.evoal.languages.model.ddl.dsl.DataDescriptionLanguageStandaloneSetup;
+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 weka.Run;
+
+import javax.enterprise.context.Dependent;
+import javax.inject.Inject;
+import javax.inject.Named;
+import java.io.File;
+
+@Slf4j
+@Dependent
+@Named("convert-arff-to-json")
+public class ConvertArff implements MainClass {
+
+    @Inject
+    @BlackboardValue(ArffBlackboardEntry.ARFF_INPUT)
+    private File arffFile;
+
+    @Inject
+    @BlackboardValue(ArffBlackboardEntry.DDL_SPECIFICATION)
+    private File ddlFile;
+
+    @Inject
+    @BlackboardValue(ArffBlackboardEntry.OUTPUT_FILE)
+    private File jsonFile;
+
+    @Override
+    public void run() {
+        final PropertiesSpecification specification = readSpecification();
+
+        try (final PropertiesReader reader = PropertiesIOFactory.reader(arffFile, specification);
+             final PropertiesWriter writer = PropertiesIOFactory.writer(jsonFile, specification);
+            ) {
+
+            while(reader.hasNext()) {
+                writer.add(reader.next());
+            }
+        } catch(final Exception e) {
+            log.error("Failed to convert from {} to {}.", arffFile, jsonFile, e);
+        }
+    }
+
+    private PropertiesSpecification readSpecification() {
+        final DataDescriptionModel model = loadSpecificationFile();
+
+        return PropertiesSpecification
+                    .builder()
+                    .add(model.getDescriptions().stream())
+                    .build();
+    }
+
+    private DataDescriptionModel loadSpecificationFile() {
+        log.info("Loading data description configuration from {}.",  ddlFile);
+
+        if(!ddlFile.exists() || ! ddlFile.canRead()) {
+            log.error("Unable to read data description configuration file '{}'", ddlFile);
+            throw new IllegalArgumentException("Unable to read data description configuration file: " + ddlFile);
+        }
+
+        // init EMF + Xtext
+        final Injector dlInjector = new DataDescriptionLanguageStandaloneSetup().createInjectorAndDoEMFRegistration();
+
+        final XtextResourceSet resourceSet = dlInjector.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 DL file.");
+            final URI modelURI = URI.createFileURI(ddlFile.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 '{}': {}", ddlFile, diagnostic);
+                }
+            }
+            if(!resource.getWarnings().isEmpty()) {
+                for(Resource.Diagnostic diagnostic : resource.getWarnings()) {
+                    log.error("Warning while processing rule '{}': {}", ddlFile, diagnostic);
+                }
+            }
+
+            if(!resource.getErrors().isEmpty()) {
+                throw new IllegalArgumentException("DL file contains errors. Please fix the file.");
+            }
+
+            return (DataDescriptionModel) resource.getContents().get(0);
+        } catch (final Exception e) {
+            log.error("Unable to load data description configuration file '{}'.", ddlFile, e);
+            throw new RuntimeException("Unable to load data description configuration file: " + ddlFile, e);
+        }
+    }
+}
diff --git a/src/core/de.evoal.core.arff/src/main/java/de/evoal/core/arff/main/ExtractDataDefinition.java b/src/core/de.evoal.core.arff/src/main/java/de/evoal/core/arff/main/ExtractDataDefinition.java
new file mode 100644
index 00000000..37c70a4d
--- /dev/null
+++ b/src/core/de.evoal.core.arff/src/main/java/de/evoal/core/arff/main/ExtractDataDefinition.java
@@ -0,0 +1,98 @@
+package de.evoal.core.arff.main;
+
+import de.evoal.core.api.cdi.BlackboardValue;
+import de.evoal.core.api.cdi.MainClass;
+import de.evoal.core.arff.cdi.ArffBlackboardEntry;
+import lombok.extern.slf4j.Slf4j;
+import weka.core.Attribute;
+import weka.core.Instances;
+import weka.core.converters.ConverterUtils;
+
+import javax.enterprise.context.Dependent;
+import javax.inject.Inject;
+import javax.inject.Named;
+import java.io.*;
+import java.util.Enumeration;
+
+@Slf4j
+@Dependent
+@Named("extract-data-definition-from-arff")
+public class ExtractDataDefinition implements MainClass {
+
+    @Inject
+    @BlackboardValue(ArffBlackboardEntry.ARFF_INPUT)
+    private String arffFile;
+
+    @Inject
+    @BlackboardValue(ArffBlackboardEntry.OUTPUT_FILE)
+    private File ddlFile;
+
+    @Override
+    public void run() {
+        try {
+            final ConverterUtils.DataSource source = new ConverterUtils.DataSource(arffFile);
+            final Instances structure = source.getStructure();
+
+            try(final OutputStream ddlStream = new FileOutputStream(ddlFile)) {
+                try(final PrintStream ddlPrinter = new PrintStream(ddlStream)) {
+                    extractDDL(ddlPrinter, structure);
+                }
+            }
+        } catch(final Exception e) {
+            log.error("Failed to extract ddl from {}. {} might be corrupt.", arffFile, ddlFile, e);
+        }
+    }
+
+    public static void extractDDL(final PrintStream writer, final Instances structure) {
+        final Enumeration<Attribute> attributes = structure.enumerateAttributes();
+        writer.println("data:");
+
+        while(attributes.hasMoreElements()) {
+            final Attribute attr = attributes.nextElement();
+
+            writer.print("    ");
+            writer.print(toType(attr.type()));
+            writer.print(" ");
+            writer.print(toStorage(attr.type()));
+            writer.print(" ");
+            writer.print("data");
+            writer.print(" ");
+            writer.print("'");
+            writer.print(attr.name());
+            writer.print("'");
+            writer.println(";");
+        }
+    }
+
+    private static String toStorage(int type) {
+        switch (type) {
+            case Attribute.NOMINAL:
+            case Attribute.STRING:
+                return "string";
+
+            case Attribute.NUMERIC:
+                return "real";
+
+            default:
+                log.error("Unsupported storage type: {}", type);
+        }
+
+        return "???";
+    }
+
+    private static String toType(int type) {
+        switch (type) {
+            case Attribute.NOMINAL:
+            case Attribute.STRING:
+                return "nominal";
+
+            case Attribute.NUMERIC:
+                return "cardinal";
+
+            default:
+                log.error("Unsupported type: {}", type);
+        }
+
+        return "???";
+    }
+}
diff --git a/src/core/de.evoal.core.arff/src/main/java/module-info.java b/src/core/de.evoal.core.arff/src/main/java/module-info.java
new file mode 100644
index 00000000..425f4937
--- /dev/null
+++ b/src/core/de.evoal.core.arff/src/main/java/module-info.java
@@ -0,0 +1,21 @@
+module de.evoal.core.arff {
+    requires jakarta.inject.api;
+    requires jakarta.enterprise.cdi.api;
+
+    requires guice;
+    requires lombok;
+    requires org.slf4j;
+
+    requires org.eclipse.emf.common;
+    requires org.eclipse.emf.ecore;
+    requires org.eclipse.xtext;
+
+    requires weka.stable;
+
+    requires de.evoal.core;
+    requires de.evoal.languages.model.ddl;
+    requires de.evoal.languages.model.ddl.dsl;
+
+    opens de.evoal.core.arff.io to weld.core.impl;
+    opens de.evoal.core.arff.main to weld.core.impl;
+}
\ No newline at end of file
diff --git a/src/core/de.evoal.core.arff/src/main/resources/META-INF/MANIFEST.MF b/src/core/de.evoal.core.arff/src/main/resources/META-INF/MANIFEST.MF
new file mode 100644
index 00000000..9d885be5
--- /dev/null
+++ b/src/core/de.evoal.core.arff/src/main/resources/META-INF/MANIFEST.MF
@@ -0,0 +1 @@
+Manifest-Version: 1.0
diff --git a/src/core/de.evoal.core.arff/src/main/resources/META-INF/beans.xml b/src/core/de.evoal.core.arff/src/main/resources/META-INF/beans.xml
new file mode 100644
index 00000000..848dca3b
--- /dev/null
+++ b/src/core/de.evoal.core.arff/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/src/main/java/de/evoal/core/api/properties/PropertiesSpecification.java b/src/core/de.evoal.core/src/main/java/de/evoal/core/api/properties/PropertiesSpecification.java
index fd6e3094..15a41c26 100644
--- a/src/core/de.evoal.core/src/main/java/de/evoal/core/api/properties/PropertiesSpecification.java
+++ b/src/core/de.evoal.core/src/main/java/de/evoal/core/api/properties/PropertiesSpecification.java
@@ -8,7 +8,8 @@ import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 public class PropertiesSpecification {
-	public static class Builder {
+
+    public static class Builder {
 
 		private final Set<PropertySpecification> properties = new TreeSet<>();
 
@@ -38,6 +39,14 @@ public class PropertiesSpecification {
 			return this;
 		}
 
+		public Builder add(final PropertySpecification specification) {
+			if (!properties.contains(specification)) {
+				properties.add(specification);
+			}
+
+			return this;
+		}
+
 		public PropertiesSpecification build() {
 			return new PropertiesSpecification(orderedProperties);
 		}
@@ -82,6 +91,11 @@ public class PropertiesSpecification {
 		return this.indices.containsKey(spec);
 	}
 
+	public boolean contains(final String name) {
+		return this.properties.stream().anyMatch(p -> p.name().equals(name));
+	}
+
+
 	public PropertySpecification find(final String name) {
 		return properties.get(indexOf(name));
 	}
diff --git a/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/api/function/ConverterFunctions.java b/src/core/de.evoal.core/src/main/java/de/evoal/core/api/utils/ConverterFunctions.java
similarity index 98%
rename from src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/api/function/ConverterFunctions.java
rename to src/core/de.evoal.core/src/main/java/de/evoal/core/api/utils/ConverterFunctions.java
index ec1f5797..5aead37a 100644
--- a/src/core/de.evoal.surrogate.api/src/main/java/de/evoal/surrogate/api/function/ConverterFunctions.java
+++ b/src/core/de.evoal.core/src/main/java/de/evoal/core/api/utils/ConverterFunctions.java
@@ -1,4 +1,4 @@
-package de.evoal.surrogate.api.function;
+package de.evoal.core.api.utils;
 
 import de.evoal.core.api.properties.Properties;
 import de.evoal.languages.model.ddl.RepresentationType;
diff --git a/src/core/de.evoal.releng.parent/pom.xml b/src/core/de.evoal.releng.parent/pom.xml
index ad60d5dd..c750a06c 100644
--- a/src/core/de.evoal.releng.parent/pom.xml
+++ b/src/core/de.evoal.releng.parent/pom.xml
@@ -28,6 +28,9 @@
     <modules>
         <module>../de.evoal.core</module>
         <module>../de.evoal.core.plugin</module>
+
+        <module>../de.evoal.core.arff</module>
+
         <module>../de.evoal.generator.main</module>
 
         <module>../de.evoal.surrogate.api</module>
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
index 889de827..26e335cb 100644
--- 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
@@ -8,7 +8,7 @@ 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 de.evoal.surrogate.api.function.ConverterFunctions;
+import de.evoal.core.api.utils.ConverterFunctions;
 import lombok.extern.slf4j.Slf4j;
 
 @Slf4j
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
index 685864a0..21e669d8 100644
--- 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
@@ -11,7 +11,7 @@ import de.evoal.surrogate.api.function.AbstractPartialSurrogateFunction;
 
 import de.evoal.core.api.properties.PropertiesSpecification;
 import de.evoal.core.api.properties.PropertySpecification;
-import de.evoal.surrogate.api.function.ConverterFunctions;
+import de.evoal.core.api.utils.ConverterFunctions;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.math3.stat.regression.SimpleRegression;
 
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
index 320c3155..902ad974 100644
--- 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
@@ -8,7 +8,7 @@ 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 de.evoal.surrogate.api.function.ConverterFunctions;
+import de.evoal.core.api.utils.ConverterFunctions;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.math3.stat.regression.SimpleRegression;
 
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
index 2e295396..2da9aad9 100644
--- 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
@@ -7,7 +7,7 @@ import de.evoal.surrogate.api.configuration.Parameter;
 import de.evoal.surrogate.api.configuration.PartialFunctionConfiguration;
 import de.evoal.surrogate.api.function.AbstractPartialSurrogateFunction;
 
-import de.evoal.surrogate.api.function.ConverterFunctions;
+import de.evoal.core.api.utils.ConverterFunctions;
 import smile.regression.KernelMachine;
 
 import java.util.LinkedList;
-- 
GitLab