User Guide
crout.hpp
Go to the documentation of this file.
1 /*
2  * Copyright 2023 Blue Brain Project, EPFL.
3  * See the top-level LICENSE file for details.
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #pragma once
9 
10 /**
11  * \dir
12  * \brief Solver for a system of linear equations : Crout matrix decomposition
13  *
14  * \file
15  * \brief Implementation of Crout matrix decomposition (LU decomposition) followed by
16  * Forward/Backward substitution: Implementation details : (Legacy code) nrn / scopmath / crout.c
17  */
18 
19 #include <Eigen/Core>
20 #include <cmath>
21 
22 #if defined(CORENEURON_ENABLE_GPU) && !defined(DISABLE_OPENACC)
23 #include "coreneuron/utils/offload.hpp"
24 #endif
25 
26 namespace nmodl {
27 namespace crout {
28 
29 /**
30  * \brief Crout matrix decomposition : in-place LU Decomposition of matrix a.
31  *
32  * Implementation details : (Legacy code) nrn / scopmath / crout.c
33  *
34  * Returns: 0 if no error; -1 if matrix is singular or ill-conditioned
35  */
36 #if defined(CORENEURON_ENABLE_GPU) && !defined(DISABLE_OPENACC)
37 nrn_pragma_acc(routine seq)
38 nrn_pragma_omp(declare target)
39 #endif
40 template <typename T>
41 EIGEN_DEVICE_FUNC inline int Crout(int n, T* const a, int* const perm, double* const rowmax) {
42  // roundoff is the minimal value for a pivot element without its being considered too close to
43  // zero
44  double roundoff = 1.e-20;
45  int i, j, k, r, pivot, irow, save_i = 0, krow;
46  T sum, equil_1, equil_2;
47 
48  /* Initialize permutation and rowmax vectors */
49 
50  for (i = 0; i < n; i++) {
51  perm[i] = i;
52  k = 0;
53  for (j = 1; j < n; j++) {
54  if (std::fabs(a[i * n + j]) > std::fabs(a[i * n + k])) {
55  k = j;
56  }
57  }
58  rowmax[i] = a[i * n + k];
59  }
60 
61  /* Loop over rows and columns r */
62 
63  for (r = 0; r < n; r++) {
64  /*
65  * Operate on rth column. This produces the lower triangular matrix
66  * of terms needed to transform the constant vector.
67  */
68 
69  for (i = r; i < n; i++) {
70  sum = 0.0;
71  irow = perm[i];
72  for (k = 0; k < r; k++) {
73  krow = perm[k];
74  sum += a[irow * n + k] * a[krow * n + r];
75  }
76  a[irow * n + r] -= sum;
77  }
78 
79  /* Find row containing the pivot in the rth column */
80 
81  pivot = perm[r];
82  equil_1 = std::fabs(a[pivot * n + r] / rowmax[pivot]);
83  for (i = r + 1; i < n; i++) {
84  irow = perm[i];
85  equil_2 = std::fabs(a[irow * n + r] / rowmax[irow]);
86  if (equil_2 > equil_1) {
87  /* make irow the new pivot row */
88 
89  pivot = irow;
90  save_i = i;
91  equil_1 = equil_2;
92  }
93  }
94 
95  /* Interchange entries in permutation vector if necessary */
96 
97  if (pivot != perm[r]) {
98  perm[save_i] = perm[r];
99  perm[r] = pivot;
100  }
101 
102  /* Check that pivot element is not too small */
103 
104  if (std::fabs(a[pivot * n + r]) < roundoff) {
105  return -1;
106  }
107 
108  /*
109  * Operate on row in rth position. This produces the upper
110  * triangular matrix whose diagonal elements are assumed to be unity.
111  * This matrix is used in the back substitution algorithm.
112  */
113 
114  for (j = r + 1; j < n; j++) {
115  sum = 0.0;
116  for (k = 0; k < r; k++) {
117  krow = perm[k];
118  sum += a[pivot * n + k] * a[krow * n + j];
119  }
120  a[pivot * n + j] = (a[pivot * n + j] - sum) / a[pivot * n + r];
121  }
122  }
123  return 0;
124 }
125 #if defined(CORENEURON_ENABLE_GPU) && !defined(DISABLE_OPENACC)
126 nrn_pragma_omp(end declare target)
127 #endif
128 
129 /**
130  * \brief Crout matrix decomposition : Forward/Backward substitution.
131  *
132  * Implementation details : (Legacy code) nrn / scopmath / crout.c
133  *
134  * Returns: no return variable
135  */
136 #define y_(arg) p[y[arg]]
137 #define b_(arg) b[arg]
138 #if defined(CORENEURON_ENABLE_GPU) && !defined(DISABLE_OPENACC)
139 nrn_pragma_acc(routine seq)
140 nrn_pragma_omp(declare target)
141 #endif
142 template <typename T>
143 EIGEN_DEVICE_FUNC inline int solveCrout(int n,
144  T const* const a,
145  T const* const b,
146  T* const p,
147  int const* const perm,
148  int const* const y = nullptr) {
149  int i, j, pivot;
150  T sum;
151 
152  /* Perform forward substitution with pivoting */
153  if (y) {
154  for (i = 0; i < n; i++) {
155  pivot = perm[i];
156  sum = 0.0;
157  for (j = 0; j < i; j++) {
158  sum += a[pivot * n + j] * (y_(j));
159  }
160  y_(i) = (b_(pivot) - sum) / a[pivot * n + i];
161  }
162 
163  /*
164  * Note that the y vector is already in the correct order for back
165  * substitution. Perform back substitution, pivoting the matrix but not
166  * the y vector. There is no need to divide by the diagonal element as
167  * this is assumed to be unity.
168  */
169 
170  for (i = n - 1; i >= 0; i--) {
171  pivot = perm[i];
172  sum = 0.0;
173  for (j = i + 1; j < n; j++) {
174  sum += a[pivot * n + j] * (y_(j));
175  }
176  y_(i) -= sum;
177  }
178  } else {
179  for (i = 0; i < n; i++) {
180  pivot = perm[i];
181  sum = 0.0;
182  for (j = 0; j < i; j++) {
183  sum += a[pivot * n + j] * (p[j]);
184  }
185  p[i] = (b_(pivot) - sum) / a[pivot * n + i];
186  }
187 
188  /*
189  * Note that the y vector is already in the correct order for back
190  * substitution. Perform back substitution, pivoting the matrix but not
191  * the y vector. There is no need to divide by the diagonal element as
192  * this is assumed to be unity.
193  */
194 
195  for (i = n - 1; i >= 0; i--) {
196  pivot = perm[i];
197  sum = 0.0;
198  for (j = i + 1; j < n; j++) {
199  sum += a[pivot * n + j] * (p[j]);
200  }
201  p[i] -= sum;
202  }
203  }
204  return 0;
205 }
206 #if defined(CORENEURON_ENABLE_GPU) && !defined(DISABLE_OPENACC)
207 nrn_pragma_omp(end declare target)
208 #endif
209 
210 #undef y_
211 #undef b_
212 
213 } // namespace crout
214 } // namespace nmodl
nmodl
encapsulates code generation backend implementations
Definition: ast_common.hpp:26
nmodl::crout::solveCrout
EIGEN_DEVICE_FUNC int solveCrout(int n, T const *const a, T const *const b, T *const p, int const *const perm, int const *const y=nullptr)
Definition: crout.hpp:143
b_
#define b_(arg)
Definition: crout.hpp:137
nmodl::crout::Crout
EIGEN_DEVICE_FUNC int Crout(int n, T *const a, int *const perm, double *const rowmax)
Crout matrix decomposition : in-place LU Decomposition of matrix a.
Definition: crout.hpp:41
y_
#define y_(arg)
Crout matrix decomposition : Forward/Backward substitution.
Definition: crout.hpp:136