def length_rational_fraction(self, var='b'): r""" Return the generating series for the number of lengths with the given boundaries """ from sage.symbolic.ring import SR F = SR.one() for dart in range(self._total_darts): if not self._active_darts[dart]: continue i = self._dart_to_edge_index[dart] j1, j2 = self._edge_cycles[i] if j1 == dart: continue else: assert j2 == dart f1 = self._dart_to_face_index[j1] f2 = self._dart_to_face_index[j2] b1 = SR.var('%s%d' %(var, f1)) b2 = SR.var('%s%d' %(var, f2)) F *= b1*b2 / (1 - b1*b2) return F
def __call__(self, a, b, z, **kwargs): """ Return symbolic hypergeometric function expression. INPUT: - ``a`` -- a list or tuple of parameters - ``b`` -- a list or tuple of parameters - ``z`` -- a number or symbolic expression EXAMPLES:: sage: hypergeometric([], [], 1) hypergeometric((), (), 1) sage: hypergeometric([], [1], 1) hypergeometric((), (1,), 1) sage: hypergeometric([2, 3], [1], 1) hypergeometric((2, 3), (1,), 1) sage: hypergeometric([], [], x) hypergeometric((), (), x) sage: hypergeometric([x], [], x^2) hypergeometric((x,), (), x^2) The only simplification that is done automatically is returning 1 if ``z`` is 0. For other simplifications use the ``simplify_hypergeometric`` method. """ return BuiltinFunction.__call__(self, SR._force_pyobject(a), SR._force_pyobject(b), z, **kwargs)
def fourier_series_sine_coefficient(cls, self, parameters, variable, n, L): r""" Returns the n-th Fourier series coefficient of `\sin(n\pi x/L)`, `b_n`. INPUT: - ``self`` - the function f(x), defined over -L x L - ``n`` - an integer n0 - ``L`` - (the period)/2 OUTPUT: `b_n = \frac{1}{L}\int_{-L}^L f(x)\sin(n\pi x/L)dx` EXAMPLES:: sage: f(x) = x^2 sage: f = piecewise([[(-1,1),f]]) sage: f.fourier_series_sine_coefficient(2,1) # L=1, n=2 0 """ from sage.all import sin, pi x = SR.var('x') result = 0 for domain, f in parameters: for interval in domain: a = interval.lower() b = interval.upper() result += (f * sin(pi * x * n / L) / L).integrate(x, a, b) return SR(result).simplify_trig()
def mma_free_integrator(expression, v, a=None, b=None): """ sage: from sage.symbolic.integration.external import mma_free_integrator sage: mma_free_integrator(sin(x), x) # optional - internet -cos(x) """ import urllib, re # We need to integrate against x vars = [str(x) for x in expression.variables()] if any(len(x)>1 for x in vars): raise NotImplementedError("Mathematica online integrator can only handle single letter variables.") x = SR.var('x') if repr(v) != 'x': for i in range(ord('a'), ord('z')+1): if chr(i) not in vars: shadow_x = SR.var(chr(i)) break expression = expression.subs({x:shadow_x}).subs({dvar: x}) params = urllib.urlencode({'expr': expression._mathematica_init_(), 'random': 'false'}) page = urllib.urlopen("http://integrals.wolfram.com/index.jsp", params).read() page = page[page.index('"inputForm"'):page.index('"outputForm"')] page = re.sub("\s", "", page) mexpr = re.match(r".*Integrate.*==</em><br/>(.*)</p>", page).groups()[0] try: ans = SR(mexpr.lower().replace('[', '(').replace(']', ')')) if repr(v) != 'x': ans = ans.subs({x:v}).subs({shadow_x:x}) return ans except TypeError: raise ValueError("Unable to parse: %s" % mexpr)
def _eval_(self, a, z): """ EXAMPLES:: sage: struve_H(0,0) 0 sage: struve_H(pi,0) 0 sage: struve_H(-1/2,x) sqrt(2)*sqrt(1/(pi*x))*sin(x) sage: struve_H(1/2,-1) -sqrt(2)*sqrt(-1/pi)*(cos(1) - 1) sage: struve_H(1/2,pi) 2*sqrt(2)/pi sage: struve_H(2,x) struve_H(2, x) sage: struve_H(-3/2,x) -bessel_J(3/2, x) """ from sage.symbolic.ring import SR if z.is_zero() \ and (SR(a).is_numeric() or SR(a).is_constant()) \ and a.real() >= -1: return ZZ(0) if a == -Integer(1)/2: from sage.functions.trig import sin return sqrt(2/(pi*z)) * sin(z) if a == Integer(1)/2: from sage.functions.trig import cos return sqrt(2/(pi*z)) * (1-cos(z)) if a < 0 and not SR(a).is_integer() and SR(2*a).is_integer(): from sage.rings.rational_field import QQ n = (a*(-2) - 1)/2 return Integer(-1)**n * bessel_J(n+QQ(1)/2, z)
def mma_free_integrator(expression, v, a=None, b=None): """ sage: from sage.symbolic.integration.external import mma_free_integrator sage: mma_free_integrator(sin(x), x) # optional - internet -cos(x) """ import urllib, re # We need to integrate against x vars = [str(x) for x in expression.variables()] if any(len(x) > 1 for x in vars): raise NotImplementedError, "Mathematica online integrator can only handle single letter variables." x = SR.var('x') if repr(v) != 'x': for i in range(ord('a'), ord('z') + 1): if chr(i) not in vars: shadow_x = SR.var(chr(i)) break expression = expression.subs({x: shadow_x}).subs({dvar: x}) params = urllib.urlencode({ 'expr': expression._mathematica_init_(), 'random': 'false' }) page = urllib.urlopen("http://integrals.wolfram.com/index.jsp", params).read() page = page[page.index('"inputForm"'):page.index('"outputForm"')] page = re.sub("\s", "", page) mexpr = re.match(r".*Integrate.*==</em><br/>(.*)</p>", page).groups()[0] try: ans = SR(mexpr.lower().replace('[', '(').replace(']', ')')) if repr(v) != 'x': ans = ans.subs({x: v}).subs({shadow_x: x}) return ans except TypeError: raise ValueError, "Unable to parse: %s" % mexpr
def _eval_(self, a, z): """ EXAMPLES:: sage: struve_L(-2,0) struve_L(-2, 0) sage: struve_L(-1,0) 0 sage: struve_L(pi,0) 0 sage: struve_L(-1/2,x) sqrt(2)*sqrt(1/(pi*x))*sinh(x) sage: struve_L(1/2,1) sqrt(2)*(cosh(1) - 1)/sqrt(pi) sage: struve_L(2,x) struve_L(2, x) sage: struve_L(-3/2,x) -bessel_I(3/2, x) """ from sage.symbolic.ring import SR if z.is_zero() \ and (SR(a).is_numeric() or SR(a).is_constant()) \ and a.real() >= -1: return ZZ(0) if a == -Integer(1)/2: from sage.functions.hyperbolic import sinh return sqrt(2/(pi*z)) * sinh(z) if a == Integer(1)/2: from sage.functions.hyperbolic import cosh return sqrt(2/(pi*z)) * (cosh(z)-1) if a < 0 and not SR(a).is_integer() and SR(2*a).is_integer(): from sage.rings.rational_field import QQ n = (a*(-2) - 1)/2 return Integer(-1)**n * bessel_I(n+QQ(1)/2, z)
def max_to_sr(expr): r""" Convert a Maxima object into a symbolic expression. INPUT: - ``expr`` - ECL object OUTPUT: symbolic expression EXAMPLES:: sage: from sage.interfaces.maxima_lib import maxima_lib, max_to_sr sage: f = maxima_lib('f(x)') sage: f.ecl() <ECL: (($F SIMP) $X)> sage: max_to_sr(f.ecl()) f(x) TESTS:: sage: from sage.interfaces.maxima_lib import sr_to_max, max_to_sr sage: f = function('f',x).diff() sage: bool(max_to_sr(sr_to_max(f)) == f) True """ if expr.consp(): op_max=caar(expr) if op_max in special_max_to_sage: return special_max_to_sage[op_max](expr) if not(op_max in max_op_dict): op_max_str=maxprint(op_max).python()[1:-1] if op_max_str in max_to_pynac_table: op = max_to_pynac_table[op_max_str] else: # This could be unsafe if the conversion to SR # changes the structure of expr sage_expr=SR(maxima(expr)) op=sage_expr.operator() if op in sage_op_dict: raise RuntimeError("Encountered operator mismatch in maxima-to-sr translation") max_op_dict[op_max]=op sage_op_dict[op]=op_max else: op=max_op_dict[op_max] max_args=cdr(expr) args=[max_to_sr(a) for a in max_args] return op(*args) elif expr.symbolp(): if not(expr in max_sym_dict): sage_symbol=SR(maxima(expr)) sage_sym_dict[sage_symbol]=expr max_sym_dict[expr]=sage_symbol return max_sym_dict[expr] else: e=expr.python() if isinstance(e,float): return sage.rings.real_double.RealDoubleElement(e) return e
def test_issue_4023(): from sage.symbolic.ring import SR from sage.functions.all import log from sympy import integrate, simplify a, x = SR.var("a x") i = integrate(log(x) / a, (x, a, a + 1)) i2 = simplify(i) s = SR(i2) assert s == (a * log(1 + a) - a * log(a) + log(1 + a) - 1) / a
def fricas_integrator(expression, v, a=None, b=None, noPole=True): """ Integration using FriCAS EXAMPLES:: sage: from sage.symbolic.integration.external import fricas_integrator # optional - fricas sage: fricas_integrator(sin(x), x) # optional - fricas -cos(x) sage: fricas_integrator(cos(x), x) # optional - fricas sin(x) sage: fricas_integrator(1/(x^2-2), x, 0, 1) # optional - fricas 1/4*sqrt(2)*(log(3*sqrt(2) - 4) - log(sqrt(2))) sage: fricas_integrator(1/(x^2+6), x, -oo, oo) # optional - fricas 1/6*sqrt(6)*pi TESTS: Check that :trac:`25220` is fixed:: sage: integral(sqrt(1-cos(x)), x, 0, 2*pi, algorithm="fricas") # optional - fricas 4*sqrt(2) Check that in case of failure one gets unevaluated integral:: sage: integral(cos(ln(cos(x))), x, 0, pi/8, algorithm='fricas') # optional - fricas integrate(cos(log(cos(x))), x, 0, 1/8*pi) sage: integral(cos(ln(cos(x))), x, algorithm='fricas') # optional - fricas integral(cos(log(cos(x))), x) """ if not isinstance(expression, Expression): expression = SR(expression) from sage.interfaces.fricas import fricas ex = fricas(expression) if a is None: result = ex.integrate(v) else: seg = fricas.equation(v, fricas.segment(a, b)) if noPole: result = ex.integrate(seg, '"noPole"') else: result = ex.integrate(seg) result = result.sage() if result == "failed": return expression.integrate(v, a, b, hold=True) if result == "potentialPole": raise ValueError("The integrand has a potential pole" " in the integration interval") return result
def laplace(cls, self, parameters, variable, x='x', s='t'): r""" Returns the Laplace transform of self with respect to the variable var. INPUT: - ``x`` - variable of self - ``s`` - variable of Laplace transform. We assume that a piecewise function is 0 outside of its domain and that the left-most endpoint of the domain is 0. EXAMPLES:: sage: x, s, w = var('x, s, w') sage: f = piecewise([[(0,1),1],[[1,2], 1-x]]) sage: f.laplace(x, s) -e^(-s)/s + (s + 1)*e^(-2*s)/s^2 + 1/s - e^(-s)/s^2 sage: f.laplace(x, w) -e^(-w)/w + (w + 1)*e^(-2*w)/w^2 + 1/w - e^(-w)/w^2 :: sage: y, t = var('y, t') sage: f = piecewise([[[1,2], 1-y]]) sage: f.laplace(y, t) (t + 1)*e^(-2*t)/t^2 - e^(-t)/t^2 :: sage: s = var('s') sage: t = var('t') sage: f1(t) = -t sage: f2(t) = 2 sage: f = piecewise([[[0,1],f1],[(1,infinity),f2]]) sage: f.laplace(t,s) (s + 1)*e^(-s)/s^2 + 2*e^(-s)/s - 1/s^2 """ from sage.all import assume, exp, forget x = SR.var(x) s = SR.var(s) assume(s>0) result = 0 for domain, f in parameters: for interval in domain: a = interval.lower() b = interval.upper() result += (SR(f)*exp(-s*x)).integral(x,a,b) forget(s>0) return result
def _step_upper_bound_low_mem(r, m, q, generating_function): r""" Low memory implementation of :func:`_step_upper_bound_internal`. Significantly slower, but the memory footprint does not significantly increase even if the series coefficients need to be computed to very high degree terms. """ L = LieAlgebra(ZZ, ['X_%d' % k for k in range(r)]).Lyndon() dim_fm = L.graded_dimension(m) PR = PolynomialRing(ZZ, 't') t = PR.gen() a = (1 - dim_fm * (1 - t**q)) * t**m b = PR.one() for k in range(1, m): b *= (1 - t**k)**L.graded_dimension(k) # extract initial coefficients from a symbolic series expansion bd = b.degree() id = max(a.degree() + 1, bd) offset = id - bd quot = SR(a / b) sym_t = SR(t) qs = quot.series(sym_t, id) # check if partial sum is positive already within series expansion # store the last offset...id terms to start the linear recurrence coeffs = deque() cumul = ZZ.zero() for s in range(id): c = ZZ(qs.coefficient(sym_t, s)) cumul += c if s >= offset: coeffs.append(c) if cumul > 0: if generating_function: return s, quot return s # the rest of the coefficients are defined by a recurrence relation multipliers = [-b.monomial_coefficient(t**(bd - k)) for k in range(bd)] while cumul <= 0: c_next = sum(c * m for c, m in zip(coeffs, multipliers)) cumul += c_next s += 1 coeffs.append(c_next) coeffs.popleft() if generating_function: return s, quot return s
def laplace(cls, self, parameters, variable, x='x', s='t'): r""" Returns the Laplace transform of self with respect to the variable var. INPUT: - ``x`` - variable of self - ``s`` - variable of Laplace transform. We assume that a piecewise function is 0 outside of its domain and that the left-most endpoint of the domain is 0. EXAMPLES:: sage: x, s, w = var('x, s, w') sage: f = piecewise([[(0,1),1],[[1,2], 1-x]]) sage: f.laplace(x, s) -e^(-s)/s + (s + 1)*e^(-2*s)/s^2 + 1/s - e^(-s)/s^2 sage: f.laplace(x, w) -e^(-w)/w + (w + 1)*e^(-2*w)/w^2 + 1/w - e^(-w)/w^2 :: sage: y, t = var('y, t') sage: f = piecewise([[[1,2], 1-y]]) sage: f.laplace(y, t) (t + 1)*e^(-2*t)/t^2 - e^(-t)/t^2 :: sage: s = var('s') sage: t = var('t') sage: f1(t) = -t sage: f2(t) = 2 sage: f = piecewise([[[0,1],f1],[(1,infinity),f2]]) sage: f.laplace(t,s) (s + 1)*e^(-s)/s^2 + 2*e^(-s)/s - 1/s^2 """ from sage.all import assume, exp, forget x = SR.var(x) s = SR.var(s) assume(s > 0) result = 0 for domain, f in parameters: for interval in domain: a = interval.lower() b = interval.upper() result += (SR(f) * exp(-s * x)).integral(x, a, b) forget(s > 0) return result
def simplify_abs_trig(expr): r""" Simplify abs(sin(...)) in symbolic expressions """ from sage.symbolic.ring import SR from sage.symbolic.constants import pi sexpr = str(expr) if 'abs(sin(' not in sexpr: # nothing to simplify return expr tp = [] val = [] for pos in range(len(sexpr)): if sexpr[pos:pos + 8] == 'abs(sin(': # finding the end of abs argument: scan = pos + 4 # start of abs parenth = 1 while parenth != 0: if sexpr[scan] == '(': parenth += 1 if sexpr[scan] == ')': parenth -= 1 scan += 1 pos_abs_end = scan # finding the end of sin argument: scan = pos + 8 # start of sin parenth = 1 while parenth != 0: if sexpr[scan] == '(': parenth += 1 if sexpr[scan] == ')': parenth -= 1 scan += 1 pos_sin_end = scan # if the abs contains only the sinus, the simplification can be tried: if pos_sin_end == pos_abs_end - 1: tp.append(pos) val.append(sexpr[pos:pos_abs_end]) simp = [] for v in val: # argument of the sinus: sx = v[8:-2] x = SR(sx) if x >= 0 and x <= pi: simp.append('sin(' + sx + ')') elif x >= -pi and x <= 0: simp.append('(-sin(' + sx + '))') else: simp.append(v) # no simplification is applicable nexpr = "" pos0 = 0 for i, pos in enumerate(tp): nexpr += sexpr[pos0:pos] + simp[i] pos0 = pos + len(val[i]) nexpr += sexpr[pos0:] return SR(nexpr)
def max_to_sr(expr): r""" Convert a Maxima object into a symbolic expression. INPUT: - ``expr`` - ECL object OUTPUT: symbolic expression EXAMPLES:: sage: from sage.interfaces.maxima_lib import maxima_lib, max_to_sr sage: f = maxima_lib('f(x)') sage: f.ecl() <ECL: (($F SIMP) $X)> sage: max_to_sr(f.ecl()) f(x) TESTS:: sage: from sage.interfaces.maxima_lib import sr_to_max, max_to_sr sage: f = function('f',x).diff() sage: bool(max_to_sr(sr_to_max(f)) == f) True """ if expr.consp(): op_max=caar(expr) if op_max in special_max_to_sage: return special_max_to_sage[op_max](expr) if not(op_max in max_op_dict): # This could be unsafe if the conversion to SR # changes the structure of expr sage_expr=SR(maxima(expr)) max_op_dict[op_max]=sage_expr.operator() sage_op_dict[sage_expr.operator()]=op_max op=max_op_dict[op_max] max_args=cdr(expr) args=[max_to_sr(a) for a in max_args] return op(*args) elif expr.symbolp(): if not(expr in max_sym_dict): sage_symbol=SR(maxima(expr)) sage_sym_dict[sage_symbol]=expr max_sym_dict[expr]=sage_symbol return max_sym_dict[expr] else: e=expr.python() if isinstance(e,float): return sage.rings.real_double.RealDoubleElement(e) return e
def simplify_sqrt_real(expr): r""" Simplify sqrt in symbolic expressions in the real domain. EXAMPLES: Simplifications of basic expressions:: sage: assume(x<0) sage: simplify_sqrt_real( sqrt(x^2) ) -x sage: simplify_sqrt_real( sqrt(x^2-2*x+1) ) -x + 1 sage: simplify_sqrt_real( sqrt(x^2) + sqrt(x^2-2*x+1) ) -2*x + 1 """ from sage.symbolic.ring import SR from sage.calculus.calculus import maxima # 1/ Search for the sqrt's in expr sexpr = str(expr) if 'sqrt(' not in sexpr: # no sqrt to simplify return expr pos_sqrts = [] # positions of the sqrt's in sexpr the_sqrts = [] # the sqrt sub-expressions in sexpr for pos in range(len(sexpr)): if sexpr[pos:pos + 5] == 'sqrt(': pos_sqrts.append(pos) parenth = 1 scan = pos + 5 while parenth != 0: if sexpr[scan] == '(': parenth += 1 if sexpr[scan] == ')': parenth -= 1 scan += 1 the_sqrts.append(sexpr[pos:scan]) # 2/ Simplifications of the sqrt's new_expr = "" # will contain the result pos0 = 0 for i, pos in enumerate(pos_sqrts): # radcan is called on each sqrt: x = SR(the_sqrts[i]) simpl = SR(x._maxima_().radcan()) # the absolute value of radcan's output is taken, the call to simplify() # taking into account possible assumptions regarding the sign of simpl: new_expr += sexpr[pos0:pos] + '(' + str(abs(simpl).simplify()) + ')' pos0 = pos + len(the_sqrts[i]) new_expr += sexpr[pos0:] return SR(new_expr)
def weight_integrand(self, simplify_factor=True): """ Weight integrand as a rational function. The Jacobian determinant of some coordinate transformation. """ def arg(x, y): return arctan(y / x) # up to a constant, but it doesn't matter def phi(x, y, a, b): z = (a + I * b - x - I * y) * (a - I * b - x - I * y) w = z.real() q = z.imag() return arg(w, q).full_simplify() n = len(self.internal_vertices()) coordinates = lambda v: SR.var(chr(97+2*(v-1)) + ',' + chr(97+2*(v-1)+1)) \ if v in self.internal_vertices() else \ [(0,0), (1,0)][self.ground_vertices().index(v)] internal_coordinates = sum( (list(coordinates(v)) for v in sorted(self.internal_vertices())), []) U = CoordinatePatch(internal_coordinates) F = DifferentialForms(U) psi = 0 two_forms = [] for v in self.internal_vertices(): x, y = coordinates(v) outgoing_edges = self.outgoing_edges([v]) left_target = filter(lambda (x, y, z): z == 'L', outgoing_edges)[0][1] right_target = filter(lambda (x, y, z): z == 'R', outgoing_edges)[0][1] one_forms = [] for target in [left_target, right_target]: a, b = coordinates(target) one_form = DifferentialForm(F, 1) for v in internal_coordinates: index = internal_coordinates.index(v) one_form[index] = phi(x, y, a, b).diff(v) if simplify_factor: one_form[index] = SR(one_form[index]).full_simplify() one_forms.append(one_form) two_form = one_forms[0] * one_forms[1] two_forms.append(two_form) import operator two_n_form = reduce(operator.mul, two_forms, 1) return two_n_form[range(0, 2 * n)]
def simplify_sqrt_real(expr): r""" Simplify sqrt in symbolic expressions in the real domain. EXAMPLES: Simplifications of basic expressions:: sage: assume(x<0) sage: simplify_sqrt_real( sqrt(x^2) ) -x sage: simplify_sqrt_real( sqrt(x^2-2*x+1) ) -x + 1 sage: simplify_sqrt_real( sqrt(x^2) + sqrt(x^2-2*x+1) ) -2*x + 1 """ from sage.symbolic.ring import SR from sage.calculus.calculus import maxima # 1/ Search for the sqrt's in expr sexpr = str(expr) if 'sqrt(' not in sexpr: # no sqrt to simplify return expr pos_sqrts = [] # positions of the sqrt's in sexpr the_sqrts = [] # the sqrt sub-expressions in sexpr for pos in range(len(sexpr)): if sexpr[pos:pos+5] == 'sqrt(': pos_sqrts.append(pos) parenth = 1 scan = pos+5 while parenth != 0: if sexpr[scan] == '(': parenth += 1 if sexpr[scan] == ')': parenth -= 1 scan += 1 the_sqrts.append( sexpr[pos:scan] ) # 2/ Simplifications of the sqrt's new_expr = "" # will contain the result pos0 = 0 for i, pos in enumerate(pos_sqrts): # radcan is called on each sqrt: x = SR(the_sqrts[i]) simpl = SR(x._maxima_().radcan()) # the absolute value of radcan's output is taken, the call to simplify() # taking into account possible assumptions regarding the sign of simpl: new_expr += sexpr[pos0:pos] + '(' + str(abs(simpl).simplify()) + ')' pos0 = pos + len(the_sqrts[i]) new_expr += sexpr[pos0:] return SR(new_expr)
def _sympysage_symbol(self): """ EXAMPLES:: sage: from sympy import Symbol sage: assert x._sympy_() == Symbol('x') sage: assert x == Symbol('x')._sage_() """ from sage.symbolic.ring import SR try: return SR.var(self.name) except ValueError: # sympy sometimes returns dummy variables # with name = 'None', str rep = '_None' # in particular in inverse Laplace and inverse Mellin transforms return SR.var(str(self))
def fourier_series_sine_coefficient(cls, self, parameters, variable, n, L): r""" Returns the n-th Fourier series coefficient of `\sin(n\pi x/L)`, `b_n`. INPUT: - ``self`` - the function f(x), defined over -L x L - ``n`` - an integer n0 - ``L`` - (the period)/2 OUTPUT: `b_n = \frac{1}{L}\int_{-L}^L f(x)\sin(n\pi x/L)dx` EXAMPLES:: sage: f(x) = x^2 sage: f = piecewise([[(-1,1),f]]) sage: f.fourier_series_sine_coefficient(2,1) # L=1, n=2 0 """ from sage.all import sin, pi x = SR.var('x') result = 0 for domain, f in parameters: for interval in domain: a = interval.lower() b = interval.upper() result += (f*sin(pi*x*n/L)/L).integrate(x, a, b) return SR(result).simplify_trig()
def __init__(self, ambient_manifold, n, coordinates, chart_name, embedding_functions, name=None, latex_name=None, ambient_chart=None, start_index=0): from sage.symbolic.ring import SR Manifold.__init__(self, n, name, latex_name, start_index) if not isinstance(ambient_manifold, Manifold): raise TypeError( "The argument ambient_manifold must be a manifold.") self.ambient_manifold = ambient_manifold Chart(self, coordinates, chart_name) if ambient_chart is None: ambient_chart = ambient_manifold.def_chart.name n_amb = ambient_manifold.dim if len(embedding_functions) != n_amb: raise ValueError( str(n_amb) + " coordinate functions must be provided.") embedding_expressions = [ SR(embedding_functions[i]) for i in range(n_amb) ] self.embedding = DiffMapping(self, ambient_manifold, embedding_expressions, chart_name, ambient_chart)
def show(self, show_hyperboloid=True, **graphics_options): r""" Plot ``self``. EXAMPLES:: sage: from sage.geometry.hyperbolic_space.hyperbolic_geodesic import * sage: g = HyperbolicPlane().HM().random_geodesic() sage: g.show() Graphics3d Object """ x = SR.var('x') opts = self.graphics_options() opts.update(graphics_options) v1, u2 = [vector(k.coordinates()) for k in self.endpoints()] # Lorentzian Gram Shmidt. The original vectors will be # u1, u2 and the orthogonal ones will be v1, v2. Except # v1 = u1, and I don't want to declare another variable, # hence the odd naming convention above. # We need the Lorentz dot product of v1 and u2. v1_ldot_u2 = u2[0]*v1[0] + u2[1]*v1[1] - u2[2]*v1[2] v2 = u2 + v1_ldot_u2 * v1 v2_norm = sqrt(v2[0]**2 + v2[1]**2 - v2[2]**2) v2 = v2 / v2_norm v2_ldot_u2 = u2[0]*v2[0] + u2[1]*v2[1] - u2[2]*v2[2] # Now v1 and v2 are Lorentz orthogonal, and |v1| = -1, |v2|=1 # That is, v1 is unit timelike and v2 is unit spacelike. # This means that cosh(x)*v1 + sinh(x)*v2 is unit timelike. hyperbola = cosh(x)*v1 + sinh(x)*v2 endtime = arcsinh(v2_ldot_u2) from sage.plot.plot3d.all import parametric_plot3d pic = parametric_plot3d(hyperbola, (x, 0, endtime), **graphics_options) if show_hyperboloid: pic += self._model.get_background_graphic() return pic
def show(self, show_hyperboloid=True, **graphics_options): r""" Plot ``self``. EXAMPLES:: sage: from sage.geometry.hyperbolic_space.hyperbolic_geodesic import * sage: g = HyperbolicPlane().HM().random_geodesic() sage: g.show() Graphics3d Object """ x = SR.var('x') opts = self.graphics_options() opts.update(graphics_options) v1, u2 = [vector(k.coordinates()) for k in self.endpoints()] # Lorentzian Gram Shmidt. The original vectors will be # u1, u2 and the orthogonal ones will be v1, v2. Except # v1 = u1, and I don't want to declare another variable, # hence the odd naming convention above. # We need the Lorentz dot product of v1 and u2. v1_ldot_u2 = u2[0] * v1[0] + u2[1] * v1[1] - u2[2] * v1[2] v2 = u2 + v1_ldot_u2 * v1 v2_norm = sqrt(v2[0]**2 + v2[1]**2 - v2[2]**2) v2 = v2 / v2_norm v2_ldot_u2 = u2[0] * v2[0] + u2[1] * v2[1] - u2[2] * v2[2] # Now v1 and v2 are Lorentz orthogonal, and |v1| = -1, |v2|=1 # That is, v1 is unit timelike and v2 is unit spacelike. # This means that cosh(x)*v1 + sinh(x)*v2 is unit timelike. hyperbola = cosh(x) * v1 + sinh(x) * v2 endtime = arcsinh(v2_ldot_u2) from sage.plot.plot3d.all import parametric_plot3d pic = parametric_plot3d(hyperbola, (x, 0, endtime), **graphics_options) if show_hyperboloid: pic += self._model.get_background_graphic() return pic
def random_expr(size, nvars=1, ncoeffs=None, var_frac=0.5, internal=full_internal, nullary=full_nullary, nullary_frac=0.2, coeff_generator=QQ.random_element, verbose=False): r""" Produce a random symbolic expression of the given size. By default, the expression involves (at most) one variable, an arbitrary number of coefficients, and all of the symbolic functions and constants (from the probability lists full_internal and full_nullary). It is possible to adjust the ratio of leaves between symbolic constants, variables, and coefficients (var_frac gives the fraction of variables, and nullary_frac the fraction of symbolic constants; the remaining leaves are coefficients). The actual mix of symbolic constants and internal nodes can be modified by specifying different probability lists. To use a different type for coefficients, you can specify coeff_generator, which should be a function that will return a random coefficient every time it is called. This function will often raise an error because it tries to create an erroneous expression (such as a division by zero). EXAMPLES:: sage: from sage.symbolic.random_tests import * sage: some_functions = [arcsinh, arctan, arctan2, arctanh, ....: arg, beta, binomial, ceil, conjugate, cos, cosh, cot, coth, ....: elliptic_pi, erf, exp, factorial, floor, heaviside, imag_part, ....: sech, sgn, sin, sinh, tan, tanh, unit_step, zeta, zetaderiv] sage: my_internal = [(0.6, full_binary, 2), (0.2, full_unary, 1), ....: (0.2, [(1.0,f,f.number_of_arguments()) for f in some_functions])] sage: set_random_seed(1) sage: random_expr(50, nvars=3, internal=my_internal, ....: coeff_generator=CDF.random_element) # not tested # known bug (v1^(0.9713408427702117 + 0.195868299334218*I)/cot(-pi + v1^2 + v3) + tan(arctan(v2 + arctan2(-0.35859061674557324 + 0.9407509502498164*I, v3) - 0.8419115504372718 + 0.30375717982404615*I) + arctan2((0.2275357305882964 - 0.8258002386106038*I)/factorial(v2), -v3 - 0.7604559947718565 - 0.5543672548552057*I) + ceil(1/arctan2(v1, v1))))/v2 sage: random_expr(5, verbose=True) # not tested # known bug About to apply <built-in function inv> to [31] About to apply sgn to [v1] About to apply <built-in function add> to [1/31, sgn(v1)] sgn(v1) + 1/31 """ vars = [(1.0, SR.var('v%d' % (n + 1))) for n in range(nvars)] if ncoeffs is None: ncoeffs = size coeffs = [(1.0, coeff_generator()) for _ in range(ncoeffs)] leaves = [(var_frac, vars), (1.0 - var_frac - nullary_frac, coeffs), (nullary_frac, nullary)] leaves = normalize_prob_list(leaves) internal = normalize_prob_list(internal) return random_expr_helper(size, internal, leaves, verbose)
def __setitem__(self, subscript, fun): r""" Modify a given component of the differential form. INPUT: - ``subscript``: subscript of the component. Must be an integer or a list of integers. EXAMPLES:: sage: F = DifferentialForms(); F Algebra of differential forms in the variables x, y, z sage: f = DifferentialForm(F, 2) sage: f[1, 2] = x; f x*dy/\dz """ if isinstance(subscript, (Integer, int)): subscript = (subscript, ) else: subscript = tuple(subscript) dim = self.parent().base_space().dim() if any([s >= dim for s in subscript]): raise ValueError("Index out of bounds.") if len(subscript) != self._degree: raise TypeError("%s is not a subscript of degree %s" %\ (subscript, self._degree)) sign, subscript = sort_subscript(subscript) self._components[subscript] = sign * SR(fun)
def fourier_series_partial_sum(cls, self, parameters, variable, N, L): r""" Returns the partial sum .. math:: f(x) \sim \frac{a_0}{2} + \sum_{n=1}^N [a_n\cos(\frac{n\pi x}{L}) + b_n\sin(\frac{n\pi x}{L})], as a string. EXAMPLE:: sage: f(x) = x^2 sage: f = piecewise([[(-1,1),f]]) sage: f.fourier_series_partial_sum(3,1) cos(2*pi*x)/pi^2 - 4*cos(pi*x)/pi^2 + 1/3 sage: f1(x) = -1 sage: f2(x) = 2 sage: f = piecewise([[(-pi,pi/2),f1],[(pi/2,pi),f2]]) sage: f.fourier_series_partial_sum(3,pi) -3*cos(x)/pi - 3*sin(2*x)/pi + 3*sin(x)/pi - 1/4 """ from sage.all import pi, sin, cos, srange x = self.default_variable() a0 = self.fourier_series_cosine_coefficient(0, L) result = a0 / 2 + sum( [(self.fourier_series_cosine_coefficient(n, L) * cos(n * pi * x / L) + self.fourier_series_sine_coefficient( n, L) * sin(n * pi * x / L)) for n in srange(1, N)]) return SR(result).expand()
def max_at_to_sage(expr): r""" Special conversion rule for AT expressions. INPUT: - ``expr`` - ECL object; a Maxima AT expression OUTPUT: symbolic expression EXAMPLES:: sage: from sage.interfaces.maxima_lib import maxima_lib, max_at_to_sage sage: a=maxima_lib("'at(f(x,y,z),[x=1,y=2,z=3])") sage: a 'at(f(x,y,z),[x=1,y=2,z=3]) sage: max_at_to_sage(a.ecl()) f(1, 2, 3) sage: a=maxima_lib("'at(f(x,y,z),x=1)") sage: a 'at(f(x,y,z),x=1) sage: max_at_to_sage(a.ecl()) f(1, y, z) """ arg=max_to_sr(expr.cadr()) subsarg=caddr(expr) if caar(subsarg)==mlist: subsvalues=dict( (v.lhs(),v.rhs()) for v in max_to_sr(subsarg)) else: v=max_to_sr(subsarg) subsvalues=dict([(v.lhs(),v.rhs())]) return SR(arg).subs(subsvalues)
def check_splittingField(self): """ Verify that the splitting field of a Q-polynomial scheme with principal multiplicity more than 2 is at most a degree 2 extension of the field of rational numbers. """ if checkNonneg(2 - self._.m[1]): return if self._has("Q"): M = self._.Q elif self._has("P"): M = self._.P else: M = self.dualEigenmatrix() t = None for r in M[1:, 1:]: for v in r: if len(SR(v).variables()) > 0: continue mp = v.minpoly() if mp.degree() == 1: continue elif mp.degree() == 2: if t is None: t = QQ.extension(mp, 'a')['t'].gen() continue elif not mp(t).is_irreducible(): continue raise InfeasibleError("splitting field of Q-polynomial scheme" " with m[1] > 2 is more than degree 2" " extension of rationals", ["CerzoSuzuki09", "MartinWilliford09"])
def spin_polynomial(part, weight, length): """ Returns the spin polynomial associated to ``part``, ``weight``, and ``length``. EXAMPLES:: sage: from sage.combinat.ribbon_tableau import spin_polynomial sage: spin_polynomial([6,6,6],[4,2],3) t^6 + t^5 + 2*t^4 + t^3 + t^2 sage: spin_polynomial([6,6,6],[4,1,1],3) t^6 + 2*t^5 + 3*t^4 + 2*t^3 + t^2 sage: spin_polynomial([3,3,3,2,1], [2,2], 3) t^(7/2) + t^(5/2) sage: spin_polynomial([3,3,3,2,1], [2,1,1], 3) 2*t^(7/2) + 2*t^(5/2) + t^(3/2) sage: spin_polynomial([3,3,3,2,1], [1,1,1,1], 3) 3*t^(7/2) + 5*t^(5/2) + 3*t^(3/2) + sqrt(t) sage: spin_polynomial([5,4,3,2,1,1,1], [2,2,1], 3) 2*t^(9/2) + 6*t^(7/2) + 2*t^(5/2) sage: spin_polynomial([[6]*6, [3,3]], [4,4,2], 3) 3*t^9 + 5*t^8 + 9*t^7 + 6*t^6 + 3*t^5 """ from sage.symbolic.ring import SR sp = spin_polynomial_square(part, weight, length) t = SR.var('t') c = sp.coefficients(sparse=False) return sum([c[i] * t**(QQ(i) / 2) for i in range(len(c))])
def bilinear_form(self, R=None): """ Return the bilinear form over ``R`` associated to ``self``. INPUT: - ``R`` -- (default: universal cyclotomic field) a ring used to compute the bilinear form EXAMPLES:: sage: CoxeterType(['A', 2, 1]).bilinear_form() [ 1 -1/2 -1/2] [-1/2 1 -1/2] [-1/2 -1/2 1] sage: CoxeterType(['H', 3]).bilinear_form() [ 1 -1/2 0] [ -1/2 1 1/2*E(5)^2 + 1/2*E(5)^3] [ 0 1/2*E(5)^2 + 1/2*E(5)^3 1] sage: C = CoxeterMatrix([[1,-1,-1],[-1,1,-1],[-1,-1,1]]) sage: C.bilinear_form() [ 1 -1 -1] [-1 1 -1] [-1 -1 1] """ n = self.rank() mat = self.coxeter_matrix()._matrix base_ring = mat.base_ring() from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField UCF = UniversalCyclotomicField() if R is None: R = UCF # if UCF.has_coerce_map_from(base_ring): # R = UCF # else: # R = base_ring # Compute the matrix with entries `- \cos( \pi / m_{ij} )`. if R is UCF: val = lambda x: (R.gen(2 * x) + ~R.gen(2 * x)) / R( -2) if x > -1 else R.one() * x else: from sage.functions.trig import cos from sage.symbolic.constants import pi val = lambda x: -R(cos(pi / SR(x))) if x > -1 else x MS = MatrixSpace(R, n, sparse=True) MC = MS._get_matrix_class() bilinear = MC(MS, entries={(i, j): val(mat[i, j]) for i in range(n) for j in range(n) if mat[i, j] != 2}, coerce=True, copy=True) bilinear.set_immutable() return bilinear
def maxima_integrator(expression, v, a=None, b=None): """ Integration using Maxima EXAMPLES:: sage: from sage.symbolic.integration.external import maxima_integrator sage: maxima_integrator(sin(x), x) -cos(x) sage: maxima_integrator(cos(x), x) sin(x) sage: f(x) = function('f')(x) sage: maxima_integrator(f(x), x) integrate(f(x), x) TESTS: Check that :trac:`25817` is fixed:: sage: maxima_integrator(log(e^x*log(x)*sin(x))/x^2, x) 1/2*(x*(Ei(-log(x)) + conjugate(Ei(-log(x)))) - 2*x*integrate(sin(x)/(x*cos(x)^2 + x*sin(x)^2 + 2*x*cos(x) + x), x) + 2*x*integrate(sin(x)/(x*cos(x)^2 + x*sin(x)^2 - 2*x*cos(x) + x), x) + 2*x*log(x) + 2*log(2) - log(cos(x)^2 + sin(x)^2 + 2*cos(x) + 1) - log(cos(x)^2 + sin(x)^2 - 2*cos(x) + 1) - 2*log(log(x)))/x """ from sage.calculus.calculus import maxima if not isinstance(expression, Expression): expression = SR(expression) if a is None: result = maxima.sr_integral(expression, v) else: result = maxima.sr_integral(expression, v, a, b) return result._sage_()
def populate_polyhedra(self): from sage.geometry.polyhedron.constructor import Polyhedron from sage.symbolic.ring import SR def get_vector(inequality, vars): coefficients = list(inequality.coefficient(var) for var in vars) constant = inequality - sum(c*v for c, v in zip(coefficients, vars)) return [constant] + coefficients d = self.dimension() prefix = self.trees[0].PREFIX vars = list(SR(prefix + "{}".format(j)) for j in range(d+1)) for tree in self.trees: others = list(self.trees) others.remove(tree) ineqs = [other.partition_cost() - tree.partition_cost() for other in others] + vars ineq_matrix = [get_vector(ineq, vars) for ineq in ineqs] P = Polyhedron(ieqs=ineq_matrix) if self.is_disjoint(): P = polyhedron_break_tie(P) tree.polyhedron = P nonnegative_orthant = Polyhedron(ieqs=[dd*(0,) + (1,) + (d+1-dd)*(0,) for dd in range(1, d+1+1)]) assert all(A.polyhedron & nonnegative_orthant == A.polyhedron for A in self.trees) if self.is_disjoint(): assert all((A.polyhedron & B.polyhedron).is_empty() for A in self.trees for B in self.trees if A != B)
def spin_polynomial(part, weight, length): """ Returns the spin polynomial associated to ``part``, ``weight``, and ``length``. EXAMPLES:: sage: from sage.combinat.ribbon_tableau import spin_polynomial sage: spin_polynomial([6,6,6],[4,2],3) t^6 + t^5 + 2*t^4 + t^3 + t^2 sage: spin_polynomial([6,6,6],[4,1,1],3) t^6 + 2*t^5 + 3*t^4 + 2*t^3 + t^2 sage: spin_polynomial([3,3,3,2,1], [2,2], 3) t^(7/2) + t^(5/2) sage: spin_polynomial([3,3,3,2,1], [2,1,1], 3) 2*t^(7/2) + 2*t^(5/2) + t^(3/2) sage: spin_polynomial([3,3,3,2,1], [1,1,1,1], 3) 3*t^(7/2) + 5*t^(5/2) + 3*t^(3/2) + sqrt(t) sage: spin_polynomial([5,4,3,2,1,1,1], [2,2,1], 3) 2*t^(9/2) + 6*t^(7/2) + 2*t^(5/2) sage: spin_polynomial([[6]*6, [3,3]], [4,4,2], 3) 3*t^9 + 5*t^8 + 9*t^7 + 6*t^6 + 3*t^5 """ from sage.symbolic.ring import SR sp = spin_polynomial_square(part,weight,length) t = SR.var('t') c = sp.coefficients(sparse=False) return sum([c[i]*t**(QQ(i)/2) for i in range(len(c))])
def _element_constructor_(self, fun): """ Coerce a given function (element of the symbolic ring) into a differential form of degree zero. EXAMPLES:: sage: x, y, z = var('x, y, z') sage: U = CoordinatePatch((x, y, z)) doctest:...: DeprecationWarning: Use Manifold instead. See http://trac.sagemath.org/24444 for details. sage: F = DifferentialForms(U); F doctest:...: DeprecationWarning: For the set of differential forms of degree p, use U.diff_form_module(p), where U is the base manifold (type U.diff_form_module? for details). See http://trac.sagemath.org/24444 for details. Algebra of differential forms in the variables x, y, z sage: F(sin(x*y)) # indirect doctest doctest:...: DeprecationWarning: Use U.diff_form(degree) instead, where U is the base manifold (type U.diff_form? for details). See http://trac.sagemath.org/24444 for details. sin(x*y) """ fun = SR(fun) if fun not in self: raise ValueError("Function not an element of this algebra of differential forms.") return DifferentialForm(self, 0, fun)
def random_expr( size, nvars=1, ncoeffs=None, var_frac=0.5, internal=full_internal, nullary=full_nullary, nullary_frac=0.2, coeff_generator=QQ.random_element, verbose=False, ): r""" Produce a random symbolic expression of the given size. By default, the expression involves (at most) one variable, an arbitrary number of coefficients, and all of the symbolic functions and constants (from the probability lists full_internal and full_nullary). It is possible to adjust the ratio of leaves between symbolic constants, variables, and coefficients (var_frac gives the fraction of variables, and nullary_frac the fraction of symbolic constants; the remaining leaves are coefficients). The actual mix of symbolic constants and internal nodes can be modified by specifying different probability lists. To use a different type for coefficients, you can specify coeff_generator, which should be a function that will return a random coefficient every time it is called. This function will often raise an error because it tries to create an erroneous expression (such as a division by zero). EXAMPLES:: sage: from sage.symbolic.random_tests import * sage: set_random_seed(53) sage: random_expr(50, nvars=3, coeff_generator=CDF.random_element) # random (v1^(0.97134084277 + 0.195868299334*I)/csc(-pi + v1^2 + v3) + sgn(1/ ((-v3 - 0.760455994772 - 0.554367254855*I)*erf(v3 + 0.982759757946 - 0.0352136502348*I)) + binomial(arccoth(v1^pi), 0.760455994772 + 0.554367254855*I) + arccosh(2*v2 - (v2 + 0.841911550437 - 0.303757179824*I)/sinh_integral(pi) + arccoth(v3 + 0.530133230474 + 0.532140303485*I))))/v2 sage: random_expr(5, verbose=True) # random About to apply <built-in function inv> to [31] About to apply sgn to [v1] About to apply <built-in function add> to [1/31, sgn(v1)] sgn(v1) + 1/31 """ vars = [(1.0, SR.var("v%d" % (n + 1))) for n in range(nvars)] if ncoeffs is None: ncoeffs = size coeffs = [(1.0, coeff_generator()) for _ in range(ncoeffs)] leaves = [(var_frac, vars), (1.0 - var_frac - nullary_frac, coeffs), (nullary_frac, nullary)] leaves = normalize_prob_list(leaves) internal = normalize_prob_list(internal) return random_expr_helper(size, internal, leaves, verbose)
def symbol(a=None): """ Return a variable from the symbolic ring with the given name. If an expression is given, it is returned unchanged. """ if isinstance(a, Expression): return a return SR.symbol(a)
def EllipticCurve_from_cubic(F, P): r""" Construct an elliptic curve from a ternary cubic with a rational point. INPUT: - ``F`` -- a homogeneous cubic in three variables with rational coefficients (either as a polynomial ring element or as a string) defining a smooth plane cubic curve. - ``P`` -- a 3-tuple `(x,y,z)` defining a projective point on the curve `F=0`. OUTPUT: (elliptic curve) An elliptic curve (in minimal Weierstrass form) isomorphic to the curve `F=0`. .. note:: USES MAGMA - This function will not work on computers that do not have magma installed. TO DO: implement this without using MAGMA. For a more general version, see the function ``EllipticCurve_from_plane_curve()``. EXAMPLES: First we find that the Fermat cubic is isomorphic to the curve with Cremona label 27a1:: sage: E = EllipticCurve_from_cubic('x^3 + y^3 + z^3', [1,-1,0]) # optional - magma sage: E # optional - magma Elliptic Curve defined by y^2 + y = x^3 - 7 over Rational Field sage: E.cremona_label() # optional - magma '27a1' Next we find the minimal model and conductor of the Jacobian of the Selmer curve. :: sage: E = EllipticCurve_from_cubic('u^3 + v^3 + 60*w^3', [1,-1,0]) # optional - magma sage: E # optional - magma Elliptic Curve defined by y^2 = x^3 - 24300 over Rational Field sage: E.conductor() # optional - magma 24300 """ from sage.interfaces.all import magma cmd = "P<%s,%s,%s> := ProjectivePlane(RationalField());" % SR( F).variables() magma.eval(cmd) cmd = 'aInvariants(MinimalModel(EllipticCurve(Curve(Scheme(P, %s)),P!%s)));' % ( F, P) s = magma.eval(cmd) return EllipticCurve(rings.RationalField(), eval(s))
def random_expr(size, nvars=1, ncoeffs=None, var_frac=0.5, internal=full_internal, nullary=full_nullary, nullary_frac=0.2, coeff_generator=QQ.random_element, verbose=False): r""" Produce a random symbolic expression of the given size. By default, the expression involves (at most) one variable, an arbitrary number of coefficients, and all of the symbolic functions and constants (from the probability lists full_internal and full_nullary). It is possible to adjust the ratio of leaves between symbolic constants, variables, and coefficients (var_frac gives the fraction of variables, and nullary_frac the fraction of symbolic constants; the remaining leaves are coefficients). The actual mix of symbolic constants and internal nodes can be modified by specifying different probability lists. To use a different type for coefficients, you can specify coeff_generator, which should be a function that will return a random coefficient every time it is called. This function will often raise an error because it tries to create an erroneous expression (such as a division by zero). EXAMPLES:: sage: from sage.symbolic.random_tests import * sage: set_random_seed(53) sage: random_expr(50, nvars=3, coeff_generator=CDF.random_element) # random (v1^(0.97134084277 + 0.195868299334*I)/csc(-pi + v1^2 + v3) + sgn(1/ ((-v3 - 0.760455994772 - 0.554367254855*I)*erf(v3 + 0.982759757946 - 0.0352136502348*I)) + binomial(arccoth(v1^pi), 0.760455994772 + 0.554367254855*I) + arccosh(2*v2 - (v2 + 0.841911550437 - 0.303757179824*I)/sinh_integral(pi) + arccoth(v3 + 0.530133230474 + 0.532140303485*I))))/v2 sage: random_expr(5, verbose=True) # random About to apply <built-in function inv> to [31] About to apply sgn to [v1] About to apply <built-in function add> to [1/31, sgn(v1)] sgn(v1) + 1/31 """ vars = [(1.0, SR.var('v%d' % (n + 1))) for n in range(nvars)] if ncoeffs is None: ncoeffs = size coeffs = [(1.0, coeff_generator()) for _ in range(ncoeffs)] leaves = [(var_frac, vars), (1.0 - var_frac - nullary_frac, coeffs), (nullary_frac, nullary)] leaves = normalize_prob_list(leaves) internal = normalize_prob_list(internal) return random_expr_helper(size, internal, leaves, verbose)
def test_issue_4023(): from sage.symbolic.ring import SR from sage.functions.all import log from sympy import integrate, simplify a,x = SR.var("a x") i = integrate(log(x)/a, (x, a, a + 1)) i2 = simplify(i) s = SR(i2) assert s == (a*log(1 + a) - a*log(a) + log(1 + a) - 1)/a
def _sympysage_symbol(self): """ EXAMPLES:: sage: from sympy import Symbol sage: assert x._sympy_() == Symbol('x') sage: assert x == Symbol('x')._sage_() """ from sage.symbolic.ring import SR return SR.var(self.name)
def check_expression(expr, var_symbols, only_from_sympy=False): """ Does ``eval(expr)`` both in Sage and SymPy and does other checks. EXAMPLES:: sage: from sage.interfaces.sympy import check_expression sage: check_expression("1.123*x", "x") """ from sage import __dict__ as sagedict from sage.symbolic.ring import SR from sympy import (__dict__ as sympydict, Basic, S, var as svar) # evaluate the expression in the context of Sage: if var_symbols: SR.var(var_symbols) is_different = False try: e_sage = SR(expr) assert not isinstance(e_sage, Basic) except (NameError, TypeError): is_different = True pass # evaluate the expression in the context of SymPy: if var_symbols: sympy_vars = svar(var_symbols) b = globals().copy() b.update(sympydict) assert "sin" in b b.update(sympydict) e_sympy = eval(expr, b) assert isinstance(e_sympy, Basic) # Sympy func may have specific _sage_ method if is_different: _sage_method = getattr(e_sympy.func, "_sage_") e_sage = _sage_method(S(e_sympy)) # Do the actual checks: if not only_from_sympy: assert S(e_sage) == e_sympy assert e_sage == SR(e_sympy)
def fricas_integrator(expression, v, a=None, b=None, noPole=True): """ Integration using FriCAS EXAMPLES:: sage: from sage.symbolic.integration.external import fricas_integrator # optional - fricas sage: fricas_integrator(sin(x), x) # optional - fricas -cos(x) sage: fricas_integrator(cos(x), x) # optional - fricas sin(x) sage: fricas_integrator(1/(x^2-2), x, 0, 1) # optional - fricas 1/4*sqrt(2)*(log(3*sqrt(2) - 4) - log(sqrt(2))) sage: fricas_integrator(1/(x^2+6), x, -oo, oo) # optional - fricas 1/6*sqrt(6)*pi """ if not isinstance(expression, Expression): expression = SR(expression) if a is None: result = expression._fricas_().integrate(v) else: import sage.rings.infinity if a == sage.rings.infinity.PlusInfinity(): a = "%plusInfinity" elif a == sage.rings.infinity.MinusInfinity(): a = "%minusInfinity" if b == sage.rings.infinity.PlusInfinity(): b = "%plusInfinity" elif b == sage.rings.infinity.MinusInfinity(): b = "%minusInfinity" if noPole: result = expression._fricas_().integrate("{}={}..{}".format(v, a, b), '"noPole"') else: result = expression._fricas_().integrate("{}={}..{}".format(v, a, b)) locals = {str(v): v for v in expression.variables()} if str(result) == "potentialPole": raise ValueError("The integrand has a potential pole" " in the integration interval") return result.sage()
def matrice_systeme(systeme, variables): """ Renvoie une matrice par block représentant un programme linéaire sous forme standard. INPUT:: - ``systeme`` -- Un programme linéaire sous forme standard - ``variables`` -- La liste des variables du système EXAMPLES:: sage: x = x1,x2,x3 = var('x1,x2,x3') sage: Chvatal13 = [[2*x1 + 3*x2 + x3 <= 5, ....: 4*x1 + x2 + 2*x3 <= 11, ....: 3*x1 + 4*x2 + 2*x3 <= 8], ....: 5*x1 + 4*x2 + 3*x3] sage: m = matrice_systeme(Chvatal13, x); m [ z|s1 s2 s3|x1 x2 x3| 0] [--+--------+--------+--] [ 1| 0 0 0|-5 -4 -3| 0] [--+--------+--------+--] [ 0| 1 0 0| 2 3 1| 5] [ 0| 0 1 0| 4 1 2|11] [ 0| 0 0 1| 3 4 2| 8] """ def liste_coeffs(expression): return [expression.coeff(v) for v in variables] inequations = systeme[0] m = matrix([liste_coeffs(ineq.lhs()) for ineq in inequations]) rhs = vector(ineq.rhs() for ineq in inequations).column() slack = SR.var(",".join("s%s" % i for i in range(1, len(inequations) + 1))) z = SR.var("z") return block_matrix( [ [z, matrix([slack]), matrix([variables]), ZZ(0)], [ZZ(1), ZZ(0), -matrix([liste_coeffs(systeme[1])]), ZZ(0)], [ZZ(0), ZZ(1), m, rhs], ] )
def fricas_integrator(expression, v, a=None, b=None): """ Integration using FriCAS EXAMPLES:: sage: from sage.symbolic.integration.external import fricas_integrator # optional - fricas sage: fricas_integrator(sin(x), x) # optional - fricas -cos(x) sage: fricas_integrator(cos(x), x) # optional - fricas sin(x) sage: fricas_integrator(1/(x^2-2), x, 0, 1) # optional - fricas 1/4*(log(3*sqrt(2) - 4) - log(sqrt(2)))*sqrt(2) sage: fricas_integrator(1/(x^2+6), x, -oo, oo) # optional - fricas 1/6*pi*sqrt(6) """ if not isinstance(expression, Expression): expression = SR(expression) if a is None: result = expression._fricas_().integrate(v) else: import sage.rings.infinity if a == sage.rings.infinity.PlusInfinity(): a = "%plusInfinity" elif a == sage.rings.infinity.MinusInfinity(): a = "%minusInfinity" if b == sage.rings.infinity.PlusInfinity(): b = "%plusInfinity" elif b == sage.rings.infinity.MinusInfinity(): b = "%minusInfinity" result = expression._fricas_().integrate("{}={}..{}".format(v, a, b)) locals = {str(v): v for v in expression.variables()} if str(result) == "potentialPole": raise ValueError("The integrand has a potential pole" " in the integration interval") parsed_result = result.unparsed_input_form() import sage.misc.sage_eval try: return sage.misc.sage_eval.sage_eval(parsed_result, locals=locals) except: raise ValueError("Unable to parse: {}".format(parsed_result))
def test_undefined_function(): from sage.symbolic.ring import SR from sage.calculus.var import function from sympy import Symbol, Function f = function('f') sf = Function('f') x,y = SR.var('x y') sx = Symbol('x') sy = Symbol('y') assert f(x)._sympy_() == sf(sx) assert f(x) == sf(sx)._sage_() assert f(x,y)._sympy_() == sf(sx, sy) assert f(x,y) == sf(sx, sy)._sage_() assert f._sympy_() == sf assert f == sf._sage_()
def weight_integrand(self, simplify_factor=True): """ Weight integrand as a rational function. The Jacobian determinant of some coordinate transformation. """ def arg(x,y): return arctan(y/x) # up to a constant, but it doesn't matter def phi(x,y,a,b): z = (a+I*b-x-I*y)*(a - I*b - x - I*y) w = z.real() q = z.imag() return arg(w,q).full_simplify() n = len(self.internal_vertices()) coordinates = lambda v: SR.var(chr(97+2*(v-1)) + ',' + chr(97+2*(v-1)+1)) \ if v in self.internal_vertices() else \ [(0,0), (1,0)][self.ground_vertices().index(v)] internal_coordinates = sum((list(coordinates(v)) for v in sorted(self.internal_vertices())), []) U = CoordinatePatch(internal_coordinates) F = DifferentialForms(U) psi = 0 two_forms = [] for v in self.internal_vertices(): x,y = coordinates(v) outgoing_edges = self.outgoing_edges([v]) left_target = filter(lambda (x, y, z): z == 'L', outgoing_edges)[0][1] right_target = filter(lambda (x, y, z): z == 'R', outgoing_edges)[0][1] one_forms = [] for target in [left_target, right_target]: a,b = coordinates(target) one_form = DifferentialForm(F, 1) for v in internal_coordinates: index = internal_coordinates.index(v) one_form[index] = phi(x,y,a,b).diff(v) if simplify_factor: one_form[index] = SR(one_form[index]).full_simplify() one_forms.append(one_form) two_form = one_forms[0]*one_forms[1] two_forms.append(two_form) import operator two_n_form = reduce(operator.mul, two_forms, 1) return two_n_form[range(0,2*n)]
def fourier_series_cosine_coefficient(cls, self, parameters, variable, n, L): r""" Returns the n-th Fourier series coefficient of `\cos(n\pi x/L)`, `a_n`. INPUT: - ``self`` - the function f(x), defined over -L x L - ``n`` - an integer n=0 - ``L`` - (the period)/2 OUTPUT: `a_n = \frac{1}{L}\int_{-L}^L f(x)\cos(n\pi x/L)dx` EXAMPLES:: sage: f(x) = x^2 sage: f = piecewise([[(-1,1),f]]) sage: f.fourier_series_cosine_coefficient(2,1) pi^(-2) sage: f(x) = x^2 sage: f = piecewise([[(-pi,pi),f]]) sage: f.fourier_series_cosine_coefficient(2,pi) 1 sage: f1(x) = -1 sage: f2(x) = 2 sage: f = piecewise([[(-pi,pi/2),f1],[(pi/2,pi),f2]]) sage: f.fourier_series_cosine_coefficient(5,pi) -3/5/pi """ from sage.all import cos, pi x = SR.var('x') result = 0 for domain, f in parameters: for interval in domain: a = interval.lower() b = interval.upper() result += (f*cos(pi*x*n/L)/L).integrate(x, a, b) return SR(result).simplify_trig()
def __init__(self, n, delta=0.01, m=None): """ Construct LWE instance parameterised by security parameter ``n`` where the modulus ``q`` and the ``stddev`` of the noise is chosen as in [LP2011]_. INPUT: - ``n`` - security parameter (integer > 0) - ``delta`` - error probability per symbol (default: 0.01) - ``m`` - number of allowed samples or ``None`` in which case ``m=2*n + 128`` as in [LP2011]_ (default: ``None``) EXAMPLES:: sage: from sage.crypto.lwe import LindnerPeikert sage: LindnerPeikert(n=20) LWE(20, 2053, Discrete Gaussian sampler over the Integers with sigma = 3.600954 and c = 0, 'noise', 168) """ if m is None: m = 2*n + 128 # Find c>=1 such that c*exp((1-c**2)/2))**(2*n) == 2**-40 # (c*exp((1-c**2)/2))**(2*n) == 2**-40 # log((c*exp((1-c**2)/2))**(2*n)) == -40*log(2) # (2*n)*log(c*exp((1-c**2)/2)) == -40*log(2) # 2*n*(log(c)+log(exp((1-c**2)/2))) == -40*log(2) # 2*n*(log(c)+(1-c**2)/2) == -40*log(2) # 2*n*log(c)+n*(1-c**2) == -40*log(2) # 2*n*log(c)+n*(1-c**2) + 40*log(2) == 0 c = SR.var('c') c = find_root(2*n*log(c)+n*(1-c**2) + 40*log(2) == 0, 1, 10) # Upper bound on s**2/t s_t_bound = (sqrt(2) * pi / c / sqrt(2*n*log(2/delta))).n() # Interpretation of "choose q just large enough to allow for a Gaussian parameter s>=8" in [LP2011]_ q = next_prime(floor(2**round(log(256 / s_t_bound, 2)))) # Gaussian parameter as defined in [LP2011]_ s = sqrt(s_t_bound*floor(q/4)) # Transform s into stddev stddev = s/sqrt(2*pi.n()) D = DiscreteGaussianDistributionIntegerSampler(stddev) LWE.__init__(self, n=n, q=q, D=D, secret_dist='noise', m=m)
def __call__(self, *args): """ EXAMPLES:: sage: from sage.symbolic.operators import FDerivativeOperator sage: x,y = var('x,y') sage: f = function('foo') sage: op = FDerivativeOperator(f, [0,1]) sage: op(x,y) diff(foo(x, y), x, y) sage: op(x,x^2) D[0, 1](foo)(x, x^2) TESTS: We should be able to operate on functions evaluated at a point, not just a symbolic variable, :trac:`12796`:: sage: from sage.symbolic.operators import FDerivativeOperator sage: f = function('f') sage: op = FDerivativeOperator(f, [0]) sage: op(1) D[0](f)(1) """ if (not all(is_SymbolicVariable(x) for x in args) or len(args) != len(set(args))): # An evaluated derivative of the form f'(1) is not a # symbolic variable, yet we would like to treat it # like one. So, we replace the argument `1` with a # temporary variable e.g. `t0` and then evaluate the # derivative f'(t0) symbolically at t0=1. See trac # #12796. temp_args=[SR.var("t%s"%i) for i in range(len(args))] vars=[temp_args[i] for i in self._parameter_set] return self._f(*temp_args).diff(*vars).function(*temp_args)(*args) vars = [args[i] for i in self._parameter_set] return self._f(*args).diff(*vars)
def __init__(self, N, delta=0.01, m=None): """ Construct a Ring-LWE oracle in dimension ``n=phi(N)`` where the modulus ``q`` and the ``stddev`` of the noise is chosen as in [LP2011]_. INPUT: - ``N`` - index of cyclotomic polynomial (integer > 0, must be power of 2) - ``delta`` - error probability per symbol (default: 0.01) - ``m`` - number of allowed samples or ``None`` in which case ``3*n`` is used (default: ``None``) EXAMPLES:: sage: from sage.crypto.lwe import RingLindnerPeikert sage: RingLindnerPeikert(N=16) RingLWE(16, 1031, Discrete Gaussian sampler for polynomials of degree < 8 with σ=2.803372 in each component, x^8 + 1, 'noise', 24) """ n = euler_phi(N) if m is None: m = 3*n # Find c>=1 such that c*exp((1-c**2)/2))**(2*n) == 2**-40 # i.e c>=1 such that 2*n*log(c)+n*(1-c**2) + 40*log(2) == 0 c = SR.var('c') c = find_root(2*n*log(c)+n*(1-c**2) + 40*log(2) == 0, 1, 10) # Upper bound on s**2/t s_t_bound = (sqrt(2) * pi / c / sqrt(2*n*log(2/delta))).n() # Interpretation of "choose q just large enough to allow for a Gaussian parameter s>=8" in [LP2011]_ q = next_prime(floor(2**round(log(256 / s_t_bound, 2)))) # Gaussian parameter as defined in [LP2011]_ s = sqrt(s_t_bound*floor(q/4)) # Transform s into stddev stddev = s/sqrt(2*pi.n()) D = DiscreteGaussianDistributionPolynomialSampler(ZZ['x'], n, stddev) RingLWE.__init__(self, N=N, q=q, D=D, poly=None, secret_dist='noise', m=m)
def __call__(cls, self, parameters, variable, value=None, **kwds): """ Call the piecewise function EXAMPLES:: sage: f = piecewise([([0,0], sin(x)), ((0,2), cos(x))]); f piecewise(x|-->sin(x) on {0}, x|-->cos(x) on (0, 2); x) sage: f(0) 0 sage: f(1) cos(1) sage: f(2) Traceback (most recent call last): ... ValueError: point 2 is not in the domain """ self = piecewise(parameters, var=variable) substitution = dict() for k, v in kwds.items(): substitution[SR.var(k)] = v if value is not None: substitution[variable] = value return self.subs(substitution)
def __call__(self, function_pieces, **kwds): r""" Piecewise functions INPUT: - ``function_pieces`` -- a list of pairs consisting of a domain and a symbolic function. - ``var=x`` -- a symbolic variable or ``None`` (default). The real variable in which the function is piecewise in. OUTPUT: A piecewise-defined function. A ``ValueError`` will be raised if the domains of the pieces are not pairwise disjoint. EXAMPLES:: sage: my_abs = piecewise([((-1, 0), -x), ([0, 1], x)], var=x); my_abs piecewise(x|-->-x on (-1, 0), x|-->x on [0, 1]; x) sage: [ my_abs(i/5) for i in range(-4, 5)] [4/5, 3/5, 2/5, 1/5, 0, 1/5, 2/5, 3/5, 4/5] TESTS:: sage: piecewise([([-1, 0], -x), ([0, 1], x)], var=x) Traceback (most recent call last): ... ValueError: domains must be pairwise disjoint sage: step = piecewise([((-1, 0), -1), ([0, 0], 0), ((0, 1), 1)], var=x); step piecewise(x|-->-1 on (-1, 0), x|-->0 on {0}, x|-->1 on (0, 1); x) sage: step(-1/2), step(0), step(1/2) (-1, 0, 1) """ from types import FunctionType var = kwds.pop('var', None) parameters = [] domain_list = [] for piece in function_pieces: domain, function = piece if not isinstance(domain, RealSet): domain = RealSet(domain) if domain.is_empty(): continue if isinstance(function, FunctionType): if var is None: var = SR.var('x') if function.func_code.co_argcount == 0: function = function() else: function = function(var) function = SR(function) if var is None and len(function.variables()) > 0: var = function.variables()[0] parameters.append((domain, function)) domain_list.append(domain) if not RealSet.are_pairwise_disjoint(*domain_list): raise ValueError('domains must be pairwise disjoint') if var is None: var = self.default_variable() parameters = SR._force_pyobject(tuple(parameters), recursive=False) return BuiltinFunction.__call__(self, parameters, var, **kwds)
def convolution(cls, self, parameters, variable, other): """ Return the convolution function, `f*g(t)=\int_{-\infty}^\infty f(u)g(t-u)du`, for compactly supported `f,g`. EXAMPLES:: sage: x = PolynomialRing(QQ,'x').gen() sage: f = piecewise([[[0,1],1]]) ## example 0 sage: g = f.convolution(f); g piecewise(x|-->x on (0, 1], x|-->-x + 2 on (1, 2]; x) sage: h = f.convolution(g); h piecewise(x|-->1/2*x^2 on (0, 1], x|-->-x^2 + 3*x - 3/2 on (1, 2], x|-->1/2*x^2 - 3*x + 9/2 on (2, 3]; x) sage: f = piecewise([[(0,1),1],[(1,2),2],[(2,3),1]]) ## example 1 sage: g = f.convolution(f) sage: h = f.convolution(g); h piecewise(x|-->1/2*x^2 on (0, 1], x|-->2*x^2 - 3*x + 3/2 on (1, 3], x|-->-2*x^2 + 21*x - 69/2 on (3, 4], x|-->-5*x^2 + 45*x - 165/2 on (4, 5], x|-->-2*x^2 + 15*x - 15/2 on (5, 6], x|-->2*x^2 - 33*x + 273/2 on (6, 8], x|-->1/2*x^2 - 9*x + 81/2 on (8, 9]; x) sage: f = piecewise([[(-1,1),1]]) ## example 2 sage: g = piecewise([[(0,3),x]]) sage: f.convolution(g) piecewise(x|-->1/2*x^2 + x + 1/2 on (-1, 1], x|-->2*x on (1, 2], x|-->-1/2*x^2 + x + 4 on (2, 4]; x) sage: g = piecewise([[(0,3),1],[(3,4),2]]) sage: f.convolution(g) piecewise(x|-->x + 1 on (-1, 1], x|-->2 on (1, 2], x|-->x on (2, 3], x|-->-x + 6 on (3, 4], x|-->-2*x + 10 on (4, 5]; x) Check that the bugs raised in :trac:`12123` are fixed:: sage: f = piecewise([[(-2, 2), 2]]) sage: g = piecewise([[(0, 2), 3/4]]) sage: f.convolution(g) piecewise(x|-->3/2*x + 3 on (-2, 0], x|-->3 on (0, 2], x|-->-3/2*x + 6 on (2, 4]; x) sage: f = piecewise([[(-1, 1), 1]]) sage: g = piecewise([[(0, 1), x], [(1, 2), -x + 2]]) sage: f.convolution(g) piecewise(x|-->1/2*x^2 + x + 1/2 on (-1, 0], x|-->-1/2*x^2 + x + 1/2 on (0, 2], x|-->1/2*x^2 - 3*x + 9/2 on (2, 3]; x) """ from sage.symbolic.integration.integral import definite_integral f = self g = other if len(f.end_points())*len(g.end_points()) == 0: raise ValueError('one of the piecewise functions is nowhere defined') M = min(min(f.end_points()),min(g.end_points())) N = max(max(f.end_points()),max(g.end_points())) tt = SR.var('tt') uu = SR.var('uu') conv = 0 fd,f0 = parameters[0] gd,g0 = next(other.items()) if len(f)==1 and len(g)==1: f = f.unextend_zero() g = g.unextend_zero() a1 = fd[0].lower() a2 = fd[0].upper() b1 = gd[0].lower() b2 = gd[0].upper() i1 = f0.subs({variable: uu}) i2 = g0.subs({variable: tt-uu}) fg1 = definite_integral(i1*i2, uu, a1, tt-b1).subs(tt = variable) fg2 = definite_integral(i1*i2, uu, tt-b2, tt-b1).subs(tt = variable) fg3 = definite_integral(i1*i2, uu, tt-b2, a2).subs(tt = variable) fg4 = definite_integral(i1*i2, uu, a1, a2).subs(tt = variable) if a1-b1<a2-b2: if a2+b1!=a1+b2: h = piecewise([[(a1+b1,a1+b2),fg1],[(a1+b2,a2+b1),fg2],[(a2+b1,a2+b2),fg3]]) else: h = piecewise([[(a1+b1,a1+b2),fg1],[(a1+b2,a2+b2),fg3]]) else: if a1+b2!=a2+b1: h = piecewise([[(a1+b1,a2+b1),fg1],[(a2+b1,a1+b2),fg4],[(a1+b2,a2+b2),fg3]]) else: h = piecewise([[(a1+b1,a2+b1),fg1],[(a2+b1,a2+b2),fg3]]) return (piecewise([[(minus_infinity,infinity),0]]).piecewise_add(h)).unextend_zero() if len(f)>1 or len(g)>1: z = piecewise([[(0,0),0]]) for fpiece in f.pieces(): for gpiece in g.pieces(): h = gpiece.convolution(fpiece) z = z.piecewise_add(h) return z.unextend_zero()
def airy_bi(alpha, x=None, hold_derivative=True, **kwds): r""" The Airy Bi function The Airy Bi function `\operatorname{Bi}(x)` is (along with `\operatorname{Ai}(x)`) one of the two linearly independent standard solutions to the Airy differential equation `f''(x) - x f(x) = 0`. It is defined by the initial conditions: .. MATH:: \operatorname{Bi}(0)=\frac{1}{3^{1/6} \Gamma\left(\frac{2}{3}\right)}, \operatorname{Bi}'(0)=\frac{3^{1/6}}{ \Gamma\left(\frac{1}{3}\right)}. Another way to define the Airy Bi function is: .. MATH:: \operatorname{Bi}(x)=\frac{1}{\pi}\int_0^\infty \left[ \exp\left( xt -\frac{t^3}{3} \right) +\sin\left(xt + \frac{1}{3}t^3\right) \right ] dt. INPUT: - ``alpha`` -- Return the `\alpha`-th order fractional derivative with respect to `z`. For `\alpha = n = 1,2,3,\ldots` this gives the derivative `\operatorname{Bi}^{(n)}(z)`, and for `\alpha = -n = -1,-2,-3,\ldots` this gives the `n`-fold iterated integral. .. MATH:: f_0(z) = \operatorname{Bi}(z) f_n(z) = \int_0^z f_{n-1}(t) dt - ``x`` -- The argument of the function - ``hold_derivative`` -- Whether or not to stop from returning higher derivatives in terms of `\operatorname{Bi}(x)` and `\operatorname{Bi}'(x)` .. SEEALSO:: :func:`airy_ai` EXAMPLES:: sage: n, x = var('n x') sage: airy_bi(x) airy_bi(x) It can return derivatives or integrals:: sage: airy_bi(2, x) airy_bi(2, x) sage: airy_bi(1, x, hold_derivative=False) airy_bi_prime(x) sage: airy_bi(2, x, hold_derivative=False) x*airy_bi(x) sage: airy_bi(-2, x, hold_derivative=False) airy_bi(-2, x) sage: airy_bi(n, x) airy_bi(n, x) It can be evaluated symbolically or numerically for real or complex values:: sage: airy_bi(0) 1/3*3^(5/6)/gamma(2/3) sage: airy_bi(0.0) 0.614926627446001 sage: airy_bi(I) airy_bi(I) sage: airy_bi(1.0*I) 0.648858208330395 + 0.344958634768048*I The functions can be evaluated numerically using mpmath, which can compute the values to arbitrary precision, and scipy:: sage: airy_bi(2).n(prec=100) 3.2980949999782147102806044252 sage: airy_bi(2).n(algorithm='mpmath', prec=100) 3.2980949999782147102806044252 sage: airy_bi(2).n(algorithm='scipy') # rel tol 1e-10 3.2980949999782134 And the derivatives can be evaluated:: sage: airy_bi(1, 0) 3^(1/6)/gamma(1/3) sage: airy_bi(1, 0.0) 0.448288357353826 Plots:: sage: plot(airy_bi(x), (x, -10, 5)) + plot(airy_bi_prime(x), ....: (x, -10, 5), color='red') Graphics object consisting of 2 graphics primitives **References** - Abramowitz, Milton; Stegun, Irene A., eds. (1965), "Chapter 10" - :wikipedia:`Airy_function` """ # We catch the case with no alpha if x is None: x = alpha return airy_bi_simple(x, **kwds) # We take care of all other cases. if not alpha in ZZ and not isinstance(alpha, Expression): return airy_bi_general(alpha, x, **kwds) if hold_derivative: return airy_bi_general(alpha, x, **kwds) elif alpha == 0: return airy_bi_simple(x, **kwds) elif alpha == 1: return airy_bi_prime(x, **kwds) elif alpha > 1: # We use a different variable here because if x is a # particular value, we would be differentiating a constant # which would return 0. What we want is the value of # the derivative at the value and not the derivative of # a particular value of the function. v = SR.symbol() return derivative(airy_bi_simple(v, **kwds), v, alpha).subs({v: x}) else: return airy_bi_general(alpha, x, **kwds)
def __call__(self, *args, **kwds): """ EXAMPLES:: sage: max_symbolic(3,5,x) max(x, 5) sage: max_symbolic(3,5,x, hold=True) max(3, 5, x) sage: max_symbolic([3,5,x]) max(x, 5) :: sage: min_symbolic(3,5,x) min(x, 3) sage: min_symbolic(3,5,x, hold=True) min(3, 5, x) sage: min_symbolic([3,5,x]) min(x, 3) TESTS: We get an exception if no arguments are given:: sage: max_symbolic() Traceback (most recent call last): ... ValueError: number of arguments must be > 0 Check if we return None, when the builtin function would:: sage: max_symbolic([None]) is None True sage: max_symbolic([None, None]) is None True sage: min_symbolic([None]) is None True sage: min_symbolic([None, None]) is None True Check if a single argument which is not iterable works:: sage: max_symbolic(None) Traceback (most recent call last): ... TypeError: 'NoneType' object is not iterable sage: max_symbolic(5) Traceback (most recent call last): ... TypeError: 'sage.rings.integer.Integer' object is not iterable sage: max_symbolic(x) Traceback (most recent call last): ... TypeError: 'sage.symbolic.expression.Expression' object is not iterable sage: min_symbolic(5) Traceback (most recent call last): ... TypeError: 'sage.rings.integer.Integer' object is not iterable sage: min_symbolic(x) Traceback (most recent call last): ... TypeError: 'sage.symbolic.expression.Expression' object is not iterable """ if len(args) == 0: raise ValueError("number of arguments must be > 0") if len(args) == 1: try: args=(SR._force_pyobject(iter(args[0])),) except TypeError as e: raise e try: return BuiltinFunction.__call__(self, *args, **kwds) except ValueError as e: if e.args[0] == "return None": return None
def simplify_sqrt_real(expr): r""" Simplify ``sqrt`` in symbolic expressions in the real domain. EXAMPLES: Simplifications of basic expressions:: sage: from sage.manifolds.utilities import simplify_sqrt_real sage: simplify_sqrt_real( sqrt(x^2) ) abs(x) sage: assume(x<0) sage: simplify_sqrt_real( sqrt(x^2) ) -x sage: simplify_sqrt_real( sqrt(x^2-2*x+1) ) -x + 1 sage: simplify_sqrt_real( sqrt(x^2) + sqrt(x^2-2*x+1) ) -2*x + 1 This improves over Sage's :meth:`~sage.symbolic.expression.Expression.canonicalize_radical`, which yields incorrect results when ``x < 0``:: sage: forget() # removes the assumption x<0 sage: sqrt(x^2).canonicalize_radical() x sage: assume(x<0) sage: sqrt(x^2).canonicalize_radical() # wrong output x sage: sqrt(x^2-2*x+1).canonicalize_radical() # wrong output x - 1 sage: ( sqrt(x^2) + sqrt(x^2-2*x+1) ).canonicalize_radical() # wrong output 2*x - 1 Simplification of nested ``sqrt``'s:: sage: forget() # removes the assumption x<0 sage: simplify_sqrt_real( sqrt(1 + sqrt(x^2)) ) sqrt(abs(x) + 1) sage: assume(x<0) sage: simplify_sqrt_real( sqrt(1 + sqrt(x^2)) ) sqrt(-x + 1) sage: simplify_sqrt_real( sqrt(x^2 + sqrt(4*x^2) + 1) ) -x + 1 Again, :meth:`~sage.symbolic.expression.Expression.canonicalize_radical` fails on the last one:: sage: (sqrt(x^2 + sqrt(4*x^2) + 1)).canonicalize_radical() # wrong output x + 1 """ from sage.symbolic.ring import SR from sage.functions.other import sqrt # 1/ Search for the sqrt's in expr sexpr = str(expr) if 'sqrt(' not in sexpr: # no sqrt to simplify return expr if 'D[' in sexpr: return expr #!# the code below is not capable of simplifying # expressions with symbolic derivatives denoted by Pynac # symbols of the type D[0] # Lists to store the positions of all the top-level sqrt's in sexpr: pos_sqrts = [] # position of first character, i.e. 's' of 'sqrt(...)' pos_after = [] # position of character immediatelty after 'sqrt(...)' the_sqrts = [] # the sqrt sub-expressions in sexpr, i.e. 'sqrt(...)' pos_max = len(sexpr) - 6 pos = 0 while pos < pos_max: if sexpr[pos:pos+5] == 'sqrt(': pos_sqrts.append(pos) parenth = 1 scan = pos+5 while parenth != 0: if sexpr[scan] == '(': parenth += 1 if sexpr[scan] == ')': parenth -= 1 scan += 1 the_sqrts.append( sexpr[pos:scan] ) pos_after.append(scan) pos = scan else: pos += 1 # 2/ Search for sub-sqrt's: for i in range(len(the_sqrts)): argum = the_sqrts[i][5:-1] # the sqrt argument if 'sqrt(' in argum: simpl = simplify_sqrt_real(SR(argum)) the_sqrts[i] = 'sqrt(' + str(simpl) + ')' # 3/ Simplifications of the sqrt's new_expr = "" # will contain the result pos0 = 0 for i, pos in enumerate(pos_sqrts): # radcan is called on each sqrt: x = SR(the_sqrts[i]) argum = x.operands()[0] # the argument of sqrt den = argum.denominator() if not (den == 1): # the argument of sqrt is a fraction # NB: after #19312 (integrated in Sage 6.10.beta7), the above # cannot be written as # if den != 1!: num = argum.numerator() if num < 0 or den < 0: x = sqrt(-num) / sqrt(-den) # new equivalent expression for x simpl = SR(x._maxima_().radcan()) if str(simpl)[:5] == 'sqrt(' or str(simpl)[:7] == '1/sqrt(': # no further simplification seems possible: ssimpl = str(simpl) else: # the absolute value of radcan's output is taken, the call to # simplify() taking into account possible assumptions regarding the # sign of simpl: ssimpl = str(abs(simpl).simplify()) # search for abs(1/sqrt(...)) term to simplify it into 1/sqrt(...): pstart = ssimpl.find('abs(1/sqrt(') if pstart != -1: ssimpl = ssimpl[:pstart] + ssimpl[pstart+3:] # getting rid of 'abs' new_expr += sexpr[pos0:pos] + '(' + ssimpl + ')' pos0 = pos_after[i] new_expr += sexpr[pos0:] return SR(new_expr)
def bezier3d(path, **options): """ Draw a 3-dimensional bezier path. Input is similar to bezier_path, but each point in the path and each control point is required to have 3 coordinates. INPUT: - ``path`` -- a list of curves, which each is a list of points. See further detail below. - ``thickness`` -- (default: 2) - ``color`` -- a string (``"red"``, ``"green"`` etc) or a tuple (r, g, b) with r, g, b numbers between 0 and 1 - ``opacity`` -- (default: 1) if less than 1 then is transparent - ``aspect_ratio`` -- (default:[1,1,1]) The path is a list of curves, and each curve is a list of points. Each point is a tuple (x,y,z). The first curve contains the endpoints as the first and last point in the list. All other curves assume a starting point given by the last entry in the preceding list, and take the last point in the list as their opposite endpoint. A curve can have 0, 1 or 2 control points listed between the endpoints. In the input example for path below, the first and second curves have 2 control points, the third has one, and the fourth has no control points:: path = [[p1, c1, c2, p2], [c3, c4, p3], [c5, p4], [p5], ...] In the case of no control points, a straight line will be drawn between the two endpoints. If one control point is supplied, then the curve at each of the endpoints will be tangent to the line from that endpoint to the control point. Similarly, in the case of two control points, at each endpoint the curve will be tangent to the line connecting that endpoint with the control point immediately after or immediately preceding it in the list. So in our example above, the curve between p1 and p2 is tangent to the line through p1 and c1 at p1, and tangent to the line through p2 and c2 at p2. Similarly, the curve between p2 and p3 is tangent to line(p2,c3) at p2 and tangent to line(p3,c4) at p3. Curve(p3,p4) is tangent to line(p3,c5) at p3 and tangent to line(p4,c5) at p4. Curve(p4,p5) is a straight line. EXAMPLES:: sage: path = [[(0,0,0),(.5,.1,.2),(.75,3,-1),(1,1,0)],[(.5,1,.2),(1,.5,0)],[(.7,.2,.5)]] sage: b = bezier3d(path, color='green') sage: b Graphics3d Object To construct a simple curve, create a list containing a single list:: sage: path = [[(0,0,0),(1,0,0),(0,1,0),(0,1,1)]] sage: curve = bezier3d(path, thickness=5, color='blue') sage: curve Graphics3d Object """ from . import parametric_plot3d as P3D from sage.modules.free_module_element import vector from sage.symbolic.ring import SR p0 = vector(path[0][-1]) t = SR.var('t') if len(path[0]) > 2: B = (1-t)**3*vector(path[0][0])+3*t*(1-t)**2*vector(path[0][1])+3*t**2*(1-t)*vector(path[0][-2])+t**3*p0 G = P3D.parametric_plot3d(list(B), (0, 1), color=options['color'], aspect_ratio=options['aspect_ratio'], thickness=options['thickness'], opacity=options['opacity']) else: G = line3d([path[0][0], p0], color=options['color'], thickness=options['thickness'], opacity=options['opacity']) for curve in path[1:]: if len(curve) > 1: p1 = vector(curve[0]) p2 = vector(curve[-2]) p3 = vector(curve[-1]) B = (1-t)**3*p0+3*t*(1-t)**2*p1+3*t**2*(1-t)*p2+t**3*p3 G += P3D.parametric_plot3d(list(B), (0, 1), color=options['color'], aspect_ratio=options['aspect_ratio'], thickness=options['thickness'], opacity=options['opacity']) else: G += line3d([p0,curve[0]], color=options['color'], thickness=options['thickness'], opacity=options['opacity']) p0 = curve[-1] return G
def inverse(self, chartname1=None, chartname2=None): r""" Returns the inverse diffeomorphism. INPUT: - ``chartname1`` -- (default: None) string defining the chart in which the computation of the inverse is performed; if none is provided, the default chart of self.manifold1 will be used - ``chartname2`` -- (default: None) string defining the chart in which the computation of the inverse is performed; if none is provided, the default chart of self.manifold2 will be used OUTPUT: - the inverse diffeomorphism EXAMPLES: The inverse of a rotation in the plane:: sage: m = Manifold(2, "plane") sage: c_cart = Chart(m, 'x y', 'cart') sage: # A pi/3 rotation around the origin: sage: rot = Diffeomorphism(m, m, ((x - sqrt(3)*y)/2, (sqrt(3)*x + y)/2)) sage: p = Point(m,(1,2)) sage: q = rot(p) sage: irot = rot.inverse() sage: p1 = irot(q) sage: p1 == p True """ from sage.symbolic.ring import SR from sage.symbolic.relation import solve from utilities import simplify_chain if self._inverse is not None: return self._inverse if chartname1 is None: chartname1 = self.manifold1.def_chart.name if chartname2 is None: chartname2 = self.manifold2.def_chart.name coord_map = self.coord_expression[(chartname1, chartname2)] chart1 = self.manifold1.atlas[chartname1] chart2 = self.manifold2.atlas[chartname2] n1 = len(chart1.xx) n2 = len(chart2.xx) # New symbolic variables (different from chart2.xx to allow for a # correct solution even when chart2 = chart1): x2 = [ SR.var('xxxx' + str(i)) for i in range(n2) ] equations = [x2[i] == coord_map.functions[i] for i in range(n2) ] solutions = solve(equations, chart1.xx, solution_dict=True) if len(solutions) == 0: raise ValueError("No solution found") if len(solutions) > 1: raise ValueError("Non-unique solution found") #!# This should be the Python 2.7 form: # substitutions = {x2[i]: chart2.xx[i] for i in range(n2)} # # Here we use a form compatible with Python 2.6: substitutions = dict([(x2[i], chart2.xx[i]) for i in range(n2)]) inv_functions = [solutions[0][chart1.xx[i]].subs(substitutions) for i in range(n1)] for i in range(n1): x = inv_functions[i] try: inv_functions[i] = simplify_chain(x) except AttributeError: pass self._inverse = Diffeomorphism(self.manifold2, self.manifold1, inv_functions, chartname2, chartname1) return self._inverse