LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
equivalence_trig.cpp
浏览该文件的文档.
2
3#include <utility>
4#include <vector>
5
7namespace {
8
14
15std::optional<TrigSquare> trig_square(
16 const detail::SymbolicNodePtr& node) {
17 auto candidate = node;
18 detail::SymbolicNodePtr coefficient =
20 if (const auto multiply =
21 std::dynamic_pointer_cast<const MultiplyNode>(node);
22 multiply && multiply->operands().size() == 2) {
23 const auto first_number =
24 std::dynamic_pointer_cast<const NumberNode>(
25 multiply->operands()[0]);
26 const auto second_number =
27 std::dynamic_pointer_cast<const NumberNode>(
28 multiply->operands()[1]);
29 if (first_number) {
30 coefficient = first_number;
31 candidate = multiply->operands()[1];
32 } else if (second_number) {
33 coefficient = second_number;
34 candidate = multiply->operands()[0];
35 }
36 }
37 const auto power =
38 std::dynamic_pointer_cast<const PowerNode>(candidate);
39 if (!power || !exact_integer_node(power->exponent(), 2)) {
40 return std::nullopt;
41 }
42 const auto function =
43 std::dynamic_pointer_cast<const FunctionNode>(power->base());
44 if (!function || function->arguments().size() != 1 ||
47 return std::nullopt;
48 }
49 return TrigSquare{
50 function->type(), function->arguments()[0], coefficient};
51}
52
53std::optional<ExprPtr> unwrap_trig_negated_argument(
55 auto multiply = std::dynamic_pointer_cast<const MultiplyNode>(node);
56 if (!multiply) { return std::nullopt; }
57
58 bool found_negative_one = false;
59 std::vector<detail::SymbolicNodePtr> remaining;
60 budget.require_nodes(multiply->operands().size());
61 std::size_t size = 0;
62 remaining.reserve(multiply->operands().size());
63 for (const auto& operand : multiply->operands()) {
64 if (!found_negative_one && exact_integer_node(operand, -1)) {
65 found_negative_one = true;
66 continue;
67 }
68 size = budget.append_size(size, budget.measure(operand));
69 remaining.push_back(operand);
70 }
71 if (!found_negative_one || remaining.empty()) { return std::nullopt; }
72 if (remaining.size() == 1) {
73 return detail::make_expression_ptr(remaining.front());
74 }
76 SymbolicFactory::create_multiply(std::move(remaining), &budget));
77}
78
79std::vector<detail::SymbolicNodePtr> rewrite_operands(
80 const std::vector<detail::SymbolicNodePtr>& operands, detail::RewriteBudget& budget) {
81 std::vector<detail::SymbolicNodePtr> rewritten;
82 budget.require_nodes(operands.size());
83 std::size_t size = 0;
84 rewritten.reserve(operands.size());
85 for (const auto& operand : operands) {
86 auto child = rewrite_trig_basic_identity(operand, budget);
87 size = budget.append_size(size, budget.measure(detail::node(child)));
88 rewritten.push_back(detail::node(child));
89 }
90 return rewritten;
91}
92
93std::optional<std::pair<std::size_t, detail::SymbolicNodePtr>>
95 const std::vector<detail::SymbolicNodePtr>& nodes,
96 const std::vector<bool>& used, std::size_t index) {
97 const auto square = trig_square(nodes[index]);
98 if (!square) { return std::nullopt; }
99 const auto complement =
100 square->type == FunctionNode::FuncType::Sin
103 for (std::size_t other = index + 1; other < nodes.size(); ++other) {
104 if (used[other]) { continue; }
105 const auto candidate = trig_square(nodes[other]);
106 if (candidate && candidate->type == complement &&
107 square->argument->equals(*candidate->argument) &&
108 square->coefficient->equals(*candidate->coefficient)) {
109 return std::pair<std::size_t, detail::SymbolicNodePtr>{
110 other, square->coefficient};
111 }
112 }
113 return std::nullopt;
114}
115
117 auto rewritten = rewrite_operands(add.operands(), budget);
118 std::vector<bool> used(rewritten.size(), false);
119 std::vector<detail::SymbolicNodePtr> result_nodes;
120 std::size_t size = 0;
121 for (std::size_t index = 0; index < rewritten.size(); ++index) {
122 if (used[index]) { continue; }
123 auto partner = complementary_square(rewritten, used, index);
124 if (partner) {
125 used[index] = true;
126 used[partner->first] = true;
127 size = budget.append_size(
128 size, budget.measure(partner->second));
129 result_nodes.push_back(partner->second);
130 } else {
131 size = budget.append_size(size, budget.measure(rewritten[index]));
132 result_nodes.push_back(rewritten[index]);
133 }
134 }
135 if (result_nodes.empty()) {
136 budget.require_nodes(1);
137 return SymbolicExpr::number(0);
138 }
140 SymbolicFactory::create_add(std::move(result_nodes), &budget));
141}
142
144 auto arguments = rewrite_operands(function.arguments(), budget);
145 if (arguments.size() == 1) {
146 auto positive_argument = unwrap_trig_negated_argument(arguments[0], budget);
147 if (positive_argument && *positive_argument) {
149 budget.append_size(3, budget.measure(detail::node(*positive_argument)));
150 return SymbolicExpr::multiply(
151 SymbolicExpr::number(-1),
152 SymbolicExpr::sin(*positive_argument));
153 }
155 budget.append_size(1, budget.measure(detail::node(*positive_argument)));
156 return SymbolicExpr::cos(*positive_argument);
157 }
158 }
159 }
160 normalization_check_children(&budget, 1, arguments);
162 detail::make_node<FunctionNode>(function.type(), std::move(arguments)));
163}
164
165}
166
168 detail::RewriteBudget& budget) {
169 if (!node) { return nullptr; }
170 detail::RewriteScope scope(&budget);
171 if (auto add = std::dynamic_pointer_cast<const AddNode>(node)) {
172 return rewrite_trig_sum(*add, budget);
173 }
174 if (auto multiply = std::dynamic_pointer_cast<const MultiplyNode>(node)) {
176 rewrite_operands(multiply->operands(), budget), &budget));
177 }
178 if (auto power = std::dynamic_pointer_cast<const PowerNode>(node)) {
179 auto base = rewrite_trig_basic_identity(power->base(), budget);
180 auto exponent = rewrite_trig_basic_identity(power->exponent(), budget);
181 budget.append_size(budget.append_size(1, budget.measure(detail::node(base))),
182 budget.measure(detail::node(exponent)));
183 return SymbolicExpr::power(base, exponent);
184 }
185 if (auto function = std::dynamic_pointer_cast<const FunctionNode>(node)) {
186 return rewrite_trig_function(*function, budget);
187 }
188 if (auto complex_node = std::dynamic_pointer_cast<const ComplexNode>(node)) {
189 auto real = rewrite_trig_basic_identity(complex_node->real(), budget);
190 auto imag = rewrite_trig_basic_identity(complex_node->imag(), budget);
191 return rewritten_complex(real, imag, node, budget);
192 }
193 budget.measure(node);
194 return detail::make_expression_ptr(node);
195}
196
197}
加法节点,表示多个操作数的求和。
函数节点,表示数学函数调用(三角函数、对数、特殊函数等)。
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::optional< std::pair< std::size_t, detail::SymbolicNodePtr > > complementary_square(const std::vector< detail::SymbolicNodePtr > &nodes, const std::vector< bool > &used, std::size_t index)
std::optional< TrigSquare > trig_square(const detail::SymbolicNodePtr &node)
std::vector< detail::SymbolicNodePtr > rewrite_operands(const std::vector< detail::SymbolicNodePtr > &operands, detail::RewriteBudget &budget)
ExprPtr rewrite_trig_sum(const AddNode &add, detail::RewriteBudget &budget)
std::optional< ExprPtr > unwrap_trig_negated_argument(const detail::SymbolicNodePtr &node, detail::RewriteBudget &budget)
ExprPtr rewrite_trig_function(const FunctionNode &function, detail::RewriteBudget &budget)
ExprPtr rewrite_trig_basic_identity(const detail::SymbolicNodePtr &node, detail::RewriteBudget &budget)
bool exact_integer_node(const std::shared_ptr< const SymbolicNode > &node, int expected)
ExprPtr rewritten_complex(const ExprPtr &real, const ExprPtr &imag, const detail::SymbolicNodePtr &original, detail::RewriteBudget &budget)
ExprResult real(const ExprPtr &expression, ComputationContext &context)
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)