Initial commit

main
Gijs 2 years ago
commit d0cb45bce2

@ -0,0 +1,92 @@
#pragma once
#include <cstdarg>
namespace PublishingHouse
{
namespace RandomForest
{
class DecisionTree
{
public:
const char* predict(float (*getObservationValue)(int), bool (*consider)(float, int, float))
{
if ((consider)((getObservationValue)(3), 3, 1.0)) {
if ((consider)((getObservationValue)(3), 3, 0.2)) {
if ((consider)((getObservationValue)(3), 3, 0.1)) {
return "Iris Setosa";
}
else {
return "Iris Setosa";
}
}
else {
return "Iris Setosa";
}
}
else {
if ((consider)((getObservationValue)(2), 2, 4.8)) {
if ((consider)((getObservationValue)(2), 2, 4.6)) {
if ((consider)((getObservationValue)(2), 2, 3.9)) {
if ((consider)((getObservationValue)(3), 3, 1.0)) {
return "Iris Versicolour";
}
else {
return "Iris Versicolour";
}
}
else {
return "Iris Versicolour";
}
}
else {
return "Iris Versicolour";
}
}
else {
if ((consider)((getObservationValue)(1), 1, 2.7)) {
if ((consider)((getObservationValue)(2), 2, 5.0)) {
if ((consider)((getObservationValue)(3), 3, 1.5)) {
return "Iris Versicolour";
}
else {
return "Iris Versicolour";
}
}
else {
return "Iris Virginica";
}
}
else {
if ((consider)((getObservationValue)(2), 2, 5.1)) {
if ((consider)((getObservationValue)(3), 3, 1.8)) {
if ((consider)((getObservationValue)(2), 2, 5.0)) {
return "Iris Versicolour";
}
else {
return "Iris Versicolour";
}
}
else {
if ((consider)((getObservationValue)(0), 0, 6.0)) {
if ((consider)((getObservationValue)(1), 1, 3.2)) {
return "Iris Versicolour";
}
else {
return "Iris Versicolour";
}
}
else {
return "Iris Virginica";
}
}
}
else {
return "Iris Virginica";
}
}
}
}
}
private:
};
}
}

@ -0,0 +1,67 @@
#pragma once
#include <cstdarg>
namespace PublishingHouse
{
namespace RandomForest
{
class DecisionTree
{
public:
const char* predict(float (*getObservationValue)(int), bool (*consider)(float, int, float))
{
if ((consider)((getObservationValue)(2), 2, 3.3)) {
if ((consider)((getObservationValue)(2), 2, 1.4)) {
if ((consider)((getObservationValue)(3), 3, 0.1)) {
return "Iris Setosa";
}
else {
return "Iris Setosa";
}
}
else {
return "Iris Setosa";
}
}
else {
if ((consider)((getObservationValue)(2), 2, 4.8)) {
if ((consider)((getObservationValue)(3), 3, 1.0)) {
return "Iris Versicolour";
}
else {
return "Iris Versicolour";
}
}
else {
if ((consider)((getObservationValue)(2), 2, 4.9)) {
if ((consider)((getObservationValue)(0), 0, 6.2)) {
return "Iris Versicolour";
}
else {
return "Iris Virginica";
}
}
else {
if ((consider)((getObservationValue)(3), 3, 1.8)) {
if ((consider)((getObservationValue)(3), 3, 1.7)) {
if ((consider)((getObservationValue)(0), 0, 6.3)) {
return "Iris Virginica";
}
else {
return "Iris Virginica";
}
}
else {
return "Iris Versicolour";
}
}
else {
return "Iris Virginica";
}
}
}
}
}
private:
};
}
}

@ -0,0 +1,92 @@
#pragma once
#include <cstdarg>
namespace PublishingHouse
{
namespace RandomForest
{
class DecisionTree
{
public:
const char* predict(float (*getObservationValue)(int), bool (*consider)(float, int, float))
{
if ((consider)((getObservationValue)(3), 3, 1.0)) {
if ((consider)((getObservationValue)(1), 1, 3.0)) {
if ((consider)((getObservationValue)(0), 0, 4.4)) {
return "Iris Setosa";
}
else {
return "Iris Setosa";
}
}
else {
return "Iris Setosa";
}
}
else {
if ((consider)((getObservationValue)(3), 3, 1.8)) {
if ((consider)((getObservationValue)(3), 3, 1.5)) {
if ((consider)((getObservationValue)(3), 3, 1.4)) {
if ((consider)((getObservationValue)(1), 1, 2.5)) {
if ((consider)((getObservationValue)(3), 3, 1.0)) {
return "Iris Versicolour";
}
else {
return "Iris Versicolour";
}
}
else {
return "Iris Versicolour";
}
}
else {
return "Iris Versicolour";
}
}
else {
if ((consider)((getObservationValue)(1), 1, 3.0)) {
if ((consider)((getObservationValue)(0), 0, 6.2)) {
return "Iris Virginica";
}
else {
if ((consider)((getObservationValue)(0), 0, 6.3)) {
return "Iris Versicolour";
}
else {
if ((consider)((getObservationValue)(2), 2, 5.1)) {
if ((consider)((getObservationValue)(3), 3, 1.5)) {
return "Iris Versicolour";
}
else {
return "Iris Versicolour";
}
}
else {
return "Iris Virginica";
}
}
}
}
else {
if ((consider)((getObservationValue)(2), 2, 5.8)) {
if ((consider)((getObservationValue)(2), 2, 4.5)) {
return "Iris Versicolour";
}
else {
return "Iris Versicolour";
}
}
else {
return "Iris Virginica";
}
}
}
}
else {
return "Iris Virginica";
}
}
}
private:
};
}
}

