Updated webpage & created a git repository

This commit is contained in:
NunoSempere 2021-04-02 17:37:40 +02:00
commit 1d0ed53d47
6 changed files with 1094 additions and 0 deletions

63
CSS/main.css Normal file
View File

@ -0,0 +1,63 @@
<style>
/* Some ideas taken from: https://stackoverflow.com/questions/4309950/how-to-align-input-forms-in-html */
div.form
{
display: block;
text-align: center;
}
form {
display: table;
margin-left: auto;
margin-right: auto;
}
p {
display: table-row;
}
label {
display: table-cell;
font: 1em serif;
}
option {
/* To make sure that all text fields have the same font settings
By default, textareas have a monospace font */
font: 1em serif;
/* Match form field borders */
border: 1px solid #9999;
}
.Box {
/* To make sure that all text fields have the same font settings
By default, textareas have a monospace font */
font: 1em serif;
width: 100px;
border: 1px solid #00011111;
text-align: right;
}
select {
font: 1em serif;
border: 1px solid #0000;
}
.Buttons {
font: 1em serif;
border: 1px solid #0000;
margin: 0 auto;
display: block;
}
</style>

View File

@ -0,0 +1,219 @@
<!DOCTYPE html>
<!--
Sources:
+ https://gist.github.com/cmatskas/8725a6ee4f5f1a8e1ceahttps://gist.github.com/cmatskas/8725a6ee4f5f1a8e1cea
+ cdnjs
-->
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0-alpha1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-csv/0.71/jquery.csv-0.71.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
// The event listener for the file upload
document.getElementById('txtFileUpload').addEventListener('change', upload, false);
document.getElementById('txtFileUpload').addEventListener('click', reset, false);
function reset(){
document.getElementById("txtFileUpload").value = null;
// This way, the event change fires even if you upload the same file twice
}
// Method that checks that the browser supports the HTML5 File API
function browserSupportFileUpload() {
var isCompatible = false;
if (window.File && window.FileReader && window.FileList && window.Blob) {
isCompatible = true;
}
return isCompatible;
}
// Method that reads and processes the selected file
function upload(evt) {
uploadedSameFileTwice = false;
if (!browserSupportFileUpload()) {
alert('The File APIs are not fully supported in this browser!');
} else {
// alert("Checkpoint Charlie");
// var data = null;
data = null;
var file = evt.target.files[0];
var reader = new FileReader();
reader.readAsText(file);
reader.onload = function(event) {
var csvData = event.target.result;
data = $.csv.toArrays(csvData);
if (data && data.length > 0) {
// alert('Imported -' + data.length + '- rows successfully!');
wrapperProportionalApprovalVoting(data);
} else {
alert('No data to import!');
}
};
reader.onerror = function() {
alert('Unable to read ' + file.fileName);
};
}
}
function wrapperProportionalApprovalVoting(data){
let dataColumn1 = data.map(x => x[1]);
// this gets us the first column (columns start at 0).
// data[][1] breaks the thing without throwing an error in the browser.
let dataColumn1Split = dataColumn1.map( element => element.split(", "));
// One row of the first column might be "Candidate1, Candidate2".
// This transforms it to ["Candidate1", "Candidate2"]
let uniqueCandidates = findUnique(dataColumn1Split);
// Finds all the candidates
// In this voting method, all voters start with a weight of 1, which changes as candidates are elected
// So that voters who have had one of their candidates elected have less influence for the next candidates.
let weights = Array(dataColumn1Split.length).fill(1);
// Find the most popular one, given the weights. Update the weights
//alert("\n"+dataColumn1Split[0]);
let n = document.getElementById("numWinners").value;
let winners = [];
for(i=0; i<n; i++){
let newWinner = findTheNextMostPopularOneGivenTheWeights(dataColumn1Split, weights, uniqueCandidates, winners);
winners.push(newWinner);
weights = updateWeightsGivenTheNewWinner(dataColumn1Split, weights, newWinner);
}
//alert(winners);
// Display the winners.
displayWinners(winners);
}
function displayWinners(winners){
// Header
// Ordered list with the winners
///alert(document.getElementsByTagName("OL")[0]);
if(document.getElementsByTagName("OL")[0]==undefined){
headerH3 = document.createElement("h3");
headerH3.innerHTML = "Winners under Proportional Approval Voting:";
document.body.appendChild(headerH3);
orderedList = document.createElement("OL"); // Creates an ordered list
for(let i =0; i<winners.length; i++){
HTMLWinner = document.createElement("li");
HTMLWinner.appendChild(document.createTextNode(winners[i]));
orderedList.appendChild(HTMLWinner);
}
document.body.appendChild(orderedList);
}else{
oldOL = document.getElementsByTagName("OL")[0];
oldOL.remove();
orderedList = document.createElement("OL"); // Creates an ordered list
for(let i =0; i<winners.length; i++){
HTMLWinner = document.createElement("li");
HTMLWinner.appendChild(document.createTextNode(winners[i]));
orderedList.appendChild(HTMLWinner);
}
document.body.appendChild(orderedList);
}
}
function findTheNextMostPopularOneGivenTheWeights(arrayOfArrays, weights, uniqueCandidates, winners){
let popularity = Array(uniqueCandidates.length).fill(0);
for(let i = 0; i<uniqueCandidates.length; i++){
for(let j=1; j<arrayOfArrays.length; j++){
// j = 1 because we don't want to include the title
//alert("array = "+arrayOfArrays[j]);
if(arrayOfArrays[j].includes(uniqueCandidates[i])){
popularity[i]+= 1/weights[j];
}
}
}
for(let i = 0; i<popularity.length; i++){
//alert("popularity["+uniqueCandidates[i]+"] =" +popularity[i]);
}
let maxPopularity = 0;
let winner = undefined;
//alert(popularity + "\n"+uniqueCandidates);
for(let i=0; i<uniqueCandidates.length; i++){
if(popularity[i]>=maxPopularity && !winners.includes(uniqueCandidates[i])){
// Note, this breaks a tie pretty arbitrarily
// Tie breaking mechanism: so obscure as to be random.
winner = uniqueCandidates[i];
//alert("new better:" +uniqueCandidates[i]);
maxPopularity = popularity[i];
}
}
//alert(winner);
return winner;
}
function updateWeightsGivenTheNewWinner(arrayOfArrays, weights, newWinner){
for(let i=0; i<arrayOfArrays.length; i++){
if(arrayOfArrays[i].includes(newWinner)){
weights[i] = weights[i]+1;
}
}
return weights;
}
function findUnique(arrayOfArrays){
let uniqueElements = [];
for(let i = 1; i<arrayOfArrays.length; i++){ // We start with the second row (i=1, instead of i=0, because we take the first row to be a header)
for(let j=0; j<arrayOfArrays[i].length; j++){
if(!uniqueElements.includes(arrayOfArrays[i][j])){
uniqueElements.push(arrayOfArrays[i][j]);
}
}
}
return uniqueElements;
}
});
</script>
</head>
<body>
<h1>Proportional Approval Voting MVP</h1>
<h2>What is this? How does this work?</h2>
<p>This is the simplest version of a program which computes the result of an election, under the <a href="https://www.electionscience.org/learn/electoral-system-glossary/#proportional_approval_voting" target="_blank">Proportional Approval Voting</a> method.</p>
<p>It takes a csv (comma separated value) file, with the same format as <a href="https://docs.google.com/spreadsheets/d/11pBOP6UJ8SSaHIY-s4dYwgBr4PHodh6cIXf-D4yl7HU/edit?usp=sharing" target="_blank">this one</a>, which might be produced by a Google Forms like <a href="https://docs.google.com/forms/d/1_-B5p8ePHnE1jXTGVT_kfRrMRqJuxmm8DPKn-MR1Pok/edit" target="_blank">this one.</a></p>
<p>It computes the result using client-side JavaScript, which means that all operations are run in your browser, as opposed to in a server which is not under your control. In effect, all this webpage does is provide you with a bunch of functions. In fact, you could just load this page, disconnect from the internet, upload your files, and you could still use the webpage to get the results you need.</p>
<div id="dvImportSegments" class="fileupload ">
<fieldset>
<legend>Upload your CSV File to compute the result</legend>
<label>Number of winners: </label><input type="number" id="numWinners" value="2">
<!-- This is not really aesthetic; change. -->
<br>
<input type="file" name="File Upload" id="txtFileUpload" accept=".csv" />
</fieldset>
</div>
<p>Proudly created by <a href="https://nunosempere.github.io">Nu&ntildeo Sempere.</a></p>
</body>
</html>

