# [SciPy-dev] Adding to an array with __radd__()

Ed Schofield schofield at ftw.at
Mon Oct 31 12:29:55 CST 2005

```Travis Oliphant wrote:

>Ed Schofield wrote:
>
>
>
>>Sparse matrix objects now support adding a sparse matrix to a dense
>>matrix of the same dimensions with the syntax:
>>
>>newdense = sparse + dense
>>
>>I'd like to add support for the opposite order too:
>>
>>newdense = dense + sparse
>>
>>but this doesn't seem possible currently.  This operation calls the
>>__radd__() method of the sparse matrix object multiple times, each time
>>passing a single element from the dense matrix.
>>
>>
>Why does it do this?   This does not seem to be the way Python would
>handle it.
>
>Can you track exactly what gets called when
>
>dense + sparse
>
>is performed?
>
>
Sure.  Actually, it looks like the scipy 0.3.2 handled it fine.  This
script:

-----------------------
class A:
def __radd__(a, b=None, c=None):
print "A.__radd__() called, with arguments (%s, %s, %s)" % (a, b, c)

def __add__(a, b=None, c=None):
print "A.__add__() called, with arguments (%s, %s, %s)" % (a, b, c)

class B:
def __radd__(a, b=None, c=None):
print "B.__radd__() called, with arguments (%s, %s, %s)" % (a, b, c)

a  = A()
b = B()
print "a + b is: " + str(a + b)
print "b + a is: " + str(b + a)

import scipy
c = scipy.array([[1,2,3],[4,5,6]])
print "c + a is: " + str(c + a)
print "a + c is: " + str(a + c)

------------------

produces this output with scipy 0.3.2:

------------------
A.__add__() called, with arguments (<__main__.A instance at 0xb7eaff8c>,
<__main__.B instance at 0xb7eaffec>, None)
a + b is: A.add()

A.__radd__() called, with arguments (<__main__.A instance at
0xb7eaff8c>, <__main__.B instance at 0xb7eaffec>, None)
b + a is: A.radd()

A.__radd__() called, with arguments (<__main__.A instance at
0xb7eaff8c>, [[1 2 3]
[4 5 6]], None)
c + a is: A.radd()

A.__add__() called, with arguments (<__main__.A instance at 0xb7eaff8c>,
[[1 2 3]
[4 5 6]], None)
a + c is: A.add()
---------------------

as expected.  With newcore (0.4.3.1401) I get:

---------------------
A.__add__() called, with arguments (<__main__.A instance at 0xb7e98f8c>,
<__main__.B instance at 0xb7e98fec>, None)
a + b is: A.add()

A.__radd__() called, with arguments (<__main__.A instance at
0xb7e98f8c>, <__main__.B instance at 0xb7e98fec>, None)
b + a is: A.radd()

Importing io to scipy
Importing interpolate to scipy
Importing fftpack to scipy
Importing special to scipy
Importing cluster to scipy
Importing sparse to scipy
Importing signal to scipy
Failed to import signal
cannot import name comb
Importing utils to scipy
Importing lib to scipy
Importing integrate to scipy
Importing optimize to scipy
Importing linalg to scipy
Importing stats to scipy
A.__radd__() called, with arguments (<__main__.A instance at
0xb7ecaf8c>, 1, None)
A.__radd__() called, with arguments (<__main__.A instance at
0xb7ecaf8c>, 2, None)
A.__radd__() called, with arguments (<__main__.A instance at
0xb7ecaf8c>, 3, None)
A.__radd__() called, with arguments (<__main__.A instance at
0xb7ecaf8c>, 4, None)
A.__radd__() called, with arguments (<__main__.A instance at
0xb7ecaf8c>, 5, None)
A.__radd__() called, with arguments (<__main__.A instance at
0xb7ecaf8c>, 6, None)
c + a is: [[A.radd()
]
]]
A.__add__() called, with arguments (<__main__.A instance at 0xb7ecaf8c>,
[[1 2 3]
[4 5 6]], None)
a + c is: A.add()

--------------------

Tracing through the code, it seems the following functions are called:

... a wrapper I don't understand ... then
PyNumber_Add() from __umath_generated.c (which supposedly works elementwise)
PyArray_FromAny()
... and ...
array_fromobject()

which queries various attributes like __array__, __array_shape__, and
__len__

I haven't yet checked further than this ... e.g. whether the type ==
PyArray_NOTYPE succeeds ...

-- Ed

```