def build_vts_poly(ts, tcs, mpp_opt): vts = [[t.subs(tc) for t in ts] for tc in tcs] vts = vset(vts, idfun=repr) #add 0 to the end of each vertex and identity elem to terms vts = [vt + [SR(0)] for vt in vts] ts = ts + [SR(0)] #the identity element is 0 in MPP if mpp_opt == IeqMPP.opt_max_then_min: def worker_(Q, ts, is_max_plus): Q.put(IeqMPPGen.build_poly(vts, ts, is_max_plus)) Q = mp.Queue() workers = [ mp.Process(target=worker_, args=(Q, ts, is_max_plus)) for is_max_plus in [True, False] ] for w in workers: w.start() rs = [] for _ in workers: rs.extend(Q.get()) else: is_max_plus = mpp_opt == IeqMPP.opt_max_plus rs = IeqMPPGen.build_poly(vts, ts, is_max_plus=is_max_plus) return rs
def padically_evaluate(self, shuffle=False): if self.root() is None: return SR(1) r = ((1 - SR('q')**(-1))**self.nvertices * LocalZetaProcessor.padically_evaluate(self, shuffle=shuffle)).factor() return r
def padically_evaluate(self, shuffle=False): if self.root() is None: return SR(1) r = ((1 - SR('q')**(-1))**(-1) * LocalZetaProcessor.padically_evaluate( self, shuffle=shuffle)).factor() return r if self.translation is None else r(t=self.translation * SR('t')).factor()
def test_is_normalized_1(t): x = SR.var("x") e = SR.var("epsilon") t.assertFalse(is_normalized(matrix([[1 / x / 2]]), x, e)) t.assertFalse(is_normalized(matrix([[-1 / x / 2]]), x, e)) t.assertTrue(is_normalized(matrix([[1 / x / 3]]), x, e)) t.assertFalse(is_normalized(matrix([[x]]), x, e)) t.assertFalse(is_normalized(matrix([[1 / x**2]]), x, e)) t.assertTrue (is_normalized( \ matrix([[(e+SR(1)/3)/x-SR(1)/2/(x-1)]]), x, e))
def __init__(self, arg, mode=None): if mode is None: mode = 'O' if mode not in ['O', 'K', 'BO', 'BK', 'TO', 'TK']: raise ValueError("invalid mode") self.translation = SR('q')**(arg.nrows() - arg.ncols()) if 'T' in mode else None self.R = arg for x in mode[:-1]: if x == 'B': self.R = bullet_dual(self.R) elif x == 'T': self.R = self.R.transpose() else: raise ValueError self.d = self.R.nrows() self.e = self.R.ncols() self.mode = mode[-1] self.ring = self.R.base_ring() self.ell = self.ring.ngens() self.basis = [ evaluate_matrix(self.R, y) for y in identity_matrix(QQ, self.ell) ]
def symbolic_to_polynomial(f, vars): # Rewrite a symbolic expression as a polynomial over SR in a given # list of variables. poly = f.polynomial(QQ) allvars = poly.variables() indices = [] for x in allvars: try: indices.append(vars.index(x)) except ValueError: indices.append(None) R = PolynomialRing(SR, len(vars), vars) res = R.zero() for coeff, alpha in zip(poly.coefficients(), poly.exponents()): if type(alpha) == int: # Once again, univariate polynomials receive special treatment # in Sage. alpha = [alpha] term = R(coeff) for i, e in enumerate(alpha): if not e: continue if indices[i] is None: term *= SR(allvars[i]**e) else: term *= R.gen(indices[i])**e res += term return res
def get_rels_elems1(self, tcs): if __debug__: assert len(tcs) >= 1, tcs aeterms = tcs[0].keys() #Find rels among array elements logger.debug('Find linear eqts over {} array elems' .format(len(aeterms))) aeterms = [SR(1)] + aeterms from dig_polynomials import Eqt solverE = Eqt(aeterms, tcs, self.xinfo) logger.info('Select traces (note: |tcs|=|terms|={})'.format(len(aeterms))) ntcs_extra = 200 solverE.tcs, solverE.tcs_extra = get_traces(tcs,len(aeterms),ntcs_extra=200) solverE.do_refine=False solverE._go() from dig_refine import Refine rf = Refine(solverE.sols) rf.rfilter(tcs=solverE.tcs_extra) ps = [p.p for p in rf.ps] return ps
def taylor_processor_factored(new_ring, Phi, scalar, alpha, I, omega): k = alpha.nrows() - 1 tau = SR.var('tau') y = [SR('y%d' % i) for i in range(k + 1)] R = PolynomialRing(QQ, len(y), y) beta = [a * Phi for a in alpha] ell = len(I) def f(i): if i == 0: return QQ(scalar) * y[0] * exp(tau * omega[0]) elif i in I: return tau / (1 - exp(tau * omega[i])) else: return 1 / (1 - y[i] * exp(tau * omega[i])) H = [ f(i).series(tau, ell + 1).truncate().collect(tau) for i in range(k + 1) ] for i in range(k + 1): H[i] = [H[i].coefficient(tau, j) for j in range(ell + 1)] r = [] # Get coefficient of tau^ell in prod(H) for w in NonnegativeCompositions(ell, k + 1): r = prod( CyclotomicRationalFunction.from_split_expression(H[i][ w[i]], y, R).monomial_substitution(new_ring, beta) for i in range(k + 1)) yield r
def sreduce(ps): """ Return the basis (e.g., a min subset of ps that implies ps) of the set of eqts input ps using Groebner basis Examples: sage: var('a y b q k') (a, y, b, q, k) sage: rs = InvEqt.sreduce([a*y-b==0,q*y+k-x==0,a*x-a*k-b*q==0]) sage: assert set(rs) == set([a*y - b == 0, q*y + k - x == 0]) sage: rs = InvEqt.sreduce([x*y==6,y==2,x==3]) sage: assert set(rs) == set([x - 3 == 0, y - 2 == 0]) #Attribute error occurs when only 1 var, thus return as is sage: rs = InvEqt.sreduce([x*x==4,x==2]) sage: assert set(rs) == set([x == 2, x^2 == 4]) """ if __debug__: assert all(p.operator() == operator.eq for p in ps), ps try: Q = PolynomialRing(QQ, get_vars(ps)) I = Q * ps #ps_ = I.radical().groebner_basis() ps = I.radical().interreduced_basis() ps = [(SR(p) == 0) for p in ps] except AttributeError: pass return ps
def slope(self): # It was before named "coefficient" """ return the angular coefficient of line. This is the coefficient a in the equation y = ax + b This is not the same as the coefficient a in self.equation ax + by + c == 0 of the points. OUTPUT: a number EXAMPLES:: sage: from yanntricks import * sage: Segment(Point(0,0),Point(1,1)).slope 1 sage: Segment(Point(1,1),Point(0,0)).slope 1 sage: Segment(Point(1,2),Point(-1,8)).slope -3 NOTE: If the line is vertical, raise a ZeroDivisionError """ return SR(self.Dy)/self.Dx
def __init__(self, precision): Parent.__init__(self) self._precision = precision self.register_coercion(MorphismToSPN(ZZ, self, self._precision)) self.register_coercion(MorphismToSPN(QQ, self, self._precision)) to_SR = Hom(self, SR, Sets())(lambda x: SR(x.sage())) SR.register_coercion(to_SR)
def Llenar_Vector_Funciones(nombreArchTxt): """Funcion que lee un archivo de texto, extrae las expresiones que estan despues de un signo '=' y las almacena en un vector columna""" try: # Se ubica a dos directorios anteriores porque esta funcion es llamada desde un programa en el directorio donde esta la funcion principal archFun = open(f"{nombreArchTxt}.txt", "r") except: print("\nNo es posible abrir el archivo") print( "Crea un archivo de texto nuevo e ingresa las funciones ahí, guardalo con el formato 'txt' y vuelve a correr el programa\n" ) sys.exit(1) # Bucle que recorre el archivo para extraer lo que aparece despues del signo '=' en el archivo de texto for linea in archFun: indIn = linea.find("=") funciones = linea[(indIn + 1):] # Elimina las llaves que hay en la cadena indLlave1 = funciones.find("[") indLlave2 = funciones.find("]") funciones = funciones[(indLlave1 + 1):indLlave2] # Separa las funciones delimitadas por comas funciones = funciones.split(',') # Crea vector que contendra las expresiones que escriba el usuario en el archivo de texto matFun = np.empty((len(funciones), 1), dtype=type(SR())) contFun = 0 # Recorre la lista de funciones, intenta convertir a formato de funciones de sagemath y las almacena en el vector de funciones for funcion in funciones: try: matFun[contFun, 0] = SR(funcion) except: print( "\nNo ha sido posible convertir alguna de las expresiones en un formato compatible con el programa" ) print( "Revise la documentacion de SageMath para ver como se pueden ingresar las expresiones\n" ) sys.exit(1) contFun += 1 # Cierra el archivo archFun.close() # Regresa el vector columna con las expresiones leidas desde el archivo de texto return matFun
def quadratic_L_function__exact(n, d): r""" Returns the exact value of a quadratic twist of the Riemann Zeta function by `\chi_d(x) = \left(\frac{d}{x}\right)`. The input `n` must be a critical value. EXAMPLES:: sage: quadratic_L_function__exact(1, -4) 1/4*pi sage: quadratic_L_function__exact(-4, -4) 5/2 sage: quadratic_L_function__exact(2, 1) 1/6*pi^2 TESTS:: sage: quadratic_L_function__exact(2, -4) Traceback (most recent call last): ... TypeError: n must be a critical value (i.e. odd > 0 or even <= 0) REFERENCES: - [Iwa1972]_, pp 16-17, Special values of `L(1-n, \chi)` and `L(n, \chi)` - [IR1990]_ - [Was1997]_ """ from sage.all import SR, sqrt if n <= 0: return QuadraticBernoulliNumber(1 - n, d) / (n - 1) elif n >= 1: # Compute the kind of critical values (p10) if kronecker_symbol(fundamental_discriminant(d), -1) == 1: delta = 0 else: delta = 1 # Compute the positive special values (p17) if ((n - delta) % 2 == 0): f = abs(fundamental_discriminant(d)) if delta == 0: GS = sqrt(f) else: GS = I * sqrt(f) ans = SR(ZZ(-1)**(1 + (n - delta) / 2)) ans *= (2 * pi / f)**n ans *= GS # Evaluate the Gauss sum here! =0 ans *= QQ.one() / (2 * I**delta) ans *= QuadraticBernoulliNumber(n, d) / factorial(n) return ans else: if delta == 0: raise TypeError( "n must be a critical value (i.e. even > 0 or odd < 0)") if delta == 1: raise TypeError( "n must be a critical value (i.e. odd > 0 or even <= 0)")
def __init__(self, a, b): self.x = SR(a) self.y = SR(b) ObjectGraph.__init__(self, self) self.point = self.obj self.add_option("PointSymbol=*") self._advised_mark_angle = None try: ax = abs(numerical_approx(self.x)) if ax < 0.00001 and ax > 0: self.x = 0 ay = abs(numerical_approx(self.y)) if ay < 0.00001 and ay > 0: self.y = 0 except TypeError: pass
def count(self): for i in ([0, 1, 2] if common.symbolic else [0]): try: return SR(self._count_general(level=i)).expand() except CountException: logger.debug('count (level=%d) failed: %s' % (i, self)) raise CountException( 'Failed to count number of rational points. Try switching to symbolic mode.' )
def phyFunction(self): if self.is_horizontal: # The trick to define a constant function is explained here: # http://groups.google.fr/group/sage-support/browse_thread/thread/e5e8775dd79459e8?hl=fr?hl=fr x = var('x') fi = SR(self.I.y).function(x) return phyFunction(fi) if not (self.is_vertical or self.is_horizontal): x = var('x') return phyFunction(self.slope*x+self.independent)
def LLenar_Matriz_Datos(nombreArchTxt): """Funcion que lee un archivo de texto, extrae los datos ingresados y los almacena en una matriz para aplicar las formulas de derivacion o integracion""" try: archDts = open(f"{nombreArchTxt}.txt", "r") except: print("\nNo es posible abrir el archivo") print("Crea un archivo de texto e ingresa los datos ahí, guardalo con el formato 'txt' y vuelve a correr el programa\n") sys.exit(1) dts = "" # Bucle que recorre todo el archivo for parr in archDts: # Guarda en la variable 'dts' la cadena de texto con los datos que hay en el archivo de texto en formato 'str' dts += parr # Intenta convertir la primera cadena de texto a formato 'SR' (caso de las integrales) try: # Variable que contendra la funcion funcion = SR(dts) # Cierra el archivo archDts.close() # Regresa la funcion en formato 'SR' return funcion except: continue # Separa los datos delimitados por espacios dts = dts.split(' ') # Crea una matriz para almacenar los datos extraidos del archivo de texto matDts = np.empty((len(dts), 2), dtype = 'f') cont = 0 # Bucle que recorre la lista con todos los datos ingresados por el usuario en el archivo de texto para separarlos for dato in dts: # Variables auxiliares que son los indices de los caracteres que se usan para delimitar los datos y separarlos indParentesis1 = dato.find("(") indParentesis2 = dato.find(")") indComa = dato.find(",") # Trata de convertir los datos en formato 'double' y los almacena en 'matDts' try: matDts[cont, 0] = float(dato[(indParentesis1 + 1):indComa]) matDts[cont, 1] = float(dato[(indComa + 1):indParentesis2]) except: print("\nAlguno de los datos no se ha podido convertir en un formato compatible que pueda usar el programa") print("Debe ingresar numeros para poder continuar\n") sys.exit(1) cont += 1 # Cierra el archivo archDts.close() # Regresa la matriz con los datos extraidos desde el archivo de texto return matDts
def Llenar_Vector_Funciones(nombreArchTxt): """Funcion que lee un archivo de texto, extrae las expresiones que estan despues de un signo '=' y las almacena en un vector columna""" try: # Se ubica a dos directorios anteriores porque esta funcion es llamada desde un programa en el directorio donde esta la funcion principal archFun = open(f"{nombreArchTxt}.txt", "r") except: print("\nNo es posible abrir el archivo") print("Crea un archivo de texto nuevo e ingresa las funciones ahí, guardalo con el formato 'txt' y vuelve a correr el programa\n") sys.exit(1) contFun = 0 # Bucle que recorre todo el archivo y cuenta cuantas expresiones hay en el archivo for parr in archFun: contFun += 1 # Crea vector que contendra las expresiones que escriba el usuario en el archivo de texto matFun = np.empty((contFun, 1), dtype = type(SR())) # Regresa al principio del documento archFun.seek(0) contFun = 0 # Bucle que recorre todo el archivo para extraer las expresiones que aparecen despues del signo '=' en cada linea for linea in archFun: indIn = linea.find("=") # Intenta pasar cada linea del archivo de texto a formato de funciones de sagemath try: matFun[contFun, 0] = SR(linea[(indIn + 1):]) except: print("\nNo ha sido posible convertir alguna de las expresiones en un formato compatible con el programa") print("Revise la documentacion de SageMath para ver como se pueden ingresar las expresiones\n") sys.exit(1) contFun += 1 # Cierra el archivo archFun.close() # Regresa el vector columna con las expresiones leidas desde el archivo de texto return matFun
def build_poly(vts, ts, is_max_plus): """ Build a MPP convex polyhedron over vts and return a set of constraints Examples: sage: var('y') y sage: rs = IeqMPPGen.build_poly([[0,0,0],[3,3,0]], [x,y,SR(0)], is_max_plus=True) dig_polynomials:Debug:Build (gen max-plus) poly from 2 vts in 3 dims: [x, y, 0] sage: print '\n'.join(map(str,sorted(rs))) ('lambda x,y: -x + y >= 0', 'y >= x') ('lambda x,y: x - y >= 0', 'x >= y') ('lambda x: -x + 3 >= 0', '0 >= x - 3') ('lambda x: x >= 0', 'x >= 0') ('lambda y: -y + 3 >= 0', '0 >= y - 3') ('lambda y: y >= 0', 'y >= 0') """ opt_arg = '' if is_max_plus: mpp_str = 'max-plus' else: mpp_str = 'min-plus' opt_arg = "{} {}".format(opt_arg, '-{}'.format(mpp_str)) # if any vertex is float if any(any(not SR(v).is_integer() for v in vt) for vt in vts): vts = [[RR(v).n() for v in vt] for vt in vts] opt_arg = "{} -numerical-data ocaml_float".format(opt_arg) # exec external program # important, has to end with newline \n !!! vts_s = '\n'.join(str(vt).replace(' ', '') for vt in vts) + '\n' logger.debug('Build (gen {}) poly from {} vts in {} dims: {}'.format( mpp_str, len(vts), len(vts[0]), ts)) cmd = 'compute_ext_rays_polar {} {}'.format(opt_arg, len(vts[0])) rs, _ = vcmd(cmd, vts_s) rs = [sage_eval(s.replace('oo', 'Infinity')) for s in rs.split()] rs = IeqMPPGen.group_rs(rs) rs = map(lambda ls: [x + y for x, y in zip(ls, ts + ts)], rs) rs = map(lambda ls: IeqMPP.sparse(ls, is_max_plus), rs) rs = filter(None, rs) return rs
def quadratic_L_function__exact(n, d): r""" Returns the exact value of a quadratic twist of the Riemann Zeta function by `\chi_d(x) = \left(\frac{d}{x}\right)`. References: - Iwasawa's "Lectures on p-adic L-functions", p16-17, "Special values of `L(1-n, \chi)` and `L(n, \chi)` - Ireland and Rosen's "A Classical Introduction to Modern Number Theory" - Washington's "Cyclotomic Fields" EXAMPLES:: sage: bool(quadratic_L_function__exact(1, -4) == pi/4) True """ from sage.all import SR, sqrt if n <= 0: k = 1 - n return -QuadraticBernoulliNumber(k, d) / k elif n >= 1: ## Compute the kind of critical values (p10) if kronecker_symbol(fundamental_discriminant(d), -1) == 1: delta = 0 else: delta = 1 ## Compute the positive special values (p17) if ((n - delta) % 2 == 0): f = abs(fundamental_discriminant(d)) if delta == 0: GS = sqrt(f) else: GS = I * sqrt(f) ans = SR(ZZ(-1)**(1 + (n - delta) / 2)) ans *= (2 * pi / f)**n ans *= GS ## Evaluate the Gauss sum here! =0 ans *= 1 / (2 * I**delta) ans *= QuadraticBernoulliNumber(n, d) / factorial(n) return ans else: if delta == 0: raise TypeError, "n must be a critical value!\n" + "(I.e. even > 0 or odd < 0.)" if delta == 1: raise TypeError, "n must be a critical value!\n" + "(I.e. odd > 0 or even <= 0.)"
def build_poly(vts, ts, is_max_plus): """ Build a MPP convex polyhedron over vts and return a set of constraints Examples: sage: logger.set_level(VLog.DEBUG) sage: IeqMPP.build_poly([[0,0,0],[3,3,0]], is_max_plus=True) dig_polynomials:Debug:Ieq: Build (MPP max-plus) polyhedra from 2 vertices in 3 dim ['[-oo,0,-oo,-oo,-oo,0]', '[0,-oo,-oo,-oo,-oo,0]', '[0,-oo,-oo,-oo,-oo,-oo]', '[-oo,0,-oo,-oo,-oo,-oo]', '[-oo,-oo,0,-oo,-oo,-oo]', '[-oo,-oo,0,-oo,-oo,0]', '[-oo,-oo,0,-oo,-3,-oo]', '[-oo,-oo,0,-3,-oo,-oo]', '[-oo,0,-oo,-oo,0,-oo]', '[-oo,0,-oo,0,-oo,-oo]', '[0,-oo,-oo,-oo,0,-oo]', '[0,-oo,-oo,0,-oo,-oo]'] """ opt_arg = '' if is_max_plus: mpp_str = 'max-plus' else: mpp_str = 'min-plus' opt_arg = "{} {}".format(opt_arg, '-{}'.format(mpp_str)) #if any vertex is float if any(any(not SR(v).is_integer() for v in vt) for vt in vts): vts = [[RR(v).n() for v in vt] for vt in vts] opt_arg = "{} -numerical-data ocaml_float".format(opt_arg) #exec external program #important, has to end with newline \n !!! vts_s = '\n'.join(str(vt).replace(' ', '') for vt in vts) + '\n' logger.debug('Build (gen {}) poly from {} vts in {} dims: {}'.format( mpp_str, len(vts), len(vts[0]), ts)) cmd = 'compute_ext_rays_polar {} {}'.format(opt_arg, len(vts[0])) rs, _ = vcmd(cmd, vts_s) rs = [sage_eval(s.replace('oo', 'Infinity')) for s in rs.split()] rs = IeqMPPGen.group_rs(rs) rs = map(lambda ls: [x + y for x, y in zip(ls, ts + ts)], rs) rs = map(lambda ls: IeqMPP.sparse(ls, is_max_plus), rs) rs = filter(None, rs) return rs
def a_solve(pivot, solve_for, tcs): """ pivot = 'A' solve_for_arr = 'B' 0: A_0 - 7*B_0 == 0 1: A_1 - 7*B_2 - 3 == 0 2: A_2 - 7*B_4 - 6 == 0 Hypothesizes B_coef = c0A_i0 + c1A_i1 + ... + cnA_in + c(n+1) B_i0 = c0A_i0 + c1A_i1 + ... + cnA_in + c(n+1) B_i1 = c0A_i0 + c1A_i1 + ... + cnA_in + c(n+1) """ logger.debug("a_solve: Assume '%s' is pivot"%pivot) logger.debug("solve '%s' with respect to pivot with |tcs|=%d"%(solve_for,len(tcs))) _getIdxs = lambda a,d: [k for k in d[a] if not 'coef' in str(k)] mytcs = [dict(tc[pivot].items() + tc[solve_for].items()) for tc in tcs] idxs_ = _getIdxs(pivot,tcs[0]) pivot_idxs_n_const = [SR(1)] + idxs_ solve_for_keys= tcs[0][solve_for].keys() rs = [Miscs.solve_eqts_(ts=pivot_idxs_n_const,rv=k,ds=mytcs) for k in solve_for_keys] rs = Miscs.keys_to_str(rs) #so that the keys are string try: sol = merge_dict(rs) sol = (solve_for, sol) return sol except Exception: return None
def graduation_bars(self, pspict): """ Return the list of bars that makes the graduation of the axes By default, it is one at each multiple of self.base. If an user-defined axes_unit is given, then self.base is modified. This function also enlarges the axe by half a *visual* centimeter. """ # bars_list contains in the same time marks (for the numbering) and segments (for the bars itself) if not self.graduation: return [] bars_list = [] bar_angle = SR(self.mark_angle).n(digits=7) # Latex does not accept # too much digits. for x, symbol in self.axes_unit.place_list(self.mx, self.Mx, self.Dx, self.mark_origin): P = (x * self.base).F if self.numbering: # The 0.2 here is hard coded in Histogram, see 71011299 mark_angle = self.mark_angle if self.segment().is_horizontal: position = "N" mark_angle = None if self.segment().is_vertical: position = "E" mark_angle = None m = P.get_mark(0.2, mark_angle, symbol, pspict=pspict, position=position) bars_list.append(m) a = visual_polar(P, 0.1, bar_angle, pspict) b = visual_polar(P, 0.1, bar_angle + 180, pspict) seg = Segment(a, b) bars_list.append(seg) return bars_list
def get_rels_elems2(self, tcs, tsinfo): """ Instead of solving a large N+M eqts once, we can solve just a tuple of size N (N is the number of arrays) N*M times. This has a O(N^M) complexity, which is lower than solving N+M equations when M = 2. Doesn't work really well in practice (even when M=2) because the large number of invocations to the equation solver. """ from dig_polynomials import Eqt from itertools import product ps = [] for i,aeterms in enumerate(product(*tsinfo.values())): #Find rels among array elements logger.debug('{}. Find linear eqts over {} array elems {}' .format(i, len(aeterms), aeterms)) aeterms = [SR(1)] + list(aeterms) solverE = Eqt(aeterms, tcs, self.xinfo) logger.info('Select traces (note: |tcs|=|terms|={})' .format(len(aeterms))) ntcs_extra = 200 solverE.tcs, solverE.tcs_extra = get_traces(tcs,len(aeterms),ntcs_extra=200) solverE.do_refine = False solverE._go() ps.extend(solverE.sols) from dig_refine import Refine rf = Refine(ps) rf.rfilter(tcs=tcs) ps = rf.ps ps = [p.p for p in ps] return ps
def taylor_processor_naive(new_ring, Phi, scalar, alpha, I, omega): k = alpha.nrows() - 1 tau = SR.var('tau') y = [SR('y%d' % i) for i in range(k + 1)] R = PolynomialRing(QQ, len(y), y) beta = [a * Phi for a in alpha] def f(i): if i == 0: return QQ(scalar) * y[0] * exp(tau * omega[0]) elif i in I: return 1 / (1 - exp(tau * omega[i])) else: return 1 / (1 - y[i] * exp(tau * omega[i])) h = prod(f(i) for i in range(k + 1)) # Get constant term of h as a Laurent series in tau. g = h.series(tau, 1).truncate().collect(tau).coefficient(tau, 0) g = g.factor() if g else g yield CyclotomicRationalFunction.from_split_expression( g, y, R).monomial_substitution(new_ring, beta)
def _parse_poly(f): from sage.all import SR, QQ, HyperplaneArrangements, Matrix if type(f) == str: f = SR(f) if f.base_ring() == SR: L = f.factor_list() K = QQ else: L = list(f.factor()) K = f.base_ring() L = filter(lambda T: not T[0] in K, L) # Remove constant factors F, M = list(zip(*L)) # Verify that each polynomial factor is linear is_lin = lambda g: all(map(lambda x: g.degree(x) <= 1, g.variables())) if not all(map(is_lin, F)): raise ValueError("Expected product of linear factors.") varbs = f.variables() varbs_str = tuple(map(lambda x: str(x), varbs)) HH = HyperplaneArrangements(K, varbs_str) def poly_vec(g): c = K(g.subs({x: 0 for x in g.variables()})) return tuple([c] + [K(g.coefficient(x)) for x in varbs]) F_vec = tuple(map(poly_vec, F)) A = HH(Matrix(K, F_vec)) # This scrambles the hyperplanes, so we need to scramble M in the same way. A_vec = tuple(map(lambda H: tuple(H.coefficients()), A.hyperplanes())) perm = tuple([F_vec.index(v) for v in A_vec]) M_new = tuple([M[i] for i in perm]) return A, M_new
def topologically_evaluate(self, shuffle=False): return (SR(1) + TopologicalZetaProcessor.topologically_evaluate(self, shuffle=shuffle)).factor()
def Interpolacion_Lagrange(nombre): """Funcion que construira el Polinomio Interpolante de Lagrange""" # Primero llena una matriz con los datos contenidos en el documento de texto matDatos = LLenar_Matriz_Datos(nombre) # Manda a llamar a la funcion 'Opciones' para pedir al usuario que elija una opcion para usar la formula de lagrange, saber cuales son # los datos que el usuario desea elegir y para almacenar los indices de las filas de 'matDatos' que se van a usar en 'indicesDatos' indicesDatos = OpcionesLag(matDatos) # Revisa el contenido del primer elemento de 'indicesDatos' para saber que opcion eligio el usuario if indicesDatos[0] == 1 or indicesDatos[ 0] == 2: # Construye el Polinomio Interpolante de Lagrange opcionAux = indicesDatos[0] # Elimina el primer elemento de 'indicesDatos' indicesDatos = indicesDatos[1:] # Ordena los indices de forma ascendente y elimina los valores duplicados indicesDatos = list(set(indicesDatos)) # Crea la lista que contendra los polinomios de lagrange PolinomiosInterLag = list() # Declara las variables que contendran la expresiones que estaran en el numerador y en el denominador de cada polinomio de lagrange numerador = "" denominador = "" cont = 0 # Bucle que construye el polinomio interpolante de lagrange for elemento in indicesDatos: # Bucle que construira el numerador for elemNum in indicesDatos: # Condicional que se saltara este paso en caso de que lleguemos al elemento que no ira en el numerdor if elemNum == elemento: # Almacena en la variable 'elemFunAux' el indice del valor que estamos saltando para despues # usarlo al multiplicar los polinomio interpolantes por el valor de la funcion en ese punto elemFunAux = elemNum continue else: numerador += f"(x - {matDatos[elemNum, 0]})*" # Elimina el ultimo signo '*' de la cadena almacenada en la variable 'numerador' numerador = "(" + numerador[:(len(numerador) - 1)] + ")" # Bulce que construira el denominador for elemDen in indicesDatos: # Condicional que se saltara este paso en caso de que lleguemos al elemento que no ira en el numerdor if elemDen == elemento: continue else: denominador += f"({matDatos[elemento, 0]} - {matDatos[elemDen, 0]})*" # Elimina el ultimo signo '*' de la cadena almacenada en la variable 'denominador' denominador = "(" + denominador[:(len(denominador) - 1)] + ")" # Agrega a la lista de polinomio el polinomio que se forma con el numerador y el denominador de los bucles anteriores PolinomiosInterLag.append(f"{numerador} / {denominador}") numerador = "" denominador = "" # Multiplica el polinomio interpolante de lagrange por el valor de la funcion PolinomiosInterLag[ cont] = "(" + f"({round(matDatos[elemFunAux, 1], 6)}) * " + f"({PolinomiosInterLag[cont]})" + ")" cont += 1 # Declara variable que contendra el polinomio aplicando la formula de lagrange polinomio = "" # Bucle que convertira de formato 'srt' a formato de sagemath los polinomios obtenidos por los bucles anteriores y los sumara for pol in PolinomiosInterLag: polinomio += pol + "+" # Elimina el ultimo signo '+' de la cadena almacenada en la variable 'polinomio' polinomio = polinomio[:(len(polinomio) - 1)] if opcionAux == 1: # Convierte la cadena de caracteres que contiene el polinomio en formato de sagemath polinomio = SR(polinomio) # Simplifica el polinomio resultante y lo imprime print( f"\n\nEl Polinomio Interpolante es: {polinomio.simplify_full()}\n" ) else: # Sustituye el punto que se quiere calcular por las 'x' que aparecen en la cadena de caracteres que contiene el polinomio x = float(input( "\nIngresa una abscisa: ")) # Pide al usuario una abscisa polinomio = polinomio.replace('x', str(x)) polinomio = SR(polinomio) # Simplifica el resultado y lo imprime redondeandolo a 8 decimales print( f"\n\nEl valor de la funcion en el punto {x} es aproximadamente: {round(polinomio.simplify_full(), 8)}\n" )
def from_symbolic(exp, dR=None): r''' Method to transform a symbolic expression into a :class:`~ajpastor.dd_functions.ddFunction.DDFunction`. This method takes a symbolic expression an tries to cast it into a differentially definable function. This is closed related with the names that the module :mod:`~ajpastor.dd_functions.ddExamples` gives to the functions. This method is the inverse of :func:`symbolic`, meaning that the output of this method after applying :func:`symbolic` is always an object that is equal to the first input. INPUT: * ``exp``: symbolic expression or an object that can be casted into one. We also allow lists, tuples and sets as possible inputs, applying this method recursively to each of its elements. * ``dR``: :class:`~ajpastor.dd_functions.ddFunction.DDRing` in which hierarchy we try to include the symbolic expression ``exp``. If ``None`` is given, we compute a :class:`~ajpastor.dd_functions.ddFunction.DDRing` using `x` as a variable and all other variables appearing in ``exp`` considered as parameters. OUTPUT: A :class:`~ajpastor.dd_functions.ddFunction.DDFunction` representation of ``exp``. TODO: add more cases from ddExamples EXAMPLES:: sage: from ajpastor.dd_functions import * sage: var('y', 'm', 'n') (y, m, n) sage: from_symbolic(exp(x)) == Exp(x) True sage: sin_yx = from_symbolic(sin(y*x)) sage: parent(sin_yx) DD-Ring over (Univariate Polynomial Ring in x over Rational Field) with parameter (y) sage: sin_yx.init(6, True) [0, y, 0, -y^3, 0, y^5] sage: from_symbolic(cos(x)) == Cos(x) True sage: from_symbolic(sinh(x)) == Sinh(x) True sage: from_symbolic(cosh(x)) == Cosh(x) True sage: from_symbolic(tan(x)) == Tan(x) True sage: from_symbolic(log(x + 1)) == Log(x+1) True sage: from_symbolic(bessel_J(4, x)) == BesselD(4) True sage: from_symbolic(hypergeometric([1,2,3],[5,6,7],x)) == GenericHypergeometricFunction((1,2,3),(5,6,7)) True ''' logger.debug("Looking for a DD-finite representation of %s", exp) if (isinstance(exp, list)): logger.debug("List case: converting each element") return [from_symbolic(el, dR) for el in exp] elif (isinstance(exp, tuple)): logger.debug("Tuple case: converting each element") return tuple([from_symbolic(el, dR) for el in exp]) elif (isinstance(exp, set)): logger.debug("Set case: converting each element") return set([from_symbolic(el, dR) for el in exp]) ## If it is not from the basic structures, we required a symbolic expression exp = SR(exp) logger.debug("Deciding the starting DDRing") if (not dR is None): logger.debug("User required solution to be in the hierarchy of %s", dR) if (any(v not in list(dR.variables(True)) + list(dR.parameters(True)) for v in exp.variables())): raise TypeError("The symbolic expression has unknown variables") else: logger.debug("DDRing not specified: we compute one") params = [str(v) for v in exp.variables() if str(v) != 'x'] if (len(params) > 0): dR = ParametrizedDDRing( DFinite, [str(v) for v in exp.variables() if str(v) != 'x']) else: dR = DFinite name = None try: name = exp.operator().__name__ except AttributeError: try: name = exp.operator().name() except AttributeError: pass operands = exp.operands() if (name in ("list", "tuple")): # special tuple and list cases logger.debug("Found a symbolic list or tuple") return tuple([from_symbolic(el, dR) for el in operands]) elif (name == "set"): # special set case logger.debug("Found a symbolic set") return set([from_symbolic(el, dR) for el in operands]) elif (exp.is_rational_expression()): # rational expression case logger.debug("Rational expression found") num = exp.numerator().polynomial(ring=dR.original_ring()) den = exp.denominator().polynomial(ring=dR.original_ring()) if (den == 1): return num return num / den elif (name == "add_vararg"): logger.debug("Found an addition") return sum([from_symbolic(el, dR) for el in operands]) elif (name == "mul_vararg"): logger.debug("Found an product") return prod([from_symbolic(el, dR) for el in operands]) elif (name == "pow"): logger.debug("Found an power") if (not operands[1] in QQ): raise TypeError("The exponent has to be a rational number") if (operands[1] in ZZ): logger.debug("Integer power: simple output") return pow(from_symbolic(operands[0], dR), ZZ(operands[1])) else: base = from_symbolic(operands[0], dR) if (is_DDFunction(base)): logger.debug("Fractional power: base DDFunction") return pow(base, QQ(operands[1])) else: logger.debug("Fractional power: base rational function") params = [str(el) for el in dR.parameters()] i = 0 while ("y%d" % i in params): i += 1 R = PolynomialRing(dR.original_ring(), "y%d" % i) y = R.gens()[0] pq = QQ(operands[1]) p = pq.numerator() q = pq.denominator() poly = y**q - R(str(operands[0]))**p x = dR.variables(True)[0] init = [ dR.coeff_field(exp.derivative(x, i)(**{ str(x): 0 })) for i in range(p + q) ] return DAlgebraic(poly, init, dR.to_depth(1)) elif (name == "sin"): logger.debug("Found an sine") return Sin(operands[0]) elif (name == "cos"): logger.debug("Found an cosine") return Cos(operands[0]) elif (name == "sinh"): logger.debug("Found a hyperbolic sine") return Sinh(operands[0]) elif (name == "cosh"): logger.debug("Found an hyperbolic cosine") return Cosh(operands[0]) elif (name == "tan"): logger.debug("Found a tangent") return Tan(operands[0]) elif (name == "log"): logger.debug("Found a logarithm") return Log(operands[0]) elif (name == "exp"): logger.debug("Found an exponential") return Exp(operands[0]) elif (name == "bessel_J"): logger.debug("Found an Bessel function of first kind") if (not (operands[0] in ZZ and operands[0] >= 0)): raise ValueError( "The Bessel has to have a non-negative integer index") return BesselD(ZZ(operands[0]))(from_symbolic(operands[1], dR)) elif (name == "legendre_P"): logger.debug("Found an Legendre function of first kind") return LegendreD(operands[0], 0, 1)(from_symbolic(operands[1], dR)) elif (name == "gen_legendre_P"): logger.debug("Found an generic Legendre function of first kind") return LegendreD(operands[0], operands[1], 1)(from_symbolic(operands[1], dR)) elif (name == "legendre_Q"): logger.debug("Found an Legendre function of second kind") return LegendreD(operands[0], 0, 2)(from_symbolic(operands[1], dR)) elif (name == "gen_legendre_Q"): logger.debug("Found an generic Legendre function of second kind") return LegendreD(operands[0], operands[1], 2)(from_symbolic(operands[1], dR)) elif (name == "chebyshev_T"): logger.debug("Found an Chebyshev function of first kind") return ChebyshevD(operands[0], 1)(from_symbolic(operands[1], dR)) elif (name == "chebyshev_U"): logger.debug("Found an Chebyshev function of second kind") return ChebyshevD(operands[0], 2)(from_symbolic(operands[1], dR)) elif (name == "hypergeometric"): return GenericHypergeometricFunction(from_symbolic(operands[0], dR), from_symbolic(operands[1], dR))(from_symbolic( operands[2], dR)) else: raise NotImplementedError( "The operator %s is not valid for 'from_symbolic'" % name)
def string_number_comparison(s1, s2, epsilon=0.01, last_justification=""): r""" Compare two strings. The comparison is True is the two string differ by numbers that are `epsilon`-close. It return a tuple of a boolean and a string. The string is a justification of the result. INPUT: - ``s1`` - first string. - ``s2`` - second string. - ``epsilon`` - tolerance. OUTPUT: tuple (boolean,string). The boolean says if the two strings are equal up to `epsilon`-close numbers. The string provides a short explanation. EXAMPLES: In the following, the comparison fails due to the first number:: sage: from yanntricks.SmallComputations import * sage: s1="Point(-0.2,0.111)" sage: s2="Point(-0.3,0.111)" sage: string_number_comparison(s1,s2) (False, 'Distance between -0.2 and -0.3 is larger than 0.01.') In the following the comparison fails due to the second number:: sage: s1="Point(-0.02,1)" sage: s2="Point(-0.03,2)" sage: string_number_comparison(s1,s2,epsilon=0.1) (False, 'd(-0.02,-0.03)=0.01\nDistance between 1 and 2 is larger than 0.100000000000000.') Here the comparison succeed:: sage: s1="Point(1.99,1.001)" sage: s2="Point(2,1.002)" sage: string_number_comparison(s1,s2,epsilon=0.1) (True, 'd(1.99,2)=-0.01\nd(1.001,1.002)=-0.001\n') """ if s1 == s2: return True, last_justification pos = 0 while s1[pos] == s2[pos]: pos = pos + 1 v1, first1, last1 = number_at_position(s1, pos) v2, first2, last2 = number_at_position(s2, pos) if v1 == False or v2 == False: line1 = get_line(s1, pos) line2 = get_line(s2, pos) justification = "There is a difference outside a number\nExpected:\n%s\nGot:\n %s" % ( line2, line1) return False, justification if abs(SR(v1) - SR(v2)) < epsilon: justification = last_justification + \ "d(%s,%s)=%s\n" % (v1, v2, str(SR(v1)-SR(v2))) t1 = s1[:first1] + v2 + s1[last1:] t2 = s2 return string_number_comparison(t1, t2, epsilon=epsilon, last_justification=justification) justification = last_justification + \ "Distance between %s and %s is larger than %s." % ( str(v1), str(v2), str(epsilon)) return False, justification