mirror of
https://github.com/flakestorm/flakestorm.git
synced 2026-07-15 22:41:02 +02:00
Add initial project structure and configuration files
- Created .gitignore to exclude unnecessary files and directories. - Added Cargo.toml for Rust workspace configuration. - Introduced example configuration file entropix.yaml.example for user customization. - Included LICENSE file with Apache 2.0 license details. - Created pyproject.toml for Python project metadata and dependencies. - Added README.md with project overview and usage instructions. - Implemented a broken agent example to demonstrate testing capabilities. - Established Rust module structure with Cargo.toml and source files. - Set up initial tests for assertions and configuration validation.
This commit is contained in:
commit
a36cecf255
37 changed files with 5397 additions and 0 deletions
186
rust/src/lib.rs
Normal file
186
rust/src/lib.rs
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
//! Entropix Rust Performance Module
|
||||
//!
|
||||
//! This module provides high-performance implementations for:
|
||||
//! - Robustness score calculation
|
||||
//! - Parallel mutation processing
|
||||
//! - Fast string similarity scoring
|
||||
|
||||
use pyo3::prelude::*;
|
||||
use rayon::prelude::*;
|
||||
|
||||
mod parallel;
|
||||
mod scoring;
|
||||
|
||||
pub use parallel::*;
|
||||
pub use scoring::*;
|
||||
|
||||
/// Calculate the robustness score for a test run.
|
||||
///
|
||||
/// The robustness score R is calculated as:
|
||||
/// R = (W_s * S_passed + W_d * D_passed) / N_total
|
||||
///
|
||||
/// Where:
|
||||
/// - S_passed = Semantic variations passed
|
||||
/// - D_passed = Deterministic tests passed
|
||||
/// - W_s, W_d = Weights for semantic and deterministic tests
|
||||
#[pyfunction]
|
||||
fn calculate_robustness_score(
|
||||
semantic_passed: u32,
|
||||
deterministic_passed: u32,
|
||||
total: u32,
|
||||
semantic_weight: f64,
|
||||
deterministic_weight: f64,
|
||||
) -> f64 {
|
||||
if total == 0 {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
let weighted_sum = semantic_weight * semantic_passed as f64
|
||||
+ deterministic_weight * deterministic_passed as f64;
|
||||
|
||||
weighted_sum / total as f64
|
||||
}
|
||||
|
||||
/// Calculate weighted robustness score with per-mutation weights.
|
||||
///
|
||||
/// Each mutation has its own weight based on difficulty.
|
||||
/// Passing a prompt injection attack is worth more than passing a typo test.
|
||||
#[pyfunction]
|
||||
fn calculate_weighted_score(
|
||||
results: Vec<(bool, f64)>, // (passed, weight)
|
||||
) -> f64 {
|
||||
if results.is_empty() {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
let total_weight: f64 = results.iter().map(|(_, w)| w).sum();
|
||||
let passed_weight: f64 = results
|
||||
.iter()
|
||||
.filter(|(passed, _)| *passed)
|
||||
.map(|(_, w)| w)
|
||||
.sum();
|
||||
|
||||
if total_weight == 0.0 {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
passed_weight / total_weight
|
||||
}
|
||||
|
||||
/// Process mutations in parallel and return results.
|
||||
///
|
||||
/// Uses Rayon for efficient parallel processing.
|
||||
#[pyfunction]
|
||||
fn parallel_process_mutations(
|
||||
mutations: Vec<String>,
|
||||
mutation_types: Vec<String>,
|
||||
weights: Vec<f64>,
|
||||
) -> Vec<(String, String, f64)> {
|
||||
mutations
|
||||
.into_par_iter()
|
||||
.enumerate()
|
||||
.map(|(i, mutation)| {
|
||||
let mutation_type = mutation_types.get(i % mutation_types.len())
|
||||
.cloned()
|
||||
.unwrap_or_else(|| "unknown".to_string());
|
||||
let weight = weights.get(i % weights.len())
|
||||
.copied()
|
||||
.unwrap_or(1.0);
|
||||
(mutation, mutation_type, weight)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Fast Levenshtein distance calculation for noise mutation validation.
|
||||
#[pyfunction]
|
||||
fn levenshtein_distance(s1: &str, s2: &str) -> usize {
|
||||
let len1 = s1.chars().count();
|
||||
let len2 = s2.chars().count();
|
||||
|
||||
if len1 == 0 {
|
||||
return len2;
|
||||
}
|
||||
if len2 == 0 {
|
||||
return len1;
|
||||
}
|
||||
|
||||
let s1_chars: Vec<char> = s1.chars().collect();
|
||||
let s2_chars: Vec<char> = s2.chars().collect();
|
||||
|
||||
let mut prev_row: Vec<usize> = (0..=len2).collect();
|
||||
let mut curr_row: Vec<usize> = vec![0; len2 + 1];
|
||||
|
||||
for i in 1..=len1 {
|
||||
curr_row[0] = i;
|
||||
for j in 1..=len2 {
|
||||
let cost = if s1_chars[i - 1] == s2_chars[j - 1] { 0 } else { 1 };
|
||||
curr_row[j] = std::cmp::min(
|
||||
std::cmp::min(prev_row[j] + 1, curr_row[j - 1] + 1),
|
||||
prev_row[j - 1] + cost,
|
||||
);
|
||||
}
|
||||
std::mem::swap(&mut prev_row, &mut curr_row);
|
||||
}
|
||||
|
||||
prev_row[len2]
|
||||
}
|
||||
|
||||
/// Calculate similarity ratio between two strings (0.0 to 1.0).
|
||||
#[pyfunction]
|
||||
fn string_similarity(s1: &str, s2: &str) -> f64 {
|
||||
let distance = levenshtein_distance(s1, s2);
|
||||
let max_len = std::cmp::max(s1.chars().count(), s2.chars().count());
|
||||
|
||||
if max_len == 0 {
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
1.0 - (distance as f64 / max_len as f64)
|
||||
}
|
||||
|
||||
/// Python module definition
|
||||
#[pymodule]
|
||||
fn entropix_rust(_py: Python, m: &PyModule) -> PyResult<()> {
|
||||
m.add_function(wrap_pyfunction!(calculate_robustness_score, m)?)?;
|
||||
m.add_function(wrap_pyfunction!(calculate_weighted_score, m)?)?;
|
||||
m.add_function(wrap_pyfunction!(parallel_process_mutations, m)?)?;
|
||||
m.add_function(wrap_pyfunction!(levenshtein_distance, m)?)?;
|
||||
m.add_function(wrap_pyfunction!(string_similarity, m)?)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_robustness_score() {
|
||||
let score = calculate_robustness_score(8, 10, 20, 1.0, 1.0);
|
||||
assert!((score - 0.9).abs() < 0.001);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_weighted_score() {
|
||||
let results = vec![
|
||||
(true, 1.0),
|
||||
(true, 1.5),
|
||||
(false, 1.0),
|
||||
];
|
||||
let score = calculate_weighted_score(results);
|
||||
assert!((score - 0.714).abs() < 0.01);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_levenshtein() {
|
||||
assert_eq!(levenshtein_distance("kitten", "sitting"), 3);
|
||||
assert_eq!(levenshtein_distance("", "abc"), 3);
|
||||
assert_eq!(levenshtein_distance("abc", "abc"), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_string_similarity() {
|
||||
let sim = string_similarity("hello", "hallo");
|
||||
assert!(sim > 0.7 && sim < 0.9);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue