
jbe@423: BEGIN;
jbe@423: 
jbe@423: CREATE OR REPLACE VIEW "liquid_feedback_version" AS
jbe@423:   SELECT * FROM (VALUES ('3.0.2', 3, 0, 2))
jbe@423:   AS "subquery"("string", "major", "minor", "revision");
jbe@423: 
jbe@430: 
jbe@430: CREATE TYPE "defeat_strength" AS ENUM ('simple', 'tuple');
jbe@430: 
jbe@430: COMMENT ON TYPE "defeat_strength" IS 'How pairwise defeats are measured for the Schulze method: ''simple'' = only the number of winning votes, ''tuple'' = primarily the number of winning votes, secondarily the number of losing votes';
jbe@430: 
jbe@430: 
jbe@430: CREATE TYPE "tie_breaking" AS ENUM ('simple', 'variant1', 'variant2');
jbe@430: 
jbe@430: COMMENT ON TYPE "tie_breaking" IS 'Tie-breaker for the Schulze method: ''simple'' = only initiative ids are used, ''variant1'' = use initiative ids in variant 1 for tie breaking of the links (TBRL) and sequentially forbid shared links, ''variant2'' = use initiative ids in variant 2 for tie breaking of the links (TBRL) and sequentially forbid shared links';
jbe@430: 
jbe@430: 
jbe@430: ALTER TABLE "policy" ADD COLUMN "defeat_strength" "defeat_strength" NOT NULL DEFAULT 'tuple';
jbe@430: ALTER TABLE "policy" ADD COLUMN "tie_breaking"    "tie_breaking"    NOT NULL DEFAULT 'variant1';
jbe@430: 
jbe@430: ALTER TABLE "policy" ADD
jbe@430:   CONSTRAINT "no_reverse_beat_path_requires_tuple_defeat_strength" CHECK (
jbe@430:     ("defeat_strength" = 'tuple'::"defeat_strength" OR "no_reverse_beat_path" = FALSE)
jbe@430:   );
jbe@430: 
jbe@430: COMMENT ON COLUMN "policy"."defeat_strength"       IS 'How pairwise defeats are measured for the Schulze method; see type "defeat_strength"; ''tuple'' is the recommended setting';
jbe@430: COMMENT ON COLUMN "policy"."tie_breaking"          IS 'Tie-breaker for the Schulze method; see type "tie_breaking"; ''variant1'' or ''variant2'' are recommended';
jbe@430: 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; set to NULL if "policy"."defeat_strength" is set to ''simple''';
jbe@430:  
jbe@430: 
jbe@430: DROP FUNCTION "calculate_ranks"("issue"."id"%TYPE);
jbe@430: DROP FUNCTION "defeat_strength"(INT4, INT4);
jbe@430: 
jbe@430: 
jbe@430: CREATE FUNCTION "defeat_strength"
jbe@430:   ( "positive_votes_p"  INT4,
jbe@430:     "negative_votes_p"  INT4,
jbe@430:     "defeat_strength_p" "defeat_strength" )
jbe@430:   RETURNS INT8
jbe@430:   LANGUAGE 'plpgsql' IMMUTABLE AS $$
jbe@430:     BEGIN
jbe@430:       IF "defeat_strength_p" = 'simple'::"defeat_strength" THEN
jbe@430:         IF "positive_votes_p" > "negative_votes_p" THEN
jbe@430:           RETURN "positive_votes_p";
jbe@430:         ELSE
jbe@430:           RETURN 0;
jbe@430:         END IF;
jbe@430:       ELSE
jbe@430:         IF "positive_votes_p" > "negative_votes_p" THEN
jbe@430:           RETURN ("positive_votes_p"::INT8 << 31) - "negative_votes_p"::INT8;
jbe@430:         ELSIF "positive_votes_p" = "negative_votes_p" THEN
jbe@430:           RETURN 0;
jbe@430:         ELSE
jbe@430:           RETURN -1;
jbe@430:         END IF;
jbe@430:       END IF;
jbe@430:     END;
jbe@430:   $$;
jbe@430: 
jbe@430: COMMENT ON FUNCTION "defeat_strength"(INT4, INT4, "defeat_strength") IS 'Calculates defeat strength (INT8!) according to the "defeat_strength" option (see comment on type "defeat_strength")';
jbe@430: 
jbe@430: 
jbe@430: CREATE FUNCTION "secondary_link_strength"
jbe@430:   ( "initiative1_ord_p" INT4,
jbe@430:     "initiative2_ord_p" INT4,
jbe@430:     "tie_breaking_p"   "tie_breaking" )
jbe@430:   RETURNS INT8
jbe@430:   LANGUAGE 'plpgsql' IMMUTABLE AS $$
jbe@430:     BEGIN
jbe@430:       IF "initiative1_ord_p" = "initiative2_ord_p" THEN
jbe@430:         RAISE EXCEPTION 'Identical initiative ids passed to "secondary_link_strength" function (should not happen)';
jbe@430:       END IF;
jbe@430:       RETURN (
jbe@430:         CASE WHEN "tie_breaking_p" = 'simple'::"tie_breaking" THEN
jbe@430:           0
jbe@430:         ELSE
jbe@430:           CASE WHEN "initiative1_ord_p" < "initiative2_ord_p" THEN
jbe@430:             1::INT8 << 62
jbe@430:           ELSE 0 END
jbe@430:           +
jbe@430:           CASE WHEN "tie_breaking_p" = 'variant2'::"tie_breaking" THEN
jbe@430:             ("initiative2_ord_p"::INT8 << 31) - "initiative1_ord_p"::INT8
jbe@430:           ELSE
jbe@430:             "initiative2_ord_p"::INT8 - ("initiative1_ord_p"::INT8 << 31)
jbe@430:           END
jbe@430:         END
jbe@430:       );
jbe@430:     END;
jbe@430:   $$;
jbe@430: 
jbe@430: COMMENT ON FUNCTION "secondary_link_strength"(INT4, INT4, "tie_breaking") IS 'Calculates a secondary criterion for the defeat strength (tie-breaking of the links)';
jbe@430: 
jbe@430: 
jbe@430: CREATE TYPE "link_strength" AS (
jbe@430:         "primary"               INT8,
jbe@430:         "secondary"             INT8 );
jbe@430: 
jbe@430: COMMENT ON TYPE "link_strength" IS 'Type to store the defeat strength of a link between two candidates plus a secondary criterion to create unique link strengths between the candidates (needed for tie-breaking ''variant1'' and ''variant2'')';
jbe@430: 
jbe@430: 
jbe@430: CREATE FUNCTION "find_best_paths"("matrix_d" "link_strength"[][])
jbe@430:   RETURNS "link_strength"[][]
jbe@430:   LANGUAGE 'plpgsql' IMMUTABLE AS $$
jbe@430:     DECLARE
jbe@430:       "dimension_v" INT4;
jbe@430:       "matrix_p"    "link_strength"[][];
jbe@430:       "i"           INT4;
jbe@430:       "j"           INT4;
jbe@430:       "k"           INT4;
jbe@430:     BEGIN
jbe@430:       "dimension_v" := array_upper("matrix_d", 1);
jbe@430:       "matrix_p" := "matrix_d";
jbe@430:       "i" := 1;
jbe@430:       LOOP
jbe@430:         "j" := 1;
jbe@430:         LOOP
jbe@430:           IF "i" != "j" THEN
jbe@430:             "k" := 1;
jbe@430:             LOOP
jbe@430:               IF "i" != "k" AND "j" != "k" THEN
jbe@430:                 IF "matrix_p"["j"]["i"] < "matrix_p"["i"]["k"] THEN
jbe@430:                   IF "matrix_p"["j"]["i"] > "matrix_p"["j"]["k"] THEN
jbe@430:                     "matrix_p"["j"]["k"] := "matrix_p"["j"]["i"];
jbe@430:                   END IF;
jbe@430:                 ELSE
jbe@430:                   IF "matrix_p"["i"]["k"] > "matrix_p"["j"]["k"] THEN
jbe@430:                     "matrix_p"["j"]["k"] := "matrix_p"["i"]["k"];
jbe@430:                   END IF;
jbe@430:                 END IF;
jbe@430:               END IF;
jbe@430:               EXIT WHEN "k" = "dimension_v";
jbe@430:               "k" := "k" + 1;
jbe@430:             END LOOP;
jbe@430:           END IF;
jbe@430:           EXIT WHEN "j" = "dimension_v";
jbe@430:           "j" := "j" + 1;
jbe@430:         END LOOP;
jbe@430:         EXIT WHEN "i" = "dimension_v";
jbe@430:         "i" := "i" + 1;
jbe@430:       END LOOP;
jbe@430:       RETURN "matrix_p";
jbe@430:     END;
jbe@430:   $$;
jbe@430: 
jbe@430: COMMENT ON FUNCTION "find_best_paths"("link_strength"[][]) IS 'Computes the strengths of the best beat-paths from a square matrix';
jbe@430:  
jbe@430: 
jbe@430: CREATE FUNCTION "calculate_ranks"("issue_id_p" "issue"."id"%TYPE)
jbe@430:   RETURNS VOID
jbe@430:   LANGUAGE 'plpgsql' VOLATILE AS $$
jbe@430:     DECLARE
jbe@430:       "issue_row"       "issue"%ROWTYPE;
jbe@430:       "policy_row"      "policy"%ROWTYPE;
jbe@430:       "dimension_v"     INT4;
jbe@430:       "matrix_a"        INT4[][];  -- absolute votes
jbe@430:       "matrix_d"        "link_strength"[][];  -- defeat strength (direct)
jbe@430:       "matrix_p"        "link_strength"[][];  -- defeat strength (best path)
jbe@430:       "matrix_t"        "link_strength"[][];  -- defeat strength (tie-breaking)
jbe@430:       "matrix_f"        BOOLEAN[][];  -- forbidden link (tie-breaking)
jbe@430:       "matrix_b"        BOOLEAN[][];  -- final order (who beats who)
jbe@430:       "i"               INT4;
jbe@430:       "j"               INT4;
jbe@430:       "m"               INT4;
jbe@430:       "n"               INT4;
jbe@430:       "battle_row"      "battle"%ROWTYPE;
jbe@430:       "rank_ary"        INT4[];
jbe@430:       "rank_v"          INT4;
jbe@430:       "initiative_id_v" "initiative"."id"%TYPE;
jbe@430:     BEGIN
jbe@430:       PERFORM "require_transaction_isolation"();
jbe@430:       SELECT * INTO "issue_row"
jbe@430:         FROM "issue" WHERE "id" = "issue_id_p";
jbe@430:       SELECT * INTO "policy_row"
jbe@430:         FROM "policy" WHERE "id" = "issue_row"."policy_id";
jbe@430:       SELECT count(1) INTO "dimension_v"
jbe@430:         FROM "battle_participant" WHERE "issue_id" = "issue_id_p";
jbe@430:       -- create "matrix_a" with absolute number of votes in pairwise
jbe@430:       -- comparison:
jbe@430:       "matrix_a" := array_fill(NULL::INT4, ARRAY["dimension_v", "dimension_v"]);
jbe@430:       "i" := 1;
jbe@430:       "j" := 2;
jbe@430:       FOR "battle_row" IN
jbe@430:         SELECT * FROM "battle" WHERE "issue_id" = "issue_id_p"
jbe@430:         ORDER BY
jbe@430:         "winning_initiative_id" NULLS FIRST,
jbe@430:         "losing_initiative_id" NULLS FIRST
jbe@430:       LOOP
jbe@430:         "matrix_a"["i"]["j"] := "battle_row"."count";
jbe@430:         IF "j" = "dimension_v" THEN
jbe@430:           "i" := "i" + 1;
jbe@430:           "j" := 1;
jbe@430:         ELSE
jbe@430:           "j" := "j" + 1;
jbe@430:           IF "j" = "i" THEN
jbe@430:             "j" := "j" + 1;
jbe@430:           END IF;
jbe@430:         END IF;
jbe@430:       END LOOP;
jbe@430:       IF "i" != "dimension_v" OR "j" != "dimension_v" + 1 THEN
jbe@430:         RAISE EXCEPTION 'Wrong battle count (should not happen)';
jbe@430:       END IF;
jbe@430:       -- store direct defeat strengths in "matrix_d" using "defeat_strength"
jbe@430:       -- and "secondary_link_strength" functions:
jbe@430:       "matrix_d" := array_fill(NULL::INT8, ARRAY["dimension_v", "dimension_v"]);
jbe@430:       "i" := 1;
jbe@430:       LOOP
jbe@430:         "j" := 1;
jbe@430:         LOOP
jbe@430:           IF "i" != "j" THEN
jbe@430:             "matrix_d"["i"]["j"] := (
jbe@430:               "defeat_strength"(
jbe@430:                 "matrix_a"["i"]["j"],
jbe@430:                 "matrix_a"["j"]["i"],
jbe@430:                 "policy_row"."defeat_strength"
jbe@430:               ),
jbe@430:               "secondary_link_strength"(
jbe@430:                 "i",
jbe@430:                 "j",
jbe@430:                 "policy_row"."tie_breaking"
jbe@430:               )
jbe@430:             )::"link_strength";
jbe@430:           END IF;
jbe@430:           EXIT WHEN "j" = "dimension_v";
jbe@430:           "j" := "j" + 1;
jbe@430:         END LOOP;
jbe@430:         EXIT WHEN "i" = "dimension_v";
jbe@430:         "i" := "i" + 1;
jbe@430:       END LOOP;
jbe@430:       -- find best paths:
jbe@430:       "matrix_p" := "find_best_paths"("matrix_d");
jbe@430:       -- create partial order:
jbe@430:       "matrix_b" := array_fill(NULL::BOOLEAN, ARRAY["dimension_v", "dimension_v"]);
jbe@430:       "i" := 1;
jbe@430:       LOOP
jbe@430:         "j" := "i" + 1;
jbe@430:         LOOP
jbe@430:           IF "i" != "j" THEN
jbe@430:             IF "matrix_p"["i"]["j"] > "matrix_p"["j"]["i"] THEN
jbe@430:               "matrix_b"["i"]["j"] := TRUE;
jbe@430:               "matrix_b"["j"]["i"] := FALSE;
jbe@430:             ELSIF "matrix_p"["i"]["j"] < "matrix_p"["j"]["i"] THEN
jbe@430:               "matrix_b"["i"]["j"] := FALSE;
jbe@430:               "matrix_b"["j"]["i"] := TRUE;
jbe@430:             END IF;
jbe@430:           END IF;
jbe@430:           EXIT WHEN "j" = "dimension_v";
jbe@430:           "j" := "j" + 1;
jbe@430:         END LOOP;
jbe@430:         EXIT WHEN "i" = "dimension_v" - 1;
jbe@430:         "i" := "i" + 1;
jbe@430:       END LOOP;
jbe@430:       -- tie-breaking by forbidding shared weakest links in beat-paths
jbe@430:       -- (unless "tie_breaking" is set to 'simple', in which case tie-breaking
jbe@430:       -- is performed later by initiative id):
jbe@430:       IF "policy_row"."tie_breaking" != 'simple'::"tie_breaking" THEN
jbe@430:         "m" := 1;
jbe@430:         LOOP
jbe@430:           "n" := "m" + 1;
jbe@430:           LOOP
jbe@430:             -- only process those candidates m and n, which are tied:
jbe@430:             IF "matrix_b"["m"]["n"] ISNULL THEN
jbe@430:               -- start with beat-paths prior tie-breaking:
jbe@430:               "matrix_t" := "matrix_p";
jbe@430:               -- start with all links allowed:
jbe@430:               "matrix_f" := array_fill(FALSE, ARRAY["dimension_v", "dimension_v"]);
jbe@430:               LOOP
jbe@430:                 -- determine (and forbid) that link that is the weakest link
jbe@430:                 -- in both the best path from candidate m to candidate n and
jbe@430:                 -- from candidate n to candidate m:
jbe@430:                 "i" := 1;
jbe@430:                 <<forbid_one_link>>
jbe@430:                 LOOP
jbe@430:                   "j" := 1;
jbe@430:                   LOOP
jbe@430:                     IF "i" != "j" THEN
jbe@430:                       IF "matrix_d"["i"]["j"] = "matrix_t"["m"]["n"] THEN
jbe@430:                         "matrix_f"["i"]["j"] := TRUE;
jbe@430:                         -- exit for performance reasons,
jbe@430:                         -- as exactly one link will be found:
jbe@430:                         EXIT forbid_one_link;
jbe@430:                       END IF;
jbe@430:                     END IF;
jbe@430:                     EXIT WHEN "j" = "dimension_v";
jbe@430:                     "j" := "j" + 1;
jbe@430:                   END LOOP;
jbe@430:                   IF "i" = "dimension_v" THEN
jbe@430:                     RAISE EXCEPTION 'Did not find shared weakest link for tie-breaking (should not happen)';
jbe@430:                   END IF;
jbe@430:                   "i" := "i" + 1;
jbe@430:                 END LOOP;
jbe@430:                 -- calculate best beat-paths while ignoring forbidden links:
jbe@430:                 "i" := 1;
jbe@430:                 LOOP
jbe@430:                   "j" := 1;
jbe@430:                   LOOP
jbe@430:                     IF "i" != "j" THEN
jbe@430:                       "matrix_t"["i"]["j"] := CASE
jbe@430:                          WHEN "matrix_f"["i"]["j"]
jbe@430:                          THEN (-1::INT8) << 63  -- worst possible value
jbe@430:                          ELSE "matrix_d"["i"]["j"] END;
jbe@430:                     END IF;
jbe@430:                     EXIT WHEN "j" = "dimension_v";
jbe@430:                     "j" := "j" + 1;
jbe@430:                   END LOOP;
jbe@430:                   EXIT WHEN "i" = "dimension_v";
jbe@430:                   "i" := "i" + 1;
jbe@430:                 END LOOP;
jbe@430:                 "matrix_t" := "find_best_paths"("matrix_t");
jbe@430:                 -- extend partial order, if tie-breaking was successful:
jbe@430:                 IF "matrix_t"["m"]["n"] > "matrix_t"["n"]["m"] THEN
jbe@430:                   "matrix_b"["m"]["n"] := TRUE;
jbe@430:                   "matrix_b"["n"]["m"] := FALSE;
jbe@430:                   EXIT;
jbe@430:                 ELSIF "matrix_t"["m"]["n"] < "matrix_t"["n"]["m"] THEN
jbe@430:                   "matrix_b"["m"]["n"] := FALSE;
jbe@430:                   "matrix_b"["n"]["m"] := TRUE;
jbe@430:                   EXIT;
jbe@430:                 END IF;
jbe@430:               END LOOP;
jbe@430:             END IF;
jbe@430:             EXIT WHEN "n" = "dimension_v";
jbe@430:             "n" := "n" + 1;
jbe@430:           END LOOP;
jbe@430:           EXIT WHEN "m" = "dimension_v" - 1;
jbe@430:           "m" := "m" + 1;
jbe@430:         END LOOP;
jbe@430:       END IF;
jbe@430:       -- store a unique ranking in "rank_ary":
jbe@430:       "rank_ary" := array_fill(NULL::INT4, ARRAY["dimension_v"]);
jbe@430:       "rank_v" := 1;
jbe@430:       LOOP
jbe@430:         "i" := 1;
jbe@430:         <<assign_next_rank>>
jbe@430:         LOOP
jbe@430:           IF "rank_ary"["i"] ISNULL THEN
jbe@430:             "j" := 1;
jbe@430:             LOOP
jbe@430:               IF
jbe@430:                 "i" != "j" AND
jbe@430:                 "rank_ary"["j"] ISNULL AND
jbe@430:                 ( "matrix_b"["j"]["i"] OR
jbe@430:                   -- tie-breaking by "id"
jbe@430:                   ( "matrix_b"["j"]["i"] ISNULL AND
jbe@430:                     "j" < "i" ) )
jbe@430:               THEN
jbe@430:                 -- someone else is better
jbe@430:                 EXIT;
jbe@430:               END IF;
jbe@430:               IF "j" = "dimension_v" THEN
jbe@430:                 -- noone is better
jbe@430:                 "rank_ary"["i"] := "rank_v";
jbe@430:                 EXIT assign_next_rank;
jbe@430:               END IF;
jbe@430:               "j" := "j" + 1;
jbe@430:             END LOOP;
jbe@430:           END IF;
jbe@430:           "i" := "i" + 1;
jbe@430:           IF "i" > "dimension_v" THEN
jbe@430:             RAISE EXCEPTION 'Schulze ranking does not compute (should not happen)';
jbe@430:           END IF;
jbe@430:         END LOOP;
jbe@430:         EXIT WHEN "rank_v" = "dimension_v";
jbe@430:         "rank_v" := "rank_v" + 1;
jbe@430:       END LOOP;
jbe@430:       -- write preliminary results:
jbe@430:       "i" := 2;  -- omit status quo with "i" = 1
jbe@430:       FOR "initiative_id_v" IN
jbe@430:         SELECT "id" FROM "initiative"
jbe@430:         WHERE "issue_id" = "issue_id_p" AND "admitted"
jbe@430:         ORDER BY "id"
jbe@430:       LOOP
jbe@430:         UPDATE "initiative" SET
jbe@430:           "direct_majority" =
jbe@430:             CASE WHEN "policy_row"."direct_majority_strict" THEN
jbe@430:               "positive_votes" * "policy_row"."direct_majority_den" >
jbe@430:               "policy_row"."direct_majority_num" * ("positive_votes"+"negative_votes")
jbe@430:             ELSE
jbe@430:               "positive_votes" * "policy_row"."direct_majority_den" >=
jbe@430:               "policy_row"."direct_majority_num" * ("positive_votes"+"negative_votes")
jbe@430:             END
jbe@430:             AND "positive_votes" >= "policy_row"."direct_majority_positive"
jbe@430:             AND "issue_row"."voter_count"-"negative_votes" >=
jbe@430:                 "policy_row"."direct_majority_non_negative",
jbe@430:             "indirect_majority" =
jbe@430:             CASE WHEN "policy_row"."indirect_majority_strict" THEN
jbe@430:               "positive_votes" * "policy_row"."indirect_majority_den" >
jbe@430:               "policy_row"."indirect_majority_num" * ("positive_votes"+"negative_votes")
jbe@430:             ELSE
jbe@430:               "positive_votes" * "policy_row"."indirect_majority_den" >=
jbe@430:               "policy_row"."indirect_majority_num" * ("positive_votes"+"negative_votes")
jbe@430:             END
jbe@430:             AND "positive_votes" >= "policy_row"."indirect_majority_positive"
jbe@430:             AND "issue_row"."voter_count"-"negative_votes" >=
jbe@430:                 "policy_row"."indirect_majority_non_negative",
jbe@430:           "schulze_rank"           = "rank_ary"["i"],
jbe@430:           "better_than_status_quo" = "rank_ary"["i"] < "rank_ary"[1],
jbe@430:           "worse_than_status_quo"  = "rank_ary"["i"] > "rank_ary"[1],
jbe@430:           "multistage_majority"    = "rank_ary"["i"] >= "rank_ary"[1],
jbe@430:           "reverse_beat_path"      = CASE WHEN "policy_row"."defeat_strength" = 'simple'::"defeat_strength"
jbe@430:                                      THEN NULL
jbe@430:                                      ELSE "matrix_p"[1]["i"]."primary" >= 0 END,
jbe@430:           "eligible"               = FALSE,
jbe@430:           "winner"                 = FALSE,
jbe@430:           "rank"                   = NULL  -- NOTE: in cases of manual reset of issue state
jbe@430:           WHERE "id" = "initiative_id_v";
jbe@430:         "i" := "i" + 1;
jbe@430:       END LOOP;
jbe@430:       IF "i" != "dimension_v" + 1 THEN
jbe@430:         RAISE EXCEPTION 'Wrong winner count (should not happen)';
jbe@430:       END IF;
jbe@430:       -- take indirect majorities into account:
jbe@430:       LOOP
jbe@430:         UPDATE "initiative" SET "indirect_majority" = TRUE
jbe@430:           FROM (
jbe@430:             SELECT "new_initiative"."id" AS "initiative_id"
jbe@430:             FROM "initiative" "old_initiative"
jbe@430:             JOIN "initiative" "new_initiative"
jbe@430:               ON "new_initiative"."issue_id" = "issue_id_p"
jbe@430:               AND "new_initiative"."indirect_majority" = FALSE
jbe@430:             JOIN "battle" "battle_win"
jbe@430:               ON "battle_win"."issue_id" = "issue_id_p"
jbe@430:               AND "battle_win"."winning_initiative_id" = "new_initiative"."id"
jbe@430:               AND "battle_win"."losing_initiative_id" = "old_initiative"."id"
jbe@430:             JOIN "battle" "battle_lose"
jbe@430:               ON "battle_lose"."issue_id" = "issue_id_p"
jbe@430:               AND "battle_lose"."losing_initiative_id" = "new_initiative"."id"
jbe@430:               AND "battle_lose"."winning_initiative_id" = "old_initiative"."id"
jbe@430:             WHERE "old_initiative"."issue_id" = "issue_id_p"
jbe@430:             AND "old_initiative"."indirect_majority" = TRUE
jbe@430:             AND CASE WHEN "policy_row"."indirect_majority_strict" THEN
jbe@430:               "battle_win"."count" * "policy_row"."indirect_majority_den" >
jbe@430:               "policy_row"."indirect_majority_num" *
jbe@430:               ("battle_win"."count"+"battle_lose"."count")
jbe@430:             ELSE
jbe@430:               "battle_win"."count" * "policy_row"."indirect_majority_den" >=
jbe@430:               "policy_row"."indirect_majority_num" *
jbe@430:               ("battle_win"."count"+"battle_lose"."count")
jbe@430:             END
jbe@430:             AND "battle_win"."count" >= "policy_row"."indirect_majority_positive"
jbe@430:             AND "issue_row"."voter_count"-"battle_lose"."count" >=
jbe@430:                 "policy_row"."indirect_majority_non_negative"
jbe@430:           ) AS "subquery"
jbe@430:           WHERE "id" = "subquery"."initiative_id";
jbe@430:         EXIT WHEN NOT FOUND;
jbe@430:       END LOOP;
jbe@430:       -- set "multistage_majority" for remaining matching initiatives:
jbe@430:       UPDATE "initiative" SET "multistage_majority" = TRUE
jbe@430:         FROM (
jbe@430:           SELECT "losing_initiative"."id" AS "initiative_id"
jbe@430:           FROM "initiative" "losing_initiative"
jbe@430:           JOIN "initiative" "winning_initiative"
jbe@430:             ON "winning_initiative"."issue_id" = "issue_id_p"
jbe@430:             AND "winning_initiative"."admitted"
jbe@430:           JOIN "battle" "battle_win"
jbe@430:             ON "battle_win"."issue_id" = "issue_id_p"
jbe@430:             AND "battle_win"."winning_initiative_id" = "winning_initiative"."id"
jbe@430:             AND "battle_win"."losing_initiative_id" = "losing_initiative"."id"
jbe@430:           JOIN "battle" "battle_lose"
jbe@430:             ON "battle_lose"."issue_id" = "issue_id_p"
jbe@430:             AND "battle_lose"."losing_initiative_id" = "winning_initiative"."id"
jbe@430:             AND "battle_lose"."winning_initiative_id" = "losing_initiative"."id"
jbe@430:           WHERE "losing_initiative"."issue_id" = "issue_id_p"
jbe@430:           AND "losing_initiative"."admitted"
jbe@430:           AND "winning_initiative"."schulze_rank" <
jbe@430:               "losing_initiative"."schulze_rank"
jbe@430:           AND "battle_win"."count" > "battle_lose"."count"
jbe@430:           AND (
jbe@430:             "battle_win"."count" > "winning_initiative"."positive_votes" OR
jbe@430:             "battle_lose"."count" < "losing_initiative"."negative_votes" )
jbe@430:         ) AS "subquery"
jbe@430:         WHERE "id" = "subquery"."initiative_id";
jbe@430:       -- mark eligible initiatives:
jbe@430:       UPDATE "initiative" SET "eligible" = TRUE
jbe@430:         WHERE "issue_id" = "issue_id_p"
jbe@430:         AND "initiative"."direct_majority"
jbe@430:         AND "initiative"."indirect_majority"
jbe@430:         AND "initiative"."better_than_status_quo"
jbe@430:         AND (
jbe@430:           "policy_row"."no_multistage_majority" = FALSE OR
jbe@430:           "initiative"."multistage_majority" = FALSE )
jbe@430:         AND (
jbe@430:           "policy_row"."no_reverse_beat_path" = FALSE OR
jbe@430:           coalesce("initiative"."reverse_beat_path", FALSE) = FALSE );
jbe@430:       -- mark final winner:
jbe@430:       UPDATE "initiative" SET "winner" = TRUE
jbe@430:         FROM (
jbe@430:           SELECT "id" AS "initiative_id"
jbe@430:           FROM "initiative"
jbe@430:           WHERE "issue_id" = "issue_id_p" AND "eligible"
jbe@430:           ORDER BY
jbe@430:             "schulze_rank",
jbe@430:             "id"
jbe@430:           LIMIT 1
jbe@430:         ) AS "subquery"
jbe@430:         WHERE "id" = "subquery"."initiative_id";
jbe@430:       -- write (final) ranks:
jbe@430:       "rank_v" := 1;
jbe@430:       FOR "initiative_id_v" IN
jbe@430:         SELECT "id"
jbe@430:         FROM "initiative"
jbe@430:         WHERE "issue_id" = "issue_id_p" AND "admitted"
jbe@430:         ORDER BY
jbe@430:           "winner" DESC,
jbe@430:           "eligible" DESC,
jbe@430:           "schulze_rank",
jbe@430:           "id"
jbe@430:       LOOP
jbe@430:         UPDATE "initiative" SET "rank" = "rank_v"
jbe@430:           WHERE "id" = "initiative_id_v";
jbe@430:         "rank_v" := "rank_v" + 1;
jbe@430:       END LOOP;
jbe@430:       -- set schulze rank of status quo and mark issue as finished:
jbe@430:       UPDATE "issue" SET
jbe@430:         "status_quo_schulze_rank" = "rank_ary"[1],
jbe@430:         "state" =
jbe@430:           CASE WHEN EXISTS (
jbe@430:             SELECT NULL FROM "initiative"
jbe@430:             WHERE "issue_id" = "issue_id_p" AND "winner"
jbe@430:           ) THEN
jbe@430:             'finished_with_winner'::"issue_state"
jbe@430:           ELSE
jbe@430:             'finished_without_winner'::"issue_state"
jbe@430:           END,
jbe@430:         "closed" = "phase_finished",
jbe@430:         "phase_finished" = NULL
jbe@430:         WHERE "id" = "issue_id_p";
jbe@430:       RETURN;
jbe@430:     END;
jbe@430:   $$;
jbe@430: 
jbe@423: 
jbe@423: COMMIT;