@ -0,0 +1,52 @@
#pragma once
#include <cstdarg>
namespace PublishingHouse
{
namespace RandomForest
{
class DecisionTree
{
public:
const char* predict(float (*getObservationValue)(int), bool (*consider)(float, int, float))
{
if ((consider)((getObservationValue)(2), 2, 3.5)) {
if ((consider)((getObservationValue)(1), 1, 4.0)) {
if ((consider)((getObservationValue)(1), 1, 3.0)) {
if ((consider)((getObservationValue)(2), 2, 1.4)) {
return "Iris Setosa";
}
else {
return "Iris Setosa";
}
}
else {
return "Iris Setosa";
}
}
else {
return "Iris Setosa";
}
}
else {
if ((consider)((getObservationValue)(3), 3, 1.8)) {
if ((consider)((getObservationValue)(0), 0, 5.7)) {
if ((consider)((getObservationValue)(0), 0, 5.2)) {
return "Iris Versicolour";
}
else {
return "Iris Versicolour";
}
}
else {
return "Iris Versicolour";
}
}
else {
return "Iris Virginica";
}
}
}
private:
};
}
}

@ -0,0 +1,97 @@
#pragma once
#include <cstdarg>
namespace PublishingHouse
{
namespace RandomForest
{
class DecisionTree
{
public:
const char* predict(float (*getObservationValue)(int), bool (*consider)(float, int, float))
{
if ((consider)((getObservationValue)(2), 2, 3.3)) {
if ((consider)((getObservationValue)(0), 0, 5.1)) {
if ((consider)((getObservationValue)(3), 3, 0.2)) {
if ((consider)((getObservationValue)(3), 3, 0.1)) {
return "Iris Setosa";
}
else {
return "Iris Setosa";
}
}
else {
return "Iris Setosa";
}
}
else {
return "Iris Setosa";
}
}
else {
if ((consider)((getObservationValue)(3), 3, 1.8)) {
if ((consider)((getObservationValue)(3), 3, 1.6)) {
if ((consider)((getObservationValue)(0), 0, 6.1)) {
if ((consider)((getObservationValue)(2), 2, 4.2)) {
if ((consider)((getObservationValue)(0), 0, 5.8)) {
if ((consider)((getObservationValue)(1), 1, 3.0)) {
if ((consider)((getObservationValue)(0), 0, 5.6)) {
if ((consider)((getObservationValue)(3), 3, 1.3)) {
if ((consider)((getObservationValue)(0), 0, 5.0)) {
return "Iris Versicolour";
}
else {
return "Iris Versicolour";
}
}
else {
return "Iris Versicolour";
}
}
else {
return "Iris Versicolour";
}
}
else {
return "Iris Versicolour";
}
}
else {
return "Iris Versicolour";
}
}
else {
return "Iris Versicolour";
}
}
else {
return "Iris Versicolour";
}
}
else {
if ((consider)((getObservationValue)(1), 1, 3.3)) {
return "Iris Virginica";
}
else {
return "Iris Versicolour";
}
}
}
else {
if ((consider)((getObservationValue)(2), 2, 4.9)) {
if ((consider)((getObservationValue)(0), 0, 6.0)) {
return "Iris Versicolour";
}
else {
return "Iris Virginica";
}
}
else {
return "Iris Virginica";
}
}
}
}
private:
};
}
}

@ -0,0 +1,57 @@
#pragma once
#include <cstdarg>
namespace PublishingHouse
{
namespace RandomForest
{
class TreeOfUnease
{
public:
const char* traverse(float (*getObservationValue)(int), bool (*considerWithUnease)(const char*, float, int, float))
{
if ((considerWithUnease)("Message", (getObservationValue)(3), 3, 1.0)) {
if ((considerWithUnease)("Message", (getObservationValue)(1), 1, 3.1)) {
if ((considerWithUnease)("Message", (getObservationValue)(2), 2, 1.3)) {
return "Iris Setosa";
}
else {
return "Iris Setosa";
}
}
else {
return "Iris Setosa";
}
}
else {
if ((considerWithUnease)("Message", (getObservationValue)(3), 3, 1.8)) {
if ((considerWithUnease)("Message", (getObservationValue)(2), 2, 5.6)) {
if ((considerWithUnease)("Message", (getObservationValue)(3), 3, 1.5)) {
if ((considerWithUnease)("Message", (getObservationValue)(3), 3, 1.3)) {
if ((considerWithUnease)("Message", (getObservationValue)(1), 1, 2.2)) {
return "Iris Versicolour";
}
else {
return "Iris Versicolour";
}
}
else {
return "Iris Versicolour";
}
}
else {
return "Iris Versicolour";
}
}
else {
return "Iris Virginica";
}
}
else {
return "Iris Virginica";
}
}
}
private:
};
}
}

@ -0,0 +1,62 @@
#pragma once
#include <cstdarg>
namespace PublishingHouse
{
namespace RandomForest
{
class TreeOfUnease
{
public:
const char* traverse(float (*getObservationValue)(int), bool (*considerWithUnease)(const char*, float, int, float))
{
if ((considerWithUnease)("Meise herbarium",(getObservationValue)(3), 3, 1.0)) {
if ((considerWithUnease)("About their « living herbarium »",(getObservationValue)(3), 3, 0.2)) {
if ((considerWithUnease)("Some of plants there come from Leopold II his garden",(getObservationValue)(3), 3, 0.1)) {
return "Iris Setosa";
}
else {
return "Iris Setosa";
}
}
else {
return "Iris Setosa";
}
}
else {
if ((considerWithUnease)("About the creation of its herbarium",(getObservationValue)(2), 2, 4.8)) {
if ((considerWithUnease)("The basis of the Meise Collection is an herbarium of the plants from Brazil",(getObservationValue)(2), 2, 4.6)) {
if ((considerWithUnease)("Leopold 2 bought it to assess whether to make Brazil a colony. But he chose Congo instead",(getObservationValue)(2), 2, 3.9)) {
return "?";
}
else {
return "Iris Versicolour";
}
}
else {
return "Iris Versicolour";
}
}
else {
if ((considerWithUnease)("Most of Meise specimens were acquired when you did not need permission from local communities to collect plants",(getObservationValue)(1), 1, 2.7)) {
if ((considerWithUnease)("This seems to change with frameworks such as the Nagoya Protocol and the convention on biological diversity",(getObservationValue)(2), 2, 5.0)) {
return "?";
}
else {
return "Iris Virginica";
}
}
else {
if ((considerWithUnease)("And there does not seem to be project to give them back to the countries they were collected from",(getObservationValue)(2), 2, 5.1)) {
return "?";
}
else {
return "Iris Virginica";
}
}
}
}
}
private:
};
}
}

