Riemann Mapping - Symbolic Calculus

Skip to content
Back to top
View this page
Edit this page

# Riemann Mapping

AUTHORS:

- Ethan Van Andel (2009-2011): initial version and upgrades

- Robert Bradshaw (2009): his “complex_plot” was adapted for plot_colored

Development supported by NSF award No. 0702939.

class sage.calculus.riemann.Riemann_Map

  Bases: `object`

  The `Riemann_Map` class computes an interior or exterior Riemann map, or an Ahlfors map of a region given by the supplied boundary curve(s) and center point. The class also provides various methods to evaluate, visualize, or extract data from the map.

  A Riemann map conformally maps a simply connected region in the complex plane to the unit disc. The Ahlfors map does the same thing for multiply connected regions.

  Note that all the methods are numerical. As a result all answers have some imprecision. Moreover, maps computed with small number of collocation points, or for unusually shaped regions, may be very inaccurate. Error computations for the ellipse can be found in the documentation for `analytic_boundary()` and `analytic_interior()`.

  [BSV2010] provides an overview of the Riemann map and discusses the research that lead to the creation of this module.

  INPUT:

  - `fs` – list of the boundaries of the region, given as complex-valued functions with domain \(0\) to \(2*pi\). Note that the outer boundary must be parameterized counter clockwise (i.e. `e^(I*t)`) while the inner boundaries must be clockwise (i.e. `e^(-I*t)`).

  - `fprimes` – list of the derivatives of the boundary functions (Must be in the same order as `fs`)

  - `a` – complex, the center of the Riemann map. Will be mapped to the origin of the unit disc. Note that `a` MUST be within the region in order for the results to be mathematically valid.

  The following inputs may be passed in as named parameters:

  - `N` – integer (default: \(500\)); the number of collocation points used to compute the map. More points will give more accurate results, especially near the boundaries, but will take longer to compute.

  - `exterior` – boolean (default: `False`); if set to `True`, the exterior map will be computed, mapping the exterior of the region to the exterior of the unit circle.

  The following inputs may be passed as named parameters in unusual circumstances:

  - `ncorners` – integer (default: \(4\)); if mapping a figure with (equally t-spaced) corners – corners that make a significant change in the direction of the boundary – better results may be sometimes obtained by accurately giving this parameter. Used to add the proper constant to the theta correspondence function.

  - `opp` – boolean (default: `False`); set to `True` in very rare cases where the theta correspondence function is off by `pi`, that is, if red is mapped left of the origin in the color plot.

  EXAMPLES:

  The unit circle identity map:

  Sage

      sage: f(t) = e^(I*t)
      sage: fprime(t) = I*e^(I*t)
      sage: m = Riemann_Map([f], [fprime], 0)  # long time (4 sec)
      sage: m.plot_colored() + m.plot_spiderweb()  # long time
      Graphics object consisting of 22 graphics primitives

  Python

      >>> from sage.all import *
      >>> __tmp__=var("t"); f = symbolic_expression(e**(I*t)).function(t)
      >>> __tmp__=var("t"); fprime = symbolic_expression(I*e**(I*t)).function(t)
      >>> m = Riemann_Map([f], [fprime], Integer(0))  # long time (4 sec)
      >>> m.plot_colored() + m.plot_spiderweb()  # long time
      Graphics object consisting of 22 graphics primitives

  The exterior map for the unit circle:

  Sage

      sage: m = Riemann_Map([f], [fprime], 0, exterior=True)  # long time (4 sec)
      sage: #spiderwebs are not supported for exterior maps
      sage: m.plot_colored() # long time
      Graphics object consisting of 1 graphics primitive

  [Python]

      >>> from sage.all import *
      >>> m = Riemann_Map([f], [fprime], Integer(0), exterior=True)  # long time (4 sec)
      >>> #spiderwebs are not supported for exterior maps
      >>> m.plot_colored() # long time
      Graphics object consisting of 1 graphics primitive

  The unit circle with a small hole:

  Sage

      sage: f(t) = e^(I*t)
      sage: fprime(t) = I*e^(I*t)
      sage: hf(t) = 0.5*e^(-I*t)
      sage: hfprime(t) = 0.5*-I*e^(-I*t)
      sage: m = Riemann_Map([f, hf], [fprime, hfprime], 0.5 + 0.5*I)
      sage: #spiderweb and color plots cannot be added for multiply
      sage: #connected regions. Instead we do this.
      sage: m.plot_spiderweb(withcolor = True)  # long time
      Graphics object consisting of 3 graphics primitives

  Python

      >>> from sage.all import *
      >>> __tmp__=var("t"); f = symbolic_expression(e**(I*t)).function(t)
      >>> __tmp__=var("t"); fprime = symbolic_expression(I*e**(I*t)).function(t)
      >>> __tmp__=var("t"); hf = symbolic_expression(RealNumber('0.5')*e**(-I*t)).function(t)
      >>> __tmp__=var("t"); hfprime = symbolic_expression(RealNumber('0.5')*-I*e**(-I*t)).function(t)
      >>> m = Riemann_Map([f, hf], [fprime, hfprime], RealNumber('0.5') + RealNumber('0.5')*I)
      >>> #spiderweb and color plots cannot be added for multiply
      >>> #connected regions. Instead we do this.
      >>> m.plot_spiderweb(withcolor = True)  # long time
      Graphics object consisting of 3 graphics primitives

  A square:

  Sage

      sage: ps = polygon_spline([(-1, -1), (1, -1), (1, 1), (-1, 1)])
      sage: f = lambda t: ps.value(real(t))
      sage: fprime = lambda t: ps.derivative(real(t))
      sage: m = Riemann_Map([f], [fprime], 0.25, ncorners=4)
      sage: m.plot_colored() + m.plot_spiderweb()  # long time
      Graphics object consisting of 22 graphics primitives

  [Python]

      >>> from sage.all import *
      >>> ps = polygon_spline([(-Integer(1), -Integer(1)), (Integer(1), -Integer(1)), (Integer(1), Integer(1)), (-Integer(1), Integer(1))])
      >>> f = lambda t: ps.value(real(t))
      >>> fprime = lambda t: ps.derivative(real(t))
      >>> m = Riemann_Map([f], [fprime], RealNumber('0.25'), ncorners=Integer(4))
      >>> m.plot_colored() + m.plot_spiderweb()  # long time
      Graphics object consisting of 22 graphics primitives

  Compute rough error for this map:

  Sage

      sage: x = 0.75  # long time
      sage: print("error = {}".format(m.inverse_riemann_map(m.riemann_map(x)) - x))  # long time
      error = (-0.000...+0.0016...j)

  Python

      >>> from sage.all import *
      >>> x = RealNumber('0.75')  # long time
      >>> print("error = {}".format(m.inverse_riemann_map(m.riemann_map(x)) - x))  # long time
      error = (-0.000...+0.0016...j)

  A fun, complex region for demonstration purposes:

  Sage

      sage: f(t) = e^(I*t)
      sage: fp(t) = I*e^(I*t)
      sage: ef1(t) = .2*e^(-I*t) +.4+.4*I
      sage: ef1p(t) = -I*.2*e^(-I*t)
      sage: ef2(t) = .2*e^(-I*t) -.4+.4*I
      sage: ef2p(t) = -I*.2*e^(-I*t)
      sage: pts = [(-.5,-.15-20/1000),(-.6,-.27-10/1000),(-.45,-.45),(0,-.65+10/1000),(.45,-.45),(.6,-.27-10/1000),(.5,-.15-10/1000),(0,-.43+10/1000)]
      sage: pts.reverse()
      sage: cs = complex_cubic_spline(pts)
      sage: mf = lambda x:cs.value(x)
      sage: mfprime = lambda x: cs.derivative(x)
      sage: m = Riemann_Map([f,ef1,ef2,mf],[fp,ef1p,ef2p,mfprime],0,N = 400) # long time
      sage: p = m.plot_colored(plot_points = 400) # long time

  [Python]

      >>> from sage.all import *
      >>> __tmp__=var("t"); f = symbolic_expression(e**(I*t)).function(t)
      >>> __tmp__=var("t"); fp = symbolic_expression(I*e**(I*t)).function(t)
      >>> __tmp__=var("t"); ef1 = symbolic_expression(RealNumber('.2')*e**(-I*t) +RealNumber('.4')+RealNumber('.4')*I).function(t)
      >>> __tmp__=var("t"); ef1p = symbolic_expression(-I*RealNumber('.2')*e**(-I*t)).function(t)
      >>> __tmp__=var("t"); ef2 = symbolic_expression(RealNumber('.2')*e**(-I*t) -RealNumber('.4')+RealNumber('.4')*I).function(t)
      >>> __tmp__=var("t"); ef2p = symbolic_expression(-I*RealNumber('.2')*e**(-I*t)).function(t)
      >>> pts = [(-RealNumber('.5'),-RealNumber('.15')-Integer(20)/Integer(1000)),(-RealNumber('.6'),-RealNumber('.27')-Integer(10)/Integer(1000)),(-RealNumber('.45'),-RealNumber('.45')),(Integer(0),-RealNumber('.65')+Integer(10)/Integer(1000)),(RealNumber('.45'),-RealNumber('.45')),(RealNumber('.6'),-RealNumber('.27')-Integer(10)/Integer(1000)),(RealNumber('.5'),-RealNumber('.15')-Integer(10)/Integer(1000)),(Integer(0),-RealNumber('.43')+Integer(10)/Integer(1000))]
      >>> pts.reverse()
      >>> cs = complex_cubic_spline(pts)
      >>> mf = lambda x:cs.value(x)
      >>> mfprime = lambda x: cs.derivative(x)
      >>> m = Riemann_Map([f,ef1,ef2,mf],[fp,ef1p,ef2p,mfprime],Integer(0),N = Integer(400)) # long time
      >>> p = m.plot_colored(plot_points = Integer(400)) # long time

  ALGORITHM:

  This class computes the Riemann Map via the Szego kernel using an adaptation of the method described by [KT1986].

  compute_on_grid(plot_range, x_points)

    Compute the Riemann map on a grid of points.

    Note that these points are complex of the form z = x + y*i.

    INPUT:

    - `plot_range` – tuple of the form `[xmin, xmax, ymin, ymax]`; if the value is `[]`, the default plotting window of the map will be used

    - `x_points` – integer; the size of the grid in the x direction; the number of points in the y direction is scaled accordingly

    OUTPUT:

    - a tuple containing `[z_values, xmin, xmax, ymin, ymax]` where `z_values` is the evaluation of the map on the specified grid.

    EXAMPLES:

    General usage:

    Sage

        sage: f(t) = e^(I*t) - 0.5*e^(-I*t)
        sage: fprime(t) = I*e^(I*t) + 0.5*I*e^(-I*t)
        sage: m = Riemann_Map([f], [fprime], 0)
        sage: data = m.compute_on_grid([],5)
        sage: data[0][8,1]
        (-0.0879...+0.9709...j)

    Python

        >>> from sage.all import *
        >>> __tmp__=var("t"); f = symbolic_expression(e**(I*t) - RealNumber('0.5')*e**(-I*t)).function(t)
        >>> __tmp__=var("t"); fprime = symbolic_expression(I*e**(I*t) + RealNumber('0.5')*I*e**(-I*t)).function(t)
        >>> m = Riemann_Map([f], [fprime], Integer(0))
        >>> data = m.compute_on_grid([],Integer(5))
        >>> data[Integer(0)][Integer(8),Integer(1)]
        (-0.0879...+0.9709...j)

  get_szego(boundary=-1, absolute_value=False)

    Return a discretized version of the Szego kernel for each boundary function.

    INPUT:

    The following inputs may be passed in as named parameters:

    - `boundary` – integer (default: \(-1\)); if < 0, `get_theta_points()` will return the points for all boundaries. If >= 0, `get_theta_points()` will return only the points for the boundary specified.

    - `absolute_value` – boolean (default: `False`); if `True`, will return the absolute value of the (complex valued) Szego kernel instead of the kernel itself. Useful for plotting.

    OUTPUT:

    A list of points of the form `[t value, value of the Szego kernel at that t]`.

    EXAMPLES:

    Generic use:

    Sage

        sage: f(t) = e^(I*t) - 0.5*e^(-I*t)
        sage: fprime(t) = I*e^(I*t) + 0.5*I*e^(-I*t)
        sage: m = Riemann_Map([f], [fprime], 0)
        sage: sz = m.get_szego(boundary=0)
        sage: points = m.get_szego(absolute_value=True)
        sage: list_plot(points)                                                     # needs sage.plot
        Graphics object consisting of 1 graphics primitive

    Python

        >>> from sage.all import *
        >>> __tmp__=var("t"); f = symbolic_expression(e**(I*t) - RealNumber('0.5')*e**(-I*t)).function(t)
        >>> __tmp__=var("t"); fprime = symbolic_expression(I*e**(I*t) + RealNumber('0.5')*I*e**(-I*t)).function(t)
        >>> m = Riemann_Map([f], [fprime], Integer(0))
        >>> sz = m.get_szego(boundary=Integer(0))
        >>> points = m.get_szego(absolute_value=True)
        >>> list_plot(points)                                                     # needs sage.plot
        Graphics object consisting of 1 graphics primitive

    Extending the points by a spline:

    Sage

        sage: s = spline(points)
        sage: s(3*pi / 4)
        0.0012158...
        sage: plot(s,0,2*pi)  # plot the kernel                                     # needs sage.plot
        Graphics object consisting of 1 graphics primitive

    [Python]

        >>> from sage.all import *
        >>> s = spline(points)
        >>> s(Integer(3)*pi / Integer(4))
        0.0012158...
        >>> plot(s,Integer(0),Integer(2)*pi)  # plot the kernel                                     # needs sage.plot
        Graphics object consisting of 1 graphics primitive

    The unit circle with a small hole:

    Sage

        sage: f(t) = e^(I*t)
        sage: fprime(t) = I*e^(I*t)
        sage: hf(t) = 0.5*e^(-I*t)
        sage: hfprime(t) = 0.5*-I*e^(-I*t)
        sage: m = Riemann_Map([f, hf], [fprime, hfprime], 0.5 + 0.5*I)

    Python

        >>> from sage.all import *
        >>> __tmp__=var("t"); f = symbolic_expression(e**(I*t)).function(t)
        >>> __tmp__=var("t"); fprime = symbolic_expression(I*e**(I*t)).function(t)
        >>> __tmp__=var("t"); hf = symbolic_expression(RealNumber('0.5')*e**(-I*t)).function(t)
        >>> __tmp__=var("t"); hfprime = symbolic_expression(RealNumber('0.5')*-I*e**(-I*t)).function(t)
        >>> m = Riemann_Map([f, hf], [fprime, hfprime], RealNumber('0.5') + RealNumber('0.5')*I)

    Getting the szego for a specific boundary:

    Sage

        sage: sz0 = m.get_szego(boundary=0)
        sage: sz1 = m.get_szego(boundary=1)

    [Python]

        >>> from sage.all import *
        >>> sz0 = m.get_szego(boundary=Integer(0))
        >>> sz1 = m.get_szego(boundary=Integer(1))

  get_theta_points(boundary=-1)

    Return an array of points of the form `[t value, theta in e^(I*theta)]`, that is, a discretized version of the theta/boundary correspondence function. In other words, a point in this array [t1, t2] represents that the boundary point given by f(t1) is mapped to a point on the boundary of the unit circle given by e^(I*t2).

    For multiply connected domains, `get_theta_points` will list the points for each boundary in the order that they were supplied.

    INPUT:

    The following input must all be passed in as named parameters:

    - `boundary` – integer (default: \(-1\)); if < 0, `get_theta_points()` will return the points for all boundaries. If >= 0, `get_theta_points()` will return only the points for the boundary specified.

    OUTPUT:

    A list of points of the form `[t value, theta in e^(I*theta)]`.

    EXAMPLES:

    Getting the list of points, extending it via a spline, getting the points for only the outside of a multiply connected domain:

    Sage

        sage: f(t) = e^(I*t) - 0.5*e^(-I*t)
        sage: fprime(t) = I*e^(I*t) + 0.5*I*e^(-I*t)
        sage: m = Riemann_Map([f], [fprime], 0)
        sage: points = m.get_theta_points()
        sage: list_plot(points)                                                     # needs sage.plot
        Graphics object consisting of 1 graphics primitive

    Python

        >>> from sage.all import *
        >>> __tmp__=var("t"); f = symbolic_expression(e**(I*t) - RealNumber('0.5')*e**(-I*t)).function(t)
        >>> __tmp__=var("t"); fprime = symbolic_expression(I*e**(I*t) + RealNumber('0.5')*I*e**(-I*t)).function(t)
        >>> m = Riemann_Map([f], [fprime], Integer(0))
        >>> points = m.get_theta_points()
        >>> list_plot(points)                                                     # needs sage.plot
        Graphics object consisting of 1 graphics primitive

    Extending the points by a spline:

    Sage

        sage: s = spline(points)
        sage: s(3*pi / 4)
        1.627660...

    [Python]

        >>> from sage.all import *
        >>> s = spline(points)
        >>> s(Integer(3)*pi / Integer(4))
        1.627660...

    The unit circle with a small hole:

    Sage

        sage: f(t) = e^(I*t)
        sage: fprime(t) = I*e^(I*t)
        sage: hf(t) = 0.5*e^(-I*t)
        sage: hfprime(t) = 0.5*-I*e^(-I*t)
        sage: m = Riemann_Map([f, hf], [hf, hfprime], 0.5 + 0.5*I)

    Python

        >>> from sage.all import *
        >>> __tmp__=var("t"); f = symbolic_expression(e**(I*t)).function(t)
        >>> __tmp__=var("t"); fprime = symbolic_expression(I*e**(I*t)).function(t)
        >>> __tmp__=var("t"); hf = symbolic_expression(RealNumber('0.5')*e**(-I*t)).function(t)
        >>> __tmp__=var("t"); hfprime = symbolic_expression(RealNumber('0.5')*-I*e**(-I*t)).function(t)
        >>> m = Riemann_Map([f, hf], [hf, hfprime], RealNumber('0.5') + RealNumber('0.5')*I)

    Getting the boundary correspondence for a specific boundary:

    Sage

        sage: tp0 = m.get_theta_points(boundary=0)
        sage: tp1 = m.get_theta_points(boundary=1)

    [Python]

        >>> from sage.all import *
        >>> tp0 = m.get_theta_points(boundary=Integer(0))
        >>> tp1 = m.get_theta_points(boundary=Integer(1))

  inverse_riemann_map(pt)

    Return the inverse Riemann mapping of a point.

    That is, given `pt` on the interior of the unit disc, `inverse_riemann_map()` will return the point on the original region that would be Riemann mapped to `pt`. Note that this method does not work for multiply connected domains.

    INPUT:

    - `pt` – a complex number (usually with absolute value <= 1) representing the point to be inverse mapped

    OUTPUT: the point on the region that Riemann maps to the input point

    EXAMPLES:

    Can work for different types of complex numbers:

    Sage

        sage: f(t) = e^(I*t) - 0.5*e^(-I*t)
        sage: fprime(t) = I*e^(I*t) + 0.5*I*e^(-I*t)
        sage: m = Riemann_Map([f], [fprime], 0)
        sage: m.inverse_riemann_map(0.5 + sqrt(-0.5))
        (0.406880...+0.3614702...j)
        sage: m.inverse_riemann_map(0.95)
        (0.486319...-4.90019052...j)
        sage: m.inverse_riemann_map(0.25 - 0.3*I)
        (0.1653244...-0.180936...j)
        sage: m.inverse_riemann_map(complex(-0.2, 0.5))
        (-0.156280...+0.321819...j)

    Python

        >>> from sage.all import *
        >>> __tmp__=var("t"); f = symbolic_expression(e**(I*t) - RealNumber('0.5')*e**(-I*t)).function(t)
        >>> __tmp__=var("t"); fprime = symbolic_expression(I*e**(I*t) + RealNumber('0.5')*I*e**(-I*t)).function(t)
        >>> m = Riemann_Map([f], [fprime], Integer(0))
        >>> m.inverse_riemann_map(RealNumber('0.5') + sqrt(-RealNumber('0.5')))
        (0.406880...+0.3614702...j)
        >>> m.inverse_riemann_map(RealNumber('0.95'))
        (0.486319...-4.90019052...j)
        >>> m.inverse_riemann_map(RealNumber('0.25') - RealNumber('0.3')*I)
        (0.1653244...-0.180936...j)
        >>> m.inverse_riemann_map(complex(-RealNumber('0.2'), RealNumber('0.5')))
        (-0.156280...+0.321819...j)

  plot_boundaries(plotjoined=True, rgbcolor=None, thickness=1)

    Plot the boundaries of the region for the Riemann map.

    Note that this method DOES work for multiply connected domains.

    INPUT:

    The following inputs may be passed in as named parameters:

    - `plotjoined` – boolean (default: `True`); if `False`, discrete points will be drawn; otherwise they will be connected by lines. In this case, if `plotjoined=False`, the points shown will be the original collocation points used to generate the Riemann map.

    - `rgbcolor` – float array (default: `[0,0,0]`) the red-green-blue color of the boundary

    - `thickness` – positive float (default: `1`) the thickness of the lines or points in the boundary

    EXAMPLES:

    General usage:

    Sage

        sage: f(t) = e^(I*t) - 0.5*e^(-I*t)
        sage: fprime(t) = I*e^(I*t) + 0.5*I*e^(-I*t)
        sage: m = Riemann_Map([f], [fprime], 0)

    Python

        >>> from sage.all import *
        >>> __tmp__=var("t"); f = symbolic_expression(e**(I*t) - RealNumber('0.5')*e**(-I*t)).function(t)
        >>> __tmp__=var("t"); fprime = symbolic_expression(I*e**(I*t) + RealNumber('0.5')*I*e**(-I*t)).function(t)
        >>> m = Riemann_Map([f], [fprime], Integer(0))

    Default plot:

    Sage

        sage: m.plot_boundaries()                                                   # needs sage.plot
        Graphics object consisting of 1 graphics primitive

    [Python]

        >>> from sage.all import *
        >>> m.plot_boundaries()                                                   # needs sage.plot
        Graphics object consisting of 1 graphics primitive

    Big blue collocation points:

    Sage

        sage: m.plot_boundaries(plotjoined=False, rgbcolor=[0,0,1], thickness=6)    # needs sage.plot
        Graphics object consisting of 1 graphics primitive

    Python

        >>> from sage.all import *
        >>> m.plot_boundaries(plotjoined=False, rgbcolor=[Integer(0),Integer(0),Integer(1)], thickness=Integer(6))    # needs sage.plot
        Graphics object consisting of 1 graphics primitive

  plot_colored(plot_range=None, plot_points=100, interpolation='catrom', **options)

    Generate a colored plot of the Riemann map.

    A red point on the colored plot corresponds to a red point on the unit disc.

    INPUT:

    The following inputs may be passed in as named parameters:

    - `plot_range` – (default: `[]`) list of 4 values `(xmin, xmax, ymin, ymax)`. Declare if you do not want the plot to use the default range for the figure.

    - `plot_points` – integer (default: 100); number of points to plot in the x direction. Points in the y direction are scaled accordingly. Note that very large values can cause this function to run slowly.

    EXAMPLES:

    Given a Riemann map m, general usage:

    Sage

        sage: f(t) = e^(I*t) - 0.5*e^(-I*t)
        sage: fprime(t) = I*e^(I*t) + 0.5*I*e^(-I*t)
        sage: m = Riemann_Map([f], [fprime], 0)
        sage: m.plot_colored()                                                      # needs sage.plot
        Graphics object consisting of 1 graphics primitive

    Python

        >>> from sage.all import *
        >>> __tmp__=var("t"); f = symbolic_expression(e**(I*t) - RealNumber('0.5')*e**(-I*t)).function(t)
        >>> __tmp__=var("t"); fprime = symbolic_expression(I*e**(I*t) + RealNumber('0.5')*I*e**(-I*t)).function(t)
        >>> m = Riemann_Map([f], [fprime], Integer(0))
        >>> m.plot_colored()                                                      # needs sage.plot
        Graphics object consisting of 1 graphics primitive

    Plot zoomed in on a specific spot:

    Sage

        sage: m.plot_colored(plot_range=[0,1,.25,.75])                              # needs sage.plot
        Graphics object consisting of 1 graphics primitive

    [Python]

        >>> from sage.all import *
        >>> m.plot_colored(plot_range=[Integer(0),Integer(1),RealNumber('.25'),RealNumber('.75')])                              # needs sage.plot
        Graphics object consisting of 1 graphics primitive

    High resolution plot:

    Sage

        sage: m.plot_colored(plot_points=1000)      # long time (29s on sage.math, 2012), needs sage.plot
        Graphics object consisting of 1 graphics primitive

    Python

        >>> from sage.all import *
        >>> m.plot_colored(plot_points=Integer(1000))      # long time (29s on sage.math, 2012), needs sage.plot
        Graphics object consisting of 1 graphics primitive

    To generate the unit circle map, it’s helpful to see what the colors correspond to:

    Sage

        sage: f(t) = e^(I*t)
        sage: fprime(t) = I*e^(I*t)
        sage: m = Riemann_Map([f], [fprime], 0, 1000)
        sage: m.plot_colored()                                                      # needs sage.plot
        Graphics object consisting of 1 graphics primitive

    [Python]

        >>> from sage.all import *
        >>> __tmp__=var("t"); f = symbolic_expression(e**(I*t)).function(t)
        >>> __tmp__=var("t"); fprime = symbolic_expression(I*e**(I*t)).function(t)
        >>> m = Riemann_Map([f], [fprime], Integer(0), Integer(1000))
        >>> m.plot_colored()                                                      # needs sage.plot
        Graphics object consisting of 1 graphics primitive

  plot_spiderweb(spokes=16, circles=4, pts=32, linescale=0.99, rgbcolor=None, thickness=1, plotjoined=True, withcolor=False, plot_points=200, min_mag=0.001, interpolation='catrom', **options)

    Generate a traditional “spiderweb plot” of the Riemann map.

    This shows what concentric circles and radial lines map to. The radial lines may exhibit erratic behavior near the boundary; if this occurs, decreasing `linescale` may mitigate the problem.

    For multiply connected domains the spiderweb is by necessity generated using the forward mapping. This method is more computationally intensive. In addition, these spiderwebs cannot be `added` to color plots. Instead the `withcolor` option must be used.

    In addition, spiderweb plots are not currently supported for exterior maps.

    INPUT:

    The following inputs may be passed in as named parameters:

    - `spokes` – integer (default: 16); the number of equally spaced radial lines to plot

    - `circles` – integer (default: 4); the number of equally spaced circles about the center to plot

    - `pts` – integer (default: 32); the number of points to plot. Each radial line is made by `1*pts` points, each circle has `2*pts` points. Note that high values may cause erratic behavior of the radial lines near the boundaries. - only for simply connected domains

    - `linescale` – float between 0 and 1; shrinks the radial lines away from the boundary to reduce erratic behavior - only for simply connected domains

    - `rgbcolor` – float array (default: `[0,0,0]`); the red-green-blue color of the spiderweb

    - `thickness` – positive float (default: 1); the thickness of the lines or points in the spiderweb

    - `plotjoined` – boolean (default: `True`); if `False`, discrete points will be drawn; otherwise they will be connected by lines - only for simply connected domains

    - `withcolor` – boolean (default: `False`); if `True`, the spiderweb will be overlaid on the basic color plot

    - `plot_points` – integer (default: 200); the size of the grid in the x direction. The number of points in the y_direction is scaled accordingly. Note that very large values can cause this function to run slowly. - only for multiply connected domains

    - `min_mag` – float (default: 0.001); the magnitude cutoff below which spiderweb points are not drawn. This only applies to multiply connected domains and is designed to prevent “fuzz” at the edge of the domain. Some complicated multiply connected domains (particularly those with corners) may require a larger value to look clean outside.

    EXAMPLES:

    General usage:

    Sage

        sage: f(t) = e^(I*t) - 0.5*e^(-I*t)
        sage: fprime(t) = I*e^(I*t) + 0.5*I*e^(-I*t)
        sage: m = Riemann_Map([f], [fprime], 0)

    Python

        >>> from sage.all import *
        >>> __tmp__=var("t"); f = symbolic_expression(e**(I*t) - RealNumber('0.5')*e**(-I*t)).function(t)
        >>> __tmp__=var("t"); fprime = symbolic_expression(I*e**(I*t) + RealNumber('0.5')*I*e**(-I*t)).function(t)
        >>> m = Riemann_Map([f], [fprime], Integer(0))

    Default plot:

    Sage

        sage: m.plot_spiderweb()                                                    # needs sage.plot
        Graphics object consisting of 21 graphics primitives

    [Python]

        >>> from sage.all import *
        >>> m.plot_spiderweb()                                                    # needs sage.plot
        Graphics object consisting of 21 graphics primitives

    Simplified plot with many discrete points:

    Sage

        sage: m.plot_spiderweb(spokes=4, circles=1, pts=400,                        # needs sage.plot
        ....:                  linescale=0.95, plotjoined=False)
        Graphics object consisting of 6 graphics primitives

    Python

        >>> from sage.all import *
        >>> m.plot_spiderweb(spokes=Integer(4), circles=Integer(1), pts=Integer(400),                        # needs sage.plot
        ...                  linescale=RealNumber('0.95'), plotjoined=False)
        Graphics object consisting of 6 graphics primitives

    Plot with thick, red lines:

    Sage

        sage: m.plot_spiderweb(rgbcolor=[1,0,0], thickness=3)                       # needs sage.plot
        Graphics object consisting of 21 graphics primitives

    [Python]

        >>> from sage.all import *
        >>> m.plot_spiderweb(rgbcolor=[Integer(1),Integer(0),Integer(0)], thickness=Integer(3))                       # needs sage.plot
        Graphics object consisting of 21 graphics primitives

    To generate the unit circle map, it’s helpful to see what the original spiderweb looks like:

    Sage

        sage: f(t) = e^(I*t)
        sage: fprime(t) = I*e^(I*t)
        sage: m = Riemann_Map([f], [fprime], 0, 1000)
        sage: m.plot_spiderweb()                                                    # needs sage.plot
        Graphics object consisting of 21 graphics primitives

    Python

        >>> from sage.all import *
        >>> __tmp__=var("t"); f = symbolic_expression(e**(I*t)).function(t)
        >>> __tmp__=var("t"); fprime = symbolic_expression(I*e**(I*t)).function(t)
        >>> m = Riemann_Map([f], [fprime], Integer(0), Integer(1000))
        >>> m.plot_spiderweb()                                                    # needs sage.plot
        Graphics object consisting of 21 graphics primitives

    A multiply connected region with corners. We set `min_mag` higher to remove “fuzz” outside the domain:

    Sage

        sage: ps = polygon_spline([(-4,-2),(4,-2),(4,2),(-4,2)])
        sage: z1 = lambda t: ps.value(t); z1p = lambda t: ps.derivative(t)
        sage: z2(t) = -2+exp(-I*t); z2p(t) = -I*exp(-I*t)
        sage: z3(t) = 2+exp(-I*t); z3p(t) = -I*exp(-I*t)
        sage: m = Riemann_Map([z1,z2,z3], [z1p,z2p,z3p], 0,             # long time
        ....:                 ncorners=4)
        sage: p = m.plot_spiderweb(withcolor=True, plot_points=500,         # long time, needs sage.plot
        ....:                      thickness=2.0, min_mag=0.1)

    [Python]

        >>> from sage.all import *
        >>> ps = polygon_spline([(-Integer(4),-Integer(2)),(Integer(4),-Integer(2)),(Integer(4),Integer(2)),(-Integer(4),Integer(2))])
        >>> z1 = lambda t: ps.value(t); z1p = lambda t: ps.derivative(t)
        >>> __tmp__=var("t"); z2 = symbolic_expression(-Integer(2)+exp(-I*t)).function(t); __tmp__=var("t"); z2p = symbolic_expression(-I*exp(-I*t)).function(t)
        >>> __tmp__=var("t"); z3 = symbolic_expression(Integer(2)+exp(-I*t)).function(t); __tmp__=var("t"); z3p = symbolic_expression(-I*exp(-I*t)).function(t)
        >>> m = Riemann_Map([z1,z2,z3], [z1p,z2p,z3p], Integer(0),             # long time
        ...                 ncorners=Integer(4))
        >>> p = m.plot_spiderweb(withcolor=True, plot_points=Integer(500),         # long time, needs sage.plot
        ...                      thickness=RealNumber('2.0'), min_mag=RealNumber('0.1'))

  riemann_map(pt)

    Return the Riemann mapping of a point.

    That is, given `pt` on the interior of the mapped region, `riemann_map` will return the point on the unit disk that `pt` maps to. Note that this method only works for interior points; accuracy breaks down very close to the boundary. To get boundary correspondence, use `get_theta_points()`.

    INPUT:

    - `pt` – a complex number representing the point to be inverse mapped

    OUTPUT:

    A complex number representing the point on the unit circle that the input point maps to.

    EXAMPLES:

    Can work for different types of complex numbers:

    Sage

        sage: f(t) = e^(I*t) - 0.5*e^(-I*t)
        sage: fprime(t) = I*e^(I*t) + 0.5*I*e^(-I*t)
        sage: m = Riemann_Map([f], [fprime], 0)
        sage: m.riemann_map(0.25 + sqrt(-0.5))
        (0.137514...+0.876696...j)
        sage: I = CDF.gen()
        sage: m.riemann_map(1.3*I)
        (-1.56...e-05+0.989694...j)
        sage: m.riemann_map(0.4)
        (0.73324...+3.2...e-06j)
        sage: m.riemann_map(complex(-3, 0.0001))
        (1.405757...e-05+8.06...e-10j)

    Python

        >>> from sage.all import *
        >>> __tmp__=var("t"); f = symbolic_expression(e**(I*t) - RealNumber('0.5')*e**(-I*t)).function(t)
        >>> __tmp__=var("t"); fprime = symbolic_expression(I*e**(I*t) + RealNumber('0.5')*I*e**(-I*t)).function(t)
        >>> m = Riemann_Map([f], [fprime], Integer(0))
        >>> m.riemann_map(RealNumber('0.25') + sqrt(-RealNumber('0.5')))
        (0.137514...+0.876696...j)
        >>> I = CDF.gen()
        >>> m.riemann_map(RealNumber('1.3')*I)
        (-1.56...e-05+0.989694...j)
        >>> m.riemann_map(RealNumber('0.4'))
        (0.73324...+3.2...e-06j)
        >>> m.riemann_map(complex(-Integer(3), RealNumber('0.0001')))
        (1.405757...e-05+8.06...e-10j)

sage.calculus.riemann.analytic_boundary(t, n, epsilon)

  Provides an exact (for \(n = \infty\)) Riemann boundary correspondence for the ellipse with axes \(1 + \epsilon\) and \(1 - \epsilon\). The boundary is therefore given by \(\exp(I t)+\epsilon\exp(-I t)\). It is primarily useful for testing the accuracy of the numerical `Riemann_Map`.

  INPUT:

  - `t` – the boundary parameter, from \(0\) to \(2 \pi\)

  - `n` – integer; the number of terms to include (10 is fairly accurate, 20 is very accurate)

  - `epsilon` – float; the skew of the ellipse (0 is circular)

  OUTPUT:

  A theta value from 0 to 2*pi, corresponding to the point on the circle e^(I*theta)

sage.calculus.riemann.analytic_interior(z, n, epsilon)

  Provide a nearly exact computation of the Riemann Map of an interior point of the ellipse with axes 1 + epsilon and 1 - epsilon.

  It is primarily useful for testing the accuracy of the numerical Riemann Map.

  INPUT:

  - `z` – complex; the point to be mapped

  - `n` – integer; the number of terms to include (10 is fairly accurate, 20 is very accurate)

sage.calculus.riemann.cauchy_kernel(t, args)

  Intermediate function for the integration in `analytic_interior()`.

  INPUT:

  - `t` – the boundary parameter, meant to be integrated over

  - `args` – tuple containing:

    - `epsilon` – float; the skew of the ellipse (0 is circular)

    - `z` – complex; the point to be mapped

    - `n` – integer; the number of terms to include (10 is fairly accurate, 20 is very accurate)

    - `part` – will return the real (‘r’), imaginary (‘i’) or complex (‘c’) value of the kernel

