LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
normalization_products.cpp
浏览该文件的文档.
3
4namespace LMCAS {
5namespace {
6struct FactorAccum {
7 std::shared_ptr<const NumberNode> exponent;
8 std::vector<std::shared_ptr<const SymbolicNode>> originals;
9 std::size_t nodes;
10};
11
12std::shared_ptr<const NumberNode> collectable_power_exponent(
13 const std::shared_ptr<const SymbolicNode>& factor,
14 std::shared_ptr<const SymbolicNode>& base, const FactsQuery& facts, Domain domain,
17 const auto power = std::dynamic_pointer_cast<const PowerNode>(factor);
18 if (!power) { return exponent; }
19 const auto numeric = std::dynamic_pointer_cast<const NumberNode>(power->exponent());
20 BigInt integer;
21 if (!try_get_integer_value(numeric, integer)) { return exponent; }
22 if (integer <= BigInt(0) &&
23 !(normalization_can_discard(power->base(), facts, domain, context) &&
25 return exponent;
26 }
27 base = power->base();
29}
30
32public:
33 bool add_number(const std::shared_ptr<const SymbolicNode>& factor) {
34 const auto number = std::dynamic_pointer_cast<const NumberNode>(factor);
35 if (!number) {
36 return false;
37 }
39 return true;
40 }
41
42 void add_base(const std::shared_ptr<const SymbolicNode>& factor,
43 const std::shared_ptr<const SymbolicNode>& base,
44 const std::shared_ptr<const NumberNode>& exponent, detail::RewriteBudget* budget) {
45 auto it = bases_.find(base);
46 if (it == bases_.end()) {
47 const auto nodes = budget ? budget->measure(factor) : 0;
48 bases_.emplace(base, FactorAccum{exponent, {factor}, nodes});
49 } else {
50 it->second.exponent = add_numbers(it->second.exponent, exponent);
51 normalization_append(budget, it->second.nodes, it->second.originals, factor);
52 }
53 }
54
55 std::shared_ptr<const SymbolicNode> finish(
56 const FactsQuery& facts, Domain domain, ComputationContext& context, bool expanding,
57 detail::RewriteBudget* budget) const {
58 if (budget) { budget->require_nodes(1); }
59 if (constant_->is_zero() && factors_defined(facts, domain, context)) { return constant_; }
60 std::vector<std::shared_ptr<const SymbolicNode>> operands;
61 std::size_t nodes = 0;
62 if (!constant_->is_one()) {
63 normalization_append(budget, nodes, operands, constant_);
64 }
65 std::vector<std::shared_ptr<const SymbolicNode>> variables;
66 std::size_t variable_nodes = 0;
67 collect_variables(facts, domain, budget, variables, variable_nodes, context);
68 std::sort(variables.begin(), variables.end(), normalization_factor_less);
69 if (budget) {
70 (void)budget->append_size(nodes, variable_nodes);
71 }
72 operands.insert(operands.end(), variables.begin(), variables.end());
73 if (expanding && operands.size() > 1 &&
74 std::dynamic_pointer_cast<const NumberNode>(operands.back())) {
75 std::rotate(operands.begin(), operands.end() - 1, operands.end());
76 }
77 return make_normalized_multiply_node(operands, budget);
78 }
79
80private:
83 std::vector<std::shared_ptr<const SymbolicNode>>& variables,
84 std::size_t& nodes, ComputationContext& context) const {
85 for (const auto& [base, accumulated] : bases_) {
86 const auto& exponent = accumulated.exponent;
87 if (exponent->is_zero()) {
88 if (normalization_can_discard(base, facts, domain, context) &&
90 continue;
91 }
92 for (const auto& original : accumulated.originals) {
93 normalization_append(budget, nodes, variables, original);
94 }
95 } else if (exponent->is_one()) {
96 normalization_append(budget, nodes, variables, base);
97 } else {
98 normalization_check_children(budget, 1, base, exponent);
99 normalization_append(budget, nodes, variables,
101 }
102 }
103 }
104
106 for (const auto& [base, accumulated] : bases_) {
107 for (const auto& original : accumulated.originals) {
108 if (!normalization_can_discard(original, facts, domain, context)) { return false; }
109 }
110 }
111 return true;
112 }
113
114 std::shared_ptr<const NumberNode> constant_ = detail::make_node<NumberNode>(BigInt(1));
115 std::map<std::shared_ptr<const SymbolicNode>, FactorAccum, NodeCompare> bases_;
116};
117
118bool has_matrix_factor(const std::vector<std::shared_ptr<const SymbolicNode>>& operands) {
119 for (const auto& operand : operands) {
120 if (std::dynamic_pointer_cast<const MatrixNode>(operand)) {
121 return true;
122 }
123 const auto power = std::dynamic_pointer_cast<const PowerNode>(operand);
124 if (power && std::dynamic_pointer_cast<const MatrixNode>(power->base())) {
125 return true;
126 }
127 }
128 return false;
129}
130}
131
132std::shared_ptr<const SymbolicNode> NormalizationVisitor::collect_product(
133 const std::vector<std::shared_ptr<const SymbolicNode>>& operands) {
134 ProductAccumulator accumulated;
135 for (const auto& operand : operands) {
136 if (accumulated.add_number(operand)) {
137 continue;
138 }
139 auto base = operand;
140 auto exponent = collectable_power_exponent(operand, base, facts_, domain_, context_);
141 if (base == operand) {
142 const auto power = std::dynamic_pointer_cast<const PowerNode>(operand);
143 if (power && can_combine_nested_power(*power, exponent)) {
144 base = power->base();
145 exponent = std::dynamic_pointer_cast<const NumberNode>(power->exponent());
146 }
147 }
148 accumulated.add_base(operand, base, exponent, rewrite_budget());
149 }
150 return accumulated.finish(facts_, domain_, context_, false, rewrite_budget());
151}
152
154 std::vector<std::shared_ptr<const SymbolicNode>> operands;
155 std::size_t nodes = 0;
156 for (const auto& operand : node.operands()) {
157 operand->accept(*this);
158 if (const auto multiply = std::dynamic_pointer_cast<const MultiplyNode>(result)) {
159 for (const auto& child : multiply->operands()) {
160 normalization_append(rewrite_budget(), nodes, operands, child);
161 }
162 } else {
163 normalization_append(rewrite_budget(), nodes, operands, result);
164 }
165 }
166 if (has_matrix_factor(operands)) {
168 return;
169 }
170 set_result(collect_product(operands));
171}
172
173std::shared_ptr<const SymbolicNode> NormalizationVisitor::expand_complex_product(
174 const std::shared_ptr<const SymbolicNode>& lhs,
175 const std::shared_ptr<const SymbolicNode>& rhs) {
176 const auto left = std::dynamic_pointer_cast<const ComplexNode>(lhs);
177 const auto right = std::dynamic_pointer_cast<const ComplexNode>(rhs);
178 if (!left && !right) {
179 return nullptr;
180 }
181 std::shared_ptr<const SymbolicNode> real;
182 std::shared_ptr<const SymbolicNode> imag;
183 if (left && right) {
184 auto ac = expand_product(left->real(), right->real());
185 auto bd = expand_product(left->imag(), right->imag());
186 auto ad = expand_product(left->real(), right->imag());
187 auto bc = expand_product(left->imag(), right->real());
188 auto negative_bd = expand_product(detail::make_node<NumberNode>(BigInt(-1)), bd);
189 real = SymbolicFactory::create_add({ac, negative_bd}, rewrite_budget());
191 } else if (left) {
192 real = expand_product(left->real(), rhs);
193 imag = expand_product(left->imag(), rhs);
194 } else {
195 real = expand_product(lhs, right->real());
196 imag = expand_product(lhs, right->imag());
197 }
199 real->accept(visitor);
200 auto normalized_real = visitor.get_result();
201 imag->accept(visitor);
202 normalization_check_children(rewrite_budget(), 1, normalized_real, visitor.get_result());
203 return SymbolicFactory::create_complex(normalized_real, visitor.get_result());
204}
205
206std::shared_ptr<const SymbolicNode> NormalizationVisitor::expand_product(
207 const std::shared_ptr<const SymbolicNode>& lhs,
208 const std::shared_ptr<const SymbolicNode>& rhs) {
210 if (auto complex = expand_complex_product(lhs, rhs)) {
211 return complex;
212 }
213 const auto left = std::dynamic_pointer_cast<const AddNode>(lhs);
214 const auto right = std::dynamic_pointer_cast<const AddNode>(rhs);
215 if (left || right) {
216 return distribute_product(lhs, rhs);
217 }
218 return collect_expanded_product(lhs, rhs);
219}
220
221std::shared_ptr<const SymbolicNode> NormalizationVisitor::distribute_product(
222 const std::shared_ptr<const SymbolicNode>& lhs,
223 const std::shared_ptr<const SymbolicNode>& rhs) {
224 const auto left = std::dynamic_pointer_cast<const AddNode>(lhs);
225 const auto right = std::dynamic_pointer_cast<const AddNode>(rhs);
226 std::size_t left_count = 1, right_count = 1;
227 if (left) {
228 left_count = left->operands().size();
229 }
230 if (right) {
231 right_count = right->operands().size();
232 }
233 normalization_check_count(rewrite_budget(), left_count, right_count, false);
234 std::vector<std::shared_ptr<const SymbolicNode>> terms;
235 std::size_t nodes = 0;
236 for (std::size_t i = 0; i < left_count; ++i) {
237 const auto& a = left ? left->operands()[i] : lhs;
238 for (std::size_t j = 0; j < right_count; ++j) {
239 const auto& b = right ? right->operands()[j] : rhs;
241 }
242 }
244 return detail::make_node<AddNode>(terms);
245}
246
247std::shared_ptr<const SymbolicNode> NormalizationVisitor::collect_expanded_product(
248 const std::shared_ptr<const SymbolicNode>& lhs,
249 const std::shared_ptr<const SymbolicNode>& rhs) {
250 ProductAccumulator accumulated;
251 const auto process = [&](const std::shared_ptr<const SymbolicNode>& factor) {
252 if (accumulated.add_number(factor)) {
253 return;
254 }
255 auto base = factor;
256 auto exponent = collectable_power_exponent(factor, base, facts_, domain_, context_);
257 accumulated.add_base(factor, base, exponent, rewrite_budget());
258 };
259 for (const auto* node : {&lhs, &rhs}) {
260 const auto multiply = std::dynamic_pointer_cast<const MultiplyNode>(*node);
261 if (!multiply) {
262 process(*node);
263 continue;
264 }
265 for (const auto& operand : multiply->operands()) {
266 process(operand);
267 }
268 }
269 return accumulated.finish(facts_, domain_, context_, true, rewrite_budget());
270}
271}
乘法节点,表示多个操作数的乘积。
bool can_combine_nested_power(const PowerNode &inner, const std::shared_ptr< const NumberNode > &outer_exponent) const
void visit(const NumberNode &node) override
std::shared_ptr< const SymbolicNode > collect_product(const std::vector< std::shared_ptr< const SymbolicNode > > &operands)
std::shared_ptr< const SymbolicNode > distribute_product(const std::shared_ptr< const SymbolicNode > &lhs, const std::shared_ptr< const SymbolicNode > &rhs)
std::shared_ptr< const SymbolicNode > expand_product(const std::shared_ptr< const SymbolicNode > &lhs, const std::shared_ptr< const SymbolicNode > &rhs)
std::shared_ptr< const SymbolicNode > expand_complex_product(const std::shared_ptr< const SymbolicNode > &lhs, const std::shared_ptr< const SymbolicNode > &rhs)
NormalizationVisitor(detail::RewriteBudget &budget, const FactsQuery &facts, Domain domain)
void set_result(std::shared_ptr< const SymbolicNode > candidate)
std::shared_ptr< const SymbolicNode > collect_expanded_product(const std::shared_ptr< const SymbolicNode > &lhs, const std::shared_ptr< const SymbolicNode > &rhs)
std::shared_ptr< const SymbolicNode > result
std::shared_ptr< const SymbolicNode > normalize_matrix_product(const 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,则返回实部).
void add_base(const std::shared_ptr< const SymbolicNode > &factor, const std::shared_ptr< const SymbolicNode > &base, const std::shared_ptr< const NumberNode > &exponent, detail::RewriteBudget *budget)
void collect_variables(const FactsQuery &facts, Domain domain, detail::RewriteBudget *budget, std::vector< std::shared_ptr< const SymbolicNode > > &variables, std::size_t &nodes, ComputationContext &context) const
std::map< std::shared_ptr< const SymbolicNode >, FactorAccum, NodeCompare > bases_
bool factors_defined(const FactsQuery &facts, Domain domain, ComputationContext &context) const
std::shared_ptr< const SymbolicNode > finish(const FactsQuery &facts, Domain domain, ComputationContext &context, bool expanding, detail::RewriteBudget *budget) const
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)
RewriteBudget * rewrite_budget() const noexcept
bool has_matrix_factor(const std::vector< std::shared_ptr< const SymbolicNode > > &operands)
std::shared_ptr< const NumberNode > collectable_power_exponent(const std::shared_ptr< const SymbolicNode > &factor, std::shared_ptr< const SymbolicNode > &base, const FactsQuery &facts, Domain domain, ComputationContext &context)
Result< Tribool > query_nonzero_value(const Node &node, const FactsQuery &facts, Domain domain, ComputationContext &context)
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)
两个数值节点相加
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
ExprResult integer(Integer)=delete
bool try_get_integer_value(const std::shared_ptr< const NumberNode > &node, BigInt &value)
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)
Domain
Mathematical domain hierarchy (least specific → most specific). Complex ⊃ Real ⊃ Algebraic ⊃ Rational...
@ Complex
Complex numbers (default, least specific)
std::size_t normalization_check_arithmetic(detail::RewriteBudget *budget, std::size_t extra_nodes, const std::shared_ptr< const Nodes > &... children)
std::size_t normalization_check_count(detail::RewriteBudget *budget, std::size_t rows, std::size_t cols=1, bool wrapped=true)
const MultiPoly & b
std::shared_ptr< const NumberNode > multiply_numbers(const std::shared_ptr< const NumberNode > &left, const std::shared_ptr< const NumberNode > &right)
两个数值节点相乘
ExprResult complex(ExprPtr real, ExprPtr imag)
const ExprPtr & exponent
__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)
const NumberDomainSet & domain
ExprPtr imag
const ExprPtr & right
const ExprPtr & rhs
bool normalization_proved(const Result< Tribool > &result)
bool normalization_factor_less(const std::shared_ptr< const SymbolicNode > &left, const std::shared_ptr< const SymbolicNode > &right)
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)
符号规范化访问器接口。