@ -0,0 +1,57 @@
#pragma once
#include <cstdarg>
namespace PublishingHouse
{
namespace RandomForest
{
class TreeOfUnease
{
public:
const char* traverse(float (*getObservationValue)(int), bool (*considerWithUnease)(const char*, float, int, float))
{
if ((considerWithUnease)("Meise Data",(getObservationValue)(2), 2, 3.3)) {
if ((considerWithUnease)("About their digital portal",(getObservationValue)(2), 2, 1.4)) {
if ((considerWithUnease)("The fields used to describe the specimens seem restrictive",(getObservationValue)(3), 3, 0.1)) {
return "Iris Setosa";
}
else {
return "Iris Setosa";
}
}
else {
return "Iris Setosa";
}
}
else {
if ((considerWithUnease)("About the content of the dataset",(getObservationValue)(2), 2, 4.8)) {
if ((considerWithUnease)("One of Meises expertise is coffee and they gather a lot of data about it",(getObservationValue)(3), 3, 1.0)) {
return "Iris Versicolour";
}
else {
return "Iris Versicolour";
}
}
else {
if ((considerWithUnease)("The repartition of the samples is quite telling",(getObservationValue)(2), 2, 4.9)) {
if ((considerWithUnease)("1,5 % of type specimen were collected in Belgium, 22 % in RDC, 18 % in Brazil",(getObservationValue)(0), 0, 6.2)) {
return "Iris Versicolour";
}
else {
return "Iris Virginica";
}
}
else {
if ((considerWithUnease)("and mirrors the history of Botany",(getObservationValue)(3), 3, 1.8)) {
return "?";
}
else {
return "Iris Virginica";
}
}
}
}
}
private:
};
}
}

@ -0,0 +1,52 @@
#pragma once
#include <cstdarg>
namespace PublishingHouse
{
namespace RandomForest
{
class TreeOfUnease
{
public:
const char* traverse(float (*getObservationValue)(int), bool (*considerWithUnease)(const char*, float, int, float))
{
if ((considerWithUnease)("Classification",(getObservationValue)(3), 3, 1.0)) {
if ((considerWithUnease)("About the need for models",(getObservationValue)(1), 1, 3.0)) {
if ((considerWithUnease)("What is simple is always wrong. What is not is unusable. Paul Valéry 1942",(getObservationValue)(0), 0, 4.4)) {
return "Iris Setosa";
}
else {
return "Iris Setosa";
}
}
else {
return "Iris Setosa";
}
}
else {
if ((considerWithUnease)("About modeling from observations",(getObservationValue)(3), 3, 1.8)) {
if ((considerWithUnease)("it seems that we are reducing plants to a few numbered characteristics",(getObservationValue)(3), 3, 1.5)) {
if ((considerWithUnease)("Why not apply the same to humans ?",(getObservationValue)(3), 3, 1.4)) {
return "?";
}
else {
return "Iris Versicolour";
}
}
else {
if ((considerWithUnease)("Is the practice of categorisation bad in itself ?",(getObservationValue)(1), 1, 3.0)) {
return "?";
}
else {
return "?";
}
}
}
else {
return "Iris Virginica";
}
}
}
private:
};
}
}

@ -0,0 +1,37 @@
#pragma once
#include <cstdarg>
namespace PublishingHouse
{
namespace RandomForest
{
class TreeOfUnease
{
public:
const char* traverse(float (*getObservationValue)(int), bool (*considerWithUnease)(const char*, float, int, float))
{
if ((considerWithUnease)("Iris Dataset",(getObservationValue)(2), 2, 3.5)) {
if ((considerWithUnease)("About the iris Dataset",(getObservationValue)(1), 1, 4.0)) {
if ((considerWithUnease)("Its origin are troubling to say the least",(getObservationValue)(1), 1, 3.0)) {
if ((considerWithUnease)("It was first published in the Annals of Eugenics… Is it wrong to display it ?",(getObservationValue)(2), 2, 1.4)) {
return "Iris Setosa";
}
else {
return "Iris Setosa";
}
}
else {
return "Iris Setosa";
}
}
else {
return "Iris Setosa";
}
}
else {
return "?";
}
}
private:
};
}
}

@ -0,0 +1,67 @@
#pragma once
#include <cstdarg>
namespace PublishingHouse
{
namespace RandomForest
{
class TreeOfUnease
{
public:
const char* traverse(float (*getObservationValue)(int), bool (*considerWithUnease)(const char*, float, int, float))
{
if ((considerWithUnease)("Meise herbarium",(getObservationValue)(2), 2, 3.3)) {
if ((considerWithUnease)("About their « living herbarium »",(getObservationValue)(0), 0, 5.1)) {
if ((considerWithUnease)("Some of plants there come from Leopold II his garden",(getObservationValue)(3), 3, 0.2)) {
if ((considerWithUnease)("They dont specify it, but you can infer it from their signs",(getObservationValue)(3), 3, 0.1)) {
return "Iris Setosa";
}
else {
return "Iris Setosa";
}
}
else {
return "Iris Setosa";
}
}
else {
return "Iris Setosa";
}
}
else {
if ((considerWithUnease)("About the creation of its herbarium",(getObservationValue)(3), 3, 1.8)) {
if ((considerWithUnease)("The basis of the Meise Collection is an herbarium of the plants from Brazil",(getObservationValue)(3), 3, 1.6)) {
if ((considerWithUnease)("Leopold 2 bought it to assess whether to make Brazil a colony. But he chose Congo instead",(getObservationValue)(0), 0, 6.1)) {
return "?";
}
else {
return "Iris Versicolour";
}
}
else {
if ((considerWithUnease)("JSB Pohl contributed to it with 1479 specimens. He also brought back a pair of indigenous people.",(getObservationValue)(1), 1, 3.3)) {
return "Iris Virginica";
}
else {
return "Iris Versicolour";
}
}
}
else {
if ((considerWithUnease)("Most of Meise specimens were acquired when you did not need permission from local communities to collect plants",(getObservationValue)(2), 2, 4.9)) {
if ((considerWithUnease)("This seems to change with frameworks such as the Nagoya Protocol and the convention on biological diversity",(getObservationValue)(0), 0, 6.0)) {
return "Iris Versicolour";
}
else {
return "Iris Virginica";
}
}
else {
return "Iris Virginica";
}
}
}
}
private:
};
}
}

