I am writing a program to find Isis rectangles based on a user input of n. The goal of the program is to run through the equation based on the input and output an array of dimensions for a rectangle where area == perimeter. I am new to NumPy and I'm struggling on finding an answer anywhere else.
Below is a chunk of my code that is responsible for outputting the array:
def choice_2():
n = int(input("Please enter a positive integer for n: "))
a1 = 2 * n +1
a2 = 4 * n
a = np.array(list(range(a1, a2+1)))
for j in range(a1, a2+1):
b = (2 * n * a)/(a - 2 * n)
print(f"\nIsis rectangles of type {n}")
print("----------------------------")
print(np.array(list(zip(a,b))))
And this is what my output is:
Isis rectangles of type 10
----------------------------
[[ 21. 420. ]
[ 22. 220. ]
[ 23. 153.33333333]
[ 24. 120. ]
[ 25. 100. ]
[ 26. 86.66666667]
[ 27. 77.14285714]
[ 28. 70. ]
[ 29. 64.44444444]
[ 30. 60. ]
[ 31. 56.36363636]
[ 32. 53.33333333]
[ 33. 50.76923077]
[ 34. 48.57142857]
[ 35. 46.66666667]
[ 36. 45. ]
[ 37. 43.52941176]
[ 38. 42.22222222]
[ 39. 41.05263158]
[ 40. 40. ]]
The math is working properly and it is zipping correctly, but I want to remove the rectangles that have float values. For example, the first rectangle with sides 21 and 420 is good, but the thrid rectangle with sides 23 and 153.33333333 is not something I want in the final array.
Find the indices which has integer values and filter a and b using this indices
idx = (b == b.astype(int)).nonzero()
print(np.array(list(zip(a[idx],b[idx]))))
Testcase:
n= 10
a1 = 2 * n +1
a2 = 4 * n
a = np.array(list(range(a1, a2+1)))
for j in range(a1, a2+1):
b = (2 * n * a)/(a - 2 * n)
print(f"\nIsis rectangles of type {n}")
print("----------------------------")
idx = (b == b.astype(int)).nonzero()
print(np.array(list(zip(a[idx],b[idx]))))
Output:
Isis rectangles of type 10
----------------------------
[[ 21. 420.]
[ 22. 220.]
[ 24. 120.]
[ 25. 100.]
[ 28. 70.]
[ 30. 60.]
[ 36. 45.]
[ 40. 40.]]
Related
Suppose that A is a three-dimensional matrix like the following:
A = [np.zeros((3, 8)) for _ in range(20)]
and B is a two-dimensional matrix that has 60 rows and 8 columns containing numbers. What should I do if I want to put numbers from matrix B into matrix A and use a loop to write code?
A[0][0] = B[0]
A[0][1] = B[1]
A[0][2] = B[2]
A[1][0] = B[3]
A[1][1] = B[4]
A[1][2] = B[5]
...
A[20][0] = B[58]
A[20][1] = B[59]
A[20][2] = B[60]
Thanks
I hope I've understood your question right. You can use .flat + indexing:
A = [np.zeros((3, 8)) for _ in range(20)]
B = np.arange(60 * 8).reshape(60, 8)
for i, subl in enumerate(A):
subl.flat[:] = B.flat[i * 3 * 8 :]
print(*A, sep="\n\n")
Prints:
[[ 0. 1. 2. 3. 4. 5. 6. 7.]
[ 8. 9. 10. 11. 12. 13. 14. 15.]
[16. 17. 18. 19. 20. 21. 22. 23.]]
[[24. 25. 26. 27. 28. 29. 30. 31.]
[32. 33. 34. 35. 36. 37. 38. 39.]
[40. 41. 42. 43. 44. 45. 46. 47.]]
...
I try to use recursive function on python, i have this matrix W:
[[ 13. 14. ]
[ 12. 15. ]
[ 0. 4. ]
[ 3. 6. ]
[ 7. 8. ]
[ 11. 18. ]
[ 10. 17. ]
[ 2. 23. ]
[ 5. 22. ]
[ 16. 19. ]
[ 1. 27. ]
[ 9. 21. ]
[ 25. 29. ]
[ 24. 28. ]
[ 20. 26. ]
[ 31. 32. ]
[ 30. 33. ]
[ 34. 35. ]
[ 36. 37. ]]
the principle that for each line, I get the values of the two columns, if they are <20 I return them, otherwise I do the modulo until I reach a value lower than 20. for example I have a value 35 which is> 20, so 35% 20 = 15, I go to line 15 I get the value, if I find it for example 11, I return 11, if I find it 23 for example, I redo the modulo 23% 20 = 3, I go to line 3 and so on .. this is my code
def modulo(entier):
if entier < 20:
return(entier)
else:
c = (entier % 20)
if int(W[c,0]) < 20:
return(int(W[c,0]))
else:
a = modulo(int(W[c,0]))
return(a)
if int(W[c,1]) < 20:
return(int(W[c,1]))
else:
e = modulo(int(W[c,1]))
return(e)
i = 12
print(modulo(int(W[i,0])), modulo(int(W[i,1])))
here I tried with line 12 of the matrix, which has both values 25 and 29, following the principle the function must return 11 and 18 for the value 25 and 16 and 19 for the value 29. but in the running, the program only displays two values 11 and 16. so I have the impression that it just points to the first column of the matrix, it does not read the second if condition. I hope I explained the problem well and I find a solution. Thank you
If I have, for example, an array of 5 * 5 that has as numbers the list from 1 to 25 such that:
X = list (range (1,26))
Dimension = 5
A = np.zeros ((dimension, dimension))
N = 0
For i in range (dimension):
For j in range (dimension):
A [i] [j] = x [n]
N = n + 1
And I want python tell me the column and row where this number 16, how is it done?
To find 16 in :
a = [[ 1. 2. 3. 4. 5.]
[ 6. 7. 8. 9. 10.]
[ 11. 12. 13. 14. 15.]
[ 16. 17. 18. 19. 20.]
[ 21. 22. 23. 24. 25.]]
Do:
np.where(a == 16)
Output:
(array([3]), array([0]))
Problem:
The input is a (i,j)-matrix M. The desired output is a (i^n,j^n) matrix K , where n is the number of products taken. The verbose way to get the desired output is as follows
Generate all arrays of n row permutations I (total of i**n n-arrays)
Generate all arrays of n column permutations J (total of j**n n-arrays)
K[i,j] = m[I[0],J[0]] * ... * m[I[n],J[n]] for all n in range(len(J))
The straightforward way I've done this is by generating a list of labels of all n-permutations of numbers in range(len(np.shape(m)[0])) and range(len(np.shape(m)[1])) for rows and columns, respectively. Afterwards you can multiply them as in the last bullet point above. This, however, is not practical for large input matrices -- so I'm looking for ways to optimize the above. Thank you in advance
Example:
Input
np.array([[1,2,3],[4,5,6]])
Output for n = 3
[[ 1. 2. 3. 2. 4. 6. 3. 6. 9. 2. 4. 6.
4. 8. 12. 6. 12. 18. 3. 6. 9. 6. 12. 18.
9. 18. 27.]
[ 4. 5. 6. 8. 10. 12. 12. 15. 18. 8. 10. 12.
16. 20. 24. 24. 30. 36. 12. 15. 18. 24. 30. 36.
36. 45. 54.]
[ 4. 8. 12. 5. 10. 15. 6. 12. 18. 8. 16. 24.
10. 20. 30. 12. 24. 36. 12. 24. 36. 15. 30. 45.
18. 36. 54.]
[ 16. 20. 24. 20. 25. 30. 24. 30. 36. 32. 40. 48.
40. 50. 60. 48. 60. 72. 48. 60. 72. 60. 75. 90.
72. 90. 108.]
[ 4. 8. 12. 8. 16. 24. 12. 24. 36. 5. 10. 15.
10. 20. 30. 15. 30. 45. 6. 12. 18. 12. 24. 36.
18. 36. 54.]
[ 16. 20. 24. 32. 40. 48. 48. 60. 72. 20. 25. 30.
40. 50. 60. 60. 75. 90. 24. 30. 36. 48. 60. 72.
72. 90. 108.]
[ 16. 32. 48. 20. 40. 60. 24. 48. 72. 20. 40. 60.
25. 50. 75. 30. 60. 90. 24. 48. 72. 30. 60. 90.
36. 72. 108.]
[ 64. 80. 96. 80. 100. 120. 96. 120. 144. 80. 100. 120.
100. 125. 150. 120. 150. 180. 96. 120. 144. 120. 150. 180.
144. 180. 216.]]
Partial solution:
The best I've found is a function to create the cartesian product of matrices proposed here: https://stackoverflow.com/a/1235363/4003747
The problem is that the output is not a matrix but an array of arrays. Multiplying the element of each array gives the values I'm after, but in an unordered fashion. I've tried for a while but I have no idea how to sensibly reorder them.
Inefficient solution for n =3:
import numpy as np
import itertools
m=np.array([[1,2,3],[4,5,6]])
def f(m):
labels_i = [list(p) for p in itertools.product(range(np.shape(m)[0]),repeat=3)]
labels_j = [list(p) for p in itertools.product(range(np.shape(m)[1]),repeat=3)]
out = np.zeros([len(labels_i),len(labels_j)])
for i in range(len(labels_i)):
for j in range(len(labels_j)):
out[i,j] = m[labels_i[i][0],labels_j[j][0]] * m[labels_i[i][1],labels_j[j][1]] * m[labels_i[i][2],labels_j[j][2]]
return out
Here's a vectorized approach using a combination of broadcasting and linear indexing -
from itertools import product
# Get input array's shape
r,c = A.shape
# Setup arrays corresponding to labels i and j
arr_i = np.array(list(product(range(r), repeat=n)))
arr_j = np.array(list(product(range(c), repeat=n)))
# Use linear indexing with ".ravel()" to extract elements.
# Perform elementwise product along the rows for the final output
out = A.ravel()[(arr_i*c)[:,None,:] + arr_j].prod(2)
Runtime test and output verification -
In [167]: # Inputs
...: n = 4
...: A = np.array([[1,2,3],[4,5,6]])
...:
...: def f(m):
...: labels_i = [list(p) for p in product(range(np.shape(m)[0]),repeat=n)]
...: labels_j = [list(p) for p in product(range(np.shape(m)[1]),repeat=n)]
...:
...: out = np.zeros([len(labels_i),len(labels_j)])
...: for i in range(len(labels_i)):
...: for j in range(len(labels_j)):
...: out[i,j] = m[labels_i[i][0],labels_j[j][0]] \
...: * m[labels_i[i][1],labels_j[j][1]] \
...: * m[labels_i[i][2],labels_j[j][2]] \
...: * m[labels_i[i][3],labels_j[j][3]]
...: return out
...:
...: def f_vectorized(A,n):
...: r,c = A.shape
...: arr_i = np.array(list(product(range(r), repeat=n)))
...: arr_j = np.array(list(product(range(c), repeat=n)))
...: return A.ravel()[(arr_i*c)[:,None,:] + arr_j].prod(2)
...:
In [168]: np.allclose(f_vectorized(A,n),f(A))
Out[168]: True
In [169]: %timeit f(A)
100 loops, best of 3: 2.37 ms per loop
In [170]: %timeit f_vectorized(A,n)
1000 loops, best of 3: 202 µs per loop
this should work:
import numpy as np
import itertools
m=np.array([[1,2,3],[4,5,6]])
n=3 # change your n here
def f(m):
labels_i = [list(p) for p in itertools.product(range(np.shape(m)[0]),repeat=n)]
labels_j = [list(p) for p in itertools.product(range(np.shape(m)[1]),repeat=n)]
out = np.zeros([len(labels_i),len(labels_j)])
for i in range(len(labels_i)):
for j in range(len(labels_j)):
out[i,j] = np.prod([m[labels_i[i][k],labels_j[j][k]] for k in range(n)])
return out
Say that I have a sparse matrix in scipy.sparse format. How can I extract a diagonal other than than the main diagonal? For a numpy array, you can use numpy.diag. Is there a scipy sparse equivalent?
For example:
from scipy import sparse
A = sparse.diags(ones(5),1)
How would I get back the vector of ones without converting to a numpy array?
When the sparse array is in dia format, the data along the diagonals is recorded in the offsets and data attributes:
import scipy.sparse as sparse
import numpy as np
def make_sparse_array():
A = np.arange(ncol*nrow).reshape(nrow, ncol)
row, col = zip(*np.ndindex(nrow, ncol))
val = A.ravel()
A = sparse.coo_matrix(
(val, (row, col)), shape=(nrow, ncol), dtype='float')
A = A.todia()
# A = sparse.diags(np.ones(5), 1)
# A = sparse.diags([np.ones(4),np.ones(3)*2,], [2,3])
print(A.toarray())
return A
nrow, ncol = 10, 5
A = make_sparse_array()
diags = {offset:(diag[offset:nrow+offset] if 0<=offset<=ncol else
diag if offset+nrow-ncol>=0 else
diag[:offset+nrow-ncol])
for offset, diag in zip(A.offsets, A.data)}
for offset, diag in sorted(diags.iteritems()):
print('{o}: {d}'.format(o=offset, d=diag))
Thus for the array
[[ 0. 1. 2. 3. 4.]
[ 5. 6. 7. 8. 9.]
[ 10. 11. 12. 13. 14.]
[ 15. 16. 17. 18. 19.]
[ 20. 21. 22. 23. 24.]
[ 25. 26. 27. 28. 29.]
[ 30. 31. 32. 33. 34.]
[ 35. 36. 37. 38. 39.]
[ 40. 41. 42. 43. 44.]
[ 45. 46. 47. 48. 49.]]
the code above yields
-9: [ 45.]
-8: [ 40. 46.]
-7: [ 35. 41. 47.]
-6: [ 30. 36. 42. 48.]
-5: [ 25. 31. 37. 43. 49.]
-4: [ 20. 26. 32. 38. 44.]
-3: [ 15. 21. 27. 33. 39.]
-2: [ 10. 16. 22. 28. 34.]
-1: [ 5. 11. 17. 23. 29.]
0: [ 0. 6. 12. 18. 24.]
1: [ 1. 7. 13. 19.]
2: [ 2. 8. 14.]
3: [ 3. 9.]
4: [ 4.]
The output above is printing the offset followed by the diagonal at that offset.
The code above should work for any sparse array. I used a fully populated sparse array only to make it easier to check that the output is correct.