特征:使用特征内禀简化表达式
Eigen: simplifying expression with Eigen intrinsics
我正在尝试使用来自向量的相应值缩放矩阵中的所有列。如果此值为 0,我想将该列替换为按常量缩放的其他矩阵中的列。听起来很复杂,但在 Matlab 中它非常简单(但可能没有完全优化):
a(:,b ~= 0) = a(:,b ~= 0)./b(b ~= 0);
a(:,b == 0) = c(:,b == 0)*x;
在C++中使用for loop
也非常简单:
RowVectorXf b;
Matrix3Xf a, c;
float x;
for (int i = 0; i < b.size(); i++) {
if (b(i) != 0) {
a.col(i) = a.col(i) / b(i);
} else {
a.col(i) = c.col(i) * x;
}
}
是否有可能使用特征内联函数(例如colwise
和select
)执行此操作(更快)?
附言我试图将 if 条件缩短为表单
a.col(i) = (b(i) != 0) ? (a.col(i) / b(i)) : (c.col(i) * x);
但这不会使用错误error: operands to ?: have different types ...(long listing of the types)
进行编译
编辑: 我添加了用于测试答案的代码,这里是:
#include <Eigen/Dense>
#include <stdlib.h>
#include <chrono>
#include <iostream>
using namespace std;
using namespace Eigen;
void flushCache()
{
const int size = 20 * 1024 * 1024; // Allocate 20M. Set much larger than L2
volatile char *c = (char *) malloc(size);
volatile int i = 8;
for (volatile int j = 0; j < size; j++)
c[j] = i * j;
free((void*) c);
}
int main()
{
Matrix3Xf a(3, 1000000);
RowVectorXf b(1000000);
Matrix3Xf c(3, 1000000);
float x = 0.4;
a.setRandom();
b.setRandom();
c.setRandom();
for (int testNumber = 0; testNumber < 4; testNumber++) {
flushCache();
chrono::high_resolution_clock::time_point t1 = chrono::high_resolution_clock::now();
for (int repetition = 0; repetition < 1000; repetition++) {
switch (testNumber) {
case 0:
for (int i = 0; i < b.size(); i++) {
if (b(i) != 0) {
a.col(i) = a.col(i) / b(i);
} else {
a.col(i) = c.col(i) * x;
}
}
break;
case 1:
for (int i = 0; i < b.size(); i++) {
a.col(i) = (b(i) != 0) ? (a.col(i) / b(i)).eval() : (c.col(i) * x).eval();
}
break;
case 2:
for (int i = 0; i < b.size(); i++) {
a.col(i) = (b(i) != 0) ? (a.col(i) * (1.0f / b(i))) : (c.col(i) * x);
}
break;
case 3:
a = b.cwiseEqual(0.0f).replicate< 3, 1 >().select(c * x, a.cwiseQuotient(b.replicate< 3, 1 >()));
break;
default:
break;
}
}
chrono::high_resolution_clock::time_point t2 = chrono::high_resolution_clock::now();
auto duration = chrono::duration_cast< chrono::milliseconds >(t2 - t1).count();
cout << "duration: " << duration << "ms" << endl;
}
return 0;
}
示例输出为:
duration: 14391ms
duration: 15219ms
duration: 9148ms
duration: 13513ms
顺便说一下,不使用 setRandom 来初始化变量,输出是完全不同的:
duration: 10255ms
duration: 11076ms
duration: 8250ms
duration: 5198ms
@chtz 认为这是因为非规范化值,但我认为这是因为分支预测。由于分支预测,初始化b.setZero();
会导致与不初始化相同的时间。
a.col(i) = (b(i) != 0) ? (a.col(i) * (1.0f/b(i))) : (c.col(i) * x);
可以工作,但只是因为表达式的类型相同,并且任何时候都可能不安全(? :
表达式本质上被转换为与if
相同的表达式 -else
分支。
如果您更喜欢将其写入一行,则以下表达式应该有效:
a = b.cwiseEqual(0.0f).replicate<3,1>().select(c*x, a.cwiseQuotient(b.replicate<3,1>()));
同样,我怀疑它会产生任何显着的性能差异。
相关文章:
- (C++)分析树以计算返回错误值的简单算术表达式
- 在VS2010-VS2015下编译时,如何使用decltype作为较大类型表达式的LHS
- 提升精神:解析布尔表达式并简化为规范范式
- 如何声明特征矩阵,然后通过嵌套循环初始化它
- 不能在初始值设定项列表中将非常量表达式从类型 'int' 缩小到'unsigned long long'
- 使用正则表达式regex_search在字符串中查找字符串
- 如何确认我的constexpr表达式实际上已经在编译时执行
- 特征::矩阵<双精度,1,3> 结构类型函数中的返回类型函数
- 概念中的cv限定符需要表达式参数列表
- 是否可以使用带有模板化参数的特征块表达式作为左值?
- 如何将特征张量的值作为'if'条件表达式
- 特征:使用特征内禀简化表达式
- 转换特征矩阵类型时,错误:在"float"之前预期主表达式
- 为什么传递特征表达式的临时性会导致访问未定义的内存
- 禁用特征表达式到const引用的临时绑定
- 表达式必须具有常值特征矩阵
- MATLAB find() / Numpy非零特征表达式
- 用特征向量化表达式
- 重用特征表达式模板
- 对于指数,特征表达式模板比手动循环慢