From 98dd9f5f2322e3ecd325aef690d7b771fe68064b Mon Sep 17 00:00:00 2001 From: Jean-Paul Pelteret Date: Tue, 7 May 2019 18:34:01 +0200 Subject: [PATCH] Implement substitution and evaluation for SD scalar types --- .../sd/symengine_scalar_operations.h | 188 ++++++++++++++++++ .../sd/symengine_scalar_operations.cc | 8 + 2 files changed, 196 insertions(+) diff --git a/include/deal.II/differentiation/sd/symengine_scalar_operations.h b/include/deal.II/differentiation/sd/symengine_scalar_operations.h index 257adb0005..ce712bd3eb 100644 --- a/include/deal.II/differentiation/sd/symengine_scalar_operations.h +++ b/include/deal.II/differentiation/sd/symengine_scalar_operations.h @@ -1246,6 +1246,155 @@ namespace Differentiation const std::vector> &symbol_values, const bool force_cyclic_dependency_resolution = false); + /** + * Perform a single substitution sweep of a set of symbols into the given + * symbolic expression. + * The symbols in the @p expression that correspond to the entry keys + * of the @p substitution_map are substituted with the map entry's associated + * value. + * This substitution function may be used to give a set of symbolic + * variables either a numeric interpretation or some symbolic definition. + * + * @note It is not required that all symbolic expressions be fully resolved + * when using this function. In other words, partial substitutions are + * valid. + * + * @note This function call is typically expensive, as by default it performs a + * dictionary substitution for the symbols in the symbolic expression. + * Should the numerical values of some symbolic expression be derired, then + * this performance deficit may be mitigated through the use of the + * BatchOptimizer class. + * Situation dependent, the overhead of using a typical dictionary based + * substitution may be on par with that of the a substitution performed + * using a BatchOptimizer. This is because there is an overhead to setting + * up the optimizer, so this should be taken into consideration if + * substitution is to occur for the given symbolic + * expression only a few times. + * + * @note If the symbols stored in the map are explicitly dependent on one another, + * then the returned result depends on order in which the map is traversed. + * It is recommended to first resolve all inter-dependencies in the map + * using the resolve_explicit_dependencies() function. + * Examples: + * 1. If map["a"] == 1 and map["b"] == "a"+ 2 then + * then the function $f(a,b(a)) = a+b$ will be evaluated and the result + * $f\vert_{a=1,b=a+2} = 3+a$ is returned. This return is because the + * symbol "a" is substituted throughout the function first, and only + * then is the symbol "b(a)" substituted, by which time its explicit + * dependency on "a" cannot be resolved. + * 2. If map["a"] == "b"+2 and map["b"] == 1 then + * then the function $f(a(b),a) = a+b$ will be evaluated and the result + * $f\vert_{a=b+2, b} = [b+2+b]_{b=1} = 4$ is returned. This is because + * the explicitly dependent symbol "a(b)" is substituted first followed by + * the symbol "b". + */ + Expression + substitute(const Expression & expression, + const types::substitution_map &substitution_map); + + /** + * Perform a substitution of the @p symbol into the given + * @p expression, with the result that all matches are assigned + * the corresponding @p value. + * This substitution function may be used to give a set of symbolic + * variables either a numeric interpretation or some symbolic definition. + * + * For more information regarding the performance of symbolic substitution, + * see the other @ref substitute(const Expression &, + * const types::substitution_map &) function. + * + * @note It is not required that all symbolic expressions be fully resolved + * when using this function. In other words, partial substitutions are + * valid. + */ + template + Expression + substitute(const Expression &expression, + const Expression &symbol, + const ValueType & value); + + /** + * Perform a single substitution sweep of a set of symbols into the given + * symbolic expression. + * The symbols in the @p expression that correspond to a matching entry key + * of the @p symbol_values vector entry are substituted by the entry's associated + * value. + * This substitution function may be used to give a set of symbolic + * variables either a numeric interpretation or some symbolic definition. + * + * For more information regarding the performance of symbolic substitution, + * see the other @ref substitute(const Expression &, + * const types::substitution_map &) function. + * + * @note It is not required that all symbolic expressions be fully resolved + * when using this function. In other words, partial substitutions are + * valid. + * + * @tparam Args Any symbolic type and value combination that is understood + * by the make_substitution_map() functions. This includes + * arguments involving individual Expressions, + * std::vector, as well as Tensors and SymmetricTensors + * of Expressions. + */ + template + ExpressionType + substitute(const ExpressionType &expression, const Args &... symbol_values); + + /** + * Perform a single substitution sweep of a set of symbols into the given + * symbolic function, and immediately evaluate the result. + * The symbols in the @p expression that correspond to the entry keys + * of the @p substitution_map are substituted with the map entry's associated + * value. + * This substitution function is used to give a set of symbolic variables + * a numeric interpretation, with the returned result being of the type + * specified by the @p ValueType template argument. + * + * For more information regarding the performance of symbolic substitution, + * and the outcome of evaluation using a substitution map with cyclic + * dependencies, see the @ref substitute(const Expression &, + * const types::substitution_map &) function. + * + * @note It is required that all symbols in the @p expression be + * successfully resolved by the @p substitution_map. + * If only partial substitution is performed, then an error is thrown. + */ + template + ValueType + substitute_and_evaluate(const Expression & expression, + const types::substitution_map &substitution_map); + + /** + * Perform a single substitution sweep of a set of symbols into the given + * symbolic function, and immediately evaluate the result. + * The symbols in the @p expression that correspond to the entry keys + * of the @p substitution_map are substituted with the map entry's associated + * value. + * This substitution function is used to give a set of symbolic variables + * a numeric interpretation, with the returned result being of the type + * specified by the @p ValueType template argument. + * + * For more information regarding the performance of symbolic substitution, + * and the outcome of evaluation using a substitution map with cyclic + * dependencies, see the @ref substitute(const Expression &, + * const types::substitution_map &) function. + * + * @note It is required that all symbols in the @p expression be + * successfully resolved by the substitution map that is generated with the + * input collection of @p symbol_values. + * If only partial substitution is performed, then an error is thrown. + * + * @tparam Args Any symbolic type and value combination that is understood + * by the make_substitution_map() functions. This includes + * arguments involving individual Expressions, + * std::vector, as well as Tensors and SymmetricTensors + * of Expressions. + */ + template + ValueType + substitute_and_evaluate(const Expression &expression, + const Args &... symbol_values); + //@} } // namespace SD @@ -1705,6 +1854,45 @@ namespace Differentiation force_cyclic_dependency_resolution); } + + template + Expression + substitute(const Expression &expression, + const Expression &symbol, + const ValueType & value) + { + return expression.substitute(symbol, value); + } + + + template + ExpressionType + substitute(const ExpressionType &expression, const Args &... symbol_values) + { + // Call other function + return substitute(expression, make_substitution_map(symbol_values...)); + } + + + template + ValueType + substitute_and_evaluate(const Expression & expression, + const types::substitution_map &substitution_map) + { + return expression.substitute_and_evaluate(substitution_map); + } + + + template + ValueType + substitute_and_evaluate(const Expression &expression, + const Args &... symbol_values) + { + // Call other function + return substitute_and_evaluate( + expression, make_substitution_map(symbol_values...)); + } + } // namespace SD } // namespace Differentiation diff --git a/source/differentiation/sd/symengine_scalar_operations.cc b/source/differentiation/sd/symengine_scalar_operations.cc index 438b804257..6366677ba1 100644 --- a/source/differentiation/sd/symengine_scalar_operations.cc +++ b/source/differentiation/sd/symengine_scalar_operations.cc @@ -253,6 +253,14 @@ namespace Differentiation return symbol_values_resolved; } + + Expression + substitute(const Expression & expression, + const types::substitution_map &substitution_map) + { + return expression.substitute(substitution_map); + } + } // namespace SD } // namespace Differentiation -- 2.39.5