LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
normalization_structural.cpp
浏览该文件的文档.
4
5#include <cstdint>
6
7namespace LMCAS {
8
9std::shared_ptr<const SymbolicNode> NormalizationVisitor::normalize_bound_body(
10 const SymbolicNode& node) {
11 const auto binder = detail::binder_view(node);
12 if (&facts_ == &detail::no_facts()) {
13 binder->scoped_body->accept(*this);
14 return result;
15 }
16 const detail::ScopedFacts scoped(facts_, binder->bound_name);
18 binder->scoped_body->accept(inner);
19 return inner.get_result();
20}
21
23 std::size_t nodes = 1;
24 if (std::holds_alternative<MatrixNode::DenseStorage>(node.storage())) {
25 auto& dense = std::get<MatrixNode::DenseStorage>(node.storage());
27 for(auto& item : dense) {
28 if(item) {
29 item->accept(*this);
30 normalization_append(rewrite_budget(), nodes, new_dense, result);
31 } else {
32 normalization_append(rewrite_budget(), nodes, new_dense, nullptr);
33 }
34 }
35 set_result(LMCAS::detail::make_node<MatrixNode>(node.rows(), node.cols(), new_dense));
36 } else {
37 auto& sparse = std::get<MatrixNode::SparseStorage>(node.storage());
39 for(auto& [idx, item] : sparse) {
40 item->accept(*this);
41 if (!result->is_zero()) {
42 if (rewrite_budget()) {
43 nodes = rewrite_budget()->append_size(nodes, rewrite_budget()->measure(result));
44 }
45 new_sparse[idx] = result;
46 }
47 }
48 set_result(LMCAS::detail::make_node<MatrixNode>(node.rows(), node.cols(), new_sparse));
49 }
50 }
52
53 std::shared_ptr<const SymbolicNode> new_left = nullptr;
54 std::shared_ptr<const SymbolicNode> new_right = nullptr;
55
56 if (node.left()) {
57 node.left()->accept(*this);
58 new_left = result;
59 }
60 if (node.right()) {
61
62 node.right()->accept(*this);
63 new_right = result;
64 }
65
66 if (!new_left) new_left = node.left();
67 if (!new_right) new_right = node.right();
68
69 normalization_check_children(rewrite_budget(), 1, new_left, new_right);
70 set_result(LMCAS::detail::make_node<RelationalNode>(new_left, new_right, node.op()));
71 }
73 /// Implication: A ⇒ B = ¬A ∨ B
74 if (node.op() == LogicalNode::Op::Implies) {
76 auto not_left = LMCAS::detail::make_node<LogicalNode>(node.left(), nullptr, LogicalNode::Op::Not);
77 normalization_check_children(rewrite_budget(), 1, not_left, node.right());
78 auto or_node = LMCAS::detail::make_node<LogicalNode>(not_left, node.right(), LogicalNode::Op::Or);
79 or_node->accept(*this);
80 return;
81 }
82
83 /// NOT handling: De Morgan's laws and double negation
84 if (node.op() == LogicalNode::Op::Not) {
85 /// Normalize the operand first
86 std::shared_ptr<const SymbolicNode> new_left = nullptr;
87 if (node.left()) {
88 node.left()->accept(*this);
89 new_left = result;
90 }
91 if (!new_left) new_left = node.left();
92
93 /// Double negation: ¬(¬A) = A
94 if (auto inner_logical = std::dynamic_pointer_cast<const LogicalNode>(new_left)) {
95 if (inner_logical->op() == LogicalNode::Op::Not) {
96 set_result(inner_logical->left());
97 return;
98 }
99 /// De Morgan's law: ¬(A∧B) = ¬A∨¬B
100 if (inner_logical->op() == LogicalNode::Op::And) {
101 normalization_check_children(rewrite_budget(), 1, inner_logical->left());
102 auto not_a = LMCAS::detail::make_node<LogicalNode>(inner_logical->left(), nullptr, LogicalNode::Op::Not);
103 normalization_check_children(rewrite_budget(), 1, inner_logical->right());
104 auto not_b = LMCAS::detail::make_node<LogicalNode>(inner_logical->right(), nullptr, LogicalNode::Op::Not);
107 or_node->accept(*this);
108 return;
109 }
110 /// De Morgan's law: ¬(A∨B) = ¬A∧¬B
111 if (inner_logical->op() == LogicalNode::Op::Or) {
112 normalization_check_children(rewrite_budget(), 1, inner_logical->left());
113 auto not_a = LMCAS::detail::make_node<LogicalNode>(inner_logical->left(), nullptr, LogicalNode::Op::Not);
114 normalization_check_children(rewrite_budget(), 1, inner_logical->right());
115 auto not_b = LMCAS::detail::make_node<LogicalNode>(inner_logical->right(), nullptr, LogicalNode::Op::Not);
117 auto and_node = LMCAS::detail::make_node<LogicalNode>(not_a, not_b, LogicalNode::Op::And);
118 and_node->accept(*this);
119 return;
120 }
121 }
122
125 return;
126 }
127
128 /// And / Or: normalize operands
129 std::shared_ptr<const SymbolicNode> new_left = nullptr;
130 std::shared_ptr<const SymbolicNode> new_right = nullptr;
131
132 if (node.left()) {
133 node.left()->accept(*this);
134 new_left = result;
135 }
136 if (node.right()) {
137 node.right()->accept(*this);
138 new_right = result;
139 }
140
141 if (!new_left) new_left = node.left();
142 if (!new_right) new_right = node.right();
143
144 normalization_check_children(rewrite_budget(), 1, new_left, new_right);
145 set_result(LMCAS::detail::make_node<LogicalNode>(new_left, new_right, node.op()));
146 }
148 std::vector<PiecewiseNode::Branch> new_branches;
149 std::size_t nodes = 1;
150 normalization_check_count(rewrite_budget(), node.branches().size(), 2);
151 new_branches.reserve(node.branches().size());
152
153 for (const auto& b : node.branches()) {
154 /// Normalize expression
155 b.expression->accept(*this);
156 auto new_expr = result;
157
158 /// Normalize condition
159 b.condition->accept(*this);
160 auto new_cond = result;
161
162 if (rewrite_budget()) {
163 nodes = rewrite_budget()->append_size(nodes, rewrite_budget()->measure(new_expr));
164 nodes = rewrite_budget()->append_size(nodes, rewrite_budget()->measure(new_cond));
165 }
166 new_branches.push_back({new_expr, new_cond});
167 }
168
169 std::shared_ptr<const SymbolicNode> new_default = nullptr;
170 if (node.default_expr()) {
171 node.default_expr()->accept(*this);
172 new_default = result;
173 if (rewrite_budget()) {
174 (void)rewrite_budget()->append_size(nodes, rewrite_budget()->measure(new_default));
175 }
176 }
177
178 set_result(LMCAS::detail::make_node<PiecewiseNode>(std::move(new_branches), new_default));
179 }
181 auto new_body = normalize_bound_body(node);
182
183 node.lower_bound()->accept(*this);
184 auto new_lower = result;
185
186 node.upper_bound()->accept(*this);
187 auto new_upper = result;
188
189 /// 当上下界均为具体整数且范围较小时,展开求和为显式和。
190 auto lo_n = std::dynamic_pointer_cast<const NumberNode>(new_lower);
191 auto hi_n = std::dynamic_pointer_cast<const NumberNode>(new_upper);
192 BigInt lo;
193 BigInt hi;
194 if (try_get_integer_value(lo_n, lo) && try_get_integer_value(hi_n, hi)) {
195 if (hi < lo) {
197 return;
198 }
199 const BigInt span = hi - lo;
200 if (span < BigInt(1000)) {
201 const auto count = span.try_to_uint64();
202 std::vector<std::shared_ptr<const SymbolicNode>> terms;
203 std::size_t nodes = 0;
204 normalization_check_count(rewrite_budget(), static_cast<std::size_t>(*count) + 1, 1, false);
205 terms.reserve(static_cast<std::size_t>(*count) + 1);
206 BigInt index = lo;
207 for (std::uint64_t offset = 0; offset <= *count; ++offset, index += BigInt(1)) {
208 auto kval = LMCAS::detail::make_node<NumberNode>(index);
209 auto term = norm_subst_index(new_body, node.index_var(), kval, rewrite_budget());
212 term->accept(inner);
213 normalization_append(rewrite_budget(), nodes, terms, inner.get_result());
214 }
215 if (terms.empty()) { set_result(LMCAS::detail::make_node<NumberNode>(BigInt(0))); return; }
217 auto sum_node = LMCAS::detail::make_node<AddNode>(terms);
218 sum_node->accept(*this);
219 return;
220 }
221 }
222
223 normalization_check_children(rewrite_budget(), 1, new_body, new_lower, new_upper);
224 set_result(LMCAS::detail::make_node<SummationNode>(new_body, node.index_var(), new_lower, new_upper));
225 }
227 auto new_body = normalize_bound_body(node);
228
229 node.lower_bound()->accept(*this);
230 auto new_lower = result;
231
232 node.upper_bound()->accept(*this);
233 auto new_upper = result;
234
235 auto lo_n = std::dynamic_pointer_cast<const NumberNode>(new_lower);
236 auto hi_n = std::dynamic_pointer_cast<const NumberNode>(new_upper);
237 BigInt lo;
238 BigInt hi;
239 if (try_get_integer_value(lo_n, lo) && try_get_integer_value(hi_n, hi)) {
240 if (hi < lo) {
242 return;
243 }
244 const BigInt span = hi - lo;
245 if (span < BigInt(1000)) {
246 const auto count = span.try_to_uint64();
247 std::vector<std::shared_ptr<const SymbolicNode>> factors;
248 std::size_t nodes = 0;
249 normalization_check_count(rewrite_budget(), static_cast<std::size_t>(*count) + 1, 1, false);
250 factors.reserve(static_cast<std::size_t>(*count) + 1);
251 BigInt index = lo;
252 for (std::uint64_t offset = 0; offset <= *count; ++offset, index += BigInt(1)) {
253 auto kval = LMCAS::detail::make_node<NumberNode>(index);
254 auto term = norm_subst_index(new_body, node.index_var(), kval, rewrite_budget());
257 term->accept(inner);
258 normalization_append(rewrite_budget(), nodes, factors, inner.get_result());
259 }
260 if (factors.empty()) { set_result(LMCAS::detail::make_node<NumberNode>(BigInt(1))); return; }
261 auto prod_node = make_normalized_multiply_node(factors, rewrite_budget());
262 prod_node->accept(*this);
263 return;
264 }
265 }
266
267 normalization_check_children(rewrite_budget(), 1, new_body, new_lower, new_upper);
268 set_result(LMCAS::detail::make_node<ProductNode>(new_body, node.index_var(), new_lower, new_upper));
269 }
271 auto new_body = normalize_bound_body(node);
272 node.target()->accept(*this);
273 auto new_target = result;
274 normalization_check_children(rewrite_budget(), 1, new_body, new_target);
276 node.transform_type(), new_body, node.source_var(), new_target));
277 }
279 node.domain()->accept(*this);
280 auto new_domain = result;
281
282 auto new_predicate = normalize_bound_body(node);
283
284 /// Simplify ∀x∈S: true → true
285 if (node.quantifier_type() == QuantifierNode::Type::ForAll) {
286 if (new_predicate->is_one()) {
288 return;
289 }
290 }
291
292 /// Simplify ∃x∈S: false → false
293 if (node.quantifier_type() == QuantifierNode::Type::Exists) {
294 if (new_predicate->is_zero()) {
296 return;
297 }
298 }
299
300 normalization_check_children(rewrite_budget(), 1, new_domain, new_predicate);
301 set_result(LMCAS::detail::make_node<QuantifierNode>(node.quantifier_type(), node.bound_var(), new_domain, new_predicate));
302 }
304 node.domain()->accept(*this);
305 auto new_domain = result;
306
307 auto new_predicate = normalize_bound_body(node);
308
309 normalization_check_children(rewrite_budget(), 1, new_domain, new_predicate);
310 set_result(LMCAS::detail::make_node<SetBuilderNode>(node.element_var(), new_domain, new_predicate));
311 }
312
314 std::vector<std::shared_ptr<const SymbolicNode>> elements;
315 std::size_t nodes = 1;
316 normalization_check_count(rewrite_budget(), node.elements().size());
317 elements.reserve(node.elements().size());
318 for (const auto& element : node.elements()) {
319 element->accept(*this);
320 normalization_append(rewrite_budget(), nodes, elements, result);
321 }
323}
324
326 node.lower()->accept(*this);
327 auto lower = result;
328 node.upper()->accept(*this);
331 lower, result, node.lower_closed(), node.upper_closed()));
332}
333
335 node.element()->accept(*this);
336 auto element = result;
337 node.set()->accept(*this);
338 auto set = result;
339 if (auto finite = std::dynamic_pointer_cast<const FiniteSetNode>(set)) {
341 BigInt(finite->contains(*element) ? 1 : 0)));
342 return;
343 }
346}
347
349 node.value()->accept(*this);
352 result, node.dimension(), node.scale_to_base(), node.display_unit()));
353}
354
356 auto body = normalize_bound_body(node);
357 std::shared_ptr<const SymbolicNode> lower;
358 std::shared_ptr<const SymbolicNode> upper;
359 if (node.lower()) {
360 node.lower()->accept(*this);
361 lower = result;
362 node.upper()->accept(*this);
363 upper = result;
364 }
367 std::move(body), node.variable(), std::move(lower), std::move(upper)));
368}
369
371 auto body = normalize_bound_body(node);
372 node.point()->accept(*this);
375 body, node.variable(), result, node.direction()));
376}
377
380 set_result(node.clone());
381}
382
383} // namespace LMCAS
@ Not
一元逻辑非,right 为 nullptr。
@ Implies
逻辑蕴含 A ⇒ B。
矩阵节点,支持稠密和稀疏两种存储方式。
std::map< size_t, std::shared_ptr< const SymbolicNode > > SparseStorage
稀疏存储,索引映射到节点。
std::vector< std::shared_ptr< const SymbolicNode > > DenseStorage
稠密存储,按行优先展开。
void visit(const NumberNode &node) override
NormalizationVisitor(detail::RewriteBudget &budget, const FactsQuery &facts, Domain domain)
void set_result(std::shared_ptr< const SymbolicNode > candidate)
std::shared_ptr< const SymbolicNode > result
std::shared_ptr< const SymbolicNode > get_result() const
std::shared_ptr< const SymbolicNode > normalize_bound_body(const SymbolicNode &node)
分段函数节点,表示条件分支表达式.
连乘节点,表示符号有限/无限连乘 prod_{k=a}^{b} f(k).
@ Exists
存在量词 exists。
定义 sets.hpp:9
@ ForAll
全称量词 forall。
定义 sets.hpp:8
求和节点,表示符号有限/无限求和 sum_{k=a}^{b} f(k).
积分变换节点,表示 Laplace,Fourier,Z 变换及其逆变换.
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
std::optional< BinderView > binder_view(const SymbolicNode &node)
const FactsQuery & no_facts() noexcept
std::shared_ptr< const Node > make_node(Args &&... args)
const ExprPtr & element
__attribute__((visibility("default"))) ExprResult function(const std __attribute__((visibility("default"))) ExprResult finite_set(std ExprPtr upper
bool try_get_integer_value(const std::shared_ptr< const NumberNode > &node, BigInt &value)
const ExprPtr & lower
const ExprPtr & set
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)
std::shared_ptr< const SymbolicNode > norm_subst_index(const std::shared_ptr< const SymbolicNode > &node, const std::string &index_var, const std::shared_ptr< const SymbolicNode > &value, detail::RewriteBudget *budget=nullptr)
const MultiPoly & b
void normalization_check_children(detail::RewriteBudget *budget, std::size_t roots, const std::shared_ptr< const Nodes > &... children)
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)
符号规范化访问器接口。