mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-14 00:31:07 +00:00
Move phragmen benchmarks out of Staking (#3588)
* Move phragmen benches to.. phragmen. * Move some basic phragmen tests to.. phragmen. * Line-width * Add phragmen equ implementation as flot * Add phragmen equ implementation as flot * Add mock and test file.
This commit is contained in:
@@ -37,6 +37,9 @@ use rstd::{prelude::*, collections::btree_map::BTreeMap};
|
||||
use sr_primitives::PerU128;
|
||||
use sr_primitives::traits::{Zero, Convert, Member, SimpleArithmetic};
|
||||
|
||||
mod mock;
|
||||
mod tests;
|
||||
|
||||
/// Type used as the fraction.
|
||||
type Fraction = PerU128;
|
||||
|
||||
@@ -355,7 +358,7 @@ pub fn elect<AccountId, Balance, FS, C>(
|
||||
/// * `tolerance`: maximum difference that can occur before an early quite happens.
|
||||
/// * `iterations`: maximum number of iterations that will be processed.
|
||||
/// * `stake_of`: something that can return the stake stake of a particular candidate or voter.
|
||||
pub fn equalize<Balance, AccountId, C, FS>(
|
||||
pub fn equalize<Balance, AccountId, FS, C>(
|
||||
mut assignments: Vec<(AccountId, Vec<PhragmenAssignment<AccountId>>)>,
|
||||
supports: &mut SupportMap<AccountId>,
|
||||
tolerance: ExtendedBalance,
|
||||
@@ -489,226 +492,3 @@ fn do_equalize<Balance, AccountId, C>(
|
||||
|
||||
difference
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{elect, ACCURACY, PhragmenResult};
|
||||
use sr_primitives::traits::{Convert, Member, SaturatedConversion};
|
||||
use rstd::collections::btree_map::BTreeMap;
|
||||
use support::assert_eq_uvec;
|
||||
|
||||
pub struct C;
|
||||
impl Convert<u64, u64> for C {
|
||||
fn convert(x: u64) -> u64 { x }
|
||||
}
|
||||
impl Convert<u128, u64> for C {
|
||||
fn convert(x: u128) -> u64 { x.saturated_into() }
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
struct _Candidate<AccountId> {
|
||||
who: AccountId,
|
||||
score: f64,
|
||||
approval_stake: f64,
|
||||
elected: bool,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
struct _Voter<AccountId> {
|
||||
who: AccountId,
|
||||
edges: Vec<_Edge<AccountId>>,
|
||||
budget: f64,
|
||||
load: f64,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
struct _Edge<AccountId> {
|
||||
who: AccountId,
|
||||
load: f64,
|
||||
candidate_index: usize,
|
||||
}
|
||||
|
||||
type _PhragmenAssignment<AccountId> = (AccountId, f64);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct _PhragmenResult<AccountId> {
|
||||
pub winners: Vec<AccountId>,
|
||||
pub assignments: Vec<(AccountId, Vec<_PhragmenAssignment<AccountId>>)>
|
||||
}
|
||||
|
||||
pub fn elect_poc<AccountId, FS>(
|
||||
candidate_count: usize,
|
||||
minimum_candidate_count: usize,
|
||||
initial_candidates: Vec<AccountId>,
|
||||
initial_voters: Vec<(AccountId, Vec<AccountId>)>,
|
||||
stake_of: FS,
|
||||
self_vote: bool,
|
||||
) -> Option<_PhragmenResult<AccountId>> where
|
||||
AccountId: Default + Ord + Member + Copy,
|
||||
for<'r> FS: Fn(&'r AccountId) -> u64,
|
||||
{
|
||||
let mut elected_candidates: Vec<AccountId>;
|
||||
let mut assigned: Vec<(AccountId, Vec<_PhragmenAssignment<AccountId>>)>;
|
||||
let mut c_idx_cache = BTreeMap::<AccountId, usize>::new();
|
||||
let num_voters = initial_candidates.len() + initial_voters.len();
|
||||
let mut voters: Vec<_Voter<AccountId>> = Vec::with_capacity(num_voters);
|
||||
|
||||
let mut candidates = if self_vote {
|
||||
initial_candidates.into_iter().map(|who| {
|
||||
let stake = stake_of(&who) as f64;
|
||||
_Candidate { who, approval_stake: stake, ..Default::default() }
|
||||
})
|
||||
.filter(|c| c.approval_stake != 0f64)
|
||||
.enumerate()
|
||||
.map(|(i, c)| {
|
||||
let who = c.who;
|
||||
voters.push(_Voter {
|
||||
who: who.clone(),
|
||||
edges: vec![
|
||||
_Edge { who: who.clone(), candidate_index: i, ..Default::default() }
|
||||
],
|
||||
budget: c.approval_stake,
|
||||
load: 0f64,
|
||||
});
|
||||
c_idx_cache.insert(c.who.clone(), i);
|
||||
c
|
||||
})
|
||||
.collect::<Vec<_Candidate<AccountId>>>()
|
||||
} else {
|
||||
initial_candidates.into_iter()
|
||||
.enumerate()
|
||||
.map(|(idx, who)| {
|
||||
c_idx_cache.insert(who.clone(), idx);
|
||||
_Candidate { who, ..Default::default() }
|
||||
})
|
||||
.collect::<Vec<_Candidate<AccountId>>>()
|
||||
};
|
||||
|
||||
if candidates.len() < minimum_candidate_count {
|
||||
return None;
|
||||
}
|
||||
|
||||
voters.extend(initial_voters.into_iter().map(|(who, votes)| {
|
||||
let voter_stake = stake_of(&who) as f64;
|
||||
let mut edges: Vec<_Edge<AccountId>> = Vec::with_capacity(votes.len());
|
||||
for v in votes {
|
||||
if let Some(idx) = c_idx_cache.get(&v) {
|
||||
candidates[*idx].approval_stake = candidates[*idx].approval_stake + voter_stake;
|
||||
edges.push(
|
||||
_Edge { who: v.clone(), candidate_index: *idx, ..Default::default() }
|
||||
);
|
||||
}
|
||||
}
|
||||
_Voter {
|
||||
who,
|
||||
edges: edges,
|
||||
budget: voter_stake,
|
||||
load: 0f64,
|
||||
}
|
||||
}));
|
||||
|
||||
let to_elect = candidate_count.min(candidates.len());
|
||||
elected_candidates = Vec::with_capacity(candidate_count);
|
||||
assigned = Vec::with_capacity(candidate_count);
|
||||
|
||||
for _round in 0..to_elect {
|
||||
for c in &mut candidates {
|
||||
if !c.elected {
|
||||
c.score = 1.0 / c.approval_stake;
|
||||
}
|
||||
}
|
||||
for n in &voters {
|
||||
for e in &n.edges {
|
||||
let c = &mut candidates[e.candidate_index];
|
||||
if !c.elected && !(c.approval_stake == 0f64) {
|
||||
c.score += n.budget * n.load / c.approval_stake;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(winner) = candidates
|
||||
.iter_mut()
|
||||
.filter(|c| !c.elected)
|
||||
.min_by(|x, y| x.score.partial_cmp(&y.score).unwrap_or(rstd::cmp::Ordering::Equal))
|
||||
{
|
||||
winner.elected = true;
|
||||
for n in &mut voters {
|
||||
for e in &mut n.edges {
|
||||
if e.who == winner.who {
|
||||
e.load = winner.score - n.load;
|
||||
n.load = winner.score;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
elected_candidates.push(winner.who.clone());
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
for n in &mut voters {
|
||||
let mut assignment = (n.who.clone(), vec![]);
|
||||
for e in &mut n.edges {
|
||||
if let Some(c) = elected_candidates.iter().cloned().find(|c| *c == e.who) {
|
||||
if c != n.who {
|
||||
let ratio = e.load / n.load;
|
||||
assignment.1.push((e.who.clone(), ratio));
|
||||
}
|
||||
}
|
||||
}
|
||||
assigned.push(assignment);
|
||||
}
|
||||
|
||||
Some(_PhragmenResult {
|
||||
winners: elected_candidates,
|
||||
assignments: assigned,
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn float_poc_works() {
|
||||
let candidates = vec![1, 2, 3];
|
||||
let voters = vec![
|
||||
(10, vec![1, 2]),
|
||||
(20, vec![1, 3]),
|
||||
(30, vec![2, 3]),
|
||||
];
|
||||
let stake_of = |x: &u64| { if *x >= 10 { *x } else { 0 }};
|
||||
let _PhragmenResult { winners, assignments } =
|
||||
elect_poc(2, 2, candidates, voters, stake_of, false).unwrap();
|
||||
|
||||
assert_eq_uvec!(winners, vec![2, 3]);
|
||||
assert_eq_uvec!(
|
||||
assignments,
|
||||
vec![
|
||||
(10, vec![(2, 1.0)]),
|
||||
(20, vec![(3, 1.0)]),
|
||||
(30, vec![(2, 0.5), (3, 0.5)])
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn phragmen_works() {
|
||||
let candidates = vec![1, 2, 3];
|
||||
let voters = vec![
|
||||
(10, vec![1, 2]),
|
||||
(20, vec![1, 3]),
|
||||
(30, vec![2, 3]),
|
||||
];
|
||||
let stake_of = |x: &u64| { if *x >= 10 { *x } else { 0 }};
|
||||
let PhragmenResult { winners, assignments } =
|
||||
elect::<_, _, _, C>(2, 2, candidates, voters, stake_of, false).unwrap();
|
||||
|
||||
assert_eq_uvec!(winners, vec![2, 3]);
|
||||
assert_eq_uvec!(
|
||||
assignments,
|
||||
vec![
|
||||
(10, vec![(2, ACCURACY)]),
|
||||
(20, vec![(3, ACCURACY)]),
|
||||
(30, vec![(2, ACCURACY/2), (3, ACCURACY/2)])
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user