public static IEnumerable <double> Alternating(int[,] d, Vector2[] positions, IEnumerable <double> eta) { int n = positions.Length; int nn = (n * (n - 1)) / 2; int[,] pairs1 = CreatePairs(n), pairs2 = CreatePairs(n); var rnd = new Random(); GraphIO.FYShuffle2(pairs1, rnd); GraphIO.FYShuffle2(pairs2, rnd); // relax int k = 0; foreach (double c in eta) { int[,] pairs = k++ % 2 == 0 ? pairs1 : pairs2; for (int ij = 0; ij < nn; ij++) { int i = pairs[ij, 0], j = pairs[ij, 1]; Satisfy(ref positions[i], ref positions[j], d[i, j], c); } yield return(GraphIO.CalculateStress(d, positions, n)); } }
public static IEnumerable <double> Modulo(int[,] d, Vector2[] positions, IEnumerable <double> eta) { int n = positions.Length; int nn = (n * (n - 1)) / 2; // relax int prime = 646957; int[] primitives = new int[] { 5, 6, 7, 17, 18, 20, 21, 24, 26, 28, 45, 46, 50, 53, 55, 58, 66, 68, 72, 73 }; int k = 0; foreach (double c in eta) { int primitive = primitives[k++]; int modulo = 1; for (int ij = 0; ij < prime; ij++) { modulo = (modulo * primitive) % prime; if (modulo > nn) { continue; } int idx = modulo - 1; int i = (int)((1 + Math.Sqrt(8 * idx + 1)) / 2); int j = idx - (i * (i - 1)) / 2; Satisfy(ref positions[i], ref positions[j], d[i, j], c); } yield return(GraphIO.CalculateStress(d, positions, n)); } }
public static IEnumerable <double> Indices(int[,] d, Vector2[] positions, IEnumerable <double> eta) { int n = positions.Length; var indices = new int[n]; for (int i = 0; i < n; i++) { indices[i] = i; } var rnd = new Random(); //GraphIO.FYShuffle(indices, rnd); // relax foreach (double c in eta) { GraphIO.FYShuffle(indices, rnd); for (int i = 0; i < n; i++) { for (int j = 0; j < i; j++) { Satisfy(ref positions[indices[i]], ref positions[indices[j]], d[indices[i], indices[j]], c); } } yield return(GraphIO.CalculateStress(d, positions, n)); } }
public static IEnumerable <double> Momentum(int[,] d, Vector2[] X, double eta = .1, double beta = .9, int numIterations = 15) { int n = X.Length; // relax for (int k = 0; k < numIterations; k++) { var gradients = new Vector2[n]; var momentums = new Vector2[n]; for (int i = 0; i < n; i++) { for (int j = 0; j < i; j++) { Vector2 gradient = Gradient(X[i], X[j], d[i, j]); gradients[i] += gradient; gradients[j] -= gradient; } } for (int i = 0; i < n; i++) { momentums[i] = momentums[i] * beta + gradients[i] * eta; X[i] += momentums[i]; } double stress = GraphIO.CalculateStress(d, X, n); yield return(stress); } }
public static IEnumerable <double> Convergence(int[,] d, Vector2[] positions, int expIter = 30, double eps = 0.03) { int n = positions.Length; int nn = (n * (n - 1)) / 2; var pairs = CreatePairs(n); var rnd = new Random(); double etaMax = EtaMax(d), etaMin = .1; double lambda = -Math.Log(etaMin / etaMax) / (expIter - 1); double tSwitch = Math.Log(etaMax) / lambda; int kSwitch = (int)tSwitch + 1; Console.Error.WriteLine(etaMax + " " + lambda + " " + tSwitch); for (int k = 0; k < kSwitch; k++) { GraphIO.FYShuffle2(pairs, rnd); double eta = etaMax * Math.Exp(-lambda * k); for (int ij = 0; ij < nn; ij++) { int i = pairs[ij, 0], j = pairs[ij, 1]; Satisfy(ref positions[i], ref positions[j], d[i, j], eta); } //Console.Error.WriteLine(" " + eta); double stress = GraphIO.CalculateStress(d, positions, n); yield return(stress); } for (int k = kSwitch; k < 1000; k++) { double maxMovement = 0; GraphIO.FYShuffle2(pairs, rnd); double eta = 1.0 / (1 + lambda * (k - tSwitch)); for (int ij = 0; ij < nn; ij++) { int i = pairs[ij, 0], j = pairs[ij, 1]; double r = Satisfy(ref positions[i], ref positions[j], d[i, j], eta); r = Math.Abs(r); //r = r * r; if (r > maxMovement) { maxMovement = r; } } //Console.Error.WriteLine(" " + eta + " " + maxMovement); double stress = GraphIO.CalculateStress(d, positions, n); yield return(stress); if (maxMovement < eps) { yield break; } } }
public static IEnumerable <double> NoRand(int[,] d, Vector2[] positions, IEnumerable <double> eta) { int n = positions.Length; // relax foreach (double c in eta) { for (int i = 0; i < n; i++) { for (int j = 0; j < i; j++) { Satisfy(ref positions[i], ref positions[j], d[i, j], c); } } yield return(GraphIO.CalculateStress(d, positions, n)); } }
public static IEnumerable <double> Local(int[,] d, Vector2[] positions, double eps = 0.0001, int maxIter = 100) { int n = positions.Length; double prevStress = GraphIO.CalculateStress(d, positions, n); // majorize for (int k = 0; k < maxIter; k++) { for (int i = 0; i < n; i++) { double topSumX = 0, topSumY = 0, botSum = 0; for (int j = 0; j < n; j++) { if (i != j) { double d_ij = d[i, j]; double w_ij = 1 / (d_ij * d_ij); double magnitude = (positions[i] - positions[j]).Magnitude(); topSumX += w_ij * (positions[j].x + d_ij * (positions[i].x - positions[j].x) / (magnitude)); topSumY += w_ij * (positions[j].y + d_ij * (positions[i].y - positions[j].y) / (magnitude)); botSum += w_ij; } } double newX = topSumX / botSum; double newY = topSumY / botSum; positions[i] = new Vector2(newX, newY); } double stress = GraphIO.CalculateStress(d, positions, n); yield return(stress); if ((prevStress - stress) / prevStress < eps) { yield break; } prevStress = stress; } }
public static IEnumerable <double> Full(int[,] d, Vector2[] positions, IEnumerable <double> eta) { int n = positions.Length; int nn = (n * (n - 1)) / 2; var pairs = CreatePairs(n); var rnd = new Random(); // relax foreach (double c in eta) { GraphIO.FYShuffle2(pairs, rnd); for (int ij = 0; ij < nn; ij++) { int i = pairs[ij, 0], j = pairs[ij, 1]; Satisfy(ref positions[i], ref positions[j], d[i, j], c); } double stress = GraphIO.CalculateStress(d, positions, n); yield return(stress); } }
public static IEnumerable <double> EveryPair(int[,] d, Vector2[] positions, IEnumerable <double> eta) { int n = positions.Length; int nn = (n * (n - 1)) / 2; var rnd = new Random(); //var indices = CreatePairs(n); // relax foreach (double c in eta) { for (int ij = 0; ij < nn; ij++) { int idx = rnd.Next(nn); int i = (int)((1 + Math.Sqrt(8 * idx + 1)) / 2); int j = idx - (i * (i - 1)) / 2; //int i = indices[idx, 0], j = indices[idx, 1]; Satisfy(ref positions[i], ref positions[j], d[i, j], c); } yield return(GraphIO.CalculateStress(d, positions, n)); } }
public static IEnumerable <double> Conj(int[,] d, Vector2[] positions, double eps = 0.0001, int maxIter = 1000) { int n = positions.Length; // first find the laplacian for the left hand side var laplacian_w = new double[n, n]; Majorization.WeightLaplacian(d, laplacian_w, n); // cut out the first row and column var Lw = new double[n - 1, n - 1]; for (int i = 1; i < n; i++) { for (int j = 1; j < n; j++) { Lw[i - 1, j - 1] = laplacian_w[i, j]; } } // delta = w_ij * d_ij as in Majorization, Gansner et al. var deltas = new double[n, n]; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { double dist = d[i, j]; deltas[i, j] = 1.0 / dist; } } var LXt = new double[n, n]; // the laplacian for the right hand side var LXt_Xt = new double[n - 1]; // skip the first position as it's fixed to (0,0) var Xt1 = new double[n - 1]; // X(t+1) // temporary variables to speed up conjugate gradient var r = new double[n - 1]; var p = new double[n - 1]; var Ap = new double[n - 1]; double prevStress = GraphIO.CalculateStress(d, positions, n); // majorize for (int k = 0; k < maxIter; k++) { PositionLaplacian(deltas, positions, LXt, n); // solve for x axis Multiply_x(LXt, positions, LXt_Xt); ConjugateGradient.Cg(Lw, Xt1, LXt_Xt, r, p, Ap, .1, 10); for (int i = 1; i < n; i++) { positions[i].x = Xt1[i - 1]; } // solve for y axis Multiply_y(LXt, positions, LXt_Xt); ConjugateGradient.Cg(Lw, Xt1, LXt_Xt, r, p, Ap, .1, 10); for (int i = 1; i < n; i++) { positions[i].y = Xt1[i - 1]; } double stress = GraphIO.CalculateStress(d, positions, n); yield return(stress); if ((prevStress - stress) / prevStress < eps) { yield break; } prevStress = stress; } }
public static IEnumerable <double> Chol(int[,] d, Vector2[] positions, double eps = 0.0001, int maxIter = 1000) { int n = positions.Length; // first find the laplacian for the left hand side var laplacian_w = new double[n, n]; WeightLaplacian(d, laplacian_w, n); // cut out the first row and column var cholesky_Lw = new double[n - 1, n - 1]; for (int i = 1; i < n; i++) { for (int j = 1; j < n; j++) { cholesky_Lw[i - 1, j - 1] = laplacian_w[i, j]; } } // p used to store diagonal values, as in Numerical Recipes var cholesky_p = new double[n - 1]; Cholesky.Choldc(cholesky_Lw, cholesky_p); // delta = w_ij * d_ij as in Majorization, Gansner et al. var deltas = new double[n, n]; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { double dist = d[i, j]; deltas[i, j] = 1.0 / dist; } } var LXt = new double[n, n]; // the laplacian for the right hand side var LXt_Xt = new double[n - 1]; // skip the first position as it's fixed to (0,0) var Xt1 = new double[n - 1]; // X(t+1) double prevStress = GraphIO.CalculateStress(d, positions, n); // majorize for (int k = 0; k < maxIter; k++) { PositionLaplacian(deltas, positions, LXt, n); // solve for x axis Multiply_x(LXt, positions, LXt_Xt); Cholesky.BackSubstitution(cholesky_Lw, cholesky_p, LXt_Xt, Xt1); for (int i = 1; i < n; i++) { positions[i].x = Xt1[i - 1]; } // solve for y axis Multiply_y(LXt, positions, LXt_Xt); Cholesky.BackSubstitution(cholesky_Lw, cholesky_p, LXt_Xt, Xt1); for (int i = 1; i < n; i++) { positions[i].y = Xt1[i - 1]; } double stress = GraphIO.CalculateStress(d, positions, n); yield return(stress); if ((prevStress - stress) / prevStress < eps) { yield break; } prevStress = stress; } }