A library to handle interval sets
Project description
Interval Arithmetic Library
A Python library for working with intervals and points on the real number line. Supports continuous intervals with open/closed boundaries, interval arithmetic, set operations, and collections of disjoint intervals.
Features
- ๐ฏ Points: Immutable points with arithmetic and comparison operations
- ๐ Continuous Intervals: Intervals with configurable open/closed boundaries
- ๐ข Set Operations: Union, intersection, difference, and complement
- ๐ฆ Disjoint Intervals: Collections of non-overlapping intervals with automatic merging
- ๐ Type Safe: Comprehensive type hints and runtime type checking
- โ Well Tested: 95%+ test coverage with 70+ test cases
- ๐ Pythonic: Full support for
in,hash(), iteration, and comparison operators
Installation
pip install interval-arithmetic # Coming soon to PyPI
Or install from source:
git clone https://github.com/yourusername/interval-arithmetic.git
cd interval-arithmetic
pip install -e .
Quick Start
Working with Points
from src.intervals import Point
# Create points
p1 = Point(5)
p2 = Point(3)
# Arithmetic operations
p3 = p1 + p2 # Point(8)
p4 = p1 - p2 # Point(2)
# Comparisons
p1 > p2 # True
p1 == Point(5) # True
# Points are hashable
point_set = {p1, p2, p3}
point_dict = {p1: "first", p2: "second"}
Working with Continuous Intervals
from src.intervals import ContinuousInterval, Point
# Create intervals with different boundary types
closed = ContinuousInterval(0, 10) # [0, 10]
open = ContinuousInterval(0, 10, True, True) # (0, 10)
half_open = ContinuousInterval(0, 10, False, True) # [0, 10)
# Check membership
5 in closed # True
0 in open # False (open boundary)
Point(5) in closed # True
# Get interval properties
closed.length() # 10.0
closed.is_empty() # False
# Set operations
i1 = ContinuousInterval(0, 10)
i2 = ContinuousInterval(5, 15)
intersection = i1.intersection(i2) # [5, 10]
union = i1.union(i2) # [0, 15]
difference = i1.difference(i2) # [[0, 5]]
# Using operators
i1 + i2 # [0, 15] (if overlapping/adjacent)
i1 - i2 # [[0, 5]] (set difference)
# Containment checks
i1.contains(Point(5)) # True
i1.contains(ContinuousInterval(3, 7)) # True
i1.contains_value(5) # True
Interval Notation
The library supports mathematical interval notation:
[a, b]- Closed interval: includes both endpoints(a, b)- Open interval: excludes both endpoints[a, b)- Half-open: includesa, excludesb(a, b]- Half-open: excludesa, includesb
# Creating intervals with different notations
closed = ContinuousInterval(0, 10, False, False) # [0, 10]
open = ContinuousInterval(0, 10, True, True) # (0, 10)
half_open = ContinuousInterval(0, 10, False, True) # [0, 10)
# String representation shows notation
print(closed) # [0, 10]
print(open) # (0, 10)
print(half_open) # [0, 10)
Working with Disjoint Intervals
from src.intervals import DisjointInterval, ContinuousInterval
# Create a collection of intervals (automatically merges overlaps)
di = DisjointInterval([
ContinuousInterval(0, 5),
ContinuousInterval(10, 15),
ContinuousInterval(3, 12) # Overlaps with first two, will be merged
])
# After merging: [[0, 15], [20, 25]] becomes [[0, 15], [20, 25]]
len(di) # 1 (merged into single interval [0, 15])
# Check membership
5 in di # True
12 in di # True
20 in di # False
# Get specific interval containing a point
interval = di.get_interval_containing_point(7) # Returns [0, 15]
# Calculate total length
di.total_length() # 15.0
# Set operations
di1 = DisjointInterval([ContinuousInterval(0, 10), ContinuousInterval(20, 30)])
di2 = DisjointInterval([ContinuousInterval(5, 15), ContinuousInterval(25, 35)])
union = di1.union(di2) # Merges all overlaps
intersection = di1.intersection(di2) # [[5, 10], [25, 30]]
difference = di1.difference(di2) # [[0, 5], [20, 25]]
# Complement
universe = ContinuousInterval(0, 40)
complement = di1.complement(universe) # [[10, 20], [30, 40]]
# Iteration
for interval in di:
print(interval) # Iterate over all intervals
# Access by index
first = di[0] # Get first interval
Common Use Cases
1. Schedule Management
from src.intervals import DisjointInterval, ContinuousInterval
# Busy times (in hours)
busy = DisjointInterval([
ContinuousInterval(9, 10), # Meeting 9-10am
ContinuousInterval(11, 12), # Meeting 11am-12pm
ContinuousInterval(14, 16) # Meeting 2-4pm
])
# Work day
work_day = ContinuousInterval(9, 17) # 9am-5pm
# Available times
available = busy.complement(work_day)
# Result: [[10, 11], [12, 14], [16, 17]]
2. Range Validation
from src.intervals import ContinuousInterval
# Valid temperature range
valid_temp = ContinuousInterval(18, 25) # 18-25ยฐC
# Check if temperature is in valid range
current_temp = 22
is_valid = current_temp in valid_temp # True
3. Data Range Analysis
from src.intervals import DisjointInterval, ContinuousInterval
# Data ranges with gaps
data_ranges = DisjointInterval([
ContinuousInterval(0, 100),
ContinuousInterval(150, 250),
ContinuousInterval(300, 400)
])
# Find gaps
universe = ContinuousInterval(0, 400)
gaps = data_ranges.complement(universe)
# Result: [[100, 150], [250, 300]]
# Total data coverage
coverage = data_ranges.total_length() # 250
coverage_percent = (coverage / universe.length()) * 100 # 62.5%
4. Numerical Ranges
from src.intervals import ContinuousInterval
# Mathematical operations with ranges
x_range = ContinuousInterval(-10, 10)
y_range = ContinuousInterval(0, 20)
# Check if ranges overlap
if x_range.is_overlapping(y_range):
overlap = x_range.intersection(y_range)
print(f"Overlap: {overlap}") # [0, 10]
API Reference
Point
Constructor
Point(value: float)- Create a point with the given value
Methods
- Arithmetic:
+,- - Comparison:
==,!=,<,<=,>,>= hash()- Points are hashable
ContinuousInterval
Constructor
ContinuousInterval(start, end, is_start_open=False, is_end_open=False)
Class Methods
ContinuousInterval.empty()- Create an empty interval
Properties
start- Start valueend- End valueis_start_open- Whether start boundary is openis_end_open- Whether end boundary is open
Methods
length()- Get interval lengthis_empty()- Check if interval is emptycontains(item)- Check if contains a Point or ContinuousIntervalcontains_value(value)- Check if contains a numeric valueintersection(interval)- Compute intersectionunion(interval)- Compute uniondifference(interval)- Compute set differenceoverlaps(interval)- Check if intervals overlapis_overlapping(interval)- Comprehensive overlap check
Operators
in- Membership testing:5 in interval+- Add/merge intervals (if adjacent or overlapping)-- Set difference<,<=,>,>=- Interval ordering==,!=- Equality comparisonhash()- Intervals are hashable
DisjointInterval
Constructor
DisjointInterval(intervals: List[ContinuousInterval])- Automatically merges overlaps
Properties
intervals- Get list of non-overlapping intervals (copy)
Methods
add_interval(interval)- Add interval (returns new DisjointInterval)get_interval_containing_point(point)- Find containing intervaltotal_length()- Sum of all interval lengthsunion(other)- Union with another DisjointIntervalintersection(other)- Intersection with another DisjointIntervaldifference(other)- Set differencecomplement(universe)- Complement within a universe interval
Collection Interface
len(di)- Number of intervalsdi[i]- Access interval by indexfor interval in di:- Iterate over intervalsitem in di- Check membership (Point, float, or ContinuousInterval)bool(di)- Check if non-empty
EmptySet
Represents an empty set. Returned by operations that produce no intervals.
Methods
==- Compare with other EmptySet or empty ContinuousInterval
Error Handling
The library provides clear error messages and custom exceptions:
from src.errors import InvalidIntervalError, IntervalError
from src.intervals import ContinuousInterval, Point
# Invalid interval (start > end)
try:
interval = ContinuousInterval(10, 5)
except InvalidIntervalError as e:
print(e) # "Invalid interval: start (10) must be less than or equal to end (5)"
# Type errors
try:
p = Point(5)
result = p + "string"
except TypeError as e:
print(e) # "Unsupported operand type(s) for +: 'Point' and 'str'"
Design Principles
- Immutability: All objects are immutable; operations return new instances
- Type Safety: Strong type checking with helpful error messages
- Pythonic: Follows Python conventions (operators, protocols, naming)
- Explicit: Clear distinction between open and closed boundaries
- Composable: Operations can be chained naturally
Requirements
- Python 3.8+
- No external dependencies for core functionality
- pytest for running tests
Development
Running Tests
# Install development dependencies
pip install pytest pytest-cov
# Run all tests
pytest
# Run with coverage
pytest --cov=src --cov-report=html
# Run specific test file
pytest tests/test_continuous_interval.py
Project Structure
interval-arithmetic/
โโโ src/
โ โโโ __init__.py # Package exports
โ โโโ intervals.py # Core classes
โ โโโ errors.py # Exception classes
โ โโโ utils.py # Utility functions
โโโ tests/
โ โโโ __init__.py
โ โโโ conftest.py # Test fixtures
โ โโโ test_point.py
โ โโโ test_continuous_interval.py
โ โโโ test_disjoint_interval.py
โ โโโ test_utils.py
โโโ README.md
โโโ pyproject.toml
Contributing
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Ensure all tests pass
- Submit a pull request
License
MIT License - see LICENSE file for details
Changelog
Version 0.1.0 (Current)
- Initial release
- Point arithmetic and comparison
- ContinuousInterval with open/closed boundaries
- Set operations (union, intersection, difference)
- DisjointInterval with automatic merging
- Comprehensive test suite (95%+ coverage)
Credits
Developed with focus on mathematical correctness and practical usability.
Support
- ๐ Documentation
- ๐ Issue Tracker
- ๐ฌ Discussions
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file interval_sets-0.1.0.tar.gz.
File metadata
- Download URL: interval_sets-0.1.0.tar.gz
- Upload date:
- Size: 24.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
903fee10baf9a5c33b67d8623b30408e79f2b0917d83e48aed1d1bd5664782e0
|
|
| MD5 |
9efd12d237367020f384b07f7ed3c8a0
|
|
| BLAKE2b-256 |
f1694aacf963b2cc07c269df1f5f1246be5aebf5dbf80162d785470739918c07
|
File details
Details for the file interval_sets-0.1.0-py3-none-any.whl.
File metadata
- Download URL: interval_sets-0.1.0-py3-none-any.whl
- Upload date:
- Size: 13.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9569ed627907810b364a81b443b46477f805dc6a51399313f0f10686ab0e1dff
|
|
| MD5 |
398cabd93f91cad515a023fd647b4d12
|
|
| BLAKE2b-256 |
401517191304fd1ab13acd7988d5ca247947a14c7ee9723573b8ae205f85fde5
|