Skip to content

Commit 958863e

Browse files
authored
Merge pull request #9 from kstrauch94/clingo-dl
Clingo dl
2 parents d9061aa + 533ee3f commit 958863e

12 files changed

+242
-48
lines changed

README.md

+5-2
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ python scripts/acclingo --instance_dir <directory> --fn_suffix ".gz" --binary <s
4747
- `--tae_class acclingo/tae/clasp_opt_tae.py`: TAE that expects `<solver>` to be a `clingo` binary and grounded instances to include `#minimize` statements. If no solution was found or the resulting cost is bigger then the ParN score, the ParN score is returned as costs. Per default 10*cutoff. Otherwise the cost is runtime times percental difference of achieved quality to best known bound.
4848
- `--tae_args "{\"best_known\": \"<csv file>\"}"`: String in json format that passes auxiliary arguments to the TAE. The TAE expects the csv file to have instance names without extension in the first column and integers representing the best known bound in the second.
4949

50+
# Additional Options
5051

51-
52-
52+
The --tae_args can also be used to change the mode of clingo. By default it is set to "clasp". If the instances require an additional file(encoding) to run, you can also provide it with the --tae_args option using "encoding":
53+
```
54+
--tae_args "{\"mode\": \"clingo\", \"encoding\": \"path/to/encoding.lp\"}"
55+
```

acclingo/tae/README.md

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Asprin TAE
22

3-
This TAE is very similar to the basic clasp TAE. The only differences are that it only counts a solution as a succesful solution if the optimum was found and it needs an asprin "binary" or a way to call asprin. The penalty for no solution or no optimal solution is the maximum available time multiplied by some penalty. This penalty can be given as a parameter:
3+
This TAE is very similar to the basic clasp TAE. The only differences are that it only counts a solution as a succesful solution if the optimum was found and that it needs an asprin "binary" or a way to call asprin. The penalty for no solution or no optimal solution is the maximum available time multiplied by some penalty value . This penalty value can be given as a parameter:
44

55
⋅⋅* Parameter to penalize no optimal solution = "penalty": float
66

@@ -14,13 +14,13 @@ example:
1414
The optimization weights TAE is a variant of "clasp\_opt\_tae" where the cost of not finding the optimal solution is calculated based on the time it takes to find some solution (or no solution) and the solution quality.
1515

1616
## Solution quality
17-
There are two ways to calculate the cost of the solution, normalized cost and not normalized cost. For both calculations we assume that a higher value is always worse.
17+
There are two ways to calculate the cost of the solution: normalized cost and not normalized cost. For both calculations we assume that a higher value is always worse.
1818

1919
Normalized cost uses the following formula:
2020
```
2121
solution_quality = 1 - (best_known_solution / found_solution_quality)
2222
```
23-
this formula will be between 0 and 1 for all values *worse* than the best solution. This also assumes that worse values are higher than better values(E.g 10 is worse than 5).
23+
this formula will be between 0 and 1 for all values *worse* than the best solution. A solution is worse than another if its value is higher(E.g 10 is worse than 5). If the solution found is better, the value will become negative.
2424

2525
Not normalized quality cost uses the following formula:
2626
```
@@ -29,7 +29,7 @@ Not normalized quality cost uses the following formula:
2929
This formula basically gives a ratio of the quality of the found solution to the best known solution. So, a value higher than 1 means that the found solution is worse and a value below 1 means that the found solution is better.
3030

3131
## Runtime quality
32-
The Above formulas are used to gage the solution quality. To calculate the actual cost we also want to take a loot at the time quality. The following formula is used regardless of the which quality formula is used:
32+
The Above formulas are used to gage the solution quality. To calculate the actual cost we also want to take a look at the time quality. The following formula is used regardless of the which quality formula is used:
3333
```
3434
runtime_quality = (found_solution_runtime / cutoff)
3535
```
@@ -41,7 +41,7 @@ If a solution was not found for the current instance, the following formula is u
4141
```
4242
cost = par_factor * unsolved_penalty
4343
```
44-
Par factor is usually set to 10 and unsolved penalty is a predefined value that modifies par factor. Users need to be careful when choosing a low unsolved_penalty when using the not normalized formula for solution quality as the value for solution quality can potentially be very big.
44+
Par factor is usually set to 10 and unsolved penalty is a predefined value that modifies par factor.
4545

4646
The actual cost is then calculated with the following formula:
4747
```

