1 /*
2  *    This file is part of CasADi.
3  *
4  *    CasADi -- A symbolic framework for dynamic optimization.
5  *    Copyright (C) 2010-2014 Joel Andersson, Joris Gillis, Moritz Diehl,
6  *                            K.U. 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 /**
27  *  Example program demonstrating the usage of C-code generated from CasADi
28  *  Generated code is encapsulated in self-contained code with the entry points
29  *  defined below.
30  *  Note that other usage, e.g. accessing the internal data structures in the
31  *  generated files is not recommended and subject to change.
32  *
33  *  We show how the generated code can be used from C (or C++), without requiring
34  *  any CasADi classes as well as how to use it from C++ using CasADi's external.
35  *
36  *  Joel Andersson, 2013-2015
37  */
38 
39 #include <stdio.h>
40 #include <dlfcn.h>
41 
42 // Usage from C
usage_c()43 int usage_c(){
44   printf("---\n");
45   printf("Standalone usage from C/C++:\n");
46   printf("\n");
47 
48   /* Handle to the dll */
49   void* handle;
50 
51   /* Load the dll */
52   handle = dlopen("./f.so", RTLD_LAZY);
53   if(handle==0){
54     printf("Cannot open f.so, error %s\n", dlerror());
55     return 1;
56   }
57 
58   /* Reset error */
59   dlerror();
60 
61   typedef long long int casadi_int;
62 
63   /* Typedefs */
64   typedef void (*signal_t)(void);
65   typedef casadi_int (*getint_t)(void);
66   typedef int (*work_t)(casadi_int* sz_arg, casadi_int* sz_res, casadi_int* sz_iw, casadi_int* sz_w);
67   typedef const casadi_int* (*sparsity_t)(casadi_int ind);
68   typedef int (*eval_t)(const double** arg, double** res, casadi_int* iw, double* w, int mem);
69   typedef int (*casadi_checkout_t)(void);
70   typedef void (*casadi_release_t)(int);
71 
72   /* Memory management -- increase reference counter */
73   signal_t incref = (signal_t)dlsym(handle, "f_incref");
74   if(dlerror()) dlerror(); // No such function, reset error flags
75 
76   /* Memory management -- decrease reference counter */
77   signal_t decref = (signal_t)dlsym(handle, "f_decref");
78   if(dlerror()) dlerror(); // No such function, reset error flags
79 
80   /* Thread-local memory management -- checkout memory */
81   casadi_checkout_t checkout = (casadi_checkout_t)dlsym(handle, "f_checkout");
82   if(dlerror()) dlerror(); // No such function, reset error flags
83 
84   /* Thread-local memory management -- release memory */
85   casadi_release_t release = (casadi_release_t)dlsym(handle, "f_release");
86   if(dlerror()) dlerror(); // No such function, reset error flags
87 
88   /* Number of inputs */
89   getint_t n_in_fcn = (getint_t)dlsym(handle, "f_n_in");
90   if (dlerror()) return 1;
91   casadi_int n_in = n_in_fcn();
92 
93   /* Number of outputs */
94   getint_t n_out_fcn = (getint_t)dlsym(handle, "f_n_out");
95   if (dlerror()) return 1;
96   casadi_int n_out = n_out_fcn();
97 
98   /* Get sizes of the required work vectors */
99   casadi_int sz_arg=n_in, sz_res=n_out, sz_iw=0, sz_w=0;
100   work_t work = (work_t)dlsym(handle, "f_work");
101   if(dlerror()) dlerror(); // No such function, reset error flags
102   if (work && work(&sz_arg, &sz_res, &sz_iw, &sz_w)) return 1;
103   printf("Work vector sizes:\n");
104   printf("sz_arg = %lld, sz_res = %lld, sz_iw = %lld, sz_w = %lld\n\n",
105          sz_arg, sz_res, sz_iw, sz_w);
106 
107   /* Input sparsities */
108   sparsity_t sparsity_in = (sparsity_t)dlsym(handle, "f_sparsity_in");
109   if (dlerror()) return 1;
110 
111   /* Output sparsities */
112   sparsity_t sparsity_out = (sparsity_t)dlsym(handle, "f_sparsity_out");
113   if (dlerror()) return 1;
114 
115   /* Print the sparsities of the inputs and outputs */
116   casadi_int i;
117   for(i=0; i<n_in + n_out; ++i){
118     // Retrieve the sparsity pattern - CasADi uses column compressed storage (CCS)
119     const casadi_int *sp_i;
120     if (i<n_in) {
121       printf("Input %lld\n", i);
122       sp_i = sparsity_in(i);
123     } else {
124       printf("Output %lld\n", i-n_in);
125       sp_i = sparsity_out(i-n_in);
126     }
127     if (sp_i==0) return 1;
128     casadi_int nrow = *sp_i++; /* Number of rows */
129     casadi_int ncol = *sp_i++; /* Number of columns */
130     const casadi_int *colind = sp_i; /* Column offsets */
131     const casadi_int *row = sp_i + ncol+1; /* Row nonzero */
132     casadi_int nnz = sp_i[ncol]; /* Number of nonzeros */
133 
134     /* Print the pattern */
135     printf("  Dimension: %lld-by-%lld (%lld nonzeros)\n", nrow, ncol, nnz);
136     printf("  Nonzeros: {");
137     casadi_int rr,cc,el;
138     for(cc=0; cc<ncol; ++cc){                    /* loop over columns */
139       for(el=colind[cc]; el<colind[cc+1]; ++el){ /* loop over the nonzeros entries of the column */
140         if(el!=0) printf(", ");                  /* Separate the entries */
141         rr = row[el];                            /* Get the row */
142         printf("{%lld,%lld}",rr,cc);                 /* Print the nonzero */
143       }
144     }
145     printf("}\n\n");
146   }
147 
148   /* Function for numerical evaluation */
149   eval_t eval = (eval_t)dlsym(handle, "f");
150   if(dlerror()){
151     printf("Failed to retrieve \"f\" function.\n");
152     return 1;
153   }
154 
155   /* Allocate input/output buffers and work vectors*/
156   const double *arg[sz_arg];
157   double *res[sz_res];
158   casadi_int iw[sz_iw];
159   double w[sz_w];
160 
161   /* Function input and output */
162   const double x_val[] = {1,2,3,4};
163   const double y_val = 5;
164   double res0;
165   double res1[4];
166 
167   // Allocate memory (thread-safe)
168   incref();
169 
170   /* Evaluate the function */
171   arg[0] = x_val;
172   arg[1] = &y_val;
173   res[0] = &res0;
174   res[1] = res1;
175 
176   // Checkout thread-local memory (not thread-safe)
177   // Note MAX_NUM_THREADS
178   int mem = checkout();
179 
180   // Evaluation is thread-safe
181   if (eval(arg, res, iw, w, mem)) return 1;
182 
183   // Release thread-local (not thread-safe)
184   release(mem);
185 
186   /* Print result of evaluation */
187   printf("result (0): %g\n",res0);
188   printf("result (1): [%g,%g;%g,%g]\n",res1[0],res1[1],res1[2],res1[3]);
189 
190   /* Free memory (thread-safe) */
191   decref();
192 
193   /* Free the handle */
194   dlclose(handle);
195 
196   return 0;
197 }
198 
199 // C++ (and CasADi) from here on
200 #include <casadi/casadi.hpp>
201 using namespace casadi;
202 using namespace std;
203 
usage_cplusplus()204 void usage_cplusplus(){
205   cout << "---" << endl;
206   cout << "Usage from CasADi C++:" << endl;
207   cout << endl;
208 
209   // Use CasADi's "external" to load the compiled function
210   Function f = external("f");
211 
212   // Use like any other CasADi function
213   vector<double> x = {1, 2, 3, 4};
214   vector<DM> arg = {reshape(DM(x), 2, 2), 5};
215   vector<DM> res = f(arg);
216 
217   cout << "result (0): " << res.at(0) << endl;
218   cout << "result (1): " << res.at(1) << endl;
219 }
220 
221 
222 // Usage from C using mem.h
223 #include <casadi/mem.h>
usage_c_with_mem()224 int usage_c_with_mem(){
225   printf("---\n");
226   printf("Usage from C/C++ with casadi/mem.h:\n");
227   printf("\n");
228 
229   /* Handle to the dll */
230   void* handle;
231 
232   /* Load the dll */
233   handle = dlopen("./f_with_mem.so", RTLD_LAZY);
234   if(handle==0){
235     printf("Cannot open f_with_mem.so, error %s\n", dlerror());
236     return 1;
237   }
238 
239   /* Reset error */
240   dlerror();
241 
242   /* Typedefs */
243   typedef casadi_functions* (*functions_t)(void);
244 
245   /* mem.h interface */
246   functions_t functions = (functions_t)dlsym(handle, "f_functions");
247   if(dlerror()) dlerror(); // No such function, reset error flags
248 
249   casadi_functions* f = functions();
250 
251   casadi_mem* mem = casadi_alloc(f);
252 
253   /* Function input and output */
254   const double x_val[] = {1,2,3,4};
255   const double y_val = 5;
256   double res0;
257   double res1[4];
258 
259   /* Evaluate the function */
260   mem->arg[0] = x_val;
261   mem->arg[1] = &y_val;
262   mem->res[0] = &res0;
263   mem->res[1] = res1;
264 
265   casadi_eval(mem);
266 
267   /* Print result of evaluation */
268   printf("result (0): %g\n",res0);
269   printf("result (1): [%g,%g;%g,%g]\n",res1[0],res1[1],res1[2],res1[3]);
270 
271   casadi_free(mem);
272 
273   /* Success */
274   return 0;
275 }
276 
277 
main()278 int main(){
279 
280   // Variables
281   SX x = SX::sym("x", 2, 2);
282   SX y = SX::sym("y");
283 
284   // Simple function
285   Function f("f", {x, y}, {sqrt(y)-1, sin(x)-y});
286 
287   // Generate C-code
288   f.generate("f");
289 
290   // Compile the C-code to a shared library
291   string compile_command = "gcc -fPIC -shared -O3 f.c -o f.so";
292   int flag = system(compile_command.c_str());
293   casadi_assert(flag==0, "Compilation failed");
294 
295   // Usage from C
296   flag = usage_c();
297   casadi_assert(flag==0, "Example failed");
298 
299   // Usage from C++
300   usage_cplusplus();
301 
302   // Generate C-code
303   f.generate("f_with_mem", {{"with_mem", true}});
304 
305   // Compile the C-code to a shared library
306   compile_command = "gcc -fPIC -I"+ std::string(INCLUDE_DIR) + " -shared -g f_with_mem.c -o f_with_mem.so";
307   flag = system(compile_command.c_str());
308   casadi_assert(flag==0, "Compilation failed");
309 
310   // Usage from c with mem.h
311   usage_c_with_mem();
312 
313   return 0;
314 }
315