diff --git a/.gitignore b/.gitignore index ae5f085df619e4faf11263c8af42121396ec16d9..cddf03602a35709c94e0d191f9fe37af69e5757e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ .gradle/ .idea/ build/dependencyUpdates/ +venv/ +*/out/ +logs/ diff --git a/benchmark/.gitignore b/benchmark/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..54c5c0b024dab04da2a43d4135ed67ed2a670b46 --- /dev/null +++ b/benchmark/.gitignore @@ -0,0 +1,2 @@ +/build/ +logs/ diff --git a/benchmark/build.gradle b/benchmark/build.gradle new file mode 100644 index 0000000000000000000000000000000000000000..dfcc1d42edbaf81885917bd8b31573056ba29dbb --- /dev/null +++ b/benchmark/build.gradle @@ -0,0 +1,36 @@ +apply plugin: 'application' + +dependencies { + compile project(':eraser-base') + compile project(':feedbackloop.learner_backup') + compile project(':datasets') + testImplementation 'junit:junit:4.12' + // https://mvnrepository.com/artifact/org.hamcrest/java-hamcrest + // https://mvnrepository.com/artifact/org.hamcrest/hamcrest-core + testCompile group: 'org.hamcrest', name: 'hamcrest-core', version: '1.3' + implementation group: 'com.opencsv', name: 'opencsv', version: '4.1' + // https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient + compile group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.0-alpha4' + testCompile group: 'org.apache.logging.log4j', name: 'log4j-slf4j-impl', version: '2.11.2' + // https://mvnrepository.com/artifact/org.apache.httpcomponents/fluent-hc + compile group: 'org.apache.httpcomponents', name: 'fluent-hc', version: '4.2.1' + // https://mvnrepository.com/artifact/junit/junit + testCompile group: 'junit', name: 'junit', version: '4.4' + +} + +run { + mainClassName = 'de.tudresden.inf.st.eraser.benchmark.Main' + standardInput = System.in + if (project.hasProperty("appArgs")) { + args Eval.me(appArgs) + } +} + +sourceSets { + main { + java { + srcDir 'src/main/java' + } + } +} diff --git a/benchmark/src/main/java/de/tudresden/inf/st/eraser/benchmark/Benchmark.java b/benchmark/src/main/java/de/tudresden/inf/st/eraser/benchmark/Benchmark.java new file mode 100644 index 0000000000000000000000000000000000000000..2c1d64d5be93238589167e0c474218d3b22a952f --- /dev/null +++ b/benchmark/src/main/java/de/tudresden/inf/st/eraser/benchmark/Benchmark.java @@ -0,0 +1,146 @@ +package de.tudresden.inf.st.eraser.benchmark; + +import com.opencsv.CSVReader; +import org.apache.http.HttpResponse; +import org.apache.http.client.fluent.Request; +import org.apache.http.entity.ContentType; +import org.apache.http.util.EntityUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import java.io.File; +import java.io.FileReader; +import java.util.Arrays; + +public class Benchmark { + + //read every 5 s from csv + //activity CSV + /** + * Col 1: smartphone acceleration x + * Col 2: smartphone acceleration y + * Col 3: smartphone acceleration z + * Col 4: smartphone rotation x + * Col 5: smartphone rotation y + * Col 6: smartphone rotation z + * Col 7: watch acceleration x + * Col 8: watch acceleration y + * Col 9: watch acceleration z + * Col 10: watch rotation x + * Col 11: watch rotation y + * Col 12: watch rotation z/*/ + //preference CSV + /** + * Col 1: Activity + * Col 2: watch brightness range "bright, medium, dimmer, dark"*/ + + private String a_csv_file_path; + private String p_csv_file_path; + private static final Logger logger = LogManager.getLogger(Benchmark.class); + private static final String ERASER_ITEM_URI = "http://localhost:4567/model/items/"; + //TODO ITEM_NAME HAS TO BE DISCUSSED + private static final String[] ACTIVITY_ITEM_NAME = { + "m_accel_x", "m_accel_y", "m_accel_z", "m_rotation_x", + "m_rotation_y", "m_rotation_z", "w_accel_x", "w_accel_y", + "w_accel_z", "w_rotation_x", "w_rotation_y", "w_rotation_z"}; + private static final String[] PREFERENCE_ITEM_NAME = { + "w_brightness" + }; + private static boolean flag2 = true; + //csv_type is activity or preference + Benchmark(String a_csv_file_path, String p_csv_file_path) { + this.a_csv_file_path = a_csv_file_path; + this.p_csv_file_path = p_csv_file_path; + } + + void start(){ + String PREFERENCE_URL = "http://localhost:4567/model/items/iris1_item/state"; + String ACTIVITY_URL = "http://localhost:4567/activity/current"; + int TIME_PERIOD = 5000; + File a_file; + File p_file; + FileReader a_file_reader; + FileReader p_file_reader; + CSVReader a_csv_reader; + CSVReader p_csv_reader; + String[] a_next_record; + String[] p_next_record; + boolean flag1; + a_file=new File(a_csv_file_path); + p_file= new File(p_csv_file_path); + try { + a_file_reader =new FileReader(a_file); + p_file_reader=new FileReader(p_file); + a_csv_reader = new CSVReader(a_file_reader); + p_csv_reader = new CSVReader(p_file_reader); + while ((((a_next_record = a_csv_reader.readNext())!= null) && flag2)){ + try{Thread.sleep(TIME_PERIOD);}catch (InterruptedException e){e.printStackTrace();} + String[] values = Arrays.copyOf(a_next_record,12); + setNewValue(values, ACTIVITY_ITEM_NAME,"activity"); + HttpResponse response= Request.Get(ACTIVITY_URL).execute().returnResponse(); + String status = response.getStatusLine().toString(); + if(status.contains("200")){ + flag1 = true; + logger.info("activity should be (read direct from CSV): " + a_next_record[12]); + logger.info(EntityUtils.toString(response.getEntity())); + logger.info("get activity from web server: response 200 ok"); + }else{ + flag1 = false; + flag2 = false; + logger.info("can not get the activity from the web server"); + } + while((((p_next_record = p_csv_reader.readNext()) != null) && flag1)) { + try{Thread.sleep(TIME_PERIOD);}catch (InterruptedException e){e.printStackTrace();} + String[] values1 = Arrays.copyOf(p_next_record,2); + setNewValue(values1, PREFERENCE_ITEM_NAME,"preference"); + HttpResponse response1= Request.Get(PREFERENCE_URL).execute().returnResponse(); + String status1=response1.getStatusLine().toString(); + if(status1.contains("200")){ + flag2 = true; + logger.info("get the iris1_item preference from web server: response 200 ok, value is: "+EntityUtils.toString(response1.getEntity())); + }else {flag2 = false; + logger.info("can not get the iris1_item from the web server");} + break; + } + } + } + catch (Exception e){ + e.printStackTrace(); + } + } + private void setNewValue(String[] values, String[] name, String file_typ){ + if(file_typ.equals("activity")) + { + int i = 0; + for(String value : values){ + String uri = ERASER_ITEM_URI + name[i] + "/state"; + try { + HttpResponse httpResponse = Request.Put(uri) + .bodyString(value, ContentType.TEXT_PLAIN) + .execute().returnResponse(); + String status=httpResponse.getStatusLine().toString(); + if(status.contains("200")){ + logger.info("put activity input name: "+name[i]+", value: "+value+"to web server: response 200 ok"); + }else{ + logger.info("can not put activity inputs to rest server"); + } + }catch (Exception e){ + e.printStackTrace(); + } + i+=1; + } + }else{ + String uri= ERASER_ITEM_URI + "w_brightness" +"/state"; + try { + HttpResponse httpResponse = Request.Put(uri) + .bodyString(values[1], ContentType.TEXT_PLAIN) + .execute().returnResponse(); + String put_response=httpResponse.getStatusLine().toString(); + if (put_response.contains("200")){logger.info("put w_brightness to web server: response 200 ok");}else{ + logger.info("can not put w_brightness to rest server"); + } + }catch (Exception e){ + e.printStackTrace(); + } + } + } +} \ No newline at end of file diff --git a/benchmark/src/main/java/de/tudresden/inf/st/eraser/benchmark/Main.java b/benchmark/src/main/java/de/tudresden/inf/st/eraser/benchmark/Main.java new file mode 100644 index 0000000000000000000000000000000000000000..ac7536cae53749132be31ebe028e5ec0e55c30f4 --- /dev/null +++ b/benchmark/src/main/java/de/tudresden/inf/st/eraser/benchmark/Main.java @@ -0,0 +1,12 @@ +package de.tudresden.inf.st.eraser.benchmark; + +public class Main { + + public static void main(String[] args) { + String A_CSV_FILE_PATH = "../datasets/backup/activity_data.csv"; + String P_CSV_FILE_PATH = "../datasets/backup/preference_data.csv"; + Benchmark benchmark=new Benchmark(A_CSV_FILE_PATH,P_CSV_FILE_PATH); + benchmark.start(); + } +} + diff --git a/feedbackloop.learner_backup/out/production/resources/log4j2.xml b/benchmark/src/main/resources/log4j2.xml similarity index 100% rename from feedbackloop.learner_backup/out/production/resources/log4j2.xml rename to benchmark/src/main/resources/log4j2.xml diff --git a/eraser-base/build.gradle b/eraser-base/build.gradle index 2d0b1f8e78a2333cf594e8732e9ba30657a78db2..fbe5f76ec7b7097ca4ef1ca48181b4c26eb71433 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/Item.jrag b/eraser-base/src/main/jastadd/Item.jrag index c143c2bbdc23e9a0a3035f7293af1700baee740c..0b370142cf57c377775294bb6c758dafa7db036f 100644 --- a/eraser-base/src/main/jastadd/Item.jrag +++ b/eraser-base/src/main/jastadd/Item.jrag @@ -10,12 +10,19 @@ aspect ItemHandling { public void Item.enableSendState() { sendState = true; } public final boolean Item.isSendState() { return sendState; } + //--- DateTimeItem.ALTERNATIVE_FORMAT --- + private static final java.time.format.DateTimeFormatter DateTimeItem.ALTERNATIVE_FORMAT = new java.time.format.DateTimeFormatterBuilder() + .appendPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ") + .toFormatter() + .withZone(java.time.ZoneId.of("UTC")); + //--- getStateAsString --- syn String Item.getStateAsString(); eq ColorItem.getStateAsString() = getState().toString(); eq DateTimeItem.getStateAsString() = getState().toString(); eq ItemWithBooleanState.getStateAsString() = Boolean.toString(getState()); eq SwitchItem.getStateAsString() = getState() ? "ON" : "OFF"; + eq ContactItem.getStateAsString() = getState() ? "OPEN" : "CLOSED"; eq ItemWithDoubleState.getStateAsString() = Double.toString(getState()); eq ItemWithStringState.getStateAsString() = getState(); @@ -50,19 +57,24 @@ aspect ItemHandling { } } public void DateTimeItem.setStateFromString(String value) { - try{ + Exception exception = null; + // try normal instant parsing. Format example: 2019-07-22T12:58:08.960Z + try { this.setState(Instant.parse(value)); - } catch (java.time.format.DateTimeParseException e1) { - // try to read input as number and use that - try { - long time = Long.parseLong(value); - this.setStateFromLong(time); - // exit the method to avoid printing the error message for e1 - return; - } catch (NumberFormatException e2) { - logger.catching(e2); - } - logger.catching(e1); + return; + } catch (java.time.format.DateTimeParseException e) { /* empty */ } + // try openHAB parsing. Format example: 2019-07-22T12:58:08.960+0000 + try { + this.setState(ALTERNATIVE_FORMAT.parse(value, Instant::from)); + return; + } catch (java.time.format.DateTimeParseException e) { /* empty */ } + // try to read input as number and use that + try { + long time = Long.parseLong(value); + this.setStateFromLong(time); + return; + } catch (NumberFormatException e) { + logger.warn("Could not parse date value from {}", value); } } public void ItemWithBooleanState.setStateFromString(String value) { @@ -75,6 +87,20 @@ aspect ItemHandling { default: super.setStateFromString(value); } } + public void ContactItem.setStateFromString(String value) { + switch (value) { + case "OPEN": this.setState(true); break; + case "CLOSED": this.setState(false); break; + default: super.setStateFromString(value); + } + } + public void RollerShutterItem.setStateFromString(String value) { + switch (value) { + case "UP": this.setState(0); break; + case "DOWN": this.setState(100); break; + default: super.setStateFromString(value); + } + } public void ItemWithDoubleState.setStateFromString(String value) { this.setState(Double.parseDouble(value)); } @@ -288,7 +314,7 @@ aspect ItemHandling { //--- sendState --- protected void Item.sendState() throws Exception { for (MachineLearningModel model : getRelevantInMachineLearningModels()) { - model.getEncoder().newData(getRoot(), java.util.Collections.singletonList(this)); + model.getEncoder().newData(Collections.singletonList(this)); } } diff --git a/eraser-base/src/main/jastadd/Logging.jadd b/eraser-base/src/main/jastadd/Logging.jadd index dd41bc70f125081ea2ab6291ae48fa0272eea4c4..710bd79a7bce048213ce0d52bb42cae5176b832a 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 e5fc2f6f3e8c2dd8e9cb17c38d1dfd2c88f4a465..e584d8f2f6b9f1b2b0ce140a46c005b32887e1dd 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 --- @@ -160,7 +161,33 @@ aspect MachineLearning { return this.decoder; } - // refine Item.stateUpdated +} + +aspect ChangeEvents { + private static final java.util.concurrent.atomic.AtomicInteger ChangeEvent.idCounter = new java.util.concurrent.atomic.AtomicInteger(0); + + //--- createRecognitionEvent --- + public static RecognitionEvent RecognitionEvent.createRecognitionEvent(MachineLearningModel modelOfRecognition) { + RecognitionEvent result = new RecognitionEvent(); + result.initChangeEvent(); + for (Item relevantItem : modelOfRecognition.getRelevantItems()) { + result.addChangedItem(ChangedItem.newFromItem(relevantItem)); + } + return result; + } + //--- newFromItem --- + public static ChangedItem ChangedItem.newFromItem(Item source) { + ChangedItem result = new ChangedItem(); + result.setItem(source); + result.setNewStateAsString(source.getStateAsString()); + return result; + } + + //--- initChangeEvent --- + protected void ChangeEvent.initChangeEvent() { + this.setCreated(Instant.now()); + this.setIdentifier(idCounter.incrementAndGet()); + } } diff --git a/eraser-base/src/main/jastadd/MachineLearning.relast b/eraser-base/src/main/jastadd/MachineLearning.relast index b31dacb02aea2143c22828f9d6fa15d24ad9c545..906d344b8f123fca5d617b174078dcfa56f7f4c8 100644 --- a/eraser-base/src/main/jastadd/MachineLearning.relast +++ b/eraser-base/src/main/jastadd/MachineLearning.relast @@ -3,7 +3,7 @@ MachineLearningRoot ::= [ActivityRecognition:MachineLearningModel] [PreferenceLe Activity ::= <Identifier:int> <Label:String> ; -abstract ChangeEvent ::= <Identifier:int> <Timestamp:long> ChangedItem* ; +abstract ChangeEvent ::= <Identifier:int> <Created:Instant> ChangedItem* ; ChangedItem ::= <NewStateAsString:String> ; rel ChangedItem.Item -> Item ; diff --git a/eraser-base/src/main/jastadd/Printing.jrag b/eraser-base/src/main/jastadd/Printing.jrag index 53206bc16b2a09708a33386393ade1f3310e1666..7402973f563eb21924f1f54a54ae8dc6d2bea848 100644 --- a/eraser-base/src/main/jastadd/Printing.jrag +++ b/eraser-base/src/main/jastadd/Printing.jrag @@ -207,4 +207,29 @@ aspect Printing { .build(); } +// Expressions + syn String ParenthesizedNumberExpression.prettyPrint() = "(" + getOperand().prettyPrint() + ")"; + syn String NumberLiteralExpression.prettyPrint() = Double.toString(getValue()); + syn String AddExpression.prettyPrint() = "(" + getLeftOperand().prettyPrint() + " + " + getRightOperand().prettyPrint() + ")"; + syn String SubExpression.prettyPrint() = "(" + getLeftOperand().prettyPrint() + " - " + getRightOperand().prettyPrint() + ")"; + syn String MultExpression.prettyPrint() = "(" + getLeftOperand().prettyPrint() + " * " + getRightOperand().prettyPrint() + ")"; + syn String DivExpression.prettyPrint() = "(" + getLeftOperand().prettyPrint() + " / " + getRightOperand().prettyPrint() + ")"; + syn String PowerExpression.prettyPrint() = "(" + getLeftOperand().prettyPrint() + " ^ " + getRightOperand().prettyPrint() + ")"; + syn String ParenthesizedLogicalExpression.prettyPrint() = "(" + getOperand().prettyPrint() + ")"; + syn String NotExpression.prettyPrint() = "!" + getOperand().prettyPrint(); + syn String ComparingExpression.prettyPrint() { + switch (getComparator()) { + case NotEquals: return "(" + getLeftOperand().prettyPrint() + " != " + getRightOperand().prettyPrint() + ")"; + case Equals: return "(" + getLeftOperand().prettyPrint() + " == " + getRightOperand().prettyPrint() + ")"; + case LessThan: return "(" + getLeftOperand().prettyPrint() + " < " + getRightOperand().prettyPrint() + ")"; + case GreaterThan: return "(" + getLeftOperand().prettyPrint() + " > " + getRightOperand().prettyPrint() + ")"; + case LessOrEqualThan: return "(" + getLeftOperand().prettyPrint() + " <= " + getRightOperand().prettyPrint() + ")"; + case GreaterOrEqualThan: return "(" + getLeftOperand().prettyPrint() + " >= " + getRightOperand().prettyPrint() + ")"; + default: throw new IllegalArgumentException("Unknown compartor type: " + getComparator()); + } + } + syn String AndExpression.prettyPrint() = "(" + getLeftOperand().prettyPrint() + " & " + getRightOperand().prettyPrint() + ")"; + syn String OrExpression.prettyPrint() = "(" + getLeftOperand().prettyPrint() + " | " + getRightOperand().prettyPrint() + ")"; + syn String Designator.prettyPrint() = getItem().getID(); + } diff --git a/eraser-base/src/main/jastadd/Util.jrag b/eraser-base/src/main/jastadd/Util.jrag index 282a44413c80ee2b5c5d71dca179ce4cf45c1fde..b038ca0dfae51d7bbea748086965b78e40f0c3e6 100644 --- a/eraser-base/src/main/jastadd/Util.jrag +++ b/eraser-base/src/main/jastadd/Util.jrag @@ -6,6 +6,7 @@ aspect Util { // } public void MqttRoot.setHostByName(String hostName) { setHost(ExternalHost.of(hostName, DEFAULT_PORT)); + flushCache(); } public void InfluxRoot.setHostByName(String hostName) { diff --git a/eraser-base/src/main/jastadd/eraser.flex b/eraser-base/src/main/jastadd/eraser.flex index 2bd49e50fdfadebce430f728fa056be76573e8d6..bc9b3e8d9a41c9bd4cc51d1879f081b32538f103 100644 --- a/eraser-base/src/main/jastadd/eraser.flex +++ b/eraser-base/src/main/jastadd/eraser.flex @@ -106,7 +106,7 @@ Comment = "//" [^\n\r]+ "<=" { return sym(Terminals.LE); } "==" { return sym(Terminals.EQ); } "!=" { return sym(Terminals.NE); } -"=>" { return sym(Terminals.GE); } +">=" { return sym(Terminals.GE); } ">" { return sym(Terminals.GT); } "+" { return sym(Terminals.PLUS); } "*" { return sym(Terminals.MULT); } diff --git a/eraser-base/src/main/jastadd/mqtt.jrag b/eraser-base/src/main/jastadd/mqtt.jrag index ee7e06e00e5979a416ab300cf5163cc731af2072..b3f9c2a24a0a62ccc1f360fdadaad4cd7bafe3b5 100644 --- a/eraser-base/src/main/jastadd/mqtt.jrag +++ b/eraser-base/src/main/jastadd/mqtt.jrag @@ -74,4 +74,14 @@ aspect MQTT { getMqttRoot().getMqttSender().publish(getOutgoingTopic(), message); } + refine OpenHAB2 public void OpenHAB2Model.addNewItem(Item item) { + refined(item); + // update mqtt-topic to new mqtt-root + JavaUtils.ifPresentOrElse( + getRoot().getMqttRoot().resolveTopicSuffix(item.getTopic().getTopicString()), + topic -> item.setTopic(topic), + () -> de.tudresden.inf.st.eraser.util.ParserUtils.createMqttTopic(item, item.getTopic().getTopicString(), getRoot()) + ); + } + } diff --git a/eraser-base/src/main/jastadd/openhab.jrag b/eraser-base/src/main/jastadd/openhab.jrag index 6d30e4b3e0fb91225c9e8ea08bfdf3ab1afb1357..56aa89f36ac62aa817352f45a639ae7c4aa62206 100644 --- a/eraser-base/src/main/jastadd/openhab.jrag +++ b/eraser-base/src/main/jastadd/openhab.jrag @@ -2,4 +2,12 @@ aspect OpenHAB2 { syn ActivityItem OpenHAB2Model.getActivityItem() { return new ActivityItem(); } + + public void OpenHAB2Model.addNewItem(Item item) { + JavaUtils.ifPresentOrElse( + resolveGroup(de.tudresden.inf.st.eraser.util.ParserUtils.UNKNOWN_GROUP_NAME), + group -> group.addItem(item), + () -> de.tudresden.inf.st.eraser.util.ParserUtils.createUnknownGroup(this, Collections.singletonList(item))); + } + } diff --git a/eraser-base/src/main/jastadd/openhab.relast b/eraser-base/src/main/jastadd/openhab.relast index 7d7d9afa27f9f9998f6c5bd4b9822f0dfa774e8d..575f875734994ee52ba5259e5cfe570aa488c139 100644 --- a/eraser-base/src/main/jastadd/openhab.relast +++ b/eraser-base/src/main/jastadd/openhab.relast @@ -40,7 +40,7 @@ ImageItem : ItemWithStringState ; LocationItem : ItemWithStringState ; NumberItem : ItemWithDoubleState ; PlayerItem : ItemWithStringState ; -RollerShutterItem : ItemWithBooleanState ; +RollerShutterItem : ItemWithDoubleState ; StringItem : ItemWithStringState ; SwitchItem : ItemWithBooleanState ; DefaultItem : ItemWithStringState ; diff --git a/eraser-base/src/main/java/de/tudresden/inf/st/eraser/jastadd/model/InternalMachineLearningHandler.java b/eraser-base/src/main/java/de/tudresden/inf/st/eraser/jastadd/model/InternalMachineLearningHandler.java index 2c59f46ca48fc18afa7aa096571a19ef9bef4b44..75d2a1d8cfc28c0293f1d55cc4e6714a6e37818a 100644 --- a/eraser-base/src/main/java/de/tudresden/inf/st/eraser/jastadd/model/InternalMachineLearningHandler.java +++ b/eraser-base/src/main/java/de/tudresden/inf/st/eraser/jastadd/model/InternalMachineLearningHandler.java @@ -22,7 +22,12 @@ public class InternalMachineLearningHandler implements MachineLearningEncoder, M } @Override - public void newData(Root model, List<Item> changedItems) { + public void setKnowledgeBaseRoot(Root root) { + // ignored + } + + @Override + public void newData(List<Item> changedItems) { logger.debug("Ignored new data of {}", changedItems); } diff --git a/eraser-base/src/main/java/de/tudresden/inf/st/eraser/jastadd/model/MachineLearningDecoder.java b/eraser-base/src/main/java/de/tudresden/inf/st/eraser/jastadd/model/MachineLearningDecoder.java index a6e01fb945226bcf91e4bc94663c24b561f7cd6f..045c7695ba325429a3ba82a4e1319e0926aa043b 100644 --- a/eraser-base/src/main/java/de/tudresden/inf/st/eraser/jastadd/model/MachineLearningDecoder.java +++ b/eraser-base/src/main/java/de/tudresden/inf/st/eraser/jastadd/model/MachineLearningDecoder.java @@ -9,7 +9,7 @@ import java.time.Instant; * @author rschoene - Initial contribution */ @SuppressWarnings("unused") -public interface MachineLearningDecoder { +public interface MachineLearningDecoder extends MachineLearningSetRoot { /** * Execute the machine learning model and returns the classification result. diff --git a/eraser-base/src/main/java/de/tudresden/inf/st/eraser/jastadd/model/MachineLearningEncoder.java b/eraser-base/src/main/java/de/tudresden/inf/st/eraser/jastadd/model/MachineLearningEncoder.java index 8cf4d78fd92a2c18bd4914ab5b805db63995be85..23ca8959f468b8210c287b163a217a0224f7d283 100644 --- a/eraser-base/src/main/java/de/tudresden/inf/st/eraser/jastadd/model/MachineLearningEncoder.java +++ b/eraser-base/src/main/java/de/tudresden/inf/st/eraser/jastadd/model/MachineLearningEncoder.java @@ -1,8 +1,5 @@ package de.tudresden.inf.st.eraser.jastadd.model; -import de.tudresden.inf.st.eraser.jastadd.model.Item; -import de.tudresden.inf.st.eraser.jastadd.model.Root; - import java.util.List; /** @@ -13,14 +10,13 @@ import java.util.List; * @author rschoene - Initial contribution */ @SuppressWarnings("unused") -public interface MachineLearningEncoder { +public interface MachineLearningEncoder extends MachineLearningSetRoot { /** * Update when new data is available. - * @param model The underlying model * @param changedItems A list of items whose state has changed */ - void newData(Root model, List<Item> changedItems); + void newData(List<Item> changedItems); // to be discussed, in which form this is specified diff --git a/eraser-base/src/main/java/de/tudresden/inf/st/eraser/jastadd/model/MachineLearningSetRoot.java b/eraser-base/src/main/java/de/tudresden/inf/st/eraser/jastadd/model/MachineLearningSetRoot.java new file mode 100644 index 0000000000000000000000000000000000000000..13fec09c243d0d15c4f5e41a8c8851321c26d5d5 --- /dev/null +++ b/eraser-base/src/main/java/de/tudresden/inf/st/eraser/jastadd/model/MachineLearningSetRoot.java @@ -0,0 +1,17 @@ +package de.tudresden.inf.st.eraser.jastadd.model; + +/** + * Common interface for both {@link MachineLearningDecoder} and {@link MachineLearningEncoder}. + * + * @author rschoene - Initial contribution + */ +public interface MachineLearningSetRoot { + + /** + * Informs this handler of the knowledge base. + * This method is called before any other of the interface methods. + * @param root The root node of the knowledge base + */ + void setKnowledgeBaseRoot(Root root); + +} diff --git a/eraser-base/src/main/java/de/tudresden/inf/st/eraser/parser/EraserParserHelper.java b/eraser-base/src/main/java/de/tudresden/inf/st/eraser/parser/EraserParserHelper.java index fe88455606c2bb7b6d78a877059077686edf12fc..5d1b1af27c4bf36e15768bd12facc02ca3a1e773 100644 --- a/eraser-base/src/main/java/de/tudresden/inf/st/eraser/parser/EraserParserHelper.java +++ b/eraser-base/src/main/java/de/tudresden/inf/st/eraser/parser/EraserParserHelper.java @@ -7,7 +7,6 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.util.*; -import java.util.Comparator; import java.util.function.BiConsumer; /** diff --git a/eraser-base/src/main/java/de/tudresden/inf/st/eraser/util/MqttReceiver.java b/eraser-base/src/main/java/de/tudresden/inf/st/eraser/util/MqttReceiver.java index 1f013ea25872e57e452a603616e95126bdd69e11..5fa9ad6800b3964369d0a1f140db6a4c3e0d164f 100644 --- a/eraser-base/src/main/java/de/tudresden/inf/st/eraser/util/MqttReceiver.java +++ b/eraser-base/src/main/java/de/tudresden/inf/st/eraser/util/MqttReceiver.java @@ -133,6 +133,17 @@ public class MqttReceiver implements AutoCloseable { connection.connect(new Callback<Void>() { @Override public void onSuccess(Void value) { + connection.publish("components", "Eraser is listening".getBytes(), QoS.AT_LEAST_ONCE, false, new Callback<Void>() { + @Override + public void onSuccess(Void value) { + logger.debug("success sending welcome message"); + } + + @Override + public void onFailure(Throwable value) { + logger.debug("failure sending welcome message", value); + } + }); Topic[] topicArray = Arrays.stream(topics).map(topicName -> new Topic(topicName, qos)).toArray(Topic[]::new); logger.info("Connected, subscribing to {} topic(s) now.", topicArray.length); connection.subscribe(topicArray, new Callback<byte[]>() { @@ -150,7 +161,7 @@ public class MqttReceiver implements AutoCloseable { @Override public void onFailure(Throwable cause) { - logger.error("Could not subscribe, because {}", cause); + logger.error("Could not subscribe", cause); } }); } diff --git a/eraser-base/src/main/java/de/tudresden/inf/st/eraser/util/ParserUtils.java b/eraser-base/src/main/java/de/tudresden/inf/st/eraser/util/ParserUtils.java index c45f02562fa72036b24749ab4fdca47fbf87ed41..716f63f9caa9462665b8819c9347aef466637a76 100644 --- a/eraser-base/src/main/java/de/tudresden/inf/st/eraser/util/ParserUtils.java +++ b/eraser-base/src/main/java/de/tudresden/inf/st/eraser/util/ParserUtils.java @@ -241,6 +241,7 @@ public class ParserUtils { EraserScanner scanner = new EraserScanner(reader); EraserParser parser = new EraserParser(); Root root = (Root) parser.parse(scanner); + parser.resolveReferences(); reader.close(); int size = root.getOpenHAB2Model().items().size(); if (size == 0) { diff --git a/eraser-base/src/test/java/de/tudresden/inf/st/eraser/ExpressionEvalTest.java b/eraser-base/src/test/java/de/tudresden/inf/st/eraser/ExpressionEvalTest.java index d9c64c57553133162dc2a355360f50fc3716cf33..1758931346632a63c9f3297912b1fb7d1430da46 100644 --- a/eraser-base/src/test/java/de/tudresden/inf/st/eraser/ExpressionEvalTest.java +++ b/eraser-base/src/test/java/de/tudresden/inf/st/eraser/ExpressionEvalTest.java @@ -73,6 +73,19 @@ public class ExpressionEvalTest { assertThat(divExpression.getRightOperand().eval(), equalTo(4.0)); } + @Test + public void expressionWithItem() throws IOException, Parser.Exception { + double itemValue = 5.3; + Item referenceItem = ParserUtils.parseItem("Number Item: id=\"myItem\" state=\"" + itemValue + "\";"); + NumberExpression sut = ParserUtils.parseNumberExpression("(myItem * 3)", referenceItem.getRoot()); + assertThat(sut.eval(), equalTo(itemValue * 3)); + + // set item state to new value + itemValue = 17; + referenceItem.setStateFromDouble(itemValue); + assertThat(sut.eval(), equalTo(itemValue * 3)); + } + @Test public void comparingExpressions() throws IOException, Parser.Exception { comparingExpression(1, "<", 2, true); @@ -89,9 +102,9 @@ public class ExpressionEvalTest { comparingExpression(7, "!=", 8, true); comparingExpression(8, "!=", 8, false); - comparingExpression(9, "=>", 10, false); - comparingExpression(10, "=>", 10, true); - comparingExpression(11, "=>", 10, true); + comparingExpression(9, ">=", 10, false); + comparingExpression(10, ">=", 10, true); + comparingExpression(11, ">=", 10, true); comparingExpression(11,">", 12, false); comparingExpression(12,">", 12, false); @@ -99,7 +112,8 @@ public class ExpressionEvalTest { } private void comparingExpression(double left, String actualComparatorString, double right, boolean expectedResult) throws IOException, Parser.Exception { - LogicalExpression sut = ParserUtils.parseLogicalExpression(String.format("(%f %s %f)", left, actualComparatorString, right)); + String expression = String.format("(%s %s %s)", Double.toString(left), actualComparatorString, Double.toString(right)); + LogicalExpression sut = ParserUtils.parseLogicalExpression(expression); assertThat(sut.eval(), equalTo(expectedResult)); } diff --git a/eraser-base/src/test/java/de/tudresden/inf/st/eraser/ExpressionParserTest.java b/eraser-base/src/test/java/de/tudresden/inf/st/eraser/ExpressionParserTest.java index c01d93df0fe1e259b3be5d7f27e0c80a6e3ba2f6..a034d3c8f8699046c9c89d2f139f14880a80b704 100644 --- a/eraser-base/src/test/java/de/tudresden/inf/st/eraser/ExpressionParserTest.java +++ b/eraser-base/src/test/java/de/tudresden/inf/st/eraser/ExpressionParserTest.java @@ -19,9 +19,11 @@ import static org.junit.Assert.assertThat; */ public class ExpressionParserTest { + private static final String TRUE_EXPRESSION = "(0.0==0.0)"; + @Test public void plusExpression() throws IOException, Parser.Exception { - NumberExpression sut = ParserUtils.parseNumberExpression("(3 + 4)"); + NumberExpression sut = parseWithRoundTripNumberExpression("(3 + 4)"); assertThat(sut, instanceOf(AddExpression.class)); AddExpression addExpression = (AddExpression) sut; assertThat(addExpression.getLeftOperand(), instanceOf(NumberLiteralExpression.class)); @@ -34,7 +36,7 @@ public class ExpressionParserTest { @Test public void minusExpression() throws IOException, Parser.Exception { - NumberExpression sut = ParserUtils.parseNumberExpression("(12.5 - 4.1)"); + NumberExpression sut = parseWithRoundTripNumberExpression("(12.5 - 4.1)"); assertThat(sut, instanceOf(SubExpression.class)); SubExpression subExpression = (SubExpression) sut; assertThat(subExpression.getLeftOperand(), instanceOf(NumberLiteralExpression.class)); @@ -47,7 +49,7 @@ public class ExpressionParserTest { @Test public void multExpression() throws IOException, Parser.Exception { - NumberExpression sut = ParserUtils.parseNumberExpression("(0 * 0)"); + NumberExpression sut = parseWithRoundTripNumberExpression("(0 * 0)"); assertThat(sut, instanceOf(MultExpression.class)); MultExpression multExpression = (MultExpression) sut; assertThat(multExpression.getLeftOperand(), instanceOf(NumberLiteralExpression.class)); @@ -60,7 +62,7 @@ public class ExpressionParserTest { @Test public void divExpression() throws IOException, Parser.Exception { - NumberExpression sut = ParserUtils.parseNumberExpression("(1.1 / 0.0)"); + NumberExpression sut = parseWithRoundTripNumberExpression("(1.1 / 0.0)"); assertThat(sut, instanceOf(DivExpression.class)); DivExpression divExpression = (DivExpression) sut; assertThat(divExpression.getLeftOperand(), instanceOf(NumberLiteralExpression.class)); @@ -73,7 +75,7 @@ public class ExpressionParserTest { @Test public void powerExpression() throws IOException, Parser.Exception { - NumberExpression sut = ParserUtils.parseNumberExpression("(3 ^ 0.5)"); + NumberExpression sut = parseWithRoundTripNumberExpression("(3 ^ 0.5)"); assertThat(sut, instanceOf(PowerExpression.class)); PowerExpression powExpression = (PowerExpression) sut; assertThat(powExpression.getLeftOperand(), instanceOf(NumberLiteralExpression.class)); @@ -86,7 +88,7 @@ public class ExpressionParserTest { @Test public void parenthesizedExpression() throws IOException, Parser.Exception { - NumberExpression sut = ParserUtils.parseNumberExpression("(3)"); + NumberExpression sut = parseWithRoundTripNumberExpression("(3)"); assertThat(sut, instanceOf(ParenthesizedNumberExpression.class)); ParenthesizedNumberExpression parenExpression = (ParenthesizedNumberExpression) sut; assertThat(parenExpression.getOperand(), instanceOf(NumberLiteralExpression.class)); @@ -96,7 +98,7 @@ public class ExpressionParserTest { @Test public void complexExpression() throws IOException, Parser.Exception { - NumberExpression sut = ParserUtils.parseNumberExpression("((3 + 4) * (1 / (12 - 8)))"); + NumberExpression sut = parseWithRoundTripNumberExpression("((3 + 4) * (1 / (12 - 8)))"); assertThat(sut, instanceOf(MultExpression.class)); MultExpression multExpression = (MultExpression) sut; @@ -130,13 +132,17 @@ public class ExpressionParserTest { } @Test - public void expressionWithItem() { - try { - ParserUtils.parseNumberExpression("(myItem * 3)"); - } catch (IOException | Parser.Exception e) { - e.printStackTrace(); - Assert.fail(e.getMessage()); - } + public void expressionWithItem() throws IOException, Parser.Exception { + Item referenceItem = ParserUtils.parseItem("Number Item: id=\"myItem\";"); + NumberExpression sut = parseWithRoundTripNumberExpression("(myItem * 3)", referenceItem.getRoot()); + assertThat(sut, instanceOf(MultExpression.class)); + MultExpression multExpression = (MultExpression) sut; + assertThat(multExpression.getLeftOperand(), instanceOf(Designator.class)); + Designator left = (Designator) multExpression.getLeftOperand(); + assertThat(left.getItem(), equalTo(referenceItem)); + assertThat(multExpression.getRightOperand(), instanceOf(NumberLiteralExpression.class)); + NumberLiteralExpression right = (NumberLiteralExpression) multExpression.getRightOperand(); + assertThat(right.getValue(), equalTo(3.0)); } @Test @@ -145,12 +151,13 @@ public class ExpressionParserTest { comparingExpression("<=", ComparatorType.LessOrEqualThan, 3, 4); comparingExpression("==", ComparatorType.Equals, 5, 6); comparingExpression("!=", ComparatorType.NotEquals, 7, 8); - comparingExpression("=>", ComparatorType.GreaterOrEqualThan, 9, 10); + comparingExpression(">=", ComparatorType.GreaterOrEqualThan, 9, 10); comparingExpression(">", ComparatorType.GreaterThan, 11, 12); } private void comparingExpression(String actualComparatorString, ComparatorType expectedComparatorType, double left, double right) throws IOException, Parser.Exception { - LogicalExpression sut = ParserUtils.parseLogicalExpression(String.format("(%f %s %f)", left, actualComparatorString, right)); + String expression = String.format("(%s %s %s)", Double.toString(left), actualComparatorString, Double.toString(right)); + LogicalExpression sut = parseWithRoundTripLogicalExpression(expression); assertThat(sut, instanceOf(ComparingExpression.class)); ComparingExpression comparingExpression = (ComparingExpression) sut; assertThat(comparingExpression.getLeftOperand(), instanceOf(NumberLiteralExpression.class)); @@ -164,7 +171,7 @@ public class ExpressionParserTest { @Test public void notExpression() throws IOException, Parser.Exception { - LogicalExpression sut = ParserUtils.parseLogicalExpression("!(0==0)"); + LogicalExpression sut = parseWithRoundTripLogicalExpression("!" + TRUE_EXPRESSION); assertThat(sut, instanceOf(NotExpression.class)); NotExpression notExpression = (NotExpression) sut; checkZeroEqualsZero(notExpression.getOperand()); @@ -172,7 +179,7 @@ public class ExpressionParserTest { @Test public void andExpression() throws IOException, Parser.Exception { - LogicalExpression sut = ParserUtils.parseLogicalExpression("((0==0) & (0==0))"); + LogicalExpression sut = parseWithRoundTripLogicalExpression("(" + TRUE_EXPRESSION + " & " + TRUE_EXPRESSION + ")"); assertThat(sut, instanceOf(AndExpression.class)); AndExpression notExpression = (AndExpression) sut; checkZeroEqualsZero(notExpression.getLeftOperand()); @@ -181,7 +188,7 @@ public class ExpressionParserTest { @Test public void orExpression() throws IOException, Parser.Exception { - LogicalExpression sut = ParserUtils.parseLogicalExpression("((0==0) | (0==0))"); + LogicalExpression sut = parseWithRoundTripLogicalExpression("(" + TRUE_EXPRESSION + " | " + TRUE_EXPRESSION + ")"); assertThat(sut, instanceOf(OrExpression.class)); OrExpression notExpression = (OrExpression) sut; checkZeroEqualsZero(notExpression.getLeftOperand()); @@ -190,12 +197,34 @@ public class ExpressionParserTest { @Test public void parenthesizedLogicalExpression() throws IOException, Parser.Exception { - LogicalExpression sut = ParserUtils.parseLogicalExpression("((0==0))"); + LogicalExpression sut = parseWithRoundTripLogicalExpression("(" + TRUE_EXPRESSION + ")"); assertThat(sut, instanceOf(ParenthesizedLogicalExpression.class)); ParenthesizedLogicalExpression parenthesizedLogicalExpression = (ParenthesizedLogicalExpression) sut; checkZeroEqualsZero(parenthesizedLogicalExpression.getOperand()); } + private NumberExpression parseWithRoundTripNumberExpression(String numberExpression) throws IOException, Parser.Exception { + return parseWithRoundTripNumberExpression(numberExpression, null); + } + + private NumberExpression parseWithRoundTripNumberExpression(String numberExpression, Root root) throws IOException, Parser.Exception { + NumberExpression sut = ParserUtils.parseNumberExpression(numberExpression, root); + String first = sut.prettyPrint(); + NumberExpression reParsed = ParserUtils.parseNumberExpression(first, root); + String second = reParsed.prettyPrint(); + assertThat(first, equalTo(second)); + return sut; + } + + private LogicalExpression parseWithRoundTripLogicalExpression(String logicalExpression) throws IOException, Parser.Exception { + LogicalExpression sut = ParserUtils.parseLogicalExpression(logicalExpression); + String first = sut.prettyPrint(); + LogicalExpression reParsed = ParserUtils.parseLogicalExpression(first); + String second = reParsed.prettyPrint(); + assertThat(first, equalTo(second)); + return sut; + } + private void checkZeroEqualsZero(LogicalExpression logicalExpression) { assertThat(logicalExpression, instanceOf(ComparingExpression.class)); ComparingExpression comparingExpression = (ComparingExpression) logicalExpression; diff --git a/eraser-base/src/test/java/de/tudresden/inf/st/eraser/InfluxTest.java b/eraser-base/src/test/java/de/tudresden/inf/st/eraser/InfluxTest.java index a7d76202ffc30da22280f9a5ec95c643cb4aee42..9526a4db04802684261f820e807db35d6a47c24f 100644 --- a/eraser-base/src/test/java/de/tudresden/inf/st/eraser/InfluxTest.java +++ b/eraser-base/src/test/java/de/tudresden/inf/st/eraser/InfluxTest.java @@ -33,8 +33,8 @@ public class InfluxTest { @ClassRule public static InfluxDBContainer influxDbContainer = new InfluxDBContainer() .withDatabase(InfluxRoot.createDefault().getDbName()) - .withUsername(InfluxRoot.createDefault().getUser()) - .withPassword(InfluxRoot.createDefault().getPassword()); + .withAdmin(InfluxRoot.createDefault().getUser()) + .withAdminPassword(InfluxRoot.createDefault().getPassword()); @Test public void oneItem() { @@ -154,9 +154,10 @@ public class InfluxTest { point -> points.add((DoubleStatePoint) point)); } else { influxRoot = InfluxRoot.createDefault(); - // use zih vm2098 running influx + // use container running influx influxRoot.setDbName(InfluxTest.class.getSimpleName()); - influxRoot.setHostByName("vm2098.zih.tu-dresden.de"); + System.out.println("ports: " + influxDbContainer.getPortBindings() + " url: '" + influxDbContainer.getUrl() + "'"); + influxRoot.setHostByName(influxDbContainer.getUrl().replaceAll("^http://", "")); } mai.model.getRoot().setInfluxRoot(influxRoot); Assume.assumeTrue(influxRoot.influxAdapter().isConnected()); diff --git a/eraser-base/src/test/resources/tests/ppc3/input.eraser b/eraser-base/src/test/resources/tests/ppc3/input.eraser index 5fad695027d88ad41935092e7a3175206a3dfb2d..9a8a80d0d47d21df28a233b13135c43a98be3f8a 100644 --- a/eraser-base/src/test/resources/tests/ppc3/input.eraser +++ b/eraser-base/src/test/resources/tests/ppc3/input.eraser @@ -14,7 +14,7 @@ Image Item : id="image1" label="an Image Item" state="def" topic="item/str/image Location Item : id="location1" label="a Location Item" state="ghi" topic="item/str/location1/state"; Number Item : id="number1" label="a Number Item" state="456" topic="item/double/number1/state"; Player Item : id="player1" label="a Player Item" state="jkl" topic="item/str/player1/state"; -RollerShutter Item : id="rollerShutter1" label="a RollerShutter Item" state="false" topic="item/str/rs1/state"; +RollerShutter Item : id="rollerShutter1" label="a RollerShutter Item" state="32" topic="item/str/rs1/state"; String Item : id="string1" label="a String Item" state="mno" topic="item/str/string1/state"; Switch Item : id="switch1" label="a Switch Item" state="true" topic="item/bool/switch1/state"; Switch Item : id="switch2" label="a second Switch Item" state="OFF" topic="item/bool/switch2/state"; diff --git a/eraser-base/src/test/resources/tests/ppc3/output.eraser b/eraser-base/src/test/resources/tests/ppc3/output.eraser index 9f209db2cbcac9ee3d862a7d005cfc159432a0a3..f480a5d4ecb8144e53e02334acf39b7e6b629868 100644 --- a/eraser-base/src/test/resources/tests/ppc3/output.eraser +++ b/eraser-base/src/test/resources/tests/ppc3/output.eraser @@ -1,5 +1,5 @@ Color Item: id="color1" label="a Color Item" state="1,2,3" topic="item/hsb/color1/state" ; -Contact Item: id="contact1" label="a Contact Item" state="true" topic="item/bool/contact1/state" ; +Contact Item: id="contact1" label="a Contact Item" state="OPEN" topic="item/bool/contact1/state" ; Image Item: id="image1" label="an Image Item" state="def" topic="item/str/image1/state" ; Location Item: id="location1" label="a Location Item" state="ghi" topic="item/str/location1/state" ; DateTime Item: id="datetime1" label="a DateTime Item" state="1970-01-18T20:43:35.826Z" topic="item/date/datetime1/state" ; @@ -7,7 +7,7 @@ Item: id="default1" label="a Default Item" state="pqr" topic="item/str/default1/ Dimmer Item: id="dimmer1" label="a Dimmer Item" state="123.0" topic="item/double/dimmer1/state" ; Player Item: id="player1" label="a Player Item" state="jkl" topic="item/str/player1/state" ; Number Item: id="number1" label="a Number Item" state="456.0" topic="item/double/number1/state" ; -RollerShutter Item: id="rollerShutter1" label="a RollerShutter Item" state="false" topic="item/str/rs1/state" ; +RollerShutter Item: id="rollerShutter1" label="a RollerShutter Item" state="32.0" topic="item/str/rs1/state" ; String Item: id="string1" label="a String Item" state="mno" topic="item/str/string1/state" ; Switch Item: id="switch1" label="a Switch Item" state="ON" topic="item/bool/switch1/state" ; Switch Item: id="switch2" label="a second Switch Item" state="OFF" topic="item/bool/switch2/state" ; diff --git a/eraser-base/src/test/resources/tests/ppc4/input.eraser b/eraser-base/src/test/resources/tests/ppc4/input.eraser index f5c7afff39c0a2d617f293076a86a794fa24263f..8687f881951aa3bc8766e209a87432a235e2a72a 100644 --- a/eraser-base/src/test/resources/tests/ppc4/input.eraser +++ b/eraser-base/src/test/resources/tests/ppc4/input.eraser @@ -8,13 +8,13 @@ Group: id="my-empty-group" ; Color Item : id="color1" label="a Color Item" state="1,2,3" topic="item/hsb/color1/state"; DateTime Item : id="datetime1" label="a DateTime Item" state="1543415826" topic="item/date/datetime1/state"; -Contact Item : id="contact1" label="a Contact Item" state="true" topic="item/bool/contact1/state"; +Contact Item : id="contact1" label="a Contact Item" state="CLOSED" topic="item/bool/contact1/state"; Dimmer Item : id="dimmer1" label="a Dimmer Item" state="123" topic="item/double/dimmer1/state" controls=["color1", "datetime1"]; Image Item : id="image1" label="an Image Item" state="def" topic="item/str/image1/state" controls=[]; Location Item : id="location1" label="a Location Item" state="ghi" topic="item/str/location1/state"; Number Item : id="number1" label="a Number Item" state="456" topic="item/double/number1/state" controls=["string1"]; Player Item : id="player1" label="a Player Item" state="jkl" topic="item/str/player1/state"; -RollerShutter Item : id="rollerShutter1" label="a RollerShutter Item" state="false" topic="item/str/rs1/state"; +RollerShutter Item : id="rollerShutter1" label="a RollerShutter Item" state="0" topic="item/str/rs1/state"; Activity Item: id="activity"; String Item : id="string1" label="a String Item" state="mno" topic="item/str/string1/state"; Switch Item : id="switch1" label="a Switch Item" state="true" topic="item/bool/switch1/state" controls=["rollerShutter1"]; diff --git a/eraser-base/src/test/resources/tests/ppc4/output.eraser b/eraser-base/src/test/resources/tests/ppc4/output.eraser index 651bf7220435c60edee891b3a244a42cce706261..d4934300c2f7e3c0c8be65bf4f4932bbc4b7be52 100644 --- a/eraser-base/src/test/resources/tests/ppc4/output.eraser +++ b/eraser-base/src/test/resources/tests/ppc4/output.eraser @@ -1,5 +1,5 @@ Color Item: id="color1" label="a Color Item" state="1,2,3" topic="item/hsb/color1/state" ; -Contact Item: id="contact1" label="a Contact Item" state="true" topic="item/bool/contact1/state" ; +Contact Item: id="contact1" label="a Contact Item" state="CLOSED" topic="item/bool/contact1/state" ; Image Item: id="image1" label="an Image Item" state="def" topic="item/str/image1/state" ; Location Item: id="location1" label="a Location Item" state="ghi" topic="item/str/location1/state" ; DateTime Item: id="datetime1" label="a DateTime Item" state="1970-01-18T20:43:35.826Z" topic="item/date/datetime1/state" ; @@ -7,7 +7,7 @@ Item: id="default1" label="a Default Item" state="pqr" topic="item/str/default1/ Dimmer Item: id="dimmer1" label="a Dimmer Item" state="123.0" topic="item/double/dimmer1/state" controls=["color1", "datetime1"] ; Player Item: id="player1" label="a Player Item" state="jkl" topic="item/str/player1/state" ; Number Item: id="number1" label="a Number Item" state="456.0" topic="item/double/number1/state" controls=["string1"] ; -RollerShutter Item: id="rollerShutter1" label="a RollerShutter Item" state="false" topic="item/str/rs1/state" ; +RollerShutter Item: id="rollerShutter1" label="a RollerShutter Item" state="0.0" topic="item/str/rs1/state" ; Activity Item: id="activity" ; String Item: id="string1" label="a String Item" state="mno" topic="item/str/string1/state" ; Switch Item: id="switch1" label="a Switch Item" state="ON" topic="item/bool/switch1/state" controls=["rollerShutter1"] ; diff --git a/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/Application.java b/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/Application.java index c1c8c2f40e4a3847e4dbfa7ea4b95a406df4d1d2..4d8df7dfaa448fe34c6cef1ed51a30d4dd2bc1ae 100644 --- a/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/Application.java +++ b/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/Application.java @@ -6,12 +6,10 @@ import de.tudresden.inf.st.eraser.util.JavaUtils; import de.tudresden.inf.st.eraser.util.ParserUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.eclipse.jetty.http.HttpStatus; import spark.Request; import spark.Response; import spark.Spark; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -41,7 +39,7 @@ public class Application { private void createRules() { ObjectMapper mapper = new ObjectMapper(); - Spark.path("/", () -> Spark.before((request, response) -> logger.debug(request.pathInfo()))); + Spark.path("/", () -> Spark.before((request, response) -> logger.debug("{}: {}", request.pathInfo(), request.body()))); Spark.path("/activity", () -> { @@ -116,13 +114,12 @@ public class Application { OpenHAB2Model openHAB2Model = root.getOpenHAB2Model(); Item item = ParserUtils.parseItem(request.body()); if (!openHAB2Model.resolveItem(item.getID()).isPresent()) { - JavaUtils.ifPresentOrElse( - root.getOpenHAB2Model().resolveGroup(ParserUtils.UNKNOWN_GROUP_NAME), - group -> group.addItem(item), - () -> ParserUtils.createUnknownGroup(root.getOpenHAB2Model(), Collections.singletonList(item))); + root.getOpenHAB2Model().addNewItem(item); response.status(201); + return "OK"; + } else { + return makeError(response, 409, "Item already exists."); } - return "OK"; }); //--- GET /model/items/:identifier/state --- @@ -169,7 +166,7 @@ public class Application { private Object safeItemRoute(Request request, Response response, Function<Item, String> action) { return JavaUtils.ifPresentOrElseReturn(root.getOpenHAB2Model().resolveItem(request.params("identifier")), action, - () -> makeError(response, 404, "Item '" + request.body() + "' not found")); + () -> makeError(response, 404, "Item '" + request.params("identifier") + "' not found")); } private String makeHistory(Item item, Response response) { diff --git a/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/DummyDataCreator.java b/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/DummyDataCreator.java index e548a6bc95012ba72675131395b9956f4a84466f..65885823f7960465adadf30bbda4f82744c54903 100644 --- a/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/DummyDataCreator.java +++ b/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/DummyDataCreator.java @@ -3,6 +3,9 @@ package de.tudresden.inf.st.eraser.spark; import de.tudresden.inf.st.eraser.jastadd.model.*; import de.tudresden.inf.st.eraser.util.JavaUtils; +import java.time.Duration; +import java.time.Instant; + /** * Creates some activities and change events. * @@ -28,12 +31,13 @@ class DummyDataCreator { Item iris1 = getOrCreateColorItem("iris1", "Hue Iris 1"); Item go1 = getOrCreateColorItem("go1", "Hue Go 1"); Item go2 = getOrCreateColorItem("go2", "Hue Go 2"); - mlRoot.addChangeEvent(newRecognitionEvent(1, 1547637740, 1, + Instant now = Instant.now(); + mlRoot.addChangeEvent(newRecognitionEvent(1, now, 1, new ChangedItem("green", iris1), new ChangedItem("green", go1))); - mlRoot.addChangeEvent(newRecognitionEvent(2, 1547637750, 1)); - mlRoot.addChangeEvent(newRecognitionEvent(4, 1547623460, 2, + mlRoot.addChangeEvent(newRecognitionEvent(2, now.plusSeconds(1), 1)); + mlRoot.addChangeEvent(newRecognitionEvent(3, now.plusSeconds(3), 2, new ChangedItem("off", go2))); - mlRoot.addChangeEvent(newManualChangeEvent(1501146256, 5, + mlRoot.addChangeEvent(newManualChangeEvent(4, now.plusSeconds(17), new ChangedItem("green", iris1), new ChangedItem("red", go1), new ChangedItem("#EE7F00", go2))); @@ -51,23 +55,23 @@ class DummyDataCreator { }); } - private RecognitionEvent newRecognitionEvent(int identifier, long timestamp, int activityIdentifier, ChangedItem... changedItems) { + private RecognitionEvent newRecognitionEvent(int identifier, Instant when, int activityIdentifier, ChangedItem... changedItems) { RecognitionEvent result = new RecognitionEvent(); JavaUtils.ifPresentOrElse(root.resolveActivity(activityIdentifier), result::setActivity, () -> { throw new RuntimeException("No activity found for identifier " + activityIdentifier); }); - initChangeEvent(result, identifier, timestamp, changedItems); + initChangeEvent(result, identifier, when, changedItems); return result; } @SuppressWarnings("SameParameterValue") - private ManualChangeEvent newManualChangeEvent(int identifier, long timestamp, ChangedItem... changedItems) { + private ManualChangeEvent newManualChangeEvent(int identifier, Instant when, ChangedItem... changedItems) { ManualChangeEvent result = new ManualChangeEvent(); - initChangeEvent(result, identifier, timestamp, changedItems); + initChangeEvent(result, identifier, when, changedItems); return result; } - private void initChangeEvent(ChangeEvent result, int identifier, long timestamp, ChangedItem... changedItems) { + private void initChangeEvent(ChangeEvent result, int identifier, Instant when, ChangedItem... changedItems) { result.setIdentifier(identifier); - result.setTimestamp(timestamp); + result.setCreated(when); for (ChangedItem changedItem : changedItems) { result.addChangedItem(changedItem); } diff --git a/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/SimpleChangeEvent.java b/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/SimpleChangeEvent.java index 07894ede8b266b46bf4aa364bb4495d07abc8740..6a1c1a91bc3d8cdc28d44b07b766168e645786bf 100644 --- a/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/SimpleChangeEvent.java +++ b/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/SimpleChangeEvent.java @@ -3,6 +3,7 @@ package de.tudresden.inf.st.eraser.spark; import lombok.AllArgsConstructor; import lombok.Data; +import java.time.Instant; import java.util.List; /** @@ -13,7 +14,7 @@ import java.util.List; @Data @AllArgsConstructor public abstract class SimpleChangeEvent { - public final long timestamp; + public final Instant created; public final int identifier; public final List<SimpleChangedItem> changed_items; } diff --git a/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/SimpleManualChangeEvent.java b/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/SimpleManualChangeEvent.java index 71e43cdbbcce6eb65704d280540220db880ed3b6..685436cd376b993403db98d4a6192b4de94975d5 100644 --- a/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/SimpleManualChangeEvent.java +++ b/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/SimpleManualChangeEvent.java @@ -5,6 +5,7 @@ import de.tudresden.inf.st.eraser.util.JavaUtils; import lombok.Data; import lombok.EqualsAndHashCode; +import java.time.Instant; import java.util.List; import java.util.stream.Collectors; @@ -18,12 +19,12 @@ import java.util.stream.Collectors; public class SimpleManualChangeEvent extends SimpleChangeEvent { public final String type = "manual"; - public SimpleManualChangeEvent(long timestamp, int identifier, List<SimpleChangedItem> changedItems) { - super(timestamp, identifier, changedItems); + public SimpleManualChangeEvent(Instant created, int identifier, List<SimpleChangedItem> changedItems) { + super(created, identifier, changedItems); } static SimpleManualChangeEvent createFrom(ManualChangeEvent event) { - return new SimpleManualChangeEvent(event.getTimestamp(), event.getIdentifier(), + return new SimpleManualChangeEvent(event.getCreated(), event.getIdentifier(), JavaUtils.toStream(event.getChangedItems()).map(SimpleChangedItem::createFrom).collect(Collectors.toList())); } } diff --git a/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/SimpleRecognitionEvent.java b/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/SimpleRecognitionEvent.java index 587c3ae127da7cf3be1064a4351e36f6bbf81e7d..0a3821e4fc49d9fa2b2d0e75717da5477c0a3fa7 100644 --- a/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/SimpleRecognitionEvent.java +++ b/eraser.spark/src/main/java/de/tudresden/inf/st/eraser/spark/SimpleRecognitionEvent.java @@ -5,6 +5,7 @@ import de.tudresden.inf.st.eraser.util.JavaUtils; import lombok.Data; import lombok.EqualsAndHashCode; +import java.time.Instant; import java.util.List; import java.util.stream.Collectors; @@ -20,14 +21,14 @@ public class SimpleRecognitionEvent extends SimpleChangeEvent { public final String description; public final String type = "recognition"; - public SimpleRecognitionEvent(long timestamp, int identifier, List<SimpleChangedItem> changedItems, int activity, String description) { - super(timestamp, identifier, changedItems); + public SimpleRecognitionEvent(Instant created, int identifier, List<SimpleChangedItem> changedItems, int activity, String description) { + super(created, identifier, changedItems); this.activity = activity; this.description = description; } static SimpleRecognitionEvent createFrom(RecognitionEvent event) { - return new SimpleRecognitionEvent(event.getTimestamp(), event.getIdentifier(), + return new SimpleRecognitionEvent(event.getCreated(), event.getIdentifier(), JavaUtils.toStream(event.getChangedItems()).map(SimpleChangedItem::createFrom).collect(Collectors.toList()), event.getActivity().getIdentifier(), event.getActivity().getLabel()); } diff --git a/eraser.starter/build.gradle b/eraser.starter/build.gradle index ddb56ddf0b9a90f815f09b20d117485c48300c70..186e75a1e448ab9f0e61c5f8df2d3ac94da2f1f9 100644 --- a/eraser.starter/build.gradle +++ b/eraser.starter/build.gradle @@ -18,10 +18,13 @@ dependencies { compile project(':feedbackloop.analyze') compile project(':feedbackloop.plan') compile project(':feedbackloop.execute') - compile project(':feedbackloop.learner') + compile project(':feedbackloop.learner_backup') + compile project(':datasets') compile group: 'com.fasterxml.jackson.dataformat', name: 'jackson-dataformat-yaml', version: '2.9.8' compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.9.8' compile group: 'net.sourceforge.argparse4j', name: 'argparse4j', version: '0.8.1' + // compile project(':feedbackloop.learner') + } run { 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 b263fd586f95781c26345076e7a3132472f20eab..acc4b93a471d0b3a02676d37cb0314c85756ed1c 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 @@ -6,18 +6,15 @@ import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; 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.Learner; 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.LearnerHelper; -import de.tudresden.inf.st.eraser.feedbackloop.learner.LearnerImpl; +import de.tudresden.inf.st.eraser.feedbackloop.learner_backup.Learner; +import de.tudresden.inf.st.eraser.feedbackloop.learner_backup.MachineLearningImpl; import de.tudresden.inf.st.eraser.feedbackloop.plan.PlanImpl; 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; @@ -28,10 +25,10 @@ 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.ArrayList; +import java.util.List; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; @@ -113,53 +110,100 @@ public class EraserStarter { } } + // initialize backup learner + Learner learner = new Learner(); + // initialize activity recognition MachineLearningRoot machineLearningRoot = root.getMachineLearningRoot(); if (settings.activity.dummy) { - logger.info("Using dummy activity recognition"); + logger.info("Using dummy activity recognition, ignoring other settings for this"); machineLearningRoot.setActivityRecognition(DummyMachineLearningModel.createDefault()); } else { - logger.error("Reading activity recognition from file is not supported yet!"); - // TODO + 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().getFile()); + ExternalMachineLearningModel machineLearningModel = new ExternalMachineLearningModel(); + machineLearningModel.setEncoder(handler); + machineLearningModel.setDecoder(handler); + root.getMachineLearningRoot().setActivityRecognition(machineLearningModel); + + //Begin the Integration + Item item1=model.resolveItem("m_accel_x").get(); + Item item2=model.resolveItem("m_accel_y").get(); + Item item3=model.resolveItem("m_accel_z").get(); + Item item4=model.resolveItem("m_rotation_x").get(); + Item item5=model.resolveItem("m_rotation_y").get(); + Item item6=model.resolveItem("m_rotation_z").get(); + Item item7=model.resolveItem("w_accel_x").get(); + Item item8=model.resolveItem("w_accel_y").get(); + Item item9=model.resolveItem("w_accel_z").get(); + Item item10=model.resolveItem("w_rotation_x").get(); + Item item11=model.resolveItem("w_rotation_y").get(); + Item item12=model.resolveItem("w_rotation_z").get(); + //0.2717419,8.698134,4.471172,0.043741,0.515962,0.854318,1.8818425,4.9320555,8.145074,0.2374878,-0.032836914,0.3381958,working + item1.setStateFromString("0.2717419"); + item2.setStateFromString("8.698134"); + item3.setStateFromString("4.471172"); + item4.setStateFromString("0.043741"); + item5.setStateFromString("0.515962"); + item6.setStateFromString("0.854318"); + item7.setStateFromString("1.8818425"); + item8.setStateFromString("4.9320555"); + item9.setStateFromString("8.145074"); + item10.setStateFromString("0.2374878"); + item11.setStateFromString("-0.032836914"); + item12.setStateFromString("0.3381958"); + + ArrayList<Item> newData=new ArrayList<>(); + newData.add(item1); + newData.add(item2); + newData.add(item3); + newData.add(item4); + newData.add(item5); + newData.add(item6); + newData.add(item7); + newData.add(item8); + newData.add(item9); + newData.add(item10); + newData.add(item11); + newData.add(item12); + handler.newData(newData); + List<ItemPreference> preference=handler.classify().getPreferences(); + for(ItemPreference preference1 : preference){ + preference1.apply(); + } } // initialize preference learning if (settings.preference.dummy) { - logger.info("Using dummy preference learning"); + logger.info("Using dummy preference learning, ignoring other settings for this"); machineLearningRoot.setPreferenceLearning(DummyMachineLearningModel.createDefault()); } else { - logger.info("Reading preference learning from file {}", settings.preference.file); - Learner learner = new LearnerImpl(); - // there should be a method to load a model using an URL - boolean loadingSuccessful = false; - try (InputStream input = settings.preference.realURL().openStream()) { - loadingSuccessful = learner.loadModelFromFile(input, settings.preference.id, - Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), Collections.emptyList()); - } catch (IOException e) { - logger.catching(e); - loadingSuccessful = false; - } -// Model preference = learner.getTrainedModel(settings.preference.realURL(), settings.preference.id); - logger.debug("Loading of {} was {}", settings.preference.realURL(), loadingSuccessful ? "successful" : "failed"); - if (loadingSuccessful) { - EncogModel preference = learner.getTrainedModel(settings.preference.id); - NeuralNetworkRoot neuralNetwork = LearnerHelper.transform(preference); - if (neuralNetwork == null) { - logger.error("Could not create preference model, see possible previous errors."); - } else { - machineLearningRoot.setPreferenceLearning(neuralNetwork); - neuralNetwork.setOutputApplication(zeroToThree -> 33 * zeroToThree); - JavaUtils.ifPresentOrElse( - model.resolveItem(settings.preference.affectedItem), - item -> neuralNetwork.getOutputLayer().setAffectedItem(item), - () -> logger.error("Output item not set from value '{}'", settings.preference.affectedItem)); - } - } else { - // loading was not successful - logger.warn("Falling back to dummy preference learning"); - machineLearningRoot.setPreferenceLearning(DummyMachineLearningModel.createDefault()); + 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().getFile()); + ExternalMachineLearningModel machineLearningModel = new ExternalMachineLearningModel(); + machineLearningModel.setEncoder(handler); + machineLearningModel.setDecoder(handler); + root.getMachineLearningRoot().setPreferenceLearning(machineLearningModel); + //working,medium,240,70 + Item activity_item = model.resolveItem("activity").get(); + String activity=activity_item.getStateAsString(); + activity_item.setStateFromString(activity); + Item brightness_item = model.resolveItem("w_brightness").get(); + brightness_item.setStateFromString("medium"); + ArrayList<Item> newData1 = new ArrayList<>(); + newData1.add(activity_item); + newData1.add(brightness_item); + handler.newData(newData1); + List<ItemPreference> preference=handler.classify().getPreferences(); + for(ItemPreference preference1 : preference){ + preference1.apply(); } } + machineLearningRoot.getPreferenceLearning().connectItems(settings.preference.items); if (!machineLearningRoot.getActivityRecognition().check()) { logger.fatal("Invalid activity recognition!"); 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 dacbb4287bb16d2f4fcdb5ba2e2cb4b67cf6406e..09af126b0a66f54aa2b6c88fb04bda9cb7218cb3 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/src/main/resources/starter.eraser b/eraser.starter/src/main/resources/starter.eraser index 25505fe24d64d3ed08ecdc0a3d741625b25e46ad..a8dc0c5731c9f5ce106c55aa4d2a87fc8f85df4f 100644 --- a/eraser.starter/src/main/resources/starter.eraser +++ b/eraser.starter/src/main/resources/starter.eraser @@ -3,26 +3,38 @@ Number Item: id="datetime_month" label="Month" state="1" topic="datetime_month"; Number Item: id="datetime_day" label="Day" state="31" topic="datetime_day"; Number Item: id="datetime_hour" label="Hour" state="13" topic="datetime_hour"; Number Item: id="datetime_minute" label="Minute" state="37" topic="datetime_minute"; -Number Item: id="bias" label="bias item" state="1" ; -Activity Item: id="activity" ; +Number Item: id="bias" label="bias item" state="1"; + + +String Item: id="m_accel_x" label="" state="0.2717419" topic="m_accel_x"; +String Item: id="m_accel_y" label="" state="8.698134" topic="m_accel_y"; +String Item: id="m_accel_z" label="" state="4.471172" topic="m_accel_z"; +String Item: id="m_rotation_x" label="" state="0.043741" topic="m_rotation_x"; +String Item: id="m_rotation_y" label="" state="0.515962" topic="m_rotation_y"; +String Item: id="m_rotation_z" label="" state="0.854318" topic="m_rotation_z"; +String Item: id="w_accel_x" label="" state="1.8818425" topic="w_accel_x"; +String Item: id="w_accel_y" label="" state="4.9320555" topic="w_accel_y"; +String Item: id="w_accel_z" label="" state="8.145074" topic="w_accel_z"; +String Item: id="w_rotation_x" label="" state="0.2374878" topic="w_rotation_x"; +String Item: id="w_rotation_y" label="" state="-0.032836914" topic="w_rotation_y"; +String Item: id="w_rotation_z" label="" state="0.3381958" topic="w_rotation_y"; +String Item: id="w_brightness" label="" state="bright" topic="w_brightness"; +//String Item: id="activity" label="" state="lying" topic="activity"; +Activity Item: id="activity" topic="activity"; Group: id="Lights" items=["iris1_item"]; Group: id="Datetime" items=["datetime_month", "datetime_day", "datetime_hour", "datetime_minute"]; -Mqtt: incoming="oh2/out/" outgoing="oh2/in/" host="localhost:2883" ; +Mqtt: incoming="oh2/out/" outgoing="oh2/in/" host="localhost:1883" ; //Mqtt: incoming="oh2/out/" outgoing="oh2/in/" host="192.168.1.250" ; Influx: host="172.22.1.152" ; - +//"working", "walking", "dancing", "lying", "getting up", "reading" ML: activities={ - 0: "Open door in empty room", - 1: "Door closed in empty room", - 2: "Open door with person in room", - 3: "Door closed with person in room", - 4: "Working", - 5: "Watch TV", - 6: "Reading", - 7: "Listening to music", - 8: "Going to sleep", - 9: "Wake up" + 0: "working", + 1: "walking", + 2: "dancing", + 3: "lying", + 4: "getting up", + 5: "reading" } ; diff --git a/eraser.starter/starter-setting.yaml b/eraser.starter/starter-setting.yaml index f29763c43dfa4b789f872efc9eec88439930eff9..e8f438cf3eeb22d71d44c675e7328e61ba612562 100644 --- a/eraser.starter/starter-setting.yaml +++ b/eraser.starter/starter-setting.yaml @@ -24,28 +24,29 @@ load: # Model for activity recognition. If dummy is true, then the file parameter is ignored. activity: - # File to read in. Expected format = eg - file: activity.eg + # File to read in. Expected format = csv /Users/boqi/eraser/datasets + file: ../datasets/backup/activity_data.csv + external: true # Use dummy model in which the current activity is directly editable. Default: false. - dummy: true + dummy: false # Model id. Default: 1. id: 1 + # Item to change with classification result + affectedItem: activity # Model for preference learning. If dummy is true, then the file parameter is ignored. preference: - # File to read in. Expected format = eg - file: preference.eg + # File to read in. Expected format = 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. id: 1 # Items to connect to inputs items: - - datetime_month - - datetime_day - - datetime_hour - - datetime_minute -# - activity + - activity + - w_brightness # Item to change with classification result affectedItem: iris1_item diff --git a/feedbackloop.learner/.settings/org.eclipse.buildship.core.prefs b/feedbackloop.learner/.settings/org.eclipse.buildship.core.prefs deleted file mode 100644 index b1886adb46c085de842f1283c1a3c25151bfc988..0000000000000000000000000000000000000000 --- a/feedbackloop.learner/.settings/org.eclipse.buildship.core.prefs +++ /dev/null @@ -1,2 +0,0 @@ -connection.project.dir=.. -eclipse.preferences.version=1 diff --git a/feedbackloop.learner_backup/build.gradle b/feedbackloop.learner_backup/build.gradle index d0cf7913f010772f11df428d587fc351d8df634a..6199fa8da5b905d3d5d4cb02d6c6858218f3ffdd 100644 --- a/feedbackloop.learner_backup/build.gradle +++ b/feedbackloop.learner_backup/build.gradle @@ -8,6 +8,13 @@ dependencies { testCompile group: 'junit', name: 'junit', version: '4.12' testCompile group: 'org.hamcrest', name: 'hamcrest-junit', version: '2.0.0.0' compile group: 'org.encog', name: 'encog-core', version: '3.4' + implementation group: 'com.opencsv', name: 'opencsv', version: '4.1' + implementation group: 'commons-io', name: 'commons-io', version: '2.5' + implementation group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.5.8' + implementation group: 'org.apache.httpcomponents', name: 'fluent-hc', version: '4.5.8' + // https://mvnrepository.com/artifact/org.apache.spark/spark-mllib + //runtime group: 'org.apache.spark', name: 'spark-mllib_2.10', version: '1.3.0' + compile group: 'com.sparkjava', name: 'spark-core', version: '2.9.0' } run { diff --git a/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/CsvTransfer.java b/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/CsvTransfer.java new file mode 100644 index 0000000000000000000000000000000000000000..1c08268d59dd4003149e551d2e3e60895d30e3f6 --- /dev/null +++ b/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/CsvTransfer.java @@ -0,0 +1,60 @@ +package de.tudresden.inf.st.eraser.feedbackloop.learner_backup; + +import java.io.*; +import java.util.*; + +import com.opencsv.CSVReader; +import com.opencsv.CSVWriter; + + +public class CsvTransfer { + public static void main(String[] args){ + Learner learner=new Learner(); + learner.train("datasets/backup/activity_data.csv","datasets/backup/preference_data.csv"); + } + + //learner.train("datasets/backup/activity_data.csv","datasets/backup/preference_data.csv"); + /**private static final String CSV_FILE_PATH + = "datasets/backup/activity_data_example.csv"; + private static final String OUTPUT_FILE_PATH + = "datasets/backup/activity_data.csv"; + public static void main(String[] args) + { + addDataToCSV(CSV_FILE_PATH, OUTPUT_FILE_PATH); + } + public static void addDataToCSV(String input, String output) + { + File input_file = new File(input); + File output_file = new File(output); + try { + // create FileWriter object with file as parameter + FileReader reader = new FileReader(input_file); + CSVReader csv_reader = new CSVReader(reader); + String[] nextRecord; + FileWriter writer = new FileWriter(output_file); + CSVWriter csv_writer = new CSVWriter(writer, ',', + CSVWriter.NO_QUOTE_CHARACTER, + CSVWriter.DEFAULT_ESCAPE_CHARACTER, + CSVWriter.DEFAULT_LINE_END); + List<String[]> data = new ArrayList<String[]>(); + + while ((nextRecord = csv_reader.readNext()) != null) { + data.add(nextRecord); + + for (String cell : nextRecord) { + System.out.print(cell + "\t"); + } + System.out.println(); + } + csv_writer.writeAll(data); + writer.close(); + csv_reader.close(); + } + catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + }*/ +} + + diff --git a/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/DummyPreference.java b/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/DummyPreference.java new file mode 100644 index 0000000000000000000000000000000000000000..59f3ad9f43fd11eab315e145b1780d4152b82181 --- /dev/null +++ b/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/DummyPreference.java @@ -0,0 +1,75 @@ +package de.tudresden.inf.st.eraser.feedbackloop.learner_backup; +import com.opencsv.CSVWriter; + +import java.io.FileWriter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +public class DummyPreference { + private static String activity; //Activity: walking, reading, working, dancing, lying, getting up + private static String watch_brightness; //dark: <45; dimmer 45-70; bright >70; + private static String light_color_openhab_H; //red 7; green 120; blue 240; yellow 60; sky blue 180; purple 300; + private static String brightness_output; //1-100**/ + private static Random random = new Random(); + + public static void main(String[] args) { + creator(); + } + static void creator(){ + + + try{ + FileWriter writer = new FileWriter("datasets/backup/preference_data.csv",true); + CSVWriter csv_writer = new CSVWriter(writer, ',', + CSVWriter.NO_QUOTE_CHARACTER, + CSVWriter.DEFAULT_ESCAPE_CHARACTER, + CSVWriter.DEFAULT_LINE_END); + + + //activity="walking" green + activity ="walking"; + + // activity ="reading"; + csv_writer.writeAll(generator("walking","green")); + csv_writer.writeAll(generator("reading","sky blue")); + csv_writer.writeAll(generator("working","blue")); + csv_writer.writeAll(generator("dancing","purple")); + csv_writer.writeAll(generator("lying","red")); + csv_writer.writeAll(generator("getting up","yellow")); + csv_writer.close(); + writer.close(); + }catch (IOException e){e.printStackTrace();} + } + static List<String[]> generator(String activity_input, String color){ + List<String[]> data = new ArrayList<String[]>(); + activity = activity_input; + light_color_openhab_H =color; + //100 walking with different lighting intensity + for (int i=0; i<100; i++){ + String[] add_data = new String[4]; + int brightness = random.nextInt(3000); + System.out.println(brightness); + if (brightness<45){ + watch_brightness = "dark"; + brightness_output ="100"; + }else if(45<=brightness && brightness<200){ + watch_brightness = "dimmer"; + brightness_output ="40"; + }else if( 200<=brightness && brightness<1000){ + watch_brightness = "medium"; + brightness_output ="70"; + }else{ + watch_brightness = "bright"; + brightness_output ="0"; + } + add_data[0] = activity; + add_data[1] = watch_brightness; + add_data[2] = light_color_openhab_H; + add_data[3] = brightness_output; + data.add(add_data); + } + return data; + } +} 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 c728eed8e76b70b64c74455633edec388e16ce3e..5d8021d8faf7519d9ec15305f0752cfbcd742a0c 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,16 +1,15 @@ package de.tudresden.inf.st.eraser.feedbackloop.learner_backup; import java.io.File; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.Arrays; - -import com.sun.javafx.tools.packager.Log; -import org.encog.ConsoleStatusReportable; +import java.io.IOException; +//import java.util.ArrayList; +//import com.sun.javafx.tools.packager.Log; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +//import org.encog.ConsoleStatusReportable; import org.encog.Encog; -import org.encog.bot.BotUtil; -import org.encog.ml.MLInput; -import org.encog.ml.MLRegression; +import org.encog.ml.MLClassification; +//import org.encog.ml.MLRegression; import org.encog.ml.data.MLData; import org.encog.ml.data.versatile.NormalizationHelper; import org.encog.ml.data.versatile.VersatileMLDataSet; @@ -22,8 +21,6 @@ import org.encog.ml.factory.MLMethodFactory; import org.encog.ml.model.EncogModel; import org.encog.neural.networks.BasicNetwork; import org.encog.util.csv.CSVFormat; -import org.encog.util.csv.ReadCSV; -import org.encog.util.simple.EncogUtility; import static org.encog.persist.EncogDirectoryPersistence.*; public class Learner { @@ -31,129 +28,163 @@ public class Learner { /** * intial train * */ - private String csv_url_activity; - private String csv_url_perference; - private String save_activity_model_file = "datasets/backup/activity_model.eg"; - private String save_perference_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 souce; - private VersatileMLDataSet data; - private EncogModel model; + private VersatileMLDataSet a_data; + private VersatileMLDataSet p_data; + private EncogModel a_model; + private EncogModel p_model; private NormalizationHelper activity_helper; private NormalizationHelper preference_helper; - private MLRegression best_method; - private String[] new_data; - private String activity_result; - private String preference_result; + private MLClassification a_best_method; + private MLClassification p_best_method; + private final Logger logger = LogManager.getLogger(Learner.class); + + 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; + VersatileDataSource a_souce; + String csv_url_activity; + csv_url_activity = activity_csv_url; this.csv_file = new File(csv_url_activity); - souce = new CSVDataSource(csv_file,false,CSVFormat.DECIMAL_POINT); - data = new VersatileMLDataSet(souce); - data.defineSourceColumn("monat", 0, ColumnType.continuous); - data.defineSourceColumn("day", 1, ColumnType.continuous); - data.defineSourceColumn("hour", 2, ColumnType.continuous); - data.defineSourceColumn("minute", 3, ColumnType.continuous); - ColumnDefinition outputColumn = data.defineSourceColumn("labels", 4, ColumnType.continuous); - data.defineSingleOutputOthersInput(outputColumn); - data.analyze(); - System.out.println("get data "); - model = new EncogModel(data); - model.selectMethod(data, MLMethodFactory.TYPE_FEEDFORWARD); - data.normalize(); - activity_helper = data.getNormHelper(); - System.out.println(activity_helper.toString()); + a_souce = new CSVDataSource(csv_file,false,CSVFormat.DECIMAL_POINT); + a_data = new VersatileMLDataSet(a_souce); + String[] activity_inputs={"m_accel_x","m_accel_y", "m_accel_z", + "m_rotation_x","m_rotation_y", "m_rotation_z", + "w_accel_x","w_accel_y", "w_accel_z", + "w_rotation_x","w_rotation_y","w_rotation_z" + }; + for(int i=0; i < activity_inputs.length; i++){ + a_data.defineSourceColumn(activity_inputs[i], i, ColumnType.continuous); + } + ColumnDefinition outputColumn = a_data.defineSourceColumn("labels", 12, ColumnType.nominal); + a_data.defineSingleOutputOthersInput(outputColumn); + a_data.analyze(); + a_model = new EncogModel(a_data); + a_model.selectMethod(a_data, MLMethodFactory.TYPE_FEEDFORWARD); + a_data.normalize(); + activity_helper = a_data.getNormHelper(); } - private void perferenceDataAnalyser(String perference_csv_url){ - this.csv_url_perference = perference_csv_url; - this.csv_file = new File(this.csv_url_perference); - souce = new CSVDataSource(csv_file,false,CSVFormat.DECIMAL_POINT); - data = new VersatileMLDataSet(souce); - data.defineSourceColumn("activity", 0, ColumnType.continuous); - data.defineSourceColumn("brightness", 1, ColumnType.continuous); - data.defineSourceColumn("time", 2, ColumnType.continuous); - data.defineSourceColumn("minute", 3, ColumnType.continuous); - ColumnDefinition outputColumn = data.defineSourceColumn("labels", 4, ColumnType.continuous); - data.defineSingleOutputOthersInput(outputColumn); - data.analyze(); - model = new EncogModel(data); - model.selectMethod(data, MLMethodFactory.TYPE_FEEDFORWARD); - //model.setReport(new ConsoleStatusReportable()); - data.normalize(); - preference_helper = data.getNormHelper(); - System.out.println(activity_helper.toString()); + private void preferenceDataAnalyser(String preference_csv_url){ + VersatileDataSource p_source; + String csv_url_preference; + csv_url_preference = preference_csv_url; + this.csv_file = new File(csv_url_preference); + p_source = new CSVDataSource(csv_file,false,CSVFormat.DECIMAL_POINT); + p_data = new VersatileMLDataSet(p_source); + p_data.defineSourceColumn("activity", 0, ColumnType.nominal); + p_data.defineSourceColumn("w_brightness", 1, ColumnType.nominal); + ColumnDefinition outputColumn1 = p_data.defineSourceColumn("label1", 2, ColumnType.continuous); + ColumnDefinition outputColumn2 = p_data.defineSourceColumn("label2", 3, ColumnType.continuous); + ColumnDefinition[] outputs = new ColumnDefinition[2]; + outputs[0] = outputColumn1; + outputs[1] = outputColumn2; + p_data.defineMultipleOutputsOthersInput(outputs); + p_data.analyze(); + p_model = new EncogModel(p_data); + p_model.selectMethod(p_data, MLMethodFactory.TYPE_FEEDFORWARD); + p_data.normalize(); + preference_helper = p_data.getNormHelper(); } - void train(String activity_url,String perference_url){ + void train(String activity_url,String preference_url){ activity_train(activity_url); - Log.info("activity training finished"); - preference_train(perference_url); - Log.info("preference training finished"); + preference_train(preference_url); + Encog.getInstance().shutdown(); } - private void activity_train(String activity_csv_url){ + + void activity_train(String activity_csv_url){ + logger.info("Activity training is beginning ... ..."); activityDataAnalyser(activity_csv_url); - model.holdBackValidation(0.3, true, 1001); - model.selectTrainingType(data); - best_method = (MLRegression)model.crossvalidate(5, true); - System.out.println(best_method); + a_model.holdBackValidation(0.3, true, 1001); + a_model.selectTrainingType(a_data); + a_best_method = (MLClassification)a_model.crossvalidate(5, true); saveEncogModel(save_activity_model_file); + logger.info("Activity training is finished ... ..."); + Encog.getInstance().shutdown(); } - private void preference_train(String perfence_csv_url){ - perferenceDataAnalyser(perfence_csv_url); - model.holdBackValidation(0.3, true, 1001); - model.selectTrainingType(data); - best_method = (MLRegression)model.crossvalidate(5, true); - System.out.println(best_method); - saveEncogModel(save_perference_model_file); + void preference_train(String prefence_csv_url){ + logger.info("Preference training is beginning ... ..."); + preferenceDataAnalyser(prefence_csv_url); + p_model.holdBackValidation(0.3, true, 1001); + p_model.selectTrainingType(p_data); + p_best_method = (MLClassification)p_model.crossvalidate(5, true); + saveEncogModel(save_preference_model_file); + logger.info("Preference training is finished ... ..."); + Encog.getInstance().shutdown(); } String[] predictor(String[] new_data){ - this.new_data = new_data; - activityDataAnalyser("datasets/backup/activity_data.csv"); - perferenceDataAnalyser("datasets/backup/preference_data.csv"); - String[] result = new String[2]; - result[0] = activity_predictor(); - result[1] = perference_predictor(); + String[] preference_data = new String[2]; + String[] result = new String[3]; + String[] activity_data= new String[12]; + for(int i=0; i<new_data.length;i++){ + activity_data[i]=new_data[i]; + } + result[0] = activity_predictor(activity_data); + preference_data[0]=result[0]; + preference_data[1]=new_data[12]; + result[1] = preference_predictor(preference_data)[0]; + result[2] = preference_predictor(preference_data)[1]; Encog.getInstance().shutdown(); return result; } - private String activity_predictor(){ - BasicNetwork activity_method = (BasicNetwork) loadObject(new File(save_activity_model_file)); + String activity_predictor(String[] new_data){ + logger.info("Activity predicting ... ..."); + String activity_result; + activityDataAnalyser("../datasets/backup/activity_data.csv"); + BasicNetwork activity_method = (BasicNetwork) loadObject(save_activity_model_file); MLData input = activity_helper.allocateInputVector(); - String[] activity_new_data = new String[4]; - activity_new_data[0] = new_data[0]; - activity_new_data[1] = new_data[1]; - activity_new_data[2] = new_data[2]; - activity_new_data[3] = new_data[3]; - activity_helper.normalizeInputVector(activity_new_data,input.getData(),false); + activity_helper.normalizeInputVector(new_data,input.getData(),false); MLData output = activity_method.compute(input); - System.out.println("input:"+input); - System.out.println("output"+output); activity_result = activity_helper.denormalizeOutputVectorToString(output)[0]; - System.out.println("output activity"+ activity_result); + Encog.getInstance().shutdown(); + logger.debug("Activity Predictor result is: {}",activity_result); return activity_result; } - private String perference_predictor(){ - BasicNetwork preference_method = (BasicNetwork)loadObject(new File(save_perference_model_file)); + String[] preference_predictor(String[] new_data){ + logger.info("Activity predicting ... ..."); + String[] preference_result; + preference_result = new String[2]; + preferenceDataAnalyser("../datasets/backup/preference_data.csv"); + BasicNetwork preference_method = (BasicNetwork)loadObject(save_preference_model_file); MLData input = preference_helper.allocateInputVector(); - String[] perference_new_data = new String[4]; - perference_new_data[0] = activity_result; - perference_new_data[1] = new_data[4]; - perference_new_data[2] = new_data[5]; - perference_new_data[3] = new_data[6]; - preference_helper.normalizeInputVector(perference_new_data, input.getData(),false); + preference_helper.normalizeInputVector(new_data, input.getData(),false); MLData output = preference_method.compute(input); - preference_result = preference_helper.denormalizeOutputVectorToString(output)[0]; + preference_result[0] = preference_helper.denormalizeOutputVectorToString(output)[0]; + preference_result[1] = preference_helper.denormalizeOutputVectorToString(output)[1]; + Encog.getInstance().shutdown(); + logger.debug("Preference Predictor result is, Color: {}",Math.round(Float.valueOf(preference_result[0]))); + logger.debug("Preference Predictor result is, Brightness: {} ",Math.round(Float.valueOf(preference_result[1]))); return preference_result; } + 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); + } - private void saveEncogModel(String model_file_url){ - saveObject(new File(model_file_url), this.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 new file mode 100644 index 0000000000000000000000000000000000000000..dc16aa2353ea216a49d2d1e75d8cfcff4d36abbc --- /dev/null +++ b/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/MachineLearningImpl.java @@ -0,0 +1,211 @@ +package de.tudresden.inf.st.eraser.feedbackloop.learner_backup; + + + +//import com.sun.javafx.tools.packager.Log; +import de.tudresden.inf.st.eraser.jastadd.model.*; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.time.Instant; +import java.util.*; +import java.util.stream.Collectors; + + +public class MachineLearningImpl implements MachineLearningDecoder, MachineLearningEncoder { + + private List<Item> target_item_list; + private List<Item> relevant_item_list; + private String[] preference_result; + + private Root root; + private final Logger logger = LogManager.getLogger(MachineLearningImpl.class); + private final Learner learner; + private final int goal; + + public static final int GOAL_ACTIVITY_PHONE_AND_WATCH = 1; + public static final int GOAL_PREFERENCE_BRIGHTNESS_IRIS = 2; + public String activity_result; + private String[] activites= new String[]{"working", "walking", "dancing", "lying", "getting up", "reading"}; + public MachineLearningImpl(Learner learner, int goal) { + this.learner = learner; + this.goal = goal; + } + + @Override + public void setKnowledgeBaseRoot(Root root) { + this.root = root; + updateItems(); + } + + private void updateItems() { + OpenHAB2Model model = root.getOpenHAB2Model(); + List<String> targetItemNames, relevantItemNames; + switch (this.goal) { + case GOAL_ACTIVITY_PHONE_AND_WATCH: + targetItemNames = Collections.singletonList("activity"); + relevantItemNames = Arrays.asList( + "m_accel_x", + "m_accel_y", + "m_accel_z", + "m_rotation_x", + "m_rotation_y", + "m_rotation_z", + "w_accel_x", + "w_accel_y", + "w_accel_z", + "w_rotation_x", + "w_rotation_y", + "w_rotation_z" + ); + break; + case GOAL_PREFERENCE_BRIGHTNESS_IRIS: + targetItemNames = Collections.singletonList("iris1_item"); + relevantItemNames = Arrays.asList( + "activity", + "w_brightness" + ); + break; + default: + logger.error("Unknown goal value ({}) set", this.goal); + targetItemNames = Collections.emptyList(); + relevantItemNames = Collections.emptyList(); + } + target_item_list = targetItemNames.stream() + .map(name -> resolve(model, name)) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + relevant_item_list = relevantItemNames.stream() + .map(name -> resolve(model, name)) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + } + + private Item resolve(OpenHAB2Model model, String id) { + Optional<Item> maybeItem = model.resolveItem(id); + if (maybeItem.isPresent()) { + return maybeItem.get(); + } else { + logger.warn("Could not find item with id {}", id); + return null; + } + } + + @Override + public void newData(List<Item> changedItems) { + /* String topic = changedItems.get(0).getTopic().toString(); + if(topic.equals("oh2/samsung/items1")){ + new_data[0]=changedItems.get(0).influxMeasurementName(); + } + model.getOpenHAB2Model().items(); + Item iris_item=model.getOpenHAB2Model().resolveItem("iris_item").get(); + iris_item.getStateAsString();*/ + /* FIXME either save state of unchanged items here (if only changed items are reported) <- pull model + or let knowledge base pass all relevant items <- push model + */ + if(this.goal==GOAL_ACTIVITY_PHONE_AND_WATCH){ + String[] new_data = new String[12]; + for (int i =0; i< new_data.length; i++){ + new_data[i] ="0"; + } + for(Item item: changedItems){ + int i = 0; + for(Item item1: relevant_item_list){ + if(item.getTopic().toString().equals(item1.getTopic().toString())){ + new_data[i]=item.getStateAsString(); + } + i++; + } + } + this.activity_result = learner.activity_predictor(new_data); + + }else if(this.goal==GOAL_PREFERENCE_BRIGHTNESS_IRIS){ + String[] new_data = new String[2]; + for(Item item: changedItems){ + if(root.getOpenHAB2Model().getActivityItem().equals(item)) + { + String test=item.getStateAsString(); + int index = Math.round(Float.valueOf(test)); + new_data[0]=activites[index]; + } + if(item.getID().equals("w_brightness")){ + new_data[1]=item.getStateAsString(); + } + } + this.preference_result=learner.preference_predictor(new_data); + } + } + + @Override + public List<Item> getTargets() { + return target_item_list; + } + + @Override + public List<Item> getRelevantItems() { + return relevant_item_list; + } + + @Override + public void triggerTraining() { + logger.debug("Ignore trigger training call"); + } + + @Override + public Instant lastModelUpdate() { + return null; + } + + @Override + public MachineLearningResult classify() { + switch (this.goal) { + case GOAL_ACTIVITY_PHONE_AND_WATCH: + String activityStringValue = activity_result; + Item activityItem = resolve(this.root.getOpenHAB2Model(), "activity"); + //activityItem.setStateFromString(activityStringValue); + // FIXME how to translate activityStringValue to a number? or should activity item state better be a String? + for (int i=0; i< activites.length;i++){ + if(activites[i].equals(activityStringValue)){ + activityItem.setStateFromString(String.valueOf(i)); + } + } + 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]}; + // FIXME what is the meaning of result[1] and result[2] + Item iris1 = resolve(this.root.getOpenHAB2Model(), "iris1_item"); + int color = 0; + int brightness = 0; + if (preference_result != null){ + color = Math.round(Float.valueOf(preference_result[0])); + brightness = Math.round(Float.valueOf(preference_result[1])); + } + + ItemPreference classifiedPreference = new ItemPreferenceColor(iris1, TupleHSB.of(color, 100, brightness)); + return new MachineLearningResultImpl(classifiedPreference); + default: + logger.error("Unknown goal value ({}) set in classify", this.goal); + return new EmptyMachineLearningResult(); + } + } + + public void initActivities(String filenameOfCsv) { + logger.debug(filenameOfCsv); + learner.activity_train(filenameOfCsv); + } + + public void initPreferences(String filenameOfCsv) { + learner.preference_train(filenameOfCsv); + } + + class EmptyMachineLearningResult implements MachineLearningResult { + + @Override + public List<ItemPreference> getPreferences() { + return Collections.emptyList(); + } + } + +} diff --git a/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/MachineLearningResultImpl.java b/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/MachineLearningResultImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..61d483a566255d51ce424d23adb014df1eec8109 --- /dev/null +++ b/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/MachineLearningResultImpl.java @@ -0,0 +1,26 @@ +package de.tudresden.inf.st.eraser.feedbackloop.learner_backup; + +import de.tudresden.inf.st.eraser.jastadd.model.ItemPreference; +import de.tudresden.inf.st.eraser.jastadd.model.MachineLearningResult; + +import java.util.Collections; +import java.util.List; + +/** + * TODO: Add description. + * + * @author rschoene - Initial contribution + */ +public class MachineLearningResultImpl implements MachineLearningResult { + + private final ItemPreference preference; + + MachineLearningResultImpl(ItemPreference preference) { + this.preference = preference; + } + + @Override + public List<ItemPreference> getPreferences() { + return Collections.singletonList(preference); + } +} diff --git a/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/Main.java b/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/Main.java index 8ef9e85f7e0bcb95e5f430e87fe48ac81fad2733..2580847d5ace8e832bde76159dad2e85974115a2 100644 --- a/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/Main.java +++ b/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/Main.java @@ -1,6 +1,9 @@ package de.tudresden.inf.st.eraser.feedbackloop.learner_backup; -import de.tudresden.inf.st.eraser.jastadd.model.*; +import org.encog.util.csv.CSVFormat; +import org.encog.util.csv.ReadCSV; + +import java.util.Arrays; public class Main { @@ -8,22 +11,154 @@ public class Main { /** * new data from KB * */ - String[] new_data = new String[7]; - new_data[0]="7"; - new_data[1]="20"; - new_data[2]="12"; - new_data[3]="13"; - new_data[4]="7"; - new_data[5]="25"; - new_data[6]="12"; + //ReaderCSV reader = new ReaderCSV("datasets/backup/activity_data.csv","preference"); + //reader.updater(); + Learner learner=new Learner(); + //learner.preference_train("../datasets/backup/preference_data.csv"); + //learner.train("datasets/backup/activity_data.csv","datasets/backup/preference_data.csv"); + //0.5793968,1.2126632,-4.6244006,-0.030779,0.801127,0.590978,-3.1411927,-0.93373865,-0.31124622,-0.35992432,0.33746338,-0.79608154,dancing + /**String[] new_data = new String[12]; + new_data[0]="0.5793968"; + new_data[1]="1.2126632"; + new_data[2]="-4.6244006"; + new_data[3]="-0.030779"; + new_data[4]="0.801127"; + new_data[5]="0.590978"; + new_data[6]="-3.1411927"; + new_data[7]="-0.93373865"; + new_data[8]="-0.31124622"; + new_data[9]="-0.35992432"; + new_data[10]="0.33746338"; + new_data[11]="-0.79608154"; + + String result =learner.activity_predictor(new_data); + System.out.println(result); + + List k=new ArrayList(); + + k.add(new_data);*/ + + //learner.preference_train("datasets/backup/preference_data.csv"); + //learner.train("datasets/backup/activity_data.csv","datasets/backup/preference_data.csv"); + //walking,medium,120,70 + //reading,bright,180,0 + + //activity_validation_learner(); + //0.10654198,8.6574335,4.414908,0.040269,0.516884,0.853285,1.2066777,-1.1444284,9.648633,1.2207031E-4,-0.055358887,0.5834961 working + String[] new_data = new String[12]; + new_data[0]="0.010773907"; + new_data[1]="8.610746"; + new_data[2]="4.4963107"; + new_data[3]="0.047136"; + new_data[4]="0.515427"; + new_data[5]="0.852877"; + new_data[6]="0.9720459"; + new_data[7]="-1.3694834"; + new_data[8]="9.696517"; + new_data[9]="-0.0056152344"; + new_data[10]="-0.049438477"; + new_data[11]="0.5576782"; + //0.010773907,8.610746,4.4963107,0.047136,0.515427,0.852877,0.9720459,-1.3694834,9.696517,-0.0056152344,-0.049438477,0.5576782 working + //0.9999999988939648,-0.9995820798966354,-0.9999999999999997,-0.9999988062118802,-0.9974031940544938,-1.0 + + //String result =learner.activity_predictor(new_data); + //System.out.println(result); + + /**String[] new_data_1 =new String[12]; + //-2.6252422,8.619126,-2.7030537,0.552147,0.5078,0.450302,-8.1881695,-1.2641385,0.038307227,-0.34222412,0.49102783,-0.016540527,walking + new_data_1[0]="-2.6252422"; + new_data_1[1]="8.619126"; + new_data_1[2]="-2.7030537"; + new_data_1[3]="0.552147"; + new_data_1[4]="0.5078"; + new_data_1[5]="0.450302"; + new_data_1[6]="-8.1881695"; + new_data_1[7]="-1.2641385"; + new_data_1[8]="0.038307227"; + new_data_1[9]="-0.34222412"; + new_data_1[10]="0.49102783"; + new_data_1[11]="-0.016540527"; + String result1 =learner.activity_predictor(new_data_1); + System.out.println(result1); /** * learner.train(activity_csv_url, preference_data_url) * learner.predictor get the result from predictor for new data * */ + /**String[] new_data_2 = new String[12]; + //-6.5565214,5.717354,5.6658783,0.185591,0.464146,0.413321,-20.580557,3.8498764,-0.4261679,0.7647095,-0.4713745,0.23999023,dancing + new_data_2[0]="-6.5565214"; + new_data_2[1]="5.717354"; + new_data_2[2]="5.6658783"; + new_data_2[3]="0.185591"; + new_data_2[4]="0.464146"; + new_data_2[5]="0.413321"; + new_data_2[6]="-20.580557"; + new_data_2[7]="3.8498764"; + new_data_2[8]="-0.4261679"; + new_data_2[9]="0.7647095"; + new_data_2[10]="-0.4713745"; + new_data_2[11]="0.23999023"; + + String[] new_data_3 = new String[12]; + new_data_3[0]="-5.3881507"; + new_data_3[1]="0.25378537"; + new_data_3[2]="7.69257"; + new_data_3[3]="-0.122974"; + new_data_3[4]="0.247411"; + new_data_3[5]="0.439031"; + new_data_3[6]="4.9224787"; + new_data_3[7]="-10.601525"; + new_data_3[8]="-4.927267"; + new_data_3[9]="0.7946167"; + new_data_3[10]="0.35272217"; + new_data_3[11]="0.16192627"; + //"-5.3881507","0.25378537","7.69257","-0.122974","0.247411","0.439031","4.9224787","-10.601525","-4.927267","0.7946167","0.35272217","0.16192627","lying" Learner learner=new Learner(); - //learner.train("datasets/activity_data.csv", "datasets/preference_data.csv"); - String[] result = learner.predictor(new_data); + //learner.train("datasets/backup/activity_data.csv", "datasets/preference_data.csv"); + String[] result = learner.predictor(new_data_3); System.out.println("activity is:" + result[0]); - System.out.println("perference is: "+ result[1]); + //System.out.println("perference is: "+ result[1]);**/ + } + public static void activity_validation_learner(){ + ReadCSV csv = new ReadCSV("datasets/backup/activity_data.csv", false, CSVFormat.DECIMAL_POINT); + String[] line = new String[12]; + Learner learner=new Learner(); + int wrong=0; + int right=0; + while(csv.next()) { + StringBuilder result = new StringBuilder(); + line[0] = csv.get(0); + line[1] = csv.get(1); + line[2] = csv.get(2); + line[3] = csv.get(3); + line[4] = csv.get(4); + line[5] = csv.get(5); + line[6] = csv.get(6); + line[7] = csv.get(7); + line[8] = csv.get(8); + line[9] = csv.get(9); + line[10] = csv.get(10); + line[11] = csv.get(11); + String correct = csv.get(12); + String irisChosen = learner.predictor(line)[0]; + result.append(Arrays.toString(line)); + result.append(" -> predicted: "); + result.append(irisChosen); + result.append("(correct: "); + result.append(correct); + result.append(")"); + if (irisChosen.equals(correct)!=true){ + System.out.println(correct); + System.out.println(irisChosen); + ++wrong; + }else{ + ++right; + } + System.out.println(result.toString()); + } + System.out.println("wrong number"+wrong); + System.out.println("right number"+right); + //double validation = (double(right))/(double(wrong+right)); + //System.out.println("%.2f"+validation); } } diff --git a/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/ReaderCSV.java b/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/ReaderCSV.java new file mode 100644 index 0000000000000000000000000000000000000000..76c1ce791b00843befc9ed8b9d0f1941532ac386 --- /dev/null +++ b/feedbackloop.learner_backup/src/main/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/ReaderCSV.java @@ -0,0 +1,116 @@ +package de.tudresden.inf.st.eraser.feedbackloop.learner_backup; + +import java.awt.*; +import java.io.FileReader; +import java.io.*; +import java.util.Arrays; + +import com.opencsv.CSVReader; +import org.apache.http.client.fluent.Request; +import org.apache.http.HttpResponse; +import org.apache.http.entity.ContentType; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReentrantLock; + +public class ReaderCSV{ + + //read every 5 s from csv + //activity CSV + /** + * Col 1: smartphone acceleration x + * Col 2: smartphone acceleration y + * Col 3: smartphone acceleration z + * Col 4: smartphone rotation x + * Col 5: smartphone rotation y + * Col 6: smartphone rotation z + * Col 7: watch acceleration x + * Col 8: watch acceleration y + * Col 9: watch acceleration z + * Col 10: watch rotation x + * Col 11: watch rotation y + * Col 12: watch rotation z/*/ + //preference CSV + /** + * Col 1: Activity + * Col 2: watch brightness range "bright, medium, dimmer, dark"*/ + + private static int TIME_PERIOD = 5000; //5 second update new value + private String csv_file_path; + private String csv_typ; + private File file; + private FileReader file_reader; + private CSVReader csv_reader; + private String[] next_record; + private static final Logger logger = LogManager.getLogger(ReaderCSV.class); + private static final String ERASER_ITEM_URI = "http://localhost:4567/model/items/"; + //TODO ITEM_NAME HAS TO BE DISCUSSED + private static final String[] ACTIVITY_ITEM_NAME = { + "m_accel_x", "m_accel_y", "m_accel_z", "m_rotation_x", + "m_rotation_y", "m_rotation_z", "w_accel_x", "w_accel_y", + "w_accel_z", "w_rotation_x", "w_rotation_y", "w_rotation_z"}; + private static final String[] PREFERENCE_ITEM_NAME = { + "w_brightness" + }; + + //csv_type is activity or preference + public ReaderCSV(String csv_file_path, String csv_type) { + this.csv_file_path = csv_file_path; + this.csv_typ = csv_type; + } + + public void updater(){ + file=new File(csv_file_path); + try { + file_reader =new FileReader(file); + csv_reader = new CSVReader(file_reader); + while ((next_record = csv_reader.readNext()) != null) { + Thread.sleep(TIME_PERIOD); + if (csv_typ =="activity"){ + String[] values = Arrays.copyOf(next_record,12); + setNewValue(values, ACTIVITY_ITEM_NAME); + + } else { + String[] values = Arrays.copyOf(next_record,2); + setNewValue(values, PREFERENCE_ITEM_NAME); + } + } + } + catch (Exception e){ + e.printStackTrace(); + } + } + private void setNewValue(String[] values, String[] name){ + if(this.csv_typ.equals("activity")) + { + int i = 0; + for(String value : values){ + String uri = ERASER_ITEM_URI + name[i] + "/state"; + logger.info("reader:",value); + try { + HttpResponse httpResponse = Request.Put(uri) + .bodyString(value, ContentType.TEXT_PLAIN) + .execute().returnResponse(); + }catch (Exception e){ + e.printStackTrace(); + } + i+=1; + } + + }else{ + String uri= ERASER_ITEM_URI + "w_brightness" +"/state"; + logger.info("reader:",values[1]); + try { + HttpResponse httpResponse = Request.Put(uri) + .bodyString(values[1], ContentType.TEXT_PLAIN) + .execute().returnResponse(); + }catch (Exception e){ + e.printStackTrace(); + } + + } + + } +} \ No newline at end of file diff --git a/feedbackloop.learner_backup/src/test/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/ATest.java b/feedbackloop.learner_backup/src/test/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/ATest.java deleted file mode 100644 index 45adf05d4acbbe801d7f9ced98e2173fdf1d259d..0000000000000000000000000000000000000000 --- a/feedbackloop.learner_backup/src/test/java/de/tudresden/inf/st/eraser/feedbackloop.learner_backup/ATest.java +++ /dev/null @@ -1,22 +0,0 @@ -package de.tudresden.inf.st.eraser.feedbackloop.learner_backup; - -import de.tudresden.inf.st.eraser.jastadd.model.*; -import org.junit.Test; - -import java.util.Set; - -import static org.hamcrest.Matchers.*; -import static org.junit.Assert.fail; - -/** - * TODO: Add description. - * - * @author rschoene - Initial contribution - */ -public class ATest { - - @Test - public void test1() { - fail(); - } -} diff --git a/feedbackloop.plan/src/main/java/de/tudresden/inf/st/eraser/feedbackloop/plan/PlanImpl.java b/feedbackloop.plan/src/main/java/de/tudresden/inf/st/eraser/feedbackloop/plan/PlanImpl.java index 7175767134e29d3ab39e2c27cb0858d6cb4cb119..e7f256b2928dfbbdd35e48b2dbf5b1797eee727d 100644 --- a/feedbackloop.plan/src/main/java/de/tudresden/inf/st/eraser/feedbackloop/plan/PlanImpl.java +++ b/feedbackloop.plan/src/main/java/de/tudresden/inf/st/eraser/feedbackloop/plan/PlanImpl.java @@ -2,9 +2,7 @@ package de.tudresden.inf.st.eraser.feedbackloop.plan; import de.tudresden.inf.st.eraser.feedbackloop.api.Execute; import de.tudresden.inf.st.eraser.feedbackloop.api.Plan; -import de.tudresden.inf.st.eraser.jastadd.model.Activity; -import de.tudresden.inf.st.eraser.jastadd.model.ItemPreference; -import de.tudresden.inf.st.eraser.jastadd.model.Root; +import de.tudresden.inf.st.eraser.jastadd.model.*; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -38,9 +36,15 @@ public class PlanImpl implements Plan { @Override public void planToMatchPreferences(Activity activity) { - // TODO actually use activity logger.info("Plan got new activity [{}]: {}", activity.getIdentifier(), activity.getLabel()); List<ItemPreference> preferences = knowledgeBase.currentPreferences(); + knowledgeBase.getMachineLearningRoot().addChangeEvent(createRecognitionEvent(activity)); informExecute(preferences); } + + private ChangeEvent createRecognitionEvent(Activity activity) { + RecognitionEvent result = RecognitionEvent.createRecognitionEvent(knowledgeBase.getMachineLearningRoot().getActivityRecognition()); + result.setActivity(activity); + return result; + } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index fb7ef980f26942c36accd5674b80128f6cf43abe..030ec1f8a437a05e86702c10632c66340d98ba0f 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ +#Tue May 07 14:40:56 CEST 2019 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip diff --git a/learner_test/.gitignore b/learner_test/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..84c048a73cc2e5dd24f807669eb99b0ce3123195 --- /dev/null +++ b/learner_test/.gitignore @@ -0,0 +1 @@ +/build/ diff --git a/learner_test/build.gradle b/learner_test/build.gradle new file mode 100644 index 0000000000000000000000000000000000000000..64ba25868ab02f58ed90c006f52cfb3e9563c411 --- /dev/null +++ b/learner_test/build.gradle @@ -0,0 +1,35 @@ +repositories { + mavenCentral() +} + +sourceCompatibility = 1.8 + +apply plugin: 'java' +apply plugin: 'application' + +dependencies { + compile project(':eraser-base') + compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.8.8.1' + compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.10.0' + compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.10.0' + testCompile group: 'junit', name: 'junit', version: '4.12' + testCompile group: 'org.hamcrest', name: 'hamcrest-junit', version: '1.0.0.0' + + compile 'org.encog:encog-core:3.4' +} + +run { + mainClassName = 'de.tudresden.inf.st.eraser.learner_test.Main' + standardInput = System.in + if (project.hasProperty("appArgs")) { + args Eval.me(appArgs) + } +} + +sourceSets { + main { + java { + srcDir 'src/main/java' + } + } +} diff --git a/learner_test/src/main/java/de/tudresden/inf/st/eraser/learner_test/Main.java b/learner_test/src/main/java/de/tudresden/inf/st/eraser/learner_test/Main.java new file mode 100644 index 0000000000000000000000000000000000000000..62f00cb624f4dbae09c84bca772d09318f5c9964 --- /dev/null +++ b/learner_test/src/main/java/de/tudresden/inf/st/eraser/learner_test/Main.java @@ -0,0 +1,112 @@ +package de.tudresden.inf.st.eraser.learner_test; +import org.encog.Encog; +import org.encog.ml.MLClassification; +import org.encog.ml.data.MLData; +import org.encog.persist.EncogDirectoryPersistence; +import org.encog.util.csv.CSVFormat; +import org.encog.util.csv.ReadCSV; +import org.encog.util.simple.EncogUtility; + +import org.encog.ml.data.versatile.NormalizationHelper; +import org.encog.ml.data.versatile.VersatileMLDataSet; +import org.encog.ml.data.versatile.columns.ColumnDefinition; +import org.encog.ml.data.versatile.columns.ColumnType; +import org.encog.ml.data.versatile.sources.VersatileDataSource; +import org.encog.ml.data.versatile.sources.CSVDataSource; +import org.encog.ml.factory.MLMethodFactory; +import org.encog.ml.model.EncogModel; +import org.encog.ConsoleStatusReportable; +import org.encog.ml.MLRegression; +import java.io.File; +import java.util.Arrays; +import static org.encog.persist.EncogDirectoryPersistence.*; + +public class Main { + + public static void main(String[] args) { + //mapping the data into model + String savefile = "src/main/java/de/tudresden/inf/st/eraser/learner_test/save_model.eg"; + String File = "src/main/java/de/tudresden/inf/st/eraser/learner_test/preference_data.csv"; + File file = new File(File); + VersatileDataSource source = new CSVDataSource(file, false, CSVFormat.DECIMAL_POINT); + VersatileMLDataSet data = new VersatileMLDataSet(source); + data.defineSourceColumn("monat", 0, ColumnType.continuous); + data.defineSourceColumn("day", 1, ColumnType.continuous); + data.defineSourceColumn("hour", 2, ColumnType.continuous); + data.defineSourceColumn("minute", 3, ColumnType.continuous); + ColumnDefinition outputColumn = data.defineSourceColumn("labels", 4, ColumnType.continuous); + data.defineSingleOutputOthersInput(outputColumn); + data.analyze(); + System.out.println("get data "); + EncogModel model = new EncogModel(data); + model.selectMethod(data, MLMethodFactory.TYPE_FEEDFORWARD); + //model.setReport(new ConsoleStatusReportable()); + data.normalize(); + NormalizationHelper helper = data.getNormHelper(); + System.out.println(helper.toString()); + model.holdBackValidation(0.3, true, 1001); + model.selectTrainingType(data); + MLRegression bestMethod = (MLRegression)model.crossvalidate(5, true); + MLClassification bestMethodtest=(MLClassification)model.crossvalidate(5,true); + /**System.out.println( "Training error: " + EncogUtility.calculateRegressionError(bestMethod, model.getTrainingDataset())); + System.out.println( "testTraining error: " + EncogUtility.calculateClassificationError(bestMethodtest, model.getTrainingDataset())); + System.out.println( "Validation error: " + EncogUtility.calculateRegressionError(bestMethod, model.getValidationDataset())); + System.out.println( "testValidation error: " + EncogUtility.calculateClassificationError(bestMethodtest, model.getValidationDataset())); + + System.out.println(helper.getClass()); + System.out.println(helper.toString()); + System.out.println("Final model: " + bestMethod); + System.out.println("Final testmodel: " + bestMethodtest);**/ + //NormalizationHelper helper = data.getNormHelper(); + + //test + String helperstr=helper.toString(); + String [] split=helperstr.split(";"); + String [] finalStr = split[split.length-1].replace("]","").replace("[",""). + split(","); + System.out.println(helper); + + // save network... + //to delete + saveObject(new File(savefile), bestMethodtest); + ReadCSV csv = new ReadCSV(File, false, CSVFormat.DECIMAL_POINT); + String[] line = new String[4]; + MLData input = helper.allocateInputVector(); + System.out.println("input test---------------"); + System.out.println(input); + while(csv.next()) { + StringBuilder result = new StringBuilder(); + line[0] = csv.get(0); + line[1] = csv.get(1); + line[2] = csv.get(2); + line[3] = csv.get(3); + String correct = csv.get(4); + helper.normalizeInputVector(line,input.getData(),false); + + MLData output = bestMethod.compute(input); + System.out.println("inputs:"); + System.out.println(input); + System.out.println("outputs:"); + System.out.println(output); + String brightnessChosen = helper.denormalizeOutputVectorToString(output)[0]; + + result.append(Arrays.toString(line)); + result.append(" -> predicted: "); + result.append(brightnessChosen); + result.append("(correct: "); + result.append(correct); + result.append(")"); + System.out.println(result.toString()); + break; + + } + // Delete data file and shut down. + //File.delete(); + Encog.getInstance().shutdown(); + /**Training error: 0.299928703107046 + testTraining error: 0.9931740614334471 + Validation error: 0.41277024952020763 + testValidation error: 0.992*/ + + } +} diff --git a/learner_test/src/main/java/de/tudresden/inf/st/eraser/learner_test/final_data.csv b/learner_test/src/main/java/de/tudresden/inf/st/eraser/learner_test/final_data.csv new file mode 100644 index 0000000000000000000000000000000000000000..a1e263194d3ee4f95c64c3eff3b5123fb2246cf5 --- /dev/null +++ b/learner_test/src/main/java/de/tudresden/inf/st/eraser/learner_test/final_data.csv @@ -0,0 +1,418 @@ +7,20,12,13,2 +7,20,14,40,1 +7,20,14,40,2 +7,21,13,2,2 +7,21,13,2,2 +7,21,14,23,2 +7,21,14,23,2 +7,21,15,41,2 +7,21,16,54,2 +7,21,16,54,2 +7,21,17,45,3 +7,22,12,28,3 +7,22,15,35,2 +7,22,15,35,2 +7,22,18,59,3 +7,22,18,59,3 +7,23,12,32,2 +7,23,12,32,2 +7,23,16,7,2 +7,23,16,7,2 +7,23,16,7,2 +7,23,16,7,2 +7,23,16,7,2 +7,24,12,4,0 +7,24,12,4,0 +7,24,12,4,1 +7,24,14,38,2 +7,24,14,38,2 +7,24,18,54,3 +7,25,12,31,0 +7,25,12,32,1 +7,25,12,32,1 +7,25,15,6,3 +7,25,18,56,3 +7,26,13,41,2 +7,26,19,14,3 +7,27,11,39,2 +7,27,11,39,3 +7,27,11,46,3 +7,27,11,46,2 +7,27,13,8,2 +7,27,13,8,2 +7,27,13,9,2 +7,27,13,45,2 +7,27,13,45,2 +7,27,15,38,3 +7,28,12,12,2 +7,28,12,13,2 +7,28,12,41,2 +7,28,12,41,2 +7,28,12,41,2 +7,28,14,0,1 +7,28,14,0,2 +7,28,15,21,3 +7,28,18,56,3 +7,29,10,9,1 +7,29,10,9,1 +7,29,10,9,1 +7,29,11,54,0 +7,29,11,54,0 +7,29,11,54,0 +7,29,11,54,1 +7,29,14,10,2 +7,29,16,44,2 +7,29,16,44,2 +7,30,16,7,3 +7,30,18,45,3 +7,31,13,2,0 +7,31,13,2,1 +7,31,13,3,1 +7,31,13,3,1 +7,31,13,3,1 +7,31,18,39,3 +8,1,12,22,0 +8,1,12,22,1 +8,1,14,20,2 +8,1,14,20,2 +8,1,14,20,2 +8,1,15,55,3 +8,1,18,31,3 +8,1,18,37,3 +8,1,18,37,3 +8,1,19,2,3 +8,1,19,2,3 +8,1,20,5,3 +8,2,10,9,2 +8,2,10,9,1 +8,2,10,9,2 +8,2,10,9,2 +8,2,13,58,2 +8,2,13,58,2 +8,2,15,44,3 +8,2,15,44,3 +8,2,15,44,3 +8,2,17,21,3 +8,2,17,21,3 +8,2,17,21,3 +8,3,13,31,1 +8,3,13,31,2 +8,3,13,32,2 +8,3,16,43,3 +8,4,13,20,1 +8,4,13,20,2 +8,4,18,27,3 +8,5,13,37,2 +8,5,13,37,2 +8,5,18,33,3 +8,6,11,24,3 +8,6,11,24,3 +8,6,11,24,3 +8,6,13,50,3 +8,7,13,4,2 +8,7,13,4,2 +8,7,14,56,3 +8,8,12,13,2 +8,8,12,13,2 +8,8,15,51,2 +8,8,15,51,2 +8,8,15,51,3 +8,9,13,32,2 +8,9,13,32,2 +8,9,13,32,2 +8,9,15,8,2 +8,9,15,8,2 +8,9,15,8,2 +8,9,16,19,2 +8,10,11,32,0 +8,10,11,32,1 +8,10,11,32,1 +8,10,13,13,1 +8,10,13,13,1 +8,10,13,13,2 +8,10,16,42,3 +8,10,16,42,3 +8,11,14,6,2 +8,11,14,7,2 +8,11,18,54,3 +8,11,18,54,3 +8,11,18,54,3 +8,12,12,27,1 +8,12,12,27,1 +8,12,12,28,1 +8,12,13,53,2 +8,12,13,53,2 +8,12,13,53,2 +8,12,15,21,3 +8,13,13,16,1 +8,13,13,16,1 +8,13,13,16,1 +8,13,14,14,2 +8,13,14,14,2 +8,13,16,11,3 +8,13,17,18,3 +8,14,13,7,1 +8,14,13,7,1 +8,14,13,7,1 +8,14,13,7,1 +8,14,13,7,2 +8,14,13,7,2 +8,14,15,6,3 +8,15,14,5,2 +8,15,14,5,2 +8,15,14,6,2 +8,15,14,6,2 +8,15,16,41,3 +8,15,16,41,3 +8,15,17,30,3 +8,16,13,40,2 +8,16,13,40,2 +8,16,17,52,3 +8,16,17,53,3 +8,17,13,34,1 +8,17,13,35,2 +8,17,14,7,2 +8,17,19,2,3 +8,18,10,21,3 +8,18,11,14,2 +8,18,11,14,2 +8,18,11,14,2 +8,18,11,14,2 +8,18,14,25,2 +8,18,14,25,3 +8,18,14,25,2 +8,18,18,18,3 +8,18,18,19,3 +8,19,18,33,3 +8,19,18,33,3 +8,19,18,33,3 +8,19,18,33,3 +8,20,14,28,2 +8,20,14,28,2 +8,20,14,28,2 +8,20,14,28,2 +8,20,17,8,3 +8,20,18,22,3 +8,21,11,24,1 +8,21,11,24,1 +8,21,11,24,1 +8,21,15,34,3 +8,21,18,55,3 +8,22,12,3,1 +8,22,12,4,2 +8,22,12,4,2 +8,22,13,51,2 +8,22,13,51,2 +8,22,13,51,2 +8,22,18,12,3 +8,22,18,12,3 +8,22,18,12,3 +8,22,18,12,3 +8,22,18,40,3 +8,22,18,40,3 +8,23,13,42,1 +8,23,13,42,1 +8,23,17,32,3 +8,23,19,28,3 +8,23,20,27,3 +8,23,20,27,3 +8,23,21,49,3 +8,24,14,0,2 +8,24,14,0,2 +8,24,14,0,2 +8,24,14,0,2 +8,24,15,4,3 +8,24,15,4,3 +8,24,16,2,3 +8,24,16,3,3 +8,24,16,37,3 +8,24,17,9,3 +8,24,17,14,3 +8,25,13,34,1 +8,25,13,34,1 +8,25,13,34,1 +8,25,13,34,1 +8,25,13,34,1 +8,25,15,1,3 +8,25,17,58,3 +8,26,10,29,0 +8,26,10,29,0 +8,26,10,29,0 +8,26,10,29,0 +8,26,10,29,0 +8,26,16,42,3 +8,26,16,42,3 +8,26,18,41,3 +8,26,18,41,3 +8,27,13,41,2 +8,27,13,41,2 +8,27,13,41,2 +8,27,13,41,2 +8,27,17,42,3 +8,28,11,9,1 +8,28,11,9,1 +8,28,12,14,0 +8,28,12,14,1 +8,28,12,14,0 +8,28,15,3,2 +8,28,15,3,2 +8,28,16,31,3 +8,28,17,40,3 +8,29,14,44,3 +8,29,17,25,3 +8,30,12,5,0 +8,30,12,5,0 +8,30,12,5,0 +8,30,13,32,1 +8,30,13,32,1 +8,30,13,56,2 +8,30,14,23,2 +8,30,14,23,2 +8,30,14,23,2 +8,30,14,23,2 +8,30,14,41,2 +8,30,14,41,2 +8,30,14,41,2 +8,30,15,50,3 +8,30,17,0,3 +8,30,18,59,3 +8,30,18,59,3 +8,31,14,31,2 +8,31,14,31,2 +8,31,14,31,2 +8,31,17,59,3 +8,31,18,0,3 +9,1,16,13,3 +9,1,16,13,3 +9,1,16,13,3 +9,1,17,41,3 +9,2,13,44,1 +9,2,13,44,1 +9,2,13,44,1 +9,2,14,49,2 +9,2,14,49,2 +9,2,14,49,2 +9,2,16,6,3 +9,2,16,6,3 +9,2,17,2,3 +9,3,16,9,3 +9,3,17,35,3 +9,3,17,36,3 +9,4,12,57,1 +9,4,12,57,1 +9,4,15,8,3 +9,4,15,34,3 +9,4,16,26,3 +9,4,16,26,3 +9,4,18,37,3 +9,4,18,37,3 +9,4,18,37,3 +9,6,11,18,0 +9,6,11,18,0 +9,6,12,54,1 +9,6,12,54,1 +9,6,14,21,2 +9,6,14,21,2 +9,6,19,20,3 +9,7,11,50,0 +9,7,14,17,2 +9,7,14,57,3 +9,7,14,57,3 +9,7,16,56,3 +9,7,16,56,3 +9,7,16,56,3 +9,7,16,56,3 +9,7,18,38,3 +9,7,18,38,3 +9,8,11,4,2 +9,8,11,4,2 +9,8,11,13,0 +9,8,11,13,0 +9,8,11,13,0 +9,8,11,13,0 +9,8,11,13,0 +9,8,11,14,0 +9,8,11,14,1 +9,8,11,14,1 +9,8,12,1,0 +9,8,12,1,0 +9,8,12,1,0 +9,8,12,1,0 +9,8,12,1,0 +9,8,12,1,1 +9,8,12,36,0 +9,8,12,36,0 +9,8,12,36,0 +9,8,12,36,0 +9,8,12,36,0 +9,8,13,37,1 +9,8,13,37,1 +9,8,13,37,1 +9,8,14,20,2 +9,8,14,20,2 +9,8,18,20,3 +9,9,12,47,1 +9,9,12,47,2 +9,9,12,47,2 +9,9,19,5,3 +9,10,13,15,1 +9,10,13,15,1 +9,10,13,15,0 +9,10,16,49,3 +9,10,19,6,3 +9,10,21,5,3 +9,11,14,16,2 +9,11,14,16,2 +9,11,14,16,2 +9,11,18,41,3 +9,12,14,43,2 +9,12,14,43,2 +9,12,14,43,2 +9,12,16,14,3 +9,12,17,12,3 +9,12,17,12,2 +9,12,17,12,3 +9,12,17,12,2 +9,12,20,44,3 +9,13,19,52,3 +9,14,14,39,2 +9,14,14,39,2 +9,14,15,14,3 +9,14,17,29,3 +9,14,17,29,3 +9,14,17,29,3 +9,15,11,41,1 +9,15,11,41,1 +9,15,13,4,1 +9,15,14,3,1 +9,15,14,3,2 +9,16,12,36,1 +9,16,12,36,1 +9,16,12,36,1 +9,16,12,36,1 +9,16,12,48,1 +9,16,12,48,1 +9,16,13,51,1 +9,16,13,51,2 +9,16,13,51,1 +9,16,15,13,3 +9,16,15,14,3 +9,16,15,14,3 +9,17,10,27,0 +9,17,10,27,0 +9,17,11,10,0 +9,17,11,10,0 +9,17,11,10,0 +9,17,12,43,1 +9,17,12,43,1 +9,17,12,43,1 +9,17,13,32,1 +9,17,13,32,1 +9,17,14,5,1 +9,17,14,5,2 +9,17,14,6,2 +9,17,15,7,3 +9,17,15,49,3 +9,17,15,49,3 +9,17,18,12,3 +9,17,18,13,3 diff --git a/learner_test/src/main/java/de/tudresden/inf/st/eraser/learner_test/save_model.eg b/learner_test/src/main/java/de/tudresden/inf/st/eraser/learner_test/save_model.eg new file mode 100644 index 0000000000000000000000000000000000000000..47c37ff28ef95b7b22a2df05ec050c3ffeb53a30 --- /dev/null +++ b/learner_test/src/main/java/de/tudresden/inf/st/eraser/learner_test/save_model.eg @@ -0,0 +1,24 @@ +encog,BasicNetwork,java,3.4.0,1,1554196571101 +[BASIC] +[BASIC:PARAMS] +[BASIC:NETWORK] +beginTraining=0 +connectionLimit=0 +contextTargetOffset=0,0,0 +contextTargetSize=0,0,0 +endTraining=2 +hasContext=f +inputCount=4 +layerCounts=1,8,5 +layerFeedCounts=1,7,4 +layerContextCount=0,0,0 +layerIndex=0,1,9 +output=0.2537517424,0.3154675575,-0.8739039638,-0.4408848221,-0.8484433638,-0.999915299,-0.6964984771,-0.208278439,1,0,0,-0.4545454545,0.3559322034,1 +outputCount=1 +weightIndex=0,8,43 +weights=0.5976774048,-0.7925906525,0.7127327881,-0.9611660362,0.8031350986,-0.7286657218,1.0990482817,-0.5985785536,-0.0783115433,0.575612931,1.1267500918,1.7184744034,0.2271044512,-1.0525796764,0.0900869671,1.1492323512,0.6141715555,-1.0455927965,-0.0925453451,0.2471651431,2.3634316872,0.3939369257,0.4607437082,-0.1435186798,0.8428535365,-0.0848896791,-0.070602589,-1.2640263565,2.4899996734,-0.2185394776,10.3421332361,-0.1650898311,-0.2750133571,-0.79680959,-0.8051139953,0.8219933747,-0.0727160299,-0.4609522002,-1.0410685492,-0.5354063412,0.3028724456,-0.6835374219,0.169591233 +biasActivation=0,1,1 +[BASIC:ACTIVATION] +"org.encog.engine.network.activation.ActivationTANH" +"org.encog.engine.network.activation.ActivationTANH" +"org.encog.engine.network.activation.ActivationLinear" diff --git a/learner_test/src/main/java/de/tudresden/inf/st/eraser/learner_test/save_model_test.eg b/learner_test/src/main/java/de/tudresden/inf/st/eraser/learner_test/save_model_test.eg new file mode 100644 index 0000000000000000000000000000000000000000..62fe6421d95e164aa14e123b950e831e37a5f23c --- /dev/null +++ b/learner_test/src/main/java/de/tudresden/inf/st/eraser/learner_test/save_model_test.eg @@ -0,0 +1,24 @@ +encog,BasicNetwork,java,3.4.0,1,1548158734516 +[BASIC] +[BASIC:PARAMS] +[BASIC:NETWORK] +beginTraining=0 +connectionLimit=0 +contextTargetOffset=0,0,0 +contextTargetSize=0,0,0 +endTraining=2 +hasContext=f +inputCount=4 +layerCounts=4,8,5 +layerFeedCounts=4,7,4 +layerContextCount=0,0,0 +layerIndex=0,4,12 +output=0.6991387348,-0.8711034513,-0.996886038,-0.832747291,-0.0935682806,-0.9996163977,0.5399150265,0.9411173394,-0.5084989975,0.4850010791,0.9999999957,1,0,-0.6666666667,-0.4545454545,0.6949152542,1 +outputCount=4 +weightIndex=0,32,67 +weights=-2.6901880743,0.6512821123,-1.2270002115,1.63124668,0.1982387305,-0.2994789552,1.5833040739,-0.9450411677,2.0541422847,-0.718279397,-1.1761952241,0.5028631512,0.0690323612,-1.496141565,-0.1955149568,-0.7453976822,-0.3691141073,0.9854755554,2.2113850088,-1.5216550292,0.9652087936,-1.3028209693,-1.3346156171,0.4142247818,1.0821207364,0.1987534858,0.6202881884,-0.2940331887,-1.4643282498,2.6960334656,-0.0167663298,-2.9907087565,0.3469960227,-0.0441249736,-2.5998575813,-0.7106361301,-0.8111809962,2.2216158678,-0.5482762437,-1.7996398291,-3.6734127565,-2.9102547958,0.4845401914,0.3760471288,-0.0124987546,0.3784047483,0.5860932613,-0.2682876707,0.7429004186,-7.559247176,-3.4421363532,1.1989747484,-2.3340717496,-1.4740773042,-0.7795788072,-1.8241693655,-0.630132295,-0.8191869009,-0.4060569987,-1.0997423162,-0.5495165849,0.1407829068,-2.2964930412,0.0798893221,-19.5271913755,2.0474187009,-0.2622671892 +biasActivation=0,1,1 +[BASIC:ACTIVATION] +"org.encog.engine.network.activation.ActivationTANH" +"org.encog.engine.network.activation.ActivationTANH" +"org.encog.engine.network.activation.ActivationLinear" diff --git a/learner_test/src/main/resources/log4j2.xml b/learner_test/src/main/resources/log4j2.xml new file mode 100644 index 0000000000000000000000000000000000000000..0594576fac98ba859e411597c90c8e3d989378bd --- /dev/null +++ b/learner_test/src/main/resources/log4j2.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Configuration> + <Appenders> + <Console name="Console"> + <PatternLayout pattern="%highlight{%d{HH:mm:ss.SSS} %-5level} %c{1.} - %msg%n"/> + </Console> + <RollingFile name="RollingFile" fileName="logs/jastadd-mquat.log" + filePattern="logs/jastadd-mquat-%i.log"> + <PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n"/> + <Policies> + <OnStartupTriggeringPolicy/> + </Policies> + <DefaultRolloverStrategy max="20"/> + </RollingFile> + </Appenders> + <Loggers> + <Root level="debug"> + <AppenderRef ref="Console"/> + <AppenderRef ref="RollingFile"/> + </Root> + </Loggers> +</Configuration> diff --git a/make-new-project.py b/make-new-project.py index afd3a51931e3a7dc6823d47e1b9c97a65a2a2e76..635755567333e0d326ff346d5852d7d62437bbcb 100755 --- a/make-new-project.py +++ b/make-new-project.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3 +#!/usr/bin/env python2.7 import argparse import os import shutil diff --git a/ml_test_boqi/.gitignore b/ml_test_boqi/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..70b583e34c3316bcd77c807e2d6b85db5e7d49f6 --- /dev/null +++ b/ml_test_boqi/.gitignore @@ -0,0 +1,3 @@ +/build/ +/bin/ +logs/ diff --git a/ml_test_boqi/build.gradle b/ml_test_boqi/build.gradle new file mode 100644 index 0000000000000000000000000000000000000000..d07b5930b7d3c75216b36bb9f5d9fa08b5d9d2c0 --- /dev/null +++ b/ml_test_boqi/build.gradle @@ -0,0 +1,33 @@ +repositories { + mavenCentral() +} + +sourceCompatibility = 1.8 + +apply plugin: 'java' +apply plugin: 'application' + +dependencies { + compile project(':eraser-base') + compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.9.8' + compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.11.1' + compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.11.1' + testCompile group: 'junit', name: 'junit', version: '4.12' + testCompile group: 'org.hamcrest', name: 'hamcrest-junit', version: '2.0.0.0' +} + +run { + mainClassName = 'de.tudresden.inf.st.eraser.ml_test_boqi.Main' + standardInput = System.in + if (project.hasProperty("appArgs")) { + args Eval.me(appArgs) + } +} + +sourceSets { + main { + java { + srcDir 'src/main/java' + } + } +} diff --git a/ml_test_boqi/src/main/java/de/tudresden/inf/st/eraser/ml_test_boqi/Main.java b/ml_test_boqi/src/main/java/de/tudresden/inf/st/eraser/ml_test_boqi/Main.java new file mode 100644 index 0000000000000000000000000000000000000000..f42663472e3a986c82df86e4bf89d0f9ff706441 --- /dev/null +++ b/ml_test_boqi/src/main/java/de/tudresden/inf/st/eraser/ml_test_boqi/Main.java @@ -0,0 +1,219 @@ +package de.tudresden.inf.st.eraser.ml_test_boqi; + +import de.tudresden.inf.st.eraser.jastadd.model.*; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.function.Function; +import java.util.stream.Collectors; +import org.apache.commons.math3.stat.StatUtils; +import de.tudresden.inf.st.eraser.jastadd.model.Item; + + +public class Main { + + private static final Logger logger = LogManager.getLogger(Main.class); + + public static void main(String[] args) { + + logger.info("Hello World!"); + createAndTestBrightnessNetwork(); + } + private static Root createModel() { + Root model = Root.createEmptyRoot(); + Group group = new Group(); + group.setID("Group1"); + model.addGroup(group); + + // inputs items muss normalize 1.0, 0.06666666666666665, 0.4545454545454546, -0.5593220338983051, 1(bias) + + NumberItem monthItem = new NumberItem(); + monthItem.setState(-1.0); + monthItem.setID("month"); + monthItem.setLabel("datetime-month"); + + NumberItem dayItem = new NumberItem(); + dayItem.setState(0.2666666666666666); + dayItem.setID("day"); + dayItem.setLabel("datetime-day"); + + NumberItem hourItem = new NumberItem(); + hourItem.setState(-0.6363636363636364); + hourItem.setID("hour"); + hourItem.setLabel("datetime-hour"); + + NumberItem minuteItem = new NumberItem(); + minuteItem.setState(-0.5593220338983051); + minuteItem.setID("minute"); + minuteItem.setLabel("datetime-minute"); + + NumberItem biasItem = new NumberItem(); + biasItem.setState(1); + biasItem.setID("bias"); + biasItem.setLabel("bias"); + + group.addItem(monthItem); + group.addItem(dayItem); + group.addItem(hourItem); + group.addItem(minuteItem); + group.addItem(biasItem); + return model; + } + private static final int REPETITIONS = 1; + private static void classifyTimed( + NeuralNetworkRoot nn, + Function<NeuralNetworkRoot, DoubleNumber> classify, + Function<DoubleNumber, String> leafToString) { + List<String> results = new ArrayList<>(); + List<Long> times = new ArrayList<>(); + long before = System.nanoTime(); + DoubleNumber classification = classify.apply(nn); + long diff = System.nanoTime() - before; + results.add(leafToString.apply(classification)); + times.add(TimeUnit.NANOSECONDS.toMillis(diff)); + logger.info("Classification results: {}", results); + logger.info("Took {}ms", String.join("ms, ", times.stream().map(l -> Long.toString(l)).collect(Collectors.toList()))); + logger.info("Took on average: {}ms", + Arrays.stream(times.toArray(new Long[0])).mapToLong(l -> l).average().orElse(-1)); + logger.info("Took on median: {}ms", + Arrays.stream(times.toArray(new Long[0])).mapToLong(l -> l).sorted() + .skip((REPETITIONS - 1) / 2).limit(2 - REPETITIONS % 2).average().orElse(Double.NaN)); + } + + /** + * Purpose: Create a neural network with 3 layers (5 + 8 + 4 neurons) + */ + private static void createAndTestBrightnessNetwork() { + Root model = createModel(); + Item monthItem = model.resolveItem("month").orElseThrow( + () -> new RuntimeException("Month not found")); + Item dayItem = model.resolveItem("day").orElseThrow( + () -> new RuntimeException("Day not found")); + Item hourItem = model.resolveItem("hour").orElseThrow( + () -> new RuntimeException("Hour not found")); + Item minuteItem = model.resolveItem("minute").orElseThrow( + () -> new RuntimeException("Minute not found")); + Item biasItem = model.resolveItem("bias").orElseThrow( + () -> new RuntimeException("Bias not found")); + + NeuralNetworkRoot nn = new NeuralNetworkRoot(); + + DoubleArrayDoubleFunction sigmoid = inputs -> Math.signum(Arrays.stream(inputs).sum()); + DoubleArrayDoubleFunction tanh= inputs ->Math.tanh(Arrays.stream(inputs).sum()); + DoubleArrayDoubleFunction function_one= inputs->function_one(); + + //Weights outputs from learner Module + ArrayList<Double> weights= new ArrayList<Double>(Arrays.asList( + -4.8288886204,0.6723236931,2.1451097188,-0.8551053267,-0.7858304445,4.1369566727,-3.3096691918, + -0.2190980261,2.6871317298,1.2272772167,-2.5292510941,-1.2860407542,-4.2280191541,1.004752063, + 0.8345207039,0.0123185817,-0.5921808915,0.0967336988,-0.305892589,0.5572392781,-0.7190098073, + -1.6247354373,0.4589248822,-0.0269816271,2.2208040852,-3.6281085698,0.2204999381,4.7263701556, + -4.8348948698,0.231141867,8.7120706018,-1.4912707741,0.9482851705,0.1377551973,-6.6525856465, + -1.321197315,-2.7369948929,17.664289214,-3.1279212743,-0.8245974167,-1.4251924355,0.8370511414, + 2.0841638143,-0.210152817,-1.9414132298,-1.7973688846,-2.1977997794,-3.6046836685,-3.3403186721, + -6.1556924635,-2.8952903587,-1.0773989561,0.2300429028,-0.2184650371,0.0297181797,0.5709092417, + 1.3960358442,-3.1577981239,0.0423944625,-17.8143314027,-1.4439317172,-0.5137688896,1.0166045804, + 0.3059149818,1.0938282764,0.6203368549,0.702449827)); + // input layer + InputNeuron month = new InputNeuron(); + month.setItem(monthItem); + InputNeuron day = new InputNeuron(); + day.setItem(dayItem); + InputNeuron hour = new InputNeuron(); + hour.setItem(hourItem); + InputNeuron minute = new InputNeuron(); + minute.setItem(minuteItem); + InputNeuron bias = new InputNeuron(); + bias.setItem(biasItem); + + nn.addInputNeuron(month); + nn.addInputNeuron(day); + nn.addInputNeuron(hour); + nn.addInputNeuron(minute); + nn.addInputNeuron(bias); + + // output layer + OutputLayer outputLayer = new OutputLayer(); + OutputNeuron output0 = new OutputNeuron(); + output0.setActivationFormula(tanh); + OutputNeuron output1 = new OutputNeuron(); + output1.setActivationFormula(tanh); + OutputNeuron output2 = new OutputNeuron(); + output2.setActivationFormula(tanh); + OutputNeuron output3 = new OutputNeuron(); + output3.setActivationFormula(tanh); + + outputLayer.addOutputNeuron(output0); + outputLayer.addOutputNeuron(output1); + outputLayer.addOutputNeuron(output2); + outputLayer.addOutputNeuron(output3); + + outputLayer.setCombinator(inputs->predictor(inputs)); + nn.setOutputLayer(outputLayer); + + // hidden layer + HiddenNeuron[] hiddenNeurons = new HiddenNeuron[8]; + for (int i = 0; i < (hiddenNeurons.length); i++) { + + if (i==7){ + HiddenNeuron hiddenNeuron = new HiddenNeuron(); + hiddenNeuron.setActivationFormula(function_one); + hiddenNeurons[i] = hiddenNeuron; + nn.addHiddenNeuron(hiddenNeuron); + bias.connectTo(hiddenNeuron,1.0); + hiddenNeuron.connectTo(output0, weights.get(i)); + hiddenNeuron.connectTo(output1, weights.get(i+8)); + hiddenNeuron.connectTo(output2, weights.get(i+8*2)); + hiddenNeuron.connectTo(output3, weights.get(i+8*3)); + } + else{ + HiddenNeuron hiddenNeuron = new HiddenNeuron(); + hiddenNeuron.setActivationFormula(tanh); + hiddenNeurons[i] = hiddenNeuron; + nn.addHiddenNeuron(hiddenNeuron); + + month.connectTo(hiddenNeuron, weights.get((hiddenNeurons.length*4)+i*5)); + day.connectTo(hiddenNeuron, weights.get((hiddenNeurons.length*4+1)+i*5)); + hour.connectTo(hiddenNeuron, weights.get((hiddenNeurons.length*4+2)+i*5)); + minute.connectTo(hiddenNeuron, weights.get((hiddenNeurons.length*4+3)+i*5)); + bias.connectTo(hiddenNeuron,weights.get((hiddenNeurons.length*4+4)+i*5)); + hiddenNeuron.connectTo(output0, weights.get(i)); + hiddenNeuron.connectTo(output1, weights.get(i+8)); + hiddenNeuron.connectTo(output2, weights.get(i+8*2)); + hiddenNeuron.connectTo(output3, weights.get(i+8*3));} + } + + model.getMachineLearningRoot().setPreferenceLearning(nn); + System.out.println(model.prettyPrint()); + + classifyTimed(nn, NeuralNetworkRoot::classify, + classification -> Double.toString(classification.number)); + } + private static double function_one() { + return 1.0; + } + private static double predictor(double[] inputs) { + int index=0; + double maxinput=StatUtils.max(inputs); + System.out.println(inputs); + for (int i = 0; i < inputs.length; i++) + { + if (inputs[i] == maxinput){ + index=i; + } + } + //outputs from learner + ArrayList<Double> outputs= new ArrayList<Double>(Arrays.asList(2.0,1.0,3.0,0.0)); + double output=outputs.get(index); + return output; + } +} + +//inputs: +//[BasicMLData:-1.0,0.2666666666666666,-0.6363636363636364,-0.5593220338983051] +//outputs: +//[BasicMLData:-0.9151867668336432,-0.1568555041251098,-0.9786996639280675,-0.9436628188408074] +//[7, 20, 12, 13] -> predicted: 1(correct: 2) \ No newline at end of file diff --git a/ml_test_boqi/src/main/resources/log4j2.xml b/ml_test_boqi/src/main/resources/log4j2.xml new file mode 100644 index 0000000000000000000000000000000000000000..0594576fac98ba859e411597c90c8e3d989378bd --- /dev/null +++ b/ml_test_boqi/src/main/resources/log4j2.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Configuration> + <Appenders> + <Console name="Console"> + <PatternLayout pattern="%highlight{%d{HH:mm:ss.SSS} %-5level} %c{1.} - %msg%n"/> + </Console> + <RollingFile name="RollingFile" fileName="logs/jastadd-mquat.log" + filePattern="logs/jastadd-mquat-%i.log"> + <PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n"/> + <Policies> + <OnStartupTriggeringPolicy/> + </Policies> + <DefaultRolloverStrategy max="20"/> + </RollingFile> + </Appenders> + <Loggers> + <Root level="debug"> + <AppenderRef ref="Console"/> + <AppenderRef ref="RollingFile"/> + </Root> + </Loggers> +</Configuration> diff --git a/settings.gradle b/settings.gradle index 4492d856ad2d58bf8a3fe0eedca93b30b9c05bb2..0a118ec458b406dfae388bf1218c2abd4bfd356b 100644 --- a/settings.gradle +++ b/settings.gradle @@ -3,6 +3,7 @@ rootProject.name = 'eraser' include ':eraser-base' include 'openhab-mock' include 'integration' +include ':benchmark' include ':commons.color' include ':skywriter-hue-integration' include ':org.openhab.action.machinelearn' @@ -19,4 +20,5 @@ include ':feedbackloop.learner' include ':influx_test' include ':eraser.spark' include ':eraser.starter' -include ':integration_test' +include ':feedbackloop.learner_backup' +include ':datasets' diff --git a/skywriter-hue-integration/src/main/resources/smart_arrive.eraser b/skywriter-hue-integration/src/main/resources/smart_arrive.eraser new file mode 100644 index 0000000000000000000000000000000000000000..44b67cf94d3bb8da666cc38743f008552041a152 --- /dev/null +++ b/skywriter-hue-integration/src/main/resources/smart_arrive.eraser @@ -0,0 +1,44 @@ +ThingType: id="hue:bridge" label="Hue Bridge" description="The hue bridge represents the Philips hue bridge." parameters=[] channelTypes=[] ; +ThingType: id="hue:0200" label="Color Light" description="A dimmable light with changeable colors." ; +ThingType: id="hue:0210" label="Extended Color Light" description="A dimmable light with changeable colors and tunable color temperature." parameters=[] channelTypes=[]; +ThingType: id="skywriter-hat" label="SkyWriterHAT" description="SkyWriterHAT Gesture Recognition" parameters=["brokername"] channelTypes=["flick-type", "skywriter-x", "skywriter-y"] ; + +Thing: id="hue:bridge:0017880adcf4" label="Philips hue (10.8.0.160)" type="hue:bridge" channels=[] ; +Thing: id="hue:0210:0017880adcf4:1" label="Wohnzimmer" type="hue:0210" channels=["hue:0210:0017880adcf4:1:color_temperature", "hue:0210:0017880adcf4:1:effect"] ; +Thing: id="hue:0200:0017880adcf4:5" label="Hue iris 1" type="hue:0200" channels=["hue:0210:0017880adcf4:4:color", "hue:0210:0017880adcf4:4:color_temperature", "hue:0210:0017880adcf4:4:alert", "hue:0210:0017880adcf4:4:effect"] ; +Thing: id="hue:0210:0017880adcf4:4" label="Hue go 1" type="hue:0210" channels=["hue:0200:0017880adcf4:5:color", "hue:0200:0017880adcf4:5:alert", "hue:0200:0017880adcf4:5:effect"] ; +Thing: id="skywriter1" label="Our skywriter" type="skywriter-hat" channels=["skywriter1-flick", "skywriter1-x", "skywriter1-y"] ; + +ChannelType: id="hue:color" label="Color" description="The color channel allows to control the color of a light. It is also possible to dim values and switch the light on and off." itemType="Color" category="ColorLight" ; +ChannelType: id="hue:alert" label="Alert" description="The alert channel allows a temporary change to the bulb’s state." itemType="String" category="Unknown" ; +ChannelType: id="hue:effect" label="Color Loop" description="The effect channel allows putting the bulb in a color looping mode." itemType="Switch" category="ColorLight" ; +ChannelType: id="hue:color_temperature" label="Color Temperature" description="The color temperature channel allows to set the color temperature of a light from 0 (cold) to 100 (warm)." itemType="Dimmer" category="ColorLight" ; +ChannelType: id="flick-type" itemType="String" label="Last Flick" description="Last Flick detected (and its direction)" category="Motion" readOnly ; +ChannelType: id="skywriter-x" itemType="String" label="Current X coordinate" description="Current X coordinate" category="Motion" readOnly ; +ChannelType: id="skywriter-y" itemType="String" label="Current Y coordinate" description="Current Y coordinate" category="Motion" readOnly ; + +Channel: id="hue:0210:0017880adcf4:1:color_temperature" type="hue:color_temperature" links=[] ; +Channel: id="hue:0210:0017880adcf4:1:effect" type="hue:effect" links=[] ; +Channel: id="hue:0210:0017880adcf4:4:color" type="hue:color" links=[] ; +Channel: id="hue:0210:0017880adcf4:4:color_temperature" type="hue:color_temperature" links=[] ; +Channel: id="hue:0210:0017880adcf4:4:alert" type="hue:alert" links=[] ; +Channel: id="hue:0210:0017880adcf4:4:effect" type="hue:effect" links=[] ; +Channel: id="hue:0200:0017880adcf4:5:color" type="hue:color" links=["iris1_item"] ; +Channel: id="hue:0200:0017880adcf4:5:alert" type="hue:alert" links=[] ; +Channel: id="hue:0200:0017880adcf4:5:effect" type="hue:color" links=[] ; +Channel: id="skywriter1-flick" type="flick-type" links=[]; +Channel: id="skywriter1-x" type="skywriter-x" links=["skywriter1_x"]; +Channel: id="skywriter1-y" type="skywriter-y" links=["skywriter1_y"]; + +Item: id="iris1_item" label="Iris 1" state="121,88,68" topic="iris1_item/state"; +Item: id="skywriter1_x" label="X" state="0" topic="skywriter/x"; +Item: id="skywriter1_y" label="Y" state="0" topic="skywriter/y"; +//Item: id="skywriter1_xyz" label="Y" state="0" topic="skywriter/xyz"; + +Group: id="Lights" items=["iris1_item"]; +Group: id="Skywriter" items=["skywriter1_x", "skywriter1_y"]; + +Parameter: id="brokername" label="Broker Name" description="Name of the broker as defined in the <broker>.url in services/mqtt.cfg. See the MQTT Binding for more information on how to configure MQTT broker connections." type="Text" context="service" default="mosquitto" required ; + +// MqttHost is set programmatically +Mqtt: incoming="oh2/out/" outgoing="oh2/in/" ;