Beispiel #1
0
def relative_superiority(m_votes,
                         v_total_seats,
                         v_party_seats,
                         m_prior_allocations,
                         divisor_gen,
                         threshold=None,
                         **kwargs):
    """Apportion by Þorkell Helgason's Relative Superiority method"""

    m_allocations = deepcopy(m_prior_allocations)
    num_allocated = sum([sum(x) for x in m_allocations])
    num_total_seats = sum(v_total_seats)
    for n in range(num_total_seats - num_allocated):
        m_votes = threshold_elimination_constituencies(m_votes, 0.0,
                                                       v_party_seats,
                                                       m_allocations)
        superiority = []
        first_in = []
        for c in range(len(m_votes)):
            seats_left = v_total_seats[c] - sum(m_allocations[c])
            if not seats_left:
                superiority.append(0)
                first_in.append(0)
                continue

            # Find the party next in line in the constituency:
            next_alloc_num = sum(m_allocations[c]) + 1
            alloc_next, div_next = apportion1d(m_votes[c], next_alloc_num,
                                               m_allocations[c], divisor_gen)
            diff = [
                alloc_next[p] - m_allocations[c][p]
                for p in range(len(m_votes[c]))
            ]
            next_in = diff.index(1)
            first_in.append(next_in)

            # Calculate continuation:
            _, div_after = apportion1d(m_votes[c], v_total_seats[c] + 1,
                                       m_allocations[c], divisor_gen)

            # Calculate relative superiority
            try:
                rs = float(div_next[2]) / div_after[2]
            except ZeroDivisionError:
                # If the next party is last possible, it must get the seat
                rs = 1000000
            superiority.append(rs)

        # Allocate seat in constituency where the calculated
        #  relative superiority is highest:
        greatest = max(superiority)
        idx = superiority.index(greatest)
        m_allocations[idx][first_in[idx]] += 1

    return m_allocations, None
def relative_superiority(m_votes,
                         v_const_seats,
                         v_party_seats,
                         m_prior_allocations,
                         divisor_gen,
                         threshold=None,
                         **kwargs):
    """Apportion by Þorkell Helgason's Relative Superiority method"""

    m_allocations = deepcopy(m_prior_allocations)
    num_preallocated_seats = sum([sum(x) for x in m_allocations])
    num_total_seats = sum(v_const_seats)
    for n in range(num_total_seats - num_preallocated_seats):
        m_votes = threshold_elimination_constituencies(m_votes, 0.0,
                                                       v_party_seats,
                                                       m_allocations)
        superiority = []
        firstin = []
        for j in range(len(m_votes)):
            seats_left = v_const_seats[j] - sum(m_allocations[j])
            if not seats_left:
                superiority.append(0)
                firstin.append(0)
                continue

            next_alloc_num = sum(m_allocations[j]) + 1
            app_next = apportion1d(m_votes[j], next_alloc_num,
                                   m_allocations[j], divisor_gen)
            change = [
                0 if app_next[0][i] == m_allocations[j][i] else 1
                for i in range(len(m_votes[j]))
            ]
            nextin = change.index(1)
            new_votes = copy(m_votes[j])
            new_votes[nextin] = app_next[0][2]
            firstin.append(nextin)
            # Create a provisional allocation where nextin gets the seat:
            v_prov_allocations = copy(m_allocations[j])
            v_prov_allocations[nextin] += 1
            # Calculate continuation:
            app_after = apportion1d(new_votes, v_const_seats[j] + 1,
                                    v_prov_allocations, divisor_gen)

            # Calculate relative superiority
            try:
                rs = float(app_next[1][2]) / app_after[1][2]
            except ZeroDivisionError:
                rs = 0
            superiority.append(rs)

        greatest = max(superiority)
        idx = superiority.index(greatest)
        m_allocations[idx][firstin[idx]] += 1

    return m_allocations
    def party_step(v_votes, party_id, v_const_multipliers,
                   v_party_multipliers):
        num_total_seats = v_party_seats[party_id]
        pm = party_multiplier = v_party_multipliers[party_id]
        #
        v_scaled_votes = [
            a / (b * pm) if b != 0 else None
            for a, b in zip(v_votes, v_const_multipliers)
        ]

        v_priors = [
            m_prior_allocations[x][party_id]
            for x in range(len(m_prior_allocations))
        ]

        alloc, div = apportion1d(v_scaled_votes, num_total_seats, v_priors,
                                 divisor_gen)

        minval = div[2]
        maxval = max([
            float(a) / b if a is not None else 0
            for a, b in zip(v_scaled_votes, div[0])
        ])
        party_multiplier = (minval + maxval) / 2

        # TODO: Make pretty-print intermediate tables on --debug
        #print "Party %d" % (party_id)
        #print " - Divisors: ", div[0]
        #print " - Scaled: ", v_scaled_votes
        #print " - Min: ", minval
        #print " - Max: ", maxval
        #print " - New const multiplier: ", party_multiplier
        #print " - Allocations: ", alloc

        return alloc, party_multiplier
    def const_step(v_votes, const_id, v_const_multipliers,
                   v_party_multipliers):
        num_total_seats = v_const_seats[const_id]
        cm = const_multiplier = v_const_multipliers[const_id]
        # See IV.3.5 in paper:
        v_scaled_votes = [
            a / (b * cm) if b * cm != 0 else 0
            for a, b in zip(v_votes, v_party_multipliers)
        ]

        v_priors = m_prior_allocations[const_id]

        alloc, div = apportion1d(v_scaled_votes, num_total_seats, v_priors,
                                 divisor_gen)

        # See IV.3.9 in paper:
        minval = div[
            2]  # apportion1d gives us the last used value, which is min
        maxval = max([
            float(a) / b if a is not 0 and a is not None else 0
            for a, b in zip(v_scaled_votes, div[0])
        ])
        const_multiplier = (minval + maxval) / 2

        # TODO: Make pretty-print intermediate tables on --debug
        # Results -- kind of
        #print "Constituency %d" % (const_id)
        #print " - Divisors: ", div[0]
        #print " - Scaled: ", v_scaled_votes
        #print " - Min: ", minval
        #print " - Max: ", maxval
        #print " - New const multiplier: ", const_multiplier
        #print " - Allocations: ", alloc
        return alloc, const_multiplier
