PageRenderTime 60ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/simulator/voter_main.cpp

https://code.google.com/p/voteutil/
C++ | 345 lines | 326 code | 17 blank | 2 comment | 91 complexity | 872e89f8c675d7f2a17e5e8c6394ec72 MD5 | raw file
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <limits.h>
  4. #include <time.h>
  5. #include <unistd.h>
  6. #include <math.h>
  7. #include <string.h>
  8. #include <signal.h>
  9. #include <pthread.h>
  10. #include <assert.h>
  11. #include "Voter.h"
  12. #include "VoterSim.h"
  13. #include "VotingSystem.h"
  14. #include "OneVotePickOne.h"
  15. #include "RankedVotePickOne.h"
  16. #include "AcceptanceVotePickOne.h"
  17. #include "FuzzyVotePickOne.h"
  18. #include "InstantRunoffVotePickOne.h"
  19. #include "Condorcet.h"
  20. #include "IRNR.h"
  21. #include "STV.h"
  22. #include "IRNRP.h"
  23. #include "RandomElection.h"
  24. #include "ResultFile.h"
  25. #include "ResultLog.h"
  26. #if NO_DB
  27. #else
  28. #include "DBResultFile.h"
  29. #include "ThreadSafeDBRF.h"
  30. #endif
  31. #include "WorkQueue.h"
  32. #include "workQThread.h"
  33. #if HAVE_PROTOBUF
  34. #include "ProtoResultLog.h"
  35. #include <fcntl.h>
  36. #else
  37. class ProtoResultLog;
  38. #endif
  39. // This doesn't do anything but make sure these methods get linked in.
  40. void* linker_tricking() {
  41. delete new STV();
  42. return new IRNRP();
  43. }
  44. volatile int goGently = 0;
  45. void mysigint( int a ) {
  46. goGently = 1;
  47. }
  48. #ifndef MAX_METHOD_ARGS
  49. #define MAX_METHOD_ARGS 64
  50. #endif
  51. static char voter_main_usage[] =
  52. "-F dbResultFile\n"
  53. "--textout textResultFile\n"
  54. "-Mef methodDescFile\n"
  55. "-M methodArg\n"
  56. "-e methodName -- consumes previous -M args initting this method\n"
  57. "--list -- show known methods and exit\n"
  58. "--vsteps -- space separated list of number-of-voters\n"
  59. "--csteps -- space separated list of number-of-choices\n"
  60. "--esteps -- space separated list of error rates\n"
  61. "--CSsteps -- space separated list of choices,seats pairs\n"
  62. "-n iter -- iterations to run\n"
  63. "--threads n\n"
  64. "\n"
  65. "VoterSim::init options:\n"
  66. "-v n -- number of voters\n"
  67. "-c n -- number of choices\n"
  68. "-e n -- error rate\n"
  69. "-n iter -- iterations to run\n"
  70. "-N iter lim -- run up to iter lim if not there already\n"
  71. "-P -- print voters every run\n"
  72. "-r -- print results every run\n"
  73. "-R -- result dump\n"
  74. "-H filename -- result dump HTML\n"
  75. "-h filename -- result dump HTML alt format\n"
  76. "-D filename -- dump voters, binary\n"
  77. "-d filename -- dump voters, text\n"
  78. "-L filename -- load voters, binary\n"
  79. "-l filename -- load voters, text\n"
  80. "-q -- quiet\n"
  81. "-s -- enable strategies\n"
  82. "-S int -- summary print style\n"
  83. "--nflat -- voters and choices exist in N demensional uniformly random space\n"
  84. "--ngauss -- voters and choices exist in N demensional gaussian random space\n"
  85. "--dimensions N\n"
  86. "--independentprefs -- voters have independent uniform -1..1 preferences for each choice\n"
  87. ;
  88. int main( int argc, char** argv ) {
  89. Steps* stepq = NULL;
  90. VoterSim* s;
  91. workQThread** wqts;
  92. ResultFile* drf = NULL;
  93. #if !NO_DB
  94. char* drfname = NULL;
  95. #endif
  96. NameBlock nb;
  97. int j = 0, i;
  98. int nsys;
  99. int numThreads = 1;
  100. int hang = 0;
  101. const char** methodArgs = (const char**)malloc( sizeof(char*) * MAX_METHOD_ARGS );
  102. int methodArgc = 0;
  103. VSConfig* systemList = NULL;
  104. VotingSystem** systems;
  105. ResultLog* rlog = NULL;
  106. assert(methodArgs);
  107. srandom(time(NULL));
  108. for ( i = 0; i < argc; i++ ) {
  109. if ( j != i ) {
  110. argv[j] = argv[i];
  111. }
  112. if ( ! strcmp( argv[i], "-F" ) ) {
  113. #if NO_DB
  114. fprintf(stderr, "database result file compiled out\n");
  115. exit(1);
  116. #else
  117. i++;
  118. drfname = argv[i];
  119. #endif
  120. } else if ( ! strcmp( argv[i], "--textout" ) ) {
  121. i++;
  122. drf = TextDumpResultFile::open(argv[i]);
  123. if (drf == NULL) {
  124. fprintf(stderr, "error: could not process \"--textout %s\"\n", argv[i]);
  125. exit(1);
  126. }
  127. #if HAVE_PROTOBUF
  128. } else if ( ! strcmp( argv[i], "--rlog" ) ) {
  129. i++;
  130. rlog = ProtoResultLog::openForAppend(argv[i]);
  131. if (rlog == NULL) {
  132. perror(argv[i]);
  133. exit(1);
  134. }
  135. #endif
  136. } else if ( ! strcmp( argv[i], "-Mef" ) ) {
  137. i++;
  138. systemList = systemsFromDescFile( argv[i], methodArgs, MAX_METHOD_ARGS, systemList );
  139. methodArgc = 0;
  140. } else if ( ! strcmp( argv[i], "-M" ) ) {
  141. i++;
  142. if ( methodArgc < MAX_METHOD_ARGS ) {
  143. methodArgs[methodArgc] = argv[i];
  144. methodArgc++;
  145. } else {
  146. fprintf( stderr, "arg \"%s\" Is beyond limit of %d method args\n", argv[i], MAX_METHOD_ARGS );
  147. }
  148. } else if ( ! strcmp( argv[i], "-e" ) ) {
  149. // enable a system, commit its args
  150. i++;
  151. if ( methodArgc > 0 ) {
  152. const char** marg = new const char*[methodArgc+1];
  153. for ( int j = 0; j < methodArgc; j++ ) {
  154. marg[j] = methodArgs[j];
  155. }
  156. marg[methodArgc] = NULL;
  157. systemList = VSConfig::newVSConfig( argv[i], marg, systemList );
  158. } else {
  159. systemList = VSConfig::newVSConfig( argv[i], NULL, systemList );
  160. }
  161. methodArgc = 0;
  162. } else if ( ! strcmp( argv[i], "--list" ) ) {
  163. VSFactory* cf;
  164. cf = VSFactory::root;
  165. while ( cf != NULL ) {
  166. printf("%s\n", cf->name );
  167. cf = cf->next;
  168. }
  169. exit(0);
  170. } else if ( ! strcmp( argv[i], "--vsteps" ) ) {
  171. i++;
  172. if ( stepq == NULL ) stepq = new Steps;
  173. stepq->parseV( argv[i] );
  174. } else if ( ! strcmp( argv[i], "--csteps" ) ) {
  175. i++;
  176. if ( stepq == NULL ) stepq = new Steps;
  177. stepq->parseC( argv[i] );
  178. } else if ( ! strcmp( argv[i], "--esteps" ) ) {
  179. i++;
  180. if ( stepq == NULL ) stepq = new Steps;
  181. stepq->parseE( argv[i] );
  182. } else if ( ! strcmp( argv[i], "--CSsteps" ) ) {
  183. i++;
  184. if ( stepq == NULL ) stepq = new Steps;
  185. stepq->parseCandidatesSeats( argv[i] );
  186. } else if ( (! strcmp( argv[i], "-n" )) && (stepq != NULL) ) {
  187. i++;j++;
  188. argv[j] = argv[i];
  189. stepq->n = atoi( argv[i] );
  190. j++;
  191. } else if ( ! strcmp( argv[i], "--threads" ) ) {
  192. i++;
  193. numThreads = atoi( argv[i] );
  194. } else if ( ! strcmp( argv[i], "--help" ) ) {
  195. fputs(voter_main_usage, stderr);
  196. exit(0);
  197. } else if ( ! strcmp( argv[i], "--hang" ) ) {
  198. hang = 1;
  199. } else {
  200. j++;
  201. }
  202. }
  203. argv[j] = argv[i];
  204. argc = j;
  205. free( methodArgs );
  206. methodArgs = NULL;
  207. nsys = 0;
  208. {
  209. VSConfig* curSys;
  210. int spos = 0;
  211. if ( systemList == NULL ) {
  212. systemList = VSConfig::defaultList();
  213. }
  214. systemList = systemList->reverseList();
  215. curSys = systemList;
  216. while ( curSys ) {
  217. curSys = curSys->next;
  218. nsys++;
  219. }
  220. systems = (VotingSystem**)malloc( sizeof(VotingSystem*) * nsys );
  221. assert(systems);
  222. curSys = systemList;
  223. while ( curSys ) {
  224. systems[spos] = curSys->getVS();
  225. spos++;
  226. curSys = curSys->next;
  227. }
  228. }
  229. votingSystemArrayToNameBlock( &nb, systems, nsys );
  230. #if !NO_DB
  231. if ( drfname != NULL ) {
  232. printf("opening result db \"%s\"...", drfname );
  233. if ( numThreads == 1 ) {
  234. drf = DBResultFile::open( drfname );
  235. } else {
  236. drf = ThreadSafeDBRF::open( drfname );
  237. }
  238. if ( drf ) {
  239. printf("success\n");
  240. } else {
  241. printf("failed\n");
  242. }
  243. }
  244. #endif
  245. if (drf == NULL) {
  246. #if 0
  247. fprintf(stderr, "error, no result output configured\n");
  248. exit(1);
  249. #endif
  250. } else {
  251. drf->useNames( &nb );
  252. }
  253. if (rlog != NULL) {
  254. printf("main useNames\n");
  255. bool ok = rlog->useNames( &nb );
  256. assert(ok);
  257. if (!ok) {
  258. exit(1);
  259. }
  260. }
  261. signal( SIGINT, mysigint );
  262. s = new VoterSim[numThreads];
  263. for ( int i = 0; i < numThreads; i++ ) {
  264. s[i].systems = systems;
  265. s[i].nsys = nsys;
  266. #if 0
  267. for ( int ai = 0; ai < argc; ai++ ) {
  268. printf("argv[%d] \"%s\"\n", ai, argv[ai] );
  269. }
  270. #endif
  271. int err = s[i].init( argc, argv );
  272. if (err < 0) {
  273. exit(1);
  274. }
  275. s[i].rlog = rlog;
  276. }
  277. if ( stepq == NULL ) {
  278. s[0].run( drf, nb );
  279. } else if ( numThreads == 1 ) {
  280. printf("running work set\n");
  281. s[0].runFromWorkQueue( drf, nb, stepq );
  282. printf("done\n");
  283. } else {
  284. WorkSource* q;
  285. printf("running %d threads...", numThreads);
  286. q = new ThreadSafeWorkSource( stepq );
  287. wqts = new workQThread*[numThreads];
  288. for ( int i = 0; i < numThreads; i++ ) {
  289. wqts[i] = new workQThread( s + i, drf, &nb, q );
  290. }
  291. printf("running\n");
  292. for ( int i = 0; i < numThreads; i++ ) {
  293. pthread_join( wqts[i]->thread, NULL );
  294. printf("thread %d done\n", i );
  295. }
  296. printf("all threads done\n");
  297. for ( int i = 0; i < numThreads; i++ ) {
  298. delete wqts[i];
  299. }
  300. delete [] wqts;
  301. delete q;
  302. }
  303. if ( hang ) {
  304. goGently = 0;
  305. while ( ! goGently ) {}
  306. }
  307. if ( drf ) {
  308. drf->flush();
  309. drf->close();
  310. }
  311. if (rlog != NULL) {
  312. for ( int i = 0; i < numThreads; ++i ) {
  313. s[i].rlog = NULL;
  314. }
  315. delete rlog;
  316. }
  317. delete [] s;
  318. if ( hang ) {
  319. goGently = 0;
  320. while ( ! goGently ) {}
  321. }
  322. #if 1
  323. fprintf(stderr, "%d Condorcet elections run, %d without cycle (%f%% have cycles)\n",
  324. Condorcet::electionsRun, Condorcet::simpleElections,
  325. 100.0 - ((Condorcet::simpleElections * 100.0) / Condorcet::electionsRun));
  326. #endif
  327. return 0;
  328. }