use std::collections::BTreeSet;
use std::fs::File;
use std::io::{BufRead,BufReader};
use ::rand::{Rng,rngs::StdRng};
use quantifiable_derive::Quantifiable;use super::{Topology,Location};
use super::cartesian::CartesianData;
use crate::config_parser::ConfigurationValue;
use crate::matrix::Matrix;
#[derive(Quantifiable)]
#[derive(Debug)]
pub struct NeighboursLists
{
list: Vec<Vec<(usize,usize)>>,
servers: Vec<usize>,
server_offsets: Vec<usize>,
routers_by_server: Vec<(usize,usize)>,
distance_matrix:Matrix<usize>,
amount_matrix:Matrix<usize>,
average_amount: f32,
}
impl Topology for NeighboursLists
{
fn num_routers(&self) -> usize
{
self.list.len()
}
fn num_servers(&self) -> usize
{
self.routers_by_server.len()
}
fn neighbour(&self, router_index:usize, port: usize) -> (Location,usize)
{
let degree=self.list[router_index].len();
if port<degree
{
let (r,p) = self.list[router_index][port];
return (Location::RouterPort{router_index:r,router_port:p},0);
}
(Location::ServerPort(self.server_offsets[router_index]+port-degree),1)
}
fn server_neighbour(&self, server_index:usize) -> (Location,usize)
{
let (r,p) = self.routers_by_server[server_index];
(Location::RouterPort{router_index:r,router_port:p},1)
}
fn diameter(&self) -> usize
{
let mut maximum=0;
let n=self.num_routers();
for source in 0..n
{
for target in 0..n
{
let d=self.distance(source,target);
if d>maximum
{
maximum=d;
}
}
}
maximum
}
fn distance(&self,origin:usize,destination:usize) -> usize
{
*self.distance_matrix.get(origin,destination)
}
fn amount_shortest_paths(&self,origin:usize,destination:usize) -> usize
{
*self.amount_matrix.get(origin,destination)
}
fn average_amount_shortest_paths(&self) -> f32
{
self.average_amount
}
fn maximum_degree(&self) -> usize
{
self.list.iter().map(|adj|adj.len()).max().expect("calling maximum_degree without routers")
}
fn minimum_degree(&self) -> usize
{
self.list.iter().map(|adj|adj.len()).min().expect("calling minimum_degree without routers")
}
fn degree(&self, router_index: usize) -> usize
{
self.list[router_index].len()
}
fn ports(&self, router_index: usize) -> usize
{
self.list[router_index].len() + self.servers[router_index]
}
fn cartesian_data(&self) -> Option<&CartesianData>
{
None
}
fn coordinated_routing_record(&self, _coordinates_a:&[usize], _coordinates_b:&[usize], _rng: Option<&mut 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 NeighboursLists
{
pub fn new(list:Vec<Vec<(usize,usize)>>,servers:Vec<usize>) -> NeighboursLists
{
let mut server_offsets=Vec::with_capacity(servers.len());
let mut offset=0;
for &size in servers.iter()
{
server_offsets.push(offset);
offset+=size;
}
let mut routers_by_server=Vec::with_capacity(offset);
for (router_index,&size) in servers.iter().enumerate()
{
let degree=list[router_index].len();
for i in 0..size
{
routers_by_server.push((router_index,degree+i));
}
}
let mut topo=NeighboursLists{
list,
servers,
server_offsets,
routers_by_server,
distance_matrix:Matrix::constant(0,0,0),
amount_matrix:Matrix::constant(0,0,0),
average_amount: 0f32,
};
let (distance_matrix,amount_matrix)=topo.compute_amount_shortest_paths();
topo.distance_matrix=distance_matrix;
topo.amount_matrix=amount_matrix;
topo.average_amount={
let n=topo.num_routers();
let mut r=0;
let mut count=0;
for i in 0..n
{
for j in 0..n
{
if i!=j
{
r+=topo.amount_shortest_paths(i,j);
count+=1;
}
}
}
r as f32/count as f32
};
topo
}
pub fn new_rrg_adj(routers:usize, degree:usize, rng: &mut StdRng) -> Vec<Vec<usize>>
{
let mut adj=vec![Vec::with_capacity(degree);routers];
let mut go=true;
while go
{
go=false;
#[allow(non_snake_case)]
let mut Un=routers*degree;
#[allow(non_snake_case)]
let mut U=(0..routers*degree).collect::<Vec<usize>>();
for adjs in adj.iter_mut()
{
adjs.clear();
}
#[allow(non_snake_case)]
let mut A=(0..routers).collect::<BTreeSet<usize>>();
while Un>0
{
if A.len()<degree
{
let mut good=false;
for &i in A.iter()
{
for &j in A.iter()
{
if j<=i
{
continue;
}
let mut inadj=false;
for &neigh in adj[j].iter()
{
if neigh==i
{
inadj=true;
break;
}
}
if !inadj
{
good=true;
}
}
}
if !good
{
go=true;
break;
}
}
let r=rng.gen_range(0..Un); let x=U[r];
U[r]=U[Un-1];
U[Un-1]=x;
let r=rng.gen_range(0..Un-1);
let y=U[r];
U[r]=U[Un-2];
U[Un-2]=y;
let u=x/degree;
let v=y/degree;
if u==v
{
continue; }
let mut inadj=false;
for &neigh in adj[u].iter()
{
if neigh==v
{
inadj=true;
break;
}
}
if inadj
{
continue; }
Un-=2;
adj[u].push(v);
if adj[u].len()==degree
{
A.remove(&u);
}
adj[v].push(u);
if adj[v].len()==degree
{
A.remove(&v);
}
}
}
adj
}
pub fn file_adj(file:&File, _format:usize) -> Vec<Vec<usize>>
{
let mut adj : Vec<Vec<usize>> =vec![];
let mut nodos=None;
let reader = BufReader::new(file);
let mut lines=reader.lines();
while let Some(rline)=lines.next()
{
let line=rline.expect("Some problem when reading the topology.");
let mut words=line.split_whitespace();
match words.next()
{
Some("NODOS") =>
{
nodos=Some(words.next().unwrap().parse::<usize>().unwrap());
},
Some("GRADO") =>
{
let grado=Some(words.next().unwrap().parse::<usize>().unwrap());
if let Some(routers)=nodos
{
if let Some(degree)=grado
{
adj=vec![Vec::with_capacity(degree);routers];
}
}
},
Some("N") =>
{
let current=words.next().unwrap().parse::<usize>().unwrap();
for wneighbour in lines.next().unwrap().unwrap().split_whitespace()
{
let neighbour=wneighbour.parse::<usize>().unwrap();
adj[current].push(neighbour);
}
},
_ => panic!("Illegal word"),
};
}
adj
}
pub fn new_cfg(cv:&ConfigurationValue, rng: &mut StdRng) -> NeighboursLists
{
let mut routers=None;
let mut degree=None;
let mut servers_per_router=None;
let mut filename=None;
let mut format=None;
enum Kind { RandomRegularGraph, File }
let kind;
if let &ConfigurationValue::Object(ref cv_name, ref cv_pairs)=cv
{
kind=match cv_name.as_ref()
{
"RandomRegularGraph" => Kind::RandomRegularGraph,
"File" => Kind::File,
_ => panic!("Unknown topology {}",cv_name),
};
for &(ref name,ref value) in cv_pairs
{
match name.as_ref()
{
"routers" => match value
{
&ConfigurationValue::Number(f) => routers=Some(f as usize),
_ => panic!("bad value for routers"),
},
"degree" => match value
{
&ConfigurationValue::Number(f) => degree=Some(f as usize),
_ => panic!("bad value for degree"),
},
"servers_per_router" => match value
{
&ConfigurationValue::Number(f) => servers_per_router=Some(f as usize),
_ => panic!("bad value for servers_per_router"),
},
"filename" => match value
{
&ConfigurationValue::Literal(ref s) => filename=Some(s.to_string()),
_ => panic!("bad value for filename"),
},
"format" => match value
{
&ConfigurationValue::Number(f) => format=Some(f as usize),
_ => panic!("bad value for format"),
},
"legend_name" => (),
_ => panic!("Nothing to do with field {} in RandomRegularGraph",name),
}
}
}
else
{
panic!("Trying to create a NeighboursLists from a non-Object");
}
let servers_per_router=servers_per_router.expect("There were no servers_per_router");
let adj = match kind
{
Kind::RandomRegularGraph =>
{
let routers=routers.expect("There were no routers");
let degree=degree.expect("There were no degree");
Self::new_rrg_adj(routers,degree,rng)
},
Kind::File =>
{
let filename=filename.expect("There were no filename");
let format=format.expect("There were no format");
let file=File::open(&filename).expect("could not open topology file.");
Self::file_adj(&file,format)
},
};
let list=adj.iter().enumerate().map(|(current,neighbours)|
neighbours.iter().map(|&neigh|(neigh,
{
let mut index=0;
for (i,&v) in adj[neigh].iter().enumerate()
{
if v==current
{
index=i;
break;
}
}
index
})).collect()
).collect();
let servers=vec![servers_per_router;adj.len()];
NeighboursLists::new(list,servers)
}
}