def build_contig_regions(self, num_regions, cardinality, w, maxiter, compact, max_swaps): if compact: grow_region = self.grow_compact else: grow_region = self.grow_free iter = 0 while iter < maxiter: # regionalization setup regions = [] size_pre = 0 counter = -1 area2region = {} self.feasible = False swap_count = 0 cards = copy.copy(cardinality) cards.sort() # try to build largest regions first (pop from end of list) candidates = copy.copy(self.ids) # these are already shuffled # begin building regions while candidates and swap_count < max_swaps: # setup test to determine if swapping is needed if size_pre == len(regions): counter += 1 else: counter = 0 size_pre = len(regions) # test if swapping is needed if counter == len(candidates): # start swapping # swapping simply changes the candidate list swap_in = None # area to become new candidate while swap_in is None: # PEP8 E711 swap_count += 1 swap_out = candidates.pop(0) # area to remove from candidates swap_neighs = copy.copy(w.neighbors[swap_out]) swap_neighs = list(np.random.permutation(swap_neighs)) # select area to add to candidates (i.e. remove from an existing region) for i in swap_neighs: if i not in candidates: join = i # area linking swap_in to swap_out swap_index = area2region[join] swap_region = regions[swap_index] swap_region = list(np.random.permutation(swap_region)) for j in swap_region: # test to ensure region connectivity after removing area swap_region_test = swap_region[:] + [swap_out] if check_contiguity(w, swap_region_test, j): swap_in = j break if swap_in is not None: # PEP8 E711 break else: candidates.append(swap_out) # swapping cleanup regions[swap_index].remove(swap_in) regions[swap_index].append(swap_out) area2region.pop(swap_in) area2region[swap_out] = swap_index candidates.append(swap_in) counter = 0 # setup to build a single region building = True seed = candidates.pop(0) region = [seed] potential = [i for i in w.neighbors[seed] if i in candidates] test_card = cards.pop() # begin building single region while building and len(region) < test_card: if potential: region, candidates, potential = grow_region( w, test_card, region, candidates, potential) else: # not enough potential neighbors to reach test_card size building = False cards.append(test_card) if len(region) in cards: # constructed region matches another candidate region size cards.remove(len(region)) else: # constructed region doesn't match a candidate region size candidates.extend(region) region = [] # cleanup when successful region built if region: regions.append(region) region_index = len(regions) - 1 for i in region: area2region[i] = region_index # area2region needed for swapping # handling of regionalization result if len(regions) < num_regions: # regionalization failed self.ids = list(np.random.permutation(self.ids)) regions = [] iter += 1 else: # regionalization successful self.feasible = True iter = maxiter self.regions = regions
def build_contig_regions(self, num_regions, cardinality, w, maxiter, compact, max_swaps): if compact: grow_region = self.grow_compact else: grow_region = self.grow_free sizecheck = self.region_size_check iter = 0 while iter < maxiter: # regionalization setup regions = [] size_pre = 0 counter = -1 area2region = {} self.feasible = False swap_count = 0 cards = copy.copy(cardinality) cards.sort( ) # try to build largest regions first (pop from end of list) candidates = copy.copy(self.ids) # these are already shuffled # begin building regions while candidates and swap_count < max_swaps: # setup test to determine if swapping is needed # print(counter, size_pre) if size_pre == len(regions): counter += 1 else: counter = 0 size_pre = len(regions) # test if swapping is needed # if counter == len(candidates): # # # start swapping # # swapping simply changes the candidate list # swap_in = None # area to become new candidate # while swap_in is None: # PEP8 E711 # swap_count += 1 # swap_out = candidates.pop(0) # area to remove from candidates # swap_neighs = copy.copy(w.neighbors[swap_out]) # swap_neighs = list(np.random.permutation(swap_neighs)) # # select area to add to candidates (i.e. remove from an existing region) # for i in swap_neighs: # if i not in candidates: # join = i # area linking swap_in to swap_out # swap_index = area2region[join] # swap_region = regions[swap_index] # print("before swap: ") # print([self.cd_dev[j][0]-sum([self.wtdict[i] for i in swap_region]) for j in range(len(regions))]) # swap_region = list(np.random.permutation(swap_region)) # swap_dev = self.cd_dev[swap_index] # for j in swap_region: # # test to ensure region connectivity after removing area # # j is an element in the region possibly to remove # swap_region_test = swap_region[:] + [swap_out] # delta = self.wtdict[swap_out]-self.wtdict[j] # if (check_contiguity(w, swap_region_test, j) # and sizecheck(swap_dev[0] + delta, swap_dev[0]-swap_dev[1]) == 0): # swap_in = j # break # if swap_in is not None: # PEP8 E711 # break # else: # candidates.append(swap_out) # # swapping cleanup # regions[swap_index].remove(swap_in) # regions[swap_index].append(swap_out) # area2region.pop(swap_in) # area2region[swap_out] = swap_index # self.cd_dev[swap_index] = tuple(i + delta for i in self.cd_dev[swap_index] ) # candidates.append(swap_in) # counter = 0 # # setup to build a single region building = True seed = candidates.pop(0) region = [seed] regpop = self.wtdict[seed] if not cards: print(len(regions)) print(sum(list(map(len, regions)))) print("Ran out of cards") break test_card = cards.pop() #test_card is the population target; potential = [ i for i in w.neighbors[seed] if (i in candidates and sizecheck(regpop + self.wtdict[i], test_card) != 1) ] # begin building single region while building and sizecheck(regpop, test_card) == -1: if potential: region, candidates, potential, regpop = grow_region( w, test_card, region, candidates, potential, regpop) else: # not enough potential neighbors to reach test_card size building = False cards.append(test_card) if regpop in cards: # constructed region matches another candidate region size cards.remove(regpop) else: # constructed region doesn't match a candidate region size candidates.extend(region) region = [] # cleanup when successful region built if region: region_index = len(regions) for i in region: area2region[ i] = region_index # area2region needed for swapping regions.append( region ) #append the successful region to the region list self.cd_dev[region_index] = np.array( [regpop, regpop - test_card]) #print(self.cd_dev) # print(building) print(regpop) # print(#[round(self.wtdict[i]/776646,2) for i in region], # round(sum([self.wtdict[i] for i in region])/self.n*7,2)) # print(regpop/self.n*7) # print(sum([self.wtdict[i] for i in candidates])) # print(sum([len(i) for i in regions])) # print(sum([sum(self.wtdict[j] for j in i) for i in regions])) # print([self.cd_dev[j][0] for j in range(len(regions))]) # print([sum([self.wtdict[i] for i in regions[j]]) for j in range(len(regions))]) # handling of regionalization result if len(regions) < num_regions: # regionalization failed print("fail") self.ids = list(np.random.permutation(self.ids)) regions = [] iter += 1 else: # regionalization successful self.feasible = True iter = maxiter self.regions = regions
def __init__( self, area_ids, num_regions=None, cardinality=None, contiguity=None, maxiter=1000, compact=False, max_swaps=1000000): self.n = len(area_ids) ids = copy.copy(area_ids) self.ids = list(np.random.permutation(ids)) self.area_ids = area_ids self.regions = [] self.feasible = True # tests for input argument consistency if cardinality: if self.n != sum(cardinality): self.feasible = False raise Exception('number of areas does not match cardinality') if contiguity: if area_ids != contiguity.id_order: self.feasible = False raise Exception('order of area_ids must match order in contiguity') if num_regions and cardinality: if num_regions != len(cardinality): self.feasible = False raise Exception('number of regions does not match cardinality') # dispatches the appropriate algorithm if num_regions and cardinality and contiguity: # conditioning on cardinality and contiguity (number of regions implied) self.build_contig_regions(num_regions, cardinality, contiguity, maxiter, compact, max_swaps) elif num_regions and cardinality: # conditioning on cardinality (number of regions implied) region_breaks = self.cards2breaks(cardinality) self.build_noncontig_regions(num_regions, region_breaks) elif num_regions and contiguity: # conditioning on number of regions and contiguity cards = self.get_cards(num_regions) self.build_contig_regions(num_regions, cards, contiguity, maxiter, compact, max_swaps) elif cardinality and contiguity: # conditioning on cardinality and contiguity num_regions = len(cardinality) self.build_contig_regions(num_regions, cardinality, contiguity, maxiter, compact, max_swaps) elif num_regions: # conditioning on number of regions only region_breaks = self.get_region_breaks(num_regions) self.build_noncontig_regions(num_regions, region_breaks) elif cardinality: # conditioning on number of cardinality only num_regions = len(cardinality) region_breaks = self.cards2breaks(cardinality) self.build_noncontig_regions(num_regions, region_breaks) elif contiguity: # conditioning on number of contiguity only num_regions = self.get_num_regions() cards = self.get_cards(num_regions) self.build_contig_regions(num_regions, cards, contiguity, maxiter, compact, max_swaps) else: # unconditioned num_regions = self.get_num_regions() region_breaks = self.get_region_breaks(num_regions) self.build_noncontig_regions(num_regions, region_breaks)
def __init__(self, area_ids, num_regions=None, cardinality=None, contiguity=None, maxiter=1000, compact=False, max_swaps=1000000, area_wts=None, tol=0): if area_wts is None: area_wts = np.ones(len(area_ids)) self.n = sum(area_wts) ids = copy.copy(area_ids) self.wtdict = dict(zip(ids, area_wts)) self.ids = list(np.random.permutation(ids)) self.area_ids = area_ids self.regions = [] self.feasible = True self.tol = tol self.cd_dev = {} #dictionary of deviations from intended cardinality # tests for input argument consistency if cardinality is not None: # if self.n != sum(cardinality): if np.greater_equal(abs(self.n - sum(cardinality)), .001 * abs(sum(cardinality))): self.feasible = False raise Exception( 'Sum of cardinalities does not equal total weight') if contiguity is not None: if area_ids != contiguity.id_order: self.feasible = False raise Exception( 'order of area_ids must match order in contiguity') if num_regions and cardinality is not None: if num_regions != len(cardinality): self.feasible = False raise Exception('number of regions does not match cardinality') # dispatches the appropriate algorithm if num_regions and cardinality is not None and contiguity is not None: # conditioning on cardinality and contiguity (number of regions implied) self.build_contig_regions(num_regions, cardinality, contiguity, maxiter, compact, max_swaps) elif num_regions and cardinality is not None: # conditioning on cardinality (number of regions implied) region_breaks = self.cards2breaks(cardinality) self.build_noncontig_regions(num_regions, region_breaks) elif num_regions and contiguity is not None: # conditioning on number of regions and contiguity cards = self.get_cards(num_regions) self.build_contig_regions(num_regions, cards, contiguity, maxiter, compact, max_swaps) elif cardinality is not None and contiguity is not None: # conditioning on cardinality and contiguity num_regions = len(cardinality) self.build_contig_regions(num_regions, cardinality, contiguity, maxiter, compact, max_swaps) elif num_regions: # conditioning on number of regions only region_breaks = self.get_region_breaks(num_regions) self.build_noncontig_regions(num_regions, region_breaks) elif cardinality is not None: # conditioning on number of cardinality only num_regions = len(cardinality) region_breaks = self.cards2breaks(cardinality) self.build_noncontig_regions(num_regions, region_breaks) elif contiguity is not None: # conditioning on number of contiguity only num_regions = self.get_num_regions() cards = self.get_cards(num_regions) self.build_contig_regions(num_regions, cards, contiguity, maxiter, compact, max_swaps) else: # unconditioned num_regions = self.get_num_regions() region_breaks = self.get_region_breaks(num_regions) self.build_noncontig_regions(num_regions, region_breaks)