From 3b119358086fbb22a06347db95589243a79cf5ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?xavier=20dupr=C3=A9?= Date: Tue, 19 Jan 2021 17:34:41 +0100 Subject: [PATCH 1/5] first modification --- setup.py | 2 +- td3a_cpp/tutorial/td_mul_cython.pyx | 21 +++++++++++++++++++++ tests/test_tutorial_td.py | 20 ++++++++++++++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 td3a_cpp/tutorial/td_mul_cython.pyx create mode 100644 tests/test_tutorial_td.py diff --git a/setup.py b/setup.py index 9cd6808..77a380d 100644 --- a/setup.py +++ b/setup.py @@ -117,7 +117,7 @@ def get_extension_tutorial(name): ext_modules = [] for ext in ['dot_blas_lapack', 'dot_cython', 'experiment_cython', 'dot_cython_omp', - 'mul_cython_omp']: + 'mul_cython_omp', 'td_mul_cython']: ext_modules.extend(get_extension_tutorial(ext)) diff --git a/td3a_cpp/tutorial/td_mul_cython.pyx b/td3a_cpp/tutorial/td_mul_cython.pyx new file mode 100644 index 0000000..463b30f --- /dev/null +++ b/td3a_cpp/tutorial/td_mul_cython.pyx @@ -0,0 +1,21 @@ +""" +TD 2021/01/19. +""" +from cython.parallel import prange +cimport cython +from cpython cimport array +import array + +import numpy as pynumpy +cimport numpy as cnumpy +cnumpy.import_array() + + +def multiply_matrix(m1, m2): + m3 = pynumpy.zeros((m1.shape[0], m2.shape[1]), dtype=m1.dtype) + for i in range(0, m1.shape[0]): + for j in range(0, m2.shape[1]): + for k in range(0, m1.shape[1]): + m3[i, j] += m1[i, k] * m2[k, j] + return m3 + diff --git a/tests/test_tutorial_td.py b/tests/test_tutorial_td.py new file mode 100644 index 0000000..c65e2c4 --- /dev/null +++ b/tests/test_tutorial_td.py @@ -0,0 +1,20 @@ +""" +""" +import unittest +import numpy +from numpy.testing import assert_almost_equal +from td3a_cpp.tutorial.td_mul_cython import multiply_matrix + + +class TestTutorialTD(unittest.TestCase): + + def test_matrix_multiply_matrix(self): + va = numpy.random.randn(3, 4).astype(numpy.float64) + vb = numpy.random.randn(4, 5).astype(numpy.float64) + res1 = va @ vb + res2 = multiply_matrix(va, vb) + assert_almost_equal(res1, res2) + + +if __name__ == '__main__': + unittest.main() From 7d6928405186c8799db37eb2173dd404fd0d3f70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?xavier=20dupr=C3=A9?= Date: Tue, 19 Jan 2021 17:49:02 +0100 Subject: [PATCH 2/5] Add cython function --- td3a_cpp/tutorial/td_mul_cython.pyx | 12 ++++++++++++ tests/test_tutorial_td.py | 10 +++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/td3a_cpp/tutorial/td_mul_cython.pyx b/td3a_cpp/tutorial/td_mul_cython.pyx index 463b30f..1638450 100644 --- a/td3a_cpp/tutorial/td_mul_cython.pyx +++ b/td3a_cpp/tutorial/td_mul_cython.pyx @@ -19,3 +19,15 @@ def multiply_matrix(m1, m2): m3[i, j] += m1[i, k] * m2[k, j] return m3 + +cdef double[:, :] _c_multiply_matrix(double[:, :] m1, double[:, :] m2): + m3 = pynumpy.zeros((m1.shape[0], m2.shape[1]), dtype=pynumpy.float64) + for i in range(0, m1.shape[0]): + for j in range(0, m2.shape[1]): + for k in range(0, m1.shape[1]): + m3[i, j] += m1[i, k] * m2[k, j] + return m3 + + +def c_multiply_matrix(double[:, :] m1, double[:, :] m2): + return _c_multiply_matrix(m1, m2) diff --git a/tests/test_tutorial_td.py b/tests/test_tutorial_td.py index c65e2c4..338c4f9 100644 --- a/tests/test_tutorial_td.py +++ b/tests/test_tutorial_td.py @@ -3,7 +3,8 @@ import unittest import numpy from numpy.testing import assert_almost_equal -from td3a_cpp.tutorial.td_mul_cython import multiply_matrix +from td3a_cpp.tutorial.td_mul_cython import ( + multiply_matrix, c_multiply_matrix) class TestTutorialTD(unittest.TestCase): @@ -15,6 +16,13 @@ def test_matrix_multiply_matrix(self): res2 = multiply_matrix(va, vb) assert_almost_equal(res1, res2) + def test_matrix_cmultiply_matrix(self): + va = numpy.random.randn(3, 4).astype(numpy.float64) + vb = numpy.random.randn(4, 5).astype(numpy.float64) + res1 = va @ vb + res2 = c_multiply_matrix(va, vb) + assert_almost_equal(res1, res2) + if __name__ == '__main__': unittest.main() From c72a2591e6d0383806b789971b9621b4f6aa4e99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?xavier=20dupr=C3=A9?= Date: Tue, 19 Jan 2021 18:55:26 +0100 Subject: [PATCH 3/5] finalize the version --- td3a_cpp/tutorial/td_mul_cython.pyx | 20 +++++++++++++------- tests/test_tutorial_td.py | 15 +++++++++++++++ 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/td3a_cpp/tutorial/td_mul_cython.pyx b/td3a_cpp/tutorial/td_mul_cython.pyx index 1638450..5ca0cc3 100644 --- a/td3a_cpp/tutorial/td_mul_cython.pyx +++ b/td3a_cpp/tutorial/td_mul_cython.pyx @@ -20,14 +20,20 @@ def multiply_matrix(m1, m2): return m3 -cdef double[:, :] _c_multiply_matrix(double[:, :] m1, double[:, :] m2): - m3 = pynumpy.zeros((m1.shape[0], m2.shape[1]), dtype=pynumpy.float64) - for i in range(0, m1.shape[0]): - for j in range(0, m2.shape[1]): - for k in range(0, m1.shape[1]): +cdef void _c_multiply_matrix(double[:, :] m1, double[:, :] m2, + double[:, :] m3, + cython.int ni, cython.int nj, cython.int nk) nogil: + cdef cython.int i, j, k + for i in prange(0, ni): + for j in range(0, nj): + for k in range(0, nk): m3[i, j] += m1[i, k] * m2[k, j] - return m3 def c_multiply_matrix(double[:, :] m1, double[:, :] m2): - return _c_multiply_matrix(m1, m2) + m3 = pynumpy.zeros((m1.shape[0], m2.shape[1]), dtype=pynumpy.float64) + cdef cython.int ni = m1.shape[0] + cdef cython.int nj = m2.shape[1] + cdef cython.int nk = m1.shape[1] + _c_multiply_matrix(m1, m2, m3, ni, nj, nk) + return m3 diff --git a/tests/test_tutorial_td.py b/tests/test_tutorial_td.py index 338c4f9..235d71d 100644 --- a/tests/test_tutorial_td.py +++ b/tests/test_tutorial_td.py @@ -1,10 +1,12 @@ """ """ import unittest +import timeit import numpy from numpy.testing import assert_almost_equal from td3a_cpp.tutorial.td_mul_cython import ( multiply_matrix, c_multiply_matrix) +from td3a_cpp.tutorial.mul_cython_omp import dmul_cython_omp class TestTutorialTD(unittest.TestCase): @@ -23,6 +25,19 @@ def test_matrix_cmultiply_matrix(self): res2 = c_multiply_matrix(va, vb) assert_almost_equal(res1, res2) + def test_timeit(self): + va = numpy.random.randn(300, 400).astype(numpy.float64) + vb = numpy.random.randn(400, 500).astype(numpy.float64) + res1 = va @ vb + res2 = c_multiply_matrix(va, vb) + ctx = {'va': va, 'vb': vb, 'c_multiply_matrix': c_multiply_matrix} + res1 = timeit.timeit('va @ vb', number=10, globals=ctx) + res2 = timeit.timeit('c_multiply_matrix(va, vb)', number=10, globals=ctx) + self.assertLess(res1, res2) # numpy is much faster. + ratio = res2 / res1 + self.assertGreater(ratio, 1) # ratio = number of times numpy is faster + # print(ratio) + if __name__ == '__main__': unittest.main() From 48e25bee8fc2891abb75e2f6e158606e35a03e06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?xavier=20dupr=C3=A9?= Date: Tue, 19 Jan 2021 19:22:42 +0100 Subject: [PATCH 4/5] lint --- td3a_cpp/tutorial/td_mul_cython.pyx | 3 +++ tests/test_tutorial_td.py | 18 ++++++++++-------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/td3a_cpp/tutorial/td_mul_cython.pyx b/td3a_cpp/tutorial/td_mul_cython.pyx index 5ca0cc3..76aec48 100644 --- a/td3a_cpp/tutorial/td_mul_cython.pyx +++ b/td3a_cpp/tutorial/td_mul_cython.pyx @@ -12,6 +12,7 @@ cnumpy.import_array() def multiply_matrix(m1, m2): + "Matrix multiplication" m3 = pynumpy.zeros((m1.shape[0], m2.shape[1]), dtype=m1.dtype) for i in range(0, m1.shape[0]): for j in range(0, m2.shape[1]): @@ -23,6 +24,7 @@ def multiply_matrix(m1, m2): cdef void _c_multiply_matrix(double[:, :] m1, double[:, :] m2, double[:, :] m3, cython.int ni, cython.int nj, cython.int nk) nogil: + "Matrix multiplication wuth cython" cdef cython.int i, j, k for i in prange(0, ni): for j in range(0, nj): @@ -31,6 +33,7 @@ cdef void _c_multiply_matrix(double[:, :] m1, double[:, :] m2, def c_multiply_matrix(double[:, :] m1, double[:, :] m2): + "Matrix multiplication calling the cython version" m3 = pynumpy.zeros((m1.shape[0], m2.shape[1]), dtype=pynumpy.float64) cdef cython.int ni = m1.shape[0] cdef cython.int nj = m2.shape[1] diff --git a/tests/test_tutorial_td.py b/tests/test_tutorial_td.py index 235d71d..78757a2 100644 --- a/tests/test_tutorial_td.py +++ b/tests/test_tutorial_td.py @@ -6,7 +6,6 @@ from numpy.testing import assert_almost_equal from td3a_cpp.tutorial.td_mul_cython import ( multiply_matrix, c_multiply_matrix) -from td3a_cpp.tutorial.mul_cython_omp import dmul_cython_omp class TestTutorialTD(unittest.TestCase): @@ -28,15 +27,18 @@ def test_matrix_cmultiply_matrix(self): def test_timeit(self): va = numpy.random.randn(300, 400).astype(numpy.float64) vb = numpy.random.randn(400, 500).astype(numpy.float64) - res1 = va @ vb - res2 = c_multiply_matrix(va, vb) - ctx = {'va': va, 'vb': vb, 'c_multiply_matrix': c_multiply_matrix} + ctx = {'va': va, 'vb': vb, 'c_multiply_matrix': c_multiply_matrix, + 'multiply_matrix': multiply_matrix} res1 = timeit.timeit('va @ vb', number=10, globals=ctx) - res2 = timeit.timeit('c_multiply_matrix(va, vb)', number=10, globals=ctx) + res2 = timeit.timeit( + 'c_multiply_matrix(va, vb)', number=10, globals=ctx) + res3 = timeit.timeit( + 'multiply_matrix(va, vb)', number=10, globals=ctx) self.assertLess(res1, res2) # numpy is much faster. - ratio = res2 / res1 - self.assertGreater(ratio, 1) # ratio = number of times numpy is faster - # print(ratio) + ratio1 = res2 / res1 + self.assertGreater(ratio1, 1) # ratio1 = number of times numpy is faster + ratio2 = res3 / res1 + self.assertGreater(ratio2, 1) if __name__ == '__main__': From f793d1fefe37fb096c39e32eb99af6646f66b0f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?xavier=20dupr=C3=A9?= Date: Wed, 20 Jan 2021 00:20:33 +0100 Subject: [PATCH 5/5] Update test_tutorial_td.py --- tests/test_tutorial_td.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_tutorial_td.py b/tests/test_tutorial_td.py index 78757a2..e906714 100644 --- a/tests/test_tutorial_td.py +++ b/tests/test_tutorial_td.py @@ -36,7 +36,8 @@ def test_timeit(self): 'multiply_matrix(va, vb)', number=10, globals=ctx) self.assertLess(res1, res2) # numpy is much faster. ratio1 = res2 / res1 - self.assertGreater(ratio1, 1) # ratio1 = number of times numpy is faster + # ratio1 = number of times numpy is faster + self.assertGreater(ratio1, 1) ratio2 = res3 / res1 self.assertGreater(ratio2, 1)