Skip to content

Commit c6e487e

Browse files
authoredJun 20, 2024
Merge pull request #64 from lcmd-epfl/new-metatensor
* New version of metatensor * Fix the discrepancies between pip's files, requirements.txt and environment.yml * Update the installation section of README * Use qstack_qml as qstack.qml
2 parents d955103 + 3ad83dc commit c6e487e

12 files changed

+134
-65
lines changed
 

‎README.md

+12-1
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,22 @@ For now, we link to the relevant packages that will be incorporated (among other
2828

2929
## Install [](#contents)
3030

31-
The installation of the library for python use can be done executing the following commands:
31+
The installation of the library for python use can be done executing one of the following commands:
3232

3333
```
3434
python -m pip install git+https://github.com/lcmd-epfl/Q-stack.git
35+
python -m pip install "qstack @ git+https://github.com/lcmd-epfl/Q-stack.git"
36+
python -m pip install "qstack[all] @ git+https://github.com/lcmd-epfl/Q-stack.git"
37+
python -m pip install -r requirements.py3.11.txt
3538
```
39+
40+
The last two are recommended if you do not know which features you wish to use, since they pull the dependencies required with all 'optional' parts of Q-stack.
41+
42+
If you wish to use a conda environment, an `environment.yml` file is also available, for the conda analogue of the last install command.
43+
44+
A small part of Q-stack, isolated in the `qstack_qml` module name, can be installed on its own, see [the qstack-qml subdirectory's readme](../master/qstack/qstack-qml/README.md).
45+
46+
3647
## Examples [](#contents)
3748
Q-stack comes with several example codes that illustrate some of its key capabilities. To run the examples, go to the example folder and run the following commands:
3849

‎environment.yml

+2-1
Original file line numberDiff line numberDiff line change
@@ -48,5 +48,6 @@ dependencies:
4848
- toml==0.10.2
4949
- ase==3.22
5050
- tqdm==4.66
51-
- git+https://github.com/lab-cosmo/equistore.git@e5b9dc365369ba2584ea01e9d6a4d648008aaab8#subdirectory=python/equistore-core
51+
- metatensor-core==0.1.8
52+
- git+https://github.com/lcmd-epfl/cell2mol.git@22473bbf12a013467137a55a63c88fbbdc95baa2
5253
- qstack/qstack-qml

‎pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ dependencies = [
4848
regression = ["scikit-learn >= 0.24.2, < 1.6"]
4949
wigner = ["sympy >= 1.5, < 1.13"]
5050
gmol = ["cell2mol @ git+https://github.com/lcmd-epfl/cell2mol.git@22473bbf12a013467137a55a63c88fbbdc95baa2"] # branch: dev, date: 2024-06-06
51-
equio = ["equistore-core @ git+https://github.com/lab-cosmo/equistore.git@e5b9dc365369ba2584ea01e9d6a4d648008aaab8#subdirectory=python/equistore-core"]
51+
equio = ["metatensor-core == 0.1.8"]
5252
all = ["qstack[qml,regression,wigner,equio,gmol]"]
5353

5454
[project.urls]

‎qstack/__init__.py

+5
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,12 @@
88
from qstack import spahm
99
from qstack import mathutils
1010
from qstack import orcaio
11+
from qstack import qml
12+
if 'b2r2' not in dir(qml):
13+
del qml
1114

15+
16+
# qstack.regression needs sklearn to work
1217
try:
1318
import sklearn
1419
except ImportError:

‎qstack/equio.py

+63-44
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1+
from functools import reduce
12
import numpy as np
23
from types import SimpleNamespace
34
from pyscf import data
4-
import equistore.core as equistore
5+
import metatensor
56
import numbers
67

78
vector_label_names = SimpleNamespace(
@@ -58,13 +59,25 @@ def _get_tsize(tensor):
5859
"""Computes the size of a tensor.
5960
6061
Args:
61-
tensor (equistore TensorMap): Tensor.
62+
tensor (metatensor TensorMap): Tensor.
6263
6364
Returns:
6465
The size of the tensor as an integer.
6566
"""
6667
return sum([np.prod(tensor.block(key).values.shape) for key in tensor.keys])
6768

69+
def _labels_to_array(labels):
70+
"""Represents a set of metatensor labels as an array of the labels, using custom dtypes
71+
72+
Args:
73+
labels (metatensor Labels): Labels
74+
75+
Returns:
76+
labels (numpy ndarray[ndim=1, structured dtype]): the same labels
77+
"""
78+
values = labels.values
79+
dtype = [ (name,values.dtype) for name in labels.names]
80+
return values.view(dtype=dtype).reshape(values.shape[0])
6881

6982
def vector_to_tensormap(mol, c):
7083
"""Transform a vector into a tensor map. Used by :py:func:`array_to_tensormap`.
@@ -74,7 +87,7 @@ def vector_to_tensormap(mol, c):
7487
v (numpy ndarray): Vector.
7588
7689
Returns:
77-
A equistore tensor map.
90+
A metatensor tensor map.
7891
"""
7992

8093
atom_charges = list(mol.atom_charges())
@@ -104,11 +117,11 @@ def vector_to_tensormap(mol, c):
104117
block_prop_label_vals[label] = np.arange(properties_count).reshape(-1,1)
105118
block_samp_label_vals[label] = np.where(atom_charges==q)[0].reshape(-1,1)
106119

107-
tm_labels = equistore.Labels(vector_label_names.tm, np.array(tm_label_vals))
120+
tm_labels = metatensor.Labels(vector_label_names.tm, np.array(tm_label_vals))
108121

109-
block_comp_labels = {key: equistore.Labels(vector_label_names.block_comp, block_comp_label_vals[key]) for key in blocks}
110-
block_prop_labels = {key: equistore.Labels(vector_label_names.block_prop, block_prop_label_vals[key]) for key in blocks}
111-
block_samp_labels = {key: equistore.Labels(vector_label_names.block_samp, block_samp_label_vals[key]) for key in blocks}
122+
block_comp_labels = {key: metatensor.Labels(vector_label_names.block_comp, block_comp_label_vals[key]) for key in blocks}
123+
block_prop_labels = {key: metatensor.Labels(vector_label_names.block_prop, block_prop_label_vals[key]) for key in blocks}
124+
block_samp_labels = {key: metatensor.Labels(vector_label_names.block_samp, block_samp_label_vals[key]) for key in blocks}
112125

113126
# Fill in the blocks
114127

@@ -138,8 +151,8 @@ def vector_to_tensormap(mol, c):
138151

139152
# Build tensor blocks and tensor map
140153

141-
tensor_blocks = [equistore.TensorBlock(values=blocks[key], samples=block_samp_labels[key], components=[block_comp_labels[key]], properties=block_prop_labels[key]) for key in tm_label_vals]
142-
tensor = equistore.TensorMap(keys=tm_labels, blocks=tensor_blocks)
154+
tensor_blocks = [metatensor.TensorBlock(values=blocks[key], samples=block_samp_labels[key], components=[block_comp_labels[key]], properties=block_prop_labels[key]) for key in tm_label_vals]
155+
tensor = metatensor.TensorMap(keys=tm_labels, blocks=tensor_blocks)
143156

144157
return tensor
145158

@@ -149,7 +162,7 @@ def tensormap_to_vector(mol, tensor):
149162
150163
Args:
151164
mol (pyscf Mole): pyscf Mole object.
152-
tensor (equistore TensorMap): Tensor.
165+
tensor (metatensor TensorMap): Tensor.
153166
154167
Returns:
155168
A numpy ndarray (vector).
@@ -185,7 +198,7 @@ def matrix_to_tensormap(mol, dm):
185198
v (numpy ndarray): Matrix.
186199
187200
Returns:
188-
A equistore tensor map.
201+
A metatensor tensor map.
189202
"""
190203

191204
def pairs(list1, list2):
@@ -226,14 +239,14 @@ def pairs(list1, list2):
226239
block_prop_label_vals[label] = pairs(np.arange(properties_count1), np.arange(properties_count2))
227240
block_samp_label_vals[label] = pairs(np.where(atom_charges==q1)[0],np.where(atom_charges==q2)[0])
228241

229-
tm_labels = equistore.Labels(matrix_label_names.tm, np.array(tm_label_vals))
242+
tm_labels = metatensor.Labels(matrix_label_names.tm, np.array(tm_label_vals))
230243

231-
block_prop_labels = {key: equistore.Labels(matrix_label_names.block_prop, block_prop_label_vals[key]) for key in blocks}
232-
block_samp_labels = {key: equistore.Labels(matrix_label_names.block_samp, block_samp_label_vals[key]) for key in blocks}
233-
block_comp_labels = {key: [equistore.Labels([name], vals) for name, vals in zip(matrix_label_names.block_comp, block_comp_label_vals[key])] for key in blocks}
244+
block_prop_labels = {key: metatensor.Labels(matrix_label_names.block_prop, block_prop_label_vals[key]) for key in blocks}
245+
block_samp_labels = {key: metatensor.Labels(matrix_label_names.block_samp, block_samp_label_vals[key]) for key in blocks}
246+
block_comp_labels = {key: [metatensor.Labels([name], vals) for name, vals in zip(matrix_label_names.block_comp, block_comp_label_vals[key])] for key in blocks}
234247

235248
# Build tensor blocks
236-
tensor_blocks = [equistore.TensorBlock(values=blocks[key], samples=block_samp_labels[key], components=block_comp_labels[key], properties=block_prop_labels[key]) for key in tm_label_vals]
249+
tensor_blocks = [metatensor.TensorBlock(values=blocks[key], samples=block_samp_labels[key], components=block_comp_labels[key], properties=block_prop_labels[key]) for key in tm_label_vals]
237250

238251
# Fill in the blocks
239252

@@ -293,8 +306,8 @@ def pairs(list1, list2):
293306
blocks[key] = np.ascontiguousarray(blocks[key][:,:,_pyscf2gpr_l1_order,:])
294307

295308
# Build tensor map
296-
tensor_blocks = [equistore.TensorBlock(values=blocks[key], samples=block_samp_labels[key], components=block_comp_labels[key], properties=block_prop_labels[key]) for key in tm_label_vals]
297-
tensor = equistore.TensorMap(keys=tm_labels, blocks=tensor_blocks)
309+
tensor_blocks = [metatensor.TensorBlock(values=blocks[key], samples=block_samp_labels[key], components=block_comp_labels[key], properties=block_prop_labels[key]) for key in tm_label_vals]
310+
tensor = metatensor.TensorMap(keys=tm_labels, blocks=tensor_blocks)
298311

299312
return tensor
300313

@@ -304,7 +317,7 @@ def tensormap_to_matrix(mol, tensor):
304317
305318
Args:
306319
mol (pyscf Mole): pyscf Mole object.
307-
tensor (equistore TensorMap): Tensor.
320+
tensor (metatensor TensorMap): Tensor.
308321
309322
Returns:
310323
A numpy ndarray (matrix).
@@ -352,7 +365,7 @@ def array_to_tensormap(mol, v):
352365
v (numpy ndarray): Array. It can be a vector or a matrix.
353366
354367
Returns:
355-
A equistore tensor map.
368+
A metatensor tensor map.
356369
"""
357370
if v.ndim==1:
358371
return vector_to_tensormap(mol, v)
@@ -367,15 +380,15 @@ def tensormap_to_array(mol, tensor):
367380
368381
Args:
369382
mol (pyscf Mole): pyscf Mole object.
370-
tensor (equistore TensorMap): Tensor.
383+
tensor (metatensor TensorMap): Tensor.
371384
372385
Returns:
373386
A numpy ndarray. Matrix or vector, depending on the key names of the tensor.
374387
"""
375388

376-
if tensor.keys.names==tuple(vector_label_names.tm):
389+
if tensor.keys.names==vector_label_names.tm:
377390
return tensormap_to_vector(mol, tensor)
378-
elif tensor.keys.names==tuple(matrix_label_names.tm):
391+
elif tensor.keys.names==matrix_label_names.tm:
379392
return tensormap_to_matrix(mol, tensor)
380393
else:
381394
raise Exception(f'Tensor key names mismatch. Cannot determine if it is a vector or a matrix')
@@ -385,16 +398,17 @@ def join(tensors):
385398
"""Merge two or more tensors with the same label names avoiding information duplictaion.
386399
387400
Args:
388-
tensors (list): List of equistore TensorMap.
401+
tensors (list): List of metatensor TensorMap.
389402
390403
Returns:
391-
A equistore TensorMap containing the information of all the input tensors.
404+
A metatensor TensorMap containing the information of all the input tensors.
392405
"""
393406

394407
if not all(tensor.keys.names==tensors[0].keys.names for tensor in tensors):
395408
raise Exception(f'Cannot merge tensors with different label names')
396-
tm_label_vals = sorted(list(set().union(*[set(tensor.keys.tolist()) for tensor in tensors])))
397-
tm_labels = equistore.Labels(tensors[0].keys.names, np.array(tm_label_vals))
409+
tm_label_vals = set().union(*[set(_labels_to_array(tensor.keys)) for tensor in tensors])
410+
tm_label_vals = sorted((tuple(value) for value in tm_label_vals))
411+
tm_labels = metatensor.Labels(tensors[0].keys.names, np.array(tm_label_vals))
398412

399413
blocks = {}
400414
block_comp_labels = {}
@@ -403,7 +417,7 @@ def join(tensors):
403417
block_samp_label_vals = {}
404418

405419
for label in tm_labels:
406-
key = tuple(label.tolist())
420+
key = tuple(label.values)
407421
blocks[key] = []
408422
block_samp_label_vals[key] = []
409423
for imol,tensor in enumerate(tensors):
@@ -420,10 +434,10 @@ def join(tensors):
420434
for key in blocks:
421435
blocks[key] = np.concatenate(blocks[key])
422436
block_samp_label_vals[key] = np.array(block_samp_label_vals[key])
423-
block_samp_labels[key] = equistore.Labels((_molid_name, *tensor.sample_names), block_samp_label_vals[key])
437+
block_samp_labels[key] = metatensor.Labels((_molid_name, *tensor.sample_names), block_samp_label_vals[key])
424438

425-
tensor_blocks = [equistore.TensorBlock(values=blocks[key], samples=block_samp_labels[key], components=block_comp_labels[key], properties=block_prop_labels[key]) for key in tm_label_vals]
426-
tensor = equistore.TensorMap(keys=tm_labels, blocks=tensor_blocks)
439+
tensor_blocks = [metatensor.TensorBlock(values=blocks[key], samples=block_samp_labels[key], components=block_comp_labels[key], properties=block_prop_labels[key]) for key in tm_label_vals]
440+
tensor = metatensor.TensorMap(keys=tm_labels, blocks=tensor_blocks)
427441

428442
return tensor
429443

@@ -432,17 +446,20 @@ def split(tensor):
432446
"""Split a tensor based on the molecule information stored within the input TensorMap.
433447
434448
Args:
435-
tensor (equistore TensorMap): Tensor containing several molecules.
449+
tensor (metatensor TensorMap): Tensor containing several molecules.
436450
437451
Returns:
438-
N equistore TensorMap, where N is equal to the total number of diferent molecules stored within the input TensorMap.
452+
N metatensor TensorMap, where N is equal to the total number of diferent molecules stored within the input TensorMap.
439453
"""
440454

441455
if tensor.sample_names[0]!=_molid_name:
442456
raise Exception(f'Tensor does not seem to contain several molecules')
443457

444458
# Check if the molecule indices are continuous
445-
mollist = sorted(set(np.hstack([np.array(tensor.block(keys).samples.tolist())[:,0] for keys in tensor.keys])))
459+
mollist = sorted(reduce(
460+
lambda a,b: a.union(b),
461+
[set(block.samples.column(_molid_name)) for block in tensor.blocks()]
462+
))
446463
if mollist==list(range(len(mollist))):
447464
tensors = [None] * len(mollist)
448465
else:
@@ -451,8 +468,8 @@ def split(tensor):
451468
# Common labels
452469
block_comp_labels = {}
453470
block_prop_labels = {}
454-
for label in tensor.keys:
455-
key = label.tolist()
471+
for label,block in tensor.items():
472+
key = tuple(label.values)
456473
block = tensor.block(label)
457474
block_comp_labels[key] = block.components
458475
block_prop_labels[key] = block.properties
@@ -463,20 +480,22 @@ def split(tensor):
463480
block_samp_labels = {}
464481

465482
for label in tensor.keys:
466-
key = label.tolist()
483+
key = tuple(label.values)
467484
block = tensor.block(label)
468485

469-
samplelbl = [lbl for lbl in block.samples.tolist() if lbl[0]==imol]
470-
if len(samplelbl)==0:
486+
samples = [(sample_i,lbl) for sample_i,lbl in enumerate(block.samples.values) if lbl[0]==imol]
487+
if len(samples)==0:
471488
continue
472-
sampleidx = [block.samples.position(lbl) for lbl in samplelbl]
489+
sampleidx = [t[0] for t in samples]
490+
samplelbl = [t[1] for t in samples]
491+
#sampleidx = [block.samples.position(lbl) for lbl in samplelbl]
473492

474493
blocks[key] = block.values[sampleidx]
475-
block_samp_labels[key] = equistore.Labels(tensor.sample_names[1:], np.array(samplelbl)[:,1:])
494+
block_samp_labels[key] = metatensor.Labels(tensor.sample_names[1:], np.array(samplelbl)[:,1:])
476495

477496
tm_label_vals = sorted(list(blocks.keys()))
478-
tm_labels = equistore.Labels(tensor.keys.names, np.array(tm_label_vals))
479-
tensor_blocks = [equistore.TensorBlock(values=blocks[key], samples=block_samp_labels[key], components=block_comp_labels[key], properties=block_prop_labels[key]) for key in tm_label_vals]
480-
tensors[imol] = equistore.TensorMap(keys=tm_labels, blocks=tensor_blocks)
497+
tm_labels = metatensor.Labels(tensor.keys.names, np.array(tm_label_vals))
498+
tensor_blocks = [metatensor.TensorBlock(values=blocks[key], samples=block_samp_labels[key], components=block_comp_labels[key], properties=block_prop_labels[key]) for key in tm_label_vals]
499+
tensors[imol] = metatensor.TensorMap(keys=tm_labels, blocks=tensor_blocks)
481500

482501
return tensors

‎qstack/qml.py

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# qstack.qml is in a different python package
2+
# but prefer "the local version of it" if we are in a development environment, and both sources are there.
3+
import os
4+
_qstack_qml_path = os.path.join(os.path.dirname(__file__), 'qstack-qml')
5+
if os.path.isfile(os.path.join(_qstack_qml_path, 'qstack_qml', '__init__.py')):
6+
import sys
7+
sys.path.insert(0,_qstack_qml_path)
8+
from qstack_qml import *
9+
sys.path.pop(0)
10+
del sys
11+
else:
12+
try:
13+
from qstack_qml import *
14+
except ImportError:
15+
pass
16+
del os, _qstack_qml_path

‎qstack/regression/kernel_utils.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ def cdist(X, Y):
205205
x = np.array([x] * len(Y))
206206
d = np.abs(x-Y)
207207
while len(d.shape)>1:
208-
d = np.sum(d, axis=1) # several axis available for np > 1.7.0
208+
d = np.sum(d, axis=1) # several axis available for np > 1.7.0 (TODO shall we move this)
209209
K[i,:] = d
210210
return K
211211
K = -gamma * cdist(X, Y)

‎requirements.py3.11.txt

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
attrs==21.4.0
2+
certifi==2021.10.8
3+
h5py==3.11.0
4+
iniconfig==1.1.1
5+
packaging==21.3
6+
pluggy==1.0.0
7+
py==1.11.0
8+
pyparsing==3.0.6
9+
pyscf==2.2.0
10+
pytest==6.2.5
11+
numpy===1.22.3
12+
scipy==1.10
13+
toml==0.10.2
14+
scikit-learn==1.5.0
15+
ase==3.22
16+
tqdm==4.66
17+
metatensor-core==0.1.8
18+
cell2mol @ git+https://github.com/lcmd-epfl/cell2mol.git@22473bbf12a013467137a55a63c88fbbdc95baa2
19+
qstack/qstack-qml

‎requirements.txt ‎requirements.py3.9.txt

+3-4
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,15 @@ iniconfig==1.1.1
55
packaging==21.3
66
pluggy==1.0.0
77
py==1.11.0
8-
#cython==0.29.24
98
pyparsing==3.0.6
109
pyscf==2.0.1
1110
pytest==6.2.5
1211
numpy===1.22.3
1312
scipy==1.10
1413
toml==0.10.2
1514
scikit-learn==0.24.2
16-
#scikit-learn==1.0.2
1715
ase==3.22
1816
tqdm==4.66
19-
equistore-core @ git+https://github.com/lab-cosmo/equistore.git@e5b9dc365369ba2584ea01e9d6a4d648008aaab8#subdirectory=python/equistore-core
20-
17+
metatensor-core==0.1.8
18+
cell2mol @ git+https://github.com/lcmd-epfl/cell2mol.git@22473bbf12a013467137a55a63c88fbbdc95baa2
19+
qstack/qstack-qml

0 commit comments

Comments
 (0)
Failed to load comments.