From f763cf0edacc2156ee63e7be3de63689fb8add22 Mon Sep 17 00:00:00 2001
From: rschoene <rene.schoene@tu-dresden.de>
Date: Fri, 28 Jun 2019 12:26:21 +0200
Subject: [PATCH] Fix Learner bugs.

- Let ExternalMachineLearningModel.check() return true instead of throwing an exception
- In Learner, use temporary files to store encog model
- In MachineLearningImpl, do not use result for now (as newData won't work at the moment)
- Minor fixes for base (add logger, add correct input to jastadd gradle task)
---
 eraser-base/build.gradle                      |  1 +
 eraser-base/src/main/jastadd/Logging.jadd     | 17 +++++++---
 .../src/main/jastadd/MachineLearning.jrag     |  3 +-
 .../inf/st/eraser/starter/EraserStarter.java  |  8 ++---
 .../inf/st/eraser/starter/Setting.java        |  2 +-
 eraser.starter/starter-setting.yaml           |  4 ++-
 .../feedbackloop.learner_backup/Learner.java  | 34 ++++++++++++++-----
 .../MachineLearningImpl.java                  |  6 ++--
 8 files changed, 51 insertions(+), 24 deletions(-)

diff --git a/eraser-base/build.gradle b/eraser-base/build.gradle
index 2d0b1f8e..fbe5f76e 100644
--- a/eraser-base/build.gradle
+++ b/eraser-base/build.gradle
@@ -118,6 +118,7 @@ task copyRagdoc(type: Copy, dependsOn: cleanRagdoc) {
 }
 
 generateAst.dependsOn preprocess
+generateAst.inputs.files file("./src/main/jastadd/mainGen.ast"), file("./src/main/jastadd/mainGen.jadd")
 //compileJava.dependsOn jastadd
 //
 //// always run jastadd
diff --git a/eraser-base/src/main/jastadd/Logging.jadd b/eraser-base/src/main/jastadd/Logging.jadd
index dd41bc70..710bd79a 100644
--- a/eraser-base/src/main/jastadd/Logging.jadd
+++ b/eraser-base/src/main/jastadd/Logging.jadd
@@ -1,12 +1,21 @@
 aspect Logging {
+  // Base
   protected org.apache.logging.log4j.Logger Item.logger = org.apache.logging.log4j.LogManager.getLogger(Item.class);
   protected org.apache.logging.log4j.Logger ItemPreference.logger = org.apache.logging.log4j.LogManager.getLogger(ItemPreference.class);
-  protected org.apache.logging.log4j.Logger Neuron.logger = org.apache.logging.log4j.LogManager.getLogger(Neuron.class);
 
+  // MachineLearning
   private org.apache.logging.log4j.Logger DummyMachineLearningModel.logger = org.apache.logging.log4j.LogManager.getLogger(DummyMachineLearningModel.class);
-  private org.apache.logging.log4j.Logger Rule.logger = org.apache.logging.log4j.LogManager.getLogger(Rule.class);
-  private org.apache.logging.log4j.Logger MqttRoot.logger = org.apache.logging.log4j.LogManager.getLogger(MqttRoot.class);
-  private org.apache.logging.log4j.Logger InternalMachineLearningModel.logger = org.apache.logging.log4j.LogManager.getLogger(MachineLearningModel.class);
+  private org.apache.logging.log4j.Logger InternalMachineLearningModel.logger = org.apache.logging.log4j.LogManager.getLogger(InternalMachineLearningModel.class);
+  private org.apache.logging.log4j.Logger ExternalMachineLearningModel.logger = org.apache.logging.log4j.LogManager.getLogger(ExternalMachineLearningModel.class);
+
+  // NeuralNetwork
   private org.apache.logging.log4j.Logger NeuralNetworkRoot.logger = org.apache.logging.log4j.LogManager.getLogger(NeuralNetworkRoot.class);
   private org.apache.logging.log4j.Logger OutputLayer.logger = org.apache.logging.log4j.LogManager.getLogger(OutputLayer.class);
+  protected org.apache.logging.log4j.Logger Neuron.logger = org.apache.logging.log4j.LogManager.getLogger(Neuron.class);
+
+  // Rules
+  private org.apache.logging.log4j.Logger Rule.logger = org.apache.logging.log4j.LogManager.getLogger(Rule.class);
+
+  // MQTT
+  private org.apache.logging.log4j.Logger MqttRoot.logger = org.apache.logging.log4j.LogManager.getLogger(MqttRoot.class);
 }
diff --git a/eraser-base/src/main/jastadd/MachineLearning.jrag b/eraser-base/src/main/jastadd/MachineLearning.jrag
index e5fc2f6f..98f5ba3b 100644
--- a/eraser-base/src/main/jastadd/MachineLearning.jrag
+++ b/eraser-base/src/main/jastadd/MachineLearning.jrag
@@ -112,7 +112,8 @@ aspect MachineLearning {
 
   @Override
   public boolean ExternalMachineLearningModel.check() {
-    throw new UnsupportedOperationException("check not available for external ML models (yet)!");
+    logger.warn("check not available for external ML models (yet)!");
+    return true;
   }
 
   //--- mlKind ---
diff --git a/eraser.starter/src/main/java/de/tudresden/inf/st/eraser/starter/EraserStarter.java b/eraser.starter/src/main/java/de/tudresden/inf/st/eraser/starter/EraserStarter.java
index 1715b337..2442c983 100644
--- a/eraser.starter/src/main/java/de/tudresden/inf/st/eraser/starter/EraserStarter.java
+++ b/eraser.starter/src/main/java/de/tudresden/inf/st/eraser/starter/EraserStarter.java
@@ -7,7 +7,6 @@ import de.tudresden.inf.st.eraser.feedbackloop.analyze.AnalyzeImpl;
 import de.tudresden.inf.st.eraser.feedbackloop.api.Analyze;
 import de.tudresden.inf.st.eraser.feedbackloop.api.Execute;
 import de.tudresden.inf.st.eraser.feedbackloop.api.Plan;
-import de.tudresden.inf.st.eraser.feedbackloop.api.EncogModel;
 import de.tudresden.inf.st.eraser.feedbackloop.execute.ExecuteImpl;
 import de.tudresden.inf.st.eraser.feedbackloop.learner_backup.Learner;
 import de.tudresden.inf.st.eraser.feedbackloop.learner_backup.MachineLearningImpl;
@@ -16,7 +15,6 @@ import de.tudresden.inf.st.eraser.jastadd.model.*;
 import de.tudresden.inf.st.eraser.openhab2.OpenHab2Importer;
 import de.tudresden.inf.st.eraser.openhab2.mqtt.MQTTUpdater;
 import de.tudresden.inf.st.eraser.spark.Application;
-import de.tudresden.inf.st.eraser.util.JavaUtils;
 import de.tudresden.inf.st.eraser.util.ParserUtils;
 import net.sourceforge.argparse4j.ArgumentParsers;
 import net.sourceforge.argparse4j.annotation.Arg;
@@ -27,10 +25,8 @@ import org.apache.logging.log4j.Logger;
 
 import java.io.File;
 import java.io.IOException;
-import java.io.InputStream;
 import java.net.MalformedURLException;
 import java.net.URL;
-import java.util.Collections;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.locks.Condition;
 import java.util.concurrent.locks.Lock;
@@ -124,7 +120,7 @@ public class EraserStarter {
       MachineLearningImpl handler = new MachineLearningImpl(learner, MachineLearningImpl.GOAL_ACTIVITY_PHONE_AND_WATCH);
       handler.setKnowledgeBaseRoot(root);
       logger.info("Reading activity recognition from csv file {}", settings.activity.file);
-      handler.initActivities(settings.activity.realURL().toString());
+      handler.initActivities(settings.activity.realURL().getFile());
       ExternalMachineLearningModel machineLearningModel = new ExternalMachineLearningModel();
       machineLearningModel.setEncoder(handler);
       machineLearningModel.setDecoder(handler);
@@ -139,7 +135,7 @@ public class EraserStarter {
       logger.info("Reading preference learning from csv file {}", settings.preference.file);
       MachineLearningImpl handler = new MachineLearningImpl(learner, MachineLearningImpl.GOAL_PREFERENCE_BRIGHTNESS_IRIS);
       handler.setKnowledgeBaseRoot(root);
-      handler.initPreferences(settings.preference.realURL().toString());
+      handler.initPreferences(settings.preference.realURL().getFile());
       ExternalMachineLearningModel machineLearningModel = new ExternalMachineLearningModel();
       machineLearningModel.setEncoder(handler);
       machineLearningModel.setDecoder(handler);
diff --git a/eraser.starter/src/main/java/de/tudresden/inf/st/eraser/starter/Setting.java b/eraser.starter/src/main/java/de/tudresden/inf/st/eraser/starter/Setting.java
index dacbb428..09af126b 100644
--- a/eraser.starter/src/main/java/de/tudresden/inf/st/eraser/starter/Setting.java
+++ b/eraser.starter/src/main/java/de/tudresden/inf/st/eraser/starter/Setting.java
@@ -32,7 +32,7 @@ class Setting {
     URL realURL() {
       if (external) {
         try {
-          return Paths.get(file).toUri().toURL();
+          return Paths.get(file).toUri().normalize().toURL();
         } catch (MalformedURLException e) {
           logger.catching(e);
           return null;
diff --git a/eraser.starter/starter-setting.yaml b/eraser.starter/starter-setting.yaml
index df759704..ca4c6fab 100644
--- a/eraser.starter/starter-setting.yaml
+++ b/eraser.starter/starter-setting.yaml
@@ -26,6 +26,7 @@ load:
 activity:
   # File to read in. Expected format = csv
   file: datasets/backup/activity_data.csv
+  external: true
   # Use dummy model in which the current activity is directly editable. Default: false.
   dummy: true
   # Model id. Default: 1.
@@ -34,7 +35,8 @@ activity:
 # Model for preference learning. If dummy is true, then the file parameter is ignored.
 preference:
   # File to read in. Expected format = csv
-  file: datasets/backup/preference_data.csv
+  file: ../datasets/backup/preference_data.csv
+  external: true
   # Use dummy model in which the current activity is directly editable. Default: false.
   dummy: false
   # Model id. Default: 1.
diff --git a/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/Learner.java b/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/Learner.java
index 52f357b1..e13e0fbe 100644
--- a/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/Learner.java
+++ b/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/Learner.java
@@ -1,6 +1,7 @@
 package de.tudresden.inf.st.eraser.feedbackloop.learner_backup;
 
 import java.io.File;
+import java.io.IOException;
 //import com.sun.javafx.tools.packager.Log;
 import org.encog.ConsoleStatusReportable;
 import org.encog.Encog;
@@ -26,8 +27,8 @@ public class Learner {
      * */
     private String csv_url_activity;
     private String csv_url_preference;
-    private String save_activity_model_file = "datasets/backup/activity_model.eg";
-    private String save_preference_model_file = "datasets/backup/preference_model.eg";
+    private File save_activity_model_file;
+    private File save_preference_model_file;
     private File csv_file;
     private VersatileDataSource a_souce;
     private VersatileMLDataSet a_data;
@@ -43,6 +44,22 @@ public class Learner {
     private String[] preference_result;
     private String activity_result;
 
+    public Learner() {
+        try {
+            save_activity_model_file = File.createTempFile("activity_model", "eg");
+        } catch (IOException e) {
+            // use local alternative
+            save_activity_model_file = new File("activity_model.eq");
+        }
+        try {
+            save_preference_model_file = File.createTempFile("preference_model", "eg");
+        } catch (IOException e) {
+            // use local alternative
+            save_preference_model_file = new File("preference_model.eg");
+        }
+        save_activity_model_file.deleteOnExit();
+        save_preference_model_file.deleteOnExit();
+    }
 
     private void activityDataAnalyser(String activity_csv_url){
         this.csv_url_activity = activity_csv_url;
@@ -149,7 +166,7 @@ public class Learner {
 
     public String activity_predictor(String[] new_data){
         activityDataAnalyser("datasets/backup/activity_data.csv");
-        BasicNetwork activity_method = (BasicNetwork) loadObject(new File(save_activity_model_file));
+        BasicNetwork activity_method = (BasicNetwork) loadObject(save_activity_model_file);
         MLData input = activity_helper.allocateInputVector();
         System.out.println("input"+activity_helper);
         String[] activity_new_data = new String[12];
@@ -191,7 +208,7 @@ public class Learner {
     public String[] preference_predictor(String[] new_data){
         preference_result = new String[2];
         preferenceDataAnalyser("datasets/backup/preference_data.csv");
-        BasicNetwork preference_method = (BasicNetwork)loadObject(new File(save_preference_model_file));
+        BasicNetwork preference_method = (BasicNetwork)loadObject(save_preference_model_file);
         MLData input = preference_helper.allocateInputVector();
         //
         // System.out.print("input: "+input);
@@ -206,10 +223,11 @@ public class Learner {
         preference_result[1] = preference_helper.denormalizeOutputVectorToString(output)[1];
         return preference_result;
     }
-    private void saveEncogModel(String model_file_url){
-        if (model_file_url.equals(save_activity_model_file)){saveObject(new File(model_file_url), this.a_best_method);}
-        else {
-            saveObject(new File(model_file_url), this.p_best_method);
+    private void saveEncogModel(File modelFile){
+        if (modelFile.equals(save_activity_model_file)) {
+          saveObject(modelFile, this.a_best_method);
+        } else {
+            saveObject(modelFile, this.p_best_method);
         }
 
     }
diff --git a/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/MachineLearningImpl.java b/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/MachineLearningImpl.java
index f2f36db3..bebc211f 100644
--- a/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/MachineLearningImpl.java
+++ b/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/MachineLearningImpl.java
@@ -135,14 +135,14 @@ public class MachineLearningImpl implements MachineLearningDecoder, MachineLearn
   public MachineLearningResult classify() {
     switch (this.goal) {
       case GOAL_ACTIVITY_PHONE_AND_WATCH:
-        String activityStringValue = result[0];
+//        String activityStringValue = result[0];
         Item activityItem = resolve(this.root.getOpenHAB2Model(), "activity");
         // FIXME how to translate activityStringValue to a number? or should activity item state better be a String?
-        logger.debug("Classify would return activity: {}", activityStringValue);
+//        logger.debug("Classify would return activity: {}", activityStringValue);
         ItemPreference classifiedActivity = new ItemPreferenceDouble(activityItem, 0);
         return new MachineLearningResultImpl(classifiedActivity);
       case GOAL_PREFERENCE_BRIGHTNESS_IRIS:
-        String[] preference = {result[1], result[2]};
+//        String[] preference = {result[1], result[2]};
         // FIXME what is the meaning of result[1] and result[2]
         Item iris1 = resolve(this.root.getOpenHAB2Model(), "iris1_item");
         ItemPreference classifiedPreference = new ItemPreferenceColor(iris1, TupleHSB.of(0, 0, 0));
-- 
GitLab