def test(): graph_path = "./Data/PA_VTDALL.json" graph = Graph.from_json(graph_path) k = 18 ep = 0.05 unit_id = "GEOID10" pop_col = "TOT_POP" plot_path = "./Data/VTD_FINAL" unit_df = gpd.read_file(plot_path) division_col = "COUNTYFP10" divisions = unit_df[[division_col, 'geometry']].dissolve(by=division_col, aggfunc='sum') updaters = {"population": updaters.Tally(pop_col, alias="population")} cddict = recursive_tree_part(graph, range(k), df[pop_col].sum() / k, pop_col, .01, node_repeats=1) initial_partition = Partition(graph, cddict, updaters) ideal_population = sum( initial_partition["population"].values()) / len(initial_partition) division_proposal = partial(recom, pop_col=pop_col, pop_target=ideal_population, epsilon=0.05, method=partial(division_bipartition_tree, division_col=division_col), node_repeats=2) chain = MarkovChain(proposal=division_proposal, constraints=[ constraints.within_percent_of_ideal_population( initial_partition, 0.05), ], accept=accept.always_accept, initial_state=initial_partition, total_steps=1000) t = 0 snapshot = 100 for part in chain: if t % snapshot == 0: draw_graph(graph, part.assignment, unit_df, divisions, './chain_' + str(t) + '.png', geo_id=unit_id) t += 1
def test_recom_works_as_a_proposal(partition_with_pop): graph = partition_with_pop.graph ideal_pop = sum(graph.nodes[node]["pop"] for node in graph) / 2 proposal = functools.partial( recom, pop_col="pop", pop_target=ideal_pop, epsilon=0.25, node_repeats=5 ) constraints = [within_percent_of_ideal_population(partition_with_pop, 0.25, "pop")] chain = MarkovChain(proposal, constraints, lambda x: True, partition_with_pop, 100) for state in chain: assert contiguous(state)
def test_pa_freeze(): from gerrychain import ( GeographicPartition, Graph, MarkovChain, proposals, updaters, constraints, accept, ) import hashlib from gerrychain.proposals import recom from functools import partial graph = Graph.from_json("docs/user/PA_VTDs.json") my_updaters = {"population": updaters.Tally("TOTPOP", alias="population")} initial_partition = GeographicPartition(graph, assignment="CD_2011", updaters=my_updaters) ideal_population = sum( initial_partition["population"].values()) / len(initial_partition) # We use functools.partial to bind the extra parameters (pop_col, pop_target, epsilon, node_repeats) # of the recom proposal. proposal = partial(recom, pop_col="TOTPOP", pop_target=ideal_population, epsilon=0.02, node_repeats=2) pop_constraint = constraints.within_percent_of_ideal_population( initial_partition, 0.02) chain = MarkovChain( proposal=proposal, constraints=[pop_constraint], accept=accept.always_accept, initial_state=initial_partition, total_steps=100, ) result = "" for count, partition in enumerate(chain): result += str(list(sorted(partition.population.values()))) result += str(len(partition.cut_edges)) result += str(count) + "\n" assert hashlib.sha256(result.encode()).hexdigest( ) == "3bef9ac8c0bfa025fb75e32aea3847757a8fba56b2b2be6f9b3b952088ae3b3c"
def toChain(self, initial_partition): """Returns chain with instance variables of self NoInitialChain and parameter initial_partition.""" return MarkovChain( proposal=self.proposal, constraints=self.constraints, accept=self.accept, # Declares new Partition with identical instances in order to avoid # attempting to access parent initial_state=Partition(initial_partition.graph, assignment=initial_partition.assignment, updaters=initial_partition.updaters), total_steps=self.total_steps )
def run_chain(disc, disc_partition, num_steps): exp_chain = MarkovChain(slow_reversible_propose_bi ,Validator([single_flip_contiguous#,boundary_condition ]), accept = cut_accept, initial_state=disc_partition, total_steps = num_steps) t = 0 for observation in exp_chain: t += 1 return observation
def test_repeatable(three_by_three_grid): from gerrychain import ( MarkovChain, Partition, accept, constraints, proposals, updaters, ) partition = Partition( three_by_three_grid, {0: 1, 1: 1, 2: 1, 3: 1, 4: 1, 5: 2, 6: 2, 7: 2, 8: 2, 9: 2}, {"cut_edges": updaters.cut_edges}, ) chain = MarkovChain( proposals.propose_random_flip, constraints.single_flip_contiguous, accept.always_accept, partition, 20, ) # Note: these might not even be the actual expected flips expected_flips = [ None, {2: 2}, {4: 2}, {6: 1}, {1: 2}, {7: 1}, {0: 2}, {3: 2}, {7: 2}, {3: 1}, {4: 1}, {7: 1}, {8: 1}, {8: 2}, {8: 1}, {8: 2}, {3: 2}, {4: 2}, {7: 2}, {3: 1}, ] flips = [partition.flips for partition in chain] print(flips) assert flips == expected_flips
def test_elections_match_the_naive_computation(partition_with_election): chain = MarkovChain( propose_random_flip, Validator([no_vanishing_districts, reject_half_of_all_flips]), lambda x: True, partition_with_election, total_steps=100, ) for partition in chain: election_view = partition["Mock Election"] expected_party_totals = { "D": expected_tally(partition, "D"), "R": expected_tally(partition, "R"), } assert expected_party_totals == election_view.totals_for_party
def test_perimeter_match_naive_perimeter_at_every_step(): partition = Grid((10, 10), with_diagonals=True) chain = MarkovChain( propose_random_flip, [single_flip_contiguous, no_vanishing_districts], always_accept, partition, 1000, ) def get_exterior_boundaries(partition): graph_boundary = partition["boundary_nodes"] exterior = defaultdict(lambda: 0) for node in graph_boundary: part = partition.assignment[node] exterior[part] += partition.graph.nodes[node]["boundary_perim"] return exterior def get_interior_boundaries(partition): cut_edges = { edge for edge in partition.graph.edges if partition.crosses_parts(edge) } interior = defaultdict(int) for edge in cut_edges: for node in edge: interior[partition.assignment[node]] += partition.graph.edges[ edge]["shared_perim"] return interior def expected_perimeter(partition): interior_boundaries = get_interior_boundaries(partition) exterior_boundaries = get_exterior_boundaries(partition) expected = { part: interior_boundaries[part] + exterior_boundaries[part] for part in partition.parts } return expected for state in chain: expected = expected_perimeter(state) assert expected == state["perimeter"]
def run_GerryChain_heuristic(G, population_deviation, k, iterations): my_updaters = {"population": updaters.Tally("TOTPOP", alias="population")} start = recursive_tree_part( G, range(k), sum(G.nodes[i]["TOTPOP"] for i in G.nodes()) / k, "TOTPOP", population_deviation / 2, 1) initial_partition = GeographicPartition(G, start, updaters=my_updaters) proposal = partial(recom, pop_col="TOTPOP", pop_target=sum(G.nodes[i]["TOTPOP"] for i in G.nodes()) / k, epsilon=population_deviation / 2, node_repeats=2) compactness_bound = constraints.UpperBound( lambda p: len(p["cut_edges"]), 1.5 * len(initial_partition["cut_edges"])) pop_constraint = constraints.within_percent_of_ideal_population( initial_partition, population_deviation / 2) my_chain = MarkovChain(proposal=proposal, constraints=[pop_constraint, compactness_bound], accept=accept.always_accept, initial_state=initial_partition, total_steps=iterations) min_cut_edges = sum(G[i][j]['edge_length'] for i, j in G.edges) print("In GerryChain heuristic, current # of cut edges: ", end='') print(min_cut_edges, ",", sep='', end=' ') for partition in my_chain: current_cut_edges = sum(G[i][j]['edge_length'] for i, j in partition["cut_edges"]) print(current_cut_edges, ",", sep='', end=' ') if current_cut_edges < min_cut_edges: best_partition = partition min_cut_edges = current_cut_edges print("Best heuristic solution has # cut edges =", min_cut_edges) return ([[i for i in G.nodes if best_partition.assignment[i] == j] for j in range(k)], min_cut_edges)
def test_cut_edges_matches_naive_cut_edges_at_every_step( proposal, number_of_steps): partition = Grid((10, 10), with_diagonals=True) chain = MarkovChain( proposal, [single_flip_contiguous, no_vanishing_districts], always_accept, partition, number_of_steps, ) for state in chain: naive_cut_edges = { edge for edge in state.graph.edges if state.crosses_parts(edge) } assert naive_cut_edges == state["cut_edges"]
def test_tally_matches_naive_tally_at_every_step(): partition = Grid((10, 10), with_diagonals=True) chain = MarkovChain( propose_random_flip, [single_flip_contiguous, no_vanishing_districts], always_accept, partition, 1000, ) def get_expected_tally(partition): expected = defaultdict(int) for node in partition.graph.nodes: part = partition.assignment[node] expected[part] += partition.graph.nodes[node]["population"] return expected for state in chain: expected = get_expected_tally(state) assert expected == state["population"]
def shift_flip(partition, ep, ideal_pop, max_steps=150000, chain_bound=.02): #TODO: Amy, where do we think this function should be stored? Its #needed in the Chain I run within this shift function def pop_accept(partition): if not partition.parent: return True proposal_dev_score = max_pop_dev(partition, ideal_pop) parent_dev_score = max_pop_dev(partition.parent, ideal_pop) if proposal_dev_score < parent_dev_score: return True else: draw = random.random() return draw < chain_bound # print("ideal pop", ideal_pop) pop_tol_initial = max_pop_dev(partition, ideal_pop) # print("pop tol initial", pop_tol_initial) #if error again from initial state, just make constraint value chain = MarkovChain(proposal=propose_random_flip, constraints=[ constraints.within_percent_of_ideal_population( partition, pop_tol_initial + .05), single_flip_contiguous ], accept=pop_accept, initial_state=partition, total_steps=max_steps) step_Num = 0 for step in chain: partition = step # print("step num", step_Num, max_pop_dev(partition, ideal_pop)) if max_pop_dev(partition, ideal_pop) <= ep: break step_Num += 1 return Partition(partition.graph, partition.assignment, partition.updaters)
def run_chain(adj_graph, elections, total_steps=100): my_updaters = { "population": updaters.Tally("population"), "cut_edges": cut_edges, "elections": lambda x: [elec.alias for elec in elections], "expected_seat_share": expected_seat_share_updater } election_updaters = {election.name: election for election in elections} my_updaters.update(election_updaters) initial_partition = GeographicPartition(adj_graph, assignment="initial_plan", updaters=my_updaters) ideal_population = sum( initial_partition["population"].values()) / len(initial_partition) proposal = partial(recom, pop_col="population", pop_target=ideal_population, epsilon=0.01, node_repeats=2) pop_constraint = constraints.within_percent_of_ideal_population( initial_partition, 0.01) chain = MarkovChain(proposal=proposal, constraints=[ pop_constraint, ], accept=accept.always_accept, initial_state=initial_partition, total_steps=total_steps) return pd.DataFrame({ ix: { "cut_edges": len(partition["cut_edges"]), "expected_R_seats": partition["expected_seat_share"] } for ix, partition in enumerate(chain) }).T
def debug(): num_steps = 100000 disc = integral_disc(10) disc_partition = initial_partition(disc) exp_chain = MarkovChain(slow_reversible_propose_bi ,Validator([single_flip_contiguous#,boundary_condition ]), accept = cut_accept, initial_state=disc_partition, total_steps = num_steps) t = 0 for observation in exp_chain: t += 1 bd = convert_partition_to_boundary(disc, observation) Facefinder.draw_with_location(disc) Facefinder.draw_with_location(bd, "red") path = convert_path_graph_to_sequence_of_nodes(bd) aligned_boundary = conformally_align(path) return aligned_boundary
def chain(iterations): idef = random.randint(1, 10000) graph = Graph.from_json("../data/PA_init/PA_VTD.json") election = Election("SEN12", {"Dem": "USS12D", "Rep": "USS12R"}) initial_partition = GeographicPartition( graph, assignment="2011_PLA_1", updaters={ "cut_edges": cut_edges, "population": Tally("TOT_POP", alias="population"), "SEN12": election } ) ideal_population = sum(initial_partition["population"].values()) / len(initial_partition) # We use functools.partial to bind the extra parameters (pop_col, pop_target, epsilon, node_repeats) # of the recom proposal. proposal = partial(recom, pop_col="TOT_POP", pop_target=ideal_population, epsilon=0.02, node_repeats=2 ) chain = MarkovChain( proposal=proposal, constraints=[], accept=contiguous, initial_state=initial_partition, total_steps=85*iterations + 17000 ) count = 0 metrics = [] boundary_nodes = [] boundary_weighted = [] for partition in chain.with_progress_bar(): mm = mean_median(partition["SEN12"]) p = pp(partition) bias = partisan_bias(partition["SEN12"]) gini = partisan_gini(partition["SEN12"]) gap = efficiency_gap(partition["SEN12"]) cut = len(partition["cut_edges"]) if count >= 17000: if count % 85 == 0: metrics.append((mm, p, bias, gini, gap, cut, partition["SEN12"].wins("Rep"))) nodes = [0]*8921 bnodes = [0]*8921 for edge in partition["cut_edges"]: nodes[edge[0]] = 1 nodes[edge[1]] = 1 bnodes[edge[0]] += 1 bnodes[edge[1]] += 1 boundary_nodes.append(nodes) boundary_weighted.append(bnodes) assign = {i: partition.assignment[i] for i in partition.assignment} shape["CD"] = shape.index.map(assign) this_map = shape.dissolve(by='CD') this_map.plot(color='white', edgecolor='black') plt.axis('off') fig = plt.gcf() fig.set_size_inches((15,9), forward=False) fig.savefig("../images/PA_neutral/" + str(idef) + str(int((count-17000)/85)+1) + ".png", dpi=600, bbox_inches="tight", pad_inches=0) plt.close() if count % 8500 == 0: print(idef, count, mm, p, bias, gini, gap, cut, partition["SEN12"].wins("Rep")) else: if count%1000 == 0: print(idef, "Mixing...... Iteration", count, "/17000") count += 1 return metrics, boundary_nodes, boundary_weighted, idef
grid_partition["population"].values()) / len(grid_partition) tree_proposal = partial( recom, pop_col="population", pop_target=ideal_population, epsilon=0.05, node_repeats=1, ) # ######BUILD AND RUN FIRST MARKOV CHAIN recom_chain = MarkovChain( tree_proposal, constraints=[popbound], accept=always_accept, initial_state=grid_partition, total_steps=100, ) for part in recom_chain: pass plt.figure() nx.draw( graph, pos={x: x for x in graph.nodes()}, node_color=[part.assignment[x] for x in graph.nodes()], node_size=ns, node_shape="s",
#########Setup Proposal ideal_population = sum(grid_partition["population"].values()) / len(grid_partition) tree_proposal = partial(recom, pop_col="population", pop_target=ideal_population, epsilon=0.05, node_repeats=1 ) #######BUILD MARKOV CHAINS exp_chain = MarkovChain(slow_reversible_propose_bi ,Validator([single_flip_contiguous, popbound#,boundary_condition ]), accept = cut_accept, initial_state=grid_partition, total_steps = 10000000) #########Run MARKOV CHAINS rsw = [] rmm = [] reg = [] rce = [] rbn=[] waits= []
epsilon=0.05, node_repeats=3) compactness_bound = constraints.UpperBound(lambda p: len(p["cut_edges"]), len(initial_partition["cut_edges"])) county_splits_bound = constraints.UpperBound( lambda p: calc_splits(p["county_splits"]), calc_splits(initial_partition["county_splits"])) chain = MarkovChain( proposal=proposal, constraints=[ constraints.within_percent_of_ideal_population(initial_partition, 0.05), compactness_bound, county_splits_bound ], accept=accept.always_accept, initial_state=initial_partition, total_steps=steps, ) BVAP = [] HVAP = [] VAP = [] POP = [] for i in election_names: vars()["{}".format(i)] = [] for i in election_names: vars()["{}wins".format(i)] = [] for i in election_names:
return (partition["P1 vs P2"].wins("P2")/k_partitions)*100 def equal_check(partition, party): for number in range(1, k_partitions+1): if partition["P1 vs P2"].wins("P1")+partition["P1 vs P2"].wins("P2") == k_partitions + number: return ((partition["P1 vs P2"].wins(party)/k_partitions)*100)-((100/k_partitions)/2)*number raise error ideal_population = sum(init_part["population"].values()) / len(init_part) popbound = within_percent_of_ideal_population(init_part, 0.1) cutedgebound = UpperBound(lambda part: len(part["cut_edges"]), 400) flip_steps = 250000 flip_chain = MarkovChain( propose_random_flip, Validator([single_flip_contiguous, popbound, cutedgebound]), accept = always_accept, initial_state = init_part, total_steps = flip_steps, ) flip_p1_seats = [] for part in flip_chain: flip_p1_seats.append(part["P1 vs P2"].wins("P1")) plt.figure() nx.draw( graph, pos = {x: x for x in graph.nodes()}, node_color = [dict(part.assignment)[x] for x in graph.nodes()], node_size = node_size, node_shape = "p", cmap = "Set2",)
recom, pop_col="TAPERSONS", pop_target=ideal_population, epsilon=0.005, node_repeats=1, method=my_uu_bipartition_tree_random) # bipartition_tree_random #) compactness_bound = constraints.UpperBound( lambda p: len(p["cut_edges"]), 2 * len(initial_partition["cut_edges"])) chain = MarkovChain( proposal=tree_proposal, constraints=[ #constraints.within_percent_of_ideal_population(initial_partition, 0.013), compactness_bound #, single_flip_contiguous#no_more_discontiguous ], accept=accept.always_accept, initial_state=initial_partition, total_steps=20000, ) print("initialized chain") with open(newdir + "Start_Values.txt", "w") as f: f.write("Values for Starting Plan: Tree Recursive\n \n ") f.write("Initial Cut: " + str(len(initial_partition["cut_edges"]))) f.write("\n") f.write("\n") for elect in range(num_elections): f.write(election_names[elect] + "District Percentages" + str(
def produce_sample(graph, k, tag, sample_size = 500, chaintype='tree'): #Samples k partitions of the graph, stores the cut edges and records them graphically #Also stores vote histograms, and returns most extreme partitions. print("producing sample") updaters = {'population': Tally('population'), 'cut_edges': cut_edges, 'step_num': step_num, } for edge in graph.edges(): graph[edge[0]][edge[1]]['cut_times'] = 0 for n in graph.nodes(): #graph.nodes[n]["population"] = 1 #graph.nodes[n]["POP10"] #This is something gerrychain will refer to for checking population balance graph.nodes[n]["last_flipped"] = 0 graph.nodes[n]["num_flips"] = 0 print("set up chain") ideal_population= sum( graph.nodes[x]["population"] for x in graph.nodes())/k initial_partition = Partition(graph, assignment='part', updaters=updaters) pop1 = .05 print("popbound") popbound = within_percent_of_ideal_population(initial_partition, pop1) if chaintype == "tree": tree_proposal = partial(recom, pop_col="population", pop_target=ideal_population, epsilon=pop1, node_repeats=1, method=facefinder.my_mst_bipartition_tree_random) elif chaintype == "uniform_tree": tree_proposal = partial(recom, pop_col="population", pop_target=ideal_population, epsilon=pop1, node_repeats=1, method=facefinder.my_uu_bipartition_tree_random) else: print("Chaintype used: ", chaintype) raise RuntimeError("Chaintype not recongized. Use 'tree' or 'uniform_tree' instead") exp_chain = MarkovChain(tree_proposal, Validator([popbound]), accept=always_true, initial_state=initial_partition, total_steps=sample_size) z = 0 num_cuts_list = [] seats_won_table = [] best_left = np.inf best_right = -np.inf print("begin chain") for part in exp_chain: z += 1 if z % 100 == 0: print("step ", z) seats_won = 0 for edge in part["cut_edges"]: graph[edge[0]][edge[1]]["cut_times"] += 1 for i in range(k): rep_votes = 0 dem_votes = 0 for n in graph.nodes(): if part.assignment[n] == i: rep_votes += graph.nodes[n]["EL16G_PR_R"] dem_votes += graph.nodes[n]["EL16G_PR_D"] total_seats = int(rep_votes > dem_votes) seats_won += total_seats # total seats won by rep seats_won_table.append(seats_won) # save gerrymandered partitionss if seats_won < best_left: best_left = seats_won #left_mander = copy.deepcopy(part.parts) if seats_won > best_right: best_right = seats_won #right_mander = copy.deepcopy(part.parts) #print("finished round" print("max", best_right, "min:", best_left) plt.figure() plt.hist(seats_won_table, bins = 10) name = "./plots/seats_histogram_metamander" + tag +".png" plt.savefig(name) plt.close() edge_colors = [graph[edge[0]][edge[1]]["cut_times"] for edge in graph.edges()] pos=nx.get_node_attributes(graph, 'pos') plt.figure() plt.hist(seats_won_table, bins=10) mean = sum(seats_won_table) / len(seats_won_table) std = np.std(seats_won_table) # plt.close() # title = 'mean: ' + str(mean) + ' standard deviation: ' + str(std) # plt.title(title) # name = "./plots/seats_hist/seats_histogram" + tag + ".png" # plt.savefig(name) # plt.close() # edge_colors = [graph[edge[0]][edge[1]]["cut_times"] for edge in graph.edges()] # # plt.figure() # nx.draw(graph, pos=nx.get_node_attributes(graph, 'pos'), node_size=0, # edge_color=edge_colors, node_shape='s', # cmap='magma', width=1) # plt.savefig("./plots/edges_plots/edges" + tag + ".png") # plt.close() return mean, std, graph
def produce_gerrymanders(graph, k, tag, sample_size, chaintype): # Samples k-partitions of the graph # stores vote histograms, and returns most extreme partitions. for node in graph.nodes(): graph.nodes[node]["last_flipped"] = 0 graph.nodes[node]["num_flips"] = 0 ideal_population = sum(graph.nodes[x][config["POPULATION_COLUMN"]] for x in graph.nodes()) / k election = Election( config['ELECTION_NAME'], {'PartyA': config['PARTY_A_COL'], 'PartyB': config['PARTY_B_COL']}, alias=config['ELECTION_ALIAS'] ) updaters = {'population': Tally(config['POPULATION_COLUMN']), 'cut_edges': cut_edges, 'step_num': step_num, config['ELECTION_ALIAS'] : election } initial_partition = Partition(graph, assignment=config['ASSIGNMENT_COLUMN'], updaters=updaters) popbound = within_percent_of_ideal_population(initial_partition, config['POPULATION_EPSILON']) if chaintype == "tree": tree_proposal = partial(recom, pop_col=config["POPULATION_COLUMN"], pop_target=ideal_population, epsilon=config['POPULATION_EPSILON'], node_repeats=config['NODE_REPEATS'], method=facefinder.my_mst_bipartition_tree_random) elif chaintype == "uniform_tree": tree_proposal = partial(recom, pop_col=config["POPULATION_COLUMN"], pop_target=ideal_population, epsilon=config['POPULATION_EPSILON'], node_repeats=config['NODE_REPEATS'], method=facefinder.my_uu_bipartition_tree_random) else: print("Chaintype used: ", chaintype) raise RuntimeError("Chaintype not recognized. Use 'tree' or 'uniform_tree' instead") exp_chain = MarkovChain(tree_proposal, Validator([popbound]), accept=accept.always_accept, initial_state=initial_partition, total_steps=sample_size) seats_won_table = [] best_left = np.inf best_right = -np.inf for ctr, part in enumerate(exp_chain): seats_won = 0 if ctr % 100 == 0: print("step ", ctr) for i in range(k): rep_votes = 0 dem_votes = 0 for node in graph.nodes(): if part.assignment[node] == i: rep_votes += graph.nodes[node]["EL16G_PR_R"] dem_votes += graph.nodes[node]["EL16G_PR_D"] total_seats = int(rep_votes > dem_votes) seats_won += total_seats # total seats won by rep seats_won_table.append(seats_won) # save gerrymandered partitions if seats_won < best_left: best_left = seats_won left_mander = copy.deepcopy(part.parts) if seats_won > best_right: best_right = seats_won right_mander = copy.deepcopy(part.parts) # print("finished round" print("max", best_right, "min:", best_left) plt.figure() plt.hist(seats_won_table, bins=10) name = "./plots/large_sample/seats_hist/seats_histogram_orig" + tag + ".png" plt.savefig(name) plt.close() return left_mander, right_mander
def run_simple(graph): election = Election("2016 President", { "Democratic": "T16PRESD", "Republican": "T16PRESR" }, alias="2016_President") initial_partition = Partition(graph, assignment="2011_PLA_1", updaters={ "2016_President": election, "population": Tally("TOT_POP", alias="population"), "perimeter": perimeter, "exterior_boundaries": exterior_boundaries, "interior_boundaries": interior_boundaries, "boundary_nodes": boundary_nodes, "cut_edges": cut_edges, "area": Tally("area", alias="area"), "cut_edges_by_part": cut_edges_by_part, "county_split": county_splits('county_split', "COUNTYFP10"), "black_population": Tally("BLACK_POP", alias="black_population"), }) efficiency_gaps = [] wins = [] beta = 0 wp = 1 wi = 1 wc = 0 wm = 1 def accept(partition): return (metro_scoring_prob(partition, beta, wp, wi, wc, wm)) is_valid = Validator([single_flip_contiguous, districts_within_tolerance]) chain = MarkovChain( proposal=propose_random_flip, is_valid=is_valid, #accept = always_accept, accept= accept, #THe acceptance criteria is what needs to be defined ourselves - to match the paper initial_state=initial_partition, total_steps=30) for partition in chain: if (hasattr(partition, 'accepted') and partition.accepted): efficiency_gaps.append( gerrychain.scores.efficiency_gap(partition["2016_President"])) wins.append(partition["2016_President"].wins("Democratic")) return (efficiency_gaps, wins, partition)
partial(recom, pop_col="TOTPOP", pop_target=totpop[i] / num_districts, epsilon=0.02, node_repeats=1)) compactness_bounds.append( constraints.UpperBound(lambda p: len(p["cut_edges"]), 2 * len(initial_partitions[i]["cut_edges"]))) chains.append( MarkovChain( proposal=proposals[i], constraints=[ constraints.within_percent_of_ideal_population( initial_partitions[i], 0.05), compactness_bounds[i] #constraints.single_flip_contiguous#no_more_discontiguous ], accept=accept.always_accept, initial_state=initial_partitions[i], total_steps=1000)) cuts = [[], [], [], []] BVAPS = [[], [], [], []] for i in range(4): t = 0 for part in chains[i]: cuts[i].append(len(part["cut_edges"])) BVAPS[i].append(sorted(part["BVAP"].percents("BVAP"))) t += 1 if t % 100 == 0:
def chain(iterations): idef = random.randint(1, 10000) graph = Graph.from_json("./PA_VTD.json") election = Election("SEN12", {"Dem": "USS12D", "Rep": "USS12R"}) initial_partition = GeographicPartition(graph, assignment="2011_PLA_1", updaters={ "cut_edges": cut_edges, "population": Tally("TOT_POP", alias="population"), "SEN12": election }) ideal_population = sum( initial_partition["population"].values()) / len(initial_partition) # We use functools.partial to bind the extra parameters (pop_col, pop_target, epsilon, node_repeats) # of the recom proposal. proposal = partial(recom, pop_col="TOT_POP", pop_target=ideal_population, epsilon=0.02, node_repeats=2) chain = MarkovChain(proposal=proposal, constraints=[republican_constraint], accept=contiguous, initial_state=initial_partition, total_steps=iterations + 100) count = 0 metrics = [] boundary_nodes = [] boundary_weighted = [] for partition in chain.with_progress_bar(): mm = mean_median(partition["SEN12"]) p = pp(partition) bias = partisan_bias(partition["SEN12"]) gini = partisan_gini(partition["SEN12"]) gap = efficiency_gap(partition["SEN12"]) cut = len(partition["cut_edges"]) if count >= 100: metrics.append((mm, p, bias, gini, gap, cut)) nodes = [0] * 8921 bnodes = [0] * 8921 for edge in partition["cut_edges"]: nodes[edge[0]] = 1 nodes[edge[1]] = 1 bnodes[edge[0]] += 1 bnodes[edge[1]] += 1 boundary_nodes.append(nodes) boundary_weighted.append(bnodes) if count % 100 == 0: print(idef, count, mm, p, bias, gini, gap, cut, partition["SEN12"].wins("Rep")) count += 1 return metrics, boundary_nodes, boundary_weighted
ideal_population = sum(gp3["population"].values()) / len(gp3) proposal = partial( recom, pop_col="population", pop_target=ideal_population, epsilon=0.02, node_repeats=1, ) popbound = within_percent_of_ideal_population(gp3, 0.05) g3chain = MarkovChain( proposal, # propose_chunk_flip, Validator([popbound]), accept=always_accept, initial_state=gp3, total_steps=100, ) t = 0 for part3 in g3chain: t += 1 print("finished tree walk") pos_dict = {n: n for n in graph.nodes()} pos = pos_dict plt.figure() plt.title("Starting Point")
#CHAIN FOR TOTPOP proposal = partial(recom, pop_col=pop_col, pop_target=tot_pop_col / num_districts, epsilon=0.02, node_repeats=1) compactness_bound = constraints.UpperBound( lambda p: len(p["cut_edges"]), 2 * len(starting_partition["cut_edges"])) chain = MarkovChain( proposal, constraints=[ constraints.within_percent_of_ideal_population(starting_partition, 0.10), compactness_bound #constraints.single_flip_contiguous#no_more_discontiguous ], accept=accept.always_accept, initial_state=starting_partition, total_steps=10000) #CHAIN FOR CPOP #proposal = partial( # recom, pop_col=ccol, pop_target=tot_ccol/num_districts, epsilon=0.02, node_repeats=1 # ) #compactness_bound = constraints.UpperBound( # lambda p: len(p["cut_edges"]), 2 * len(starting_partition["cut_edges"]) # ) #chain = MarkovChain(
tree_proposal = partial( recom, pop_col="population", pop_target=ideal_population, epsilon=0.05, node_repeats=1, ) # ######BUILD MARKOV CHAINS numIters = 10000 recom_chain = MarkovChain( tree_proposal, Validator([popbound]), accept=always_accept, initial_state=grid_partition, total_steps=numIters, ) # ########Run MARKOV CHAINS rsw = [] rmm = [] reg = [] rce = [] expectednumberseats = 0 for part in recom_chain: rsw.append(part["Pink-Purple"].wins("Pink"))
) # print(ideal_population) tree_proposal = partial( recom, pop_col="TOT_POP", pop_target=ideal_population, epsilon=0.01, node_repeats=1, method = bipartition_tree_random ) compactness_bound = constraints.UpperBound( lambda p: len(p["cut_edges"]), 2 * len(initial_partition["cut_edges"]) ) chain = MarkovChain( proposal=slow_reversible_propose, constraints=[ constraints.within_percent_of_ideal_population(initial_partition, 0.01), compactness_bound, single_flip_contiguous#no_more_discontiguous ], accept=accept.always_accept, initial_state=initial_partition, total_steps=10000000, ) print("initialized chain") with open(newdir + "Start_Values.txt", "w") as f: f.write("Values for Starting Plan: Tree31\n \n ") f.write("Initial Cut: " + str(len(initial_partition["cut_edges"]))) f.write("\n") f.write("\n") for elect in range(num_elections):
## Setup chain proposal = partial(recom, pop_col=POP_COL, pop_target=ideal_pop, epsilon=EPS, node_repeats=1) compactness_bound = constraints.UpperBound( lambda p: len(p["cut_edges"]), 2 * len(init_partition["cut_edges"])) chain = MarkovChain(proposal, constraints=[ constraints.within_percent_of_ideal_population( init_partition, EPS), compactness_bound ], accept=accept.always_accept, initial_state=init_partition, total_steps=ITERS) ## Run chain print("Starting Markov Chain") def init_chain_results(): data = {"cutedges": np.zeros(ITERS)} parts = {"samples": []} for c in DEMO_COLS: data[c] = np.zeros((ITERS, NUM_DISTRICTS))