# Path: soap/lattice/base.py
# class Lattice(Flyweight):
#     """Common lattice structure.
# 
#     Because the partial orders we are using are always complete lattices,
#     structures such as preorders, partial orders, dcpos are not implemented.
# 
#     Subclasses of this class must implement the member functions:
#     :member:`join`, :member:`meet`, :member:`le`.
#     """
#     __slots__ = ('_hash', 'top', 'bottom')
# 
#     def __init__(self, *args, top=False, bottom=False, **kwargs):
#         super().__init__()
#         if top and bottom:
#             raise ValueError(
#                 'Lattice element cannot be bottom and top simultaneously.')
#         self.top = top
#         self.bottom = bottom
#         self._hash = None
# 
#         _decorate(self.__class__)
# 
#     def is_top(self):
#         if self.top:
#             return True
#         if self.bottom:
#             return False
# 
#     def is_bottom(self):
#         if self.top:
#             return False
#         if self.bottom:
#             return True
# 
#     def join(self, other):
#         if self.is_top() or other.is_bottom():
#             return self
#         if self.is_bottom() or other.is_top():
#             return other
# 
#     def meet(self, other):
#         if self.is_top() or other.is_bottom():
#             return other
#         if self.is_bottom() or other.is_top():
#             return self
# 
#     def le(self, other):
#         if not isinstance(other, self.__class__):
#             return False
#         if self.is_bottom() or other.is_top():
#             return True
#         if self.is_top() and not other.is_top():
#             return False
#         if not self.is_bottom() and other.is_bottom():
#             return False
# 
#     __or__ = lambda self, other: self.join(other)
#     __ror__ = lambda self, other: self.join(other)
#     __and__ = lambda self, other: self.meet(other)
#     __rand__ = lambda self, other: self.meet(other)
# 
#     __le__ = _compare(lambda self, other: self.le(other))
#     __lt__ = _compare(
#         lambda self, other: self.le(other) and not other.le(self))
#     __ge__ = _compare(lambda self, other: other.le(self))
#     __gt__ = _compare(
#         lambda self, other: other.le(self) and not self.le(other))
#     __eq__ = _compare(lambda self, other: self.le(other) and other.le(self))
#     __ne__ = _compare(
#         lambda self, other: not self.le(other) or not other.le(self))
# 
#     def __hash__(self):
#         hash_val = self._hash
#         if hash_val:
#             return hash_val
#         is_top = self.is_top()
#         is_bottom = self.is_bottom()
#         if is_top or is_bottom:
#             self._hash = hash_val = hash((is_top, is_bottom))
#             return hash_val
# 
#     def __str__(self):
#         if self.is_top():
#             return '⊤'
#         if self.is_bottom():
#             return '⊥'
# 
#     def __repr__(self):
#         if self.is_top():
#             return self.__class__.__name__ + '(top=True)'
#         if self.is_bottom():
#             return self.__class__.__name__ + '(bottom=True)'


import unittest
from soap.lattice import Lattice



class TestLattice(unittest.TestCase):
    """Unittesting for :class:`soap.lattice.base.Lattice`."""
    def setUp(self):
        self.bottom = Lattice(bottom=True)

# Path: soap/lattice/base.py
# class Lattice(Flyweight):
#     """Common lattice structure.
# 
#     Because the partial orders we are using are always complete lattices,
#     structures such as preorders, partial orders, dcpos are not implemented.
# 
#     Subclasses of this class must implement the member functions:
#     :member:`join`, :member:`meet`, :member:`le`.
#     """
#     __slots__ = ('_hash', 'top', 'bottom')
# 
#     def __init__(self, *args, top=False, bottom=False, **kwargs):
#         super().__init__()
#         if top and bottom:
#             raise ValueError(
#                 'Lattice element cannot be bottom and top simultaneously.')
#         self.top = top
#         self.bottom = bottom
#         self._hash = None
# 
#         _decorate(self.__class__)
# 
#     def is_top(self):
#         if self.top:
#             return True
#         if self.bottom:
#             return False
# 
#     def is_bottom(self):
#         if self.top:
#             return False
#         if self.bottom:
#             return True
# 
#     def join(self, other):
#         if self.is_top() or other.is_bottom():
#             return self
#         if self.is_bottom() or other.is_top():
#             return other
# 
#     def meet(self, other):
#         if self.is_top() or other.is_bottom():
#             return other
#         if self.is_bottom() or other.is_top():
#             return self
# 
#     def le(self, other):
#         if not isinstance(other, self.__class__):
#             return False
#         if self.is_bottom() or other.is_top():
#             return True
#         if self.is_top() and not other.is_top():
#             return False
#         if not self.is_bottom() and other.is_bottom():
#             return False
# 
#     __or__ = lambda self, other: self.join(other)
#     __ror__ = lambda self, other: self.join(other)
#     __and__ = lambda self, other: self.meet(other)
#     __rand__ = lambda self, other: self.meet(other)
# 
#     __le__ = _compare(lambda self, other: self.le(other))
#     __lt__ = _compare(
#         lambda self, other: self.le(other) and not other.le(self))
#     __ge__ = _compare(lambda self, other: other.le(self))
#     __gt__ = _compare(
#         lambda self, other: other.le(self) and not self.le(other))
#     __eq__ = _compare(lambda self, other: self.le(other) and other.le(self))
#     __ne__ = _compare(
#         lambda self, other: not self.le(other) or not other.le(self))
# 
#     def __hash__(self):
#         hash_val = self._hash
#         if hash_val:
#             return hash_val
#         is_top = self.is_top()
#         is_bottom = self.is_bottom()
#         if is_top or is_bottom:
#             self._hash = hash_val = hash((is_top, is_bottom))
#             return hash_val
# 
#     def __str__(self):
#         if self.is_top():
#             return '⊤'
#         if self.is_bottom():
#             return '⊥'
# 
#     def __repr__(self):
#         if self.is_top():
#             return self.__class__.__name__ + '(top=True)'
#         if self.is_bottom():
#             return self.__class__.__name__ + '(bottom=True)'


# Path: tests/test_lattice.py
import unittest
from soap.lattice import Lattice




class TestLattice(unittest.TestCase):
    """Unittesting for :class:`soap.lattice.base.Lattice`."""
    def setUp(self):
        self.bottom = Lattice(bottom=True)

        self.top = Lattice(top=True)