use super::{
ApplicationError, ApplicationResult, ConditionOperator, ConstraintSpec, ConvergenceExpectation,
CriterionType, CriterionValue, DensitySpec, Duration, ExpectedMetrics, HashMap, Instant,
IsingModel, ProblemSpecification, ProblemType, PropertyValue, ValidationCriterion, VecDeque,
};
#[derive(Debug)]
pub struct TestScenarioEngine {
pub scenarios: HashMap<String, TestScenario>,
pub execution_history: VecDeque<ScenarioExecution>,
pub generators: Vec<ProblemGenerator>,
pub validation_rules: Vec<ValidationRule>,
}
#[derive(Debug, Clone)]
pub struct TestScenario {
pub id: String,
pub description: String,
pub problem_specs: ProblemSpecification,
pub expected_metrics: ExpectedMetrics,
pub validation_criteria: Vec<ValidationCriterion>,
pub timeout: Duration,
pub max_retries: usize,
}
#[derive(Debug, Clone)]
pub struct ScenarioExecution {
pub scenario_id: String,
pub timestamp: Instant,
pub duration: Duration,
pub success: bool,
pub metrics: HashMap<String, f64>,
pub error: Option<String>,
}
#[derive(Debug)]
pub struct ProblemGenerator {
pub id: String,
pub generator_type: GeneratorType,
pub parameters: HashMap<String, f64>,
pub constraints: Vec<GeneratorConstraint>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum GeneratorType {
Random,
Structured,
RealWorld,
Adversarial,
Benchmark,
}
#[derive(Debug, Clone)]
pub struct GeneratorConstraint {
pub constraint_type: String,
pub parameters: HashMap<String, f64>,
pub priority: f64,
}
#[derive(Debug, Clone)]
pub struct ValidationRule {
pub id: String,
pub description: String,
pub condition: RuleCondition,
pub expected_outcome: RuleOutcome,
pub severity: RuleSeverity,
}
#[derive(Debug, Clone)]
pub struct RuleCondition {
pub expression: String,
pub parameters: HashMap<String, PropertyValue>,
pub evaluation_method: EvaluationMethod,
}
#[derive(Debug, Clone)]
pub struct RuleOutcome {
pub expected_result: PropertyValue,
pub tolerance: f64,
pub comparison_op: ConditionOperator,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum RuleSeverity {
Critical,
Warning,
Info,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum EvaluationMethod {
Direct,
Statistical,
MachineLearning,
Custom(String),
}
impl TestScenarioEngine {
#[must_use]
pub fn new() -> Self {
let mut scenarios = HashMap::new();
scenarios.insert(
"basic_optimization".to_string(),
TestScenario {
id: "basic_optimization".to_string(),
description: "Basic optimization scenario".to_string(),
problem_specs: ProblemSpecification {
problem_type: ProblemType::RandomIsing,
size_range: (10, 100),
density: DensitySpec {
edge_density: (0.1, 0.3),
constraint_density: None,
bias_sparsity: Some(0.5),
},
constraints: ConstraintSpec {
num_constraints: None,
constraint_types: Vec::new(),
strength_range: (0.1, 1.0),
},
seed: Some(42),
},
expected_metrics: ExpectedMetrics {
solution_quality: (0.7, 1.0),
runtime: (Duration::from_millis(100), Duration::from_secs(10)),
success_rate: 0.9,
convergence: ConvergenceExpectation {
convergence_time: Duration::from_secs(5),
final_energy: None,
energy_gap: None,
},
},
validation_criteria: vec![ValidationCriterion {
criterion_type: CriterionType::Performance,
expected_value: CriterionValue::Range(0.7, 1.0),
tolerance: 0.1,
mandatory: true,
}],
timeout: Duration::from_secs(30),
max_retries: 3,
},
);
scenarios.insert(
"large_scale_test".to_string(),
TestScenario {
id: "large_scale_test".to_string(),
description: "Large scale problem test".to_string(),
problem_specs: ProblemSpecification {
problem_type: ProblemType::RandomIsing,
size_range: (1000, 5000),
density: DensitySpec {
edge_density: (0.05, 0.15),
constraint_density: None,
bias_sparsity: Some(0.3),
},
constraints: ConstraintSpec {
num_constraints: None,
constraint_types: Vec::new(),
strength_range: (0.1, 1.0),
},
seed: Some(123),
},
expected_metrics: ExpectedMetrics {
solution_quality: (0.6, 0.9),
runtime: (Duration::from_secs(10), Duration::from_secs(300)),
success_rate: 0.8,
convergence: ConvergenceExpectation {
convergence_time: Duration::from_secs(60),
final_energy: None,
energy_gap: None,
},
},
validation_criteria: vec![
ValidationCriterion {
criterion_type: CriterionType::Performance,
expected_value: CriterionValue::Range(0.6, 0.9),
tolerance: 0.1,
mandatory: true,
},
ValidationCriterion {
criterion_type: CriterionType::Runtime,
expected_value: CriterionValue::Maximum(300.0),
tolerance: 0.0,
mandatory: true,
},
],
timeout: Duration::from_secs(600),
max_retries: 2,
},
);
Self {
scenarios,
execution_history: VecDeque::new(),
generators: Self::create_default_generators(),
validation_rules: Self::create_default_validation_rules(),
}
}
fn create_default_generators() -> Vec<ProblemGenerator> {
vec![
ProblemGenerator {
id: "random_ising".to_string(),
generator_type: GeneratorType::Random,
parameters: {
let mut params = HashMap::new();
params.insert("density".to_string(), 0.2);
params.insert("bias_range".to_string(), 1.0);
params.insert("coupling_range".to_string(), 1.0);
params
},
constraints: Vec::new(),
},
ProblemGenerator {
id: "structured_ising".to_string(),
generator_type: GeneratorType::Structured,
parameters: {
let mut params = HashMap::new();
params.insert("regularity".to_string(), 0.8);
params.insert("locality".to_string(), 0.9);
params
},
constraints: Vec::new(),
},
]
}
fn create_default_validation_rules() -> Vec<ValidationRule> {
vec![
ValidationRule {
id: "solution_feasibility".to_string(),
description: "Solution must be feasible".to_string(),
condition: RuleCondition {
expression: "solution_valid == true".to_string(),
parameters: HashMap::new(),
evaluation_method: EvaluationMethod::Direct,
},
expected_outcome: RuleOutcome {
expected_result: PropertyValue::Boolean(true),
tolerance: 0.0,
comparison_op: ConditionOperator::Equal,
},
severity: RuleSeverity::Critical,
},
ValidationRule {
id: "performance_threshold".to_string(),
description: "Performance must exceed minimum threshold".to_string(),
condition: RuleCondition {
expression: "solution_quality >= threshold".to_string(),
parameters: {
let mut params = HashMap::new();
params.insert("threshold".to_string(), PropertyValue::Numeric(0.5));
params
},
evaluation_method: EvaluationMethod::Direct,
},
expected_outcome: RuleOutcome {
expected_result: PropertyValue::Boolean(true),
tolerance: 0.0,
comparison_op: ConditionOperator::Equal,
},
severity: RuleSeverity::Warning,
},
]
}
pub fn add_scenario(&mut self, scenario: TestScenario) {
self.scenarios.insert(scenario.id.clone(), scenario);
}
pub fn remove_scenario(&mut self, scenario_id: &str) -> Option<TestScenario> {
self.scenarios.remove(scenario_id)
}
#[must_use]
pub fn get_scenario(&self, scenario_id: &str) -> Option<&TestScenario> {
self.scenarios.get(scenario_id)
}
pub fn record_execution(&mut self, execution: ScenarioExecution) {
self.execution_history.push_back(execution);
while self.execution_history.len() > 1000 {
self.execution_history.pop_front();
}
}
#[must_use]
pub fn get_execution_history(&self, scenario_id: &str) -> Vec<&ScenarioExecution> {
self.execution_history
.iter()
.filter(|exec| exec.scenario_id == scenario_id)
.collect()
}
pub fn generate_problem(&self, spec: &ProblemSpecification) -> ApplicationResult<IsingModel> {
let generator = self
.generators
.iter()
.find(|g| self.can_generate_problem_type(g, &spec.problem_type))
.ok_or_else(|| {
ApplicationError::ConfigurationError(format!(
"No generator available for problem type: {:?}",
spec.problem_type
))
})?;
self.generate_with_generator(generator, spec)
}
fn can_generate_problem_type(
&self,
generator: &ProblemGenerator,
problem_type: &ProblemType,
) -> bool {
match (generator.generator_type.clone(), problem_type) {
(GeneratorType::Random, ProblemType::RandomIsing) => true,
(GeneratorType::Structured, _) => true,
(GeneratorType::Benchmark, _) => true,
_ => false,
}
}
fn generate_with_generator(
&self,
generator: &ProblemGenerator,
spec: &ProblemSpecification,
) -> ApplicationResult<IsingModel> {
let size = usize::midpoint(spec.size_range.0, spec.size_range.1);
let mut problem = IsingModel::new(size);
match generator.generator_type {
GeneratorType::Random => self.generate_random_problem(&mut problem, spec, generator)?,
GeneratorType::Structured => {
self.generate_structured_problem(&mut problem, spec, generator)?;
}
_ => {
return Err(ApplicationError::ConfigurationError(format!(
"Generator type {:?} not implemented",
generator.generator_type
)));
}
}
Ok(problem)
}
fn generate_random_problem(
&self,
problem: &mut IsingModel,
spec: &ProblemSpecification,
generator: &ProblemGenerator,
) -> ApplicationResult<()> {
let size = problem.num_qubits;
let bias_range = generator.parameters.get("bias_range").unwrap_or(&1.0);
let coupling_range = generator.parameters.get("coupling_range").unwrap_or(&1.0);
for i in 0..size {
let bias = (i as f64 % 10.0) / 10.0 * bias_range - bias_range / 2.0;
problem.set_bias(i, bias)?;
}
let target_density =
f64::midpoint(spec.density.edge_density.0, spec.density.edge_density.1);
let max_edges = size * (size - 1) / 2;
let target_edges = (max_edges as f64 * target_density) as usize;
let mut edges_added = 0;
for i in 0..size {
for j in (i + 1)..size {
if edges_added >= target_edges {
break;
}
if (i + j) % 3 == 0 {
let coupling =
((i + j) as f64 % 20.0) / 20.0 * coupling_range - coupling_range / 2.0;
problem.set_coupling(i, j, coupling)?;
edges_added += 1;
}
}
if edges_added >= target_edges {
break;
}
}
Ok(())
}
fn generate_structured_problem(
&self,
problem: &mut IsingModel,
spec: &ProblemSpecification,
generator: &ProblemGenerator,
) -> ApplicationResult<()> {
let size = problem.num_qubits;
let regularity = generator.parameters.get("regularity").unwrap_or(&0.8);
let locality = generator.parameters.get("locality").unwrap_or(&0.9);
for i in 0..size {
let bias = if (i as f64) < size as f64 * regularity {
((i % 4) as f64 - 1.5) / 2.0
} else {
(i as f64 % 7.0) / 7.0 - 0.5
};
problem.set_bias(i, bias)?;
}
let local_range = (size as f64 * locality) as usize;
for i in 0..size {
let max_j = (i + local_range).min(size);
for j in (i + 1)..max_j {
if (i + j) % 2 == 0 {
let coupling = ((i as f64 - j as f64).abs() / local_range as f64) * 0.5;
problem.set_coupling(i, j, coupling)?;
}
}
}
Ok(())
}
}