@ -0,0 +1,297 @@
/*********
For display
GxEPD_Example : test example for e-Paper displays from Waveshare and from Dalian Good Display Inc.
//
// Created by Jean-Marc Zingg based on demo code from Good Display,
// available on http://www.e-paper-display.com/download_list/downloadcategoryid=34&isMode=false.html
//
// Supporting Arduino Forum Topics:
// Waveshare e-paper displays with SPI: http://forum.arduino.cc/index.php?topic=487007.0
// Good Dispay ePaper for Arduino : https://forum.arduino.cc/index.php?topic=436411.0
// mapping suggestion for ESP32, e.g. LOLIN32, see .../variants/.../pins_arduino.h for your board
// NOTE: there are variants with different pins for SPI ! CHECK SPI PINS OF YOUR BOARD
// BUSY -> 4, RST -> 16, DC -> 17, CS -> SS(5), CLK -> SCK(18), DIN -> MOSI(23), GND -> GND, 3.3V -> 3.3V
*********/
/*********
For communication
Rui Santos
Complete project details at https://RandomNerdTutorials.com/esp-now-one-to-many-esp32-esp8266/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
*********/
// include library, include base class, make path known
#include <GxEPD.h> //->display
#include <esp_now.h>
#include <WiFi.h>
//#include "unease.h"
#include "Tree_0.h"
#include "Tree_of_unease_0.h"
//#include "Tree_1.h"
//#include "Tree_of_unease_1.h"
//#include "Tree_2.h"
//#include "Tree_of_unease_2.h"
//#include "Tree_3.h"
//#include "Tree_of_unease_3.h"
//#include "Tree_4.h"
//#include "Tree_of_unease_4.h"
PublishingHouse :: RandomForest :: TreeOfUnease treeOfUnease;
PublishingHouse :: RandomForest :: DecisionTree tree;
//const int randSeed = 6730/;
const int featureCount = 4;
const int treeNumber = 0;
int considerationStep = 0;
String considerationTraces = String();
const int verticalOffset = 19;
float lastObservation[featureCount] = { 0.0, 0.0, 0.0, 0.0 };
const char *answer;
const int answerPrefixLength = 3;
const char *answerPrefix[] = {
"It might be ",
"I think it is ",
"I would say it is "
};
///////////////////
///DISPLAY///
//////////////////
// select the display class to use, only one
#include <GxGDEH0154D67/GxGDEH0154D67.h> // 1.54" b/w
// FreeFonts from Adafruit_GFX
//#include <Fonts/FreeMonoBold9pt7b.h>/
//#include <Fonts/FreeMonoBold12pt7b.h>//
#include <Fonts/FreeSans12pt7b.h>
#include <Fonts/FreeSansOblique12pt7b.h>
//#include <Fonts/FreeMonoBold18pt7b.h>/
//#include <Fonts/FreeMonoBold24pt7b.h>/
#include <GxIO/GxIO_SPI/GxIO_SPI.h>
#include <GxIO/GxIO.h>
#if defined(ESP32)
// for SPI pin definitions see e.g.:
// C:\Users\xxx\Documents\Arduino\hardware\espressif\esp32\variants\lolin32\pins_arduino.h
GxIO_Class io(SPI, /*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16); // arbitrary selection of 17, 16
GxEPD_Class display(io, /*RST=*/ 16, /*BUSY=*/ 4); // arbitrary selection of (16), 4
#else
// for SPI pin definitions see e.g.:
// C:\Users\xxx\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\variants\standard\pins_arduino.h
GxIO_Class io(SPI, /*CS=*/ SS, /*DC=*/ 8, /*RST=*/ 9); // arbitrary selection of 8, 9 selected for default of GxEPD_Class
GxEPD_Class display(io, /*RST=*/ 9, /*BUSY=*/ 7); // default selection of (9), 7
#endif
float getObservationValue (int key)
{
return lastObservation[key];
}
///////////////////
///COMMUNICATION///
//////////////////
//Structure example to receive data
//Must match the sender structure
// This is the main loop of the program. It is ran whenever the board
// receives an observation.
void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len)
{
Serial.println("received data");
clearDisplay();
display.println("Received an observation:");
memcpy(&lastObservation, incomingData, sizeof(lastObservation));
for(int i=0; i < featureCount; i++) {
//lastObservation[i] = *incomingData[i];
Serial.println(lastObservation[i]);
display.println(lastObservation[i]);
}
display.update();
delay(10 * 1000);
classify();
}
void clearDisplay (){
display.fillScreen(GxEPD_WHITE);
display.setTextColor(GxEPD_BLACK);
display.setFont(&FreeSans12pt7b);
display.setCursor(0, verticalOffset);
// display.update();
}
void mightPrintUnease () {
// Serial.println(random(2));/
// Serial.println(random(2));/
if (random(3) < 2) {
clearDisplay();
display.fillScreen(GxEPD_BLACK);
display.setTextColor(GxEPD_WHITE);
display.setFont(&FreeSansOblique12pt7b);
Serial.println("Printing an unease.");
// display.println(tracesOfUnease[random(t/raceCount)]);
display.update();
display.fillScreen(GxEPD_WHITE);
display.setTextColor(GxEPD_BLACK);
display.setFont(&FreeSans12pt7b);
delay(15 * 1000);
}
}
// Consider a given value, feature number and threshold.
// If the value is lower than the threshold, answer yes
// otherwise answer no.
//
// Once every three calls a trace of unease will be printed
bool consider(float value, int feature, float threshold)
{
//mightPrintUnease();
clearDisplay();
Serial.println("Printing consideration");
clearDisplay();
Serial.println(considerationTraces);
display.println(considerationTraces);
// display.print("Step ");
// display.print(considerationStep);
display.print(".\nConsidering fea-\nture ");
display.print(feature);
display.print(", is it smaller\nthan ");
display.print(threshold);
display.print("?\n");
display.update();
delay(10 * 1000);
considerationStep = considerationStep + 1;
if (value < threshold) {
display.println("Yes. Going left.");
considerationTraces.concat(considerationStep);
considerationTraces.concat(": L ");
display.update();
delay(10 * 1000);
return true;
}
else {
display.println("No. Going right.");
considerationTraces.concat(considerationStep);
considerationTraces.concat(": R ");
display.update();
delay(10 * 1000);
return false;
}
}
// Print the forwarded unease and consider the given value,
// feature number and threshold. If the value is lower than the threshold,
// return true otherwise false.
bool considerWithUnease(const char *unease, float value, int feature, float threshold)
{
Serial.println("Printing unease");
clearDisplay();
Serial.println(unease);
display.println(unease); // Test whether it's * ?
display.update();
delay(20 * 1000);
if (value < threshold) {
return true;
}
else {
return false;
}
}
void classify ()
{
considerationStep = 0;
Serial.println("Starting classification");
if (random(3) == 0) {
treeOfUnease.traverse(&getObservationValue, &considerWithUnease);
}
else {
answer=tree.predict(&getObservationValue, &consider);
clearDisplay();
// display.print("I say: ");
display.print(answerPrefix[random(answerPrefixLength)]);
display.print(answer);
display.update();
}
}
void setup()
{
randomSeed(analogRead(26));
// Setup serial
Serial.begin(115200);
Serial.println();
Serial.println("setup");
display.init(115200); // enable diagnostic output on Serial
Serial.println("Starting...\n");
// Setup WiFi
// Set device as a Wi-Fi Station
WiFi.mode(WIFI_STA);
// print our mac address
Serial.println(WiFi.macAddress());
// Init ESP-NOW
if (esp_now_init() != ESP_OK) {
Serial.println("Error initializing ESP-NOW");
for(;;) { delay(1); } // do not initialize wait forever
}
Serial.println("initialized ESP-NOW");
// First output to the world!
clearDisplay();
display.setRotation(2);
// display.println("Hello!");
display.print("Tree ");
display.print(treeNumber);
display.print("\n");
display.println("You can reach me at");
display.println(WiFi.macAddress());
display.update();
delay(1000);
// Register for a callback function that will be called when data is received
esp_now_register_recv_cb(OnDataRecv);
}
void loop()
{
delay(500);
// clearDisplay();
// if (dataReceived%2==0){
// Serial.println();
//// dataReceived_s= "whispers in my ears";
//// predicted= " an oak ";
// }
// else{
// Serial.println(clf.predict(irisSample, println, clear, delay));
//// dataReceived_s= "murmurations";
//// predicted= "an Iris";
// }
}

