The neighbours() Function - python

I am working on a new question. How am I supposed to develop the a solution for the following:
The neighbors() Function
In a 2D array, each element has up to eight neighbors - the cells immediately to the north, east, west, south, northeast, northwest, southeast, and southwest of it. Of course, elements on the boundary of the array have fewer neighbors (entries at the four corners only have three neighbors). Your task is to write a function called neighbors() that takes a 2D array named input, a row index, and a column index as input and returns the number of neighbors of array[row][column] that are 1's.
For example, if the 2D input array is
array = [ [0, 0, 0, 0], [1, 1, 0, 1], [0, 0, 0, 1] ]
representing the array
0__0__0__0
1__1__0__1
0__0__0__1
then here are some examples of the function being used:
>>> neighbors(array, 1, 1)
1
>>> neighbors(array, 2, 2)
3

Related

numpy vectorization of cellular automata

Trying to optimize my current implementation of a program that generates cellular automata using Wolfram Numbering. I am having trouble applying the rule to the board after calculating the neighbors for each cell. The current example uses 2 states and is the same as Conway's Game of Life, but my program can do any number of states. The decimal 224 corresponds to the ruleset for CGOL in the following way:
[0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0]
Basically, there are 18 positions, or nine possible neighborhood sums for each state (0-8).
If the current cell is 1, you index into the rule in the following way:
>>> [0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0][1::2]
[0, 0, 1, 1, 0, 0, 0, 0, 0]
1 being the value of the cell, and 2 being the number of states. As you can see, if the state is 1, then if there are 2 or 3 neighbors the cell survives, else dies. From there you index w/ the neighborhood sum for that cell to get the actual update value of the cell. So to update a cell in each generation you do: Rule[state_value::total_states][sum of neighbors].
E.g.,
>>> [0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0][1::2][2]
1
Currently then, I have the grid of all cells, called world, of an arbitrary shape, another equally shaped numpy array that has the sum of all the neighbors for each of those cells calculated using convolve from scipy - call it nbrs -, and the previously mentioned list for the rule - is it possible to update the value of each cell in world while avoiding a for loop?
For instance:
world = rule[cell_value::total_states][sum_of_neighbors_for_given_cell_in_nbrs]
You haven't given us a lot of code to work with, so here is a minimal idea of how it could work.
First, create an array that you can index with the current state to get the rule:
rule = [0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0]
rule_map = np.stack((rule[0::2], rule[1::2]), axis=0)
Now you can use your current states to get the rule for each cell:
world = np.random.randint(2, size=(5, 6))
cur_cell_rules = rule_map[world] # shape: (5, 6, 9)
To get the new world state, we can use index interators. Here, I use an array containing all world indices to first get the (flattened) current cell neighborhood sums, and then use those to get the (flattened) new states. In the assignment, I unflatten it again to the world shape. (There probably is an easier way to do this...)
cur_cell_neighborhood_sum = ... # shape: (5, 6)
world_ind = np.asarray([*np.ndindex(world.shape)])
# update world
world[world_ind[:, 0], world_ind[:, 1]] = cur_cell_rules[world_ind[:, 0], world_ind[:, 1], cur_cell_neighborhood_sum[world_ind[:, 0], world_ind[:, 1]]]
Edit:
To avoid the large cur_cell_rules array, you can go the other way, too:
world_potential = rule_map[:, cur_cell_neighborhood_sum] # shape: (2, 5, 6)
# update world, this time in smaller steps
world_flat = world[world_ind[:, 0], world_ind[:, 1]]
world_new_flat = world_potential[world_flat, world_ind[:, 0], world_ind[:, 1]]
world[world_ind[:, 0], world_ind[:, 1]] = world_new_flat

Numpy "Place Object" in Array

I have a program where I am trying to generate outputs based on a few IO's--like these two IOs.
The program recognizes objects in the grids, and it represents the grids as numpy arrays. Is there a built in numpy function, or elegant solution, to 'inserting' an object into a numpy array?
Ex: if it recognizes a square object, like [[1, 1], [1, 1]], and I have a grid [[0, 0, 0], [0, 0, 0], [0, 0, 0]], how can I insert the object into the grid so it becomes [[0, 1, 1], [0, 1, 1], [0, 0, 0]] (but for any object inserted at any index)?
There is no way other than knowing the indices at which to change the value of your 2-D numpy array.
So if your grid is a 2-D array of zeros like:
grid = np.zeros((10, 10))
Then you can use a tuple of indices tuples (x, y), each identifying a cell of your grid at which you want to change the grid value:
indices = ((x1, y1), (x2, y2), ..., (xn, yn))
then you can use it to assign values in your 2-D numpy array like so:
grid[indices] = 1

Trying to extract a patch given 8 points from NumPy array

