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;
25 for (
const auto& argument : fn.
arguments()) {
34 if (!node) {
return true; }
35 if (
auto vn = std::dynamic_pointer_cast<const VariableNode>(node)) {
37 return vn->is_constant() || vn->name() != var;
39 if (std::dynamic_pointer_cast<const NumberNode>(node)) {
return true; }
40 if (
auto add = std::dynamic_pointer_cast<const AddNode>(node)) {
44 if (
auto mul = std::dynamic_pointer_cast<const MultiplyNode>(node)) {
48 if (
auto pw = std::dynamic_pointer_cast<const PowerNode>(node)) {
50 auto en = std::dynamic_pointer_cast<const NumberNode>(pw->exponent());
51 if (!en) {
return false; }
54 if (
auto fn = std::dynamic_pointer_cast<const FunctionNode>(node)) {
64 auto argument = std::dynamic_pointer_cast<const VariableNode>(
function.arguments()[0]);
65 return argument && !argument->is_constant() && argument->name() == var;
70 if (!node) {
return false; }
71 if (
auto fn = std::dynamic_pointer_cast<const FunctionNode>(node)) {
78 if (
auto add = std::dynamic_pointer_cast<const AddNode>(node)) {
82 if (
auto mul = std::dynamic_pointer_cast<const MultiplyNode>(node)) {
86 if (
auto pw = std::dynamic_pointer_cast<const PowerNode>(node)) {
93 const FunctionNode& fn,
const std::string& var,
const std::string& tvar) {
98 auto av = std::dynamic_pointer_cast<const VariableNode>(fn.
arguments()[0]);
99 if (!av || av->is_constant() || av->name() != var) {
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);
106 auto onem = SymbolicExpr::add(one, SymbolicExpr::multiply(SymbolicExpr::number(-1), t2));
107 auto two_t = SymbolicExpr::multiply(SymbolicExpr::number(2),
t);
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)) {
137 if (replaced) {
return replaced; }
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));
143 if (
auto add = std::dynamic_pointer_cast<const AddNode>(node)) {
144 std::vector<std::shared_ptr<const SymbolicNode>> ops;
148 if (
auto mul = std::dynamic_pointer_cast<const MultiplyNode>(node)) {
149 std::vector<std::shared_ptr<const SymbolicNode>> ops;
153 if (
auto pw = std::dynamic_pointer_cast<const PowerNode>(node)) {
157 return node->
clone();
162typedef std::pair<std::shared_ptr<SymbolicExpr>, std::shared_ptr<SymbolicExpr>>
RatPair;
170 (
context).limits().max_ast_nodes,
"transform");
171 auto en = std::dynamic_pointer_cast<const NumberNode>(pw.
exponent());
172 if (!en) {
return std::nullopt; }
174 if (!bounded_exponent) {
return std::nullopt; }
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) {
186 if (
neg) std::swap(
num, den);
194 (
context).limits().max_ast_nodes,
"transform");
195 auto one = SymbolicExpr::number(1);
196 if (!node) {
return RatPair{SymbolicExpr::number(0), one}; }
198 if (std::dynamic_pointer_cast<const NumberNode>(node) ||
199 std::dynamic_pointer_cast<const VariableNode>(node)) {
202 if (
auto add = std::dynamic_pointer_cast<const AddNode>(node)) {
204 std::shared_ptr<SymbolicExpr>
num = SymbolicExpr::number(0);
205 std::shared_ptr<SymbolicExpr> den = one;
206 for (
auto&
op :
add->operands()) {
208 if (!
r) {
return std::nullopt; }
210 auto new_num = SymbolicExpr::add(
211 SymbolicExpr::multiply(
num, d2), SymbolicExpr::multiply(n2, den));
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()) {
222 if (!
r) {
return std::nullopt; }
229 if (
auto pw = std::dynamic_pointer_cast<const PowerNode>(node)) {
237 const std::shared_ptr<SymbolicExpr>& num_poly,
241 (
context).limits().max_ast_nodes,
"transform");
250 if (!numerator || !
denominator) {
return SymbolicExpr::divide(num_poly, den_poly); }
251 auto Np = std::move(numerator.value());
253 if (Dp.is_zero()) {
return SymbolicExpr::divide(num_poly, den_poly); }
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; }
260 auto np_expr = poly_to_symbolic(Np);
261 auto dp_expr = poly_to_symbolic(Dp);
262 return SymbolicExpr::divide(np_expr, dp_expr);
271 const SymbolicExpr& expr,
const std::string& var,
274 (computation).limits().max_ast_nodes,
"transform");
279 return std::optional<detail::IntegralParts>{};
282 return std::optional<detail::IntegralParts>{};
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++);
291 cycle_state_.occupied_names.insert(tvar);
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);
299 auto integrand_raw = SymbolicExpr::multiply(replaced, dx);
304 if (!rat) {
return std::optional<detail::IntegralParts>{}; }
305 auto [num_poly, den_poly] = *rat;
307 return std::optional<detail::IntegralParts>{};
315 auto integrand_t = std::move(reduced.value());
319 inner.cycle_state_.occupied_names.insert(tvar);
320 if (computation.assumptions()) {
322 *computation.assumptions(), inner.cycle_state_.occupied_names, transform_budget);
324 auto attempted = inner.try_rational_decomposition(
325 *integrand_t, tvar, computation,
depth + 1);
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());
336 auto recursive = inner.integrate_recursive(*integrand_t, tvar, computation, 0);
340 integrated = std::move(recursive.value());
343 inner.has_cycle_placeholder(integrated->primitive) ||
344 inner.has_cycle_placeholder(integrated->remainder) ||
346 return std::optional<detail::IntegralParts>{};
350 auto half_x = SymbolicExpr::multiply(SymbolicExpr::number(
Rational(1, 2)),
351 SymbolicExpr::variable(var));
358 return std::optional<detail::IntegralParts>{};
360 return std::optional<detail::IntegralParts>{{std::move(primitive), zero_}};
函数节点,表示数学函数调用(三角函数、对数、特殊函数等)。
FuncType type() const noexcept
const std::vector< std::shared_ptr< const SymbolicNode > > & arguments() const noexcept
static Polynomial gcd(Polynomial a, Polynomial b)
计算两个多项式的最大公因式
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_trig_function(const FunctionNode &fn)
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