/// <summary> /// Verifies a matrix product is equal to a given matrix /// </summary> public static bool IsEqual(string matrixProduct, ImmutableMatrix2x2 compareMatrix) { var matrix = MatrixProductIdentifiersToMatrix(matrixProduct); if (!matrix.Equals(compareMatrix)) { return(false); } return(true); }
public void Inverse_Throws_IfDeterminantZero() { var values = new BigRational[2, 2] { { 2, 8 }, { 1, 4 } }; var matrix = new ImmutableMatrix2x2(values); Assert.Throws <InvalidOperationException>(() => matrix.Inverse()); }
/// <summary> /// Converts a matrix in SL(2,Z) to a form using only generator matrices. /// Returns a list of matrices made up of only S and R that when mutliplied in order /// are equivelent to the original matrix. /// Based on the algorithm described here: /// https://kconrad.math.uconn.edu/blurbs/grouptheory/SL(2,Z).pdf /// </summary> public static string ConvertMatrixToCanonicalString(ImmutableMatrix2x2 matrix) { // The process is 3 steps. First convert the matrix to use the T and S matrices. // Then T, T^-1 and S^-1 need to be replaced to use S,R,X // Finally, simplify the expression to canonical form var matrixProduct = ConvertMatrixToUseTAndSGeneratorMatrices(matrix) .ReplaceTAndInverseWithStandardGenerators() .SimplifyToCanonicalForm(); return(String.Join("", matrixProduct.Select(m => m.ToString()))); }
public void Determinant_FindsDeterminant() { var values = new BigRational[2, 2] { { 2, 5 }, { 1, 4 } }; var matrix = new ImmutableMatrix2x2(values); var determinant = matrix.Determinant(); Assert.Equal(3, determinant); }
public void ConvertMatrixToUseTAndSGeneratorMatrices_ConvertsCorrectly() { var matrixValues = new BigRational[2, 2] { { 437, 202 }, { 543, 251 } }; var matrix = new ImmutableMatrix2x2(matrixValues); var expectedIdentifierList = new[] { GeneratorMatrixIdentifier.X, GeneratorMatrixIdentifier.SInverse, // -1 GeneratorMatrixIdentifier.TInverse, // S Switch GeneratorMatrixIdentifier.SInverse, // 4 GeneratorMatrixIdentifier.T, GeneratorMatrixIdentifier.T, GeneratorMatrixIdentifier.T, GeneratorMatrixIdentifier.T, // S Switch GeneratorMatrixIdentifier.SInverse, // -8 GeneratorMatrixIdentifier.TInverse, GeneratorMatrixIdentifier.TInverse, GeneratorMatrixIdentifier.TInverse, GeneratorMatrixIdentifier.TInverse, GeneratorMatrixIdentifier.TInverse, GeneratorMatrixIdentifier.TInverse, GeneratorMatrixIdentifier.TInverse, GeneratorMatrixIdentifier.TInverse, // S Switch GeneratorMatrixIdentifier.SInverse, // 6 GeneratorMatrixIdentifier.T, GeneratorMatrixIdentifier.T, GeneratorMatrixIdentifier.T, GeneratorMatrixIdentifier.T, GeneratorMatrixIdentifier.T, GeneratorMatrixIdentifier.T, // S Switch GeneratorMatrixIdentifier.SInverse, // -2 GeneratorMatrixIdentifier.TInverse, GeneratorMatrixIdentifier.TInverse, // S Switch GeneratorMatrixIdentifier.SInverse }; var matrixIdentifierList = MathematicalHelper.ConvertMatrixToUseTAndSGeneratorMatrices(matrix); Assert.Equal(expectedIdentifierList, matrixIdentifierList); }
public void Inverse_InvertsMatrix() { var values = new BigRational[2, 2] { { 2, 5 }, { 1, 4 } }; var matrix = new ImmutableMatrix2x2(values); var inverse = matrix.Inverse(); Assert.Equal(new BigRational(4, 3), inverse.UnderlyingValues[0, 0]); Assert.Equal(new BigRational(-5, 3), inverse.UnderlyingValues[0, 1]); Assert.Equal(new BigRational(-1, 3), inverse.UnderlyingValues[1, 0]); Assert.Equal(new BigRational(2, 3), inverse.UnderlyingValues[1, 1]); Assert.Equal(Constants.Matrices.I, matrix * inverse); }
public void Constructor_Initialises_IfValidValues(int value1, int value2, int value3, int value4) { var values = new BigRational[2, 2] { { value1, value2 }, { value3, value4 } }; // No exception thrown is a pass. var matrix = new ImmutableMatrix2x2(values); for (int i = 0; i < 2; i++) { for (int j = 0; j < 2; j++) { Assert.Equal(values[i, j], matrix.UnderlyingValues[i, j]); } } }
public void Multiply_MultipliesAMatrixAndVector() { var matrixValues = new BigRational[2, 2] { { 3, 4 }, { 5, 6 } }; var vectorValues = new BigRational[2] { 1, 5 }; var matrix = new ImmutableMatrix2x2(matrixValues); var vector = new ImmutableVector2D(vectorValues); var resultingVector = matrix * vector; Assert.Equal(23, resultingVector.UnderlyingVector[0]); Assert.Equal(35, resultingVector.UnderlyingVector[1]); }
public void ConvertMatrixToUseTAndSGeneratorMatrices_ConvertsCorrectly_WithTFinish(int bValue, int cornerSign, GeneratorMatrixIdentifier expectedIdentifier, bool expectedX) { var matrixValues = new BigRational[2, 2] { { cornerSign, bValue }, { 0, cornerSign } }; var matrix = new ImmutableMatrix2x2(matrixValues); var count = Math.Abs(bValue); var expectedIdentifierList = new List <GeneratorMatrixIdentifier>(); if (expectedX) { expectedIdentifierList.Add(GeneratorMatrixIdentifier.X); } for (int i = 0; i < count; i++) { expectedIdentifierList.Add(expectedIdentifier); } var matrixIdentifierList = MathematicalHelper.ConvertMatrixToUseTAndSGeneratorMatrices(matrix); Assert.Equal(expectedIdentifierList, matrixIdentifierList); }
internal static LinkedList <GeneratorMatrixIdentifier> ConvertMatrixToUseTAndSGeneratorMatrices(ImmutableMatrix2x2 toConvertMatrix) { var matrix = Matrix2x2.Copy(toConvertMatrix); LinkedList <GeneratorMatrixIdentifier> matrixProduct = new LinkedList <GeneratorMatrixIdentifier>(); // Setup aliases for a and c Func <BigInteger> a = () => matrix.UnderlyingValues[0, 0].Numerator; Func <BigInteger> c = () => matrix.UnderlyingValues[1, 0].Numerator; Action PerformSSwitchIfNeeded = () => { if (BigInteger.Abs(a()) < BigInteger.Abs(c())) { matrix.MultiplyLeft(Constants.Matrices.S); matrixProduct.AddLast(GeneratorMatrixIdentifier.SInverse); } }; PerformSSwitchIfNeeded(); // Continue until the lower left entry is 0 while (c() != 0) { var quotient = a() / c(); var targetMatrix = TToPower(-quotient); matrix.MultiplyLeft(targetMatrix); var targetMatrixIdentifier = GeneratorMatrixIdentifier.TInverse; // Choose either T or T^-1 depending on the matrix used if (quotient > 0) { targetMatrixIdentifier = GeneratorMatrixIdentifier.T; } for (int i = 0; i < BigInteger.Abs(quotient); i++) { matrixProduct.AddLast(targetMatrixIdentifier); } PerformSSwitchIfNeeded(); } // The matrix should now be in the form [[+-1, m], [0, +-1]]. This is ensured by the SL(2,Z) Group Property // Therefore it is either T^m or -T^-m = X*T^-m. var sign = a(); if (sign == -1) { // We need to add a minus to the front (I.e. X) matrixProduct.AddFirst(GeneratorMatrixIdentifier.X); } var power = matrix.UnderlyingValues[0, 1].Numerator * sign; var TOrTInverse = GeneratorMatrixIdentifier.T; // If the resulting matrix has a negative power of T, use the inverse matrix instead. if (power < 0) { TOrTInverse = GeneratorMatrixIdentifier.TInverse; } for (int i = 0; i < BigInteger.Abs(power); i++) { matrixProduct.AddLast(TOrTInverse); } return(matrixProduct); }
static Matrices() { var tMatrix = new BigRational[2, 2]; tMatrix[0, 0] = 1; tMatrix[0, 1] = 1; tMatrix[1, 0] = 0; tMatrix[1, 1] = 1; T = new ImmutableMatrix2x2(tMatrix); var sMatrix = new BigRational[2, 2]; sMatrix[0, 0] = 0; sMatrix[0, 1] = -1; sMatrix[1, 0] = 1; sMatrix[1, 1] = 0; S = new ImmutableMatrix2x2(sMatrix); var rMatrix = new BigRational[2, 2]; rMatrix[0, 0] = 0; rMatrix[0, 1] = -1; rMatrix[1, 0] = 1; rMatrix[1, 1] = 1; R = new ImmutableMatrix2x2(rMatrix); var xMatrix = new BigRational[2, 2]; xMatrix[0, 0] = -1; xMatrix[0, 1] = 0; xMatrix[1, 0] = 0; xMatrix[1, 1] = -1; X = new ImmutableMatrix2x2(xMatrix); var iMatrix = new BigRational[2, 2]; iMatrix[0, 0] = 1; iMatrix[0, 1] = 0; iMatrix[1, 0] = 0; iMatrix[1, 1] = 1; I = new ImmutableMatrix2x2(iMatrix); MatrixIdentifierDictionary = new Dictionary <GeneratorMatrixIdentifier, ImmutableMatrix2x2> { [GeneratorMatrixIdentifier.T] = Constants.Matrices.T, [GeneratorMatrixIdentifier.S] = Constants.Matrices.S, [GeneratorMatrixIdentifier.R] = Constants.Matrices.R, [GeneratorMatrixIdentifier.X] = Constants.Matrices.X, [GeneratorMatrixIdentifier.SInverse] = Constants.Matrices.S.Inverse(), // Or -S [GeneratorMatrixIdentifier.TInverse] = Constants.Matrices.T.Inverse() }; GeneratorMatrixIdentifierLookup = new Dictionary <GeneratorMatrixIdentifier, GeneratorMatrixIdentifier[]> { [GeneratorMatrixIdentifier.T] = new GeneratorMatrixIdentifier[] { GeneratorMatrixIdentifier.X, GeneratorMatrixIdentifier.S, GeneratorMatrixIdentifier.R }, [GeneratorMatrixIdentifier.TInverse] = new GeneratorMatrixIdentifier[] { GeneratorMatrixIdentifier.X, GeneratorMatrixIdentifier.R, GeneratorMatrixIdentifier.R, GeneratorMatrixIdentifier.S }, [GeneratorMatrixIdentifier.SInverse] = new GeneratorMatrixIdentifier[] { GeneratorMatrixIdentifier.X, GeneratorMatrixIdentifier.S } }; }