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 initial_partition(disc):

    updaters = {
        'population': Tally('population'),
        'base': new_base,
        'b_nodes': b_nodes_bi,
        'cut_edges': cut_edges,
        "boundary": bnodes_p,
        'step_num': step_num,
        'geom': geom_wait,
    }

    assignment = {}
    for x in disc.nodes():

        if x[0] > 0:
            assignment[x] = 1
        else:
            assignment[x] = -1

    #b_nodes = {(x[0], partition.assignment[x[1]]) for x in partition["cut_edges"]}.union({(x[1], partition.assignment[x[0]]) for x in partition["cut_edges"]})

    partition = Partition(disc, assignment, updaters=updaters)

    return partition
def buildPartition(graph, mean):
    """
    The function build 2 partition based on x coordinate value
    Parameters:
        graph (Graph): The given graph represent state information
        mean (int): the value to determine partition
    Returns:
        Partition: the partitions of the graph based on mean value
    """
    assignment = {}

    # assign node into different partition based on x coordinate
    for x in graph.node():
        if graph.node[x]['C_X'] < mean:
            assignment[x] = -1
        else:
            assignment[x] = 1

    updaters = {
        'population': Tally('population'),
        "boundary": bnodes_p,
        'cut_edges': cut_edges,
        'step_num': step_num,
        'b_nodes': b_nodes_bi,
        'base': new_base,
        'geom': geom_wait,
    }

    grid_partition = Partition(graph, assignment=assignment, updaters=updaters)
    return grid_partition
Exemple #4
0
def metamander_around_partition(graph, dual, target_partition, tag):
    updaters = {'population': Tally('population'),
                        'cut_edges': cut_edges,
                        'step_num': step_num,
                        }
    
    assignment = {}
    for x in graph.nodes():
        color = 0
        for block in target_partition.keys():
            if x in target_partition[block]:
                assignment[x] = color
            color += 1
    
    target_partition = Partition(graph, assignment, updaters = updaters)
    plt.figure()
    
    viz(graph, set([]), target_partition.parts)
    plt.savefig("./plots/target_map" + tag + ".png", format = 'png')
    plt.close()
    
    print("made partition")
    crosses = compute_cross_edge(graph, target_partition)
    
    k = len(target_partition.parts)
    
    dual_crosses = []
    for edge in dual.edges:
        if dual.edges[edge]["original_name"] in crosses:
            dual_crosses.append(edge)
            
    print("making dual distances")
    dual = distance_from_partition(dual, dual_crosses)
    print('finished making dual distances')
    special_faces = assign_special_faces(dual,2)
    print('finished assigning special faces')
    g_sierpinsky = face_sierpinski_mesh(graph, special_faces)
    print("made metamander")
    # change from RVAP and UVAP to approprate election data columns 
    for node in g_sierpinsky:
        g_sierpinsky.nodes[node]['C_X'] = g_sierpinsky.nodes[node]['pos'][0]
        g_sierpinsky.nodes[node]['C_Y'] = g_sierpinsky.nodes[node]['pos'][1]
        if 'population' not in g_sierpinsky.nodes[node]:
            g_sierpinsky.nodes[node]['population'] = 0
        if 'EL16G_PR_D' not in g_sierpinsky.nodes[node]:
            g_sierpinsky.nodes[node]['EL16G_PR_D'] = 0
        if 'EL16G_PR_R' not in g_sierpinsky.nodes[node]:
            g_sierpinsky.nodes[node]['EL16G_PR_R'] = 0
        ##Need to add the voting data
    total_pop = sum( [ g_sierpinsky.nodes[node]['population'] for node in g_sierpinsky])
    
    #sierp_partition = build_trivial_partition(g_sierpinsky)
    
    plt.figure()
    nx.draw(g_sierpinsky, pos=nx.get_node_attributes(g_sierpinsky, 'pos'), node_size = 1, width = 1, cmap=plt.get_cmap('jet'))
    plt.savefig("./plots/sierpinsky_mesh.png", format='png')
    plt.close()
    
    left_mander, right_mander = produce_sample(g_sierpinsky, k , tag)
Exemple #5
0
def build_balanced_k_partition(graph, k, pop_col, pop_target, epsilon):
    
    assignment = recursive_tree_part(graph, k, pop_target, pop_col, epsilon)
    updaters = {'population': Tally('population'),
                        'cut_edges': cut_edges,
                        'step_num': step_num,
                        }
    partition = Partition(graph, assignment=assignment, updaters=updaters)
    return partition
