Multiplying a square array and row array with nested for loops - python

I'm trying to multiply a square array and a row array with nested for loops but I am running into errors such as object of type numpy.int64' has no len().
I need to be able to calculate the product with two nested for loops but I am unsure where I can change my code to optimise and fix my errors.
def matvec_row_variant_scalar(A,x):
product_array = np.zeros((len(A),len(A)),dtype=int)
for i in range(len(A)):
for j in range(len(x[0])):
for k in range(len(x)):
product_array[i][j] += A[i][k] * x[k][j]
return product_array
# Test arrays
square_array = np.array([[1,2],[3,4]])
row_array = np.array([2,2])
matvec_row_variant_scalar(square_array,row_array)

I think the code has two problems.
On the second for loop you used len(x[0]). as declaration x is 1D array and then x[0] is an Integer and calculating length on integer will thrown type error .
print(len(2)) #TypeError: object of type int has no len()
On product_array[i][j] += A[i][k] * x[k][j], again you should consider x is 1D!
Here is your fixed code.
import numpy as np
def matvec_row_variant_scalar(A,x):
product_array = np.zeros((len(A),len(A)),dtype=int)
for i in range(len(A)):
for j in range(len(A[i])):
for k in range(len(x)):
product_array[i][j] += A[i][k] * x[j]
return product_array
# Test arrays
square_array = np.array([[1,2],[3,4]])
row_array = np.array([2,2])
matvec_row_variant_scalar(square_array,row_array)
The returned Result is
array([[ 6, 6],
[14, 14]])

Okay, I figured it out. Thanks for the help from everyone. Here's the code for anyone interested:
import numpy as np
def matvec_row_variant_scalar(A,x):
product_array = np.zeros((len(A),len(A)),dtype=int)
for i in range(len(A)):
for j in range(len(A[i])):
product_array[i][j] += x[i] * A[i][j]
column_sum = product_array.sum(axis=0)
return column_sum
square_array = np.array([[1,2],[3,4]])
row_array = np.array([2,2])
matvec_row_variant_scalar(square_array,row_array)

Related

How can this function be vectorized?

I have a NumPy array with the following properties:
shape: (9986080, 2)
dtype: np.float32
I have a method that loops over the range of the array, performs an operation and then inputs result to new array:
def foo(arr):
new_arr = np.empty(arr.size, dtype=np.uint64)
for i in range(arr.size):
x, y = arr[i]
e, n = ''
if x < 0:
e = '1'
else:
w = '2'
if y > 0:
n = '3'
else:
s = '4'
new_arr[i] = int(f'{abs(x)}{e}{abs(y){n}'.replace('.', ''))
I agree with Iguananaut's comment that this data structure seems a bit odd. My biggest problem with it is that it is really tricky to try and vectorize the putting together of integers in a string and then re-converting that to an integer. Still, this will certainly help speed up the function:
def foo(arr):
x_values = arr[:,0]
y_values = arr[:,1]
ones = np.ones(arr.shape[0], dtype=np.uint64)
e = np.char.array(np.where(x_values < 0, ones, ones * 2))
n = np.char.array(np.where(y_values < 0, ones * 3, ones * 4))
x_values = np.char.array(np.absolute(x_values))
y_values = np.char.array(np.absolute(y_values))
x_values = np.char.replace(x_values, '.', '')
y_values = np.char.replace(y_values, '.', '')
new_arr = np.char.add(np.char.add(x_values, e), np.char.add(y_values, n))
return new_arr.astype(np.uint64)
Here, the x and y values of the input array are first split up. Then we use a vectorized computation to determine where e and n should be 1 or 2, 3 or 4. The last line uses a standard list comprehension to do the string merging bit, which is still undesirably slow for super large arrays but faster than a regular for loop. Also vectorizing the previous computations should speed the function up hugely.
Edit:
I was mistaken before. Numpy does have a nice way of handling string concatenation using the np.char.add() method. This requires converting x_values and y_values to Numpy character arrays using np.char.array(). Also for some reason, the np.char.add() method only takes two arrays as inputs, so it is necessary to first concatenate x_values and e and y_values and n and then concatenate these results. Still, this vectorizes the computations and should be pretty fast. The code is still a bit clunky because of the rather odd operation you are after, but I think this will help you speed up the function greatly.
You may use np.apply_along_axis. When you feed this function with another function that takes row (or column) as an argument, it does what you want to do.
For you case, You may rewrite the function as below:
def foo(row):
x, y = row
e, n = ''
if x < 0:
e = '1'
else:
w = '2'
if y > 0:
n = '3'
else:
s = '4'
return int(f'{abs(x)}{e}{abs(y){n}'.replace('.', ''))
# Where you want to you use it.
new_arr = np.apply_along_axis(foo, 1, n)

An array of floats giving a numpy.ndarray object

