use crate::{Community, GeometricNetwork, NetworkError, NodeMetadata, PropagationAnalysis};
use amari_core::Multivector;
use std::marker::PhantomData;
#[cfg(feature = "formal-verification")]
use creusot_contracts::macros::{ensures, requires};
pub struct NetworkSignature<const P: usize, const Q: usize, const R: usize>;
pub struct NetworkProperty<const PROPERTY: usize>;
pub const CONNECTED: usize = 1;
pub const DISCONNECTED: usize = 2;
pub const WEAKLY_CONNECTED: usize = 3;
pub const DIRECTED: usize = 10;
pub const UNDIRECTED: usize = 11;
pub const MIXED: usize = 12;
#[derive(Debug, Clone)]
pub struct VerifiedGeometricNetwork<
const P: usize,
const Q: usize,
const R: usize,
const CONNECTIVITY: usize = DISCONNECTED,
const NETWORK_TYPE: usize = DIRECTED,
> {
pub(crate) inner: GeometricNetwork<P, Q, R>,
_signature: PhantomData<NetworkSignature<P, Q, R>>,
_properties: PhantomData<(NetworkProperty<CONNECTIVITY>, NetworkProperty<NETWORK_TYPE>)>,
}
impl<
const P: usize,
const Q: usize,
const R: usize,
const CONNECTIVITY: usize,
const NETWORK_TYPE: usize,
> VerifiedGeometricNetwork<P, Q, R, CONNECTIVITY, NETWORK_TYPE>
{
pub const DIM: usize = P + Q + R;
#[cfg_attr(feature = "formal-verification",
ensures(result.num_nodes() == 0),
ensures(result.num_edges() == 0))]
pub fn new() -> Self {
Self {
inner: GeometricNetwork::new(),
_signature: PhantomData,
_properties: PhantomData,
}
}
#[cfg_attr(feature = "formal-verification",
ensures(result.num_nodes() == old(self.num_nodes()) + 1))]
pub fn add_node(&mut self, position: Multivector<P, Q, R>) -> usize {
self.inner.add_node(position)
}
#[cfg_attr(feature = "formal-verification",
ensures(result.num_nodes() == old(self.num_nodes()) + 1))]
pub fn add_node_with_metadata(
&mut self,
position: Multivector<P, Q, R>,
metadata: NodeMetadata,
) -> usize {
self.inner.add_node_with_metadata(position, metadata)
}
#[cfg_attr(feature = "formal-verification",
requires(source < self.num_nodes()),
requires(target < self.num_nodes()),
requires(weight >= 0.0))]
pub fn add_edge(
&mut self,
source: usize,
target: usize,
weight: f64,
) -> Result<(), NetworkError> {
self.inner.add_edge(source, target, weight)
}
#[cfg_attr(feature = "formal-verification",
requires(source < self.num_nodes()),
requires(target < self.num_nodes()),
requires(weight >= 0.0))]
pub fn add_undirected_edge(
&mut self,
source: usize,
target: usize,
weight: f64,
) -> Result<(), NetworkError> {
self.inner.add_undirected_edge(source, target, weight)
}
#[cfg_attr(feature = "formal-verification",
ensures(result >= 0))]
pub fn num_nodes(&self) -> usize {
self.inner.num_nodes()
}
#[cfg_attr(feature = "formal-verification",
ensures(result >= 0))]
pub fn num_edges(&self) -> usize {
self.inner.num_edges()
}
#[cfg_attr(feature = "formal-verification",
requires(i < self.num_nodes()),
requires(j < self.num_nodes()),
ensures(result >= 0.0),
ensures(i == j ==> result == 0.0))]
pub fn geometric_distance(&self, i: usize, j: usize) -> Result<f64, NetworkError> {
self.inner.geometric_distance(i, j)
}
#[cfg_attr(feature = "formal-verification",
ensures(result.len() == self.num_nodes()),
ensures(forall(|i: usize| i < result.len() ==> result[i] >= 0.0)))]
pub fn compute_geometric_centrality(&self) -> Result<Vec<f64>, NetworkError> {
self.inner.compute_geometric_centrality()
}
#[cfg_attr(feature = "formal-verification",
requires(num_clusters > 0),
requires(num_clusters <= self.num_nodes()),
ensures(result.len() <= num_clusters))]
pub fn find_communities(
&self,
num_clusters: usize,
) -> Result<Vec<Community<P, Q, R>>, NetworkError> {
self.inner.find_communities(num_clusters)
}
#[cfg_attr(feature = "formal-verification",
requires(time_steps > 0),
requires(decay_factor > 0.0 && decay_factor < 1.0),
requires(forall(|i: usize| i < sources.len() ==> sources[i] < self.num_nodes())))]
pub fn simulate_diffusion(
&self,
sources: &[usize],
time_steps: usize,
decay_factor: f64,
) -> Result<PropagationAnalysis, NetworkError> {
self.inner
.simulate_diffusion(sources, time_steps, decay_factor)
}
#[cfg_attr(feature = "formal-verification",
ensures(result.size() == self.num_nodes()))]
pub fn to_tropical_network(&self) -> Result<crate::tropical::TropicalNetwork, NetworkError> {
self.inner.to_tropical_network()
}
#[cfg_attr(feature = "formal-verification",
requires(index < self.num_nodes()))]
pub fn get_metadata(&self, index: usize) -> Option<&NodeMetadata> {
self.inner.get_metadata(index)
}
#[cfg_attr(feature = "formal-verification",
requires(node < self.num_nodes()))]
pub fn neighbors(&self, node: usize) -> Vec<usize> {
self.inner.neighbors(node)
}
#[cfg_attr(feature = "formal-verification",
requires(node < self.num_nodes()),
ensures(result >= 0))]
pub fn degree(&self, node: usize) -> usize {
self.inner.degree(node)
}
}
impl<const P: usize, const Q: usize, const R: usize> From<GeometricNetwork<P, Q, R>>
for VerifiedGeometricNetwork<P, Q, R>
{
fn from(network: GeometricNetwork<P, Q, R>) -> Self {
Self {
inner: network,
_signature: PhantomData,
_properties: PhantomData,
}
}
}
impl<
const P: usize,
const Q: usize,
const R: usize,
const CONNECTIVITY: usize,
const NETWORK_TYPE: usize,
> From<VerifiedGeometricNetwork<P, Q, R, CONNECTIVITY, NETWORK_TYPE>>
for GeometricNetwork<P, Q, R>
{
fn from(verified: VerifiedGeometricNetwork<P, Q, R, CONNECTIVITY, NETWORK_TYPE>) -> Self {
verified.inner
}
}
impl<const P: usize, const Q: usize, const R: usize> Default for VerifiedGeometricNetwork<P, Q, R> {
fn default() -> Self {
Self::new()
}
}