-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcluster.py
151 lines (122 loc) · 5.64 KB
/
cluster.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
import json
import subprocess
import argparse
import os
import re
def parse_args():
parser = argparse.ArgumentParser(description="Run stainless-dotty with various parameters.")
parser.add_argument('--filenames', type=str, required=True, help='Comma-separated list of filenames')
parser.add_argument('--assn1', type=bool, default=False, help='Boolean flag for assn1')
parser.add_argument('--assn2', type=bool, default=False, help='Boolean flag for assn2')
parser.add_argument('--subfns-equiv', type=bool, default=False, help='Boolean flag for sub functions equivalence')
parser.add_argument('--gen-subfns', type=bool, default=False, help='Boolean flag for generating sub functions')
parser.add_argument('--fake-exs', type=str, required=False, help='Comma-separated list of fake exercises')
parser.add_argument('--extract', type=str, required=True, help='Comma-separated list of extract')
parser.add_argument('--compare', type=str, required=False, help='Comma-separated list of compare funs')
parser.add_argument('--output', type=str, default='result.json', help='Output JSON file name')
parser.add_argument('--debug', type=bool, default=False, help='Show debug messages of transformation')
return parser.parse_args()
def generate_comparefuns_models(filenames, extract):
comparefuns = set()
models = set()
# Extract the first element from filenames for models
if filenames:
packagename = filenames[0].split('/')[-1].replace('.scala', '')
models.add(f"{packagename}.{extract}")
# Extract the remaining elements from filenames for comparefuns
if len(filenames) > 1:
comparefuns.update(
f"{filename.replace('.scala', '').split('/')[-1]}.{extract}"
for filename in filenames[1:])
return comparefuns, models
def run_dotty(filenames, params):
command = [
os.path.dirname(os.path.abspath(__file__)) + '/frontends/dotty/target/universal/stage/bin/stainless-dotty']
command.extend(filenames.split(','))
for key, value in params.items():
if value:
if isinstance(value, bool):
command.append(f'--{key}={str(value).lower()}')
else:
command.append(f'--{key}={value}')
command.append('--equivchk=true')
command.append('--transformation=true')
command.append('--timeout=2')
command.append('--equivchk-output=temp.json')
print("[*] Running command:", ' '.join(command))
subprocess.run(command)
def read_json(filename):
with open(filename, 'r') as f:
return json.load(f)
def update_comparefuns(comparefuns, models, temp_data):
models.clear()
for item in temp_data.get('unsafe', []):
comparefuns.discard(item['function'])
for item in temp_data.get('unknownSafety', []):
comparefuns.discard(item['function'])
for item in temp_data.get('wrong', []):
comparefuns.discard(item)
for item in temp_data.get('equivalent', []):
functions = [func for func in item['functions']]
comparefuns.difference_update(functions)
unequivalent_functions = [item['function'] for item in temp_data.get('unequivalent', [])]
unknown_functions = [func for func in temp_data.get('unknownEquivalence', [])]
unequivalent_functions.extend(unknown_functions)
print("[*] unequivalent or unknown functions:", unequivalent_functions)
if unequivalent_functions:
models.add(unequivalent_functions[0])
comparefuns.discard(unequivalent_functions[0])
def normalize_id(obj):
if isinstance(obj, dict):
return {normalize_id(key): normalize_id(value) for key, value in obj.items()}
elif isinstance(obj, list):
return [normalize_id(item) for item in obj]
elif isinstance(obj, str):
return re.sub(r'\..*\$package\.', '.', obj)
else:
return obj
def main():
args = parse_args()
if (args.compare):
comparefuns, models = generate_comparefuns_models(args.filenames.split(','), args.compare)
else:
comparefuns, models = generate_comparefuns_models(args.filenames.split(','), args.extract.split(',')[0])
print("[*] comparefuns:", comparefuns)
print("[*] models:", models)
temp_json_results = []
while comparefuns and models:
params = {
'extract': args.extract,
'comparefuns': ','.join(comparefuns),
'models': ','.join(models),
'assn1': args.assn1,
'assn2': args.assn2,
'subfns-equiv': args.subfns_equiv,
'gen-subfns': args.gen_subfns,
}
if (args.debug):
params['debug'] = "transformation"
if (args.fake_exs):
params['fake-exs'] = args.fake_exs
run_dotty(args.filenames, params)
if (os.path.exists('temp.json')):
temp_data = normalize_id(read_json('temp.json'))
if (len(temp_data['equivalent']) == 0):
temp_data['equivalent'].append({'model': list(models), 'functions': []})
else:
temp_data['equivalent'][0]['model'] = list(models)
temp_json_results.append(temp_data)
update_comparefuns(comparefuns, models, temp_data)
print("[*] new comparefuns:", comparefuns)
print("[*] new models:", models)
os.remove('temp.json')
else:
break
if models:
temp_json_results.append({'equivalent': [{"models": list(models), "functions": []}]})
if comparefuns:
temp_json_results.append({"equivalent": [{'specific function not found': list(comparefuns)}]})
with open(args.output, 'w') as f:
json.dump(temp_json_results, f, indent=4)
if __name__ == "__main__":
main()