@ -0,0 +1,154 @@
const int observationCount = 150;
const int observationFeatureCount = 4;
float observations[observationCount][observationFeatureCount] = {
{5.1, 3.5, 1.4, 0.2},
{4.9, 3.0, 1.4, 0.2},
{4.7, 3.2, 1.3, 0.2},
{4.6, 3.1, 1.5, 0.2},
{5.0, 3.6, 1.4, 0.2},
{5.4, 3.9, 1.7, 0.4},
{4.6, 3.4, 1.4, 0.3},
{5.0, 3.4, 1.5, 0.2},
{4.4, 2.9, 1.4, 0.2},
{4.9, 3.1, 1.5, 0.1},
{5.4, 3.7, 1.5, 0.2},
{4.8, 3.4, 1.6, 0.2},
{4.8, 3.0, 1.4, 0.1},
{4.3, 3.0, 1.1, 0.1},
{5.8, 4.0, 1.2, 0.2},
{5.7, 4.4, 1.5, 0.4},
{5.4, 3.9, 1.3, 0.4},
{5.1, 3.5, 1.4, 0.3},
{5.7, 3.8, 1.7, 0.3},
{5.1, 3.8, 1.5, 0.3},
{5.4, 3.4, 1.7, 0.2},
{5.1, 3.7, 1.5, 0.4},
{4.6, 3.6, 1.0, 0.2},
{5.1, 3.3, 1.7, 0.5},
{4.8, 3.4, 1.9, 0.2},
{5.0, 3.0, 1.6, 0.2},
{5.0, 3.4, 1.6, 0.4},
{5.2, 3.5, 1.5, 0.2},
{5.2, 3.4, 1.4, 0.2},
{4.7, 3.2, 1.6, 0.2},
{4.8, 3.1, 1.6, 0.2},
{5.4, 3.4, 1.5, 0.4},
{5.2, 4.1, 1.5, 0.1},
{5.5, 4.2, 1.4, 0.2},
{4.9, 3.1, 1.5, 0.1},
{5.0, 3.2, 1.2, 0.2},
{5.5, 3.5, 1.3, 0.2},
{4.9, 3.1, 1.5, 0.1},
{4.4, 3.0, 1.3, 0.2},
{5.1, 3.4, 1.5, 0.2},
{5.0, 3.5, 1.3, 0.3},
{4.5, 2.3, 1.3, 0.3},
{4.4, 3.2, 1.3, 0.2},
{5.0, 3.5, 1.6, 0.6},
{5.1, 3.8, 1.9, 0.4},
{4.8, 3.0, 1.4, 0.3},
{5.1, 3.8, 1.6, 0.2},
{4.6, 3.2, 1.4, 0.2},
{5.3, 3.7, 1.5, 0.2},
{5.0, 3.3, 1.4, 0.2},
{7.0, 3.2, 4.7, 1.4},
{6.4, 3.2, 4.5, 1.5},
{6.9, 3.1, 4.9, 1.5},
{5.5, 2.3, 4.0, 1.3},
{6.5, 2.8, 4.6, 1.5},
{5.7, 2.8, 4.5, 1.3},
{6.3, 3.3, 4.7, 1.6},
{4.9, 2.4, 3.3, 1.0},
{6.6, 2.9, 4.6, 1.3},
{5.2, 2.7, 3.9, 1.4},
{5.0, 2.0, 3.5, 1.0},
{5.9, 3.0, 4.2, 1.5},
{6.0, 2.2, 4.0, 1.0},
{6.1, 2.9, 4.7, 1.4},
{5.6, 2.9, 3.6, 1.3},
{6.7, 3.1, 4.4, 1.4},
{5.6, 3.0, 4.5, 1.5},
{5.8, 2.7, 4.1, 1.0},
{6.2, 2.2, 4.5, 1.5},
{5.6, 2.5, 3.9, 1.1},
{5.9, 3.2, 4.8, 1.8},
{6.1, 2.8, 4.0, 1.3},
{6.3, 2.5, 4.9, 1.5},
{6.1, 2.8, 4.7, 1.2},
{6.4, 2.9, 4.3, 1.3},
{6.6, 3.0, 4.4, 1.4},
{6.8, 2.8, 4.8, 1.4},
{6.7, 3.0, 5.0, 1.7},
{6.0, 2.9, 4.5, 1.5},
{5.7, 2.6, 3.5, 1.0},
{5.5, 2.4, 3.8, 1.1},
{5.5, 2.4, 3.7, 1.0},
{5.8, 2.7, 3.9, 1.2},
{6.0, 2.7, 5.1, 1.6},
{5.4, 3.0, 4.5, 1.5},
{6.0, 3.4, 4.5, 1.6},
{6.7, 3.1, 4.7, 1.5},
{6.3, 2.3, 4.4, 1.3},
{5.6, 3.0, 4.1, 1.3},
{5.5, 2.5, 4.0, 1.3},
{5.5, 2.6, 4.4, 1.2},
{6.1, 3.0, 4.6, 1.4},
{5.8, 2.6, 4.0, 1.2},
{5.0, 2.3, 3.3, 1.0},
{5.6, 2.7, 4.2, 1.3},
{5.7, 3.0, 4.2, 1.2},
{5.7, 2.9, 4.2, 1.3},
{6.2, 2.9, 4.3, 1.3},
{5.1, 2.5, 3.0, 1.1},
{5.7, 2.8, 4.1, 1.3},
{6.3, 3.3, 6.0, 2.5},
{5.8, 2.7, 5.1, 1.9},
{7.1, 3.0, 5.9, 2.1},
{6.3, 2.9, 5.6, 1.8},
{6.5, 3.0, 5.8, 2.2},
{7.6, 3.0, 6.6, 2.1},
{4.9, 2.5, 4.5, 1.7},
{7.3, 2.9, 6.3, 1.8},
{6.7, 2.5, 5.8, 1.8},
{7.2, 3.6, 6.1, 2.5},
{6.5, 3.2, 5.1, 2.0},
{6.4, 2.7, 5.3, 1.9},
{6.8, 3.0, 5.5, 2.1},
{5.7, 2.5, 5.0, 2.0},
{5.8, 2.8, 5.1, 2.4},
{6.4, 3.2, 5.3, 2.3},
{6.5, 3.0, 5.5, 1.8},
{7.7, 3.8, 6.7, 2.2},
{7.7, 2.6, 6.9, 2.3},
{6.0, 2.2, 5.0, 1.5},
{6.9, 3.2, 5.7, 2.3},
{5.6, 2.8, 4.9, 2.0},
{7.7, 2.8, 6.7, 2.0},
{6.3, 2.7, 4.9, 1.8},
{6.7, 3.3, 5.7, 2.1},
{7.2, 3.2, 6.0, 1.8},
{6.2, 2.8, 4.8, 1.8},
{6.1, 3.0, 4.9, 1.8},
{6.4, 2.8, 5.6, 2.1},
{7.2, 3.0, 5.8, 1.6},
{7.4, 2.8, 6.1, 1.9},
{7.9, 3.8, 6.4, 2.0},
{6.4, 2.8, 5.6, 2.2},
{6.3, 2.8, 5.1, 1.5},
{6.1, 2.6, 5.6, 1.4},
{7.7, 3.0, 6.1, 2.3},
{6.3, 3.4, 5.6, 2.4},
{6.4, 3.1, 5.5, 1.8},
{6.0, 3.0, 4.8, 1.8},
{6.9, 3.1, 5.4, 2.1},
{6.7, 3.1, 5.6, 2.4},
{6.9, 3.1, 5.1, 2.3},
{5.8, 2.7, 5.1, 1.9},
{6.8, 3.2, 5.9, 2.3},
{6.7, 3.3, 5.7, 2.5},
{6.7, 3.0, 5.2, 2.3},
{6.3, 2.5, 5.0, 1.9},
{6.5, 3.0, 5.2, 2.0},
{6.2, 3.4, 5.4, 2.3},
{5.9, 3.0, 5.1, 1.8}
};

