func getSiblingsByASN(n LeafNode, inventory []LeafNode) []LeafNode {
	if ipn, ok := n.(*IPNode) ; ok {
		return getSiblingsUsingFilteringFun(inventory, ipn.similarASN)
	}
	return []LeafNode{}
}
TODO add comment
package graph
import (
	"fmt"
	"github.com/hashicorp/go-immutable-radix"
	"github.com/deckarep/golang-set"
	"net"
	"github.com/ANSSI-FR/transdep/tools"
)
func (rn *RelationshipNode) simplifyRelWithCycle() bool {
	var newChildren []Node
	modif := false
	childrenToAnalyze := rn.children[:]
	Outerloop:
	for len(childrenToAnalyze) != 0 {
		var mergedChildren []Node
		Innerloop:
		for _, chld := range childrenToAnalyze {
			if dg, ok := chld.(*RelationshipNode); ok {
				modif = dg.simplifyRelWithCycle() || modif
				if len(dg.children) == 1 {
					mergedChildren = append(mergedChildren, dg.children[0])
					modif = true
					continue Innerloop
				}
			}
			if _, ok := chld.(*Cycle); ok {
				if rn.relation == AND_REL && len(rn.children) > 1 {
					newChildren = []Node{new(Cycle)}
					modif = true
					break Outerloop
				}
			}
			newChildren = append(newChildren, chld)
		}
		childrenToAnalyze = mergedChildren
	}
	rn.children = newChildren
	return modif
}
func (rn *RelationshipNode) auxSimplifyGraph() bool {
	var newChildren []Node
	modif := false
	childrenToAnalyze := make([]Node, len(rn.children))
	copy(childrenToAnalyze, rn.children)
	for len(childrenToAnalyze) > 0 {
		var mergedChildren []Node
		for _, chldGraphNode := range childrenToAnalyze {
			if chld, ok := chldGraphNode.(*RelationshipNode); ok {
				if chld.relation == rn.relation {
					mergedChildren = append(mergedChildren, chld.children...)
					modif = true
				} else {
					newChildren = append(newChildren, chldGraphNode)
				}
			} else {
				newChildren = append(newChildren, chldGraphNode)
			}
		}
		childrenToAnalyze = make([]Node, len(mergedChildren))
		copy(childrenToAnalyze, mergedChildren)
	}
	rn.children = make([]Node, len(newChildren))
	copy(rn.children, newChildren)
	for _, chldGraphNode := range rn.children {
		if chld, ok := chldGraphNode.(*RelationshipNode); ok {
			modif = chld.auxSimplifyGraph() || modif
		}
	}
	return modif
}
func (rn *RelationshipNode) SimplifyGraph() *RelationshipNode {
	ng, ok := rn.deepcopy().(*RelationshipNode)
	if !ok {
		return nil
	}
	modif := true
	for modif {
		modif = false
		modif = ng.auxSimplifyGraph() || modif
		modif = ng.simplifyRelWithCycle() || modif
	}
	return ng
}
func (rn *RelationshipNode) buildLeafNodeInventory() []LeafNode {
	l := make([]LeafNode, 0)
	for _, absChld := range rn.children {
		switch chld := absChld.(type) {
		case *RelationshipNode:
			l2 := chld.buildLeafNodeInventory()
			l = append(l, l2...)
		case LeafNode:
			l = append(l, chld)
		}
	}
	return l
}
func getSiblingsUsingSimilarity(leafNode LeafNode, inventory []LeafNode, breakV4, breakV6, DNSSECOnly bool) []LeafNode {
	var siblings []LeafNode
	for _, node := range inventory {
		toIgnore := false
		toAdd := false
		switch n := node.(type) {
		case *DomainNameNode:
			if DNSSECOnly && !n.DNSSECProtected() {
				toIgnore = true
			}
		case *AliasNode:
			toIgnore = true
		case *IPNode:
			isV4 := n.IsV4()
			if (breakV4 && isV4) || (breakV6 && !isV4) {
				toAdd = true
			}
		case *Cycle:
			toAdd = true
		}
		if toAdd || (!toIgnore && leafNode.similar(node)) {
			siblings = append(siblings, node)
		}
	}
	return siblings
}
func (rn *RelationshipNode) testNodeCriticity(siblings []LeafNode) bool {
	orSet := make(map[*RelationshipNode]int)
	andSet := make(map[*RelationshipNode]bool)
	var unavailableNodes []Node
	for _, n := range siblings {
		unavailableNodes = append(unavailableNodes, n)
	}
	for len(unavailableNodes) > 0 {
		nodesToHandle := unavailableNodes
		unavailableNodes = []Node{}
		for _, node := range nodesToHandle {
			parent := node.parent()
			if parent == nil {
				return true
			}
			n := parent.(*RelationshipNode)
			if n.relation == AND_REL {
				if _, ok := andSet[n]; !ok {
					andSet[n] = true
					unavailableNodes = append(unavailableNodes, n)
				}
			} else {
				if v, ok := orSet[n]; ok {
					orSet[n] = v + 1
				} else {
					orSet[n] = 1
				}
				if len(n.children) == orSet[n] {
					unavailableNodes = append(unavailableNodes, n)
				}
			}
		}
	}
	return false
}
func getSiblingsByPrefixCloseness(n LeafNode, inventory []LeafNode) []LeafNode {
	if ipn, ok := n.(*IPNode) ; ok {
		return getSiblingsUsingFilteringFun(inventory, ipn.similarPrefix)
	}
	return []LeafNode{}
}
func (rn *RelationshipNode) findMandatoryNodesUsingPrefixCloseness(inventory []LeafNode)(mandatoryNodes, optionalNodes mapset.Set) {
	return rn.findMandatoryNodes(inventory, getSiblingsByPrefixCloseness)
}
func (rn *RelationshipNode) findMandatoryNodesUsingSimilarity(inventory []LeafNode, breakV4, breakV6, DNSSECOnly bool) (mandatoryNodes, optionalNodes mapset.Set) {
	getSiblingsFun := func(n LeafNode, inv []LeafNode) []LeafNode {
		return getSiblingsUsingSimilarity(n, inv, breakV4, breakV6, DNSSECOnly)
	}
	return rn.findMandatoryNodes(inventory, getSiblingsFun)
}
func getSiblingsUsingFilteringFun(inventory []LeafNode, customFilterFun func(lf LeafNode) bool) []LeafNode {
	var siblings []LeafNode
	for _, lf := range inventory {
		if _, ok := lf.(*Cycle) ; ok || customFilterFun(lf) {
			siblings = append(siblings, lf)
		}
	}
	return siblings
}