2020 GPVA Presidential Primary Results

BALLOT RESULTS for 2020 GPVA Presidential Primary


Winners: Howie Hawkins (66%), Dario Hunter (34%)

Number of candidates: 12

Number of ballots received: 67


LIST OF ALL CANDIDATES (including write-ins):

Hawkins

Hunter

Rolde

Lambert

Lochocki

Mesplay

Moyowasiza-Curry

Wilson

Stein

Sanders

Nader

Ventura


RESULTS: With 5 delegates having 10 half-votes to apportion for the first ballot at
the national convention, Virginia awards 7 half-votes to Hawkins, and 3 half-votes to Hunter.


The Primary was held online from April 20th to April 26th inclusive. The procedures of the Primary, as approved by the Leadership Council, are published below, following the balloting and calculations details. Following this is the program, written in Python, that was used to calculate the results.


DETAILS OF BALLOTS, ELIMINATIONS, AND APPORTIONMENT:


RAW BALLOTS:

[Hunter, Hawkins, none]

[Hawkins, Hunter, Rolde, Lochocki, Moyowasiza-Curry, Lambert, Mesplay, Wilson, none]

[Hawkins, Hunter, none]

[Hunter, Hawkins, Mesplay, none]

[Hawkins, Hunter, none]

[Hunter, Hawkins, Mesplay, Lambert, Lochocki, none]

[Hawkins, none]

[Hawkins, Hunter, none]

[Hawkins, none]

[Mesplay, Lambert, Lochocki, Moyowasiza-Curry, Rolde, Wilson, Hunter, none]

[Hunter, Hawkins, Rolde, Lambert, Lochocki, Mesplay, Moyowasiza-Curry, Wilson, none]

[Hawkins, Hunter, Rolde, Moyowasiza-Curry, Mesplay, Lochocki, Lambert, Wilson, none]

[Hawkins, Hunter, none]

[Moyowasiza-Curry, Hunter, none]

[Hawkins, Hunter, none]

[Hawkins, Hunter, Rolde, none]

[Hawkins, none]

[Hawkins, Hunter, Mesplay, Lambert, Moyowasiza-Curry, none]

[Hawkins, none]

[Hunter, Hawkins, none]

[Hawkins, Mesplay, Hunter, none]

[Hawkins, Hunter, none]

[Hawkins, Hunter, Rolde, Lambert, Moyowasiza-Curry, Mesplay, Lochocki, Wilson, none]

[Moyowasiza-Curry, Lochocki, Hawkins, Hunter, Rolde, none]

[Hunter, Hawkins, Mesplay, Rolde, none]

[Hawkins, Hunter, none]

[Hunter, Hawkins, none]

[Hunter, Mesplay, none]

[Hawkins, Lochocki, Hunter, Rolde, Moyowasiza-Curry, Mesplay, Lambert, Wilson, none]

[Hawkins, Moyowasiza-Curry, Hunter, Lambert, Lochocki, Wilson, Rolde, Mesplay, none]

[Mesplay, Hawkins, Hunter, Rolde, Wilson, Lambert, Moyowasiza-Curry, Lochocki, none]

[Hawkins, Lambert, none]

[Hunter, Hawkins, Mesplay, Rolde, Moyowasiza-Curry, Lambert, Wilson, Lochocki, none]

[Hawkins, Hunter, none]

[Hawkins, Hunter, Rolde, Wilson, Lambert, Mesplay, Moyowasiza-Curry, Lochocki, none]

[Hunter, Hawkins, Rolde, Lambert, Lochocki, Mesplay, Moyowasiza-Curry, Wilson, none]

[Hawkins, Hunter, none]

[Hunter, Moyowasiza-Curry, Mesplay, Hawkins, Lambert, Lochocki, Rolde, Wilson, none]

[Hunter, Hawkins, Lambert, Mesplay, Moyowasiza-Curry, Lochocki, Rolde, Wilson, none]

[Hawkins, none]

[Hawkins, Hunter, Lambert, Mesplay, Moyowasiza-Curry, Wilson, Lochocki, Rolde, none]

