diff --git a/js/Draw/DrawLayer.js b/js/Draw/DrawLayer.js index 609dfeb..3aa7bfa 100644 --- a/js/Draw/DrawLayer.js +++ b/js/Draw/DrawLayer.js @@ -66,7 +66,7 @@ class DrawLayer extends Draggable { handleRemove() { if (this.isIsolated()) { - this.destroy(); + this.parent.destroy(); return; } this.isolate(); @@ -77,19 +77,11 @@ class DrawLayer extends Draggable { } isolate() { - let parentLayers = this.parent.getLayers(); - if (this.dots[1].isOccupied()) { - const targetLayer = parentLayers[parentLayers.indexOf(this) + 1]; - targetLayer.dots[0].free(); - this.splitMLp(targetLayer); - } + const { prev: prevLayer, next: targetLayer } = + this.parent.getPrevAndNext(this); - parentLayers = this.parent.getLayers(); - if (this.dots[0].isOccupied()) { - const prevLayer = parentLayers[parentLayers.indexOf(this)]; - this.dots[0].free(); - prevLayer.splitMLp(this); - } + targetLayer && this.splitMlp(targetLayer); + prevLayer && prevLayer.splitMlp(this); } setShownNeuronsNum(shownNeuronsNum) { @@ -104,23 +96,20 @@ class DrawLayer extends Draggable { setShownNeurons() { this.shownNeurons.indexes = []; const shownNeuronsNum = this.getShownNeuronsNum(); - const neuronNum = this.getNeuronNum(); - this.infoBox.val = neuronNum - shownNeuronsNum; + const neuronsNum = this.getNeuronNum(); + this.infoBox.val = neuronsNum - shownNeuronsNum; + const mid = + (this.parent ? shownNeuronsNum : Math.min(shownNeuronsNum, 5)) / 2; - const displayedNeuronsNum = this.parent - ? shownNeuronsNum - : Math.min(shownNeuronsNum, 5); - const mid = displayedNeuronsNum / 2; - - for (let i = 0; i < this.neurons.length; i++) { - const neuron = this.neurons[i]; - if (i < mid || i >= neuronNum - mid) { + this.neurons.forEach((neuron, i) => { + if (i < mid || i >= neuronsNum - mid) { neuron.visible(); this.shownNeurons.indexes.push(i); - continue; + } else { + neuron.hide(); } - neuron.hide(); - } + }); + this.updateNeuronsCoordinates(); } @@ -148,12 +137,12 @@ class DrawLayer extends Draggable { this.dots.forEach((dot) => dot.updateCoordinates()); } - splitMLp(targetLayer) { - const parentLayers = targetLayer.parent.layers; - const splitIndex = parentLayers.indexOf(targetLayer); - parentLayers[splitIndex - 1].clearLines(); + splitMlp(targetLayer) { + const parent = targetLayer.parent; + const { prev, index: splitIndex } = parent.getPrevAndNext(targetLayer); + prev.clearLines(targetLayer); - const newLayers = parentLayers.splice(0, splitIndex); + const newLayers = parent.getLayers().splice(0, splitIndex); const [x, y] = [newLayers[0].x, newLayers[0].y]; @@ -165,19 +154,14 @@ class DrawLayer extends Draggable { } reconnectNeurons() { - const layers = this.parent.layers; - const index = layers.indexOf(this); - const prev = layers[index - 1]; - const next = layers[index + 1]; + const parent = this.parent; + const { prev, next } = parent.getPrevAndNext(this); + + prev && prev.connectNeurons(this); + next && this.connectNeurons(next); - if (prev) { - prev.connectNeurons(this); - } - if (next) { - this.connectNeurons(next); - } this.updateButtonCoordinates(); - this.parent.updateBorders(); + parent.updateBorders(); } connectNeurons(targetLayer) { @@ -192,27 +176,21 @@ class DrawLayer extends Draggable { } connectLayer(targetLayer) { + console.log(this, targetLayer); if (this.parent === targetLayer.parent) return; if (targetLayer.dots[0].isOccupied()) { - this.splitMLp(targetLayer); + this.splitMlp(targetLayer); } this.connectNeurons(targetLayer); - - targetLayer.parent.layers.forEach((layer) => { - this.parent.pushLayer(layer); - }); - - targetLayer.parent.destroy(); - targetLayer.parent.layers.forEach((layer) => { - layer.parent = this.parent; - }); + targetLayer.parent.moveLayers(this.parent); } - clearLines() { + clearLines(targetLayer) { this.neurons.forEach((neuron) => neuron.removeLines()); this.dots[1].free(); + targetLayer.dots[0].free(); } destroy() { @@ -221,7 +199,8 @@ class DrawLayer extends Draggable { this.dots.forEach((dot) => dot.destroy()); this.dots = []; this.canvas = null; - this.parent = null; + this.button?.destroy(); + this.button = null; } handlePressed() { @@ -288,14 +267,14 @@ class Dot { occupy() { this.occupied = true; - this.parent.button.changeImg(organizer.getImageByKey("brokenLink")); + this.parent.button.changeImg("brokenLink"); } free() { this.occupied = false; const allFree = this.parent.dots.every((d) => !d.isOccupied()); - allFree && this.parent.button.changeImg(organizer.getImageByKey("delete")); + allFree && this.parent.button.changeImg("delete"); } destroy() { @@ -343,16 +322,18 @@ class Dot { if (!this.rollover) return; const activeLine = organizer.getActiveLine(); + if (!activeLine) { - organizer.setActiveLine(new Line(this, null, true)); + !this.isInput && organizer.setActiveLine(new Line(this, null, true)); return; } - if (activeLine.from === this) { + if (activeLine.from === this || !this.isInput) { organizer.setActiveLine(null); - } else { - this.combineSchemas(); + return; } + + this.combineSchemas(); } draw() { diff --git a/js/Draw/Schema.js b/js/Draw/Schema.js index a1ab368..82b5546 100644 --- a/js/Draw/Schema.js +++ b/js/Draw/Schema.js @@ -7,6 +7,12 @@ class Schema extends Draggable { this.updateBorders(); } + getPrevAndNext(layer) { + const layers = this.getLayers(); + const index = layers.indexOf(layer); + return { prev: layers[index - 1], next: layers[index + 1], index: index }; + } + getLayers() { return this.layers; } @@ -18,21 +24,24 @@ class Schema extends Draggable { }); } + moveLayers(targetSchema) { + this.getLayers().forEach((layer) => { + targetSchema.pushLayer(layer); + }); + this.setLayers([]); + this.destroy(); + } + destroy() { - // this.canvas = null; + this.canvas = null; + this.getLayers().forEach((l) => l.destroy()); + this.setLayers([]); organizer.removeSchema(this); } pushLayer(layer) { - this.layers.push(layer); - } - - removeLayer(layer) { - const layers = this.layers; - const index = layers.indexOf(layer); - const prevLayer = layers[index - 1]; - prevLayer.splitMLp(layer); - layers.splice(index, 1); + layer.parent = this; + this.getLayers().push(layer); } updateBorders() { @@ -41,8 +50,8 @@ class Schema extends Draggable { firstY = height, lastY = 0; - for (let i = 0; i < this.layers.length; i++) { - const layer = this.layers[i]; + for (let i = 0; i < this.getLayers().length; i++) { + const layer = this.getLayers()[i]; lastX = Math.max(layer.x, lastX); firstX = Math.min(layer.x, firstX); @@ -56,7 +65,7 @@ class Schema extends Draggable { } handlePressed() { - this.layers.forEach((layer) => { + this.getLayers().forEach((layer) => { layer.handlePressed(); }); if (organizer.getDragActive()) return; @@ -64,7 +73,7 @@ class Schema extends Draggable { } resetCoordinates() { - const layers = this.layers; + const layers = this.getLayers(); const originLayer = layers[0]; layers.forEach((layer, index) => { @@ -81,14 +90,14 @@ class Schema extends Draggable { } handleReleased() { - this.layers.forEach((layer) => { + this.getLayers().forEach((layer) => { layer.released(); }); this.released(); } handleDoubleClicked() { - this.layers.forEach((layer) => layer.doubleClicked()); + this.getLayers().forEach((layer) => layer.doubleClicked()); } show() { @@ -101,8 +110,8 @@ class Schema extends Draggable { } draw() { - this.layers.forEach((layer) => layer.draw()); - this.layers.length > 1 && this.show(); + this.getLayers().forEach((layer) => layer.draw()); + this.getLayers().length > 1 && this.show(); !organizer.getDragActive() && this.over(); diff --git a/js/Draw/canvasButton.js b/js/Draw/canvasButton.js index dbaee3d..9f8fee2 100644 --- a/js/Draw/canvasButton.js +++ b/js/Draw/canvasButton.js @@ -9,8 +9,13 @@ class CanvasButton { this.img = image; } - changeImg(img) { - this.img = img; + destroy() { + this.onClick = null; + this.img = null; + } + + changeImg(imgKey) { + this.img = organizer.getImageByKey(imgKey); } setCoordinates(x, y) { diff --git a/js/MLP/Layer.js b/js/MLP/Layer.js index 41919a3..45d6151 100644 --- a/js/MLP/Layer.js +++ b/js/MLP/Layer.js @@ -4,22 +4,6 @@ class Layer { this.neurons = Array.from({ length: nout }, () => new Neuron(nin)); } - changeNin(nin) { - this.nin = nin; - this.neurons = Array.from( - { length: this.neurons.length }, - () => new Neuron(nin), - ); - } - - addNeuron() { - this.neurons.push(new Neuron(this.nin)); - } - - popNeuron() { - this.neurons.pop(); - } - call(x) { let outs = this.neurons.map((neuron) => neuron.call(x)); return outs.length === 1 ? outs[0] : outs; diff --git a/js/MLP/MLP.js b/js/MLP/MLP.js index 954986f..9284418 100644 --- a/js/MLP/MLP.js +++ b/js/MLP/MLP.js @@ -1,18 +1,8 @@ class MLP { constructor(layers = []) { - this.id = organizer.getNextId(); this.layers = layers; } - addLayer(layer) { - this.layers.push(layer); - } - - removeLayer(layer) { - let indexToRemove = this.layers.findIndex((l) => l === layer); - this.layers.splice(indexToRemove, 1); - } - predict(x) { let output = x; this.layers.forEach((layer) => { diff --git a/js/MLP/Neuron.js b/js/MLP/Neuron.js index d932723..42688b1 100644 --- a/js/MLP/Neuron.js +++ b/js/MLP/Neuron.js @@ -8,14 +8,6 @@ class Neuron { this.act_func = ActivationFunction.TANH; } - addWeight() { - this.w.push(new Value(Math.random() * 2 - 1)); - } - - popWeight() { - this.w.pop(); - } - call(x) { let act = this.b; for (let i = 0; i < this.w.length; i++) { diff --git a/js/Organizers/editOrganizer.js b/js/Organizers/editOrganizer.js index 138cabb..1d02359 100644 --- a/js/Organizers/editOrganizer.js +++ b/js/Organizers/editOrganizer.js @@ -11,7 +11,7 @@ class EditOrganizer { this.h = 500; this.editPanel = getElementById("edit-panel"); - new EventManager(this); + this.eventManager = new EventManager(this); } isEnabled() { @@ -22,11 +22,6 @@ class EditOrganizer { return this.selectedCopy; } - adjustOrigins() { - this.originX = (width - 500) / 2; - this.originY = 150; - } - toggleShrink() { const btn = getElementById("toggle-shrink-btn"); this.shrank = !this.shrank; @@ -40,6 +35,15 @@ class EditOrganizer { getElementById("info-message").innerText = text; } + getCanvas() { + return this.canvas; + } + + adjustOrigins() { + this.originX = (width - 500) / 2; + this.originY = 150; + } + placeSelected() { const layer = this.selectedCopy; const x = this.originX + (this.w - layer.w) / 2; @@ -48,66 +52,6 @@ class EditOrganizer { layer.updateNeuronsCoordinates(); } - onNeuronFocusOut(e) { - const val = parseInt(e.target.value) || 1; - setElementProperties("set-neuron-num", { value: val }); - } - - onNeuronNumChange(e) { - const layer = this.selectedCopy; - const val = this.makeInputValid(e.target.value); - const diff = val - layer.getNeuronNum(); - - for (let i = 0; i < Math.abs(diff); i++) { - diff > 0 ? layer.pushNeuron() : layer.popNeuron(); - } - - this.setMaxShownNeuronInput(); - } - - onSetShownNeuron(otherElId, e) { - const layer = this.selectedCopy; - const val = Math.min( - this.makeInputValid(e.target.value), - layer.getNeuronNum(), - ); - - setElementProperties(otherElId, { value: val }); - this.setShownNeuronsNum(val); - } - - setShownNeuronsNum(shownNeuronNum) { - this.selectedCopy.setShownNeuronsNum(shownNeuronNum); - this.setInfoText(); - } - - setMaxShownNeuronInput() { - const layer = this.selectedCopy; - const neuronNum = layer.getNeuronNum(); - const newShownNeuronNum = Math.min(layer.getShownNeuronsNum(), neuronNum); - - setElementProperties("set-shown-neuron", { - value: newShownNeuronNum, - max: neuronNum, - }); - - setElementProperties("shown-neuron-inp", { value: newShownNeuronNum }); - this.setShownNeuronsNum(newShownNeuronNum); - } - - onShownNeuronFocusOut(e) { - let val = parseInt(e.target.value) || 1; - val = Math.max(1, Math.min(val, this.selectedCopy.getNeuronNum())); - setElementProperties("shown-neuron-inp", { value: val }); - } - - makeInputValid(val) { - return isNaN(val) || val === "" || val < 1 ? 1 : val; - } - getCanvas() { - return this.canvas; - } - setLayout() { this.adjustOrigins(); this.editPanel.style.left = this.originX + "px"; @@ -123,7 +67,7 @@ class EditOrganizer { setElementProperties("set-neuron-num", { value: this.selectedCopy.getNeuronNum(), }); - this.setMaxShownNeuronInput(); + this.eventManager.setMaxShownNeuronInput(); } update() { @@ -157,7 +101,7 @@ class EditOrganizer { this.copyNeurons(layer, copy); this.shrank = !layer.shrank; // will call toggleShrink. I wanted to use same function this.selectedCopy = copy; - this.setShownNeuronsNum(layer.getShownNeuronsNum()); + this.eventManager.setShownNeuronsNum(layer.getShownNeuronsNum()); this.enabled = true; this.setup(); } diff --git a/js/Organizers/organizer.js b/js/Organizers/organizer.js index 72dc92e..54fa8cc 100644 --- a/js/Organizers/organizer.js +++ b/js/Organizers/organizer.js @@ -36,10 +36,6 @@ class Organizer { this.activeLine = line; } - getNextId() { - return ++this.lastUsedId; - } - setDragActive(dragActive) { this.dragActive = dragActive; } diff --git a/js/script.js b/js/script.js index 364f516..3d1edef 100644 --- a/js/script.js +++ b/js/script.js @@ -1,19 +1,3 @@ -function mixin(targetClass, ...mixins) { - mixins.forEach((mixin) => { - Object.getOwnPropertyNames(mixin.prototype).forEach((name) => { - if (name !== "constructor") { - const original = targetClass.prototype[name]; - targetClass.prototype[name] = function (...args) { - if (original) { - original.apply(this, args); - } - mixin.prototype[name].apply(this, args); - }; - } - }); - }); -} - function executeDrawingCommands(cnv, arr) { const parent = cnv instanceof p5.Graphics ? cnv : window; @@ -46,10 +30,6 @@ function removeEvents(elId) { getElementById(elId).removeEventListeners(); } -function findMLPbyId(id) { - return schemas.find((mlp) => mlp.origin.id == id).origin; -} - function addLayer() { organizer.addSchema(new Schema(300, 500)); }