Skip to content

Commit

Permalink
Share interval tree code between and .
Browse files Browse the repository at this point in the history
  • Loading branch information
renggli committed Dec 31, 2023
1 parent 6436618 commit b08877e
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 178 deletions.
112 changes: 23 additions & 89 deletions lib/src/interval/map.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import 'dart:collection' show MapBase;

import 'package:collection/collection.dart' show QueueList;

import '../functional/scope.dart';
import 'interval.dart';
import 'tree.dart';

/// A [IntervalMap] associates intervals with a value.
///
Expand All @@ -27,12 +25,14 @@ class IntervalMap<K extends Comparable<K>, V>
/// Internal [Map] delegate.
final Map<Interval<K>, V> _map = {};

/// Internal root of the balanced interval tree.
_IntervalNode<K, V>? _root;
/// Internal root node of the balanced interval tree.
IntervalTreeNode<K, MapEntry<Interval<K>, V>>? _node;

/// Returns an [Iterable] over all entries that contain a [value].
Iterable<MapEntry<Interval<K>, V>> entriesContainingPoint(K value) =>
_queryPoint(value);
Iterable<MapEntry<Interval<K>, V>> entriesContainingPoint(K value) {
_refresh();
return queryPoint(_node, value).where((each) => each.key.contains(value));
}

/// Returns an [Iterable] over all keys that contain a [value].
Iterable<Interval<K>> keysContainingPoint(K value) =>
Expand All @@ -44,8 +44,11 @@ class IntervalMap<K extends Comparable<K>, V>

/// Returns an [Iterable] over all entries that overlap with [interval].
Iterable<MapEntry<Interval<K>, V>> entriesIntersectingInterval(
Interval<K> interval) =>
_queryInterval(interval).where((entry) => entry.key.intersects(interval));
Interval<K> interval) {
_refresh();
return queryInterval(_node, interval)
.where((entry) => entry.key.intersects(interval));
}

/// Returns an [Iterable] over all keys that overlap with [interval].
Iterable<Interval<K>> keysIntersectingInterval(Interval<K> interval) =>
Expand All @@ -57,8 +60,11 @@ class IntervalMap<K extends Comparable<K>, V>

/// Returns an [Iterable] over all entries that cover [interval].
Iterable<MapEntry<Interval<K>, V>> entriesEnclosingInterval(
Interval<K> interval) =>
_queryInterval(interval).where((entry) => entry.key.encloses(interval));
Interval<K> interval) {
_refresh();
return queryInterval(_node, interval)
.where((entry) => entry.key.encloses(interval));
}

/// Returns an [Iterable] over all keys that cover [interval].
Iterable<Interval<K>> keysEnclosingInterval(Interval<K> interval) =>
Expand Down Expand Up @@ -91,98 +97,26 @@ class IntervalMap<K extends Comparable<K>, V>

@override
void operator []=(Interval<K> key, V value) {
_root = null;
_node = null;
_map[key] = value;
}

@override
void clear() {
_root = null;
_node = null;
_map.clear();
}

@override
V? remove(Object? key) {
_root = null;
_node = null;
return _map.remove(key);
}

void _refresh() {
if (isEmpty || _root != null) return;
_root = _createNode(_map.entries);
}

Iterable<MapEntry<Interval<K>, V>> _queryPoint(K value) sync* {
_refresh();
var node = _root;
while (node != null) {
for (final entry in node.entries) {
if (entry.key.contains(value)) {
yield entry;
}
}
final comparison = value.compareTo(node.median);
node = comparison < 0
? node.left
: comparison > 0
? node.right
: null;
}
if (isEmpty || _node != null) return;
_node = createTreeNode(_map.entries, _value);
}

Iterable<MapEntry<Interval<K>, V>> _queryInterval(
Interval<K> interval) sync* {
_refresh();
final nodes = QueueList<_IntervalNode<K, V>>();
if (_root case final root?) nodes.add(root);
while (nodes.isNotEmpty) {
final node = nodes.removeFirst();
yield* node.entries;
if (interval.upper.compareTo(node.median) < 0) {
node.left?.also(nodes.add);
}
if (node.median.compareTo(interval.lower) < 0) {
node.right?.also(nodes.add);
}
}
}
}

class _IntervalNode<K extends Comparable<K>, V> {
final K median;
final _IntervalNode<K, V>? left;
final List<MapEntry<Interval<K>, V>> entries;
final _IntervalNode<K, V>? right;

_IntervalNode(this.median, this.left, this.entries, this.right);
}

_IntervalNode<K, V>? _createNode<K extends Comparable<K>, V>(
Iterable<MapEntry<Interval<K>, V>> entries) {
if (entries.isEmpty) return null;
final endpoints = <K>[];
for (final entry in entries) {
endpoints.add(entry.key.lower);
endpoints.add(entry.key.upper);
}
endpoints.sort();
final median = endpoints[endpoints.length ~/ 2];
final left = <MapEntry<Interval<K>, V>>[];
final center = <MapEntry<Interval<K>, V>>[];
final right = <MapEntry<Interval<K>, V>>[];
for (final entry in entries) {
if (entry.key.upper.compareTo(median) < 0) {
left.add(entry);
} else if (median.compareTo(entry.key.lower) < 0) {
right.add(entry);
} else {
center.add(entry);
}
}
return _IntervalNode<K, V>(
median,
_createNode(left),
center,
_createNode(right),
);
Interval<K> _value(MapEntry<Interval<K>, V> entry) => entry.key;
}
114 changes: 25 additions & 89 deletions lib/src/interval/set.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import 'dart:collection' show SetBase;

