From e590c7eef3518ba0384685ad3c2d890f2bb74b05 Mon Sep 17 00:00:00 2001 From: samwaseda Date: Thu, 2 Nov 2023 08:39:55 +0000 Subject: [PATCH 01/10] add check for np.ndarray and list --- mamonca/mc.pyx | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/mamonca/mc.pyx b/mamonca/mc.pyx index 8b07ca8..8d50f4f 100644 --- a/mamonca/mc.pyx +++ b/mamonca/mc.pyx @@ -84,14 +84,16 @@ cdef class MC: negative sign. """ if i is None and j is None: - n = self.c_mc.get_number_of_atoms() - if np.array(coeff).shape!=(n, n): - raise ValueError( - 'If i and j are not specified, coeff has to be a 2d tensor with the length ' - + 'equal to the number of atoms in each direction.' - ) - i,j = np.where(coeff!=0) - coeff = coeff[coeff!=0] + if isinstance(coeff, np.ndarray | list): + n = self.c_mc.get_number_of_atoms() + if np.array(coeff).shape!=(n, n): + raise ValueError( + "If i and j are not specified, coeff has to be a 2d" + " tensor with the length equal to the number of atoms in" + " each direction." + ) + i,j = np.where(coeff != 0) + coeff = coeff[coeff != 0] coeff = np.array([coeff]).flatten() i = np.array(i).flatten() j = np.array(j).flatten() From ba5799ba8b9f6f80b2f5ed20a026c148e287601f Mon Sep 17 00:00:00 2001 From: samwaseda Date: Thu, 2 Nov 2023 08:46:24 +0000 Subject: [PATCH 02/10] clean code --- mamonca/mc.pyx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mamonca/mc.pyx b/mamonca/mc.pyx index 8d50f4f..98cf1a2 100644 --- a/mamonca/mc.pyx +++ b/mamonca/mc.pyx @@ -94,12 +94,12 @@ cdef class MC: ) i,j = np.where(coeff != 0) coeff = coeff[coeff != 0] - coeff = np.array([coeff]).flatten() - i = np.array(i).flatten() - j = np.array(j).flatten() - if len(coeff)==1: + coeff = np.asarray([coeff]).flatten() + i = np.asarray(i).flatten() + j = np.asarray(j).flatten() + if len(coeff) == 1: coeff = np.tile(coeff, len(i)) - if len(coeff)!=len(i) or len(i)!=len(j): + if not len(coeff) == len(i) == len(j): raise ValueError('Length of vectors not the same') self.c_mc.set_heisenberg_coeff(coeff, i, j, deg, index) From b9b2f581461d03ec3512a0608cb1a89bba986c7d Mon Sep 17 00:00:00 2001 From: samwaseda Date: Thu, 2 Nov 2023 08:52:30 +0000 Subject: [PATCH 03/10] add coo --- mamonca/mc.pyx | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/mamonca/mc.pyx b/mamonca/mc.pyx index 98cf1a2..67bfd89 100644 --- a/mamonca/mc.pyx +++ b/mamonca/mc.pyx @@ -84,8 +84,8 @@ cdef class MC: negative sign. """ if i is None and j is None: + n = self.c_mc.get_number_of_atoms() if isinstance(coeff, np.ndarray | list): - n = self.c_mc.get_number_of_atoms() if np.array(coeff).shape!=(n, n): raise ValueError( "If i and j are not specified, coeff has to be a 2d" @@ -94,6 +94,18 @@ cdef class MC: ) i,j = np.where(coeff != 0) coeff = coeff[coeff != 0] + else: + if hasattr(coeff, "tocoo"): + coeff = coeff.tocoo() + try: + i = coeff.row + j = coeff.col + coeff = coeff.data + except AttributeError: + raise ValueError( + "Input can be a sparse matrix or a numpy array of" + f" shape ({n}, {n}) or you must specify i, j and coeff" + ) coeff = np.asarray([coeff]).flatten() i = np.asarray(i).flatten() j = np.asarray(j).flatten() From 0b1b656a9263d16bdb512a2dbeb7d4421f5ba9ba Mon Sep 17 00:00:00 2001 From: samwaseda Date: Thu, 2 Nov 2023 09:19:41 +0000 Subject: [PATCH 04/10] update tests --- tests/test_heisenberg.py | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/tests/test_heisenberg.py b/tests/test_heisenberg.py index f41b5db..7c0c471 100644 --- a/tests/test_heisenberg.py +++ b/tests/test_heisenberg.py @@ -2,6 +2,7 @@ import numpy as np import unittest import os +from scipy.sparse import coo_matrix class TestFull(unittest.TestCase): @@ -9,11 +10,27 @@ class TestFull(unittest.TestCase): @classmethod def setUpClass(cls): cls.file_location = os.path.dirname(os.path.abspath(__file__)) - ij = np.loadtxt(os.path.join(cls.file_location, "neighbors.txt")) - cls.mc = MC(np.max(ij) + 1) - cls.mc.set_heisenberg_coeff(0.1, *ij) + cls.ij = np.loadtxt( + os.path.join(cls.file_location, "neighbors.txt") + ).astype(int) + cls.n = np.max(cls.ij) + 1 + cls.mc = MC(cls.n) + cls.mc.set_heisenberg_coeff(0.1, *cls.ij) cls.mc.run(temperature=300, number_of_iterations=1000) + def test_coo_mat(self): + data = -0.1 * np.ones(self.ij.shape[1]) + mat = coo_matrix( + (data, (self.ij[0], self.ij[1])), + shape=(self.n, self.n), + ) + for i in range(2): + mc = MC(self.n) + mc.set_heisenberg_coeff(mat) + mc.run(100, number_of_iterations=1000) + self.assertLess(mc.get_energy(), 0) + mat = mat + mat # transforms to csr + def test_acceptance_ratio(self): self.assertGreater(self.mc.get_acceptance_ratio(), 0) self.assertLess(self.mc.get_acceptance_ratio(), 1) From 30bf9b86563447c069e8ed060901398fc6e448fc Mon Sep 17 00:00:00 2001 From: samwaseda Date: Thu, 2 Nov 2023 09:21:08 +0000 Subject: [PATCH 05/10] update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index be4429e..5dd49e1 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ neighbors = structure.get_neighbors() first_shell_tensor = neighbors.get_shell_matrix()[0] mc = MC(len(structure)) -mc.set_heisenberg_coeff(J*first_shell_tensor.toarray()) +mc.set_heisenberg_coeff(J * first_shell_tensor) mc.run(temperature=300, number_of_iterations=1000) ``` From 99fcac12ac880b0053a23746a50175a60f74cfa7 Mon Sep 17 00:00:00 2001 From: samwaseda Date: Thu, 2 Nov 2023 09:21:43 +0000 Subject: [PATCH 06/10] update heisenberg coeff to avoid confusion --- tests/test_heisenberg.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_heisenberg.py b/tests/test_heisenberg.py index 7c0c471..30d4edf 100644 --- a/tests/test_heisenberg.py +++ b/tests/test_heisenberg.py @@ -19,7 +19,7 @@ def setUpClass(cls): cls.mc.run(temperature=300, number_of_iterations=1000) def test_coo_mat(self): - data = -0.1 * np.ones(self.ij.shape[1]) + data = 0.1 * np.ones(self.ij.shape[1]) mat = coo_matrix( (data, (self.ij[0], self.ij[1])), shape=(self.n, self.n), From 63cbee8b71f156b01c6b71108088a67a10fbb233 Mon Sep 17 00:00:00 2001 From: samwaseda Date: Thu, 2 Nov 2023 10:06:09 +0000 Subject: [PATCH 07/10] modify environment.yml --- .ci_support/environment.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.ci_support/environment.yml b/.ci_support/environment.yml index 4ee6ce7..7f810a3 100644 --- a/.ci_support/environment.yml +++ b/.ci_support/environment.yml @@ -4,3 +4,4 @@ channels: dependencies: - numpy - cython + - scipy From a249d5a7604988da389225980ce41b46e5372384 Mon Sep 17 00:00:00 2001 From: samwaseda Date: Thu, 2 Nov 2023 10:13:30 +0000 Subject: [PATCH 08/10] update doc --- mamonca/mc.pyx | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/mamonca/mc.pyx b/mamonca/mc.pyx index 67bfd89..44937de 100644 --- a/mamonca/mc.pyx +++ b/mamonca/mc.pyx @@ -71,17 +71,19 @@ cdef class MC: def set_heisenberg_coeff(self, coeff, i=None, j=None, deg=1, index=0): """ Args: - coeff (float/list/ndarray): Heisenberg coefficient. If a single number is given, - the same parameter is applied to all the pairs defined in me and neigh. - Instead of giving me and neigh, you can also give a n_atom x n_atom tensor. - i (list/ndarray): list of indices i (s. definition in the comment) - j (list/ndarray): list of indices j (s. definition in the comment) + coeff (float/list/ndarray/scipy.sparse): Heisenberg coefficient. + If a single number is given, the same parameter is applied + to all the pairs defined in me and neigh. Instead of + giving me and neigh, you can also give a n_atom x n_atom + tensor. + i (list/ndarray): list of indices i (s. def in the comment) + j (list/ndarray): list of indices j (s. def in the comment) deg (int): polynomial degree - index (int): potential index for thermodynamic integration (0 or 1; choose 0 if - not thermodynamic integration) + index (int): potential index for thermodynamic integration + (0 or 1; choose 0 if not thermodynamic integration) Comment: - Heisenberg term is given by: -sum_ij coeff_ij*(m_i*m_j)^deg. Beware of the - negative sign. + Heisenberg term is given by: -sum_ij coeff_ij*(m_i*m_j)^deg. + Beware of the negative sign. """ if i is None and j is None: n = self.c_mc.get_number_of_atoms() From d2df6c52f5ea8f38064b54b0f40d0a05c0bca26e Mon Sep 17 00:00:00 2001 From: samwaseda Date: Thu, 2 Nov 2023 10:16:28 +0000 Subject: [PATCH 09/10] correct type --- mamonca/mc.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mamonca/mc.pyx b/mamonca/mc.pyx index 44937de..ef7a45b 100644 --- a/mamonca/mc.pyx +++ b/mamonca/mc.pyx @@ -87,7 +87,7 @@ cdef class MC: """ if i is None and j is None: n = self.c_mc.get_number_of_atoms() - if isinstance(coeff, np.ndarray | list): + if isinstance(coeff, (np.ndarray, list)): if np.array(coeff).shape!=(n, n): raise ValueError( "If i and j are not specified, coeff has to be a 2d" From 2ad674b78e282b1f228eb8ef2533bb44e94d885c Mon Sep 17 00:00:00 2001 From: samwaseda Date: Thu, 2 Nov 2023 10:24:43 +0000 Subject: [PATCH 10/10] update doc string --- mamonca/mc.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mamonca/mc.pyx b/mamonca/mc.pyx index ef7a45b..23431eb 100644 --- a/mamonca/mc.pyx +++ b/mamonca/mc.pyx @@ -24,7 +24,7 @@ cdef class MC: >>> first_shell_tensor = neighbors.get_shell_matrix()[0] >>> >>> mc = MC(len(structure)) - >>> mc.set_heisenberg_coeff(J*first_shell_tensor.toarray()) + >>> mc.set_heisenberg_coeff(J*first_shell_tensor) >>> >>> mc.run(temperature=300, number_of_iterations=1000)