#!/usr/bin/env python3 import argparse import os import glob import json import numpy as np import matplotlib.pyplot as plt import collections from script import script as scriptUtils def main(): args = __parseArguments() print(args) __stats(args["comparisonDir"], args["outputDir"]) def __parseArguments(): argParser = scriptUtils.ArgParser() argParser.addInstanceDirArg(); argParser.addArg(alias="comparisonDir", shortFlag="c", longFlag="comparison_dir", help="the direcotry with all comparison files", type=str) argParser.addArg(alias="outputDir", shortFlag="o", longFlag="comparison_stats_dir", help="Directory to store the stats", type=str) return argParser.parse() def __stats(comparisonDir, outputDir): stats = __collectStats(comparisonDir) __writeStats(stats, outputDir) def __collectStats(comparisonDir): files = glob.glob(os.path.join(comparisonDir, "*.cmp")) stats = [] for path in files: comparison = __readComparison(path) stats.append(__processSingleInstance(comparison)) return stats def __processSingleInstance(comparison): instanceStats = {} conflicts = comparison["conflicts_per_variable"] conflictArr = np.array(list(conflicts.values())) instanceStats["conflicts_per_variable_mean"] = conflictArr.mean() instanceStats["conflicts_per_variable_median"] = np.median(conflictArr) instanceStats["conflicts_per_variable_std_dev"] = np.std(conflictArr) instanceStats["conflicts_per_variable_max"] = conflictArr.max() instanceStats["conflicts_per_variable_min"] = conflictArr.min() instanceStats["conflicts_per_instance"] = np.sum(conflictArr) instanceStats["raw_conflicts"] = list(conflictArr) instanceStats["conflicts_to_degree_per_variable"] = __calcConflictsToDegree(conflicts, comparison["degrees_of_variables"]) if comparison["minisat_satisfiable"]: if __instanceIsFalseNegative(comparison): instanceStats["result"] = "false_negative" else: instanceStats["result"] = "satisfiable" else: instanceStats["result"] = "unsatisfiable" return instanceStats def __calcConflictsToDegree(degreesPerVariable, conflictsPerVariable): conflictsToDegreePerVariable = [] for varLabel, degree in degreesPerVariable.items(): conflicts = conflictsPerVariable[varLabel] cnflToDeg = conflicts / (float(degree) / 2.0)**2 if cnflToDeg <= 1: conflictsToDegreePerVariable.append(cnflToDeg) return conflictsToDegreePerVariable def __instanceIsFalseNegative(comparison): return (comparison["minisat_satisfiable"] == True and comparison["qubo_satisfiable"] == False) def __readComparison(path): cmpFile = open(path, "r") comparison = json.load(cmpFile) cmpFile.close() return comparison def __writeStats(stats, outputDir): data = __seperateMatchesAndFalseNegatives(stats) overviewFig = __createOverviewFig(data) meanFig = __createSingleStatFig(data["mean"], "Conflicts per variable mean") medianFig = __createSingleStatFig(data["median"], "Conflicts per variable median") maxFig = __createSingleStatFig(data["max"], "Conflicts per variable max") minFig = __createSingleStatFig(data["min"], "Conflicts per variable min") stdDevFig = __createSingleStatFig(data["std_dev"], "Conflicts per variable\nstandard deviation") cnflPerInstFig = __createSingleStatFig(data["cnfl_per_inst"], "Conflicts per instance") cnflDegFig1 = __createSingleStatFig(data["cnflDeg"], "Conflicts in relation to degree", showfliers=False); cnflDegFig2 = __createSingleStatFig(data["cnflDeg"], "Conflicts in relation to degree", showfliers=True); histFig = __createHistogramFig(data, "raw", "Conflict per variable"); #cnflDegHistFig = __createHistogramFig(data, "cnflDeg", "Conflicts in relation to degree"); __setBatchXticks(figures=[overviewFig, meanFig, medianFig, maxFig, minFig, stdDevFig, cnflPerInstFig, cnflDegFig1, cnflDegFig2], ticks=[1, 2, 3], labels=["satisfiable", "false negative", "unsatisfiable"]) __setBatchXtickLabelRotation(figures=[overviewFig, meanFig, medianFig, maxFig, minFig, stdDevFig, cnflPerInstFig, cnflDegFig1, cnflDegFig2], rotation=30) overviewFig.savefig(os.path.join(outputDir, "conflicts_overview.png")) meanFig.savefig(os.path.join(outputDir, "conflicts_mean.png")) medianFig.savefig(os.path.join(outputDir, "conflicts_median.png")) maxFig.savefig(os.path.join(outputDir, "conflicts_max.png")) minFig.savefig(os.path.join(outputDir, "conflicts_min.png")) stdDevFig.savefig(os.path.join(outputDir, "conflicts_std_dev.png")) cnflPerInstFig.savefig(os.path.join(outputDir, "conflicts_per_instance.png")) histFig.savefig(os.path.join(outputDir, "conflicts_per_var_hist.png")) cnflDegFig1.savefig(os.path.join(outputDir, "conflicts_in_relation_to_degree_1.png")) cnflDegFig2.savefig(os.path.join(outputDir, "conflicts_in_relation_to_degree_2.png")) #plt.show(overviewFig) def __createOverviewFig(data): fig = plt.figure() ax0 = fig.add_subplot(141,) ax0.boxplot([data["mean"]["satisfiable"], data["mean"]["false_negative"], data["mean"]["unsatisfiable"]]) ax0.set_title("mean") ax1 = fig.add_subplot(142, sharey=ax0) ax1.boxplot([data["median"]["satisfiable"], data["median"]["false_negative"], data["median"]["unsatisfiable"]]) ax1.set_title("median") ax2 = fig.add_subplot(143, sharey=ax0) ax2.boxplot([data["max"]["satisfiable"], data["max"]["false_negative"], data["max"]["unsatisfiable"]]) ax2.set_title("max degree") ax3 = fig.add_subplot(144, sharey=ax0) ax3.boxplot([data["min"]["satisfiable"], data["min"]["false_negative"], data["min"]["unsatisfiable"]]) ax3.set_title("min degree") fig.set_size_inches(12, 8) fig.suptitle("Conflicts per variable overview", fontsize=16) return fig def __createHistogramFig(data, subDataSet, title): fig = plt.figure() bins = int(max(data[subDataSet]["satisfiable"]) / 5) ax0 = fig.add_subplot(321) ax0.hist(data[subDataSet]["satisfiable"], bins=bins) ax0_2 = fig.add_subplot(322) ax0_2.boxplot(data[subDataSet]["satisfiable"], vert=False) ax1 = fig.add_subplot(323, sharex=ax0) ax1.hist(data[subDataSet]["false_negative"], bins=bins) ax1_2 = fig.add_subplot(324, sharex=ax0_2) ax1_2.boxplot(data[subDataSet]["false_negative"], vert=False) ax2 = fig.add_subplot(325, sharex=ax0) ax2.hist(data[subDataSet]["unsatisfiable"], bins=bins) ax2_2 = fig.add_subplot(326, sharex=ax0_2) ax2_2.boxplot(data[subDataSet]["unsatisfiable"], vert=False) fig.set_size_inches(14, 10) fig.suptitle(title, fontsize=16) return fig def __createSingleStatFig(subDataset, title, showfliers=True): fig = plt.figure() ax = fig.add_subplot(111) ax.boxplot([subDataset["satisfiable"], subDataset["false_negative"], subDataset["unsatisfiable"]], showfliers=showfliers) fig.set_size_inches(3.5, 8) fig.suptitle(title, fontsize=16) return fig def __setBatchXticks(figures, ticks, labels): for fig in figures: plt.setp(fig.get_axes(), xticks=ticks, xticklabels=labels) def __setBatchXtickLabelRotation(figures, rotation): for fig in figures: for ax in fig.get_axes(): plt.setp(ax.get_xticklabels(), rotation=rotation) def __seperateMatchesAndFalseNegatives(stats): data = {} data["mean"] = {"false_negative": [], "satisfiable": [], "unsatisfiable": []} data["median"] = {"false_negative": [], "satisfiable": [], "unsatisfiable": []} data["std_dev"] = {"false_negative": [], "satisfiable": [], "unsatisfiable": []} data["max"] = {"false_negative": [], "satisfiable": [], "unsatisfiable": []} data["min"] = {"false_negative": [], "satisfiable": [], "unsatisfiable": []} data["cnfl_per_inst"] = {"false_negative": [], "satisfiable": [], "unsatisfiable": []} data["raw"] = {"false_negative": [], "satisfiable": [], "unsatisfiable": []} data["cnflDeg"] = {"false_negative": [], "satisfiable": [], "unsatisfiable": []} for instance in stats: target = instance["result"] data["mean"][target].append(instance["conflicts_per_variable_mean"]) data["median"][target].append(instance["conflicts_per_variable_median"]) data["std_dev"][target].append(instance["conflicts_per_variable_std_dev"]) data["max"][target].append(instance["conflicts_per_variable_max"]) data["min"][target].append(instance["conflicts_per_variable_min"]) data["cnfl_per_inst"][target].append(instance["conflicts_per_instance"]) data["raw"][target].extend(instance["raw_conflicts"]) data["cnflDeg"][target].extend(instance["conflicts_to_degree_per_variable"]) return data if __name__ == "__main__": main()