def is_structured_decomposable(spn, verbose=False):
    if (not is_consistent(spn)):
        return False
    nodes = get_nodes_by_type(spn)
    scope_set = set()
    for n in nodes:
        if isinstance(n, Product):
            scope_set.add(tuple(n.scope))
        elif isinstance(n, CLTree):
            vtree = from_dtree_to_vtree(n.dtree_root)
            scope_set.update([tuple(s) for s in vtree.scopes])
    scopes = list(scope_set)
    scopes = [set(t) for t in scopes]
    if verbose:
        scopes.sort(key=len)
        for s in scopes:
            print(s)
    for i in range(len(scopes)):
        for j in range(len(scopes)):
            int_len = len(scopes[i].intersection(scopes[j]))
            if ((int_len != 0) and (int_len != min(len(scopes[i]), len(scopes[j])))):
                return False
    return True
def is_structured_decomposable(spn, verbose=False):
    if (not is_consistent(spn)):
        return False
    nodes = get_nodes_by_type(spn)
    scope_set = set()
    for n in nodes:
        if isinstance(n, Product):
            scope_set.add(tuple(n.scope))
        elif isinstance(n, CLTree):
            vtree = from_dtree_to_vtree(n.dtree_root)
            scope_set.update([tuple(s) for s in vtree.scopes])
    scopes = list(scope_set)
    scopes = [set(t) for t in scopes]
    if verbose:
        scopes.sort(key=len)
        for s in scopes:
            print(s)
    for i in range(len(scopes)):
        for j in range(len(scopes)):
            int_len = len(scopes[i].intersection(scopes[j]))
            if ((int_len != 0) and (int_len != min(len(scopes[i]), len(scopes[j])))):
                return False
    return True