I have an indexing issue that I am trying to solve. I have a n-dimensional array with known shape. I would like to traverse the array with a stride (possibly different in each dim).
我有一个索引问题,我试图解决。我有一个已知形状的n维阵列。我想以一个步幅(每个暗淡可能不同)遍历数组。
With fixed dimensions, I would do this with nested for loops (small arrays) and increment by the stride:
对于固定的维度,我会使用嵌套for循环(小数组)并按步幅递增:
std::vector<int> shape = {10, 10}; // h,w
int num_dim = shape.size();
std::vector<int> stride = {1,2};
for (int i = 0; i< shape[0]; i+=stride[0]) {
for (int j = 0; j< shape[1]; j+=stride[1]) {
//print flattened index (row major)
printf("index: %d\n",i*shape[0]+j);
}
}
But how would I do this with an n-dimensional array (flattened)? I.e. something like:
但是我如何使用n维数组(展平)呢?即就像是:
std::vector<int> shape = {10, 10}; // h,w
int num_dim = shape.size();
std::vector<int> stride = {1,2};
int shape_size = 1;
for (int i = 0; i< num_dim; ++i) {
shape_size *= shape[i];
}
int ind = 0;
while (ind < shape_size) {
// somehow incr ind by the correct amount according to stride, and shape
// or check if the ind is in the stride (less desirable)
}
2 个解决方案
#1
class Foo {
public:
std::vector<int> shape = { 10, 10 }; // h,w
std::vector<int> stride = { 1, 2 };
std::vector<int> d = { 0, 0 };
bool add_end = false;
void AddStride(int index) {
d[index] += stride[index];
if (d[index] < shape[index]) {
return;
} else {
if (index == 0) {
add_end = true;
return;
}
d[index] = 0;
index--;
AddStride(index);
}
}
bool AddStride() {
AddStride(d.size() - 1);
}
};
int main() {
Foo f;
while(f.add_end != true) {
//do something
f.AddStride();
}
}
#2
class Traverse {
private:
unsigned m_numDim;
std::vector<unsigned int> m_vShape;
std::map<unsigned int, unsigned int> m_mStrides;
public:
Traverse( const std::vector<unsigned int>& shape, const std::vector<unsigned int>& strides );
std::vector<unsigned int>& traverse();
}; // Traverse
// ---------------------------------------------------------------
// Traverse()
Traverse::Traverse( const std::vector<unsigned int>& shape, const std::vector<unsigned int>& strides ) {
if ( shape.empty() || strides.empty() ) {
return;
}
m_vShape = shape;
m_numDim = m_vShape.size();
// Here Use The Passed In Vector Of Known Strides To Create Your Map As
// An Association For Each Dimension With Its Stride
for ( unsigned index = 0; index < strides.size(); index++ ) {
m_mStrides[index+1] = strides[index];
}
} // Traverse
// ----------------------------------------------------------------
// traverse()
std::vector<unsigned int>& Traverse::traverse() {
std::vector<unsigned int> vTemp;
for ( unsigned index = 0; index < m_numDim; ++index ) {
// Use Your Map Against Your Stored Shape Vector To Do The Traversing.
}
return vTemp; // Or m_vShape;
} // traverse
Here m_mStrides is easy to work with knowing that m_mStrides.first = Which Dimension and m_mStrides.second = The Stride in that Dimension.
在这里,m_mStrides很容易知道m_mStrides.first =哪个Dimension和m_mStrides.second =该Dimension中的Stride。
This is not a complete working class but just an illustration to get you started. I also choose to use unsigned int rather then ints because when dealing with shape's sizes, dimensions and strides negative numbers doesn't make sense, however if you are using existing code that is already preformatted using int would be okay, but I would suggest doing error or bounds checking for negatives.
这不是一个完整的工人阶级,只是一个让你入门的插图。我也选择使用unsigned int而不是int,因为在处理shape的大小时,尺寸和步幅负数没有意义,但是如果你使用已经使用int预先格式化的现有代码就可以了,但我建议你这样做错误或边界检查否定。
#1
class Foo {
public:
std::vector<int> shape = { 10, 10 }; // h,w
std::vector<int> stride = { 1, 2 };
std::vector<int> d = { 0, 0 };
bool add_end = false;
void AddStride(int index) {
d[index] += stride[index];
if (d[index] < shape[index]) {
return;
} else {
if (index == 0) {
add_end = true;
return;
}
d[index] = 0;
index--;
AddStride(index);
}
}
bool AddStride() {
AddStride(d.size() - 1);
}
};
int main() {
Foo f;
while(f.add_end != true) {
//do something
f.AddStride();
}
}
#2
class Traverse {
private:
unsigned m_numDim;
std::vector<unsigned int> m_vShape;
std::map<unsigned int, unsigned int> m_mStrides;
public:
Traverse( const std::vector<unsigned int>& shape, const std::vector<unsigned int>& strides );
std::vector<unsigned int>& traverse();
}; // Traverse
// ---------------------------------------------------------------
// Traverse()
Traverse::Traverse( const std::vector<unsigned int>& shape, const std::vector<unsigned int>& strides ) {
if ( shape.empty() || strides.empty() ) {
return;
}
m_vShape = shape;
m_numDim = m_vShape.size();
// Here Use The Passed In Vector Of Known Strides To Create Your Map As
// An Association For Each Dimension With Its Stride
for ( unsigned index = 0; index < strides.size(); index++ ) {
m_mStrides[index+1] = strides[index];
}
} // Traverse
// ----------------------------------------------------------------
// traverse()
std::vector<unsigned int>& Traverse::traverse() {
std::vector<unsigned int> vTemp;
for ( unsigned index = 0; index < m_numDim; ++index ) {
// Use Your Map Against Your Stored Shape Vector To Do The Traversing.
}
return vTemp; // Or m_vShape;
} // traverse
Here m_mStrides is easy to work with knowing that m_mStrides.first = Which Dimension and m_mStrides.second = The Stride in that Dimension.
在这里,m_mStrides很容易知道m_mStrides.first =哪个Dimension和m_mStrides.second =该Dimension中的Stride。
This is not a complete working class but just an illustration to get you started. I also choose to use unsigned int rather then ints because when dealing with shape's sizes, dimensions and strides negative numbers doesn't make sense, however if you are using existing code that is already preformatted using int would be okay, but I would suggest doing error or bounds checking for negatives.
这不是一个完整的工人阶级,只是一个让你入门的插图。我也选择使用unsigned int而不是int,因为在处理shape的大小时,尺寸和步幅负数没有意义,但是如果你使用已经使用int预先格式化的现有代码就可以了,但我建议你这样做错误或边界检查否定。