LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
inequality_solver_numeric.cpp
浏览该文件的文档.
4#include "poly_utils.hpp"
12#include <algorithm>
13#include <cmath>
14#include <memory>
15#include <optional>
16#include <utility>
17#include <vector>
18
20
21std::optional<double> try_checked_numeric_constant(
22 const SymbolicExpr& expr, ComputationContext& context) {
24}
25
26int exact_numeric_sign(const std::shared_ptr<SymbolicExpr>& expr,
28 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
29 (context).limits().max_ast_nodes, "transform");
30 if (!expr || !LMCAS::detail::node(expr)) {
31 return 0;
32 }
33 auto simplified = detail::make_expression_ptr(detail::normalize_node(detail::node(expr), transform_budget));
34 if (!simplified || !LMCAS::detail::node(simplified)) {
35 return 0;
36 }
37 auto num = std::dynamic_pointer_cast<const NumberNode>(LMCAS::detail::node(simplified));
38 if (!num) {
39 return 0;
40 }
41 if (std::holds_alternative<BigInt>(num->value())) {
42 const auto& value = std::get<BigInt>(num->value());
43 if (value.is_zero()) {
44 return 0;
45 }
46 return value.is_negative() ? -1 : 1;
47 }
48 const auto& value = std::get<Rational>(num->value());
49 if (value.get_numerator().is_zero()) {
50 return 0;
51 }
52 return value.get_numerator().is_negative() ? -1 : 1;
53}
54
57 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
58 (context).limits().max_ast_nodes, "transform");
59 if (poly.is_zero()) {
60 return 0;
61 }
62 auto lc = poly.lead_coeff().val;
63 if (!lc) {
64 return 1;
65 }
66 auto simplified = detail::make_expression_ptr(detail::normalize_node(detail::node(lc), transform_budget));
67 if (!simplified) {
68 return 1;
69 }
70
71 if (auto val = try_checked_numeric_constant(*simplified, context)) {
72 if (*val > 0) {
73 return 1;
74 }
75 if (*val < 0) {
76 return -1;
77 }
78 }
79
80 if (auto num = std::dynamic_pointer_cast<const NumberNode>(LMCAS::detail::node(simplified))) {
81 if (std::holds_alternative<BigInt>(num->value())) {
82 return std::get<BigInt>(num->value()).is_negative() ? -1 : 1;
83 }
84 if (std::holds_alternative<Rational>(num->value())) {
85 return std::get<Rational>(num->value()).get_numerator().is_negative() ? -1 : 1;
86 }
87 }
88 return 1;
89}
90
91static std::shared_ptr<SymbolicExpr> snap_verified_integer_root(
92 const Polynomial<Rational>& poly,
93 const std::shared_ptr<SymbolicExpr>& root, ComputationContext& context) {
94 if (!root || poly.is_zero()) {
95 return root;
96 }
97 auto numeric = try_checked_numeric_constant(*root, context);
98 if (!numeric) {
99 return root;
100 }
101
102 const Rational candidate = Rational::from_double(*numeric);
103 if (!candidate.is_integer()) {
104 return root;
105 }
106 if (poly.eval(candidate) == Rational(0)) {
107 return SymbolicExpr::number(candidate);
108 }
109 return root;
110}
111
112using RootMultiplicityList = std::vector<std::pair<std::shared_ptr<SymbolicExpr>, int>>;
113
115 RootMultiplicityList& result,
116 const Polynomial<Rational>& polynomial,
117 const std::vector<std::shared_ptr<SymbolicExpr>>& roots,
119 for (const auto& root : roots) {
120 if (!root) {
121 continue;
122 }
123 auto verified = snap_verified_integer_root(polynomial, root, context);
124 if (try_checked_numeric_constant(*verified, context)) {
125 result.push_back({verified, multiplicity});
126 }
127 }
128}
129
131 const Polynomial<Rational>& factor, int mult,
133 Rational a = factor.coeffs[1];
134 Rational b = factor.coeffs[0];
135 if (a != Rational(0)) {
136 Rational root_val = Rational(0) - b / a;
137 auto root_expr = SymbolicExpr::number(root_val);
138 if (try_checked_numeric_constant(*root_expr, context)) {
139 result.push_back({root_expr, mult});
140 }
141 }
142}
143
145 const Polynomial<Rational>& factor, int mult,
147 Rational a = factor.coeffs[2];
148 Rational b = factor.coeffs[1];
149 Rational c = factor.coeffs[0];
150
151 Rational disc = b * b - Rational(4) * a * c;
152 if (disc < Rational(0)) {
153 return;
154 }
155 double disc_val = disc.to_double();
156
157 double a_val = a.to_double();
158 double b_val = b.to_double();
159 double sqrt_disc = std::sqrt(disc_val);
160
161 double r1;
162 double r2;
163 if (sqrt_disc == 0.0) {
164 r1 = -b_val / (2.0 * a_val);
165 r2 = r1;
166 } else {
167 const double q =
168 -0.5 * b_val - 0.5 * std::copysign(sqrt_disc, b_val);
169 r1 = q / a_val;
170 r2 = c.to_double() / q;
171 }
172
173 if (std::isfinite(r1)) {
174 auto root = snap_verified_integer_root(factor, SymbolicExpr::number(r1), context);
175 result.push_back({root, mult});
176 }
177 if (std::isfinite(r2) && r2 != r1) {
178 auto root = snap_verified_integer_root(factor, SymbolicExpr::number(r2), context);
179 result.push_back({root, mult});
180 }
181}
182
184 const Polynomial<Rational>& factor, int mult,
185 const std::string& variable, ComputationContext& context) {
186 std::vector<SymbolicPolyCoeff> spc_coeffs;
187 for (int i = 0; i <= factor.degree(); ++i) {
188 spc_coeffs.push_back(SymbolicPolyCoeff(SymbolicExpr::number(factor.coeffs[i])));
189 }
190 Polynomial<SymbolicPolyCoeff> factor_spc(spc_coeffs, variable);
191
193 factor_spc, variable, context);
194 append_verified_roots(result, factor, factor_roots, mult, context);
195}
196
197std::vector<std::pair<std::shared_ptr<SymbolicExpr>, int>> find_roots_with_multiplicity(
198 const std::shared_ptr<SymbolicExpr>& expr,
199 const std::string& variable, ComputationContext& context) {
200
201 std::vector<std::pair<std::shared_ptr<SymbolicExpr>, int>> result;
202
203 auto converted = symbolic_to_poly<Rational>(expr, variable);
204 if (!converted) throw std::invalid_argument(converted.error().message);
205 const auto& poly_rat = converted.value();
206 if (poly_rat.is_zero() || poly_rat.degree() <= 0) {
207 return result;
208 }
209
210 auto factors = square_free_factorization(poly_rat);
211 if (factors.empty()) {
212 auto symbolic = symbolic_to_poly<SymbolicPolyCoeff>(expr, variable);
213 if (!symbolic) throw std::invalid_argument(symbolic.error().message);
214 const auto& poly_spc = symbolic.value();
215 if (!poly_spc.is_zero() && poly_spc.degree() >= 1) {
217 poly_spc, variable, context);
218 append_verified_roots(result, poly_rat, roots, 1, context);
219 }
220 return result;
221 }
222 for (const auto& [factor, mult] : factors) {
223 if (factor.degree() <= 0) {
224 continue;
225 }
226 if (factor.degree() == 1) {
227 append_affine_root(result, factor, mult, context);
228 } else if (factor.degree() == 2) {
229 append_quadratic_roots(result, factor, mult, context);
230 } else {
231 append_factor_roots(result, factor, mult, variable, context);
232 }
233 }
234 return result;
235}
236
237bool depends_on_any_param(const std::shared_ptr<SymbolicExpr>& expr,
238 const std::vector<std::string>& parameters) {
239 if (!expr || !LMCAS::detail::node(expr)) {
240 return false;
241 }
242 for (const auto& param : parameters) {
244 return true;
245 }
246 }
247 return false;
248}
249
250std::vector<std::shared_ptr<SymbolicExpr>> solve_symbolic_poly(
252 const std::string& variable, ComputationContext& context) {
253 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
254 (context).limits().max_ast_nodes, "transform");
255
256 if (poly.is_zero() || poly.degree() < 1) {
257 return {};
258 }
259
260 int deg = poly.degree();
261 auto get_coeff = [&](int d) -> std::shared_ptr<SymbolicExpr> {
262 if (d < 0 || d > deg) {
263 return SymbolicExpr::number(0);
264 }
265 return poly.coeffs[d].val ? poly.coeffs[d].val : SymbolicExpr::number(0);
266 };
267
268 if (deg == 1) {
269
270 auto a = get_coeff(1);
271 auto b = get_coeff(0);
272 auto neg_b = SymbolicExpr::multiply(b, SymbolicExpr::number(-1));
273 auto root = detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::divide(neg_b, a)), transform_budget));
274 return { root };
275 }
276
278 return results;
279}
280}
一元多项式模板类
CoeffType eval(const CoeffType &val) const
对多项式求值(Horner 法)
bool is_zero() const
判断是否为零多项式
std::vector< CoeffType > coeffs
系数数组,coeffs[i] 为 x^i 的系数
CoeffType lead_coeff() const
获取首项系数
int degree() const
获取多项式的次数
不等式求解器 InequalitySolver,支持多项式,有理式,参数化不等式.
static void append_affine_root(RootMultiplicityList &result, const Polynomial< Rational > &factor, int mult, ComputationContext &context)
static void append_quadratic_roots(RootMultiplicityList &result, const Polynomial< Rational > &factor, int mult, ComputationContext &context)
static void append_verified_roots(RootMultiplicityList &result, const Polynomial< Rational > &polynomial, const std::vector< std::shared_ptr< SymbolicExpr > > &roots, int multiplicity, ComputationContext &context)
std::vector< std::pair< std::shared_ptr< SymbolicExpr >, int > > find_roots_with_multiplicity(const std::shared_ptr< SymbolicExpr > &expr, const std::string &variable, ComputationContext &context)
static std::shared_ptr< SymbolicExpr > snap_verified_integer_root(const Polynomial< Rational > &poly, const std::shared_ptr< SymbolicExpr > &root, ComputationContext &context)
std::vector< std::shared_ptr< SymbolicExpr > > solve_symbolic_poly(const Polynomial< SymbolicPolyCoeff > &poly, const std::string &variable, ComputationContext &context)
static void append_factor_roots(RootMultiplicityList &result, const Polynomial< Rational > &factor, int mult, const std::string &variable, ComputationContext &context)
int exact_numeric_sign(const std::shared_ptr< SymbolicExpr > &expr, ComputationContext &context)
std::vector< std::pair< std::shared_ptr< SymbolicExpr >, int > > RootMultiplicityList
std::optional< double > try_checked_numeric_constant(const SymbolicExpr &expr, ComputationContext &context)
bool depends_on_any_param(const std::shared_ptr< SymbolicExpr > &expr, const std::vector< std::string > &parameters)
int determine_leading_sign(const Polynomial< SymbolicPolyCoeff > &poly, ComputationContext &context)
std::shared_ptr<::LMCAS::SymbolicExpr > make_expression_ptr(SymbolicNodePtr root)
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
const std::string & variable
std::size_t std::size_t multiplicity
std::optional< double > try_finite_numeric(const SymbolicExpr &expression, ComputationContext &context)
SymbolicNodePtr normalize_node(const SymbolicNodePtr &node, RewriteBudget &budget, const FactsQuery &facts, Domain domain)
std::size_t std::size_t ComputationContext & context
std::shared_ptr< SymbolicExpr > num(int value)
std::vector< std::shared_ptr< SymbolicExpr > > solve_by_factoring_impl(const Polynomial< SymbolicPolyCoeff > &polynomial, const std::string &variable, ComputationContext &context)
std::vector< std::pair< Polynomial< Rational >, int > > square_free_factorization(const Polynomial< Rational > &poly)
const VectorField const VectorField & c
bool expression_depends_on_variable(const detail::SymbolicNodePtr &expression, const std::string &variable, detail::RewriteBudget *budget)
const MultiPoly & b
__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::shared_ptr< SymbolicExpr > get_coeff(const Polynomial< SymbolicPolyCoeff > &p, int deg)
ExprSetResult roots(const ExprPtr &expression, const std::string &variable, ComputationContext &context, const SolveOptions &options)
const std::string const ExprPtr & value
多项式转换与精确符号多项式代数。
方程求解策略调度器 solve_dispatch 及相关选项结构体.
内部 AST 定义。