This commit is contained in:
2025-04-30 13:11:11 -04:00
parent fdb65cdbcc
commit b9c84bee83
4 changed files with 320 additions and 2 deletions

View File

@@ -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"

View File

@@ -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

View File

@@ -14,4 +14,317 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
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<f64>,
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<f64>,
pub confidence_intervals: Option<Vec<Vec<f64>>>,
pub execution_time_ms: Option<i32>,
pub statistical_metrics: Option<Value>,
}
/// Extended configuration for advanced Bellande Probability calculations
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AdvancedProbabilityConfig {
pub basic_config: SpatialProbabilityConfig,
pub distribution_parameters: Option<Value>,
pub confidence_level: Option<f64>,
pub prior_probabilities: Option<Vec<f64>>,
}
/// 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<ProbabilityCalculationResult, BellandeArchError> {
// 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<ProbabilityCalculationResult, BellandeArchError> {
// 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::<Result<Vec<f64>, _>>()?;
// 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::<Vec<f64>>()
})
})
.collect::<Vec<Vec<f64>>>()
});
// 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<Vec<f64>>,
dimensions: i32,
) -> Result<Vec<f64>, 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<SpatialProbabilityConfig>,
) -> Vec<Result<ProbabilityCalculationResult, BellandeArchError>> {
// 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<AdvancedProbabilityConfig>,
) -> Vec<Result<ProbabilityCalculationResult, BellandeArchError>> {
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<Vec<f64>, 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::<f64>();
// 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<f64>],
probabilities: &[f64],
) -> Result<Vec<f64>, 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::<f64>();
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<f64, BellandeArchError> {
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<f64, BellandeArchError> {
if log_likelihood > 0.0 {
return Err(BellandeArchError::InvalidParameters(format!(
"Invalid log likelihood value: {}",
log_likelihood
)));
}
Ok(log_likelihood.exp())
}

View File

@@ -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),