use std::cell::{RefCell};
use ::rand::{Rng,StdRng};
use std::fs::File;
use std::io::{BufRead,BufReader};
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;
pub trait Pattern : Quantifiable + std::fmt::Debug
{
fn initialize(&mut self, source_size:usize, target_size:usize, topology:&Box<dyn Topology>, rng: &RefCell<StdRng>);
fn get_destination(&self, origin:usize, topology:&Box<dyn Topology>, rng: &RefCell<StdRng>)->usize;
}
#[non_exhaustive]
#[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
{
match arg.plugs.patterns.get(cv_name)
{
Some(builder) => return builder(arg),
_ => (),
};
match cv_name.as_ref()
{
"Uniform" => Box::new(UniformPattern::new(arg)),
"RandomPermutation" => Box::new(RandomPermutation::new(arg)),
"RandomInvolution" => Box::new(RandomInvolution::new(arg)),
"FileMap" => Box::new(FileMap::new(arg)),
"Product" => Box::new(ProductPattern::new(arg)),
"Components" => Box::new(ComponentsPattern::new(arg)),
"CartesianTransform" => Box::new(CartesianTransform::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)),
_ => panic!("Unknown pattern {}",cv_name),
}
}
else
{
panic!("Trying to create a Pattern from a non-Object");
}
}
#[derive(Quantifiable)]
#[derive(Debug)]
pub struct UniformPattern
{
size: usize,
}
impl Pattern for UniformPattern
{
fn initialize(&mut self, source_size:usize, target_size:usize, _topology:&Box<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:&Box<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
{
if let &ConfigurationValue::Object(ref cv_name, ref cv_pairs)=arg.cv
{
if cv_name!="Uniform"
{
panic!("A UniformPattern must be created from a `Uniform` object not `{}`",cv_name);
}
for &(ref name,ref _value) in cv_pairs
{
match AsRef::<str>::as_ref(&name)
{
"legend_name" => (),
_ => panic!("Nothing to do with field {} in UniformPattern",name),
}
}
}
else
{
panic!("Trying to create a UniformPattern from a non-Object");
}
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:&Box<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();
rng.borrow_mut().shuffle(&mut self.permutation);
}
fn get_destination(&self, origin:usize, _topology:&Box<dyn Topology>, _rng: &RefCell<StdRng>)->usize
{
self.permutation[origin]
}
}
impl RandomPermutation
{
fn new(arg:PatternBuilderArgument) -> RandomPermutation
{
if let &ConfigurationValue::Object(ref cv_name, ref cv_pairs)=arg.cv
{
if cv_name!="RandomPermutation"
{
panic!("A RandomPermutation must be created from a `RandomPermutation` object not `{}`",cv_name);
}
for &(ref name,ref _value) in cv_pairs
{
match AsRef::<str>::as_ref(&name)
{
"legend_name" => (),
_ => panic!("Nothing to do with field {} in RandomPermutation",name),
}
}
}
else
{
panic!("Trying to create a RandomPermutation from a non-Object");
}
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:&Box<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:&Box<dyn Topology>, _rng: &RefCell<StdRng>)->usize
{
self.permutation[origin]
}
}
impl RandomInvolution
{
fn new(arg:PatternBuilderArgument) -> RandomInvolution
{
if let &ConfigurationValue::Object(ref cv_name, ref cv_pairs)=arg.cv
{
if cv_name!="RandomInvolution"
{
panic!("A RandomInvolution must be created from a `RandomInvolution` object not `{}`",cv_name);
}
for &(ref name,ref _value) in cv_pairs
{
match AsRef::<str>::as_ref(&name)
{
"legend_name" => (),
_ => panic!("Nothing to do with field {} in RandomInvolution",name),
}
}
}
else
{
panic!("Trying to create a RandomInvolution from a non-Object");
}
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:&Box<dyn Topology>, _rng: &RefCell<StdRng>)
{
}
fn get_destination(&self, origin:usize, _topology:&Box<dyn Topology>, _rng: &RefCell<StdRng>)->usize
{
self.permutation[origin]
}
}
impl FileMap
{
fn new(arg:PatternBuilderArgument) -> FileMap
{
let mut filename=None;
if let &ConfigurationValue::Object(ref cv_name, ref cv_pairs)=arg.cv
{
if cv_name!="FileMap"
{
panic!("A FileMap must be created from a `FileMap` object not `{}`",cv_name);
}
for &(ref name,ref value) in cv_pairs
{
match AsRef::<str>::as_ref(&name)
{
"filename" => match value
{
&ConfigurationValue::Literal(ref s) => filename=Some(s.to_string()),
_ => panic!("bad value for filename"),
},
"legend_name" => (),
_ => panic!("Nothing to do with field {} in FileMap",name),
}
}
}
else
{
panic!("Trying to create a FileMap from a non-Object");
}
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 lines=reader.lines();
let mut permutation=Vec::new();
while let Some(rline)=lines.next()
{
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,
}
}
}
#[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:&Box<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:&Box<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;
if let &ConfigurationValue::Object(ref cv_name, ref cv_pairs)=arg.cv
{
if cv_name!="Product"
{
panic!("A ProductPattern must be created from a `Product` object not `{}`",cv_name);
}
for &(ref name,ref value) in cv_pairs
{
match AsRef::<str>::as_ref(&name)
{
"block_pattern" => block_pattern=Some(new_pattern(PatternBuilderArgument{cv:value,..arg})),
"global_pattern" => global_pattern=Some(new_pattern(PatternBuilderArgument{cv:value,..arg})),
"block_size" => match value
{
&ConfigurationValue::Number(f) => block_size=Some(f as usize),
_ => panic!("bad value for block_size"),
}
"legend_name" => (),
_ => panic!("Nothing to do with field {} in ProductPattern",name),
}
}
}
else
{
panic!("Trying to create a ProductPattern from a non-Object");
}
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:&Box<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:&Box<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;
if let &ConfigurationValue::Object(ref cv_name, ref cv_pairs)=arg.cv
{
if cv_name!="Components"
{
panic!("A ComponentsPattern must be created from a `Components` object not `{}`",cv_name);
}
for &(ref name,ref value) in cv_pairs
{
match AsRef::<str>::as_ref(&name)
{
"global_pattern" => global_pattern=Some(new_pattern(PatternBuilderArgument{cv:value,..arg})),
"component_classes" => match value
{
&ConfigurationValue::Array(ref a) => component_classes=Some(a.iter().map(|v|match v{
&ConfigurationValue::Number(f) => f as usize,
_ => panic!("bad value in component_classes"),
}).collect()),
_ => panic!("bad value for component_classes"),
}
"legend_name" => (),
_ => panic!("Nothing to do with field {} in ComponentsPattern",name),
}
}
}
else
{
panic!("Trying to create a ComponentsPattern from a non-Object");
}
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>>,
}
impl Pattern for CartesianTransform
{
fn initialize(&mut self, source_size:usize, target_size:usize, _topology:&Box<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:&Box<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,
};
self.cartesian_data.pack(&up_complemented)
}
}
impl CartesianTransform
{
fn new(arg:PatternBuilderArgument) -> CartesianTransform
{
let mut sides=None;
let mut shift=None;
let mut permute=None;
let mut complement=None;
if let &ConfigurationValue::Object(ref cv_name, ref cv_pairs)=arg.cv
{
if cv_name!="CartesianTransform"
{
panic!("A CartesianTransform must be created from a `CartesianTransform` object not `{}`",cv_name);
}
for &(ref name,ref value) in cv_pairs
{
match AsRef::<str>::as_ref(&name)
{
"sides" => match value
{
&ConfigurationValue::Array(ref a) => sides=Some(a.iter().map(|v|match v{
&ConfigurationValue::Number(f) => f as usize,
_ => panic!("bad value in sides"),
}).collect()),
_ => panic!("bad value for sides"),
}
"shift" => match value
{
&ConfigurationValue::Array(ref a) => shift=Some(a.iter().map(|v|match v{
&ConfigurationValue::Number(f) => f as usize,
_ => panic!("bad value in shift"),
}).collect()),
_ => panic!("bad value for shift"),
}
"permute" => match value
{
&ConfigurationValue::Array(ref a) => permute=Some(a.iter().map(|v|match v{
&ConfigurationValue::Number(f) => f as usize,
_ => panic!("bad value in permute"),
}).collect()),
_ => panic!("bad value for permute"),
}
"complement" => match value
{
&ConfigurationValue::Array(ref a) => complement=Some(a.iter().map(|v|match v{
&ConfigurationValue::True => true,
&ConfigurationValue::False => false,
_ => panic!("bad value in complement"),
}).collect()),
_ => panic!("bad value for complement"),
}
"legend_name" => (),
_ => panic!("Nothing to do with field {} in CartesianTransform",name),
}
}
}
else
{
panic!("Trying to create a CartesianTransform from a non-Object");
}
let sides=sides.expect("There were no sides");
CartesianTransform{
cartesian_data: CartesianData::new(&sides),
shift,
permute,
complement,
}
}
}
#[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:&Box<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:&Box<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;
if let &ConfigurationValue::Object(ref cv_name, ref cv_pairs)=arg.cv
{
if cv_name!="Composition"
{
panic!("A Composition must be created from a `Composition` object not `{}`",cv_name);
}
for &(ref name,ref value) in cv_pairs
{
match AsRef::<str>::as_ref(&name)
{
"patterns" => match value
{
&ConfigurationValue::Array(ref l) => patterns=Some(l.iter().map(|pcv|new_pattern(PatternBuilderArgument{cv:pcv,..arg})).collect()),
_ => panic!("bad value for patterns"),
}
"legend_name" => (),
_ => panic!("Nothing to do with field {} in Composition",name),
}
}
}
else
{
panic!("Trying to create a Composition from a non-Object");
}
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:&Box<dyn Topology>, rng: &RefCell<StdRng>)
{
self.pattern.initialize(source_size,target_size,topology,rng);
}
fn get_destination(&self, origin:usize, topology:&Box<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;
if let &ConfigurationValue::Object(ref cv_name, ref cv_pairs)=arg.cv
{
if cv_name!="Pow"
{
panic!("A Pow must be created from a `Pow` object not `{}`",cv_name);
}
for &(ref name,ref value) in cv_pairs
{
match AsRef::<str>::as_ref(&name)
{
"pattern" => pattern=Some(new_pattern(PatternBuilderArgument{cv:value,..arg})),
"exponent" => match value
{
&ConfigurationValue::Number(x) => exponent=Some(x as usize),
_ => panic!("bad value for exponent"),
},
"legend_name" => (),
_ => panic!("Nothing to do with field {} in Pow",name),
}
}
}
else
{
panic!("Trying to create a Pow from a non-Object");
}
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:&Box<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:&Box<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=None;
let mut factors=None;
if let &ConfigurationValue::Object(ref cv_name, ref cv_pairs)=arg.cv
{
if cv_name!="CartesianFactor"
{
panic!("A CartesianFactor must be created from a `CartesianFactor` object not `{}`",cv_name);
}
for &(ref name,ref value) in cv_pairs
{
match AsRef::<str>::as_ref(&name)
{
"sides" => match value
{
&ConfigurationValue::Array(ref a) => sides=Some(a.iter().map(|v|match v{
&ConfigurationValue::Number(f) => f as usize,
_ => panic!("bad value in sides"),
}).collect()),
_ => panic!("bad value for sides"),
}
"factors" => match value
{
&ConfigurationValue::Array(ref a) => factors=Some(a.iter().map(|v|match v{
&ConfigurationValue::Number(f) => f,
_ => panic!("bad value in factors"),
}).collect()),
_ => panic!("bad value for factors"),
}
"legend_name" => (),
_ => panic!("Nothing to do with field {} in CartesianFactor",name),
}
}
}
else
{
panic!("Trying to create a CartesianFactor from a non-Object");
}
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:&Box<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:&Box<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;
if let &ConfigurationValue::Object(ref cv_name, ref cv_pairs)=arg.cv
{
if cv_name!="Hotspots"
{
panic!("A Hotspots must be created from a `Hotspots` object not `{}`",cv_name);
}
for &(ref name,ref value) in cv_pairs
{
match AsRef::<str>::as_ref(&name)
{
"destinations" => match value
{
&ConfigurationValue::Array(ref a) => destinations=Some(a.iter().map(|v|match v{
&ConfigurationValue::Number(f) => f as usize,
_ => panic!("bad value in destinations"),
}).collect()),
_ => panic!("bad value for destinations"),
}
"extra_random_destinations" => match value
{
&ConfigurationValue::Number(f) => extra_random_destinations=Some(f as usize),
_ => panic!("bad value for extra_random_destinations ({:?})",value),
}
"legend_name" => (),
_ => panic!("Nothing to do with field {} in Hotspots",name),
}
}
}
else
{
panic!("Trying to create a Hotspots from a non-Object");
}
let destinations=destinations.unwrap_or_else(Vec::new);
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:&Box<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.len()==0
{
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:&Box<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;
if let &ConfigurationValue::Object(ref cv_name, ref cv_pairs)=arg.cv
{
if cv_name!="RandomMix"
{
panic!("A RandomMix must be created from a `RandomMix` object not `{}`",cv_name);
}
for &(ref name,ref value) in cv_pairs
{
match AsRef::<str>::as_ref(&name)
{
"patterns" => match value
{
&ConfigurationValue::Array(ref a) => patterns=Some(a.iter().map(|pcv|new_pattern(PatternBuilderArgument{cv:pcv,..arg})).collect()),
_ => panic!("bad value for patterns"),
}
"weights" => match value
{
&ConfigurationValue::Array(ref a) => weights=Some(a.iter().map(|v|match v{
&ConfigurationValue::Number(f) => f as usize,
_ => panic!("bad value in weights"),
}).collect()),
_ => panic!("bad value for weights"),
}
"legend_name" => (),
_ => panic!("Nothing to do with field {} in RandomMix",name),
}
}
}
else
{
panic!("Trying to create a RandomMix from a non-Object");
}
let patterns=patterns.expect("There were no patterns");
let weights=weights.expect("There were no weights");
RandomMix{
patterns,
weights,
total_weight:0, }
}
}