/**
   * Makes a disjoint union with another graph. They must share the same bottom and top elements.
   *
   * @param otherGraph other graph to make the union
   */
  public void disjointUnion(IntegerHierarchicalGraph otherGraph) {
    Objects.requireNonNull(otherGraph);
    if (getBottomElement().equals(otherGraph.getBottomElement())
        && getTopElement().equals(otherGraph.getTopElement())) {
      Set<Integer> set = new HashSet<>();
      set.addAll(getElements());
      set.remove(getBottomElement());
      set.remove(getTopElement());
      set.retainAll(otherGraph.getElements());

      if (!set.isEmpty()) {
        throw new IllegalArgumentException("Graphs are not disjoint.");
      }

      Set<Integer> otherSet = new HashSet<>();
      otherSet.addAll(otherGraph.getElements());
      otherSet.forEach(
          elem -> {
            if (Objects.isNull(this.children.get(elem))) {
              this.children.put(elem, new HashSet<>());
            }
            this.children.get(elem).addAll(otherGraph.getChildren(elem));

            if (Objects.isNull(this.parents.get(elem))) {
              this.parents.put(elem, new HashSet<>());
            }
            this.parents.get(elem).addAll(otherGraph.getParents(elem));

            if (Objects.isNull(this.equivalents.get(elem))) {
              this.equivalents.put(elem, new HashSet<>());
            }
            if (Objects.isNull(this.representative.get(elem))) {
              this.representative.put(elem, elem);
            }
            otherGraph.getEquivalents(elem).forEach(otherElem -> makeEquivalent(elem, otherElem));
          });

    } else {
      throw new IllegalArgumentException(
          "Both graphs have different bottom element or different top element.");
    }
  }
  @Override
  public boolean equals(Object o) {
    boolean ret = (this == o);
    if (!ret && (o instanceof IntegerHierarchicalGraph)) {
      IntegerHierarchicalGraph other = (IntegerHierarchicalGraph) o;
      ret =
          getBottomElement().equals(other.getBottomElement())
              && getTopElement().equals(other.getTopElement())
              && getElements().equals(other.getElements());

      ret =
          ret
              && getElements()
                  .stream()
                  .allMatch(
                      elem ->
                          getChildren(elem).equals(other.getChildren(elem))
                              && getParents(elem).equals(other.getParents(elem))
                              && getEquivalents(elem).equals(other.getEquivalents(elem)));
    }
    return ret;
  }