liquid_feedback_core
diff core.sql @ 304:e403f47525ce
Removed broken tie-breaking implementation
author | jbe |
---|---|
date | Sun Sep 30 12:59:07 2012 +0200 (2012-09-30) |
parents | 585c1cf4a3c9 |
children | 847d59f94ceb |
line diff
1.1 --- a/core.sql Sun Sep 30 00:56:01 2012 +0200 1.2 +++ b/core.sql Sun Sep 30 12:59:07 2012 +0200 1.3 @@ -7,7 +7,7 @@ 1.4 BEGIN; 1.5 1.6 CREATE VIEW "liquid_feedback_version" AS 1.7 - SELECT * FROM (VALUES ('2.2.0', 2, 2, 0)) 1.8 + SELECT * FROM (VALUES ('2.1.0', 2, 1, 0)) 1.9 AS "subquery"("string", "major", "minor", "revision"); 1.10 1.11 1.12 @@ -329,11 +329,6 @@ 1.13 COMMENT ON COLUMN "session"."lang" IS 'Language code of the selected language'; 1.14 1.15 1.16 -CREATE TYPE "schulze_variant" AS ENUM ('absolute_strength', 'tuple_strength', 'partial_tie_breaking', 'tie_breaking_with_negative_strength'); 1.17 - 1.18 -COMMENT ON TYPE "schulze_variant" IS 'Variant of schulze method, which differ by complexity; greater values have a higher complexity'; 1.19 - 1.20 - 1.21 CREATE TABLE "policy" ( 1.22 "id" SERIAL4 PRIMARY KEY, 1.23 "index" INT4 NOT NULL, 1.24 @@ -361,7 +356,6 @@ 1.25 "indirect_majority_non_negative" INT4 NOT NULL DEFAULT 0, 1.26 "no_reverse_beat_path" BOOLEAN NOT NULL DEFAULT TRUE, 1.27 "no_multistage_majority" BOOLEAN NOT NULL DEFAULT FALSE, 1.28 - "schulze_variant" "schulze_variant" NOT NULL DEFAULT 'tie_breaking_with_negative_strength', 1.29 CONSTRAINT "timing" CHECK ( 1.30 ( "polling" = FALSE AND 1.31 "admission_time" NOTNULL AND "discussion_time" NOTNULL AND 1.32 @@ -677,13 +671,13 @@ 1.33 COMMENT ON COLUMN "initiative"."negative_votes" IS 'Calculated from table "direct_voter"'; 1.34 COMMENT ON COLUMN "initiative"."direct_majority" IS 'TRUE, if "positive_votes"/("positive_votes"+"negative_votes") is strictly greater or greater-equal than "direct_majority_num"/"direct_majority_den", and "positive_votes" is greater-equal than "direct_majority_positive", and ("positive_votes"+abstentions) is greater-equal than "direct_majority_non_negative"'; 1.35 COMMENT ON COLUMN "initiative"."indirect_majority" IS 'Same as "direct_majority", but also considering indirect beat paths'; 1.36 -COMMENT ON COLUMN "initiative"."schulze_rank" IS 'Schulze-Ranking'; 1.37 -COMMENT ON COLUMN "initiative"."better_than_status_quo" IS 'TRUE, if initiative has a schulze-ranking better than the status quo'; 1.38 -COMMENT ON COLUMN "initiative"."worse_than_status_quo" IS 'TRUE, if initiative has a schulze-ranking worse than the status quo'; 1.39 +COMMENT ON COLUMN "initiative"."schulze_rank" IS 'Schulze-Ranking without tie-breaking'; 1.40 +COMMENT ON COLUMN "initiative"."better_than_status_quo" IS 'TRUE, if initiative has a schulze-ranking better than the status quo (without tie-breaking)'; 1.41 +COMMENT ON COLUMN "initiative"."worse_than_status_quo" IS 'TRUE, if initiative has a schulze-ranking worse than the status quo (without tie-breaking)'; 1.42 COMMENT ON COLUMN "initiative"."reverse_beat_path" IS 'TRUE, if there is a beat path (may include ties) from this initiative to the status quo'; 1.43 COMMENT ON COLUMN "initiative"."multistage_majority" IS 'TRUE, if either (a) this initiative has no better rank than the status quo, or (b) there exists a better ranked initiative X, which directly beats this initiative, and either more voters prefer X to this initiative than voters preferring X to the status quo or less voters prefer this initiative to X than voters preferring the status quo to X'; 1.44 COMMENT ON COLUMN "initiative"."eligible" IS 'Initiative has a "direct_majority" and an "indirect_majority", is "better_than_status_quo" and depending on selected policy the initiative has no "reverse_beat_path" or "multistage_majority"'; 1.45 -COMMENT ON COLUMN "initiative"."winner" IS 'Winner is the "eligible" initiative with best "schulze_rank" and in case of unresolved ties with lowest "id"'; 1.46 +COMMENT ON COLUMN "initiative"."winner" IS 'Winner is the "eligible" initiative with best "schulze_rank" and in case of ties with lowest "id"'; 1.47 COMMENT ON COLUMN "initiative"."rank" IS 'Unique ranking for all "admitted" initiatives per issue; lower rank is better; a winner always has rank 1, but rank 1 does not imply that an initiative is winner; initiatives with "direct_majority" AND "indirect_majority" always have a better (lower) rank than other initiatives'; 1.48 1.49 1.50 @@ -3854,47 +3848,22 @@ 1.51 IS 'Closes the voting on an issue, and calculates positive and negative votes for each initiative; The ranking is not calculated yet, to keep the (locking) transaction short.'; 1.52 1.53 1.54 -CREATE FUNCTION "impossible_defeat_strength"() 1.55 - RETURNS INT8 1.56 - LANGUAGE 'plpgsql' IMMUTABLE AS $$ 1.57 - BEGIN 1.58 - RETURN -1::INT8 << 63; 1.59 - END; 1.60 - $$; 1.61 - 1.62 -COMMENT ON FUNCTION "impossible_defeat_strength"() IS 'An INT8 value lower than any other value returned by function "defeat_strength"(INT4, INT4)'; 1.63 - 1.64 - 1.65 CREATE FUNCTION "defeat_strength" 1.66 - ( "schulze_variant_p" "schulze_variant", 1.67 - "positive_votes_p" INT4, 1.68 - "negative_votes_p" INT4 ) 1.69 + ( "positive_votes_p" INT4, "negative_votes_p" INT4 ) 1.70 RETURNS INT8 1.71 LANGUAGE 'plpgsql' IMMUTABLE AS $$ 1.72 BEGIN 1.73 - IF "schulze_variant_p" >= 'tuple_strength'::"schulze_variant" THEN 1.74 - IF "positive_votes_p" > "negative_votes_p" THEN 1.75 - RETURN ("positive_votes_p"::INT8 << 31) - "negative_votes_p"::INT8; 1.76 - ELSIF "positive_votes_p" = "negative_votes_p" THEN 1.77 - RETURN 0::INT8; 1.78 - ELSE 1.79 - IF "schulze_variant_p" >= 'tie_breaking_with_negative_strength'::"schulze_variant" THEN 1.80 - RETURN "positive_votes_p"::INT8 - ("negative_votes_p"::INT8 << 31); 1.81 - ELSE 1.82 - RETURN "impossible_defeat_strength"(); 1.83 - END IF; 1.84 - END IF; 1.85 + IF "positive_votes_p" > "negative_votes_p" THEN 1.86 + RETURN ("positive_votes_p"::INT8 << 31) - "negative_votes_p"::INT8; 1.87 + ELSIF "positive_votes_p" = "negative_votes_p" THEN 1.88 + RETURN 0; 1.89 ELSE 1.90 - IF "positive_votes_p" > "negative_votes_p" THEN 1.91 - RETURN "positive_votes_p"::INT8; 1.92 - ELSE 1.93 - RETURN 0::INT8; 1.94 - END IF; 1.95 + RETURN -1; 1.96 END IF; 1.97 END; 1.98 $$; 1.99 1.100 -COMMENT ON FUNCTION "defeat_strength"("schulze_variant", INT4, INT4) IS 'Calculates defeat strength (INT8!) of a pairwise defeat primarily by the absolute number of votes for the winner and secondarily by the absolute number of votes for the loser. A tie has a strength of zero.'; 1.101 +COMMENT ON FUNCTION "defeat_strength"(INT4, INT4) IS 'Calculates defeat strength (INT8!) of a pairwise defeat primarily by the absolute number of votes for the winner and secondarily by the absolute number of votes for the loser'; 1.102 1.103 1.104 CREATE FUNCTION "calculate_ranks"("issue_id_p" "issue"."id"%TYPE) 1.105 @@ -3904,17 +3873,11 @@ 1.106 "issue_row" "issue"%ROWTYPE; 1.107 "policy_row" "policy"%ROWTYPE; 1.108 "dimension_v" INTEGER; 1.109 - "vote_matrix" INT4[][]; -- absolute votes 1.110 - "direct_matrix" INT8[][]; -- direct defeat strength 1.111 - "path_matrix" INT8[][]; -- defeat strength of best path 1.112 - "compare_matrix" BOOLEAN[][]; -- binary relation to create schulze-rank 1.113 - "forbidden_matrix" BOOLEAN[][]; -- forbidden links for tie-breaking 1.114 - "modified_matrix" INT8[][]; -- defeat strength after tie-breaking 1.115 + "vote_matrix" INT4[][]; -- absolute votes 1.116 + "matrix" INT8[][]; -- defeat strength / best paths 1.117 "i" INTEGER; 1.118 "j" INTEGER; 1.119 "k" INTEGER; 1.120 - "m" INTEGER; 1.121 - "n" INTEGER; 1.122 "battle_row" "battle"%ROWTYPE; 1.123 "rank_ary" INT4[]; 1.124 "rank_v" INT4; 1.125 @@ -3954,16 +3917,15 @@ 1.126 IF "i" != "dimension_v" OR "j" != "dimension_v" + 1 THEN 1.127 RAISE EXCEPTION 'Wrong battle count (should not happen)'; 1.128 END IF; 1.129 - -- Store defeat strengths in "path_matrix" using "defeat_strength" 1.130 + -- Store defeat strengths in "matrix" using "defeat_strength" 1.131 -- function: 1.132 - "direct_matrix" := array_fill(NULL::INT8, ARRAY["dimension_v", "dimension_v"]); 1.133 + "matrix" := array_fill(NULL::INT8, ARRAY["dimension_v", "dimension_v"]); 1.134 "i" := 1; 1.135 LOOP 1.136 "j" := 1; 1.137 LOOP 1.138 IF "i" != "j" THEN 1.139 - "direct_matrix"["i"]["j"] := "defeat_strength"( 1.140 - "policy_row"."schulze_variant", 1.141 + "matrix"["i"]["j"] := "defeat_strength"( 1.142 "vote_matrix"["i"]["j"], 1.143 "vote_matrix"["j"]["i"] 1.144 ); 1.145 @@ -3975,7 +3937,6 @@ 1.146 "i" := "i" + 1; 1.147 END LOOP; 1.148 -- Find best paths: 1.149 - "path_matrix" := "direct_matrix"; 1.150 "i" := 1; 1.151 LOOP 1.152 "j" := 1; 1.153 @@ -3984,13 +3945,13 @@ 1.154 "k" := 1; 1.155 LOOP 1.156 IF "i" != "k" AND "j" != "k" THEN 1.157 - IF "path_matrix"["j"]["i"] < "path_matrix"["i"]["k"] THEN 1.158 - IF "path_matrix"["j"]["i"] > "path_matrix"["j"]["k"] THEN 1.159 - "path_matrix"["j"]["k"] := "path_matrix"["j"]["i"]; 1.160 + IF "matrix"["j"]["i"] < "matrix"["i"]["k"] THEN 1.161 + IF "matrix"["j"]["i"] > "matrix"["j"]["k"] THEN 1.162 + "matrix"["j"]["k"] := "matrix"["j"]["i"]; 1.163 END IF; 1.164 ELSE 1.165 - IF "path_matrix"["i"]["k"] > "path_matrix"["j"]["k"] THEN 1.166 - "path_matrix"["j"]["k"] := "path_matrix"["i"]["k"]; 1.167 + IF "matrix"["i"]["k"] > "matrix"["j"]["k"] THEN 1.168 + "matrix"["j"]["k"] := "matrix"["i"]["k"]; 1.169 END IF; 1.170 END IF; 1.171 END IF; 1.172 @@ -4004,132 +3965,6 @@ 1.173 EXIT WHEN "i" = "dimension_v"; 1.174 "i" := "i" + 1; 1.175 END LOOP; 1.176 - -- initial calculation of binary relation: 1.177 - "compare_matrix" := array_fill(NULL::BOOLEAN, ARRAY["dimension_v", "dimension_v"]); 1.178 - "i" := 1; 1.179 - LOOP 1.180 - "j" := 1; 1.181 - LOOP 1.182 - IF "i" != "j" THEN 1.183 - IF "path_matrix"["i"]["j"] > "path_matrix"["j"]["i"] THEN 1.184 - "compare_matrix"["i"]["j"] = TRUE; 1.185 - "compare_matrix"["j"]["i"] = FALSE; 1.186 - ELSIF "path_matrix"["i"]["j"] < "path_matrix"["j"]["i"] THEN 1.187 - "compare_matrix"["i"]["j"] = FALSE; 1.188 - "compare_matrix"["j"]["i"] = TRUE; 1.189 - END IF; 1.190 - END IF; 1.191 - EXIT WHEN "j" = "dimension_v"; 1.192 - "j" := "j" + 1; 1.193 - END LOOP; 1.194 - EXIT WHEN "i" = "dimension_v"; 1.195 - "i" := "i" + 1; 1.196 - END LOOP; 1.197 - -- tie-breaking: 1.198 - IF "policy_row"."schulze_variant" >= 'partial_tie_breaking'::"schulze_variant" THEN 1.199 - "modified_matrix" := array_fill(NULL::INT8, ARRAY["dimension_v", "dimension_v"]); 1.200 - "forbidden_matrix" := array_fill(NULL::BOOLEAN, ARRAY["dimension_v", "dimension_v"]); 1.201 - "m" := 1; 1.202 - LOOP 1.203 - "n" := "m" + 1; 1.204 - LOOP 1.205 - IF "compare_matrix"["m"]["n"] ISNULL THEN 1.206 - "i" := 1; 1.207 - LOOP 1.208 - "j" := 1; 1.209 - LOOP 1.210 - IF "i" != "j" THEN 1.211 - "forbidden_matrix"["i"]["j"] := FALSE; 1.212 - "modified_matrix"["i"]["j"] := "path_matrix"["i"]["j"]; 1.213 - END IF; 1.214 - EXIT WHEN "j" = "dimension_v"; 1.215 - "j" := "j" + 1; 1.216 - END LOOP; 1.217 - EXIT WHEN "i" = "dimension_v"; 1.218 - "i" := "i" + 1; 1.219 - END LOOP; 1.220 - LOOP 1.221 - "i" := 1; 1.222 - LOOP 1.223 - "j" := 1; 1.224 - LOOP 1.225 - IF "i" != "j" THEN 1.226 - -- TODO: Bug here. This can cause other links to be forbidden, which should not be forbidden: 1.227 - IF "modified_matrix"["m"]["n"] = "direct_matrix"["i"]["j"] THEN 1.228 - "forbidden_matrix"["i"]["j"] := TRUE; 1.229 - END IF; 1.230 - END IF; 1.231 - EXIT WHEN "j" = "dimension_v"; 1.232 - "j" := "j" + 1; 1.233 - END LOOP; 1.234 - EXIT WHEN "i" = "dimension_v"; 1.235 - "i" := "i" + 1; 1.236 - END LOOP; 1.237 - "i" := 1; 1.238 - LOOP 1.239 - "j" := 1; 1.240 - LOOP 1.241 - IF "i" != "j" THEN 1.242 - IF "forbidden_matrix"["i"]["j"] THEN 1.243 - "modified_matrix"["i"]["j"] := "impossible_defeat_strength"(); 1.244 - ELSE 1.245 - "modified_matrix"["i"]["j"] := "direct_matrix"["i"]["j"]; 1.246 - END IF; 1.247 - END IF; 1.248 - EXIT WHEN "j" = "dimension_v"; 1.249 - "j" := "j" + 1; 1.250 - END LOOP; 1.251 - EXIT WHEN "i" = "dimension_v"; 1.252 - "i" := "i" + 1; 1.253 - END LOOP; 1.254 - "i" := 1; 1.255 - LOOP 1.256 - "j" := 1; 1.257 - LOOP 1.258 - IF "i" != "j" THEN 1.259 - "k" := 1; 1.260 - LOOP 1.261 - IF "i" != "k" AND "j" != "k" THEN 1.262 - IF "modified_matrix"["j"]["i"] < "modified_matrix"["i"]["k"] THEN 1.263 - IF "modified_matrix"["j"]["i"] > "modified_matrix"["j"]["k"] THEN 1.264 - "modified_matrix"["j"]["k"] := "modified_matrix"["j"]["i"]; 1.265 - END IF; 1.266 - ELSE 1.267 - IF "modified_matrix"["i"]["k"] > "modified_matrix"["j"]["k"] THEN 1.268 - "modified_matrix"["j"]["k"] := "modified_matrix"["i"]["k"]; 1.269 - END IF; 1.270 - END IF; 1.271 - END IF; 1.272 - EXIT WHEN "k" = "dimension_v"; 1.273 - "k" := "k" + 1; 1.274 - END LOOP; 1.275 - END IF; 1.276 - EXIT WHEN "j" = "dimension_v"; 1.277 - "j" := "j" + 1; 1.278 - END LOOP; 1.279 - EXIT WHEN "i" = "dimension_v"; 1.280 - "i" := "i" + 1; 1.281 - END LOOP; 1.282 - IF "modified_matrix"["m"]["n"] > "modified_matrix"["n"]["m"] THEN 1.283 - "compare_matrix"["m"]["n"] := TRUE; 1.284 - "compare_matrix"["n"]["m"] := FALSE; 1.285 - EXIT; 1.286 - ELSIF "modified_matrix"["m"]["n"] < "modified_matrix"["n"]["m"] THEN 1.287 - "compare_matrix"["m"]["n"] := FALSE; 1.288 - "compare_matrix"["n"]["m"] := TRUE; 1.289 - EXIT; 1.290 - ELSIF "modified_matrix"["m"]["n"] = "impossible_defeat_strength"() THEN 1.291 - EXIT; 1.292 - END IF; 1.293 - END LOOP; 1.294 - END IF; 1.295 - EXIT WHEN "n" = "dimension_v"; 1.296 - "n" := "n" + 1; 1.297 - END LOOP; 1.298 - EXIT WHEN "m" = "dimension_v" - 1; 1.299 - "m" := "m" + 1; 1.300 - END LOOP; 1.301 - END IF; 1.302 -- Determine order of winners: 1.303 "rank_ary" := array_fill(NULL::INT4, ARRAY["dimension_v"]); 1.304 "rank_v" := 1; 1.305 @@ -4144,7 +3979,7 @@ 1.306 IF 1.307 "i" != "j" AND 1.308 "rank_ary"["j"] ISNULL AND 1.309 - "compare_matrix"["j"]["i"] 1.310 + "matrix"["j"]["i"] > "matrix"["i"]["j"] 1.311 THEN 1.312 -- someone else is better 1.313 EXIT; 1.314 @@ -4204,7 +4039,7 @@ 1.315 "better_than_status_quo" = "rank_ary"["i"] < "rank_ary"["dimension_v"], 1.316 "worse_than_status_quo" = "rank_ary"["i"] > "rank_ary"["dimension_v"], 1.317 "multistage_majority" = "rank_ary"["i"] >= "rank_ary"["dimension_v"], 1.318 - "reverse_beat_path" = "path_matrix"["dimension_v"]["i"] >= 0, 1.319 + "reverse_beat_path" = "matrix"["dimension_v"]["i"] >= 0, 1.320 "eligible" = FALSE, 1.321 "winner" = FALSE, 1.322 "rank" = NULL -- NOTE: in cases of manual reset of issue state