How do you use the BandMatrix class in Eigen? - c++

I'm writing some numerical code in C++ and chose to use the Eigen library. One of the reasons for this that it seems to support band matrices.
The only info I've been able to find is this file http://eigen.tuxfamily.org/dox/BandMatrix_8h_source.html. But being new to C++, I'm not even sure how to #include it.
(I have a version of it on my file system, under /usr/include/eigen3/Eigen/src/Core/BandMatrix.h)
#include <Eigen/Core/BandMatrix>
doesn't work
#include <Eigen/Core>
does, but I can't find the BandMatrix class.
Can you provide some sample code that an initializes a - say tridiagonal - band matrix? Any help would be appreciated! Thanks
ps. I also tried working around this by using the unsupported Skyline module
#include <Eigen/Skyline>
(adding -I/usr/include/eigen3/unsupported switch) but this introduces a bunch of compilation errors starting with /usr/include/eigen3/unsupported/Eigen/src/Skyline/SkylineUtil.h:74:44: error: type/value mismatch at argument 2 in template parameter list for ‘template<class T, class StorageKind> struct Eigen::internal::eval’

To include it you would just #include <Eigen/Core> (assuming -I /usr/include/eigen3/) as it's included by that file (Eigen/Core: line ~341):
#include "src/Core/BandMatrix.h"
As for how to use it, I would refer to the test/bandmatrix.cpp file:
using Eigen::internal::BandMatrix;
void test_bandmatrix()
{
typedef BandMatrix<float>::Index Index;
for(int i = 0; i < 10*g_repeat ; i++) {
Index rows = internal::random<Index>(1,10);
Index cols = internal::random<Index>(1,10);
Index sups = internal::random<Index>(0,cols-1);
Index subs = internal::random<Index>(0,rows-1);
CALL_SUBTEST(bandmatrix(BandMatrix<float>(rows,cols,sups,subs)) );
}
}
After reading the BandMatrix.h file, I'm not sure it actually does what you really want. It appears to be just a storage class without any band specific operations. Any operations would have to be done after copying to a dense matrix with band.toDenseMatrix().
As for how to initialize a BandMatrix, here's a quick demo.
#include <Eigen/Core>
#include <iostream>
using Eigen::internal::BandMatrix;
int main()
{
int rows = 7;
int cols = 6;
int sups = 2;
int subs = 3;
BandMatrix<float> bm(rows,cols,sups,subs);
for(int i = -bm.subs(); i <= bm.supers(); ++i)
{
bm.diagonal(i).setConstant(0);
}
std::cout << bm.toDenseMatrix() << "\n\n";
bm.diagonal().setConstant(1010);
std::cout << bm.toDenseMatrix() << "\n\n";
for(int i = 1; i <= bm.supers(); ++i)
{
bm.diagonal(i).setConstant(i);
}
for(int i = 1; i <= bm.subs(); ++i)
{
bm.diagonal(-i).setConstant(-i);
}
std::cout << bm.toDenseMatrix() << "\n\n";
bm.diagonal(-2)(3) = 2345.f;
std::cout << bm.toDenseMatrix() << "\n\n";
}
Note that it doesn't appear that any operators besides operator= are implemented for the BandMatrix.

Related

Initialize all elements in matrix with variable dimensions to zero

I'm trying to initialize an int matrix in C++, with user-inputted dimensions, with every element set to zero. I know there are some elegant ways to do that with a one-dimensional array so I was wondering if there are any similar ways to do it with a two-dimensional array without using for loops and iterating through every element.
I found a source that gave several different ways, including std::fill (I've modified the code so that the dimensions are read with cin):
#include <iostream>
using namespace std;
int main() {
int x;
cin >> x;
int matrix[x][x];
fill(*matrix, *matrix + x * 3, 0);
for (int i = 0; i < x; i++) {
for (int j = 0; j < 3; j++) {
cout << matrix[i][j] << " ";
}
cout << endl;
}
}
But why does this work, and why would the pointer to the matrix in the arguments for fill be necessary if it's not necessary for a one-dimensional array? That source said it was because matrixes in C++ are treated like one-dimensional arrays, which would make sense, but that is why I don't understand why the pointer is needed.
I don't know if this is relevant, but in case it can help, I've described my previous attempts below.
At first I thought I could initialize all elements to zero like in a one-dimensional array. For the matrix, this worked fine when the side lengths were not read with cin (i.e. when I declared the matrix as int matrix[3][3] = {{}}; as answered here) but when I tried getting the side lengths from cin I started getting errors.
This was my code:
#include <iostream>
using namespace std;
int main() {
int x;
cin >> x;
int matrix[x][x] = {{}};
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
cout << matrix[i][j] << " ";
}
cout << endl;
}
}
And when I tried to compile it, it threw this error:
matrix_test.cpp:7:14: error: variable-sized object may not be initialized
int matrix[x][x] = {{}};
^
1 error generated.
Why you're getting the error
c-style arrays (such as int matrix[3][3]) must have size specified at the point you declare it. They can't vary in size in C++.
What you could do instead.
If you use std::vector, there's a really elegant way to do it:
#include <vector>
#include <iostream>
int main() {
using namespace std;
int x;
cin >> x;
auto matrix = vector<vector<int>>(x, vector<int>(x, 0));
// This is how we can print it
for(auto& row : matrix) {
for(auto& elem : row) {
cout << elem << ' ';
}
cout << '\n';
}
}
In C++17, you can shorten this even further:
auto matrix = vector(x, vector(x, 0));
What vector(number, thing) means is "Create a vector of number, where each element is thing".
The second dimension of two-dimension array must be a compile time constant, but in your code x is not.
Actually if you write a function with a two-dimension parameter, the second dimension must also be a compile time constant. That's because the array is stored linearly in the memory and the compiler must know the second dimension to calculate the offset correctly.

