diff --git a/Dart/P003_Dot_Product.dart b/Dart/P003_Dot_Product.dart index 1278463..dbbe280 100644 --- a/Dart/P003_Dot_Product.dart +++ b/Dart/P003_Dot_Product.dart @@ -20,7 +20,8 @@ void main() { print(finalOutputs); } -List dotProduct({List> weights, List inputs}) { +List dotProduct( + {required List> weights, required List inputs}) { List layerOutputs = []; for (List singleWeight in weights) { @@ -34,7 +35,8 @@ List dotProduct({List> weights, List inputs}) { return layerOutputs; } -List addVectors({List interOutputs, List biases}) { +List addVectors( + {required List interOutputs, required List biases}) { List output = []; for (int i = 0; i < interOutputs.length; i++) { diff --git a/Dart/p004-Layers-and-Objects.dart b/Dart/p004-Layers-and-Objects.dart new file mode 100644 index 0000000..934d9f5 --- /dev/null +++ b/Dart/p004-Layers-and-Objects.dart @@ -0,0 +1,126 @@ +import 'dart:math'; + +Random rng = new Random(0); + +void main() { + List> X = [ + [1.0, 2.0, 3.0, 2.5], + [2.0, 5.0, -1.0, 2.0], + [-1.5, 2.7, 3.3, -0.8] + ]; + + Layer_Dense layer1 = new Layer_Dense(4, 5); + Layer_Dense layer2 = new Layer_Dense(5, 2); + + layer1.forward(X); + layer2.forward(layer1.output); + print(layer2.output); +} + +class Layer_Dense { + late List> output; + late List> weights; + late List biases; + + Layer_Dense(int n_inputs, int n_neurons) { + weights = []; + for (int i = 0; i < n_inputs; i++) { + List temp = []; + for (int j = 0; j < n_neurons; j++) { + temp.add(rng.nextDouble() * 0.1); + } + weights.add(temp); + } + biases = new List.filled(n_neurons, 0); + output = new List>.filled(n_neurons, []); + } + + void forward(List> inputs) { + output = inputs.dot(weights).addList(biases); + } +} + +/** + * Everything below is implementation of numpy in dart + */ + +extension NNFSV on List { + // dot product of 2 1D array + num dot(List list) { + if (this.length != list.length) { + throw new Exception("Lists must be the same size"); + } else { + num result = 0; + for (int i = 0; i < this.length; i++) { + result += this[i] * list[i]; + } + return result; + } + } + + // add 1D array to another + List addList(List list) { + if (this.length != list.length) { + throw new Exception("Lists must be the same length"); + } + return zip({this, list}).map((e) => e[0] + e[1]).toList(); + } +} + +// extension to allow numpy functions on 2D list +extension NNFSM on List> { + // dot product of 2 2D arrays + List> dot(List> list) { + var result = new List.filled(this.length, 0) + .map((e) => List.filled(list[0].length, 0)) + .toList(); + for (var r = 0; r < this.length; r++) { + for (var c = 0; c < list[0].length; c++) { + for (var i = 0; i < this[0].length; i++) { + result[r][c] += this[r][i] * list[i][c]; + } + } + } + return result; + } + + // transpose 2D array + List T() { + List> out = []; + var x = this.length; + var y = this[0].length; + var N = x > y ? x : y; + var M = y < x ? y : x; + for (int n = 0; n < N; n++) { + for (int m = 0; m < M; m++) { + var a = x > y ? n : m; + var b = y < x ? m : n; + if (out.length <= b) { + out.add([]); + } + out[b].add(this[a][b]); + } + } + return out; + } + + // add 1D array to 2D array + List> addList(List list) { + if (this[0].length != list.length) { + throw new Exception("List indicies must have same length"); + } + return this + .map((e) => zip({e, list}).map((j) => j[0] + j[1]).toList()) + .toList(); + } +} + +// for zipping two arrays like python, from: +// https://pub.dev/documentation/quiver/latest/quiver.iterables/zip.html +Iterable> zip(Iterable> iterables) sync* { + if (iterables.isEmpty) return; + final iterators = iterables.map((e) => e.iterator).toList(growable: false); + while (iterators.every((e) => e.moveNext())) { + yield iterators.map((e) => e.current).toList(growable: false); + } +} diff --git a/Dart/p005-ReLU-Activation.dart b/Dart/p005-ReLU-Activation.dart new file mode 100644 index 0000000..05ef764 --- /dev/null +++ b/Dart/p005-ReLU-Activation.dart @@ -0,0 +1,171 @@ +import 'dart:math'; + +Random rng = new Random(0); + +void main() { + Dataset dataset = new Dataset(); + dataset.generate_data(100, 3); + + Layer_Dense layer1 = Layer_Dense(2, 5); + Activation_ReLU activation1 = Activation_ReLU(); + + layer1.forward(dataset.X); + + activation1.forward(layer1.output); + print(activation1.output); +} + +class Layer_Dense { + late List> output; + late List> weights; + late List biases; + + Layer_Dense(int n_inputs, int n_neurons) { + weights = []; + for (int i = 0; i < n_inputs; i++) { + List temp = []; + for (int j = 0; j < n_neurons; j++) { + temp.add(rng.nextDouble() * 0.1); + } + weights.add(temp); + } + biases = new List.filled(n_neurons, 0); + output = new List>.filled(n_neurons, []); + } + + void forward(List> inputs) { + output = inputs.dot(weights).addList(biases); + } +} + +class Activation_ReLU { + late List> output; + + Activation_ReLU() { + output = []; + } + + void forward(List> inputs) { + output = + inputs.map((e) => e.map((f) => max(0, f).toDouble()).toList()).toList(); + } +} + +/** + * Everything below is implementation of numpy in dart + */ + +extension NNFSV on List { + // dot product of 2 1D array + num dot(List list) { + if (this.length != list.length) { + throw new Exception("Lists must be the same size"); + } else { + num result = 0; + for (int i = 0; i < this.length; i++) { + result += this[i] * list[i]; + } + return result; + } + } + + // add 1D array to another + List addList(List list) { + if (this.length != list.length) { + throw new Exception("Lists must be the same length"); + } + return zip({this, list}).map((e) => e[0] + e[1]).toList(); + } +} + +// extension to allow numpy functions on 2D list +extension NNFSM on List> { + // dot product of 2 2D arrays + List> dot(List> list) { + var result = new List.filled(this.length, 0) + .map((e) => List.filled(list[0].length, 0)) + .toList(); + for (var r = 0; r < this.length; r++) { + for (var c = 0; c < list[0].length; c++) { + for (var i = 0; i < this[0].length; i++) { + result[r][c] += this[r][i] * list[i][c]; + } + } + } + return result; + } + + // transpose 2D array + List T() { + List> out = []; + var x = this.length; + var y = this[0].length; + var N = x > y ? x : y; + var M = y < x ? y : x; + for (int n = 0; n < N; n++) { + for (int m = 0; m < M; m++) { + var a = x > y ? n : m; + var b = y < x ? m : n; + if (out.length <= b) { + out.add([]); + } + out[b].add(this[a][b]); + } + } + return out; + } + + // add 1D array to 2D array + List> addList(List list) { + if (this[0].length != list.length) { + throw new Exception("List indicies must have same length"); + } + return this + .map((e) => zip({e, list}).map((j) => j[0] + j[1]).toList()) + .toList(); + } +} + +// for zipping two arrays like python, from: +// https://pub.dev/documentation/quiver/latest/quiver.iterables/zip.html +Iterable> zip(Iterable> iterables) sync* { + if (iterables.isEmpty) return; + final iterators = iterables.map((e) => e.iterator).toList(growable: false); + while (iterators.every((e) => e.moveNext())) { + yield iterators.map((e) => e.current).toList(growable: false); + } +} + +// for generating spiral dataset +class Dataset { + late List> X; + late List y; + + Dataset() { + X = []; + y = []; + } + + void generate_data(int points, int classes) { + X = []; + y = new List.filled(points * classes, 0); + int ix = 0; + for (int class_number = 0; class_number < classes; class_number++) { + double r = 0; + double t = class_number * 4; + + while (r <= 1 && t <= (class_number + 1) * 4) { + double random_t = t + rng.nextInt(points) * 0.2; + List temp = [r * sin(random_t * 2.5), r * cos(random_t * 2.5)]; + y[ix] = class_number; + + X.add(temp); + + r += 1.0 / (points - 1); + t += 4.0 / (points - 1); + + ix++; + } + } + } +} diff --git a/Dart/p006-Softmax-Activation.dart b/Dart/p006-Softmax-Activation.dart new file mode 100644 index 0000000..6155bdf --- /dev/null +++ b/Dart/p006-Softmax-Activation.dart @@ -0,0 +1,219 @@ +import 'dart:math'; + +Random rng = new Random(0); + +void main() { + Dataset dataset = new Dataset(); + dataset.generate_data(100, 3); + + Layer_Dense dense1 = Layer_Dense(2, 3); + Activation_ReLU activation1 = Activation_ReLU(); + + Layer_Dense dense2 = Layer_Dense(3, 3); + Activation_SoftMax activation2 = Activation_SoftMax(); + + dense1.forward(dataset.X); + activation1.forward(dense1.output); + + dense2.forward(activation1.output); + activation2.forward(dense2.output); + + print(activation2.output); +} + +class Layer_Dense { + late List> output; + late List> weights; + late List biases; + + Layer_Dense(int n_inputs, int n_neurons) { + weights = []; + for (int i = 0; i < n_inputs; i++) { + List temp = []; + for (int j = 0; j < n_neurons; j++) { + temp.add(rng.nextDouble() * 0.1); + } + weights.add(temp); + } + biases = new List.filled(n_neurons, 0); + output = new List>.filled(n_neurons, []); + } + + void forward(List> inputs) { + output = inputs.dot(weights).addList(biases); + } +} + +class Activation_ReLU { + late List> output; + + Activation_ReLU() { + output = []; + } + + void forward(List> inputs) { + output = + inputs.map((e) => e.map((f) => max(0, f).toDouble()).toList()).toList(); + } +} + +class Activation_SoftMax { + late List> output; + + Activation_SoftMax() { + output = []; + } + + void forward(List> inputs) { + List> exp_values = inputs + .map((row) => row.map((e) => exp(e - row.max())).toList()) + .toList(); + output = exp_values + .map((row) => row.map((e) => e / row.sum()).toList()) + .toList(); + } +} + +// def forward(self, inputs): +// exp_values = np.exp(inputs - np.max(inputs, axis=1, keepdims=True)) +// probabilities = exp_values / np.sum(exp_values, axis=1, keepdims=True) +// self.output = probabilities + +/** + * Everything below is implementation of numpy in dart + */ + +extension NNFSV on List { + // dot product of 2 1D array + num dot(List list) { + if (this.length != list.length) { + throw new Exception("Lists must be the same size"); + } else { + num result = 0; + for (int i = 0; i < this.length; i++) { + result += this[i] * list[i]; + } + return result; + } + } + + // add 1D array to another + List addList(List list) { + if (this.length != list.length) { + throw new Exception("Lists must be the same length"); + } + return zip({this, list}).map((e) => e[0] + e[1]).toList(); + } + + // get max value from 1D array + double max() { + double max_value = -100; + for (var i in this) { + if (i > max_value) { + max_value = i; + } + } + return max_value; + } + + // get sum of a 1D array + double sum() { + double sum = 0; + for (var i in this) { + sum += i; + } + return sum; + } +} + +// extension to allow numpy functions on 2D list +extension NNFSM on List> { + // dot product of 2 2D arrays + List> dot(List> list) { + var result = new List.filled(this.length, 0) + .map((e) => List.filled(list[0].length, 0)) + .toList(); + for (var r = 0; r < this.length; r++) { + for (var c = 0; c < list[0].length; c++) { + for (var i = 0; i < this[0].length; i++) { + result[r][c] += this[r][i] * list[i][c]; + } + } + } + return result; + } + + // transpose 2D array + List T() { + List> out = []; + var x = this.length; + var y = this[0].length; + var N = x > y ? x : y; + var M = y < x ? y : x; + for (int n = 0; n < N; n++) { + for (int m = 0; m < M; m++) { + var a = x > y ? n : m; + var b = y < x ? m : n; + if (out.length <= b) { + out.add([]); + } + out[b].add(this[a][b]); + } + } + return out; + } + + // add 1D array to 2D array + List> addList(List list) { + if (this[0].length != list.length) { + throw new Exception("List indicies must have same length"); + } + return this + .map((e) => zip({e, list}).map((j) => j[0] + j[1]).toList()) + .toList(); + } +} + +// for zipping two arrays like python, from: +// https://pub.dev/documentation/quiver/latest/quiver.iterables/zip.html +Iterable> zip(Iterable> iterables) sync* { + if (iterables.isEmpty) return; + final iterators = iterables.map((e) => e.iterator).toList(growable: false); + while (iterators.every((e) => e.moveNext())) { + yield iterators.map((e) => e.current).toList(growable: false); + } +} + +// for generating spiral dataset +class Dataset { + late List> X; + late List y; + + Dataset() { + X = []; + y = []; + } + + void generate_data(int points, int classes) { + X = []; + y = new List.filled(points * classes, 0); + int ix = 0; + for (int class_number = 0; class_number < classes; class_number++) { + double r = 0; + double t = class_number * 4; + + while (r <= 1 && t <= (class_number + 1) * 4) { + double random_t = t + rng.nextInt(points) * 0.2; + List temp = [r * sin(random_t * 2.5), r * cos(random_t * 2.5)]; + y[ix] = class_number; + + X.add(temp); + + r += 1.0 / (points - 1); + t += 4.0 / (points - 1); + + ix++; + } + } + } +} diff --git a/Kotlin/p004-Layers-and-Objects.kt b/Kotlin/p004-Layers-and-Objects.kt new file mode 100644 index 0000000..093b39e --- /dev/null +++ b/Kotlin/p004-Layers-and-Objects.kt @@ -0,0 +1,105 @@ +import kotlin.random.Random + +val rng: Random = Random(0) + +fun main() { + var X: MutableList> = + mutableListOf( + mutableListOf(1.0, 2.0, 3.0, 2.5), + mutableListOf(2.0, 5.0, -1.0, 2.0), + mutableListOf(-1.5, 2.7, 3.3, -0.8) + ) + + var layer1: Layer_Dense = Layer_Dense(4, 5) + var layer2: Layer_Dense = Layer_Dense(5, 2) + + layer1.forward(X) + layer2.forward(layer1.output) + println(layer2.output) +} + +private class Layer_Dense { + var output: MutableList> = mutableListOf() + var weights: MutableList> = mutableListOf() + var biases: MutableList = mutableListOf() + + constructor(n_inputs: Int, n_neurons: Int) { + weights = MutableList(n_inputs) { MutableList(n_neurons) { rng.nextDouble(from = -0.5, until = 1.0) * 0.1 }} // -0.5 to make # more likely to be positive + biases = MutableList(n_neurons) { 0.0 } + output = MutableList(n_neurons) { mutableListOf() } + } + + fun forward(inputs: MutableList>) { + output = inputs.dot2D(weights).addList2D(biases) + } +} + +/** Everything below is implementation of numpy in kotlin ------------------------ */ + +// dot product of 2 1D arrays +private fun MutableList.dot1D(list: MutableList): Double { + if (list.size != this.size) { + throw Exception("Lists must be the same size") + } + var result: Double = 0.0 + for (i in 0..this.size - 1) { + result += this[i] * list[i] + } + return result +} + +// add 1D array to another 1A array +private fun MutableList.addList1D(list: MutableList): List { + if (this.size != list.size) { + throw Exception("Lists must be the same size") + } + return this.zip(list) { a, b -> a + b } +} + +// dot product of 2 2D arrays +private fun MutableList>.dot2D( + list: MutableList> +): MutableList> { + var result: MutableList> = + MutableList(this.size) { MutableList(list[0].size) { 0.0 } } + + for (r in 0..this.size - 1) { + for (c in 0..list[0].size - 1) { + for (i in 0..this[0].size - 1) { + result[r][c] += (this[r][i] * list[i][c]) + } + } + } + return result +} + +// transposes a 2D array +private fun MutableList>.T(): MutableList> { + var out: MutableList> = mutableListOf() + + var x = this.size + var y = this[0].size + var N = if (x > y) x else y + var M = if (y < x) y else x + for (n in 0..N - 1) { + for (m in 0..M - 1) { + var a = if (x > y) n else m + var b = if (y < x) m else n + if (out.size <= b) { + out.add(mutableListOf()) + } + out[b].add(this[a][b]) + } + } + return out +} + +// adds a 1D array to a 2D array +private fun MutableList>.addList2D( + list: MutableList +): MutableList> { + if (this[0].size != list.size) { + throw Exception("List indicies must be the same size") + } + return this.map { a -> a.zip(list) { b, c -> b + c }.toMutableList() }.toMutableList() +} diff --git a/Kotlin/p005-ReLU-Activation.kt b/Kotlin/p005-ReLU-Activation.kt new file mode 100644 index 0000000..129a462 --- /dev/null +++ b/Kotlin/p005-ReLU-Activation.kt @@ -0,0 +1,144 @@ +// import kotlin.math.* +// import kotlin.random.Random + +// val rng: Random = Random(0) + +// fun main() { +// var dataset = Dataset() +// dataset.generate_data(100, 3) + +// var layer1: Layer_Dense = Layer_Dense(4, 5) +// var activation1: Activation_ReLU = Activation_ReLU() + +// layer1.forward(dataset.X) +// activation1.forward(layer1.output) +// println(activation1.output) +// } + +// private class Layer_Dense { +// var output: MutableList> = mutableListOf() +// var weights: MutableList> = mutableListOf() +// var biases: MutableList = mutableListOf() + +// constructor(n_inputs: Int, n_neurons: Int) { +// weights = MutableList(n_inputs) { MutableList(n_neurons) { rng.nextDouble(from = -0.5, until = 1.0) * 0.1 }} // -0.5 to make # more likely to be positive +// biases = MutableList(n_neurons) { 0.0 } +// output = MutableList(n_neurons) { mutableListOf() } +// } + +// fun forward(inputs: MutableList>) { +// output = inputs.dot2D(weights).addList2D(biases) +// } +// } + +// private class Activation_ReLU { +// var output: MutableList> = mutableListOf() + +// fun forward(inputs: MutableList>) { +// output = inputs +// .map { e -> e.map { f -> if (0.0 > f) 0.0 else f }.toMutableList() } +// .toMutableList() +// } +// } + +// /** Everything below is implementation of numpy in kotlin ------------------------ */ + +// // dot product of 2 1D arrays +// private fun MutableList.dot1D(list: MutableList): Double { +// if (list.size != this.size) { +// throw Exception("Lists must be the same size") +// } +// var result: Double = 0.0 +// for (i in 0..this.size - 1) { +// result += this[i] * list[i] +// } +// return result +// } + +// // add 1D array to another 1A array +// private fun MutableList.addList1D(list: MutableList): List { +// if (this.size != list.size) { +// throw Exception("Lists must be the same size") +// } +// return this.zip(list) { a, b -> a + b } +// } + +// // dot product of 2 2D arrays +// private fun MutableList>.dot2D( +// list: MutableList> +// ): MutableList> { +// var result: MutableList> = +// MutableList(this.size) { MutableList(list[0].size) { 0.0 } } + +// for (r in 0..this.size - 1) { +// for (c in 0..list[0].size - 1) { +// for (i in 0..this[0].size - 1) { +// result[r][c] += (this[r][i] * list[i][c]) +// } +// } +// } +// return result +// } + +// // transposes a 2D array +// private fun MutableList>.T(): MutableList> { +// var out: MutableList> = mutableListOf() + +// var x = this.size +// var y = this[0].size +// var N = if (x > y) x else y +// var M = if (y < x) y else x +// for (n in 0..N - 1) { +// for (m in 0..M - 1) { +// var a = if (x > y) n else m +// var b = if (y < x) m else n +// if (out.size <= b) { +// out.add(mutableListOf()) +// } +// out[b].add(this[a][b]) +// } +// } +// return out +// } + +// // adds a 1D array to a 2D array +// private fun MutableList>.addList2D( +// list: MutableList +// ): MutableList> { +// if (this[0].size != list.size) { +// throw Exception("List indicies must be the same size") +// } +// return this.map { a -> a.zip(list) { b, c -> b + c }.toMutableList() }.toMutableList() +// } + +// // for generating spiral dataset +// private class Dataset { +// var X: MutableList> = mutableListOf() +// var y: MutableList = mutableListOf() + +// fun generate_data(points: Int, classes: Int) { +// y = MutableList(points * classes) { 0 } +// var ix: Int = 0 + +// for (class_number in 0..classes - 1) { +// var r: Double = 0.0 +// var t: Double = class_number * 4.0 + +// while (r <= 1 && t <= (class_number + 1) * 4) { +// var random_t: Double = t + rng.nextInt(points) * 0.2 +// var temp: MutableList = mutableListOf() +// temp.add(r * sin(random_t * 2.5)) +// temp.add(r * cos(random_t * 2.5)) + +// X.add(temp) + +// y[ix] = class_number + +// r += 1.0 / (points - 1) +// t += 4.0 / (points - 1) + +// ix++ +// } +// } +// } +// } diff --git a/Kotlin/p006-Softmax-Activation.kt b/Kotlin/p006-Softmax-Activation.kt new file mode 100644 index 0000000..abcaccf --- /dev/null +++ b/Kotlin/p006-Softmax-Activation.kt @@ -0,0 +1,181 @@ +import kotlin.math.* +import kotlin.random.Random + +val rng: Random = Random(0) + +fun main() { + var dataset = Dataset() + dataset.generate_data(100, 3) + + var dense1 = Layer_Dense(2, 3) + var activation1 = Activation_ReLU() + + var dense2 = Layer_Dense(3, 3) + var activation2 = Activation_SoftMax() + + dense1.forward(dataset.X) + activation1.forward(dense1.output) + + dense2.forward(activation1.output) + activation2.forward(dense2.output) + + println(activation2.output) +} + +private class Layer_Dense { + var output: MutableList> = mutableListOf() + var weights: MutableList> = mutableListOf() + var biases: MutableList = mutableListOf() + + constructor(n_inputs: Int, n_neurons: Int) { + weights = MutableList(n_inputs) { MutableList(n_neurons) { rng.nextDouble(from = -0.5, until = 1.0) * 0.1 }} // -0.5 to make # more likely to be positive + biases = MutableList(n_neurons) { 0.0 } + output = MutableList(n_neurons) { mutableListOf() } + } + + fun forward(inputs: MutableList>) { + output = inputs.dot2D(weights).addList2D(biases) + } +} + +private class Activation_ReLU { + var output: MutableList> = mutableListOf() + + fun forward(inputs: MutableList>) { + output = inputs + .map { e -> e.map { f -> if (0.0 > f) 0.0 else f }.toMutableList() } + .toMutableList() + } +} + +private class Activation_SoftMax { + var output: MutableList> = mutableListOf() + + fun forward(inputs: MutableList>) { + var exp_values: MutableList> = inputs.map { row -> row.map { e -> exp(e - row.max())}.toMutableList()}.toMutableList() + + output = exp_values.map { row -> row.map { e -> e / row.sum()}.toMutableList()}.toMutableList() + } +} + +/** Everything below is implementation of numpy in kotlin ------------------------ */ + +// dot product of 2 1D arrays +private fun MutableList.dot1D(list: MutableList): Double { + if (list.size != this.size) { + throw Exception("Lists must be the same size") + } + var result: Double = 0.0 + for (i in 0..this.size - 1) { + result += this[i] * list[i] + } + return result +} + +// add 1D array to another 1A array +private fun MutableList.addList1D(list: MutableList): List { + if (this.size != list.size) { + throw Exception("Lists must be the same size") + } + return this.zip(list) { a, b -> a + b } +} + +// get max value from 1D array +private fun MutableList.max(): Double { + var max_value: Double = -10.0; + for (i in this) { + if (i > max_value) { + max_value = i + } + } + return max_value +} + +// get sum of 1D array +private fun MutableList.sum(): Double { + var sum: Double = 0.0 + for (i in this) { + sum += i + } + return sum +} + +// dot product of 2 2D arrays +private fun MutableList>.dot2D( + list: MutableList> +): MutableList> { + var result: MutableList> = + MutableList(this.size) { MutableList(list[0].size) { 0.0 } } + + for (r in 0..this.size - 1) { + for (c in 0..list[0].size - 1) { + for (i in 0..this[0].size - 1) { + result[r][c] += (this[r][i] * list[i][c]) + } + } + } + return result +} + +// transposes a 2D array +private fun MutableList>.T(): MutableList> { + var out: MutableList> = mutableListOf() + + var x = this.size + var y = this[0].size + var N = if (x > y) x else y + var M = if (y < x) y else x + for (n in 0..N - 1) { + for (m in 0..M - 1) { + var a = if (x > y) n else m + var b = if (y < x) m else n + if (out.size <= b) { + out.add(mutableListOf()) + } + out[b].add(this[a][b]) + } + } + return out +} + +// adds a 1D array to a 2D array +private fun MutableList>.addList2D( + list: MutableList +): MutableList> { + if (this[0].size != list.size) { + throw Exception("List indicies must be the same size") + } + return this.map { a -> a.zip(list) { b, c -> b + c }.toMutableList() }.toMutableList() +} + +// for generating spiral dataset +private class Dataset { + var X: MutableList> = mutableListOf() + var y: MutableList = mutableListOf() + + fun generate_data(points: Int, classes: Int) { + y = MutableList(points * classes) { 0 } + var ix: Int = 0 + + for (class_number in 0..classes - 1) { + var r: Double = 0.0 + var t: Double = class_number * 4.0 + + while (r <= 1 && t <= (class_number + 1) * 4) { + var random_t: Double = t + rng.nextInt(points) * 0.2 + var temp: MutableList = mutableListOf() + temp.add(r * sin(random_t * 2.5)) + temp.add(r * cos(random_t * 2.5)) + + X.add(temp) + + y[ix] = class_number + + r += 1.0 / (points - 1) + t += 4.0 / (points - 1) + + ix++ + } + } + } +} \ No newline at end of file