Ejemplo n.º 1
0
    def _acted_upon_(self, g, self_on_left):
        r"""
        Implements the left action of `SL_2(\ZZ)` on self.

        EXAMPLES::

            sage: g = matrix(ZZ, 2, [1,1,0,1]); g
            [1 1]
            [0 1]
            sage: g * Cusp(2,5)
            7/5
            sage: Cusp(2,5) * g
            Traceback (most recent call last):
            ...
            TypeError: unsupported operand parent(s) for '*': 'Set P^1(QQ) of all cusps' and 'Full MatrixSpace of 2 by 2 dense matrices over Integer Ring'
            sage: h = matrix(ZZ, 2, [12,3,-100,7])
            sage: h * Cusp(2,5)
            -13/55
            sage: Cusp(2,5)._acted_upon_(h, False)
            -13/55
            sage: (h*g) * Cusp(3,7) == h * (g * Cusp(3,7))
            True

            sage: cm = sage.structure.element.get_coercion_model()
            sage: cm.explain(MatrixSpace(ZZ, 2), Cusps)
            Action discovered.
                Left action by Full MatrixSpace of 2 by 2 dense matrices over Integer Ring on Set P^1(QQ) of all cusps
            Result lives in Set P^1(QQ) of all cusps
            Set P^1(QQ) of all cusps
        """
        if not self_on_left:
            if (is_Matrix(g) and g.base_ring() is ZZ
                    and g.ncols() == 2 and g.nrows() == 2):
                a, b, c, d = g.list()
                return Cusp(a*self.__a + b*self.__b, c*self.__a + d*self.__b)
Ejemplo n.º 2
0
 def __init__(self, parent, A):
     """
     INPUT:
     
     
     -  ``parent`` - a homspace
     
     -  ``A`` - matrix
     
     
     EXAMPLES::
     
         sage: from sage.modules.matrix_morphism import MatrixMorphism
         sage: T = End(ZZ^3)
         sage: M = MatrixSpace(ZZ,3)
         sage: I = M.identity_matrix()
         sage: A = MatrixMorphism(T, I)
         sage: loads(A.dumps()) == A
         True
     """
     if not matrix.is_Matrix(A):
         A = matrix.MatrixSpace(parent.category().base_ring(),
                                parent.domain().rank(),
                                parent.codomain().rank())(A)
     R = A.base_ring()
     if A.nrows() != parent.domain().rank():
         raise ArithmeticError, "number of rows of matrix (=%s) must equal rank of domain (=%s)"%(A.nrows(), parent.domain().rank())
     if A.ncols() != parent.codomain().rank():
             raise ArithmeticError, "number of columns of matrix (=%s) must equal rank of codomain (=%s)"%(A.ncols(), parent.codomain().rank())
     self._matrix = A
     MatrixMorphism_abstract.__init__(self, parent)
Ejemplo n.º 3
0
 def __init__(self, parent, A):
     """
     INPUT:
     
     
     -  ``parent`` - a homspace
     
     -  ``A`` - matrix
     
     
     EXAMPLES::
     
         sage: from sage.modules.matrix_morphism import MatrixMorphism
         sage: T = End(ZZ^3)
         sage: M = MatrixSpace(ZZ,3)
         sage: I = M.identity_matrix()
         sage: A = MatrixMorphism(T, I)
         sage: loads(A.dumps()) == A
         True
     """
     if not matrix.is_Matrix(A):
         A = matrix.MatrixSpace(parent.category().base_ring(),
                                parent.domain().rank(),
                                parent.codomain().rank())(A)
     R = A.base_ring()
     if A.nrows() != parent.domain().rank():
         raise ArithmeticError, "number of rows of matrix (=%s) must equal rank of domain (=%s)" % (
             A.nrows(), parent.domain().rank())
     if A.ncols() != parent.codomain().rank():
         raise ArithmeticError, "number of columns of matrix (=%s) must equal rank of codomain (=%s)" % (
             A.ncols(), parent.codomain().rank())
     self._matrix = A
     MatrixMorphism_abstract.__init__(self, parent)
Ejemplo n.º 4
0
def normalize_square_matrices(matrices):
    """
    Find a common space for all matrices.

    OUTPUT:

    A list of matrices, all elements of the same matrix space.

    EXAMPLES::

        sage: from sage.groups.matrix_gps.finitely_generated import normalize_square_matrices
        sage: m1 = [[1,2],[3,4]]
        sage: m2 = [2, 3, 4, 5]
        sage: m3 = matrix(QQ, [[1/2,1/3],[1/4,1/5]])
        sage: m4 = MatrixGroup(m3).gen(0)
        sage: normalize_square_matrices([m1, m2, m3, m4])
        [
        [1 2]  [2 3]  [1/2 1/3]  [1/2 1/3]
        [3 4], [4 5], [1/4 1/5], [1/4 1/5]
        ]
    """
    deg = []
    gens = []
    for m in matrices:
        if is_MatrixGroupElement(m):
            deg.append(m.parent().degree())
            gens.append(m.matrix())
            continue
        if is_Matrix(m):
            if not m.is_square():
                raise TypeError('matrix must be square')
            deg.append(m.ncols())
            gens.append(m)
            continue
        try:
            m = list(m)
        except TypeError:
            gens.append(m)
            continue
        if isinstance(m[0], (list, tuple)):
            m = map(list, m)
            degree = ZZ(len(m))
        else:
            degree, rem = ZZ(len(m)).sqrtrem()
            if rem != 0:
                raise ValueError(
                    'list of plain numbers must have square integer length')
        deg.append(degree)
        gens.append(matrix(degree, degree, m))
    deg = set(deg)
    if len(set(deg)) != 1:
        raise ValueError('not all matrices have the same size')
    gens = Sequence(gens, immutable=True)
    MS = gens.universe()
    if not is_MatrixSpace(MS):
        raise TypeError('all generators must be matrices')
    if MS.nrows() != MS.ncols():
        raise ValueError('matrices must be square')
    return gens
Ejemplo n.º 5
0
def normalize_square_matrices(matrices):
    """
    Find a common space for all matrices.

    OUTPUT:

    A list of matrices, all elements of the same matrix space.

    EXAMPLES::

        sage: from sage.groups.matrix_gps.finitely_generated import normalize_square_matrices
        sage: m1 = [[1,2],[3,4]]
        sage: m2 = [2, 3, 4, 5]
        sage: m3 = matrix(QQ, [[1/2,1/3],[1/4,1/5]])
        sage: m4 = MatrixGroup(m3).gen(0)
        sage: normalize_square_matrices([m1, m2, m3, m4])
        [
        [1 2]  [2 3]  [1/2 1/3]  [1/2 1/3]
        [3 4], [4 5], [1/4 1/5], [1/4 1/5]
        ]
    """
    deg = []
    gens = []
    for m in matrices:
        if is_MatrixGroupElement(m):
            deg.append(m.parent().degree())
            gens.append(m.matrix())
            continue
        if is_Matrix(m):
            if not m.is_square():
                raise TypeError('matrix must be square')
            deg.append(m.ncols())
            gens.append(m)
            continue
        try:
            m = list(m)
        except TypeError:
            gens.append(m)
            continue
        if isinstance(m[0], (list, tuple)):
            m = map(list, m)
            degree = ZZ(len(m))
        else:
            degree, rem = ZZ(len(m)).sqrtrem()
            if rem!=0:
                raise ValueError('list of plain numbers must have square integer length')
        deg.append(degree)
        gens.append(matrix(degree, degree, m))
    deg = set(deg)
    if len(set(deg)) != 1:
        raise ValueError('not all matrices have the same size')
    gens = Sequence(gens, immutable=True)
    MS = gens.universe()
    if not is_MatrixSpace(MS):
        raise TypeError('all generators must be matrices')
    if MS.nrows() != MS.ncols():
        raise ValueError('matrices must be square')
    return gens
