Skip to content
This repository was archived by the owner on Dec 8, 2024. It is now read-only.

Commit de0065f

Browse files
authored
Bob bug (#33)
* Fixed ordering in Bob, added integration test * Tightened threshold in Bob integration test to 2.8 kcal/mol
1 parent 9843ab1 commit de0065f

6 files changed

+200
-19
lines changed

qml/compound.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ def generate_atomic_coulomb_matrix(self, size = 23, sorting = "row-norm",
214214
sorting = sorting, central_cutoff = central_cutoff, central_decay = central_decay,
215215
interaction_cutoff = interaction_cutoff, interaction_decay = interaction_decay)
216216

217-
def generate_bob(self, asize = {"O":3, "C":7, "N":3, "H":16, "S":1}):
217+
def generate_bob(self, size=23, asize = {"O":3, "C":7, "N":3, "H":16, "S":1}):
218218
""" Creates a Bag of Bonds (BOB) representation of a molecule.
219219
The representation expands on the coulomb matrix representation.
220220
For each element a bag (vector) is constructed for self interactions

qml/representations.py

+63-3
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,41 @@
3030
from .frepresentations import fgenerate_local_coulomb_matrix
3131
from .frepresentations import fgenerate_atomic_coulomb_matrix
3232
from .frepresentations import fgenerate_eigenvalue_coulomb_matrix
33-
from .frepresentations import fgenerate_bob
3433

3534
from .data import NUCLEAR_CHARGE
3635

3736
from .slatm import get_boa
3837
from .slatm import get_sbop
3938
from .slatm import get_sbot
4039

40+
def vector_to_matrix(v):
41+
""" Converts a representation from 1D vector to 2D square matrix.
42+
:param v: 1D input representation.
43+
:type v: numpy array
44+
:return: Square matrix representation.
45+
:rtype: numpy array
46+
"""
47+
48+
if not (np.sqrt(8*v.shape[0]+1) == int(np.sqrt(8*v.shape[0]+1))):
49+
print("ERROR: Can not make a square matrix.")
50+
exit(1)
51+
52+
n = v.shape[0]
53+
l = (-1 + int(np.sqrt(8*n+1)))//2
54+
M = np.empty((l,l))
55+
56+
index = 0
57+
for i in range(l):
58+
for j in range(l):
59+
if j > i:
60+
continue
61+
62+
M[i,j] = v[index]
63+
M[j,i] = M[i,j]
64+
65+
index += 1
66+
return M
67+
4168
def generate_coulomb_matrix(nuclear_charges, coordinates, size = 23, sorting = "row-norm"):
4269
""" Creates a Coulomb Matrix representation of a molecule.
4370
Sorting of the elements can either be done by ``sorting="row-norm"`` or ``sorting="unsorted"``.
@@ -234,7 +261,7 @@ def generate_eigenvalue_coulomb_matrix(nuclear_charges, coordinates, size = 23):
234261
return fgenerate_eigenvalue_coulomb_matrix(nuclear_charges,
235262
coordinates, size)
236263

237-
def generate_bob(nuclear_charges, coordinates, atomtypes, asize = {"O":3, "C":7, "N":3, "H":16, "S":1}):
264+
def generate_bob(nuclear_charges, coordinates, atomtypes, size=23, asize = {"O":3, "C":7, "N":3, "H":16, "S":1}):
238265
""" Creates a Bag of Bonds (BOB) representation of a molecule.
239266
The representation expands on the coulomb matrix representation.
240267
For each element a bag (vector) is constructed for self interactions
@@ -259,12 +286,45 @@ def generate_bob(nuclear_charges, coordinates, atomtypes, asize = {"O":3, "C":7,
259286
:type nuclear_charges: numpy array
260287
:param coordinates: 3D Coordinates of the atoms in the molecule
261288
:type coordinates: numpy array
289+
:param size: The maximum number of atoms in the representation
290+
:type size: integer
262291
:param asize: The maximum number of atoms of each element type supported by the representation
263-
:type size: dictionary
292+
:type asize: dictionary
264293
265294
:return: 1D representation
266295
:rtype: numpy array
267296
"""
297+
natoms = len(nuclear_charges)
298+
299+
coulomb_matrix = fgenerate_unsorted_coulomb_matrix(nuclear_charges, coordinates, size)
300+
301+
coulomb_matrix = vector_to_matrix(coulomb_matrix)
302+
descriptor = []
303+
atomtypes = np.asarray(atomtypes)
304+
for atom1, size1 in sorted(asize.items()):
305+
pos1 = np.where(atomtypes == atom1)[0]
306+
feature_vector = np.zeros(size1)
307+
feature_vector[:pos1.size] = np.diag(coulomb_matrix)[pos1]
308+
feature_vector.sort()
309+
descriptor.append(feature_vector[:])
310+
for atom2, size2 in sorted(asize.items()):
311+
if atom1 > atom2:
312+
continue
313+
if atom1 == atom2:
314+
size = size1*(size1-1)//2
315+
feature_vector = np.zeros(size)
316+
sub_matrix = coulomb_matrix[np.ix_(pos1,pos1)]
317+
feature_vector[:pos1.size*(pos1.size-1)//2] = sub_matrix[np.triu_indices(pos1.size, 1)]
318+
feature_vector.sort()
319+
descriptor.append(feature_vector[:])
320+
else:
321+
pos2 = np.where(atomtypes == atom2)[0]
322+
feature_vector = np.zeros(size1*size2)
323+
feature_vector[:pos1.size*pos2.size] = coulomb_matrix[np.ix_(pos1,pos2)].ravel()
324+
feature_vector.sort()
325+
descriptor.append(feature_vector[:])
326+
327+
return np.concatenate(descriptor)
268328

269329
n = 0
270330
atoms = sorted(asize, key=asize.get)

0 commit comments

Comments
 (0)