use std::collections::BTreeSet;
use num_rational::BigRational;
use crate::field::{MODULUS_LIMIT, is_prime};
use crate::{Error, KineticEdgeKey, Result};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub struct CoverageLimits {
pub max_vertices: usize,
pub max_edges: usize,
pub max_triangles: usize,
pub max_matrix_entries: usize,
pub max_states: usize,
pub max_actions: usize,
pub max_failure_sets: usize,
}
impl Default for CoverageLimits {
fn default() -> Self {
Self {
max_vertices: 1_000_000,
max_edges: 20_000_000,
max_triangles: 1_000_000,
max_matrix_entries: 100_000_000,
max_states: 4_096,
max_actions: 65_536,
max_failure_sets: 10_000_000,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct PlanarCoverageModel {
broadcast_radius: f64,
sensing_radius: f64,
}
impl PlanarCoverageModel {
pub fn new(broadcast_radius: f64, sensing_radius: f64) -> Result<Self> {
if !broadcast_radius.is_finite()
|| !sensing_radius.is_finite()
|| broadcast_radius <= 0.0
|| sensing_radius <= 0.0
{
return Err(Error::InvalidInput(
"coverage radii must be finite and positive".into(),
));
}
let broadcast = rational(broadcast_radius);
let sensing = rational(sensing_radius);
if BigRational::from_integer(3.into()) * &sensing * sensing < broadcast.clone() * broadcast
{
return Err(Error::InvalidInput(
"coverage radii violate 3 * sensing_radius^2 >= broadcast_radius^2".into(),
));
}
Ok(Self {
broadcast_radius,
sensing_radius,
})
}
pub fn broadcast_radius(self) -> f64 {
self.broadcast_radius
}
pub fn sensing_radius(self) -> f64 {
self.sensing_radius
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CoverageFence {
vertices: Vec<usize>,
}
impl CoverageFence {
pub fn new(vertices: Vec<usize>) -> Result<Self> {
if vertices.len() < 3 {
return Err(Error::InvalidInput(
"coverage fence requires at least three vertices".into(),
));
}
if vertices.iter().copied().collect::<BTreeSet<_>>().len() != vertices.len() {
return Err(Error::InvalidInput(
"coverage fence repeats a vertex".into(),
));
}
let forward = rotate_to_minimum(&vertices);
let mut reversed = vertices;
reversed.reverse();
let reversed = rotate_to_minimum(&reversed);
Ok(Self {
vertices: forward.min(reversed),
})
}
pub fn vertices(&self) -> &[usize] {
&self.vertices
}
pub(crate) fn edges(&self) -> Vec<KineticEdgeKey> {
cycle_pairs(&self.vertices)
.map(|(u, v)| KineticEdgeKey::new(u, v))
.collect()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct CoverageTriangleTerm {
pub a: usize,
pub b: usize,
pub c: usize,
pub coefficient: u32,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CoverageEvaluation {
pub criterion_holds: bool,
pub witness: Vec<CoverageTriangleTerm>,
pub active_vertices: usize,
pub active_edges: usize,
pub active_triangles: usize,
}
pub(crate) fn cycle_pairs(vertices: &[usize]) -> impl Iterator<Item = (usize, usize)> + '_ {
vertices
.iter()
.copied()
.zip(vertices.iter().copied().cycle().skip(1))
.take(vertices.len())
}
fn rotate_to_minimum(values: &[usize]) -> Vec<usize> {
let position = values
.iter()
.enumerate()
.min_by_key(|(_, value)| **value)
.map(|(position, _)| position)
.unwrap_or(0);
values[position..]
.iter()
.chain(&values[..position])
.copied()
.collect()
}
pub(crate) fn validate_field(modulus: u32) -> Result<()> {
if u64::from(modulus) >= MODULUS_LIMIT || !is_prime(u64::from(modulus)) {
return Err(Error::InvalidInput(
"coverage modulus must be a supported prime".into(),
));
}
Ok(())
}
fn rational(value: f64) -> BigRational {
BigRational::from_float(value).expect("validated finite f64 has an exact rational form")
}