sage.calculus.riemann.complex_to_rgb(z_values)

  Convert from a (Numpy) array of complex numbers to its corresponding matrix of RGB values. For internal use of `plot_colored()` only.

  INPUT:

  - `z_values` – numpy array of complex numbers

  OUTPUT:

  An \(N \times M \times 3\) floating point Numpy array `X`, where `X[i,j]` is an (r,g,b) tuple.

  EXAMPLES:

  Sage

      sage: from sage.calculus.riemann import complex_to_rgb
      sage: import numpy
      sage: complex_to_rgb(numpy.array([[0, 1, 1000]], dtype=numpy.complex128))
      array([[[1.        , 1.        , 1.        ],
              [1.        , 0.05558355, 0.05558355],
              [0.17301243, 0.        , 0.        ]]])

      sage: complex_to_rgb(numpy.array([[0, 1j, 1000j]], dtype=numpy.complex128))
      array([[[1.        , 1.        , 1.        ],
              [0.52779177, 1.        , 0.05558355],
              [0.08650622, 0.17301243, 0.        ]]])

  Python

      >>> from sage.all import *
      >>> from sage.calculus.riemann import complex_to_rgb
      >>> import numpy
      >>> complex_to_rgb(numpy.array([[Integer(0), Integer(1), Integer(1000)]], dtype=numpy.complex128))
      array([[[1.        , 1.        , 1.        ],
              [1.        , 0.05558355, 0.05558355],
              [0.17301243, 0.        , 0.        ]]])

      >>> complex_to_rgb(numpy.array([[Integer(0), ComplexNumber(0, '1'), ComplexNumber(0, '1000')]], dtype=numpy.complex128))
      array([[[1.        , 1.        , 1.        ],
              [0.52779177, 1.        , 0.05558355],
              [0.08650622, 0.17301243, 0.        ]]])

sage.calculus.riemann.complex_to_spiderweb(z_values, dr, dtheta, spokes, circles, rgbcolor, thickness, withcolor, min_mag)

  Convert a grid of complex numbers into a matrix containing rgb data for the Riemann spiderweb plot.

  INPUT:

  - `z_values` – a grid of complex numbers, as a list of lists

  - `dr` – grid of floats, the r derivative of `z_values` Used to determine precision

  - `dtheta` – grid of floats, the theta derivative of `z_values` Used to determine precision

  - `spokes` – integer; the number of equally spaced radial lines to plot

  - `circles` – integer; the number of equally spaced circles about the center to plot

  - `rgbcolor` – float array; the red-green-blue color of the lines of the spiderweb

  - `thickness` – positive float; the thickness of the lines or points in the spiderweb

  - `withcolor` – boolean; if `True` the spiderweb will be overlaid on the basic color plot

  - `min_mag` – float; the magnitude cutoff below which spiderweb points are not drawn. This only applies to multiply connected domains and is designed to prevent “fuzz” at the edge of the domain. Some complicated multiply connected domains (particularly those with corners) may require a larger value to look clean outside.

  OUTPUT:

  An \(N x M x 3\) floating point Numpy array `X`, where `X[i,j]` is an (r,g,b) tuple.

  EXAMPLES:

  Sage

      sage: from sage.calculus.riemann import complex_to_spiderweb
      sage: import numpy
      sage: zval = numpy.array([[0,1,1000], [.2+.3j,1,-.3j], [0,0,0]],
      ....:                    dtype=numpy.complex128)
      sage: deriv = numpy.array([[.1]],dtype = numpy.float64)
      sage: complex_to_spiderweb(zval, deriv, deriv, 4, 4, [0,0,0], 1, False, 0.001)
      array([[[1., 1., 1.],
              [1., 1., 1.],
              [1., 1., 1.]],

             [[1., 1., 1.],
              [0., 0., 0.],
              [1., 1., 1.]],

             [[1., 1., 1.],
              [1., 1., 1.],
              [1., 1., 1.]]])

      sage: complex_to_spiderweb(zval, deriv, deriv, 4, 4, [0,0,0], 1, True, 0.001)
      array([[[1.        , 1.        , 1.        ],
              [1.        , 0.05558355, 0.05558355],
              [0.17301243, 0.        , 0.        ]],

             [[1.        , 0.96804683, 0.48044583],
              [0.        , 0.        , 0.        ],
              [0.77351965, 0.5470393 , 1.        ]],

             [[1.        , 1.        , 1.        ],
              [1.        , 1.        , 1.        ],
              [1.        , 1.        , 1.        ]]])

  Python

      >>> from sage.all import *
      >>> from sage.calculus.riemann import complex_to_spiderweb
      >>> import numpy
      >>> zval = numpy.array([[Integer(0),Integer(1),Integer(1000)], [RealNumber('.2')+ComplexNumber(0, '.3'),Integer(1),-ComplexNumber(0, '.3')], [Integer(0),Integer(0),Integer(0)]],
      ...                    dtype=numpy.complex128)
      >>> deriv = numpy.array([[RealNumber('.1')]],dtype = numpy.float64)
      >>> complex_to_spiderweb(zval, deriv, deriv, Integer(4), Integer(4), [Integer(0),Integer(0),Integer(0)], Integer(1), False, RealNumber('0.001'))
      array([[[1., 1., 1.],
              [1., 1., 1.],
              [1., 1., 1.]],
      <BLANKLINE>
             [[1., 1., 1.],
              [0., 0., 0.],
              [1., 1., 1.]],
      <BLANKLINE>
             [[1., 1., 1.],
              [1., 1., 1.],
              [1., 1., 1.]]])

      >>> complex_to_spiderweb(zval, deriv, deriv, Integer(4), Integer(4), [Integer(0),Integer(0),Integer(0)], Integer(1), True, RealNumber('0.001'))
      array([[[1.        , 1.        , 1.        ],
              [1.        , 0.05558355, 0.05558355],
              [0.17301243, 0.        , 0.        ]],
      <BLANKLINE>
             [[1.        , 0.96804683, 0.48044583],
              [0.        , 0.        , 0.        ],
              [0.77351965, 0.5470393 , 1.        ]],
      <BLANKLINE>
             [[1.        , 1.        , 1.        ],
              [1.        , 1.        , 1.        ],
              [1.        , 1.        , 1.        ]]])