Beispiel #5
0
    def run_primary_apportionment(self):
        """Conduct primary apportionment"""
        if self.rules["debug"]:
            print(" + Primary apportionment")

        gen = self.rules.get_generator("primary_divider")
        const_seats = self.rules["constituency_seats"]
        parties = self.rules["parties"]

        m_allocations = []
        self.last = []
        for i in range(len(const_seats)):
            num_seats = const_seats[i]
            if num_seats != 0:
                alloc, div = apportion1d(self.m_votes[i], num_seats,
                                         [0] * len(parties), gen)
                self.last.append(div[2])
            else:
                alloc = [0] * len(parties)
                self.last.append(0)
            m_allocations.append(alloc)
            # self.order.append(seats)

        # Useful:
        # print tabulate([[parties[x] for x in y] for y in self.order])

        v_allocations = [sum(x) for x in zip(*m_allocations)]

        self.m_const_seats_alloc = m_allocations
        self.v_const_seats_alloc = v_allocations
Beispiel #6
0
 def run_determine_adjustment_seats(self):
     """Calculate the number of adjustment seats each party gets."""
     if self.rules["debug"]:
         print(" + Determine adjustment seats")
     v_votes = self.v_votes_eliminated
     gen = self.rules.get_generator("adj_determine_divider")
     v_priors = self.v_const_seats_alloc
     v_seats, _ = apportion1d(v_votes, self.total_seats, v_priors, gen)
     self.v_adjustment_seats = v_seats
     return v_seats
