Commit c952081c authored by LIGNEUL CLEMENT's avatar LIGNEUL CLEMENT
Browse files

add parser + plot systeme + improve menus

parent 93255db8
......@@ -13,6 +13,10 @@ all:
npx nodegui-packer --pack ./dist
@echo "\n##### Copie du script de graphe #####\n"
find 'deploy/' -type d -name doc | sed 's/doc//' | xargs -n 1 cp -v src/plot.py
@echo "\n##### Packaging terminé #####\n"
clean:
......
......@@ -8,13 +8,25 @@ Cette application a été conçu et testé sur Ubuntu 20.10
Pour utiliser ce programme il est nécessaire d'avoir installé EASEA (voir http://easea.unistra.fr/index.php/Downloading_EASEA)
### Linux
### General dependencies
- Python 3 minimum
- Plotly to plot graphs :
- With pip : `pip install plotly==5.1.0`
- With conda : `conda install -c plotly plotly=5.1.0`
- Pandas :
- With pip : `pip install pandas`
- kaleido to save graphs :
- With pip : `pip install kaleido`
- With conda : `conda install -c conda-forge python-kaleido`
### Linux dependencies
- Make, GCC v7
- CMake 3.1 ou ultérieur
- Node.JS version 12 et plus
### macOS
### macOS dependencies
- macOS 10.10 et plus (OS 64 bits seulement)
- Make, GCC v7
......
{
"name": "EASEA-compiler-app",
"version": "1.0.0",
"main": "index.js",
"main": "index.ts",
"description": "Interface graphique du compilateur EASEA",
"author": "Clément Ligneul <clement.ligneul@etu.unistra.fr>",
"private": false,
......@@ -16,6 +16,7 @@
},
"devDependencies": {
"@nodegui/packer": "^1.4.1",
"@types/fs-extra": "^9.0.11",
"@types/node": "^15.12.4",
"clean-webpack-plugin": "^3.0.0",
"file-loader": "^6.2.0",
......
......@@ -34,7 +34,7 @@ export class Advanced_option_widget{
this.text_edit.setPlaceholderText(this.place_holder);
this.layout.addWidget(this.label);
this.layout.addWidget(this.text_edit);
this.widget.setMaximumSize(290, 100);
this.widget.setMaximumSize(310, 100);
}
}
\ No newline at end of file
This diff is collapsed.
......@@ -5,6 +5,9 @@ import { general_css } from './style';
import { Run_tab } from './run_tab';
import * as util from './utilities';
import { QMenuBar, QAction, QGridLayout } from "@nodegui/nodegui";
import { Plot_result } from './plot_tab';
import fs from 'fs';
import { exit } from 'process';
// list of running child processes
export let running_proc: ChildProcess[] = [];
......@@ -35,9 +38,15 @@ const run = new QWidget();
export const run_obj = new Run_tab('', '');
run.setLayout(run_obj.generate());
const plot = new QWidget();
export const plot_obj = new Plot_result();
plot.setLayout(plot_obj.generate());
const tab_menu = new QTabWidget();
tab_menu.addTab(compile, new QIcon(), 'Compile');
tab_menu.addTab(run, new QIcon(), 'Run');
tab_menu.addTab(plot, new QIcon(), 'Result Plot')
general_layout.addWidget(tab_menu);
......@@ -47,14 +56,23 @@ global_win.setLayout(general_layout);
global_win.setStyleSheet(general_css);
// global_win.setFixedSize(1300, 800);
// call at the end
global_win.addEventListener(WidgetEventTypes.Close, () => {
// console.log("On kill tout ici");
util.kill_all(running_proc);
fs.rmSync('./plotting', {recursive:true, force:true});
});
global_win.adjustSize();
global_win.setFixedSize(global_win.size().width(), global_win.size().height());
fs.mkdir('plotting/', (err)=>{
if(err && err.code !== 'EEXIST'){
console.log(err.message);
console.log(err);
exit(1);
}
});
global_win.show();
......
......@@ -12,8 +12,9 @@ export class Island_options_win{
constructor(){
this.window = new QDialog();
this.window.setWindowTitle('Islands Options');
this.window.setWindowFlag(WindowType.FramelessWindowHint, true);
this.window.setWindowTitle('Island Model Options');
this.window.setWindowFlag(WindowType.CustomizeWindowHint, true);
this.window.setWindowFlag(WindowType.WindowCloseButtonHint, false);
this.reevaluate = false;
this.server_port = NaN;
this.migration_proba = NaN;
......
import { Direction, QBoxLayout, QDialog, QPushButton, QWidget, WindowType } from "@nodegui/nodegui";
import { Direction, QBoxLayout, QComboBox, QDialog, QPushButton, QWidget, WindowType } from "@nodegui/nodegui";
import { Advanced_option_widget } from "./advanced_option_widget";
import { print_errors } from "./utilities";
......@@ -6,17 +6,20 @@ export class Offspring_options_win{
window: QDialog
size_off: number;
surviving_off: number;
surviving_off_type: string;
reduce_op: string;
reduce_pressure: number;
constructor(){
this.window = new QDialog();
this.window.setWindowTitle('Offspring Options');
this.window.setWindowFlag(WindowType.FramelessWindowHint, true);
this.window.setWindowFlag(WindowType.CustomizeWindowHint, true);
this.window.setWindowFlag(WindowType.WindowCloseButtonHint, false);
this.surviving_off = NaN;
this.reduce_op = 'Tournament';
this.reduce_pressure = 2.0;
this.size_off = NaN;
this.surviving_off_type = '#';
const main_layout = new QBoxLayout(Direction.TopToBottom);
......@@ -48,9 +51,27 @@ export class Offspring_options_win{
this.surviving_off = val;
});
const surviving_off_type = new QComboBox();
surviving_off_type.addItem(undefined, '#');
surviving_off_type.addItem(undefined, '%');
surviving_off_type.addEventListener('currentTextChanged', ()=>{
this.surviving_off_type = surviving_off_type.currentText();
});
surviving_offspring.layout.addWidget(surviving_off_type);
const reduce_off_op = new Advanced_option_widget('Reduce Operator :', 0, 'Tournament');
reduce_off_op.text_edit.addEventListener('textChanged', ()=>{
var text = reduce_off_op.text_edit.toPlainText();
var text = reduce_off_op.text_edit.toPlainText().toLowerCase();
if(text === 'tournament' || text === ''){
reduce_off_pressure.widget.setEnabled(true);
} else {
reduce_off_pressure.widget.setEnabled(false);
reduce_off_pressure.text_edit.setText('');
}
text = reduce_off_op.text_edit.toPlainText();
if(text === ''){
this.reduce_op = 'Tournament';
......@@ -84,9 +105,19 @@ export class Offspring_options_win{
var errors = [];
var ok = 1;
if(isNaN(Number(reduce_off_pressure.text_edit.toPlainText()))){
var pressure = Number(reduce_off_pressure.text_edit.toPlainText());
if(isNaN(pressure)){
ok = 0;
errors.push('Reduce Pressure');
} else if(pressure < 0.5 && pressure != 0){
ok = 0;
errors.push('Reduce Pressure : should be in [ 0.5 ; 1 [ U [ 2 ; +\u221e [');
} else if(pressure >= 1 && pressure < 2){
ok = 0;
errors.push('Reduce Pressure : should be in [ 0.5 ; 1 [ U [ 2 ; +\u221e [');
} else if(pressure >= 2 && pressure % 1 !== 0) {
ok = 0;
errors.push('Reduce Pressure : should be an integer if \u2265 2');
}
if(isNaN(Number(surviving_offspring.text_edit.toPlainText()))){
......
import { Direction, QBoxLayout, QDialog, QPushButton, QWidget, WindowType } from "@nodegui/nodegui";
import { Direction, QBoxLayout, QComboBox, QDialog, QPushButton, QWidget, WindowType } from "@nodegui/nodegui";
import { Advanced_option_widget } from "./advanced_option_widget";
import * as util from './utilities';
......@@ -6,35 +6,31 @@ export class Parent_options_win{
surviving: number;
reduce_op: string;
reduce_pressure: number;
nb_elite: number;
window: QDialog;
surviving_parent_type: string;
constructor(){
this.window = new QDialog();
this.window.setWindowTitle('Parents Options');
this.window.setWindowFlag(WindowType.FramelessWindowHint, true);
this.window.setWindowFlag(WindowType.CustomizeWindowHint, true);
this.window.setWindowFlag(WindowType.WindowCloseButtonHint, false);
this.surviving = NaN;
this.reduce_op = 'Tournament';
this.reduce_pressure = 2.0;
this.nb_elite = NaN;
this.surviving_parent_type = '#';
const main_layout = new QBoxLayout(Direction.TopToBottom);
const elite = new Advanced_option_widget('Elite Parents :', 0, '0');
elite.text_edit.addEventListener('textChanged', ()=>{
var text = elite.text_edit.toPlainText();
var val = Number(text);
if(text === ''){
this.nb_elite = NaN;
return ;
}
if(!isNaN(val))
this.nb_elite = val;
const surviving_parent = new Advanced_option_widget('Surviving Parents :', 0)
const surviving_parent_type = new QComboBox();
surviving_parent_type.addItem(undefined, '#');
surviving_parent_type.addItem(undefined, '%');
surviving_parent_type.addEventListener('currentTextChanged', ()=>{
this.surviving_parent_type = surviving_parent_type.currentText();
});
const surviving_parent = new Advanced_option_widget('Surviving Parents :', 0)
surviving_parent.layout.addWidget(surviving_parent_type);
surviving_parent.text_edit.addEventListener('textChanged', ()=>{
var text = surviving_parent.text_edit.toPlainText();
var val = Number(text);
......@@ -50,7 +46,16 @@ export class Parent_options_win{
const reduce_parent_op = new Advanced_option_widget('Reduction Operator :', 0, 'Tournament');
reduce_parent_op.text_edit.addEventListener('textChanged', ()=>{
var text = reduce_parent_op.text_edit.toPlainText();
var text = reduce_parent_op.text_edit.toPlainText().toLowerCase();
if(text === 'tournament' || text === ''){
reduce_parent_pressure.widget.setEnabled(true);
} else {
reduce_parent_pressure.widget.setEnabled(false);
reduce_parent_pressure.text_edit.setText('');
}
text = reduce_parent_op.text_edit.toPlainText();
if(text === ''){
this.reduce_op = 'Tournament';
......@@ -89,14 +94,19 @@ export class Parent_options_win{
errors.push('Surviving Parents');
}
if(isNaN(Number(reduce_parent_pressure.text_edit.toPlainText()))){
var pressure = Number(reduce_parent_pressure.text_edit.toPlainText());
if(isNaN(pressure)){
ok = 0;
errors.push('Reduce Pressure');
}
if(isNaN(Number(elite.text_edit.toPlainText()))){
} else if(pressure < 0.5 && pressure != 0){
ok = 0;
errors.push('Elite Parents');
errors.push('Reduce Pressure : should be in [ 0.5 ; 1 [ U [ 2 ; +\u221e [');
} else if(pressure >= 1 && pressure < 2){
ok = 0;
errors.push('Reduce Pressure : should be in [ 0.5 ; 1 [ U [ 2 ; +\u221e [');
} else if(pressure >= 2 && pressure % 1 !== 0) {
ok = 0;
errors.push('Reduce Pressure : should be an integer if \u2265 2');
}
if(ok){
......@@ -115,16 +125,12 @@ export class Parent_options_win{
reduce_parent_pressure.text_edit.setText('');
reduce_parent_op.text_edit.setText('');
elite.text_edit.setText('');
});
reset_btn.setFixedSize(100, 25);
btn_layout.addWidget(save_btn);
btn_layout.addWidget(reset_btn);
main_layout.addWidget(elite.widget);
main_layout.addWidget(surviving_parent.widget);
main_layout.addWidget(reduce_parent_op.widget);
main_layout.addWidget(reduce_parent_pressure.widget);
......
from os import name
from pandas.io.parsers import read_csv
import plotly.express as px
import plotly.graph_objects as go
import sys
from math import ceil
# df = read_csv(
# "https://raw.githubusercontent.com/plotly/datasets/master/violin_data.csv"
# )
# fig = go.Figure()
# fig.add_trace(
# go.Violin(
# x=df["day"],
# y=df["total_bill"],
# legendgroup="M",
# scalegroup="M",
# name="M",
# line_color="red",
# )
# )
# fig.add_trace(
# go.Violin(
# x=df["day"],
# y=df["total_bill"],
# legendgroup="F",
# scalegroup="F",
# name="F",
# line_color="green",
# )
# )
if(len(sys.argv) != 3):
print("Usage : " + sys.argv[0] + " <nb of generations> <nb of plots>" , file=sys.stderr)
exit(1)
# number of generations
nb_gen = int(sys.argv[1])
# number of violin plots
nb_plots = int(sys.argv[2])
treshold = ceil(nb_gen / nb_plots)
df = read_csv('plotting/data.csv')
fig = go.Figure()
for i in range(nb_plots):
fig.add_trace(
go.Violin(
y=df["BEST_FIT"] [df["GEN"] < (i * treshold)][df["GEN"] >= treshold * (i-1)],
fillcolor="red",
line_color="black",
name= '<' + str((i+1)*treshold)
)
)
fig.update_traces(box_visible=True, meanline_visible=True, points="all")
fig.update_layout(
# violinmode="group",
title={
"text": "Results",
"y": 0.9,
"x": 0.5,
"xanchor": "center",
"yanchor": "top",
},
)
fig.update_xaxes(
title_text="Generations"
)
fig.update_yaxes(
title_text="Best Fitness"
)
fig.write_image("plotting/fig.svg")
fig.write_html("plotting/fig.html")
import fs from 'fs';
export const data_csv = 'plotting/data.csv';
export function parser(data: string):number[][]{
var nb_lines = 0; // for final array
var str = data.toString()
// parse lines
var lines = str.split('\n'); //(/(\r?\n)/g);
var val_col: number[][] = [];
for(var i = 0; i < lines.length; i++)
val_col.push([]);
for (var i = 0; i < lines.length; i++) {
// parse columns
var col = lines[i].split('\t');
if(col.length === 8){
// nb_lines++;
for(var j = 0; j < 8; j++){
// time
if(col[j].charAt(col[j].length - 1) === 's')
col[j] = col[j].substring(0, col[j].length - 1);
if(!isNaN(Number(col[j]))){
val_col[i].push(Number(col[j]));
if(j !== 7){
write_in_file(Number(col[j]) + ',');
} else {
write_in_file(Number(col[j]) + '\n');
}
// console.log('add ' + col[j]);
}
}
}
}
// var final: number[][] = [];
// for(var i = 0; i < nb_lines; i++)
// final.push([]);
// for(var i = 0; i < nb_lines; i++){
// for(var j = 0; j < 8; j++){
// final[i].push(val_col[i][j]);
// }
// }
// for(var i = 0; i < val_col.length; i++){
// for(var j = 0; j < val_col[i].length; j++){
// if(isNaN(Number(val_col[i][j])))
// console.log('nan');
// else
// console.log(Number(val_col[i][j]));
// }
// console.log('\n');
// }
return val_col;
}
export function print_data(array: number[][]){
for(var i = 0; i < array.length; i++){
if(array[i].length === 8){
console.log('Generation : ' + array[i][0]);
console.log('Time : ' + array[i][1]);
console.log('Planned evaluation : ' + array[i][2]);
console.log('Actual evaluation : ' + array[i][3]);
console.log('Best individual fitness : ' + array[i][4]);
console.log('Avg fitness : ' + array[i][5]);
console.log('Worst fitness : ' + array[i][6]);
console.log('Stand dev : ' + array[i][7] + '\n');
}
}
}
export function write_in_file(buffer: string){
var fd:number;
try{
fd = fs.openSync(data_csv, 'ax');
} catch {
fd = fs.openSync(data_csv, 'a');
fs.writeFileSync(fd, buffer);
fs.closeSync(fd);
return;
}
var init_buf = 'GEN,TIME,PLAN_EVAL,ACTU_EVAL,BEST_FIT,AVG_FIT,WORST_FIT,STD_DEV';
fs.writeFileSync(fd, init_buf);
fs.writeFileSync(fd, '\n' + buffer);
fs.closeSync(fd);
}
\ No newline at end of file
import { QBoxLayout, QLabel, QPixmap, QPushButton, QTextEdit, QWidget, WidgetEventTypes } from "@nodegui/nodegui";
import { Pseudo_term } from "./pseudo_term";
import fs from 'fs';
import { exec, execSync, spawnSync, spawn } from "child_process";
import * as util from './utilities';
import { running_proc } from ".";
import { run_obj } from './index'
export class Plot_result{
widget: QWidget;
layout: QBoxLayout;
text: QTextEdit;
image_path: string;
image: QPixmap;
image_label: QLabel;
constructor(){
this.widget = new QWidget();
this.layout = new QBoxLayout(0);
this.text = new QTextEdit();
this.image_path = '';
this.image = new QPixmap();
this.image_label = new QLabel();
}
update_plot(path: string){
this.image_label.setText('');
try{
var nb_gen = run_obj.option_obj.nb_gen
execSync('python3 "src/plot.py" ' + nb_gen + ' 5', {timeout:20000});
} catch(e) {
try{
execSync('python3 "plot.py" 10 5', {timeout:20000});
} catch {
console.log('Error in "plot.py" : ' + e);
this.image_label.setText('Error in the python script, the graph can\'t be displayed');
return;
}
}
this.image_path = path;
if(this.image.load(path)){
this.image_label.setPixmap(this.image);
} else {
this.image_label.setText('Error : graph not found');
}
}
generate(){
this.widget.setLayout(this.layout);
this.text.setFixedSize(800,500);
this.text.setReadOnly(true);
// graph
this.image.load(this.image_path);
this.image_label.setPixmap(this.image);
const ps_console = new Pseudo_term('Plot :');
const btn = new QPushButton();
btn.setText('Go');
btn.addEventListener('clicked', ()=>{
ps_console.run_command('pwd');
ps_console.run_command('ls', ['-la']);
});
this.image_label.addEventListener(WidgetEventTypes.MouseButtonDblClick, ()=>{
spawn('open', ['plotting/fig.html'], {detached:true});
})
this.layout.addWidget(this.image_label);
// this.layout.addWidget(btn);
// this.layout.addWidget(ps_console.window);
return this.layout;
}
}
\ No newline at end of file
......@@ -4,6 +4,8 @@ import { spawn } from 'child_process';
import { spawnSync } from 'child_process';
import { running_proc } from '.';
import { Win_alert } from './win_alert';
import * as plot_generation from './plot_generation';
import { plot_obj, run_obj } from './index';
require('child_process').spawn('node', ['--version'], {
env: {
......@@ -60,7 +62,7 @@ export class Pseudo_term{
}
if(command != "nvcc"){
this.text.insertPlainText('\n$ ' + command + ' ' + res + '\n');
console.log('$ ' + command + ' ' + res + '\n');
// console.log('$ ' + command + ' ' + res + '\n');
}
}
......@@ -116,7 +118,7 @@ export class Pseudo_term{
}
if(command != "nvcc"){
this.text.insertPlainText('\n$ ' + command + ' ' + res + '\n');
console.log('$ ' + command + ' ' + res + '\n');
// console.log('$ ' + command + ' ' + res + '\n');
}
}
......@@ -182,7 +184,7 @@ export class Pseudo_term{
// }