GiNaC  1.8.0
excompiler.cpp
Go to the documentation of this file.
1 
8 /*
9  * GiNaC Copyright (C) 1999-2020 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 
56 namespace GiNaC {
57 
58 #ifdef HAVE_LIBDL
59 
69 class excompiler
70 {
74  struct filedesc
75  {
76  void* module;
77  std::string name;
78  bool clean_up;
79  };
80  std::vector<filedesc> filelist;
81 public:
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 
203 static excompiler global_excompiler;
204 
205 void 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 
230 void 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 
255 void 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 
290 void 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 
297 void 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 
304 void 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 
311 void 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 
323 void 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 
328 void 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 
333 void 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 
338 void 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 
343 void 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 
348 void 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 
353 void 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
Interface to GiNaC&#39;s symbolic objects.
exset syms
Definition: factor.cpp:2434
Context for C source output using double precision.
Definition: print.h:173
Definition: add.cpp:38
ex x
Definition: factor.cpp:1641
container< std::list > lst
Definition: lst.h:32
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
Functions to facilitate the conversion of a ex to a function pointer suited for fast numerical integr...
double(* FUNCP_2P)(double, double)
Function pointer with two function parameters.
Definition: excompiler.h:44
Interface to GiNaC&#39;s overloaded operators.
Interface to GiNaC&#39;s light-weight expression handles.
Definition of GiNaC&#39;s lst.
Lightweight wrapper for GiNaC&#39;s symbolic objects.
Definition: ex.h:72
Basic CAS symbol.
Definition: symbol.h:38
double(* FUNCP_1P)(double)
Function pointer with one function parameter.
Definition: excompiler.h:39
Wrapper template for making GiNaC classes out of STL containers.
Definition: container.h:73
Interface to relations between expressions.
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
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 unlink_ex(const std::string filename)
Closes all linked .so files that have the supplied filename.
Definition: excompiler.cpp:353

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