It is possible to implement almost any kind of machine learning algorithm using C# or the Python NumPy numeric library. NumPy has hundreds of built-in functions to do almost anything. But raw C# doesn’t have any and so it’s necessary to implement even the most basic functions.
I was sitting at home one evening and speculated aboout the absolutely essential matrix and functions needed for C# machine learning. I came up with 17 functions: MatMake(), MatLoad(), MatShow(), VecShow(), MatCopy(), MatIdentity(), MatTranspose(), MatProduct(), MatSum(), MatVecProduct(), VecMatProduct(), VecToMat(), MatToVec(), VecNorm(), VecDot(), VecEucDist(), Shuffle().
Of course there are dozens more, but for a beginner I think these are definitely the required ones. And note that I’m not considering sophisticated matrix functions such as matrix inverse, matrix pseudo-inverse, and matrix decomposition.
My matrix functions use a simple array-of-arrays design, as opposed to some sort of program-defined Matrix class definition, which is overkill in my opinion.
Output of a super short demo:
Begin matrix and vector basics A = 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 0.0 1.0 2.0 At = 1.0 5.0 9.0 2.0 6.0 0.0 3.0 7.0 1.0 4.0 8.0 2.0 At * A = 107.0 32.0 47.0 62.0 32.0 40.0 48.0 56.0 47.0 48.0 59.0 70.0 62.0 56.0 70.0 84.0 v = 2.0 4.0 6.0 8.0 A * v = 60.0 140.0 40.0 End demo
The purpose of most of these 17 basic functions should be clear from their names. MatLoad() loads a matrix from values in a text file. The Shuffle() function scrambles the order of indices in an array of integers — this is used to randomize the order in which rows of training data are processed for SGD training.

