java—n个有序元素的组合

wnvonmuf  于 2021-06-04  发布在  Hadoop
关注(0)|答案(3)|浏览(278)

我有一组k元素,需要创建一个n个有序元素的组合。
例如,如果k=1,我有{x1,emptyset}和n=2,那么我有一个有序对,我需要这样做:
例1:

({},{})  
 ({X1},{}), ({},{X1})  
 ({X1},{X1})

请注意,我需要按以下顺序获取元素:首先是节点为0的元素作为两对的和,其次是节点为1的元素,ecc
我的想法是把初始集合的各个部分组成一个集合,每次添加一个元素,但我已经失去理智了。有什么建议吗?我需要用java来做这个。
编辑1:换句话说,我需要创建一个哈斯图:http://en.wikipedia.org/wiki/hasse_diagram
其中,每个节点是零件集的一个元素,偏序函数是所有子集上的包含,如下所示:
例2:
ni=(s1i,s2i)c nj=(s1j,s2j)仅当s1i c s1j和s21 c s2j
编辑2:@罗纳德:
如果一个集合s={1,2}和n=2的k=2,我需要这个输出:

level0: ({}, {})  
 level1: ({1}, {}); ({2}, {}); ({}, {1}); ({}, {2})  
 level2: ({1,2}, {}); ({1}, {1}); ({1}, {2}); ({2}, {1}); ({2}, {2}); ({}, {1,2});   
 [..]

级别之间的顺序很重要,例如:
如果在一级我有

({1}, {}); ({2}, {}); ({}, {1}); ({}, {2})

或者

({}, {2}); ({}, {1}); ({2}, {}); ({1}, {});

是一样的。但重要的是,在2级我有2级的所有超集,一个超集在例子2中解释
编辑3:
如果我的集合是s={x,y,z},并且每个节点只有一个集合,那么结果(从底部开始)是这样的:http://upload.wikimedia.org/wikipedia/commons/e/ea/hasse_diagram_of_powerset_of_3.svg
如果我有s={1,2}并且每个节点有两个集合,结果是这样的(感谢ronald的图表):
http://www.independit.de/downloads/hasse.pdf
编辑4:
因为这是一个超指数问题,我的想法是:我一次计算一个级别(在有序模式下!)我用一些规则修剪一个节点和他的所有超集。另一个停止规则可能是在某个水平停止。对于这条规则,必须以有序的方式直接计算组合,而不是计算全部,然后重新排序。
编辑5:
marco13的代码运行良好,我对其进行了一些修改:
使用函数powerset,因为它只对集合s的k元素的makeall组合有帮助(我只需要获取powerset的第一个tot元素就可以了)。
现在算法可以做所有的,但我需要加快它。有什么方法可以并行计算吗?这样一种使用map reduce(apachehadoop实现)范式的方法?