Ejemplo n.º 6
0
def jacobian(functions, variables):
    """
    Return the Jacobian matrix, which is the matrix of partial
    derivatives in which the i,j entry of the Jacobian matrix is the
    partial derivative diff(functions[i], variables[j]).

    EXAMPLES::
    
        sage: x,y = var('x,y')
        sage: g=x^2-2*x*y
        sage: jacobian(g, (x,y))
        [2*x - 2*y      -2*x]

    The Jacobian of the Jacobian should give us the "second derivative", which is the Hessian matrix::
    
        sage: jacobian(jacobian(g, (x,y)), (x,y))
        [ 2 -2]
        [-2  0]
        sage: g.hessian()
        [ 2 -2]
        [-2  0]

        sage: f=(x^3*sin(y), cos(x)*sin(y), exp(x))
        sage: jacobian(f, (x,y))
        [  3*x^2*sin(y)     x^3*cos(y)]
        [-sin(x)*sin(y)  cos(x)*cos(y)]
        [           e^x              0]
        sage: jacobian(f, (y,x))
        [    x^3*cos(y)   3*x^2*sin(y)]
        [ cos(x)*cos(y) -sin(x)*sin(y)]
        [             0            e^x]
    
    """
    if is_Matrix(functions) and (functions.nrows() == 1
                                 or functions.ncols() == 1):
        functions = functions.list()
    elif not (isinstance(functions, (tuple, list)) or is_Vector(functions)):
        functions = [functions]

    if not isinstance(variables, (tuple, list)) and not is_Vector(variables):
        variables = [variables]

    return matrix([[diff(f, v) for v in variables] for f in functions])
Ejemplo n.º 7
0
def jacobian(functions, variables):
    """
    Return the Jacobian matrix, which is the matrix of partial
    derivatives in which the i,j entry of the Jacobian matrix is the
    partial derivative diff(functions[i], variables[j]).

    EXAMPLES::

        sage: x,y = var('x,y')
        sage: g=x^2-2*x*y
        sage: jacobian(g, (x,y))
        [2*x - 2*y      -2*x]

    The Jacobian of the Jacobian should give us the "second derivative", which is the Hessian matrix::

        sage: jacobian(jacobian(g, (x,y)), (x,y))
        [ 2 -2]
        [-2  0]
        sage: g.hessian()
        [ 2 -2]
        [-2  0]

        sage: f=(x^3*sin(y), cos(x)*sin(y), exp(x))
        sage: jacobian(f, (x,y))
        [  3*x^2*sin(y)     x^3*cos(y)]
        [-sin(x)*sin(y)  cos(x)*cos(y)]
        [           e^x              0]
        sage: jacobian(f, (y,x))
        [    x^3*cos(y)   3*x^2*sin(y)]
        [ cos(x)*cos(y) -sin(x)*sin(y)]
        [             0            e^x]

    """
    if is_Matrix(functions) and (functions.nrows()==1 or functions.ncols()==1):
        functions = functions.list()
    elif not (isinstance(functions, (tuple, list)) or is_Vector(functions)):
        functions = [functions]

    if not isinstance(variables, (tuple, list)) and not is_Vector(variables):
        variables = [variables]

    return matrix([[diff(f, v) for v in variables] for f in functions])
