LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
transcendental_substitution.cpp
浏览该文件的文档.
3#include "poly_utils.hpp"
6
7#include <string>
8#include <vector>
9#include <unordered_set>
10#include <limits>
11#include <cstdint>
12
13namespace LMCAS {
14
15/**
16 * @brief 判断函数类型是否支持超越函数换元。
17 * @param[in] ft 函数类型枚举
18 * @return 属于 Sin/Cos/Exp/Ln/Tan 之一返回 true
19 * @internal
20 */
28
29/**
30 * @brief 按先序收集依赖 var 的超越函数子表达式。
31 *
32 * 嵌套函数按外层优先收集,如 sin(exp(x)) 先于 exp(x)。
33 *
34 * @param[in] node 当前 AST 节点
35 * @param[in] var 目标变量名
36 * @param[out] candidates 收集到的超越子表达式列表
37 * @internal
38 */
40 const std::shared_ptr<const SymbolicNode>& node,
41 const std::string& var,
42 std::vector<std::shared_ptr<const SymbolicNode>>& candidates) {
43
44 if (!node) return;
45
46 if (auto func = std::dynamic_pointer_cast<const FunctionNode>(node)) {
47 if (func->arguments().size() == 1 &&
48 tf_is_transcendental_type(func->type()) &&
49 expression_depends_on_variable(func->arguments()[0], var)) {
50 candidates.push_back(node);
51 }
52 for (auto& arg : func->arguments()) {
53 tf_collect_transcendental(arg, var, candidates);
54 }
55 return;
56 }
57
58 if (auto add = std::dynamic_pointer_cast<const AddNode>(node)) {
59 for (auto& op : add->operands()) {
60 tf_collect_transcendental(op, var, candidates);
61 }
62 return;
63 }
64
65 if (auto mul = std::dynamic_pointer_cast<const MultiplyNode>(node)) {
66 for (auto& op : mul->operands()) {
67 tf_collect_transcendental(op, var, candidates);
68 }
69 return;
70 }
71
72 if (auto pow = std::dynamic_pointer_cast<const PowerNode>(node)) {
73 tf_collect_transcendental(pow->base(), var, candidates);
74 tf_collect_transcendental(pow->exponent(), var, candidates);
75 return;
76 }
77
78}
79
80/**
81 * @brief 按结构哈希和 equals 比较去重,保留首次出现的顺序。
82 *
83 * @param[in,out] candidates 候选列表,去重后仅保留唯一项
84 * @internal
85 */
86static void tf_deduplicate(std::vector<std::shared_ptr<const SymbolicNode>>& candidates) {
87 NodeSet seen;
88 std::vector<std::shared_ptr<const SymbolicNode>> unique;
89
90 for (auto& node : candidates) {
91 if (seen.find(node) == seen.end()) {
92 seen.insert(node);
93 unique.push_back(node);
94 }
95 }
96
97 candidates = std::move(unique);
98}
99
100/**
101 * @brief 判断两个 AST 节点是否结构相等。
102 * @param[in] a 第一个节点
103 * @param[in] b 第二个节点
104 * @return 结构相等返回 true
105 * @internal
106 */
107static bool tf_nodes_equal(const std::shared_ptr<const SymbolicNode>& a,
108 const std::shared_ptr<const SymbolicNode>& b) {
109 if (!a || !b) return a == b;
110 return a->equals(*b);
111}
112
113/**
114 * @brief 匹配 (-1)*arg 或 arg*(-1) 的二因子乘积结构。
115 *
116 * @param[in] node 待检测节点
117 * @param[in] arg 参考参数节点
118 * @return 若 node 表示 -arg 则返回 true
119 * @internal
120 */
121static bool tf_is_negation_of(const std::shared_ptr<const SymbolicNode>& node,
122 const std::shared_ptr<const SymbolicNode>& arg) {
123 if (!node || !arg) {
124 return false;
125 }
126
127 auto mul = std::dynamic_pointer_cast<const MultiplyNode>(node);
128 if (!mul || mul->operands().size() != 2) {
129 return false;
130 }
131
132 for (int i = 0; i < 2; ++i) {
133 auto num_node = std::dynamic_pointer_cast<const NumberNode>(mul->operands()[i]);
134 if (!num_node) {
135 continue;
136 }
137
138 if (num_node->is_negative_one()) {
139 int other_idx = 1 - i;
140 return tf_nodes_equal(mul->operands()[other_idx], arg);
141 }
142 }
143
144 return false;
145}
146
147/**
148 * @brief 按映射顺序将超越子表达式替换为不定元,递归重建未匹配节点。
149 *
150 * 外层映射优先:sin(exp(x)) 整体替换为 u0,exp(x) 保留在 u0 的定义中。
151 *
152 * @param[in] node 当前 AST 节点
153 * @param[in] mappings 换元映射列表(按分配顺序)
154 * @return 替换后的新节点
155 * @internal
156 */
157static std::shared_ptr<const SymbolicNode> tf_substitute_expr(
158 const std::shared_ptr<const SymbolicNode>& node,
159 const std::vector<TransSubstitution>& mappings) {
160
161 if (!node) return nullptr;
162
163 for (const auto& m : mappings) {
164 if (m.trans_expr && LMCAS::detail::node(m.trans_expr) &&
165 node->equals(*LMCAS::detail::node(m.trans_expr))) {
166 return LMCAS::detail::make_node<VariableNode>(m.indeterminate);
167 }
168 }
169
170 if (auto func = std::dynamic_pointer_cast<const FunctionNode>(node)) {
171 std::vector<std::shared_ptr<const SymbolicNode>> new_args;
172 new_args.reserve(func->arguments().size());
173 for (const auto& arg : func->arguments()) {
174 new_args.push_back(tf_substitute_expr(arg, mappings));
175 }
176 return LMCAS::detail::make_node<FunctionNode>(func->type(), std::move(new_args));
177 }
178
179 if (auto add = std::dynamic_pointer_cast<const AddNode>(node)) {
180 std::vector<std::shared_ptr<const SymbolicNode>> new_ops;
181 new_ops.reserve(add->operands().size());
182 for (const auto& op : add->operands()) {
183 new_ops.push_back(tf_substitute_expr(op, mappings));
184 }
185 return LMCAS::detail::make_node<AddNode>(std::move(new_ops));
186 }
187
188 if (auto mul = std::dynamic_pointer_cast<const MultiplyNode>(node)) {
189 std::vector<std::shared_ptr<const SymbolicNode>> new_ops;
190 new_ops.reserve(mul->operands().size());
191 for (const auto& op : mul->operands()) {
192 new_ops.push_back(tf_substitute_expr(op, mappings));
193 }
194 return LMCAS::detail::make_node<MultiplyNode>(std::move(new_ops));
195 }
196
197 if (auto pow = std::dynamic_pointer_cast<const PowerNode>(node)) {
198 auto new_base = tf_substitute_expr(pow->base(), mappings);
199 auto new_exp = tf_substitute_expr(pow->exponent(), mappings);
200 return LMCAS::detail::make_node<PowerNode>(std::move(new_base), std::move(new_exp));
201 }
202
203 return node;
204}
205
207 if (first == FunctionNode::FuncType::Sin) {
208 return second == FunctionNode::FuncType::Cos;
209 }
210 return first == FunctionNode::FuncType::Cos && second == FunctionNode::FuncType::Sin;
211}
212
213static std::shared_ptr<SymbolicExpr> tf_pair_constraint(
214 const TransSubstitution& left, const TransSubstitution& right,
215 const FunctionNode& first, const FunctionNode& second) {
216 const auto first_type = first.type();
217 const auto second_type = second.type();
218 const bool sin_cos = tf_is_sine_cosine_pair(first_type, second_type);
219 if (sin_cos && tf_nodes_equal(first.arguments()[0], second.arguments()[0])) {
220 auto ui = SymbolicExpr::variable(left.indeterminate);
221 auto uj = SymbolicExpr::variable(right.indeterminate);
222 auto two = SymbolicExpr::number(2);
223 auto sum = SymbolicExpr::add(SymbolicExpr::power(ui, two), SymbolicExpr::power(uj, two));
224 return SymbolicExpr::add(sum, SymbolicExpr::number(-1));
225 }
226 if (first_type != FunctionNode::FuncType::Exp ||
227 second_type != FunctionNode::FuncType::Exp) {
228 return nullptr;
229 }
230 if (!tf_is_negation_of(second.arguments()[0], first.arguments()[0]) &&
231 !tf_is_negation_of(first.arguments()[0], second.arguments()[0])) {
232 return nullptr;
233 }
234 auto ui = SymbolicExpr::variable(left.indeterminate);
235 auto uj = SymbolicExpr::variable(right.indeterminate);
236 return SymbolicExpr::add(SymbolicExpr::multiply(ui, uj), SymbolicExpr::number(-1));
237}
238
240 const auto& mappings = result.mappings;
241 for (size_t i = 0; i < mappings.size(); ++i) {
242 auto first = std::dynamic_pointer_cast<const FunctionNode>(
243 detail::node(mappings[i].trans_expr));
244 if (!first || first->arguments().size() != 1) continue;
245 for (size_t j = i + 1; j < mappings.size(); ++j) {
246 auto second = std::dynamic_pointer_cast<const FunctionNode>(
247 detail::node(mappings[j].trans_expr));
248 if (!second || second->arguments().size() != 1) continue;
249 auto constraint = tf_pair_constraint(mappings[i], mappings[j], *first, *second);
250 if (constraint) result.constraints.push_back(std::move(constraint));
251 }
252 }
253}
254
255/**
256 * @brief 为依赖 var 的 Sin、Cos、Exp、Ln、Tan 子表达式构造换元结果。
257 *
258 * 按结构去重后,依次分配不定元 u0、u1、u2 等。
259 *
260 * @param[in] expr 待检测的符号表达式
261 * @param[in] var 目标变量名
262 * @return 换元映射、代数约束及替换后的表达式;无匹配时保留原表达式。
263 */
265 const std::shared_ptr<SymbolicExpr>& expr,
266 const std::string& var) {
267
269 result.poly_expr = nullptr;
270
271 if (!expr || !LMCAS::detail::node(expr)) {
272 return result;
273 }
274
275 std::vector<std::shared_ptr<const SymbolicNode>> candidates;
276 tf_collect_transcendental(LMCAS::detail::node(expr), var, candidates);
277
278 tf_deduplicate(candidates);
279
280 for (size_t i = 0; i < candidates.size(); ++i) {
281 TransSubstitution mapping;
282 mapping.trans_expr = LMCAS::detail::make_expression_ptr(candidates[i]);
283 mapping.indeterminate = "u" + std::to_string(i);
284 result.mappings.push_back(std::move(mapping));
285 }
286
287 tf_detect_constraints(result);
288
289 if (!result.mappings.empty()) {
290 auto substituted = tf_substitute_expr(LMCAS::detail::node(expr), result.mappings);
291 result.poly_expr = LMCAS::detail::make_expression_ptr(substituted);
292 } else {
293 result.poly_expr = expr;
294 }
295
296 return result;
297}
298
299}
函数节点,表示数学函数调用(三角函数、对数、特殊函数等)。
FuncType type() const noexcept
const std::vector< std::shared_ptr< const SymbolicNode > > & arguments() const noexcept
bool equals(const SymbolicNode &other) const
判断两个节点是否结构相等.
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)
std::unordered_set< std::shared_ptr< const SymbolicNode >, NodeHash, NodeEqual > NodeSet
ExprResult pow(const ExprPtr &base, const ExprPtr &exponent, ComputationContext &context)
ExprResult mul(const ExprPtr &lhs, const ExprPtr &rhs, ComputationContext &context)
bool expression_depends_on_variable(const detail::SymbolicNodePtr &expression, const std::string &variable, detail::RewriteBudget *budget)
ExprResult add(const ExprPtr &lhs, const ExprPtr &rhs, ComputationContext &context)
std::shared_ptr< SymbolicExpr > poly_expr
换元后的多项式表达式
const MultiPoly & b
static bool tf_is_sine_cosine_pair(FunctionNode::FuncType first, FunctionNode::FuncType second)
const ExprPtr RelationOp op
__attribute__((visibility("default"))) VectorCalculusExprResult curve_integral_scalar_checked(const std __attribute__((visibility("default"))) VectorCalculusExprResult curve_integral_scalar_checked(const std __attribute__((visibility("default"))) std const VectorField const std::string const std::shared_ptr< SymbolicExpr > & a
static std::shared_ptr< SymbolicExpr > tf_pair_constraint(const TransSubstitution &left, const TransSubstitution &right, const FunctionNode &first, const FunctionNode &second)
std::string indeterminate
代数不定元名 (e.g., "u0")
static std::shared_ptr< const SymbolicNode > tf_substitute_expr(const std::shared_ptr< const SymbolicNode > &node, const std::vector< TransSubstitution > &mappings)
按映射顺序将超越子表达式替换为不定元,递归重建未匹配节点。
bool tf_is_transcendental_type(FunctionNode::FuncType function_type)
判断函数类型是否支持超越函数换元。
TransSubstitutionResult detect_trans_substitutions(const std::shared_ptr< SymbolicExpr > &expr, const std::string &var)
为依赖 var 的 Sin、Cos、Exp、Ln、Tan 子表达式构造换元结果。
const ExprPtr & right
static void tf_collect_transcendental(const std::shared_ptr< const SymbolicNode > &node, const std::string &var, std::vector< std::shared_ptr< const SymbolicNode > > &candidates)
按先序收集依赖 var 的超越函数子表达式。
static void tf_deduplicate(std::vector< std::shared_ptr< const SymbolicNode > > &candidates)
按结构哈希和 equals 比较去重,保留首次出现的顺序。
std::shared_ptr< SymbolicExpr > trans_expr
原始超越子表达式 (e.g., sin(x))
std::vector< TransSubstitution > mappings
所有换元映射
static void tf_detect_constraints(TransSubstitutionResult &result)
static bool tf_is_negation_of(const std::shared_ptr< const SymbolicNode > &node, const std::shared_ptr< const SymbolicNode > &arg)
匹配 (-1)*arg 或 arg*(-1) 的二因子乘积结构。
static bool tf_nodes_equal(const std::shared_ptr< const SymbolicNode > &a, const std::shared_ptr< const SymbolicNode > &b)
判断两个 AST 节点是否结构相等。
std::vector< std::shared_ptr< SymbolicExpr > > constraints
代数约束 (e.g., u0^2+u1^2-1=0)
换元映射条目:超越子表达式 -> 代数不定元名
多项式转换与精确符号多项式代数。
内部 AST 定义。
混合超越方程不可约因式分解器公共 API.