创建一个可以返回对角矩阵的 C++ mex 函数

Posted

技术标签:

【中文标题】创建一个可以返回对角矩阵的 C++ mex 函数【英文标题】:Creating a C++ mex function that can return a diagonal matrix 【发布时间】:2021-10-24 15:51:09 【问题描述】:

我需要创建一个 c++ mex 函数,该函数输入一个矩阵并将其与每个数组在其自己的块中的对角线一起返回。 例如。

input_matrix = ([1,2,3;4,5,6;7,8,9])

output_matrix = 1 2 3 0 0 0 0 0 0
                0 0 0 4 5 6 0 0 0
                0 0 0 0 0 0 7 8 9

任何人都可以帮助我在这一点上非常迷茫。

【问题讨论】:

您是否有理由为此特别需要使用 mex 函数?您希望输出是稀疏数组还是密集数组? “我从哪里开始”在这个网站上不是一个很好的问题。选择一个 MEX 文件教程,编写一个 MEX 文件,考虑如何创建一个矩阵,尝试一些东西,如果你遇到困难,你可以在这里提出一个特定的问题,带有代码和对问题的良好理解(但要确保它以前没有被问过)。 【参考方案1】:

我为你做了这个例子,基本的构建块是std::vector。 矩阵可以建模为 std::vector 的 std::vector。 std::vector 是动态分配数组的 C++ 标准库类型

#include <array>
#include <cassert>
#include <vector>
#include <iostream>

// for fixed size arrays use templates, this will also ensure contiguous memory allocation
// to be compatible with other libraries
template<typename type_t, std::size_t rows_v, std::size_t cols_v>
auto create_diagonal_matrix(const type_t(&input)[rows_v][cols_v])

    // unlike "C" style arrays std::array can be returned from a function
    std::array<std::array<type_t,cols_v*rows_v>, rows_v> matrix;

    std::size_t prefix_size = 0ul;                         // number of zeros in front of the next row
    std::size_t postfix_size = (rows_v - 1ul) * cols_v;    // how many zeros to append at the end of next row;

    for (std::size_t row = 0ul; row < rows_v; ++row)
    
        std::size_t col = 0ul;

        // fill prefix_size indices with 0
        for (std::size_t n = 0ul; n < prefix_size; ++n, ++col) matrix[row][col] = 0;

        // fill input row size entries with values from the input
        for (std::size_t n = 0ul; n < rows_v; ++n, ++col) matrix[row][col] = input[row][n];

        // then fill postfix_size indices with 0
        for (std::size_t n = 0ul; n < postfix_size; ++n, ++col) matrix[row][col] = 0;

        // adjuest the prefix and postfix sizes
        prefix_size += rows_v;
        postfix_size -= rows_v;
    

    return matrix;



auto create_diagonal_matrix_dynamic(const std::vector<std::vector<int>>& input)

    std::vector<std::vector<int>> matrix;
    assert(input.size() > 0);
    auto row_size = input[0].size();

    std::size_t prefix_size = 0ul;                                  // number of zeros in front of the next row
    std::size_t postfix_size = (input.size() - 1ul) * row_size;    // how many zeros to append at the end of next row;

    for (const auto& row : input)
    
        assert(row.size() == row_size);                             // runtime validation, all rows must have same length
        std::vector<int> new_row;

        // fill prefix_size indices with 0
        for (std::size_t n = 0ul; n < prefix_size; ++n) new_row.push_back(0);

        // fill input row size entries with values from the input
        for (std::size_t n = 0ul; n < row_size; ++n) new_row.push_back(row[n]);

        // then fill postfix_size indices with 0
        for (std::size_t n = 0ul; n < postfix_size; ++n) new_row.push_back(0);

        matrix.push_back(new_row);

        // adjuest the prefix and postfix sizes
        prefix_size += row_size;
        postfix_size -= row_size;
    

    return matrix;


int main()

    // use an initializer list to setup the 2D input array
    // I think in your code this should be done through parsing an input string
    // and then build up a std::vector<std::vector<int>> yourself.
    auto matrix = create_diagonal_matrix( 1,2,3, 4,5,6, 7,8,9 );

    // output the generated matrix.
    for (const auto& row : matrix)
    
        bool comma = false;
        for (const auto& value : row)
        
            if (comma) std::cout << ", ";
            std::cout << value;
            comma = true;
        

        std::cout << "\n";
    
    std::cout << std::endl;

    // to show memory is contiguous in std::array<std::array<int,9>,3>
    // this is how to get access to contiguous memory for std::array
    auto data_ptr = matrix.data();

    for (std::size_t row = 0; row < matrix.size(); row++)   
    
        bool comma = false;

        for (std::size_t col = 0; col < matrix[0].size(); col++)
        
            if (comma) std::cout << ", ";
            std::cout << data_ptr[row][col];    
            comma = true;
        

        std::cout << "\n";
    

    // creating a mex file is desribed here 
    // https://www.mathworks.com/help/matlab/matlab_external/c-mex-source-file.html

    return 0;

【讨论】:

这不会生成 MEX 文件。此外,向量的向量是存储矩阵的一种糟糕方式,并且与我所知道的任何矩阵库都不兼容。最好使用单个内存块(常规向量)并将其索引映射到数组索引:i + j*nRows 如何创建 MEX 文件不是 C++ 问题,此处描述:mathworks.com/help/matlab/matlab_external/…。 vector 的向量并不是一种糟糕的方式(即使 matlab 示例也使用它),并且仍然比自己键入 new/delete 更喜欢。无论如何,我确实使用模板制作了一个连续的内存示例,但觉得模板代码会分散填充矩阵的算法的注意力。我现在已经在示例中包含了模板代码。

以上是关于创建一个可以返回对角矩阵的 C++ mex 函数的主要内容,如果未能解决你的问题,请参考以下文章

如何逐行读取 Matlab mex 函数的输入矩阵?

在C ++中返回二维数组对角元素之和的函数[重复]

如何从 mex 函数返回矩阵结构?

如何获得矩阵中两个数字之间的对角线数字?

Matlab Mex 文件 - 创建一个常量数组

C++(数据结构与算法):16---特殊矩阵的实现(对角矩阵三对角矩阵下三角矩阵上三角矩阵对称矩阵)