How to choose specific row and column indices in C++ Eigen Array? - c++

I wonder how it is possible to choose specific elements in Eigen Array given lists of indices for rows and columns. For example:
array = [[1, 2, 3],
[4, 5, 6],
[7, 8, 9]]
rowIndices = [0, 1, 2]
colIndices = [0, 1, 2]
expectedResult = [1, 5, 9]
I tried something similar to this but didn't get the expected result.
std::vector<int> indices = {0, 1, 2};
array(indices, indices);

Related

Eigen MatrixXi to VectorXi conversion

I have a MatrixXi, say
[0, 1, 2]
[0, 2, 3]
[4, 7, 6]
[4, 6, 5]
[0, 4, 5]
[0, 5, 1]
[1, 5, 6]
I get a part of it by doing:
MatrixXi MR = F.middleRows(first, last);
with first and last at will. Now I'd like to turn those n rows into a column VectorXi, like:
[0,
1,
2,
0,
2,
3]
possibly without using a for loop. I've tried:
VectorXi VRT(MR.rows() * MR.cols());
VRT.tail(MR.rows() * MR.cols()) = MR.array();
But I get:
Assertion failed: (rows == this->rows() && cols == this->cols() && "DenseBase::resize() does not actually allow to resize."), function resize, file /Users/max/Developer/Stage/Workspace/AutoTools3D/dep/libigl/external/eigen/Eigen/src/Core/DenseBase.h, line 257.
How do I get that? I'm using Eigen before v4 so I cannot use reshape...
Thank you
As pointed out by chtz, this works:
Eigen::VectorXi VR(MR.size());
Eigen::MatrixXi::Map(VR.data(), MR.cols(), MR.rows()) =
MR.transpose();

Writting in sub-ndarray of a ndarray in the most pythonian way. Python 2

I have a ndarray like this one:
number_of_rows = 3
number_of_columns = 3
a = np.arange(number_of_rows*number_of_columns).reshape(number_of_rows,number_of_columns)
a
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
But I want something like this:
array([[0, 100, 101],
[3, 102, 103],
[6, 7, 8]])
To do that I want to avoid to do it one by one, I rather prefer to do it in arrays or matrices, because later I want to extend the code.
Nothe I have change a submatrix of the initial matrix (in mathematical terms, in terms of this example ndarray). In the example the columns considered are [1,2] and the rows [0,1].
columns_to_keep = [1,2]
rows_to_keep = [0,1]
My first try was to do:
a[rows_to_keep,:][:,columns_to_keep] = np.asarray([[100,101],[102,103]])
However this doesn't modify the initial a, I am not having any error, so a=
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
So I have implemented a piece of code that goes do the job:
b = [[100, 101],[102, 103]]
for i in range(len(rows_to_keep)):
a[i,columns_to_keep] = b[i]
Al thought the previous lines do the job I am wondering how to do it slicing and in a faster fashion. Also in a way that with:
columns_to_keep = [0,2]
rows_to_keep = [0,2]
the desired output is
array([[100, 1, 101],
[3, 4, 5],
[102, 7, 103]]).
Many thanks!
Indexing with lists like [1,2] is called advanced indexing. By itself it produces a copy, not a view. You have to use one indexing expression, not two to assign or change values. That is a[[1,2],:] is a copy, a[[1,2],:][:,[1,2]] += 100 modifies that copy, not the original a.
In [68]: arr = np.arange(12).reshape(3,4)
Indexing with slices; this is basic indexing:
In [69]: arr[1:,2:]
Out[69]:
array([[ 6, 7],
[10, 11]])
In [70]: arr[1:,2:] += 100
In [71]: arr
Out[71]:
array([[ 0, 1, 2, 3],
[ 4, 5, 106, 107],
[ 8, 9, 110, 111]])
Doing the same indexing with lists requires arrays that 'broadcast' against each other. ix_ is a handy way of generating these:
In [73]: arr[np.ix_([1,2],[2,3])]
Out[73]:
array([[106, 107],
[110, 111]])
In [74]: arr[np.ix_([1,2],[2,3])] -= 100
In [75]: arr
Out[75]:
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
Here's what ix_ produces - a tuple of arrays, one is (2,1) in shape, the other (1,2). Together they index a (2,2) block:
In [76]: np.ix_([1,2],[2,3])
Out[76]:
(array([[1],
[2]]), array([[2, 3]]))
For the continuous rows and columns case, you can use basic slicing like this:
In [634]: a
Out[634]:
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
In [635]: b = np.asarray([[100, 101],[102, 103]])
In [636]: a[:rows_to_keep[1]+1, columns_to_keep[0]:] = b
In [637]: a
Out[637]:
array([[ 0, 100, 101],
[ 3, 102, 103],
[ 6, 7, 8]])

