def Torus(r=2, R=3, name="Torus"): r""" Returns a torus obtained by revolving a circle of radius ``r`` around a coplanar axis ``R`` units away from the center of the circle. The parametrization used is .. MATH:: \begin{aligned} x(u, v) & = (R + r \cos(v)) \cos(u); \\ y(u, v) & = (R + r \cos(v)) \sin(u); \\ z(u, v) & = r \sin(v). \end{aligned} INPUT: - ``r``, ``R`` -- Minor and major radius of the torus. - ``name`` -- string. Name of the surface. EXAMPLES:: sage: torus = surfaces.Torus(); torus Parametrized surface ('Torus') with equation ((2*cos(v) + 3)*cos(u), (2*cos(v) + 3)*sin(u), 2*sin(v)) sage: torus.plot() Graphics3d Object """ u, v = var("u, v") torus_eq = [(R + r * cos(v)) * cos(u), (R + r * cos(v)) * sin(u), r * sin(v)] coords = ((u, 0, 2 * pi), (v, 0, 2 * pi)) return ParametrizedSurface3D(torus_eq, coords, name)
def Klein(r=1, name="Klein bottle"): r""" Returns the Klein bottle, in the figure-8 parametrization given by .. MATH:: \begin{aligned} x(u, v) & = (r + \cos(u/2)\cos(v) - \sin(u/2)\sin(2v)) \cos(u); \\ y(u, v) & = (r + \cos(u/2)\cos(v) - \sin(u/2)\sin(2v)) \sin(u); \\ z(u, v) & = \sin(u/2)\cos(v) + \cos(u/2)\sin(2v). \end{aligned} INPUT: - ``r`` -- radius of the "figure-8" circle. - ``name`` -- string. Name of the surface. EXAMPLES:: sage: klein = surfaces.Klein(); klein Parametrized surface ('Klein bottle') with equation (-(sin(1/2*u)*sin(2*v) - cos(1/2*u)*sin(v) - 1)*cos(u), -(sin(1/2*u)*sin(2*v) - cos(1/2*u)*sin(v) - 1)*sin(u), cos(1/2*u)*sin(2*v) + sin(1/2*u)*sin(v)) sage: klein.plot() Graphics3d Object """ u, v = var("u, v") x = (r + cos(u / 2) * sin(v) - sin(u / 2) * sin(2 * v)) * cos(u) y = (r + cos(u / 2) * sin(v) - sin(u / 2) * sin(2 * v)) * sin(u) z = sin(u / 2) * sin(v) + cos(u / 2) * sin(2 * v) klein_eq = [x, y, z] coords = ((u, 0, 2 * pi), (v, 0, 2 * pi)) return ParametrizedSurface3D(klein_eq, coords, name)
def Crosscap(r=1, name="Crosscap"): r""" Returns a crosscap surface, with parametrization .. MATH:: \begin{aligned} x(u, v) & = r(1 + \cos(v)) \cos(u); \\ y(u, v) & = r(1 + \cos(v)) \sin(u); \\ z(u, v) & = - r\tanh(u - \pi) \sin(v). \end{aligned} INPUT: - ``r`` -- surface parameter. - ``name`` -- string. Name of the surface. EXAMPLES:: sage: crosscap = surfaces.Crosscap(); crosscap Parametrized surface ('Crosscap') with equation ((cos(v) + 1)*cos(u), (cos(v) + 1)*sin(u), -sin(v)*tanh(-pi + u)) sage: crosscap.plot() """ u, v = var('u, v') crosscap_eq = [r*(1+cos(v))*cos(u), r*(1+cos(v))*sin(u), -tanh(u-pi)*r*sin(v)] coords = ((u, 0, 2*pi), (v, 0, 2*pi)) return ParametrizedSurface3D(crosscap_eq, coords, name)
def Dini(a=1, b=1, name="Dini's surface"): r""" Returns Dini's surface, with parametrization .. MATH:: \begin{aligned} x(u, v) & = a \cos(u)\sin(v); \\ y(u, v) & = a \sin(u)\sin(v); \\ z(u, v) & = u + \log(\tan(v/2)) + \cos(v). \end{aligned} INPUT: - ``a, b`` -- surface parameters. - ``name`` -- string. Name of the surface. EXAMPLES:: sage: dini = surfaces.Dini(a=3, b=4); dini Parametrized surface ('Dini's surface') with equation (3*cos(u)*sin(v), 3*sin(u)*sin(v), 4*u + 3*cos(v) + 3*log(tan(1/2*v))) sage: dini.plot() # not tested -- known bug (see #10132) """ u, v = var("u, v") dini_eq = [a * cos(u) * sin(v), a * sin(u) * sin(v), a * (cos(v) + log(tan(v / 2))) + b * u] coords = ((u, 0, 2 * pi), (v, 0, 2 * pi)) return ParametrizedSurface3D(dini_eq, coords, name)
def Crosscap(r=1, name="Crosscap"): r""" Return a crosscap surface, with parametrization .. MATH:: \begin{aligned} x(u, v) & = r(1 + \cos(v)) \cos(u); \\ y(u, v) & = r(1 + \cos(v)) \sin(u); \\ z(u, v) & = - r\tanh(u - \pi) \sin(v). \end{aligned} INPUT: - ``r`` -- surface parameter. - ``name`` -- string. Name of the surface. For more information, see :wikipedia:`Cross-cap`. EXAMPLES:: sage: crosscap = surfaces.Crosscap(); crosscap Parametrized surface ('Crosscap') with equation ((cos(v) + 1)*cos(u), (cos(v) + 1)*sin(u), -sin(v)*tanh(-pi + u)) sage: crosscap.plot() Graphics3d Object """ u, v = var('u, v') crosscap_eq = [ r * (1 + cos(v)) * cos(u), r * (1 + cos(v)) * sin(u), -tanh(u - pi) * r * sin(v) ] coords = ((u, 0, 2 * pi), (v, 0, 2 * pi)) return ParametrizedSurface3D(crosscap_eq, coords, name)
def Dini(a=1, b=1, name="Dini's surface"): r""" Return Dini's surface, with parametrization .. MATH:: \begin{aligned} x(u, v) & = a \cos(u)\sin(v); \\ y(u, v) & = a \sin(u)\sin(v); \\ z(u, v) & = u + \log(\tan(v/2)) + \cos(v). \end{aligned} INPUT: - ``a, b`` -- surface parameters. - ``name`` -- string. Name of the surface. For more information, see :wikipedia:`Dini%27s_surface`. EXAMPLES:: sage: dini = surfaces.Dini(a=3, b=4); dini Parametrized surface ('Dini's surface') with equation (3*cos(u)*sin(v), 3*sin(u)*sin(v), 4*u + 3*cos(v) + 3*log(tan(1/2*v))) sage: dini.plot() Graphics3d Object """ u, v = var('u, v') dini_eq = [ a * cos(u) * sin(v), a * sin(u) * sin(v), a * (cos(v) + log(tan(v / 2))) + b * u ] coords = ((u, 0, 2 * pi), (v, 0, 2 * pi)) return ParametrizedSurface3D(dini_eq, coords, name)
def evaluate_L(self, affine_parameter, solution_key=None): r""" Compute the conserved angular momentum about the rotation axis `L` at a given value of the affine parameter `\lambda`. INPUT: - ``affine_parameter`` -- value of the affine parameter `\lambda` - ``solution_key`` -- (default: ``None``) string denoting the numerical solution to use for the evaluation; if ``None``, the latest solution computed by :meth:`integrate` is used. OUTPUT: - value of `L` """ p = self.evaluate_tangent_vector(affine_parameter, solution_key=solution_key) point = p.parent().base_point() BLchart = self._spacetime.boyer_lindquist_coordinates() r, th = BLchart(point)[1:3] a, m = self._a, self._m r2 = r**2 a2 = a**2 rho2 = r2 + (a * cos(th))**2 p_comp = p.components(basis=BLchart.frame().at(point)) pt = p_comp[0] pph = p_comp[3] bs = 2 * a * m * r * sin(th)**2 / rho2 L = -bs * pt + (r2 + a2 + a * bs) * sin(th)**2 * pph return L.substitute(self._numerical_substitutions())
def Torus(r=2, R=3, name="Torus"): r""" Return a torus obtained by revolving a circle of radius ``r`` around a coplanar axis ``R`` units away from the center of the circle. The parametrization used is .. MATH:: \begin{aligned} x(u, v) & = (R + r \cos(v)) \cos(u); \\ y(u, v) & = (R + r \cos(v)) \sin(u); \\ z(u, v) & = r \sin(v). \end{aligned} INPUT: - ``r``, ``R`` -- Minor and major radius of the torus. - ``name`` -- string. Name of the surface. For more information, see :wikipedia:`Torus`. EXAMPLES:: sage: torus = surfaces.Torus(); torus Parametrized surface ('Torus') with equation ((2*cos(v) + 3)*cos(u), (2*cos(v) + 3)*sin(u), 2*sin(v)) sage: torus.plot() Graphics3d Object """ u, v = var('u, v') torus_eq = [(R + r * cos(v)) * cos(u), (R + r * cos(v)) * sin(u), r * sin(v)] coords = ((u, 0, 2 * pi), (v, 0, 2 * pi)) return ParametrizedSurface3D(torus_eq, coords, name)
def Dini(a=1, b=1, name="Dini's surface"): r""" Returns Dini's surface, with parametrization .. MATH:: \begin{aligned} x(u, v) & = a \cos(u)\sin(v); \\ y(u, v) & = a \sin(u)\sin(v); \\ z(u, v) & = u + \log(\tan(v/2)) + \cos(v). \end{aligned} INPUT: - ``a, b`` -- surface parameters. - ``name`` -- string. Name of the surface. EXAMPLES:: sage: dini = surfaces.Dini(a=3, b=4); dini Parametrized surface ('Dini's surface') with equation (3*cos(u)*sin(v), 3*sin(u)*sin(v), 4*u + 3*cos(v) + 3*log(tan(1/2*v))) sage: dini.plot() # not tested -- known bug (see #10132) """ u, v = var('u, v') dini_eq = [a*cos(u)*sin(v), a*sin(u)*sin(v), a*(cos(v) + log(tan(v/2))) + b*u] coords = ((u, 0, 2*pi), (v, 0, 2*pi)) return ParametrizedSurface3D(dini_eq, coords, name)
def Klein(r=1, name="Klein bottle"): r""" Return the Klein bottle, in the figure-8 parametrization given by .. MATH:: \begin{aligned} x(u, v) & = (r + \cos(u/2)\cos(v) - \sin(u/2)\sin(2v)) \cos(u); \\ y(u, v) & = (r + \cos(u/2)\cos(v) - \sin(u/2)\sin(2v)) \sin(u); \\ z(u, v) & = \sin(u/2)\cos(v) + \cos(u/2)\sin(2v). \end{aligned} INPUT: - ``r`` -- radius of the "figure-8" circle. - ``name`` -- string. Name of the surface. For more information, see :wikipedia:`Klein_bottle`. EXAMPLES:: sage: klein = surfaces.Klein(); klein Parametrized surface ('Klein bottle') with equation (-(sin(1/2*u)*sin(2*v) - cos(1/2*u)*sin(v) - 1)*cos(u), -(sin(1/2*u)*sin(2*v) - cos(1/2*u)*sin(v) - 1)*sin(u), cos(1/2*u)*sin(2*v) + sin(1/2*u)*sin(v)) sage: klein.plot() Graphics3d Object """ u, v = var('u, v') x = (r + cos(u / 2) * sin(v) - sin(u / 2) * sin(2 * v)) * cos(u) y = (r + cos(u / 2) * sin(v) - sin(u / 2) * sin(2 * v)) * sin(u) z = sin(u / 2) * sin(v) + cos(u / 2) * sin(2 * v) klein_eq = [x, y, z] coords = ((u, 0, 2 * pi), (v, 0, 2 * pi)) return ParametrizedSurface3D(klein_eq, coords, name)
def plot_arc(radius, p, q, **opts): # TODO: THIS SHOULD USE THE EXISTING PLOT OF ARCS! # plot the arc from p to q differently depending on the type of self p = ZZ(p) q = ZZ(q) t = var('t') if p - q in [1, -1]: def f(t): return (radius * cos(t), radius * sin(t)) (p, q) = sorted([p, q]) angle_p = vertex_to_angle(p) angle_q = vertex_to_angle(q) return parametric_plot(f(t), (t, angle_q, angle_p), **opts) if self.type() == 'A': angle_p = vertex_to_angle(p) angle_q = vertex_to_angle(q) if angle_p < angle_q: angle_p += 2 * pi internal_angle = angle_p - angle_q if internal_angle > pi: (angle_p, angle_q) = (angle_q + 2 * pi, angle_p) internal_angle = angle_p - angle_q angle_center = (angle_p + angle_q) / 2 hypotenuse = radius / cos(internal_angle / 2) radius_arc = hypotenuse * sin(internal_angle / 2) center = (hypotenuse * cos(angle_center), hypotenuse * sin(angle_center)) center_angle_p = angle_p + pi / 2 center_angle_q = angle_q + 3 * pi / 2 def f(t): return (radius_arc * cos(t) + center[0], radius_arc * sin(t) + center[1]) return parametric_plot(f(t), (t, center_angle_p, center_angle_q), **opts) elif self.type() == 'D': if p >= q: q += self.r() px = -2 * pi * p / self.r() + pi / 2 qx = -2 * pi * q / self.r() + pi / 2 arc_radius = (px - qx) / 2 arc_center = qx + arc_radius def f(t): return exp(I * ((cos(t) + I * sin(t)) * arc_radius + arc_center)) * radius return parametric_plot((real_part(f(t)), imag_part(f(t))), (t, 0, pi), **opts)
def show(self, boundary=True, **options): r""" Plot ``self``. EXAMPLES:: sage: HyperbolicPlane().PD().get_geodesic(0, 1).show() Graphics object consisting of 2 graphics primitives """ opts = dict([('axes', False), ('aspect_ratio', 1)]) opts.update(self.graphics_options()) opts.update(options) end_1, end_2 = [CC(k.coordinates()) for k in self.endpoints()] bd_1, bd_2 = [CC(k.coordinates()) for k in self.ideal_endpoints()] # Check to see if it's a line if bool(real(bd_1)*imag(bd_2) - real(bd_2)*imag(bd_1))**2 < EPSILON: from sage.plot.line import line pic = line([(real(bd_1),imag(bd_1)),(real(bd_2),imag(bd_2))], **opts) else: # If we are here, we know it's not a line # So we compute the center and radius of the circle center = (1/(real(bd_1)*imag(bd_2) - real(bd_2)*imag(bd_1)) * ((imag(bd_2)-imag(bd_1)) + (real(bd_1)-real(bd_2))*I)) radius = RR(abs(bd_1 - center)) # abs is Euclidean distance # Now we calculate the angles for the parametric plot theta1 = CC(end_1 - center).arg() theta2 = CC(end_2 - center).arg() if theta2 < theta1: theta1, theta2 = theta2, theta1 from sage.calculus.var import var from sage.plot.plot import parametric_plot x = var('x') mid = (theta1 + theta2)/2.0 if (radius*cos(mid) + real(center))**2 + \ (radius*sin(mid) + imag(center))**2 > 1.0: # Swap theta1 and theta2 tmp = theta1 + 2*pi theta1 = theta2 theta2 = tmp pic = parametric_plot((radius*cos(x) + real(center), radius*sin(x) + imag(center)), (x, theta1, theta2), **opts) else: pic = parametric_plot((radius*cos(x) + real(center), radius*sin(x) + imag(center)), (x, theta1, theta2), **opts) if boundary: bd_pic = self._model.get_background_graphic() pic = bd_pic + pic return pic
def transform(self, radius=None, azimuth=None, elevation=None): """ A spherical elevation coordinates transform. EXAMPLES:: sage: T = SphericalElevation('radius', ['azimuth', 'elevation']) sage: T.transform(radius=var('r'), azimuth=var('theta'), elevation=var('phi')) (r*cos(phi)*cos(theta), r*cos(phi)*sin(theta), r*sin(phi)) """ return (radius * cos(elevation) * cos(azimuth), radius * cos(elevation) * sin(azimuth), radius * sin(elevation))
def transform(self, radius=None, azimuth=None, elevation=None): """ A spherical elevation coordinates transform. EXAMPLE:: sage: T = SphericalElevation('radius', ['azimuth', 'elevation']) sage: T.transform(radius=var('r'), azimuth=var('theta'), elevation=var('phi')) (r*cos(phi)*cos(theta), r*cos(phi)*sin(theta), r*sin(phi)) """ return (radius * cos(elevation) * cos(azimuth), radius * cos(elevation) * sin(azimuth), radius * sin(elevation))
def Torus(R=2, r=1, names=None): """ Generate a 2-dimensional torus embedded in Euclidean space. The shortcut operator ``.<,>`` can be used to specify the coordinates. INPUT: - ``R`` -- (default: ``2``) distance form the center to the center of the tube - ``r`` -- (default: ``1``) radius of the tube - ``names`` -- (default: ``None``) name of the coordinates, automatically set by the shortcut operator OUTPUT: - Riemannian manifold EXAMPLES:: sage: T.<theta, phi> = manifolds.Torus(3, 1) sage: T 2-dimensional Riemannian submanifold T embedded in the Euclidean space E^3 sage: T.atlas() [Chart (T, (theta, phi))] sage: T.embedding().display() T → E^3 (theta, phi) ↦ (X, Y, Z) = ((cos(theta) + 3)*cos(phi), (cos(theta) + 3)*sin(phi), sin(theta)) sage: T.metric().display() gamma = dtheta⊗dtheta + (cos(theta)^2 + 6*cos(theta) + 9) dphi⊗dphi """ from sage.functions.trig import cos, sin from sage.manifolds.manifold import Manifold from sage.manifolds.differentiable.examples.euclidean import EuclideanSpace E = EuclideanSpace(3, symbols='X Y Z') M = Manifold(2, 'T', ambient=E, structure="Riemannian") if names is None: names = ("th", "ph") names = tuple([names[i] + ":(-pi,pi):periodic" for i in range(2)]) C = M.chart(names=names) M._first_ngens = C._first_ngens th, ph = C[:] coordfunc = [(R + r * cos(th)) * cos(ph), (R + r * cos(th)) * sin(ph), r * sin(th)] imm = M.diff_map(E, coordfunc) M.set_embedding(imm) M.induced_metric() return M
def metric(self): r""" Return the metric tensor. EXAMPLES:: sage: from kerrgeodesic_gw import KerrBH sage: a, m = var('a m') sage: BH = KerrBH(a, m) sage: BH.metric() Lorentzian metric g on the Kerr spacetime M sage: BH.metric().display() g = -(a^2*cos(th)^2 - 2*m*r + r^2)/(a^2*cos(th)^2 + r^2) dt*dt - 2*a*m*r*sin(th)^2/(a^2*cos(th)^2 + r^2) dt*dph + (a^2*cos(th)^2 + r^2)/(a^2 - 2*m*r + r^2) dr*dr + (a^2*cos(th)^2 + r^2) dth*dth - 2*a*m*r*sin(th)^2/(a^2*cos(th)^2 + r^2) dph*dt + (2*a^2*m*r*sin(th)^4 + (a^2*r^2 + r^4 + (a^4 + a^2*r^2)*cos(th)^2)*sin(th)^2)/(a^2*cos(th)^2 + r^2) dph*dph The Schwarzschild metric:: sage: KerrBH(0, m).metric().display() g = (2*m - r)/r dt*dt - r/(2*m - r) dr*dr + r^2 dth*dth + r^2*sin(th)^2 dph*dph """ if self._metric is None: # Initialization of the metric tensor in Boyer-Lindquist coordinates cBL = self.boyer_lindquist_coordinates() t, r, th, ph = cBL[:] g = super(KerrBH, self).metric() # the initialized metric object m = self._m a = self._a r2 = r**2 a2 = a**2 rho2 = r2 + (a * cos(th))**2 Delta = r2 - 2 * m * r + a2 fBL = cBL.frame() # vector frame associated to BL coordinates g[fBL, 0, 0, cBL] = -1 + 2 * m * r / rho2 g[fBL, 0, 3, cBL] = -2 * a * m * r * sin(th)**2 / rho2 g[fBL, 1, 1, cBL] = rho2 / Delta g[fBL, 2, 2, cBL] = rho2 g[fBL, 3, 3, cBL] = (r2 + a2 + 2 * m * r * (a * sin(th))**2 / rho2) * sin(th)**2 for i in self.irange(): g[fBL, i, i, cBL].simplify() g[fBL, 0, 3, cBL].simplify() return self._metric
def plot(self, **kwargs): """ Return a graphics object representing the Kontsevich graph. INPUT: - ``edge_labels`` (boolean, default True) -- if True, show edge labels. - ``indices`` (boolean, default False) -- if True, show indices as edge labels instead of L and R; see :meth:`._latex_`. - ``upright`` (boolean, default False) -- if True, try to plot the graph with the ground vertices on the bottom and the rest on top. """ if not 'edge_labels' in kwargs: kwargs['edge_labels'] = True # show edge labels by default if 'indices' in kwargs: del kwargs['indices'] KG = DiGraph(self) for (k, e) in enumerate(self.edges()): KG.delete_edge(e) KG.add_edge((e[0], e[1], chr(97 + k))) return KG.plot(**kwargs) if len(self.ground_vertices()) == 2 and 'upright' in kwargs: del kwargs['upright'] kwargs['save_pos'] = True DiGraph.plot(self, **kwargs) positions = self.get_pos() # translate F to origin: F_pos = vector(positions[self.ground_vertices()[0]]) for p in positions: positions[p] = list(vector(positions[p]) - F_pos) # scale F - G distance to 1: G_len = abs(vector(positions[self.ground_vertices()[1]])) for p in positions: positions[p] = list(vector(positions[p]) / G_len) # rotate the vector F - G to (1,0) from math import atan2 theta = -atan2(positions[self.ground_vertices()[1]][1], positions[self.ground_vertices()[1]][0]) for p in positions: positions[p] = list( matrix([[cos(theta), -(sin(theta))], [sin(theta), cos(theta)]]) * vector(positions[p])) # flip if most things are below the x-axis: if len([(x, y) for (x, y) in positions.values() if y < 0]) / len( self.internal_vertices()) > 0.5: for p in positions: positions[p] = [positions[p][0], -positions[p][1]] return DiGraph.plot(self, **kwargs)
def plot_arc(radius, p, q, **opts): # TODO: THIS SHOULD USE THE EXISTING PLOT OF ARCS! # plot the arc from p to q differently depending on the type of self p = ZZ(p) q = ZZ(q) t = var('t') if p - q in [1, -1]: def f(t): return (radius * cos(t), radius * sin(t)) (p, q) = sorted([p, q]) angle_p = vertex_to_angle(p) angle_q = vertex_to_angle(q) return parametric_plot(f(t), (t, angle_q, angle_p), **opts) if self.type() == 'A': angle_p = vertex_to_angle(p) angle_q = vertex_to_angle(q) if angle_p < angle_q: angle_p += 2 * pi internal_angle = angle_p - angle_q if internal_angle > pi: (angle_p, angle_q) = (angle_q + 2 * pi, angle_p) internal_angle = angle_p - angle_q angle_center = (angle_p+angle_q) / 2 hypotenuse = radius / cos(internal_angle / 2) radius_arc = hypotenuse * sin(internal_angle / 2) center = (hypotenuse * cos(angle_center), hypotenuse * sin(angle_center)) center_angle_p = angle_p + pi / 2 center_angle_q = angle_q + 3 * pi / 2 def f(t): return (radius_arc * cos(t) + center[0], radius_arc * sin(t) + center[1]) return parametric_plot(f(t), (t, center_angle_p, center_angle_q), **opts) elif self.type() == 'D': if p >= q: q += self.r() px = -2 * pi * p / self.r() + pi / 2 qx = -2 * pi * q / self.r() + pi / 2 arc_radius = (px - qx) / 2 arc_center = qx + arc_radius def f(t): return exp(I * ((cos(t) + I * sin(t)) * arc_radius + arc_center)) * radius return parametric_plot((real_part(f(t)), imag_part(f(t))), (t, 0, pi), **opts)
def Catenoid(c=1, name="Catenoid"): r""" Returns a catenoid surface, with parametric representation .. MATH:: \begin{aligned} x(u, v) & = c \cosh(v/c) \cos(u); \\ y(u, v) & = c \cosh(v/c) \sin(u); \\ z(u, v) & = v. \end{aligned} INPUT: - ``c`` -- surface parameter. - ``name`` -- string. Name of the surface. EXAMPLES:: sage: cat = surfaces.Catenoid(); cat Parametrized surface ('Catenoid') with equation (cos(u)*cosh(v), cosh(v)*sin(u), v) sage: cat.plot() Graphics3d Object """ u, v = var("u, v") catenoid_eq = [c * cosh(v / c) * cos(u), c * cosh(v / c) * sin(u), v] coords = ((u, 0, 2 * pi), (v, -1, 1)) return ParametrizedSurface3D(catenoid_eq, coords, name)
def _i_rotation(self, z, alpha): r""" Return the resulting point after applying a hyperbolic rotation centered at `0 + i` and angle ``alpha`` to ``z``. INPUT: - ``z``-- point in the upper complex halfplane to which apply the isometry - ``alpha``-- angle of rotation (radians,counterwise) OUTPUT: - rotated point in the upper complex halfplane TESTS:: sage: from sage.plot.hyperbolic_regular_polygon import HyperbolicRegularPolygon sage: P = HyperbolicRegularPolygon(4, pi/4, 1+I, {}) sage: P._i_rotation(2+I, pi/2) I - 2 """ _a = alpha / 2 _c = cos(_a) _s = sin(_a) G = matrix([[_c, _s], [-_s, _c]]) return (G[0][0] * z + G[0][1]) / (G[1][0] * z + G[1][1])
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 Helicoid(h=1, name="Helicoid"): r""" Return a helicoid surface, with parametrization .. MATH:: \begin{aligned} x(\rho, \theta) & = \rho \cos(\theta); \\ y(\rho, \theta) & = \rho \sin(\theta); \\ z(\rho, \theta) & = h\theta/(2\pi). \end{aligned} INPUT: - ``h`` -- distance along the z-axis between two successive turns of the helicoid. - ``name`` -- string. Name of the surface. For more information, see :wikipedia:`Helicoid`. EXAMPLES:: sage: helicoid = surfaces.Helicoid(h=2); helicoid Parametrized surface ('Helicoid') with equation (rho*cos(theta), rho*sin(theta), theta/pi) sage: helicoid.plot() Graphics3d Object """ rho, theta = var('rho, theta') helicoid_eq = [ rho * cos(theta), rho * sin(theta), h * theta / (2 * pi) ] coords = ((rho, -2, 2), (theta, 0, 2 * pi)) return ParametrizedSurface3D(helicoid_eq, coords, name)
def evaluate_E(self, affine_parameter, solution_key=None): r""" Compute the conserved energy `E` at a given value of the affine parameter `\lambda`. INPUT: - ``affine_parameter`` -- value of the affine parameter `\lambda` - ``solution_key`` -- (default: ``None``) string denoting the numerical solution to use for the evaluation; if ``None``, the latest solution computed by :meth:`integrate` is used. OUTPUT: - value of `E` """ p = self.evaluate_tangent_vector(affine_parameter, solution_key=solution_key) point = p.parent().base_point() BLchart = self._spacetime.boyer_lindquist_coordinates() r, th = BLchart(point)[1:3] a, m = self._a, self._m rho2 = r**2 + (a * cos(th))**2 p_comp = p.components(basis=BLchart.frame().at(point)) pt = p_comp[0] pph = p_comp[3] b = 2 * m * r / rho2 E = (1 - b) * pt + b * a * sin(th)**2 * pph return E.substitute(self._numerical_substitutions())
def Catenoid(c=1, name="Catenoid"): r""" Return a catenoid surface, with parametric representation .. MATH:: \begin{aligned} x(u, v) & = c \cosh(v/c) \cos(u); \\ y(u, v) & = c \cosh(v/c) \sin(u); \\ z(u, v) & = v. \end{aligned} INPUT: - ``c`` -- surface parameter. - ``name`` -- string. Name of the surface. For more information, see :wikipedia:`Catenoid`. EXAMPLES:: sage: cat = surfaces.Catenoid(); cat Parametrized surface ('Catenoid') with equation (cos(u)*cosh(v), cosh(v)*sin(u), v) sage: cat.plot() Graphics3d Object """ u, v = var('u, v') catenoid_eq = [c * cosh(v / c) * cos(u), c * cosh(v / c) * sin(u), v] coords = ((u, 0, 2 * pi), (v, -1, 1)) return ParametrizedSurface3D(catenoid_eq, coords, name)
def evaluate_Q(self, affine_parameter, solution_key=None): r""" Compute the Carter constant `Q` at a given value of the affine parameter `\lambda`. INPUT: - ``affine_parameter`` -- value of the affine parameter `\lambda` - ``solution_key`` -- (default: ``None``) string denoting the numerical solution to use for the evaluation; if ``None``, the latest solution computed by :meth:`integrate` is used. OUTPUT: - value of `Q` """ p = self.evaluate_tangent_vector(affine_parameter, solution_key=solution_key) point = p.parent().base_point() BLchart = self._spacetime.boyer_lindquist_coordinates() r, th = BLchart(point)[1:3] a = self._a rho4 = (r**2 + (a * cos(th))**2)**2 mu2 = self.evaluate_mu(affine_parameter)**2 E2 = self.evaluate_E(affine_parameter, solution_key=solution_key)**2 L2 = self.evaluate_L(affine_parameter, solution_key=solution_key)**2 p_comp = p.components(basis=BLchart.frame().at(point)) pth = p_comp[2] Q = rho4 * pth**2 + cos(th)**2 * (L2 / sin(th)**2 + a**2 * (mu2 - E2)) return Q.substitute(self._numerical_substitutions())
def Helicoid(h=1, name="Helicoid"): r""" Returns a helicoid surface, with parametrization .. MATH:: \begin{aligned} x(\rho, \theta) & = \rho \cos(\theta); \\ y(\rho, \theta) & = \rho \sin(\theta); \\ z(\rho, \theta) & = h\theta/(2\pi). \end{aligned} INPUT: - ``h`` -- distance along the z-axis between two successive turns of the helicoid. - ``name`` -- string. Name of the surface. EXAMPLES:: sage: helicoid = surfaces.Helicoid(h=2); helicoid Parametrized surface ('Helicoid') with equation (rho*cos(theta), rho*sin(theta), theta/pi) sage: helicoid.plot() Graphics3d Object """ rho, theta = var("rho, theta") helicoid_eq = [rho * cos(theta), rho * sin(theta), h * theta / (2 * pi)] coords = ((rho, -2, 2), (theta, 0, 2 * pi)) return ParametrizedSurface3D(helicoid_eq, [rho, theta], name)
def _circ_arc(t0, t1, c, r, num_pts=500): r""" Circular arc INPUTS: - ''t0'' -- starting parameter - ''t1'' -- ending parameter - ''c'' -- center point of the circle - ''r'' -- radius of circle - ''num_pts'' -- (default 100) number of points on polygon OUTPUT: - ''ca'' -- a polygonal approximation of a circular arc centered at c and radius r, starting at t0 and ending at t1 EXAMPLES:: sage: ca=_circ_arc(0.1,0.2,0.0,1.0,100) """ from sage.plot.plot import parametric_plot from sage.functions.trig import cos, sin from sage.all import var t00 = t0 t11 = t1 ## To make sure the line is correct we reduce all arguments to the same branch, ## e.g. [0,2pi] pi = RR.pi() while t00 < 0.0: t00 = t00 + RR(2.0 * pi) while t11 < 0: t11 = t11 + RR(2.0 * pi) while t00 > 2 * pi: t00 = t00 - RR(2.0 * pi) while t11 > 2 * pi: t11 = t11 - RR(2.0 * pi) xc = CC(c).real() yc = CC(c).imag() # L0 = # [[RR(r*cos(t00+i*(t11-t00)/num_pts))+xc,RR(r*sin(t00+i*(t11-t00)/num_pts))+yc] # for i in range(0 ,num_pts)] t = var("t") if t11 > t00: ca = parametric_plot((r * cos(t) + xc, r * sin(t) + yc), (t, t00, t11)) else: ca = parametric_plot((r * cos(t) + xc, r * sin(t) + yc), (t, t11, t00)) return ca
def show(self, boundary=True, **options): r""" Plot ``self``. EXAMPLES:: sage: HyperbolicPlane().UHP().get_geodesic(0, 1).show() Graphics object consisting of 2 graphics primitives """ opts = {'axes': False, 'aspect_ratio': 1} opts.update(self.graphics_options()) opts.update(options) end_1, end_2 = [CC(k.coordinates()) for k in self.endpoints()] bd_1, bd_2 = [CC(k.coordinates()) for k in self.ideal_endpoints()] if (abs(real(end_1) - real(end_2)) < EPSILON) \ or CC(infinity) in [end_1, end_2]: #on same vertical line # If one of the endpoints is infinity, we replace it with a # large finite point if end_1 == CC(infinity): end_1 = (real(end_2), (imag(end_2) + 10)) end_2 = (real(end_2), imag(end_2)) elif end_2 == CC(infinity): end_2 = (real(end_1), (imag(end_1) + 10)) end_1 = (real(end_1), imag(end_1)) from sage.plot.line import line pic = line((end_1, end_2), **opts) if boundary: cent = min(bd_1, bd_2) bd_dict = {'bd_min': cent - 3, 'bd_max': cent + 3} bd_pic = self._model.get_background_graphic(**bd_dict) pic = bd_pic + pic return pic else: center = (bd_1 + bd_2)/2 # Circle center radius = abs(bd_1 - bd_2)/2 theta1 = CC(end_1 - center).arg() theta2 = CC(end_2 - center).arg() if abs(theta1 - theta2) < EPSILON: theta2 += pi [theta1, theta2] = sorted([theta1, theta2]) from sage.calculus.var import var from sage.plot.plot import parametric_plot x = var('x') pic = parametric_plot((radius*cos(x) + real(center), radius*sin(x) + imag(center)), (x, theta1, theta2), **opts) if boundary: # We want to draw a segment of the real line. The # computations below compute the projection of the # geodesic to the real line, and then draw a little # to the left and right of the projection. shadow_1, shadow_2 = [real(k) for k in [end_1, end_2]] midpoint = (shadow_1 + shadow_2)/2 length = abs(shadow_1 - shadow_2) bd_dict = {'bd_min': midpoint - length, 'bd_max': midpoint + length} bd_pic = self._model.get_background_graphic(**bd_dict) pic = bd_pic + pic return pic
def _draw_funddom(coset_reps,format="S"): r""" Draw a fundamental domain for G. INPUT: - ``format`` -- (default 'Disp') How to present the f.d. - ``S`` -- Display directly on the screen EXAMPLES:: sage: G=MySubgroup(Gamma0(3)) sage: G._draw_funddom() """ pi=RR.pi() pi_3 = pi / RR(3.0) from sage.plot.plot import (Graphics,line) from sage.functions.trig import (cos,sin) g=Graphics() x1=RR(-0.5) ; y1=RR(sqrt(3 )/2 ) x2=RR(0.5) ; y2=RR(sqrt(3 )/2 ) xmax=RR(20.0) l1 = line([[x1,y1],[x1,xmax]]) l2 = line([[x2,y2],[x2,xmax]]) l3 = line([[x2,xmax],[x1,xmax]]) # This is added to make a closed contour c0=_circ_arc(RR(pi/3.0) ,RR(2.0*pi)/RR(3.0) ,0 ,1 ,100 ) tri=c0+l1+l3+l2 g=g+tri for A in coset_reps: [a,b,c,d]=A if(a==1 and b==0 and c==0 and d==1 ): continue if(a<0 ): a=RR(-a); b=RR(-b); c=RR(-c); d=RR(-d) else: a=RR(a); b=RR(b); c=RR(c); d=RR(d) if(c==0 ): # then this is easier L0 = [[cos(pi_3*RR(i/100.0))+b,sin(pi_3*RR(i/100.0))] for i in range(100 ,201 )] L1 = [[x1+b,y1],[x1+b,xmax]] L2 = [[x2+b,y2],[x2+b,xmax]] L3 = [[x2+b,xmax],[x1+b,xmax]] c0=line(L0); l1=line(L1); l2=line(L2); l3=line(L3) tri=c0+l1+l3+l2 g=g+tri else: den=(c*x1+d)**2 +c**2 *y1**2 x1_t=(a*c*(x1**2 +y1**2 )+(a*d+b*c)*x1+b*d)/den y1_t=y1/den den=(c*x2+d)**2 +c**2 *y2**2 x2_t=(a*c*(x2**2 +y2**2 )+(a*d+b*c)*x2+b*d)/den y2_t=y2/den inf_t=a/c c0=_geodesic_between_two_points(x1_t,y1_t,x2_t,y2_t) c1=_geodesic_between_two_points(x1_t,y1_t,inf_t,0. ) c2=_geodesic_between_two_points(x2_t,y2_t,inf_t,0.0) tri=c0+c1+c2 g=g+tri return g
def plot(self): from sage.functions.trig import sin, cos from sage.plot.circle import circle from sage.plot.point import point from sage.plot.text import text p = circle((0,0),1) for i in range(self._dimension): a = self._alpha[i] p += point([cos(2*pi*a),sin(2*pi*a)], color='blue', size=100) p += text(r"$\alpha_%i$"%(self._i_alpha[i]+1), [1.2*cos(2*pi*a),1.2*sin(2*pi*a)],fontsize=40) for i in range(self._dimension): b = self._beta[i] p += point([cos(2*pi*b),sin(2*pi*b)], color='red', size=100) p += text(r"$\beta_%i$"%(self._i_beta[i]+1), [1.2*cos(2*pi*b),1.2*sin(2*pi*b)],fontsize=40) p.show(axes=False, xmin=-1, xmax=1, ymin=-1, ymax=1)
def _circ_arc(t0, t1, c, r, num_pts=5000): r""" Circular arc INPUTS: - ''t0'' -- starting parameter - ''t1'' -- ending parameter - ''c'' -- center point of the circle - ''r'' -- radius of circle - ''num_pts'' -- (default 100) number of points on polygon OUTPUT: - ''ca'' -- a polygonal approximation of a circular arc centered at c and radius r, starting at t0 and ending at t1 EXAMPLES:: sage: ca=_circ_arc(0.1,0.2,0.0,1.0,100) """ from sage.plot.plot import line, parametric_plot from sage.functions.trig import (cos, sin) from sage.all import var t00 = t0 t11 = t1 ## To make sure the line is correct we reduce all arguments to the same branch, ## e.g. [0,2pi] pi = RR.pi() while (t00 < 0.0): t00 = t00 + RR(2.0 * pi) while (t11 < 0): t11 = t11 + RR(2.0 * pi) while (t00 > 2 * pi): t00 = t00 - RR(2.0 * pi) while (t11 > 2 * pi): t11 = t11 - RR(2.0 * pi) xc = CC(c).real() yc = CC(c).imag() num_pts = 3 t = var('t') if t11 > t00: ca = parametric_plot((r * cos(t) + xc, r * sin(t) + yc), (t, t00, t11)) else: ca = parametric_plot((r * cos(t) + xc, r * sin(t) + yc), (t, t11, t00)) #L0 = [[RR(r*cos(t00+i*(t11-t00)/num_pts))+xc,RR(r*sin(t00+i*(t11-t00)/num_pts))+yc] for i in range(0 ,num_pts)] #ca=line(L0) return ca
def plot(self, show_box=False, colors=["white","lightgray","darkgray"]): r""" Return a plot of ``self``. INPUT: - ``show_box`` -- boolean (default: ``False``); if ``True``, also shows the visible tiles on the `xy`-, `yz`-, `zx`-planes - ``colors`` -- (default: ``["white", "lightgray", "darkgray"]``) list ``[A, B, C]`` of 3 strings representing colors EXAMPLES:: sage: PP = PlanePartition([[4,3,3,1],[2,1,1],[1,1]]) sage: PP.plot() Graphics object consisting of 27 graphics primitives """ x = self._max_x y = self._max_y z = self._max_z from sage.functions.trig import cos, sin from sage.plot.polygon import polygon from sage.symbolic.constants import pi from sage.plot.plot import plot Uside = [[0,0], [cos(-pi/6),sin(-pi/6)], [0,-1], [cos(7*pi/6),sin(7*pi/6)]] Lside = [[0,0], [cos(-pi/6),sin(-pi/6)], [cos(pi/6),sin(pi/6)], [0,1]] Rside = [[0,0], [0,1], [cos(5*pi/6),sin(5*pi/6)], [cos(7*pi/6),sin(7*pi/6)]] Xdir = [cos(7*pi/6), sin(7*pi/6)] Ydir = [cos(-pi/6), sin(-pi/6)] Zdir = [0, 1] def move(side, i, j, k): return [[P[0]+i*Xdir[0]+j*Ydir[0]+k*Zdir[0], P[1]+i*Xdir[1]+j*Ydir[1]+k*Zdir[1]] for P in side] def add_topside(i, j, k): return polygon(move(Uside,i,j,k), edgecolor="black", color=colors[0]) def add_leftside(i, j, k): return polygon(move(Lside,i,j,k), edgecolor="black", color=colors[1]) def add_rightside(i, j, k): return polygon(move(Rside,i,j,k), edgecolor="black", color=colors[2]) TP = plot([]) for r in range(len(self.z_tableau())): for c in range(len(self.z_tableau()[r])): if self.z_tableau()[r][c] > 0 or show_box: TP += add_topside(r, c, self.z_tableau()[r][c]) for r in range(len(self.y_tableau())): for c in range(len(self.y_tableau()[r])): if self.y_tableau()[r][c] > 0 or show_box: TP += add_rightside(c, self.y_tableau()[r][c], r) for r in range(len(self.x_tableau())): for c in range(len(self.x_tableau()[r])): if self.x_tableau()[r][c] > 0 or show_box: TP += add_leftside(self.x_tableau()[r][c], r, c) TP.axes(show=False) return TP
def __init__(self, sides, i_angle, center, options): """ Initialize HyperbolicRegularPolygon. EXAMPLES:: sage: from sage.plot.hyperbolic_regular_polygon import HyperbolicRegularPolygon sage: print(HyperbolicRegularPolygon(5,pi/2,I, {})) Hyperbolic regular polygon (sides=5, i_angle=1/2*pi, center=1.00000000000000*I) """ self.center = CC(center) if self.center.imag() <= 0 : raise ValueError("center: %s is not a valid point in the upper half plane model of the hyperbolic plane"%(self.center)) if sides < 3 : raise ValueError("degenerated polygons (sides<=2) are not supported") if i_angle <=0 or i_angle >= pi: raise ValueError("interior angle %s must be in (0, pi) interval"%(i_angle)) if pi*(sides-2) - sides*i_angle <= 0 : raise ValueError("there exists no hyperbolic regular compact polygon, for sides=%s the interior angle must be less than %s"%(sides, pi * (sides-2) / sides)) self.sides = sides self.i_angle = i_angle beta = 2 * pi / self.sides # compute the rotation angle to be used ahead alpha = self.i_angle / Integer(2) I = CC(0, 1) # compute using cosine theorem the radius of the circumscribed circle # using the triangle formed by the radius and the three known angles r = arccosh(cot(alpha) * (1 + cos(beta)) / sin(beta)) # The first point will be always on the imaginary axis limited # to 8 digits for efficiency in the subsequent calculations. z_0 = [I*(e**r).n(digits=8)] # Compute the dilation isometry used to move the center # from I to the imaginary part of the given center. scale = self.center.imag() # Compute the parabolic isometry to move the center to the # real part of the given center. h_disp = self.center.real() d_z_k = [z_0[0]*scale + h_disp] #d_k has the points for the polygon in the given center z_k = z_0 #z_k has the Re(z)>0 vertices for the I centered polygon r_z_k = [] #r_z_k has the Re(z)<0 vertices if is_odd(self.sides): vert = (self.sides - 1) / 2 else: vert = self.sides / 2 - 1 for k in range(0, vert): # Compute with 8 digits to accelerate calculations new_z_k = self._i_rotation(z_k[-1], beta).n(digits=8) z_k = z_k + [new_z_k] d_z_k = d_z_k + [new_z_k * scale + h_disp] r_z_k=[-(new_z_k).conjugate() * scale + h_disp] + r_z_k if is_odd(self.sides): HyperbolicPolygon.__init__(self, d_z_k + r_z_k, options) else: z_opo = [I * (e**(-r)).n(digits=8) * scale + h_disp] HyperbolicPolygon.__init__(self, d_z_k + z_opo + r_z_k, options)
def plot(self, **kwargs): """ Return a graphics object representing the Kontsevich graph. INPUT: - ``edge_labels`` (boolean, default True) -- if True, show edge labels. - ``indices`` (boolean, default False) -- if True, show indices as edge labels instead of L and R; see :meth:`._latex_`. - ``upright`` (boolean, default False) -- if True, try to plot the graph with the ground vertices on the bottom and the rest on top. """ if not 'edge_labels' in kwargs: kwargs['edge_labels'] = True # show edge labels by default if 'indices' in kwargs: del kwargs['indices'] KG = DiGraph(self) for (k,e) in enumerate(self.edges()): KG.delete_edge(e) KG.add_edge((e[0], e[1], chr(97 + k))) return KG.plot(**kwargs) if len(self.ground_vertices()) == 2 and 'upright' in kwargs: del kwargs['upright'] kwargs['save_pos'] = True DiGraph.plot(self, **kwargs) positions = self.get_pos() # translate F to origin: F_pos = vector(positions[self.ground_vertices()[0]]) for p in positions: positions[p] = list(vector(positions[p]) - F_pos) # scale F - G distance to 1: G_len = abs(vector(positions[self.ground_vertices()[1]])) for p in positions: positions[p] = list(vector(positions[p])/G_len) # rotate the vector F - G to (1,0) from math import atan2 theta = -atan2(positions[self.ground_vertices()[1]][1], positions[self.ground_vertices()[1]][0]) for p in positions: positions[p] = list(matrix([[cos(theta),-(sin(theta))],[sin(theta),cos(theta)]]) * vector(positions[p])) # flip if most things are below the x-axis: if len([(x,y) for (x,y) in positions.values() if y < 0])/len(self.internal_vertices()) > 0.5: for p in positions: positions[p] = [positions[p][0], -positions[p][1]] return DiGraph.plot(self, **kwargs)
def draw_transformed_triangle_H(A, xmax=20): r""" Draw the modular triangle translated by A=[a,b,c,d] """ #print "A=",A,type(A) pi = RR.pi() pi_3 = pi / RR(3.0) from sage.plot.plot import (Graphics, line) from sage.functions.trig import (cos, sin) x1 = RR(-0.5) y1 = RR(sqrt(3) / 2) x2 = RR(0.5) y2 = RR(sqrt(3) / 2) a, b, c, d = A #[0,0]; b=A[0,1]; c=A[1,0]; d=A[1,1] if a < 0: a = RR(-a) b = RR(-b) c = RR(-c) d = RR(-d) else: a = RR(a) b = RR(b) c = RR(c) d = RR(d) if c == 0: # then this is easier if a * d <> 0: a = a / d b = b / d L0 = [[ a * cos(pi_3 * RR(i / 100.0)) + b, a * sin(pi_3 * RR(i / 100.0)) ] for i in range(100, 201)] L1 = [[a * x1 + b, a * y1], [a * x1 + b, xmax]] L2 = [[a * x2 + b, a * y2], [a * x2 + b, xmax]] L3 = [[a * x2 + b, xmax], [a * x1 + b, xmax]] c0 = line(L0) l1 = line(L1) l2 = line(L2) l3 = line(L3) tri = c0 + l1 + l3 + l2 else: den = (c * x1 + d)**2 + c**2 * y1**2 x1_t = (a * c * (x1**2 + y1**2) + (a * d + b * c) * x1 + b * d) / den y1_t = y1 / den den = (c * x2 + d)**2 + c**2 * y2**2 x2_t = (a * c * (x2**2 + y2**2) + (a * d + b * c) * x2 + b * d) / den y2_t = y2 / den inf_t = a / c #print "A=",A #print "arg1=",x1_t,y1_t,x2_t,y2_t c0 = _geodesic_between_two_points(x1_t, y1_t, x2_t, y2_t) #print "arg1=",x1_t,y1_t,inf_t c1 = _geodesic_between_two_points(x1_t, y1_t, inf_t, 0.) #print "arg1=",x2_t,y2_t,inf_t c2 = _geodesic_between_two_points(x2_t, y2_t, inf_t, 0.0) tri = c0 + c1 + c2 return tri
def _derivative_(self, x, diff_param=None): """ EXAMPLES:: sage: x = var('x') sage: fresnel_sin(x).diff(x) sin(1/2*pi*x^2) """ from sage.functions.trig import sin return sin(pi*x**2/2)
def map_to_Euclidean(self): r""" Map from Kerr spacetime to the Euclidean 4-space, based on Boyer-Lindquist coordinates """ if self._map_to_E4 is None: E4 = EuclideanSpace(4, coordinates='Cartesian', symbols='t x y z', start_index=0) X4 = E4.cartesian_coordinates() BL = self.boyer_lindquist_coordinates() t, r, th, ph = BL[:] self._map_to_E4 = self.diff_map(E4, { (BL, X4): [t, r * sin(th) * cos(ph), r * sin(th) * sin(ph), r * cos(th)] }, name='F') return self._map_to_E4
def _derivative_(self, x, diff_param=None): """ EXAMPLES:: sage: x = var('x') sage: fresnel_sin(x).diff(x) sin(1/2*pi*x^2) """ from sage.functions.trig import sin return sin(pi * x**2 / 2)
def transform(self, radius=None, azimuth=None, height=None): """ A cylindrical coordinates transform. EXAMPLES:: sage: T = Cylindrical('height', ['azimuth', 'radius']) sage: T.transform(radius=var('r'), azimuth=var('theta'), height=var('z')) (r*cos(theta), r*sin(theta), z) """ return (radius * cos(azimuth), radius * sin(azimuth), height)
def Ellipsoid(center=(0,0,0), axes=(1,1,1), name="Ellipsoid"): r""" Returns an ellipsoid centered at ``center`` whose semi-principal axes have lengths given by the components of ``axes``. The parametrization of the ellipsoid is given by .. MATH:: \begin{aligned} x(u, v) & = x_0 + a \cos(u) \cos(v); \\ y(u, v) & = y_0 + b \sin(u) \cos(v); \\ z(u, v) & = z_0 + c \sin(v). \end{aligned} INPUT: - ``center`` -- 3-tuple. Coordinates of the center of the ellipsoid. - ``axes`` -- 3-tuple. Lengths of the semi-principal axes. - ``name`` -- string. Name of the ellipsoid. EXAMPLES:: sage: ell = surfaces.Ellipsoid(axes=(1, 2, 3)); ell Parametrized surface ('Ellipsoid') with equation (cos(u)*cos(v), 2*cos(v)*sin(u), 3*sin(v)) sage: ell.plot() Graphics3d Object """ u, v = var ('u, v') x, y, z = center a, b, c = axes ellipsoid_parametric_eq = [x + a*cos(u)*cos(v), y + b*sin(u)*cos(v), z + c*sin(v)] coords = ((u, 0, 2*pi), (v, -pi/2, pi/2)) return ParametrizedSurface3D(ellipsoid_parametric_eq, coords, name)
def transform(self, radius=None, azimuth=None, height=None): """ A cylindrical coordinates transform. EXAMPLE:: sage: T = Cylindrical('height', ['azimuth', 'radius']) sage: T.transform(radius=var('r'), azimuth=var('theta'), height=var('z')) (r*cos(theta), r*sin(theta), z) """ return (radius * cos(azimuth), radius * sin(azimuth), height)
def Ellipsoid(center=(0,0,0), axes=(1,1,1), name="Ellipsoid"): r""" Returns an ellipsoid centered at ``center`` whose semi-principal axes have lengths given by the components of ``axes``. The parametrization of the ellipsoid is given by .. MATH:: \begin{aligned} x(u, v) & = x_0 + a \cos(u) \cos(v); \\ y(u, v) & = y_0 + b \sin(u) \cos(v); \\ z(u, v) & = z_0 + c \sin(v). \end{aligned} INPUT: - ``center`` -- 3-tuple. Coordinates of the center of the ellipsoid. - ``axes`` -- 3-tuple. Lengths of the semi-principal axes. - ``name`` -- string. Name of the ellipsoid. EXAMPLES:: sage: ell = surfaces.Ellipsoid(axes=(1, 2, 3)); ell Parametrized surface ('Ellipsoid') with equation (cos(u)*cos(v), 2*cos(v)*sin(u), 3*sin(v)) sage: ell.plot() """ u, v = var ('u, v') x, y, z = center a, b, c = axes ellipsoid_parametric_eq = [x + a*cos(u)*cos(v), y + b*sin(u)*cos(v), z + c*sin(v)] coords = ((u, 0, 2*pi), (v, -pi/2, pi/2)) return ParametrizedSurface3D(ellipsoid_parametric_eq, coords, name)
def plot(self): from sage.functions.trig import sin, cos from sage.plot.circle import circle from sage.plot.point import point from sage.plot.text import text p = circle((0, 0), 1) for i in range(self._dimension): a = self._alpha[i] p += point([cos(2 * pi * a), sin(2 * pi * a)], color='blue', size=100) p += text(r"$\alpha_%i$" % (self._i_alpha[i] + 1), [1.2 * cos(2 * pi * a), 1.2 * sin(2 * pi * a)], fontsize=40) for i in range(self._dimension): b = self._beta[i] p += point([cos(2 * pi * b), sin(2 * pi * b)], color='red', size=100) p += text(r"$\beta_%i$" % (self._i_beta[i] + 1), [1.2 * cos(2 * pi * b), 1.2 * sin(2 * pi * b)], fontsize=40) p.show(axes=False, xmin=-1, xmax=1, ymin=-1, ymax=1)
def triangulation(self): r""" Plot a regular polygon with some diagonals. If ``self`` is positive and integral then this will be a triangulation. .. PLOT:: :width: 600 px G = path_tableaux.FriezePattern([1,2,7,5,3,7,4,1]).triangulation() p = graphics_array(G, 7, 6) sphinx_plot(p) EXAMPLES:: sage: path_tableaux.FriezePattern([1,2,7,5,3,7,4,1]).triangulation() Graphics object consisting of 25 graphics primitives sage: path_tableaux.FriezePattern([1,2,1/7,5,3]).triangulation() Graphics object consisting of 12 graphics primitives sage: K.<sqrt2> = NumberField(x^2-2) sage: path_tableaux.FriezePattern([1,sqrt2,1,sqrt2,3,2*sqrt2,5,3*sqrt2,1], field=K).triangulation() Graphics object consisting of 24 graphics primitives """ n = len(self) - 1 cd = CylindricalDiagram(self).diagram from sage.plot.plot import Graphics from sage.plot.line import line from sage.plot.text import text from sage.functions.trig import sin, cos from sage.all import pi G = Graphics() G.set_aspect_ratio(1.0) vt = [(cos(2 * theta * pi / (n)), sin(2 * theta * pi / (n))) for theta in range(n + 1)] for i, p in enumerate(vt): G += text(str(i), [1.05 * p[0], 1.05 * p[1]]) for i, r in enumerate(cd): for j, a in enumerate(r[:n]): if a == 1: G += line([vt[i], vt[j]]) G.axes(False) return G
def _derivative_(self, z, diff_param=None): r""" The derivative of `\operatorname{Si}(z)` is `\sin(z)/z` if `z` is not zero. The derivative at `z = 0` is `1` (but this exception is not currently implemented). EXAMPLES:: sage: x = var('x') sage: f = sin_integral(x) sage: f.diff(x) sin(x)/x sage: f = sin_integral(x^2) sage: f.diff(x) 2*sin(x^2)/x """ return sin(z)/z
def _derivative_(self, z, diff_param=None): r""" The derivative of `\operatorname{Si}(z)` is `\sin(z)/z` if `z` is not zero. The derivative at `z = 0` is `1` (but this exception is not currently implemented). EXAMPLES:: sage: x = var('x') sage: f = sin_integral(x) sage: f.diff(x) sin(x)/x sage: f = sin_integral(x^2) sage: f.diff(x) 2*sin(x^2)/x """ return sin(z) / z
def draw_transformed_triangle_H(A,xmax=20): r""" Draw the modular triangle translated by A=[a,b,c,d] """ #print "A=",A,type(A) pi=RR.pi() pi_3 = pi / RR(3.0) from sage.plot.plot import (Graphics,line) from sage.functions.trig import (cos,sin) x1=RR(-0.5) ; y1=RR(sqrt(3 )/2 ) x2=RR(0.5) ; y2=RR(sqrt(3 )/2 ) a,b,c,d = A #[0,0]; b=A[0,1]; c=A[1,0]; d=A[1,1] if a<0: a=RR(-a); b=RR(-b); c=RR(-c); d=RR(-d) else: a=RR(a); b=RR(b); c=RR(c); d=RR(d) if c==0: # then this is easier if a*d<>0: a=a/d; b=b/d; L0 = [[a*cos(pi_3*RR(i/100.0))+b,a*sin(pi_3*RR(i/100.0))] for i in range(100 ,201 )] L1 = [[a*x1+b,a*y1],[a*x1+b,xmax]] L2 = [[a*x2+b,a*y2],[a*x2+b,xmax]] L3 = [[a*x2+b,xmax],[a*x1+b,xmax]] c0=line(L0); l1=line(L1); l2=line(L2); l3=line(L3) tri=c0+l1+l3+l2 else: den=(c*x1+d)**2 +c**2 *y1**2 x1_t=(a*c*(x1**2 +y1**2 )+(a*d+b*c)*x1+b*d)/den y1_t=y1/den den=(c*x2+d)**2 +c**2 *y2**2 x2_t=(a*c*(x2**2 +y2**2 )+(a*d+b*c)*x2+b*d)/den y2_t=y2/den inf_t=a/c #print "A=",A #print "arg1=",x1_t,y1_t,x2_t,y2_t c0=_geodesic_between_two_points(x1_t,y1_t,x2_t,y2_t) #print "arg1=",x1_t,y1_t,inf_t c1=_geodesic_between_two_points(x1_t,y1_t,inf_t,0. ) #print "arg1=",x2_t,y2_t,inf_t c2=_geodesic_between_two_points(x2_t,y2_t,inf_t,0.0) tri=c0+c1+c2 return tri
def regular_polygon(self, n, base_ring=QQ): """ Return a regular polygon with n vertices. Over the rational field the vertices may not be exact. INPUT: - ``n`` -- a positive integer, the number of vertices. - ``field`` -- either ``QQ`` or ``RDF``. EXAMPLES:: sage: octagon = polytopes.regular_polygon(8) sage: len(octagon.vertices()) 8 """ npi = 3.14159265359 verts = [] for i in range(n): t = 2*npi*i/n verts.append([sin(t),cos(t)]) verts = [[base_ring(RDF(x)) for x in y] for y in verts] return Polyhedron(vertices=verts, base_ring=base_ring)
def regular_polygon(self, n, base_ring=QQ): """ Return a regular polygon with n vertices. Over the rational field the vertices may not be exact. INPUT: - ``n`` -- a positive integer, the number of vertices. - ``field`` -- either ``QQ`` or ``RDF``. EXAMPLES:: sage: octagon = polytopes.regular_polygon(8) sage: len(octagon.vertices()) 8 """ npi = 3.14159265359 verts = [] for i in range(n): t = 2 * npi * i / n verts.append([sin(t), cos(t)]) verts = [[base_ring(RDF(x)) for x in y] for y in verts] return Polyhedron(vertices=verts, base_ring=base_ring)
def revolution_plot3d(curve, trange, phirange=None, parallel_axis='z', axis=(0, 0), print_vector=False, show_curve=False, **kwds): """ Return a plot of a revolved curve. There are three ways to call this function: - ``revolution_plot3d(f,trange)`` where `f` is a function located in the `x z` plane. - ``revolution_plot3d((f_x,f_z),trange)`` where `(f_x,f_z)` is a parametric curve on the `x z` plane. - ``revolution_plot3d((f_x,f_y,f_z),trange)`` where `(f_x,f_y,f_z)` can be any parametric curve. INPUT: - ``curve`` - A curve to be revolved, specified as a function, a 2-tuple or a 3-tuple. - ``trange`` - A 3-tuple `(t,t_{\min},t_{\max})` where t is the independent variable of the curve. - ``phirange`` - A 2-tuple of the form `(\phi_{\min},\phi_{\max})`, (default `(0,\pi)`) that specifies the angle in which the curve is to be revolved. - ``parallel_axis`` - A string (Either 'x', 'y', or 'z') that specifies the coordinate axis parallel to the revolution axis. - ``axis`` - A 2-tuple that specifies the position of the revolution axis. If parallel is: - 'z' - then axis is the point in which the revolution axis intersects the `x y` plane. - 'x' - then axis is the point in which the revolution axis intersects the `y z` plane. - 'y' - then axis is the point in which the revolution axis intersects the `x z` plane. - ``print_vector`` - If True, the parametrization of the surface of revolution will be printed. - ``show_curve`` - If True, the curve will be displayed. EXAMPLES: Let's revolve a simple function around different axes:: sage: u = var('u') sage: f=u^2 sage: revolution_plot3d(f,(u,0,2),show_curve=True,opacity=0.7).show(aspect_ratio=(1,1,1)) If we move slightly the axis, we get a goblet-like surface:: sage: revolution_plot3d(f,(u,0,2),axis=(1,0.2),show_curve=True,opacity=0.5).show(aspect_ratio=(1,1,1)) A common problem in calculus books, find the volume within the following revolution solid:: sage: line=u sage: parabola=u^2 sage: sur1=revolution_plot3d(line,(u,0,1),opacity=0.5,rgbcolor=(1,0.5,0),show_curve=True,parallel_axis='x') sage: sur2=revolution_plot3d(parabola,(u,0,1),opacity=0.5,rgbcolor=(0,1,0),show_curve=True,parallel_axis='x') sage: (sur1+sur2).show() Now let's revolve a parametrically defined circle. We can play with the topology of the surface by changing the axis, an axis in `(0,0)` (as the previous one) will produce a sphere-like surface:: sage: u = var('u') sage: circle=(cos(u),sin(u)) sage: revolution_plot3d(circle,(u,0,2*pi),axis=(0,0),show_curve=True,opacity=0.5).show(aspect_ratio=(1,1,1)) An axis on `(0,y)` will produce a cylinder-like surface:: sage: revolution_plot3d(circle,(u,0,2*pi),axis=(0,2),show_curve=True,opacity=0.5).show(aspect_ratio=(1,1,1)) And any other axis will produce a torus-like surface:: sage: revolution_plot3d(circle,(u,0,2*pi),axis=(2,0),show_curve=True,opacity=0.5).show(aspect_ratio=(1,1,1)) Now, we can get another goblet-like surface by revolving a curve in 3d:: sage: u = var('u') sage: curve=(u,cos(4*u),u^2) sage: revolution_plot3d(curve,(u,0,2),show_curve=True,parallel_axis='z',axis=(1,.2),opacity=0.5).show(aspect_ratio=(1,1,1)) A curvy curve with only a quarter turn:: sage: u = var('u') sage: curve=(sin(3*u),.8*cos(4*u),cos(u)) sage: revolution_plot3d(curve,(u,0,pi),(0,pi/2),show_curve=True,parallel_axis='z',opacity=0.5).show(aspect_ratio=(1,1,1),frame=False) """ from sage.symbolic.ring import SR from sage.symbolic.constants import pi from sage.functions.other import sqrt from sage.functions.trig import sin from sage.functions.trig import cos from sage.functions.trig import atan2 if parallel_axis not in ['x', 'y', 'z']: raise ValueError("parallel_axis must be either 'x', 'y', or 'z'.") vart = trange[0] if str(vart) == 'phi': phi = SR.var('fi') else: phi = SR.var('phi') if phirange is None: #this if-else provides a phirange phirange = (phi, 0, 2 * pi) elif len(phirange) == 3: phi = phirange[0] pass else: phirange = (phi, phirange[0], phirange[1]) if isinstance(curve, tuple) or isinstance(curve, list): #this if-else provides a vector v to be plotted #if curve is a tuple or a list of length 2, it is interpreted as a parametric curve #in the x-z plane. #if it is of length 3 it is interpreted as a parametric curve in 3d space if len(curve) == 2: x = curve[0] y = 0 z = curve[1] elif len(curve) == 3: x = curve[0] y = curve[1] z = curve[2] else: x = vart y = 0 z = curve if parallel_axis == 'z': x0 = axis[0] y0 = axis[1] # (0,0) must be handled separately for the phase value phase = 0 if x0 != 0 or y0 != 0: phase = atan2((y - y0), (x - x0)) R = sqrt((x - x0)**2 + (y - y0)**2) v = (R * cos(phi + phase) + x0, R * sin(phi + phase) + y0, z) elif parallel_axis == 'x': y0 = axis[0] z0 = axis[1] # (0,0) must be handled separately for the phase value phase = 0 if z0 != 0 or y0 != 0: phase = atan2((z - z0), (y - y0)) R = sqrt((y - y0)**2 + (z - z0)**2) v = (x, R * cos(phi + phase) + y0, R * sin(phi + phase) + z0) elif parallel_axis == 'y': x0 = axis[0] z0 = axis[1] # (0,0) must be handled separately for the phase value phase = 0 if z0 != 0 or x0 != 0: phase = atan2((z - z0), (x - x0)) R = sqrt((x - x0)**2 + (z - z0)**2) v = (R * cos(phi + phase) + x0, y, R * sin(phi + phase) + z0) if print_vector: print(v) if show_curve: curveplot = parametric_plot3d((x, y, z), trange, thickness=2, rgbcolor=(1, 0, 0)) return parametric_plot3d(v, trange, phirange, **kwds) + curveplot return parametric_plot3d(v, trange, phirange, **kwds)
def subexpressions_list(f, pars=None): """ Construct the lists with the intermediate steps on the evaluation of the function. INPUT: - ``f`` -- a symbolic function of several components. - ``pars`` -- a list of the parameters that appear in the function this should be the symbolic constants that appear in f but are not arguments. OUTPUT: - a list of the intermediate subexpressions that appear in the evaluation of f. - a list with the operations used to construct each of the subexpressions. each element of this list is a tuple, formed by a string describing the operation made, and the operands. For the trigonometric functions, some extra expressions will be added. These extra expressions will be used later to compute their derivatives. EXAMPLES:: sage: from sage.interfaces.tides import subexpressions_list sage: var('x,y') (x, y) sage: f(x,y) = [x^2+y, cos(x)/log(y)] sage: subexpressions_list(f) ([x^2, x^2 + y, sin(x), cos(x), log(y), cos(x)/log(y)], [('mul', x, x), ('add', y, x^2), ('sin', x), ('cos', x), ('log', y), ('div', log(y), cos(x))]) :: sage: f(a)=[cos(a), arctan(a)] sage: from sage.interfaces.tides import subexpressions_list sage: subexpressions_list(f) ([sin(a), cos(a), a^2, a^2 + 1, arctan(a)], [('sin', a), ('cos', a), ('mul', a, a), ('add', 1, a^2), ('atan', a)]) :: sage: from sage.interfaces.tides import subexpressions_list sage: var('s,b,r') (s, b, r) sage: f(t,x,y,z)= [s*(y-x),x*(r-z)-y,x*y-b*z] sage: subexpressions_list(f,[s,b,r]) ([-y, x - y, s*(x - y), -s*(x - y), -z, r - z, (r - z)*x, -y, (r - z)*x - y, x*y, b*z, -b*z, x*y - b*z], [('mul', -1, y), ('add', -y, x), ('mul', x - y, s), ('mul', -1, s*(x - y)), ('mul', -1, z), ('add', -z, r), ('mul', x, r - z), ('mul', -1, y), ('add', -y, (r - z)*x), ('mul', y, x), ('mul', z, b), ('mul', -1, b*z), ('add', -b*z, x*y)]) :: sage: var('x, y') (x, y) sage: f(x,y)=[exp(x^2+sin(y))] sage: from sage.interfaces.tides import * sage: subexpressions_list(f) ([x^2, sin(y), cos(y), x^2 + sin(y), e^(x^2 + sin(y))], [('mul', x, x), ('sin', y), ('cos', y), ('add', sin(y), x^2), ('exp', x^2 + sin(y))]) """ from sage.functions.trig import sin, cos, arcsin, arctan, arccos variables = f[0].arguments() if not pars: parameters = [] else: parameters = pars varpar = list(parameters) + list(variables) F = symbolic_expression([i(*variables) for i in f]).function(*varpar) lis = flatten([fast_callable(i,vars=varpar).op_list() for i in F], max_level=1) stack = [] const =[] stackcomp=[] detail=[] for i in lis: if i[0] == 'load_arg': stack.append(varpar[i[1]]) elif i[0] == 'ipow': if i[1] in NN: basis = stack[-1] for j in range(i[1]-1): a=stack.pop(-1) detail.append(('mul', a, basis)) stack.append(a*basis) stackcomp.append(stack[-1]) else: detail.append(('pow',stack[-1],i[1])) stack[-1]=stack[-1]**i[1] stackcomp.append(stack[-1]) elif i[0] == 'load_const': const.append(i[1]) stack.append(i[1]) elif i == 'mul': a=stack.pop(-1) b=stack.pop(-1) detail.append(('mul', a, b)) stack.append(a*b) stackcomp.append(stack[-1]) elif i == 'div': a=stack.pop(-1) b=stack.pop(-1) detail.append(('div', a, b)) stack.append(b/a) stackcomp.append(stack[-1]) elif i == 'add': a=stack.pop(-1) b=stack.pop(-1) detail.append(('add',a,b)) stack.append(a+b) stackcomp.append(stack[-1]) elif i == 'pow': a=stack.pop(-1) b=stack.pop(-1) detail.append(('pow', b, a)) stack.append(b**a) stackcomp.append(stack[-1]) elif i[0] == 'py_call' and str(i[1])=='log': a=stack.pop(-1) detail.append(('log', a)) stack.append(log(a)) stackcomp.append(stack[-1]) elif i[0] == 'py_call' and str(i[1])=='exp': a=stack.pop(-1) detail.append(('exp', a)) stack.append(exp(a)) stackcomp.append(stack[-1]) elif i[0] == 'py_call' and str(i[1])=='sin': a=stack.pop(-1) detail.append(('sin', a)) detail.append(('cos', a)) stackcomp.append(sin(a)) stackcomp.append(cos(a)) stack.append(sin(a)) elif i[0] == 'py_call' and str(i[1])=='cos': a=stack.pop(-1) detail.append(('sin', a)) detail.append(('cos', a)) stackcomp.append(sin(a)) stackcomp.append(cos(a)) stack.append(cos(a)) elif i[0] == 'py_call' and str(i[1])=='tan': a=stack.pop(-1) b = sin(a) c = cos(a) detail.append(('sin', a)) detail.append(('cos', a)) detail.append(('div', b, c)) stackcomp.append(b) stackcomp.append(c) stackcomp.append(b/c) stack.append(b/c) elif i[0] == 'py_call' and str(i[1])=='arctan': a=stack.pop(-1) detail.append(('mul', a, a)) detail.append(('add', 1, a*a)) detail.append(('atan', a)) stackcomp.append(a*a) stackcomp.append(1+a*a) stackcomp.append(arctan(a)) stack.append(arctan(a)) elif i[0] == 'py_call' and str(i[1])=='arcsin': a=stack.pop(-1) detail.append(('mul', a, a)) detail.append(('mul', -1, a*a)) detail.append(('add', 1, -a*a)) detail.append(('pow', 1- a*a, 0.5)) detail.append(('asin', a)) stackcomp.append(a*a) stackcomp.append(-a*a) stackcomp.append(1-a*a) stackcomp.append(sqrt(1-a*a)) stackcomp.append(arcsin(a)) stack.append(arcsin(a)) elif i[0] == 'py_call' and str(i[1])=='arccos': a=stack.pop(-1) detail.append(('mul', a, a)) detail.append(('mul', -1, a*a)) detail.append(('add', 1, -a*a)) detail.append(('pow', 1- a*a, 0.5)) detail.append(('mul', -1, sqrt(1-a*a))) detail.append(('acos', a)) stackcomp.append(a*a) stackcomp.append(-a*a) stackcomp.append(1-a*a) stackcomp.append(sqrt(1-a*a)) stackcomp.append(-sqrt(1-a*a)) stackcomp.append(arccos(a)) stack.append(arccos(a)) elif i[0] == 'py_call' and 'sqrt' in str(i[1]): a=stack.pop(-1) detail.append(('pow', a, 0.5)) stackcomp.append(sqrt(a)) stack.append(sqrt(a)) elif i == 'neg': a = stack.pop(-1) detail.append(('mul', -1, a)) stack.append(-a) stackcomp.append(-a) return stackcomp,detail
def _geodesic_between_two_points_d(x1,y1,x2,y2,z0=I): r""" Geodesic path between two points represented in the unit disc by the map w = (z-I)/(z+I) INPUTS: - ''(x1,y1)'' -- starting point (0<y1<=infinity) - ''(x2,y2)'' -- ending point (0<y2<=infinity) - ''z0'' -- (default I) the point in the upper corresponding to the point 0 in the disc. I.e. the transform is w -> (z-I)/(z+I) OUTPUT: - ''ca'' -- a polygonal approximation of a circular arc centered at c and radius r, starting at t0 and ending at t1 EXAMPLES:: sage: l=_geodesic_between_two_points_d(0.1,0.2,0.0,0.5) """ pi=RR.pi() from sage.plot.plot import line from sage.functions.trig import (cos,sin) # First compute the points if(y1<0 or y2<0 ): raise ValueError,"Need points in the upper half-plane! Got y1=%s, y2=%s" %(y1,y2) if(y1==infinity): P1=CC(1 ) else: P1=CC((x1+I*y1-z0)/(x1+I*y1-z0.conjugate())) if(y2==infinity): P2=CC(1 ) else: P2=CC((x2+I*y2-z0)/(x2+I*y2-z0.conjugate())) # First find the endpoints of the completed geodesic in D if(x1==x2): a=CC((x1-z0)/(x1-z0.conjugate())) b=CC(1 ) else: c=RR(y1**2 -y2**2 +x1**2 -x2**2 )/RR(2 *(x1-x2)) r=RR(sqrt(y1**2 +(x1-c)**2 )) a=c-r b=c+r a=CC((a-z0)/(a-z0.conjugate())) b=CC((b-z0)/(b-z0.conjugate())) if( abs(a+b) < 1E-10 ): # On a diagonal return line([[P1.real(),P1.imag()],[P2.real(),P2.imag()]]) th_a=a.argument() th_b=b.argument() # Compute the center of the circle in the disc model if( min(abs(b-1 ),abs(b+1 ))< 1E-10 and min(abs(a-1 ),abs(a+1 ))>1E-10 ): c=b+I*(1 -b*cos(th_a))/sin(th_a) elif( min(abs(b-1 ),abs(b+1 ))> 1E-10 and min(abs(a-1 ),abs(a+1 ))<1E-10 ): c=a+I*(1 -a*cos(th_b))/RR(sin(th_b)) else: cx=(sin(th_b)-sin(th_a))/sin(th_b-th_a) c=cx+I*(1 -cx*cos(th_b))/RR(sin(th_b)) # First find the endpoints of the completed geodesic r=abs(c-a) t1=CC(P1-c).argument() t2=CC(P2-c).argument() #print "t1,t2=",t1,t2 return _circ_arc(t1,t2,c,r)
def f(t): return (radius_arc * cos(t) + center[0], radius_arc * sin(t) + center[1])
def f(t): return exp(I * ((cos(t) + I * sin(t)) * arc_radius + arc_center)) * radius
radius=norm(first_vector) if norm(second_vector)!=radius: raise ValueError("Ellipse not implemented") first_unit_vector=first_vector/radius second_unit_vector=second_vector/radius normal_vector=second_vector-(second_vector*first_unit_vector)*first_unit_vector if norm(normal_vector)==0: print (first_point,second_point) return normal_unit_vector=normal_vector/norm(normal_vector) scalar_product=first_unit_vector*second_unit_vector if abs(scalar_product) == 1: raise ValueError("The points are alligned") angle=arccos(scalar_product) var('t') return parametric_plot3d(center+first_vector*cos(t)+radius*normal_unit_vector*sin(t),(0,angle),**kwds) def _arc(p,q,s,**kwds): #rewrite this to use polar_plot and get points to do filled triangles from sage.misc.functional import det from sage.plot.line import line from sage.misc.functional import norm from sage.symbolic.all import pi from sage.plot.arc import arc p,q,s = map( lambda x: vector(x), [p,q,s]) # to avoid running into division by 0 we set to be colinear vectors that are # almost colinear
def barycentric_projection_matrix(n, angle=0): r""" Returns a family of `n+1` vectors evenly spaced in a real vector space of dimension `n` Those vectors are of norm `1`, the scalar product between any two vector is `1/n`, thus the distance between two tips is constant. The family is built recursively and uniquely determined by the following property: the last vector is `(0,\dots,0,-1)`, and the projection of the first `n` vectors in dimension `n-1`, after appropriate rescaling to norm `1`, retrieves the family for `n-1`. OUTPUT: A matrix with `n+1` columns of height `n` with rational or symbolic coefficients. EXAMPLES: One vector in dimension `0`:: sage: from sage.combinat.root_system.root_lattice_realizations import barycentric_projection_matrix sage: m = barycentric_projection_matrix(0); m [] sage: matrix(QQ,0,1).nrows() 0 sage: matrix(QQ,0,1).ncols() 1 Two vectors in dimension 1:: sage: barycentric_projection_matrix(1) [ 1 -1] Three vectors in dimension 2:: sage: barycentric_projection_matrix(2) [ 1/2*sqrt(3) -1/2*sqrt(3) 0] [ 1/2 1/2 -1] Four vectors in dimension 3:: sage: m = barycentric_projection_matrix(3); m [ 1/3*sqrt(3)*sqrt(2) -1/3*sqrt(3)*sqrt(2) 0 0] [ 1/3*sqrt(2) 1/3*sqrt(2) -2/3*sqrt(2) 0] [ 1/3 1/3 1/3 -1] The columns give four vectors that sum up to zero:: sage: sum(m.columns()) (0, 0, 0) and have regular mutual angles:: sage: m.transpose()*m [ 1 -1/3 -1/3 -1/3] [-1/3 1 -1/3 -1/3] [-1/3 -1/3 1 -1/3] [-1/3 -1/3 -1/3 1] Here is a plot of them:: sage: sum(arrow((0,0,0),x) for x in m.columns()) For 2D drawings of root systems, it is desirable to rotate the result to match with the usual conventions:: sage: barycentric_projection_matrix(2, angle=2*pi/3) [ 1/2 -1 1/2] [ 1/2*sqrt(3) 0 -1/2*sqrt(3)] TESTS:: sage: for n in range(1, 7): ... m = barycentric_projection_matrix(n) ... assert sum(m.columns()).is_zero() ... assert matrix(QQ, n+1,n+1, lambda i,j: 1 if i==j else -1/n) == m.transpose()*m """ from sage.matrix.constructor import matrix from sage.functions.other import sqrt n = ZZ(n) if n == 0: return matrix(QQ, 0, 1) a = 1/n b = sqrt(1-a**2) result = b * barycentric_projection_matrix(n-1) result = result.augment(vector([0]*(n-1))) result = result.stack(matrix([[a]*n+[-1]])) assert sum(result.columns()).is_zero() if angle and n == 2: from sage.functions.trig import sin from sage.functions.trig import cos rotation = matrix([[sin(angle), cos(angle)],[-cos(angle), sin(angle)]]) result = rotation * result result.set_immutable() return result