-
Notifications
You must be signed in to change notification settings - Fork 0
/
banzdemo.d
816 lines (709 loc) · 19.4 KB
/
banzdemo.d
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
// banzdemo.d
/*
Ported from banzdemo in pascal from Byte Magazine, March 1983.
writeln(' BANZHAF INDEX DEMONSTRATION PROGRAM');
writeln(' (c) 1983, Philip A. Schrodt');
*/
@safe
import std.random : unpredictableSeed ;
// ============================================================
// Consts and Vars
enum EXIT_NOERROR = 0;
enum EXIT_BADFORMATHEADER = 1;
enum EXIT_BADFORMATVOTES = 2;
enum EXIT_UNKNOWNFORMAT = 3;
enum EXIT_NOPIVOTS = 4;
enum EXIT_BADARGS = 5;
enum EXIT_INCONSISTENTDATA = 6;
// The source uses pascal arrays counting from 1, I have lots of
// memory, just add one to the top end so I can pretend it is one
// indexeed
// Original wa 200
enum MAXVOTES = 200 + 1;
// Original was 10
// This stsrts from 0 to MAXIDLINES - 1.
enum MAXIDLINES = 50 ;
alias FloatT = double;
/// Pseudo Random Generator config
/// uint is always 32 bits
alias PrngOutputType = uint ;
PrngOutputType seed = 0;
int[MAXVOTES] Votes = 0;;
int[MAXVOTES] NumPivots = 0;
string[MAXVOTES] PartyNames;
string[MAXIDLINES] IdHeader;
/++
CoalitionMember is treated as an unsigned integer with a width of
(NumParties + 1) bits, a true bit means the coresponding party is in
the coalition. The extra bit ia the carry bit, if it is true you are
past the valid range. In theory, it might be faser to pack it into
bits instead of the byte default to reduce cache pressure..
+/
bool[MAXVOTES+1] CoalitionMember = false;
// Should initialize to NaN
FloatT[MAXVOTES] BanzIndex;
/// number of coalitions evaluated, running number of experiments
/// Used for status output, when I readd it.
int ncex;
/// total pivots,
int totpivots;
/// number of header lines,
int nid;
/// Number of Parties,
int np;
/// Cache of Number of Parties + 1
int npp1 ;
/// votes required for mwc (Minimum Winning Coalition)
int mwcvote ;
/// total votes = sum(Votes)
int totalVotes;
/// iindicates we are in the unanimity special case
/// where we can shortcut the calculations
bool unanimityFlag = false;
/// Number of Experiments: number of Monte Carlo runs..
/// 2 ** 20
int nex =1_048_576;
// Assorted counters, might be removeable.
// int kz, ka, kb;
/// Error message to accompany error returns.
string errString;
// ============================================================
// flags to be set from command line
enum InputFormat : int {
// the format used in the original byte article with header and
// colon separator
bytemag,
// single tab delimited, first 2 couloms are columns are assumed
// party and votes, remainder of columns ignored. Optional cilumn
// headers.
tab,
// CSV, first 2 columns are assumed to be party and votes.
// Optional column headers.
csv,
};
InputFormat inputFormatExpected;
// If true, skip the first line in formates that can have a column
// header.
bool expectInputColumnHeader;
// Proportion of voltes you must have to win a wote. Implementation so
// far is kinda iffy.
uint mwcProportionNumerator = 0;
uint mwcProportionDenominator = 0;
enum ProcessingType {
montecarlo,
all,
}
ProcessingType howToProcess ;
enum OutputHeaderGenerated {
none,
columns,
all
}
OutputHeaderGenerated shouldOutputHeader;
// ============================================================
// First atempt at a static debug printet that will compile out to
// nothing
// if Static venbosty == 0, no level >= 0 should log
// if stati verbosity is 1,
// level should aleays be [0,+inf]
// if SV is 0, then print nothing
enum StaticVerbosity = 0;
@trusted void debugPrint(int level = 1, string prefix = "", bool eoln = false)(string datum){
import std.stdio;
static if (StaticVerbosity >= level) {
stderr.write(prefix,datum);
static if (eoln) {
stderr.writeln();
}
}
}
/++
A port of the c-mersennetwister.c rng at
https://github.com/bmurray7/mersenne-twister-examples/ . I've wrapped
its state in a struct and moved all the support into the struct as
well.
+/
struct MersenneTwisterGeneratorU32 {
// #include <stdint.h>
alias uint32_t = uint;
alias uint16_t = ushort;
/// Define MT19937 constants (32-bit RNG)
enum
{
// Assumes W = 32 (omitting this)
N = 624,
M = 397,
R = 31,
A = 0x9908B0DF,
F = 1812433253,
U = 11,
// Assumes D = 0xFFFFFFFF (omitting this)
S = 7,
B = 0x9D2C5680,
T = 15,
C = 0xEFC60000,
L = 18,
MASK_LOWER = (1UL << R) - 1,
MASK_UPPER = (1UL << R)
};
///
uint32_t[N] mt;
///
uint16_t index;
/// Re-init with a given seed
void initialize(const uint32_t seed) @nogc nothrow @safe
{
uint32_t i;
mt[0] = seed;
for ( i = 1; i < N; i++ )
{
mt[i] = (F * (mt[i - 1] ^ (mt[i - 1] >> 30)) + i);
}
index = N;
}
/// Interal function to mix the data.
void twist() @nogc nothrow @safe
{
uint32_t i, x, xA;
for ( i = 0; i < N; i++ )
{
x = (mt[i] & MASK_UPPER) + (mt[(i + 1) % N] & MASK_LOWER);
xA = x >> 1;
if ( x & 0x1 )
xA ^= A;
mt[i] = mt[(i + M) % N] ^ xA;
}
index = 0;
}
/// Obtain a 32-bit random number
uint32_t extractU32() @nogc nothrow @safe
{
uint32_t y;
int i = index;
if ( index >= N )
{
twist();
i = index;
}
y = mt[i];
index = cast(uint16_t)(i + 1);
y ^= (y >> U);
y ^= (y << S) & B;
y ^= (y << T) & C;
y ^= (y >> L);
return y;
}
}
PrngOutputType randomGen() @nogc nothrow @safe {
return monteCarloGen.extractU32();
}
MersenneTwisterGeneratorU32 monteCarloGen;
// ============================================================
// Procedures
//
int setFromCommandFlags(ref string[] args) @safe {
import std.getopt;
// banzdemo --process=all --mwc=51 --informat=bytemag --header=all < votes.txt > results.txt
// --process=montecarlo --process=all
// --mwc=567
// --informat=bytemag --informat=tab --informat=csv
// --header==all --header=none --header=column
// --nex=1224 - Number of expoerments run. if monto caro this is a request.
// --mecp=1/5
// --seed=653567864543
// --mwcfrac=1/2
mwcvote = -1;
// nex = 1_048_576;
shouldOutputHeader = OutputHeaderGenerated.all;
howToProcess = ProcessingType.all;
inputFormatExpected = InputFormat.bytemag;
// FIXME would it make sense to optionally use a percentage for mwc?
// should default to 1/2
mwcProportionNumerator = 0;
mwcProportionDenominator = 0;
GetoptResult aparse;
try {
aparse = getopt(args,
config.required,
"mwc" , &mwcvote,
config.passThrough,
"process", &howToProcess,
);
} catch (GetOptException ex) {
errString = "--mwc required";
return EXIT_BADARGS;
}
aparse = getopt(args,
config.passThrough,
"header", &shouldOutputHeader,
"informat", &inputFormatExpected,
"nex", &nex,
"seed", &seed,
);
return EXIT_NOERROR;
}
/++
Early initialization. Can throw and be @gc.
+/
void init() @safe {
// Might make sense to move all this to massage()?
ncex = 0;
final switch (howToProcess) {
case ProcessingType.all:
break;
case ProcessingType.montecarlo:
if (seed == 0) {
// FIXME need to find non Phobos seeding source
monteCarloGen.initialize(unpredictableSeed());
} else {
monteCarloGen.initialize(seed);
}
break;
}
}
/++
Read the data from stdin. Changes process based in --informat swittch
expressed in the inputFormatExpected var. Error handling on bad
format is either Exit Code, or crash with an assertion failure.
+/
@safe int readdata() {
@trusted int readbytedata() {
import std.stdio;
import std.string;
import std.conv;
// for now we are going to do the format he used in the BYTE
// article 1 to MAXIDLINES lines of header, followed by a
// blank line followed by name:votes pairs one per line
// spearated by a colon, followef by the end of the file or a
// blank line later this should have the option of a tab
// delimited file in >= 2 columns without the useful
// descriptoive header
//
nid = 0;
bool scanningHeader = true;
debugPrint!(2,"Start of Header Parse",true)("");
while (scanningHeader) {
string rawLine = readln();
size_t len = rawLine.length;
if (len == 0) {
// early end of file, incorrect file
errString = "Early end of file in header. Incorrect file?";
return (EXIT_BADFORMATHEADER);
} else if (len == 1) {
// end of the header
scanningHeader = false;
} else {
if (nid == MAXIDLINES) {
errString = "Header too large.";
return (EXIT_BADFORMATHEADER);
}
IdHeader[nid] = rawLine[0..$-1];
debugPrint!(2,"==>",true)(IdHeader[nid]);
nid = nid + 1;
}
}
debugPrint!(2,"End of Header Parse",true)("");
np = 0 ;
bool scanningBody = true;
while (scanningBody) {
string rawLine = readln();
size_t len = rawLine.length;
if ((len == 0) || (len == 1)) {
// Correct End is either EOF or empty line
scanningBody = false;
} else {
// should check for overflow here
debugPrint!(2,"==>", false)(rawLine);
size_t sepIndex = rawLine.indexOf(':');
if (sepIndex == -1) {
// No seperator, line oif ill formed.
errString = "Separator (:) missing in votes.";
return EXIT_BADFORMATVOTES;
} else {
string partyName = rawLine[0..sepIndex];
string partyVotes = rawLine[sepIndex+1..$-1];
debugPrint!(2,"N==>", true)(partyName);
debugPrint!(2,"V==>", true)(partyVotes);
PartyNames[np + 1] = strip(partyName);
Votes[np + 1] = to!int(strip(partyVotes));
}
np = np + 1;
}
}
debugPrint!(2,"End of Body Parse, count ",true)(to!string(np));
return EXIT_NOERROR;
}
@trusted int readtabdelimited() {
import std.stdio;
import std.string;
import std.conv;
import std.regex;
bool finished = false;
uint currIndex = 0;
auto splitPattern = regex(r"\t|\n");
while(!finished) {
string rawLine = readln();
// has newline at end
size_t len = rawLine.length;
if ((len == 0) || (len == 1)) {
// Correct End is either EOF or empty line
finished = true;
} else {
currIndex = currIndex + 1;
string[] fields = split(rawLine,splitPattern);
if(fields.length < 2) {
errString = "Fewer than 2 fields in record in tab delimited file.";
return EXIT_BADFORMATVOTES;
}
PartyNames[currIndex] = strip(fields[0]);
Votes[currIndex] = to!int(strip(fields[1]));
}
}
np = currIndex;
return EXIT_NOERROR;
}
@trusted int readcsv() {
import std.csv;
assert(0,"CSV Parser Not Yet Written.");
return EXIT_NOERROR;
}
final switch(inputFormatExpected) {
case InputFormat.bytemag:
return readbytedata();
break;
case InputFormat.tab:
return readtabdelimited();
break;
case InputFormat.csv:
return readcsv();
break;
}
}
/**
Copy of the sort from the Pascal original. Claimed to be a bubblesort.
Not really a bubblesort though I think it has the same time
complexity.
*/
@nogc nothrow @safe int sortdata_orig() {
int tmpi;
string tmps;
int ka, kb;
for(ka = 1; ka <= (np - 1); ka++) {
for(kb = ka; kb <= np ; kb++) {
// Ordering contraint (Votes[ka] >= Votes[kb] for ka < kb
if (Votes[kb] > Votes[ka]) {
tmps = PartyNames[ka];
PartyNames[ka] = PartyNames[kb];
PartyNames[kb] = tmps;
tmpi = Votes[ka];
Votes[ka] = Votes[kb];
Votes[kb] = tmpi;
}
}
}
return EXIT_NOERROR;
}
// =================================================================
// Sorting
// used in th swap function. in global for improved locality.
// string tmps;
// int tmpi;
//@safe @nogc void myswap(int ka, int kb) nothrow {
// // could replace with system swap? FIXME check.
// tmps = PartyNames[ka];
// PartyNames[ka] = PartyNames[kb];
// PartyNames[kb] = tmps;
// tmpi = Votes[ka];
// Votes[ka] = Votes[kb];
// Votes[kb] = tmpi;
//}
//@safe @nogc bool mylessthan(int ka, int kb) nothrow {
// return Votes[ka] > Votes[kb];
//}
//@safe @nogc int sortdata() {
// import ceres.sorting ;
// uint swaps = bubbleSortFn!(int, myswap,mylessthan)(1, np);
// return EXIT_NOERROR;
//}
//====================================================================
/++
Calculates values from the read data that need only be done
once. Data consistency checking should go here.
+/
int massage() @nogc nothrow @safe {
// No longer needed, initialization are now on the declaration.
// for(int ka = 1; ka < MAXVOTES; ka ++ ) { NumPivots[ka] = 0; }
totalVotes = 0;
for(int ka = 1; ka <= np; ka++){
totalVotes = totalVotes + Votes[ka];
}
// FIXME shoud we check the individual viotes for z/positivity
// here or in readdata?
if(totalVotes <= 0) {
errString = "totalVotes <= 0, probably bad data.";
return EXIT_INCONSISTENTDATA;
}
npp1 = np + 1;
if (false) {
//if (mwcvote < 1) {
// if it is less than one, it is impossible, then it needs to be
// calculated from proportions. in 1 or more, we assume it is good.
// Probably should be checked to ensure that it is in [1,np]
// for now, just crash with a meaningful error message.
assert(0, "mwc proportion calculation unimplemented.");
assert(mwcProportionNumerator > 0);
assert(mwcProportionDenominator > 0);
uint votesToPass = (totalVotes * mwcProportionNumerator) / mwcProportionDenominator;
uint remainderToPass = (totalVotes * mwcProportionNumerator) % mwcProportionDenominator;
// FIXME probably not right
mwcvote = votesToPass + 1;
}
if(mwcvote < 0){
errString = "mwc votes is less than 1.";
return EXIT_INCONSISTENTDATA;
}
if(mwcvote > totalVotes){
errString = "mwc votes > total votes.";
return EXIT_INCONSISTENTDATA;
}
if(mwcvote == totalVotes) {
// special case, we can shortcut the calculation and save a lot of time.
unanimityFlag = true;
}
sortdata_orig();
return EXIT_NOERROR;
}
/++
For the current configuation of CoalitionMember, count all the pivotal
votes in NumPivots[]..
+/
@nogc nothrow @safe void countpivots() {
//var totvot , ka:integer;
//begin
// totvot:=O;
// for ka := 1 to np do
// if mem[ka] then totvot := totvot+votes[ka];
// if totvot >= mwcvote then begin
// for ka :=1 to np do
// if mem[ka] then
// if (totvot - votes[ka]) < mwcvote then
// numpivots[ka]:= numpivots[ka]+1
// else
// ka := np; (*note: this shortcut assumes sorted votes...*)
// end;
//end;
/// Total votes th the current coalition
int coalitionVotes ;
int ka ;
coalitionVotes = 0;
for(ka = 1; ka <= np; ka++ ) {
if (CoalitionMember[ka]) {
coalitionVotes = coalitionVotes + Votes[ka];
}
}
if(coalitionVotes >= mwcvote) {
for(ka = 1; ka <= np; ka ++) {
if(CoalitionMember[ka]) {
if((coalitionVotes - Votes[ka]) < mwcvote) {
NumPivots[ka]++;
} else {
/+
We skip to the next coalition when the number of
party votes gets small enough that changing
their votes doesn't matter. Since sorted
descending, all the later ones are equal in
size or smaller, so are in the same position.
Done like this probably because Pascal has
none of return, continue, or break.
+/
// ka = np;
return;
}
}
}
}
}
/**
this increments the CoalitionMember array to get the next coalition.
Cycles through all coalitions by treating CoalitionMember as though
it were a sequence of binary numbers [1, 2^np] "allcoal" in effect
does a binary add of "1" to "CoalitionMember".
*/
@nogc nothrow @safe void allcoal() {
int bitNum = 1;
CoalitionMember[bitNum] = !(CoalitionMember[bitNum]);
while( !(CoalitionMember[bitNum]) ) {
bitNum ++;
CoalitionMember[bitNum] = !(CoalitionMember[bitNum]);
}
}
/**
Taken from the original Pascal program, this is essentially
counting up with the binary number represented by the bit
array CoalitionMember. You could probably do it with an array
of unsigned, at some complexity cost. CoalitionMember[np+1] is
the "carry" bit and it being set is the sign that you have
reached the end.
*/
void exhaust() @nogc nothrow @safe
{
/* void dump(){
import std.stdio;
writeln(CoalitionMember[1..npp1 + 2]);
}
*/
int ka;
ncex = 0;
// decl init should have sone this.
/*for (ka = 1; ka <= npp1; ka ++) {
CoalitionMember[ka] = false;
}*/
do {
ncex++;
//dump();
allcoal();
countpivots();
} while (!(CoalitionMember[npp1]));
}
/**
Set CoalitionMember to a randomly generated coalition.
*/
void randcoal() @safe @nogc nothrow {
size_t ka;
PrngOutputType pMembership = randomGen();
for(ka = 1; ka <= np; ka ++){
CoalitionMember[ka] = randomGen() < pMembership ;
}
}
/**
nex times, pick a random coalition ads count the pivots.
*/
void randcomp() @nogc nothrow @safe {
int ka;
// Validate nex here , should be set from switches
assert(nex > 0, "Number of experiments (--nex) should be > 0.");
for (ka = 1; ka <= nex; ka ++){
randcoal();
countpivots();
ncex++;
// FIXME this is in original code, should it be outside the
// loop?
// ncex = nex;
}
}
/++
Handle the special case where in the case of unanimity is required,
(mwcvotes == totalVotes) there is only one case that will generate
pivots. Set that up, count the pivots and we are done.
+/
void unanimousVote() @nogc nothrow @safe {
CoalitionMember = true;
CoalitionMember[npp1] = false;
countpivots();
ncex++;
}
/**
After the main processing, sum the core results before printing.
*/
@nogc nothrow @safe int banzcomp() {
int ka;
totpivots = 0;
for (ka = 1; ka <= np; ka ++) {
totpivots = totpivots + NumPivots[ka];
}
if (totpivots == 0) {
// Avoids an upcoming divide by zero
errString = "Total pivot count is 0, cannot proceed.";
return EXIT_NOPIVOTS;
}
for (ka = 1; ka <= np; ka ++) {
BanzIndex[ka] = (cast(FloatT)NumPivots[ka]) / (cast(FloatT)totpivots);
}
return EXIT_NOERROR;
}
/**
The output is a tab delimited file, with eoln being \n. Columns are
party name, voltes, banzhaf index, etc. Not the approach from the
source as we are trying to make it Unix tools friendly.
*/
@trusted void banzprint() {
import std.stdio;
import std.conv;
int ka, kb;
if (shouldOutputHeader == OutputHeaderGenerated.all) {
debugPrint!(1, "Header line count: \t", true)(to!string(nid));
for (ka = 0; ka < nid; ka++) {
writeln(IdHeader[ka]);
}
static if (StaticVerbosity >= 1) {
writeln("mwcvote\t",mwcvote);
writeln("totalVotes\t",totalVotes);
writeln("nex\t",nex);
writeln("ncex\t",ncex);
writeln("totpivots\t",totpivots);
}
writeln();
}
debugPrint!(1, "Body line count: \t", true)(to!string(np));
if (shouldOutputHeader == OutputHeaderGenerated.columns || shouldOutputHeader == OutputHeaderGenerated.all) {
write("PartyName\tVotes\tVoteProp\t");
writeln("NumPivots\tBanzIndex\tBI-VP\tBI/VP");
}
for (ka = 1; ka <= np; ka ++) {
FloatT voteProp = (Votes[ka] / cast(FloatT)totalVotes);
write(PartyNames[ka], "\t", Votes[ka], "\t", voteProp, "\t");
write( NumPivots[ka], "\t", BanzIndex[ka], "\t", (BanzIndex[ka] - voteProp), "\t", (BanzIndex[ka] / voteProp),"\n");
}
}
/// del function to check data tyoes
@trusted void dumpTechData() {
import std.stdio : writeln , stderr ;
stderr.writeln("", typeof(CoalitionMember).sizeof);
}
/// del function to check data tyoes
@trusted void dumpError() {
import std.stdio : writeln , stderr ;
stderr.writeln("Error: ", errString);
}
/**
Main:
*/
@safe int main(string[] args) {
//dumpTechData();
int err = 0;
err = setFromCommandFlags(args);
if (err != EXIT_NOERROR) {
dumpError();
return err;
}
init();
err = readdata();
if (err != EXIT_NOERROR) {
dumpError();
return err;
}
err = massage();
if (err != EXIT_NOERROR) {
dumpError();
return err;
}
if(unanimityFlag) {
unanimousVote();
} else {
final switch (howToProcess) {
case ProcessingType.montecarlo:
randcomp();
break;
case ProcessingType.all:
exhaust();
break;
}
}
err = banzcomp();
if (err != EXIT_NOERROR) {
dumpError();
return err;
}
banzprint();
return EXIT_NOERROR;
}