Title: | Social Ranking Solutions for Power Relations on Coalitions |
---|---|
Description: | The notion of power index has been widely used in literature to evaluate the influence of individual players (e.g., voters, political parties, nations, stockholders, etc.) involved in a collective decision situation like an electoral system, a parliament, a council, a management board, etc., where players may form coalitions. Traditionally this ranking is determined through numerical evaluation. More often than not however only ordinal data between coalitions is known. The package 'socialranking' offers a set of solutions to rank players based on a transitive ranking between coalitions, including through CP-Majority, ordinal Banzhaf or lexicographic excellence solution summarized by Tahar Allouche, Bruno Escoffier, Stefano Moretti and Meltem Öztürk (2020, <doi:10.24963/ijcai.2020/3>). |
Authors: | Felix Fritz [aut, cre], Jochen Staudacher [aut, cph, ths], Moretti Stefano [aut, cph, ths] |
Maintainer: | Felix Fritz <[email protected]> |
License: | GPL-3 |
Version: | 1.2.0 |
Built: | 2024-11-20 05:06:03 UTC |
Source: | https://github.com/jassler/socialranking |
Append an equivalence class to a power relation with all coalitions of elements that do not appear in the power relation.
appendMissingCoalitions(powerRelation, includeEmptySet = TRUE)
appendMissingCoalitions(powerRelation, includeEmptySet = TRUE)
powerRelation |
A |
includeEmptySet |
If |
For a given set of elements , a
PowerRelation
object describes a total preorder
of its subsets, or coalitions, , where
is the superset of elements.
If , that means that there are some coalitions
,
such that we cannot compare
or
for every
.
This may be caused by having too many coalitions to consider.
In certain cases, it may be more interesting to only consider the top ranking coalitions and "shoving" all remaining coalitions into the back.
For this use-case, appendMissingCoalitions()
takes the set
and attaches it in form of an equivalence class to the back of the power relation.
I.e., take as an example . Here, we have
Adding the missing coalitions to the power relation then gives us .
PowerRelation
object containing the following values:
$elements
: vector of elements
$eqs
: equivalence classes. Nested list of lists, each containing vectors representing groups of elements in the same equivalence class
$coalitionLookup
: function(v)
taking a coalition vector v
and returning the equivalence class it belongs to. See coalitionLookup()
for more.
$elementLookup
: function(e)
taking an element e
and returning a list of 2-sized tuples. See elementLookup()
for more.
Other helper functions for transforming power relations:
makePowerRelationMonotonic()
pr <- as.PowerRelation(list(c(1,2), 3)) # 12 > 3 appendMissingCoalitions(pr) # 12 > 3 > (123 ~ 13 ~ 23 ~ 1 ~ 2 ~ {}) appendMissingCoalitions(pr, includeEmptySet = FALSE) # 12 > 3 > (123 ~ 13 ~ 23 ~ 1 ~ 2)
pr <- as.PowerRelation(list(c(1,2), 3)) # 12 > 3 appendMissingCoalitions(pr) # 12 > 3 > (123 ~ 13 ~ 23 ~ 1 ~ 2 ~ {}) appendMissingCoalitions(pr, includeEmptySet = FALSE) # 12 > 3 > (123 ~ 13 ~ 23 ~ 1 ~ 2)
Alternative ways of creating PowerRelation
objects.
as.PowerRelation(x, ...) ## S3 method for class 'character' as.PowerRelation(x, ...) ## S3 method for class 'list' as.PowerRelation(x, ..., comparators = c(">"))
as.PowerRelation(x, ...) ## S3 method for class 'character' as.PowerRelation(x, ...) ## S3 method for class 'list' as.PowerRelation(x, ..., comparators = c(">"))
x |
An object |
... |
Optional additional parameters |
comparators |
Vector of ">" or "~" characters |
The same way a power relation may be represented in literature (or printed by an
PowerRelation
object),
a simple string containing letters, numbers, >
or ~
can be used to input a new power relation.
Every special character is ignored, with the exception of (
"\u227B"
) and (
"\u223C"
).
Every letter or number is assumed to be an individual element.
"abc > ac"
therefore would represent two coalitions, the first one of size 3 with the elements a
, b
, and c
.
This method does not allow for elements to be entered that are supposed to be multiple characters long.
An empty coalitions can be simply left blank (i.e., "abc > ~ ac"
),
though it is often clearer if curly braces are used to indicate such (i.e., "abc > {} ~ ac"
).
Create a PowerRelation
object with an unnested list of coalition vectors.
By default, a linear order is assumed on the coalitions.
I.e., if it is given list(c(1,2),1,2)
, these three coalitions are put into their own equivalence class,
producing 12 > 1 > 2
.
The comparators in-between can be adjusted to indicate
whether the relation between two coalitions is that of strict preference >
or indifference ~
.
# Using character strings as.PowerRelation("abc > ab > ({} ~ c) > (a ~ b ~ ac) > bc") # abc > ab > ({} ~ c) > (a ~ b ~ ac) > bc # using createPowerset(), then shifting coalitions up and down using Alt+Up and Alt+Down if(interactive()) { createPowerset(1:2, result = "copy") } as.PowerRelation(" 12 > 1 ~ {} > 2 ") # Using lists as.PowerRelation(list(c(1,2), 2, c(), 1)) # 12 > 2 > {} > 1 as.PowerRelation(list(c(1,2), 2, c(), 1), comparators = c("~", ">", ">")) # (12 ~ 2) > {} > 1 # the length of comparators doesn't necessarily matter. # If comparators are missing, the existing ones are simply repeated... as.PowerRelation(list(c(1,2), 2, c(), 1), comparators = "~") # (12 ~ 2 ~ {} ~ 1) as.PowerRelation(list(c(1,2), 2, c(), 1), comparators = c("~", ">")) # (12 ~ 2) > ({} ~ 1) # ... or the rest is cut off as.PowerRelation(list(c(1,2), 2, c(), 1), comparators = c("~", ">", "~", "~", ">")) # (12 ~ 2) > ({} ~ 1)
# Using character strings as.PowerRelation("abc > ab > ({} ~ c) > (a ~ b ~ ac) > bc") # abc > ab > ({} ~ c) > (a ~ b ~ ac) > bc # using createPowerset(), then shifting coalitions up and down using Alt+Up and Alt+Down if(interactive()) { createPowerset(1:2, result = "copy") } as.PowerRelation(" 12 > 1 ~ {} > 2 ") # Using lists as.PowerRelation(list(c(1,2), 2, c(), 1)) # 12 > 2 > {} > 1 as.PowerRelation(list(c(1,2), 2, c(), 1), comparators = c("~", ">", ">")) # (12 ~ 2) > {} > 1 # the length of comparators doesn't necessarily matter. # If comparators are missing, the existing ones are simply repeated... as.PowerRelation(list(c(1,2), 2, c(), 1), comparators = "~") # (12 ~ 2 ~ {} ~ 1) as.PowerRelation(list(c(1,2), 2, c(), 1), comparators = c("~", ">")) # (12 ~ 2) > ({} ~ 1) # ... or the rest is cut off as.PowerRelation(list(c(1,2), 2, c(), 1), comparators = c("~", ">", "~", "~", ">")) # (12 ~ 2) > ({} ~ 1)
Check if coalitions are indifferent to one another, or, in other words, if they appear in the same equivalence class.
coalitionsAreIndifferent(powerRelation, c1, c2)
coalitionsAreIndifferent(powerRelation, c1, c2)
powerRelation |
A |
c1 |
Coalition vector |
c2 |
Coalition vector |
Logical value TRUE
if c1
and c2
are in the same equivalence class, else FALSE
.
Other lookup functions:
elementLookup()
,
equivalenceClassIndex()
pr <- PowerRelation(list(list(c(1,2)), list(1, 2))) stopifnot(coalitionsAreIndifferent(pr, c(1,2), c(1)) == FALSE) stopifnot(coalitionsAreIndifferent(pr, 2, 1) == TRUE) # Note that it doesn't fail with non-existing power relations stopifnot(coalitionsAreIndifferent(pr, 1, c()) == FALSE) stopifnot(coalitionsAreIndifferent(pr, 3, c(1,2,3)) == TRUE)
pr <- PowerRelation(list(list(c(1,2)), list(1, 2))) stopifnot(coalitionsAreIndifferent(pr, c(1,2), c(1)) == FALSE) stopifnot(coalitionsAreIndifferent(pr, 2, 1) == TRUE) # Note that it doesn't fail with non-existing power relations stopifnot(coalitionsAreIndifferent(pr, 1, c()) == FALSE) stopifnot(coalitionsAreIndifferent(pr, 3, c(1,2,3)) == TRUE)
Based on cpMajorityComparison()
, add or subtract scores
based on how an element fares against the others.
copelandRanking()
returns the corresponding ranking.
copelandScores(powerRelation, elements = powerRelation$elements) copelandRanking(powerRelation)
copelandScores(powerRelation, elements = powerRelation$elements) copelandRanking(powerRelation)
powerRelation |
A |
elements |
Vector of elements of which to calculate their scores.
By default, the scores of all elements in |
Strongly inspired by the Copeland score of social choice theory (Copeland 1951), the Copeland-like solution is based on the net flow of the CP-majority graph (Allouche et al. 2020).
Individuals are ordered according to the number of pairwise winning comparisons, minus the number of pairwise losing comparisons, over the set of all CP-comparisons.
More formally, in a given PowerRelation pr
with element , count the number of elements
where
cpMajorityComparison
(pr, i, j) >= 0
and subtract those where
cpMajorityComparison
(pr, i, j) <= 0
.
Score function returns a list of type CopelandScores
and length of powerRelation$elements
(unless parameter elements
is specified). Each element is a vector of 2 numbers,
the number of pairwise winning comparisons and the number of pairwise losing comparisons.
Those two numbers summed together gives us the actual ordinal Copeland score.
Ranking function returns corresponding SocialRanking
object.
Allouche T, Escoffier B, Moretti S, Öztürk M (2020). “Social Ranking Manipulability for the CP-Majority, Banzhaf and Lexicographic Excellence Solutions.” In Bessiere C (ed.), Proceedings of the Twenty-Ninth International Joint Conference on Artificial Intelligence, IJCAI-20, 17–23. doi:10.24963/ijcai.2020/3, Main track.
Copeland AH (1951). “A reasonable social welfare function.” mimeo, 1951. University of Michigan.
Other CP-majority based functions:
cpMajorityComparison()
,
kramerSimpsonScores()
Other ranking solution functions:
L1Scores()
,
L2Scores()
,
LPSScores()
,
LPScores()
,
cumulativeScores()
,
kramerSimpsonScores()
,
lexcelScores()
,
ordinalBanzhafScores()
# (123 ~ 12 ~ 3 ~ 1) > (2 ~ 23) > 13 pr <- PowerRelation(list( list(c(1,2,3), c(1,2), 3, 1), list(c(2,3), 2), list(c(1,3)) )) copelandScores(pr) # `1` = c(2, -1) # `2` = c(2, -2) # `3` = c(1, -2) # only calculate results for two elements copelandScores(pr, c(1,3)) # `1` = c(2, -1) # `3` = c(1, -2) # or just one element copelandScores(pr, 2) # `2` = c(2, -2) # 1 > 2 > 3 copelandRanking(pr)
# (123 ~ 12 ~ 3 ~ 1) > (2 ~ 23) > 13 pr <- PowerRelation(list( list(c(1,2,3), c(1,2), 3, 1), list(c(2,3), 2), list(c(1,3)) )) copelandScores(pr) # `1` = c(2, -1) # `2` = c(2, -2) # `3` = c(1, -2) # only calculate results for two elements copelandScores(pr, c(1,3)) # `1` = c(2, -1) # `3` = c(1, -2) # or just one element copelandScores(pr, 2) # `2` = c(2, -2) # 1 > 2 > 3 copelandRanking(pr)
The Ceteris Paribus-majority relation compares the relative success between two players joining a coalition.
cpMajorityComparisonScore()
only returns two numbers, a positive number of coalitions where e1
beats e2
,
and a negative number of coalitions where e1
is beaten by e2
.
cpMajorityComparison( powerRelation, e1, e2, strictly = FALSE, includeEmptySet = TRUE ) cpMajorityComparisonScore( powerRelation, e1, e2, strictly = FALSE, includeEmptySet = TRUE )
cpMajorityComparison( powerRelation, e1, e2, strictly = FALSE, includeEmptySet = TRUE ) cpMajorityComparisonScore( powerRelation, e1, e2, strictly = FALSE, includeEmptySet = TRUE )
powerRelation |
A |
e1 , e2
|
Elements in |
strictly |
Only include |
includeEmptySet |
If |
Given two elements and
, go through each coalition
.
then contains all coalitions
where
and
contains all coalitions where
.
The cardinalities
and
represent the score of the two elements, where
if
and
if
.
cpMajorityComparison()
tries to retain all that information. The list returned contains the following information.
Note that in this context the two elements and
refer to element 1 and element 2 respectively.
$e1
: list of information about element 1
$e1$name
: name of element 1
$e1$score
: score .
if
strictly == TRUE
$e1$winningCoalitions
: list of coalition vectors
.
if
strictly == TRUE
$e2
: list of information about element 2
$e2$name
: name of element 2
$e1$score
: score .
if
strictly == TRUE
$e1$winningCoalitions
: list of coalition vectors
.
if
strictly == TRUE
$winner
: name of higher scoring element. NULL
if they are indifferent.
$loser
: name of lower scoring element. NULL
if they are indifferent.
$tuples
: a list of coalitions with:
$tuples[[x]]$coalition
: vector
, the coalition
$tuples[[x]]$included
: logical, TRUE
if and
are in the power relation
$tuples[[x]]$winner
: name of the winning element where
. It is
NULL
if
$tuples[[x]]$e1
: index at which
$tuples[[x]]$e2
: index at which
The much more efficient cpMajorityComparisonScore()
only calculates $e1$score
.
Unlike Lexcel, Ordinal Banzhaf, etc., this power relation can introduce cycles. For this reason the function
cpMajorityComparison()
and cpMajorityComparisonScore()
only offers direct comparisons between two elements
and not a ranking of all players. See the other CP-majority based functions that offer a way to rank all players.
cpMajorityComparison()
returns a list with elements described in the details.
cpMajorityComparisonScore()
returns a vector of two numbers, a positive number of coalitions where e1
beats e2
(), and a negative number of coalitions where
e1
is beaten by e2
().
Haret A, Khani H, Moretti S, Öztürk M (2018). “Ceteris paribus majority for social ranking.” In 27th International Joint Conference on Artificial Intelligence (IJCAI-ECAI-18), 303–309.
Fayard N, Escoffier MÖ (2018). “Ordinal Social ranking: simulation for CP-majority rule.” In DA2PL'2018 (From Multiple Criteria Decision Aid to Preference Learning).
Other CP-majority based functions:
copelandScores()
,
kramerSimpsonScores()
pr <- as.PowerRelation("ac > (a ~ b) > (c ~ bc)") scores <- cpMajorityComparison(pr, "a", "b") scores # a > b # D_ab = {c, {}} # D_ba = {{}} # Score of a = 2 # Score of b = 1 stopifnot(scores$e1$name == "a") stopifnot(scores$e2$name == "b") stopifnot(scores$e1$score == 2) stopifnot(scores$e2$score == 1) stopifnot(scores$e1$score == length(scores$e1$winningCoalitions)) stopifnot(scores$e2$score == length(scores$e2$winningCoalitions)) # get tuples with coalitions S in 2^(N - {i,j}) emptySetTuple <- Filter(function(x) identical(x$coalition, c()), scores$tuples)[[1]] playerCTuple <- Filter(function(x) identical(x$coalition, "c"), scores$tuples)[[1]] # because {}u{a} ~ {}u{b}, there is no winner stopifnot(is.null(emptySetTuple$winner)) stopifnot(emptySetTuple$e1 == emptySetTuple$e2) # because {c}u{a} > {c}u{b}, player "a" gets the score stopifnot(playerCTuple$winner == "a") stopifnot(playerCTuple$e1 < playerCTuple$e2) stopifnot(playerCTuple$e1 == 1L) stopifnot(playerCTuple$e2 == 3L) cpMajorityComparisonScore(pr, "a", "b") # c(1,0) cpMajorityComparisonScore(pr, "b", "a") # c(0,-1)
pr <- as.PowerRelation("ac > (a ~ b) > (c ~ bc)") scores <- cpMajorityComparison(pr, "a", "b") scores # a > b # D_ab = {c, {}} # D_ba = {{}} # Score of a = 2 # Score of b = 1 stopifnot(scores$e1$name == "a") stopifnot(scores$e2$name == "b") stopifnot(scores$e1$score == 2) stopifnot(scores$e2$score == 1) stopifnot(scores$e1$score == length(scores$e1$winningCoalitions)) stopifnot(scores$e2$score == length(scores$e2$winningCoalitions)) # get tuples with coalitions S in 2^(N - {i,j}) emptySetTuple <- Filter(function(x) identical(x$coalition, c()), scores$tuples)[[1]] playerCTuple <- Filter(function(x) identical(x$coalition, "c"), scores$tuples)[[1]] # because {}u{a} ~ {}u{b}, there is no winner stopifnot(is.null(emptySetTuple$winner)) stopifnot(emptySetTuple$e1 == emptySetTuple$e2) # because {c}u{a} > {c}u{b}, player "a" gets the score stopifnot(playerCTuple$winner == "a") stopifnot(playerCTuple$e1 < playerCTuple$e2) stopifnot(playerCTuple$e1 == 1L) stopifnot(playerCTuple$e2 == 3L) cpMajorityComparisonScore(pr, "a", "b") # c(1,0) cpMajorityComparisonScore(pr, "b", "a") # c(0,-1)
Given a vector of elements generate a power set.
createPowerset( elements, includeEmptySet = TRUE, result = c("return", "print", "copy", "printCompact", "copyCompact") )
createPowerset( elements, includeEmptySet = TRUE, result = c("return", "print", "copy", "printCompact", "copyCompact") )
elements |
vector of elements |
includeEmptySet |
If |
result |
What to do with the result. Can be either:
|
List of power set vectors.
If the parameter result
is set to "print"
or "copy"
, nothing is returned.
Instead, a character string is generated that can be used in R to call and create a new PowerRelation
object.
This string is either printed or copied to clipboard (see argument result
).
# normal return type is a list of vectors createPowerset(c("Alice", "Bob"), includeEmptySet = FALSE) ## [[1]] ## [1] "Alice" "Bob" ## ## [[2]] ## [1] "Alice" ## ## [[3]] ## [1] "Bob" # instead of creating a list, print the power set such that it can be copy-pasted # and used to create a new PowerRelation object createPowerset(letters[1:4], result = "print") # prints # as.PowerRelation(" # abcd # > abc # > abd # > acd # > bcd # > ab # ... # > {} # ") createPowerset(letters[1:3], includeEmptySet = FALSE, result = "printCompact") # as.PowerRelation("abc > ab > ac > bc > a > b > c") # create the same string as before, but now copy it to the clipboard instead if(interactive()) { createPowerset(1:3, result = "copyCompact") } # Note that as.PowerRelation(character) only assumes single-char elements. # As such, the generated function call string with multi-character names # looks a little different. createPowerset(c("Alice", "Bob"), result = "print") # PowerRelation(rlang::list2( # list(c("Alice", "Bob")), # list(c("Alice")), # list(c("Bob")), # list(c()), # ))
# normal return type is a list of vectors createPowerset(c("Alice", "Bob"), includeEmptySet = FALSE) ## [[1]] ## [1] "Alice" "Bob" ## ## [[2]] ## [1] "Alice" ## ## [[3]] ## [1] "Bob" # instead of creating a list, print the power set such that it can be copy-pasted # and used to create a new PowerRelation object createPowerset(letters[1:4], result = "print") # prints # as.PowerRelation(" # abcd # > abc # > abd # > acd # > bcd # > ab # ... # > {} # ") createPowerset(letters[1:3], includeEmptySet = FALSE, result = "printCompact") # as.PowerRelation("abc > ab > ac > bc > a > b > c") # create the same string as before, but now copy it to the clipboard instead if(interactive()) { createPowerset(1:3, result = "copyCompact") } # Note that as.PowerRelation(character) only assumes single-char elements. # As such, the generated function call string with multi-character names # looks a little different. createPowerset(c("Alice", "Bob"), result = "print") # PowerRelation(rlang::list2( # list(c("Alice", "Bob")), # list(c("Alice")), # list(c("Bob")), # list(c()), # ))
Calculate cumulative score vectors for each element.
cumulativeScores(powerRelation, elements = powerRelation$elements) cumulativelyDominates(powerRelation, e1, e2, strictly = FALSE)
cumulativeScores(powerRelation, elements = powerRelation$elements) cumulativelyDominates(powerRelation, e1, e2, strictly = FALSE)
powerRelation |
A |
elements |
Vector of elements of which to calculate their scores.
By default, the scores of all elements in |
e1 , e2
|
Elements in |
strictly |
If |
An element's cumulative score vector is calculated by cumulatively adding up the
amount of times it appears in each equivalence class in the powerRelation
.
I.e., in a linear power relation with eight coalitions, if element 1 appears in coalitions placed at 1, 3, and 6,
its score vector is [1, 1, 2, 2, 2, 3, 3, 3].
Score function returns a list of type CumulativeScores
and length of powerRelation$elements
(unless parameter elements
is specified).
Each index contains a vector of length powerRelation$eqs
, cumulatively counting up the number of
times the given element appears in each equivalence class.
cumulativelyDominates()
returns TRUE
if e1
cumulatively dominates e2
, else FALSE
.
dominates
if, for each index
.
strictly dominates
if there exists an
such that
.
Moretti S (2015). “An axiomatic approach to social ranking under coalitional power relations.” Homo Oeconomicus, 32(2), 183–208.
Moretti S, Öztürk M (2017). “Some axiomatic and algorithmic perspectives on the social ranking problem.” In International Conference on Algorithmic Decision Theory, 166–181. Springer.
Other ranking solution functions:
L1Scores()
,
L2Scores()
,
LPSScores()
,
LPScores()
,
copelandScores()
,
kramerSimpsonScores()
,
lexcelScores()
,
ordinalBanzhafScores()
pr <- as.PowerRelation("12 > 1 > 2") # `1`: c(1, 2, 2) # `2`: c(1, 1, 2) cumulativeScores(pr) # calculate for selected number of elements cumulativeScores(pr, c(2)) # TRUE d1 <- cumulativelyDominates(pr, 1, 2) # TRUE d2 <- cumulativelyDominates(pr, 1, 1) # FALSE d3 <- cumulativelyDominates(pr, 1, 1, strictly = TRUE) stopifnot(all(d1, d2, !d3))
pr <- as.PowerRelation("12 > 1 > 2") # `1`: c(1, 2, 2) # `2`: c(1, 1, 2) cumulativeScores(pr) # calculate for selected number of elements cumulativeScores(pr, c(2)) # TRUE d1 <- cumulativelyDominates(pr, 1, 2) # TRUE d2 <- cumulativelyDominates(pr, 1, 1) # FALSE d3 <- cumulativelyDominates(pr, 1, 1, strictly = TRUE) stopifnot(all(d1, d2, !d3))
Check if one element dominates the other.
dominates(powerRelation, e1, e2, strictly = FALSE, includeEmptySet = TRUE)
dominates(powerRelation, e1, e2, strictly = FALSE, includeEmptySet = TRUE)
powerRelation |
A |
e1 , e2
|
Elements in |
strictly |
If |
includeEmptySet |
If |
is said to dominate
if
for all
.
strictly dominates
if there also exists an
such that
.
Logical value TRUE
if e1
dominates e2
, else FALSE
.
pr <- as.PowerRelation("12 > 1 > 2") # TRUE d1 <- dominates(pr, 1, 2) # FALSE d2 <- dominates(pr, 2, 1) # TRUE (because it's not strict dominance) d3 <- dominates(pr, 1, 1) # FALSE d4 <- dominates(pr, 1, 1, strictly = TRUE) stopifnot(all(d1, !d2, d3, !d4))
pr <- as.PowerRelation("12 > 1 > 2") # TRUE d1 <- dominates(pr, 1, 2) # FALSE d2 <- dominates(pr, 2, 1) # TRUE (because it's not strict dominance) d3 <- dominates(pr, 1, 1) # FALSE d4 <- dominates(pr, 1, 1, strictly = TRUE) stopifnot(all(d1, !d2, d3, !d4))
SocialRanking
objectRank elements based on their scores.
doRanking(scores, compare = NULL, decreasing = TRUE)
doRanking(scores, compare = NULL, decreasing = TRUE)
scores |
A vector or list representing each element's score. If |
compare |
Optional comparison function taking in two elements and returning a numerical value based on the relation between
these two elements. If set to |
decreasing |
If |
All ranking solutions in the package are tied to the scores or score vectors of the elements.
For these kinds of solutions, doRanking()
offers a simple way that turns a (named) vector or list of scores for each element into a SocialRanking
object.
For example, doRanking(c(a=1,b=2))
produces b > a
(), because
b
with a score of 2
should be placed higher than a
with a score of 1
.
Ranking solutions in the package include lexcelRanking()
, ordinalBanzhafRanking()
and L1Ranking()
, among others.
These functions take a power relation, calculate the scores of each element and returns a SocialRanking
object.
R natively supports sorting for vectors, but not for lists. If the use of lists is necessary, or if the native sort method in vectors does not produce the desired results, there are two possible ways to solve this:
by the introduction of custom S3 classes, or
by setting the compare
parameter in doRanking()
.
For S3 classes, the class for the score object has to be set and the ==
and >
(and [
for lists) operators overloaded.
I.e., lexcelScores()
returns a list with the custom class LexcelScores
that implements ==.LexcelScores
, >.LexcelScores
, [.LexcelScores
and is.na.LexcelScores
.
In cases where we only want to experiment, introducing new S3 classes can be cumbersome.
As an alternative, the compare
parameter can be assigned a function.
This function must take two parameters, i.e., function(a, b)
, where a
and b
are the scores of two arbitrary elements.
The function then must return one of the following:
> 0
(positive value) if score a
is ranked higher than score b
,
< 0
(negative value) if score a
is ranked lower than score b
, or
= 0
if both scores a
and b
are considered equal.
In doRanking(c(a=3,b=2,c=2), compare = function(a,b) a - b)
, the compare function returns a positive value of the first parameter is larger than the second.
a
has the highest value and will there for be ranked highest, a > b ~ c
.
Conversely, doRanking(c(a=3,b=2,c=2), compare = function(a,b) b - a)
favors elements with lower scores, resulting in the element ranking b ~ c > a
.
A list of type SocialRanking
.
Each element of the list contains a vector of elements in powerRelation$elements
that are indifferent to one another.
doRanking(c(a=1,b=2)) # b > a doRanking(c(a=2,b=2)) # a ~ b # a custom ranking function. Here, we implement the following ranking solution: # disregard any big coalitions and only rank elements based on their individual performances # iRj if and only if {i} >= {j} singletonRanking <- function(pr) { scores <- sapply(pr$elements, equivalenceClassIndex, powerRelation = pr) # note that coalitions in higher indexed equivalence classes are less preferable # hence, scores should be sorted in an increasing order doRanking(scores, decreasing = FALSE) } pr <- as.PowerRelation("abc > ab > ac > b ~ c ~ bc > a") singletonRanking(pr) # b ~ c > a # a reverse lexcel ranking, where vectors are compared right to left # here, we introduce a compare function. It returns: # * 0, if a and b are identical # * a positive value, if a[i] > b[i] and every value after that is equal # * a negative value, if a[i] < b[i] and every value after that is equal reverseLexcelCompare <- function(a, b) { i <- which(a != b) |> rev() if(length(i) == 0) 0 else a[i[1]] - b[i[1]] } scores <- unclass(cumulativeScores(pr)) # R cannot natively sort a class. Instead: # Method 1 - utilize the compare parameter doRanking(scores, compare = reverseLexcelCompare) # Method 2 - introduce S3 class `[.RevLex` <- function(x, i, ...) structure(unclass(x)[i], class = "RevLex") `==.RevLex` <- function(a, b) reverseLexcelCompare(a[[1]],b[[1]]) == 0 `>.RevLex` <- function(a, b) reverseLexcelCompare(a[[1]],b[[1]]) > 0 is.na.RevLex <- function(x) FALSE doRanking(structure(scores, class = "RevLex")) stopifnot( doRanking(scores, compare = reverseLexcelCompare) == doRanking(structure(scores, class = "RevLex")) )
doRanking(c(a=1,b=2)) # b > a doRanking(c(a=2,b=2)) # a ~ b # a custom ranking function. Here, we implement the following ranking solution: # disregard any big coalitions and only rank elements based on their individual performances # iRj if and only if {i} >= {j} singletonRanking <- function(pr) { scores <- sapply(pr$elements, equivalenceClassIndex, powerRelation = pr) # note that coalitions in higher indexed equivalence classes are less preferable # hence, scores should be sorted in an increasing order doRanking(scores, decreasing = FALSE) } pr <- as.PowerRelation("abc > ab > ac > b ~ c ~ bc > a") singletonRanking(pr) # b ~ c > a # a reverse lexcel ranking, where vectors are compared right to left # here, we introduce a compare function. It returns: # * 0, if a and b are identical # * a positive value, if a[i] > b[i] and every value after that is equal # * a negative value, if a[i] < b[i] and every value after that is equal reverseLexcelCompare <- function(a, b) { i <- which(a != b) |> rev() if(length(i) == 0) 0 else a[i[1]] - b[i[1]] } scores <- unclass(cumulativeScores(pr)) # R cannot natively sort a class. Instead: # Method 1 - utilize the compare parameter doRanking(scores, compare = reverseLexcelCompare) # Method 2 - introduce S3 class `[.RevLex` <- function(x, i, ...) structure(unclass(x)[i], class = "RevLex") `==.RevLex` <- function(a, b) reverseLexcelCompare(a[[1]],b[[1]]) == 0 `>.RevLex` <- function(a, b) reverseLexcelCompare(a[[1]],b[[1]]) > 0 is.na.RevLex <- function(x) FALSE doRanking(structure(scores, class = "RevLex")) stopifnot( doRanking(scores, compare = reverseLexcelCompare) == doRanking(structure(scores, class = "RevLex")) )
List coalitions that an element appears in.
elementLookup(powerRelation, element)
elementLookup(powerRelation, element)
powerRelation |
A |
element |
an element in |
This function calls powerRelation$elementLookup(element)
.
The returned list contains tuples containing the index to find the corresponding coalitions in powerRelation$eqs
.
If elementLookup(powerRelation, 2)
returns list(c(1,1), c(1,2), c(3,1))
, we can determine that the element 2
appears twice in equivalence class 1
and once in equivalence class 3
.
The specific coalition then can be accessed with powerRelation$eqs[[i]][[j]]
, where i
is the equivalence class index
and j
is the coalition in that equivalence class containing the element.
List of tuples, each of size 2.
First value of a tuple indicates the equivalence class index,
the second value the index inside that equivalence class with the coalition containing the element.
Returns NULL
if the element does not exist.
Other lookup functions:
coalitionsAreIndifferent()
,
equivalenceClassIndex()
pr <- as.PowerRelation("12 > 2 ~ 1") l <- elementLookup(pr, 1) l # (1,1), (2,2) sapply(l, function(tuple) 1 %in% pr$eqs[[tuple[1]]][[tuple[2]]]) |> all() |> stopifnot() # if element does not exist, it returns NULL elementLookup(pr, 3) |> is.null() |> stopifnot()
pr <- as.PowerRelation("12 > 2 ~ 1") l <- elementLookup(pr, 1) l # (1,1), (2,2) sapply(l, function(tuple) 1 %in% pr$eqs[[tuple[1]]][[tuple[2]]]) |> all() |> stopifnot() # if element does not exist, it returns NULL elementLookup(pr, 3) |> is.null() |> stopifnot()
Given a coalition
vector, return the equivalence class index it appears in.
equivalenceClassIndex(powerRelation, coalition) coalitionLookup(powerRelation, coalition)
equivalenceClassIndex(powerRelation, coalition) coalitionLookup(powerRelation, coalition)
powerRelation |
A |
coalition |
a coalition vector or that is part of |
This function calls powerRelation$coalitionLookup(coalition)
.
equivalenceClassIndex()
serves as an alias to coalitionLookup()
.
Numeric value, equivalence class index containing coalition
.
NULL
if the coalition does not exist.
If the powerRelation
contains cycles, it is possible that multiple values are returned.
Other lookup functions:
coalitionsAreIndifferent()
,
elementLookup()
pr <- as.PowerRelation("12 > 2 ~ 1") (e1 <- equivalenceClassIndex(pr, c(1, 2))) # 1 (e2 <- equivalenceClassIndex(pr, c(1))) # 2 (e3 <- equivalenceClassIndex(pr, c(2))) # 2 (e4 <- equivalenceClassIndex(pr, c())) # NULL <- empty set does not exist stopifnot(all(c(e1,e2,e3,e4) == c(1,2,2)))
pr <- as.PowerRelation("12 > 2 ~ 1") (e1 <- equivalenceClassIndex(pr, c(1, 2))) # 1 (e2 <- equivalenceClassIndex(pr, c(1))) # 2 (e3 <- equivalenceClassIndex(pr, c(2))) # 2 (e4 <- equivalenceClassIndex(pr, c())) # NULL <- empty set does not exist stopifnot(all(c(e1,e2,e3,e4) == c(1,2,2)))
Calculate the Kramer-Simpson-like scores. Higher scores are better.
kramerSimpsonRanking()
returns the corresponding ranking.
kramerSimpsonScores(powerRelation, elements = powerRelation$elements) kramerSimpsonRanking(powerRelation)
kramerSimpsonScores(powerRelation, elements = powerRelation$elements) kramerSimpsonRanking(powerRelation)
powerRelation |
A |
elements |
Vector of elements of which to calculate their scores.
By default, the scores of all elements in |
Inspired by the Kramer-Simpson method of social choice theory (Simpson 1969) (Kramer 1975), the Kramer-Simpson-like method compares each element against all other elements using the CP-Majority rule.
For a given element , calculate the
cpMajorityComparisonScore()
against all elements ,
(notice that
and
are in reverse order).
then
determines the final score, where higher scoring elements are ranked higher (notice the negative symbol in front of the
statement).
The implementation slightly differs from the original definition in Allouche T, Escoffier B, Moretti S, Öztürk M (2020). “Social Ranking Manipulability for the CP-Majority, Banzhaf and Lexicographic Excellence Solutions.” In Bessiere C (ed.), Proceedings of the Twenty-Ninth International Joint Conference on Artificial Intelligence, IJCAI-20, 17–23. doi:10.24963/ijcai.2020/3, Main track.. While the ranking solution itself is the same, the scores for this package are intentionally multiplied by -1, as this significantly improves performance when sorting the elements, as well as making simple comparisons between elements more logical to the user.
Score function returns a vector of type KramerSimpsonScores
and length of powerRelation$elements
(unless parameter elements
is specified). Higher scoring elements are ranked higher.
Ranking function returns corresponding SocialRanking
object.
Allouche T, Escoffier B, Moretti S, Öztürk M (2020). “Social Ranking Manipulability for the CP-Majority, Banzhaf and Lexicographic Excellence Solutions.” In Bessiere C (ed.), Proceedings of the Twenty-Ninth International Joint Conference on Artificial Intelligence, IJCAI-20, 17–23. doi:10.24963/ijcai.2020/3, Main track.
Simpson PB (1969). “On defining areas of voter choice: Professor Tullock on stable voting.” The Quarterly Journal of Economics, 83(3), 478–490.
Kramer GH (1975). “A dynamical model of political equilibrium.” Journal of Economic Theory, 16(2), 310–334.
Other CP-majority based functions:
copelandScores()
,
cpMajorityComparison()
Other ranking solution functions:
L1Scores()
,
L2Scores()
,
LPSScores()
,
LPScores()
,
copelandScores()
,
cumulativeScores()
,
lexcelScores()
,
ordinalBanzhafScores()
# 2 > (1 ~ 3) > 12 > (13 ~ 23) > {} > 123 pr <- as.PowerRelation("2 > (1~3) > 12 > (13~23) > {} > 123") # get scores for all elements # cpMajorityComparisonScore(pr, 2, 1, strictly = TRUE)[1] = 1 # cpMajorityComparisonScore(pr, 3, 1, strictly = TRUE)[1] = 0 # therefore the Kramer-Simpson-Score for element # `1` = -max(0, 1) = -1 # # Score analogous for the other elements # `2` = 0 # `3` = -2 kramerSimpsonScores(pr) # get scores for two elements # `1` = 1 # `3` = 2 kramerSimpsonScores(pr, c(1,3)) # or single element # result is still a list kramerSimpsonScores(pr, 2) # 2 > 1 > 3 kramerSimpsonRanking(pr)
# 2 > (1 ~ 3) > 12 > (13 ~ 23) > {} > 123 pr <- as.PowerRelation("2 > (1~3) > 12 > (13~23) > {} > 123") # get scores for all elements # cpMajorityComparisonScore(pr, 2, 1, strictly = TRUE)[1] = 1 # cpMajorityComparisonScore(pr, 3, 1, strictly = TRUE)[1] = 0 # therefore the Kramer-Simpson-Score for element # `1` = -max(0, 1) = -1 # # Score analogous for the other elements # `2` = 0 # `3` = -2 kramerSimpsonScores(pr) # get scores for two elements # `1` = 1 # `3` = 2 kramerSimpsonScores(pr, c(1,3)) # or single element # result is still a list kramerSimpsonScores(pr, 2) # 2 > 1 > 3 kramerSimpsonRanking(pr)
Calculate the scores.
L1Scores(powerRelation, elements = powerRelation$elements) L1Ranking(powerRelation) lexcel1Scores(powerRelation, elements = powerRelation$elements) lexcel1Ranking(powerRelation)
L1Scores(powerRelation, elements = powerRelation$elements) L1Ranking(powerRelation) lexcel1Scores(powerRelation, elements = powerRelation$elements) lexcel1Ranking(powerRelation)
powerRelation |
A |
elements |
Vector of elements of which to calculate their scores.
By default, the scores of all elements in |
Similar to lexcelRanking()
, the number of times an element appears in each equivalence class is counted.
In addition, we now also consider the size of the coalitions.
Let be a set of elements,
a power relation,
and
its corresponding quotient order.
For an element , construct a matrix
with
columns and
rows.
Whereas each column
represents an equivalence class, each row
corresponds to the coalition size.
The rewards elements that appear in higher ranking coalitions as well as in smaller coalitions.
When comparing two matrices for a power relation, if
,
this suggests that there exists a
and
such that the following holds:
for all
for all
and
Score function returns a list of type L1Scores
and length of powerRelation$elements
(unless parameter elements
is specified).
Each index contains a vector of length powerRelation$eqs
, the number of
times the given element appears in each equivalence class.
Ranking function returns corresponding SocialRanking
object.
Let .
From this, we get the following three matrices:
From and
it
immediately follows that
is ranked above
and
according to
.
Comparing against
we can set
and
.
Following the constraints from the definition above, we can verify that the entire column 1 is identical.
In column 2, we determine that
, whereas
, indicating that
is ranked higher than
, hence
according to
.
For better discoverability, lexcel1Scores()
and lexcel1Ranking()
serve as aliases for L1Scores()
and L1Ranking()
, respectively.
Algaba E, Moretti S, Rémila E, Solal P (2021). “Lexicographic solutions for coalitional rankings.” Social Choice and Welfare, 57(4), 1–33.
Other ranking solution functions:
L2Scores()
,
LPSScores()
,
LPScores()
,
copelandScores()
,
cumulativeScores()
,
kramerSimpsonScores()
,
lexcelScores()
,
ordinalBanzhafScores()
pr <- as.PowerRelation("(123 ~ 13 ~ 2) > (12 ~ 1 ~ 3) > (23 ~ {})") scores <- L1Scores(pr) scores$`1` # [,1] [,2] [,3] # [1,] 0 1 0 # [2,] 1 1 0 # [3,] 1 0 0 L1Ranking(pr) # 2 > 1 > 3
pr <- as.PowerRelation("(123 ~ 13 ~ 2) > (12 ~ 1 ~ 3) > (23 ~ {})") scores <- L1Scores(pr) scores$`1` # [,1] [,2] [,3] # [1,] 0 1 0 # [2,] 1 1 0 # [3,] 1 0 0 L1Ranking(pr) # 2 > 1 > 3
Calculate the scores.
L2Scores(powerRelation, elements = powerRelation$elements) L2Ranking(powerRelation) lexcel2Scores(powerRelation, elements = powerRelation$elements) lexcel2Ranking(powerRelation)
L2Scores(powerRelation, elements = powerRelation$elements) L2Ranking(powerRelation) lexcel2Scores(powerRelation, elements = powerRelation$elements) lexcel2Ranking(powerRelation)
powerRelation |
A |
elements |
Vector of elements of which to calculate their scores.
By default, the scores of all elements in |
Let be a set of elements,
a power relation,
and
its corresponding quotient order.
For an element , construct a matrix
with
columns and
rows.
Whereas each column
represents an equivalence class, each row
corresponds to the coalition size.
Given two elements ,
then ranks
strictly above
if there is some row
and column
such that
,
Note that the conditions are very similar to L1Ranking()
, with the difference that condition 3.(i)
also ranks an element over another if they simply appear more often in an equivalence class, regardless of coalition size.
This implies that a row for condition 3.(ii) to be satisfied may not have to exist.
Score function returns a list of type L2Scores
and length of powerRelation$elements
(unless parameter elements
is specified).
Each index contains a matrix with length(powerRelation$eqs)
columns and 1 + length(powerRelation$elements)
rows.
Ranking function returns corresponding SocialRanking
object.
Let and
,
where
is every other coalition not present in the first equivalence class.
From this, we get the following four matrices:
For the sums in column 1, we get
This immediately puts above all other elements and
above
and
according to the
.
would in this case prefer
over
, simply because
appears once in a coalition of size 1 and
doesn't.
Since the column sum for and
is the same, we can next evaluate if the individual row values are also the same.
Here, since
, this gives an edge of element
over
.
Note that, if the column was identical for and
, we would go to the next column and repeat the process.
Elements are only then considered indifferent from each other, if the entire matrix is identical between the two.
The matrices as described above and in Béal S, Rémila E, Solal P (2022).
“Lexicographic solutions for coalitional rankings based on individual and collective performances.”
Journal of Mathematical Economics, 102, 102738. can be investigated with the L1Scores()
function.
For less complexity, another row is prepended to the matrix showing the sum of each column.
Through this, a simple comparison can be applied.
For better discoverability, lexcel2Scores()
and lexcel2Ranking()
serve as aliases for L2Scores()
and L2Ranking()
, respectively.
Algaba E, Moretti S, Rémila E, Solal P (2021). “Lexicographic solutions for coalitional rankings.” Social Choice and Welfare, 57(4), 1–33.
Other ranking solution functions:
L1Scores()
,
LPSScores()
,
LPScores()
,
copelandScores()
,
cumulativeScores()
,
kramerSimpsonScores()
,
lexcelScores()
,
ordinalBanzhafScores()
pr <- as.PowerRelation("123 ~ 12 ~ 13 ~ 14 ~ 2 ~ 4") pr <- appendMissingCoalitions(pr) scores <- L2Scores(pr) scores$`1` # [,1] [,2] # [1,] 0 1 # [2,] 3 0 # [3,] 1 2 # [3,] 0 1 L2Ranking(pr) # 1 > 2 > 4 > 3 L1Ranking(pr) # 2 > 4 > 1 > 3
pr <- as.PowerRelation("123 ~ 12 ~ 13 ~ 14 ~ 2 ~ 4") pr <- appendMissingCoalitions(pr) scores <- L2Scores(pr) scores$`1` # [,1] [,2] # [1,] 0 1 # [2,] 3 0 # [3,] 1 2 # [3,] 0 1 L2Ranking(pr) # 1 > 2 > 4 > 3 L1Ranking(pr) # 2 > 4 > 1 > 3
Calculate the Lexicographical Excellence (or Lexcel) score.
lexcelRanking()
returns the corresponding ranking.
dualLexcelRanking()
uses the same score vectors but instead of rewarding
participation, it punishes mediocrity.
lexcelScores(powerRelation, elements = powerRelation$elements) lexcelRanking(powerRelation) dualLexcelRanking(powerRelation)
lexcelScores(powerRelation, elements = powerRelation$elements) lexcelRanking(powerRelation) dualLexcelRanking(powerRelation)
powerRelation |
A |
elements |
Vector of elements of which to calculate their scores.
By default, the scores of all elements in |
An equivalence class contains coalitions that are indifferent to one another.
In a given power relation created with
PowerRelation()
or as.PowerRelation()
, the equivalence classes are saved in $eqs
.
As an example, consider the power relation
.
The corresponding equivalence classes are:
The lexcel score of an element is a vector wherein each index indicates the number of times that element appears in the equivalence class. From our example, we would get
Score function returns a list of type LexcelScores
and length of powerRelation$elements
(unless parameter elements
is specified).
Each index contains a vector of length powerRelation$eqs
, the number of
times the given element appears in each equivalence class.
Ranking function returns corresponding SocialRanking
object.
The most "excellent contribution" of an element determines its ranking against the other elements.
Given two Lexcel score vectors
and
, the first index
where
determines which element should be ranked higher.
From the previous example this would be , because:
,
.
The dual lexcel works in reverse order and, instead of rewarding high
scores, punishes mediocrity. In that case we get
because:
and
,
.
Bernardi G, Lucchetti R, Moretti S (2019). “Ranking objects from a preference relation over their subsets.” Social Choice and Welfare, 52(4), 589–606.
Algaba E, Moretti S, Rémila E, Solal P (2021). “Lexicographic solutions for coalitional rankings.” Social Choice and Welfare, 57(4), 1–33.
Serramia M, López-Sánchez M, Moretti S, Rodríguez-Aguilar JA (2021). “On the dominant set selection problem and its application to value alignment.” Autonomous Agents and Multi-Agent Systems, 35(2), 1–38.
Other ranking solution functions:
L1Scores()
,
L2Scores()
,
LPSScores()
,
LPScores()
,
copelandScores()
,
cumulativeScores()
,
kramerSimpsonScores()
,
ordinalBanzhafScores()
# note that the coalition {1} appears twice # 123 > 12 ~ 13 ~ 1 ~ {} > 23 ~ 1 ~ 2 # E = {123} > {12, 13, 1, {}} > {23, 1, 2} pr <- suppressWarnings(as.PowerRelation( "123 > (12 ~ 13 ~ 1 ~ {}) > (23 ~ 1 ~ 2)" )) # lexcel scores for all elements # `1` = c(1, 3, 1) # `2` = c(1, 1, 2) # `3` = c(1, 1, 1) lexcelScores(pr) # lexcel scores for a subset of all elements lexcelScores(pr, c(1, 3)) lexcelScores(pr, 2) # 1 > 2 > 3 lexcelRanking(pr) # 3 > 1 > 2 dualLexcelRanking(pr)
# note that the coalition {1} appears twice # 123 > 12 ~ 13 ~ 1 ~ {} > 23 ~ 1 ~ 2 # E = {123} > {12, 13, 1, {}} > {23, 1, 2} pr <- suppressWarnings(as.PowerRelation( "123 > (12 ~ 13 ~ 1 ~ {}) > (23 ~ 1 ~ 2)" )) # lexcel scores for all elements # `1` = c(1, 3, 1) # `2` = c(1, 1, 2) # `3` = c(1, 1, 1) lexcelScores(pr) # lexcel scores for a subset of all elements lexcelScores(pr, c(1, 3)) lexcelScores(pr, 2) # 1 > 2 > 3 lexcelRanking(pr) # 3 > 1 > 2 dualLexcelRanking(pr)
Calculate the scores.
LPScores(powerRelation, elements = powerRelation$elements) LPRanking(powerRelation) lexcelPScores(powerRelation, elements = powerRelation$elements) lexcelPRanking(powerRelation)
LPScores(powerRelation, elements = powerRelation$elements) LPRanking(powerRelation) lexcelPScores(powerRelation, elements = powerRelation$elements) lexcelPRanking(powerRelation)
powerRelation |
A |
elements |
Vector of elements of which to calculate their scores.
By default, the scores of all elements in |
Let be a set of elements,
a power relation,
and
its corresponding quotient order.
For an element , construct a matrix
with
columns and
rows.
Whereas each column
represents an equivalence class, each row
corresponds to the coalition size.
For , the social ranking solution
then ranks
strictly above
if one of the following conditions hold:
;
and there exists a row
such that:
In R
, given two matrices M_i
and M_j
, this comparison could be expressed as
# function that returns TRUE if i should be ranked strictly above j k_i <- which(M_i[1,] == 1) k_j <- which(M_j[1,] == 1) if(k_i != k_j) return(k_i < k_j) if(k_i == 1) return(FALSE) # get sum for each row # removing the first row implies that we start in row 2 sums_i <- apply(M_i[-1,seq(k_i-1)], 1, sum) sums_j <- apply(M_j[-1,seq(k_j-1)], 1, sum) # apply lexcel comparison i <- which(a != b) return(length(i) > 0 && a[i[1]] > b[i[1]])
Score function returns a list of type LPScores
and length of powerRelation$elements
(unless parameter elements
is specified).
Each index contains a vector of length length(powerRelation$elements)
.
Ranking function returns corresponding SocialRanking
object.
Let .
From this, we get the following three matrices:
in this context refers to the value in the second row and third column of element 2, in this case
.
In the example, will be immediately put above
and
because
and
.
Since
, we next consider the coalitions of size 2. Here, it turns out that
is equal to
.
For obvious reasons the grand coalition does not have to be considered, thus
and
are considered equally powerful by the
solution.
is a social ranking solution belonging to the family of lexicographical ranking functions.
While related to
L1Ranking()
, it incorporates the property of "standardness", stating that if the
singleton coalition , then the ranking solution
should also prefer
over
.
If , then all coalitions from size 2 and upward are inspected,
giving higher precedence to coalitions with a lower number of elements.
While this preference is similar to the
, it differs in two notable ways:
If , then only coalitions
are considered,
From this subset of coalitions, consider the total number of coalitions (or
) belongs to, given each coalition size.
This may ignore information about the distribution of these coalitions within the different equivalence classes,
which
and the slight variation
of the
solution take into account.
The matrices as described above and in Béal S, Rémila E, Solal P (2022).
“Lexicographic solutions for coalitional rankings based on individual and collective performances.”
Journal of Mathematical Economics, 102, 102738. can be investigated with the L1Scores()
function.
For efficiency, LPScores()
discards much of the redundant information.
Instead of a matrix for each element, it returns a vector of size .
Given a score vector v
for an element i
, v[1]
is the position of the singleton coalition {i}
.
This implies that if v[1] < w[1]
, where w
is the score vector of an element j
, then i
is ranked strictly above j
.
v[2]
, v[3]
, ..., v[n]
then indicates the number of coalitions of size 2
, 3
, ..., n
that the element i
appears in.
For better discoverability, lexcelPScores()
and lexcelPRanking()
serve as aliases for LPScores()
and LPRanking()
, respectively.
Béal S, Rémila E, Solal P (2022). “Lexicographic solutions for coalitional rankings based on individual and collective performances.” Journal of Mathematical Economics, 102, 102738.
Other ranking solution functions:
L1Scores()
,
L2Scores()
,
LPSScores()
,
copelandScores()
,
cumulativeScores()
,
kramerSimpsonScores()
,
lexcelScores()
,
ordinalBanzhafScores()
pr <- as.PowerRelation("(123 ~ 13 ~ 2) > (12 ~ 1 ~ 3) > (23 ~ {})") scores <- LPScores(pr) scores$`2` # [1] 1 0 0 LPRanking(pr) # 2 > 1 ~ 3 # Since L^(1) also the relation {1,2}, which ranks above {2,3}, it will place 1 above 3 L1Ranking(pr) # 2 > 1 > 3
pr <- as.PowerRelation("(123 ~ 13 ~ 2) > (12 ~ 1 ~ 3) > (23 ~ {})") scores <- LPScores(pr) scores$`2` # [1] 1 0 0 LPRanking(pr) # 2 > 1 ~ 3 # Since L^(1) also the relation {1,2}, which ranks above {2,3}, it will place 1 above 3 L1Ranking(pr) # 2 > 1 > 3
Calculate the scores.
LPSScores(powerRelation, elements = powerRelation$elements) LPSRanking(powerRelation) lexcelPSScores(powerRelation, elements = powerRelation$elements) lexcelPSRanking(powerRelation)
LPSScores(powerRelation, elements = powerRelation$elements) LPSRanking(powerRelation) lexcelPSScores(powerRelation, elements = powerRelation$elements) lexcelPSRanking(powerRelation)
powerRelation |
A |
elements |
Vector of elements of which to calculate their scores.
By default, the scores of all elements in |
Let be a set of elements,
a power relation,
and
its corresponding quotient order.
For an element , construct a matrix
with
columns and
rows.
Whereas each column
represents an equivalence class, each row
corresponds to the coalition size.
For , the social ranking solution
then ranks
strictly above
if one of the following conditions hold:
;
and there exists a row
and column
such that:
Score function returns a list of type LP*Scores
and length of powerRelation$elements
(unless parameter elements
is specified).
Each index contains a matrix with length(powerRelation$elements)
rows and a variable number of columns, depending on the equivalence class index containing the singleton coalition of that element (matrix can have 0 columns).
Ranking function returns corresponding SocialRanking
object.
Let .
From this, we get the following three matrices:
in this context refers to the value in the second row and third column of element 2, in this case
.
In the example, will be immediately put above
and
because
and
.
Since
, we next consider the coalitions of size 2. Here, it turns out that
,
setting
to be the least preferred option (this is opposed to the
relation, which has no strict preference of
over
).
As alluded to, is similar to
,
LPRanking()
, in that it first considers the singleton coalitions, then sequentially every coalition of size 2 and above that ranks better than the corresponding singleton.
It can be assumed, however, that is more granular, as it doesn't throw away any information about which equivalence class these bigger coalitions belong to.
The matrices as described above and in Béal S, Rémila E, Solal P (2022).
“Lexicographic solutions for coalitional rankings based on individual and collective performances.”
Journal of Mathematical Economics, 102, 102738. can be investigated with the L1Scores()
function.
LPSScores()
discards some redundant information, most notably all columns from each element's singleton class and the ones thereafter.
The first row is also removed, as all values there are guaranteed to be 0.
For the example above, this would actually result in the matrices
matrix(c(1,1, 1,0), nrow=2) matrix(numeric(), nrow=2) matrix(c(0,1, 2,0), nrow=2)
For better discoverability, lexcelPSScores()
and lexcelPSRanking()
serve as aliases for LPSScores()
and LPSRanking()
, respectively.
Béal S, Rémila E, Solal P (2022). “Lexicographic solutions for coalitional rankings based on individual and collective performances.” Journal of Mathematical Economics, 102, 102738.
Other ranking solution functions:
L1Scores()
,
L2Scores()
,
LPScores()
,
copelandScores()
,
cumulativeScores()
,
kramerSimpsonScores()
,
lexcelScores()
,
ordinalBanzhafScores()
pr <- as.PowerRelation("(123 ~ 12 ~ 2) > (13 ~ 23) > (1 ~ 3 ~ {})") scores <- LPSScores(pr) scores$`1` # [,1] [,2] # [1,] 1 1 # [2,] 1 0 scores$`2` # # [1,] # [2,] LPSRanking(pr) # 2 > 1 > 3
pr <- as.PowerRelation("(123 ~ 12 ~ 2) > (13 ~ 23) > (1 ~ 3 ~ {})") scores <- LPSScores(pr) scores$`1` # [,1] [,2] # [1,] 1 1 # [2,] 1 0 scores$`2` # # [1,] # [2,] LPSRanking(pr) # 2 > 1 > 3
Given a powerRelation
object, make its order monotonic.
makePowerRelationMonotonic(powerRelation, addMissingCoalitions = TRUE)
makePowerRelationMonotonic(powerRelation, addMissingCoalitions = TRUE)
powerRelation |
A |
addMissingCoalitions |
If |
A power relation is monotonic if
for every coalition .
Calling makePowerRelationMonotonic()
on some PowerRelation
object moves or adds coalitions to certain equivalence classes
so that the power relation becomes monotonic.
PowerRelation
object containing the following values:
$elements
: vector of elements
$eqs
: equivalence classes. Nested list of lists, each containing vectors representing groups of elements in the same equivalence class
$coalitionLookup
: function(v)
taking a coalition vector v
and returning the equivalence class it belongs to. See coalitionLookup()
for more.
$elementLookup
: function(e)
taking an element e
and returning a list of 2-sized tuples. See elementLookup()
for more.
Other helper functions for transforming power relations:
appendMissingCoalitions()
pr <- as.PowerRelation("ab > ac > abc > b > a > {} > c > bc") makePowerRelationMonotonic(pr) # (abc ~ ab) > ac > (bc ~ b) > a > (c ~ {}) # notice that missing coalitions are automatically added, # except for the empty set pr <- as.PowerRelation("a > b > c") makePowerRelationMonotonic(pr) # (abc ~ ab ~ ac ~ a) > (bc ~ b) > c # setting addMissingCoalitions to FALSE changes this behavior pr <- as.PowerRelation("a > ab > c ~ {} > b") makePowerRelationMonotonic(pr, addMissingCoalitions = FALSE) # (ab ~ a) > (b ~ c ~ {}) # notice that an equivalence class containing an empty coalition # automatically moves all remaining coalitions to that equivalence class. pr <- as.PowerRelation("a > {} > b > c") makePowerRelationMonotonic(pr) # (abc ~ ab ~ ac ~ a) > (bc ~ b ~ c ~ {})
pr <- as.PowerRelation("ab > ac > abc > b > a > {} > c > bc") makePowerRelationMonotonic(pr) # (abc ~ ab) > ac > (bc ~ b) > a > (c ~ {}) # notice that missing coalitions are automatically added, # except for the empty set pr <- as.PowerRelation("a > b > c") makePowerRelationMonotonic(pr) # (abc ~ ab ~ ac ~ a) > (bc ~ b) > c # setting addMissingCoalitions to FALSE changes this behavior pr <- as.PowerRelation("a > ab > c ~ {} > b") makePowerRelationMonotonic(pr, addMissingCoalitions = FALSE) # (ab ~ a) > (b ~ c ~ {}) # notice that an equivalence class containing an empty coalition # automatically moves all remaining coalitions to that equivalence class. pr <- as.PowerRelation("a > {} > b > c") makePowerRelationMonotonic(pr) # (abc ~ ab ~ ac ~ a) > (bc ~ b ~ c ~ {})
Deprecated. Use PowerRelation()
instead.
newPowerRelation(...)
newPowerRelation(...)
... |
Any parameter. |
No return value.
PowerRelation
objectDeprecated. Use as.PowerRelation()
instead.
newPowerRelationFromString(...)
newPowerRelationFromString(...)
... |
Any parameter. |
No return value.
Calculate the Ordinal Banzhaf scores, the number of positive and the number of negative marginal contributions.
ordinalBanzhafRanking()
returns the corresponding ranking.
ordinalBanzhafScores(powerRelation, elements = powerRelation$elements) ordinalBanzhafRanking(powerRelation)
ordinalBanzhafScores(powerRelation, elements = powerRelation$elements) ordinalBanzhafRanking(powerRelation)
powerRelation |
A |
elements |
Vector of elements of which to calculate their scores.
By default, the scores of all elements in |
Inspired by the Banzhaf index (Banzhaf III 1964), the Ordinal Banzhaf
determines the score of element by adding the amount of coalitions
its contribution impacts positively (
)
and subtracting the amount of coalitions where its contribution
had a negative impact (
)(Khani et al. 2019).
The original definition only takes total power relations into account, where either or
for every
.
If coalitions are missing from the power relation, we may not be able to perform certain comparisons.
To indicate these missing comparisons, the ordinal Banzhaf score of an element
also includes that number at index
3
.
I.e., if the ordinal Banzhaf score of an element is c(4, -2, 1)
, it means that it contributed positively to 4
coalitions and negatively to 2
others.
For one coalition, no comparison could be made.
Score function returns list of class type OrdinalBanzhafScores
and length of powerRelation$elements
.
Each index contains a vector of three numbers, the number of positive marginal contributions, the number of negative marginal contributions, and the number of coalitions for which no comparison could be done.
The first two numbers summed together gives us the actual ordinal Banzhaf score.
Ranking function returns corresponding SocialRanking
object.
Khani H, Moretti S, Öztürk M (2019). “An ordinal banzhaf index for social ranking.” In 28th International Joint Conference on Artificial Intelligence (IJCAI 2019), 378–384.
Banzhaf III JF (1964). “Weighted voting doesn't work: A mathematical analysis.” Rutgers L. Rev., 19, 317.
Other ranking solution functions:
L1Scores()
,
L2Scores()
,
LPSScores()
,
LPScores()
,
copelandScores()
,
cumulativeScores()
,
kramerSimpsonScores()
,
lexcelScores()
pr <- as.PowerRelation("12 > (2 ~ {}) > 1") # Player 1 contributes positively to {2} # Player 1 contributes negatively to {empty set} # Therefore player 1 has a score of 1 - 1 = 0 # # Player 2 contributes positively to {1} # Player 2 does NOT have an impact on {empty set} # Therefore player 2 has a score of 1 - 0 = 0 ordinalBanzhafScores(pr) # `1` = c(1, -1, 0) # `2` = c(1, 0, 0) ordinalBanzhafRanking(pr) # 1 > 2
pr <- as.PowerRelation("12 > (2 ~ {}) > 1") # Player 1 contributes positively to {2} # Player 1 contributes negatively to {empty set} # Therefore player 1 has a score of 1 - 1 = 0 # # Player 2 contributes positively to {1} # Player 2 does NOT have an impact on {empty set} # Therefore player 2 has a score of 1 - 0 = 0 ordinalBanzhafScores(pr) # `1` = c(1, -1, 0) # `2` = c(1, 0, 0) ordinalBanzhafRanking(pr) # 1 > 2
Create a PowerRelation
object.
PowerRelation( equivalenceClasses, elements = NULL, coalitionLookup = NULL, elementLookup = NULL ) is.PowerRelation(x, ...) ## S3 method for class 'PowerRelation' print(x, ...)
PowerRelation( equivalenceClasses, elements = NULL, coalitionLookup = NULL, elementLookup = NULL ) is.PowerRelation(x, ...) ## S3 method for class 'PowerRelation' print(x, ...)
equivalenceClasses |
A nested list of lists, each containing coalitions or groups represented as vectors that are in the same equivalence class. |
elements |
Vector of elements in power relation. Only set this value if you know what you are doing. See Details for more. |
coalitionLookup |
A function taking a vector parameter and returning an index. See return value for more details. Only set this value if you know what you are doing. |
elementLookup |
A function taking an element and returning a list of 2-sized tuples. See return value for more details. Only set this value if you know what you are doing. |
x |
An R object. |
... |
Additional arguments to be passed to or from methods. |
A power relation describes the ordinal information between elements. Here specifically, we are interested in the power relation between coalitions, or groups of elements. Each coalition is assumed to be a vector containing zero (empty coalition), one (singleton) or more elements.
createPowerset()
offers a convenient way of creating a power set over a set of elements that can be used to call PowerRelation()
or as.PowerRelation()
.
Trying to figure out what equivalence class certain coalitions or elements belong to is quite common.
For these sets of problems, the functions $coalitionLookup(v)
and $elementLookup(e)
should be utilized.
We use some redundancy to speed up the lookup methods.
As such, it is highly discouraged to edit a PowerRelation
object directly, as the different power relation representations will fall out of sync.
For more information, see the vignette: vignette(package = 'socialranking')
The PowerRelation()
function expects a nested list of coalitions as input. For alternatives, see as.PowerRelation()
.
PowerRelation
object containing the following values:
$elements
: vector of elements
$eqs
: equivalence classes. Nested list of lists, each containing vectors representing groups of elements in the same equivalence class
$coalitionLookup
: function(v)
taking a coalition vector v
and returning the equivalence class it belongs to. See coalitionLookup()
for more.
$elementLookup
: function(e)
taking an element e
and returning a list of 2-sized tuples. See elementLookup()
for more.
Let be a finite set of elements (also called players).
Any subset
is considered to be a group or coalition of elements,
where
is referred to as the empty coalition,
as a singleton (a coalition of size 1), and
as the grand coalition.
The power set
denotes the set of all subsets over
.
Let be a collection of coalitions.
A power relation on
is a total preorder
.
That is, for any two coalitions
, either
, or
, or both.
In other words, we can compare any two groups of elements in
and determine, if one group is better than, worse than, or equivalent to the other.
More commonly, the relation is notated as
.
denotes the family of all power relations on every collection
.
Given a power relation
,
denotes its symmetric part whereas
its asymmetric part.
Let
.
Then,
Coalitions which are deemed equivalent () can be collected into an equivalence class
.
The list of equivalence classes forms a linear order,
.
As an example, consider the elements .
Each of them individually may go well with pancakes, but we are also interested in the combination of condiments.
If we consider all possibilities, we will have to compare the sets
Looking for a way to rank this group of objects, one may arrive at the following total preorder :
In this particular case, we get five equivalence classes.
The power relation can be copy-pasted as a character string to the
as.PowerRelation()
function (it should accept the special characters and
).
as.PowerRelation("{b,c} > ({a} ~ {c}) > {b} > {} > ({a,b,c} ~ {a,b} ~ {a,c})")
Moretti S, Öztürk M (2017). “Some axiomatic and algorithmic perspectives on the social ranking problem.” In International Conference on Algorithmic Decision Theory, 166–181. Springer.
Bernardi G, Lucchetti R, Moretti S (2019). “Ranking objects from a preference relation over their subsets.” Social Choice and Welfare, 52(4), 589–606.
Algaba E, Moretti S, Rémila E, Solal P (2021). “Lexicographic solutions for coalitional rankings.” Social Choice and Welfare, 57(4), 1–33.
Other ways to create a PowerRelation()
object using as.PowerRelation()
.
pr <- PowerRelation(list( list(c(1,2,3)), list(c(1, 2), 2, 3), list(c(2, 3), c()), list(c(1, 3)), list(1) )) pr # 123 > (12 ~ 2 ~ 3) > (23 ~ {}) > 13 > 1 stopifnot(pr$elements == 1:3) stopifnot(pr$coalitionLookup(1) == 5) stopifnot(pr$coalitionLookup(c()) == 3) stopifnot(pr$coalitionLookup(c(1,2)) == 2) # find coalitions an element appears in for(t in pr$elementLookup(2)) { stopifnot(2 %in% pr$eqs[[t[1]]][[t[2]]]) } # use createPowerset to help generate a valid function call if(interactive()) createPowerset(letters[1:3], result = "copy") # pasted, rearranged using alt+up / alt+down in RStudio # note that the function call looks different if elements are multiple characters long if(interactive()) createPowerset(c("apple", "banana", "chocolate"), result = "copy") # pasted clipboard PowerRelation(rlang::list2( list(c("banana", "chocolate")), list(c("apple"), c("chocolate")), list(c("banana")), list(c()), list(c("apple", "banana", "chocolate"), c("apple", "banana"), c("apple", "chocolate")), )) # {banana, chocolate} > ({apple} ~ {chocolate}) > {banana} > {} > ...
pr <- PowerRelation(list( list(c(1,2,3)), list(c(1, 2), 2, 3), list(c(2, 3), c()), list(c(1, 3)), list(1) )) pr # 123 > (12 ~ 2 ~ 3) > (23 ~ {}) > 13 > 1 stopifnot(pr$elements == 1:3) stopifnot(pr$coalitionLookup(1) == 5) stopifnot(pr$coalitionLookup(c()) == 3) stopifnot(pr$coalitionLookup(c(1,2)) == 2) # find coalitions an element appears in for(t in pr$elementLookup(2)) { stopifnot(2 %in% pr$eqs[[t[1]]][[t[2]]]) } # use createPowerset to help generate a valid function call if(interactive()) createPowerset(letters[1:3], result = "copy") # pasted, rearranged using alt+up / alt+down in RStudio # note that the function call looks different if elements are multiple characters long if(interactive()) createPowerset(c("apple", "banana", "chocolate"), result = "copy") # pasted clipboard PowerRelation(rlang::list2( list(c("banana", "chocolate")), list(c("apple"), c("chocolate")), list(c("banana")), list(c()), list(c("apple", "banana", "chocolate"), c("apple", "banana"), c("apple", "chocolate")), )) # {banana, chocolate} > ({apple} ~ {chocolate}) > {banana} > {} > ...
Based on a list of coalitions, create a generator function that returns a new PowerRelation
object with every call.
NULL
is returned once every possible power relation has been generated.
Alternatively, use generateRandomPowerRelation()
to create random power relations.
powerRelationGenerator(coalitions, startWithLinearOrder = FALSE) generateNextPartition(gen) generateRandomPowerRelation(coalitions, linearOrder = FALSE, monotonic = FALSE)
powerRelationGenerator(coalitions, startWithLinearOrder = FALSE) generateNextPartition(gen) generateRandomPowerRelation(coalitions, linearOrder = FALSE, monotonic = FALSE)
coalitions |
List of coalition vectors. An empty coalition can be set with |
startWithLinearOrder |
If set to |
gen |
A generator object returned by |
linearOrder |
logical, if TRUE, only linear orders are generated. |
monotonic |
logical, if TRUE, only monotonic power relations are created (see |
Using the partitions
library, partitions::compositions()
is used to create all possible partitions over the set of coalitions.
For every partition, partitions::multinomial()
is used to create all permutations over the order of the coalitions.
Note that the number of power relations (or total preorders) grows incredibly fast.
The Stirling number of second kind gives us the number of
partitions over
elements.
For example, with 4 coalitions (n = 4) there are 6 ways to split it into k = 3 partitions.
The sum of all partitions of any size is also known as the Bell number (, see also
numbers::bell()
).
Regarding total preorders over a set
, the Stirling number of second kind can be used to determine the number of all possible total preorders
.
In literature, it is referred to as the ordered Bell number or Fubini number.
In the context of social rankings we may consider total preorders over the set of coalitions for a given set of elements or players
.
Here, the number of coalitions doubles with every new element.
The number of preorders then are:
# of elements | # of coalitions | # of total preorders | 1ms / computation |
0 | 1 | 1 | 1ms |
1 | 2 | 3 | 3ms |
2 | 4 | 75 | 75ms |
3 | 7 (w/o empty set) | 47,293 | 47 seconds |
3 | 8 | 545,835 | 9 minutes |
4 | 15 (w/o empty set) | 230,283,190,977,853 | 7,302 years |
4 | 16 | 5,315,654,681,981,355 | 168,558 years |
A generator function.
Every time this generator function is called, a different PowerRelation
object is returned.
Once all possible power relations have been generated, the generator function returns NULL
.
A generator function. If the generator is already down to its last partition, it will throw an error.
Use generateNextPartition(gen)
to skip to the next partition of the generator.
Due to its implementation, randomPowerRelation()
does not create weak orders uniformly.
I.e., it is much less likely to generate linear orders even though they have the proportionally highest representation
in the set of all weak orders.
coalitions <- createPowerset(c('a','b'), includeEmptySet = FALSE) # list(c('a','b'), 'a', 'b') gen <- powerRelationGenerator(coalitions) while(!is.null(pr <- gen())) { print(pr) } # (ab ~ a ~ b) # (ab ~ a) > b # (ab ~ b) > a # (a ~ b) > ab # ab > (a ~ b) # a > (ab ~ b) # b > (ab ~ a) # ab > a > b # ab > b > a # a > ab > b # b > ab > a # a > b > ab # b > a > ab # from now on, gen() always returns NULL gen() # NULL # Use generateNextPartition() to skip certain partitions gen <- powerRelationGenerator(coalitions) gen <- generateNextPartition(gen) gen <- generateNextPartition(gen) gen() # ab > (a ~ b) gen <- generateNextPartition(gen) gen() # ab > a > b coalitions <- createPowerset(c('a','b'), includeEmptySet = FALSE) # list(c('a','b'), 'a', 'b') gen <- powerRelationGenerator(coalitions) gen() # (ab ~ a ~ b) gen() # (ab ~ b) > a # skipping partition of size two, where the first partition has # 2 coalitions and the second partition has 1 coalition gen <- generateNextPartition(gen) gen() # ab > (a ~ b) # only remaining partition is one of size 3, wherein each # equivalence class is of size 1 gen <- generateNextPartition(gen) gen() # ab > a > b # went through all partitions, it will only generate NULL now gen <- generateNextPartition(gen) stopifnot(is.null(gen())) # create random power relation generateRandomPowerRelation(coalitions) # make sure it's monotonic, i.e., {1} > {1,2} cannot exist # because {1} is a subset of {1,2} generateRandomPowerRelation(coalitions, monotonic = TRUE)
coalitions <- createPowerset(c('a','b'), includeEmptySet = FALSE) # list(c('a','b'), 'a', 'b') gen <- powerRelationGenerator(coalitions) while(!is.null(pr <- gen())) { print(pr) } # (ab ~ a ~ b) # (ab ~ a) > b # (ab ~ b) > a # (a ~ b) > ab # ab > (a ~ b) # a > (ab ~ b) # b > (ab ~ a) # ab > a > b # ab > b > a # a > ab > b # b > ab > a # a > b > ab # b > a > ab # from now on, gen() always returns NULL gen() # NULL # Use generateNextPartition() to skip certain partitions gen <- powerRelationGenerator(coalitions) gen <- generateNextPartition(gen) gen <- generateNextPartition(gen) gen() # ab > (a ~ b) gen <- generateNextPartition(gen) gen() # ab > a > b coalitions <- createPowerset(c('a','b'), includeEmptySet = FALSE) # list(c('a','b'), 'a', 'b') gen <- powerRelationGenerator(coalitions) gen() # (ab ~ a ~ b) gen() # (ab ~ b) > a # skipping partition of size two, where the first partition has # 2 coalitions and the second partition has 1 coalition gen <- generateNextPartition(gen) gen() # ab > (a ~ b) # only remaining partition is one of size 3, wherein each # equivalence class is of size 1 gen <- generateNextPartition(gen) gen() # ab > a > b # went through all partitions, it will only generate NULL now gen <- generateNextPartition(gen) stopifnot(is.null(gen())) # create random power relation generateRandomPowerRelation(coalitions) # make sure it's monotonic, i.e., {1} > {1,2} cannot exist # because {1} is a subset of {1,2} generateRandomPowerRelation(coalitions, monotonic = TRUE)
For a given PowerRelation
object create a relations::relation()
object.
powerRelationMatrix( powerRelation, domainNames = c("pretty", "numericPrec", "numeric") ) ## S3 method for class 'PowerRelation' as.relation(x, ...)
powerRelationMatrix( powerRelation, domainNames = c("pretty", "numericPrec", "numeric") ) ## S3 method for class 'PowerRelation' as.relation(x, ...)
powerRelation |
A |
domainNames |
How should the row and column names be formatted?
|
x |
A |
... |
Further parameters (ignored) |
Turn a PowerRelation
object into a relations::relation()
object. The incidence matrix can be viewed with
relations::relation_incidence()
.
The columns and rows of a PowerRelation
object are ordered by TODO powerRelation$rankingCoalitions
.
The relations
package automatically sorts the columns and rows by their domain names, which is the reason the
parameter domainNames
is included. This way we ensure that the columns and rows are sorted by
the order of the power relation.
relations::relation()
object to the corresponding power relation.
A PowerRelation
object is defined as being transitive. If a power relation includes a cycle,
meaning that the same coalition appears twice in the ranking, all coalitions within that cycle will be considered
to be indifferent from one another.
For example, given the power relation ,
the relation is somewhat equivalent to
. There is no way
to check for cycles in the incidence matrix only.
Call transitiveClosure()
to remove cycles in a PowerRelation
object.
pr <- as.PowerRelation("12 > 1 > 2") relation <- powerRelationMatrix(pr) # do relation stuff # Incidence matrix # 111 # 011 # 001 relations::relation_incidence(relation) # all TRUE stopifnot(all( relations::relation_is_acyclic(relation), relations::relation_is_antisymmetric(relation), relations::relation_is_linear_order(relation), relations::relation_is_complete(relation), relations::relation_is_reflexive(relation), relations::relation_is_transitive(relation) )) # a power relation where coalitions {1} and {2} are indifferent pr <- as.PowerRelation("12 > (1 ~ 2)") relation <- powerRelationMatrix(pr) # Incidence matrix # 111 # 011 # 011 relations::relation_incidence(relation) # FALSE stopifnot(!any( relations::relation_is_acyclic(relation), relations::relation_is_antisymmetric(relation), relations::relation_is_linear_order(relation) )) # TRUE stopifnot(all( relations::relation_is_complete(relation), relations::relation_is_reflexive(relation), relations::relation_is_transitive(relation) )) # a pr with cycles pr <- suppressWarnings(as.PowerRelation("12 > 1 > 2 > 1")) relation <- powerRelationMatrix(pr) # Incidence matrix # 1111 # 0111 # 0111 # 0111 relations::relation_incidence(relation) # custom naming convention relation <- powerRelationMatrix( pr, function(x) paste0(letters[x], ":", paste(pr$rankingCoalitions[[x]], collapse = "|")) ) relations::relation_incidence(relation) # Incidences: # a:1|2 b:1 c:2 d:1 # a:1|2 1 1 1 1 # b:1 0 1 1 1 # c:2 0 1 1 1 # d:1 0 1 1 1
pr <- as.PowerRelation("12 > 1 > 2") relation <- powerRelationMatrix(pr) # do relation stuff # Incidence matrix # 111 # 011 # 001 relations::relation_incidence(relation) # all TRUE stopifnot(all( relations::relation_is_acyclic(relation), relations::relation_is_antisymmetric(relation), relations::relation_is_linear_order(relation), relations::relation_is_complete(relation), relations::relation_is_reflexive(relation), relations::relation_is_transitive(relation) )) # a power relation where coalitions {1} and {2} are indifferent pr <- as.PowerRelation("12 > (1 ~ 2)") relation <- powerRelationMatrix(pr) # Incidence matrix # 111 # 011 # 011 relations::relation_incidence(relation) # FALSE stopifnot(!any( relations::relation_is_acyclic(relation), relations::relation_is_antisymmetric(relation), relations::relation_is_linear_order(relation) )) # TRUE stopifnot(all( relations::relation_is_complete(relation), relations::relation_is_reflexive(relation), relations::relation_is_transitive(relation) )) # a pr with cycles pr <- suppressWarnings(as.PowerRelation("12 > 1 > 2 > 1")) relation <- powerRelationMatrix(pr) # Incidence matrix # 1111 # 0111 # 0111 # 0111 relations::relation_incidence(relation) # custom naming convention relation <- powerRelationMatrix( pr, function(x) paste0(letters[x], ":", paste(pr$rankingCoalitions[[x]], collapse = "|")) ) relations::relation_incidence(relation) # Incidences: # a:1|2 b:1 c:2 d:1 # a:1|2 1 1 1 1 # b:1 0 1 1 1 # c:2 0 1 1 1 # d:1 0 1 1 1
On a given PowerRelation
object pr
, check if e1
relates to e2
based on the given social ranking solution.
testRelation(powerRelation, e1) powerRelation %:% e1 pr_e1 %>=dom% e2 pr_e1 %>dom% e2 pr_e1 %>=cumuldom% e2 pr_e1 %>cumuldom% e2 pr_e1 %>=cp% e2 pr_e1 %>cp% e2 pr_e1 %>=banz% e2 pr_e1 %>banz% e2 pr_e1 %>=cop% e2 pr_e1 %>cop% e2 pr_e1 %>=ks% e2 pr_e1 %>ks% e2 pr_e1 %>=lex% e2 pr_e1 %>lex% e2 pr_e1 %>=duallex% e2 pr_e1 %>duallex% e2 pr_e1 %>=L1% e2 pr_e1 %>L1% e2 pr_e1 %>=L2% e2 pr_e1 %>L2% e2 pr_e1 %>=LP% e2 pr_e1 %>LP% e2 pr_e1 %>=LPS% e2 pr_e1 %>LPS% e2
testRelation(powerRelation, e1) powerRelation %:% e1 pr_e1 %>=dom% e2 pr_e1 %>dom% e2 pr_e1 %>=cumuldom% e2 pr_e1 %>cumuldom% e2 pr_e1 %>=cp% e2 pr_e1 %>cp% e2 pr_e1 %>=banz% e2 pr_e1 %>banz% e2 pr_e1 %>=cop% e2 pr_e1 %>cop% e2 pr_e1 %>=ks% e2 pr_e1 %>ks% e2 pr_e1 %>=lex% e2 pr_e1 %>lex% e2 pr_e1 %>=duallex% e2 pr_e1 %>duallex% e2 pr_e1 %>=L1% e2 pr_e1 %>L1% e2 pr_e1 %>=L2% e2 pr_e1 %>L2% e2 pr_e1 %>=LP% e2 pr_e1 %>LP% e2 pr_e1 %>=LPS% e2 pr_e1 %>LPS% e2
powerRelation |
A |
e1 , e2
|
Elements in |
pr_e1 |
|
The function testRelation
is somewhat only used to make the offered comparison operators in the package better discoverable.
testRelation(pr, e1)
is equivalent to pr %:% e1
and list(pr, e1)
. It should be used together with one of the
comparison operators listed in the usage section.
testRelation()
and %:%
returns list(powerRelation, e1)
.
Followed by a %>=comparison%
or %>comparison%
it returns TRUE
or FALSE
, depending on the relation between
e1
and e2
.
Comparison function: dominates()
, cumulativelyDominates()
, cpMajorityComparison()
.
Score Functions: ordinalBanzhafScores()
, copelandScores()
, kramerSimpsonScores()
, lexcelScores()
.
pr <- as.PowerRelation("123 > 12 ~ 13 ~ 23 > 3 > 1 ~ 2 > {}") # Dominance stopifnot(pr %:% 1 %>=dom% 2) # Strict dominance stopifnot((pr %:% 1 %>dom% 2) == FALSE) # Cumulative dominance stopifnot(pr %:% 1 %>=cumuldom% 2) # Strict cumulative dominance stopifnot((pr %:% 1 %>cumuldom% 2) == FALSE) # CP-Majority relation stopifnot(pr %:% 1 %>=cp% 2) # Strict CP-Majority relation stopifnot((pr %:% 1 %>cp% 2) == FALSE) # Ordinal banzhaf relation stopifnot(pr %:% 1 %>=banz% 2) # Strict ordinal banzhaf relation # (meaning 1 had a strictly higher positive contribution than 2) stopifnot((pr %:% 1 %>banz% 2) == FALSE) # Copeland-like method stopifnot(pr %:% 1 %>=cop% 2) stopifnot(pr %:% 2 %>=cop% 1) # Strict Copeland-like method # (meaning pairwise winning minus pairwise losing comparison of # 1 is strictly higher than of 2) stopifnot((pr %:% 1 %>cop% 2) == FALSE) stopifnot((pr %:% 2 %>cop% 1) == FALSE) stopifnot(pr %:% 3 %>cop% 1) # Kramer-Simpson-like method stopifnot(pr %:% 1 %>=ks% 2) stopifnot(pr %:% 2 %>=ks% 1) # Strict Kramer-Simpson-like method # (meaning ks-score of 1 is actually higher than 2) stopifnot((pr %:% 2 %>ks% 1) == FALSE) stopifnot((pr %:% 1 %>ks% 2) == FALSE) stopifnot(pr %:% 3 %>ks% 1) # Lexicographical and dual lexicographical excellence stopifnot(pr %:% 3 %>=lex% 1) stopifnot(pr %:% 3 %>=duallex% 1) # Strict lexicographical and dual lexicographical excellence # (meaning their lexicographical scores don't match) stopifnot(pr %:% 3 %>lex% 1) stopifnot(pr %:% 3 %>duallex% 1) # L^(1) and L^(2) stopifnot(pr %:% 1 %>=L1% 2) stopifnot(pr %:% 1 %>=L2% 2) # Strict L^(1) and L^(2) stopifnot((pr %:% 1 %>L1% 2) == FALSE) stopifnot(pr %:% 3 %>L1% 1) stopifnot((pr %:% 1 %>L2% 2) == FALSE) stopifnot(pr %:% 3 %>L2% 1) # L^p and L^p* stopifnot(pr %:% 1 %>=LP% 2) stopifnot(pr %:% 1 %>=LPS% 2) # Strict L^(1) and L^(2) stopifnot((pr %:% 1 %>LP% 2) == FALSE) stopifnot(pr %:% 3 %>LP% 1) stopifnot((pr %:% 1 %>LPS% 2) == FALSE) stopifnot(pr %:% 3 %>LPS% 1)
pr <- as.PowerRelation("123 > 12 ~ 13 ~ 23 > 3 > 1 ~ 2 > {}") # Dominance stopifnot(pr %:% 1 %>=dom% 2) # Strict dominance stopifnot((pr %:% 1 %>dom% 2) == FALSE) # Cumulative dominance stopifnot(pr %:% 1 %>=cumuldom% 2) # Strict cumulative dominance stopifnot((pr %:% 1 %>cumuldom% 2) == FALSE) # CP-Majority relation stopifnot(pr %:% 1 %>=cp% 2) # Strict CP-Majority relation stopifnot((pr %:% 1 %>cp% 2) == FALSE) # Ordinal banzhaf relation stopifnot(pr %:% 1 %>=banz% 2) # Strict ordinal banzhaf relation # (meaning 1 had a strictly higher positive contribution than 2) stopifnot((pr %:% 1 %>banz% 2) == FALSE) # Copeland-like method stopifnot(pr %:% 1 %>=cop% 2) stopifnot(pr %:% 2 %>=cop% 1) # Strict Copeland-like method # (meaning pairwise winning minus pairwise losing comparison of # 1 is strictly higher than of 2) stopifnot((pr %:% 1 %>cop% 2) == FALSE) stopifnot((pr %:% 2 %>cop% 1) == FALSE) stopifnot(pr %:% 3 %>cop% 1) # Kramer-Simpson-like method stopifnot(pr %:% 1 %>=ks% 2) stopifnot(pr %:% 2 %>=ks% 1) # Strict Kramer-Simpson-like method # (meaning ks-score of 1 is actually higher than 2) stopifnot((pr %:% 2 %>ks% 1) == FALSE) stopifnot((pr %:% 1 %>ks% 2) == FALSE) stopifnot(pr %:% 3 %>ks% 1) # Lexicographical and dual lexicographical excellence stopifnot(pr %:% 3 %>=lex% 1) stopifnot(pr %:% 3 %>=duallex% 1) # Strict lexicographical and dual lexicographical excellence # (meaning their lexicographical scores don't match) stopifnot(pr %:% 3 %>lex% 1) stopifnot(pr %:% 3 %>duallex% 1) # L^(1) and L^(2) stopifnot(pr %:% 1 %>=L1% 2) stopifnot(pr %:% 1 %>=L2% 2) # Strict L^(1) and L^(2) stopifnot((pr %:% 1 %>L1% 2) == FALSE) stopifnot(pr %:% 3 %>L1% 1) stopifnot((pr %:% 1 %>L2% 2) == FALSE) stopifnot(pr %:% 3 %>L2% 1) # L^p and L^p* stopifnot(pr %:% 1 %>=LP% 2) stopifnot(pr %:% 1 %>=LPS% 2) # Strict L^(1) and L^(2) stopifnot((pr %:% 1 %>LP% 2) == FALSE) stopifnot(pr %:% 3 %>LP% 1) stopifnot((pr %:% 1 %>LPS% 2) == FALSE) stopifnot(pr %:% 3 %>LPS% 1)
Apply transitive closure over power relation that has cycles.
transitiveClosure(powerRelation)
transitiveClosure(powerRelation)
powerRelation |
A |
A power relation is a binary relationship between coalitions that is transitive.
For coalitions , this means that if
and
, then
.
A power relation with cycles is not transitive. A transitive closure over a power relation removes all cycles and turns it into a
transitive relation, placing all coalitions within a cycle in the same equivalence class.
If , from the symmetric definition in
PowerRelation()
we
therefore assume that . Similarly, if
, the transitive closure turns it into
.
transitiveClosure()
transforms a PowerRelation
object with cycles into a PowerRelation
object without cycles.
As described above, all coalitions within a cycle then are put into the same equivalence class
and all duplicate coalitions are removed.
PowerRelation
object with no cycles.
pr <- as.PowerRelation("1 > 2") # nothing changes transitiveClosure(pr) pr <- suppressWarnings(as.PowerRelation("1 > 2 > 1")) # 1 ~ 2 transitiveClosure(pr) pr <- suppressWarnings( as.PowerRelation("1 > 3 > 1 > 2 > 23 > 2") ) # 1 > 3 > 1 > 2 > 23 > 2 => # 1 ~ 3 > 2 ~ 23 transitiveClosure(pr)
pr <- as.PowerRelation("1 > 2") # nothing changes transitiveClosure(pr) pr <- suppressWarnings(as.PowerRelation("1 > 2 > 1")) # 1 ~ 2 transitiveClosure(pr) pr <- suppressWarnings( as.PowerRelation("1 > 3 > 1 > 2 > 23 > 2") ) # 1 > 3 > 1 > 2 > 23 > 2 => # 1 ~ 3 > 2 ~ 23 transitiveClosure(pr)
SocialRanking
objectDescription
Create a
SocialRanking
object.Usage
Arguments
l
A list of vectors
Details
Similar to
PowerRelation()
,SocialRanking
expects expects a list to represent a power relation. UnlikePowerRelation()
however, this list should not be nested and should only contain vectors, each vector containing elements that are deemed equally preferable.Use
doRanking()
to rank elements based on arbitrary score objects.A social ranking solution, or ranking solution, or solution, maps each power relation between coalitions to a power relation between its elements. I.e., from the power relation
≿:{1,2}≻{2}≻{1}
, we may expect the result of a ranking solutionR≿
to rank element 2 over 1. Therefore2R≿1
will be present, but not1R≿2
.Formally, a ranking solution
R:T(P)→T(N)
is a function that, given a power relation≿∈T(P)
, always produces a power relationR(≿)
(orR≿
) over its set of elements. For two elementsi,j∈N
,iR≿j
means that applying the solutionR
on the ranking≿
makesi
at least as preferable asj
. Often timesiI≿j
andiP≿j
are used to indicate its symmetric and asymmetric part, respectively. As in,iI≿j
implies thatiR≿j
andjR≿i
, whereasiP≿j
implies thatiR≿j
but notjR≿i
.Value
A list of type
SocialRanking
. Each element of the list contains a vector of elements inpowerRelation$elements
that are indifferent to one another.See Also
Function that ranks elements based on their scores,
doRanking()
Examples