Sl30202
Sl30202

Reputation: 5

Error in Python code for Schelling Segregation problem

I have a problem where I am supposed to model the Schelling Segregation problem using Python. I have been stuck on this for quite a while now, but I think my issue is that my neighbours aren't being swapped correctly from an unhappy agent into an empty agent.

**Scope of problem: ** We have a matrix with 0s and 1s and 2s. Os represent empty houses, 1s represent one type of ethnicity, 2s represent another ethnicity. If one ethnicity isn't happy with their fraction of neighbours (defined by self.par) being similar to them, they then become unhappy agents. These unhappy agents need to swapped to empty houses. This needs to reiterated over multiple time steps and the metric (i.e. frac_mean as defined by code below) should decrease as people become "happied"

However, my issue is that the frac mean metric is not showing a consistent patter of decrease.

** Things I have tried: ** The main thing I tried was instead of making the swaps in the original self.array, I made a copy of it and made all swaps on that, then equated it to the original self array as seen by the second last line of the code.

Any help would be appreciated:

class Schelling():
    kernel = [[1,1,1],[1,0,1],[1,1,1]]
    #par = 0.3
    
    def __init__(self, n, par=0.3):
        self.par=par
        probs = [0.1, 0.45, 0.45]
        choices = [0, 1, 2]
        self.array = np.random.choice(choices, (n, n), p=probs)

    def count_neighbours(self):
        a = self.array
        
        empty = a == 0
        red = a == 1
        blue = a == 2

        num_red = correlate2d(red, self.kernel, mode='same', boundary='wrap')
        num_blue = correlate2d(blue, self.kernel, mode='same', boundary='wrap')
        num_neighbours = num_red + num_blue

        frac_red = num_red / num_neighbours
        frac_blue = num_blue / num_neighbours

        frac_red[num_neighbours == 0] = 0
        frac_blue[num_neighbours == 0] = 0

        # Nice way to do a vector if-else application
        frac_same = np.where(red, frac_red, frac_blue)

        # Because only if-else, empty will have frac_blue, so we need to correct this
        frac_same[empty] = np.nan

        return empty, frac_red, frac_blue, frac_same, a
    
    def step(self):
        empty, frac_red, frac_blue, frac_same, count_neighbours_list = self.count_neighbours()
        metric=np.nanmean(frac_same)
        unhappy_address = list(zip(*np.array(np.nonzero(frac_same < self.par))))
        np.random.shuffle(unhappy_address)
        empty_address = list(zip(*np.array(np.nonzero(empty))))

        
        # Perform swaps until no more swaps are possible
        unhappy_copy=unhappy_address.copy()
        empty_copy=empty_address.copy()
        
        ind=len(unhappy_copy)
        
        #ind=min(len(unhappy_address), len(empty_address))
        for i in range(ind):
            #adding a check: 
            #add in a break: for the value of i if its greater than len-1 of empty_address, then break  
            if i == len(empty_address):
                
                break
                
            else:
            
                unhappy_tup_req=unhappy_copy[i]
                emp_tup_req=empty_copy[i]
                
                #count_neighbours_list[emp_tup_req]=count_neighbours_list[unhappy_tup_req]
                #count_neighbours_list[unhappy_tup_req]==0
                
                count_neighbours_list[emp_tup_req], count_neighbours_list[unhappy_tup_req] = count_neighbours_list[unhappy_tup_req], count_neighbours_list[emp_tup_req]

            
        self.array= count_neighbours_list
                

        return unhappy_address, empty_address, count_neighbours_list, metric


Upvotes: 0

Views: 137

Answers (1)

David
David

Reputation: 1

Here are some things you can try:

  1. Make sure that you are correctly identifying the unhappy agents. You can do this by looping through the array and checking if the fraction of neighbors of each agent is less than the similarity threshold.
  2. Once you have identified the unhappy agents, you need to find an empty house for them to move to. You can do this by looping through the array and checking if any of the houses are empty.
  3. Once you have found an empty house for an unhappy agent, you need to swap the agent with the occupant of the empty house. You can do this by using the swap function.
  4. Once you have swapped the agent with the occupant of the empty house, you need to update the array to reflect the change. You can do this by using the update function.
  5. Repeat steps 1-4 until no more unhappy agents are found.

Here is an example of how you can implement the above steps in Python:

def schelling_segregation(array, similarity_threshold):
  """
  This function implements the Schelling segregation model.

  Args:
    array: A 2D array representing the city.
    similarity_threshold: The threshold that is used to determine if an agent is happy.

  Returns:
    A 2D array representing the final state of the city.
  """

  # Initialize the list of unhappy agents.
  unhappy_agents = []

  # Loop through the array and identify the unhappy agents.
  for i in range(len(array)):
    for j in range(len(array[0])):
      if array[i][j] != 0:
        fraction_of_neighbors = 0
        for neighbor in [(i - 1, j), (i + 1, j), (i, j - 1), (i, j + 1)]:
          if 0 <= neighbor[0] < len(array) and 0 <= neighbor[1] < len(array[0]):
            if array[neighbor[0]][neighbor[1]] == array[i][j]:
              fraction_of_neighbors += 1

        if fraction_of_neighbors < similarity_threshold:
          unhappy_agents.append((i, j))

  # Loop through the list of unhappy agents and swap them with an empty house.
  for i, j in unhappy_agents:
    while True:
      empty_house = None
      for neighbor in [(i - 1, j), (i + 1, j), (i, j - 1), (i, j + 1)]:
        if 0 <= neighbor[0] < len(array) and 0 <= neighbor[1] < len(array[0]):
          if array[neighbor[0]][neighbor[1]] == 0:
            empty_house = neighbor
            break

      if empty_house is not None:
        array[i][j], array[empty_house[0]][empty_house[1]] = array[empty_house[0]][empty_house[1]], array[i][j]
        break

  return array

I hope this helps!

Upvotes: 0

Related Questions