Xmipp  v3.23.11-Nereus
sparse_matrix2d.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * Authors: Javier Vargas (jvargas@cnb.csic.es)
3  *
4  *
5  * Unidad de Bioinformatica of Centro Nacional de Biotecnologia , CSIC
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20  * 02111-1307 USA
21  *
22  * All comments concerning this program package may be sent to the
23  * e-mail address 'xmipp@cnb.csic.es'
24  ***************************************************************************/
25 
26 #include <algorithm>
27 #include <fstream>
28 #include "sparse_matrix2d.h"
29 #include "core/xmipp_filename.h"
30 
31 // Sparse matrices --------------------------------------------------------
32 SparseMatrix2D::SparseMatrix2D(std::vector<SparseElement> &_elements, int _Nelements)
33 {
34  //First of all, we sort the elements by rows and then by columns
35  std::sort(_elements.begin(),_elements.end());
36 
37  size_t ln = _elements.size();
38  N = _Nelements;
39 
40  values.resizeNoCopy(ln);
41  jIdx.resizeNoCopy(ln);
43 
44  int actualRow = -1;
45  int i = 0; // Iterator for the vectors "values" and "jIdx"
46 
47  for (size_t k=0 ; k< ln ; ++k )// Iterator for vector of SparseElemets
48  {
49  if(_elements.at(k).value != 0.0) // Searching that there isn't any zero value
50  {
51  DIRECT_MULTIDIM_ELEM(values,i) = _elements.at(k).value;
52  DIRECT_MULTIDIM_ELEM(jIdx,i) = _elements.at(k).j +1;
53 
54  int rse = _elements.at(k).i;
55  while( rse > actualRow )
56  {
57  actualRow++;
58  if( rse == actualRow )
59  // The first element in row number "x" is in position iIdx(x-1)
60  DIRECT_MULTIDIM_ELEM(iIdx,actualRow) = i+1;
61 
62  else
63  // If there isn't any nonzero value on this row, the value in this vector is 0
64  DIRECT_MULTIDIM_ELEM(iIdx,actualRow) = 0;
65  }
66  ++i;
67  }
68  }
69 }
70 
71 /*
72  * Fills the matrix form a vector of SparseElements
73  */
74 void SparseMatrix2D::sparseMatrix2DFromVector(std::vector<SparseElement> &_elements)
75 {
76  std::sort(_elements.begin(),_elements.end());
77 
78  size_t ln = _elements.size();
79  N = _elements.at(ln-1).j;
80  values.resizeNoCopy(ln);
81  jIdx.resizeNoCopy(ln);
83 
84  int actualRow = -1;
85  int i = 0;
86 
87  for (size_t k=0 ; k< ln ; ++k )
88  {
89  if(_elements.at(k).value != 0.0) // Seaching that there isn't any zero value
90  {
91  DIRECT_MULTIDIM_ELEM(values,i) = _elements.at(k).value;
92  DIRECT_MULTIDIM_ELEM(jIdx,i) = _elements.at(k).j +1;
93 
94  int rse = _elements.at(k).i;
95  while( rse > actualRow )
96  {
97  actualRow++;
98  if( rse == actualRow )
99  DIRECT_MULTIDIM_ELEM(iIdx,actualRow) = i+1;
100 
101  else
102  DIRECT_MULTIDIM_ELEM(iIdx,actualRow) = 0;
103  }
104  ++i;
105  }
106  }
107  N = actualRow+1;
108 }
109 
113 void SparseMatrix2D::multMv(double* x, double* y)
114 {
115  int col, rowEnd, rowBeg;
116  double val;
117  memset(y,0,N*sizeof(double));
118 
119  size_t nnz=XSIZE(values);
120  for(int i = 0; i< N; i++)
121  {
122  // We get the gap where are the elements of the row i in value's vector
123  rowBeg = DIRECT_MULTIDIM_ELEM(iIdx,i) -1;
124  if( i != N-1 )
125  rowEnd = DIRECT_MULTIDIM_ELEM(iIdx,i+1) -1;
126  else
127  rowEnd = nnz;
128 
129  val = 0.0;
130  for(int j = rowBeg; j < rowEnd ; j++)
131  {
132  col = DIRECT_MULTIDIM_ELEM(jIdx,j) -1;// Column with a nonzero element in this row of the matrix
133  val += DIRECT_MULTIDIM_ELEM(values,j) * x[col];
134  }
135  y[i] = val;
136  }
137 }
138 
139 /*
140  * It shows the sparse matrix as a full matrix. If the sparse matrix is real big, you shoudn't use it
141  * */
142 std::ostream & operator << (std::ostream &out, const SparseMatrix2D &X)
143 {
144  int N=X.nrows();
145  for(int i =0 ; i< N ; i++)
146  {
147  for(int j =0; j<N ; j++)
148  out << X.getElemIJ(i, j) << "\t";
149  out << std::endl;
150  }
151  return out;
152 }
153 
157 double SparseMatrix2D::getElemIJ(int row, int col) const
158 {
159  int rowBeg = DIRECT_MULTIDIM_ELEM(iIdx,row) -1;
160  int rowEnd;
161 
162  if( row != N-1 )
163  rowEnd = DIRECT_MULTIDIM_ELEM(iIdx,row+1) -1;
164  else
165  rowEnd = XSIZE(values);
166 
167  // If there is a non-zero element, the column is in jIdx
168  for(int i = rowBeg; i < rowEnd ; i++)
169  if( DIRECT_MULTIDIM_ELEM(jIdx,i)-1 == col )
170  return DIRECT_MULTIDIM_ELEM(values,i);
171  return 0.0;
172 }
173 
176 {
177  size_t nnz=XSIZE(X.values);
178 
179  Y.N = X.N;
180  Y.values.initZeros(nnz);
181  Y.jIdx.initZeros(nnz);
182  Y.iIdx.initZeros(N);
183 
184  size_t nnzY = 0;
185  int Nelems = X.N;
186  for(int row = 0; row < Nelems ; ++row){
187  int firstElemRow = 0;
188  for(int col = 0; col < Nelems ; ++col){
189  double aij = 0.0;
190  for(int k = 0; k < Nelems ; ++k ){
191  double val=getElemIJ(row, k);
192  if(val != 0.0){ // If GetElemIJ(row, k) is 0, the product is 0.
193  double val2=X.getElemIJ(k,col);
194  aij += val * val2;
195  }
196  }
197 
198  if(aij != 0.0){ // If there is a nonzero element in (row,col) position, we include that in the matrix
199  if(firstElemRow == 0)
200  firstElemRow = nnzY +1;
201  DIRECT_MULTIDIM_ELEM(Y.values,nnzY) = aij;
202  DIRECT_MULTIDIM_ELEM(Y.jIdx,nnzY) = col+1;
203  ++nnzY;
204  }
205  }
206  // Indicates where is the first element of the row
207  DIRECT_MULTIDIM_ELEM(Y.iIdx,row) = firstElemRow;
208  }
209  Y.values.resize(nnzY);
210  Y.jIdx.resize(nnzY);
211 }
212 
214 /*
215  * The matrix D is diagonal.
216  *
217  * | a11 a12 a13| | d11 0 0 | | a11*d1 a12*d1 a13*d1|
218  * | a21 a22 a23| * | 0 d22 0 | = | a21*d2 a22*d2 a23*d2|
219  * | a31 a32 a33| | 0 0 a33 | | a31*d3 a32*d3 a33*d3|
220  *
221  * Vectors iIdx and jIdx are the same as the non diagonal matrix
222  * Vector Values is the same as the non diagonal matrix multiply each row by each d_row
223  *
224  * The values are obtain from the last to the beginning.
225  * *
226  */
228 {
229  int actualRow = N-1;
230 
231  Y=*this;
232 
233  // We see where is the first element in the next row
234  int until = DIRECT_MULTIDIM_ELEM(iIdx,actualRow) -1;
235 
236  // Obtain the value that we have to multiply by the first row.
237  double dx = DIRECT_MULTIDIM_ELEM(D,actualRow);
238  size_t nnz=XSIZE(values);
239  for(int i = nnz-1; i >= 0 ; --i)
240  {
241  // Yij = Aij * Dii / Y = A => Yij = Yij * Dii
243 
244  if(until == i && i > 0){
245  --actualRow;
246  // Search for a row with nonzero elements
247  while( DIRECT_MULTIDIM_ELEM(iIdx,actualRow) == 0 )
248  --actualRow;
249 
250  until = DIRECT_MULTIDIM_ELEM(iIdx,actualRow) -1;
251  dx = DIRECT_MULTIDIM_ELEM(D,actualRow);
252  }
253  }
254 }
255 
256 /*
257  * Load matrix */
259 {
260  std::ifstream fhIn;
261  fhIn.open(fn.c_str());
262  if (!fhIn)
264 
265  double dobVecSize, auxDob;
266  int vectorSize = 0;
267  fhIn >> dobVecSize;
268  vectorSize = (int)dobVecSize ;
269 
270  std::vector<SparseElement> elems(vectorSize);
271  for(int i =0; i< vectorSize; ++i){
272  fhIn >> auxDob;
273  elems.at(i).i = (int) auxDob -1;
274 
275  fhIn >> auxDob;
276  elems.at(i).j = (int) auxDob -1;
277 
278  fhIn >> elems.at(i).value;
279  }
281 }
282 
void resize(size_t Ndim, size_t Zdim, size_t Ydim, size_t Xdim, bool copy=true)
friend std::ostream & operator<<(std::ostream &out, const SparseMatrix2D &X)
Shows the dense Matrix associated.
MultidimArray< double > values
List of values.
#define REPORT_ERROR(nerr, ErrormMsg)
Definition: xmipp_error.h:211
void resizeNoCopy(const MultidimArray< T1 > &v)
static double * y
void multMM(const SparseMatrix2D &X, SparseMatrix2D &Y)
Computes Y=this*X.
doublereal * x
#define i
ql0001_ & k(htemp+1),(cvec+1),(atemp+1),(bj+1),(bl+1),(bu+1),(x+1),(clamda+1), &iout, infoqp, &zero,(w+1), &lenw,(iw+1), &leniw, &glob_grd.epsmac
void multMMDiagonal(const MultidimArray< double > &D, SparseMatrix2D &Y)
Computes y=SparseMatrixThis*SparseMatrix.
void sparseMatrix2DFromVector(std::vector< SparseElement > &_elements)
Fill the sparse matrix A with the elements of the vector.
#define XSIZE(v)
MultidimArray< int > iIdx
List of i positions.
double dx
#define DIRECT_MULTIDIM_ELEM(v, n)
File or directory does not exist.
Definition: xmipp_error.h:136
SparseMatrix2D(std::vector< SparseElement > &_elements, int _Nelements)
int nrows() const
Y size of the matrix.
void sort(struct DCEL_T *dcel)
Definition: sorting.cpp:18
#define j
int N
The matrix is of size NxN.
void multMv(double *x, double *y)
void loadMatrix(const FileName &fn)
void initZeros(const MultidimArray< T1 > &op)
MultidimArray< int > jIdx
List of j positions.
double getElemIJ(int row, int col) const