|
GiNaC
1.6.2
|
00001 00008 /* 00009 * GiNaC Copyright (C) 1999-2011 Johannes Gutenberg University Mainz, Germany 00010 * 00011 * This program is free software; you can redistribute it and/or modify 00012 * it under the terms of the GNU General Public License as published by 00013 * the Free Software Foundation; either version 2 of the License, or 00014 * (at your option) any later version. 00015 * 00016 * This program is distributed in the hope that it will be useful, 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 * GNU General Public License for more details. 00020 * 00021 * You should have received a copy of the GNU General Public License 00022 * along with this program; if not, write to the Free Software 00023 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00024 */ 00025 00026 #include "excompiler.h" 00027 00028 #ifdef HAVE_CONFIG_H 00029 #include "config.h" 00030 #endif 00031 00032 #include "ex.h" 00033 #include "lst.h" 00034 #include "operators.h" 00035 #include "relational.h" 00036 #include "symbol.h" 00037 00038 #ifdef HAVE_LIBDL 00039 #include <dlfcn.h> 00040 #endif // def HAVE_LIBDL 00041 #include <fstream> 00042 #include <ios> 00043 #include <sstream> 00044 #include <stdexcept> 00045 #include <string> 00046 #include <vector> 00047 00048 namespace GiNaC { 00049 00050 #ifdef HAVE_LIBDL 00051 00061 class excompiler 00062 { 00066 struct filedesc 00067 { 00068 void* module; 00069 std::string name; 00070 bool clean_up; 00071 }; 00072 std::vector<filedesc> filelist; 00073 public: 00077 ~excompiler() 00078 { 00079 for (std::vector<filedesc>::const_iterator it = filelist.begin(); it != filelist.end(); ++it) { 00080 clean_up(it); 00081 } 00082 } 00086 void add_opened_module(void* module, const std::string& name, bool clean_up) 00087 { 00088 filedesc fd; 00089 fd.module = module; 00090 fd.name = name; 00091 fd.clean_up = clean_up; 00092 filelist.push_back(fd); 00093 } 00097 void clean_up(const std::vector<filedesc>::const_iterator it) 00098 { 00099 dlclose(it->module); 00100 if (it->clean_up) { 00101 remove(it->name.c_str()); 00102 } 00103 } 00108 void create_src_file(std::string& filename, std::ofstream& ofs) 00109 { 00110 if (filename.empty()) { 00111 // fill filename with unique random word 00112 const char* filename_pattern = "./GiNaCXXXXXX"; 00113 char* new_filename = new char[strlen(filename_pattern)+1]; 00114 strcpy(new_filename, filename_pattern); 00115 if (!mktemp(new_filename)) { 00116 delete[] new_filename; 00117 throw std::runtime_error("mktemp failed"); 00118 } 00119 filename = std::string(new_filename); 00120 ofs.open(new_filename, std::ios::out); 00121 delete[] new_filename; 00122 } else { 00123 // use parameter as filename 00124 ofs.open(filename.c_str(), std::ios::out); 00125 } 00126 00127 if (!ofs) { 00128 throw std::runtime_error("could not create source code file for compilation"); 00129 } 00130 00131 ofs << "#include <stddef.h> " << std::endl; 00132 ofs << "#include <stdlib.h> " << std::endl; 00133 ofs << "#include <math.h> " << std::endl; 00134 ofs << std::endl; 00135 } 00141 void compile_src_file(const std::string filename, bool clean_up) 00142 { 00143 std::string strcompile = "ginac-excompiler " + filename; 00144 if (system(strcompile.c_str())) { 00145 throw std::runtime_error("excompiler::compile_src_file: error compiling source file!"); 00146 } 00147 if (clean_up) { 00148 remove(filename.c_str()); 00149 } 00150 } 00154 void* link_so_file(const std::string filename, bool clean_up) 00155 { 00156 void* module = NULL; 00157 module = dlopen(filename.c_str(), RTLD_NOW); 00158 if (module == NULL) { 00159 throw std::runtime_error("excompiler::link_so_file: could not open compiled module!"); 00160 } 00161 00162 add_opened_module(module, filename, clean_up); 00163 00164 return dlsym(module, "compiled_ex"); 00165 } 00170 void unlink(const std::string filename) 00171 { 00172 for (std::vector<filedesc>::iterator it = filelist.begin(); it != filelist.end();) { 00173 if (it->name == filename) { 00174 clean_up(it); 00175 it = filelist.erase(it); 00176 } else { 00177 ++it; 00178 } 00179 } 00180 } 00181 }; 00182 00193 static excompiler global_excompiler; 00194 00195 void compile_ex(const ex& expr, const symbol& sym, FUNCP_1P& fp, const std::string filename) 00196 { 00197 symbol x("x"); 00198 ex expr_with_x = expr.subs(lst(sym==x)); 00199 00200 std::ofstream ofs; 00201 std::string unique_filename = filename; 00202 global_excompiler.create_src_file(unique_filename, ofs); 00203 00204 ofs << "double compiled_ex(double x)" << std::endl; 00205 ofs << "{" << std::endl; 00206 ofs << "double res = "; 00207 expr_with_x.print(GiNaC::print_csrc_double(ofs)); 00208 ofs << ";" << std::endl; 00209 ofs << "return(res); " << std::endl; 00210 ofs << "}" << std::endl; 00211 00212 ofs.close(); 00213 00214 global_excompiler.compile_src_file(unique_filename, filename.empty()); 00215 // This is not standard compliant! ... no conversion between 00216 // pointer-to-functions and pointer-to-objects ... 00217 fp = (FUNCP_1P) global_excompiler.link_so_file(unique_filename+".so", filename.empty()); 00218 } 00219 00220 void compile_ex(const ex& expr, const symbol& sym1, const symbol& sym2, FUNCP_2P& fp, const std::string filename) 00221 { 00222 symbol x("x"), y("y"); 00223 ex expr_with_xy = expr.subs(lst(sym1==x, sym2==y)); 00224 00225 std::ofstream ofs; 00226 std::string unique_filename = filename; 00227 global_excompiler.create_src_file(unique_filename, ofs); 00228 00229 ofs << "double compiled_ex(double x, double y)" << std::endl; 00230 ofs << "{" << std::endl; 00231 ofs << "double res = "; 00232 expr_with_xy.print(GiNaC::print_csrc_double(ofs)); 00233 ofs << ";" << std::endl; 00234 ofs << "return(res); " << std::endl; 00235 ofs << "}" << std::endl; 00236 00237 ofs.close(); 00238 00239 global_excompiler.compile_src_file(unique_filename, filename.empty()); 00240 // This is not standard compliant! ... no conversion between 00241 // pointer-to-functions and pointer-to-objects ... 00242 fp = (FUNCP_2P) global_excompiler.link_so_file(unique_filename+".so", filename.empty()); 00243 } 00244 00245 void compile_ex(const lst& exprs, const lst& syms, FUNCP_CUBA& fp, const std::string filename) 00246 { 00247 lst replacements; 00248 for (std::size_t count=0; count<syms.nops(); ++count) { 00249 std::ostringstream s; 00250 s << "a[" << count << "]"; 00251 replacements.append(syms.op(count) == symbol(s.str())); 00252 } 00253 00254 std::vector<ex> expr_with_cname; 00255 for (std::size_t count=0; count<exprs.nops(); ++count) { 00256 expr_with_cname.push_back(exprs.op(count).subs(replacements)); 00257 } 00258 00259 std::ofstream ofs; 00260 std::string unique_filename = filename; 00261 global_excompiler.create_src_file(unique_filename, ofs); 00262 00263 ofs << "void compiled_ex(const int* an, const double a[], const int* fn, double f[])" << std::endl; 00264 ofs << "{" << std::endl; 00265 for (std::size_t count=0; count<exprs.nops(); ++count) { 00266 ofs << "f[" << count << "] = "; 00267 expr_with_cname[count].print(GiNaC::print_csrc_double(ofs)); 00268 ofs << ";" << std::endl; 00269 } 00270 ofs << "}" << std::endl; 00271 00272 ofs.close(); 00273 00274 global_excompiler.compile_src_file(unique_filename, filename.empty()); 00275 // This is not standard compliant! ... no conversion between 00276 // pointer-to-functions and pointer-to-objects ... 00277 fp = (FUNCP_CUBA) global_excompiler.link_so_file(unique_filename+".so", filename.empty()); 00278 } 00279 00280 void link_ex(const std::string filename, FUNCP_1P& fp) 00281 { 00282 // This is not standard compliant! ... no conversion between 00283 // pointer-to-functions and pointer-to-objects ... 00284 fp = (FUNCP_1P) global_excompiler.link_so_file(filename, false); 00285 } 00286 00287 void link_ex(const std::string filename, FUNCP_2P& fp) 00288 { 00289 // This is not standard compliant! ... no conversion between 00290 // pointer-to-functions and pointer-to-objects ... 00291 fp = (FUNCP_2P) global_excompiler.link_so_file(filename, false); 00292 } 00293 00294 void link_ex(const std::string filename, FUNCP_CUBA& fp) 00295 { 00296 // This is not standard compliant! ... no conversion between 00297 // pointer-to-functions and pointer-to-objects ... 00298 fp = (FUNCP_CUBA) global_excompiler.link_so_file(filename, false); 00299 } 00300 00301 void unlink_ex(const std::string filename) 00302 { 00303 global_excompiler.unlink(filename); 00304 } 00305 00306 #else // def HAVE_LIBDL 00307 00308 /* 00309 * In case no working libdl has been found by configure, the following function 00310 * stubs preserve the interface. Every function just raises an exception. 00311 */ 00312 00313 void compile_ex(const ex& expr, const symbol& sym, FUNCP_1P& fp, const std::string filename) 00314 { 00315 throw std::runtime_error("compile_ex has been disabled because of missing libdl!"); 00316 } 00317 00318 void compile_ex(const ex& expr, const symbol& sym1, const symbol& sym2, FUNCP_2P& fp, const std::string filename) 00319 { 00320 throw std::runtime_error("compile_ex has been disabled because of missing libdl!"); 00321 } 00322 00323 void compile_ex(const lst& exprs, const lst& syms, FUNCP_CUBA& fp, const std::string filename) 00324 { 00325 throw std::runtime_error("compile_ex has been disabled because of missing libdl!"); 00326 } 00327 00328 void link_ex(const std::string filename, FUNCP_1P& fp) 00329 { 00330 throw std::runtime_error("link_ex has been disabled because of missing libdl!"); 00331 } 00332 00333 void link_ex(const std::string filename, FUNCP_2P& fp) 00334 { 00335 throw std::runtime_error("link_ex has been disabled because of missing libdl!"); 00336 } 00337 00338 void link_ex(const std::string filename, FUNCP_CUBA& fp) 00339 { 00340 throw std::runtime_error("link_ex has been disabled because of missing libdl!"); 00341 } 00342 00343 void unlink_ex(const std::string filename) 00344 { 00345 throw std::runtime_error("unlink_ex has been disabled because of missing libdl!"); 00346 } 00347 00348 #endif // def HAVE_LIBDL 00349 00350 } // namespace GiNaC