Free cookie consent management tool by TermsFeed Policy Generator

Ignore:
Timestamp:
03/10/11 01:49:10 (13 years ago)
Author:
abeham
Message:

#1330

  • Unified QAP visualization in solution and problem view
  • Fixed bug in gradient-descent gradient calculation when performing multidimensional scaling
  • Extended QAPLIB parsers to cover some file format variations
  • Added unit tests to check if all QAPLIB instances import without error
  • Changed BestKnownSolution to be an OptionalValueParameter
Location:
branches/QAP
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • branches/QAP

    • Property svn:ignore
      •  

        old new  
        11*.suo
         2TestResults
  • branches/QAP/HeuristicLab.Problems.QuadraticAssignment.Views/3.3/MultidimensionalScaling.cs

    r5641 r5648  
    2323using HeuristicLab.Data;
    2424
    25 namespace HeuristicLab.Problems.QuadraticAssignment {
     25namespace HeuristicLab.Problems.QuadraticAssignment.Views {
    2626  public static class MultidimensionalScaling {
    27 
    28     public static DoubleMatrix Classic(DoubleMatrix distances, out double error) {
    29       if (distances == null) throw new ArgumentNullException("distances");
    30       if (distances.Rows != distances.Columns) throw new ArgumentException("Distance matrix must be a square matrix.", "distances");
    31       error = 0.0;
    32 
    33       int dimension = distances.Rows;
    34       if (dimension == 1) return new DoubleMatrix(new double[,] { { 0, 0 } });
    35       else if (dimension == 2) return new DoubleMatrix(new double[,] { { 0, distances[0, 1] } });
    36 
    37       double[,] A = new double[dimension + 1, dimension + 1];
    38       for (int i = 1; i < dimension; i++) {
    39         for (int j = i + 1; j < dimension + 1; j++) {
    40           A[i, j] = -0.5 * distances[i - 1, j - 1] * distances[i - 1, j - 1];
    41           A[j, i] = A[i, j];
    42           A[0, 0] += A[i, j] / (dimension * dimension);
    43           double avg = A[i, j] / (double)dimension;
    44           A[0, j] += avg;
    45           A[0, i] += avg;
    46           A[i, 0] += avg;
    47           A[j, 0] += avg;
    48         }
    49       }
    50       double[,] B = new double[dimension, dimension];
    51       for (int i = 0; i < dimension - 1; i++) {
    52         for (int j = i + 1; j < dimension; j++) {
    53           B[i, j] = A[i + 1, j + 1] - A[0, j + 1] - A[i + 1, 0] + A[0, 0];
    54         }
    55       }
    56       double[] eigenvalues;
    57       double[,] eigenvectors;
    58       alglib.smatrixevd(B, dimension, 1, true, out eigenvalues, out eigenvectors);
    59 
    60       DoubleMatrix coordinates = new DoubleMatrix(dimension, 2);
    61       for (int i = 0; i < dimension; i++) {
    62         for (int j = 0; j < dimension; j++) {
    63           coordinates[i, 0] += eigenvectors[eigenvectors.GetLength(0) - 1, j]
    64                              * distances[i, j];
    65           coordinates[i, 1] += eigenvectors[eigenvectors.GetLength(0) - 2, j]
    66                              * distances[i, j];
    67         }
    68       }
    69 
    70       return coordinates;
    71     }
    7227
    7328    /// <summary>
     
    7732    /// </summary>
    7833    /// <param name="distances">A symmetric NxN matrix that specifies the distances between each element i and j. Diagonal elements are ignored.</param>
    79     /// <param name="error">Returns the error between the fit distances and the actual distances.</param>
     34    /// <param name="stress">Returns the stress between the fit distances and the actual distances.</param>
    8035    /// <returns>A Nx2 matrix where the first column represents the x- and the second column the y coordinates.</returns>
    81     public static DoubleMatrix Metric(DoubleMatrix distances, out double error) {
     36    public static DoubleMatrix MetricByDistance(DoubleMatrix distances, out double stress) {
    8237      if (distances == null) throw new ArgumentNullException("distances");
    8338      if (distances.Rows != distances.Columns) throw new ArgumentException("Distance matrix must be a square matrix.", "distances");
    84       error = 0.0;
     39      stress = 0.0;
    8540
    8641      int dimension = distances.Rows;
     
    9449        coordinates[i, 1] = 10 * Math.Sin(rad * i);
    9550      }
    96       double epsg = 0.0000000001;
     51
     52      double epsg = 1e-7;
    9753      double epsf = 0;
    9854      double epsx = 0;
    99       int maxits = 1000;
     55      int maxits = 0;
    10056      alglib.mincgstate state = null;
    10157      alglib.mincgreport rep;
    10258
    103       for (int iterations = 0; iterations < 200; iterations++) {
     59      for (int iterations = 0; iterations < 10; iterations++) {
    10460        for (int i = 0; i < dimension; i++) {
    10561          double[] c = new double[] { coordinates[i, 0], coordinates[i, 1] };
     
    11167            alglib.mincgrestartfrom(state, c);
    11268          }
    113           alglib.mincgoptimize(state, func, null, new Info(coordinates, distances, i));
     69          alglib.mincgoptimize(state, StressGradient, null, new Info(coordinates, distances, i));
    11470          alglib.mincgresults(state, out c, out rep);
    11571
     
    11874        }
    11975      }
    120       error = 0;
     76      stress = CalculateNormalizedStress(dimension, distances, coordinates);
     77      return coordinates;
     78    }
     79
     80    private static void StressGradient(double[] x, ref double func, double[] grad, object obj) {
     81      func = 0; grad[0] = 0; grad[1] = 0;
     82      Info info = (obj as Info);
     83      for (int i = 0; i < info.Coordinates.Rows; i++) {
     84        double c = info.Distances[info.Row, i];
     85        if (i != info.Row) {
     86          double a = info.Coordinates[i, 0];
     87          double b = info.Coordinates[i, 1];
     88          func += Stress(x, c, a, b);
     89          grad[0] += ((2 * x[0] - 2 * a) * Math.Sqrt(x[1] * x[1] - 2 * b * x[1] + x[0] * x[0] - 2 * a * x[0] + b * b + a * a) - 2 * c * x[0] + 2 * a * c) / Math.Sqrt(x[1] * x[1] - 2 * b * x[1] + x[0] * x[0] - 2 * a * x[0] + b * b + a * a);
     90          grad[1] += ((2 * x[1] - 2 * b) * Math.Sqrt(x[1] * x[1] - 2 * b * x[1] + x[0] * x[0] - 2 * a * x[0] + b * b + a * a) - 2 * c * x[1] + 2 * b * c) / Math.Sqrt(x[1] * x[1] - 2 * b * x[1] + x[0] * x[0] - 2 * a * x[0] + b * b + a * a);
     91        }
     92      }
     93    }
     94
     95    private static double Stress(double[] x, double distance, double xCoord, double yCoord) {
     96      return Stress(x[0], x[1], distance, xCoord, yCoord);
     97    }
     98
     99    private static double Stress(double x, double y, double distance, double otherX, double otherY) {
     100      double d = Math.Sqrt((x - otherX) * (x - otherX)
     101                         + (y - otherY) * (y - otherY));
     102      return (d - distance) * (d - distance);
     103    }
     104
     105    public static double CalculateNormalizedStress(int dimension, DoubleMatrix distances, DoubleMatrix coordinates) {
     106      double stress = 0;
    121107      for (int i = 0; i < dimension - 1; i++) {
    122108        for (int j = i + 1; j < dimension; j++) {
    123109          if (distances[i, j] != 0) {
    124             double dx = coordinates[i, 0] - coordinates[j, 0];
    125             double dy = coordinates[i, 1] - coordinates[j, 1];
    126             double d = Math.Sqrt(dx * dx + dy * dy);
    127             error += ((distances[i, j] - d) * (distances[i, j] - d)) / (distances[i, j] * distances[i, j]);
     110            stress += Stress(coordinates[i, 0], coordinates[i, 1], distances[i, j], coordinates[j, 0], coordinates[j, 1])
     111              / (distances[i, j] * distances[i, j]);
    128112          }
    129113        }
    130114      }
    131       return coordinates;
    132     }
    133 
    134     public static void func(double[] x, ref double func, double[] grad, object obj) {
    135       func = 0; grad[0] = 0; grad[1] = 0;
    136       Info info = (obj as Info);
    137       for (int i = 0; i < x.Length; i++) {
    138         if (i != info.Row) {
    139           double d = (x[0] - info.Coordinates[i, 0])
    140                    * (x[0] - info.Coordinates[i, 0])
    141                    + (x[1] - info.Coordinates[i, 1])
    142                    * (x[1] - info.Coordinates[i, 1]);
    143           func += (d - info.Distances[info.Row, i]) * (d - info.Distances[info.Row, i]);
    144           grad[0] += 2 * x[0] - 2 * info.Coordinates[i, 0];
    145           grad[1] += 2 * x[1] - 2 * info.Coordinates[i, 1];
    146         }
    147       }
     115      return stress;
    148116    }
    149117
Note: See TracChangeset for help on using the changeset viewer.