计算科学-第一次课程设计

第一次课程设计:

  1. 把矩阵向量相乘示例中的for_each(),for_each_n(),generate(),transform()等stl库函数调用改写成普通for循环。测试算例。

  2. 保留上面的stl库函数调用,但添加execution的执行策略,测试并行的效果。

  3. 调用utilities_sc.h中Timer计时器,给程序添加计时功能。

  4. 改写给矩阵赋初值的方式,允许非方阵的矩阵向量相乘。

按照发布的实验报告模板,提交课程设计。谢谢。

一、代码理解或课程设计原理

  1. for_each(),for_each_n(),generate(),transform()函数

四个函数的结构都如下:

for_each( _first, _last, func() )
其中:
_first和_last都为正向迭代器,[first, last) 是用于赋值的范围;
func()是函数,可以是lambda函数或者一般函数函数,或者函数对象。

这些函数都可以改为如下所示的for循环体:

for( i=_first;i<_last;i++)
{
   func();
}

2.execution——标准库的并行算法

能够标定了程序应该串行、并行,还是与向量化并行。

std::execution::seq: 串行执行
std::execution::par: 多线程并行执行
std::execution::par_unseq: 多个线程上并行,可以循环交叉,也能使用SIMD(单指令多数据)
std::execution::par或std::execution::par_unseq允许算法并行或向量化并行。。

二、课程设计过程及结果
1.把矩阵向量相乘示例中的for_each(),for_each_n(),generate(),transform()等stl库函数调用改写成普通for循环
(1) for_each函数与for循环的等价:

for_each(begin(vec4), end(vec4), [&norm1](ZPLX &x){ norm1 = norm1< AbsT(x) ? AbsT(x):norm1; } );   

for(size_t i=0; i<m; i++)
{
       ZPLX x=vec4[i];
       norm1 = norm1< AbsT(x) ? AbsT(x):norm1;
}

(2) for_each_n函数与for循环的等价:

for_each_n(std::execution::seq, arr.begin()+i*cols, i+1, [&urd, &mre](auto& e){ e = urd(mre); } );  

for (size_t j = 0; j < i+1; j++) 
{
      arr[i*cols + j] = urd(mre);
}

(3)transform函数与for循环的等价:

transform(begin(out), end(out), begin(vr), begin(out), minus<>());

for(size_t i=0; i<out.size(); ++i) out[i] -= vr[i];

(4) generate函数与for循环的等价:

generate(begin(vec1), end(vec1), [&n, i=-1]() mutable {i++; return ZPLX(0.8*(i-0.5*n), i); } );

for (size_t i=0; i< m; i++) 
{
    vec1[i]= ZPLX(0.8*(i-0.5*n), i);
}

2.保留上面的stl库函数调用,但添加execution的执行策略,测试并行的效果。
如下,分别加入execution的不同执行策略。

