提升笛卡尔乘积效率

最近项目的计算节点用的最多的是一个笛卡尔乘积算法,由于字典集合比较多,总高度有时会达到很高的一个量级,例如:1G。这样笛卡尔算法所 耗费的时间将很大,如何提交笛卡尔算法效率已经是当务之急。

笛卡尔乘积的算法很简单,复杂度就摆在这里O(high*n) :n指字典集合个数,high是所有集合的高度乘积。复杂度没法降低,所以我们从循环里面的运算下手,尽量降低循环内的计算,性能有所提升,下面是老版笛卡尔和新版笛卡尔的代码:

新版: 对比旧版,减少了high*(maxHigh-1)*2*n次除法,效率有所提高

int DICJob::descarte(DICComputationTask* dicTask,map<string,charset_mem*>& dicMap,uint8 segSIndex,uint8 segEIndex,uint8** resData,uint64* resHigh,int* reWidth){
	#define MAX_WORD_LEN 64
	cout<<"begin descarte!"<<endl;
	uint64 i,j,k;// 循环变量
	// maxDicHigh为所有字典库高度最大值, maxDicInx为最高字典库的下标 (均要除去star字典库)
	// maxDicOffset为最高字典库在表达式口令中的偏移量, expressionLen为表达式口令长度
	uint64 maxDicHigh = 0, maxDicInx = 0, maxDicOffset = 0, expressionLen = 0;
	// highProduct为所有字典库高度乘积 (除去star字典库)
	// outerIter为外层迭代次数, innerIter为内层迭代次数
	uint64 highProduct = 1, outerIter, innerIter;
	charset_mem* dicCharsetArray[MAX_WORD_LEN]={NULL};
	for(int i=segSIndex; i<=segEIndex; i++){
		map<string,charset_mem*>::iterator iterDic=dicMap.find(dicTask->cn_re.dicName[i]);
		if(iterDic==dicMap.end()){
			cout<<dicTask->cn_re.dicName[i]<<" do not exist"<<endl;
			LOG(ERROR)<<dicTask->cn_re.dicName[i]<<" do not exist";
			return -1;
		}
		int temHigh=dicTask->cn_re.segInfo[i].end-dicTask->cn_re.segInfo[i].begin+1;
		if(temHigh > maxDicHigh) {
			maxDicHigh = temHigh;
			maxDicInx = i;
		}
		dicCharsetArray[i-segSIndex]=iterDic->second;
		highProduct *= temHigh;
		expressionLen += iterDic->second->width;
	}
	uint8 *result = new uint8[highProduct*expressionLen];
	memset(result,0,highProduct*expressionLen);

	// 每条口令后添加一个换行符,所以表达式宽度需要加1
	//expressionLen += 1;
	// 求最高字典库在表达式口令中的偏移量
	for(i = 0; i < maxDicInx; i++) {
		map<string,charset_mem*>::iterator iterDic=dicMap.find(dicTask->cn_re.dicName[i]);
		if(iterDic==dicMap.end()){
			cout<<dicTask->cn_re.dicName[i]<<" do not exist"<<endl;
			LOG(ERROR)<<dicTask->cn_re.dicName[i]<<" do not exist";
			return -1;
		}
		maxDicOffset += iterDic->second->width;
	}
	cout<<"descarte 11!"<<endl;
	// 内层迭代次数为最高字典库高度
	// 外层迭代次数为除了star位和最高字典库的高度乘积
	innerIter = maxDicHigh;
	outerIter = highProduct / maxDicHigh;
	// 外层循环,程序热点(hotspot)
	int thread_num = omp_get_max_threads();
	#pragma omp parallel for num_threads(thread_num) shared(result) private(i, j, k)
	for(i = 0; i < outerIter; i++) {
		// star字典库字段设为0
		// 构造外层模板
		uint32 memOffset = 0;
		uint8 outerPwdTemplate[expressionLen];
		uint8 outerPwdTemplate_32[32 * expressionLen];
		memset(outerPwdTemplate, 0, expressionLen * sizeof(uint8));
		//outerPwdTemplate[expressionLen - 1] = '\n';	// 口令后面添加一个换行
		memset(outerPwdTemplate_32, 0, 32 * expressionLen * sizeof(uint8));
		uint32 remainder , quotient = i; // 除数和余数
		for(int k=segSIndex;k<=segEIndex;++k){
			// 构造外层模板时,排除star字典库和最高字典库(用作内层模板)
			if( k != maxDicInx) {
				remainder = quotient % dicCharsetArray[k-segSIndex]->high;
				quotient = quotient / dicCharsetArray[k-segSIndex]->high;
				memcpy(outerPwdTemplate + memOffset, dicCharsetArray[k-segSIndex]->data + remainder * dicCharsetArray[k-segSIndex]->width,dicCharsetArray[k-segSIndex]->width);
			}
			memOffset += dicCharsetArray[k-segSIndex]->width;
		}
		for(k = 0; k < 32; k++)
			memcpy(outerPwdTemplate_32 + k * expressionLen, outerPwdTemplate, expressionLen);
		// 内层循环
		uint8 innerPwdTemplate_32[32 * expressionLen];
		memset(innerPwdTemplate_32, 0, 32 * expressionLen * sizeof(uint8));
		for(j = 0; j < innerIter; j+=32) {
			uint32 kNum = (j + 32) < innerIter ? 32 : innerIter - j;
			// 构造内层模板
			for(k = 0; k < kNum; k++)
				memcpy(innerPwdTemplate_32 + k * expressionLen + maxDicOffset, dicCharsetArray[maxDicInx]->data + (j + k) * dicCharsetArray[maxDicInx]->width, dicCharsetArray[maxDicInx]->width);
			// 将内层模板和外层模板做或操作,得到结果数组
			for(k = 0; k < kNum * expressionLen; k++)
				result[(i * innerIter + j) * expressionLen + k] = 					innerPwdTemplate_32[k] | outerPwdTemplate_32[k];
		}
	}
	cout<<"descarte 22!"<<endl;
    *resData=result;
	*resHigh=highProduct;
	*reWidth=expressionLen;
	return 0;
	//return highProduct * expressionLen;

}