Ejemplo n.º 8
0
def matrix_plot(mat, **options):
    r"""
    A plot of a given matrix or 2D array.
    
    If the matrix is dense, each matrix element is given a different
    color value depending on its relative size compared to the other
    elements in the matrix.  If the matrix is sparse, colors only
    indicate whether an element is nonzero or zero, so the plot
    represents the sparsity pattern of the matrix.

    The tick marks drawn on the frame axes denote the row numbers
    (vertical ticks) and the column numbers (horizontal ticks) of the
    matrix.

    INPUT:

    - ``mat`` - a 2D matrix or array

    The following input must all be passed in as named parameters, if
    default not used:

    - ``cmap`` - a colormap (default: 'gray'), the name of
      a predefined colormap, a list of colors,
      or an instance of a matplotlib Colormap.
      Type: ``import matplotlib.cm; matplotlib.cm.datad.keys()``
      for available colormap names.

    - ``colorbar`` -- boolean (default: False) Show a colorbar or not (dense matrices only).
    
      The following options are used to adjust the style and placement
      of colorbars.  They have no effect if a colorbar is not shown.

      - ``colorbar_orientation`` -- string (default: 'vertical'),
        controls placement of the colorbar, can be either 'vertical'
        or 'horizontal'

      - ``colorbar_format`` -- a format string, this is used to format
        the colorbar labels.

      - ``colorbar_options`` -- a dictionary of options for the matplotlib
        colorbar API.  Documentation for the :mod:`matplotlib.colorbar` module
        has details.

    - ``norm`` - If None (default), the value range is scaled to the interval
      [0,1].  If 'value', then the actual value is used with no
      scaling.  A :class:`matplotlib.colors.Normalize` instance may
      also passed.

    - ``vmin`` - The minimum value (values below this are set to this value)

    - ``vmax`` - The maximum value (values above this are set to this value)

    - ``origin`` - If 'upper' (default), the first row of the matrix
      is on the top of the graph.  If 'lower', the first row is on the
      bottom of the graph.

    - ``subdivisions`` - If True, plot the subdivisions of the matrix as lines.

    - ``subdivision_boundaries`` - a list of lists in the form
      ``[row_subdivisions, column_subdivisions]``, which specifies
      the row and column subdivisions to use.  If not specified,
      defaults to the matrix subdivisions
    
    - ``subdivision_style`` - a dictionary of properties passed
      on to the :func:`~sage.plot.line.line2d` command for plotting
      subdivisions.  If this is a two-element list or tuple, then it 
      specifies the styles of row and column divisions, respectively.

    EXAMPLES:
    
    A matrix over `\ZZ` colored with different grey levels::
    
        sage: matrix_plot(matrix([[1,3,5,1],[2,4,5,6],[1,3,5,7]]))

    Here we make a random matrix over `\RR` and use ``cmap='hsv'``
    to color the matrix elements different RGB colors::

        sage: matrix_plot(random_matrix(RDF, 50), cmap='hsv')

    By default, entries are scaled to the interval [0,1] before
    determining colors from the color map.  That means the two plots
    below are the same::

        sage: P = matrix_plot(matrix(2,[1,1,3,3]))
        sage: Q = matrix_plot(matrix(2,[2,2,3,3]))
        sage: P; Q

    However, we can specify which values scale to 0 or 1 with the
    ``vmin`` and ``vmax`` parameters (values outside the range are
    clipped).  The two plots below are now distinguished::

        sage: P = matrix_plot(matrix(2,[1,1,3,3]), vmin=0, vmax=3, colorbar=True)
        sage: Q = matrix_plot(matrix(2,[2,2,3,3]), vmin=0, vmax=3, colorbar=True)
        sage: P; Q

    We can also specify a norm function of 'value', which means that
    there is no scaling performed::
    
        sage: matrix_plot(random_matrix(ZZ,10)*.05, norm='value', colorbar=True)

    Matrix subdivisions can be plotted as well::
    
        sage: m=random_matrix(RR,10)
        sage: m.subdivide([2,4],[6,8])
        sage: matrix_plot(m, subdivisions=True, subdivision_style=dict(color='red',thickness=3))
    
    You can also specify your own subdivisions and separate styles
    for row or column subdivisions::
    
        sage: m=random_matrix(RR,10)
        sage: matrix_plot(m, subdivisions=True, subdivision_boundaries=[[2,4],[6,8]], subdivision_style=[dict(color='red',thickness=3),dict(linestyle='--',thickness=6)])

    Generally matrices are plotted with the (0,0) entry in the upper
    left.  However, sometimes if we are plotting an image, we'd like
    the (0,0) entry to be in the lower left.  We can do that with the
    ``origin`` argument::

        sage: matrix_plot(identity_matrix(100), origin='lower')

    Another random plot, but over `\GF{389}`::

        sage: m = random_matrix(GF(389), 10)
        sage: matrix_plot(m, cmap='Oranges')

    It also works if you lift it to the polynomial ring::

        sage: matrix_plot(m.change_ring(GF(389)['x']), cmap='Oranges')

    We have several options for colorbars::

        sage: matrix_plot(random_matrix(RDF, 50), colorbar=True, colorbar_orientation='horizontal')

    ::

        sage: matrix_plot(random_matrix(RDF, 50), colorbar=True, colorbar_format='%.3f')

    The length of a color bar and the length of the adjacent
    matrix plot dimension may be quite different.  This example
    shows how to adjust the length of the colorbar by passing a
    dictionary of options to the matplotlib colorbar routines.  ::

        sage: m = random_matrix(ZZ, 40, 80, x=-10, y=10)
        sage: m.plot(colorbar=True, colorbar_orientation='vertical',
        ...          colorbar_options={'shrink':0.50})

    Here we plot a random sparse matrix::

        sage: sparse = matrix(dict([((randint(0, 10), randint(0, 10)), 1) for i in xrange(100)]))
        sage: matrix_plot(sparse)

    ::

        sage: A=random_matrix(ZZ,100000,density=.00001,sparse=True)
        sage: matrix_plot(A,marker=',')

    As with dense matrices, sparse matrix entries are automatically
    converted to floating point numbers before plotting.  Thus the
    following works::

        sage: b=random_matrix(GF(2),200,sparse=True,density=0.01)
        sage: matrix_plot(b)

    While this returns an error::

        sage: b=random_matrix(CDF,200,sparse=True,density=0.01)
        sage: matrix_plot(b)
        Traceback (most recent call last):
        ...
        ValueError: can not convert entries to floating point numbers

    To plot the absolute value of a complex matrix, use the
    ``apply_map`` method::

        sage: b=random_matrix(CDF,200,sparse=True,density=0.01)
        sage: matrix_plot(b.apply_map(abs))

    Plotting lists of lists also works::

        sage: matrix_plot([[1,3,5,1],[2,4,5,6],[1,3,5,7]])

    As does plotting of NumPy arrays::

        sage: import numpy
        sage: matrix_plot(numpy.random.rand(10, 10))

    TESTS::

        sage: P.<t> = RR[]
        sage: matrix_plot(random_matrix(P, 3, 3))
        Traceback (most recent call last):
        ...
        TypeError: cannot coerce nonconstant polynomial to float

    ::

        sage: matrix_plot([1,2,3])
        Traceback (most recent call last):
        ...
        TypeError: mat must be a Matrix or a two dimensional array

    ::

        sage: matrix_plot([[sin(x), cos(x)], [1, 0]])
        Traceback (most recent call last):
        ...
        ValueError: can not convert entries to floating point numbers

    Test that sparse matrices also work with subdivisions::

        sage: matrix_plot(sparse, subdivisions=True, subdivision_boundaries=[[2,4],[6,8]])
    """
    import numpy as np
    import scipy.sparse as scipysparse
    from sage.plot.plot import Graphics
    from sage.matrix.all import is_Matrix
    from sage.rings.all import RDF
    orig_mat = mat
    if is_Matrix(mat):
        sparse = mat.is_sparse()
        if sparse:
            entries = list(mat._dict().items())
            try:
                data = np.asarray([d for _, d in entries], dtype=float)
            except:
                raise ValueError, "can not convert entries to floating point numbers"
            positions = np.asarray([[row for (row, col), _ in entries],
                                    [col for (row, col), _ in entries]],
                                   dtype=int)
            mat = scipysparse.coo_matrix((data, positions),
                                         shape=(mat.nrows(), mat.ncols()))
        else:
            mat = mat.change_ring(RDF).numpy()
    elif hasattr(mat, 'tocoo'):
        sparse = True
    else:
        sparse = False

    try:
        if sparse:
            xy_data_array = mat
        else:
            xy_data_array = np.asarray(mat, dtype=float)
    except TypeError:
        raise TypeError, "mat must be a Matrix or a two dimensional array"
    except ValueError:
        raise ValueError, "can not convert entries to floating point numbers"

    if len(xy_data_array.shape) < 2:
        raise TypeError, "mat must be a Matrix or a two dimensional array"

    xrange = (0, xy_data_array.shape[1])
    yrange = (0, xy_data_array.shape[0])

    if options['subdivisions'] and options['subdivision_options'][
            'boundaries'] is None:
        options['subdivision_options'][
            'boundaries'] = orig_mat.get_subdivisions()

    g = Graphics()
    g._set_extra_kwds(Graphics._extract_kwds_for_show(options))
    g.add_primitive(MatrixPlot(xy_data_array, xrange, yrange, options))
    return g
Ejemplo n.º 9
0
def MatrixGroup(gens):
    r"""
    Return the matrix group with given generators.

    INPUT:

    -  ``gens`` - list of matrices in a matrix space or
       matrix group

    EXAMPLES::

        sage: F = GF(5)
        sage: gens = [matrix(F,2,[1,2, -1, 1]), matrix(F,2, [1,1, 0,1])]
        sage: G = MatrixGroup(gens); G
        Matrix group over Finite Field of size 5 with 2 generators:
        [[[1, 2], [4, 1]], [[1, 1], [0, 1]]]

    In the second example, the generators are a matrix over
    `\ZZ`, a matrix over a finite field, and the integer
    `2`. Sage determines that they both canonically map to
    matrices over the finite field, so creates that matrix group
    there.

    ::

        sage: gens = [matrix(2,[1,2, -1, 1]), matrix(GF(7), 2, [1,1, 0,1]), 2]
        sage: G = MatrixGroup(gens); G
        Matrix group over Finite Field of size 7 with 3 generators:
        [[[1, 2], [6, 1]], [[1, 1], [0, 1]], [[2, 0], [0, 2]]]

    Each generator must be invertible::

        sage: G = MatrixGroup([matrix(ZZ,2,[1,2,3,4])])
        Traceback (most recent call last):
        ...
        ValueError: each generator must be an invertible matrix but one is not:
        [1 2]
        [3 4]

    Some groups aren't supported::

        sage: SL(2, CC).gens()
        Traceback (most recent call last):
        ...
        NotImplementedError: Matrix group over Complex Field with 53 bits of precision not implemented.
        sage: G = SL(0, QQ)
        Traceback (most recent call last):
        ...
        ValueError: The degree must be at least 1
    """
    if len(gens) == 0:
        raise ValueError, "gens must have positive length"
    try:
        R = gens[0].base_ring()
    except AttributeError:
        raise TypeError, "gens must be a list of matrices"
    for i in range(len(gens)):
        if not is_Matrix(gens[i]):
            try:
                gens[i] = gens[i].matrix()
            except AttributeError:
                pass
    if is_FiniteField(R):
        return MatrixGroup_gens_finite_field(gens)
    else:
        return MatrixGroup_gens(gens)
