在上一篇中,我主要介绍了对赛题的初步攻击——单机Pollard-Rho。接下来介绍分布式算法。
让多个机子,从点集合G中不同的起点进行出发,用QD法记录的桩点会被记录到一个公共表里,然后每个机子共享数据,也就是说每个机子可以知道一个桩点,是否曾经被自己或者其它机子产生出来过。
这里面有一些隐含的信息。首先,并不是有n台机子,产生答案的时间就会缩短到原来的1/n,事实上,随机产生的Rho图数量非常巨大,基本上而言每个起点会落在不同的Rho图中,然后产生答案的时间会是它们各自工作的最小值。这样的话分布式意义就不会很大。因此有不少人提出了更好的迭代函数,以及提出迭代一定步数后重新开始,增加起点落在相同图中的概率。
这方面的理论,我拿捏得并不是很清楚,因此只是保守地去实现基本化的分布式Rho法,至于改进,可以交给各位读者了。
接下来是需要一个类似分布式的解决方案。一开始完全不了解这一块,开始学习hadoop,不过难度太大放弃了,而且像是杀鸡用牛刀的感觉。之后查了很多资料也百思不得其解。后来向一位经管的学长提了这方面的需求问题,他向我建议了Redis(太感谢了),Redis是一个比较傻瓜式的软件。它支持在一个服务器上部署Redis的Server服务,对一些诸如列表,集合,映射进行记录,然后多个Client可以访问服务器,对这些记录进行修改和查询。
Redis相关的命令网络上资料已经很丰富,不再详述。
使用Redis的一个好处是很方便,弱点在于毕竟是通过网络交互,速度会比真正的分布式集群要慢,当然成本也就更小啦。考虑到我们效率的瓶颈并不是在于映射表的修改和查询,因此我觉得Redis是一个完全可以接受的方案。
第二个问题是选机子。根据我的估计,无论在阿里云,腾讯云还是其他的平台上租机子都是一笔可怕的开销(穷人的哀伤)。我产生了一个大胆的想法,只租用搭载Redis的服务器,而运算端则可以靠身边有心人们发动自己的算力进行支持。因此我选择了在华为云上租了一个Redis3.0的单机,存储是2GB,由于是新用户正好是免费的。注:当时只有Redis3.0能用购买的弹性公网IP,使得外网能够访问这个服务器,更高版本的Redis只能从华为云内部的机子来访问了。
又遇到了一个小难题,Redis对于C++的API似乎不是很友好,我花了一阵子又去下载了国人开发的一个网络框架库ACL(万分感谢)https://www.oschina.net/news/60340/ace-redis-cpp,学习了一下,终于能够用C++来操纵Redis了。给出运算端源代码。
//Milo: 正式程序
#include<cstdio>
#include<ctime>
#include "lib_acl.hpp"
#include "ecn.h"
using namespace std;
const int sz = 2;
const int csz = 3;
const int check_mod = 100003;
Miracl precision(20, 0);
miracl *mip = &precision;
Big mo = "604462909807314587353111";
Big a = mo-3;
Big b = 95;
Big r = "604462909807750541909849";
Big A1, B1, A2, B2, x, y;
ECn P, R, Fm;
ECn stp[sz];
Big da[sz], db[sz];
Big seeda = "1655165156177", seedb = "384864864613";
acl::redis O;
char bufx[200], bufy[200];
int len;
big temp = mirvar(0);
inline int Block(ECn &num)
{
num.getx(x);
return x[0] % csz;
}
inline void F(Big &A, Big &B, ECn &Tmp)
{
register int i = Block(Tmp);
if (i < sz)
{
A += da[i];
B += db[i];
Tmp