[Hawkins, none]

[Hawkins, Mesplay, none]

[Hawkins, Hunter, Rolde, Lochocki, Moyowasiza-Curry, Lambert, Mesplay, Wilson, none]

[Hawkins, none]

[Hawkins, Hunter, Rolde, Lambert, Lochocki, Mesplay, Moyowasiza-Curry, Wilson, none]

[Hawkins, none]

[Hunter, Mesplay, none]

[Hunter, Moyowasiza-Curry, Hawkins, Mesplay, Lambert, Rolde, Lochocki, Wilson, none]

[Hawkins, Hunter, Rolde, none]

[Hunter, Mesplay, Hawkins, none]

[Hawkins, Rolde, Hunter, Moyowasiza-Curry, Lambert, Mesplay, Wilson, Lochocki, none]

[Hunter, Rolde, Hawkins, none]

[Hawkins, Hunter, Rolde, Moyowasiza-Curry, none]

[Hawkins, Moyowasiza-Curry, Lochocki, none]

[Hawkins, Hunter, Lambert, Lochocki, Moyowasiza-Curry, Wilson, Mesplay, Rolde, none]

[Hunter, Rolde, Lochocki, Moyowasiza-Curry, Hawkins, Mesplay, Lambert, Wilson, none]

[Hawkins, none]

[Hawkins, Hunter, none]

[Hawkins, Hunter, Lambert, none]

[Hawkins, Hunter, Rolde, Mesplay, Moyowasiza-Curry, Lochocki, Wilson, Lambert, none]

[Hawkins, Hunter, Moyowasiza-Curry, none]

[Mesplay, Hunter, Lochocki, Moyowasiza-Curry, Hawkins, Nader, Sanders, none]

[Stein, Hunter, none]

[Stein, Hunter, none]

[Ventura, Hunter, Hawkins, none]

[Hawkins, none]


Candidates with no 'firsts' removed: Rolde, Lambert, Lochocki, Wilson, Sanders, Nader.


New state of ballots:

[Hunter, Hawkins, none]

[Hawkins, Hunter, Moyowasiza-Curry, Mesplay, none]

[Hawkins, Hunter, none]

[Hunter, Hawkins, Mesplay, none]

[Hawkins, Hunter, none]

[Hunter, Hawkins, Mesplay, none]

[Hawkins, none]

[Hawkins, Hunter, none]

[Hawkins, none]

[Mesplay, Moyowasiza-Curry, Hunter, none]

[Hunter, Hawkins, Mesplay, Moyowasiza-Curry, none]

[Hawkins, Hunter, Moyowasiza-Curry, Mesplay, none]

[Hawkins, Hunter, none]

[Moyowasiza-Curry, Hunter, none]

[Hawkins, Hunter, none]

[Hawkins, Hunter, none]

[Hawkins, none]

[Hawkins, Hunter, Mesplay, Moyowasiza-Curry, none]

[Hawkins, none]

[Hunter, Hawkins, none]

[Hawkins, Mesplay, Hunter, none]

[Hawkins, Hunter, none]

[Hawkins, Hunter, Moyowasiza-Curry, Mesplay, none]

[Moyowasiza-Curry, Hawkins, Hunter, none]

[Hunter, Hawkins, Mesplay, none]

[Hawkins, Hunter, none]

[Hunter, Hawkins, none]

[Hunter, Mesplay, none]

[Hawkins, Hunter, Moyowasiza-Curry, Mesplay, none]

[Hawkins, Moyowasiza-Curry, Hunter, Mesplay, none]

[Mesplay, Hawkins, Hunter, Moyowasiza-Curry, none]

[Hawkins, none]

[Hunter, Hawkins, Mesplay, Moyowasiza-Curry, none]

[Hawkins, Hunter, none]

[Hawkins, Hunter, Mesplay, Moyowasiza-Curry, none]

[Hunter, Hawkins, Mesplay, Moyowasiza-Curry, none]

[Hawkins, Hunter, none]

[Hunter, Moyowasiza-Curry, Mesplay, Hawkins, none]

