Пример #1
0
def row_reduced_form(M, transformation=False):
    """
    This function computes a row reduced form of a matrix over a rational
    function field `k(x)`, for `k` a field.

    INPUT:

     - `M` - a matrix over `k(x)` or `k[x]` for `k` a field.
     - `transformation` - A boolean (default: `False`). If this boolean is set to `True` a second matrix is output (see OUTPUT).
     
    OUTPUT:

    If `transformation` is `False`, the output is `W`, a row reduced form of `M`.
    
    If `transformation` is `True`, this function will output a pair `(W,N)` consisting of two matrices over `k(x)`:

    1. `W` - a row reduced form of `M`.
    2. `N` - an invertible matrix over `k(x)` satisfying `NW = M`.

    EXAMPLES:

    The fuction expects matrices over the rational function field, but
    other examples below show how one can provide matrices over the ring
    of polynomials (whose quotient field is the rational function field).

    ::

        sage: R.<t> = GF(3)['t']
        sage: K = FractionField(R)
        sage: import sage.matrix.matrix_misc
        sage: sage.matrix.matrix_misc.row_reduced_form(matrix([[(t-1)^2/t],[(t-1)]]))
        [(2*t + 1)/t]
        [          0]

    The last example shows the usage of the transformation parameter.
        
    ::
        sage: Fq.<a> = GF(2^3)
        sage: Fx.<x> = Fq[]
        sage: A = matrix(Fx,[[x^2+a,x^4+a],[x^3,a*x^4]])
        sage: from sage.matrix.matrix_misc import row_reduced_form
        sage: row_reduced_form(A,transformation=True)
        (
        [(a^2 + 1)*x^3 + x^2 + a                       a]  [      1 a^2 + 1]
        [                    x^3                   a*x^4], [      0                 1]
        )
            
    NOTES:

    See docstring for row_reduced_form method of matrices for
    more information.
    """

    # determine whether M has polynomial or rational function coefficients
    R0 = M.base_ring()

    #Compute the base polynomial ring
    if R0 in _Fields:
        R = R0.base()
    else:
        R = R0
    from sage.rings.polynomial.polynomial_ring import is_PolynomialRing
    if not is_PolynomialRing(R) or not R.base_ring().is_field():
        raise TypeError(
            "the coefficients of M must lie in a univariate polynomial ring over a field"
        )

    t = R.gen()

    # calculate least-common denominator of matrix entries and clear
    # denominators. The result lies in R
    from sage.arith.all import lcm
    from sage.matrix.constructor import matrix
    from sage.misc.functional import numerator
    if R0 in _Fields:
        den = lcm([a.denominator() for a in M.list()])
        num = matrix([[numerator(_) for _ in v] for v in (M * den).rows()])
    else:
        # No need to clear denominators
        num = M

    r = [list(v) for v in num.rows()]

    if transformation:
        N = matrix(num.nrows(), num.nrows(), R(1)).rows()

    rank = 0
    num_zero = 0
    if M.is_zero():
        num_zero = len(r)
    while rank != len(r) - num_zero:
        # construct matrix of leading coefficients
        v = []
        for w in map(list, r):
            # calculate degree of row (= max of degree of entries)
            d = max([e.numerator().degree() for e in w])

            # extract leading coefficients from current row
            x = []
            for y in w:
                if y.degree() >= d and d >= 0:
                    x.append(y.coefficients(sparse=False)[d])
                else:
                    x.append(0)
            v.append(x)
        l = matrix(v)

        # count number of zero rows in leading coefficient matrix
        # because they do *not* contribute interesting relations
        num_zero = 0
        for v in l.rows():
            is_zero = 1
            for w in v:
                if w != 0:
                    is_zero = 0
            if is_zero == 1:
                num_zero += 1

        # find non-trivial relations among the columns of the
        # leading coefficient matrix
        kern = l.kernel().basis()
        rank = num.nrows() - len(kern)

        # do a row operation if there's a non-trivial relation
        if not rank == len(r) - num_zero:
            for rel in kern:
                # find the row of num involved in the relation and of
                # maximal degree
                indices = []
                degrees = []
                for i in range(len(rel)):
                    if rel[i] != 0:
                        indices.append(i)
                        degrees.append(max([e.degree() for e in r[i]]))

                # find maximum degree among rows involved in relation
                max_deg = max(degrees)

                # check if relation involves non-zero rows
                if max_deg != -1:
                    i = degrees.index(max_deg)
                    rel /= rel[indices[i]]

                    for j in range(len(indices)):
                        if j != i:
                            # do the row operation
                            v = []
                            for k in range(len(r[indices[i]])):
                                v.append(r[indices[i]][k] + rel[indices[j]] *
                                         t**(max_deg - degrees[j]) *
                                         r[indices[j]][k])
                            r[indices[i]] = v

                            if transformation:
                                # If the user asked for it, record the row operation
                                v = []
                                for k in range(len(N[indices[i]])):
                                    v.append(N[indices[i]][k] +
                                             rel[indices[j]] *
                                             t**(max_deg - degrees[j]) *
                                             N[indices[j]][k])
                                N[indices[i]] = v

                    # remaining relations (if any) are no longer valid,
                    # so continue onto next step of algorithm
                    break
    if is_PolynomialRing(R0):
        A = matrix(R, r)
    else:
        A = matrix(R, r) / den
    if transformation:
        return (A, matrix(N))
    else:
        return A
