LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
mixed_transcendental_search.cpp
浏览该文件的文档.
4#include <cmath>
5#include <limits>
6
7namespace LMCAS {
8namespace {
9static lmmc_real_t extract_real_value(const std::shared_ptr<const SymbolicNode>& node) {
10 auto num = std::dynamic_pointer_cast<const NumberNode>(node);
11 if (!num) {
12 return std::numeric_limits<lmmc_real_t>::quiet_NaN();
13 }
14
15 if (std::holds_alternative<Rational>(num->value())) {
16 return static_cast<lmmc_real_t>(std::get<Rational>(num->value()).to_double());
17 }
18 if (std::holds_alternative<BigInt>(num->value())) {
19 return static_cast<lmmc_real_t>(std::get<BigInt>(num->value()).to_double());
20 }
21 return std::numeric_limits<lmmc_real_t>::quiet_NaN();
22}
23
24// Accept k*x in either operand order. The caller also handles x and k*x+c.
25static lmmc_real_t product_linear_coefficient(
26 const MultiplyNode& product, const std::string& var) {
27 if (product.operands().size() != 2) {
28 return std::numeric_limits<lmmc_real_t>::quiet_NaN();
29 }
30 std::shared_ptr<const SymbolicNode> number;
31 bool has_variable = false;
32 for (const auto& operand : product.operands()) {
33 if (operand->is_number()) {
34 number = operand;
35 } else if (auto variable = std::dynamic_pointer_cast<const VariableNode>(operand)) {
36 if (!variable->is_constant() && variable->name() == var) {
37 has_variable = true;
38 }
39 }
40 }
41 if (number && has_variable) {
42 return extract_real_value(number);
43 }
44 return std::numeric_limits<lmmc_real_t>::quiet_NaN();
45}
46
47static lmmc_real_t extract_linear_coefficient(
48 const std::shared_ptr<const SymbolicNode>& node,
49 const std::string& var)
50{
51 if (!node || !expression_depends_on_variable(node, var)) {
52 return 0.0;
53 }
54
55 if (auto v = std::dynamic_pointer_cast<const VariableNode>(node)) {
56 if (!v->is_constant() && v->name() == var) {
57 return 1.0;
58 }
59 return std::numeric_limits<lmmc_real_t>::quiet_NaN();
60 }
61
62 if (auto mul = std::dynamic_pointer_cast<const MultiplyNode>(node)) {
63 return product_linear_coefficient(*mul, var);
64 }
65
66 if (auto add = std::dynamic_pointer_cast<const AddNode>(node)) {
67 lmmc_real_t coeff = std::numeric_limits<lmmc_real_t>::quiet_NaN();
68 bool found_var_term = false;
69
70 for (const auto& op : add->operands()) {
72 continue;
73 }
74 if (found_var_term) {
75 return std::numeric_limits<lmmc_real_t>::quiet_NaN();
76 }
77 found_var_term = true;
78 coeff = extract_linear_coefficient(op, var);
79 }
80
81 return found_var_term ? coeff : std::numeric_limits<lmmc_real_t>::quiet_NaN();
82 }
83
84 return std::numeric_limits<lmmc_real_t>::quiet_NaN();
85}
86
88 switch (t) {
92 return true;
93 default:
94 return false;
95 }
96}
97
98// Record the periods of trigonometric nodes with affine arguments in target_var.
99// Sine and cosine use 2pi/|k|; tangent uses pi/|k|.
101 const std::string& target_var;
102 lmmc_real_t max_period = 0.0;
103 bool found_periodic = false;
105
106 explicit PeriodicCollector(const std::string& v) : target_var(v) {}
107
108 void visit(const MatrixNode&) override {}
109
110 void visit(const TransformNode& node) override {
111 visit_child(node.body());
112 }
113
115 if (!is_periodic_func(n.type()) || n.arguments().empty()) {
116 return;
117 }
119 return;
120 }
121 found_periodic = true;
122 const auto k = extract_linear_coefficient(n.arguments()[0], target_var);
123 if (std::isnan(k) || k == 0.0) {
125 return;
126 }
127 const auto period = n.type() == FunctionNode::FuncType::Tan
128 ? LMMC_CONST_PI / std::fabs(k)
129 : 2.0 * LMMC_CONST_PI / std::fabs(k);
130 if (period > max_period) {
131 max_period = period;
132 }
133 }
134
135 void visit(const FunctionNode& node) override {
136 collect_period(node);
138 }
139};
140
141}
142
143std::optional<SearchInterval> determine_search_interval(
144 const std::shared_ptr<SymbolicExpr>& expr,
145 const std::string& var,
146 const SolveOptions& opts)
147{
148 if (opts.has_search_interval) {
149 if (opts.search_lo >= opts.search_hi) {
150 return std::nullopt;
151 }
152 if ((opts.search_hi - opts.search_lo) <= opts.tolerance) {
153 return std::nullopt;
154 }
155 return SearchInterval{opts.search_lo, opts.search_hi};
156 }
157
158 lmmc_real_t lo = -10.0;
159 lmmc_real_t hi = 10.0;
160
161 if (expr && LMCAS::detail::node(expr)) {
162 PeriodicCollector collector(var);
163 LMCAS::detail::node(expr)->accept(collector);
164
165 if (collector.found_periodic && !collector.has_nonlinear_periodic && collector.max_period > 0.0) {
166 // [-period, period] covers two complete periods around zero.
167 lmmc_real_t half_span = collector.max_period;
168 if (half_span > lo * -1.0 || half_span > hi) {
169 lo = -half_span;
170 hi = half_span;
171 }
172 // Cap automatic interval growth to keep numeric scanning bounded.
173 if (lo < -100.0) {
174 lo = -100.0;
175 }
176 if (hi > 100.0) {
177 hi = 100.0;
178 }
179 }
180 }
181
182 if (lo >= hi) {
183 return std::nullopt;
184 }
185 if ((hi - lo) <= opts.tolerance) {
186 return std::nullopt;
187 }
188
189 return SearchInterval{lo, hi};
190}
191
192}
函数节点,表示数学函数调用(三角函数、对数、特殊函数等)。
FuncType type() const noexcept
const std::vector< std::shared_ptr< const SymbolicNode > > & arguments() const noexcept
矩阵节点,支持稠密和稀疏两种存储方式。
乘法节点,表示多个操作数的乘积。
const std::vector< std::shared_ptr< const SymbolicNode > > & operands() const noexcept
virtual void accept(LMCAS::detail::SymbolicVisitor &visitor) const =0
积分变换节点,表示 Laplace,Fourier,Z 变换及其逆变换.
void visit(const NumberNode &) override
virtual void visit_child(const SymbolicNodePtr &child)
static lmmc_real_t extract_real_value(const std::shared_ptr< const SymbolicNode > &node)
static lmmc_real_t extract_linear_coefficient(const std::shared_ptr< const SymbolicNode > &node, const std::string &var)
static lmmc_real_t product_linear_coefficient(const MultiplyNode &product, const std::string &var)
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
std::shared_ptr< SymbolicExpr > num(int value)
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
bool has_search_interval
是否指定了搜索区间
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)
std::optional< SearchInterval > determine_search_interval(const std::shared_ptr< SymbolicExpr > &expr, const std::string &var, const SolveOptions &opts)
lmmc_real_t tolerance
收敛容差
const ExprPtr RelationOp op
lmmc_real_t search_lo
搜索区间下界(默认 -10)
lmmc_real_t search_hi
搜索区间上界(默认 10)
__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
方程求解选项,控制数值求解行为和结果形式.
混合超越方程求解:符号预处理 + 自适应根隔离 + Newton-Raphson 精化.
内部 AST 定义。