std::execution::seq: 串行执行
std::execution::par: 多线程并行执行
std::execution::par_unseq: 多个线程上并行,可以循环交叉,也能使用SIMD(单指令多数
1.transform(std::execution::seq,begin(out), end(out), 
2.      begin(vr), begin(out), minus<>());
3.
4.generate(std::execution::seq,begin(vec1), end(vec1), 
5.      [&n, i=-1]() mutable {i++; return ZPLX(0.8*(i-0.5*n), i); } );
6.
7.for_each(std::execution::seq,begin(vec4), end(vec4),
8.      [&norm1](ZPLX &x){ norm1 = norm1< AbsT(x) ? AbsT(x):norm1; } );
9.
10.for_each_n(std::execution::seq, arr.begin()+i*cols, i+1, 
11.      [&urd, &mre](auto& e){ e = urd(mre); } );  

3.调用utilities_sc.h中Timer计时器,给程序添加计时功能。

1.#include "utilities_sc.h"     //加入头文件
2.    ......
3.
4.    Timer t;
5.    vec4 -= vec2;
6.
7.    norm1 = 0.0;
8.    for_each(std::execution::seq,begin(vec4), end(vec4), [&norm1](ZPLX &x){ norm1 = norm1< AbsT(x) ? AbsT(x):norm1; } );
9. 
10.    norm2 = norm_L2(vec4);
11.    t.printDiff("for_each: ");
12.    ......

如上,通过调用Timer类中的printDiff函数计时。

4.改写给矩阵赋初值的方式,允许非方阵的矩阵向量相乘。
矩阵初始化头文件中只能初始化方阵。示例中sparse_mat/danse_mat是nm维的矩阵,vec1长度为m,即是m1维的矩阵,两者相乘结果是n1维的。我将其更改为nm的矩阵与m*q的矩阵相乘。
更改如下:
(1)将矩阵赋初值的方式由方阵改为非方阵:
原init_matrix.h中通过上下对角矩阵赋值的方式只能对方阵赋值,我将其更改为对全矩阵赋值。

1.    for (size_t i = 0; i < rows; i++) 
2.        for_each_n(std::execution::seq, arr.begin()+i*cols, cols, 
3.            [&urd, &mre](auto& e){ e = urd(mre); } ); 

(2)除nm维矩阵外,再引入一个mq维的矩阵与其相乘:
在两个.cc文件中,除了n,m外,引入整数q,用vec1[mq]存储这个mq维的矩阵的元素,并为其赋值。

1.size_t n{20}, m{25}, q{20};
2.vector<double> vec1(m*q);
3.generate(begin(vec1), end(vec1), [&n, i=-1]() mutable {i++; return (0.8*(i-0.5*n));});

(3)将nm维的矩阵与mq维的矩阵相乘:
各个vector的作用如下:

1.vector<double> vec1(m*q);   //存储初始的m*q维的矩阵
2.vector<double> vec1_1(m);   //每次将vec1中的一列共m个数据传给vec1_1用于乘法运算
3.vector<double> vec2(n*q);   //存储sparse_mat*vec1计算结果,共n*q个数据
4.vector<double> vec4(n*q);   //存储dense_mat*vec1计算结果,共n*q个数据
5.vector<double> vec2_1;  //存储每次让sparse_mat与vec1_1相乘得到的结果,后续要传递到vec2中
6.vector<double> vec4_1; //存储每次让dense_mat与vec_1相乘得到的结果,后续要传递到vec4中

用vec1_1[m]每次从vec1中取出一列的数据与sparse_mat/danse_mat相乘,并将计算结果存储在vec2_1[m]/vec4_1[m]中,然后将vec2_1[m]/vec4_1[m]中的数据映射到vec2[nq]/vec4[nq]相应列中,最后打印输出vec2/vec4。

1.   
2.    size_t n{20}, m{25},q{10};
3.
4.    SparseMat<double> sparse_mat(n, m, n*m);
5.    DenseMat<double> dense_mat(n, m);
6.
7.    vector<double> vec1(m*q);    //存储一个包含m*q个数据的矩阵
8.    generate(begin(vec1), end(vec1), [&n, i=-1]() mutable {i++; return (0.8*(i-0.5*n)); } );
9.    vector<double> vec1_1(m);   //每次将vec1中的一列m个数据传给vec1_1
10.    vector<double> vec2(n*q);   //存储sparse_mat*vec1的计算结果,共n*q个数据
11.    vector<double> vec4(n*q);   //存储dense_mat*vec1的计算结果,共n*q个数据
12.    
13.    for(size_t x = 0; x < q;x++)
14.    {
15.        for(size_t y = 0;y < m;y++)
16.        {
17.            vec1_1[y] = vec1[x+y*q];//每次将vec1中的一列传给vec1_1
18.        }
19.
20.        vector<double> vec2_1 = sparse_mat*vec1_1;
21.        vector<double> vec4_1 = dense_mat*vec1_1;
22.
23.        for(size_t z = 0;z < n;z++)
24.        {
25.            vec2[z*q+x] = vec2_1[z];     //每次将结果的一列传入vec2
26.            vec4[z*q+x] = vec4_1[z];    //每次将结果的一列传入vec4
27.        }
28.    }

三、结果分析

1.把矩阵向量相乘示例中的for_each(),for_each_n(),generate(),transform()等stl库函数调用改写成普通for循环。
见上,略。

2.保留上面的stl库函数调用,但添加execution的执行策略,测试并行的效果。
对一些程序,std::execution::seq 串行执行结果正确,而std::execution::par多线程并行执行和std::execution::par_unseq由于并行使数据传入不同而导致结果不同。

3.调用utilities_sc.h中Timer计时器,给程序添加计时功能。
见上,略。

4.改写给矩阵赋初值的方式,允许非方阵的矩阵向量相乘。
详细结果可以运行代码,略。

详细报告及修改后的代码包见:
https://download.csdn.net/download/weixin_50836014/85007999

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

一只野指针.

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

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

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

打赏作者

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

抵扣说明:

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

余额充值