// http://bechirot.gov.il/election/about/Pages/CalculatingSeatsMethod.aspx
// http://www.knesset.gov.il/lexicon/eng/seats_eng.htm
// http://main.knesset.gov.il/About/Lexicon/Pages/seats.aspx
/**
* Computes the Badder-Offer score for specific party.
*
* @param {party_votes} Two columns, name-votes pairs.
* @param {agreement_pairs} Two columns, name-name pairs.
* @param {party} The name of the party to be shown.
* @param {qualifying_threshold} ×חוז החסימה.
* @customfunction
*/
function BadderOfferMethod(party_votes, agreement_pairs, party, qualifying_threshold) {
if (typeof qualifying_threshold === 'undefined')
qualifying_threshold = 0.0325;
var parties = prepare_data_(party_votes, agreement_pairs);
var passed_parties = filter_parties_(parties, qualifying_threshold);
var agreements_list = get_agreement_list_(passed_parties);
mandate_splitting_(agreements_list).forEach(split_share_);
var d = make_dict(parties);
return d[party].seats;
}
function list_indicator_(x) {
/* The reason for adding 1 is for determining what the indicator would be
if the pair would receive that additional seat. */
return Math.floor(x.votes / (x.seats + 1))
}
/*
חלוקה ר××©×•× ×”
×. ×ž×—×œ×§×™× ×ת סה"×› הקולות ×”×›×©×¨×™× ×©×œ הרשימות המשתתפות בחלוקת ×”×ž× ×“×˜×™× ×œ-120 (מספר המקומות ×”×¢×•×ž×“×™× ×œ×—×œ×•×§×”), והתוצ××” ×”×™× ×”×ž×•×“×“ הכללי.
ב. ×ž×—×œ×§×™× ×ת סה"×› הקולות של כל רשימה המשתתפת בחלוקה למודד הכללי ×•×ž×§×‘×œ×™× ×ת מספר ×”×ž× ×“×˜×™× ×©×§×™×‘×œ×” הרשימה.
×’. בדרך זו, ×ž×—×œ×§×™× ×ת הקולות של כל הרשימות שעברו ×ת ×חוז החסימה ומשתתפות בחלוקה.
ד. ×”×ž×¡×¤×¨×™× ×”×©×œ×ž×™× ×”×™×•×¦××™× ×ž×”×—×œ×•×§×” ×”× ×ž×¡×¤×¨ ×”×ž× ×“×˜×™×.
*/
function get_agreement_list_(passed_parties) {
// first phase
var total_votes = sum_(passed_parties, 'votes');
var general_indicator = Math.floor(total_votes / 120);
passed_parties.forEach(function(p) {
p.agreement.seats += Math.floor(p.votes / general_indicator);
});
return passed_parties.map(key_('agreement')).toSet();
}
/*
חלוקה ×©× ×™×”
×”. ×ž×—×‘×¨×™× ×ת כל ×”×ž× ×“×˜×™×, ×•×”×ž× ×“×˜×™× ×”× ×•×ª×¨×™× ×¢×“ להשלמת מספר ×”×ž× ×“×˜×™× ×œ-120, ××•×ª× ×ž×—×œ×§×™× ×¢×œ פי שיטת מודד הרשימה הגדול ביותר.
למשל, בבחירות ×œ×›× ×¡×ª ×”-18 × ×•×ª×¨×• 5 ×ž× ×“×˜×™× ×œ×—×œ×•×§×”.
ו. לצורך חלוקת ×”×ž× ×“×˜×™× ×”× ×•×ª×¨×™×, רו××™× 2 רשימות שהתקשרו ×‘×™× ×™×”×Ÿ כרשימה ×חת â€“×ž×—×‘×¨×™× ×ת הקולות ×”×›×©×¨×™× ×©×§×™×‘×œ×• 2 הרשימות ו×ת מספר ×”×ž× ×“×˜×™× ×©×§×™×‘×œ×• 2 הרשימות בחלוקה הר××©×•× ×”, ×•×ž×ª×™×™×—×¡×™× ××œ×™×”× ×‘×©×œ×‘ ×–×” ×›×ל רשימת ×ž×•×¢×ž×“×™× ×חת, ×–×ת ×‘×ª× ××™ שכל ×חת מהרשימות עברה ×ת ×חוז החסימה.
×–. ×ת ×”×ž× ×“×˜×™× ×”× ×•×ª×¨×™× ×ž×—×œ×§×™× ×œ×¤×™ מודד לכל רשימה לפי ×”× ×•×¡×—×”:
מודד רשימה = מספר הקולות שקיבלה הרשימה
________________________________________
לחלק ל - מספר ×”×ž× ×“×˜×™× ×©×§×™×‘×œ×” בחלוקה הר××©×•× ×” + 1
×§×•×‘×¢×™× ×›×š על פי ×”× ×•×¡×—×” ×”×מורה ×ת המודד לכל רשימה. רשימה שלה המודד הגדול ביותר מקבלת ×ת ×”×ž× ×“×˜.
×—. לרשימה שקיבלה ×ž× ×“×˜ בחלוקת המקומות ×”× ×•×ª×¨×™× × ×§×‘×¢ מודד רשימה חדש בהת×× ×œ×ž×¡×¤×¨ ×”×ž× ×“×˜×™× ×©×™×© לה.
ט. כך ×§×•×‘×¢×™× ×ž×•×“×“×™× ×¢×“ לחלוקת כל ×”×ž× ×“×˜×™× ×”× ×•×ª×¨×™×.
*/
function mandate_splitting_(agreements_list) {
// second phase
var seats_so_far = sum_(agreements_list, 'seats');
agreements_list.forEach(function(s) {
s.votes = s.parties.sum('votes');
});
for (var i = seats_so_far; i < 120; i++) {
agreements_list.max(list_indicator_).seats += 1;
}
return agreements_list
}
/*
3. חלוקת ×”×ž× ×“×˜×™× ×‘×™×Ÿ הרשימות הקשורות ×‘×™× ×™×”×Ÿ
עתה × ×•×ª×¨ לקבוע ×יזו רשימה מבין שתי רשימות שהתקשרו ×‘×™× ×™×”×Ÿ תקבל ×ת ×”×ž× ×“×˜ ×”× ×•×¡×£ שבו זכו שתיהן בחלוקת ×”×ž× ×“×˜×™× ×”× ×•×ª×¨×™×.
קביעה זו × ×¢×©×™×ª ×’× ×”×™× ×‘×©× ×™ שלבי×.
להלן שלבי החישוב:
שלב ×'
×. קביעת מודד ×¤× ×™×ž×™ ×חיד ×œ×ž× ×“×˜ של זוג הרשימות המתקשרות.
מודד ×¤× ×™×ž×™ ×חיד ×œ×ž× ×“×˜ = מספר הקולות ×”×›×©×¨×™× ×©×œ שתי הרשימות
________________________________________
לחלק ל - מספר ×”×ž× ×“×˜×™× ×©×§×™×‘×œ×• שתי הרשימות
ב. ×‘×•×“×§×™× ×›×ž×” ×ž× ×“×˜×™× ×מורה לקבל כל רשימה ×‘× ×¤×¨×“ על פי המודד ×”× "ל.
×”×™×™× ×•,
מספר ×”×ž× ×“×˜×™× ×©×§×™×‘×œ×” הרשימה ×‘× ×¤×¨×“ = סה"×› הקולות ×”×›×©×¨×™× ×©×§×™×‘×œ×” רשימה ×‘× ×¤×¨×“
________________________________________
לחלק ל - מודד ×œ×ž× ×“×˜
שלב ב'
על פי מספר ×”×ž× ×“×˜×™× ×©×§×™×‘×œ×• שתי הרשימות ביחד, × ×•×ª×¨ ×ž× ×“×˜ × ×•×¡×£ לחלוקה.
×ת ×”×ž× ×“×˜ ×”× ×•×¡×£ תקבל רשימה שלה "מודד רשימה ×ישי הגדול ביותר".
חישוב המודד ×”×ישי לכל רשימה ×‘× ×¤×¨×“ × ×¢×©×” ב×ותה דרך חישוב של חלוקת ×”×ž× ×“×˜×™× ×”× ×•×ª×¨×™×.
×”×™×™× ×•, לפי ×”× ×•×¡×—×”:
מודד רשימה = מספר הקולות ×”×›×©×¨×™× ×©×§×™×‘×œ×” הרשימה ×‘× ×¤×¨×“
________________________________________
לחלק ל - מספר ×”×ž× ×“×˜×™× ×©×§×™×‘×œ×” הרשימה ×‘× ×¤×¨×“ + 1
*/
function split_share_(s) {
if (s.parties.length === 1) {
s.parties[0].seats = s.seats;
return;
}
// split between sharing parties
var indicator = Math.floor(s.votes / s.seats);
s.parties.forEach(function(p) {
p.seats = Math.floor(p.votes / indicator);
});
s.parties.max(list_indicator_).seats += 1;
}
/*
1. קביעת הרשימות המשתתפות בחלוקת ×”×ž× ×“×˜×™×
×. ×ž×¡×›×ž×™× ×ת סך הקולות ×”×›×©×¨×™× ×©×§×™×‘×œ×” כל ×חת מרשימות המועמדי×.
ב. ×§×•×‘×¢×™× ×ת מס' הקולות המהווה ×ת ×חוז החסימה.
×חוז החסימה = 3.25% מכלל הקולות הכשרי×.
×’. רשימות ×”×ž×•×¢×ž×“×™× ×©×œ× ×–×›×• במספר הקולות הדרוש – ×œ× ×ž×©×ª×ª×¤×•×ª בחלוקת ×”×ž× ×“×˜×™×.
ד. ×§×•×‘×¢×™× ×ת מספר הקולות ×”×›×©×¨×™× ×©×œ הרשימות המשתתפות בחלוקת ×”×ž× ×“×˜×™×.
המספר הכולל של הקולות ×”×›×©×¨×™× ×©×œ כל הרשימות פחות מספר הקולות ×”×›×©×¨×™× ×©×œ רשימות ×©×œ× ×¢×‘×¨×• ×ת ×חוז החסימה ×•×œ× ×ž×©×ª×ª×¤×•×ª בחלוקה שווה לסה"×› הקולות ×”×›×©×¨×™× ×©×œ הרשימות המשתתפות בחלוקת ×”×ž× ×“×˜×™×.
*/
function filter_parties_(parties, qualifying_threshold_percentage) {
var total_votes = parties.sum('votes');
function passed(party) {
return party.votes >= total_votes * qualifying_threshold_percentage;
}
var passed_parties = parties.filter(passed);
passed_parties.forEach(function(p) {
p.agreement.parties = p.agreement.parties.filter(passed);
});
return passed_parties;
}
function Agreement(parties) {
return {
seats: 0,
parties: parties
}
}
function Party(name, votes) {
var res = {
name: name,
votes: votes,
seats: 0
};
res.agreement = Agreement([res]);
return res;
}
function prepare_data_(party_votes, agreement_pairs) {
var parties = {}
var all_parties = [];
party_votes.forEach(function(nv) {
var name = nv[0], votes = nv[1];
parties[name] = Party(name, votes);
all_parties.push(parties[name]);
});
agreement_pairs.forEach(function(pair) {
var p1 = parties[pair[0]];
var p2 = parties[pair[1]];
p1.agreement = Agreement([p2, p1]);
p2.agreement = p1.agreement;
});
return all_parties;
}
function make_dict(parties) {
var res = {};
parties.forEach(function(p) {
res[p.name] = p;
});
return res;
}
function test() {
var party_votes = [
['Likud', 925279],
['Labor', 455183],
['Shinui', 386535],
['Shas', 258879],
['Ichud Leumi-Yisrael Beiteinu', 173973],
['Meretz', 164122],
['United Torah Judaism', 135087],
['National Religious Party', 132370],
['Hadash', 93819],
['Am Ehad', 86808],
['Balad', 71299],
['Yisrael BeAliyah', 67719],
['United Arab List', 65551],
];
var agreement_pairs = [ ];
var res = BadderOfferMethod(party_votes, agreement_pairs, 'Likud');
return 0;
}
//HELPERS
function key_(f) {
if (typeof f == 'string')
return function(p) { return p[f]; };
if (typeof f == 'undefined')
return function(x) { return x; };
return f;
}
Array.prototype.max = function(key) {
key = key_(key);
return this.reduce(function(x, y) {
return key(x) > key(y) ? x : y;
});
};
Array.prototype.sum = function(key) {
return sum_(this, key);
};
Array.prototype.toSet = function(key) {
var res = [];
this.forEach(function(p) {
var val = key_(key)(p);
if (res.indexOf(val) < 0)
res.push(val);
});
return res;
}
Array.prototype.min = function() {
return Math.min.apply(null, this);
};
function sum_(arr, key) {
if (!arr.length)
return 0;
return arr.map(key_(key)).reduce(function(a, b) { return a + b });
}