holos-tda 0.9.0

Vietoris-Rips persistence and checked degree-Rips modules
Documentation
//! Cohomology intervention and topological synthesis workflows.

use std::path::Path;

use crate::io;
use crate::{
    CohomologyInterventionArtifact, CohomologyInterventionCandidate, CohomologyInterventionLimits,
    CohomologyInterventionScenario, CohomologyLimits, KineticFiltration, KineticLimits,
    SparseDistanceMatrix, SynthesisAction, SynthesisArtifact, SynthesisLimits, SynthesisState,
    TopologicalSpecification, cohomology_space,
};

use super::args::{CohomologyInterventionCli, KineticSynthesisCli, LinkPlanCli, SynthesisCli};
use super::input::{read_kinetic_edges, read_proof_input, write_via_temporary};

pub(super) fn run_cohomology_intervention(cli: CohomologyInterventionCli) -> crate::Result<()> {
    let graph = read_proof_input(&cli.input, cli.format, cli.threads, Some(cli.scale))?;
    let candidates = parse_weighted_candidates(&cli.candidates)?;
    let limits = CohomologyInterventionLimits {
        max_oracle_calls: cli.oracle_limit,
        max_search_nodes: cli.node_limit,
        ..CohomologyInterventionLimits::default()
    };
    let scenario = CohomologyInterventionScenario::from_graph(&graph, cli.scale, cli.target)?;
    let artifact = CohomologyInterventionArtifact::build(
        graph.len(),
        cli.dimension,
        cli.scale,
        cli.modulus,
        &[scenario],
        &candidates,
        cli.max_edits,
        limits,
    )?;
    let bytes = artifact.encode(limits)?;
    write_via_temporary(&cli.output, &bytes)?;
    println!(
        "certified H{} intervention: {}, {} edits, {} oracle calls, cost bounds {:?} to {:?}, wrote {} bytes",
        cli.dimension,
        artifact.status(),
        artifact.edits().len(),
        artifact.oracle_calls(),
        artifact.lower_bound_cost(),
        artifact.upper_bound_cost(),
        bytes.len()
    );
    Ok(())
}

pub(super) fn run_link_plan(cli: LinkPlanCli) -> crate::Result<()> {
    if cli.scenarios.len() != cli.targets.len() {
        return Err(crate::Error::InvalidInput(
            "--scenario and --target counts must match".into(),
        ));
    }
    let scenarios = cli
        .scenarios
        .iter()
        .zip(&cli.targets)
        .map(|(path, target)| {
            let parsed = io::read_sparse_matrix(path, cli.threads)?;
            if parsed.len() > cli.vertices {
                return Err(crate::Error::InvalidInput(format!(
                    "scenario {} uses a vertex above --vertices {}",
                    path.display(),
                    cli.vertices
                )));
            }
            let triplets = parsed.edges().collect::<Vec<_>>();
            let graph = SparseDistanceMatrix::from_triplets(cli.vertices, &triplets)?;
            CohomologyInterventionScenario::from_graph(&graph, cli.scale, *target)
        })
        .collect::<crate::Result<Vec<_>>>()?;
    let candidates = parse_weighted_candidates(&cli.candidates)?;
    let limits = CohomologyInterventionLimits {
        max_oracle_calls: cli.oracle_limit,
        max_search_nodes: cli.node_limit,
        ..CohomologyInterventionLimits::default()
    };
    let artifact = CohomologyInterventionArtifact::build(
        cli.vertices,
        cli.dimension,
        cli.scale,
        cli.modulus,
        &scenarios,
        &candidates,
        cli.max_edits,
        limits,
    )?;
    let bytes = artifact.encode(limits)?;
    write_via_temporary(&cli.output, &bytes)?;
    println!(
        "certified H{} link plan across {} scenarios: {}, {} links, cost bounds {:?} to {:?}, {} oracle calls, wrote {} bytes",
        cli.dimension,
        scenarios.len(),
        artifact.status(),
        artifact.edits().len(),
        artifact.lower_bound_cost(),
        artifact.upper_bound_cost(),
        artifact.oracle_calls(),
        bytes.len(),
    );
    Ok(())
}

pub(super) fn run_synthesis(cli: SynthesisCli) -> crate::Result<()> {
    let declared_states = cli.states.len();
    let states = synthesis_states(&cli)?;
    let specification =
        TopologicalSpecification::new(cli.vertices, cli.dimension, cli.scale, cli.modulus, states);
    let actions = parse_synthesis_actions(&cli.candidates, &specification)?;
    let limits = SynthesisLimits {
        max_oracle_calls: cli.oracle_limit,
        max_search_nodes: cli.node_limit,
        ..SynthesisLimits::default()
    };
    let artifact = SynthesisArtifact::build(specification, actions, cli.max_edits, limits)?;
    let bytes = artifact.encode(limits)?;
    write_via_temporary(&cli.output, &bytes)?;
    println!(
        "certified H{} synthesis across {} of {} constrained states: {}, {} actions, cost bounds {:?} to {:?}, {} producer topology calls, {} proof topology checks, wrote {} bytes",
        cli.dimension,
        artifact.specification().states().len(),
        declared_states,
        artifact.status(),
        artifact.selected().len(),
        artifact.lower_bound_cost(),
        artifact.upper_bound_cost(),
        artifact.producer_oracle_calls(),
        artifact.proof_topology_checks(),
        bytes.len(),
    );
    Ok(())
}

pub(super) fn synthesis_states(cli: &SynthesisCli) -> crate::Result<Vec<SynthesisState>> {
    let mut states = Vec::new();
    for (step, path) in cli.states.iter().enumerate() {
        let graph = read_synthesis_state(path, cli.vertices, cli.threads)?;
        let space = cohomology_space(
            &graph,
            cli.dimension,
            cli.scale,
            cli.modulus,
            CohomologyLimits::default(),
        )?;
        if space.rank() <= cli.max_rank {
            continue;
        }
        let target = space.full_subspace();
        states.push(SynthesisState::from_subspace(
            0,
            step as u64,
            &graph,
            cli.scale,
            &space,
            &target,
            cli.max_rank,
        )?);
    }
    Ok(states)
}

pub(super) fn read_synthesis_state(
    path: &Path,
    vertices: usize,
    threads: usize,
) -> crate::Result<SparseDistanceMatrix> {
    let parsed = io::read_sparse_matrix(path, threads)?;
    if parsed.len() > vertices {
        return Err(crate::Error::InvalidInput(format!(
            "state {} uses a vertex above --vertices {vertices}",
            path.display()
        )));
    }
    SparseDistanceMatrix::from_triplets(vertices, &parsed.edges().collect::<Vec<_>>())
}

pub(super) fn run_kinetic_synthesis(cli: KineticSynthesisCli) -> crate::Result<()> {
    let edges = read_kinetic_edges(&cli.input, cli.max_artifact_bytes)?;
    let trajectory = KineticFiltration::new(
        cli.vertices,
        edges,
        cli.start,
        cli.end,
        KineticLimits::default(),
    )?;
    let specification = TopologicalSpecification::from_kinetic_rank_ceiling(
        &trajectory,
        0,
        cli.dimension,
        cli.scale,
        cli.modulus,
        cli.max_rank,
        CohomologyLimits::default(),
    )?;
    let actions = parse_synthesis_actions(&cli.candidates, &specification)?;
    let limits = SynthesisLimits {
        max_bytes: cli.max_artifact_bytes,
        max_oracle_calls: cli.oracle_limit,
        max_search_nodes: cli.node_limit,
        ..SynthesisLimits::default()
    };
    let artifact = SynthesisArtifact::build(specification, actions, cli.max_edits, limits)?;
    let bytes = artifact.encode(limits)?;
    write_via_temporary(&cli.output, &bytes)?;
    println!(
        "certified H{} all-time Rips rank plan across {} constrained critical states: {}, {} actions, cost bounds {:?} to {:?}, {} producer topology calls, {} proof topology checks, wrote {} bytes",
        cli.dimension,
        artifact.specification().states().len(),
        artifact.status(),
        artifact.selected().len(),
        artifact.lower_bound_cost(),
        artifact.upper_bound_cost(),
        artifact.producer_oracle_calls(),
        artifact.proof_topology_checks(),
        bytes.len(),
    );
    Ok(())
}

pub(super) fn parse_synthesis_actions(
    values: &[usize],
    specification: &TopologicalSpecification,
) -> crate::Result<Vec<SynthesisAction>> {
    if specification.states().is_empty() {
        return Ok(Vec::new());
    }
    let mut actions = values
        .chunks_exact(3)
        .map(|candidate| {
            SynthesisAction::throughout(
                candidate[0],
                candidate[1],
                candidate[2] as u64,
                specification,
            )
        })
        .collect::<Vec<_>>();
    actions.sort();
    let original_count = actions.len();
    actions.dedup_by_key(|action| action.edge);
    if actions.len() != original_count {
        return Err(crate::Error::InvalidInput(
            "--candidate repeats an edge".into(),
        ));
    }
    Ok(actions)
}

pub(super) fn parse_weighted_candidates(
    values: &[usize],
) -> crate::Result<Vec<CohomologyInterventionCandidate>> {
    let mut candidates = values
        .chunks_exact(3)
        .map(|candidate| {
            CohomologyInterventionCandidate::new(candidate[0], candidate[1], candidate[2] as u64)
        })
        .collect::<Vec<_>>();
    candidates.sort_by_key(|candidate| candidate.edge);
    let original_count = candidates.len();
    candidates.dedup_by_key(|candidate| candidate.edge);
    if candidates.len() != original_count {
        return Err(crate::Error::InvalidInput(
            "--candidate repeats an edge".into(),
        ));
    }
    Ok(candidates)
}