acclingo/tae/asprin_tae.py

+44-9
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,22 @@ def __init__(self, ta_bin:str, runsolver_bin:str,
6767
self.penalty = misc["penalty"]
6868
else:
6969
self.penalty = 2
70+
71+
self.encoding = ""
72+
73+
self.mode = "clasp"
74+
75+
if "encoding" in misc:
76+
self.encoding = misc["encoding"]
77+
78+
if "mode" in misc:
79+
self.mode = misc["mode"]
7080

7181

7282
def run(self, config, instance,
7383
cutoff,
7484
seed=12345,
85+
budget=None,
7586
instance_specific="0"
7687
):
7788
"""
@@ -105,9 +116,9 @@ def run(self, config, instance,
105116

106117

107118
if not instance.endswith(".gz"):
108-
cmd = "%s %s --seed=%d " %(self.ta_bin, instance, seed)
119+
cmd = "{bin} {encoding} {instance} --seed {seed} ".format(bin=self.ta_bin, encoding=self.encoding, instance=instance, seed=seed)
109120
else:
110-
cmd = "bash -c 'zcat %s | %s --seed=%d " %(instance, self.ta_bin, seed )
121+
cmd = "bash -c 'zcat {instance} | {bin} {encoding} --seed {seed} ".format(instance=instance, bin=self.ta_bin, encoding=self.encoding, seed=seed )
111122

112123
params = []
113124
for name in config:
@@ -118,9 +129,28 @@ def run(self, config, instance,
118129
params.append(value)
119130
thread_to_params, thread_to_solver, params_to_tags = self.parse_parameters(params)
120131

121-
for t, p_list in thread_to_params.items():
122-
for p in p_list:
123-
cmd += " "+p
132+
thread_count = int(max(thread_to_params.keys()))
133+
config_file = "config_file.tmp"
134+
with open(config_file, "w") as cfile:
135+
for t, p_list in thread_to_params.items():
136+
if t == 0: # global params
137+
for p in p_list:
138+
cmd += " " + p
139+
else:
140+
new_p_list = []
141+
thread_config = "auto"
142+
for p in p_list:
143+
if "--configuration" in p:
144+
thread_config = p.split("=")[1]
145+
else:
146+
new_p_list.append(p)
147+
148+
cfile.write("{}({}): {}\n".format(t, thread_config, " ".join(new_p_list)))
149+
150+
cmd += " --mode={}".format(self.mode)
151+
cmd += " --configuration={}".format(config_file)
152+
cmd += " --quiet=2 --stats"
153+
cmd += " --parallel-mode={}".format(thread_count)
124154

125155
if instance.endswith(".gz"):
126156
cmd += "'"
@@ -146,8 +176,11 @@ def run(self, config, instance,
146176

147177
ta_status_rs, ta_runtime, ta_exit_code = self.read_runsolver_output(watcher_file)
148178

149-
ta_status, ta_quality = self.parse_output(fn=solver_file, exit_code=ta_exit_code)
150-
179+
ta_status, ta_quality, clingo_runtime = self.parse_output(fn=solver_file, exit_code=ta_exit_code)
180+
181+
if ta_runtime is None:
182+
ta_runtime = clingo_runtime
183+
151184
if not ta_status:
152185
ta_status = ta_status_rs
153186

@@ -378,8 +411,10 @@ def parse_output(self, fn, exit_code):
378411
ta_status = StatusType.TIMEOUT
379412
elif re.search('INDETERMINATE', data):
380413
ta_status = StatusType.TIMEOUT
381-
382-
return ta_status, ta_quality
414+
415+
clingo_runtime = re.search(r"Time[ ]*:[ ]*(\d+\.\d+)s", data).group(1)
416+
417+
return ta_status, ta_quality, float(clingo_runtime)
383418

384419
def read_runsolver_output(self, watcher_fn: str):
385420
'''

acclingo/tae/clasp_opt_tae.py

+43-10
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,20 @@ def __init__(self, ta_bin:str, runsolver_bin:str,
6868
for line in f.readlines():
6969
self.best_known[line.split(',')[0].strip()]=int(line.split(',')[1].strip())
7070

71+
self.encoding = ""
72+
73+
self.mode = "clasp"
74+
75+
if "encoding" in misc:
76+
self.encoding = misc["encoding"]
77+
78+
if "mode" in misc:
79+
self.mode = misc["mode"]
80+
7181
def run(self, config, instance,
7282
cutoff,
7383
seed=12345,
84+
budget=None,
7485
instance_specific="0"
7586
):
7687
"""
@@ -104,9 +115,9 @@ def run(self, config, instance,
104115

105116

106117
if not instance.endswith(".gz"):
107-
cmd = "%s %s --seed %d " %(self.ta_bin, instance, seed)
118+
cmd = "{bin} {encoding} {instance} --seed {seed} ".format(bin=self.ta_bin, encoding=self.encoding, instance=instance, seed=seed)
108119
else:
109-
cmd = "bash -c 'zcat %s | %s --seed %d " %(instance, self.ta_bin, seed )
120+
cmd = "bash -c 'zcat {instance} | {bin} {encoding} --seed {seed} ".format(instance=instance, bin=self.ta_bin, encoding=self.encoding, seed=seed )
110121

111122
params = []
112123
for name in config:
@@ -117,11 +128,28 @@ def run(self, config, instance,
117128
params.append(value)
118129
thread_to_params, thread_to_solver, params_to_tags = self.parse_parameters(params)
119130

120-
for t, p_list in thread_to_params.items():
121-
for p in p_list:
122-
cmd += " "+p
131+
thread_count = int(max(thread_to_params.keys()))
132+
config_file = "config_file.tmp"
133+
with open(config_file, "w") as cfile:
134+
for t, p_list in thread_to_params.items():
135+
if t == 0: # global params
136+
for p in p_list:
137+
cmd += " " + p
138+
else:
139+
new_p_list = []
140+
thread_config = "auto"
141+
for p in p_list:
142+
if "--configuration" in p:
143+
thread_config = p.split("=")[1]
144+
else:
145+
new_p_list.append(p)
146+
147+
cfile.write("{}({}): {}\n".format(t, thread_config, " ".join(new_p_list)))
123148

124-
cmd += " --mode=clasp"
149+
cmd += " --mode={}".format(self.mode)
150+
cmd += " --configuration={}".format(config_file)
151+
cmd += " --quiet=2 --stats"
152+
cmd += " --parallel-mode={}".format(thread_count)
125153

126154
if instance.endswith(".gz"):
127155
cmd += "'"
@@ -147,8 +175,11 @@ def run(self, config, instance,
147175

148176
ta_status_rs, ta_runtime, ta_exit_code = self.read_runsolver_output(watcher_file)
149177

150-
ta_status, ta_quality = self.parse_output(fn=solver_file, exit_code=ta_exit_code)
178+
ta_status, ta_quality, clingo_runtime = self.parse_output(fn=solver_file, exit_code=ta_exit_code)
151179

180+
if ta_runtime is None:
181+
ta_runtime = clingo_runtime
182+
152183
if not ta_status:
153184
ta_status = ta_status_rs
154185

@@ -168,7 +199,7 @@ def run(self, config, instance,
168199
diff = float(ta_quality) - float(best)
169200
prct = float(best)/100.0 if best!=0 else 1.0
170201
cost = min(float(cutoff * self.par_factor),ta_runtime*(1+diff/prct))
171-
202+
172203
return ta_status, cost, ta_runtime, {}
173204

174205
def parse_parameters(self, params,prefix="--",separator="="):
@@ -383,12 +414,14 @@ def parse_output(self, fn, exit_code):
383414
ta_status = StatusType.SUCCESS
384415
elif re.search('OPTIMUM FOUND', data):
385416
ta_status = StatusType.SUCCESS
386-
elif re.search('s UNKNOWN', data):
417+
elif re.search('UNKNOWN', data):
387418
ta_status = StatusType.TIMEOUT
388419
elif re.search('INDETERMINATE', data):
389420
ta_status = StatusType.TIMEOUT
421+
422+
clingo_runtime = re.search(r"Time[ ]*:[ ]*(\d+\.\d+)s", data).group(1)
390423

391-
return ta_status, ta_quality
424+
return ta_status, ta_quality, float(clingo_runtime)
392425

393426
def read_runsolver_output(self, watcher_fn: str):
394427
'''

acclingo/tae/clasp_opt_weights_tae.py

+41-8
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,21 @@ def __init__(self, ta_bin:str, runsolver_bin:str,
9090

9191
if "normalized" in misc:
9292
self.normalized = misc["normalized"]
93+
94+
self.encoding = ""
95+
96+
self.mode = "clasp"
97+
98+
if "encoding" in misc:
99+
self.encoding = misc["encoding"]
100+
101+
if "mode" in misc:
102+
self.mode = misc["mode"]
93103

94104
def run(self, config, instance,
95105
cutoff,
96106
seed=12345,
107+
budget=None,
97108
instance_specific="0"
98109
):
99110
"""
@@ -127,9 +138,9 @@ def run(self, config, instance,
127138

128139

129140
if not instance.endswith(".gz"):
130-
cmd = "%s %s --seed %d " %(self.ta_bin, instance, seed)
141+
cmd = "{bin} {encoding} {instance} --seed {seed} ".format(bin=self.ta_bin, encoding=self.encoding, instance=instance, seed=seed)
131142
else:
132-
cmd = "bash -c 'zcat %s | %s --seed %d " %(instance, self.ta_bin, seed )
143+
cmd = "bash -c 'zcat {instance} | {bin} {encoding} --seed {seed} ".format(instance=instance, bin=self.ta_bin, encoding=self.encoding, seed=seed )
133144

134145
params = []
135146
for name in config:
@@ -140,11 +151,28 @@ def run(self, config, instance,
140151
params.append(value)
141152
thread_to_params, thread_to_solver, params_to_tags = self.parse_parameters(params)
142153

143-
for t, p_list in thread_to_params.items():
144-
for p in p_list:
145-
cmd += " "+p
154+
thread_count = int(max(thread_to_params.keys()))
155+
config_file = "config_file.tmp"
156+
with open(config_file, "w") as cfile:
157+
for t, p_list in thread_to_params.items():
158+
if t == 0: # global params
159+
for p in p_list:
160+
cmd += " " + p
161+
else:
162+
new_p_list = []
163+
thread_config = "auto"
164+
for p in p_list:
165+
if "--configuration" in p:
166+
thread_config = p.split("=")[1]
167+
else:
168+
new_p_list.append(p)
169+
170+
cfile.write("{}({}): {}\n".format(t, thread_config, " ".join(new_p_list)))
146171

147-
cmd += " --mode=clasp"
172+
cmd += " --mode={}".format(self.mode)
173+
cmd += " --configuration={}".format(config_file)
174+
cmd += " --quiet=2 --stats"
175+
cmd += " --parallel-mode={}".format(thread_count)
148176

149177
if instance.endswith(".gz"):
150178
cmd += "'"
@@ -170,7 +198,10 @@ def run(self, config, instance,
170198

171199
ta_status_rs, ta_runtime, ta_exit_code = self.read_runsolver_output(watcher_file)
172200

173-
ta_status, ta_quality = self.parse_output(fn=solver_file, exit_code=ta_exit_code)
201+
ta_status, ta_quality, clingo_runtime = self.parse_output(fn=solver_file, exit_code=ta_exit_code)
202+
203+
if ta_runtime is None:
204+
ta_runtime = clingo_runtime
174205

175206
if not ta_status:
176207
ta_status = ta_status_rs
@@ -423,7 +454,9 @@ def parse_output(self, fn, exit_code):
423454
elif re.search('INDETERMINATE', data):
424455
ta_status = StatusType.TIMEOUT
425456

426-
return ta_status, ta_quality
457+
clingo_runtime = re.search(r"Time[ ]*:[ ]*(\d+\.\d+)s", data).group(1)
458+
459+
return ta_status, ta_quality, float(clingo_runtime)
427460

428461
def read_runsolver_output(self, watcher_fn: str):
429462
'''

0 commit comments

Comments
 (0)