Commit 674cb4cc authored by dboe's avatar dboe
Browse files

grid working

parent f568111d
Pipeline #102800 passed with stages
in 54 seconds
......@@ -53,7 +53,6 @@ install_requires =
sortedcontainers
tests_require =
doctest
unittest
[options.packages.find]
exclude =
......@@ -66,6 +65,7 @@ all =
dev =
%(docs)s
%(test)s
%(io)s
bumpversion # for incrementing the version
twine # for publishing
sphinx # for documentation
......@@ -87,6 +87,8 @@ test =
pytest-xdist
matplotlib
io =
numpy-stl
[bdist_wheel]
universal = 1
......
import unittest
import itertools
import numpy as np
import tfields
from tfields.lib import grid
from tfields.tensor_grid import TensorGrid
class TensorGrid_Test(unittest.TestCase):
def setUp(self):
self.bv = [(0, 1, 2j), (2, 4, 3j), (5, 8, 4j)]
self.iter_order = [0, 1, 2]
self.res = tfields.Tensors(
[
[0.0, 2.0, 5.0],
[0.0, 2.0, 6.0],
[0.0, 2.0, 7.0],
[0.0, 2.0, 8.0],
[0.0, 3.0, 5.0],
[0.0, 3.0, 6.0],
[0.0, 3.0, 7.0],
[0.0, 3.0, 8.0],
[0.0, 4.0, 5.0],
[0.0, 4.0, 6.0],
[0.0, 4.0, 7.0],
[0.0, 4.0, 8.0],
[1.0, 2.0, 5.0],
[1.0, 2.0, 6.0],
[1.0, 2.0, 7.0],
[1.0, 2.0, 8.0],
[1.0, 3.0, 5.0],
[1.0, 3.0, 6.0],
[1.0, 3.0, 7.0],
[1.0, 3.0, 8.0],
[1.0, 4.0, 5.0],
[1.0, 4.0, 6.0],
[1.0, 4.0, 7.0],
[1.0, 4.0, 8.0],
]
)
def get_tg(self):
tg = TensorGrid.from_base_vectors(*self.bv, iter_order=self.iter_order)
return tg
def check_filled(self, tg):
self.assertTrue(tg.equal(self.res))
self.assertListEqual(tg.base_vectors, self.bv)
def check_empty(self, tg):
self.assertTrue(tg.is_empty())
def test_from_base_vectors(self):
tg = self.get_tg()
self.check_filled(tg)
def test_empty(self):
tg = TensorGrid.empty(*self.bv, iter_order=self.iter_order)
self.check_empty(tg)
tge = tg.explicit()
self.check_filled(tge)
class TensorGrid_Test_Permutation1(TensorGrid_Test):
def setUp(self):
self.bv = [(0, 1, 2j), (2, 4, 3j), (5, 8, 4j)]
self.iter_order = [2, 0, 1]
self.res = tfields.Tensors(
[
[0.0, 2.0, 5.0],
[0.0, 3.0, 5.0],
[0.0, 4.0, 5.0],
[1.0, 2.0, 5.0],
[1.0, 3.0, 5.0],
[1.0, 4.0, 5.0],
[0.0, 2.0, 6.0],
[0.0, 3.0, 6.0],
[0.0, 4.0, 6.0],
[1.0, 2.0, 6.0],
[1.0, 3.0, 6.0],
[1.0, 4.0, 6.0],
[0.0, 2.0, 7.0],
[0.0, 3.0, 7.0],
[0.0, 4.0, 7.0],
[1.0, 2.0, 7.0],
[1.0, 3.0, 7.0],
[1.0, 4.0, 7.0],
[0.0, 2.0, 8.0],
[0.0, 3.0, 8.0],
[0.0, 4.0, 8.0],
[1.0, 2.0, 8.0],
[1.0, 3.0, 8.0],
[1.0, 4.0, 8.0],
]
)
class TensorGrid_Test_IO_Change(unittest.TestCase):
def test_change_iter_order(self):
t1 = TensorGrid_Test()
t1.setUp()
t2 = TensorGrid_Test_Permutation1()
t2.setUp()
tg1 = t1.get_tg()
tg1.fields.append(tfields.Tensors(tg1))
tg1_original = tg1.copy()
tg2 = t2.get_tg()
tg2.fields.append(tfields.Tensors(tg2))
tg1.change_iter_order(t2.iter_order)
self.assertTrue(tg1.equal(tg2))
self.assertFalse(tg1.equal(tg1_original))
tg1.change_iter_order(t1.iter_order)
self.assertTrue(tg1.equal(tg1_original))
def test_lib_forward_backward(self):
bv_lengths = [2, 3, 4]
forw = grid.change_iter_order(bv_lengths, [0, 1, 2], [2, 0, 1])
back = grid.change_iter_order(bv_lengths, [2, 0, 1], [0, 1, 2])
self.assertTrue((np.array(forw)[back] == np.arange(np.prod(bv_lengths))).all())
def test_lib_multi(self):
bv_lengths = [2, 3, 4]
for iter_order in itertools.permutations([0, 1, 2]):
for new_iter_order in itertools.permutations([0, 1, 2]):
forw = grid.change_iter_order(bv_lengths, [0, 1, 2], [2, 0, 1])
back = grid.change_iter_order(bv_lengths, [2, 0, 1], [0, 1, 2])
self.assertTrue(
(np.array(forw)[back] == np.arange(np.prod(bv_lengths))).all()
)
if __name__ == "__main__":
TensorGrid_Test().test_tensor_grid()
# unittest.main()
......@@ -1631,14 +1631,63 @@ class Tensors(AbstractNdarray): # pylint: disable=too-many-public-methods
>>> assert c.equal([42])
>>> assert c.equal(np.dot(a[0], b[0]))
>>> assert c.rank == 0
To get the angle between a and b you now just need
>>> angle = np.arccos(c)
"""
return Tensors(np.einsum("t...i,t...i->t...", self, other))
def norm(self, ord=None, axis=None, keepdims=False):
"""
Calculate the norm up to rank 2
Args:
See numpy.linal.norm except redefinition in axis
axis: by default omitting first axis
Examples:
>>> import tfields
>>> a = tfields.Tensors([[1, 0, 0]])
>>> assert a.norm().equal([1])
"""
if axis is None:
axis = tuple(range(self.ndim)[1:])
return Tensors(np.linalg.norm(self, ord=ord, axis=axis, keepdims=keepdims))
def normalized(self, *args, **kwargs):
"""
Return the self / norm(self)
Args:
forwarded to :meth:norm
Examples:
>>> import tfields
>>> a = tfields.Tensors([[1, 4, 3]])
>>> assert not a.norm().equal([1])
>>> a = a.normalized()
>>> assert a.norm().equal([1])
>>> a = tfields.Tensors([[1, 0, 0],
... [0, 2, 0],
... [0, 0, 3]])
>>> assert a.norm().equal([1, 2, 3])
>>> a = a.normalized()
>>> assert a.equal([
... [1, 0, 0],
... [0, 1, 0],
... [0, 0, 1],
... ])
>>> assert a.norm().equal([1, 1, 1])
"""
# return np.divide(self.T, self.norm(*args, **kwargs)).T
return np.divide(self, self.norm(*args, **kwargs)[:, None])
def plot(self, **kwargs):
"""
Forwarding to rna.plotting.plot_array
Forwarding to rna.plotting.plot_tensor
"""
artist = rna.plotting.plot_array(self, **kwargs) # pylint: disable=no-member
artist = rna.plotting.plot_tensor(self, **kwargs) # pylint: disable=no-member
return artist
......@@ -1992,8 +2041,10 @@ class TensorFields(Tensors):
"different dimension. No coord_sys check performed."
)
if field.dim <= 3:
artist = rna.plotting.plot_tensor_field( # noqa: E501 pylint: disable=no-member
self, field, **kwargs
artist = (
rna.plotting.plot_tensor( # noqa: E501 pylint: disable=no-member
self, field, **kwargs
)
)
else:
raise NotImplementedError(
......
import typing
import numpy as np
import functools
import tfields.lib.util
......@@ -92,7 +93,7 @@ def igrid(*base_vectors, **kwargs):
... [ 1., 4., 7.]])
"""
iter_order = kwargs.pop('iter_order', np.arange(len(base_vectors)))
iter_order = kwargs.pop("iter_order", np.arange(len(base_vectors)))
base_vectors = ensure_complex(*base_vectors)
# create the grid
......@@ -103,9 +104,12 @@ def igrid(*base_vectors, **kwargs):
else:
base_vectors = to_base_vectors(*base_vectors)
obj = np.empty(shape=(functools.reduce(lambda x, y: x * y,
map(len, base_vectors)),
len(base_vectors)))
obj = np.empty(
shape=(
functools.reduce(lambda x, y: x * y, map(len, base_vectors)),
len(base_vectors),
)
)
def loop_rec(y, n_max, i=0, n=None, *vals):
if n is None:
......@@ -173,6 +177,7 @@ def swap_columns(array, *index_tuples):
Args:
array (list or array)
expects tuples with indices to swap as arguments
Examples:
>>> import tfields
>>> l = np.array([[3, 2, 1, 0], [6, 5, 4, 3]])
......@@ -180,15 +185,13 @@ def swap_columns(array, *index_tuples):
>>> l
array([[0, 1, 2, 3],
[3, 4, 5, 6]])
"""
# test swap_indices type
for si in index_tuples:
if hasattr(si, '__iter__'):
if hasattr(si, "__iter__"):
if len(si) == 2:
continue
raise TypeError("swap_indices must be tuple but is {}"
.format(si))
raise TypeError("swap_indices must be tuple but is {}".format(si))
for i, j in index_tuples:
array[:, [i, j]] = array[:, [j, i]]
......@@ -198,13 +201,13 @@ def swap_rows(array, *args):
Args:
array (list)
expects tuples with indices to swap as arguments
Examples:
>>> import tfields
>>> l = [[3,3,3], [2,2,2], [1,1,1], [0, 0, 0]]
>>> tfields.lib.grid.swap_rows(l, (1, 2), (0, 3))
>>> l
[[0, 0, 0], [1, 1, 1], [2, 2, 2], [3, 3, 3]]
"""
for i, j in args:
array[i], array[j] = array[j], array[i]
......@@ -212,7 +215,8 @@ def swap_rows(array, *args):
def compare_permutations(permut1, permut2):
"""
Return what you need to switch in order to make permut1 become permut2
Return what rows you need to switch in order to make permut1 become permut2
Examples:
>>> import tfields
>>> a = [1, 2, 0, 4, 3]
......@@ -225,7 +229,6 @@ def compare_permutations(permut1, permut2):
[0, 1, 2, 3, 4]
>>> a == b
True
"""
swap_indices = []
permut1 = list(permut1)
......@@ -239,6 +242,28 @@ def compare_permutations(permut1, permut2):
return swap_indices
if __name__ == '__main__':
import doctest
doctest.testmod()
def change_iter_order(
bv_lengths: typing.List[int],
iter_order: typing.List[int],
iter_order_new: typing.List[int],
):
"""
Args:
bv_lengths: lenghts of basis vectors
Returns:
indices for changeing fields generated with iter_order to iter_order_new
"""
indices = np.arange(np.prod(bv_lengths))
shape = []
for i in iter_order:
shape.append(bv_lengths[i])
indices = indices.reshape(shape)
# swaps = compare_permutations(iter_order_new, iter_order)
swaps = compare_permutations(iter_order, iter_order_new)
# swaps = compare_permutations(iter_order_new, np.arange(len(iter_order)))
for swap in swaps:
indices = np.swapaxes(indices, swap[0], swap[1])
# indices = np.transpose(indices, axes=axes_transp)
return np.array(indices.flat)
import numpy as np
from .lib import grid
from .core import TensorFields
class TensorGrid(TensorFields):
"""
A Tensor Grid is a TensorField which is aware of it's grid nature, which is order of iteration
(iter-order) over the base vectors (base_vectors).
Args:
*base_vectors (tuple): indices of the axes which should be iterated
**kwargs:
iter_order (np.array): index order of building the grid.
further: see TensorFields class
"""
__slots__ = ["coord_sys", "name", "fields", "base_vectors", "iter_order"]
__slot_setters__ = TensorFields.__slot_setters__ + [
None,
None,
]
def __new__(cls, tensors, *fields, **kwargs):
if issubclass(type(tensors), TensorGrid):
default_base_vectors = tensors.base_vectors
default_iter_order = tensors.iter_order
else:
default_base_vectors = kwargs.pop("base_vectors")
default_iter_order = np.arange(len(default_base_vectors))
base_vectors = kwargs.pop("base_vectors", default_base_vectors)
iter_order = kwargs.pop("iter_order", default_iter_order)
base_vectors = grid.ensure_complex(*base_vectors)
obj = super(TensorGrid, cls).__new__(cls, tensors, *fields, **kwargs)
obj.base_vectors = base_vectors
obj.iter_order = iter_order
return obj
@classmethod
def from_base_vectors(cls, *base_vectors, tensors=None, fields=None, **kwargs):
iter_order = kwargs.pop("iter_order", np.arange(len(base_vectors)))
if tensors is None:
tensors = TensorFields.grid(*base_vectors, iter_order=iter_order, **kwargs)
obj = cls(tensors, base_vectors=base_vectors, iter_order=iter_order)
if fields:
obj.fields = fields
return obj
@classmethod
def empty(cls, *base_vectors, **kwargs):
base_vectors = grid.ensure_complex(*base_vectors)
bv_lengths = [int(bv[2].imag) for bv in base_vectors]
tensors = np.empty(shape=(np.prod(bv_lengths), 0))
return cls.from_base_vectors(*base_vectors, tensors=tensors, **kwargs)
@property
def rank(self):
if self.is_empty():
return 1
return super().rank
def is_empty(self):
return 0 in self.shape
def explicit(self):
"""
Build the grid explicitly (e.g. after changing base_vector, iter_order or init with empty)
"""
kwargs = {attr: getattr(self, attr) for attr in self.__slots__}
base_vectors = kwargs.pop("base_vectors")
return self.from_base_vectors(*base_vectors, **kwargs)
def change_iter_order(self, iter_order):
bv_lengths = [int(bv[2].imag) for bv in self.base_vectors]
field_swap_indices = grid.change_iter_order(
bv_lengths, self.iter_order, iter_order
)
for field in self.fields:
field[:] = field[field_swap_indices]
self.iter_order = iter_order
self[:] = self.explicit()
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment