ma27_interface.cpp
1 
2 /*
3  * This file is part of CasADi.
4  *
5  * CasADi -- A symbolic framework for dynamic optimization.
6  * Copyright (C) 2010-2023 Joel Andersson, Joris Gillis, Moritz Diehl,
7  * KU Leuven. All rights reserved.
8  * Copyright (C) 2011-2014 Greg Horn
9  *
10  * CasADi is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 3 of the License, or (at your option) any later version.
14  *
15  * CasADi is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with CasADi; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23  *
24  */
25 
26 
27 #include "ma27_interface.hpp"
28 #include "casadi/core/global_options.hpp"
29 
30 namespace casadi {
31 
32  extern "C"
33  int CASADI_LINSOL_MA27_EXPORT
34  casadi_register_linsol_ma27(LinsolInternal::Plugin* plugin) {
35  plugin->creator = Ma27Interface::creator;
36  plugin->name = "ma27";
37  plugin->doc = Ma27Interface::meta_doc.c_str();
38  plugin->version = CASADI_VERSION;
39  plugin->options = &Ma27Interface::options_;
40  plugin->deserialize = &Ma27Interface::deserialize;
41  return 0;
42  }
43 
44  extern "C"
45  void CASADI_LINSOL_MA27_EXPORT casadi_load_linsol_ma27() {
47  }
48 
49  Ma27Interface::Ma27Interface(const std::string& name, const Sparsity& sp)
50  : LinsolInternal(name, sp) {
51  }
52 
54  clear_mem();
55  }
56 
57  void Ma27Interface::init(const Dict& opts) {
58  // Call the init method of the base class
60 
61  }
62 
63  int Ma27Interface::init_mem(void* mem) const {
64  if (LinsolInternal::init_mem(mem)) return 1;
65  auto m = static_cast<Ma27Memory*>(mem);
66 
67  // Set default options for MA27
68  ma27id_(m->icntl, m->cntl);
69  m->icntl[0] = 0; // Suppress error messages
70  m->icntl[1] = 0; // Suppress diagnostic messages
71  m->cntl[0] = 1e-8; // Set pivot tolerance
72 
73  // Dynamically resized work vectors
74  casadi_int N = this->ncol();
75  casadi_int nnz = this->nnz();
76  double liw_factor = 2;
77  m->iw.resize(ceil(liw_factor * (2*nnz+3*N+1)));
78  double la_factor = 2;
79  m->nz.resize(ceil(la_factor * nnz));
80  m->irn.resize(nnz);
81  m->jcn.resize(nnz);
82  m->iw1.resize(2*N);
83  m->ikeep.resize(3*N);
84  return 0;
85  }
86 
87  int Ma27Interface::nfact(void* mem, const double* A) const {
88  auto m = static_cast<Ma27Memory*>(mem);
89  casadi_assert_dev(A!=nullptr);
90 
91  // Get sparsity
92  const casadi_int ncol = this->ncol();
93  const casadi_int* colind = this->colind();
94  const casadi_int* row = this->row();
95 
96  // Get actual nonzeros
97  int nnz=0;
98  for (casadi_int cc=0; cc<ncol; ++cc) {
99  for (casadi_int el=colind[cc]; el<colind[cc+1]; ++el) {
100  casadi_int rr=row[el];
101  if (rr>cc) continue; // only upper triangular part
102  if (A[el]!=0) {
103  m->nz[nnz] = A[el];
104  m->irn[nnz] = rr+1;
105  m->jcn[nnz] = cc+1;
106  nnz++;
107  }
108  }
109  }
110  m->nnz = nnz;
111 
112  // Order of the matrix
113  int N = this->ncol();
114 
115  // Symbolic factorization (MA27AD)
116  int LIW = m->iw.size();
117  int iflag = 0;
118  int info[20];
119  double ops;
120  ma27ad_(&N, &nnz, get_ptr(m->irn), get_ptr(m->jcn), &m->iw[0], &LIW,
121  get_ptr(m->ikeep), get_ptr(m->iw1), &m->nsteps, &iflag, m->icntl, m->cntl,
122  info, &ops);
123  iflag = info[0]; // Information flag
124  casadi_int ierror = info[1]; // Error flag
125  //casadi_int nrlnec = info[4]; // recommended value for la
126  casadi_int nirnec = info[5]; // recommended value for liw
127  casadi_assert(iflag==0,
128  "ma27ad_ returns iflag = " + str(iflag) + " with ierror = " + str(ierror));
129 
130  // Allocate more memory?
131  double la_init_factor = 20.0; // This could be an option.
132  casadi_int la_min = ceil(la_init_factor * nirnec);
133  if (la_min > m->nz.size()) m->nz.resize(la_min);
134  double liw_init_factor = 5.0; // This could be an option.
135  casadi_int liw_min = ceil(liw_init_factor * nirnec);
136  if (liw_min > m->iw.size()) m->iw.resize(liw_min);
137 
138  // Numerical factorization (MA27BD)
139  int LA = m->nz.size();
140  LIW = m->iw.size();
141  ma27bd_(&N, &nnz, get_ptr(m->irn), get_ptr(m->jcn), get_ptr(m->nz),
142  &LA, get_ptr(m->iw), &LIW, get_ptr(m->ikeep), &m->nsteps,
143  &m->maxfrt, get_ptr(m->iw1), m->icntl, m->cntl, info);
144  iflag = info[0]; // Information flag
145  ierror = info[1]; // Error flag
146  m->neig = info[14]; // Number of negative eigenvalues
147  if (iflag == 3) {
148  m->rank = info[1];
149  } else if (iflag == -5) {
150  //DJ: I think this is more severe. Can this actually happen?
151  m->rank = -1;
152  } else if (iflag != 0) {
153  casadi_error("ma2bd_ returns iflag = " + str(iflag)
154  + " with ierror = " + str(ierror));
155  } else {
156  m->rank = N;
157  }
158 
159  // Real work array
160  if (m->w.size() < m->maxfrt) m->w.resize(m->maxfrt);
161  return 0;
162  }
163 
164  casadi_int Ma27Interface::neig(void* mem, const double* A) const {
165  auto m = static_cast<Ma27Memory*>(mem);
166  casadi_assert_dev(m->is_nfact);
167  return m->neig;
168  }
169 
170  casadi_int Ma27Interface::rank(void* mem, const double* A) const {
171  auto m = static_cast<Ma27Memory*>(mem);
172  casadi_assert_dev(m->is_nfact);
173  return m->rank;
174  }
175 
176  int Ma27Interface::solve(void* mem, const double* A, double* x, casadi_int nrhs, bool tr) const {
177  auto m = static_cast<Ma27Memory*>(mem);
178 
179  // Solve for each right-hand-side
180  int N = this->ncol();
181  int LA = m->nz.size();
182  int LIW = m->iw.size();
183  for (casadi_int k=0; k<nrhs; ++k) {
184  ma27cd_(&N, get_ptr(m->nz), &LA, get_ptr(m->iw), &LIW, get_ptr(m->w),
185  &m->maxfrt, x, get_ptr(m->iw1), &m->nsteps, m->icntl, m->cntl);
186  x += N;
187  }
188  return 0;
189  }
190 
192  nnz = -1;
193  neig = -1;
194  rank = -1;
195 
196  nsteps = -1;
197  maxfrt = -1;
198  }
199 
201  }
202 
203 } // namespace casadi
const casadi_int * colind() const
void init(const Dict &opts) override
Initialize.
const casadi_int * row() const
casadi_int nnz() const
casadi_int ncol() const
int init_mem(void *mem) const override
Initalize memory block.
Ma27Interface(const std::string &name, const Sparsity &sp)
casadi_int neig(void *mem, const double *A) const override
Number of negative eigenvalues.
int solve(void *mem, const double *A, double *x, casadi_int nrhs, bool tr) const override
static const std::string meta_doc
A documentation string.
casadi_int rank(void *mem, const double *A) const override
Matrix rank.
int nfact(void *mem, const double *A) const override
Numeric factorization.
void init(const Dict &opts) override
Initialize.
static ProtoFunction * deserialize(DeserializingStream &s)
Deserialize with type disambiguation.
int init_mem(void *mem) const override
Initalize memory block.
static LinsolInternal * creator(const std::string &name, const Sparsity &sp)
Create a new Linsol.
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)
General sparsity class.
Definition: sparsity.hpp:106
The casadi namespace.
Definition: archiver.cpp:28
void CASADI_LINSOL_MA27_EXPORT casadi_load_linsol_ma27()
std::string str(const T &v)
String representation, any type.
GenericType::Dict Dict
C++ equivalent of Python's dict or MATLAB's struct.
int CASADI_LINSOL_MA27_EXPORT casadi_register_linsol_ma27(LinsolInternal::Plugin *plugin)
T * get_ptr(std::vector< T > &v)
Get a pointer to the data contained in the vector.