Пример #2
0
def row_reduced_form(M, ascend=True):
    """
    This function computes a weak Popov form of a matrix over a rational
    function field `k(x)`, for `k` a field.

    INPUT:

     - `M` - matrix

     - `ascend` - if True, rows of output matrix `W` are sorted so
       degree (= the maximum of the degrees of the elements in
       the row) increases monotonically, and otherwise degrees decrease.

    OUTPUT:

    A 3-tuple `(W,N,d)` consisting of two matrices over `k(x)` and a list
    of integers:

    1. `W` - matrix giving a weak the Popov form of M
    2. `N` - matrix representing row operations used to transform
       `M` to `W`
    3. `d` - degree of respective columns of W; the degree of a column is
       the maximum of the degree of its elements

    `N` is invertible over `k(x)`. These matrices satisfy the relation
    `N*M = W`.

    EXAMPLES:

    The routine expects matrices over the rational function field, but
    other examples below show how one can provide matrices over the ring
    of polynomials (whose quotient field is the rational function field).

    ::

        sage: R.<t> = GF(3)['t']
        sage: K = FractionField(R)
        sage: import sage.matrix.matrix_misc
        sage: sage.matrix.matrix_misc.row_reduced_form(matrix([[(t-1)^2/t],[(t-1)]]))
        (
        [          0]  [      t 2*t + 1]
        [(2*t + 1)/t], [      1       2], [-Infinity, 0]
        )

    NOTES:

    See docstring for row_reduced_form method of matrices for
    more information.
    """

    # determine whether M has polynomial or rational function coefficients
    R0 = M.base_ring()

    #Compute the base polynomial ring
    if R0 in _Fields:
        R = R0.base()
    else:
        R = R0
    from sage.rings.polynomial.polynomial_ring import is_PolynomialRing
    if not is_PolynomialRing(R):
        raise TypeError(
            "the coefficients of M must lie in a univariate polynomial ring")

    t = R.gen()

    # calculate least-common denominator of matrix entries and clear
    # denominators. The result lies in R
    from sage.rings.arith import lcm
    from sage.matrix.constructor import matrix
    from sage.misc.functional import numerator
    if R0 in _Fields:
        den = lcm([a.denominator() for a in M.list()])
        num = matrix([[numerator(_) for _ in v] for v in (M * den).rows()])
    else:
        # No need to clear denominators
        den = R.one()
        num = M

    r = [list(v) for v in num.rows()]

    N = matrix(num.nrows(), num.nrows(), R(1)).rows()

    from sage.rings.infinity import Infinity
    if M.is_zero():
        return (M, matrix(N), [-Infinity for i in range(num.nrows())])

    rank = 0
    num_zero = 0
    while rank != len(r) - num_zero:
        # construct matrix of leading coefficients
        v = []
        for w in map(list, r):
            # calculate degree of row (= max of degree of entries)
            d = max([e.numerator().degree() for e in w])

            # extract leading coefficients from current row
            x = []
            for y in w:
                if y.degree() >= d and d >= 0:
                    x.append(y.coefficients(sparse=False)[d])
                else:
                    x.append(0)
            v.append(x)
        l = matrix(v)

        # count number of zero rows in leading coefficient matrix
        # because they do *not* contribute interesting relations
        num_zero = 0
        for v in l.rows():
            is_zero = 1
            for w in v:
                if w != 0:
                    is_zero = 0
            if is_zero == 1:
                num_zero += 1

        # find non-trivial relations among the columns of the
        # leading coefficient matrix
        kern = l.kernel().basis()
        rank = num.nrows() - len(kern)

        # do a row operation if there's a non-trivial relation
        if not rank == len(r) - num_zero:
            for rel in kern:
                # find the row of num involved in the relation and of
                # maximal degree
                indices = []
                degrees = []
                for i in range(len(rel)):
                    if rel[i] != 0:
                        indices.append(i)
                        degrees.append(max([e.degree() for e in r[i]]))

                # find maximum degree among rows involved in relation
                max_deg = max(degrees)

                # check if relation involves non-zero rows
                if max_deg != -1:
                    i = degrees.index(max_deg)
                    rel /= rel[indices[i]]

                    for j in range(len(indices)):
                        if j != i:
                            # do row operation and record it
                            v = []
                            for k in range(len(r[indices[i]])):
                                v.append(r[indices[i]][k] + rel[indices[j]] *
                                         t**(max_deg - degrees[j]) *
                                         r[indices[j]][k])
                            r[indices[i]] = v

                            v = []
                            for k in range(len(N[indices[i]])):
                                v.append(N[indices[i]][k] + rel[indices[j]] *
                                         t**(max_deg - degrees[j]) *
                                         N[indices[j]][k])
                            N[indices[i]] = v

                    # remaining relations (if any) are no longer valid,
                    # so continue onto next step of algorithm
                    break

    # sort the rows in order of degree
    d = []
    from sage.rings.all import infinity
    for i in range(len(r)):
        d.append(max([e.degree() for e in r[i]]))
        if d[i] < 0:
            d[i] = -infinity
        else:
            d[i] -= den.degree()

    for i in range(len(r)):
        for j in range(i + 1, len(r)):
            if (ascend and d[i] > d[j]) or (not ascend and d[i] < d[j]):
                (r[i], r[j]) = (r[j], r[i])
                (d[i], d[j]) = (d[j], d[i])
                (N[i], N[j]) = (N[j], N[i])

    # return reduced matrix and operations matrix
    return (matrix(r) / den, matrix(N), d)