def main(config_data, id):
    try:
        timeBeg = time.time()
        print('Experiment', id, 'has begun')
        # Save configuration into global variable
        global config
        config = config_data

        graph = Graph.from_json(config['INPUT_GRAPH_FILENAME'])

        # List of districts in original graph
        parts = list(
            set([
                graph.nodes[node][config['ASSIGN_COL']]
                for node in graph.nodes()
            ]))
        # Ideal population of districts
        ideal_pop = sum(
            [graph.nodes[node][config['POP_COL']]
             for node in graph.nodes()]) / len(parts)

        election = Election(config['ELECTION_NAME'], {
            'PartyA': config['PARTY_A_COL'],
            'PartyB': config['PARTY_B_COL']
        })

        updaters = {
            'population': Tally(config['POP_COL']),
            'cut_edges': cut_edges,
            config['ELECTION_NAME']: election
        }

        partDict = recursive_tree_part(graph, parts, ideal_pop,
                                       config['POP_COL'], config['EPSILON'],
                                       config['NODE_REPEATS'])
        for node in graph.nodes():
            graph.nodes[node][config['ASSIGN_COL']] = partDict[node]
        part = Partition(graph=graph,
                         assignment=config['ASSIGN_COL'],
                         updaters=updaters)
        for len_ in config['RUN_LENGTHS']:
            for num in range(config['RUNS_PER_LEN']):
                run_chain(part, config['CHAIN_TYPE'], len_, ideal_pop,
                          '{}_{}_{}_{}'.format(config['TAG'], id, len_, num))

        print('Experiment {} completed in {} seconds'.format(
            id,
            time.time() - timeBeg))

    except Exception as e:
        # Print notification if any experiment fails to complete
        track = traceback.format_exc()
        print(track)
        print('Experiment {} failed to complete after {:.2f} seconds'.format(
            id,
            time.time() - timeBeg))
def test_tally_multiple_columns(graph_with_d_and_r_cols):
    graph = graph_with_d_and_r_cols

    updaters = {"total": Tally(["D", "R"], alias="total")}
    assignment = {i: 1 if i in range(4) else 2 for i in range(9)}

    partition = Partition(graph, assignment, updaters)
    expected_total_in_district_one = sum(
        graph.nodes[i]["D"] + graph.nodes[i]["R"] for i in range(4))
    assert partition["total"][1] == expected_total_in_district_one
def test_tally_multiple_columns(graph_with_d_and_r_cols):
    graph = graph_with_d_and_r_cols

    updaters = {'total': Tally(['D', 'R'], alias='total')}
    assignment = {i: 1 if i in range(4) else 2 for i in range(9)}

    partition = Partition(graph, assignment, updaters)
    expected_total_in_district_one = sum(
        graph.nodes[i]['D'] + graph.nodes[i]['R'] for i in range(4))
    assert partition['total'][1] == expected_total_in_district_one
Exemple #9
0
def test_recursive_seed_part_returns_within_epsilon_of_target_pop(twelve_by_twelve_with_pop):
    n_districts = 7  # 144/7 ≈ 20.5 nodes/subgraph (1 person/node)
    ideal_pop = (sum(twelve_by_twelve_with_pop.nodes[node]["pop"]
                     for node in twelve_by_twelve_with_pop)) / n_districts
    epsilon = 0.1
    result = recursive_seed_part(twelve_by_twelve_with_pop, range(n_districts),
                                 ideal_pop, "pop", epsilon, n=5, ceil=None)
    partition = Partition(twelve_by_twelve_with_pop, result,
                          updaters={"pop": Tally("pop")})
    return all(abs(part_pop - ideal_pop) / ideal_pop < epsilon
               for part_pop in partition['pop'].values())
Exemple #10
0
def build_trivial_partition(graph):
    assignment = {}
    for y in graph.nodes():
        assignment[y] = 1
    first_node = list(graph.nodes())[0]
    assignment[first_node] = -1
    updaters = {'population': Tally('population'),
                        'cut_edges': cut_edges,
                        'step_num': step_num,
                        }
    partition = Partition(graph, assignment=assignment, updaters=updaters)
    return partition
