docs: public void pack() {
          // we must clone, since we want to iterate only over the original list
          final Object[] clone = this.children.toArray();
          for (Object aClone : clone) {
              // if child is also a group element, there may be
              // some possible clean up / optimizations to be done
              if (aClone instanceof GroupElement) {
                  final GroupElement childGroup = (GroupElement) aClone;
                  childGroup.pack(this);
              }
          }
  
          // if after packing, this is an AND or OR GE with a single
          // child GE, then clone child into current node eliminating child
          if ( (this.isAnd() || this.isOr()) && (this.children.size() == 1) ) {
              final Object child = this.getChildren().get( 0 );
              if ( child instanceof GroupElement ) {
                  mergeGroupElements( this, (GroupElement) child );
              }
          }
          
          // if after packing, this is a NOT GE with an EXISTS child
          // or this is an EXISTS GE with a NOT child, eliminate the redundant 
          // child and make this a NOT GE
          if ( this.isNot() && this.children.size() == 1 && this.getChildren().get( 0 ) instanceof GroupElement ) {
              final GroupElement child = (GroupElement) this.getChildren().get( 0 );
              if ( child.isExists() ) {
                  this.children.clear();
                  this.children.addAll( child.getChildren() );
              }
          }
          if ( this.isExists() && this.children.size() == 1 && this.getChildren().get( 0 ) instanceof GroupElement ) {
              final GroupElement child = (GroupElement) this.getChildren().get( 0 );
              if ( child.isNot() ) {
                  this.setType( NOT );
                  this.children.clear();
                  this.children.addAll( child.getChildren() );
              }
          }
  
      }