Best sparse matrix representation for column and row swaping - c++

I am looking for sparse matrix representation that allow for efficient row and column swaping. The classic representation (by compressed row,compressed column or triplets) seems to only allow to perform one or the other but never booth.
Any one know a good data structure for this ?
--Edit--
To clarify , i want to be able to swap rows, like swap row 5 and row 7, and also swap column like swap column 6 and column 8.

You may just want to just add another level of indirection to handle swapping whichever is not efficient. For example, if you have a sparse representation that can efficiently swap rows but not columns, then have an array that maps from the true columns to the effective columns. When you access an element, use the array to find the proper underlying element.
class SparseMatrix {
public:
Element& operator()(Index row,Index col)
{
return matrix(row,col_map[col]);
}
void swapRows(Index row1,Index row2)
{
matrix.swapRows(row1,row2);
}
void swapCols(Index col1,Index col2)
{
swap(col_map[col1],col_map[col2]);
}
private:
FastRowSwapSparseMatrix matrix;
vector<Index> col_map;
};

My suggestion is
Eigen: Very fast and efficient for Linear algebra operations
http://eigen.tuxfamily.org/
or
Mapped Matrix in boost --> more flexible, but slower for linear algebra operations
http://www.boost.org/doc/libs/1_39_0/libs/numeric/ublas/doc/matrix_sparse.htm
For your case, both libraries allow you to manipulate rows and columns efficiently

Related

Sorting 1D std::vector based Matrix based on columns

