<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="de">
	<id>https://wikimirror.piraten.tools/wiki/index.php?action=history&amp;feed=atom&amp;title=Benutzer%3ARhoTP%2Fschulze-simple_2_3</id>
	<title>Benutzer:RhoTP/schulze-simple 2 3 - Versionsgeschichte</title>
	<link rel="self" type="application/atom+xml" href="https://wikimirror.piraten.tools/wiki/index.php?action=history&amp;feed=atom&amp;title=Benutzer%3ARhoTP%2Fschulze-simple_2_3"/>
	<link rel="alternate" type="text/html" href="https://wikimirror.piraten.tools/wiki/index.php?title=Benutzer:RhoTP/schulze-simple_2_3&amp;action=history"/>
	<updated>2026-05-03T19:00:57Z</updated>
	<subtitle>Versionsgeschichte dieser Seite in Piratenwiki Mirror</subtitle>
	<generator>MediaWiki 1.35.14</generator>
	<entry>
		<id>https://wikimirror.piraten.tools/wiki/index.php?title=Benutzer:RhoTP/schulze-simple_2_3&amp;diff=55916011&amp;oldid=prev</id>
		<title>imported&gt;RhoTP am 1. März 2014 um 23:31 Uhr</title>
		<link rel="alternate" type="text/html" href="https://wikimirror.piraten.tools/wiki/index.php?title=Benutzer:RhoTP/schulze-simple_2_3&amp;diff=55916011&amp;oldid=prev"/>
		<updated>2014-03-01T23:31:05Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Neue Seite&lt;/b&gt;&lt;/p&gt;&lt;div&gt;Hier der Source-Code für die Auswertung mit schulze-simple für 2/3 Mehrheiten (schulze-simple_2_3).&amp;lt;br/&amp;gt;&lt;br /&gt;
