def undirectedFwdCycle(val, fromELR, rels, drsELR, drsRelsFrom, drsRelsTo, fromConceptELRs, ELRsVisited=None):
    if not ELRsVisited: ELRsVisited = set()
    ELRsVisited.add(fromELR)
    for rel in rels:
        if rel.linkrole == fromELR:
            relTo = rel.toModelObject
            if isinstance(relTo, ModelConcept):
                toELR = rel.targetRole
                if not toELR:
                    toELR = fromELR
                if relTo in fromConceptELRs and toELR in fromConceptELRs[relTo]: #forms a directed cycle
                    return [rel,True]
                fromConceptELRs[relTo].add(toELR)
                if drsRelsFrom:
                    domMbrRels = drsRelsFrom[relTo]
                else:
                    domMbrRels = val.modelXbrl.relationshipSet(
                             XbrlConst.domainMember, toELR).fromModelObject(relTo)
                cycleCausingConcept = undirectedFwdCycle(val, toELR, domMbrRels, drsELR, drsRelsFrom, drsRelsTo, fromConceptELRs, ELRsVisited)
                if cycleCausingConcept is not None:
                    cycleCausingConcept.append(rel)
                    cycleCausingConcept.append(True)
                    return cycleCausingConcept
                fromConceptELRs[relTo].discard(toELR)
                # look for back path in any of the ELRs visited (pass None as ELR)
                cycleCausingConcept = undirectedRevCycle(val, None, relTo, rel, drsELR, drsRelsFrom, drsRelsTo, fromConceptELRs, ELRsVisited)
                if cycleCausingConcept is not None:
                    cycleCausingConcept.append(rel)
                    cycleCausingConcept.append(True)
                    return cycleCausingConcept
    return None
dataset/ETHPy150Open Arelle/Arelle/arelle/ValidateFilingDimensions.py/undirectedFwdCycle/original