生物信息学(5)——基于CUDA的多序列比对并行算法的设计与代码实现

生物信息学系列博客索引

生物信息学(1)——双序列比对之Needleman-Wunsch(NW)算法详解及C++实现
生物信息学(2)——双序列比对之Smith-Waterman(SW)算法详解
生物信息学(3)——双序列比对之BLAST算法简介
生物信息学(4)——多序列比对之CLUSTAL算法详解及C++实现
生物信息学(5)——基于CUDA的多序列比对并行算法的设计与代码实现
项目gitee地址,内附源码、论文等文档信息

1. 设计并行算法的原因

虽然 CLUSTAL 算法具有较高的精度,但是由于其构造导向树的距离,即两 两比对的过程,需要迭代调用双序列比对算法,这将使得算法的时间复杂度来到 n 的四次方,数据愈多,需要消耗的时间就指数增加,对 CPU 造成巨大压力。 CUDA 平台调度 GPU 提供的并行计算能力有效的缓解了这一问题。

2. CUDA 下 CLUSTAL 执行流程

由于 CLUSTAL 算法分为三步:两两比对、构建向导树、渐近比对,最耗时 间的为迭代调用双序列比对算法进行两两比对,且此时两两比对数据无写相关, 公共数据仅仅是读共同的序列簇,所以就可以在此处利有 CUDA 调度 GPU 提供 的并行计算能力,并行的进行两两序列比对,以此来加快 CLUSTAL 算法的执行 速度
在这里插入图片描述

3. 代码

有些实现的细节见文末,这是CUDA代码,安装CUDA需要先安装vs2015,然后根据电脑GPU版本去NVIDIA官网安装对应的CUDA。


#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <stdio.h>
#include<iostream>
#include <string>
#include<algorithm>
#include <vector>                          
#include <iterator> 
#include<ctime>
//声明命名空间std
using namespace std;
#define MATCH 1
#define DIS_MATCH -1
#define INDEL -2
#define INDEL_CHAR '-'


class ResUnit {		//一次双序列比对后的结果
public:
	char str1[30];	//原始序列1
	char str2[30];	//原始序列2
	char res1[30];	//结果序列1
	char res2[30];	//结果序列2
	int str1Len;
	int str2Len;
	int res1Len;
	int res2Len;
	int score;		//序列总得分,反映两个序列的相似程度
	int tag;		//禁止迭代多次
};

class SingleSeq {	//一个序列被整合后的样子
public:
	string str;		//一个序列的原始序列
	string res;		//一个序列被整合后的样子
};


class ResUnit2 {		//一次双序列比对后的结果
public:
	string str1;	//原始序列1
	string str2;	//原始序列2
	string res1;	//结果序列1
	string res2;	//结果序列2
	int score;		//序列总得分,反映两个序列的相似程度
	int tag;		//禁止迭代多次
};

struct BacktrackingUnit {
	int goUp;		//是否向上回溯
	int goLeftUp;	//是否向左上回溯
	int goLeft;		//是否向左回溯
	int score;		//得分矩阵第(i, j)这个单元的分值
};

typedef struct BacktrackingUnit *unitLine;

__device__ int max3(int a, int b, int c);
__device__ int myCompare(char a, char b);
int max32(int a, int b, int c);
int myCompare2(char a, char b);
bool complare2(const ResUnit2 &a, const ResUnit2 &b);
ResUnit2 traceback(unitLine** item, const int i, const int j, string str1, string str2, string res1, string res2, int n, ResUnit2 resUnit);
ResUnit2 NeedlemanWunch(string str1, string str2);
int ifStrInQueueFinish(string str, vector<SingleSeq> queue_finish);
vector<SingleSeq> RegularTwo(ResUnit2 tag, ResUnit2 temp, vector<SingleSeq> queue_finish);
vector<SingleSeq> RegularSeq1(ResUnit2 tag, vector<SingleSeq> queue_finish, int item);
vector<SingleSeq> RegularSeq2(ResUnit2 tag, vector<SingleSeq> queue_finish, int item);


