27 std::size_t nodes = 0;
28 for (
const auto&
interval : intervals) {
35 return value.get_numerator().is_negative();
39 const bool zero =
value == Rational(0);
51 return strict ? Endpoint::open(
value) : Endpoint::closed(
value);
56 const std::shared_ptr<SymbolicExpr>& boundary,
57 const Rational& rational_part,
58 const Rational& radical_coefficient,
59 const Rational& radicand,
69 "quadratic boundary verification could not construct an expression",
73 const Rational& constant = polynomial.
coeffs[0];
74 const Rational& linear = polynomial.
coeffs[1];
75 const Rational& quadratic = polynomial.
coeffs[2];
76 const Rational residual_rational =
77 quadratic * (rational_part * rational_part +
78 radical_coefficient * radical_coefficient * radicand) +
79 linear * rational_part + constant;
80 const Rational residual_radical =
81 Rational(2) * quadratic * rational_part * radical_coefficient +
82 linear * radical_coefficient;
83 if (residual_rational != Rational(0) ||
84 residual_radical != Rational(0)) {
87 "quadratic boundary could not be verified by exact substitution",
97 bool wants_positive,
bool leading_positive,
bool strict,
100 auto root = SymbolicExpr::number(rational_part);
101 auto verified = verify_quadratic_boundary(
102 polynomial, root, rational_part, Rational(0), Rational(0),
context);
107 if (wants_positive == leading_positive) {
111 std::vector<Interval> rays{
112 Interval{Endpoint::neg_inf(), Endpoint::open(root)},
113 Interval{Endpoint::open(root), Endpoint::pos_inf()}
115 check_interval_forest(rays, budget);
121 std::vector<Interval>
point{Interval::point(root)};
122 check_interval_forest(
point, budget);
127 std::shared_ptr<SymbolicExpr>
first;
133 const Rational&
denominator,
const Rational& discriminant,
137 SymbolicExpr::sqrt(SymbolicExpr::number(discriminant))), budget));
138 const Rational first_radical_coefficient = Rational(-1) /
denominator;
139 const Rational second_radical_coefficient = Rational(1) /
denominator;
141 SymbolicExpr::add(SymbolicExpr::number(rational_part),
142 SymbolicExpr::multiply(SymbolicExpr::number(first_radical_coefficient),
143 sqrt_discriminant))), budget));
145 SymbolicExpr::add(SymbolicExpr::number(rational_part),
146 SymbolicExpr::multiply(SymbolicExpr::number(second_radical_coefficient),
147 sqrt_discriminant))), budget));
150 auto first_verified = verify_quadratic_boundary(
151 polynomial, first_formula, rational_part,
152 first_radical_coefficient, discriminant,
context);
153 if (!first_verified) {
156 auto second_verified = verify_quadratic_boundary(
157 polynomial, second_formula, rational_part,
158 second_radical_coefficient, discriminant,
context);
159 if (!second_verified) {
163 {std::move(first_formula), std::move(second_formula)});
166Result<IntervalUnion> InequalitySolver::solve_exact_quadratic_inequality(
167 const Polynomial<Rational>& polynomial,
170 detail::RewriteBudget budget(
context,
context.limits().max_recursion_depth,
171 context.limits().max_ast_nodes, kCheckedInequalityOperation);
172 const Rational& constant = polynomial.coeffs[0];
173 const Rational& linear = polynomial.coeffs[1];
174 const Rational& quadratic = polynomial.coeffs[2];
175 if (quadratic == Rational(0)) {
178 "quadratic polynomial has a zero leading coefficient",
179 kCheckedInequalityOperation);
182 auto steps =
context.consume_steps(3, kCheckedInequalityOperation);
186 const Rational discriminant = linear * linear -
Rational(4) * quadratic * constant;
194 const bool satisfied = wants_positive == leading_positive;
196 satisfied ? IntervalUnion::entire_line() : IntervalUnion::empty());
204 wants_positive, leading_positive, strict, budget);
209 IntervalUnion::from_checked_normalized(std::move(intervals.value())));
213 polynomial, rational_part,
denominator, discriminant, budget);
217 auto lower = leading_positive ? boundaries.value().first : boundaries.value().second;
218 auto upper = leading_positive ? boundaries.value().second : boundaries.value().first;
220 const bool outside = wants_positive == leading_positive;
222 std::vector<Interval> rays{
228 IntervalUnion::from_checked_normalized(std::move(rays)));
235 IntervalUnion::from_checked_normalized(std::move(
interval)));
248 if (polynomial.
degree() <= 0) {
254 ? IntervalUnion::entire_line()
255 : IntervalUnion::empty());
258 if (polynomial.
degree() != 1 || polynomial.
coeffs.size() < 2) {
261 "checked inequality solving currently supports exact polynomials through degree two",
265 const Rational& intercept = polynomial.
coeffs[0];
266 const Rational& slope = polynomial.
coeffs[1];
267 if (slope == Rational(0)) {
270 "affine polynomial has a zero leading coefficient",
274 const Rational boundary = (Rational(0) - intercept) / slope;
275 auto boundary_expr = SymbolicExpr::number(boundary);
286 const Endpoint finite = strict
287 ? Endpoint::open(boundary_expr)
288 : Endpoint::closed(boundary_expr);
289 const Interval
interval = solution_above
290 ? Interval{finite, Endpoint::pos_inf()}
291 : Interval{Endpoint::neg_inf(), finite};
308 std::shared_ptr<SymbolicExpr> sum = SymbolicExpr::number(0);
309 for (
int degree = 0; degree <= polynomial.
degree(); ++degree) {
310 if (polynomial.
coeffs[degree] == Rational(0)) {
313 auto term = SymbolicExpr::number(polynomial.
coeffs[degree]);
315 auto power = degree == 1
317 : SymbolicExpr::power(
variable, SymbolicExpr::number(degree));
318 term = SymbolicExpr::multiply(term, power);
320 sum = SymbolicExpr::add(sum, term);
329 std::size_t& root_nodes) {
335 const auto& intervals = isolated.value();
337 for (std::size_t index = 0; index < intervals.size(); ++index) {
339 factor, index,
static_cast<std::size_t
>(multiplicity),
context);
344 SymbolicExpr::root_of(
346 static_cast<int>(index)),
347 std::move(algebraic.value()),
356 for (std::size_t i = 1; i <
roots.size(); ++i) {
357 auto root = std::move(
roots[i]);
358 std::size_t position = i;
359 while (position > 0) {
361 roots[position - 1].algebraic, root.algebraic,
context);
365 if (
order.value() <= 0) {
368 roots[position] = std::move(
roots[position - 1]);
371 roots[position] = std::move(root);
379 const bool wants_positive =
385 auto sign_satisfies = [&](
int sign_value) {
386 return wants_positive ? sign_value > 0 : sign_value < 0;
390 if ((polynomial.
degree() & 1) != 0) {
391 sign_value = -sign_value;
394 std::vector<Interval> intervals;
395 Endpoint
lower = Endpoint::neg_inf();
396 for (
const auto& root :
roots) {
397 if (sign_satisfies(sign_value)) {
398 intervals.push_back(Interval{
399 lower, Endpoint::open(root.expression)});
402 intervals.push_back(Interval::point(root.expression));
404 lower = Endpoint::open(root.expression);
405 if ((root.multiplicity & 1) != 0) {
406 sign_value = -sign_value;
409 if (sign_satisfies(sign_value)) {
410 intervals.push_back(Interval{
lower, Endpoint::pos_inf()});
420 std::vector<ExactInequalityRoot>
roots;
424 std::size_t root_nodes = 0;
425 for (
const auto& [factor, multiplicity] : factors) {
426 if (factor.degree() < 1) {
441 return IntervalUnion::from_intervals_checked(std::move(intervals),
context);
444 }
catch (
const std::length_error& error) {
447 }
catch (
const std::bad_alloc&) {
450 "polynomial inequality root allocation failed",
452 }
catch (
const std::exception& error) {
461namespace detail::inequality_support {
467 return solve_exact_affine_inequality_impl(polynomial, type,
context);
474 return solve_exact_polynomial_inequality_impl(polynomial, type,
context);
std::string variable_name
变量名
bool is_zero() const
判断是否为零多项式
std::vector< CoeffType > coeffs
系数数组,coeffs[i] 为 x^i 的系数
CoeffType lead_coeff() const
获取首项系数
int degree() const
获取多项式的次数
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success(T value)
ComputationContext & context() const noexcept
std::size_t measure(const std::shared_ptr< const SymbolicNode > &node)
std::size_t append_size(std::size_t current, std::size_t child)
不等式求解器 InequalitySolver,支持多项式,有理式,参数化不等式.
bool constant_satisfies(const Rational &value, InequalityType type)
std::shared_ptr< SymbolicExpr > rational_polynomial_expression(const Polynomial< Rational > &polynomial, detail::RewriteBudget &budget)
std::vector< Interval > exact_polynomial_sign_intervals(const Polynomial< Rational > &polynomial, const std::vector< ExactInequalityRoot > &roots, InequalityType type)
void check_interval_forest(const std::vector< Interval > &intervals, detail::RewriteBudget &budget)
Result< IntervalUnion > solve_exact_affine_inequality_impl(const Polynomial< Rational > &polynomial, InequalityType type, ComputationContext &context)
bool rational_is_negative(const Rational &value)
Endpoint finite_endpoint(const std::shared_ptr< SymbolicExpr > &value, bool strict)
std::shared_ptr< SymbolicExpr > expression
Result< void > verify_quadratic_boundary(const Polynomial< Rational > &polynomial, const std::shared_ptr< SymbolicExpr > &boundary, const Rational &rational_part, const Rational &radical_coefficient, const Rational &radicand, ComputationContext &context)
Result< void > append_exact_factor_roots(std::vector< ExactInequalityRoot > &roots, const Polynomial< Rational > &factor, int multiplicity, const std::string &variable, detail::RewriteBudget &budget, std::size_t &root_nodes)
constexpr const char * kCheckedInequalityOperation
LMCAS::detail::ExactRealAlgebraic algebraic
Result< IntervalUnion > solve_exact_polynomial_inequality_impl(const Polynomial< Rational > &polynomial, InequalityType type, ComputationContext &context)
Result< void > sort_exact_inequality_roots(std::vector< ExactInequalityRoot > &roots, ComputationContext &context)
Result< IntervalUnion > solve_exact_polynomial_inequality(const Polynomial< Rational > &polynomial, InequalityType type, ComputationContext &context)
Result< IntervalUnion > solve_exact_affine_inequality(const Polynomial< Rational > &polynomial, InequalityType type, ComputationContext &context)
std::shared_ptr<::LMCAS::SymbolicExpr > make_expression_ptr(SymbolicNodePtr root)
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
Result< int > compare_exact_real_algebraic(ExactRealAlgebraic lhs, ExactRealAlgebraic rhs, ComputationContext &context)
SymbolicNodePtr normalize_node(const SymbolicNodePtr &node, RewriteBudget &budget, const FactsQuery &facts, Domain domain)
ExactRealAlgebraicResult make_exact_real_algebraic(Polynomial< Rational > polynomial, std::size_t root_index, std::size_t multiplicity, ComputationContext &context)
std::size_t std::size_t ComputationContext & context
const std::string const LimitExprPtr & point
const std::string & variable
std::vector< std::pair< Polynomial< Rational >, int > > square_free_factorization(const Polynomial< Rational > &poly)
__attribute__((visibility("default"))) ExprResult function(const std __attribute__((visibility("default"))) ExprResult finite_set(std ExprPtr upper
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
ExprResult interval(ExprPtr lower, ExprPtr upper, bool lower_closed, bool upper_closed)
const std::vector< FGLMPoly > const MonomialOrder & order
static Result< QuadraticBoundaries > verified_quadratic_boundaries(const Polynomial< Rational > &polynomial, const Rational &rational_part, const Rational &denominator, const Rational &discriminant, detail::RewriteBudget &budget)
@ Rational
Rational numbers
Result< std::vector< std::pair< Rational, Rational > > > isolate_real_roots_checked(const Polynomial< Rational > &polynomial, ComputationContext &context)
std::shared_ptr< SymbolicExpr > second
ExprSetResult roots(const ExprPtr &expression, const std::string &variable, ComputationContext &context, const SolveOptions &options)
const std::string const ExprPtr & value
static Result< std::vector< Interval > > double_root_inequality_intervals(const Polynomial< Rational > &polynomial, const Rational &rational_part, bool wants_positive, bool leading_positive, bool strict, detail::RewriteBudget &budget)
const ExprPtr & denominator
std::shared_ptr< SymbolicExpr > first
数值求根:Newton-Raphson 迭代,二分法,Sturm 实根隔离.
方程求解策略调度器 solve_dispatch 及相关选项结构体.