[Hunter, Hawkins, Mesplay, Moyowasiza-Curry, none]

[Hawkins, none]

[Hawkins, Hunter, Mesplay, Moyowasiza-Curry, none]

[Hawkins, none]

[Hawkins, Mesplay, none]

[Hawkins, Hunter, Moyowasiza-Curry, Mesplay, none]

[Hawkins, none]

[Hawkins, Hunter, Mesplay, Moyowasiza-Curry, none]

[Hawkins, none]

[Hunter, Mesplay, none]

[Hunter, Moyowasiza-Curry, Hawkins, Mesplay, none]

[Hawkins, Hunter, none]

[Hunter, Mesplay, Hawkins, none]

[Hawkins, Hunter, Moyowasiza-Curry, Mesplay, none]

[Hunter, Hawkins, none]

[Hawkins, Hunter, Moyowasiza-Curry, none]

[Hawkins, Moyowasiza-Curry, none]

[Hawkins, Hunter, Moyowasiza-Curry, Mesplay, none]

[Hunter, Moyowasiza-Curry, Hawkins, Mesplay, none]

[Hawkins, none]

[Hawkins, Hunter, none]

[Hawkins, Hunter, none]

[Hawkins, Hunter, Mesplay, Moyowasiza-Curry, none]

[Hawkins, Hunter, Moyowasiza-Curry, none]

[Mesplay, Hunter, Moyowasiza-Curry, Hawkins, none]

[Stein, Hunter, none]

[Stein, Hunter, none]

[Ventura, Hunter, Hawkins, none]

[Hawkins, none]


Number of 'firsts' for each remaining candidate:

Hawkins: 42 (62.7%)

Hunter: 17 (25.4%)

Mesplay: 3 (4.5%)

Moyowasiza-Curry: 2
(3.0%)

Stein: 2 (3.0%)

Ventura: 1 (1.5%)


Awarding a delegate to the candidate(s) with 1 'firsts' would result in 67 delegates (more than 10); Ventura eliminated.


New state of ballots:

[Hunter, Hawkins, none]

[Hawkins, Hunter, Moyowasiza-Curry, Mesplay, none]

[Hawkins, Hunter, none]

[Hunter, Hawkins, Mesplay, none]

[Hawkins, Hunter, none]

[Hunter, Hawkins, Mesplay, none]

[Hawkins, none]

[Hawkins, Hunter, none]

[Hawkins, none]

[Mesplay, Moyowasiza-Curry, Hunter, none]

[Hunter, Hawkins, Mesplay, Moyowasiza-Curry, none]

[Hawkins, Hunter, Moyowasiza-Curry, Mesplay, none]

[Hawkins, Hunter, none]

[Moyowasiza-Curry, Hunter, none]

[Hawkins, Hunter, none]

[Hawkins, Hunter, none]

[Hawkins, none]

[Hawkins, Hunter, Mesplay, Moyowasiza-Curry, none]

[Hawkins, none]

[Hunter, Hawkins, none]

[Hawkins, Mesplay, Hunter, none]

[Hawkins, Hunter, none]

[Hawkins, Hunter, Moyowasiza-Curry, Mesplay, none]

[Moyowasiza-Curry, Hawkins, Hunter, none]

[Hunter, Hawkins, Mesplay, none]

[Hawkins, Hunter, none]

[Hunter, Hawkins, none]

[Hunter, Mesplay, none]

[Hawkins, Hunter, Moyowasiza-Curry, Mesplay, none]

[Hawkins, Moyowasiza-Curry, Hunter, Mesplay, none]

[Mesplay, Hawkins, Hunter, Moyowasiza-Curry, none]

[Hawkins, none]

[Hunter, Hawkins, Mesplay, Moyowasiza-Curry, none]

[Hawkins, Hunter, none]

[Hawkins, Hunter, Mesplay, Moyowasiza-Curry, none]

[Hunter, Hawkins, Mesplay, Moyowasiza-Curry, none]

[Hawkins, Hunter, none]

[Hunter, Moyowasiza-Curry, Mesplay, Hawkins, none]