Ejemplo n.º 10
0
def list_plot3d(v,
                interpolation_type='default',
                texture="automatic",
                point_list=None,
                **kwds):
    r"""
    A 3-dimensional plot of a surface defined by the list `v`
    of points in 3-dimensional space.
    
    INPUT:
    
    
    - ``v`` - something that defines a set of points in 3
      space, for example:

      - a matrix

      - a list of 3-tuples
    
      - a list of lists (all of the same length) - this is treated the same as
        a matrix.
    
    - ``texture`` - (default: "automatic", a solid light blue)
    
    OPTIONAL KEYWORDS:
    
    - ``interpolation_type`` - 'linear', 'nn' (nearest neighbor), 'spline'
    
      'linear' will perform linear interpolation
    
      The option 'nn' will interpolate by averaging the value of the
      nearest neighbors, this produces an interpolating function that is
      smoother than a linear interpolation, it has one derivative
      everywhere except at the sample points.
    
      The option 'spline' interpolates using a bivariate B-spline.
    
      When v is a matrix the default is to use linear interpolation, when
      v is a list of points the default is nearest neighbor.
    
    - ``degree`` - an integer between 1 and 5, controls the degree of spline
      used for spline interpolation. For data that is highly oscillatory
      use higher values
    
    - ``point_list`` - If point_list=True is passed, then if the array
      is a list of lists of length three, it will be treated as an
      array of points rather than a 3xn array.
    
    - ``num_points`` - Number of points to sample interpolating
      function in each direction, when ``interpolation_type`` is not
      ``default``. By default for an `n\times n` array this is `n`.
    
    - ``**kwds`` - all other arguments are passed to the surface function
    
    OUTPUT: a 3d plot
    
    EXAMPLES:

    We plot a matrix that illustrates summation modulo `n`.
    
    ::
    
        sage: n = 5; list_plot3d(matrix(RDF,n,[(i+j)%n for i in [1..n] for j in [1..n]]))
    
    We plot a matrix of values of sin.
    
    ::
    
        sage: pi = float(pi)
        sage: m = matrix(RDF, 6, [sin(i^2 + j^2) for i in [0,pi/5,..,pi] for j in [0,pi/5,..,pi]])
        sage: list_plot3d(m, texture='yellow', frame_aspect_ratio=[1,1,1/3])
    
    Though it doesn't change the shape of the graph, increasing
    num_points can increase the clarity of the graph.
    
    ::
    
        sage: list_plot3d(m, texture='yellow', frame_aspect_ratio=[1,1,1/3],num_points=40)
    
    We can change the interpolation type.
    
    ::
    
        sage: list_plot3d(m, texture='yellow', interpolation_type='nn',frame_aspect_ratio=[1,1,1/3])
    
    We can make this look better by increasing the number of samples.
    
    ::
    
        sage: list_plot3d(m, texture='yellow', interpolation_type='nn',frame_aspect_ratio=[1,1,1/3],num_points=40)
    
    Let's try a spline.
    
    ::
    
        sage: list_plot3d(m, texture='yellow', interpolation_type='spline',frame_aspect_ratio=[1,1,1/3])
    
    That spline doesn't capture the oscillation very well; let's try a
    higher degree spline.
    
    ::
    
        sage: list_plot3d(m, texture='yellow', interpolation_type='spline', degree=5, frame_aspect_ratio=[1,1,1/3])
    
    We plot a list of lists::
    
        sage: show(list_plot3d([[1, 1, 1, 1], [1, 2, 1, 2], [1, 1, 3, 1], [1, 2, 1, 4]]))
    
    We plot a list of points.  As a first example we can extract the
    (x,y,z) coordinates from the above example and make a list plot
    out of it. By default we do linear interpolation.
    
    ::
    
        sage: l=[]
        sage: for i in range(6):
        ...      for j in range(6):
        ...         l.append((float(i*pi/5),float(j*pi/5),m[i,j]))
        sage: list_plot3d(l,texture='yellow')
    
    Note that the points do not have to be regularly sampled. For example::
    
        sage: l=[]
        sage: for i in range(-5,5):
        ...    for j in range(-5,5):
        ...      l.append((normalvariate(0,1),normalvariate(0,1),normalvariate(0,1)))
        sage: list_plot3d(l,interpolation_type='nn',texture='yellow',num_points=100)

    TESTS:

    We plot 0, 1, and 2 points::
    
        sage: list_plot3d([])
    
    ::
    
        sage: list_plot3d([(2,3,4)])
    
    ::
    
        sage: list_plot3d([(0,0,1), (2,3,4)])

    However, if two points are given with the same x,y coordinates but
    different z coordinates, an exception will be raised::
    
        sage: pts =[(-4/5, -2/5, -2/5), (-4/5, -2/5, 2/5), (-4/5, 2/5, -2/5), (-4/5, 2/5, 2/5), (-2/5, -4/5, -2/5), (-2/5, -4/5, 2/5), (-2/5, -2/5, -4/5), (-2/5, -2/5, 4/5), (-2/5, 2/5, -4/5), (-2/5, 2/5, 4/5), (-2/5, 4/5, -2/5), (-2/5, 4/5, 2/5), (2/5, -4/5, -2/5), (2/5, -4/5, 2/5), (2/5, -2/5, -4/5), (2/5, -2/5, 4/5), (2/5, 2/5, -4/5), (2/5, 2/5, 4/5), (2/5, 4/5, -2/5), (2/5, 4/5, 2/5), (4/5, -2/5, -2/5), (4/5, -2/5, 2/5), (4/5, 2/5, -2/5), (4/5, 2/5, 2/5)]
        sage: show(list_plot3d(pts, interpolation_type='nn'))
        Traceback (most recent call last):
        ...
        ValueError: Two points with same x,y coordinates and different z coordinates were given. Interpolation cannot handle this.

    Additionally we need at least 3 points to do the interpolation::
    
        sage: mat = matrix(RDF, 1, 2, [3.2, 1.550])
        sage: show(list_plot3d(mat,interpolation_type='nn'))
        Traceback (most recent call last):
        ... 
        ValueError: We need at least 3 points to perform the interpolation
    """
    import numpy
    if texture == "automatic":
        texture = "lightblue"
    if is_Matrix(v):
        if interpolation_type == 'default' or interpolation_type == 'linear' and not kwds.has_key(
                'num_points'):
            return list_plot3d_matrix(v, texture=texture, **kwds)
        else:
            l = []
            for i in xrange(v.nrows()):
                for j in xrange(v.ncols()):
                    l.append((i, j, v[i, j]))
            return list_plot3d_tuples(l, interpolation_type, texture, **kwds)

    if type(v) == numpy.ndarray:
        return list_plot3d(matrix(v), interpolation_type, texture, **kwds)

    if isinstance(v, list):
        if len(v) == 0:
            # return empty 3d graphic
            from base import Graphics3d
            return Graphics3d()
        elif len(v) == 1:
            # return a point
            from shapes2 import point3d
            return point3d(v[0], **kwds)
        elif len(v) == 2:
            # return a line
            from shapes2 import line3d
            return line3d(v, **kwds)
        elif isinstance(v[0], tuple) or point_list == True and len(v[0]) == 3:
            return list_plot3d_tuples(v,
                                      interpolation_type,
                                      texture=texture,
                                      **kwds)
        else:
            return list_plot3d_array_of_arrays(v, interpolation_type, texture,
                                               **kwds)
    raise TypeError, "v must be a matrix or list"
Ejemplo n.º 11
0
def MatrixGroup(gens):
    r"""
    Return the matrix group with given generators.
    
    INPUT:
    
    
    -  ``gens`` - list of matrices in a matrix space or
       matrix group
    
    
    EXAMPLES::
    
        sage: F = GF(5)
        sage: gens = [matrix(F,2,[1,2, -1, 1]), matrix(F,2, [1,1, 0,1])]
        sage: G = MatrixGroup(gens); G
        Matrix group over Finite Field of size 5 with 2 generators: 
        [[[1, 2], [4, 1]], [[1, 1], [0, 1]]]
    
    In the second example, the generators are a matrix over
    `\ZZ`, a matrix over a finite field, and the integer
    `2`. Sage determines that they both canonically map to
    matrices over the finite field, so creates that matrix group
    there.
    
    ::
    
        sage: gens = [matrix(2,[1,2, -1, 1]), matrix(GF(7), 2, [1,1, 0,1]), 2]
        sage: G = MatrixGroup(gens); G
        Matrix group over Finite Field of size 7 with 3 generators: 
        [[[1, 2], [6, 1]], [[1, 1], [0, 1]], [[2, 0], [0, 2]]]
    
    Each generator must be invertible::
    
        sage: G = MatrixGroup([matrix(ZZ,2,[1,2,3,4])])
        Traceback (most recent call last):
        ...
        ValueError: each generator must be an invertible matrix but one is not:
        [1 2]
        [3 4]
    
    Some groups aren't supported::
    
        sage: SL(2, CC).gens()
        Traceback (most recent call last):
        ...
        NotImplementedError: Matrix group over Complex Field with 53 bits of precision not implemented.
        sage: G = SL(0, QQ)
        Traceback (most recent call last):
        ...
        ValueError: The degree must be at least 1
    """
    if len(gens) == 0:
        raise ValueError, "gens must have positive length"
    try:
        R = gens[0].base_ring()
    except AttributeError:
        raise TypeError, "gens must be a list of matrices"
    for i in range(len(gens)):
        if not is_Matrix(gens[i]):
            try:
                gens[i] = gens[i].matrix()
            except AttributeError:
                pass
    if is_FiniteField(R):
        return MatrixGroup_gens_finite_field(gens)
    else:
        return MatrixGroup_gens(gens)
