Ballot Types in Simulation
-
Up to now, I have been thinking for my simulator that each voting system could offer, at least potentially, a choice of voting decision procedures. But it has just come to me that these don't properly belong to the voting systems. They belong to the ballot types, e. g. rating ballots, strict-ranking ballots, ranking ballots permitting equal ranking, vote for and against ballots, vote for or against ballots, vote-for-one ballots or vote-against-one ballots.
-
I hope you look at the Codepen where I parse and stringify a bunch of different ballot types: https://codepen.io/karmatics/pen/poLPpzW
It's a bit tricky because it does its best to infer ballot type and put them all into a reasonable object structure, also allowing you do condense them (if the line starts with "134:" that means 134 ballots identical to this one) as well as expand them back.
I try to use formats that also work on forums, so they are very human readable.
So:
134: a[5] b[4] c[2] d[1] e[0] f[0]
64: a[5] b[4] c[3] d[1] e[0] f[0]
94: a[3] b[5] c[4] d[1] e[0] f[0]
70: a[2] b[2] c[5] d[2] e[0] f[0]
63: a[0] b[0] c[0] d[3] e[4] f[5]
55: a[0] b[0] c[1] d[3] e[5] f[4]
55: a[0] b[1] c[4] d[3] e[5] f[3]
48: a[0] b[0] c[5] d[3] e[5] f[5]Candidate names don't have to be single letters and can have spaces. If no number at the beginning, it will be interpreted as "1:" Floating point is allowed.
You might also using name mapping, so you could have a long name i.e. "Robert J. Brown" which maps to a short name "rb" for more compact representation.
You can do ranked like this:
5: d>b>e>c
2: d>b
e>f>gAnd equal rankings can be in there as
d>b=c>a
(there should probably be a flag for whether this is allowed, same goes for lots of things, like floating point scores)
And of course approval:
b,c
c
d,eAnyway, not sure the degree you are interested in using code that isn't yours, but all I'm saying is that a lot of work has been done and is free to use.
-
@rob said in Ballot Types in Simulation:
a lot of work has been done
Understood; I appreciate your intent in making sure I am aware of existing work that might apply.
At the moment, external notation is not an immediate concern for me as I am still in the more basic level of implementing semantics and behavior. As I conceive this thing, the ballots go from software to other software, not from humans to software.
-
@jack-waugh said in Ballot Types in Simulation:
At the moment, external notation is not an immediate concern for me
Ok, I mean, usually I like for things to be viewable by humans. But also, this does go beyond external notation because it parses them into a form that is usable by the program. It also makes the distinction you note between ballot types and tabulation methods.
Obviously its up to you to do it how you see best, but since you keep posting here your thoughts as you build things out, presumably so others can weigh in, this is me weighing in: I think having it able to import and export to a human readable, human editable format should typically be a first step on a project like this. If only to do regular sanity checks as you build things out.
Is there something else you are looking for?
-
@rob You are identifying candidates by name rather than index for the tallies. For determining the chances of our collaborating on code, how important is it that I imitate that practice?
I see that the structure you are using when equal ranking is allowed is that
ranks
is an array of arrays and the inner arrays list the candidates. I let your code parse "a=b>c=d" and it came up with{ranks: [["a", "b"], ["c", "d"]]}
. -
@rob Pressing "tabulate" does nothing in Firefox.
-
@rob
class PairwiseResults
defines.tabulate (ballots)
but that is never called. -
@jack-waugh Not sure "name" is the right word for what I identify candidates by, since you can just use a one character string, which in turn maps back to the full name. (in which case "key" might be a better word for it) But it also allows you use a full name. I aimed for flexibility.
I haven't looked at the code for a while, but you could probably use numbers as keys. The problem with that is it might confuse it unless you add a bit of logic to make it smarter.
Regardless I preferred by able to do both this:
a[5] c[4]
and this
Joe Smith[5] Jane Jones[4]
As for arrays when you have equal ranking, how else could you do it? You have to be able to have multiple members at each ranking. I'm not sure the best solution, but that is what I came up with. I don't think I did much if anything in terms of tabulating ranked ballots, mostly I did cardinal ballots.... I'm open to suggestions.
-
@rob said in Ballot Types in Simulation:
how else could you do it
I don't know that there is any other reasonable way to do it. I hadn't worked out a way, and I was just remarking that I understood how you were doing it as a result of my reverse engineering. I can see using the same format with names or IDs or indices.
I erred by not trying to draft in the first place a tally that would take equal ranking. Once such a tally is working, it won't care whether arbitrary and evil restrictions are imposed with respect to the ballots before they are handed to the tally. It is only up to the voting decision procedures to obey such restrictions or not, depending on what purpose they are designed for.
In regard to names, my idea has been that a given tallying algorithm would get called at first without names, since they have no bearing on the tally. The tally would return the set of candidates (by index) who tied for the win and a closure to be called later to report, rendered into DOM elements, the details of how the tally went. The candidate names would be supplied on this second call. But if you say it is your earnest opinion that the names should come along in the first call, I will change the design accordingly. I think there is something to be said for my putting some value on making it smooth for either of us to adapt code written for one context to run in the other. No need to duplicate effort in writing tallying algorithms, I suppose, if we can manage to make them understandable to each other.
-
@jack-waugh Sorry that Codepen doesn't tabulate, I must have been working on it and broken something. This one does, and is just a previous fork:
https://codepen.io/karmatics/pen/gOrLLxP
I did test it with numerical "names" for candidates so this works:
134: 0[5] 1[4] 2[2] 3[1] 4[0] 5[0]
64: 0[5] 1[4] 2[3] 3[1] 4[0] 5[0]
94: 0[3] 1[5] 2[4] 3[1] 4[0] 5[0]
70: 0[2] 1[2] 2[5] 3[2] 4[0] 5[0]
63: 0[0] 1[0] 2[0] 3[3] 4[4] 5[5]
55: 0[0] 1[0] 2[1] 3[3] 4[5] 5[4]
55: 0[0] 1[1] 2[4] 3[3] 4[5] 5[3]
48: 0[0] 1[0] 2[5] 3[3] 4[5] 5[5]
30: 0[1] 1[0] 2[1] 3[3] 4[3] 5[5]
30: 0[0] 1[1] 2[2] 3[5] 4[5] 5[4]
28: 0[2] 1[1] 2[0] 3[3] 4[3] 5[5]
27: 0[0] 1[0] 2[0] 3[3] 4[5] 5[5]
26: 0[0] 1[1] 2[3] 3[3] 4[5] 5[3]
22: 0[1] 1[0] 2[0] 3[3] 4[4] 5[5]
20: 0[1] 1[1] 2[0] 3[3] 4[3] 5[5]They are treated as strings by the tabulation logic, but you don't have to.
Also, notice this codepen, where it does rankings (but I don't know if it handles equal rankings, it probably will parse them but simply use the first member of each subarray, since I was using it on real election data from the infamous Burlington election.
https://codepen.io/karmatics/pen/PoRvYaX
Also notice how it uses single characters for the candidate "names" (to keep the data really small), but those are simply keys into a list (a.k.a. hash table) of full names. Keep in mind that hash lookup is ridiculously fast in Javascript, in case you were doing indexes into an array as an optimization. The latter is probably no faster.
a: Kiss b: Montroll c: Simpson d: Smith e: Wright f: w-i ------------ 840:e 355:a>b 326:a 271:e>d 256:e>b 234:a>b>d 200:b>a 178:b 147:e>b>d 145:b>a>d 139:b>d 125:a>d 124:d
-
-
BTW, you mentioned how equal ranks are done:
a=b>e>c=d
becomes:
{ ranks: [ ["a", "b"], ["e"], ["c", "d"] ] }
Another option might be:
{ ranks: [ "a=b", "e", "c=d" ] }
This simplifies the default case of no equal ranks, but allows a simple operation ( item.split('=') ) to get them into a list if needed.
-
@rob I prefer the current way, where it is completely parsed, to the alternative you mention, which would require further parsing (even so simple as with one
.split("=")
). -
I am posting to indicate that I have not abandoned the simulation project; I am gradually trying to progress it. I don't expect a response unless you think I have left something important out or am painting myself into a corner with the design choices I am laying out.
I asked myself: What are we going to read from the file directories and how will what we read figure in during prompting and execution?
At the indicative level, a voting system declares what form of ballot it requires.
Tactics, at the indicative level, will be able to answer given a ballot form, are they capable of generating ballots conforming thereto.
So, when the user selects a voting system, the app will offer the tactics that can produce ballots for that system.
Since tactics will have an indicative level and an executive level, they must comprise at least two files, so it makes sense to use a directory for each tactic.
So there will be one directory containing the subdirectories for the voting systems and one directory containing the subdirectories for the tactics. There is no need for the hierarchy of directories to reflect any kind of categorization of either. So, for example, there will not be a directory of ranking voting systems nor a directory of rating voting systems nor a directory of Condorcet-compliant voting systems, etc.
Example declarations of ballot types:
{ [0]: 'rating', finite: false, /* Continuous -- allows floating-point ratings. */ min: 0, max: 1, } { [0]: 'rating', finite: true, range: [0, 1, 2, 3, 4, 5], /* like STAR */ } { [0]: 'ranking', equal_ranking_allowed: true, }
Here's Approval:
{ [0]: 'rating', finite: true, range: [0, 1], /* Approval */ }