def relative_inferiority(m_votes,
                         v_const_seats,
                         v_party_seats,
                         m_prior_allocations,
                         divisor_gen,
                         threshold=None,
                         **kwargs):
    """Apportion by Þorkell Helgason's Relative Inferiority method."""

    assert ("last" in kwargs)
    last = kwargs["last"]

    m_allocations = deepcopy(m_prior_allocations)
    num_allocated = sum([sum(x) for x in m_allocations])
    num_total_seats = sum(v_const_seats)
    for n in range(num_total_seats - num_allocated):
        m_votes = threshold_elimination_constituencies(m_votes, 0.0,
                                                       v_party_seats,
                                                       m_allocations)
        inferiority = []
        first_in = []
        next_used = []
        for j in range(len(m_votes)):
            seats_left = v_const_seats[j] - sum(m_allocations[j])
            if not seats_left:
                inferiority.append(10000000)
                first_in.append(0)
                next_used.append(0)
                continue

            # Find the party next in line in the constituency:
            next_alloc_num = sum(m_allocations[j]) + 1
            alloc_next, div = apportion1d(m_votes[j], next_alloc_num,
                                          m_allocations[j], divisor_gen)
            diff = [
                alloc_next[i] - m_allocations[j][i]
                for i in range(len(m_votes[j]))
            ]
            next_in = diff.index(1)
            first_in.append(next_in)
            next_used.append(div[2])

            # Calculate relative inferiority:
            ri = float(last[j]) / next_used[j]
            inferiority.append(ri)

        # Allocate seat in constituency where the calculated
        #  relative inferiority is lowest:
        least = min(inferiority)
        idx = inferiority.index(least)
        m_allocations[idx][first_in[idx]] += 1
        last[idx] = next_used[idx]

    return m_allocations, None
Beispiel #8
0
def nearest_neighbor(m_votes,
                     v_total_seats,
                     v_party_seats,
                     m_prior_allocations,
                     divisor_gen,
                     threshold=None,
                     **kwargs):

    assert ("last" in kwargs)
    last = kwargs["last"]

    m_allocations = deepcopy(m_prior_allocations)
    num_allocated = sum([sum(x) for x in m_allocations])
    num_total_seats = sum(v_total_seats)
    for n in range(num_total_seats - num_allocated):
        m_votes = threshold_elimination_constituencies(m_votes, 0.0,
                                                       v_party_seats,
                                                       m_allocations)
        neighbor_ratio = []
        first_in = []
        next_used = []
        for c in range(len(m_votes)):
            seats_left = v_total_seats[c] - sum(m_allocations[c])
            if not seats_left:
                neighbor_ratio.append(10000000)
                first_in.append(0)
                next_used.append(0)
                continue

            # Find the party next in line in the constituency:
            next_alloc_num = sum(m_allocations[c]) + 1
            alloc_next, div = apportion1d(m_votes[c], next_alloc_num,
                                          m_allocations[c], divisor_gen)
            diff = [
                alloc_next[p] - m_allocations[c][p]
                for p in range(len(m_votes[c]))
            ]
            next_in = diff.index(1)
            first_in.append(next_in)
            next_used.append(div[2])

            # Calculate neighbor ratio:
            nr = float(last[c]) / next_used[c]
            neighbor_ratio.append(nr)

        # Allocate seat in constituency where the calculated
        #  neighbor ratio is lowest:
        least = min(neighbor_ratio)
        idx = neighbor_ratio.index(least)
        m_allocations[idx][first_in[idx]] += 1
        last[idx] = next_used[idx]

    return m_allocations, None
Beispiel #9
0
    def party_step(v_votes, party_id, const_multipliers, party_multipliers):
        num_total_seats = v_party_seats[party_id]
        pm = party_multiplier = party_multipliers[party_id]
        
        v_scaled_votes = [a/(b*pm) if b != 0 else 0
                          for a, b in zip(v_votes, const_multipliers)]

        v_priors = [const_alloc[party_id] for const_alloc in m_allocations]

        alloc, div = apportion1d(v_scaled_votes, num_total_seats, v_priors,
                                 divisor_gen)

        minval = div[2]
        maxval = max([float(a)/b for a, b in zip(v_scaled_votes, div[0])])
        party_multiplier = (minval+maxval)/2

        return party_multiplier, alloc
Beispiel #10
0
    def const_step(v_votes, const_id, const_multipliers, party_multipliers):
        num_total_seats = v_total_seats[const_id]
        cm = const_multiplier = const_multipliers[const_id]
        # See IV.3.5 in paper:
        v_scaled_votes = [a/(b*cm) if b*cm != 0 else 0
                          for a, b in zip(v_votes, party_multipliers)]

        v_priors = m_allocations[const_id]

        alloc, div = apportion1d(v_scaled_votes, num_total_seats,
                                 v_priors, divisor_gen)

        # See IV.3.9 in paper:
        minval = div[2] # apportion1d gives the last used value, which is min
        maxval = max([float(a)/b for a, b in zip(v_scaled_votes, div[0])])
        const_multiplier = (minval+maxval)/2

        return const_multiplier, alloc
def relative_inferiority(m_votes,
                         v_const_seats,
                         v_party_seats,
                         m_prior_allocations,
                         divisor_gen,
                         threshold=None,
                         **kwargs):
    """
    Apportion by Þorkell Helgason's Relative Inferiority method.
    This method is incomplete.
    """
    m_allocations = copy(m_prior_allocations)
    m_max_seats = [[min(Ci, Pj) for Pj in v_party_seats]
                   for Ci in v_const_seats]
    # Probably not needed:
    const_filled = [False] * len(v_const_seats)
    party_filled = [False] * len(v_party_seats)

    # num_allocated =
    for i in range(10):
        for i in range(len(v_const_seats)):
            app = apportion1d(m_votes[i], 10, m_allocations[i], divisor_gen)

    return m_allocations
Beispiel #12
0
def var_alt_scal(m_votes, v_total_seats, v_party_seats,
                        m_prior_allocations, divisor_gen, threshold,
                        **kwargs):
    """
    # Implementation of the Alternating-Scaling algorithm.

    Inputs:
        - m_votes: A matrix of votes (rows: constituencies, columns:
            parties)
        - v_const_seats: A vector of total seats in each constituency
        - v_party_seats: A vector of seats allocated to parties
        - m_prior_allocations: A matrix of where parties have previously
            gotten seats
        - divisor_gen: A generator function generating divisors, e.g. d'Hondt
        - threshold: A cutoff threshold for participation.
    """
    m_allocations = deepcopy(m_prior_allocations)

    def const_step(v_votes, const_id, const_multipliers, party_multipliers):
        num_total_seats = v_total_seats[const_id]
        cm = const_multiplier = const_multipliers[const_id]
        # See IV.3.5 in paper:
        v_scaled_votes = [a/(b*cm) if b*cm != 0 else 0
                          for a, b in zip(v_votes, party_multipliers)]

        v_priors = m_allocations[const_id]

        alloc, div = apportion1d(v_scaled_votes, num_total_seats,
                                 v_priors, divisor_gen)

        # See IV.3.9 in paper:
        minval = div[2] # apportion1d gives the last used value, which is min
        maxval = max([float(a)/b for a, b in zip(v_scaled_votes, div[0])])
        const_multiplier = (minval+maxval)/2

        return const_multiplier, alloc

    def party_step(v_votes, party_id, const_multipliers, party_multipliers):
        num_total_seats = v_party_seats[party_id]
        pm = party_multiplier = party_multipliers[party_id]
        
        v_scaled_votes = [a/(b*pm) if b != 0 else 0
                          for a, b in zip(v_votes, const_multipliers)]

        v_priors = [const_alloc[party_id] for const_alloc in m_allocations]

        alloc, div = apportion1d(v_scaled_votes, num_total_seats, v_priors,
                                 divisor_gen)

        minval = div[2]
        maxval = max([float(a)/b for a, b in zip(v_scaled_votes, div[0])])
        party_multiplier = (minval+maxval)/2

        return party_multiplier, alloc

    num_constituencies = len(m_votes)
    num_parties = len(m_votes[0])
    const_multipliers = [1] * num_constituencies
    party_multipliers = [1] * num_parties
    step = 0

    while step < 100:
        # Constituency step:
        c_muls = []
        const_allocs = []
        for c in range(num_constituencies):
            mul, alloc = const_step(m_votes[c], c, const_multipliers,
                                    party_multipliers)
            const_multipliers[c] *= mul
            c_muls.append(mul)
            const_allocs.append(alloc)

        # Party step:
        p_muls = []
        party_allocs = []
        for p in range(num_parties):
            vp = [v[p] for v in m_votes]
            mul, alloc = party_step(vp, p, const_multipliers,
                                    party_multipliers)
            party_multipliers[p] *= mul
            p_muls.append(mul)
            party_allocs.append(alloc)

        step += 1

        # Stop when constituency step and party step give the same result
        done = all([const_allocs[i][j] == party_allocs[j][i]
                    for i in range(len(const_allocs))
                    for j in range(len(party_allocs))])
        if done:
            break

    # Finally, use party_multipliers and const_multipliers to arrive at
    #  final apportionment:
    results = []
    for c in range(num_constituencies):
        num_total_seats = v_total_seats[c]
        cm = const_multipliers[c]
        v_scaled_votes = [a/(b*cm) if b*cm != 0 else 0
                          for a, b in zip(m_votes[c], party_multipliers)]
        v_priors = m_allocations[c]
        alloc, _ = apportion1d(v_scaled_votes, num_total_seats,
                                 v_priors, divisor_gen)
        results.append(alloc)

    return results, None