Пример #3
0
def row_reduced_form(M,transformation=False):
    """
    This function computes a row reduced form of a matrix over a rational
    function field `k(x)`, for `k` a field.

    INPUT:

     - `M` - a matrix over `k(x)` or `k[x]` for `k` a field.
     - `transformation` - A boolean (default: `False`). If this boolean is set to `True` a second matrix is output (see OUTPUT).

    OUTPUT:

    If `transformation` is `False`, the output is `W`, a row reduced form of `M`.

    If `transformation` is `True`, this function will output a pair `(W,N)` consisting of two matrices over `k(x)`:

    1. `W` - a row reduced form of `M`.
    2. `N` - an invertible matrix over `k(x)` satisfying `NW = M`.

    EXAMPLES:

    The function expects matrices over the rational function field, but
    other examples below show how one can provide matrices over the ring
    of polynomials (whose quotient field is the rational function field).

    ::

        sage: R.<t> = GF(3)['t']
        sage: K = FractionField(R)
        sage: import sage.matrix.matrix_misc
        sage: sage.matrix.matrix_misc.row_reduced_form(matrix([[(t-1)^2/t],[(t-1)]]))
        doctest:...: DeprecationWarning: Row reduced form will soon be supported only for matrices of polynomials.
        See http://trac.sagemath.org/21024 for details.
        [        0]
        [(t + 2)/t]

    The last example shows the usage of the transformation parameter.

    ::
        sage: Fq.<a> = GF(2^3)
        sage: Fx.<x> = Fq[]
        sage: A = matrix(Fx,[[x^2+a,x^4+a],[x^3,a*x^4]])
        sage: from sage.matrix.matrix_misc import row_reduced_form
        sage: row_reduced_form(A,transformation=True)
        (
        [          x^2 + a           x^4 + a]  [1 0]
        [x^3 + a*x^2 + a^2               a^2], [a 1]
        )

    NOTES:

    See docstring for row_reduced_form method of matrices for
    more information.
    """
    from sage.misc.superseded import deprecation
    deprecation(21024, "Row reduced form will soon be supported only for matrices of polynomials.")

    # determine whether M has polynomial or rational function coefficients
    R0 = M.base_ring()

    #Compute the base polynomial ring
    if R0 in _Fields:
        R = R0.base()
    else:
        R = R0
    from sage.rings.polynomial.polynomial_ring import is_PolynomialRing
    if not is_PolynomialRing(R) or not R.base_ring().is_field():
        raise TypeError("the coefficients of M must lie in a univariate polynomial ring over a field")

    t = R.gen()

    # calculate least-common denominator of matrix entries and clear
    # denominators. The result lies in R
    from sage.arith.all import lcm
    from sage.matrix.constructor import matrix
    from sage.misc.functional import numerator
    if R0 in _Fields:
        den = lcm([a.denominator() for a in M.list()])
        num = matrix([[numerator(_) for _ in v] for v in (M*den).rows()])
    else:
        # No need to clear denominators
        num = M

    if transformation:
        A, N = num.row_reduced_form(transformation=True)
    else:
        A = num.row_reduced_form(transformation=False)

    if not is_PolynomialRing(R0):
        A = ~den * A

    if transformation:
        return (A, N)
    else:
        return A