package utilis;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class HasseDiagramTest4
{
    public static void main(String[] args)
    {
        int numberOfSetsPerNode = 3;

        List<Integer> set = Arrays.asList(1, 2, 3, 4, 5,6);
        List<Set<Integer>> powerSet = computePowerSet(set);
        powerSet = KPowerSet(powerSet, 3);

        List<List<Set<Integer>>> prunedNodes = 
            new ArrayList<List<Set<Integer>>>();
        List<Set<Integer>> prunedNode = new ArrayList<Set<Integer>>();

        HashSet<Integer> s = new HashSet<Integer>();
        HashSet<Integer> s_vuoto = new HashSet<Integer>();
        s.add(1);
        s.add(2);
        prunedNode.add(s);
        prunedNode.add(s_vuoto);
        prunedNode.add(s);

       prunedNodes.add(prunedNode);

        compute(ordina(powerSet), numberOfSetsPerNode, prunedNodes);
    }

    private static <T> HashMap<Integer, List<Set<T>>> ordina(List<Set<T>> powerSet) {

        HashMap<Integer, List<Set<T>>> hs = new HashMap<Integer, List<Set<T>>>();

        for(Set<T> l: powerSet)
        {
            List<Set<T>> lput = new  ArrayList<Set<T>>();
            if(hs.containsKey(l.size()))
            {
                lput = hs.get(l.size());
                lput.add(l);
                hs.put(l.size(), lput);
            }
            else
            {
                lput.add(l);
                hs.put(l.size(), lput); 
            }

        }

        return hs;
    }

    private static <T> List<Set<T>> KPowerSet(List<Set<T>> powerSet, int k)
    {
        List<Set<T>> result = new ArrayList<Set<T>>();

        for(Set<T>s:powerSet)
        {
            if(s.size() <= k)
            {
                result.add(s);
            }
        }
        return result;
    }

    private static <T> List<Set<T>> computePowerSet(List<T> set)
    {
        List<Set<T>> result = new ArrayList<Set<T>>();
        int numElements = 1 << set.size();
        for (int j=0; j<numElements; j++)
        {
            Set<T> element = new HashSet<T>();
            for (int i = 0; i < set.size(); i++)
            {
                long b = 1 << i;
                if ((j & b) != 0)
                {
                    element.add(set.get(i));
                }
            }
            result.add(element);
        }
        return result;
    }

    private static List<Integer> createList(int numberOfElements)
    {
        List<Integer> list = new ArrayList<Integer>();
        for (int i=0; i<numberOfElements; i++)
        {
            list.add(i+1);
        }
        return list;
    }

    private static <T> void compute(
            HashMap<Integer, List<Set<T>>> powerSet, int numberOfSetsPerNode,
        List<List<Set<T>>> prunedNodes)
    {
        Set<List<Set<T>>> level0 = createLevel0(numberOfSetsPerNode);
        System.out.println("Level 0:");
        print(level0);

        Set<List<Set<T>>> currentLevel = level0;
        int level = 0;
        while (true)
        {
            Set<List<Set<T>>> nextLevel = 
                createNextLevel(currentLevel, powerSet, prunedNodes);
            if (nextLevel.size() == 0)
            {
                break;
            }

            System.out.println("Next level: "+nextLevel.size()+" nodes");
            print(nextLevel);

            currentLevel = nextLevel;
            level++;
        }
    }

    private static <T> Set<List<Set<T>>> createLevel0(int numberOfSetsPerNode)
    {
        Set<List<Set<T>>> level0 = 
            new LinkedHashSet<List<Set<T>>>();
        List<Set<T>> level0element = new ArrayList<Set<T>>();
        for (int i=0; i<numberOfSetsPerNode; i++)
        {
            level0element.add(new LinkedHashSet<T>());
        }
        level0.add(level0element);
        return level0;
    }

    private static <T> List<Set<T>> getNext(Set<T> current, HashMap<Integer, List<Set<T>>> powerSet)
    {
        ArrayList<Set<T>> ritorno = new ArrayList<Set<T>>(); 
        int level = current.size();
        List<Set<T>> listnext = powerSet.get(level+1);

        if(listnext != null)
        {
            for(Set<T> next: listnext)
            {
                if(next.containsAll(current))
                {
                    ritorno.add(next);
                }
            }
        }

        return ritorno;
    }

    private static <T> Set<List<Set<T>>> createNextLevel(
        Set<List<Set<T>>> currentLevel, HashMap<Integer, List<Set<T>>> powerSet,
        List<List<Set<T>>> prunedNodes)
    {
        Set<List<Set<T>>> nextLevel = new LinkedHashSet<List<Set<T>>>();

        //Per ogni nodo del livello corrente
        for (List<Set<T>> currentLevelElement : currentLevel)
        {
            //Per ogni insieme del nodo preso in considerazione
            for (int i=0; i<currentLevelElement.size(); i++)
            {
                List<Set<T>> listOfnext = getNext (currentLevelElement.get(i), powerSet);

                for (Set<T> element : listOfnext)
                {
                    List<Set<T>> nextLevelElement = copy(currentLevelElement);
                    Set<T> next = element;
                    nextLevelElement.remove(i);
                    nextLevelElement.add(i, next);

                    boolean pruned = false;
                    for (List<Set<T>> prunedNode : prunedNodes)
                    {
                        if (isSuccessor(prunedNode, nextLevelElement))
                        {
                            pruned = true;
                        }
                    }
                    if (!pruned)
                    {
                        nextLevel.add(nextLevelElement);
                    }
                    else
                    {
                        System.out.println("Pruned "+nextLevelElement+ " due to "+prunedNodes);
                    }
                }
            }
        }
        return nextLevel;
    }

    private static <T> boolean isSuccessor(
        List<Set<T>> list, List<Set<T>> successor)
    {
        for (int i=0; i<list.size(); i++)
        {
            Set<T> set = list.get(i);
            Set<T> successorSet = successor.get(i);
            //System.out.println("Successor:" + successorSet + "pruned:" + set);
            if (!successorSet.containsAll(set))
            {
                return false;
            }
        }
        return true;
    }

    private static <T> List<Set<T>> copy(List<Set<T>> list)
    {
        List<Set<T>> result = new ArrayList<Set<T>>();
        for (Set<T> element : list)
        {
            result.add(new LinkedHashSet<T>(element));
        }
        return result;
    }

    private static <T> void print(
        Iterable<? extends Collection<? extends Collection<T>>> sequence)
    {
        for (Collection<? extends Collection<T>> collections : sequence)
        {
            System.out.println("    "+collections);
        }
    }

}
3bygqnnd

