happyjack27 / autoredistrict

Programmatically makes a fair congressional district map (prevents gerrymandering)
GNU General Public License v3.0
89 stars 14 forks source link

add ability to turn off the recombination stage #184

Closed happyjack27 closed 7 years ago

happyjack27 commented 7 years ago

add ability to turn off the recombination stage, for local refinement (fine tuning)

happyjack27 commented 7 years ago

From Colin:

Yeah if turning off recombination is all that is needed to preserve contiguity then that would be a good feature. Recombination could be used early on to ensure decent diversity in the solutions and then turned off later on to attempt to focus on local quality. Here is a heuristic algorithm for building the maximum number of regions possible where each region satisfies a floor constraint and is a homogeneous as possible http://pysal.readthedocs.io/en/latest/users/tutorials/region.html There are a lot of differences between this an redistricting but in the big picture there are some parallels. They generate random solutions at first and then use a swapping algorithm for local improvement. It works pretty well. The local search is expensive but at some point it becomes worthwhile to use it. I think it must be the case that while the state space search rate takes a hit, there is a tradeoff where ensuring that the search is confined to the feasible solution space leads to a net improvement in the search effectiveness locally.

ColinMcAuliffe commented 7 years ago

I think it could even be worth considering doing a local search where all moves are constrained a priori to preserve contiguity. Swapping precincts on the border of districts can end up breaking contiguity and those solutions may remain in the population. It may also be possible to simply drop any solution that does not satisfy contiguity during the local search phase.

happyjack27 commented 7 years ago

"It may also be possible to simply drop any solution that does not satisfy contiguity during the local search phase."

The local search phase might be -- most often will be -- started at a point where no candidate solutions are fully contiguous.

Also there may be islands and what not that make full contiguity impossible.

Dropping solutions that do not fully satisfy contiguity might not be viable. Though setting a threshold, whether a quantity, a level of improvement, or a percentile rank, might be viable,

In any case it occured to me that forcing mutation in the least populated regions of a discontiguous district might help repair discontiguity. But the problem is that makes the population less equal, which harms fitness. Maybe a) you could try to expand the largest region, b) you could measure population equality before contiguity repair, thus avoiding the penalty, at least in the current generation.

ColinMcAuliffe commented 7 years ago

Maybe a contiguity repair phase before the initiation of the local search phase could help. Say we have a population of solutions and only a few of them are contiguous. For each solution that is not contiguos, repair the contiguity by freezing the assignments of precincts which belong to the largest connected region for each district. Then the island precincts can be assigned to districts such that contiguity is repaired and the loss of solution fitness is minimized by some heuristic. Then the local search phase could begin with a contiguous population

ColinMcAuliffe commented 7 years ago

A related concept is the enclave assignment procedure described in psuedocode 3 of this paper https://pdfs.semanticscholar.org/82cf/136eee7393a057d76ecaf03a0b0df37c8bbd.pdf

happyjack27 commented 7 years ago

I've added a checkbox to the main ui screen to enable/disable the recombination step. when unchecked, the recombination step will ignore the second genome, and just use the first genome as both the first and the second genome, thus resulting in a clone.

i think that should suffice. moving this issue to done (add to changelog in next release)

happyjack27 commented 7 years ago
public void crossover(int[] genome1, int[] genome2) {
    if( !Settings.recombination_on) {
        genome2 = genome1; //if no recombination, clone.
    }

...