schulze-vote 2.2.0 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9866e914ebb502be11324a542dfb49de786a7408
4
- data.tar.gz: 6ade5e377c2b4e1f01444fd110e535e54df71ac4
3
+ metadata.gz: 3016d28cfc6bef2976750a075643923e602bd304
4
+ data.tar.gz: 5dcb2b785be020acc0a8761cda566981867e5486
5
5
  SHA512:
6
- metadata.gz: 03f614f995678224821bc5d81fa8e5d86945aa0086f767ad96b35d6d577d2d9742177b2bad6fa23ad4e7fa0560e3f17638cf1113d1738e463d40f912d76a2a5a
7
- data.tar.gz: 5088baad29d4959dee3df8d4aa232be97090dda1111648a9c388f65dc87e07f4ce6aac55b757e674bbd0f745866424d3eedeb7f69fa43a095ecd2764f89631d5
6
+ metadata.gz: edb55c862b09981e06dbe6e46e0b5093c622e22e3ceffa9ab2af0254081de28bc78566f91ab8756caded729ac0bc49fdf3a2aaec647a495e7ba45bb371299200
7
+ data.tar.gz: 7771b158d623a1efbc5ed29705949e7f5a297d7e29b1cbc8d6731a3986d8346e629f3bad7b7efeee54e4682b673b0c22fc56161a1671fca91adc81f27d1e79ac
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License
2
2
 
3
- Copyright (c) 2010-2015 Renuo GmbH. https://www.renuo.ch
3
+ Copyright (c) 2010-2016 Alessandro Rodi.
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -6,6 +6,7 @@ a type of the Condorcet voting methods.
6
6
  ## Master
7
7
 