3bygqnnd1#

正如在评论中提到的,我相当肯定,对实际应该做什么的形式化不是不清楚就是明显错误。比较“节点”的标准与示例不匹配。但是,一旦排序标准(以 Comparator )这应该很容易实现。
在这里,比较两个“节点”的标准是节点中所有集合的大小之和,这与给出的示例相匹配(尽管它直观上没有意义,因为它不对应于任何真实的子集关系……)

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class HasseDiagramTest
{
    public static void main(String[] args)
    {
        List<Integer> set = Arrays.asList(1, 2);
        List<List<Integer>> powerSet = computePowerSet(set);
        List<List<List<Integer>>> combinations = 
            computeCombinations(powerSet, 2);
        Comparator<List<List<Integer>>> comparator = createComparator();
        Collections.sort(combinations, comparator);
        List<List<List<List<Integer>>>> levels = createLevels(combinations);
        for (List<List<List<Integer>>> level : levels)
        {
            System.out.println(level);
        }
    }

    private static <T> List<List<List<List<T>>>> createLevels(
        List<List<List<T>>> sortedCombinations)
    {
        List<List<List<List<T>>>> levels = new ArrayList<List<List<List<T>>>>();
        int previousTotalSize = -1;
        List<List<List<T>>> currentLevel = null;
        for (int i=0; i<sortedCombinations.size(); i++)
        {
            List<List<T>> combination = sortedCombinations.get(i);
            int totalSize = totalSize(combination);
            if (previousTotalSize != totalSize)
            {
                previousTotalSize = totalSize;
                currentLevel = new ArrayList<List<List<T>>>();
                levels.add(currentLevel);
            }
            currentLevel.add(combination);
        }
        return levels;
    }

    private static <T> Comparator<List<List<T>>> createComparator()
    {
        return new Comparator<List<List<T>>>()
        {
            @Override
            public int compare(List<List<T>> list0, List<List<T>> list1)
            {
                return Integer.compare(totalSize(list0), totalSize(list1));
            }
        };
    }

    private static <T> int totalSize(List<List<T>> lists)
    {
        int totalSize = 0;
        for (List<T> list : lists)
        {
            totalSize += list.size();
        }
        return totalSize;
    }

    private static <T> List<List<T>> computePowerSet(List<T> set)
    {
        List<List<T>> result = new ArrayList<List<T>>();
        int numElements = 1 << set.size();
        for (int j=0; j<numElements; j++)
        {
            List<T> element = new ArrayList<T>();
            for (int i = 0; i < set.size(); i++)
            {
                long b = 1 << i;
                if ((j & b) != 0)
                {
                    element.add(set.get(i));
                }
            }
            result.add(element);
        }
        return result;
    }

    private static <T> List<List<T>> computeCombinations(List<T> list, int sampleSize)
    {
         int numElements = (int) Math.pow(list.size(), sampleSize);
         int chosen[] = new int[sampleSize];
         List<List<T>> result = new ArrayList<List<T>>();
         for (int current = 0; current < numElements; current++)
         {
             List<T> element = new ArrayList<T>(sampleSize);
             for (int i = 0; i < sampleSize; i++)
             {
                 element.add(list.get(chosen[i]));
             }
             result.add(element);
             increase(chosen, list.size());
         }
         return result;
    }

    private static void increase(int chosen[], int inputSize)
    {
        int index = chosen.length - 1;
        while (index >= 0)
        {
            if (chosen[index] < inputSize - 1)
            {
                chosen[index]++;
                return;
            }
            chosen[index] = 0;
            index--;
        }
    }
}
qeeaahzv

qeeaahzv2#

如果你有一个基本的集合 S = {1, 2} ,那么 K = 2 s的子集集是 {{}, {1}, {2}, {1,2}} . 假设n仍然是2。那么你的输出就会是

({}, {})
({1}, {}); ({2}, {}); ({}, {1}); ({}, {2})
({1,2}, {});          ({}, {1,2})
({1}, {1}); ({1}, {2}); ({2}, {1}); ({2}, {2})
({1}, {1,2}); ({1,2}, {1}); ({2}, {1,2}); ({1,2}, {2})
({1,2}, {1,2})