40
examples.html Normal file
View File

@ -0,0 +1,40 @@
<html>
<head>
<title>Shapley Value Calculator</title>
<meta name="copyright" content="Nuño Sempere López-Hidalgo">
<meta name="keywords" content="Shapley Value, Shapley value, calculate Shapley value, calculate Shapley value online free, Shapley value program">
<meta name="description" content="Shapley value calculator">
<link rel="stylesheet" href="CSS/main.css" type="text/css">
</head>
<body>
<h1> List of examples </h1>
<p><a href="/">Go back</a></p></br>
<p>
<a href="/?example=1">Example 1</a>: Alice and Bob and both necessary to produce something which has value 1500. Alice is player 1, Bob is player 2.
</p></br><p>
<a href="/?example=2">Example 2</a>: Alice and Bob are each individually responsible for two different projects, each of which has value 1000. Alice is player 1, Bob is player 2.
</p></br><p>
<a href="/?example=3">Example 3</a>: Newton and Leibniz invented calculus at the same time. It has a value of 100, in arbitrary units. Assumption: Nobody else could have invented calculus. Newton is player 1, Leibniz is player 2
</p></br><p>
<a href="/?example=4">Example 4</a>: Netwon invented Calculus. Leibniz, mad with envy, pretended that he also invented calculus at the same time. Newton is player 1. Lebniz is player 2.
</p></br><p>
<a href="/?example=5">Example 5</a>: Suppose that AMF will spend $1m on a net distribution. As a result of AMFs commitment, the Gates Foundation contributes $400,000. If AMF had not acted, Gates would have spent the $400,000 on something else, half as valuable. AMF is player 1, Gates is player 2.
</p></br><p>
<a href="/?example=6">Example 6</a>: Suppose again that AMF commits $1m to a net distribution. But if AMF had put nothing in, DFID would instead have committed $500,000 to the net distribution. Now, DFID commits that money to something half as valuable. AMF is player 1, DFID is player 2.
</p></br><p>
<a href="/?example=7">Example 7</a>: 7 people boil a goat in their mother's milk, independently and at the same time. According to the Kabbalah, this has terrible implications: -1000 value is lost. Suppose that all the damage is done once the first deed is done.
</p></br><p>
<a href="/?example=8">Example 8</a>: Suppose that there was a position in an EA org, for which there were 6 qualified applicants which are otherwise 'idle'. In arbitrary units, the person in that position in that organization can produce an impact of 100 utility. The organization is player 1, applicants are players 2-7.
</p></br><p>
<a href="/?example=9">Example 9</a>: A small Indian state with 10 million inhabitants spends $60 million to vaccinate 30% of their population. An NGO which would otherwise be doing something really ineffective, comes in, and by sending reminders, increases the vaccination rate to 35%. They do this very cheaply, for $100,000. The government is player 1, the indian state is player 2. What if, instead, the NGO would have done something equally valuable?
</p></br><p>
<a href="/?example=10">Example 10</a> 1: Same as <a href="../?example=x">Example 9</a>, but now there are 6 government subagencies, each of which we consider as a distinct agent. The NGO is player 1, government agencies are players 2-7.
</p></br><p>
<p><a href="/">Go back</a></p></br>
</body>
</html>

