15 const std::shared_ptr<const SymbolicNode>& node)
17 auto power = std::dynamic_pointer_cast<const PowerNode>(node);
21 auto number = std::dynamic_pointer_cast<const NumberNode>(power->exponent());
25 const Rational
exponent = std::holds_alternative<BigInt>(number->value())
26 ? Rational(std::get<BigInt>(number->value()))
27 : std::get<Rational>(number->value());
39 const std::shared_ptr<SymbolicExpr>& expr)
52 std::vector<std::shared_ptr<const SymbolicNode>> factors;
53 for (
const auto& operand : multiply->operands()) {
57 if (factors.empty()) {
60 if (factors.size() == 1) {
72 (
context).limits().max_ast_nodes,
"transform");
73 if (factors.empty()) {
74 return SymbolicExpr::number(1);
76 if (factors.size() == 1) {
87 if (std::holds_alternative<BigInt>(number->value())) {
88 return std::get<BigInt>(number->value()) == BigInt(-1);
90 return std::get<Rational>(number->value()) == Rational(-1);
94 const std::shared_ptr<SymbolicExpr>& expr,
95 std::shared_ptr<SymbolicExpr>& numerator,
102 std::vector<std::shared_ptr<const SymbolicNode>> num_factors;
103 std::vector<std::shared_ptr<const SymbolicNode>> den_factors;
105 auto collect_factor = [&](
const std::shared_ptr<const SymbolicNode>& factor) {
106 if (
auto power = std::dynamic_pointer_cast<const PowerNode>(factor)) {
107 auto exponent = std::dynamic_pointer_cast<const NumberNode>(power->exponent());
109 den_factors.push_back(power->base());
113 num_factors.push_back(factor);
116 if (
auto multiply = std::dynamic_pointer_cast<const MultiplyNode>(
LMCAS::detail::node(expr))) {
117 for (
const auto& factor : multiply->operands()) collect_factor(factor);
122 if (den_factors.empty()) {
131 const std::shared_ptr<SymbolicExpr>& f,
132 const std::string& var,
133 std::shared_ptr<SymbolicExpr>& slope,
138 (
context).limits().max_ast_nodes,
"transform");
139 std::shared_ptr<SymbolicExpr> numerator;
148 if (!num_poly || !den_poly || den_poly.value().is_zero()) {
151 auto [quotient, remainder] = num_poly.value().div_mod(den_poly.value());
153 if (quotient.degree() != 1 || quotient.coeffs.size() < 2) {
158 return !slope->is_zero();
159 }
catch (
const std::invalid_argument&) {
161 }
catch (
const std::out_of_range&) {
168 const std::string& operation)
174 const auto& zero_set = solved.
value();
175 const auto* finite = std::get_if<FiniteSolutions>(&zero_set);
176 if (!std::holds_alternative<EmptySolutions>(zero_set) && !finite) {
179 "asymptote denominator zeros are outside the finite exact support domain",
182 std::vector<std::shared_ptr<SymbolicExpr>> zeros;
186 zeros.reserve(finite->values.size());
187 for (
const auto& solution : finite->values) {
191 "checked solver returned a null vertical-asymptote candidate", operation);
197 "checked solver returned a malformed vertical-asymptote candidate", operation);
202 "vertical-asymptote candidate could not be reduced to an exact explicit point",
205 zeros.push_back(candidate);
211 const std::shared_ptr<SymbolicExpr>& f,
const std::string& var,
223 return value && (std::holds_alternative<PositiveInfinityLimit>(
value.value().value) ||
224 std::holds_alternative<NegativeInfinityLimit>(
value.value().value));
226 if (infinite(
right) || infinite(left)) {
return true; }
233 const std::shared_ptr<SymbolicExpr>& f,
const std::string& var,
235 const std::string& operation)
245 for (
const auto&
point : zeros.value()) {
259 const AsymptoteResult& result,
const std::shared_ptr<SymbolicExpr>& slope,
260 const std::shared_ptr<SymbolicExpr>& intercept)
262 for (
const auto& entry : result.
oblique) {
272 const std::shared_ptr<SymbolicExpr>& f,
const std::string& var,
273 const std::shared_ptr<SymbolicExpr>& x_expr,
278 (
context).limits().max_ast_nodes,
"transform");
279 auto quotient = SymbolicExpr::multiply(f,
280 SymbolicExpr::power(x_expr, SymbolicExpr::number(-1)));
286 auto slope = std::move(slope_result.value());
291 auto linear = SymbolicExpr::multiply(slope, x_expr);
292 auto remainder = SymbolicExpr::add(f,
293 SymbolicExpr::multiply(SymbolicExpr::number(-1), linear));
296 if (!intercept_result) {
299 auto intercept = std::move(intercept_result.value());
303 result.
oblique.emplace_back(slope, intercept);
307}
catch (
const CasError& error) {
309}
catch (
const std::bad_alloc&) {
311}
catch (
const std::length_error& error) {
313}
catch (
const std::exception& error) {
321 (
context).limits().max_ast_nodes,
"transform");
329 const std::shared_ptr<SymbolicExpr>& f,
const std::string& var,
330 const std::shared_ptr<SymbolicExpr>& pos_inf,
331 const std::shared_ptr<SymbolicExpr>& neg_inf,
342 auto lim_pos = std::move(positive.value());
343 auto lim_neg = std::move(negative.value());
346 if (horizontal_pos) result.
horizontal.push_back(lim_pos);
347 if (horizontal_neg) {
352 auto x_expr = SymbolicExpr::variable(var);
353 if (!horizontal_pos && !horizontal_neg) {
354 std::shared_ptr<SymbolicExpr> slope;
355 std::shared_ptr<SymbolicExpr> intercept;
357 result.
oblique.emplace_back(slope, intercept);
361 if (!horizontal_pos) {
367 if (!horizontal_neg) {
374 const std::shared_ptr<SymbolicExpr>& f,
const std::string& var,
379 const std::string operation =
"asymptotes";
384 auto pos_inf = SymbolicExpr::infinity(1);
385 auto neg_inf = SymbolicExpr::infinity(-1);
395 }
catch (
const std::bad_alloc&) {
398 }
catch (
const std::exception& ex) {
405 const std::shared_ptr<SymbolicExpr>& f,
const std::string& var)
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success(std::vector< std::shared_ptr< SymbolicExpr > > value)
bool calculus_utils_is_infinity(const std::shared_ptr< SymbolicExpr > &expr)
判断表达式是否包含无穷大节点.
bool calculus_utils_expr_equal(const std::shared_ptr< SymbolicExpr > &a, const std::shared_ptr< SymbolicExpr > &b)
判断两个表达式是否结构相等.
Result< void > calculus_utils_validate_expr(const std::shared_ptr< SymbolicExpr > &expr, const std::string &var, ComputationContext &context, const std::string &operation)
SymbolicNodePtr expand_node(const SymbolicNodePtr &node, RewriteBudget &budget, const FactsQuery &facts, Domain domain)
std::shared_ptr<::LMCAS::SymbolicExpr > make_expression_ptr(SymbolicNodePtr root)
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
bool contains_node_type(const SymbolicNodePtr &root)
std::shared_ptr< const Node > make_node(Args &&... args)
SymbolicNodePtr normalize_node(const SymbolicNodePtr &node, RewriteBudget &budget, const FactsQuery &facts, Domain domain)
const std::string const LimitExprPtr & point
static Result< void > collect_oblique_asymptote(const std::shared_ptr< SymbolicExpr > &f, const std::string &var, const std::shared_ptr< SymbolicExpr > &x_expr, const std::shared_ptr< SymbolicExpr > &infinity, ComputationContext &context, AsymptoteResult &result)
std::shared_ptr< SymbolicExpr > rootof_simplify(const std::shared_ptr< SymbolicExpr > &rootof_expr)
LimitResult limit_checked(const LimitExprPtr &expression, const std::string &variable, const LimitExprPtr &point, LimitDirection direction, ComputationContext &context, Domain domain)
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
AsymptoteAnalysisResult asymptotes_checked(const std::shared_ptr< SymbolicExpr > &f, const std::string &var, ComputationContext &context)
static std::shared_ptr< SymbolicExpr > calculus_utils_product(const std::vector< std::shared_ptr< const SymbolicNode > > &factors, ComputationContext &context)
LMCAS::SolveResult solve_equation(const std::shared_ptr< SymbolicExpr > &expr, const std::string &var, ComputationContext &context, const SolveOptions &opts)
LimitExpressionResult limit_expression_checked(const LimitExprPtr &expression, const std::string &variable, const LimitExprPtr &point, LimitDirection direction, ComputationContext &context, Domain domain)
Result< std::vector< std::shared_ptr< SymbolicExpr > > > SymbolicExprVectorResult
static SymbolicExprVectorResult asymptote_candidates(const std::shared_ptr< SymbolicExpr > &denominator, const std::string &var, ComputationContext &context, const std::string &operation)
static bool simplify_finite_limit(std::shared_ptr< SymbolicExpr > &value, ComputationContext &context)
static Result< bool > is_vertical_asymptote(const std::shared_ptr< SymbolicExpr > &f, const std::string &var, const std::shared_ptr< SymbolicExpr > &point, ComputationContext &context)
Result< Verified< LimitOutcome > > LimitResult
static Result< void > collect_vertical_asymptotes(const std::shared_ptr< SymbolicExpr > &f, const std::string &var, ComputationContext &context, AsymptoteResult &result, const std::string &operation)
static Result< void > collect_infinite_asymptotes(const std::shared_ptr< SymbolicExpr > &f, const std::string &var, const std::shared_ptr< SymbolicExpr > &pos_inf, const std::shared_ptr< SymbolicExpr > &neg_inf, ComputationContext &context, AsymptoteResult &result)
static bool calculus_utils_split_rational(const std::shared_ptr< SymbolicExpr > &expr, std::shared_ptr< SymbolicExpr > &numerator, std::shared_ptr< SymbolicExpr > &denominator, ComputationContext &context)
static bool calculus_utils_is_minus_one(const std::shared_ptr< const NumberNode > &number)
Result< AsymptoteResult > AsymptoteAnalysisResult
const std::string const ExprPtr & value
static bool calculus_utils_oblique_from_rational(const std::shared_ptr< SymbolicExpr > &f, const std::string &var, std::shared_ptr< SymbolicExpr > &slope, std::shared_ptr< SymbolicExpr > &intercept, ComputationContext &context)
static bool has_oblique_asymptote(const AsymptoteResult &result, const std::shared_ptr< SymbolicExpr > &slope, const std::shared_ptr< SymbolicExpr > &intercept)
const ExprPtr & denominator
static std::shared_ptr< SymbolicExpr > calculus_utils_extract_denominator(const std::shared_ptr< SymbolicExpr > &expr)
static std::shared_ptr< const SymbolicNode > denominator_factor(const std::shared_ptr< const SymbolicNode > &node)
方程求解策略调度器 solve_dispatch 及相关选项结构体.
根据左右极限与函数值,在给定上下文假设下证明实数域中的连续性分类。 跳跃与可去间断的比较需证明逐点不等,相等性需保证各值有定义;形式非恒等不足以证明二者。 参数值或有定义性未确定时返回 Inconclu...
std::vector< std::pair< std::shared_ptr< SymbolicExpr >, std::shared_ptr< SymbolicExpr > > > oblique
斜渐近线 (斜率, 截距)
std::vector< std::shared_ptr< SymbolicExpr > > vertical
垂直渐近线 x = a
std::vector< std::shared_ptr< SymbolicExpr > > horizontal
水平渐近线 y = L