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.

290 lines
10 KiB

6 years ago
6 years ago
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. from script import script as scriptUtils
  10. def main():
  11. args = __parseArguments()
  12. print(args)
  13. __stats(args["comparisonDir"], args["outputDir"])
  14. def __parseArguments():
  15. argParser = scriptUtils.ArgParser()
  16. argParser.addInstanceDirArg();
  17. argParser.addArg(alias="comparisonDir", shortFlag="c", longFlag="comparison_dir",
  18. help="the direcotry with all comparison files", type=str)
  19. argParser.addArg(alias="outputDir", shortFlag="o", longFlag="comparison_stats_dir",
  20. help="Directory to store the stats", type=str)
  21. return argParser.parse()
  22. def __stats(comparisonDir, outputDir):
  23. stats = __collectStats(comparisonDir)
  24. __writeStats(stats, outputDir)
  25. def __collectStats(comparisonDir):
  26. files = glob.glob(os.path.join(comparisonDir, "*.cmp"))
  27. stats = []
  28. for path in files:
  29. comparison = __readComparison(path)
  30. stats.append(__processSingleInstance(comparison))
  31. return stats
  32. def __processSingleInstance(comparison):
  33. instanceStats = {}
  34. conflicts = comparison["conflicts_per_variable"]
  35. conflictArr = np.array(list(conflicts.values()))
  36. instanceStats["conflicts_per_variable_mean"] = conflictArr.mean()
  37. instanceStats["conflicts_per_variable_median"] = np.median(conflictArr)
  38. instanceStats["conflicts_per_variable_std_dev"] = np.std(conflictArr)
  39. instanceStats["conflicts_per_variable_max"] = conflictArr.max()
  40. instanceStats["conflicts_per_variable_min"] = conflictArr.min()
  41. instanceStats["conflicts_per_instance"] = np.sum(conflictArr)
  42. instanceStats["raw_conflicts"] = list(conflictArr)
  43. instanceStats["conflicts_to_degree_per_variable"] = __calcConflictsToDegree(conflicts,
  44. comparison["degrees_of_variables"])
  45. if comparison["minisat_satisfiable"]:
  46. if __instanceIsFalseNegative(comparison):
  47. instanceStats["result"] = "false_negative"
  48. else:
  49. instanceStats["result"] = "satisfiable"
  50. else:
  51. instanceStats["result"] = "unsatisfiable"
  52. return instanceStats
  53. def __calcConflictsToDegree(degreesPerVariable, conflictsPerVariable):
  54. conflictsToDegreePerVariable = []
  55. for varLabel, degree in degreesPerVariable.items():
  56. conflicts = conflictsPerVariable[varLabel]
  57. cnflToDeg = conflicts / (float(degree) / 2.0)**2
  58. if cnflToDeg <= 1:
  59. conflictsToDegreePerVariable.append(cnflToDeg)
  60. return conflictsToDegreePerVariable
  61. def __instanceIsFalseNegative(comparison):
  62. return (comparison["minisat_satisfiable"] == True and
  63. comparison["qubo_satisfiable"] == False)
  64. def __readComparison(path):
  65. cmpFile = open(path, "r")
  66. comparison = json.load(cmpFile)
  67. cmpFile.close()
  68. return comparison
  69. def __writeStats(stats, outputDir):
  70. data = __seperateMatchesAndFalseNegatives(stats)
  71. overviewFig = __createOverviewFig(data)
  72. meanFig = __createSingleStatFig(data["mean"], "Conflicts per variable mean")
  73. medianFig = __createSingleStatFig(data["median"], "Conflicts per variable median")
  74. maxFig = __createSingleStatFig(data["max"], "Conflicts per variable max")
  75. minFig = __createSingleStatFig(data["min"], "Conflicts per variable min")
  76. stdDevFig = __createSingleStatFig(data["std_dev"], "Conflicts per variable\nstandard deviation")
  77. cnflPerInstFig = __createSingleStatFig(data["cnfl_per_inst"], "Conflicts per instance")
  78. cnflDegFig1 = __createSingleStatFig(data["cnflDeg"], "Conflicts in relation to degree", showfliers=False);
  79. cnflDegFig2 = __createSingleStatFig(data["cnflDeg"], "Conflicts in relation to degree", showfliers=True);
  80. histFig = __createHistogramFig(data, "raw", "Conflict per variable");
  81. #cnflDegHistFig = __createHistogramFig(data, "cnflDeg", "Conflicts in relation to degree");
  82. __setBatchXticks(figures=[overviewFig,
  83. meanFig,
  84. medianFig,
  85. maxFig,
  86. minFig,
  87. stdDevFig,
  88. cnflPerInstFig,
  89. cnflDegFig1,
  90. cnflDegFig2],
  91. ticks=[1, 2, 3],
  92. labels=["satisfiable",
  93. "false negative",
  94. "unsatisfiable"])
  95. __setBatchXtickLabelRotation(figures=[overviewFig,
  96. meanFig,
  97. medianFig,
  98. maxFig,
  99. minFig,
  100. stdDevFig,
  101. cnflPerInstFig,
  102. cnflDegFig1,
  103. cnflDegFig2],
  104. rotation=30)
  105. overviewFig.savefig(os.path.join(outputDir, "conflicts_overview.png"))
  106. meanFig.savefig(os.path.join(outputDir, "conflicts_mean.png"))
  107. medianFig.savefig(os.path.join(outputDir, "conflicts_median.png"))
  108. maxFig.savefig(os.path.join(outputDir, "conflicts_max.png"))
  109. minFig.savefig(os.path.join(outputDir, "conflicts_min.png"))
  110. stdDevFig.savefig(os.path.join(outputDir, "conflicts_std_dev.png"))
  111. cnflPerInstFig.savefig(os.path.join(outputDir, "conflicts_per_instance.png"))
  112. histFig.savefig(os.path.join(outputDir, "conflicts_per_var_hist.png"))
  113. cnflDegFig1.savefig(os.path.join(outputDir, "conflicts_in_relation_to_degree_1.png"))
  114. cnflDegFig2.savefig(os.path.join(outputDir, "conflicts_in_relation_to_degree_2.png"))
  115. #plt.show(overviewFig)
  116. def __createOverviewFig(data):
  117. fig = plt.figure()
  118. ax0 = fig.add_subplot(141,)
  119. ax0.boxplot([data["mean"]["satisfiable"],
  120. data["mean"]["false_negative"],
  121. data["mean"]["unsatisfiable"]])
  122. ax0.set_title("mean")
  123. ax1 = fig.add_subplot(142, sharey=ax0)
  124. ax1.boxplot([data["median"]["satisfiable"],
  125. data["median"]["false_negative"],
  126. data["median"]["unsatisfiable"]])
  127. ax1.set_title("median")
  128. ax2 = fig.add_subplot(143, sharey=ax0)
  129. ax2.boxplot([data["max"]["satisfiable"],
  130. data["max"]["false_negative"],
  131. data["max"]["unsatisfiable"]])
  132. ax2.set_title("max degree")
  133. ax3 = fig.add_subplot(144, sharey=ax0)
  134. ax3.boxplot([data["min"]["satisfiable"],
  135. data["min"]["false_negative"],
  136. data["min"]["unsatisfiable"]])
  137. ax3.set_title("min degree")
  138. fig.set_size_inches(12, 8)
  139. fig.suptitle("Conflicts per variable overview", fontsize=16)
  140. return fig
  141. def __createHistogramFig(data, subDataSet, title):
  142. fig = plt.figure()
  143. bins = int(max(data[subDataSet]["satisfiable"]) / 5)
  144. ax0 = fig.add_subplot(321)
  145. ax0.hist(data[subDataSet]["satisfiable"], bins=bins)
  146. ax0_2 = fig.add_subplot(322)
  147. ax0_2.boxplot(data[subDataSet]["satisfiable"], vert=False)
  148. ax1 = fig.add_subplot(323, sharex=ax0)
  149. ax1.hist(data[subDataSet]["false_negative"], bins=bins)
  150. ax1_2 = fig.add_subplot(324, sharex=ax0_2)
  151. ax1_2.boxplot(data[subDataSet]["false_negative"], vert=False)
  152. ax2 = fig.add_subplot(325, sharex=ax0)
  153. ax2.hist(data[subDataSet]["unsatisfiable"], bins=bins)
  154. ax2_2 = fig.add_subplot(326, sharex=ax0_2)
  155. ax2_2.boxplot(data[subDataSet]["unsatisfiable"], vert=False)
  156. fig.set_size_inches(14, 10)
  157. fig.suptitle(title, fontsize=16)
  158. return fig
  159. def __createSingleStatFig(subDataset, title, showfliers=True):
  160. fig = plt.figure()
  161. ax = fig.add_subplot(111)
  162. ax.boxplot([subDataset["satisfiable"],
  163. subDataset["false_negative"],
  164. subDataset["unsatisfiable"]], showfliers=showfliers)
  165. fig.set_size_inches(3.5, 8)
  166. fig.suptitle(title, fontsize=16)
  167. return fig
  168. def __setBatchXticks(figures, ticks, labels):
  169. for fig in figures:
  170. plt.setp(fig.get_axes(), xticks=ticks, xticklabels=labels)
  171. def __setBatchXtickLabelRotation(figures, rotation):
  172. for fig in figures:
  173. for ax in fig.get_axes():
  174. plt.setp(ax.get_xticklabels(), rotation=rotation)
  175. def __seperateMatchesAndFalseNegatives(stats):
  176. data = {}
  177. data["mean"] = {"false_negative": [],
  178. "satisfiable": [],
  179. "unsatisfiable": []}
  180. data["median"] = {"false_negative": [],
  181. "satisfiable": [],
  182. "unsatisfiable": []}
  183. data["std_dev"] = {"false_negative": [],
  184. "satisfiable": [],
  185. "unsatisfiable": []}
  186. data["max"] = {"false_negative": [],
  187. "satisfiable": [],
  188. "unsatisfiable": []}
  189. data["min"] = {"false_negative": [],
  190. "satisfiable": [],
  191. "unsatisfiable": []}
  192. data["cnfl_per_inst"] = {"false_negative": [],
  193. "satisfiable": [],
  194. "unsatisfiable": []}
  195. data["raw"] = {"false_negative": [],
  196. "satisfiable": [],
  197. "unsatisfiable": []}
  198. data["cnflDeg"] = {"false_negative": [],
  199. "satisfiable": [],
  200. "unsatisfiable": []}
  201. for instance in stats:
  202. target = instance["result"]
  203. data["mean"][target].append(instance["conflicts_per_variable_mean"])
  204. data["median"][target].append(instance["conflicts_per_variable_median"])
  205. data["std_dev"][target].append(instance["conflicts_per_variable_std_dev"])
  206. data["max"][target].append(instance["conflicts_per_variable_max"])
  207. data["min"][target].append(instance["conflicts_per_variable_min"])
  208. data["cnfl_per_inst"][target].append(instance["conflicts_per_instance"])
  209. data["raw"][target].extend(instance["raw_conflicts"])
  210. data["cnflDeg"][target].extend(instance["conflicts_to_degree_per_variable"])
  211. return data
  212. if __name__ == "__main__":
  213. main()