Ejemplo n.º 12
0
    def __call__(self, A, check=True):
        r"""
        INPUT:

        - A -- either a matrix or a list/tuple of images of generators,
          or a function returning elements of the codomain for elements
          of the domain.
        - check -- bool (default: True)

        If A is a matrix, then it is the matrix of this linear
        transformation, with respect to the basis for the domain and
        codomain.  Thus the identity matrix always defines the
        identity morphism.

        EXAMPLES::

            sage: V = (ZZ^3).span_of_basis([[1,1,0],[1,0,2]])
            sage: H = V.Hom(V); H
            Set of Morphisms from ...
            sage: H([V.0,V.1])                    # indirect doctest
            Free module morphism defined by the matrix
            [1 0]
            [0 1]...
            sage: phi = H([V.1,V.0]); phi
            Free module morphism defined by the matrix
            [0 1]
            [1 0]...
            sage: phi(V.1) == V.0
            True
            sage: phi(V.0) == V.1
            True

        The following tests against a bug that was fixed in trac
        ticket #9944. The method ``zero()`` calls this hom space with
        a function, not with a matrix, and that case had previously
        not been taken care of::

            sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ)
            sage: V.Hom(V).zero()   # indirect doctest
            Free module morphism defined by the matrix
            [0 0 0]
            [0 0 0]
            [0 0 0]
            Domain: Free module of degree 3 and rank 3 over Integer Ring
            Echelon ...
            Codomain: Free module of degree 3 and rank 3 over Integer Ring
            Echelon ...

        """
        if not matrix.is_Matrix(A):
            # Compute the matrix of the morphism that sends the
            # generators of the domain to the elements of A.
            C = self.codomain()
            if isfunction(A):
                try:
                    v = [C(A(g)) for g in self.domain().gens()]
                    A = matrix.matrix([C.coordinates(a) for a in v])
                except TypeError, msg:
                    # Let us hope that FreeModuleMorphism knows to handle that case
                    pass
            else:
                try:
                    v = [C(a) for a in A]
                    A = matrix.matrix([C.coordinates(a) for a in v])
                except TypeError, msg:
                    # Let us hope that FreeModuleMorphism knows to handle that case
                    pass
Ejemplo n.º 13
0
    def __call__(self, A, check=True):
        r"""
        INPUT:

        - ``A`` - one of several possible inputs representing
          a morphism from this vector space homspace.
          - a vector space morphism in this homspace
          - a matrix representation relative to the bases of the vector spaces,
            which acts on a vector placed to the left of the matrix
          - a list or tuple containing images of the domain's basis vectors
          - a function from the domain to the codomain
        - ``check`` (default: True) - ``True`` or ``False``, required for
          compatibility with calls from
          :meth:`sage.structure.parent_gens.ParentWithGens.hom`.

        EXAMPLES::

            sage: V = (QQ^3).span_of_basis([[1,1,0],[1,0,2]])
            sage: H = V.Hom(V)
            sage: H
            Set of Morphisms (Linear Transformations) from
            Vector space of degree 3 and dimension 2 over Rational Field
            User basis matrix:
            [1 1 0]
            [1 0 2]
            to
            Vector space of degree 3 and dimension 2 over Rational Field
            User basis matrix:
            [1 1 0]
            [1 0 2]

        Coercing a matrix::

            sage: A = matrix(QQ, [[0, 1], [1, 0]])
            sage: rho = H(A)          # indirect doctest
            sage: rho
            Vector space morphism represented by the matrix:
            [0 1]
            [1 0]
            Domain: Vector space of degree 3 and dimension 2 over Rational Field
            User basis matrix:
            [1 1 0]
            [1 0 2]
            Codomain: Vector space of degree 3 and dimension 2 over Rational Field
            User basis matrix:
            [1 1 0]
            [1 0 2]

        Coercing a list of images::

            sage: phi = H([V.1, V.0])
            sage: phi(V.1) == V.0
            True
            sage: phi(V.0) == V.1
            True
            sage: phi
            Vector space morphism represented by the matrix:
            [0 1]
            [1 0]
            Domain: Vector space of degree 3 and dimension 2 over Rational Field
            User basis matrix:
            [1 1 0]
            [1 0 2]
            Codomain: Vector space of degree 3 and dimension 2 over Rational Field
            User basis matrix:
            [1 1 0]
            [1 0 2]

        Coercing a lambda function::

            sage: f = lambda x: vector(QQ, [x[0], (1/2)*x[2], 2*x[1]])
            sage: zeta = H(f)
            sage: zeta
            Vector space morphism represented by the matrix:
            [0 1]
            [1 0]
            Domain: Vector space of degree 3 and dimension 2 over Rational Field
            User basis matrix:
            [1 1 0]
            [1 0 2]
            Codomain: Vector space of degree 3 and dimension 2 over Rational Field
            User basis matrix:
            [1 1 0]
            [1 0 2]

        Coercing a vector space morphism into the parent of a second vector
        space morphism will unify their parents. ::

            sage: U = QQ^3
            sage: V = QQ^4
            sage: W = QQ^3
            sage: X = QQ^4
            sage: H = Hom(U, V)
            sage: K = Hom(W, X)

            sage: A = matrix(QQ, 3, 4, [0]*12)
            sage: f = H(A)
            sage: B = matrix(QQ, 3, 4, range(12))
            sage: g = K(B)
            sage: f.parent() is g.parent()
            False

            sage: h = H(g)
            sage: f.parent() is h.parent()
            True

        See other examples in the module-level documentation.
        
        TESTS::
        
            sage: V = GF(3)^0
            sage: W = GF(3)^1
            sage: H = V.Hom(W)
            sage: H.zero_element().is_zero()
            True
            
        Previously the above code resulted in a TypeError because the
        dimensions of the matrix were incorrect.
        """
        import vector_space_morphism
        D = self.domain()
        C = self.codomain()
        if matrix.is_Matrix(A):
            pass
        elif vector_space_morphism.is_VectorSpaceMorphism(A):
            A = A.matrix()
        elif inspect.isfunction(A):
            try:
                images = [A(g) for g in D.basis()]
            except (ValueError, TypeError, IndexError), e:
                msg = 'function cannot be applied properly to some basis element because\n' + e.args[
                    0]
                raise ValueError(msg)
            try:
                A = matrix.matrix(D.dimension(), C.dimension(),
                                  [C.coordinates(C(a)) for a in images])
            except (ArithmeticError, TypeError), e:
                msg = 'some image of the function is not in the codomain, because\n' + e.args[
                    0]
                raise ArithmeticError(msg)