merging a collection of `Eigen::VectorXd`s into one large `Eigen::VectorXd`

If you go to this Eigen page, you'll see you can initialize VectorXd objects with the << operator. You can also dump a few vector objects into one big VectorXd object (e.g. look at the third example in the section called "The comma initializer").
I want to dump a few vectors into a big vector, but I'm having a hard time writing code that will work for an arbitrarily sized collection of vectors. The following doesn't work, and I'm having a hard time writing it in a way that does (that isn't a double for loop). Any suggestions?
#include <iostream>
#include <Eigen/Dense>
#include <vector>
int main(int argc, char **argv)
{
// make some random VectorXds
std::vector<Eigen::VectorXd> vOfV;
Eigen::VectorXd first(3);
Eigen::VectorXd second(4);
first << 1,2,3;
second << 4,5,6,7;
vOfV.push_back(first);
vOfV.push_back(second);
// here is the problem
Eigen::VectorXd flattened(7);
for(int i = 0; i < vOfV.size(); ++i)
flattened << vOfV[i];
//shows that this doesn't work
for(int i = 0; i < 7; ++i)
std::cout << flattened(i) << "\n";
return 0;
}
The comma initializer does not work like that. You have to fully initialize the matrix from that. Instead, allocate a large enough vector and iterate and assign the blocks.
#include <iostream>
#include <vector>
#include <Eigen/Dense>
// http://eigen.tuxfamily.org/dox/group__TopicStlContainers.html
#include <Eigen/StdVector>
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Eigen::VectorXd)
int main()
{
// make some random VectorXds
std::vector<Eigen::VectorXd> vOfV;
Eigen::VectorXd first(3);
Eigen::VectorXd second(4);
first << 1,2,3;
second << 4,5,6,7;
vOfV.push_back(first);
vOfV.push_back(second);
int len = 0;
for (auto const &v : vOfV)
len += v.size();
Eigen::VectorXd flattened(len);
int offset = 0;
for (auto const &v : vOfV)
{
flattened.middleRows(offset,v.size()) = v;
offset += v.size();
}
std::cout << flattened << "\n";
}

Use of boost libraries apply_visitor, bind and function in C++

