package resa.migrate.plan; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.stream.IntStream; /** * Created by ding on 14-6-28. */ public class SinglePackCalculator extends PackCalculator { private Map<String, Pack> cache; private KuhnMunkres kmAlg; private Range[] currPack; protected Pack calcPack() { currPack = srcPacks[0].getKey(); kmAlg = new KuhnMunkres(Math.max(packSize, currPack.length)); Pack p; if (normalizedWordloads.length == packSize) { int[] ret = new int[normalizedWordloads.length]; Arrays.fill(ret, 1); Range[] packs = IntStream.range(0, packSize).mapToObj(i -> new Range(i, i)).toArray(Range[]::new); p = new Pack(ret, gain(packs, 0, currPack.length)); } else { //init buffer cache = new HashMap<>(); p = calc0(0, normalizedWordloads.length, packSize, 0, currPack.length); // release memory cache = null; } kmAlg = null; return p; } private Pack calc0(int wStart, int wEnd, int numPartition, int pStart, int pEnd) { if (wEnd - wStart < numPartition || numPartition == 0) { throw new IllegalStateException("start=" + wStart + ", end=" + wEnd + ", numPartition=" + numPartition); } String key = wStart + "-" + wEnd + "-" + numPartition + "-" + pStart + "-" + pEnd; return cache.computeIfAbsent(key, k -> calc1(wStart, wEnd, numPartition, pStart, pEnd)); } private Pack calc1(int wStart, int wEnd, int numPartition, int pStart, int pEnd) { if (numPartition == 1) { double sum = totalWorkload(wStart, wEnd); return sum > loadUpperLimit ? INFEASIBLE : new Pack(new int[]{wEnd - wStart}, gain(new Range[]{new Range(wStart, wEnd - 1)}, pStart, pEnd)); } else if (wEnd - wStart == numPartition) { int[] ret = new int[numPartition]; Arrays.fill(ret, 1); Range[] newRanges = IntStream.range(wStart, wEnd).mapToObj(i -> new Range(i, i)).toArray(Range[]::new); return new Pack(ret, gain(newRanges, pStart, pEnd)); } int split = wStart + 1; Pack rightPack = INFEASIBLE; double gain = Double.MIN_VALUE; for (int i = split; i < wEnd; i++) { if (totalWorkload(wStart, i) > loadUpperLimit || wEnd - i < numPartition - 1) { break; } int startPack = findPack(i); int stopPack = currPack[startPack].start < i ? startPack + 1 : startPack; startPack = Math.max(startPack, pStart); stopPack = Math.min(stopPack, pEnd); for (int k = startPack; k <= stopPack; k++) { Pack left = calc0(wStart, i, 1, pStart, k); Pack right = calc0(i, wEnd, numPartition - 1, k, pEnd); if (left != INFEASIBLE && right != INFEASIBLE) { double newGain = left.gain + right.gain; if (Double.compare(newGain, gain) > 0) { gain = newGain; split = i; rightPack = right; } } } } if (rightPack == INFEASIBLE) { return INFEASIBLE; } int[] ret = new int[numPartition]; ret[0] = split - wStart; System.arraycopy(rightPack.packing, 0, ret, 1, numPartition - 1); return new Pack(ret, gain); } private int findPack(int v) { for (int i = 0; i < currPack.length; i++) { if (currPack[i].end >= v) { return i; } } throw new IllegalStateException("value is " + v); } private double totalWorkload(int wStart, int wEnd) { double sum = 0; for (int i = wStart; i < wEnd; i++) { sum += normalizedWordloads[i]; } return sum; } private double gain(Range[] newPacks, int pStart, int pEnd) { if (newPacks.length == 0 || pStart == pEnd) { return 0; } double[][] weights = new double[newPacks.length][pEnd - pStart]; for (int i = 0; i < weights.length; i++) { for (int j = 0; j < weights[i].length; j++) { weights[i][j] = overlap(newPacks[i], currPack[pStart + j]); } } double[] maxWeight = new double[1]; kmAlg.getMaxBipartie(weights, maxWeight); // int[][] pairs = kmAlg.getMaxBipartie(weights, maxWeight); // return Stream.of(pairs).mapToDouble(r -> overlap(newPacks[r[0]], currPack[pStart + r[1]])).sum(); return maxWeight[0]; } private double overlap(Range r1, Range r2) { if (r1.start <= r2.start && r1.end >= r2.start) { return IntStream.rangeClosed(r2.start, Math.min(r2.end, r1.end)).mapToDouble(i -> dataSizes[i]).sum(); } else if (r1.start >= r2.start && r1.start <= r2.end) { return IntStream.rangeClosed(r1.start, Math.min(r2.end, r1.end)).mapToDouble(i -> dataSizes[i]).sum(); } return 0; } }