LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
solve_polynomial_cubic.cpp
浏览该文件的文档.
5#include <algorithm>
6#include <cmath>
7#include <limits>
8#include <stdexcept>
9#include <utility>
10
11namespace LMCAS {
12using namespace polynomial_solver_detail;
13
14static std::shared_ptr<SymbolicExpr> cbrt_expr(const std::shared_ptr<SymbolicExpr>& x) {
15 return SymbolicExpr::power(x, SymbolicExpr::number(Rational(1, 3)));
16}
17
18static std::vector<std::shared_ptr<SymbolicExpr>> solve_degenerate_cubic(
19 const std::shared_ptr<SymbolicExpr>& b, const std::shared_ptr<SymbolicExpr>& c,
20 const std::shared_ptr<SymbolicExpr>& d, ComputationContext& context) {
21 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
22 (context).limits().max_ast_nodes, "transform");
23 if (!detail::make_expression_ptr(detail::normalize_node(detail::node(b), transform_budget))->get_number_value_is_zero()) {
25 }
26 if (!detail::make_expression_ptr(detail::normalize_node(detail::node(c), transform_budget))->get_number_value_is_zero()) {
27 return {detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::divide(negate(d), c)), transform_budget))};
28 }
29 auto constant = detail::make_expression_ptr(detail::normalize_node(detail::node(d), transform_budget));
30 if (constant->get_number_value_is_zero()) {
31 throw std::invalid_argument(
32 "solve_cubic: identically zero equation has no finite root list");
33 }
34 if (is_purely_numeric(constant)) return {};
35 throw std::invalid_argument(
36 "solve_cubic: equation is independent of the requested variable");
37}
38
39static std::vector<std::shared_ptr<SymbolicExpr>> symbolic_cubic_roots(
40 const std::shared_ptr<SymbolicExpr>& a, const std::shared_ptr<SymbolicExpr>& b,
41 const std::shared_ptr<SymbolicExpr>& c, const std::shared_ptr<SymbolicExpr>& d, ComputationContext& context) {
42
43 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
44 (context).limits().max_ast_nodes, "transform");
45 auto a2 = SymbolicExpr::power(a, num(2));
46 auto a3 = SymbolicExpr::power(a, num(3));
47 auto b2 = SymbolicExpr::power(b, num(2));
48 auto b3 = SymbolicExpr::power(b, num(3));
49 auto three_ac = SymbolicExpr::multiply(
50 num(3), SymbolicExpr::multiply(a, c));
51 auto p_num = sub(three_ac, b2);
52 auto p_den = SymbolicExpr::multiply(num(3), a2);
53 auto p = detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::divide(p_num, p_den)), transform_budget));
54 auto two_b3 = SymbolicExpr::multiply(num(2), b3);
55 auto nine_abc = SymbolicExpr::multiply(
56 num(9), SymbolicExpr::multiply(
57 a, SymbolicExpr::multiply(b, c)));
58 auto twentyseven_a2d = SymbolicExpr::multiply(
59 num(27), SymbolicExpr::multiply(a2, d));
60 auto q_num = SymbolicExpr::add(
61 sub(two_b3, nine_abc), twentyseven_a2d);
62 auto q_den = SymbolicExpr::multiply(num(27), a3);
63 auto q = detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::divide(q_num, q_den)), transform_budget));
64 auto shift = detail::make_expression_ptr(detail::normalize_node(detail::node(SymbolicExpr::divide(
65 b, SymbolicExpr::multiply(num(3), a))), transform_budget));
66
67
68 auto q_half = SymbolicExpr::divide(q, num(2));
69 auto p_third = SymbolicExpr::divide(p, num(3));
71 SymbolicExpr::power(q_half, num(2)),
72 SymbolicExpr::power(p_third, num(3)))), transform_budget));
73
74 auto neg_q_half = detail::make_expression_ptr(detail::normalize_node(detail::node(negate(q_half)), transform_budget));
75 auto sqrt_D = SymbolicExpr::sqrt(D_expr);
76
77 auto u = detail::make_expression_ptr(detail::normalize_node(detail::node(cbrt_expr(SymbolicExpr::add(neg_q_half, sqrt_D))), transform_budget));
78 auto v = detail::make_expression_ptr(detail::normalize_node(detail::node(cbrt_expr(sub(neg_q_half, sqrt_D))), transform_budget));
79
80 auto t1 = SymbolicExpr::add(u, v);
81 auto x1 = detail::make_expression_ptr(detail::normalize_node(detail::node(sub(t1, shift)), transform_budget));
82
83 auto neg_half_sum = SymbolicExpr::divide(negate(SymbolicExpr::add(u, v)), num(2));
84 auto diff_uv = sub(u, v);
85 auto sqrt3_half = SymbolicExpr::divide(SymbolicExpr::sqrt(num(3)), num(2));
86 auto imag_coeff = SymbolicExpr::multiply(sqrt3_half, diff_uv);
87
88 auto i_unit = SymbolicExpr::sqrt(num(-1));
89 auto x2 = detail::make_expression_ptr(detail::normalize_node(detail::node(sub(SymbolicExpr::add(neg_half_sum, SymbolicExpr::multiply(i_unit, imag_coeff)), shift)), transform_budget));
90 auto x3 = detail::make_expression_ptr(detail::normalize_node(detail::node(sub(sub(neg_half_sum, SymbolicExpr::multiply(i_unit, imag_coeff)), shift)), transform_budget));
91
92 return {x1, x2, x3};
93}
94
96 const Polynomial<Rational>& polynomial) {
97 if (polynomial.degree() <= 1) return true;
98 if (polynomial.lead_coeff() != Rational(1)) {
99 return bounded_rational_root_search(polynomial.make_monic());
100 }
101 BigInt denominator_lcm(1);
102 for (const auto& coefficient : polynomial.coeffs) {
103 denominator_lcm = BigInt::lcm(
104 denominator_lcm, coefficient.get_denominator());
105 if (denominator_lcm.bit_length() > 32) return false;
106 }
107 /**
108 * @brief find_rational_roots 在枚举因子前移除零根。
109 * 大小限制针对本原整数多项式的实际首尾系数;
110 * 各分母虽小,其最小公倍数仍可能很大。
111 */
112 for (const auto& coefficient : polynomial.coeffs) {
113 if (coefficient != Rational(0)) {
114 return (coefficient * Rational(denominator_lcm))
115 .get_numerator().bit_length() <= 32;
116 }
117 }
118 return true;
119}
120
121static std::vector<std::shared_ptr<SymbolicExpr>> exact_factor_roots(
123
124 std::vector<std::shared_ptr<SymbolicExpr>> roots;
125 while (polynomial.degree() >= 3 && polynomial.coeffs[0] == Rational(0)) {
126 roots.push_back(SymbolicExpr::number(0));
127 polynomial.coeffs.erase(polynomial.coeffs.begin());
128 }
129 if (polynomial.degree() >= 3) {
130 if (bounded_rational_root_search(polynomial)) {
131 for (const auto& root : find_rational_roots(polynomial)) {
133 {-root, Rational(1)}, polynomial.variable_name);
134 auto [quotient, remainder] = polynomial.div_mod(linear);
135 if (!remainder.is_zero()) {
136 throw std::logic_error("polynomial solver: inexact rational root division");
137 }
138 roots.push_back(SymbolicExpr::number(root));
139 polynomial = std::move(quotient);
140 }
141 }
142 }
143 if (polynomial.degree() == 1) {
144 roots.push_back(SymbolicExpr::number(
145 -polynomial.coeffs[0] / polynomial.coeffs[1]));
146 } else if (polynomial.degree() == 2) {
147 auto quadratic = solve_quadratic_internal(
148 SymbolicExpr::number(polynomial.coeffs[2]),
149 SymbolicExpr::number(polynomial.coeffs[1]),
150 SymbolicExpr::number(polynomial.coeffs[0]), context);
151 roots.insert(roots.end(), quadratic.begin(), quadratic.end());
152 } else if (polynomial.degree() == 4 &&
153 polynomial.coeffs[3] == Rational(0) &&
154 polynomial.coeffs[1] == Rational(0)) {
155 auto biquadratic = solve_biquadratic_impl(
156 SymbolicExpr::number(polynomial.coeffs[4]),
157 SymbolicExpr::number(polynomial.coeffs[2]),
158 SymbolicExpr::number(polynomial.coeffs[0]),
159 polynomial.variable_name, context);
160 roots.insert(roots.end(), biquadratic.begin(), biquadratic.end());
161 } else if (polynomial.degree() >= 3) {
162 auto expression = poly_to_symbolic(polynomial);
163 for (int index = 0; index < polynomial.degree(); ++index) {
164 auto root = make_rootof_checked(expression, polynomial.variable_name,
165 static_cast<std::size_t>(index), context);
166 if (!root) throw root.error();
167 roots.push_back(std::move(root.value()));
168 }
169 }
170 return roots;
171}
172
173std::vector<std::shared_ptr<SymbolicExpr>> polynomial_solver_detail::exact_polynomial_roots(
174 const Polynomial<Rational>& polynomial, ComputationContext& context) {
175 if (polynomial.is_zero()) {
176 throw std::invalid_argument(
177 "polynomial solver: identically zero equation has no finite root list");
178 }
179 std::vector<std::shared_ptr<SymbolicExpr>> roots;
180 for (const auto& [factor, multiplicity] :
181 square_free_factorization(polynomial)) {
182 auto factor_roots = exact_factor_roots(factor, context);
183 for (int repeat = 0; repeat < multiplicity; ++repeat) {
184 roots.insert(roots.end(), factor_roots.begin(), factor_roots.end());
185 }
186 }
187 return roots;
188}
189
190std::vector<std::shared_ptr<SymbolicExpr>> polynomial_solver_detail::solve_cubic_impl(
191 const std::shared_ptr<SymbolicExpr>& a,
192 const std::shared_ptr<SymbolicExpr>& b,
193 const std::shared_ptr<SymbolicExpr>& c,
194 const std::shared_ptr<SymbolicExpr>& d,
195 const std::string& variable, ComputationContext& context) {
196 detail::RewriteBudget transform_budget(context, (context).limits().max_recursion_depth,
197 (context).limits().max_ast_nodes, "transform");
202 if (convert_to_rational_poly(symbolic, exact, context)) {
203 return exact_polynomial_roots(exact, context);
204 }
205 if (detail::make_expression_ptr(detail::normalize_node(detail::node(a), transform_budget))->get_number_value_is_zero()) {
206 return solve_degenerate_cubic(b, c, d, context);
207 }
208 return symbolic_cubic_roots(a, b, c, d, context);
209}
210
211std::vector<std::shared_ptr<SymbolicExpr>> solve_cubic(
212 const std::shared_ptr<SymbolicExpr>& a,
213 const std::shared_ptr<SymbolicExpr>& b,
214 const std::shared_ptr<SymbolicExpr>& c,
215 const std::shared_ptr<SymbolicExpr>& d,
216 const std::string& variable) {
218 return solve_cubic_impl(a, b, c, d, variable, context);
219}
220
221}
一元多项式模板类
std::pair< Polynomial, Polynomial > div_mod(const Polynomial &other) const
多项式带余除法
std::string variable_name
变量名
bool is_zero() const
判断是否为零多项式
std::vector< CoeffType > coeffs
系数数组,coeffs[i] 为 x^i 的系数
CoeffType lead_coeff() const
获取首项系数
int degree() const
获取多项式的次数
Polynomial make_monic() const
首一化(使首项系数为 1)
std::shared_ptr<::LMCAS::SymbolicExpr > make_expression_ptr(SymbolicNodePtr root)
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
SymbolicNodePtr normalize_node(const SymbolicNodePtr &node, RewriteBudget &budget, const FactsQuery &facts, Domain domain)
bool bounded_rational_root_search(const Polynomial< Rational > &polynomial)
std::shared_ptr< SymbolicExpr > num(int value)
std::vector< std::shared_ptr< SymbolicExpr > > solve_cubic_impl(const std::shared_ptr< SymbolicExpr > &a, const std::shared_ptr< SymbolicExpr > &b, const std::shared_ptr< SymbolicExpr > &c, const std::shared_ptr< SymbolicExpr > &d, const std::string &variable, ComputationContext &context)
bool convert_to_rational_poly(const Polynomial< SymbolicPolyCoeff > &poly, Polynomial< Rational > &output, ComputationContext &context)
std::vector< std::shared_ptr< SymbolicExpr > > exact_polynomial_roots(const Polynomial< Rational > &polynomial, ComputationContext &context)
std::vector< std::shared_ptr< SymbolicExpr > > solve_biquadratic_impl(const std::shared_ptr< SymbolicExpr > &a, const std::shared_ptr< SymbolicExpr > &b, const std::shared_ptr< SymbolicExpr > &c, const std::string &variable, ComputationContext &context)
std::shared_ptr< SymbolicExpr > negate(const std::shared_ptr< SymbolicExpr > &expr)
bool is_purely_numeric(const std::shared_ptr< SymbolicExpr > &expr)
std::vector< std::shared_ptr< SymbolicExpr > > solve_quadratic_internal(const std::shared_ptr< SymbolicExpr > &a, const std::shared_ptr< SymbolicExpr > &b, const std::shared_ptr< SymbolicExpr > &c, ComputationContext &context)
const std::string & variable
static std::vector< std::shared_ptr< SymbolicExpr > > solve_degenerate_cubic(const std::shared_ptr< SymbolicExpr > &b, const std::shared_ptr< SymbolicExpr > &c, const std::shared_ptr< SymbolicExpr > &d, ComputationContext &context)
std::vector< std::pair< Polynomial< Rational >, int > > square_free_factorization(const Polynomial< Rational > &poly)
__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
ExprResult sub(const ExprPtr &lhs, const ExprPtr &rhs, ComputationContext &context)
const VectorField const VectorField & c
const MultiPoly & b
RootOfConstructionResult make_rootof_checked(const std::shared_ptr< SymbolicExpr > &polynomial, const std::string &variable, std::size_t index, ComputationContext &context)
static std::shared_ptr< SymbolicExpr > cbrt_expr(const std::shared_ptr< SymbolicExpr > &x)
__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::vector< Rational > find_rational_roots(const Polynomial< Rational > &poly)
ExprSetResult roots(const ExprPtr &expression, const std::string &variable, ComputationContext &context, const SolveOptions &options)
std::vector< std::shared_ptr< SymbolicExpr > > solve_cubic(const std::shared_ptr< SymbolicExpr > &a, const std::shared_ptr< SymbolicExpr > &b, const std::shared_ptr< SymbolicExpr > &c, const std::shared_ptr< SymbolicExpr > &d, const std::string &variable)
static std::vector< std::shared_ptr< SymbolicExpr > > exact_factor_roots(Polynomial< Rational > polynomial, ComputationContext &context)
static std::vector< std::shared_ptr< SymbolicExpr > > symbolic_cubic_roots(const std::shared_ptr< SymbolicExpr > &a, const std::shared_ptr< SymbolicExpr > &b, const std::shared_ptr< SymbolicExpr > &c, const std::shared_ptr< SymbolicExpr > &d, ComputationContext &context)
__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 & u
精确 RootOf 标识构造及受检数值求值。