# © 2015-2018, ETH Zurich, Institut für Theoretische Physik
# Author: Dominik Gresch <greschd@gmx.ch>
import typing as ty
import numpy as np
from ._coordinate import Coordinate
class Sentinel:
__INSTANCES: ty.Dict[str, "Sentinel"] = dict()
def __new__(cls, value: str) -> "Sentinel":
if value in cls.__INSTANCES:
return cls.__INSTANCES[value]
self = ty.cast("Sentinel", super().__new__(cls))
self._value = value # type: ignore
cls.__INSTANCES[value] = self
return self
def __repr__(self):
return f"Sentinel({self._value!r})" # pylint: disable=no-member
PHASE_UNDEFINED = Sentinel("undefined phase")
[docs]class Box:
"""
Class describing a "box" (or n-dimensional hyperrectangle).
Attributes
----------
corner: Coordinate
The vertex with the lowest indices.
size: Coordinate
Size of the box.
phase:
The phase of the box, determined by the evaluated points it contains: If all points have the same phase, the box will have that phase. Otherwise, the phase of the box is undefined.
"""
def __init__(self, *, corner, size):
self.corner = Coordinate(corner)
self.phase = None
self.size = Coordinate(size)
self._neighbours = set()
self._points = dict()
def __hash__(self):
return hash((self.corner, self.size))
def __eq__(self, other):
return np.all(self.corner == other.corner) and np.all(self.size == other.size)
def __repr__(self):
return "Box(corner={0.corner}, size={0.size}, phase={0.phase})".format(self)
def contains_coord(self, coord):
# Faster than pure numpy operations because of the slow 'Fraction'.
# In this way, the remaining operations are not performed if one
# expression evaluates to False.
return all(c1 <= c2 for c1, c2 in zip(self.corner, coord)) and all(
c2 <= c1 + s for c1, c2, s in zip(self.corner, coord, self.size)
)
def add_point(self, coord, phase):
if self.contains_coord(coord):
self._points[coord] = phase
if self.phase is None:
self.phase = phase
elif self.phase == phase:
return
else:
self.phase = PHASE_UNDEFINED
def is_neighbour(self, other):
return all(
c1 + s1 >= c2 and c2 + s2 >= c1
for c1, s1, c2, s2 in zip(self.corner, self.size, other.corner, other.size)
)
def process_possible_neighbour(self, box):
if self.is_neighbour(box):
self.process_certain_neighbour(box)
def process_certain_neighbour(self, box):
self._neighbours.add(box)
box._neighbours.add(self) # pylint: disable=protected-access
def delete_from_neighbours(self):
for n in self._neighbours:
n.delete_neighbour(self)
def delete_neighbour(self, box):
self._neighbours.discard(box)