class FunAlgorithm {

    protected LinkedList<FunQuadruple> generateCandidates(List<FunQuadruple> lk) {

        // what about keys (last statement in set expression from paper)

        LinkedList<FunQuadruple> lkPlus1 = new LinkedList<>();
        if (lk.isEmpty()) {
            return lkPlus1;
        }
        Set<ColumnCombinationBitset> subsets = new HashSet<>();
        int k = lk.get(0).candidate.size();
        ColumnCombinationBitset union = new ColumnCombinationBitset();
        for (FunQuadruple subsetQuadruple : lk) {
            // TODO optimise: all bits are set? --> break
            // If subsetQuadruple represents a unique do not add it to subsets and union (it should be pruned).
            if (subsetQuadruple.count == 0) {
                continue;
            }
            union = subsetQuadruple.candidate.union(union);
            subsets.add(subsetQuadruple.candidate);
        }

        Map<ColumnCombinationBitset, Integer> candidateGenerationCount = new HashMap<>();

        List<ColumnCombinationBitset> lkPlus1Candidates;
        FunQuadruple lkPlus1Member;
        for (ColumnCombinationBitset subset : subsets) {
            lkPlus1Candidates = union.getNSubsetColumnCombinationsSupersetOf(
                    subset, k + 1);
            // FIXME add key conditional here
            // Removed key conditional - should not be triggerable?
            for (ColumnCombinationBitset candidate : lkPlus1Candidates) {
                if (candidateGenerationCount.containsKey(candidate)) {
                    int count = candidateGenerationCount.get(candidate);
                    count++;
                    candidateGenerationCount.put(candidate, count);
                } else {
                    candidateGenerationCount.put(candidate, 1);
                }
            }
        }

        for (ColumnCombinationBitset candidate : candidateGenerationCount
                .keySet()) {
            if (candidateGenerationCount.get(candidate) == (k + 1)) {
                lkPlus1Member = new FunQuadruple(candidate, addPliGenerate(
                        candidate).getRawKeyError());
                lkPlus1.add(lkPlus1Member);
            }
        }
        return lkPlus1;
    }

    public  FunAlgorithm(String relationName, List<String> columnNames,
                        FunctionalDependencyResultReceiver fdReceiver);
    public  FunAlgorithm(String relationName, List<String> columnNames,
                        FunctionalDependencyResultReceiver fdReceiver,
                        UniqueColumnCombinationResultReceiver uccReceiver);

}