#!/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()
|