GiNaC 1.8.7
excompiler.cpp
Go to the documentation of this file.
1
8/*
9 * GiNaC Copyright (C) 1999-2023 Johannes Gutenberg University Mainz, Germany
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 */
25
26#include "excompiler.h"
27
28#ifdef HAVE_CONFIG_H
29#include "config.h"
30#endif
31
32#include "ex.h"
33#include "lst.h"
34#include "operators.h"
35#include "relational.h"
36#include "symbol.h"
37
38#ifdef HAVE_LIBDL
39# include <dlfcn.h>
40#endif // def HAVE_LIBDL
41#ifdef HAVE_UNISTD_H
42# include <unistd.h>
43#else
44# ifdef _MSC_VER
45# include <io.h> // for close(3)
46# endif // def _MSC_VER
47#endif // def HAVE_UNISTD_H
48#include <cstdlib>
49#include <fstream>
50#include <ios>
51#include <sstream>
52#include <stdexcept>
53#include <string>
54#include <vector>
55
56namespace GiNaC {
57
58#ifdef HAVE_LIBDL
59
69class excompiler
70{
74 struct filedesc
75 {
76 void* module;
77 std::string name;
78 bool clean_up;
79 };
80 std::vector<filedesc> filelist;
81public:
85 ~excompiler()
86 {
87 for (auto it = filelist.begin(); it != filelist.end(); ++it) {
88 clean_up(it);
89 }
90 }
94 void add_opened_module(void* module, const std::string& name, bool clean_up)
95 {
96 filedesc fd;
97 fd.module = module;
98 fd.name = name;
99 fd.clean_up = clean_up;
100 filelist.push_back(fd);
101 }
105 void clean_up(const std::vector<filedesc>::const_iterator it)
106 {
107 dlclose(it->module);
108 if (it->clean_up) {
109 remove(it->name.c_str());
110 }
111 }
116 void create_src_file(std::string& filename, std::ofstream& ofs)
117 {
118 if (filename.empty()) {
119 // fill filename with unique random word
120 const char* filename_pattern = "./GiNaCXXXXXX";
121 char* new_filename = new char[strlen(filename_pattern)+1];
122 strcpy(new_filename, filename_pattern);
123 int fd = mkstemp(new_filename);
124 if (fd == -1) {
125 delete[] new_filename;
126 throw std::runtime_error("mkstemp failed");
127 }
128 filename = std::string(new_filename);
129 ofs.open(new_filename, std::ios::out);
130 close(fd);
131 delete[] new_filename;
132 } else {
133 // use parameter as filename
134 ofs.open(filename.c_str(), std::ios::out);
135 }
136
137 if (!ofs) {
138 throw std::runtime_error("could not create source code file for compilation");
139 }
140
141 ofs << "#include <stddef.h> " << std::endl;
142 ofs << "#include <stdlib.h> " << std::endl;
143 ofs << "#include <math.h> " << std::endl;
144 ofs << std::endl;
145 }
151 void compile_src_file(const std::string filename, bool clean_up)
152 {
153 std::string strcompile = LIBEXECDIR "ginac-excompiler " + filename;
154 if (system(strcompile.c_str())) {
155 throw std::runtime_error("excompiler::compile_src_file: error compiling source file!");
156 }
157 if (clean_up) {
158 remove(filename.c_str());
159 }
160 }
164 void* link_so_file(const std::string filename, bool clean_up)
165 {
166 void* module = nullptr;
167 module = dlopen(filename.c_str(), RTLD_NOW);
168 if (module == nullptr) {
169 throw std::runtime_error("excompiler::link_so_file: could not open compiled module!");
170 }
171
172 add_opened_module(module, filename, clean_up);
173
174 return dlsym(module, "compiled_ex");
175 }
180 void unlink(const std::string filename)
181 {
182 for (auto it = filelist.begin(); it != filelist.end();) {
183 if (it->name == filename) {
184 clean_up(it);
185 it = filelist.erase(it);
186 } else {
187 ++it;
188 }
189 }
190 }
191};
192
203static excompiler global_excompiler;
204
205void compile_ex(const ex& expr, const symbol& sym, FUNCP_1P& fp, const std::string filename)
206{
207 symbol x("x");
208 ex expr_with_x = expr.subs(lst{sym==x});
209
210 std::ofstream ofs;
211 std::string unique_filename = filename;
212 global_excompiler.create_src_file(unique_filename, ofs);
213
214 ofs << "double compiled_ex(double x)" << std::endl;
215 ofs << "{" << std::endl;
216 ofs << "double res = ";
217 expr_with_x.print(GiNaC::print_csrc_double(ofs));
218 ofs << ";" << std::endl;
219 ofs << "return(res); " << std::endl;
220 ofs << "}" << std::endl;
221
222 ofs.close();
223
224 global_excompiler.compile_src_file(unique_filename, filename.empty());
225 // This is not standard compliant! ... no conversion between
226 // pointer-to-functions and pointer-to-objects ...
227 fp = (FUNCP_1P) global_excompiler.link_so_file(unique_filename+".so", filename.empty());
228}
229
230void compile_ex(const ex& expr, const symbol& sym1, const symbol& sym2, FUNCP_2P& fp, const std::string filename)
231{
232 symbol x("x"), y("y");
233 ex expr_with_xy = expr.subs(lst{sym1==x, sym2==y});
234
235 std::ofstream ofs;
236 std::string unique_filename = filename;
237 global_excompiler.create_src_file(unique_filename, ofs);
238
239 ofs << "double compiled_ex(double x, double y)" << std::endl;
240 ofs << "{" << std::endl;
241 ofs << "double res = ";
242 expr_with_xy.print(GiNaC::print_csrc_double(ofs));
243 ofs << ";" << std::endl;
244 ofs << "return(res); " << std::endl;
245 ofs << "}" << std::endl;
246
247 ofs.close();
248
249 global_excompiler.compile_src_file(unique_filename, filename.empty());
250 // This is not standard compliant! ... no conversion between
251 // pointer-to-functions and pointer-to-objects ...
252 fp = (FUNCP_2P) global_excompiler.link_so_file(unique_filename+".so", filename.empty());
253}
254
255void compile_ex(const lst& exprs, const lst& syms, FUNCP_CUBA& fp, const std::string filename)
256{
257 lst replacements;
258 for (std::size_t count=0; count<syms.nops(); ++count) {
259 std::ostringstream s;
260 s << "a[" << count << "]";
261 replacements.append(syms.op(count) == symbol(s.str()));
262 }
263
264 std::vector<ex> expr_with_cname;
265 for (std::size_t count=0; count<exprs.nops(); ++count) {
266 expr_with_cname.push_back(exprs.op(count).subs(replacements));
267 }
268
269 std::ofstream ofs;
270 std::string unique_filename = filename;
271 global_excompiler.create_src_file(unique_filename, ofs);
272
273 ofs << "void compiled_ex(const int* an, const double a[], const int* fn, double f[])" << std::endl;
274 ofs << "{" << std::endl;
275 for (std::size_t count=0; count<exprs.nops(); ++count) {
276 ofs << "f[" << count << "] = ";
277 expr_with_cname[count].print(GiNaC::print_csrc_double(ofs));
278 ofs << ";" << std::endl;
279 }
280 ofs << "}" << std::endl;
281
282 ofs.close();
283
284 global_excompiler.compile_src_file(unique_filename, filename.empty());
285 // This is not standard compliant! ... no conversion between
286 // pointer-to-functions and pointer-to-objects ...
287 fp = (FUNCP_CUBA) global_excompiler.link_so_file(unique_filename+".so", filename.empty());
288}
289
290void link_ex(const std::string filename, FUNCP_1P& fp)
291{
292 // This is not standard compliant! ... no conversion between
293 // pointer-to-functions and pointer-to-objects ...
294 fp = (FUNCP_1P) global_excompiler.link_so_file(filename, false);
295}
296
297void link_ex(const std::string filename, FUNCP_2P& fp)
298{
299 // This is not standard compliant! ... no conversion between
300 // pointer-to-functions and pointer-to-objects ...
301 fp = (FUNCP_2P) global_excompiler.link_so_file(filename, false);
302}
303
304void link_ex(const std::string filename, FUNCP_CUBA& fp)
305{
306 // This is not standard compliant! ... no conversion between
307 // pointer-to-functions and pointer-to-objects ...
308 fp = (FUNCP_CUBA) global_excompiler.link_so_file(filename, false);
309}
310
311void unlink_ex(const std::string filename)
312{
313 global_excompiler.unlink(filename);
314}
315
316#else // def HAVE_LIBDL
317
318/*
319 * In case no working libdl has been found by configure, the following function
320 * stubs preserve the interface. Every function just raises an exception.
321 */
322
323void compile_ex(const ex& expr, const symbol& sym, FUNCP_1P& fp, const std::string filename)
324{
325 throw std::runtime_error("compile_ex has been disabled because of missing libdl!");
326}
327
328void compile_ex(const ex& expr, const symbol& sym1, const symbol& sym2, FUNCP_2P& fp, const std::string filename)
329{
330 throw std::runtime_error("compile_ex has been disabled because of missing libdl!");
331}
332
333void compile_ex(const lst& exprs, const lst& syms, FUNCP_CUBA& fp, const std::string filename)
334{
335 throw std::runtime_error("compile_ex has been disabled because of missing libdl!");
336}
337
338void link_ex(const std::string filename, FUNCP_1P& fp)
339{
340 throw std::runtime_error("link_ex has been disabled because of missing libdl!");
341}
342
343void link_ex(const std::string filename, FUNCP_2P& fp)
344{
345 throw std::runtime_error("link_ex has been disabled because of missing libdl!");
346}
347
348void link_ex(const std::string filename, FUNCP_CUBA& fp)
349{
350 throw std::runtime_error("link_ex has been disabled because of missing libdl!");
351}
352
353void unlink_ex(const std::string filename)
354{
355 throw std::runtime_error("unlink_ex has been disabled because of missing libdl!");
356}
357
358#endif // def HAVE_LIBDL
359
360} // namespace GiNaC
Wrapper template for making GiNaC classes out of STL containers.
Definition: container.h:73
Lightweight wrapper for GiNaC's symbolic objects.
Definition: ex.h:72
Context for C source output using double precision.
Definition: print.h:174
Basic CAS symbol.
Definition: symbol.h:39
Interface to GiNaC's light-weight expression handles.
Functions to facilitate the conversion of a ex to a function pointer suited for fast numerical integr...
ex x
Definition: factor.cpp:1610
exset syms
Definition: factor.cpp:2429
Definition of GiNaC's lst.
Definition: add.cpp:38
container< std::list > lst
Definition: lst.h:32
void compile_ex(const ex &expr, const symbol &sym, FUNCP_1P &fp, const std::string filename)
Takes an expression and produces a function pointer to the compiled and linked C code equivalent in d...
Definition: excompiler.cpp:323
void(* FUNCP_CUBA)(const int *, const double[], const int *, double[])
Function pointer for use with the CUBA library (http://www.feynarts.de/cuba).
Definition: excompiler.h:49
void link_ex(const std::string filename, FUNCP_1P &fp)
Opens an existing so-file and returns a function pointer of type FUNCP_1P to the contained function.
Definition: excompiler.cpp:338
double(* FUNCP_1P)(double)
Function pointer with one function parameter.
Definition: excompiler.h:39
void unlink_ex(const std::string filename)
Closes all linked .so files that have the supplied filename.
Definition: excompiler.cpp:353
double(* FUNCP_2P)(double, double)
Function pointer with two function parameters.
Definition: excompiler.h:44
Interface to GiNaC's overloaded operators.
Interface to relations between expressions.
Interface to GiNaC's symbolic objects.

This page is part of the GiNaC developer's reference. It was generated automatically by doxygen. For an introduction, see the tutorial.