public void SquareMatrixDifficultEigensystem() { // this requires > 30 iterations to converge, looses more accuracy than it should // this example throws a NonConvergenceException without the ad hoc shift but works once the ad hoc shift is included SquareMatrix M = new SquareMatrix(4); M[0, 1] = 2; M[0, 3] = -1; M[1, 0] = 1; M[2, 1] = 1; M[3, 2] = 1; // The eigenvalues of this matrix are -1, -1, 1, 1. // There are only two distinct eigenvectors: (1, -1, 1, -1) with eigenvalue -1, and (1, 1, 1, 1) with eigenvalue 1. ComplexEigensystem E = M.Eigensystem(); for (int i = 0; i < E.Dimension; i++) { Console.WriteLine(E.Eigenvalue(i)); for (int j = 0; j < E.Dimension; j++) { Console.Write("{0} ", E.Eigenvector(i)[j]); } Console.WriteLine(); Assert.IsTrue(TestUtilities.IsNearlyEigenpair(M, E.Eigenvector(i), E.Eigenvalue(i))); } }
public void SquareVandermondeMatrixEigenvalues() { for (int d = 1; d <= 8; d++) { SquareMatrix H = CreateVandermondeMatrix(d); double tr = H.Trace(); ComplexEigensystem E = H.Eigensystem(); double sum = 0.0; for (int i = 0; i < d; i++) { Console.WriteLine(E.Eigenvalue(i)); double e = E.Eigenvalue(i).Re; sum += e; Complex[] vc = E.Eigenvector(i); ColumnVector v = new ColumnVector(d); for (int j = 0; j < d; j++) { //Console.WriteLine(" {0}", vc[j]); v[j] = vc[j].Re; } ColumnVector Hv = H * v; ColumnVector ev = e * v; Assert.IsTrue(TestUtilities.IsNearlyEigenpair(H, v, e)); } Assert.IsTrue(TestUtilities.IsNearlyEqual(tr, sum)); } }
public void SquareUnitMatrixEigensystem() { int d = 3; SquareMatrix I = TestUtilities.CreateSquareUnitMatrix(d); ComplexEigensystem E = I.Eigensystem(); Assert.IsTrue(E.Dimension == d); for (int i = 0; i < d; i++) { Complex val = E.Eigenvalue(i); Assert.IsTrue(val == 1.0); Complex[] vec = E.Eigenvector(i); for (int j = 0; j < d; j++) { if (i == j) { Assert.IsTrue(vec[j] == 1.0); } else { Assert.IsTrue(vec[j] == 0.0); } } } }
public void SquareMatrixStochasticEigensystem() { // this is a simplifed form of a Markov matrix that arose in the Monopoly problem // and failed to converge int n = 12; // originally failed for n=12 due to lack of 2x2 detection at top // now tested for n up to 40, but n=14 appears to still be a problem, // probably due to a six-times degenerate eigenvalue SquareMatrix R = new SquareMatrix(n); for (int c = 0; c < n; c++) { R[(c + 2) % n, c] = 1.0 / 36.0; R[(c + 3) % n, c] = 2.0 / 36.0; R[(c + 4) % n, c] = 3.0 / 36.0; R[(c + 5) % n, c] = 4.0 / 36.0; R[(c + 6) % n, c] = 5.0 / 36.0; R[(c + 7) % n, c] = 6.0 / 36.0; R[(c + 8) % n, c] = 5.0 / 36.0; R[(c + 9) % n, c] = 4.0 / 36.0; R[(c + 10) % n, c] = 3.0 / 36.0; R[(c + 11) % n, c] = 2.0 / 36.0; R[(c + 12) % n, c] = 1.0 / 36.0; } //Complex[] v = R.Eigenvalues(); ComplexEigensystem E = R.Eigensystem(); for (int i = 0; i < E.Dimension; i++) { Console.WriteLine(E.Eigenvalue(i)); Assert.IsTrue(TestUtilities.IsNearlyEigenpair(R, E.Eigenvector(i), E.Eigenvalue(i))); } }
public void Bug7208() { // this matrix has two eigenpairs with the same eigenvalue but distinct eigenvectors // we would report the same eigenvector for both, making the matrix of eigenvectors // non-invertible int n = 4; SquareMatrix matrix = new SquareMatrix(n + 1); double d = (3 + 2 * Math.Cos(2 * Math.PI / n)); double w = (64 * n) / (40 - d * d) - n; double w1 = w / (w + n); double w2 = 1 / (w + n); matrix[0, 0] = w1; for (int i = 1; i < n; i++) { matrix[0, i + 1] = w2; matrix[i + 1, 0] = 3.0 / 8; matrix[i + 1, i + 1] = 3.0 / 8; matrix[i, i + 1] = 1.0 / 8; matrix[i + 1, i] = 1.0 / 8; } matrix[0, 1] = w2; matrix[1, 0] = 3.0 / 8; matrix[1, 1] = 3.0 / 8; matrix[1, n] = 1.0 / 8; matrix[n, 1] = 1.0 / 8; ComplexEigensystem ces = matrix.Eigensystem(); Console.WriteLine("output"); SquareMatrix V = new SquareMatrix(n + 1); for (int i = 0; i < n + 1; i++) { Console.WriteLine("#{0}: {1}", i, ces.Eigenvalue(i)); for (int j = 0; j < n + 1; j++) { V[i, j] = ces.Eigenvector(i)[j].Re; Console.WriteLine(V[i, j]); } } SquareMatrix inv = V.Inverse(); }
public void Bug8021() { // User presented a matrix with a large number (138) of zero eigenvalues. // QR algorithm got tripped up on high degeneracy, but eigenvalues could // be revealed before QR by simple index permutation. Added code to isolate // these "cheap" eigenvalues before starting QR algorithm. int n = 276; SquareMatrix A = new SquareMatrix(n); using (System.IO.StreamReader reader = System.IO.File.OpenText(@"Bug8021.csv")) { int r = 0; while (!reader.EndOfStream) { string line = reader.ReadLine(); string[] cells = line.Split(','); for (int c = 0; c < cells.Length; c++) { string cell = cells[c]; double value = Double.Parse(cell); A[r, c] = value; } r++; } } ComplexEigensystem S = A.Eigensystem(); for (int i = 0; i < S.Dimension; i++) { TestUtilities.IsNearlyEigenpair(A, S.Eigenvector(i), S.Eigenvalue(i)); } Complex[] eigenvalues = A.Eigenvalues(); double trace = A.Trace(); Complex sum = 0.0; for (int i = 0; i < eigenvalues.Length; i++) { sum += eigenvalues[i]; } TestUtilities.IsNearlyEqual(trace, sum); }
public void SquareRandomMatrixEigenvalues() { for (int d = 1; d <= 67; d = d + 11) { SquareMatrix I = TestUtilities.CreateSquareUnitMatrix(d); SquareMatrix M = CreateSquareRandomMatrix(d, d); double tr = M.Trace(); DateTime start = DateTime.Now; ComplexEigensystem E = M.Eigensystem(); DateTime finish = DateTime.Now; Console.WriteLine("d={0} t={1} ms", d, (finish - start).Milliseconds); Assert.IsTrue(E.Dimension == d); Complex[] es = new Complex[d]; for (int i = 0; i < d; i++) { es[i] = E.Eigenvalue(i); Complex[] v = E.Eigenvector(i); Assert.IsTrue(TestUtilities.IsNearlyEigenpair(M, v, es[i])); } Assert.IsTrue(TestUtilities.IsSumNearlyEqual(es, tr)); } }
public void CompanionMatrixEigenvalues() { SquareMatrix CM = new SquareMatrix(3); CM[0, 2] = -1.0; CM[1, 0] = 1.0; CM[1, 2] = -3.0; CM[2, 1] = 1.0; CM[2, 2] = -3.0; ComplexEigensystem EM = CM.Eigensystem(); for (int i = 0; i < EM.Dimension; i++) { Console.WriteLine("! {0}", EM.Eigenvalue(i)); } for (int d = 2; d <= 8; d++) { Console.WriteLine(d); SquareMatrix C = new SquareMatrix(d); for (int r = 1; r < d; r++) { C[r, r - 1] = 1.0; } for (int r = 0; r < d; r++) { C[r, d - 1] = -AdvancedIntegerMath.BinomialCoefficient(d, r); } ComplexEigensystem e = C.Eigensystem(); for (int i = 0; i < e.Dimension; i++) { Console.WriteLine("!! {0}", e.Eigenvalue(i)); } } }
private static void Main(string[] args) { // define squares BoardSpace[] spaces = new BoardSpace[] { new BoardSpace("Go", 0.0, Double.PositiveInfinity), new BoardSpace("Mediterranean Avenue", 2.0, 60.0), new BoardSpace("Community Chest", 0.0, Double.PositiveInfinity), new BoardSpace("Baltic Avenue", 4.0, 60.0), new BoardSpace("Income Tax", 0.0, Double.PositiveInfinity), new BoardSpace("Reading Railroad", 25.0, 200.0), new BoardSpace("Oriental Avenue", 6.0, 100.0), new BoardSpace("Chance", 0.0, Double.PositiveInfinity), new BoardSpace("Vermont Avenue", 6.0, 100.0), new BoardSpace("Connecticut Avenue", 8.0, 120.0), new BoardSpace("Jail", 0.0, Double.PositiveInfinity), new BoardSpace("St. Charles Place", 10.0, 140.0), new BoardSpace("Electric Company", 4.0 * 6.0, 150.0), new BoardSpace("States Avenue", 10.0, 140.0), new BoardSpace("Virginia Avenue", 12.0, 160.0), new BoardSpace("Pennsylvania Railroad", 25.0, 200.0), new BoardSpace("St. James Place", 14.0, 180.0), new BoardSpace("Community Chest", 0.0, Double.PositiveInfinity), new BoardSpace("Tennessee Avenue", 14.0, 180.0), new BoardSpace("New York Avenue", 16.0, 200.0), new BoardSpace("Free Parking", 0.0, Double.PositiveInfinity), new BoardSpace("Kentucky Avenue", 18.0, 220.0), new BoardSpace("Chance", 0.0, Double.PositiveInfinity), new BoardSpace("Indiana Avenue", 18.0, 220.0), new BoardSpace("Illinois Avenue", 20.0, 240.0), new BoardSpace("B & O Railroad", 25.0, 200.0), new BoardSpace("Atlantic Avenue", 22.0, 260.0), new BoardSpace("Ventnor Avenue", 22.0, 260.0), new BoardSpace("Water Works", 4.0 * 6.0, 150.0), new BoardSpace("Marvin Gardens", 24.0, 280.0), new BoardSpace("Go To Jail", 0.0, Double.PositiveInfinity), new BoardSpace("Pacific Avenue", 26.0, 300.0), new BoardSpace("North Carolina Avenue", 26.0, 300.0), new BoardSpace("Community Chest", 0.0, Double.PositiveInfinity), new BoardSpace("Pennsylvania Avenue", 28.0, 320.0), new BoardSpace("Short Line", 25.0, 200.0), new BoardSpace("Chance", 0.0, Double.PositiveInfinity), new BoardSpace("Park Place", 35.0, 350.0), new BoardSpace("Luxury Tax", 0.0, Double.PositiveInfinity), new BoardSpace("Boardwalk", 50.0, 400.0) }; // number of squares int n = spaces.Length; // compute the transition matrix which takes the dice roll // into account: Moves us ahead by two spaces with // probability 1/36 (“snake-eyes”), three spaces with // probability 2/36, and so on up to twelve spaces with // probability 1/36 (“double-sixes”), etc. SquareMatrix R = new SquareMatrix(n); for (int c = 0; c < n; c++) { R[(c + 2) % n, c] = 1.0 / 36.0; R[(c + 3) % n, c] = 2.0 / 36.0; R[(c + 4) % n, c] = 3.0 / 36.0; R[(c + 5) % n, c] = 4.0 / 36.0; R[(c + 6) % n, c] = 5.0 / 36.0; R[(c + 7) % n, c] = 6.0 / 36.0; R[(c + 8) % n, c] = 5.0 / 36.0; R[(c + 9) % n, c] = 4.0 / 36.0; R[(c + 10) % n, c] = 3.0 / 36.0; R[(c + 11) % n, c] = 2.0 / 36.0; R[(c + 12) % n, c] = 1.0 / 36.0; } // compute the special matrix, which takes board into account: // The column for space 30, “Go To Jail”, transitions with // certainty to space 10, the jail. // A token that lands on a community chest space sometimes // transitions to go and sometimes transitions to jail, but // most often just stays put SquareMatrix S = new SquareMatrix(n); for (int c = 0; c < n; c++) { if (c == 30) { // go to jail S[10, 30] = 1.0; } else if ((c == 7) || (c == 22) || (c == 36)) { // chance // advance to go S[0, c] = 1.0 / 16.0; // advance to illinois avenue S[24, c] = 1.0 / 16.0; // take a walk on the boardwalk S[39, c] = 1.0 / 16.0; // go to jail S[10, c] = 1.0 / 16.0; // take a ride on the reading S[5, c] = 1.0 / 16.0; // advance to St. Charles place S[11, c] = 1.0 / 16.0; // go back 3 spaces S[(c - 3) % S.Dimension, c] = 1.0 / 16.0; // advance token to the nearest utility if ((c < 12) || (c > 28)) { S[12, c] = 1.0 / 16.0; } else { S[28, c] = 1.0 / 16.0; } // advance token to the nearest railroad if (c < 5) { S[5, c] += 1.0 / 16.0; } else if (c < 15) { S[15, c] = 1.0 / 16.0; } else if (c < 25) { S[25, c] = 1.0 / 16.0; } else if (c < 35) { S[35, c] = 1.0 / 16.0; } else { S[5, c] += 1.0 / 16.0; } // stay put S[c, c] = 7.0 / 16.0; } else if ((c == 2) || (c == 17) || (c == 33)) { // community chest // advance to go S[0, c] = 1.0 / 16.0; // go to jail S[10, c] = 1.0 / 16.0; // stay put S[c, c] = 14.0 / 16.0; } else { // all other spaces are no-ops S[c, c] = 1.0; } } // compute the complete transition matrix SquareMatrix P = S * R; // verify Markov conditions for (int c = 0; c < P.Dimension; c++) { double sr = 0.0; for (int r = 0; r < P.Dimension; r++) { sr += P[r, c]; } Debug.Assert(Math.Abs(sr - 1.0) < 1.0e-15); } // An alternative now is to begin with some initial state vector // guess, and repeatedly apply P until the resultant vector // no longer changes. The resultant vector will be the dominant // eigenvector. That's how PageRank is evaluated by Google, // using MapReduce. // Another alternative is to compute the eigenvalues and // eigenvectors of the transition matrix ComplexEigensystem E = P.Eigensystem(); // get the dominant eigenvector: The one with the largest // eigenvalue Complex e = -1.0; IList <Complex> v = null; for (int i = 0; i < E.Dimension; i++) { Complex ei = E.Eigenvalue(i); if (ComplexMath.Abs(ei) > ComplexMath.Abs(e)) { e = ei; v = E.Eigenvector(i); } } // verify that it has eigenvalue 1 and is real Debug.Assert(Math.Abs(e.Re - 1.0) < 1.0e-15); Debug.Assert(e.Im == 0.0); for (int i = 0; i < n; i++) { Debug.Assert(v[i].Im == 0.0); } // normalize the probabilities double sv = 0.0; for (int i = 0; i < E.Dimension; i++) { sv += v[i].Re; } double[] p = new double[E.Dimension]; for (int i = 0; i < E.Dimension; i++) { p[i] = v[i].Re / sv; } // Having found the dominant eigenvector, we can examine its components // to find the long-run relative probabilities of a token landing on each // space. // Print the probabilities // First column: Which rent-generating properties are most landed upon // Second column: A rent-seeking player would be willing to accept a slightly // less frequently landed upon space, if it generates a much higher rent when // landed upon --> Multiply the landing probability per turn by the rent per landing // Third column: A clever investor cares not only about cash flow, but // also about the return on his investment (ROI), that is the rent generated // per dollar paid --> Divide the rent per turn by the property price for (int i = 0; i < n; i++) { Console.WriteLine("{0,-24} {1:f4} {2:f4} {3:f4}", spaces[i].Name, p[i], p[i] * spaces[i].Rent, p[i] * spaces[i].Rent / spaces[i].Price); } // First column: Which rent-generating properties are most landed upon: // Illinois Avenue (3.2%) and New York Avenue (3.1%), followed by Tennessee, the Reading, and the B & O (2.9% each). // Second column: A rent-seeking player would be willing to accept a slightly less frequently landed upon space, // if it generates a much higher rent when landed upon. To know which spaces maximize rent per turn, // we need to multiply the landing probability per turn by the rent per landing. // Boardwalk ($1.32/turn) is far and away the most rent-generating property to own // Third column: Finally, a clever investor cares not only about cash flow, but also about the return on his // investment (ROI), that is the rent generated per dollar paid. Dividing the rent per turn by // the property price changes the picture yet again. By this metric, the best values on the board // are the utilities, followed by the railways. Console.ReadLine(); }
static void Main(string[] args) { SquareMatrix T = new SquareMatrix(3); // Construct the transition matrix for the weather. T[0, 0] = 0.5; // sunny to sunny T[1, 0] = 0.4; // sunny to rainy T[2, 0] = 0.1; // sunny to cloudy T[0, 1] = 0.3; // rainy to sunny T[1, 1] = 0.4; // rainy to rainy T[2, 1] = 0.3; // rainy to cloudy T[0, 2] = 0.2; // cloudy to sunny T[1, 2] = 0.3; // cloudy to rainy T[2, 2] = 0.5; // cloudy to cloudy // verify Markov conditions for (int c = 0; c < T.Dimension; c++) { double sr = 0.0; for (int r = 0; r < T.Dimension; r++) { sr += T[r, c]; } Debug.Assert(Math.Abs(sr - 1.0) < 1.0e-15); } // Begin with some initial state vector, and repeatedly // apply P until the resultant vector no longer changes. // The resultant vector will be the dominant eigenvector. ComplexEigensystem E = T.Eigensystem(); Complex e = -1.0; IList <Complex> v = null; Complex maxEI = E.Eigenvalue(0); v = E.Eigenvector(0); // Find the dominant eigenvector for (int i = 1; i < E.Dimension; i++) { Complex ei = E.Eigenvalue(i); if (ComplexMath.Abs(ei) > ComplexMath.Abs(maxEI)) { maxEI = ei; v = E.Eigenvector(i); } } // verify that it has eigenvalue 1 and is real Debug.Assert(Math.Abs(maxEI.Re - 1.0) < 1.0e-15); Debug.Assert(maxEI.Im == 0.0); for (int i = 0; i < 3; i++) { Debug.Assert(v[i].Im == 0.0); } // normalize the probabilities double sv = 0.0; for (int i = 0; i < E.Dimension; i++) { sv += v[i].Re; } double[] p = new double[E.Dimension]; for (int i = 0; i < E.Dimension; i++) { p[i] = v[i].Re / sv; } // print the probabilities (steady state of the weather) Console.Write("Sunny = "); Console.WriteLine(p[0]); Console.Write("Rainy = "); Console.WriteLine(p[1]); Console.Write("Cloudy = "); Console.WriteLine(p[2]); Console.ReadLine(); }