static void Main(string[] args) { string matrixProduct; string inputFile = ""; if (args.Length < 1) { Console.WriteLine("Error: No argument received for input file"); return; } if (args.Length < 2) { Console.WriteLine("No argument received for string. String assumed to be the empty string."); inputFile = args[0]; matrixProduct = ""; } else { inputFile = args[0]; matrixProduct = args[1]; } var symbols = new HashSet <char>(MatrixSolver.Computations.Constants.RegularLanguage.Symbols); foreach (var symbol in matrixProduct) { if (!symbols.Contains(symbol)) { throw new ArgumentException($"String contained unknown symbol {symbol}"); } } // TODO: Duplicate of main function. Expose this procedure somewhere to reduce duplicate code. var json = File.ReadAllText(inputFile); var data = JsonConvert.DeserializeObject <InputData>(json); data.ThrowIfNull(); var vectorX = new ImmutableVector2D(data.VectorX); var vectorY = new ImmutableVector2D(data.VectorY); var matrices = data.Matrices.Select(m => new ImmutableMatrix2x2(As2DArray(m, 2, 2))).ToArray(); Console.WriteLine($"Computing matrix product M = {matrixProduct}"); var M = RegularLanguageHelper.MatrixProductStringToMatrix(matrixProduct); Console.WriteLine($"Calculated M = {M}"); var expectedY = M * vectorX; if (expectedY.Equals(vectorY)) { Console.WriteLine($"Mx = y is solved for M = {M}, x = {vectorX}, y = {vectorY}"); } else { Console.WriteLine($"Expected vector y = {vectorY}, but instead found y = {expectedY}"); } }
private static ImmutableMatrix2x2 CalculateMatrixA(ImmutableVector2D vector) { var euclideanAlgorithmValues = MathematicalHelper.ExtendedEuclideanAlgorithm(vector.UnderlyingVector[0].Numerator, vector.UnderlyingVector[1].Numerator); var matrix = new BigRational[2, 2]; matrix[0, 0] = vector.UnderlyingVector[0]; matrix[1, 0] = vector.UnderlyingVector[1]; matrix[0, 1] = -euclideanAlgorithmValues.t; matrix[1, 1] = euclideanAlgorithmValues.s; return(new ImmutableMatrix2x2(matrix)); }
private static void ValidateVectorIsNonZeroAndInteger(ImmutableVector2D vector, string vectorName) { if (vector.UnderlyingVector.Any(e => !e.IsInteger())) { throw new ArgumentException($"Vector {vectorName} had a non integer element."); } if (vector.UnderlyingVector[0] == 0 && vector.UnderlyingVector[1] == 0) { throw new ArgumentException($"Vector {vectorName} was equal to zero"); } }
public void Constructor_AllowsValidVectors(int value1, int value2) { var values = new BigRational[] { value1, value2, }; var vector = new ImmutableVector2D(values); Assert.Equal(value1, vector.UnderlyingVector[0]); Assert.Equal(value2, vector.UnderlyingVector[1]); }
private static void ValidateVRPVectors(ImmutableVector2D vectorX, ImmutableVector2D vectorY, out BigRational scalar) { // Validate vectors ValidateVectorIsNonZeroAndInteger(vectorX, "x"); ValidateVectorIsNonZeroAndInteger(vectorY, "y"); var xGcd = MathematicalHelper.GCD(vectorX.UnderlyingVector[0].Numerator, vectorX.UnderlyingVector[1].Numerator); var yGcd = MathematicalHelper.GCD(vectorY.UnderlyingVector[0].Numerator, vectorY.UnderlyingVector[1].Numerator); if (xGcd != yGcd) { throw new ArgumentException($"Vector X GCD had value {xGcd} which was different to Vector Y GCD of {yGcd}. Therefore, there are no solutions in SL(2,Z)"); } scalar = new BigRational(1, xGcd); }
public void MultiplyConstant_Multiplies() { var values = new BigRational[] { 5, 7, }; var scalar = 9; var vector = new ImmutableVector2D(values); var resultingVector = vector * scalar; Assert.Equal(45, resultingVector.UnderlyingVector[0]); Assert.Equal(63, resultingVector.UnderlyingVector[1]); }
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 Subtract_SubtractsValues() { var values1 = new BigRational[] { 5, 7, }; var values2 = new BigRational[] { 1, 9, }; var vector1 = new ImmutableVector2D(values1); var vector2 = new ImmutableVector2D(values2); var resultingVector = vector1 - vector2; Assert.Equal(4, resultingVector.UnderlyingVector[0]); Assert.Equal(-2, resultingVector.UnderlyingVector[1]); }
public void Add_AddsValues() { var values1 = new BigRational[] { 5, 7, }; var values2 = new BigRational[] { 1, 9, }; var vector1 = new ImmutableVector2D(values1); var vector2 = new ImmutableVector2D(values2); var resultingVector = vector1 + vector2; Assert.Equal(6, resultingVector.UnderlyingVector[0]); Assert.Equal(16, resultingVector.UnderlyingVector[1]); }
internal static string GetVectorReachabilityProblemRegex(ImmutableVector2D vectorX, ImmutableVector2D vectorY) { // Validate input data ValidateVRPVectors(vectorX, vectorY, out BigRational scalar); // Scale down by gcd(x1, x2) = gcd(y1, y2) = d var scaledVectorX = scalar * vectorX; var scaledVectorY = scalar * vectorY; // Calcualte A(x)^-1, A(y) var AxInverse = CalculateMatrixA(scaledVectorX).Inverse(); var Ay = CalculateMatrixA(scaledVectorY); // Convert each matrix we require for the final form into a canonical string var AyAsCanonicalString = MathematicalHelper.ConvertMatrixToCanonicalString(Ay); var AxAsCanonicalString = MathematicalHelper.ConvertMatrixToCanonicalString(AxInverse); var TAsCanonicalString = String.Join("", Constants.Matrices.GeneratorMatrixIdentifierLookup[GeneratorMatrixIdentifier.T]); var TInverseAsCanonicalString = String.Join("", Constants.Matrices.GeneratorMatrixIdentifierLookup[GeneratorMatrixIdentifier.TInverse]); string matrixSolutionRegex = String.Format("{0}(({1})*|({2})*){3}", AyAsCanonicalString, TAsCanonicalString, TInverseAsCanonicalString, AxAsCanonicalString); return(matrixSolutionRegex); }
protected override void OnStartup(StartupEventArgs e) { // Application is running // Process command line args var args = e.Args; if (args.Length == 0) { Console.WriteLine("Expected a file path as an argument but received no arguments"); Shutdown(); return; } var file = args[0]; string json; try { json = File.ReadAllText(file); } catch { Console.WriteLine($"An error occured while reading file {file}"); Shutdown(); return; } InputData data; try { data = JsonConvert.DeserializeObject <InputData>(json); data.ThrowIfNull(); } catch { Console.WriteLine($"File {file} contained invalid data. Please make sure all parameters are set correctly"); Shutdown(); return; } try { var vectorX = new ImmutableVector2D(data.VectorX); var vectorY = new ImmutableVector2D(data.VectorY); var matrices = data.Matrices.Select(m => new ImmutableMatrix2x2(As2DArray(m, 2, 2))).ToArray(); Console.WriteLine("Vector Reachability Problem Input data: "); Console.WriteLine("-------------------------"); Console.WriteLine($"M1, ..., Mn = {String.Join(", ", matrices.Select(m => m.ToString()))}"); Console.WriteLine($"x = {vectorX}"); Console.WriteLine($"y = {vectorY}"); Console.WriteLine("-------------------------"); // Solve equation var sw = Stopwatch.StartNew(); var automaton = MatrixEquationSolutionFinder.SolveVectorReachabilityProblem(matrices, vectorX, vectorY); sw.Stop(); Console.WriteLine($"Solution found in {sw.ElapsedMilliseconds}ms"); // Create main application window, starting minimized if specified MainWindow mainWindow = new MainWindow(automaton); mainWindow.Show(); } catch (ArgumentException exc) { Console.WriteLine($"VRP data provided from file {file} was invalid: \n{exc.Message}"); Shutdown(); return; } catch (Exception) { Console.WriteLine("An unexpected error occured while running"); Shutdown(); return; } }
public static Automaton SolveGeneralisedVectorReachabilityProblem(string languageRegex, string languageName, ImmutableVector2D vectorX, ImmutableVector2D vectorY) { string matrixSolutionRegex = TimedFunction(() => GetVectorReachabilityProblemRegex(vectorX, vectorY), "Calculate Lvrp regex"); Console.WriteLine($"Solutions of Mx = y as a regex are of the form: Lvrp = {matrixSolutionRegex}"); Console.WriteLine($"Solution intersected with language: {languageName} = {languageRegex}"); var matrixSolutionAsCanonicalDfa = RegularLanguageRegexToCanonicalWordAcceptingDfa(matrixSolutionRegex, "Lvrp"); var languageAsCanonicalDfa = RegularLanguageRegexToCanonicalWordAcceptingDfa(languageRegex, "Lsemigr"); var intersectedDFA = TimedFunction(() => Constants.Automaton.Canonical .IntersectionWithDFA(matrixSolutionAsCanonicalDfa) .IntersectionWithDFA(languageAsCanonicalDfa), $"Intersection of Lcan, Lvrp, {languageName}") ; var minimizedDfa = TimedFunction(() => intersectedDFA.MinimizeDFA(), "DFA minimization"); return(minimizedDfa); }
/// <summary> /// Finds a solution if it exists to the vector reachability problem. /// I.e. given a list of matrices /// </summary> public static Automaton SolveVectorReachabilityProblem(ImmutableMatrix2x2[] matrices, ImmutableVector2D vectorX, ImmutableVector2D vectorY) { // Validate input data ValidateMatrixList(matrices); string matrixProductRegex = TimedFunction(() => GetMatrixSemigroupRegex(matrices), "Calculate Lsemigr regex"); return(SolveGeneralisedVectorReachabilityProblem(matrixProductRegex, "Lsemigr", vectorX, vectorY)); }