我正在尝试使用OpenMP并行化我自己的旅行商问题的C ++实现。
我有一个计算道路cost()
和矢量[0,1,2,...,N]成本的函数,其中N是道路的节点数。
在main()
,我正在努力找到最好的道路:
do
{
cost();
} while (std::next_permutation(permutation_base, permutation_base + operations_number));
我试图使用#pragma omp parallel
来并行化该代码,但这只会让它更耗时。
有没有办法并行化该代码?
答案 0 :(得分:4)
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:weightSum="2">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="#192832">
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:background="#193222">
</LinearLayout>
</LinearLayout>
<ImageView
android:id="@+id/yourImage"
android:src="@drawable/yourImageSrc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"/>
</RelativeLayout>
不会在不同的线程上自动划分计算。如果要分割计算,则需要另外使用#pragma omp parallel
,否则孔计算多次完成,每个线程一次。例如,以下代码打印&#34; Hello World!&#34;我的笔记本电脑上有四次,因为它有4个核心。
#pragma omp for
如果你简单地写int main(int argc, char* argv[]){
#pragma omp parallel
cout << "Hello World!\n";
}
,你的代码就会发生同样的事情。您的代码会被执行多次,每个线程执行一次。因此,您的计划不会更快。如果你想将工作分成线程(每个线程做不同的事情),你必须使用#pragma omp parallel
之类的东西。
现在我们可以查看您的代码了。它不适合并行化。让我们看看为什么。您从数组#pragma omp parallel for
开始计算成本。然后用permutation_base
操纵permutation_base
。在允许操作数组之前,您实际上必须等待完成的成本计算,否则成本计算将是错误的。所以整个事情不会在单独的线程上工作。
一种可能的解决方案是保留数组next_permutation
的多个副本,并且每个可能的排列基础只运行所有排列的一部分。例如:
permutation_base
答案 1 :(得分:1)
绝对是最好的。
并行化这些排列问题的一个大问题是,为了很好地并行化,你需要“索引”成一个任意的排列。简而言之,您需要找到第k个排列。你可以利用一些很酷的数学属性,你会发现:
std::vector<int> kth_perm(long long k, std::vector<int> V) {
long long int index;
long long int next;
std::vector<int> new_v;
while(V.size()) {
index = k / fact(V.size() - 1);
new_v.push_back(V.at(index));
next = k % fact(V.size() - 1);
V.erase(V.begin() + index);
k = next;
}
return new_v;
}
那么你的逻辑可能看起来像这样:
long long int start = (numperms*threadnum)/ numthreads;
long long int end = threadnum == numthreads-1 ? numperms : (numperms*(threadnum+1))/numthreads;
perm = kth_perm(start, perm); // perm is your list of permutations
for (int j = start; j < end; ++j){
if (is_valid_tour(adj_list, perm, startingVertex, endingVertex)) {
isValidTour=true;
return perm;
}
std::next_permutation(perm.begin(),perm.end());
}
isValidTour = false;
return perm;
显然有很多代码,但是我发布的小代码可以捕获并行化的想法。你可以像这样想象“索引”:
|--------------------------------|
^ ^ ^
t1 t2 ... tn
找到第i个排列并让线程调用std::next_permutation
,直到找到下一个线程的起点。
请注意,您需要在#pragma omp parallel