From 36a81897abe3172c215a1e15e66a972bc94acecf Mon Sep 17 00:00:00 2001
From: Dylan Kruyff <d.l.w.kruyff@students.uu.nl>
Date: Sat, 28 Nov 2020 18:51:33 +0100
Subject: [PATCH] Refactor code

Former-commit-id: a63b132756f09dfeb25d2cce191947dca121d2f6
---
 AngularApp/prototype/src/app/api.service.ts   |  71 ++-
 .../progress-view/progress-view.component.ts  | 108 +---
 AngularApp/prototype/src/app/state.service.ts | 112 ++--
 .../table-overview.component.ts               |   6 +-
 Flaskserver/.idea/workspace.xml               |  19 +-
 Flaskserver/__pycache__/DBA.cpython-38.pyc    | Bin 4285 -> 0 bytes
 Flaskserver/__pycache__/DBA.cpython-39.pyc    | Bin 4269 -> 0 bytes
 Flaskserver/__pycache__/bigwig.cpython-38.pyc | Bin 7806 -> 0 bytes
 Flaskserver/__pycache__/main.cpython-38.pyc   | Bin 14695 -> 3405 bytes
 .../__pycache__/preprocessing.cpython-38.pyc  | Bin 0 -> 4100 bytes
 Flaskserver/__pycache__/pseudo.cpython-38.pyc | Bin 0 -> 7381 bytes
 Flaskserver/__pycache__/utils.cpython-38.pyc  | Bin 1180 -> 0 bytes
 Flaskserver/{ => data}/.gitattributes         |   0
 Flaskserver/{ => data}/21.csv                 |   0
 .../{ => data}/NW_Ground_Stations_2016.csv    |   0
 Flaskserver/{ => data}/chip_w-3000_r-25.h5    |   0
 Flaskserver/{ => data}/data.pkl               |   0
 Flaskserver/{ => data}/parameters.npy         |   0
 Flaskserver/{ => data}/processed-data         | Bin
 Flaskserver/{ => data}/processed-data.npy     |   0
 Flaskserver/{ => data}/query                  |   0
 Flaskserver/{ => data}/test.bigWig            |   0
 Flaskserver/{ => libs}/DBA.py                 |   0
 Flaskserver/{ => libs}/DBA_multivariate.py    |   0
 .../DBA_multivariate.cpython-38.pyc           | Bin 6075 -> 6080 bytes
 .../__pycache__/bigwig.cpython-38.pyc}        | Bin 7782 -> 7811 bytes
 Flaskserver/{ => libs}/bigwig.py              |   0
 Flaskserver/{ => libs}/setup.py               |   0
 Flaskserver/{ => libs}/utils.py               |   0
 Flaskserver/main.py                           | 590 +++++-------------
 Flaskserver/preprocessing.py                  | 118 ++++
 Flaskserver/pseudo.py                         | 243 ++++++++
 Flaskserver/topk.npy                          |   3 -
 33 files changed, 653 insertions(+), 617 deletions(-)
 delete mode 100644 Flaskserver/__pycache__/DBA.cpython-38.pyc
 delete mode 100644 Flaskserver/__pycache__/DBA.cpython-39.pyc
 delete mode 100644 Flaskserver/__pycache__/bigwig.cpython-38.pyc
 create mode 100644 Flaskserver/__pycache__/preprocessing.cpython-38.pyc
 create mode 100644 Flaskserver/__pycache__/pseudo.cpython-38.pyc
 delete mode 100644 Flaskserver/__pycache__/utils.cpython-38.pyc
 rename Flaskserver/{ => data}/.gitattributes (100%)
 rename Flaskserver/{ => data}/21.csv (100%)
 rename Flaskserver/{ => data}/NW_Ground_Stations_2016.csv (100%)
 rename Flaskserver/{ => data}/chip_w-3000_r-25.h5 (100%)
 rename Flaskserver/{ => data}/data.pkl (100%)
 rename Flaskserver/{ => data}/parameters.npy (100%)
 rename Flaskserver/{ => data}/processed-data (100%)
 rename Flaskserver/{ => data}/processed-data.npy (100%)
 rename Flaskserver/{ => data}/query (100%)
 rename Flaskserver/{ => data}/test.bigWig (100%)
 rename Flaskserver/{ => libs}/DBA.py (100%)
 rename Flaskserver/{ => libs}/DBA_multivariate.py (100%)
 rename Flaskserver/{ => libs}/__pycache__/DBA_multivariate.cpython-38.pyc (97%)
 rename Flaskserver/{__pycache__/bigwig.cpython-39.pyc => libs/__pycache__/bigwig.cpython-38.pyc} (71%)
 rename Flaskserver/{ => libs}/bigwig.py (100%)
 rename Flaskserver/{ => libs}/setup.py (100%)
 rename Flaskserver/{ => libs}/utils.py (100%)
 create mode 100644 Flaskserver/preprocessing.py
 create mode 100644 Flaskserver/pseudo.py
 delete mode 100644 Flaskserver/topk.npy

diff --git a/AngularApp/prototype/src/app/api.service.ts b/AngularApp/prototype/src/app/api.service.ts
index 80573ff4..9b23e33d 100644
--- a/AngularApp/prototype/src/app/api.service.ts
+++ b/AngularApp/prototype/src/app/api.service.ts
@@ -7,11 +7,12 @@ export interface RawData {
 
 export interface LshData {
   candidates: number[][][];
-  tables: {[bucket: string]: number[]}[];
+  distances: number[][][];
   average_candidates: number[];
   average_distances: number[];
+  tables: {[bucket: string]: number[]}[];
+  average_table: {[bucket: string]: number[]};
   samples: number[];
-  distances: number[][][];
   hash_functions: number[][];
   parameters?: number[];
 }
@@ -25,23 +26,37 @@ export interface TableInfoData {
   distances: number[][];
 }
 
+export interface Parameters {
+  windowsize: number;
+  hashsize: number;
+  tablesize: number;
+  stepsize: number;
+}
+
 @Injectable({
   providedIn: 'root'
 })
+/**
+ * This service acts as the interface between the client and server side.
+ */
 export class ApiService {
 
   constructor() { }
 
-  // Read input data
+  /**
+   * Read input data. The format is a list of channels, where each channel is an object of type RawData
+   */
   async readFile(): Promise<RawData[]> {
-    const response = await fetch('http://127.0.0.1:5000/read-mts-data');
+    const response = await fetch('http://127.0.0.1:5000/read-data');
     return await response.json();
   }
 
-  // Split data into windows and normalize
-  async createWindows(parameters): Promise<any> {
+  /**
+   * Split the data into windows (server side)
+   */
+  async createWindows(parameters: Parameters): Promise<any> {
     const postData = {parameters};
-    const response = await fetch('http://127.0.0.1:5000/create-mts-windows', {
+    await fetch('http://127.0.0.1:5000/create-windows', {
       method: 'POST',
       headers: {
         'Accept': 'application/json',
@@ -51,32 +66,39 @@ export class ApiService {
     });
   }
 
-  // Calculate parameters for LSH + find candidates using LSH
-  async lshInitial(query): Promise<LshData> {
-    const response = await fetch('http://127.0.0.1:5000/initialize', {
+  /**
+   * Get weights which will be applied to the LSH hash functions
+   */
+  async getWeights(query: number[][], labels: {[index: number]: boolean}, weights: number[], hash_functions: number[][]): Promise<number[]> {
+    const response = await fetch('http://127.0.0.1:5000/weights', {
       method: 'POST',
       headers: {
         'Accept': 'application/json',
         'Content-Type': 'application/json'
       },
-      body: new Blob( [ JSON.stringify({query}) ], { type: 'text/plain' } )
+      body: new Blob( [ JSON.stringify({query, labels, weights, hash_functions}) ], { type: 'text/plain' } )
     });
     return await response.json();
   }
 
-  async getWeights(query: number[][], labels: {[index: number]: boolean}, weights: number[], hash_functions: number[][]): Promise<number[]> {
-    const response = await fetch('http://127.0.0.1:5000/weights', {
+  /**
+   * Do the first iteration of LSH and return important information
+   */
+  async lshInitial(query: number[][]): Promise<LshData> {
+    const response = await fetch('http://127.0.0.1:5000/initialize', {
       method: 'POST',
       headers: {
         'Accept': 'application/json',
         'Content-Type': 'application/json'
       },
-      body: new Blob( [ JSON.stringify({query, labels, weights, hash_functions}) ], { type: 'text/plain' } )
+      body: new Blob( [ JSON.stringify({query}) ], { type: 'text/plain' } )
     });
     return await response.json();
   }
 
-  // Find candidates using LSH with weights
+  /**
+   * Do another iteration of LSH, with weights, and return important information
+   */
   async lshUpdate(query, weights, parameters): Promise<LshData> {
     const response = await fetch('http://127.0.0.1:5000/update', {
       method: 'POST',
@@ -89,20 +111,24 @@ export class ApiService {
     return await response.json();
   }
 
-  // Get query window based on windows labeled correct
-  async getQueryWindow(window): Promise<number[][]> {
+  /**
+   * Get query window based on windows labeled correct
+   */
+  async getQueryWindow(indices: number | {[index: number]: boolean}): Promise<number[][]> {
     const response = await fetch('http://127.0.0.1:5000/query', {
       method: 'POST',
       headers: {
         'Accept': 'application/json',
         'Content-Type': 'application/json'
       },
-      body: JSON.stringify({window})
+      body: JSON.stringify({indices})
     });
     return await response.json();
   }
 
-  // Get data of a window by indices
+  /**
+   * Get data of a window by indices
+   */
   async getWindowByIndices(indices: number[]): Promise<number[][][]> {
     const response = await fetch('http://127.0.0.1:5000/window', {
       method: 'POST',
@@ -115,14 +141,17 @@ export class ApiService {
     return await response.json();
   }
 
-  async getTableInfo(windows): Promise<TableInfoData> {
+  /**
+   * Get additional information for a given table
+   */
+  async getTableInfo(table: number[][]): Promise<TableInfoData> {
     const response = await fetch('http://127.0.0.1:5000/table-info', {
       method: 'POST',
       headers: {
         'Accept': 'application/json',
         'Content-Type': 'application/json'
       },
-      body: JSON.stringify({windows})
+      body: JSON.stringify({table})
     });
     return await response.json();
   }
diff --git a/AngularApp/prototype/src/app/progress-view/progress-view.component.ts b/AngularApp/prototype/src/app/progress-view/progress-view.component.ts
index 69e5c657..c379c9e5 100644
--- a/AngularApp/prototype/src/app/progress-view/progress-view.component.ts
+++ b/AngularApp/prototype/src/app/progress-view/progress-view.component.ts
@@ -1,6 +1,7 @@
 import {Component, OnInit, ViewChild} from '@angular/core';
 import {StateService} from '../state.service';
 import * as d3 from 'd3';
+import {TableInfoData} from '../api.service';
 
 @Component({
   selector: 'app-progress-view',
@@ -21,12 +22,14 @@ export class ProgressViewComponent implements OnInit {
   constructor(private state: StateService) { }
 
   ngOnInit(): void {
-    this.state.onNewTableInfo.subscribe(() => { this.showgraph(); });
-    this.state.onNewTableInfo.subscribe(() => { this.showHistogram(); });
+    this.state.onNewLshData.subscribe(() => {
+      this.showgraph();
+      this.showHistogram();
+    });
   }
 
   showHistogram() {
-    const table = this.state._averageTable;
+    const table = this.state.lshData.average_table;
     this.hist = {
       data: [{
         x: Object.keys(table),
@@ -162,7 +165,7 @@ export class ProgressViewComponent implements OnInit {
     d3.selectAll('circle').transition().style('stroke', undefined);
     d3.select('#node-' + v.value).transition().style('stroke', 'black').style('stroke-width', 20);
     const data = this.hist;
-    data.data[0].marker.line.width = Object.keys(this.state._averageTable).map((key) => {
+    data.data[0].marker.line.width = Object.keys(this.state.lshData.average_table).map((key) => {
       return Number(key) === v.value ? 4 : 0;
     });
     this.hist = data;
@@ -177,102 +180,15 @@ export class ProgressViewComponent implements OnInit {
 }
 
   public get table() {
-    return this.state._averageTable;
+    return this.state.lshData.average_table;
   }
 
   async showgraph() {
-    const nodes = [];
-    const links = [];
-    const keys = Object.keys(this.table);
-    this.hoverPlot(this.state.tableInfo.prototypes);
-    const distances = this.state.tableInfo.distances;
-
-    // for (const key in this.table) {
-    //   const size = this.table[key].length;
-    //   nodes.push({id: key, group: Number(key), size: size});
-    // }
-    // for (const key in this.table) {
-    //   for (const key2 in this.table) {
-    //     if (key === key2) {
-    //       continue;
-    //     }
-    //     links.push({source: key, target: key2, value: 0.001 * (100 - 5 * distances[keys.indexOf(key)][keys.indexOf(key2)])});
-    //   }
-    // }
-    // const graph = {nodes, links};
-    //
-    // const svg = d3.select('#visual');
-    // const width = +svg.attr('width');
-    // const height = +svg.attr('height');
-    //
-    // svg.selectAll('*').remove();
-    //
-    // const simulation = d3.forceSimulation()
-    //   .force('link', d3.forceLink().id((d: any) => d.id))
-    //   .force('charge', d3.forceManyBody().strength(100)) // Gravity force
-    //   .force('collide', d3.forceCollide().radius(25).iterations(3)) // Repulsion force
-    //   .force('center', d3.forceCenter(width / 2, height / 2)); // Position force
-    //
-    // const link = svg.append('g')
-    //   .selectAll('line')
-    //   .data(graph.links)
-    //   .enter().append('line')
-    //   .attr('stroke', 'grey')
-    //   .attr('stroke-width', (d: any) => d.value);
-    //
-    // const node = svg.append('g')
-    //   .selectAll('circle')
-    //   .data(graph.nodes)
-    //   .enter().append('circle')
-    //   .attr('r', (d: any) => 5 * Math.log(d.size) / Math.log(10))
-    //   .attr('fill', (d: any) => this.getColor(d.group / graph.nodes.length))
-    //   .attr('id', (d: any) => 'node-' + d.group)
-    //   .on('mouseover', (d: any) => {this.sliderValue = d.group; })
-    //   .call(d3.drag()
-    //     .on('start', dragstarted)
-    //     .on('drag', dragged)
-    //     .on('end', dragended));
-    //
-    // simulation
-    //   .nodes(graph.nodes as any)
-    //   .on('tick', ticked);
-    //
-    // simulation.force<any>('link')
-    //   .links(graph.links);
-    //
-    // function ticked() {
-    //   link
-    //     .attr('x1', (d: any) => d.source.x)
-    //     .attr('y1', (d: any) => d.source.y)
-    //     .attr('x2', (d: any) => d.target.x)
-    //     .attr('y2', (d: any) => d.target.y);
-    //
-    //   node
-    //     .attr('cx', (d: any) => d.x)
-    //     .attr('cy', (d: any) => d.y);
-    // }
-    //
-    // function dragstarted(d) {
-    //   if (!d3.event.active) {
-    //     simulation.alphaTarget(0.1).restart();
-    //   }
-    //   d.fx = d.x;
-    //   d.fy = d.y;
-    // }
-    //
-    // function dragged(d) {
-    //   d.fx = d3.event.x;
-    //   d.fy = d3.event.y;
-    // }
-    //
-    // function dragended(d) {
-    //   if (!d3.event.active) {
-    //     simulation.alphaTarget(0);
-    //   }
-    //   d.fx = null;
-    //   d.fy = null;
-    // }
+    const tableInfo: TableInfoData = await this.state.getTableInfo(Object.values(this.state.lshData.average_table));
+    this.hoverPlot(tableInfo.prototypes);
+    const distances = tableInfo.distances;
   }
+
   getColor(value) {
     const hue=((1-value)*120).toString(10);
     return ["hsl(",hue,",100%,50%)"].join("");
diff --git a/AngularApp/prototype/src/app/state.service.ts b/AngularApp/prototype/src/app/state.service.ts
index c711c42c..4745c9eb 100644
--- a/AngularApp/prototype/src/app/state.service.ts
+++ b/AngularApp/prototype/src/app/state.service.ts
@@ -1,38 +1,42 @@
 import {EventEmitter, Injectable} from '@angular/core';
-import {ApiService, LshData, RawData, TableInfoData} from './api.service';
+import {ApiService, LshData, Parameters, RawData, TableInfoData} from './api.service';
 
 @Injectable({
   providedIn: 'root'
 })
+/**
+ * This service acts as the state of the entire application. Components can subscribe to EventEmitters within this state to update their
+ * contents.
+ */
 export class StateService {
-  public loadingProgress: number = 0;
-
+  /**
+   * These are all LSH specific variables. The variables can be accessed using the getters and setters
+   */
   private _rawData: RawData[];
   private _lshData: LshData;
-  private _tableInfo: TableInfoData;
   private _queryWindow: number[][];
-  private _table: {[bucket: string]: number[]}[];
-  public _averageTable: {[bucket: string]: number[]};
   private _weights: number[];
-
-  private _currentTab: number;
   private _labels = {};
-  private _sliderValue;
   private _lshParameters: number[];
-
-  private states = [];
-
   public windowSize = 120;
   public nrOfTables = 5;
   public hashSize = 5;
   public stepSize = 200;
+
+  /**
+   * These are all GUI variables
+   */
+  public loadingProgress = 0;
   public querySelectionMode = true;
+  private _currentTab: number;
+  private _sliderValue;
 
+  /**
+   * These are all EventEmitters. Subscribe to these if you want to be informed about an update in state.
+   */
   public onNewData: EventEmitter<void> = new EventEmitter<void>();
   public onNewWindows: EventEmitter<void> = new EventEmitter<void>();
   public onNewQuery: EventEmitter<void> = new EventEmitter<void>();
-  public onNewTable: EventEmitter<void> = new EventEmitter<void>();
-  public onNewTableInfo: EventEmitter<void> = new EventEmitter<void>();
   public onNewLshData: EventEmitter<void> = new EventEmitter<void>();
 
   public onNewLabels: EventEmitter<void> = new EventEmitter<void>();
@@ -43,6 +47,9 @@ export class StateService {
      this.initialize();
   }
 
+  /**
+   * This function initializes the application. It retrieves the raw data and creates windows.
+   */
   async initialize(): Promise<void> {
     this.loadingProgress = 0;
     await this.getRawData();
@@ -51,72 +58,73 @@ export class StateService {
     this.loadingProgress = 100;
   }
 
+  /**
+   * This function resets the application. It re-creates the windows
+   */
   async reset(): Promise<void> {
     this.loadingProgress = 50;
     await this.createWindows();
     this.loadingProgress = 100;
   }
 
+  /**
+   * This function retrieves the raw data
+   */
   async getRawData(): Promise<void> {
     this.rawData = await this.api.readFile();
   }
 
+  /**
+   * This function creates the windows on the server side
+   */
   async createWindows(): Promise<void> {
     await this.api.createWindows(this.parameters);
     this.onNewWindows.emit();
   }
 
+  /**
+   * This function performs the first iteration of LSH
+   */
   async lshInitial(): Promise<void> {
+    this._weights = Array(this._queryWindow.length).fill(1);
     this.lshData = await this.api.lshInitial(this._queryWindow);
-    console.log('data loaded');
     this._lshParameters = this.lshData.parameters;
-    this._weights = [1, 1, 1];
-    this.createTable();
   }
 
+  /**
+   * This function performs every other iteration of LSH
+   */
   async update(labels, hashFunctions): Promise<void> {
     this._weights = await this.api.getWeights(this._queryWindow, labels, this._weights, hashFunctions);
-    console.log(this._weights);
     this.lshData = await this.api.lshUpdate(this._queryWindow, this._weights, this._lshParameters);
-    this.createTable();
   }
 
+  /**
+   * This function retrieves additional information given a table
+   */
   async getTableInfo(table: number[][]): Promise<TableInfoData> {
-    // console.log(this.tableInfo);
     return await this.api.getTableInfo(table);
   }
 
+  /**
+   * This function retrieves the query
+   */
   async getQueryWindow(windowIndex: number | {[index: number]: boolean}): Promise<number[][]> {
     this.queryWindow = await this.api.getQueryWindow(windowIndex);
     console.log(this.queryWindow);
     return this._queryWindow;
   }
 
+  /**
+   * This function retrieves the window given the window index
+   */
   async getWindow(indices: number[]): Promise<number[][][]> {
     return await this.api.getWindowByIndices(indices);
   }
 
-  async createTable() {
-    console.log('setting table param');
-    this.table = this.lshData.tables;
-    console.log('table param set');
-    const averageTable = {};
-    const length = this.lshData.average_distances.length;
-    const median = this.lshData.average_distances[Math.ceil(length / 2)];
-    const stepsize = median / 10;
-    const indices: number[] = this.lshData.average_distances.map((x) => x > median * 2 ? 19 : Math.floor(x / stepsize));
-    this.lshData.average_candidates.forEach((candidate: number, index: number) => {
-      if (averageTable[indices[index]] === undefined)
-      {
-        averageTable[indices[index]] = [];
-      }
-      averageTable[indices[index]].push(candidate);
-    });
-    this._averageTable = averageTable;
-    console.log('table created');
-    this.tableInfo = await this.getTableInfo(Object.values(this._averageTable));
-  }
-
+  /**
+   * These are all setters and getters
+   */
   public set rawData(v: RawData[]) {
     this._rawData = v;
     console.log(this._rawData);
@@ -137,26 +145,6 @@ export class StateService {
     return this._lshData;
   }
 
-  public set tableInfo(v: TableInfoData) {
-    this._tableInfo = v;
-    this.onNewTableInfo.emit();
-  }
-
-  public get tableInfo(): TableInfoData {
-    return this._tableInfo;
-  }
-
-  public set table(v: {[bucket: string]: number[]}[]) {
-    console.log(v);
-    this._table = v;
-    console.log('emitting onNewTable');
-    this.onNewTable.emit();
-  }
-
-  public get table(): {[bucket: string]: number[]}[] {
-    return this._table;
-  }
-
   public set labels(v) {
     this._labels = v;
     this.onNewLabels.emit();
@@ -197,7 +185,7 @@ export class StateService {
     return this._lshParameters;
   }
 
-  public get parameters(): {[parameter: string]: number} {
+  public get parameters(): Parameters {
     return {
       windowsize: this.windowSize,
       hashsize: this.hashSize,
diff --git a/AngularApp/prototype/src/app/table-overview/table-overview.component.ts b/AngularApp/prototype/src/app/table-overview/table-overview.component.ts
index e7894e53..0aef1ba5 100644
--- a/AngularApp/prototype/src/app/table-overview/table-overview.component.ts
+++ b/AngularApp/prototype/src/app/table-overview/table-overview.component.ts
@@ -15,7 +15,7 @@ export class TableOverviewComponent implements OnInit {
   constructor(private state: StateService) { }
 
   ngOnInit(): void {
-    this.state.onNewTable.subscribe(() => {
+    this.state.onNewLshData.subscribe(() => {
       this.createHistograms();
       this.createPrototypes();
     });
@@ -132,7 +132,7 @@ export class TableOverviewComponent implements OnInit {
     console.log('creating table histograms');
     this.subplots = [];
     this.averages = [];
-    const tables = this.state.table;
+    const tables = this.state.lshData.tables;
     console.log('start of table histograms');
     tables.forEach((table, index) => {
       console.log(index);
@@ -181,7 +181,7 @@ export class TableOverviewComponent implements OnInit {
   // }
 
   public get tables() {
-    return this.state.table;
+    return this.state.lshData.tables;
   }
 
   public get visible() {
diff --git a/Flaskserver/.idea/workspace.xml b/Flaskserver/.idea/workspace.xml
index 88459681..25b40fe7 100644
--- a/Flaskserver/.idea/workspace.xml
+++ b/Flaskserver/.idea/workspace.xml
@@ -20,18 +20,23 @@
   </component>
   <component name="ChangeListManager">
     <list default="true" id="556080ba-825c-4b55-a92a-867a4df4fb32" name="Default Changelist" comment="">
-      <change beforePath="$PROJECT_DIR$/../AngularApp/prototype/src/app/api.service.ts" beforeDir="false" afterPath="$PROJECT_DIR$/../AngularApp/prototype/src/app/api.service.ts" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/../AngularApp/prototype/src/app/labeling-window/labeling-window.component.ts" beforeDir="false" afterPath="$PROJECT_DIR$/../AngularApp/prototype/src/app/labeling-window/labeling-window.component.ts" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/../AngularApp/prototype/src/app/overview-window/overview-window.component.ts" beforeDir="false" afterPath="$PROJECT_DIR$/../AngularApp/prototype/src/app/overview-window/overview-window.component.ts" afterDir="false" />
       <change beforePath="$PROJECT_DIR$/../AngularApp/prototype/src/app/state.service.ts" beforeDir="false" afterPath="$PROJECT_DIR$/../AngularApp/prototype/src/app/state.service.ts" afterDir="false" />
       <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
       <change beforePath="$PROJECT_DIR$/main.py" beforeDir="false" afterPath="$PROJECT_DIR$/main.py" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/pseudo.py" beforeDir="false" afterPath="$PROJECT_DIR$/pseudo.py" afterDir="false" />
     </list>
     <option name="SHOW_DIALOG" value="false" />
     <option name="HIGHLIGHT_CONFLICTS" value="true" />
     <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
     <option name="LAST_RESOLUTION" value="IGNORE" />
   </component>
+  <component name="FileTemplateManagerImpl">
+    <option name="RECENT_TEMPLATES">
+      <list>
+        <option value="Python Script" />
+      </list>
+    </option>
+  </component>
   <component name="Git.Settings">
     <option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$/.." />
   </component>
@@ -50,6 +55,10 @@
     <property name="nodejs_npm_path_reset_for_default_project" value="true" />
   </component>
   <component name="RecentsManager">
+    <key name="MoveFile.RECENT_KEYS">
+      <recent name="$PROJECT_DIR$/data" />
+      <recent name="$PROJECT_DIR$/libs" />
+    </key>
     <key name="CopyFile.RECENT_KEYS">
       <recent name="$PROJECT_DIR$" />
     </key>
@@ -144,6 +153,10 @@
       <screen x="72" y="27" width="1848" height="1053" />
     </state>
     <state x="779" y="311" width="424" height="491" key="FileChooserDialogImpl/72.27.1848.1053@72.27.1848.1053" timestamp="1606260652750" />
+    <state x="687" y="162" width="618" height="783" key="find.popup" timestamp="1606586473850">
+      <screen x="72" y="27" width="1848" height="1053" />
+    </state>
+    <state x="687" y="162" width="618" height="783" key="find.popup/72.27.1848.1053@72.27.1848.1053" timestamp="1606586473850" />
     <state x="659" y="259" width="672" height="678" key="search.everywhere.popup" timestamp="1604929652702">
       <screen x="72" y="27" width="1848" height="1053" />
     </state>
diff --git a/Flaskserver/__pycache__/DBA.cpython-38.pyc b/Flaskserver/__pycache__/DBA.cpython-38.pyc
deleted file mode 100644
index ee756e972d4a8aac20fcbf3c7ac617a69c472ca0..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 4285
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

diff --git a/Flaskserver/__pycache__/DBA.cpython-39.pyc b/Flaskserver/__pycache__/DBA.cpython-39.pyc
deleted file mode 100644
index 368c5be97531cb8f6473dc6bef50b905d96221c0..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 4269
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

diff --git a/Flaskserver/__pycache__/bigwig.cpython-38.pyc b/Flaskserver/__pycache__/bigwig.cpython-38.pyc
deleted file mode 100644
index 00c1792d524e86a06d07155df2a61697b8296f77..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 7806
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

diff --git a/Flaskserver/__pycache__/main.cpython-38.pyc b/Flaskserver/__pycache__/main.cpython-38.pyc
index 0a689a6143fa33130b1d62a5e9afc3f056bdce18..d7e1394f0ec8adca440344b7cccf0ad1393d6745 100644
GIT binary patch
literal 3405
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

literal 14695
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
WBOOF~3(_Le8<8fEvPd(z=l&OL7snU?

diff --git a/Flaskserver/__pycache__/preprocessing.cpython-38.pyc b/Flaskserver/__pycache__/preprocessing.cpython-38.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..a7235ecbfce8b71c221b4345ca9ee868b8370c8b
GIT binary patch
literal 4100
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
Wi5-;aQQBvU@XmYBdR6b7H~%mGXTnDS

literal 0
HcmV?d00001

diff --git a/Flaskserver/__pycache__/pseudo.cpython-38.pyc b/Flaskserver/__pycache__/pseudo.cpython-38.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..59cff614cd0a683799a6b40d1e3c54bddacc3b8a
GIT binary patch
literal 7381
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

literal 0
HcmV?d00001

diff --git a/Flaskserver/__pycache__/utils.cpython-38.pyc b/Flaskserver/__pycache__/utils.cpython-38.pyc
deleted file mode 100644
index 53aa8e25f8cca63b270439f74b880d04a1d5e23d..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 1180
zcmY*Z!EW0|5G5%}wh5~!Q1p<T2EMccBr(k?XoDb%?W9Cw8Zhm;(M4Eum(s$^U3PaV
zS%q>+ej-H=@v$G#AK|r!BA?KnIx7pVx&W7$o#D)zH*a~-?M5E1`YS&9qvd&jI%9i<
zXgtTq^l_u!*rPrTgg*}O-4d-b9EZL~cUhaZfAeXF?!0f0J2c3=-X3`scwTg<s-@=B
znT5xXzIg(vniFlgfkYb1ZEcx>LTPxx)d{0KCj!oxVMOOM49SPlYo0S{7=>C=roqk_
zj4G1jYvbv|k4zh`Bs?BIg0Ee`!Nzsa`z~6l8cMPRsVvlnVFD~(aKV7x<gBv5CFH8C
z1Sc|Qu;6yKF0x56jNWV#s4Gh_mSA+X1XXND0kP4{+UnalUMv<vvIaO*dK!y6_$Gdx
z93H3H@c=<a7g8`|K(n7~uCcYNC6Edc<m3u*39<lWgiJL<pH&XwLUYUIv=2rVc0n|Y
zC^uH~D<p86nhk2e9=8LK93tUhltGdmz>86qWc}zeIsg9j;v6nVXJ@1IJUPzb^b8J9
z)1%}(IZe@e38VB4{E(zaePBoo^3QH6?XV+2?nq;F7-h`SdOwi$Je_SSmh*z=*pZyp
zWXfQw=1fa$1S+OWZrs=mLZgx3CAY+`?f)iyKZH-HJ}>S0&Hf3OC*&qWp)mc|uOD#z
z{nK-FM3@nkVsWxL>h69y0q@{*h>scLX1$O83T3?Vi{LhR8=xJmyj%ZmYlWhI;H_GC
z(pqh-YxF$z&=dU6gVuHEJT`pieQd8<w?0a~m1-X=d~#c_(*&~8u6z?Z$u#W+63Daz
z*K`YRCsq?_Q2b>tY(h#bxr^@PwN*ti-g8G2iT>X`y^ml0a~aQ6$zsap13@aQs`zM$
z+{Qv79o#Ml2CoVVWzGgOVrIzmV9rfV#DGX5mX_xxekq8#HcaCn;u_g9Lxi^Hs$hy=
z*cVvGtbYmq=YHfr^dAQLGd%108h;O7Z>QOrOsL8ylcp`}67O~gkH=q{Yk`+m4pAMI
qRyj%ptKaq7E`%a>on_s|*4D*uo870SqP1Yp9Bsy>3%k4ie)un$PG7qK

diff --git a/Flaskserver/.gitattributes b/Flaskserver/data/.gitattributes
similarity index 100%
rename from Flaskserver/.gitattributes
rename to Flaskserver/data/.gitattributes
diff --git a/Flaskserver/21.csv b/Flaskserver/data/21.csv
similarity index 100%
rename from Flaskserver/21.csv
rename to Flaskserver/data/21.csv
diff --git a/Flaskserver/NW_Ground_Stations_2016.csv b/Flaskserver/data/NW_Ground_Stations_2016.csv
similarity index 100%
rename from Flaskserver/NW_Ground_Stations_2016.csv
rename to Flaskserver/data/NW_Ground_Stations_2016.csv
diff --git a/Flaskserver/chip_w-3000_r-25.h5 b/Flaskserver/data/chip_w-3000_r-25.h5
similarity index 100%
rename from Flaskserver/chip_w-3000_r-25.h5
rename to Flaskserver/data/chip_w-3000_r-25.h5
diff --git a/Flaskserver/data.pkl b/Flaskserver/data/data.pkl
similarity index 100%
rename from Flaskserver/data.pkl
rename to Flaskserver/data/data.pkl
diff --git a/Flaskserver/parameters.npy b/Flaskserver/data/parameters.npy
similarity index 100%
rename from Flaskserver/parameters.npy
rename to Flaskserver/data/parameters.npy
diff --git a/Flaskserver/processed-data b/Flaskserver/data/processed-data
similarity index 100%
rename from Flaskserver/processed-data
rename to Flaskserver/data/processed-data
diff --git a/Flaskserver/processed-data.npy b/Flaskserver/data/processed-data.npy
similarity index 100%
rename from Flaskserver/processed-data.npy
rename to Flaskserver/data/processed-data.npy
diff --git a/Flaskserver/query b/Flaskserver/data/query
similarity index 100%
rename from Flaskserver/query
rename to Flaskserver/data/query
diff --git a/Flaskserver/test.bigWig b/Flaskserver/data/test.bigWig
similarity index 100%
rename from Flaskserver/test.bigWig
rename to Flaskserver/data/test.bigWig
diff --git a/Flaskserver/DBA.py b/Flaskserver/libs/DBA.py
similarity index 100%
rename from Flaskserver/DBA.py
rename to Flaskserver/libs/DBA.py
diff --git a/Flaskserver/DBA_multivariate.py b/Flaskserver/libs/DBA_multivariate.py
similarity index 100%
rename from Flaskserver/DBA_multivariate.py
rename to Flaskserver/libs/DBA_multivariate.py
diff --git a/Flaskserver/__pycache__/DBA_multivariate.cpython-38.pyc b/Flaskserver/libs/__pycache__/DBA_multivariate.cpython-38.pyc
similarity index 97%
rename from Flaskserver/__pycache__/DBA_multivariate.cpython-38.pyc
rename to Flaskserver/libs/__pycache__/DBA_multivariate.cpython-38.pyc
index eaac5b3ae6a624df5de796f13360e27285d379c7..c05779e917b5cab3b52eb89a19ee2a3f8aa6e2ff 100644
GIT binary patch
delta 23
fcmdn3e?Wi3PFBYB$-7wnS#mOyiZ^qxZ59LoZ@UPD

delta 18
acmX@0zgvI9PFBXG$-7wnH}kP=5(EH9cm~!0

diff --git a/Flaskserver/__pycache__/bigwig.cpython-39.pyc b/Flaskserver/libs/__pycache__/bigwig.cpython-38.pyc
similarity index 71%
rename from Flaskserver/__pycache__/bigwig.cpython-39.pyc
rename to Flaskserver/libs/__pycache__/bigwig.cpython-38.pyc
index d7b5cc2d9c3f2b82802447276d67013e31df8328..53394d44f75209bebbfc7b6452b784f4de06c190 100644
GIT binary patch
delta 395
zcmaE6(`?Hax{+}Q3uEl$T`c}AIhjetlQ~#Jn6f!0$FUkQWwULb#45+cQOv@?z`(}9
zG<geqHKX=q1CED`w>ArL&SzoNoV<y5C)YKgbPY=i15jHjpEl#H$qV`N<>XixO1QJR
ziuN%wfM5yB0-hS~g^aa)kqmiE5tDWJ4S6+y`ZW2AjDb{<_T(&nB}Sdez5MqW`6lNG
zWC0zq`G&v&CPuBvGleU;irFA;VBp#;CUTes<iy(&T};{Ro6{vHFakCHklMf)HF>49
zqF5AXaY<rPNqka4aTI%MUJ8g&WH$MutS}F2az<%h_Gh3`#W9orOS{T&F);n-W8q<B
z0zwWT6#K)%&c?{b#Ku%qH91Zun_CCuI4=-U4KiW!a~T1~n#n(8tW>}<x<Hv*ta+um
z1(ikIAXUO30k(p~yp+V^B7@0cvVOo2TPo|wRt1u+nfyjp4d_f^xj-H!1~~i=0I*|b
AN&o-=

delta 349
zcmZp+eP+X$xRG%O3uDCOT`c~S`B;OQN*N|6vl=m#F>IdBD#yg~nSp^}@?Q38MxDuq
zY$B6=InFXhZI<So&%&rRc{lG)t}8(K8kQ6Wptd?bZN?dsSMlY`$gnV!a98eOWB|bu
zmIXXD+zT0N`63zem<%SH^BeMN0(EKf7a0SoBAv;l{7Q_vlV|YXW8|4!E|3Lu!sf>U
z2bdVOCod7MWGT{MVA!lKa+n3=v^Nr6Ol6FlD<mf{0<~~TZ(zJNd6%>z&n?d4lEk8t
z_@sj3Ta%wlYcNJl7Lak3;`z_V!o$b}gd9L9_J@U?jggIsjj5=1a-mE%w=T$jFAz~T
z`J=S(<X<uZjP;YbWvx`eGI~InTdaAdxdoL)+#prLKq88*ATci`vAD=^a;B^wFj#iT
YI<nP*Wa}sYmsMj7n5-rj$i(v>09y)OMgRZ+

diff --git a/Flaskserver/bigwig.py b/Flaskserver/libs/bigwig.py
similarity index 100%
rename from Flaskserver/bigwig.py
rename to Flaskserver/libs/bigwig.py
diff --git a/Flaskserver/setup.py b/Flaskserver/libs/setup.py
similarity index 100%
rename from Flaskserver/setup.py
rename to Flaskserver/libs/setup.py
diff --git a/Flaskserver/utils.py b/Flaskserver/libs/utils.py
similarity index 100%
rename from Flaskserver/utils.py
rename to Flaskserver/libs/utils.py
diff --git a/Flaskserver/main.py b/Flaskserver/main.py
index 713ce99f..fbfcdbad 100644
--- a/Flaskserver/main.py
+++ b/Flaskserver/main.py
@@ -2,24 +2,12 @@ from flask import Flask, request
 import numpy as np
 from flask_cors import CORS
 from time import time
-import pandas as pd
 import orjson
-import bigwig
-import bbi
-import _ucrdtw
-import _lsh
-import math
-import dask.dataframe as dd
 import os.path
-from random import sample
-from DBA_multivariate import performDBA
-from tslearn.metrics import dtw
-from sklearn import preprocessing
-from collections import defaultdict
-from dtaidistance import dtw_ndim
-from scipy.spatial.distance import euclidean
+import pseudo
+import preprocessing
 
-from fastdtw import fastdtw
+data_path = 'data/processed-data.npy'
 
 reload = False
 
@@ -30,478 +18,222 @@ CORS(app)
 def index():
     return "hi"
 
+
+"""
+Returns raw data
+
+Output: [{
+    index: 1d array [x]
+    values: 1d array [x]
+}]
+"""
 @app.route('/read-data', methods=['GET'])
 def read_data():
     t0 = time()
-    size = bbi.chromsizes('test.bigWig')['chr1']
-    bins = 100000
-    data = bigwig.get('test.bigWig', 'chr1', 0, size, bins)
-    print(data.shape)
-    response = [
-        {
-            "index": list(range(0, size, int(size/(bins)))),
-            "values": data.tolist()
-        },
-        {
-            "index": list(range(0, size, int(size / (bins)))),
-            "values": data.tolist()
-        },
-        {
-            "index": list(range(0, size, int(size / (bins)))),
-            "values": data.tolist()
-        }
-    ]
+    response = preprocessing.read_mts_data()
     response = orjson.dumps(response)
     print('Data read: ' + str(time()-t0))
     return response
 
-@app.route('/read-mts-data', methods=['GET'])
-def read_mts_data():
-    filename = 'data.pkl'
-    if (not os.path.isfile(filename)):
-        print("start")
-        df = dd.read_csv("NW_Ground_Stations_2016.csv", usecols=['number_sta', 'date', 't', 'hu', 'td'])
-        print("read file")
-        df = df.loc[df['number_sta'].isin([14066001, 14137001, 14216001, 14372001, 22092001, 22113006, 22135001])].fillna(0)
-        print("split rows")
-        df = df.compute()
-        df.to_pickle(filename)
-        print("to_pandas")
-    df = pd.read_pickle(filename)
-    df.dropna(subset=['t'], inplace=True)
-    response = [
-        {
-            "index": df.loc[df['number_sta'] == 14066001].loc[:, 'date'].values.astype(str).tolist(),
-            "values": df.loc[df['number_sta'] == 14066001].loc[:, 't'].values.tolist()
-        },
-        {
-            "index": df.loc[df['number_sta'] == 14066001].loc[:, 'date'].values.astype(str).tolist(),
-            "values": df.loc[df['number_sta'] == 14066001].loc[:, 'hu'].values.tolist()
-        },
-        {
-            "index": df.loc[df['number_sta'] == 14066001].loc[:, 'date'].values.astype(str).tolist(),
-            "values": df.loc[df['number_sta'] == 14066001].loc[:, 'td'].values.tolist()
-        }
-    ]
-    print("response ready")
-    response = orjson.dumps(response)
-    return response
 
-@app.route('/create-mts-windows', methods=['POST'])
-def create_mts_windows():
-    t0 = time()
-    if (not os.path.isfile('processed-data.npy')):
-        filename = 'data.pkl'
-        df = pd.read_pickle(filename)
-        channels = list()
-        channels.append(df.loc[df['number_sta'] == 14066001].loc[:, 't'].fillna(0).values.tolist())
-        channels.append(df.loc[df['number_sta'] == 14066001].loc[:, 'hu'].fillna(0).values.tolist())
-        channels.append(df.loc[df['number_sta'] == 14066001].loc[:, 'td'].fillna(0).values.tolist())
-        print("Data read: " + str(time()-t0))
-        # raw_data = request.json
-        window_size = 120 #int(raw_data['parameters']["windowsize"])
-        print("Processing: " + str(time()-t0))
-        data = [([values[i:i+window_size] for values in channels]) for i in range(0, len(channels[0]) - window_size, 1)]
-        print("Raw windows: " + str(time()-t0))
-        windows = []
-        for i in range(len(data)):
-            if i % 5000 == 0:
-                print(i)
-            windows.append(preprocessing.minmax_scale(data[i], (-1, 1), axis=1))
-        print("Preprocessed: " + str(time()-t0))
-        np.save('processed-data', windows)
-    # data = np.load('processed-data.npy')
-    # data = np.reshape(data, (len(data), len(data[0][0]), len(data[0])))
-    # r, a, sd = preprocess(data, 11.5)
-    # np.save('parameters', np.array([r, a, sd]))
-    print("Sending response: " + str(time()-t0))
-    return '1'
+"""
+Creates windows
 
+Input: {
+    parameters: {
+        windowssize: int
+    }
+}
 
+Output: '1'
+"""
 @app.route('/create-windows', methods=['POST'])
 def create_windows():
     t0 = time()
-    if (not os.path.isfile('processed-data.npy')):
-        # raw_data = request.json
-        # window_size = int(raw_data['parameters']["windowsize"])
-        window_size = 120
-        data = bigwig.chunk(
-            'test.bigWig',
-            12000,
-            int(12000 / window_size),
-            int(12000 / 6),
-            ['chr1'],
-            verbose=True,
-        )
-        data = np.reshape(data, (len(data), 1, len(data[0])))
-        data2 = np.copy(data)
-        np.random.shuffle(data2)
-        data3 = np.copy(data)
-        np.random.shuffle(data3)
-
-        data = np.concatenate((data, data2), axis=1)
-        data = np.concatenate((data, data3), axis=1)
-        # data = np.repeat(data, repeats=3, axis=1)
-        np.save('processed-data', data)
-    print('Windows created: ' + str(time()-t0))
-    return '1'
-
-@app.route('/create-test-windows', methods=['POST'])
-def create_test_windows():
-    t0 = time()
-    if (not os.path.isfile('processed-data.npy')):
-        datafile = '21.csv'
-
-        data = pd.read_csv(datafile, header=None)
-
-        # and convert it to numpy array:
-        npdata = np.array(data)
-        print('data loaded')
-        window_data = [npdata[i:i + 120, 0:5] for i in range(0, npdata.shape[0] - 120, int(120 / 8))]
-        del npdata
-        print('data created')
-        np_window_data = np.repeat(window_data, repeats=3, axis=0)
-        print(np_window_data.shape)
-        del window_data
-        data = np.reshape(np_window_data, (len(np_window_data), 5, len(np_window_data[0])))
-        print(data.shape)
-        np.save('processed-data', data)
+    if (not os.path.isfile(data_path)):
+        raw_data = request.json
+        window_size = int(raw_data['parameters']["windowsize"])
+        preprocessing.create_eeg_windows(window_size, 5)
     print('Windows created: ' + str(time()-t0))
     return '1'
 
 
+"""
+Does first iteration of LSH and returns a bunch of useful information
+
+Input: {
+    query: 2d array [d][t]
+}
+
+Output: {
+    hash_functions: 3d array [k][l][d]
+    candidates: 3d array [k][l][i]
+    distances: 3d array [k][l][i]
+    average_candidates: 1d array [i]
+    average_distances: 1d array [i]
+    tables: [{
+        bucket: 1d array
+    }]
+    average_table: {
+        bucket: 1d array
+    }
+    samples: 1d array
+    parameters: 1d array
+}
+"""
 @app.route('/initialize', methods=['POST'])
 def initialize():
     t0 = time()
     raw_data = orjson.loads(request.data)
-    data = np.load('processed-data.npy')
+    data = np.load(data_path)
     data = np.swapaxes(data, 1, 2)
-    # data = np.reshape(data, (len(data), len(data[0][0]), len(data[0])))
     query = raw_data["query"]
     query = np.swapaxes(query, 0, 1)
-    # query = np.reshape(query, (len(query[0]), len(query)))
-    parameters = preprocess(data)
     # parameters = np.load('parameters.npy')
-    r = parameters[0]
-    a = parameters[1]
-    sd = parameters[2]
-
-    candidates, distances, hf = _lsh.lsh(data, query, r, a, sd)
-    print(distances)
-
-    dict = defaultdict(int)
-    for l in range(len(candidates)):
-        for k in range(len(candidates[0])):
-            for i in range(len(candidates[0][0])):
-                dict[candidates[l][k][i]] += distances[l][k][i]
-    sorted_dict = {k: v for k, v in sorted(dict.items(), key=lambda item: item[1])}
-    average_candidates = list(sorted_dict.keys())
-    average_distances = list(sorted_dict.values())
-
-    tables = []
-    samples_set = set()
-    candidates = candidates.tolist()
-    for l in range(len(candidates)):
-        for k in range(len(candidates[0])):
-            samples_set.update(candidates[l][k][0:5])
-            dict = defaultdict(list)
-            length = len(distances[l][k])
-            median = distances[l][k][math.ceil(length/2)]
-            stepsize = median / 10
-            indices = list(map(lambda x: 19 if x > median * 2 else math.floor(x / stepsize), distances[l][k]))
-            for i in range(len(candidates[0][0])):
-                dict[str(indices[i])].append(candidates[l][k][i])
-            tables.append(dict)
-
-    samples = np.array(list(filter(lambda x: x in samples_set, average_candidates))).tolist()
-
-
-    response = {
-        "hash_functions": hf.reshape((len(candidates) * len(candidates[0]), len(query[0]))).tolist(),
-        "candidates": candidates,
-        "tables": tables,
-        "distances": distances.tolist(),
-        "samples": list(samples),
-        "average_candidates": np.array(average_candidates).tolist(),
-        "average_distances": np.array(average_distances).tolist(),
-        "parameters": [float(r), float(a), float(sd)]
-    }
-    response = orjson.dumps(response)
-    print('LSH done: ' + str(time()-t0))
-    return response
 
-@app.route('/weights', methods=['POST'])
-def weights():
-    alpha = 0.2
-    raw_data = orjson.loads(request.data)
-    labels = raw_data["labels"]
-    hash_functions = raw_data["hash_functions"]
-    query = raw_data["query"]
-    old_weights = raw_data["weights"]
-    data = np.load('processed-data.npy')
-    all_good_windows = data[[[int(index) for index, value in labels.items() if value is True]]]
-
-    good_distances = np.zeros(len(query))
-    for window in all_good_windows:
-        for i in range(len(all_good_windows[0])):
-            good_distances[i] += _ucrdtw.ucrdtw(query[i], window[i], 0.05, False)[1]
-    if len(all_good_windows) != 0:
-        good_distances = np.square(good_distances)
-        good_distances /= np.sum(good_distances)
-        good_distances = np.ones(len(query)) - good_distances
-        good_distances /= np.sum(good_distances)
-        good_distances *= len(all_good_windows[0])
-        good_distances = np.sqrt(good_distances)
-
-    if len(hash_functions) != 0:
-        summed_hash_functions = np.sum(hash_functions, axis=0)
-        summed_hash_functions = np.square(summed_hash_functions)
-        normalized_hash_functions = summed_hash_functions / np.sum(summed_hash_functions)
-        normalized_hash_functions *= len(hash_functions[0])
-
-    if len(hash_functions) + len(all_good_windows) == 0:
-        print("no update")
-        new_weights = old_weights
-    elif len(hash_functions) == 0:
-        print("only windows")
-        new_weights = alpha * np.array(old_weights) + (1 - alpha) * good_distances
-    elif len(all_good_windows) == 0:
-        print("only tables")
-        new_weights = alpha * np.array(old_weights) + (1 - alpha) * normalized_hash_functions
-    else:
-        print("tables & windows")
-        new_weights = alpha * np.array(old_weights) + 0.5 * (1-alpha) * good_distances + 0.5 * (1-alpha) * normalized_hash_functions
-
-    print(new_weights)
-
-    response = orjson.dumps(new_weights.tolist())
+    lsh_data = pseudo.lsh(data, query)
+
+    response = orjson.dumps(lsh_data)
+    print('LSH done: ' + str(time()-t0))
     return response
 
 
+"""
+Does LSH and returns a bunch of useful information
+
+Input: {
+    query: 2d array [d][t]
+}
+
+Output: {
+    hash_functions: 3d array [k][l][d]
+    candidates: 3d array [k][l][i]
+    distances: 3d array [k][l][i]
+    average_candidates: 1d array [i]
+    average_distances: 1d array [i]
+    tables: [{
+        bucket: 1d array
+    }]
+    average_table: {
+        bucket: 1d array
+    }
+    samples: 1d array
+}
+"""
 @app.route('/update', methods=['POST'])
 def update():
     t0 = time()
     raw_data = orjson.loads(request.data)
-    data = np.load('processed-data.npy')
+    data = np.load(data_path)
     data = np.swapaxes(data, 1, 2)
-    # data = np.reshape(data, (len(data), len(data[0][0]), len(data[0])))
     query = raw_data["query"]
     query = np.swapaxes(query, 0, 1)
-    # query = np.reshape(query, (len(query[0]), len(query)))
     weights = raw_data["weights"]
     parameters = raw_data["parameters"]
 
-    candidates, distances, hf = _lsh.lsh(data, query, parameters[0], parameters[1], parameters[2], weights)
-    dict = defaultdict(int)
-    for l in range(len(candidates)):
-        for k in range(len(candidates[0])):
-            for i in range(len(candidates[0][0])):
-                dict[candidates[l][k][i]] += distances[l][k][i]
-    sorted_dict = {k: v for k, v in sorted(dict.items(), key=lambda item: item[1])}
-    average_candidates = list(sorted_dict.keys())
-    average_distances = list(sorted_dict.values())
-
-    tables = []
-    samples_set = set()
-    candidates = candidates.tolist()
-    for l in range(len(candidates)):
-        for k in range(len(candidates[0])):
-            samples_set.update(candidates[l][k][0:5])
-            dict = defaultdict(list)
-            length = len(distances[l][k])
-            median = distances[l][k][math.ceil(length/2)]
-            stepsize = median / 10
-            indices = list(map(lambda x: 19 if x > median * 2 else math.floor(x / stepsize), distances[l][k]))
-            for i in range(len(candidates[0][0])):
-                dict[str(indices[i])].append(candidates[l][k][i])
-            tables.append(dict)
-
-    samples = np.array(list(filter(lambda x: x in samples_set, average_candidates))).tolist()
-
-    response = {
-        "hash_functions": hf.reshape((len(candidates) * len(candidates[0]), len(query[0]))).tolist(),
-        "candidates": candidates,
-        "tables": tables,
-        "samples": list(samples),
-        "average_candidates": np.array(average_candidates).tolist(),
-        "average_distances": np.array(average_distances).tolist(),
-        "distances": distances.tolist(),
-    }
-    response = orjson.dumps(response)
+    lsh_data = pseudo.lsh(data, query, parameters=parameters, weights=weights)
+
+    response = orjson.dumps(lsh_data)
     print('LSH done: ' + str(time()-t0))
     return response
 
+
+"""
+Calculates new weights for LSH algorithm
+
+Input: {
+    labels: 1d array [?]
+    hash_functions: 2d array [?][d]
+    query: 2d array [d][t]
+    weights: 1d array [d]
+}
+
+Output: 1d array [d]
+"""
+@app.route('/weights', methods=['POST'])
+def weights():
+    raw_data = orjson.loads(request.data)
+    labels = raw_data["labels"]
+    hash_functions = raw_data["hash_functions"]
+    query = raw_data["query"]
+    old_weights = raw_data["weights"]
+    data = np.load(data_path)
+
+    new_weights = pseudo.weights(data, query, old_weights, labels, hash_functions)
+
+    response = orjson.dumps(new_weights)
+    return response
+
+
+"""
+Calculates query based on given indices
+
+Input: {
+    indices: 1d array [?]
+}
+
+Output: 2d array [d][t]
+"""
 @app.route('/query', methods=['POST'])
 def query():
     t0 = time()
     raw_data = orjson.loads(request.data)
-    windowIndices = raw_data['window']
-    if isinstance(windowIndices, int):
-        output = np.load('processed-data.npy')[windowIndices]
-        response = orjson.dumps(output.tolist())
-        print("Query done: " + str(time() - t0))
-        return response
-    else:
-        indices = [int(index) for index, value in windowIndices.items() if value is True]
-        data = np.load('processed-data.npy')[indices]
-        output = performDBA(data)
-        response = orjson.dumps(output.tolist())
-        print("Query done: " + str(time()-t0))
-        return response
+    window_indices = raw_data['indices']
+    data = np.load(data_path)
+
+    response = pseudo.query(data, window_indices)
+
+    response = orjson.dumps(response)
+    print("Query done: " + str(time() - t0))
+    return response
+
+
+"""
+Returns values of windows on given indices
 
+Input: {
+    indices: 1d array [x]
+}
+
+Output: 3d array [x][d][t]
+"""
 @app.route('/window', methods=['POST'])
 def window():
     t0 = time()
     raw_data = orjson.loads(request.data)
     indices = raw_data['indices']
-    output = np.load('processed-data.npy')[indices]
+
+    output = np.load(data_path)[indices]
+
     response = orjson.dumps(output.tolist())
-    print("Query done: " + str(time() - t0))
+    print("Window(s) done: " + str(time() - t0))
     return response
 
+
+"""
+Returns additional information on given table
+
+Input: {
+    table: 2d array [x][?]
+}
+
+Output: {
+    prototypes: {
+        average: 1d array [t]
+        max: 1d array [t]
+        min: 1d array [t]
+    }
+    distances: 2d array [x][x]
+}
+"""
 @app.route('/table-info', methods=['POST'])
 def table_info():
     t0 = time()
     raw_data = orjson.loads(request.data)
-    all_windows = raw_data['windows']
-    data = np.load('processed-data.npy')
-    prototypes = []
-    for windows in all_windows:
-        actual_windows = data[windows]
-        average_values = np.average(actual_windows, 0)
-        std_values = np.std(actual_windows, 0)
-        max_values = average_values + std_values
-        min_values = average_values - std_values
-        prototypes.append({
-            'average': average_values.tolist(),
-            'max': max_values.tolist(),
-            'min': min_values.tolist()
-        })
-    # distances = [[dtw(np.array(v["average"]), np.array(w["average"]), global_constraint='sakoe_chiba', sakoe_chiba_radius=int(0.05 * 120)) for j, w in enumerate(prototypes)] for i, v in enumerate(prototypes)]
-    response = orjson.dumps({'prototypes': prototypes, 'distances': []})
-    print("Averages calculated: " + str(time() - t0))
-    return response
-
-def preprocess(data, r=10.0):
-    # return 0.10882589134534404, 3.1202154563478928, 0.9705780396843037
-    # data = np.load('processed-data.npy')
-    # data = np.reshape(data, (59999, 20, 120))
-    # data = np.repeat(data, repeats=1, axis=1)
-    subset = []
-    t0 = time()
-
-    i = 0
-    while i < len(data):
-        if i % 999 == 0:
-            print(r)
-            print(str(i) + ':' + str(len(subset)))
-
-        state = 1
-        for s in subset:
-            if np.linalg.norm(data[i] - data[s]) < r:
-                state = 0
-                break
-        if state == 1:
-            subset.append(i)
-
-        i = i + 1
-        if i == 10000 and len(subset) < 10:
-            r = r / 2
-            subset = []
-            i = 0
-        if len(subset) > 200:
-            r = r + r / 2
-            subset = []
-            i = 0
-
-    # subset = sample(list(range(len(data))), 200)
-    print("r = " + str(r))
-    dtw_distances = []
-    eq_distances = []
-    for i, index_1 in enumerate(subset):
-        print(i)
-        for j, index_2 in enumerate(subset):
-            if index_1 == index_2:
-                continue
-            e = np.linalg.norm(data[index_1] - data[index_2])
-            if (math.isnan(e) or e == 0):
-                eq_distances.append(0.0001)
-                dtw_distances.append(0.0001)
-                continue
-            eq_distances.append(e)
-            d = 0
-            # d, _ = fastdtw(data[index_1], data[index_2], dist=euclidean)
-            d = dtw(data[index_1], data[index_2], global_constraint='sakoe_chiba', sakoe_chiba_radius=int(0.05*120))
-            # d = _ucrdtw.ucrdtw(data[index_1], data[index_2], 0.05, False)[1]
-            # d = dtw.dtw(data[index_1], data[index_2], dist_method="Euclidean", window_type="sakoechiba", window_args={"window_size": 120}).distance
-            dtw_distances.append(d)
-
-    ratios = np.array(dtw_distances)/np.array(eq_distances)
-    mean_dtw = np.mean(dtw_distances)
-    sd_dtw = np.std(dtw_distances)
-    mean_eq = np.mean(eq_distances)
-    sd_eq = np.std(eq_distances)
-    a = np.mean(ratios)
-    sd = np.std(ratios)
-    theta = mean_dtw + -2.58 * sd_dtw
-    # theta = mean_eq + -2.58 * sd_eq
-    r = theta / ((a-sd)*math.sqrt(120))
-    if r < 0:
-        r = mean_dtw / 100
-    # r = theta / (math.sqrt(120))
-    print('Mean: ' + str(mean_dtw))
-    print('Stdev: ' + str(sd_dtw))
-    print('Ratio mean: ' + str(a))
-    print('Ratio stdev: ' + str(sd))
-    print('Theta: ' + str(theta))
-    print('r: ' + str(r))
-    print('Preprocessing time: ' + str(time() - t0))
-    return r, a, sd
-
-def debug_test_lsh():
-    data = np.load('processed-data.npy')
-    # data = np.repeat(data, repeats=7, axis=1)
-    print(data.shape)
-    data = np.reshape(data, (len(data), len(data[0][0]), len(data[0])))
-
-    r, a, sd = preprocess(data, 11.25)
-    create_windows()
-    query_n = 1234
-    t0 = time()
-    query = data[query_n]
-    data = data.astype('double')
-    dict = defaultdict(int)
-    candidates, distances, hf = _lsh.lsh(data, query, r, a, sd)
-    print("Calculated approximate in: " + str(time()-t0))
-    for l in range(len(candidates)):
-        for k in range(len(candidates[0])):
-            for i in range(len(candidates[0][0])):
-                dict[candidates[l][k][i]] += distances[l][k][i]
-    sorted_dict = {k: v for k, v in sorted(dict.items(), key=lambda item: item[1])}
-    candidates = list(sorted_dict.keys())
-
-    print(candidates[0:20])
+    table = raw_data['table']
+    data = np.load(data_path)
 
-    t0 = time()
-    # distances = [dtw_ndim.distance_fast(window, query) for window in data]
-    distances = [dtw(window, query, global_constraint='sakoe_chiba', sakoe_chiba_radius=int(0.05*120)) for window in data]
-    topk_dtw = sorted(range(len(distances)), key=lambda k: distances[k])
-    print("Calculated exact dtw in: " + str(time()-t0))
-    print(topk_dtw[0:20])
+    response = pseudo.table_info(data, table)
 
-    t0 = time()
-    l2distances = [np.linalg.norm(window - query) for window in data]
-    print("Calculated exact l2 in: " + str(time()-t0))
-
-    # # distances_ed = [distance.euclidean(query, window) for window in data]
-    # # topk_ed = sorted(range(len(distances_ed)), key=lambda k: distances_ed[k])
-    #
-    accuracy = 0
-    for index in topk_dtw[0:20]:
-        if index in candidates:
-            accuracy += 1
-    print(accuracy)
-
-# read_mts_data()
-# create_mts_windows()
-# debug_test_lsh()
\ No newline at end of file
+    print("Averages calculated: " + str(time() - t0))
+    return response
\ No newline at end of file
diff --git a/Flaskserver/preprocessing.py b/Flaskserver/preprocessing.py
new file mode 100644
index 00000000..fe389268
--- /dev/null
+++ b/Flaskserver/preprocessing.py
@@ -0,0 +1,118 @@
+import numpy as np
+import pandas as pd
+from libs import bigwig
+import bbi
+import dask.dataframe as dd
+import os.path
+from sklearn import preprocessing
+
+def read_data():
+    size = bbi.chromsizes('test.bigWig')['chr1']
+    bins = 100000
+    data = bigwig.get('data/test.bigWig', 'chr1', 0, size, bins)
+    print(data.shape)
+    response = [
+        {
+            "index": list(range(0, size, int(size/(bins)))),
+            "values": data.tolist()
+        },
+        {
+            "index": list(range(0, size, int(size / (bins)))),
+            "values": data.tolist()
+        },
+        {
+            "index": list(range(0, size, int(size / (bins)))),
+            "values": data.tolist()
+        }
+    ]
+    return response
+
+def read_mts_data():
+    filename = 'data/data.pkl'
+    if (not os.path.isfile(filename)):
+        print("start")
+        df = dd.read_csv("NW_Ground_Stations_2016.csv", usecols=['number_sta', 'date', 't', 'hu', 'td'])
+        print("read file")
+        df = df.loc[df['number_sta'].isin([14066001, 14137001, 14216001, 14372001, 22092001, 22113006, 22135001])].fillna(0)
+        print("split rows")
+        df = df.compute()
+        df.to_pickle(filename)
+        print("to_pandas")
+    df = pd.read_pickle(filename)
+    df.dropna(subset=['t'], inplace=True)
+    response = [
+        {
+            "index": df.loc[df['number_sta'] == 14066001].loc[:, 'date'].values.astype(str).tolist(),
+            "values": df.loc[df['number_sta'] == 14066001].loc[:, 't'].values.tolist()
+        },
+        {
+            "index": df.loc[df['number_sta'] == 14066001].loc[:, 'date'].values.astype(str).tolist(),
+            "values": df.loc[df['number_sta'] == 14066001].loc[:, 'hu'].values.tolist()
+        },
+        {
+            "index": df.loc[df['number_sta'] == 14066001].loc[:, 'date'].values.astype(str).tolist(),
+            "values": df.loc[df['number_sta'] == 14066001].loc[:, 'td'].values.tolist()
+        }
+    ]
+    return response
+
+def create_peax_windows_12kb(window_size):
+    data = bigwig.chunk(
+        'test.bigWig',
+        12000,
+        int(12000 / window_size),
+        int(12000 / 6),
+        ['chr1'],
+        verbose=True,
+    )
+    data = np.reshape(data, (len(data), 1, len(data[0])))
+    np.save(data_path, data)
+    return '1'
+
+def create_peax_windows_12kb_mts(window_size):
+    data = bigwig.chunk(
+        'test.bigWig',
+        12000,
+        int(12000 / window_size),
+        int(12000 / 6),
+        ['chr1'],
+        verbose=True,
+    )
+    data = np.reshape(data, (len(data), 1, len(data[0])))
+    data2 = np.copy(data)
+    np.random.shuffle(data2)
+    data3 = np.copy(data)
+    np.random.shuffle(data3)
+
+    data = np.concatenate((data, data2), axis=1)
+    data = np.concatenate((data, data3), axis=1)
+    np.save(data_path, data)
+    return '1'
+
+def create_eeg_windows(window_size, nr_of_channels):
+    datafile = '21.csv'
+    data = pd.read_csv(datafile, header=None)
+    npdata = np.array(data)
+    window_data = [npdata[i:i + window_size, 0:nr_of_channels] for i in range(0, npdata.shape[0] - window_size, int(window_size / 8))]
+    del npdata
+    np_window_data = np.repeat(window_data, repeats=3, axis=0)
+    del window_data
+    data = np.reshape(np_window_data, (len(np_window_data), nr_of_channels, len(np_window_data[0])))
+    np.save(data_path, data)
+    return '1'
+
+def create_weather_windows(window_size):
+    filename = 'data/data.pkl'
+    df = pd.read_pickle(filename)
+    channels = list()
+    channels.append(df.loc[df['number_sta'] == 14066001].loc[:, 't'].fillna(0).values.tolist())
+    channels.append(df.loc[df['number_sta'] == 14066001].loc[:, 'hu'].fillna(0).values.tolist())
+    channels.append(df.loc[df['number_sta'] == 14066001].loc[:, 'td'].fillna(0).values.tolist())
+    data = [([values[i:i+window_size] for values in channels]) for i in range(0, len(channels[0]) - window_size, 1)]
+    windows = []
+    for i in range(len(data)):
+        if i % 5000 == 0:
+            print(i)
+        windows.append(preprocessing.minmax_scale(data[i], (-1, 1), axis=1))
+    np.save('processed-data', windows)
+    return '1'
\ No newline at end of file
diff --git a/Flaskserver/pseudo.py b/Flaskserver/pseudo.py
new file mode 100644
index 00000000..9adf51db
--- /dev/null
+++ b/Flaskserver/pseudo.py
@@ -0,0 +1,243 @@
+import numpy as np
+from time import time
+import _ucrdtw
+import _lsh
+import math
+from libs.DBA_multivariate import performDBA
+from tslearn.metrics import dtw
+from collections import defaultdict
+
+def lsh(data, query, parameters = None, weights = None):
+    if parameters is None:
+        parameters = preprocess(data)
+    r = parameters[0]
+    a = parameters[1]
+    sd = parameters[2]
+
+    if weights is None:
+        candidates, distances, hf = _lsh.lsh(data, query, r, a, sd)
+    else:
+        candidates, distances, hf = _lsh.lsh(data, query, r, a, sd, weights)
+
+    dict = defaultdict(int)
+    for l in range(len(candidates)):
+        for k in range(len(candidates[0])):
+            for i in range(len(candidates[0][0])):
+                dict[candidates[l][k][i]] += distances[l][k][i]
+    sorted_dict = {k: v for k, v in sorted(dict.items(), key=lambda item: item[1])}
+    average_candidates = np.array(list(sorted_dict.keys())).tolist()
+    average_distances = np.array(list(sorted_dict.values())).tolist()
+
+    tables = []
+    samples_set = set()
+    candidates = candidates.tolist()
+    for l in range(len(candidates)):
+        for k in range(len(candidates[0])):
+            samples_set.update(candidates[l][k][0:5])
+            dict = defaultdict(list)
+            length = len(distances[l][k])
+            median = distances[l][k][math.ceil(length/2)]
+            stepsize = median / 10
+            indices = list(map(lambda x: 19 if x > median * 2 else math.floor(x / stepsize), distances[l][k]))
+            for i in range(len(candidates[0][0])):
+                dict[str(indices[i])].append(candidates[l][k][i])
+            tables.append(dict)
+
+    length = len(average_distances)
+    median = average_distances[math.ceil(length/2)]
+    stepsize = median / 10
+    indices = list(map(lambda x: 19 if x > median * 2 else math.floor(x / stepsize), average_distances))
+    average_table = defaultdict(list)
+    for i in range(len(average_candidates)):
+        average_table[str(indices[i])].append(average_candidates[i])
+
+    samples = np.array(list(filter(lambda x: x in samples_set, average_candidates))).tolist()
+
+
+    response = {
+        "hash_functions": hf.reshape((len(candidates) * len(candidates[0]), len(query[0]))).tolist(),
+        "candidates": candidates,
+        "distances": distances.tolist(),
+        "average_candidates": average_candidates,
+        "average_distances": average_distances,
+        "tables": tables,
+        "average_table": average_table,
+        "samples": list(samples),
+        "parameters": [float(r), float(a), float(sd)]
+    }
+    return response
+
+def preprocess(data, r=10.0):
+    subset = []
+    t0 = time()
+
+    i = 0
+    while i < len(data):
+        if i % 999 == 0:
+            print(r)
+            print(str(i) + ':' + str(len(subset)))
+
+        state = 1
+        for s in subset:
+            if np.linalg.norm(data[i] - data[s]) < r:
+                state = 0
+                break
+        if state == 1:
+            subset.append(i)
+
+        i = i + 1
+        if i == 10000 and len(subset) < 10:
+            r = r / 2
+            subset = []
+            i = 0
+        if len(subset) > 200:
+            r = r + r / 2
+            subset = []
+            i = 0
+
+    # subset = sample(list(range(len(data))), 200)
+    print("r = " + str(r))
+    dtw_distances = []
+    eq_distances = []
+    for i, index_1 in enumerate(subset):
+        print(i)
+        for j, index_2 in enumerate(subset):
+            if index_1 == index_2:
+                continue
+            e = np.linalg.norm(data[index_1] - data[index_2])
+            if (math.isnan(e) or e == 0):
+                eq_distances.append(0.0001)
+                dtw_distances.append(0.0001)
+                continue
+            eq_distances.append(e)
+            d = dtw(data[index_1], data[index_2], global_constraint='sakoe_chiba', sakoe_chiba_radius=int(0.05*120))
+            dtw_distances.append(d)
+
+    ratios = np.array(dtw_distances)/np.array(eq_distances)
+    mean_dtw = np.mean(dtw_distances)
+    sd_dtw = np.std(dtw_distances)
+    mean_eq = np.mean(eq_distances)
+    sd_eq = np.std(eq_distances)
+    a = np.mean(ratios)
+    sd = np.std(ratios)
+    theta = mean_dtw + -2.58 * sd_dtw
+    # theta = mean_eq + -2.58 * sd_eq
+    r = theta / ((a-sd)*math.sqrt(120))
+    if r < 0:
+        r = mean_dtw / 100
+    # r = theta / (math.sqrt(120))
+    print('Mean: ' + str(mean_dtw))
+    print('Stdev: ' + str(sd_dtw))
+    print('Ratio mean: ' + str(a))
+    print('Ratio stdev: ' + str(sd))
+    print('Theta: ' + str(theta))
+    print('r: ' + str(r))
+    print('Preprocessing time: ' + str(time() - t0))
+    return r, a, sd
+
+def weights(data, query, old_weights, labels, hash_functions):
+    alpha = 0.2
+    all_good_windows = data[[[int(index) for index, value in labels.items() if value is True]]]
+
+    good_distances = np.zeros(len(query))
+    for window in all_good_windows:
+        for i in range(len(all_good_windows[0])):
+            good_distances[i] += _ucrdtw.ucrdtw(query[i], window[i], 0.05, False)[1]
+    if len(all_good_windows) != 0:
+        good_distances = np.square(good_distances)
+        if np.sum(good_distances) != 0:
+            good_distances /= np.sum(good_distances)
+        good_distances = np.ones(len(query)) - good_distances
+        good_distances /= np.sum(good_distances)
+        good_distances *= len(all_good_windows[0])
+        good_distances = np.sqrt(good_distances)
+
+    if len(hash_functions) != 0:
+        summed_hash_functions = np.sum(hash_functions, axis=0)
+        summed_hash_functions = np.square(summed_hash_functions)
+        normalized_hash_functions = summed_hash_functions / np.sum(summed_hash_functions)
+        normalized_hash_functions *= len(hash_functions[0])
+
+    if len(hash_functions) + len(all_good_windows) == 0:
+        print("no update")
+        new_weights = old_weights
+    elif len(hash_functions) == 0:
+        print("only windows")
+        new_weights = alpha * np.array(old_weights) + (1 - alpha) * good_distances
+    elif len(all_good_windows) == 0:
+        print("only tables")
+        new_weights = alpha * np.array(old_weights) + (1 - alpha) * normalized_hash_functions
+    else:
+        print("tables & windows")
+        new_weights = alpha * np.array(old_weights) + 0.5 * (1-alpha) * good_distances + 0.5 * (1-alpha) * normalized_hash_functions
+
+    print(new_weights)
+    return new_weights.tolist()
+
+def table_info(data, table):
+    prototypes = []
+    for cluster in table:
+        windows = data[cluster]
+        average_values = np.average(windows, 0)
+        std_values = np.std(windows, 0)
+        max_values = average_values + std_values
+        min_values = average_values - std_values
+        prototypes.append({
+            'average': average_values.tolist(),
+            'max': max_values.tolist(),
+            'min': min_values.tolist()
+        })
+    # distances = [[dtw(np.array(v["average"]), np.array(w["average"]), global_constraint='sakoe_chiba', sakoe_chiba_radius=int(0.05 * 120)) for j, w in enumerate(prototypes)] for i, v in enumerate(prototypes)]
+    return {'prototypes': prototypes, 'distances': []}
+
+def query(data, window_indices):
+    if isinstance(window_indices, int):
+        output = data[window_indices]
+    else:
+        indices = [int(index) for index, value in window_indices.items() if value is True]
+        indices_windows = data[indices]
+        output = performDBA(indices_windows)
+    return output.tolist()
+
+def debug_test_lsh():
+    data = np.load('processed-data.npy')
+    # data = np.repeat(data, repeats=7, axis=1)
+    print(data.shape)
+    data = np.reshape(data, (len(data), len(data[0][0]), len(data[0])))
+
+    r, a, sd = preprocess(data, 11.25)
+    query_n = 1234
+    t0 = time()
+    query = data[query_n]
+    data = data.astype('double')
+    dict = defaultdict(int)
+    candidates, distances, hf = _lsh.lsh(data, query, r, a, sd)
+    print("Calculated approximate in: " + str(time()-t0))
+    for l in range(len(candidates)):
+        for k in range(len(candidates[0])):
+            for i in range(len(candidates[0][0])):
+                dict[candidates[l][k][i]] += distances[l][k][i]
+    sorted_dict = {k: v for k, v in sorted(dict.items(), key=lambda item: item[1])}
+    candidates = list(sorted_dict.keys())
+
+    print(candidates[0:20])
+
+    t0 = time()
+    # distances = [dtw_ndim.distance_fast(window, query) for window in data]
+    distances = [dtw(window, query, global_constraint='sakoe_chiba', sakoe_chiba_radius=int(0.05*120)) for window in data]
+    topk_dtw = sorted(range(len(distances)), key=lambda k: distances[k])
+    print("Calculated exact dtw in: " + str(time()-t0))
+    print(topk_dtw[0:20])
+
+    t0 = time()
+    l2distances = [np.linalg.norm(window - query) for window in data]
+    print("Calculated exact l2 in: " + str(time()-t0))
+
+    # # distances_ed = [distance.euclidean(query, window) for window in data]
+    # # topk_ed = sorted(range(len(distances_ed)), key=lambda k: distances_ed[k])
+    #
+    accuracy = 0
+    for index in topk_dtw[0:20]:
+        if index in candidates:
+            accuracy += 1
+    print(accuracy)
diff --git a/Flaskserver/topk.npy b/Flaskserver/topk.npy
deleted file mode 100644
index cd3b20f8..00000000
--- a/Flaskserver/topk.npy
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:76c9d862591f8291da412257fb4eff58ec5f567d7c7b14a46de3d5269958c863
-size 997096
-- 
GitLab