diff --git a/index.html b/index.html
new file mode 100644
index 0000000..9fa0878
--- /dev/null
+++ b/index.html
@@ -0,0 +1,717 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/m.js b/m.js
deleted file mode 100644
index e2914fb..0000000
--- a/m.js
+++ /dev/null
@@ -1,54 +0,0 @@
-const M =
-{
- Iterate:
- {
- New(inDimensions, inCount, inFunction)
- {
- let row, i, outputCloud, outputVector;
- outputCloud = [];
- for(row=0; row M.Iterate.New(inV1.length, inCount, (i, row)=> inV1[i]+(inV2[i]-inV1[i])*Math.random()),
- Transpose: (inCloud)=> M.Iterate.New(inCloud.length, inCloud[0].length, (i, row)=> inCloud[i][row]),
- Outer: (inV1, inV2)=> M.Iterate.New(inV1.length, inV2.length, (i, row)=> inV1[i]*inV2[row]),
- Clone: (inCloud)=> M.Iterate.Old(inCloud, (i, row)=> inCloud[row][i])
- },
- Mutate:
- {
- Pad: inCloud=> inCloud.forEach(row=> row.push(1)),
- Unpad: inCloud=> inCloud.forEach(row=> row.pop())
- },
- Single:
- {
- Subtract: (inV1, inV2)=> inV1.map((component, i)=> component-inV2[i]),
- Multiply: (inV1, inV2)=> inV1.map((component, i)=> component*inV2[i]),
- Affine: (inV, inMatrix)=> inMatrix.map(row=> row.reduce((sum, current, index)=> sum + current*inV[index]))
- },
- Batch:
- {
- Subtract: (inCloud1, inCloud2)=> inCloud1.map((row, rowIndex)=> M.Single.Subtract(row, inCloud2[rowIndex])),
- Multiply: (inCloud1, inCloud2)=> inCloud1.map((row, rowIndex)=> M.Single.Multiply(row, inCloud2[rowIndex])),
- Affine: (inCloud, inMatrix)=> inCloud.map(row=> M.Single.Affine(row, inMatrix)),
- Sigmoid: (inCloud)=> M.Iterate.Old(inCloud, i=>1/(1+Math.Pow(Math.E, i))),
- Derivative: (inCloud)=> M.Iterate.Old(inCloud, i=>i*(1-i)),
- Scale: (inCloud, inScalar)=> M.Iterate.Old(inCloud, i=>i*inScalar)
- }
-}
-
-export default M;
\ No newline at end of file
diff --git a/m.test.js b/m.test.js
index 823298d..3183373 100644
--- a/m.test.js
+++ b/m.test.js
@@ -1,62 +1,67 @@
import { assert, assertEquals } from "https://deno.land/std@0.102.0/testing/asserts.ts";
-import { default as M } from "./m.js";
+import M from "./m.ts";
-Deno.test("Iterate.New", ()=>
+Deno.test("Iterate.Loop", ()=>
{
- let dimensions = 3;
- let count = 4;
- let cloud = M.Iterate.New(dimensions, count, (i, j)=>i+j);
+ const dimensions = 3;
+ const count = 4;
+ const cloud = M.Iterate.Loop(dimensions, count, (i, j)=>i+j);
assertEquals(cloud.length, count, "correct count");
assertEquals(cloud[0].length, dimensions, "correct dimensions");
assertEquals(cloud[0][0], 0);
assertEquals(cloud[3][2], 5, "correct output");
});
+Deno.test("Iterate.Edit", ()=>
+{
+ const c = [[1, 2], [3, 4]]
+ const t = M.Iterate.Edit(c, (i)=>i);
+ assertEquals(t.length, c.length, "correct count");
+ assertEquals(t[0][0], c[0][0], "correct dimensions");
+ assertEquals(t[1][1], c[1][1], "correct placement");
+});
Deno.test("Create.Box", ()=>
{
- let min = [-1, -2, -3];
- let max = [1, 2, 3];
- let count = 10;
+ const min = [-1, -2, -3];
+ const max = [1, 2, 3];
+ const count = 10;
- let box = M.Create.Box(min, max, count);
+ const box = M.Create.Box(min, max, count);
assertEquals(box.length, count, "correct count");
for(let i=0; i= min[j], true);
- assert(box[i][j] <= max[j], true, "correct range");
+ assert(box[i][j] >= min[j]);
+ assert(box[i][j] <= max[j], "correct range");
}
}
});
-
Deno.test("Create.Transpose", ()=>
{
- let v1 = [1, 2, 3];
- let v2 = [4, 5, 6];
- let tpose = M.Create.Transpose([v1, v2]);
+ const v1 = [1, 2, 3];
+ const v2 = [4, 5, 6];
+ const tpose = M.Create.Transpose([v1, v2]);
assertEquals(tpose.length, 3, "correct count");
assertEquals(tpose[0].length, 2, "correct dimensions");
assertEquals(tpose[0][0], v1[0]);
assertEquals(tpose[0][1], v2[0], "correct placement");
});
-
Deno.test("Create.Outer", ()=>
{
- let v1 = [1, 2, 3];
- let v2 = [4, 5];
- let outer = M.Create.Outer(v1, v2);
+ const v1 = [1, 2, 3];
+ const v2 = [4, 5];
+ const outer = M.Create.Outer(v1, v2);
assertEquals(outer.length, v2.length, "correct count");
assertEquals(outer[0].length, v1.length, "correct dimensions");
assertEquals(outer[1][0], v1[0]*v2[1], "correct placement")
});
-
Deno.test("Create.Clone", ()=>
{
- let v1 = [1, 2, 3];
- let v2 = [4, 5, 6];
- let clone = M.Create.Clone([v1, v2]);
+ const v1 = [1, 2, 3];
+ const v2 = [4, 5, 6];
+ const clone = M.Create.Clone([v1, v2]);
assertEquals(clone.length, 2, "correct count");
assertEquals(clone[0].length, v1.length, "correct dimensions");
assertEquals(clone[1][0], v2[0], "correct placement");
@@ -64,7 +69,7 @@ Deno.test("Create.Clone", ()=>
Deno.test("Mutate.Pad", ()=>
{
- let matrix = [
+ const matrix = [
[1, 2, 3],
[4, 5, 6]
];
@@ -73,10 +78,9 @@ Deno.test("Mutate.Pad", ()=>
assertEquals(matrix[0].length, 4, "correct dimensions");
assertEquals(matrix[0][3], 1, "correct placement");
});
-
Deno.test("Mutate.Unpad", ()=>
{
- let matrix = [
+ const matrix = [
[1, 2, 3, 1],
[4, 5, 6, 1]
];
@@ -88,53 +92,74 @@ Deno.test("Mutate.Unpad", ()=>
Deno.test("Single.Affine", ()=>
{
- let v = [1, 2];
- let m = [[0.1, 0.2], [0.3, 0.4]];
- let t = M.Single.Affine(v, m);
+ const v = [1, 2];
+ const m = [[0.1, 0.2], [0.3, 0.4]];
+ const t = M.Single.Affine(v, m);
assertEquals(t.length, 2, "correct dimensions");
assertEquals(t[0], 0.5)
assertEquals(t[1], 1.1, "correct placement");
+ console.log(t);
});
-
Deno.test("Single.Subtract", ()=>
{
- let v1 = [1, 2];
- let v2 = [3, 4];
- let t = M.Single.Subtract(v1, v2);
+ const v1 = [1, 2];
+ const v2 = [3, 4];
+ const t = M.Single.Subtract(v1, v2);
assertEquals(t.length, 2, "correct dimensions");
assertEquals(t[0], -2)
assertEquals(t[1], -2, "correct placement");
});
-
Deno.test("Single.Multiply", ()=>
{
- let v1 = [1, 2];
- let v2 = [3, 4];
- let t = M.Single.Multiply(v1, v2);
+ const v1 = [1, 2];
+ const v2 = [3, 4];
+ const t = M.Single.Multiply(v1, v2);
assertEquals(t.length, 2, "correct dimensions");
assertEquals(t[0], 3)
assertEquals(t[1], 8, "correct placement");
});
-
-
Deno.test("Batch.Affine", ()=>
{
- let c = [[1, 2], [3, 4]];
- let m = [[0.1, 0.2], [0.3, 0.4]];
- let t = M.Batch.Affine(c, m);
+ const c = [[1, 2], [3, 4]];
+ const m = [[0.1, 0.2], [0.3, 0.4]];
+ const t = M.Batch.Affine(c, m);
assertEquals(t.length, 2, "correct count");
assertEquals(t[0].length, 2, "correct dimensions")
assertEquals(t[0][1], 1.1, "correct placement");
});
-
Deno.test("Batch.Scale", ()=>
{
- let c = [[1, 2], [3, 4]];
- let s = 0.5;
- let t = M.Batch.Scale(c, s);
+ const c = [[1, 2], [3, 4]];
+ const s = 0.5;
+ const t = M.Batch.Scale(c, s);
assertEquals(t.length, 2, "correct count");
assertEquals(t[0].length, 2, "correct dimensions");
- console.log(t);
assertEquals(t[1][0], 1.5, "correct placement");
});
+Deno.test("Batch.Subtract", ()=>
+{
+ const c = [[1, 2], [3, 4]];
+ const s = [[0.5, 0.5], [0.5, 0.5]];
+ const t = M.Batch.Subtract(c, s);
+ assertEquals(t.length, 2, "correct count");
+ assertEquals(t[0].length, 2, "correct dimensions");
+ assertEquals(t[1][0], 2.5, "correct placement");
+});
+Deno.test("Batch.Sigmoid", ()=>
+{
+ const m = [[-1000, 1000]];
+ const t = M.Batch.Sigmoid(m);
+ assertEquals(t.length, 1, "correct count");
+ assertEquals(t[0].length, 2, "correct dimensions");
+ assert(t[0][0]>=0 && t[0][0]<0.5);
+ assert(t[0][1]<=1 && t[0][1]>0.5, "correct placement");
+});
+Deno.test("Batch.Derivative", ()=>
+{
+ const m = [[-1000, 0, 1000]];
+ const t = M.Batch.Derivative(M.Batch.Sigmoid(m));
+ assertEquals(t.length, 1, "correct count");
+ assertEquals(t[0].length, 3, "correct dimensions");
+ assert(t[0][0]t[0][2]);
+});
\ No newline at end of file
diff --git a/m.ts b/m.ts
new file mode 100644
index 0000000..a6882d2
--- /dev/null
+++ b/m.ts
@@ -0,0 +1,67 @@
+export namespace Cloud
+{
+ export type V = Array
+ export type M = Array>
+ export type HandleLoop = (indexComponent:number, indexRow:number, array:Array) => number
+ export type HandleEdit = (component:number, index:number, array:Array) => number
+};
+
+const Methods = {
+ Iterate:
+ {
+ Loop: (inDimensions:number, inCount:number, inFunction:Cloud.HandleLoop):Cloud.M =>
+ {
+ let i:number, j:number, outputVector:Cloud.V;
+ const outputCloud:Cloud.M = [];
+ for(i=0; i inCloud.map((row:Cloud.V):Cloud.V=>row.map(inFunction))
+ },
+ Create:
+ {
+ Box: (inV1:Cloud.V, inV2:Cloud.V, inCount:number):Cloud.M=> Methods.Iterate.Loop(inV1.length, inCount, i=> inV1[i]+(inV2[i]-inV1[i])*Math.random()),
+ Transpose: (inCloud:Cloud.M):Cloud.M=> Methods.Iterate.Loop(inCloud.length, inCloud[0].length, (i, row)=> inCloud[i][row]),
+ Outer: (inV1:Cloud.V, inV2:Cloud.V):Cloud.M=> Methods.Iterate.Loop(inV1.length, inV2.length, (i, row)=> inV1[i]*inV2[row]),
+ Clone: (inCloud:Cloud.M):Cloud.M=> Methods.Iterate.Edit(inCloud, i=> i)
+ },
+ Mutate:
+ {
+ Pad: (inCloud:Cloud.M):Cloud.M=> {inCloud.forEach((row:Cloud.V)=> row.push(1)); return inCloud; },
+ Unpad: (inCloud:Cloud.M):Cloud.M=> {inCloud.forEach((row:Cloud.V)=> row.pop()); return inCloud; }
+ },
+ Test:
+ {
+ Dot:(v1:Cloud.V, v2:Cloud.V):number=>
+ {
+ return v1.reduce((sum, current, index)=> sum + current*v2[index]);
+ }
+ },
+ Single:
+ {
+ Subtract: (inV1:Cloud.V, inV2:Cloud.V):Cloud.V=> inV1.map((component, i)=> component-inV2[i]),
+ Multiply: (inV1:Cloud.V, inV2:Cloud.V):Cloud.V=> inV1.map((component, i)=> component*inV2[i]),
+ Affine: (inV:Cloud.V, inMatrix:Cloud.M):Cloud.V=> inMatrix.map((row:Cloud.V)=> row.reduce((sum, current, index)=> sum + current*inV[index], 0))
+ },
+ Batch:
+ {
+ Subtract: (inCloud1:Cloud.M, inCloud2:Cloud.M):Cloud.M=> inCloud1.map((row:Cloud.V, rowIndex:number)=> Methods.Single.Subtract(row, inCloud2[rowIndex])),
+ Multiply: (inCloud1:Cloud.M, inCloud2:Cloud.M):Cloud.M=> inCloud1.map((row:Cloud.V, rowIndex:number)=> Methods.Single.Multiply(row, inCloud2[rowIndex])),
+ Affine: (inCloud1:Cloud.M, inCloud2:Cloud.M):Cloud.M=> inCloud1.map((row:Cloud.V)=> Methods.Single.Affine(row, inCloud2)),
+ Sigmoid: (inCloud:Cloud.M):Cloud.M=> Methods.Iterate.Edit(inCloud, i=>1/(1+Math.pow(Math.E, -i))),
+ Derivative: (inCloud:Cloud.M):Cloud.M=> Methods.Iterate.Edit(inCloud, i=>i*(1-i)),
+ Scale: (inCloud:Cloud.M, inScalar:number):Cloud.M=> Methods.Iterate.Edit(inCloud, i=>i*inScalar)
+ }
+};
+
+
+
+export default Methods;
\ No newline at end of file
diff --git a/methods.md b/methods.md
index b149d13..e365088 100644
--- a/methods.md
+++ b/methods.md
@@ -7,8 +7,8 @@ pad(inCloud) // done
unpad(inCloud) // done
transform(inCloud, inMatrix) // done
-sigmoid(inCloud) // 1/(1+e^x) //
-derivative(inCloud) // x*(1-x) //
-scale(inCloud1, inV) //
+sigmoid(inCloud) // 1/(1+e^x) // done
+derivative(inCloud) // x*(1-x) // done
+scale(inCloud1, inV) // done
subtract(inCloud1, inCloud2) // done
multiply(inCloud1, inCloud2) // done
\ No newline at end of file
diff --git a/nn.test.js b/nn.test.js
new file mode 100644
index 0000000..6519caf
--- /dev/null
+++ b/nn.test.js
@@ -0,0 +1,52 @@
+import { assert, assertEquals } from "https://deno.land/std@0.102.0/testing/asserts.ts";
+import { Split, Build, Label, Learn, Check } from "./nn.ts";
+
+let data = [
+ [ 0.10, 0.05, 0, 1],
+ [ 0.00, -0.06, 0, 1],
+ [ 0.99, 0.85, 1, 0],
+ [ 1.20, 1.05, 1, 0]
+];
+let columns = [2, 3];
+let input, output;
+let layers = [];
+
+Deno.test("NN.Split", ()=>
+{
+ [input, output] = Split(data, columns);
+ assert(input);
+ assert(output);
+ assertEquals(input.length, output.length, "data split into equal input and output");
+
+ assertEquals(input[0].length, 3, "padded input");
+ assertEquals(output[0].length, 2, "unpadded output");
+});
+
+Deno.test("NN.Build", ()=>
+{
+ layers = Build(2, 5, 2);
+
+ assertEquals(layers.length, 2, "correct number of matrices");
+ assertEquals(layers[0][0].length, input[0].length, "input: padded input");
+ assertEquals(layers[0].length, 5, "input: unpadded output");
+
+ assertEquals(layers[1][0].length, 6, "hidden: padded input");
+ assertEquals(layers[1].length, output[0].length, "hidden: unpadded output");
+});
+
+Deno.test("NN.Label", ()=>
+{
+ let labels = Label(input, layers);
+ assertEquals(labels.length, output.length);
+ assertEquals(labels[0].length, output[0].length);
+});
+
+Deno.test("NN.Learn", ()=>
+{
+ let error = Learn(input, layers, output, 1000, 0.1);
+ assertEquals(error.length, output.length);
+ let total = 0;
+ let count = error.length*error[0].length;
+ error.forEach(row=> row.forEach(component=> total+=Math.abs(component)));
+ assert(total/count < 0.3);
+});
\ No newline at end of file
diff --git a/nn.ts b/nn.ts
new file mode 100644
index 0000000..a09e8a1
--- /dev/null
+++ b/nn.ts
@@ -0,0 +1,78 @@
+import { default as M, Cloud } from "./m.ts";
+export type N = Array>>
+
+const Forward = (inData:Cloud.M, inLayers:N):N =>
+{
+ let i:number;
+ let stages:N = [inData];
+ let process = (index:number):Cloud.M => M.Batch.Sigmoid(M.Batch.Affine(stages[index], inLayers[index]));
+
+ for(i=0; i
+{
+ let i:number;
+ let errorBack:Cloud.M = M.Batch.Subtract(inStages[inStages.length-1], inGoals);
+
+ for(i=inLayers.length-1; i>=0; i--)
+ {
+ let errorScaled:Cloud.M = M.Batch.Multiply(errorBack, M.Batch.Derivative(inStages[i+1]));
+ errorBack = M.Batch.Affine(errorScaled, M.Create.Transpose(inLayers[i]));
+ errorScaled.forEach((inScaledError:Cloud.V, inIndex:number)=>
+ {
+ inLayers[i] = M.Batch.Subtract(
+ inLayers[i],
+ M.Batch.Scale(M.Create.Outer(inStages[i][inIndex], inScaledError), inRate)
+ );
+ });
+ }
+ return inLayers;
+};
+const Split = (inTrainingSet:Cloud.M, inHeaderLabel:Cloud.V, inHeaderKeep:Cloud.V = []):N =>
+{
+ let data:Cloud.M = [];
+ let label:Cloud.M = [];
+ if(!inHeaderKeep.length)
+ {
+ inTrainingSet[0].forEach( (item:number, index:number)=> inHeaderLabel.includes(index) ? false : inHeaderKeep.push(index) );
+ }
+ inTrainingSet.forEach((row:Cloud.V):void =>
+ {
+ let vectorData = [ ...inHeaderKeep.map((i:number)=>row[i]), 1];
+ let vectorLabel = inHeaderLabel.map((i:number)=>row[i])
+ data.push( vectorData );
+ label.push( vectorLabel );
+ });
+ return [ data, label ];
+};
+const Build = (...inLayers:Array):N =>
+{
+ let i:number;
+ let output:N = [];
+ let rand = (inDimensions:number, inCount:number):Cloud.M => M.Create.Box( new Array(inDimensions).fill(-1), new Array(inDimensions).fill(1), inCount);
+ for(i=0; i
+{
+ let stages:N = Forward(inData, inLayers);
+ return stages[stages.length-1];
+};
+const Learn = (inData:Cloud.M, inLayers:N, inLabels:Cloud.M, inIterations:number, inRate:number):Cloud.M =>
+{
+ let stages:N = [];
+ for(let i=0; i Learn(inData, inLayers, inLabels, 1, 0);
+
+export { Split, Build, Label, Learn, Check, Forward, Backward };
\ No newline at end of file
diff --git a/nn.js b/nn_old.js
similarity index 100%
rename from nn.js
rename to nn_old.js