I am new to the use of the boost library and have questions regarding its use. I have a vector union of ints and strings generated by use of boost::variant. Assume the vector is called myvec. I tried following the advice on this post to extract elements of the vector; essentially myvec[i] where i is the iterator integer in a for-loop. However, I am getting errors when I try to access elements in this way. It was advised by Ari that boost::apply_visitor is the best for this.
How can this error be fixed? In fixing this, would I have to use the same method if I had a conditional (say in an if statement).
Furthur, how could I count the number of strings elements within the vector myvec? This is because I would like to find the length of the vector excluding all of the string elments.
Finally, I would like to clean up my code and so I have functions doing seperate parts. I would like to pass a function called function1 as an argument to another function function2. As I understand, the boost_bind and boost_function need to be used given the cumbersome alternative by ordinary C++ code. But how can this be done?
For each of the questions, culd you please provide an example code and list any headers or libraries that need to be linked. would I hav to, for example, link all of the command I use; -lboost_apply_visitor, -lboost_bind, -lboost_function etc.
I am using C++ in Xcode 6.1. Thanks for all your help in advance.
EDIT:
The code that I have is:
#include <iostream>
#include <sstream>
#include <string>
#include <fstream>
#include <iomanip>
#include <vector>
#include <boost/filesystem.hpp>
#include <boost/assign/std/vector.hpp>
#include <boost/variant.hpp>
#include <boost/get.hpp>
#include <boost/bind.hpp>
#include <boost/function.hpp>
using namespace std;
typedef vector<int> int_vec;
typedef boost::variant<std::string,int> StringOrInt;
//typedef boost::function< void() > Function; // This allows for functions to be taken as arguments
// ------------------
// SET UP FIELD ARRAY
// ------------------
int *standard (int fieldarray[], int j, int n){
for (int i=0; i<n; i++){fieldarray[i] = n - i;}
for (int i=n; i<n+2; i++){fieldarray[i] = j;}
int k = 1;
for (int i=n+2; i< (2*n + 2); i++){fieldarray[i] = k; k++;}
return fieldarray;
}
// -----------------
// SET UP BOOL ARRAY
// -----------------
int *comparison (int boolarray[], int n){
for (int i=0; i<n; i++){boolarray[i] = 0;}
boolarray[n] = 1;
boolarray[n+1] = 0;
for (int i=n+2; i< (2*n + 2); i++){boolarray[i] = 1;}
return boolarray;
}
// ------------------------
// DELTA FUNCTION GENERATOR
// ------------------------
void deltafunction(vector<StringOrInt>&x, int i){
stringstream name;
name << "\u03b4" << "(" << x[i-1] << "-" << x[i] << ")";
cout << name.str() << endl;
}
// ----------------------------------------------------
// SWAPS VECTOR ELEMENTS ASSOCIATED WITH THE COMMUTATOR
// ----------------------------------------------------
void swap_element(vector<StringOrInt>&x, int i){
StringOrInt c = x[i];
x[i] = x[i-1];
x[i-1] = c;
}
// -----------------------
// START THE MAIN FUNCTION
// -----------------------
int main()
{
int n=4, j=3, x[2 * n + 2], y[2 * n + 2]; // x and y for the field and bool arrays
int *fieldarray = standard(x, j, n), *boolarray = comparison(y, n);
vector<StringOrInt> fields (fieldarray, fieldarray + (2 * n + 2)); // Field vector from field arrays
vector<StringOrInt> bools (boolarray, boolarray + (2 * n + 2));
vector< vector<StringOrInt> > normally_ordered_fields; // Empty vector of vectors
/*for (int j=bools.size() - 1; j >= 0; j--){
if (bools[j] == 1 && bools[j - 1] == 0){
vector<StringOrInt> reduced = bools;
swap_element(bools, j);
reduced.erase(reduced.begin() + j, reduced.begin() + j + 1);
stringstream name; // Declare the string
name << "\u03b4" << "(" << bools[j-1] << "-" << bools[j] << ")";
reduced.push_back(name.str());
j = -1;
}
}*/
return 0;
}
As can be seen, I am setting the vector to only have integer arguments at first. But then my some operations, there will be the introduction of a string (which is done by the deltafunction).
For this to work, one needs to link the boost library. Also if we remove the /* */ braces from the for-statement within the main, I get a complaint, since I am trying to access elements within the vector through its index.
I would like to promote the contents of the if statement within the for-loop to a function. But for it to work, it would require the swap_elements function to be passed as an argument. How could this be done.
Also, whilst I am not calling the deltafunction, how could I count the number of elements which have int arguments.

Sorting my 2d array in c++

