PageRenderTime 61ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/java/org/bolson/vote/staticballot/IRNR.java

https://code.google.com/p/voteutil/
Java | 333 lines | 324 code | 4 blank | 5 comment | 15 complexity | 85fa10c96fe1f5408f1a8ae20f6fc255 MD5 | raw file
  1. package org.bolson.vote.staticballot;
  2. import java.util.Vector;
  3. /**
  4. * Instant Runoff Normalized Ratings
  5. @author Brian Olson
  6. */
  7. public class IRNR extends RatedVotingSystem {
  8. Vector votes = new Vector();
  9. int voterToTrack = -1;
  10. boolean showIntermedite = false;
  11. int[] winners = null;
  12. boolean rmsnorm = true;
  13. Vector debugHistory = null;
  14. StringBuffer debugStr = null;
  15. public IRNR( int numCandidates ) {
  16. super( numCandidates );
  17. talley = new double[numc];
  18. }
  19. public String name() {
  20. return "Instant Runoff Normalized Ratings";
  21. }
  22. public VotingSystem init( String argv[] ) {
  23. if ( argv == null ) return this;
  24. for ( int i = 0; i < argv.length; i++ ) {
  25. if ( argv[i].equals( "track" ) ) {
  26. i++;
  27. voterToTrack = Integer.parseInt( argv[i] );
  28. } else if ( argv[i].equals( "show" ) ) {
  29. showIntermedite = true;
  30. } else if ( argv[i].equals( "rmsnorm" ) || argv[i].equals( "l2norm" ) || argv[i].equals( "sphericalNorm" ) ) {
  31. rmsnorm = true;
  32. } else if ( argv[i].equals( "linearNorm" ) || argv[i].equals( "l1norm" ) || argv[i].equals( "manhattanNorm" ) ) {
  33. rmsnorm = false;
  34. // } else if ( argv[i].equals( "" ) ) {
  35. } else {
  36. System.err.println( "IRNR.init: bogus arg \"" + argv[i] + '"' );
  37. return this;
  38. }
  39. }
  40. return this;
  41. }
  42. public int voteRating( int rating[] ) {
  43. votes.add( rating.clone() );
  44. winners = null;
  45. return 0;
  46. }
  47. public int voteRating( float rating[] ) {
  48. votes.add( rating.clone() );
  49. winners = null;
  50. return 0;
  51. }
  52. public int voteRating( double rating[] ) {
  53. votes.add( rating.clone() );
  54. winners = null;
  55. return 0;
  56. }
  57. public int[] getWinners() {
  58. if ( winners != null ) {
  59. return (int[])winners.clone();
  60. }
  61. int i;
  62. int numWinners = 1;
  63. int numActive = numc;
  64. boolean active[] = new boolean[numc];
  65. int choiceIndecies[] = new int[numc];
  66. for ( int c = 0; c < numc; c++ ) {
  67. active[c] = true;
  68. }
  69. if ( debug ) {
  70. debugHistory = new Vector();
  71. debugStr = new StringBuffer();
  72. }
  73. while ( numActive > 1 ) {
  74. // per IR setup
  75. {
  76. int curact = 0;
  77. for ( int c = 0; c < numc; c++ ) {
  78. if ( active[c] ) {
  79. talley[c] = 0;
  80. choiceIndecies[curact] = c;
  81. curact++;
  82. }
  83. }
  84. }
  85. // sum up into talley
  86. for ( int v = 0; v < votes.size(); v++ ) {
  87. Object o;
  88. double ts;
  89. ts = 0.0;
  90. o = votes.elementAt( v );
  91. if ( o instanceof int[] ) {
  92. int[] ot = (int[])o;
  93. for ( int c = 0; c < numc; c++ ) if ( ot[c] != NO_VOTE && active[c] ) {
  94. //System.out.println("int[] ot[" + c + "] = " + ot[c] );
  95. if ( rmsnorm ) {
  96. ts += ot[c] * ot[c];
  97. } else {
  98. ts += Math.abs(ot[c]);
  99. }
  100. }
  101. if ( rmsnorm ) {
  102. ts = Math.sqrt( ts );
  103. }
  104. for ( int c = 0; c < numc; c++ ) if ( ot[c] != NO_VOTE && active[c] && ts != 0 ) {
  105. talley[c] += ot[c] / ts;
  106. }
  107. } else if ( o instanceof float[] ) {
  108. float[] ot = (float[])o;
  109. for ( int c = 0; c < numc; c++ ) if ( active[c] && ! Float.isNaN( ot[c] ) ) {
  110. //System.out.println("float[] ot[" + c + "] = " + ot[c] );
  111. if ( rmsnorm ) {
  112. ts += ot[c] * ot[c];
  113. } else {
  114. ts += Math.abs(ot[c]);
  115. }
  116. }
  117. if ( rmsnorm ) {
  118. ts = Math.sqrt( ts );
  119. }
  120. for ( int c = 0; c < numc; c++ ) if ( active[c] && ! Float.isNaN( ot[c] ) && ts != 0 ) {
  121. //System.out.println("float[] ot[" + c + "] = " + ot[c] + " / (ts = " + ts + ") = " + (ot[c] / ts) );
  122. talley[c] += ot[c] / ts;
  123. }
  124. if ( v == voterToTrack ) {
  125. for ( int c = 0; c < numc; c++ ) {
  126. if ( active[c] ) {
  127. System.out.print( ot[c] + " / " + ts + " = " + (ot[c] / ts) + '\t' );
  128. } else {
  129. System.out.print( ot[c] + " disabled = 0\t" );
  130. }
  131. }
  132. System.out.println();
  133. }
  134. } else if ( o instanceof double[] ) {
  135. double[] ot = (double[])o;
  136. for ( int c = 0; c < numc; c++ ) if ( active[c] && ! Double.isNaN( ot[c] ) ) {
  137. //System.out.println("double[] ot[" + c + "] = " + ot[c] );
  138. if ( rmsnorm ) {
  139. ts += ot[c] * ot[c];
  140. } else {
  141. ts += Math.abs(ot[c]);
  142. }
  143. }
  144. if ( rmsnorm ) {
  145. ts = Math.sqrt( ts );
  146. }
  147. for ( int c = 0; c < numc; c++ ) if ( active[c] && ! Double.isNaN( ot[c] ) && ts != 0 ) {
  148. talley[c] += ot[c] / ts;
  149. }
  150. } else {
  151. System.err.println( "bogus vote \"" + o + '\"' );
  152. }
  153. }
  154. if ( debug ) {
  155. debugHistory.add( active.clone() );
  156. debugHistory.add( talley.clone() );
  157. for ( int c = 0; c < numc; c++ ) {
  158. if ( ! active[c] ) {
  159. debugStr.append('x');
  160. }
  161. debugStr.append( talley[c] );
  162. if ( (c + 1) < numc ) {
  163. debugStr.append( "\t" );
  164. }
  165. }
  166. debugStr.append('\n');
  167. }
  168. // sort
  169. boolean notdone = true;
  170. while ( notdone ) {
  171. notdone = false;
  172. for ( int c = 1; c < numActive; c++ ) {
  173. if ( talley[choiceIndecies[c]] > talley[choiceIndecies[c-1]] ) {
  174. int ti = choiceIndecies[c];
  175. choiceIndecies[c] = choiceIndecies[c-1];
  176. choiceIndecies[c-1] = ti;
  177. notdone = true;
  178. }
  179. }
  180. }
  181. if ( showIntermedite ) {
  182. System.out.println("num active " + numActive );
  183. for ( int c = 0; c < numc; c++ ) {
  184. int tci;
  185. tci = choiceIndecies[c];
  186. System.out.println("\tchoiceIndecies[" + c + "] = " + tci +
  187. "\ttalley[" + tci + "] = " + talley[tci] +
  188. "\tactive[" + tci + "] = " + active[tci] );
  189. }
  190. }
  191. if ( talley[choiceIndecies[0]] == talley[choiceIndecies[numActive-1]] ) {
  192. // N-way tie.
  193. numWinners = numActive;
  194. break;
  195. }
  196. active[choiceIndecies[numActive-1]] = false;
  197. numActive--;
  198. while ( (numActive > 1) &&
  199. (talley[choiceIndecies[numActive-1]] == talley[choiceIndecies[numActive]]) ) {
  200. // eliminate all who tied for last
  201. active[choiceIndecies[numActive-1]] = false;
  202. numActive--;
  203. }
  204. }
  205. winners = new int[numWinners];
  206. for ( i = 0; i < numWinners; i++ ) {
  207. winners[i] = choiceIndecies[i];
  208. }
  209. return (int[])winners.clone();
  210. }
  211. /**
  212. Multi-seat IRNR.
  213. Everyone who votes for a winner shares in the distribution of the overvote and retains that fraction of their voting power.*/
  214. public int[] getWinners( /*java.io.PrintWriter out, */int numSeats ) {
  215. return null;
  216. }
  217. protected double talley[];
  218. public String toString() {
  219. StringBuffer sb = new StringBuffer();
  220. for ( int i = 0; i < talley.length; i++ ) {
  221. sb.append( talley[i] ).append('\n');
  222. }
  223. return sb.toString();
  224. }
  225. public String toString( String names[] ) {
  226. StringBuffer sb = new StringBuffer();
  227. for ( int i = 0; i < talley.length; i++ ) {
  228. sb.append( names[i] ).append('\t');
  229. sb.append( talley[i] ).append('\n');
  230. }
  231. return sb.toString();
  232. }
  233. public String htmlSummary( String names[] ) {
  234. StringBuffer sb;
  235. double max;
  236. boolean in[] = new boolean[numc];
  237. int maxi = 0,i;
  238. for ( i = 0; i < numc; i++ ) {
  239. in[i] = true;
  240. }
  241. if ( names != null ) {
  242. sb = new StringBuffer( "<table border=\"1\"><tr><th></th><th>IRNR Rating Summation</th></tr>\n" );
  243. } else {
  244. sb = new StringBuffer( "<table border=\"1\"><tr><th>Choice Index</th><th>IRNR Rating Summation</th></tr>\n" );
  245. }
  246. getWinners();
  247. while ( true ) {
  248. boolean done;
  249. max = Double.NEGATIVE_INFINITY;
  250. done = true;
  251. for ( i = 0; i < numc; i++ ) {
  252. if ( in[i] ) {
  253. if ( (talley[i] > max) || done ) {
  254. done = false;
  255. maxi = i;
  256. max = talley[i];
  257. }
  258. }
  259. }
  260. if ( done ) break;
  261. i = maxi;
  262. in[i] = false;
  263. sb.append( "<tr><td>" );
  264. if ( names != null ) {
  265. sb.append( names[i] );
  266. } else {
  267. sb.append( i+1 );
  268. }
  269. sb.append( "</td><td>" );
  270. sb.append( talley[i] );
  271. sb.append( "</td></tr>\n" );
  272. }
  273. sb.append( "</table>\n" );
  274. return sb.toString();
  275. }
  276. public String getDebugHTML( String[] names ) {
  277. int i = 0, j;
  278. if ( ! debug || debugHistory == null ) {
  279. return null;
  280. }
  281. int rounds = debugHistory.size() / 2;
  282. boolean[][] actives = new boolean[rounds][];
  283. double[][] tallies = new double[rounds][];
  284. while ( i < rounds ) {
  285. //boolean[] active;
  286. //double[] talley;
  287. actives[i] = (boolean[])debugHistory.elementAt( i * 2 );
  288. tallies[i] = (double[]) debugHistory.elementAt( i * 2 + 1 );
  289. i++;
  290. }
  291. StringBuffer toret = new StringBuffer( 2048 );
  292. toret.append("<pre>");
  293. toret.append(debugStr);
  294. toret.append("</pre>");
  295. toret.append("<TABLE BORDER=\"1\"><TR><TH></TH>");
  296. for ( j = 0; j < rounds; j++ ) {
  297. toret.append("<TH>").append(j).append("</TH>");
  298. }
  299. toret.append("</TR>");
  300. for ( i = 0; i < numc; i++ ) {
  301. toret.append("<TR>");
  302. toret.append("<TD>");
  303. toret.append(names[i]);
  304. toret.append("</TD>");
  305. for ( j = 0; j < rounds; j++ ) {
  306. toret.append("<TD>");
  307. if ( ! actives[j][i] ) {
  308. toret.append("<FONT COLOR=\"#999999\">");
  309. }
  310. toret.append( tallies[j][i] );
  311. if ( ! actives[j][i] ) {
  312. toret.append("</FONT>");
  313. }
  314. toret.append("</TD>");
  315. }
  316. toret.append("</TR>");
  317. }
  318. toret.append("</TABLE>");
  319. return toret.toString();
  320. }
  321. };