package resa.migrate.plan;
import java.util.Map;
import java.util.stream.IntStream;
import java.util.stream.Stream;
/**
* Created by ding on 14-7-23.
*/
public class SimpleCalculator extends PackCalculator {
private double gain = -1.0;
private int[] pack = null;
private KuhnMunkres kmAlg;
@Override
protected Pack calcPack() {
int maxPackSize = Stream.of(srcPacks).map(Map.Entry::getKey).mapToInt(pack -> pack.length).max().getAsInt();
kmAlg = new KuhnMunkres(Math.max(packSize, maxPackSize));
split(0, new int[0], packSize);
kmAlg = null;
if (pack == null) {
throw new IllegalStateException("No pack is found");
}
Pack ret = new Pack(pack, gain);
gain = -1.0;
pack = null;
return ret;
}
private void split(int start, int[] spilts, int part) {
if (start + part > workloads.length) {
return;
}
if (part == 1) {
if (start == workloads.length || spilts.length + 1 != packSize) {
throw new IllegalStateException("start == workloads.length");
} else if (totalWorkload(start, workloads.length) <= loadUpperLimit) {
int[] newPack = new int[spilts.length + 1];
System.arraycopy(spilts, 0, newPack, 0, spilts.length);
newPack[newPack.length - 1] = workloads.length - start;
double g = totalGain(convertPack(newPack));
if (g > gain) {
gain = g;
pack = newPack;
}
}
return;
}
int[] newSplits = new int[spilts.length + 1];
System.arraycopy(spilts, 0, newSplits, 0, spilts.length);
for (int i = start + 1; i < workloads.length; i++) {
if (totalWorkload(start, i) > loadUpperLimit) {
break;
}
newSplits[newSplits.length - 1] = i - start;
split(i, newSplits, part - 1);
}
}
private double totalGain(Range[] pack) {
return Stream.of(srcPacks).mapToDouble(e -> packGain(pack, e.getKey()) * e.getValue()).sum();
}
private double packGain(Range[] pack1, Range[] pack2) {
double[][] weights = new double[pack1.length][pack2.length];
for (int i = 0; i < pack1.length; i++) {
for (int j = 0; j < pack2.length; j++) {
weights[i][j] = overlap(pack1[i], pack2[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]], currPacks[pStart + r[1]])).sum();
return maxWeight[0];
}
private double overlap(Range r1, Range r2) {
if (r1.end < r2.start || r1.start > r2.end) {
return 0;
} else 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;
}
private double totalWorkload(int wStart, int wEnd) {
double sum = 0;
for (int i = wStart; i < wEnd; i++) {
sum += normalizedWordloads[i];
}
return sum;
}
}