diff --git a/python/ptolemy/processFileBase.py b/python/ptolemy/processFileBase.py index f47f70e1..69cc395e 100644 --- a/python/ptolemy/processFileBase.py +++ b/python/ptolemy/processFileBase.py @@ -1,6 +1,7 @@ import re from . import utilities +from .ptolemyObstructionClass import PtolemyObstructionClass """ Basic functions to read a ptolemy solutions file. @@ -139,6 +140,47 @@ def get_py_eval(text): utilities.join_long_lines( find_unique_section(text, "PY=EVAL=SECTION"))) +# A dict-like object we can feed into the variable dict +# function in the pre-computed solution file. +# +# It is sufficient to evaluate the obstruction class but +# returns 1 for all other keys. +# +class _DummyDict: + def __getitem__(self, key): + if key == '1' or key[0] == 'c': + return 1 + raise KeyError(key) + +def check_obstruction_class_for_variable_dict_function( + variable_dict_function, obstruction_class): + + if not isinstance(obstruction_class, PtolemyObstructionClass): + # Note that no obstruction class has always been + # corresponding to index 0 ("c0" in file name). + # So nothing to check. + # + # We also don't check for the generalized + # obstruction class. + # + # We should double check that our solutions + # for PSL(n,C) with n>2 are still fine... + # + return + + variable_dict = variable_dict_function(_DummyDict()) + precomputed_class = [ + variable_dict[var_name] + for var_name in obstruction_class._explain_basis ] + + # Obstruction class contains element in Z/2 as additive group. + # We need to convert it to be in multiplicative group {-1, 1}. + actual_class = [ + (-1) ** i for i in obstruction_class._H2_element ] + + if actual_class != precomputed_class: + print("Warning: the obstruction class does not match the obstruction class of the pre-computed solution.") + print(actual_class, precomputed_class) def get_manifold_thunk(text): """ diff --git a/python/ptolemy/ptolemyVariety.py b/python/ptolemy/ptolemyVariety.py index f6d2ef3e..f8e67714 100644 --- a/python/ptolemy/ptolemyVariety.py +++ b/python/ptolemy/ptolemyVariety.py @@ -495,7 +495,8 @@ def _solution_file_url(self, data_url=None, rur=False): return data_url + self.path_to_file() + '/' + urlquote(filename) - def _retrieve_solution_file(self, data_url=None, prefer_rur=False, + def _retrieve_solution_file(self, + data_url=None, prefer_rur=False, verbose=False): # First try to retrieve solutions from the URL corresponding to @@ -510,15 +511,45 @@ def _retrieve_solution_file(self, data_url=None, prefer_rur=False, return _retrieve_url(url) except PtolemyFileMissingError: + pass - # If that file wasn't there, try to retrieve solutions from URL - # corresponding to the non-prefered format + # If that file wasn't there, try to retrieve solutions from URL + # corresponding to the non-prefered format - url = self._solution_file_url(data_url=data_url, - rur=not prefer_rur) - if verbose: - print("Retrieving solutions instead from %s ...:" % url) - return _retrieve_url(url) + url = self._solution_file_url(data_url=data_url, + rur=not prefer_rur) + if verbose: + print("Retrieving solutions instead from %s ...:" % url) + + return _retrieve_url(url) + + def _check_obstruction_class_for_precomputed_file( + self, text): + + # Grab the PY=EVAL=SECTION + # Note that this will be evaluated again later. + # But it is cheap enough that the double evaluation should not matter. + py_eval = processFileBase.get_py_eval(text) + + # Now get the function that takes a dictionary-like object with + # the solutions to the variety and expands it to a dictionary + # assigning a value to all Ptolemy coordinates and obstruction class + # variables. + variable_dict_function = py_eval['variable_dict'] + + # As noticed by Nathan, the obstruction classes used for producing + # the pre-computed solutions do not match the obstruction classes + # we compute now. + # This is due to pari changing the code for computing the + # Smith normal form in version 2.13 (see + # http://pari.math.u-bordeaux.fr/archives/pari-announce-20/msg00006.html) + # + # We thus check here explicitly that the obstruction class still + # matches. + # + processFileBase.check_obstruction_class_for_variable_dict_function( + variable_dict_function, + self._obstruction_class) def retrieve_decomposition(self, data_url=None, verbose=True): @@ -545,6 +576,9 @@ def retrieve_solutions(self, numerical=False, text = self._retrieve_solution_file(data_url=data_url, prefer_rur=prefer_rur, verbose=verbose) + + self._check_obstruction_class_for_precomputed_file(text) + if verbose: print("Parsing...")