Ejemplo n.º 14
0
def matrix_plot(mat, **options):
    r"""
    A plot of a given matrix or 2D array.

    If the matrix is dense, each matrix element is given a different
    color value depending on its relative size compared to the other
    elements in the matrix.  If the matrix is sparse, colors only
    indicate whether an element is nonzero or zero, so the plot
    represents the sparsity pattern of the matrix.

    The tick marks drawn on the frame axes denote the row numbers
    (vertical ticks) and the column numbers (horizontal ticks) of the
    matrix.

    INPUT:

    - ``mat`` - a 2D matrix or array

    The following input must all be passed in as named parameters, if
    default not used:

    - ``cmap`` - a colormap (default: 'gray'), the name of
      a predefined colormap, a list of colors,
      or an instance of a matplotlib Colormap.
      Type: ``import matplotlib.cm; matplotlib.cm.datad.keys()``
      for available colormap names.

    - ``colorbar`` -- boolean (default: False) Show a colorbar or not (dense matrices only).

      The following options are used to adjust the style and placement
      of colorbars.  They have no effect if a colorbar is not shown.

      - ``colorbar_orientation`` -- string (default: 'vertical'),
        controls placement of the colorbar, can be either 'vertical'
        or 'horizontal'

      - ``colorbar_format`` -- a format string, this is used to format
        the colorbar labels.

      - ``colorbar_options`` -- a dictionary of options for the matplotlib
        colorbar API.  Documentation for the :mod:`matplotlib.colorbar` module
        has details.

    - ``norm`` - If None (default), the value range is scaled to the interval
      [0,1].  If 'value', then the actual value is used with no
      scaling.  A :class:`matplotlib.colors.Normalize` instance may
      also passed.

    - ``vmin`` - The minimum value (values below this are set to this value)

    - ``vmax`` - The maximum value (values above this are set to this value)

    - ``origin`` - If 'upper' (default), the first row of the matrix
      is on the top of the graph.  If 'lower', the first row is on the
      bottom of the graph.

    - ``subdivisions`` - If True, plot the subdivisions of the matrix as lines.

    - ``subdivision_boundaries`` - a list of lists in the form
      ``[row_subdivisions, column_subdivisions]``, which specifies
      the row and column subdivisions to use.  If not specified,
      defaults to the matrix subdivisions

    - ``subdivision_style`` - a dictionary of properties passed
      on to the :func:`~sage.plot.line.line2d` command for plotting
      subdivisions.  If this is a two-element list or tuple, then it
      specifies the styles of row and column divisions, respectively.

    EXAMPLES:

    A matrix over `\ZZ` colored with different grey levels::

        sage: matrix_plot(matrix([[1,3,5,1],[2,4,5,6],[1,3,5,7]]))

    Here we make a random matrix over `\RR` and use ``cmap='hsv'``
    to color the matrix elements different RGB colors::

        sage: matrix_plot(random_matrix(RDF, 50), cmap='hsv')

    By default, entries are scaled to the interval [0,1] before
    determining colors from the color map.  That means the two plots
    below are the same::

        sage: P = matrix_plot(matrix(2,[1,1,3,3]))
        sage: Q = matrix_plot(matrix(2,[2,2,3,3]))
        sage: P; Q

    However, we can specify which values scale to 0 or 1 with the
    ``vmin`` and ``vmax`` parameters (values outside the range are
    clipped).  The two plots below are now distinguished::

        sage: P = matrix_plot(matrix(2,[1,1,3,3]), vmin=0, vmax=3, colorbar=True)
        sage: Q = matrix_plot(matrix(2,[2,2,3,3]), vmin=0, vmax=3, colorbar=True)
        sage: P; Q

    We can also specify a norm function of 'value', which means that
    there is no scaling performed::

        sage: matrix_plot(random_matrix(ZZ,10)*.05, norm='value', colorbar=True)

    Matrix subdivisions can be plotted as well::

        sage: m=random_matrix(RR,10)
        sage: m.subdivide([2,4],[6,8])
        sage: matrix_plot(m, subdivisions=True, subdivision_style=dict(color='red',thickness=3))

    You can also specify your own subdivisions and separate styles
    for row or column subdivisions::

        sage: m=random_matrix(RR,10)
        sage: matrix_plot(m, subdivisions=True, subdivision_boundaries=[[2,4],[6,8]], subdivision_style=[dict(color='red',thickness=3),dict(linestyle='--',thickness=6)])

    Generally matrices are plotted with the (0,0) entry in the upper
    left.  However, sometimes if we are plotting an image, we'd like
    the (0,0) entry to be in the lower left.  We can do that with the
    ``origin`` argument::

        sage: matrix_plot(identity_matrix(100), origin='lower')

    Another random plot, but over `\GF{389}`::

        sage: m = random_matrix(GF(389), 10)
        sage: matrix_plot(m, cmap='Oranges')

    It also works if you lift it to the polynomial ring::

        sage: matrix_plot(m.change_ring(GF(389)['x']), cmap='Oranges')

    We have several options for colorbars::

        sage: matrix_plot(random_matrix(RDF, 50), colorbar=True, colorbar_orientation='horizontal')

    ::

        sage: matrix_plot(random_matrix(RDF, 50), colorbar=True, colorbar_format='%.3f')

    The length of a color bar and the length of the adjacent
    matrix plot dimension may be quite different.  This example
    shows how to adjust the length of the colorbar by passing a
    dictionary of options to the matplotlib colorbar routines.  ::

        sage: m = random_matrix(ZZ, 40, 80, x=-10, y=10)
        sage: m.plot(colorbar=True, colorbar_orientation='vertical',
        ...          colorbar_options={'shrink':0.50})

    Here we plot a random sparse matrix::

        sage: sparse = matrix(dict([((randint(0, 10), randint(0, 10)), 1) for i in xrange(100)]))
        sage: matrix_plot(sparse)

    ::

        sage: A=random_matrix(ZZ,100000,density=.00001,sparse=True)
        sage: matrix_plot(A,marker=',')

    As with dense matrices, sparse matrix entries are automatically
    converted to floating point numbers before plotting.  Thus the
    following works::

        sage: b=random_matrix(GF(2),200,sparse=True,density=0.01)
        sage: matrix_plot(b)

    While this returns an error::

        sage: b=random_matrix(CDF,200,sparse=True,density=0.01)
        sage: matrix_plot(b)
        Traceback (most recent call last):
        ...
        ValueError: can not convert entries to floating point numbers

    To plot the absolute value of a complex matrix, use the
    ``apply_map`` method::

        sage: b=random_matrix(CDF,200,sparse=True,density=0.01)
        sage: matrix_plot(b.apply_map(abs))

    Plotting lists of lists also works::

        sage: matrix_plot([[1,3,5,1],[2,4,5,6],[1,3,5,7]])

    As does plotting of NumPy arrays::

        sage: import numpy
        sage: matrix_plot(numpy.random.rand(10, 10))

    A plot title can be added to the matrix plot.::

        sage: matrix_plot(identity_matrix(50), origin='lower', title='not identity')

    The title position is adjusted upwards if the ``origin`` keyword is set
    to ``"upper"`` (this is the default).::

        sage: matrix_plot(identity_matrix(50), title='identity')

    TESTS::

        sage: P.<t> = RR[]
        sage: matrix_plot(random_matrix(P, 3, 3))
        Traceback (most recent call last):
        ...
        TypeError: cannot coerce nonconstant polynomial to float

    ::

        sage: matrix_plot([1,2,3])
        Traceback (most recent call last):
        ...
        TypeError: mat must be a Matrix or a two dimensional array

    ::

        sage: matrix_plot([[sin(x), cos(x)], [1, 0]])
        Traceback (most recent call last):
        ...
        ValueError: can not convert entries to floating point numbers

    Test that sparse matrices also work with subdivisions::

        sage: matrix_plot(sparse, subdivisions=True, subdivision_boundaries=[[2,4],[6,8]])
    """
    import numpy as np
    import scipy.sparse as scipysparse
    from sage.plot.all import Graphics
    from sage.matrix.all import is_Matrix
    from sage.rings.all import RDF
    orig_mat=mat
    if is_Matrix(mat):
        sparse = mat.is_sparse()
        if sparse:
            entries = list(mat._dict().items())
            try:
                data = np.asarray([d for _,d in entries], dtype=float)
            except StandardError:
                raise ValueError, "can not convert entries to floating point numbers"
            positions = np.asarray([[row for (row,col),_ in entries],
                                    [col for (row,col),_ in entries]], dtype=int)
            mat = scipysparse.coo_matrix((data,positions), shape=(mat.nrows(), mat.ncols()))
        else:
            mat = mat.change_ring(RDF).numpy()
    elif hasattr(mat, 'tocoo'):
        sparse = True
    else:
        sparse = False


    try:
        if sparse:
            xy_data_array = mat
        else:
            xy_data_array = np.asarray(mat, dtype = float)
    except TypeError:
        raise TypeError, "mat must be a Matrix or a two dimensional array"
    except ValueError:
        raise ValueError, "can not convert entries to floating point numbers"

    if len(xy_data_array.shape) < 2:
        raise TypeError, "mat must be a Matrix or a two dimensional array"

    xrange = (0, xy_data_array.shape[1])
    yrange = (0, xy_data_array.shape[0])

    if options['subdivisions'] and options['subdivision_options']['boundaries'] is None:
        options['subdivision_options']['boundaries']=orig_mat.get_subdivisions()

    # Custom position the title. Otherwise it overlaps with tick labels
    if options['origin'] == 'upper' and 'title_pos' not in options:
        options['title_pos'] = (0.5, 1.05)

    g = Graphics()
    g._set_extra_kwds(Graphics._extract_kwds_for_show(options))
    g.add_primitive(MatrixPlot(xy_data_array, xrange, yrange, options))
    return g
