diff --git a/Cargo.toml b/Cargo.toml
index e7539b1..cfd16ea 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -32,7 +32,7 @@ tokio-rustls = "0.24"
bellande_step = "0.1.1"
bellande_limit = "0.1.2"
bellande_node_importance = "0.1.3"
+bellande_probability = "0.1.2"
bellande_particle = "0.1.1"
-bellande_probability = "0.1.1"
# bellande_tree = "0.1.0"
# bellande_segment = "0.1.0"
diff --git a/README.md b/README.md
index 12f79d6..ee17c2e 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,8 @@
# Bellande Mesh Sync {BMS}
+## Run Bellande Mesh Sync with Bellande API
+ - Use the Bellande Mesh Sync with the Bellande API to do efficient communication
+
# Run Bellos Scripts
- build_bellande_framework.bellos
- make_rust_executable.bellos
diff --git a/src/algorithm/bellande_probability.rs b/src/algorithm/bellande_probability.rs
index 1e1074c..d44de13 100644
--- a/src/algorithm/bellande_probability.rs
+++ b/src/algorithm/bellande_probability.rs
@@ -14,4 +14,317 @@
// along with this program. If not, see .
use crate::algorithm::connections::BellandeArchError;
-// use bellande_probability::make_bellande_probability_request;
+use bellande_probability::make_bellande_probability_request;
+use futures::future::join_all;
+use serde::{Deserialize, Serialize};
+use serde_json::Value;
+
+/// Configuration for spatial probability calculations using Bellande Probability algorithm
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct SpatialProbabilityConfig {
+ pub mu_function: String,
+ pub sigma_function: String,
+ pub input_vector: Vec,
+ pub dimensions: i32,
+ pub full_auth: bool,
+ pub use_local_executable: bool,
+}
+
+/// Result of a spatial probability calculation using Bellande Probability
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct ProbabilityCalculationResult {
+ pub probability_values: Vec,
+ pub confidence_intervals: Option>>,
+ pub execution_time_ms: Option,
+ pub statistical_metrics: Option,
+}
+
+/// Extended configuration for advanced Bellande Probability calculations
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct AdvancedProbabilityConfig {
+ pub basic_config: SpatialProbabilityConfig,
+ pub distribution_parameters: Option,
+ pub confidence_level: Option,
+ pub prior_probabilities: Option>,
+}
+
+/// Main spatial probability module that leverages the Bellande Probability algorithm
+pub struct SpatialProbabilityCalculator;
+
+impl SpatialProbabilityCalculator {
+ /// Performs a spatial probability calculation using the Bellande Probability algorithm
+ pub async fn calculate(
+ config: SpatialProbabilityConfig,
+ ) -> Result {
+ // Validate input parameters
+ if config.mu_function.is_empty() || config.sigma_function.is_empty() {
+ return Err(BellandeArchError::InvalidParameters(
+ "Mu and Sigma functions cannot be empty".to_string(),
+ ));
+ }
+
+ if config.input_vector.is_empty() {
+ return Err(BellandeArchError::InvalidParameters(
+ "Input vector cannot be empty".to_string(),
+ ));
+ }
+
+ if config.dimensions <= 0 {
+ return Err(BellandeArchError::InvalidParameters(
+ "Dimensions must be a positive integer".to_string(),
+ ));
+ }
+
+ // Convert input vector to JSON Value
+ let x = serde_json::json!(config.input_vector);
+
+ // Run the Bellande Probability algorithm using the API
+ let result = if !config.use_local_executable {
+ make_bellande_probability_request(
+ config.mu_function.clone(),
+ config.sigma_function.clone(),
+ x,
+ config.dimensions,
+ config.full_auth,
+ )
+ .await
+ .map_err(|e| BellandeArchError::AlgorithmError(e.to_string()))?
+ } else {
+ return Err(BellandeArchError::AlgorithmError(
+ "Local executable functionality not implemented".to_string(),
+ ));
+ };
+
+ // Process and transform the results
+ Self::process_result(result)
+ }
+
+ /// Process the raw Bellande Probability result into our domain-specific format
+ pub fn process_result(
+ result: Value,
+ ) -> Result {
+ // Extract the probability values from the result
+ let probability_values = result
+ .get("probability_values")
+ .and_then(|p| p.as_array())
+ .ok_or_else(|| {
+ BellandeArchError::AlgorithmError(
+ "Missing probability values in algorithm result".to_string(),
+ )
+ })?
+ .iter()
+ .map(|v| {
+ v.as_f64().ok_or_else(|| {
+ BellandeArchError::AlgorithmError(
+ "Non-numeric probability value in algorithm result".to_string(),
+ )
+ })
+ })
+ .collect::, _>>()?;
+
+ // Extract confidence intervals if available
+ let confidence_intervals = result
+ .get("confidence_intervals")
+ .and_then(|ci| ci.as_array())
+ .map(|intervals| {
+ intervals
+ .iter()
+ .filter_map(|interval| {
+ interval.as_array().map(|bounds| {
+ bounds
+ .iter()
+ .filter_map(|v| v.as_f64())
+ .collect::>()
+ })
+ })
+ .collect::>>()
+ });
+
+ // Extract execution time if available
+ let execution_time_ms = result
+ .get("execution_time_ms")
+ .and_then(|t| t.as_i64())
+ .map(|t| t as i32);
+
+ // Extract statistical metrics if available
+ let statistical_metrics = result.get("statistical_metrics").cloned();
+
+ Ok(ProbabilityCalculationResult {
+ probability_values,
+ confidence_intervals,
+ execution_time_ms,
+ statistical_metrics,
+ })
+ }
+
+ /// Calculates the probability distribution for a given set of inputs
+ pub async fn calculate_distribution(
+ mu_function: String,
+ sigma_function: String,
+ inputs: Vec>,
+ dimensions: i32,
+ ) -> Result, BellandeArchError> {
+ // Validate inputs
+ if inputs.is_empty() {
+ return Err(BellandeArchError::InvalidParameters(
+ "Input vectors cannot be empty".to_string(),
+ ));
+ }
+
+ if mu_function.is_empty() || sigma_function.is_empty() {
+ return Err(BellandeArchError::InvalidParameters(
+ "Mu and Sigma functions cannot be empty".to_string(),
+ ));
+ }
+
+ // Calculate probabilities for each input vector
+ let mut probabilities = Vec::new();
+ for input_vector in inputs {
+ // Basic configuration
+ let config = SpatialProbabilityConfig {
+ mu_function: mu_function.clone(),
+ sigma_function: sigma_function.clone(),
+ input_vector,
+ dimensions,
+ full_auth: false,
+ use_local_executable: false,
+ };
+
+ // Perform calculation
+ let result = Self::calculate(config).await?;
+
+ // Add the first probability value (assuming it's the main one)
+ if !result.probability_values.is_empty() {
+ probabilities.push(result.probability_values[0]);
+ } else {
+ return Err(BellandeArchError::AlgorithmError(
+ "Empty probability values returned".to_string(),
+ ));
+ }
+ }
+
+ Ok(probabilities)
+ }
+
+ /// Batch processes multiple probability calculations in parallel
+ pub async fn batch_calculate(
+ configs: Vec,
+ ) -> Vec> {
+ // Process each configuration in parallel
+ let futures = configs.into_iter().map(|config| Self::calculate(config));
+
+ // Collect all results
+ join_all(futures).await
+ }
+
+ /// Advanced batch processing with custom parameters for each calculation
+ pub async fn advanced_batch_calculate(
+ configs: Vec,
+ ) -> Vec> {
+ let futures = configs.into_iter().map(|config| {
+ // Use basic calculation
+ Self::calculate(config.basic_config)
+ });
+
+ join_all(futures).await
+ }
+
+ /// Normalizes a set of probability values to ensure they sum to 1.0
+ pub fn normalize_probabilities(probabilities: &[f64]) -> Result, BellandeArchError> {
+ if probabilities.is_empty() {
+ return Err(BellandeArchError::InvalidParameters(
+ "Probability vector cannot be empty for normalization".to_string(),
+ ));
+ }
+
+ // Calculate sum of all probabilities
+ let sum = probabilities.iter().sum::();
+
+ // Check if sum is close to zero to avoid division by zero
+ if sum.abs() < 1e-10 {
+ return Err(BellandeArchError::AlgorithmError(
+ "Cannot normalize probabilities with sum close to zero".to_string(),
+ ));
+ }
+
+ // Normalize each probability by dividing by the sum
+ let normalized = probabilities.iter().map(|&p| p / sum).collect();
+
+ Ok(normalized)
+ }
+
+ /// Calculates the weighted average of vectors using probability weights
+ pub fn calculate_weighted_average(
+ vectors: &[Vec],
+ probabilities: &[f64],
+ ) -> Result, BellandeArchError> {
+ if vectors.is_empty() || probabilities.is_empty() {
+ return Err(BellandeArchError::InvalidParameters(
+ "Vectors and probabilities cannot be empty for weighted average".to_string(),
+ ));
+ }
+
+ if vectors.len() != probabilities.len() {
+ return Err(BellandeArchError::DimensionMismatch(format!(
+ "Mismatch between number of vectors ({}) and probabilities ({})",
+ vectors.len(),
+ probabilities.len()
+ )));
+ }
+
+ // Ensure all vectors have the same dimension
+ let dimension = vectors[0].len();
+ for (i, vector) in vectors.iter().enumerate() {
+ if vector.len() != dimension {
+ return Err(BellandeArchError::DimensionMismatch(format!(
+ "Vector at index {} has dimension {} but expected {}",
+ i,
+ vector.len(),
+ dimension
+ )));
+ }
+ }
+
+ // Calculate the weighted average for each dimension
+ let mut weighted_average = vec![0.0; dimension];
+ let prob_sum = probabilities.iter().sum::();
+
+ if prob_sum.abs() < 1e-10 {
+ return Err(BellandeArchError::AlgorithmError(
+ "Sum of probabilities is too close to zero".to_string(),
+ ));
+ }
+
+ for d in 0..dimension {
+ for (i, vector) in vectors.iter().enumerate() {
+ weighted_average[d] += vector[d] * probabilities[i] / prob_sum;
+ }
+ }
+
+ Ok(weighted_average)
+ }
+}
+
+/// Converts a probability value to a log-likelihood for numerical stability
+pub fn probability_to_log_likelihood(probability: f64) -> Result {
+ if probability <= 0.0 || probability > 1.0 {
+ return Err(BellandeArchError::InvalidParameters(format!(
+ "Invalid probability value: {}",
+ probability
+ )));
+ }
+
+ Ok(probability.ln())
+}
+
+/// Converts a log-likelihood back to a probability value
+pub fn log_likelihood_to_probability(log_likelihood: f64) -> Result {
+ if log_likelihood > 0.0 {
+ return Err(BellandeArchError::InvalidParameters(format!(
+ "Invalid log likelihood value: {}",
+ log_likelihood
+ )));
+ }
+
+ Ok(log_likelihood.exp())
+}
diff --git a/src/algorithm/connections.rs b/src/algorithm/connections.rs
index 97e7c1e..c075ae2 100644
--- a/src/algorithm/connections.rs
+++ b/src/algorithm/connections.rs
@@ -19,6 +19,7 @@ use std::fmt;
#[derive(Debug)]
pub enum BellandeArchError {
DimensionMismatch(String),
+ InvalidParameters(String),
InvalidCoordinates(String),
AlgorithmError(String),
NetworkError(String),
@@ -28,6 +29,7 @@ impl fmt::Display for BellandeArchError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
BellandeArchError::DimensionMismatch(msg) => write!(f, "Dimension mismatch: {}", msg),
+ BellandeArchError::InvalidParameters(msg) => write!(f, "Invalid parameters: {}", msg),
BellandeArchError::InvalidCoordinates(msg) => write!(f, "Invalid coordinates: {}", msg),
BellandeArchError::AlgorithmError(msg) => write!(f, "Algorithm error: {}", msg),
BellandeArchError::NetworkError(msg) => write!(f, "Network error: {}", msg),