LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
property_intervals.cpp
浏览该文件的文档.
3#include <algorithm>
4
5namespace LMCAS {
6
7using namespace property_detail;
8
11 const std::string& operation) {
12 auto normalized = normalize_intervals_checked({interval}, context);
13 if (!normalized) {
15 normalized.error().code, normalized.error().message, operation);
16 }
17 if (normalized.value().empty()) {
20 "property declaration interval must not be empty",
21 operation);
22 }
24}
25
26static bool endpoints_equivalent(const Endpoint& left, const Endpoint& right) {
27 if (left.is_open != right.is_open ||
28 left.is_neg_infinity != right.is_neg_infinity ||
29 left.is_pos_infinity != right.is_pos_infinity) {
30 return false;
31 }
32 if (!left.value || !right.value) {
33 return left.value == right.value;
34 }
35 if (!LMCAS::detail::node(left.value) || !LMCAS::detail::node(right.value)) {
36 return LMCAS::detail::node(left.value) == LMCAS::detail::node(right.value);
37 }
38 return LMCAS::detail::node(left.value)->compare(*LMCAS::detail::node(right.value)) == 0;
39}
40
41static bool intervals_equivalent(const Interval& left, const Interval& right) {
42 return endpoints_equivalent(left.lower, right.lower) &&
43 endpoints_equivalent(left.upper, right.upper);
44}
45
46/**
47 * @brief 判断两个区间是否存在已证明的交集。
48 * 端点排序采用受检区间运算;超出支持域时,交集判定仍为未决。
49 */
51 const Interval& a,
52 const Interval& b,
54 auto left = IntervalUnion::from_intervals_checked({a}, context);
55 if (!left) return Result<bool>::failure(left.error());
56 auto right = IntervalUnion::from_intervals_checked({b}, context);
57 if (!right) return Result<bool>::failure(right.error());
58 auto intersection = left.value().intersect_checked(right.value(), context);
59 if (!intersection) return Result<bool>::failure(intersection.error());
60 return Result<bool>::success(!intersection.value().is_empty());
61}
62
63/**
64 * @brief 判断 outer 是否完全包含 inner。
65 * 包含条件为 outer.lower <= inner.lower 且 inner.upper <= outer.upper,
66 * 并结合端点的开闭属性判断边界。
67 */
69 const Interval& outer,
70 const Interval& inner,
72 auto normalized_outer = IntervalUnion::from_intervals_checked({outer}, context);
73 if (!normalized_outer) {
74 return Result<bool>::failure(normalized_outer.error());
75 }
76 auto normalized_inner = IntervalUnion::from_intervals_checked({inner}, context);
77 if (!normalized_inner) {
78 return Result<bool>::failure(normalized_inner.error());
79 }
80 if (normalized_inner.value().is_empty()) return Result<bool>::success(true);
81 if (normalized_outer.value().is_empty()) return Result<bool>::success(false);
82
83 auto intersection = normalized_outer.value().intersect_checked(
84 normalized_inner.value(), context);
85 if (!intersection) {
86 return Result<bool>::failure(intersection.error());
87 }
88 const auto& intersection_intervals = intersection.value().intervals();
89 const auto& inner_intervals = normalized_inner.value().intervals();
90 if (intersection_intervals.size() != inner_intervals.size()) {
91 return Result<bool>::success(false);
92 }
93 for (std::size_t i = 0; i < inner_intervals.size(); ++i) {
94 if (!intervals_equivalent(intersection_intervals[i], inner_intervals[i])) {
95 return Result<bool>::success(false);
96 }
97 }
98 return Result<bool>::success(true);
99}
100
101
102Result<bool> PropertyStore::check_continuous_declarations(
103 const std::vector<SymbolProperties::ContinuityDecl>& declarations,
104 const std::string& symbol, const Interval& interval,
105 ComputationContext& context) {
106 constexpr const char* operation = "declare_continuous";
107 for (const auto& declaration : declarations) {
108 if (!declaration.is_differentiable &&
109 intervals_equivalent(declaration.interval, interval)) {
110 return Result<bool>::success(false);
111 }
112 auto overlap = intervals_overlap_checked_impl(
113 declaration.interval, interval, context);
114 if (!overlap) {
116 overlap.error().code, overlap.error().message, operation);
117 }
118 if (overlap.value() && declaration.is_differentiable) {
121 "Contradiction for symbol '" + symbol +
122 "': continuous-only declaration overlaps an existing "
123 "differentiable declaration",
124 operation);
125 }
126 }
127 return Result<bool>::success(true);
128}
129
130bool PropertyStore::has_differentiable_declaration(
131 const std::vector<SymbolProperties::ContinuityDecl>& declarations,
132 const Interval& interval) {
133 for (const auto& declaration : declarations) {
134 if (declaration.is_differentiable &&
135 intervals_equivalent(declaration.interval, interval)) {
136 return true;
137 }
138 }
139 return false;
140}
141
142PropertyStoreResult PropertyStore::declare_continuous(
143 const std::string& symbol, const Interval& interval) {
144 return declare_continuous_checked(symbol, interval);
145}
146
147PropertyStoreResult PropertyStore::declare_continuous_checked(
148 const std::string& symbol,
149 const Interval& interval,
151 constexpr const char* operation = "declare_continuous";
152 if (symbol.empty()) return invalid_empty_symbol(operation);
153 auto valid = validate_property_interval(interval, context, operation);
154 if (!valid) return valid;
155
156 try {
157 PropertyStore candidate = *this;
158 auto& declarations = candidate.properties_[symbol].continuity_decls;
159 auto checked = check_continuous_declarations(declarations, symbol, interval, context);
160 if (!checked) return PropertyStoreResult::failure(checked.error());
161 if (!checked.value()) return PropertyStoreResult::success();
162 declarations.push_back({interval, false});
163 *this = std::move(candidate);
164 } catch (const std::bad_alloc&) {
166 CasErrc::ResourceLimit, "property-store allocation failed", operation);
167 } catch (const std::exception& ex) {
169 CasErrc::InternalInvariant, ex.what(), operation);
170 }
172}
173
174PropertyStoreResult PropertyStore::declare_continuous_checked(
175 const std::string& symbol,
176 const Interval& interval) {
178 return declare_continuous_checked(symbol, interval, context);
179}
180
181PropertyStoreResult PropertyStore::declare_differentiable(
182 const std::string& symbol, const Interval& interval) {
183 return declare_differentiable_checked(symbol, interval);
184}
185
186PropertyStoreResult PropertyStore::declare_differentiable_checked(
187 const std::string& symbol,
188 const Interval& interval,
190 constexpr const char* operation = "declare_differentiable";
191 if (symbol.empty()) return invalid_empty_symbol(operation);
192 auto valid = validate_property_interval(interval, context, operation);
193 if (!valid) return valid;
194
195 try {
196 PropertyStore candidate = *this;
197 auto& declarations = candidate.properties_[symbol].continuity_decls;
198 if (has_differentiable_declaration(declarations, interval)) {
200 }
201 declarations.push_back({interval, true});
202 *this = std::move(candidate);
203 } catch (const std::bad_alloc&) {
205 CasErrc::ResourceLimit, "property-store allocation failed", operation);
206 } catch (const std::exception& ex) {
208 CasErrc::InternalInvariant, ex.what(), operation);
209 }
211}
212
213PropertyStoreResult PropertyStore::declare_differentiable_checked(
214 const std::string& symbol,
215 const Interval& interval) {
217 return declare_differentiable_checked(symbol, interval, context);
218}
219
220Result<bool> PropertyStore::is_continuous(
221 const std::string& symbol, const Interval& interval) const {
222 return is_continuous_checked(symbol, interval);
223}
224
225Result<bool> PropertyStore::is_continuous_checked(
226 const std::string& symbol,
227 const Interval& interval,
229 constexpr const char* operation = "is_continuous";
230 if (symbol.empty()) {
232 CasErrc::InvalidArgument, "symbol name must not be empty", operation);
233 }
234 auto valid = validate_property_interval(interval, context, operation);
235 if (!valid) return Result<bool>::failure(valid.error());
236
237 auto it = properties_.find(symbol);
238 if (it == properties_.end()) {
239 return Result<bool>::success(false);
240 }
241
242 for (const auto& decl : it->second.continuity_decls) {
243 auto covers = interval_covers_checked_impl(decl.interval, interval, context);
244 if (!covers) {
246 covers.error().code, covers.error().message, operation);
247 }
248 if (covers.value()) return Result<bool>::success(true);
249 }
250 return Result<bool>::success(false);
251}
252
253Result<bool> PropertyStore::is_continuous_checked(
254 const std::string& symbol,
255 const Interval& interval) const {
257 return is_continuous_checked(symbol, interval, context);
258}
259
260Result<bool> PropertyStore::is_differentiable(
261 const std::string& symbol, const Interval& interval) const {
262 return is_differentiable_checked(symbol, interval);
263}
264
265Result<bool> PropertyStore::is_differentiable_checked(
266 const std::string& symbol,
267 const Interval& interval,
269 constexpr const char* operation = "is_differentiable";
270 if (symbol.empty()) {
272 CasErrc::InvalidArgument, "symbol name must not be empty", operation);
273 }
274 auto valid = validate_property_interval(interval, context, operation);
275 if (!valid) return Result<bool>::failure(valid.error());
276
277 auto it = properties_.find(symbol);
278 if (it == properties_.end()) {
279 return Result<bool>::success(false);
280 }
281
282 for (const auto& decl : it->second.continuity_decls) {
283 if (!decl.is_differentiable) continue;
284 auto covers = interval_covers_checked_impl(decl.interval, interval, context);
285 if (!covers) {
287 covers.error().code, covers.error().message, operation);
288 }
289 if (covers.value()) return Result<bool>::success(true);
290 }
291 return Result<bool>::success(false);
292}
293
294Result<bool> PropertyStore::is_differentiable_checked(
295 const std::string& symbol,
296 const Interval& interval) const {
298 return is_differentiable_checked(symbol, interval, context);
299}
300
301
302PropertyStoreResult PropertyStore::declare_monotonicity(
303 const std::string& symbol,
304 const std::string& variable,
305 const Interval& interval,
306 Monotonicity mono) {
307 return declare_monotonicity_checked(symbol, variable, interval, mono);
308}
309
310PropertyStoreResult PropertyStore::declare_monotonicity_checked(
311 const std::string& symbol,
312 const std::string& variable,
313 const Interval& interval,
314 Monotonicity mono,
316 constexpr const char* operation = "declare_monotonicity";
317 if (symbol.empty()) return invalid_empty_symbol(operation);
318 if (variable.empty()) {
320 CasErrc::InvalidArgument, "variable name must not be empty", operation);
321 }
322 auto valid = validate_property_interval(interval, context, operation);
323 if (!valid) return valid;
324
325 try {
326 PropertyStore candidate = *this;
327 auto& declarations = candidate.properties_[symbol].monotonicity_decls;
328 for (const auto& declaration : declarations) {
329 if (declaration.variable == variable && declaration.type == mono &&
330 intervals_equivalent(declaration.interval, interval)) {
332 }
333 }
334 declarations.push_back({variable, interval, mono});
335 *this = std::move(candidate);
336 } catch (const std::bad_alloc&) {
338 CasErrc::ResourceLimit, "property-store allocation failed", operation);
339 } catch (const std::exception& ex) {
341 CasErrc::InternalInvariant, ex.what(), operation);
342 }
344}
345
346PropertyStoreResult PropertyStore::declare_monotonicity_checked(
347 const std::string& symbol,
348 const std::string& variable,
349 const Interval& interval,
350 Monotonicity mono) {
352 return declare_monotonicity_checked(symbol, variable, interval, mono, context);
353}
354
355Result<Monotonicity> PropertyStore::get_monotonicity(
356 const std::string& symbol,
357 const std::string& variable,
358 const Interval& interval) const {
359 return get_monotonicity_checked(symbol, variable, interval);
360}
361
362Result<Monotonicity> PropertyStore::get_monotonicity_checked(
363 const std::string& symbol,
364 const std::string& variable,
365 const Interval& interval,
367 constexpr const char* operation = "get_monotonicity";
368 if (symbol.empty() || variable.empty()) {
371 symbol.empty() ? "symbol name must not be empty" : "variable name must not be empty",
372 operation);
373 }
374 auto valid = validate_property_interval(interval, context, operation);
375 if (!valid) return Result<Monotonicity>::failure(valid.error());
376
377 auto it = properties_.find(symbol);
378 if (it == properties_.end()) {
380 }
381
382 for (const auto& decl : it->second.monotonicity_decls) {
383 if (decl.variable != variable) continue;
384 auto covers = interval_covers_checked_impl(decl.interval, interval, context);
385 if (!covers) {
387 covers.error().code, covers.error().message, operation);
388 }
389 if (covers.value()) return Result<Monotonicity>::success(decl.type);
390 }
392}
393
394Result<Monotonicity> PropertyStore::get_monotonicity_checked(
395 const std::string& symbol,
396 const std::string& variable,
397 const Interval& interval) const {
399 return get_monotonicity_checked(symbol, variable, interval, context);
400}
401
402}
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)
int compare(const SymbolicNode &other) const
与另一个节点进行全序比较.
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
ComputationContext const std::string & operation
PropertyStoreResult invalid_empty_symbol(const std::string &operation)
const std::string & variable
static Result< bool > interval_covers_checked_impl(const Interval &outer, const Interval &inner, ComputationContext &context)
判断 outer 是否完全包含 inner。 包含条件为 outer.lower <= inner.lower 且 inner.upper <= outer.upper, 并结合端点的开闭属性判断边界。
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
ExprResult interval(ExprPtr lower, ExprPtr upper, bool lower_closed, bool upper_closed)
Result< void > PropertyStoreResult
static Result< bool > intervals_overlap_checked_impl(const Interval &a, const Interval &b, ComputationContext &context)
判断两个区间是否存在已证明的交集。 端点排序采用受检区间运算;超出支持域时,交集判定仍为未决。
static bool endpoints_equivalent(const Endpoint &left, const Endpoint &right)
const MultiPoly & b
Monotonicity
Monotonicity classification for functions over intervals.
@ Unknown
Monotonicity not determined
Result< std::vector< Interval > > normalize_intervals_checked(std::vector< Interval > intervals, ComputationContext &context)
__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
static bool intervals_equivalent(const Interval &left, const Interval &right)
const ExprPtr & right
PropertyStoreResult validate_property_interval(const Interval &interval, ComputationContext &context, const std::string &operation)
内部 AST 定义。