mineForItem<T> function

Map<List<int>, int> mineForItem<T>(
  1. FPTree tree,
  2. int item,
  3. List<int> prefix,
  4. Map<int, int> frequency,
  5. int absoluteMinSupport,
  6. ItemMapper<T> mapper,
  7. Logger logger,
)

Recursively mines frequent itemsets for a specific item and its conditional tree.

This function explores the FP-Tree starting from a given item, builds its conditional FP-Tree, and recursively mines it to find all frequent itemsets that are extensions of the current prefix and the item.

Implementation

Map<List<int>, int> mineForItem<T>(
  FPTree tree,
  int item,
  List<int> prefix,
  Map<int, int> frequency,
  int absoluteMinSupport,
  ItemMapper<T> mapper,
  Logger logger,
) {
  final frequentItemsets = <List<int>, int>{};
  final newPrefix = List<int>.from(prefix)..add(item);
  final support = frequency[item]!;
  frequentItemsets[newPrefix] = support;

  logger.debug(
    '  Processing item: ${mapper.getItem(item)} (support: $support)',
  );

  // Find conditional pattern bases
  final conditionalPatternBases = tree.findPaths(item);

  // Calculate conditional frequency
  final conditionalFrequency = <int, int>{};
  for (final entry in conditionalPatternBases.entries) {
    for (final itemInPath in entry.key) {
      conditionalFrequency[itemInPath] =
          (conditionalFrequency[itemInPath] ?? 0) + entry.value;
    }
  }

  final conditionalFrequentItems = filterFrequentItems(
    conditionalFrequency,
    absoluteMinSupport,
  );

  if (conditionalFrequentItems.isNotEmpty) {
    // Reconstruct transactions for conditional tree
    final weightedTransactions = buildConditionalTransactions(
      conditionalPatternBases,
      conditionalFrequentItems,
    );

    if (weightedTransactions.isNotEmpty) {
      final conditionalTree = FPTree(conditionalFrequentItems)
        ..addWeightedTransactions(weightedTransactions);

      // Single-path optimization
      if (conditionalTree.isSinglePath()) {
        logger.debug(
          '    Single-path optimization applied for prefix: ${newPrefix.map(mapper.getItem).join(', ')}',
        );
        final pathNodes = conditionalTree.getSinglePathNodes();
        final allSubsets = generateSubsets(pathNodes);

        for (final subset in allSubsets) {
          final itemset = subset.map((node) => node.item!).toList();
          final support = subset
              .map((node) => node.count)
              .reduce((a, b) => a < b ? a : b);
          frequentItemsets[List<int>.from(newPrefix)..addAll(itemset)] =
              support;
        }
      } else {
        // Recursively mine the conditional tree
        final minedPatterns = mineLogic(
          conditionalTree,
          newPrefix,
          conditionalFrequentItems,
          absoluteMinSupport,
          mapper,
          logger,
        );
        frequentItemsets.addAll(minedPatterns);
      }
    }
  }

  return frequentItemsets;
}