You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

256 lines
7.9 KiB

6 years ago
  1. #!/usr/bin/env python3
  2. import argparse
  3. import os
  4. import glob
  5. import json
  6. import numpy as np
  7. import matplotlib.pyplot as plt
  8. import collections
  9. def main():
  10. args = __parseArguments()
  11. __stats(args["comparisonDir"], args["outputDir"])
  12. def __parseArguments():
  13. parser = argparse.ArgumentParser()
  14. parser.add_argument("-d", "--directory", help="the direcotry with all comparison files", type=str)
  15. parser.add_argument("-o", "--output", help="Directory to store the stats", type=str)
  16. args = parser.parse_args()
  17. arguments = {}
  18. print(args)
  19. arguments["comparisonDir"] = args.directory
  20. if arguments["comparisonDir"] == None:
  21. arguments["comparisonDir"] = str(input("Comparison directory: "))
  22. arguments["comparisonDir"] = os.path.abspath(arguments["comparisonDir"])
  23. arguments["outputDir"] = args.output
  24. if arguments["outputDir"] == None:
  25. arguments["outputDir"] = str(input("Output directory: "))
  26. arguments["outputDir"] = os.path.abspath(arguments["outputDir"])
  27. return arguments
  28. def __stats(comparisonDir, outputDir):
  29. stats = __collectStats(comparisonDir)
  30. __writeStats(stats, outputDir)
  31. def __collectStats(comparisonDir):
  32. files = glob.glob(os.path.join(comparisonDir, "*.cmp"))
  33. stats = []
  34. for path in files:
  35. comparison = __readComparison(path)
  36. stats.append(__processSingleInstance(comparison))
  37. return stats
  38. def __processSingleInstance(comparison):
  39. instanceStats = {}
  40. degrees = comparison["degrees_of_variables"]
  41. degreeArr = np.array(list(degrees.values()))
  42. instanceStats["degree_of_variables_mean"] = degreeArr.mean()
  43. instanceStats["degree_of_variables_median"] = np.median(degreeArr)
  44. instanceStats["degree_of_variables_std_dev"] = np.std(degreeArr)
  45. instanceStats["degree_of_variables_max"] = degreeArr.max()
  46. instanceStats["degree_of_variables_min"] = degreeArr.min()
  47. instanceStats["variables_per_degree"] = __getVarsPerDegree(degreeArr)
  48. if comparison["minisat_satisfiable"]:
  49. if __instanceIsFalseNegative(comparison):
  50. instanceStats["result"] = "false_negative"
  51. else:
  52. instanceStats["result"] = "satisfiable"
  53. else:
  54. instanceStats["result"] = "unsatisfiable"
  55. return instanceStats
  56. def __instanceIsFalseNegative(comparison):
  57. return (comparison["minisat_satisfiable"] == True and
  58. comparison["qubo_satisfiable"] == False)
  59. def __getVarsPerDegree(degreeArr):
  60. degCount = collections.Counter(degreeArr)
  61. varsPerDegree = {}
  62. for degree in degCount:
  63. varsPerDegree[degree] = degCount[degree]
  64. return varsPerDegree
  65. def __readComparison(path):
  66. cmpFile = open(path, "r")
  67. comparison = json.load(cmpFile)
  68. cmpFile.close()
  69. return comparison
  70. def __writeStats(stats, outputDir):
  71. fig1 = plt.figure()
  72. data = __seperateMatchesAndFalseNegatives(stats)
  73. ax0 = fig1.add_subplot(141,)
  74. ax0.boxplot([data["mean"]["satisfiable"],
  75. data["mean"]["false_negative"],
  76. data["mean"]["unsatisfiable"]])
  77. ax0.set_title("mean")
  78. ax1 = fig1.add_subplot(142, sharey=ax0)
  79. ax1.boxplot([data["median"]["satisfiable"],
  80. data["median"]["false_negative"],
  81. data["median"]["unsatisfiable"]])
  82. ax1.set_title("median")
  83. ax2 = fig1.add_subplot(143, sharey=ax0)
  84. ax2.boxplot([data["max"]["satisfiable"],
  85. data["max"]["false_negative"],
  86. data["max"]["unsatisfiable"]])
  87. ax2.set_title("max degree")
  88. ax3 = fig1.add_subplot(144, sharey=ax0)
  89. ax3.boxplot([data["min"]["satisfiable"],
  90. data["min"]["false_negative"],
  91. data["min"]["unsatisfiable"]])
  92. ax3.set_title("min degree")
  93. fig2 = plt.figure()
  94. ax4 = fig2.add_subplot(111)
  95. ax4.boxplot([data["std_dev"]["satisfiable"],
  96. data["std_dev"]["false_negative"],
  97. data["std_dev"]["unsatisfiable"]])
  98. ax4.set_title("standard deviation")
  99. _BINS_ = 23
  100. fig3 = plt.figure()
  101. ax5 = fig3.add_subplot(311)
  102. varsPerDegreeSat = __accumulateVarsPerDegree(data["vars_per_degree"]["satisfiable"])
  103. ax5.hist(varsPerDegreeSat, density=True, bins=_BINS_)
  104. ax6 = fig3.add_subplot(312, sharex=ax5)
  105. varsPerDegreeFP = __accumulateVarsPerDegree(data["vars_per_degree"]["false_negative"])
  106. ax6.hist(varsPerDegreeFP, density=True, bins=_BINS_)
  107. ax7 = fig3.add_subplot(313, sharex=ax6)
  108. varsPerDegreeUnsat = __accumulateVarsPerDegree(data["vars_per_degree"]["unsatisfiable"])
  109. ax7.hist(varsPerDegreeUnsat, density=True, bins=_BINS_)
  110. plt.setp([ax0, ax1, ax2, ax3, ax4], xticks=[1, 2, 3], xticklabels=["satisfiable",
  111. "false negative",
  112. "unsatisfiable"])
  113. plt.setp(ax0.get_xticklabels(), rotation=45)
  114. plt.setp(ax1.get_xticklabels(), rotation=45)
  115. plt.setp(ax2.get_xticklabels(), rotation=45)
  116. plt.setp(ax3.get_xticklabels(), rotation=45)
  117. plt.setp(ax4.get_xticklabels(), rotation=45)
  118. fig1.set_size_inches(12, 8)
  119. fig1.suptitle("Degrees of variables", fontsize=16)
  120. fig2.set_size_inches(4, 8)
  121. fig3.set_size_inches(5, 12)
  122. fig1.savefig(os.path.join(outputDir, "degrees1.png"))
  123. fig2.savefig(os.path.join(outputDir, "degrees2.png"))
  124. fig3.savefig(os.path.join(outputDir, "degrees3.png"))
  125. plt.show()
  126. def __accumulateVarsPerDegree(listOfVarsPerDegreeDicts):
  127. accumulated = []
  128. for instance in listOfVarsPerDegreeDicts:
  129. for degree in instance:
  130. accumulated += [degree] * instance[degree]
  131. return accumulated
  132. def __compressVarsPerDegree(listOfVarsPerDegreeDicts):
  133. compressed = {}
  134. countOfVars = 0
  135. for instance in listOfVarsPerDegreeDicts:
  136. for degree in instance:
  137. if degree in compressed:
  138. compressed[degree] += float(instance[degree])
  139. else:
  140. compressed[degree] = float(instance[degree])
  141. countOfVars += instance[degree]
  142. check = 0
  143. for degree in compressed:
  144. compressed[degree] /= countOfVars
  145. check += compressed[degree]
  146. print("check: ", check)
  147. return compressed
  148. def __seperateMatchesAndFalseNegatives(stats):
  149. data = {}
  150. data["mean"] = {"false_negative": [],
  151. "satisfiable": [],
  152. "unsatisfiable": []}
  153. data["median"] = {"false_negative": [],
  154. "satisfiable": [],
  155. "unsatisfiable": []}
  156. data["std_dev"] = {"false_negative": [],
  157. "satisfiable": [],
  158. "unsatisfiable": []}
  159. data["max"] = {"false_negative": [],
  160. "satisfiable": [],
  161. "unsatisfiable": []}
  162. data["min"] = {"false_negative": [],
  163. "satisfiable": [],
  164. "unsatisfiable": []}
  165. data["vars_per_degree"] = {"false_negative": [],
  166. "satisfiable": [],
  167. "unsatisfiable": []}
  168. for instance in stats:
  169. target = instance["result"]
  170. data["mean"][target].append(instance["degree_of_variables_mean"])
  171. data["median"][target].append(instance["degree_of_variables_median"])
  172. data["std_dev"][target].append(instance["degree_of_variables_std_dev"])
  173. data["max"][target].append(instance["degree_of_variables_max"])
  174. data["min"][target].append(instance["degree_of_variables_min"])
  175. data["vars_per_degree"][target].append(instance["variables_per_degree"])
  176. return data
  177. if __name__ == "__main__":
  178. main()