'Verifies that there is no loop in a directed graph of records, by
following a many2many relationship with the given field name.
:param field_name: field to check
:return: **True** if no loop was found, **False** otherwise.'

@api.multi
def _check_m2m_recursion(self, field_name):

    field = self._fields.get(field_name)
    if (not (field and (field.type == 'many2many') and (field.comodel_name == self._name) and field.store)):
        raise ValueError(('invalid    field_name:    %r' % (field_name,)))
    cr = self._cr
    query = ('SELECT    "%s",    "%s"    FROM    "%s"    WHERE    "%s"    IN    %%s    AND    "%s"    IS    NOT    NULL' % (field.column1, field.column2, field.relation, field.column1, field.column2))
    succs = defaultdict(set)
    preds = defaultdict(set)
    (todo, done) = (set(self.ids), set())
    while todo:
        cr.execute(query, [tuple(todo)])
        done.update(todo)
        todo.clear()
        for (id1, id2) in cr.fetchall():
            for (x, y) in itertools.product(([id1] + list(preds[id1])), ([id2] + list(succs[id2]))):
                if (x == y):
                    return False
                succs[x].add(y)
                preds[y].add(x)
            if (id2 not in done):
                todo.add(id2)
    return True
