'Returns the dual of a matrix, which is:
`(1/2)*levicivita(i, j, k, l)*M(k, l)` summed over indices `k` and `l`
Since the levicivita method is anti_symmetric for any pairwise
exchange of indices, the dual of a symmetric matrix is the zero
matrix. Strictly speaking the dual defined here assumes that the
\'matrix\' `M` is a contravariant anti_symmetric second rank tensor,
so that the dual is a covariant second rank tensor.'

def dual(self):

    from sympy import LeviCivita
    from sympy.matrices import zeros
    (M, n) = (self[:, :], self.rows)
    work = zeros(n)
    if self.is_symmetric():
        return work
    for i in range(1, n):
        for j in range(1, n):
            acum = 0
            for k in range(1, n):
                acum += (LeviCivita(i, j, 0, k) * M[(0, k)])
            work[(i, j)] = acum
            work[(j, i)] = (- acum)
    for l in range(1, n):
        acum = 0
        for a in range(1, n):
            for b in range(1, n):
                acum += (LeviCivita(0, l, a, b) * M[(a, b)])
        acum /= 2
        work[(0, l)] = (- acum)
        work[(l, 0)] = acum
    return work
