#!/usr/bin/env python3 import argparse import os import glob import json import numpy as np import matplotlib.pyplot as plt import collections def main(): args = __parseArguments() __stats(args["comparisonDir"], args["outputDir"]) def __parseArguments(): parser = argparse.ArgumentParser() parser.add_argument("-d", "--directory", help="the direcotry with all comparison files", type=str) parser.add_argument("-o", "--output", help="Directory to store the stats", type=str) args = parser.parse_args() arguments = {} print(args) arguments["comparisonDir"] = args.directory if arguments["comparisonDir"] == None: arguments["comparisonDir"] = str(input("Comparison directory: ")) arguments["comparisonDir"] = os.path.abspath(arguments["comparisonDir"]) arguments["outputDir"] = args.output if arguments["outputDir"] == None: arguments["outputDir"] = str(input("Output directory: ")) arguments["outputDir"] = os.path.abspath(arguments["outputDir"]) return arguments 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 = {} degrees = comparison["degrees_of_variables"] degreeArr = np.array(list(degrees.values())) instanceStats["degree_of_variables_mean"] = degreeArr.mean() instanceStats["degree_of_variables_median"] = np.median(degreeArr) instanceStats["degree_of_variables_std_dev"] = np.std(degreeArr) instanceStats["degree_of_variables_max"] = degreeArr.max() instanceStats["degree_of_variables_min"] = degreeArr.min() instanceStats["variables_per_degree"] = __getVarsPerDegree(degreeArr) if comparison["minisat_satisfiable"]: if __instanceIsFalseNegative(comparison): instanceStats["result"] = "false_negative" else: instanceStats["result"] = "satisfiable" else: instanceStats["result"] = "unsatisfiable" return instanceStats def __instanceIsFalseNegative(comparison): return (comparison["minisat_satisfiable"] == True and comparison["qubo_satisfiable"] == False) def __getVarsPerDegree(degreeArr): degCount = collections.Counter(degreeArr) varsPerDegree = {} for degree in degCount: varsPerDegree[degree] = degCount[degree] return varsPerDegree def __readComparison(path): cmpFile = open(path, "r") comparison = json.load(cmpFile) cmpFile.close() return comparison def __writeStats(stats, outputDir): fig1 = plt.figure() data = __seperateMatchesAndFalseNegatives(stats) ax0 = fig1.add_subplot(141,) ax0.boxplot([data["mean"]["satisfiable"], data["mean"]["false_negative"], data["mean"]["unsatisfiable"]]) ax0.set_title("mean") ax1 = fig1.add_subplot(142, sharey=ax0) ax1.boxplot([data["median"]["satisfiable"], data["median"]["false_negative"], data["median"]["unsatisfiable"]]) ax1.set_title("median") ax2 = fig1.add_subplot(143, sharey=ax0) ax2.boxplot([data["max"]["satisfiable"], data["max"]["false_negative"], data["max"]["unsatisfiable"]]) ax2.set_title("max degree") ax3 = fig1.add_subplot(144, sharey=ax0) ax3.boxplot([data["min"]["satisfiable"], data["min"]["false_negative"], data["min"]["unsatisfiable"]]) ax3.set_title("min degree") fig2 = plt.figure() ax4 = fig2.add_subplot(111) ax4.boxplot([data["std_dev"]["satisfiable"], data["std_dev"]["false_negative"], data["std_dev"]["unsatisfiable"]]) ax4.set_title("standard deviation") _BINS_ = 23 fig3 = plt.figure() ax5 = fig3.add_subplot(311) varsPerDegreeSat = __accumulateVarsPerDegree(data["vars_per_degree"]["satisfiable"]) ax5.hist(varsPerDegreeSat, density=True, bins=_BINS_) ax6 = fig3.add_subplot(312, sharex=ax5) varsPerDegreeFP = __accumulateVarsPerDegree(data["vars_per_degree"]["false_negative"]) ax6.hist(varsPerDegreeFP, density=True, bins=_BINS_) ax7 = fig3.add_subplot(313, sharex=ax6) varsPerDegreeUnsat = __accumulateVarsPerDegree(data["vars_per_degree"]["unsatisfiable"]) ax7.hist(varsPerDegreeUnsat, density=True, bins=_BINS_) plt.setp([ax0, ax1, ax2, ax3, ax4], xticks=[1, 2, 3], xticklabels=["satisfiable", "false negative", "unsatisfiable"]) plt.setp(ax0.get_xticklabels(), rotation=45) plt.setp(ax1.get_xticklabels(), rotation=45) plt.setp(ax2.get_xticklabels(), rotation=45) plt.setp(ax3.get_xticklabels(), rotation=45) plt.setp(ax4.get_xticklabels(), rotation=45) fig1.set_size_inches(12, 8) fig1.suptitle("Degrees of variables", fontsize=16) fig2.set_size_inches(4, 8) fig3.set_size_inches(5, 12) fig1.savefig(os.path.join(outputDir, "degrees1.png")) fig2.savefig(os.path.join(outputDir, "degrees2.png")) fig3.savefig(os.path.join(outputDir, "degrees3.png")) plt.show() def __accumulateVarsPerDegree(listOfVarsPerDegreeDicts): accumulated = [] for instance in listOfVarsPerDegreeDicts: for degree in instance: accumulated += [degree] * instance[degree] return accumulated def __compressVarsPerDegree(listOfVarsPerDegreeDicts): compressed = {} countOfVars = 0 for instance in listOfVarsPerDegreeDicts: for degree in instance: if degree in compressed: compressed[degree] += float(instance[degree]) else: compressed[degree] = float(instance[degree]) countOfVars += instance[degree] check = 0 for degree in compressed: compressed[degree] /= countOfVars check += compressed[degree] print("check: ", check) return compressed 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["vars_per_degree"] = {"false_negative": [], "satisfiable": [], "unsatisfiable": []} for instance in stats: target = instance["result"] data["mean"][target].append(instance["degree_of_variables_mean"]) data["median"][target].append(instance["degree_of_variables_median"]) data["std_dev"][target].append(instance["degree_of_variables_std_dev"]) data["max"][target].append(instance["degree_of_variables_max"]) data["min"][target].append(instance["degree_of_variables_min"]) data["vars_per_degree"][target].append(instance["variables_per_degree"]) return data if __name__ == "__main__": main()