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  else
135  m->equed = 'N';
136  }
137 
138  // Factorize the matrix
139  int info = -100;
140  dgetrf_(&ncol, &ncol, get_ptr(m->mat), &ncol, get_ptr(m->ipiv), &info);
141  if (info) {
142  if (verbose_) casadi_warning("dgetrf_ failed: Info: " + str(info));
143  return 1;
144  }
145  return 0;
146  }
147 
148  int LapackLu::solve(void* mem, const double* A, double* x, casadi_int nrhs, bool tr) const {
149  auto m = static_cast<LapackLuMemory*>(mem);
150 
151  // Dimensions
152  int nrow = this->nrow();
153  int ncol = this->ncol();
154 
155  int n_rhs = nrhs;
156 
157  // Scale the right hand side
158  if (tr) {
159  if (m->equed=='C' || m->equed=='B')
160  for (casadi_int rhs=0; rhs<nrhs; ++rhs)
161  for (casadi_int i=0; i<nrow; ++i)
162  x[i+rhs*nrow] *= m->c[i];
163  } else {
164  if (m->equed=='R' || m->equed=='B')
165  for (casadi_int rhs=0; rhs<nrhs; ++rhs)
166  for (casadi_int i=0; i<ncol; ++i)
167  x[i+rhs*nrow] *= m->r[i];
168  }
169 
170  // Solve the system of equations
171  int info = 100;
172  char trans = tr ? 'T' : 'N';
173  dgetrs_(&trans, &ncol, &n_rhs, get_ptr(m->mat), &ncol, get_ptr(m->ipiv), x, &ncol, &info);
174  if (info) return 1;
175 
176  // Scale the solution
177  if (tr) {
178  if (m->equed=='R' || m->equed=='B')
179  for (casadi_int rhs=0; rhs<nrhs; ++rhs)
180  for (casadi_int i=0; i<ncol; ++i)
181  x[i+rhs*nrow] *= m->r[i];
182  } else {
183  if (m->equed=='C' || m->equed=='B')
184  for (casadi_int rhs=0; rhs<nrhs; ++rhs)
185  for (casadi_int i=0; i<nrow; ++i)
186  x[i+rhs*nrow] *= m->c[i];
187  }
188  return 0;
189  }
190 
192  s.version("LapackLu", 1);
193  s.unpack("LapackLu::equilibriate", equilibriate_);
194  s.unpack("LapackLu::allow_equilibration_failure", allow_equilibration_failure_);
195  }
196 
199  s.version("LapackLu", 1);
200  s.pack("LapackLu::equilibriate", equilibriate_);
201  s.pack("LapackLu::allow_equilibration_failure", allow_equilibration_failure_);
202  }
203 
204 } // 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:126
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
Definition: lapack_lu.cpp:197
~LapackLu() override
Destructor.
Definition: lapack_lu.cpp:56
bool equilibriate_
Equilibrate?
Definition: lapack_lu.hpp:133
int solve(void *mem, const double *A, double *x, casadi_int nrhs, bool tr) const override
Definition: lapack_lu.cpp:148
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:97
static LinsolInternal * creator(const std::string &name, const Sparsity &sp)
Create a new Linsol.
Definition: lapack_lu.hpp:88
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:136
static const std::string meta_doc
A documentation string.
Definition: lapack_lu.hpp:120
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:64
Options metadata for a class.
Definition: options.hpp:40