/**
kernel函数	数据并行处理函数
*/
__global__ void kernelFunc(ResUnit *res)
{
	int x = threadIdx.x;

	char *str1 = res[x].str1;
	char *str2 = res[x].str2;

	//字符串str1,str2长度
	const int m = res[x].str1Len;
	const int n = res[x].str2Len;

	int m1, m2, m3, mm;


	BacktrackingUnit **unit;
	unit = new BacktrackingUnit*[m+1];

	for (int i = 0; i < m+1; i++)
	{
		unit[i] = new BacktrackingUnit[n+1];
		for (int j = 0; j < n + 1;j++) {
			unit[i][j] = BacktrackingUnit();
			unit[i][j].goUp = 0;
			unit[i][j].goLeftUp = 0;
			unit[i][j].goLeft = 0;
		}
	}

	unit[0][0].score = 0;
	for (int i = 1; i <= m; i++) {
		unit[i][0].score = -2 * i;
		unit[i][0].goUp = 1;
	}
	for (int j = 1; j <= n; j++) {
		unit[0][j].score = -2 * j;
		unit[0][j].goLeft = 1;
	}
	
	// 动态规划算法计算得分矩阵每个单元的分值
	for (int i = 1; i <= m; i++) {
		for (int j = 1; j <= n; j++) {
			m1 = unit[i - 1][j].score + -2;
			m2 = unit[i - 1][j - 1].score + myCompare(str1[i - 1], str2[j - 1]);
			m3 = unit[i][j - 1].score + -2;
			mm = max3(m1, m2, m3);
			unit[i][j].score = mm;
			//判断路径来源
			if (m1 == mm) unit[i][j].goUp = 1;
			if (m2 == mm) unit[i][j].goLeftUp = 1;
			if (m3 == mm) unit[i][j].goLeft = 1;
		}
	}

	//开始回溯

	int i = m, int j = n;
	ResUnit resUnit;
	resUnit.tag = 0;
	resUnit.res1Len = 0;
	resUnit.res2Len = 0;
	resUnit.score = unit[m][n].score;

	while (resUnit.tag != 1)
	{
		BacktrackingUnit temp = unit[i][j];

		if (!(i || j)) {   // 到矩阵单元(0, 0)才算结束,这代表初始的两个字符串的每个字符都被比对到了
			resUnit.tag = 1;
		}
		if (temp.goUp) {    // 向上回溯一格
			resUnit.res1[resUnit.res1Len] = str1[i - 1];
			resUnit.res2[resUnit.res2Len] = '-';
			++resUnit.res1Len;
			++resUnit.res2Len;
			--i;
		}
		if (temp.goLeftUp) {    // 向左上回溯一格 
			resUnit.res1[resUnit.res1Len] = str1[i - 1];
			resUnit.res2[resUnit.res2Len] = str2[j - 1];
			++resUnit.res1Len;
			++resUnit.res2Len;
			--i;
			--j;
		}
		if (temp.goLeft) {    // 向左回溯一格
			resUnit.res1[resUnit.res1Len] = '-';
			resUnit.res2[resUnit.res2Len] = str2[j - 1];
			++resUnit.res1Len;
			++resUnit.res2Len;
			--j;
		}
	}
	delete(unit);
	
	for (int k = 0; k < m;k++)
	{
		resUnit.str1[k] = str1[k];
	}
	
	for (int k = 0; k < n;k++)
	{
		resUnit.str2[k] = str2[k];
	}

	res[x] = resUnit;
	
}