对的?对输出进行排序有点困难,因为结果不是完全有序的。但归根结底还是要数。不是像我最初想的那样,(k+1)元而是更多的(2^k)元。
为了确定一个集合是否是另一个集合的子集,可以使用素数。给原始集合的每个元素分配一个素数。在我的例子中,是2和3。子集集可以通过生成素数的所有乘积来建立。在我的例子中 {1 /* empty set */, 2, 3, 6} . 如果您有两套产品,以您的产品为代表,则很容易测试是否包含:

if (a % b == 0) then b is a subset of a

这只是一堆想法,但它们可能会帮助你找到解决办法。当然,素数技巧只适用于原始集合中相对较少的元素,但只要k和n增长,无论如何都会遇到问题(输出中的元素数将是 (2^K)^N = 2^(NK) . 如果 K == N == 5 ,你会有 2^(5 * 5) = 2^25 ,约3200万个产出要素。在这里,主要思想仍然有效)。
编辑:我写了一个小java程序来展示我的想法。
保存到hasse.java
编译它: javac Hasse.java 运行它: java Hasse > hasse.dot 运行点: dot -Tpdf -ohasse.pdf hasse.dot 查看: acroread hasse.pdf 源代码:

import java.lang.*;
import java.util.*;

public class Hasse {

        private static int K[] = { 1, 2, 3 };
        private static int N   = 2;
        private static int prime[] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97 };
        //
        // PK[0][] is the array of "subsets"
        // PK[1][] is the array of number of elements of K participating in the subset
        //
        private static int PK[][];

        // some constants; the initialization is clear enough
        private static final long twoNK = pow(2, N * K.length);
        private static final int twoK = (int) pow(2, K.length);
        private static final int  NK = N * K.length;
        private static final long NKf = fac(NK);

        //
        // this power function isn't suitable for large powers
        // but in the range we are working, it's OK
        //
        public static long pow(int b, int p)
        {
                long result = 1;
                for (int i = 0; i < p; ++i)
                        result *= b;

                return result;
        }

        // fac calculates n! (needed for the a over b calculation)
        public static long fac(int n)
        {
                long result = 1;
                for (int i = n; i > 0; --i) result *= i;

                return result;
        }

        //
        // constructPK builds the set of subsets of K
        // a subset is represented by a product of primes
        // each element k_i of K has an associated prime p_i
        // since the prime factorization of a number is unique,
        // the product can be translated into a subset and vice versa
        //
        public static void constructPK()
        {
                int i, cnt;
                int numElms = twoK;
                PK = new int[2][numElms];

                for (i = 0; i < numElms; ++i) {
                        int j = i;
                        cnt = 0;
                        PK[0][i] = 1;
                        PK[1][i] = 0;
                        while (j > 0) {
                                if (j % 2 == 1) {
                                        PK[0][i] *= prime[cnt];
                                        PK[1][i]++;
                                }
                                cnt++;
                                j /= 2;
                        }
                }
        }

        // we have a k-ary number (that is: binary if k == 2, octal if k == 8
        // and so on
        // the addOne() function calculates the next number based on the input
        public static void addOne(int kAry[])
        {
                int i = 0;

                kAry[i] += 1;
                while (kAry[i] >= twoK) {
                        kAry[i] = 0;
                        ++i;
                        kAry[i] += 1;
                }
        }

        // the addN() function is similar to the addOne() function
        // with the difference that it add n to the input, not just 1
        public static void addN(int kAry[], int n)
        {
                int i = 0;

                kAry[i] += n;
                for (i = 0; i < N - 1; ++i) {
                        while (kAry[i] >= twoK) {
                                kAry[i] -= twoK;
                                kAry[i+1] += 1;
                        }
                }
        }

        // from the k-ary number, which represents a node in the graph,
        // the "level" is calculated.
        public static int getLevel(int kAry[])
        {
                int level = 0;

                for (int i = 0; i < N; ++i) {
                        level += PK[1][kAry[i]];
                }
                return level;
        }

        // output function for a node
        public static String renderNode(int kAry[])
        {
                StringBuffer sb = new StringBuffer();
                String sep = "";

                sb.append("(");
                for (int i = 0; i < N; ++i) {
                        String setSep = "";
                        int p = PK[0][kAry[i]];
                        sb.append(sep);
                        sb.append("{");
                        for (int j = 0; j < K.length; ++j) {
                                if (p % prime[j] == 0) {
                                        sb.append(setSep + K[j]);
                                        setSep = ", ";
                                }
                        }
                        sb.append("}");
                        sep = ", ";
                }
                sb.append(")");

                return sb.toString();
        }

        // This function calculates the numerical representation
        // of a node, addressed by its level and position within the level,
        // in the k-ary number system
        // if there's a more elegant way of finding the node, it would 
        // largely speed up the calculation, since this function is needed
        // for calculating the edges
        public static int[] getKAry(int level, int node)
        {
                int kAry[] = new int[N];
                int nodesSoFar = 0;

                for (int i = 0; i < N; ++i) kAry[i] = 0;

                for (int cnt = 0; cnt < twoNK; ++cnt) {
                        if (getLevel(kAry) == level) {
                                if (nodesSoFar == node) {
                                        return kAry;
                                } else
                                        nodesSoFar++;
                        }
                        if (cnt + 1 < twoNK)
                                addOne(kAry);
                }
                return null;
        }

        // this function converts the decimal nodeNumber to
        // its k-ary representation
        public static int[] getKAry(int nodeNumber)
        {
                int kAry[] = new int[N];

                for (int i = 0; i < N; ++i) kAry[i] = 0;

                addN(kAry, nodeNumber);

                return kAry;
        }

        public static String getLabel(int level, int node)
        {
                int kAry[] = getKAry(level, node);

                return (kAry == null ? "Oops!" : renderNode(kAry));
        }

        public static void printPK()
        {
                System.out.println("# Number of elements: " + PK[0].length);
                for (int i = 0; i < PK[0].length; ++i) {
                        System.out.println("# PK[0][" + i + "] = " + PK[0][i] + ",\tPK[1][" + i + "] = " + PK[1][i]);
                }
        }

        public static void printPreamble()
        {
                System.out.println("digraph G {");
                System.out.println("ranksep = 3");
                System.out.println();
        }

        public static void printEnd()
        {
                System.out.println("}");
        }

        public static void printNodes()
        {
                int numNodes;

                for (int i = 0; i <= NK; ++i) {
                        int level = i + 1;
                        numNodes = (int) (NKf / (fac(i) * fac(NK - i)));
                        for (int j = 0; j < numNodes; ++j) {
                                System.out.println("level_" + level + "_" + (j+1) + " [shape=box,label=\"" + getLabel(i, j) + "\"];");
                        }
                        System.out.println();
                }
                System.out.println();
        }

        // having two vectors of "sets", this function determines
        // if each set in the ss (small set) vector is a subset of
        // the corresponding set in the ls (large set) vector
        public static boolean isSubset(int ss[], int ls[])
        {
                for (int i = 0; i < N; ++i)
                        if (PK[0][ls[i]] % PK[0][ss[i]] != 0) return false;
                return true;
        }

        // this function finds and prints the edges
        // it is called about twoNK times (once for each node)
        // therefore performance optimizations have to be done here
        public static void printEdges(int level, int node, int nodeNumber)
        {
                int kAry[] = getKAry(node);
                int nlAry[];
                int numNodes = (int) (NKf / (fac(level + 1) * fac(NK - level - 1)));
                String myNode = "level_" + (level + 1) + "_" + (node + 1);

                for (int i = 0; i < numNodes; ++i) {
                        nlAry = getKAry(level + 1, i);
                        if (nlAry == null) System.exit(1);
                        if (isSubset(kAry, nlAry)) {
                                System.out.println(myNode + " -> level_" + (level + 2) + "_" + (i + 1));
                        }
                }
        }

        // this function renders the dot file
        // first some initial text (preamble),
        // then the nodes and the edges
        // and finally the closing brace
        public static void renderDot()
        {
                int numNodes;
                int nodeNumber = 0;

                printPreamble();
                printNodes();
                for (int level = 0; level < NK; ++level) {
                        numNodes = (int) (NKf / (fac(level) * fac(NK - level)));
                        for (int node = 0; node < numNodes; ++node) {
                                // find the edges to the nodes on the next level
                                printEdges(level, node, nodeNumber);
                                ++nodeNumber;
                        }
                        System.out.println();
                }
                printEnd();
        }

        public static void main (String argv[])
        {
                constructPK();
                renderDot();
        }
}
wd2eg0qa

