csparse_cholesky_interface.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  *
9  * CasADi is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 3 of the License, or (at your option) any later version.
13  *
14  * CasADi is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with CasADi; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22  *
23  */
24 
25 
26 #include "csparse_cholesky_interface.hpp"
27 
29 
30 namespace casadi {
31 
32  extern "C"
33  int CASADI_LINSOL_CSPARSECHOLESKY_EXPORT
34  casadi_register_linsol_csparsecholesky(LinsolInternal::Plugin* plugin) {
35  plugin->creator = CSparseCholeskyInterface::creator;
36  plugin->name = "csparsecholesky";
37  plugin->doc = CSparseCholeskyInterface::meta_doc.c_str();
38  plugin->version = CASADI_VERSION;
39  plugin->options = &CSparseCholeskyInterface::options_;
40  plugin->deserialize = &CSparseCholeskyInterface::deserialize;
41  return 0;
42  }
43 
44  extern "C"
45  void CASADI_LINSOL_CSPARSECHOLESKY_EXPORT casadi_load_linsol_csparsecholesky() {
46  LinsolInternal::registerPlugin(casadi_register_linsol_csparsecholesky);
47  }
48 
50  CSparseCholeskyInterface(const std::string& name, const Sparsity& sp) :
51  LinsolInternal(name, sp) {
52  }
53 
54  CSparseCholeskyInterface::~CSparseCholeskyInterface() {
55  clear_mem();
56  }
57 
58  CsparseCholMemory::~CsparseCholMemory() {
59  if (this->S) cs_sfree(this->S);
60  if (this->L) cs_nfree(this->L);
61  }
62 
63  void CSparseCholeskyInterface::init(const Dict& opts) {
64  // Call the init method of the base class
65  LinsolInternal::init(opts);
66  }
67 
68  int CSparseCholeskyInterface::init_mem(void* mem) const {
69  if (LinsolInternal::init_mem(mem)) return 1;
70  auto m = static_cast<CsparseCholMemory*>(mem);
71 
72  m->L = nullptr;
73  m->S = nullptr;
74  m->A.nzmax = this->nnz(); // maximum number of entries
75  m->A.m = this->nrow(); // number of columns
76  m->A.n = this->ncol(); // number of rows
77  m->colind.resize(m->A.n+1);
78  m->row.resize(this->nnz());
79  copy_vector(this->colind(), m->colind);
80  copy_vector(this->row(), m->row);
81  m->row.resize(m->A.nzmax);
82  m->A.p = get_ptr(m->colind); // row pointers (size n+1)
83  // or row indices (size nzmax)
84  m->A.i = get_ptr(m->row); // column indices, size nzmax
85  m->A.x = nullptr; // numerical values, size nzmax
86  m->A.nz = -1; // of entries in triplet matrix, -1 for compressed-row
87 
88  // Temporary
89  m->temp.resize(m->A.n);
90 
91  return 0;
92  }
93 
94  int CSparseCholeskyInterface::sfact(void* mem, const double* A) const {
95  auto m = static_cast<CsparseCholMemory*>(mem);
96 
97  // Set the nonzeros of the matrix
98  m->A.x = const_cast<double*>(A);
99 
100  // ordering and symbolic analysis
101  casadi_int order = 0; // ordering?
102  m->S = cs_schol(order, &m->A);
103  return 0;
104  }
105 
106  int CSparseCholeskyInterface::nfact(void* mem, const double* A) const {
107  auto m = static_cast<CsparseCholMemory*>(mem);
108  // Set the nonzeros of the matrix
109  m->A.x = const_cast<double*>(A);
110 
111  // Make sure that all entries of the linear system are valid
112  casadi_int nnz = this->nnz();
113  for (casadi_int k=0; k<nnz; ++k) {
114  casadi_assert(!isnan(A[k]),
115  "Nonzero " + str(k) + " is not-a-number");
116  casadi_assert(!isinf(A[k]),
117  "Nonzero " + str(k) + " is infinite");
118  }
119 
120  if (m->L) cs_nfree(m->L);
121  m->L = cs_chol(&m->A, m->S) ; // numeric Cholesky factorization
122  casadi_assert_dev(m->L!=nullptr);
123  return 0;
124  }
125 
126  int CSparseCholeskyInterface::
127  solve(void* mem, const double* A, double* x, casadi_int nrhs, bool tr) const {
128  auto m = static_cast<CsparseCholMemory*>(mem);
129 
130  casadi_assert_dev(m->L!=nullptr);
131 
132  double *t = &m->temp.front();
133  for (casadi_int k=0; k<nrhs; ++k) {
134  if (tr) {
135  cs_pvec(m->S->q, x, t, m->A.n) ; // t = P1\b
136  cs_ltsolve(m->L->L, t) ; // t = L\t
137  cs_lsolve(m->L->L, t) ; // t = U\t
138  cs_pvec(m->L->pinv, t, x, m->A.n) ; // x = P2\t
139  } else {
140  cs_ipvec(m->L->pinv, x, t, m->A.n) ; // t = P1\b
141  cs_lsolve(m->L->L, t) ; // t = L\t
142  cs_ltsolve(m->L->L, t) ; // t = U\t
143  cs_ipvec(m->S->q, t, x, m->A.n) ; // x = P2\t
144  }
145  x += this->ncol();
146  }
147  return 0;
148  }
149 
150 } // namespace casadi
151 
static const std::string meta_doc
A documentation string.
CSparseCholeskyInterface(const std::string &name, const Sparsity &sp)
static ProtoFunction * deserialize(DeserializingStream &s)
Deserialize with type disambiguation.
static LinsolInternal * creator(const std::string &name, const Sparsity &sp)
Create a new LinsolInternal.
static void registerPlugin(const Plugin &plugin, bool needs_lock=true)
Register an integrator in the factory.
static const Options options_
Options.
The casadi namespace.
Definition: archiver.cpp:28
void copy_vector(const std::vector< S > &s, std::vector< D > &d)
std::string str(const T &v)
String representation, any type.
T * get_ptr(std::vector< T > &v)
Get a pointer to the data contained in the vector.