327
index.php Executable file
View File

@ -0,0 +1,327 @@
<?php
/*
* File: /shapleyvalue/calculator
* By: Nuño Sempere
* Date: 23 Sept 2019
* Last modified: 2 Apr 2021
* This file calculates the Shapley value of every member of a given coalition.
*/
## HTML Flavor
echo '<html>';
echo '<head>
<title>Shapley Value Calculator</title>
<meta name="copyright" content="Nuño Sempere López-Hidalgo">
<meta name="keywords" content="Shapley Value, Shapley value, calculate Shapley value, calculate Shapley value online free, Shapley value program">
<meta name="description" content="Shapley value calculator">
<script async defer data-domain="shapleyvalue.com" src="https://plausible.io/js/plausible.js"></script>
<link rel="stylesheet" href="CSS/main.css" type="text/css">';
// script is the reference to plausible.io web tracking
// link rel is the reference to the CSS style sheet.'
echo '</head>';
echo '<body>';
echo '<h1> Shapley Value Calculator </h1>';
## Pointer to this file
$thisFile = "index.php";
## Decide the Number of Players
$numPlayers = $_POST["numplayers"] ?? 3;
// It sees what number of players the user has selected.
// If it's the first time the user comes to the webpage, the default will be 3
## Prints the current example:
$example = $_GET["example"] ?? -1;
echo '<div class="centeredExample">';
echo "<p>";
switch ($example) {
case 1:
echo "Example 1: Alice and Bob and both necessary to produce something which has value 1500. Alice is player 1, Bob is player 2.";
$numPlayers = 2;
$getCoalitionNum = array(0,0,0,1500);
break;
case 2:
echo "Example 2: Alice and Bob are each individually responsible for two different projects, each of which has value 1000. Alice is player 1, Bob is player 2.";
$getCoalitionNum = array(0,1000,1000,2000);
$numPlayers =2;
break;
case 3:
echo "Example 3: Newton and Leibniz invented calculus at the same time. It has a value of 100, in arbitrary units. Assumption: Nobody else could have invented calculus. Newton is player 1, Leibniz is player 2";
$getCoalitionNum = array(0,100,100,100);
$numPlayers =2;
break;
case 4:
echo "Example 4: Netwon invented Calculus. Leibniz, mad with envy, pretended that he also invented calculus at the same time. Newton is player 1. Lebniz is player 2.";
$getCoalitionNum = array(0,100,0,100);
$numPlayers =2;
break;
case 5:
echo "Example 5: Suppose that AMF will spend $1M on a net distribution. As a result of AMFs commitment, the Gates Foundation contributes $400,000. If AMF had not acted, Gates would have spent the $400,000 on something else, half as valuable. AMF is player 1, Gates is player 2.";
$getCoalitionNum = array(0,1000000,200000,1400000);
$numPlayers =2;
break;
case 6:
echo "Example 6: Suppose that AMF commits $1M to a net distribution. But if AMF had put nothing in, DFID would instead have committed $500,000 to the net distribution. Now, DFID commits that money to something half as valuable. AMF is player 1, DFID is player 2.";
$getCoalitionNum = array(0,1000000,500000,1250000);
$numPlayers =2;
break;
case 7:
echo "Example 7: 7 people boil a goat in their mother's milk, independently and at the same time. According to the Kabbalah, this has terrible implications: -1000 value is lost. Suppose that all the damage is done once the first deed is done.";
$numPlayers =7;
$getCoalitionNum = array(0);
for($i = 1; $i<128; $i++){
array_push($getCoalitionNum, -100);
}
break;
case 8:
echo "Example 8: Suppose that there was a position in an EA org, for which there were 6 qualified applicants which are otherwise 'idle'. In arbitrary units, the person in that position in that organization can produce an impact of 100 utility. The organization is player 1, applicants are players 2-7.";
$numPlayers =7;
$getCoalitionNum = array(0);
for($i = 1; $i<128; $i++){
if($i<=64){
array_push($getCoalitionNum, 0);
}else{
array_push($getCoalitionNum, 100);
}
}
break;
case 9:
echo "Example 9: A small Indian state with 10 million inhabitants spends $60 million to vaccinate 30% of their population. An NGO which would otherwise be doing something really ineffective, comes in, and by sending reminders, increases the vaccination rate to 35%. They do this very cheaply, for $100,000. The government is player 1, the indian state is player 2. Exercise: What if, instead, the NGO would have done something equally valuable?";
$numPlayers =2;
$getCoalitionNum = array(0,3000000,0,3500000);
break;
case 10:
echo "Example 10: Same as Example 9, but now there are 6 government subagencies, each of which we consider as a distinct agent. The NGO is player 1, government agencies are players 2-7.";
$numPlayers =7;
$getCoalitionNum = array(0);
for($i = 1; $i<128; $i++){
if($i<126){
array_push($getCoalitionNum, 0);
}else if($i==126){
array_push($getCoalitionNum, 3000000);
}else{
array_push($getCoalitionNum, 3500000);
}
}
break;
default:
$example = -1;
break;
}
echo "</p>";
echo "</div>";
echo "</br>";
echo "<form action=".$thisFile." method='post'>
<select name='numplayers'>";
for($n = 1; $n<8; $n++){
if($n == $numPlayers){
$hasBeenSelected = "selected = 'selected'";
}else{
$hasBeenSelected = "";
}
echo "<option value =".$n." ".$hasBeenSelected.">Number of players: ".$n."</option>";
}
echo "</select>";
echo "&nbsp;";
echo "<input type='submit' value='Change' class = 'Buttons'>";
echo "</form>";
## Power set of all players
for($n = 1; $n <= $numPlayers; $n++){
$setOfPlayers[$n] = $n;
}
$powerSet = powerSet($setOfPlayers);
$i = 0;
foreach($powerSet as $set){
$powerSetAsStrings[$i] = setToString($set);
$i++;
}
## Forms for the value of the coalition. If there is an example, use that.
if($example==-1){
$getCoalitionNum = $_POST['CoalitionNum']?? 0;
}
if($getCoalitionNum == 0){
//That is, if we haven't yet posted anything to ourselves regarding the size of the coalition
// Or if we're not in an example.
echo '<form action='.$thisFile.' method = "post">';
echo '<div class="form">';
echo '<input type="hidden" name="numplayers" value='.$numPlayers.' />';
$i = 0;
foreach($powerSetAsStrings as $setAsString){
echo '<p>';
echo '<label>Value of coalition '.$setAsString.': </label>';
echo '<input type="number" name="CoalitionNum['.$i.']" value = "0" class = "Box">';
echo '</p>';
$i++;
}
echo '</br>';
echo '</div>';
echo '<input type="submit" value="Compute" class="Buttons" >';
echo '</form>';
}else{
echo '<form action='.$thisFile.' method = "post">';
echo '<input type="hidden" name="numplayers" value='.$numPlayers.' />';
echo '<div class="form">';
$i = 0;
foreach($powerSetAsStrings as $setAsString){
echo '<p>';
echo '<label>Value of coalition '.$setAsString.': </label>';
echo '<input type="number" name="CoalitionNum['.$i.']" value ='.$getCoalitionNum[$i].' class = "Box">';
echo '</p>';
$i++;
}
echo '</br>';
echo '</div>';
echo '<input type="submit" value="Compute" class="Buttons" >';
echo '</form>';
## Compute the Shapley values
// Now, we have posted our data to ourselves. Note that we're still inside the else{} part of the loop
// All that remains is to do the actual calculations.
/*
Reminder
numPlayers: number of players
setOfPlayers: Numbers from 1 to n
powerSet: The power set of the above. All the different possible combinations.
getCoalitionNum: The value of coalitions 1 through 2^#
*/
$i = 0;
for($n = 0; $n<$numPlayers; $n++){
$Impact[$n] = 0;
}
foreach($powerSet as $set){
// in_array() function: will be useful. https://www.php.net/manual/es/function.in-array.php
$size = sizeof($set);
if($size !=0){
foreach($set as $player){
$marginalImpact = $getCoalitionNum[$i] - $getCoalitionNum[$i - pow(2,($player-1) ) ];
$Impact[$player-1] += $marginalImpact / choose($size-1,$numPlayers-1);
}
}
$i++;
}
echo '<p>';
for($n=1; $n <=$numPlayers; $n++){
echo "The Shapley value of player ".$n." is: ".$Impact[$n-1]/$numPlayers."</br>";
}
echo '</p>';
} // this is the end of the else{} part of the "have we posted any data to ourselves yet, or are we in an example" question. Only executes if we indeed have.
echo '</br>';
echo '<a href="/examples.html">List of examples</a></br>';
echo '<a href="?example='.rand(1,10).'">Random example</a></br>';
## More HTML flavor
//echo '<h3>Also of interest:</h3>
// <a href="url">Shapley value resources</a> </br>'
echo '<p>';
echo '<br /></br>';
echo '<a href="https://nunosempere.github.io/">Other things I have done</a> </br>';
echo '</p>';
echo '</body>';
echo '</html>';
## Functions
function powerSet($array){
$results = array(array());
foreach($array as $element){
foreach($results as $combination){
array_push($results, array_merge(array($element), $combination));
}
}
return $results;
// https://docstore.mik.ua/orelly/webprog/pcook/ch04_25.htm
}
function setToString($set){
$size = sizeof($set);
if($size == 0){
return "{}";
}else{
$return = "{";
for($i=0; $i<$size-1; $i++){
$return .= $set[$i].", ";
}
$return .= $set[$i]."}";
return $return;
}
}
function factorial($n){
if($n == 0){
return 1;
}else{
$f = 1;
for($i=$n; $i>=1;$i--){
$f *= $i;
}
return $f;
}
}
function choose($m, $n){
// Choose n objects among m choices
return factorial($n) / (factorial($m)*factorial($n-$m));
}
?>

