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