I enjoy trivia contests. There are a lot of areas that are essential knowledge, such as geography, American history, and classical art. James Tissot (1836-1902) makes occassional appearances in trivia answers. Tissot did a wide range of paintings, illustrations, and caricatures. Here are two of my favorite Tissot paintings. Left: “An Interesting Story” (1872). Right: “The Gallery of HMS Calcutta” (1876).
Demo program. Replace “lt” (less than), “gt”, “lte”, “gte” with Boolean operator symbols (my blog editor chokes on symbols).
using System;
using System.IO;
using System.Collections.Generic;
namespace MatrixVectorBasics
{
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine("\nBegin matrix and vector basics ");
//double[][] A = MatLoad("data.txt",
// new int[] { 0, 1, 2, 3 }, ',', "#");
double[][] A = new double[3][];
A[0] = new double[] { 1, 2, 3, 4 };
A[1] = new double[] { 5, 6, 7, 8 };
A[2] = new double[] { 9, 0, 1, 2 };
Console.WriteLine("\nA = ");
MatShow(A, 1, 5);
double[][] At = MatTranspose(A);
Console.WriteLine("\nAt = ");
MatShow(At, 1, 5);
double[][] AtA = MatProduct(At, A);
Console.WriteLine("\nAt * A = ");
MatShow(AtA, 1, 6);
double[] v = new double[] { 2.0, 4.0, 6.0, 8.0 };
Console.WriteLine("\nv = ");
VecShow(v, 1, 6);
double[] Av = MatVecProd(A, v);
Console.WriteLine("\nA * v = ");
VecShow(Av, 1, 7);
Console.WriteLine("\nEnd demo ");
Console.ReadLine();
} // Main
// --------------------------------------------------------
static double[][] MatMake(int nRows, int nCols)
{
double[][] result = new double[nRows][];
for (int i = 0; i "lt" nRows; ++i)
result[i] = new double[nCols];
return result;
}
// --------------------------------------------------------
static double[][] MatLoad(string fn,
int[] usecols, char sep, string comment)
{
List"lt"double[]"gt" result =
new List"lt"double[]"gt"();
string line = "";
FileStream ifs = new FileStream(fn, FileMode.Open);
StreamReader sr = new StreamReader(ifs);
while ((line = sr.ReadLine()) != null)
{
if (line.StartsWith(comment) == true)
continue;
string[] tokens = line.Split(sep);
List"lt"double"gt" lst = new List"lt"double"gt"();
for (int j = 0; j "lt" usecols.Length; ++j)
lst.Add(double.Parse(tokens[usecols[j]]));
double[] row = lst.ToArray();
result.Add(row);
}
sr.Close(); ifs.Close();
return result.ToArray();
}
// --------------------------------------------------------
static void MatShow(double[][] A, int dec, int wid)
{
int nRows = A.Length; int nCols = A[0].Length;
double small = 1.0 / Math.Pow(10, dec);
for (int i = 0; i "lt" nRows; ++i)
{
for (int j = 0; j "lt" nCols; ++j)
{
double v = A[i][j];
if (Math.Abs(v) "lt" small) v = 0.0;
Console.Write(v.ToString("F" + dec).
PadLeft(wid));
}
Console.WriteLine("");
}
}
// --------------------------------------------------------
static void VecShow(double[] v, int dec, int wid)
{
int n = v.Length;
double small = 1.0 / Math.Pow(10, dec);
for (int i = 0; i "lt" n; ++i)
{
double x = v[i];
if (Math.Abs(x) "lt" small) x = 0.0;
Console.Write(x.ToString("F" + dec).
PadLeft(wid));
}
Console.WriteLine("");
}
// --------------------------------------------------------
static double[][] MatCopy(double[][] A)
{
int nRows = A.Length; int nCols = A[0].Length;
double[][] result = MatMake(nRows, nCols);
for (int i = 0; i "lt" nRows; ++i)
for (int j = 0; j "lt" nCols; ++j)
result[i][j] = A[i][j];
return result;
}
// ------------------------------------------------------
static double[][] MatIdentity(int n)
{
double[][] result = MatMake(n, n);
for (int i = 0; i "lt" n; ++i)
result[i][i] = 1.0;
return result;
}
// --------------------------------------------------------
static double[][] MatTranspose(double[][] A)
{
int nRows = A.Length; int nCols = A[0].Length;
double[][] result = MatMake(nCols, nRows); // note
for (int i = 0; i "lt" nRows; ++i)
for (int j = 0; j "lt" nCols; ++j)
result[j][i] = A[i][j];
return result;
}
// --------------------------------------------------------
static double[][] MatProduct(double[][] A, double[][] B)
{
int aRows = A.Length;
int aCols = A[0].Length;
int bRows = B.Length;
int bCols = B[0].Length;
if (aCols != bRows)
throw new Exception("Non-conformable matrices");
double[][] result = MatMake(aRows, bCols);
for (int i = 0; i "lt" aRows; ++i) // each row of A
for (int j = 0; j "lt" bCols; ++j) // each col of B
for (int k = 0; k "lt" aCols; ++k) // could use bRows
result[i][j] += A[i][k] * B[k][j];
return result;
}
// --------------------------------------------------------
static double[][] MatSum(double[][] A, double[][] B)
{
int nRows = A.Length; int nCols = A[0].Length;
double[][] result = MatMake(nRows, nCols);
for (int i = 0; i "lt" nRows; ++i)
for (int j = 0; j "lt" nCols; ++j)
result[i][j] = A[i][j] + B[i][j];
return result;
}
// --------------------------------------------------------
static double[] MatVecProd(double[][] A, double[] v)
{
// return a regular vector
int nRows = A.Length; int nCols = A[0].Length;
int n = v.Length;
if (nCols != n)
throw new Exception("non-comform in MatVecProd");
double[] result = new double[nRows];
for (int i = 0; i "lt" nRows; ++i)
for (int k = 0; k "lt" nCols; ++k)
result[i] += A[i][k] * v[k];
return result;
}
static double[] VecMatProd(double[] v, double[][] A)
{
// return a regular vector
int nRows = A.Length; int nCols = A[0].Length;
int n = v.Length;
if (n != nRows)
throw new Exception("non-comform in VecMatProd");
double[] result = new double[nCols];
for (int j = 0; j "lt" nCols; ++j)
for (int k = 0; k "lt" n; ++k)
result[j] += v[k] * A[k][j];
return result;
}
// --------------------------------------------------------
static double[][] VecToMat(double[] vec,
int nRows, int nCols)
{
double[][] result = MatMake(nRows, nCols);
int k = 0;
for (int i = 0; i "lt" nRows; ++i)
for (int j = 0; j "lt" nCols; ++j)
result[i][j] = vec[k++];
return result;
}
// --------------------------------------------------------
static double[] MatToVec(double[][] A)
{
int nRows = A.Length; int nCols = A[0].Length;
double[] result = new double[nRows * nCols];
int k = 0;
for (int i = 0; i "lt" nRows; ++i)
for (int j = 0; j "lt" nCols; ++j)
{
result[k++] = A[i][j];
}
return result;
}
// --------------------------------------------------------
static double VecNorm(double[] vec)
{
int n = vec.Length;
double sum = 0.0;
for (int i = 0; i "lt" n; ++i)
sum += vec[i] * vec[i];
return Math.Sqrt(sum);
}
// --------------------------------------------------------
static double VecDot(double[] v1, double[] v2)
{
double result = 0.0;
int n = v1.Length;
for (int i = 0; i "lt" n; ++i)
result += v1[i] * v2[i];
return result;
}
// --------------------------------------------------------
static double VecEucDist(double[] v1, double[] v2)
{
// Eucliden distance v1, v2
double sum = 0.0;
int n = v1.Length;
for (int i = 0; i "lt" n; ++i)
sum += (v1[i] - v2[i]) * (v1[i] - v2[i]);
return Math.Sqrt(sum);
}
// --------------------------------------------------------
static void Shuffle(int[] indices, Random rnd)
{
// Fisher-Yates. last iteration not necessary
for (int i = 0; i "lt" indices.Length; ++i)
{
int ri = rnd.Next(i, indices.Length);
int tmp = indices[i];
indices[i] = indices[ri];
indices[ri] = tmp;
}
} // Shuffle
} // class Program
} // ns

.NET Test Automation Recipes
Software Testing
SciPy Programming Succinctly
Keras Succinctly
R Programming
2026 Visual Studio Live
2025 Summer MLADS Conference
2026 DevIntersection Conference
2025 Machine Learning Week
2025 Ai4 Conference
2026 G2E Conference
2026 iSC West Conference
You must be logged in to post a comment.