~mht/cra

77dcba4841d83eb08bba94aec7e7234ac3e6374b — Martin Hafskjold Thoresen 2 years ago a9f2af5
More dimension specific numbers
1 files changed, 125 insertions(+), 76 deletions(-)

M cra/src/main.rs
M cra/src/main.rs => cra/src/main.rs +125 -76
@@ 8,7 8,7 @@ use std::iter;
use std::path::Path;
use std::process::{Command, Stdio};

const R_CUTOFF: f64 = 300.0;
const R_CUTOFF: f64 = 30000.0;

fn f64_eq(a: f64, b: f64) -> bool {
    let u = 1_000_000.0;


@@ 19,6 19,8 @@ fn f64_eq(a: f64, b: f64) -> bool {
    // (a - b).abs() < 10_000.0 * std::f64::EPSILON
}

const MAX_DIM: usize = 3;

/// All the statistics we want to measure for performance reasoning.
#[derive(Debug)]
pub struct Statistics {


@@ 30,12 32,15 @@ pub struct Statistics {
    ex_reductions: Vec<usize>,
    ex_searches: Vec<usize>,
    zeroed: usize,
    zeroed_d: [usize; MAX_DIM],
    placed_single: usize,
    placed_full: usize,
    placed_full_d: [usize; MAX_DIM],
    simplex_with_low_queries: usize,

    // Number of simlpices in all dimensions
    num_of_dimens: Vec<usize>,
    num_of_dimens: [usize; MAX_DIM],
    skip_d: [usize; MAX_DIM],

    time: u64,
}


@@ 51,10 56,14 @@ impl Statistics {
            ex_reductions: Vec::new(),
            ex_searches: Vec::new(),
            zeroed: 0,
            zeroed_d: [0; MAX_DIM],
            placed_single: 0,
            placed_full: 0,
            placed_full_d: [0; MAX_DIM],
            simplex_with_low_queries: 0,
            num_of_dimens: Vec::new(),

            num_of_dimens: [0; MAX_DIM],
            skip_d: [0; MAX_DIM],

            time: 0,
        }


@@ 80,18 89,15 @@ impl Statistics {
    }

    /// Record the number of times a reduction ended up removing the simplex.
    pub fn zeroed(&mut self) {
    pub fn zeroed(&mut self, d: usize) {
        self.zeroed += 1;
    }

    /// Record the number of times a reduction ended up storing a single index.
    pub fn placed_single(&mut self) {
        self.placed_single += 1;
        self.zeroed_d[d] += 1;
    }

    /// Record the number of times a reduction ended up with storing a list of indices.
    pub fn placed_full(&mut self) {
    pub fn placed_full(&mut self, d: usize) {
        self.placed_full += 1;
        self.placed_full_d[d] += 1;
    }

    /// Record the number of times we looked for another column with the same low, and added it to


@@ 105,6 111,10 @@ impl Statistics {
        self.add_size_sum.push(a + b);
    }

    pub fn skip(&mut self, d: usize) {
        self.skip_d[d] += 1;
    }

    /// Record the nubmer of times we're queried the `simplex_with_low` array.
    pub fn swl(&mut self) {
        self.simplex_with_low_queries += 1;


@@ 294,14 304,12 @@ pub struct Persistence {
impl Persistence {
    /// Fill in some stats
    fn register_stats(&self, stats: &mut Statistics) {
        let mut dim_counts = vec![0; 10];
        for s in &self.simplices {
            if s.dim() < 0 {
                continue;
            }
            dim_counts[s.dim() as usize] += 1;
            stats.num_of_dimens[s.dim() as usize] += 1;
        }
        stats.num_of_dimens = dim_counts;
    }
}



@@ 538,7 546,7 @@ impl Reduction {
        for j in 1..n {
            let s = &simplices[j];
            write!(w, "{};| {:?};| {:?};| ", s.j, s.faces, additions_of[j])?;
            if let Some(i) = i_of_j[j] {
            if let Some(_i) = i_of_j[j] {
                // writeln!(w, "{:?}", self.simplex_with_low[i].get())?;
                writeln!(w, " +");
            } else {


@@ 573,11 581,14 @@ pub fn reduce(p: &Persistence, variant: Variant, stats: &mut Statistics) -> Redu

    for simplex in p.simplices.iter() {
        let j = simplex.j;
        if simplex.faces.last().is_none() || simplex.r_when_born >= R_CUTOFF {
        if simplex.faces.last().is_none() {
            continue; 
        }
        let s_dim = simplex.dim().max(0) as usize; 
        if simplex.r_when_born >= R_CUTOFF {
            stats.skip(s_dim);
            continue;
        }
        let s_dim = simplex.dim();

        let mut current_simplex = simplex.faces.clone();
        current_simplex.sort();



@@ 592,7 603,7 @@ pub fn reduce(p: &Persistence, variant: Variant, stats: &mut Statistics) -> Redu
                debug_assert!(low <= j);
                pairings.push((low, j));

                stats.placed_full();
                stats.placed_full(s_dim);
                simplex_with_low[low] = List(current_simplex);
                j_stored_at[low] = j;



@@ 638,7 649,7 @@ pub fn reduce(p: &Persistence, variant: Variant, stats: &mut Statistics) -> Redu
            additions.push((j_stored_at[low], j));
            column_add(&mut current_simplex, cand.get(), s_dim, stats);
            if current_simplex.is_empty() {
                stats.zeroed();
                stats.zeroed(s_dim);
                break;
            }
        }


@@ 721,7 732,7 @@ impl IndList {

/// Add the `other` column into the `this` column. Since we're in (mod 2) arithmetic, this `xor`s
/// together the two vectors.
fn column_add(this: &mut Vec<usize>, other: &Vec<usize>, simplex_dim: isize, stats: &mut Statistics) {
fn column_add(this: &mut Vec<usize>, other: &Vec<usize>, simplex_dim: usize, stats: &mut Statistics) {
    // TODO: hehe
    static mut BUFFER: Option<Vec<usize>> = None;
    let buffer: &mut Vec<usize> = unsafe {


@@ 731,9 742,7 @@ fn column_add(this: &mut Vec<usize>, other: &Vec<usize>, simplex_dim: isize, sta
        BUFFER.as_mut().unwrap()
    };
    debug_assert_eq!(buffer.len(), 0);
    if simplex_dim >= 0 {
        stats.col_add(simplex_dim as usize);
    }
    stats.col_add(simplex_dim);
    stats.add_sizes(this.len(), other.len());

    let mut our_i = 0;


@@ 1117,24 1126,24 @@ fn tex_table<W: Write>(reg: &Statistics, exh: &Statistics, writer: &mut W) {
        format!("{:.2}\\%", 100.0 * b / a)
    }

    let mut v: Vec<(&str, String, String, String)> = Vec::new();
    let mut v: Vec<(String, String, String, String)> = Vec::new();

    v.push((
        "Column additions",
        format!("Column additions"),
        thousand_split(reg.col_adds),
        thousand_split(exh.col_adds),
        percent(reg.col_adds as f64, exh.col_adds as f64),
    ));

    v.push((
        "Estimate total \\texttt{column\\_add} cost",
        format!("Estimate \\texttt{{column\\_add}} cost"),
        thousand_split(sum(&reg.add_size_sum) as usize),
        thousand_split(sum(&exh.add_size_sum) as usize),
        percent(sum(&reg.add_size_sum), sum(&exh.add_size_sum)),
    ));

    v.push((
        "\\texttt{simplex\\_with\\_low} queries",
        format!("\\texttt{{simplex\\_with\\_low}} queries"),
        thousand_split(reg.simplex_with_low_queries),
        thousand_split(exh.simplex_with_low_queries),
        percent(


@@ 1144,7 1153,7 @@ fn tex_table<W: Write>(reg: &Statistics, exh: &Statistics, writer: &mut W) {
    ));

    v.push((
        "Time spent (ns)",
        format!("Time spent (ns)"),
        thousand_split(reg.time as usize),
        thousand_split(exh.time as usize),
        percent(reg.time as f64, exh.time as f64),


@@ 1152,7 1161,7 @@ fn tex_table<W: Write>(reg: &Statistics, exh: &Statistics, writer: &mut W) {

    let as0 = |s: &[(usize, usize)]| s.iter().map(|(a, _)| a).cloned().collect::<Vec<_>>();
    v.push((
        "Average size of first operand",
        format!("Size of first operand"),
        format!("{:.4}", avg(&as0(&reg.add_size))),
        format!("{:.4}", avg(&as0(&exh.add_size))),
        percent(avg(&as0(&reg.add_size)), avg(&as0(&exh.add_size))),


@@ 1160,54 1169,40 @@ fn tex_table<W: Write>(reg: &Statistics, exh: &Statistics, writer: &mut W) {

    let as1 = |s: &[(usize, usize)]| s.iter().map(|(_, b)| b).cloned().collect::<Vec<_>>();
    v.push((
        "Average size of second operand",
        format!("Size of second operand"),
        format!("{:.4}", avg(&as1(&reg.add_size))),
        format!("{:.4}", avg(&as1(&exh.add_size))),
        percent(avg(&as1(&reg.add_size)), avg(&as1(&exh.add_size))),
    ));

    v.push((
        "Average \\#iterations before reducing a column",
        format!("Iters for reducing a column"),
        format!("{:.4}", avg(&reg.num_iters)),
        format!("{:.4}", avg(&exh.num_iters)),
        percent(avg(&reg.num_iters), avg(&exh.num_iters)),
    ));

    v.push((
        "Average cost of one column addition",
        format!("Cost of one column addition"),
        format!("{:.4}", avg(&reg.add_size_sum)),
        format!("{:.4}", avg(&exh.add_size_sum)),
        percent(avg(&reg.add_size_sum), avg(&exh.add_size_sum)),
    ));

    v.push((
        "Average iterations to exh.\\ reduce a col",
        format!("Iters to exh.\\ reduce a col"),
        format!(""),
        format!("{:.4}", avg(&exh.ex_reductions)),
        format!(""),
    ));

    v.push((
        "Average searches to find \\texttt{j=low(k)}",
        format!("Searches to find \\texttt{{j=low(k)}}"),
        format!(""),
        format!("{:.4}", avg(&exh.ex_searches)),
        format!(""),
    ));

    v.push((
        "Number of zeroed simplices",
        thousand_split(reg.zeroed),
        thousand_split(exh.zeroed),
        format!("")
    ));

    v.push((
        "Number of stored simplices",
        thousand_split(reg.placed_full),
        thousand_split(exh.placed_full),
        format!("")
    ));

    // TODO: 4 could be bigger!
    let mut reg_counts = [0; 4];
    for &d in &reg.col_add_dimens {


@@ 1217,54 1212,108 @@ fn tex_table<W: Write>(reg: &Statistics, exh: &Statistics, writer: &mut W) {
    for &d in &exh.col_add_dimens {
        exh_counts[(d + 1) as usize] += 1;
    }
    let strs = (0..exh_counts.len()).map(|d1| format!("Column adds with $d={}$", d1 as isize - 1)).collect::<Vec<_>>();

    for (d1, (&r, &e)) in reg_counts.iter().zip(exh_counts.iter()).enumerate().skip(1) {
        v.push((
            &strs[d1],
            format!("Column adds with $d={}$", d1 as isize - 1),
            thousand_split(r),
            thousand_split(e),
            percent(r as f64, e as f64)
        ));
    }

    let mut last_pos = 0;
    for (i, (&a, &b)) in reg
        .num_of_dimens
        .iter()
        .zip(exh.num_of_dimens.iter())
        .enumerate()
    {
        if a > 0 || b > 0 {
            last_pos = i;
        }
    write!(
        writer,
        r#"\begin{{tabular}}{{r r r r}}
  Counter & Regular & Exhausitve & Difference \\
  \toprule
"#
    )
    .unwrap();
    for (l, a, b, p) in v {
        write!(writer, "  {} & {} & {} & {}\\\\\n", l, a, b, p).unwrap();
    }
    let strs = (0..last_pos + 1)
        .map(|d| format!("Simplices with $d={}$", d))
        .collect::<Vec<_>>();
    for d in 0..last_pos + 1 {
        let r = reg.num_of_dimens[d];
        let e = reg.num_of_dimens[d];
        v.push((
            &strs[d],
            thousand_split(r),
            thousand_split(e),
    writeln!(writer, "\\end{{tabular}}").unwrap();

    let mut s: Vec<(String, String, String)> = Vec::new();

    s.push((
        format!("Simplices"),
        thousand_split(reg.num_of_dimens.iter().sum::<usize>()),
        format!("")
    ));
    for (d, &n) in reg.num_of_dimens.iter().enumerate() {
        s.push((
            format!("$d={}$", d),
            thousand_split(n),
            format!("")
        ));
    }

    s.push((
        format!("Skipped simplices"),
        thousand_split(reg.skip_d.iter().sum::<usize>()),
        format!("")
    ));
    for (d, &r) in reg.skip_d.iter().enumerate() {
        s.push((
            format!("\\ldots $d={}$", d),
            thousand_split(r),
            if reg.num_of_dimens[d] > 0 {
                percent(reg.num_of_dimens[d] as f64, r as f64)
            } else {
                format!("")
            }
        ));
    }

    s.push((
        format!("Zeroed simplices"),
        thousand_split(reg.zeroed),
        format!("")
    ));
    for (d, &r) in reg.zeroed_d.iter().enumerate() {
        s.push((
            format!("\\ldots $d={}$", d),
            thousand_split(r),
            if reg.num_of_dimens[d] > 0 {
                percent(reg.num_of_dimens[d] as f64, r as f64)
            } else {
                format!("")
            }
        ));
    }

    s.push((
        format!("Stored simplices"),
        thousand_split(reg.placed_full),
        format!("")
    ));

    for (d, &r) in reg.placed_full_d.iter().enumerate() {
        s.push((
            format!("\\ldots $d={}$", d),
            thousand_split(r),
            if reg.num_of_dimens[d] > 0 {
                percent(reg.num_of_dimens[d] as f64, r as f64)
            } else {
                format!("")
            }
        ));
    }

    write!(
        writer,
        r#"
\begin{{tabular}}{{r r r r}}
  Counter & Regular & Exhausitve & Difference \\
        r#"\begin{{tabular}}{{r r r r}}
  Counter & Value & \\
  \toprule
"#
    )
    .unwrap();
    for (l, a, b, p) in v {
        write!(writer, "  {} & {} & {} & {}\\\\\n", l, a, b, p).unwrap();
    for (l, a, p) in s {
        write!(writer, "  {} & {} & {}\\\\\n", l, a, p).unwrap();
    }
    write!(writer, "\\end{{tabular}}\n").unwrap();
    writeln!(writer, "\\end{{tabular}}\n").unwrap();
}

/// Write out a dotfile with the directed edges given by `simplex_with_low`