Compare commits

..

No commits in common. "c9a5b0c526c6640f4a7af91c02c71644c234ba0d" and "b078e13cb6c6deb8ca31540b2fba2f64b7eb3e2e" have entirely different histories.

2 changed files with 31 additions and 70 deletions

View File

@ -1,36 +0,0 @@
//
// Copyright 2023 James Pace
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
//
// This Source Code Form is "Incompatible With Secondary Licenses", as
// defined by the Mozilla Public License, v. 2.0.
//
use alloc::string::{String, ToString};
#[derive(Debug, Clone)]
pub enum Error {
Msg(String),
}
impl Error {
pub fn from_msg(msg: &str) -> Self {
Error::Msg(msg.to_string())
}
}
impl core::fmt::Display for Error {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
match self {
Error::Msg(msg) => {
write!(f, "Error manipulating graph: {}", msg)
}
}
}
}
impl core::error::Error for Error {}
pub type Result<T, E = Error> = core::result::Result<T, E>;

View File

@ -10,13 +10,11 @@
// //
#![no_std] #![no_std]
extern crate alloc; extern crate alloc;
mod error;
mod node; mod node;
use alloc::collections::vec_deque::VecDeque; use alloc::string::{String, ToString};
use alloc::vec; use alloc::vec;
use alloc::vec::Vec; use alloc::vec::Vec;
pub use error::*;
pub use node::*; pub use node::*;
/// A generic graph type holding values connected to other values. /// A generic graph type holding values connected to other values.
@ -39,10 +37,10 @@ impl<NodeValueT: NodeValue> Graph<NodeValueT> {
/// Add a child wth value `val` to the parent with Key `parent`. /// Add a child wth value `val` to the parent with Key `parent`.
/// If the parent key is not in the graph, returns an error. /// If the parent key is not in the graph, returns an error.
/// Returns a result with the key of the new node or an error. /// Returns a result with the key of the new node or an error.
pub fn add(&mut self, val: NodeValueT, parent: Key) -> Result<Key> { pub fn add(&mut self, val: NodeValueT, parent: Key) -> Result<Key, GraphError> {
// Make sure parent is valid. // Make sure parent is valid.
if parent >= self.nodes.len() { if parent >= self.nodes.len() {
return Err(Error::from_msg("Parent node not in graph.")); return Err(GraphError::from_msg("Parent node not in graph."));
} }
// Add new node to graph, get it's key. // Add new node to graph, get it's key.
let new_node = Node::new(val, Some(parent)); let new_node = Node::new(val, Some(parent));
@ -55,35 +53,35 @@ impl<NodeValueT: NodeValue> Graph<NodeValueT> {
/// Replace the value of `key` with value `value`. /// Replace the value of `key` with value `value`.
/// `key` must already exist in the graph, and no connections will be modified. /// `key` must already exist in the graph, and no connections will be modified.
pub fn replace_value_of(&mut self, key: &Key, value: NodeValueT) -> Result<()> { pub fn replace_value_of(&mut self, key: &Key, value: NodeValueT) -> Result<(), GraphError> {
if let Some(node) = self.nodes.get_mut(*key) { if let Some(node) = self.nodes.get_mut(*key) {
node.set_value(value); node.set_value(value);
return Ok(()); return Ok(());
} }
Err(Error::from_msg("Can't set value of invalid key.")) return Err(GraphError::from_msg("Can't set value of invalid key."));
} }
/// Get the value of key `key` if the key is valid. /// Get the value of key `key` if the key is valid.
pub fn value_of(&self, key: &Key) -> Result<NodeValueT> { pub fn value_of(&self, key: &Key) -> Result<NodeValueT, GraphError> {
if key >= &self.nodes.len() { if key >= &self.nodes.len() {
return Err(Error::from_msg("Can't get value of invalid key.")); return Err(GraphError::from_msg("Can't get value of invalid key."));
} }
Ok(self.nodes[*key].value()) Ok(self.nodes[*key].value())
} }
/// Get the children (as a list of keys) of key `key` if the key is valid. /// Get the children (as a list of keys) of key `key` if the key is valid.
pub fn children_of(&self, key: &Key) -> Result<Vec<Key>> { pub fn children_of(&self, key: &Key) -> Result<Vec<Key>, GraphError> {
if key >= &self.nodes.len() { if key >= &self.nodes.len() {
return Err(Error::from_msg("Can't get children of invalid key.")); return Err(GraphError::from_msg("Can't get children of invalid key."));
} }
Ok(self.nodes[*key].children()) Ok(self.nodes[*key].children())
} }
/// Get the parent of key `key` if the key is valid. /// Get the parent of key `key` if the key is valid.
/// Will return None if the node at `key` as no parent (i.e. is the root node). /// Will return None if the node at `key` as no parent (i.e. is the root node).
pub fn parent_of(&self, key: &Key) -> Result<Option<Key>> { pub fn parent_of(&self, key: &Key) -> Result<Option<Key>, GraphError> {
if key >= &self.nodes.len() { if key >= &self.nodes.len() {
return Err(Error::from_msg("Can't get parent of invalid key.")); return Err(GraphError::from_msg("Can't get parent of invalid key."));
} }
Ok(self.nodes[*key].parent()) Ok(self.nodes[*key].parent())
} }
@ -96,7 +94,7 @@ impl<NodeValueT: NodeValue> Graph<NodeValueT> {
/// Find all nodes that are leaf nodes. /// Find all nodes that are leaf nodes.
/// A leaf node is one that doesn't have any children. /// A leaf node is one that doesn't have any children.
pub fn find_leaf_keys(&self) -> Result<Vec<Key>> { pub fn find_leaf_keys(&self) -> Result<Vec<Key>, GraphError> {
let mut leaf_keys = Vec::<Key>::new(); let mut leaf_keys = Vec::<Key>::new();
for key in 0..self.nodes.len() { for key in 0..self.nodes.len() {
@ -106,12 +104,12 @@ impl<NodeValueT: NodeValue> Graph<NodeValueT> {
} }
} }
Ok(leaf_keys) return Ok(leaf_keys);
} }
/// Return all keys ordered like you were doing /// Return all keys ordered like you were doing
/// a depth first search. /// a depth first search.
pub fn get_keys_by_depth(&self) -> Result<Vec<Key>> { pub fn get_keys_by_depth(&self) -> Result<Vec<Key>, GraphError> {
let mut visited_keys = Vec::<Key>::new(); let mut visited_keys = Vec::<Key>::new();
let mut stack = Vec::<Key>::new(); let mut stack = Vec::<Key>::new();
@ -128,23 +126,28 @@ impl<NodeValueT: NodeValue> Graph<NodeValueT> {
Ok(visited_keys) Ok(visited_keys)
} }
/// Given a key, return the vec of keys connecting that key to the root.
/// Order is root->key inclusive.
pub fn backtrack_from_key(&self, key: &Key) -> Result<Vec<Key>> {
let mut curr_key = key.clone();
let mut deque = VecDeque::<Key>::new();
deque.push_front(curr_key.clone());
while curr_key != self.root_key() {
let new_parent = self.parent_of(&curr_key)?.unwrap();
deque.push_front(new_parent.clone());
curr_key = new_parent;
} }
Ok(Vec::from(deque)) #[derive(Debug, Clone)]
pub struct GraphError {
pub msg: String,
}
impl GraphError {
pub fn from_msg(msg: &str) -> Self {
GraphError {
msg: msg.to_string(),
} }
} }
}
impl core::fmt::Display for GraphError {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "Error manipulating graph: {}", self.msg)
}
}
impl core::error::Error for GraphError {}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
@ -190,7 +193,6 @@ mod tests {
#[test] #[test]
fn graph_search() { fn graph_search() {
// Build the graph.
let root_val = NodeType::new(1.0); let root_val = NodeType::new(1.0);
let mut graph = Graph::new(root_val); let mut graph = Graph::new(root_val);
@ -210,16 +212,11 @@ mod tests {
let fifth_add_res = graph.add(fifth_val, 2); let fifth_add_res = graph.add(fifth_val, 2);
assert!(fifth_add_res.is_ok()); assert!(fifth_add_res.is_ok());
// Do the testing.
let leaf_keys = graph.find_leaf_keys().unwrap(); let leaf_keys = graph.find_leaf_keys().unwrap();
assert!(leaf_keys.len() == 2); assert!(leaf_keys.len() == 2);
let keys_by_depth = graph.get_keys_by_depth().unwrap(); let keys_by_depth = graph.get_keys_by_depth().unwrap();
let expected_keys_by_depth = vec![0, 2, 4, 1, 3]; let expected_keys_by_depth = vec![0, 2, 4, 1, 3];
assert!(keys_by_depth == expected_keys_by_depth); assert!(keys_by_depth == expected_keys_by_depth);
let backtracked_keys = graph.backtrack_from_key(&4).unwrap();
let expected_backtracked_keys = vec![0, 2, 4];
assert!(backtracked_keys == expected_backtracked_keys);
} }
} }