def alternating_scaling(m_votes, v_const_seats, v_party_seats,
                        m_prior_allocations, divisor_gen, threshold, **kwargs):
    """
    # Implementation of the Alternating-Scaling algorithm.

    Inputs:
        - m_votes_orig: A matrix of votes (rows: constituencies, columns:
          parties)
        - v_const_seats: A vector of constituency seats
        - v_party_seats: A vector of seats allocated to parties
        - m_prior_allocations: A matrix of where parties have previously gotten
          seats
        - divisor_gen: A generator function generating divisors, e.g. d'Hondt
        - threshold: A cutoff threshold for participation.
    """
    def const_step(v_votes, const_id, v_const_multipliers,
                   v_party_multipliers):
        num_total_seats = v_const_seats[const_id]
        cm = const_multiplier = v_const_multipliers[const_id]
        # See IV.3.5 in paper:
        v_scaled_votes = [
            a / (b * cm) if b * cm != 0 else 0
            for a, b in zip(v_votes, v_party_multipliers)
        ]

        v_priors = m_prior_allocations[const_id]

        alloc, div = apportion1d(v_scaled_votes, num_total_seats, v_priors,
                                 divisor_gen)

        # See IV.3.9 in paper:
        minval = div[
            2]  # apportion1d gives us the last used value, which is min
        maxval = max([
            float(a) / b if a is not 0 and a is not None else 0
            for a, b in zip(v_scaled_votes, div[0])
        ])
        const_multiplier = (minval + maxval) / 2

        # TODO: Make pretty-print intermediate tables on --debug
        # Results -- kind of
        #print "Constituency %d" % (const_id)
        #print " - Divisors: ", div[0]
        #print " - Scaled: ", v_scaled_votes
        #print " - Min: ", minval
        #print " - Max: ", maxval
        #print " - New const multiplier: ", const_multiplier
        #print " - Allocations: ", alloc
        return alloc, const_multiplier

    def party_step(v_votes, party_id, v_const_multipliers,
                   v_party_multipliers):
        num_total_seats = v_party_seats[party_id]
        pm = party_multiplier = v_party_multipliers[party_id]
        #
        v_scaled_votes = [
            a / (b * pm) if b != 0 else None
            for a, b in zip(v_votes, v_const_multipliers)
        ]

        v_priors = [
            m_prior_allocations[x][party_id]
            for x in range(len(m_prior_allocations))
        ]

        alloc, div = apportion1d(v_scaled_votes, num_total_seats, v_priors,
                                 divisor_gen)

        minval = div[2]
        maxval = max([
            float(a) / b if a is not None else 0
            for a, b in zip(v_scaled_votes, div[0])
        ])
        party_multiplier = (minval + maxval) / 2

        # TODO: Make pretty-print intermediate tables on --debug
        #print "Party %d" % (party_id)
        #print " - Divisors: ", div[0]
        #print " - Scaled: ", v_scaled_votes
        #print " - Min: ", minval
        #print " - Max: ", maxval
        #print " - New const multiplier: ", party_multiplier
        #print " - Allocations: ", alloc

        return alloc, party_multiplier

    num_constituencies = len(m_votes)
    num_parties = len(m_votes[0])
    const_multipliers = [1] * num_constituencies
    party_multipliers = [1] * num_parties
    step = 0

    const_done = False
    party_done = False
    while step < 200:
        step += 1
        if step % 2 == 1:
            #Constituency step:
            muls = []
            for c in range(num_constituencies):
                alloc, mul = const_step(m_votes[c], c, const_multipliers,
                                        party_multipliers)
                const_multipliers[c] *= mul
                muls.append(mul)
            const_done = all([round(x, 5) == 1.0 or x == 500000 for x in muls])
        else:
            # print "== Party step %d ==" % step
            muls = []
            for p in range(num_parties):
                vp = [v[p] for v in m_votes]
                alloc, mul = party_step(vp, p, const_multipliers,
                                        party_multipliers)
                party_multipliers[p] *= mul
                muls.append(mul)
            party_done = all([round(x, 5) == 1.0 or x == 500000 for x in muls])

        if const_done and party_done:
            break

    # Finally, use party_multipliers and const_multipliers to arrive at
    #  final apportionment:
    results = []
    for c in range(num_constituencies):
        num_total_seats = v_const_seats[c]
        cm = const_multipliers[c]
        v_scaled_votes = [
            a / (b * cm) if b != 0 else None
            for a, b in zip(m_votes[c], party_multipliers)
        ]
        v_priors = m_prior_allocations[c]
        alloc, div = apportion1d(v_scaled_votes, num_total_seats, v_priors,
                                 divisor_gen)
        results.append(alloc)

    return results
