class Vote::Condorcet::Schulze::Classifications

Public Class Methods

new(schulze_basic) click to toggle source
# File lib/vote/condorcet/schulze/classifications.rb, line 5
def initialize(schulze_basic)
  @schulze_basic = schulze_basic
end

Public Instance Methods

classification_with_ties() click to toggle source

compute the final classification with ties included the result is an array of arrays. each position can contain one or more elements in tie e.g. [[0,1], [2,3], [4], [5]]

# File lib/vote/condorcet/schulze/classifications.rb, line 24
def classification_with_ties
  result = []
  result << @schulze_basic.potential_winners # add potential winners on first place
  result += @schulze_basic.ties.clone.sort_by { |tie| -@schulze_basic.ranking[tie[0]] } # add ties by ranking
  result.uniq! # remove duplicates (potential winners are also ties)
  add_excludeds(result)
end
classifications(limit_results = false) click to toggle source

compute all possible solutions since this can take days, there is an option to limit the number of calculated classifications the default is 10. if the system is calculating more then 10 possible classifications it will stop raising a TooManyClassifications exception you can set it to false to disable the limit

# File lib/vote/condorcet/schulze/classifications.rb, line 14
def classifications(limit_results = false)
  @classifications = []
  @limit_results = limit_results
  calculate_classifications
  @classifications
end

Private Instance Methods

add_element(classif, beated_list, start_list, element) click to toggle source
# File lib/vote/condorcet/schulze/classifications.rb, line 87
def add_element(classif, beated_list, start_list, element)
  return if beated_list.any? { |c| c[1] == element }
  classification = classif.clone << element
  next_start_list = clone_and_delete(start_list, element)
  if next_start_list.empty?
    @classifications << classification
    check_limits
  else
    compute_classifications(classification, nil,
                            beated_list.clone.delete_if { |c| c[0] == element }, next_start_list)
  end
end
add_elements(beated_list, classif, potential_winners, start_list) click to toggle source
# File lib/vote/condorcet/schulze/classifications.rb, line 72
def add_elements(beated_list, classif, potential_winners, start_list)
  potential_winners.each { |element| add_element(classif, beated_list, start_list, element) }
end
add_excludeds(result) click to toggle source
# File lib/vote/condorcet/schulze/classifications.rb, line 34
def add_excludeds(result)
  excludeds = (@schulze_basic.candidates - result.flatten) # all remaining elements (not in tie, not winners)
  excludeds.each do |excluded|
    result.each_with_index do |position, index|
      # insert before another element if they have a better ranking
      break result.insert(index, [excluded]) if better_ranking?(excluded, position[0])
      # insert at the end if it's the last possible position
      break result.insert(-1, [excluded]) if index == result.size - 1
    end
  end
  result
end
better_ranking?(a, b) click to toggle source
# File lib/vote/condorcet/schulze/classifications.rb, line 47
def better_ranking?(a, b)
  @schulze_basic.ranking[a] > @schulze_basic.ranking[b]
end
calculate_classifications() click to toggle source
# File lib/vote/condorcet/schulze/classifications.rb, line 60
def calculate_classifications
  start_list = (0..@schulze_basic.ranking.length - 1).to_a
  start_list.sort! { |e1, e2| rank_element(e1) <=> rank_element(e2) }
  compute_classifications([], @schulze_basic.potential_winners, @schulze_basic.beat_couples, start_list)
end
check_limits() click to toggle source
# File lib/vote/condorcet/schulze/classifications.rb, line 83
def check_limits
  fail TooManyClassificationsException if @limit_results && @classifications.size > @limit_results
end
clone_and_delete(list, element) click to toggle source
# File lib/vote/condorcet/schulze/classifications.rb, line 100
def clone_and_delete(list, element)
  list.clone.tap { |l| l.delete(element) }
end
compute_classifications(classif = [], potential_winners, beated_list, start_list) click to toggle source
# File lib/vote/condorcet/schulze/classifications.rb, line 66
def compute_classifications(classif = [], potential_winners, beated_list, start_list)
  return compute_permutations(classif, start_list) if beated_list.empty?
  next_list = (classif.empty? && potential_winners.any?) ? potential_winners : start_list
  add_elements(beated_list, classif, next_list, start_list)
end
compute_permutations(classif, start_list) click to toggle source
# File lib/vote/condorcet/schulze/classifications.rb, line 76
def compute_permutations(classif, start_list)
  start_list.permutation.each do |array|
    @classifications << classif + array
    check_limits
  end
end
rank_element(el) click to toggle source
# File lib/vote/condorcet/schulze/classifications.rb, line 51
def rank_element(el)
  rank = 0
  rank -= 100 if @schulze_basic.potential_winners.include?(el)
  @schulze_basic.beat_couples.each do |b|
    rank -= 1 if b[0] == el
  end
  rank
end