Skip to content
Snippets Groups Projects
Commit 0d9f3fc2 authored by René Schöne's avatar René Schöne
Browse files

Squashed commit of branch 'learner'

- Fixed pattern to parse datetime coming from openHAB.
- add benchmark
- Create RecognitionEvents in component Plan.
- Add expression printing and fix expression tests.
- Fixing tests.
- Remove build artefacts of datasets module.
- Fixing item behavior.
- Fix bug when adding item using REST API.
  - More debug output for REST application and MQTT receiver
  - Flush cache if new MQTT Host is set
- first integration for test
- update integration activity ML
- add item room_brightness
- add ML Items in starter file
- fix import error
- update newData function
- Fix Learner bugs.
  - Let ExternalMachineLearningModel.check() return true instead of throwing an exception
  - In Learner, use temporary files to store encog model
  - In MachineLearningImpl, do not use result for now (as newData won't work at the moment)
  - Minor fixes for base (add logger, add correct input to jastadd gradle task)
- Progressing to integration of machine learning.
  - Added setKnowledgeBase to MachineLearningEncoder and -Decoder, and removed Root argument in other methods
  - Changed Learner-Impl to match new adapters
  - Updated starter to new adapters, and to use CSV files for initialization of learner
- update readercsv
- Fix imports and dependencies.
- Fix errors with changed MachineLearningEncoder interface.
- upate learner
- add ML interfaces
- implement decode encode
- learner with activity and preference
parent 4221d160
Branches
No related tags found
No related merge requests found
Showing
with 337 additions and 30 deletions
.gradle/
.idea/
build/dependencyUpdates/
venv/
*/out/
logs/
/build/
logs/
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'
}
}
}
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
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();
}
}
......@@ -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
......
......@@ -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) {
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) {
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);
// exit the method to avoid printing the error message for e1
return;
} catch (NumberFormatException e2) {
logger.catching(e2);
}
logger.catching(e1);
} 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));
}
}
......
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);
}
......@@ -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());
}
}
......@@ -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 ;
......
......@@ -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();
}
......@@ -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) {
......
......@@ -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); }
......
......@@ -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())
);
}
}
......@@ -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)));
}
}
......@@ -40,7 +40,7 @@ ImageItem : ItemWithStringState ;
LocationItem : ItemWithStringState ;
NumberItem : ItemWithDoubleState ;
PlayerItem : ItemWithStringState ;
RollerShutterItem : ItemWithBooleanState ;
RollerShutterItem : ItemWithDoubleState ;
StringItem : ItemWithStringState ;
SwitchItem : ItemWithBooleanState ;
DefaultItem : ItemWithStringState ;
......
......@@ -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);
}
......
......@@ -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.
......
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
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment