【问题标题】:Nested loops: permuting an n-dimensional array represented by a vector嵌套循环:置换由向量表示的 n 维数组
【发布时间】:2017-01-20 22:19:02
【问题描述】:

我有一个n 维数组T,其中每个维度的长度相同L。该数组由一维向量v 表示(可以看作是T 的“重塑”版本,因此v 的长度为L^n)。

以下示例显示如何根据T(其中n = 3L = 4)的索引对v 进行索引:

(例如T(0,3,2) = v[14]

我想做的是创建一个向量u,它代表一个n维数组S,其中S是通过将T置换/旋转1获得的,即

T(i1,i2,...,in) = S(i2,i3,...,in,i1) 用于任何(i1,i2,...,in)

(当T为矩阵时,S对应T的转置)。

更新:

以下代码可能更好地解释我的问题:

void permute(vector<double> &output, const vector<double> &v, int L)
{
    int n = log(v.size())/log(L);

    // Suppose that we have a function doing this
    narray T = get_narray_from_vector(v, L);

    // Get the permutation of T
    narray S(T.size());
    for(int i1 = 0; i1 < L; i1++){
        for(int i2 = 0; i2 < L; i2++){
            ...
            for(int in = 0; in < L; in++){
                S(i2,i3,...,in,i1) = T(i1,i2,...,in);
            }
        }
    }

    // get vector from narray
    output.resize(v.size());
    int idx = 0;   
    for(int i1 = 0; i1 < L; i1++){
        for(int i2 = 0; i2 < L; i2++){
            ...
            for(int in = 0; in < L; in++){
                output[idx] = S(i1,i2,...,in);
                idx++;
            }
        }
    }   
}

然而,在实践中,我认为直接使用向量会更好。因此,我会做这样的事情:

void permute(vector<double> &output, const vector<double> &v, int L)
{
    int n = log(v.size())/log(L);
    output.resize(v.size());

    // Get the permutation
    for(int i1 = 0; i1 < L; i1++){
        for(int i2 = 0; i2 < L; i2++){
            ...
            for(int in = 0; in < L; in++){
                output[i2*pow(L, n-1) + i3*pow(L, n-2) + ... + in*L + i1] = v[i1*pow(L, n-1) + i2*pow(L, n-2) + ... + i_{n-1}*L + in];
            }
        }
    } 
}

这里的难点在于嵌套循环,因为n是一个参数。

任何想法如何做到这一点? 预先感谢您的帮助!!

【问题讨论】:

  • 你的问题不是很清楚。你有什么尝试?假设i1i2 等代表“列”,您想删除第一列,将所有其他列随机排列,然后将(删除的)第一列添加为最后一列? (注意:在多维数组的上下文中,“转置”这个词有一个特殊的含义,这似乎与您使用该词的含义不同)。
  • 需要用这种方式将T存入vector吗?我的第一个倾向是将其存储为扩展为 n 维的“数组数组”,然后(我认为)您所要求的只需要将顶级数组移动一个索引
  • 另外,在你的例子中,每个维度的长度似乎都是 4 (0, 1, 2, 3) 而你说 L=3
  • 完全跑题了:@Nic 向量的向量和数组的数组由于空间局部性差而具有潜在的显着性能损失。
  • @user4581301 在许多(可能是大多数)情况下都是如此,但这取决于对矩阵所做的事情。例如,如果这是唯一需要实现的操作,您可以通过简单地移动指针数组而不是移动整个矩阵中的所有数据来节省内存访问的数量级

标签: c++ arrays algorithm loops


【解决方案1】:

这是一个不需要 n 嵌套 for 循环的解决方案。

首先,我有一些旧代码将数字分解为基于L 的数字系统。

std::vector<int>
num2base(const int value,
         const unsigned int base){

  // Represents an input int VALUE in a new BASE-based number system                                                                                                    
  // n = a0*b^0 + a1*b^1 + ...                                                                                                                                          

  std::vector<int> base_representation;
  unsigned int num_digs = (unsigned int) (floor(log(value)/log(base))+1);
  base_representation.resize(num_digs);

  for (unsigned int i_dig = 0; i_dig < num_digs; i_dig++){
    base_representation[i_dig] =
      ((value % (int) pow(base,i_dig+1)) - (value % (int) pow(base, i_dig))) /
      (int) pow(base, i_dig);
  }

  return base_representation;
}

换句话说,这是一种将单值索引idx 转换为i1in n-元组索引的方法。

idx = i1*L^0 + i2*L^1 + ... in*L^(n-1)

这是另一种方式的代码

int
base2num(const std::vector<int> base_representation,
         const unsigned int base){

  unsigned int digit_val = 1;

  int value = 0;

  for (unsigned int digit = 0; digit < base_representation.size(); digit++){
    value += base_representation[digit]*digit_val;
    digit_val *= base;
  }

  return value;
}

一旦有了代表n-tuple 索引的std::vector&lt;int&gt;,就很容易置换它。

void
permute_once(std::vector<int> &base_representation){

  std::vector<int>::iterator pbr = base_representation.begin();
  int tmp = *pbr;
  base_representation.erase(pbr);
  base_representation.push_back(tmp);

  return;
}

所以,要生成新的n维数组S

  1. 遍历idxS 的每个索引S

  2. idxS 转换为n-元组(iS1iS2,...,iSn

  3. T及其n-tuple(iT1iT2、...、iTn)中查找关联条目

  4. 将其转换为单个索引idxT

  5. u[idxS] = v[idxT];

【讨论】:

  • 谢谢。这也是一种方法。
猜你喜欢
  • 2023-04-01
  • 2016-11-06
  • 1970-01-01
  • 2016-12-09
  • 2021-01-29
  • 1970-01-01
  • 2016-10-18
  • 2016-04-04
相关资源
最近更新 更多