lapack_lu.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_lu.hpp"
27 #include "../../core/casadi_misc.hpp"
28 
29 namespace casadi {
30 
31  extern "C"
32  int CASADI_LINSOL_LAPACKLU_EXPORT
33  casadi_register_linsol_lapacklu(LinsolInternal::Plugin* plugin) {
34  plugin->creator = LapackLu::creator;
35  plugin->name = "lapacklu";
36  plugin->doc = LapackLu::meta_doc.c_str();
37  plugin->version = CASADI_VERSION;
38  plugin->options = &LapackLu::options_;
39  plugin->deserialize = &LapackLu::deserialize;
40  return 0;
41  }
42 
43  extern "C"
44  void CASADI_LINSOL_LAPACKLU_EXPORT casadi_load_linsol_lapacklu() {
46  }
47 
48  LapackLu::LapackLu(const std::string& name, const Sparsity& sp)
49  : LinsolInternal(name, sp) {
50 
51  // Default options
52  equilibriate_ = true;
54  }
55 
57  clear_mem();
58  }
59 
62  {{"equilibration",
63  {OT_BOOL,
64  "Equilibrate the matrix"}},
65  {"allow_equilibration_failure",
66  {OT_BOOL,
67  "Non-fatal error when equilibration fails"}}
68  }
69  };
70 
71  void LapackLu::init(const Dict& opts) {
72  // Call the base class initializer
74 
75  // Read options
76  for (auto&& op : opts) {
77  if (op.first=="equilibration") {
78  equilibriate_ = op.second;
79  } else if (op.first=="allow_equilibration_failure") {
80  allow_equilibration_failure_ = op.second;
81  }
82  }
83  }
84 
85  int LapackLu::init_mem(void* mem) const {
86  if (LinsolInternal::init_mem(mem)) return 0;
87  auto m = static_cast<LapackLuMemory*>(mem);
88 
89  // Allocate matrix
90  m->mat.resize(nrow() * ncol());
91  m->ipiv.resize(ncol());
92 
93  // Equilibration
94  if (equilibriate_) {
95  m->r.resize(nrow());
96  m->c.resize(ncol());
97  }
98  m->equed = 'N'; // No equilibration
99  return 0;
100  }
101 
102  int LapackLu::nfact(void* mem, const double* A) const {
103  auto m = static_cast<LapackLuMemory*>(mem);
104 
105  // Dimensions
106  int nrow = this->nrow();
107  int ncol = this->ncol();
108 
109  // Get the elements of the matrix, dense format
110  casadi_densify(A, sp_, get_ptr(m->mat), false);
111 
112  if (equilibriate_) {
113  // Calculate the col and row scaling factors
114  double colcnd, rowcnd; // ratio of the smallest to the largest col/row scaling factor
115  double amax; // absolute value of the largest matrix element
116  int info = -100;
117  dgeequ_(&ncol, &nrow, get_ptr(m->mat), &ncol, get_ptr(m->r),
118  get_ptr(m->c), &colcnd, &rowcnd, &amax, &info);
119  if (info < 0) return 1;
120  if (info > 0) {
121  std::stringstream ss;
122  ss << "LapackLu::prepare: ";
123  if (info<=ncol) ss << (info-1) << "-th row (zero-based) is exactly zero";
124  else ss << (info-1-ncol) << "-th col (zero-based) is exactly zero";
125  uout() << "Warning: " << ss.str() << std::endl;
126  if (allow_equilibration_failure_) uout() << "Warning: " << ss.str() << std::endl;
127  else casadi_error(ss.str());
128  }
129 
130  // Equilibrate the matrix if scaling was successful
131  if (info!=0)
132  dlaqge_(&ncol, &nrow, get_ptr(m->mat), &ncol, get_ptr(m->r), get_ptr(m->c),
133  &colcnd, &rowcnd, &amax, &m->equed
134  CASADI_LAPACK_CHARLEN_1);
135  else
136  m->equed = 'N';
137  }
138 
139  // Factorize the matrix
140  int info = -100;
141  dgetrf_(&ncol, &ncol, get_ptr(m->mat), &ncol, get_ptr(m->ipiv), &info);
142  if (info) {
143  if (verbose_) casadi_warning("dgetrf_ failed: Info: " + str(info));
144  return 1;
145  }
146  return 0;
147  }
148 
149  int LapackLu::solve(void* mem, const double* A, double* x, casadi_int nrhs, bool tr) const {
150  auto m = static_cast<LapackLuMemory*>(mem);
151 
152  // Dimensions
153  int nrow = this->nrow();
154  int ncol = this->ncol();
155 
156  int n_rhs = nrhs;
157 
158  // Scale the right hand side
159  if (tr) {
160  if (m->equed=='C' || m->equed=='B')
161  for (casadi_int rhs=0; rhs<nrhs; ++rhs)
162  for (casadi_int i=0; i<nrow; ++i)
163  x[i+rhs*nrow] *= m->c[i];
164  } else {
165  if (m->equed=='R' || m->equed=='B')
166  for (casadi_int rhs=0; rhs<nrhs; ++rhs)
167  for (casadi_int i=0; i<ncol; ++i)
168  x[i+rhs*nrow] *= m->r[i];
169  }
170 
171  // Solve the system of equations
172  int info = 100;
173  char trans = tr ? 'T' : 'N';
174  dgetrs_(&trans, &ncol, &n_rhs, get_ptr(m->mat), &ncol, get_ptr(m->ipiv), x, &ncol, &info
175  CASADI_LAPACK_CHARLEN_1);
176  if (info) return 1;
177 
178  // Scale the solution
179  if (tr) {
180  if (m->equed=='R' || m->equed=='B')
181  for (casadi_int rhs=0; rhs<nrhs; ++rhs)
182  for (casadi_int i=0; i<ncol; ++i)
183  x[i+rhs*nrow] *= m->r[i];
184  } else {
185  if (m->equed=='C' || m->equed=='B')
186  for (casadi_int rhs=0; rhs<nrhs; ++rhs)
187  for (casadi_int i=0; i<nrow; ++i)
188  x[i+rhs*nrow] *= m->c[i];
189  }
190  return 0;
191  }
192 
194  s.version("LapackLu", 1);
195  s.unpack("LapackLu::equilibriate", equilibriate_);
196  s.unpack("LapackLu::allow_equilibration_failure", allow_equilibration_failure_);
197  }
198 
201  s.version("LapackLu", 1);
202  s.pack("LapackLu::equilibriate", equilibriate_);
203  s.pack("LapackLu::allow_equilibration_failure", allow_equilibration_failure_);
204  }
205 
206 } // namespace casadi
Helper class for Serialization.
void unpack(Sparsity &e)
Reconstruct an object from the input stream.
void version(const std::string &name, int v)
static const Options options_
Options.
int init_mem(void *mem) const override
Initalize memory block.
Definition: lapack_lu.cpp:85
static ProtoFunction * deserialize(DeserializingStream &s)
Deserialize with type disambiguation.
Definition: lapack_lu.hpp:151
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
Definition: lapack_lu.cpp:199
~LapackLu() override
Destructor.
Definition: lapack_lu.cpp:56
bool equilibriate_
Equilibrate?
Definition: lapack_lu.hpp:158
int solve(void *mem, const double *A, double *x, casadi_int nrhs, bool tr) const override
Definition: lapack_lu.cpp:149
int nfact(void *mem, const double *A) const override
Numeric factorization.
Definition: lapack_lu.cpp:102
void init(const Dict &opts) override
Initialize the solver.
Definition: lapack_lu.cpp:71
static const Options options_
Options.
Definition: lapack_lu.hpp:122
static LinsolInternal * creator(const std::string &name, const Sparsity &sp)
Create a new Linsol.
Definition: lapack_lu.hpp:113
LapackLu(const std::string &name, const Sparsity &sp)
Definition: lapack_lu.cpp:48
bool allow_equilibration_failure_
Allow the equilibration to fail.
Definition: lapack_lu.hpp:161
static const std::string meta_doc
A documentation string.
Definition: lapack_lu.hpp:145
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 version(const std::string &name, int v)
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
int CASADI_LINSOL_LAPACKLU_EXPORT casadi_register_linsol_lapacklu(LinsolInternal::Plugin *plugin)
Definition: lapack_lu.cpp:33
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.
void CASADI_LINSOL_LAPACKLU_EXPORT casadi_load_linsol_lapacklu()
Definition: lapack_lu.cpp:44
T * get_ptr(std::vector< T > &v)
Get a pointer to the data contained in the vector.
std::ostream & uout()
std::vector< double > mat
Definition: lapack_lu.hpp:89
Options metadata for a class.
Definition: options.hpp:40