"""
Defines the basis structure to store subsets of real line.
The main purpose of this module is to be returned from analytics roots
or when concatenating piecewise curves
Here we define 5 classes:
* Empty : Represents an empty set {} of the real line R1
* Whole : Represents the entire real line R1
* SingleValue : Represents a subset of R1 with only one finite element
* Interval : Represents a subset of R1 with continuous points
* Disjoint : Represents the union of some SingleValue and Interval
With them, we can verify if one subset contains another subset
It's possible to make the standard boolean operations, like union,
intersection, inversion, xor and so on
"""
from __future__ import annotations
from abc import ABC, abstractmethod
from typing import Tuple, Union
from .error import NotExpectedError
from .numbs import NEGINF, POSINF, Is, Real, To
class Future:
"""
Class that stores methods that are further defined.
They are overrided by other methods in __init__.py file
"""
@staticmethod
def convert(obj: object) -> SubSetR1:
"""
Converts an object to a SubSetR1 instance.
This function is overrided by a function defined
in the `converter.py` file
Example
-------
>>> type(convert("{}"))
<class "rbool.base.EmptyR2">
"""
raise NotExpectedError
@staticmethod
def unite(*subsets: SubSetR1) -> SubSetR1:
"""
Computes the union of some SubSetR1 instances
This function is overrided by a function defined
in the `rbool.bool1d.py` file
"""
raise NotExpectedError
@staticmethod
def intersect(*subsets: SubSetR1) -> SubSetR1:
"""
Computes the intersection of some SubSetR1 instances
This function is overrided by a function defined
in the `rbool.bool1d.py` file
"""
raise NotExpectedError
@staticmethod
def invert(subset: SubSetR1) -> SubSetR1:
"""
Computes the inversion of a SubSetR1 instance
This function is overrided by a function defined
in the `rbool.bool1d.py` file
"""
raise NotExpectedError
@staticmethod
def contains(subseta: SubSetR1, subsetb: SubSetR1) -> bool:
"""
Checks if the subsetb is contained by subseta
This function is overrided by a function defined
in the `rbool.bool1d.py` file
"""
raise NotExpectedError
@staticmethod
def move(subset: SubSetR1, vector: Tuple[Real, Real]) -> SubSetR1:
"""
Moves the SubSetR1 instance by given vector
This function is overrided by a function defined
in the `rbool.transform.py` file
"""
raise NotExpectedError
@staticmethod
def scale(
subset: SubSetR1, amount: Union[Real, Tuple[Real, Real]]
) -> SubSetR1:
"""
Scales the SubSetR1 instance by given amount
This function is overrided by a function defined
in the `rbool.transform.py` file
"""
raise NotExpectedError
class SubSetR1(ABC):
"""
General class to be parent of some others.
It represents an arbitrary subset of R1.
"""
@abstractmethod
def __hash__(self):
raise NotImplementedError
@abstractmethod
def __eq__(self, other):
raise NotImplementedError
@abstractmethod
def __contains__(self, other):
raise NotImplementedError
def move(self, amount: Real) -> SubSetR1:
"""
Translates the entire subset of R1 to the right by given amount
new_set = {x + a for x in old_set}
Parameters
----------
amount : Real
The quantity to be translated
Return
------
SubSetR1
The translated subset
"""
return Future.move(self, amount)
def scale(self, amount: Real) -> SubSetR1:
"""
Scales the entire subset of R1 to the right by given amount
new_set = {a * x for x in old_set}
Negative values are valid.
Parameters
----------
amount : Real
The quantity to be scaled. Cannot be zero.
Return
------
SubSetR1
The scaled subset
"""
return Future.scale(self, amount)
def __invert__(self):
return Future.invert(self)
def __or__(self, other):
return Future.unite(self, Future.convert(other))
def __and__(self, other):
return Future.intersect(self, Future.convert(other))
def __ror__(self, other):
return self.__or__(Future.convert(other))
def __rand__(self, other):
return self.__and__(Future.convert(other))
def __xor__(self, other):
other = Future.convert(other)
return (self & (~other)) | (other & (~self))
def __sub__(self, other):
return self & (~Future.convert(other))
def __rsub__(self, other):
return (~self) & Future.convert(other)
def __rxor__(self, other):
return self ^ Future.convert(other)
def __repr__(self):
return self.__str__()
def __ne__(self, other):
return not self == other
[docs]
class Empty(SubSetR1):
"""
Empty class is a singleton that represents an empty set
It's equivalent to: Empty = {}
"""
instance = None
def __new__(cls):
if cls.instance is None:
cls.instance = super().__new__(cls)
return cls.instance
def __contains__(self, other) -> bool:
if Is.real(other):
return False
return Future.convert(other) is self
[docs]
def move(self, amount: Real) -> SubSetR1:
To.finite(amount) # Checks if it's finite
return self
[docs]
def scale(self, amount: Real) -> SubSetR1:
To.finite(amount) # Checks if it's finite
return self
def __invert__(self):
return Whole()
def __and__(self, other):
Future.convert(other)
return self
def __or__(self, other):
return Future.convert(other)
def __rand__(self, other):
Future.convert(other)
return self
def __ror__(self, other):
return Future.convert(other)
def __str__(self):
return r"{}"
def __repr__(self):
return "Empty"
def __eq__(self, other):
return self is Future.convert(other)
def __hash__(self):
return 0
[docs]
class Whole(SubSetR1):
"""
Whole class is a singleton that represents the entire real line
It's equivalent to: Whole = (-inf, +inf)
"""
instance = None
def __new__(cls):
if cls.instance is None:
cls.instance = super().__new__(cls)
return cls.instance
def __contains__(self, other) -> bool:
if Is.real(other):
return True
Future.convert(other)
return True
[docs]
def move(self, amount: Real) -> SubSetR1:
To.finite(amount) # Checks if it's finite
return self
[docs]
def scale(self, amount: Real) -> SubSetR1:
To.finite(amount) # Checks if it's finite
return self
def __invert__(self):
return Empty()
def __and__(self, other):
return Future.convert(other)
def __or__(self, other):
Future.convert(other)
return self
def __rand__(self, other):
return Future.convert(other)
def __ror__(self, other):
Future.convert(other)
return self
def __str__(self):
return "(" + str(NEGINF) + ", " + str(POSINF) + ")"
def __repr__(self):
return "Whole"
def __eq__(self, other):
return self is Future.convert(other)
def __hash__(self):
return 1