Forming array from for loop output - python

I have the following
import math
import matplotlib.pyplot as plt
def nraphson(fn, dfn, x, tol, maxiter):
for i in range(maxiter):
xnew = x - fn(x)/dfn(x)
if abs(xnew - x) < tol: break
x = xnew
return xnew, i
y = lambda x: math.exp(x) - x**2
dy = lambda x: math.exp(x) - 2*x
x, n = nraphson(y, dy, j, 10**-5, 100)
guess = range(-10,6)
for j in guess:
print(nraphson(y, dy, j, 10**-5, 100))
my output is of the form
(-0.7034674225098828, 6)
(-0.7034674224990228, 6)
(-0.7034674224984084, 6)
(-0.7034674224983918, 6)
(-0.7034674224983917, 6)
(-0.703467422509882, 5)
(-0.7034674224984084, 5)
(-0.7034674224983917, 5)
(-0.7034674224984067, 4)
(-0.7034674224983924, 3)
(-0.7034674224983924, 4)
(-0.7034674224983917, 5)
(-0.7034674224983917, 6)
(-0.7034674224983917, 6)
(-0.7034674224984245, 8)
(-0.7034674224983917, 10)
I am attempting to isolate the second number from my output to form a list or array to us to plot a graph, how can I adjust my code as to give me a list or array like the following?
[6, 6, 6, 6, 6, 5, 5, 5, 4, 3, 4, 5, 6, 6, 8, 10]

Try this:
...
guess = range(-10,6)
result = [nraphson(y, dy, j, 10**-5, 100)[1] for j in guess]
print(result)

If you just want to print the second values, in the for loop at the end:
for j in guess:
print(nraphson(y, dy, j, 10**-5, 100)[1])
In your code you were printing the result of nraphson(y, dy, j, 10**-5, 100), which is a tuple with two elements. To get the second element, just access it with [1].
If you don't want to print the values but want to create a list with those values, simply do something like this:
tuples = [nraphson(y, dy, j, 10**-5, 100) for j in guess]
second_nums = [t[1] for t in tuples]

Replace the last two lines of your code with this:
L = [nraphson(y, dy, j, 10**-5, 100)[1] for j in guess]
print(L)

Related

Find three numbers with a given sum and product

