'Return True if the sides of the relationship are mathematically
identical and the type of relationship is the same.
If failing_expression is True, return the expression whose truth value
was unknown.'

def equals(self, other, failing_expression=False):

    if isinstance(other, Relational):
        if ((self == other) or (self.reversed == other)):
            return True
        (a, b) = (self, other)
        if ((a.func in (Eq, Ne)) or (b.func in (Eq, Ne))):
            if (a.func != b.func):
                return False
            (l, r) = [i.equals(j, failing_expression=failing_expression) for (i, j) in zip(a.args, b.args)]
            if (l is True):
                return r
            if (r is True):
                return l
            (lr, rl) = [i.equals(j, failing_expression=failing_expression) for (i, j) in zip(a.args, b.reversed.args)]
            if (lr is True):
                return rl
            if (rl is True):
                return lr
            e = (l, r, lr, rl)
            if all(((i is False) for i in e)):
                return False
            for i in e:
                if (i not in (True, False)):
                    return i
        else:
            if (b.func != a.func):
                b = b.reversed
            if (a.func != b.func):
                return False
            l = a.lhs.equals(b.lhs, failing_expression=failing_expression)
            if (l is False):
                return False
            r = a.rhs.equals(b.rhs, failing_expression=failing_expression)
            if (r is False):
                return False
            if (l is True):
                return r
            return l
