@snapshot-labs/snapshot.js 0.12.52 → 0.12.53
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/snapshot.cjs.js +78 -34
- package/dist/snapshot.esm.js +78 -34
- package/dist/snapshot.min.js +1 -1
- package/package.json +1 -1
- package/src/voting/__snapshots__/copeland.spec.js.snap +66 -33
- package/src/voting/copeland.spec.js +101 -0
- package/src/voting/copeland.ts +125 -34
package/dist/snapshot.cjs.js
CHANGED
|
@@ -3976,36 +3976,46 @@ class CopelandVoting {
|
|
|
3976
3976
|
const validVotes = this.getValidVotes();
|
|
3977
3977
|
const choicesCount = this.proposal.choices.length;
|
|
3978
3978
|
const pairwiseComparisons = Array.from({ length: choicesCount }, () => Array(choicesCount).fill(0));
|
|
3979
|
+
const totalVotingPower = this.getScoresTotal();
|
|
3979
3980
|
// Calculate pairwise comparisons
|
|
3980
3981
|
for (const vote of validVotes) {
|
|
3981
|
-
for (let
|
|
3982
|
-
for (let
|
|
3983
|
-
const
|
|
3984
|
-
const
|
|
3985
|
-
pairwiseComparisons[
|
|
3986
|
-
pairwiseComparisons[
|
|
3982
|
+
for (let currentRank = 0; currentRank < vote.choice.length; currentRank++) {
|
|
3983
|
+
for (let nextRank = currentRank + 1; nextRank < vote.choice.length; nextRank++) {
|
|
3984
|
+
const preferredChoice = vote.choice[currentRank] - 1;
|
|
3985
|
+
const lowerChoice = vote.choice[nextRank] - 1;
|
|
3986
|
+
pairwiseComparisons[preferredChoice][lowerChoice] += vote.balance;
|
|
3987
|
+
pairwiseComparisons[lowerChoice][preferredChoice] -= vote.balance;
|
|
3987
3988
|
}
|
|
3988
3989
|
}
|
|
3989
3990
|
}
|
|
3990
3991
|
// Calculate Copeland scores
|
|
3991
3992
|
const scores = Array(choicesCount).fill(0);
|
|
3992
|
-
|
|
3993
|
-
|
|
3994
|
-
|
|
3995
|
-
|
|
3996
|
-
|
|
3993
|
+
let totalCopelandScore = 0;
|
|
3994
|
+
for (let choiceIndex = 0; choiceIndex < choicesCount; choiceIndex++) {
|
|
3995
|
+
for (let opponentIndex = 0; opponentIndex < choicesCount; opponentIndex++) {
|
|
3996
|
+
if (choiceIndex !== opponentIndex) {
|
|
3997
|
+
const comparison = pairwiseComparisons[choiceIndex][opponentIndex];
|
|
3998
|
+
if (comparison > 0) {
|
|
3999
|
+
scores[choiceIndex]++;
|
|
3997
4000
|
}
|
|
3998
|
-
else if (
|
|
3999
|
-
scores[
|
|
4001
|
+
else if (comparison < 0) {
|
|
4002
|
+
scores[opponentIndex]++;
|
|
4000
4003
|
}
|
|
4001
4004
|
else {
|
|
4002
|
-
scores[
|
|
4003
|
-
scores[
|
|
4005
|
+
scores[choiceIndex] += 0.5;
|
|
4006
|
+
scores[opponentIndex] += 0.5;
|
|
4004
4007
|
}
|
|
4005
4008
|
}
|
|
4006
4009
|
}
|
|
4007
4010
|
}
|
|
4008
|
-
|
|
4011
|
+
// Calculate total Copeland score for normalization
|
|
4012
|
+
totalCopelandScore = scores.reduce((sum, score) => sum + score, 0);
|
|
4013
|
+
// Normalize scores to distribute voting power
|
|
4014
|
+
if (totalCopelandScore > 0) {
|
|
4015
|
+
return scores.map((score) => (score / totalCopelandScore) * totalVotingPower);
|
|
4016
|
+
}
|
|
4017
|
+
// If no clear winners, distribute power equally
|
|
4018
|
+
return scores.map(() => totalVotingPower / choicesCount);
|
|
4009
4019
|
}
|
|
4010
4020
|
// Calculates the Copeland scores for each choice, broken down by strategy
|
|
4011
4021
|
getScoresByStrategy() {
|
|
@@ -4013,40 +4023,74 @@ class CopelandVoting {
|
|
|
4013
4023
|
const choicesCount = this.proposal.choices.length;
|
|
4014
4024
|
const strategiesCount = this.strategies.length;
|
|
4015
4025
|
const pairwiseComparisons = Array.from({ length: choicesCount }, () => Array.from({ length: choicesCount }, () => Array(strategiesCount).fill(0)));
|
|
4026
|
+
// Calculate total voting power per strategy
|
|
4027
|
+
const strategyTotals = Array(strategiesCount).fill(0);
|
|
4028
|
+
for (const vote of validVotes) {
|
|
4029
|
+
for (let i = 0; i < strategiesCount; i++) {
|
|
4030
|
+
strategyTotals[i] += vote.scores[i];
|
|
4031
|
+
}
|
|
4032
|
+
}
|
|
4016
4033
|
// Calculate pairwise comparisons for each strategy
|
|
4017
4034
|
for (const vote of validVotes) {
|
|
4018
|
-
for (let
|
|
4019
|
-
for (let
|
|
4020
|
-
const
|
|
4021
|
-
const
|
|
4022
|
-
for (let
|
|
4023
|
-
pairwiseComparisons[
|
|
4024
|
-
|
|
4035
|
+
for (let currentRank = 0; currentRank < vote.choice.length; currentRank++) {
|
|
4036
|
+
for (let nextRank = currentRank + 1; nextRank < vote.choice.length; nextRank++) {
|
|
4037
|
+
const preferredChoice = vote.choice[currentRank] - 1;
|
|
4038
|
+
const lowerChoice = vote.choice[nextRank] - 1;
|
|
4039
|
+
for (let strategyIndex = 0; strategyIndex < strategiesCount; strategyIndex++) {
|
|
4040
|
+
pairwiseComparisons[preferredChoice][lowerChoice][strategyIndex] +=
|
|
4041
|
+
vote.scores[strategyIndex];
|
|
4042
|
+
pairwiseComparisons[lowerChoice][preferredChoice][strategyIndex] -=
|
|
4043
|
+
vote.scores[strategyIndex];
|
|
4025
4044
|
}
|
|
4026
4045
|
}
|
|
4027
4046
|
}
|
|
4028
4047
|
}
|
|
4029
4048
|
// Calculate Copeland scores for each strategy
|
|
4030
4049
|
const scores = Array.from({ length: choicesCount }, () => Array(strategiesCount).fill(0));
|
|
4031
|
-
for (let
|
|
4032
|
-
for (let
|
|
4033
|
-
if (
|
|
4034
|
-
for (let
|
|
4035
|
-
|
|
4036
|
-
|
|
4050
|
+
for (let choiceIndex = 0; choiceIndex < choicesCount; choiceIndex++) {
|
|
4051
|
+
for (let opponentIndex = 0; opponentIndex < choicesCount; opponentIndex++) {
|
|
4052
|
+
if (choiceIndex !== opponentIndex) {
|
|
4053
|
+
for (let strategyIndex = 0; strategyIndex < strategiesCount; strategyIndex++) {
|
|
4054
|
+
const comparison = pairwiseComparisons[choiceIndex][opponentIndex][strategyIndex];
|
|
4055
|
+
if (comparison > 0) {
|
|
4056
|
+
scores[choiceIndex][strategyIndex]++;
|
|
4037
4057
|
}
|
|
4038
|
-
else if (
|
|
4039
|
-
scores[
|
|
4058
|
+
else if (comparison < 0) {
|
|
4059
|
+
scores[opponentIndex][strategyIndex]++;
|
|
4040
4060
|
}
|
|
4041
4061
|
else {
|
|
4042
|
-
scores[
|
|
4043
|
-
scores[
|
|
4062
|
+
scores[choiceIndex][strategyIndex] += 0.5;
|
|
4063
|
+
scores[opponentIndex][strategyIndex] += 0.5;
|
|
4044
4064
|
}
|
|
4045
4065
|
}
|
|
4046
4066
|
}
|
|
4047
4067
|
}
|
|
4048
4068
|
}
|
|
4049
|
-
|
|
4069
|
+
// Normalize scores by strategy to distribute voting power
|
|
4070
|
+
const normalizedScores = Array.from({ length: choicesCount }, () => Array(strategiesCount).fill(0));
|
|
4071
|
+
for (let strategyIndex = 0; strategyIndex < strategiesCount; strategyIndex++) {
|
|
4072
|
+
// Calculate total Copeland score for this strategy
|
|
4073
|
+
let totalCopelandScore = 0;
|
|
4074
|
+
for (let choiceIndex = 0; choiceIndex < choicesCount; choiceIndex++) {
|
|
4075
|
+
totalCopelandScore += scores[choiceIndex][strategyIndex];
|
|
4076
|
+
}
|
|
4077
|
+
// Normalize scores to distribute voting power for this strategy
|
|
4078
|
+
if (totalCopelandScore > 0) {
|
|
4079
|
+
for (let choiceIndex = 0; choiceIndex < choicesCount; choiceIndex++) {
|
|
4080
|
+
normalizedScores[choiceIndex][strategyIndex] =
|
|
4081
|
+
(scores[choiceIndex][strategyIndex] / totalCopelandScore) *
|
|
4082
|
+
strategyTotals[strategyIndex];
|
|
4083
|
+
}
|
|
4084
|
+
}
|
|
4085
|
+
else if (strategyTotals[strategyIndex] > 0) {
|
|
4086
|
+
// If no clear winners, distribute power equally for this strategy
|
|
4087
|
+
for (let choiceIndex = 0; choiceIndex < choicesCount; choiceIndex++) {
|
|
4088
|
+
normalizedScores[choiceIndex][strategyIndex] =
|
|
4089
|
+
strategyTotals[strategyIndex] / choicesCount;
|
|
4090
|
+
}
|
|
4091
|
+
}
|
|
4092
|
+
}
|
|
4093
|
+
return normalizedScores;
|
|
4050
4094
|
}
|
|
4051
4095
|
// Calculates the total score (sum of all valid vote balances)
|
|
4052
4096
|
getScoresTotal() {
|
package/dist/snapshot.esm.js
CHANGED
|
@@ -3966,36 +3966,46 @@ class CopelandVoting {
|
|
|
3966
3966
|
const validVotes = this.getValidVotes();
|
|
3967
3967
|
const choicesCount = this.proposal.choices.length;
|
|
3968
3968
|
const pairwiseComparisons = Array.from({ length: choicesCount }, () => Array(choicesCount).fill(0));
|
|
3969
|
+
const totalVotingPower = this.getScoresTotal();
|
|
3969
3970
|
// Calculate pairwise comparisons
|
|
3970
3971
|
for (const vote of validVotes) {
|
|
3971
|
-
for (let
|
|
3972
|
-
for (let
|
|
3973
|
-
const
|
|
3974
|
-
const
|
|
3975
|
-
pairwiseComparisons[
|
|
3976
|
-
pairwiseComparisons[
|
|
3972
|
+
for (let currentRank = 0; currentRank < vote.choice.length; currentRank++) {
|
|
3973
|
+
for (let nextRank = currentRank + 1; nextRank < vote.choice.length; nextRank++) {
|
|
3974
|
+
const preferredChoice = vote.choice[currentRank] - 1;
|
|
3975
|
+
const lowerChoice = vote.choice[nextRank] - 1;
|
|
3976
|
+
pairwiseComparisons[preferredChoice][lowerChoice] += vote.balance;
|
|
3977
|
+
pairwiseComparisons[lowerChoice][preferredChoice] -= vote.balance;
|
|
3977
3978
|
}
|
|
3978
3979
|
}
|
|
3979
3980
|
}
|
|
3980
3981
|
// Calculate Copeland scores
|
|
3981
3982
|
const scores = Array(choicesCount).fill(0);
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
|
|
3985
|
-
|
|
3986
|
-
|
|
3983
|
+
let totalCopelandScore = 0;
|
|
3984
|
+
for (let choiceIndex = 0; choiceIndex < choicesCount; choiceIndex++) {
|
|
3985
|
+
for (let opponentIndex = 0; opponentIndex < choicesCount; opponentIndex++) {
|
|
3986
|
+
if (choiceIndex !== opponentIndex) {
|
|
3987
|
+
const comparison = pairwiseComparisons[choiceIndex][opponentIndex];
|
|
3988
|
+
if (comparison > 0) {
|
|
3989
|
+
scores[choiceIndex]++;
|
|
3987
3990
|
}
|
|
3988
|
-
else if (
|
|
3989
|
-
scores[
|
|
3991
|
+
else if (comparison < 0) {
|
|
3992
|
+
scores[opponentIndex]++;
|
|
3990
3993
|
}
|
|
3991
3994
|
else {
|
|
3992
|
-
scores[
|
|
3993
|
-
scores[
|
|
3995
|
+
scores[choiceIndex] += 0.5;
|
|
3996
|
+
scores[opponentIndex] += 0.5;
|
|
3994
3997
|
}
|
|
3995
3998
|
}
|
|
3996
3999
|
}
|
|
3997
4000
|
}
|
|
3998
|
-
|
|
4001
|
+
// Calculate total Copeland score for normalization
|
|
4002
|
+
totalCopelandScore = scores.reduce((sum, score) => sum + score, 0);
|
|
4003
|
+
// Normalize scores to distribute voting power
|
|
4004
|
+
if (totalCopelandScore > 0) {
|
|
4005
|
+
return scores.map((score) => (score / totalCopelandScore) * totalVotingPower);
|
|
4006
|
+
}
|
|
4007
|
+
// If no clear winners, distribute power equally
|
|
4008
|
+
return scores.map(() => totalVotingPower / choicesCount);
|
|
3999
4009
|
}
|
|
4000
4010
|
// Calculates the Copeland scores for each choice, broken down by strategy
|
|
4001
4011
|
getScoresByStrategy() {
|
|
@@ -4003,40 +4013,74 @@ class CopelandVoting {
|
|
|
4003
4013
|
const choicesCount = this.proposal.choices.length;
|
|
4004
4014
|
const strategiesCount = this.strategies.length;
|
|
4005
4015
|
const pairwiseComparisons = Array.from({ length: choicesCount }, () => Array.from({ length: choicesCount }, () => Array(strategiesCount).fill(0)));
|
|
4016
|
+
// Calculate total voting power per strategy
|
|
4017
|
+
const strategyTotals = Array(strategiesCount).fill(0);
|
|
4018
|
+
for (const vote of validVotes) {
|
|
4019
|
+
for (let i = 0; i < strategiesCount; i++) {
|
|
4020
|
+
strategyTotals[i] += vote.scores[i];
|
|
4021
|
+
}
|
|
4022
|
+
}
|
|
4006
4023
|
// Calculate pairwise comparisons for each strategy
|
|
4007
4024
|
for (const vote of validVotes) {
|
|
4008
|
-
for (let
|
|
4009
|
-
for (let
|
|
4010
|
-
const
|
|
4011
|
-
const
|
|
4012
|
-
for (let
|
|
4013
|
-
pairwiseComparisons[
|
|
4014
|
-
|
|
4025
|
+
for (let currentRank = 0; currentRank < vote.choice.length; currentRank++) {
|
|
4026
|
+
for (let nextRank = currentRank + 1; nextRank < vote.choice.length; nextRank++) {
|
|
4027
|
+
const preferredChoice = vote.choice[currentRank] - 1;
|
|
4028
|
+
const lowerChoice = vote.choice[nextRank] - 1;
|
|
4029
|
+
for (let strategyIndex = 0; strategyIndex < strategiesCount; strategyIndex++) {
|
|
4030
|
+
pairwiseComparisons[preferredChoice][lowerChoice][strategyIndex] +=
|
|
4031
|
+
vote.scores[strategyIndex];
|
|
4032
|
+
pairwiseComparisons[lowerChoice][preferredChoice][strategyIndex] -=
|
|
4033
|
+
vote.scores[strategyIndex];
|
|
4015
4034
|
}
|
|
4016
4035
|
}
|
|
4017
4036
|
}
|
|
4018
4037
|
}
|
|
4019
4038
|
// Calculate Copeland scores for each strategy
|
|
4020
4039
|
const scores = Array.from({ length: choicesCount }, () => Array(strategiesCount).fill(0));
|
|
4021
|
-
for (let
|
|
4022
|
-
for (let
|
|
4023
|
-
if (
|
|
4024
|
-
for (let
|
|
4025
|
-
|
|
4026
|
-
|
|
4040
|
+
for (let choiceIndex = 0; choiceIndex < choicesCount; choiceIndex++) {
|
|
4041
|
+
for (let opponentIndex = 0; opponentIndex < choicesCount; opponentIndex++) {
|
|
4042
|
+
if (choiceIndex !== opponentIndex) {
|
|
4043
|
+
for (let strategyIndex = 0; strategyIndex < strategiesCount; strategyIndex++) {
|
|
4044
|
+
const comparison = pairwiseComparisons[choiceIndex][opponentIndex][strategyIndex];
|
|
4045
|
+
if (comparison > 0) {
|
|
4046
|
+
scores[choiceIndex][strategyIndex]++;
|
|
4027
4047
|
}
|
|
4028
|
-
else if (
|
|
4029
|
-
scores[
|
|
4048
|
+
else if (comparison < 0) {
|
|
4049
|
+
scores[opponentIndex][strategyIndex]++;
|
|
4030
4050
|
}
|
|
4031
4051
|
else {
|
|
4032
|
-
scores[
|
|
4033
|
-
scores[
|
|
4052
|
+
scores[choiceIndex][strategyIndex] += 0.5;
|
|
4053
|
+
scores[opponentIndex][strategyIndex] += 0.5;
|
|
4034
4054
|
}
|
|
4035
4055
|
}
|
|
4036
4056
|
}
|
|
4037
4057
|
}
|
|
4038
4058
|
}
|
|
4039
|
-
|
|
4059
|
+
// Normalize scores by strategy to distribute voting power
|
|
4060
|
+
const normalizedScores = Array.from({ length: choicesCount }, () => Array(strategiesCount).fill(0));
|
|
4061
|
+
for (let strategyIndex = 0; strategyIndex < strategiesCount; strategyIndex++) {
|
|
4062
|
+
// Calculate total Copeland score for this strategy
|
|
4063
|
+
let totalCopelandScore = 0;
|
|
4064
|
+
for (let choiceIndex = 0; choiceIndex < choicesCount; choiceIndex++) {
|
|
4065
|
+
totalCopelandScore += scores[choiceIndex][strategyIndex];
|
|
4066
|
+
}
|
|
4067
|
+
// Normalize scores to distribute voting power for this strategy
|
|
4068
|
+
if (totalCopelandScore > 0) {
|
|
4069
|
+
for (let choiceIndex = 0; choiceIndex < choicesCount; choiceIndex++) {
|
|
4070
|
+
normalizedScores[choiceIndex][strategyIndex] =
|
|
4071
|
+
(scores[choiceIndex][strategyIndex] / totalCopelandScore) *
|
|
4072
|
+
strategyTotals[strategyIndex];
|
|
4073
|
+
}
|
|
4074
|
+
}
|
|
4075
|
+
else if (strategyTotals[strategyIndex] > 0) {
|
|
4076
|
+
// If no clear winners, distribute power equally for this strategy
|
|
4077
|
+
for (let choiceIndex = 0; choiceIndex < choicesCount; choiceIndex++) {
|
|
4078
|
+
normalizedScores[choiceIndex][strategyIndex] =
|
|
4079
|
+
strategyTotals[strategyIndex] / choicesCount;
|
|
4080
|
+
}
|
|
4081
|
+
}
|
|
4082
|
+
}
|
|
4083
|
+
return normalizedScores;
|
|
4040
4084
|
}
|
|
4041
4085
|
// Calculates the total score (sum of all valid vote balances)
|
|
4042
4086
|
getScoresTotal() {
|