From e2b2ebe862ba4affb77a8b44eeefc447a0db2e77 Mon Sep 17 00:00:00 2001 From: Jim Bosch Date: Fri, 14 May 2010 22:47:14 +0000 Subject: [PATCH] numpy python extension - added basic SCons build system, started on unit tests --- SConstruct | 51 ++++++++++++++++++++++++++++ libs/python/numpy/src/SConscript | 5 +++ libs/python/numpy/test/SConscript | 17 ++++++++++ libs/python/numpy/test/ufunc.py | 49 ++++++++++++++++++++++++++ libs/python/numpy/test/ufunc_mod.cpp | 31 +++++++++++++++++ 5 files changed, 153 insertions(+) create mode 100644 SConstruct create mode 100644 libs/python/numpy/src/SConscript create mode 100644 libs/python/numpy/test/SConscript create mode 100755 libs/python/numpy/test/ufunc.py create mode 100644 libs/python/numpy/test/ufunc_mod.cpp diff --git a/SConstruct b/SConstruct new file mode 100644 index 00000000..14d42ee5 --- /dev/null +++ b/SConstruct @@ -0,0 +1,51 @@ +import distutils.sysconfig +import numpy.distutils.misc_util +import re +import os + +def ApplyFlags(env, flags): + flags = env.ParseFlags(flags) + flags["CCFLAGS"] = [opt for opt in flags["CCFLAGS"] if not opt.startswith("-O")] + flags["CFLAGS"] = [opt for opt in flags["CFLAGS"] if not opt.startswith("-O")] + debug = ARGUMENTS.get('debug', 0) + if int(debug): + try: + flags["CPPDEFINES"].remove("NDEBUG") + except: pass + env.MergeFlags(flags) + +def ConfigurePython(env): + cflags = " ".join(v for v in distutils.sysconfig.get_config_vars("BASECFLAGS","OPT") + if v is not None).split() + libs = " ".join(v for v in distutils.sysconfig.get_config_vars("BLDLIBRARY","LIBS") + if v is not None).split() + try: # not valid for C++ + cflags.remove("-Wstrict-prototypes") + except ValueError: pass + cflags = [f for f in cflags if not f.startswith("-O")] + try: + libs.remove("-L.") + except ValueError: pass + cflags.append("-I%s" % distutils.sysconfig.get_python_inc()) + ApplyFlags(env, cflags + libs) + +def ConfigureNumpy(env): + folders = numpy.distutils.misc_util.get_numpy_include_dirs() + env.Append(CPPPATH=folders) + +env = Environment() +ConfigurePython(env) +ConfigureNumpy(env) +env.Append(LIBS = "boost_python") +env.Append(CPPPATH = "#") + +Export("env") +lib = SConscript("libs/python/numpy/src/SConscript") +libpath = os.path.abspath("libs/python/numpy/src") +if os.environ.has_key("LD_LIBRARY_PATH"): + env["ENV"]["LD_LIBRARY_PATH"] = "%s:%s" % (libpath, os.environ["LD_LIBRARY_PATH"]) +else: + env["ENV"]["LD_LIBRARY_PATH"] = libpath +env.Append(LIBPATH=libpath) +Export("lib") +SConscript("libs/python/numpy/test/SConscript") diff --git a/libs/python/numpy/src/SConscript b/libs/python/numpy/src/SConscript new file mode 100644 index 00000000..c06300a1 --- /dev/null +++ b/libs/python/numpy/src/SConscript @@ -0,0 +1,5 @@ +Import("env") + +lib = env.SharedLibrary("boost_python_numpy", Glob("*.cpp")) + +Return("lib") diff --git a/libs/python/numpy/test/SConscript b/libs/python/numpy/test/SConscript new file mode 100644 index 00000000..f9615976 --- /dev/null +++ b/libs/python/numpy/test/SConscript @@ -0,0 +1,17 @@ +Import("env") +import os + +test_env = env.Clone() +test_env.Append(LIBS="boost_python_numpy") + +tests = ("ufunc",) +test_mods = [test_env.SharedLibrary("%s_mod" % k, "%s_mod.cpp" % k, SHLIBPREFIX="") + for k in tests] +os.path.abspath(".") +test_runs = [test_env.Command(".%s" % name, [mod,"%s.py" % name], + "cd %s; python %s.py" % (os.path.abspath("."), name)) + for name, mod in zip(tests, test_mods)] + +test = Alias("test",[test_runs]) + +Return("test") diff --git a/libs/python/numpy/test/ufunc.py b/libs/python/numpy/test/ufunc.py new file mode 100755 index 00000000..c66a148b --- /dev/null +++ b/libs/python/numpy/test/ufunc.py @@ -0,0 +1,49 @@ +import ufunc_mod +import unittest +import numpy + +class TestUnary(unittest.TestCase): + + def testScalar(self): + f = ufunc_mod.UnaryCallable() + self.assertEqual(f(1.0), 2.0) + self.assertEqual(f(3.0), 6.0) + + def testArray(self): + f = ufunc_mod.UnaryCallable() + a = numpy.arange(5, dtype=float) + b = f(a) + self.assert_((b == a*2.0).all()) + c = numpy.zeros(5, dtype=float) + d = f(a,output=c) + self.assert_((c == a*2.0).all()) + self.assert_((d == a*2.0).all()) + + def testList(self): + f = ufunc_mod.UnaryCallable() + a = range(5) + b = f(a) + self.assert_((b/2.0 == a).all()) + +class TestBinary(unittest.TestCase): + + def testScalar(self): + f = ufunc_mod.BinaryCallable() + self.assertEqual(f(1.0, 3.0), 11.0) + self.assertEqual(f(3.0, 2.0), 12.0) + + def testArray(self): + f = ufunc_mod.BinaryCallable() + a = numpy.random.randn(5) + b = numpy.random.randn(5) + self.assert_((f(a,b) == (a*2+b*3)).all()) + c = numpy.zeros(5, dtype=float) + d = f(a,b,output=c) + self.assert_((c == a*2 + b*3).all()) + self.assert_((d == a*2 + b*3).all()) + self.assert_((f(a, 2.0) == a*2 + 6.0).all()) + self.assert_((f(1.0, b) == 2.0 + b*3).all()) + + +if __name__=="__main__": + unittest.main() diff --git a/libs/python/numpy/test/ufunc_mod.cpp b/libs/python/numpy/test/ufunc_mod.cpp new file mode 100644 index 00000000..4b5c9563 --- /dev/null +++ b/libs/python/numpy/test/ufunc_mod.cpp @@ -0,0 +1,31 @@ +#include + +namespace bp = boost::python; + +struct UnaryCallable { + + typedef double argument_type; + typedef double result_type; + + double operator()(double r) const { return r * 2; } + +}; + +struct BinaryCallable { + + typedef double first_argument_type; + typedef double second_argument_type; + typedef double result_type; + + double operator()(double a, double b) const { return a * 2 + b * 3; } + +}; + +BOOST_PYTHON_MODULE(ufunc_mod) { + bp::numpy::initialize(); + bp::class_< UnaryCallable, boost::shared_ptr >("UnaryCallable") + .def("__call__", bp::numpy::unary_ufunc::make()); + bp::class_< BinaryCallable, boost::shared_ptr >("BinaryCallable") + .def("__call__", bp::numpy::binary_ufunc::make()); + +}