[Hunter, Hawkins, Mesplay, Moyowasiza-Curry, none]

[Hawkins, none]

[Hawkins, Hunter, Mesplay, Moyowasiza-Curry, none]

[Hawkins, none]

[Hawkins, Mesplay, none]

[Hawkins, Hunter, Moyowasiza-Curry, Mesplay, none]

[Hawkins, none]

[Hawkins, Hunter, Mesplay, Moyowasiza-Curry, none]

[Hawkins, none]

[Hunter, Mesplay, none]

[Hunter, Moyowasiza-Curry, Hawkins, Mesplay, none]

[Hawkins, Hunter, none]

[Hunter, Mesplay, Hawkins, none]

[Hawkins, Hunter, Moyowasiza-Curry, Mesplay, none]

[Hunter, Hawkins, none]

[Hawkins, Hunter, Moyowasiza-Curry, none]

[Hawkins, Moyowasiza-Curry, none]

[Hawkins, Hunter, Moyowasiza-Curry, Mesplay, none]

[Hunter, Moyowasiza-Curry, Hawkins, Mesplay, none]

[Hawkins, none]

[Hawkins, Hunter, none]

[Hawkins, Hunter, none]

[Hawkins, Hunter, Mesplay, Moyowasiza-Curry, none]

[Hawkins, Hunter, Moyowasiza-Curry, none]

[Mesplay, Hunter, Moyowasiza-Curry, Hawkins, none]

[Stein, Hunter, none]

[Stein, Hunter, none]

[Hunter, Hawkins, none]

[Hawkins, none]



Number of 'firsts' for each remaining candidate:

Hawkins: 42 (62.7%)

Hunter: 18 (26.9%)

Mesplay: 3 (4.5%)

Moyowasiza-Curry: 2
(3.0%)

Stein: 2 (3.0%)


Awarding a delegate to the candidate(s) with 2 'firsts' would result in 33 delegates (more than 10); Moyowasiza-Curry, Stein eliminated.


New state of ballots:

[Hunter, Hawkins, none]

[Hawkins, Hunter, Mesplay, none]

[Hawkins, Hunter, none]

[Hunter, Hawkins, Mesplay, none]

[Hawkins, Hunter, none]

[Hunter, Hawkins, Mesplay, none]

[Hawkins, none]

[Hawkins, Hunter, none]

[Hawkins, none]

[Mesplay, Hunter, none]

[Hunter, Hawkins, Mesplay, none]

[Hawkins, Hunter, Mesplay, none]

[Hawkins, Hunter, none]

[Hunter, none]

[Hawkins, Hunter, none]

[Hawkins, Hunter, none]

[Hawkins, none]

[Hawkins, Hunter, Mesplay, none]

[Hawkins, none]

[Hunter, Hawkins, none]

[Hawkins, Mesplay, Hunter, none]

[Hawkins, Hunter, none]

[Hawkins, Hunter, Mesplay, none]

[Hawkins, Hunter, none]

[Hunter, Hawkins, Mesplay, none]

[Hawkins, Hunter, none]

[Hunter, Hawkins, none]

[Hunter, Mesplay, none]

[Hawkins, Hunter, Mesplay, none]

[Hawkins, Hunter, Mesplay, none]

[Mesplay, Hawkins, Hunter, none]

[Hawkins, none]

[Hunter, Hawkins, Mesplay, none]

[Hawkins, Hunter, none]

[Hawkins, Hunter, Mesplay, none]

[Hunter, Hawkins, Mesplay, none]

[Hawkins, Hunter, none]

[Hunter, Mesplay, Hawkins, none]

[Hunter, Hawkins, Mesplay, none]

[Hawkins, none]

[Hawkins, Hunter, Mesplay, none]

[Hawkins, none]

[Hawkins, Mesplay, none]

[Hawkins, Hunter, Mesplay, none]

[Hawkins, none]

[Hawkins, Hunter, Mesplay, none]

[Hawkins, none]

[Hunter, Mesplay, none]

[Hunter, Hawkins, Mesplay, none]

