package beast.util;
import static beast.util.OutputUtils.format;
import java.io.File;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
import beast.app.BEASTVersion2;
import beast.app.util.Utils;
/**
* Compare log files to find the set of parameters same between logs but having significantly different value.
* Z score = 2 * |mean1 - mean2| / (stdError1 + stdError2), If Z score > 2 it is significant.
* It is limited to 2 logs at a time at moment.
*
* @author Walter Xie
*/
public class LogComparator {
/**
* matched column labels in log files
*/
protected List<String> matchedLabels;
protected Double[] zScore; // Z score
protected LogAnalyser analyser1, analyser2;
/**
* at least 2 logs
* @param analyser1
* @param analyser2
*/
public LogComparator (LogAnalyser analyser1, LogAnalyser analyser2) {
assert analyser1 != null;
assert analyser2 != null;
this.analyser1 = analyser1;
this.analyser2 = analyser2;
compareLogs();
}
public double getZScore(String label) {
int index = matchedLabels.indexOf(label);
if (index < 0)
throw new IllegalArgumentException("Cannot find " + label + " from matched parameter list !");
return zScore[index];
}
protected void compareLogs() {
matchedLabels = CollectionUtils.intersection(analyser1.getLabels(), analyser2.getLabels());
if (matchedLabels.size() < 1)
throw new IllegalArgumentException("There is no parameter name matched between log files !");
zScore = new Double[matchedLabels.size()];
for (String mLabel : matchedLabels) {
int index1 = analyser1.indexof(mLabel);
double m1 = analyser1.getMean(index1);
double se1 = analyser1.getStdError(index1);
int index2 = analyser2.indexof(mLabel);
double m2 = analyser2.getMean(index2);
double se2 = analyser2.getStdError(index2);
int index = matchedLabels.indexOf(mLabel);
// Z score = 2 * |m1 - m2| / (se1 + se2), If Z score > 2 it is significant
zScore[index] = 2 * Math.abs(m1 - m2) / (se1 + se2);
}
}
final String SPACE = OutputUtils.SPACE;
final String STAR = "* ";
final String NON_STAR = " ";
public void print(PrintStream out, boolean verbose) {
// set up header for prefix, if any is specified
String prefix = System.getProperty("prefix");
String prefixHead = (prefix == null ? "" : "prefix ");
if (prefix != null) {
String [] p = prefix.trim().split("\\s+");
if (p.length > 1) {
prefixHead = "";
for (int i = 0; i < p.length; i++) {
prefixHead += "prefix" + i + " ";
}
}
}
int max = 0;
for (int i = 1; i < matchedLabels.size(); i++)
max = Math.max(matchedLabels.get(i).length(), max);
String space = "";
for (int i = 0; i < max; i++)
space += " ";
out.println("Comparing log " + analyser1.getLogFile() + " and " + analyser2.getLogFile() + "\n");
List<String> significantLabels = new ArrayList<>();
if (verbose) {
out.println("item" + space.substring(4) + " " + prefixHead + " " + format("ZScore") +
format("mean1") + format("stderr1") + format("mean2") + format("stderr2"));
for (int i = 1; i < matchedLabels.size(); i++) {
String mLabel = matchedLabels.get(i);
int index1 = analyser1.indexof(mLabel);
double m1 = analyser1.getMean(index1);
double se1 = analyser1.getStdError(index1);
int index2 = analyser2.indexof(mLabel);
double m2 = analyser2.getMean(index2);
double se2 = analyser2.getStdError(index2);
out.println(mLabel + space.substring(mLabel.length()) + SPACE + (prefix == null ? "" : prefix + SPACE) +
(zScore[i] > 2 ? STAR : NON_STAR) + SPACE + format(zScore[i]) + SPACE +
format(m1) + SPACE + format(se1) + SPACE + format(m2) + SPACE + format(se2));
if (zScore[i] > 2) significantLabels.add(mLabel);
}
}
out.println("\nThere are " + significantLabels.size() + " parameters having significantly different value : " +
OutputUtils.toString(significantLabels) + "\n\n");
}
/**
* main
*/
public static void main(String[] args) {
LogAnalyser analyser1 = null;
LogAnalyser analyser2 = null;
try {
if (args.length == 0) {
BEASTVersion2 version = new BEASTVersion2();
File file = Utils.getLoadFile("LogComparator " + version.getVersionString() + " - Select first log file to analyse",
null, "BEAST log (*.log) Files", "log", "txt");
if (file == null) {
return;
}
analyser1 = new LogAnalyser(file.getAbsolutePath());
file = Utils.getLoadFile("LogComparator " + version.getVersionString() + " - Select second log file to analyse",
null, "BEAST log (*.log) Files", "log", "txt");
if (file == null) {
return;
}
analyser2 = new LogAnalyser(file.getAbsolutePath());
} else {
analyser1 = new LogAnalyser(args[0]);
analyser2 = new LogAnalyser(args[1]);
}
} catch (Exception e) {
e.printStackTrace();
}
LogComparator logComparator = new LogComparator(analyser1, analyser2);
logComparator.print(System.out, true);
} // main
}