How to average sub arrays in Numpy using broadcasting?

If there is a numpy array that is a list of 2d arrays, is there more efficient way than calling the mean function twice?
z = np.array([[[0, 0, 0],
[10, 10, 10]],
[[0, 0, 0],
[5, 5, 5]],
[[0, 0, 0],
[2, 2, 2]]])
print(z.mean(axis=2).mean(axis=1))
>[ 5. 2.5 1. ]

When changing data inside a list using a for loop, how do you append the list to a dictionary each time the loop iterates?

Basically, wanted to iterate over a list of numerical data to change it's contents, where the numerical at the start of the list is moved to the last, and then the data is shifted to the left. Whilst I have achieved this, as the printed contents of the loop gives the desired results, when trying to append the contents of said loop to said dictionary, it only does this for the final iteration. Here's my code:
minor=[1,2,3,4,5,6]
MNP = {'scale degree' : []
}
def patterns(scale):
for i in scale:
print (scale)
scale.insert(len(scale),scale[0])
del(scale[0])
MNP['scale degree'].append(scale)
using the function patterns, this is the output:
>>> patterns(minor)
the list, minor, is at the top of the page by the way.
output:
[1, 2, 3, 4, 5, 6]
[2, 3, 4, 5, 6, 1]
[3, 4, 5, 6, 1, 2]
[4, 5, 6, 1, 2, 3]
[5, 6, 1, 2, 3, 4]
[6, 1, 2, 3, 4, 5]
Yet when I try to print the contents of the list, scale degree, in the MNP dict, the result is:
MNP['scale degree']
[[1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6]]
I am very perplexed by this result, it's as if the output changes depending on the operation called upon it?
Thank you for any help in advance. It's also worth noting that I've been stuck with this for a good amount of time, so if there's any resources out there that may help me understand similar occurrences i certainly wouldn't pass that up.
The reason this happens is because what you store in MNP['scale degree'] is only a reference to scale. So when you change scale, so do the entries in MNP['scale degree']. What you need to do to avoid this is copying scale each time you append it (i.e. creating a new list instead of adding a reference). You can do this with the copy module:
import copy
minor=[1,2,3,4,5,6]
MNP = {'scale degree' : []
}
def patterns(scale):
for i in scale:
print (scale)
scale.insert(len(scale),scale[0])
del(scale[0])
MNP['scale degree'].append(copy.copy(scale))
patterns(minor)
print(MNP['scale degree'])

Creating lists from elements in a bigger list

I have a list whose size is a multiple of 16. What I want to do is go through the list and get 16 elements and create a list from those values, and then store those values somewhere. After that I can either ignore them or remove them from the list, and continue this process until the bigger list is empty. What I was trying to do was to go through the list, and keep a counter of some sort to keep track of the number of elements that have been appended to the list. However, I have been stuck from there. Any ideas on how to accomplish on what I am trying to do? Any ideas would be greatly appreciated.
lst = [[1, 4, 0], [2, 4, 0], [3, 4, 0], [4, 4, 0], [1, 3, 0], [2, 3, 0], [3, 3, 0], [4, 3, 0], [1, 2, 0], [2, 2, 0], [3, 2, 0], [4, 2, 0], [1, 1, 0], [2, 1, 0], [3, 1, 0], [4, 1, 0],[1, 4, 0], [2, 4, 0], [3, 4, 0], [4, 4, 0], [1, 3, 0], [2, 3, 0], [3, 3, 0], [4, 3, 0], [1, 2, 0], [2, 2, 0], [3, 2, 0], [4, 2, 0], [1, 1, 0], [2, 1, 0], [3, 1, 0], [4, 1, 0]]
If I understand you correctly, you start with a list of size n, where n % 16 == 0. You want to end with n/16 lists of size 16. You can accomplish this pretty easily with a double for loop. The outer loop should go for n/16 iterations. the inner loop should go for 16 iterations. The outer loop creates a new list with each iteration. the inner loop takes elements from the original list and appends them to the newly created list.
Thank you for taking the time to respond to my question. After clicking on random links on the right hand side I came to answer that did exactly what I needed to happen.
Here is the solution to my problem:
[input[i:i+n] for i in range(0, len(input), n)]
The solution above goes through input and creates a list of size n.