def printRealNumberAsFixed(r): assert isinstance(r, mpmath.mpf) if lessThanMaxErr(r): return '0' else: maxErrDigits = globalsettings.getSetting("maximalErrorDigits") s = mpmath.nstr(r, maxErrDigits, min_fixed = -mpmath.inf, max_fixed = mpmath.inf) a, b = s.split('.') # mpmath chops 1.2000000 to 1.2, so we are adding '0' to b alen = len(a) if a[0] in '+-': alen -= 1 b += (maxErrDigits - alen + len(b)) * '0' # b should never be more than maximalErrorDigits b = b[:maxErrDigits - alen] return a + '.' + b
def binarySearchIndex(listOfDicts, key, value): return _binarySearchIndex( listOfDicts, key, value=value + globalsettings.getSetting("maximalError"), firstIndex=0, lastIndex=len(listOfDicts), )
def _solutionCheck(dict1, dict2): maxErr = globalsettings.getSetting("maximalError") assert set(dict1.keys()) == set(dict2.keys()) for k in dict1.keys(): if not abs(dict1[k] - dict2[k]) < maxErr: return False return True
def binarySearch(listOfDicts, key, value): index = binarySearchIndex(listOfDicts, key, value) maxError = globalsettings.getSetting("maximalError") if index < len(listOfDicts) and abs(listOfDicts[index][key] - value) < maxError: return listOfDicts[index] return None
def logOfSquare(c): return mpmath.log(c) csquare = c * c maxErr = globalsettings.getSetting("maximalError") if not ((csquare.real > 0 or abs(csquare.imag) > maxErr)): raise NumericalError(c, msg = "logOfSqaure near branch cut") return mpmath.log(csquare) / 2
def pqCandidates(z, w = w): PiI = mpmath.pi * 1j if abs(1 - z) < globalsettings.getSetting("maximalError"): return (z, 0, 0), 1 p = mpmathRoundToInt( (w.w0 - mpmath.log( z)) / PiI) q = mpmathRoundToInt( (w.w1 + mpmath.log(1-z)) / PiI) err = abs(w.w2 + mpmath.log(z) - mpmath.log(1-z) + p * PiI + q * PiI) return (z, p, q), err
def matchingRowIndices(listOfDicts, key, value): index = binarySearchIndex(listOfDicts, key, value) + 1 firstIndex = index lastIndex = index maxError = globalsettings.getSetting("maximalError") while firstIndex > 0 and abs(listOfDicts[firstIndex - 1][key] - value) < maxError: firstIndex -= 1 return firstIndex, lastIndex
def __init__(self, P, no_check = False): assert isinstance(P, PtolemyCochain) self.sign = P.sign self.ptolemy_index = P.ptolemy_index self.tet_index = P.tet_index self.w0 = logOfSquare(P.c03) + logOfSquare(P.c12) - logOfSquare(P.c02) - logOfSquare(P.c13) self.w1 = logOfSquare(P.c02) + logOfSquare(P.c13) - logOfSquare(P.c01) - logOfSquare(P.c23) if no_check: self.w2 = - (self.w0 + self.w1) return self.w2 = logOfSquare(P.c01) + logOfSquare(P.c23) - logOfSquare(P.c03) - logOfSquare(P.c12) w0_e = mpmath.exp(self.w0) w1_e = mpmath.exp(-self.w1) errs = [abs(1 - w0_e - w1_e), abs(1 + w0_e - w1_e), abs(1 - w0_e + w1_e), abs(1 + w0_e + w1_e)] if not (errs[0] < globalsettings.getSetting("maximalError") or errs[1] < globalsettings.getSetting("maximalError") or errs[2] < globalsettings.getSetting("maximalError") or errs[3] < globalsettings.getSetting("maximalError")): raise NumericalError(val = errs, msg = "w triple (%s,%s,%s) from %s %s %s %s %s %s" % (self.w0, self.w1, self.w2, P.c01, P.c02, P.c03, P.c12, P.c13, P.c23)) if not abs(self.w0+self.w1+self.w2) < globalsettings.getSetting("maximalError"): raise NumericalError(val = (self.w0+self.w1+self.w2).abs(), msg = "w triple (%s,%s,%s) not sum to 0 from %s %s %s %s %s %s" % (self.w0, self.w1, self.w2, P.c01, P.c02, P.c03, P.c12, P.c13, P.c23))
def checkConsistency(self): c01c23 = self.c01 * self.c23 c02c13 = self.c02 * self.c13 c03c12 = self.c03 * self.c12 maxErr = globalsettings.getSetting("maximalError") if not ( (abs(- c03c12 - c01c23 + c02c13) < maxErr) or (abs(- c03c12 + c01c23 + c02c13) < maxErr) or (abs( c03c12 - c01c23 + c02c13) < maxErr) or (abs( c03c12 + c01c23 + c02c13) < maxErr)): raise NumericalError( val=[ (- c03c12 - c01c23 + c02c13).abs(), (- c03c12 + c01c23 + c02c13).abs(), (c03c12 - c01c23 + c02c13).abs(), ( c03c12 + c01c23 + c02c13).abs()], msg = "PtolemyCochain(%s,%s,%s,%s,%s,%s)" % ( self.c01, self.c02, self.c03, self.c12, self.c13, self.c23))
def check_solution_on_gluing_equations(t, N, solution, cohomology_class = None): maxErr = globalsettings.getSetting("maximalError") if cohomology_class: cohomology_coefficients = ( cohomology_2_rel_boundary_class_to_coeffs(t,cohomology_class)) for tet in t.tet_list: i = tet.index if cohomology_class: signs = cohomology_coefficients[tet.index] sign_01 = Z2_to_sign(signs[2] + signs[3]) sign_12 = Z2_to_sign(signs[0] + signs[3]) else: sign_01 = +1 sign_12 = +1 for coord in simplex_coords_with_fixed_sum(4, N-2): err = ( - sign_01 * solution[c_parameter_var(coord+(1,0,0,1),i)] * solution[c_parameter_var(coord+(0,1,1,0),i)] - sign_12 * solution[c_parameter_var(coord+(1,1,0,0),i)] * solution[c_parameter_var(coord+(0,0,1,1),i)] + solution[c_parameter_var(coord+(1,0,1,0),i)] * solution[c_parameter_var(coord+(0,1,0,1),i)]) if abs(err) > maxErr: raise NumericalError( val = err, msg = "in verify gluing equations")
def lessThanMaxErr(r): return abs(r) < globalsettings.getSetting("maximalError")
def __init__(self, w, no_check = False): assert isinstance(w, w_triple) self.sign = w.sign self.ptolemy_index = w.ptolemy_index self.tet_index = w.tet_index def pqCandidates(z, w = w): PiI = mpmath.pi * 1j if abs(1 - z) < globalsettings.getSetting("maximalError"): return (z, 0, 0), 1 p = mpmathRoundToInt( (w.w0 - mpmath.log( z)) / PiI) q = mpmathRoundToInt( (w.w1 + mpmath.log(1-z)) / PiI) err = abs(w.w2 + mpmath.log(z) - mpmath.log(1-z) + p * PiI + q * PiI) return (z, p, q), err candidate1, err1 = pqCandidates(z = mpmath.exp(w.w0)) candidate2, err2 = pqCandidates(z = - mpmath.exp(w.w0)) if err1 < err2: candidate, err = candidate1, err1 else: candidate, err = candidate2, err2 if err > globalsettings.getSetting("maximalError"): raise NumericalError(val = err, msg = "err1 %s %s" % (candidate, err)) self.z, self.p, self.q = candidate self.zp = 1 / (1 - self.z) self.zpp = 1 - 1 / self.z return if abs(w.w0) < globalsettings.getSetting("maximalError"): err1 = 1 else: z1 = mpmath.exp(w.w0) p1 = int( ((w.w0 - mpmath.log(z1)) / PiI).real ) q1 = int( ((w.w1 + mpmath.log(1 - z1)) / PiI).real ) err1 = abs((w.w2 + mpmath.log(z1) - mpmath.log(1 - z1) + p1 * PiI + q1 * PiI)) z2 = - mpmath.exp(w.w0) p2 = int( ((w.w0 - mpmath.log(z2)) / PiI).real ) q2 = int( ((w.w1 + mpmath.log(1 - z2)) / PiI).real ) err2 = abs((w.w2 + mpmath.log(z2) - mpmath.log(1 - z2) + p2 * PiI + q2 * PiI)) if err1 < err2: if not err1 < globalsettings.getSetting("maximalError"): raise NumericalError(val = err1, msg = "err1 %s %s %s %s %s %s" % ( z1, p1, q1, w.w0, w.w1, w.w2)) self.z = z1 self.p = p1 self.q = q1 else: if not err2 < globalsettings.getSetting("maximalError"): raise NumericalError(val = err2, msg = "err1 %s %s %s %s %s %s" % ( z2, p2, q2, w.w0, w.w1, w.w2)) self.z = z2 self.p = p2 self.q = q2
from csvUtilities.readCensusTable import readCensusTable import globalsettings import mpmath from linearCombinations import binarySearch, filterRepresentativeMfds, twoTerms from linearCombinations.formatLinearCombination import formatLinearCombination mpmath.mp.dps = 70 globalsettings.setSetting("maximalError", mpmath.mpf("0.1") ** 50) globalsettings.setSetting("maximalErrorDigits", 50) testCensusTablePath = globalsettings.getSetting("testCensusTablePath") censusTableFile = testCensusTablePath + "/exampleCensusTable.csv" censusTable = readCensusTable(censusTableFile, sortKey="Volume") representatives = filterRepresentativeMfds.filterRepresentativeMfds(censusTable.listOfDicts) def checkBinarySearchResult(vol, resultNames): if isinstance(vol, str): vol = mpmath.mpf(vol) rows = binarySearch.matchingRows(censusTable.listOfDicts, "Volume", vol) names = [row["Name"] for row in rows] assert set(resultNames) == set(names), Exception("Expected: %s\nGot %s" % (resultNames, names)) def testBinarySearch(): checkBinarySearchResult(
def solvePolynomialEquations(polys, polynomialSolver, free_dim = 0, with_poly_history = False, poly_history="", variable_dict = { }, non_linear_equation_encountered=False): # polys = [polynomial.convertCoefficients(number) for polynomial in polys] if globalsettings.getSetting("solvePolynomialEquationsLog"): poly_history += '\n\n\n\n'+'\n'.join(map(_printPoly,polys))+'\n\n============\n' if not polys: assert free_dim == 0 if with_poly_history: return [(variable_dict,poly_history)] else: return [variable_dict] solutions=[] for i in polys: assert isinstance(i,Polynomial) univariate_polys = [ poly for poly in polys if poly.isUnivariate() ] if globalsettings.getSetting("solvePolynomialEquationsLog"): poly_history=poly_history+'\n\n'+str(map(_printPoly,univariate_polys))+'\n' if univariate_polys: univariate_poly = univariate_polys[0] # print univariate_poly variable_name = univariate_poly.variables()[0] if globalsettings.getSetting("solvePolynomialEquationsLog"): poly_history = poly_history + '\n\nSolving for %s\n' % variable_name try: sol = polynomialSolver(univariate_poly) if globalsettings.getSetting("solvePolynomialEquationsLog"): poly_history = poly_history+'\n'+str(sol)+'\n' except Exception as e: raise SolverException("Error in find_complex_roots when solving: " + str(univariate_poly) + " " + repr(e), poly_history) assert len(sol)==univariate_poly.degree() #if not len(sol)==1: # if non_linear_equation_encountered: # raise SolverException( # "Encountered second non linear equation: " + # str(univariate_poly), # poly_history) # # non_linear_equation_encountered = True else: if free_dim == 0: raise SolverException("No univariate polynomial left", poly_history) else: univariate_poly = None variable_name = polys[-1].variables()[0] sol = [random_complex_modulos()] if globalsettings.getSetting("solvePolynomialEquationsLog"): poly_history += "In pick random solution for %s:\n %s\n\n" % (variable_name, sol) free_dim = free_dim - 1 for value in sol: new_variable_dict = dict(variable_dict) new_variable_dict[variable_name] = value new_polys = [ poly.substitute( { variable_name : Polynomial.constantPolynomial(value) }) for poly in polys if not poly is univariate_poly] new_solutions = solvePolynomialEquations( new_polys, polynomialSolver = polynomialSolver, free_dim = free_dim, with_poly_history = with_poly_history, poly_history = poly_history, variable_dict = new_variable_dict) solutions = solutions + new_solutions return solutions
def get_complex_volumes_and_cross_ratios(t, N, c, primeIdeal, not_paranoid = False): # Find the points in the variety # solvePolynomialEquations assumes that prime_ideal is given # in Groebner basis all_cvols = [] all_cross_ratios = [] sys.stderr.write("Solving numerically the old way...\n") def conversionFunction(c): if isinstance(c, Fraction): return mpmath.mpc(c.numerator) / mpmath.mpc(c.denominator) else: return mpmath.mpc(c) primeIdealFloatCoeff = primeIdeal.convertCoefficients(conversionFunction) solutions = solvePolynomialEquations( primeIdealFloatCoeff, polynomialSolver = algebra.mpmathFunctions.PolynomialSolver) # Solutions is a list with one element per Galois conjugate if not len(solutions) == primeIdeal.numberOfPoints: raise NumericalError("Number of solutions doesn't match") sys.stderr.write("Solved numerically the old way\n") # make Nf contain the error message ! try: class SolverThread(threading.Thread): def __init__(self, ideal): threading.Thread.__init__(self) self.ideal = ideal self.solution = None self.nf = None self.event = threading.Event() self.done = False def run(self): try: self.solution, self.nf = ( solvePolynomialEquationsExactly(self.ideal, timeout = "process")) self.done = True except: pass self.event.set() sys.stderr.write("Solving exactly...\n") thread = SolverThread(primeIdeal) thread.start() if not thread.event.wait(1200.0): thread._Thread__stop() raise pari.TimeoutAlarm if not thread.done: raise pari.PariError sys.stderr.write("Solved exactly.\n") solution, nf = thread.solution, thread.nf nfDegree = 1 if nf: nfDegree = nf.degree() if not nfDegree == primeIdeal.numberOfPoints: print nf, nfDegree, primeIdeal.numberOfPoints raise Exception, "points not matching" if nf: print "Number field", nf.printMagma() sys.stderr.write("Solving numerically the new way...\n") solutionsNew = exactSolutionsToNumerical( solution, nf, coeffConversion = conversionFunction, polynomialSolver = algebra.mpmathFunctions.PolynomialSolver) sys.stderr.write("Solved numerically the new way.\n") sys.stderr.write("Checking against other solutions...\n") try: solutionCheck(solutionsNew, solutions) sys.stderr.write("Checked against other solution.\n") except: nf = "Error: Solutions not matching" except pari.TimeoutAlarm: nf = "Error: Timeout" except Exception as e: print e nf = "Error: unknown" id_c_parms = manifold.slN.get_identified_c_parameters(t, N) if N % 2 == 0: H = manifold.slN.get_all_obstruction_classes(t) h = H[c] else: h = None # Each element in solutions is a dictionary # mapping the variable name to the numerical value for solution in solutions: # the Ptolemy coordinates are projective # We multiply all Ptolemy coordinates by the same random number # to avoid taking the logarithm of a negative real number solution = manifold.slN.multiply_solution_by_constant( solution, mpmath.mpc("1.0","0.32433234644")) # We assign a value to each Ptolemy coordinate based on the # solution c_parms = manifold.slN.map_solution_to_c_parameters(solution, id_c_parms) # Consistency check if not not_paranoid: manifold.slN.check_solution_identification(t, N, c_parms) # Consistency check manifold.slN.check_solution_on_gluing_equations( t, N, c_parms, h) # Get Ptolemy cochain # P consists of Ptolemy_cochain objects which encapsulate # a sign for orientation and 6 edge parameters c P = manifold.slN.get_Ptolemy_cochain(t, N, c_parms, no_check = not_paranoid) # convert the 6 edge parameters into an element of the # extended Bloch group represented by (w0,w1,w2) ws = [manifold.bloch_group.w_triple(x, no_check = not_paranoid) for x in P] # convert the triples (w0,w1,w2) into [z;p,q] # a different representation of an extended Bloch group element zpqs = [manifold.bloch_group.zpq_triple(x, no_check = not_paranoid) for x in ws] cross_ratios = {} for zpq_triple in zpqs: for k, v in zpq_triple.cross_ratios().items(): cross_ratios[k] = v all_cross_ratios.append(cross_ratios) #for i in zpqs: # print i # Compute the volume function and sum for all [z;p,q] vols = [x.volume() for x in zpqs] vol = sum(vols) # Compute the L function and sum for all [z;p,q] cvols = [x.L_function() for x in zpqs] cvol = sum(cvols) / 1j sys.stderr.write(" %s\n" % ( utilities.printNumbers.printComplexNumberAsFixed(cvol))) # Consistency check maxErr = globalsettings.getSetting("maximalError") if not abs(vol - cvol.real) < maxErr: raise NumericalError(val = [vol, cvol], msg = "Vol and Complex Vol not matching") all_cvols.append(cvol) return all_cvols, nf, all_cross_ratios