LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
equivalence_exp_log.cpp
浏览该文件的文档.
2
4
5#include <optional>
6#include <utility>
7#include <vector>
8
10namespace {
11
12std::vector<detail::SymbolicNodePtr> rewrite_operands(
13 const std::vector<detail::SymbolicNodePtr>& operands,
14 const AssumptionContext* assumptions, detail::RewriteBudget& budget) {
15 std::vector<detail::SymbolicNodePtr> rewritten;
16 budget.require_nodes(operands.size());
17 std::size_t size = 0;
18 rewritten.reserve(operands.size());
19 for (const auto& operand : operands) {
20 auto child = rewrite_exp_log_basic_identity(operand, assumptions, budget);
21 size = budget.append_size(size, budget.measure(detail::node(child)));
22 rewritten.push_back(detail::node(child));
23 }
24 return rewritten;
25}
26
28 const AssumptionContext* assumptions) {
29 auto inner_ln = std::dynamic_pointer_cast<const FunctionNode>(node);
30 if (!inner_ln || inner_ln->type() != FunctionNode::FuncType::Ln ||
31 inner_ln->arguments().size() != 1) {
32 return nullptr;
33 }
34 auto argument = detail::make_expression_ptr(inner_ln->arguments()[0]);
35 auto positive = assumptions
36 ? assumptions->is_positive(*argument)
38 const bool known_positive = inner_ln->arguments()[0]->is_positive() ||
39 (positive && positive.value() == Tribool::True);
40 return known_positive ? argument : nullptr;
41}
44 const auto product = std::dynamic_pointer_cast<const MultiplyNode>(node);
45 if (!product || product->operands().size() != 2) {
46 return std::nullopt;
47 }
48 detail::SymbolicNodePtr lambert_node;
49 if (exact_integer_node(product->operands()[0], -1)) {
50 lambert_node = product->operands()[1];
51 } else if (exact_integer_node(product->operands()[1], -1)) {
52 lambert_node = product->operands()[0];
53 } else {
54 return std::nullopt;
55 }
56 const auto lambert = std::dynamic_pointer_cast<const FunctionNode>(lambert_node);
57 if (!lambert || lambert->type() != FunctionNode::FuncType::LambertW ||
58 lambert->arguments().size() != 1) {
59 return std::nullopt;
60 }
61 const auto argument =
62 std::dynamic_pointer_cast<const NumberNode>(lambert->arguments()[0]);
63 if (!argument || !argument->is_positive()) {
64 return std::nullopt;
65 }
66 if (argument->is_one()) {
67 budget.measure(lambert_node);
68 return detail::make_expression_ptr(lambert_node);
69 }
70 budget.require_nodes(3);
71 auto reciprocal = detail::make_node<PowerNode>(
72 lambert->arguments()[0], detail::make_node<NumberNode>(BigInt(-1)));
73 auto rewritten = SymbolicFactory::create_multiply(
74 {lambert_node, std::move(reciprocal)}, &budget);
76 detail::make_expression_ptr(std::move(rewritten)), budget);
77}
78
80 const AssumptionContext* assumptions,
81 detail::RewriteBudget& budget) {
82 auto arguments = rewrite_operands(function.arguments(), assumptions, budget);
83 if (arguments.size() == 1) {
85 if (exact_integer_node(arguments[0], 0)) {
86 budget.require_nodes(1);
87 return SymbolicExpr::number(1);
88 }
89 auto argument = positive_log_argument(arguments[0], assumptions);
90 if (auto lambert =
91 rewrite_negative_lambert_exponential(arguments[0], budget)) {
92 return std::move(*lambert);
93 }
94 if (argument) { return argument; }
95 }
97 exact_integer_node(arguments[0], 1)) {
98 budget.require_nodes(1);
99 return SymbolicExpr::number(0);
100 }
101 }
102 normalization_check_children(&budget, 1, arguments);
104 function.type(), std::move(arguments)));
105}
106
107}
108
110 const AssumptionContext* assumptions,
111 detail::RewriteBudget& budget) {
112 if (!node) { return nullptr; }
113 detail::RewriteScope scope(&budget);
114 if (auto add = std::dynamic_pointer_cast<const AddNode>(node)) {
116 rewrite_operands(add->operands(), assumptions, budget), &budget));
117 }
118 if (auto multiply = std::dynamic_pointer_cast<const MultiplyNode>(node)) {
120 rewrite_operands(multiply->operands(), assumptions, budget), &budget));
121 }
122 if (auto power = std::dynamic_pointer_cast<const PowerNode>(node)) {
123 auto base = rewrite_exp_log_basic_identity(power->base(), assumptions, budget);
124 auto exponent = rewrite_exp_log_basic_identity(power->exponent(), assumptions, budget);
125 budget.append_size(budget.append_size(1, budget.measure(detail::node(base))),
126 budget.measure(detail::node(exponent)));
127 return SymbolicExpr::power(base, exponent);
128 }
129 if (auto function = std::dynamic_pointer_cast<const FunctionNode>(node)) {
130 return rewrite_exp_log_function(*function, assumptions, budget);
131 }
132 if (auto complex_node = std::dynamic_pointer_cast<const ComplexNode>(node)) {
133 auto real = rewrite_exp_log_basic_identity(complex_node->real(), assumptions, budget);
134 auto imag = rewrite_exp_log_basic_identity(complex_node->imag(), assumptions, budget);
135 return rewritten_complex(real, imag, node, budget);
136 }
137 budget.measure(node);
138 return detail::make_expression_ptr(node);
139}
140
141}
AssumptionContext class with scoped push/pop management.
函数节点,表示数学函数调用(三角函数、对数、特殊函数等)。
static Result success(T value)
static std::shared_ptr< const SymbolicNode > create_add(std::vector< std::shared_ptr< const SymbolicNode > > ops, detail::RewriteBudget *budget=nullptr)
创建加法节点,自动扁平化嵌套加法并消除零项.
static std::shared_ptr< const SymbolicNode > create_multiply(std::vector< std::shared_ptr< const SymbolicNode > > ops, detail::RewriteBudget *budget=nullptr)
创建乘法节点,自动扁平化嵌套乘法并消除单位元.
std::size_t measure(const std::shared_ptr< const SymbolicNode > &node)
void require_nodes(std::size_t nodes) const
std::size_t append_size(std::size_t current, std::size_t child)
std::shared_ptr<::LMCAS::SymbolicExpr > make_expression_ptr(SymbolicNodePtr root)
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
std::shared_ptr< const SymbolicNode > SymbolicNodePtr
std::shared_ptr< const Node > make_node(Args &&... args)
std::vector< detail::SymbolicNodePtr > rewrite_operands(const std::vector< detail::SymbolicNodePtr > &operands, const AssumptionContext *assumptions, detail::RewriteBudget &budget)
ExprPtr positive_log_argument(const detail::SymbolicNodePtr &node, const AssumptionContext *assumptions)
ExprPtr rewrite_exp_log_function(const FunctionNode &function, const AssumptionContext *assumptions, detail::RewriteBudget &budget)
std::optional< ExprPtr > rewrite_negative_lambert_exponential(const detail::SymbolicNodePtr &node, detail::RewriteBudget &budget)
ExprPtr normalize_equivalence(const ExprPtr &expression, detail::RewriteBudget &budget)
bool exact_integer_node(const std::shared_ptr< const SymbolicNode > &node, int expected)
ExprPtr rewrite_exp_log_basic_identity(const detail::SymbolicNodePtr &node, const AssumptionContext *assumptions, detail::RewriteBudget &budget)
ExprPtr rewritten_complex(const ExprPtr &real, const ExprPtr &imag, const detail::SymbolicNodePtr &original, detail::RewriteBudget &budget)
ExprResult real(const ExprPtr &expression, ComputationContext &context)
@ Unknown
Property cannot be determined
@ True
Property definitely holds
ExprResult add(const ExprPtr &lhs, const ExprPtr &rhs, ComputationContext &context)
const ExprPtr & exponent
void normalization_check_children(detail::RewriteBudget *budget, std::size_t roots, const std::shared_ptr< const Nodes > &... children)
ExprPtr imag
std::shared_ptr< SymbolicExpr > ExprPtr
ExprResult function(const std::string &name, std::vector< ExprPtr > arguments)