using System.Collections.Generic;
namespace NeuralNetwork {
int rows { get => data.GetLength(0); }
int cols { get => data.GetLength(1); }
public Matrix(int rows, int cols) {
this.data = new decimal[rows, cols];
public Matrix(decimal[,] m) {
this.data = new decimal[m.GetLength(0), m.GetLength(1)];
for (int i = 0; i < this.rows; i++) {
for (int j = 0; j < this.cols; j++) {
public Matrix(params decimal[][] rows) {
this.data = new decimal[rows.Length, rows[0].Length];
for (int i = 0; i < rows.Length; i++) {
for (int j = 0; j < rows[i].Length; j++) {
this.data[i, j] = rows[i][j];
public decimal this[int row, int col] {
get => this.data[row, col];
set => this.data[row, col] = value;
public decimal[] toArray() {
decimal[] result = new decimal[this.data.Length];
for (int i = 0; i < this.rows; i++)
for (int j = 0; j < this.cols; j++)
result[k++] = this[i, j];
static public Matrix operator +(Matrix a, Matrix b) {
Matrix result = new Matrix(a.rows, a.cols);
for (int i = 0; i < a.rows; i++)
for (int j = 0; j < a.cols; j++)
result[i, j] = a[i, j] + b[i, j];
static public Matrix operator -(Matrix a, Matrix b) {
Matrix result = new Matrix(a.rows, a.cols);
for (int i = 0; i < a.rows; i++)
for (int j = 0; j < a.cols; j++)
result[i, j] = a[i, j] - b[i, j];
static public Matrix operator *(decimal a, Matrix b) {
Matrix result = new Matrix(b.rows, b.cols);
for (int i = 0; i < b.rows; i++)
for (int j = 0; j < b.cols; j++)
result[i, j] = a * b[i, j];
static public Matrix operator *(Matrix b, decimal a) {
public Matrix cross(Matrix other) {
if (this.cols==other.cols&&this.rows==other.rows) return this.hadamard(other);
if (this.cols != other.rows) throw new Exception("DimensionMismatch");
Matrix result = new Matrix(this.rows, other.cols);
for (int i = 0; i < result.rows; i++)
for (int j = 0; j < result.cols; j++)
for (int k = 0; k < this.cols; k++)
result[i, j] += this[i, k] * other[k, j];
public Matrix slice(int row, int column) {
Matrix res = new Matrix(this.rows, column);
if (column != -1) throw new Exception("slicing without -1 not allowed");
Matrix result = new Matrix(row, this.cols);
public Matrix hadamard(Matrix other) {
if (this.cols != other.cols || this.rows != other.rows) throw new Exception("DimensionMismatch");
Matrix result = new Matrix(this.rows, other.cols);
for (int i = 0; i < result.rows; i++)
for (int j = 0; j < result.cols; j++)
result[i, j] = this[i, j] * other[i, j];
Console.WriteLine("Size: " + this.rows.ToString() + "," + this.cols.ToString());
for (int i = 0; i < this.rows; i++) {
for (int j = 0; j < this.cols; j++)
Console.Write(this[i,j].ToString());
public Matrix map(Func<decimal, decimal> mappingFunciton) {
Matrix result = new Matrix(this.rows, this.cols);
for (int i = 0; i < this.rows; i++)
for (int j = 0; j < this.cols; j++)
result[i, j] = mappingFunciton(this[i, j]);
public Matrix transpose() {
Matrix result = new Matrix(this.cols, this.rows);
for (int i = 0; i < this.rows; i++)
for (int j = 0; j < this.cols; j++)
result[j, i] = this[i, j];
public class WithRandomValues : Matrix {
public WithRandomValues(int rows, int cols) : base(rows, cols) {
this.data = new decimal[rows, cols];
for (int i = 0; i < this.rows; i++)
for (int j = 0; j < this.cols; j++)
data[i, j] = (decimal)random.NextDouble();
public class WithZeroValues : Matrix {
public WithZeroValues(int rows, int cols) : base(rows, cols) {
this.data = new decimal[rows, cols];
for (int i = 0; i < this.rows; i++)
for (int j = 0; j < this.cols; j++)
data[i, j] = (decimal) 0;
public class Column : Matrix {
public Column(decimal[] input) : base(input.Length, 1) {
this.data = new decimal[rows, cols];
for (int i = 0; i < this.rows; i++)
public NeuralNetwork(params int[] layerSizes) {
this.layerSizes = layerSizes;
this.weights = new List<Matrix>();
this.biases = new List<Matrix>();
for (int i = 1; i < layerSizes.Length; i++) {
int previousLayerSize = layerSizes[i - 1];
int currentLayerSize = layerSizes[i];
this.weights.Add(new Matrix.WithZeroValues(currentLayerSize, previousLayerSize));
this.biases.Add(new Matrix.WithZeroValues(currentLayerSize, previousLayerSize));
public decimal activate(decimal x) {
return (decimal)(1 / (1 + Math.Exp((double)-x)));
public decimal dActivate(decimal x) {
public List<Matrix> feedForward(decimal[] input) {
List<Matrix> layerActivations = new List<Matrix>();
Matrix inputMatrix = new Matrix.Column(input);
for (int i = 0; i < this.layerSizes.Length - 1; i++) {
Matrix outputMatrix = (this.weights[i].cross(inputMatrix) + this.biases[i]).map(this.activate);
layerActivations.Add(outputMatrix);
inputMatrix = outputMatrix;
public decimal[] predict(decimal[] input) {
return this.feedForward(input).Last().toArray();
public void train(decimal[] input, decimal[] expected) {
decimal learningRate = 0.1m;
Matrix inputMatrix = new Matrix.Column(input);
Matrix expectedMatrix = new Matrix.Column(expected);
List<Matrix> layerActivations = this.feedForward(input);
Matrix inputActivation = inputMatrix;
Matrix hiddenActivation = layerActivations[0];
Matrix outputActivation = layerActivations[1];
Matrix weights_input_hidden = this.weights[0];
Matrix weights_hidden_output = this.weights[1];
Matrix bias_input_hidden = this.biases[0];
Matrix bias_hidden_output = this.biases[1];
var predicted = this.predict(input);
var cost_final = (expected[0] - predicted[0]) * dActivate(predicted[0]);
var rows = this.layerSizes[0];
var columns = this.layerSizes[1];
Matrix delta_weights = new Matrix.WithZeroValues(rows, columns);
Matrix delta_biases = new Matrix.WithZeroValues(rows, 1);
static void Main(string[] args) {
NeuralNetwork nn = new NeuralNetwork(2, 4, 1);
for (int i = 0; i < 1; i++) {
nn.train(new decimal[] { 0, 1 }, new decimal[] { 1 });
nn.train(new decimal[] { 1, 0 }, new decimal[] { 1 });
nn.train(new decimal[] { 0, 0 }, new decimal[] { 0 });
nn.train(new decimal[] { 1, 1 }, new decimal[] { 0 });
var b = nn.predict(new decimal[] { 0, 1 });
var c = nn.predict(new decimal[] { 0, 0 });
var d = nn.predict(new decimal[] { 1, 1 });
var e = nn.predict(new decimal[] { 1, 0 });