Indexing Matrix in Boost - c++

I am a python programmer, and I am trying to understand boost.
Here is what I got:
>>> import numpy as np
>>> a
array([[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8],
[ 9, 10, 11]])
>>> b
array([[20, 21, 22],
[23, 24, 25]])
>>> a[[0,2]] = b
>>> a
array([[20, 21, 22], # first row of b
[ 3, 4, 5],
[23, 24, 25], # second row of b
[ 9, 10, 11]])
I can do this using boost:
#include <iostream>
#include <boost/numeric/ublas/matrix.hpp>
#include <boost/numeric/ublas/io.hpp>
using namespace std;
int main()
{
using namespace boost::numeric::ublas;
matrix<double> a (4, 3);
for (unsigned i = 0; i < a.size1 (); ++ i)
for (unsigned j = 0; j < a.size2 (); ++ j)
a (i, j) = a.size2() * i + j;
matrix<double> b (2,3);
for (unsigned i = 0; i < b.size1 (); ++ i)
for (unsigned j = 0; j < b.size2 (); ++ j)
b (i, j) = b.size2() * i + j + 20;
cout << "matrix a : " << a << endl;
cout << "matrix b : " << b << endl;
// replace row 0 in a with row 0 in b
// replace row 2 in a with row 1 in b
unsigned rows[] = {0,2};
int length = sizeof(rows) / sizeof(rows[0]);
for(int i = 0; i < length; i++)
for(int j = 0; j < a.size2(); j++)
a(rows[i], j) = b(i, j);
cout << "matrix a : " << a << endl;
return 0;
}
However, I am not sure whether this is the best way to do it. Looking at the documentation I did not see a built in method for indexing, so it looks like looping is the only option, am I missing anything?
However, looping in C++ might not be that bad. Looping in python in python is slow, and my above example looping takes place at the C level. But looping is not slow in C++, and hence even if we have to manually loop, the code is still efficient is that correct?
Please let me know if my understanding is correct and/or I am missing a better way to implement the above.

Boost.MultiArray is better suited for this sort of indexing. Your Python example can be reproduced as follows:
// helper type for a 2d matrix of ints
using array_type = boost::multi_array<int, 2>;
array_type a(boost::extents[4][3]); // 4x3 matrix
array_type b(boost::extents[2][3]); // 2x3 matrix
Now fill these matrices
std::iota(a.data(), a.data() + a.num_elements(), 0);
std::iota(b.data(), b.data() + b.num_elements(), 20);
Then define a lambda function that'll print a 2d matrix, so we can see the contents
auto array_printer = [](array_type const& arr) {
for(auto const &row : arr) {
for(auto const& elem : row) {
std::cout << std::setw(2) << elem << ' ';
}
std::cout << '\n';
}
std::cout << '\n';
};
Let's print what we have so far
std::cout << "Before:\na =\n";
array_printer(a);
std::cout << "b =\n";
array_printer(b);
Output:
Before:
a =
0 1 2
3 4 5
6 7 8
9 10 11
b =
20 21 22
23 24 25
Time to create a 2d view of the array
using range_type = boost::multi_array_types::index_range;
using view_type = array_type::array_view<2>::type;
// Create a 2d view of a
// - the rows of the view consist of rows [0, 3) with a stride of 2
// - the columns of the view consist of all columns of a
view_type a_view = a[boost::indices[range_type(0,3,2)][range_type()]];
Now assign b to the view we created, and print the result
a_view = b;
std::cout << "After:\na =\n";
array_printer(a);
Output:
After:
a =
20 21 22
3 4 5
23 24 25
9 10 11
Live demo

Related

How can I sort only some parts of the array in a specific order in c++?

So let's assume I have an array array{12, 10, 10, 9, 8, 8, 8} in descending order.
I want to sort the numbers that can be divided by 2 but not with 4 in ascending order at the end of the array, the numbers that are divided by 4 sorted at the start of the array in descending order and the rest in the middle(no specific order). For my example, after the transformation it should look something like this:
array{12, 8, 8, 8, 9, 10, 10}. Is there any way I can do this efficiently? c++ language.
Sorry for any misspelling.
Let's organize the requirement.
The required order is:
Numbers that are divided by 4
Others
Numbers that can be divided by 2 but not with 4
Among the numbers with same priority according to the above rule, the numbers should be
Descending order
No specific order
Ascending order
Let's implement this:
#include <iostream>
#include <vector>
#include <algorithm>
void test(std::vector<int> array) { // intensionally passed by value
std::cout << "before sorting:";
for (int v : array) std::cout << ' ' << v;
std::cout << '\n';
std::sort(array.begin(), array.end(), [](int a, int b) -> bool {
int pa, pb; // priority a/b
if (a % 4 == 0) pa = 1;
else if (a % 2 == 0) pa = 3;
else pa = 2;
if (b % 4 == 0) pb = 1;
else if (b % 2 == 0) pb = 3;
else pb = 2;
// if the priority differs, sort according to the priority
if (pa != pb) return pa < pb;
// if both can be divided by 4, sort in descending order
if (pa == 1) return b < a;
// if both can be divided by 2 but not with 4, sort in ascending order
if (pa == 3) return a < b;
// no specific order for the rest
return false;
});
std::cout << "after sorting:";
for (int v : array) std::cout << ' ' << v;
std::cout << '\n';
}
int main(void) {
std::vector<int> array = {12, 10, 10, 9, 8, 8, 8};
std::vector<int> array2 = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
test(array);
std::cout << '\n';
test(array2);
return 0;
}
Example output:
before sorting: 12 10 10 9 8 8 8
after sorting: 12 8 8 8 9 10 10
before sorting: 10 9 8 7 6 5 4 3 2 1
after sorting: 8 4 9 7 5 3 1 2 6 10
As an alternative to MikeCAT's fine answer, C++20 adds a variation of sort which accepts a projection, i.e. a function to apply to each element before we pass it to the comparison functor.
This utilises the fact that std::tuple has a predefined < that orders the tuple by each member in turn.
#include <iostream>
#include <vector>
#include <algorithm>
std::tuple<int, int> my_order(int val) {
if (val % 4 == 0) return { 1, -val };
else if (val % 2 == 0) return { 3, val };
else return { 2, 0 };
}
void test(std::vector<int> array) { // intensionally passed by value
std::cout << "before sorting:";
for (int v : array) std::cout << ' ' << v;
std::cout << '\n';
std::ranges::sort(array.begin(), array.end(), std::ranges::less{}, my_order);
std::cout << "after sorting:";
for (int v : array) std::cout << ' ' << v;
std::cout << '\n';
}
int main(void) {
std::vector<int> array = {12, 10, 10, 9, 8, 8, 8};
std::vector<int> array2 = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
test(array);
std::cout << '\n';
test(array2);
return 0;
}

In C++, how can I write a function that flips a 2d array at a specified position?

For my 2d array in C++, the 2d array needs to be flipped at a certain position. I have to write a function that flips the array
Foe instance,
Before:
double A[][2] = {{0,0}, {1,1}, {2,2}, {3,3}, {4,4}, {5,5}, {6,6}, {7,7}}
A B C D
call function invert(or flip): invert(A, 8, 3, 4);
after:
double A[][2] = { {0, 0}, {1, 1}, {2, 2},{6, 6}, {5, 5}, {4, 4}, {3, 3}, {7, 7}}
D C B A
Here is the attempt I have tried
#param A is the list of locations (x,y) of the cities in the current tour.
#param n is the number of cities in A.
#param start is the index of the beginning of the section to be inverted.
#param len is the length of the segment to invert(or flip).
void invert ( double A[][2], int n, int start, int len ) {
int(*tmp)[2] = new int[][2];
for(int i = 0; i >= A.length; i--){
for(int j = 0; j >= A[i].length; j--){
if( i > start)
tmp = A[i][j];
}
}
for(i = start; i < A.length; i++)
for(j = start; j < A[i].length; j++){
while (i <= end){
tmp = A[i][j];
}
}
}
The errors I have are
expressions must have class type
a value of type double cannot be assigned to an entity of type "double(*)[2]
cannot determine which instance of overload function "end" is intended
I am fully aware that most of the errors in my code are evident to find, but I needed to start somewhere.
I admit, I don't know how to do it with a 2D C-array. I can only tell you about the simple way to do it.
First, a general advice: Name your stuff. What if I had to read only your code to see that you are dealing with locations of cities, that have x and y coordinates, instead of having to read your text, wouldn't that be great?
Next, for resizable arrays, you can (/should) use std::vector instead of C-arrays. C-arrays decay to pointers when passed to functions. C-arrays have their size as part of their type, but it is inconvenient to access it (and impossible once decayed to a pointer). And manually resizing dynamic C-arrays isn't much fun either.
Eventually, the "simple way" is to use an existing algorithm. To reverse elements in a range it is std::reverse:
#include <iostream>
#include <vector>
#include <algorithm>
struct location {
int x;
int y;
};
int main() {
std::vector<location> cities{{0,0}, {1,1}, {2,2}, {3,3}, {4,4}, {5,5}, {6,6}, {7,7}};
for (const auto& loc : cities){
std::cout << loc.x << " " << loc.y << "\n";
}
std::cout << "\n";
std::reverse(cities.begin()+ 3,cities.begin() + 7);
for (const auto& loc : cities){
std::cout << loc.x << " " << loc.y << "\n";
}
}
Output:
0 0
1 1
2 2
3 3
4 4
5 5
6 6
7 7
0 0
1 1
2 2
6 6
5 5
4 4
3 3
7 7
Actually with a 1-D c-array it is almost the same. The major difference is that c-arrays do not have begin as member. This produces same output as above:
location cities2[] = {{0,0}, {1,1}, {2,2}, {3,3}, {4,4}, {5,5}, {6,6}, {7,7}};
for (const auto& loc : cities2){
std::cout << loc.x << " " << loc.y << "\n";
}
std::cout << "\n";
std::reverse(std::begin(cities2)+ 3,std::begin(cities2) + 7);
for (const auto& loc : cities2){
std::cout << loc.x << " " << loc.y << "\n";
}
And if you want to wrap it in a function you need to take care of the array decaying to a pointer:
void my_reverse(location* loc, size_t len, size_t first, size_t last){
std::reverse(loc + first, loc + last + 1);
}
(I choose last to be the last element to be reversed. Note that the algorithm takes an iterator to the element one past the last element to be reversed).
Complete example with all three variants: https://godbolt.org/z/WMdea7WP3
That's how I'd write the function if I knew it would always be used with 2 column arrays
void invert(double cities[][2], int size, int start, int len) {
if (size < 0 || len < 0)
return;
double tempCoordsX, tempCoordsY;
int endPos = start + len - 1;
for (int i = start; i < (start + len/2); i++) {
int mirroredPos = (endPos - (i - start)) % size;
tempCoordsX = cities[i][0];
tempCoordsY = cities[i][1];
cities[i][0] = cities[mirroredPos][0];
cities[i][1] = cities[mirroredPos][1];
cities[mirroredPos][0] = tempCoordsX;
cities[mirroredPos][1] = tempCoordsY;
}
}
I repeat: please name your stuff

C++ fftw3: compute fft of the matrix rows stored as an 1D array