[Hawkins, Hunter, none]

[Hunter, Mesplay, Hawkins, none]

[Hawkins, Hunter, Mesplay, none]

[Hunter, Hawkins, none]

[Hawkins, Hunter, none]

[Hawkins, none]

[Hawkins, Hunter, Mesplay, none]

[Hunter, Hawkins, Mesplay, none]

[Hawkins, none]

[Hawkins, Hunter, none]

[Hawkins, Hunter, none]

[Hawkins, Hunter, Mesplay, none]

[Hawkins, Hunter, none]

[Mesplay, Hunter, Hawkins, none]

[Hunter, none]

[Hunter, none]

[Hunter, Hawkins, none]

[Hawkins, none]



Number of 'firsts' for each remaining candidate:

Hawkins: 43 (64.2%)

Hunter: 21 (31.3%)

Mesplay: 3 (4.5%)


Awarding a delegate to the candidate(s) with 3 'firsts' would result in 22 delegates (more than 10); Mesplay eliminated.


New state of ballots:

[Hunter, Hawkins, none]

[Hawkins, Hunter, none]

[Hawkins, Hunter, none]

[Hunter, Hawkins, none]

[Hawkins, Hunter, none]

[Hunter, Hawkins, none]

[Hawkins, none]

[Hawkins, Hunter, none]

[Hawkins, none]

[Hunter, none]

[Hunter, Hawkins, none]

[Hawkins, Hunter, none]

[Hawkins, Hunter, none]

[Hunter, none]

[Hawkins, Hunter, none]

[Hawkins, Hunter, none]

[Hawkins, none]

[Hawkins, Hunter, none]

[Hawkins, none]

[Hunter, Hawkins, none]

[Hawkins, Hunter, none]

[Hawkins, Hunter, none]

[Hawkins, Hunter, none]

[Hawkins, Hunter, none]

[Hunter, Hawkins, none]

[Hawkins, Hunter, none]

[Hunter, Hawkins, none]

[Hunter, none]

[Hawkins, Hunter, none]

[Hawkins, Hunter, none]

[Hawkins, Hunter, none]

[Hawkins, none]

[Hunter, Hawkins, none]

[Hawkins, Hunter, none]

[Hawkins, Hunter, none]

[Hunter, Hawkins, none]

[Hawkins, Hunter, none]

[Hunter, Hawkins, none]

[Hunter, Hawkins, none]

[Hawkins, none]

[Hawkins, Hunter, none]

[Hawkins, none]

[Hawkins, none]

[Hawkins, Hunter, none]

[Hawkins, none]

[Hawkins, Hunter, none]

[Hawkins, none]

[Hunter, none]

[Hunter, Hawkins, none]

[Hawkins, Hunter, none]

[Hunter, Hawkins, none]

[Hawkins, Hunter, none]

[Hunter, Hawkins, none]

[Hawkins, Hunter, none]

[Hawkins, none]

[Hawkins, Hunter, none]

[Hunter, Hawkins, none]

[Hawkins, none]

[Hawkins, Hunter, none]

[Hawkins, Hunter, none]

[Hawkins, Hunter, none]

[Hawkins, Hunter, none]

[Hunter, Hawkins, none]

[Hunter, none]

[Hunter, none]

[Hunter, Hawkins, none]

[Hawkins, none]



Number of 'firsts' for each remaining candidate:

Hawkins: 44 (65.7%)

Hunter: 23 (34.3%)


Awarding a delegate to the candidate(s) with 23 'firsts' would not result in more than 10 delegates.


ELIMINATION ROUND
COMPLETE


Below are the calculated sums of the pairwise differences of Percentage Value of a Delegate for each possible apportionment of 10 delegates among the 2 remaining candidates. The apportionment with the smallest sum (listed first) should be chosen. Accordingly, Hawkins is awarded 7 half votes, and Hunter is awarded 3 half votes.


[[7, 3], 0.020611229566453435]

[[6, 4], 0.023631840796019904]

[[5, 5], 0.0626865671641791]

[[8, 2], 0.08955223880597014]