int main()
{
	
	const int sequence_groups = 31;
	string *ss = new string[sequence_groups];
	ss[0] = "AATTCCGGAAAATTCCGGGACA";
	ss[1] = "AATTCGAACGAATGGACATCGA";
	ss[2] = "GTTCGGAAGTTCCGGAAAAAGG";
	ss[3] = "AACTCCGCGAACTCCGCGGACA";
	ss[4] = "ATTCCGGGAAATTGGACAGGG";
	ss[5] = "ATTCCGGACACCGGGAAACTTAA";
	ss[6] = "CTCCGGGAAATTCCGGGACAG";
	ss[7] = "ATTCCGGGAAGGACATCCGGGA";
	ss[8] = "ATCACCGGGAAAGGGACGGACA";
	ss[9] = "CCGCCGGATTAGGGGACAGCAA";
	ss[10] = "CCGGACCCGTGGGACAAATT";
	ss[11] = "CTCGCCCGGACATTAGGAATT";
	ss[12] = "CACCGGACATTAGGACAGGGC";
	ss[13] = "CGCGCCGGCCGGGGACAACGG";
	ss[14] = "CCGGACAATTAAGGGACGGACA";
	ss[15] = "CCGGACAGGACATTCATTAGG";
	ss[16] = "CTCGATTAGGGCACATTAGGA";
	ss[17] = "CACCGGACATTAGGGGGACAC";
	ss[18] = "CGATTAGGGCGCCGGACGGAC";
	ss[19] = "CCGGACTAGGGCGGACTGACT";
	ss[20] = "CCGTAGGGCTTAAGGGACTGACT";
	ss[21] = "CCGGACAATTAGGGCTGACT";
	ss[22] = "CTAGGGCATTAAGGGACTGACT";
	ss[23] = "CCGGACAATTTAGGGCTGACT";
	ss[24] = "CCGGTAGGGCTAAGGGACTGACT";
	ss[25] = "CCGGACTAGGGCGGACTGACT";
	ss[26] = "CCGTAGGGCATTAAACTGACT";
	ss[27] = "CCGTTAAACTAGGGACTGACT";
	ss[28] = "CCGGACTTAAACTGGACTGACT";
	ss[29] = "CTTAAACTTTAAGGGACTGACT";
	ss[30] = "CCGGACAATTTAAACTGACT";


	vector<ResUnit2> queue_initial(0); //定义等待整合的队列,是一个ResUnit对象vector
	vector<SingleSeq> queue_finish(0); //定义整合完毕的队列,是一个String类型的vector
	vector<ResUnit2>::iterator it; //迭代器,访问queue_initial
	vector<SingleSeq>::iterator it_finish;  //迭代器,访问queue_finish

	clock_t startTime, endTime;
	startTime = clock();//计时开始

	//定义队列长度
	const int queue_length = ((sequence_groups - 1)*sequence_groups) / 2;
	//初始化矩阵
	//res保存的是待排序的双序列组合,对象数组长度为queue_length
	ResUnit res[queue_length];
	int k = 0;
	//初始化,将string类型的字符串转入char[]数组
	for (int i = 0;i < sequence_groups;i++) {
		for (int j = i + 1;j < sequence_groups;j++) {
			//只遍历上三角区域
			for (int m = 0; m < ss[i].length(); m++)
			{
				res[k].str1[m] = ss[i][m];
			}
			res[k].str1Len = ss[i].length();
			for (int m = 0; m < ss[j].length(); m++)
			{
				res[k].str2[m] = ss[j][m];
			}
			res[k].str2Len = ss[j].length();
			k++;
		}
	}
	

	//定义GPU上的变量
	ResUnit *resGpu;
	//分配地址
	cudaMalloc((void**)&resGpu, queue_length * sizeof(ResUnit));

	//将主机上的数据转到设备上
	cudaMemcpy(resGpu, res, queue_length * sizeof(ResUnit), cudaMemcpyHostToDevice);
	//分配线程
	kernelFunc << <1, queue_length >> > (resGpu);
	//将设备上的数据拷贝回主机上
	cudaMemcpy(res, resGpu, queue_length * sizeof(ResUnit), cudaMemcpyDeviceToHost);
	//释放
	cudaFree(resGpu);

	//拷贝到queue_initial
	for (int i = 0; i < queue_length; i++)
	{
		ResUnit2 resUnit2;
		string str1 = res[i].str1;
		string str2 = res[i].str2;
		string res1 = strrev(res[i].res1);
		string res2 = strrev(res[i].res2);
		resUnit2.str1 = str1;
		resUnit2.str2 = str2;
		resUnit2.res1 = res1;
		resUnit2.res2 = res2;
		resUnit2.score = res[i].score;
		queue_initial.push_back(resUnit2);
		
		//cout << "str1:" << str1 << ",str2:" << str2 << ",res1:" << res1 << ",res2:" << res2 << endl;
	}
	//clustal算法
	//排序
	sort(queue_initial.begin(), queue_initial.end(), complare2);

	//最多循环queue_length次
	for (int i = 0;i < queue_length;i++) {
		//当结果队列长度与sequence_groups相等之后,就说明全部放入了结果队列,可以跳出循环了
		if (sequence_groups == queue_finish.size())
			break;

		//一个ResUnit对象的str1属性和str2均不在
		if (ifStrInQueueFinish(queue_initial.at(i).str1, queue_finish) < 0 && ifStrInQueueFinish(queue_initial.at(i).str2, queue_finish) < 0) {
			SingleSeq singleSeq1, singleSeq2;
			singleSeq1.str = queue_initial.at(i).str1;
			singleSeq1.res = queue_initial.at(i).res1;
			singleSeq2.str = queue_initial.at(i).str2;
			singleSeq2.res = queue_initial.at(i).res2;

			//如果结果队列已经有元素,,且又来了俩不相干的,却很匹配的序列对
			if (queue_finish.size()>0) {

				//将结果队列第一个的序列和queue_initial.at(i).str1进行双序列比对
				ResUnit2 temp = NeedlemanWunch(queue_finish.front().str, queue_initial.at(i).str1);
				//进行规整操作
				queue_finish = RegularTwo(queue_initial.at(i), temp, queue_finish);
			}
			else
			{
				queue_finish.push_back(singleSeq1);
				queue_finish.push_back(singleSeq2);
			}

		}
		//str1在,str2不在
		else if (ifStrInQueueFinish(queue_initial.at(i).str1, queue_finish) > -1 && ifStrInQueueFinish(queue_initial.at(i).str2, queue_finish) < 0) {
			int item = ifStrInQueueFinish(queue_initial.at(i).str1, queue_finish);
			queue_finish = RegularSeq1(queue_initial.at(i), queue_finish, item);
		}
		//str2在,str1不在
		else if (ifStrInQueueFinish(queue_initial.at(i).str2, queue_finish) > -1 && ifStrInQueueFinish(queue_initial.at(i).str1, queue_finish) < 0) {
			int item = ifStrInQueueFinish(queue_initial.at(i).str2, queue_finish);
			queue_finish = RegularSeq2(queue_initial.at(i), queue_finish, item);
		}
	}


	//声明一个迭代器,来访问vector容器
	cout << "--------------------------------------------------------------------" << endl;
	cout << endl << "原序列" << endl;
	for (it_finish = queue_finish.begin();it_finish != queue_finish.end();it_finish++) {
		cout << it_finish->str << endl;
	}
	cout << endl << "比对后" << endl;
	for (it_finish = queue_finish.begin();it_finish != queue_finish.end();it_finish++) {
		cout << it_finish->res << endl;
	}

	endTime = clock();//计时结束
	cout << endl << endl << "The run time is: " << (double)(endTime - startTime) / CLOCKS_PER_SEC << "s" << endl;
	cout << "--------------------------------------------------------------------" << endl;



	system("pause");
	return 0;
}

