1 | #region License Information |
---|
2 | /* HeuristicLab |
---|
3 | * Copyright (C) 2002-2017 Heuristic and Evolutionary Algorithms Laboratory (HEAL) |
---|
4 | * |
---|
5 | * This file is part of HeuristicLab. |
---|
6 | * |
---|
7 | * HeuristicLab is free software: you can redistribute it and/or modify |
---|
8 | * it under the terms of the GNU General Public License as published by |
---|
9 | * the Free Software Foundation, either version 3 of the License, or |
---|
10 | * (at your option) any later version. |
---|
11 | * |
---|
12 | * HeuristicLab is distributed in the hope that it will be useful, |
---|
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
15 | * GNU General Public License for more details. |
---|
16 | * |
---|
17 | * You should have received a copy of the GNU General Public License |
---|
18 | * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>. |
---|
19 | */ |
---|
20 | #endregion |
---|
21 | |
---|
22 | using System; |
---|
23 | using HeuristicLab.Data; |
---|
24 | using HeuristicLab.Encodings.IntegerVectorEncoding; |
---|
25 | using HeuristicLab.Random; |
---|
26 | using Microsoft.VisualStudio.TestTools.UnitTesting; |
---|
27 | |
---|
28 | namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment.Tests { |
---|
29 | /// <summary> |
---|
30 | ///This is a test class for GQAPNMoveEvaluatorTest and is intended |
---|
31 | ///to contain all GQAPNMoveEvaluatorTest Unit Tests |
---|
32 | ///</summary> |
---|
33 | [TestClass()] |
---|
34 | public class GQAPNMoveEvaluatorTest { |
---|
35 | private const int Equipments = 10, Locations = 5; |
---|
36 | private static GQAPInstance symmetricInstance, asymmetricInstance, nonZeroDiagonalInstance; |
---|
37 | private static IntegerVector assignment; |
---|
38 | private static MersenneTwister random; |
---|
39 | |
---|
40 | private TestContext testContextInstance; |
---|
41 | |
---|
42 | /// <summary> |
---|
43 | ///Gets or sets the test context which provides |
---|
44 | ///information about and functionality for the current test run. |
---|
45 | ///</summary> |
---|
46 | public TestContext TestContext { |
---|
47 | get { return testContextInstance; } |
---|
48 | set { testContextInstance = value; } |
---|
49 | } |
---|
50 | |
---|
51 | #region Additional test attributes |
---|
52 | [ClassInitialize()] |
---|
53 | public static void MyClassInitialize(TestContext testContext) { |
---|
54 | random = new MersenneTwister(); |
---|
55 | var symmetricDistances = new DoubleMatrix(Locations, Locations); |
---|
56 | var symmetricWeights = new DoubleMatrix(Equipments, Equipments); |
---|
57 | var asymmetricDistances = new DoubleMatrix(Locations, Locations); |
---|
58 | var asymmetricWeights = new DoubleMatrix(Equipments, Equipments); |
---|
59 | var nonZeroDiagonalDistances = new DoubleMatrix(Locations, Locations); |
---|
60 | var nonZeroDiagonalWeights = new DoubleMatrix(Equipments, Equipments); |
---|
61 | for (int i = 0; i < Equipments - 1; i++) { |
---|
62 | for (int j = i + 1; j < Equipments; j++) { |
---|
63 | symmetricWeights[i, j] = random.Next(Equipments * 100); |
---|
64 | symmetricWeights[j, i] = symmetricWeights[i, j]; |
---|
65 | asymmetricWeights[i, j] = random.Next(Equipments * 100); |
---|
66 | asymmetricWeights[j, i] = random.Next(Equipments * 100); |
---|
67 | nonZeroDiagonalWeights[i, j] = random.Next(Equipments * 100); |
---|
68 | nonZeroDiagonalWeights[j, i] = random.Next(Equipments * 100); |
---|
69 | } |
---|
70 | nonZeroDiagonalWeights[i, i] = random.Next(Equipments * 100); |
---|
71 | } |
---|
72 | for (int i = 0; i < Locations - 1; i++) { |
---|
73 | for (int j = i + 1; j < Locations; j++) { |
---|
74 | symmetricDistances[i, j] = random.Next(Locations * 100); |
---|
75 | symmetricDistances[j, i] = symmetricDistances[i, j]; |
---|
76 | asymmetricDistances[i, j] = random.Next(Locations * 100); |
---|
77 | asymmetricDistances[j, i] = random.Next(Locations * 100); |
---|
78 | nonZeroDiagonalDistances[i, j] = random.Next(Locations * 100); |
---|
79 | nonZeroDiagonalDistances[j, i] = random.Next(Locations * 100); |
---|
80 | } |
---|
81 | nonZeroDiagonalDistances[i, i] = random.Next(Locations * 100); |
---|
82 | } |
---|
83 | var installationCosts = new DoubleMatrix(Equipments, Locations); |
---|
84 | for (int i = 0; i < Equipments; i++) { |
---|
85 | for (int j = 0; j < Locations; j++) { |
---|
86 | installationCosts[i, j] = random.Next(0, 10); |
---|
87 | } |
---|
88 | } |
---|
89 | var demands = new DoubleArray(Equipments); |
---|
90 | for (int i = 0; i < Equipments; i++) { |
---|
91 | demands[i] = random.Next(1, 10); |
---|
92 | } |
---|
93 | var capacities = new DoubleArray(Locations); |
---|
94 | for (int j = 0; j < Locations; j++) { |
---|
95 | capacities[j] = random.Next(1, 10) * ((double)Equipments / (double)Locations) * 1.5; |
---|
96 | } |
---|
97 | int index = random.Next(Locations); |
---|
98 | if (nonZeroDiagonalDistances[index, index] == 0) |
---|
99 | nonZeroDiagonalDistances[index, index] = random.Next(1, Equipments * 100); |
---|
100 | index = random.Next(Equipments); |
---|
101 | if (nonZeroDiagonalWeights[index, index] == 0) |
---|
102 | nonZeroDiagonalWeights[index, index] = random.Next(1, Equipments * 100); |
---|
103 | |
---|
104 | var transportationCosts = random.NextDouble() * 10; |
---|
105 | var overbookedCapacityPenalty = 1000 * random.NextDouble() + 100; |
---|
106 | assignment = new IntegerVector(Equipments, random, 0, Locations); |
---|
107 | |
---|
108 | symmetricInstance = new GQAPInstance() { |
---|
109 | Capacities = capacities, |
---|
110 | Demands = demands, |
---|
111 | InstallationCosts = installationCosts, |
---|
112 | PenaltyLevel = overbookedCapacityPenalty, |
---|
113 | TransportationCosts = transportationCosts, |
---|
114 | Weights = symmetricWeights, |
---|
115 | Distances = symmetricDistances |
---|
116 | }; |
---|
117 | asymmetricInstance = new GQAPInstance() { |
---|
118 | Capacities = capacities, |
---|
119 | Demands = demands, |
---|
120 | InstallationCosts = installationCosts, |
---|
121 | PenaltyLevel = overbookedCapacityPenalty, |
---|
122 | TransportationCosts = transportationCosts, |
---|
123 | Weights = asymmetricWeights, |
---|
124 | Distances = asymmetricDistances |
---|
125 | }; |
---|
126 | nonZeroDiagonalInstance = new GQAPInstance() { |
---|
127 | Capacities = capacities, |
---|
128 | Demands = demands, |
---|
129 | InstallationCosts = installationCosts, |
---|
130 | PenaltyLevel = overbookedCapacityPenalty, |
---|
131 | TransportationCosts = transportationCosts, |
---|
132 | Weights = nonZeroDiagonalWeights, |
---|
133 | Distances = nonZeroDiagonalDistances |
---|
134 | }; |
---|
135 | } |
---|
136 | #endregion |
---|
137 | |
---|
138 | |
---|
139 | /// <summary> |
---|
140 | ///A test for Evaluate |
---|
141 | ///</summary> |
---|
142 | [TestMethod()] |
---|
143 | public void EvaluateTest() { |
---|
144 | for (int i = 0; i < 500; i++) { |
---|
145 | NMove currentMove = StochasticNMoveSingleMoveGenerator.GenerateUpToN(random, assignment, 3, symmetricInstance.Capacities); |
---|
146 | IntegerVector prevAssignment = (IntegerVector)assignment.Clone(); |
---|
147 | NMoveMaker.Apply(assignment, currentMove); |
---|
148 | var beforeEval = symmetricInstance.Evaluate(prevAssignment); |
---|
149 | double before = symmetricInstance.ToSingleObjective(beforeEval); |
---|
150 | double after = Evaluate(symmetricInstance, assignment); |
---|
151 | double moveDiff = symmetricInstance.ToSingleObjective( |
---|
152 | GQAPNMoveEvaluator.Evaluate(currentMove, prevAssignment, beforeEval, symmetricInstance) |
---|
153 | ) - symmetricInstance.ToSingleObjective(beforeEval); |
---|
154 | Assert.IsTrue(Math.Abs(moveDiff - (after - before)) < 1e-07, "Failed on symmetric matrices: " + Environment.NewLine |
---|
155 | + "Quality changed from " + before + " to " + after + " (" + (after - before).ToString() + "), but move quality change was " + moveDiff + "."); |
---|
156 | |
---|
157 | beforeEval = asymmetricInstance.Evaluate(prevAssignment); |
---|
158 | before = asymmetricInstance.ToSingleObjective(beforeEval); |
---|
159 | after = Evaluate(asymmetricInstance, assignment); |
---|
160 | moveDiff = asymmetricInstance.ToSingleObjective( |
---|
161 | GQAPNMoveEvaluator.Evaluate(currentMove, prevAssignment, beforeEval, asymmetricInstance) |
---|
162 | ) - asymmetricInstance.ToSingleObjective(beforeEval); |
---|
163 | Assert.IsTrue(Math.Abs(moveDiff - (after - before)) < 1e-07, "Failed on asymmetric matrices: " + Environment.NewLine |
---|
164 | + "Quality changed from " + before + " to " + after + " (" + (after - before).ToString() + "), but move quality change was " + moveDiff + "."); |
---|
165 | |
---|
166 | beforeEval = nonZeroDiagonalInstance.Evaluate(prevAssignment); |
---|
167 | before = nonZeroDiagonalInstance.ToSingleObjective(beforeEval); |
---|
168 | after = Evaluate(nonZeroDiagonalInstance, assignment); |
---|
169 | moveDiff = nonZeroDiagonalInstance.ToSingleObjective( |
---|
170 | GQAPNMoveEvaluator.Evaluate(currentMove, prevAssignment, beforeEval, nonZeroDiagonalInstance) |
---|
171 | ) - nonZeroDiagonalInstance.ToSingleObjective(beforeEval); |
---|
172 | Assert.IsTrue(Math.Abs(moveDiff - (after - before)) < 1e-07, "Failed on non-zero diagonal matrices: " + Environment.NewLine |
---|
173 | + "Quality changed from " + before + " to " + after + " (" + (after - before).ToString() + "), but move quality change was " + moveDiff + "."); |
---|
174 | } |
---|
175 | } |
---|
176 | |
---|
177 | private double Evaluate(GQAPInstance instance, IntegerVector assignment) { |
---|
178 | return instance.ToSingleObjective(instance.Evaluate(assignment)); |
---|
179 | } |
---|
180 | } |
---|
181 | } |
---|