forked from leanprover-community/mathlib3
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpolyrith_sage.py
84 lines (74 loc) · 3.19 KB
/
polyrith_sage.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
# This file is part of the `polyrith` tactic in `src/tactic/polyrith.lean`.
# It interfaces between Lean and the Sage web interface.
import requests
import json
import sys
from os.path import join, dirname
# These functions are used to format the output of Sage for parsing in Lean.
# They are stored here as a string since they are passed to Sage via the web API.
with open(join(dirname(__file__), "polyrith_sage_helper.py"), encoding='utf8') as f:
polynomial_formatting_functions = f.read()
# future extensions may change behavior depending on the base type
def type_str(type):
return "QQ"
def create_query(type: str, n_vars: int, eq_list, goal_type):
""" Create a query to invoke Sage's `MPolynomial_libsingular.lift`. See
https://github.com/sagemath/sage/blob/f8df80820dc7321dc9b18c9644c3b8315999670b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx#L4472-L4518
for a description of this method. """
var_list = ", ".join([f"var{i}" for i in range(n_vars)])
query = f'''
import json
P = PolynomialRing({type_str(type)}, 'var', {n_vars!r})
[{var_list}] = P.gens()
gens = {eq_list}
p = P({goal_type})
I = ideal(gens)
coeffs = p.lift(I)
print(json.dumps([polynomial_to_string(c) for c in coeffs]))
'''
return query
class EvaluationError(Exception):
def __init__(self, ename, evalue, message='Error in Sage communication'):
self.ename = ename
self.evalue = evalue
self.message = message
super().__init__(self.message)
def evaluate_in_sage(query: str) -> str:
data = {'code': query}
headers = {'content-type': 'application/x-www-form-urlencoded'}
response = requests.post('https://sagecell.sagemath.org/service', data, headers=headers).json()
if response['success']:
return json.loads(response.get('stdout'))
elif 'execute_reply' in response and 'ename' in response['execute_reply'] and 'evalue' in response['execute_reply']:
raise EvaluationError(response['execute_reply']['ename'], response['execute_reply']['evalue'])
else:
raise Exception(response)
def main():
'''The system args contain the following:
0 - the path to this python file
1 - a string containing "tt" or "ff" depending on whether polyrith was called with trace enabled
2 - a string representing the base type of the target
3 - the number of variables used
4 - a list of the polynomial hypotheses/proof terms in terms of the variables
5 - a single polynomial representing the target
This returns a json object with format:
```
{ success: bool,
data: Optional[list[str]],
trace: Optional[str],
error_name: Optional[str],
error_value: Optional[str] }
```
'''
command = create_query(sys.argv[2], int(sys.argv[3]), sys.argv[4], sys.argv[5])
final_query = polynomial_formatting_functions + "\n" + command
if sys.argv[1] == 'tt': # trace dry run enabled
output = dict(success=True, trace=command)
else:
try:
output = dict(success=True, data=evaluate_in_sage(final_query))
except EvaluationError as e:
output = dict(success=False, error_name=e.ename, error_value=e.evalue)
print(json.dumps(output))
if __name__ == "__main__":
main()