@ -0,0 +1,97 @@
#include <Arduino.h>
#include <esp_now.h>
#include "WiFi.h"
#include "observations.h"
#include <stdlib.h>
#include <time.h>
const int timeBetweenBroadcasts = 5 * 60 * 1000;
uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success 1" : "Delivery Fail 1");
if (status ==0){
Serial.println("Delivery Success 2");
}
else{
Serial.println("Delivery fail 2");
}
Serial.println();
}
void setup()
{
// Seed random number generator
randomSeed(analogRead(26));
// 2700451
// 5827809
Serial.begin(115200);
Serial.println("Starting...\n");
// Set device as a Wi-Fi Station
WiFi.mode(WIFI_STA);
Serial.println(WiFi.macAddress());
// Init ESP-NOW
if (esp_now_init() != ESP_OK) {
Serial.println("Error initializing ESP-NOW");
for(;;) { delay(1); } // do not initialize wait forever
}
Serial.println("initialized ESP-NOW");
// Once ESPNow is successfully Init, we will register for Send CB to
// get the status of Trasnmitted packet
esp_now_register_send_cb(OnDataSent);
// Register peer
esp_now_peer_info_t peerInfo;
memset(&peerInfo, 0, sizeof(peerInfo));
memcpy(peerInfo.peer_addr, broadcastAddress, 6);
peerInfo.channel = 0;
peerInfo.encrypt = false;
// Add peer
if (esp_now_add_peer(&peerInfo) != ESP_OK){
Serial.println("Failed to add peer");
for(;;) { delay(1); } // do not initialize wait forever
}
}
float pickedObservation[observationFeatureCount];
const int datasize=observationFeatureCount*sizeof(float);
unsigned int pickedIndex;
void loop()
{
pickedIndex = random(observationCount);
Serial.print("Picked index ");
Serial.print(pickedIndex);
Serial.println();
// Fix. Less ugly way of copying?
for (int i=0; i < observationFeatureCount; i++) {
pickedObservation[i] = observations[pickedIndex][i];
Serial.println(pickedObservation[i]);
}
//pickedObservation[4] = observations[pickedIndex];
// Send message via ESP-NOW (size of an int is 4 bytes on ESP32)
esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) pickedObservation, datasize);
if (result == ESP_OK) {
Serial.println("Sent observation with success");
}
else {
Serial.println("Error sending the data");
}
Serial.println(WiFi.macAddress());
delay(timeBetweenBroadcasts);
}