I'm trying to figure out, how can I calculate fft row by row of the following matrix (stored as an array) using fftw3:
double signal[9] = {
1, 2, 3,
4, 5, 6,
7, 8, 9
}
to obtain the matrix with rows (pseudo-code)
fft([signal[0], signal[1], signal[2]])
fft([signal[3], signal[4], signal[5]])
fft([signal[6], signal[7], signal[8]])
I can check the result using Python just applying np.fft.fft([[1, 2, 3], [4, 5, 6], [7, 8, 9]], axis=1) and I want to get the same result with fftw3.
My code:
#include <fftw3.h>
#include <iostream>
int main()
{
// it is needed to compute fft row-by-row of the following matrix
double signal[9] {
1, 2, 3,
4, 5, 6,
7, 8, 9
}; // 3x3 matrix
// so that the output will have the form (pseudo-code)
// fft(signal[0], signal[1], signal[2])
// fft(signal[3], signal[4], signal[5])
// fft(signal[6], signal[7], signal[8])
fftw_complex result[9]{ };
// prepare parameters
int rank = 1;
int n[] = { 3 };
int howmany = 3;
int idist = 3;
int odist = 3;
int istride = 1;
int ostride = 1;
auto plan_ = fftw_plan_many_dft_r2c(
rank, // 1D problem
n, // 1D transforms of length n[0] = 3
howmany, // 3 1D transforms
signal, // input matrix (array)
NULL, // will be assigned to n
istride, // distance between two elements in the same row
idist, // distance between the first elements of neighboring rows
result, // output
NULL, // will be assigned to n
ostride, // distance between two elements in the same row
odist, // distance between the firsn elements of neighboring rows
FFTW_ESTIMATE
);
fftw_execute(plan_);
for (int i = 0; i < 3; ++i)
{
for (int j = 0; j < 3; ++j)
{
std::cout << result[i * 3 + j][0] << " + 1j*" << result[i * 3 + j][1] << '\t';
}
std::cout << '\n';
}
fftw_destroy_plan(plan_);
return 0;
}
The corresponding explanations are in the code. Python gives the following answer:
array([[ 6. +0.j , -1.5+0.8660254j, -1.5-0.8660254j],
[15. +0.j , -1.5+0.8660254j, -1.5-0.8660254j],
[24. +0.j , -1.5+0.8660254j, -1.5-0.8660254j]])
My code gives the following
6 + 1j*0 -1.5 + 1j*0.866025 0 + 1j*0
15 + 1j*0 -1.5 + 1j*0.866025 0 + 1j*0
24 + 1j*0 -1.5 + 1j*0.866025 0 + 1j*0
I see that the output almost the same as with Python, but third elements of each row are zeros. Can someone help me?
Thank you.

sorting a 2d array by one row

