16 #ifndef dealii_differentiation_sd_symengine_optimizer_h
17 #define dealii_differentiation_sd_symengine_optimizer_h
21 #ifdef DEAL_II_WITH_SYMENGINE
25 # include <symengine/basic.h>
26 # include <symengine/dict.h>
27 # include <symengine/symengine_exception.h>
28 # include <symengine/symengine_rcp.h>
31 # include <symengine/lambda_double.h>
32 # include <symengine/visitor.h>
33 # ifdef HAVE_SYMENGINE_LLVM
34 # include <symengine/llvm_double.h>
48 # include <boost/serialization/split_member.hpp>
49 # include <boost/type_traits.hpp>
54 # include <type_traits>
76 "SymEngine has not been built with LLVM support.");
83 "The SymEngine LLVM optimizer does not (yet) support the "
84 "selected return type.");
90 template <
typename ReturnType>
121 template <
class StreamType>
183 static_cast<unsigned int>(f2));
215 static_cast<unsigned int>(f2));
261 const bool use_agg_opt =
263 const int opt_level = (use_agg_opt ? 3 : 2);
273 template <
class StreamType>
277 s <<
" OptimizationFlags|";
302 template <
typename ReturnType,
typename T =
void>
315 template <
typename ReturnType,
typename T =
void>
319 # ifdef HAVE_SYMENGINE_LLVM
329 template <
typename ReturnType,
typename T =
void>
330 struct LLVMOptimizer;
331 # endif // HAVE_SYMENGINE_LLVM
349 template <
typename ReturnType,
typename Optimizer,
typename T =
void>
361 template <
typename ReturnType_,
typename T =
void>
362 struct SupportedOptimizerTypeTraits
364 static const bool is_supported =
false;
366 using ReturnType = void;
372 template <
typename ReturnType_>
373 struct SupportedOptimizerTypeTraits<
375 typename std::enable_if<std::is_arithmetic<ReturnType_>::value>::type>
377 static const bool is_supported =
true;
388 template <
typename ReturnType_>
389 struct SupportedOptimizerTypeTraits<
391 typename std::enable_if<
392 boost::is_complex<ReturnType_>::value &&
393 std::is_arithmetic<typename ReturnType_::value_type>::value>::type>
395 static const bool is_supported =
true;
397 using ReturnType =
typename std::conditional<
398 std::is_same<ReturnType_, std::complex<float>>
::value,
400 std::complex<double>>::type;
405 template <
typename ReturnType_>
406 struct DictionaryOptimizer<
408 typename std::enable_if<
409 SupportedOptimizerTypeTraits<ReturnType_>::is_supported>::type>
412 typename SupportedOptimizerTypeTraits<ReturnType_>::ReturnType;
414 internal::DictionarySubstitutionVisitor<ReturnType, SD::Expression>;
427 const SymEngine::vec_basic & independent_symbols,
428 const SymEngine::vec_basic & dependent_functions,
432 optimizer.init(independent_symbols,
443 template <
class Archive>
445 save(Archive & archive,
446 const unsigned int version,
449 optimizer.save(archive, version);
458 template <
class Archive>
460 load(Archive & archive,
461 const unsigned int version,
463 const SymEngine::vec_basic & ,
464 const SymEngine::vec_basic & ,
467 optimizer.load(archive, version);
487 template <
typename Stream>
489 print(Stream & stream,
491 const bool print_independent_symbols =
false,
492 const bool print_dependent_functions =
false,
493 const bool print_cse_reductions =
true)
495 optimizer.print(stream,
496 print_independent_symbols,
497 print_dependent_functions,
498 print_cse_reductions);
504 template <
typename ReturnType_>
505 struct LambdaOptimizer<
507 typename std::enable_if<
508 SupportedOptimizerTypeTraits<ReturnType_>::is_supported>::type>
513 std::complex<double>>::type;
516 SymEngine::LambdaRealDoubleVisitor,
517 SymEngine::LambdaComplexDoubleVisitor>::type;
530 const SymEngine::vec_basic & independent_symbols,
531 const SymEngine::vec_basic & dependent_functions,
535 optimizer.init(independent_symbols,
546 template <
class Archive>
558 template <
class Archive>
563 const SymEngine::vec_basic & independent_symbols,
564 const SymEngine::vec_basic & dependent_functions,
567 initialize(optimizer,
590 template <
typename StreamType>
604 # ifdef HAVE_SYMENGINE_LLVM
605 template <
typename ReturnType_>
606 struct LLVMOptimizer<
608 typename std::enable_if<std::is_arithmetic<ReturnType_>::value>::type>
616 SymEngine::LLVMFloatVisitor,
617 SymEngine::LLVMDoubleVisitor>::type;
623 static const bool supported_by_LLVM =
true;
636 const SymEngine::vec_basic & independent_symbols,
637 const SymEngine::vec_basic & dependent_functions,
642 optimizer.init(independent_symbols,
654 template <
class Archive>
656 save(Archive &archive,
660 const std::string llvm_compiled_function = optimizer.dumps();
661 archive & llvm_compiled_function;
670 template <
class Archive>
672 load(Archive &archive,
675 const SymEngine::vec_basic & ,
676 const SymEngine::vec_basic & ,
679 std::string llvm_compiled_function;
680 archive & llvm_compiled_function;
681 optimizer.loads(llvm_compiled_function);
701 template <
typename StreamType>
719 template <
typename ReturnType_>
720 struct LLVMOptimizer<
722 typename std::enable_if<
723 boost::is_complex<ReturnType_>::value &&
724 std::is_arithmetic<typename ReturnType_::value_type>::value>::type>
728 using ReturnType =
typename LambdaOptimizer<ReturnType_>::ReturnType;
736 static const bool supported_by_LLVM =
false;
749 const SymEngine::vec_basic & ,
750 const SymEngine::vec_basic & ,
762 template <
class Archive>
777 template <
class Archive>
782 const SymEngine::vec_basic & ,
783 const SymEngine::vec_basic & ,
806 template <
typename StreamType>
817 # endif // HAVE_SYMENGINE_LLVM
823 template <
typename ReturnType,
typename Optimizer>
824 struct OptimizerHelper<ReturnType,
826 typename std::enable_if<std::is_same<
828 typename Optimizer::ReturnType>::value>::type>
840 const SymEngine::vec_basic & independent_symbols,
841 const SymEngine::vec_basic & dependent_functions,
849 Optimizer::initialize(*optimizer,
872 std::vector<ReturnType> & output_values,
873 const std::vector<ReturnType> & substitution_values)
876 optimizer->call(output_values.data(), substitution_values.data());
885 template <
class Archive>
887 save(Archive & archive,
888 const unsigned int version,
896 Optimizer::save(archive, version, *optimizer);
905 template <
class Archive>
907 load(Archive & archive,
908 const unsigned int version,
910 const SymEngine::vec_basic & independent_symbols,
911 const SymEngine::vec_basic & dependent_functions,
919 Optimizer::load(archive,
944 template <
typename Stream>
946 print(Stream & stream,
948 const bool print_independent_symbols =
false,
949 const bool print_dependent_functions =
false,
950 const bool print_cse_reductions =
true)
957 Optimizer::print(stream,
959 print_independent_symbols,
960 print_dependent_functions,
961 print_cse_reductions);
965 template <
typename ReturnType,
typename Optimizer>
966 struct OptimizerHelper<ReturnType,
968 typename std::enable_if<!std::is_same<
970 typename Optimizer::ReturnType>::value>::type>
982 const SymEngine::vec_basic & independent_symbols,
983 const SymEngine::vec_basic & dependent_functions,
989 optimizer->init(independent_symbols,
1011 std::vector<ReturnType> & output_values,
1012 const std::vector<ReturnType> & substitution_values)
1018 std::vector<typename Optimizer::ReturnType> int_outputs(
1019 output_values.size());
1020 std::vector<typename Optimizer::ReturnType> int_inputs(
1021 substitution_values.size());
1024 substitution_values.end(),
1025 int_inputs.begin());
1026 optimizer->call(int_outputs.data(), int_inputs.data());
1029 output_values.begin());
1038 template <
class Archive>
1040 save(Archive & archive,
1041 const unsigned int version,
1045 Optimizer::save(archive, version, *optimizer);
1054 template <
class Archive>
1056 load(Archive & archive,
1057 const unsigned int version,
1059 const SymEngine::vec_basic & independent_symbols,
1060 const SymEngine::vec_basic & dependent_functions,
1068 Optimizer::load(archive,
1071 independent_symbols,
1072 dependent_functions,
1073 optimization_flags);
1093 template <
typename Stream>
1095 print(Stream & stream,
1097 const bool print_cse_reductions =
true,
1098 const bool print_independent_symbols =
false,
1099 const bool print_dependent_functions =
false)
1103 optimizer->print(stream,
1104 print_independent_symbols,
1105 print_dependent_functions,
1106 print_cse_reductions);
1132 template <
typename NumberType,
1135 template <
int,
int,
typename>
class TensorType>
1136 TensorType<rank, dim, NumberType>
1138 const TensorType<rank, dim, Expression> &symbol_tensor,
1141 TensorType<rank, dim, NumberType> out;
1142 for (
unsigned int i = 0; i < out.n_independent_components; ++i)
1145 out.unrolled_to_component_indices(i));
1146 out[indices] = optimizer.
evaluate(symbol_tensor[indices]);
1169 template <
typename NumberType,
int dim>
1176 for (
unsigned int i = 0;
1177 i < SymmetricTensor<2, dim>::n_independent_components;
1179 for (
unsigned int j = 0;
1180 j < SymmetricTensor<2, dim>::n_independent_components;
1184 make_rank_4_tensor_indices<dim>(i, j);
1185 out[indices] = optimizer.
evaluate(symbol_tensor[indices]);
1208 template <
typename NumberType,
typename T>
1234 template <
typename NumberType,
typename T>
1263 template <
typename NumberType,
typename T,
typename... Args>
1267 const Args &... other_functions)
1287 template <
int,
int,
typename>
class TensorType>
1290 const TensorType<rank, dim, Expression> &symbol_tensor)
1293 out.reserve(symbol_tensor.n_independent_components);
1294 for (
unsigned int i = 0; i < symbol_tensor.n_independent_components;
1298 symbol_tensor.unrolled_to_component_indices(i));
1299 out.push_back(symbol_tensor[indices].get_RCP());
1321 for (
unsigned int i = 0;
1322 i < SymmetricTensor<2, dim>::n_independent_components;
1324 for (
unsigned int j = 0;
1325 j < SymmetricTensor<2, dim>::n_independent_components;
1329 make_rank_4_tensor_indices<dim>(i, j);
1330 out.push_back(symbol_tensor[indices].get_RCP());
1431 template <
typename ReturnType>
1432 class BatchOptimizer
1496 template <
typename Stream>
1498 print(Stream &stream,
const bool print_cse =
false)
const;
1507 template <
class Archive>
1509 save(Archive &archive,
const unsigned int version)
const;
1523 template <
class Archive>
1525 load(Archive &archive,
const unsigned int version);
1548 template <
class Archive>
1550 serialize(Archive &archive,
const unsigned int version);
1554 BOOST_SERIALIZATION_SPLIT_MEMBER()
1637 template <
int rank,
int dim>
1645 template <
int rank,
int dim>
1673 template <
typename T>
1690 template <
typename T,
typename... Args>
1823 const std::vector<ReturnType> &values)
const;
1836 substitute(
const SymEngine::vec_basic & symbols,
1837 const std::vector<ReturnType> &values)
const;
1874 const std::vector<ReturnType> &
1885 evaluate(
const Expression &func)
const;
1895 std::vector<ReturnType>
1896 evaluate(
const std::vector<Expression> &funcs)
const;
1906 template <
int rank,
int dim>
1919 template <
int rank,
int dim>
1969 const SymEngine::RCP<const SymEngine::Basic> &
function)
const;
2066 substitute(
const std::vector<ReturnType> &substitution_values)
const;
2077 template <
typename ReturnType>
2078 template <
typename Stream>
2084 stream <<
"Method? " << optimization_method() <<
"\n";
2085 stream <<
"Flags: " << optimization_flags() <<
"\n";
2086 stream <<
"Optimized? " << (optimized() ?
"Yes" :
"No") <<
"\n";
2087 stream <<
"Values substituted? " << values_substituted() <<
"\n\n";
2090 stream <<
"Symbols (" << n_independent_variables()
2091 <<
" independent variables):"
2094 for (SD::types::substitution_map::const_iterator it =
2095 independent_variables_symbols.begin();
2096 it != independent_variables_symbols.end();
2099 stream << cntr <<
": " << it->first <<
"\n";
2101 stream <<
"\n" << std::flush;
2104 stream <<
"Functions (" << n_dependent_variables()
2105 <<
" dependent variables):"
2108 for (
typename SD::types::symbol_vector::const_iterator it =
2109 dependent_variables_functions.begin();
2110 it != dependent_variables_functions.end();
2113 stream << cntr <<
": " << (*it) <<
"\n";
2115 stream <<
"\n" << std::flush;
2121 const bool print_cse_reductions =
true;
2122 const bool print_independent_symbols =
false;
2123 const bool print_dependent_functions =
false;
2127 Assert(
dynamic_cast<typename internal::DictionaryOptimizer<
2129 ExcMessage(
"Cannot cast optimizer to Dictionary type."));
2131 internal::OptimizerHelper<
2133 internal::DictionaryOptimizer<ReturnType>>::
2135 dynamic_cast<typename internal::DictionaryOptimizer<
2137 print_independent_symbols,
2138 print_dependent_functions,
2139 print_cse_reductions);
2141 stream <<
"\n" << std::flush;
2145 Assert(
dynamic_cast<typename internal::LambdaOptimizer<
2147 ExcMessage(
"Cannot cast optimizer to Lambda type."));
2149 internal::OptimizerHelper<ReturnType,
2150 internal::LambdaOptimizer<ReturnType>>::
2152 dynamic_cast<typename internal::LambdaOptimizer<
2154 print_independent_symbols,
2155 print_dependent_functions,
2156 print_cse_reductions);
2158 # ifdef HAVE_SYMENGINE_LLVM
2161 Assert(
dynamic_cast<typename internal::LLVMOptimizer<
2163 ExcMessage(
"Cannot cast optimizer to LLVM type."));
2165 internal::OptimizerHelper<ReturnType,
2166 internal::LLVMOptimizer<ReturnType>>::
2168 dynamic_cast<typename internal::LLVMOptimizer<
2170 print_independent_symbols,
2171 print_dependent_functions,
2172 print_cse_reductions);
2174 # endif // HAVE_SYMENGINE_LLVM
2181 if (values_substituted())
2183 stream <<
"Evaluated functions:"
2185 stream << std::flush;
2187 for (
typename std::vector<ReturnType>::const_iterator it =
2188 dependent_variables_output.begin();
2189 it != dependent_variables_output.end();
2192 stream << cntr <<
": " << (*it) <<
"\n";
2194 stream <<
"\n" << std::flush;
2200 template <
typename ReturnType>
2201 template <
class Archive>
2204 const unsigned int version)
const
2209 static_cast<typename std::underlying_type<OptimizerType>::type
>(
2215 static_cast<typename std::underlying_type<OptimizationFlags>::type
>(
2222 ar &independent_variables_symbols;
2223 ar &dependent_variables_functions;
2225 ar &dependent_variables_output;
2226 ar &map_dep_expr_vec_entry;
2227 ar &ready_for_value_extraction;
2230 has_been_serialized =
true;
2231 ar &has_been_serialized;
2240 *opt =
dynamic_cast<typename internal::DictionaryOptimizer<
2245 internal::OptimizerHelper<
2247 internal::DictionaryOptimizer<ReturnType>>::save(ar, version, opt);
2250 *opt =
dynamic_cast<typename internal::LambdaOptimizer<
2255 internal::OptimizerHelper<
2257 internal::LambdaOptimizer<ReturnType>>::save(ar, version, opt);
2259 # ifdef HAVE_SYMENGINE_LLVM
2261 *opt =
dynamic_cast<typename internal::LLVMOptimizer<
2266 internal::OptimizerHelper<
2268 internal::LLVMOptimizer<ReturnType>>::save(ar, version, opt);
2279 template <
typename ReturnType>
2280 template <
class Archive>
2292 typename std::underlying_type<OptimizerType>::type m;
2297 typename std::underlying_type<OptimizationFlags>::type f;
2304 ar &independent_variables_symbols;
2305 ar &dependent_variables_functions;
2307 ar &dependent_variables_output;
2308 ar &map_dep_expr_vec_entry;
2309 ar &ready_for_value_extraction;
2311 ar &has_been_serialized;
2318 create_optimizer(optimizer);
2328 *opt =
dynamic_cast<typename internal::DictionaryOptimizer<
2333 internal::OptimizerHelper<ReturnType,
2334 internal::DictionaryOptimizer<ReturnType>>::
2341 dependent_variables_functions),
2342 optimization_flags());
2345 *opt =
dynamic_cast<typename internal::LambdaOptimizer<
2350 internal::OptimizerHelper<ReturnType,
2351 internal::LambdaOptimizer<ReturnType>>::
2358 dependent_variables_functions),
2359 optimization_flags());
2361 # ifdef HAVE_SYMENGINE_LLVM
2363 *opt =
dynamic_cast<typename internal::LLVMOptimizer<
2368 internal::OptimizerHelper<ReturnType,
2369 internal::LLVMOptimizer<ReturnType>>::
2376 dependent_variables_functions),
2377 optimization_flags());
2388 template <
typename ReturnType>
2389 template <
int rank,
int dim>
2394 Assert(optimized() ==
false,
2396 "Cannot register functions once the optimizer is finalised."));
2398 register_vector_functions(
2404 template <
typename ReturnType>
2405 template <
int rank,
int dim>
2410 Assert(optimized() ==
false,
2412 "Cannot register functions once the optimizer is finalised."));
2414 register_vector_functions(
2420 template <
typename ReturnType>
2421 template <
typename T,
typename... Args>
2425 const Args &... other_functions)
2433 template <
typename ReturnType>
2434 template <
typename T>
2444 template <
typename ReturnType>
2445 template <
int rank,
int dim>
2451 values_substituted() ==
true,
2453 "The optimizer is not configured to perform evaluation. "
2454 "This action can only performed after substitute() has been called."));
2461 template <
typename ReturnType>
2462 template <
int rank,
int dim>
2468 values_substituted() ==
true,
2470 "The optimizer is not configured to perform evaluation. "
2471 "This action can only performed after substitute() has been called."));
2484 #endif // DEAL_II_WITH_SYMENGINE