@ -0,0 +1,7 @@
# A Council of trees
Code is meant to run on ESP-32 boards.
The sender broadcasts an observation, over WiFi.
On receiving the data the receivers classify trees using a decision tree model.

@ -0,0 +1,28 @@
I have a thought about the Meise herbarium...,...about their « living herbarium »...,...some of plants there come from Leopold II his garden:,"...they dont specify it, but you can infer it from their signs"
,,,...(how) Should they be exhibited ?
,,...some of the plants are engineered or kept just there...,…the sansevira was even long thought to be extinct in the wild
,,,..or cultivated to flourish the desks of Belgian civil servants
,...about the creation of its herbarium...,...the basis of the Meise Collection is an herbarium of the plants from Brazil...,...Leopold II bought it to assess Brazil as a colony. But he chose Congo instead
,,,...JSB Pohl contributed to it with 1479 specimens. He also brought back a pair of indigenous people.
,,...most specimens were acquired when permission from local communities wasnt required…,...this seems to change with frameworks such as the Nagoya Protocol and the convention on biological diversity
,,,…and there does not seem to be project to give them back to the countries they were collected from
But on the data of Meise…,...and their digital portal...,...the fields used to describe the specimens seem restrictive,"...there is no field for indigenous names, indigenous use or possible help that the collecter had when collecting the plant"
,,,...is a plant collected or extracted ? What makes the difference ?
,,...an interesting term is a « type specimen »…,"...the type specimen, is the first descrition a specimen for western science. Meise has 63,652 type specimens."
,,,...a type specimen cannot be living. The only way to make a type specimen of an endling is to kill it.
,...and the content of the dataset…,...one of Meises expertise is coffee and they gather a lot of data about it…,...yet Coffee does not grow in Belgium
,,,...an expertise they inherited from colonisation and that they can only sustain through their relationships with former colonies
,,...the repartition of the samples is quite telling...,"...1,5 % of type specimen were collected in Belgium, 22 % in RDC, 18 % in Brazil"
,,,...and mirrors the history of Botany
I feel unease on classification...,...about the need for models…,...what is simple is always wrong. What is not is unusable. Paul Valéry 1942…,...it is the core problem of abstract reasoning
,,,...but usable for who? And for what?
,,"...all models are wrong, but some are useful...",...but are they really ?
,,,"...its la carte et le territoire again, isnt it ?"
,...about modeling from observations…,...it seems that we are reducing plants to a few numbered characteristics…,...why not apply the same to humans ?
,,,...is the practice of categorisation bad in itself ?
,,"...a model is an abstraction, considering only a limited set of measurable properties…",...thats a lot to consider
,,,...we tend to forget that there is more to reality than this.
There is something with the Iris Dataset,...its origin are troubling to say the least…,...it was first published in the Annals of Eugenics… Is it wrong to display it ?,
,,...its creator was a fervent Eugenist… Should we still use it ?,
,...species in this dataset are lineraly separable.. ,...which make classification algorithms reach perfect accuracy…,...this also explains why it is so popular in Machine Learning education.
,,,...but the data in the world is seldom as simply separable and correlated as this.
1 I have a thought about the Meise herbarium... ...about their « living herbarium »... ...some of plants there come from Leopold II his garden: ...they don’t specify it, but you can infer it from their signs
2 ...(how) Should they be exhibited ?
3 ...some of the plants are engineered or kept just there... …the sansevira was even long thought to be extinct in the wild
4 ..or cultivated to flourish the desks of Belgian civil servants
5 ...about the creation of its herbarium... ...the basis of the Meise Collection is an herbarium of the plants from Brazil... ...Leopold II bought it to assess Brazil as a colony. But he chose Congo instead
6 ...JSB Pohl contributed to it with 1479 specimens. He also brought back a pair of indigenous people.
7 ...most specimens were acquired when permission from local communities wasn’t required… ...this seems to change with frameworks such as the Nagoya Protocol and the convention on biological diversity
8 …and there does not seem to be project to give them back to the countries they were collected from
9 But on the data of Meise… ...and their digital portal... ...the fields used to describe the specimens seem restrictive ...there is no field for indigenous names, indigenous use or possible help that the collecter had when collecting the plant
10 ...is a plant collected or extracted ? What makes the difference ?
11 ...an interesting term is a « type specimen »… ...the ‘type specimen‘, is the first descrition a specimen for western science. Meise has 63,652 type specimens.
12 ...a type specimen cannot be living. The only way to make a type specimen of an endling is to kill it.
13 ...and the content of the dataset… ...one of Meise’s expertise is coffee and they gather a lot of data about it… ...yet Coffee does not grow in Belgium
14 ...an expertise they inherited from colonisation and that they can only sustain through their relationships with former colonies
15 ...the repartition of the samples is quite telling... ...1,5 % of type specimen were collected in Belgium, 22 % in RDC, 18 % in Brazil
16 ...and mirrors the history of Botany
17 I feel unease on classification... ...about the need for models… ...what is simple is always wrong. What is not is unusable. Paul Valéry 1942… ...it is the core problem of abstract reasoning
18 ...but usable for who? And for what?
19 ...all models are wrong, but some are useful... ...but are they really ?
20 ...it’s la carte et le territoire again, isn’t it ?
21 ...about modeling from observations… ...it seems that we are reducing plants to a few numbered characteristics… ...why not apply the same to humans ?
22 ...is the practice of categorisation bad in itself ?
23 ...a model is an abstraction, considering only a limited set of measurable properties… ...that’s a lot to consider
24 ...we tend to forget that there is more to reality than this.
25 There is something with the Iris Dataset ...its origin are troubling to say the least… ...it was first published in the Annals of Eugenics… Is it wrong to display it ?
26 ...its creator was a fervent Eugenist… Should we still use it ?
27 ...species in this dataset are lineraly separable.. ...which make classification algorithms reach perfect accuracy… ...this also explains why it is so popular in Machine Learning education.
28 ...but the data in the world is seldom as simply separable and correlated as this.

