// interval-set.h // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // Copyright 2005-2010 Google, Inc. // Author: riley@google.com (Michael Riley) // // \file // Class to represent and operate on sets of intervals. #ifndef FST_LIB_INTERVAL_SET_H__ #define FST_LIB_INTERVAL_SET_H__ #include #include using std::vector; #include namespace fst { // Stores and operates on a set of half-open integral intervals [a,b) // of signed integers of type T. template class IntervalSet { public: struct Interval { T begin; T end; Interval() : begin(-1), end(-1) {} Interval(T b, T e) : begin(b), end(e) {} bool operator<(const Interval &i) const { return begin < i.begin || (begin == i.begin && end > i.end); } bool operator==(const Interval &i) const { return begin == i.begin && end == i.end; } bool operator!=(const Interval &i) const { return begin != i.begin || end != i.end; } istream &Read(istream &strm) { T n; ReadType(strm, &n); begin = n; ReadType(strm, &n); end = n; return strm; } ostream &Write(ostream &strm) const { T n = begin; WriteType(strm, n); n = end; WriteType(strm, n); return strm; } }; IntervalSet() : count_(-1) {} // Returns the interval set as a vector. vector *Intervals() { return &intervals_; } const vector *Intervals() const { return &intervals_; } const bool Empty() const { return intervals_.empty(); } const T Size() const { return intervals_.size(); } // Number of points in the intervals (undefined if not normalized). const T Count() const { return count_; } void Clear() { intervals_.clear(); count_ = 0; } // Adds an interval set to the set. The result may not be normalized. void Union(const IntervalSet &iset) { const vector *intervals = iset.Intervals(); for (typename vector::const_iterator it = intervals->begin(); it != intervals->end(); ++it) intervals_.push_back(*it); } // Requires intervals be normalized. bool Member(T value) const { Interval interval(value, value); typename vector::const_iterator lb = lower_bound(intervals_.begin(), intervals_.end(), interval); if (lb == intervals_.begin()) return false; return (--lb)->end > value; } // Requires intervals be normalized. bool operator==(const IntervalSet& iset) const { return *(iset.Intervals()) == intervals_; } // Requires intervals be normalized. bool operator!=(const IntervalSet& iset) const { return *(iset.Intervals()) != intervals_; } bool Singleton() const { return intervals_.size() == 1 && intervals_[0].begin + 1 == intervals_[0].end; } // Sorts; collapses overlapping and adjacent interals; sets count. void Normalize(); // Intersects an interval set with the set. Requires intervals be // normalized. The result is normalized. void Intersect(const IntervalSet &iset, IntervalSet *oset) const; // Complements the set w.r.t [0, maxval). Requires intervals be // normalized. The result is normalized. void Complement(T maxval, IntervalSet *oset) const; // Subtract an interval set from the set. Requires intervals be // normalized. The result is normalized. void Difference(const IntervalSet &iset, IntervalSet *oset) const; // Determines if an interval set overlaps with the set. Requires // intervals be normalized. bool Overlaps(const IntervalSet &iset) const; // Determines if an interval set overlaps with the set but neither // is contained in the other. Requires intervals be normalized. bool StrictlyOverlaps(const IntervalSet &iset) const; // Determines if an interval set is contained within the set. Requires // intervals be normalized. bool Contains(const IntervalSet &iset) const; istream &Read(istream &strm) { ReadType(strm, &intervals_); return ReadType(strm, &count_); } ostream &Write(ostream &strm) const { WriteType(strm, intervals_); return WriteType(strm, count_); } private: vector intervals_; T count_; }; // Sorts; collapses overlapping and adjacent interavls; sets count. template void IntervalSet::Normalize() { sort(intervals_.begin(), intervals_.end()); count_ = 0; T size = 0; for (T i = 0; i < intervals_.size(); ++i) { Interval &inti = intervals_[i]; if (inti.begin == inti.end) continue; for (T j = i + 1; j < intervals_.size(); ++j) { Interval &intj = intervals_[j]; if (intj.begin > inti.end) break; if (intj.end > inti.end) inti.end = intj.end; ++i; } count_ += inti.end - inti.begin; intervals_[size++] = inti; } intervals_.resize(size); } // Intersects an interval set with the set. Requires intervals be normalized. // The result is normalized. template void IntervalSet::Intersect(const IntervalSet &iset, IntervalSet *oset) const { const vector *iintervals = iset.Intervals(); vector *ointervals = oset->Intervals(); typename vector::const_iterator it1 = intervals_.begin(); typename vector::const_iterator it2 = iintervals->begin(); ointervals->clear(); oset->count_ = 0; while (it1 != intervals_.end() && it2 != iintervals->end()) { if (it1->end <= it2->begin) { ++it1; } else if (it2->end <= it1->begin) { ++it2; } else { Interval interval; interval.begin = max(it1->begin, it2->begin); interval.end = min(it1->end, it2->end); ointervals->push_back(interval); oset->count_ += interval.end - interval.begin; if (it1->end < it2->end) ++it1; else ++it2; } } } // Complements the set w.r.t [0, maxval). Requires intervals be normalized. // The result is normalized. template void IntervalSet::Complement(T maxval, IntervalSet *oset) const { vector *ointervals = oset->Intervals(); ointervals->clear(); oset->count_ = 0; Interval interval; interval.begin = 0; for (typename vector::const_iterator it = intervals_.begin(); it != intervals_.end(); ++it) { interval.end = min(it->begin, maxval); if (interval.begin < interval.end) { ointervals->push_back(interval); oset->count_ += interval.end - interval.begin; } interval.begin = it->end; } interval.end = maxval; if (interval.begin < interval.end) { ointervals->push_back(interval); oset->count_ += interval.end - interval.begin; } } // Subtract an interval set from the set. Requires intervals be normalized. // The result is normalized. template void IntervalSet::Difference(const IntervalSet &iset, IntervalSet *oset) const { if (intervals_.empty()) { oset->Intervals()->clear(); oset->count_ = 0; } else { IntervalSet cset; iset.Complement(intervals_.back().end, &cset); Intersect(cset, oset); } } // Determines if an interval set overlaps with the set. Requires // intervals be normalized. template bool IntervalSet::Overlaps(const IntervalSet &iset) const { const vector *intervals = iset.Intervals(); typename vector::const_iterator it1 = intervals_.begin(); typename vector::const_iterator it2 = intervals->begin(); while (it1 != intervals_.end() && it2 != intervals->end()) { if (it1->end <= it2->begin) { ++it1; } else if (it2->end <= it1->begin) { ++it2; } else { return true; } } return false; } // Determines if an interval set overlaps with the set but neither // is contained in the other. Requires intervals be normalized. template bool IntervalSet::StrictlyOverlaps(const IntervalSet &iset) const { const vector *intervals = iset.Intervals(); typename vector::const_iterator it1 = intervals_.begin(); typename vector::const_iterator it2 = intervals->begin(); bool only1 = false; // point in intervals_ but not intervals bool only2 = false; // point in intervals but not intervals_ bool overlap = false; // point in both intervals_ and intervals while (it1 != intervals_.end() && it2 != intervals->end()) { if (it1->end <= it2->begin) { // no overlap - it1 first only1 = true; ++it1; } else if (it2->end <= it1->begin) { // no overlap - it2 first only2 = true; ++it2; } else if (it2->begin == it1->begin && it2->end == it1->end) { // equals overlap = true; ++it1; ++it2; } else if (it2->begin <= it1->begin && it2->end >= it1->end) { // 1 c 2 only2 = true; overlap = true; ++it1; } else if (it1->begin <= it2->begin && it1->end >= it2->end) { // 2 c 1 only1 = true; overlap = true; ++it2; } else { // strict overlap only1 = true; only2 = true; overlap = true; } if (only1 == true && only2 == true && overlap == true) return true; } if (it1 != intervals_.end()) only1 = true; if (it2 != intervals->end()) only2 = true; return only1 == true && only2 == true && overlap == true; } // Determines if an interval set is contained within the set. Requires // intervals be normalized. template bool IntervalSet::Contains(const IntervalSet &iset) const { if (iset.Count() > Count()) return false; const vector *intervals = iset.Intervals(); typename vector::const_iterator it1 = intervals_.begin(); typename vector::const_iterator it2 = intervals->begin(); while (it1 != intervals_.end() && it2 != intervals->end()) { if (it1->end <= it2->begin) { // no overlap - it1 first ++it1; } else if (it2->begin < it1->begin || it2->end > it1->end) { // no C return false; } else if (it2->end == it1->end) { ++it1; ++it2; } else { ++it2; } } return it2 == intervals->end(); } template ostream &operator<<(ostream &strm, const IntervalSet &s) { typedef typename IntervalSet::Interval Interval; const vector *intervals = s.Intervals(); strm << "{"; for (typename vector::const_iterator it = intervals->begin(); it != intervals->end(); ++it) { if (it != intervals->begin()) strm << ","; strm << "[" << it->begin << "," << it->end << ")"; } strm << "}"; return strm; } } // namespace fst #endif // FST_LIB_INTERVAL_SET_H__