8
8
  [![Build Status](https://travis-ci.org/coorasse/schulze-vote.svg?branch=master)](https://travis-ci.org/coorasse/schulze-vote)
9
+ [![Gem Version](https://badge.fury.io/rb/schulze-vote.svg)](https://badge.fury.io/rb/schulze-vote)
9
10
 
10
11
  ## Develop
11
12
 
@@ -13,11 +14,6 @@ a type of the Condorcet voting methods.
13
14
  [![Code Climate](https://codeclimate.com/github/coorasse/schulze-vote/badges/gpa.svg)](https://codeclimate.com/github/coorasse/schulze-vote)
14
15
  [![Test Coverage](https://codeclimate.com/github/coorasse/schulze-vote/badges/coverage.svg)](https://codeclimate.com/github/coorasse/schulze-vote/coverage)
15
16
 
16
- Wikipedia:
17
-
18
- * [Schulze method](http://en.wikipedia.org/wiki/Schulze_method) ([deutsch](http://de.wikipedia.org/wiki/Schulze-Methode))
19
- * [Floyd–Warshall algorithm](http://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm)
20
-
21
17
  ## Install
22
18
 
23
19
  ``` bash
@@ -34,21 +30,27 @@ gem 'schulze-vote', require: 'schulze_vote'
34
30
 
35
31
  ``` ruby
36
32
  require 'schulze_vote'
37
- vs = SchulzeBasic.do vote_list, candidate_count
38
- vs.ranks
33
+ vote_list = <<EOF
34
+ C;A;B
35
+ C;B;A
36
+ A;B;C
37
+ A;C;B
38
+ B;C;A
39
+ B;A;C
40
+ EOF
41
+ schulze_basic = SchulzeBasic.do(vote_list, candidate_count)
42
+ schulze_classifications.classification_with_ties # shows the final classification
39
43
  ```
40
44
 
41
- `SchulzeBasic.do` - SchulzeBasic is a short term for `Vote::Condorcet::Schulze::Basic` and `.do` is a method of this class!
42
-
43
45
  Input:
44
46
 
45
47
  * `vote_list`
46
- * Array of Arrays: votes of each voter as weights `[ [A,B,C,...],[A,B,C,...],[A,B,C,...] ]`
47
- * String: "A;B;C\nA;B;C\n;3=A;B;C..."
48
+ * Array of Arrays: votes of each voter as weights `[ [1,2,3],[3,2,1],[1,1,2] ]`
49
+ * String: "A;B;C\nB,A;C\n;3=C;B;A"
48
50
  * File: first line **must** be a single integer, following lines like vote_list type String (see vote lists under `examples` directory)
49
- * `candidate_count` Integer: number of candidates
51
+ * `candidate_count` Integer: number of options
50
52
  * **required** for vote_list types of Array and String
51
- * _leave empty if vote_list is a File handle!_
53
+ * leave empty if vote_list is a File
52
54
 
53
55
  ### String/File format:
54
56
 
@@ -84,14 +86,11 @@ Very easy: The reason is, that voters can leave out candidates (they give no spe
84
86
 
85
87
  So, schulze-vote needs to know, how many real candidates are in the voting process.
86
88
 
87
- Okay, for Array inputs it's currently a little bit overhead, because the voters array normally should have the size of the candidates count.
88
- See it as an visual reminder while coding with this gem.
89
-
90
89
  ### Examples
91
90
 
92
91
  #### Array
93
92
 
94
- (Only weight values, no letters here! See section "_preference order to weight_ example")
93
+ Only weight values, no letters here
95
94
 
96
95
  ``` ruby
97
96
  require 'schulze_vote'
@@ -99,6 +98,20 @@ vote_list_array = [[3,2,1],[1,3,2],[3,1,2]]
99
98
  vs = SchulzeBasic.do vote_list_array, 3
100
99
  ```
101
100
 
101
+ ```
102
+ voter => A D C B
103
+
104
+ weight => 4,1,2,3
105
+
106
+ A is on first position = highest prio == 4
107
+ B is on last position == 1
108
+ C is on third position == 2
109
+ D is on second position == 3
110
+ ```
111
+
112
+ Next versions will have an automatic Preference-to-Weight algorithm.
113
+ (Internally only integers are used for calculation of ranking.)
114
+
102
115
  #### String
103
116
 
104
117
  ``` ruby
@@ -120,23 +133,8 @@ require 'schulze_vote'
120
133
  vs = SchulzeBasic.do File.open('path/to/vote.list')
121
134
  ```
122
135
 
123
- ### _preference order to weight_ example
124
-
125
- ```
126
- voter => A D C B
127
-
128
- weight => 4,1,2,3
129
-
130
- A is on first position = highest prio == 4
131
- B is on last position == 1
132
- C is on third position == 2
133
- D is on second position == 3
134
- ```
135
-
136
- Later versions will have an automatic Preference-to-Weight algorithm.
137
- (Internally only integers are used for calculation of ranking.)
138
136
 
139
- ### _SchulzeBasic_
137
+ ### SchulzeBasic
140
138
 
141
139
  It doesn't matter if you start counting at 0 (zero) or 1 (one).
142
140
 
@@ -146,8 +144,16 @@ Internally it will only check if candidate X > candidate Y
146
144
 
147
145
  Output:
148
146
 
149
- * `.ranks` Array: numbers of total wins for each candidate `[candidate A, candidate B, candidate C, ...]`
147
+ * `.ranking` Array: numbers of total wins for each candidate `[candidate A, candidate B, candidate C, ...]`
150
148
  * `.winners_array` Array: set 1 if the candidate is a potential winner `[candidate A, candidate B, candidate C, ...]`
149
+ * `.vote_matrix` Matrix: it contains the pairwise defeats
150
+ * `.play_matrix` Matrix: it contains the strongest paths
151
+ * `.result_matrix` Matrix: it contains the beat pairwise
152
+ * `.beat_couples` Array of Pairs: it contains the beat pairwise in array format
153
+ * `.ties` Array of Array: it contains the ties between candidates
154
+ * `.potential_winners` Array: it contains the possible winners
155
+
156
+
151
157
 
152
158
  ## Example
153
159
 
@@ -168,7 +174,7 @@ votestring = <<EOF
168
174
  7=D;C;E;B;A
169
175
  8=E;B;A;D;C
170
176
  EOF
171
- vs = SchulzeBasic.do votestring, 5
177
+ vs = SchulzeBasic.do(votestring, 5)
172
178
  puts_m vs.vote_matrix
173
179
 
174
180
  #=> [0, 20, 26, 30, 22]
@@ -204,18 +210,17 @@ end
204
210
  #=> ["E", "A", "C", "B", "D"]
205
211
  ```
206
212
 
207
- which is the same result of the reference above.
208
213
 
209
214
  ## Classifications
210
215
 
211
- You have a `classifications(limit_results = false)` that you can call.
216
+ You have a `SchulzeClassifications.new(vs).classifications(limit_results = false)` that you can call.
212
217
  If the number of results is greater then the `limit_results` parameter then a `TooManyClassificationsException`
213
218
  is raised.
214
219
  If you set this parameter to any value other then `false` be careful to catch and manage the exception properly.
215
220
 
216
221
  ## Classification with ties
217
222
 
218
- You have a `classification_with_ties` that you can call.
223
+ You have a `SchulzeClassifications.new(vs).classification_with_ties` that you can call.
219
224
  This method return a uniq classification in array of arrays format to display results on screen.
220
225
  Please note that for cases like this: https://en.wikipedia.org/wiki/User:MarkusSchulze/Schulze_method_examples#Example_4
221
226
  it will return the following: [[B,D], [A,C]]
@@ -233,12 +238,18 @@ it will return the following: [[B,D], [A,C]]
233
238
 
234
239
  ## Problems? Questions?
235
240
 
236
- ![Alessandro Rodi](http://www.gravatar.com/avatar/32d80da41830a6e6c1bb3eb977537e3e)
241
+ [![Alessandro Rodi](http://www.gravatar.com/avatar/32d80da41830a6e6c1bb3eb977537e3e)](https://github.com/coorasse)
237
242
 
238
243
  ## Thanks
239
244
 
240
245
  Thanks to Christoph Grabo for providing the idea and base code of the gem
241
246
 
247
+ ## Wikipedia:
248
+
249
+ * [Schulze method](http://en.wikipedia.org/wiki/Schulze_method) ([deutsch](http://de.wikipedia.org/wiki/Schulze-Methode))
250
+ * [Schulze method examples](https://en.wikipedia.org/wiki/User:MarkusSchulze/Schulze_method_examples)
251
+ * [Floyd-Warshall algorithm](http://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm)
252
+
242
253
  ## Copyright
243
254
 
244
255
  See LICENSE for further details.
@@ -29,6 +29,8 @@ module Vote
29
29
  add_excludeds(result)
30
30
  end
31
31
 
32
+ private
33
+
32
34
  def add_excludeds(result)
33
35
  excludeds = (@schulze_basic.candidates - result.flatten) # all remaining elements (not in tie, not winners)
34
36
  excludeds.each do |excluded|
@@ -42,8 +44,6 @@ module Vote
42
44
  result
43
45
  end
44
46
 
45
- private
46
-
47
47
  def better_ranking?(a, b)
48
48
  @schulze_basic.ranking[a] > @schulze_basic.ranking[b]
49
49
  end
@@ -5,10 +5,9 @@ module Vote
5
5
  def initialize(vote_list, candidate_count = nil)
6
6
  @vote_list = vote_list
7
7
  @candidate_count = candidate_count
8
-
8
+ @candidates_abc = []
9
9
  if @candidate_count.nil?
10
10
  insert_vote_file(@vote_list) if vote_list.is_a?(File)
11
-
12
11
  else
13
12
  @vote_matrix = ::Matrix.scalar(@candidate_count, 0).extend(Vote::Matrix)
14
13
  insert_vote_array(@vote_list) if vote_list.is_a?(Array)
@@ -32,27 +31,30 @@ module Vote
32
31
  vs.split(/\n|\n\r|\r/).each do |voter|
33
32
  voter = voter.split(/=/)
34
33
  vcount = (voter.size == 1) ? 1 : voter[0].to_i
35
-
36
34
  vcount.times do
37
35
  tmp = voter.last.split(/;/)
38
36
  vote_array << extract_vote_string(tmp)
39
37
  end
40
38
  end
41
-
42
39
  insert_vote_array vote_array
43
40
  end
44
41
 
45
- def extract_vote_string(tmp) # array of preferences [['1, 2'], ['3']. ['4, 5']]
42
+ def extract_vote_string(tmp) # array of preferences [['1, 2'], ['3']. ['4, 5']]
43
+ tmp2 = flatten_votes(order_and_remap(tmp))
44
+ tmp2.map! { |e| [e[0].to_i, e[1]] } if all_numbers?(tmp2)
45
+ tmp2.sort.map { |e| e[1] } # order, strip & add
46
+ end
47
+
48
+ def flatten_votes(votes)
46
49
  tmp2 = []
47
- order_and_remap(tmp).
48
- map do |e| # find equal-weighted candidates
49
- if e[0].size > 1
50
- e[0].split(/,/).each { |f| tmp2 << [f, e[1]] }
51
- else
52
- tmp2 << e
53
- end
50
+ votes.map do |e| # find equal-weighted candidates
51
+ (e[0].size > 1) ? e[0].split(/,/).each { |f| tmp2 << [f, e[1]] } : tmp2 << e
54
52
  end
55
- tmp2.sort.map { |e| e[1] } # order, strip & add
53
+ tmp2
54
+ end
55
+
56
+ def all_numbers?(array)
57
+ array.map { |e| e[0] }.all? { |el| /\A\d+\z/.match(el) }
56
58
  end
57
59
 
58
60
  def order_and_remap(tmp)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: schulze-vote
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.0
4
+ version: 2.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alessandro Rodi