I have a really specified problem to deal with. I need to descending sort an array[4][x].
From instance if i get values like:
{121,120,203,240}
{0.5,0.2,3.2,1.4}
{1.3,1.5,1.2,1.8}
{3 ,2 ,5 ,4 }
All values have to bo sorted by the 4th row. Thus, I need an output like this:
{203,240,121,120}
{3.2,1.4,0.5,0.2}
{1.2,1.8,1.3,1.5}
{5 ,4 ,3 ,2 }
I have tried doing it by the bubble sort method, but it does not work properly.
A straightforward approach of sorting the array using the bubble sort can look the following way
#include <iostream>
#include <iomanip>
#include <utility>
int main()
{
const size_t N = 4;
double a[][N] =
{
{ 121, 120, 203, 240 },
{ 0.5, 0.2, 3.2, 1.4 },
{ 1.3, 1.5, 1.2, 1.8 },
{ 3, 2, 5, 4 }
};
for (const auto &row : a)
{
for (double x : row) std::cout << std::setw( 3 ) << x << ' ';
std::cout << '\n';
}
std::cout << std::endl;
// The bubble sort
for (size_t n = N, last = N; not (n < 2); n = last)
{
for (size_t i = last = 1; i < n; i++)
{
if (a[N - 1][i - 1] < a[N - 1][i])
{
for (size_t j = 0; j < N; j++)
{
std::swap(a[j][i - 1], a[j][i]);
}
last = i;
}
}
}
for (const auto &row : a)
{
for (double x : row) std::cout << std::setw( 3 ) << x << ' ';
std::cout << '\n';
}
std::cout << std::endl;
return 0;
}
The program output is
121 120 203 240
0.5 0.2 3.2 1.4
1.3 1.5 1.2 1.8
3 2 5 4
203 240 121 120
3.2 1.4 0.5 0.2
1.2 1.8 1.3 1.5
5 4 3 2
All you need is to extract the code of the bubble sort from main and rewrite it as a separate function for any 2D array and any row used as the criteria of sorting.
The problem would be easy to solve if instead of parallel vectors we had a structure containing parallel values.
It is easy enough to get back to such a structure: just create some intermediate vector containing sort keys and indexes and sort it.
After sorting the indexes are giving us a direct way to reorder all the individual vectors in the right order.
I would do something like below (I put it in a Boost Unit Test, but what is done should be obvious) .
#define BOOST_AUTO_TEST_MAIN
#define BOOST_TEST_MODULE TestPenta
#include <boost/test/auto_unit_test.hpp>
#include <iostream>
#include <vector>
std::vector<int> v1 = {121,120,203,240};
std::vector<float> v2 = {0.5,0.2,3.2,1.4};
std::vector<float> v3 = {1.3,1.5,1.2,1.8};
std::vector<int> v4 = {3 ,2 ,5 ,4 };
std::vector<int> expected_v1 = {203,240,121,120};
std::vector<float> expected_v2 = {3.2,1.4,0.5,0.2};
std::vector<float> expected_v3 = {1.2,1.8,1.3,1.5};
std::vector<int> expected_v4 = {5 ,4 ,3 ,2 };
BOOST_AUTO_TEST_CASE(TestFailing)
{
// First create an index to sort containing sort key and initial position
std::vector<std::pair<int,int>> vindex{};
int i = 0;
for (auto x: v4){
vindex.push_back(std::pair<int,int>(x,i));
++i;
}
// Sort the index vector by key value
struct CmpIndex {
bool operator() (std::pair<int, int> & a, std::pair<int, int> & b) {
return a.first > b.first ;
}
} cmp;
std::sort(vindex.begin(), vindex.end(), cmp);
// Now reorder all the parallel vectors using index
// (of course in actual code we would write some loop if several vector are of the same type).
// I'm using parallel loops to avoid using too much memory for intermediate vectors
{
std::vector<int> r1;
for (auto & p: vindex){
r1.push_back(v1[p.second]);
}
v1 = r1;
}
{
std::vector<float> r2;
for (auto & p: vindex){
r2.push_back(v2[p.second]);
}
v2 = r2;
}
{
std::vector<float> r3;
for (auto & p: vindex){
r3.push_back(v3[p.second]);
}
v3 = r3;
}
{
std::vector<int> r4;
for (auto & p: vindex){
r4.push_back(v4[p.second]);
}
v4 = r4;
}
// Et voila! The vectors are all sorted as expected
i = 0;
for (int i = 0 ; i < 4 ; ++i){
BOOST_CHECK_EQUAL(expected_v1[i], v1[i]);
BOOST_CHECK_EQUAL(expected_v2[i], v2[i]);
BOOST_CHECK_EQUAL(expected_v3[i], v3[i]);
BOOST_CHECK_EQUAL(expected_v4[i], v4[i]);
++i;
}
}

Slicing a vector