Exemple #11
0
def build_partition_meta(graph, mean):
    assignment = {}
    for y in graph.nodes():
        if graph.nodes[y]['C_Y'] < mean:
            assignment[y] = -1
        else:
            assignment[y] = 1
    updaters = {'population': Tally('population'),
                        'cut_edges': cut_edges,
                        'step_num': step_num,
                        }
    partition = Partition(graph, assignment=assignment, updaters=updaters)
    print("cut edges are", partition["cut_edges"])
    return partition
Exemple #12
0
class GeographicPartition(Partition):
    """A :class:`Partition` with areas, perimeters, and boundary information included.
    These additional data allow you to compute compactness scores like
    `Polsby-Popper <https://en.wikipedia.org/wiki/Polsby-Popper_Test>`_.
    """

    default_updaters = {
        "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,
    }
Exemple #13
0
def build_balanced_partition(graph, pop_col, pop_target, epsilon):
    
    block = my_mst_bipartition_tree_random(graph, pop_col, pop_target, epsilon)
    assignment = {}
    for y in graph.nodes():
        if y in block:
            assignment[y] = 1
        else:
            assignment[y] = -1
    updaters = {'population': Tally('population'),
                        'cut_edges': cut_edges,
                        'step_num': step_num,
                        }
    partition = Partition(graph, assignment=assignment, updaters=updaters)
    return partition
def test_Partition_can_update_stats():
    graph = networkx.complete_graph(3)
    assignment = {0: 1, 1: 1, 2: 2}

    graph.nodes[0]['stat'] = 1
    graph.nodes[1]['stat'] = 2
    graph.nodes[2]['stat'] = 3

    updaters = {'total_stat': Tally('stat', alias='total_stat')}

    partition = Partition(graph, assignment, updaters)
    assert partition['total_stat'][2] == 3
    flip = {1: 2}

    new_partition = partition.merge(flip)
    assert new_partition['total_stat'][2] == 5
def test_Partition_can_update_stats():
    graph = networkx.complete_graph(3)
    assignment = {0: 1, 1: 1, 2: 2}

    graph.nodes[0]["stat"] = 1
    graph.nodes[1]["stat"] = 2
    graph.nodes[2]["stat"] = 3

    updaters = {"total_stat": Tally("stat", alias="total_stat")}

    partition = Partition(graph, assignment, updaters)
    assert partition["total_stat"][2] == 3
    flip = {1: 2}

    new_partition = partition.flip(flip)
    assert new_partition["total_stat"][2] == 5
Exemple #16
0
def build_partition(graph):

    partition_dict = {}
    partition_block = my_mst_kpartition_tree_random(graph, pop_col="population", pop_target=0, epsilon=0.05,
                                                num_blocks=8, node_repeats=1, spanning_tree=None,
                                                choice=random.choice)
    for n in graph.nodes:
        for x in range(len(partition_block)):
            if n in partition_block[x]:
                partition_dict[n] = x

    updaters = {'population': Tally('population'),
            'cut_edges': cut_edges,
            'step_num': step_num,
            'base': new_base,
            }
    grid_partition = Partition(graph, assignment=partition_dict, updaters=updaters)
    return grid_partition, partition_dict
Exemple #17
0
def partition_with_pop(graph_with_pop):
    return Partition(
        graph_with_pop,
        {
            0: 0,
            1: 0,
            2: 0,
            3: 0,
            4: 0,
            5: 1,
            6: 1,
            7: 1,
            8: 1
        },
        updaters={
            "pop": Tally("pop"),
            "cut_edges": cut_edges
        },
    )
def buildPartition(graph, mean):
    # horizontal = []
    assignment = {}
    for x in graph.node():
        if graph.node[x]['C_X'] < mean:
            assignment[x] = -1
        else:
            assignment[x] = 1

    updaters = {
        'population': Tally('population'),
        "boundary": bnodes_p,
        'cut_edges': cut_edges,
        'step_num': step_num,
        'b_nodes': b_nodes_bi,
        'base': new_base,
        'geom': geom_wait,
    }

    grid_partition = Partition(graph, assignment=assignment, updaters=updaters)
    return grid_partition
