LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
integration_weierstrass.cpp
浏览该文件的文档.
4
5namespace LMCAS {
6
7namespace {
8
10 using FT = FunctionNode::FuncType;
11 if (fn.arguments().size() != 1) {
12 return false;
13 }
14 return fn.type() == FT::Sin || fn.type() == FT::Cos ||
15 fn.type() == FT::Tan || fn.type() == FT::Sec ||
16 fn.type() == FT::Csc || fn.type() == FT::Cot;
17}
18
19bool weier_rational_function(const FunctionNode& fn, const std::string& var) {
20 if (weier_trig_function(fn)) {
21 auto variable = std::dynamic_pointer_cast<const VariableNode>(fn.arguments()[0]);
22 if (variable && !variable->is_constant() && variable->name() == var) { return true; }
23 return !expression_depends_on_variable(fn.arguments()[0], var);
24 }
25 for (const auto& argument : fn.arguments()) {
26 if (expression_depends_on_variable(argument, var)) { return false; }
27 }
28 return true;
29}
30
31/// 判断表达式是否仅由 var 通过 sin(var)/cos(var)/tan(var) 以及常数,四则,整数幂构成,
32/// 即关于 sin/cos 的有理函数.含有其它依赖 var 的函数(exp/ln/sqrt 等)时返回 false.
33bool weier_is_rational_trig(const std::shared_ptr<const SymbolicNode>& node, const std::string& var) {
34 if (!node) { return true; }
35 if (auto vn = std::dynamic_pointer_cast<const VariableNode>(node)) {
36 /// 裸 var 表示输入超出 sin/cos 有理函数域.
37 return vn->is_constant() || vn->name() != var;
38 }
39 if (std::dynamic_pointer_cast<const NumberNode>(node)) { return true; }
40 if (auto add = std::dynamic_pointer_cast<const AddNode>(node)) {
41 for (auto& op : add->operands()) if (!weier_is_rational_trig(op, var)) { return false; }
42 return true;
43 }
44 if (auto mul = std::dynamic_pointer_cast<const MultiplyNode>(node)) {
45 for (auto& op : mul->operands()) if (!weier_is_rational_trig(op, var)) { return false; }
46 return true;
47 }
48 if (auto pw = std::dynamic_pointer_cast<const PowerNode>(node)) {
49 /// 指数必须是不依赖 var 的整数常数
50 auto en = std::dynamic_pointer_cast<const NumberNode>(pw->exponent());
51 if (!en) { return false; }
52 return weier_is_rational_trig(pw->base(), var);
53 }
54 if (auto fn = std::dynamic_pointer_cast<const FunctionNode>(node)) {
55 return weier_rational_function(*fn, var);
56 }
57 return false;
58}
59
60bool weier_trig_of_variable(const FunctionNode& function, const std::string& var) {
62 return false;
63 }
64 auto argument = std::dynamic_pointer_cast<const VariableNode>(function.arguments()[0]);
65 return argument && !argument->is_constant() && argument->name() == var;
66}
67
68/// 是否至少包含一个 sin(var)/cos(var)/tan(var)... 形式(确保确实是三角有理函数)
69bool weier_has_trig_of_var(const std::shared_ptr<const SymbolicNode>& node, const std::string& var) {
70 if (!node) { return false; }
71 if (auto fn = std::dynamic_pointer_cast<const FunctionNode>(node)) {
72 if (weier_trig_of_variable(*fn, var)) {
73 return true;
74 }
75 for (auto& a : fn->arguments()) if (weier_has_trig_of_var(a, var)) { return true; }
76 return false;
77 }
78 if (auto add = std::dynamic_pointer_cast<const AddNode>(node)) {
79 for (auto& op : add->operands()) if (weier_has_trig_of_var(op, var)) { return true; }
80 return false;
81 }
82 if (auto mul = std::dynamic_pointer_cast<const MultiplyNode>(node)) {
83 for (auto& op : mul->operands()) if (weier_has_trig_of_var(op, var)) { return true; }
84 return false;
85 }
86 if (auto pw = std::dynamic_pointer_cast<const PowerNode>(node)) {
87 return weier_has_trig_of_var(pw->base(), var) || weier_has_trig_of_var(pw->exponent(), var);
88 }
89 return false;
90}
91
92std::shared_ptr<const SymbolicNode> weier_replace_function(
93 const FunctionNode& fn, const std::string& var, const std::string& tvar) {
94 using FT = FunctionNode::FuncType;
95 if (fn.arguments().size() != 1) {
96 return nullptr;
97 }
98 auto av = std::dynamic_pointer_cast<const VariableNode>(fn.arguments()[0]);
99 if (!av || av->is_constant() || av->name() != var) {
100 return nullptr;
101 }
102 auto t = SymbolicExpr::variable(tvar);
103 auto one = SymbolicExpr::number(1);
104 auto t2 = SymbolicExpr::power(t, SymbolicExpr::number(2));
105 auto onep = SymbolicExpr::add(one, t2); /**< 多项式 1+t^2。 */
106 auto onem = SymbolicExpr::add(one, SymbolicExpr::multiply(SymbolicExpr::number(-1), t2)); /**< 多项式 1-t^2。 */
107 auto two_t = SymbolicExpr::multiply(SymbolicExpr::number(2), t);
108 switch (fn.type()) {
109 case FT::Sin: {
110 return LMCAS::detail::node(SymbolicExpr::divide(two_t, onep));
111 }
112 case FT::Cos: {
113 return LMCAS::detail::node(SymbolicExpr::divide(onem, onep));
114 }
115 case FT::Tan: {
116 return LMCAS::detail::node(SymbolicExpr::divide(two_t, onem));
117 }
118 case FT::Csc: {
119 return LMCAS::detail::node(SymbolicExpr::divide(onep, two_t));
120 }
121 case FT::Sec: {
122 return LMCAS::detail::node(SymbolicExpr::divide(onep, onem));
123 }
124 case FT::Cot: {
125 return LMCAS::detail::node(SymbolicExpr::divide(onem, two_t));
126 }
127 default: break;
128 }
129 return nullptr;
130}
131
132std::shared_ptr<const SymbolicNode> weier_replace(const std::shared_ptr<const SymbolicNode>& node,
133 const std::string& var, const std::string& tvar) {
134 if (!node) { return node; }
135 if (auto fn = std::dynamic_pointer_cast<const FunctionNode>(node)) {
136 auto replaced = weier_replace_function(*fn, var, tvar);
137 if (replaced) { return replaced; }
138 /// 其它函数:递归替换参数
139 std::vector<std::shared_ptr<const SymbolicNode>> new_args;
140 for (auto& a : fn->arguments()) new_args.push_back(weier_replace(a, var, tvar));
141 return LMCAS::detail::make_node<FunctionNode>(fn->type(), new_args);
142 }
143 if (auto add = std::dynamic_pointer_cast<const AddNode>(node)) {
144 std::vector<std::shared_ptr<const SymbolicNode>> ops;
145 for (auto& op : add->operands()) ops.push_back(weier_replace(op, var, tvar));
147 }
148 if (auto mul = std::dynamic_pointer_cast<const MultiplyNode>(node)) {
149 std::vector<std::shared_ptr<const SymbolicNode>> ops;
150 for (auto& op : mul->operands()) ops.push_back(weier_replace(op, var, tvar));
152 }
153 if (auto pw = std::dynamic_pointer_cast<const PowerNode>(node)) {
154 return LMCAS::detail::make_node<PowerNode>(weier_replace(pw->base(), var, tvar),
155 weier_replace(pw->exponent(), var, tvar));
156 }
157 return node->clone();
158}
159
160/// 递归求值已执行 sin/cos->t 代换的表达式,生成关于 t 的多项式分子与分母;
161/// nullopt 表示当前节点位于有理函数支持域之外.
162typedef std::pair<std::shared_ptr<SymbolicExpr>, std::shared_ptr<SymbolicExpr>> RatPair;
163std::optional<RatPair> weier_to_rational(
164 const std::shared_ptr<const SymbolicNode>& node, const std::string& tvar, ComputationContext& context);
165
166std::optional<RatPair> weier_rational_power(const PowerNode& pw, const std::string& tvar,
167 const std::shared_ptr<SymbolicExpr>& one, ComputationContext& context) {
168
169 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
170 (context).limits().max_ast_nodes, "transform");
171 auto en = std::dynamic_pointer_cast<const NumberNode>(pw.exponent());
172 if (!en) { return std::nullopt; }
173 const auto bounded_exponent = integration_bounded_exponent(*en, -32, 32);
174 if (!bounded_exponent) { return std::nullopt; }
175
176 auto base = weier_to_rational(pw.base(), tvar, context);
177 if (!base) { return std::nullopt; }
178 auto [bn, bd] = *base;
179 const bool neg = *bounded_exponent < 0;
180 const int power_count = neg ? -*bounded_exponent : *bounded_exponent;
181 std::shared_ptr<SymbolicExpr> num = one, den = one;
182 for (int i = 0; i < power_count; ++i) {
183 num = detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::multiply(num, bn)), transform_budget));
184 den = detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::multiply(den, bd)), transform_budget));
185 }
186 if (neg) std::swap(num, den);
187 return RatPair{num, den};
188}
189
190std::optional<RatPair> weier_to_rational(const std::shared_ptr<const SymbolicNode>& node,
191 const std::string& tvar, ComputationContext& context) {
192
193 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
194 (context).limits().max_ast_nodes, "transform");
195 auto one = SymbolicExpr::number(1);
196 if (!node) { return RatPair{SymbolicExpr::number(0), one}; }
197
198 if (std::dynamic_pointer_cast<const NumberNode>(node) ||
199 std::dynamic_pointer_cast<const VariableNode>(node)) {
201 }
202 if (auto add = std::dynamic_pointer_cast<const AddNode>(node)) {
203 /// 累加:a/b + c/d = (a*d + c*b)/(b*d)
204 std::shared_ptr<SymbolicExpr> num = SymbolicExpr::number(0);
205 std::shared_ptr<SymbolicExpr> den = one;
206 for (auto& op : add->operands()) {
207 auto r = weier_to_rational(op, tvar, context);
208 if (!r) { return std::nullopt; }
209 auto [n2, d2] = *r;
210 auto new_num = SymbolicExpr::add(
211 SymbolicExpr::multiply(num, d2), SymbolicExpr::multiply(n2, den));
212 den = detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::multiply(den, d2)), transform_budget));
214 }
215 return RatPair{num, den};
216 }
217 if (auto mul = std::dynamic_pointer_cast<const MultiplyNode>(node)) {
218 std::shared_ptr<SymbolicExpr> num = one;
219 std::shared_ptr<SymbolicExpr> den = one;
220 for (auto& op : mul->operands()) {
221 auto r = weier_to_rational(op, tvar, context);
222 if (!r) { return std::nullopt; }
223 auto [n2, d2] = *r;
224 num = detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::multiply(num, n2)), transform_budget));
225 den = detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::multiply(den, d2)), transform_budget));
226 }
227 return RatPair{num, den};
228 }
229 if (auto pw = std::dynamic_pointer_cast<const PowerNode>(node)) {
230 return weier_rational_power(*pw, tvar, one, context);
231 }
232 /// 其他节点结构由 nullopt 标记为 t 有理函数域之外.
233 return std::nullopt;
234}
235
237 const std::shared_ptr<SymbolicExpr>& num_poly,
238 const std::shared_ptr<SymbolicExpr>& den_poly, const std::string& tvar, ComputationContext& context) try {
239
240 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
241 (context).limits().max_ast_nodes, "transform");
242 auto numerator = symbolic_to_poly<Rational>(detail::make_expression_ptr(detail::expand_node(detail::node(num_poly), transform_budget)), tvar);
243 if (!numerator && numerator.error().code != CasErrc::UnsupportedExpression) {
244 return Result<std::shared_ptr<SymbolicExpr>>::failure(numerator.error());
245 }
246 auto denominator = symbolic_to_poly<Rational>(detail::make_expression_ptr(detail::expand_node(detail::node(den_poly), transform_budget)), tvar);
248 return Result<std::shared_ptr<SymbolicExpr>>::failure(denominator.error());
249 }
250 if (!numerator || !denominator) { return SymbolicExpr::divide(num_poly, den_poly); }
251 auto Np = std::move(numerator.value());
252 auto Dp = std::move(denominator.value());
253 if (Dp.is_zero()) { return SymbolicExpr::divide(num_poly, den_poly); }
254 auto g = Polynomial<Rational>::gcd(Np, Dp);
255 if (g.degree() >= 1) {
256 auto [q1, r1] = Np.div_mod(g);
257 auto [q2, r2] = Dp.div_mod(g);
258 if (r1.is_zero() && r2.is_zero()) { Np = q1; Dp = q2; }
259 }
260 auto np_expr = poly_to_symbolic(Np);
261 auto dp_expr = poly_to_symbolic(Dp);
262 return SymbolicExpr::divide(np_expr, dp_expr);
263} catch (const CasError& error) {
264 return Result<std::shared_ptr<SymbolicExpr>>::failure(error);
265}
266
267
268}
269
270Result<std::optional<detail::IntegralParts>> Integrator::try_weierstrass(
271 const SymbolicExpr& expr, const std::string& var,
272 ComputationContext& computation, int depth) try {
273 detail::RewriteBudget transform_budget(computation, (computation).limits().max_recursion_depth,
274 (computation).limits().max_ast_nodes, "transform");
275 if (!LMCAS::detail::node(expr)) { return std::optional<detail::IntegralParts>{}; }
276
277 /// 必须确实含有 sin/cos(var) 且整体为其有理函数
279 return std::optional<detail::IntegralParts>{};
280 }
282 return std::optional<detail::IntegralParts>{};
283 }
284
285 std::string tvar = "__weier_t";
286 std::size_t suffix = 0;
287 while (cycle_state_.occupied_names.count(tvar)) {
288 transform_budget.consume();
289 tvar = "__weier_t_" + std::to_string(suffix++);
290 }
291 cycle_state_.occupied_names.insert(tvar);
292
293 /// 替换 sin/cos -> t 的有理式,并乘以 dx = 2/(1+t^2) dt
295 auto t = SymbolicExpr::variable(tvar);
296 auto t2 = SymbolicExpr::power(t, SymbolicExpr::number(2));
297 auto onep = SymbolicExpr::add(SymbolicExpr::number(1), t2);
298 auto dx = SymbolicExpr::divide(SymbolicExpr::number(2), onep); // 2/(1+t^2)
299 auto integrand_raw = SymbolicExpr::multiply(replaced, dx);
300
301 /// sin/cos 有理函数经代换后仍为 t 的有理函数.
302 /// 通过多项式对递归求值整棵表达式树,直接得到 N(t)/D(t).
303 auto rat = weier_to_rational(LMCAS::detail::node(integrand_raw), tvar, computation);
304 if (!rat) { return std::optional<detail::IntegralParts>{}; }
305 auto [num_poly, den_poly] = *rat;
306 if (!den_poly || LMCAS::detail::node(den_poly)->is_zero()) {
307 return std::optional<detail::IntegralParts>{};
308 }
309
310 /// 使用多项式 GCD 将 num/den 化为最简有理函数,并保持单一分式结构.
311 auto reduced = weier_reduce_rational(num_poly, den_poly, tvar, computation);
312 if (!reduced) {
313 return Result<std::optional<detail::IntegralParts>>::failure(reduced.error());
314 }
315 auto integrand_t = std::move(reduced.value());
316 Integrator inner;
317 inner.cycle_state_.occupied_names = detail::all_variable_names(
318 detail::node(integrand_t), &transform_budget);
319 inner.cycle_state_.occupied_names.insert(tvar);
320 if (computation.assumptions()) {
322 *computation.assumptions(), inner.cycle_state_.occupied_names, transform_budget);
323 }
324 auto attempted = inner.try_rational_decomposition(
325 *integrand_t, tvar, computation, depth + 1);
326 if (!attempted) {
327 return Result<std::optional<detail::IntegralParts>>::failure(attempted.error());
328 }
329 std::optional<detail::IntegralParts> integrated;
330 if (attempted.value() && detail::node(attempted.value()->remainder)->is_zero() &&
331 !inner.has_cycle_placeholder(attempted.value()->primitive) &&
332 !inner.has_cycle_placeholder(attempted.value()->remainder)) {
333 integrated = std::move(*attempted.value());
334 }
335 if (!integrated) {
336 auto recursive = inner.integrate_recursive(*integrand_t, tvar, computation, 0);
337 if (!recursive) {
338 return Result<std::optional<detail::IntegralParts>>::failure(recursive.error());
339 }
340 integrated = std::move(recursive.value());
341 }
342 if (!detail::node(integrated->remainder)->is_zero() ||
343 inner.has_cycle_placeholder(integrated->primitive) ||
344 inner.has_cycle_placeholder(integrated->remainder) ||
345 contains_unevaluated_integral(detail::node(integrated->primitive))) {
346 return std::optional<detail::IntegralParts>{};
347 }
348
349 /// 回代 t = tan(x/2)
350 auto half_x = SymbolicExpr::multiply(SymbolicExpr::number(Rational(1, 2)),
351 SymbolicExpr::variable(var));
353 FunctionNode::FuncType::Tan, std::vector<std::shared_ptr<const SymbolicNode>>{LMCAS::detail::node(half_x)}));
354 auto result = detail::substitute_node(
355 detail::node(integrated->primitive), tvar, detail::node(tan_half), transform_budget);
356 auto primitive = detail::expression_from_node(detail::normalize_node(result, transform_budget));
357 if (depends_on_integration_variable(primitive, tvar)) {
358 return std::optional<detail::IntegralParts>{};
359 }
360 return std::optional<detail::IntegralParts>{{std::move(primitive), zero_}};
361} catch (const CasError& error) {
362 return Result<std::optional<detail::IntegralParts>>::failure(error);
363}
364
365}
函数节点,表示数学函数调用(三角函数、对数、特殊函数等)。
FuncType type() const noexcept
const std::vector< std::shared_ptr< const SymbolicNode > > & arguments() const noexcept
static Polynomial gcd(Polynomial a, Polynomial b)
计算两个多项式的最大公因式
幂运算节点,表示 base^exponent。
const std::shared_ptr< const SymbolicNode > & exponent() const noexcept
const std::shared_ptr< const SymbolicNode > & base() const noexcept
virtual std::shared_ptr< const SymbolicNode > clone() const =0
static void collect_names(const AssumptionContext &assumptions, std::set< std::string > &names, RewriteBudget &budget)
std::pair< std::shared_ptr< SymbolicExpr >, std::shared_ptr< SymbolicExpr > > RatPair
递归求值已执行 sin/cos->t 代换的表达式,生成关于 t 的多项式分子与分母; nullopt 表示当前节点位于有理函数支持域之外.
bool weier_is_rational_trig(const std::shared_ptr< const SymbolicNode > &node, const std::string &var)
判断表达式是否仅由 var 通过 sin(var)/cos(var)/tan(var) 以及常数,四则,整数幂构成, 即关于 sin/cos 的有理函数.含有其它依赖 var 的函数(exp/ln/sq...
bool weier_rational_function(const FunctionNode &fn, const std::string &var)
std::optional< RatPair > weier_to_rational(const std::shared_ptr< const SymbolicNode > &node, const std::string &tvar, ComputationContext &context)
std::shared_ptr< const SymbolicNode > weier_replace_function(const FunctionNode &fn, const std::string &var, const std::string &tvar)
std::shared_ptr< const SymbolicNode > weier_replace(const std::shared_ptr< const SymbolicNode > &node, const std::string &var, const std::string &tvar)
bool weier_trig_of_variable(const FunctionNode &function, const std::string &var)
Result< std::shared_ptr< SymbolicExpr > > weier_reduce_rational(const std::shared_ptr< SymbolicExpr > &num_poly, const std::shared_ptr< SymbolicExpr > &den_poly, const std::string &tvar, ComputationContext &context)
bool weier_has_trig_of_var(const std::shared_ptr< const SymbolicNode > &node, const std::string &var)
是否至少包含一个 sin(var)/cos(var)/tan(var)... 形式(确保确实是三角有理函数)
std::optional< RatPair > weier_rational_power(const PowerNode &pw, const std::string &tvar, const std::shared_ptr< SymbolicExpr > &one, ComputationContext &context)
bool is_zero(const SymbolicExpr &expression)
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
inline ::LMCAS::SymbolicExpr expression_from_node(SymbolicNodePtr root)
std::shared_ptr< const Node > make_node(Args &&... args)
SymbolicNodePtr normalize_node(const SymbolicNodePtr &node, RewriteBudget &budget, const FactsQuery &facts, Domain domain)
std::set< std::string > all_variable_names(const SymbolicNodePtr &expression, RewriteBudget *budget=nullptr)
SymbolicNodePtr substitute_node(const SymbolicNodePtr &node, const std::string &variable, const SymbolicNodePtr &replacement, RewriteBudget &budget, const FactsQuery &facts, Domain domain)
std::shared_ptr< SymbolicExpr > num(int value)
const std::string & variable
__attribute__((visibility("default"))) ComplexSymbolicResult complex_exp_form_checked(std __attribute__((visibility("default"))) ComplexSymbolicResult complex_exp_form_checked(std __attribute__((visibility("default"))) ComplexSymbolicResult complex_trig_form_checked(std __attribute__((visibility("default"))) ComplexSymbolicResult complex_trig_form_checked(std __attribute__((visibility("default"))) ComplexRootsResult solve_complex_nth_root_checked(std __attribute__((visibility("default"))) ComplexRootsResult solve_complex_nth_root_checked(std __attribute__((visibility("default"))) ComplexRootsResult solve_complex_quadratic_checked(std __attribute__((visibility("default"))) ComplexRootsResult solve_complex_quadratic_checked(std std::shared_ptr< SymbolicExpr > r
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
ExprResult neg(const ExprPtr &expression, ComputationContext &context)
bool contains_unevaluated_integral(const std::shared_ptr< const SymbolicNode > &node)
@ Rational
Rational numbers
ExprResult mul(const ExprPtr &lhs, const ExprPtr &rhs, ComputationContext &context)
bool expression_depends_on_variable(const detail::SymbolicNodePtr &expression, const std::string &variable, detail::RewriteBudget *budget)
ExprResult add(const ExprPtr &lhs, const ExprPtr &rhs, ComputationContext &context)
bool depends_on_integration_variable(const SymbolicExpr &expression, const std::string &variable)
const ExprPtr RelationOp op
__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
std::size_t std::size_t depth
std::optional< int > integration_bounded_exponent(const NumberNode &number, int minimum_exponent, int maximum_exponent)
const ExprPtr & denominator
ExprResult function(const std::string &name, std::vector< ExprPtr > arguments)
__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 & t