C++ 如何从稀疏矩阵中得到右下部分?

C++ 如何从稀疏矩阵中得到右下部分?,c++,c,matrix,C++,C,Matrix,获得“坐标格式”中稀疏矩阵右下四分之一的最佳方法是什么?我需要它来补充舒尔 坐标从1开始索引(我用的是腮腺炎) 例子: 所以我的矩阵应该是这样的: |1 0 2 0| |0 0 3 0| |0 0 4 5| |0 0 0 6| int schur_complement_size = 1 |6| int schur_complement_size = 2 |4 5| |0 6| int schur_complement_size = 3 |0 3 0| |0 4 5| |0 0 6| in

获得“坐标格式”中稀疏矩阵右下四分之一的最佳方法是什么?我需要它来补充舒尔

坐标从1开始索引(我用的是腮腺炎)

例子: 所以我的矩阵应该是这样的:

|1 0 2 0|
|0 0 3 0|
|0 0 4 5|
|0 0 0 6|
int schur_complement_size = 1
|6|

int schur_complement_size = 2
|4 5|
|0 6|

int schur_complement_size = 3
|0 3 0|
|0 4 5|
|0 0 6|

int schur_complement_size = 4
|1 0 2 0|
|0 0 3 0|
|0 0 4 5|
|0 0 0 6|
现在,我需要从右下角获取如下值:

|1 0 2 0|
|0 0 3 0|
|0 0 4 5|
|0 0 0 6|
int schur_complement_size = 1
|6|

int schur_complement_size = 2
|4 5|
|0 6|

int schur_complement_size = 3
|0 3 0|
|0 4 5|
|0 0 6|

int schur_complement_size = 4
|1 0 2 0|
|0 0 3 0|
|0 0 4 5|
|0 0 0 6|

在不将矩阵转换为密集格式的情况下,有什么优雅的方法可以实现这一点吗?密集格式对我来说是一个很大的问题,因为我的程序实际使用的矩阵将非常大。

假设您无法更改稀疏矩阵的建模方式,您可以尝试以下方法:

  • 确保已订购行坐标(如您提供的示例所示)。注意,您也可以选择col_coords,您需要的是两个数组中的一个是有序的
  • 计算q=矩阵的阶数-子矩阵的阶数+1
  • 在排序数组(row_coords)中运行二进制搜索,以查找第一个元素row_coords[i]=q的索引
  • 现在,您可以使用3个新数组(您知道它们的最大大小)创建子矩阵,并仅当col_coords[i]>=q时添加一个元素

    子坐标系[j]=坐标系[i]-q+1; 子行坐标[j]=列坐标[i]-q+1; sub_VAL[j]=VAL[i]


对于您的任务,我已经编写了一个工作示例,如果您不介意的话,我已经使用std::vector作为输出,因为动态分配的内存管理可能会变得复杂:

// Example program
#include <iostream>
#include <vector>

