metatensor-core 0.2.2__tar.gz → 0.2.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. {metatensor_core-0.2.2 → metatensor_core-0.2.3}/CMakeLists.txt +1 -1
  2. {metatensor_core-0.2.2 → metatensor_core-0.2.3}/PKG-INFO +1 -1
  3. metatensor_core-0.2.3/git_version_info +2 -0
  4. {metatensor_core-0.2.2 → metatensor_core-0.2.3}/metatensor/_data/_array.py +2 -2
  5. {metatensor_core-0.2.2 → metatensor_core-0.2.3}/metatensor/_data/_dlpack.py +16 -11
  6. {metatensor_core-0.2.2 → metatensor_core-0.2.3}/metatensor/_labels.py +75 -46
  7. {metatensor_core-0.2.2 → metatensor_core-0.2.3}/metatensor/_tensor.py +76 -6
  8. metatensor_core-0.2.3/metatensor-core-cxx-0.2.3.tar.gz +0 -0
  9. {metatensor_core-0.2.2 → metatensor_core-0.2.3}/metatensor_core.egg-info/PKG-INFO +1 -1
  10. {metatensor_core-0.2.2 → metatensor_core-0.2.3}/metatensor_core.egg-info/SOURCES.txt +1 -1
  11. metatensor_core-0.2.2/git_version_info +0 -2
  12. metatensor_core-0.2.2/metatensor-core-cxx-0.2.2.tar.gz +0 -0
  13. {metatensor_core-0.2.2 → metatensor_core-0.2.3}/AUTHORS +0 -0
  14. {metatensor_core-0.2.2 → metatensor_core-0.2.3}/LICENSE +0 -0
  15. {metatensor_core-0.2.2 → metatensor_core-0.2.3}/MANIFEST.in +0 -0
  16. {metatensor_core-0.2.2 → metatensor_core-0.2.3}/README.rst +0 -0
  17. {metatensor_core-0.2.2 → metatensor_core-0.2.3}/metatensor/__init__.py +0 -0
  18. {metatensor_core-0.2.2 → metatensor_core-0.2.3}/metatensor/_block.py +0 -0
  19. {metatensor_core-0.2.2 → metatensor_core-0.2.3}/metatensor/_c_api.py +0 -0
  20. {metatensor_core-0.2.2 → metatensor_core-0.2.3}/metatensor/_c_lib.py +0 -0
  21. {metatensor_core-0.2.2 → metatensor_core-0.2.3}/metatensor/_data/__init__.py +0 -0
  22. {metatensor_core-0.2.2 → metatensor_core-0.2.3}/metatensor/_data/_extract.py +0 -0
  23. {metatensor_core-0.2.2 → metatensor_core-0.2.3}/metatensor/_status.py +0 -0
  24. {metatensor_core-0.2.2 → metatensor_core-0.2.3}/metatensor/_version.py +0 -0
  25. {metatensor_core-0.2.2 → metatensor_core-0.2.3}/metatensor/io/__init__.py +0 -0
  26. {metatensor_core-0.2.2 → metatensor_core-0.2.3}/metatensor/io/_block.py +0 -0
  27. {metatensor_core-0.2.2 → metatensor_core-0.2.3}/metatensor/io/_labels.py +0 -0
  28. {metatensor_core-0.2.2 → metatensor_core-0.2.3}/metatensor/io/_tensor.py +0 -0
  29. {metatensor_core-0.2.2 → metatensor_core-0.2.3}/metatensor/io/_utils.py +0 -0
  30. {metatensor_core-0.2.2 → metatensor_core-0.2.3}/metatensor/learn.py +0 -0
  31. {metatensor_core-0.2.2 → metatensor_core-0.2.3}/metatensor/operations.py +0 -0
  32. {metatensor_core-0.2.2 → metatensor_core-0.2.3}/metatensor/torch.py +0 -0
  33. {metatensor_core-0.2.2 → metatensor_core-0.2.3}/metatensor/utils.py +0 -0
  34. {metatensor_core-0.2.2 → metatensor_core-0.2.3}/metatensor_core.egg-info/dependency_links.txt +0 -0
  35. {metatensor_core-0.2.2 → metatensor_core-0.2.3}/metatensor_core.egg-info/not-zip-safe +0 -0
  36. {metatensor_core-0.2.2 → metatensor_core-0.2.3}/metatensor_core.egg-info/requires.txt +0 -0
  37. {metatensor_core-0.2.2 → metatensor_core-0.2.3}/metatensor_core.egg-info/top_level.txt +0 -0
  38. {metatensor_core-0.2.2 → metatensor_core-0.2.3}/pyproject.toml +0 -0
  39. {metatensor_core-0.2.2 → metatensor_core-0.2.3}/setup.cfg +0 -0
  40. {metatensor_core-0.2.2 → metatensor_core-0.2.3}/setup.py +0 -0
