16using Node = std::shared_ptr<const SymbolicNode>;
21 if (
a == T::False ||
b == T::False)
return T::False;
22 return a == T::True &&
b == T::True ? T::True : T::Unknown;
26 if (
a == T::True ||
b == T::True)
return T::True;
27 return a == T::False &&
b == T::False ? T::False : T::Unknown;
45 context.limits().max_ast_nodes,
"facts.domain_condition") {}
59 auto entered =
context_.enter_recursion(
"facts.domain");
61 error = entered.error();
66 ~Leave() {
context.leave_recursion(); }
70 if (result.defined == T::False || (result.defined != T::True && !
project_)) {
71 result.real = result.nonzero = result.positive = result.nonnegative = T::Unknown;
72 }
else if (result.defined == T::True && values) {
93 return result.
value();
96 template<
class N,
class... Args>
115 std::vector<Node> operands;
117 operands.push_back(std::move(
a));
118 operands.push_back(std::move(
b));
122 template<
class Predicate>
124 bool real_restriction =
true) {
129 auto condition = predicate();
130 if (!
error && condition) {
140 result.
real = T::True;
143 if (result.
real == T::False) {
145 }
else if (result.
positive == T::True) {
147 }
else if (result.
nonzero == T::False) {
159 if (
error) {
return; }
162 if (
error) {
return; }
164 if (
error) {
return; }
166 if (
error) {
return; }
169 if (
error) {
return; }
170 if (negative == T::True) {
188 { result.
real = T::False; }
208 for (
const auto& operand : operands) {
209 auto child =
walk(operand, values);
210 if (
error) {
return {}; }
212 if (!values) {
continue; }
217 reduction.
any_zero |= child.nonzero == T::False;
218 reduction.
all_zero &= child.nonzero == T::False;
222 if (child.positive == T::True) {
224 }
else if (child.real == T::True && child.nonnegative == T::False) {
230 if (!values) {
return result; }
231 return reduction.
finish(result, product);
235 const auto exponent_number = std::dynamic_pointer_cast<const NumberNode>(
node.exponent());
238 bool needs_base_value = values || !integral;
239 if (!needs_base_value) {
240 needs_base_value =
integer.is_negative() ||
243 auto base =
walk(
node.base(), needs_base_value);
244 if (
error) {
return {}; }
246 if (
error) {
return {}; }
252 if (exponent_number) {
259 if (exact_exponent && exact_exponent->is_integer()) {
266 const bool zero =
integer == BigInt(0);
269 return relation(node.base(), number(0), RelationOp::NEQ);
275 if (base.
real == T::True) { result.
real = T::True; }
278 if (base.
real == T::True) {
279 if (
integer % BigInt(2) == BigInt(0)) {
293 unresolved_integer_domain =
false;
297 unresolved_integer_domain = !known_noninteger && base.
nonnegative != T::True;
298 if (unresolved_integer_domain && allowed != T::True) { allowed = T::Unknown; }
299 if (known_noninteger && base.
real == T::True && base.
nonnegative == T::False)
300 { allowed = T::False; }
302 exponent.real == T::True) { allowed = T::False; }
305 base.
nonzero == T::False ? T::True :
306 base.
nonzero == T::True ? T::False : T::Unknown,
314 bool unresolved_integer_domain;
316 if (allowed == T::Unknown &&
317 (
exponent.real != T::True || unresolved_integer_domain)) {
336 ValueFacts result,
bool known_noninteger)
const {
347 }
else if (known_noninteger && base.
real == T::True && base.
nonnegative == T::False) {
348 result.
real = T::False;
365 const auto& arguments =
node.arguments();
366 if (
node.type() == FT::Infinity) {
return {T::False}; }
372 const auto& argument = arguments[0];
374 auto child =
walk(argument, values || restricted);
375 if (
error) {
return {}; }
377 result.
defined = child.defined;
382 if (type == FT::Ln || type == FT::Log || type == FT::Tan ||
383 type == FT::Sec || type == FT::Cot || type == FT::Csc) {
386 if (type == FT::ArcTan || type == FT::Sgn) {
389 if (type == FT::Sqrt || type == FT::ArcSin || type == FT::ArcCos) {
396 switch (
node.type()) {
399 if (child.
real == T::True)
403 case FT::Sin: {
break; }
404 case FT::Cos: {
break; }
405 case FT::Sinh: {
break; }
406 case FT::Cosh: {
break; }
407 case FT::Erf: {
break; }
408 case FT::Si: {
break; }
411 if (child.
real == T::True) { result.
real = T::True; }
412 if (child.
nonzero == T::False) {
414 ? T::True : T::False;
421 switch (
node.type()) {
422 case FT::Ln: {
return logarithm(
node.arguments(), child, result); }
423 case FT::Log: {
return logarithm(
node.arguments(), child, result); }
447 if (
node.type() == FT::Sqrt) {
450 return relation(node.arguments()[0], number(0), RelationOp::GEQ);
458 result.
real = T::False;
462 if (
node.type() == FT::Abs ||
node.type() == FT::ComplexAbs) {
468 if (child.
defined == T::True) { result.
real = T::True; }
487 const T in_principal_domain = child.
nonnegative == T::True ? T::True : T::Unknown;
488 require(result, in_principal_domain, [&] {
492 if (in_principal_domain == T::True ||
project_) {
493 result.
real = T::True;
506 const auto& argument = arguments[0];
508 return relation(argument, number(0),
509 domain_ == Domain::Real ? RelationOp::GT : RelationOp::NEQ);
512 { result.
real = T::True; }
513 if (
const auto* numeric =
dynamic_cast<const NumberNode*
>(argument.get())) {
514 if (numeric->is_one()) { result.
nonzero = T::False; }
515 else if (numeric->is_positive()) {
519 }
else if (!numeric->is_zero()) {
520 result.
real = T::False;
524 if (arguments.size() == 2) {
return logarithm_base(arguments[1], child, result); }
528 auto base =
walk(argument,
true);
529 if (
error) {
return {}; }
532 return relation(argument, number(0),
533 domain_ == Domain::Real ? RelationOp::GT : RelationOp::NEQ);
535 T different_from_one = T::Unknown;
536 if (
const auto* numeric =
dynamic_cast<const NumberNode*
>(argument.get()))
537 { different_from_one = numeric->is_one() ? T::False : T::True; }
538 require(result, different_from_one, [&] {
542 (child.
positive == T::True && base.positive == T::True)
543 ? T::True : T::Unknown;
549 const auto& argument =
node.arguments()[0];
550 if (
node.type() == FT::ArcSin ||
node.type() == FT::ArcCos) {
552 T inside = T::Unknown;
553 if (
const auto* numeric =
dynamic_cast<const NumberNode*
>(argument.get())) {
555 inside =
value >= Rational(-1) &&
value <= Rational(1) ? T::True : T::False;
565 if (
node.type() == FT::ArcTan) {
566 if (child.
real == T::True) {
567 result.
real = T::True;
577 const bool cosine =
node.type() == FT::Tan ||
node.type() == FT::Sec;
578 T nonzero = T::Unknown;
579 if (child.
nonzero == T::False) { nonzero = cosine ? T::True : T::False; }
584 if (child.
real == T::True) { result.
real = T::True; }
590 const T nz =
number->is_zero() ? T::False : T::True;
591 const T positive =
number->is_positive() ? T::True : T::False;
592 return {T::True, T::True, nz, positive,
593 nz == T::False || positive == T::True ? T::True : T::False};
607 if (
const auto* root =
dynamic_cast<const RootOfNode*
>(
node.get())) {
612 if (
error) {
return {}; }
624 {
return {T::True, T::True, T::True, T::True, T::True}; }
630 if (
error) {
return {}; }
632 if (
error) {
return {}; }
638 const T zero =
imag.nonzero == T::False ? T::True :
639 imag.nonzero == T::True ? T::False : T::Unknown;
645 result.
real =
imag.nonzero == T::False ? T::True :
646 imag.nonzero == T::True ? T::False : T::Unknown;
647 if (result.
real == T::True) {
660 error = isolation.error();
663 if (
const auto*
real = std::get_if<RealIsolation>(&isolation.value())) {
664 result.
real = T::True;
670 result.
real = T::False;
681 bool* violated_real_restriction =
nullptr) {
684 "value domain must be Real or Complex",
"facts.domain");
688 auto result = traversal.
walk(
node, values);
690 if (violated_real_restriction)
695 }
catch (
const std::bad_alloc&) {
697 "value facts allocation failed",
"facts.domain");
706 violated_real_restriction);
723 using Output = std::optional<std::vector<std::shared_ptr<SymbolicExpr>>>;
726 "value domain must be Real or Complex",
"facts.domain");
730 auto result = traversal.walk(
node);
732 if (result.defined == T::False) {
736 if (complex_defined.value() != T::False) {
739 if (real_value.value() == T::Unknown)
return Output{};
742 auto impossible = traversal.false_condition();
744 traversal.conditions.clear();
746 }
else if (!traversal.expressible) {
749 return Output{std::move(traversal.conditions)};
752 }
catch (
const std::bad_alloc&) {
754 "domain projection allocation failed",
"facts.domain");
virtual Result< Tribool > is_real(const std::shared_ptr< const SymbolicNode > &node, ComputationContext &context) const =0
virtual Result< Tribool > is_nonnegative(const std::shared_ptr< const SymbolicNode > &node, ComputationContext &context) const =0
virtual Result< Tribool > is_positive(const std::shared_ptr< const SymbolicNode > &node, ComputationContext &context) const =0
virtual Result< Tribool > is_nonzero(const std::shared_ptr< const SymbolicNode > &node, ComputationContext &context) const =0
virtual Result< Tribool > is_negative(const std::shared_ptr< const SymbolicNode > &node, ComputationContext &context) const =0
函数节点,表示数学函数调用(三角函数、对数、特殊函数等)。
static Result failure(CasErrc code, std::string message, std::string operation={})
const LMCAS::detail::ExactRootId & exact_id() const noexcept
std::size_t measure(const std::shared_ptr< const SymbolicNode > &node)
std::size_t append_size(std::size_t current, std::size_t child)
Node make(Args &&... args)
ValueFacts elementary_value(const FunctionNode &node, const ValueFacts &child, ValueFacts result)
std::size_t condition_nodes_
bool violated_real_restriction
void require(ValueFacts &result, T truth, Predicate &&predicate, bool real_restriction=true)
ValueFacts elementary(const FunctionNode &node, bool values)
std::optional< CasError > error
T nonintegral_domain(const ValueFacts &base, const ValueFacts &exponent, bool known_noninteger, bool &unresolved_integer_domain)
ValueFacts restricted_function(const FunctionNode &node, const ValueFacts &child, ValueFacts result)
ValueFacts logarithm(const std::vector< Node > &arguments, const ValueFacts &child, ValueFacts result)
ValueFacts lambert_w_domain(const FunctionNode &node, const ValueFacts &child, ValueFacts result)
ComputationContext & context_
bool restricted_argument(FT type) const
std::vector< std::shared_ptr< SymbolicExpr > > conditions
static void implications(ValueFacts &result)
ValueFacts nonintegral_value(const ValueFacts &base, const ValueFacts &exponent, ValueFacts result, bool known_noninteger) const
T checked(Result< T > result)
ValueFacts trigonometric_domain(const FunctionNode &node, const ValueFacts &child, ValueFacts result)
ValueFacts logarithm_base(const Node &argument, const ValueFacts &child, ValueFacts result)
ValueFacts structural(const Node &node, bool values)
ValueFacts zero_base_power_value(const ValueFacts &exponent, ValueFacts result) const
DomainTraversal(const FactsQuery &facts, Domain domain, ComputationContext &context, bool project=false)
ValueFacts power(const PowerNode &node, bool values)
ValueFacts complex_facts(const ComplexNode &complex)
Node function(FT type, const Node &argument)
ValueFacts arithmetic(const std::vector< Node > &operands, bool product, bool values)
Node multiply(Node a, Node b)
ValueFacts integral_power(const PowerNode &node, const ValueFacts &base, const BigInt &integer, ValueFacts result)
ValueFacts variable_facts(const VariableNode &variable)
ValueFacts root_facts(const RootOfNode &root, bool values)
void infer(const Node &node, ValueFacts &result)
ValueFacts walk(const Node &node, bool values=false)
const FactsQuery & facts_
Node relation(Node a, Node b, RelationOp op)
ValueFacts nonintegral_power(const PowerNode &node, const ValueFacts &base, const ValueFacts &exponent, ValueFacts result, bool known_noninteger)
Node logical(Node a, Node b, LogicalNode::Op op)
ValueFacts real_valued_function(const FunctionNode &node, const ValueFacts &child, ValueFacts result)
FunctionNode::FuncType FT
Result< Tribool > query_value(const Node &node, const FactsQuery &facts, Domain domain, T ValueFacts::*member, bool values, ComputationContext &context, bool *violated_real_restriction=nullptr)
std::shared_ptr< const SymbolicNode > Node
std::shared_ptr<::LMCAS::SymbolicExpr > make_expression_ptr(SymbolicNodePtr root)
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
Result< RootIsolation > isolate_exact_root(const ExactRootId &root, ComputationContext &context, const std::string &operation)
Result< Tribool > query_nonzero_value(const Node &node, const FactsQuery &facts, Domain domain, ComputationContext &context)
const std::string & variable
std::shared_ptr< const SymbolicNode > Node
RewriteBudget const FactsQuery Domain domain
Result< Tribool > query_definedness(const Node &node, const FactsQuery &facts, Domain domain, ComputationContext &context, bool *violated_real_restriction)
RewriteBudget const FactsQuery & facts
std::optional< Rational > closed_rational_value(const std::shared_ptr< const SymbolicNode > &node, Domain domain, ComputationContext &context)
std::shared_ptr< const Node > make_node(Args &&... args)
Result< std::optional< std::vector< std::shared_ptr< SymbolicExpr > > > > domain_constraints(const Node &node, const FactsQuery &facts, Domain domain, ComputationContext &context)
Result< Tribool > query_real_value(const Node &node, const FactsQuery &facts, ComputationContext &context)
Result< Tribool > query_nonnegative_value(const Node &node, const FactsQuery &facts, ComputationContext &context)
std::size_t std::size_t ComputationContext & context
Result< Tribool > query_positive_value(const Node &node, const FactsQuery &facts, ComputationContext &context)
ExprResult pow(const ExprPtr &base, const ExprPtr &exponent, 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)
Domain
Mathematical domain hierarchy (least specific → most specific). Complex ⊃ Real ⊃ Algebraic ⊃ Rational...
@ Complex
Complex numbers (default, least specific)
Tribool
Tri-state logic value for property queries.
ExprResult add(const ExprPtr &lhs, const ExprPtr &rhs, ComputationContext &context)
RelationOp
Stable relational operator used by public APIs.
const ExprPtr RelationOp op
ExprResult complex(ExprPtr real, ExprPtr imag)
__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
ExprResult member(const ExprPtr &element, const ExprPtr &set, ComputationContext &context)
const std::string const ExprPtr & value
Rational exact_number_as_rational(const NumberNode &node)
bool other_factors_nonzero
std::size_t nonreal_count
ValueFacts finish(ValueFacts result, bool product) const