schulze-vote 2.0.6 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +7 -1
- data/lib/vote/condorcet/schulze/basic.rb +50 -9
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 53d7c71ae5e43fcd9a28bf01eaf4e7f16819f5b0
|
4
|
+
data.tar.gz: 989df507edb37c37e043891c28224b643572b0ea
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1082070bf51ba9aa979670a21240bc0a42efad17ee2eb385284ed2e5386f850dd537d4f837a04cdf766238cd70e691665615f478366d4735e357fa389da89c30
|
7
|
+
data.tar.gz: c2b409116e6066aebc43250aae94081681d70d700e65738dc246beeacca6c313628d2c19570ed040276a7802ec5a9a50c46ce7df0604cda8bf4adae49a26924a
|
data/README.md
CHANGED
@@ -27,7 +27,6 @@ gem 'schulze-vote', require: 'schulze_vote'
|
|
27
27
|
require 'schulze_vote'
|
28
28
|
vs = SchulzeBasic.do vote_list, candidate_count
|
29
29
|
vs.ranks
|
30
|
-
vs.ranks_abc
|
31
30
|
```
|
32
31
|
|
33
32
|
`SchulzeBasic.do` - SchulzeBasic is a short term for `Vote::Condorcet::Schulze::Basic` and `.do` is a method of this class!
|
@@ -205,6 +204,13 @@ If the number of results is greater then the `limit_results` parameter then a `T
|
|
205
204
|
is raised.
|
206
205
|
If you set this parameter to any value other then `false` be careful to catch and manage the exception properly.
|
207
206
|
|
207
|
+
## Classification with ties
|
208
|
+
|
209
|
+
You have a `classification_with_ties` that you can call.
|
210
|
+
This method return a uniq classification in array of arrays format to display results on screen.
|
211
|
+
Please note that for cases like this: https://en.wikipedia.org/wiki/User:MarkusSchulze/Schulze_method_examples#Example_4
|
212
|
+
it will return the following: [[B,D], [A,C]]
|
213
|
+
|
208
214
|
## Contributing to schulze-vote
|
209
215
|
|
210
216
|
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
@@ -21,6 +21,7 @@ module Vote
|
|
21
21
|
end
|
22
22
|
@vote_matrix = input.matrix
|
23
23
|
@candidate_count = input.candidates
|
24
|
+
@candidates = (0..@candidate_count - 1).to_a
|
24
25
|
@vote_count = input.voters
|
25
26
|
self
|
26
27
|
end
|
@@ -30,6 +31,7 @@ module Vote
|
|
30
31
|
result
|
31
32
|
calculate_winners
|
32
33
|
rank
|
34
|
+
calculate_beat_couples
|
33
35
|
end
|
34
36
|
|
35
37
|
attr_reader :vote_matrix
|
@@ -50,7 +52,7 @@ module Vote
|
|
50
52
|
attr_reader :winners_array
|
51
53
|
|
52
54
|
# compute all possible solutions
|
53
|
-
# since this can take days, there is an option to limit the
|
55
|
+
# since this can take days, there is an option to limit the number of calculated classifications
|
54
56
|
# the default is 10. if the system is calculating more then 10 possible classifications it will stop
|
55
57
|
# raising a TooManyClassifications exception
|
56
58
|
# you can set it to false to disable the limit
|
@@ -58,8 +60,29 @@ module Vote
|
|
58
60
|
@classifications ||= calculate_classifications(limit_results)
|
59
61
|
end
|
60
62
|
|
61
|
-
|
62
|
-
|
63
|
+
attr_reader :beat_couples
|
64
|
+
|
65
|
+
attr_reader :ties
|
66
|
+
|
67
|
+
# compute the final classification with ties included
|
68
|
+
# the result is an array of arrays. each position can contain one or more elements in tie
|
69
|
+
# e.g. [[0,1], [2,3], [4], [5]]
|
70
|
+
def classification_with_ties
|
71
|
+
calculate_potential_winners
|
72
|
+
result = []
|
73
|
+
result << @potential_winners # add potential winners on first place
|
74
|
+
result += @ties.clone.sort_by { |tie| -@ranking[tie[0]] } # add all the ties ordered by ranking
|
75
|
+
result.uniq! # remove duplicates (potential winners are also ties)
|
76
|
+
excludeds = (@candidates - result.flatten) # all remaining elements (not in a tie and not winners)
|
77
|
+
excludeds.each do |excluded|
|
78
|
+
result.each_with_index do |position, index|
|
79
|
+
# insert before another element if they have a better ranking
|
80
|
+
break result.insert(index, [excluded]) if has_better_ranking?(excluded, position[0])
|
81
|
+
# insert at the end if it's the last possible position
|
82
|
+
break result.insert(-1, [excluded]) if index == result.size - 1
|
83
|
+
end
|
84
|
+
end
|
85
|
+
result
|
63
86
|
end
|
64
87
|
|
65
88
|
private
|
@@ -126,17 +149,35 @@ module Vote
|
|
126
149
|
@potential_winners
|
127
150
|
end
|
128
151
|
|
152
|
+
# calculates @beat_couples and @ties in roder to display results afterward
|
129
153
|
def calculate_beat_couples
|
130
|
-
|
154
|
+
return if @calculated_beat_couples
|
155
|
+
@beat_couples = []
|
156
|
+
@ties = []
|
131
157
|
ranks.each_with_index do |_val, idx|
|
132
158
|
ranks.each_with_index do |_val2, idx2|
|
133
159
|
next if idx == idx2
|
134
|
-
if play_matrix[idx, idx2] > play_matrix[idx2, idx]
|
135
|
-
|
136
|
-
|
160
|
+
next @beat_couples << [idx, idx2] if play_matrix[idx, idx2] > play_matrix[idx2, idx]
|
161
|
+
next unless in_tie?(idx, idx2)
|
162
|
+
next if @ties.any? { |tie| ([idx, idx2] - tie).empty? }
|
163
|
+
tie = @ties.find { |tie| tie.any? { |el| el == idx } }
|
164
|
+
next tie << idx2 if tie
|
165
|
+
tie = @ties.find { |tie| tie.any? { |el| el == idx2 } }
|
166
|
+
next tie << idx if tie
|
167
|
+
@ties << [idx, idx2]
|
137
168
|
end
|
138
169
|
end
|
139
|
-
|
170
|
+
@calculated_beat_couples = true
|
171
|
+
end
|
172
|
+
|
173
|
+
def in_tie?(idx, idx2)
|
174
|
+
play_matrix[idx, idx2] == play_matrix[idx2, idx] &&
|
175
|
+
@ranking[idx] == @ranking[idx2] &&
|
176
|
+
@winners_array[idx] == @winners_array[idx2]
|
177
|
+
end
|
178
|
+
|
179
|
+
def has_better_ranking?(a, b)
|
180
|
+
@ranking[a] > @ranking[b]
|
140
181
|
end
|
141
182
|
|
142
183
|
def rank_element(el)
|
@@ -180,7 +221,7 @@ module Vote
|
|
180
221
|
end
|
181
222
|
|
182
223
|
def check_limits(classifications, limit_results)
|
183
|
-
|
224
|
+
fail TooManyClassificationsException if limit_results && classifications.size > limit_results
|
184
225
|
end
|
185
226
|
|
186
227
|
def add_element(classifications, classif, _potential_winners, beated_list, start_list, element, limit_results)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: schulze-vote
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0
|
4
|
+
version: 2.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alessandro Rodi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-10-17 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: This gem is a Ruby implementation of the Schulze voting method (with
|
14
14
|
help of the Floyd-Warshall algorithm), a type of the Condorcet voting methods.
|