/**
比较三种路径之间谁最大

f(i-1,j-1),f(i-1,j)+indel,f(i,j-1)+indel
*/
__device__ int max3(int a, int b, int c) {
	int temp = a > b ? a : b;
	return temp > c ? temp : c;
}

/**
比较两个字符类型属于什么,match,dismatch,indel
*/
__device__ int myCompare(char a, char b) {
	if (a == b)
		return 1;
	else if (a == ' ' || b == ' ')
		return -2;
	else
		return -1;
}

/*
规整函数,规整两个序列情况

queue_finish      temp		tag
A1				  A2		E1
B				  E2		F
C
D
*/
vector<SingleSeq> RegularTwo(ResUnit2 tag, ResUnit2 temp, vector<SingleSeq> queue_finish) {
	string E2 = temp.res2;
	string E1 = tag.res1;
	string A1 = queue_finish.front().res;
	string A2 = temp.res1;
	string F = tag.res2;
	string tempStr = "";
	vector<SingleSeq>::iterator it;//声明一个迭代器,来访问vector容器

	int i = 0, j = 0;
	//第一步,,整合tag与temp
	while (E2 != E1 && j < E1.length() && i < E2.length()) {
		if (E2[i] == E1[j]) {
			i++;
			j++;
		}
		else {
			if (E2[i] == '-') {
				E1.insert(j, "-");
				F.insert(j, "-");

			}
			else if (E1[j] == '-')
			{
				E2.insert(i, "-");
				A2.insert(i, "-");

			}
		}
	}

	if (i == E2.length()) {

		//E2先到头
		for (int k = 0; k < E1.length() - j; k++)
		{
			tempStr += "-";
		}
		E2 += tempStr;
		A2 += tempStr;

	}
	else if (j == E1.length()) {
		//E1先到头
		for (int k = 0; k < E2.length() - i; k++)
		{
			tempStr += "-";
		}
		E1 += tempStr;
		F += tempStr;
	}

	//将tempStr置空
	tempStr = "";

	//第二步 融合进queue_finish
	i = 0, j = 0;
	while (A1 != A2 && i < A1.length() && j < A2.length()) {
		if (A1[i] == A2[j]) {
			i++;
			j++;
		}
		else {
			if (A1[i] == '-') {
				A2.insert(j, "-");
				E1.insert(j, "-");
				F.insert(j, "-");
			}
			else if (A2[j] == '-')
			{
				A1.insert(i, "-");
				for (it = queue_finish.begin();it != queue_finish.end();it++) {
					it->res = it->res.insert(i, "-");
				}
			}
		}
	}

	if (i == A1.length()) {

		//A1先到头
		for (int k = 0; k < A2.length() - j; k++)
		{
			tempStr += "-";
		}
		A1 += tempStr;
		for (it = queue_finish.begin();it != queue_finish.end();it++) {
			it->res = it->res + tempStr;
		}

	}
	else if (j == A2.length()) {
		//A2先到头
		for (int k = 0; k < A1.length() - i; k++)
		{
			tempStr += "-";
		}
		A2 += tempStr;
		E1 += tempStr;
		F += tempStr;
	}

	//规划好之后,,将 E F 插入queue_finish尾部
	SingleSeq sE, sF;
	sE.res = E1;
	sE.str = tag.str1;
	sF.res = F;
	sF.str = tag.str2;
	queue_finish.push_back(sE);
	queue_finish.push_back(sF);
	return queue_finish;
}

