linsol_tridiag.cpp
1 /*
2  * This file is part of CasADi.
3  *
4  * CasADi -- A symbolic framework for dynamic optimization.
5  * Copyright (C) 2010-2023 Joel Andersson, Joris Gillis, Moritz Diehl,
6  * KU Leuven. All rights reserved.
7  * Copyright (C) 2011-2014 Greg Horn
8  * Copyright (C) 2019 Jorn Baayen, KISTERS AG
9  *
10  * CasADi is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 3 of the License, or (at your option) any later version.
14  *
15  * CasADi is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with CasADi; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23  *
24  */
25 
26 #include <iostream>
27 #include "linsol_tridiag.hpp"
28 #include "casadi/core/global_options.hpp"
29 
30 namespace casadi {
31 
32  extern "C"
33  int CASADI_LINSOL_TRIDIAG_EXPORT
34  casadi_register_linsol_tridiag(LinsolInternal::Plugin* plugin) {
35  plugin->creator = LinsolTridiag::creator;
36  plugin->name = "tridiag";
37  plugin->doc = LinsolTridiag::meta_doc.c_str();
38  plugin->version = CASADI_VERSION;
39  plugin->options = &LinsolTridiag::options_;
40  return 0;
41  }
42 
43  extern "C"
44  void CASADI_LINSOL_TRIDIAG_EXPORT casadi_load_linsol_tridiag() {
46  }
47 
48  LinsolTridiag::LinsolTridiag(const std::string& name, const Sparsity& sp)
49  : LinsolInternal(name, sp) {
50  }
51 
53  clear_mem();
54  }
55 
56  void LinsolTridiag::init(const Dict& opts) {
57  // Call the init method of the base class
59  }
60 
61  int LinsolTridiag::init_mem(void* mem) const {
62  if (LinsolInternal::init_mem(mem)) return 1;
63  auto m = static_cast<LinsolTridiagMemory*>(mem);
64 
65  // Memory for numerical solution
66  m->c.resize(nrow());
67  m->ctr.resize(nrow());
68  m->d.resize(nrow());
69  return 0;
70  }
71 
72  int LinsolTridiag::sfact(void* mem, const double* A) const {
73  return 0;
74  }
75 
76  int LinsolTridiag::nfact(void* mem, const double* A) const {
77  auto m = static_cast<LinsolTridiagMemory*>(mem);
78  m->have_c = false;
79  m->have_ctr = false;
80  return 0;
81  }
82 
83  int LinsolTridiag::solve(void* mem, const double* A, double* x, casadi_int nrhs, bool tr) const {
84  auto m = static_cast<LinsolTridiagMemory*>(mem);
85  casadi_int i, k;
86  const casadi_int *a_colind;
87  // Extract sparsity
88  a_colind = sp_ + 2;
89  // Precompute cacheable coefficients
90  if (tr) {
91  if (!m->have_ctr) {
92  // Precompute coefficients (transposed matrix)
93  m->ctr[0] = A[a_colind[0] + 1] / A[a_colind[0] + 0];
94  for (i = 1; i < nrow(); i++) {
95  // A[i + 1, i] / (A[i, i] - A[i - 1, i] * m->ctr[i - 1]);
96  double denom = A[a_colind[i] + 1] - A[a_colind[i] + 0] * m->ctr[i - 1];
97  m->ctr[i] = A[a_colind[i] + 2] / denom;
98  }
99  m->have_ctr = true;
100  }
101  } else {
102  if (!m->have_c) {
103  // Precompute coefficients
104  m->c[0] = A[a_colind[1] + 0] / A[a_colind[0] + 0];
105  double denom = A[a_colind[1] + 1] - A[a_colind[1 - 1] + 1] * m->c[1 - 1];
106  m->c[1] = A[a_colind[1 + 1] + 0] / denom;
107  for (i = 2; i < nrow(); i++) {
108  // A[i, i + 1] / (A[i, i] - A[i, i - 1] * m->c[i - 1]);
109  double denom = A[a_colind[i] + 1] - A[a_colind[i - 1] + 2] * m->c[i - 1];
110  m->c[i] = A[a_colind[i + 1] + 0] / denom;
111  }
112  m->have_c = true;
113  }
114  }
115  // Compute
116  for (k = 0; k < nrhs; k++) {
117  if (tr) {
118  // Compute remaining coefficients (transposed matrix)
119  m->d[0] = x[0] / A[a_colind[0] + 0];
120  for (i = 1; i < nrow(); i++) {
121  //m->d[i] = (x[i] - A[i - 1, i] * m->d[i - 1]) / (A[i, i] - A[i - 1, i] * m->c[i - 1]);
122  double denom = A[a_colind[i] + 1] - A[a_colind[i] + 0] * m->ctr[i - 1];
123  m->d[i] = (x[i] - A[a_colind[i] + 0] * m->d[i - 1]) / denom;
124  }
125  // Solve
126  x[nrow() - 1] = m->d[nrow() - 1];
127  for (i = nrow() - 2; i >= 0; i--) {
128  x[i] = m->d[i] - m->ctr[i] * x[i + 1];
129  }
130  } else {
131  // Compute remaining coefficients
132  m->d[0] = x[0] / A[a_colind[0] + 0];
133  double denom = A[a_colind[1] + 1] - A[a_colind[1 - 1] + 1] * m->c[1 - 1];
134  m->d[1] = (x[1] - A[a_colind[1 - 1] + 1] * m->d[1 - 1]) / denom;
135  for (i = 2; i < nrow(); i++) {
136  //m->d[i] = (x[i] - A[i, i - 1] * m->d[i - 1]) / (A[i, i] - A[i, i - 1] * m->c[i - 1]);
137  double denom = A[a_colind[i] + 1] - A[a_colind[i - 1] + 2] * m->c[i - 1];
138  m->d[i] = (x[i] - A[a_colind[i - 1] + 2] * m->d[i - 1]) / denom;
139  }
140  // Solve
141  x[nrow() - 1] = m->d[nrow() - 1];
142  for (i = nrow() - 2; i >= 0; i--) {
143  x[i] = m->d[i] - m->c[i] * x[i + 1];
144  }
145  }
146  x += ncol();
147  }
148  return 0;
149  }
150 
151  void LinsolTridiag::generate(CodeGenerator& g, const std::string& A, const std::string& x,
152  casadi_int nrhs, bool tr) const {
153  casadi_error("Not implemented");
154  }
155 
156 } // namespace casadi
Helper class for C code generation.
void init(const Dict &opts) override
Initialize.
casadi_int nrow() const
Get sparsity pattern.
casadi_int ncol() const
int init_mem(void *mem) const override
Initalize memory block.
int nfact(void *mem, const double *A) const override
Numeric factorization.
static const std::string meta_doc
A documentation string.
int init_mem(void *mem) const override
Initalize memory block.
int solve(void *mem, const double *A, double *x, casadi_int nrhs, bool tr) const override
int sfact(void *mem, const double *A) const override
static LinsolInternal * creator(const std::string &name, const Sparsity &sp)
Create a new LinsolInternal.
void init(const Dict &opts) override
Initialize.
void generate(CodeGenerator &g, const std::string &A, const std::string &x, casadi_int nrhs, bool tr) const override
Generate C code.
LinsolTridiag(const std::string &name, const Sparsity &sp)
static void registerPlugin(const Plugin &plugin, bool needs_lock=true)
Register an integrator in the factory.
static const Options options_
Options.
void clear_mem()
Clear all memory (called from destructor)
General sparsity class.
Definition: sparsity.hpp:106
The casadi namespace.
Definition: archiver.cpp:28
int CASADI_LINSOL_TRIDIAG_EXPORT casadi_register_linsol_tridiag(LinsolInternal::Plugin *plugin)
GenericType::Dict Dict
C++ equivalent of Python's dict or MATLAB's struct.
void CASADI_LINSOL_TRIDIAG_EXPORT casadi_load_linsol_tridiag()
std::vector< double > c