I have an array which looks like this
boxes = [268,885,426,865,406,707,248,727]
It's a collection of (x,y) points. If I plot this using this function:
def draw_boxes_on_image_mod(image, boxes):
image_copy = image.copy()
image_copy = np.array(image_copy)
cv2.line(image_copy, (boxes[0],boxes[1]),(boxes[2],boxes[3]),(0,255,255),2)
cv2.line(image_copy, (boxes[4], boxes[5]),(boxes[6],boxes[7]),(0,255,255),2)
cv2.line(image_copy, (boxes[0],boxes[1]),(boxes[6],boxes[7]),(0,255,255),2)
cv2.line(image_copy, (boxes[4], boxes[5]),(boxes[2],boxes[3]),(0,255,255),2)
scipy. misc.imsave('/home/ryan/TEST.png', image_copy)
return image_copy
I get an image with a rectangle drawn on the part of the image I'm interested in, But what I want is to extract that portion and convert it into an image.
I was thinking of using NumPy indexing to achieve this but
image = image[268:426]
I am finding it difficult to understand how to index the (x,y) values together.
Any suggestions would be really helpful.Thanks in advance.
When you just call A[1:3] all you are asking for are the rows 1 and 2, the rows including 1 and stopping before 3, so you must take into account columns as well to get the exact subsection you need.
You can do this in numpy by stating the range of the rows and columns, the subsection of the array you want will start at a row and end at row + m as well as starting at a column and ending at column + n
For example take
A = np.array([[0, 0, 0, 0],
[0, 1, 1, 0],
[0, 1, 1, 0],
[0, 0, 0, 0]])
We want just the values in the middle set to 1, so we select them with
Asub = A[1:3,1:3]
To get
[[1 1]
[1 1]]

Is it possible to use numpy to replace this for loop?

I'm trying to speed up a function that evaluates the fitness of a solution, the idea is to apply a for loop in an array, is it possible to do this with np.sum ?
def calculate_fitness2(individual):
fitness=0
for i in range(0,len(individual)-1):
fitness=fitness+sp.spatial.distance.euclidean(city_list[individual][i][1:],city_list[individual][i+1][1:])
return fitness
individual is an array of ids ex.[1,5,3,4,6,7] , each of these is represented on the city list, the city list, this list includes the coordinates of the cities, ex . [[1,34,55],[2,44,78],...,[7,99,23]]. The main idea is to calculate the distance on a TSP problem.
Thank you all
Assuming you want the total distance traveled by going city to city according to the individual list, one way to write it is:
city_list = np.array([[0, 0], [1, 0], [1, 1], [0, 1]])
path_idx = [0, 1, 2, 3] # i.e. individual
polyline = city_list[path_idx] # the list of visited coordinates
# a (n x dim) array
distance = np.sum(np.sqrt(np.sum(np.diff(polyline, axis=0)**2, axis=1)))
distance # 3.0

Create matrix with same in and out degree for all nodes

I've stated this question in graph theory terms, but that conceptualization isn't necessary.
What I'm trying to do, using Python, is produce a matrix of zeros and ones, where every row has the same number of ones and every column has the same number of ones. The number for rows will not be the same as the number for columns when the number of rows (sending nodes) does not equal the number of columns (receiving nodes) -- which is something I'm allowing.
It makes sense to me to do this in numpy, but there may be other packages (like networkx?) that would help.
Here's the function I'm looking to write with the desired inputs and outputs:
n_pre = 4 # number of nodes available to send a connection
n_post = 4 # number of nodes available to receive a connection
p = 0.5 # proportion of all possible connections that exist
mat = generate_mat(n_pre, n_post, p)
print mat
The output would be, for example:
[[0, 1, 0, 1],
[1, 0, 1, 0],
[1, 1, 0, 0],
[0, 0, 1, 1]]
Notice, every column and every row has two ones in it. Aside from this constraint, the positions of the ones should be random (and vary from call to call of this function).
In graph theory terms, this means every node has an in-degree of 2 and an out-degree of 2 (50% of all possible connections, as specified with p = 0.5).
For a square matrix, what you describe is the adjacency matrix of a random k-regular directed graph, and there are known algorithms to generate such graphs. igraph implements one:
# I think this is how you call it - it's an instance method for some reason.
igraph.Graph().K_Regular(n, k, directed=True)
networkx has a function for random k-regular undirected graphs:
networkx.random_regular_graph(k, n)
For a non-square matrix, what you describe is isomorphic to a random biregular graph. I have found no convenient existing implementation for random biregular graphs, but the term should be a good starting point for searching for known algorithms.
First, do the pre-work so that we have available the size of the square matrix and the population pop of each row and column. Now, initialize a matrix with pop ones on the diagonal. For n = 6 and pop = 3, you'd have
[[1, 1, 1, 0, 0, 0]
[0, 1, 1, 1, 0, 0]
[0, 0, 1, 1, 1, 0]
[0, 0, 0, 1, 1, 1]
[1, 0, 0, 0, 1, 1]
[1, 1, 0, 0, 0, 1]]
Now, apply your friendly neighborhood random shuffle operation to the columns, then the rows (or in the other order). There's your matrix. A shuffle of rows-only or columns-only does not change the population on either axis.

Categories