import java.io.BufferedReader;
import java.io.FileReader;
import java.util.ArrayList;

/*
 * At the bottom, change size to 2*size if computing all
 * ECFGs with order N since B and -B give the same ECFG.
 *
 * If you go large enough (say, over 1 million graphs),
 * you may need to adjust the heapsize (I think Java's
 * default is 96 megs?)
 */

public class ECstats {

	public static void main(String[] args) {
		int N = 997;
		String filename = "" + N + "out.txt";
		ArrayList<String> graphs = new ArrayList<String>();
		try { /* read file */
			BufferedReader in = new BufferedReader(new FileReader(filename));
			while(in.ready())
				graphs.add(in.readLine());
		} catch (Exception e) {
			System.err.println(e);
		} /* end read file */

		/* make arrays for each statistic (array indices range over all the graphs) */
		int size = graphs.size();
		int[] terminalNodes = new int[size];
		int[] imageNodes = new int[size];
		int[] fixedPoints = new int[size];
		int[] twoCycles = new int[size];
		int[] threeCycles = new int[size];
		int[] fiveCycles = new int[size];
		int[] components = new int[size];
		double[] avgCycleSize = new double[size];
		int[] cyclicNodes = new int[size];
		int[] tailNodes = new int[size];
		double[] avgCycle = new double[size];
		double[] avgTail = new double[size];
		int[] maxCycle = new int[size];
		int[] maxTail = new int[size];
		int i = 0;
		int maxCyclea = 1;
		/* end make arrays */

		/* fill arrays */
		for(String graph : graphs) {
			terminalNodes[i] = Integer.parseInt(graph.substring(0, graph.indexOf(' ')));
			graph = graph.substring(graph.indexOf(' ') + 1);
			imageNodes[i] = Integer.parseInt(graph.substring(0, graph.indexOf(' ')));
			graph = graph.substring(graph.indexOf(' ') + 1);
			fixedPoints[i] = Integer.parseInt(graph.substring(0, graph.indexOf(' ')));
			graph = graph.substring(graph.indexOf(' ') + 1);
			twoCycles[i] = Integer.parseInt(graph.substring(0, graph.indexOf(' ')));
			graph = graph.substring(graph.indexOf(' ') + 1);
			threeCycles[i] = Integer.parseInt(graph.substring(0, graph.indexOf(' ')));
			graph = graph.substring(graph.indexOf(' ') + 1);
			fiveCycles[i] = Integer.parseInt(graph.substring(0, graph.indexOf(' ')));
			graph = graph.substring(graph.indexOf(' ') + 1);
			components[i] = Integer.parseInt(graph.substring(0, graph.indexOf(' ')));
			graph = graph.substring(graph.indexOf(' ') + 1);
			avgCycleSize[i] = Double.parseDouble(graph.substring(0, graph.indexOf(' ')));
			graph = graph.substring(graph.indexOf(' ') + 1);
			cyclicNodes[i] = Integer.parseInt(graph.substring(0, graph.indexOf(' ')));
			graph = graph.substring(graph.indexOf(' ') + 1);
			tailNodes[i] = Integer.parseInt(graph.substring(0, graph.indexOf(' ')));
			graph = graph.substring(graph.indexOf(' ') + 1);
			avgCycle[i] = Double.parseDouble(graph.substring(0, graph.indexOf(' ')));
			graph = graph.substring(graph.indexOf(' ') + 1);
			avgTail[i] = Double.parseDouble(graph.substring(0, graph.indexOf(' ')));
			graph = graph.substring(graph.indexOf(' ') + 1);
			maxCycle[i] = Integer.parseInt(graph.substring(0, graph.indexOf(' ')));
			graph = graph.substring(graph.indexOf(' ') + 1);
			if(maxCycle[i] > maxCyclea)
				maxCyclea = maxCycle[i];
			maxTail[i] = Integer.parseInt(graph);
			i++;
		} /* end fill arrays */

		/* compute averages */
		double terminalNodesAvg, imageNodesAvg, fixedPointsAvg, twoCyclesAvg, threeCyclesAvg, fiveCyclesAvg,
		componentsAvg, avgCycleSizeAvg, cyclicNodesAvg, tailNodesAvg, avgCycleAvg, avgTailAvg, maxCycleAvg,
		maxTailAvg;
		terminalNodesAvg = imageNodesAvg = fixedPointsAvg = twoCyclesAvg = threeCyclesAvg = fiveCyclesAvg = componentsAvg = avgCycleSizeAvg = cyclicNodesAvg = tailNodesAvg = avgCycleAvg = avgTailAvg = maxCycleAvg = maxTailAvg = 0;
		for(i = 0; i < size; i++) {
			terminalNodesAvg += terminalNodes[i];
			imageNodesAvg += imageNodes[i];
			fixedPointsAvg += fixedPoints[i];
			twoCyclesAvg += twoCycles[i];
			threeCyclesAvg += threeCycles[i];
			fiveCyclesAvg += fiveCycles[i];
			componentsAvg += components[i];
			avgCycleSizeAvg += avgCycleSize[i];
			cyclicNodesAvg += cyclicNodes[i];
			tailNodesAvg += tailNodes[i];
			avgCycleAvg += avgCycle[i];
			avgTailAvg += avgTail[i];
			maxCycleAvg += maxCycle[i];
			maxTailAvg += maxTail[i];
		}
		terminalNodesAvg /= size;
		imageNodesAvg /= size;
		fixedPointsAvg /= size;
		twoCyclesAvg /= size;
		threeCyclesAvg /= size;
		fiveCyclesAvg /= size;
		componentsAvg /= size;
		avgCycleSizeAvg /= size;
		cyclicNodesAvg /= size;
		tailNodesAvg /= size;
		avgCycleAvg /= size;
		avgTailAvg /= size;
		maxCycleAvg /= size;
		maxTailAvg /= size;
		/* end compute averages */

		/* compute variances */
		double terminalNodesVar, imageNodesVar, fixedPointsVar, twoCyclesVar, threeCyclesVar, fiveCyclesVar,
		componentsVar, avgCycleSizeVar, cyclicNodesVar, tailNodesVar, avgCycleVar, avgTailVar, maxCycleVar,
		maxTailVar;
		terminalNodesVar = imageNodesVar = fixedPointsVar = twoCyclesVar = threeCyclesVar = fiveCyclesVar = componentsVar = avgCycleSizeVar = cyclicNodesVar = tailNodesVar = avgCycleVar = avgTailVar = maxCycleVar = maxTailVar = 0;
		for(i = 0; i < size; i++) {
			terminalNodesVar += (terminalNodes[i] - terminalNodesAvg)*(terminalNodes[i] - terminalNodesAvg);
			imageNodesVar += (imageNodes[i] - imageNodesAvg)*(imageNodes[i] - imageNodesAvg);
			fixedPointsVar += (fixedPoints[i] - fixedPointsAvg)*(fixedPoints[i] - fixedPointsAvg);
			twoCyclesVar += (twoCycles[i] - twoCyclesAvg)*(twoCycles[i] - twoCyclesAvg);
			threeCyclesVar += (threeCycles[i] - threeCyclesAvg)*(threeCycles[i] - threeCyclesAvg);
			fiveCyclesVar += (fiveCycles[i] - fiveCyclesAvg)*(fiveCycles[i] - fiveCyclesAvg);
			componentsVar += (components[i] - componentsAvg)*(components[i] - componentsAvg);
			avgCycleSizeVar += (avgCycleSize[i] - avgCycleSizeAvg)*(avgCycleSize[i] - avgCycleSizeAvg);
			cyclicNodesVar += (cyclicNodes[i] - cyclicNodesAvg)*(cyclicNodes[i] - cyclicNodesAvg);
			tailNodesVar += (tailNodes[i] - tailNodesAvg)*(tailNodes[i] - tailNodesAvg);
			avgCycleVar += (avgCycle[i] - avgCycleAvg)*(avgCycle[i] - avgCycleAvg);
			avgTailVar += (avgTail[i] - avgTailAvg)*(avgTail[i] - avgTailAvg);
			maxCycleVar += (maxCycle[i] - maxCycleAvg)*(maxCycle[i] - maxCycleAvg);
			maxTailVar += (maxTail[i] - maxTailAvg)*(maxTail[i] - maxTailAvg);
		}
		terminalNodesVar /= size;
		imageNodesVar /= size;
		fixedPointsVar /= size;
		twoCyclesVar /= size;
		threeCyclesVar /= size;
		fiveCyclesVar /= size;
		componentsVar /= size;
		avgCycleSizeVar /= size;
		cyclicNodesVar /= size;
		tailNodesVar /= size;
		avgCycleVar /= size;
		avgTailVar /= size;
		maxCycleVar /= size;
		maxTailVar /= size;
		/* end compute variances */

		/* compute standard deviation */
		double terminalNodesStd, imageNodesStd, fixedPointsStd, twoCyclesStd, threeCyclesStd, fiveCyclesStd,
		componentsStd, avgCycleSizeStd, cyclicNodesStd, tailNodesStd, avgCycleStd, avgTailStd, maxCycleStd,
		maxTailStd;
		terminalNodesStd = Math.sqrt(terminalNodesVar);
		imageNodesStd = Math.sqrt(imageNodesVar);
		fixedPointsStd = Math.sqrt(fixedPointsVar);
		twoCyclesStd = Math.sqrt(twoCyclesVar);
		threeCyclesStd = Math.sqrt(threeCyclesVar);
		fiveCyclesStd = Math.sqrt(fiveCyclesVar);
		componentsStd = Math.sqrt(componentsVar);
		avgCycleSizeStd = Math.sqrt(avgCycleSizeVar);
		cyclicNodesStd = Math.sqrt(cyclicNodesVar);
		tailNodesStd = Math.sqrt(tailNodesVar);
		avgCycleStd = Math.sqrt(avgCycleVar);
		avgTailStd = Math.sqrt(avgTailVar);
		maxCycleStd = Math.sqrt(maxCycleVar);
		maxTailStd = Math.sqrt(maxTailVar);
		/* end compute standard deviation

		/* compute expectations for 10 of the 14 statistics (expectations for k-cycles is 1/k) */
		double gamma = 0.5772156649;
		double terminalNodesExp = (N+1)/2;
		double imageNodesExp = (N+1)/2;
		double componentsExp = 0.5*(Math.log(2*(N+1)) + gamma);
		double cyclicNodesExp = Math.sqrt(Math.PI*(N+1)/2) - 1;
		double tailNodesExp = (N+1) - cyclicNodesExp;
		double avgCycleExp = Math.sqrt(Math.PI*(N+1)/8);
		double avgTailExp = Math.sqrt(Math.PI*(N+1)/8);
		double maxCycleExp = 0.78248*Math.sqrt(N+1);
		double maxTailExp = 1.73746*Math.sqrt(N+1) + 1.61371;
		double avgCycleSizeExp = cyclicNodesExp/componentsExp;

		/* end compute expected values */

		/* print stuff out */
		System.out.printf("Terminal Nodes -- expected: %f, mean: %f, variance: %f, stddev %f\n", terminalNodesExp, terminalNodesAvg, terminalNodesVar, terminalNodesStd);
		System.out.printf("Image Nodes -- expected: %f, mean: %f, variance: %f, stddev %f\n", imageNodesExp, imageNodesAvg, imageNodesVar, imageNodesStd);
		System.out.printf("Fixed Points -- mean: %f, variance: %f, stddev %f\n", fixedPointsAvg, fixedPointsVar, fixedPointsStd);
		System.out.printf("2-cycles -- mean: %f, variance: %f, stddev %f\n", twoCyclesAvg, twoCyclesVar, twoCyclesStd);
		System.out.printf("3-cycles -- mean: %f, variance: %f, stddev %f\n", threeCyclesAvg, threeCyclesVar, threeCyclesStd);
		System.out.printf("5-cycles -- mean: %f, variance: %f, stddev %f\n", fiveCyclesAvg, fiveCyclesVar, fiveCyclesStd);
		System.out.printf("Components -- expected: %f, mean: %f, variance: %f, stddev %f\n", componentsExp, componentsAvg, componentsVar, componentsStd);
		System.out.printf("Average Cycle Length -- expected: %f, mean: %f, variance: %f, stddev %f\n", avgCycleSizeExp, avgCycleSizeAvg, avgCycleSizeVar, avgCycleSizeStd);
		System.out.printf("Cyclic Nodes -- expected: %f, mean: %f, variance: %f, stddev %f\n", cyclicNodesExp, cyclicNodesAvg, cyclicNodesVar, cyclicNodesStd);
		System.out.printf("Tail Nodes -- expected: %f, mean: %f, variance: %f, stddev %f\n", tailNodesExp, tailNodesAvg, tailNodesVar, tailNodesStd);
		System.out.printf("Weighted Average Cycle Length -- expected: %f, mean: %f, variance: %f, stddev %f\n", avgCycleExp, avgCycleAvg, avgCycleVar, avgCycleStd);
		System.out.printf("Average Tail Length -- expected: %f, mean: %f, variance: %f, stddev %f\n", avgTailExp, avgTailAvg, avgTailVar, avgTailStd);
		System.out.printf("Max Cycle Length -- expected: %f, mean: %f, variance: %f, stddev %f\n", maxCycleExp, maxCycleAvg, maxCycleVar, maxCycleStd);
		System.out.printf("Max Tail Length -- expected: %f, mean: %f, variance: %f, stddev %f\n", maxTailExp, maxTailAvg, maxTailVar, maxTailStd);
		System.out.println("Binary ECFGs for N = " + N + ": " + size);
		System.out.println("Max cycle over all graphs is " + maxCyclea);
		/* end print stuff out */
	}
}