/*
规整函数,规整序列1情况

queue_finish      tag
A1				  A2
B				  E
C
D
*/
vector<SingleSeq> RegularSeq1(ResUnit2 tag, vector<SingleSeq> queue_finish, int item) {
	SingleSeq main_seq = queue_finish.at(item);//找到和seq1相同的序列
	string A1 = main_seq.res;
	string A2 = tag.res1;
	string E = tag.res2;
	string tempStr = "";
	vector<SingleSeq>::iterator it;//声明一个迭代器,来访问vector容器
	int i = 0, j = 0;

	while (A1 != A2 && i < A1.length() && j < A2.length()) {
		if (A1[i] == A2[j]) {
			i++;
			j++;
		}
		else {
			if (A1[i] == '-') {
				A2.insert(j, "-");
				E.insert(j, "-");
			}
			else if (A2[j] == '-') {
				//遍历queue_finish,给queue_finish内res洗头
				A1.insert(i, "-");
				for (it = queue_finish.begin();it != queue_finish.end();it++) {
					it->res = it->res.insert(i, "-");
				}
			}
		}
	}

	if (i == A1.length()) {

		//A1先到头
		for (int k = 0; k < A2.length() - j; k++)
		{
			tempStr += "-";
		}
		A1 += tempStr;
		for (it = queue_finish.begin();it != queue_finish.end();it++) {
			it->res = it->res + tempStr;
		}

	}
	else if (j == A2.length()) {
		//A2先到头
		for (int k = 0; k < A1.length() - i; k++)
		{
			tempStr += "-";
		}
		A2 += tempStr;
		E += tempStr;
	}

	//添加
	SingleSeq sE;
	sE.res = E;
	sE.str = tag.str2;
	queue_finish.push_back(sE);
	return queue_finish;
}

