use std::cell::RefCell;
use ::rand::{StdRng};
use super::{Topology,Location};
use super::cartesian::CartesianData;
use quantifiable_derive::Quantifiable;use crate::config_parser::ConfigurationValue;
use crate::matrix::Matrix;
#[derive(Quantifiable)]
#[derive(Debug)]
pub struct CanonicDragonfly
{
global_ports_per_router: usize,
servers_per_router: usize,
group_size: usize,
number_of_groups: usize,
distance_matrix:Matrix<usize>,
}
impl Topology for CanonicDragonfly
{
fn num_routers(&self) -> usize
{
self.group_size * self.number_of_groups
}
fn num_servers(&self) -> usize
{
self.group_size * self.number_of_groups * self.servers_per_router
}
fn neighbour(&self, router_index:usize, port: usize) -> (Location,usize)
{
let (router_local,router_global)=self.unpack(router_index);
let degree=self.group_size-1+self.global_ports_per_router;
if port<self.group_size-1
{
let target_local = (router_local+1+port)%self.group_size;
let target_port = self.group_size - 2 - port;
(Location::RouterPort{router_index:self.pack((target_local,router_global)),router_port:target_port},0)
}
else if port<degree
{
let port_offset=port+1-self.group_size;
let target_global=(router_global+self.number_of_groups-(router_local*self.global_ports_per_router+port_offset+1)) % self.number_of_groups;
let target_local=( ((self.number_of_groups+target_global-router_global)%self.number_of_groups)-1 )/self.global_ports_per_router;
let target_port=self.group_size-1 + self.global_ports_per_router-1-port_offset;
(Location::RouterPort{router_index:self.pack((target_local,target_global)),router_port:target_port},1)
}
else
{
(Location::ServerPort(router_index*self.servers_per_router + port-degree),2)
}
}
fn server_neighbour(&self, server_index:usize) -> (Location,usize)
{
let r=self.group_size-1 + self.global_ports_per_router;
(Location::RouterPort{
router_index: server_index/self.servers_per_router,
router_port: r+server_index%self.servers_per_router,
},2)
}
fn diameter(&self) -> usize
{
3
}
fn distance(&self,origin:usize,destination:usize) -> usize
{
*self.distance_matrix.get(origin,destination)
}
fn amount_shortest_paths(&self,_origin:usize,_destination:usize) -> usize
{
unimplemented!();
}
fn average_amount_shortest_paths(&self) -> f32
{
unimplemented!();
}
fn maximum_degree(&self) -> usize
{
self.group_size-1 + self.global_ports_per_router
}
fn minimum_degree(&self) -> usize
{
self.group_size-1 + self.global_ports_per_router
}
fn degree(&self, _router_index: usize) -> usize
{
self.group_size-1 + self.global_ports_per_router
}
fn ports(&self, _router_index: usize) -> usize
{
self.group_size-1 + self.global_ports_per_router + self.servers_per_router
}
fn cartesian_data(&self) -> Option<&CartesianData>
{
None
}
fn coordinated_routing_record(&self, _coordinates_a:&Vec<usize>, _coordinates_b:&Vec<usize>, _rng: Option<&RefCell<StdRng>>)->Vec<i32>
{
unimplemented!();
}
fn is_direction_change(&self, _router_index:usize, _input_port: usize, _output_port: usize) -> bool
{
true
}
fn up_down_distance(&self,_origin:usize,_destination:usize) -> Option<(usize,usize)>
{
None
}
}
impl CanonicDragonfly
{
pub fn new(cv:&ConfigurationValue) -> CanonicDragonfly
{
let mut global_ports_per_router=None;
let mut servers_per_router=None;
if let &ConfigurationValue::Object(ref cv_name, ref cv_pairs)=cv
{
if cv_name!="CanonicDragonfly"
{
panic!("A CanonicDragonfly must be created from a `CanonicDragonfly` object not `{}`",cv_name);
}
for &(ref name,ref value) in cv_pairs
{
match name.as_ref()
{
"global_ports_per_router" => match value
{
&ConfigurationValue::Number(f) => global_ports_per_router=Some(f as usize),
_ => panic!("bad value for global_ports_per_router"),
}
"servers_per_router" => match value
{
&ConfigurationValue::Number(f) => servers_per_router=Some(f as usize),
_ => panic!("bad value for servers_per_router"),
}
_ => panic!("Nothing to do with field {} in CanonicDragonfly",name),
}
}
}
else
{
panic!("Trying to create a CanonicDragonfly from a non-Object");
}
let global_ports_per_router=global_ports_per_router.expect("There were no global_ports_per_router");
let servers_per_router=servers_per_router.expect("There were no servers_per_router");
let group_size = 2*global_ports_per_router;
let number_of_groups = group_size*global_ports_per_router + 1;
let mut topo=CanonicDragonfly{
global_ports_per_router,
servers_per_router,
group_size,
number_of_groups,
distance_matrix:Matrix::constant(0,0,0),
};
let (distance_matrix,_amount_matrix)=topo.compute_amount_shortest_paths();
topo.distance_matrix=distance_matrix;
topo
}
fn unpack(&self, router_index: usize) -> (usize,usize)
{
(router_index%self.group_size,router_index/self.group_size)
}
fn pack(&self, coordinates:(usize,usize)) -> usize
{
coordinates.0+coordinates.1*self.group_size
}
}