allclose

metatensor.allclose(tensor_1: TensorMap, tensor_2: TensorMap, rtol: float = 1e-13, atol: float = 1e-12, equal_nan: bool = False) bool[source]

Compare two TensorMap.

This function returns True if the two tensors have the same keys (potentially in different order) and all the TensorBlock have the same (and in the same order) samples, components, properties, and their values matrices pass the numpy-like allclose test with the provided rtol, and atol.

The TensorMap contains gradient data, then this function only returns True if all the gradients also have the same samples, components, properties and their data matrices pass the numpy-like allclose test with the provided rtol, and atol.

In practice this function calls allclose_raise(), returning True if no exception is raised, False otherwise.

Parameters:
Return type:

bool

Examples

>>> import numpy as np
>>> from metatensor import Labels, TensorBlock

Create simple block

>>> block_1 = TensorBlock(
...     values=np.array(
...         [
...             [1, 2, 4],
...             [3, 5, 6],
...         ]
...     ),
...     samples=Labels(
...         ["system", "atom"],
...         np.array(
...             [
...                 [0, 0],
...                 [0, 1],
...             ]
...         ),
...     ),
...     components=[],
...     properties=Labels(["properties"], np.array([[0], [1], [2]])),
... )

Create a second block that is equivalent to block_1.

>>> block_2 = TensorBlock(
...     values=np.array(
...         [
...             [1, 2, 4],
...             [3, 5, 6],
...         ]
...     ),
...     samples=Labels(
...         ["system", "atom"],
...         np.array(
...             [
...                 [0, 0],
...                 [0, 1],
...             ]
...         ),
...     ),
...     components=[],
...     properties=Labels(["properties"], np.array([[0], [1], [2]])),
... )

Create tensors from blocks, using keys with different names

>>> keys1 = Labels(names=["key1"], values=np.array([[0]]))
>>> keys2 = Labels(names=["key2"], values=np.array([[0]]))
>>> tensor_1 = TensorMap(keys1, [block_1])
>>> tensor_2 = TensorMap(keys2, [block_2])

Call metatensor.allclose(), which should fail as the blocks have different keys associated with them.

>>> allclose(tensor_1, tensor_2)
False

Create a third tensor, which differs from tensor_1 only by 1e-5 in a single block value.

>>> block3 = TensorBlock(
...     values=np.array(
...         [
...             [1 + 1e-5, 2, 4],
...             [3, 5, 6],
...         ]
...     ),
...     samples=Labels(
...         ["system", "atom"],
...         np.array(
...             [
...                 [0, 0],
...                 [0, 1],
...             ]
...         ),
...     ),
...     components=[],
...     properties=Labels(["properties"], np.array([[0], [1], [2]])),
... )

Create tensors from blocks, using a key with same name as block_1.

>>> keys3 = Labels(names=["key1"], values=np.array([[0]]))
>>> tensor3 = TensorMap(keys3, [block3])

Call metatensor.allclose(), which should return False because the default rtol is 1e-13, and the difference in the first value between the blocks of the two tensors is 1e-5.

>>> allclose(tensor_1, tensor3)
False

Calling allclose again with the optional argument rtol=1e-5 should return True, as the difference in the first value between the blocks of the two tensors is within the tolerance limit

>>> allclose(tensor_1, tensor3, rtol=1e-5)
True
metatensor.allclose_raise(tensor_1: TensorMap, tensor_2: TensorMap, rtol: float = 1e-13, atol: float = 1e-12, equal_nan: bool = False)[source]

Compare two TensorMap, raising NotEqualError if they are not the same.

The message associated with the exception will contain more information on where the two TensorMap differ. See allclose() for more information on which TensorMap are considered equal.

Raises:

NotEqualError if the blocks are different

Parameters:

Examples

>>> import numpy as np
>>> import metatensor
>>> from metatensor import Labels, TensorBlock

Create simple block, with one py:obj:np.nan value.

>>> block_1 = TensorBlock(
...     values=np.array(
...         [
...             [1, 2, 4],
...             [3, 5, np.nan],
...         ]
...     ),
...     samples=Labels(
...         ["system", "atom"],
...         np.array(
...             [
...                 [0, 0],
...                 [0, 1],
...             ]
...         ),
...     ),
...     components=[],
...     properties=Labels(["properties"], np.array([[0], [1], [2]])),
... )

Create a second block that differs from block_1 by 1e-5 in its first value.

>>> block_2 = TensorBlock(
...     values=np.array(
...         [
...             [1 + 1e-5, 2, 4],
...             [3, 5, np.nan],
...         ]
...     ),
...     samples=Labels(
...         ["system", "atom"],
...         np.array(
...             [
...                 [0, 0],
...                 [0, 1],
...             ]
...         ),
...     ),
...     components=[],
...     properties=Labels(["properties"], np.array([[0], [1], [2]])),
... )

Create tensors from blocks, using same keys

