holos-tda 0.9.0

Vietoris-Rips persistence and checked degree-Rips modules
Documentation
use super::super::{
    CollapseCertificate, CollapseCompleteness, CollapseObjective, RemovalStep, SchedulePosition,
};
use super::model::{ArtifactError, CollapseArtifact};
use super::primitives::{put_optional_f64, put_optional_u64, put_u16, put_u32, put_u64, put_usize};
use super::{F64_BITS_CODEC, MAGIC, WIRE_VERSION};

pub(super) fn encode_header(
    out: &mut Vec<u8>,
    artifact: &CollapseArtifact,
    output_count: usize,
) -> Result<(), ArtifactError> {
    encode_prefix(out);
    encode_metadata_prefix(out, &artifact.certificate);
    encode_graph_counts(out, &artifact.certificate)?;
    put_optional_u64(out, artifact.certificate.work_limit());
    put_u64(out, artifact.certificate.work_used());
    out.extend_from_slice(&artifact.input_digest);
    out.extend_from_slice(&artifact.output_digest);
    put_usize(out, artifact.certificate.steps().len(), "step count")?;
    put_usize(out, output_count, "output edge count")
}

fn encode_prefix(out: &mut Vec<u8>) {
    out.extend_from_slice(MAGIC);
    put_u16(out, WIRE_VERSION);
    out.push(F64_BITS_CODEC);
}

fn encode_metadata_prefix(out: &mut Vec<u8>, certificate: &CollapseCertificate) {
    put_u32(out, certificate.algorithm_version());
    out.push(objective_tag(certificate.objective()));
    out.push(completeness_tag(certificate.completeness()));
    put_optional_f64(out, certificate.requested_threshold());
    put_u64(out, certificate.terminal_level().to_bits());
}

fn objective_tag(objective: Option<CollapseObjective>) -> u8 {
    match objective {
        None => 0,
        Some(CollapseObjective::H1) => 1,
        Some(CollapseObjective::H2) => 2,
    }
}

fn completeness_tag(completeness: CollapseCompleteness) -> u8 {
    match completeness {
        CollapseCompleteness::CompleteFixedPoint => 0,
        CollapseCompleteness::BudgetLimited => 1,
    }
}

fn encode_graph_counts(
    out: &mut Vec<u8>,
    certificate: &CollapseCertificate,
) -> Result<(), ArtifactError> {
    put_usize(out, certificate.vertex_count(), "vertex count")?;
    put_usize(out, certificate.input_edge_count(), "input edge count")?;
    put_usize(out, certificate.output_edge_count(), "output edge count")
}

pub(super) fn encode_output_edges(
    out: &mut Vec<u8>,
    edges: &[(usize, usize, f64)],
) -> Result<(), ArtifactError> {
    for &(u, v, value) in edges {
        put_usize(out, u, "edge endpoint")?;
        put_usize(out, v, "edge endpoint")?;
        put_u64(out, value.to_bits());
    }
    Ok(())
}

pub(super) fn encode_steps(out: &mut Vec<u8>, steps: &[RemovalStep]) -> Result<(), ArtifactError> {
    for step in steps {
        encode_step(out, step)?;
    }
    Ok(())
}

fn encode_step(out: &mut Vec<u8>, step: &RemovalStep) -> Result<(), ArtifactError> {
    let (u, v) = step.edge();
    put_usize(out, u, "step endpoint")?;
    put_usize(out, v, "step endpoint")?;
    put_u64(out, step.value().to_bits());
    let (kind, number) = encode_schedule_position(step.position());
    out.push(kind);
    put_usize(out, number, "schedule position")?;
    encode_witnesses(out, step.witnesses())
}

fn encode_schedule_position(position: SchedulePosition) -> (u8, usize) {
    match position {
        SchedulePosition::Pass(number) => (1, number),
        SchedulePosition::Round(number) => (2, number),
        SchedulePosition::Sequence(number) => (3, number),
    }
}

fn encode_witnesses(out: &mut Vec<u8>, witnesses: &[(f64, usize)]) -> Result<(), ArtifactError> {
    put_usize(out, witnesses.len(), "witness count")?;
    for &(start, apex) in witnesses {
        put_u64(out, start.to_bits());
        put_usize(out, apex, "witness apex")?;
    }
    Ok(())
}