def _test_against_known_canonical_retriangulations(): from snappy import Manifold for name, bytes_ in _known_canonical_retriangulations: M = Manifold(name); K = verified_canonical_retriangulation(M) L = Manifold('empty'); L._from_bytes(bytes_) if not len(K.isomorphisms_to(L)): raise Exception('%s failed' % name)
def get_volume_data(man_nms, engine = 'magma', max_secs = 20, retrieve = True, sln = 2, max_itf_degree = MAX_ITF): """ Returns a VolumeData object containing exotic volumes for manifolds with the given names Volumes' precision is based on pari, so set it there set retrieve = False to skip retrieving ptolemy data from files set engine = None to skip computing ptolemy data in an engine set max_secs to specify how long we will spend computing a given manifolds' data before killing the engine and moving on; specifying None means we will never give up (unless something crashes) if the engine given crashes, so will IDLE and SnapPy; to avoid this, run this command only from within python scripts. Manifolds with more than floor(max_itf_degree/2) distinct volumes to an obstruction class will have their data for that obstruction class removed, since this demonstrates an invariant trace field with too high ncp Set to None and it will be ignored.""" #TODO: special case max_secs=None to not bother with processes if engine: def _use_engine(v,p): # this function will be called in a second process to facilitate time limits p.send(v.compute_solutions(engine = engine)) recs = dict() for nm in man_nms: try: sols = None var = Manifold(nm).ptolemy_variety(sln,'all') try: if retrieve: sols = var.retrieve_decomposition() else: raise Exception("Go on and compute") except Exception as e: # try using engine if engine: mine, theirs = Pipe(duplex = False) p = Process(target=_use_engine,args=[var,theirs]) p.daemon = True p.start() if mine.poll(max_secs): # Here is the time limit stuff sols = mine.recv() p.terminate() else: p.terminate() # give up on this one print 'Computation took too long; skipping '+nm continue else: print 'No engine and no data retrieved; skipping '+nm continue if sols: data = [(c.number_field(),c.solutions(numerical = True).volume_numerical()) for c in sols.flatten()] for cl_idx in xrange(len(data)): if data[cl_idx]: # TODO may be trivial since no check here for v in data[cl_idx][1]: recs.setdefault(str(data[cl_idx][0]),dict()).setdefault(str(v),list()).append((nm,cl_idx)) else: print 'Got no solutions; skipping '+nm except Exception as e: print(str(e))+'; skipping '+nm continue for p in recs.keys(): for v in recs[p].keys(): recs[p][v] = list(set(recs[p][v])) return VolumeData(data = recs)
def link_exterior_tri(DT_code, starts=4, random=4): tris = [] for s in range(starts): M = Manifold('DT[%s]' % DT_code) for r in range(random + 1): tris.append(M.copy()) for i in range(r): M.randomize() return min(tris, key=triangulation_sort_key)
def helper_test_by_dehn_filling(M): from snappy import Manifold M_filled = M.filled_triangulation() for ignore_cusp_ordering in [False, True]: for ignore_curve_orientations in [False, True]: isosig = M.triangulation_isosig( decorated=True, ignore_cusp_ordering=ignore_cusp_ordering, ignore_curve_orientations=ignore_curve_orientations) N = Manifold(isosig) N_filled = N.filled_triangulation() helper_are_isometric(M, N)
def check_certified_intervals(): for n in [ 'm009', 'm015', 't02333', 't02333(1,2)', 'm129(2,3)', 'm129(2,3)(3,4)' ]: M = Manifold(n) high_prec = M.tetrahedra_shapes('rect', bits_prec=1000) intervals = M.tetrahedra_shapes('rect', bits_prec=100, intervals=True) for z, interval in zip(high_prec, intervals): if not abs(interval.center() - z) < 1e-10: raise Exception if not z in interval: raise Exception
def __init__(self, manifold, order=128, offset=0.001, elevation=None, base_dir='PR_base_fibers', hint_dir='PR_hints', ignore_saved=False): self.base_dir = base_dir if not isinstance(manifold, (Manifold, ManifoldHP)): manifold = Manifold(manifold) self.offset = offset self.order = order if elevation is None: self.elevation = LineElevation(manifold, order=order, offset=offset, base_dir=base_dir, hint_dir=hint_dir, ignore_saved=ignore_saved) else: self.elevation = elevation # Save the manifold here, because it may have been replaced by a saved manifold. self.manifold = self.elevation.manifold self.elevation.tighten() print('Building arcs, rep kinds, and long trans...') self.build_arcs() print('Done!')
def _get_saved_data(self): base_fiber_file = os.path.join(self.base_dir, self.manifold.name() + '.base') ask_save = False try: with open(base_fiber_file) as datafile: data = eval(datafile.read()) self._print('Loaded the base fiber from %s' % base_fiber_file) M = Manifold(data['manifold']) if not M == self.manifold: if self.verbose: self._print( 'The saved base fiber uses a different triangulation of %s!' % M) response = user_input( 'Would you like to \n' '(a) use the saved triangulation; or\n' '(b) recompute the base fiber\n' '? ') while response.lower() not in ('a', 'b'): response = user_input('Please type "a" or "b": ') if response.lower() == 'a': self.manifold = M elif response == 'b': ask_save = True data = {} else: data = {} except IOError: data = {} return data, ask_save raise ValueError('Only subclasses of Elevation can be instantiated.')
def setup_extended_db(dbfile): if os.path.exists(dbfile): os.remove(dbfile) connection = sqlite3.connect(dbfile) create_extended_tables(connection) make_extended_views(connection) # Add the poor missing trefoil M = Manifold('3_1') M.set_name('K3a1') insert_cusped_manifold(connection, 'HT_links', M, is_link=True, DTcode='cacbca') connection.commit() connection.close()
def test_induced_sl4_representation(): M = Manifold("m004") z_gl2 = ptolemy.CrossRatios.from_snappy_manifold(M) z_gl4 = z_gl2.induced_representation(4) G = M.fundamental_group() mat = z_gl4.evaluate_word(G.relators()[0], G) for i, row in enumerate(mat): for j, entry in enumerate(row): if i == j: assert abs(entry - 1) < 1e-9 else: assert abs(entry) < 1e-9
def __init__(self, manifold, order=169, radius=1.02, elevation=None, base_dir='PE_base_fibers', hint_dir='hints', ignore_saved=False): # The default order is 13^2 because 13th roots of 1 are rarely singularities. self.base_dir = base_dir if not isinstance(manifold, (Manifold, ManifoldHP)): manifold = Manifold(manifold) self.radius = radius self.order = order if elevation is None: self.elevation = CircleElevation(manifold, order=order, radius=radius, base_dir=base_dir, hint_dir=hint_dir, ignore_saved=ignore_saved) else: self.elevation = elevation # Save the manifold here, because it may have been replaced by a saved manifold. self.manifold = self.elevation.manifold self.elevation.tighten()
def bytes_n_cobs(mfld): """ Return a bytestring encoding of the manifold and a list of basis changes that convert the combinatorial basis of the decoded bytestring back to the original peripheral basis of the manifold, and a permutation to be applied to the cusp indices. """ cobs = mfld.set_peripheral_curves('combinatorial', return_matrices=True) bytestring = mfld._to_bytes() encoded_perm = 0 N = Manifold('empty') N._from_bytes(bytestring) N.set_peripheral_curves('combinatorial') mfld.set_peripheral_curves(cobs) # put it back the way it was isoms = mfld.isomorphisms_to(N) abcd = False while isoms: pick_one = isoms.pop() abcd = tuples(pick_one) if abcd: break if not abcd: print('No orientation preserving isometries????') return bytestring, cobs, 0 perm = pick_one.cusp_images() for n in range(mfld.num_cusps()): a, b, c, d = abcd[n] cobs[perm[n]] = [[a, c], [b, d]] encoded_perm |= (n << (perm[n] << 2)) return bytestring, cobs, encoded_perm
def draw_ladders_and_geometric_boundary_for_veering_isosig(sig, args={}): if args == {}: args = { 'draw_boundary_triangulation': True, 'draw_triangles_near_poles': False, 'ct_depth': -1, 'ct_epsilon': 0.03, 'global_drawing_scale': 4, 'delta': 0.2, 'ladder_width': 10.0, 'ladder_height': 20.0, 'draw_labels': True } out_dir_ladders = 'Images/Ladders' out_dir_geometric = 'Images/Geometric' output_filename = sig + '.pdf' tri, angle = isosig_to_tri_angle(sig) M = Manifold(tri) tet_shapes = M.tetrahedra_shapes() tet_shapes = [complex(shape["rect"]) for shape in tet_shapes] args['tet_shapes'] = tet_shapes B = generate_boundary_triangulation(tri, angle, args=args, output_filename=output_filename) args_ladder = args.copy() args_ladder['style'] = 'ladders' output_filename_ladders = out_dir_ladders + '/' + output_filename B.draw(output_filename_ladders, args=args_ladder) args_geometric = args.copy() args_geometric['style'] = 'geometric' output_filename_geometric = out_dir_geometric + '/' + output_filename B.draw(output_filename_geometric, args=args_geometric)
def testGeometricRep(compute_solutions): from snappy.ptolemy import geometricRep M = Manifold("m019") if compute_solutions: sol = geometricRep.compute_geometric_solution(M) else: from urllib.request import pathname2url url = pathname2url(os.path.abspath(testing_files_directory)) sol = geometricRep.retrieve_geometric_solution(M, data_url=url) # Make sure this is of type Ptolemy sol['c_0011_2'] assert any( [abs(vol - 2.9441064867) < 1e-9 for vol in sol.volume_numerical()])
def flipper_bundle_data(self): """ Return the flipper triangulation, flip sequence and edge closer defined by following this TautStructure. """ # How to wrap from the bottom edge back to the top. top = dict((arrow.Tetrahedron.Index, index) for index, starts in enumerate(self.tops) for arrow in starts) bottom = dict((arrow.Tetrahedron.Index, index) for index, ends in enumerate(self.bottoms) for arrow in ends) edge_advance = dict( ((loci, sum(self.surface.weights[face_index(arrow)] for arrow in self.branch_loci[loci][0]) - 1), (top[tet], 0)) for tet, loci in bottom.items()) S0, E0 = self.surface.connected_component( ) # Get a component and its edges. E_curr = E0 flips = [] while True: flips += [ i for i, edge in enumerate(E_curr) if edge in edge_advance ] # Find the edges where we are not moving directly across. E_curr = [ edge_advance.get((loci, sheet), (loci, sheet + 1)) for loci, sheet in E_curr ] # Move across. if sorted(E_curr) == E0: break F = S0.flipper_triangulation() M0 = self.manifold.snappy_manifold() image_edge = E0.index(E_curr[0]) for edge in [image_edge, ~image_edge]: try: h = F.encode_flips_and_close(flips, 0, edge) B = h.bundle(veering=False, _safety=False) if M0.is_isometric_to(Manifold(B)): return F, flips, edge except (flipper.AssumptionError, AssertionError): pass raise RuntimeError( "Neither sister triangulations are the starting triangulation")
def get_manifold(text = text): triangulation_text = utilities.join_long_lines( find_unique_section(text, "TRIANGULATION")) if triangulation_text[:15] == '% Triangulation': from snappy import Manifold return Manifold(triangulation_text) if ('<?xml' in triangulation_text and '<reginadata' in triangulation_text and '<packet' in triangulation_text): from reginaWrapper import NTriangulationForPtolemy return NTriangulationForPtolemy.from_xml(triangulation_text) raise Exception("Triangulation format not supported: %s..." % triangulation_text[:20])
def run_perf_test(): gui = InsideManifoldGUI(Manifold("m004")) PerfTest(gui.main_widget)
""" Run this in Sage and SnapPy and see that the last line of the result differs dramatically. If we multiply two numbers with different precisions, we expect the result to be of the lower precision. This is consistent between Sage and SnapPy. However, if we cast the low precision to a type of higher precision and then multiply, we expect the result to be of the type of the higher precision. This works in Sage, but it doesn't work for SnapPy Numbers. This affects the code computing cusp translations, look for "_SnapPyNumberHack". """ from snappy import Manifold M = Manifold("m004") # Let's take a real 53bit precision number v = M.cusp_neighborhood().volume(0) # And a complex 1000bit precision number z = M.tetrahedra_shapes('rect', bits_prec = 1000)[0] # High precision real field RF = z.real().parent() print("Expect low precision number: ", v) print("Expect high precision number:", z) print("Product, expect low precision number:", v * z) print("Casting to high precision:", RF(v)) print("Product again, this time it should be high precision (!!!):", RF(v) * z)
class Apoly(object): """ The A-polynomial of a SnapPy manifold. Constructor: Apoly(mfld, order=128, gluing_form=False, denom=None, multi=False, use_hints=True, verbose=True) <mfld> is a manifold name recognized by SnapPy, or a Manifold instance. <gluing_form> (True/False) indicates whether to find a "standard" A-polynomial, or the gluing variety variant. <order> must be at least twice the M-degree. Try doubling this if the coefficients seem to be wrapping. <denom> Denominator for leading coefficient. This should be a string, representing a polynomial expression in H, the meridian holonomy. e.g. denom='((H-1)**3)*((H+1)**4)' <multi> If True, multiple copies of lifts are not removed, so multiplicities of factors of the polynomial are computed. <use_hints> Whether to check for and use hints from a hint file. <verbose> Whether to print information about the computation. <precision> Specify 'double'(default), or a number of bits. Methods: An Apoly object A is callable: A(x,y) returns the value at (x,y). A.as_string(exp='^') returns a string suitable for input to a generic symbolic algebra program which uses the symbol exp for exponentiation. A.sage() returns a Sage polynomial with parent ring ZZ['M', 'L'] A.show(text=False) shows the newton polygon with dots. The text flag shows the coefficients. A.show_R_longitude_evs() uses matplotlib to graph the L-projections of arcs of the elevation of the circle of radius R in the M-plane. A.show_T_longitude_evs() uses matplotlib to graph the L-projections of components of the inverse image of the tightened circle of radius T in the M-plane. A.boundary_slopes() returns the boundary slopes detected by the character variety. A.save(basename=None, dir='polys', with_hint=True, twist=0) Saves the polynomial in a .apoly or .gpoly text file for input to a symbolic computation program. The directory can be overridden by specifying dir. Saves the parameters in a .hint file unless with_hint==False. Assumes that the preferred longitude is LM^twist, where L,M are the SnapPea meridian and longitued A.verify() runs various consistency checks on the polynomial. An Apoly object prints itself as a matrix of coefficients. """ def __init__(self, mfld, order=128, gluing_form=False, radius=1.02, denom=None, multi=False, use_hints=True, verbose=True, apoly_dir='apolys', gpoly_dir='gpolys', base_dir='PE_base_fibers', hint_dir='hints', dict_dir='apoly_dicts', precision='double', phc_rescue=False): if isinstance(mfld, Manifold): self.manifold = mfld self.mfld_name = mfld.name() else: self.mfld_name = mfld self.manifold = Manifold(mfld) self.viewer= None self.gluing_form = gluing_form self.verbose = verbose self.apoly_dir = apoly_dir self.gpoly_dir = gpoly_dir self.base_dir = base_dir self.hint_dir = hint_dir self.dict_dir = dict_dir options = {'order' : order, 'denom' : denom, 'multi' : multi, 'radius' : radius, 'precision' : precision, 'phc_rescue' : phc_rescue } # 'apoly_dir' : apoly_dir, # 'gpoly_dir' : gpoly_dir, # 'base_dir' : base_dir, # 'hint_dir' : hint_dir} # 'dict_dir' : dict_dir} if use_hints: self._print("Checking for hints ... ", end='') hintfile = os.path.join(self.hint_dir, self.mfld_name+'.hint') if os.path.exists(hintfile): self._print("yes!") exec(open(hintfile).read()) options.update(hint) prec = options['precision'] else: print("nope.") self.order = N = options['order'] self._denom = options['denom'] self.multi = options['multi'] self.radius = options['radius'] self.precision = precision = options['precision'] if precision != 'double': self.precision = int(precision) # avoid Sage Integers self.fft_obj = ComplexFFT(self.order) self.phc_rescue = phc_rescue filename = self.manifold.name()+'.base' saved_base_fiber = os.path.join(self.base_dir, filename) prec = 53 if self.precision == 'double' else self.precision msg = 'Using: radius=%g; order=%d; denom=%s; precision=%d bits.'%( options['radius'], options['order'], options['denom'], prec) self.elevation = CircleElevation( self.manifold, order=self.order, radius=self.radius, base_dir=self.base_dir, phc_rescue=self.phc_rescue, verbose=self.verbose, msg=msg ) if self.elevation.failed: print("Warning: Failed to elevate the R-circle. This Apoly is incomplete.") return if self.gluing_form: vals = array([track for track in self.elevation.R_longitude_holos]) else: if isinstance(self.precision, int): self.elevation.polish_R_longitude_vals(precision=self.precision) vals = array(self.elevation.polished_R_longitude_evs) else: vals = array(self.elevation.R_longitude_evs) self.degree = len(vals) if multi == False: self.multiplicities, vals = self.demultiply(vals) self.reduced_degree = len(vals) self._compute_all(vals) self._print('done.') def __call__(self, M, L): result = 0 rows, cols = self.coefficients.shape for i in range(rows): Lresult = 0 for j in range(cols): Lresult = Lresult*L + self.coefficients[-1-i][-1-j] result = result*M + Lresult return result def __repr__(self): return 'A-polynomial of %s'%self.mfld_name def __str__(self): digits = 2 + int(ceil(log(self.height)/log(10))) width = len(self.coefficients[0]) format = '[' + ('%' + str(digits) + '.0f')*width + ']\n' result = '' for row in self.coefficients: result += format%tuple(row + 0.) return result def _print(self, *args, **kwargs): if self.verbose: print(*args, **kwargs) @staticmethod def _rounded_real(z): if is_ComplexNumber(z): return z.real().round() elif isinstance(z, complex): return round(z.real) else: raise ValueError('Unknown type %s.'%type(z)) @staticmethod def realpart(z): if is_ComplexNumber(z): return z.real() else: return z.real @property def denom(self): return self._denom def find_denom(self, base_index=None, row=None): # Look for a short integer vector K such that the convolution # of a row of normalized coefficients with K has a long block # of zeros starting at the base index. This function only # looks for one zero, but it could be used with different base # indices or rows to corroborate the result. Also note that # the denominator should be a product of cyclotomic # polynomials. # The base index and row default to the middle. if base_index is None: assert self.order%2 == 0 base_index = self.order // 2 max_size = self.order - base_index if row is None: row = self.normalized_coeffs.shape[0] // 2 X = array([float(self.realpart(z)) for z in self.normalized_coeffs[row]]) # Find the shortest block with a non-trivial relation. M = None for n in range(max_size): N = array([X[base_index+i:base_index+i+n] for i in range(n)]) r = matrix_rank(N) if r == n - 1: M = N if n > r + 5: # looks like the rank has stabilized ... break if M is None: raise RuntimeError("Failed to find a denominator.") # Now M should be square with a null space of dimension 1. U, S, V = svd(M) K = V[-1] # unit vector in the null space of M coeffs = [int(round(x)) for x in K/K[-1]] # Perhaps we should remove powers of H and verify that we # are left with a product of cyclotomics. return PolynomialRing(ZZ, 'H')(coeffs) @denom.setter def denom(self, denom_string): assert denom_string is None or isinstance(denom_string, str) self._denom = denom_string if self.precision != 'double': self._compute_all(array(self.elevation.polished_R_longitude_evs)) else: self._compute_all(array(self.elevation.R_longitude_evs)) def _compute_all(self, vals): """ Use a discrete Fourier transform to compute the A-polynomial from the longitude eigenvalues (or holonomies). We are viewing the A-polynomial as a polynomial in L with coefficients in QQ[M]. For a number z on the R-circle, we find a monic polynomial in L vanishing on the values taken by L at those points of the A-curve where M takes the value z. Thus we get a polynomial in L whose coefficients are polynomials in M vanishing on the A-curve. To compute the integer coefficients of these M-polynomials we renormalize to the unit circle and use the inverse FFT. (Note: this produces a monic polynomial in L, but the A-polynomial is not monic when there is an ideal point of the character variety which is associated with a meridian boundary slope. The denom parameter is used to resolve this issue.) """ self.sampled_roots = vals self.sampled_coeffs = self.symmetric_funcs(vals) if isinstance(self.precision, int): radius = RealField(self.precision)(self.radius) ifft = self.fft_obj.ifft def real(z): return z.real() else: radius = self.radius ifft = fft.ifft def real(z): return z.real self._print("Interpolating with IFFT.") if self._denom: exec('denom_function = lambda H : %s'%self._denom) if isinstance(self.precision, int): circle = [radius*U1Q(-n, self.order, precision=self.precision) for n in range(self.order)] D = array([denom_function(z) for z in circle]) else: D = array([denom_function(z) for z in self.elevation.R_path]) self.raw_coeffs = array([ifft(x*D) for x in self.sampled_coeffs]) else: self.raw_coeffs = array([ifft(x) for x in self.sampled_coeffs]) # Renormalize the coefficients, to adjust for the circle radius. N = self.order if N%2 == 0: powers = -array(list(range(1+N//2))+list(range(1-N//2, 0))) else: powers = -array(list(range(1+N//2))+list(range(-(N//2), 0))) renorm = array([radius**n for n in powers]) self.normalized_coeffs = self.raw_coeffs*renorm self.int_coeffs = array([map(self._rounded_real, x) for x in self.normalized_coeffs], dtype='O') #self.int_coeffs = array([[self. for z in row] # for row in self.normalized_coeffs], dtype='O') self.height = int(max([max(abs(x)) for x in self.int_coeffs])) self.bits_height = int(ceil(log(float(self.height))/log(2))) #self.bits_height = log(self.height, 2) self.noise = (array([[real(z) for z in row] for row in self.normalized_coeffs], dtype='O') - self.int_coeffs) self.max_noise = [max(abs(x)) for x in self.noise] self.shift = self.find_shift() self._print('Shift is %d.'%self.shift) if self.shift is None: raise ValueError('Could not compute the shift. ' 'Coefficients may be wrapping. ' 'If so, a larger order might help.') C = self.int_coeffs.transpose() coefficient_array = take(C, arange(len(C))-self.shift, axis=0) rows, cols = coefficient_array.shape while rows > 0: if max(abs(coefficient_array[rows-1])) > 0: break rows -= 1 self.coefficients = coefficient_array[:rows] self._print('log_2(height) is %s'%self.bits_height) self._print("Noise levels: ") for level in self.max_noise: self._print(level) if max(self.max_noise) > 0.2: self._print('Failed to find integer coefficients with tolerance 0.2') return self._print('Computing the Newton polygon.') self.compute_newton_polygon() def compute_newton_polygon(self): power_scale = (1, 1) if self.gluing_form else (1, 2) self.newton_polygon = NewtonPolygon(self.as_dict(), power_scale) def recompute(self): """ Recompute A after changing attributes. """ self._compute_all(array(self.elevation.R_longitude_evs)) def help(self): print(self.__doc__) def symmetric_funcs(self, evs): """ Given a numpy 2D array whose rows are L-eigenvalues sampled on a circle, return a 2D array whose rows are the elementary symmetric functions of the roots. Before computing the elementary symmetric functions, each column is sorted in descending size, to avoid 'catastrophic cancellation'. This means, for example (using decimal floating point with 3 digits) that we want to compute .101E3 - .100E3 - .999E0 = .1E-2 == .001 rather than .101E3 - .999E0 - .100E3 "=" .1E1 == 1.0 """ for n in range(evs.shape[1]): evs[:, n] = sorted(evs[:, n], key=lambda x: -abs(x)) coeffs = [0, ones(evs[0].shape, evs.dtype)] for root in evs: for i in range(1, len(coeffs)): coeffs[-i] = -root*coeffs[-i] + coeffs[-1-i] coeffs.append(ones(evs[0].shape, evs.dtype)) return coeffs[1:] def demultiply(self, eigenvalues): multiplicities = [] sdr = [] #system of distinct representatives multis = [1]*len(eigenvalues) for i in range(len(eigenvalues)): unique = True for j in range(i+1,len(eigenvalues)): # If this row is the same as a lower row, do not # put it in the sdr. Just increment the multiplicity # of the lower row. if max(abs(eigenvalues[i] - eigenvalues[j])) < 1.0E-6: unique = False multis[j] += multis[i] break if unique: sdr.append(i) multiplicities.append((i, multis[i])) return multiplicities, take(eigenvalues, sdr, 0) def find_shift(self): rows, cols = self.normalized_coeffs.shape shifts = [0] #start from the top and search for the last row above the middle #whose left-most non-zero entry is +-1. for i in range(rows): for j in range(1, 1 + cols//2): if abs(abs(self.normalized_coeffs[i][-j]) - 1.) < .01: shifts.append(j) return max(shifts) # Should have a monomial class, and generate a list of monomials here not a string def monomials(self): rows, cols = self.coefficients.shape monomials = [] for j in range(cols): for i in range(rows): if self.gluing_form: m,n = 2*i, 2*j else: m,n = 2*i, j a = int(self.coefficients[i][j]) if a != 0: if i > 0: if j > 0: monomial = '%d*(M^%d)*(L^%d)'%(a,m,n) else: monomial = '%d*(M^%d)'%(a,m) else: if j > 0: monomial = '%d*(L^%d)'%(a,n) else: monomial = '%d'%a monomials.append(monomial) return monomials # Should use the list of monomials to generate the dict def as_dict(self): rows, cols = self.coefficients.shape result = {} for j in range(cols): for i in range(rows): if self.gluing_form: m,n = 2*i, 2*j else: m,n = 2*i, j coeff = int(self.coefficients[i][j]) if coeff: result[(m,n)] = coeff return result def break_line(self, line): marks = [0] start = 60 while True: mark = line.find('+', start) if mark == -1: break marks.append(mark) start = mark+60 lines = [] for i in range(len(marks) - 1): lines.append(line[marks[i]:marks[i+1]]) lines.append(line[marks[-1]:]) return '\n '.join(lines) def as_string(self, exp='^'): polynomial_string = ('+'.join(self.monomials())).replace('+-','-') return polynomial_string.replace('^', exp) def sage(self): return sage_poly_ring(self.as_dict()) # could do this by sorting the monomials def as_Lpolynomial(self, name='A', twist=0): terms = [] rows, cols = self.coefficients.shape #We are taking the true longitude to be L*M^twist. #So we change variables by L -> M^(-twist)*L. #Then renormalize so the minimal power of M is 0. minexp = 2*rows for j in range(cols): for i in range(rows): if self.coefficients[i][j]: break minexp = min(2*i - j*twist, minexp) for j in range(cols): if self.gluing_form: n = 2*j else: n = j monomials = [] for i in range(rows): m = 2*i a = int(self.coefficients[i][j]) if a != 0: if i > 0: monomial = '%d*M^%d'%(a,m) else: monomial = '%d'%a monomials.append(monomial.replace('^1 ',' ')) if monomials: p = - n*twist - minexp if p: P = '%d'%p if p < 0: P = '('+P+')' if n > 0: term = '+ (L^%d*M^%s)*('%(n,P) + ' + '.join(monomials) + ')' else: term = '(M^%s)*('%P + ' + '.join(monomials) + ')' else: if n > 0: term = '+ (L^%d)*('%n + ' + '.join(monomials) + ')' else: term = '(' + ' + '.join(monomials) + ')' term = self.break_line(term) terms.append(term.replace('+ -','- ')) return name + ' :=\n' + '\n'.join(terms) def save(self, basename=None, dir=None, with_hint=True, twist=0): if dir == None: if self.gluing_form: poly_dir = self.gpoly_dir hint_dir = self.hint_dir ext = '.gpoly' else: poly_dir = self.apoly_dir hint_dir = self.hint_dir ext = '.apoly' dict_dir = self.dict_dir for dir in (poly_dir, hint_dir, dict_dir): if not os.path.exists(dir): cwd = os.path.abspath(os.path.curdir) newdir = os.path.join(cwd,dir) response = user_input("May I create a directory %s?(y/n)"%newdir) if response.lower() != 'y': sys.exit(0) os.mkdir(newdir) if basename == None: basename = self.mfld_name polyfile_name = os.path.join(poly_dir, basename + ext) hintfile_name = os.path.join(hint_dir, basename + '.hint') dictfile_name = os.path.join(dict_dir, basename + '.dict') if self.gluing_form: lhs = 'G_%s'%basename else: lhs = 'A_%s'%basename with open(polyfile_name,'wb') as polyfile: polyfile.write(self.as_Lpolynomial(name=lhs, twist=twist)) polyfile.write(';\n') with open(dictfile_name, 'wb') as dictfile: dictfile.write('%s = {\n'%lhs) polydict = self.as_dict() for key in sorted(polydict.keys()): dictfile.write(' %s : %s,\n'%(key, polydict[key])) dictfile.write('}\n') if with_hint: self.elevation.save_hint( directory=self.hint_dir, extra_options={ 'denom': self._denom, 'multi': self.multi, 'precision': self.precision }) def boundary_slopes(self): return [s.sage() for s in self.newton_polygon.lower_slopes] def show_R_longitude_evs(self): self.elevation.show_R_longitude_evs() def show_T_longitude_evs(self): if not self.elevation.T_circle: self.tighten() self.elevation.show_T_longitude_evs() def show_coefficients(self): plot = Plot([[self.realpart(z) for z in row] for row in self.normalized_coeffs.real], number_type=float) def show_noise(self): plot = Plot(self.noise, number_type=float) def show_imag_noise(self): plot = Plot(self.normalized_coeffs.imag, number_type=float) def show(self, text=False): self.viewer= V = PolyViewer(self.newton_polygon, title=self.mfld_name) if text: V.show_text() else: V.show_dots() V.show_sides() def show_R_volumes(self): H = self.elevation Plot(H.volumes(H.R_fibers), number_type=float) def show_T_volumes(self): H = self.elevation Plot(H.volumes(H.T_fibers), number_type=float) def tighten(self, T=1.0): self.elevation.tighten(T) def verify(self): noise_ok = True symmetry = True sign = None self._print('Checking max noise level: ', end=' ') self._print(max(self.max_noise)) if max(self.max_noise) > 0.2: noise_ok = False self._print('Failed') self._print('Checking for reciprocal symmetry ... ', end=' ') if max(abs(self.coefficients[0] - self.coefficients[-1][-1::-1]))==0: sign = -1.0 elif max(abs(self.coefficients[0] + self.coefficients[-1][-1::-1]))==0: sign = 1.0 else: self._print('Failed!') symmetry = False if sign: for i in range(len(self.coefficients)): maxgap = max(abs(self.coefficients[i] + sign*self.coefficients[-i-1][-1::-1])) if maxgap > 0: self._print('Failed! gap = %d'%maxgap) symmetry = False if symmetry: self._print('OK.') result = noise_ok and symmetry if result: self._print('Passed!') return result
def __init__(self, mfld, order=128, gluing_form=False, radius=1.02, denom=None, multi=False, use_hints=True, verbose=True, apoly_dir='apolys', gpoly_dir='gpolys', base_dir='PE_base_fibers', hint_dir='hints', dict_dir='apoly_dicts', precision='double', phc_rescue=False): if isinstance(mfld, Manifold): self.manifold = mfld self.mfld_name = mfld.name() else: self.mfld_name = mfld self.manifold = Manifold(mfld) self.viewer= None self.gluing_form = gluing_form self.verbose = verbose self.apoly_dir = apoly_dir self.gpoly_dir = gpoly_dir self.base_dir = base_dir self.hint_dir = hint_dir self.dict_dir = dict_dir options = {'order' : order, 'denom' : denom, 'multi' : multi, 'radius' : radius, 'precision' : precision, 'phc_rescue' : phc_rescue } # 'apoly_dir' : apoly_dir, # 'gpoly_dir' : gpoly_dir, # 'base_dir' : base_dir, # 'hint_dir' : hint_dir} # 'dict_dir' : dict_dir} if use_hints: self._print("Checking for hints ... ", end='') hintfile = os.path.join(self.hint_dir, self.mfld_name+'.hint') if os.path.exists(hintfile): self._print("yes!") exec(open(hintfile).read()) options.update(hint) prec = options['precision'] else: print("nope.") self.order = N = options['order'] self._denom = options['denom'] self.multi = options['multi'] self.radius = options['radius'] self.precision = precision = options['precision'] if precision != 'double': self.precision = int(precision) # avoid Sage Integers self.fft_obj = ComplexFFT(self.order) self.phc_rescue = phc_rescue filename = self.manifold.name()+'.base' saved_base_fiber = os.path.join(self.base_dir, filename) prec = 53 if self.precision == 'double' else self.precision msg = 'Using: radius=%g; order=%d; denom=%s; precision=%d bits.'%( options['radius'], options['order'], options['denom'], prec) self.elevation = CircleElevation( self.manifold, order=self.order, radius=self.radius, base_dir=self.base_dir, phc_rescue=self.phc_rescue, verbose=self.verbose, msg=msg ) if self.elevation.failed: print("Warning: Failed to elevate the R-circle. This Apoly is incomplete.") return if self.gluing_form: vals = array([track for track in self.elevation.R_longitude_holos]) else: if isinstance(self.precision, int): self.elevation.polish_R_longitude_vals(precision=self.precision) vals = array(self.elevation.polished_R_longitude_evs) else: vals = array(self.elevation.R_longitude_evs) self.degree = len(vals) if multi == False: self.multiplicities, vals = self.demultiply(vals) self.reduced_degree = len(vals) self._compute_all(vals) self._print('done.')
def run_perf_test(): gui = InsideViewer(Manifold("m004")) PerfTest(gui.widget)
def handle_return(self, event): if self.state == 'ready': self.choose() else: self.show_covers() def choose(self, event=None): self.result = [ self.cover_list[self.covers.index(x)] for x in self.covers.selection() ] self.root.destroy() def cancel(self): self.result = [] self.root.destroy() def go(self): self.root.grab_set() self.root.wait_window() if __name__ == '__main__': from snappy import Manifold root = Tk_.Tk() root.withdraw() browser1 = Browser(Manifold('m125'), root) browser2 = Browser(Manifold('12n345')) root.wait_window(browser1.window) root.wait_window(browser2.window)
pos_c2 = [weights[to_index(face_class[2])] for face_class in face_classes] neg_c2 = [weights[to_index(face_class[3])] for face_class in face_classes] for p, n in zip(pos_c2, neg_c2): if p != -n: raise Exception("Not matching") for row in trig._ptolemy_equations_boundary_map_2()[0]: if len(row) != len(pos_c2): raise Exception("Not matching") s = sum([e * p for e, p in zip(row, pos_c2)]) if s != 0: raise Exception("Not in kernel") if __name__ == '__main__': print(sys.argv) if sys.argv[1] == 'perf': run_perf_test() else: trig = Manifold(sys.argv[1]) weights = None if len(sys.argv) == 3: weights = eval(sys.argv[2]) check_weights(trig, weights) main(trig, weights)
def run_perf_test(): gui = ViewerWindow(InsideViewer, Manifold("m004")) PerfTest(gui.view.widget)
def run_perf_test(): from snappy import Manifold gui = RaytracingWidget(Manifold("m004")) PerfTest(gui.main_widget)
from __future__ import print_function from builtins import range """ We decorate Regina's triangulation isomorphism signature (isosig) to record the peripheral structure of a cusped manifold M, that is, the cusp labels and the peripheral curves on each cusp. The basic idea is to store these relative to SnapPy's combinatorial defaults for the triangulation created from the bare isosig. Specifically, if M has n cusps, we append a permutation on {0,...,n-1} as well as n change-of-basis matrices, represented as a sequence of 5n integers and encoded as a string of isosig characters. This decoration string is appended to the isosig string, after first appending a separator character which is not a valid isosig character. To save space, the permutation may be omitted when it is equal to the identity permutation; this is indicated by the fact that the length of the decoration is 4n rather than 5n. Currently, only oriented manifolds are supported. A simple valid decorated isosig for a two-cusped manifold is:: eLPkbdcddhgggb_abBaaBBaaB Here, the bare isosig is what precedes the underscore; what follows is an encoded version of the 5n integers mentioned above. This decorated isosig is equivalent to eLPkbdcddhgggb_BaaBBaaB where the permutation part has been elided since the permutation is
def cross_ratios(M): return [ptolemys.cross_ratios() for ptolemys in ptolemy_coordinates(M)] if __name__ == '__main__': from snappy import Manifold import sys if len(sys.argv) != 2: print("Usage: sage -python printMatrices.py CLOSED_MFD") print() print('Example: sage -python printMatrices.py "m004(2,3)"') sys.exit(1) M = Manifold(sys.argv[1]) G = M.fundamental_group() list_z = cross_ratios(M) for i, z in enumerate(list_z): print("Solution %d:" % i) nf = z['z_0000_0'].parent() print(" Number field:", nf.defining_polynomial()) print(" Exact values:") for g in G.generators(): print(" Generator %s:" % g) print(z.evaluate_word(g, G)) for z_numerical in evaluate_at_roots(nf, z, precision=100): print(" Numerical values:") d = CrossRatios(z_numerical, manifold_thunk=lambda: M)
def ManifoldGetter(name): return NTriangulationForPtolemy( NTriangulation(Manifold(name)._to_string()))
def run_perf_test(): from snappy import Manifold gui = InsideViewer(Manifold("m004")) PerfTest(gui.widget)
# Import raytracing directly from SnapPy source so that we can quickly # iterate on shaders without the need to build/install SnapPy every time. snappy_path, dir_name = os.path.split(os.getcwd()) sys.path.append(os.path.join(snappy_path, 'python')) from raytracing.inside_viewer import * def run_perf_test(): gui = InsideViewer(Manifold("m004")) PerfTest(gui.widget) def main(manifold): if sys.platform == 'darwin': print(darwinTkMsg) gui = InsideViewer(manifold) gui.widget.focus_set() gui.container.mainloop() if __name__ == '__main__': print(sys.argv) if sys.argv[1] == 'perf': run_perf_test() else: main(Manifold(sys.argv[1]))
def run_perf_test(): from snappy import Manifold gui = FiniteViewer(Manifold("m004(3,2)")) PerfTest(gui.widget)
def ManifoldGetter(name): return Manifold(name)