Adding ramen graph logic sketch here

This commit is contained in:
Skye Terran 2022-09-14 23:44:05 -07:00
parent 62bb5c620c
commit d3f9f81468
2 changed files with 148 additions and 0 deletions

7
ramen/Cargo.toml Normal file
View File

@ -0,0 +1,7 @@
[package]
name = "ramen"
version = "0.1.0"
edition = "2021"
[dependencies]

141
ramen/src/main.rs Normal file
View File

@ -0,0 +1,141 @@
fn main() {
// Represent the graph as adjacency lists
let mut graph = Graph {
// (1 + 2) / 4
nodes: vec![
Node { kind: NodeKind::Lit(1.0), inputs: vec![] },
Node { kind: NodeKind::Lit(2.0), inputs: vec![] },
Node { kind: NodeKind::Op(AtomOp::Add), inputs: vec![0, 1] },
Node { kind: NodeKind::Lit(4.0), inputs: vec![] },
Node { kind: NodeKind::Op(AtomOp::Div), inputs: vec![2, 3] },
Node { kind: NodeKind::Op(AtomOp::Mul), inputs: vec![4, 4] },
Node { kind: NodeKind::Op(AtomOp::Add), inputs: vec![5, 0] },
Node { kind: NodeKind::Lit(0.0), inputs: vec![] }, // Should be ignored since it's not used
]
};
graph.compile().expect("Compilation failure");
}
#[derive(Debug, Clone)]
struct Node {
kind: NodeKind,
inputs: Vec<usize>,
}
#[derive(Debug, Clone)]
enum NodeKind {
Lit(f32),
Op(AtomOp)
}
#[derive(Debug)]
enum GraphError {
Cyclic
}
#[derive(Debug)]
struct Graph {
nodes: Vec<Node>,
}
#[derive(Debug, Clone)]
enum AtomOp {
Add,
Sub,
Mul,
Div,
}
impl Graph {
fn compile(&self) -> Result<(), GraphError> {
// TODO: Only compile the nodes that are actually used
// Iterate through the nodes in topological order
for key in self.topological_order()? {
let node = &self.nodes[key];
match &node.kind {
NodeKind::Lit(x) => {
//
println!("let n{}: f32 = {:?};", key, x);
},
NodeKind::Op(op) => {
let symbol = match op {
AtomOp::Add => '+',
AtomOp::Sub => '-',
AtomOp::Mul => '*',
AtomOp::Div => '/',
};
println!("let n{}: f32 = n{} {} n{};", key, &node.inputs[0], symbol, &node.inputs[1]);
},
}
}
Ok(())
}
// Return the edges that can be derived from the graph
fn edges(&self) -> Result<Vec<(usize, usize)>, GraphError> {
let topo_order = self.topological_order()?;
let mut edges: Vec<(usize, usize)> = Vec::new();
for (i, node) in topo_order.iter().enumerate() {
for j in &self.nodes[*node].inputs {
edges.push((*j, i));
}
}
Ok(edges)
}
fn topological_order(&self) -> Result<Vec<usize>, GraphError> {
// The number of nodes
let v = self.nodes.len();
// Forward-directed adjacency lists
let mut adjacency_lists: Vec<Vec<usize>> = vec![Vec::new(); v];
for (i, node) in self.nodes.iter().enumerate() {
for j in &node.inputs {
adjacency_lists[*j].push(i);
}
}
// Create list of indegrees
let mut indegrees: Vec<usize> = vec![0; v];
for (i, node) in self.nodes.iter().enumerate() {
indegrees[i] = node.inputs.len();
}
// Create a queue and initialize it with nodes with no indegrees
let mut queue: Vec<usize> = Vec::new();
for (i, count) in indegrees.iter().enumerate() {
if *count == 0 {
queue.push(i);
}
}
let mut sort_count = 0;
let mut topo_order: Vec<usize> = Vec::new();
while !queue.is_empty() {
let u = queue.pop().unwrap();
topo_order.push(u);
for i in &adjacency_lists[u] {
indegrees[*i] -= 1;
if indegrees[*i] == 0 {
queue.push(*i);
}
}
sort_count += 1;
}
// Check if there was a cycle
if sort_count != v {
Err(GraphError::Cyclic)
} else {
Ok(topo_order)
}
}
}