10std::string IntervalUnion::to_string()
const {
12 if (intervals_.empty()) {
13 return "\xe2\x88\x85";
16 if (intervals_.size() == 1 && intervals_[0].is_entire_line()) {
17 return "(-\xe2\x88\x9e, +\xe2\x88\x9e)";
21 for (
size_t i = 0; i < intervals_.size(); ++i) {
23 result +=
" \xe2\x88\xaa ";
26 const Interval& iv = intervals_[i];
28 if (iv.lower.is_open) {
34 if (iv.lower.is_neg_infinity) {
35 result +=
"-\xe2\x88\x9e";
36 }
else if (iv.lower.value) {
37 result += iv.lower.value->to_string();
44 if (iv.upper.is_pos_infinity) {
45 result +=
"+\xe2\x88\x9e";
46 }
else if (iv.upper.value) {
47 result += iv.upper.value->to_string();
52 if (iv.upper.is_open) {
62static bool starts_with_at(
const std::string& str,
size_t pos,
const std::string& prefix) {
63 if (pos + prefix.size() > str.size()) {
66 return str.compare(pos, prefix.size(), prefix) == 0;
69static size_t skip_ws(
const std::string& str,
size_t pos) {
70 while (pos < str.size() && std::isspace(
static_cast<unsigned char>(str[pos]))) {
77 const size_t start = pos;
78 while (pos < str.size() &&
79 std::isdigit(
static_cast<unsigned char>(str[pos]))) {
86 if (pos < str.size() && (str[pos] ==
'-' || str[pos] ==
'+')) ++pos;
90 const std::string& str,
size_t start,
size_t& pos) {
91 const size_t slash = pos++;
92 const size_t denominator_start = pos;
97 const BigInt numerator(str.substr(start, slash - start));
98 const BigInt
denominator(str.substr(denominator_start, pos - denominator_start));
103 return SymbolicExpr::number(Rational(numerator,
denominator));
107 const std::string& str,
size_t start,
size_t& pos,
bool decimal) {
108 const std::string token = str.substr(start, pos - start);
110 return SymbolicExpr::number(BigInt(token));
112 return SymbolicExpr::number(Rational(token));
116 const std::string& str,
size_t& pos) {
117 const size_t start = pos;
119 const auto token_start = pos;
120 while (pos < str.size() && str[pos] !=
')' &&
121 !std::isspace(
static_cast<unsigned char>(str[pos]))) { ++pos; }
122 const std::string_view token(str.data() + token_start, pos - token_start);
124 if (pos == str.size() || str[pos] !=
')') {
134 return SymbolicExpr::number(
value.value());
138 const std::string& str,
size_t& pos) {
139 const size_t start = pos;
145 if (has_digit && pos < str.size() && str[pos] ==
'/') {
148 bool decimal =
false;
149 if (pos < str.size() && str[pos] ==
'.') {
158 if (pos < str.size() && (str[pos] ==
'e' || str[pos] ==
'E')) {
174 ep.is_neg_infinity =
true;
175 ep.is_pos_infinity =
false;
183 ep.is_pos_infinity =
true;
184 ep.is_neg_infinity =
false;
197 ep.is_neg_infinity =
false;
198 ep.is_pos_infinity =
false;
204 const std::string& str,
size_t& pos, Endpoint&
lower) {
206 if (pos >= str.size()) {
209 const char bracket = str[pos];
210 if (bracket !=
'(' && bracket !=
'[') {
213 const bool open = bracket ==
'(';
218 if (
lower.is_pos_infinity || (
lower.is_neg_infinity && !open)) {
221 if (!
lower.is_neg_infinity)
lower.is_open = open;
226 const std::string& str,
size_t& pos, Endpoint&
upper) {
231 if (pos >= str.size()) {
234 const char bracket = str[pos];
235 if (bracket !=
')' && bracket !=
']') {
238 const bool open = bracket ==
')';
240 if (
upper.is_neg_infinity || (
upper.is_pos_infinity && !open)) {
243 if (!
upper.is_pos_infinity)
upper.is_open = open;
248 const std::string& str,
size_t& pos, Interval& iv) {
254 if (pos >= str.size() || str[pos] !=
',') {
262 iv.lower = std::move(
lower);
263 iv.upper = std::move(
upper);
267std::optional<IntervalUnion> IntervalUnion::parse(
const std::string& str) {
272 if (str ==
"\xe2\x88\x85") {
273 return IntervalUnion::empty();
277 std::vector<Interval> intervals;
284 intervals.push_back(std::move(iv));
286 while (pos < str.size()) {
288 if (pos >= str.size())
break;
300 intervals.push_back(std::move(next_iv));
304 IntervalUnion::from_intervals_checked(std::move(intervals));
308 return std::move(normalized.value());
309 }
catch (
const std::invalid_argument&) {
311 }
catch (
const std::out_of_range&) {
317 const Interval&
interval,
const std::shared_ptr<const SymbolicNode>&
variable) {
318 std::shared_ptr<const SymbolicNode>
lower;
319 std::shared_ptr<const SymbolicNode>
upper;
320 if (!
interval.lower.is_neg_infinity) {
323 const auto op =
interval.lower.is_open ? RelationalNode::Op::GT
324 : RelationalNode::Op::GEQ;
327 if (!
interval.upper.is_pos_infinity) {
330 const auto op =
interval.upper.is_open ? RelationalNode::Op::LT
331 : RelationalNode::Op::LEQ;
340std::shared_ptr<SymbolicExpr> IntervalUnion::to_expr(
const std::string& var)
const {
344 std::vector<std::shared_ptr<const SymbolicNode>>{}));
348 if (is_entire_line()) {
352 zero, zero, RelationalNode::Op::EQ));
355 if (intervals_.size() == 1) {
364 for (
size_t i = 1; i < intervals_.size(); ++i) {
366 if (result && next) {
区间与区间并集 IntervalUnion,用于不等式解集表示。
std::shared_ptr<::LMCAS::SymbolicExpr > make_expression_ptr(SymbolicNodePtr root)
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
Result< double > parse_finite_decimal(std::string_view token)
std::shared_ptr< const Node > make_node(Args &&... args)
const std::string & variable
__attribute__((visibility("default"))) ExprResult function(const std __attribute__((visibility("default"))) ExprResult finite_set(std ExprPtr upper
static std::shared_ptr< SymbolicExpr > parse_numeric_value(const std::string &str, size_t &pos)
static bool parse_interval_lower(const std::string &str, size_t &pos, Endpoint &lower)
ExprResult interval(ExprPtr lower, ExprPtr upper, bool lower_closed, bool upper_closed)
static bool parse_interval_upper(const std::string &str, size_t &pos, Endpoint &upper)
static size_t skip_ws(const std::string &str, size_t pos)
static std::shared_ptr< SymbolicExpr > parse_approximate_atom(const std::string &str, size_t &pos)
const ExprPtr RelationOp op
static std::shared_ptr< SymbolicExpr > numeric_token_value(const std::string &str, size_t start, size_t &pos, bool decimal)
static bool starts_with_at(const std::string &str, size_t pos, const std::string &prefix)
static bool consume_digits(const std::string &str, size_t &pos)
const std::string const ExprPtr & value
static void consume_sign(const std::string &str, size_t &pos)
static std::shared_ptr< const SymbolicNode > interval_to_expr(const Interval &interval, const std::shared_ptr< const SymbolicNode > &variable)
static std::shared_ptr< SymbolicExpr > parse_fraction(const std::string &str, size_t start, size_t &pos)
const ExprPtr & denominator
static bool parse_single_interval(const std::string &str, size_t &pos, Interval &iv)
static bool parse_endpoint_value(const std::string &str, size_t &pos, Endpoint &ep)