【问题标题】:Linear index for a diagonal run of an upper triangular matrix上三角矩阵的对角线运行的线性索引
【发布时间】:2021-11-15 14:20:58
【问题描述】:

给定一个 NxN 矩阵,我想线性索引到它的右上三角形, 一个对角线一个对角线的模式,从主对角线开始。

例如,给定一个 4x4 矩阵

X 0 3 5
X X 1 4
X X X 2
X X X X

我正在寻找一个非递归(封闭形式)函数,将线性索引从 0 到 5 映射到 (x,y) 实现

f(0) = (0, 1)
f(1) = (1, 2)
f(2) = (2, 3)
f(3) = (0, 2)
f(4) = (1, 3)
f(5) = (0, 3)

与逐行运行相关:

【问题讨论】:

  • 你可能会想出一个从k到矩阵索引的算法。除了搜索,您还尝试过什么?
  • 你可以很容易地从你链接的行方法中得到这个:第二个坐标已经是正确的,你可以通过从第二个中减去第一个坐标来得到:(y,x) -> (x-1 -y,x)。

标签: c++ arrays numpy linear-algebra triangular


【解决方案1】:

我为您提供的数组和值创建了一个自定义方法。

int a[4][4] ={{-1, 0, 3, 5}, {-1, -1, 1, 4}, {-1, -1, -1, 2}, {-1, -1, -1, -1}};

代码就是这样的。你给数组,无论你给 Func 方法中的第二个值,上对角线中的值的索引都会到达你。

#include <iostream>

using namespace std;

int b[2] ={-1,-1};

int Func(int a[4][4],int n)
{
    
    for(int i =0;i<4;i++)
    {
        for(int j=0;j<4;j++)
        {
            if(a[i][j]==n)
            {
                if(i<j)
                {
                    b[0]=i;
                    b[1]=j;
                    return 0;
                }
            }
        }
    }
}
int main()
{
    int a[4][4] ={{-1, 0, 3, 5}, {-1, -1, 1, 4}, {-1, -1, -1, 2}, {-1, -1, -1, -1}};
    Func(a,5);
    for(int i=0;i<2;i++)
    {
        cout<<b[i]<<" ";
    }
    return 0;
}

感谢USEFUL 的反馈,如果它对你有用

【讨论】:

  • 感谢您的努力,但有一些事情我想引起您的注意。首先是 C++ 形式:不鼓励使用 C 字符串;例如Func 中的参数a 的类型为int (*)[4];这不会影响您的特定解决方案,因为您在任何地方都对矩阵大小进行了硬编码。全局变量的使用也是有问题的。
  • 关于这个解决方案的第二点:它在 N 上不是通用的(仅适用于 N 4),它具有 O(N^2) 空间复杂度和 O(n^2) 时间复杂度,实际上并没有提供所需的解决方案 - 从索引到坐标的映射函数;要拥有它,您需要另一个 O(n^2) 函数来在您的矩阵中搜索
  • @bolov 我同意你所说的一切。我开始考虑如何解决这个问题
  • @EminNiftiyev 感谢您抽出宝贵时间回答!我确实在寻找 N 上的通用函数 - 我的问题并不清楚,抱歉!
【解决方案2】:

也许有人可以想出一个不需要循环的数学公式,但在那之前我想出了一个O(N) 解决方案:

#include <utility>

constexpr std::pair<int, int> f(int n, int idx)
{
    int group_size = n - 1;
    int rest = idx + 1;

    while (rest > group_size)
    {
        rest = rest - group_size;
        --group_size;
    }
    return {(rest - 1) % group_size,
            n - group_size +  (rest - 1) % group_size};
}
/* 3x3
X 0 2
X X 1
X X X
*/
static_assert(f(3, 0) == std::pair{0, 1});
static_assert(f(3, 1) == std::pair{1, 2});
static_assert(f(3, 2) == std::pair{0, 2});

// 4x4
static_assert(f(4, 0) == std::pair{0, 1});
static_assert(f(4, 1) == std::pair{1, 2});
static_assert(f(4, 2) == std::pair{2, 3});
static_assert(f(4, 3) == std::pair{0, 2});
static_assert(f(4, 4) == std::pair{1, 3});
static_assert(f(4, 5) == std::pair{0, 3});

/* 5x5
X 0 4 7 9
X X 1 5 8
X X X 2 6
X X X X 3
X X X X X
*/
static_assert(f(5, 0) == std::pair{0, 1});
static_assert(f(5, 1) == std::pair{1, 2});
static_assert(f(5, 2) == std::pair{2, 3});
static_assert(f(5, 3) == std::pair{3, 4});
static_assert(f(5, 4) == std::pair{0, 2});
static_assert(f(5, 5) == std::pair{1, 3});
static_assert(f(5, 6) == std::pair{2, 4});
static_assert(f(5, 7) == std::pair{0, 3});
static_assert(f(5, 8) == std::pair{1, 4});
static_assert(f(5, 9) == std::pair{0, 4});