Is it possible to write a Python program to find three numbers whose sum and product are given by the user? For example, 3 + 3 + 5 = 11 and 3 × 3 × 5 = 45, so if I give it 11 and 45, it should return (3, 3, 5).
The caveman approach (brute force with a miniscule amount of dynamic programming). MiTriPy's answer generalizes to n variables, although probably isn't more performant.
def solve(eqsum, eqprod):
solution_count = 0
for x in range(1, eqsum+1):
for y in range(1, eqsum+1-x):
for z in range(1, eqsum+1-x-y):
if x+y+z == eqsum:
if x*y*z == eqprod:
print(f"x={x} y={y} z={z}")
solution_count += 1
print(f"Found {solution_count} solutions.");
solve(eqsum=11, eqprod=45)
Made something fast and very clumsy:
import itertools
from numpy import prod
def find_subset_of_numbers(number, product):
subset_of_numbers = [x for x in range(1, number + 1)]
for x in range(1, number+1):
subset_of_numbers.append(x)
for x in range(1, number+1):
subset_of_numbers.append(x)
result = [seq for i in range(3, 0, -1)
for seq in itertools.combinations(subset_of_numbers, i)
if sum(seq) == number and len(seq) == 3 and prod(seq) == product]
return result
This will not handle duplicates very well but you could add another check for that:
print(find_subset_of_numbers(11, 45))
output: [(3, 5, 3), (3, 5, 3), (3, 3, 5), (3, 3, 5), (3, 5, 3), (3, 3, 5), (5, 3, 3), (3, 5, 3), (3, 3, 5)]
Here is a fairly efficient solution.
from collections.abc import Iterator
from math import sqrt
def solve(target_sum: int, target_prod: int) -> Iterator[tuple[int, int, int]]:
for x in range(1, target_sum):
if target_prod % x:
continue
midpoint = (target_sum - x) / 2
try:
radius = sqrt(midpoint ** 2 - target_prod // x)
except ValueError:
continue
y = midpoint + radius
if y.is_integer():
y = int(y)
z = int(midpoint - radius)
yield (x, y, z)
yield (x, y, z)
It uses the fact that if x + y = 2m and xy = p, then {x, y} = {m ± √(m² − p)}.

Is it possible to reshape a Python array stacked in one way into another stacked type? [duplicate]

This question already has answers here:
How do I re-shape an array with shape(band,row,column) to (row,column,band)?
(2 answers)
Closed 4 years ago.
I have this array:
import numpy as np
shape = (3, 2, 2)
x = np.round(np.random.rand(*shape) * 100)
y = np.round(np.random.rand(*shape) * 100)
z = np.round(np.random.rand(*shape) * 100)
w = np.round(np.random.rand(*shape) * 100)
first_stacked = np.stack((x, y, z, w), axis=0)
print(first_stacked.shape) # (4, 3, 2, 2)
And I want to convert into this array:
import numpy as np
shape = (3, 2, 2)
x = np.round(np.random.rand(*shape) * 100)
y = np.round(np.random.rand(*shape) * 100)
z = np.round(np.random.rand(*shape) * 100)
w = np.round(np.random.rand(*shape) * 100)
last_stacked = np.stack((x, y, z, w), axis=-1)
print(last_stacked.shape) # (3, 2, 2, 4)
I tried this:
new_stacked = [i for i in first_stacked]
new_stacked = np.stack(new_stacked, axis=-1)
other_stacked = np.stack(first_stacked, axis=-1)
print(new_stacked.shape)
print(other_stacked.shape)
print(np.array_equal(new_stacked, last_stacked))
print(np.array_equal(new_stacked, other_stacked))
Output:
(3, 2, 2, 4)
(3, 2, 2, 4)
False
True
So neither of my two attempts work. What am I missing? Can it be done with just a reshape on the first_stacked? I worry if my arrays are too big, if it's more than a reshape, it could be a problem, though maybe my fears are unfounded.
Edit: I was randomizing the x,y,z,w arrays twice in the Jupyter Notebook and the second values were obviously not equal to the first. I apologize. Though if there's a better way to do it, I'm still interested.
So, the working code:
import numpy as np
shape = (3, 2, 2)
x = np.round(np.random.rand(*shape) * 100)
y = np.round(np.random.rand(*shape) * 100)
z = np.round(np.random.rand(*shape) * 100)
w = np.round(np.random.rand(*shape) * 100)
first_stacked = np.stack((x, y, z, w), axis=0)
print(first_stacked.shape)
last_stacked = np.stack((x, y, z, w), axis=-1)
print(last_stacked.shape)
new_stacked = [i for i in first_stacked]
new_stacked = np.stack(new_stacked, axis=-1)
other_stacked = np.stack(first_stacked, axis=-1)
print(new_stacked.shape)
print(other_stacked.shape)
print(np.array_equal(new_stacked, last_stacked))
print(np.array_equal(new_stacked, other_stacked))
Output:
(4, 3, 2, 2)
(3, 2, 2, 4)
(3, 2, 2, 4)
(3, 2, 2, 4)
True
True
You can use numpy.moveaxis to move the first axis to the last position.
np.moveaxis(first_stacked, 0, -1)
Or you can roll the axis into the desired position
np.rollaxis(first_stacked, 0, first_stacked.ndim)

Connecting just a piece of number array in matplotlib

Given a 3D scatter plot with 7 points. These 7 points, geometrically make a double tetrahedron. I am able to connect all of the bottom points(z=0) to the apex(z=4/3 * sqrt(3)).
The base is made two triangles that have a common centroid(middle point), which is directly under the apex.
How do I outline the two triangles that make up the base?
In my number arrays, the points for the base would be [index0,1,2] for the first triangle and [index3,4,5] for the second and the [index7] would be the apex of the double pyramid(tetrahedron).
The image below shows what I would like to see. The missing lines are in red.
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
import math as m
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
tr = m.sqrt(3.)
sx = m.sqrt(6.)
x = np.array([4.,2.,6.,4.,6.,2.,4.])
y = np.array([1.,1.+2*tr,1.+2*tr,1+(8*tr)/3,1+(2*tr)/3,1+(2*tr)/3,1+(4*tr)/3])
z = np.array([0.,0.,0.,0.,0.,0.,(4*sx)/3])
ax.scatter(x,y,zs = z, s=100)
for r, s, t in zip(x, y, z):
X = np.array([r, 4.])
Y = np.array( [s, 1+(4*tr)/3])
Z = np.array([t, (4*sx)/3])
ax.plot3D(X, Y, Z, 'b')
ax.set_ylim([0,8])
ax.set_xlim([8,0])
ax.set_zlim([0,8])
plt.show()
Some Code:
To plot the missing vertices:
for index in range(6):
import math
next_idx = (index+1) % 3 + math.floor(index / 3) * 3
X = (x[index], x[next_idx])
Y = (y[index], y[next_idx])
Z = (z[index], z[next_idx])
ax.plot3D(X, Y, Z, 'r')
A Small Explanation:
The operative code is:
next_idx = (index+1) % 3 + math.floor(index / 3) * 3
this uses the fact that the data comes in triads. It selects the next index based on the current index plus one but staying in a group of 3. This effectively chooses all three elements of the triangles, in all possible sequences.
This works because (index+1) % 3 will only take the values 0, 1, 2, while math.floor(index / 3) * 3 takes the values 0, 3, 6.... So it ends up being:
index, next_idx
0 1
1 2
2 0
3 4
4 5
5 3
Alternate Ending:
This can also be done without the loop, using a list comprehension:
X = [x[i] for i in (0, 1, 2, 0)]
Y = [y[i] for i in (0, 1, 2, 0)]
Z = [z[i] for i in (0, 1, 2, 0)]
ax.plot3D(X, Y, Z, 'r')
X = [x[i] for i in (3, 4, 5, 3)]
Y = [y[i] for i in (3, 4, 5, 3)]
Z = [z[i] for i in (3, 4, 5, 3)]
ax.plot3D(X, Y, Z, 'r')
Picture:

numpy iterate over two 2d arrays

Say I have two matrices:
X, Y = np.meshgrid(np.arange(0, 2, 0.1), np.arange(3, 5, 0.1))
And a function, something like:
def func(x) :
return x[0]**2 + x[1]**2
How can I fill a matrix Z (of size np.shape(X)), where each entry is formed by calling func on the two corresponding values of X and Y, i.e.:
Z[i, j] = func([X[i, j], Y[i, j]])
Is there a way without using a double nested for-loop?
This is also works as a vectorized form of function evaluation:
import numpy as np
X, Y = np.meshgrid(np.arange(0, 2, 0.1), np.arange(3, 5, 0.1))
def func(x) :
return x[0]**2 + x[1]**2
Z = func([X,Y])
For given numpy arrays X and Y, you could just do -
Zout = X**2 + Y**2
If you are actually constructing X and Y like that, there is a direct way to get Z with broadcasting and thus avoid np.meshgrid, like so -
Zout = np.arange(0, 2, 0.1)**2 + np.arange(3, 5, 0.1)[:,None]**2

Determining neighbours of cell two dimensional list

I have a list of lists, something like
[[1, 2, 3,],[4, 5, 6,],[7, 8, 9]].
Represented graphically as:
1 2 3
4 5 6
7 8 9
I'm looking for an elegant approach to check the value of neighbours of a cell, horizontally, vertically and diagonally. For instance, the neighbours of [0][2] are [0][1], [1][1] and [1][2] or the numbers 2, 5, 6.
Now I realise, I could just do a bruteforce attack checking every value a la:
[i-1][j]
[i][j-1]
[i-1][j-1]
[i+1][j]
[i][j+1]
[i+1][j+1]
[i+1][j-1]
[i-1][j+1]
But thats easy, and I figured I can learn more by seeing some more elegant approaches.
# Size of "board"
X = 10
Y = 10
neighbors = lambda x, y : [(x2, y2) for x2 in range(x-1, x+2)
for y2 in range(y-1, y+2)
if (-1 < x <= X and
-1 < y <= Y and
(x != x2 or y != y2) and
(0 <= x2 <= X) and
(0 <= y2 <= Y))]
>>> print(neighbors(5, 5))
[(4, 4), (4, 5), (4, 6), (5, 4), (5, 6), (6, 4), (6, 5), (6, 6)]
I don't know if this is considered clean, but this one-liner gives you all neighbors by iterating over them and discarding any edge cases.
Assuming you have a square matrix:
from itertools import product
size = 3
def neighbours(cell):
for c in product(*(range(n-1, n+2) for n in cell)):
if c != cell and all(0 <= n < size for n in c):
yield c
Using itertools.product and thanks to Python's yield expression and star operator, the function is pretty dry but still readable enough.
Given a matrix size of 3, you can then (if needed) collect the neighbours in a list:
>>> list(neighbours((2,2)))
[(1, 1), (1, 2), (2, 1)]
What the function does can be visualized as follows:
mb...
from itertools import product, starmap
x, y = (8, 13)
cells = starmap(lambda a,b: (x+a, y+b), product((0,-1,+1), (0,-1,+1)))
// [(8, 12), (8, 14), (7, 13), (7, 12), (7, 14), (9, 13), (9, 12), (9, 14)]
print(list(cells)[1:])
for x_ in range(max(0,x-1),min(height,x+2)):
for y_ in range(max(0,y-1),min(width,y+2)):
if (x,y)==(x_,y_): continue
# do stuff with the neighbours
>>> a=[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> width=height=3
>>> x,y=0,2
>>> for x_ in range(max(0,x-1),min(height,x+2)):
... for y_ in range(max(0,y-1),min(width,y+2)):
... if (x,y)==(x_,y_): continue
... print a[x_][y_]
...
2
5
6
If someone is curious about alternative way to pick direct (non-diagonal) neighbors, here you go:
neighbors = [(x+a[0], y+a[1]) for a in
[(-1,0), (1,0), (0,-1), (0,1)]
if ( (0 <= x+a[0] < w) and (0 <= y+a[1] < h))]
There's no cleaner way to do this. If you really want you could create a function:
def top(matrix, x, y):
try:
return matrix[x][y - 1];
except IndexError:
return None
Here is your list:
(x - 1, y - 1) (x, y - 1) (x + 1, y - 1)
(x - 1, y) (x, y) (x + 1, y)
(x - 1, y + 1) (x, y + 1) (x + 1, y + 1)
So the horizontal neighbors of (x, y) are (x +/- 1, y).
The vertical neighbors are (x, y +/- 1).
Diagonal neighbors are (x +/- 1, y +/- 1).
These rules apply for an infinite matrix.
To make sure the neighbors fit into a finite matrix, if the initial (x, y) is at the edge, just apply one more restriction to the coordinates of neighbors - the matrix size.
>>> import itertools
>>> def sl(lst, i, j):
il, iu = max(0, i-1), min(len(lst)-1, i+1)
jl, ju = max(0, j-1), min(len(lst[0])-1, j+1)
return (il, iu), (jl, ju)
>>> lst = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> tup = 0, 2
>>> [lst[i][j] for i, j in itertools.product(*sl(lst, *tup)) if (i, j) != tup]
[2, 5, 6]
I don't know how elegant it seems to you, but it seems to work w/o any hard-coding.
This generates all indices:
def neighboring( array ):
nn,mm = len(array), len(array[0])
offset = (0,-1,1) # 0 first so the current cell is the first in the gen
indices = ( (i,j) for i in range(nn) for j in range(mm) )
for i,j in indices:
all_neigh = ( (i+x,j+y) for x in offset for y in offset )
valid = ( (i,j) for i,j in all_neigh if (0<=i<nn) and (0<=j<mm) ) # -1 is a valid index in normal lists, but not here so throw it out
yield valid.next(), valid ## first is the current cell, next are the neightbors
for (x,y), neigh in neighboring( l ):
print l[x][y], [l[x][y] for x,y in neigh]
If lambdas daunt you here you are .But lambdas make your code look clean.#johniek_comp has a very clean solution TBH
k,l=(2,3)
x = (0,-1,+1)
y = (0,-1,+1)
cell_u = ((k+a,l+b) for a in x for b in y)
print(list(cell_u))
Inspired by one of the previous answers.
You can use min() and max() functions to shorten the calculations:
width = 3
height = 3
[(x2, y2) for x2 in range(max(0, x-1), min(width, x+2))
for y2 in range(max(0, y-1), min(height, y+2))
if (x2, y2) != (x, y)]
Thank you to #JS_is_bad for a great hint about the neighbors. Here is the running code for this problem:
def findNeighbours(l,elem):
#This try is for escaping from unbound error that happens
#when we try to iterate through indices that are not in array
try:
#Iterate through each item of multidimensional array using enumerate
for row,i in enumerate(l):
try:
#Identifying the column index of the givem element
column=i.index(elem)
except ValueError:
continue
x,y=row,column
# hn=list(((x,y+1),(x,y-1))) #horizontal neighbours=(x,y+/-1)
# vn=list(((x+1,y),(x-1,y))) #vertical neighbours=(x+/-1,y)
# dn=list(((x+1,y+1),(x-1,y-1),(x+1,y-1),(x-1,y+1))) #diagonal neighbours=(x+/-1,y+/-1)
#Creating a list with values that are actual neighbors for the extracted index of array
neighbours=[(x,y+1),(x,y-1),(x+1,y),(x-1,y),(x+1,y+1),(x-1,y-1),(x+1,y-1),(x-1,y+1)]
#Creating a universe of indices from given array
index_list=[(i,j) for i in range(len(l)) for j in range(len(l[i]))]
#Looping through index_list and nested loop for neighbours but filter for matched ones
# and extract the value of respective index
return_values=[l[index[0]][index[1]] for index in index_list for neighbour in neighbours if index==neighbour]
return return_values,neighbours
except UnboundLocalError:
return []
Inspired by johniek's answer here is my solution which also checks for boundaries.
def get_neighbours(node, grid_map):
row_index, col_index = node
height, width = len(grid_map), len(grid_map[0])
cells = list(starmap(lambda a, b: (row_index + a, col_index + b), product((0, -1, +1), (0, -1, +1))))
cells.pop(0) # do not include original node
cells = list(filter(lambda cell: cell[0] in range(height) and cell[1] in range(width), cells))
return cells
def numCells(grid):
x=len(grid)
y=len(grid[0])
c=0
for i in range(x):
for j in range(y):
value_=grid[i][j]
f=1
for i2 in range(max(0,i-1),min(x,i+2)):
for j2 in range(max(0,j-1),min(y,j+2)):
if (i2,j2) != (i,j) and value_<=grid[i2][j2]:
flag=0
break
if flag ==0:
break
else:
c+=1
return c
def getNeighbors(matrix: list, point: tuple):
neighbors = []
m = len(matrix)
n = len(matrix[0])
x, y = point
for i in range (x -1, x +2): #prev row to next row
for j in range(y - 1, y +2): #prev column to next col
if (0 <= i < m) and (0 <= j < n):
neighbors.append((i,j))
return neighbors
maybe you are checking a sudoku box. If the box is n x n and current cell is (x,y) start checking:
startingRow = x / n * n;
startingCol = y/ n * n

Categories