LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
transcendental_patterns.cpp
浏览该文件的文档.
4#include "lmmc/config.h"
5
6#include <cmath>
7
9namespace {
10
11bool invertible_function(const FunctionNode& function, const std::string&) {
12 if (function.arguments().size() != 1) {
13 return false;
14 }
15 using Type = FunctionNode::FuncType;
16 switch (function.type()) {
17 case Type::Sin: {
18 return true;
19 }
20 case Type::Cos: {
21 return true;
22 }
23 case Type::Tan: {
24 return true;
25 }
26 case Type::Exp: {
27 return true;
28 }
29 case Type::Ln: {
30 return true;
31 }
32 default:
33 return false;
34 }
35}
36
37std::shared_ptr<SymbolicExpr> constant_sum(
38 std::vector<std::shared_ptr<const SymbolicNode>> terms) {
39 if (terms.empty()) {
40 return SymbolicExpr::number(0);
41 }
42 if (terms.size() == 1) {
43 return make_expression_ptr(terms[0]);
44 }
45 return make_expression_ptr(make_node<AddNode>(std::move(terms)));
46}
47
49 std::shared_ptr<const FunctionNode> function;
50 std::shared_ptr<const SymbolicNode> coefficient;
51};
52
53std::optional<ScaledFunction> scaled_function(
54 const std::shared_ptr<const SymbolicNode>& node, const std::string& var) {
55 auto function = std::dynamic_pointer_cast<const FunctionNode>(node);
59 }
60 auto product = std::dynamic_pointer_cast<const MultiplyNode>(node);
61 if (!product) {
62 return std::nullopt;
63 }
64 std::vector<std::shared_ptr<const SymbolicNode>> coefficients;
65 std::shared_ptr<const FunctionNode> found;
66 for (const auto& operand : product->operands()) {
67 auto candidate = std::dynamic_pointer_cast<const FunctionNode>(operand);
68 if (candidate && invertible_function(*candidate, var) && !found &&
69 expression_depends_on_variable(operand, var)) {
70 found = candidate;
71 } else {
72 coefficients.push_back(operand);
73 }
74 }
75 if (!found) {
76 return std::nullopt;
77 }
78 auto coefficient = SymbolicFactory::create_multiply(std::move(coefficients));
79 if (expression_depends_on_variable(coefficient, var)) {
80 return std::nullopt;
81 }
82 return ScaledFunction{found, coefficient};
83}
84
85std::optional<InversePattern> additive_function_pattern(
86 const AddNode& sum, const std::string& var) {
87 std::optional<ScaledFunction> function;
88 std::vector<std::shared_ptr<const SymbolicNode>> constants;
89 for (const auto& operand : sum.operands()) {
90 auto candidate = scaled_function(operand, var);
91 if (candidate && !function) {
92 function = std::move(candidate);
93 continue;
94 }
95 if (expression_depends_on_variable(operand, var)) {
96 return std::nullopt;
97 }
98 constants.push_back(operand);
99 }
100 if (!function) {
101 return std::nullopt;
102 }
103 auto negative = SymbolicExpr::multiply(
104 constant_sum(std::move(constants)), SymbolicExpr::number(-1));
105 return InversePattern{function->function->type(),
106 make_expression_ptr(function->function->arguments()[0]), negative,
107 make_expression_ptr(function->coefficient)};
108}
109
110std::shared_ptr<const SymbolicNode> product_without(
111 const MultiplyNode& product, std::size_t index) {
112 std::vector<std::shared_ptr<const SymbolicNode>> remaining;
113 for (std::size_t i = 0; i < product.operands().size(); ++i) {
114 if (i != index) {
115 remaining.push_back(product.operands()[i]);
116 }
117 }
118 if (remaining.size() == 1) {
119 return remaining[0];
120 }
121 return make_node<MultiplyNode>(std::move(remaining));
122}
123
124std::optional<std::shared_ptr<SymbolicExpr>> lambert_inner(
125 const MultiplyNode& product, const std::string& var) {
126 for (std::size_t i = 0; i < product.operands().size(); ++i) {
127 auto function = std::dynamic_pointer_cast<const FunctionNode>(product.operands()[i]);
128 if (!function || function->type() != FunctionNode::FuncType::Exp ||
129 function->arguments().size() != 1) {
130 continue;
131 }
132 const auto& argument = function->arguments()[0];
133 auto remainder = product_without(product, i);
134 const bool equal = !remainder || !argument
135 ? remainder == argument : remainder->equals(*argument);
136 if (equal && expression_depends_on_variable(remainder, var)) {
137 return make_expression_ptr(remainder);
138 }
139 }
140 return std::nullopt;
141}
142
143std::optional<LambertWPattern> opposite_exponential_lambert_pattern(
144 const AddNode& sum, const std::string& var, ComputationContext& context) {
145
146 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
147 (context).limits().max_ast_nodes, "transform");
148 if (sum.operands().size() != 2) {
149 return std::nullopt;
150 }
151 for (std::size_t index = 0; index < 2; ++index) {
152 auto exponential = std::dynamic_pointer_cast<const FunctionNode>(
153 sum.operands()[index]);
154 if (!exponential ||
155 exponential->type() != FunctionNode::FuncType::Exp ||
156 exponential->arguments().size() != 1) {
157 continue;
158 }
159 const auto& argument = exponential->arguments()[0];
160 const auto& other = sum.operands()[1 - index];
161 if (!argument || !other || !argument->equals(*other) ||
162 !expression_depends_on_variable(argument, var)) {
163 continue;
164 }
165 auto inner = detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::multiply(
166 SymbolicExpr::number(-1), make_expression_ptr(argument))), transform_budget));
167 return LambertWPattern{std::move(inner), SymbolicExpr::number(1)};
168 }
169 return std::nullopt;
170}
171
172std::optional<LambertWPattern> additive_lambert_pattern(
173 const AddNode& sum, const std::string& var, ComputationContext& context) {
174
175 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
176 (context).limits().max_ast_nodes, "transform");
177 if (auto direct = opposite_exponential_lambert_pattern(sum, var, context)) {
178 return direct;
179 }
180 std::optional<std::shared_ptr<SymbolicExpr>> found;
181 std::vector<std::shared_ptr<const SymbolicNode>> constants;
182 bool other_variables = false;
183 for (const auto& operand : sum.operands()) {
184 auto product = std::dynamic_pointer_cast<const MultiplyNode>(operand);
185 if (product) {
186 auto candidate = lambert_inner(*product, var);
187 if (candidate && !found) {
188 found = candidate;
189 continue;
190 }
191 }
192 if (!expression_depends_on_variable(operand, var)) {
193 constants.push_back(operand);
194 } else {
195 other_variables = true;
196 }
197 }
198 if (!found || other_variables) {
199 return std::nullopt;
200 }
202 constant_sum(std::move(constants)), SymbolicExpr::number(-1))), transform_budget));
203 return LambertWPattern{*found, rhs};
204}
205
206std::optional<ExpBasePattern> power_pattern(
207 const PowerNode& power, const std::string& var, ComputationContext& context) {
208 if (expression_depends_on_variable(power.base(), var) ||
210 return std::nullopt;
211 }
212 auto base = make_expression_ptr(power.base());
213 auto exponent = make_expression_ptr(power.exponent());
214 lmmc_real_t value;
215 if (try_evaluate_numeric(base, value, context) && value > 0 &&
216 std::abs(value - 1.0) > LMMC_REAL_EPSILON) {
217 return ExpBasePattern{base, exponent, nullptr};
218 }
219 return std::nullopt;
220}
221
222std::optional<ExpBasePattern> additive_power_pattern(
223 const AddNode& sum, const std::string& var, ComputationContext& context) {
224 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
225 (context).limits().max_ast_nodes, "transform");
226 std::optional<ExpBasePattern> found;
227 std::vector<std::shared_ptr<const SymbolicNode>> constants;
228 bool other_variables = false;
229 for (const auto& operand : sum.operands()) {
230 if (auto power = std::dynamic_pointer_cast<const PowerNode>(operand)) {
231 auto candidate = power_pattern(*power, var, context);
232 if (candidate && !found) {
233 found = std::move(candidate);
234 continue;
235 }
236 }
237 if (!expression_depends_on_variable(operand, var)) {
238 constants.push_back(operand);
239 } else {
240 other_variables = true;
241 }
242 }
243 if (!found || other_variables) {
244 return std::nullopt;
245 }
246 found->rhs = detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::multiply(
247 constant_sum(std::move(constants)), SymbolicExpr::number(-1))), transform_budget));
248 return found;
249}
250
251}
252
253std::optional<InversePattern> decompose_trig_exp_pattern(
254 const std::shared_ptr<SymbolicExpr>& expr, const std::string& var) {
255 if (!expr || !node(expr)) {
256 return std::nullopt;
257 }
258 if (auto function = std::dynamic_pointer_cast<const FunctionNode>(node(expr))) {
259 if (invertible_function(*function, var)) {
260 return InversePattern{function->type(),
261 make_expression_ptr(function->arguments()[0]), SymbolicExpr::number(0), nullptr};
262 }
263 }
264 if (auto sum = std::dynamic_pointer_cast<const AddNode>(node(expr))) {
265 return additive_function_pattern(*sum, var);
266 }
267 return std::nullopt;
268}
269
270std::optional<LambertWPattern> decompose_lambert_w_pattern(
271 const std::shared_ptr<SymbolicExpr>& expr, const std::string& var, ComputationContext& context) {
272 if (!expr || !node(expr)) {
273 return std::nullopt;
274 }
275 if (auto product = std::dynamic_pointer_cast<const MultiplyNode>(node(expr))) {
276 auto inner = lambert_inner(*product, var);
277 if (inner) {
278 return LambertWPattern{*inner, SymbolicExpr::number(0)};
279 }
280 }
281 if (auto sum = std::dynamic_pointer_cast<const AddNode>(node(expr))) {
282 return additive_lambert_pattern(*sum, var, context);
283 }
284 return std::nullopt;
285}
286
287std::optional<ExpBasePattern> decompose_exp_base_pattern(
288 const std::shared_ptr<SymbolicExpr>& expr, const std::string& var,
290 if (!expr || !node(expr)) {
291 return std::nullopt;
292 }
293 if (auto power = std::dynamic_pointer_cast<const PowerNode>(node(expr))) {
294 auto pattern = power_pattern(*power, var, context);
295 if (pattern) {
296 pattern->rhs = SymbolicExpr::number(0);
297 return pattern;
298 }
299 }
300 if (auto sum = std::dynamic_pointer_cast<const AddNode>(node(expr))) {
301 return additive_power_pattern(*sum, var, context);
302 }
303 return std::nullopt;
304}
305
306}
加法节点,表示多个操作数的求和。
const std::vector< std::shared_ptr< const SymbolicNode > > & operands() const noexcept
函数节点,表示数学函数调用(三角函数、对数、特殊函数等)。
乘法节点,表示多个操作数的乘积。
const std::vector< std::shared_ptr< const SymbolicNode > > & operands() const noexcept
幂运算节点,表示 base^exponent。
const std::shared_ptr< const SymbolicNode > & exponent() const noexcept
const std::shared_ptr< const SymbolicNode > & base() const noexcept
static std::shared_ptr< const SymbolicNode > create_multiply(std::vector< std::shared_ptr< const SymbolicNode > > ops, detail::RewriteBudget *budget=nullptr)
创建乘法节点,自动扁平化嵌套乘法并消除单位元.
std::optional< LambertWPattern > opposite_exponential_lambert_pattern(const AddNode &sum, const std::string &var, ComputationContext &context)
std::optional< ScaledFunction > scaled_function(const std::shared_ptr< const SymbolicNode > &node, const std::string &var)
std::optional< LambertWPattern > additive_lambert_pattern(const AddNode &sum, const std::string &var, ComputationContext &context)
std::shared_ptr< SymbolicExpr > constant_sum(std::vector< std::shared_ptr< const SymbolicNode > > terms)
std::optional< InversePattern > additive_function_pattern(const AddNode &sum, const std::string &var)
std::optional< ExpBasePattern > additive_power_pattern(const AddNode &sum, const std::string &var, ComputationContext &context)
std::shared_ptr< const SymbolicNode > product_without(const MultiplyNode &product, std::size_t index)
std::optional< std::shared_ptr< SymbolicExpr > > lambert_inner(const MultiplyNode &product, const std::string &var)
std::optional< ExpBasePattern > power_pattern(const PowerNode &power, const std::string &var, ComputationContext &context)
std::optional< LambertWPattern > decompose_lambert_w_pattern(const std::shared_ptr< SymbolicExpr > &expr, const std::string &var, ComputationContext &context)
std::optional< ExpBasePattern > decompose_exp_base_pattern(const std::shared_ptr< SymbolicExpr > &expr, const std::string &var, ComputationContext &context)
std::optional< InversePattern > decompose_trig_exp_pattern(const std::shared_ptr< SymbolicExpr > &expr, const std::string &var)
bool try_evaluate_numeric(const std::shared_ptr< SymbolicExpr > &expr, lmmc_real_t &out, ComputationContext &context)
std::shared_ptr<::LMCAS::SymbolicExpr > make_expression_ptr(SymbolicNodePtr root)
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
ExactRealAlgebraic rhs
std::shared_ptr< const Node > make_node(Args &&... args)
SymbolicNodePtr normalize_node(const SymbolicNodePtr &node, RewriteBudget &budget, const FactsQuery &facts, Domain domain)
std::size_t std::size_t ComputationContext & context
bool expression_depends_on_variable(const detail::SymbolicNodePtr &expression, const std::string &variable, detail::RewriteBudget *budget)
const ExprPtr & exponent
const std::string const ExprPtr & value
ExprResult function(const std::string &name, std::vector< ExprPtr > arguments)