def build_markov_chain(steps, chaintype, ideal_population, grid_partition): if chaintype == "tree": tree_proposal = partial(recom, pop_col="population", pop_target=ideal_population, epsilon=0.05, node_repeats=1, method=my_mst_bipartition_tree_random) # tree_proposal = partial(recom, pop_col="population", pop_target=ideal_population, epsilon=0.1, # node_repeats=1, method=recursive_tree_part) exp_chain = MarkovChain(tree_proposal, Validator([#popbound # ,boundary_condition ]), accept=cut_accept, initial_state=grid_partition, total_steps=steps) if chaintype == "uniform_tree": #tree_proposal = partial(uniform_tree_propose) tree_proposal = partial(recom, pop_col="population", pop_target=ideal_population, epsilon=0.05, node_repeats=1, method=my_uu_bipartition_tree_random) #This tree proposal is returning partitions that are balanced to within epsilon #But its not good enough for this validator. exp_chain = MarkovChain(tree_proposal, Validator([#popbound # ,boundary_condition ]), accept=cut_accept, initial_state=grid_partition, total_steps=steps) return exp_chain
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_with_election(partition_with_election): return MarkovChain( propose_random_flip, Validator([no_vanishing_districts]), lambda x: True, partition_with_election, total_steps=10, )
def __init__(self, partition, constraints, total_steps): if len(constraints) > 0: validator = Validator(constraints) else: validator = lambda x: True super().__init__( propose_random_flip, validator, always_accept, partition, total_steps )
def run_simple2(graph): election = Election("2014 Senate", { "Democratic": "sen_blue", "Republican": "sen_red" }, alias="2014_Senate") initial_partition = Partition(graph, assignment="con_distri", updaters={ "2014_Senate": election, "population": Tally("population", alias="population"), "exterior_boundaries": exterior_boundaries, "interior_boundaries": interior_boundaries, "perimeter": perimeter, "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', "COUNTY_ID"), "black_population": Tally("black_pop", alias="black_population"), }) districts_within_tolerance_2 = lambda part: districts_within_tolerance( part, 'population', 0.3) is_valid = Validator( [single_flip_contiguous, districts_within_tolerance_2]) 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, ) efficiency_gaps = [] wins = [] for partition in chain: if (hasattr(partition, 'accepted') and partition.accepted): efficiency_gaps.append( gerrychain.scores.efficiency_gap(partition["2014_Senate"])) wins.append(partition["2014_Senate"].wins("Democratic")) return (efficiency_gaps, wins, partition)
def test_validator_accepts_numpy_booleans(): mock_partition = MagicMock() mock_constraint = MagicMock() mock_constraint.return_value = numpy.bool_(True) mock_constraint.__name__ = "mock_constraint" is_valid = Validator([mock_constraint]) assert is_valid(mock_partition)
def test_vote_proportion_updater_returns_percentage_or_nan_on_later_steps( partition_with_election): chain = MarkovChain(propose_random_flip, Validator([no_vanishing_districts]), lambda x: True, partition_with_election, total_steps=10) for partition in chain: election_view = partition['Mock Election'] assert all( is_percentage_or_nan(value) for party_percents in election_view.percents_for_party.values() for value in party_percents.values())
def test_validator_raises_TypeError_if_constraint_returns_non_boolean(): def function(): pass mock_partition = MagicMock() mock_constraint = MagicMock() mock_constraint.return_value = function mock_constraint.__name__ = "mock_constraint" validator = Validator([mock_constraint]) with pytest.raises(TypeError): validator(mock_partition)
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_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
ideal_population = sum( init_partition["population"].values()) / len(init_partition) proposal = partial( recom, pop_col="TOTPOP", pop_target=ideal_population, epsilon=0.02, node_repeats=1, ) popbound = within_percent_of_ideal_population(init_partition, 0.05) gchain = MarkovChain( proposal, Validator([popbound]), accept=always_accept, initial_state=init_partition, total_steps=100, ) t = 0 for part in gchain: t += 1 init_partition = part print("FINISHED TREE WALK") gdf_print_map(init_partition, './opt_plots/starting_plan.png', gdf, unit_name) record_partition(init_partition, 0, 'starting', graph_name, exp_num)
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",
# # tree_proposal = partial(recom, # pop_col="population", # pop_target=ideal_population, # epsilon=1, # node_repeats=1 # ) #######BUILD MARKOV CHAINS pop_col = "population" epsilon = 0.05 if chaintype == "tree": tree_proposal = partial(recom, pop_col="population", pop_target=ideal_population, epsilon=0.05, node_repeats=1, method=my_mst_bipartition_tree_random) exp_chain = MarkovChain(tree_proposal, Validator([#popbound # ,boundary_condition ]), accept=cut_accept, initial_state=grid_partition, total_steps=steps) if chaintype == "uniform_tree": #tree_proposal = partial(uniform_tree_propose) tree_proposal = partial(recom, pop_col="population", pop_target=ideal_population, epsilon=0.05, node_repeats=1, method=my_uu_bipartition_tree_random) #This tree proposal is returning partitions that are balanced to within epsilon #But its not good enough for this validator. exp_chain = MarkovChain(tree_proposal, Validator([#popbound # ,boundary_condition ]), accept=cut_accept, initial_state=grid_partition, total_steps=steps)
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 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 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)
def run_simple(graph, num_samples = 80000, wp = 3000, wi = 2.5, wc = 0.4, wm = 800, get_parts = 5): election = Election( "2014 Senate", {"Democratic": "sen_blue", "Republican": "sen_red"}, alias="2014_Senate" ) initial_partition = Partition( graph, assignment="2014_CD", updaters={ "2014_Senate": election, "population": Tally("population", alias="population"), "exterior_boundaries": exterior_boundaries, "interior_boundaries": interior_boundaries, "perimeter": perimeter, "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', "COUNTY_ID"), "black_population": Tally("black_pop", alias = "black_population"), } ) def vra_validator(part): if(vra_district_requirement(part, 2, [0.4, 0.335]) > 0): return False return True districts_within_tolerance_2 = lambda part : districts_within_tolerance(part, 'population', 0.12) is_valid = Validator([single_flip_contiguous, districts_within_tolerance_2, vra_validator ]) def accept(partition, counter): if(counter < 40000): beta = 0 elif(counter < 60000): beta = (counter - 40000) /(60000-40000) else: beta = 1 return(metro_scoring_prob(partition, beta, wp, wi, wc, wm)) chain = MarkovChainAnneal( proposal=propose_random_flip, is_valid=is_valid, accept=accept, initial_state=initial_partition, total_steps= num_samples * 100, ) # going to show 5 partitions from this sample part_con = max(1, num_samples / get_parts) efficiency_gaps = [] wins = [] voting_percents = [] sample_parts = [] tbefore = time.time() for partition in chain: if(hasattr(partition, 'accepted') and partition.accepted): efficiency_gaps.append(gerrychain.scores.efficiency_gap(partition["2014_Senate"])) wins.append(partition["2014_Senate"].wins("Democratic")) voting_percents.append(partition["2014_Senate"].percents("Democratic")) num_s = len(wins) if(num_s % part_con) == 0: sample_parts.append(partition) if(num_s> num_samples): break if(num_s % 1000 == 0): tnext = time.time() print("It took %i time to get 1000 samples" % (tnext - tbefore)) tbefore = time.time() return(efficiency_gaps, wins, voting_percents, sample_parts)
A MarkovChain with propose_random_flips proposal and always_accept acceptance function. Also instantiates a Validator for you from a list of constraints. """ def __init__(self, partition, constraints, total_steps): if len(constraints) > 0: validator = Validator(constraints) else: validator = lambda x: True super().__init__( propose_random_flip, validator, always_accept, partition, total_steps ) grid_validator = Validator([single_flip_contiguous, no_vanishing_districts]) class GridChain(MarkovChain): """ A basic MarkovChain for use with the Grid partition. The proposal is a single random flip at the boundary of a district. A step is valid if the districts are connected and no districts disappear. Requires a 'cut_edges' updater. """ def __init__(self, initial_grid, total_steps=1000): if not initial_grid["cut_edges"]: raise ValueError( "BasicChain needs the Partition to have a cut_edges updater." )
def produce_gerrymanders(graph, k, tag, sample_size, chaintype): #Samples k partitions of the graph #stores vote histograms, and returns most extreme partitions. for n in graph.nodes(): graph.nodes[n]["last_flipped"] = 0 graph.nodes[n]["num_flips"] = 0 ideal_population= sum( graph.nodes[x]["population"] for x in graph.nodes())/k updaters = {'population': Tally('population'), 'cut_edges': cut_edges, 'step_num': step_num, } initial_partition = Partition(graph, assignment='part', updaters=updaters) pop1 = .05 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=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=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) seats_won_table = [] best_left = np.inf best_right = -np.inf ctr = 0 for part in exp_chain: ctr += 1 seats_won = 0 if ctr % 100 == 0: print("step ", ctr) 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" + tag +".png" #plt.savefig(name) #plt.close() sns_plot = sns.distplot(seats_won_table, label="North Carolina Republican Vote Distribution").get_figure() plt.legend() sns_plot.savefig(name) return left_mander, right_mander
print("Finished ReCom") # ########BUILD SECOND PARTITION squiggle_partition = Partition(graph, assignment=part.assignment, updaters=updaters) # ADD CONSTRAINTS popbound = within_percent_of_ideal_population(squiggle_partition, 0.1) # ######BUILD AND RUN SECOND MARKOV CHAIN squiggle_chain = MarkovChain( propose_random_flip, Validator([single_flip_contiguous, popbound]), accept=always_accept, initial_state=squiggle_partition, total_steps=100_000, ) for part2 in squiggle_chain: pass plt.figure() nx.draw( graph, pos={x: x for x in graph.nodes()}, node_color=[part2.assignment[x] for x in graph.nodes()], node_size=ns,
def produce_sample(graph, k, tag, sample_size = 500): #Samples k partitions of the graph, stores the cut edges and records them graphically #Also stores vote histograms, and returns most extreme partitions. 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 #sierp_partition = build_balanced_partition(g_sierpinsky, "population", ideal_population, .01) ideal_population= sum( graph.nodes[x]["population"] for x in graph.nodes())/k updaters = {'population': Tally('population'), 'cut_edges': cut_edges, 'step_num': step_num, } initial_partition = Partition(graph, assignment='part', updaters=updaters) #viz(g_sierpinsky, set([]), sierp_partition.parts) #ideal_population = sum(sierp_partition["population"].values()) / len(sierp_partition) print(ideal_population) steps = sample_size pop1 = .1 popbound = within_percent_of_ideal_population(initial_partition, pop1) chaintype = "tree" if chaintype == "tree": tree_proposal = partial(recom, pop_col="population", pop_target=ideal_population, epsilon=pop1, node_repeats=1, method=my_mst_bipartition_tree_random) if chaintype == "uniform_tree": tree_proposal = partial(recom, pop_col="population", pop_target=ideal_population, epsilon=pop1, node_repeats=1, method=my_uu_bipartition_tree_random) exp_chain = MarkovChain(tree_proposal, Validator([popbound]), accept=always_true, initial_state=initial_partition, total_steps=steps) z = 0 num_cuts_list = [] seats_won_table = [] best_left = np.inf best_right = -np.inf ctr = 0 for part in exp_chain: ctr += 1 print(ctr) #for i in range(steps): # part = build_balanced_partition(g_sierpinsky, "population", ideal_population, .05) seats_won = 0 z += 1 if z % 100 == 0: print("step ", z) for edge in part["cut_edges"]: graph[edge[0]][edge[1]]["cut_times"] += 1 for i in range(k): rural_pop = 0 urban_pop = 0 for n in graph.nodes(): if part.assignment[n] == i: rural_pop += graph.nodes[n]["EL16G_PR_R"] urban_pop += graph.nodes[n]["EL16G_PR_D"] total_seats = int(rural_pop > urban_pop) seats_won += total_seats #total seats won by rual pop 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) edge_colors = [graph[edge[0]][edge[1]]["cut_times"] for edge in graph.edges()] pos=nx.get_node_attributes(graph, 'pos') plt.figure() nx.draw(graph, pos=nx.get_node_attributes(graph, 'pos'), node_size=1, edge_color=edge_colors, node_shape='s', cmap='magma', width=3) plt.savefig("./plots/edges" + tag + ".png") plt.close() plt.figure() plt.hist(seats_won_table, bins = 10) name = "./plots/seats_histogram" + tag +".png" plt.savefig(name) plt.close() return left_mander, right_mander
#########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=1000000) #########Run MARKOV CHAINS rsw = [] rmm = [] reg = [] rce = [] rbn = [] waits = [] slopes = []
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 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:
# print(len(clusters)) flips = {} for val in clusters.keys(): flips[val] = edd[clusters[val]] # print(len(flips)) # print(partition.assignment) # print(flips) return partition.flip(flips) # ######BUILD AND RUN FINAL MARKOV CHAIN final_chain = MarkovChain( propose_spectral_merge, Validator([]), accept=always_accept, initial_state=initial_partition, total_steps=10, ) for part in final_chain: df["clusters"] = df.index.map(dict(part.assignment)) df.plot(column="clusters") plt.axis('off') plt.savefig(f"./plots/spectral_step{part['step_num']:02d}.png") plt.close() #plt.show() #plt.figure()
def min_pop(part): return min(list(part["population"].values())) def sd_pop(part): return np.std(list(part["population"].values())) mean_one_sd_up = mean_pop(init_partition) + (2 / 3) * sd_pop(init_partition) mean_one_sd_down = mean_pop(init_partition) - (2 / 3) * sd_pop(init_partition) # initalize and run both chains is_valid = Validator([ LowerBound(min_pop, min_pop(init_partition) % 50), UpperBound(mean_pop, mean_one_sd_up), LowerBound(mean_pop, mean_one_sd_down), WithinPercentRangeOfBounds(sd_pop, 25), ]) chunk = Process( target=generate_entropies, args=("chunk", STEP_COUNT, BURN_IN, results, int(TOT_WORKERS / 2)), ) random = Process( target=generate_entropies, args=("random", STEP_COUNT, BURN_IN, results, int(TOT_WORKERS / 2)), ) chunk.start(), random.start() chunk.join(), random.join() save_results(CITY_NAME, STEP_COUNT, results["chunk"], results["random"])
def main(): """ Contains majority of expermiment. Runs a markov chain on the state dual graph, determining how the distribution is affected to changes in the state dual graph. Raises: RuntimeError if PROPOSAL_TYPE of config file is neither 'sierpinski' nor 'convex' """ output_directory = createDirectory(config) epsilon = config["epsilon"] k = config["NUM_DISTRICTS"] updaters = {'population': Tally('population'), 'cut_edges': cut_edges, "Blue-Red": Election("Blue-Red", {"Blue": "blue", "Red": "red"}) } graph, dual = preprocessing(output_directory) cddict = {x: int(x[0] / gn) for x in graph.nodes()} plt.figure() nx.draw( graph, pos={x: x for x in graph.nodes()}, node_color=[cddict[x] for x in graph.nodes()], node_size=ns, node_shape="s", cmap="tab20", ) plt.show() ideal_population = sum(graph.nodes[x]["population"] for x in graph.nodes()) / k faces = graph.graph["faces"] faces = list(faces) square_faces = [face for face in faces if len(face) == 4] totpop = 0 for node in graph.nodes(): totpop += int(graph.nodes[node]['population']) # length of chain steps = config["CHAIN_STEPS"] # length of each gerrychain step gerrychain_steps = config["GERRYCHAIN_STEPS"] # faces that are currently modified. Code maintains list of modified faces, and at each step selects a face. if face is already in list, # the face is un-modified, and if it is not, the face is modified by the specified proposal type. special_faces = set([face for face in square_faces if np.random.uniform(0, 1) < .5]) #chain_output = {'dem_seat_data': [], 'rep_seat_data': [], 'score': []} chain_output = defaultdict(list) # start with small score to move in right direction print("Choosing", math.floor(len(faces) * config['PERCENT_FACES']), "faces of the dual graph at each step") max_score = -math.inf # this is the main markov chain for i in tqdm.tqdm(range(1, steps + 1), ncols=100, desc="Chain Progress"): special_faces_proposal = copy.deepcopy(special_faces) proposal_graph = copy.deepcopy(graph) if (config["PROPOSAL_TYPE"] == "sierpinski"): for i in range(math.floor(len(faces) * config['PERCENT_FACES'])): face = random.choice(faces) ##Makes the Markov chain lazy -- this just makes the chain aperiodic. if random.random() > .5: if not (face in special_faces_proposal): special_faces_proposal.append(face) else: special_faces_proposal.remove(face) chain_on_subsets_of_faces.face_sierpinski_mesh(proposal_graph, special_faces_proposal) elif (config["PROPOSAL_TYPE"] == "add_edge"): for j in range(math.floor(len(square_faces) * config['PERCENT_FACES'])): face = random.choice(square_faces) ##Makes the Markov chain lazy -- this just makes the chain aperiodic. if random.random() > .5: if not (face in special_faces_proposal): special_faces_proposal.add(face) else: special_faces_proposal.remove(face) chain_on_subsets_of_faces.add_edge_proposal(proposal_graph, special_faces_proposal) else: raise RuntimeError('PROPOSAL TYPE must be "sierpinski" or "convex"') initial_partition = Partition(proposal_graph, assignment=cddict, updaters=updaters) # Sets up Markov chain popbound = within_percent_of_ideal_population(initial_partition, epsilon) tree_proposal = partial(recom, pop_col=config['POP_COL'], pop_target=ideal_population, epsilon=epsilon, node_repeats=1) # make new function -- this computes the energy of the current map exp_chain = MarkovChain(tree_proposal, Validator([popbound]), accept=accept.always_accept, initial_state=initial_partition, total_steps=gerrychain_steps) seats_won_for_republicans = [] seats_won_for_democrats = [] for part in exp_chain: for u, v in part["cut_edges"]: proposal_graph[u][v]["cut_times"] += 1 rep_seats_won = 0 dem_seats_won = 0 for j in range(k): rep_votes = 0 dem_votes = 0 for n in graph.nodes(): if part.assignment[n] == j: rep_votes += graph.nodes[n]["blue"] dem_votes += graph.nodes[n]["red"] total_seats_dem = int(dem_votes > rep_votes) total_seats_rep = int(rep_votes > dem_votes) rep_seats_won += total_seats_rep dem_seats_won += total_seats_dem seats_won_for_republicans.append(rep_seats_won) seats_won_for_democrats.append(dem_seats_won) seat_score = statistics.mean(seats_won_for_republicans) # implement mattingly simulated annealing scheme, from evaluating partisan gerrymandering in wisconsin if i <= math.floor(steps * .67): beta = i / math.floor(steps * .67) else: beta = (i / math.floor(steps * 0.67)) * 100 temperature = 1 / (beta) weight_seats = 1 weight_flips = -.2 config['PERCENT_FACES'] = config['PERCENT_FACES'] # what is this? flip_score = len(special_faces) # This is the number of edges being swapped score = weight_seats * seat_score + weight_flips * flip_score ##This is the acceptance step of the Metropolis-Hasting's algorithm. Specifically, rand < min(1, P(x')/P(x)), where P is the energy and x' is proposed state # if the acceptance criteria is met or if it is the first step of the chain def update_outputs(): chain_output['dem_seat_data'].append(seats_won_for_democrats) chain_output['rep_seat_data'].append(seats_won_for_republicans) chain_output['score'].append(score) chain_output['seat_score'].append(seat_score) chain_output['flip_score'].append(flip_score) def propagate_outputs(): for key in chain_output.keys(): chain_output[key].append(chain_output[key][-1]) if i == 1: update_outputs() special_faces = copy.deepcopy(special_faces_proposal) # this is the simplified form of the acceptance criteria, for intuitive purposes # exp((1/temperature) ( proposal_score - previous_score)) elif np.random.uniform(0, 1) < (math.exp(score) / math.exp(chain_output['score'][-1])) ** (1 / temperature): update_outputs() special_faces = copy.deepcopy(special_faces_proposal) else: propagate_outputs() # if score is highest seen, save map. if score > max_score: # todo: all graph coloring for graph changes that produced this score nx.write_gpickle(proposal_graph, "obj/graphs/"+str(score)+'sc_'+str(config['CHAIN_STEPS'])+'mcs_'+ str(config["GERRYCHAIN_STEPS"])+ "gcs_" + config['PROPOSAL_TYPE']+'_'+ str(len(special_faces)), pickle.HIGHEST_PROTOCOL) save_obj(special_faces, output_directory, 'north_carolina_highest_found') nx.write_gpickle(proposal_graph, output_directory + '/' + "max_score", pickle.HIGHEST_PROTOCOL) f=open(output_directory + "/max_score_data.txt","w+") f.write("maximum score: " + str(score) + "\n" + "edges changed: " + str(len(special_faces)) + "\n" + "Seat Score: " + str(seat_score)) save_obj(special_faces, output_directory + '/', "special_faces") max_score = score plt.plot(range(len(chain_output['score'])), chain_output['score']) plt.xlabel("Meta-Chain Step") plt.ylabel("Score") plt.show() plt.close() plt.plot(range(len(chain_output['seat_score'])), chain_output['seat_score']) plt.xlabel("Meta-Chain Step") plt.ylabel("Number of average seats republicans won") plt.show() plt.close()
#########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= []
def run_ensemble_on_distro(graph, min_pop_col, maj_pop_col, tot_pop_col, num_districts, initial_plan, num_steps, pop_tol = 0.05, min_win_thresh = 0.5): """Runs a Recom chain on a given graph with a given minority/majority population distribution and returns lists of cut edges, minority seat wins, and tuples of minority percentage by district for each step of the chain. Parameters: graph (networkx.Graph) -- a NetworkX graph object representing the dual graph on which to run the chain. The nodes should have attributes for majority population, minority population, and total population. min_pop_col (string) -- the key/column name for the minority population attribute in graph maj_pop_col (string) -- the key/column name for the majority population attribute in graph tot_pop_col (string) -- the key/column name for the total population attribute in graph num_districts (int) -- number of districts to run for the chain initial_plan (gerrychain.Partition) -- an initial partition for the chain (which does not need updaters since the function will supply its own updaters) num_steps (int) -- the number of steps for which to run the chain pop_tol (float, default 0.05) -- tolerance for deviation from perfectly balanced populations between districts min_win_thresh (float, default 0.5) -- percent of minority population needed in a district for it to be considered a minority win. If the minority percentage in a district is greater than or equal to min_win_thresh then that district is considered a minority win. Returns: [cut_edges_list,min_seats_list,min_percents_list] (list) WHERE cut_edges_list (list) -- list where cut_edges_list[i] is the number of cut edges in the partition at step i of the Markov chain min_seats_list -- list where min_seats_list[i] is the number of districts won by the minority (according to min_win_thresh) at step i of the chain min_percents_list -- list where min_percents_list[i] is a tuple, with min_percents_list[i][j] being the minority percentage in district j at step i of the chain """ my_updaters = { "population": Tally(tot_pop_col, alias = "population"), "cut_edges": cut_edges, "maj-min": Election("maj-min", {"maj": maj_pop_col, "min": min_pop_col}), } initial_partition = Partition(graph = initial_plan.graph, assignment = initial_plan.assignment, updaters = my_updaters) # ADD CONSTRAINTS popbound = within_percent_of_ideal_population(initial_partition, 0.1) # ########Setup Proposal ideal_population = sum(initial_partition["population"].values()) / len(initial_partition) tree_proposal = partial( recom, pop_col=tot_pop_col, pop_target=ideal_population, epsilon=pop_tol, node_repeats=1, ) # ######BUILD MARKOV CHAINS recom_chain = MarkovChain( tree_proposal, Validator([popbound]), accept=always_accept, initial_state=initial_partition, total_steps=num_steps, ) cut_edges_list = [] min_seats_list = [] min_percents_list = [] for part in recom_chain: cut_edges_list.append(len(part["cut_edges"])) min_percents_list.append(part["maj-min"].percents("min")) min_seats = (np.array(part["maj-min"].percents("min")) >= min_win_thresh).sum() min_seats_list.append(min_seats) return [cut_edges_list,min_seats_list,min_percents_list]
def run_chain(init_part, chaintype, length, ideal_population, id): """Runs a Recom chain, and saves the seats won histogram to a file and returns the most Gerrymandered plans for both PartyA and PartyB Args: init_part (Gerrychain Partition): initial partition of chain chaintype (String): indicates which proposal to be used to generate spanning tree during Recom. Must be either "tree" or "uniform_tree" length (int): total steps of chain id (String): id of experiment, used when printing progress Raises: RuntimeError: If chaintype is not "tree" nor 'uniform_tree" Returns: list of partitions generated by chain """ graph = init_part.graph popbound = within_percent_of_ideal_population(init_part, config['EPSILON']) # Determine proposal for generating spanning tree based upon parameter if chaintype == "tree": tree_proposal = partial( recom, pop_col=config["POP_COL"], pop_target=ideal_population, epsilon=config['EPSILON'], node_repeats=config['NODE_REPEATS'], method=facefinder.my_mst_bipartition_tree_random) elif chaintype == "uniform_tree": tree_proposal = partial( recom, pop_col=config["POP_COL"], pop_target=ideal_population, epsilon=config['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") # Chain to be run chain = MarkovChain(tree_proposal, Validator([popbound]), accept=accept.always_accept, initial_state=init_part, total_steps=length) electionDict = { 'seats': (lambda x: x[config['ELECTION_NAME']].seats('PartyA')), 'won': (lambda x: x[config['ELECTION_NAME']].seats('PartyA')), 'efficiency_gap': (lambda x: x[config['ELECTION_NAME']].efficiency_gap()), 'mean_median': (lambda x: x[config['ELECTION_NAME']].mean_median()), 'mean_thirdian': (lambda x: x[config['ELECTION_NAME']].mean_thirdian()), 'partisan_bias': (lambda x: x[config['ELECTION_NAME']].partisan_bias()), 'partisan_gini': (lambda x: x[config['ELECTION_NAME']].partisan_gini()) } # Run chain, save each desired statistic, and keep track of cuts. Save most # left gerrymandered partition statistics = {statistic: [] for statistic in config['ELECTION_STATISTICS']} for i, partition in enumerate(chain): # Save statistics of partition for statistic in config['ELECTION_STATISTICS']: statistics[statistic].append(electionDict[statistic](partition)) if i % 500 == 0: print('{}: {}'.format(id, i)) saveRunStatistics(statistics, id)
def run_experiment(bases=[2 * 2.63815853], pops=[.1], time_between_outputs=10000, total_run_length=100000000000000): mu = 2.63815853 subsequence_step_size = 10000 balances_burn_in = 1000000 #ignore the first 10000 balances # creating the boundary figure plot plt.figure() fig = plt.figure() #fig_intervals = plt.figure() #ax2=fig.add_axes([0,0,1,1]) ax = plt.subplot(111, projection='polar') #ax.set_axis_off() #ax.xaxis.set_ticklabels([]) ax.yaxis.set_ticklabels([]) for pop1 in pops: for base in bases: for alignment in [1]: gn = 20 k = 2 ns = 120 p = .5 graph = nx.grid_graph([k * gn, k * gn]) ########## BUILD ASSIGNMENT #cddict = {x: int(x[0]/gn) for x in graph.nodes()} cddict = {x: 1 - 2 * int(x[0] / gn) for x in graph.nodes()} for n in graph.nodes(): if alignment == 0: if n[0] > 19: cddict[n] = 1 else: cddict[n] = -1 elif alignment == 1: if n[1] > 19: cddict[n] = 1 else: cddict[n] = -1 elif alignment == 2: if n[0] > n[1]: cddict[n] = 1 elif n[0] == n[1] and n[0] > 19: cddict[n] = 1 else: cddict[n] = -1 elif alignment == 10: #This is for debugging the case of reaching trivial partitions. if n[0] == 10 and n[1] == 10: cddict[n] = 1 else: cddict[n] = -1 for n in graph.nodes(): graph.nodes[n]["population"] = 1 graph.nodes[n]["part_sum"] = cddict[n] graph.nodes[n]["last_flipped"] = 0 graph.nodes[n]["num_flips"] = 0 if random.random() < p: graph.nodes[n]["pink"] = 1 graph.nodes[n]["purple"] = 0 else: graph.nodes[n]["pink"] = 0 graph.nodes[n]["purple"] = 1 if 0 in n or k * gn - 1 in n: graph.nodes[n]["boundary_node"] = True graph.nodes[n]["boundary_perim"] = 1 else: graph.nodes[n]["boundary_node"] = False #graph.add_edges_from([((0,1),(1,0)), ((0,38),(1,39)), ((38,0),(39,1)), ((38,39),(39,38))]) for edge in graph.edges(): graph[edge[0]][edge[1]]['cut_times'] = 0 #this part adds queen adjacency #for i in range(k*gn-1): # for j in range(k*gn): # if j<(k*gn-1): # graph.add_edge((i,j),(i+1,j+1)) # graph[(i,j)][(i+1,j+1)]["shared_perim"]=0 # if j >0: # graph.add_edge((i,j),(i+1,j-1)) # graph[(i,j)][(i+1,j-1)]["shared_perim"]=0 #graph.remove_nodes_from([(0,0),(0,39),(39,0),(39,39)]) #del cddict[(0,0)] #del cddict[(0,39)] # cddict[(39,0)] #del cddict[(39,39)] ######PLOT GRIDS """ plt.figure() nx.draw(graph, pos = {x:x for x in graph.nodes()} ,node_size = ns, node_shape ='s') plt.show() cdict = {1:'pink',0:'purple'} plt.figure() nx.draw(graph, pos = {x:x for x in graph.nodes()}, node_color = [cdict[graph.nodes[x]["pink"]] for x in graph.nodes()],node_size = ns, node_shape ='s' ) plt.show() plt.figure() nx.draw(graph, pos = {x:x for x in graph.nodes()}, node_color = [cddict[x] for x in graph.nodes()] ,node_size = ns, node_shape ='s',cmap = 'tab20') plt.show() """ ####CONFIGURE UPDATERS def new_base(partition): return base def step_num(partition): parent = partition.parent if not parent: return 0 return parent["step_num"] + 1 bnodes = [ x for x in graph.nodes() if graph.nodes[x]["boundary_node"] == 1 ] def bnodes_p(partition): return [ x for x in graph.nodes() if graph.nodes[x]["boundary_node"] == 1 ] updaters = { 'population': Tally('population'), "boundary": bnodes_p, #"slope": boundary_slope, 'cut_edges': cut_edges, 'step_num': step_num, 'b_nodes': b_nodes_bi, 'base': new_base, 'geom': geom_wait, #"Pink-Purple": Election("Pink-Purple", {"Pink":"pink","Purple":"purple"}) } balances = [] #########BUILD PARTITION grid_partition = Partition(graph, assignment=cddict, updaters=updaters) #ADD CONSTRAINTS popbound = within_percent_of_ideal_population( grid_partition, pop1) #plt.figure() #nx.draw(graph, pos = {x:x for x in graph.nodes()}, node_color = [dict(grid_partition.assignment)[x] for x in graph.nodes()] ,node_size = ns, node_shape ='s',cmap = 'tab20') #plt.savefig("./plots/"+str(alignment)+"B"+str(int(100*base))+"P"+str(int(100*pop1))+"start.png") #plt.close() #########Setup Proposal ideal_population = sum(grid_partition["population"].values() ) / len(grid_partition) tree_proposal = partial(recom, pop_col="population", pop_target=ideal_population, epsilon=pop1, 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=total_run_length) #########Run MARKOV CHAINS rsw = [] rmm = [] reg = [] rce = [] rbn = [] waits = [] slopes = [] angles = [] angles_safe = [] ends_vectors_normalized = LinkedList() ends_vectors_normalized_bloated = LinkedList() import time st = time.time() total_waits = 0 last_total_waits = 0 t = 0 subsequence_timer = 0 balances = {} for b in np.linspace(0, 2, 100001): balances[int(b * 100) / 100] = 0 #first_partition = True for part in exp_chain: rce.append(len(part["cut_edges"])) wait_time_rv = part.geom waits.append(wait_time_rv) total_waits += wait_time_rv rbn.append(len(list(part["b_nodes"]))) if total_waits > subsequence_timer + subsequence_step_size: last_total_waits = total_waits ends = boundary_ends(part) if len(ends) == 2: ends_vector = np.asarray(ends[1]) - np.asarray( ends[0]) ends_vector_normalized = ends_vector / np.linalg.norm( ends_vector) #if first_partition == True: # ends_vectors_normalized.last_vector = ends_vector_normalized # first_partition = False if ends_vectors_normalized.last: # We choose the vector that preserves continuity # previous_angle = ends_vectors_normalized.last_value() previous = ends_vectors_normalized.last_vector d_previous = np.linalg.norm( previous - ends_vector_normalized) d_previous_neg = np.linalg.norm( previous + ends_vector_normalized) if d_previous < d_previous_neg: continuous_lift = ends_vector_normalized else: continuous_lift = -1 * ends_vector_normalized #print(previous, ends_vector_normalized) else: continuous_lift = ends_vector_normalized # *random.choice([-1,1]) # just to debias it, in the regime of very unbalanced partitions # that touch the empty partition frequently else: continuous_lift = [0, 0] ##############For Debugging############# ''' if total_waits > subsequence_timer + subsequence_step_size: last_total_waits = total_waits ends = boundary_ends(part) if ends: ends_vector = np.asarray(ends[1]) - np.asarray(ends[0]) ends_vector_normalized = ends_vector / np.linalg.norm(ends_vector) if ends_vectors_normalized_bloated.last: # We choose the vector that preserves continuity previous = ends_vectors_normalized_bloated.last_value() d_previous = np.linalg.norm( ends_vector_normalized - previous) d_previous_neg = np.linalg.norm( ends_vector_normalized + previous ) if d_previous < d_previous_neg: continuous_lift_bloated = ends_vector_normalized else: continuous_lift_bloated = -1* ends_vector_normalized else: continuous_lift_bloated = ends_vector_normalized # *random.choice([-1,1]) # just to debias it, in the regime of very unbalanced partitions # that touch the empty partition frequently else: continuous_lift_bloated = [0,0] ''' ################ # Pop balance stuff: left_pop, right_pop = part["population"].values() ideal_population = (left_pop + right_pop) / 2 left_bal = (left_pop / ideal_population) right_bal = (right_pop / ideal_population) while subsequence_timer < total_waits: subsequence_timer += subsequence_step_size if (continuous_lift == np.asarray([0, 0])).all(): lifted_angle = False print("false") draw_other_plots(balances, graph, alignment, "NonSimplyConnected", base, pop1, part, ns) #Flag to hold the exceptional case of the boundary vanishing else: lifted_angle = np.arctan2( continuous_lift[1], continuous_lift[0]) #+ np.pi ends_vectors_normalized.last_vector = continuous_lift ends_vectors_normalized.append(lifted_angle) if subsequence_timer > balances_burn_in: left_bal_rounded = int(left_bal * 100) / 100 right_bal_rounded = int(right_bal * 100) / 100 balances[ left_bal_rounded] += 1 #left_bal_rounded balances[ right_bal_rounded] += 1 # right_bal_rounded #NB wait times are accounted for by the while loops for edge in part["cut_edges"]: graph[edge[0]][edge[1]]["cut_times"] += wait_time_rv #print(graph[edge[0]][edge[1]]["cut_times"]) if part.flips is not None: f = list(part.flips.keys())[0] graph.nodes[f]["part_sum"] = graph.nodes[f][ "part_sum"] - part.assignment[f] * ( total_waits - graph.nodes[f]["last_flipped"]) graph.nodes[f]["last_flipped"] = total_waits graph.nodes[f]["num_flips"] = graph.nodes[f][ "num_flips"] + wait_time_rv t += 1 if t % time_between_outputs == 0: #ends_vectors_normalized[1:] #Remove the first one because it will overlap with last one of previous dump identifier_string = "state_after_num_steps" + str( t) + "and_time" + str(st - time.time()) #print("finished no", st-time.time()) with open( "./plots/" + str(alignment) + "B" + str(int(100 * base)) + "P" + str(int(100 * pop1)) + "wait.txt", 'w') as wfile: wfile.write(str(sum(waits))) #with open("./plots/"+str(alignment)+"B"+str(int(100*base))+"P"+str(int(100*pop1)) + "ends_vectors.txt",'w') as wfile: # wfile.write(str(ends_vectors_normalized)) #with open("./plots/"+str(alignment)+"B"+str(int(100*base))+"P"+str(int(100*pop1)) + "ends_vectors.pkl",'wb') as wfile: # pickle.dump(ends_vectors_normalized, wfile) with open( "./plots/" + str(alignment) + "B" + str(int(100 * base)) + "P" + str(int(100 * pop1)) + "balances.txt", 'w') as wfile: wfile.write(str(balances)) with open( "./plots/" + str(alignment) + "B" + str(int(100 * base)) + "P" + str(int(100 * pop1)) + "balances.pkl", 'wb') as wfile: pickle.dump(balances, wfile) for n in graph.nodes(): if graph.nodes[n]["last_flipped"] == 0: graph.nodes[n][ "part_sum"] = total_waits * part.assignment[ n] graph.nodes[n]["lognum_flips"] = math.log( graph.nodes[n]["num_flips"] + 1) total_part_sum = 0 for n in graph.nodes(): total_part_sum += graph.nodes[n]["part_sum"] for n in graph.nodes(): if total_part_sum != 0: graph.nodes[n][ "normalized_part_sum"] = graph.nodes[n][ "part_sum"] / total_part_sum else: graph.nodes[n]["normalized_part_sum"] = 0 #print(len(rsw[-1])) #print(graph[(1,0)][(0,1)]["cut_times"]) print("creating boundary plot, ", time.time()) max_time = ends_vectors_normalized.last.end_time non_simply_connected_intervals = [ [x.start_time, x.end_time] for x in ends_vectors_normalized if type(x.data) == bool ] for x in ends_vectors_normalized: if type(x.data) != bool: #times = np.linspace(x.start_time, x.end_time, 100) #times.append(x.end_time) times = [x.start_time, x.end_time] angles = [x.data] * len(times) plt.polar(angles, times, lw=.1, color='b') next_point = x.next #''' if next_point != None: if type(next_point.data) != bool: if np.abs( (x.data - next_point.data)) % ( 2 * np.pi) < .1: # added that last if to avoid # the big jumps that happen with # small size subcritical plt.polar( [x.data, next_point.data], [ x.end_time, next_point.start_time ], lw=.1, color='b') #''' # Create the regular segments corresponding to time ''' for k in range(11): plt.polar ( np.arange(0, (2 * np.pi), 0.01), [int(max_time/10) * k ] * len( np.arange(0, (2 * np.pi), 0.01)), lw = .2, color = 'g' ) ''' # Create the intervals representing when the partition is null. # Removing these might be just as good, and a little cleaner. #''' for interval in non_simply_connected_intervals: start = interval[0] end = interval[1] for s in np.linspace(start, end, 10): plt.polar( np.arange(0, (2 * np.pi), 0.01), s * np.ones( len(np.arange(0, (2 * np.pi), 0.01))), lw=.3, color='r') #''' #plt.savefig("./plots/"+str(alignment)+"B"+str(int(100*base))+"P"+str(int(100*pop1)) + str("proposals_") + str( max_time * subsequence_step_size ) + "boundary_slope.svg") plt.savefig("./plots/" + str(alignment) + "B" + str(int(100 * base)) + "P" + str(int(100 * pop1)) + str("proposals_") + identifier_string + "boundary_slope.png", dpi=500) # now clear the ends vectors list last = ends_vectors_normalized.last last_non_zero = ends_vectors_normalized.last_non_zero last_vector = ends_vectors_normalized.last_vector # Explicit Garbage collection https://stackoverflow.com/questions/1316767/how-can-i-explicitly-free-memory-in-python print( "finished boundary plot, doing garbage collection", time.time()) del ends_vectors_normalized gc.collect() ends_vectors_normalized = LinkedList() ends_vectors_normalized.head = last ends_vectors_normalized.last = last ends_vectors_normalized.last_non_zero = last_non_zero # can be ahead of head... ends_vectors_normalized.last_vector = last_vector #print(last) print("drawing other plots", time.time()) draw_other_plots(balances, graph, alignment, identifier_string, base, pop1, part, ns) print("finished drawing other plots, ", time.time())