0

I have been using Petgraph recently to make simple graphs with Structs for nodes and custom edges, but I have come across a problem which I am unsure if it comes from the library or Rust.

I have a graph, in which I have multiple nodes, each nodes have a name. I then put all of the index of the node (with type NodeIndex) in a vector, since Petgraph doesn't have a function to give all the nodes from a graph. I want to then create a function that given a string, it returns the index of the node that matches the name.

My problem is that somehow the type in the vector containing the nodes seems to change. I store it as NodeIndex yet the types somehow change by themselves to u32 without me changing anything. Since it changes automatically, I can't pass the values inside Petgraph functions since they require NodeIndex as inputs and not u32.

The code following is what I have so far and the problem arises in the function find_node_index_with_name where the types seem to change even though I pass a vector of NodeIndex as input so when I iterate over it, I should also get NodeIndex back.

use petgraph::adj::NodeIndex;
use petgraph::stable_graph::StableGraph;
use petgraph::dot::Dot;

#[derive(Clone,Debug,Default)]
struct ControlBloc
{
    name:String,
    value:u32,
}

fn create_bloc(name:String,value:u32) -> ControlBloc
{
    ControlBloc
    {
        name,
        value,
    }
}

fn find_node_index_with_name(gr:StableGraph<ControlBloc,u32> , nodes:Vec<NodeIndex> , name_search:String) -> Option<NodeIndex>
{
    for i in 0..nodes.len()
    {
        if gr.node_weight(nodes[i]).unwrap().name == name_search
        {
            return nodes[i];
        }
    }
    return None;
}

fn main() {
    let mut graph = StableGraph::<ControlBloc,u32>::new();
    let m = create_bloc(String::from("Main"),10);
    let b1 = create_bloc(String::from("sub1"),20);
    let b2 = create_bloc(String::from("sub2"),30);
    let main = graph.add_node(m);
    let sub1 = graph.add_node(b1);
    let sub2 = graph.add_node(b2);

    let all_nodes = vec![main,sub1,sub2];

    println!("{:?}",find_node_index_with_name(graph, all_nodes, String::from("Main")));
}

I am a bit stumped as to why the types change.

Thank you for any inputs!

GuiGui
  • 83
  • 8
  • Please post the full error message from `cargo check`. That being said, you should return `Some (nodes[i])`, no plain `nodes[i]` since your function returns an `Option`. – Jmb Jul 18 '22 at 13:46

1 Answers1

1

graph.add_node() returns a petgraph::graph::NodeIndex. But you used petgraph::adj::NodeIndex which appears to be a different type (don't ask me why), thus the type mismatch.

I took the liberty to change a bit your code in order to use references where you used owned values.

use petgraph::graph::NodeIndex; // graph not adj
use petgraph::stable_graph::StableGraph;

#[derive(Clone, Debug, Default)]
struct ControlBloc {
    name: String,
    value: u32,
}

fn create_bloc(
    name: String,
    value: u32,
) -> ControlBloc {
    ControlBloc { name, value }
}

fn find_node_index_with_name(
    gr: &StableGraph<ControlBloc, u32>,
    nodes: &[NodeIndex],
    name_search: &str,
) -> Option<NodeIndex> {
    nodes
        .iter()
        .map(|n| *n)
        .find(|n| gr.node_weight(*n).unwrap().name == name_search)
    /*
    for i in 0..nodes.len() {
        if gr.node_weight(nodes[i]).unwrap().name == name_search {
            return Some(nodes[i]);
        }
    }
    None
    */
}

fn main() {
    let mut graph = StableGraph::<ControlBloc, u32>::new();
    let m = create_bloc(String::from("Main"), 10);
    let b1 = create_bloc(String::from("sub1"), 20);
    let b2 = create_bloc(String::from("sub2"), 30);
    let main = graph.add_node(m);
    let sub1 = graph.add_node(b1);
    let sub2 = graph.add_node(b2);

    let all_nodes = vec![main, sub1, sub2];

    for n in ["Main", "sub1", "sub2"] {
        println!("{:?}", find_node_index_with_name(&graph, &all_nodes, n));
    }
}
/*
Some(NodeIndex(0))
Some(NodeIndex(1))
Some(NodeIndex(2))
*/
prog-fh
  • 13,492
  • 1
  • 15
  • 30
  • Thank you so much it indeed helped a lot! Could I just ask why it is better to use references instead of owned values? I'm still struggling to understand when to use which in functions. – GuiGui Jul 18 '22 at 14:03
  • 1
    @Guillaume If your function uses owned values as parameters, this means that at the call site these values will be moved into the function, so will not be accessible anymore at the call site. Of course, you could clone them (if the types allow that) but it will cost some resources. On the other hand, taking references enables working with the original values, without duplicating them and this lets these values usable at the call site afterwards. For example, in your code you could call your function only once, in my version it was called three times. – prog-fh Jul 18 '22 at 14:19
  • 1
    Thank you very much for your answer, indeed I only recently started to post on stackoverflow, I just noticed the button and will definitely accept from now on :) – GuiGui Jul 18 '22 at 14:42