diff --git a/src/main.rs b/src/main.rs
index eb3ac1678a4af91bc0c62cf5fca22ff8f1e5002f..dfa92baac002dea5a93fec027b0f7066abd7e867 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,19 +1,104 @@
 mod undirected_graph;
+use std::collections::HashMap;
+use std::env;
+use std::process;
 use undirected_graph::UndirectedGraph;
 
 fn main() {
-    let g: UndirectedGraph = UndirectedGraph::wheel_graph(5);
-    println!("g = {:?}", g);
-    println!("g.to_nauty() = {:?}", g.to_nauty());
-    println!("UndirectedGraph::from_nauty(&g.to_nauty()) = {:?}", UndirectedGraph::from_nauty(&g.to_nauty()));
-    let (_sign, normal_g, orbits,_) = g.normal_form(false);
-    println!("normal_g = {:?}", normal_g);
-    println!("normal_g.expanding_differential(&orbits) = {:?}", normal_g.expanding_differential(&orbits));
-    println!("normal_g.contractions() = {:?}", normal_g.contractions(&vec![0_usize]));
-    let h: UndirectedGraph = UndirectedGraph::new(7,vec![(0, 1), (0, 2), (0, 6), (1, 4), (1, 6), (2, 5), (2, 6), (3, 4), (3, 5), (3, 6), (4, 5)]);
-    let edge_orbits_h: Vec<usize> = vec![0, 0, 2, 3, 4, 3, 4, 10, 7, 7, 9];
-    println!("normal_h.contractions(&edge_orbits_h) = {:?}", h.contractions(&edge_orbits_h));
-    let triangle: UndirectedGraph = UndirectedGraph::new(3, vec![(0,1), (1,2), (0,2)]);
-    println!("triangle.normal_form() = {:?}", triangle.normal_form(true));
-    println!("triangle.contractions() = {:?}", triangle.contractions(&vec![0_usize]));
+    let args: Vec<String> = env::args().collect();
+
+    if args.len() != 2 {
+        eprintln!("Usage: {} <number-of-spokes>", args[0]);
+        process::exit(1);
+    }
+
+    let num_spokes_maybe: Result<usize, std::num::ParseIntError> = args[1].parse::<usize>();
+    if num_spokes_maybe.is_err() {
+        eprintln!("Error parsing the first argument as number-of-spokes.");
+        process::exit(1);
+    }
+    let num_spokes: usize = num_spokes_maybe.unwrap();
+
+    if num_spokes < 2 {
+        eprintln!("A wheel graph without tadpoles must have at least two spokes.");
+        process::exit(1);
+    }
+
+    let mut cocycle_graphs: Vec<UndirectedGraph> = vec![];
+    let mut cocycle_graph_index: HashMap<UndirectedGraph, usize> = HashMap::new();
+    let mut cocycle_graph_vertex_orbits: Vec<HashMap<usize, usize>> = vec![];
+
+    let mut cocycle_differential_graphs: Vec<UndirectedGraph> = vec![];
+    let mut cocycle_differential_graph_index: HashMap<UndirectedGraph, usize> = HashMap::new();
+    let mut cocycle_differential_graph_edge_orbits: Vec<Vec<usize>> = vec![];
+
+    // NOTE: Start with the normal form of the wheel graph.
+    let wheel_graph: UndirectedGraph = UndirectedGraph::wheel_graph(num_spokes);
+    let (wheel_graph_sign, wheel_graph_normal, wheel_graph_vertex_orbits, _) =
+        wheel_graph.normal_form(false);
+    if wheel_graph_sign == 0 {
+        eprintln!("The {}-wheel graph has an automorphism that induces an odd permutation on edges, so it is equal to zero in the graph complex.", num_spokes);
+        process::exit(1);
+    }
+    cocycle_graphs.push(wheel_graph_normal.clone());
+    cocycle_graph_index.insert(wheel_graph_normal.clone(), 0);
+    cocycle_graph_vertex_orbits.push(wheel_graph_vertex_orbits);
+
+    println!("? ? M");
+    let mut g_idx: usize = 0;
+    loop {
+        // dbg!(&g_idx);
+        let dg_data: HashMap<UndirectedGraph, (i64, Vec<usize>)> =
+            cocycle_graphs[g_idx].expanding_differential(&cocycle_graph_vertex_orbits[g_idx]);
+
+        for (dg, (c, dg_edge_orbits)) in dg_data {
+            // eprintln!("{:?}", dg);
+            let dg_idx: usize = if let Some(&idx) = cocycle_differential_graph_index.get(&dg) {
+                // eprintln!("old graph in differential: {}", idx);
+                idx
+            } else {
+                let idx: usize = cocycle_differential_graphs.len();
+                // eprintln!("new graph in differential: {}", idx);
+                cocycle_differential_graphs.push(dg.clone());
+                cocycle_differential_graph_edge_orbits.push(dg_edge_orbits.clone());
+                cocycle_differential_graph_index.insert(dg.clone(), idx);
+                idx
+            };
+            // TODO: Make the output lexicographically ordered? Strictly speaking this is not the SMS format right now.
+            println!("{} {} {}", dg_idx + 1, g_idx + 1, c);
+
+            let cg_data: HashMap<UndirectedGraph, HashMap<usize, usize>> =
+                dg.contractions(&dg_edge_orbits);
+            for (cg, cg_vertex_orbits) in cg_data {
+                // eprintln!("{:?}", cg);
+                if !cocycle_graph_index.contains_key(&cg) {
+                    let idx: usize = cocycle_graphs.len();
+                    // eprintln!("new graph in cocycle: {}", idx);
+                    cocycle_graphs.push(cg.clone());
+                    cocycle_graph_vertex_orbits.push(cg_vertex_orbits);
+                    cocycle_graph_index.insert(cg.clone(), idx);
+                }
+            }
+        }
+
+        g_idx += 1;
+        if g_idx >= cocycle_graphs.len() {
+            break;
+        }
+    }
+    println!("0 0 0");
+    println!("# Move this line to the top:");
+    println!(
+        "{} {} M",
+        cocycle_differential_graphs.len(),
+        cocycle_graphs.len()
+    );
+
+    eprintln!(
+        "Matrix size: {} x {}",
+        cocycle_differential_graphs.len(),
+        cocycle_graphs.len()
+    );
+
+    // TODO: Also output the ordered bases of graphs.
 }