use std::fmt;
use crate::{CohomologyLimits, Error, KineticEdgeKey, Result, SparseDistanceMatrix};
pub(super) const FORMAT_MAX_SCENARIOS: usize = 256;
pub(super) const FORMAT_MAX_CANDIDATES: usize = 4_096;
pub(super) const FORMAT_MAX_PROOF_TERMS: usize = 1_000_000;
pub(super) const FORMAT_MAX_ORACLE_CALLS: usize = 10_000_000;
pub(super) const FORMAT_MAX_SEARCH_NODES: usize = 10_000_000;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub struct CohomologyInterventionLimits {
pub max_bytes: usize,
pub max_vertices: usize,
pub max_edges_per_scenario: usize,
pub max_scenarios: usize,
pub max_candidates: usize,
pub max_proof_terms: usize,
pub max_oracle_calls: usize,
pub max_search_nodes: usize,
pub cohomology: CohomologyLimits,
}
impl Default for CohomologyInterventionLimits {
fn default() -> Self {
Self {
max_bytes: 1 << 30,
max_vertices: 1_000_000,
max_edges_per_scenario: 20_000_000,
max_scenarios: 64,
max_candidates: 4_096,
max_proof_terms: 1_000_000,
max_oracle_calls: 1_000_000,
max_search_nodes: 1_000_000,
cohomology: CohomologyLimits::default(),
}
}
}
impl CohomologyInterventionLimits {
#[must_use]
pub fn with_max_oracle_calls(mut self, max_oracle_calls: usize) -> Self {
self.max_oracle_calls = max_oracle_calls;
self
}
#[must_use]
pub fn with_max_search_nodes(mut self, max_search_nodes: usize) -> Self {
self.max_search_nodes = max_search_nodes;
self
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CohomologyInterventionScenario {
pub(super) active_edges: Vec<KineticEdgeKey>,
pub(super) target_basis: usize,
}
impl CohomologyInterventionScenario {
pub fn from_graph(
graph: &SparseDistanceMatrix,
scale: f64,
target_basis: usize,
) -> Result<Self> {
if !scale.is_finite() || scale < 0.0 {
return Err(Error::InvalidInput(
"cohomology intervention scale must be finite and non-negative".into(),
));
}
Ok(Self {
active_edges: graph
.edges()
.filter(|edge| edge.2 <= scale)
.map(|(u, v, _)| KineticEdgeKey { u, v })
.collect(),
target_basis,
})
}
pub fn active_edges(&self) -> &[KineticEdgeKey] {
&self.active_edges
}
pub fn target_basis(&self) -> usize {
self.target_basis
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct CohomologyInterventionCandidate {
pub edge: KineticEdgeKey,
pub cost: u64,
}
impl CohomologyInterventionCandidate {
pub fn new(u: usize, v: usize, cost: u64) -> Self {
Self {
edge: KineticEdgeKey::new(u, v),
cost,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CohomologyInterventionStatus {
Optimal,
Infeasible,
SearchIncomplete,
}
impl CohomologyInterventionStatus {
pub(super) fn code(self) -> u8 {
match self {
Self::Optimal => 1,
Self::Infeasible => 2,
Self::SearchIncomplete => 3,
}
}
pub(super) fn from_code(code: u8) -> Result<Self> {
match code {
1 => Ok(Self::Optimal),
2 => Ok(Self::Infeasible),
3 => Ok(Self::SearchIncomplete),
_ => Err(Error::InvalidInput(
"cohomology intervention status is invalid".into(),
)),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct CohomologyInterventionArtifact {
pub(super) vertex_count: usize,
pub(super) dimension: usize,
pub(super) scale: f64,
pub(super) modulus: u32,
pub(super) scenarios: Vec<CohomologyInterventionScenario>,
pub(super) candidates: Vec<CohomologyInterventionCandidate>,
pub(super) max_edits: usize,
pub(super) oracle_limit: usize,
pub(super) node_limit: usize,
pub(super) status: CohomologyInterventionStatus,
pub(super) edits: Vec<CohomologyInterventionCandidate>,
pub(super) lower_bound_cost: Option<u64>,
pub(super) upper_bound_cost: Option<u64>,
pub(super) oracle_calls: usize,
pub(super) search_nodes: usize,
pub(super) cache_hits: usize,
pub(super) root_blockers: Vec<Vec<usize>>,
pub(super) root_blocker_bound: u64,
pub(super) before_ranks: Vec<usize>,
pub(super) after_ranks: Vec<usize>,
pub(super) digest: [u8; 32],
}
pub(super) struct InterventionHeader {
pub(super) vertex_count: usize,
pub(super) dimension: usize,
pub(super) scale: f64,
pub(super) modulus: u32,
}
pub(super) struct InterventionSearchData {
pub(super) max_edits: usize,
pub(super) oracle_limit: usize,
pub(super) node_limit: usize,
pub(super) status: CohomologyInterventionStatus,
pub(super) edit_indices: Vec<usize>,
pub(super) lower_bound_cost: Option<u64>,
pub(super) upper_bound_cost: Option<u64>,
pub(super) oracle_calls: usize,
pub(super) search_nodes: usize,
pub(super) cache_hits: usize,
}
pub(super) struct InterventionWorkLimits {
pub(super) oracle: usize,
pub(super) nodes: usize,
}
pub(super) struct InterventionSelection {
pub(super) status: CohomologyInterventionStatus,
pub(super) edit_indices: Vec<usize>,
pub(super) lower_bound_cost: Option<u64>,
pub(super) upper_bound_cost: Option<u64>,
}
pub(super) struct InterventionProducerWork {
pub(super) oracle_calls: usize,
pub(super) search_nodes: usize,
pub(super) cache_hits: usize,
}
pub(super) struct InterventionProofData {
pub(super) root_blockers: Vec<Vec<usize>>,
pub(super) root_blocker_bound: u64,
pub(super) before_ranks: Vec<usize>,
pub(super) after_ranks: Vec<usize>,
}
impl fmt::Display for CohomologyInterventionStatus {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(match self {
Self::Optimal => "optimal",
Self::Infeasible => "infeasible",
Self::SearchIncomplete => "search incomplete",
})
}
}