wd2eg0qa3#

经过4次编辑和大量讨论,这个应用程序的目标慢慢变得更加清晰。事实上,我们必须考虑一个适当的形式化,但它最终似乎并不那么困难。
与我的第一个答案相比(https://stackoverflow.com/a/22092523 )这个新的迭代计算上一个层次的下一个层次(以及这个层次的核心, createNextLevel ,只有10行代码)。
compute 方法,可以将“edit4”中要求的修剪集成到 while 循环。
编辑:评论中还有更多的请求。整合了它们。但这正变得荒谬。我想休息一下ü默恩。

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

public class HasseDiagramTest2
{
    public static void main(String[] args)
    {
        int numberOfElements = 2;
        int numberOfSetsPerNode = 2;

        List<Integer> list = createList(numberOfElements);

        List<List<Set<Integer>>> prunedNodes = 
            new ArrayList<List<Set<Integer>>>();
        List<Set<Integer>> prunedNode = new ArrayList<Set<Integer>>();
        prunedNode.add(Collections.singleton(1));
        prunedNode.add(Collections.singleton(1));
        prunedNodes.add(prunedNode);

        compute(list, numberOfSetsPerNode, prunedNodes);
    }

    private static List<Integer> createList(int numberOfElements)
    {
        List<Integer> list = new ArrayList<Integer>();
        for (int i=0; i<numberOfElements; i++)
        {
            list.add(i+1);
        }
        return list;
    }

    private static <T> void compute(
        List<T> elements, int numberOfSetsPerNode,
        List<List<Set<T>>> prunedNodes)
    {
        Set<List<Set<T>>> level0 = createLevel0(numberOfSetsPerNode);
        System.out.println("Level 0:");
        print(level0);

        Set<List<Set<T>>> currentLevel = level0;
        int level = 0;
        while (true)
        {
            Set<List<Set<T>>> nextLevel = 
                createNextLevel(currentLevel, elements, prunedNodes);
            if (nextLevel.size() == 0)
            {
                break;
            }

            System.out.println("Next level: "+nextLevel.size()+" nodes");
            print(nextLevel);

            currentLevel = nextLevel;
            level++;
        }
    }

    private static <T> Set<List<Set<T>>> createLevel0(int numberOfSetsPerNode)
    {
        Set<List<Set<T>>> level0 = 
            new LinkedHashSet<List<Set<T>>>();
        List<Set<T>> level0element = new ArrayList<Set<T>>();
        for (int i=0; i<numberOfSetsPerNode; i++)
        {
            level0element.add(new LinkedHashSet<T>());
        }
        level0.add(level0element);
        return level0;
    }

    private static <T> Set<List<Set<T>>> createNextLevel(
        Set<List<Set<T>>> currentLevel, List<T> elements,
        List<List<Set<T>>> prunedNodes)
    {
        Set<List<Set<T>>> nextLevel = new LinkedHashSet<List<Set<T>>>();
        for (List<Set<T>> currentLevelElement : currentLevel)
        {
            for (int i=0; i<currentLevelElement.size(); i++)
            {
                for (T element : elements)
                {
                    List<Set<T>> nextLevelElement = copy(currentLevelElement);
                    Set<T> next = nextLevelElement.get(i);
                    boolean changed = next.add(element);
                    if (!changed)
                    {
                        continue;
                    }
                    boolean pruned = false;
                    for (List<Set<T>> prunedNode : prunedNodes)
                    {
                        if (isSuccessor(prunedNode, nextLevelElement))
                        {
                            pruned = true;
                        }
                    }
                    if (!pruned)
                    {
                        nextLevel.add(nextLevelElement);
                    }
                    else
                    {
//                        System.out.println(
//                            "Pruned "+nextLevelElement+
//                            " due to "+prunedNodes);
                    }
                }
            }
        }
        return nextLevel;
    }

    private static <T> boolean isSuccessor(
        List<Set<T>> list, List<Set<T>> successor)
    {
        for (int i=0; i<list.size(); i++)
        {
            Set<T> set = list.get(i);
            Set<T> successorSet = successor.get(i);
            if (!successorSet.containsAll(set))
            {
                return false;
            }
        }
        return true;
    }

    private static <T> List<Set<T>> copy(List<Set<T>> list)
    {
        List<Set<T>> result = new ArrayList<Set<T>>();
        for (Set<T> element : list)
        {
            result.add(new LinkedHashSet<T>(element));
        }
        return result;
    }

    private static <T> void print(
        Iterable<? extends Collection<? extends Collection<T>>> sequence)
    {
        for (Collection<? extends Collection<T>> collections : sequence)
        {
            System.out.println("    "+collections);
        }
    }

}

相关问题