void GetSubSparseMatrixLowerRight(int order_of_matrix , int pointCount, int * row_coords, int *col_coords, int * vals, int schur_complement_size, std::vector<int> &row_coordsOut, std::vector<int> &col_coordsOut, std::vector<int> &valsOut)
{
    int upperLeftRow = order_of_matrix - schur_complement_size;
    int upperLeftCol = order_of_matrix - schur_complement_size;

    for(int i=0; i<pointCount; i++)
    {
        if(row_coords[i] > upperLeftRow && col_coords[i] > upperLeftCol)
        {
            row_coordsOut.push_back(row_coords[i] - upperLeftRow);
            col_coordsOut.push_back(col_coords[i] - upperLeftCol);
            valsOut.push_back(vals[i]);
        }
    }
}
int main()
{
  int order_of_matrix = 4;

  int row_coords[] = {1,1,2,3,3,4};
  int col_coords[] = {1,3,3,3,4,4};
  int vals[]       = {1,2,3,4,5,6};

  int schur_complement_size = 4;

  std::vector<int> row_coordsOut;
  std::vector<int> col_coordsOut;
  std::vector<int> valsOut;

  GetSubSparseMatrixLowerRight(order_of_matrix , sizeof(row_coords)/sizeof(row_coords[0]), (int *)row_coords, (int *)col_coords, (int *) vals, schur_complement_size, row_coordsOut,col_coordsOut, valsOut);

  std::cout<<valsOut[0]<<" "<<row_coordsOut[0]<<" "<<col_coordsOut[0]<<std::endl; //to control the output
}
//示例程序
#包括
#包括
void GetSubSparseMatrixLowerRight(矩阵的整数阶、整数点计数、整数*行坐标、整数*列坐标、整数*VAL、整数schur_补码大小、标准::向量和行坐标、标准::向量和列坐标、标准::向量和列坐标
{
int upperLeftRow=矩阵的阶数-舒尔补大小;
int upperLeftCol=矩阵的阶数-舒尔补大小;
对于(int i=0;i upperLeftRow&&col\u coords[i]>upperLeftCol)
{
row_coordsOut.向后推(row_coords[i]-左上排);
col_coordsOut.向后推(col_coords[i]-upperLeftCol);
推回(vals[i]);
}
}
}
int main()
{
_矩阵的int阶_=4;
int row_coords[]={1,1,2,3,3,4};
int col_coords[]={1,3,3,4,4};
int vals[]={1,2,3,4,5,6};
int-schur\u补码大小=4;
std::向量行坐标;
std::矢量坐标;
std::向量输出;
GetSubparseMatrixlowerRight(矩阵的阶数,大小(行坐标)/大小(行坐标[0]),(int*)行坐标,(int*)列坐标,(int*)列坐标,(int*)VAL,schur_补码大小,行坐标,列坐标,VALUT);

std::cout如果存储非零项的方式没有特殊的结构,那么本质上唯一的算法就是对所有项进行迭代,将想要的项复制到一个新的矩阵中

校样草图:你必须检查所有的条目,否则你可能会错过一个相关条目;缺乏结构意味着你不能排除任何位置

(漏洞:如果您的格式不包含重复条目,并且您已经读取了足够多的条目以完全填充密集矩阵,则可以中止)

因为你无论如何都要阅读每一条条目,很难想象任何算法都能比通读它们并获取你想要的更好

可能允许更快算法的“特殊结构”的示例有:条目以排序顺序(按坐标按字典顺序)存储,或者可能以其他更灵活的顺序(例如,沿空间填充曲线)存储,从而更容易提取块,或者您保留辅助此操作的辅助数据结构



可能会有一个有趣的问题,即“我可以使用什么样的数据结构来简化此操作?”但这需要清楚地描述需求。(应该在不同的帖子中提问)我首先要做的是创建一个结构,这样你就不必为矩阵的不同部分保留相等大小的三个向量。然后,考虑现有矩阵中新矩阵的哪些部分以及元素是如何不同的。最后,决定一种语言,因为答案会有所不同。我必须使用几个数组,这就是使用它的方式。在我之前,我还没有完成这个项目。我已经在标题中插入了“C++”,所以现在它更具体了。我不理解“考虑”的部分-我只是想提取矩阵的“右下角”…索引非零值的行和列向量是否保证被排序?如果是,如何排序?这肯定会改变结果“非常优雅"解决方案优于蛮力方法,因为您可以进行二进制搜索以找到起点。对于大型稀疏矩阵,速度可能会显著加快。如果您想避免使用三种不同的动态分配向量的麻烦以及随之而来的内存管理负担,那就这样吧。无论如何,逻辑上您仍然有三元组行、列和值,无论您如何存储它们。我想让您考虑的是如何确定一个三元组是否是要从中提取的矩阵的一部分。然后,考虑在新矩阵中将使用哪个新的三元组。这对于大型数组来说,具有某种结构是必不可少的。如果只是因为在处理矩阵-但也因为它将显著减少主循环期间访问的元素数量,我担心在大型阵列的内存管理方面,
push_back
可能会变得非常低效-我建议预分配大约1/4N(+3*sqrt(N))要显著加快速度。否则,这确实概述了未排序输入的基本方法。@Floris当然,reserve()是一个不错的选择,但std::vector在到达其边界时以2的倍数保留此类空间。