Free Electron
ListSparseMatrix.h
Go to the documentation of this file.
1 /* Copyright (C) 2003-2021 Free Electron Organization
2  Any use of this software requires a license. If a valid license
3  was not distributed with this file, visit freeelectron.org. */
4 
5 /** @file */
6 
7 #ifndef __solve_SparseMatrix_h__
8 #define __solve_SparseMatrix_h__
9 
10 namespace fe
11 {
12 namespace ext
13 {
14 /**************************************************************************//**
15  @brief Dense array of sparse rows
16 
17  SparseMatrix has some similar functionailty to Matrix through
18  overloaded non-member operations.
19 
20  Only a small number of operations are implemented for SparseMatrix.
21  Others may be added as needed.
22 
23 *//***************************************************************************/
24 template<class T>
26 {
27  public:
28  SparseMatrix(void);
29  SparseMatrix(U32 rows,U32 columns);
30  SparseMatrix(const SparseMatrix<T>& rhs);
31  ~SparseMatrix(void);
32 
33  SparseMatrix<T>& operator=(const SparseMatrix<T>& rhs);
34 
35  T operator()(U32 i, U32 j) const;
36  T& operator()(U32 i, U32 j);
37 
38  void reset(U32 rows,U32 columns);
39  void clear(void);
40  U32 rows(void) const { return m_rows; }
41  U32 columns(void) const { return m_columns; }
42 
43  void setTranspose(const SparseMatrix<T>& rhs);
44  void setSum(const SparseMatrix<T> &rhs);
45  void setDifference(const SparseMatrix<T> &rhs);
46 
47  void premultiplyDiagonal(const SparseMatrix<T> &diag,
48  SparseMatrix<T> &b) const;
49 
50  void scale(const F32 scalar,
51  SparseMatrix<T>& result) const;
52 
53  void transform(const DenseVector<T> &x,
54  DenseVector<T> &b) const;
55  void transposeTransform(const DenseVector<T> &x,
56  DenseVector<T> &b) const;
57 
58  protected:
59  BWORD seek(U32 i, U32 j) const;
60 
61  U32 m_rows;
62  U32 m_columns;
63 
64  class Entry
65  {
66  public:
67  Entry(U32 column):
68  m_column(column),
69  m_value(T(0)) {}
70  U32 m_column;
71  T m_value;
72  };
73  class Row: public List<Entry*>
74  {
75  public:
76  Row(void) { ListCore::setAutoDestruct(TRUE); }
77  };
78 
79  Row* m_pRow;
80 mutable Row* m_pCurrent;
81 mutable ListCore::Context m_context;
82 };
83 
84 template<class T>
86  m_rows(1),
87  m_columns(1),
88  m_pCurrent(NULL)
89 {
90  m_pRow=new Row[m_rows];
91 }
92 
93 template<class T>
94 inline SparseMatrix<T>::SparseMatrix(U32 rows,U32 columns):
95  m_rows(rows),
96  m_columns(columns),
97  m_pCurrent(NULL)
98 {
99  m_pRow=new Row[m_rows];
100 }
101 
102 template<class T>
104  m_rows(rhs.m_rows),
105  m_columns(rhs.m_columns),
106  m_pRow(NULL),
107  m_pCurrent(NULL)
108 {
109  operator=(rhs);
110 }
111 
112 template<class T>
114 {
115  delete[] m_pRow;
116 }
117 
118 template<class T>
119 inline void SparseMatrix<T>::reset(U32 rows,U32 columns)
120 {
121  delete[] m_pRow;
122  m_rows=rows;
123  m_columns=columns;
124  m_pCurrent=NULL;
125  m_pRow=new Row[m_rows];
126 }
127 template<class T>
128 inline void SparseMatrix<T>::clear(void)
129 {
130  delete[] m_pRow;
131  m_pCurrent=NULL;
132  m_pRow=new Row[m_rows];
133 }
134 
135 template<class T>
136 inline BWORD SparseMatrix<T>::seek(U32 i, U32 j) const
137 {
138 #if FE_BOUNDSCHECK
139  if(i >= m_rows || j >= m_columns) { feX(e_invalidRange); }
140 #endif
141 
142  Row& row=m_pRow[i];
143  if(m_pCurrent!=&row)
144  {
145  m_pCurrent=&row;
146  row.toHead(m_context);
147  }
148 
149 // feLog("seek(%d,%d)\n",i,j);
150  I32 column= -1;
151  if(row.isAtHeadNull(m_context))
152  {
153 // feLog("%d++\n",column);
154  row.postIncrement(m_context);
155  }
156  while(!row.isAtHeadNull(m_context) && !row.isAtTailNull(m_context) &&
157  (column=I32(row.current(m_context)->m_column))<I32(j))
158  {
159 // feLog("%d++\n",column);
160  row.postIncrement(m_context);
161  }
162  while(!row.isAtHeadNull(m_context) && (row.isAtTailNull(m_context) ||
163  (column=I32(row.current(m_context)->m_column))>I32(j)))
164  {
165 // feLog("%d--\n",column);
166  row.postDecrement(m_context);
167  }
168 
169  if(!row.isAtHeadNull(m_context) && row.isAtTailNull(m_context))
170  {
171  column=I32(row.current(m_context)->m_column);
172  }
173 // feLog("at %d\n",column);
174  return column==I32(j);
175 }
176 
177 template<class T>
178 inline T SparseMatrix<T>::operator()(U32 i, U32 j) const
179 {
180  if(seek(i,j))
181  {
182  return m_pRow[i].current(m_context)->m_value;
183  }
184 
185  return T(0);
186 }
187 
188 template<class T>
189 inline T& SparseMatrix<T>::operator()(U32 i, U32 j)
190 {
191  if(seek(i,j))
192  {
193  return m_pRow[i].current(m_context)->m_value;
194  }
195 
196  Entry** ppEntry=m_pRow[i].insertAfter(m_context,new Entry(j));
197  return (*ppEntry)->m_value;
198 }
199 
200 /** Copy existing matrix
201  @relates SparseMatrix
202  */
203 template<class T>
205 {
206  if(this != &rhs)
207  {
208  m_rows=rhs.m_rows;
209  m_columns=rhs.m_columns;
210 
211  clear();
212 
213  for(U32 i = 0; i<m_rows; i++)
214  {
215  Row& row=rhs.m_pRow[i];
216  rhs.m_pCurrent=&row;
217  row.toHead(rhs.m_context);
218 
219  Entry* pNode;
220  while((pNode=row.postIncrement(rhs.m_context)) != NULL)
221  {
222  //* effectively this(j,i) = rhs(i,j)
223  operator()(i,pNode->m_column)=pNode->m_value;
224  }
225  }
226  }
227  return *this;
228 }
229 
230 #if FALSE
231 /** Sets to the transpose of the argument
232  @relates SparseMatrix
233  */
234 template<class T>
236 {
237  //* WARNING This will thrash the output context. Is there a faster way?
238 
239  for(U32 i = 0; i<m_rows; i++)
240  {
241  Row& row=rhs.m_pRow[i];
242  rhs.m_pCurrent=&row;
243  row.toHead(rhs.m_context);
244 
245  Entry* pNode;
246  while((pNode=row.postIncrement(rhs.m_context)) != NULL)
247  {
248  //* effectively this(j,i) = rhs(i,j)
249  operator()(pNode->m_column,i)=pNode->m_value;
250  }
251  }
252 }
253 #endif
254 
255 /** add to SparseMatrix in place
256  @relates SparseMatrix
257  */
258 template<class T>
260 {
261  for(U32 i = 0; i<m_rows; i++)
262  {
263  Row& row=rhs.m_pRow[i];
264  rhs.m_pCurrent=&row;
265  row.toHead(rhs.m_context);
266 
267  Entry* pNode;
268  while((pNode=row.postIncrement(rhs.m_context)) != NULL)
269  {
270  //* effectively this(i,j) += rhs(i,j)
271  operator()(i,pNode->m_column)+=pNode->m_value;
272  }
273  }
274 }
275 
276 /** subtract from SparseMatrix in place
277  @relates SparseMatrix
278  */
279 template<class T>
281 {
282  for(U32 i = 0; i<m_rows; i++)
283  {
284  Row& row=rhs.m_pRow[i];
285  rhs.m_pCurrent=&row;
286  row.toHead(rhs.m_context);
287 
288  Entry* pNode;
289  while((pNode=row.postIncrement(rhs.m_context)) != NULL)
290  {
291  //* effectively this(i,j) -= rhs(i,j)
292  operator()(i,pNode->m_column)-=pNode->m_value;
293  }
294  }
295 }
296 
297 /** SparseMatrix-Scalar multiply
298  @relates SparseMatrix
299  */
300 template<class T>
301 void SparseMatrix<T>::scale(const F32 scalar,SparseMatrix<T> &result) const
302 {
303  for(U32 i = 0; i<m_rows; i++)
304  {
305  Row& row=m_pRow[i];
306  m_pCurrent=&row;
307  row.toHead(m_context);
308 
309  Entry* pNode;
310  while((pNode=row.postIncrement(m_context)) != NULL)
311  {
312  //* effectively result(i,j) = A(i,j) * scalar
313  result(i,pNode->m_column)=pNode->m_value*scalar;
314  }
315  }
316 }
317 
318 /** SparseMatrix-Vector multiply
319  @relates SparseMatrix
320  */
321 template<class T>
323 {
324  for(U32 i = 0; i<m_rows; i++)
325  {
326  Row& row=m_pRow[i];
327  m_pCurrent=&row;
328  row.toHead(m_context);
329 
330  T sum=T(0);
331  Entry* pNode;
332  while((pNode=row.postIncrement(m_context)) != NULL)
333  {
334  //* effectively b[i] += A(i,j) * x[j]
335  sum+=pNode->m_value * x[pNode->m_column];
336  }
337  setAt(b,i,sum);
338  }
339 }
340 
341 /** SparseMatrix-Vector multiply with matrix transposed
342  @relates SparseMatrix
343  */
344 template<class T>
346  DenseVector<T> &b) const
347 {
348  set(b);
349 
350  for(U32 i = 0; i<m_rows; i++)
351  {
352  Row& row=m_pRow[i];
353  m_pCurrent=&row;
354  row.toHead(m_context);
355 
356  Entry* pNode;
357  while((pNode=row.postIncrement(m_context)) != NULL)
358  {
359  //* effectively b[j] += A(i,j) * x[i]
360  b[pNode->m_column]+=pNode->m_value * x[i];
361  }
362  }
363 }
364 
365 /** SparseMatrix-Diagonal multiply
366  @relates SparseMatrix
367 
368  This amounts to a scale of each row by the corresponding diagonal element.
369  */
370 template<class T>
372  SparseMatrix<T> &result) const
373 {
374  for(U32 i = 0; i<m_rows; i++)
375  {
376  Row& row=m_pRow[i];
377  m_pCurrent=&row;
378  row.toHead(m_context);
379 
380  T d=diag(i,i);
381 
382  Entry* pNode;
383  while((pNode=row.postIncrement(m_context)) != NULL)
384  {
385  //* effectively result(i,j) = A(i,j) * diag(i,i)
386  result(i,pNode->m_column)=pNode->m_value*d;
387  }
388  }
389 }
390 
391 /* non member operations */
392 
393 template<class T>
394 inline SparseMatrix<T>& set(SparseMatrix<T> &matrix)
395 {
396  matrix.clear();
397  return matrix;
398 }
399 
400 /** Return true is matrix is square, otherwise return false.
401  @relates SparseMatrix
402  */
403 template<class T>
404 inline BWORD isSquare(const SparseMatrix<T> &matrix)
405 {
406  return(matrix.rows()==matrix.columns());
407 }
408 
409 /** Set matrix to identity matrix
410  @relates SparseMatrix
411  */
412 template<class T>
414 {
415  U32 limit=minimum(matrix.columns(),matrix.rows());
416  matrix.clear();
417  for(U32 i = 0;i < limit;i++)
418  matrix(i,i) = T(1);
419  return matrix;
420 }
421 
422 /** Return transpose of matrix
423  @relates SparseMatrix
424  */
425 template<class T>
427 {
428  SparseMatrix<T> A(matrix.rows(),matrix.columns());
429  A.setTranspose(matrix);
430 
431  return A;
432 }
433 
434 /** SparseMatrix add
435  @relates SparseMatrix
436  */
437 template<class T>
439  const SparseMatrix<T> &rhs)
440 {
441  SparseMatrix<T> result=lhs;
442  result.setSum(rhs);
443  return result;
444 }
445 
446 /** SparseMatrix subtract
447  @relates SparseMatrix
448  */
449 template<class T>
451  const SparseMatrix<T> &rhs)
452 {
453  SparseMatrix<T> result=lhs;
454  result.setDifference(rhs);
455  return result;
456 }
457 
458 /** SparseMatrix-SparseMatrix multiply where first matrix is a diagonal
459  @relates SparseMatrix
460  */
461 template<class T>
463  const SparseMatrix<T> &rhs)
464 {
465  SparseMatrix<T> result(rhs.rows(),rhs.columns());
466  rhs.premultiplyDiagonal(lhs,result);
467  return result;
468 }
469 
470 /** SparseMatrix-Vector multiply
471  @relates SparseMatrix
472  */
473 template<class T>
475 {
476  DenseVector<T> b(rhs.size());
477  lhs.transform(rhs,b);
478  return b;
479 }
480 
481 /** SparseMatrix-Vector multiply with matrix transposed
482  @relates SparseMatrix
483  */
484 template<class T>
486  const DenseVector<T>& rhs)
487 {
488  DenseVector<T> b(rhs.size());
489  lhs.transposeTransform(rhs,b);
490  return b;
491 }
492 
493 /** SparseMatrix-Scalar post-multiply
494  @relates SparseMatrix
495  */
496 template<class T>
497 SparseMatrix<T> operator*(const SparseMatrix<T> &matrix, const F32 scalar)
498 {
499  SparseMatrix<T> result(matrix.rows(),matrix.columns());
500  matrix.scale(scalar,result);
501  return result;
502 }
503 
504 /** SparseMatrix-Scalar pre-multiply
505  @relates SparseMatrix
506  */
507 template<class T>
508 SparseMatrix<T> operator*(const F32 scalar, const SparseMatrix<T> &matrix)
509 {
510  SparseMatrix<T> result(matrix.rows(),matrix.columns());
511  matrix.scale(scalar,result);
512  return result;
513 }
514 
515 /** SparseMatrix print
516  @relates SparseMatrix
517 
518  The output isn't sparse.
519  */
520 template<class T>
522 {
523  String s;
524  for(U32 i = 0; i<matrix.rows(); i++)
525  {
526  for(U32 j = 0; j<matrix.columns(); j++)
527  {
528  s.catf("%6.3f ", matrix(i,j));
529  }
530  s.cat("\n");
531  }
532  return s;
533 }
534 
535 } /* namespace ext */
536 } /* namespace fe */
537 
538 #endif // __solve_SparseMatrix_h__
Fully Bidirectional Doubly-Linked List.
Definition: List.h:496
BWORD isSquare(const SparseMatrix< T > &matrix)
Return true is matrix is square, otherwise return false.
Definition: ListSparseMatrix.h:404
Dense vector - size fixed at construction or reset.
Definition: DenseVector.h:21
SparseMatrix< T > operator*(const F32 scalar, const SparseMatrix< T > &matrix)
SparseMatrix-Scalar pre-multiply.
Definition: ListSparseMatrix.h:508
kernel
Definition: namespace.dox:3
String print(const SparseMatrix< T > &matrix)
SparseMatrix print.
Definition: ListSparseMatrix.h:521
DenseVector< T > transposeMultiply(const SparseMatrix< T > &lhs, const DenseVector< T > &rhs)
SparseMatrix-Vector multiply with matrix transposed.
Definition: ListSparseMatrix.h:485
A view state into an fe::List <>
Definition: List.h:101
String & cat(const char *operand)
Append the current String with the given text.
Definition: String.cc:545
void setAutoDestruct(BWORD set)
Set the AutoDestruct flag.
Definition: List.h:52
DenseVector< T > operator*(const SparseMatrix< T > &lhs, const DenseVector< T > &rhs)
SparseMatrix-Vector multiply.
Definition: ListSparseMatrix.h:474
Automatically reference-counted string container.
Definition: String.h:128
String & catf(const char *fmt,...)
Populate the string as with sPrintf(), but by concatenating the results to the existing string...
Definition: String.cc:554
Dense array of sparse rows.
Definition: ListSparseMatrix.h:25
SparseMatrix< T > premultiplyDiagonal(const SparseMatrix< T > &lhs, const SparseMatrix< T > &rhs)
SparseMatrix-SparseMatrix multiply where first matrix is a diagonal.
Definition: ListSparseMatrix.h:462
SparseMatrix< T > operator*(const SparseMatrix< T > &matrix, const F32 scalar)
SparseMatrix-Scalar post-multiply.
Definition: ListSparseMatrix.h:497
SparseMatrix< T > operator-(const SparseMatrix< T > &lhs, const SparseMatrix< T > &rhs)
SparseMatrix subtract.
Definition: ListSparseMatrix.h:450
SparseMatrix< T > & setIdentity(SparseMatrix< T > &matrix)
Set matrix to identity matrix.
Definition: ListSparseMatrix.h:413
SparseMatrix< T > operator+(const SparseMatrix< T > &lhs, const SparseMatrix< T > &rhs)
SparseMatrix add.
Definition: ListSparseMatrix.h:438
SparseMatrix< T > transpose(const SparseMatrix< T > &matrix)
Return transpose of matrix.
Definition: ListSparseMatrix.h:426