use std::cell::{RefCell};
use ::rand::{Rng,rngs::StdRng,prelude::SliceRandom};
use std::fs::File;
use std::io::{BufRead,BufReader};
use std::ops::DerefMut;
use quantifiable_derive::Quantifiable;use crate::config_parser::ConfigurationValue;
use crate::topology::cartesian::CartesianData;use crate::topology::{Topology,Location};
use crate::quantify::Quantifiable;
use crate::{Plugs,match_object_panic};
pub trait Pattern : Quantifiable + std::fmt::Debug
{
fn initialize(&mut self, source_size:usize, target_size:usize, topology:&dyn Topology, rng: &RefCell<StdRng>);
fn get_destination(&self, origin:usize, topology:&dyn Topology, rng: &RefCell<StdRng>)->usize;
}
#[derive(Debug)]
pub struct PatternBuilderArgument<'a>
{
pub cv: &'a ConfigurationValue,
pub plugs: &'a Plugs,
}
pub fn new_pattern(arg:PatternBuilderArgument) -> Box<dyn Pattern>
{
if let &ConfigurationValue::Object(ref cv_name, ref _cv_pairs)=arg.cv
{
if let Some(builder) = arg.plugs.patterns.get(cv_name)
{
return builder(arg);
}
match cv_name.as_ref()
{
"Identity" => Box::new(Identity::new(arg)),
"Uniform" => Box::new(UniformPattern::new(arg)),
"RandomPermutation" => Box::new(RandomPermutation::new(arg)),
"RandomInvolution" => Box::new(RandomInvolution::new(arg)),
"FileMap" => Box::new(FileMap::new(arg)),
"EmbeddedMap" => Box::new(FileMap::embedded(arg)),
"Product" => Box::new(ProductPattern::new(arg)),
"Components" => Box::new(ComponentsPattern::new(arg)),
"CartesianTransform" => Box::new(CartesianTransform::new(arg)),
"CartesianTiling" => Box::new(CartesianTiling::new(arg)),
"Composition" => Box::new(Composition::new(arg)),
"Pow" => Box::new(Pow::new(arg)),
"CartesianFactor" => Box::new(CartesianFactor::new(arg)),
"Hotspots" => Box::new(Hotspots::new(arg)),
"RandomMix" => Box::new(RandomMix::new(arg)),
"ConstantShuffle" =>
{
println!("WARNING: the name ConstantShuffle is deprecated, use GloballyShufflingDestinations");
Box::new(GloballyShufflingDestinations::new(arg))
}
"GloballyShufflingDestinations" => Box::new(GloballyShufflingDestinations::new(arg)),
"GroupShufflingDestinations" => Box::new(GroupShufflingDestinations::new(arg)),
"UniformDistance" => Box::new(UniformDistance::new(arg)),
"FixedRandom" => Box::new(FixedRandom::new(arg)),
_ => panic!("Unknown pattern {}",cv_name),
}
}
else
{
panic!("Trying to create a Pattern from a non-Object");
}
}
#[derive(Quantifiable)]
#[derive(Debug)]
pub struct Identity
{
}
impl Pattern for Identity
{
fn initialize(&mut self, source_size:usize, target_size:usize, _topology:&dyn Topology, _rng: &RefCell<StdRng>)
{
if source_size!=target_size
{
unimplemented!("The Identity pattern requires source_size({})=target_size({})",source_size,target_size);
}
}
fn get_destination(&self, origin:usize, _topology:&dyn Topology, _rng: &RefCell<StdRng>)->usize
{
origin
}
}
impl Identity
{
fn new(arg:PatternBuilderArgument) -> Identity
{
match_object_panic!(arg.cv,"Identity",_value);
Identity{
}
}
}
#[derive(Quantifiable)]
#[derive(Debug)]
pub struct UniformPattern
{
size: usize,
}
impl Pattern for UniformPattern
{
fn initialize(&mut self, source_size:usize, target_size:usize, _topology:&dyn Topology, _rng: &RefCell<StdRng>)
{
self.size=target_size;
if source_size!=target_size
{
unimplemented!("Different sizes are not yet implemented for UniformPattern");
}
}
fn get_destination(&self, origin:usize, _topology:&dyn Topology, rng: &RefCell<StdRng>)->usize
{
loop
{
let r=rng.borrow_mut().gen_range(0..self.size); if r!=origin
{
return r;
}
}
}
}
impl UniformPattern
{
fn new(arg:PatternBuilderArgument) -> UniformPattern
{
match_object_panic!(arg.cv,"Uniform",_value);
UniformPattern{
size:0, }
}
}
#[derive(Quantifiable)]
#[derive(Debug)]
pub struct RandomPermutation
{
permutation: Vec<usize>,
}
impl Pattern for RandomPermutation
{
fn initialize(&mut self, source_size:usize, target_size:usize, _topology:&dyn Topology, rng: &RefCell<StdRng>)
{
if source_size!=target_size
{
panic!("In a permutation source_size({}) must be equal to target_size({}).",source_size,target_size);
}
self.permutation=(0..source_size).collect();
self.permutation.shuffle(rng.borrow_mut().deref_mut()); }
fn get_destination(&self, origin:usize, _topology:&dyn Topology, _rng: &RefCell<StdRng>)->usize
{
self.permutation[origin]
}
}
impl RandomPermutation
{
fn new(arg:PatternBuilderArgument) -> RandomPermutation
{
match_object_panic!(arg.cv,"RandomPermutation",_value);
RandomPermutation{
permutation: vec![],
}
}
}
#[derive(Quantifiable)]
#[derive(Debug)]
pub struct RandomInvolution
{
permutation: Vec<usize>,
}
impl Pattern for RandomInvolution
{
fn initialize(&mut self, source_size:usize, target_size:usize, _topology:&dyn Topology, rng: &RefCell<StdRng>)
{
if source_size!=target_size
{
panic!("In a permutation source_size({}) must be equal to target_size({}).",source_size,target_size);
}
self.permutation=vec![source_size;source_size];
assert!(source_size%2==0);
let iterations=source_size/2;
let mut max=2;
for _iteration in 0..iterations
{
let first=rng.borrow_mut().gen_range(0..max);
let second=rng.borrow_mut().gen_range(0..max-1);
let (low,high) = if second>=first
{
(first,second+1)
}
else
{
(second,first)
};
let mut rep_low = max-2;
let mut rep_high = max-1;
if high==rep_low
{
rep_high=high;
rep_low=max-1;
}
let mut mate_low=self.permutation[low];
let mut mate_high=self.permutation[high];
if mate_low != source_size
{
if mate_low==high
{
mate_low=rep_high;
}
self.permutation[rep_low]=mate_low;
self.permutation[mate_low]=rep_low;
}
if mate_high != source_size
{
if mate_high==low
{
mate_high=rep_low;
}
self.permutation[rep_high]=mate_high;
self.permutation[mate_high]=rep_high;
}
self.permutation[low]=high;
self.permutation[high]=low;
max+=2;
}
}
fn get_destination(&self, origin:usize, _topology:&dyn Topology, _rng: &RefCell<StdRng>)->usize
{
self.permutation[origin]
}
}
impl RandomInvolution
{
fn new(arg:PatternBuilderArgument) -> RandomInvolution
{
match_object_panic!(arg.cv,"RandomInvolution",_value);
RandomInvolution{
permutation: vec![],
}
}
}
#[derive(Quantifiable)]
#[derive(Debug)]
pub struct FileMap
{
permutation: Vec<usize>,
}
impl Pattern for FileMap
{
fn initialize(&mut self, _source_size:usize, _target_size:usize, _topology:&dyn Topology, _rng: &RefCell<StdRng>)
{
}
fn get_destination(&self, origin:usize, _topology:&dyn Topology, _rng: &RefCell<StdRng>)->usize
{
self.permutation[origin]
}
}
impl FileMap
{
fn new(arg:PatternBuilderArgument) -> FileMap
{
let mut filename=None;
match_object_panic!(arg.cv,"FileMap",value,
"filename" => filename = Some(value.as_str().expect("bad value for filename").to_string()),
);
let filename=filename.expect("There were no filename");
let file=File::open(&filename).expect("could not open pattern file.");
let reader = BufReader::new(&file);
let mut permutation=Vec::new();
for rline in reader.lines()
{
let line=rline.expect("Some problem when reading the traffic pattern.");
let mut words=line.split_whitespace();
let origin=words.next().unwrap().parse::<usize>().unwrap();
let destination=words.next().unwrap().parse::<usize>().unwrap();
while permutation.len()<=origin || permutation.len()<=destination
{
permutation.push((-1isize) as usize); }
permutation[origin]=destination;
}
FileMap{
permutation,
}
}
fn embedded(arg:PatternBuilderArgument) -> FileMap
{
let mut map = None;
match_object_panic!(arg.cv,"EmbeddedMap",value,
"map" => map = Some(value.as_array()
.expect("bad value for map").iter()
.map(|v|v.as_f64().expect("bad value for map") as usize).collect()),
);
let permutation = map.expect("There were no map");
FileMap{
permutation
}
}
}
#[derive(Quantifiable)]
#[derive(Debug)]
pub struct ProductPattern
{
block_size: usize,
block_pattern: Box<dyn Pattern>,
global_pattern: Box<dyn Pattern>,
}
impl Pattern for ProductPattern
{
fn initialize(&mut self, source_size:usize, target_size:usize, topology:&dyn Topology, rng: &RefCell<StdRng>)
{
if source_size!=target_size
{
unimplemented!("Different sizes are not yet implemented for ProductPattern");
}
self.block_pattern.initialize(self.block_size,self.block_size,topology,rng);
let global_size=source_size/self.block_size;
self.global_pattern.initialize(global_size,global_size,topology,rng);
}
fn get_destination(&self, origin:usize, topology:&dyn Topology, rng: &RefCell<StdRng>)->usize
{
let local=origin % self.block_size;
let global=origin / self.block_size;
let local_dest=self.block_pattern.get_destination(local,topology,rng);
let global_dest=self.global_pattern.get_destination(global,topology,rng);
global_dest*self.block_size+local_dest
}
}
impl ProductPattern
{
fn new(arg:PatternBuilderArgument) -> ProductPattern
{
let mut block_size=None;
let mut block_pattern=None;
let mut global_pattern=None;
match_object_panic!(arg.cv,"Product",value,
"block_pattern" => block_pattern=Some(new_pattern(PatternBuilderArgument{cv:value,..arg})),
"global_pattern" => global_pattern=Some(new_pattern(PatternBuilderArgument{cv:value,..arg})),
"block_size" => block_size=Some(value.as_f64().expect("bad value for block_size") as usize),
);
let block_size=block_size.expect("There were no block_size");
let block_pattern=block_pattern.expect("There were no block_pattern");
let global_pattern=global_pattern.expect("There were no global_pattern");
ProductPattern{
block_size,
block_pattern,
global_pattern,
}
}
}
#[derive(Quantifiable)]
#[derive(Debug)]
pub struct ComponentsPattern
{
component_classes: Vec<usize>,
global_pattern: Box<dyn Pattern>,
components: Vec<Vec<usize>>,
}
impl Pattern for ComponentsPattern
{
fn initialize(&mut self, _source_size:usize, _target_size:usize, topology:&dyn Topology, rng: &RefCell<StdRng>)
{
let mut allowed_components=vec![];
for link_class in self.component_classes.iter()
{
if *link_class>=allowed_components.len()
{
allowed_components.resize(*link_class+1,false);
}
allowed_components[*link_class]=true;
}
self.components=topology.components(&allowed_components);
self.global_pattern.initialize(self.components.len(),self.components.len(),topology,rng);
}
fn get_destination(&self, origin:usize, topology:&dyn Topology, rng: &RefCell<StdRng>)->usize
{
let router_origin=match topology.server_neighbour(origin).0
{
Location::RouterPort{
router_index,
router_port: _,
} => router_index,
_ => panic!("what origin?"),
};
let mut global=self.components.len();
for (g,component) in self.components.iter().enumerate()
{
if component.contains(&router_origin)
{
global=g;
break;
}
}
if global==self.components.len()
{
panic!("Could not found component of {}",router_origin);
}
let global_dest=self.global_pattern.get_destination(global,topology,rng);
let r_local=rng.borrow_mut().gen_range(0..self.components[global_dest].len());
let dest=self.components[global_dest][r_local];
let radix=topology.ports(dest);
let mut candidate_stack=Vec::with_capacity(radix);
for port in 0..radix
{
match topology.neighbour(dest,port).0
{
Location::ServerPort(destination) => candidate_stack.push(destination),
_ => (),
}
}
let rserver=rng.borrow_mut().gen_range(0..candidate_stack.len());
candidate_stack[rserver]
}
}
impl ComponentsPattern
{
fn new(arg:PatternBuilderArgument) -> ComponentsPattern
{
let mut component_classes=None;
let mut global_pattern=None;
match_object_panic!(arg.cv,"Components",value,
"global_pattern" => global_pattern=Some(new_pattern(PatternBuilderArgument{cv:value,..arg})),
"component_classes" => component_classes = Some(value.as_array()
.expect("bad value for component_classes").iter()
.map(|v|v.as_f64().expect("bad value in component_classes") as usize).collect()),
);
let component_classes=component_classes.expect("There were no component_classes");
let global_pattern=global_pattern.expect("There were no global_pattern");
ComponentsPattern{
component_classes,
global_pattern,
components:vec![], }
}
}
#[derive(Quantifiable)]
#[derive(Debug)]
pub struct CartesianTransform
{
cartesian_data: CartesianData,
shift: Option<Vec<usize>>,
permute: Option<Vec<usize>>,
complement: Option<Vec<bool>>,
project: Option<Vec<bool>>,
}
impl Pattern for CartesianTransform
{
fn initialize(&mut self, source_size:usize, target_size:usize, _topology:&dyn Topology, _rng: &RefCell<StdRng>)
{
if source_size!=target_size
{
panic!("In a Cartesiantransform source_size({}) must be equal to target_size({}).",source_size,target_size);
}
if source_size!=self.cartesian_data.size
{
panic!("Sizes do not agree on CartesianTransform.");
}
}
fn get_destination(&self, origin:usize, _topology:&dyn Topology, _rng: &RefCell<StdRng>)->usize
{
let up_origin=self.cartesian_data.unpack(origin);
let up_shifted=match self.shift
{
Some(ref v) => v.iter().enumerate().map(|(index,&value)|(up_origin[index]+value)%self.cartesian_data.sides[index]).collect(),
None => up_origin,
};
let up_permuted=match self.permute
{
Some(ref v) => v.iter().map(|&index|up_shifted[index]).collect(),
None => up_shifted,
};
let up_complemented=match self.complement
{
Some(ref v) => up_permuted.iter().enumerate().map(|(index,&value)|if v[index]{self.cartesian_data.sides[index]-1-value}else {value}).collect(),
None => up_permuted,
};
let up_projected=match self.project
{
Some(ref v) => up_complemented.iter().enumerate().map(|(index,&value)|if v[index]{0} else {value}).collect(),
None => up_complemented,
};
self.cartesian_data.pack(&up_projected)
}
}
impl CartesianTransform
{
fn new(arg:PatternBuilderArgument) -> CartesianTransform
{
let mut sides:Option<Vec<_>>=None;
let mut shift=None;
let mut permute=None;
let mut complement=None;
let mut project=None;
match_object_panic!(arg.cv,"CartesianTransform",value,
"sides" => sides = Some(value.as_array().expect("bad value for sides").iter()
.map(|v|v.as_f64().expect("bad value in sides") as usize).collect()),
"shift" => shift=Some(value.as_array().expect("bad value for shift").iter()
.map(|v|v.as_f64().expect("bad value in shift") as usize).collect()),
"permute" => permute=Some(value.as_array().expect("bad value for permute").iter()
.map(|v|v.as_f64().expect("bad value in permute") as usize).collect()),
"complement" => complement=Some(value.as_array().expect("bad value for complement").iter()
.map(|v|v.as_bool().expect("bad value in complement")).collect()),
"project" => project=Some(value.as_array().expect("bad value for project").iter()
.map(|v|v.as_bool().expect("bad value in project")).collect()),
);
let sides=sides.expect("There were no sides");
CartesianTransform{
cartesian_data: CartesianData::new(&sides),
shift,
permute,
complement,
project,
}
}
}
#[derive(Quantifiable)]
#[derive(Debug)]
struct CartesianTiling
{
pattern: Box<dyn Pattern>,
base_cartesian_data: CartesianData,
repetitions: Vec<usize>,
final_cartesian_data: CartesianData,
}
impl Pattern for CartesianTiling
{
fn initialize(&mut self, source_size:usize, target_size:usize, topology:&dyn Topology, rng: &RefCell<StdRng>)
{
let factor: usize = self.repetitions.iter().product();
assert!(source_size % factor == 0);
assert!(target_size % factor == 0);
let base_source_size = source_size / factor;
let base_target_size = target_size / factor;
self.pattern.initialize(base_source_size,base_target_size,topology,rng);
}
fn get_destination(&self, origin:usize, topology:&dyn Topology, rng: &RefCell<StdRng>)->usize
{
let up_origin=self.final_cartesian_data.unpack(origin);
let n=up_origin.len();
let base_up_origin:Vec<usize> = (0..n).map(|index|up_origin[index]%self.base_cartesian_data.sides[index]).collect();
let base_origin = self.base_cartesian_data.pack(&base_up_origin);
let base_destination = self.pattern.get_destination(base_origin,topology,rng);
let base_up_destination = self.base_cartesian_data.unpack(base_destination);
let up_destination:Vec<usize> = (0..n).map(|index|{
let size = self.base_cartesian_data.sides[index];
let tile = up_origin[index]/size;
base_up_destination[index] + size*tile
}).collect();
self.final_cartesian_data.pack(&up_destination)
}
}
impl CartesianTiling
{
pub fn new(arg:PatternBuilderArgument) -> CartesianTiling
{
let mut pattern = None;
let mut sides:Option<Vec<_>>=None;
let mut repetitions:Option<Vec<_>> = None;
match_object_panic!(arg.cv,"CartesianTiling",value,
"pattern" => pattern=Some(new_pattern(PatternBuilderArgument{cv:value,..arg})),
"sides" => sides = Some(value.as_array().expect("bad value for sides").iter()
.map(|v|v.as_f64().expect("bad value in sides") as usize).collect()),
"repetitions" => repetitions = Some(value.as_array().expect("bad value for repetitions").iter()
.map(|v|v.as_f64().expect("bad value in repetitions") as usize).collect()),
);
let pattern=pattern.expect("There were no pattern");
let sides=sides.expect("There were no sides");
let repetitions=repetitions.expect("There were no repetitions");
let n=sides.len();
assert!(n==repetitions.len());
let final_sides : Vec<_> = (0..n).map(|index|sides[index]*repetitions[index]).collect();
CartesianTiling{
pattern,
base_cartesian_data: CartesianData::new(&sides),
repetitions,
final_cartesian_data: CartesianData::new(&final_sides),
}
}
}
#[derive(Quantifiable)]
#[derive(Debug)]
pub struct Composition
{
patterns: Vec<Box<dyn Pattern>>,
}
impl Pattern for Composition
{
fn initialize(&mut self, source_size:usize, target_size:usize, topology:&dyn Topology, rng: &RefCell<StdRng>)
{
for pattern in self.patterns.iter_mut()
{
pattern.initialize(source_size,target_size,topology,rng);
}
}
fn get_destination(&self, origin:usize, topology:&dyn Topology, rng: &RefCell<StdRng>)->usize
{
let mut destination=origin;
for pattern in self.patterns.iter()
{
destination=pattern.get_destination(destination,topology,rng);
}
destination
}
}
impl Composition
{
fn new(arg:PatternBuilderArgument) -> Composition
{
let mut patterns=None;
match_object_panic!(arg.cv,"Composition",value,
"patterns" => patterns=Some(value.as_array().expect("bad value for patterns").iter()
.map(|pcv|new_pattern(PatternBuilderArgument{cv:pcv,..arg})).collect()),
);
let patterns=patterns.expect("There were no patterns");
Composition{
patterns,
}
}
}
#[derive(Quantifiable)]
#[derive(Debug)]
pub struct Pow
{
pattern: Box<dyn Pattern>,
exponent: usize,
}
impl Pattern for Pow
{
fn initialize(&mut self, source_size:usize, target_size:usize, topology:&dyn Topology, rng: &RefCell<StdRng>)
{
self.pattern.initialize(source_size,target_size,topology,rng);
}
fn get_destination(&self, origin:usize, topology:&dyn Topology, rng: &RefCell<StdRng>)->usize
{
let mut destination=origin;
for _ in 0..self.exponent
{
destination=self.pattern.get_destination(destination,topology,rng);
}
destination
}
}
impl Pow
{
fn new(arg:PatternBuilderArgument) -> Pow
{
let mut pattern=None;
let mut exponent=None;
match_object_panic!(arg.cv,"Pow",value,
"pattern" => pattern=Some(new_pattern(PatternBuilderArgument{cv:value,..arg})),
"exponent" => exponent=Some(value.as_f64().expect("bad value for exponent") as usize),
);
let pattern=pattern.expect("There were no pattern");
let exponent=exponent.expect("There were no exponent");
Pow{
pattern,
exponent,
}
}
}
#[derive(Quantifiable)]
#[derive(Debug)]
pub struct CartesianFactor
{
cartesian_data: CartesianData,
factors: Vec<f64>,
target_size: usize,
}
impl Pattern for CartesianFactor
{
fn initialize(&mut self, source_size:usize, target_size:usize, _topology:&dyn Topology, _rng: &RefCell<StdRng>)
{
self.target_size = target_size;
if source_size!=self.cartesian_data.size
{
panic!("Sizes do not agree on CartesianFactor.");
}
}
fn get_destination(&self, origin:usize, _topology:&dyn Topology, _rng: &RefCell<StdRng>)->usize
{
let up_origin=self.cartesian_data.unpack(origin);
let destination = up_origin.iter().zip(self.factors.iter()).map(|(&coord,&f)|coord as f64 * f).sum::<f64>() as usize;
destination % self.target_size
}
}
impl CartesianFactor
{
fn new(arg:PatternBuilderArgument) -> CartesianFactor
{
let mut sides: Option<Vec<_>>=None;
let mut factors=None;
match_object_panic!(arg.cv,"CartesianFactor",value,
"sides" => sides=Some(value.as_array().expect("bad value for sides").iter()
.map(|v|v.as_f64().expect("bad value in sides") as usize).collect()),
"factors" => factors=Some(value.as_array().expect("bad value for factors").iter()
.map(|v|v.as_f64().expect("bad value in factors")).collect()),
);
let sides=sides.expect("There were no sides");
let factors=factors.expect("There were no factors");
CartesianFactor{
cartesian_data: CartesianData::new(&sides),
factors,
target_size:0,
}
}
}
#[derive(Quantifiable)]
#[derive(Debug)]
pub struct Hotspots
{
destinations: Vec<usize>,
extra_random_destinations: usize
}
impl Pattern for Hotspots
{
fn initialize(&mut self, _source_size:usize, target_size:usize, _topology:&dyn Topology, rng: &RefCell<StdRng>)
{
for _ in 0..self.extra_random_destinations
{
let r=rng.borrow_mut().gen_range(0..target_size);
self.destinations.push(r);
}
if self.destinations.is_empty()
{
panic!("The Hotspots pattern requires to have at least one destination.");
}
}
fn get_destination(&self, _origin:usize, _topology:&dyn Topology, rng: &RefCell<StdRng>)->usize
{
let r = rng.borrow_mut().gen_range(0..self.destinations.len());
self.destinations[r]
}
}
impl Hotspots
{
fn new(arg:PatternBuilderArgument) -> Hotspots
{
let mut destinations=None;
let mut extra_random_destinations=None;
match_object_panic!(arg.cv,"Hotspots",value,
"destinations" => destinations=Some(value.as_array().expect("bad value for destinations").iter()
.map(|v|v.as_f64().expect("bad value in destinations") as usize).collect()),
"extra_random_destinations" => extra_random_destinations=Some(
value.as_f64().unwrap_or_else(|_|panic!("bad value for extra_random_destinations ({:?})",value)) as usize),
);
let destinations=destinations.unwrap_or_default();
let extra_random_destinations=extra_random_destinations.unwrap_or(0);
Hotspots{
destinations,
extra_random_destinations,
}
}
}
#[derive(Quantifiable)]
#[derive(Debug)]
pub struct RandomMix
{
patterns: Vec<Box<dyn Pattern>>,
weights: Vec<usize>,
total_weight: usize,
}
impl Pattern for RandomMix
{
fn initialize(&mut self, source_size:usize, target_size:usize, topology:&dyn Topology, rng: &RefCell<StdRng>)
{
if self.patterns.len()!=self.weights.len()
{
panic!("Number of patterns must match number of weights for the RandomMix meta-pattern.");
}
if self.patterns.is_empty()
{
panic!("RandomMix requires at least one pattern (and 2 to be sensible).");
}
for pat in self.patterns.iter_mut()
{
pat.initialize(source_size,target_size,topology,rng);
}
self.total_weight=self.weights.iter().sum();
}
fn get_destination(&self, origin:usize, topology:&dyn Topology, rng: &RefCell<StdRng>)->usize
{
let mut w = rng.borrow_mut().gen_range(0..self.total_weight);
let mut index = 0;
while w>self.weights[index]
{
w-=self.weights[index];
index+=1;
}
self.patterns[index].get_destination(origin,topology,rng)
}
}
impl RandomMix
{
fn new(arg:PatternBuilderArgument) -> RandomMix
{
let mut patterns=None;
let mut weights=None;
match_object_panic!(arg.cv,"RandomMix",value,
"patterns" => patterns=Some(value.as_array().expect("bad value for patterns").iter()
.map(|pcv|new_pattern(PatternBuilderArgument{cv:pcv,..arg})).collect()),
"weights" => weights=Some(value.as_array().expect("bad value for weights").iter()
.map(|v|v.as_f64().expect("bad value in weights") as usize).collect()),
);
let patterns=patterns.expect("There were no patterns");
let weights=weights.expect("There were no weights");
RandomMix{
patterns,
weights,
total_weight:0, }
}
}
#[derive(Quantifiable)]
#[derive(Debug)]
pub struct GloballyShufflingDestinations
{
size: usize,
pending: RefCell<Vec<usize>>,
}
impl Pattern for GloballyShufflingDestinations
{
fn initialize(&mut self, _source_size:usize, target_size:usize, _topology:&dyn Topology, _rng: &RefCell<StdRng>)
{
self.size=target_size;
self.pending=RefCell::new(Vec::with_capacity(self.size));
}
fn get_destination(&self, _origin:usize, _topology:&dyn Topology, rng: &RefCell<StdRng>)->usize
{
let mut pending = self.pending.borrow_mut();
if pending.is_empty()
{
for i in 0..self.size
{
pending.push(i);
}
pending.shuffle(rng.borrow_mut().deref_mut()); }
pending.pop().unwrap()
}
}
impl GloballyShufflingDestinations
{
fn new(arg:PatternBuilderArgument) -> GloballyShufflingDestinations
{
match_object_panic!(arg.cv,"GloballyShufflingDestinations",_value);
GloballyShufflingDestinations{
size:0, pending:RefCell::new(Vec::new()), }
}
}
#[derive(Quantifiable)]
#[derive(Debug)]
pub struct GroupShufflingDestinations
{
group_size: usize,
size: usize,
pending: Vec<RefCell<Vec<usize>>>,
}
impl Pattern for GroupShufflingDestinations
{
fn initialize(&mut self, source_size:usize, target_size:usize, _topology:&dyn Topology, _rng: &RefCell<StdRng>)
{
self.size = target_size;
let number_of_groups = (source_size+self.group_size-1) / self.group_size; self.pending=vec![RefCell::new(Vec::with_capacity(self.size)) ; number_of_groups];
}
fn get_destination(&self, origin:usize, _topology:&dyn Topology, rng: &RefCell<StdRng>)->usize
{
let group = origin / self.group_size;
let mut pending = self.pending[group].borrow_mut();
if pending.is_empty()
{
for i in 0..self.size
{
pending.push(i);
}
pending.shuffle(rng.borrow_mut().deref_mut()); }
pending.pop().unwrap()
}
}
impl GroupShufflingDestinations
{
fn new(arg:PatternBuilderArgument) -> GroupShufflingDestinations
{
let mut group_size = None;
if let &ConfigurationValue::Object(ref cv_name, ref cv_pairs)=arg.cv
{
if cv_name!="GroupShufflingDestinations"
{
panic!("A GroupShufflingDestinations must be created from a `GroupShufflingDestinations` object not `{}`",cv_name);
}
for &(ref name,ref value) in cv_pairs
{
match AsRef::<str>::as_ref(&name)
{
"group_size" => match value
{
&ConfigurationValue::Number(f) => group_size=Some(f as usize),
_ => panic!("bad value for group_size"),
}
"legend_name" => (),
_ => panic!("Nothing to do with field {} in GroupShufflingDestinations",name),
}
}
}
else
{
panic!("Trying to create a GroupShufflingDestinations from a non-Object");
}
let group_size = group_size.expect("There was no group_size");
GroupShufflingDestinations{
group_size,
size:0, pending:vec![], }
}
}
#[derive(Quantifiable)]
#[derive(Debug)]
pub struct UniformDistance
{
distance: usize,
concentration: usize,
pool: Vec<Vec<usize>>,
}
impl Pattern for UniformDistance
{
fn initialize(&mut self, source_size:usize, target_size:usize, topology:&dyn Topology, _rng: &RefCell<StdRng>)
{
let n=topology.num_routers();
assert!(source_size==target_size,"The UniformDistance pattern needs source_size({})==target_size({})",source_size,target_size);
assert!(source_size%n == 0,"The UniformDistance pattern needs the number of routers({}) to be a divisor of source_size({})",n,source_size);
self.concentration = source_size/n;
self.pool.reserve(n);
for i in 0..n
{
let mut found: Vec<usize> = (0..n).filter(|&j|topology.distance(i,j)==self.distance).collect();
found.shrink_to_fit();
self.pool.push(found);
}
}
fn get_destination(&self, origin:usize, _topology:&dyn Topology, rng: &RefCell<StdRng>)->usize
{
let pool = &self.pool[origin/self.concentration];
let r=rng.borrow_mut().gen_range(0..pool.len());
pool[r]*self.concentration + (origin%self.concentration)
}
}
impl UniformDistance
{
fn new(arg:PatternBuilderArgument) -> UniformDistance
{
let mut distance = None;
match_object_panic!(arg.cv,"UniformDistance",value,
"distance" => distance=Some(value.as_f64().expect("bad value for distance") as usize),
);
let distance = distance.expect("There were no distance");
UniformDistance{
distance,
concentration:0, pool: vec![], }
}
}
#[derive(Quantifiable)]
#[derive(Debug)]
pub struct FixedRandom
{
map: Vec<usize>,
allow_self: bool,
}
impl Pattern for FixedRandom
{
fn initialize(&mut self, source_size:usize, target_size:usize, _topology:&dyn Topology, rng: &RefCell<StdRng>)
{
self.map.reserve(source_size);
let mut rng = rng.borrow_mut();
for source in 0..source_size
{
let n = if self.allow_self || target_size<source { target_size } else { target_size -1 };
let mut elem = rng.gen_range(0..n);
if !self.allow_self && elem>=source
{
elem += 1;
}
self.map.push(elem);
}
}
fn get_destination(&self, origin:usize, _topology:&dyn Topology, _rng: &RefCell<StdRng>)->usize
{
self.map[origin]
}
}
impl FixedRandom
{
fn new(arg:PatternBuilderArgument) -> FixedRandom
{
let mut allow_self = false;
match_object_panic!(arg.cv,"FixedRandom",value,
"allow_self" => allow_self=value.as_bool().expect("bad value for allow_self"),
);
FixedRandom{
map: vec![], allow_self,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use rand::SeedableRng;
#[test]
fn fixed_random_self()
{
let plugs = Plugs::default();
let cv = ConfigurationValue::Object("FixedRandom".to_string(),vec![("allow_self".to_string(),ConfigurationValue::True)]);
let rng=RefCell::new(StdRng::seed_from_u64(10u64));
use crate::topology::{new_topology,TopologyBuilderArgument};
let topo_cv = ConfigurationValue::Object("Hamming".to_string(),vec![("sides".to_string(),ConfigurationValue::Array(vec![])), ("servers_per_router".to_string(),ConfigurationValue::Number(1.0))]);
let dummy_topology = new_topology(TopologyBuilderArgument{cv:&topo_cv,plugs:&plugs,rng:&rng});
for size in [1000]
{
let mut count = 0;
let sizef = size as f64;
let sample_size = 100;
let expected_unique = sizef* ( (sizef-1.0)/sizef ).powf(sizef-1.0) * sample_size as f64;
let mut unique_count = 0;
for _ in 0..sample_size
{
let arg = PatternBuilderArgument{ cv:&cv, plugs:&plugs };
let mut with_self = FixedRandom::new(arg);
with_self.initialize(size,size,&*dummy_topology,&rng);
let mut dests = vec![0;size];
for origin in 0..size
{
let destination = with_self.get_destination(origin,&*dummy_topology,&rng);
if destination==origin
{
count+=1;
}
dests[destination]+=1;
}
unique_count += dests.iter().filter(|&&x|x==1).count();
}
assert!( count>=sample_size-1,"too few self messages {}, expecting {}",count,sample_size);
assert!( count<=sample_size+1,"too many self messages {}, expecting {}",count,sample_size);
assert!( (unique_count as f64) >= expected_unique*0.99 ,"too few unique destinations {}, expecting {}",unique_count,expected_unique);
assert!( (unique_count as f64) <= expected_unique*1.01 ,"too many unique destinations {}, expecting {}",unique_count,expected_unique);
}
let cv = ConfigurationValue::Object("FixedRandom".to_string(),vec![("allow_self".to_string(),ConfigurationValue::False)]);
for logsize in 1..10
{
let arg = PatternBuilderArgument{ cv:&cv, plugs:&plugs };
let size = 2usize.pow(logsize);
let mut without_self = FixedRandom::new(arg);
without_self.initialize(size,size,&*dummy_topology,&rng);
let count = (0..size).filter( |&origin| origin==without_self.get_destination(origin,&*dummy_topology,&rng) ).count();
assert!(count==0, "Got {} selfs at size {}.", count, size );
}
}
}