238
index_old.php Executable file
View File

@ -0,0 +1,238 @@
<?php
/*
* File: /shapleyvalue/calculator
* By: Nuño Sempere
* Date: 23 Sept 2019
*
* This file calculates the Shapley value of every member of a given coalition.
*/
## HTML Flavor
echo '<html>';
echo '<head>
<title>Shapley Value Calculator</title>
<meta name="copyright" content="Nuño Sempere López-Hidalgo">
<meta name="keywords" content="Shapley Value, Shapley value, calculate Shapley value, calculate Shapley value online free, Shapley value program">
<meta name="description" content="Shapley value calculator">
<link rel="stylesheet" href="CSS/main.css" type="text/css">';
// This is the reference to our CSS style sheet.'
echo '</head>';
echo '<body>';
echo '<h1> Shapley Value Calculator </h1>';
## Pointer to this file
$thisFile = "index.php";
## Decide the Number of Players
$numPlayers = $_POST["numplayers"] ?? 3;
// It sees what number of players the user has selected.
// If it's the first time the user comes to the webpage, the default will be 3
echo "<form action=".$thisFile." method='post'>
<select name='numplayers'>";
for($n = 1; $n<8; $n++){
if($n == $numPlayers){
$hasBeenSelected = "selected = 'selected'";
}else{
$hasBeenSelected = "";
}
echo "<option value =".$n." ".$hasBeenSelected.">Number of players: ".$n."</option>";
}
echo "</select>";
echo "&nbsp;";
echo "<input type='submit' value='Change' class = 'Buttons'>";
echo "</form>";
## Power set of all players
for($n = 1; $n <= $numPlayers; $n++){
$setOfPlayers[$n] = $n;
}
$powerSet = powerSet($setOfPlayers);
$i = 0;
foreach($powerSet as $set){
$powerSetAsStrings[$i] = setToString($set);
$i++;
}
## Forms for the value of the coalition
$getCoalitionNum = $_POST['CoalitionNum']?? 0;
if($getCoalitionNum == 0){
//That is, if we haven't yet posted anything to ourselves regarding the size of the coalition
echo '<form action='.$thisFile.' method = "post">';
echo '<div class="form">';
echo '<input type="hidden" name="numplayers" value='.$numPlayers.' />';
$i = 0;
foreach($powerSetAsStrings as $setAsString){
echo '<p>';
echo '<label>Value of coalition '.$setAsString.': </label>';
echo '<input type="number" name="CoalitionNum['.$i.']" value = "0" class = "Box">';
echo '</p>';
$i++;
}
echo '</br>';
echo '</div>';
echo '<input type="submit" value="Compute" class="Buttons" >';
echo '</form>';
}else{
echo '<form action='.$thisFile.' method = "post">';
echo '<input type="hidden" name="numplayers" value='.$numPlayers.' />';
echo '<div class="form">';
$i = 0;
foreach($powerSetAsStrings as $setAsString){
echo '<p>';
echo '<label>Value of coalition '.$setAsString.': </label>';
echo '<input type="number" name="CoalitionNum['.$i.']" value ='.$getCoalitionNum[$i].' class = "Box">';
echo '</p>';
$i++;
}
echo '</br>';
echo '</div>';
echo '<input type="submit" value="Compute" class="Buttons" >';
echo '</form>';
## Compute the Shapley values
// Now, we have posted our data to ourselves. Note that we're still inside the else{} part of the loop
// All that remains is to do the actual calculations.
$i = 0;
/*
Reminder
numPlayers: number of players
setOfPlayers: Numbers from 1 to n
powerSet: The power set of the above. All the different possible combinations.
getCoalitionNum: The value of coalitions 1 through 2^#
*/
$i = 0;
for($n = 0; $n<$numPlayers; $n++){
$Impact[$n] = 0;
}
foreach($powerSet as $set){
// in_array() function: will be useful. https://www.php.net/manual/es/function.in-array.php
$size = sizeof($set);
if($size !=0){
foreach($set as $player){
$marginalImpact = $getCoalitionNum[$i] - $getCoalitionNum[$i - pow(2,($player-1) ) ];
$Impact[$player-1] += $marginalImpact / choose($size-1,$numPlayers-1);
}
}
$i++;
}
echo '<p>';
for($n=1; $n <=$numPlayers; $n++){
echo "The Shapley value of player ".$n." is: ".$Impact[$n-1]/$numPlayers."</br>";
}
echo '</p>';
} // this is the end of the else{} part of the "have we posted any data to ourselves yet" question. Only executes if we indeed have.
## More HTML flavor
//echo '<h3>Also of interest:</h3>
// <a href="url">Shapley value resources</a> </br>'
echo '<p>';
echo '<br /></br>';
echo '<a href="https://nunosempere.github.io/">Other things I have done</a> </br>';
echo '</p>';
echo '</body>';
echo '</html>';
## Functions
function powerSet($array){
$results = array(array());
foreach($array as $element){
foreach($results as $combination){
array_push($results, array_merge(array($element), $combination));
}
}
return $results;
// https://docstore.mik.ua/orelly/webprog/pcook/ch04_25.htm
}
function setToString($set){
$size = sizeof($set);
if($size == 0){
return "{}";
}else{
$return = "{";
for($i=0; $i<$size-1; $i++){
$return .= $set[$i].", ";
}
$return .= $set[$i]."}";
return $return;
}
}
function factorial($n){
if($n == 0){
return 1;
}else{
$f = 1;
for($i=$n; $i>=1;$i--){
$f *= $i;
}
return $f;
}
}
function choose($m, $n){
// Choose n objects among m choices
return factorial($n) / (factorial($m)*factorial($n-$m));
}
?>