>>> keys = Labels(names=["key"], values=np.array([[0]]))
>>> tensor_1 = TensorMap(keys, [block_1])
>>> tensor_2 = TensorMap(keys, [block_2])

Call metatensor.allclose_raise(), which should raise metatensor.NotEqualError because:

  1. The two NaN are not considered equal.

  2. The difference between the first value in the blocks is greater than the default rtol of 1e-13.

If this is executed yourself, you will see a nested exception explaining that the values of the two blocks are not allclose.

>>> allclose_raise(tensor_1, tensor_2)
Traceback (most recent call last):
    ...
metatensor.operations._utils.NotEqualError: blocks for key (key=0) are different: values are not allclose

call metatensor.allclose_raise() again, but use equal_nan=True and rtol=1e-5 This passes, as the two NaN are now considered equal, and the difference between the first value of the blocks of the two tensors is within the rtol limit of 1e-5.

>>> allclose_raise(tensor_1, tensor_2, equal_nan=True, rtol=1e-5)
metatensor.allclose_block(block_1: TensorBlock, block_2: TensorBlock, rtol: float = 1e-13, atol: float = 1e-12, equal_nan: bool = False) bool[source]

Compare two TensorBlock.

This function returns True if the two TensorBlock have the same samples, components, properties and their values matrices must pass the numpy-like allclose test with the provided rtol, and atol.

If the TensorBlock contains gradients, then the gradient must also have same (and in the same order) samples, components, properties and their data matrices must pass the numpy-like allclose test with the provided rtol, and atol.

In practice this function calls allclose_block_raise(), returning True if no exception is raised, False otherwise.

Parameters:
Return type:

bool

Examples

>>> import numpy as np
>>> from metatensor import Labels, TensorBlock

Create simple block

>>> block_1 = TensorBlock(
...     values=np.array(
...         [
...             [1, 2, 4],
...             [3, 5, 6],
...         ]
...     ),
...     samples=Labels(
...         ["system", "atom"],
...         np.array(
...             [
...                 [0, 0],
...                 [0, 1],
...             ]
...         ),
...     ),
...     components=[],
...     properties=Labels(["property_1"], np.array([[0], [1], [2]])),
... )

Recreate block_1, but change first value in the block from 1 to 1.00001.

>>> block_2 = TensorBlock(
...     values=np.array(
...         [
...             [1 + 1e-5, 2, 4],
...             [3, 5, 6],
...         ]
...     ),
...     samples=Labels(
...         ["system", "atom"],
...         np.array(
...             [
...                 [0, 0],
...                 [0, 1],
...             ]
...         ),
...     ),
...     components=[],
...     properties=Labels(["property_1"], np.array([[0], [1], [2]])),
... )

Call metatensor.allclose_block(), which should return False because the default rtol is 1e-13, and the difference in the first value between the two blocks is 1e-5.

>>> allclose_block(block_1, block_2)
False

Calling metatensor.allclose_block() with the optional argument rtol=1e-5 should return True, as the difference in the first value between the two blocks is within the tolerance limit.

>>> allclose_block(block_1, block_2, rtol=1e-5)
True
metatensor.allclose_block_raise(block_1: TensorBlock, block_2: TensorBlock, rtol: float = 1e-13, atol: float = 1e-12, equal_nan: bool = False)[source]

Compare two TensorBlock, raising NotEqualError if they are not the same.

The message associated with the exception will contain more information on where the two TensorBlock differ. See allclose_block() for more information on which TensorBlock are considered equal.

Raises:

NotEqualError if the blocks are different

Parameters:

Examples

>>> import numpy as np
>>> import metatensor
>>> from metatensor import Labels, TensorBlock

Create simple block

>>> block_1 = TensorBlock(
...     values=np.array(
...         [
...             [1, 2, 4],
...             [3, 5, 6],
...         ]
...     ),
...     samples=Labels(
...         ["system", "atom"],
...         np.array(
...             [
...                 [0, 0],
...                 [0, 1],
...             ]
...         ),
...     ),
...     components=[],
...     properties=Labels(["property_1"], np.array([[0], [1], [2]])),
... )

Recreate block_1, but rename properties label 'property_1' to 'property_2'.

>>> block_2 = TensorBlock(
...     values=np.array(
...         [
...             [1, 2, 4],
...             [3, 5, 6],
...         ]
...     ),
...     samples=Labels(
...         ["system", "atom"],
...         np.array(
...             [
...                 [0, 0],
...                 [0, 1],
...             ]
...         ),
...     ),
...     components=[],
...     properties=Labels(["property_2"], np.array([[0], [1], [2]])),
... )

Call metatensor.allclose_block_raise(), which should raise metatensor.NotEqualError() because the properties of the two blocks are not equal.

>>> allclose_block_raise(block_1, block_2)
Traceback (most recent call last):
    ...
metatensor.operations._utils.NotEqualError: inputs to 'allclose' should have the same properties, but they are not the same or not in the same order