老版:

int Old_descarte(DICComputationTask* dicTask,map<string,charset_mem*>& dicMap,uint8 segSIndex,uint8 segEIndex,uint8** resData,uint64* resHigh,int* reWidth){
	#define MAX_WORD_LEN 64
	uint64 s[MAX_DIC_NUM]={0};					//字典段进制位

	uint64 high=1;
	int width=0;
	charset_mem* dicCharsetArray[MAX_WORD_LEN]={NULL};

	for(int i=segEIndex; i>=segSIndex; --i){
		s[i]=high;
		map<string,charset_mem*>::iterator iterDic=dicMap.find(dicTask->cn_re.dicName[i]);
		if(iterDic==dicMap.end()){
			cout<<dicTask->cn_re.dicName[i]<<" do not exist"<<endl;
			LOG(ERROR)<<dicTask->cn_re.dicName[i]<<" do not exist";
			return -1;
		}
		dicCharsetArray[i-segSIndex]=iterDic->second;
		high*=dicTask->cn_re.segInfo[i].end-dicTask->cn_re.segInfo[i].begin+1;
		width+=iterDic->second->width;
	}
	uint8* data=new uint8[high*width];
	memset(data,0,high*width);

	//笛卡尔乘积
	int thread_num=omp_get_max_threads();
	#pragma omp parallel for num_threads(thread_num)
	for(uint64 i=0;i<high;++i){
		uint8 wordTmp[MAX_WORD_LEN]={0};
		int offset=0;
		int charpos=i;
		for(int j=segSIndex;j<=segEIndex;++j){

			int indexDic=charpos/s[j];
			int offsetDic=(indexDic+dicTask->cn_re.segInfo[j].begin)*dicCharsetArray[j-segSIndex]->width;
			memcpy(wordTmp+offset,dicCharsetArray[j-segSIndex]->data+offsetDic,dicCharsetArray[j-segSIndex]->width);
			charpos=charpos%s[j];
			offset+=dicCharsetArray[j-segSIndex]->width;
		}
		memcpy(data+i*width,wordTmp,width);
	}
    *resData=data;
	*resHigh=high;
	*reWidth=width;
	return 0;
}
时间: 2024-07-30 15:28:20

提升笛卡尔乘积效率的相关文章

[转]sql语句中出现笛卡尔乘积 SQL查询入门篇

