'Returns a matrix with the specified diagonal.
If matrices are passed, a block-diagonal matrix
is created.
kwargs
rows : rows of the resulting matrix; computed if
not given.
cols : columns of the resulting matrix; computed if
not given.
cls : class for the resulting matrix
Examples
>>> from sympy.matrices import Matrix
>>> Matrix.diag(1, 2, 3)
Matrix([
[1, 0, 0],
[0, 2, 0],
[0, 0, 3]])
>>> Matrix.diag([1, 2, 3])
Matrix([
[1, 0, 0],
[0, 2, 0],
[0, 0, 3]])
The diagonal elements can be matrices; diagonal filling will
continue on the diagonal from the last element of the matrix:
>>> from sympy.abc import x, y, z
>>> a = Matrix([x, y, z])
>>> b = Matrix([[1, 2], [3, 4]])
>>> c = Matrix([[5, 6]])
>>> Matrix.diag(a, 7, b, c)
Matrix([
[x, 0, 0, 0, 0, 0],
[y, 0, 0, 0, 0, 0],
[z, 0, 0, 0, 0, 0],
[0, 7, 0, 0, 0, 0],
[0, 0, 1, 2, 0, 0],
[0, 0, 3, 4, 0, 0],
[0, 0, 0, 0, 5, 6]])
A given band off the diagonal can be made by padding with a
vertical or horizontal "kerning" vector:
>>> hpad = Matrix(0, 2, [])
>>> vpad = Matrix(2, 0, [])
>>> Matrix.diag(vpad, 1, 2, 3, hpad) + Matrix.diag(hpad, 4, 5, 6, vpad)
Matrix([
[0, 0, 4, 0, 0],
[0, 0, 0, 5, 0],
[1, 0, 0, 0, 6],
[0, 2, 0, 0, 0],
[0, 0, 3, 0, 0]])
The type of the resulting matrix can be affected with the ``cls``
keyword.
>>> type(Matrix.diag(1))
<class \'sympy.matrices.dense.MutableDenseMatrix\'>
>>> from sympy.matrices import ImmutableMatrix
>>> type(Matrix.diag(1, cls=ImmutableMatrix))
<class \'sympy.matrices.immutable.ImmutableDenseMatrix\'>'

@classmethod
def diag(kls, *args, **kwargs):

    klass = kwargs.get('cls', kls)
    if ((len(args) == 1) and is_sequence(args[0]) and (not getattr(args[0], 'is_Matrix', False))):
        args = args[0]
    def size(m):
        'Compute    the    size    of    the    diagonal    block'
        if hasattr(m, 'rows'):
            return (m.rows, m.cols)
        return (1, 1)
    diag_rows = sum((size(m)[0] for m in args))
    diag_cols = sum((size(m)[1] for m in args))
    rows = kwargs.get('rows', diag_rows)
    cols = kwargs.get('cols', diag_cols)
    if ((rows < diag_rows) or (cols < diag_cols)):
        raise ValueError('A    {}    x    {}    diagnal    matrix    cannot    accomodate    adiagonal    of    size    at    least    {}    x    {}.'.format(rows, cols, diag_rows, diag_cols))
    diag_entries = collections.defaultdict((lambda : S.Zero))
    (row_pos, col_pos) = (0, 0)
    for m in args:
        if hasattr(m, 'rows'):
            for i in range(m.rows):
                for j in range(m.cols):
                    diag_entries[((i + row_pos), (j + col_pos))] = m[(i, j)]
            row_pos += m.rows
            col_pos += m.cols
        else:
            diag_entries[(row_pos, col_pos)] = m
            row_pos += 1
            col_pos += 1
    return klass._eval_diag(rows, cols, diag_entries)
