Geometry Operations Enhancement (#122)

* updating exclusion domain
- update sample/ is_inside
- create tests

* difference fixes
- random iteration list for sample

* created Intersection

* created a Difference domain

* unittest

* docstrings and minor fixes

* Refacotring Geometries
- added OperationInterface
- redid test cases
- edited Union, Intersect, Exclusion, and Difference
to inherit from OperationInterface
- simplified Union, Intersect, Exclusion, and Difference

* rm lighting logs

---------

Co-authored-by: Dario Coscia <dariocoscia@cli-10-110-16-239.WIFIeduroamSTUD.units.it>
This commit is contained in:
Kush
2023-07-04 12:08:47 +02:00
committed by Nicola Demo
parent 44cf800491
commit 2d0256a179
13 changed files with 534 additions and 80 deletions

View File

@@ -1,28 +1,88 @@
"""Module for Location class."""
from .location import Location
import torch
from .exclusion_domain import Exclusion
from .operation_interface import OperationInterface
from ..label_tensor import LabelTensor
class Difference(Location):
"""
"""
class Difference(OperationInterface):
""" PINA implementation of Difference of Domains."""
def __init__(self, first, second):
def __init__(self, geometries):
""" PINA implementation of Difference of Domains.
self.first = first
self.second = second
:param list geometries: A list of geometries from 'pina.geometry'
such as 'EllipsoidDomain' or 'CartesianDomain'. The first
geometry in the list is the geometry from which points are
sampled. The rest of the geometries are the geometries that
are excluded from the first geometry to find the difference.
:Example:
# Create two ellipsoid domains
>>> ellipsoid1 = EllipsoidDomain({'x': [-1, 1], 'y': [-1, 1]})
>>> ellipsoid2 = EllipsoidDomain({'x': [0, 2], 'y': [0, 2]})
# Create a Difference of the ellipsoid domains
>>> difference = Difference([ellipsoid1, ellipsoid2])
"""
super().__init__(geometries)
def is_inside(self, point, check_border=False):
for geometry in self.geometries[1:]:
if geometry.is_inside(point):
return False
return self.geometries[0].is_inside(point, check_border)
def sample(self, n, mode='random', variables='all'):
"""
"""
assert mode == 'random', 'Only random mode is implemented'
"""Sample routine for difference domain.
samples = []
while len(samples) < n:
sample = self.first.sample(1, 'random')
if not self.second.is_inside(sample):
samples.append(sample)
:param n: Number of points to sample in the shape.
:type n: int
:param mode: Mode for sampling, defaults to 'random'.
Available modes include: random sampling, 'random'.
:type mode: str, optional
:param variables: pinn variable to be sampled, defaults to 'all'.
:type variables: str or list[str], optional
import torch
return LabelTensor(torch.cat(samples), labels=['x', 'y'])
:Example:
# Create two Cartesian domains
>>> cartesian1 = CartesianDomain({'x': [0, 2], 'y': [0, 2]})
>>> cartesian2 = CartesianDomain({'x': [1, 3], 'y': [1, 3]})
# Create a Difference of the ellipsoid domains
>>> difference = Difference([cartesian1, cartesian2])
>>> difference.sample(n=5)
LabelTensor([[0.8400, 0.9179],
[0.9154, 0.5769],
[1.7403, 0.4835],
[0.9545, 1.2851],
[1.3726, 0.9831]])
>>> len(difference.sample(n=5)
5
"""
if mode != 'random':
raise NotImplementedError(
f'{mode} is not a valid mode for sampling.')
sampled = []
# sample the points
while len(sampled) < n:
# get sample point from first geometry
point = self.geometries[0].sample(1, mode, variables)
is_inside = False
# check if point is inside any other geometry
for geometry in self.geometries[1:]:
# if point is inside any other geometry, break
if geometry.is_inside(point):
is_inside = True
break
# if point is not inside any other geometry, add to sampled
if not is_inside:
sampled.append(point)
return LabelTensor(torch.cat(sampled), labels=self.variables)