I have a matrix class as follows (some parts are omitted for clarity):
template <typename T> class CMatrix{
protected:
vector<T>* m_matrix;
public:
void SetCellValue(unsigned int row,unsigned int col,T value){ m_matrix->at(row*m_column+col)=value;}
T& GetCellValue(unsigned int row,unsigned int column) const{return m_matrix->at(row*m_column+column);}
I would like to have a function to sort the matrix based on a chosen column. Say if the matrix is:
2 3
1 4
After sorting based on 1st column it should look like:
1 4
2 3
Basically, since 1<2 we performed a row exchange. I know if m_matrix was a 2D vector, then std::sort would have worked. Is it possible to achieve sorting 1D std::vector based matrix, based on a chosen column.
The following worked very well for a 1D data type but could not tweak it to work with a matrix:
template <typename T> class Sorter{
bool m_IsAscending;
public:
Sorter() {m_IsAscending=true;}
void SortAscending() {m_IsAscending=true;}
void SortDescending(){m_IsAscending=false;}
bool operator()(T i, T j){
if(m_IsAscending) return (i<j); else return (i>j);
}
};
The solution is very easy. Remember that std::sort takes begin and end iterators. So all you have to do is split your matrix into parts and sort them individually:
for(long i = 0; i < num_of_columns; i++)
{
std::sort(m_matrix->begin()+num_of_rows*i, m_matrix->begin()+num_of_rows*(i+1));
}
This will sort all individual columns independently. If you want to sort only one column, don't use a loop, and choose an i that is the column number you want to sort.
Caveats:
This will work if your matrix is flattened in column-major order. Otherwise, if it's in row-major, all you have to do is transpose the matrix, sort it with the code above, and transpose it back. I guess this is the only way to go if you want to avoid writing your own sorting function. However, if all you want is to sort a single column, and your matrix is in row-major order, then it's much cheaper to just copy that row to a new vector, sort it, and copy it back.
Btw, I don't understand why m_matrix is a pointer... that's very bad practice and is a welcome invitation to memory leaks (unless you're using a smart pointer to wrap it, such as std::unique_ptr).
Hope this helps. Cheers!

Reordering of matrix in c++

I have a matrix in C++, A(n,n) and a vector P(n) which looks something like this:
P = [ 3 6 1 13 12 16 ... ]
it contains numbers 1:n but not in an ascending order but scrambled.
My aim is to change the rows and columns of matrix A to the same order. For example since P[0] = 3 I want the 3rd row and 3rd column to move to the 1st row and column in matrix A.
But because the matrix could be potentially really large, I can't use another matrix of size same as A because that would be wasteful.
In matlab this can be done simply by using the command:
A(P,P);
Any ideas on how to do the same thing in c++?
I will suggest using a level of indirection, to locate each matrix in a cell.
Let's say your matrix object is called M. Instead of using
M[R][C]
to refer to the cell in row R, column C (assuming row-major matrix ordering), you will have an associated pair of vectors, let's call them y and x, so the value of the cell in row R column C is:
M[y[R]][x[C]]
Initially, both y and x vectors map each "logical" row or column to the corresponding physical row and column, that is both y and x contain [0..max_row] and [0..max_col].
Then, to effect the swapping in your question, you simply copy your P vector to the y and x vectors.
You should implement your matrix not directly, as a two-dimensional std::vector, but as a standalone class:
class Matrix {
public:
// ...
auto operator()(size_t R, size_t C) const;
auto &operator()(size_t R, size_t C);
// ...
};
and implement the indirect mapping of rows and columns as part of the class implementation.
Easiest way is probably to just brute-force it. The best idea is probably to do it row by row. You'll need a helper array of length N which keeps track of the original row index, and one temporary row. Then, starting at row R=0, check if row R is in the right position. If not, copy it to the temporary row, copy the right row to row R (permuting it on the go), and copy the temporary row to the spot that was just freed. If a row happens to be in the right spot, copy it to the temporary row, and permute it when copying back.

C++ row and columns matrix manipulation

I've created a 2D matrix as a vector of vectors like this :
vector<vector<int>> mat;
now I need to swap the row and columns of my matrix for example :
row 0 swapped with row 4
column 5 swapped with column 1
the rows aren't a problem since there is the swap() function of the stl library. Exchanging rows though seems quite problematic because, of course, they are not considered as one atomic structure. so at this point I'm really stuck... I've considered doing it brutally swapping every element of the rows I'm interested in, but it seems quite inelegant. Any idea of how I could achieve my goal ?
If you consider "elenance" as a STL function that can do all this stuff for you, then there's no function like this. The aim of STL is not about making your code as simple as possible, the creators of C++ only add to STL things that:
Is really hard to implement with the current language's instrument
Things that need a special support from your compiler (special optimization, etc.)
Some elements that became common
So, just implement by your own.
If you don't want to use for (;;) loops because it's not "elegant" at some point, then you can do something like this:
/* swapping column i and j */
std::vector<std::vector<T>> mat;
std::for_each(mat.begin(), mat.end(), [i,j](std::vector<int>& a)
{ std::swap(a[i], a[j]); });
Update: If the speed is important for you and you want to swap columns as fast as swapping rows (in O(1) ), then you can use this implementation (that takes extra space)):
std::vector<std::vector<int>> mat;
/* preprocessing */
std::vector<int> permutation(mat[0].size());
std::iota(permutation.begin(), permutation.end(), 0);
/* now, if you need to get the element mat[i][j] */
mat_i_j = mat[i][ permutation[j] ];
/* if you want to swap column i and j */
std::swap(permutation[i], permutation[j]);

OpenCV Add columns to a matrix

in OpenCV 2 and later there is method Mat::resize that let's you add any number of rows with the default value to your matrix is there any equivalent method for the column. and if not what is the most efficient way to do this.
Thanks
Use cv::hconcat:
Mat mat;
Mat cols;
cv::hconcat(mat, cols, mat);
Worst case scenario: rotate the image by 90 degrees and use Mat::resize(), making columns become rows.
Since OpenCV, stores elements of matrix rows sequentially one after another there is no direct method to increase column size but I bring up myself two solutions for the above matter,
First using the following method (the order of copying elements is less than other methods), also you could use a similar method if you want to insert some rows or columns not specifically at the end of matrices.
void resizeCol(Mat& m, size_t sz, const Scalar& s)
{
Mat tm(m.rows, m.cols + sz, m.type());
tm.setTo(s);
m.copyTo(tm(Rect(Point(0, 0), m.size())));
m = tm;
}
And the other one if you are insisting not to include even copying data order into your algorithms then it is better to create your matrix with the big number of rows and columns and start the algorithm with the smaller submatrix then increase your matrix size by Mat::adjustROI method.

Sorting eigenvectors by their eigenvalues (associated sorting)

I have an unsorted vector of eigenvalues and a related matrix of eigenvectors. I'd like to sort the columns of the matrix with respect to the sorted set of eigenvalues. (e.g., if eigenvalue[3] moves to eigenvalue[2], I want column 3 of the eigenvector matrix to move over to column 2.)
I know I can sort the eigenvalues in O(N log N) via std::sort. Without rolling my own sorting algorithm, how do I make sure the matrix's columns (the associated eigenvectors) follow along with their eigenvalues as the latter are sorted?
Typically just create a structure something like this:
struct eigen {
int value;
double *vector;
bool operator<(eigen const &other) const {
return value < other.value;
}
};
Alternatively, just put the eigenvalue/eigenvector into an std::pair -- though I'd prefer eigen.value and eigen.vector over something.first and something.second.
I've done this a number of times in different situations. Rather than sorting the array, just create a new array that has the sorted indices in it.
For example, you have a length n array (vector) evals, and a 2d nxn array evects. Create a new array index that has contains the values [0, n-1].
Then rather than accessing evals as evals[i], you access it as evals[index[i]] and instead of evects[i][j], you access it evects[index[i]][j].
Now you write your sort routine to sort the index array rather than the evals array, so instead of index looking like {0, 1, 2, ... , n-1}, the value in the index array will be in increasing order of the values in the evals array.
So after sorting, if you do this:
for (int i=0;i<n;++i)
{
cout << evals[index[i]] << endl;
}
you'll get a sorted list of evals.
this way you can sort anything that's associated with that evals array without actually moving memory around. This is important when n gets large, you don't want to be moving around the columns of the evects matrix.
basically the i'th smallest eval will be located at index[i] and that corresponds to the index[i]th evect.
Edited to add. Here's a sort function that I've written to work with std::sort to do what I just said:
template <class DataType, class IndexType>
class SortIndicesInc
{
protected:
DataType* mData;
public:
SortIndicesInc(DataType* Data) : mData(Data) {}
Bool operator()(const IndexType& i, const IndexType& j) const
{
return mData[i]<mData[j];
}
};
The solution purely relies on the way you store your eigenvector matrix.
The best performance while sorting will be achieved if you can implement swap(evector1, evector2) so that it only rebinds the pointers and the real data is left unchanged.
This could be done using something like double* or probably something more complicated, depends on your matrix implementation.
If done this way, swap(...) wouldn't affect your sorting operation performance.
The idea of conglomerating your vector and matrix is probably the best way to do it in C++. I am thinking about how I would do it in R and seeing if that can be translated to C++. In R it's very easy, simply evec<-evec[,order(eval)]. Unfortunately, I don't know of any built in way to perform the order() operation in C++. Perhaps someone else does, in which case this could be done in a similar way.