From 5ffdffb94aa534c6b006b47fa0a10375e81e9d17 Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Sat, 10 Mar 2018 12:01:13 -0800 Subject: [PATCH 01/49] Cleaned up README.md --- README.md | 127 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 77 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index aeb81dd..250e24e 100644 --- a/README.md +++ b/README.md @@ -1,44 +1,67 @@ -Note that the file code incorporates an adapted version of CS2, Andrew -Goldberg and Boris Cherkassky's implementation of a min-cost flow -algorithm due to Goldberg. See cs2-COPYRIGHT for the license -information, and also see cs2-README. +Note that the file code incorporates an adapted version of CS2, Andrew Goldberg +and Boris Cherkassky's implementation of a min-cost flow algorithm due to +Goldberg. See cs2-COPYRIGHT for the license information, and also see +cs2-README. The rest of the code is subject to the following license: Copyright 2017 Philip N. Klein and Vincent Cohen-Addad -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Extract census blocks and populations - python3 read_census_blocks.py -where contains shape file specifying census blocks, e.g. + + python3 read_census_blocks.py + +where `` contains shape file specifying census blocks, +e.g. + abblock010_44_pophu/tabblock2010_44_pophu + which can be downloaded from https://www.census.gov/geo/maps-data/data/tiger-data.html (Select Population & Housing Unit Counts -- Blocks, then select a state.) -The output file written has one line per client point. -It specifies the x coordinate (longitude), the y coordinate -(latitude), and the population assigned to that point. -The script selects the point to be the centroid of the census block -shape. (WHAT HAPPENS IF THE SHAPE CONSISTS OF MULTIPLE POLYGONS?) +The output file written has one line per client point. It specifies the x +coordinate (longitude), the y coordinate (latitude), and the population assigned +to that point. The script selects the point to be the centroid of the census +block shape. (WHAT HAPPENS IF THE SHAPE CONSISTS OF MULTIPLE POLYGONS?) Also, extract the boundary polygons of a state: - python3 read_state_shapefile.py - where is the two-letter abbreviation for a state, and -is the name of a directory (not including suffix) giving shape records for - state boundaries, e.g. cb_2016_us_state_500k as downloaded from https://www.census.gov/geo/maps-data/data/cbf/cbf_state.html + + python3 read_state_shapefile.py + +here `` is the two-letter abbreviation for a state, and `` + +is the name of a directory (not including suffix) giving shape records for state +boundaries, e.g. cb_2016_us_state_500k as downloaded from +https://www.census.gov/geo/maps-data/data/cbf/cbf_state.html Next, compute the clustering using - do_redistrict -where the first argument is the number of clusters to find, and the -input file is in the format of the output of the read_census_blocks.py script. -This program sends some text indicating progress to standard err, and, -when it terminates, sends the output to standard out. - Output format: + + do_redistrict + +where the first argument is the number of clusters to find, and the input file +is in the format of the output of the `read_census_blocks.py` script. This program +sends some text indicating progress to standard err, and, when it terminates, +sends the output to standard out. + +Output format: +
@@ -54,29 +77,33 @@ when it terminates, sends the output to standard out. Standard out should be piped into a file Next, use - python3 Voronoi_boundaries.py -to produce a file that specifies: - the client points, with colors reflecting the assignment to - centers, and the boundaries of the convex polygons that form the - power diagram of the chosen centers. + + python3 Voronoi_boundaries.py + +to produce a file that specifies: the client points, with colors reflecting the +assignment to centers, and the boundaries of the convex polygons that form the +power diagram of the chosen centers. Format: - -
-
- . - . -
- ... - ... - . - . - ... + + +
+
+ . + . +
+ ... + ... + . + . + ... Next, use - python3 plotGNUPlot.py -where is the name of a file specifying the - boundaries of the state, given in the format + + python3 plotGNUPlot.py + +where is the name of a file specifying the boundaries of the state, given in the format + . @@ -86,16 +113,16 @@ where is the name of a file specifying the . . - + . . -where each sequence of x-y lines specifes the coordinates of polygon -vertices of some polygon that is part of the boundary of the state. +where each sequence of x-y lines specifes the coordinates of polygon vertices of +some polygon that is part of the boundary of the state. -The output is a file with gnuplot commands. Running gnuplot on that -file shows the client points according to the color assignment, and -also the state boundaries, and also the boundaries of the -power-diagram cells (clipped against the state boundaries). +The output is a file with gnuplot commands. Running gnuplot on that file shows +the client points according to the color assignment, and also the state +boundaries, and also the boundaries of the power-diagram cells (clipped against +the state boundaries). From 02dcc3fcf369fb46d392a9967a3329eecbb54fc5 Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Sat, 10 Mar 2018 12:31:41 -0800 Subject: [PATCH 02/49] Make executable --- Voronoi_boundaries.py | 0 plotGNUPlot.py | 0 read_census_blocks.py | 0 read_state_shapefile.py | 0 4 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 Voronoi_boundaries.py mode change 100644 => 100755 plotGNUPlot.py mode change 100644 => 100755 read_census_blocks.py mode change 100644 => 100755 read_state_shapefile.py diff --git a/Voronoi_boundaries.py b/Voronoi_boundaries.py old mode 100644 new mode 100755 diff --git a/plotGNUPlot.py b/plotGNUPlot.py old mode 100644 new mode 100755 diff --git a/read_census_blocks.py b/read_census_blocks.py old mode 100644 new mode 100755 diff --git a/read_state_shapefile.py b/read_state_shapefile.py old mode 100644 new mode 100755 From e466181ad0c8f7223f29a04001ffccb56f2a837b Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Thu, 22 Mar 2018 23:40:48 -0700 Subject: [PATCH 03/49] Add necessary header --- mincostflow.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/mincostflow.cpp b/mincostflow.cpp index 0c0366a..d3412a1 100755 --- a/mincostflow.cpp +++ b/mincostflow.cpp @@ -11,6 +11,7 @@ #include #include #include "check_weights.hpp" +#include //#include From 628644f7bb642106e2d769b76d30ffdc1cfcc939 Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Thu, 22 Mar 2018 23:41:03 -0700 Subject: [PATCH 04/49] Add better error checking and command line argument interface --- read_state_shapefile.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/read_state_shapefile.py b/read_state_shapefile.py index 923a0c0..4ca4535 100755 --- a/read_state_shapefile.py +++ b/read_state_shapefile.py @@ -7,13 +7,23 @@ e.g. "/Users/klein/Downloads/cb_2016_us_state_500k/cb_2016_us_state_500k" ''' +if len(sys.argv)!=3: + print("Syntax: {0} ") + sys.exit(-1) + #This will print out a sequence of line segments sf = shapefile.Reader(sys.argv[2]) -x = next(x for x in sf.iterShapeRecords() if x.record[4]==sys.argv[1]) -for i in range(1,len(x.shape.points)): - if i in x.shape.parts: + +for state in sf.iterShapeRecords(): + if state.record[2]==sys.argv[1]: + break +else: + raise Exception("Could not find state!") + +for i in range(1,len(state.shape.points)): + if i in state.shape.parts: print() - pt = x.shape.points[i] + pt = state.shape.points[i] print(pt[0], pt[1]) From 44c671ab4770bc677829d677d522256858143b26 Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Fri, 23 Mar 2018 16:45:56 -0700 Subject: [PATCH 05/49] Make debugging message more helpful. --- read_state_shapefile.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/read_state_shapefile.py b/read_state_shapefile.py index 4ca4535..6e6dcd1 100755 --- a/read_state_shapefile.py +++ b/read_state_shapefile.py @@ -15,15 +15,13 @@ sf = shapefile.Reader(sys.argv[2]) for state in sf.iterShapeRecords(): - if state.record[2]==sys.argv[1]: + if state.record[1]==sys.argv[1]: break else: - raise Exception("Could not find state!") + raise Exception("Could not find state '{0}'!".format(sys.argv[1])) for i in range(1,len(state.shape.points)): if i in state.shape.parts: print() pt = state.shape.points[i] print(pt[0], pt[1]) - - From 847dbfc02b6645e3faecb491c618e6bfeb5cdfa6 Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Fri, 23 Mar 2018 16:47:08 -0700 Subject: [PATCH 06/49] Initial import --- RUN.sh | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100755 RUN.sh diff --git a/RUN.sh b/RUN.sh new file mode 100755 index 0000000..8225cbb --- /dev/null +++ b/RUN.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +echo "Syntax: $0 " + +pop_file=$1 +state_name=$2 +state_shapefile=$3 +district_num=$4 + +temp_out_pop=/z/temp_out_pop +temp_out_power=/z/temp_out_power +temp_out_state=/z/temp_out_state +temp_out_voronoi=/z/temp_out_voronoi +temp_out_gnuplot=/z/temp_out_gnuplot + +echo "Reading census blocks..." +python3 read_census_blocks.py $pop_file $temp_out_pop +echo "Reading state boundaries" +python3 read_state_shapefile.py $state_name $state_shapefile > $temp_out_state +echo "Generating power diagrams" +./do_redistrict $district_num $temp_out_pop > $temp_out_power +python3 Voronoi_boundaries.py $temp_out_power $temp_out_voronoi +python3 plotGNUPlot.py $temp_out_voronoi $temp_out_state $temp_out_gnuplot False +gnuplot < $temp_out_gnuplot \ No newline at end of file From 10ac5158aabcd845370a0fb334452d713da3a604 Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Fri, 23 Mar 2018 17:05:09 -0700 Subject: [PATCH 07/49] Added extract_district_boundaries.py --- RUN.sh | 14 +++-- extract_district_boundaries.py | 101 +++++++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+), 6 deletions(-) create mode 100644 extract_district_boundaries.py diff --git a/RUN.sh b/RUN.sh index 8225cbb..25ebdd5 100755 --- a/RUN.sh +++ b/RUN.sh @@ -12,13 +12,15 @@ temp_out_power=/z/temp_out_power temp_out_state=/z/temp_out_state temp_out_voronoi=/z/temp_out_voronoi temp_out_gnuplot=/z/temp_out_gnuplot +temp_out_districts=/z/temp_out_districts echo "Reading census blocks..." -python3 read_census_blocks.py $pop_file $temp_out_pop +#python3 read_census_blocks.py $pop_file $temp_out_pop echo "Reading state boundaries" -python3 read_state_shapefile.py $state_name $state_shapefile > $temp_out_state +#python3 read_state_shapefile.py $state_name $state_shapefile > $temp_out_state echo "Generating power diagrams" -./do_redistrict $district_num $temp_out_pop > $temp_out_power -python3 Voronoi_boundaries.py $temp_out_power $temp_out_voronoi -python3 plotGNUPlot.py $temp_out_voronoi $temp_out_state $temp_out_gnuplot False -gnuplot < $temp_out_gnuplot \ No newline at end of file +#./do_redistrict $district_num $temp_out_pop > $temp_out_power +#python3 Voronoi_boundaries.py $temp_out_power $temp_out_voronoi +python3 extract_district_boundaries.py $temp_out_voronoi $temp_out_state > $temp_out_districts +#python3 plotGNUPlot.py $temp_out_voronoi $temp_out_state $temp_out_gnuplot False +#gnuplot < $temp_out_gnuplot \ No newline at end of file diff --git a/extract_district_boundaries.py b/extract_district_boundaries.py new file mode 100644 index 0000000..068dec3 --- /dev/null +++ b/extract_district_boundaries.py @@ -0,0 +1,101 @@ +import numpy as np +import matplotlib.pyplot as plt +import sys +import scipy.spatial as sp +import shapely.geometry as sg +from shapely.geometry.polygon import Polygon +import shapely.wkt +from matplotlib import colors as mcolors + +def Parse_boundary(filename): + f = open(filename, "r") + lines = f.readlines() + boundaries = [] + i = 0 + points = [] + for l in lines: + if l == "\n" : + boundaries.append(Polygon(points)) + points = [] + continue + s = l.split() + x = float(s[0]) + y = float(s[1]) + points.append([x,y]) + boundaries.append(Polygon(points)) + f.close() + return boundaries + + + +def Parse(filename): + f = open(filename, "r") + lines = f.readlines() + s = lines[0].split() + nb_centers = int(s[0]) + nb_clients = int(s[1]) + x_min, y_min = (float("inf"),float("inf")) + x_max, y_max = (-float("inf"),-float("inf")) + + C = [] + for i in range(1, nb_centers+1): + s = lines[i].split() + x = float(s[0]) + y = float(s[1]) + color = s[2] + C.append([x,y,color]) + x_max = max(x_max, x) + y_max = max(y_max, y) + x_min = min(x_min, x) + y_min = min(y_min, y) + + + assign_pairs = {} + A = [] + for i in range(nb_centers+1, nb_centers+nb_clients+1): + s = lines[i].split() + x = float(s[0]) + y = float(s[1]) + color = s[2] + A.append([x,y,color]) + x_max = max(x_max, x) + y_max = max(y_max, y) + x_min = min(x_min, x) + y_min = min(y_min, y) + + polygons = [] + for i in range(nb_centers+nb_clients+1, len(lines)): + points_unsplit = lines[i].split() + points = [[float(points_unsplit[j].split(",")[0]), + float(points_unsplit[j].split(",")[1])] + for j in range(len(points_unsplit))] + polygons.append(Polygon(points)) + # print(polygons[-1].exterior.xy) + f.close() + return C,A,polygons,[[x_min,y_min],[x_max,y_max]] + +def clip(polygons, boundary): + clipped = polygons + new_clipped = [] + for b in boundary: + for i in range(len(polygons)): + p = polygons[i] + if b.contains(p): + new_clipped.append(p) + elif p.intersects(b) : + new_clipped.append(p.intersection(b)) + return new_clipped + +if __name__ == '__main__': + if len(sys.argv)!=3: + print("Use: ", sys.argv[0], "[voronoi boundary file] [state boundary file]") + exit(-1) + + C_3D, A, polygons, bbox = Parse(sys.argv[1]) + + boundary = Parse_boundary(sys.argv[2]) + + clipped_polygons = clip(polygons, boundary) + + for cp in clipped_polygons: + print(shapely.wkt.dumps(cp)) \ No newline at end of file From 8f007bbf70e5d7de8386c04c85989be88cf356fe Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Fri, 23 Mar 2018 17:05:30 -0700 Subject: [PATCH 08/49] Ignore *.o --- .gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5761abc --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.o From 8a94812927ee4aae47714d6228fa7970eeef3cd5 Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Fri, 23 Mar 2018 17:08:01 -0700 Subject: [PATCH 09/49] Formatting. ELiminated mixed tabs/spaces. --- initial_centers.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/initial_centers.cpp b/initial_centers.cpp index 1a23da7..71689bd 100644 --- a/initial_centers.cpp +++ b/initial_centers.cpp @@ -12,6 +12,7 @@ vector choose_initial_centers(const vector &clients, long * popula long population = accumulate(populations, populations+clients.size(), 0); long r = rand() % population; vector centers(num_centers); + for (int i=0; i < clients.size(); ++i){ r -= populations[i]; if (r <= 0) { @@ -19,6 +20,7 @@ vector choose_initial_centers(const vector &clients, long * popula break; } } + vector distances_sq(clients.size(), numeric_limits::infinity()); double weighted_sum_dist_sq = 0.; for (int j = 1; j < centers.size(); ++j){ @@ -30,10 +32,11 @@ vector choose_initial_centers(const vector &clients, long * popula for (int i = 0; i < clients.size(); ++i) { choice -= distances_sq[i]*populations[i]; if (choice <= 0){ - centers[j] = clients[j]; - break; + centers[j] = clients[j]; + break; } } } + return centers; } From bb7493f2466fe18c7769014b428c653617ec7665 Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Sat, 24 Mar 2018 08:58:37 -0700 Subject: [PATCH 10/49] Fixed indenting: tabs and spaces should not be mixed. Added `unsigned` for various loop iteration variables to suppress warnings. Added exception at the end of the function; without this the function returns uninitialized centers if max tries is reached without convergence. This is a bad idea. --- redistrict.cpp | 101 ++++++++++++++++++++++++++----------------------- 1 file changed, 53 insertions(+), 48 deletions(-) diff --git a/redistrict.cpp b/redistrict.cpp index 3b5fbba..f9f5e90 100644 --- a/redistrict.cpp +++ b/redistrict.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include "initial_centers.hpp" #include "mincostflow.hpp" @@ -31,58 +32,62 @@ tuple, Assignment, vector > choose_centers(const vector center2num_clients(num_centers); - vector new_centers(num_centers); - int iter_count = 0; - do {//iterate until stable - cerr << "ITERATION COUNT: " << ++iter_count << "\n"; - for (int i = 0; i < clients.size(); ++i){ - //find distances to centers - double dist_sq = numeric_limits::infinity(); - for (int j = 0; j < centers.size(); ++j){ - dist_sq = centers[j].dist_sq(clients[i]); - distances_sq[i*num_centers+j] = dist_sq; - max_dist_sq = max(max_dist_sq, dist_sq); + centers = choose_initial_centers(clients, populations, num_centers); + vector center2num_clients(num_centers); + vector new_centers(num_centers); + int iter_count = 0; + do {//iterate until stable + cerr << "ITERATION COUNT: " << ++iter_count << "\n"; + for (unsigned int i = 0; i < clients.size(); ++i){ + //find distances to centers + double dist_sq = numeric_limits::infinity(); + for (unsigned int j = 0; j < centers.size(); ++j){ + dist_sq = centers[j].dist_sq(clients[i]); + distances_sq[i*num_centers+j] = dist_sq; + max_dist_sq = max(max_dist_sq, dist_sq); + } } - } - //convert doubles to ints - scale = (double) LONG_MAX / max_dist_sq/ (clients.size()*num_centers)/100; - for (int i = 0; i < clients.size(); ++i){ - for (int j = 0; j < centers.size(); ++j){ - costs[i*num_centers+j] = (long) (scale * distances_sq[i*num_centers+j]); + //convert doubles to ints + scale = (double) LONG_MAX / max_dist_sq/ (clients.size()*num_centers)/100; + for (unsigned int i = 0; i < clients.size(); ++i){ + for (unsigned int j = 0; j < centers.size(); ++j){ + costs[i*num_centers+j] = (long) (scale * distances_sq[i*num_centers+j]); + } } - } - //find assignment of clients to centers - find_assignment(costs, populations, clients.size(), num_centers, assignment, int_weights); - different = assignment != old_assignment; - old_assignment = assignment; - //move centers to centroids - //first initialize accumulators to the zero point - fill(new_centers.begin(), new_centers.end(), Point(0.,0.)); - fill(center2num_clients.begin(), center2num_clients.end(), 0); - //iterate through clients and the centers they are assigned to - for (int i = 0; i < clients.size(); ++i){ - for (AssignmentElement ae : assignment[i]){ - new_centers[ae.center] = new_centers[ae.center].add(clients[i].scale(ae.flow)); - center2num_clients[ae.center] += ae.flow; + + //find assignment of clients to centers + find_assignment(costs, populations, clients.size(), num_centers, assignment, int_weights); + different = assignment != old_assignment; + old_assignment = assignment; + + //move centers to centroids + //first initialize accumulators to the zero point + fill(new_centers.begin(), new_centers.end(), Point(0.,0.)); + fill(center2num_clients.begin(), center2num_clients.end(), 0); + + //iterate through clients and the centers they are assigned to + for (unsigned int i = 0; i < clients.size(); ++i){ + for (AssignmentElement ae : assignment[i]){ + new_centers[ae.center] = new_centers[ae.center].add(clients[i].scale(ae.flow)); + center2num_clients[ae.center] += ae.flow; + } } + for (int j = 0; j < num_centers; ++j){ + Point new_center = new_centers[j].scale(1./center2num_clients[j]); + centers[j] = new_center; + } + } while (different and iter_count < 5*num_centers); + + if (different){ + cerr << "FAILURE TO CONVERGE\n"; + } else { + vector weights(int_weights.size()); + transform(int_weights.begin(), int_weights.end(), weights.begin(), [scale](long w){return ((double) w)/scale;}); + check_weights(clients, centers, assignment, weights); + return make_tuple(centers, assignment, weights); } - for (int j = 0; j < num_centers; ++j){ - Point new_center = new_centers[j].scale(1./center2num_clients[j]); - centers[j] = new_center; - } - } - while (different and iter_count < 5*num_centers); - if (different){ - cerr << "FAILURE TO CONVERGE\n"; - } - else { - vector weights(int_weights.size()); - transform(int_weights.begin(), int_weights.end(), weights.begin(), [scale](long w){return ((double) w)/scale;}); - check_weights(clients, centers, assignment, weights); - return make_tuple(centers, assignment, weights); - } } + + throw std::runtime_error("Tried too many times to converge!"); } From e93b4bfdd1aca6a71fe3f00f848bff188878079a Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Sat, 24 Mar 2018 09:01:15 -0700 Subject: [PATCH 11/49] Use const in the function definition to protect pointer inputs --- initial_centers.cpp | 8 +++++--- initial_centers.hpp | 3 ++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/initial_centers.cpp b/initial_centers.cpp index 71689bd..7d053b0 100644 --- a/initial_centers.cpp +++ b/initial_centers.cpp @@ -7,9 +7,11 @@ using namespace std; -vector choose_initial_centers(const vector &clients, long * populations, int num_centers){ - vector rand_values(clients.size()); - long population = accumulate(populations, populations+clients.size(), 0); +std::vector choose_initial_centers( + const std::vector &clients, + const long *const populations, + int num_centers +){ long r = rand() % population; vector centers(num_centers); diff --git a/initial_centers.hpp b/initial_centers.hpp index 314722f..6faad90 100644 --- a/initial_centers.hpp +++ b/initial_centers.hpp @@ -2,4 +2,5 @@ #include #include "point.hpp" -std::vector choose_initial_centers(const std::vector &clients, long * populations, int num_centers); + +std::vector choose_initial_centers(const std::vector &clients, const long *const populations, int num_centers); From 8507940edccfcfce73699c4d98e2773396817acf Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Sat, 24 Mar 2018 09:01:38 -0700 Subject: [PATCH 12/49] Use const for `population` variable. --- initial_centers.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/initial_centers.cpp b/initial_centers.cpp index 7d053b0..77e9b26 100644 --- a/initial_centers.cpp +++ b/initial_centers.cpp @@ -12,6 +12,7 @@ std::vector choose_initial_centers( const long *const populations, int num_centers ){ + const long population = std::accumulate(populations, populations+clients.size(), 0); long r = rand() % population; vector centers(num_centers); From 9194435d8f0c2b2d5eca37b22d66bc9345e60b5b Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Sat, 24 Mar 2018 09:02:21 -0700 Subject: [PATCH 13/49] Added rationale commenting and used `at` for improved access safety on a non-performance-critical vector access. --- initial_centers.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/initial_centers.cpp b/initial_centers.cpp index 77e9b26..deb64f0 100644 --- a/initial_centers.cpp +++ b/initial_centers.cpp @@ -14,12 +14,14 @@ std::vector choose_initial_centers( ){ const long population = std::accumulate(populations, populations+clients.size(), 0); long r = rand() % population; - vector centers(num_centers); + std::vector centers(num_centers); - for (int i=0; i < clients.size(); ++i){ + //Choose a random initial centroid from the list of population points + //weighting each one's probability of being chosen by its population + for (unsigned int i=0; i < clients.size(); ++i){ r -= populations[i]; if (r <= 0) { - centers[0] = clients[i]; + centers.at(0) = clients[i]; break; } } From 117d2f3771f8aa21d8286fd2c0bede117d09761f Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Sat, 24 Mar 2018 12:57:03 -0700 Subject: [PATCH 14/49] Resolve a sign warning --- initial_centers.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/initial_centers.cpp b/initial_centers.cpp index deb64f0..6f9e5e0 100644 --- a/initial_centers.cpp +++ b/initial_centers.cpp @@ -34,7 +34,7 @@ std::vector choose_initial_centers( weighted_sum_dist_sq += distances_sq[i]*populations[i]; } double choice = rand_float(0, weighted_sum_dist_sq); - for (int i = 0; i < clients.size(); ++i) { + for (unsigned int i = 0; i < clients.size(); ++i) { choice -= distances_sq[i]*populations[i]; if (choice <= 0){ centers[j] = clients[j]; From 17cde13684313ac355b5751e2cf83f8c449611bf Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Sat, 24 Mar 2018 12:57:56 -0700 Subject: [PATCH 15/49] Resolve sign warnings. Switch to using `std::` --- initial_centers.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/initial_centers.cpp b/initial_centers.cpp index 6f9e5e0..fb4641e 100644 --- a/initial_centers.cpp +++ b/initial_centers.cpp @@ -5,8 +5,6 @@ #include "rand_float.hpp" #include "rand_point.hpp" -using namespace std; - std::vector choose_initial_centers( const std::vector &clients, const long *const populations, @@ -26,11 +24,11 @@ std::vector choose_initial_centers( } } - vector distances_sq(clients.size(), numeric_limits::infinity()); + std::vector distances_sq(clients.size(), std::numeric_limits::infinity()); double weighted_sum_dist_sq = 0.; - for (int j = 1; j < centers.size(); ++j){ - for (int i = 1; i < clients.size(); ++i){ - distances_sq[i] = min(distances_sq[i], centers[j-1].dist_sq(clients[i])); + for (unsigned int j = 1; j < centers.size(); ++j){ + for (unsigned int i = 1; i < clients.size(); ++i){ + distances_sq[i] = std::min(distances_sq[i], centers[j-1].dist_sq(clients[i])); weighted_sum_dist_sq += distances_sq[i]*populations[i]; } double choice = rand_float(0, weighted_sum_dist_sq); From ec05f7d44ff95c21901ae2a03e0abede5379c3e3 Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Sat, 24 Mar 2018 12:59:01 -0700 Subject: [PATCH 16/49] Compiling with `-g` doesn't make code slower, so it's a good thing to do for diagnosing performance issues and exceptions. --- makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/makefile b/makefile index b3c5aed..c52cc6c 100755 --- a/makefile +++ b/makefile @@ -11,8 +11,8 @@ CCOMP = g++-7 #CCOMP = gcc-4 #CFLAGS = -g -DCHECK_SOLUTION -Wall DEBUG = -g -CFLAGS = -O3 -Wall -CPPFLAGS = -O3 -Wall -std=c++1z +CFLAGS = -O3 -Wall -g +CPPFLAGS = -O3 -Wall -std=c++1z -g #CPPFLAGS = -g -Wall -std=c++1z #CFLAGS = -O4 -DNDEBUG -DNO_ZERO_CYCLES BIN=cs2 do_redistrict test_initial_centers test_redistrict test_find_weights From 18aadce0305fb16dab04c570925746070be97070 Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Sat, 24 Mar 2018 13:01:49 -0700 Subject: [PATCH 17/49] Eliminate unused variables to suppress warnings --- mincostflow.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/mincostflow.cpp b/mincostflow.cpp index d3412a1..152607a 100755 --- a/mincostflow.cpp +++ b/mincostflow.cpp @@ -877,14 +877,8 @@ void refine () node *i; /* current node */ excess_t i_exc; /* excess of i */ -long np, nr, ns; /* variables for additional print */ - int pr_in_int; /* current number of updates between price_in */ -np = n_push; -nr = n_relabel; -ns = n_scan; - n_refine ++; n_ref ++; n_rel = 0; From 6815ca6395abc1f3249b3c09221d6c2a8b63c683 Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Sat, 24 Mar 2018 13:02:22 -0700 Subject: [PATCH 18/49] Resolved signedness warnings --- check_weights.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/check_weights.cpp b/check_weights.cpp index 4737a8d..88e1247 100644 --- a/check_weights.cpp +++ b/check_weights.cpp @@ -4,11 +4,11 @@ using namespace std; bool check_weights(const vector & clients, const vector & centers, const Assignment & assignment, const vector & weights){ const double tolerance= 1e-6; - for (int i = 0; i < clients.size(); ++i){ + for (unsigned int i = 0; i < clients.size(); ++i){ for (AssignmentElement ae : assignment[i]){ double client_to_assigned_center_weighted_dist_sq = centers[ae.center].dist_sq(clients[i]) + weights[ae.center]; - for (int j = 0; j < centers.size(); ++j){ + for (unsigned int j = 0; j < centers.size(); ++j){ if (client_to_assigned_center_weighted_dist_sq > centers[j].dist_sq(clients[i]) + weights[j]+tolerance){ cerr << "ERROR: client " << i << " closer to center " << j << " than to assigned center " << ae.center << "\n"; From 3ca5b0f57dc28f5e5d99740b385671977023062e Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Mon, 26 Mar 2018 09:56:08 -0700 Subject: [PATCH 19/49] Fixing whitespace --- mincostflow.cpp | 72 ++++++++++++++++++++++--------------------------- 1 file changed, 32 insertions(+), 40 deletions(-) diff --git a/mincostflow.cpp b/mincostflow.cpp index 152607a..e181db5 100755 --- a/mincostflow.cpp +++ b/mincostflow.cpp @@ -507,75 +507,67 @@ i -> rank = -1; /*************************************************** price_update *******/ -void price_update () +void price_update (){ + register node *i; -{ - -register node *i; - -excess_t remain; /* total excess of unscanned nodes with - positive excess */ -bucket *b; /* current bucket */ -price_t dp; /* amount to be subtracted from prices */ + excess_t remain; /* total excess of unscanned nodes with + positive excess */ + bucket *b; /* current bucket */ + price_t dp; /* amount to be subtracted from prices */ -n_update ++; - -FOR_ALL_NODES_i - { + n_update ++; - if ( i -> excess < 0 ) - { - INSERT_TO_BUCKET ( i, buckets ); - i -> rank = 0; - } - else - { - i -> rank = linf; - } + FOR_ALL_NODES_i { + if ( i -> excess < 0 ){ + INSERT_TO_BUCKET ( i, buckets ); + i -> rank = 0; + } else { + i -> rank = linf; + } } -remain = total_excess; -if ( remain < 0.5 ) return; + remain = total_excess; + if ( remain < 0.5 ) return; -/* main loop */ + /* main loop */ -for ( b = buckets; b != l_bucket; b ++ ) + for ( b = buckets; b != l_bucket; b ++ ) { while ( NONEMPTY_BUCKET ( b ) ) - { - GET_FROM_BUCKET ( i, b ) + { + GET_FROM_BUCKET ( i, b ) - up_node_scan ( i ); + up_node_scan ( i ); - if ( i -> excess > 0 ) - { - remain -= (i -> excess); - if ( remain <= 0 ) break; - } + if ( i -> excess > 0 ) + { + remain -= (i -> excess); + if ( remain <= 0 ) break; + } - } /* end of scanning the bucket */ + } /* end of scanning the bucket */ if ( remain <= 0 ) break; } /* end of scanning buckets */ -if ( remain > 0.5 ) flag_updt = 1; + if ( remain > 0.5 ) flag_updt = 1; /* finishup */ /* changing prices for nodes which were not scanned during main loop */ -dp = ( b - buckets ) * epsilon; + dp = ( b - buckets ) * epsilon; -FOR_ALL_NODES_i + FOR_ALL_NODES_i { if ( i -> rank >= 0 ) { if ( i -> rank < linf ) - REMOVE_FROM_BUCKET ( i, (buckets + i -> rank) ); + REMOVE_FROM_BUCKET ( i, (buckets + i -> rank) ); if ( i -> price > price_min ) - i -> price -= dp; + i -> price -= dp; } } From 0c6f02010b36e06af53f0c62c7232bd372d306d0 Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Mon, 26 Mar 2018 09:56:59 -0700 Subject: [PATCH 20/49] Generate multiple district plans --- RUN.sh | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/RUN.sh b/RUN.sh index 25ebdd5..859b6bb 100755 --- a/RUN.sh +++ b/RUN.sh @@ -15,12 +15,15 @@ temp_out_gnuplot=/z/temp_out_gnuplot temp_out_districts=/z/temp_out_districts echo "Reading census blocks..." -#python3 read_census_blocks.py $pop_file $temp_out_pop +python3 read_census_blocks.py $pop_file $temp_out_pop echo "Reading state boundaries" -#python3 read_state_shapefile.py $state_name $state_shapefile > $temp_out_state +python3 read_state_shapefile.py $state_name $state_shapefile > $temp_out_state echo "Generating power diagrams" -#./do_redistrict $district_num $temp_out_pop > $temp_out_power -#python3 Voronoi_boundaries.py $temp_out_power $temp_out_voronoi -python3 extract_district_boundaries.py $temp_out_voronoi $temp_out_state > $temp_out_districts -#python3 plotGNUPlot.py $temp_out_voronoi $temp_out_state $temp_out_gnuplot False -#gnuplot < $temp_out_gnuplot \ No newline at end of file +for (( i=0 ; i < 10 ; i++ )) ; do + temp_out_gnuplot="/z/temp_out_gnuplot_${i}" + ./do_redistrict $district_num $temp_out_pop > $temp_out_power + python3 Voronoi_boundaries.py $temp_out_power $temp_out_voronoi + #python3 extract_district_boundaries.py $temp_out_voronoi $temp_out_state > "${temp_out_districts}_${i}" + python3 plotGNUPlot.py $temp_out_voronoi $temp_out_state $temp_out_gnuplot False + gnuplot < $temp_out_gnuplot +done \ No newline at end of file From eff56ef20bdd027bbb76bb7796e5fa549f2f3122 Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Mon, 26 Mar 2018 09:57:20 -0700 Subject: [PATCH 21/49] Set random seed from time. --- do_redistrict.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/do_redistrict.cpp b/do_redistrict.cpp index e5712d4..0f01b89 100644 --- a/do_redistrict.cpp +++ b/do_redistrict.cpp @@ -1,11 +1,14 @@ #include #include +#include #include "redistrict.hpp" #include "print_out_solution.hpp" using namespace std; int main(int argc, char *argv[]){ + srand(time(NULL)); + int num_centers = atoi(argv[1]); // string client_filename = argv[2]; std::ifstream inf(argv[2]); From f2bc4bc188e097653c2f52d100cd1b5d3bcf67b9 Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Mon, 26 Mar 2018 11:00:28 -0700 Subject: [PATCH 22/49] Fixed bug --- initial_centers.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/initial_centers.cpp b/initial_centers.cpp index fb4641e..b37b227 100644 --- a/initial_centers.cpp +++ b/initial_centers.cpp @@ -25,8 +25,8 @@ std::vector choose_initial_centers( } std::vector distances_sq(clients.size(), std::numeric_limits::infinity()); - double weighted_sum_dist_sq = 0.; for (unsigned int j = 1; j < centers.size(); ++j){ + double weighted_sum_dist_sq = 0.; for (unsigned int i = 1; i < clients.size(); ++i){ distances_sq[i] = std::min(distances_sq[i], centers[j-1].dist_sq(clients[i])); weighted_sum_dist_sq += distances_sq[i]*populations[i]; From d3b96c9a829fc1eb400dccb44e6e4bde2bb94a93 Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Mon, 2 Apr 2018 12:09:55 -0600 Subject: [PATCH 23/49] Using more useful names --- extract_district_boundaries.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/extract_district_boundaries.py b/extract_district_boundaries.py index 068dec3..8b7a219 100644 --- a/extract_district_boundaries.py +++ b/extract_district_boundaries.py @@ -91,9 +91,12 @@ def clip(polygons, boundary): print("Use: ", sys.argv[0], "[voronoi boundary file] [state boundary file]") exit(-1) - C_3D, A, polygons, bbox = Parse(sys.argv[1]) + voronoi_file = sys.argv[1] + state_boundary = sys.argv[2] - boundary = Parse_boundary(sys.argv[2]) + C_3D, A, polygons, bbox = Parse(voronoi_file) + + boundary = Parse_boundary(state_boundary) clipped_polygons = clip(polygons, boundary) From 34b7dda317e961effb77bc52fc7c3086772beaba Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Mon, 2 Apr 2018 12:16:59 -0600 Subject: [PATCH 24/49] Output districts rather than sadly broken polygons --- extract_district_boundaries.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) mode change 100644 => 100755 extract_district_boundaries.py diff --git a/extract_district_boundaries.py b/extract_district_boundaries.py old mode 100644 new mode 100755 index 8b7a219..3731b14 --- a/extract_district_boundaries.py +++ b/extract_district_boundaries.py @@ -1,9 +1,11 @@ +#!/usr/bin/env python3 import numpy as np import matplotlib.pyplot as plt import sys import scipy.spatial as sp import shapely.geometry as sg from shapely.geometry.polygon import Polygon +import shapely.ops import shapely.wkt from matplotlib import colors as mcolors @@ -75,15 +77,15 @@ def Parse(filename): return C,A,polygons,[[x_min,y_min],[x_max,y_max]] def clip(polygons, boundary): - clipped = polygons new_clipped = [] - for b in boundary: - for i in range(len(polygons)): - p = polygons[i] + for p in polygons: + new_poly = [] + for b in boundary: if b.contains(p): - new_clipped.append(p) + new_poly.append(p) elif p.intersects(b) : - new_clipped.append(p.intersection(b)) + new_poly.append(p.intersection(b)) + new_clipped.append(shapely.ops.cascaded_union(new_poly)) return new_clipped if __name__ == '__main__': From c9e951cf0bff0e6c8b3fcae2b2e58ee8fa8d07ba Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Mon, 2 Apr 2018 12:17:19 -0600 Subject: [PATCH 25/49] Extract districts --- RUN.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/RUN.sh b/RUN.sh index 859b6bb..9e4b87d 100755 --- a/RUN.sh +++ b/RUN.sh @@ -23,7 +23,7 @@ for (( i=0 ; i < 10 ; i++ )) ; do temp_out_gnuplot="/z/temp_out_gnuplot_${i}" ./do_redistrict $district_num $temp_out_pop > $temp_out_power python3 Voronoi_boundaries.py $temp_out_power $temp_out_voronoi - #python3 extract_district_boundaries.py $temp_out_voronoi $temp_out_state > "${temp_out_districts}_${i}" - python3 plotGNUPlot.py $temp_out_voronoi $temp_out_state $temp_out_gnuplot False - gnuplot < $temp_out_gnuplot + python3 extract_district_boundaries.py $temp_out_voronoi $temp_out_state > "${temp_out_districts}_${i}" + #python3 plotGNUPlot.py $temp_out_voronoi $temp_out_state $temp_out_gnuplot False + #gnuplot < $temp_out_gnuplot done \ No newline at end of file From 28efcb0f3de0edef10274567f32163e8dd9702d8 Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Mon, 2 Apr 2018 12:26:03 -0600 Subject: [PATCH 26/49] Handle possibility of multithreading --- RUN.sh | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/RUN.sh b/RUN.sh index 9e4b87d..00550c6 100755 --- a/RUN.sh +++ b/RUN.sh @@ -7,23 +7,26 @@ state_name=$2 state_shapefile=$3 district_num=$4 -temp_out_pop=/z/temp_out_pop -temp_out_power=/z/temp_out_power -temp_out_state=/z/temp_out_state -temp_out_voronoi=/z/temp_out_voronoi -temp_out_gnuplot=/z/temp_out_gnuplot -temp_out_districts=/z/temp_out_districts +rand_str=`tr -dc A-Za-z0-9_ < /dev/urandom | head -c 20` +temp_out_pop="tmp.census_data.${rand_str}" +temp_out_power="tmp.power_diag.${rand_str}" +temp_out_state="tmp.state_boundary.${rand_str}" +temp_out_voronoi="tmp.voronoi_boundary.${rand_str}" +temp_out_gnuplot="tmp.gnuplot.${rand_str}" +temp_out_districts="out_districts.${rand_str}" echo "Reading census blocks..." python3 read_census_blocks.py $pop_file $temp_out_pop echo "Reading state boundaries" python3 read_state_shapefile.py $state_name $state_shapefile > $temp_out_state echo "Generating power diagrams" -for (( i=0 ; i < 10 ; i++ )) ; do +for (( i=0 ; i < 1 ; i++ )) ; do temp_out_gnuplot="/z/temp_out_gnuplot_${i}" ./do_redistrict $district_num $temp_out_pop > $temp_out_power python3 Voronoi_boundaries.py $temp_out_power $temp_out_voronoi python3 extract_district_boundaries.py $temp_out_voronoi $temp_out_state > "${temp_out_districts}_${i}" #python3 plotGNUPlot.py $temp_out_voronoi $temp_out_state $temp_out_gnuplot False #gnuplot < $temp_out_gnuplot -done \ No newline at end of file +done + +rm -f $temp_out_pop $temp_out_power $temp_out_state $temp_out_voronoi $temp_out_gnuplot \ No newline at end of file From fd3449e19f6c242bf1d55bc087caf292e2d0a0e8 Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Mon, 2 Apr 2018 12:26:36 -0600 Subject: [PATCH 27/49] Ignore executables and outputs --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 5761abc..cdd132c 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ *.o +do_redistrict +out_* From 384bca5716e4c49d4106fd873d18bc8f137cd2a7 Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Mon, 2 Apr 2018 14:12:04 -0600 Subject: [PATCH 28/49] Fix script for running within other scripts --- RUN.sh | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/RUN.sh b/RUN.sh index 00550c6..ee95daa 100755 --- a/RUN.sh +++ b/RUN.sh @@ -1,32 +1,38 @@ #!/bin/bash -echo "Syntax: $0 " +if [ "$#" -ne 5 ]; then + echo "Syntax: $0 " + exit 1 +fi pop_file=$1 state_name=$2 state_shapefile=$3 district_num=$4 +output_name=$5 -rand_str=`tr -dc A-Za-z0-9_ < /dev/urandom | head -c 20` -temp_out_pop="tmp.census_data.${rand_str}" -temp_out_power="tmp.power_diag.${rand_str}" -temp_out_state="tmp.state_boundary.${rand_str}" -temp_out_voronoi="tmp.voronoi_boundary.${rand_str}" -temp_out_gnuplot="tmp.gnuplot.${rand_str}" -temp_out_districts="out_districts.${rand_str}" +rand_str=`tr -dc A-Za-z0-9_ < /dev/urandom | head -c 20` #Prevents issues when using parallelism +temp_out_pop="temp_census_data_${state_name}_${rand_str}" +temp_out_power="temp_power_diag_${state_name}_${rand_str}" +temp_out_state="temp_state_boundary_${state_name}_${rand_str}" +temp_out_voronoi="temp_voronoi_boundary_${state_name}_${rand_str}" +temp_out_gnuplot="temp_gnuplot_${state_name}_${rand_str}" echo "Reading census blocks..." python3 read_census_blocks.py $pop_file $temp_out_pop -echo "Reading state boundaries" + +echo "Reading state boundaries..." python3 read_state_shapefile.py $state_name $state_shapefile > $temp_out_state -echo "Generating power diagrams" -for (( i=0 ; i < 1 ; i++ )) ; do - temp_out_gnuplot="/z/temp_out_gnuplot_${i}" - ./do_redistrict $district_num $temp_out_pop > $temp_out_power - python3 Voronoi_boundaries.py $temp_out_power $temp_out_voronoi - python3 extract_district_boundaries.py $temp_out_voronoi $temp_out_state > "${temp_out_districts}_${i}" - #python3 plotGNUPlot.py $temp_out_voronoi $temp_out_state $temp_out_gnuplot False - #gnuplot < $temp_out_gnuplot -done + +echo "Generating power diagram..." +./do_redistrict $district_num $temp_out_pop > $temp_out_power + +echo "Generating Voronoi boundaries..." +python3 Voronoi_boundaries.py $temp_out_power $temp_out_voronoi + +echo "Extracting districting boundaries..." +python3 extract_district_boundaries.py $temp_out_voronoi $temp_out_state > "$output_name" +#python3 plotGNUPlot.py $temp_out_voronoi $temp_out_state $temp_out_gnuplot False +#gnuplot < $temp_out_gnuplot rm -f $temp_out_pop $temp_out_power $temp_out_state $temp_out_voronoi $temp_out_gnuplot \ No newline at end of file From 06a94e307cefb91ca99617b36129dd9413e6370f Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Thu, 5 Apr 2018 14:02:40 -0600 Subject: [PATCH 29/49] Make RUN.sh use scripts from its own directory --- RUN.sh | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/RUN.sh b/RUN.sh index ee95daa..7fcb29f 100755 --- a/RUN.sh +++ b/RUN.sh @@ -5,6 +5,9 @@ if [ "$#" -ne 5 ]; then exit 1 fi +#Get the script's directory +dir=$(cd -P -- "$(dirname -- "$0")" && pwd -P) + pop_file=$1 state_name=$2 state_shapefile=$3 @@ -19,19 +22,19 @@ temp_out_voronoi="temp_voronoi_boundary_${state_name}_${rand_str}" temp_out_gnuplot="temp_gnuplot_${state_name}_${rand_str}" echo "Reading census blocks..." -python3 read_census_blocks.py $pop_file $temp_out_pop +python3 $dir/read_census_blocks.py $pop_file $temp_out_pop echo "Reading state boundaries..." -python3 read_state_shapefile.py $state_name $state_shapefile > $temp_out_state +python3 $dir/read_state_shapefile.py $state_name $state_shapefile > $temp_out_state echo "Generating power diagram..." -./do_redistrict $district_num $temp_out_pop > $temp_out_power +$dir/do_redistrict $district_num $temp_out_pop > $temp_out_power echo "Generating Voronoi boundaries..." -python3 Voronoi_boundaries.py $temp_out_power $temp_out_voronoi +python3 $dir/Voronoi_boundaries.py $temp_out_power $temp_out_voronoi echo "Extracting districting boundaries..." -python3 extract_district_boundaries.py $temp_out_voronoi $temp_out_state > "$output_name" +python3 $dir/extract_district_boundaries.py $temp_out_voronoi $temp_out_state > "$output_name" #python3 plotGNUPlot.py $temp_out_voronoi $temp_out_state $temp_out_gnuplot False #gnuplot < $temp_out_gnuplot From 2d8ca50dde45b25728f46b5a782da8fe06690c02 Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Thu, 5 Apr 2018 14:03:04 -0600 Subject: [PATCH 30/49] Compile using standard CXX flag --- makefile | 40 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/makefile b/makefile index c52cc6c..419927a 100755 --- a/makefile +++ b/makefile @@ -7,8 +7,6 @@ # CHECK_SOLUTION check feasibility/optimality. HIGH OVERHEAD! # change these to suit your system -CCOMP = g++-7 -#CCOMP = gcc-4 #CFLAGS = -g -DCHECK_SOLUTION -Wall DEBUG = -g CFLAGS = -O3 -Wall -g @@ -18,66 +16,66 @@ CPPFLAGS = -O3 -Wall -std=c++1z -g BIN=cs2 do_redistrict test_initial_centers test_redistrict test_find_weights do_redistrict: do_redistrict.o redistrict.o initial_centers.o mincostflow.o check_weights.o rand_point.o rand_float.o point.o print_out_solution.o - $(CCOMP) $(CPPFLAGS) do_redistrict.o redistrict.o initial_centers.o mincostflow.o check_weights.o rand_point.o point.o print_out_solution.o rand_float.o -o do_redistrict + $(CXX) $(CPPFLAGS) do_redistrict.o redistrict.o initial_centers.o mincostflow.o check_weights.o rand_point.o point.o print_out_solution.o rand_float.o -o do_redistrict clean: rm -f $(BIN) *.o *~ rand_float.o: rand_float.cpp rand_float.hpp - $(CCOMP) $(CPPFLAGS) -c rand_float.cpp + $(CXX) $(CPPFLAGS) -c rand_float.cpp point.o: point.cpp point.hpp - $(CCOMP) $(CPPFLAGS) -c point.cpp + $(CXX) $(CPPFLAGS) -c point.cpp rand_point.o: rand_point.cpp rand_point.hpp - $(CCOMP) $(CPPFLAGS) -c rand_point.cpp + $(CXX) $(CPPFLAGS) -c rand_point.cpp initial_centers.o: initial_centers.cpp initial_centers.hpp - $(CCOMP) $(CPPFLAGS) -c initial_centers.cpp + $(CXX) $(CPPFLAGS) -c initial_centers.cpp test_initial_centers.o: test_initial_centers.cpp initial_centers.hpp - $(CCOMP) $(CPPFLAGS) -c test_initial_centers.cpp + $(CXX) $(CPPFLAGS) -c test_initial_centers.cpp test_initial_centers: test_initial_centers.o initial_centers.o point.o - $(CCOMP) $(CPPFLAGS) test_initial_centers.o initial_centers.o point.o -o test_initial_centers + $(CXX) $(CPPFLAGS) test_initial_centers.o initial_centers.o point.o -o test_initial_centers mincostflow.o: mincostflow.cpp mincostflow.hpp build_graph.h types_cs2.h assignment.hpp - $(CCOMP) $(CFLAGS) -c mincostflow.cpp + $(CXX) $(CFLAGS) -c mincostflow.cpp redistrict.o: redistrict.cpp redistrict.hpp point.hpp assignment.hpp - $(CCOMP) $(CPPFLAGS) -c redistrict.cpp + $(CXX) $(CPPFLAGS) -c redistrict.cpp print_out_solution.o: print_out_solution.cpp - $(CCOMP) $(CPPFLAGS) -c print_out_solution.cpp + $(CXX) $(CPPFLAGS) -c print_out_solution.cpp test_redistrict.o: test_redistrict.cpp redistrict.hpp rand_point.hpp - $(CCOMP) $(CPPFLAGS) -c test_redistrict.cpp + $(CXX) $(CPPFLAGS) -c test_redistrict.cpp do_redistrict.o: do_redistrict.cpp redistrict.hpp - $(CCOMP) $(CPPFLAGS) -c do_redistrict.cpp + $(CXX) $(CPPFLAGS) -c do_redistrict.cpp test_redistrict: test_redistrict.o redistrict.o initial_centers.o mincostflow.o check_weights.o point.o rand_point.o rand_float.o - $(CCOMP) $(CPPFLAGS) test_redistrict.o redistrict.o initial_centers.o mincostflow.o check_weights.o rand_point.o point.o rand_float.o -o test_redistrict + $(CXX) $(CPPFLAGS) test_redistrict.o redistrict.o initial_centers.o mincostflow.o check_weights.o rand_point.o point.o rand_float.o -o test_redistrict do_redistrict: do_redistrict.o redistrict.o initial_centers.o mincostflow.o check_weights.o rand_point.o rand_float.o point.o print_out_solution.o - $(CCOMP) $(CPPFLAGS) do_redistrict.o redistrict.o initial_centers.o mincostflow.o check_weights.o rand_point.o point.o print_out_solution.o rand_float.o -o do_redistrict + $(CXX) $(CPPFLAGS) do_redistrict.o redistrict.o initial_centers.o mincostflow.o check_weights.o rand_point.o point.o print_out_solution.o rand_float.o -o do_redistrict find_weights.hpp: point.hpp find_weights.o: find_weights.cpp find_weights.hpp - $(CCOMP) $(CPPFLAGS) -c find_weights.cpp + $(CXX) $(CPPFLAGS) -c find_weights.cpp test_find_weights.o: test_find_weights.cpp find_weights.hpp - $(CCOMP) $(CPPFLAGS) -c test_find_weights.cpp + $(CXX) $(CPPFLAGS) -c test_find_weights.cpp test_find_weights: test_find_weights.o find_weights.o point.o - $(CCOMP) $(CPPFLAGS) test_find_weights.o find_weights.o point.o -o test_find_weights + $(CXX) $(CPPFLAGS) test_find_weights.o find_weights.o point.o -o test_find_weights test_mincostflow.o: test_mincostflow.cpp mincostflow.hpp - $(CCOMP) $(CPPFLAGS) -c test_mincostflow.cpp + $(CXX) $(CPPFLAGS) -c test_mincostflow.cpp test_mincostflow: test_mincostflow.o mincostflow.o point.o - $(CCOMP) $(CPPFLAGS) test_mincostflow.o mincostflow.o point.o -o test_mincostflow + $(CXX) $(CPPFLAGS) test_mincostflow.o mincostflow.o point.o -o test_mincostflow mincostflow.hpp: assignment.hpp types_cs2.h From 2ce5ad13114f634c9885eb45f5fb5813f2c04e17 Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Thu, 5 Apr 2018 14:08:34 -0600 Subject: [PATCH 31/49] Add file extensions --- makefile | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/makefile b/makefile index 419927a..4f6a201 100755 --- a/makefile +++ b/makefile @@ -13,10 +13,10 @@ CFLAGS = -O3 -Wall -g CPPFLAGS = -O3 -Wall -std=c++1z -g #CPPFLAGS = -g -Wall -std=c++1z #CFLAGS = -O4 -DNDEBUG -DNO_ZERO_CYCLES -BIN=cs2 do_redistrict test_initial_centers test_redistrict test_find_weights +BIN=cs2 do_redistrict.exe test_initial_centers.exe test_redistrict.exe test_find_weights -do_redistrict: do_redistrict.o redistrict.o initial_centers.o mincostflow.o check_weights.o rand_point.o rand_float.o point.o print_out_solution.o - $(CXX) $(CPPFLAGS) do_redistrict.o redistrict.o initial_centers.o mincostflow.o check_weights.o rand_point.o point.o print_out_solution.o rand_float.o -o do_redistrict +do_redistrict.exe: do_redistrict.o redistrict.o initial_centers.o mincostflow.o check_weights.o rand_point.o rand_float.o point.o print_out_solution.o + $(CXX) $(CPPFLAGS) do_redistrict.o redistrict.o initial_centers.o mincostflow.o check_weights.o rand_point.o point.o print_out_solution.o rand_float.o -o do_redistrict.exe clean: rm -f $(BIN) *.o *~ @@ -36,8 +36,8 @@ initial_centers.o: initial_centers.cpp initial_centers.hpp test_initial_centers.o: test_initial_centers.cpp initial_centers.hpp $(CXX) $(CPPFLAGS) -c test_initial_centers.cpp -test_initial_centers: test_initial_centers.o initial_centers.o point.o - $(CXX) $(CPPFLAGS) test_initial_centers.o initial_centers.o point.o -o test_initial_centers +test_initial_centers.exe: test_initial_centers.o initial_centers.o point.o + $(CXX) $(CPPFLAGS) test_initial_centers.o initial_centers.o point.o -o test_initial_centers.exe mincostflow.o: mincostflow.cpp mincostflow.hpp build_graph.h types_cs2.h assignment.hpp $(CXX) $(CFLAGS) -c mincostflow.cpp @@ -54,8 +54,8 @@ test_redistrict.o: test_redistrict.cpp redistrict.hpp rand_point.hpp do_redistrict.o: do_redistrict.cpp redistrict.hpp $(CXX) $(CPPFLAGS) -c do_redistrict.cpp -test_redistrict: test_redistrict.o redistrict.o initial_centers.o mincostflow.o check_weights.o point.o rand_point.o rand_float.o - $(CXX) $(CPPFLAGS) test_redistrict.o redistrict.o initial_centers.o mincostflow.o check_weights.o rand_point.o point.o rand_float.o -o test_redistrict +test_redistrict.exe: test_redistrict.o redistrict.o initial_centers.o mincostflow.o check_weights.o point.o rand_point.o rand_float.o + $(CXX) $(CPPFLAGS) test_redistrict.o redistrict.o initial_centers.o mincostflow.o check_weights.o rand_point.o point.o rand_float.o -o test_redistrict.exe do_redistrict: do_redistrict.o redistrict.o initial_centers.o mincostflow.o check_weights.o rand_point.o rand_float.o point.o print_out_solution.o $(CXX) $(CPPFLAGS) do_redistrict.o redistrict.o initial_centers.o mincostflow.o check_weights.o rand_point.o point.o print_out_solution.o rand_float.o -o do_redistrict @@ -68,8 +68,8 @@ find_weights.o: find_weights.cpp find_weights.hpp test_find_weights.o: test_find_weights.cpp find_weights.hpp $(CXX) $(CPPFLAGS) -c test_find_weights.cpp -test_find_weights: test_find_weights.o find_weights.o point.o - $(CXX) $(CPPFLAGS) test_find_weights.o find_weights.o point.o -o test_find_weights +test_find_weights.exe: test_find_weights.o find_weights.o point.o + $(CXX) $(CPPFLAGS) test_find_weights.o find_weights.o point.o -o test_find_weights.exe test_mincostflow.o: test_mincostflow.cpp mincostflow.hpp $(CXX) $(CPPFLAGS) -c test_mincostflow.cpp From 8d0667fc395c3f5c242e5ad28a8a277894078c3c Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Thu, 5 Apr 2018 14:16:06 -0600 Subject: [PATCH 32/49] Changes to drop std to c++11 from c++1z --- do_redistrict.cpp | 9 ++++++++- makefile | 2 +- redistrict.cpp | 16 +++++++++++----- redistrict.hpp | 2 +- 4 files changed, 21 insertions(+), 8 deletions(-) diff --git a/do_redistrict.cpp b/do_redistrict.cpp index 0f01b89..963a879 100644 --- a/do_redistrict.cpp +++ b/do_redistrict.cpp @@ -1,6 +1,7 @@ #include #include #include +#include "assignment.hpp" #include "redistrict.hpp" #include "print_out_solution.hpp" @@ -22,7 +23,13 @@ int main(int argc, char *argv[]){ populations_vec.push_back(population); } } - auto [centers, assignment, weights ] = choose_centers(clients, &populations_vec[0], num_centers); + + std::vector centers; + Assignment assignment; + std::vector weights; + + choose_centers(clients, &populations_vec[0], num_centers, centers, assignment, weights); + if (centers.size() == 0){ cout << "FAILURE TO CONVERGE\n"; return -1; diff --git a/makefile b/makefile index 4f6a201..fc57656 100755 --- a/makefile +++ b/makefile @@ -10,7 +10,7 @@ #CFLAGS = -g -DCHECK_SOLUTION -Wall DEBUG = -g CFLAGS = -O3 -Wall -g -CPPFLAGS = -O3 -Wall -std=c++1z -g +CPPFLAGS = -O3 -Wall -std=c++11 -g #CPPFLAGS = -g -Wall -std=c++1z #CFLAGS = -O4 -DNDEBUG -DNO_ZERO_CYCLES BIN=cs2 do_redistrict.exe test_initial_centers.exe test_redistrict.exe test_find_weights diff --git a/redistrict.cpp b/redistrict.cpp index f9f5e90..7c79fb8 100644 --- a/redistrict.cpp +++ b/redistrict.cpp @@ -18,13 +18,19 @@ using namespace std; -tuple, Assignment, vector > choose_centers(const vector &clients, long * populations, int num_centers){ +void choose_centers( + const vector &clients, + long * populations, + int num_centers, + std::vector ¢ers, + Assignment &assignment, + std::vector &weights +){ long * costs = (long *) calloc(clients.size() * num_centers, sizeof(long)); vector distances_sq(clients.size()*num_centers, numeric_limits::infinity()); double max_dist_sq = 0; - Assignment assignment(clients.size()); + assignment.resize(clients.size()); Assignment old_assignment(clients.size()); - vector centers; vector int_weights(num_centers); bool different; @@ -81,10 +87,10 @@ tuple, Assignment, vector > choose_centers(const vector weights(int_weights.size()); + weights.resize(int_weights.size()); transform(int_weights.begin(), int_weights.end(), weights.begin(), [scale](long w){return ((double) w)/scale;}); check_weights(clients, centers, assignment, weights); - return make_tuple(centers, assignment, weights); + return; } } diff --git a/redistrict.hpp b/redistrict.hpp index 832ad76..355f008 100644 --- a/redistrict.hpp +++ b/redistrict.hpp @@ -8,4 +8,4 @@ using namespace std; -tuple, Assignment, vector > choose_centers(const vector &clients, long * populations, int num_centers); +void choose_centers(const vector &clients, long * populations, int num_centers, std::vector ¢ers, Assignment &assignment, std::vector &weights); From 1c929c5a158f3c6ced4da3ea4d8e5737b56b8395 Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Thu, 5 Apr 2018 14:16:25 -0600 Subject: [PATCH 33/49] Ignore *.exe --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index cdd132c..5ab5a85 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ *.o do_redistrict out_* +*.exe From 609d3f1968f575016e0505a0ed1ba1298aa0370d Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Thu, 5 Apr 2018 15:11:34 -0600 Subject: [PATCH 34/49] Ditch matplotlib dependency --- extract_district_boundaries.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/extract_district_boundaries.py b/extract_district_boundaries.py index 3731b14..cb22c9d 100755 --- a/extract_district_boundaries.py +++ b/extract_district_boundaries.py @@ -1,13 +1,11 @@ #!/usr/bin/env python3 import numpy as np -import matplotlib.pyplot as plt import sys import scipy.spatial as sp import shapely.geometry as sg from shapely.geometry.polygon import Polygon import shapely.ops import shapely.wkt -from matplotlib import colors as mcolors def Parse_boundary(filename): f = open(filename, "r") From 9624c264e6fb8793bf24a7e50981a42098f6e989 Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Thu, 5 Apr 2018 15:14:22 -0600 Subject: [PATCH 35/49] Drop matplotlib dependency --- Voronoi_boundaries.py | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/Voronoi_boundaries.py b/Voronoi_boundaries.py index 8f7a45b..6e1181c 100755 --- a/Voronoi_boundaries.py +++ b/Voronoi_boundaries.py @@ -1,11 +1,8 @@ import numpy as np -import matplotlib.pyplot as plt import sys import scipy.spatial as sp import shapely.geometry as sg -from matplotlib import colors as mcolors -color_dict = dict(mcolors.BASE_COLORS, **mcolors.CSS4_COLORS) -# colors = [x for x in color_dict if x not in {"w",'aliceblue','antiquewhite','azure','beige','bisque','blanchedalmond'}] + colors = [ 'red', #ff0000 = 255 0 0 'web-green', #00c000 = 0 192 0 @@ -139,8 +136,6 @@ def PlotAll(C, A, assignment, bounded_regions, bbox, output): f.write("\n") #x, y, color = 'black') Plot_extra_lines(C, f) f.close() - # plt.axis([bbox[0][0],bbox[1][0], bbox[0][1],bbox[1][1]]) - # plt.show(block=True) @@ -200,20 +195,12 @@ def find_proj(bounded_regions): proj_regions[i].append(proj_point) return proj_regions -def plot_regions(proj_regions): - - for r in proj_regions: - if proj_regions[r] == []: continue - region = proj_regions[r] - convex_hull = sg.MultiPoint(region).convex_hull - x,y = convex_hull.exterior.xy - plt.plot(x, y, color = 'black') def Plot_extra_lines(C,f): diagram = sp.Voronoi(C) - - + + def unbounded(input_region): return any(x==-1 for x in input_region) ## insert points to remove From beeba76fa12ca686869ec6ea2a9a723db041b072 Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Thu, 5 Apr 2018 15:24:34 -0600 Subject: [PATCH 36/49] Fix file path --- RUN.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RUN.sh b/RUN.sh index 7fcb29f..785d405 100755 --- a/RUN.sh +++ b/RUN.sh @@ -28,7 +28,7 @@ echo "Reading state boundaries..." python3 $dir/read_state_shapefile.py $state_name $state_shapefile > $temp_out_state echo "Generating power diagram..." -$dir/do_redistrict $district_num $temp_out_pop > $temp_out_power +$dir/do_redistrict.exe $district_num $temp_out_pop > $temp_out_power echo "Generating Voronoi boundaries..." python3 $dir/Voronoi_boundaries.py $temp_out_power $temp_out_voronoi From a99f8b36f92a111436238c6306630514f934c9e0 Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Thu, 5 Apr 2018 23:39:12 -0600 Subject: [PATCH 37/49] Don't delete temporary files. Might be needed to recover valuable work --- RUN.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RUN.sh b/RUN.sh index 785d405..4b0a015 100755 --- a/RUN.sh +++ b/RUN.sh @@ -38,4 +38,4 @@ python3 $dir/extract_district_boundaries.py $temp_out_voronoi $temp_out_state > #python3 plotGNUPlot.py $temp_out_voronoi $temp_out_state $temp_out_gnuplot False #gnuplot < $temp_out_gnuplot -rm -f $temp_out_pop $temp_out_power $temp_out_state $temp_out_voronoi $temp_out_gnuplot \ No newline at end of file +#rm -f $temp_out_pop $temp_out_power $temp_out_state $temp_out_voronoi $temp_out_gnuplot \ No newline at end of file From 109154927ec63c3b75ca847abb679d658786267f Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Thu, 5 Apr 2018 23:39:27 -0600 Subject: [PATCH 38/49] Endeavour to clean polygons prior to intersecting them --- extract_district_boundaries.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/extract_district_boundaries.py b/extract_district_boundaries.py index cb22c9d..2e6643a 100755 --- a/extract_district_boundaries.py +++ b/extract_district_boundaries.py @@ -79,10 +79,12 @@ def clip(polygons, boundary): for p in polygons: new_poly = [] for b in boundary: - if b.contains(p): - new_poly.append(p) - elif p.intersects(b) : - new_poly.append(p.intersection(b)) + pclean = p.buffer(0) + bclean = b.buffer(0) + if blcean.contains(pclean): + new_poly.append(pclean) + elif pclean.intersects(blcean) : + new_poly.append(pclean.intersection(blcean)) new_clipped.append(shapely.ops.cascaded_union(new_poly)) return new_clipped From 197c44328b14eb94936db3c18a56511e3330d5d1 Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Fri, 6 Apr 2018 12:01:01 -0600 Subject: [PATCH 39/49] Clean polygons before calculating intersection --- extract_district_boundaries.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/extract_district_boundaries.py b/extract_district_boundaries.py index 2e6643a..9e9348c 100755 --- a/extract_district_boundaries.py +++ b/extract_district_boundaries.py @@ -81,10 +81,10 @@ def clip(polygons, boundary): for b in boundary: pclean = p.buffer(0) bclean = b.buffer(0) - if blcean.contains(pclean): + if bclean.contains(pclean): new_poly.append(pclean) - elif pclean.intersects(blcean) : - new_poly.append(pclean.intersection(blcean)) + elif pclean.intersects(bclean) : + new_poly.append(pclean.intersection(bclean)) new_clipped.append(shapely.ops.cascaded_union(new_poly)) return new_clipped From a068196afdd64641515318bb286ccbb531a4f61b Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Fri, 6 Apr 2018 12:01:13 -0600 Subject: [PATCH 40/49] Try harder to converge --- redistrict.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/redistrict.cpp b/redistrict.cpp index 7c79fb8..4fa1367 100644 --- a/redistrict.cpp +++ b/redistrict.cpp @@ -82,7 +82,7 @@ void choose_centers( Point new_center = new_centers[j].scale(1./center2num_clients[j]); centers[j] = new_center; } - } while (different and iter_count < 5*num_centers); + } while (different and iter_count < 10*num_centers); if (different){ cerr << "FAILURE TO CONVERGE\n"; From 9dae723ce15f9a2ca272442e4f66094fbbdf5e23 Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Fri, 6 Apr 2018 14:11:06 -0600 Subject: [PATCH 41/49] Add command-line argument checking --- do_redistrict.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/do_redistrict.cpp b/do_redistrict.cpp index 963a879..6783420 100644 --- a/do_redistrict.cpp +++ b/do_redistrict.cpp @@ -10,6 +10,11 @@ using namespace std; int main(int argc, char *argv[]){ srand(time(NULL)); + if(argc!=3){ + cout<<"Syntax: "< "< Date: Fri, 6 Apr 2018 14:11:20 -0600 Subject: [PATCH 42/49] Add link-time optimization --- makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/makefile b/makefile index fc57656..34e1cf2 100755 --- a/makefile +++ b/makefile @@ -10,7 +10,7 @@ #CFLAGS = -g -DCHECK_SOLUTION -Wall DEBUG = -g CFLAGS = -O3 -Wall -g -CPPFLAGS = -O3 -Wall -std=c++11 -g +CPPFLAGS = -O3 -Wall -std=c++11 -g -flto #CPPFLAGS = -g -Wall -std=c++1z #CFLAGS = -O4 -DNDEBUG -DNO_ZERO_CYCLES BIN=cs2 do_redistrict.exe test_initial_centers.exe test_redistrict.exe test_find_weights From 47de671978bf7df97b51c06abfc6bfa5e99e63e9 Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Fri, 6 Apr 2018 14:17:15 -0600 Subject: [PATCH 43/49] Moved license info to its own file. --- LICENSE | 24 ++++++++++++++++++++++++ README.md | 25 ++++--------------------- 2 files changed, 28 insertions(+), 21 deletions(-) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..05adbd3 --- /dev/null +++ b/LICENSE @@ -0,0 +1,24 @@ +Note that the file code incorporates an adapted version of CS2, Andrew Goldberg +and Boris Cherkassky's implementation of a min-cost flow algorithm due to +Goldberg. See cs2-COPYRIGHT for the license information, and also see +cs2-README. + +The rest of the code is subject to the following license: +Copyright 2017 Philip N. Klein and Vincent Cohen-Addad + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index 250e24e..e3361d1 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,10 @@ -Note that the file code incorporates an adapted version of CS2, Andrew Goldberg -and Boris Cherkassky's implementation of a min-cost flow algorithm due to -Goldberg. See cs2-COPYRIGHT for the license information, and also see -cs2-README. +Balanced Centroidal Power Diagram Redistricting +=============================================== + -The rest of the code is subject to the following license: -Copyright 2017 Philip N. Klein and Vincent Cohen-Addad -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Extract census blocks and populations @@ -31,7 +14,7 @@ Extract census blocks and populations where `` contains shape file specifying census blocks, e.g. - abblock010_44_pophu/tabblock2010_44_pophu + abblock010_44_pophu/tabblock2010_44_pophu which can be downloaded from https://www.census.gov/geo/maps-data/data/tiger-data.html (Select Population & Housing Unit Counts -- Blocks, then select a state.) From 735cf42928dcb06e6bb679554da61dffe3f1e55f Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Fri, 6 Apr 2018 14:20:47 -0600 Subject: [PATCH 44/49] Added better instructions for using the code --- README.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/README.md b/README.md index e3361d1..fd9502f 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,33 @@ Balanced Centroidal Power Diagram Redistricting =============================================== +Compilation +----------- +Compile the code by running: + make +Running the Code: Short Version +------------------------------- +The code can be run using: + + ./RUN.sh + +where + + * `` is a census block shapefile. These have names like `tabblock2010_44_pophu` (see below). + * `` is the FIPS code of the state to be processed. In this example, this is `44`. + * `` is the name of a state boundary shapefile. This is a file like `cb_2016_us_state_500k` (see below). + * `` is the number of districts to generate + * `` is the name of the output file. Output will a representation of the districts in well-known text (WKT) format. + + + +Running the Code: Long Version +------------------------------ Extract census blocks and populations From 673c3b9e4fce9ade9e532376d99ec7fced0c9f9e Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Fri, 6 Apr 2018 14:21:29 -0600 Subject: [PATCH 45/49] Clarified WKT format. --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index fd9502f..7291d23 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,10 @@ where * `` is the FIPS code of the state to be processed. In this example, this is `44`. * `` is the name of a state boundary shapefile. This is a file like `cb_2016_us_state_500k` (see below). * `` is the number of districts to generate - * `` is the name of the output file. Output will a representation of the districts in well-known text (WKT) format. + * `` is the name of the output file. + +Output will a representation of the districts in well-known text (WKT) format. +This is suitable for interoperation with many standard GIS programs. From 38098281168de2085cf4b3199d794043b6150155 Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Sun, 15 Apr 2018 19:58:01 -0400 Subject: [PATCH 46/49] Formatting --- do_redistrict.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/do_redistrict.cpp b/do_redistrict.cpp index 6783420..5412853 100644 --- a/do_redistrict.cpp +++ b/do_redistrict.cpp @@ -11,7 +11,7 @@ int main(int argc, char *argv[]){ srand(time(NULL)); if(argc!=3){ - cout<<"Syntax: "< "< "< Date: Sun, 15 Apr 2018 19:58:15 -0400 Subject: [PATCH 47/49] Fix random number generation so it uses a better seed --- do_redistrict.cpp | 4 ++-- makefile | 7 +++++-- rand_float.cpp | 3 ++- rand_point.cpp | 1 + random.cpp | 52 +++++++++++++++++++++++++++++++++++++++++++++++ random.hpp | 46 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 108 insertions(+), 5 deletions(-) create mode 100644 random.cpp create mode 100644 random.hpp diff --git a/do_redistrict.cpp b/do_redistrict.cpp index 5412853..78c90b9 100644 --- a/do_redistrict.cpp +++ b/do_redistrict.cpp @@ -1,14 +1,14 @@ #include #include -#include #include "assignment.hpp" +#include "random.hpp" #include "redistrict.hpp" #include "print_out_solution.hpp" using namespace std; int main(int argc, char *argv[]){ - srand(time(NULL)); + seed_rand(0); if(argc!=3){ cout<<"Syntax: "< "<(rand()) / static_cast(RAND_MAX/(upper-lower)); + return uniform_rand_real(lower, upper); } diff --git a/rand_point.cpp b/rand_point.cpp index 763c182..667d8ae 100644 --- a/rand_point.cpp +++ b/rand_point.cpp @@ -1,5 +1,6 @@ #include "rand_point.hpp" #include "rand_float.hpp" +#include "random.hpp" Point rand_point(){ return Point(rand_float(-1,1), rand_float(-1,1)); diff --git a/random.cpp b/random.cpp new file mode 100644 index 0000000..52786f6 --- /dev/null +++ b/random.cpp @@ -0,0 +1,52 @@ +#include "random.hpp" +#include +#include +#include +#include +#include +#include +#include + +our_random_engine& rand_engine(){ + static our_random_engine e[PRNG_THREAD_MAX]; + return e[omp_get_thread_num()]; +} + + +//Be sure to read: http://www.pcg-random.org/posts/cpp-seeding-surprises.html +//and http://www.pcg-random.org/posts/cpps-random_device.html +void seed_rand(unsigned long seed){ + #pragma omp parallel //All threads must come here + { + #pragma omp critical //But only one at a time + if(seed==0){ + std::uint_least32_t seed_data[std::mt19937::state_size]; + std::random_device r; + std::generate_n(seed_data, std::mt19937::state_size, std::ref(r)); + std::seed_seq q(std::begin(seed_data), std::end(seed_data)); + rand_engine().seed(q); + } else + rand_engine().seed( seed*omp_get_thread_num() ); + } +} + + +int uniform_rand_int(int from, int thru){ + static std::uniform_int_distribution<> d[PRNG_THREAD_MAX]; + using parm_t = std::uniform_int_distribution<>::param_type; + return d[omp_get_thread_num()]( rand_engine(), parm_t{from, thru} ); +} + + +double uniform_rand_real(double from, double thru){ + static std::uniform_real_distribution<> d[PRNG_THREAD_MAX]; + using parm_t = std::uniform_real_distribution<>::param_type; + return d[omp_get_thread_num()]( rand_engine(), parm_t{from, thru} ); +} + + +double normal_rand(double mean, double stddev){ + static std::normal_distribution d[PRNG_THREAD_MAX]; + using parm_t = std::normal_distribution::param_type; + return d[omp_get_thread_num()]( rand_engine(), parm_t{mean, stddev} ); +} \ No newline at end of file diff --git a/random.hpp b/random.hpp new file mode 100644 index 0000000..a95e9a3 --- /dev/null +++ b/random.hpp @@ -0,0 +1,46 @@ +//This file contains a number of functions for getting seeding random number +//generators and pulling numbers from them in a thread-safe manner. +#ifndef _prng_header +#define _prng_header + +///Maximum number of threads this class should deal with +#define PRNG_THREAD_MAX 32 + +#ifdef _OPENMP + #include +#else + #define omp_get_thread_num() 0 + #define omp_get_num_threads() 1 + #define omp_get_max_threads() 1 +#endif + +#include + +typedef std::mt19937 our_random_engine; + +//Returns a PRNG engine specific to the calling thread +our_random_engine& rand_engine(); + +//Seeds the PRNG engines using entropy from the computer's random device +void seed_rand(unsigned long seed); + +//Returns an integer value on the closed interval [from,thru] +//Thread-safe +int uniform_rand_int(int from, int thru); + +//Returns an floating-point value on the interval [from,thru) +//Thread-safe +double uniform_rand_real(double from, double thru); + +//Returns a Gaussian-distributed value with specified mean and standard +//deviation. Thread-safe +double normal_rand(double mean, double stddev); + +template +T uniform_bits(){ + std::uniform_int_distribution + dist(std::numeric_limits::lowest(),std::numeric_limits::max()); + return dist( rand_engine() ); +} + +#endif From 84be2991876e930080a904ca4c4e5c48b51bfc2a Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Sun, 15 Apr 2018 19:58:44 -0400 Subject: [PATCH 48/49] Add script header --- read_state_shapefile.py | 1 + 1 file changed, 1 insertion(+) diff --git a/read_state_shapefile.py b/read_state_shapefile.py index 6e6dcd1..fc5fb7f 100755 --- a/read_state_shapefile.py +++ b/read_state_shapefile.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python3 import shapefile from shapely.geometry import shape import sys From f726ed16bf893b41d43dd64bdc35ead7a46e74ea Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Sun, 15 Apr 2018 20:31:04 -0400 Subject: [PATCH 49/49] Shuffle input to improve randomness --- do_redistrict.cpp | 7 +++++++ initial_centers.cpp | 1 + 2 files changed, 8 insertions(+) diff --git a/do_redistrict.cpp b/do_redistrict.cpp index 78c90b9..8422d7f 100644 --- a/do_redistrict.cpp +++ b/do_redistrict.cpp @@ -29,6 +29,13 @@ int main(int argc, char *argv[]){ } } + //Shuffle centers + for(unsigned int i=0;i centers; Assignment assignment; std::vector weights; diff --git a/initial_centers.cpp b/initial_centers.cpp index b37b227..3eca959 100644 --- a/initial_centers.cpp +++ b/initial_centers.cpp @@ -4,6 +4,7 @@ #include "initial_centers.hpp" #include "rand_float.hpp" #include "rand_point.hpp" +#include "random.hpp" std::vector choose_initial_centers( const std::vector &clients,