sage.calculus.riemann.get_derivatives(z_values, xstep, ystep)

  Compute the r*e^(I*theta) form of derivatives from the grid of points. The derivatives are computed using quick-and-dirty taylor expansion and assuming analyticity. As such `get_derivatives` is primarily intended to be used for comparisons in `plot_spiderweb` and not for applications that require great precision.

  INPUT:

  - `z_values` – the values for a complex function evaluated on a grid in the complex plane, usually from `compute_on_grid`

  - `xstep` – float, the spacing of the grid points in the real direction

  OUTPUT:

  - A tuple of arrays, [`dr`, `dtheta`], with each array 2 less in both dimensions than `z_values`

    - `dr` – the abs of the derivative of the function in the +r direction

    - `dtheta` – the rate of accumulation of angle in the +theta direction

  EXAMPLES:

  Standard usage with compute_on_grid:

  Sage

      sage: from sage.calculus.riemann import get_derivatives
      sage: f(t) = e^(I*t) - 0.5*e^(-I*t)
      sage: fprime(t) = I*e^(I*t) + 0.5*I*e^(-I*t)
      sage: m = Riemann_Map([f], [fprime], 0)
      sage: data = m.compute_on_grid([],19)
      sage: xstep = (data[2]-data[1])/19
      sage: ystep = (data[4]-data[3])/19
      sage: dr, dtheta = get_derivatives(data[0],xstep,ystep)
      sage: dr[8,8]
      0.241...
      sage: dtheta[5,5]
      5.907...

  Python

      >>> from sage.all import *
      >>> from sage.calculus.riemann import get_derivatives
      >>> __tmp__=var("t"); f = symbolic_expression(e**(I*t) - RealNumber('0.5')*e**(-I*t)).function(t)
      >>> __tmp__=var("t"); fprime = symbolic_expression(I*e**(I*t) + RealNumber('0.5')*I*e**(-I*t)).function(t)
      >>> m = Riemann_Map([f], [fprime], Integer(0))
      >>> data = m.compute_on_grid([],Integer(19))
      >>> xstep = (data[Integer(2)]-data[Integer(1)])/Integer(19)
      >>> ystep = (data[Integer(4)]-data[Integer(3)])/Integer(19)
      >>> dr, dtheta = get_derivatives(data[Integer(0)],xstep,ystep)
      >>> dr[Integer(8),Integer(8)]
      0.241...
      >>> dtheta[Integer(5),Integer(5)]
      5.907...