/*
规整函数,规整序列2情况

queue_finish      tag
A1				  E
B				  A2
C
D
*/
vector<SingleSeq> RegularSeq2(ResUnit2 tag, vector<SingleSeq> queue_finish, int item) {
	SingleSeq main_seq = queue_finish.at(item);//找到和seq1相同的序列
	string A1 = main_seq.res;
	string A2 = tag.res2;
	string E = tag.res1;
	string tempStr = "";
	vector<SingleSeq>::iterator it;//声明一个迭代器,来访问vector容器

	int i = 0, j = 0;
	while (A1 != A2 && i < A1.length() && j < A2.length()) {
		if (A1[i] == A2[j]) {
			i++;
			j++;
		}
		else {
			if (A1[i] == '-') {
				A2.insert(j, "-");
				E.insert(j, "-");
			}
			else if (A2[j] == '-') {
				//遍历queue_finish,给queue_finish内res洗头
				A1.insert(i, "-");
				for (it = queue_finish.begin();it != queue_finish.end();it++) {
					it->res = it->res.insert(i, "-");
				}
			}
		}
	}

	if (i == A1.length()) {

		//A1先到头
		for (int k = 0; k < A2.length() - j; k++)
		{
			tempStr += "-";
		}
		A1 += tempStr;
		for (it = queue_finish.begin();it != queue_finish.end();it++) {
			it->res = it->res + tempStr;
		}

	}
	else if (j == A2.length()) {
		//A2先到头
		for (int k = 0; k < A1.length() - i; k++)
		{
			tempStr += "-";
		}
		A2 += tempStr;
		E += tempStr;
	}
	//添加
	SingleSeq sE;
	sE.res = E;
	sE.str = tag.str1;
	queue_finish.push_back(sE);
	return queue_finish;
}


//判断一个str是否有与queue_finish数组对象内的seq相等的,没有返回-1,有就返回序号
int ifStrInQueueFinish(string str, vector<SingleSeq> queue_finish) {
	int i = 0;
	vector<SingleSeq>::iterator it;//声明一个迭代器,来访问vector容器
	for (it = queue_finish.begin();it != queue_finish.end();it++) {
		if (str == it->str)
			return i;
		i++;
	}
	return -1;
}


