liquid_feedback_core
changeset 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 |
files | core.sql test.sql |
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
2.1 --- a/test.sql Sun Sep 30 00:56:01 2012 +0200 2.2 +++ b/test.sql Sun Sep 30 12:59:07 2012 +0200 2.3 @@ -41,8 +41,7 @@ 2.4 "issue_quorum_num", "issue_quorum_den", 2.5 "initiative_quorum_num", "initiative_quorum_den", 2.6 "direct_majority_num", "direct_majority_den", "direct_majority_strict", 2.7 - "no_reverse_beat_path", "no_multistage_majority", 2.8 - "schulze_variant" 2.9 + "no_reverse_beat_path", "no_multistage_majority" 2.10 ) VALUES ( 2.11 1, 2.12 'Default policy', 2.13 @@ -50,8 +49,7 @@ 2.14 25, 100, 2.15 20, 100, 2.16 1, 2, TRUE, 2.17 - TRUE, FALSE, 2.18 - 'tie_breaking_with_negative_strength'::"schulze_variant" ); 2.19 + TRUE, FALSE ); 2.20 2.21 CREATE FUNCTION "time_warp"() RETURNS VOID 2.22 LANGUAGE 'plpgsql' VOLATILE AS $$ 2.23 @@ -120,37 +118,10 @@ 2.24 (18, 'unit', 1, 19), 2.25 (23, 'unit', 1, 22); 2.26 2.27 --- no delegations in area #1 2.28 -INSERT INTO "delegation" 2.29 - ("truster_id", "scope", "area_id", "trustee_id") VALUES 2.30 - ( 1, 'area', 1, NULL), 2.31 - ( 2, 'area', 1, NULL), 2.32 - ( 3, 'area', 1, NULL), 2.33 - ( 4, 'area', 1, NULL), 2.34 - ( 5, 'area', 1, NULL), 2.35 - ( 6, 'area', 1, NULL), 2.36 - ( 7, 'area', 1, NULL), 2.37 - ( 8, 'area', 1, NULL), 2.38 - ( 9, 'area', 1, NULL), 2.39 - (10, 'area', 1, NULL), 2.40 - (11, 'area', 1, NULL), 2.41 - (12, 'area', 1, NULL), 2.42 - (13, 'area', 1, NULL), 2.43 - (14, 'area', 1, NULL), 2.44 - (15, 'area', 1, NULL), 2.45 - (16, 'area', 1, NULL), 2.46 - (17, 'area', 1, NULL), 2.47 - (18, 'area', 1, NULL), 2.48 - (19, 'area', 1, NULL), 2.49 - (20, 'area', 1, NULL), 2.50 - (21, 'area', 1, NULL), 2.51 - (22, 'area', 1, NULL), 2.52 - (23, 'area', 1, NULL); 2.53 - 2.54 -- delegations for topics 2.55 INSERT INTO "delegation" 2.56 ("area_id", "truster_id", "scope", "trustee_id") VALUES 2.57 - --(1, 3, 'area', 17), 2.58 + (1, 3, 'area', 17), 2.59 (2, 5, 'area', 10), 2.60 (2, 9, 'area', 10), 2.61 (3, 4, 'area', 14), 2.62 @@ -265,25 +236,6 @@ 2.63 (6, 9, 9), 2.64 (6, 10, 10), 2.65 (6, 11, 11); 2.66 - 2.67 -INSERT INTO "issue" ("area_id", "policy_id") VALUES 2.68 - (1, 1); -- id 3 2.69 - 2.70 -INSERT INTO "initiative" ("issue_id", "name") VALUES 2.71 - (3, 'First initiative'), -- id 12 2.72 - (3, 'Second initiative'); -- id 13 2.73 - 2.74 -INSERT INTO "draft" ("initiative_id", "author_id", "content") VALUES 2.75 - (12, 1, 'Lorem ipsum...'), -- id 12 2.76 - (13, 2, 'Lorem ipsum...'); -- id 13 2.77 - 2.78 -INSERT INTO "initiator" ("initiative_id", "member_id") VALUES 2.79 - (12, 1), 2.80 - (13, 2); 2.81 - 2.82 -INSERT INTO "supporter" ("initiative_id", "member_id") VALUES 2.83 - (12, 1), 2.84 - (13, 2); 2.85 2.86 SELECT "time_warp"(); 2.87 SELECT "time_warp"(); 2.88 @@ -450,25 +402,6 @@ 2.89 (20, 2, 10, -1), 2.90 (20, 2, 11, 3); 2.91 2.92 -INSERT INTO "direct_voter" ("member_id", "issue_id") VALUES 2.93 - ( 1, 3), 2.94 - ( 2, 3), 2.95 - ( 3, 3), 2.96 - ( 4, 3), 2.97 - ( 5, 3); 2.98 - 2.99 -INSERT INTO "vote" ("member_id", "issue_id", "initiative_id", "grade") VALUES 2.100 - (1, 3, 12, 1), 2.101 - (1, 3, 13, 1), 2.102 - (2, 3, 12, 1), 2.103 - (2, 3, 13, 1), 2.104 - (3, 3, 12, 0), 2.105 - (3, 3, 13, 1), 2.106 - (4, 3, 12, 0), 2.107 - (4, 3, 13, -1), 2.108 - (5, 3, 12, -1), 2.109 - (5, 3, 13, -1); 2.110 - 2.111 SELECT "time_warp"(); 2.112 2.113 DROP FUNCTION "time_warp"();