/**
   * Try to expand a rule by right expansion only.
   *
   * @param ruleG the rule
   */
  private void expandR(RuleG ruleG) {
    // map to record the potential item to expand the right side of the rule
    // Key: item   Value: bitset indicating the IDs of the transaction containing the item
    // from the transactions containing the rule.
    Map<Integer, BitSet> mapCountRight = new HashMap<Integer, BitSet>();

    // for each transaction containing the rule
    for (int tid = ruleG.common.nextSetBit(0); tid >= 0; tid = ruleG.common.nextSetBit(tid + 1)) {

      // iterate over the items in this transaction
      Iterator<Integer> iter = database.getTransactions().get(tid).getItems().iterator();
      while (iter.hasNext()) {
        Integer item = iter.next();

        // if  that item is not frequent, then remove it from the transaction
        if (tableItemCount[item] < minsuppRelative) {
          iter.remove();
          continue;
        }

        // If the item is smaller than the largest item in the right side
        // of the rule, we can stop this loop because items
        // are sorted in lexicographical order.
        if (item < ruleG.maxRight) {
          break;
        }

        // if the item is larger than the maximum item in the right side
        // and is not contained in the left side of the rule
        if (item > ruleG.maxRight
            && !ArraysAlgos.containsLEX(ruleG.getItemset1(), item, ruleG.maxLeft)) {

          // update the tidset of the item
          BitSet tidsItem = mapCountRight.get(item);
          if (tidsItem == null) {
            tidsItem = new BitSet();
            mapCountRight.put(item, tidsItem);
          }
          tidsItem.set(tid);
        }
      }
    }

    // for each item c found in the previous step, we create a rule
    // I ==> J U {c} if the support is enough
    for (Entry<Integer, BitSet> entry : mapCountRight.entrySet()) {
      BitSet tidsRule = entry.getValue();
      int ruleSupport = tidsRule.cardinality();

      // if the support is enough
      if (ruleSupport >= minsuppRelative) {
        Integer itemC = entry.getKey();

        // create new right part of rule
        Integer[] newRightItemset = new Integer[ruleG.getItemset2().length + 1];
        System.arraycopy(ruleG.getItemset2(), 0, newRightItemset, 0, ruleG.getItemset2().length);
        newRightItemset[ruleG.getItemset2().length] = itemC;

        // recompute maxRight
        int maxRight = itemC >= ruleG.maxRight ? itemC : ruleG.maxRight;

        // calculate confidence
        double confidence = ((double) ruleSupport) / ruleG.tids1.cardinality();

        // create the rule
        RuleG candidate =
            new RuleG(
                ruleG.getItemset1(),
                newRightItemset,
                ruleSupport,
                ruleG.tids1,
                tidsRule,
                ruleG.maxLeft,
                maxRight);

        // if the confidence is enough
        if (confidence >= minConfidence) {
          // save the rule to the current top-k rules
          save(candidate, ruleSupport);
        }
        // register the rule as a candidate for future expansion(s)
        registerAsCandidate(false, candidate);
      }
    }
  }
  /**
   * Try to expand a rule by left and right expansions.
   *
   * @param ruleG the rule
   */
  private void expandLR(RuleG ruleG) {
    // Maps to record the potential item to expand the left/right sides of the rule
    // Key: item   Value: bitset indicating the IDs of the transaction containing the item
    // from the transactions containing the rule.
    Map<Integer, BitSet> mapCountLeft = new HashMap<Integer, BitSet>();
    Map<Integer, BitSet> mapCountRight = new HashMap<Integer, BitSet>();

    for (int tid = ruleG.common.nextSetBit(0); tid >= 0; tid = ruleG.common.nextSetBit(tid + 1)) {
      Iterator<Integer> iter = database.getTransactions().get(tid).getItems().iterator();
      while (iter.hasNext()) {
        Integer item = iter.next();
        // CAN DO THIS BECAUSE TRANSACTIONS ARE SORTED BY DESCENDING
        // ITEM IDS (see Database.Java)
        if (item < ruleG.maxLeft && item < ruleG.maxRight) { //
          break;
        }
        if (tableItemCount[item] < minsuppRelative) {
          iter.remove();
          continue;
        }
        if (item > ruleG.maxLeft
            && !ArraysAlgos.containsLEX(ruleG.getItemset2(), item, ruleG.maxRight)) {
          BitSet tidsItem = mapCountLeft.get(item);
          if (tidsItem == null) {
            tidsItem = new BitSet();
            mapCountLeft.put(item, tidsItem);
          }
          tidsItem.set(tid);
        }
        if (item > ruleG.maxRight
            && !ArraysAlgos.containsLEX(ruleG.getItemset1(), item, ruleG.maxLeft)) {
          BitSet tidsItem = mapCountRight.get(item);
          if (tidsItem == null) {
            tidsItem = new BitSet();
            mapCountRight.put(item, tidsItem);
          }
          tidsItem.set(tid);
        }
      }
    }

    // for each item c found in the previous step, we create a rule
    // I  ==> J U {c} if the support is enough
    for (Entry<Integer, BitSet> entry : mapCountRight.entrySet()) {
      BitSet tidsRule = entry.getValue();
      int ruleSupport = tidsRule.cardinality();

      // if the support is enough
      if (ruleSupport >= minsuppRelative) {
        Integer itemC = entry.getKey();

        // create new right part of rule
        Integer[] newRightItemset = new Integer[ruleG.getItemset2().length + 1];
        System.arraycopy(ruleG.getItemset2(), 0, newRightItemset, 0, ruleG.getItemset2().length);
        newRightItemset[ruleG.getItemset2().length] = itemC;

        // recompute maxRight
        int maxRight = (itemC >= ruleG.maxRight) ? itemC : ruleG.maxRight;

        // calculate the confidence of the rule
        double confidence = ((double) ruleSupport) / ruleG.tids1.cardinality();

        // create the rule
        RuleG candidate =
            new RuleG(
                ruleG.getItemset1(),
                newRightItemset,
                ruleSupport,
                ruleG.tids1,
                tidsRule,
                ruleG.maxLeft,
                maxRight);

        // if the confidence is enough
        if (confidence >= minConfidence) {
          // save the rule in current top-k rules
          save(candidate, ruleSupport);
        }
        // register the rule as a candidate for future expansion
        registerAsCandidate(false, candidate);
      }
    }

    // for each item c found in the previous step, we create a rule
    // I  U {c} ==> J if the support is enough
    for (Entry<Integer, BitSet> entry : mapCountLeft.entrySet()) {
      BitSet tidsRule = entry.getValue();
      int ruleSupport = tidsRule.cardinality();

      // if the support is enough
      if (ruleSupport >= minsuppRelative) {
        Integer itemC = entry.getKey();

        // The tidset of the left itemset is calculated
        BitSet tidsLeft = (BitSet) ruleG.tids1.clone();
        tidsLeft.and(tableItemTids[itemC]);

        // create new left part of rule
        Integer[] newLeftItemset = new Integer[ruleG.getItemset1().length + 1];
        System.arraycopy(ruleG.getItemset1(), 0, newLeftItemset, 0, ruleG.getItemset1().length);
        newLeftItemset[ruleG.getItemset1().length] = itemC;

        // recompute maxLeft
        int maxLeft = itemC >= ruleG.maxLeft ? itemC : ruleG.maxLeft;

        // calculate the confidence of the rule
        double confidence = ((double) ruleSupport) / tidsLeft.cardinality();

        // create the rule
        RuleG candidate =
            new RuleG(
                newLeftItemset,
                ruleG.getItemset2(),
                ruleSupport,
                tidsLeft,
                tidsRule,
                maxLeft,
                ruleG.maxRight);

        // if the confidence is high enough
        if (confidence >= minConfidence) {
          // save the rule to the top-k rules
          save(candidate, ruleSupport);
        }
        // register the rule as a candidate for further expansions
        registerAsCandidate(true, candidate);
      }
    }
  }