lapack_qr.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 "lapack_qr.hpp"
27 #include "../../core/casadi_misc.hpp"
28 
29 namespace casadi {
30 
31  extern "C"
32  int CASADI_LINSOL_LAPACKQR_EXPORT
33  casadi_register_linsol_lapackqr(LinsolInternal::Plugin* plugin) {
34  plugin->creator = LapackQr::creator;
35  plugin->name = "lapackqr";
36  plugin->doc = LapackQr::meta_doc.c_str();;
37  plugin->version = CASADI_VERSION;
38  plugin->options = &LapackQr::options_;
39  plugin->deserialize = &LapackQr::deserialize;
40  return 0;
41  }
42 
43  extern "C"
44  void CASADI_LINSOL_LAPACKQR_EXPORT casadi_load_linsol_lapackqr() {
46  }
47 
48  LapackQr::LapackQr(const std::string& name, const Sparsity& sp) :
49  LinsolInternal(name, sp) {
50  }
51 
53  clear_mem();
54  }
55 
58  {{"max_nrhs",
59  {OT_INT,
60  "Maximum number of right-hand-sides that get processed in a single pass [default:10]."}}
61  }
62  };
63 
64  void LapackQr::init(const Dict& opts) {
65  // Call the base class initializer
67 
68  max_nrhs_ = 10;
69 
70  // Read options
71  for (auto&& op : opts) {
72  if (op.first=="max_nrhs") {
73  max_nrhs_ = op.second;
74  }
75  }
76  }
77 
78  int LapackQr::init_mem(void* mem) const {
79  if (LinsolInternal::init_mem(mem)) return 1;
80  auto m = static_cast<LapackQrMemory*>(mem);
81  m->mat.resize(ncol() * ncol());
82  m->tau.resize(ncol());
83  m->work.resize(std::max(max_nrhs_, ncol())*10);
84  return 0;
85  }
86 
87  int LapackQr::nfact(void* mem, const double* A) const {
88  auto m = static_cast<LapackQrMemory*>(mem);
89 
90  // Dimensions
91  //casadi_int nrow = this->nrow();
92  int ncol = this->ncol();
93 
94  // Get the elements of the matrix, dense format
95  casadi_densify(A, sp_, get_ptr(m->mat), false);
96 
97  // Factorize the matrix
98  int info = -100;
99  int lwork = m->work.size();
100  dgeqrf_(&ncol, &ncol, get_ptr(m->mat), &ncol, get_ptr(m->tau),
101  get_ptr(m->work), &lwork, &info);
102  if (info) {
103  if (verbose_) casadi_warning("dgeqrf_ failed: Info: " + str(info));
104  return 1;
105  }
106  return 0;
107  }
108 
109  int LapackQr::solve(void* mem, const double* A, double* x, casadi_int nrhs, bool tr) const {
110  auto m = static_cast<LapackQrMemory*>(mem);
111 
112  // Solve up to max_nrhs rhs at a time
113  casadi_int offset = 0;
114  while (nrhs>0) {
115  if (solve_batch(m, A, x+offset, std::min(max_nrhs_, nrhs), tr)) return 1;
116  nrhs-= max_nrhs_;
117  offset+= max_nrhs_*nrow();
118  }
119  return 0;
120  }
121 
122  int LapackQr::solve_batch(void* mem, const double* A, double* x, casadi_int nrhs, bool tr) const {
123  auto m = static_cast<LapackQrMemory*>(mem);
124 
125  // Dimensions
126  //casadi_int nrow = this->nrow();
127  int ncol = this->ncol();
128 
129  // Properties of R
130  char uploR = 'U';
131  char diagR = 'N';
132  char sideR = 'L';
133  double alphaR = 1.;
134  char transR = tr ? 'T' : 'N';
135 
136  // Properties of Q
137  char transQ = tr ? 'N' : 'T';
138  char sideQ = 'L';
139  int k = m->tau.size(); // minimum of ncol and nrow
140  int lwork = m->work.size();
141 
142  int n_rhs = nrhs;
143 
144  if (tr) {
145 
146  // Solve for transpose(R)
147  dtrsm_(&sideR, &uploR, &transR, &diagR, &ncol, &n_rhs, &alphaR,
148  get_ptr(m->mat), &ncol, x, &ncol);
149 
150  // Multiply by Q
151  int info = 100;
152  dormqr_(&sideQ, &transQ, &ncol, &n_rhs, &k, get_ptr(m->mat), &ncol, get_ptr(m->tau), x,
153  &ncol, get_ptr(m->work), &lwork, &info);
154  casadi_assert(info == 0,
155  "LapackQr::solve: dormqr_ A failed to solve the linear system. Info: " + str(info) + ".");
156  } else {
157 
158  // Multiply by transpose(Q)
159  int info = 100;
160  dormqr_(&sideQ, &transQ, &ncol, &n_rhs, &k, get_ptr(m->mat), &ncol, get_ptr(m->tau), x,
161  &ncol, get_ptr(m->work), &lwork, &info);
162  casadi_assert(info == 0,
163  "LapackQr::solve: dormqr_ B failed to solve the linear system. Info: " + str(info) + ".");
164 
165  // Solve for R
166  dtrsm_(&sideR, &uploR, &transR, &diagR, &ncol, &n_rhs, &alphaR,
167  get_ptr(m->mat), &ncol, x, &ncol);
168  }
169  return 0;
170  }
171 
173  s.unpack("LapackQr::max_nrhs", max_nrhs_);
174  }
175 
178  s.pack("LapackQr::max_nrhs", max_nrhs_);
179  }
180 
181 } // namespace casadi
Helper class for Serialization.
void unpack(Sparsity &e)
Reconstruct an object from the input stream.
static const Options options_
Options.
casadi_int max_nrhs_
Definition: lapack_qr.hpp:126
static LinsolInternal * creator(const std::string &name, const Sparsity &sp)
Create a new Linsol.
Definition: lapack_qr.hpp:82
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
Definition: lapack_qr.cpp:176
int init_mem(void *mem) const override
Initalize memory block.
Definition: lapack_qr.cpp:78
static ProtoFunction * deserialize(DeserializingStream &s)
Deserialize with type disambiguation.
Definition: lapack_qr.hpp:132
static const Options options_
Options.
Definition: lapack_qr.hpp:94
int nfact(void *mem, const double *A) const override
Numeric factorization.
Definition: lapack_qr.cpp:87
int solve(void *mem, const double *A, double *x, casadi_int nrhs, bool tr) const override
Definition: lapack_qr.cpp:109
~LapackQr() override
Definition: lapack_qr.cpp:52
void init(const Dict &opts) override
Initialize.
Definition: lapack_qr.cpp:64
int solve_batch(void *mem, const double *A, double *x, casadi_int nrhs, bool tr) const
Definition: lapack_qr.cpp:122
static const std::string meta_doc
A documentation string.
Definition: lapack_qr.hpp:117
LapackQr(const std::string &name, const Sparsity &sp)
Definition: lapack_qr.cpp:48
void init(const Dict &opts) override
Initialize.
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
casadi_int nrow() const
Get sparsity pattern.
casadi_int ncol() const
int init_mem(void *mem) const override
Initalize memory block.
static void registerPlugin(const Plugin &plugin, bool needs_lock=true)
Register an integrator in the factory.
bool verbose_
Verbose printout.
void clear_mem()
Clear all memory (called from destructor)
Helper class for Serialization.
void pack(const Sparsity &e)
Serializes an object to the output stream.
General sparsity class.
Definition: sparsity.hpp:106
The casadi namespace.
Definition: archiver.cpp:28
void CASADI_LINSOL_LAPACKQR_EXPORT casadi_load_linsol_lapackqr()
Definition: lapack_qr.cpp:44
std::string str(const T &v)
String representation, any type.
GenericType::Dict Dict
C++ equivalent of Python's dict or MATLAB's struct.
void casadi_densify(const T1 *x, const casadi_int *sp_x, T2 *y, casadi_int tr)
Convert sparse to dense.
T * get_ptr(std::vector< T > &v)
Get a pointer to the data contained in the vector.
int CASADI_LINSOL_LAPACKQR_EXPORT casadi_register_linsol_lapackqr(LinsolInternal::Plugin *plugin)
Definition: lapack_qr.cpp:33
std::vector< double > mat
Definition: lapack_qr.hpp:61
Options metadata for a class.
Definition: options.hpp:40