Lewis Proctor
Lewis Proctor

Reputation: 121

2d sum using an array - Python

I'm trying to sum a two dimensional function using the array method, somehow, using a for loop is not outputting the correct answer. I want to find (in latex) $$\sum_{i=1}^{M}\sum_{j=1}^{M_2}\cos(i)\cos(j)$$ where according to Mathematica the answer when M=5 is 1.52725. According to the for loop:

def f(N):
s1=0;
for p1 in range(N):
    for p2 in range(N):
        s1+=np.cos(p1+1)*np.cos(p2+1)
        return s1
print(f(4))

is 0.291927.

I have thus been trying to use some code of the form:

def f1(N):
mat3=np.zeros((N,N),np.complex)
for i in range(0,len(mat3)):
    for j in range(0,len(mat3)):
        mat3[i][j]=np.cos(i+1)*np.cos(j+1)
        return sum(mat3)

which again

print(f1(4))

outputs 0.291927. Looking at the array we should find for each value of i and j a matrix of the form

mat3=[[np.cos(1)*np.cos(1),np.cos(2)*np.cos(1),...],[np.cos(2)*np.cos(1),...]...[np.cos(N+1)*np.cos(N+1)]]

so for N=4 we should have

mat3=[[np.cos(1)*np.cos(1) np.cos(2)*np.cos(1) ...] [np.cos(2)*np.cos(1) ...]...[... np.cos(5)*np.cos(5)]]

but what I actually get is the following

mat3=[[0.29192658+0.j 0.+0.j 0.+0.j ... 0.+0.j] ... [... 0.+0.j]]

or a matrix of all zeros apart from the mat3[0][0] element.

Does anybody know a correct way to do this and get the correct answer? I chose this as an example because the problem I'm trying to solve involves plotting a function which has been summed over two indices and the function that python outputs is not the same as Mathematica (i.e., a function of the form $$f(E)=\sum_{i=1}^{M}\sum_{j=1}^{M_2}F(i,j,E)$$).

Upvotes: 1

Views: 65

Answers (2)

lhk
lhk

Reputation: 30016

I have moved your code to a more numpy-ish version:

import numpy as np

N = 5
x = np.arange(N) + 1
y = np.arange(N) + 1

x = x.reshape((-1, 1))
y = y.reshape((1, -1))

mat = np.cos(x) * np.cos(y)
print(mat.sum()) # 1.5272472727003474

The trick here is to reshape x to a column and y to a row vector. If you multiply them, they are matched up like in your loop.

This should be more performant, since cos() is only called 2*N times. And it avoids loops (bad in python).

UPDATE (regarding your comment):

This pattern can be extended in any dimension. Basically, you get something like a crossproduct. Where every instance of x is matched up with every instance of y, z, u, k, ... Along the corresponding dimensions.

It's a bit confusing to describe, so here is some more code:

import numpy as np

N = 5
x = np.arange(N) + 1
y = np.arange(N) + 1
z = np.arange(N) + 1

x = x.reshape((-1, 1, 1))
y = y.reshape((1, -1, 1))
z = z.reshape((1, 1, -1))

mat = z**2 * np.cos(x) * np.cos(y)

# x along first axis
# y along second, z along third
# mat[0, 0, 0] == 1**2 * np.cos(1) * np.cos(1)
# mat[0, 4, 2] == 3**2 * np.cos(1) * np.cos(5)

If you use this for many dimensions, and big values for N, you will run into memory problems, though.

Upvotes: 1

w-m
w-m

Reputation: 11232

The return statement is not indented correctly in your sample code. It returns immediately in the first loop iteration. Indent it on the function body instead, so that both for loops finish:

def f(N):
    s1=0;
    for p1 in range(N):
        for p2 in range(N):
            s1+=np.cos(p1+1)*np.cos(p2+1)
    return s1

>>> print(f(5))
1.527247272700347

Upvotes: 1

Related Questions