原创作者:郑同学的笔记
原文链接:https://zhengjunxue.blog.csdn.net/article/details/149140136

一、unaryExpr(一元表达式)

    1. 作用:对矩阵/数组的每个元素应用自定义的一元函数(单输入操作)。
    1. 语法:
result = matrix.unaryExpr(const Functor& func);
  • func:函数对象(如lambda、函数指针或仿函数),接受一个标量参数并返回新值。
  • 立即计算:返回新对象。
  1. 示例:
#include <iostream>
#include <Eigen/Eigen>
using namespace Eigen;
using namespace std;

int main()
{
    Eigen::MatrixXd m(2, 2);
    m << 1.1, 2.2,
        3.3, 4.4;

    // 示例1:自定义平方函数
    auto square = [](double x) { return x * x; };
    Eigen::MatrixXd squared = m.unaryExpr(square);

    // 示例2:带参数的缩放 (C++14)
    double scale = 2.5;
    auto scaler = [scale](double x) { return x * scale; };
    Eigen::MatrixXd scaled = m.unaryExpr(scaler);

    // 示例3:元素取整
    auto rounder2 = [](double x) {
        return static_cast<int>(std::round(x));
        };
    Eigen::MatrixXi rounded2 = m.unaryExpr(rounder2);

    // 示例4:条件操作 (将负值设为0)
    auto clamp = [](double x) { return x < 0 ? 0 : x; };
    Eigen::MatrixXd clamped = m.unaryExpr(clamp);

    return 0;
}

使用场景
元素级转换(如缩放、取整)
自定义数学运算
类型转换

    1. 关键点
      函数必须为纯函数(无状态、无副作用)
      支持Lambda表达式(推荐)
      返回值类型自动推导

二、nullaryExpr(零元表达式)

Eigen::VectorXi::NullaryExpr 用于动态生成整数向量,它通过一个自定义函数或函子(functor)计算每个元素的值,无需显式循环。这种方法利用 Eigen 的表达式模板优化,可提升性能。

    1. 作用:生成新矩阵,每个元素由自定义函数动态计算(基于行列索引)。
    1. 语法:
auto mat = Eigen::MatrixXd::NullaryExpr(rows, cols, const Functor& func);
Eigen::VectorXi vec = Eigen::VectorXi::NullaryExpr(size, generator);
  • func:函数对象,接受行索引 i 和列索引 j 作为参数,返回位置 (i, j) 的值。
  • 惰性求值:返回表达式模板,优化计算效率。

参数说明

  • rows, cols:向量的行和列
  • size:向量长度(元素数量)
  • generator:生成函数,接收索引i返回对应位置的值

generator
在 Eigen::VectorXi::NullaryExpr 中,生成器函数需要满足以下要求:
ReturnType generator(Eigen::Index i);
ReturnType generator(Eigen::Index i,Eigen::Index j);

输入参数:必须是 Eigen::Index 类型
返回值:必须与目标容器元素类型匹配

  • 对于 VectorXi → 返回 int
  • 对于 VectorXf → 返回 float
  • 对于 VectorXd → 返回 double
#include <iostream>
#include <Eigen/Eigen>
using namespace Eigen;
using namespace std;

int main()
{
    // 示例1:生成5x5单位矩阵
    auto identity = Eigen::MatrixXd::NullaryExpr(5, 5,
        [](Eigen::Index i, Eigen::Index j) { return (i == j) ? 1.0 : 0.0; });

    // 示例2:创建渐变矩阵 (行索引 + 列索引)
    auto gradient = Eigen::MatrixXd::NullaryExpr(3, 4,
        [](Eigen::Index i, Eigen::Index j) { return i + j; });

    // 示例3:极坐标转换 (r = sqrt(x^2+y^2))
    const int size = 100;
    auto polar = Eigen::MatrixXd::NullaryExpr(size, size,
        [size](Eigen::Index i, Eigen::Index j) {
            double x = j - size / 2.0;
            double y = i - size / 2.0;
            return std::sqrt(x * x + y * y);
        });

    return 0;
}

使用场景
动态生成矩阵(如坐标网格、渐变、自定义模式)
替代循环初始化

    1. 关键点
      生成器函数签名:T f(Eigen::Index row, Eigen::Index col)

支持按需计算

二、 基础示例:

1、生成平方序列 [0, 1, 4, 9, 16]

#include <Eigen/Dense>
#include <iostream>

int main() {
    int size = 5;
    // 使用 lambda 定义生成器 (计算 i²)
    Eigen::VectorXi vec = Eigen::VectorXi::NullaryExpr(size, 
        [](Eigen::Index i) { return i * i; }
    );

    std::cout << vec.transpose() << std::endl; 
    // 输出: 0  1  4  9  16
    return 0;
}

2、完整修正示例:生成随机数

#include <Eigen/Dense>
#include <iostream>
#include <random>

int main() {
    const int size = 5;
    
    // 1. 创建随机数生成器(返回 int)
    std::random_device rd;
    std::mt19937 rng(rd());
    std::uniform_int_distribution<int> dist(0, 99);

    // 2. 使用 NullaryExpr(生成器返回类型 int 匹配 VectorXi)
    Eigen::VectorXi rand_vec = Eigen::VectorXi::NullaryExpr(size,
        [&](Eigen::Index i) -> int {  // 显式声明返回类型
            return dist(rng);
        }
    );

    // 3. 验证类型匹配
    static_assert(
        std::is_same_v<
            decltype(rand_vec)::Scalar,  // VectorXi 的元素类型
            int                          // 生成器返回类型
        >, 
        "类型不匹配!"
    );

    std::cout << "随机向量: " << rand_vec.transpose() << std::endl;
    return 0;
}

三、关键区别

特性 unaryExpr nullaryExpr
输入来源 已有矩阵的元素 无输入(通过索引生成值)
参数 单个标量值 行列索引 (i, j)
用途 元素级转换(如log, sin) 动态生成矩阵(如单位矩阵)

四、相关解析:

static_assert(  // 编译时断言,如果条件不满足则编译失败
    std::is_same_v<         // 类型特性检查:判断两个类型是否完全相同
        decltype(rand_vec)::Scalar,  // 获取 rand_vec 的元素类型
        int                          // 期望的类型(int)
    >, 
    "类型不匹配!"           // 如果断言失败,显示的错误信息
);

关键组件详解:

1、decltype(rand_vec)::Scalar

  • decltype(rand_vec):获取变量 rand_vec 的编译时类型(Eigen::VectorXi)
  • ::Scalar:Eigen 容器的内嵌类型别名,表示容器元素的类型
  • 对于 Eigen::VectorXi,Scalar 就是 int

2、std::is_same_v<…>

C++17 引入的模板变量(等同于 std::is_same<…>::value)
检查两个类型是否完全相同
如果类型相同 → 值为 true
如果类型不同 → 值为 false

3、static_assert(condition, message)

编译时断言:在编译阶段检查条件
如果条件为 true → 编译继续
如果条件为 false → 编译失败,显示指定的错误信息

对比其他类型获取方式

方法 特点 示例
decltype(expr) 获取表达式的确切类型(包括引用和const decltype(x) → int
auto 自动推导变量类型(会移除引用和const限定符 auto y = x → int
std::is_same_v<T,U> 编译时比较两个类型是否相同(常与 decltype 配合使用) std::is_same_v<int, float> → false
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