ResUnit2 NeedlemanWunch(string str1, string str2) {
	//字符串str1,str2长度
	const int m = str1.length();
	const int n = str2.length();

	int m1, m2, m3, mm;

	unitLine **unit;

	// 初始化
	if ((unit = (unitLine **)malloc(sizeof(unitLine*) * (m + 1))) == NULL) {
		fputs("Error: Out of space!\n", stderr);
		exit(1);
	}
	for (int i = 0; i <= m; i++) {
		if ((unit[i] = (unitLine *)malloc(sizeof(unitLine) * (n + 1))) == NULL) {
			fputs("Error: Out of space!\n", stderr);
			exit(1);
		}
		for (int j = 0; j <= n; j++) {
			if ((unit[i][j] = (unitLine)malloc(sizeof(struct BacktrackingUnit))) == NULL) {
				fputs("Error: Out of space!\n", stderr);
				exit(1);
			}
			unit[i][j]->goUp = 0;
			unit[i][j]->goLeftUp = 0;
			unit[i][j]->goLeft = 0;
		}
	}
	unit[0][0]->score = 0;
	for (int i = 1; i <= m; i++) {
		unit[i][0]->score = INDEL * i;
		unit[i][0]->goUp = 1;
	}
	for (int j = 1; j <= n; j++) {
		unit[0][j]->score = INDEL * j;
		unit[0][j]->goLeft = 1;
	}


	// 动态规划算法计算得分矩阵每个单元的分值
	for (int i = 1; i <= m; i++) {
		for (int j = 1; j <= n; j++) {
			m1 = unit[i - 1][j]->score + INDEL;
			m2 = unit[i - 1][j - 1]->score + myCompare2(str1[i - 1], str2[j - 1]);
			m3 = unit[i][j - 1]->score + INDEL;
			mm = max32(m1, m2, m3);
			unit[i][j]->score = mm;
			//判断路径来源
			if (m1 == mm) unit[i][j]->goUp = 1;
			if (m2 == mm) unit[i][j]->goLeftUp = 1;
			if (m3 == mm) unit[i][j]->goLeft = 1;
		}
	}


	//开始回溯
	ResUnit2 res;
	res.tag = 0;
	res = traceback(unit, m, n, str1, str2, "", "", 0, res);
	res.score = unit[m][n]->score;


	//释放内存
	for (int i = 0; i <= m; i++) {
		for (int j = 0; j <= n; j++) {
			free(unit[i][j]);
		}
		free(unit[i]);
	}
	free(unit);

	//返回值
	return res;
}


ResUnit2 traceback(unitLine** item, const int i, const int j, string str1, string str2, string res1, string res2, int n, ResUnit2 resUnit) {
	unitLine temp = item[i][j];
	if (resUnit.tag != 1)
	{
		if (!(i || j)) {   // 到矩阵单元(0, 0)才算结束,这代表初始的两个字符串的每个字符都被比对到了

			resUnit.str1 = str1;
			resUnit.str2 = str2;
			resUnit.res1 = res1;
			resUnit.res2 = res2;
			resUnit.tag = 1;
			return resUnit;
		}
		if (temp->goUp) {    // 向上回溯一格
			res1 = str1[i - 1] + res1;
			res2 = INDEL_CHAR + res2;
			resUnit = traceback(item, i - 1, j, str1, str2, res1, res2, n + 1, resUnit);
		}
		if (temp->goLeftUp) {    // 向左上回溯一格 
			res1 = str1[i - 1] + res1;
			res2 = str2[j - 1] + res2;
			resUnit = traceback(item, i - 1, j - 1, str1, str2, res1, res2, n + 1, resUnit);
		}
		if (temp->goLeft) {    // 向左回溯一格
			res1 = INDEL_CHAR + res1;
			res2 = str2[j - 1] + res2;
			resUnit = traceback(item, i, j - 1, str1, str2, res1, res2, n + 1, resUnit);
		}
		return resUnit;
	}
	else
	{
		return resUnit;
	}

}

bool complare2(const ResUnit2 &a, const ResUnit2 &b)
{
	return a.score > b.score;
}

/**
比较三种路径之间谁最大

f(i-1,j-1),f(i-1,j)+indel,f(i,j-1)+indel
*/
int max32(int a, int b, int c) {
	int temp = a > b ? a : b;
	return temp > c ? temp : c;
}

/**
比较两个字符类型属于什么,match,dismatch,indel
*/
int myCompare2(char a, char b) {
	if (a == b)
		return MATCH;
	else if (a == ' ' || b == ' ')
		return INDEL;
	else
		return DIS_MATCH;
}

4. 结果分析

