From 94206d24ab08e73823eafacaa8cb11d5885cf025 Mon Sep 17 00:00:00 2001 From: Shinya Morino Date: Sat, 10 Nov 2018 23:02:54 +0900 Subject: [PATCH] python c-extension for get_system_E(). get_system_E() is added to sqaod.py. --- sqaodc/pyglue/annealer.inc | 29 +++++++++++++++++++ .../common/bipartite_graph_annealer_base.py | 4 +++ .../sqaod/common/dense_graph_annealer_base.py | 4 +++ sqaodpy/sqaod/common/preference.py | 10 +++++++ sqaodpy/sqaod/py/bipartite_graph_annealer.py | 20 +++++++++++++ sqaodpy/sqaod/py/dense_graph_annealer.py | 17 +++++++++++ 6 files changed, 84 insertions(+) diff --git a/sqaodc/pyglue/annealer.inc b/sqaodc/pyglue/annealer.inc index e19dc32..89f9fe9 100644 --- a/sqaodc/pyglue/annealer.inc +++ b/sqaodc/pyglue/annealer.inc @@ -820,6 +820,34 @@ PyObject *annealer_make_solution(PyObject *module, PyObject *args) { return Py_None; } +template +PyObject *internal_get_system_E(PyObject *objExt, PyObject *objG, PyObject *objBeta) { + typedef NpConstScalarType NpConstScalar; + NpConstScalar G(objG), beta(objBeta); + if (G.err || beta.err) + return NULL; + real E = pyobjToCppObj(objExt)->getSystemE(G, beta); + PyObject *objE = newScalarObj(E); + // Py_INCREF(objE); + return objE; +} + +extern "C" +PyObject *annealer_get_system_E(PyObject *module, PyObject *args) { + PyObject *objExt, *objG, *objKT, *dtype; + if (!PyArg_ParseTuple(args, "OOOO", &objExt, &objG, &objKT, &dtype)) + return NULL; + + ASSERT_DTYPE(dtype); + + TRY { + if (isFloat64(dtype)) + return internal_get_system_E(objExt, objG, objKT); + else // if (isFloat32(dtype)) + return internal_get_system_E(objExt, objG, objKT); + } CATCH_ERROR_AND_RETURN; + return NULL; +} template PyObject *internal_anneal_one_step(PyObject *objExt, PyObject *objG, PyObject *objBeta) { @@ -876,6 +904,7 @@ PyMethodDef annealer_methods[] = { {"calculate_E", annealer_calculate_E, METH_VARARGS}, {"prepare", annealer_prepare, METH_VARARGS}, {"make_solution", annealer_make_solution, METH_VARARGS}, + {"get_system_E", annealer_get_system_E, METH_VARARGS}, {"anneal_one_step", annealer_anneal_one_step, METH_VARARGS}, {NULL}, }; diff --git a/sqaodpy/sqaod/common/bipartite_graph_annealer_base.py b/sqaodpy/sqaod/common/bipartite_graph_annealer_base.py index 8d1980d..e8c1c7b 100644 --- a/sqaodpy/sqaod/common/bipartite_graph_annealer_base.py +++ b/sqaodpy/sqaod/common/bipartite_graph_annealer_base.py @@ -98,6 +98,10 @@ def prepare(self) : def make_solution(self) : self._cext.make_solution(self._cobj, self.dtype) + + def get_system_E(self, G, beta) : + G, beta = self.dtype(G), self.dtype(beta) + return self._cext.get_system_E(self._cobj, G, beta, self.dtype) def anneal_one_step(self, G, beta) : G, beta = self.dtype(G), self.dtype(beta) diff --git a/sqaodpy/sqaod/common/dense_graph_annealer_base.py b/sqaodpy/sqaod/common/dense_graph_annealer_base.py index 82ea30d..41503b7 100644 --- a/sqaodpy/sqaod/common/dense_graph_annealer_base.py +++ b/sqaodpy/sqaod/common/dense_graph_annealer_base.py @@ -92,6 +92,10 @@ def prepare(self) : def make_solution(self) : self._cext.make_solution(self._cobj, self.dtype) + def get_system_E(self, G, beta) : + G, beta = self.dtype(G), self.dtype(beta) + return self._cext.get_system_E(self._cobj, G, beta, self.dtype) + def anneal_one_step(self, G, beta) : G, beta = self.dtype(G), self.dtype(beta) self._cext.anneal_one_step(self._cobj, G, beta, self.dtype) diff --git a/sqaodpy/sqaod/common/preference.py b/sqaodpy/sqaod/common/preference.py index 14bcc0c..e2ee122 100644 --- a/sqaodpy/sqaod/common/preference.py +++ b/sqaodpy/sqaod/common/preference.py @@ -8,6 +8,16 @@ class Algorithm : sa_default = 'sa_default' sa_naive = 'sa_naive' sa_coloring = 'sa_coloring' + + @staticmethod + def is_sqa(algo) : + if algo == Algorithm.default or \ + algo == Algorithm.naive or \ + algo == Algorithm.coloring : + return True + + return False + algorithm = Algorithm() """ diff --git a/sqaodpy/sqaod/py/bipartite_graph_annealer.py b/sqaodpy/sqaod/py/bipartite_graph_annealer.py index 940c71e..2d54208 100644 --- a/sqaodpy/sqaod/py/bipartite_graph_annealer.py +++ b/sqaodpy/sqaod/py/bipartite_graph_annealer.py @@ -258,6 +258,26 @@ def make_solution(self) : """ pass + def get_system_E(self, G, beta) : + # average energy + E = np.mean(self.get_E()) + + m = self._m + algo = self._get_algorithm() + if sqaod.algorithm.is_sqa(algo) : + q0, q1 = self._q0, self._q1 + spinDotSum = 0. + for im in range(m) : + q00 = np.asarray(q0[im], np.float64) + q01 = np.asarray(q0[(im + 1) % m], np.float64) + spinDotSum += q00.dot(q01) + q10 = np.asarray(q1[im], np.float64) + q11 = np.asarray(q1[(im + 1) % m], np.float64) + spinDotSum += q10.dot(q11) + E += - 1. / (2 * beta) * np.log(np.tanh(G * beta / m)) * spinDotSum + + return E + def anneal_one_step(self, G, beta) : """ Run annealing one step. diff --git a/sqaodpy/sqaod/py/dense_graph_annealer.py b/sqaodpy/sqaod/py/dense_graph_annealer.py index c12e0ae..089bdbf 100644 --- a/sqaodpy/sqaod/py/dense_graph_annealer.py +++ b/sqaodpy/sqaod/py/dense_graph_annealer.py @@ -261,6 +261,23 @@ def make_solution(self) : """ pass + def get_system_E(self, G, beta) : + # average energy + E = np.mean(self.get_E()) + + m = self._m + algo = self._get_algorithm() + if sqaod.algorithm.is_sqa(algo) : + q = self._q + spinDotSum = 0. + for im in range(m) : + q0 = np.asarray(q[im], np.float64) + q1 = np.asarray(q[(im + 1) % m], np.float64) + spinDotSum += q0.dot(q1) + E -= 0.5 / beta * np.log(np.tanh(G * beta / m)) * spinDotSum + + return E + def anneal_one_step(self, G, beta) : """ Run annealing one step.