@@ -14,7 +14,7 @@ set(METATENSOR_CORE_SOURCE_DIR "" CACHE PATH "Path to the sources of metatensor-
14
14
 
15
15
  file(REMOVE ${CMAKE_INSTALL_PREFIX}/_external.py)
16
16
 
17
- set(REQUIRED_METATENSOR_VERSION "0.2.2")
17
+ set(REQUIRED_METATENSOR_VERSION "0.2.3")
18
18
  if(${METATENSOR_CORE_PYTHON_USE_EXTERNAL_LIB})
19
19
  # when building a source checkout, update version to include git information
20
20
  # this will not apply when building a sdist
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: metatensor-core
3
- Version: 0.2.2
3
+ Version: 0.2.3
4
4
  Summary: Python bindings for metatensor
5
5
  Author: Guillaume Fraux, Rohit Goswami, Philip Loche, Filippo Bigi, Joseph W. Abbott, Davide Tisi, Alexander Goscinski, Michele Ceriotti
6
6
  License-Expression: BSD-3-Clause
@@ -0,0 +1,2 @@
1
+ 0
2
+ git.604d7b2
@@ -37,9 +37,9 @@ except ImportError:
37
37
  if HAS_TORCH:
38
38
  # This NewType is only used for typechecking and documentation purposes. If you are
39
39
  # trying to add support for new array types, see `data.array.ArrayWrapper` instead.
40
- Array = NewType("Array", Union[np.ndarray, torch.Tensor])
40
+ Array = NewType("Array", Union[np.ndarray, torch.Tensor, mts_array_t])
41
41
  else:
42
- Array = NewType("Array", np.ndarray)
42
+ Array = NewType("Array", Union[np.ndarray, mts_array_t])
43
43
 
44
44
  Array.__doc__ = """
45
45
  An ``Array`` contains the actual data stored in a :py:class:`metatensor.TensorBlock`.
@@ -264,16 +264,6 @@ class DLPackArray:
264
264
  if stream is not None:
265
265
  raise RuntimeError("only `stream=None` is supported")
266
266
 
267
- if self._versioned:
268
- version = pointer[0].version
269
- version = (version.major, version.minor)
270
- if max_version is not None:
271
- if version[0] > max_version[0]:
272
- raise RuntimeError(
273
- f"requested DLPack version {max_version}, but tensor has "
274
- f"version {version}"
275
- )
276
-
277
267
  if dl_device is not None and dl_device != self.__dlpack_device__():
278
268
  raise RuntimeError("device conversion is not supported")
279
269
 
@@ -282,7 +272,22 @@ class DLPackArray:
282
272
 
283
273
  self._pointer = None
284
274
  if self._versioned:
285
- capsule = make_dlpack_versioned_capsule(pointer)
275
+ version = pointer[0].version
276
+ version_tuple = (version.major, version.minor)
277
+
278
+ if max_version is not None and version_tuple[0] > max_version[0]:
279
+ raise RuntimeError(
280
+ f"requested DLPack version {max_version}, but tensor has "
281
+ f"version {version_tuple}"
282
+ )
283
+
284
+ if max_version is not None and max_version >= (1, 0):
285
+ capsule = make_dlpack_versioned_capsule(pointer)
286
+ else:
287
+ # Consumer doesn't signal DLPack v1 support (e.g. PyTorch < 2.9.0),
288
+ # wrap as unversioned for compatibility
289
+ unversioned_ptr = wrap_versioned_as_unversioned(pointer)
290
+ capsule = make_dlpack_unversioned_capsule(unversioned_ptr)
286
291
  else:
287
292
  capsule = make_dlpack_unversioned_capsule(pointer)
288
293
 
@@ -8,13 +8,15 @@ import numpy as np
8
8
 
9
9
  from . import _data
10
10
  from ._c_api import (
11
+ DLDataType,
12
+ DLDataTypeCode,
11
13
  c_uintptr_t,
12
14
  mts_array_t,
13
15
  mts_labels_t,
14
16
  )
15
17
  from ._c_lib import _get_library
16
18
  from ._data import Array, Device
17
- from ._status import check_pointer
19
+ from ._status import check_pointer, check_status
18
20
 
19
21
 
20
22
  try:
@@ -138,6 +140,72 @@ class LabelsEntry:
138
140
  return not self.__eq__(other)
139
141
 
140
142
 
143
+ def _labels_values_mts_array(array: Array, size: int) -> (mts_array_t, Array):
144
+ if isinstance(array, mts_array_t):
145
+ shape_ptr = ctypes.POINTER(c_uintptr_t)()
146
+ shape_count = c_uintptr_t()
147
+ check_status(
148
+ array.shape(array.ptr, ctypes.byref(shape_ptr), ctypes.byref(shape_count))
149
+ )
150
+ shape = [shape_ptr[i] for i in range(shape_count.value)]
151
+
152
+ if len(shape) != 2:
153
+ raise ValueError("`values` must be a 2D array")
154
+
155
+ if shape[1] != size:
156
+ raise ValueError(
157
+ "`names` must have an entry for each column of the `values` array"
158
+ )
159
+
160
+ dtype = DLDataType()
161
+ check_status(array.dtype(array.ptr, ctypes.byref(dtype)))
162
+ if dtype.code != DLDataTypeCode.kDLInt or dtype.bits != 32 or dtype.lanes != 1:
163
+ raise TypeError("Labels values must be of dtype int32")
164
+
165
+ return array, None
166
+ else:
167
+ values = array
168
+ backend = _data.array_backend(values)
169
+
170
+ if len(values) == 0:
171
+ # Explicitly define empty labels
172
+ values = np.empty((0, size), dtype=np.int32)
173
+ values = _data.array_change_backend(values, backend)
174
+
175
+ if len(values.shape) != 2:
176
+ # make sure the array is 2D
177
+ raise ValueError("`values` must be a 2D array")
178
+
179
+ if values.shape[1] != size:
180
+ raise ValueError(
181
+ "`names` must have an entry for each column of the `values` array"
182
+ )
183
+
184
+ if backend == "numpy":
185
+ try:
186
+ # We need to make sure the data has the right type
187
+ values = values.astype(
188
+ np.int32,
189
+ casting="same_kind",
190
+ subok=False,
191
+ copy=False,
192
+ )
193
+ # values should not be writeable
194
+ values.flags.writeable = False
195
+ except TypeError as e:
196
+ raise TypeError("Labels values must be convertible to integers") from e
197
+ elif backend == "torch":
198
+ if values.requires_grad:
199
+ raise ValueError("Labels values can not require gradients")
200
+
201
+ if not _data.array_dtype_is_integer(values):
202
+ raise TypeError("Labels values must be of integer dtype")
203
+
204
+ values = values.to(dtype=torch.int32, copy=False)
205
+
206
+ return _data.create_mts_array(values), values
207
+
208
+
141
209
  class Labels:
142
210
  """
143
211
  A set of labels carrying metadata associated with a :py:class:`TensorMap`.
@@ -213,7 +281,7 @@ class Labels:
213
281
  def __init__(
214
282
  self,
215
283
  names: Union[str, Sequence[str]],
216
- values: np.ndarray,
284
+ values: Array,
217
285
  assume_unique: bool = False,
218
286
  ):
219
287
  """
@@ -227,59 +295,20 @@ class Labels:
227
295
  either by construction or because you checked.
228
296
  """
229
297
 
230
- names = _normalize_names_type(names)
231
-
232
298
  if not isinstance(values, Array.__supertype__):
233
- raise ValueError("`values` must be a numpy ndarray or torch tensor")
234
-
235
- backend = _data.array_backend(values)
236
-
237
- if len(values) == 0:
238
- # Explicitly define empty labels
239
- values = np.empty((0, len(names)), dtype=np.int32)
240
- values = _data.array_change_backend(values, backend)
241
-
242
- if len(values.shape) != 2:
243
- # make sure the array is 2D
244
- raise ValueError("`values` must be a 2D array")
245
-
246
- if len(names) != values.shape[1]:
247
299
  raise ValueError(
248
- "`names` must have an entry for each column of the `values` array"
300
+ "`values` must be a numpy ndarray, torch tensor, or mts_array_t, "
301
+ f"got {type(values)}"
249
302
  )
250
303
 
251
- if backend == "numpy":
252
- try:
253
- # We need to make sure the data has the right type
254
- values = values.astype(
255
- np.int32,
256
- casting="same_kind",
257
- subok=False,
258
- copy=False,
259
- )
260
- # values should not be writeable
261
- values.flags.writeable = False
262
- except TypeError as e:
263
- raise TypeError("Labels values must be convertible to integers") from e
264
- elif backend == "torch":
265
- if values.requires_grad:
266
- raise ValueError("Labels values can not require gradients")
267
-
268
- if not _data.array_dtype_is_integer(values):
269
- raise TypeError("Labels values must be of integer dtype")
270
-
271
- values = values.to(dtype=torch.int32, copy=False)
272
-
273
- if values.ndim == 1:
274
- values = values.reshape(-1, len(names))
275
-
304
+ names = _normalize_names_type(names)
276
305
  self._lib = _get_library()
306
+ array, values = _labels_values_mts_array(values, len(names))
307
+
277
308
  c_names = ctypes.ARRAY(ctypes.c_char_p, len(names))()
278
309
  for i, n in enumerate(names):
279
310
  c_names[i] = n.encode("utf8")
280
311
 
281
- array = _data.create_mts_array(values)
282
-
283
312
  if assume_unique:
284
313
  ptr = self._lib.mts_labels_assume_unique(c_names, len(names), array)
285
314
  else:
@@ -7,11 +7,20 @@ import numpy as np
7
7
 
8
8
  from . import _data
9
9
  from ._block import TensorBlock
10
- from ._c_api import c_uintptr_t, mts_array_t, mts_block_t, mts_tensormap_t
10
+ from ._c_api import (
11
+ DLDevice,
12
+ DLDeviceType,
13
+ DLManagedTensorVersioned,
14
+ DLPackVersion,
15
+ c_uintptr_t,
16
+ mts_array_t,
17
+ mts_block_t,
18
+ mts_tensormap_t,
19
+ )
11
20
  from ._c_lib import _get_library
12
21
  from ._data import Device, DType
13
22
  from ._labels import Labels, LabelsEntry
14
- from ._status import check_pointer
23
+ from ._status import check_pointer, check_status
15
24
 
16
25
 
17
26
  class TensorMap:
@@ -417,7 +426,7 @@ class TensorMap:
417
426
  elif isinstance(selection, int):
418
427
  return self.block_by_id(selection)
419
428
  else:
420
- selection = _normalize_selection(selection)
429
+ selection = _normalize_selection(selection, like=self.keys)
421
430
 
422
431
  keys = self.keys
423
432
  matching = keys.select(selection)
@@ -471,7 +480,7 @@ class TensorMap:
471
480
  elif isinstance(selection, int):
472
481
  return [self.block_by_id(selection)]
473
482
  else:
474
- selection = _normalize_selection(selection)
483
+ selection = _normalize_selection(selection, like=self.keys)
475
484
 
476
485
  keys = self.keys
477
486
  matching = keys.select(selection)
@@ -833,8 +842,69 @@ def _can_cast_to_numpy_int(value):
833
842
  return np.can_cast(value, np.int32, casting="same_kind")
834
843
 
835
844
 
845
+ def _array_like(values: List[int], like: Labels) -> mts_array_t:
846
+ """
847
+ Convert a list of integers to an array with the same dtype, device and array backend
848
+ as ``like``.
849
+
850
+ :param values: list of integers to convert
851
+ :param like: Labels whose array backend and device to match
852
+ :return: a new ``mts_array_t`` with the same dtype, device and array backend as
853
+ ``like``
854
+ """
855
+ np_values = np.array(values, dtype=np.int32).reshape(1, -1)
856
+ cpu_array = _data.create_mts_array(np_values)
857
+
858
+ try:
859
+ like_array = like._raw_values
860
+
861
+ dl_managed_ptr = ctypes.POINTER(DLManagedTensorVersioned)()
862
+ device = DLDevice(device_type=DLDeviceType.kDLCPU, device_id=0)
863
+ version = DLPackVersion(major=1, minor=0)
864
+ status = cpu_array.as_dlpack(
865
+ cpu_array.ptr,
866
+ ctypes.byref(dl_managed_ptr),
867
+ device,
868
+ None,
869
+ version,
870
+ )
871
+ check_status(status)
872
+
873
+ result_array = mts_array_t()
874
+ status = like_array.from_dlpack(
875
+ like_array.ptr,
876
+ dl_managed_ptr,
877
+ ctypes.byref(result_array),
878
+ )
879
+ check_status(status)
880
+
881
+ target_device = DLDevice()
882
+ status = like_array.device(like_array.ptr, ctypes.byref(target_device))
883
+ check_status(status)
884
+
885
+ if target_device.device_type != DLDeviceType.kDLCPU:
886
+ device_array = mts_array_t()
887
+ status = result_array.copy(
888
+ result_array.ptr,
889
+ target_device,
890
+ ctypes.byref(device_array),
891
+ )
892
+ check_status(status)
893
+
894
+ if result_array.destroy:
895
+ result_array.destroy(result_array.ptr)
896
+
897
+ result_array = device_array
898
+
899
+ return result_array
900
+ finally:
901
+ if cpu_array.destroy:
902
+ cpu_array.destroy(cpu_array.ptr)
903
+
904
+
836
905
  def _normalize_selection(
837
906
  selection: Union[Labels, LabelsEntry, Dict[str, int]],
907
+ like: Labels,
838
908
  ) -> Labels:
839
909
  if isinstance(selection, dict):
840
910
  for key, value in selection.items():
@@ -848,11 +918,11 @@ def _normalize_selection(
848
918
  )
849
919
 
850
920
  if len(selection) == 0:
851
- return Labels([], np.empty((0, 0), dtype=np.int32))
921
+ return Labels([], _array_like([], like))
852
922
  else:
853
923
  return Labels(
854
924
  list(selection.keys()),
855
- np.array([[np.int32(v) for v in selection.values()]], dtype=np.int32),
925
+ _array_like([np.int32(v) for v in selection.values()], like),
856
926
  )
857
927
 
858
928
  elif isinstance(selection, Labels):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: metatensor-core
3
- Version: 0.2.2
3
+ Version: 0.2.3
4
4
  Summary: Python bindings for metatensor
5
5
  Author: Guillaume Fraux, Rohit Goswami, Philip Loche, Filippo Bigi, Joseph W. Abbott, Davide Tisi, Alexander Goscinski, Michele Ceriotti
6
6
  License-Expression: BSD-3-Clause
@@ -4,7 +4,7 @@ LICENSE
4
4
  MANIFEST.in
5
5
  README.rst
6
6
  git_version_info
7
- metatensor-core-cxx-0.2.2.tar.gz
7
+ metatensor-core-cxx-0.2.3.tar.gz
8
8
  pyproject.toml
9
9
  setup.py
10
10
  metatensor/__init__.py
@@ -1,2 +0,0 @@
1
- 0
2
- git.cf11e6d
File without changes
File without changes