def is_torsion_same(p, K, chi, B=30, uniform=False): """Returns true if the minus part of J0(p) does not gain new torsion when base changing to K""" M = ModularSymbols(p) S = M.cuspidal_subspace() T = S.atkin_lehner_operator() S_min = (T + parent(T)(1)).kernel() J0_min = S_min.abelian_variety() d = K.degree() if uniform: frob_poly_data = [(q, d) for q in prime_range(d + 2, B) if q != p] else: frob_poly_data = [(q, 1) if chi(q) == 1 else (q, d) for q in prime_range(d + 2, B) if gcd(q, p) == 1] point_counts = [] for q, i in frob_poly_data: frob_pol_q = J0_min.frobenius_polynomial(q) frob_mat = companion_matrix(frob_pol_q) point_counts.append((frob_mat**i).charpoly()(1)) # Recall that the rational torsion on J0(p) is entirely contained in # the minus part (theorem of Mazur), so checking no-growth of torsion # in minus part is done simply as follows return J0(p).rational_torsion_order(proof=False) == gcd(point_counts)
def ff(v, offset, start=0): """Fast-forward through vector `v` in ``offset`` sized steps starting at ``start`` :param v: vector :param offset: increment in each step :param start: start offset """ p = parent(v) return p(list(v)[start::offset])
def balance(e, q=None): """ Return a representation of `e` with elements balanced between `-q/2` and `q/2` :param e: a vector, polynomial or scalar :param q: optional modulus, if not present this function tries to recover it from `e` :returns: a vector, polynomial or scalar over/in the integers """ try: p = parent(e).change_ring(ZZ) return p([balance(e_, q=q) for e_ in e]) except (TypeError, AttributeError): if q is None: try: q = parent(e).order() except AttributeError: q = parent(e).base_ring().order() e = ZZ(e) e = e % q return ZZ(e-q) if e>q//2 else ZZ(e)
def _grid2motion(self, NAC_coloring, data, check): self._par_type = 'symbolic' alpha = var('alpha') self._field = parent(alpha) self._parameter = alpha self._active_NACs = [NAC_coloring] zigzag = data['zigzag'] grid_coor = NAC_coloring.grid_coordinates(ordered_red=data['red'], ordered_blue=data['blue']) self._same_lengths = [] for i, edges in enumerate([NAC_coloring.blue_edges(), NAC_coloring.red_edges()]): partition = [[list(edges[0])]] for u, v in edges[1:]: appended = False for part in partition: u2, v2 = part[0] if Set([grid_coor[u][i], grid_coor[v][i]]) == Set([grid_coor[u2][i], grid_coor[v2][i]]): part.append([u, v]) appended = True break if not appended: partition.append([[u, v]]) self._same_lengths += partition if check and len(Set(grid_coor.values())) != self._graph.num_verts(): raise exceptions.ValueError('The NAC-coloring does not yield a proper flexible labeling.') if zigzag: if type(zigzag) == list and len(zigzag) == 2: a = [vector(c) for c in zigzag[0]] b = [vector(c) for c in zigzag[1]] else: m = max([k for _, k in grid_coor.values()]) n = max([k for k, _ in grid_coor.values()]) a = [vector([0.3*((-1)**i-1)+0.3*sin(i), i]) for i in range(0,m+1)] b = [vector([j, 0.3*((-1)**j-1)+0.3*sin(j)]) for j in range(0,n+1)] else: m = max([k for _, k in grid_coor.values()]) n = max([k for k, _ in grid_coor.values()]) a = [vector([0, i]) for i in range(0,m+1)] b = [vector([j, 0]) for j in range(0,n+1)] rotation = matrix([[cos(alpha), sin(alpha)], [-sin(alpha), cos(alpha)]]) positions = {} for v in self._graph.vertices(): positions[v] = rotation * a[grid_coor[v][1]] + b[grid_coor[v][0]] self._parametrization = positions
def _parametrization2motion(self, active_NACs, data, check): self._parametrization = data['parametrization'] element = (sum([self._parametrization[v][0]**Integer(2) for v in self._parametrization]) + sum([self._parametrization[v][1]**Integer(2) for v in self._parametrization])) self._field = parent(element) for v in self._parametrization: self._parametrization[v] = vector([self._field(x) for x in self._parametrization[v]]) if data['par_type'] == 'symbolic': self._par_type = 'symbolic' if len(element.variables()) != 1: raise exceptions.ValueError('The parametrization has to have one parameter (' + str(len(element.variables())) + ' found).') self._parameter = element.variables()[0] if data['par_type'] == 'rational': self._par_type = 'rational' self._parameter = self._field.gen() if check: self._edges_with_same_length() self._active_NACs = active_NACs
def is_rank_of_twist_zero(p, chi): """Returns true if the rank of the twist of the minus part of X_0(p) by the character chi is zero""" ML = ModularSymbols(p, base_ring=chi.base_ring()) SL = ML.cuspidal_subspace() TL = SL.atkin_lehner_operator() S_min_L = (TL + parent(TL)(1)).kernel() for S in S_min_L.decomposition(): my_map = S.rational_period_mapping() w = ML([0, oo]) wmap = my_map(w) if wmap == 0: return False tw = ML.twisted_winding_element(0, chi) twmap = my_map(tw) if twmap == 0: return False return True
def test_masur_veech_edge_weight(): from surface_dynamics.topological_recursion import MasurVeechTR from sage.all import PolynomialRing R = PolynomialRing(QQ, 't') t = R.gen() MV = MasurVeechTR(edge_weight=t) for g, n, value in [ (0, 3, R.one()), (0, 4, t), (0, 5, QQ((4, 9)) * t + QQ((5, 9)) * t**2), (0, 6, QQ((8, 27)) * t + QQ((4, 9)) * t**2 + QQ((7, 27)) * t**3), (1, 1, t), (1, 2, QQ((5, 9)) * t + QQ((4, 9)) * t**2), (1, 3, QQ((4, 9)) * t + QQ((13, 33)) * t**2 + QQ((16, 99)) * t**3), (2, 1, QQ((76, 261)) * t + QQ((125, 261)) * t**2 + QQ( (440, 2349)) * t**3 + QQ((100, 2349)) * t**4), (2, 2, QQ((296, 1011)) * t + QQ((19748, 45495)) * t**2 + QQ( (9127, 45495)) * t**3 + QQ((560, 9099)) * t**4 + QQ( (100, 9099)) * t**5) ]: p = MV.F(g, n, (0, ) * n) assert parent(p) is R p /= p(1) assert p == value, (g, n, p, value)
def _element_constructor_(self, x, e=1): r"""Construct a Puiseux series from `x`. INPUT: - ``x`` -- an object that can be converted into a Puiseux series in (x-a) - ``a`` -- (default: 0) the series is in powers of (var - a) - ``e`` -- (default: 1) the ramification index of the series """ P = parent(x) # 1. x is a Puiseux series belonging to this ring if isinstance(x, self.element_class) and P is self: return x # 2. x is a Puiseux series but not an element of this ring. the laurent # part should be coercible to the laurent series ring of self elif isinstance(x, self.element_class): l = self.laurent_series_ring()(x.laurent_part) e = x.ramification_index # 3. x is a member of the base ring then convert x to a laurent series # and set the ramificaiton index of the Puiseux series to 1. elif P is self.base_ring(): l = self.laurent_series_ring()(x) e = 1 # 4. x is a Laurent or power series with the same base ring elif ((is_LaurentSeries(x) or is_PowerSeries(x)) and P is self.base_ring()): l = self.laurent_series_ring()(x) # 5. everything else: try to coerce to laurent series ring else: l = self.laurent_series_ring()(x) e = 1 return self.element_class(self, l, e=e)
def automatic_control(control, var=None): """ Guesses the desired interact control from the syntax of the parameter. :arg control: Parameter value. :returns: An InteractControl object. :rtype: InteractControl """ from numbers import Number from types import GeneratorType label = None default_value = 0 # For backwards compatibility, we check to see if # auto_update=False as passed in. If so, we set up an # UpdateButton. This should be deprecated. if var=="auto_update" and control is False: return UpdateButton() # Checks for interact controls that are verbosely defined if isinstance(control, InteractControl): return control # Checks for labels and control values for _ in range(2): if isinstance(control, tuple) and len(control) == 2 and isinstance(control[0], str): label, control = control if isinstance(control, tuple) and len(control) == 2 and isinstance(control[1], (tuple, list, GeneratorType)): default_value, control = control if isinstance(control, str): C = InputBox(default = control, label = label) elif isinstance(control, bool): C = Checkbox(default = control, label = label, raw = True) elif isinstance(control, Number): C = InputBox(default = control, label = label, raw = True) elif isinstance(control, list): if len(control)==1: if isinstance(control[0], (list,tuple)) and len(control[0])==2: buttonvalue, buttontext=control[0] else: buttonvalue, buttontext=control[0],str(control[0]) C = Button(value=buttonvalue, text=buttontext, default=buttonvalue, label=label) else: if len(control) <= 5: selectortype = "button" else: selectortype = "list" C = Selector(selector_type = selectortype, default = control[default_value], label = label, values = control) elif isinstance(control, GeneratorType): values=take(10000,control) C = DiscreteSlider(default = values[default_value], values = values, label = label) elif isinstance (control, tuple): if len(control) == 2: C = ContinuousSlider(default = default_value, interval = (control[0], control[1]), label = label) elif len(control) == 3: C = ContinuousSlider(default = default_value, interval = (control[0], control[1]), stepsize = control[2], label = label) else: values=list(control) C = DiscreteSlider(default = values[default_value], values = values, label = label) else: C = InputBox(default = control, label=label, raw = True) if CONFIG.EMBEDDED_MODE["sage_mode"] and CONFIG.EMBEDDED_MODE["enable_sage"]: from sagenb.misc.misc import Color from sage.structure.all import is_Vector, is_Matrix from sage.all import parent if is_Matrix(control): nrows = control.nrows() ncols = control.ncols() default_value = control.list() default_value = [[default_value[j * ncols + i] for i in range(ncols)] for j in range(nrows)] C = InputGrid(nrows = nrows, ncols = ncols, label = label, default = default_value, adapter=lambda x, globs: parent(control)(x)) elif is_Vector(control): default_value = [control.list()] nrows = 1 ncols = len(control) C = InputGrid(nrows = nrows, ncols = ncols, label = label, default = default_value, adapter=lambda x, globs: parent(control)(x[0])) elif isinstance(control, Color): C = ColorSelector(default = control, label = label) return C
def automatic_control(control, var=None): """ Guesses the desired interact control from the syntax of the parameter. :arg control: Parameter value. :returns: An InteractControl object. :rtype: InteractControl """ from numbers import Number from types import GeneratorType label = None default_value = 0 # For backwards compatibility, we check to see if # auto_update=False as passed in. If so, we set up an # UpdateButton. This should be deprecated. if var=="auto_update" and control is False: return UpdateButton() # Checks for interact controls that are verbosely defined if isinstance(control, InteractControl): return control # Checks for labels and control values for _ in range(2): if isinstance(control, tuple) and len(control) == 2 and isinstance(control[0], str): label, control = control if isinstance(control, tuple) and len(control) == 2 and isinstance(control[1], (tuple, list, GeneratorType)): default_value, control = control if isinstance(control, basestring): C = InputBox(default = control, label = label, evaluate=False) elif isinstance(control, bool): C = Checkbox(default = control, label = label, raw = True) elif isinstance(control, list): if len(control)==1: if isinstance(control[0], (list,tuple)) and len(control[0])==2: buttonvalue, buttontext=control[0] else: buttonvalue, buttontext=control[0],str(control[0]) C = Button(value=buttonvalue, text=buttontext, default=buttonvalue, label=label) else: if len(control) <= 5: selectortype = "button" else: selectortype = "list" C = Selector(selector_type = selectortype, default = default_value, label = label, values = control) elif isinstance(control, GeneratorType): values=take(10000,control) C = DiscreteSlider(default = default_value, values = values, label = label) elif isinstance (control, tuple): if len(control) == 2: C = ContinuousSlider(default = default_value, interval = (control[0], control[1]), label = label) elif len(control) == 3: C = ContinuousSlider(default = default_value, interval = (control[0], control[1]), stepsize = control[2], label = label) else: values=list(control) C = DiscreteSlider(default = default_value, values = values, label = label) else: from sage.all import sage_eval C = InputBox(default = control, label=label, evaluate=True) if CONFIG.EMBEDDED_MODE["sage_mode"] and CONFIG.EMBEDDED_MODE["enable_sage"]: from sagenb.misc.misc import Color from sage.structure.all import is_Vector, is_Matrix from sage.all import parent if is_Matrix(control): nrows = control.nrows() ncols = control.ncols() default_value = control.list() default_value = [[default_value[j * ncols + i] for i in range(ncols)] for j in range(nrows)] C = InputGrid(nrows = nrows, ncols = ncols, label = label, default = default_value, adapter=lambda x, globs: parent(control)(x)) elif is_Vector(control): default_value = [control.list()] nrows = 1 ncols = len(control) C = InputGrid(nrows = nrows, ncols = ncols, label = label, default = default_value, adapter=lambda x, globs: parent(control)(x[0])) elif isinstance(control, Color): C = ColorSelector(default = control, label = label) return C
def eval(self, element, *args, **kwds): r''' Method to evaluate elements in the ring of differential polynomials. Since the differential polynomials have an intrinsic meaning (namely, the variables are related by derivation), evaluating a differential polynomial is a straight-forward computation once the objects for the ``*_0`` term is given. This method evaluates elements in ``self`` following that rule. INPUT: * ``element``: element (that must be in ``self``) to be evaluated * ``args``: list of arguments that will be linearly related with the generators of ``self`` (like they are given by ``self.gens()``) * ``kwds``: dictionary for providing values to the generators of ``self``. The name of the keys must be the names of the generators (as they can be got using the attribute ``_name``). We allow a mixed used of ``args`` and ``kwds`` but an error will be raised if * There are too many arguments in ``args``, * An input in ``kwds`` is not a valid name of a generator, * There are duplicate entries for a generator. OUTPUT: The resulting element after evaluating the variable `\alpha_n = \partial^n(\alpha)`, where `\alpha` is the name of the generator. EXAMPLES:: sage: from dalgebra.differential_polynomial.differential_polynomial_ring import * sage: R.<y> = DiffPolynomialRing(QQ['x']); x = R.base().gens()[0] sage: R.eval(y[1], 0) 0 sage: R.eval(y[0] + y[1], x) x + 1 sage: R.eval(y[0] + y[1], y=x) x + 1 This method commutes with the use of :func:`derivation`:: sage: R.eval(R.derivation(x^2*y[1]^2 - y[2]*y[1]), y=x) == R.derivation(R.eval(x^2*y[1]^2 - y[2]*y[1], y=x)) True This evaluation also works naturally with several infinite variables:: sage: S = DiffPolynomialRing(R, 'a'); a,y = S.gens() sage: S.eval(a[1] + y[0]*a[0], a=x, y=x^2) x^3 + 1 sage: in_eval = S.eval(a[1] + y[0]*a[0], y=x); in_eval a_1 + x*a_0 sage: parent(in_eval) Ring of differential polynomials in (a) over [Univariate Polynomial Ring in x over Rational Field] ''' if (not element in self): raise TypeError("Impossible to evaluate %s as an element of %s" % (element, self)) g = self.gens() final_input = {} names = [el._name for el in g] if (len(args) > self.ngens()): raise ValueError( "Too many argument for evaluation: given %d, expected (at most) %d" % (len(args), self.ngens())) for i in range(len(args)): final_input[g[i]] = args[i] for key in kwds: if (not key in names): raise TypeError("Invalid name for argument %s" % key) gen = g[names.index(key)] if (gen in final_input): raise TypeError("Duplicated value for generator %s" % gen) final_input[gen] = kwds[key] max_derivation = {gen: 0 for gen in final_input} for v in element.variables(): for gen in max_derivation: if (gen.contains(v)): max_derivation[gen] = max(max_derivation[gen], gen.index(v)) break to_evaluate = {} for gen in max_derivation: for i in range(max_derivation[gen] + 1): to_evaluate[str(gen[i])] = diff(final_input[gen], i) ## Computing the final ring values = list(final_input.values()) R = parent(values[0]) for i in range(1, len(values)): R = pushout(R, parent(values[i])) poly = element.polynomial() ## Adding all the non-appearing variables on element if (len(final_input) == len(g)): for v in poly.parent().gens(): if (v not in poly.variables()) and (not str(v) in to_evaluate): to_evaluate[str(v)] = 0 else: left_gens = [gen for gen in g if gen not in final_input] R = DiffPolynomialRing(R, [el._name for el in left_gens]) for v in poly.parent().gens(): if (not any(gen.contains(v) for gen in left_gens)) and (not str(v) in to_evaluate): to_evaluate[str(v)] = 0 return R(poly(**to_evaluate))