From bd38695baf2b3b4343c1474b438be85ee602ecb1 Mon Sep 17 00:00:00 2001 From: Nigel Leck Date: Sun, 24 Mar 2024 11:57:02 +1100 Subject: [PATCH 1/6] Add .coverage to the list of files to be removed in quality.sh and optimize the getSynapse method in Creature.ts --- quality.sh | 2 +- src/Creature.ts | 36 +++++++++++++++--------------------- src/architecture/Neuron.ts | 8 -------- test/Constants/Constant.ts | 25 +++++++++++++------------ test/Projection.ts | 4 ---- 5 files changed, 29 insertions(+), 46 deletions(-) diff --git a/quality.sh b/quality.sh index bbfd2f95..ca6b3b7f 100755 --- a/quality.sh +++ b/quality.sh @@ -3,7 +3,7 @@ set -e deno fmt src test bench mod.ts deno lint src test bench mod.ts -rm -rf .trace .test +rm -rf .trace .test .coverage deno test \ --allow-read \ --allow-write \ diff --git a/src/Creature.ts b/src/Creature.ts index 7e7d675f..6bd69597 100644 --- a/src/Creature.ts +++ b/src/Creature.ts @@ -730,9 +730,9 @@ export class Creature implements CreatureInternal { let results = this.cacheTo.get(toIndx); if (results === undefined) { results = []; - const tmpList = this.synapses; - for (let i = tmpList.length; i--;) { - const c = tmpList[i]; + + for (let i = this.synapses.length; i--;) { + const c = this.synapses[i]; if (c.to === toIndx) results.push(c); } @@ -760,33 +760,27 @@ export class Creature implements CreatureInternal { for (let i = tmpList.length; i--;) { const c = tmpList[i]; - if (c.from === fromIndx) results.push(c); + if (c.from === fromIndx) { + results.push(c); + } else if (c.from < fromIndx) { + break; + } } + results.reverse(); this.cacheFrom.set(fromIndx, results); } return results; } getSynapse(from: number, to: number): Synapse | null { - if (Number.isInteger(from) == false || from < 0) { - throw new Error("FROM should be a non-negative integer was: " + from); - } - - if (Number.isInteger(to) == false || to < 0) { - throw new Error("TO should be a non-negative integer was: " + to); - } + const outwardConnections = this.outwardConnections(from); - for (let pos = this.synapses.length; pos--;) { - const c = this.synapses[pos]; - - if (c.from == from) { - if (c.to == to) { - return c; - } else if (c.to < to) { - break; - } - } else if (c.from < from) { + for (let indx = outwardConnections.length; indx--;) { + const c = outwardConnections[indx]; + if (c.to == to) { + return c; + } else if (c.to < to) { break; } } diff --git a/src/architecture/Neuron.ts b/src/architecture/Neuron.ts index a950eeaf..4d9b5794 100644 --- a/src/architecture/Neuron.ts +++ b/src/architecture/Neuron.ts @@ -616,14 +616,6 @@ export class Neuron implements TagsInterface, NeuronInternal { return c != null; } - /** - * Checks if the given node is projecting to this node - */ - isProjectedBy(node: Neuron) { - const c = this.creature.getSynapse(node.index, this.index); - return c != null; - } - /** * Converts the node to a json object */ diff --git a/test/Constants/Constant.ts b/test/Constants/Constant.ts index 030fb346..e81a9b86 100644 --- a/test/Constants/Constant.ts +++ b/test/Constants/Constant.ts @@ -50,30 +50,31 @@ Deno.test("Constants", () => { input: 1, output: 1, }; - const network = Creature.fromJSON(json); - network.validate(); + const creature = Creature.fromJSON(json); + creature.validate(); for (let i = 100; i--;) { - network.modBias(); - network.addConnection(); + creature.modBias(); + creature.addConnection(); } - network.validate(); - Creature.fromJSON(network.exportJSON()); + creature.validate(); + Creature.fromJSON(creature.exportJSON()); assert( - Math.abs(network.neurons[1].bias) - 0.5 < + Math.abs(creature.neurons[1].bias) - 0.5 < 0.00001, - "Should NOT have changed the constant node was: " + network.neurons[1].bias, + "Should NOT have changed the constant node was: " + + creature.neurons[1].bias, ); assert( - (network.neurons[2].bias) > 0.60001 || - (network.neurons[2].bias) < 0.59999, - "Should have changed the hidden node was: " + network.neurons[2].bias, + (creature.neurons[2].bias) > 0.60001 || + (creature.neurons[2].bias) < 0.59999, + "Should have changed the hidden node was: " + creature.neurons[2].bias, ); assert( - network.inwardConnections(1).length === 0, + creature.inwardConnections(1).length === 0, "Should not have any inward connections", ); }); diff --git a/test/Projection.ts b/test/Projection.ts index 9aa074d9..c448e9ba 100644 --- a/test/Projection.ts +++ b/test/Projection.ts @@ -39,8 +39,4 @@ Deno.test("projection", () => { const flag3to0 = (outNode as Neuron).isProjectingTo(inNode0 as Neuron); assert(!flag3to0, "3 -> 0 should not be associated"); - - const project3by0 = (outNode as Neuron).isProjectedBy(inNode0 as Neuron); - - assert(project3by0, "3 is projected by 0"); }); From 11d35eeedc6cec7d38c0f65ee63ccd10d468c82e Mon Sep 17 00:00:00 2001 From: Nigel Leck Date: Sun, 24 Mar 2024 13:25:38 +1100 Subject: [PATCH 2/6] Refactor clearCache method and optimize outwardConnections method --- src/Creature.ts | 81 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 66 insertions(+), 15 deletions(-) diff --git a/src/Creature.ts b/src/Creature.ts index 6bd69597..b95a5012 100644 --- a/src/Creature.ts +++ b/src/Creature.ts @@ -99,10 +99,16 @@ export class Creature implements CreatureInternal { this.neurons.length = 0; } - public clearCache() { - this.cacheTo.clear(); - this.cacheFrom.clear(); - this.cacheSelf.clear(); + public clearCache(from = -1, to = -1) { + if (from == -1 || to == -1) { + this.cacheTo.clear(); + this.cacheFrom.clear(); + this.cacheSelf.clear(); + } else { + this.cacheTo.delete(to); + this.cacheFrom.delete(from); + this.cacheSelf.delete(from); + } } private initialize(options: { @@ -752,27 +758,72 @@ export class Creature implements CreatureInternal { * @param fromIndx the connections from this neuron by index * @returns the list of connections from the neuron. */ + // outwardConnections(fromIndx: number): Synapse[] { + // let results = this.cacheFrom.get(fromIndx); + // if (results === undefined) { + // results = []; + // const tmpList = this.synapses; + // for (let i = tmpList.length; i--;) { + // const c = tmpList[i]; + + // if (c.from === fromIndx) { + // results.push(c); + // } else if (c.from < fromIndx) { + // break; + // } + // } + + // results.reverse(); + // this.cacheFrom.set(fromIndx, results); + // } + // return results; + // } outwardConnections(fromIndx: number): Synapse[] { let results = this.cacheFrom.get(fromIndx); if (results === undefined) { - results = []; - const tmpList = this.synapses; - for (let i = tmpList.length; i--;) { - const c = tmpList[i]; - - if (c.from === fromIndx) { - results.push(c); - } else if (c.from < fromIndx) { - break; + const startIndex = this.binarySearchForStartIndex(fromIndx); + + if (startIndex !== -1) { + results = []; + for (let i = startIndex; i < this.synapses.length; i++) { + const tmp = this.synapses[i]; + if (tmp.from === fromIndx) { + results.push(tmp); + } else { + break; // Since it's sorted, no need to continue once 'from' changes + } } + } else { + results = []; // No connections found } - results.reverse(); this.cacheFrom.set(fromIndx, results); } return results; } + private binarySearchForStartIndex(fromIndx: number): number { + let low = 0; + let high = this.synapses.length - 1; + let result = -1; // Default to -1 if not found + + while (low <= high) { + const mid = Math.floor((low + high) / 2); + const midValue = this.synapses[mid]; + + if (midValue.from < fromIndx) { + low = mid + 1; + } else if (midValue.from > fromIndx) { + high = mid - 1; + } else { + result = mid; // Found a matching 'from', but need the first occurrence + high = mid - 1; // Look left to find the first match + } + } + + return result; + } + getSynapse(from: number, to: number): Synapse | null { const outwardConnections = this.outwardConnections(from); @@ -881,7 +932,7 @@ export class Creature implements CreatureInternal { this.synapses.push(connection); } - this.clearCache(); + this.clearCache(from, to); return connection; } From 8c2dd15521a87cc3fc4de5fa9c0d0ba3322e2be6 Mon Sep 17 00:00:00 2001 From: Nigel Leck Date: Sun, 24 Mar 2024 13:29:23 +1100 Subject: [PATCH 3/6] Remove commented out code for outwardConnections method --- src/Creature.ts | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/src/Creature.ts b/src/Creature.ts index b95a5012..0d4433cb 100644 --- a/src/Creature.ts +++ b/src/Creature.ts @@ -758,26 +758,6 @@ export class Creature implements CreatureInternal { * @param fromIndx the connections from this neuron by index * @returns the list of connections from the neuron. */ - // outwardConnections(fromIndx: number): Synapse[] { - // let results = this.cacheFrom.get(fromIndx); - // if (results === undefined) { - // results = []; - // const tmpList = this.synapses; - // for (let i = tmpList.length; i--;) { - // const c = tmpList[i]; - - // if (c.from === fromIndx) { - // results.push(c); - // } else if (c.from < fromIndx) { - // break; - // } - // } - - // results.reverse(); - // this.cacheFrom.set(fromIndx, results); - // } - // return results; - // } outwardConnections(fromIndx: number): Synapse[] { let results = this.cacheFrom.get(fromIndx); if (results === undefined) { From 1aaf6e231d632a6881243575e9aba6a22c62351b Mon Sep 17 00:00:00 2001 From: Nigel Leck Date: Sun, 24 Mar 2024 13:34:28 +1100 Subject: [PATCH 4/6] Refactor clearCache method in Creature class --- src/Creature.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Creature.ts b/src/Creature.ts index 0d4433cb..56583a58 100644 --- a/src/Creature.ts +++ b/src/Creature.ts @@ -937,15 +937,13 @@ export class Creature implements CreatureInternal { if (connection.from === from && connection.to === to) { found = true; connections.splice(i, 1); - this.clearCache(); + this.clearCache(from, to); break; } } - if (!found) { - throw new Error("No connection from: " + from + ", to: " + to); - } + assert(found, "Can't disconnect"); } async applyLearnings(config: BackPropagationConfig) { From 426feda5dacd45f483d9a2dbf11d95ae8f788429 Mon Sep 17 00:00:00 2001 From: Nigel Leck Date: Sun, 24 Mar 2024 13:34:57 +1100 Subject: [PATCH 5/6] Remove input validation in Creature.disconnect() --- src/Creature.ts | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/Creature.ts b/src/Creature.ts index 56583a58..91784a81 100644 --- a/src/Creature.ts +++ b/src/Creature.ts @@ -921,14 +921,6 @@ export class Creature implements CreatureInternal { * Disconnects the from neuron from the to node */ disconnect(from: number, to: number) { - if (Number.isInteger(from) == false || from < 0) { - throw new Error("from should be a non-negative integer was: " + from); - } - if (Number.isInteger(to) == false || to < 0) { - throw new Error("to should be a non-negative integer was: " + to); - } - - // Delete the connection in the creature's connection array const connections = this.synapses; let found = false; From 9bee5a19013948142ce9db6e555020606c98597d Mon Sep 17 00:00:00 2001 From: Nigel Leck Date: Sun, 24 Mar 2024 13:39:45 +1100 Subject: [PATCH 6/6] Refactor Synapse connection validation in Creature.ts --- src/Creature.ts | 44 -------------------------------------------- 1 file changed, 44 deletions(-) diff --git a/src/Creature.ts b/src/Creature.ts index 91784a81..d7698260 100644 --- a/src/Creature.ts +++ b/src/Creature.ts @@ -828,50 +828,6 @@ export class Creature implements CreatureInternal { weight: number, type?: "positive" | "negative" | "condition", ): Synapse { - if (Number.isInteger(from) == false || from < 0) { - throw new Error("from should be a non-negative integer was: " + from); - } - - if (Number.isInteger(to) == false || to < 0) { - throw new Error("to should be a non-negative integer was: " + to); - } - - if (to < this.input) { - throw new Error( - "to should not be pointed to any input neurons(" + - this.input + "): " + to, - ); - } - - if (to < from) { - throw new Error("to: " + to + " should not be less than from: " + from); - } - - if (typeof weight !== "number") { - if (this.DEBUG) { - this.DEBUG = false; - console.warn( - JSON.stringify(this.exportJSON(), null, 2), - ); - - this.DEBUG = true; - } - - throw new Error(from + ":" + to + ") weight not a number was: " + weight); - } - - const toNeuron = this.neurons[to]; - if (toNeuron) { - const toType = toNeuron.type; - if (toType == "constant" || toType == "input") { - throw new Error(`Can not connect ${from}->${to} with type ${toType}`); - } - } else { - throw new Error( - `Can't connect to index: ${to} of length: ${this.neurons.length}`, - ); - } - const connection = new Synapse( from, to,