1 | package geniusweb.ip.ipSolver;
|
---|
2 |
|
---|
3 | import geniusweb.ip.general.Combinations;
|
---|
4 | import geniusweb.ip.general.ElementOfMultiset;
|
---|
5 | import geniusweb.ip.general.General;
|
---|
6 | import geniusweb.ip.general.IntegerPartition;
|
---|
7 | import geniusweb.ip.general.SubsetsOfMultiset;
|
---|
8 | import geniusweb.ip.inputOutput.Input;
|
---|
9 | import geniusweb.ip.inputOutput.Output;
|
---|
10 | import geniusweb.ip.inputOutput.SolverNames;
|
---|
11 | import geniusweb.ip.mainSolver.Result;
|
---|
12 |
|
---|
13 | public class IPSolver {
|
---|
14 | /**
|
---|
15 | * the IP algorithm.
|
---|
16 | */
|
---|
17 | public void solve(Input input, Output output, Result result) {
|
---|
18 | // Initialization
|
---|
19 | int numOfAgents = input.numOfAgents;
|
---|
20 | result.initialize();
|
---|
21 |
|
---|
22 | // Find the best CS in the first & last Levels of the Integer Partition
|
---|
23 | // Graph
|
---|
24 | searchFirstAndLastLevel(input, result);
|
---|
25 |
|
---|
26 | // Calculate the average of the values of coalitions of size:
|
---|
27 | // s=1,2,...,numOfAgents.
|
---|
28 | // While doing this, search the second level of the integer partition
|
---|
29 | // graph. Also, if required,
|
---|
30 | // search the side subspaces of levels 3,4,...,numOfAgents-1 (e.g. the
|
---|
31 | // subspace [5,1,1,...,1])
|
---|
32 | double[] avgValueForEachSize = new double[numOfAgents];
|
---|
33 | MethodsForScanningTheInput.scanTheInputAndComputeAverage(input, output,
|
---|
34 | result, avgValueForEachSize);
|
---|
35 |
|
---|
36 | // Calculate the highest value, 2nd highest, 3rd highest, and so on, as
|
---|
37 | // long as this is useful
|
---|
38 | // (e.g. given 15 agents, for the coalitions of size 4, we only need to
|
---|
39 | // calculate the highest
|
---|
40 | // 3 values since it is not possible to have more than 3 fours in a
|
---|
41 | // single integer partition
|
---|
42 | double[][] maxValueForEachSize = setMaxValueForEachSize(input);
|
---|
43 |
|
---|
44 | // Create the integer partition graph
|
---|
45 | Subspace[][] subspaces = initSubspaces(avgValueForEachSize,
|
---|
46 | maxValueForEachSize, input);
|
---|
47 | if (input.solverName == SolverNames.ODPIP)
|
---|
48 | result.ipIntegerPartitionGraph = new IntegerPartitionGraph(
|
---|
49 | subspaces, input.numOfAgents, 1);
|
---|
50 | else
|
---|
51 | result.ipIntegerPartitionGraph = new IntegerPartitionGraph(
|
---|
52 | subspaces, input.numOfAgents,
|
---|
53 | ((int) Math.floor(2 * input.numOfAgents / (double) 3)));
|
---|
54 |
|
---|
55 | result.totalNumOfExpansions = computeTotalNumOfExpansions(result);
|
---|
56 |
|
---|
57 | // create subspaces, and calculate their bounds, average values, and
|
---|
58 | // size. Also compute
|
---|
59 | // the overall upper and lower bounds on the value of the optimal
|
---|
60 | // coalition structure
|
---|
61 | long numOfRemainingSubspaces = IntegerPartition
|
---|
62 | .getNumOfIntegerPartitions(numOfAgents);
|
---|
63 | numOfRemainingSubspaces -= disableSubspacesThatWereSearchedWhileScanningTheInput(
|
---|
64 | result, input);
|
---|
65 |
|
---|
66 | // Set the upper and lower bounds on the value of the optimal coalition
|
---|
67 | // structure
|
---|
68 | setUpperAndLowerBoundsOnOptimalValue(input, result);
|
---|
69 |
|
---|
70 | // Disable subspaces based on their bounds
|
---|
71 | numOfRemainingSubspaces -= disableSubspacesWithUBLowerThanTheHighestLB(
|
---|
72 | input, output, result);
|
---|
73 |
|
---|
74 | // Print the size, upperBound, and lowerBound for each subspace
|
---|
75 | output.printDetailsOfSubspaces(input, result);
|
---|
76 |
|
---|
77 | // If there are no more subspaces to be searched, then...
|
---|
78 | if (numOfRemainingSubspaces == 0) {
|
---|
79 | finalize(result, input, output);
|
---|
80 | return;
|
---|
81 | }
|
---|
82 | // Initialize the table used in the technique called: "Branch and bound
|
---|
83 | // in opposite direction"
|
---|
84 | result.idpSolver_whenRunning_ODPIP = null;
|
---|
85 | if (input.solverName == SolverNames.ODPIP) {
|
---|
86 | result.idpSolver_whenRunning_ODPIP = new IDPSolver_whenRunning_ODPIP(
|
---|
87 | input, result);
|
---|
88 | result.idpSolver_whenRunning_ODPIP
|
---|
89 | .initValueOfBestPartitionFound(input, maxValueForEachSize);
|
---|
90 | result.idpSolver_whenRunning_ODPIP.start();
|
---|
91 | }
|
---|
92 | // Calculate the value which, if found, causes the search to stop:
|
---|
93 | double acceptableValue = result.ipUpperBoundOnOptimalValue
|
---|
94 | * input.acceptableRatio / 100;
|
---|
95 |
|
---|
96 | if (input.pruneSubspaces == false)
|
---|
97 | acceptableValue = Double.MAX_VALUE;
|
---|
98 |
|
---|
99 | // Assign to each subspace a priority based on the subspace-selection
|
---|
100 | // function, and then sort them based on priorities
|
---|
101 | Node[] sortedNodes = getListOfSortedNodes(subspaces, input, result);
|
---|
102 |
|
---|
103 | // Check whether the current LB of the optimal is within the acceptable
|
---|
104 | // bound...
|
---|
105 | while ((result.ipLowerBoundOnOptimalValue) < acceptableValue) {
|
---|
106 | // Update the integer partition graph based on the max size that was
|
---|
107 | // completed by IDP so far
|
---|
108 | if (input.solverName == SolverNames.ODPIP)
|
---|
109 | result.ipIntegerPartitionGraph.updateEdges(input.numOfAgents,
|
---|
110 | result.get_dpMaxSizeThatWasComputedSoFar());
|
---|
111 |
|
---|
112 | // disable any subspaces that are reachable from the bottom node
|
---|
113 | if (input.solverName == SolverNames.ODPIP)
|
---|
114 | numOfRemainingSubspaces -= disableSubspacesReachableFromBottomNode(
|
---|
115 | input, result);
|
---|
116 |
|
---|
117 | // Select the subspace to be searched:
|
---|
118 | Node nodeToBeSearched = getFirstEnabledNode(sortedNodes);
|
---|
119 | if (nodeToBeSearched == null)
|
---|
120 | break;
|
---|
121 |
|
---|
122 | // if IP is helping DP, then we need to group certain integers
|
---|
123 | // (depending on the size for which DP has finished computing)\
|
---|
124 | ElementOfMultiset[] subsetToBePutAtTheBeginning = getRelevantNodes(
|
---|
125 | nodeToBeSearched, input, result, 1);
|
---|
126 |
|
---|
127 | // Place the best subset at the beginning of the node's
|
---|
128 | // subspace.integers.
|
---|
129 | putSubsetAtTheBeginning(nodeToBeSearched,
|
---|
130 | subsetToBePutAtTheBeginning, input);
|
---|
131 |
|
---|
132 | // Compute the upper bounds that are used in the branch-and-bound
|
---|
133 | // formula\
|
---|
134 | double[] sumOfMax = computeSumOfMax_splitOneInteger(
|
---|
135 | nodeToBeSearched, maxValueForEachSize, input, result);
|
---|
136 |
|
---|
137 | // search the subspace
|
---|
138 | int numOfIntegersToSplit = 0;
|
---|
139 | if ((input.solverName == SolverNames.ODPIP)
|
---|
140 | && (subsetToBePutAtTheBeginning != null))
|
---|
141 | numOfIntegersToSplit = nodeToBeSearched.subspace.integers.length
|
---|
142 | - General.getCardinalityOfMultiset(
|
---|
143 | subsetToBePutAtTheBeginning);
|
---|
144 | numOfRemainingSubspaces -= nodeToBeSearched.subspace.search(input,
|
---|
145 | output, result, acceptableValue, avgValueForEachSize,
|
---|
146 | sumOfMax, numOfIntegersToSplit);
|
---|
147 |
|
---|
148 | // update the upper bound on the optimal CS, as well as the
|
---|
149 | // acceptable value
|
---|
150 | setUpperAndLowerBoundsOnOptimalValue(input, result);
|
---|
151 | acceptableValue = result.ipUpperBoundOnOptimalValue
|
---|
152 | * input.acceptableRatio / 100;
|
---|
153 | if (input.pruneSubspaces == false)
|
---|
154 | acceptableValue = Double.MAX_VALUE;
|
---|
155 |
|
---|
156 | // update the lower bound on the optimal CS
|
---|
157 | if (result.ipLowerBoundOnOptimalValue < result
|
---|
158 | .get_ipValueOfBestCSFound()) {
|
---|
159 | result.ipLowerBoundOnOptimalValue = result
|
---|
160 | .get_ipValueOfBestCSFound();
|
---|
161 | numOfRemainingSubspaces -= disableSubspacesWithUBLowerThanTheHighestLB(
|
---|
162 | input, output, result);
|
---|
163 | }
|
---|
164 | // If there are no more subspaces to be searched, or if we found a
|
---|
165 | // good enough value, then...
|
---|
166 | if ((numOfRemainingSubspaces == 0)
|
---|
167 | || ((input.solverName == SolverNames.ODPIP) && (result
|
---|
168 | .get_dpMaxSizeThatWasComputedSoFar() >= ((int) Math
|
---|
169 | .floor(2 * input.numOfAgents
|
---|
170 | / (double) 3))))) {
|
---|
171 | break;
|
---|
172 | }
|
---|
173 | }
|
---|
174 | // prepare final result of IP before terminating
|
---|
175 | finalize(result, input, output);
|
---|
176 | if (result.idpSolver_whenRunning_ODPIP != null)
|
---|
177 | result.idpSolver_whenRunning_ODPIP.setStop(true);
|
---|
178 | }
|
---|
179 |
|
---|
180 | // *****************************************************************************************************
|
---|
181 |
|
---|
182 | /**
|
---|
183 | * Disable any subspaces that are reachable from the bottom node, using only
|
---|
184 | * the movements that have been evaluated by IDP so far.
|
---|
185 | *
|
---|
186 | * Returns the number of subspaces that it pruned.
|
---|
187 | */
|
---|
188 | private long disableSubspacesReachableFromBottomNode(Input input,
|
---|
189 | Result result) {
|
---|
190 | Node bottomNode = result.ipIntegerPartitionGraph.nodes[0][0];
|
---|
191 |
|
---|
192 | // get the list of nodes that are reachable from the bottom node.
|
---|
193 | Node[] reachableNodes = result.ipIntegerPartitionGraph
|
---|
194 | .getReachableNodes(bottomNode);
|
---|
195 |
|
---|
196 | // disable all those nodes
|
---|
197 | int numOfDisabledNodes = 0;
|
---|
198 | if (reachableNodes != null)
|
---|
199 | for (int i = 0; i < reachableNodes.length; i++)
|
---|
200 | if (reachableNodes[i].subspace.enabled) {
|
---|
201 | reachableNodes[i].subspace.enabled = false;
|
---|
202 | // System.out.println(input.problemID+" - &&&&&& IDP pruned
|
---|
203 | // the subspace
|
---|
204 | // "+General.convertArrayToString(reachableNodes[i].subspace.integersSortedAscendingly));
|
---|
205 | numOfDisabledNodes++;
|
---|
206 | }
|
---|
207 | return (numOfDisabledNodes);
|
---|
208 | }
|
---|
209 |
|
---|
210 | // *****************************************************************************************************
|
---|
211 |
|
---|
212 | /**
|
---|
213 | * Prepare the final result of IP before terminating
|
---|
214 | */
|
---|
215 | private void finalize(Result result, Input input, Output output) {
|
---|
216 | if (input.solverName == SolverNames.ODPIP) {
|
---|
217 | if (result.get_dpBestCSFound() != null)
|
---|
218 | result.updateIPSolution(result.get_dpBestCSFound(),
|
---|
219 | result.get_dpValueOfBestCSFound());
|
---|
220 | }
|
---|
221 | result.ipTime = System.currentTimeMillis() - result.ipStartTime;
|
---|
222 | output.emptyStringBufferContentsIntoOutputFiles(input);
|
---|
223 | output.printFinalResultsOfIPToFiles(input, result);
|
---|
224 | }
|
---|
225 |
|
---|
226 | // *****************************************************************************************************
|
---|
227 |
|
---|
228 | /**
|
---|
229 | * Finds the best out of the first and the last level of the Integer
|
---|
230 | * partition graph
|
---|
231 | */
|
---|
232 | private void searchFirstAndLastLevel(Input input, Result result) {
|
---|
233 | int numOfAgents = input.numOfAgents;
|
---|
234 | boolean CS1IsFeasible = true;
|
---|
235 | boolean CS2IsFeasible = true;
|
---|
236 |
|
---|
237 | // Calculate the value of the coalition structure that is made of
|
---|
238 | // singletons
|
---|
239 | int[][] CS1 = new int[numOfAgents][1];
|
---|
240 | for (int i = 0; i <= numOfAgents - 1; i++)
|
---|
241 | CS1[i][0] = i + 1;
|
---|
242 |
|
---|
243 | // Calculate the value of the coalition structure that contains the
|
---|
244 | // grand coalition
|
---|
245 | int[][] CS2 = new int[1][numOfAgents];
|
---|
246 | for (int i = 0; i <= numOfAgents - 1; i++)
|
---|
247 | CS2[0][i] = i + 1;
|
---|
248 |
|
---|
249 | if (input.feasibleCoalitions != null) {
|
---|
250 | // Check whether CS1 is feasible
|
---|
251 | for (int i = 0; i < CS1.length; i++) {
|
---|
252 | int curCoalitionInBitFormat = Combinations
|
---|
253 | .convertCombinationFromByteToBitFormat(CS1[i]);
|
---|
254 | if (input.feasibleCoalitions
|
---|
255 | .contains(curCoalitionInBitFormat) == false) {
|
---|
256 | CS1IsFeasible = false;
|
---|
257 | break;
|
---|
258 | }
|
---|
259 | }
|
---|
260 | // Check whether CS2 is feasible
|
---|
261 | for (int i = 0; i < CS2.length; i++) {
|
---|
262 | int curCoalitionInBitFormat = Combinations
|
---|
263 | .convertCombinationFromByteToBitFormat(CS2[i]);
|
---|
264 | if (input.feasibleCoalitions
|
---|
265 | .contains(curCoalitionInBitFormat) == false) {
|
---|
266 | CS2IsFeasible = false;
|
---|
267 | break;
|
---|
268 | }
|
---|
269 | }
|
---|
270 | }
|
---|
271 | // Compute the values of CS1 and CS2
|
---|
272 | double valueOfCS1 = input.getCoalitionStructureValue(CS1);
|
---|
273 | double valueOfCS2 = input.getCoalitionStructureValue(CS2);
|
---|
274 |
|
---|
275 | // Compare the two values
|
---|
276 | if (((CS1IsFeasible) && (CS2IsFeasible == false)) || ((CS1IsFeasible)
|
---|
277 | && (CS2IsFeasible) && (valueOfCS1 >= valueOfCS2))) {
|
---|
278 | result.updateIPSolution(CS1, valueOfCS1);
|
---|
279 | }
|
---|
280 | if (((CS2IsFeasible) && (CS1IsFeasible == false)) || ((CS2IsFeasible)
|
---|
281 | && (CS1IsFeasible) && (valueOfCS2 >= valueOfCS1))) {
|
---|
282 | result.updateIPSolution(CS2, valueOfCS2);
|
---|
283 | }
|
---|
284 | }
|
---|
285 |
|
---|
286 | // ******************************************************************************************************
|
---|
287 |
|
---|
288 | /**
|
---|
289 | * create subspaces, and calculate their bounds, average values, and size.
|
---|
290 | * Also compute the overall upper and lower bounds on the value of the
|
---|
291 | * optimal coalition structure
|
---|
292 | */
|
---|
293 | private Subspace[][] initSubspaces(double[] avgValueForEachSize,
|
---|
294 | double[][] maxValueForEachSize, Input input) {
|
---|
295 | // Generate all integer partitions
|
---|
296 | int[][][] integers = IntegerPartition.getIntegerPartitions(
|
---|
297 | input.numOfAgents, input.orderIntegerPartitionsAscendingly);
|
---|
298 |
|
---|
299 | // Initialize all subspaces and compute the upper and lower bounds on
|
---|
300 | // the optimal value
|
---|
301 | Subspace[][] subspaces = new Subspace[integers.length][];
|
---|
302 | for (int level = 0; level < input.numOfAgents; level++) {
|
---|
303 | subspaces[level] = new Subspace[integers[level].length];
|
---|
304 | for (int i = 0; i < integers[level].length; i++) {
|
---|
305 | subspaces[level][i] = new Subspace(integers[level][i],
|
---|
306 | avgValueForEachSize, maxValueForEachSize, input);
|
---|
307 | }
|
---|
308 | }
|
---|
309 | return (subspaces);
|
---|
310 | }
|
---|
311 |
|
---|
312 | // ******************************************************************************************************
|
---|
313 |
|
---|
314 | /**
|
---|
315 | * For any subspace "S", set "S.enabled" to "false" if it has been searched
|
---|
316 | * while scanning the input
|
---|
317 | */
|
---|
318 | private long disableSubspacesThatWereSearchedWhileScanningTheInput(
|
---|
319 | Result result, Input input) {
|
---|
320 | Node[][] nodes = result.ipIntegerPartitionGraph.nodes;
|
---|
321 | long numOfSubspacesThatThisMethodHasDisabled = 0;
|
---|
322 | for (int level = 0; level < nodes.length; level++) {
|
---|
323 | for (int i = 0; i < nodes[level].length; i++) {
|
---|
324 | Subspace curSubspace = nodes[level][i].subspace;
|
---|
325 | // identify whether the current integer partition is of size "1"
|
---|
326 | // or "2" or "numOfAgents"
|
---|
327 | if ((level == 0) || (level == 1)
|
---|
328 | || (level == (input.numOfAgents - 1))) {
|
---|
329 | if (curSubspace.enabled) {
|
---|
330 | curSubspace.enabled = false;
|
---|
331 | numOfSubspacesThatThisMethodHasDisabled++;
|
---|
332 | }
|
---|
333 | }
|
---|
334 | }
|
---|
335 | }
|
---|
336 | return (numOfSubspacesThatThisMethodHasDisabled);
|
---|
337 | }
|
---|
338 |
|
---|
339 | // ******************************************************************************************************
|
---|
340 |
|
---|
341 | /**
|
---|
342 | * Calculate the highest value, 2nd highest, 3rd highest, and so on, as long
|
---|
343 | * as this is useful (e.g. given 15 agents, for the coalitions of size 4, we
|
---|
344 | * only need to calculate the highest 3 values since it is not possible to
|
---|
345 | * have more than 3 fours in a single integer partition
|
---|
346 | */
|
---|
347 | private double[][] setMaxValueForEachSize(Input input) {
|
---|
348 | // Initialization
|
---|
349 | int numOfAgents = input.numOfAgents;
|
---|
350 | int[] numOfRequiredMaxValues = new int[numOfAgents];
|
---|
351 | long[] numOfCoalitions = new long[numOfAgents];
|
---|
352 | double[][] maxValue = new double[numOfAgents][];
|
---|
353 | for (int size = 1; size <= numOfAgents; size++) {
|
---|
354 | numOfRequiredMaxValues[size - 1] = (int) Math
|
---|
355 | .floor(numOfAgents / (double) size);
|
---|
356 | numOfCoalitions[size - 1] = Combinations
|
---|
357 | .binomialCoefficient(numOfAgents, size);
|
---|
358 | maxValue[size - 1] = new double[numOfRequiredMaxValues[size - 1]];
|
---|
359 | for (int i = 0; i < maxValue[size - 1].length; i++)
|
---|
360 | maxValue[size - 1][i] = 0;
|
---|
361 | }
|
---|
362 | final boolean constraintsExist;
|
---|
363 | if (input.feasibleCoalitions == null)
|
---|
364 | constraintsExist = false;
|
---|
365 | else
|
---|
366 | constraintsExist = true;
|
---|
367 |
|
---|
368 | for (int coalitionInBitFormat = (int) Math.pow(2, numOfAgents)
|
---|
369 | - 1; coalitionInBitFormat > 0; coalitionInBitFormat--)
|
---|
370 | if ((constraintsExist == false) || (input.feasibleCoalitions
|
---|
371 | .contains(coalitionInBitFormat)))
|
---|
372 | // if a coalition is feasible, and it's upperBound is greater than
|
---|
373 | // the smallest element in "curMax" then update "curMax"
|
---|
374 | {
|
---|
375 | int size = Combinations.getSizeOfCombinationInBitFormat(
|
---|
376 | coalitionInBitFormat, numOfAgents);
|
---|
377 | double[] curMaxValue = maxValue[size - 1];
|
---|
378 | int j = numOfRequiredMaxValues[size - 1] - 1;
|
---|
379 | if (input.getCoalitionValue(
|
---|
380 | coalitionInBitFormat) > curMaxValue[j]) {
|
---|
381 | while ((j > 0) && (input.getCoalitionValue(
|
---|
382 | coalitionInBitFormat) > curMaxValue[j - 1])) {
|
---|
383 | curMaxValue[j] = curMaxValue[j - 1];
|
---|
384 | j--;
|
---|
385 | }
|
---|
386 | curMaxValue[j] = input
|
---|
387 | .getCoalitionValue(coalitionInBitFormat);
|
---|
388 | }
|
---|
389 | }
|
---|
390 | return (maxValue);
|
---|
391 | }
|
---|
392 |
|
---|
393 | // ******************************************************************************************************
|
---|
394 |
|
---|
395 | /**
|
---|
396 | * This method disables any subspaces with a UB lower that the value of the
|
---|
397 | * current best solution (i.e. lower than LB*), and returns the number of
|
---|
398 | * subspaces that this method has disabled
|
---|
399 | */
|
---|
400 | private long disableSubspacesWithUBLowerThanTheHighestLB(Input input,
|
---|
401 | Output output, Result result) {
|
---|
402 | Node[][] nodes = result.ipIntegerPartitionGraph.nodes;
|
---|
403 | if (input.pruneSubspaces == false)
|
---|
404 | return (0);
|
---|
405 |
|
---|
406 | long numOfSubspacesThatThisMethodHasDisabled = 0;
|
---|
407 |
|
---|
408 | for (int level = 0; level < nodes.length; level++) {
|
---|
409 | for (int i = 0; i < nodes[level].length; i++) {
|
---|
410 | Subspace curSubspace = nodes[level][i].subspace;
|
---|
411 | if (curSubspace.enabled == true) {
|
---|
412 | // if( curSubspace.UB < result.ipLowerBoundOnOptimalValue )
|
---|
413 | if (curSubspace.UB
|
---|
414 | - result.ipLowerBoundOnOptimalValue < -0.00000000005) {
|
---|
415 | curSubspace.enabled = false;
|
---|
416 | numOfSubspacesThatThisMethodHasDisabled += 1;
|
---|
417 | }
|
---|
418 | }
|
---|
419 | }
|
---|
420 | }
|
---|
421 | output.printCurrentResultsOfIPToStringBuffer_ifPrevResultsAreDifferent(
|
---|
422 | input, result);
|
---|
423 | return (numOfSubspacesThatThisMethodHasDisabled);
|
---|
424 | }
|
---|
425 |
|
---|
426 | // ******************************************************************************************************
|
---|
427 |
|
---|
428 | /**
|
---|
429 | * Assign to each node a priority based on the subspace-selection function,
|
---|
430 | * and then sort the nodes based on their priorities.
|
---|
431 | */
|
---|
432 | private Node[] getListOfSortedNodes(Subspace[][] subspaces, Input input,
|
---|
433 | Result result) {
|
---|
434 | Node[][] nodes = result.ipIntegerPartitionGraph.nodes;
|
---|
435 |
|
---|
436 | // *******************************************
|
---|
437 | // *** ***
|
---|
438 | // *** Assign priorities to nodes ***
|
---|
439 | // *** ***
|
---|
440 | // *******************************************
|
---|
441 |
|
---|
442 | for (int level = 0; level < nodes.length; level++) { // For each level
|
---|
443 | for (int i = 0; i < nodes[level].length; i++) // For each subspace
|
---|
444 | // in the current
|
---|
445 | // level
|
---|
446 | {
|
---|
447 | Subspace curSubspace = nodes[level][i].subspace;
|
---|
448 | curSubspace.priority = curSubspace.UB;
|
---|
449 | // curSubspace.priority = -1 * curSubspace.sizeOfSubspace;
|
---|
450 | // curSubspace.priority = curSubspace.LB;
|
---|
451 | }
|
---|
452 | }
|
---|
453 |
|
---|
454 | // ********************************************************
|
---|
455 | // *** ***
|
---|
456 | // *** Sort subspaces based on their priorities ***
|
---|
457 | // *** ***
|
---|
458 | // ********************************************************
|
---|
459 |
|
---|
460 | // Initialization
|
---|
461 | Node[] sortedNodes = new Node[IntegerPartition
|
---|
462 | .getNumOfIntegerPartitions(input.numOfAgents)];
|
---|
463 | int k = 0;
|
---|
464 | for (int level = 0; level < nodes.length; level++) { // For each level
|
---|
465 | for (int i = 0; i < nodes[level].length; i++) { // For each subspace
|
---|
466 | // in the current
|
---|
467 | // level
|
---|
468 | sortedNodes[k] = nodes[level][i];
|
---|
469 | k++;
|
---|
470 | }
|
---|
471 | }
|
---|
472 | // Sorting
|
---|
473 | for (int i = sortedNodes.length - 1; i >= 0; i--) // start at the end of
|
---|
474 | // the array
|
---|
475 | {
|
---|
476 | int indexOfSmallestElement = i; // (1) default value of the index
|
---|
477 | // the of smallest element.
|
---|
478 | for (int j = i; j >= 0; j--) // (2) loop from the end of unsorted
|
---|
479 | // zone to the beginning of the
|
---|
480 | // array.
|
---|
481 | {
|
---|
482 | // compare current element to smallest one
|
---|
483 | if ((sortedNodes[j].subspace.priority < sortedNodes[indexOfSmallestElement].subspace.priority)
|
---|
484 | || ((sortedNodes[j].subspace.priority == sortedNodes[indexOfSmallestElement].subspace.priority)
|
---|
485 | && (sortedNodes[j].subspace.UB < sortedNodes[indexOfSmallestElement].subspace.UB)))
|
---|
486 | indexOfSmallestElement = j; // if it's smaller, it becomes
|
---|
487 | // the new smallest
|
---|
488 | }
|
---|
489 | // swap the two values
|
---|
490 | Node temp = sortedNodes[i];
|
---|
491 | sortedNodes[i] = sortedNodes[indexOfSmallestElement];
|
---|
492 | sortedNodes[indexOfSmallestElement] = temp;
|
---|
493 | }
|
---|
494 | return (sortedNodes);
|
---|
495 | }
|
---|
496 |
|
---|
497 | // ******************************************************************************************************
|
---|
498 |
|
---|
499 | /**
|
---|
500 | * Returns the first enabled subspace in the given list of subspaces
|
---|
501 | */
|
---|
502 | private Node getFirstEnabledNode(Node[] sortedNodes) {
|
---|
503 | for (int i = 0; i < sortedNodes.length; i++) {
|
---|
504 | if (sortedNodes[i].subspace.enabled)
|
---|
505 | return (sortedNodes[i]);
|
---|
506 | }
|
---|
507 | return (null);
|
---|
508 | }
|
---|
509 |
|
---|
510 | // ******************************************************************************************************
|
---|
511 |
|
---|
512 | /**
|
---|
513 | * This method sets "result.ipUpperBoundOnOptimalValue" to the
|
---|
514 | * "initialValue", and searches through the upper bounds of the "enabled"
|
---|
515 | * subspaces to see if there is one that is greater than that value
|
---|
516 | */
|
---|
517 | private void setUpperAndLowerBoundsOnOptimalValue(Input input,
|
---|
518 | Result result) {
|
---|
519 | result.ipUpperBoundOnOptimalValue = result.get_ipValueOfBestCSFound();
|
---|
520 | result.ipLowerBoundOnOptimalValue = result.get_ipValueOfBestCSFound();
|
---|
521 |
|
---|
522 | Node[][] nodes = result.ipIntegerPartitionGraph.nodes;
|
---|
523 | for (int level = 0; level < nodes.length; level++) {
|
---|
524 | for (int i = 0; i < nodes[level].length; i++) {
|
---|
525 | Subspace curSubspace = nodes[level][i].subspace;
|
---|
526 | if (curSubspace.enabled) {
|
---|
527 | if (result.ipUpperBoundOnOptimalValue < curSubspace.UB)
|
---|
528 | result.ipUpperBoundOnOptimalValue = curSubspace.UB;
|
---|
529 |
|
---|
530 | if (result.ipLowerBoundOnOptimalValue < curSubspace.LB)
|
---|
531 | result.ipLowerBoundOnOptimalValue = curSubspace.LB;
|
---|
532 | }
|
---|
533 | }
|
---|
534 | }
|
---|
535 | }
|
---|
536 |
|
---|
537 | // ******************************************************************************************************
|
---|
538 |
|
---|
539 | /**
|
---|
540 | * This method initializes sumOfMax, which is used in
|
---|
541 | * "Subspace.search_useBranchAndBound". Here, none of the values in f are
|
---|
542 | * used.
|
---|
543 | */
|
---|
544 | private double[] computeSumOfMax_splitNoIntegers(int[] integers,
|
---|
545 | double[][] maxValueForEachSize) {
|
---|
546 | // Initialization
|
---|
547 | double[] sumOfMax = new double[integers.length + 1];
|
---|
548 |
|
---|
549 | // Compute the upper bounds of the last list
|
---|
550 | sumOfMax[integers.length] = maxValueForEachSize[integers[integers.length
|
---|
551 | - 1] - 1][0];
|
---|
552 |
|
---|
553 | // Compute the upper bounds of the remaining lists
|
---|
554 | int j = 0;
|
---|
555 | for (int i = integers.length - 1; i > 0; i--) {
|
---|
556 | if (integers[i - 1] == integers[i])
|
---|
557 | j++;
|
---|
558 | else
|
---|
559 | j = 0;
|
---|
560 | sumOfMax[i] = sumOfMax[i + 1]
|
---|
561 | + maxValueForEachSize[integers[i - 1] - 1][j];
|
---|
562 | }
|
---|
563 | return (sumOfMax);
|
---|
564 | }
|
---|
565 |
|
---|
566 | // ******************************************************************************************************
|
---|
567 |
|
---|
568 | /**
|
---|
569 | * This method initializes sumOfMax, which is used in
|
---|
570 | * "Subspace.search_useBranchAndBound". Here, none of the values in f are
|
---|
571 | * used.
|
---|
572 | */
|
---|
573 | private double[] computeSumOfMax_usefInsteadOfv(int[] integers,
|
---|
574 | double[][] maxValueForEachSize, Result result) {
|
---|
575 | // Initialization
|
---|
576 | double[] sumOfMax = new double[integers.length + 1];
|
---|
577 |
|
---|
578 | // Compute the upper bounds of the last list
|
---|
579 | sumOfMax[integers.length] = result
|
---|
580 | .get_max_f(integers[integers.length - 1] - 1);
|
---|
581 | for (int i = integers.length - 1; i > 0; i--)
|
---|
582 | sumOfMax[i] = sumOfMax[i + 1]
|
---|
583 | + result.get_max_f(integers[i - 1] - 1);
|
---|
584 |
|
---|
585 | return (sumOfMax);
|
---|
586 | }
|
---|
587 |
|
---|
588 | // ******************************************************************************************************
|
---|
589 |
|
---|
590 | /**
|
---|
591 | * This method initializes sumOfMax, which is used in
|
---|
592 | * "Subspace.search_useBranchAndBound". Here, none of the values in f are
|
---|
593 | * used.
|
---|
594 | */
|
---|
595 | private double computeUpperBound(ElementOfMultiset[] integers,
|
---|
596 | double[][] maxValueForEachSize) {
|
---|
597 | double upperBound = 0;
|
---|
598 | for (int i = 0; i < integers.length; i++) {
|
---|
599 | int j = 0;
|
---|
600 | for (int k = 0; k < integers[i].repetition; k++) {
|
---|
601 | upperBound += maxValueForEachSize[integers[i].element - 1][j];
|
---|
602 | j++;
|
---|
603 | }
|
---|
604 | }
|
---|
605 | return (upperBound);
|
---|
606 | }
|
---|
607 |
|
---|
608 | // ******************************************************************************************************
|
---|
609 |
|
---|
610 | /**
|
---|
611 | * This method initializes sumOfMax, which is used in
|
---|
612 | * "Subspace.search_useBranchAndBound"
|
---|
613 | */
|
---|
614 | private double[] computeSumOfMax_splitManyIntegers(Node node,
|
---|
615 | double[][] maxValueForEachSize, Input input,
|
---|
616 | ElementOfMultiset[] subsetToBePutAtTheBeginning, Result result) {
|
---|
617 | if ((input.solverName == SolverNames.IP)
|
---|
618 | || (node.subspace.relevantNodes == null))
|
---|
619 | return (computeSumOfMax_splitNoIntegers(node.subspace.integers,
|
---|
620 | maxValueForEachSize));
|
---|
621 |
|
---|
622 | // Initialization
|
---|
623 | int[] integers = node.subspace.integers;
|
---|
624 | Node[] relevantNodes = node.subspace.relevantNodes;
|
---|
625 | double[] sumOfMax = new double[integers.length + 1];
|
---|
626 |
|
---|
627 | // Count the number of integers in the subset that will be put at the
|
---|
628 | // beginning, i.e., the subset containing the
|
---|
629 | // integers that are common between this node, and every relevant node
|
---|
630 | // (i.e., the integers that will not be split)
|
---|
631 | int numOfIntegersToBePutAtTheBeginning = 0;
|
---|
632 | if (subsetToBePutAtTheBeginning != null)
|
---|
633 | for (int i = 0; i < subsetToBePutAtTheBeginning.length; i++)
|
---|
634 | numOfIntegersToBePutAtTheBeginning += subsetToBePutAtTheBeginning[i].repetition;
|
---|
635 |
|
---|
636 | // For this node, and every relevant node, we are going to keep a copy
|
---|
637 | // of its integer partition
|
---|
638 | int[][] tempIntegers = new int[relevantNodes.length + 1][];
|
---|
639 | int[][] tempIntegerRoots = new int[relevantNodes.length + 1][];
|
---|
640 | tempIntegers[0] = General
|
---|
641 | .copyArray(node.integerPartition.partsSortedAscendingly);
|
---|
642 | tempIntegerRoots[0] = General.copyArray(node.tempIntegerRoots);
|
---|
643 | for (int i = 1; i < tempIntegers.length; i++) {
|
---|
644 | tempIntegers[i] = General.copyArray(relevantNodes[i
|
---|
645 | - 1].integerPartition.partsSortedAscendingly);
|
---|
646 | tempIntegerRoots[i] = General
|
---|
647 | .copyArray(relevantNodes[i - 1].tempIntegerRoots);
|
---|
648 | }
|
---|
649 | // Compute sumOfMax[1]...
|
---|
650 | double maxUB = node.subspace.UB;
|
---|
651 | for (int i = 0; i < relevantNodes.length; i++) {
|
---|
652 | if (maxUB < relevantNodes[i].subspace.UB) {
|
---|
653 | maxUB = relevantNodes[i].subspace.UB;
|
---|
654 | }
|
---|
655 | }
|
---|
656 | sumOfMax[1] = maxUB;
|
---|
657 | int index = 1;
|
---|
658 |
|
---|
659 | // Compute sumOfMax[i] : i>1
|
---|
660 | while (index < integers.length) {
|
---|
661 | sumOfMax[index + 1] = Integer.MIN_VALUE;
|
---|
662 | int curInteger = integers[index - 1];
|
---|
663 | for (int i = 0; i < tempIntegers.length; i++) {
|
---|
664 | ElementOfMultiset[] set = null;
|
---|
665 | ElementOfMultiset[] subset = null;
|
---|
666 | if (index <= numOfIntegersToBePutAtTheBeginning) {
|
---|
667 | subset = new ElementOfMultiset[1];
|
---|
668 | subset[0] = new ElementOfMultiset(curInteger, 1);
|
---|
669 | } else {
|
---|
670 | set = getSetOfIntegersGivenTheirRoot(tempIntegers[i],
|
---|
671 | tempIntegerRoots[i], curInteger);
|
---|
672 | subset = getSubsetOfIntegersGivenTheirSum(set, curInteger);
|
---|
673 | if (subset == null) {
|
---|
674 | subset = new ElementOfMultiset[1];
|
---|
675 | subset[0] = new ElementOfMultiset(curInteger, 1);
|
---|
676 | }
|
---|
677 | }
|
---|
678 | if (i == 0) {
|
---|
679 | removeSubset(node, subset, tempIntegers, tempIntegerRoots,
|
---|
680 | i);
|
---|
681 | } else {
|
---|
682 | removeSubset(relevantNodes[i - 1], subset, tempIntegers,
|
---|
683 | tempIntegerRoots, i);
|
---|
684 | }
|
---|
685 | double[] tempSumOfMax = computeSumOfMax_splitNoIntegers(
|
---|
686 | tempIntegers[i], maxValueForEachSize);
|
---|
687 | if (sumOfMax[index + 1] < tempSumOfMax[1])
|
---|
688 | sumOfMax[index + 1] = tempSumOfMax[1];
|
---|
689 | }
|
---|
690 | // Compute the bounds using f, and see if this improves things...
|
---|
691 | double[] sumOfMaxUsingf = computeSumOfMax_usefInsteadOfv(
|
---|
692 | tempIntegers[0], maxValueForEachSize, result);
|
---|
693 | if (sumOfMax[index + 1] > sumOfMaxUsingf[1])
|
---|
694 | sumOfMax[index + 1] = sumOfMaxUsingf[1];
|
---|
695 |
|
---|
696 | index++;
|
---|
697 | }
|
---|
698 | return (sumOfMax);
|
---|
699 | }
|
---|
700 |
|
---|
701 | // ******************************************************************************************************
|
---|
702 |
|
---|
703 | /**
|
---|
704 | * This method initializes sumOfMax, which is used in
|
---|
705 | * "Subspace.search_useBranchAndBound" IMPORTANT: this version assumes that
|
---|
706 | * there is ONLY ONE integer that will be split at the end
|
---|
707 | */
|
---|
708 | private double[] computeSumOfMax_splitOneInteger(Node node,
|
---|
709 | double[][] maxValueForEachSize, Input input, Result result) {
|
---|
710 | if ((input.solverName == SolverNames.IP)
|
---|
711 | || (node.subspace.relevantNodes == null))
|
---|
712 | return (computeSumOfMax_splitNoIntegers(node.subspace.integers,
|
---|
713 | maxValueForEachSize));
|
---|
714 |
|
---|
715 | int[] integers = node.subspace.integers;
|
---|
716 | double[] sumOfMax = new double[integers.length + 1];
|
---|
717 |
|
---|
718 | // compute the maximum upper bound of this node and all relevant nodes
|
---|
719 | double maxUB = node.subspace.UB;
|
---|
720 | for (int i = 0; i < node.subspace.relevantNodes.length; i++)
|
---|
721 | if (maxUB < node.subspace.relevantNodes[i].subspace.UB)
|
---|
722 | maxUB = node.subspace.relevantNodes[i].subspace.UB;
|
---|
723 |
|
---|
724 | // Compute the upper bound of the last list
|
---|
725 | sumOfMax[integers.length] = maxValueForEachSize[integers[integers.length
|
---|
726 | - 1] - 1][0] + (maxUB - node.subspace.UB);
|
---|
727 | double max_f = result.get_max_f(integers[integers.length - 1] - 1);
|
---|
728 | if ((max_f != 0) && (sumOfMax[integers.length] > max_f))
|
---|
729 | sumOfMax[integers.length] = max_f;
|
---|
730 |
|
---|
731 | sumOfMax[integers.length - 1] = sumOfMax[integers.length]
|
---|
732 | + maxValueForEachSize[integers[integers.length - 2] - 1][0];
|
---|
733 | int k = 2;
|
---|
734 |
|
---|
735 | // Compute the upper bounds of the remaining lists
|
---|
736 | int x = integers.length - k;
|
---|
737 | int j = 0;
|
---|
738 | for (int i = x; i > 0; i--) {
|
---|
739 | if (integers[i - 1] == integers[i])
|
---|
740 | j++;
|
---|
741 | else
|
---|
742 | j = 0;
|
---|
743 | sumOfMax[i] = sumOfMax[i + 1]
|
---|
744 | + maxValueForEachSize[integers[i - 1] - 1][j];
|
---|
745 | k++;
|
---|
746 | }
|
---|
747 | return (sumOfMax);
|
---|
748 | }
|
---|
749 |
|
---|
750 | // ******************************************************************************************************
|
---|
751 |
|
---|
752 | /**
|
---|
753 | * This method initializes sumOfMax, which is used in
|
---|
754 | * "Subspace.search_useBranchAndBound"
|
---|
755 | */
|
---|
756 | private double[] computeSumOfMax_splitOneInteger_improveUsingf(Node node,
|
---|
757 | double[][] maxValueForEachSize, Input input, Result result) {
|
---|
758 | if ((input.solverName == SolverNames.IP)
|
---|
759 | || (node.subspace.relevantNodes == null))
|
---|
760 | return (computeSumOfMax_splitNoIntegers(node.subspace.integers,
|
---|
761 | maxValueForEachSize));
|
---|
762 |
|
---|
763 | // Initialization
|
---|
764 | int[] integers = node.subspace.integers;
|
---|
765 | double[] sumOfMax = new double[integers.length + 1];
|
---|
766 |
|
---|
767 | // Basically, "sumOfMax[i] = arrayOfMax[i][0] + arrayOfMax[i][1] + ... "
|
---|
768 | double[][] arrayOfMax = new double[integers.length + 1][];
|
---|
769 | for (int i = 1; i < arrayOfMax.length; i++) {
|
---|
770 | arrayOfMax[i] = new double[arrayOfMax.length - i];
|
---|
771 | }
|
---|
772 | // compute the maximum upper bound of this node and all relevant nodes
|
---|
773 | double maxUB = node.subspace.UB;
|
---|
774 | for (int i = 0; i < node.subspace.relevantNodes.length; i++)
|
---|
775 | if (maxUB < node.subspace.relevantNodes[i].subspace.UB)
|
---|
776 | maxUB = node.subspace.relevantNodes[i].subspace.UB;
|
---|
777 |
|
---|
778 | // Compute the upper bound of the last list
|
---|
779 | sumOfMax[integers.length] = maxValueForEachSize[integers[integers.length
|
---|
780 | - 1] - 1][0] + (maxUB - node.subspace.UB);
|
---|
781 | double max_f = result.get_max_f(integers[integers.length - 1] - 1);
|
---|
782 | if ((max_f != 0) && (sumOfMax[integers.length] > max_f))
|
---|
783 | sumOfMax[integers.length] = max_f;
|
---|
784 | sumOfMax[integers.length - 1] = sumOfMax[integers.length]
|
---|
785 | + maxValueForEachSize[integers[integers.length - 2] - 1][0];
|
---|
786 |
|
---|
787 | // Update arrayOfMax
|
---|
788 | for (int i = 1; i < arrayOfMax.length; i++)
|
---|
789 | arrayOfMax[i][arrayOfMax[i].length
|
---|
790 | - 1] = maxValueForEachSize[integers[integers.length - 1]
|
---|
791 | - 1][0] + (maxUB - node.subspace.UB);
|
---|
792 | for (int i = 1; i < arrayOfMax.length - 1; i++)
|
---|
793 | arrayOfMax[i][arrayOfMax[i].length
|
---|
794 | - 2] = maxValueForEachSize[integers[integers.length - 2]
|
---|
795 | - 1][0];
|
---|
796 |
|
---|
797 | // Compute the upper bounds of the remaining lists
|
---|
798 | int k = 2;
|
---|
799 | int x = integers.length - k;
|
---|
800 | int j = 0;
|
---|
801 | for (int i = x; i > 0; i--) {
|
---|
802 | if (integers[i - 1] == integers[i])
|
---|
803 | j++;
|
---|
804 | else
|
---|
805 | j = 0;
|
---|
806 | sumOfMax[i] = sumOfMax[i + 1]
|
---|
807 | + maxValueForEachSize[integers[i - 1] - 1][j];
|
---|
808 |
|
---|
809 | // Update arrayOfMax
|
---|
810 | for (int w = 1; w < arrayOfMax.length - k; w++)
|
---|
811 | arrayOfMax[w][arrayOfMax[w].length
|
---|
812 | - (k + 1)] = maxValueForEachSize[integers[i - 1]
|
---|
813 | - 1][j];
|
---|
814 | k++;
|
---|
815 | }
|
---|
816 | // the technique below did not make any difference in performace, so, to
|
---|
817 | // be safe, I disabled it
|
---|
818 | if (input.solverName == SolverNames.ODPIP)
|
---|
819 | improveUpperBoundUsingf(input.numOfAgents, sumOfMax, arrayOfMax,
|
---|
820 | maxValueForEachSize, integers, result);
|
---|
821 |
|
---|
822 | return (sumOfMax);
|
---|
823 | }
|
---|
824 |
|
---|
825 | // ******************************************************************************************************
|
---|
826 |
|
---|
827 | /**
|
---|
828 | * Try to reduce the upper bound using f. Example: Given [1,1,2,3],
|
---|
829 | * max_v1+max_v1+max_v2 can be replaced with: max_f4.
|
---|
830 | */
|
---|
831 | private void improveUpperBoundUsingf(int numOfAgents, double[] sumOfMax,
|
---|
832 | double[][] arrayOfMax, double[][] maxValueForEachSize,
|
---|
833 | int[] integers, Result result) {
|
---|
834 | // ******************************************************************************
|
---|
835 | // **** ****
|
---|
836 | // **** try to start from the first list, and head towards the last list
|
---|
837 | // ****
|
---|
838 | // **** ****
|
---|
839 | // ******************************************************************************
|
---|
840 |
|
---|
841 | // for each list "i"...
|
---|
842 | for (int i = 1; i < sumOfMax.length; i++) // try to reduce "sumOfMax[i]"
|
---|
843 | {
|
---|
844 | // Initialization
|
---|
845 | int start = i;
|
---|
846 | double newSumOfMax = 0;
|
---|
847 | int[] numOfTimesWeComputedASizeRegularly = new int[numOfAgents + 1];
|
---|
848 | for (int size = 0; size <= numOfAgents; size++)
|
---|
849 | numOfTimesWeComputedASizeRegularly[size] = 0;
|
---|
850 |
|
---|
851 | /*
|
---|
852 | * In the 1st loop, we group a few integers (from "start" to "end"),
|
---|
853 | * where "start" equals "i" In the 2nd loop, we group a few integers
|
---|
854 | * (from "start" to "end"), where "start" equals the. previous "end"
|
---|
855 | * plus 1. This is repeated until we reach the last integer...
|
---|
856 | */
|
---|
857 | do {
|
---|
858 | // every time we enter this loop, we have the same "i", but a
|
---|
859 | // new "start"
|
---|
860 | int sumOfIntegers = 0;
|
---|
861 | int bestSumOfIntegers = -1;
|
---|
862 | double bestSavings = 0;
|
---|
863 | int bestEnd = 0;
|
---|
864 | boolean exitLoop = false;
|
---|
865 | // Given the current "start", we want to find the best "end"
|
---|
866 | for (int end = start; end < sumOfMax.length; end++) {
|
---|
867 | sumOfIntegers += integers[end - 1];
|
---|
868 | if (sumOfIntegers > result
|
---|
869 | .get_dpMaxSizeThatWasComputedSoFar()) {
|
---|
870 | exitLoop = true;
|
---|
871 | break;
|
---|
872 | }
|
---|
873 | // Compute the savings if we use: "result.max_f[
|
---|
874 | // sumOfIntegers-1 ]" instead
|
---|
875 | // of: "arrayOfMax[i][start]+...+arrayOfMax[i][end]"
|
---|
876 | double savings = -1 * result.get_max_f(sumOfIntegers - 1);
|
---|
877 | for (int j = start; j <= end; j++)
|
---|
878 | savings += arrayOfMax[i][j - i];
|
---|
879 |
|
---|
880 | if (bestSavings < savings) {
|
---|
881 | bestSavings = savings;
|
---|
882 | bestSumOfIntegers = sumOfIntegers;
|
---|
883 | bestEnd = end;
|
---|
884 | }
|
---|
885 | }
|
---|
886 | // if even the best savings are 0, then the current start is
|
---|
887 | // useless...
|
---|
888 | if (bestSavings < 0.0000000001) {
|
---|
889 | int curSize = integers[start - 1];
|
---|
890 | newSumOfMax += maxValueForEachSize[curSize
|
---|
891 | - 1][numOfTimesWeComputedASizeRegularly[curSize]];
|
---|
892 | numOfTimesWeComputedASizeRegularly[curSize]++;
|
---|
893 | start++;
|
---|
894 | } else {
|
---|
895 | newSumOfMax += result.get_max_f(bestSumOfIntegers - 1);
|
---|
896 | start = bestEnd + 1;
|
---|
897 | }
|
---|
898 | } while (start < sumOfMax.length);
|
---|
899 |
|
---|
900 | if (sumOfMax[i] > newSumOfMax)
|
---|
901 | sumOfMax[i] = newSumOfMax;
|
---|
902 | }
|
---|
903 | }
|
---|
904 |
|
---|
905 | // ******************************************************************************************************
|
---|
906 |
|
---|
907 | /**
|
---|
908 | * select the subset of integers that will be put at the beginning. The
|
---|
909 | * remaining integers will be put at the end and will be searched using the
|
---|
910 | * f table, not the v table.
|
---|
911 | *
|
---|
912 | * Here, you explicitly specify the number of integers to be placed at the
|
---|
913 | * end.
|
---|
914 | *
|
---|
915 | * Returns the subset of integers that is common between the node and all
|
---|
916 | * reachable nodes.
|
---|
917 | */
|
---|
918 | private ElementOfMultiset[] getRelevantNodes(Node node, Input input,
|
---|
919 | Result result, int numOfIntegersToSplitAtTheEnd) {
|
---|
920 | if (input.solverName == SolverNames.IP) {
|
---|
921 | node.subspace.relevantNodes = null;
|
---|
922 | return (null);
|
---|
923 | }
|
---|
924 | int numOfIntegersInNode = node.integerPartition.partsSortedAscendingly.length;
|
---|
925 |
|
---|
926 | // get the list of nodes that are reachable from the original node.
|
---|
927 | Node[] reachableNodes = result.ipIntegerPartitionGraph
|
---|
928 | .getReachableNodes(node);
|
---|
929 | if (reachableNodes == null) {
|
---|
930 | node.subspace.relevantNodes = null;
|
---|
931 | return (null);
|
---|
932 | }
|
---|
933 | // create an iterator that will iterate over subsets of the original
|
---|
934 | // integer partition
|
---|
935 | SubsetsOfMultiset[] subsetIterators = new SubsetsOfMultiset[numOfIntegersToSplitAtTheEnd];
|
---|
936 | for (int s = 0; s < numOfIntegersToSplitAtTheEnd; s++)
|
---|
937 | subsetIterators[s] = new SubsetsOfMultiset(
|
---|
938 | node.integerPartition.sortedMultiset,
|
---|
939 | numOfIntegersInNode - (s + 1), false);
|
---|
940 |
|
---|
941 | // Initialization
|
---|
942 | ElementOfMultiset[] bestSubset = null;
|
---|
943 | long bestSavings = 0;
|
---|
944 | int bestNumOfRelevantNodes = 0;
|
---|
945 |
|
---|
946 | for (int s = 0; s < numOfIntegersToSplitAtTheEnd; s++) {
|
---|
947 | // Iterate over all subsets of size: s+1
|
---|
948 | ElementOfMultiset[] subset = subsetIterators[s].getNextSubset();
|
---|
949 | while (subset != null) {
|
---|
950 | long savings = 0;
|
---|
951 | int numOfRelevantSubspaces = 0;
|
---|
952 | // out of all nodes reachable from "node", find the ones that
|
---|
953 | // contain "subset"
|
---|
954 | for (int i = 0; i < reachableNodes.length; i++) {
|
---|
955 | if ((reachableNodes[i].integerPartition.contains(subset))
|
---|
956 | && (reachableNodes[i].subspace.enabled)) {
|
---|
957 | savings += reachableNodes[i].subspace.totalNumOfExpansionsInSubspace;
|
---|
958 | numOfRelevantSubspaces++;
|
---|
959 | }
|
---|
960 | }
|
---|
961 | // update the best subset
|
---|
962 | if (bestSavings < savings) {
|
---|
963 | bestSavings = savings;
|
---|
964 | bestSubset = General.copyMultiset(subset);
|
---|
965 | bestNumOfRelevantNodes = numOfRelevantSubspaces;
|
---|
966 | }
|
---|
967 | // Get the next subset
|
---|
968 | subset = subsetIterators[s].getNextSubset();
|
---|
969 | }
|
---|
970 | }
|
---|
971 | // get the list of relevant subspaces, based on the best subset
|
---|
972 | int index = 0;
|
---|
973 | if (bestNumOfRelevantNodes == 0) {
|
---|
974 | node.subspace.relevantNodes = null;
|
---|
975 | return (null);
|
---|
976 | } else {
|
---|
977 | node.subspace.relevantNodes = new Node[bestNumOfRelevantNodes];
|
---|
978 | for (int i = 0; i < reachableNodes.length; i++) {
|
---|
979 | if ((reachableNodes[i].integerPartition.contains(bestSubset))
|
---|
980 | && (reachableNodes[i].subspace.enabled)) {
|
---|
981 | node.subspace.relevantNodes[index] = reachableNodes[i];
|
---|
982 | index++;
|
---|
983 | }
|
---|
984 | }
|
---|
985 | return (bestSubset);
|
---|
986 | }
|
---|
987 | }
|
---|
988 |
|
---|
989 | // ******************************************************************************************************
|
---|
990 |
|
---|
991 | /**
|
---|
992 | * select the subset of integers that will be put at the beginning. The
|
---|
993 | * remaining integers will be put at the end and will be searched using the
|
---|
994 | * f table, not the v table.
|
---|
995 | *
|
---|
996 | * Here, the number of integers to be put at the end is not limited; it can
|
---|
997 | * be as large as needed
|
---|
998 | *
|
---|
999 | * Returns the subset of integers that is common between the node and all
|
---|
1000 | * reachable nodes.
|
---|
1001 | */
|
---|
1002 | private ElementOfMultiset[] getRelevantNodes(Node node, Input input,
|
---|
1003 | Result result) {
|
---|
1004 | if (input.solverName == SolverNames.IP) {
|
---|
1005 | node.subspace.relevantNodes = null;
|
---|
1006 | return (null);
|
---|
1007 | }
|
---|
1008 | // get the list of nodes that are reachable from the original node.
|
---|
1009 | Node[] reachableNodes = result.ipIntegerPartitionGraph
|
---|
1010 | .getReachableNodes(node);
|
---|
1011 | if (reachableNodes == null) {
|
---|
1012 | node.subspace.relevantNodes = null;
|
---|
1013 | return (null);
|
---|
1014 | }
|
---|
1015 | // Count how many of those nodes are actually enabled
|
---|
1016 | int numOfEnabledReachableNodes = 0;
|
---|
1017 | for (int j = 0; j < reachableNodes.length; j++)
|
---|
1018 | if (reachableNodes[j].subspace.enabled)
|
---|
1019 | numOfEnabledReachableNodes++;
|
---|
1020 |
|
---|
1021 | // Put all reachable, enabled, nodes in the list of relevant nodes
|
---|
1022 | if (numOfEnabledReachableNodes == 0) {
|
---|
1023 | node.subspace.relevantNodes = null;
|
---|
1024 | return (null);
|
---|
1025 | } else {
|
---|
1026 | node.subspace.relevantNodes = new Node[numOfEnabledReachableNodes];
|
---|
1027 | int index = 0;
|
---|
1028 | for (int j = 0; j < reachableNodes.length; j++) {
|
---|
1029 | if (reachableNodes[j].subspace.enabled) {
|
---|
1030 | node.subspace.relevantNodes[index] = reachableNodes[j];
|
---|
1031 | index++;
|
---|
1032 | }
|
---|
1033 | }
|
---|
1034 | }
|
---|
1035 | Node[] relevantNodes = node.subspace.relevantNodes;
|
---|
1036 |
|
---|
1037 | // Create a copy of the multiset representation of the integer partition
|
---|
1038 | // of the node
|
---|
1039 | ElementOfMultiset[] copyOfMultiset = General
|
---|
1040 | .copyMultiset(node.integerPartition.sortedMultiset);
|
---|
1041 |
|
---|
1042 | // For every element in the multiset
|
---|
1043 | for (int i = 0; i < copyOfMultiset.length; i++) {
|
---|
1044 | // count the minimum number of times this element appears in a
|
---|
1045 | // reachable node
|
---|
1046 | int curElement = copyOfMultiset[i].element;
|
---|
1047 | int minNumOfRepetitions = copyOfMultiset[i].repetition;
|
---|
1048 | for (int j = 0; j < relevantNodes.length; j++) {
|
---|
1049 | boolean foundElement = false;
|
---|
1050 | ElementOfMultiset[] multiset = relevantNodes[j].integerPartition.sortedMultiset;
|
---|
1051 | for (int k = 0; k < multiset.length; k++)
|
---|
1052 | if (multiset[k].element == curElement) {
|
---|
1053 | foundElement = true;
|
---|
1054 | if (minNumOfRepetitions > multiset[k].repetition)
|
---|
1055 | minNumOfRepetitions = multiset[k].repetition;
|
---|
1056 | break;
|
---|
1057 | }
|
---|
1058 | if (foundElement == false) {
|
---|
1059 | minNumOfRepetitions = 0;
|
---|
1060 | break;
|
---|
1061 | }
|
---|
1062 | }
|
---|
1063 | // set the number of repetitions to be the minimum
|
---|
1064 | copyOfMultiset[i].repetition = minNumOfRepetitions;
|
---|
1065 | }
|
---|
1066 | // Get rid of any elements that are repeated 0 times, and return the
|
---|
1067 | // remaining
|
---|
1068 | int counter = 0;
|
---|
1069 | for (int i = 0; i < copyOfMultiset.length; i++) {
|
---|
1070 | if (copyOfMultiset[i].repetition > 0) {
|
---|
1071 | counter++;
|
---|
1072 | }
|
---|
1073 | }
|
---|
1074 | if (counter == 0) {
|
---|
1075 | return (null);
|
---|
1076 | } else {
|
---|
1077 | ElementOfMultiset[] subset = new ElementOfMultiset[counter];
|
---|
1078 | int index = 0;
|
---|
1079 | for (int i = 0; i < copyOfMultiset.length; i++)
|
---|
1080 | if (copyOfMultiset[i].repetition > 0) {
|
---|
1081 | subset[index] = new ElementOfMultiset(
|
---|
1082 | copyOfMultiset[i].element,
|
---|
1083 | copyOfMultiset[i].repetition);
|
---|
1084 | index++;
|
---|
1085 | }
|
---|
1086 | return (subset);
|
---|
1087 | }
|
---|
1088 | }
|
---|
1089 |
|
---|
1090 | // ******************************************************************************************************
|
---|
1091 |
|
---|
1092 | /**
|
---|
1093 | * Place the best subset at the beginning of the node's subspace.integers.
|
---|
1094 | * Also, place it at the beginning of every relevant node's
|
---|
1095 | * subspace.integers.
|
---|
1096 | */
|
---|
1097 | private void putSubsetAtTheBeginning(Node node, ElementOfMultiset[] subset,
|
---|
1098 | Input input) {
|
---|
1099 | if ((subset == null) || (input.solverName == SolverNames.IP))
|
---|
1100 | return;
|
---|
1101 |
|
---|
1102 | // Put all remaining integers (i.e., those not in the subset) in a set
|
---|
1103 | // represented as a MULTISET
|
---|
1104 | ElementOfMultiset[] remainingIntegers_multiset = General
|
---|
1105 | .copyMultiset(node.integerPartition.sortedMultiset);
|
---|
1106 | for (int i = 0; i < subset.length; i++)
|
---|
1107 | for (int j = 0; j < remainingIntegers_multiset.length; j++)
|
---|
1108 | if (remainingIntegers_multiset[j].element == subset[i].element) {
|
---|
1109 | remainingIntegers_multiset[j].repetition -= subset[i].repetition;
|
---|
1110 | break;
|
---|
1111 | }
|
---|
1112 | // Count the total number of remaining integers (i.e., those that are
|
---|
1113 | // not in the subset)
|
---|
1114 | int counter = 0;
|
---|
1115 | for (int i = 0; i < remainingIntegers_multiset.length; i++)
|
---|
1116 | counter += remainingIntegers_multiset[i].repetition;
|
---|
1117 |
|
---|
1118 | // Put all remaining integers (i.e., those not in the subset) in a set
|
---|
1119 | // represented as an ARRAY.
|
---|
1120 | int[] remainingIntegers_array = new int[counter];
|
---|
1121 | int index = 0;
|
---|
1122 | for (int i = 0; i < remainingIntegers_multiset.length; i++)
|
---|
1123 | for (int j = 0; j < remainingIntegers_multiset[i].repetition; j++) {
|
---|
1124 | remainingIntegers_array[index] = remainingIntegers_multiset[i].element;
|
---|
1125 | index++;
|
---|
1126 | }
|
---|
1127 | // place the subset at the beginning, and the remaining integers at the
|
---|
1128 | // end
|
---|
1129 | int[] newIntegers = new int[node.subspace.integers.length];
|
---|
1130 | int index1 = 0;
|
---|
1131 | int index2 = newIntegers.length - counter;
|
---|
1132 | for (int i = 0; i < node.subspace.integers.length; i++) {
|
---|
1133 | boolean found = false;
|
---|
1134 | for (int j = 0; j < remainingIntegers_array.length; j++) {
|
---|
1135 | if (remainingIntegers_array[j] == node.subspace.integers[i]) {
|
---|
1136 | newIntegers[index2] = node.subspace.integers[i];
|
---|
1137 | index2++;
|
---|
1138 | remainingIntegers_array[j] = -1;
|
---|
1139 | found = true;
|
---|
1140 | break;
|
---|
1141 | }
|
---|
1142 | }
|
---|
1143 | if (found == false) {
|
---|
1144 | newIntegers[index1] = node.subspace.integers[i];
|
---|
1145 | index1++;
|
---|
1146 | }
|
---|
1147 | }
|
---|
1148 | node.subspace.integers = newIntegers;
|
---|
1149 | }
|
---|
1150 |
|
---|
1151 | // ******************************************************************************************************
|
---|
1152 |
|
---|
1153 | /**
|
---|
1154 | * Returns the maximum multiplicity of the integer in the node, and in every
|
---|
1155 | * relevant node
|
---|
1156 | */
|
---|
1157 | private int getMaximumMultiplicity(int integer, Node node) {
|
---|
1158 | // initialize by setting the maximum multiplicity to be within the node
|
---|
1159 | // itself
|
---|
1160 | int maximumMultiplicity = 0;
|
---|
1161 | for (int i = 0; i < node.integerPartition.sortedMultiset.length; i++)
|
---|
1162 | if (integer == node.integerPartition.sortedMultiset[i].element)
|
---|
1163 | maximumMultiplicity = node.integerPartition.sortedMultiset[i].repetition;
|
---|
1164 |
|
---|
1165 | // Now, consider the relevant nodes
|
---|
1166 | for (int k = 0; k < node.subspace.relevantNodes.length; k++) {
|
---|
1167 | Node curNode = node.subspace.relevantNodes[k];
|
---|
1168 | for (int i = 0; i < curNode.integerPartition.sortedMultiset.length; i++)
|
---|
1169 | if (integer == curNode.integerPartition.sortedMultiset[i].element)
|
---|
1170 | if (maximumMultiplicity < curNode.integerPartition.sortedMultiset[i].repetition)
|
---|
1171 | maximumMultiplicity = curNode.integerPartition.sortedMultiset[i].repetition;
|
---|
1172 | }
|
---|
1173 | return (maximumMultiplicity);
|
---|
1174 | }
|
---|
1175 |
|
---|
1176 | // ******************************************************************************************************
|
---|
1177 |
|
---|
1178 | /**
|
---|
1179 | * Given "sumOfIntegers", this method returns a subset of "mutliset" of
|
---|
1180 | * which the sum equals "sumOfIntegers"
|
---|
1181 | */
|
---|
1182 | private ElementOfMultiset[] getSubsetOfIntegersGivenTheirSum(
|
---|
1183 | ElementOfMultiset[] multiset, int sumOfIntegers) {
|
---|
1184 | if (multiset == null)
|
---|
1185 | return (null);
|
---|
1186 |
|
---|
1187 | int maxSize = Math.min(sumOfIntegers,
|
---|
1188 | General.getCardinalityOfMultiset(multiset));
|
---|
1189 |
|
---|
1190 | ElementOfMultiset[] subset;
|
---|
1191 | for (int size = 1; size <= maxSize; size++) {
|
---|
1192 | SubsetsOfMultiset subsetsOfMultiset = new SubsetsOfMultiset(
|
---|
1193 | multiset, size, false);
|
---|
1194 | subset = subsetsOfMultiset.getNextSubset();
|
---|
1195 | while (subset != null) {
|
---|
1196 | int sum = 0;
|
---|
1197 | for (int i = 0; i < subset.length; i++)
|
---|
1198 | sum += subset[i].element * subset[i].repetition;
|
---|
1199 |
|
---|
1200 | if (sum == sumOfIntegers)
|
---|
1201 | return (subset);
|
---|
1202 | else
|
---|
1203 | subset = subsetsOfMultiset.getNextSubset();
|
---|
1204 | }
|
---|
1205 | }
|
---|
1206 | return (null);
|
---|
1207 | }
|
---|
1208 |
|
---|
1209 | // ************************************************************************************************
|
---|
1210 |
|
---|
1211 | /**
|
---|
1212 | * Given "sumOfIntegers", this method returns a subset of "mutliset" of
|
---|
1213 | * which the sum equals "sumOfIntegers"
|
---|
1214 | */
|
---|
1215 | private ElementOfMultiset[] getSetOfIntegersGivenTheirRoot(
|
---|
1216 | int[] tempIntegers, int[] tempIntegerRoots, int root) {
|
---|
1217 | if (tempIntegerRoots == null)
|
---|
1218 | return (null);
|
---|
1219 |
|
---|
1220 | // count the integer that whose root equals "root"
|
---|
1221 | int counter = 0;
|
---|
1222 | for (int i = 0; i < tempIntegerRoots.length; i++) {
|
---|
1223 | if (tempIntegerRoots[i] == root) {
|
---|
1224 | counter++;
|
---|
1225 | }
|
---|
1226 | }
|
---|
1227 | // keep only those integers
|
---|
1228 | if (counter == 0) {
|
---|
1229 | return (null);
|
---|
1230 | } else {
|
---|
1231 | int[] resultAsArray = new int[counter];
|
---|
1232 | int index = 0;
|
---|
1233 | for (int i = 0; i < tempIntegerRoots.length; i++) {
|
---|
1234 | if (tempIntegerRoots[i] == root) {
|
---|
1235 | resultAsArray[index] = tempIntegers[i];
|
---|
1236 | index++;
|
---|
1237 | }
|
---|
1238 | }
|
---|
1239 | return (General.convertArrayToMultiset(resultAsArray));
|
---|
1240 | }
|
---|
1241 | }
|
---|
1242 |
|
---|
1243 | // ************************************************************************************************
|
---|
1244 |
|
---|
1245 | /**
|
---|
1246 | * remove the subset of integers from the node
|
---|
1247 | */
|
---|
1248 | public static void removeSubset(Node node, ElementOfMultiset[] subset,
|
---|
1249 | int[][] tempIntegers, int[][] tempIntegerRoots, int e) {
|
---|
1250 | if (subset == null)
|
---|
1251 | return;
|
---|
1252 |
|
---|
1253 | int[] integers = General.copyArray(tempIntegers[e]);
|
---|
1254 | int[] integerRoots = General.copyArray(tempIntegerRoots[e]);
|
---|
1255 | ElementOfMultiset[] tempSubset = General.copyMultiset(subset);
|
---|
1256 |
|
---|
1257 | for (int i = 0; i < integers.length; i++) {
|
---|
1258 | for (int j = 0; j < tempSubset.length; j++) {
|
---|
1259 | if ((integers[i] == tempSubset[j].element)
|
---|
1260 | && (tempSubset[j].repetition > 0)) {
|
---|
1261 | integers[i] = -1;
|
---|
1262 | tempSubset[j].repetition--;
|
---|
1263 | break;
|
---|
1264 | }
|
---|
1265 | }
|
---|
1266 | }
|
---|
1267 | // count the elements that have not been deleted
|
---|
1268 | int counter = 0;
|
---|
1269 | for (int i = 0; i < integers.length; i++) {
|
---|
1270 | if (integers[i] > -1) {
|
---|
1271 | counter++;
|
---|
1272 | }
|
---|
1273 | }
|
---|
1274 | // Get rid of any elements that have been deleted
|
---|
1275 | if (counter == 0) {
|
---|
1276 | tempIntegers[e] = integers;
|
---|
1277 | tempIntegerRoots[e] = integerRoots;
|
---|
1278 | } else {
|
---|
1279 | tempIntegers[e] = new int[counter];
|
---|
1280 | if (integerRoots != null)
|
---|
1281 | tempIntegerRoots[e] = new int[counter];
|
---|
1282 | else
|
---|
1283 | tempIntegerRoots[e] = null;
|
---|
1284 | int index = 0;
|
---|
1285 | for (int i = 0; i < integers.length; i++)
|
---|
1286 | if (integers[i] > -1) {
|
---|
1287 | tempIntegers[e][index] = integers[i];
|
---|
1288 | if (integerRoots != null)
|
---|
1289 | tempIntegerRoots[e][index] = integerRoots[i];
|
---|
1290 | index++;
|
---|
1291 | }
|
---|
1292 | }
|
---|
1293 | }
|
---|
1294 |
|
---|
1295 | // ************************************************************************************************
|
---|
1296 |
|
---|
1297 | /**
|
---|
1298 | * Returns the total number of expansions in the search space, given the
|
---|
1299 | * tree-like representation of different integer-partition-based subspaces
|
---|
1300 | */
|
---|
1301 | public long computeTotalNumOfExpansions(Result result) {
|
---|
1302 | long totalNumOfExpansions = 0;
|
---|
1303 | Node[][] nodes = result.ipIntegerPartitionGraph.nodes;
|
---|
1304 | for (int level = 0; level < nodes.length; level++) {
|
---|
1305 | for (int i = 0; i < nodes[level].length; i++) {
|
---|
1306 | Subspace curSubspace = nodes[level][i].subspace;
|
---|
1307 | totalNumOfExpansions += curSubspace.totalNumOfExpansionsInSubspace;
|
---|
1308 | }
|
---|
1309 | }
|
---|
1310 | return totalNumOfExpansions;
|
---|
1311 | }
|
---|
1312 | } |
---|