Beispiel #14
0
def switching(m_votes,
              v_total_seats,
              v_party_seats,
              m_prior_allocations,
              divisor_gen,
              threshold=None,
              orig_votes=None,
              **kwargs):

    v_prior_allocations = [sum(x) for x in zip(*m_prior_allocations)]
    # The number of adjustment seats each party should receive:
    correct_adj_seats = [
        v_party_seats[p] - v_prior_allocations[p]
        for p in range(len(v_party_seats))
    ]

    # Allocate adjustment seats as if they were constituency seats
    m_adj_seats = []
    for c in range(len(m_prior_allocations)):
        votes = [
            m_votes[c][p] if correct_adj_seats[p] > 0 else 0
            for p in range(len(m_votes[c]))
        ]
        alloc, div = apportion1d(votes, v_total_seats[c],
                                 m_prior_allocations[c], divisor_gen)
        adj_seats = [
            alloc[p] - m_prior_allocations[c][p] for p in range(len(alloc))
        ]
        m_adj_seats.append(adj_seats)

    # Transfer adjustment seats within constituencies from parties that have
    #  too many seats to parties that have too few seats, prioritized by
    #  "sensitivity", until all parties have the correct number of seats
    #  or no more swaps can be made:

    done = False
    while not done:
        v_adj_seats = [sum(x) for x in zip(*m_adj_seats)]
        diff_party = [
            v_adj_seats[p] - correct_adj_seats[p]
            for p in range(len(v_adj_seats))
        ]

        over = [i for i in range(len(diff_party)) if diff_party[i] > 0]
        under = [i for i in range(len(diff_party)) if diff_party[i] < 0]
        sensitivity = []
        for i in range(len(m_votes)):
            for j in over:
                for k in under:
                    if m_adj_seats[i][j] != 0 and m_votes[i][k] != 0:
                        gen_j = divisor_gen()
                        j_seats = m_prior_allocations[i][j] + m_adj_seats[i][j]
                        for x in range(j_seats):
                            div_j = next(gen_j)
                        gen_k = divisor_gen()
                        k_seats = m_prior_allocations[i][k] + m_adj_seats[i][k]
                        for x in range(k_seats + 1):
                            div_k = next(gen_k)
                        s = (m_votes[i][j] / div_j) / (m_votes[i][k] / div_k)
                        heapq.heappush(sensitivity, (s, (i, j, k)))

        done = len(sensitivity) == 0
        if not done:
            # Find the constituency and pair of parties with the lowest
            #  sensitivity, and transfer a seat:
            i, j, k = heapq.heappop(sensitivity)[1]
            m_adj_seats[i][j] -= 1
            m_adj_seats[i][k] += 1

    m_allocations = [[
        m_prior_allocations[c][p] + m_adj_seats[c][p]
        for p in range(len(m_adj_seats[c]))
    ] for c in range(len(m_adj_seats))]

    return m_allocations, None
