Permit --surplus meek with --quota-mode static
This commit is contained in:
parent
2f6614c0c1
commit
566cdeb185
|
@ -212,24 +212,68 @@ impl STVOptions {
|
||||||
/// Validate the combination of [STVOptions] and error if invalid
|
/// Validate the combination of [STVOptions] and error if invalid
|
||||||
pub fn validate(&self) -> Result<(), STVError> {
|
pub fn validate(&self) -> Result<(), STVError> {
|
||||||
if self.surplus == SurplusMethod::Meek {
|
if self.surplus == SurplusMethod::Meek {
|
||||||
if self.quota_mode != QuotaMode::DynamicByTotal { return Err(STVError::InvalidOptions("--surplus meek requires --quota-mode dynamic_by_total")); }
|
if self.quota_mode == QuotaMode::ERS97 {
|
||||||
if self.transferable_only { return Err(STVError::InvalidOptions("--surplus meek is incompatible with --transferable-only")); }
|
// Invalid because keep values cannot be calculated for a candidate elected with less than a surplus
|
||||||
if self.exclusion != ExclusionMethod::SingleStage { return Err(STVError::InvalidOptions("--surplus meek requires --exclusion single_stage")); }
|
return Err(STVError::InvalidOptions("--surplus meek is incompatible with --quota-mode ers97"));
|
||||||
if self.constraints_path.is_some() && self.constraint_mode == ConstraintMode::RepeatCount { return Err(STVError::InvalidOptions("--constraint-mode repeat_count requires a Gregory method for --surplus")); } // TODO: NYI?
|
}
|
||||||
|
if self.quota_mode == QuotaMode::ERS76 {
|
||||||
|
// Invalid because keep values cannot be calculated for a candidate elected with less than a surplus
|
||||||
|
return Err(STVError::InvalidOptions("--surplus meek is incompatible with --quota-mode ers76"));
|
||||||
|
}
|
||||||
|
if self.quota_mode == QuotaMode::DynamicByActive {
|
||||||
|
// Invalid because all votes are "active" in Meek STV
|
||||||
|
return Err(STVError::InvalidOptions("--surplus meek is incompatible with --quota-mode dynamic_by_active"));
|
||||||
|
}
|
||||||
|
if self.transferable_only {
|
||||||
|
// Invalid because this would imply a different keep value applies to nontransferable ballots (?)
|
||||||
|
// TODO: NYI?
|
||||||
|
return Err(STVError::InvalidOptions("--surplus meek is incompatible with --transferable-only"));
|
||||||
|
}
|
||||||
|
if self.exclusion != ExclusionMethod::SingleStage {
|
||||||
|
// Invalid because Meek STV is independent of order of exclusion, so segmented exclusion has no impact
|
||||||
|
return Err(STVError::InvalidOptions("--surplus meek requires --exclusion single_stage"));
|
||||||
|
}
|
||||||
|
if self.constraints_path.is_some() && self.constraint_mode == ConstraintMode::RepeatCount {
|
||||||
|
// TODO: NYI?
|
||||||
|
return Err(STVError::InvalidOptions("--constraint-mode repeat_count requires a Gregory method for --surplus"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if self.surplus == SurplusMethod::IHare || self.surplus == SurplusMethod::Hare {
|
if self.surplus == SurplusMethod::IHare || self.surplus == SurplusMethod::Hare {
|
||||||
if self.round_quota != Some(0) { return Err(STVError::InvalidOptions("--surplus ihare and --surplus hare require --round-quota 0")); }
|
if self.round_quota != Some(0) {
|
||||||
if self.sample == SampleMethod::StratifyLR && self.sample_per_ballot { return Err(STVError::InvalidOptions("--sample stratify is incompatible with --sample-per-ballot")); }
|
// Invalid because votes are counted only in whole numbers
|
||||||
//if self.sample == SampleMethod::StratifyFloor && self.sample_per_ballot { return Err(STVError::InvalidOptions("--sample stratify_floor is incompatible with --sample-per-ballot")); }
|
return Err(STVError::InvalidOptions("--surplus ihare and --surplus hare require --round-quota 0"));
|
||||||
if self.sample_per_ballot && !self.immediate_elect { return Err(STVError::InvalidOptions("--sample-per-ballot is incompatible with --no-immediate-elect")); }
|
}
|
||||||
if self.constraints_path.is_some() && self.constraint_mode == ConstraintMode::RepeatCount { return Err(STVError::InvalidOptions("--constraint-mode repeat_count requires a Gregory method for --surplus")); } // TODO: NYI?
|
if self.sample == SampleMethod::StratifyLR && self.sample_per_ballot {
|
||||||
|
// Invalid because a stratification cannot be made until all relevant ballots are transferred
|
||||||
|
return Err(STVError::InvalidOptions("--sample stratify is incompatible with --sample-per-ballot"));
|
||||||
|
}
|
||||||
|
if self.sample_per_ballot && !self.immediate_elect {
|
||||||
|
// Invalid because otherwise --sample-per-ballot would be ineffectual
|
||||||
|
return Err(STVError::InvalidOptions("--sample-per-ballot is incompatible with --no-immediate-elect"));
|
||||||
|
}
|
||||||
|
if self.constraints_path.is_some() && self.constraint_mode == ConstraintMode::RepeatCount {
|
||||||
|
// TODO: NYI?
|
||||||
|
return Err(STVError::InvalidOptions("--constraint-mode repeat_count requires a Gregory method for --surplus"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if self.subtract_nontransferable {
|
if self.subtract_nontransferable {
|
||||||
if self.surplus != SurplusMethod::WIG { return Err(STVError::InvalidOptions("--subtract-nontransferable requires --surplus wig")) }
|
if self.surplus != SurplusMethod::WIG {
|
||||||
if !self.transferable_only { return Err(STVError::InvalidOptions("--subtract-nontransferable requires --transferable-only")) }
|
// Invalid because other methods do not distinguish between ballots of different value during surplus transfer
|
||||||
|
return Err(STVError::InvalidOptions("--subtract-nontransferable requires --surplus wig"));
|
||||||
|
}
|
||||||
|
if !self.transferable_only {
|
||||||
|
// Invalid because nontransferables are only subtracted with --transferable-only
|
||||||
|
return Err(STVError::InvalidOptions("--subtract-nontransferable requires --transferable-only"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if self.min_threshold != "0" && self.defer_surpluses {
|
||||||
|
// TODO: NYI
|
||||||
|
return Err(STVError::InvalidOptions("--min-threshold is incompatible with --defer-surpluses (not yet implemented)"));
|
||||||
|
}
|
||||||
|
if self.round_subtransfers == RoundSubtransfersMode::ByValueAndSource && self.bulk_exclude {
|
||||||
|
// TODO: NYI
|
||||||
|
return Err(STVError::InvalidOptions("--round-subtransfers by_value_and_source is incompatible with --bulk-exclude (not yet implemented)"));
|
||||||
}
|
}
|
||||||
if self.min_threshold != "0" && self.defer_surpluses { return Err(STVError::InvalidOptions("--min-threshold is incompatible with --defer-surpluses (not yet implemented)")); } // TODO: NYI
|
|
||||||
if self.round_subtransfers == RoundSubtransfersMode::ByValueAndSource && self.bulk_exclude { return Err(STVError::InvalidOptions("--round-subtransfers by_value_and_source is incompatible with --bulk-exclude (not yet implemented)")); } // TODO: NYI
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1792,7 +1836,8 @@ pub fn should_show_vre(opts: &STVOptions) -> bool {
|
||||||
if opts.quota_mode == QuotaMode::ERS97 || opts.quota_mode == QuotaMode::ERS76 {
|
if opts.quota_mode == QuotaMode::ERS97 || opts.quota_mode == QuotaMode::ERS76 {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if opts.surplus == SurplusMethod::Meek {
|
if opts.surplus == SurplusMethod::Meek && opts.quota_mode == QuotaMode::DynamicByTotal {
|
||||||
|
// Meek method ensures that, if the quota is recalculated, every candidate will be elected with a quota
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if opts.early_bulk_elect {
|
if opts.early_bulk_elect {
|
||||||
|
|
Loading…
Reference in New Issue