Exemple #19
0
class GeographicPartition(Partition):
    """A :class:`Partition` with areas, perimeters, and boundary information included.
    These additional data allow you to compute compactness scores like
    `Polsby-Popper_ <https://en.wikipedia.org/wiki/Polsby-Popper_Test>`.
    """

    default_updaters = {
        "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,
    }

    @classmethod
    def from_file(cls, filename, assignment, updaters, columns=None):
        """Create a :class:`GeographicPartition` from an ESRI Shapefile, a GeoPackage,
        a GeoJSON file, or any other file that the `fiona` library can handle.
        """
        graph = Graph.from_file(filename, columns)
        cls(graph, assignment, updaters)
graph = nx.relabel_nodes(graph, df[uid])

elections = [
    Election("PRES16", {
        "Democratic": "PRES16D",
        "Republican": "PRES16R"
    }),
    Election("SEN16", {
        "Democratic": "SEN16D",
        "Republican": "SEN16R"
    })
]

#my_updaters = {"population" : updaters.Tally("TOTPOP", alias="population")}
my_updaters = {
    "population": Tally(pop_col, alias="population"),
    "cpop": Tally(ccol, alias="cpop"),
    "cut_edges": cut_edges
}
election_updaters = {election.name: election for election in elections}
my_updaters.update(election_updaters)

tot_pop_col = 0
tot_ccol = 0
#for tallying over totpop:
for n in graph.nodes():
    graph.node[n][pop_col] = int(graph.node[n][pop_col])
    tot_pop_col += graph.node[n][pop_col]

cddict = recursive_tree_part(graph, range(num_districts),
                             tot_pop_col / num_districts, pop_col, 0.01, 1)
# open enacted map
graph = Graph.from_file(
    "/Users/hopecj/projects/gerryspam/MO/dat/final_prec/prec_labeled.shp")
elections = [
    Election("USSEN16", {
        "Dem": "G16USSDKAN",
        "Rep": "G16USSRBLU"
    }),
    Election("PRES16", {
        "Dem": "G16PREDCLI",
        "Rep": "G16PRERTRU"
    })
]

mo_updaters = {
    "population": Tally("POP10", alias="population"),
    "cut_edges": cut_edges
}
election_updaters = {election.name: election for election in elections}
mo_updaters.update(election_updaters)

sen_part = Partition(graph, assignment="SLDUST", updaters=mo_updaters)
sen_part["PRES16"].efficiency_gap()
sen_part.plot(cmap="tab20")
plt.show()  # show the state senate map
cong_part = Partition(graph, assignment="SLDLST", updaters=mo_updaters)

# load parts (aka district maps) from gerrychain
# "assignment" = mapping of node IDs to district IDs
sen_parts = np.load(
    "/Users/hopecj/projects/gerryspam/MO/res/MO_state_senate_100000_0.05_parts.p"
Exemple #22
0
                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,
                                '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"})
                    }





            #########BUILD PARTITION
# ######### BUILD ASSIGNMENT
cddict = {x: int(x[0] / gn) for x in graph.nodes()}
pos = {x: x for x in graph.nodes()}

# ### CONFIGURE UPDATERS


def step_num(partition):
    parent = partition.parent
    if not parent:
        return 0
    return parent["step_num"] + 1


updaters = {
    "population": Tally("population"),
    "cut_edges": cut_edges,
    "step_num": step_num,
    # "Pink-Purple": Election("Pink-Purple", {"Pink":"pink","Purple":"purple"})
}

# ########BUILD FIRST PARTITION

grid_partition = Partition(graph, assignment=cddict, updaters=updaters)

# ADD CONSTRAINTS
popbound = within_percent_of_ideal_population(grid_partition, 0.1)

# ########Setup Proposal
ideal_population = sum(
    grid_partition["population"].values()) / len(grid_partition)
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
Exemple #25
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,
                '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"})
            }

            #########BUILD PARTITION

            grid_partition = Partition(graph,
                                       assignment=cddict,
                                       updaters=updaters)
Exemple #26
0
    return total

## ## ## ## ## ## ## ## ## ## ## 
## creating an initial partition
## ## ## ## ## ## ## ## ## ## ## 
print("Reading in Data/Graph")

dat_path = "/Users/hopecj/projects/gerryspam/MO/dat/final_prec/prec_labeled.shp"
dat = gpd.read_file(dat_path)
list(dat.columns)
dat['SLDUST'].nunique()
dat['SLDLST'].nunique()

graph = Graph.from_file(dat_path)