(Anlage für diesen Antrag : [[BE:Parteitag/2014.1/Antragskommission/Antragsportal/Sonstiger_Antrag_-_004 ]])&lt;br /&gt;
&lt;br /&gt;
Das Tool schulze-simple benutzen wir in Berlin bisher zur Auswertung von Wahlen für Kandidatenlisten nach [[BE:Wahl-_und_Geschäftsordnung#Anlage_A |Anlage A der GO]].&lt;br /&gt;
&lt;br /&gt;
Das Orginal für 1/2-Mehrheiten gibt es hier: [http://www.public-software-group.org/preftools preftools].&lt;br /&gt;
&lt;br /&gt;
Das wiki erlaubt es mir nicht Skripte hochzuladen, deshalb hier der Source-Code zum copy/pasten.&lt;br /&gt;
&lt;br /&gt;
Das Tool ist in Lua geschrieben.&lt;br /&gt;
&lt;br /&gt;
Diff von schulze-simple und schulze-simple_2_3:&lt;br /&gt;
[https://wiki.piratenpartei.de/wiki//index.php?title=Benutzer%3ARhoTP%2Fschulze-simple_2_3&amp;amp;action=historysubmit&amp;amp;diff=2284484&amp;amp;oldid=2284483 Diff]&lt;br /&gt;
&lt;br /&gt;
==Lizenz (preftools)==&lt;br /&gt;
Copyright (c) 2010 Public Software Group e. V., Berlin, Germany&lt;br /&gt;
&lt;br /&gt;
Permission is hereby granted, free of charge, to any person obtaining a&lt;br /&gt;
copy of this software and associated documentation files (the &amp;quot;Software&amp;quot;),&lt;br /&gt;
to deal in the Software without restriction, including without limitation&lt;br /&gt;
the rights to use, copy, modify, merge, publish, distribute, sublicense,&lt;br /&gt;
and/or sell copies of the Software, and to permit persons to whom the&lt;br /&gt;
Software is furnished to do so, subject to the following conditions:&lt;br /&gt;
&lt;br /&gt;
The above copyright notice and this permission notice shall be included in&lt;br /&gt;
all copies or substantial portions of the Software.&lt;br /&gt;
&lt;br /&gt;
THE SOFTWARE IS PROVIDED &amp;quot;AS IS&amp;quot;, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR&lt;br /&gt;
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,&lt;br /&gt;
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE&lt;br /&gt;
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER&lt;br /&gt;
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING&lt;br /&gt;
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER&lt;br /&gt;
DEALINGS IN THE SOFTWARE.&lt;br /&gt;
&lt;br /&gt;
==Quellcode==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/usr/bin/env lua&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----------------------&lt;br /&gt;
-- Helper functions --&lt;br /&gt;
----------------------&lt;br /&gt;
&lt;br /&gt;
function message(...)&lt;br /&gt;
  io.stderr:write(...)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
------------------------------------------&lt;br /&gt;
-- Print notice related to tie-breaking --&lt;br /&gt;
------------------------------------------&lt;br /&gt;
&lt;br /&gt;
message(&amp;quot;NOTICE: This simplified version of the program does not perform tie-breaking.\n\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--------------------------------------&lt;br /&gt;
-- Command line argument processing --&lt;br /&gt;
--------------------------------------&lt;br /&gt;
&lt;br /&gt;
settings = {}&lt;br /&gt;
&lt;br /&gt;
do&lt;br /&gt;
  local next_arg&lt;br /&gt;
  do&lt;br /&gt;
    local argv = {...}&lt;br /&gt;
    local i = 0&lt;br /&gt;
    next_arg = function()&lt;br /&gt;
      i = i + 1&lt;br /&gt;
      return argv[i]&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
  local function command_line_error()&lt;br /&gt;
    message(&amp;quot;Get help with -h or --help.\n&amp;quot;)&lt;br /&gt;
    os.exit(1)&lt;br /&gt;
  end&lt;br /&gt;
  for option in next_arg do&lt;br /&gt;
    local argument, lower_argument&lt;br /&gt;
    local function require_argument()&lt;br /&gt;
      argument = next_arg()&lt;br /&gt;
      if argument == nil then&lt;br /&gt;
        message('Command line option &amp;quot;', option, '&amp;quot; requires an argument.\n')&lt;br /&gt;
        command_line_error()&lt;br /&gt;
      end&lt;br /&gt;
      lower_argument = string.lower(argument)&lt;br /&gt;
    end&lt;br /&gt;
    local function set_setting_once(key, value)&lt;br /&gt;
      if settings[key] ~= nil then&lt;br /&gt;
        message('Command line option &amp;quot;', option, '&amp;quot; occurred multiple times.\n')&lt;br /&gt;
        command_line_error()&lt;br /&gt;
      end&lt;br /&gt;
      settings[key] = value&lt;br /&gt;
    end&lt;br /&gt;
    if option == &amp;quot;-h&amp;quot; or option == &amp;quot;--help&amp;quot; then&lt;br /&gt;
      io.stdout:write(&amp;quot;Usage:\n&amp;quot;)&lt;br /&gt;
      io.stdout:write(&amp;quot;schuool   -c|--candidates &amp;lt;candidates_file&amp;gt;\n&amp;quot;)&lt;br /&gt;
      io.stdout:write(&amp;quot;          -b|--ballots    &amp;lt;ballots_file&amp;gt;\n&amp;quot;)&lt;br /&gt;
      io.stdout:write(&amp;quot;        [ -d|--default    n|neutral|f|first|l|last            ]\n&amp;quot;)&lt;br /&gt;
      io.stdout:write(&amp;quot;        [ -o|--output     &amp;lt;output_file&amp;gt;                       ]\n&amp;quot;)&lt;br /&gt;
      os.exit(0)&lt;br /&gt;
    elseif option == &amp;quot;-c&amp;quot; or option == &amp;quot;--candidates&amp;quot; then&lt;br /&gt;
      require_argument()&lt;br /&gt;
      set_setting_once(&amp;quot;candidates_filename&amp;quot;, argument)&lt;br /&gt;
    elseif option == &amp;quot;-b&amp;quot; or option == &amp;quot;--ballots&amp;quot; then&lt;br /&gt;
      require_argument()&lt;br /&gt;
      set_setting_once(&amp;quot;ballots_filename&amp;quot;, argument)&lt;br /&gt;
    elseif option == &amp;quot;-d&amp;quot; or option == &amp;quot;--default&amp;quot; then&lt;br /&gt;
      require_argument()&lt;br /&gt;
      if lower_argument == &amp;quot;n&amp;quot; or lower_argument == &amp;quot;neutral&amp;quot; then&lt;br /&gt;
        set_setting_once(&amp;quot;default&amp;quot;, &amp;quot;n&amp;quot;)&lt;br /&gt;
      elseif lower_argument == &amp;quot;f&amp;quot; or lower_argument == &amp;quot;first&amp;quot; then&lt;br /&gt;
        set_setting_once(&amp;quot;default&amp;quot;, &amp;quot;f&amp;quot;)&lt;br /&gt;
      elseif lower_argument == &amp;quot;l&amp;quot; or lower_argument == &amp;quot;last&amp;quot; then&lt;br /&gt;
        set_setting_once(&amp;quot;default&amp;quot;, &amp;quot;l&amp;quot;)&lt;br /&gt;
      else&lt;br /&gt;
        message('Unknown default position &amp;quot;', argument, '&amp;quot; specified after ', option, ' switch.\n')&lt;br /&gt;
        command_line_error()&lt;br /&gt;
      end&lt;br /&gt;
    elseif option == &amp;quot;-o&amp;quot; or option == &amp;quot;--output&amp;quot; then&lt;br /&gt;
      require_argument()&lt;br /&gt;
      set_setting_once(&amp;quot;output_filename&amp;quot;, argument)&lt;br /&gt;
    else&lt;br /&gt;
      message('Illegal command line option &amp;quot;', option, '&amp;quot;\n')&lt;br /&gt;
      command_line_error()&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
  if settings.candidates_filename == nil then&lt;br /&gt;
    message(&amp;quot;Use -c or --candidates to specify file containing candidate information.\n&amp;quot;)&lt;br /&gt;
    command_line_error()&lt;br /&gt;
  end&lt;br /&gt;
  if settings.ballots_filename == nil then&lt;br /&gt;
    message(&amp;quot;Use -b or --ballots to specify file containing all ballot data.\n&amp;quot;)&lt;br /&gt;
    command_line_error()&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--------------------------&lt;br /&gt;
-- I/O helper functions --&lt;br /&gt;
--------------------------&lt;br /&gt;
&lt;br /&gt;
function strip(str)&lt;br /&gt;
  return string.match(str, &amp;quot;^%s*(.-)%s*$&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function stripped_lines(filename)&lt;br /&gt;
  local file, errmsg = io.open(filename, &amp;quot;r&amp;quot;)&lt;br /&gt;
  if not file then&lt;br /&gt;
    message(errmsg, &amp;quot;\n&amp;quot;)&lt;br /&gt;
    os.exit(2)&lt;br /&gt;
  end&lt;br /&gt;
  local get_next_line = file:lines(filename)&lt;br /&gt;
  return function()&lt;br /&gt;
    if not file then return nil end&lt;br /&gt;
    local line&lt;br /&gt;
    repeat&lt;br /&gt;
      line = get_next_line()&lt;br /&gt;
      if line == nil then&lt;br /&gt;
        file:close()&lt;br /&gt;
        file = nil&lt;br /&gt;
        return nil&lt;br /&gt;
      end&lt;br /&gt;
      line = strip(string.match(line, &amp;quot;^[^#]*&amp;quot;))&lt;br /&gt;
    until line ~= &amp;quot;&amp;quot;&lt;br /&gt;
    return line&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function stripped_gmatch(str, pattern)&lt;br /&gt;
  local next_entry = string.gmatch(str, pattern)&lt;br /&gt;
  return function()&lt;br /&gt;
    local entry&lt;br /&gt;
    repeat&lt;br /&gt;
      entry = next_entry()&lt;br /&gt;
      if entry then entry = strip(entry) end&lt;br /&gt;
    until entry ~= &amp;quot;&amp;quot;&lt;br /&gt;
    return entry&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
do&lt;br /&gt;
  local output_file&lt;br /&gt;
  if settings.output_filename == nil then&lt;br /&gt;
    output_file = io.stdout&lt;br /&gt;
  else&lt;br /&gt;
    local errmsg&lt;br /&gt;
    output_file, errmsg = io.open(settings.output_filename, &amp;quot;w&amp;quot;)&lt;br /&gt;
    if not output_file then&lt;br /&gt;
      message(errmsg, &amp;quot;\n&amp;quot;)&lt;br /&gt;
      os.exit(2)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
  function output(...)&lt;br /&gt;
    output_file:write(...)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function padded_number(number, maximum)&lt;br /&gt;
  local str = tostring(number)&lt;br /&gt;
  local max_digits = 1&lt;br /&gt;
  local tmp = maximum&lt;br /&gt;
  while tmp &amp;gt;= 10 do&lt;br /&gt;
    tmp = math.floor(tmp / 10)&lt;br /&gt;
    max_digits = max_digits + 1&lt;br /&gt;
  end&lt;br /&gt;
  for i = 1, max_digits - #str do&lt;br /&gt;
    str = &amp;quot; &amp;quot; .. str&lt;br /&gt;
  end&lt;br /&gt;
  return str&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
---------------------&lt;br /&gt;
-- Read candidates --&lt;br /&gt;
---------------------&lt;br /&gt;
&lt;br /&gt;
candidates = {}  -- mapping string to candidate number and vice versa&lt;br /&gt;
&lt;br /&gt;
do&lt;br /&gt;
  for line in stripped_lines(settings.candidates_filename) do&lt;br /&gt;
    for candidate in stripped_gmatch(line, &amp;quot;[^;,]+&amp;quot;) do&lt;br /&gt;
      if candidates[candidate] then&lt;br /&gt;
        message('Duplicate candidate in &amp;quot;', settings.candidates_filename, '&amp;quot;: &amp;quot;', candidate, '&amp;quot;.\n')&lt;br /&gt;
        os.exit(2)&lt;br /&gt;
      end&lt;br /&gt;
      candidates[#candidates+1] = candidate&lt;br /&gt;
      candidates[candidate] = #candidates&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
------------------------------&lt;br /&gt;
-- Read and process ballots --&lt;br /&gt;
------------------------------&lt;br /&gt;
&lt;br /&gt;
ballots = {}&lt;br /&gt;
approval_counts = {}&lt;br /&gt;
disapproval_counts = {}&lt;br /&gt;
for i = 1, #candidates do&lt;br /&gt;
  approval_counts[candidates[i]] = 0&lt;br /&gt;
  disapproval_counts[candidates[i]] = 0&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
for line in stripped_lines(settings.ballots_filename) do&lt;br /&gt;
  local ballot = {}&lt;br /&gt;
  local rank&lt;br /&gt;
  local processed = {}&lt;br /&gt;
  local approvals, neutrals, disapprovals = string.match(line, &amp;quot;^([^/]*)/([^/]*)/([^/]*)$&amp;quot;)&lt;br /&gt;
  if not approvals then&lt;br /&gt;
    approvals, neutrals, disapprovals = string.match(line, &amp;quot;^([^/]*)$&amp;quot;), &amp;quot;&amp;quot;, &amp;quot;&amp;quot;&lt;br /&gt;
  end&lt;br /&gt;
  if not approvals then&lt;br /&gt;
    message('Ill formatted ballot: &amp;quot;', line, '&amp;quot;.\n')&lt;br /&gt;
    os.exit(2)&lt;br /&gt;
  end&lt;br /&gt;
  local function process_lists(candidate_lists, count_table)&lt;br /&gt;
    for candidate_list in string.gmatch(candidate_lists, &amp;quot;[^;]+&amp;quot;) do&lt;br /&gt;
      if rank == -1 then&lt;br /&gt;
        -- only happens when there are different rankings in the neutral section&lt;br /&gt;
        message('Different rankings (semicolon) found in neutral section of ballot &amp;quot;', line, '&amp;quot;.\n')&lt;br /&gt;
        os.exit(2)&lt;br /&gt;
      end&lt;br /&gt;
      local empty = true&lt;br /&gt;
      for candidate in stripped_gmatch(candidate_list, &amp;quot;[^,]+&amp;quot;) do&lt;br /&gt;
        empty = false&lt;br /&gt;
        if not candidates[candidate] then&lt;br /&gt;
          message('Unknown candidate &amp;quot;', candidate, '&amp;quot; contained in ballot &amp;quot;', line, '&amp;quot;.\n')&lt;br /&gt;
          os.exit(2)&lt;br /&gt;
        end&lt;br /&gt;
        if processed[candidate] then&lt;br /&gt;
          message('Duplicate candidate &amp;quot;', candidate, '&amp;quot; in ballot &amp;quot;', line, '&amp;quot;.\n')&lt;br /&gt;
          os.exit(2)&lt;br /&gt;
        end&lt;br /&gt;
        ballot[candidate] = rank&lt;br /&gt;
        if count_table then&lt;br /&gt;
          count_table[candidate] = count_table[candidate] + 1&lt;br /&gt;
        end&lt;br /&gt;
        processed[candidate] = true&lt;br /&gt;
      end&lt;br /&gt;
      if not empty then&lt;br /&gt;
        -- It is important to only decrease rank, when candidates have been processed.&lt;br /&gt;
        rank = rank - 1&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
  rank = #candidates&lt;br /&gt;
  process_lists(approvals, approval_counts)&lt;br /&gt;
  rank = 0&lt;br /&gt;
  process_lists(neutrals)&lt;br /&gt;
  rank = -2  -- rank -1 is reserved for default=first&lt;br /&gt;
  process_lists(disapprovals, disapproval_counts)&lt;br /&gt;
  for i = 1, #candidates do&lt;br /&gt;
    local candidate = candidates[i]&lt;br /&gt;
    if not processed[candidate] then&lt;br /&gt;
      if settings.default == &amp;quot;n&amp;quot; then&lt;br /&gt;
        ballot[candidate] = 0&lt;br /&gt;
      elseif settings.default == &amp;quot;f&amp;quot; then&lt;br /&gt;
        ballot[candidate] = -1&lt;br /&gt;
        disapproval_counts[candidate] = disapproval_counts[candidate] + 1&lt;br /&gt;
      elseif settings.default == &amp;quot;l&amp;quot; then&lt;br /&gt;
        ballot[candidate] = -#candidates - 2&lt;br /&gt;
        disapproval_counts[candidate] = disapproval_counts[candidate] + 1&lt;br /&gt;
      else&lt;br /&gt;
        message('Candidate &amp;quot;', candidate, '&amp;quot; missing in ballot &amp;quot;', line, '&amp;quot;.\n')&lt;br /&gt;
        os.exit(2)&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
  ballots[#ballots+1] = ballot&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
-------------------------------------------------------------------------&lt;br /&gt;
-- Select approved candidates, who passed the hard-coded quota of 2/3+ --&lt;br /&gt;
-------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
local approved_candidates = {}&lt;br /&gt;
&lt;br /&gt;
do&lt;br /&gt;
  local max_approval    = 0&lt;br /&gt;
  local max_disapproval = 0&lt;br /&gt;
  local max_neutral     = 0&lt;br /&gt;
  for i = 1, #candidates do&lt;br /&gt;
    local candidate = candidates[i]&lt;br /&gt;
    local approval_count    = approval_counts[candidate]&lt;br /&gt;
    local disapproval_count = disapproval_counts[candidate]&lt;br /&gt;
    local neutral_count     = #ballots - approval_count - disapproval_count&lt;br /&gt;
    max_approval    = math.max(max_approval,    approval_count)&lt;br /&gt;
    max_disapproval = math.max(max_disapproval, disapproval_count)&lt;br /&gt;
    max_neutral     = math.max(max_neutral,     neutral_count)&lt;br /&gt;
  end&lt;br /&gt;
  output(&amp;quot;Candidates:\n&amp;quot;)&lt;br /&gt;
  for i = 1, #candidates do&lt;br /&gt;
    local candidate = candidates[i]&lt;br /&gt;
    local approval_count    = approval_counts[candidate]&lt;br /&gt;
    local disapproval_count = disapproval_counts[candidate]&lt;br /&gt;
    local neutral_count     = #ballots - approval_count - disapproval_count&lt;br /&gt;
    local approved = approval_count &amp;gt; 2*disapproval_count&lt;br /&gt;
    output(padded_number(i, #candidates), &amp;quot;. &amp;quot;, padded_number(approval_count, max_approval), ':', padded_number(disapproval_count, max_disapproval), '(:', padded_number(neutral_count, max_neutral), ') 2/3+ ', approved and &amp;quot;APPROVED&amp;quot; or &amp;quot;FAILED  &amp;quot;, ' ', candidates[i], &amp;quot;\n&amp;quot;)&lt;br /&gt;
    if approved then&lt;br /&gt;
      approved_candidates[#approved_candidates+1] = candidate&lt;br /&gt;
      approved_candidates[candidate] = #approved_candidates&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
  output(&amp;quot;\n&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----------------------------------------------------------------&lt;br /&gt;
-- Calculate battles and rankings according to Schulze method --&lt;br /&gt;
----------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
battles = {}  -- two dimensional array&lt;br /&gt;
max_pro_contra = 0&lt;br /&gt;
for i = 1, #approved_candidates do&lt;br /&gt;
  battles[i] = {}&lt;br /&gt;
end&lt;br /&gt;
ranking = {}  -- mapping candidate name to ranking number and ranking number to list of candidates&lt;br /&gt;
&lt;br /&gt;
function beating_weight(pro, contra)&lt;br /&gt;
  if pro &amp;gt; contra then&lt;br /&gt;
    return pro&lt;br /&gt;
  else&lt;br /&gt;
    return 0&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
do&lt;br /&gt;
  local matrix = {}&lt;br /&gt;
  for i = 1, #approved_candidates do&lt;br /&gt;
    matrix[i] = {}&lt;br /&gt;
  end&lt;br /&gt;
  for i = 1, #approved_candidates do&lt;br /&gt;
    for j = i+1, #approved_candidates do&lt;br /&gt;
      local pro, contra = 0, 0&lt;br /&gt;
      for k = 1, #ballots do&lt;br /&gt;
        local ballot = ballots[k]&lt;br /&gt;
        local rank1 = ballot[approved_candidates[i]]&lt;br /&gt;
        local rank2 = ballot[approved_candidates[j]]&lt;br /&gt;
        if rank1 &amp;gt; rank2 then&lt;br /&gt;
          pro = pro + 1&lt;br /&gt;
        elseif rank2 &amp;gt; rank1 then&lt;br /&gt;
          contra = contra + 1&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      battles[i][j] = pro&lt;br /&gt;
      battles[j][i] = contra&lt;br /&gt;
      max_pro_contra = math.max(max_pro_contra, pro)&lt;br /&gt;
      matrix[i][j] = beating_weight(pro, contra)&lt;br /&gt;
      matrix[j][i] = beating_weight(contra, pro)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
  for i = 1, #approved_candidates do&lt;br /&gt;
    for j = 1, #approved_candidates do&lt;br /&gt;
      if i ~= j then&lt;br /&gt;
        for k = 1, #approved_candidates do&lt;br /&gt;
          if i ~= k and j ~= k then&lt;br /&gt;
            matrix[j][k] = math.max(matrix[j][k], math.min(matrix[j][i], matrix[i][k]))&lt;br /&gt;
          end&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
  local count = 0&lt;br /&gt;
  repeat&lt;br /&gt;
    local winners = {}&lt;br /&gt;
    for i = 1, #approved_candidates do&lt;br /&gt;
      local candidate = approved_candidates[i]&lt;br /&gt;
      if ranking[candidate] == nil then&lt;br /&gt;
        local best = true&lt;br /&gt;
        for j = 1, #approved_candidates do&lt;br /&gt;
          if i ~= j then&lt;br /&gt;
            local other_candidate = approved_candidates[j]&lt;br /&gt;
            if ranking[other_candidate] == nil and matrix[j][i] &amp;gt; matrix[i][j] then&lt;br /&gt;
              best = false&lt;br /&gt;
              break&lt;br /&gt;
            end&lt;br /&gt;
          end&lt;br /&gt;
        end&lt;br /&gt;
        if best then&lt;br /&gt;
          winners[#winners+1] = candidate&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
    end&lt;br /&gt;
    ranking[#ranking+1] = winners&lt;br /&gt;
    for i = 1, #winners do&lt;br /&gt;
      ranking[winners[i]] = #ranking&lt;br /&gt;
      count = count + 1&lt;br /&gt;
    end&lt;br /&gt;
  until count == #approved_candidates&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--------------------&lt;br /&gt;
-- Output ranking --&lt;br /&gt;
--------------------&lt;br /&gt;
&lt;br /&gt;
if #approved_candidates &amp;gt; 0 then&lt;br /&gt;
  output(&amp;quot;Ranking:\n&amp;quot;)&lt;br /&gt;
  for rank = 1, #ranking do&lt;br /&gt;
    local list = ranking[rank]&lt;br /&gt;
    for i = 1, #list do&lt;br /&gt;
      local candidate = list[i]&lt;br /&gt;
      output(padded_number(rank, #ranking), &amp;quot;. &amp;quot;, candidate, &amp;quot;\n&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
  output(&amp;quot;\n&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
---------------------------&lt;br /&gt;
-- Output battle results --&lt;br /&gt;
---------------------------&lt;br /&gt;
&lt;br /&gt;
if #approved_candidates &amp;gt; 1 then&lt;br /&gt;
  for rank = 1, #ranking do&lt;br /&gt;
    local list = ranking[rank]&lt;br /&gt;
    for i = 1, #list do&lt;br /&gt;
      local candidate = list[i]&lt;br /&gt;
      output(&amp;quot;Direct comparison of: &amp;quot;, padded_number(rank, #ranking), &amp;quot;. &amp;quot;, candidate, &amp;quot;\n&amp;quot;)&lt;br /&gt;
      for other_rank = 1, #ranking do&lt;br /&gt;
        local other_list = ranking[other_rank]&lt;br /&gt;
        for j = 1, #other_list do&lt;br /&gt;
          local other_candidate = other_list[j]&lt;br /&gt;
          if candidate ~= other_candidate then&lt;br /&gt;
            local pro    = battles[approved_candidates[candidate]][approved_candidates[other_candidate]]&lt;br /&gt;
            local contra = battles[approved_candidates[other_candidate]][approved_candidates[candidate]]&lt;br /&gt;
            output(padded_number(pro, max_pro_contra), &amp;quot;:&amp;quot;, padded_number(contra, max_pro_contra), &amp;quot;  &amp;quot;, padded_number(other_rank, #ranking), &amp;quot;. &amp;quot;, other_candidate, &amp;quot;\n&amp;quot;)&lt;br /&gt;
          end&lt;br /&gt;
        end&lt;br /&gt;
      end&lt;br /&gt;
      output(&amp;quot;\n&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>imported&gt;RhoTP</name></author>
	</entry>
</feed>