deal.II version GIT relicensing-6839-g338455934c 2026-10-02 12:10:01+00:00
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
Loading...
Searching...
No Matches
symengine_scalar_operations.cc
Go to the documentation of this file.
1// -----------------------------------------------------------------------------
2//
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception OR LGPL-2.1-or-later
4// Copyright (C) 2019 - 2026 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Detailed license information governing the source code and contributions
9// can be found in LICENSE.md and CONTRIBUTING.md at the top level directory.
10//
11// -----------------------------------------------------------------------------
12
13
14#include <deal.II/base/config.h>
15
16#ifdef DEAL_II_WITH_SYMENGINE
17
22
23# include <symengine/real_double.h>
24
25
26#endif // DEAL_II_WITH_SYMENGINE
27
29
30#ifdef DEAL_II_WITH_SYMENGINE
31
32namespace Differentiation
33{
34 namespace SD
35 {
36 namespace SE = ::SymEngine;
37
38
39 /* ------------------------- Symbol creation -----------------------*/
40
41
42 Expression
43 make_symbol(const std::string &symbol)
44 {
45 return Expression(symbol);
46 }
47
48
49# ifndef DOXYGEN
50 Expression
51 make_symbolic_function(const std::string &symbol,
52 const SD::types::symbol_vector &arguments)
53 {
54 return Expression(symbol, arguments);
55 }
56
57
58 Expression
59 make_symbolic_function(const std::string &symbol,
60 const SD::types::substitution_map &arguments)
61 {
62 return make_symbolic_function(symbol,
64 }
65# endif
66
67
68 /* --------------------------- Differentiation ------------------------- */
69
70
71 Expression
72 differentiate(const Expression &func, const Expression &op)
73 {
74 return func.differentiate(op);
75 }
76
77
78 /* ---------------- Symbol map creation and manipulation --------------*/
79
80
81# ifndef DOXYGEN
82 namespace internal
83 {
84 bool
85 is_valid_substitution_symbol(const SE::Basic &entry)
86 {
87 // Allow substitution of a symbol
88 // It is pretty clear as to why this is wanted...
89 if (SE::is_a<SE::Symbol>(entry))
90 return true;
91
92 // Allow substitution of a function symbol
93 // If desired, we can transform general but undefined functional
94 // relationships to an explicit form that is concrete. This is
95 // required for a symbolic expression to be parsed by a Lambda or LLVM
96 // optimizer.
97 if (SE::is_a<SE::FunctionSymbol>(entry))
98 return true;
99
100 // Allow substitution of the explicit expression of the derivative of
101 // an implicitly defined symbol (i.e. the result of the derivative of
102 // a FunctionSymbol).
103 if (SE::is_a<SE::Derivative>(entry))
104 return true;
105
106 // When performing tensor differentiation, one may end up with a
107 // coefficient of one half due to symmetry operations, e.g.
108 // 0.5*Derivative(Qi_00(C_11, C_00, C_01), C_01)
109 // So we explicitly check for this exact case
110 if (SE::is_a<SE::Mul>(entry))
111 {
112 const SE::Mul &entry_mul = SE::down_cast<const SE::Mul &>(entry);
113 // Check that the factor is a half...
114 if (SE::eq(*(entry_mul.get_coef()), *SE::real_double(0.5)))
115 {
116 // ...and that there is only one entry and that its a
117 // Derivative type
118 const SE::map_basic_basic &entry_mul_dict =
119 entry_mul.get_dict();
120 if (entry_mul_dict.size() == 1 &&
121 SE::is_a<SE::Derivative>(*(entry_mul_dict.begin()->first)))
122 return true;
123 }
124 }
125
126 return false;
127 }
128
129
130 void
132 types::substitution_map &substitution_map,
133 const SymEngine::RCP<const SymEngine::Basic> &symbol,
134 const SymEngine::RCP<const SymEngine::Basic> &value)
135 {
136 Assert(
139 "Substitution with a number that does not represent a symbol or symbolic derivative"));
140
141 auto it_sym = substitution_map.find(Expression(symbol));
142 Assert(it_sym != substitution_map.end(),
143 ExcMessage("Did not find this symbol in the map."));
144
145 it_sym->second = Expression(value);
146 }
147
148 } // namespace internal
149
150
151 void
153 const Expression &symbol,
154 const Expression &value)
155 {
156 internal::set_value_in_symbol_map(substitution_map,
157 symbol.get_RCP(),
158 value.get_RCP());
159 }
160
161
162 void
164 const types::substitution_map &symbol_values)
165 {
166 for (const auto &entry : symbol_values)
168 }
169# endif
170
171
172 /* ------------------ Symbol substitution map creation ----------------*/
173
174
176 make_substitution_map(const Expression &symbol, const Expression &value)
177 {
178 types::substitution_map substitution_map;
179 add_to_substitution_map(substitution_map, symbol, value);
180 return substitution_map;
181 }
182
183
184# ifndef DOXYGEN
185 /* ---------------- Symbolic substitution map enlargement --------------*/
186
187
188 void
190 const types::substitution_map &symb_map_in)
191 {
192 // Do this by hand so that we can perform some sanity checks
193 for (const auto &entry : symb_map_in)
194 {
195 const typename types::substitution_map::const_iterator it_other =
196 symb_map_out.find(entry.first);
197 if (it_other == symb_map_out.end())
198 symb_map_out.insert(std::make_pair(entry.first, entry.second));
199 else
200 {
201 Assert(SE::eq(*(entry.second.get_RCP()),
202 *(it_other->second.get_RCP())),
203 ExcMessage("Key already in map, but values don't match"));
204 }
205 }
206 }
207
208
209 /* ---------------- Symbol substitution and evaluation --------------*/
210
211
214 const bool force_cyclic_dependency_resolution)
215 {
216 types::substitution_map symbol_values_resolved = symbol_values;
217 const std::size_t size = symbol_values.size();
218 (void)size;
219 for (auto &entry : symbol_values_resolved)
220 {
221 // Perform dictionary-based substitution to
222 // resolve all explicit relations in a map.
223 // Instead of checking by value (and thus having
224 // to store a temporary value), we check to see
225 // if the hash of the map entry changes.
226 Expression &out = entry.second;
227 SE::hash_t hash_old;
228 SE::hash_t hash_new = out.get_RCP()->hash();
229 unsigned int iter = 0;
230 do
231 {
232 // Write the substituted value straight back
233 // into the map.
234 if (force_cyclic_dependency_resolution)
235 {
236 // Here we substitute in symbol_values_resolved instead of
237 // symbol_values, in order to break any cyclic dependencies.
238 // The earlier entries in the dictionary are in this way
239 // guaranteed to be resolved before any subsequent entries,
240 // thereby breaking the dependency loop.
241 out = out.substitute(symbol_values_resolved);
242 }
243 else
244 {
245 out = out.substitute(symbol_values);
246 }
247
248 // Compute and store the hash of the new object
249 hash_old = hash_new;
250 hash_new = out.get_RCP()->hash();
252 iter < size,
254 "Unresolvable cyclic dependency detected in substitution map."));
255 ++iter;
256 }
257 while (hash_new != hash_old);
258 }
259
260 return symbol_values_resolved;
261 }
262
263
264 Expression
265 substitute(const Expression &expression,
266 const types::substitution_map &substitution_map)
267 {
268 return expression.substitute(substitution_map);
269 }
270# endif // DOXYGEN
271
272 } // namespace SD
273} // namespace Differentiation
274
275
276#endif // DEAL_II_WITH_SYMENGINE
Expression substitute(const types::substitution_map &substitution_values) const
Expression differentiate(const Expression &symbol) const
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
Point< 2 > second
Definition grid_out.cc:4640
Point< 2 > first
Definition grid_out.cc:4639
#define Assert(cond, exc)
static ::ExceptionBase & ExcMessage(std::string arg1)
#define AssertThrow(cond, exc)
std::size_t size
Definition mpi.cc:733
SD::types::symbol_vector extract_symbols(const SD::types::substitution_map &substitution_values)
bool is_valid_substitution_symbol(const SymEngine::Basic &entry)
void set_value_in_symbol_map(types::substitution_map &substitution_map, const SymEngine::RCP< const SymEngine::Basic > &symbol, const SymEngine::RCP< const SymEngine::Basic > &value)
std::vector< SD::Expression > symbol_vector
std::map< SD::Expression, SD::Expression, internal::ExpressionKeyLess > substitution_map
void merge_substitution_maps(types::substitution_map &substitution_map_out, const types::substitution_map &substitution_map_in)
Expression differentiate(const Expression &f, const Expression &x)
Expression make_symbolic_function(const std::string &symbol, const types::symbol_vector &arguments)
void set_value_in_symbol_map(types::substitution_map &substitution_map, const Expression &symbol, const Expression &value)
void add_to_substitution_map(types::substitution_map &substitution_map, const Expression &symbol, const Expression &value)
types::substitution_map resolve_explicit_dependencies(const types::substitution_map &substitution_map, const bool force_cyclic_dependency_resolution=false)
Expression substitute(const Expression &expression, const types::substitution_map &substitution_map)
types::substitution_map make_substitution_map(const Expression &symbol, const Expression &value)
Expression make_symbol(const std::string &symbol)