This is a followup question from the one I posted a few minutes ago. The problem I was having with multiplying int with float is fixed, thanks to user2357112 in the comments. However, it's come across another roadblock.
Code:
from __future__ import division
from fractions import Fraction
import numpy as np
from numpy import linalg as LA
def gcd(m,n):
if m < n:
return gcd(n,m)
return gcd(n,m%n)
def lcm(m,n):
return (m*n)/(gcd(m,n))
def answer(m):
tbd = []
l = len(m)
for i in range(l):
s = sum(m[i])
if s == 0:
tbd.append(i)
m[i][i] = 1
else:
for j in range(l):
m[i][j] /= s
tbd.sort(reverse=True)
a = np.array(m)
r = np.diag([1.0 for x in range(l)])
for i in range(100):
r *= a
initial = [0 for x in range(l)]
initial[0] = 1
final = initial * r
for i in tbd:
del final[i]
dens = []
for i in range(len(final)):
final[i] = final[i].limit_denominator()
dens.append(final[i].denominator)
lc = dens[0]
for j in range(1,len(dens)):
lc = lcm(lc,dens[j])
for i in range(len(final)):
final[i] = int(final[i] * lc)
final.append(lc)
return final
def main():
print answer([[1,2],[2,1]])
print answer([[0,1,0,0,0,1],[4,0,0,3,2,0],[0,0,0,0,0,0],[0,0,0,0,0,0],[0,0,0,0,0,0],[0,0,0,0,0,0]])
main()
Code in ideone: http://ideone.com/DO1otS
Error:
Traceback (most recent call last):
File "prog.py", line 51, in <module>
File "prog.py", line 48, in main
File "prog.py", line 37, in answer
AttributeError: 'numpy.ndarray' object has no attribute 'limit_denominator'
I am confused about why final[i] was recognized as a numpy.ndarray object. I thought that, since final is a 1-dimensional array, final[i] will therefore return the value (a float) within that array at index i. I'm not sure why that is not the case. Thank you in advance!
This is the answer to your question "I am confused about why final[i] was recognized as a numpy.ndarray object." In the following snippet of code
r = np.diag([1.0 for x in range(l)])
initial = [0 for x in range(l)]
final = initial * r
I skipped non-essential code. The code above shows that r is a numpy.ndarray and initial is a list. Then final is a product of a numpy.ndarray and a list. The result of this product is a numpy.ndarray.
What is also important is that r is an array of floats. Therefore final is also an array of floats and not fraction objects. Therefore you cannot call limit_denominator() on elements of final.
In addition, code such as:
for i in tbd:
del final[i]
looks quite suspicious.

Sum of column if not a square matirx in numpy?

a=np.array([[1,2,3],[1]])
print(np.sum(a,axis=1))
I am assuming that a matrix will be like
[1,2,3]
[1]
Not very general, because it only works if the first line is the longest, but you can simply stick your array into an array of zeros.
For example:
a = np.array([[1,2,3],[4,5]])
dim_x = len(a[0])
dim_y = a.shape[0]
a0 = np.zeros((dim_y, dim_x))
for i in range(dim_y):
dim = len(a[i])
a0[i,0:dim] = a[i]

'int' object has no attribute '__getitem__' Python

My code is method of Euller for second ODE. I already try to do a function to define f this way
{def inicial():
global f
f=matrix(M,N)}
But I had problem in the same line. I don't know how to recognize my function in that line.
N=101
x_min = -10.0
x_max = 10.0;
dx = (x_max - x_min)/(N-1)
dt = 0.25*dx*dx
t=0
t_max = 1000
Q=1
j=0
M=2
f = [N , M]
def f_xx(i,t):
return ((f[i+1][t]-2*f[i][t]+f[i-1][t])/(dx*dx))
def guess(x):
return ((pi*Q/x_max)*x +(pi*Q))
for i in range (N):
for j in range(j):
x = x_min + i*dx
f[i][j] = guess(x)
for j in range(t_max+1):
for i in range(N-1):
x = x_min + i*dx
f[i][j+1] = f[i][j]+(f_xx(i,j)-sin(f[i][j]))*dt <<<error
for i in range (N-1):
f[i][j] = f[i][j+1]
What does mean 'int' object has no attribute getitem? Could anyone help fix it?
f is a list containing two ints. f[i] refers to the the i'th int; so f[i][j], will try and get the j'th value of an int, which cannot possibly work, whatever the value of j.
It's not clear what you are trying to do with this call, though.
You are trying to use f as a list of lists (i.e. like a 2-dimensional array), but it's really just one list: [101, 2].
I'm rusty on ODEs but I think you were trying to create a 101x2 grid of 0s. If so try f = [[0.0]*M for x in range(N)].

mean of elements i and i+1 in a numpy array

Out of curiosity, is there a specific numpy function to do the following (which would supposedly be faster):
a = np.array((0,2,4))
b = np.zeros(len(a) - 1)
for i in range(len(b)):
b[i] = a[i:i+2].mean()
print(b)
#prints [1,3]
Cheers
You could use
b = (a[1:] + a[:-1]) / 2.
to avoid the Python loop.

Categories

Resources