sqic_interface.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 "sqic_interface.hpp"
27 #include "casadi/core/conic.hpp"
28 #include "casadi/core/mx_function.hpp"
29 #include "casadi/core/casadi_misc.hpp"
30 
31 #include "wsqic.hpp"
32 #include "casadi/interfaces/sqic/resource_sqic.hpp"
33 
34 namespace casadi {
35 
36  extern "C"
37  int CASADI_CONIC_SQIC_EXPORT
38  casadi_register_conic_sqic(Conic::Plugin* plugin) {
39  plugin->creator = SqicInterface::creator;
40  plugin->name = "sqic";
41  plugin->doc = SqicInterface::meta_doc.c_str();
42  plugin->version = CASADI_VERSION;
43  plugin->options = &SqicInterface::options_;
44  return 0;
45  }
46 
47  extern "C"
48  void CASADI_CONIC_SQIC_EXPORT casadi_load_conic_sqic() {
50  }
51 
52  SqicInterface::SqicInterface(const std::map<std::string, Sparsity>& st) : Conic(st) {
53  is_init_ = false;
54  }
55 
57  sqicDestroy();
58  }
59 
61  if (inputs_check_) {
62  check_inputs(input(CONIC_LBX).ptr(), input(CONIC_UBX).ptr(),
63  input(CONIC_LBA).ptr(), input(CONIC_UBA).ptr());
64  }
65 
66  std::copy(input(CONIC_X0)->begin(), input(CONIC_X0)->end(), x_.begin());
67  std::fill(x_.begin()+n_, x_.end(), 0);
68 
69  std::transform(input(CONIC_LAM_X0)->begin(), input(CONIC_LAM_X0)->end(),
70  rc_.begin(), negate<double>());
71  std::fill(rc_.begin()+n_, rc_.end(), 0);
72 
73  std::copy(input(CONIC_LBX)->begin(), input(CONIC_LBX)->end(), bl_.begin());
74  std::copy(input(CONIC_UBX)->begin(), input(CONIC_UBX)->end(), bu_.begin());
75 
76  std::copy(input(CONIC_LBA)->begin(), input(CONIC_LBA)->end(), bl_.begin()+n_);
77  std::copy(input(CONIC_UBA)->begin(), input(CONIC_UBA)->end(), bu_.begin()+n_);
78 
79  for (casadi_int i=0;i<n_+nc_+1;++i) {
80  if (bl_[i]==-std::numeric_limits<double>::infinity()) bl_[i]=-inf_;
81  if (bu_[i]==std::numeric_limits<double>::infinity()) bu_[i]=inf_;
82  }
83 
84  formatA_.setInput(input(CONIC_A), 0);
85  formatA_.setInput(input(CONIC_G), 1);
86  formatA_.evaluate();
87 
88  sqicSolve(&output(CONIC_COST).nonzeros()[0]);
89 
90  std::copy(x_.begin(), x_.begin()+n_, output(CONIC_X)->begin());
91  std::transform(rc_.begin(), rc_.begin()+n_, output(CONIC_LAM_X)->begin(),
92  negate<double>());
93  std::transform(rc_.begin()+n_, rc_.begin()+n_+nc_, output(CONIC_LAM_A)->begin(),
94  negate<double>());
95 
96  output(CONIC_COST)[0]+= x_[n_+nc_];
97  }
98 
100  // Call the init method of the base class
101  Conic::init();
102 
103  if (is_init_) sqicDestroy();
104 
105  inf_ = 1.0e+20;
106 
107  // Allocate data structures for SQIC
108  bl_.resize(n_+nc_+1, 0);
109  bu_.resize(n_+nc_+1, 0);
110  x_.resize(n_+nc_+1, 0);
111  hs_.resize(n_+nc_+1, 0);
112  hEtype_.resize(n_+nc_+1, 0);
113  pi_.resize(nc_+1, 0);
114  rc_.resize(n_+nc_+1, 0);
115 
116  locH_ = st_[QP_STRUCT_H].colind();
117  indH_ = st_[QP_STRUCT_H].row();
118 
119  // Fortran indices are one-based
120  for (casadi_int i=0;i<indH_.size();++i) indH_[i]+=1;
121  for (casadi_int i=0;i<locH_.size();++i) locH_[i]+=1;
122 
123  // Sparsity of augmented linear constraint matrix
124  Sparsity A_ = vertcat(st_[QP_STRUCT_A], Sparsity::dense(1, n_));
125  locA_ = A_.colind();
126  indA_ = A_.row();
127 
128  // Fortran indices are one-based
129  for (casadi_int i=0;i<indA_.size();++i) indA_[i]+=1;
130  for (casadi_int i=0;i<locA_.size();++i) locA_[i]+=1;
131 
132  // helper functions for augmented linear constraint matrix
133  MX a = MX::sym("A", st_[QP_STRUCT_A]);
134  MX g = MX::sym("g", n_);
135  std::vector<MX> ins;
136  ins.push_back(a);
137  ins.push_back(g);
138  formatA_ = Function("formatA", ins, vertcat(a, g.T()));
139 
140  // Set objective row of augmented linear constraints
141  bu_[n_+nc_] = inf_;
142  bl_[n_+nc_] = -inf_;
143 
144  is_init_ = true;
145 
146  casadi_int n = n_;
147  casadi_int m = nc_+1;
148 
149  casadi_int nnzA=formatA_.size_out(0);
150  casadi_int nnzH=input(CONIC_H).size();
151 
152  std::fill(hEtype_.begin()+n_, hEtype_.end(), 3);
153 
154  sqic(&m , &n, &nnzA, &indA_[0], &locA_[0], &formatA_.output().nonzeros()[0], &bl_[0], &bu_[0],
155  &hEtype_[0], &hs_[0], &x_[0], &pi_[0], &rc_[0], &nnzH, &indH_[0], &locH_[0],
156  &input(CONIC_H).nonzeros()[0]);
157 
158  }
159 
160  std::map<casadi_int, string> SqicInterface::calc_flagmap() {
161  std::map<casadi_int, string> f;
162 
163  return f;
164  }
165 
166  std::map<casadi_int, string> SqicInterface::flagmap = SqicInterface::calc_flagmap();
167 
168  void SqicInterface::sqic_error(const std::string& module, casadi_int flag) {
169  // Find the error
170  std::map<casadi_int, string>::const_iterator it = flagmap.find(flag);
171 
172  std::stringstream ss;
173  if (it == flagmap.end()) {
174  ss << "Unknown error (" << flag << ") from module \"" << module << "\".";
175  } else {
176  ss << "Module \"" << module << "\" returned flag \"" << it->second << "\".";
177  }
178  ss << " Consult SQIC documentation.";
179  casadi_error(ss.str());
180  }
181 
182  void SqicInterface::generateNativeCode(std::ostream& file) const {
183  // Dump the contents of resource_sqic, but filter out the C bind stuff
184  std::string resource_sqic_input(resource_sqic);
185  std::istringstream stream(resource_sqic_input);
186  std::string line;
187  while (std::getline(stream, line)) {
188  size_t b_i = line.find("bind ( C, ");
189  if (b_i!=std::string::npos) {
190  file << line.substr(0, b_i) << std::endl;
191  } else {
192  file << line << std::endl;
193  }
194  }
195 
196  file.precision(std::numeric_limits<double>::digits10+2);
197  file << std::scientific; // This is really only to force a decimal dot,
198  // would be better if it can be avoided
199 
200  file << "program exported" << std::endl;
201  file << " use SQICModule" << std::endl;
202  file << " implicit none" << std::endl;
203  file << " integer(ip) :: m, n, n_inf, nnH, nnzH, nnzA, nS" << std::endl;
204 
205 
206  file << " real(rp) :: Obj" << std::endl;
207 
208  file << " real(rp), allocatable:: bl(:), bu(:), x(:), valA(:), valH(:) , pi(:), rc(:)"
209  << std::endl;
210  file << " integer(ip), allocatable:: indA(:), locA(:), indH(:), locH(:), hEtype(:), hs(:)"
211  << std::endl;
212 
213  casadi_int n = n_;
214  casadi_int m = nc_+1;
215  casadi_int nnzA=formatA_.size_out(0);
216  casadi_int nnzH=input(CONIC_H).size();
217 
218  file << " n = " << n << std::endl;
219  file << " m = " << m << std::endl;
220  file << " nnzA = " << nnzA << std::endl;
221  file << " nnzH = " << nnzH << std::endl;
222 
223  file << " allocate ( bl(n+m), bu(n+m) )" << std::endl;
224  file << " allocate ( hEtype(n+m) )" << std::endl;
225  file << " allocate ( locA(n+1), valA(nnzA), indA(nnzA) )" << std::endl;
226  file << " allocate ( pi(m), rc(n+m), x(n+m) )" << std::endl;
227  file << " allocate ( hs(n+m) )" << std::endl;
228  file << " allocate ( valH(nnzH), locH(n+1), indH(nnzH) )" << std::endl;
229 
230  for (casadi_int i=0;i<indA_.size();++i) {
231  file << " indA(" << i +1 << ") = " << indA_[i] << std::endl;
232  }
233  for (casadi_int i=0;i<locA_.size();++i) {
234  file << " locA(" << i +1 << ") = " << locA_[i] << std::endl;
235  }
236  for (casadi_int i=0;i<formatA_.size_out(0);++i) {
237  file << " valA(" << i +1 << ") = " << formatA_.output().at(i) << std::endl;
238  }
239  for (casadi_int i=0;i<bl_.size();++i) {
240  file << " bl(" << i +1 << ") = " << bl_[i] << std::endl;
241  file << " bu(" << i +1 << ") = " << bu_[i] << std::endl;
242  }
243  for (casadi_int i=0;i<hEtype_.size();++i) {
244  file << " hEtype(" << i +1 << ") = " << hEtype_[i] << std::endl;
245  }
246  for (casadi_int i=0;i<hs_.size();++i) {
247  file << " hs(" << i +1 << ") = " << hs_[i] << std::endl;
248  }
249  for (casadi_int i=0;i<indH_.size();++i) {
250  file << " indH(" << i +1 << ") = " << indH_[i] << std::endl;
251  }
252  for (casadi_int i=0;i<locH_.size();++i) {
253  file << " locH(" << i +1 << ") = " << locH_[i] << std::endl;
254  }
255  for (casadi_int i=0;i<input(CONIC_H).size();++i) {
256  file << " valH(" << i +1 << ") = " << input(CONIC_H).at(i) << std::endl;
257  }
258  for (casadi_int i=0;i<input(CONIC_X0).size();++i) {
259  file << " x(" << i +1 << ") = " << input(CONIC_X0).at(i) << std::endl;
260  }
261  for (casadi_int i=0;i<pi_.size();++i) {
262  file << " pi(" << i +1 << ") = " << 0 << std::endl; //pi_[i] << std::endl;
263  }
264  uout() << "lam_x0:::" << input(CONIC_LAM_X0) << std::endl;
265  for (casadi_int i=0;i<rc_.size();++i) {
266  file << " rc(" << i +1 << ") = "
267  << ((i<input(CONIC_LAM_X0).size()) ? -input(CONIC_LAM_X0).at(i) : 0.0)
268  << std::endl;
269  }
270 
271  file << " call wsqic (m, n, nnzA, indA, locA, valA, bl, bu, hEtype, "
272  << "hs, x, pi, rc, nnzH, indH, locH, valH)" << std::endl;
300  file << " call sqicSolve(Obj)" << std::endl;
301  file << " deallocate ( bl, bu )" << std::endl;
302  file << " deallocate ( hEtype )" << std::endl;
303  file << " deallocate ( locA, valA, indA )" << std::endl;
304  file << " deallocate ( pi, rc, x )" << std::endl;
305  file << " deallocate ( valH, locH, indH )" << std::endl;
306  file << " call sqicDestroy()" << std::endl;
307  file << "end program exported" << std::endl;
308 
309 
310  }
311 
312 } // namespace casadi
Internal class.
Definition: conic_impl.hpp:44
static const Options options_
Options.
Definition: conic_impl.hpp:83
virtual void check_inputs(const double *lbx, const double *ubx, const double *lba, const double *uba) const
Check if the numerical values of the supplied bounds make sense.
Definition: conic.cpp:488
void init(const Dict &opts) override
Initialize.
Definition: conic.cpp:412
bool inputs_check_
Errors are thrown if numerical values of inputs look bad.
std::pair< casadi_int, casadi_int > size_out(casadi_int ind) const
Get output dimension.
Definition: function.cpp:847
static MX sym(const std::string &name, casadi_int nrow=1, casadi_int ncol=1)
Create an nrow-by-ncol symbolic primitive.
MX - Matrix expression.
Definition: mx.hpp:92
MX T() const
Transpose the matrix.
Definition: mx.cpp:1029
static void registerPlugin(const Plugin &plugin, bool needs_lock=true)
Register an integrator in the factory.
General sparsity class.
Definition: sparsity.hpp:106
static Sparsity dense(casadi_int nrow, casadi_int ncol=1)
Create a dense rectangular sparsity pattern *.
Definition: sparsity.cpp:1012
const casadi_int * row() const
Get a reference to row-vector,.
Definition: sparsity.cpp:164
const casadi_int * colind() const
Get a reference to the colindex of all column element (see class description)
Definition: sparsity.cpp:168
bool is_init_
Flag: is already initialized.
static Conic * creator(const std::map< std::string, Sparsity > &st)
Create a new QP Solver.
std::vector< casadi_int > hEtype_
Storage space for sqic hEtype variable.
std::vector< double > pi_
Storage space for sqic rc variable.
std::vector< double > rc_
Storage space for sqic rc variable.
static std::map< casadi_int, std::string > calc_flagmap()
Calculate the error message map.
~SqicInterface() override
Destructor.
static void sqic_error(const std::string &module, casadi_int flag)
Throw error.
SqicInterface()
Constructor.
static const std::string meta_doc
A documentation string.
std::vector< casadi_int > locH_
Storage space for sqic locH variable.
virtual void generateNativeCode(std::ostream &file) const
Generate native code for debugging.
std::vector< casadi_int > locA_
Storage space for sqic locA variable.
std::vector< casadi_int > indA_
Storage space for sqic indA variable.
static std::map< casadi_int, std::string > flagmap
Error message map.
std::vector< casadi_int > indH_
Storage space for sqic indH variable.
virtual void evaluate()
std::vector< double > bu_
Storage space for sqic bu variable.
std::vector< casadi_int > hs_
Storage space for sqic hs variable.
Function formatA_
Helper function to bring A into correct format.
virtual void init()
Initialize.
std::vector< double > x_
Storage space for sqic x variable.
std::vector< double > bl_
Storage space for sqic bl variable.
The casadi namespace.
Definition: archiver.cpp:28
@ CONIC_UBA
dense, (nc x 1)
Definition: conic.hpp:181
@ CONIC_X0
dense, (n x 1)
Definition: conic.hpp:187
@ CONIC_A
The matrix A: sparse, (nc x n) - product with x must be dense.
Definition: conic.hpp:177
@ CONIC_G
The vector g: dense, (n x 1)
Definition: conic.hpp:175
@ CONIC_LBA
dense, (nc x 1)
Definition: conic.hpp:179
@ CONIC_UBX
dense, (n x 1)
Definition: conic.hpp:185
@ CONIC_H
Definition: conic.hpp:173
@ CONIC_LBX
dense, (n x 1)
Definition: conic.hpp:183
@ CONIC_LAM_X0
dense
Definition: conic.hpp:189
int CASADI_CONIC_SQIC_EXPORT casadi_register_conic_sqic(Conic::Plugin *plugin)
void CASADI_CONIC_SQIC_EXPORT casadi_load_conic_sqic()
std::ostream & uout()
@ CONIC_X
The primal solution.
Definition: conic.hpp:201
@ CONIC_LAM_A
The dual solution corresponding to linear bounds.
Definition: conic.hpp:205
@ CONIC_COST
The optimal cost.
Definition: conic.hpp:203
@ CONIC_LAM_X
The dual solution corresponding to simple bounds.
Definition: conic.hpp:207