Пример #4
0
def row_reduced_form(M, transformation=False):
    """
    This function computes a row reduced form of a matrix over a rational
    function field `k(x)`, for `k` a field.

    INPUT:

     - `M` - a matrix over `k(x)` or `k[x]` for `k` a field.
     - `transformation` - A boolean (default: `False`). If this boolean is set to `True` a second matrix is output (see OUTPUT).

    OUTPUT:

    If `transformation` is `False`, the output is `W`, a row reduced form of `M`.

    If `transformation` is `True`, this function will output a pair `(W,N)` consisting of two matrices over `k(x)`:

    1. `W` - a row reduced form of `M`.
    2. `N` - an invertible matrix over `k(x)` satisfying `NW = M`.

    EXAMPLES:

    The function expects matrices over the rational function field, but
    other examples below show how one can provide matrices over the ring
    of polynomials (whose quotient field is the rational function field).

    ::

        sage: R.<t> = GF(3)['t']
        sage: K = FractionField(R)
        sage: import sage.matrix.matrix_misc
        sage: sage.matrix.matrix_misc.row_reduced_form(matrix([[(t-1)^2/t],[(t-1)]]))
        doctest:...: DeprecationWarning: Row reduced form will soon be supported only for matrices of polynomials.
        See http://trac.sagemath.org/21024 for details.
        [        0]
        [(t + 2)/t]

    The last example shows the usage of the transformation parameter.

    ::
        sage: Fq.<a> = GF(2^3)
        sage: Fx.<x> = Fq[]
        sage: A = matrix(Fx,[[x^2+a,x^4+a],[x^3,a*x^4]])
        sage: from sage.matrix.matrix_misc import row_reduced_form
        sage: row_reduced_form(A,transformation=True)
        (
        [          x^2 + a           x^4 + a]  [1 0]
        [x^3 + a*x^2 + a^2               a^2], [a 1]
        )

    NOTES:

    See docstring for row_reduced_form method of matrices for
    more information.
    """
    from sage.misc.superseded import deprecation
    deprecation(
        21024,
        "Row reduced form will soon be supported only for matrices of polynomials."
    )

    # determine whether M has polynomial or rational function coefficients
    R0 = M.base_ring()

    #Compute the base polynomial ring
    if R0 in _Fields:
        R = R0.base()
    else:
        R = R0
    from sage.rings.polynomial.polynomial_ring import is_PolynomialRing
    if not is_PolynomialRing(R) or not R.base_ring().is_field():
        raise TypeError(
            "the coefficients of M must lie in a univariate polynomial ring over a field"
        )

    t = R.gen()

    # calculate least-common denominator of matrix entries and clear
    # denominators. The result lies in R
    from sage.arith.all import lcm
    from sage.matrix.constructor import matrix
    from sage.misc.functional import numerator
    if R0 in _Fields:
        den = lcm([a.denominator() for a in M.list()])
        num = matrix([[numerator(_) for _ in v] for v in (M * den).rows()])
    else:
        # No need to clear denominators
        num = M

    if transformation:
        A, N = num.row_reduced_form(transformation=True)
    else:
        A = num.row_reduced_form(transformation=False)

    if not is_PolynomialRing(R0):
        A = ~den * A

    if transformation:
        return (A, N)
    else:
        return A
