use crate::error::Error;
use crate::framework::ValueBasedFramework;
use crate::types::{Audience, Value};
use std::hash::Hash;
pub const ENUMERATION_LIMIT: usize = 6;
pub fn subjectively_accepted<A>(
vaf: &ValueBasedFramework<A>,
arg: &A,
) -> Result<bool, Error>
where
A: Clone + Eq + Hash + Ord + std::fmt::Debug,
{
let values: Vec<Value> = vaf
.value_assignment()
.distinct_values()
.into_iter()
.cloned()
.collect();
if values.len() > ENUMERATION_LIMIT {
return Err(Error::AudienceTooLarge {
values: values.len(),
limit: ENUMERATION_LIMIT,
});
}
for perm in permutations(&values) {
let audience = Audience::total(perm);
if vaf.accepted_for(&audience, arg)? {
return Ok(true);
}
}
Ok(false)
}
pub fn objectively_accepted<A>(
vaf: &ValueBasedFramework<A>,
arg: &A,
) -> Result<bool, Error>
where
A: Clone + Eq + Hash + Ord + std::fmt::Debug,
{
let values: Vec<Value> = vaf
.value_assignment()
.distinct_values()
.into_iter()
.cloned()
.collect();
if values.len() > ENUMERATION_LIMIT {
return Err(Error::AudienceTooLarge {
values: values.len(),
limit: ENUMERATION_LIMIT,
});
}
for perm in permutations(&values) {
let audience = Audience::total(perm);
if !vaf.accepted_for(&audience, arg)? {
return Ok(false);
}
}
Ok(true)
}
fn permutations<T: Clone>(items: &[T]) -> Vec<Vec<T>> {
let mut result = Vec::new();
let mut working: Vec<T> = items.to_vec();
permute_recursive(&mut working, 0, &mut result);
result
}
fn permute_recursive<T: Clone>(items: &mut [T], start: usize, out: &mut Vec<Vec<T>>) {
if start == items.len() {
out.push(items.to_vec());
return;
}
for i in start..items.len() {
items.swap(start, i);
permute_recursive(items, start + 1, out);
items.swap(start, i);
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::types::ValueAssignment;
use argumentation::ArgumentationFramework;
fn hal_carla() -> ValueBasedFramework<&'static str> {
let mut base = ArgumentationFramework::new();
for arg in ["h1", "c1", "h2", "c2"] {
base.add_argument(arg);
}
base.add_attack(&"h1", &"c1").unwrap();
base.add_attack(&"c1", &"h1").unwrap();
base.add_attack(&"c2", &"h2").unwrap();
base.add_attack(&"h2", &"c1").unwrap();
let mut values = ValueAssignment::new();
values.promote("h1", Value::new("life"));
values.promote("c1", Value::new("property"));
values.promote("h2", Value::new("fairness"));
values.promote("c2", Value::new("life"));
ValueBasedFramework::new(base, values)
}
#[test]
fn c2_objectively_accepted() {
let vaf = hal_carla();
assert!(objectively_accepted(&vaf, &"c2").unwrap());
}
#[test]
fn h1_subjectively_but_not_objectively_accepted() {
let vaf = hal_carla();
assert!(subjectively_accepted(&vaf, &"h1").unwrap());
assert!(!objectively_accepted(&vaf, &"h1").unwrap());
}
#[test]
fn c1_subjectively_but_not_objectively_accepted() {
let vaf = hal_carla();
assert!(subjectively_accepted(&vaf, &"c1").unwrap());
assert!(!objectively_accepted(&vaf, &"c1").unwrap());
}
#[test]
fn audience_too_large_returns_error() {
let mut base = ArgumentationFramework::new();
for arg in ["a", "b", "c", "d", "e", "f", "g"] {
base.add_argument(arg);
}
let mut values = ValueAssignment::new();
for (i, name) in ["v1", "v2", "v3", "v4", "v5", "v6", "v7"].iter().enumerate() {
let arg = ["a", "b", "c", "d", "e", "f", "g"][i];
values.promote(arg, Value::new(*name));
}
let vaf = ValueBasedFramework::new(base, values);
let result = subjectively_accepted(&vaf, &"a");
assert!(matches!(
result,
Err(Error::AudienceTooLarge { values: 7, limit: 6 })
));
}
#[test]
fn permutations_of_three_yields_six() {
let perms = permutations(&[1, 2, 3]);
assert_eq!(perms.len(), 6);
}
#[test]
fn permutations_of_zero_yields_one_empty() {
let perms: Vec<Vec<i32>> = permutations(&[]);
assert_eq!(perms.len(), 1);
assert!(perms[0].is_empty());
}
}