package viz.process;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class CladeBranchInfo {
int count = 0;
int totalNrOfTrees = 0;
//int [] overlapcount;
float [] cumscore;
List<Float> height= new ArrayList<Float>();
private float score, oldLength = -1;
private float dScore, dOldLength = -1;
void initialise(List<Double> cladeHeightSetBottom, List<Double> cladeHeightSetTop, int totalNrOfTrees) {
this.totalNrOfTrees = totalNrOfTrees;
for (int i = 0; i < cladeHeightSetBottom.size(); i++) {
height.add((float)(cladeHeightSetBottom.get(i)-cladeHeightSetTop.get(i)));
}
Collections.sort(height);
count = height.size();
float [] revcumscore = new float[count];
cumscore = new float[count];
cumscore[0] = 0;
for (int i = 1; i < count; i++) {
cumscore[i] = cumscore[i-1] + (height.get(i) - height.get(i-1)) * i;
}
revcumscore[count-1] = 0;
for (int i = count - 2; i >= 0; i--) {
revcumscore[i] = revcumscore[i+1] + (height.get(i+1) - height.get(i)) * (count - i - 1);
}
for (int i = 0; i < count; i++) {
cumscore[i] += revcumscore[i];
}
}
// float score(float bottom, float top) {
// float score = score2(bottom, top);
// if (score < 0) {
// int h = 3;
// h++;
// score = score2(bottom, top);
// }
// return score;
// }
float score(float bottom, float top) {
if (count == 0) {
return 0;
}
float length = top - bottom;
if (length == oldLength) {
return score;
}
oldLength = length;
if (length < -1e-8) {
return Float.POSITIVE_INFINITY;
}
// contribution due to trees not containing this clade
score = length * (totalNrOfTrees - count);
int i = Collections.binarySearch(height, length);
if (i >= 0) {
score += cumscore[i];
return score;
}
i = -1-i;
if (i >= count) {
// length is larger than largest branch length
score += cumscore[count - 1];
score += (length - height.get(count - 1)) * count;
return score;
}
if (i == 0) {
score += cumscore[0];
score += (height.get(0) - length) * count;
return score;
}
score += cumscore[i-1];
score += (length - height.get(i-1))/(height.get(i) - height.get(i-1)) * (cumscore[i] - cumscore[i-1]);
return score;
}
float dScore(float bottom, float top) {
float length = top - bottom;
if (length == dOldLength) {
return dScore;
}
dOldLength = length;
int i = Collections.binarySearch(height, length);
if (i < 0) {
i = -1-i;
}
if (i >= count) {
dScore = count;
return dScore;
}
if (i == 0) {
dScore = -count;
return dScore;
}
dScore += (cumscore[i] - cumscore[i-1])/(height.get(i) - height.get(i-1));
return dScore;
}
public float getMaxLength() {
return height.get(count - 1);
}
// void initialise(List<Double> cladeHeightSetBottom, List<Double> cladeHeightSetTop) {
// for (int i = 0; i < cladeHeightSetBottom.size(); i++) {
// insertBranch((float)(double)cladeHeightSetTop.get(i), (float)(double)cladeHeightSetBottom.get(i));
// }
// overlapcount = new int[height.size()];
// cumscore = new float[height.size()];
// overlapcount[0] = 1;
// cumscore[0] = 0;
// for (int i = 1; i < overlapcount.length; i++) {
// if (height.get(i) >= 0) {
// cumscore[i] = cumscore[i-1] + (height.get(i) - height.get(i-1)) * overlapcount[i-1];
// overlapcount[i] = overlapcount[i-1] + 1;
// } else {
// height.set(i, -height.get(i));
// cumscore[i] = cumscore[i-1] + (height.get(i) - height.get(i-1)) * overlapcount[i-1];
// overlapcount[i] = overlapcount[i-1] - 1;
// }
// }
// }
//
// private void insertBranch(float bottom, float top) {
// if (top <= bottom) {
// // ignore zero length branches, since their
// // contribution is constant and does not change
// // when the summary tree changes.
// return;
// }
//
// int iBottom = Collections.binarySearch(height, bottom);
// if (iBottom < 0) {
// iBottom = -1-iBottom;
// }
// height.add(iBottom, Math.abs(bottom));
// int iTop = Collections.binarySearch(height, top, floatComparator);
// if (iTop < 0) {
// iTop = -1-iTop;
// }
// if (iTop <= iBottom) {
// iTop = iBottom+1;
// }
//
// height.add(iTop, -top);
// count++;
// }
//
// float score(float bottom, float top) {
// float score = score2(bottom, top);
// if (score < 0) {
// int h = 3;
// h++;
// score = score2(bottom, top);
// }
// return score;
// }
// float score2(float bottom, float top) {
// if (height.size() == 0) {
// return 0;
// }
//
// int iBottom = Collections.binarySearch(height, bottom);
// if (iBottom < 0) {
// iBottom = -1-iBottom;
// }
// int iTop = Collections.binarySearch(height, top, floatComparator);
// if (iTop < 0) {
// iTop = -1-iTop;
// }
//
// int max = height.size()-1;
// if (iBottom > 0) {
// if (iBottom > max) {
// // branch outside region
// float score = cumscore[max] + (top-bottom) * count;
// return score;
// }
// float score = cumscore[iBottom-1];
// score += (bottom - height.get(iBottom-1)) * overlapcount[iBottom-1];
// if (iTop <= max) {
// score += (top - bottom) * count;
// score -= (height.get(iBottom) - bottom) * overlapcount[iBottom-1];
// score -= cumscore[iTop-1] - cumscore[iBottom];
// score -= (top - height.get(iTop-1)) * overlapcount[iTop-1];
// score += (height.get(iTop) - top) * overlapcount[iTop-1];
// score += cumscore[max] - cumscore[iTop];
// return score;
// } else { // iTop >= max
// score += (height.get(max) - bottom) * count;
// score -= (height.get(iBottom) - bottom) * overlapcount[iBottom];
// score -= cumscore[max] - cumscore[iBottom];
// score += (top - height.get(max)) * count;
// return score;
// }
// } else { // iBottom == 0
// if (iTop == 0) {
// // branch outside region
// float score = cumscore[max] + (top-bottom) * count;
// return score;
// }
// if (iTop <= max) {
// float score = (height.get(0) - bottom) * count;
// score += (top - height.get(0)) * count;
// score -= cumscore[iTop-1] - cumscore[0];
// score -= (top - height.get(iTop-1)) * overlapcount[iTop-1];
// score += (height.get(iTop) - top) * overlapcount[iTop-1];
// score += cumscore[max] - cumscore[iTop];
// return score;
// } else { // iTop >= max, branch overlaps complete interval
// float score = (top - bottom) * count - cumscore[max];
// return score;
// }
// }
// }
}