[[4, 6], 0.10696517412935325]

[[3, 7], 0.16986496090973702]

[[9, 1], 0.2703150912106136]

[[2, 8], 0.28544776119402987]

[[1, 9], 0.6185737976782753]


****************

PROCEDURES


The GPVA presidential primary is held in presidential election years to determine who our delegates to the Presidential Nominating Convention will vote for on the first ballot. (This year we are apportioned 5 PNC delegates.) The primary is to be conducted as follows.


1. Voting is open to any permanent resident of Virginia who identifies as a Green by registering on the GPVA website. The opportunity to vote will be broadcast on all available media, including social media, through our locals, and through our list-serves and internal email lists.


2. The vote itself will be conducted on OpaVote.com, an independent and reputable online voting website. Voters will obtain a unique-to-them voter code by requesting it through a form on the GPVA website. They must be logged in to do this, and provide both an email and a physical address. A link will be emailed to them that can be used to cast a vote on OpaVote.com. Neither registration nor any information other than the voter code will be required of them on OpaVote.com. They will also be provided with information on the candidates, including which ones are officially recognized candidates, who will have an asterisk after their name on the ballot. The information provided will include the criteria for official recognition, a history of the interactions the candidates have had with GPVA or its members and officers, and any relevant information about their known interactions with other Green Party members around the country. Voters wishing to include a write-in candidate(s) not on the official ballot will be asked to email their ranked choices directly to the GPVA General Secretary, rather than casting their vote on OpaVote.


3. The ballot will list the three candidates who are officially recognized by the GPUS Presidential Campaign Support Committee, and other active candidates listed as such by that committee. The officially recognized candidates will be listed first, in alphabetical order, with an asterisk after their name, and the remaining candidates after, also in alphabetical order (by last name). The ballot will permit voters to rank some, none, or all of the candidates.


4. At the conclusion of the voting period the GPVA General Secretary will download the ballots, and will then apply the following algorithm to determine the apportionment of delegates to the candidates:


a. Calculate the percentage of "firsts" that each candidate got. Divide each candidate's "first" percentage by the lowest one, rounding down. For instance, if Candidate A got 32% of the firsts and the lowest candidate, Candidate B, got 3% of the firsts, then we calculate 32 divided by 3 equals 10 (and discard the remainder). This is done for each candidate.


b. Add up all the numbers. If the result is more than twice the number of GPVA PNC delegates, then drop the lowest candidate from all the ballots, so that the second-place choice (if any) for those who placed the eliminated candidate first becomes their new first-place choice. (We use twice the number of delegates because on the first PNC ballot half votes are permitted, i.e., a delegate may split their vote between two candidates.)


c. Repeat (a) and (b) until the result calculated in (b) is less than or equal to twice the number of GPVA PNC delegates.


d. Apportion the GPVA PNC delegates among the remaining candidates in such a way as to minimize the differences in percentage-value-of-a-delegate (PVD) among the candidates. This is achieved by taking the percentage of firsts that a candidate has and dividing it by the number of half-delegates they get. That's the PVD for that candidate. Calculate the pairwise differences in PVD's among the candidates. The delegates are to be awarded in such a way as to minimize the sum of these differences. In the extremely unlikely event of a tie, the GPVA co-chairs will determine the outcome by a coin-toss or other random method.


5. The election period is to be for exactly one week, starting at midnighton a Sunday. At least two weeks must be allowed to notify Virginia Greens of the election before voting commences.


6. The General Secretary will publish the ballots, the detailed results of their calculations, and the delegate apportionment to the GPVA membership within 3 days of the end of voting.

**


THE PROGRAM USED FOR PERFORMING CALCULATIONS

(Written in Python 3)



# GPVA PRESIDENTIAL PRIMARY BALLOT PROCESSOR
# The ballots should be in a file with one ballot per line, each line consisting of
# an ordered list (of the candidate names) that repesents the ranked choices of that
# voter, with the candidate names separated by a pipe "|", and ending with candidate "none".  
# The candidate names must be in a file with the names, one per line, exactly as they are on
# the ballots (but not including "none").



