diff --git a/src/expand_n_contract.rs b/src/expand_n_contract.rs index e75599674f5824825ccf59b759bcb5bc1ba80593..a043c718cf4e13fa910438677939c4ae2e56fc85 100644 --- a/src/expand_n_contract.rs +++ b/src/expand_n_contract.rs @@ -31,10 +31,10 @@ pub fn expand_n_contract( let mut g_idx: usize = 0; loop { // dbg!(&g_idx); - let dg_data: HashMap<UndirectedGraph, (i64, Vec<usize>)> = + let dg_data: Vec<(i64, UndirectedGraph, Vec<usize>)> = cocycle_graphs[g_idx].expanding_differential(&cocycle_graph_vertex_orbits[g_idx]); - for (dg, (c, dg_edge_orbits)) in dg_data { + for (c, dg, 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); @@ -51,7 +51,7 @@ pub fn expand_n_contract( writeln!(sparse_matrix_file, "{} {} {}", dg_idx + 1, g_idx + 1, c)?; num_nonzeros += 1; - let cg_data: HashMap<UndirectedGraph, Vec<usize>> = dg.contractions(&dg_edge_orbits); + let cg_data: Vec<(UndirectedGraph, Vec<usize>)> = dg.contractions(&dg_edge_orbits); for (cg, cg_vertex_orbits) in cg_data { // eprintln!("{:?}", cg); if !cocycle_graph_index.contains_key(&cg) { diff --git a/src/undirected_graph.rs b/src/undirected_graph.rs index fc6a0a72ccef738a45d01a2e0c94e78b7f316a59..cde40ee40e383f9150b975a39642d71afe9ef7c8 100644 --- a/src/undirected_graph.rs +++ b/src/undirected_graph.rs @@ -463,19 +463,24 @@ impl UndirectedGraph { pub fn expanding_differential( &self, orbits: &[usize], - ) -> HashMap<UndirectedGraph, (i64, Vec<usize>)> { - let mut diff: HashMap<UndirectedGraph, (i64, Vec<usize>)> = HashMap::new(); + ) -> Vec<(i64, UndirectedGraph, Vec<usize>)> { + let mut diff: Vec<(i64, UndirectedGraph, Vec<usize>)> = vec![]; + let mut graph_pos_in_diff: HashMap<UndirectedGraph, usize> = HashMap::new(); - let mut orbit_reps: HashMap<usize, usize> = HashMap::new(); + // NOTE: We do some extra work to make the ordering of the result deterministic. + let mut orbit_sizes: HashMap<usize, usize> = HashMap::new(); + let mut orbit_reps: Vec<usize> = vec![]; for &orbit_rep in orbits { - if let Some(orbit_size) = orbit_reps.get_mut(&orbit_rep) { + if let Some(orbit_size) = orbit_sizes.get_mut(&orbit_rep) { *orbit_size += 1; } else { - orbit_reps.insert(orbit_rep, 1); + orbit_reps.push(orbit_rep); + orbit_sizes.insert(orbit_rep, 1); } } - for (orbit_rep, orbit_size) in orbit_reps { + for orbit_rep in orbit_reps { + let orbit_size: usize = orbit_sizes[&orbit_rep]; for (c, mut dg) in self.expand_vertex(&orbit_rep) { let (normal_dg_sign, normal_dg_edge_orbits) = dg.normal_form(true); if normal_dg_sign == 0 { @@ -483,19 +488,22 @@ impl UndirectedGraph { } // TODO: Fix coefficient types. let normal_dg_coeff: i64 = (normal_dg_sign as i64) * (orbit_size as i64) * c; - if let Some((diff_coeff, _)) = diff.get_mut(&dg) { - *diff_coeff += normal_dg_coeff; + if let Some(&diff_idx) = graph_pos_in_diff.get(&dg) { + diff[diff_idx].0 += normal_dg_coeff; } else { - diff.insert(dg, (normal_dg_coeff, normal_dg_edge_orbits)); + graph_pos_in_diff.insert(dg.clone(), diff.len()); + diff.push((normal_dg_coeff, dg, normal_dg_edge_orbits)); } } } - diff.retain(|_dg, (dg_coeff, _)| *dg_coeff != 0); + diff.retain(|(dg_coeff, _, _)| *dg_coeff != 0); diff } - pub fn contractions(&self, edge_orbits: &Vec<usize>) -> HashMap<UndirectedGraph, Vec<usize>> { - let mut contractions: HashMap<UndirectedGraph, Vec<usize>> = HashMap::new(); + pub fn contractions(&self, edge_orbits: &Vec<usize>) -> Vec<(UndirectedGraph, Vec<usize>)> { + let mut contractions: Vec<(UndirectedGraph, Vec<usize>)> = vec![]; + let mut graphs_seen: HashSet<UndirectedGraph> = HashSet::new(); + let mut edge_orbit_reps: HashSet<usize> = HashSet::new(); for &edge_orbit_rep in edge_orbits { // Skip orbits already seen. @@ -574,7 +582,9 @@ impl UndirectedGraph { continue; } - contractions.insert(cg, normal_cg_orbits); + if graphs_seen.insert(cg.clone()) { + contractions.push((cg, normal_cg_orbits)); + } } contractions }