Пример #5
0
def row_reduced_form(M,transformation=False):
    """
    This function computes a row reduced form of a matrix over a rational
    function field `k(x)`, for `k` a field.

    INPUT:

     - `M` - a matrix over `k(x)` or `k[x]` for `k` a field.
     - `transformation` - A boolean (default: `False`). If this boolean is set to `True` a second matrix is output (see OUTPUT).
     
    OUTPUT:

    If `transformation` is `False`, the output is `W`, a row reduced form of `M`.
    
    If `transformation` is `True`, this function will output a pair `(W,N)` consisting of two matrices over `k(x)`:

    1. `W` - a row reduced form of `M`.
    2. `N` - an invertible matrix over `k(x)` satisfying `NW = M`.

    EXAMPLES:

    The fuction expects matrices over the rational function field, but
    other examples below show how one can provide matrices over the ring
    of polynomials (whose quotient field is the rational function field).

    ::

        sage: R.<t> = GF(3)['t']
        sage: K = FractionField(R)
        sage: import sage.matrix.matrix_misc
        sage: sage.matrix.matrix_misc.row_reduced_form(matrix([[(t-1)^2/t],[(t-1)]]))
        [(2*t + 1)/t]
        [          0]

    The last example shows the usage of the transformation parameter.
        
    ::
        sage: Fq.<a> = GF(2^3)
        sage: Fx.<x> = Fq[]
        sage: A = matrix(Fx,[[x^2+a,x^4+a],[x^3,a*x^4]])
        sage: from sage.matrix.matrix_misc import row_reduced_form
        sage: row_reduced_form(A,transformation=True)
        (
        [(a^2 + 1)*x^3 + x^2 + a                       a]  [      1 a^2 + 1]
        [                    x^3                   a*x^4], [      0                 1]
        )
            
    NOTES:

    See docstring for row_reduced_form method of matrices for
    more information.
    """

    # determine whether M has polynomial or rational function coefficients
    R0 = M.base_ring()

    #Compute the base polynomial ring
    if R0 in _Fields:
        R = R0.base()
    else:
        R = R0
    from sage.rings.polynomial.polynomial_ring import is_PolynomialRing
    if not is_PolynomialRing(R) or not R.base_ring().is_field():
        raise TypeError("the coefficients of M must lie in a univariate polynomial ring over a field")

    t = R.gen()

    # calculate least-common denominator of matrix entries and clear
    # denominators. The result lies in R
    from sage.arith.all import lcm
    from sage.matrix.constructor import matrix
    from sage.misc.functional import numerator
    if R0 in _Fields:
        den = lcm([a.denominator() for a in M.list()])
        num = matrix([[numerator(_) for _ in v] for v in (M*den).rows()])
    else:
        # No need to clear denominators
        num = M

    r = [list(v) for v in num.rows()]

    if transformation:
        N = matrix(num.nrows(), num.nrows(), R(1)).rows()


    rank = 0
    num_zero = 0
    if M.is_zero():
        num_zero = len(r)
    while rank != len(r) - num_zero:
        # construct matrix of leading coefficients
        v = []
        for w in map(list, r):
            # calculate degree of row (= max of degree of entries)
            d = max([e.numerator().degree() for e in w])

            # extract leading coefficients from current row
            x = []
            for y in w:
                if y.degree() >= d and d >= 0:   x.append(y.coefficients(sparse=False)[d])
                else:                            x.append(0)
            v.append(x)
        l = matrix(v)

        # count number of zero rows in leading coefficient matrix
        # because they do *not* contribute interesting relations
        num_zero = 0
        for v in l.rows():
            is_zero = 1
            for w in v:
                if w != 0:
                    is_zero = 0
            if is_zero == 1:
                num_zero += 1

        # find non-trivial relations among the columns of the
        # leading coefficient matrix
        kern = l.kernel().basis()
        rank = num.nrows() - len(kern)

        # do a row operation if there's a non-trivial relation
        if not rank == len(r) - num_zero:
            for rel in kern:
                # find the row of num involved in the relation and of
                # maximal degree
                indices = []
                degrees = []
                for i in range(len(rel)):
                    if rel[i] != 0:
                        indices.append(i)
                        degrees.append(max([e.degree() for e in r[i]]))

                # find maximum degree among rows involved in relation
                max_deg = max(degrees)

                # check if relation involves non-zero rows
                if max_deg != -1:
                    i = degrees.index(max_deg)
                    rel /= rel[indices[i]]

                    for j in range(len(indices)):
                        if j != i:
                            # do the row operation
                            v = []
                            for k in range(len(r[indices[i]])):
                                v.append(r[indices[i]][k] + rel[indices[j]] * t**(max_deg-degrees[j]) * r[indices[j]][k])
                            r[indices[i]] = v

                            if transformation:
                                # If the user asked for it, record the row operation 
                                v = []
                                for k in range(len(N[indices[i]])):
                                    v.append(N[indices[i]][k] + rel[indices[j]] * t**(max_deg-degrees[j]) * N[indices[j]][k])
                                N[indices[i]] = v

                    # remaining relations (if any) are no longer valid,
                    # so continue onto next step of algorithm
                    break
    if is_PolynomialRing(R0):
        A = matrix(R, r)
    else:
        A = matrix(R, r)/den
    if transformation:
        return (A, matrix(N))
    else:
        return A
