linsol_ldl.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 "linsol_ldl.hpp"
27 #include "casadi/core/global_options.hpp"
28 
29 namespace casadi {
30 
31  extern "C"
32  int CASADI_LINSOL_LDL_EXPORT
33  casadi_register_linsol_ldl(LinsolInternal::Plugin* plugin) {
34  plugin->creator = LinsolLdl::creator;
35  plugin->name = "ldl";
36  plugin->doc = LinsolLdl::meta_doc.c_str();
37  plugin->version = CASADI_VERSION;
38  plugin->options = &LinsolLdl::options_;
39  plugin->deserialize = &LinsolLdl::deserialize;
40  return 0;
41  }
42 
43  extern "C"
44  void CASADI_LINSOL_LDL_EXPORT casadi_load_linsol_ldl() {
46  }
47 
48  LinsolLdl::LinsolLdl(const std::string& name, const Sparsity& sp)
49  : LinsolInternal(name, sp) {
50  }
51 
53  clear_mem();
54  }
55 
58  {{"incomplete",
59  {OT_BOOL,
60  "Incomplete factorization, without any fill-in"}},
61  {"preordering",
62  {OT_BOOL,
63  "Approximate minimal degree (AMD) preordering"}}
64  }
65  };
66 
67  void LinsolLdl::init(const Dict& opts) {
68  // Call the init method of the base class
70 
71  // Default options
72  incomplete_ = false;
73  amd_ = true;
74 
75  // Read user options
76  for (auto&& op : opts) {
77  if (op.first=="incomplete") {
78  incomplete_ = op.second;
79  } else if (op.first=="amd") {
80  amd_ = op.second;
81  }
82  }
83 
84  // Symbolic factorization
85  if (incomplete_) {
86  if (amd_) {
87  // Incomplete LDL^T, AMD permutation
88  p_ = sp_.amd();
89  std::vector<casadi_int> tmp;
90  Sparsity Aperm = sp_.sub(p_, p_, tmp);
91  sp_Lt_ = triu(Aperm, false); // no fill-in
92  } else {
93  p_ = range(sp_.size1()); // no reordering
94  sp_Lt_ = triu(sp_, false); // no fill-in
95  }
96  } else {
97  // Regular LDL^T
98  sp_Lt_ = sp_.ldl(p_, amd_);
99  }
100  }
101 
102  int LinsolLdl::init_mem(void* mem) const {
103  if (LinsolInternal::init_mem(mem)) return 1;
104  auto m = static_cast<LinsolLdlMemory*>(mem);
105 
106  // Work vectors
107  casadi_int nrow = this->nrow();
108  m->d.resize(nrow);
109  m->l.resize(sp_Lt_.nnz());
110  m->w.resize(nrow);
111 
112  return 0;
113  }
114 
115  int LinsolLdl::sfact(void* mem, const double* A) const {
116  return 0;
117  }
118 
119  int LinsolLdl::nfact(void* mem, const double* A) const {
120  auto m = static_cast<LinsolLdlMemory*>(mem);
121  casadi_ldl(sp_, A, sp_Lt_, get_ptr(m->l), get_ptr(m->d), get_ptr(p_), get_ptr(m->w));
122  for (double d : m->d) {
123  if (d==0) casadi_warning("LDL factorization has zeros in D");
124  }
125  return 0;
126  }
127 
128  int LinsolLdl::solve(void* mem, const double* A, double* x, casadi_int nrhs, bool tr) const {
129  auto m = static_cast<LinsolLdlMemory*>(mem);
130  casadi_ldl_solve(x, nrhs, sp_Lt_, get_ptr(m->l), get_ptr(m->d), get_ptr(p_), get_ptr(m->w));
131  return 0;
132  }
133 
134  casadi_int LinsolLdl::neig(void* mem, const double* A) const {
135  // Count number of negative eigenvalues
136  auto m = static_cast<LinsolLdlMemory*>(mem);
137  casadi_int nrow = this->nrow();
138  casadi_int ret = 0;
139  for (casadi_int i=0; i<nrow; ++i) if (m->d[i]<0) ret++;
140  return ret;
141  }
142 
143  casadi_int LinsolLdl::rank(void* mem, const double* A) const {
144  // Count number of nonzero eigenvalues
145  auto m = static_cast<LinsolLdlMemory*>(mem);
146  casadi_int nrow = this->nrow();
147  casadi_int ret = 0;
148  for (casadi_int i=0; i<nrow; ++i) if (m->d[i]!=0) ret++;
149  return ret;
150  }
151 
152  void LinsolLdl::generate(CodeGenerator& g, const std::string& A, const std::string& x,
153  casadi_int nrhs, bool tr) const {
154  // Codegen the integer vectors
155  std::string sp = g.sparsity(sp_);
156  std::string sp_Lt = g.sparsity(sp_Lt_);
157  std::string p = g.constant(p_);
158 
159  // Place in block to avoid conflicts caused by local variables
160  g << "{\n";
161  g.comment("FIXME(@jaeandersson): Memory allocation can be avoided");
162  g << "casadi_real lt[" << sp_Lt_.nnz() << "], "
163  "d[" << nrow() << "], "
164  "w[" << nrow() << "];\n";
165 
166  // Factorize
167  g << g.ldl(sp, A, sp_Lt, "lt", "d", p, "w") << "\n";
168 
169  // Solve
170  g << g.ldl_solve(x, nrhs, sp_Lt, "lt", "d", p, "w") << "\n";
171 
172  // End of block
173  g << "}\n";
174  }
175 
177  s.version("LinsolLdl", 1);
178  s.unpack("LinsolLdl::p", p_);
179  s.unpack("LinsolLdl::sp_Lt", sp_Lt_);
180  }
181 
184  s.version("LinsolLdl", 1);
185  s.pack("LinsolLdl::p", p_);
186  s.pack("LinsolLdl::sp_Lt", sp_Lt_);
187  }
188 
189 } // namespace casadi
Helper class for C code generation.
void comment(const std::string &s)
Write a comment line (ignored if not verbose)
std::string constant(const std::vector< casadi_int > &v)
Represent an array constant; adding it when new.
std::string ldl_solve(const std::string &x, casadi_int nrhs, const std::string &sp_lt, const std::string &lt, const std::string &d, const std::string &p, const std::string &w)
LDL solve.
std::string ldl(const std::string &sp_a, const std::string &a, const std::string &sp_lt, const std::string &lt, const std::string &d, const std::string &p, const std::string &w)
LDL factorization.
std::string sparsity(const Sparsity &sp, bool canonical=true)
Helper class for Serialization.
void unpack(Sparsity &e)
Reconstruct an object from the input stream.
void version(const std::string &name, int v)
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.
int init_mem(void *mem) const override
Initalize memory block.
void init(const Dict &opts) override
Initialize.
Definition: linsol_ldl.cpp:67
casadi_int rank(void *mem, const double *A) const override
Matrix rank.
Definition: linsol_ldl.cpp:143
static const std::string meta_doc
A documentation string.
Definition: linsol_ldl.hpp:103
int solve(void *mem, const double *A, double *x, casadi_int nrhs, bool tr) const override
Definition: linsol_ldl.cpp:128
int nfact(void *mem, const double *A) const override
Numeric factorization.
Definition: linsol_ldl.cpp:119
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
Definition: linsol_ldl.cpp:182
static LinsolInternal * creator(const std::string &name, const Sparsity &sp)
Create a new LinsolInternal.
Definition: linsol_ldl.hpp:58
void generate(CodeGenerator &g, const std::string &A, const std::string &x, casadi_int nrhs, bool tr) const override
Generate C code.
Definition: linsol_ldl.cpp:152
LinsolLdl(const std::string &name, const Sparsity &sp)
Definition: linsol_ldl.cpp:48
casadi_int neig(void *mem, const double *A) const override
Number of negative eigenvalues.
Definition: linsol_ldl.cpp:134
~LinsolLdl() override
Definition: linsol_ldl.cpp:52
static const Options options_
Options.
Definition: linsol_ldl.hpp:67
std::vector< casadi_int > p_
Definition: linsol_ldl.hpp:112
int sfact(void *mem, const double *A) const override
Definition: linsol_ldl.cpp:115
static ProtoFunction * deserialize(DeserializingStream &s)
Deserialize with type disambiguation.
Definition: linsol_ldl.hpp:124
int init_mem(void *mem) const override
Initalize memory block.
Definition: linsol_ldl.cpp:102
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)
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
Sparsity sub(const std::vector< casadi_int > &rr, const std::vector< casadi_int > &cc, std::vector< casadi_int > &mapping, bool ind1=false) const
Get a submatrix.
Definition: sparsity.cpp:334
casadi_int size1() const
Get the number of rows.
Definition: sparsity.cpp:124
std::vector< casadi_int > amd() const
Approximate minimal degree preordering.
Definition: sparsity.cpp:707
casadi_int nnz() const
Get the number of (structural) non-zeros.
Definition: sparsity.cpp:148
Sparsity ldl(std::vector< casadi_int > &p, bool amd=true) const
Symbolic LDL factorization.
Definition: sparsity.cpp:621
The casadi namespace.
Definition: archiver.cpp:28
std::vector< casadi_int > range(casadi_int start, casadi_int stop, casadi_int step, casadi_int len)
Range function.
int CASADI_LINSOL_LDL_EXPORT casadi_register_linsol_ldl(LinsolInternal::Plugin *plugin)
Definition: linsol_ldl.cpp:33
GenericType::Dict Dict
C++ equivalent of Python's dict or MATLAB's struct.
void CASADI_LINSOL_LDL_EXPORT casadi_load_linsol_ldl()
Definition: linsol_ldl.cpp:44
T * get_ptr(std::vector< T > &v)
Get a pointer to the data contained in the vector.
Options metadata for a class.
Definition: options.hpp:40