diff --git a/src/sage/interfaces/phc.py b/src/sage/interfaces/phc.py index bf8a5d6d0cb..25e870f020e 100644 --- a/src/sage/interfaces/phc.py +++ b/src/sage/interfaces/phc.py @@ -34,7 +34,7 @@ import os import re import pexpect -import random +from random import random from sage.misc.temporary_file import tmp_filename from sage.rings.real_mpfr import RR @@ -44,7 +44,7 @@ from sage.plot.point import point -def get_solution_dicts(output_file_contents, input_ring, get_failures = True): +def get_solution_dicts(output_file_contents, input_ring, get_failures=True): """ Return a list of dictionaries of variable:value (key:value) pairs. Only used internally; see the solution_dict function in @@ -71,29 +71,31 @@ def get_solution_dicts(output_file_contents, input_ring, get_failures = True): """ output_list = output_file_contents.splitlines() solution_dicts = [] - for solution_line in range(len(output_list)-1,-1,-1): + for solution_line in range(len(output_list) - 1, -1, -1): if output_list[solution_line].find('THE SOLUTIONS') == 0: break try: - var_number = int(output_list[solution_line+2].split(' ')[1]) + var_number = int(output_list[solution_line + 2].split(' ')[1]) # sol_number = int(output_list[solution_line+2].split(' ')[0]) except IndexError: - var_number = int(output_list[solution_line+1].split(' ')[1]) + var_number = int(output_list[solution_line + 1].split(' ')[1]) # sol_number = int(output_list[solution_line+1].split(' ')[0]) - for i in range(solution_line + 1,len(output_list)): + for i in range(solution_line + 1, len(output_list)): if output_list[i].count('the solution for t') == 1: - if output_list[i-3].count('success') > 0 or get_failures: + if output_list[i - 3].count('success') > 0 or get_failures: temp_dict = {} - for j in range(1,var_number+1): - rawsplit = output_list[i+j].split(': ')[1].split(' ') + for j in range(1, var_number + 1): + rawsplit = output_list[i + j].split(': ')[1].split(' ') for extras in range(rawsplit.count('')): rawsplit.remove('') - temp_var = output_list[i+j].split(': ')[0].replace(' ','') - temp_dict[input_ring(temp_var)] = CC(rawsplit[0],rawsplit[1]) + temp_var = output_list[i + j].split(': ')[0].replace(' ', '') + temp_dict[input_ring(temp_var)] = CC(rawsplit[0], + rawsplit[1]) solution_dicts.append(temp_dict) return solution_dicts -def get_classified_solution_dicts(output_file_contents, input_ring, get_failures = True): + +def get_classified_solution_dicts(output_file_contents, input_ring, get_failures=True): """ Return a dictionary of lists of dictionaries of variable:value (key:value) pairs. Only used internally; see the classified_solution_dict function in @@ -120,17 +122,17 @@ def get_classified_solution_dicts(output_file_contents, input_ring, get_failures """ output_list = output_file_contents.splitlines() solution_dicts = {} - solution_types = ['complex', 'real','failure'] + solution_types = ['complex', 'real', 'failure'] for sol_type in solution_types: solution_dicts[sol_type] = [] - for solution_line in range(len(output_list)-1,-1,-1): + for solution_line in range(len(output_list) - 1, -1, -1): if output_list[solution_line].find('THE SOLUTIONS') == 0: break - var_number = int(output_list[solution_line+2].split(' ')[1]) + var_number = int(output_list[solution_line + 2].split(' ')[1]) # sol_number = int(output_list[solution_line+2].split(' ')[0]) - for i in range(solution_line + 1,len(output_list)): + for i in range(solution_line + 1, len(output_list)): if output_list[i].count('the solution for t') == 1: - phc_type = output_list[i+var_number+1].split(' = ')[-1] + phc_type = output_list[i + var_number + 1].split(' = ')[-1] if phc_type.find('complex') != -1: phc_type = 'complex' elif phc_type.find('real') != -1: @@ -138,18 +140,20 @@ def get_classified_solution_dicts(output_file_contents, input_ring, get_failures else: phc_type = 'failure' temp_dict = {} - for j in range(1,var_number+1): - rawsplit = output_list[i+j].split(': ')[1].split(' ') + for j in range(1, var_number + 1): + rawsplit = output_list[i + j].split(': ')[1].split(' ') for extras in range(rawsplit.count('')): rawsplit.remove('') - temp_var = output_list[i+j].split(': ')[0].replace(' ','') + temp_var = output_list[i + j].split(': ')[0].replace(' ', '') if phc_type == 'real': temp_dict[input_ring(temp_var)] = RR(rawsplit[0]) else: - temp_dict[input_ring(temp_var)] = CC(rawsplit[0],rawsplit[1]) + temp_dict[input_ring(temp_var)] = CC(rawsplit[0], + rawsplit[1]) solution_dicts[phc_type].append(temp_dict) return solution_dicts + def get_variable_list(output_file_contents): """ Return the variables, as strings, in the order in which PHCpack has processed them. @@ -164,16 +168,17 @@ def get_variable_list(output_file_contents): ['x1', 'x2'] """ output_list = output_file_contents.splitlines() - for solution_line in range(len(output_list)-1,-1,-1): + for solution_line in range(len(output_list) - 1, -1, -1): if output_list[solution_line].find('THE SOLUTIONS') == 0: break - var_number = int(output_list[solution_line+2].split(' ')[1]) + var_number = int(output_list[solution_line + 2].split(' ')[1]) varlist = [] for var_ind in range(var_number): var = output_list[solution_line + 8 + var_ind].split(' ')[1] varlist.append(var) return varlist + class PHC_Object: def __init__(self, output_file_contents, input_ring): @@ -199,10 +204,9 @@ def __init__(self, output_file_contents, input_ring): self.output_file_contents = output_file_contents self.input_ring = input_ring - - def save_as_start(self, start_filename = None, sol_filter = ''): + def save_as_start(self, start_filename=None, sol_filter=''): """ - Saves a solution as a phcpack start file. The usual output is + Save a solution as a phcpack start file. The usual output is just as a string, but it can be saved to a file as well. Even if saved to a file, it still returns the output string. @@ -225,27 +229,27 @@ def save_as_start(self, start_filename = None, sol_filter = ''): break else: start_data += a_line + '\n' - for index in range(len(output_list)-1,0,-1): + for index in range(len(output_list) - 1, 0, -1): a_line = output_list[index] if a_line.find('THE SOLUTIONS') != -1: found_solutions = index break start_data += output_list[found_solutions] + '\n\n' try: - var_number = int(output_list[found_solutions+1].split(' ')[1]) + var_number = int(output_list[found_solutions + 1].split(' ')[1]) except Exception: # bad error handling - var_number = int(output_list[found_solutions+2].split(' ')[1]) + var_number = int(output_list[found_solutions + 2].split(' ')[1]) sol_count = 0 sol_data = '' for i in range(found_solutions + 2, len(output_list)): - if output_list[i].count('the solution for t') == 1 and output_list[i+1+var_number].find(sol_filter) != -1: - phc_type = output_list[i+var_number+1].split(' = ')[-1] + if output_list[i].count('the solution for t') == 1 and output_list[i + 1 + var_number].find(sol_filter) != -1: + phc_type = output_list[i + var_number + 1].split(' = ')[-1] if phc_type.find('no solution') == -1: sol_count += 1 - for ind2 in range(i-3,i+var_number+2): + for ind2 in range(i - 3, i + var_number + 2): sol_data += output_list[ind2] + '\n' - jan_bar = '===========================================================================\n' + jan_bar = '=' * 75 + '\n' sol_data += jan_bar start_data += str(sol_count) + ' ' + str(var_number) + '\n' start_data += jan_bar + sol_data @@ -257,6 +261,7 @@ def save_as_start(self, start_filename = None, sol_filter = ''): def classified_solution_dicts(self): """ Return a dictionary of lists of dictionaries of solutions. + Its not as crazy as it sounds; the keys are the types of solutions as classified by phcpack: regular vs. singular, complex vs. real @@ -286,7 +291,7 @@ def classified_solution_dicts(self): self.__classified_sols = classified_sols return classified_sols - def solution_dicts(self, get_failures = False): + def solution_dicts(self, get_failures=False): """ Return a list of solutions in dictionary form: variable:value. @@ -321,11 +326,11 @@ def solution_dicts(self, get_failures = False): return self.__solution_dicts except AttributeError: pass - solution_dicts = get_solution_dicts(self.output_file_contents, self.input_ring, get_failures = get_failures) + solution_dicts = get_solution_dicts(self.output_file_contents, self.input_ring, get_failures=get_failures) self.__solution_dicts = solution_dicts return solution_dicts - def solutions(self, get_failures = False): + def solutions(self, get_failures=False): """ Return a list of solutions in the ComplexField. @@ -358,7 +363,7 @@ def solutions(self, get_failures = False): return self.__solutions except AttributeError: pass - solution_dicts = get_solution_dicts(self.output_file_contents, self.input_ring, get_failures = get_failures) + solution_dicts = get_solution_dicts(self.output_file_contents, self.input_ring, get_failures=get_failures) self.__solution_dicts = solution_dicts solutions = [sol_dict.values() for sol_dict in solution_dicts] self.__solutions = solutions @@ -386,6 +391,7 @@ def variable_list(self): self.__var_list = var_list return var_list + class PHC: """ A class to interface with PHCpack, for computing numerical @@ -412,7 +418,7 @@ class PHC: [[0, 0], [0, 0]] """ - def _output_from_command_list(self, command_list, polys, verbose = False): + def _output_from_command_list(self, command_list, polys, verbose=False): """ A pexpect interface to phcpack, given a command list for interactive dialogs. The input file is supplied from the @@ -499,13 +505,12 @@ def _input_file(self, polys): """ if not isinstance(polys, (list, tuple)): raise TypeError('polys must be a list or tuple') - s = '%s\n'%len(polys) + s = '%s\n' % len(polys) for f in polys: - s += f._repr_() + ';\n' # note the semicolon *terminators* - + s += f._repr_() + ';\n' # note the semicolon *terminators* return s - def _parse_path_file(self, input_filename, verbose = False): + def _parse_path_file(self, input_filename, verbose=False): """ Takes a phpack output file containing path tracking information and parses it into a list of lists of dictionaries - i.e. a @@ -533,7 +538,6 @@ def _parse_path_file(self, input_filename, verbose = False): sage: len(sol_paths) # optional -- phc 25 """ - if not os.path.exists(input_filename): raise RuntimeError("The file containing output from phc (" + input_filename + ") cannot be found") @@ -546,10 +550,10 @@ def _parse_path_file(self, input_filename, verbose = False): # regular expressions for matching certain output types var_cnt_regex = re.compile('^ +([0-9]+)') - output_regex = re.compile('^OUTPUT INFORMATION DURING') - 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) - 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) - complete_regex= re.compile('^TIMING INFORMATION') + output_regex = re.compile('^OUTPUT INFORMATION DURING') + 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) + 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) + complete_regex = re.compile('^TIMING INFORMATION') breakfast = False a_line = fh.readline() @@ -574,7 +578,7 @@ def _parse_path_file(self, input_filename, verbose = False): # fh_w.write( "T=> G1(" + m.group(2) + '),G2(' + m.group(3) + ")\n") # read off two lines - this should be 'm' and 'the solution for t :' a_line = fh.readline() - end_test = a_line # store this to check for end of solution + end_test = a_line # store this to check for end of solution a_line = fh.readline() t_val = CC(m.group(2), m.group(3)) temp_dict = {} @@ -586,7 +590,8 @@ def _parse_path_file(self, input_filename, verbose = False): # m.group(2) contains our var name # m.group(4) contains our real val # m.group(5) contains our imaginary val - temp_dict[m.group(2)] = CC(m.group(4),m.group(5)) + temp_dict[m.group(2)] = CC(m.group(4), + m.group(5)) steps_dicts.append(temp_dict) # check if its the end of a solution if end_test.find('Length of path') != -1: @@ -605,7 +610,7 @@ def _parse_path_file(self, input_filename, verbose = False): fh.close() return solutions_dicts - def _path_track_file(self, start_filename_or_string, polys, input_ring, c_skew = 0.001, verbose = False): + def _path_track_file(self, start_filename_or_string, polys, input_ring, c_skew=0.001, verbose=False): """ Return the filename which contains path tracking output. @@ -632,9 +637,9 @@ def _path_track_file(self, start_filename_or_string, polys, input_ring, c_skew = else: raise RuntimeError("There is something wrong with your start string or filename") - 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) + 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) - def path_track(self, start_sys, end_sys, input_ring, c_skew = .001, saved_start = None): + def path_track(self, start_sys, end_sys, input_ring, c_skew=.001, saved_start=None): """ This function computes homotopy paths between the solutions of start_sys and end_sys. @@ -664,18 +669,17 @@ def path_track(self, start_sys, end_sys, input_ring, c_skew = .001, saved_start sage: len(sol_paths) # optional -- phc 30 """ - if not saved_start: sol = phc.blackbox(start_sys, input_ring) saved_start = sol.save_as_start() - path_track_filename = phc._path_track_file(saved_start, end_sys, input_ring = input_ring, c_skew = c_skew) + path_track_filename = phc._path_track_file(saved_start, end_sys, input_ring=input_ring, c_skew=c_skew) sol_paths = phc._parse_path_file(path_track_filename) os.unlink(path_track_filename) return sol_paths - def plot_paths_2d(self, start_sys, end_sys, input_ring, c_skew = .001, endpoints = True, saved_start = None, rand_colors = False): + def plot_paths_2d(self, start_sys, end_sys, input_ring, c_skew=.001, endpoints=True, saved_start=None, rand_colors=False): """ - This returns a graphics object of solution paths in the complex plane. + Return a graphics object of solution paths in the complex plane. INPUT: @@ -705,14 +709,14 @@ def plot_paths_2d(self, start_sys, end_sys, input_ring, c_skew = .001, endpoints sage: type(testing) # optional -- phc (normally use plot here) """ - paths = phc.path_track(start_sys, end_sys, input_ring, c_skew = c_skew, saved_start = saved_start) + paths = phc.path_track(start_sys, end_sys, input_ring, c_skew=c_skew, saved_start=saved_start) path_lines = [] sol_pts = [] if rand_colors: r_color = {} for a_var in input_ring.gens(): var_name = str(a_var) - r_color[var_name] = (random(),random(),random()) + r_color[var_name] = (random(), random(), random()) for a_sol in paths: for a_var in input_ring.gens(): var_name = str(a_var) @@ -720,7 +724,7 @@ def plot_paths_2d(self, start_sys, end_sys, input_ring, c_skew = .001, endpoints for data in a_sol: temp_line.append([data[var_name].real(), data[var_name].imag()]) if rand_colors: - path_lines.append(line(temp_line, rgbcolor = r_color[var_name])) + path_lines.append(line(temp_line, rgbcolor=r_color[var_name])) else: path_lines.append(line(temp_line)) if endpoints: @@ -732,11 +736,11 @@ def plot_paths_2d(self, start_sys, end_sys, input_ring, c_skew = .001, endpoints sol_pts.append(point([a_sol[-1][var_name].real(), a_sol[-1][var_name].imag()])) return sum(sol_pts) + sum(path_lines) else: - return sum(path_lines) + return sum(path_lines) def mixed_volume(self, polys, verbose=False): """ - Computes the mixed volume of the polynomial system given by the input polys. + Compute the mixed volume of the polynomial system given by the input polys. INPUT: @@ -756,7 +760,7 @@ def mixed_volume(self, polys, verbose=False): sage: phc.mixed_volume(test_sys) # optional -- phc 4 """ - output_filename = self._output_from_command_list(['phc -m','4','n','n','n'], polys, verbose = verbose) + output_filename = self._output_from_command_list(['phc -m', '4', 'n', 'n', 'n'], polys, verbose=verbose) with open(output_filename) as out: out.read() @@ -766,7 +770,7 @@ def mixed_volume(self, polys, verbose=False): # the two conditions below are necessary because of changes in output format if a_line.find('The mixed volume equals :') == 0 or a_line.find('common mixed volume :') == 0: if verbose: - print('found line: ' + a_line) + print('found line: ' + a_line) mixed_vol = Integer(a_line.split(':')[1]) break @@ -775,8 +779,7 @@ def mixed_volume(self, polys, verbose=False): except NameError: raise RuntimeError("Mixed volume not found in output; something went wrong running phc.") - - def start_from(self, start_filename_or_string, polys, input_ring, path_track_file = None, verbose = False): + def start_from(self, start_filename_or_string, polys, input_ring, path_track_file=None, verbose=False): """ This computes solutions starting from a phcpack solution file. @@ -845,13 +848,13 @@ def start_from(self, start_filename_or_string, polys, input_ring, path_track_fil child_phc.sendline('1') child_phc.sendline('0') if verbose: - phc_dialog = child_phc.read(size = 40) + phc_dialog = child_phc.read(size=40) print(phc_dialog) child_phc.sendline('n') child_phc.sendline('0') if verbose: child_phc.expect('CURRENT CONTINUATION') - phc_dialog = child_phc.read(size = 40) + phc_dialog = child_phc.read(size=40) print(phc_dialog) child_phc.sendline('0') if path_track_file is None: @@ -863,7 +866,7 @@ def start_from(self, start_filename_or_string, polys, input_ring, path_track_fil if verbose: print("should be . : " + dots) - #close down the process: + # close down the process: child_phc.close() if not os.path.exists(output_filename): raise RuntimeError("The output file does not exist; something went wrong running phc.") @@ -879,7 +882,7 @@ def start_from(self, start_filename_or_string, polys, input_ring, path_track_fil # All done return PHC_Object(out, input_ring) - def blackbox(self, polys, input_ring, verbose = False): + def blackbox(self, polys, input_ring, verbose=False): """ Return as a string the result of running PHC with the given polynomials under blackbox mode (the '-b' option). @@ -922,7 +925,7 @@ def blackbox(self, polys, input_ring, verbose = False): print(input) # Create the phc command line> - cmd = 'phc -b %s %s'%(input_filename, output_filename) + cmd = 'phc -b %s %s' % (input_filename, output_filename) if verbose: print("The phc command line is:")