aba2sat/scripts/aba-generator-acyclic.py

175 lines
6.2 KiB
Python
Executable file

#!/usr/bin/env python3
import argparse
import random
import os
import concurrent.futures
def create_framework(
n_sentences, n_assumptions, n_rules_per_head, size_of_bodies, cycle_prob
):
"""
Create a random framework.
sentences contains the non-assumption sentences.
n_rules_per_head should be a list exhausting the possible number of rules each head can have
size_of_bodies should be a list exhausting the possible number of sentences in any rule body
These should hold in order to get non-counterintuitive results:
- n_assumptions < n_sentences
- max(size_of_bodies) <= n_sentences+n_assumptions
"""
assumptions = [str(i) for i in range(1, n_assumptions + 1)]
sentences = [str(i) for i in range(n_assumptions + 1, n_sentences + 1)]
contraries = {
asmpt: random.choice(sentences + assumptions) for asmpt in assumptions
}
# order sentences to avoid cycles
random.shuffle(sentences)
rules = []
for i, head in enumerate(sentences):
n_rules_in_this_head = random.choice(n_rules_per_head)
for _ in range(n_rules_in_this_head):
size_of_body = random.choice(size_of_bodies)
# only allow stuff to occur in body if it is lower in the (topological) order
n_available = len(assumptions) + i
selection_set = assumptions + sentences[:i]
# add potentially cycle creating sentences to the selection set with a given probability
extra_selection = random.sample(
sentences[i:], min(len(sentences[i:]), int(cycle_prob * len(sentences)))
)
selection_set.extend(extra_selection)
# body = random.sample(assumptions+sentences[:i], min(size_of_body, n_available))
body = random.sample(
assumptions + selection_set, min(size_of_body, n_available)
)
rules.append((head, body))
return assumptions, sentences, contraries, rules
def print_ICCMA_format(assumptions, contraries, rules, n_sentences, out_filename):
"""
Print the given framework in the ICCMA 2023 format.
"""
offset = len(assumptions)
with open(out_filename, "w") as out:
out.write(f"p aba {n_sentences}\n")
for i, asm in enumerate(assumptions):
out.write(f"a {asm}\n")
# print(f"a {asm}")
for ctr in contraries:
out.write(f"c {ctr} {contraries.get(ctr)}\n")
# print(f"c {ctr} {contraries.get(ctr)}")
for rule in rules:
out.write(f"r {rule[0]} {' '.join(rule[1])}\n")
# print(f"r {rule[0]} {' '.join(rule[1])}")
def generate_configs(
sentences,
max_rules_per_head_list,
max_rule_size_list,
assumption_ratios,
cycle_props,
count,
directory,
identifier,
):
for sentence in sentences:
for assumption_ratio in assumption_ratios:
for max_rules_per_head in max_rules_per_head_list:
for max_rule_size in max_rule_size_list:
for cycle_prop in cycle_props:
for i in range(count):
yield {
"sentence": sentence,
"assumption_ratio": assumption_ratio,
"max_rules_per_head": max_rules_per_head,
"max_rule_size": max_rule_size,
"cycle_prop": cycle_prop,
"count": i,
"directory": directory,
"identifier": identifier,
}
def executor_main(config):
sentence = config["sentence"]
assumption_ratio = config["assumption_ratio"]
max_rules_per_head = config["max_rules_per_head"]
max_rule_size = config["max_rule_size"]
cycle_prop = config["cycle_prop"]
i = config["count"]
directory = config["directory"]
identifier = config["identifier"]
number_assumptions = int(round(assumption_ratio * sentence))
number_rules_per_head = range(1, max_rules_per_head + 1)
n_spb = range(1, max_rule_size + 1)
filename = f"{directory}/{identifier}_{sentence}_{assumption_ratio}_{max_rules_per_head}_{max_rule_size}_{cycle_prop}_{i}.aba"
print(filename)
framework = create_framework(
sentence, number_assumptions, number_rules_per_head, n_spb, cycle_prop
)
query = random.randint(1, number_assumptions)
with open(f"{filename}.asm", "w") as out:
print(f"{filename}.asm")
out.write(f"{query}")
print_ICCMA_format(framework[0], framework[2], framework[3], sentence, filename)
def ICCMA23_benchmarks(
sentences=[1000, 2000, 3000, 4000, 5000],
max_rules_per_head_list=[5, 10],
max_rule_size_list=[5, 10],
assumption_ratios=[0.1, 0.3],
cycle_props=[0, 0.1, 0.2, 0.4, 0.6, 0.8, 1.0],
count=10,
directory="iccma23_aba_benchmarks",
identifier="aba",
):
random.seed(811543731122527)
os.makedirs(directory, exist_ok=True)
with concurrent.futures.ProcessPoolExecutor(max_workers=os.cpu_count()) as executor:
print(f"Starting generation in {directory}..")
configs = generate_configs(
sentences=sentences,
max_rules_per_head_list=max_rules_per_head_list,
max_rule_size_list=max_rule_size_list,
assumption_ratios=assumption_ratios,
cycle_props=cycle_props,
count=count,
directory=directory,
identifier=identifier,
)
list(executor.map(executor_main, configs))
print("Done")
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("-d", "--directory")
parser.add_argument("-i", "--identifier")
args = parser.parse_args()
ICCMA23_benchmarks(
sentences=[50, 100, 300, 500, 1000, 2000, 4000, 6000],
max_rules_per_head_list=[1, 2, 8, 16, 64],
max_rule_size_list=[1, 2, 8, 16, 32],
assumption_ratios=[0.1, 0.3, 0.5, 0.7, 0.9],
cycle_props=[0, 0.1, 0.2, 0.4, 0.6, 0.8, 1.0],
count=2,
directory=args.directory if args.directory is not None else "acyclic",
identifier=args.identifier if args.identifier is not None else "aba",
)