LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
normalization_arithmetic.cpp
浏览该文件的文档.
3
4namespace LMCAS {
5namespace {
6bool sum_term_less(const std::shared_ptr<const SymbolicNode>& left,
7 const std::shared_ptr<const SymbolicNode>& right) {
8 const BigInt a = get_node_degree_helper(left);
9 const BigInt b = get_node_degree_helper(right);
10 if (a != b) {
11 return a > b;
12 }
13 const bool left_number = std::dynamic_pointer_cast<const NumberNode>(left) != nullptr;
14 const bool right_number = std::dynamic_pointer_cast<const NumberNode>(right) != nullptr;
15 if (left_number != right_number) {
16 return right_number;
17 }
18 return left->compare(*right) < 0;
19}
20
21std::shared_ptr<const SymbolicNode> weighted_term(
22 const std::shared_ptr<const SymbolicNode>& term,
23 const std::shared_ptr<const NumberNode>& coefficient, detail::RewriteBudget* budget) {
24 if (coefficient->is_one()) {
25 return term;
26 }
27 std::vector<std::shared_ptr<const SymbolicNode>> operands;
28 std::size_t nodes = 0;
29 normalization_append(budget, nodes, operands, coefficient);
30 if (const auto multiply = std::dynamic_pointer_cast<const MultiplyNode>(term)) {
31 for (const auto& child : multiply->operands()) {
32 normalization_append(budget, nodes, operands, child);
33 }
34 } else {
35 normalization_append(budget, nodes, operands, term);
36 }
37 return make_normalized_multiply_node(operands, budget);
38}
39}
40
41std::shared_ptr<const SymbolicNode> NormalizationVisitor::get_result() const {
42 return result;
43}
44
45void NormalizationVisitor::set_result(std::shared_ptr<const SymbolicNode> candidate) {
46 if (auto* budget = rewrite_budget()) {
47 budget->measure_result(candidate);
48 }
49 result.swap(candidate);
50}
51
54 set_result(node.clone());
55}
56
59 set_result(node.clone());
60}
61
63 node.real()->accept(*this);
64 auto real = result;
65 node.imag()->accept(*this);
68}
69
71 std::vector<std::shared_ptr<const SymbolicNode>>& operands) {
72 std::vector<std::shared_ptr<const SymbolicNode>> real;
73 std::vector<std::shared_ptr<const SymbolicNode>> imag;
74 std::vector<std::shared_ptr<const SymbolicNode>> remaining;
75 std::size_t real_nodes = 0, imag_nodes = 0, remaining_nodes = 0;
76 bool has_complex = false;
77 for (const auto& operand : operands) {
78 if (const auto complex = std::dynamic_pointer_cast<const ComplexNode>(operand)) {
79 has_complex = true;
80 normalization_append(rewrite_budget(), real_nodes, real, complex->real());
81 normalization_append(rewrite_budget(), imag_nodes, imag, complex->imag());
82 } else if (std::dynamic_pointer_cast<const NumberNode>(operand)) {
83 normalization_append(rewrite_budget(), real_nodes, real, operand);
86 } else {
87 normalization_append(rewrite_budget(), remaining_nodes, remaining, operand);
88 }
89 }
90 if (!has_complex) {
91 return;
92 }
96 real_sum->accept(visitor);
97 auto normalized_real = visitor.get_result();
98 imag_sum->accept(visitor);
99 normalization_check_children(rewrite_budget(), 1, normalized_real, visitor.get_result());
100 auto merged = SymbolicFactory::create_complex(normalized_real, visitor.get_result());
101 if (!merged->is_zero()) {
102 normalization_append(rewrite_budget(), remaining_nodes, remaining, merged);
103 }
104 operands = std::move(remaining);
105}
106
107std::shared_ptr<const NumberNode> NormalizationVisitor::extract_term_coefficient(
108 std::shared_ptr<const SymbolicNode>& term) {
109 auto coefficient = detail::make_node<NumberNode>(BigInt(1));
110 const auto multiply = std::dynamic_pointer_cast<const MultiplyNode>(term);
111 if (!multiply || multiply->operands().empty()) {
112 return coefficient;
113 }
114 const auto& operands = multiply->operands();
115 auto number = std::dynamic_pointer_cast<const NumberNode>(operands.front());
116 std::size_t index = 0;
117 if (!number) {
118 number = std::dynamic_pointer_cast<const NumberNode>(operands.back());
119 index = operands.size() - 1;
120 }
121 if (!number) {
122 return coefficient;
123 }
124 coefficient = number;
125 if (operands.size() == 2) {
126 term = operands[index == 0 ? 1 : 0];
127 return coefficient;
128 }
129 std::vector<std::shared_ptr<const SymbolicNode>> rest;
130 std::size_t nodes = 0;
131 normalization_check_count(rewrite_budget(), operands.size() - 1, 1, false);
132 rest.reserve(operands.size() - 1);
133 for (std::size_t k = 0; k < operands.size(); ++k) {
134 if (k != index) {
135 normalization_append(rewrite_budget(), nodes, rest, operands[k]);
136 }
137 }
138 auto rest_product = make_normalized_multiply_node(rest, rewrite_budget());
140 rest_product->accept(visitor);
141 term = visitor.get_result();
142 return coefficient;
143}
144
145std::shared_ptr<const SymbolicNode> NormalizationVisitor::collect_sum(
146 const std::vector<std::shared_ptr<const SymbolicNode>>& operands) {
147 auto constant = detail::make_node<NumberNode>(BigInt(0));
148 struct TermAccum {
149 std::shared_ptr<const NumberNode> coefficient;
150 std::vector<std::shared_ptr<const SymbolicNode>> originals;
151 std::size_t nodes;
152 };
153 std::map<std::shared_ptr<const SymbolicNode>, TermAccum, NodeCompare> terms;
154 for (const auto& operand : operands) {
155 if (const auto number = std::dynamic_pointer_cast<const NumberNode>(operand)) {
156 constant = add_numbers(constant, number);
157 continue;
158 }
159 auto term = operand;
160 auto coefficient = extract_term_coefficient(term);
161 auto found = terms.find(term);
162 if (found == terms.end()) {
163 const auto nodes = rewrite_budget() ? rewrite_budget()->measure(operand) : 0;
164 terms.emplace(term, TermAccum{coefficient, {operand}, nodes});
165 } else {
166 found->second.coefficient = add_numbers(found->second.coefficient, coefficient);
167 normalization_append(rewrite_budget(), found->second.nodes, found->second.originals, operand);
168 }
169 }
170 std::vector<std::shared_ptr<const SymbolicNode>> collected;
171 std::size_t nodes = 0;
172 if (!constant->is_zero()) {
173 normalization_append(rewrite_budget(), nodes, collected, constant);
174 }
175 for (const auto& [term, accumulated] : terms) {
176 if (!accumulated.coefficient->is_zero()) {
177 normalization_append(rewrite_budget(), nodes, collected,
178 weighted_term(term, accumulated.coefficient, rewrite_budget()));
179 } else if (!normalization_can_discard(term, facts_, domain_, context_)) {
180 for (const auto& original : accumulated.originals) {
181 normalization_append(rewrite_budget(), nodes, collected, original);
182 }
183 }
184 }
185 if (collected.empty()) {
186 return detail::make_node<NumberNode>(BigInt(0));
187 }
188 if (collected.size() == 1) {
189 return collected.front();
190 }
192 std::sort(collected.begin(), collected.end(), sum_term_less);
193 return detail::make_node<AddNode>(collected);
194}
195
197 std::vector<std::shared_ptr<const SymbolicNode>> operands;
198 std::size_t nodes = 0;
199 for (const auto& operand : node.operands()) {
200 operand->accept(*this);
201 if (const auto add = std::dynamic_pointer_cast<const AddNode>(result)) {
202 for (const auto& child : add->operands()) {
203 normalization_append(rewrite_budget(), nodes, operands, child);
204 }
205 } else {
206 normalization_append(rewrite_budget(), nodes, operands, result);
207 }
208 }
209 merge_complex_terms(operands);
210 if (normalize_matrix_sum(operands)) {
211 return;
212 }
213 set_result(collect_sum(operands));
214}
215}
加法节点,表示多个操作数的求和。
复数节点,表示 real + imag * i。
void visit(const NumberNode &node) override
std::shared_ptr< const NumberNode > extract_term_coefficient(std::shared_ptr< const SymbolicNode > &term)
NormalizationVisitor(detail::RewriteBudget &budget, const FactsQuery &facts, Domain domain)
void set_result(std::shared_ptr< const SymbolicNode > candidate)
std::shared_ptr< const SymbolicNode > collect_sum(const std::vector< std::shared_ptr< const SymbolicNode > > &operands)
std::shared_ptr< const SymbolicNode > result
bool normalize_matrix_sum(const std::vector< std::shared_ptr< const SymbolicNode > > &operands)
void merge_complex_terms(std::vector< std::shared_ptr< const SymbolicNode > > &operands)
std::shared_ptr< const SymbolicNode > get_result() const
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_complex(std::shared_ptr< const SymbolicNode > real, std::shared_ptr< const SymbolicNode > imag)
创建复数节点,自动简化(若虚部为 0,则返回实部).
static std::shared_ptr< const SymbolicNode > create_number(const ::LMCAS::BigInt &v)
变量节点,表示一个符号变量。
std::size_t measure(const std::shared_ptr< const SymbolicNode > &node)
void require_nodes(std::size_t nodes) const
std::size_t measure_result(const std::shared_ptr< const SymbolicNode > &node)
RewriteBudget * rewrite_budget() const noexcept
bool sum_term_less(const std::shared_ptr< const SymbolicNode > &left, const std::shared_ptr< const SymbolicNode > &right)
std::shared_ptr< const SymbolicNode > weighted_term(const std::shared_ptr< const SymbolicNode > &term, const std::shared_ptr< const NumberNode > &coefficient, detail::RewriteBudget *budget)
std::shared_ptr< const Node > make_node(Args &&... args)
std::shared_ptr< const NumberNode > add_numbers(const std::shared_ptr< const NumberNode > &left, const std::shared_ptr< const NumberNode > &right)
两个数值节点相加
ExprResult real(const ExprPtr &expression, ComputationContext &context)
bool normalization_can_discard(const std::shared_ptr< const SymbolicNode > &node, const FactsQuery &facts, Domain domain, ComputationContext &context)
std::size_t normalization_check_arithmetic(detail::RewriteBudget *budget, std::size_t extra_nodes, const std::shared_ptr< const Nodes > &... children)
ExprResult add(const ExprPtr &lhs, const ExprPtr &rhs, ComputationContext &context)
std::size_t normalization_check_count(detail::RewriteBudget *budget, std::size_t rows, std::size_t cols=1, bool wrapped=true)
const MultiPoly & b
ExprResult complex(ExprPtr real, ExprPtr imag)
__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
void normalization_check_children(detail::RewriteBudget *budget, std::size_t roots, const std::shared_ptr< const Nodes > &... children)
ExprPtr imag
const ExprPtr & right
BigInt get_node_degree_helper(const std::shared_ptr< const SymbolicNode > &node)
计算 AST 节点的多项式次数
std::shared_ptr< const SymbolicNode > make_normalized_multiply_node(const std::vector< std::shared_ptr< const SymbolicNode > > &operands, detail::RewriteBudget *budget=nullptr)
void normalization_append(detail::RewriteBudget *budget, std::size_t &nodes, std::vector< std::shared_ptr< const SymbolicNode > > &children, std::shared_ptr< const SymbolicNode > child)
符号规范化访问器接口。