Ejemplo n.º 15
0
    def __call__(self, A, check=True):
        r"""
        INPUT:

        - ``A`` - one of several possible inputs representing
          a morphism from this vector space homspace.
          - a vector space morphism in this homspace
          - a matrix representation relative to the bases of the vector spaces,
            which acts on a vector placed to the left of the matrix
          - a list or tuple containing images of the domain's basis vectors
          - a function from the domain to the codomain
        - ``check`` (default: True) - ``True`` or ``False``, required for
          compatibility with calls from
          :meth:`sage.structure.parent_gens.ParentWithGens.hom`.

        EXAMPLES::

            sage: V = (QQ^3).span_of_basis([[1,1,0],[1,0,2]])
            sage: H = V.Hom(V)
            sage: H
            Set of Morphisms (Linear Transformations) from
            Vector space of degree 3 and dimension 2 over Rational Field
            User basis matrix:
            [1 1 0]
            [1 0 2]
            to
            Vector space of degree 3 and dimension 2 over Rational Field
            User basis matrix:
            [1 1 0]
            [1 0 2]

        Coercing a matrix::

            sage: A = matrix(QQ, [[0, 1], [1, 0]])
            sage: rho = H(A)          # indirect doctest
            sage: rho
            Vector space morphism represented by the matrix:
            [0 1]
            [1 0]
            Domain: Vector space of degree 3 and dimension 2 over Rational Field
            User basis matrix:
            [1 1 0]
            [1 0 2]
            Codomain: Vector space of degree 3 and dimension 2 over Rational Field
            User basis matrix:
            [1 1 0]
            [1 0 2]

        Coercing a list of images::

            sage: phi = H([V.1, V.0])
            sage: phi(V.1) == V.0
            True
            sage: phi(V.0) == V.1
            True
            sage: phi
            Vector space morphism represented by the matrix:
            [0 1]
            [1 0]
            Domain: Vector space of degree 3 and dimension 2 over Rational Field
            User basis matrix:
            [1 1 0]
            [1 0 2]
            Codomain: Vector space of degree 3 and dimension 2 over Rational Field
            User basis matrix:
            [1 1 0]
            [1 0 2]

        Coercing a lambda function::

            sage: f = lambda x: vector(QQ, [x[0], (1/2)*x[2], 2*x[1]])
            sage: zeta = H(f)
            sage: zeta
            Vector space morphism represented by the matrix:
            [0 1]
            [1 0]
            Domain: Vector space of degree 3 and dimension 2 over Rational Field
            User basis matrix:
            [1 1 0]
            [1 0 2]
            Codomain: Vector space of degree 3 and dimension 2 over Rational Field
            User basis matrix:
            [1 1 0]
            [1 0 2]

        Coercing a vector space morphism into the parent of a second vector
        space morphism will unify their parents. ::

            sage: U = QQ^3
            sage: V = QQ^4
            sage: W = FreeModule(QQ,3,sparse=True)
            sage: X = QQ^4
            sage: H = Hom(U, V)
            sage: K = Hom(W, X)
            sage: H is K
            False

            sage: A = matrix(QQ, 3, 4, [0]*12)
            sage: f = H(A)
            sage: B = matrix(QQ, 3, 4, range(12))
            sage: g = K(B)
            sage: f.parent() is H and g.parent() is K
            True

            sage: h = H(g)
            sage: f.parent() is h.parent()
            True

        See other examples in the module-level documentation.

        TESTS::

            sage: V = GF(3)^0
            sage: W = GF(3)^1
            sage: H = V.Hom(W)
            sage: H.zero_element().is_zero()
            True

        Previously the above code resulted in a TypeError because the
        dimensions of the matrix were incorrect.
        """
        from vector_space_morphism import is_VectorSpaceMorphism, VectorSpaceMorphism
        D = self.domain()
        C = self.codomain()
        if matrix.is_Matrix(A):
            pass
        elif is_VectorSpaceMorphism(A):
            A = A.matrix()
        elif inspect.isfunction(A):
            try:
                images = [A(g) for g in D.basis()]
            except (ValueError, TypeError, IndexError), e:
                msg = 'function cannot be applied properly to some basis element because\n' + e.args[0]
                raise ValueError(msg)
            try:
                A = matrix.matrix(D.dimension(), C.dimension(), [C.coordinates(C(a)) for a in images])
            except (ArithmeticError, TypeError), e:
                msg = 'some image of the function is not in the codomain, because\n' + e.args[0]
                raise ArithmeticError(msg)
Ejemplo n.º 16
0
    def __call__(self, A, check=True):
        r"""
        INPUT:

        - A -- either a matrix or a list/tuple of images of generators,
          or a function returning elements of the codomain for elements
          of the domain.
        - check -- bool (default: True)

        If A is a matrix, then it is the matrix of this linear
        transformation, with respect to the basis for the domain and
        codomain.  Thus the identity matrix always defines the
        identity morphism.

        EXAMPLES::

            sage: V = (ZZ^3).span_of_basis([[1,1,0],[1,0,2]])
            sage: H = V.Hom(V); H
            Set of Morphisms from ...
            sage: H([V.0,V.1])                    # indirect doctest
            Free module morphism defined by the matrix
            [1 0]
            [0 1]...
            sage: phi = H([V.1,V.0]); phi
            Free module morphism defined by the matrix
            [0 1]
            [1 0]...
            sage: phi(V.1) == V.0
            True
            sage: phi(V.0) == V.1
            True

        The following tests against a bug that was fixed in trac
        ticket #9944. The method ``zero()`` calls this hom space with
        a function, not with a matrix, and that case had previously
        not been taken care of::

            sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ)
            sage: V.Hom(V).zero()   # indirect doctest
            Free module morphism defined by the matrix
            [0 0 0]
            [0 0 0]
            [0 0 0]
            Domain: Free module of degree 3 and rank 3 over Integer Ring
            Echelon ...
            Codomain: Free module of degree 3 and rank 3 over Integer Ring
            Echelon ...

        """
        if not matrix.is_Matrix(A):
            # Compute the matrix of the morphism that sends the
            # generators of the domain to the elements of A.
            C = self.codomain()
            if isfunction(A):
                try:
                    v = [C(A(g)) for g in self.domain().gens()]
                    A = matrix.matrix([C.coordinates(a) for a in v])
                except TypeError, msg:
                    # Let us hope that FreeModuleMorphism knows to handle that case
                    pass
            else:
                try:
                    v = [C(a) for a in A]
                    A = matrix.matrix([C.coordinates(a) for a in v])
                except TypeError, msg:
                    # Let us hope that FreeModuleMorphism knows to handle that case
                    pass
