code: @SuppressWarnings({"unchecked", "rawtypes"})
      private static InternalNode<?> joinMIDDatSameLevel(InternalNode n1, InternalNode n2) throws MIDDException {
          if (n1.getID() != n2.getID()) {
              throw new IllegalArgumentException("Both params should have the same variable level at their root");
          }
  
          if (n1.getType() != n2.getType()) {
              throw new IllegalArgumentException("Both IDD roots should have the same data type");
          }
  
          Partition p1 = PartitionBuilder.createPartition(n1.getIntervals());
          Partition p2 = PartitionBuilder.createPartition(n2.getIntervals());
  
          // Get the common intervals of two partitions
          Partition<?> p = PartitionBuilder.intersect(p1, p2);
          if (p.size() == 0) {
              // return false-node
              log.error("empty intersect partition");
              return null;
          }
  
          // Clone n1: warning: new MIDD node's state should be combined from two node states: n1 & n2???
          InternalNode<?> newMIDD = NodeUtils.createInternalNode(n1.getID(), n1.getState(), n1.getType());
  
          for (Interval<?> interval : p.getIntervals()) {
              AbstractNode op1 = n1.getChild(interval);
              AbstractNode op2 = n2.getChild(interval);
  
              AbstractNode child = null;
  
              if (op1 != null && op2 != null) {
                  child = join(op1, op2);
              } else if (op1 != null || op2 != null) {
                  child = (op1 == null) ? GenericUtils.newInstance(op2) : GenericUtils.newInstance(op1);
              } else {
                  throw new RuntimeException("Error joining two partitions, the output partition is incorrect");
              }
  
              if (child != null) {
                  AbstractEdge<?> edge = EdgeUtils.createEdge(interval, newMIDD.getType());
                  newMIDD.addChild(edge, child);
              } else {
                  System.err.println("Empty child");
              }
          }
  
          return newMIDD;
      }
docs: Combine two MIDD with same level of attribute at their roots
  
  @param n1
  @param n2
  @return