import 'package:collection/collection.dart' show QueueList;

import '../functional/scope.dart';
import 'interval.dart';
import 'tree.dart';

/// A [IntervalSet] contains unique intervals.
///
Expand All @@ -24,22 +22,31 @@ class IntervalSet<E extends Comparable<E>>
/// Internal [Map] delegate.
final Set<Interval<E>> _set = {};

/// Internal root of the balanced interval tree.
_IntervalNode<E>? _root;
/// Internal root node of the balanced interval tree.
IntervalTreeNode<E, Interval<E>>? _node;

/// Returns an [Iterable] over all intervals in arbitrary order that contain
/// a [value].
Iterable<Interval<E>> containingPoint(E value) => _queryPoint(value);
Iterable<Interval<E>> containingPoint(E value) {
_refresh();
return queryPoint(_node, value).where((each) => each.contains(value));
}

/// Returns an [Iterable] over all intervals in arbitrary order that overlap
/// with [interval] in arbitrary order.
Iterable<Interval<E>> intersectingInterval(Interval<E> interval) =>
_queryInterval(interval).where((each) => each.intersects(interval));
Iterable<Interval<E>> intersectingInterval(Interval<E> interval) {
_refresh();
return queryInterval(_node, interval)
.where((each) => each.intersects(interval));
}

/// Returns an [Iterable] over all intervals in arbitrary order that are
/// covering [interval] in arbitrary order.
Iterable<Interval<E>> enclosingInterval(Interval<E> interval) =>
_queryInterval(interval).where((each) => each.encloses(interval));
Iterable<Interval<E>> enclosingInterval(Interval<E> interval) {
_refresh();
return queryInterval(_node, interval)
.where((each) => each.encloses(interval));
}

@override
int get length => _set.length;
Expand All @@ -62,7 +69,7 @@ class IntervalSet<E extends Comparable<E>>
@override
bool add(Interval<E> value) {
final result = _set.add(value);
if (result) _root = null;
if (result) _node = null;
return result;
}

Expand All @@ -72,19 +79,19 @@ class IntervalSet<E extends Comparable<E>>
for (final element in elements) {
changed |= _set.add(element);
}
if (changed) _root = null;
if (changed) _node = null;
}

@override
void clear() {
_set.clear();
_root = null;
_node = null;
}

@override
bool remove(Object? value) {
final result = _set.remove(value);
if (result) _root = null;
if (result) _node = null;
return result;
}

Expand All @@ -94,87 +101,16 @@ class IntervalSet<E extends Comparable<E>>
for (final element in elements) {
changed |= _set.remove(element);
}
if (changed) _root = null;
if (changed) _node = null;
}

@override
Set<Interval<E>> toSet() => _set.toSet();

void _refresh() {
if (isEmpty || _root != null) return;
_root = _createNode(this);
}

Iterable<Interval<E>> _queryPoint(E value) sync* {
_refresh();
var node = _root;
while (node != null) {
for (final interval in node.intervals) {
if (interval.contains(value)) {
yield interval;
}
}
final comparison = value.compareTo(node.median);
node = comparison < 0
? node.left
: comparison > 0
? node.right
: null;
}
if (isEmpty || _node != null) return;
_node = createTreeNode(this, _identity);
}

Iterable<Interval<E>> _queryInterval(Interval<E> interval) sync* {
_refresh();
final nodes = QueueList<_IntervalNode<E>>();
if (_root case final root?) nodes.add(root);
while (nodes.isNotEmpty) {
final node = nodes.removeFirst();
yield* node.intervals;
if (interval.upper.compareTo(node.median) < 0) {
node.left?.also(nodes.add);
}
if (node.median.compareTo(interval.lower) < 0) {
node.right?.also(nodes.add);
}
}
}
}

class _IntervalNode<E extends Comparable<E>> {
final E median;
final _IntervalNode<E>? left;
final List<Interval<E>> intervals;
final _IntervalNode<E>? right;

_IntervalNode(this.median, this.left, this.intervals, this.right);
}

_IntervalNode<E>? _createNode<E extends Comparable<E>>(
Iterable<Interval<E>> intervals) {
if (intervals.isEmpty) return null;
final endpoints = <E>[];
for (final interval in intervals) {
endpoints.add(interval.lower);
endpoints.add(interval.upper);
}
endpoints.sort();
final median = endpoints[endpoints.length ~/ 2];
final left = <Interval<E>>[];
final center = <Interval<E>>[];
final right = <Interval<E>>[];
for (final interval in intervals) {
if (interval.upper.compareTo(median) < 0) {
left.add(interval);
} else if (median.compareTo(interval.lower) < 0) {
right.add(interval);
} else {
center.add(interval);
}
}
return _IntervalNode<E>(
median,
_createNode(left),
center,
_createNode(right),
);
Interval<E> _identity(Interval<E> interval) => interval;
}
Loading

0 comments on commit b08877e

Please sign in to comment.