Attachment 'symbolic_vs_numeric.rst'
DownloadSymbolic vs numerics in Sage
Parent and element
When using Sage, it is important to understand where your objects live. Or more mathematically in which structure they belong to. The number 1 as an integer will behave differently as the number 1 as a rational number...
In Sage this ambient space is called parent:
sage: a = 4 sage: parent(a) sage: a = 2/3 sage: parent(a) sage: a = 2.5 sage: parent(a) sage: a = pi sage: parent(pi)
The parent determines the behavior of many operations:
sage: x = SR.var('x') sage: p = 12*x^2 + 12*x + 24 sage: print parent(p) sage: print p.factor() sage: x = polygen(ZZ) sage: p = 12*x^2 + 12*x + 24 sage: print parent(p) sage: print p.factor() sage: x = polygen(QQ) sage: p = 12*x^2 + 12*x + 24 sage: print parent(p) sage: print p.factor() sage: x = polygen(QQbar) sage: p = 12*x^2 + 12*x + 24 sage: print parent(p) sage: print p.factor()
Even for real numbers there is a huge variety of them
- exact numbers (integer, rational, algebraic numbers)
- floating point numbers (real or complex)
- intervals and balls (real or complex)
- symbolic (the "big garbage")
Floating point numbers are inexact by nature... it is particularly dangerous in an unstable situation. They should be used with a lot of care.
Exercise 1: stability matters
Look at the following four cells and try to guess what will be the output before executing them.:
sage: x0 = 1/3 sage: print 4*x0 - 1 == x0 sage: x = x0 sage: for i in range(100): ....: x = 4*x - 1 sage: print x sage: x0 = RR(1/3) sage: print 4*x0 - 1 == x0 sage: x = x0 sage: for i in range(100): ....: x = 4*x - 1 sage: print x sage: #edit
Exercise 2: parent matters
Compare the following two cells. Which computations is the most accurate? the fastest?:
sage: a = sqrt(2) + sqrt(3) + sqrt(5) + sqrt(7) - 6 sage: for i in range(8): ....: a = a^4 - 4*a^3 + 4*a^2 sage: print a.numerical_approx() sage: a = sqrt(2.) + sqrt(3.) + sqrt(5.) + sqrt(7.) - 6 sage: for i in range(8): ....: a = a^4 - 4*a^3 + 4*a^2 sage: print a.numerical_approx() sage: #edit
In both cases, add some code to see what is the parent of a.
Coercion
Coercion is what happens when you mix numbers (or more generally objects) of different kinds.
For example the addition of an integer and a rational will be a rational:
sage: parent(5 + 2/3)
But what about:
- the addition of a rational with a polynomial with integer coefficients?
- division of two integers?
- division of two polynomials?
sage: # edit sage: # edit sage: # edit
Interval and ball arithmetic
Interval and balls are two kinds of floating point arithmetic that take care of error propagation. These types correspond to pairs of floating point numbers that represent respectively:
- the left and right endpoints of an interval
- the center and the radius of a ball
The parents are RIF (for real interval field) and RBF (for real ball field):
sage: RIF(sqrt(2)) sage: RBF(sqrt(2))
The arithmetic is done in such way that for any operation f(X) applied to an interval or a ball X contains all of {f(x): x in X}:
sage: a = RIF(1/2,1) # the interval [1/2,1] sage: print a.endpoints() sage: b = a^2 sage: print b.endpoints() sage: a = RBF(RIF(1/2,1)) # the same seen as a ball sage: print a.endpoints() sage: b = a^2 sage: print b.endpoints()
You can prove theorems using balls or intervals (which is much harder using floating point)!
You can apply most of standard functions on intervals and balls:
sage: a = RIF(1/3) sage: print a.cos() sage: print a.tan() sage: # etc
Exercise:
Find an example of a singleton interval X = [x,x] and a function f where the f(X) is not a singleton:
sage: # edit sage: # edit sage: # edit
Precision
Most floating point parents admit a precision attribute:
sage: R = RealField(64) sage: R(1/3) sage: R = RealField(256) sage: R(1/3) sage: R = RealIntervalField(64) sage: R(1/3) sage: R = RealIntervalField(256) sage: R(1/3)
Playing with algebraic numbers
Since sage-7.1 it is possible to work with embedded number fields in the set of real numbers:
sage: R.<x> = PolynomialRing(ZZ) sage: K.<cbrt2> = NumberField(x^3 - 2, embedding=AA(2)**(1/3)) sage: 1 < cbrt2 < 2 sage: continued_fraction(cbrt2)
These numbers are exact by nature, but comparing them can lead to expensive computations. Moreover the complexity of addition/multiplication increase (linearly) with the degree of the number field.
Integrating Abelian differentials
In this section, you are invited to play with Abelian differential in the complex plane. The aim is to:
- compute holonomy of paths $$ int_gamma f(x) dx = int_0^1 f(gamma(t)) gamma'(t) dt.$$
- integrate $f(x) dx$ in other words find numerica solutions to the one parameter family of ODEs $$f left(gamma(t) right)gamma'(t) = e^{i theta}.$$
Two basic functions in Sage to perform this task are:
- numerical_integral
- ode_solver
sage: class DifferentialCaller: ....: def __init__(self, f): ....: vars = f.variables() ....: assert len(vars) == 1 ....: var = vars[0] ....: ....: x = SR.var('x') ....: y = SR.var('y') ....: theta = SR.var('theta') ....: I = SR('I') ....: g = exp(I * theta) / f(x + I*y) ....: g1 = g.real() ....: self.g1 = fast_callable(g1, vars=[x,y,theta], domain=float) ....: g2 = g.imag() ....: self.g2 = fast_callable(g2, vars=[x,y,theta], domain=float) ....: dF = exp(I * theta) * f.derivative(var)(x + I*y) / (f(x+I*y) * f(x+I*y)) ....: dF = dF.full_simplify() ....: print dF ....: self.dg1x = fast_callable(dF.real(), vars=[x,y,theta], domain=float) ....: self.dg1y = fast_callable((I * dF).real(), vars=[x,y,theta], domain=float) ....: self.dg2x = fast_callable(dF.imag(), vars=[x,y,theta], domain=float) ....: self.dg2y = fast_callable((I * dF).imag(), vars=[x,y,theta], domain=float) ....: def function(self, t, z, params): ....: return (self.g1(z[0], z[1], params[0]), self.g2(z[0], z[1], params[0])) ....: ....: def jacobian(self, t, z, params): ....: return ((self.dg1x(z[0], z[1], params[0]), self.dg2x(z[0],z[1],params[0])), ....: (self.dg1y(z[0], z[1], params[0]), self.dg2y(z[0],z[1],params[0]))) sage: f(z) = exp(1/z) sage: D = DifferentialCaller(f) -e^(I*theta - 1/(x + I*y))/(x^2 + 2*I*x*y - y^2) sage: T = ode_solver() sage: T.function = D.function sage: #T.jacobian = D.jacobian sage: G = Graphics() sage: Z0 = [(-1,0.3)] sage: theta_step = 0.5 sage: for z0 in Z0: ....: theta = 0.0 ....: while theta < 2*RR.pi()+theta_step/2: ....: T.ode_solve(y_0=z0, t_span=[0,1], params=[theta], num_points=100) ....: G += line2d([z for t,z in T.solution], color='blue') ....: theta += theta_step sage: G.show()
Attached Files
To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.You are not allowed to attach a file to this page.