use scirs2_core::ndarray::{Array1, Array2, Array3};
use scirs2_core::random::{Random, rng};
use scirs2_core::random::distributions::{Normal, StandardNormal};
use sklears_core::error::{Result, SklearsError};
pub fn make_gene_expression_dataset(
n_samples: usize,
n_genes: usize,
n_cell_types: usize,
noise_level: f64,
random_state: Option<u64>,
) -> Result<(Array2<f64>, Array1<i32>)> {
if n_samples == 0 || n_genes == 0 || n_cell_types == 0 {
return Err(SklearsError::InvalidInput(
"n_samples, n_genes, and n_cell_types must be positive".to_string(),
));
}
let mut rng = Random::from_seed(random_state.unwrap_or_else(|| rng().gen()));
let mut labels = Array1::zeros(n_samples);
for i in 0..n_samples {
labels[i] = rng.gen_range(0..n_cell_types) as i32;
}
let mut expression_patterns = Array2::zeros((n_cell_types, n_genes));
for i in 0..n_cell_types {
for j in 0..n_genes {
let log_expr = rng.sample(Normal::new(5.0, 2.0).expect("sampling should succeed"));
expression_patterns[[i, j]] = log_expr.exp();
}
}
let mut expression = Array2::zeros((n_samples, n_genes));
for i in 0..n_samples {
let cell_type = labels[i] as usize;
for j in 0..n_genes {
let base_expression = expression_patterns[[cell_type, j]];
let noise = rng.sample(Normal::new(0.0, noise_level).expect("sampling should succeed"));
expression[[i, j]] = base_expression + noise;
}
}
Ok((expression, labels))
}
pub fn make_dna_sequence_dataset(
n_sequences: usize,
sequence_length: usize,
n_classes: usize,
gc_content: f64,
random_state: Option<u64>,
) -> Result<(Array2<f64>, Array1<i32>)> {
if n_sequences == 0 || sequence_length == 0 || n_classes == 0 {
return Err(SklearsError::InvalidInput(
"n_sequences, sequence_length, and n_classes must be positive".to_string(),
));
}
if gc_content < 0.0 || gc_content > 1.0 {
return Err(SklearsError::InvalidInput(
"gc_content must be between 0.0 and 1.0".to_string(),
));
}
let mut rng = Random::from_seed(random_state.unwrap_or_else(|| rng().gen()));
let mut sequences = Array2::zeros((n_sequences, sequence_length * 4));
let mut labels = Array1::zeros(n_sequences);
for i in 0..n_sequences {
labels[i] = rng.gen_range(0..n_classes) as i32;
for j in 0..sequence_length {
let base_idx = if rng.gen() < gc_content / 2.0 {
if rng.gen() < 0.5 { 2 } else { 3 } } else {
if rng.gen() < 0.5 { 0 } else { 1 } };
sequences[[i, j * 4 + base_idx]] = 1.0;
}
}
Ok((sequences, labels))
}
pub fn make_document_clustering_dataset(
n_documents: usize,
n_features: usize,
n_topics: usize,
sparsity: f64,
random_state: Option<u64>,
) -> Result<(Array2<f64>, Array1<i32>)> {
if n_documents == 0 || n_features == 0 || n_topics == 0 {
return Err(SklearsError::InvalidInput(
"n_documents, n_features, and n_topics must be positive".to_string(),
));
}
if sparsity < 0.0 || sparsity > 1.0 {
return Err(SklearsError::InvalidInput(
"sparsity must be between 0.0 and 1.0".to_string(),
));
}
let mut rng = Random::from_seed(random_state.unwrap_or_else(|| rng().gen()));
let mut topic_distributions = Array2::zeros((n_topics, n_features));
for i in 0..n_topics {
for j in 0..n_features {
topic_distributions[[i, j]] = rng.sample(Normal::new(0.0, 1.0).expect("sampling should succeed")).abs();
}
let row_sum = topic_distributions.row(i).sum();
for j in 0..n_features {
topic_distributions[[i, j]] /= row_sum;
}
}
let mut documents = Array2::zeros((n_documents, n_features));
let mut labels = Array1::zeros(n_documents);
for i in 0..n_documents {
let topic = rng.gen_range(0..n_topics);
labels[i] = topic as i32;
for j in 0..n_features {
if rng.gen() > sparsity {
let word_prob = topic_distributions[[topic, j]];
let word_count = rng.sample(Normal::new(word_prob * 100.0, 10.0).expect("sampling should succeed")).max(0.0);
documents[[i, j]] = word_count;
}
}
}
Ok((documents, labels))
}
pub fn make_synthetic_image_classification(
n_images: usize,
image_height: usize,
image_width: usize,
n_channels: usize,
n_classes: usize,
noise_level: f64,
random_state: Option<u64>,
) -> Result<(Array2<f64>, Array1<i32>)> {
if n_images == 0 || image_height == 0 || image_width == 0 || n_channels == 0 || n_classes == 0 {
return Err(SklearsError::InvalidInput(
"All dimension parameters must be positive".to_string(),
));
}
let mut rng = Random::from_seed(random_state.unwrap_or_else(|| rng().gen()));
let n_pixels = image_height * image_width * n_channels;
let mut images = Array2::zeros((n_images, n_pixels));
let mut labels = Array1::zeros(n_images);
let mut prototypes = Array2::zeros((n_classes, n_pixels));
for i in 0..n_classes {
for j in 0..n_pixels {
prototypes[[i, j]] = rng.random_range(0.0..1.0);
}
}
for i in 0..n_images {
let class = rng.gen_range(0..n_classes);
labels[i] = class as i32;
for j in 0..n_pixels {
let base_value = prototypes[[class, j]];
let noise = rng.sample(Normal::new(0.0, noise_level).expect("sampling should succeed"));
images[[i, j]] = (base_value + noise).clamp(0.0, 1.0);
}
}
Ok((images, labels))
}
pub fn make_privacy_preserving_dataset(
data: &Array2<f64>,
epsilon: f64,
delta: f64,
sensitivity: f64,
random_state: Option<u64>,
) -> Result<Array2<f64>> {
if epsilon <= 0.0 {
return Err(SklearsError::InvalidInput(
"epsilon must be positive".to_string(),
));
}
if delta < 0.0 || delta >= 1.0 {
return Err(SklearsError::InvalidInput(
"delta must be between 0.0 and 1.0".to_string(),
));
}
if sensitivity <= 0.0 {
return Err(SklearsError::InvalidInput(
"sensitivity must be positive".to_string(),
));
}
let mut rng = Random::from_seed(random_state.unwrap_or_else(|| rng().gen()));
let mut result = data.clone();
let (n_rows, n_cols) = data.dim();
let noise_scale = (2.0 * (1.25 / delta).ln()).sqrt() * sensitivity / epsilon;
for i in 0..n_rows {
for j in 0..n_cols {
let noise = rng.sample(Normal::new(0.0, noise_scale).expect("sampling should succeed"));
result[[i, j]] += noise;
}
}
Ok(result)
}
pub fn make_multi_agent_environment(
n_episodes: usize,
episode_length: usize,
n_agents: usize,
n_actions: usize,
cooperation_probability: f64,
random_state: Option<u64>,
) -> Result<(Array3<f64>, Array2<f64>)> {
if n_episodes == 0 || episode_length == 0 || n_agents == 0 || n_actions == 0 {
return Err(SklearsError::InvalidInput(
"All parameters must be positive".to_string(),
));
}
if cooperation_probability < 0.0 || cooperation_probability > 1.0 {
return Err(SklearsError::InvalidInput(
"cooperation_probability must be between 0.0 and 1.0".to_string(),
));
}
let mut rng = Random::from_seed(random_state.unwrap_or_else(|| rng().gen()));
let mut sequences = Array3::zeros((n_episodes, episode_length, n_agents * n_actions));
let mut rewards = Array2::zeros((n_episodes, episode_length));
for episode in 0..n_episodes {
for timestep in 0..episode_length {
let mut episode_reward = 0.0;
for agent in 0..n_agents {
let action = if rng.gen() < cooperation_probability {
rng.gen_range(0..(n_actions / 2).max(1))
} else {
rng.gen_range(0..n_actions)
};
sequences[[episode, timestep, agent * n_actions + action]] = 1.0;
if action < n_actions / 2 {
episode_reward += 1.0;
} else {
episode_reward -= 0.5;
}
}
rewards[[episode, timestep]] = episode_reward / n_agents as f64;
}
}
Ok((sequences, rewards))
}
pub fn make_ab_testing_simulation(
n_users: usize,
n_features: usize,
treatment_effect: f64,
confounding_strength: f64,
random_state: Option<u64>,
) -> Result<(Array2<f64>, Array1<i32>, Array1<f64>)> {
if n_users == 0 || n_features == 0 {
return Err(SklearsError::InvalidInput(
"n_users and n_features must be positive".to_string(),
));
}
let mut rng = Random::from_seed(random_state.unwrap_or_else(|| rng().gen()));
let mut features = Array2::zeros((n_users, n_features));
for i in 0..n_users {
for j in 0..n_features {
features[[i, j]] = rng.sample(StandardNormal);
}
}
let mut treatments = Array1::zeros(n_users);
for i in 0..n_users {
let confounding_score = features.row(i).sum() * confounding_strength;
let treatment_prob = 0.5 + 0.2 * confounding_score.tanh();
treatments[i] = if rng.gen() < treatment_prob { 1 } else { 0 };
}
let mut outcomes = Array1::zeros(n_users);
for i in 0..n_users {
let baseline = features.row(i).sum() * 0.5; let treatment_contribution = treatments[i] as f64 * treatment_effect;
let noise = rng.sample(Normal::new(0.0, 1.0).expect("sampling should succeed"));
outcomes[i] = baseline + treatment_contribution + noise;
}
Ok((features, treatments, outcomes))
}