NEURON
ocmatrix.cpp
Go to the documentation of this file.
1 #include <../../nrnconf.h>
2 #include <vector>
3 #include <cmath>
4 
5 #define v_elem(v, i) (*(vector_vec(v) + i))
6 
7 #include <Eigen/Eigen>
8 #include <unsupported/Eigen/MatrixFunctions>
9 
10 #include "ivocvect.h"
11 #include "oc_ansi.h"
12 
13 #include "ocmatrix.h"
14 
15 int nrn_matrix_dim(void* vm, int d) {
16  OcMatrix* m = (OcMatrix*) vm;
17  return d ? m->ncol() : m->nrow();
18 }
19 
20 static Eigen::Map<Eigen::VectorXd> Vect2VEC(Vect* v1) {
21  return Eigen::Map<Eigen::VectorXd>(v1->data(), v1->size());
22 }
23 
25  : type_(type) {}
26 
27 OcMatrix* OcMatrix::instance(int nrow, int ncol, int type) {
28  switch (type) {
29  default:
30  case MFULL:
31  return new OcFullMatrix(nrow, ncol);
32  case MSPARSE:
33  return new OcSparseMatrix(nrow, ncol);
34  }
35 }
36 
37 void OcMatrix::unimp() const {
38  hoc_execerror("Matrix method not implemented for this type matrix", nullptr);
39 }
40 
41 std::vector<std::pair<int, int>> OcMatrix::nonzeros() const {
42  std::vector<std::pair<int, int>> nzs;
43  for (int i = 0; i < nrow(); i++) {
44  for (int j = 0; j < ncol(); j++) {
45  if (getval(i, j) != 0.) {
46  nzs.emplace_back(i, j);
47  }
48  }
49  }
50  return nzs;
51 }
52 
54  if (type_ != MFULL) { // could clone one maybe
55  hoc_execerror("Matrix is not a FULL matrix (type 1)", 0);
56  }
57  return (OcFullMatrix*) this;
58 }
59 
60 OcFullMatrix::OcFullMatrix(int nrow, int ncol)
61  : OcMatrix(MFULL)
62  , m_(nrow, ncol) {
63  // The constructor of Eigen::Matrix does not initialize values
64  m_.setZero();
65 }
66 
67 double& OcFullMatrix::coeff(int i, int j) {
68  return m_(i, j);
69 }
70 double OcFullMatrix::getval(int i, int j) const {
71  return m_(i, j);
72 }
73 int OcFullMatrix::nrow() const {
74  return m_.rows();
75 }
76 int OcFullMatrix::ncol() const {
77  return m_.cols();
78 }
79 
80 void OcFullMatrix::resize(int i, int j) {
81  // This is here because we want that new values are initialized to 0
82  auto v = Eigen::MatrixXd::Zero(i, j);
83  m_.conservativeResizeLike(v);
84 }
85 
86 void OcFullMatrix::mulv(Vect* vin, Vect* vout) const {
87  auto v1 = Vect2VEC(vin);
88  auto v2 = Vect2VEC(vout);
89  v2 = m_ * v1;
90 }
91 
92 void OcFullMatrix::mulm(Matrix* in, Matrix* out) const {
93  out->full()->m_ = m_ * in->full()->m_;
94 }
95 
96 void OcFullMatrix::muls(double s, Matrix* out) const {
97  out->full()->m_ = s * m_;
98 }
99 
100 void OcFullMatrix::add(Matrix* in, Matrix* out) const {
101  out->full()->m_ = m_ + in->full()->m_;
102 }
103 
104 void OcFullMatrix::copy(Matrix* out) const {
105  out->full()->m_ = m_;
106 }
107 
108 void OcFullMatrix::bcopy(Matrix* out, int i0, int j0, int n0, int m0, int i1, int j1) const {
109  out->full()->m_.block(i1, j1, n0, m0) = m_.block(i0, j0, n0, m0);
110 }
111 
113  if (out->full()->m_ == m_) {
114  m_.transposeInPlace();
115  } else {
116  out->full()->m_ = m_.transpose();
117  }
118 }
119 
120 // As only symmetric matrix are accepted, eigenvalues are not complex
121 void OcFullMatrix::symmeigen(Matrix* mout, Vect* vout) const {
122  auto v1 = Vect2VEC(vout);
123  Eigen::EigenSolver<Eigen::MatrixXd> es(m_);
124  v1 = es.eigenvalues().real();
125  mout->full()->m_ = es.eigenvectors().real();
126 }
127 
128 void OcFullMatrix::svd1(Matrix* u, Matrix* v, Vect* d) const {
129  auto v1 = Vect2VEC(d);
130  Eigen::JacobiSVD<Eigen::MatrixXd> svd(m_, Eigen::ComputeFullU | Eigen::ComputeFullV);
131  v1 = svd.singularValues();
132  if (u) {
133  u->full()->m_ = svd.matrixU().transpose();
134  }
135  if (v) {
136  v->full()->m_ = svd.matrixV().transpose();
137  }
138 }
139 
140 void OcFullMatrix::getrow(int k, Vect* out) const {
141  auto v1 = Vect2VEC(out);
142  v1 = m_.row(k);
143 }
144 
145 void OcFullMatrix::getcol(int k, Vect* out) const {
146  auto v1 = Vect2VEC(out);
147  v1 = m_.col(k);
148 }
149 
150 void OcFullMatrix::getdiag(int k, Vect* out) const {
151  auto vout = m_.diagonal(k);
152  if (k >= 0) {
153  for (int i = 0, j = k; i < nrow() && j < ncol(); ++i, ++j) {
154  out->elem(i) = vout(i);
155  }
156  } else {
157  for (int i = -k, j = 0; i < nrow() && j < ncol(); ++i, ++j) {
158  out->elem(i) = vout(j);
159  }
160  }
161 }
162 
163 void OcFullMatrix::setrow(int k, Vect* in) {
164  auto v1 = Vect2VEC(in);
165  m_.block(k, 0, 1, v1.size()) = v1.transpose();
166 }
167 
168 void OcFullMatrix::setcol(int k, Vect* in) {
169  auto v1 = Vect2VEC(in);
170  m_.block(0, k, v1.size(), 1) = v1;
171 }
172 
173 void OcFullMatrix::setdiag(int k, Vect* in) {
174  auto out = m_.diagonal(k);
175  if (k >= 0) {
176  for (int i = 0, j = k; i < nrow() && j < ncol() && i < in->size(); ++i, ++j) {
177  out(i) = in->elem(i);
178  }
179  } else {
180  for (int i = -k, j = 0; i < nrow() && j < ncol() && i < in->size(); ++i, ++j) {
181  out(j) = in->elem(i);
182  }
183  }
184  m_.diagonal(k) = out;
185 }
186 
187 void OcFullMatrix::setrow(int k, double in) {
188  m_.row(k).fill(in);
189 }
190 
191 void OcFullMatrix::setcol(int k, double in) {
192  m_.col(k).fill(in);
193 }
194 
195 void OcFullMatrix::setdiag(int k, double in) {
196  m_.diagonal(k).fill(in);
197 }
198 
200  m_.setZero();
201 }
202 
204  m_.setIdentity();
205 }
206 
207 void OcFullMatrix::exp(Matrix* out) const {
208  out->full()->m_ = m_.exp();
209 }
210 
211 void OcFullMatrix::pow(int i, Matrix* out) const {
212  out->full()->m_ = m_.pow(i).eval();
213 }
214 
215 void OcFullMatrix::inverse(Matrix* out) const {
216  out->full()->m_ = m_.inverse();
217 }
218 
219 void OcFullMatrix::solv(Vect* in, Vect* out, bool use_lu) {
220  if (!lu_ || !use_lu || lu_->rows() != m_.rows()) {
221  lu_ = std::make_unique<Eigen::FullPivLU<decltype(m_)>>(m_);
222  }
223  auto v1 = Vect2VEC(in);
224  auto v2 = Vect2VEC(out);
225  v2 = lu_->solve(v1);
226 }
227 
228 double OcFullMatrix::det(int* e) const {
229  *e = 0;
230  double m = m_.determinant();
231  if (m) {
232  while (std::abs(m) >= 10.0) {
233  m *= 0.1;
234  *e += 1;
235  }
236  while (std::abs(m) < 1.0) {
237  m *= 10.0;
238  *e -= 1;
239  }
240  }
241  return m;
242 }
243 
244 //--------------------------
245 
247  : OcMatrix(MSPARSE)
248  , m_(nrow, ncol) {}
249 
250 double& OcSparseMatrix::coeff(int i, int j) {
251  return m_.coeffRef(i, j);
252 }
253 
255  for (int k = 0; k < m_.outerSize(); ++k) {
256  for (decltype(m_)::InnerIterator it(m_, k); it; ++it) {
257  it.valueRef() = 0.;
258  }
259  }
260 }
261 
262 double OcSparseMatrix::getval(int i, int j) const {
263  return m_.coeff(i, j);
264 }
265 
266 int OcSparseMatrix::nrow() const {
267  return m_.rows();
268 }
269 
270 int OcSparseMatrix::ncol() const {
271  return m_.cols();
272 }
273 
274 void OcSparseMatrix::mulv(Vect* vin, Vect* vout) const {
275  auto v1 = Vect2VEC(vin);
276  auto v2 = Vect2VEC(vout);
277  v2 = m_ * v1;
278 }
279 
280 void OcSparseMatrix::solv(Vect* in, Vect* out, bool use_lu) {
281  if (!lu_ || !use_lu || lu_->rows() != m_.rows()) {
282  m_.makeCompressed();
283  lu_ = std::make_unique<Eigen::SparseLU<decltype(m_)>>(m_);
284  }
285  auto v1 = Vect2VEC(in);
286  auto v2 = Vect2VEC(out);
287  v2 = lu_->solve(v1);
288 }
289 
290 void OcSparseMatrix::setrow(int k, Vect* in) {
291  int col = m_.cols();
292  for (int i = 0; i < col; ++i) {
293  m_.coeffRef(k, i) = in->elem(i);
294  }
295 }
296 
297 void OcSparseMatrix::setcol(int k, Vect* in) {
298  int row = m_.rows();
299  for (int i = 0; i < row; ++i) {
300  m_.coeffRef(i, k) = in->elem(i);
301  }
302 }
303 
305  int row = m_.rows();
306  int col = m_.cols();
307  if (k >= 0) {
308  for (int i = 0, j = k; i < row && j < col; ++i, ++j) {
309  m_.coeffRef(i, j) = in->elem(i);
310  }
311  } else {
312  for (int i = -k, j = 0; i < row && j < col; ++i, ++j) {
313  m_.coeffRef(i, j) = in->elem(i);
314  }
315  }
316 }
317 
318 void OcSparseMatrix::setrow(int k, double in) {
319  int col = m_.cols();
320  for (int i = 0; i < col; ++i) {
321  m_.coeffRef(k, i) = in;
322  }
323 }
324 
325 void OcSparseMatrix::setcol(int k, double in) {
326  int row = m_.rows();
327  for (int i = 0; i < row; ++i) {
328  m_.coeffRef(i, k) = in;
329  }
330 }
331 
333  m_.setIdentity();
334 }
335 
336 void OcSparseMatrix::setdiag(int k, double in) {
337  int row = m_.rows();
338  int col = m_.cols();
339  if (k >= 0) {
340  for (int i = 0, j = k; i < row && j < col; ++i, ++j) {
341  m_.coeffRef(i, j) = in;
342  }
343  } else {
344  for (int i = -k, j = 0; i < row && j < col; ++i, ++j) {
345  m_.coeffRef(i, j) = in;
346  }
347  }
348 }
349 
350 int OcSparseMatrix::sprowlen(int i) const {
351  int acc = 0;
352  for (decltype(m_)::InnerIterator it(m_, i); it; ++it) {
353  acc += 1;
354  }
355  return acc;
356 }
357 
358 double OcSparseMatrix::spgetrowval(int i, int jindx, int* j) const {
359  int acc = 0;
360  for (decltype(m_)::InnerIterator it(m_, i); it; ++it) {
361  if (acc == jindx) {
362  *j = it.col();
363  return it.value();
364  }
365  acc += 1;
366  }
367  return 0;
368 }
369 
370 std::vector<std::pair<int, int>> OcSparseMatrix::nonzeros() const {
371  std::vector<std::pair<int, int>> nzs;
372  nzs.reserve(m_.nonZeros());
373  for (int k = 0; k < m_.outerSize(); ++k) {
374  for (decltype(m_)::InnerIterator it(m_, k); it; ++it) {
375  nzs.emplace_back(it.row(), it.col());
376  }
377  }
378  return nzs;
379 }
double const * data() const
Definition: ivocvect.h:34
size_t size() const
Definition: ivocvect.h:42
double & elem(int n)
Definition: ivocvect.h:26
double getval(int i, int j) const override
Definition: ocmatrix.cpp:70
void exp(Matrix *out) const override
Definition: ocmatrix.cpp:207
void mulm(Matrix *in, Matrix *out) const override
Definition: ocmatrix.cpp:92
void ident() override
Definition: ocmatrix.cpp:203
void solv(Vect *vin, Vect *vout, bool use_lu) override
Definition: ocmatrix.cpp:219
int nrow() const override
Definition: ocmatrix.cpp:73
void getcol(int, Vect *out) const override
Definition: ocmatrix.cpp:145
double & coeff(int, int) override
Definition: ocmatrix.cpp:67
void inverse(Matrix *out) const override
Definition: ocmatrix.cpp:215
Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor > m_
Definition: ocmatrix.h:204
void setrow(int, Vect *in) override
Definition: ocmatrix.cpp:163
void pow(int, Matrix *out) const override
Definition: ocmatrix.cpp:211
void bcopy(Matrix *mout, int i0, int j0, int n0, int m0, int i1, int j1) const override
Definition: ocmatrix.cpp:108
int ncol() const override
Definition: ocmatrix.cpp:76
void mulv(Vect *in, Vect *out) const override
Definition: ocmatrix.cpp:86
std::unique_ptr< Eigen::FullPivLU< decltype(m_)> > lu_
Definition: ocmatrix.h:205
void resize(int, int) override
Definition: ocmatrix.cpp:80
void transpose(Matrix *out) override
Definition: ocmatrix.cpp:112
void symmeigen(Matrix *mout, Vect *vout) const override
Definition: ocmatrix.cpp:121
void add(Matrix *, Matrix *out) const override
Definition: ocmatrix.cpp:100
double det(int *exponent) const override
Definition: ocmatrix.cpp:228
void getrow(int, Vect *out) const override
Definition: ocmatrix.cpp:140
void setcol(int, Vect *in) override
Definition: ocmatrix.cpp:168
void muls(double, Matrix *out) const override
Definition: ocmatrix.cpp:96
void zero() override
Definition: ocmatrix.cpp:199
void getdiag(int, Vect *out) const override
Definition: ocmatrix.cpp:150
void setdiag(int, Vect *in) override
Definition: ocmatrix.cpp:173
void copy(Matrix *out) const override
Definition: ocmatrix.cpp:104
void svd1(Matrix *u, Matrix *v, Vect *d) const override
Definition: ocmatrix.cpp:128
OcFullMatrix(int, int)
Definition: ocmatrix.cpp:60
@ MFULL
Definition: ocmatrix.h:20
@ MSPARSE
Definition: ocmatrix.h:20
virtual int nrow() const
Definition: ocmatrix.h:48
int type_
Definition: ocmatrix.h:161
static OcMatrix * instance(int nrow, int ncol, int type=MFULL)
Definition: ocmatrix.cpp:27
OcFullMatrix * full()
Definition: ocmatrix.cpp:53
OcMatrix(int type)
Definition: ocmatrix.cpp:24
virtual int ncol() const
Definition: ocmatrix.h:52
virtual std::vector< std::pair< int, int > > nonzeros() const
Definition: ocmatrix.cpp:41
void unimp() const
Definition: ocmatrix.cpp:37
virtual double getval(int i, int j) const
Definition: ocmatrix.h:44
int sprowlen(int) const override
Definition: ocmatrix.cpp:350
std::vector< std::pair< int, int > > nonzeros() const override
Definition: ocmatrix.cpp:370
int nrow() const override
Definition: ocmatrix.cpp:266
Eigen::SparseMatrix< double, Eigen::RowMajor > m_
Definition: ocmatrix.h:236
void mulv(Vect *in, Vect *out) const override
Definition: ocmatrix.cpp:274
double spgetrowval(int i, int jindx, int *j) const override
Definition: ocmatrix.cpp:358
double getval(int, int) const override
Definition: ocmatrix.cpp:262
void setdiag(int, Vect *in) override
Definition: ocmatrix.cpp:304
int ncol() const override
Definition: ocmatrix.cpp:270
OcSparseMatrix(int, int)
Definition: ocmatrix.cpp:246
void setcol(int, Vect *in) override
Definition: ocmatrix.cpp:297
double & coeff(int, int) override
Definition: ocmatrix.cpp:250
std::unique_ptr< Eigen::SparseLU< decltype(m_)> > lu_
Definition: ocmatrix.h:237
void setrow(int, Vect *in) override
Definition: ocmatrix.cpp:290
void solv(Vect *vin, Vect *vout, bool use_lu) override
Definition: ocmatrix.cpp:280
void ident() override
Definition: ocmatrix.cpp:332
void zero() override
Definition: ocmatrix.cpp:254
#define v
Definition: md1redef.h:11
#define i
Definition: md1redef.h:19
static RNG::key_type k
Definition: nrnran123.cpp:9
void hoc_execerror(const char *s1, const char *s2)
Definition: nrnoc_aux.cpp:39
static unsigned row
Definition: nonlin.cpp:78
size_t j
s
Definition: multisend.cpp:521
short type
Definition: cabvars.h:10
HOC interpreter function declarations (included by hocdec.h)
static Eigen::Map< Eigen::VectorXd > Vect2VEC(Vect *v1)
Definition: ocmatrix.cpp:20
int nrn_matrix_dim(void *vm, int d)
Definition: ocmatrix.cpp:15