9bool LimitVisitor::is_infinite_product(
const MultiplyNode& product)
const {
10 bool infinite =
false;
11 for (
const auto& operand : product.operands()) {
12 if (is_inf(operand)) { infinite =
true; }
14 auto sign = get_node_sign(operand);
15 if (!sign || !*sign) {
return false; }
21bool LimitVisitor::is_infinite_sum(
const AddNode& sum)
const {
23 for (
const auto& operand : sum.operands()) {
24 if (is_inf(operand)) {
25 int next = is_neg_inf(operand) ? -1 : 1;
26 if (sign && sign != next) {
return false; }
28 }
else if (!std::dynamic_pointer_cast<const NumberNode>(operand)) {
return false; }
33std::optional<int> LimitVisitor::assumed_node_sign(
34 const std::shared_ptr<const SymbolicNode>& node)
const {
35 std::optional<detail::AssumptionFacts> assumed;
36 if (assumption_ctx_) { assumed.emplace(*assumption_ctx_); }
39 if (!nonzero) {
throw nonzero.error(); }
42 if (!positive) {
throw positive.error(); }
45 if (!nonnegative) {
throw nonnegative.error(); }
54bool LimitVisitor::is_infinite_power(
const PowerNode& node)
const {
55 auto number = std::dynamic_pointer_cast<const NumberNode>(
node.exponent());
60bool LimitVisitor::is_inf(
const std::shared_ptr<const SymbolicNode>& node)
const {
61 if (!node) {
return false; }
62 if (
auto f = std::dynamic_pointer_cast<const FunctionNode>(node))
64 if (
auto product = std::dynamic_pointer_cast<const MultiplyNode>(node)) {
65 return is_infinite_product(*product);
67 if (
auto sum = std::dynamic_pointer_cast<const AddNode>(node)) {
68 return is_infinite_sum(*sum);
70 if (
auto power = std::dynamic_pointer_cast<const PowerNode>(node)) {
return is_infinite_power(*power); }
74bool LimitVisitor::is_neg_inf(
const std::shared_ptr<const SymbolicNode>& node)
const {
75 if (
auto product = std::dynamic_pointer_cast<const MultiplyNode>(node)) {
76 if (!is_inf(node)) {
return false; }
78 for (
const auto& operand : product->operands())
79 {
sign *= is_inf(operand) ? (is_neg_inf(operand) ? -1 : 1) : *get_node_sign(operand); }
82 if (
auto sum = std::dynamic_pointer_cast<const AddNode>(node)) {
83 if (!is_inf(node)) {
return false; }
84 for (
const auto& operand : sum->operands()) {
if (is_inf(operand)) {
return is_neg_inf(operand); } }
86 if (
auto power = std::dynamic_pointer_cast<const PowerNode>(node)) {
88 auto number = std::dynamic_pointer_cast<const NumberNode>(power->exponent());
94std::optional<int> LimitVisitor::get_node_sign(
95 const std::shared_ptr<const SymbolicNode>& node)
const {
102 if (std::dynamic_pointer_cast<const NumberNode>(node)) {
103 return get_sign(node);
106 return is_neg_inf(node) ? -1 : 1;
108 return assumed_node_sign(node);
111double LimitVisitor::get_numeric_value(
const std::shared_ptr<const NumberNode>&
num)
const {
112 if (std::holds_alternative<BigInt>(
num->value())) {
113 return std::get<BigInt>(
num->value()).to_double();
115 if (std::holds_alternative<Rational>(
num->value())) {
116 return std::get<Rational>(
num->value()).to_double();
118 return std::numeric_limits<double>::quiet_NaN();
121bool LimitVisitor::is_bounded_product(
const MultiplyNode& node)
const {
122 bool has_bounded =
false;
123 for (
const auto& operand :
node.operands()) {
124 if (is_bounded(operand)) {
126 }
else if (!std::dynamic_pointer_cast<const NumberNode>(operand)) {
133bool LimitVisitor::defined_near_point(
const std::shared_ptr<const SymbolicNode>& node)
const {
134 std::optional<detail::AssumptionFacts> assumed;
135 if (assumption_ctx_) { assumed.emplace(*assumption_ctx_); }
139 if (!obligations) {
throw obligations.error(); }
140 if (!obligations.value()) {
return false; }
142 for (
const auto& condition : *obligations.value())
143 {
if (!witness.condition_holds_near_point(
detail::node(condition))) {
return false; } }
147bool LimitVisitor::is_bounded(
const std::shared_ptr<const SymbolicNode>& node)
const {
148 if (
auto function = std::dynamic_pointer_cast<const FunctionNode>(node)) {
153 if (
auto product = std::dynamic_pointer_cast<const MultiplyNode>(node)) {
154 return is_bounded_product(*product);
156 auto power = std::dynamic_pointer_cast<const PowerNode>(node);
157 if (!power || !is_bounded(power->base())) {
160 auto exponent = std::dynamic_pointer_cast<const NumberNode>(power->exponent());
164bool LimitVisitor::is_bounded_expression(
const std::shared_ptr<const SymbolicNode>& node)
const {
168 if (is_bounded(node)) {
171 auto sum = std::dynamic_pointer_cast<const AddNode>(node);
175 bool has_bounded =
false;
176 for (
const auto& operand : sum->operands()) {
177 if (is_bounded(operand) || is_bounded_expression(operand)) {
179 }
else if (!std::dynamic_pointer_cast<const NumberNode>(operand)) {
186bool LimitVisitor::is_zero_limit(
const std::shared_ptr<const SymbolicNode>& node)
const {
190LimitVisitor::IndeterminateForm LimitVisitor::classify_product_form(
191 const std::vector<std::shared_ptr<const SymbolicNode>>& values) {
193 bool infinity =
false;
194 for (
const auto&
value : values) {
195 if (is_zero_limit(
value)) zero =
true;
196 if (is_inf(
value)) infinity =
true;
198 return zero && infinity ? IndeterminateForm::ZeroTimesInf : IndeterminateForm::None;
201LimitVisitor::IndeterminateForm LimitVisitor::classify_power_form(
202 const std::shared_ptr<const SymbolicNode>& base,
203 const std::shared_ptr<const SymbolicNode>&
exponent) {
204 if (base && base->is_one() && is_inf(
exponent)) {
205 return IndeterminateForm::OnePowInf;
208 return IndeterminateForm::None;
210 if (is_zero_limit(base)) {
211 return IndeterminateForm::ZeroPowZero;
214 return IndeterminateForm::InfPowZero;
216 return IndeterminateForm::None;
219LimitVisitor::IndeterminateForm LimitVisitor::classify_add_form(
220 const std::vector<std::shared_ptr<const SymbolicNode>>& values) {
221 bool positive =
false;
222 bool negative =
false;
223 for (
const auto&
value : values) {
224 if (is_inf(
value) && !is_neg_inf(
value)) positive =
true;
225 if (is_neg_inf(
value)) negative =
true;
227 return positive && negative ? IndeterminateForm::InfMinusInf : IndeterminateForm::None;
230std::shared_ptr<const SymbolicNode> LimitVisitor::signed_infinity(
int sign)
const {
237 std::vector<std::shared_ptr<const SymbolicNode>>{
virtual bool is_zero() const
极限访问器,通过代入和 L'Hôpital 法则计算极限。
int sign(const Rational &value)
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
Result< Tribool > query_nonzero_value(const Node &node, const FactsQuery &facts, Domain domain, ComputationContext &context)
const FactsQuery & no_facts() noexcept
RewriteBudget const FactsQuery & facts
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)
Result< Tribool > query_positive_value(const Node &node, const FactsQuery &facts, ComputationContext &context)
std::shared_ptr< SymbolicExpr > num(int value)
const std::string const LimitExprPtr & point
const std::vector< Polynomial< BigInt > > const BigInt 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)
const std::string const LimitExprPtr LimitDirection direction
@ True
Property definitely holds
@ False
Property definitely does not hold
const std::string const ExprPtr & value
ExprResult function(const std::string &name, std::vector< ExprPtr > arguments)
符号表达式主类 SymbolicExpr 及其工厂方法,运算接口.