LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
transcendental_rewrite.cpp
浏览该文件的文档.
2/**
3 * @file transcendental_rewrite.cpp
4 * @brief 超越因子的逆换元、常数提取与乘法结构识别。
5 */
6
9
10#include <string>
11#include <vector>
12
14
15namespace LMCAS {
16
17/**
18 * @brief 将因子表达式中的不定元变量替换回原始超越子表达式.
19 *
20 * 对换元后的因子执行逆操作:遍历映射列表,将每个不定元(u0, u1, ...)
21 * 替换为其对应的原始超越表达式(如 sin(x),cos(x) 等).
22 * 逐一执行自由变量代入,复用调用者的变换预算。
23 *
24 * @param[in] factor_expr 以不定元表示的因子表达式
25 * @param[in] mappings 换元映射列表(indeterminate -> trans_expr)
26 * @return 替换后的符号表达式,以原始变量和超越函数表示
27 * @internal
28 */
29std::shared_ptr<SymbolicExpr> tf_back_substitute(
30 const std::shared_ptr<SymbolicExpr>& factor_expr,
31 const std::vector<TransSubstitution>& mappings, ComputationContext& context) {
32
33 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
34 (context).limits().max_ast_nodes, "transform");
35
36 if (!factor_expr || !LMCAS::detail::node(factor_expr)) {
37 return factor_expr;
38 }
39 if (mappings.empty()) {
40 return factor_expr;
41 }
42
43 auto result = factor_expr;
44
45 for (const auto& m : mappings) {
46 if (!m.trans_expr || m.indeterminate.empty()) {
47 continue;
48 }
49
50 /// 仅当表达式依赖该不定元时才执行替换
51 if (expression_depends_on_variable(LMCAS::detail::node(result), m.indeterminate)) {
52 result = detail::make_expression_ptr(detail::substitute_node(detail::node(result), m.indeterminate, detail::node(m.trans_expr), transform_budget));
53 }
54 }
55
56 return result;
57}
58
59namespace {
60
62public:
63 std::vector<std::shared_ptr<SymbolicExpr>> run(
64 const std::vector<std::shared_ptr<SymbolicExpr>>& factors,
65 detail::RewriteBudget& budget) {
66 for (const auto& factor : factors) {
67 if (!factor || !LMCAS::detail::node(factor)) {
68 continue;
69 }
70 auto simplified = detail::make_expression_ptr(
71 detail::normalize_node(detail::node(factor), budget));
72 if (!simplified || !LMCAS::detail::node(simplified)) {
73 simplified = factor;
74 }
75 if (!append(simplified)) {
76 return std::move(result_);
77 }
78 }
79 if (constant_ != Rational(1)) {
80 result_.insert(result_.begin(), SymbolicExpr::number(constant_));
81 }
82 return std::move(result_);
83 }
84
85private:
86 bool append(const std::shared_ptr<SymbolicExpr>& factor) {
87 const auto& node = LMCAS::detail::node(factor);
88 if (auto number = std::dynamic_pointer_cast<const NumberNode>(node)) {
89 return append_number(*number);
90 }
91 if (auto product = std::dynamic_pointer_cast<const MultiplyNode>(node)) {
92 append_product(*product, factor);
93 } else {
94 result_.push_back(factor);
95 }
96 return true;
97 }
98
99 bool append_number(const NumberNode& number) {
100 const auto value = exact_number_as_rational(number);
101 if (value == Rational(0)) {
102 result_.clear();
103 result_.push_back(SymbolicExpr::number(0));
104 return false;
105 }
107 return true;
108 }
109
111 const std::vector<std::shared_ptr<const SymbolicNode>>& numeric,
112 std::vector<std::shared_ptr<const SymbolicNode>>& symbolic) {
113 for (const auto& operand : numeric) {
114 auto number = std::dynamic_pointer_cast<const NumberNode>(operand);
116 }
117 if (symbolic.size() == 1) {
118 result_.push_back(LMCAS::detail::make_expression_ptr(symbolic[0]));
119 } else {
121 LMCAS::detail::make_node<MultiplyNode>(std::move(symbolic))));
122 }
123 }
124
126 const std::vector<std::shared_ptr<const SymbolicNode>>& numeric) {
127 Rational product(1);
128 for (const auto& operand : numeric) {
129 auto number = std::dynamic_pointer_cast<const NumberNode>(operand);
130 product = product * exact_number_as_rational(*number);
131 }
132 constant_ = constant_ * product;
133 }
134
135 void append_product(const MultiplyNode& product,
136 const std::shared_ptr<SymbolicExpr>& factor) {
137 std::vector<std::shared_ptr<const SymbolicNode>> numeric;
138 std::vector<std::shared_ptr<const SymbolicNode>> symbolic;
139 for (const auto& operand : product.operands()) {
140 if (std::dynamic_pointer_cast<const NumberNode>(operand)) {
141 numeric.push_back(operand);
142 } else {
143 symbolic.push_back(operand);
144 }
145 }
146 if (!numeric.empty() && !symbolic.empty()) {
147 append_mixed_product(numeric, symbolic);
148 } else if (numeric.empty()) {
149 result_.push_back(factor);
150 } else {
152 }
153 }
154
155 std::vector<std::shared_ptr<SymbolicExpr>> result_;
156 Rational constant_{1};
157};
158
159}
160
161/**
162 * @brief 化简逆换元后的因子,合并数值因子及乘积的数值前导系数。
163 * 保留非常数部分,将非 1 的常数积置于结果首位。
164 * @param[in,out] factors 就地化简的因子列表
165 * @return 化简并提取常数后的因子列表
166 */
167std::vector<std::shared_ptr<SymbolicExpr>> tf_simplify_factors(
168 std::vector<std::shared_ptr<SymbolicExpr>>& factors) {
170 return tf_simplify_factors_impl(factors, context);
171}
172
173std::vector<std::shared_ptr<SymbolicExpr>> tf_simplify_factors_impl(
174 const std::vector<std::shared_ptr<SymbolicExpr>>& factors, ComputationContext& context) {
175 detail::RewriteBudget budget(context, context.limits().max_recursion_depth,
176 context.limits().max_ast_nodes, "factor_transcendental");
177 FactorSimplification simplification;
178 return simplification.run(factors, budget);
179}
180
181
182/**
183 * @brief 判断换元后的表达式是否对所有不定元和原始变量均为线性.
184 *
185 * 换元表达式对每个不定元(u0, u1, ...)及原始变量的次数均小于等于 1 时,
186 * 该表达式在超越多项式环中为整体元素.
187 * 例如 a*sin(x) + b*x + c 映射为 a*u0 + b*x + c,对 u0 与 x 均为线性.
188 *
189 * @param[in] sub_result 换元结果(含 poly_expr 和 mappings)
190 * @param[in] var 原始目标变量名
191 * @return 表达式对所有变量均为线性返回 true
192 * @internal
193 */
195 const TransSubstitutionResult& sub_result,
196 const std::string& var) {
197
198 if (!sub_result.poly_expr || !LMCAS::detail::node(sub_result.poly_expr)) {
199 return false;
200 }
201 if (sub_result.mappings.empty()) {
202 return false;
203 }
204
205 const auto& root = LMCAS::detail::node(sub_result.poly_expr);
206
207 /// 检查每个不定元的次数是否 <= 1
208 for (const auto& m : sub_result.mappings) {
209 int deg = tf_degree_in(root, m.indeterminate);
210 if (deg < 0 || deg > 1) {
211 return false;
212 }
213 }
214
215 /// 检查原始变量的次数是否 <= 1
216 if (expression_depends_on_variable(root, var)) {
217 int deg = tf_degree_in(root, var);
218 if (deg < 0 || deg > 1) {
219 return false;
220 }
221 }
222
223 return true;
224}
225
226/**
227 * @brief 检测表达式是否已为独立子表达式的乘积形式.
228 *
229 * MultiplyNode 的各操作数直接形成独立因子,沿乘法结构完成分解;
230 * 数值常数单独累积,并在值异于 1 时形成常数因子.
231 *
232 * @param[in] expr 待检测的符号表达式
233 * @return 因子列表;若表达式非乘积形式则返回空向量(表示无快速路径)
234 * @internal
235 */
236std::vector<std::shared_ptr<SymbolicExpr>> tf_detect_multiplicative_structure(
237 const std::shared_ptr<SymbolicExpr>& expr) {
238
239 if (!expr || !LMCAS::detail::node(expr)) {
240 return {};
241 }
242
243 auto mul = std::dynamic_pointer_cast<const MultiplyNode>(LMCAS::detail::node(expr));
244 if (!mul || mul->operands().size() < 2) {
245 return {};
246 }
247
248 std::vector<std::shared_ptr<SymbolicExpr>> factors;
249 Rational constant_acc(1);
250
251 for (const auto& op : mul->operands()) {
252 if (!op) {
253 continue;
254 }
255
256 /// 数值常数单独累积
257 if (op->is_number()) {
258 auto num = std::dynamic_pointer_cast<const NumberNode>(op);
259 if (num) {
260 if (std::holds_alternative<BigInt>(num->value())) {
261 constant_acc = constant_acc * Rational(std::get<BigInt>(num->value()));
262 } else if (std::holds_alternative<Rational>(num->value())) {
263 constant_acc = constant_acc * std::get<Rational>(num->value());
264 } else {
265 /// 浮点数值:作为独立因子保留
266 factors.push_back(LMCAS::detail::make_expression_ptr(op));
267 }
268 }
269 continue;
270 }
271
272 /// 非数值操作数作为独立因子
273 factors.push_back(LMCAS::detail::make_expression_ptr(op));
274 }
275
276 /// 仅当存在至少两个非常数因子(或一个非常数因子加一个非 1 常数)时才视为有效乘积分解
277 if (factors.size() < 2 && (factors.empty() || constant_acc == Rational(1))) {
278 return {};
279 }
280
281 /// 插入累积常数因子(若非 1)
282 if (constant_acc != Rational(1)) {
283 auto const_expr = SymbolicExpr::number(constant_acc);
284 factors.insert(factors.begin(), const_expr);
285 }
286
287 return factors;
288}
289
291 const std::shared_ptr<const SymbolicNode>& node, const std::string& var) {
292 auto function = std::dynamic_pointer_cast<const FunctionNode>(node);
293 if (!function) {
294 return false;
295 }
296 if (function->type() != FunctionNode::FuncType::Exp ||
297 function->arguments().size() != 1) {
298 return false;
299 }
300 return expression_depends_on_variable(function->arguments()[0], var);
301}
302
303/**
304 * @brief 从乘积项中提取指数函数因子.
305 *
306 * 若节点本身为 exp(f(x)) 形式,直接返回该节点.
307 * 若节点为 MultiplyNode,遍历其操作数寻找 exp(f(x)) 因子.
308 * 仅提取第一个匹配的指数函数因子.
309 *
310 * @param[in] node 待检测的 AST 节点
311 * @param[in] var 目标变量名
312 * @return 找到的 exp 因子节点;未找到返回 nullptr
313 * @internal
314 */
315static std::shared_ptr<const SymbolicNode> tf_extract_exp_factor(
316 const std::shared_ptr<const SymbolicNode>& node,
317 const std::string& var) {
318
319 if (!node) {
320 return nullptr;
321 }
322
323 /// 直接为 exp(f(x)) 形式
324 if (tf_is_variable_exponential(node, var)) {
325 return node;
326 }
327
328 /// 乘积形式:遍历操作数寻找 exp 因子
329 if (auto mul = std::dynamic_pointer_cast<const MultiplyNode>(node)) {
330 for (const auto& op : mul->operands()) {
331 if (tf_is_variable_exponential(op, var)) {
332 return op;
333 }
334 }
335 }
336
337 return nullptr;
338}
339
340/**
341 * @brief 从乘积项中移除指定的指数函数因子,返回剩余部分.
342 *
343 * 若节点本身即为该 exp 因子,返回数值 1.
344 * 若节点为 MultiplyNode,移除匹配的 exp 操作数后重建乘积.
345 *
346 * @param[in] node 原始乘积项节点
347 * @param[in] exp_factor 待移除的 exp 因子节点
348 * @return 移除 exp 因子后的剩余节点
349 * @internal
350 */
351static std::shared_ptr<const SymbolicNode> tf_remove_exp_factor(
352 const std::shared_ptr<const SymbolicNode>& node,
353 const std::shared_ptr<const SymbolicNode>& exp_factor) {
354
355 if (!node || !exp_factor) {
356 return node;
357 }
358
359 /// 节点本身即为 exp 因子
360 if (node->equals(*exp_factor)) {
361 return LMCAS::detail::make_node<NumberNode>(BigInt(1));
362 }
363
364 /// 乘积形式:移除匹配的操作数
365 if (auto mul = std::dynamic_pointer_cast<const MultiplyNode>(node)) {
366 std::vector<std::shared_ptr<const SymbolicNode>> remaining_ops;
367 bool removed = false;
368
369 for (const auto& op : mul->operands()) {
370 if (!removed && op->equals(*exp_factor)) {
371 removed = true;
372 continue;
373 }
374 remaining_ops.push_back(op);
375 }
376
377 if (!removed) {
378 return node;
379 }
380
381 if (remaining_ops.empty()) {
382 return LMCAS::detail::make_node<NumberNode>(BigInt(1));
383 }
384 if (remaining_ops.size() == 1) {
385 return remaining_ops[0];
386 }
387 return LMCAS::detail::make_node<MultiplyNode>(std::move(remaining_ops));
388 }
389
390 return node;
391}
392
393/**
394 * @brief 检测加法表达式中的公共指数因子并执行分离.
395 *
396 * 对于 AddNode 形式的表达式,检查所有加法项是否共享相同的 exp(f(x)) 因子.
397 * 若是,则提取公因子:expr = exp(f(x)) * (t1' + t2' + ... + tn'),
398 * 其中 ti' = ti / exp(f(x)).
399 *
400 * 典型用例:
401 * - exp(x)*x + exp(x) -> [exp(x), x+1]
402 * - exp(x)*x^2 + 2*exp(x)*x + exp(x) -> [exp(x), x^2+2x+1]
403 *
404 * @param[in] expr 待检测的符号表达式
405 * @param[in] var 目标变量名
406 * @return 因子列表 [exp(f(x)), remaining_sum];若无公共 exp 因子则返回空向量
407 * @internal
408 */
409std::vector<std::shared_ptr<SymbolicExpr>> tf_detect_exponential_separation(
410 const std::shared_ptr<SymbolicExpr>& expr,
411 const std::string& var, ComputationContext& context) {
412
413 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
414 (context).limits().max_ast_nodes, "transform");
415
416 if (!expr || !LMCAS::detail::node(expr)) {
417 return {};
418 }
419
420 auto add = std::dynamic_pointer_cast<const AddNode>(LMCAS::detail::node(expr));
421 if (!add || add->operands().size() < 2) {
422 return {};
423 }
424
425 /// 从第一个加法项中提取 exp 因子作为候选公因子
426 std::shared_ptr<const SymbolicNode> common_exp = tf_extract_exp_factor(add->operands()[0], var);
427 if (!common_exp) {
428 return {};
429 }
430
431 /// 验证所有加法项均含有相同的 exp 因子
432 for (size_t i = 1; i < add->operands().size(); ++i) {
433 std::shared_ptr<const SymbolicNode> term_exp = tf_extract_exp_factor(add->operands()[i], var);
434 if (!term_exp || !term_exp->equals(*common_exp)) {
435 return {};
436 }
437 }
438
439 /// 所有项共享相同的 exp(f(x)),执行分离
440 /// 构造剩余和:对每个项移除 exp 因子
441 std::vector<std::shared_ptr<const SymbolicNode>> remainder_terms;
442 remainder_terms.reserve(add->operands().size());
443
444 for (const auto& op : add->operands()) {
445 auto remainder = tf_remove_exp_factor(op, common_exp);
446 remainder_terms.push_back(remainder);
447 }
448
449 /// 构造结果
450 auto exp_factor_expr = LMCAS::detail::make_expression_ptr(common_exp);
451
452 std::shared_ptr<SymbolicExpr> sum_expr;
453 if (remainder_terms.size() == 1) {
454 sum_expr = LMCAS::detail::make_expression_ptr(remainder_terms[0]);
455 } else {
457 LMCAS::detail::make_node<AddNode>(std::move(remainder_terms)));
458 }
459
460 /// 化简剩余和
461 auto simplified_sum = detail::make_expression_ptr(detail::normalize_node(detail::node(sum_expr), transform_budget));
462 if (simplified_sum && LMCAS::detail::node(simplified_sum)) {
463 sum_expr = simplified_sum;
464 }
465
466 return {exp_factor_expr, sum_expr};
467}
468
469
470/**
471 * @brief 判断表达式 AST 中是否包含依赖指定变量的超越函数.
472 *
473 * 递归遍历 AST,若发现任何 FunctionNode 类型为 Sin/Cos/Exp/Ln/Tan
474 * 且其参数依赖 var,则返回 true.
475 *
476 * @param[in] node 当前 AST 节点
477 * @param[in] var 目标变量名
478 * @return 包含超越函数返回 true
479 * @internal
480 */
482 const std::vector<std::shared_ptr<const SymbolicNode>>& nodes,
483 const std::string& var) {
484 for (const auto& node : nodes) {
485 if (tf_contains_transcendental(node, var)) {
486 return true;
487 }
488 }
489 return false;
490}
491
493 const std::shared_ptr<const SymbolicNode>& node,
494 const std::string& var) {
495
496 if (!node) {
497 return false;
498 }
499
500 if (auto func = std::dynamic_pointer_cast<const FunctionNode>(node)) {
501 if (func->arguments().size() == 1 &&
502 tf_is_transcendental_type(func->type()) &&
503 expression_depends_on_variable(func->arguments()[0], var)) {
504 return true;
505 }
506 return any_transcendental(func->arguments(), var);
507 }
508
509 if (auto add = std::dynamic_pointer_cast<const AddNode>(node)) {
510 return any_transcendental(add->operands(), var);
511 }
512
513 if (auto mul = std::dynamic_pointer_cast<const MultiplyNode>(node)) {
514 return any_transcendental(mul->operands(), var);
515 }
516 if (auto pow = std::dynamic_pointer_cast<const PowerNode>(node)) {
517 return tf_contains_transcendental(pow->base(), var) ||
518 tf_contains_transcendental(pow->exponent(), var);
519 }
520
521 return false;
522}
523
524}
乘法节点,表示多个操作数的乘积。
const std::vector< std::shared_ptr< const SymbolicNode > > & operands() const noexcept
bool equals(const SymbolicNode &other) const
判断两个节点是否结构相等.
std::vector< std::shared_ptr< SymbolicExpr > > run(const std::vector< std::shared_ptr< SymbolicExpr > > &factors, detail::RewriteBudget &budget)
void accumulate_numeric_product(const std::vector< std::shared_ptr< const SymbolicNode > > &numeric)
void append_mixed_product(const std::vector< std::shared_ptr< const SymbolicNode > > &numeric, std::vector< std::shared_ptr< const SymbolicNode > > &symbolic)
void append_product(const MultiplyNode &product, const std::shared_ptr< SymbolicExpr > &factor)
std::shared_ptr<::LMCAS::SymbolicExpr > make_expression_ptr(SymbolicNodePtr root)
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
std::shared_ptr< const Node > make_node(Args &&... args)
SymbolicNodePtr normalize_node(const SymbolicNodePtr &node, RewriteBudget &budget, const FactsQuery &facts, Domain domain)
SymbolicNodePtr substitute_node(const SymbolicNodePtr &node, const std::string &variable, const SymbolicNodePtr &replacement, RewriteBudget &budget, const FactsQuery &facts, Domain domain)
std::shared_ptr< SymbolicExpr > num(int value)
ExprResult pow(const ExprPtr &base, const ExprPtr &exponent, ComputationContext &context)
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
bool tf_is_linear_irreducible(const TransSubstitutionResult &substitution, const std::string &variable)
判断换元后的表达式是否对所有不定元和原始变量均为线性.
ExprResult mul(const ExprPtr &lhs, const ExprPtr &rhs, ComputationContext &context)
std::shared_ptr< SymbolicExpr > tf_back_substitute(const std::shared_ptr< SymbolicExpr > &expression, const std::vector< TransSubstitution > &mappings, ComputationContext &context)
将因子表达式中的不定元变量替换回原始超越子表达式.
static bool tf_is_variable_exponential(const std::shared_ptr< const SymbolicNode > &node, const std::string &var)
bool expression_depends_on_variable(const detail::SymbolicNodePtr &expression, const std::string &variable, detail::RewriteBudget *budget)
std::vector< std::shared_ptr< SymbolicExpr > > tf_detect_multiplicative_structure(const std::shared_ptr< SymbolicExpr > &expression)
检测表达式是否已为独立子表达式的乘积形式.
std::vector< std::shared_ptr< SymbolicExpr > > tf_simplify_factors_impl(const std::vector< std::shared_ptr< SymbolicExpr > > &factors, ComputationContext &context)
bool tf_contains_transcendental(const std::shared_ptr< const SymbolicNode > &node, const std::string &variable)
ExprResult add(const ExprPtr &lhs, const ExprPtr &rhs, ComputationContext &context)
std::shared_ptr< SymbolicExpr > poly_expr
换元后的多项式表达式
static std::shared_ptr< const SymbolicNode > tf_extract_exp_factor(const std::shared_ptr< const SymbolicNode > &node, const std::string &var)
从乘积项中提取指数函数因子.
std::vector< std::shared_ptr< SymbolicExpr > > tf_simplify_factors(std::vector< std::shared_ptr< SymbolicExpr > > &factors)
化简逆换元后的因子,合并数值因子及乘积的数值前导系数。 保留非常数部分,将非 1 的常数积置于结果首位。
const ExprPtr RelationOp op
static std::shared_ptr< const SymbolicNode > tf_remove_exp_factor(const std::shared_ptr< const SymbolicNode > &node, const std::shared_ptr< const SymbolicNode > &exp_factor)
从乘积项中移除指定的指数函数因子,返回剩余部分.
int tf_degree_in(const std::shared_ptr< const SymbolicNode > &node, const std::string &variable)
static bool any_transcendental(const std::vector< std::shared_ptr< const SymbolicNode > > &nodes, const std::string &var)
判断表达式 AST 中是否包含依赖指定变量的超越函数.
bool tf_is_transcendental_type(FunctionNode::FuncType function_type)
判断函数类型是否支持超越函数换元。
std::vector< std::shared_ptr< SymbolicExpr > > tf_detect_exponential_separation(const std::shared_ptr< SymbolicExpr > &expression, const std::string &variable, ComputationContext &context)
检测加法表达式中的公共指数因子并执行分离.
const std::string const ExprPtr & value
std::vector< TransSubstitution > mappings
所有换元映射
Rational exact_number_as_rational(const NumberNode &node)
ExprResult function(const std::string &name, std::vector< ExprPtr > arguments)