LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
integration_trig_substitution.cpp
浏览该文件的文档.
4
5namespace LMCAS {
6
7namespace {
8
9// 标准二次根式使用精确有理系数,保留原被积式的指数和尺度。
11 int pattern = 0; // 1: a²-x², 2: a²+x², 3: x²-a²
12 Rational exponent{0};
13 Rational a_sq{0};
14};
15
16bool trigsub_half_exponent(const NumberNode& number, Rational& exponent) {
17 const auto exact = detail::exact_rational_value(number);
18 if (!exact || (*exact != Rational(1, 2) && *exact != Rational(-1, 2))) {
19 return false;
20 }
21 exponent = *exact;
22 return true;
23}
24
26 const std::string& var, ComputationContext& context, Rational& c0, Rational& c2) {
27 auto polynomial = recognize_rational_polynomial(
29 if (!polynomial) { throw polynomial.error(); }
30 if (!polynomial.value() || polynomial.value()->degree() != 2) { return false; }
31 const auto& coefficients = polynomial.value()->coeffs;
32 if (coefficients[1] != Rational(0) ||
33 (coefficients[2] != Rational(1) && coefficients[2] != Rational(-1))) {
34 return false;
35 }
36 c0 = coefficients[0];
37 c2 = coefficients[2];
38 return true;
39}
40
41bool trigsub_match_radical(const std::shared_ptr<const SymbolicNode>& node,
42 const std::string& var,
44 QuadRadical& out) {
45 auto pw = std::dynamic_pointer_cast<const PowerNode>(node);
46 if (!pw) { return false; }
47 auto en = std::dynamic_pointer_cast<const NumberNode>(pw->exponent());
48 if (!en) { return false; }
49 Rational exponent;
50 auto radicand = pw->base();
51 const auto outer = detail::exact_rational_value(*en);
52 if (outer && *outer == Rational(-1)) {
53 if (const auto* root = dynamic_cast<const PowerNode*>(radicand.get())) {
54 const auto inner = detail::exact_rational_value(root->exponent());
55 if (!inner || *inner != Rational(1, 2)) { return false; }
56 radicand = root->base();
57 } else if (const auto* root = dynamic_cast<const FunctionNode*>(radicand.get());
58 root && root->type() == FunctionNode::FuncType::Sqrt &&
59 root->arguments().size() == 1) {
60 radicand = root->arguments()[0];
61 } else {
62 return false;
63 }
64 exponent = Rational(-1, 2);
65 } else if (!trigsub_half_exponent(*en, exponent)) {
66 return false;
67 }
68 Rational c0, c2;
69 if (!trigsub_quadratic_coefficients(radicand, var, context, c0, c2)) { return false; }
70 out.exponent = exponent;
71 if (c2 < Rational(0) && c0 > Rational(0)) { out.pattern = 1; out.a_sq = c0; }
72 else if (c2 > Rational(0) && c0 > Rational(0)) { out.pattern = 2; out.a_sq = c0; }
73 else if (c2 > Rational(0) && c0 < Rational(0)) { out.pattern = 3; out.a_sq = Rational(0) - c0; }
74 else return false;
75 return true;
76}
77
78} // anonymous namespace
79
80Result<std::optional<detail::IntegralParts>> Integrator::try_trig_substitution(
81 const SymbolicExpr& expr, const std::string& var,
82 ComputationContext& context, int) try {
83 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
84 (context).limits().max_ast_nodes, "transform");
85 if (!LMCAS::detail::node(expr)) { return std::optional<detail::IntegralParts>{}; }
86
87 auto x = SymbolicExpr::variable(var);
88
89 /// 仅处理被积函数恰为单个二次根式幂的常见闭式情形:
90 /// ∫ (a²-x²)^(-1/2) dx = arcsin(x/a)
91 /// ∫ (a²+x²)^(-1/2) dx = arcsinh(x/a) = ln(x + √(x²+a²))
92 /// ∫ (x²-a²)^(-1/2) dx = arccosh(x/a) = ln(x + √(x²-a²))
93 /// ∫ (a²-x²)^( 1/2) dx = (x/2)√(a²-x²) + (a²/2)arcsin(x/a)
94 QuadRadical qr;
96 LMCAS::detail::node(expr), var, context, qr)) {
97 return std::optional<detail::IntegralParts>{};
98 }
99
100 auto a_sq_expr = SymbolicExpr::number(qr.a_sq);
101 auto a_expr = SymbolicExpr::sqrt(a_sq_expr); // a = √(a²)
102
103 /// 构造 √(模式) 表达式
104 auto x_sq = SymbolicExpr::power(x, SymbolicExpr::number(2));
105 auto make_radicand = [&]() -> std::shared_ptr<SymbolicExpr> {
106 if (qr.pattern == 1) // a²-x²
107 return SymbolicExpr::add(a_sq_expr, SymbolicExpr::multiply(SymbolicExpr::number(-1), x_sq));
108 if (qr.pattern == 2) // a²+x²
109 return SymbolicExpr::add(a_sq_expr, x_sq);
110 return SymbolicExpr::add(x_sq, SymbolicExpr::multiply(SymbolicExpr::number(-1), a_sq_expr)); // x²-a²
111 };
112 auto x_over_a = SymbolicExpr::divide(x, a_expr);
113
114 auto arcsin = [&](const std::shared_ptr<SymbolicExpr>& u) {
116 FunctionNode::FuncType::ArcSin, std::vector<std::shared_ptr<const SymbolicNode>>{LMCAS::detail::node(u)}));
117 };
118 auto ln = [&](const std::shared_ptr<SymbolicExpr>& u) { return SymbolicExpr::ln(u); };
119
120 if (qr.exponent < Rational(0)) {
121 /// (...)^(-1/2)
122 if (qr.pattern == 1) {
123 /// arcsin(x/a)
124 return std::optional<detail::IntegralParts>{{detail::expression_from_node(
125 detail::normalize_node(detail::node(arcsin(x_over_a)), transform_budget)), zero_}};
126 }
127 if (qr.pattern == 2) {
128 /// ln(x + √(x²+a²))
129 auto rad = SymbolicExpr::sqrt(SymbolicExpr::add(x_sq, a_sq_expr));
130 return std::optional<detail::IntegralParts>{{detail::expression_from_node(
131 detail::normalize_node(detail::node(ln(SymbolicExpr::add(x, rad))), transform_budget)), zero_}};
132 }
133 /// pattern 3: ln(x + √(x²-a²))
134 auto rad = SymbolicExpr::sqrt(SymbolicExpr::add(x_sq,
135 SymbolicExpr::multiply(SymbolicExpr::number(-1), a_sq_expr)));
136 return std::optional<detail::IntegralParts>{{detail::expression_from_node(
137 detail::normalize_node(detail::node(ln(SymbolicExpr::add(x, rad))), transform_budget)), zero_}};
138 } else {
139 /// (...)^(+1/2)
140 auto rad = SymbolicExpr::sqrt(make_radicand());
141 auto half = SymbolicExpr::number(Rational(1, 2));
142 if (qr.pattern == 1) {
143 /// (x/2)√(a²-x²) + (a²/2)arcsin(x/a)
144 auto term1 = SymbolicExpr::multiply(SymbolicExpr::multiply(half, x), rad);
145 auto term2 = SymbolicExpr::multiply(SymbolicExpr::multiply(half, a_sq_expr), arcsin(x_over_a));
146 return std::optional<detail::IntegralParts>{{detail::expression_from_node(
147 detail::normalize_node(detail::node(SymbolicExpr::add(term1, term2)), transform_budget)), zero_}};
148 }
149 if (qr.pattern == 2) {
150 /// (x/2)√(a²+x²) + (a²/2)ln(x+√(x²+a²))
151 auto lrad = SymbolicExpr::sqrt(SymbolicExpr::add(x_sq, a_sq_expr));
152 auto term1 = SymbolicExpr::multiply(SymbolicExpr::multiply(half, x), rad);
153 auto term2 = SymbolicExpr::multiply(SymbolicExpr::multiply(half, a_sq_expr),
154 ln(SymbolicExpr::add(x, lrad)));
155 return std::optional<detail::IntegralParts>{{detail::expression_from_node(
156 detail::normalize_node(detail::node(SymbolicExpr::add(term1, term2)), transform_budget)), zero_}};
157 }
158 /// pattern 3: (x/2)√(x²-a²) - (a²/2)ln(x+√(x²-a²))
159 auto lrad = SymbolicExpr::sqrt(SymbolicExpr::add(x_sq,
160 SymbolicExpr::multiply(SymbolicExpr::number(-1), a_sq_expr)));
161 auto term1 = SymbolicExpr::multiply(SymbolicExpr::multiply(half, x), rad);
162 auto term2 = SymbolicExpr::multiply(
163 SymbolicExpr::multiply(SymbolicExpr::multiply(SymbolicExpr::number(-1), half), a_sq_expr),
164 ln(SymbolicExpr::add(x, lrad)));
165 return std::optional<detail::IntegralParts>{{detail::expression_from_node(
166 detail::normalize_node(detail::node(SymbolicExpr::add(term1, term2)), transform_budget)), zero_}};
167 }
168} catch (const CasError& error) {
169 return Result<std::optional<detail::IntegralParts>>::failure(error);
170}
171
172}
函数节点,表示数学函数调用(三角函数、对数、特殊函数等)。
FuncType type() const noexcept
@ Sqrt
对数、绝对值、平方根。
幂运算节点,表示 base^exponent。
bool trigsub_match_radical(const std::shared_ptr< const SymbolicNode > &node, const std::string &var, ComputationContext &context, QuadRadical &out)
bool trigsub_quadratic_coefficients(const detail::SymbolicNodePtr &radicand, const std::string &var, ComputationContext &context, Rational &c0, Rational &c2)
std::shared_ptr<::LMCAS::SymbolicExpr > make_expression_ptr(SymbolicNodePtr root)
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
std::shared_ptr< const SymbolicNode > SymbolicNodePtr
inline ::LMCAS::SymbolicExpr expression_from_node(SymbolicNodePtr root)
std::shared_ptr< const Node > make_node(Args &&... args)
std::optional< Rational > exact_rational_value(const NumberNode &number)
SymbolicNodePtr normalize_node(const SymbolicNodePtr &node, RewriteBudget &budget, const FactsQuery &facts, Domain domain)
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
@ Rational
Rational numbers
const ExprPtr & exponent
Result< OptionalRationalPolynomial > recognize_rational_polynomial(const SymbolicExpr &expression, const std::string &variable, ComputationContext &context)
__attribute__((visibility("default"))) VectorCalculusExprResult surface_integral_scalar_checked(const std __attribute__((visibility("default"))) VectorCalculusExprResult surface_integral_scalar_checked(const std __attribute__((visibility("default"))) std const VectorField const std::string & u
符号表达式与一元多项式的转换。