Reference documentation for deal.II version 9.3.3
\(\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\}}\)
symengine_scalar_operations.h
Go to the documentation of this file.
1// ---------------------------------------------------------------------
2//
3// Copyright (C) 2019 - 2020 by the deal.II authors
4//
5// This file is part of the deal.II library.
6//
7// The deal.II library is free software; you can use it, redistribute
8// it, and/or modify it under the terms of the GNU Lesser General
9// Public License as published by the Free Software Foundation; either
10// version 2.1 of the License, or (at your option) any later version.
11// The full text of the license can be found in the file LICENSE at
12// the top level of the deal.II distribution.
13//
14// ---------------------------------------------------------------------
15
16#ifndef dealii_differentiation_sd_symengine_scalar_operations_h
17#define dealii_differentiation_sd_symengine_scalar_operations_h
18
19#include <deal.II/base/config.h>
20
21#ifdef DEAL_II_WITH_SYMENGINE
22
23# include <deal.II/base/numbers.h>
24
27
28# include <symengine/basic.h>
29# include <symengine/symengine_rcp.h>
30
31# include <algorithm>
32# include <type_traits>
33# include <utility>
34# include <vector>
35
37
38namespace Differentiation
39{
40 namespace SD
41 {
46
61 Expression
62 make_symbol(const std::string &symbol);
63
84 Expression
85 make_symbolic_function(const std::string & symbol,
86 const types::symbol_vector &arguments);
87
109 Expression
110 make_symbolic_function(const std::string & symbol,
111 const types::substitution_map &arguments);
112
114
119
131 Expression
132 differentiate(const Expression &f, const Expression &x);
133
135
140
141 namespace internal
142 {
147 bool
148 is_valid_substitution_symbol(const SymEngine::Basic &entry);
149
159 void
162 const SymEngine::RCP<const SymEngine::Basic> &symbol,
163 const SymEngine::RCP<const SymEngine::Basic> &value);
164 } // namespace internal
165
186 template <bool ignore_invalid_symbols = false,
187 typename ValueType = double,
188 typename SymbolicType>
190 make_symbol_map(const SymbolicType &symbol);
191
227 template <bool ignore_invalid_symbols = false,
228 typename ValueType = double,
229 typename SymbolicType,
230 typename... Args>
232 make_symbol_map(const SymbolicType &symbol, const Args &... other_symbols);
233
270 template <bool ignore_invalid_symbols = false, typename ValueType = double>
271 void
273 const Expression & symbol);
274
303 template <bool ignore_invalid_symbols = false,
304 typename ValueType = double,
305 typename SymbolicType,
306 typename T = typename std::enable_if<
307 !std::is_base_of<Expression, SymbolicType>::value &&
309 SymbolicType,
310 const SymEngine::RCP<const SymEngine::Basic> &>::value>::type>
311 void
313 const SymbolicType & symbol);
314
340 template <bool ignore_invalid_symbols = false,
341 typename ValueType = double,
342 typename SymbolicType>
343 void
345 const std::vector<SymbolicType> &symbols);
346
366 template <bool ignore_invalid_symbols = false, typename ValueType = double>
367 void
369 const types::substitution_map &other_symbols);
370
413 template <bool ignore_invalid_symbols = false,
414 typename ValueType = double,
415 typename SymbolicType,
416 typename... Args>
417 void
419 const SymbolicType & symbol,
420 const Args &... other_symbols);
421
430 void
432 const Expression & symbol,
433 const Expression & value);
434
461 template <typename SymbolicType,
462 typename ValueType,
463 typename T = typename std::enable_if<
465 SymbolicType,
466 const SymEngine::RCP<const SymEngine::Basic> &>::value &&
467 std::is_constructible<SymbolicType, ValueType>::value>::type>
468 void
470 const SymbolicType & symbol,
471 const ValueType & value);
472
492 template <typename SymbolicType, typename ValueType>
493 void
495 const std::vector<SymbolicType> &symbols,
496 const std::vector<ValueType> & values);
497
519 template <typename SymbolicType, typename ValueType>
520 void
523 const std::pair<SymbolicType, ValueType> &symbol_value);
524
549 template <typename SymbolicType, typename ValueType, typename... Args>
550 void
553 const std::pair<SymbolicType, ValueType> &symbol_value,
554 const Args &... other_symbol_values);
555
577 template <typename SymbolicType, typename ValueType>
578 void
581 const std::vector<std::pair<SymbolicType, ValueType>> &symbol_values);
582
593 void
595 const types::substitution_map &symbol_values);
596
598
603
617 make_substitution_map(const Expression &symbol, const Expression &value);
618
650 template <typename ExpressionType,
651 typename ValueType,
652 typename T = typename std::enable_if<
654 ExpressionType,
655 const SymEngine::RCP<const SymEngine::Basic> &>::value &&
656 std::is_constructible<ExpressionType, ValueType>::value>::type>
658 make_substitution_map(const ExpressionType &symbol, const ValueType &value);
659
681 template <typename ExpressionType, typename ValueType>
683 make_substitution_map(const std::vector<ExpressionType> &symbols,
684 const std::vector<ValueType> & values);
685
707 template <typename ExpressionType, typename ValueType>
710 const std::pair<ExpressionType, ValueType> &symbol_value);
711
734 template <typename ExpressionType, typename ValueType>
737 const std::vector<std::pair<ExpressionType, ValueType>> &symbol_values);
738
779 template <typename ExpressionType, typename ValueType, typename... Args>
782 const std::pair<ExpressionType, ValueType> &symbol_value,
783 const Args &... other_symbol_values);
784
786
791
792 namespace internal
793 {
816 template <bool ignore_invalid_symbols = false>
817 void
820 const SymEngine::RCP<const SymEngine::Basic> &symbol,
821 const SymEngine::RCP<const SymEngine::Basic> &value);
822 } // namespace internal
823
854 template <bool ignore_invalid_symbols = false>
855 void
857 const Expression & symbol,
858 const Expression & value);
859
892 template <bool ignore_invalid_symbols = false,
893 typename ExpressionType,
894 typename ValueType,
895 typename = typename std::enable_if<
897 ExpressionType,
898 const SymEngine::RCP<const SymEngine::Basic> &>::value &&
899 std::is_constructible<ExpressionType, ValueType>::value>::type>
900 void
902 const ExpressionType & symbol,
903 const ValueType & value);
904
938 template <bool ignore_invalid_symbols = false,
939 typename ExpressionType,
940 typename ValueType,
941 typename = typename std::enable_if<
943 ExpressionType,
944 const SymEngine::RCP<const SymEngine::Basic> &>::value &&
945 std::is_constructible<ExpressionType, ValueType>::value>::type>
946 void
948 const std::vector<ExpressionType> &symbols,
949 const std::vector<ValueType> & values);
950
967 template <bool ignore_invalid_symbols = false>
968 void
970 const types::substitution_map &symbol_values);
971
1012 template <bool ignore_invalid_symbols = false,
1013 typename ExpressionType,
1014 typename ValueType>
1015 void
1018 const std::pair<ExpressionType, ValueType> &symbol_value);
1019
1064 template <bool ignore_invalid_symbols = false,
1065 typename ExpressionType,
1066 typename ValueType>
1067 void
1070 const std::vector<std::pair<ExpressionType, ValueType>> &symbol_values);
1071
1116 template <bool ignore_invalid_symbols = false,
1117 typename ExpressionType,
1118 typename ValueType,
1119 typename... Args>
1120 void
1123 const std::pair<ExpressionType, ValueType> &symbol_value,
1124 const Args &... other_symbol_values);
1125
1134 void
1136 const types::substitution_map &substitution_map_in);
1137
1147 template <typename... Args>
1148 void
1150 const types::substitution_map &substitution_map_in,
1151 const Args &... other_substitution_maps_in);
1152
1160 template <typename... Args>
1163 const Args &... other_substitution_maps_in);
1164
1166
1171
1213 const bool force_cyclic_dependency_resolution = false);
1214
1245 template <typename ExpressionType, typename ValueType>
1248 const std::vector<std::pair<ExpressionType, ValueType>> &symbol_values,
1249 const bool force_cyclic_dependency_resolution = false);
1250
1298 substitute(const Expression & expression,
1300
1322 template <typename ValueType>
1324 substitute(const Expression &expression,
1325 const Expression &symbol,
1326 const ValueType & value);
1327
1356 template <typename ExpressionType, typename... Args>
1357 ExpressionType
1358 substitute(const ExpressionType &expression, const Args &... symbol_values);
1359
1385 template <typename ValueType>
1386 ValueType
1389
1421 template <typename ValueType, typename... Args>
1422 ValueType
1424 const Args &... symbol_values);
1425
1427
1428 } // namespace SD
1429} // namespace Differentiation
1430
1431
1432/* -------------------- inline and template functions ------------------ */
1433
1434
1435# ifndef DOXYGEN
1436
1437
1438namespace Differentiation
1439{
1440 namespace SD
1441 {
1442 /* ---------------- Symbol map creation and manipulation --------------*/
1443
1444
1445 template <bool ignore_invalid_symbols,
1446 typename ValueType,
1447 typename SymbolicType>
1449 make_symbol_map(const SymbolicType &symbol)
1450 {
1451 types::substitution_map symbol_map;
1452 add_to_symbol_map<ignore_invalid_symbols, ValueType>(symbol_map, symbol);
1453 return symbol_map;
1454 }
1455
1456
1457 template <bool ignore_invalid_symbols,
1458 typename ValueType,
1459 typename SymbolicType,
1460 typename... Args>
1462 make_symbol_map(const SymbolicType &symbol, const Args &... other_symbols)
1463 {
1464 types::substitution_map symbol_map;
1465 add_to_symbol_map<ignore_invalid_symbols, ValueType>(symbol_map,
1466 symbol,
1467 other_symbols...);
1468 return symbol_map;
1469 }
1470
1471
1472 template <bool ignore_invalid_symbols, typename ValueType>
1473 void
1475 const Expression & symbol)
1476 {
1477 // Call the above function
1478 add_to_substitution_map<ignore_invalid_symbols>(
1479 symbol_map,
1480 symbol,
1482 }
1483
1484
1485 template <bool ignore_invalid_symbols,
1486 typename ValueType,
1487 typename SymbolicType,
1488 typename>
1489 void
1491 const SymbolicType & symbol)
1492 {
1493 // Call the above function
1494 using SE_RCP_Basic = const SymEngine::RCP<const SymEngine::Basic> &;
1495 add_to_substitution_map<ignore_invalid_symbols>(
1496 symbol_map,
1497 static_cast<SE_RCP_Basic>(symbol),
1499 }
1500
1501
1502 template <bool ignore_invalid_symbols,
1503 typename ValueType,
1504 typename SymbolicType>
1505 void
1507 const std::vector<SymbolicType> &symbols)
1508 {
1509 for (const auto &symbol : symbols)
1510 add_to_symbol_map<ignore_invalid_symbols, ValueType>(symbol_map,
1511 symbol);
1512 }
1513
1514
1515 template <bool ignore_invalid_symbols, typename ValueType>
1516 void
1518 const types::substitution_map &other_symbols)
1519 {
1520 // We should be cautious as to whether or not the user has
1521 // hand-made the other_symbols map to be "merged" in.
1522 // So instead of blindly merging using the merge_substitution_maps()
1523 // function, we do it by hand and check for invalid symbols
1524 // if required.
1525 for (types::substitution_map::const_iterator it = other_symbols.begin();
1526 it != other_symbols.end();
1527 ++it)
1528 {
1529 Assert(symbol_map.find(it->first) == symbol_map.end(),
1530 ExcMessage("Entry already exists in symbol map"));
1531 add_to_symbol_map<ignore_invalid_symbols, ValueType>(
1532 symbol_map, Expression(it->first));
1533 }
1534 }
1535
1536
1537 template <bool ignore_invalid_symbols,
1538 typename ValueType,
1539 typename SymbolicType,
1540 typename... Args>
1541 void
1543 const SymbolicType & symbol,
1544 const Args &... other_symbols)
1545 {
1546 add_to_symbol_map<ignore_invalid_symbols, ValueType>(symbol_map, symbol);
1547 add_to_symbol_map<ignore_invalid_symbols, ValueType>(symbol_map,
1548 other_symbols...);
1549 }
1550
1551
1552 template <typename SymbolicType, typename ValueType, typename>
1553 void
1555 const SymbolicType & symbol,
1556 const ValueType & value)
1557 {
1558 // Call the above function
1559 using SE_RCP_Basic = const SymEngine::RCP<const SymEngine::Basic> &;
1561 static_cast<SE_RCP_Basic>(symbol),
1562 static_cast<SE_RCP_Basic>(
1563 SymbolicType(value)));
1564 }
1565
1566
1567 template <typename SymbolicType, typename ValueType>
1568 void
1570 const std::vector<SymbolicType> &symbols,
1571 const std::vector<ValueType> & values)
1572 {
1573 Assert(symbols.size() == values.size(),
1574 ExcDimensionMismatch(symbols.size(), values.size()));
1575
1576 typename std::vector<SymbolicType>::const_iterator it_symb =
1577 symbols.begin();
1578 typename std::vector<ValueType>::const_iterator it_val = values.begin();
1579 for (; it_symb != symbols.end(); ++it_symb, ++it_val)
1580 {
1581 Assert(it_val != values.end(), ExcInternalError());
1582 set_value_in_symbol_map(substitution_map, *it_symb, *it_val);
1583 }
1584 }
1585
1586
1587 template <typename SymbolicType, typename ValueType>
1588 void
1591 const std::pair<SymbolicType, ValueType> &symbol_value)
1592 {
1594 symbol_value.first,
1595 symbol_value.second);
1596 }
1597
1598
1599 template <typename SymbolicType, typename ValueType, typename... Args>
1600 void
1603 const std::pair<SymbolicType, ValueType> &symbol_value,
1604 const Args &... other_symbol_values)
1605 {
1607 set_value_in_symbol_map(substitution_map, other_symbol_values...);
1608 }
1609
1610
1611 template <typename SymbolicType, typename ValueType>
1612 void
1615 const std::vector<std::pair<SymbolicType, ValueType>> &symbol_values)
1616 {
1617 // Call the above function
1618 for (const auto &entry : symbol_values)
1619 set_value_in_symbol_map(substitution_map, entry.first, entry.second);
1620 }
1621
1622
1623 /* ------------------ Symbol substitution map creation ----------------*/
1624
1625
1626 template <typename ExpressionType, typename ValueType, typename>
1628 make_substitution_map(const ExpressionType &symbol, const ValueType &value)
1629 {
1632 return substitution_map;
1633 }
1634
1635
1636 template <typename ExpressionType, typename ValueType>
1638 make_substitution_map(const std::vector<ExpressionType> &symbols,
1639 const std::vector<ValueType> & values)
1640 {
1643 return substitution_map;
1644 }
1645
1646
1647 template <typename ExpressionType, typename ValueType>
1650 const std::pair<ExpressionType, ValueType> &symbol_value)
1651 {
1654 return substitution_map;
1655 }
1656
1657
1658 template <typename ExpressionType, typename ValueType>
1661 const std::vector<std::pair<ExpressionType, ValueType>> &symbol_values)
1662 {
1665 return substitution_map;
1666 }
1667
1668
1669 template <typename ExpressionType, typename ValueType, typename... Args>
1672 const std::pair<ExpressionType, ValueType> &symbol_value,
1673 const Args &... other_symbol_values)
1674 {
1677 symbol_value,
1678 other_symbol_values...);
1679 return substitution_map;
1680 }
1681
1682
1683 /* ---------------- Symbolic substitution map enlargement --------------*/
1684
1685 namespace internal
1686 {
1698 template <bool ignore_invalid_symbols>
1699 void
1702 const SymEngine::RCP<const SymEngine::Basic> &symbol,
1703 const SymEngine::RCP<const SymEngine::Basic> &value)
1704 {
1705 if (ignore_invalid_symbols == false)
1706 {
1707 Assert(
1709 ExcMessage(
1710 "Substitution with a number that does not represent a symbol or symbolic derivative"));
1711 Assert(substitution_map.find(symbol) == substitution_map.end(),
1712 ExcMessage("This symbol is already in the map."));
1713 substitution_map[Expression(symbol)] = Expression(value);
1714 }
1715 else
1716 {
1718 {
1719 Assert(substitution_map.find(symbol) == substitution_map.end(),
1720 ExcMessage("This symbol is already in the map."));
1721 substitution_map[Expression(symbol)] = Expression(value);
1722 }
1723 }
1724 }
1725
1726 } // namespace internal
1727
1728
1729 template <bool ignore_invalid_symbols>
1730 void
1732 const Expression & symbol,
1733 const Expression & value)
1734 {
1735 internal::add_to_substitution_map<ignore_invalid_symbols>(
1736 substitution_map, symbol.get_RCP(), value.get_RCP());
1737 }
1738
1739
1740 template <bool ignore_invalid_symbols,
1741 typename ExpressionType,
1742 typename ValueType,
1743 typename>
1744 void
1746 const ExpressionType & symbol,
1747 const ValueType & value)
1748 {
1749 using SE_RCP_Basic = const SymEngine::RCP<const SymEngine::Basic> &;
1750 internal::add_to_substitution_map<ignore_invalid_symbols>(
1752 static_cast<SE_RCP_Basic>(symbol),
1753 static_cast<SE_RCP_Basic>(ExpressionType(value)));
1754 }
1755
1756
1757 template <bool ignore_invalid_symbols,
1758 typename ExpressionType,
1759 typename ValueType,
1760 typename>
1761 void
1763 const std::vector<ExpressionType> &symbols,
1764 const std::vector<ValueType> & values)
1765 {
1766 Assert(symbols.size() == values.size(),
1767 ExcMessage(
1768 "Vector of symbols and values must be of equal length."));
1769
1770 typename types::symbol_vector::const_iterator it_s = symbols.begin();
1771 typename std::vector<ValueType>::const_iterator it_v = values.begin();
1772 using SE_RCP_Basic = const SymEngine::RCP<const SymEngine::Basic> &;
1773 for (; it_s != symbols.end(); ++it_s, ++it_v)
1774 {
1775 Assert(it_v != values.end(), ExcInternalError());
1776 internal::add_to_substitution_map<ignore_invalid_symbols>(
1778 static_cast<SE_RCP_Basic>(*it_s),
1779 static_cast<SE_RCP_Basic>(ExpressionType(*it_v)));
1780 }
1781 }
1782
1783
1784 template <bool ignore_invalid_symbols,
1785 typename ExpressionType,
1786 typename ValueType>
1787 void
1790 const std::pair<ExpressionType, ValueType> &symbol_value)
1791 {
1792 add_to_substitution_map<ignore_invalid_symbols>(substitution_map,
1793 symbol_value.first,
1794 symbol_value.second);
1795 }
1796
1797
1798 template <bool ignore_invalid_symbols,
1799 typename ExpressionType,
1800 typename ValueType>
1801 void
1804 const std::vector<std::pair<ExpressionType, ValueType>> &symbol_values)
1805 {
1806 for (const auto &entry : symbol_values)
1807 {
1808 add_to_substitution_map<ignore_invalid_symbols>(substitution_map,
1809 entry);
1810 }
1811 }
1812
1813
1814 template <bool ignore_invalid_symbols>
1815 void
1817 const types::substitution_map &symbol_values)
1818 {
1819 for (const auto &entry : symbol_values)
1820 {
1821 const SymEngine::RCP<const SymEngine::Basic> &symbol = entry.first;
1822 const SymEngine::RCP<const SymEngine::Basic> &value = entry.second;
1823 internal::add_to_substitution_map<ignore_invalid_symbols>(
1824 substitution_map, symbol, value);
1825 }
1826 }
1827
1828
1829 template <bool ignore_invalid_symbols,
1830 typename ExpressionType,
1831 typename ValueType,
1832 typename... Args>
1833 void
1836 const std::pair<ExpressionType, ValueType> &symbol_value,
1837 const Args &... other_symbol_values)
1838 {
1839 add_to_substitution_map<ignore_invalid_symbols>(substitution_map,
1840 symbol_value);
1841 add_to_substitution_map<ignore_invalid_symbols>(substitution_map,
1842 other_symbol_values...);
1843 }
1844
1845
1846 template <typename... Args>
1849 const types::substitution_map &substitution_map_in_1,
1850 const Args &... other_substitution_maps_in)
1851 {
1852 types::substitution_map substitution_map_out = substitution_map_in_1;
1853 merge_substitution_maps(substitution_map_out,
1854 other_substitution_maps_in...);
1855 return substitution_map_out;
1856 }
1857
1858
1859 template <typename... Args>
1860 void
1862 types::substitution_map & substitution_map_out,
1863 const types::substitution_map &substitution_map_in_1,
1864 const Args &... other_substitution_maps_in)
1865 {
1866 merge_substitution_maps(substitution_map_out, substitution_map_in_1);
1867 merge_substitution_maps(substitution_map_out,
1868 other_substitution_maps_in...);
1869 }
1870
1871
1872 /* ---------------- Symbol substitution and evaluation --------------*/
1873
1874
1875 template <typename ExpressionType, typename ValueType>
1878 const std::vector<std::pair<ExpressionType, ValueType>> &symbol_values,
1879 const bool force_cyclic_dependency_resolution)
1880 {
1882 force_cyclic_dependency_resolution);
1883 }
1884
1885
1886 template <typename ValueType>
1887 Expression
1888 substitute(const Expression &expression,
1889 const Expression &symbol,
1890 const ValueType & value)
1891 {
1892 return expression.substitute(symbol, value);
1893 }
1894
1895
1896 template <typename ExpressionType, typename... Args>
1897 ExpressionType
1898 substitute(const ExpressionType &expression, const Args &... symbol_values)
1899 {
1900 // Call other function
1901 return substitute(expression, make_substitution_map(symbol_values...));
1902 }
1903
1904
1905 template <typename ValueType>
1906 ValueType
1907 substitute_and_evaluate(const Expression & expression,
1909 {
1910 return expression.substitute_and_evaluate<ValueType>(substitution_map);
1911 }
1912
1913
1914 template <typename ValueType, typename... Args>
1915 ValueType
1916 substitute_and_evaluate(const Expression &expression,
1917 const Args &... symbol_values)
1918 {
1919 // Call other function
1920 return substitute_and_evaluate<ValueType>(
1921 expression, make_substitution_map(symbol_values...));
1922 }
1923
1924 } // namespace SD
1925} // namespace Differentiation
1926
1927
1928# endif // DOXYGEN
1929
1931
1932#endif // DEAL_II_WITH_SYMENGINE
1933
1934#endif
#define DEAL_II_NAMESPACE_OPEN
Definition: config.h:402
#define DEAL_II_NAMESPACE_CLOSE
Definition: config.h:403
#define Assert(cond, exc)
Definition: exceptions.h:1465
Expression substitute(const types::substitution_map &substitution_values) const
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
static ::ExceptionBase & ExcMessage(std::string arg1)
void add_to_substitution_map(types::substitution_map &substitution_map, const SymEngine::RCP< const SymEngine::Basic > &symbol, const SymEngine::RCP< const SymEngine::Basic > &value)
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)
ValueType substitute_and_evaluate(const Expression &expression, const types::substitution_map &substitution_map)
types::substitution_map make_symbol_map(const SymbolicType &symbol)
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_symbol_map(types::substitution_map &symbol_map, const Expression &symbol)
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)
static const char T