1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
//! Defines the interface and implementations for working with regular directed graphs with

//! labeled edges.

//!

//! # Examples

//! We need to choose which graph implementation to ground our knowledge and reasoning on. All

//! implementations should be logically equivalent. Let's use the in-memory one for simplicity:

//!

//! ```rust

//! use zamm_yin::graph::bind_in_memory_graph;

//!

//! bind_in_memory_graph();

//! ```

//!

//! No matter which implementation you choose, `InjectionGraph` allows you to use that

//! implementation via dependency injection:

//!

//! ```rust

//! # use zamm_yin::graph::bind_in_memory_graph;

//! # bind_in_memory_graph();

//! use zamm_yin::graph::InjectionGraph;

//!

//! let mut g = InjectionGraph::new();

//! ```

//!

//! Now we can create a new node:

//! ```rust

//! # use zamm_yin::graph::{bind_in_memory_graph, InjectionGraph};

//! # bind_in_memory_graph();

//! # let mut g = InjectionGraph::new();

//! use zamm_yin::graph::Graph;

//!

//! let a_id = g.add_node();

//! ```

//!

//! We can set a name for the node. Note that names don't need to be unique.

//!

//! ```rust

//! # use zamm_yin::graph::{bind_in_memory_graph, InjectionGraph, Graph};

//! # bind_in_memory_graph();

//! # let mut g = InjectionGraph::new();

//! # let a_id = g.add_node();

//! use std::rc::Rc;

//!

//! g.set_node_name(a_id, "A".to_string());

//! assert_eq!(g.node_name(a_id), Some(Rc::new("A".to_string())));

//! ```

//!

//! We can also set a value for the node. We use `Rc` here because Yin being the map and not the

//! territory, we generally don't want to have Yin itself own the data being operated on.

//!

//! ```rust

//! # use zamm_yin::graph::{bind_in_memory_graph, InjectionGraph, Graph};

//! # bind_in_memory_graph();

//! # let mut g = InjectionGraph::new();

//! # let a_id = g.add_node();

//! use zamm_yin::graph::value_wrappers::{unwrap_weak, WeakValue};

//! use std::rc::Rc;

//!

//! let v = Rc::new(5);

//! g.set_node_value(a_id, Box::new(WeakValue::new(&v)));

//! assert_eq!(unwrap_weak::<i32>(g.node_value(a_id)), Some(v));

//! ```

//!

//! Let's create a few more nodes:

//! ```rust

//! # use zamm_yin::graph::{bind_in_memory_graph, InjectionGraph, Graph};

//! # bind_in_memory_graph();

//! # let mut g = InjectionGraph::new();

//! # let a_id = g.add_node();

//! let b_id = g.add_node();

//! let c_id = g.add_node();

//! let d_id = g.add_node();

//! let edge_type1 = g.add_node();

//! let edge_type2 = g.add_node();

//! ```

//!

//! Let's now connect some of these nodes together. Note that while edge labels can technically be

//! any integer, they are assumed to be node IDs by higher-level Yin abstractions:

//!

//! ```rust

//! # use zamm_yin::graph::{bind_in_memory_graph, InjectionGraph, Graph};

//! # bind_in_memory_graph();

//! # let mut g = InjectionGraph::new();

//! # let a_id = g.add_node();

//! # let b_id = g.add_node();

//! # let c_id = g.add_node();

//! # let d_id = g.add_node();

//! # let edge_type1 = g.add_node();

//! # let edge_type2 = g.add_node();

//! g.add_edge(b_id, edge_type1, a_id);

//! g.add_edge(c_id, edge_type2, a_id);

//! g.add_edge(d_id, edge_type1, a_id);

//!

//! assert_eq!(g.all_incoming_nodes(a_id), vec![b_id, c_id, d_id]);

//! assert_eq!(g.incoming_nodes(a_id, edge_type1), vec![b_id, d_id]);

//! assert_eq!(g.all_outgoing_nodes(b_id), vec![a_id]);

//! assert_eq!(g.outgoing_nodes(c_id, edge_type2), vec![a_id]);

//! ```

//!

//! We can also use the KB to invoke certain functionality. Note that we are passing in a `Tao`

//! concept to the callback function because that's the only supported function at this moment.

//!

//! ```rust

//! # use zamm_yin::graph::{bind_in_memory_graph, InjectionGraph, Graph};

//! # use zamm_yin::graph::value_wrappers::{unwrap_weak, WeakValue};

