mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 15:11:03 +00:00
Abstracts elections-phragmen pallet to use NposSolver (#12588)
* Abstracts elections-phragmen pallet to use NposSolver * Update frame/elections-phragmen/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/elections-phragmen/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * changes the name of the pallet; adds changelog * update changelog * Adds weight testing * Adds log macro_rules * renames elections-phragment dir to elections * weights rename * fixes typo in cargo toml * pre/post solve weight scafolding * refactor do_post_election * refactors into pre and post election solve for independent benchmarking * deconstructs PreElectionResults struct * updates benchmarking pre and post election solve; mock weights * Update frame/elections/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/elections/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * addresses PR comments * adds pre_solve and post_sove weights * Adds comments on election pallet id param name change * ".git/.scripts/bench-bot.sh" pallet dev pallet_elections * Finishes pre-post solve weights * Update frame/elections/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/elections/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Addresses PR comments: no panic in on_init path; nits * Fixes node build * Implements approval voting to use as a `NposSolver` (#13367) * Implements the approval voting methods in sp_npos_elections * fmt * remove unecessary file * comment clarification * re-run weights * fix typo * updates MaxVoters in tests for integrity_tests to pass * Refactors election provider support benchmarks outside its own crate (#13431) * Refactors election provider support benchmarks outside its own crate --------- Co-authored-by: command-bot <> --------- Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: parity-processbot <> Co-authored-by: Ross Bulat <ross@parity.io>
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 2023 Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Implementation of the approval voting election method.
|
||||
//!
|
||||
//! This method allows voters to select many candidates and backing each of them with the same
|
||||
//! vote weight. The candidates with the most backing are the election winners.
|
||||
|
||||
use crate::{setup_inputs, ElectionResult, IdentifierT, PerThing128, VoteWeight};
|
||||
use sp_arithmetic::traits::Zero;
|
||||
use sp_std::{cmp::Reverse, vec::Vec};
|
||||
|
||||
/// Execute an approvals voting election scheme. The return type is a list of winners. The weight
|
||||
/// vector of all voters who contribute to the winners, which for this scheme is always 100% per
|
||||
/// vote.
|
||||
///
|
||||
/// - The vote assignment distribution for each vote is always 100%, since a voter backs a candidate
|
||||
/// with its full stake, regardless of how many candidates are backed by the same stake. However,
|
||||
/// the caller may normalize votes on site if required.
|
||||
/// - Returning winners are sorted based on desirability. Voters are unsorted.
|
||||
/// - The returning winners are zipped with their final backing stake. Yet, to get the exact final
|
||||
/// weight distribution from the winner's point of view, one needs to build a support map. See
|
||||
/// [`crate::SupportMap`] for more info. Note that this backing stake is computed in
|
||||
/// ExtendedBalance and may be slightly different that what will be computed from the support map,
|
||||
/// due to accuracy loss.
|
||||
///
|
||||
/// This can only fail if the normalization fails. This can happen if for any of the resulting
|
||||
/// assignments, `assignment.distribution.map(|p| p.deconstruct()).sum()` fails to fit inside
|
||||
/// `UpperOf<P>`. A user of this crate may statically assert that this can never happen and safely
|
||||
/// `expect` this to return `Ok`.
|
||||
pub fn approval_voting<AccountId: IdentifierT, P: PerThing128>(
|
||||
to_elect: usize,
|
||||
candidates: Vec<AccountId>,
|
||||
voters: Vec<(AccountId, VoteWeight, impl IntoIterator<Item = AccountId>)>,
|
||||
) -> Result<ElectionResult<AccountId, P>, crate::Error> {
|
||||
let to_elect = to_elect.min(candidates.len());
|
||||
|
||||
let (mut candidates, mut voters) = setup_inputs(candidates, voters);
|
||||
|
||||
candidates.sort_by_key(|c| Reverse(c.borrow().approval_stake));
|
||||
|
||||
let winners = candidates
|
||||
.into_iter()
|
||||
.take(to_elect)
|
||||
.map(|w| {
|
||||
w.borrow_mut().elected = true;
|
||||
w
|
||||
})
|
||||
.map(|w_ptr| (w_ptr.borrow().who.clone(), w_ptr.borrow().approval_stake))
|
||||
.collect();
|
||||
|
||||
for voter in &mut voters {
|
||||
for edge in &mut voter.edges {
|
||||
if edge.candidate.borrow().elected {
|
||||
edge.weight = voter.budget
|
||||
} else {
|
||||
edge.weight = Zero::zero()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let assignments = voters.into_iter().filter_map(|v| v.into_assignment()).collect::<Vec<_>>();
|
||||
|
||||
Ok(ElectionResult { winners, assignments })
|
||||
}
|
||||
@@ -25,6 +25,8 @@
|
||||
//! - [`balance`](balancing::balance): Implements the star balancing algorithm. This iterative
|
||||
//! process can push a solution toward being more "balanced", which in turn can increase its
|
||||
//! score.
|
||||
//! - [`approval_voting`](approval_voting::approval_voting): Implements an approval voting electoral
|
||||
//! system where voters can back multiple candidates with the same stake.
|
||||
//!
|
||||
//! ### Terminology
|
||||
//!
|
||||
@@ -90,6 +92,7 @@ mod mock;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
pub mod approval_voting;
|
||||
mod assignments;
|
||||
pub mod balancing;
|
||||
pub mod helpers;
|
||||
@@ -100,6 +103,7 @@ pub mod pjr;
|
||||
pub mod reduce;
|
||||
pub mod traits;
|
||||
|
||||
pub use approval_voting::*;
|
||||
pub use assignments::{Assignment, StakedAssignment};
|
||||
pub use balancing::*;
|
||||
pub use helpers::*;
|
||||
|
||||
@@ -57,7 +57,7 @@ const DEN: ExtendedBalance = ExtendedBalance::max_value();
|
||||
/// - The returning weight distribution is _normalized_, meaning that it is guaranteed that the sum
|
||||
/// of the ratios in each voter's distribution sums up to exactly `P::one()`.
|
||||
///
|
||||
/// This can only fail of the normalization fails. This can happen if for any of the resulting
|
||||
/// This can only fail if the normalization fails. This can happen if for any of the resulting
|
||||
/// assignments, `assignment.distribution.map(|p| p.deconstruct()).sum()` fails to fit inside
|
||||
/// `UpperOf<P>`. A user of this crate may statically assert that this can never happen and safely
|
||||
/// `expect` this to return `Ok`.
|
||||
|
||||
@@ -18,12 +18,57 @@
|
||||
//! Tests for npos-elections.
|
||||
|
||||
use crate::{
|
||||
balancing, helpers::*, mock::*, seq_phragmen, seq_phragmen_core, setup_inputs, to_support_map,
|
||||
Assignment, BalancingConfig, ElectionResult, ExtendedBalance, StakedAssignment, Support, Voter,
|
||||
approval_voting::*, balancing, helpers::*, mock::*, seq_phragmen, seq_phragmen_core,
|
||||
setup_inputs, to_support_map, Assignment, BalancingConfig, ElectionResult, ExtendedBalance,
|
||||
StakedAssignment, Support, Voter,
|
||||
};
|
||||
use sp_arithmetic::{PerU16, Perbill, Percent, Permill};
|
||||
use substrate_test_utils::assert_eq_uvec;
|
||||
|
||||
#[test]
|
||||
fn approval_voting_works() {
|
||||
let candidates = vec![1, 2, 3, 4];
|
||||
let voters = vec![(10, vec![1, 2]), (20, vec![1, 2]), (30, vec![1, 2, 3]), (40, vec![4])];
|
||||
let stake_of = create_stake_of(&[(10, 10), (20, 20), (30, 30), (40, 40)]);
|
||||
|
||||
let voters = voters
|
||||
.iter()
|
||||
.map(|(ref v, ref vs)| (*v, stake_of(v), vs.clone()))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let ElectionResult::<_, Perbill> { winners, assignments } =
|
||||
approval_voting(3, candidates, voters).unwrap();
|
||||
|
||||
assert_eq_uvec!(winners, vec![(1, 60), (2, 60), (4, 40)]);
|
||||
assert_eq_uvec!(
|
||||
assignments,
|
||||
vec![
|
||||
Assignment {
|
||||
who: 10u64,
|
||||
distribution: vec![
|
||||
(1, Perbill::from_percent(100)),
|
||||
(2, Perbill::from_percent(100))
|
||||
]
|
||||
},
|
||||
Assignment {
|
||||
who: 20u64,
|
||||
distribution: vec![
|
||||
(1, Perbill::from_percent(100)),
|
||||
(2, Perbill::from_percent(100))
|
||||
]
|
||||
},
|
||||
Assignment {
|
||||
who: 30u64,
|
||||
distribution: vec![
|
||||
(1, Perbill::from_percent(100)),
|
||||
(2, Perbill::from_percent(100))
|
||||
]
|
||||
},
|
||||
Assignment { who: 40u64, distribution: vec![(4, Perbill::from_percent(100))] },
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn float_phragmen_poc_works() {
|
||||
let candidates = vec![1, 2, 3];
|
||||
|
||||
Reference in New Issue
Block a user