Collaborative Coding for Simulation
-
If you are looking for voting strategies and you aren't already familiar with it, you might want to look at Warren D. Smith's 2000 Range Voting paper. In it he proposes Range Voting (now more commonly referred to as Score) and compares it to about 30 other voting methods (really 14 other methods with naïve and strategic variations), The last I checked the paper can be found at Range Voting. The (c) code is also available at votetest2.c.
According to the (many) voting papers I've read over the past several years, there is a major decision that needs to be made when representing the electorate. In my opinion, the worst option is to use tournaments, which essentially ignore voters and even elections, and are about choosing a winner among a fixed set of alternatives based on a graph in which an arrow points from node A to node B if A would defeat B in a one-on-one simple majority election. The graph is just a given, and the challenge is to figure out a way to pick the winner. These papers have tended to focus on the computational difficulty of making this choice when the graph is large. The second way of representing the electorate is preference profiles, which is just a ranking of the fixed set of alternatives combined with a mulitplicity for each raking indicating how many voters would order the alternative that way. My problem with this method is that it doesn't provide any data for approval voting or score voting, or indeed any cardinal voting method.
My preferred method (which generally requires computer simulation for any realistically sized electorate) is to represent voters as points in an issue space (usually 2D or higher), and use a distance function between the voters and the alternatives (also points in the issue space) to generate ordinal or cardinal ballots.
One of the projects I'm considering is to start with something like Nicky Case's To Build A Better Ballot, and use interactive JavaScript to illustrate many of the problems with various voting systems. This is also similar to what @rob did in the underlying electorate model in his voting strategy simulation. (I do have an ulterior motive here. If the simulations start with the voters and distance functions to the alternatives, it becomes a lot easier to show exactly how an iterative voting system like SAVE would work, and how it would be significantly better than any non-iterative system. That argument is a lot easier with pictures.)
-
@tec said in Collaborative Coding for Simulation:
My preferred method (which generally requires computer simulation for any realistically sized electorate) is to represent voters as points in an issue space (usually 2D or higher), and use a distance function between the voters and the alternatives (also points in the issue space) to generate ordinal or cardinal ballots.
......
This is also similar to what @rob did in the underlying electorate model in his voting strategy simulationYes that is exactly what I do. The thing I do that isn't realistic at all, though, is that I simply spread the voters around with a random distribution, rather than having any clustering at all. That said, most of the clustering in US politics today is, in my opinion, caused by the voting system itself. Duverger's law and such. So I erred in the opposite direction, and assumed that it was spread evenly among the electorate. The orange/gray/blue dots below represent voters in "issue space" (or "ideological space"). The crosshair simply indicates the median value of X and Y.
I use 2 dimensions rather than more because it is easier to show on screen, as well as just being the right level of complexity to illustrate concepts to people (which I prioritized a bit higher than making it fully realistic). Both candidates and voters have an X and a Y value. When talking about it, I usually consider X to mean "left vs. right", both in a geometrical sense but also political. (so I can talk about "voters on the left" indicating liberals/democrats, at least in the US politics sense)
In addition to X and Y values, voters have another property which is "how strategic they are." This is shown in the color: orange is fully strategic, blue is fully sincere. I use this in a simplified, but not totally unrealistic way: those that are the most strategic vote as if they know for sure who the two front runners are, those who are most sincere vote as if they consider every single candidate equally likely to be elected. Those in the middle will vote as if some in-between number of candidates (say, 4) will be front-runners.
Meanwhile, candidates (large colored dots with a letter on them) have a property beyond their X Y position in issue space, and that is what I call "universal appeal." This can include things like their appearance, their speaking skills and debating skills, their intelligence, and so on. Basically, those things that are deemed good regardless of what a voter's position on issues are. So candidate B above has higher universal appeal than others, while candidate E has lower universal appeal. This is shown by size. (note that the video I shared earlier did not have this as I hadn't implemented it yet)
Notice that I have also added one more thing to the simulation, which is the "Raw" scoring in the output. (at right)
This is not calculated based on any vote, but just by determining the average "voter satisfaction" at their being elected. I consider this to be an indication of what is the best winner actually is. This only works because the app has the ability to essentially read the voter's minds --- for the actual voting methods, the app can only look at their ballots.It is expected that the raw scoring "method" will tend to give the candidate nearest the median (i.e. the crosshair) the highest score. More or less. And this assumes that all have the same universal appeal.
I haven't yet tried to do Condorcet methods, STAR or IRV, since strategy is so much more complicated for them.
(the app in its current form -- i.e. unfinished -- is at https://pianop.ly/voteSim/voteSim.html . To use it, first click "make voters", then click around to place candidates, then click "vote". You can delete candidates by clicking on them, you can adjust their universal appeal by mousing over them and using up and down arrow keys, or by using the "default UA" slider prior to placing them)
-
Codesandbox
If you have a github repo, you can automatically deploy to CodeSandbox.io to give a sandbox for your creations.
Here's an example I'm working on: https://codesandbox.io/s/github/paretoman/votekit
Embeds
Also, we might be able to embed examples here: https://codesandbox.io/docs/embedding
But that is something that would have to be specifically set up somehow on NodeBB, and I don't really know about that. For now, a link is good.
-
@rob, does this code represent voter affinities toward candidates?
-
@jack-waugh said in Collaborative Coding for Simulation:
@rob, does this code represent voter affinities toward candidates?
Are you speaking of Paretoman's code? I don't know what it represents, I ran it quickly but in the absence of a good explanation I don't know what it is supposed to be showing.
Personally I'd recommend a video demo if he cares to do one. OBS and YouTube are your friends.
-
@paretoman said in Collaborative Coding for Simulation:
Maybe _codesandbox_ is part of a good solution, but, to date, I haven't taken time to look into it, because I am already using [0] a hosting solution that provides full flexibility.
-
If anybody would feel inclined to make their tabulation API 'black boxed' so you can just hand me a .csv file and I will hand you a list of winners, I would be happy to implement a great number of voting methods, including some of the most complicated like Stable Voting or Meek-STV.
I do want to contribute, but I'm just much more comfortable iterating on local scripts in Julia or Python than I am with JS. Does JS have the ability to invoke command line scripts?
-
@andy-dienes JS can be run on the command line via node.js, which is quick to download and install and generally "just works". Of course it also allows you to run web servers and the like, but you can also just say "node myprogram.js" to run things from the command line on mac, windows and any flavor of linux.
I prefer things like Codepen, though, because it is so easily sharable. You can just point people to the Codepen url, and they can paste whatever data in they want. They can also fork it if they want to edit the code. I did a bunch of work to parse ballot formats that are easy to use in forums. (comma separated aren't terrible, but that seems a bit more optimized for the machine rather than for human eyes, and I prefer optimizing for humans)
See https://codepen.io/karmatics/pen/ExKZVjM for example. You can paste in data or use the default. (just click "tabulate" in the bottom right)
But yeah if you prefer work at the command line, but do it in javascript, I'd be glad to convert them to Codepens (or set up a simple template so you can do it yourself), so you can just refer people to a url rather than having them send you csv files, which doesn't lend itself to experimentation and such.
-
@rob Oops, let me clarify. Does JS have the ability to easily call other scripts from command line? Something like Python's subprocess.call()
-
@andy-dienes I went back and thought about what you asked, I think the answer is "yes":
https://nodejs.org/api/child_process.html
However I first thought you were asking how to include one JS file in another, or spawn a thread, or whatever... I'll just leave what I wrote about all that.....
Here I'm using modules.exports and require in the normal way to include one js file in another (and call a function in the included module from the original file):
main.js
console.log("hello there"); var otherModule = require("./included.js"); otherModule.sayHi();
included.js
module.exports = { sayHi: () => { console.log("hi!"); } };
then run it:
> node main
hello there
hi!I'm not sure what you're trying to do.... spawn a thread? Javascript is single-threaded typically but uses callbacks (and the more modern async and promise stuff) when you want to start something that runs separately. I mostly do that for animations or various UI stuff, but that tends to be overkill for just, say, running a calculation that runs in a few milliseconds.
There is also WebWorkers which are essentially background threads. (yes they work in non-browser environments like node.js) I've never had the need for them.
BTW, if you are interested in checking out Codepen, I made a super simple starter app that allows you to do really basic stuff that might be relevant to us (such as process text input and produce text output), with a easy to use UI. Anyone should be able to follow it.
-
@rob said in Collaborative Coding for Simulation:
I'm not sure what you're trying to do.... spawn a thread?
I'm wondering if there is some way to run
js.run_shell_command("julia my_awesome_and_hard_to_implement_voting_method.jl --election=ballot_data.csv --seats=3 --output=winners.csv")
Some of these algorithms are quite pleasant to implement given tools & libraries present in Julia / Python, but I wouldn't even know where to look for the same in JS. Maybe just for mental context, pretend I'm talking about implementing Schulze-STV which involves solving a linear optimization program for every single pair of possible sets of winners.
-
@andy-dienes
Probably exec() is what you want, although spawn() is a bit more powerful I think for long running programs.Here's exec. Most of the bulk below is just showing how to handle all the stderr etc.
const { exec } = require('child_process'); const newProcess = exec('julia my_awesome_and_hard_to_implement_voting_method.jl --election=ballot_data.csv --seats=3 --output=winners.csv', function (error, stdout, stderr) { if (error) { console.log(error.stack); console.log('error code: ' + error.code); console.log('signal: ' + error.signal); } console.log('stdout: ' + stdout); console.log('stderr: ' + stderr); }); newProcess.on('exit', function (code) { console.log('exited with exit code ' + code); });
I don't know what to suggest as far as Schulze-STV, that method makes my brain hurt. But I'd hope you can implement it with just some for loops or basic recursion.... right?
-
@rob said in Collaborative Coding for Simulation:
But I'd hope you can implement it with just some for loops or basic recursion.... right?
Alas, no. It requires solving a linear program (aka an optimization program that looks like this) for every single pair of possible committees, of which there are exponentially many... I have implemented the algorithm using JuMP for which there are a number of convex solvers (e.g. COSMO, Clarabel, or the more canonical CLP), and in Python there is stuff like Pyomo, cvxopt, or even just scipy, but the corresponding JS libraries seem less pleasant to use.
There are other methods too for which some serious complexity is needed like the above. More examples are the strategy-proof randomized Condorcet methods (1) and (2). Also, there are methods which technically can be implemented with simple algorithms, but really benefit from just having the language be natively fast, e.g. Stable Voting or PAV; similarly if some kind of Monte Carlo simulations are desired, one can run a whole lot more of these in a whole lot less time using Julia / Numpy than I imagine one could ever do in JS.
I am not criticizing the choice to use JS and there seems to be a good context to use it here---I'm just trying to give reasons why it might be useful to 'black box' the actual winner selection into separately-executable scripts.
-
@andy-dienes Gotcha. I tend to be a fan of simple methods.
All the methods I've done are very few lines of code and could process millions of ballots in milliseconds.
I always found it odd that, for instance, the equal vote people had never bothered even providing a reference implementation of STAR in JS. (which meant it was a huge ordeal when we tried to do a STAR election in this community with only a dozen candidates and about the same number of voters a couple years ago)
-
@rob said in Collaborative Coding for Simulation:
exec
Of course, this technique would preclude running the election in the front end. It would have to send a request to the server. But that's not a blocking issue. It may still be practical, even if the researcher is rapidly tweaking the problem definition. The Internet is faster than the old phone lines were.
-
@jack-waugh said in Collaborative Coding for Simulation:
But that's not a blocking issue.
I think there are huge advantages to making stuff that runs on the front end, if you want others in the community to be able to run it. Especially if you don't have web hosting. But mostly if you want others to be able to fork your code and play with it or build on top of it, such as to build it into a voting widget, to build a simulator, etc.
But I can see why on really hard methods like Schulze (which I'm convinced was invented as a parody of improved voting methods.... "let's see if we can make something so complicated none of us even understand it" ), it makes some sense to do it in whatever language makes it easier.