Beispiel #15
0
def icelandic_apportionment(m_votes, v_total_seats, v_party_seats,
                            m_prior_allocations, divisor_gen, threshold=None,
                            orig_votes=None, **kwargs):
    """
    Apportion based on Icelandic law nr. 24/2000.
    """
    m_allocations = deepcopy(m_prior_allocations)

    # 2.1.
    #   (Deila skal í atkvæðatölur samtakanna með tölu kjördæmissæta þeirra,
    #   fyrst að viðbættum 1, síðan 2, þá 3 o.s.frv. Útkomutölurnar nefnast
    #   landstölur samtakanna.)
    v_seats = [sum(x) for x in zip(*m_prior_allocations)]
    v_votes = [sum(x) for x in zip(*m_votes)]
    num_allocated = sum(v_seats)
    total_seats = sum(v_total_seats)

    # 2.2.
    #   (Taka skal saman skrá um þau tvö sæti hvers framboðslista sem næst
    #   komust því að fá úthlutun í kjördæmi skv. 107. gr. Við hvert
    #   þessara sæta skal skrá hlutfall útkomutölu sætisins skv. 1. tölul.
    #   107. gr. af öllum gildum atkvæðum í kjördæminu.)
    # Create list of 2 top seats on each remaining list that almost got in.


    # 2.7.
    #   (Beita skal ákvæðum 3. tölul. svo oft sem þarf þar til lokið er
    #   úthlutun allra jöfnunarsæta, sbr. 2. mgr. 8. gr.)
    invalid = []
    v_last_alloc = deepcopy(v_seats)
    seats_info = []
    while num_allocated < total_seats:
        alloc, d = apportion1d(v_votes, num_allocated+1, v_last_alloc,
                                divisor_gen, invalid)
        # 2.6.
        #   (Hafi allar hlutfallstölur stjórnmálasamtaka verið numdar brott
        #   skal jafnframt fella niður allar landstölur þeirra.)

        diff = [alloc[j]-v_last_alloc[j] for j in range(len(alloc))]
        idx = diff.index(1)

        v_proportions = []
        for const in range(len(m_votes)):
            const_votes = orig_votes[const]
            s = sum(const_votes)
            div = divisor_gen()
            for i in range(m_allocations[const][idx]+1):
                x = next(div)
            p = (float(const_votes[idx])/s)/x
            v_proportions.append(p)

            # 2.5.
            #   (Þegar lokið hefur verið að úthluta jöfnunarsætum í hverju
            #   kjördæmi skv. 2. mgr. 8. gr. skulu hlutfallstölur allra
            #   lista í því kjördæmi felldar niður.)
            if sum(m_allocations[const]) == v_total_seats[const]:
                v_proportions[const] = 0

        # 2.3.
        #   (Finna skal hæstu landstölu skv. 1. tölul. sem hefur ekki þegar
        #   verið felld niður. Hjá þeim stjórnmálasamtökum, sem eiga þá
        #   landstölu, skal finna hæstu hlutfallstölu lista skv. 2. tölul.
        #   og úthluta jöfnunarsæti til hans. Landstalan og hlutfallstalan
        #   skulu síðan báðar felldar niður.)

        if max(v_proportions) != 0:
            const = [j for j,k in enumerate(v_proportions)
                        if k == max(v_proportions)]
            if len(const) > 1:
                # 2.4.
                #   (Nú eru tvær eða fleiri lands- eða hlutfallstölur jafnháar
                #   þegar að þeim kemur skv. 3. tölul. og skal þá hluta um röð
                #   þeirra.)
                const = [random.choice(const)]

            m_allocations[const[0]][idx] += 1
            num_allocated += 1
            v_last_alloc = alloc
            seats_info.append((const[0], d[2], idx,
                                v_proportions[const[0]]))
        else: 
            invalid.append(idx)
    return m_allocations, seats_info
