passagemath-standard-no-symbolics 10.6.31rc3__cp314-cp314-macosx_13_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of passagemath-standard-no-symbolics might be problematic. Click here for more details.
- passagemath_standard_no_symbolics-10.6.31rc3.data/scripts/sage-grep +5 -0
- passagemath_standard_no_symbolics-10.6.31rc3.data/scripts/sage-grepdoc +5 -0
- passagemath_standard_no_symbolics-10.6.31rc3.data/scripts/sage-list-packages +103 -0
- passagemath_standard_no_symbolics-10.6.31rc3.dist-info/METADATA +151 -0
- passagemath_standard_no_symbolics-10.6.31rc3.dist-info/RECORD +82 -0
- passagemath_standard_no_symbolics-10.6.31rc3.dist-info/WHEEL +6 -0
- passagemath_standard_no_symbolics-10.6.31rc3.dist-info/top_level.txt +1 -0
- sage/all.py +207 -0
- sage/all_cmdline.py +36 -0
- sage/cli/__init__.py +61 -0
- sage/cli/__main__.py +5 -0
- sage/cli/eval_cmd.py +45 -0
- sage/cli/eval_cmd_test.py +25 -0
- sage/cli/interactive_shell_cmd.py +28 -0
- sage/cli/notebook_cmd.py +51 -0
- sage/cli/notebook_cmd_test.py +39 -0
- sage/cli/options.py +26 -0
- sage/cli/run_file_cmd.py +50 -0
- sage/cli/version_cmd.py +26 -0
- sage/databases/all.py +83 -0
- sage/databases/cubic_hecke_db.py +1527 -0
- sage/dynamics/all.py +31 -0
- sage/dynamics/surface_dynamics_deprecation.py +32 -0
- sage/ext_data/kenzo/CP2.txt +45 -0
- sage/ext_data/kenzo/CP3.txt +349 -0
- sage/ext_data/kenzo/CP4.txt +4774 -0
- sage/ext_data/kenzo/README.txt +49 -0
- sage/ext_data/kenzo/S4.txt +20 -0
- sage/ext_data/mwrank/PRIMES +1 -0
- sage/ext_data/nbconvert/postprocess.py +48 -0
- sage/ext_data/nbconvert/rst_sage.tpl +99 -0
- sage/ext_data/nodoctest +0 -0
- sage/ext_data/notebook-ipython/kernel.json.in +11 -0
- sage/ext_data/notebook-ipython/logo-64x64.png +0 -0
- sage/ext_data/notebook-ipython/logo.svg +352 -0
- sage/ext_data/valgrind/pyalloc.supp +58 -0
- sage/ext_data/valgrind/sage-additional.supp +417 -0
- sage/ext_data/valgrind/sage.supp +43 -0
- sage/ext_data/valgrind/valgrind-python.supp +480 -0
- sage/geometry/all.py +12 -0
- sage/groups/matrix_gps/pickling_overrides.py +110 -0
- sage/homology/tests.py +66 -0
- sage/interacts/algebra.py +20 -0
- sage/interacts/all.py +25 -0
- sage/interacts/calculus.py +24 -0
- sage/interacts/fractals.py +18 -0
- sage/interacts/geometry.py +19 -0
- sage/interacts/library.py +1950 -0
- sage/interacts/library_cython.cpython-314-darwin.so +0 -0
- sage/interacts/statistics.py +19 -0
- sage/interfaces/axiom.py +1002 -0
- sage/interfaces/kash.py +834 -0
- sage/interfaces/lie.py +950 -0
- sage/interfaces/matlab.py +413 -0
- sage/interfaces/mupad.py +686 -0
- sage/interfaces/octave.py +858 -0
- sage/interfaces/phc.py +943 -0
- sage/interfaces/psage.py +189 -0
- sage/interfaces/qsieve.py +4 -0
- sage/interfaces/r.py +2096 -0
- sage/interfaces/read_data.py +46 -0
- sage/interfaces/scilab.py +576 -0
- sage/interfaces/tests.py +81 -0
- sage/libs/all.py +11 -0
- sage/libs/cremona/__init__.py +0 -0
- sage/libs/mwrank/__init__.py +0 -0
- sage/logic/all.py +3 -0
- sage/logic/booleval.py +160 -0
- sage/logic/boolformula.py +1490 -0
- sage/logic/logic.py +856 -0
- sage/logic/logicparser.py +696 -0
- sage/logic/logictable.py +272 -0
- sage/logic/propcalc.py +311 -0
- sage/misc/all.py +28 -0
- sage/misc/lazy_attribute.pyi +11 -0
- sage/rings/all.py +48 -0
- sage/rings/commutative_algebra.py +38 -0
- sage/rings/finite_rings/all.py +21 -0
- sage/rings/numbers_abc.py +58 -0
- sage/rings/polynomial/all.py +22 -0
- sage/rings/polynomial/convolution.py +421 -0
- sage/symbolic/all__sagemath_standard_no_symbolics.py +0 -0
sage/interfaces/phc.py
ADDED
|
@@ -0,0 +1,943 @@
|
|
|
1
|
+
r"""
|
|
2
|
+
Interface to PHC.
|
|
3
|
+
|
|
4
|
+
PHC computes numerical information about systems of polynomials over
|
|
5
|
+
the complex numbers.
|
|
6
|
+
|
|
7
|
+
PHC implements polynomial homotopy methods to exploit structure in
|
|
8
|
+
order to better approximate all isolated solutions. The package also
|
|
9
|
+
includes extra tools to handle positive dimensional solution
|
|
10
|
+
components.
|
|
11
|
+
|
|
12
|
+
AUTHORS:
|
|
13
|
+
|
|
14
|
+
- PHC was written by J. Verschelde, R. Cools, and many others (?)
|
|
15
|
+
|
|
16
|
+
- William Stein and Kelly ?? -- first version of interface to PHC
|
|
17
|
+
|
|
18
|
+
- Marshall Hampton -- second version of interface to PHC
|
|
19
|
+
|
|
20
|
+
- Marshall Hampton and Alex Jokela -- third version, path tracking
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
# ****************************************************************************
|
|
24
|
+
# Copyright (C) 2006 William Stein <wstein@gmail.com>
|
|
25
|
+
# Copyright (C) 2008 Marshall Hampton <hamptonio@gmail.com>
|
|
26
|
+
#
|
|
27
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
28
|
+
# as published by the Free Software Foundation; either version 2 of
|
|
29
|
+
# the License, or (at your option) any later version.
|
|
30
|
+
# https://www.gnu.org/licenses/
|
|
31
|
+
# ****************************************************************************
|
|
32
|
+
|
|
33
|
+
import os
|
|
34
|
+
import re
|
|
35
|
+
import pexpect
|
|
36
|
+
from random import random
|
|
37
|
+
|
|
38
|
+
from sage.misc.temporary_file import tmp_filename
|
|
39
|
+
from sage.rings.real_mpfr import RR
|
|
40
|
+
from sage.rings.cc import CC
|
|
41
|
+
from sage.rings.integer import Integer
|
|
42
|
+
from sage.misc.lazy_import import lazy_import
|
|
43
|
+
lazy_import("sage.plot.line", "line")
|
|
44
|
+
lazy_import("sage.plot.point", "point")
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def get_solution_dicts(output_file_contents, input_ring, get_failures=True):
|
|
48
|
+
"""
|
|
49
|
+
Return a list of dictionaries of variable:value (key:value)
|
|
50
|
+
pairs. Only used internally; see the solution_dict function in
|
|
51
|
+
the PHC_Object class definition for details.
|
|
52
|
+
|
|
53
|
+
INPUT:
|
|
54
|
+
|
|
55
|
+
- ``output_file_contents`` -- phc solution output as a string
|
|
56
|
+
- ``input_ring`` -- a PolynomialRing that variable names can be coerced into
|
|
57
|
+
|
|
58
|
+
OUTPUT: list of dictionaries of solutions
|
|
59
|
+
|
|
60
|
+
EXAMPLES::
|
|
61
|
+
|
|
62
|
+
sage: from sage.interfaces.phc import *
|
|
63
|
+
sage: R2.<x1,x2> = PolynomialRing(QQ,2)
|
|
64
|
+
sage: test_sys = [(x1-1)^5-x2, (x2-1)^5-1]
|
|
65
|
+
sage: sol = phc.blackbox(test_sys, R2) # optional -- phc
|
|
66
|
+
sage: test = get_solution_dicts(sol.output_file_contents,R2) # optional -- phc
|
|
67
|
+
sage: str(sum([q[x1].real() for q in test]))[0:4] # optional -- phc
|
|
68
|
+
'25.0'
|
|
69
|
+
"""
|
|
70
|
+
output_list = output_file_contents.splitlines()
|
|
71
|
+
solution_dicts = []
|
|
72
|
+
for solution_line in range(len(output_list) - 1, -1, -1):
|
|
73
|
+
if output_list[solution_line].find('THE SOLUTIONS') == 0:
|
|
74
|
+
break
|
|
75
|
+
try:
|
|
76
|
+
var_number = int(output_list[solution_line + 2].split(' ')[1])
|
|
77
|
+
# sol_number = int(output_list[solution_line+2].split(' ')[0])
|
|
78
|
+
except IndexError:
|
|
79
|
+
var_number = int(output_list[solution_line + 1].split(' ')[1])
|
|
80
|
+
# sol_number = int(output_list[solution_line+1].split(' ')[0])
|
|
81
|
+
for i in range(solution_line + 1, len(output_list)):
|
|
82
|
+
if output_list[i].count('the solution for t') == 1:
|
|
83
|
+
if output_list[i - 3].count('success') > 0 or get_failures:
|
|
84
|
+
temp_dict = {}
|
|
85
|
+
for j in range(1, var_number + 1):
|
|
86
|
+
rawsplit = output_list[i + j].split(': ')[1].split(' ')
|
|
87
|
+
for extras in range(rawsplit.count('')):
|
|
88
|
+
rawsplit.remove('')
|
|
89
|
+
temp_var = output_list[i + j].split(': ')[0].replace(' ', '')
|
|
90
|
+
temp_dict[input_ring(temp_var)] = CC(rawsplit[0],
|
|
91
|
+
rawsplit[1])
|
|
92
|
+
solution_dicts.append(temp_dict)
|
|
93
|
+
return solution_dicts
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def get_classified_solution_dicts(output_file_contents, input_ring, get_failures=True):
|
|
97
|
+
"""
|
|
98
|
+
Return a dictionary of lists of dictionaries of variable:value (key:value)
|
|
99
|
+
pairs. Only used internally; see the classified_solution_dict function in
|
|
100
|
+
the PHC_Object class definition for details.
|
|
101
|
+
|
|
102
|
+
INPUT:
|
|
103
|
+
|
|
104
|
+
- ``output_file_contents`` -- phc solution output as a string
|
|
105
|
+
- ``input_ring`` -- a PolynomialRing that variable names can be coerced into
|
|
106
|
+
|
|
107
|
+
OUTPUT: a dictionary of lists if dictionaries of solutions, classifies by type
|
|
108
|
+
|
|
109
|
+
EXAMPLES::
|
|
110
|
+
|
|
111
|
+
sage: from sage.interfaces.phc import *
|
|
112
|
+
sage: R2.<x1,x2> = PolynomialRing(QQ,2)
|
|
113
|
+
sage: test_sys = [(x1-2)^5-x2, (x2-1)^5-1]
|
|
114
|
+
sage: sol = phc.blackbox(test_sys, R2) # optional -- phc
|
|
115
|
+
sage: sol_classes = get_classified_solution_dicts(sol.output_file_contents,R2) # optional -- phc
|
|
116
|
+
sage: len(sol_classes['real']) # optional -- phc
|
|
117
|
+
1
|
|
118
|
+
"""
|
|
119
|
+
output_list = output_file_contents.splitlines()
|
|
120
|
+
solution_dicts = {}
|
|
121
|
+
solution_types = ['complex', 'real', 'failure']
|
|
122
|
+
for sol_type in solution_types:
|
|
123
|
+
solution_dicts[sol_type] = []
|
|
124
|
+
for solution_line in range(len(output_list) - 1, -1, -1):
|
|
125
|
+
if output_list[solution_line].find('THE SOLUTIONS') == 0:
|
|
126
|
+
break
|
|
127
|
+
var_number = int(output_list[solution_line + 2].split(' ')[1])
|
|
128
|
+
# sol_number = int(output_list[solution_line+2].split(' ')[0])
|
|
129
|
+
for i in range(solution_line + 1, len(output_list)):
|
|
130
|
+
if output_list[i].count('the solution for t') == 1:
|
|
131
|
+
phc_type = output_list[i + var_number + 1].split(' = ')[-1]
|
|
132
|
+
if phc_type.find('complex') != -1:
|
|
133
|
+
phc_type = 'complex'
|
|
134
|
+
elif phc_type.find('real') != -1:
|
|
135
|
+
phc_type = 'real'
|
|
136
|
+
else:
|
|
137
|
+
phc_type = 'failure'
|
|
138
|
+
temp_dict = {}
|
|
139
|
+
for j in range(1, var_number + 1):
|
|
140
|
+
rawsplit = output_list[i + j].split(': ')[1].split(' ')
|
|
141
|
+
for extras in range(rawsplit.count('')):
|
|
142
|
+
rawsplit.remove('')
|
|
143
|
+
temp_var = output_list[i + j].split(': ')[0].replace(' ', '')
|
|
144
|
+
if phc_type == 'real':
|
|
145
|
+
temp_dict[input_ring(temp_var)] = RR(rawsplit[0])
|
|
146
|
+
else:
|
|
147
|
+
temp_dict[input_ring(temp_var)] = CC(rawsplit[0],
|
|
148
|
+
rawsplit[1])
|
|
149
|
+
solution_dicts[phc_type].append(temp_dict)
|
|
150
|
+
return solution_dicts
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def get_variable_list(output_file_contents):
|
|
154
|
+
"""
|
|
155
|
+
Return the variables, as strings, in the order in which PHCpack has processed them.
|
|
156
|
+
|
|
157
|
+
EXAMPLES::
|
|
158
|
+
|
|
159
|
+
sage: from sage.interfaces.phc import *
|
|
160
|
+
sage: R2.<x1,x2> = PolynomialRing(QQ,2)
|
|
161
|
+
sage: test_sys = [(x1-2)^5-x2, (x2-1)^5-1]
|
|
162
|
+
sage: sol = phc.blackbox(test_sys, R2) # optional -- phc
|
|
163
|
+
sage: get_variable_list(sol.output_file_contents) # optional -- phc
|
|
164
|
+
['x1', 'x2']
|
|
165
|
+
"""
|
|
166
|
+
output_list = output_file_contents.splitlines()
|
|
167
|
+
for solution_line in range(len(output_list) - 1, -1, -1):
|
|
168
|
+
if output_list[solution_line].find('THE SOLUTIONS') == 0:
|
|
169
|
+
break
|
|
170
|
+
var_number = int(output_list[solution_line + 2].split(' ')[1])
|
|
171
|
+
varlist = []
|
|
172
|
+
for var_ind in range(var_number):
|
|
173
|
+
var = output_list[solution_line + 8 + var_ind].split(' ')[1]
|
|
174
|
+
varlist.append(var)
|
|
175
|
+
return varlist
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
class PHC_Object:
|
|
179
|
+
|
|
180
|
+
def __init__(self, output_file_contents, input_ring):
|
|
181
|
+
"""
|
|
182
|
+
A container for data from the PHCpack program - lists of float
|
|
183
|
+
solutions, etc. Currently the file contents are kept as a string;
|
|
184
|
+
for really large outputs this would be bad.
|
|
185
|
+
|
|
186
|
+
INPUT:
|
|
187
|
+
|
|
188
|
+
- ``output_file_contents`` -- the string output of PHCpack
|
|
189
|
+
- ``input_ring`` -- for coercion of the variables into the desired ring
|
|
190
|
+
|
|
191
|
+
EXAMPLES::
|
|
192
|
+
|
|
193
|
+
sage: from sage.interfaces.phc import phc
|
|
194
|
+
sage: R2.<x,y> = PolynomialRing(QQ,2)
|
|
195
|
+
sage: start_sys = [(x-1)^2+(y-1)-1, x^2+y^2-1]
|
|
196
|
+
sage: sol = phc.blackbox(start_sys, R2) # optional -- phc
|
|
197
|
+
sage: str(sum([x[0] for x in sol.solutions()]).real())[0:3] # optional -- phc
|
|
198
|
+
'2.0'
|
|
199
|
+
"""
|
|
200
|
+
self.output_file_contents = output_file_contents
|
|
201
|
+
self.input_ring = input_ring
|
|
202
|
+
|
|
203
|
+
def save_as_start(self, start_filename=None, sol_filter=''):
|
|
204
|
+
"""
|
|
205
|
+
Save a solution as a phcpack start file. The usual output is
|
|
206
|
+
just as a string, but it can be saved to a file as well. Even
|
|
207
|
+
if saved to a file, it still returns the output string.
|
|
208
|
+
|
|
209
|
+
EXAMPLES::
|
|
210
|
+
|
|
211
|
+
sage: from sage.interfaces.phc import phc
|
|
212
|
+
sage: R2.<x,y> = PolynomialRing(QQ,2)
|
|
213
|
+
sage: start_sys = [x^3-y^2,y^5-1]
|
|
214
|
+
sage: sol = phc.blackbox(start_sys, R2) # optional -- phc
|
|
215
|
+
sage: start_save = sol.save_as_start() # optional -- phc
|
|
216
|
+
sage: end_sys = [x^7-2,y^5-x^2] # optional -- phc
|
|
217
|
+
sage: sol = phc.start_from(start_save, end_sys, R2) # optional -- phc
|
|
218
|
+
sage: len(sol.solutions()) # optional -- phc
|
|
219
|
+
15
|
|
220
|
+
"""
|
|
221
|
+
start_data = ''
|
|
222
|
+
output_list = self.output_file_contents.splitlines()
|
|
223
|
+
for a_line in output_list:
|
|
224
|
+
if a_line.find('ROOT COUNTS') != -1 or a_line.find('START SOLUTIONS') != -1:
|
|
225
|
+
break
|
|
226
|
+
else:
|
|
227
|
+
start_data += a_line + '\n'
|
|
228
|
+
for index in range(len(output_list) - 1, 0, -1):
|
|
229
|
+
a_line = output_list[index]
|
|
230
|
+
if a_line.find('THE SOLUTIONS') != -1:
|
|
231
|
+
found_solutions = index
|
|
232
|
+
break
|
|
233
|
+
start_data += output_list[found_solutions] + '\n\n'
|
|
234
|
+
try:
|
|
235
|
+
var_number = int(output_list[found_solutions + 1].split(' ')[1])
|
|
236
|
+
except Exception:
|
|
237
|
+
# bad error handling
|
|
238
|
+
var_number = int(output_list[found_solutions + 2].split(' ')[1])
|
|
239
|
+
sol_count = 0
|
|
240
|
+
sol_data = ''
|
|
241
|
+
for i in range(found_solutions + 2, len(output_list)):
|
|
242
|
+
if output_list[i].count('the solution for t') == 1 and output_list[i + 1 + var_number].find(sol_filter) != -1:
|
|
243
|
+
phc_type = output_list[i + var_number + 1].split(' = ')[-1]
|
|
244
|
+
if phc_type.find('no solution') == -1:
|
|
245
|
+
sol_count += 1
|
|
246
|
+
for ind2 in range(i - 3, i + var_number + 2):
|
|
247
|
+
sol_data += output_list[ind2] + '\n'
|
|
248
|
+
jan_bar = '=' * 75 + '\n'
|
|
249
|
+
sol_data += jan_bar
|
|
250
|
+
start_data += str(sol_count) + ' ' + str(var_number) + '\n'
|
|
251
|
+
start_data += jan_bar + sol_data
|
|
252
|
+
if start_filename is not None:
|
|
253
|
+
with open(start_filename, 'w') as start_file:
|
|
254
|
+
start_file.write(start_data)
|
|
255
|
+
return start_data
|
|
256
|
+
|
|
257
|
+
def classified_solution_dicts(self):
|
|
258
|
+
"""
|
|
259
|
+
Return a dictionary of lists of dictionaries of solutions.
|
|
260
|
+
|
|
261
|
+
Its not as crazy as it sounds; the keys are the types of solutions as
|
|
262
|
+
classified by phcpack: regular vs. singular, complex vs. real
|
|
263
|
+
|
|
264
|
+
INPUT:
|
|
265
|
+
|
|
266
|
+
- None
|
|
267
|
+
|
|
268
|
+
OUTPUT: a dictionary of lists of dictionaries of solutions
|
|
269
|
+
|
|
270
|
+
EXAMPLES::
|
|
271
|
+
|
|
272
|
+
sage: from sage.interfaces.phc import phc
|
|
273
|
+
sage: R.<x,y> = PolynomialRing(CC,2)
|
|
274
|
+
sage: p_sys = [x^10-y,y^2-1]
|
|
275
|
+
sage: sol = phc.blackbox(p_sys,R) # optional -- phc
|
|
276
|
+
sage: classifieds = sol.classified_solution_dicts() # optional -- phc
|
|
277
|
+
sage: str(sum([q[y] for q in classifieds['real']]))[0:3] # optional -- phc
|
|
278
|
+
'2.0'
|
|
279
|
+
"""
|
|
280
|
+
try:
|
|
281
|
+
return self.__classified_sols
|
|
282
|
+
except AttributeError:
|
|
283
|
+
pass
|
|
284
|
+
classified_sols = get_classified_solution_dicts(self.output_file_contents, self.input_ring)
|
|
285
|
+
self.__classified_sols = classified_sols
|
|
286
|
+
return classified_sols
|
|
287
|
+
|
|
288
|
+
def solution_dicts(self, get_failures=False):
|
|
289
|
+
"""
|
|
290
|
+
Return a list of solutions in dictionary form: variable:value.
|
|
291
|
+
|
|
292
|
+
INPUT:
|
|
293
|
+
|
|
294
|
+
- ``self`` -- for access to self_out_file_contents, the string
|
|
295
|
+
of raw PHCpack output
|
|
296
|
+
- ``get_failures`` -- boolean (default: ``False``); the default
|
|
297
|
+
is to not process failed homotopies. These either lie on
|
|
298
|
+
positive-dimensional components or at infinity.
|
|
299
|
+
|
|
300
|
+
OUTPUT:
|
|
301
|
+
|
|
302
|
+
- solution_dicts: a list of dictionaries. Each dictionary
|
|
303
|
+
element is of the form variable:value, where the variable
|
|
304
|
+
is an element of the input_ring, and the value is in
|
|
305
|
+
ComplexField.
|
|
306
|
+
|
|
307
|
+
EXAMPLES::
|
|
308
|
+
|
|
309
|
+
sage: from sage.interfaces.phc import *
|
|
310
|
+
sage: R.<x,y,z> = PolynomialRing(QQ,3)
|
|
311
|
+
sage: fs = [x^2-1,y^2-x,z^2-y]
|
|
312
|
+
sage: sol = phc.blackbox(fs,R) # optional -- phc
|
|
313
|
+
sage: s_list = sol.solution_dicts() # optional -- phc
|
|
314
|
+
sage: s_list.sort() # optional -- phc
|
|
315
|
+
sage: s_list[0] # optional -- phc
|
|
316
|
+
{y: 1.00000000000000, z: -1.00000000000000, x: 1.00000000000000}
|
|
317
|
+
"""
|
|
318
|
+
try:
|
|
319
|
+
return self.__solution_dicts
|
|
320
|
+
except AttributeError:
|
|
321
|
+
pass
|
|
322
|
+
solution_dicts = get_solution_dicts(self.output_file_contents, self.input_ring, get_failures=get_failures)
|
|
323
|
+
self.__solution_dicts = solution_dicts
|
|
324
|
+
return solution_dicts
|
|
325
|
+
|
|
326
|
+
def solutions(self, get_failures=False):
|
|
327
|
+
"""
|
|
328
|
+
Return a list of solutions in the ComplexField.
|
|
329
|
+
|
|
330
|
+
Use the variable_list function to get the order of variables used by
|
|
331
|
+
PHCpack, which is usually different than the term order of the
|
|
332
|
+
input_ring.
|
|
333
|
+
|
|
334
|
+
INPUT:
|
|
335
|
+
|
|
336
|
+
- ``self`` -- for access to self_out_file_contents, the string
|
|
337
|
+
of raw PHCpack output
|
|
338
|
+
- ``get_failures`` -- boolean (default: ``False``); the default
|
|
339
|
+
is to not process failed homotopies. These either lie on
|
|
340
|
+
positive-dimensional components or at infinity.
|
|
341
|
+
|
|
342
|
+
OUTPUT: solutions: a list of lists of ComplexField-valued solutions
|
|
343
|
+
|
|
344
|
+
EXAMPLES::
|
|
345
|
+
|
|
346
|
+
sage: from sage.interfaces.phc import *
|
|
347
|
+
sage: R2.<x1,x2> = PolynomialRing(QQ,2)
|
|
348
|
+
sage: test_sys = [x1^5-x1*x2^2-1, x2^5-x1*x2-1]
|
|
349
|
+
sage: sol = phc.blackbox(test_sys, R2) # optional -- phc
|
|
350
|
+
sage: len(sol.solutions()) # optional -- phc
|
|
351
|
+
25
|
|
352
|
+
"""
|
|
353
|
+
try:
|
|
354
|
+
return self.__solutions
|
|
355
|
+
except AttributeError:
|
|
356
|
+
pass
|
|
357
|
+
solution_dicts = get_solution_dicts(self.output_file_contents, self.input_ring, get_failures=get_failures)
|
|
358
|
+
self.__solution_dicts = solution_dicts
|
|
359
|
+
solutions = [sol_dict.values() for sol_dict in solution_dicts]
|
|
360
|
+
self.__solutions = solutions
|
|
361
|
+
return solutions
|
|
362
|
+
|
|
363
|
+
def variable_list(self):
|
|
364
|
+
"""
|
|
365
|
+
Return the variables, as strings, in the order in which
|
|
366
|
+
PHCpack has processed them.
|
|
367
|
+
|
|
368
|
+
EXAMPLES::
|
|
369
|
+
|
|
370
|
+
sage: from sage.interfaces.phc import *
|
|
371
|
+
sage: R2.<x1,x2> = PolynomialRing(QQ,2)
|
|
372
|
+
sage: test_sys = [x1^5-x1*x2^2-1, x2^5-x1*x2-1]
|
|
373
|
+
sage: sol = phc.blackbox(test_sys, R2) # optional -- phc
|
|
374
|
+
sage: sol.variable_list() # optional -- phc
|
|
375
|
+
['x1', 'x2']
|
|
376
|
+
"""
|
|
377
|
+
try:
|
|
378
|
+
return self.__var_list
|
|
379
|
+
except AttributeError:
|
|
380
|
+
pass
|
|
381
|
+
var_list = get_variable_list(self.output_file_contents)
|
|
382
|
+
self.__var_list = var_list
|
|
383
|
+
return var_list
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
class PHC:
|
|
387
|
+
"""
|
|
388
|
+
A class to interface with PHCpack, for computing numerical
|
|
389
|
+
homotopies and root counts.
|
|
390
|
+
|
|
391
|
+
EXAMPLES::
|
|
392
|
+
|
|
393
|
+
sage: from sage.interfaces.phc import phc
|
|
394
|
+
sage: R.<x,y> = PolynomialRing(CDF,2)
|
|
395
|
+
sage: testsys = [x^2 + 1, x*y - 1]
|
|
396
|
+
sage: phc.mixed_volume(testsys) # optional -- phc
|
|
397
|
+
2
|
|
398
|
+
sage: v = phc.blackbox(testsys, R) # optional -- phc
|
|
399
|
+
sage: sols = v.solutions() # optional -- phc
|
|
400
|
+
sage: sols.sort() # optional -- phc
|
|
401
|
+
sage: sols # optional -- phc
|
|
402
|
+
[[-1.00000000000000*I, 1.00000000000000*I], [1.00000000000000*I, -1.00000000000000*I]]
|
|
403
|
+
sage: sol_dict = v.solution_dicts() # optional -- phc
|
|
404
|
+
sage: x_sols_from_dict = [d[x] for d in sol_dict] # optional -- phc
|
|
405
|
+
sage: x_sols_from_dict.sort(); x_sols_from_dict # optional -- phc
|
|
406
|
+
[-1.00000000000000*I, 1.00000000000000*I]
|
|
407
|
+
sage: residuals = [[test_equation.change_ring(CDF).subs(sol) for test_equation in testsys] for sol in v.solution_dicts()] # optional -- phc
|
|
408
|
+
sage: residuals # optional -- phc
|
|
409
|
+
[[0, 0], [0, 0]]
|
|
410
|
+
"""
|
|
411
|
+
|
|
412
|
+
def _output_from_command_list(self, command_list, polys, verbose=False):
|
|
413
|
+
"""
|
|
414
|
+
A pexpect interface to phcpack, given a command list for
|
|
415
|
+
interactive dialogs. The input file is supplied from the
|
|
416
|
+
polynomial list, output file is also supplied. This is
|
|
417
|
+
only used as a building block for the interface.
|
|
418
|
+
|
|
419
|
+
INPUT:
|
|
420
|
+
|
|
421
|
+
- ``command_list`` -- list of commands to phc
|
|
422
|
+
- ``polys`` -- a polynomial system as a list of polynomials
|
|
423
|
+
|
|
424
|
+
OUTPUT: an output string from phc
|
|
425
|
+
|
|
426
|
+
EXAMPLES::
|
|
427
|
+
|
|
428
|
+
sage: from sage.interfaces.phc import *
|
|
429
|
+
sage: R2.<x,y> = PolynomialRing(QQ,2)
|
|
430
|
+
sage: start_sys = [(x-1)^2+(y-1)-1, x^2+y^2-1] # optional -- phc
|
|
431
|
+
sage: a = phc._output_from_command_list(['phc -m','4','n','n','n'], start_sys) # optional -- phc
|
|
432
|
+
"""
|
|
433
|
+
# Get temporary file names (these will be in SAGE_HOME/.sage/tmp/pid)
|
|
434
|
+
input_filename = tmp_filename()
|
|
435
|
+
output_filename = tmp_filename()
|
|
436
|
+
|
|
437
|
+
# Get the input polynomial text
|
|
438
|
+
input = self._input_file(polys)
|
|
439
|
+
if verbose:
|
|
440
|
+
print("Writing the input file to %s" % input_filename)
|
|
441
|
+
with open(input_filename, 'w') as file:
|
|
442
|
+
file.write(input)
|
|
443
|
+
|
|
444
|
+
if verbose:
|
|
445
|
+
print("The following file will be the input polynomial file to phc.")
|
|
446
|
+
print(input)
|
|
447
|
+
|
|
448
|
+
# Create a phc process
|
|
449
|
+
child_phc = pexpect.spawn(command_list[0])
|
|
450
|
+
# feed it the commands
|
|
451
|
+
child_phc.sendline('y')
|
|
452
|
+
child_phc.sendline(input_filename)
|
|
453
|
+
child_phc.sendline(output_filename)
|
|
454
|
+
for command_string in command_list[1:]:
|
|
455
|
+
if verbose:
|
|
456
|
+
print(command_string)
|
|
457
|
+
child_phc.sendline(command_string)
|
|
458
|
+
child_phc.expect('results')
|
|
459
|
+
read_stuff = child_phc.read()
|
|
460
|
+
if verbose:
|
|
461
|
+
print(read_stuff)
|
|
462
|
+
child_phc.close()
|
|
463
|
+
if not os.path.exists(output_filename):
|
|
464
|
+
raise RuntimeError("The output file does not exist; something went wrong running phc.")
|
|
465
|
+
|
|
466
|
+
# Delete the input file
|
|
467
|
+
os.unlink(input_filename)
|
|
468
|
+
|
|
469
|
+
# Return the output filename
|
|
470
|
+
return output_filename
|
|
471
|
+
|
|
472
|
+
def _input_file(self, polys):
|
|
473
|
+
r"""
|
|
474
|
+
This is used internally to implement the PHC interface.
|
|
475
|
+
|
|
476
|
+
INPUT:
|
|
477
|
+
|
|
478
|
+
- ``polys`` -- list of polynomials in a Sage polynomial ring
|
|
479
|
+
over a field that embeds into the complex numbers
|
|
480
|
+
|
|
481
|
+
OUTPUT: a PHC input file (as a text string) that describes these
|
|
482
|
+
polynomials
|
|
483
|
+
|
|
484
|
+
EXAMPLES::
|
|
485
|
+
|
|
486
|
+
sage: from sage.interfaces.phc import *
|
|
487
|
+
sage: R2.<x,y> = PolynomialRing(QQ,2)
|
|
488
|
+
sage: start_sys = [(x-1)^2+(y-1)-1, x^2+y^2-1]
|
|
489
|
+
sage: phc._input_file(start_sys) # optional -- phc
|
|
490
|
+
'2\nx^2 - 2*x + y - 1;\nx^2 + y^2 - 1;\n'
|
|
491
|
+
"""
|
|
492
|
+
if not isinstance(polys, (list, tuple)):
|
|
493
|
+
raise TypeError('polys must be a list or tuple')
|
|
494
|
+
s = '%s\n' % len(polys)
|
|
495
|
+
for f in polys:
|
|
496
|
+
s += f._repr_() + ';\n' # note the semicolon *terminators*
|
|
497
|
+
return s
|
|
498
|
+
|
|
499
|
+
def _parse_path_file(self, input_filename, verbose=False):
|
|
500
|
+
"""
|
|
501
|
+
Take a phpack output file containing path tracking information
|
|
502
|
+
and parses it into a list of lists of dictionaries - i.e. a
|
|
503
|
+
list of solutions paths, where each solution path is a list of
|
|
504
|
+
dictionaries of variable and homotopy parameter values.
|
|
505
|
+
|
|
506
|
+
INPUT:
|
|
507
|
+
|
|
508
|
+
- ``input_filename`` -- file must have path-tracking information
|
|
509
|
+
|
|
510
|
+
OUTPUT: list of lists of dictionaries, described above
|
|
511
|
+
|
|
512
|
+
EXAMPLES::
|
|
513
|
+
|
|
514
|
+
sage: from sage.interfaces.phc import *
|
|
515
|
+
sage: R2.<x,y> = PolynomialRing(QQ,2)
|
|
516
|
+
sage: start_sys = [x^5-y^2,y^5-1]
|
|
517
|
+
sage: sol = phc.blackbox(start_sys, R2) # optional -- phc
|
|
518
|
+
sage: start_save = sol.save_as_start() # optional -- phc
|
|
519
|
+
sage: end_sys = [x^5-2,y^5-x^2] # optional -- phc
|
|
520
|
+
sage: path_track_filename = phc._path_track_file(start_save, end_sys, R2, c_skew = .001) # optional -- phc
|
|
521
|
+
sage: sol_paths = phc._parse_path_file(path_track_filename) # optional -- phc
|
|
522
|
+
sage: len(sol_paths) # optional -- phc
|
|
523
|
+
25
|
|
524
|
+
"""
|
|
525
|
+
if not os.path.exists(input_filename):
|
|
526
|
+
raise RuntimeError("The file containing output from phc (" + input_filename + ") cannot be found")
|
|
527
|
+
|
|
528
|
+
fh = open(input_filename)
|
|
529
|
+
line_idx = 0
|
|
530
|
+
begin = 0
|
|
531
|
+
count = 0
|
|
532
|
+
solutions_dicts = []
|
|
533
|
+
steps_dicts = []
|
|
534
|
+
|
|
535
|
+
# regular expressions for matching certain output types
|
|
536
|
+
var_cnt_regex = re.compile('^ +([0-9]+)')
|
|
537
|
+
output_regex = re.compile('^OUTPUT INFORMATION DURING')
|
|
538
|
+
t_regex = re.compile(r'(^t +: +(-{0,1}[0-9]+\.[0-9]+E[-+][0-9]+) +(-{0,1}[0-9]+\.[0-9]+E[-+][0-9]+)$)', re.IGNORECASE)
|
|
539
|
+
sols_regex = re.compile(r'(^ *(([a-z]|[0-9])+) +: +(-?[0-9]+\.[0-9]+E[-+][0-9]+) +(-?[0-9]+\.[0-9]+E[-+][0-9]+)$)', re.IGNORECASE)
|
|
540
|
+
complete_regex = re.compile('^TIMING INFORMATION')
|
|
541
|
+
|
|
542
|
+
breakfast = False
|
|
543
|
+
a_line = fh.readline()
|
|
544
|
+
end_test = ''
|
|
545
|
+
while a_line:
|
|
546
|
+
# processing....
|
|
547
|
+
a_line = a_line.replace("\n", '')
|
|
548
|
+
if line_idx == 0:
|
|
549
|
+
m = var_cnt_regex.match(a_line)
|
|
550
|
+
if m:
|
|
551
|
+
count = Integer(m.group(1))
|
|
552
|
+
if count > 0:
|
|
553
|
+
m = output_regex.match(a_line)
|
|
554
|
+
if m:
|
|
555
|
+
begin = 1
|
|
556
|
+
if begin:
|
|
557
|
+
m = t_regex.match(a_line)
|
|
558
|
+
if m:
|
|
559
|
+
# put the t-values into a dict
|
|
560
|
+
# m.group(2) contains the real val
|
|
561
|
+
# m.group(3) contains the imaginary val
|
|
562
|
+
# fh_w.write( "T=> G1(" + m.group(2) + '),G2(' + m.group(3) + ")\n")
|
|
563
|
+
# read off two lines - this should be 'm' and 'the solution for t :'
|
|
564
|
+
a_line = fh.readline()
|
|
565
|
+
end_test = a_line # store this to check for end of solution
|
|
566
|
+
a_line = fh.readline()
|
|
567
|
+
t_val = CC(m.group(2), m.group(3))
|
|
568
|
+
temp_dict = {}
|
|
569
|
+
temp_dict["t"] = t_val
|
|
570
|
+
for i in range(count):
|
|
571
|
+
a_line = fh.readline()
|
|
572
|
+
m = sols_regex.match(a_line)
|
|
573
|
+
if m:
|
|
574
|
+
# m.group(2) contains our var name
|
|
575
|
+
# m.group(4) contains our real val
|
|
576
|
+
# m.group(5) contains our imaginary val
|
|
577
|
+
temp_dict[m.group(2)] = CC(m.group(4),
|
|
578
|
+
m.group(5))
|
|
579
|
+
steps_dicts.append(temp_dict)
|
|
580
|
+
# check if its the end of a solution
|
|
581
|
+
if end_test.find('Length of path') != -1:
|
|
582
|
+
if verbose:
|
|
583
|
+
print("recording sol")
|
|
584
|
+
if steps_dicts != []:
|
|
585
|
+
solutions_dicts.append(steps_dicts)
|
|
586
|
+
steps_dicts = []
|
|
587
|
+
m = complete_regex.match(a_line)
|
|
588
|
+
if m:
|
|
589
|
+
breakfast = True
|
|
590
|
+
if breakfast:
|
|
591
|
+
break
|
|
592
|
+
line_idx += 1
|
|
593
|
+
a_line = fh.readline()
|
|
594
|
+
fh.close()
|
|
595
|
+
return solutions_dicts
|
|
596
|
+
|
|
597
|
+
def _path_track_file(self, start_filename_or_string, polys, input_ring, c_skew=0.001, verbose=False):
|
|
598
|
+
"""
|
|
599
|
+
Return the filename which contains path tracking output.
|
|
600
|
+
|
|
601
|
+
EXAMPLES::
|
|
602
|
+
|
|
603
|
+
sage: from sage.interfaces.phc import *
|
|
604
|
+
sage: R2.<x,y> = PolynomialRing(QQ,2)
|
|
605
|
+
sage: start_sys = [x^6-y^2,y^5-1]
|
|
606
|
+
sage: sol = phc.blackbox(start_sys, R2) # optional -- phc
|
|
607
|
+
sage: start_save = sol.save_as_start() # optional -- phc
|
|
608
|
+
sage: end_sys = [x^7-2,y^5-x^2] # optional -- phc
|
|
609
|
+
sage: path_track_filename = phc._path_track_file(start_save, end_sys, R2, c_skew = .001) # optional -- phc
|
|
610
|
+
sage: sol_paths = phc._parse_path_file(path_track_filename) # optional -- phc
|
|
611
|
+
sage: len(sol_paths) # optional -- phc
|
|
612
|
+
30
|
|
613
|
+
"""
|
|
614
|
+
# Probably unnecessarily redundant from the start_from function
|
|
615
|
+
if start_filename_or_string.find('THE SOLUTIONS') != -1:
|
|
616
|
+
start_filename = tmp_filename()
|
|
617
|
+
with open(start_filename, 'w') as start_file:
|
|
618
|
+
start_file.write(start_filename_or_string)
|
|
619
|
+
elif os.path.exists(start_filename_or_string):
|
|
620
|
+
start_filename = start_filename_or_string
|
|
621
|
+
else:
|
|
622
|
+
raise RuntimeError("There is something wrong with your start string or filename")
|
|
623
|
+
|
|
624
|
+
return self._output_from_command_list(['phc', '0', '0', 'A', start_filename, 'y', '1', '0', 'n', 'k', '2', 'a', '1', str(c_skew), '0', '0', '2'], polys, verbose=verbose)
|
|
625
|
+
|
|
626
|
+
def path_track(self, start_sys, end_sys, input_ring, c_skew=.001, saved_start=None):
|
|
627
|
+
"""
|
|
628
|
+
This function computes homotopy paths between the solutions of
|
|
629
|
+
``start_sys`` and ``end_sys``.
|
|
630
|
+
|
|
631
|
+
INPUT:
|
|
632
|
+
|
|
633
|
+
- ``start_sys`` -- a square polynomial system, given as a list of
|
|
634
|
+
polynomials
|
|
635
|
+
- ``end_sys`` -- same type as ``start_sys``
|
|
636
|
+
- ``input_ring`` -- for coercion of the variables into the desired ring
|
|
637
|
+
- ``c_skew`` -- (optional) the imaginary part of homotopy multiplier;
|
|
638
|
+
nonzero values are often necessary to avoid intermediate path
|
|
639
|
+
collisions
|
|
640
|
+
- ``saved_start`` -- (optional) a phc output file; if not given, start
|
|
641
|
+
system solutions are computed via the ``phc.blackbox`` function
|
|
642
|
+
|
|
643
|
+
OUTPUT: list of paths as dictionaries, with the keys variables and
|
|
644
|
+
t-values on the path
|
|
645
|
+
|
|
646
|
+
EXAMPLES::
|
|
647
|
+
|
|
648
|
+
sage: from sage.interfaces.phc import *
|
|
649
|
+
sage: R2.<x,y> = PolynomialRing(QQ,2)
|
|
650
|
+
sage: start_sys = [x^6-y^2,y^5-1]
|
|
651
|
+
sage: sol = phc.blackbox(start_sys, R2) # optional -- phc
|
|
652
|
+
sage: start_save = sol.save_as_start() # optional -- phc
|
|
653
|
+
sage: end_sys = [x^7-2,y^5-x^2] # optional -- phc
|
|
654
|
+
sage: sol_paths = phc.path_track(start_sys, end_sys, R2, saved_start = start_save) # optional -- phc
|
|
655
|
+
sage: len(sol_paths) # optional -- phc
|
|
656
|
+
30
|
|
657
|
+
"""
|
|
658
|
+
if not saved_start:
|
|
659
|
+
sol = phc.blackbox(start_sys, input_ring)
|
|
660
|
+
saved_start = sol.save_as_start()
|
|
661
|
+
path_track_filename = phc._path_track_file(saved_start, end_sys, input_ring=input_ring, c_skew=c_skew)
|
|
662
|
+
sol_paths = phc._parse_path_file(path_track_filename)
|
|
663
|
+
os.unlink(path_track_filename)
|
|
664
|
+
return sol_paths
|
|
665
|
+
|
|
666
|
+
def plot_paths_2d(self, start_sys, end_sys, input_ring, c_skew=.001, endpoints=True, saved_start=None, rand_colors=False):
|
|
667
|
+
"""
|
|
668
|
+
Return a graphics object of solution paths in the complex plane.
|
|
669
|
+
|
|
670
|
+
INPUT:
|
|
671
|
+
|
|
672
|
+
- ``start_sys`` -- a square polynomial system, given as a list of
|
|
673
|
+
polynomials
|
|
674
|
+
- ``end_sys`` -- same type as start_sys
|
|
675
|
+
- ``input_ring`` -- for coercion of the variables into the desired ring
|
|
676
|
+
- ``c_skew`` -- (optional) the imaginary part of homotopy multiplier;
|
|
677
|
+
nonzero values are often necessary to avoid intermediate path
|
|
678
|
+
collisions
|
|
679
|
+
- ``endpoints`` -- (optional) whether to draw in the ends of paths as
|
|
680
|
+
points
|
|
681
|
+
- ``saved_start`` -- (optional) a phc output file; if not given, start
|
|
682
|
+
system solutions are computed via the ``phc.blackbox`` function
|
|
683
|
+
|
|
684
|
+
OUTPUT: lines and points of solution paths
|
|
685
|
+
|
|
686
|
+
EXAMPLES::
|
|
687
|
+
|
|
688
|
+
sage: from sage.interfaces.phc import *
|
|
689
|
+
sage: from sage.structure.sage_object import SageObject
|
|
690
|
+
sage: R2.<x,y> = PolynomialRing(QQ,2)
|
|
691
|
+
sage: start_sys = [x^5-y^2,y^5-1]
|
|
692
|
+
sage: sol = phc.blackbox(start_sys, R2) # optional -- phc
|
|
693
|
+
sage: start_save = sol.save_as_start() # optional -- phc
|
|
694
|
+
sage: end_sys = [x^5-25,y^5-x^2] # optional -- phc
|
|
695
|
+
sage: testing = phc.plot_paths_2d(start_sys, end_sys, R2) # optional -- phc
|
|
696
|
+
sage: type(testing) # optional -- phc (normally use plot here)
|
|
697
|
+
<class 'sage.plot.graphics.Graphics'>
|
|
698
|
+
"""
|
|
699
|
+
paths = phc.path_track(start_sys, end_sys, input_ring, c_skew=c_skew, saved_start=saved_start)
|
|
700
|
+
path_lines = []
|
|
701
|
+
sol_pts = []
|
|
702
|
+
if rand_colors:
|
|
703
|
+
r_color = {}
|
|
704
|
+
for a_var in input_ring.gens():
|
|
705
|
+
var_name = str(a_var)
|
|
706
|
+
r_color[var_name] = (random(), random(), random())
|
|
707
|
+
for a_sol in paths:
|
|
708
|
+
for a_var in input_ring.gens():
|
|
709
|
+
var_name = str(a_var)
|
|
710
|
+
temp_line = []
|
|
711
|
+
for data in a_sol:
|
|
712
|
+
temp_line.append([data[var_name].real(), data[var_name].imag()])
|
|
713
|
+
if rand_colors:
|
|
714
|
+
path_lines.append(line(temp_line, rgbcolor=r_color[var_name]))
|
|
715
|
+
else:
|
|
716
|
+
path_lines.append(line(temp_line))
|
|
717
|
+
if endpoints:
|
|
718
|
+
sol_pts = []
|
|
719
|
+
for a_sol in paths:
|
|
720
|
+
for a_var in input_ring.gens():
|
|
721
|
+
var_name = str(a_var)
|
|
722
|
+
sol_pts.append(point([a_sol[0][var_name].real(), a_sol[0][var_name].imag()]))
|
|
723
|
+
sol_pts.append(point([a_sol[-1][var_name].real(), a_sol[-1][var_name].imag()]))
|
|
724
|
+
return sum(sol_pts) + sum(path_lines)
|
|
725
|
+
else:
|
|
726
|
+
return sum(path_lines)
|
|
727
|
+
|
|
728
|
+
def mixed_volume(self, polys, verbose=False):
|
|
729
|
+
"""
|
|
730
|
+
Compute the mixed volume of the polynomial system given by the input polys.
|
|
731
|
+
|
|
732
|
+
INPUT:
|
|
733
|
+
|
|
734
|
+
- ``polys`` -- list of multivariate polynomials (elements of a multivariate
|
|
735
|
+
polynomial ring).
|
|
736
|
+
- ``verbose`` -- print lots of verbose information about what this function does
|
|
737
|
+
|
|
738
|
+
OUTPUT: the mixed volume
|
|
739
|
+
|
|
740
|
+
EXAMPLES::
|
|
741
|
+
|
|
742
|
+
sage: from sage.interfaces.phc import *
|
|
743
|
+
sage: R2.<x,y,z> = PolynomialRing(QQ,3)
|
|
744
|
+
sage: test_sys = [(x+y+z)^2-1,x^2-x,y^2-1]
|
|
745
|
+
sage: phc.mixed_volume(test_sys) # optional -- phc
|
|
746
|
+
4
|
|
747
|
+
"""
|
|
748
|
+
output_filename = self._output_from_command_list(['phc -m', '4', 'n', 'n', 'n'], polys, verbose=verbose)
|
|
749
|
+
|
|
750
|
+
with open(output_filename) as out:
|
|
751
|
+
out.read()
|
|
752
|
+
# All done
|
|
753
|
+
out_lines = out.split('\n')
|
|
754
|
+
for a_line in out_lines:
|
|
755
|
+
# the two conditions below are necessary because of changes in output format
|
|
756
|
+
if a_line.find('The mixed volume equals :') == 0 or a_line.find('common mixed volume :') == 0:
|
|
757
|
+
if verbose:
|
|
758
|
+
print('found line: ' + a_line)
|
|
759
|
+
mixed_vol = Integer(a_line.split(':')[1])
|
|
760
|
+
break
|
|
761
|
+
|
|
762
|
+
try:
|
|
763
|
+
return mixed_vol
|
|
764
|
+
except NameError:
|
|
765
|
+
raise RuntimeError("Mixed volume not found in output; something went wrong running phc.")
|
|
766
|
+
|
|
767
|
+
def start_from(self, start_filename_or_string, polys, input_ring, path_track_file=None, verbose=False):
|
|
768
|
+
"""
|
|
769
|
+
This computes solutions starting from a phcpack solution file.
|
|
770
|
+
|
|
771
|
+
INPUT:
|
|
772
|
+
|
|
773
|
+
- ``start_filename_or_string`` -- the filename for a phcpack start system,
|
|
774
|
+
or the contents of such a file as a string. Variable names must match
|
|
775
|
+
the inputring variables. The value of the homotopy variable t should
|
|
776
|
+
be 1, not 0.
|
|
777
|
+
- ``polys`` -- list of multivariate polynomials (elements of a multivariate
|
|
778
|
+
polynomial ring).
|
|
779
|
+
- input_ring: for coercion of the variables into the desired ring.
|
|
780
|
+
- path_track_file: whether to save path-tracking information
|
|
781
|
+
- ``verbose`` -- print lots of verbose information about what this function does
|
|
782
|
+
|
|
783
|
+
OUTPUT: a solution in the form of a PHCObject
|
|
784
|
+
|
|
785
|
+
EXAMPLES::
|
|
786
|
+
|
|
787
|
+
sage: from sage.interfaces.phc import *
|
|
788
|
+
sage: R2.<x,y> = PolynomialRing(QQ,2)
|
|
789
|
+
sage: start_sys = [x^6-y^2,y^5-1]
|
|
790
|
+
sage: sol = phc.blackbox(start_sys, R2) # optional -- phc
|
|
791
|
+
sage: start_save = sol.save_as_start() # optional -- phc
|
|
792
|
+
sage: end_sys = [x^7-2,y^5-x^2] # optional -- phc
|
|
793
|
+
sage: sol = phc.start_from(start_save, end_sys, R2) # optional -- phc
|
|
794
|
+
sage: len(sol.solutions()) # optional -- phc
|
|
795
|
+
30
|
|
796
|
+
"""
|
|
797
|
+
input_filename = tmp_filename()
|
|
798
|
+
output_filename = tmp_filename()
|
|
799
|
+
|
|
800
|
+
if start_filename_or_string.find('THE SOLUTIONS') != -1:
|
|
801
|
+
start_filename = tmp_filename()
|
|
802
|
+
with open(start_filename, 'w') as start_file:
|
|
803
|
+
start_file.write(start_filename_or_string)
|
|
804
|
+
elif os.path.exists(start_filename_or_string):
|
|
805
|
+
start_filename = start_filename_or_string
|
|
806
|
+
else:
|
|
807
|
+
raise RuntimeError("There is something wrong with your start string or filename")
|
|
808
|
+
|
|
809
|
+
# Get the input polynomial text
|
|
810
|
+
input = self._input_file(polys)
|
|
811
|
+
if verbose:
|
|
812
|
+
print("Writing the input file to %s" % input_filename)
|
|
813
|
+
with open(input_filename, 'w') as f:
|
|
814
|
+
f.write(input)
|
|
815
|
+
|
|
816
|
+
if verbose:
|
|
817
|
+
print("The following file will be the input polynomial file to phc.")
|
|
818
|
+
print(input)
|
|
819
|
+
|
|
820
|
+
# Create a phc process
|
|
821
|
+
child_phc = pexpect.spawn('phc')
|
|
822
|
+
child_phc.sendline('y')
|
|
823
|
+
child_phc.sendline(input_filename)
|
|
824
|
+
child_phc.sendline(output_filename)
|
|
825
|
+
child_phc.sendline('0')
|
|
826
|
+
child_phc.sendline('0')
|
|
827
|
+
child_phc.expect('Nonlinear Reduction')
|
|
828
|
+
child_phc.sendline('A')
|
|
829
|
+
child_phc.sendline(start_filename)
|
|
830
|
+
child_phc.sendline('y')
|
|
831
|
+
child_phc.sendline('1')
|
|
832
|
+
child_phc.sendline('0')
|
|
833
|
+
if verbose:
|
|
834
|
+
phc_dialog = child_phc.read(size=40)
|
|
835
|
+
print(phc_dialog)
|
|
836
|
+
child_phc.sendline('n')
|
|
837
|
+
child_phc.sendline('0')
|
|
838
|
+
if verbose:
|
|
839
|
+
child_phc.expect('CURRENT CONTINUATION')
|
|
840
|
+
phc_dialog = child_phc.read(size=40)
|
|
841
|
+
print(phc_dialog)
|
|
842
|
+
child_phc.sendline('0')
|
|
843
|
+
if path_track_file is None:
|
|
844
|
+
child_phc.sendline('0')
|
|
845
|
+
else:
|
|
846
|
+
child_phc.sendline('2')
|
|
847
|
+
child_phc.expect('results')
|
|
848
|
+
dots = child_phc.read()
|
|
849
|
+
if verbose:
|
|
850
|
+
print("should be . : " + dots)
|
|
851
|
+
|
|
852
|
+
# close down the process:
|
|
853
|
+
child_phc.close()
|
|
854
|
+
if not os.path.exists(output_filename):
|
|
855
|
+
raise RuntimeError("The output file does not exist; something went wrong running phc.")
|
|
856
|
+
|
|
857
|
+
# Read the output produced by PHC
|
|
858
|
+
with open(output_filename) as f:
|
|
859
|
+
out = f.read()
|
|
860
|
+
|
|
861
|
+
# Delete the temporary files
|
|
862
|
+
os.unlink(output_filename)
|
|
863
|
+
os.unlink(input_filename)
|
|
864
|
+
|
|
865
|
+
# All done
|
|
866
|
+
return PHC_Object(out, input_ring)
|
|
867
|
+
|
|
868
|
+
def blackbox(self, polys, input_ring, verbose=False):
|
|
869
|
+
"""
|
|
870
|
+
Return as a string the result of running PHC with the given polynomials
|
|
871
|
+
under blackbox mode (the '-b' option).
|
|
872
|
+
|
|
873
|
+
INPUT:
|
|
874
|
+
|
|
875
|
+
- ``polys`` -- list of multivariate polynomials (elements of a multivariate
|
|
876
|
+
polynomial ring).
|
|
877
|
+
- ``input_ring`` -- for coercion of the variables into the desired ring
|
|
878
|
+
- ``verbose`` -- print lots of verbose information about what this function does
|
|
879
|
+
|
|
880
|
+
OUTPUT: a PHC_Object object containing the phcpack output string
|
|
881
|
+
|
|
882
|
+
EXAMPLES::
|
|
883
|
+
|
|
884
|
+
sage: from sage.interfaces.phc import *
|
|
885
|
+
sage: R2.<x,y> = PolynomialRing(QQ,2)
|
|
886
|
+
sage: start_sys = [x^6-y^2,y^5-1]
|
|
887
|
+
sage: sol = phc.blackbox(start_sys, R2) # optional -- phc
|
|
888
|
+
sage: len(sol.solutions()) # optional -- phc
|
|
889
|
+
30
|
|
890
|
+
"""
|
|
891
|
+
|
|
892
|
+
# Get three temporary file names (these will be in SAGE_HOME/.sage/tmp/pid)
|
|
893
|
+
input_filename = tmp_filename()
|
|
894
|
+
output_filename = input_filename + ".phc"
|
|
895
|
+
log_filename = tmp_filename()
|
|
896
|
+
|
|
897
|
+
# Get the input polynomial text
|
|
898
|
+
input = self._input_file(polys)
|
|
899
|
+
if verbose:
|
|
900
|
+
print("Writing the input file to %s" % input_filename)
|
|
901
|
+
with open(input_filename, 'w') as f:
|
|
902
|
+
f.write(input)
|
|
903
|
+
|
|
904
|
+
if verbose:
|
|
905
|
+
print("The following file will be the input polynomial file to phc.")
|
|
906
|
+
print(input)
|
|
907
|
+
|
|
908
|
+
# Create the phc command line>
|
|
909
|
+
cmd = 'phc -b %s %s' % (input_filename, output_filename)
|
|
910
|
+
|
|
911
|
+
if verbose:
|
|
912
|
+
print("The phc command line is:")
|
|
913
|
+
print(cmd)
|
|
914
|
+
|
|
915
|
+
# Do it -- make the system call.
|
|
916
|
+
e = os.system(cmd)
|
|
917
|
+
|
|
918
|
+
# Was there an error?
|
|
919
|
+
if e:
|
|
920
|
+
from sage.misc.sage_ostools import have_program
|
|
921
|
+
if not have_program('phc'):
|
|
922
|
+
print(str(os.system('which phc')) + ' PHC needs to be installed and in your path')
|
|
923
|
+
raise RuntimeError
|
|
924
|
+
# todo -- why? etc.
|
|
925
|
+
with open(log_filename) as f:
|
|
926
|
+
msg = f.read()
|
|
927
|
+
raise RuntimeError(msg + "\nError running phc.")
|
|
928
|
+
|
|
929
|
+
if not os.path.exists(output_filename):
|
|
930
|
+
raise RuntimeError("The output file does not exist; something went wrong running phc.")
|
|
931
|
+
|
|
932
|
+
# Read the output produced by PHC
|
|
933
|
+
with open(output_filename) as f:
|
|
934
|
+
out = f.read()
|
|
935
|
+
|
|
936
|
+
# All done
|
|
937
|
+
return PHC_Object(out, input_ring)
|
|
938
|
+
|
|
939
|
+
|
|
940
|
+
################################
|
|
941
|
+
|
|
942
|
+
# The unique phc interface instance.
|
|
943
|
+
phc = PHC()
|