My homework program has to write random numbers for arrival time and burst time into a file. Then after they are written, it reads the file and sorts the contents.
I figured setting up a 2d array would be the easiest way for me to go about this. But I am unsure on how to implement my sort so that if an arrival time swaps places then burst time of that arrival goes along for the ride.
I feel like I worded that poorly, but a basic example would be:
array[3][10] > array[2][23]
So since second array has an earlier arrival time I need both its arrival 2 and its burst 23 to move before array[3][10], but I need this do that and compare 100 inputs.
#include <iostream>
#include <cstdlib>
#include <iomanip>
#include <fstream>
const int max = 100;
using namespace std;
int main()
{
multimap<int [][]> myMap;
int randomBurst[max];
int arrivalTime[max];
int line[max][2];
int first = 0;
for (int i = 0; i < 100; i++)
{
if (i < 100)
{
ofstream write("Schedule.txt", ios::app);
randomBurst[i] = rand() % 1000;
arrivalTime[i] = rand() % 1000;
write << arrivalTime[i] << " " << randomBurst[i] << endl;
}
}
ifstream read("Schedule.txt");
for (int i = 0; i <= max; i++)
{
for (int j = 0; j < 2; j++)
{
read >> line[i][j];
cout << line[i][j] << " " ;
}
cout << endl;
}
cout << endl;
cout << endl;
for (int i = 0; i <= max; i++)
{
for (int j = 0; j < 2; j++)
{
myMap.insert(pair<int[][]>(line[i][j]);
}
cout << endl;
}
system("pause");
return 0;
}
My code sets up my array correctly after it reads the written file content, but I'm kind of lost what I should implement for a sort.
Well coming forward with this, mainly left that comment to be able to find this question faster on my laptop.
Like I said in the comment, if you want a presorted, by key value 2D "array", the quickest manner in which you could do this is with the map container., and if you really need the internal points to be ordered, and you will be using multiple entries within it, lets say entries 2,30 2,12 ... You could either build a map of vectors, or arrays, or use a Multimap. Not too sure of this data structure, as I have never really had a reason to use it as of yet. Referenced here http://www.cplusplus.com/reference/map/multimap/
The above will provide you with the sorting done for you, and the reason why I recommended a vector is the lack of order within it, and not sure if the 'bursts?' are to be ordered as well.
EDIT:
Forgot to mention, that a map will not hold more than one key of any given value, so if you are, again, inputting multiple points a above, then you will. if implementing things as you were before, overwrite things.
EDIT:
So this is more or less the fix I think I have, but you are working around this in a very indirect manner, that is hard to follow honestly.
#include <map>
#include <iostream>
#include <cstdlib>
#include <iomanip>
#include <fstream>
using namespace std;
const int MAX = 100;
int main()
{
multimap<int,int> myMap;
int randomBurst[100];
int arrivalTime[100];
int line[100][2];
int first = 0;
for (int i = 0; i < 100; i++)
{
if (i < 100)
{
ofstream write("Schedule.txt", ios::app);
randomBurst[i] = rand() % 1000;
arrivalTime[i] = rand() % 1000;
write << arrivalTime[i] << " " << randomBurst[i] << endl;
}
}
ifstream read("Schedule.txt");
for (int i = 0; i <= 100; i++)
{
for (int j = 0; j < 2; j++)
{
read >> line[i][j];
cout << line[i][j] << " " ;
}
cout << endl;
}
// cout << endl;
// cout << endl;
for (int i = 0; i < 100; i++)
{
for (int j = 0; j < 2; j++)
{
//Attain the value in the index, and the held value within it.
myMap.insert(pair<int, int> (line[i][j], line[i][j]));
}
cout << endl;
}
// system("pause");
return 0;
This fixes the insertion point, just because you give it an array it does not mean that the program will take that as a pair, as the first index is a point to another array in itself. And so on. I recommend starting off wiht a map object instead, as the multimap makes things a bit annoying, if you are familiar with the vector containers then use that instead within the map to log multiple values.

Can I Use vector's Fill Constructor to Create a Multi-Dimensional Array? [duplicate]

I'm trying to do something like:
#include <iostream>
#include <vector>
#include <ctime>
class Clickomania
{
public:
Clickomania();
std::vector<std::vector<int> > board;
};
Clickomania::Clickomania()
: board(12, std::vector<int>(8,0)) <<<<<<<
{
srand((unsigned)time(0));
for(int i = 0; i < 12; i++)
{
for(int j = 0; j < 8; j++)
{
int color = (rand() % 6) + 1;
board[i][j] = color;
}
}
}
However, apparently I can't initialize the "board" vector of vectors this way.
How can I create a public member of a 2d vector type and initialize it properly?
you should use the constructor that allows you to specify size and initial value for both vectors which may make it a bit easier altogether.
something like:
vector<vector<int>> v2DVector(3, vector<int>(2,0));
should work.
Use a matrix instead:
(Basic example from boost documentation)
#include <boost/numeric/ublas/matrix.hpp>
#include <boost/numeric/ublas/io.hpp>
int main () {
using namespace boost::numeric::ublas;
matrix<double> m (3, 3);
for (unsigned i = 0; i < m.size1 (); ++ i)
for (unsigned j = 0; j < m.size2 (); ++ j)
m (i, j) = 3 * i + j;
std::cout << m << std::endl;
}
Compiling your code with g++, the error I get is that neither srand() nor rand() were declared. I had to add #include <cstdlib> for the code to compile. But once I did that, it worked just fine. So, I'd say that other than adding that include statement, your code is fine. You're initializing the vector correctly.
Perhaps the code you have doesn't quite match what you posted? I would assume that if your actual code didn't include cstdlib, that you would have quickly understood that that was the problem rather than something with vector. So, if your code doesn't quite match what you posted, maybe that's the problem. If not, what compiler are you using?