LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
expr_number_domains.cpp
浏览该文件的文档.
1#include "expr.hpp"
2
3#include <cmath>
4#include <optional>
5#include <utility>
6#include <vector>
7
11#include "root_of_identity.hpp"
12
13namespace LMCAS {
14namespace {
15
16constexpr const char* kNumberDomainOperation = "LMCAS.number_domain";
17
18Result<bool> bool_failure(CasErrc code, std::string message,
19 const char* operation) {
20 return Result<bool>::failure(code, std::move(message), operation);
21}
22
25 "domain membership is only decidable for numeric and explicit complex expressions",
27}
28
29
31 switch (domain) {
33 return 0;
34 }
36 return 1;
37 }
39 return 2;
40 }
42 return 3;
43 }
45 return 4;
46 }
47 }
48 return -1;
49}
50
51Result<bool> domain_contains_node(
52 NumberDomain domain, const std::shared_ptr<const SymbolicNode>& node);
53
55 const auto& value = number.value();
56 if (std::holds_alternative<BigInt>(value)) {
57 return Result<bool>::success(true);
58 }
59 if (std::holds_alternative<Rational>(value)) {
60 const auto& rational = std::get<Rational>(value);
62 return Result<bool>::success(rational.is_integer());
63 }
64 if (domain_rank(domain) >= 0) {
65 return Result<bool>::success(true);
66 }
67 }
68 return inconclusive_domain();
69}
70
74 if (!real) {
75 return real;
76 }
78 if (!imag) {
79 return imag;
80 }
81 return Result<bool>::success(real.value() && imag.value());
82 }
83 if (!node.imag()->is_zero()) {
84 return Result<bool>::success(false);
85 }
86 return domain_contains_node(domain, node.real());
87}
88
91 const std::vector<std::shared_ptr<const SymbolicNode>>& operands) {
92 bool all_members = true;
93 for (const auto& operand : operands) {
94 auto member = domain_contains_node(domain, operand);
95 if (!member) {
97 return member;
98 }
99 all_members = false;
100 continue;
101 }
102 all_members = all_members && member.value();
103 }
104 return all_members ? Result<bool>::success(true) : inconclusive_domain();
105}
106
108 if (value < Rational(0)) {
110 }
112 return true;
113 }
114 const bool rational_root = value.get_numerator().is_perfect_square() &&
115 value.get_denominator().is_perfect_square();
117 ? rational_root
118 : rational_root && value.get_denominator() == BigInt(1);
119}
120
122 NumberDomain domain, const PowerNode& power, const Rational& exponent) {
123 auto base = detail::exact_rational_value(power.base());
124 if (exponent == Rational(1, 2) && base) {
126 }
127 return bool_failure(
129 "non-integer power membership requires a branch/domain proof",
131}
132
134 const Rational& exponent,
135 const std::shared_ptr<const NumberNode>& base) {
136 return exponent <= Rational(0) && base && base->is_zero();
137}
138
141 const std::shared_ptr<const NumberNode>& base_number,
142 const std::optional<Rational>& exact_base) {
143 if (exact_base) {
146 exact_base->get_numerator().abs() == BigInt(1));
147 }
152 }
153 if (base_number) {
154 return domain_contains_number(domain, *base_number);
155 }
156 return inconclusive_domain();
157}
158
160 NumberDomain domain, const PowerNode& power) {
161 auto base = domain_contains_node(domain, power.base());
162 if (!base) {
163 return base.error().code == CasErrc::Inconclusive
165 : Result<bool>::failure(base.error());
166 }
167 return base.value() ? Result<bool>::success(true) : inconclusive_domain();
168}
169
171 const auto exponent = detail::exact_rational_value(power.exponent());
172 if (!exponent) {
173 return bool_failure(
175 "domain membership for powers requires an exact exponent",
177 }
178 if (!exponent->is_integer()) {
180 }
181
182 const auto base_number =
183 std::dynamic_pointer_cast<const NumberNode>(power.base());
184 const auto exact_base = detail::exact_rational_value(power.base());
185 if (is_undefined_zero_power(*exponent, base_number)) {
186 return bool_failure(
188 "zero to a nonpositive integer power is undefined",
190 }
191 if (exponent->is_zero()) {
192 return base_number ? Result<bool>::success(true)
194 }
195 if (*exponent < Rational(0)) {
197 domain, base_number, exact_base);
198 }
200}
201
203 NumberDomain domain, const std::shared_ptr<const SymbolicNode>& node) {
204 auto expression = detail::make_expression_ptr(node);
206 auto value = rootof_evaluate_complex_checked(expression);
207 return value ? Result<bool>::success(true)
208 : Result<bool>::failure(value.error());
209 }
211 auto value = rootof_evaluate_checked(expression, context);
212 if (value) {
214 }
215 if (value.error().code == CasErrc::DomainError) {
216 return Result<bool>::success(false);
217 }
218 return Result<bool>::failure(value.error());
219}
220
222 switch (type) {
224 return true;
225 }
227 return true;
228 }
230 return true;
231 }
233 return true;
234 }
236 return true;
237 }
239 return true;
240 }
242 return true;
243 }
244 default:
245 return false;
246 }
247}
248
250 if (function.arguments().size() != 1) {
251 return inconclusive_domain();
252 }
254 auto exact = detail::exact_rational_value(function.arguments()[0]);
255 if (exact) {
256 if (domain_rank(domain) >= 0) {
258 }
259 if (*exact < Rational(0)) {
260 return Result<bool>::success(false);
261 }
262 }
263 }
267 return inconclusive_domain();
268 }
272 function.arguments()[0]);
273 }
274 return inconclusive_domain();
275}
276
278 NumberDomain domain, const std::shared_ptr<const SymbolicNode>& node) {
279 if (!node) {
281 "domain membership element must not be null",
283 }
285 return Result<bool>::success(true);
286 }
287 if (auto number = std::dynamic_pointer_cast<const NumberNode>(node)) {
288 return domain_contains_number(domain, *number);
289 }
290 if (auto complex = std::dynamic_pointer_cast<const ComplexNode>(node)) {
292 }
293 if (auto add = std::dynamic_pointer_cast<const AddNode>(node)) {
294 return domain_contains_operands(domain, add->operands());
295 }
296 if (auto multiply = std::dynamic_pointer_cast<const MultiplyNode>(node)) {
297 return domain_contains_operands(domain, multiply->operands());
298 }
299 if (auto power = std::dynamic_pointer_cast<const PowerNode>(node)) {
300 return domain_contains_power(domain, *power);
301 }
302 if (std::dynamic_pointer_cast<const RootOfNode>(node)) {
303 return domain_contains_root(domain, node);
304 }
305 if (auto function = std::dynamic_pointer_cast<const FunctionNode>(node)) {
307 }
308 return inconclusive_domain();
309}
310
311}
312
313const char* NumberDomainSet::name() const noexcept {
314 switch (domain_) {
316 return "Z";
317 }
319 return "Q";
320 }
321 case NumberDomain::Reals: {
322 return "R";
323 }
325 return "C";
326 }
328 return "Expr";
329 }
330 }
331 return "?";
332}
333
334bool NumberDomainSet::subset_of(const NumberDomainSet& other) const noexcept {
335 return domain_rank(domain_) <= domain_rank(other.domain_);
336}
337
338Result<bool> NumberDomainSet::contains(const ConstExprPtr& element) const {
339 if (!element || !detail::node(*element)) {
341 "domain membership element must not be null",
342 kNumberDomainOperation);
343 }
344 if (domain_ == NumberDomain::Expressions) {
345 return Result<bool>::success(true);
346 }
347
349 auto normalized = detail::simplify_expression(
351 if (!normalized) {
352 return Result<bool>::failure(normalized.error());
353 }
354 return domain_contains_node(domain_, detail::node(normalized.value()));
355}
356
357NumberDomainSet integers() {
358 return NumberDomainSet(NumberDomain::Integers);
359}
360
361NumberDomainSet rationals() {
362 return NumberDomainSet(NumberDomain::Rationals);
363}
364
365NumberDomainSet reals() {
366 return NumberDomainSet(NumberDomain::Reals);
367}
368
369NumberDomainSet complexes() {
370 return NumberDomainSet(NumberDomain::Complexes);
371}
372
373NumberDomainSet expressions() {
374 return NumberDomainSet(NumberDomain::Expressions);
375}
376
377Result<bool> domain_contains(const NumberDomainSet& domain, const ExprPtr& element) {
378 return domain.contains(element);
379}
380
381Result<bool> domain_subset(const NumberDomainSet& lhs, const NumberDomainSet& rhs) {
382 return Result<bool>::success(lhs.subset_of(rhs));
383}
384
385}
复数节点,表示 real + imag * i。
函数节点,表示数学函数调用(三角函数、对数、特殊函数等)。
@ Sqrt
对数、绝对值、平方根。
const std::variant< BigInt, Rational > & value() const noexcept
幂运算节点,表示 base^exponent。
const std::shared_ptr< const SymbolicNode > & exponent() const noexcept
const std::shared_ptr< const SymbolicNode > & base() const noexcept
CasError & error()
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success(T value)
virtual bool is_zero() const
Result< bool > domain_contains_operands(NumberDomain domain, const std::vector< std::shared_ptr< const SymbolicNode > > &operands)
Result< bool > domain_contains_power(NumberDomain domain, const PowerNode &power)
Result< bool > domain_contains_positive_integer_power(NumberDomain domain, const PowerNode &power)
bool exact_sqrt_contains(NumberDomain domain, const Rational &value)
Result< bool > bool_failure(CasErrc code, std::string message, const char *operation)
Result< bool > domain_contains_node(NumberDomain domain, const std::shared_ptr< const SymbolicNode > &node)
Result< bool > domain_contains_root(NumberDomain domain, const std::shared_ptr< const SymbolicNode > &node)
bool is_undefined_zero_power(const Rational &exponent, const std::shared_ptr< const NumberNode > &base)
Result< bool > domain_contains_number(NumberDomain domain, const NumberNode &number)
Result< bool > domain_contains_function(NumberDomain domain, const FunctionNode &function)
Result< bool > domain_contains_complex(NumberDomain domain, const ComplexNode &node)
Result< bool > domain_contains_fractional_power(NumberDomain domain, const PowerNode &power, const Rational &exponent)
Result< bool > domain_contains_negative_integer_power(NumberDomain domain, const std::shared_ptr< const NumberNode > &base_number, const std::optional< Rational > &exact_base)
std::shared_ptr<::LMCAS::SymbolicExpr > make_expression_ptr(SymbolicNodePtr root)
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
ExpressionResult simplify_expression(const ExprPtr &expression, ComputationContext &context)
std::optional< Rational > exact_rational_value(const NumberNode &number)
const ExprPtr & element
RootOfComplexEvaluationResult rootof_evaluate_complex_checked(const std::shared_ptr< SymbolicExpr > &rootof_expr, ComputationContext &context)
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
ExprResult real(const ExprPtr &expression, ComputationContext &context)
RootOfEvaluationResult rootof_evaluate_checked(const std::shared_ptr< SymbolicExpr > &rootof_expr, ComputationContext &context)
ExprResult add(const ExprPtr &lhs, const ExprPtr &rhs, ComputationContext &context)
NumberDomainSet reals()
std::shared_ptr< const SymbolicExpr > ConstExprPtr
ExprResult complex(ExprPtr real, ExprPtr imag)
const ExprPtr & exponent
NumberDomainSet integers()
const NumberDomainSet & domain
ExprPtr imag
ExprResult member(const ExprPtr &element, const ExprPtr &set, ComputationContext &context)
std::shared_ptr< SymbolicExpr > ExprPtr
Result< bool > domain_subset(const NumberDomainSet &lhs, const NumberDomainSet &rhs)
const std::string const ExprPtr & value
const ExprPtr & rhs
NumberDomainSet expressions()
NumberDomainSet rationals()
Result< bool > domain_contains(const NumberDomainSet &domain, const ExprPtr &element)
NumberDomainSet complexes()
ExprResult function(const std::string &name, std::vector< ExprPtr > arguments)
ExprResult rational(const Rational &value)
精确 RootOf 标识构造及受检数值求值。
内部 AST 定义。