LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
relation_store.cpp
浏览该文件的文档.
1#include "relation_store.hpp"
4#include "property_store.hpp"
5#include <algorithm>
6#include <queue>
7
8namespace LMCAS {
9
10RelationStore::RelationStore(RelationStore&& other) noexcept
11 : relations_(std::move(other.relations_)), proofs_(std::move(other.proofs_)),
12 declaration_order_(std::move(other.declaration_order_)) {
13 other.relations_.clear();
14 other.proofs_.clear();
15 other.declaration_order_.clear();
16 ++other.revision_;
17}
18
19RelationStore& RelationStore::operator=(const RelationStore& other) {
20 if (this != &other) {
21 RelationStore candidate(other);
22 relations_.swap(candidate.relations_);
23 proofs_.swap(candidate.proofs_);
24 declaration_order_.swap(candidate.declaration_order_);
25 ++revision_;
26 }
27 return *this;
28}
29
30RelationStore& RelationStore::operator=(RelationStore&& other) noexcept {
31 if (this != &other) {
32 relations_ = std::move(other.relations_);
33 proofs_ = std::move(other.proofs_);
34 declaration_order_ = std::move(other.declaration_order_);
35 other.relations_.clear();
36 other.proofs_.clear();
37 other.declaration_order_.clear();
38 ++revision_;
39 ++other.revision_;
40 }
41 return *this;
42}
43
44namespace {
45
46/**
47 * @brief Check if an operator participates in transitive closure.
48 * Only GT and GEQ form transitive chains.
49 */
53
54/**
55 * @brief Combine two transitive operators according to the combination rules:
56 * GT+GT→GT, GT+GEQ→GT, GEQ+GT→GT, GEQ+GEQ→GEQ.
57 */
59 if (op1 == RelationOp::GEQ && op2 == RelationOp::GEQ) {
60 return RelationOp::GEQ;
61 }
62 return RelationOp::GT;
63}
64
65/**
66 * @brief Check structural equality of two expression roots.
67 */
68bool expr_equals(const SymbolicExpr& a, const SymbolicExpr& b) {
69 if (!LMCAS::detail::node(a) && !LMCAS::detail::node(b)) return true;
70 if (!LMCAS::detail::node(a) || !LMCAS::detail::node(b)) return false;
72}
73
75 RelationOp op, PropertyStore& store) {
76 struct SignRule {
78 Sign sign;
79 };
80 static constexpr SignRule rules[] = {
86 };
87 for (const auto& rule : rules) {
88 if (rule.op == op) return store.declare_sign(symbol, rule.sign);
89 }
91}
92
93
95 const SymbolicExpr& rhs,
96 RelationOp op, PropertyStore& store) {
97 const auto variable = std::dynamic_pointer_cast<const VariableNode>(LMCAS::detail::node(lhs));
98 const auto number = std::dynamic_pointer_cast<const NumberNode>(LMCAS::detail::node(rhs));
99 if (variable && !variable->is_constant() && number && number->is_zero()) {
100 return declare_comparison_sign(variable->name(), op, store);
101 }
102 const auto zero = std::dynamic_pointer_cast<const NumberNode>(LMCAS::detail::node(lhs));
103 const auto reversed_variable = std::dynamic_pointer_cast<const VariableNode>(LMCAS::detail::node(rhs));
104 if (zero && zero->is_zero() && reversed_variable &&
105 !reversed_variable->is_constant()) {
107 reversed_variable->name(), detail::reversed_relation(op), store);
108 }
110}
111
112}
113
114RelationStoreResult RelationStore::add_relation_unchecked(
115 const SymbolicExpr& lhs,
116 const SymbolicExpr& rhs,
117 RelationOp op,
118 PropertyStore& prop_store) {
119 auto index = find_relation(lhs, rhs, op);
120 if (!index) {
121 index = relations_.size();
122 relations_.push_back(Relation{lhs, rhs, op});
123 proofs_.push_back(RelationProofs{});
124 }
125 const bool already_declared = proofs_[*index].declared;
126 if (!already_declared) {
127 proofs_[*index].declared = true;
128 declaration_order_.push_back(*index);
129 }
130
133 }
134
135 auto derived = derive_comparison_sign(lhs, rhs, op, prop_store);
136 if (!derived) return derived;
137
138 // Compute transitive closure for GT/GEQ relations
139 if (is_transitive_op(op)) {
140 auto closure = compute_transitive_closure(*index, prop_store);
141 if (!closure) return RelationStoreResult::failure(closure.error());
142 if (already_declared && closure.value()) {
143 // 重复声明可以推进受限闭包,序列化需重放这次操作。
144 declaration_order_.push_back(*index);
145 }
146 }
148}
149
150RelationStoreResult RelationStore::add_relation(
151 const SymbolicExpr& lhs,
152 const SymbolicExpr& rhs,
154 PropertyStore& prop_store) {
155 return add_relation_checked(lhs, rhs, op, prop_store);
156}
157
158RelationStoreResult RelationStore::add_relation_checked(
159 const SymbolicExpr& lhs,
160 const SymbolicExpr& rhs,
162 PropertyStore& prop_store) {
163 if (!LMCAS::detail::node(lhs)) {
165 CasErrc::InvalidArgument, "relation lhs must not be null", "add_relation");
166 }
167 if (!LMCAS::detail::node(rhs)) {
169 CasErrc::InvalidArgument, "relation rhs must not be null", "add_relation");
170 }
171
172 try {
173 RelationStore relation_candidate = *this;
174 PropertyStore property_candidate = prop_store;
175 auto inserted = relation_candidate.add_relation_unchecked(
176 lhs, rhs, op, property_candidate);
177 if (!inserted) return inserted;
178 *this = std::move(relation_candidate);
179 prop_store = std::move(property_candidate);
180 } catch (const std::bad_alloc&) {
182 CasErrc::ResourceLimit, "relation-store allocation failed", "add_relation");
183 } catch (const std::invalid_argument& ex) {
184 return RelationStoreResult::failure(CasErrc::InvalidArgument, ex.what(), "add_relation");
185 } catch (const std::exception& ex) {
187 CasErrc::InternalInvariant, ex.what(), "add_relation");
188 }
189
191}
193 std::queue<std::size_t> queue;
194 int deductions = 0;
195 bool changed = false;
196};
197
198RelationStoreResult RelationStore::enqueue_transitive_deduction(
199 const Relation& deduced, Premises premises,
200 PropertyStore& prop_store, TransitiveWork& work) {
201 if (premises[1] < premises[0]) std::swap(premises[0], premises[1]);
202 if (const auto index = find_relation(deduced.lhs, deduced.rhs, deduced.op)) {
203 if (premises[0] == *index || premises[1] == *index) {
205 }
206 auto& alternatives = proofs_[*index].alternatives;
207 if (std::find(alternatives.begin(), alternatives.end(), premises) ==
208 alternatives.end()) {
209 alternatives.push_back(premises);
210 work.changed = true;
211 }
213 }
214 if (work.deductions == MAX_TRANSITIVE_DEDUCTIONS) {
216 }
217 relations_.push_back(deduced);
218 proofs_.push_back(RelationProofs{false, {premises}});
219 ++work.deductions;
220 work.changed = true;
221 auto derived = derive_comparison_sign(
222 deduced.lhs, deduced.rhs, deduced.op, prop_store);
223 if (!derived) return derived;
224 work.queue.push(relations_.size() - 1);
226}
227
228Result<bool> RelationStore::compute_transitive_closure(
229 std::size_t new_relation, PropertyStore& prop_store) {
230 TransitiveWork work;
231 work.queue.push(new_relation);
232 while (!work.queue.empty()) {
233 const auto current_index = work.queue.front();
234 const auto current = relations_[current_index];
235 work.queue.pop();
236 /**
237 * @brief 双向推导共用同一快照,先正向后反向。
238 * @note 插入可能使向量引用失效,跨插入仅保留索引或副本。
239 */
240 const std::size_t relation_count = relations_.size();
241 for (std::size_t i = 0; i < relation_count; ++i) {
242 if (!is_transitive_op(relations_[i].op)) continue;
243 if (!expr_equals(current.rhs, relations_[i].lhs)) continue;
244 auto result = enqueue_transitive_deduction(
245 {current.lhs, relations_[i].rhs, combine_ops(current.op, relations_[i].op)},
246 {current_index, i}, prop_store, work);
247 if (!result) return Result<bool>::failure(result.error());
248 }
249 for (std::size_t i = 0; i < relation_count; ++i) {
250 if (!is_transitive_op(relations_[i].op)) continue;
251 if (!expr_equals(relations_[i].rhs, current.lhs)) continue;
252 auto result = enqueue_transitive_deduction(
253 {relations_[i].lhs, current.rhs, combine_ops(relations_[i].op, current.op)},
254 {i, current_index}, prop_store, work);
255 if (!result) return Result<bool>::failure(result.error());
256 }
257 }
258 return Result<bool>::success(work.changed);
259}
260
261const std::vector<Relation>& RelationStore::get_relations() const {
262 return relations_;
263}
264
265std::optional<std::size_t> RelationStore::find_relation(
266 const SymbolicExpr& lhs, const SymbolicExpr& rhs, RelationOp op) const {
267 for (std::size_t i = 0; i < relations_.size(); ++i) {
268 const auto& relation = relations_[i];
269 if (relation.op == op && expr_equals(relation.lhs, lhs) &&
270 expr_equals(relation.rhs, rhs)) {
271 return i;
272 }
273 }
274 return std::nullopt;
275}
276
277bool RelationStore::has_relation(const SymbolicExpr& lhs, const SymbolicExpr& rhs,
278 RelationOp op) const {
279 return find_relation(lhs, rhs, op).has_value();
280}
281
282void RelationStore::clear() {
283 if (!relations_.empty()) {
284 relations_.clear();
285 proofs_.clear();
286 declaration_order_.clear();
287 ++revision_;
288 }
289}
290
291}
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success()
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success(T value)
bool equals(const SymbolicNode &other) const
判断两个节点是否结构相等.
RelationStoreResult declare_comparison_sign(const std::string &symbol, RelationOp op, PropertyStore &store)
RelationOp combine_ops(RelationOp op1, RelationOp op2)
Combine two transitive operators according to the combination rules: GT+GT→GT, GT+GEQ→GT,...
bool expr_equals(const SymbolicExpr &a, const SymbolicExpr &b)
Check structural equality of two expression roots.
bool is_transitive_op(RelationOp op)
Check if an operator participates in transitive closure.
RelationStoreResult derive_comparison_sign(const SymbolicExpr &lhs, const SymbolicExpr &rhs, RelationOp op, PropertyStore &store)
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
constexpr RelationOp reversed_relation(RelationOp op) noexcept
const std::string & variable
const MultiPoly & b
RelationOp
Stable relational operator used by public APIs.
const ExprPtr RelationOp op
__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
Result< void > RelationStoreResult
SymbolicExpr lhs
Left-hand side expression
ExprResult relation(const ExprPtr &lhs, const ExprPtr &rhs, RelationOp op)
const ExprPtr & rhs
SymbolicExpr rhs
Right-hand side expression
Sign
Sign classification for symbols and expressions.
RelationOp op
Relational operator (GT, LT, GEQ, LEQ, NEQ, EQ)
A stored relational constraint between two symbolic expressions.
PropertyStore class for mapping symbol names to declared properties.
RelationStore class for storing relational constraints between symbolic expressions.
内部 AST 定义。