this repo has no description
1#!/usr/bin/env python3
2"""
3This script will produce the final value of a variable named 'objective' and its
4area for every file ending in '.sol' in the directory provided. The files are
5expected to be fzn-gecode output piped through solns2out with the
6'--output-time' flag. Furthermore the file is expected to contain the initial
7area which can be found by adding
8'constraint trace("% init_area = \(ub(objective));\n", true);'
9to the model in question.
10"""
11import csv
12import os
13import re
14import sys
15
16from statistics import stdev
17
18
19def compute_area(file, time):
20 area = -1
21
22 objectives = []
23 times = [0]
24 timeout = -1
25 objectives.append(0)
26 for line in contents:
27 # match = re.match(r'%\sinit_area\s=\s(\d+)', line)
28 # if match:
29 # objectives.append(int(match.group(1)))
30 # continue
31 match = re.match(r"objective\s=\s(\d+)", line)
32 if match:
33 objectives.append(int(match.group(1)))
34 continue
35 match = re.match(r"%\stime elapsed:\s(\d+\.\d+)\ss", line)
36 if match:
37 times.append(float(match.group(1)))
38 continue
39 # Not proven optimal
40 if len(times) == len(objectives):
41 times.append(time)
42
43 assert len(objectives) > 0
44 assert len(objectives) + 1 == len(times)
45 area = 0
46 for i in range(len(objectives)):
47 area += (times[i + 1] - times[i]) * objectives[i]
48 return int(area)
49
50
51folder = sys.argv[1]
52statistics = dict()
53instances = set()
54for config in ["original", "restart"]:
55 for root, dirs, files in os.walk(folder + "/" + config):
56 for name in files:
57 if name.endswith(".sol"):
58 components = name[:-(4)].split(".")
59 data = components[0]
60 instances.add(data)
61 seed = 1
62 if len(components) > 1:
63 assert len(components) == 2
64 seed = components[1]
65
66 if data not in statistics:
67 statistics[data] = dict()
68 if config not in statistics[data]:
69 statistics[data][config] = []
70
71 with open(os.path.join(root, name)) as f:
72 contents = f.readlines()
73
74 nodes = None
75 solvetime = None
76 restarts = None
77 objective = None
78 for line in contents:
79 # Nodes
80 match = re.search(r"%%%mzn-stat: nodes=(\d+)", line)
81 if match:
82 nodes = int(match.group(1))
83 continue
84 # Solve time
85 match = re.search(r"%%%mzn-stat: solveTime=(\d+\.\d+)", line)
86 if match:
87 solvetime = float(match.group(1))
88 continue
89 # Restarts
90 match = re.search(r"%%%mzn-stat: restarts=(\d+)", line)
91 if match:
92 restarts = int(match.group(1))
93 continue
94
95 for line in contents[::-1]:
96 # Best objective
97 match = re.match(r"%%%mzn-stat: objective=(-?\d+)", line)
98 if match:
99 objective = int(match.group(1))
100 break
101 # Area
102 area = compute_area(contents, solvetime)
103
104 statistics[data][config].append(
105 (
106 area,
107 objective,
108 solvetime,
109 restarts,
110 nodes,
111 )
112 )
113
114for data in instances:
115 for config in ["original", "restart"]:
116 stats = statistics[data][config]
117 cumulative = stats[0]
118 for i in range(1, len(stats)):
119 cumulative = tuple(map(sum, zip(cumulative, stats[i])))
120 avg = tuple([x / len(stats) for x in cumulative])
121 dev = stdev([x[1] for x in stats]) if len(stats) > 1 else 0
122 # (avg area, avg objective, stdev objective)
123 statistics[data][config] = (avg[0], avg[1], dev)
124
125# Print header
126print(
127 """
128\\begin{tabular}{l|rr|rr|rr}
129\\toprule
130& \multicolumn{2}{c|}{Chuffed} & \multicolumn{2}{c|}{Chuffed Restart} \\\\
131Instance & $\intobj$ & $\minobj$ & $\intobj$ & $\minobj$ \\\\
132\midrule
133"""
134)
135
136sorted_instances = sorted(instances)
137for data in sorted_instances:
138 print(f"{data}", end="")
139 for config in ["original", "restart"]:
140 print(
141 f" & {int(statistics[data][config][0] / 1000) }k & {int(statistics[data][config][1])}",
142 end="",
143 )
144 if statistics[data][config][2] != 0:
145 print("^{", end="")
146 print(
147 int(statistics[data][config][2] / statistics[data][config][1] * 100),
148 # int(statistics[data][config][2]),
149 end="",
150 )
151 print("}", end="")
152 print(" \\\\")
153
154# Print footer
155print("\n\\bottomrule\n\end{tabular}")