From 6d776c685aaad081fa0c7c64b61870fe3182d21e Mon Sep 17 00:00:00 2001 From: Joey Beauvais-Feisthauer Date: Tue, 20 Feb 2024 17:10:36 -0500 Subject: [PATCH] Implement `chartmaker` compatible output --- ext/crates/chart/src/lib.rs | 129 ++++++++++++++++++++++++++++++++- ext/examples/unstable_chart.rs | 19 +++-- 2 files changed, 139 insertions(+), 9 deletions(-) diff --git a/ext/crates/chart/src/lib.rs b/ext/crates/chart/src/lib.rs index 58d4dbde9..96f2b8666 100644 --- a/ext/crates/chart/src/lib.rs +++ b/ext/crates/chart/src/lib.rs @@ -1,4 +1,8 @@ -use std::{collections::HashMap, fmt::Display, io::Write}; +use std::{ + collections::{BTreeMap, HashMap}, + fmt::Display, + io::Write, +}; #[rustfmt::skip] const PATTERNS: [(f32, &[(f32, f32)]); 12] = [ @@ -436,6 +440,129 @@ impl Drop for TikzBackend { } } +pub struct NodeMetadata { + pub index: String, + pub s: i32, + pub f: i32, + pub shift: i32, + pub h0target: Vec, + pub h1target: Vec, + pub h2target: Vec, + pub h3target: Vec, +} + +pub struct ChartmakerBackend { + out: T, + indices: BTreeMap<(i32, i32, usize), NodeMetadata>, +} + +impl ChartmakerBackend { + pub fn new(out: T) -> Self { + Self { + out, + indices: BTreeMap::new(), + } + } +} + +impl Backend for ChartmakerBackend { + type Error = std::io::Error; + + const EXT: &'static str = ".csv"; + + fn header(&mut self, _max_x: i32, _max_y: i32) -> Result<(), Self::Error> { + writeln!( + self.out, + "index,s,f,shift,h0target,h1target,h2target,h3target,XX" + )?; + Ok(()) + } + + fn line( + &mut self, + _start_x: i32, + _end_x: i32, + _start_y: i32, + _end_y: i32, + _style: &str, + ) -> Result<(), Self::Error> { + Ok(()) + } + + fn text( + &mut self, + _x: i32, + _y: i32, + _content: impl Display, + _orientation: Orientation, + ) -> Result<(), Self::Error> { + Ok(()) + } + + fn node(&mut self, x: i32, y: i32, n: usize) -> Result<(), Self::Error> { + let n = n as i32; + for i in 0..n { + let index = format!("{x}_{y}_{i}"); + let metadata = NodeMetadata { + index, + s: x, + f: y, + shift: 2 * i + 1 - n, + h0target: vec![], + h1target: vec![], + h2target: vec![], + h3target: vec![], + }; + self.indices.insert((x, y, i as usize), metadata); + } + Ok(()) + } + + fn structline( + &mut self, + source: (i32, i32, usize), + target: (i32, i32, usize), + _style: Option<&str>, + ) -> Result<(), Self::Error> { + let target_index = self.indices.get(&target).unwrap().index.clone(); + let source_metadata = self.indices.get_mut(&source).unwrap(); + match (target.0 - source.0, target.1 - source.1) { + (0, 1) => source_metadata.h0target.push(target_index), + (1, 1) => source_metadata.h1target.push(target_index), + (3, 1) => source_metadata.h2target.push(target_index), + (7, 1) => source_metadata.h3target.push(target_index), + _ => panic!("Invalid structline"), + } + Ok(()) + } + + fn init(&mut self, max_x: i32, max_y: i32) -> Result<(), Self::Error> { + self.header(max_x, max_y)?; + Ok(()) + } +} + +impl Drop for ChartmakerBackend { + fn drop(&mut self) { + for metadata in self.indices.values() { + writeln!( + self.out, + "{},{},{},{},{},{},{},{},", + metadata.index, + metadata.s, + metadata.f, + metadata.shift, + metadata.h0target.join(";"), + metadata.h1target.join(";"), + metadata.h2target.join(";"), + metadata.h3target.join(";"), + ) + .unwrap(); + } + self.out.flush().unwrap(); + } +} + #[cfg(test)] mod test { use expect_test::expect_file; diff --git a/ext/examples/unstable_chart.rs b/ext/examples/unstable_chart.rs index 1107bce8a..d3695e452 100644 --- a/ext/examples/unstable_chart.rs +++ b/ext/examples/unstable_chart.rs @@ -22,7 +22,7 @@ use algebra::{ module::{Module, SuspensionModule}, Algebra, }; -use chart::{Backend, Orientation, TikzBackend}; +use chart::{Backend, ChartmakerBackend, Orientation}; use ext::{ chain_complex::{FiniteChainComplex, FreeChainComplex}, resolution::UnstableResolution, @@ -48,10 +48,11 @@ fn main() -> anyhow::Result<()> { query::raw("Max s", str::parse), ); - let disp_template: String = query::raw( - "LaTeX name template (replace % with min degree)", - str::parse, - ); + let disp_template = ""; + // let disp_template: String = query::raw( + // "LaTeX name template (replace % with min degree)", + // str::parse, + // ); let products = module.algebra().default_filtration_one_products(); @@ -68,7 +69,7 @@ fn main() -> anyhow::Result<()> { res.compute_through_stem(max + shift); - println!("\\begin{{figure}}[p]\\centering"); + // println!("\\begin{{figure}}[p]\\centering"); let sseq = res.to_sseq(); let products = products @@ -79,7 +80,9 @@ fn main() -> anyhow::Result<()> { .collect::>(); sseq.write_to_graph( - TikzBackend::new(std::io::stdout()), + ChartmakerBackend::new( + std::fs::File::create(&format!("{module}_{shift_t}.csv")).unwrap(), + ), 2, false, products.iter(), @@ -93,7 +96,7 @@ fn main() -> anyhow::Result<()> { }, )?; - println!("\\end{{figure}}"); + // println!("\\end{{figure}}"); } Ok(()) }