【讨论】:

  • 感谢您的回答!我现在有了封闭式答案。
【解决方案3】:

感谢@loopy-walt 的观察,我们有了答案! 使用来自Linear index upper triangular matrix 的结果,对结果进行转换

(i, j) |-> (j-i-1, j)

给出预期的结果。

这是一个 C++ 实现。

#include<tuple>
#include<cmath>

// Linear indexing of the upper triangle, row by row
std::tuple<size_t, size_t> k2ij(size_t n, size_t k){
  size_t i = n - 2 - (size_t)std::floor(std::sqrt(4*n*(n-1) - (8*k) -7)/2.0 - 0.5);
  size_t j = k + i + 1 - n*(n-1)/2 + (n-i)*((n-i)-1)/2;
  return {i,j};
}

// Linear indexing of the upper triangle, diagonal by diagonal
std::tuple<size_t, size_t> d2ij(size_t n, size_t d){
  const auto [i, j] = k2ij(n, d);
  return {j-i-1, j}; // Conversion from row by row to diag by diag
}

#include<iostream>
#include<set>
int main(int argc, char** argv) {

  size_t n = 4;
  size_t top = n*(n-1)/2;

  for(size_t d=0; d<top; ++d){
    const auto [i,j] = d2ij(n, d);
    std::cout << "d2ij(" << n << ", " << d << ") = (" << i << ", " << j << ")" << std::endl;
  }

  return 0;
}

制作

d2ij(4, 0) = (0, 1)
d2ij(4, 1) = (1, 2)
d2ij(4, 2) = (2, 3)
d2ij(4, 3) = (0, 2)
d2ij(4, 4) = (1, 3)
d2ij(4, 5) = (0, 3)

注意:如果有人希望改用 f(d) 形式,则可以使用 lambda 来捕获维度“n”

auto f = [n](size_t d){return d2ij(n, d);};
const auto [i,j] = f(5);

感谢所有花时间阅读和帮助的人!

【讨论】:

    【解决方案4】:

    所以你想要以下函数的反函数

    • 元素 [i,j] 的从零开始的索引形式,用于包含对角线的 n×n 上三角矩阵

      index = i*n-i*(i+1)/2+j
      
      i=0..4, j=0..4, index=
      |  0 |  1 |  2 |  3 |  4 |
      |  X |  5 |  6 |  7 |  8 |
      |  X |  X |  9 | 10 | 11 |
      |  X |  X |  X | 12 | 13 |
      |  X |  X |  X |  X | 14 |
      

    我能想到的最简单的算法是循环 i 的所有行并查看 j 列是否匹配,这样:

    • i &lt;= j
    • j&gt;=0
    • j&lt;n

    这是给出indexn的示例代码

    for(i=0; i<n; i++)
    {
        j = index - i*n + i*(i+1)/2
        if( j>=0 && j<n && j>= i)
        {
           break;
        }
    }
    

    n=7[i,j]=[1,5] 的示例产生 index=11。现在这个索引的坐标是

    i j i&lt;=j &amp;&amp; j&gt;=0 &amp;&amp; j&lt;7
    0 11
    1 5 valid
    2 0
    3 -4
    4 -7
    5 -9
    6 -10

    如果你想要严格的上三角元素,那么不包括对角线

    • 元素 [i,j] 的从零开始的索引形式,用于不包括对角线的 n×n 上三角矩阵

      index = i*n-i*(i+3)/2+j-1
      
      i=0..3, j=0..4, index=
      |  X |  0 |  1 |  2 |  3 |
      |  X |  X |  4 |  5 |  6 |
      |  X |  X |  X |  7 |  8 |
      |  X |  X |  X |  X |  9 |
      |  X |  X |  X |  X |  X |
      

    现在的算法是循环所有行 i 并查看列 j 是否匹配,这样:

    • i &lt; j
    • j&gt;0
    • j&lt;n

    这是给出indexn的示例代码

    for(i=0; i<n; i++)
    {
        j = index - i*n + i*(i+3)/2 + 1
        if( j>0 && j<n && j>i)
        {
           break;
        }
    }
    

    n=7[i,j]=[1,5] 的示例产生 index=9。现在这个索引的坐标是

    i j i&lt;j &amp;&amp; j&gt;0 &amp;&amp; j&lt;7
    0 10
    1 5 valid
    2 1
    3 -2
    4 -4
    5 -5

    【讨论】:

    • 感谢您抽出宝贵时间回答。不幸的是,我正在寻找一个不同问题的封闭形式(即没有递归和没有循环):对角线逐对角线运行而不是逐行运行。
    猜你喜欢
    • 2015-01-21
    • 1970-01-01
    • 1970-01-01
    • 2022-01-11
    • 2014-12-11
    • 2019-10-04
    • 1970-01-01
    • 2016-06-02
    • 2023-03-25
    相关资源
    最近更新 更多