207
publicGoodsGame.php Executable file
View File

@ -0,0 +1,207 @@
<?php
/*
* File: /shapleyvalue.com/publicGoodsGame.php
* By: Nuño Sempere
* Date: 23 Sept 2019
*
* This file applies the Shapley value to a public goods game with 6 players.
*/
## HTML Flavor
echo '<html>';
echo '<head>
<title>Shapley Value Calculator</title>
<meta name="copyright" content="Nuño Sempere López-Hidalgo">
<meta name="keywords" content="Shapley Value, Shapley value, calculate Shapley value, calculate Shapley value online free, Shapley value program">
<meta name="description" content="Shapley value calculator">
<link rel="stylesheet" href="CSS/main.css" type="text/css">';
// This is the reference to our CSS style sheet.'
echo '</head>';
echo '<body>';
echo '<h1> Shapley Value Calculator </h1>';
## Pointer to this file
$thisFile = "publicGoodsGame.php";
## Power set of all players
$numPlayers = 6;
## Initially, the number of players is 6.
for($n = 1; $n <= $numPlayers; $n++){
$setOfPlayers[$n] = $n;
}
$powerSet = powerSet($setOfPlayers);
$i = 0;
foreach($powerSet as $set){
$powerSetAsStrings[$i] = setToString($set);
$i++;
}
## Check if the thing has been posted
$getContributionPlayer = $_POST['ContributionPlayer']?? -1;
$getMultiplier = $_POST['Multiplier'] ?? -1;
if($getContributionPlayer == -1){
## Get the contributions of each player to the common pot
echo '<form action='.$thisFile.' method = "post">';
echo '<div class="form">';
echo '<input type="hidden" name="numplayers" value='.$numPlayers.' />';
$i = 0;
for($i = 0; $i<$numPlayers; $i++){
echo '<p>';
echo '<label>Contribution of Player #'.($i+1).': &nbsp</label>';
echo '<input type="number" name="ContributionPlayer['.($i).']" value = "0" class = "Box">';
echo '</p>';
}
echo '<p></br></p>';
echo '<p>';
echo '<label>Multiplier = &nbsp </label>';
echo '<input type="number" name="Multiplier" value = "0" step="0.01" class = "Box">';
echo '</p>';
echo '</br>';
echo '</div>';
echo '<input type="submit" value="Compute" class="Buttons" >';
echo '</form>';
}else{
echo '<form action='.$thisFile.' method = "post">';
echo '<div class="form">';
echo '<input type="hidden" name="numplayers" value='.$numPlayers.' />';
$i = 0;
for($i = 0; $i<$numPlayers; $i++){
echo '<p>';
echo '<label>Contribution of Player #'.($i+1).': &nbsp</label>';
echo '<input type="number" name="ContributionPlayer['.($i).']" value ='.$getContributionPlayer[($i)].' class = "Box">';
echo '</p>';
}
echo '<p></br></p>';
echo '<p>';
echo '<label>Multiplier = &nbsp </label>';
echo '<input type="number" name="Multiplier" value ='.$getMultiplier.' step = "0.01" class = "Box">';
echo '</p>';
echo '</br>';
echo '</div>';
echo '<input type="submit" value="Compute" class="Buttons" >';
echo '</form>';
## Now, the Shapley value in a public good game is simply going to be contribution*multiplier
## The classical reward is simply aggregate*multiplier/number of players.
## Let D = Shapley value - Classical reward
## Then it would be interesting to check what happens when the payout is
## P = Classical Reward + Alpha*D,
## Where alpha ranges from 0 to 1.
## I think that just comparing alpha = 0, alpha = 1/3, alpha = 2/3, (alpha = 1) would be interesting.
$sumContributions = array_sum($getContributionPlayer);
echo '<p>';
echo 'Sum of the contributions = &nbsp'.$sumContributions;
echo '</p>';
echo '<p>';
echo 'Sum*Multiplier = &nbsp'.($sumContributions*$getMultiplier);
echo '</p>';
echo '<p>';
$payout = ($sumContributions*$getMultiplier/$numPlayers);
echo 'Payout = Sum*Multiplier/ Number of Players = &nbsp'.$payout;
echo '</p>';
## What is the difference between the payout and the Shapley value?
echo '<div class="centeredExample">';
echo '<p>';
echo "<h3>For each player, what is the difference between the payout and the Shapley value? </h3>";
for($i = 0; $i<$numPlayers; $i++){
echo '<p>';
echo 'Difference for Player #'.($i+1).'&nbsp = '.($getMultiplier*$getContributionPlayer[$i]-$payout);
echo '</p>';
}
echo '</p>';
echo '</div>';
}
## Footer
echo '<p><a href="/">Go back</a></p></br>';
echo '</body>';
echo '</html>';
## Functions
function powerSet($array){
$results = array(array());
foreach($array as $element){
foreach($results as $combination){
array_push($results, array_merge(array($element), $combination));
}
}
return $results;
// https://docstore.mik.ua/orelly/webprog/pcook/ch04_25.htm
}
function setToString($set){
$size = sizeof($set);
if($size == 0){
return "{}";
}else{
$return = "{";
for($i=0; $i<$size-1; $i++){
$return .= $set[$i].", ";
}
$return .= $set[$i]."}";
return $return;
}
}
function factorial($n){
if($n == 0){
return 1;
}else{
$f = 1;
for($i=$n; $i>=1;$i--){
$f *= $i;
}
return $f;
}
}
function choose($m, $n){
// Choose n objects among m choices
return factorial($n) / (factorial($m)*factorial($n-$m));
}