本篇文章中,主要说明SQL中的各种连接以及使用范围,以及更进一步的解释关系代数法和关系演算法对在同一条查询的不同思路. 多表连接简介 在关系数据库中,一个查询往往会涉及多个表,因为很少有数据库只有一个表,而如果大多查询只涉及到一个表的,那么那个表也往往低于第三范式,存在大量冗余和异常. 因此,连接(Join)就是一种把多个表连接成一个表的重要手段. 比如简单两个表连接学生表(Student)和班级(Class)表,如图: 进行连接后如图: 笛卡尔积 笛卡尔积在SQL中的实现方式既是交叉连接(Cr

ASP.NET MVC中实现属性和属性值的组合,即笛卡尔乘积01, 在控制台实现

在电商产品模块中必经的一个环节是:当选择某一个产品类别,动态生成该类别下的所有属性和属性项,这些属性项有些是以DropDownList的形式存在,有些是以CheckBoxList的形式存在.接着,把CheckBoxList的选中项组合生成产品SKU项. 本系列将在ASP.NET MVC中实现以上功能.但本篇,先在控制台实现属性值的笛卡尔乘积. 关于属性的类: public class Prop { public int Id { get; set; } public string Name {

sql语句中出现笛卡尔乘积

没有join条件导致笛卡尔乘积 学过线性代数的人都知道,笛卡尔乘积通俗的说,就是两个集合中的每个成员,都与对方集合中的随意一个成员有关联.能够想象,在SQL查询中,假设对两张表join查询而没有join条件时,就会产生笛卡尔乘积.这就是我们的笛卡尔乘积导致的性能问题中最常见的案例:开发者在写代码时遗漏了join条件. 发生笛卡尔乘积的sql: select sum(project_fj.danjia*project_fj.mianji) from project_fj,orderform whe

ASP.NET MVC中实现属性和属性值的组合,即笛卡尔乘积02, 在界面实现

在"ASP.NET MVC中实现属性和属性值的组合,即笛卡尔乘积01, 在控制台实现"中,在控制台应用程序中实现了属性值的笛卡尔乘积.本篇在界面中实现.需要实现的大致如下: 在界面中勾选CheckBoxList中属性值选项: 把勾选的属性值进行笛卡尔乘积,每行需要填写价格: 我们暂且不考虑这些CheckBoxList是如何显示出来的(在后续有关商品模块的文章中会实现),还需考虑的方面包括: 1.从CheckBoxList中获取到什么再往控制器传? 对于每行的CheckBoxList来说

js实现的笛卡尔乘积-商品发布

//笛卡儿积组合 function descartes(list) { //parent上一级索引;count指针计数 var point = {}; var result = []; var pIndex = null; var tempCount = 0; var temp = []; //根据参数列生成指针对象 for(var index in list) { if(typeof list[index] == 'object') { point[index] = {'parent':pIn

mysql 查询的字段来自多个表时的笛卡尔现象和解决不同表同名问题

#会发生笛卡尔乘积现象,表1 m行,表2 n行,结果为mn行,原因是没有有效的连接条件 SELECT NAME,boyName FROM beauty,boys; #解决笛卡尔现象和不同表同名字段问题 SELECT NAME, boyName FROM beauty, boys WHERE beauty.boyfriend_id=boys.id; 原文地址:https://blog.51cto.com/14437184/2437017

CROSS JOIN连接用于生成两张表的笛卡尔集

将两张表的情况全部列举出来 结果表: 列= 原表列数相加 行= 原表行数相乘 CROSS JOIN连接用于生成两张表的笛卡尔集. 在sql中cross join的使用: 1.返回的记录数为两个表的记录数乘积. 2.将A表的所有行分别与B表的所有行进行连接. 例如: tableA r1 r2 A B C D tableB r3 r4 1 2 3 4 select * from tableA cross join tableB; return: r1 r2 r3 r4 r1 r2 1 2 r1 r2

笛卡尔心形线

Matlab代码: close all; alpha = -pi : pi/50 : pi; x = 2*cos(alpha);y = 2*sin(alpha);for p=1:length(x)        alpha1 = -pi : pi/100 : pi;         x1 = 1*cos(alpha1);        y1 = 1*sin(alpha1);        hold on;        plot(x(1,p)+x1,y(1,p)+y1-1,'g');endaxi

hdu 5412 CRB and Queries(线段树套笛卡尔树 - 动态区间第k大)

题目链接:hdu 5412 CRB and Queries 首先对所有出现过的值排序,建立线段树,每个线段树的节点是一棵笛卡尔树,笛卡尔树记录区间下标值. #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> using namespace std; #define lson(x) (x<<1) #define rson(x) ((x<<