liquid_feedback_core
changeset 356:4698b68e0942
Calculation of ranks in "lf_update_suggestion_order"
author | jbe |
---|---|
date | Sun Mar 17 09:28:39 2013 +0100 (2013-03-17) |
parents | accffcefeff7 |
children | d420e7a5a75f |
files | lf_update_suggestion_order.c |
line diff
1.1 --- a/lf_update_suggestion_order.c Sat Mar 16 18:29:55 2013 +0100 1.2 +++ b/lf_update_suggestion_order.c Sun Mar 17 09:28:39 2013 +0100 1.3 @@ -31,6 +31,8 @@ 1.4 1.5 struct candidate { 1.6 char *key; 1.7 + double score_per_step; 1.8 + int reaches_score; 1.9 double score; 1.10 int seat; 1.11 }; 1.12 @@ -47,7 +49,6 @@ 1.13 struct candidate *candidate; 1.14 candidate = candidates + (candidate_count++); 1.15 candidate->key = *candidate_key; 1.16 - candidate->score = 0.0; 1.17 candidate->seat = 0; 1.18 } 1.19 } 1.20 @@ -58,7 +59,7 @@ 1.21 compare.key = candidate_key; 1.22 candidate = bsearch(&compare, candidates, candidate_count, sizeof(struct candidate), (void *)compare_candidate); 1.23 if (!candidate) { 1.24 - fprintf(stderr, "Candidate not found (should not happen)\n"); 1.25 + fprintf(stderr, "Candidate not found (should not happen).\n"); 1.26 abort(); 1.27 } 1.28 return candidate; 1.29 @@ -74,10 +75,77 @@ 1.30 struct ballot_section sections[4]; 1.31 }; 1.32 1.33 +static struct candidate *loser(int round_number, struct ballot *ballots, int ballot_count) { 1.34 + int i, j, k; 1.35 + int remaining; 1.36 + for (i=0; i<candidate_count; i++) { 1.37 + candidates[i].score = 0.0; 1.38 + } 1.39 + remaining = candidate_count - round_number; 1.40 + while (1) { 1.41 + double scale; 1.42 + if (remaining <= 1) break; 1.43 + for (i=0; i<candidate_count; i++) { 1.44 + candidates[i].score_per_step = 0.0; 1.45 + candidates[i].reaches_score = 0; 1.46 + } 1.47 + for (i=0; i<ballot_count; i++) { 1.48 + for (j=0; j<4; j++) { 1.49 + int matches = 0; 1.50 + for (k=0; k<ballots[i].sections[j].count; k++) { 1.51 + struct candidate *candidate; 1.52 + candidate = ballots[i].sections[j].candidates[k]; 1.53 + if (candidate->score < 1.0 && !candidate->seat) matches++; 1.54 + } 1.55 + if (matches) { 1.56 + double score_inc; 1.57 + score_inc = 1.0 / (double)matches; 1.58 + for (k=0; k<ballots[i].sections[j].count; k++) { 1.59 + struct candidate *candidate; 1.60 + candidate = ballots[i].sections[j].candidates[k]; 1.61 + if (candidate->score < 1.0 && !candidate->seat) { 1.62 + candidate->score_per_step += score_inc; 1.63 + } 1.64 + } 1.65 + break; 1.66 + } 1.67 + } 1.68 + } 1.69 + scale = (double)candidate_count; 1.70 + for (i=0; i<candidate_count; i++) { 1.71 + double max_scale; 1.72 + if (candidates[i].score_per_step > 0.0) { 1.73 + max_scale = (1.0-candidates[i].score) / candidates[i].score_per_step; 1.74 + if (max_scale <= scale) { 1.75 + scale = max_scale; 1.76 + candidates[i].reaches_score = 1; 1.77 + } 1.78 + } 1.79 + } 1.80 + for (i=0; i<candidate_count; i++) { 1.81 + if (candidates[i].score_per_step > 0.0) { 1.82 + if (candidates[i].reaches_score) { 1.83 + candidates[i].score = 1.0; 1.84 + remaining--; 1.85 + } else { 1.86 + candidates[i].score += scale * candidates[i].score_per_step; 1.87 + if (candidates[i].score >= 1.0) remaining--; 1.88 + } 1.89 + if (remaining <= 1) break; 1.90 + } 1.91 + } 1.92 + } 1.93 + for (i=candidate_count-1; i>=0; i--) { 1.94 + if (candidates[i].score < 1.0 && !candidates[i].seat) return candidates+i; 1.95 + } 1.96 + fprintf(stderr, "No remaining candidate (should not happen)."); 1.97 + abort(); 1.98 +} 1.99 + 1.100 static void process_initiative(PGresult *res) { 1.101 int ballot_count = 0; 1.102 + struct ballot *ballots; 1.103 int i; 1.104 - struct ballot *ballots; 1.105 { 1.106 void *candidate_tree = NULL; 1.107 int tuple_count; 1.108 @@ -94,7 +162,7 @@ 1.109 if (!candidate_tree || !tfind(suggestion_id, &candidate_tree, (void *)strcmp)) { 1.110 candidate_count++; 1.111 if (!tsearch(suggestion_id, &candidate_tree, (void *)strcmp)) { 1.112 - fprintf(stderr, "Insufficient memory\n"); 1.113 + fprintf(stderr, "Insufficient memory while inserting into candidate tree.\n"); 1.114 abort(); 1.115 } 1.116 } 1.117 @@ -107,7 +175,7 @@ 1.118 printf("Candidate count: %i\n", candidate_count); 1.119 candidates = malloc(candidate_count * sizeof(struct candidate)); 1.120 if (!candidates) { 1.121 - fprintf(stderr, "Insufficient memory\n"); 1.122 + fprintf(stderr, "Insufficient memory while creating candidate list.\n"); 1.123 abort(); 1.124 } 1.125 candidate_count = 0; 1.126 @@ -116,7 +184,7 @@ 1.127 printf("Ballot count: %i\n", ballot_count); 1.128 ballots = calloc(ballot_count, sizeof(struct ballot)); 1.129 if (!ballots) { 1.130 - fprintf(stderr, "Insufficient memory\n"); 1.131 + fprintf(stderr, "Insufficient memory while creating ballot list.\n"); 1.132 abort(); 1.133 } 1.134 ballot = ballots; 1.135 @@ -127,12 +195,12 @@ 1.136 suggestion_id = PQgetvalue(res, i, COL_SUGGESTION_ID); 1.137 weight = (int)strtol(PQgetvalue(res, i, COL_WEIGHT), (char **)NULL, 10); 1.138 if (weight <= 0) { 1.139 - fprintf(stderr, "Unexpected weight value\n"); 1.140 + fprintf(stderr, "Unexpected weight value.\n"); 1.141 abort(); 1.142 } 1.143 preference = (int)strtol(PQgetvalue(res, i, COL_PREFERENCE), (char **)NULL, 10); 1.144 if (preference < 1 || preference > 4) { 1.145 - fprintf(stderr, "Unexpected preference value\n"); 1.146 + fprintf(stderr, "Unexpected preference value.\n"); 1.147 abort(); 1.148 } 1.149 preference--; 1.150 @@ -147,7 +215,7 @@ 1.151 if (ballots[i].sections[j].count) { 1.152 ballots[i].sections[j].candidates = malloc(ballots[i].sections[j].count * sizeof(struct candidate *)); 1.153 if (!ballots[i].sections[j].candidates) { 1.154 - fprintf(stderr, "Insufficient memory\n"); 1.155 + fprintf(stderr, "Insufficient memory while creating ballot section.\n"); 1.156 abort(); 1.157 } 1.158 } 1.159 @@ -161,10 +229,6 @@ 1.160 member_id = PQgetvalue(res, i, COL_MEMBER_ID); 1.161 suggestion_id = PQgetvalue(res, i, COL_SUGGESTION_ID); 1.162 preference = (int)strtol(PQgetvalue(res, i, COL_PREFERENCE), (char **)NULL, 10); 1.163 - if (preference < 1 || preference > 4) { 1.164 - fprintf(stderr, "Unexpected preference value\n"); 1.165 - abort(); 1.166 - } 1.167 preference--; 1.168 ballot->sections[preference].candidates[candidates_in_sections[preference]++] = candidate_by_key(suggestion_id); 1.169 } 1.170 @@ -179,6 +243,11 @@ 1.171 } 1.172 } 1.173 1.174 + for (i=0; i<candidate_count; i++) { 1.175 + struct candidate *candidate = loser(i, ballots, ballot_count); 1.176 + candidate->seat = candidate_count - i; 1.177 + } 1.178 + 1.179 free(candidates); 1.180 for (i=0; i<ballot_count; i++) { 1.181 int j; 1.182 @@ -273,6 +342,10 @@ 1.183 fprintf(stderr, "Error while executing SQL command selecting open issues:\n%s", PQresultErrorMessage(res)); 1.184 err = 1; 1.185 PQclear(res2); 1.186 + } else if (PQnfields(res2) < 4) { 1.187 + fprintf(stderr, "Too few columns returned by SQL command selecting open issues.\n"); 1.188 + err = 1; 1.189 + PQclear(res2); 1.190 } else { 1.191 if (PQntuples(res2) == 0) { 1.192 printf("Nothing to do.\n");