Ejemplo n.º 17
0
def list_plot3d(v, interpolation_type='default', texture="automatic", point_list=None,**kwds):
    r"""
    A 3-dimensional plot of a surface defined by the list `v`
    of points in 3-dimensional space.
    
    INPUT:
    
    
    - ``v`` - something that defines a set of points in 3
      space, for example:

      - a matrix

      - a list of 3-tuples
    
      - a list of lists (all of the same length) - this is treated the same as
        a matrix.
    
    - ``texture`` - (default: "automatic", a solid light blue)
    
    OPTIONAL KEYWORDS:
    
    - ``interpolation_type`` - 'linear', 'nn' (nearest neighbor), 'spline'
    
      'linear' will perform linear interpolation
    
      The option 'nn' will interpolate by averaging the value of the
      nearest neighbors, this produces an interpolating function that is
      smoother than a linear interpolation, it has one derivative
      everywhere except at the sample points.
    
      The option 'spline' interpolates using a bivariate B-spline.
    
      When v is a matrix the default is to use linear interpolation, when
      v is a list of points the default is nearest neighbor.
    
    - ``degree`` - an integer between 1 and 5, controls the degree of spline
      used for spline interpolation. For data that is highly oscillatory
      use higher values
    
    - ``point_list`` - If point_list=True is passed, then if the array
      is a list of lists of length three, it will be treated as an
      array of points rather than a 3xn array.
    
    - ``num_points`` - Number of points to sample interpolating
      function in each direction, when ``interpolation_type`` is not
      ``default``. By default for an `n\times n` array this is `n`.
    
    - ``**kwds`` - all other arguments are passed to the surface function
    
    OUTPUT: a 3d plot
    
    EXAMPLES:

    We plot a matrix that illustrates summation modulo `n`.
    
    ::
    
        sage: n = 5; list_plot3d(matrix(RDF,n,[(i+j)%n for i in [1..n] for j in [1..n]]))
    
    We plot a matrix of values of sin.
    
    ::
    
        sage: pi = float(pi)
        sage: m = matrix(RDF, 6, [sin(i^2 + j^2) for i in [0,pi/5,..,pi] for j in [0,pi/5,..,pi]])
        sage: list_plot3d(m, texture='yellow', frame_aspect_ratio=[1,1,1/3])
    
    Though it doesn't change the shape of the graph, increasing
    num_points can increase the clarity of the graph.
    
    ::
    
        sage: list_plot3d(m, texture='yellow', frame_aspect_ratio=[1,1,1/3],num_points=40)
    
    We can change the interpolation type.
    
    ::
    
        sage: list_plot3d(m, texture='yellow', interpolation_type='nn',frame_aspect_ratio=[1,1,1/3])
    
    We can make this look better by increasing the number of samples.
    
    ::
    
        sage: list_plot3d(m, texture='yellow', interpolation_type='nn',frame_aspect_ratio=[1,1,1/3],num_points=40)
    
    Let's try a spline.
    
    ::
    
        sage: list_plot3d(m, texture='yellow', interpolation_type='spline',frame_aspect_ratio=[1,1,1/3])
    
    That spline doesn't capture the oscillation very well; let's try a
    higher degree spline.
    
    ::
    
        sage: list_plot3d(m, texture='yellow', interpolation_type='spline', degree=5, frame_aspect_ratio=[1,1,1/3])
    
    We plot a list of lists::
    
        sage: show(list_plot3d([[1, 1, 1, 1], [1, 2, 1, 2], [1, 1, 3, 1], [1, 2, 1, 4]]))
    
    We plot a list of points.  As a first example we can extract the
    (x,y,z) coordinates from the above example and make a list plot
    out of it. By default we do linear interpolation.
    
    ::
    
        sage: l=[]
        sage: for i in range(6):
        ...      for j in range(6):
        ...         l.append((float(i*pi/5),float(j*pi/5),m[i,j]))
        sage: list_plot3d(l,texture='yellow')
    
    Note that the points do not have to be regularly sampled. For example::
    
        sage: l=[]
        sage: for i in range(-5,5):
        ...    for j in range(-5,5):
        ...      l.append((normalvariate(0,1),normalvariate(0,1),normalvariate(0,1)))
        sage: list_plot3d(l,interpolation_type='nn',texture='yellow',num_points=100)

    TESTS:

    We plot 0, 1, and 2 points::
    
        sage: list_plot3d([])
    
    ::
    
        sage: list_plot3d([(2,3,4)])
    
    ::
    
        sage: list_plot3d([(0,0,1), (2,3,4)])

    However, if two points are given with the same x,y coordinates but
    different z coordinates, an exception will be raised::
    
        sage: pts =[(-4/5, -2/5, -2/5), (-4/5, -2/5, 2/5), (-4/5, 2/5, -2/5), (-4/5, 2/5, 2/5), (-2/5, -4/5, -2/5), (-2/5, -4/5, 2/5), (-2/5, -2/5, -4/5), (-2/5, -2/5, 4/5), (-2/5, 2/5, -4/5), (-2/5, 2/5, 4/5), (-2/5, 4/5, -2/5), (-2/5, 4/5, 2/5), (2/5, -4/5, -2/5), (2/5, -4/5, 2/5), (2/5, -2/5, -4/5), (2/5, -2/5, 4/5), (2/5, 2/5, -4/5), (2/5, 2/5, 4/5), (2/5, 4/5, -2/5), (2/5, 4/5, 2/5), (4/5, -2/5, -2/5), (4/5, -2/5, 2/5), (4/5, 2/5, -2/5), (4/5, 2/5, 2/5)]
        sage: show(list_plot3d(pts, interpolation_type='nn'))
        Traceback (most recent call last):
        ...
        ValueError: Two points with same x,y coordinates and different z coordinates were given. Interpolation cannot handle this.

    Additionally we need at least 3 points to do the interpolation::
    
        sage: mat = matrix(RDF, 1, 2, [3.2, 1.550])
        sage: show(list_plot3d(mat,interpolation_type='nn'))
        Traceback (most recent call last):
        ... 
        ValueError: We need at least 3 points to perform the interpolation
    """
    import numpy
    if texture == "automatic":
        texture = "lightblue"
    if is_Matrix(v):
        if interpolation_type=='default' or interpolation_type=='linear' and not kwds.has_key('num_points'):
            return list_plot3d_matrix(v, texture=texture,  **kwds)
        else:
            l=[]
            for i in xrange(v.nrows()):
                for j in xrange(v.ncols()):
                    l.append((i,j,v[i,j]))
            return list_plot3d_tuples(l,interpolation_type,texture,**kwds)

    if type(v)==numpy.ndarray:
        return list_plot3d(matrix(v),interpolation_type,texture,**kwds)
        
    if isinstance(v, list):
        if len(v) == 0:
            # return empty 3d graphic
            from base import Graphics3d
            return Graphics3d()
        elif len(v) == 1:
            # return a point
            from shapes2 import point3d
            return point3d(v[0], **kwds)
        elif len(v) == 2:
            # return a line
            from shapes2 import line3d
            return line3d(v, **kwds)
        elif isinstance(v[0],tuple) or point_list==True and len(v[0]) == 3:
            return list_plot3d_tuples(v,interpolation_type,texture=texture, **kwds)
        else:
            return list_plot3d_array_of_arrays(v, interpolation_type,texture, **kwds)
    raise TypeError, "v must be a matrix or list"