mo_updaters = {"population" : Tally(POP_COL, alias="population"),
               "cut_edges": cut_edges,
               "county_splits": county_splits("county_splits", "COUNTYFP"),
               "num_vra_districts": num_vra_districts,
               "polsby_popper": polsby_popper}

elections = [Election("USSEN16", {"Dem": "G16USSDKAN", "Rep": "G16USSRBLU"}),
             Election("PRES16", {"Dem": "G16PREDCLI", "Rep": "G16PRERTRU"})]
election_updaters = {election.name: election for election in elections}

mo_updaters.update(election_updaters)

## ## ## ## ## ## ## ## ## ## ## 
## Initial partition
## ## ## ## ## ## ## ## ## ## ## 
print("Creating seed plan")
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 metamander_around_partition(graph, dual, target_partition, tag, num_dist, secret):
    updaters = {'population': Tally('population'),
                'cut_edges': cut_edges,
                'step_num': step_num,
                }

    assignment = {}
    for x in graph.nodes():
        color = 0
        for block in target_partition.keys():
            if x in target_partition[block]:
                assignment[x] = color
            color += 1

    target_partition = Partition(graph, assignment, updaters=updaters)

    facefinder.viz(graph, set([]), target_partition.parts)
    plt.savefig("./plots/large_sample/target_maps/target_map" + tag + ".png", format='png')
    plt.close()

    print("made partition")
    crosses = facefinder.compute_cross_edge(graph, target_partition)

    k = len(target_partition.parts)

    dual_crosses = []
    for edge in dual.edges:
        if dual.edges[edge]["original_name"] in crosses:
            dual_crosses.append(edge)

    print("making dual distances")
    dual = facefinder.distance_from_partition(dual, dual_crosses)
    print('finished making dual distances')
    if secret:
        special_faces = assign_special_faces_random(dual)
        # special_faces = assign_special_faces_sqrt(dual)
    else:
        special_faces = assign_special_faces(dual, 2)
    print('finished assigning special faces')
    g_sierpinsky = face_sierpinski_mesh(graph, special_faces)
    print("made metamander")
    # change from RVAP and UVAP to approprate election data columns
    for node in g_sierpinsky:
        g_sierpinsky.nodes[node]['C_X'] = g_sierpinsky.nodes[node]['pos'][0]
        g_sierpinsky.nodes[node]['C_Y'] = g_sierpinsky.nodes[node]['pos'][1]
        if 'population' not in g_sierpinsky.nodes[node]:
            g_sierpinsky.nodes[node]['population'] = 0
        if 'EL16G_PR_D' not in g_sierpinsky.nodes[node]:
            g_sierpinsky.nodes[node]['EL16G_PR_D'] = 0
        if 'EL16G_PR_R' not in g_sierpinsky.nodes[node]:
            g_sierpinsky.nodes[node]['EL16G_PR_R'] = 0
        ##Need to add the voting data
    print("assigning districts to metamander")

    total_pop = sum( [ g_sierpinsky.nodes[node]['population'] for node in g_sierpinsky])
    cddict = recursive_tree_part(graph,range(num_dist),total_pop/num_dist,"population", .01,1)
    for node in graph.nodes():
        graph.nodes[node]['part'] = cddict[node]
    #sierp_partition = build_trivial_partition(g_sierpinsky)

    print("assigned districts")
    plt.figure()
    nx.draw(g_sierpinsky, pos=nx.get_node_attributes(g_sierpinsky, 'pos'), node_size=1, width=1,
            cmap=plt.get_cmap('jet'))
    plt.savefig("./plots/large_sample/sierpinsky_plots/sierpinsky_mesh" + tag + ".png", format='png')
    plt.close()
    return g_sierpinsky, k
def step_num(partition):
    parent = partition.parent
    if not parent:
        return 0
    return parent["step_num"] + 1


def b_nodes_bi(partition):
    return {x[0]
            for x in partition["cut_edges"]
            }.union({x[1]
                     for x in partition["cut_edges"]})


updaters = {
    "population": Tally("TOTPOP"),
    "cut_edges": cut_edges,
    "step_num": step_num,
    'b_nodes': b_nodes_bi
}

Part1 = Partition(g, cddict1, updaters)
Part2 = Partition(g, cddict2, updaters)

initial_infection = len(Part1['b_nodes'])

spontaneous = 0.01
recover = .01
spread = .05
reinfect = False
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)