我们需要把有依赖关系的数据都交给同一个CPU处理,这样其他数据都可以交给其他CPU并行处理,并行的加速比公式Amdahl定律:
1/( (1 - f) + (f / p) )
笔者个人认为,这个公式的主要精髓在于并行流受限于串行流,加速比其实主要取决于并行化最低的数据,也就是依赖性最严重的数据,这部分数据必须串行执行。
数据依赖有三种类型:
真依赖:写运算后面接一个读运算
反依赖:读运算后面接一个写运算
输出依赖:两个针对同一个位置的写运算
依赖性产生的条件:
1.必须有一个操作是写操作
2.存在不同的迭代访问了同一个内存位置
举例:
for(i = 0; i <= 10; i++){
for(j = 0; j <= 10; j++){
Z[i][j] = Z[j+10][i+11];
}
}
只考虑整数解的方程被称为丢番图方程。
我们考虑有两次访问,列出不等式和依赖条件:
0<=i1,j1,i2,j2<=10
i1 = j2 + 10
j1 = i2 + 11
gcd测试就是最大公约数测试,我们可以把方程写成gcd(1,1,10),然后确定是否有解,如果gcd无解,那么该方程也无解。
理由是:对于整数乘法,相等的两边必定存在公约数。
举例:
2i = 2j +1
这个丢番图方程显然是没有解的。
观察两个方程,可以确定都存在整数解,我们求解的结果是不等式,因此求解的技巧就是将等式带入不等式,
重新整理不等式可以得到:
10 <= i1 <= 10
11 <= i2 <= 10
那么数据依赖并不存在,因为该不等式无法满足。
在求解不等式时,我们也可以观察上下界,并将上下界替换为某些最小的常量,这被称之为无环测试。
任何数据,只要它能够体现出方向性,那么它就可以被转换为有向图。
我们可以使用循环残数测试不等式的有向图是否合理,具体规则就是:如果有环的值是负数,那么这些约束肯定不成立。
有向图边长的权重的实际意义就是:将不等式消去中间项,转化为上界和下界,如果上下界发生矛盾,那么该解就不成立。
具体做法如下:
v <= c替换成v <= v0 + c
c <= v替换成v0 <= v - c
举例:
1 <= v1,v2 <= 10
0 <= v3 <= 4
v2 <= v1
2v1 <= 2v3 - 7
我们可以先从最后一个入手,由于我们求解的对象是丢番图方程,也就是说,我们只用考虑整数解,最后一个方程化为:
v1 <= v3 - 7/2
也就是:
v1 <= v3 -4 <= v3 - 7/2
现在应用上面的做法:
v0 <= v1 - 1, v1 <= v0 + 10
v0 <= v2 - 1, v2 <= v0 + 10
v0 <= v3, v3 <= v0 + 4
v2 <= v1,
v1 <= v3 - 4
画出约束图:
我们观察到,在v0–>v1–>v3–>v0这条环中,权重是负数,也就是说这些约束条件无解。
可能使用图直接应用不够直观,让我们从不等式进行推导:
v1-->v0,对应图的-4 + +4 ,也就是0,对应不等式变换:
v1 + 4 <= v3 <= v0 + 4,
剩下的同理
我们发现,各边权重相加的过程,其实就是不等式消除中间变量导向两边关系的过程。
最终,如果环的权重小于0,那么说明两边出现了矛盾性,我们可以推断出:
v < v
这样的关系明显是不可能存在的,所以这些约束关系无解。
记忆模式就是查表记录,对图问题的求解是一个NPC问题,就是可以看见求解集合的范围,也可以进行穷举,但是很难找到一个多项式算法来描述它,不过也有人给出了各种条件下的NPC问题求解算法,所以有人开玩笑说:证明NPC问题本身就是一个NPC问题。
记忆模式,其实就是计算结果后,保存到表中,这样处理后,每次算法都可以查询这个表。
其实既然涉及到了记忆模式,那么可以考虑使用自动机了,我们可以保留某些结果的特征,作为NFA(有穷自动机)中的状态转换的部分,不然每一次都要遍历全部结果,这样的算法是得不偿失的。
在前面的文章中提到过这个算法,它是一个多面体约束常用的算法,我们也可以用它对不等式进行运算处理,这里就不过多赘述了。