[][src]Type Definition net_ensembles::graph::Graph

type Graph<T> = GenericGraph<T, NodeContainer<T>>;

Contains the topology and implements functions for analyzing topology

used for graph ensembles

Example:

A graph, where each node stores a phase

use net_ensembles::{traits::*,Graph};
use std::fs::File;
use std::io::prelude::*;
// define your own vertices, if you need to store extra information at each vertex
#[derive(Debug, Clone)]
pub struct PhaseNode {phase: f64,}

// implement whatever you need
impl PhaseNode {
    pub fn set_phase(&mut self, phase: f64) {
        self.phase = phase;
    }

    pub fn get_phase(&self) -> f64 {
        self.phase
    }
}

// implement the trait `Node`
impl Node for PhaseNode {
    fn new_from_index(index: u32) -> Self {
        PhaseNode { phase: index as f64 * 10.0}
    }

    // if you do not wish to print/load etc. you can do the following.
    // I do not recommend this though
    fn make_string(&self) -> Option<String> { unimplemented!() }

    fn parse_str(_: &str) -> Option<(&str, Self)> { unimplemented!() }
}

// now you can create an empty graph
let mut graph: Graph<PhaseNode> = Graph::new(4);
for i in 0..4 {
    assert_eq!(
      graph.at(i).get_phase(),
      i as f64 * 10.0
    );
}

// and fill it with edges
for i in 0..4 {
    graph.add_edge(i, (i + 1) % 4).unwrap();
}


// you can manipulate the extra information stored at each Vertex
for i in 0..4 {
    graph.at_mut(i).set_phase(i as f64 * 0.5);
}

// you can, of course, also access the information
for i in 0..4 {
    assert_eq!(
        graph.at(i).get_phase(),
        i as f64 * 0.5
    );
}

// if you want to visualize your graph, you can generate a string with graphviz representation
let dot = graph.to_dot_with_labels_from_contained(
    "",
    |contained, index|
           format!(
                "Phase: {} at index {}",
                contained.get_phase(),
                index
            )
);
// which you can store in a dot file
let mut f = File::create("phase_example.dot").expect("Unable to create file");
f.write_all(dot.as_bytes()).expect("Unable to write data");

// or just print it out
println!("{}", dot);

phase_example.dot will then contain

graph G{

	0 1 2 3 ;
	"0" [label="Phase: 0 at index 0"];
	"1" [label="Phase: 0.5 at index 1"];
	"2" [label="Phase: 1 at index 2"];
	"3" [label="Phase: 1.5 at index 3"];
	0 -- 1
	0 -- 3
	1 -- 2
	2 -- 3
}

Now you can use circo or similar programs to create a pdf from that. Search for graphviz for more info.

Example 2

  • if you also want to be able to store your graph, you have to override two functions of the Node trait, as shown below
use net_ensembles::{Node,Graph,traits::*};
use std::fs::File;
use std::io::prelude::*;
// define your own vertices, if you need to store extra information at each vertex
#[derive(Debug, Clone)]
pub struct PhaseNode {phase: f64,}

impl PhaseNode {
    pub fn set_phase(&mut self, phase: f64) {
        self.phase = phase;
    }

    pub fn get_phase(&self) -> f64 {
        self.phase
    }
}

impl Node for PhaseNode {
    fn new_from_index(index: u32) -> Self {
        PhaseNode { phase: 10.0 * index as f64 }
    }

    // Override this, to save the graph
    fn make_string(&self) -> Option<String> {
        Some(format!("phase: {},", self.phase))
    }

    // Override this, since you want to load the stored graph
    fn parse_str(to_parse: &str) -> Option<(&str, Self)>
        where Self: Sized
    {
        let identifier = "phase: ";
        // searching for identifier
        let mut split_index = to_parse.find(identifier)?;

        // add length of identifier to index
        split_index += identifier.len();

        // new string slice to skip to our identifier
        let remaining_to_parse = &to_parse[split_index..];

        // find out, where our data ends
        split_index = remaining_to_parse.find(",")?;

        // create new string slice, beginning after what Node::make_string() created
        let (phase_str, mut remaining_to_parse) = remaining_to_parse.split_at(split_index);
        remaining_to_parse = &remaining_to_parse[1..];

        // parse our data
        let phase = phase_str.parse::<f64>().ok()?;
        let node = PhaseNode{ phase };

        // return our struct as option
        Some((remaining_to_parse, node))
    }
}

// now you can create an empty graph
let mut graph: Graph<PhaseNode> = Graph::new(4);
for i in 0..4 {
    assert_eq!(
      graph.at(i).get_phase(),
      i as f64 * 10.0
    );
}

// and fill it with edges
for i in 0..4 {
    graph.add_edge(i, (i + 1) % 4).unwrap();
}


// you can manipulate the extra information stored at each Vertex
for i in 0..4 {
    graph.at_mut(i).set_phase(i as f64 * 0.5);
}

// you can, of course, also access the information
for i in 0..4 {
    assert_eq!(
        graph.at(i).get_phase(),
        i as f64 * 0.5
    );
}

// if you want to visualize your graph, you can generate a string with graphviz representation
let dot = graph.to_dot_with_labels_from_contained(
    "",
    |contained, index|
           format!(
                "Phase: {} at index {}",
                contained.get_phase(),
                index
            )
);
// which you can store in a dot file
let mut f = File::create("phase_example_still_works.dot").expect("Unable to create file");
f.write_all(dot.as_bytes()).expect("Unable to write data");

// or just print it out
println!("{}", dot);

// if you want to store your graph, you can do the following:
// first get string representation
let s = graph.to_string();
// open file
let mut graph_file = File::create("store_graph_example.dat").expect("Unable to create file");
// write to file
graph_file.write_all(s.as_bytes()).expect("Unable to write data");
// close file
drop(graph_file);

// now, if you want to load your network:
let mut read_in = File::open("store_graph_example.dat").expect("unable to open file");
let mut test_data = String::new();
read_in.read_to_string(&mut test_data).expect("unable to read file");

// now we read the string. We still have to parse it:
let (_, graph2) = Graph::<PhaseNode>::parse_str(&test_data).unwrap();

// now, to show, that the graphs are equal, here is one of my test functions:
// modified for this example, which is a doc-test, so this example also serves as unit test

fn assert_equal_graphs(g1: &Graph<PhaseNode>, g2: &Graph<PhaseNode>) {
    assert_eq!(g1.edge_count(), g2.edge_count());
    assert_eq!(g1.vertex_count(), g2.vertex_count());
    for (n0, n1) in g2.container_iter().zip(g1.container_iter()) {
        assert_eq!(n1.id(), n0.id());
        assert_eq!(n0.degree(), n1.degree());

        for (i, j) in n1.neighbors().zip(n0.neighbors()) {
            assert_eq!(i, j);
        }
    }

    for i in 0..g2.vertex_count() as usize {
        assert_eq!(
            g1.at(i).get_phase(),
            g2.at(i).get_phase()
        );
    }
}
// lets use it
assert_equal_graphs(&graph, &graph2);

// you can also clone the graph, if you need:
let clone = graph.clone();
assert_equal_graphs(&graph, &clone);
let clone2 = graph2.clone();
assert_equal_graphs(&clone, &clone2);