//! # use std::rc::Rc;

//! # bind_in_memory_graph();

//! # let mut g = InjectionGraph::new();

//! use zamm_yin::concepts::{Tao, ArchetypeTrait, FormTrait};

//! use zamm_yin::graph::value_wrappers::{StrongValue, KBClosure, unwrap_closure};

//! use zamm_yin::{define_closure, run_closure};

//! use zamm_yin::node_wrappers::BaseNodeTrait;

//! use std::any::Any;

//! use std::cell::{RefCell, RefMut};

//!

//! let count_id = g.add_node();

//! let count_value: Rc<i64> = Rc::new(5);

//! g.set_node_value(count_id, Box::new(WeakValue::new(&count_value)));

//!

//! let mut triple_id = g.add_node();

//! g.set_node_value(triple_id, define_closure!(|t: Tao| {

//!     Box::new(*unwrap_weak::<i64>(t.essence().value()).unwrap() * 3)

//! }));

//! assert_eq!(

//!     run_closure!(&g.node_value(triple_id), Tao::from(count_id), i64),

//!     Some(Box::new(15))

//! );

//! ```

//!

//! In general, it's recommended to only use the KB to decide what to do at a very high level, and

//! not to actually do things via the KB. For example, perhaps we could use the KB to decide to run

//! Dijkstra's. We could even use the KB to design and debug an implementation of Dijkstra's. But

//! the actual computation of Dijkstra's algorithm should involve low-level data structures and

//! logic outside of the KB.


#[cfg(feature = "cypher")]
mod cypher_graph;
mod in_memory_graph;
mod injection_graph;
mod invalid_graph;
/// Wrappers around values associated with nodes in the KB. This differs from the other

/// [`wrappers`](../wrappers/index.html) package because this abstraction only wraps the

/// values associated with nodes, while the other one wraps the nodes themselves.

///

/// Due to Rust restrictions around upcasting to Any, it appears necessary to create an extra

/// wrapper.

pub mod value_wrappers;

use crate::graph::value_wrappers::KBValue;
#[cfg(feature = "cypher")]
pub use injection_graph::bind_cypher_graph;
pub use injection_graph::{bind_in_memory_graph, print_graph_debug, InjectionGraph};

use std::rc::Rc;

/// A classic directed Graph with nodes and labeled links.

pub trait Graph {
    /// The number of nodes in the graph.

    fn size(&self) -> usize;

    /// Adds a new node to the graph, and returns the node's ID.

    fn add_node(&mut self) -> usize;

    /// Sets the value for a given node. Values can only be set once.

    fn set_node_value(&mut self, id: usize, value: Box<dyn KBValue>);

    /// Sets the name for a given node. Names can only be set once.

    fn set_node_name(&mut self, id: usize, name: String);

    /// Retrieve's a node's name from the graph, or None if the node does not exist or is unnamed.

    fn node_name(&self, id: usize) -> Option<Rc<String>>;

    /// Retrieve's a node's name from the graph, or None if the node does not exist or does not

    /// have a value.

    fn node_value(&self, id: usize) -> Option<Rc<Box<dyn KBValue>>>;

    /// Look up a node ID based on name. A vec is returned because there are no constraints on name

    /// uniqueness.

    fn lookup(&self, name: &str) -> Vec<usize>;

    /// Add a labeled edge between two nodes. The label should be the ID of an existing node.

    fn add_edge(&mut self, from: usize, edge_type: usize, to: usize);

    /// Checks for a labeled edge between two nodes. The label should be the ID of an existing node.

    fn has_edge(&self, from: usize, edge_type: usize, to: usize) -> bool;

    /// Retrieve all node IDs that are on the other end of an outgoing edge of the given type.

    fn outgoing_nodes(&self, from: usize, edge_type: usize) -> Vec<usize>;

    /// Retrieve all node IDs that are on the other end of an incoming edge of the given type.

    fn incoming_nodes(&self, to: usize, edge_type: usize) -> Vec<usize>;

    /// Retrieve all node IDs that are on the other end of outgoing edges.

    fn all_outgoing_nodes(&self, from: usize) -> Vec<usize>;

    /// Retrieve all node IDs that are on the other end of incoming edges.

    fn all_incoming_nodes(&self, to: usize) -> Vec<usize>;

    /// Outputs the entire graph in DOT format.

    fn into_dot(&self) -> String;
}