Commits

Alex Gaynor committed 52cadac

Implemented subtraction in numpy (thanks to brentp). Also refactored to metaprogram (this is why we use pypy).

Comments (0)

Files changed (2)

pypy/module/micronumpy/numarray.py

 from pypy.interpreter.baseobjspace import ObjSpace, W_Root, Wrappable
 from pypy.interpreter.error import operationerrfmt
+from pypy.interpreter.gateway import interp2app, unwrap_spec
 from pypy.interpreter.typedef import TypeDef
-from pypy.interpreter.gateway import interp2app, unwrap_spec
-from pypy.rpython.lltypesystem import lltype
 from pypy.rlib import jit
 from pypy.rlib.nonconst import NonConstant
+from pypy.rpython.lltypesystem import lltype
+from pypy.tool.sourcetools import func_with_new_name
+
 
 TP = lltype.Array(lltype.Float, hints={'nolength': True})
 
                 frame.pushvalue(val)
             elif opcode == 'a':
                 # Add.
+                a = frame.popvalue()
                 b = frame.popvalue()
+                frame.pushvalue(a + b)
+            elif opcode == 's':
+                # Subtract
                 a = frame.popvalue()
-                frame.pushvalue(a + b)
+                b = frame.popvalue()
+                frame.pushvalue(a - b)
             elif opcode == 'm':
                 # Multiply.
+                a = frame.popvalue()
                 b = frame.popvalue()
-                a = frame.popvalue()
                 frame.pushvalue(a * b)
             else:
                 raise NotImplementedError(
         # (we still have to compile new bytecode, but too bad)
         return compute(code)
 
-    def descr_add(self, space, w_other):
-        if isinstance(w_other, BaseArray):
-            return space.wrap(BinOp('a', self, w_other))
-        else:
-            return space.wrap(BinOp('a', self,
-                FloatWrapper(space.float_w(w_other))))
+    def _binop_impl(bytecode):
+        def impl(self, space, w_other):
+            if isinstance(w_other, BaseArray):
+                return space.wrap(BinOp(bytecode, self, w_other))
+            else:
+                return space.wrap(BinOp(
+                    bytecode,
+                    self,
+                    FloatWrapper(space.float_w(w_other))
+                ))
+        return func_with_new_name(impl, "binop_%s_impl" % bytecode)
 
-    def descr_mul(self, space, w_other):
-        if isinstance(w_other, BaseArray):
-            return space.wrap(BinOp('m', self, w_other))
-        else:
-            return space.wrap(BinOp('m', self,
-                FloatWrapper(space.float_w(w_other))))
+    descr_add = _binop_impl("a")
+    descr_mul = _binop_impl("m")
+    descr_sub = _binop_impl("s")
 
     def compile(self):
         raise NotImplementedError("abstract base class")
     'Operation',
     force = interp2app(BaseArray.force),
     __add__ = interp2app(BaseArray.descr_add),
+    __sub__ = interp2app(BaseArray.descr_sub),
     __mul__ = interp2app(BaseArray.descr_mul),
 )
 
     __getitem__ = interp2app(SingleDimArray.descr_getitem),
     __setitem__ = interp2app(SingleDimArray.descr_setitem),
     __add__ = interp2app(BaseArray.descr_add),
+    __sub__ = interp2app(BaseArray.descr_sub),
     __mul__ = interp2app(BaseArray.descr_mul),
     force = interp2app(SingleDimArray.force),
 )

pypy/module/micronumpy/test/test_numpy.py

         for i in range(5):
             assert b[i] == i + 5
 
+    def test_subtract(self):
+        from numpy import array
+        a = array(range(5))
+        b = (a - a).force()
+        for i in range(5):
+            assert b[i] == 0
+
+    def test_subtract_other(self):
+        from numpy import array
+        a = array(range(5))
+        b = array([1, 1, 1, 1, 1])
+        c = (a - b).force()
+        for i in range(5):
+            assert c[i] == i - 1
+
+    def test_subtract_constant(self):
+        from numpy import array
+        a = array(range(5))
+        b = (a - 5).force()
+        for i in range(5):
+            assert b[i] == i - 5
+
     def test_mul(self):
         from numpy import array
         a = array(range(5))
     def setup_class(cls):
         py.test.skip("unimplemented")
         cls.space = gettestobjspace(usemodules=('micronumpy',))
-    
+
     def test_zeroes(self):
         from numpy import zeros
         ar = zeros(3, dtype=int)
         assert ar[0] == 0
-    
+
     def test_setitem_getitem(self):
         from numpy import zeros
         ar = zeros(8, dtype=int)