LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
transcendental_pythagorean.cpp
浏览该文件的文档.
2
3#include <string>
4#include <vector>
5
6namespace LMCAS {
7/**
8 * @brief 匹配 sin^2(f) 或 cos^2(f),提取函数类型和参数。
9 * @note 对应 PowerNode(FunctionNode(Sin/Cos, [f]), NumberNode(2))。
10 *
11 * @param[in] node 待检测的 AST 节点
12 * @param[out] func_type 输出函数类型(Sin 或 Cos)
13 * @param[out] argument 输出函数参数节点
14 * @return 匹配成功返回 true
15 * @internal
16 */
18 const std::shared_ptr<const SymbolicNode>& node,
19 FunctionNode::FuncType& func_type,
20 std::shared_ptr<const SymbolicNode>& argument) {
21
22 auto pow = std::dynamic_pointer_cast<const PowerNode>(node);
23 if (!pow) {
24 return false;
25 }
26
27 auto exp_num = std::dynamic_pointer_cast<const NumberNode>(pow->exponent());
28 if (!exp_num) {
29 return false;
30 }
31
32 const bool is_two = std::holds_alternative<BigInt>(exp_num->value())
33 ? std::get<BigInt>(exp_num->value()) == BigInt(2)
34 : std::get<Rational>(exp_num->value()) == Rational(2);
35 if (!is_two) {
36 return false;
37 }
38
39 auto func = std::dynamic_pointer_cast<const FunctionNode>(pow->base());
40 if (!func || func->arguments().size() != 1) {
41 return false;
42 }
43
44 if (func->type() != FunctionNode::FuncType::Sin &&
45 func->type() != FunctionNode::FuncType::Cos) {
46 return false;
47 }
48
49 func_type = func->type();
50 argument = func->arguments()[0];
51 return true;
52}
53
54/**
55 * @brief 从 a*sin^2(f) 或 a*cos^2(f) 提取系数和三角平方项。
56 * @note 单独的三角平方项系数为 1。
57 *
58 * @param[in] node 待分析的加法操作数节点
59 * @param[out] coeff 输出系数节点(nullptr 表示系数为 1)
60 * @param[out] func_type 输出函数类型(Sin 或 Cos)
61 * @param[out] argument 输出函数参数节点
62 * @return 匹配成功返回 true
63 * @internal
64 */
66 const std::shared_ptr<const SymbolicNode>& node,
67 std::shared_ptr<const SymbolicNode>& coeff,
68 FunctionNode::FuncType& func_type,
69 std::shared_ptr<const SymbolicNode>& argument) {
70
71 if (tf_is_trig_squared(node, func_type, argument)) {
72 coeff = nullptr; /**< 表示系数为 1。 */
73 return true;
74 }
75
76 auto mul = std::dynamic_pointer_cast<const MultiplyNode>(node);
77 if (!mul || mul->operands().size() < 2) {
78 return false;
79 }
80
81 for (size_t i = 0; i < mul->operands().size(); ++i) {
82 if (tf_is_trig_squared(mul->operands()[i], func_type, argument)) {
83 std::vector<std::shared_ptr<const SymbolicNode>> coeff_ops;
84 for (size_t j = 0; j < mul->operands().size(); ++j) {
85 if (j != i) {
86 coeff_ops.push_back(mul->operands()[j]);
87 }
88 }
89
90 if (coeff_ops.size() == 1) {
91 coeff = coeff_ops[0];
92 } else {
93 coeff = LMCAS::detail::make_node<MultiplyNode>(std::move(coeff_ops));
94 }
95 return true;
96 }
97 }
98
99 return false;
100}
101
102static std::shared_ptr<const SymbolicNode> tf_simplify_pythagorean_node(
103 const std::shared_ptr<const SymbolicNode>& node, const std::string& var);
104
106 std::shared_ptr<const SymbolicNode> coefficient;
108 std::shared_ptr<const SymbolicNode> argument;
109};
110
112 const std::shared_ptr<const SymbolicNode>& node, const TrigSquare& square) {
113 TrigSquare other;
115 node, other.coefficient, other.type, other.argument)) {
116 return false;
117 }
118 const auto target = square.type == FunctionNode::FuncType::Sin
120 if (other.type != target || !square.argument || !other.argument ||
121 !square.argument->equals(*other.argument)) {
122 return false;
123 }
124 if (!square.coefficient || !other.coefficient) {
125 return !square.coefficient && !other.coefficient;
126 }
127 return square.coefficient->equals(*other.coefficient);
128}
129
130static std::size_t find_complementary_square(
131 const std::vector<std::shared_ptr<const SymbolicNode>>& operands,
132 const std::vector<bool>& consumed, std::size_t start, const TrigSquare& square) {
133 for (std::size_t i = start; i < operands.size(); ++i) {
134 if (!consumed[i] && complementary_square(operands[i], square)) {
135 return i;
136 }
137 }
138 return operands.size();
139}
140
141static std::shared_ptr<const SymbolicNode> simplify_pythagorean_sum(
142 const AddNode& sum, const std::string& var) {
143 std::vector<std::shared_ptr<const SymbolicNode>> operands;
144 operands.reserve(sum.operands().size());
145 for (const auto& operand : sum.operands()) {
146 operands.push_back(tf_simplify_pythagorean_node(operand, var));
147 }
148 std::vector<bool> consumed(operands.size(), false);
149 std::vector<std::shared_ptr<const SymbolicNode>> result;
150 for (std::size_t i = 0; i < operands.size(); ++i) {
151 if (consumed[i]) {
152 continue;
153 }
154 TrigSquare square;
156 operands[i], square.coefficient, square.type, square.argument)) {
157 result.push_back(operands[i]);
158 continue;
159 }
160 const auto partner = find_complementary_square(operands, consumed, i + 1, square);
161 if (partner == operands.size()) {
162 result.push_back(operands[i]);
163 continue;
164 }
165 consumed[i] = true;
166 consumed[partner] = true;
167 if (square.coefficient) {
168 result.push_back(square.coefficient);
169 } else {
170 result.push_back(LMCAS::detail::make_node<NumberNode>(BigInt(1)));
171 }
172 }
173 if (result.empty()) {
174 return LMCAS::detail::make_node<NumberNode>(BigInt(0));
175 }
176 if (result.size() == 1) {
177 return result[0];
178 }
179 return LMCAS::detail::make_node<AddNode>(std::move(result));
180}
181
182/**
183 * @brief 递归化简 a*sin^2(f) + a*cos^2(f) 为 a,系数为 1 时结果为 1。
184 * @note 在加法节点中配对,要求参数 f 与系数 a 分别结构相等。
185 *
186 * @param[in] node 当前 AST 节点
187 * @param[in] var 目标变量名(用于限定化简范围)
188 * @return 化简后的节点;若无可化简的模式则返回原节点
189 * @internal
190 */
191static std::shared_ptr<const SymbolicNode> tf_simplify_pythagorean_node(
192 const std::shared_ptr<const SymbolicNode>& node,
193 const std::string& var) {
194
195 if (!node) {
196 return node;
197 }
198
199 if (auto add = std::dynamic_pointer_cast<const AddNode>(node)) {
200 return simplify_pythagorean_sum(*add, var);
201 }
202
203 if (auto mul = std::dynamic_pointer_cast<const MultiplyNode>(node)) {
204 std::vector<std::shared_ptr<const SymbolicNode>> new_ops;
205 new_ops.reserve(mul->operands().size());
206 for (const auto& op : mul->operands()) {
207 new_ops.push_back(tf_simplify_pythagorean_node(op, var));
208 }
209 return LMCAS::detail::make_node<MultiplyNode>(std::move(new_ops));
210 }
211
212 if (auto pow = std::dynamic_pointer_cast<const PowerNode>(node)) {
213 auto new_base = tf_simplify_pythagorean_node(pow->base(), var);
214 auto new_exp = tf_simplify_pythagorean_node(pow->exponent(), var);
215 return LMCAS::detail::make_node<PowerNode>(std::move(new_base), std::move(new_exp));
216 }
217
218 if (auto func = std::dynamic_pointer_cast<const FunctionNode>(node)) {
219 std::vector<std::shared_ptr<const SymbolicNode>> new_args;
220 new_args.reserve(func->arguments().size());
221 for (const auto& arg : func->arguments()) {
222 new_args.push_back(tf_simplify_pythagorean_node(arg, var));
223 }
224 return LMCAS::detail::make_node<FunctionNode>(func->type(), std::move(new_args));
225 }
226
227 return node;
228}
229
230/**
231 * @brief 在因式分解前用 sin^2(f) + cos^2(f) = 1 化简表达式。
232 *
233 * @param[in] expr 待化简的符号表达式
234 * @param[in] var 目标变量名
235 * @return 化简后的表达式;若无可化简模式则返回原表达式
236 * @internal
237 */
238std::shared_ptr<SymbolicExpr> tf_simplify_pythagorean(
239 const std::shared_ptr<SymbolicExpr>& expr,
240 const std::string& var) {
241
242 if (!expr || !LMCAS::detail::node(expr)) {
243 return expr;
244 }
245
246 auto simplified_root = tf_simplify_pythagorean_node(LMCAS::detail::node(expr), var);
247
248 if (!simplified_root) {
249 return expr;
250 }
251 if (simplified_root->equals(*LMCAS::detail::node(expr))) {
252 return expr;
253 }
254
255 return LMCAS::detail::make_expression_ptr(simplified_root);
256}
257
258}
加法节点,表示多个操作数的求和。
const std::vector< std::shared_ptr< const SymbolicNode > > & operands() 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)
ExprResult pow(const ExprPtr &base, const ExprPtr &exponent, ComputationContext &context)
std::shared_ptr< SymbolicExpr > tf_simplify_pythagorean(const std::shared_ptr< SymbolicExpr > &expression, const std::string &variable)
在因式分解前用 sin^2(f) + cos^2(f) = 1 化简表达式。
ExprResult mul(const ExprPtr &lhs, const ExprPtr &rhs, ComputationContext &context)
static std::shared_ptr< const SymbolicNode > simplify_pythagorean_sum(const AddNode &sum, const std::string &var)
ExprResult add(const ExprPtr &lhs, const ExprPtr &rhs, ComputationContext &context)
static std::size_t find_complementary_square(const std::vector< std::shared_ptr< const SymbolicNode > > &operands, const std::vector< bool > &consumed, std::size_t start, const TrigSquare &square)
const ExprPtr RelationOp op
const ExprPtr & target
static std::shared_ptr< const SymbolicNode > tf_simplify_pythagorean_node(const std::shared_ptr< const SymbolicNode > &node, const std::string &var)
递归化简 a*sin^2(f) + a*cos^2(f) 为 a,系数为 1 时结果为 1。
std::shared_ptr< const SymbolicNode > argument
static bool complementary_square(const std::shared_ptr< const SymbolicNode > &node, const TrigSquare &square)
static bool tf_extract_coeff_trig_squared(const std::shared_ptr< const SymbolicNode > &node, std::shared_ptr< const SymbolicNode > &coeff, FunctionNode::FuncType &func_type, std::shared_ptr< const SymbolicNode > &argument)
从 a*sin^2(f) 或 a*cos^2(f) 提取系数和三角平方项。
static bool tf_is_trig_squared(const std::shared_ptr< const SymbolicNode > &node, FunctionNode::FuncType &func_type, std::shared_ptr< const SymbolicNode > &argument)
匹配 sin^2(f) 或 cos^2(f),提取函数类型和参数。
std::shared_ptr< const SymbolicNode > coefficient