Beispiel #16
0
def icelandic_apportionment(m_votes,
                            v_const_seats,
                            v_party_seats,
                            m_prior_allocations,
                            divisor_gen,
                            threshold=None,
                            orig_votes=None,
                            **kwargs):
    """
    Apportion based on Icelandic law nr. 24/2000.
    """
    m_allocations = deepcopy(m_prior_allocations)

    # 2.1
    #       (Deila skal í atkvæðatölur samtakanna með tölu kjördæmissæta þeirra,
    #        fyrst að viðbættum 1, síðan 2, þá 3 o.s.frv. Útkomutölurnar nefnast
    #        landstölur samtakanna.)
    v_seats = [sum(x) for x in zip(*m_prior_allocations)]
    v_votes = [sum(x) for x in zip(*m_votes)]
    num_allocated = sum(v_seats)
    num_missing = sum(v_const_seats) - num_allocated

    # 2.2. Create list of 2 top seats on each remaining list that almost got in.
    #       (Taka skal saman skrá um þau tvö sæti hvers framboðslista sem næst
    #        komust því að fá úthlutun í kjördæmi skv. 107. gr. Við hvert
    #        þessara sæta skal skrá hlutfall útkomutölu sætisins skv. 1. tölul.
    #        107. gr. af öllum gildum atkvæðum í kjördæminu.)

    # 2.7.
    #       (Beita skal ákvæðum 3. tölul. svo oft sem þarf þar til lokið er
    #        úthlutun allra jöfnunarsæta, sbr. 2. mgr. 8. gr.)
    v_last_alloc = deepcopy(v_seats)
    for i in range(num_allocated + 1, num_allocated + num_missing + 1):
        alloc, div = apportion1d(v_votes, i, v_last_alloc, divisor_gen)
        # 2.6.
        #       (Hafi allar hlutfallstölur stjórnmálasamtaka verið numdar brott
        #        skal jafnframt fella niður allar landstölur þeirra.)

        diff = [alloc[i] - v_last_alloc[i] for i in range(len(alloc))]
        idx = diff.index(1)
        v_last_alloc = alloc

        m_proportions = []
        for cons in range(len(m_votes)):
            cons_votes = orig_votes[cons]
            s = sum(cons_votes)
            proportions = []
            for party in range(len(m_votes[0])):
                d = divisor_gen()
                for j in range(m_allocations[cons][party] + 1):
                    x = next(d)
                k = (float(orig_votes[cons][party]) / s) / x
                proportions.append(k)

            m_proportions.append(proportions)

            # 2.5.
            #       (Þegar lokið hefur verið að úthluta jöfnunarsætum í hverju
            #        kjördæmi skv. 2. mgr. 8. gr. skulu hlutfallstölur allra
            #        lista í því kjördæmi felldar niður.)
            if sum(m_allocations[cons]) == v_const_seats[cons]:
                # print "Done allocating in constituency %d" % (cons)
                m_proportions[cons] = [0] * len(v_seats)

        # 2.3.
        #       (Finna skal hæstu landstölu skv. 1. tölul. sem hefur ekki þegar
        #        verið felld niður. Hjá þeim stjórnmálasamtökum, sem eiga þá
        #        landstölu, skal finna hæstu hlutfallstölu lista skv. 2. tölul.
        #        og úthluta jöfnunarsæti til hans. Landstalan og hlutfallstalan
        #        skulu síðan báðar felldar niður.)

        w = [m_proportions[i][idx] for i in range(len(m_proportions))]
        # print "Proportions for %d: %s" % (idx, w)
        const = [i for i, j in enumerate(w) if j == max(w)]
        if len(const) > 1:
            # 2.4.
            #       (Nú eru tvær eða fleiri lands- eða hlutfallstölur jafnháar
            #        þegar að þeim kemur skv. 3. tölul. og skal þá hluta um röð
            #        þeirra.)
            const = [random.choice(const)]

        m_allocations[const[0]][idx] += 1
    return m_allocations