import datetime
delegateNum = 10 #number of delegate votes (or half votes)
candidateNamesFile = "CANDIDATES.txt" # location/name of candidates file
ballotFile = "BALLOTS.txt" # location/name of ballots file
boolEliminationRoundsComplete = False
resultsFileText = ""



# Open candidates name file and assign to list
resultsFileText += "LIST OF ALL CANDIDATES (including write-ins):\n"
candidateNamesFile = open(candidateNamesFile, 'r')
candidateData = []
candidateNum = 0
for line in candidateNamesFile:
    line = line.strip()
    if len(line) > 2:
        candidateData.append([line,0,0]) 
        candidateNum += 1
        resultsFileText += line + "\n"
candidateNamesFile.close()
totalCandidatesNum = candidateNum
  
# Open ballot file and make list of ballots
resultsFileText += "\nRAW BALLOTS:\n"
ballotFile = open(ballotFile, 'r')  
ballots = []
for line in ballotFile:
    line = line.strip()
    ballot = line.split("|")
    ballots.append(ballot)
    resultsFileText +="[" + ', '.join(ballot) + "]\n"
ballotFile.close()
# for debugging:
print(ballots)
print(candidateData)
print(candidateNum)
  
while boolEliminationRoundsComplete == False:
    # count each candidate's "firsts"
    leastFirstsNum = len(ballots) # max number of firsts is the number of ballots
    totalFirstsNum = 0 # count all the firsts (poss. less than number of ballots)
    for candidate in candidateData:
        candidate[1] = 0 # reset number of firsts to zero
        for ballot in ballots:
            if ballot[0] == candidate[0]:
                candidate[1] += 1
                totalFirstsNum += 1
        if candidate[1] > 0: # searching for the smallest number of "firsts"
            leastFirstsNum = min(leastFirstsNum,candidate[1]) 
    for candidate in candidateData:
        candidate[2] = candidate[1]/totalFirstsNum # record percentage of first for the candidate
    # make list of candidates with no "firsts"         
    noFirstsCandidates = [x for x in candidateData if (x[1] == 0)]
    if len(noFirstsCandidates) > 0:
        resultsFileText += "\nCandidates with no 'firsts' removed: "
        for candidate in noFirstsCandidates:
            resultsFileText += candidate[0] + ', '
        resultsFileText = resultsFileText[:-2] + ".\n" # remove trailing ", " then add period
        resultsFileText += "\nNew state of ballots:\n"
    else:
        resultsFileText += "\n"
    # remove candidates with "no firsts" from candidate list
    candidateData[:] = [x for x in candidateData if (x[1] != 0)]
    # remove "no firsts" candidates from ballots
    for candidate in noFirstsCandidates:
        for ballot in ballots:
            try:
                ballot.remove(candidate[0])
            except Exception:
                dunno = True #made me put something
    if len(noFirstsCandidates) > 0:
        for ballot in ballots: # print present state of ballots
            resultsFileText +="[" + ', '.join(ballot) + "]\n"
    candidateNum = len(candidateData)
  
    # calculate whether lowest candidate(s) should be eliminated by dividing smallest number of firsts
    # into each candidate's firsts, drop fractions, add the result, compare to delegateNum
    resultNum = 0
    resultsFileText += "\nNumber of 'firsts' for each remaining candidate:\n"
    for candidate in candidateData:
        resultsFileText += candidate[0] + ": " + str(candidate[1]) + " (" + "{:.1%}".format(candidate[2]) + ")\n"
        resultNum += int(candidate[1]/leastFirstsNum)
    if resultNum > delegateNum: # too many delegates if we stop here
        eliminatedCandidates = [x for x in candidateData if (x[1] == leastFirstsNum)]
        strEliminatedStatement = "Awarding a delegate to the candidate(s) with " + str(leastFirstsNum) + " 'firsts' would result in " \
            + str(resultNum) + " delegates (more than " + str(delegateNum) + "); "
        for candidate in eliminatedCandidates:
            strEliminatedStatement += candidate[0] + ", "
        strEliminatedStatement = strEliminatedStatement[:-2] #remove trailing ", "
        strEliminatedStatement += " eliminated."
        resultsFileText += "\n" + strEliminatedStatement + "\n"
        candidateData = [x for x in candidateData if (x[1] != leastFirstsNum)]
        # remove eliminated candidates from ballots
        for candidate in eliminatedCandidates:
            for ballot in ballots:
                try:
                    ballot.remove(candidate[0])
                except Exception:
                    dunno = True #made me put something
        candidateNum = len(candidateData)
        resultsFileText += "\nNew state of ballots:\n"
        for ballot in ballots: # print present state of ballots
            resultsFileText +="[" + ', '.join(ballot) + "]\n"
    else:
        boolEliminationRoundsComplete = True
        resultsFileText += "\nAwarding a delegate to the candidate(s) with " + str(leastFirstsNum) + " 'firsts' would not result in " \
            " more than " + str(delegateNum) + " delegates.\n\nELIMINATION ROUND COMPLETE"
  
