简体   繁体   English

组合算法并行化

[英]Combinatorics algorithm parallelization

I'm writing the program which is calculates C(n, k) combinations and have big difference between n and k (eg n=39, k=13 -> 8122425444 combinations). 我正在编写计算C(n,k)组合并且在n和k之间有很大差异的程序(例如n = 39,k = 13-> 8122425444组合)。 Also, I need to make some calculations with every combination in realtime. 另外,我需要实时对每种组合进行一些计算。 The question is how can I divide my algorithm to several threads to make it faster? 问题是如何将算法划分为多个线程以使其更快?

public void getCombinations(List<Item> items) {
    int n = items.size();
    int k = 13;
    int[] res = new int[k];
    for (int i = 1; i <= k; i++) {
        res[i - 1] = i;
    }
    int p = k;
    while (p >= 1) {
        //here I make a Set from items in List by ids in res[]
        Set<Item> cards = convert(res, items);
        //some calculations
        if (res[k - 1] == n) {
            p--;
        } else {
            p = k;
        }
        if (p >= 1) {
            for (int i = k; i >= p; i--) {
                res[i - 1] = res[p - 1] + i - p + 1;
            }
        }
    }
}

private Set<Item> convert(int[] res, List<Item> items) {
    Set<Item> set = new TreeSet<Item>();
    for (int i : res) {
        set.add(items.get(i - 1));
    }
    return set;
}

If you're using JDK 7 then you could use fork/join to divide and conquer this algorithm. 如果您使用的是JDK 7,则可以使用fork / join划分并征服此算法。

If you want to keep things simple then I would just get a thread to compute a subset of the input and use a CountDownLatch until all threads have completed. 如果您想保持简单,那么我只需要一个线程来计算输入的子集,并使用CountDownLatch直到所有线程都完成。 The number of threads depends on your CPU. 线程数取决于您的CPU。

You could also use Hadoop's map/reduce if you think the input will grow so you can compute on several computers. 如果您认为输入会增加,那么您也可以使用Hadoop的map / reduce,以便可以在多台计算机上进行计算。 You will need to normalise it as a map/reduce operation - but look at examples. 您将需要将其规范化为映射/归约操作-但请查看示例。

I have been working on some code that works with combinatoric sets of this size. 我一直在研究一些可用于这种大小的组合集的代码。 Here are a few suggestions for getting output in a reasonable amount of time. 以下是在合理的时间内获得输出的一些建议。

  • Instead of building a list of combinations and then processing them, write your program to take a rank for a combination. 无需构建组合列表然后进行处理,而是编写程序以对组合进行排名。 You can safely assign signed 64 bit long values to each combination for all k values up to n = 66. This will let you easily break up the number system and assign it to different threads/hardware. 您可以为n个最大n = 66的所有k个值安全地为每个组合分配带符号的64位长值。这将使您轻松拆分数字系统并将其分配给不同的线程/硬件。
  • If your computation is simple, you should look at using OpenCL or CUDA to do the work. 如果您的计算很简单,则应考虑使用OpenCL或CUDA进行工作。 There are a couple of options for doing this. 有两种方法可以执行此操作。 Rootbeer and Aparapi are options for staying in Java and letting a library take care of the GPU details. RootbeerAparapi是留在Java中并使库处理GPU详细信息的选项。 JavaCL is a nice binding to OpenCL, if you do not mind writing kernels directly in C99. 如果您不介意直接在C99中编写内核,则JavaCL是与OpenCL的很好的绑定。 AWS has GPU instance for doing this type of work. AWS具有用于执行此类工作的GPU实例。
  • If you are going to collect a result for each combination, you are really going to need to consider storage space. 如果要为每种组合收集结果,则确实需要考虑存储空间。 For your example of C(39,13), you would need a little under 61 Gigs just to store a long for each combination. 对于C(39,13)的示例,您需要在61 Gigs以下一点以便为每个组合存储一个long。 You need a good strategy for dealing with datasets of this size. 您需要一个好的策略来处理这种大小的数据集。
    • If you are trying to roll up this data into a simple result for the entire set of combinations, then follow @algolicious' suggestion and look at map/reduce to solve this problem. 如果您尝试将这些数据汇总为整个组合的简单结果,请遵循@algolicious的建议并查看map / reduce以解决此问题。
    • If you really need answers for each combination, but a little error is OK, you may want to look at using AI algorithms or a linear solver to compress the data. 如果您确实需要每种组合的答案,但是有一点错误是可以的,那么您可能需要考虑使用AI算法或线性求解器来压缩数据。 Be aware that these techniques will only work if there is something to learn in the resulting data. 请注意,这些技术仅在结果数据中有一些要学习的地方才有效。
    • If some error will not work, but you need every answer, you may want to just consider recomputing it each time you need it, based on the element's rank. 如果某些错误无法解决,但是您需要每个答案,则可能需要根据元素的等级考虑在每次需要时重新计算它。

The simplest way to split combinations is to have combinations of combinations. 拆分组合的最简单方法是拥有组合的组合。 ;) ;)

For each possible "first" value you can create a new task in a thread pool. 对于每个可能的“第一个”值,您都可以在线程池中创建一个新任务。 Or you can create each possible pair of "first" and "second" in as a new task. 或者,您可以在新任务中创建每个“第一”和“第二”对。 or three etc. You only need to create as many tasks as you have cpus, so you don't need to go over board. 或三个等。您只需要创建cpus,就可以创建尽可能多的任务,因此您无需费力。

eg say you want to create all possible selections of 13 from 39 items. 例如,说您想从39个项目中创建13个所有可能的选择。

for(Item item: items) {
   List<Item> items2 = new ArrayList<Item>(items);
   items2.remove(item);
   // create a task which considers all selections of 12 from 38 (plus item)
   createCombinationsOf(item, item2, 12);
}

This creates roughly equal work for 39 cpus which may be more than enough. 这为39 cpus创建了大致相等的功,这可能绰绰有余。 If you want more create pairs (39*38/2) of those. 如果您要创建更多(39 * 38/2)对。

Your question is quite vague. 您的问题很模糊。

What problem are you having right now? 您现在有什么问题? Implementing the divide and conquer part of the algorithm (threading, joining, etc), or figuring out how to divide a problem into it's sub-parts. 实现算法的分而治之部分(线程,连接等),或者弄清楚如何将问题分为子部分。

The later should be your first step. 稍后应该是您的第一步。 Do you know how to break your original problem into several smaller problems (that can then be dispatched to Executor threads or a similar mechanism to be processed), and how to join the results? 您知道如何将最初的问题分解为几个较小的问题(然后可以将其分发到Executor线程或类似的机制进行处理),以及如何将结果结合在一起?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM