14 if (
function.arguments().size() != 1 ||
28 auto exponent = std::dynamic_pointer_cast<const NumberNode>(power.
exponent());
35 const std::shared_ptr<const SymbolicNode>& node,
36 const std::string& var,
37 std::vector<std::shared_ptr<SymbolicExpr>>& candidates) {
43 if (
auto func = std::dynamic_pointer_cast<const FunctionNode>(node)) {
48 for (
auto& arg : func->arguments()) {
54 if (
auto pow = std::dynamic_pointer_cast<const PowerNode>(node)) {
64 if (
auto add = std::dynamic_pointer_cast<const AddNode>(node)) {
65 for (
auto&
op :
add->operands()) {
71 if (
auto mul = std::dynamic_pointer_cast<const MultiplyNode>(node)) {
72 for (
auto&
op :
mul->operands()) {
80 std::vector<std::shared_ptr<SymbolicExpr>> unique;
81 std::vector<std::string> seen;
82 for (
auto&
c : candidates) {
83 std::string s =
c->to_string();
85 for (
auto& existing : seen) {
86 if (existing == s) { found =
true;
break; }
93 candidates = std::move(unique);
97 std::shared_ptr<const NumberNode> number;
98 bool has_variable =
false;
99 bool has_other =
false;
100 for (
const auto& operand : product.
operands()) {
101 if (
auto numeric = std::dynamic_pointer_cast<const NumberNode>(operand)) {
107 }
else if (
auto variable = std::dynamic_pointer_cast<const VariableNode>(operand)) {
118 if (has_variable && number && !has_other &&
126 auto func = std::dynamic_pointer_cast<const FunctionNode>(node);
131 auto arg = func->arguments()[0];
133 if (
auto v = std::dynamic_pointer_cast<const VariableNode>(arg)) {
134 if (!
v->is_constant() &&
v->name() == var) {
139 if (
auto mul = std::dynamic_pointer_cast<const MultiplyNode>(arg)) {
147 const std::shared_ptr<const SymbolicNode>& node,
148 const std::string& var,
149 const std::string& u_var) {
164 if (
auto add = std::dynamic_pointer_cast<const AddNode>(node)) {
165 std::vector<std::shared_ptr<const SymbolicNode>> new_ops;
166 new_ops.reserve(
add->operands().size());
167 for (
auto&
op :
add->operands()) {
173 if (
auto mul = std::dynamic_pointer_cast<const MultiplyNode>(node)) {
174 std::vector<std::shared_ptr<const SymbolicNode>> new_ops;
175 new_ops.reserve(
mul->operands().size());
176 for (
auto&
op :
mul->operands()) {
182 if (
auto pow = std::dynamic_pointer_cast<const PowerNode>(node)) {
188 if (
auto func = std::dynamic_pointer_cast<const FunctionNode>(node)) {
189 std::vector<std::shared_ptr<const SymbolicNode>> new_args;
190 new_args.reserve(func->arguments().size());
191 for (
auto& arg : func->arguments()) {
209 if (
auto add = std::dynamic_pointer_cast<const AddNode>(node)) {
210 for (
auto&
op :
add->operands()) {
216 if (
auto mul = std::dynamic_pointer_cast<const MultiplyNode>(node)) {
217 for (
auto&
op :
mul->operands()) {
223 if (
auto pow = std::dynamic_pointer_cast<const PowerNode>(node)) {
231 if (
auto func = std::dynamic_pointer_cast<const FunctionNode>(node)) {
232 for (
auto& arg : func->arguments()) {
243 std::shared_ptr<const SymbolicNode>
target;
246 std::shared_ptr<const SymbolicNode>
replace(
const std::shared_ptr<const SymbolicNode>& node) {
251 if (node->equals(*
target)) {
255 if (
auto add = std::dynamic_pointer_cast<const AddNode>(node)) {
256 std::vector<std::shared_ptr<const SymbolicNode>> new_ops;
257 new_ops.reserve(
add->operands().size());
258 for (
auto&
op :
add->operands()) {
263 if (
auto mul = std::dynamic_pointer_cast<const MultiplyNode>(node)) {
264 std::vector<std::shared_ptr<const SymbolicNode>> new_ops;
265 new_ops.reserve(
mul->operands().size());
266 for (
auto&
op :
mul->operands()) {
271 if (
auto pow = std::dynamic_pointer_cast<const PowerNode>(node)) {
276 if (
auto func = std::dynamic_pointer_cast<const FunctionNode>(node)) {
277 std::vector<std::shared_ptr<const SymbolicNode>> new_args;
278 new_args.reserve(func->arguments().size());
279 for (
auto& arg : func->arguments()) {
280 new_args.push_back(
replace(arg));
290 const std::shared_ptr<SymbolicExpr>& candidate,
291 const std::shared_ptr<SymbolicExpr>& expr,
const std::string& var) {
296 auto polynomial = symbolic_to_poly<SymbolicPolyCoeff>(expr, var);
303 return polynomial.value().degree() >= 2;
307 const std::shared_ptr<SymbolicExpr>& expr,
308 const std::string& var,
const std::string& u_var) {
312 auto polynomial = symbolic_to_poly<SymbolicPolyCoeff>(expr, u_var);
319 return polynomial.value().degree() >= 2;
325 const std::shared_ptr<SymbolicExpr>& expr,
326 const std::string& var)
try {
329 (
context).limits().max_ast_nodes,
"transform");
332 return std::optional<SubstitutionResult>{};
336 return std::optional<SubstitutionResult>{};
339 const std::string u_var =
"_u_subst";
341 std::vector<std::shared_ptr<SymbolicExpr>> candidates;
343 deduplicate_candidates(candidates);
345 for (
auto& h : candidates) {
347 auto redundant = redundant_variable_candidate(h, expr, var);
351 if (redundant.value()) {
357 SubstNodeVisitor visitor;
359 visitor.u_name = u_var;
365 auto polynomial = is_substitution_polynomial(substituted_expr, var, u_var);
369 if (polynomial.value()) {
370 return std::optional<SubstitutionResult>{{h, substituted_expr, u_var}};
379 auto polynomial = is_substitution_polynomial(rewritten_expr, var, u_var);
383 if (polynomial.value()) {
384 auto exp_x = SymbolicExpr::exp(SymbolicExpr::variable(var));
385 return std::optional<SubstitutionResult>{{exp_x, rewritten_expr, u_var}};
389 return std::optional<SubstitutionResult>{};
390}
catch (
const CasError& error) {
391 return Result<std::optional<SubstitutionResult>>::failure(error);
392}
catch (
const std::bad_alloc&) {
394}
catch (
const std::length_error& error) {
396}
catch (
const std::exception& error) {
函数节点,表示数学函数调用(三角函数、对数、特殊函数等)。
const std::vector< std::shared_ptr< const SymbolicNode > > & operands() const noexcept
const std::shared_ptr< const SymbolicNode > & exponent() const noexcept
const std::shared_ptr< const SymbolicNode > & base() const noexcept
static Result failure(CasErrc code, std::string message, std::string operation={})
static std::shared_ptr< const SymbolicNode > create_add(std::vector< std::shared_ptr< const SymbolicNode > > ops, detail::RewriteBudget *budget=nullptr)
创建加法节点,自动扁平化嵌套加法并消除零项.
static std::shared_ptr< const SymbolicNode > create_power(std::shared_ptr< const SymbolicNode > base, std::shared_ptr< const SymbolicNode > exponent)
创建幂运算节点,自动处理指数为 0/1 及底数为 0/1 的情况.
static std::shared_ptr< const SymbolicNode > create_multiply(std::vector< std::shared_ptr< const SymbolicNode > > ops, detail::RewriteBudget *budget=nullptr)
创建乘法节点,自动扁平化嵌套乘法并消除单位元.
static BigInt extract_exp_multiplier(const std::shared_ptr< const SymbolicNode > &node, const std::string &var)
static Result< bool > is_substitution_polynomial(const std::shared_ptr< SymbolicExpr > &expr, const std::string &var, const std::string &u_var)
static bool has_exp_k_var_terms(const std::shared_ptr< const SymbolicNode > &node, const std::string &var)
static void deduplicate_candidates(std::vector< std::shared_ptr< SymbolicExpr > > &candidates)
static Result< bool > redundant_variable_candidate(const std::shared_ptr< SymbolicExpr > &candidate, const std::shared_ptr< SymbolicExpr > &expr, const std::string &var)
static BigInt product_exp_multiplier(const MultiplyNode &product, const std::string &var)
static void collect_transcendental_subexprs(const std::shared_ptr< const SymbolicNode > &node, const std::string &var, std::vector< std::shared_ptr< SymbolicExpr > > &candidates)
static bool power_candidate(const PowerNode &power, const std::string &var)
static std::shared_ptr< const SymbolicNode > rewrite_exp_as_u_power(const std::shared_ptr< const SymbolicNode > &node, const std::string &var, const std::string &u_var)
static bool function_candidate(const FunctionNode &function, const std::string &var)
std::shared_ptr<::LMCAS::SymbolicExpr > make_expression_ptr(SymbolicNodePtr root)
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
std::shared_ptr< const Node > make_node(Args &&... args)
SymbolicNodePtr normalize_node(const SymbolicNodePtr &node, RewriteBudget &budget, const FactsQuery &facts, Domain domain)
ExprResult pow(const ExprPtr &base, const ExprPtr &exponent, ComputationContext &context)
const std::string & variable
__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 const std::string & v
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
bool try_get_integer_value(const std::shared_ptr< const NumberNode > &node, BigInt &value)
ExprResult mul(const ExprPtr &lhs, const ExprPtr &rhs, ComputationContext &context)
const VectorField const VectorField & c
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)
const ExprPtr RelationOp op
Result< std::optional< SubstitutionResult > > detect_substitution(const std::shared_ptr< SymbolicExpr > &expr, const std::string &var)
const std::string const ExprPtr & value
ExprResult function(const std::string &name, std::vector< ExprPtr > arguments)
std::shared_ptr< const SymbolicNode > replace(const std::shared_ptr< const SymbolicNode > &node)
std::shared_ptr< const SymbolicNode > target