GiNaC 1.8.10
excompiler.cpp
Go to the documentation of this file.
1
8/*
9 * GiNaC Copyright (C) 1999-2026 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, see <https://www.gnu.org/licenses/>.
23 */
24
25#include "excompiler.h"
26
27#ifdef HAVE_CONFIG_H
28#include "config.h"
29#endif
30
31#include "ex.h"
32#include "lst.h"
33#include "operators.h"
34#include "relational.h"
35#include "symbol.h"
36
37#ifdef HAVE_LIBDL
38# include <dlfcn.h>
39#endif // def HAVE_LIBDL
40#ifdef HAVE_UNISTD_H
41# include <unistd.h>
42#else
43# ifdef _MSC_VER
44# include <io.h> // for close(3)
45# endif // def _MSC_VER
46#endif // def HAVE_UNISTD_H
47#include <cstdlib>
48#include <fstream>
49#include <ios>
50#include <sstream>
51#include <stdexcept>
52#include <string>
53#include <vector>
54
55namespace GiNaC {
56
57#ifdef HAVE_LIBDL
58
68class excompiler
69{
73 struct filedesc
74 {
75 void* module;
76 std::string name;
77 bool clean_up;
78 };
79 std::vector<filedesc> filelist;
80public:
84 ~excompiler()
85 {
86 for (auto it = filelist.begin(); it != filelist.end(); ++it) {
87 clean_up(it);
88 }
89 }
93 void add_opened_module(void* module, const std::string& name, bool clean_up)
94 {
95 filedesc fd;
96 fd.module = module;
97 fd.name = name;
98 fd.clean_up = clean_up;
99 filelist.push_back(fd);
100 }
104 void clean_up(const std::vector<filedesc>::const_iterator it)
105 {
106 dlclose(it->module);
107 if (it->clean_up) {
108 remove(it->name.c_str());
109 }
110 }
115 void create_src_file(std::string& filename, std::ofstream& ofs)
116 {
117 if (filename.empty()) {
118 // fill filename with unique random word
119 const char* filename_pattern = "./GiNaCXXXXXX";
120 char* new_filename = new char[strlen(filename_pattern)+1];
121 strcpy(new_filename, filename_pattern);
122 int fd = mkstemp(new_filename);
123 if (fd == -1) {
124 delete[] new_filename;
125 throw std::runtime_error("mkstemp failed");
126 }
127 filename = std::string(new_filename);
128 ofs.open(new_filename, std::ios::out);
129 close(fd);
130 delete[] new_filename;
131 } else {
132 // use parameter as filename
133 ofs.open(filename.c_str(), std::ios::out);
134 }
135
136 if (!ofs) {
137 throw std::runtime_error("could not create source code file for compilation");
138 }
139
140 ofs << "#include <stddef.h> " << std::endl;
141 ofs << "#include <stdlib.h> " << std::endl;
142 ofs << "#include <math.h> " << std::endl;
143 ofs << std::endl;
144 }
150 void compile_src_file(const std::string filename, bool clean_up)
151 {
152 std::string strcompile = LIBEXECDIR "ginac-excompiler " + filename;
153 if (system(strcompile.c_str())) {
154 throw std::runtime_error("excompiler::compile_src_file: error compiling source file!");
155 }
156 if (clean_up) {
157 remove(filename.c_str());
158 }
159 }
163 void* link_so_file(const std::string filename, bool clean_up)
164 {
165 void* module = nullptr;
166 module = dlopen(filename.c_str(), RTLD_NOW);
167 if (module == nullptr) {
168 throw std::runtime_error("excompiler::link_so_file: could not open compiled module!");
169 }
170
171 add_opened_module(module, filename, clean_up);
172
173 return dlsym(module, "compiled_ex");
174 }
179 void unlink(const std::string filename)
180 {
181 for (auto it = filelist.begin(); it != filelist.end();) {
182 if (it->name == filename) {
183 clean_up(it);
184 it = filelist.erase(it);
185 } else {
186 ++it;
187 }
188 }
189 }
190};
191
202static excompiler global_excompiler;
203
204void compile_ex(const ex& expr, const symbol& sym, FUNCP_1P& fp, const std::string filename)
205{
206 symbol x("x");
207 ex expr_with_x = expr.subs(lst{sym==x});
208
209 std::ofstream ofs;
210 std::string unique_filename = filename;
211 global_excompiler.create_src_file(unique_filename, ofs);
212
213 ofs << "double compiled_ex(double x)" << std::endl;
214 ofs << "{" << std::endl;
215 ofs << "double res = ";
216 expr_with_x.print(GiNaC::print_csrc_double(ofs));
217 ofs << ";" << std::endl;
218 ofs << "return(res); " << std::endl;
219 ofs << "}" << std::endl;
220
221 ofs.close();
222
223 global_excompiler.compile_src_file(unique_filename, filename.empty());
224 // This is not standard compliant! ... no conversion between
225 // pointer-to-functions and pointer-to-objects ...
226 fp = (FUNCP_1P) global_excompiler.link_so_file(unique_filename+".so", filename.empty());
227}
228
229void compile_ex(const ex& expr, const symbol& sym1, const symbol& sym2, FUNCP_2P& fp, const std::string filename)
230{
231 symbol x("x"), y("y");
232 ex expr_with_xy = expr.subs(lst{sym1==x, sym2==y});
233
234 std::ofstream ofs;
235 std::string unique_filename = filename;
236 global_excompiler.create_src_file(unique_filename, ofs);
237
238 ofs << "double compiled_ex(double x, double y)" << std::endl;
239 ofs << "{" << std::endl;
240 ofs << "double res = ";
241 expr_with_xy.print(GiNaC::print_csrc_double(ofs));
242 ofs << ";" << std::endl;
243 ofs << "return(res); " << std::endl;
244 ofs << "}" << std::endl;
245
246 ofs.close();
247
248 global_excompiler.compile_src_file(unique_filename, filename.empty());
249 // This is not standard compliant! ... no conversion between
250 // pointer-to-functions and pointer-to-objects ...
251 fp = (FUNCP_2P) global_excompiler.link_so_file(unique_filename+".so", filename.empty());
252}
253
254void compile_ex(const lst& exprs, const lst& syms, FUNCP_CUBA& fp, const std::string filename)
255{
256 lst replacements;
257 for (std::size_t count=0; count<syms.nops(); ++count) {
258 std::ostringstream s;
259 s << "a[" << count << "]";
260 replacements.append(syms.op(count) == symbol(s.str()));
261 }
262
263 std::vector<ex> expr_with_cname;
264 for (std::size_t count=0; count<exprs.nops(); ++count) {
265 expr_with_cname.push_back(exprs.op(count).subs(replacements));
266 }
267
268 std::ofstream ofs;
269 std::string unique_filename = filename;
270 global_excompiler.create_src_file(unique_filename, ofs);
271
272 ofs << "void compiled_ex(const int* an, const double a[], const int* fn, double f[])" << std::endl;
273 ofs << "{" << std::endl;
274 for (std::size_t count=0; count<exprs.nops(); ++count) {
275 ofs << "f[" << count << "] = ";
276 expr_with_cname[count].print(GiNaC::print_csrc_double(ofs));
277 ofs << ";" << std::endl;
278 }
279 ofs << "}" << std::endl;
280
281 ofs.close();
282
283 global_excompiler.compile_src_file(unique_filename, filename.empty());
284 // This is not standard compliant! ... no conversion between
285 // pointer-to-functions and pointer-to-objects ...
286 fp = (FUNCP_CUBA) global_excompiler.link_so_file(unique_filename+".so", filename.empty());
287}
288
289void link_ex(const std::string filename, FUNCP_1P& fp)
290{
291 // This is not standard compliant! ... no conversion between
292 // pointer-to-functions and pointer-to-objects ...
293 fp = (FUNCP_1P) global_excompiler.link_so_file(filename, false);
294}
295
296void link_ex(const std::string filename, FUNCP_2P& fp)
297{
298 // This is not standard compliant! ... no conversion between
299 // pointer-to-functions and pointer-to-objects ...
300 fp = (FUNCP_2P) global_excompiler.link_so_file(filename, false);
301}
302
303void link_ex(const std::string filename, FUNCP_CUBA& fp)
304{
305 // This is not standard compliant! ... no conversion between
306 // pointer-to-functions and pointer-to-objects ...
307 fp = (FUNCP_CUBA) global_excompiler.link_so_file(filename, false);
308}
309
310void unlink_ex(const std::string filename)
311{
312 global_excompiler.unlink(filename);
313}
314
315#else // def HAVE_LIBDL
316
317/*
318 * In case no working libdl has been found by configure, the following function
319 * stubs preserve the interface. Every function just raises an exception.
320 */
321
322void compile_ex(const ex& expr, const symbol& sym, FUNCP_1P& fp, const std::string filename)
323{
324 throw std::runtime_error("compile_ex has been disabled because of missing libdl!");
325}
326
327void compile_ex(const ex& expr, const symbol& sym1, const symbol& sym2, FUNCP_2P& fp, const std::string filename)
328{
329 throw std::runtime_error("compile_ex has been disabled because of missing libdl!");
330}
331
332void compile_ex(const lst& exprs, const lst& syms, FUNCP_CUBA& fp, const std::string filename)
333{
334 throw std::runtime_error("compile_ex has been disabled because of missing libdl!");
335}
336
337void link_ex(const std::string filename, FUNCP_1P& fp)
338{
339 throw std::runtime_error("link_ex has been disabled because of missing libdl!");
340}
341
342void link_ex(const std::string filename, FUNCP_2P& fp)
343{
344 throw std::runtime_error("link_ex has been disabled because of missing libdl!");
345}
346
347void link_ex(const std::string filename, FUNCP_CUBA& fp)
348{
349 throw std::runtime_error("link_ex has been disabled because of missing libdl!");
350}
351
352void unlink_ex(const std::string filename)
353{
354 throw std::runtime_error("unlink_ex has been disabled because of missing libdl!");
355}
356
357#endif // def HAVE_LIBDL
358
359} // namespace GiNaC
Wrapper template for making GiNaC classes out of STL containers.
Definition container.h:72
Lightweight wrapper for GiNaC's symbolic objects.
Definition ex.h:72
Context for C source output using double precision.
Definition print.h:172
Basic CAS symbol.
Definition symbol.h:38
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:1609
exset syms
Definition factor.cpp:2427
Definition of GiNaC's lst.
Definition add.cpp:35
container< std::list > lst
Definition lst.h:31
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...
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:48
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.
double(* FUNCP_1P)(double)
Function pointer with one function parameter.
Definition excompiler.h:38
void unlink_ex(const std::string filename)
Closes all linked .so files that have the supplied filename.
double(* FUNCP_2P)(double, double)
Function pointer with two function parameters.
Definition excompiler.h:43
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.