在这里插入图片描述
在这里插入图片描述
由表 5-2 a 组数据可知,当序列长度和序列数量都很小时候,CUDA 并没有 展现出他的能力,由于要将数据从主机端拷贝到设备端,且运行结束又有将设备 端数据拷贝至主机端,所以相对于 CPU 版本代码,GPU 版代码运行的效果非常 的差,甚至于来说,运行时间根本不在一个数量级。

由表 5-2 b 组数据可知,当数据量微有上升,CUP 与 GPU 运行时间虽然还 是有差距,但是已经将时间缩短至一个数量级。

表 5-2 c 组与 d 组数据放一起比对,可得当序列数量不变,序列长度增加时, GPU 对算法的加速效果虽有但甚微。

表 5-2 c 组与 d 组数据放一起比对,可得,当序列长度不变,序列数量增加 时,GPU 明显优于 CPU 版本代码执行速度,具有明显的加速效果。

GPU加速CLUSTAL算法是通过并行执行CLUSTAL算法过程中两两比对执 行双序列比对来进行加速。设有 n 条序列,则共需迭代执行 n(n-1)/2 次双序列比 对过程。当 n 数量上升时,CPU 运行时间将明显上升。GPU 并行调用 Kernel 函 数中的 NW 算法,分配 n(n-1)/2 个 block 并行执行,只需额外增加拷贝数据的时 间,便可以主观上人为的运行一次双序列比对算法时间,完成 n(n-1)/2 次双序列 比对,所以时间明显减少。

5. 代码的一些细节

在实现细节上,由于 C++与 C 未提供对字符串的设 备端处理函数,即 CUDA 中的 kernel 核函数中不能调用 strLen()等方法处理字符 串。本文通过将字符串看成字符数组进行字符串的添加操作,由于需要比对的序 列长度大致相仿,联系实际,用预设定长度的字符数组处理字符串,亦是可行之 举。

6. 总结

显然,博文的题目是篇毕业论文,当你看到这篇博文的时候,我也已经顺利的毕业,大学四年自此画上了句号。四年的本科生涯并没有学习生物信息学的我,也是这半年加班加点、临时抱佛脚学的,有些内容或者概念可能并不是理解的很透彻,如果有错误也请您不吝赐教,加以斧正。独学而无友,孤陋而寡闻,学习之途我也迷茫过,无助过,正因为此,我才知道分享的重要性。希望屏幕前的陌生人,能从我这获取一些帮助,也算是在我平凡的生活里,增添一抹荣光了。

  • 11
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
《基于GPU的BWA序列比对算法分析与加速》是一篇研究基于图形处理器(GPU)加速BWA序列比对算法的论文。BWA是一种常用的高通量测序数据比对算法,用于将测序数据与参考基因组进行比对。然而,BWA算法处理大规模测序数据时存在计算量大、性能低下等问题。因此,该论文探索了基于GPU的加速算法,旨在提高BWA算法的计算效率。 论文首先分析了BWA算法的思想,包括Seed-and-Extend方法和BWT索引结构。然后介绍了GPU的并行计算架构和CUDA编程模型,指出了GPU在并行计算方面的优势。 接着,该论文提出了一种基于GPU的BWA算法优化方案。通过将算法的计算任务划分为多个并行任务,在GPU上并行执行,可以大大提高计算效率。同时,为了减小数据传输的开销,该论文使用了一种基于shared memory的优化策略,将数据存储在GPU内存中,减少了与主机内存之间的数据传输。 为了验证提出的加速算法的效果,论文进行了大量的实验,并比较了加速算法和传统算法在性能方面的差异。实验结果表明,基于GPU的BWA算法能够大幅度提高比对速度和计算效率,尤其是在处理大规模测序数据时表现更加突出。 综上所述,《基于GPU的BWA序列比对算法分析与加速》论文通过研究基于GPU的加速算法,有效地优化了BWA序列比对算法的性能。该研究对于加速大规模测序数据的处理具有重要的实际意义,可以为基因组学和生物信息学领域的研究提供更快速、高效的测序数据比对工具。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大青儿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值