15#ifndef dealii_differentiation_sd_symengine_optimizer_h
16#define dealii_differentiation_sd_symengine_optimizer_h
20#ifdef DEAL_II_WITH_SYMENGINE
23# include <symengine/basic.h>
24# include <symengine/dict.h>
25# include <symengine/symengine_exception.h>
26# include <symengine/symengine_rcp.h>
29# include <symengine/lambda_double.h>
30# include <symengine/visitor.h>
31# ifdef HAVE_SYMENGINE_LLVM
32# include <symengine/llvm_double.h>
45# include <boost/serialization/split_member.hpp>
46# include <boost/type_traits.hpp>
51# include <type_traits>
73 "SymEngine has not been built with LLVM support.");
80 "The SymEngine LLVM optimizer does not (yet) support the "
81 "selected return type.");
87 template <
typename ReturnType>
118 template <
typename StreamType>
180 static_cast<unsigned int>(f2));
212 static_cast<unsigned int>(f2));
258 const bool use_agg_opt =
260 const int opt_level = (use_agg_opt ? 3 : 2);
270 template <
typename StreamType>
274 s <<
" OptimizationFlags|";
297 template <
typename ReturnType,
typename T =
void>
310 template <
typename ReturnType,
typename T =
void>
314# ifdef HAVE_SYMENGINE_LLVM
324 template <
typename ReturnType,
typename T =
void>
325 struct LLVMOptimizer;
344 template <
typename ReturnType,
typename Optimizer,
typename T =
void>
356 template <
typename ReturnType_,
typename T =
void>
357 struct SupportedOptimizerTypeTraits
359 static const bool is_supported =
false;
361 using ReturnType = void;
367 template <
typename ReturnType_>
368 struct SupportedOptimizerTypeTraits<
370 std::enable_if_t<std::is_arithmetic_v<ReturnType_>>>
372 static const bool is_supported =
true;
374 using ReturnType =
typename std::
375 conditional<std::is_same_v<ReturnType_, float>, float,
double>::type;
381 template <
typename ReturnType_>
382 struct SupportedOptimizerTypeTraits<
385 boost::is_complex<ReturnType_>::value &&
386 std::is_arithmetic_v<typename ReturnType_::value_type>>>
388 static const bool is_supported =
true;
391 std::conditional_t<std::is_same_v<ReturnType_, std::complex<float>>,
393 std::complex<double>>;
398 template <
typename ReturnType_>
399 struct DictionaryOptimizer<ReturnType_,
400 std::enable_if_t<SupportedOptimizerTypeTraits<
401 ReturnType_>::is_supported>>
404 typename SupportedOptimizerTypeTraits<ReturnType_>::ReturnType;
406 internal::DictionarySubstitutionVisitor<ReturnType, SD::Expression>;
419 const SymEngine::vec_basic &independent_symbols,
420 const SymEngine::vec_basic &dependent_functions,
424 optimizer.init(independent_symbols,
435 template <
class Archive>
437 save(Archive &archive,
438 const unsigned int version,
441 optimizer.save(archive, version);
450 template <
class Archive>
452 load(Archive &archive,
453 const unsigned int version,
455 const SymEngine::vec_basic & ,
456 const SymEngine::vec_basic & ,
459 optimizer.load(archive, version);
479 template <
typename Stream>
481 print(Stream &stream,
483 const bool print_independent_symbols =
false,
484 const bool print_dependent_functions =
false,
485 const bool print_cse_reductions =
true)
487 optimizer.print(stream,
488 print_independent_symbols,
489 print_dependent_functions,
490 print_cse_reductions);
496 template <
typename ReturnType_>
497 struct LambdaOptimizer<ReturnType_,
498 std::enable_if_t<SupportedOptimizerTypeTraits<
499 ReturnType_>::is_supported>>
502 std::conditional_t<!boost::is_complex<ReturnType_>::value,
504 std::complex<double>>;
506 std::conditional_t<!boost::is_complex<ReturnType_>::value,
507 SymEngine::LambdaRealDoubleVisitor,
508 SymEngine::LambdaComplexDoubleVisitor>;
521 const SymEngine::vec_basic &independent_symbols,
522 const SymEngine::vec_basic &dependent_functions,
526 optimizer.init(independent_symbols,
537 template <
class Archive>
549 template <
class Archive>
554 const SymEngine::vec_basic &independent_symbols,
555 const SymEngine::vec_basic &dependent_functions,
558 initialize(optimizer,
581 template <
typename StreamType>
595# ifdef HAVE_SYMENGINE_LLVM
596 template <
typename ReturnType_>
597 struct LLVMOptimizer<ReturnType_,
598 std::enable_if_t<std::is_arithmetic_v<ReturnType_>>>
600 using ReturnType =
typename std::
601 conditional<std::is_same_v<ReturnType_, float>, float,
double>::type;
603 std::conditional_t<std::is_same_v<ReturnType_, float>,
604 SymEngine::LLVMFloatVisitor,
605 SymEngine::LLVMDoubleVisitor>;
611 static const bool supported_by_LLVM =
true;
623 initialize(OptimizerType &optimizer,
624 const SymEngine::vec_basic &independent_symbols,
625 const SymEngine::vec_basic &dependent_functions,
626 const enum OptimizationFlags &optimization_flags)
630 optimizer.init(independent_symbols,
642 template <
class Archive>
644 save(Archive &archive,
646 OptimizerType &optimizer)
648 const std::string llvm_compiled_function = optimizer.dumps();
649 archive &llvm_compiled_function;
658 template <
class Archive>
660 load(Archive &archive,
662 OptimizerType &optimizer,
663 const SymEngine::vec_basic & ,
664 const SymEngine::vec_basic & ,
665 const enum OptimizationFlags & )
667 std::string llvm_compiled_function;
668 archive &llvm_compiled_function;
669 optimizer.loads(llvm_compiled_function);
689 template <
typename StreamType>
692 const OptimizerType & ,
707 template <
typename ReturnType_>
708 struct LLVMOptimizer<
711 boost::is_complex<ReturnType_>::value &&
712 std::is_arithmetic_v<typename ReturnType_::value_type>>>
716 using ReturnType =
typename LambdaOptimizer<ReturnType_>::ReturnType;
718 typename LambdaOptimizer<ReturnType_>::OptimizerType;
724 static const bool supported_by_LLVM =
false;
736 initialize(OptimizerType & ,
737 const SymEngine::vec_basic & ,
738 const SymEngine::vec_basic & ,
739 const enum OptimizationFlags & )
750 template <
class Archive>
765 template <
class Archive>
770 const SymEngine::vec_basic & ,
771 const SymEngine::vec_basic & ,
772 const enum OptimizationFlags & )
794 template <
typename StreamType>
797 const OptimizerType & ,
811 template <
typename ReturnType,
typename Optimizer>
812 struct OptimizerHelper<
816 std::is_same_v<ReturnType, typename Optimizer::ReturnType>>>
827 initialize(
typename Optimizer::OptimizerType *optimizer,
828 const SymEngine::vec_basic &independent_symbols,
829 const SymEngine::vec_basic &dependent_functions,
837 Optimizer::initialize(*optimizer,
859 substitute(
typename Optimizer::OptimizerType *optimizer,
860 std::vector<ReturnType> &output_values,
861 const std::vector<ReturnType> &substitution_values)
864 optimizer->call(output_values.data(), substitution_values.data());
873 template <
class Archive>
875 save(Archive &archive,
876 const unsigned int version,
877 typename Optimizer::OptimizerType *optimizer)
884 Optimizer::save(archive, version, *optimizer);
893 template <
class Archive>
895 load(Archive &archive,
896 const unsigned int version,
897 typename Optimizer::OptimizerType *optimizer,
898 const SymEngine::vec_basic &independent_symbols,
899 const SymEngine::vec_basic &dependent_functions,
907 Optimizer::load(archive,
932 template <
typename Stream>
934 print(Stream &stream,
935 typename Optimizer::OptimizerType *optimizer,
936 const bool print_independent_symbols =
false,
937 const bool print_dependent_functions =
false,
938 const bool print_cse_reductions =
true)
945 Optimizer::print(stream,
947 print_independent_symbols,
948 print_dependent_functions,
949 print_cse_reductions);
953 template <
typename ReturnType,
typename Optimizer>
954 struct OptimizerHelper<
958 !std::is_same_v<ReturnType, typename Optimizer::ReturnType>>>
969 initialize(
typename Optimizer::OptimizerType *optimizer,
970 const SymEngine::vec_basic &independent_symbols,
971 const SymEngine::vec_basic &dependent_functions,
977 optimizer->init(independent_symbols,
998 substitute(
typename Optimizer::OptimizerType *optimizer,
999 std::vector<ReturnType> &output_values,
1000 const std::vector<ReturnType> &substitution_values)
1006 std::vector<typename Optimizer::ReturnType> int_outputs(
1007 output_values.size());
1008 std::vector<typename Optimizer::ReturnType> int_inputs(
1009 substitution_values.size());
1011 std::copy(substitution_values.begin(),
1012 substitution_values.end(),
1013 int_inputs.begin());
1014 optimizer->call(int_outputs.data(), int_inputs.data());
1015 std::copy(int_outputs.begin(),
1017 output_values.begin());
1026 template <
class Archive>
1028 save(Archive &archive,
1029 const unsigned int version,
1030 typename Optimizer::OptimizerType *optimizer)
1033 Optimizer::save(archive, version, *optimizer);
1042 template <
class Archive>
1044 load(Archive &archive,
1045 const unsigned int version,
1046 typename Optimizer::OptimizerType *optimizer,
1047 const SymEngine::vec_basic &independent_symbols,
1048 const SymEngine::vec_basic &dependent_functions,
1056 Optimizer::load(archive,
1059 independent_symbols,
1060 dependent_functions,
1061 optimization_flags);
1081 template <
typename Stream>
1083 print(Stream &stream,
1084 typename Optimizer::OptimizerType *optimizer,
1085 const bool print_cse_reductions =
true,
1086 const bool print_independent_symbols =
false,
1087 const bool print_dependent_functions =
false)
1091 optimizer->print(stream,
1092 print_independent_symbols,
1093 print_dependent_functions,
1094 print_cse_reductions);
1125 template <
typename NumberType,
1128 template <
int,
int,
typename>
1130 TensorType<rank, dim, NumberType>
1132 const TensorType<rank, dim, Expression> &symbol_tensor,
1133 const std::vector<NumberType> &cached_evaluation,
1136 TensorType<rank, dim, NumberType> out;
1137 for (
unsigned int i = 0; i < out.n_independent_components; ++i)
1140 out.unrolled_to_component_indices(i));
1142 optimizer.
extract(symbol_tensor[indices], cached_evaluation);
1170 template <
typename NumberType,
int dim>
1174 const std::vector<NumberType> &cached_evaluation,
1178 for (
unsigned int i = 0;
1179 i < SymmetricTensor<2, dim>::n_independent_components;
1181 for (
unsigned int j = 0;
1182 j < SymmetricTensor<2, dim>::n_independent_components;
1186 make_rank_4_tensor_indices<dim>(i, j);
1188 optimizer.
extract(symbol_tensor[indices], cached_evaluation);
1211 template <
typename NumberType,
typename T>
1237 template <
typename NumberType,
typename T>
1240 const std::vector<T> &functions)
1242 for (
const auto &function : functions)
1266 template <
typename NumberType,
typename T,
typename... Args>
1270 const Args &...other_functions)
1290 template <
int,
int,
typename>
1294 const TensorType<rank, dim, Expression> &symbol_tensor)
1297 out.reserve(symbol_tensor.n_independent_components);
1298 for (
unsigned int i = 0; i < symbol_tensor.n_independent_components;
1302 symbol_tensor.unrolled_to_component_indices(i));
1303 out.push_back(symbol_tensor[indices].get_RCP());
1325 for (
unsigned int i = 0;
1326 i < SymmetricTensor<2, dim>::n_independent_components;
1328 for (
unsigned int j = 0;
1329 j < SymmetricTensor<2, dim>::n_independent_components;
1333 make_rank_4_tensor_indices<dim>(i, j);
1334 out.push_back(symbol_tensor[indices].get_RCP());
1433 template <
typename ReturnType>
1510 template <typename Stream>
1512 print(Stream &stream, const
bool print_cse = false) const;
1522 template <class Archive>
1524 save(Archive &archive, const
unsigned int version) const;
1539 template <class Archive>
1541 load(Archive &archive, const
unsigned int version);
1565 template <
class Archive>
1571 BOOST_SERIALIZATION_SPLIT_MEMBER()
1654 template <
int rank,
int dim>
1662 template <
int rank,
int dim>
1690 template <
typename T>
1707 template <
typename T,
typename... Args>
1826 substitute(
const SymEngine::map_basic_basic &substitution_map)
const;
1840 const std::vector<ReturnType> &values)
const;
1853 substitute(
const SymEngine::vec_basic &symbols,
1854 const std::vector<ReturnType> &values)
const;
1893 const std::vector<ReturnType> &
1914 std::vector<ReturnType>
1915 evaluate(
const std::vector<Expression> &funcs)
const;
1925 template <
int rank,
int dim>
1938 template <
int rank,
int dim>
1952 const std::vector<ReturnType> &cached_evaluation)
const;
1962 std::vector<ReturnType>
1963 extract(
const std::vector<Expression> &funcs,
1964 const std::vector<ReturnType> &cached_evaluation)
const;
1974 template <
int rank,
int dim>
1977 const std::vector<ReturnType> &cached_evaluation)
const;
1987 template <
int rank,
int dim>
1990 const std::vector<ReturnType> &cached_evaluation)
const;
2038 const SymEngine::RCP<const SymEngine::Basic> &function)
const;
2135 substitute(
const std::vector<ReturnType> &substitution_values)
const;
2146 template <
typename ReturnType>
2147 template <
typename Stream>
2153 stream <<
"Method? " << optimization_method() <<
'\n';
2154 stream <<
"Flags: " << optimization_flags() <<
'\n';
2155 stream <<
"Optimized? " << (optimized() ?
"Yes" :
"No") <<
'\n';
2156 stream <<
"Values substituted? " << values_substituted() <<
"\n\n";
2159 stream <<
"Symbols (" << n_independent_variables()
2160 <<
" independent variables):" <<
'\n';
2162 for (SD::types::substitution_map::const_iterator it =
2163 independent_variables_symbols.begin();
2164 it != independent_variables_symbols.end();
2167 stream << cntr <<
": " << it->first <<
'\n';
2169 stream <<
'\n' << std::flush;
2172 stream <<
"Functions (" << n_dependent_variables()
2173 <<
" dependent variables):" <<
'\n';
2175 for (
typename SD::types::symbol_vector::const_iterator it =
2176 dependent_variables_functions.begin();
2177 it != dependent_variables_functions.end();
2180 stream << cntr <<
": " << (*it) <<
'\n';
2182 stream <<
'\n' << std::flush;
2185 if (optimized() ==
true && use_symbolic_CSE() ==
true)
2188 const bool print_cse_reductions =
true;
2189 const bool print_independent_symbols =
false;
2190 const bool print_dependent_functions =
false;
2194 Assert(
dynamic_cast<typename internal::DictionaryOptimizer<
2196 ExcMessage(
"Cannot cast optimizer to Dictionary type."));
2198 internal::OptimizerHelper<
2200 internal::DictionaryOptimizer<ReturnType>>::
2202 dynamic_cast<typename internal::DictionaryOptimizer<
2204 print_independent_symbols,
2205 print_dependent_functions,
2206 print_cse_reductions);
2208 stream <<
'\n' << std::flush;
2212 Assert(
dynamic_cast<typename internal::LambdaOptimizer<
2214 ExcMessage(
"Cannot cast optimizer to Lambda type."));
2216 internal::OptimizerHelper<ReturnType,
2217 internal::LambdaOptimizer<ReturnType>>::
2219 dynamic_cast<typename internal::LambdaOptimizer<
2221 print_independent_symbols,
2222 print_dependent_functions,
2223 print_cse_reductions);
2225# ifdef HAVE_SYMENGINE_LLVM
2228 Assert(
dynamic_cast<typename internal::LLVMOptimizer<
2230 ExcMessage(
"Cannot cast optimizer to LLVM type."));
2232 internal::OptimizerHelper<ReturnType,
2233 internal::LLVMOptimizer<ReturnType>>::
2235 dynamic_cast<typename internal::LLVMOptimizer<
2237 print_independent_symbols,
2238 print_dependent_functions,
2239 print_cse_reductions);
2248 if (values_substituted())
2250 stream <<
"Evaluated functions:" <<
'\n';
2251 stream << std::flush;
2253 for (
typename std::vector<ReturnType>::const_iterator it =
2254 dependent_variables_output.begin();
2255 it != dependent_variables_output.end();
2258 stream << cntr <<
": " << (*it) <<
'\n';
2260 stream <<
'\n' << std::flush;
2266 template <
typename ReturnType>
2267 template <
class Archive>
2270 const unsigned int version)
const
2275 static_cast<typename std::underlying_type<OptimizerType>::type
>(
2281 static_cast<typename std::underlying_type<OptimizationFlags>::type
>(
2288 ar &independent_variables_symbols;
2289 ar &dependent_variables_functions;
2291 ar &dependent_variables_output;
2292 ar &map_dep_expr_vec_entry;
2293 ar &ready_for_value_extraction;
2296 has_been_serialized =
true;
2297 ar &has_been_serialized;
2305 if (
typename internal::DictionaryOptimizer<ReturnType>::OptimizerType
2306 *opt =
dynamic_cast<typename internal::DictionaryOptimizer<
2311 internal::OptimizerHelper<
2313 internal::DictionaryOptimizer<ReturnType>>::save(ar, version, opt);
2315 else if (
typename internal::LambdaOptimizer<ReturnType>::OptimizerType
2316 *opt =
dynamic_cast<typename internal::LambdaOptimizer<
2321 internal::OptimizerHelper<
2323 internal::LambdaOptimizer<ReturnType>>::save(ar, version, opt);
2325# ifdef HAVE_SYMENGINE_LLVM
2326 else if (
typename internal::LLVMOptimizer<ReturnType>::OptimizerType
2327 *opt =
dynamic_cast<typename internal::LLVMOptimizer<
2332 internal::OptimizerHelper<
2334 internal::LLVMOptimizer<ReturnType>>::save(ar, version, opt);
2345 template <
typename ReturnType>
2346 template <
class Archive>
2358 typename std::underlying_type<OptimizerType>::type m;
2363 typename std::underlying_type<OptimizationFlags>::type f;
2370 ar &independent_variables_symbols;
2371 ar &dependent_variables_functions;
2373 ar &dependent_variables_output;
2374 ar &map_dep_expr_vec_entry;
2375 ar &ready_for_value_extraction;
2377 ar &has_been_serialized;
2384 create_optimizer(optimizer);
2393 if (
typename internal::DictionaryOptimizer<ReturnType>::OptimizerType
2394 *opt =
dynamic_cast<typename internal::DictionaryOptimizer<
2399 internal::OptimizerHelper<ReturnType,
2400 internal::DictionaryOptimizer<ReturnType>>::
2407 dependent_variables_functions),
2408 optimization_flags());
2410 else if (
typename internal::LambdaOptimizer<ReturnType>::OptimizerType
2411 *opt =
dynamic_cast<typename internal::LambdaOptimizer<
2416 internal::OptimizerHelper<ReturnType,
2417 internal::LambdaOptimizer<ReturnType>>::
2424 dependent_variables_functions),
2425 optimization_flags());
2427# ifdef HAVE_SYMENGINE_LLVM
2428 else if (
typename internal::LLVMOptimizer<ReturnType>::OptimizerType
2429 *opt =
dynamic_cast<typename internal::LLVMOptimizer<
2434 internal::OptimizerHelper<ReturnType,
2435 internal::LLVMOptimizer<ReturnType>>::
2442 dependent_variables_functions),
2443 optimization_flags());
2454 template <
typename ReturnType>
2455 template <
int rank,
int dim>
2460 Assert(optimized() ==
false,
2462 "Cannot register functions once the optimizer is finalised."));
2464 register_vector_functions(
2470 template <
typename ReturnType>
2471 template <
int rank,
int dim>
2476 Assert(optimized() ==
false,
2478 "Cannot register functions once the optimizer is finalised."));
2480 register_vector_functions(
2486 template <
typename ReturnType>
2487 template <
typename T,
typename... Args>
2491 const Args &...other_functions)
2499 template <
typename ReturnType>
2500 template <
typename T>
2503 const std::vector<T> &functions)
2510 template <
typename ReturnType>
2511 template <
int rank,
int dim>
2515 const std::vector<ReturnType> &cached_evaluation)
const
2524 template <
typename ReturnType>
2525 template <
int rank,
int dim>
2531 values_substituted() ==
true,
2533 "The optimizer is not configured to perform evaluation. "
2534 "This action can only performed after substitute() has been called."));
2536 return extract(funcs, dependent_variables_output);
2541 template <
typename ReturnType>
2542 template <
int rank,
int dim>
2546 const std::vector<ReturnType> &cached_evaluation)
const
2555 template <
typename ReturnType>
2556 template <
int rank,
int dim>
2562 values_substituted() ==
true,
2564 "The optimizer is not configured to perform evaluation. "
2565 "This action can only performed after substitute() has been called."));
2567 return extract(funcs, dependent_variables_output);
SymmetricTensor< rank, dim, ReturnType > extract(const SymmetricTensor< rank, dim, Expression > &funcs, const std::vector< ReturnType > &cached_evaluation) const
bool use_symbolic_CSE() const
types::substitution_map independent_variables_symbols
types::symbol_vector dependent_variables_functions
void substitute(const types::substitution_map &substitution_map) const
enum OptimizationFlags flags
void register_functions(const T &functions, const Args &...other_functions)
void register_scalar_function(const SD::Expression &function)
const types::symbol_vector & get_dependent_functions() const
void create_optimizer(std::unique_ptr< SymEngine::Visitor > &optimizer)
bool ready_for_value_extraction
void print(Stream &stream, const bool print_cse=false) const
enum OptimizerType optimization_method() const
void copy_from(const BatchOptimizer &other)
void register_function(const Tensor< rank, dim, Expression > &function_tensor)
void set_optimization_method(const enum OptimizerType &optimization_method, const enum OptimizationFlags &optimization_flags=OptimizationFlags::optimize_all)
SymmetricTensor< rank, dim, ReturnType > evaluate(const SymmetricTensor< rank, dim, Expression > &funcs) const
void save(Archive &archive, const unsigned int version) const
enum OptimizationFlags optimization_flags() const
void register_functions(const types::symbol_vector &functions)
std::vector< ReturnType > dependent_variables_output
enum OptimizerType method
Tensor< rank, dim, ReturnType > extract(const Tensor< rank, dim, Expression > &funcs, const std::vector< ReturnType > &cached_evaluation) const
std::size_t n_dependent_variables() const
void serialize(Archive &archive, const unsigned int version)
void register_symbols(const types::substitution_map &substitution_map)
const std::vector< ReturnType > & evaluate() const
std::map< SD::Expression, std::size_t, SD::types::internal::ExpressionKeyLess > map_dependent_expression_to_vector_entry_t
void register_function(const Expression &function)
Tensor< rank, dim, ReturnType > evaluate(const Tensor< rank, dim, Expression > &funcs) const
std::unique_ptr< SymEngine::Visitor > optimizer
ReturnType extract(const Expression &func, const std::vector< ReturnType > &cached_evaluation) const
BatchOptimizer(BatchOptimizer &&) noexcept=default
void load(Archive &archive, const unsigned int version)
void register_functions(const std::vector< T > &functions)
bool is_valid_nonunique_dependent_variable(const SD::Expression &function) const
void register_vector_functions(const types::symbol_vector &functions)
std::size_t n_independent_variables() const
types::symbol_vector get_independent_symbols() const
void register_function(const SymmetricTensor< rank, dim, Expression > &function_tensor)
map_dependent_expression_to_vector_entry_t map_dep_expr_vec_entry
bool values_substituted() const
static constexpr unsigned int n_independent_components
#define DEAL_II_NAMESPACE_OPEN
#define DEAL_II_NAMESPACE_CLOSE
static ::ExceptionBase & ExcNotImplemented()
#define Assert(cond, exc)
static ::ExceptionBase & ExcSymEngineLLVMReturnTypeNotSupported()
#define DeclExceptionMsg(Exception, defaulttext)
static ::ExceptionBase & ExcSymEngineLLVMNotAvailable()
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcNotInitialized()
static ::ExceptionBase & ExcMessage(std::string arg1)
#define AssertThrow(cond, exc)
SD::types::symbol_vector extract_symbols(const SD::types::substitution_map &substitution_values)
SymEngine::vec_basic convert_expression_vector_to_basic_vector(const SD::types::symbol_vector &symbol_vector)
TensorType< rank, dim, NumberType > tensor_evaluate_optimized(const TensorType< rank, dim, Expression > &symbol_tensor, const std::vector< NumberType > &cached_evaluation, const BatchOptimizer< NumberType > &optimizer)
bool use_symbolic_CSE(const enum OptimizationFlags &flags)
types::symbol_vector unroll_to_expression_vector(const TensorType< rank, dim, Expression > &symbol_tensor)
int get_LLVM_optimization_level(const enum OptimizationFlags &flags)
void register_functions(BatchOptimizer< NumberType > &optimizer, const T &function)
std::vector< SD::Expression > symbol_vector
std::map< SD::Expression, SD::Expression, internal::ExpressionKeyLess > substitution_map
OptimizationFlags & operator|=(OptimizationFlags &f1, const OptimizationFlags f2)
Expression operator|(const Expression &lhs, const Expression &rhs)
Expression operator&(const Expression &lhs, const Expression &rhs)
Expression substitute(const Expression &expression, const types::substitution_map &substitution_map)
std::ostream & operator<<(std::ostream &stream, const Expression &expression)
OptimizationFlags & operator&=(OptimizationFlags &f1, const OptimizationFlags f2)
constexpr ReturnType< rank, T >::value_type & extract(T &t, const ArrayType &indices)