LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
inequality_solver_rational.cpp
浏览该文件的文档.
4#include <algorithm>
5
6namespace LMCAS {
7using namespace detail::inequality_support;
8namespace {
9
11 std::shared_ptr<SymbolicExpr> value;
14};
15
16IntervalUnion zero_numerator_domain(const std::shared_ptr<SymbolicExpr>& denominator,
17 InequalityType type, const std::string& variable,
20 return IntervalUnion::empty();
21 }
22
23 auto den_roots_with_mult = find_roots_with_multiplicity(denominator, variable, context);
24 if (den_roots_with_mult.empty()) {
25 return IntervalUnion::entire_line();
26 }
27
28 std::vector<std::shared_ptr<SymbolicExpr>> den_roots;
29 for (const auto& [root, mult] : den_roots_with_mult) {
30 den_roots.push_back(root);
31 }
32 std::sort(den_roots.begin(), den_roots.end(),
33 [&context](const auto& lhs, const auto& rhs) {
34 return root_less_than(lhs, rhs, context);
35 });
36
37 std::vector<Interval> intervals;
38
39 {
40 Interval iv;
41 iv.lower = Endpoint::neg_inf();
42 iv.upper = Endpoint::open(den_roots[0]);
43 intervals.push_back(iv);
44 }
45 for (size_t i = 0; i + 1 < den_roots.size(); ++i) {
46 Interval iv;
47 iv.lower = Endpoint::open(den_roots[i]);
48 iv.upper = Endpoint::open(den_roots[i + 1]);
49 intervals.push_back(iv);
50 }
51
52 {
53 Interval iv;
54 iv.lower = Endpoint::open(den_roots.back());
55 iv.upper = Endpoint::pos_inf();
56 intervals.push_back(iv);
57 }
58 return IntervalUnion(intervals);
59}
60
61std::vector<CriticalPoint> rational_critical_points(
62 const std::shared_ptr<SymbolicExpr>& numerator,
63 const std::shared_ptr<SymbolicExpr>& denominator,
64 const std::string& variable, ComputationContext& context) {
65 auto num_roots_with_mult = find_roots_with_multiplicity(numerator, variable, context);
66
67 auto den_roots_with_mult = find_roots_with_multiplicity(denominator, variable, context);
68 std::vector<CriticalPoint> critical_points;
69
70 for (const auto& [root, mult] : num_roots_with_mult) {
71 critical_points.push_back({root, mult, 0});
72 }
73 for (const auto& [root, mult] : den_roots_with_mult) {
74
75 bool found = false;
76 for (auto& cp : critical_points) {
77 if (roots_equal(cp.value, root, context)) {
78 cp.den_multiplicity = mult;
79 found = true;
80 break;
81 }
82 }
83 if (!found) {
84 critical_points.push_back({root, 0, mult});
85 }
86 }
87
88 std::sort(critical_points.begin(), critical_points.end(),
89 [&context](const CriticalPoint& a, const CriticalPoint& b) {
90 return root_less_than(a.value, b.value, context);
91 });
92 return critical_points;
93}
94
95std::vector<Interval> rational_sign_intervals(
96 const std::vector<CriticalPoint>& critical_points,
97 int combined_leading_sign, int target_sign) {
98 size_t n_cp = critical_points.size();
99 std::vector<int> interval_signs(n_cp + 1);
100
101 interval_signs[n_cp] = combined_leading_sign;
102
103 for (int i = (int)n_cp - 1; i >= 0; --i) {
104 int total_mult = critical_points[i].num_multiplicity + critical_points[i].den_multiplicity;
105 interval_signs[i] = interval_signs[i + 1];
106 if (total_mult % 2 != 0) {
107 interval_signs[i] = -interval_signs[i];
108 }
109 }
110 std::vector<Interval> result_intervals;
111 for (size_t i = 0; i <= n_cp; ++i) {
112 if (interval_signs[i] != target_sign) {
113 continue;
114 }
115 Interval interval;
116 interval.lower = i == 0 ? Endpoint::neg_inf() : Endpoint::open(critical_points[i - 1].value);
117 interval.upper = i == n_cp ? Endpoint::pos_inf() : Endpoint::open(critical_points[i].value);
118 result_intervals.push_back(interval);
119 }
120 return result_intervals;
121}
122
124 const std::shared_ptr<SymbolicExpr>& expression, const std::string& variable) {
125 auto polynomial = symbolic_to_poly<Rational>(expression, variable);
126 return !polynomial;
127}
128
130 std::vector<Interval>& intervals, const std::vector<CriticalPoint>& points,
132 for (const auto& point : points) {
133 if (point.num_multiplicity > 0 && point.den_multiplicity == 0) {
134 include_numeric_root(intervals, point.value, context);
135 }
136 }
137}
138
139}
140
141IntervalUnion InequalitySolver::solve_rational_inequality(
142 const std::shared_ptr<SymbolicExpr>& numerator,
143 const std::shared_ptr<SymbolicExpr>& denominator,
144 InequalityType type,
145 const std::string& variable) {
146 ComputationContext context;
147
148 if (!numerator || !denominator) {
149 return IntervalUnion::empty();
150 }
151
152 auto num_conversion = symbolic_to_poly<SymbolicPolyCoeff>(numerator, variable);
153 auto den_conversion = symbolic_to_poly<SymbolicPolyCoeff>(denominator, variable);
154 if (!num_conversion) throw std::invalid_argument(num_conversion.error().message);
155 if (!den_conversion) throw std::invalid_argument(den_conversion.error().message);
156 const auto& num_poly = num_conversion.value();
157 const auto& den_poly = den_conversion.value();
158
159 if (den_poly.is_zero()) {
160 return IntervalUnion::empty();
161 }
162
163 if (num_poly.is_zero()) {
165 }
167 throw std::invalid_argument("Numerator is not a supported rational polynomial");
168 }
170 throw std::invalid_argument("Denominator is not a supported rational polynomial");
171 }
172 auto critical_points = rational_critical_points(numerator, denominator, variable, context);
173 int num_leading_sign = determine_leading_sign(num_poly, context);
174 int den_leading_sign = determine_leading_sign(den_poly, context);
175 int combined_leading_sign = num_leading_sign * den_leading_sign;
176 bool want_positive = (type == InequalityType::GreaterThan || type == InequalityType::GreaterEqual);
177 bool is_strict = (type == InequalityType::GreaterThan || type == InequalityType::LessThan);
178 int target_sign = want_positive ? 1 : -1;
179 auto result_intervals = rational_sign_intervals(critical_points, combined_leading_sign, target_sign);
180 if (!is_strict) {
181 include_rational_zeros(result_intervals, critical_points, context);
182 }
183 return IntervalUnion(result_intervals);
184}
185
186}
void include_rational_zeros(std::vector< Interval > &intervals, const std::vector< CriticalPoint > &points, ComputationContext &context)
bool has_unrecognized_variable_polynomial(const std::shared_ptr< SymbolicExpr > &expression, const std::string &variable)
IntervalUnion zero_numerator_domain(const std::shared_ptr< SymbolicExpr > &denominator, InequalityType type, const std::string &variable, ComputationContext &context)
std::vector< Interval > rational_sign_intervals(const std::vector< CriticalPoint > &critical_points, int combined_leading_sign, int target_sign)
std::vector< CriticalPoint > rational_critical_points(const std::shared_ptr< SymbolicExpr > &numerator, const std::shared_ptr< SymbolicExpr > &denominator, const std::string &variable, 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)
bool roots_equal(const std::shared_ptr< SymbolicExpr > &a, const std::shared_ptr< SymbolicExpr > &b, ComputationContext &context)
void include_numeric_root(std::vector< Interval > &intervals, const std::shared_ptr< SymbolicExpr > &root, ComputationContext &context)
int determine_leading_sign(const Polynomial< SymbolicPolyCoeff > &poly, ComputationContext &context)
const std::string const LimitExprPtr & point
const std::string & variable
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
ExprResult interval(ExprPtr lower, ExprPtr upper, bool lower_closed, bool upper_closed)
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
InequalityType
不等式类型
const std::string const ExprPtr & value
const ExprPtr & rhs
const ExprPtr & denominator
内部 AST 定义。