human
Complete this python program:
def invariant_factors(m, domain=None):
assistant
#Here is the Python program you requested.

    """Return the tuple of abelian invariants for a matrix `m`
    (as in the Smith-Normal form)
    References
    [1] https://en.wikipedia.org/wiki/Smith_normal_form#Algorithm
    [2] http://sierra.nmsu.edu/morandi/notes/SmithNormalForm.pdf
    """
    if (not domain):
        if (not (hasattr(m, 'ring') and m.ring.is_PID)):
            raise ValueError('The    matrix    entries    must    be    over    a    principal    ideal    domain')
        else:
            domain = m.ring
    if (len(m) == 0):
        return ()
    m = m[:, :]
    def add_rows(m, i, j, a, b, c, d):
        for k in range(m.cols):
            e = m[(i, k)]
            m[(i, k)] = ((a * e) + (b * m[(j, k)]))
            m[(j, k)] = ((c * e) + (d * m[(j, k)]))
    def add_columns(m, i, j, a, b, c, d):
        for k in range(m.rows):
            e = m[(k, i)]
            m[(k, i)] = ((a * e) + (b * m[(k, j)]))
            m[(k, j)] = ((c * e) + (d * m[(k, j)]))
    def clear_column(m):
        if (m[(0, 0)] == 0):
            return m
        pivot = m[(0, 0)]
        for j in range(1, m.rows):
            if (m[(j, 0)] == 0):
                continue
            (d, r) = domain.div(m[(j, 0)], pivot)
            if (r == 0):
                add_rows(m, 0, j, 1, 0, (- d), 1)
            else:
                (a, b, g) = domain.gcdex(pivot, m[(j, 0)])
                d_0 = domain.div(m[(j, 0)], g)[0]
                d_j = domain.div(pivot, g)[0]
                add_rows(m, 0, j, a, b, d_0, (- d_j))
                pivot = g
        return m
    def clear_row(m):
        if (m[0] == 0):
            return m
        pivot = m[(0, 0)]
        for j in range(1, m.cols):
            if (m[(0, j)] == 0):
                continue
            (d, r) = domain.div(m[(0, j)], pivot)
            if (r == 0):
                add_columns(m, 0, j, 1, 0, (- d), 1)
            else:
                (a, b, g) = domain.gcdex(pivot, m[(0, j)])
                d_0 = domain.div(m[(0, j)], g)[0]
                d_j = domain.div(pivot, g)[0]
                add_columns(m, 0, j, a, b, d_0, (- d_j))
                pivot = g
        return m
    ind = [i for i in range(m.rows) if (m[(i, 0)] != 0)]
    if ind:
        m = m.permute_rows([[0, ind[0]]])
    else:
        ind = [j for j in range(m.cols) if (m[(0,...