@ -0,0 +1,159 @@
indent_prefix = 2 * ' '
def indent_line(line):
return indent_prefix + line
def encode_branch_with_unease(branch):
if isinstance(branch, dict):
if 'label' in branch:
return encode_tree_with_unease(branch)
else:
return [ indent_line('return "?";') ]
elif isinstance(branch, (int, float)):
return [ indent_line('return {};'.format(branch)) ]
else:
return [ indent_line('return "{}";'.format(branch)) ]
# if value at index is smaller than threshold
# enter left, else right
def encode_tree_with_unease(tree):
lines = [
"if ((considerWithUnease)(\"{unease}\",(getObservationValue)({index}), {index}, {threshold})) {{".format(index=tree['index'], threshold=tree['value'], unease=tree['label']),
*encode_branch_with_unease(tree['left']),
"}",
"else {",
*encode_branch_with_unease(tree['right']),
"}"
]
return map(indent_line, lines)
def encode_branch(branch):
if isinstance(branch, dict):
return encode_tree(branch)
elif isinstance(branch, (int, float)):
return [ indent_line('return {};'.format(branch)) ]
else:
return [ indent_line('return "{}";'.format(branch)) ]
# if value at index is smaller than threshold
# enter left, else right
def encode_tree(tree):
lines = [
"if ((consider)((getObservationValue)({index}), {index}, {threshold})) {{".format(index=tree['index'], threshold=tree['value']),
*encode_branch(tree['left']),
"}",
"else {",
*encode_branch(tree['right']),
"}"
]
return map(indent_line, lines)
def make_classifier (tree):
lines = [
"#pragma once",
"#include <cstdarg>",
"namespace PublishingHouse",
"{",
*map(indent_line, [
"namespace RandomForest",
"{",
*map(indent_line, [
"class DecisionTree",
"{",
"public:",
*map(indent_line, [
"const char* predict(float (*getObservationValue)(int), bool (*consider)(float, int, float))",
"{",
*encode_tree(tree),
"}",
]),
"private:",
"};"
]),
"}"
]),
"}",
]
return('\n'.join(lines))
def make_classifier_unease (tree):
lines = [
"#pragma once",
"#include <cstdarg>",
"namespace PublishingHouse",
"{",
*map(indent_line, [
"namespace RandomForest",
"{",
*map(indent_line, [
"class TreeOfUnease",
"{",
"public:",
*map(indent_line, [
"const char* traverse(float (*getObservationValue)(int), bool (*considerWithUnease)(const char*, float, int, float))",
"{",
*encode_tree_with_unease(tree),
"}",
]),
"private:",
"};"
]),
"}"
]),
"}",
]
return('\n'.join(lines))
if __name__ == '__main__':
import json
import os.path
import glob
basepath = os.path.dirname(os.path.realpath(__file__))
globpath = os.path.realpath(os.path.join(basepath, 'random_forest_model_*-trees.json'))
globpath = os.path.realpath(os.path.join(basepath, '*.json'))
models = glob.glob(globpath)
# Search for exported models
print("Found:")
for k, modelpath in enumerate(models):
print("[{}] {}".format(k, modelpath))
model_key = int(input("Which model?\n"))
modelpath = models[model_key]
# Open model
with open(modelpath, 'r') as file_in:
# Parse the forest
forest = json.load(file_in)
modelname, _ = os.path.splitext(os.path.basename(modelpath))
classifiernamepattern = 'Tree_{{}}.h'.format(modelname)
uneasenamepattern = 'Tree_of_unease_{{}}.h'.format(modelname)
# Walk through the forest and visualize the trees
for idx, tree in enumerate(forest):
print('Transforming tree {} of {}'.format(idx, len(forest)))
with open(os.path.join(basepath, classifiernamepattern.format(idx)), 'w') as h:
h.write(make_classifier(tree))
with open(os.path.join(basepath, uneasenamepattern.format(idx)), 'w') as h:
h.write(make_classifier_unease(tree))
print('Classifiers placed in: {}'.format(basepath))

@ -0,0 +1,44 @@
"""
Parses the spreadsheet into a tree structure
"""
import csv
import os.path
import json
columns = 4
position = [ 0 for _ in range(columns) ]
tree = []
def parse_column_chunk (column, start):
label = data[start][column]
end = start
children = []
while end + 1 < len(data) and (data[end + 1][column] == label or data[end + 1][column] == ''):
end += 1
if column + 1 < columns:
child_end = start
while child_end <= end and child_end < len(data):
_, child_end, child = parse_column_chunk(column + 1, child_end)
child_end += 1
children.append(child)
return (start, end, { 'label': label, 'children': children})
basepath = os.path.abspath(os.path.dirname(__file__))
with open(os.path.join(basepath, 'data.csv'), 'r') as csvfile:
reader = csv.reader(csvfile)
data = [row for row in reader]
start = 0
while start < len(data):
_, end, node = parse_column_chunk(0, start)
start = end + 1
tree.append(node)
json.dump(tree, open(os.path.join(basepath, 'unease.json'), 'w'), ensure_ascii=False)
Loading…
Cancel
Save