I have a std::vector. I want to create iterators representing a slice of that vector. How do I do it? In pseudo C++:
class InterestingType;
void doSomething(slice& s) {
for (slice::iterator i = s.begin(); i != s.end(); ++i) {
std::cout << *i << endl;
}
}
int main() {
std::vector v();
for (int i= 0; i < 10; ++i) { v.push_back(i); }
slice slice1 = slice(v, 1, 5);
slice slice2 = slice(v, 2, 4);
doSomething(slice1);
doSomething(slice2);
return 0;
}
I would prefer not to have to copy the elements to a new datastructure.
You'd just use a pair of iterators:
typedef std::vector<int>::iterator vec_iter;
void doSomething(vec_iter first, vec_iter last) {
for (vec_iter cur = first; cur != last; ++cur) {
std::cout << *cur << endl;
}
}
int main() {
std::vector v();
for (int i= 0; i < 10; ++i) { v.push_back(i); }
doSomething(v.begin() + 1, v.begin() + 5);
doSomething(v.begin() + 2, v.begin() + 4);
return 0;
}
Alternatively, the Boost.Range library should allow you to represent iterator pairs as a single object, but the above is the canonical way to do it.
I learnt Python before I learnt C++. I wondered if C++ offered slicing of vectors like slicing in Python lists. Took a couple of minutes to write this function that allows you to slice a vector analogous to the way its done in Python.
vector<int> slice(const vector<int>& v, int start=0, int end=-1) {
int oldlen = v.size();
int newlen;
if (end == -1 or end >= oldlen){
newlen = oldlen-start;
} else {
newlen = end-start;
}
vector<int> nv(newlen);
for (int i=0; i<newlen; i++) {
nv[i] = v[start+i];
}
return nv;
}
Usage:
vector<int> newvector = slice(vector_variable, start_index, end_index);
The start_index element will be included in the slice, whereas the end_index will not be included.
Example:
For a vector v1 like {1,3,5,7,9}
slice(v1,2,4) returns {5,7}
Taken from here:
std::vector<myvector::value_type>(myvector.begin()+start, myvector.begin()+end).swap(myvector);
Usage example:
#include <iostream>
#include <vector>
int main ()
{
std::vector<int> indexes{3, 6, 9};
for( auto index : indexes )
{
int slice = 3;
std::vector<int> bar{1, 2, 3, 4, 5, 6, 7, 8, 9};
std::vector<int>( bar.begin() + index - slice, bar.begin() + index ).swap(bar);
std::cout << "bar index " << index << " contains:";
for (unsigned i=0; i<bar.size(); i++)
std::cout << ' ' << bar[i];
std::cout << '\n';
}
return 0;
}
Outputs:
bar index 3 contains: 1 2 3
bar index 6 contains: 4 5 6
bar index 9 contains: 7 8 9
As others have said, you can represent the "slice" as pair of iterators. If you are willing to use Boost, you can use the range concept. Then you will have even begin()/end() member functions available and the whole thing looks a lot like a container.
use boost range adapters. they are lazy:
operator|() is used to add new behaviour lazily and never modifies its
left argument.
boost::for_each(v|sliced(1,5)|transformed(doSomething));
doSomething needs to take range as input. a simple (may be lambda) wrapper would fix that.
You can represent those "slices" with a pair of iterators.
You don't need a pair of iterators to slice a vector. Three indexes will do because it allows you to create slices with steps:
static const int arr[] = {16,2,77,29,42};
vector<int> v (arr, arr + sizeof(arr) / sizeof(arr[0]) );
vector<int>::iterator i;
const int step = 2;
const int first = 0;
const int last = v.size()-1;
int counter=first;
for (i = v.begin()+first; counter<last; i+=step, counter+=step) {
// Do something with *i
cout << *i << endl;
}
Prints:
16
77
In this code, a counter is needed to track the position because not all iterators can do this.
It is possible to use slices with std::valarray. Which is an STL analogue of numpy.array in python. It support different vectorized operations like min, max, +,-, *, /, etc.
More info here.
std::slice(start, length, stride) allows to select and modify slices of an array without copying (documentation here).
The slicing would look like this:
std::valarray<int> foo (9);
for (int i=0; i<9; ++i) foo[i]=i; // 0 1 2 3 4 5 6 7 8
// | | | | |
std::slice myslice=std::slice(1,5,1); // v v v v v
foo[myslice] *= std::valarray<int>(10,3); // 0 10 20 30 40 50 6 7 8
Or with stride=2:
std::valarray<int> foo (9);
for (int i=0; i<9; ++i) foo[i]=i; // 0 1 2 3 4 5 6 7 8
// | | |
std::slice myslice=std::slice(1,3,2); // v v v
foo[myslice] *= std::valarray<int>(10,3); // 0 10 2 30 4 50 6 7 8
// | | |
foo[std::slice (0,3,3)] = 99; // v v v
// 99 10 2 99 4 50 99 7 8
std::cout << "foo:";
for (std::size_t n=0; n<foo.size(); n++)
std::cout << ' ' << foo[n];
std::cout << '\n';