Пример #6
0
def row_reduced_form(M,ascend=True):
    """
    This function computes a weak Popov form of a matrix over a rational
    function field `k(x)`, for `k` a field.

    INPUT:

     - `M` - matrix

     - `ascend` - if True, rows of output matrix `W` are sorted so
       degree (= the maximum of the degrees of the elements in
       the row) increases monotonically, and otherwise degrees decrease.

    OUTPUT:

    A 3-tuple `(W,N,d)` consisting of two matrices over `k(x)` and a list
    of integers:

    1. `W` - matrix giving a weak the Popov form of M
    2. `N` - matrix representing row operations used to transform
       `M` to `W`
    3. `d` - degree of respective columns of W; the degree of a column is
       the maximum of the degree of its elements

    `N` is invertible over `k(x)`. These matrices satisfy the relation
    `N*M = W`.

    EXAMPLES:

    The routine expects matrices over the rational function field, but
    other examples below show how one can provide matrices over the ring
    of polynomials (whose quotient field is the rational function field).

    ::

        sage: R.<t> = GF(3)['t']
        sage: K = FractionField(R)
        sage: import sage.matrix.matrix_misc
        sage: sage.matrix.matrix_misc.row_reduced_form(matrix([[(t-1)^2/t],[(t-1)]]))
        (
        [          0]  [      t 2*t + 1]
        [(2*t + 1)/t], [      1       2], [-Infinity, 0]
        )

    NOTES:

    See docstring for row_reduced_form method of matrices for
    more information.
    """

    # determine whether M has polynomial or rational function coefficients
    R0 = M.base_ring()

    #Compute the base polynomial ring
    if R0 in _Fields:
        R = R0.base()
    else:
        R = R0
    from sage.rings.polynomial.polynomial_ring import is_PolynomialRing
    if not is_PolynomialRing(R):
        raise TypeError("the coefficients of M must lie in a univariate polynomial ring")

    t = R.gen()

    # calculate least-common denominator of matrix entries and clear
    # denominators. The result lies in R
    from sage.rings.arith import lcm
    from sage.matrix.constructor import matrix
    from sage.misc.functional import numerator
    if R0 in _Fields:
        den = lcm([a.denominator() for a in M.list()])
        num = matrix([[numerator(_) for _ in v] for v in (M*den).rows()])
    else:
        # No need to clear denominators
        den = R.one()
        num = M

    r = [list(v) for v in num.rows()]

    N = matrix(num.nrows(), num.nrows(), R(1)).rows()

    from sage.rings.infinity import Infinity
    if M.is_zero():
        return (M, matrix(N), [-Infinity for i in range(num.nrows())])

    rank = 0
    num_zero = 0
    while rank != len(r) - num_zero:
        # construct matrix of leading coefficients
        v = []
        for w in map(list, r):
            # calculate degree of row (= max of degree of entries)
            d = max([e.numerator().degree() for e in w])

            # extract leading coefficients from current row
            x = []
            for y in w:
                if y.degree() >= d and d >= 0:   x.append(y.coefficients(sparse=False)[d])
                else:                            x.append(0)
            v.append(x)
        l = matrix(v)

        # count number of zero rows in leading coefficient matrix
        # because they do *not* contribute interesting relations
        num_zero = 0
        for v in l.rows():
            is_zero = 1
            for w in v:
                if w != 0:
                    is_zero = 0
            if is_zero == 1:
                num_zero += 1

        # find non-trivial relations among the columns of the
        # leading coefficient matrix
        kern = l.kernel().basis()
        rank = num.nrows() - len(kern)

        # do a row operation if there's a non-trivial relation
        if not rank == len(r) - num_zero:
            for rel in kern:
                # find the row of num involved in the relation and of
                # maximal degree
                indices = []
                degrees = []
                for i in range(len(rel)):
                    if rel[i] != 0:
                        indices.append(i)
                        degrees.append(max([e.degree() for e in r[i]]))

                # find maximum degree among rows involved in relation
                max_deg = max(degrees)

                # check if relation involves non-zero rows
                if max_deg != -1:
                    i = degrees.index(max_deg)
                    rel /= rel[indices[i]]

                    for j in range(len(indices)):
                        if j != i:
                            # do row operation and record it
                            v = []
                            for k in range(len(r[indices[i]])):
                                v.append(r[indices[i]][k] + rel[indices[j]] * t**(max_deg-degrees[j]) * r[indices[j]][k])
                            r[indices[i]] = v

                            v = []
                            for k in range(len(N[indices[i]])):
                                v.append(N[indices[i]][k] + rel[indices[j]] * t**(max_deg-degrees[j]) * N[indices[j]][k])
                            N[indices[i]] = v

                    # remaining relations (if any) are no longer valid,
                    # so continue onto next step of algorithm
                    break

    # sort the rows in order of degree
    d = []
    from sage.rings.all import infinity
    for i in range(len(r)):
        d.append(max([e.degree() for e in r[i]]))
        if d[i] < 0:
            d[i] = -infinity
        else:
            d[i] -= den.degree()

    for i in range(len(r)):
        for j in range(i+1,len(r)):
            if (ascend and d[i] > d[j]) or (not ascend and d[i] < d[j]):
                (r[i], r[j]) = (r[j], r[i])
                (d[i], d[j]) = (d[j], d[i])
                (N[i], N[j]) = (N[j], N[i])

    # return reduced matrix and operations matrix
    return (matrix(r)/den, matrix(N), d)