# CALCULATE ASSIGNMENT OF DELEGATE VOTES TO CANDIDATES
# get partitions of the number of delegate votes of size equal to number of remaining candidates
def partition(number):
    answer = set()
    answer.add((number, ))
    for x in range(1, number):
        for y in partition(number - x):
            answer.add((x, ) + y)
    return answer
rawPartitions = partition(delegateNum)
restrictedPartitions = []
for element in rawPartitions:
    if len(element) == candidateNum:
        restrictedPartitions.append(list(element))
print(restrictedPartitions)
  
# get upper triangle of indices for pairs of candidates to do pairwise comparison of CVDs
def upperTriangle(number):
    index = 0
    listNumber = []
    while index < number:
        listNumber.append(index)
        index += 1
    cartesianProduct = [[x,y] for x in listNumber for y in listNumber]
    upperTriangle = []
    for pair in cartesianProduct:
        if pair[0] < pair[1]:
            upperTriangle.append(pair)
    return upperTriangle
pairwise = upperTriangle(candidateNum)
print(pairwise)
  
# calculate minimum differences of percentage value of a delegate (PVD) among the candidates for each partition
calculatedPVDSums = [] # to store a list of tuples of the form [partition, summed PVDs]
for thisPartition in restrictedPartitions:
    totalPVD = 0
    firstCandidatePVD = 0
    secondCandidatePVD = 0
    for pair in pairwise:
        firstCandidatePVD = candidateData[pair[0]][2]/thisPartition[pair[0]]
        secondCandidatePVD = candidateData[pair[1]][2]/thisPartition[pair[1]]
        totalPVD += abs(firstCandidatePVD - secondCandidatePVD)
        print(str(firstCandidatePVD) + ":" + str(secondCandidatePVD) + ":" + str(totalPVD))
    calculatedPVDSums.append([thisPartition,totalPVD])
# function to sort calculated PVD sums by value of the sum, ascending
def Sort(sub_li):  
    return(sorted(sub_li, key = lambda x: x[1]))
sortedPVDsums = Sort(calculatedPVDSums)
# write the results to the report
resultsFileText += "\nBelow are the calculated sums of the pairwise differences of Percentage Value of a Delegate " \
    + "for each possible apportionment of " + str(delegateNum) + " delegates among the " \
    + str(candidateNum) + " remaining candidates. The apportionment with the smallest sum (listed first) should be chosen.\n\n"
for summedPVDs in sortedPVDsums:
    resultsFileText += str(summedPVDs) + "\n"
    #print(summedPVDs)
# CREATE RESULTS FILE
thisDateTime = datetime.datetime.now().strftime("%m%d%H%M")
fileResults = open('electionResults' + thisDateTime + '.txt', 'w')
fileResults.write("BALLOT RESULTS FILE\n\n")
fileResults.write("Number of candidates: " + str(totalCandidatesNum) + "\n")
fileResults.write("Number of ballots received: " + str(len(ballots)) + "\n\n")
  fileResults.write(resultsFileText)
fileResults.close()

Tags: