use std::collections::{HashMap, VecDeque};
use std::fmt;
use crate::advanced_quantum_algorithms::{
AdiabaticShortcutsOptimizer, AdvancedAlgorithmConfig, AdvancedQuantumAlgorithms,
AlgorithmSelectionStrategy, InfiniteDepthQAOA, InfiniteQAOAConfig, QuantumZenoAnnealer,
ShortcutsConfig, ZenoConfig,
};
use crate::applications::{
ApplicationError, ApplicationResult, IndustrySolution, OptimizationProblem,
};
use crate::bayesian_hyperopt::{optimize_annealing_parameters, BayesianHyperoptimizer};
use crate::ising::IsingModel;
use crate::neural_annealing_schedules::{NeuralAnnealingScheduler, NeuralSchedulerConfig};
use crate::non_stoquastic::{HamiltonianType, NonStoquasticHamiltonian};
use crate::quantum_error_correction::{
ErrorCorrectionCode, ErrorMitigationConfig, ErrorMitigationManager, LogicalAnnealingEncoder,
NoiseResilientAnnealingProtocol, SyndromeDetector,
};
use crate::simulator::{AnnealingParams, QuantumAnnealingSimulator};
use std::fmt::Write;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LatticeType {
SimpleCubic,
BodyCenteredCubic,
FaceCenteredCubic,
HexagonalClosePacked,
Diamond,
Graphene,
Perovskite,
Custom {
coordination: usize,
dimension: usize,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct LatticePosition {
pub x: i32,
pub y: i32,
pub z: i32,
}
impl LatticePosition {
#[must_use]
pub const fn new(x: i32, y: i32, z: i32) -> Self {
Self { x, y, z }
}
#[must_use]
pub fn distance(&self, other: &Self) -> f64 {
let dx = f64::from(self.x - other.x);
let dy = f64::from(self.y - other.y);
let dz = f64::from(self.z - other.z);
dz.mul_add(dz, dx.mul_add(dx, dy * dy)).sqrt()
}
#[must_use]
pub fn neighbors(&self, lattice_type: LatticeType) -> Vec<Self> {
match lattice_type {
LatticeType::SimpleCubic => {
vec![
Self::new(self.x + 1, self.y, self.z),
Self::new(self.x - 1, self.y, self.z),
Self::new(self.x, self.y + 1, self.z),
Self::new(self.x, self.y - 1, self.z),
Self::new(self.x, self.y, self.z + 1),
Self::new(self.x, self.y, self.z - 1),
]
}
LatticeType::Graphene => {
vec![
Self::new(self.x + 1, self.y, self.z),
Self::new(self.x, self.y + 1, self.z),
Self::new(self.x - 1, self.y + 1, self.z),
]
}
_ => {
self.neighbors(LatticeType::SimpleCubic)
}
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct AtomicSpecies {
pub symbol: String,
pub atomic_number: u32,
pub mass: f64,
pub magnetic_moment: Option<f64>,
pub charge: f64,
pub radius: f64,
}
impl AtomicSpecies {
#[must_use]
pub const fn new(symbol: String, atomic_number: u32, mass: f64) -> Self {
Self {
symbol,
atomic_number,
mass,
magnetic_moment: None,
charge: 0.0,
radius: 1.0,
}
}
#[must_use]
pub const fn with_magnetic_moment(mut self, moment: f64) -> Self {
self.magnetic_moment = Some(moment);
self
}
#[must_use]
pub const fn with_charge(mut self, charge: f64) -> Self {
self.charge = charge;
self
}
}
#[derive(Debug, Clone)]
pub struct LatticeSite {
pub position: LatticePosition,
pub species: Option<AtomicSpecies>,
pub occupation: bool,
pub spin: Option<[f64; 3]>, pub defect_type: Option<DefectType>,
pub local_energy: f64,
}
impl LatticeSite {
#[must_use]
pub const fn new(position: LatticePosition) -> Self {
Self {
position,
species: None,
occupation: false,
spin: None,
defect_type: None,
local_energy: 0.0,
}
}
#[must_use]
pub fn with_species(mut self, species: AtomicSpecies) -> Self {
self.species = Some(species);
self.occupation = true;
self
}
#[must_use]
pub const fn with_spin(mut self, spin: [f64; 3]) -> Self {
self.spin = Some(spin);
self
}
#[must_use]
pub fn with_defect(mut self, defect: DefectType) -> Self {
self.defect_type = Some(defect);
self
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum DefectType {
Vacancy,
Interstitial(AtomicSpecies),
Substitutional(AtomicSpecies),
GrainBoundary,
Dislocation { burgers_vector: [f64; 3] },
Surface,
}
#[derive(Debug, Clone)]
pub struct MaterialsLattice {
pub lattice_type: LatticeType,
pub dimensions: [usize; 3], pub lattice_constants: [f64; 3], pub sites: HashMap<LatticePosition, LatticeSite>,
pub temperature: f64,
pub external_field: Option<[f64; 3]>, }
impl MaterialsLattice {
#[must_use]
pub fn new(lattice_type: LatticeType, dimensions: [usize; 3]) -> Self {
let mut sites = HashMap::new();
for x in 0..(dimensions[0] as i32) {
for y in 0..(dimensions[1] as i32) {
for z in 0..(dimensions[2] as i32) {
let pos = LatticePosition::new(x, y, z);
sites.insert(pos, LatticeSite::new(pos));
}
}
}
Self {
lattice_type,
dimensions,
lattice_constants: [1.0, 1.0, 1.0],
sites,
temperature: 300.0, external_field: None,
}
}
pub const fn set_lattice_constants(&mut self, constants: [f64; 3]) {
self.lattice_constants = constants;
}
pub fn add_atom(
&mut self,
position: LatticePosition,
species: AtomicSpecies,
) -> ApplicationResult<()> {
if let Some(site) = self.sites.get_mut(&position) {
site.species = Some(species);
site.occupation = true;
Ok(())
} else {
Err(ApplicationError::InvalidConfiguration(format!(
"Position {position:?} not found in lattice"
)))
}
}
pub fn create_defect(
&mut self,
position: LatticePosition,
defect: DefectType,
) -> ApplicationResult<()> {
if let Some(site) = self.sites.get_mut(&position) {
site.defect_type = Some(defect);
match &site.defect_type {
Some(DefectType::Vacancy) => {
site.occupation = false;
site.species = None;
}
Some(DefectType::Interstitial(species)) => {
site.species = Some(species.clone());
site.occupation = true;
}
Some(DefectType::Substitutional(species)) => {
site.species = Some(species.clone());
site.occupation = true;
}
_ => {}
}
Ok(())
} else {
Err(ApplicationError::InvalidConfiguration(format!(
"Position {position:?} not found in lattice"
)))
}
}
#[must_use]
pub fn calculate_total_energy(&self) -> f64 {
let mut total_energy = 0.0;
for (pos, site) in &self.sites {
total_energy += site.local_energy;
let neighbors = pos.neighbors(self.lattice_type);
for neighbor_pos in neighbors {
if let Some(neighbor_site) = self.sites.get(&neighbor_pos) {
if site.occupation && neighbor_site.occupation {
total_energy += self.interaction_energy(site, neighbor_site);
}
}
}
if let Some(ref defect) = site.defect_type {
total_energy += self.defect_energy(defect);
}
}
total_energy / 2.0 }
fn interaction_energy(&self, site1: &LatticeSite, site2: &LatticeSite) -> f64 {
let mut energy = 0.0;
if let (Some(ref species1), Some(ref species2)) = (&site1.species, &site2.species) {
let distance = site1.position.distance(&site2.position) * self.lattice_constants[0];
let k_coulomb = 8.99e9; energy += k_coulomb * species1.charge * species2.charge / distance;
}
if let (Some(spin1), Some(spin2)) = (site1.spin, site2.spin) {
let j_exchange = -1.0; energy += j_exchange
* spin1[2].mul_add(spin2[2], spin1[0].mul_add(spin2[0], spin1[1] * spin2[1]));
}
energy
}
const fn defect_energy(&self, defect: &DefectType) -> f64 {
match defect {
DefectType::Vacancy => 2.0, DefectType::Interstitial(_) => 3.0, DefectType::Substitutional(_) => 0.5, DefectType::GrainBoundary => 1.0,
DefectType::Dislocation { .. } => 5.0,
DefectType::Surface => 0.8,
}
}
#[must_use]
pub fn calculate_order_parameter(&self) -> f64 {
let mut magnetization = [0.0, 0.0, 0.0];
let mut count = 0;
for site in self.sites.values() {
if let Some(spin) = site.spin {
magnetization[0] += spin[0];
magnetization[1] += spin[1];
magnetization[2] += spin[2];
count += 1;
}
}
if count > 0 {
let mag = magnetization[2].mul_add(
magnetization[2],
magnetization[0].mul_add(magnetization[0], magnetization[1] * magnetization[1]),
);
mag.sqrt() / f64::from(count)
} else {
0.0
}
}
}
#[derive(Debug, Clone)]
pub enum MaterialsObjective {
MinimizeEnergy,
MaximizeStability,
MinimizeDefects,
OptimizeMagnetism,
MinimizeFormationEnergy,
MaximizeOrder,
MultiObjective(Vec<(Self, f64)>),
}
#[derive(Debug, Clone)]
pub struct MaterialsOptimizationProblem {
pub lattice: MaterialsLattice,
pub objectives: Vec<MaterialsObjective>,
pub constraints: Vec<MaterialsConstraint>,
pub qec_framework: Option<String>,
pub advanced_config: AdvancedAlgorithmConfig,
pub neural_config: Option<NeuralSchedulerConfig>,
}
#[derive(Debug, Clone)]
pub enum MaterialsConstraint {
Stoichiometry { elements: HashMap<String, f64> },
ChargeNeutrality,
MaxDefectDensity(f64),
TemperatureRange { min: f64, max: f64 },
MagneticMomentConservation,
StructuralStability { min_coordination: usize },
}
impl MaterialsOptimizationProblem {
#[must_use]
pub fn new(lattice: MaterialsLattice) -> Self {
Self {
lattice,
objectives: vec![MaterialsObjective::MinimizeEnergy],
constraints: vec![],
qec_framework: None,
advanced_config: AdvancedAlgorithmConfig {
enable_infinite_qaoa: true,
enable_zeno_annealing: true,
enable_adiabatic_shortcuts: true,
enable_counterdiabatic: true,
selection_strategy: AlgorithmSelectionStrategy::ProblemSpecific,
track_performance: true,
},
neural_config: None,
}
}
#[must_use]
pub fn with_quantum_error_correction(mut self, config: String) -> Self {
self.qec_framework = Some(config);
self
}
#[must_use]
pub fn with_neural_annealing(mut self, config: NeuralSchedulerConfig) -> Self {
self.neural_config = Some(config);
self
}
#[must_use]
pub fn add_objective(mut self, objective: MaterialsObjective) -> Self {
self.objectives.push(objective);
self
}
#[must_use]
pub fn add_constraint(mut self, constraint: MaterialsConstraint) -> Self {
self.constraints.push(constraint);
self
}
pub fn solve_with_infinite_qaoa(&self) -> ApplicationResult<MaterialsLattice> {
println!("Starting materials optimization with infinite-depth QAOA");
let (ising_model, variable_map) = self.to_ising_model()?;
let qaoa_config = InfiniteQAOAConfig {
max_depth: 50,
initial_depth: 3,
optimization_tolerance: 1e-8,
..Default::default()
};
let mut qaoa = InfiniteDepthQAOA::new(qaoa_config);
let result = qaoa.solve(&ising_model).map_err(|e| {
ApplicationError::OptimizationError(format!("Infinite QAOA failed: {e:?}"))
})?;
let solution = result
.map_err(|e| ApplicationError::OptimizationError(format!("QAOA solver error: {e}")))?;
self.solution_to_lattice(&solution, &variable_map)
}
pub fn solve_with_zeno_annealing(&self) -> ApplicationResult<MaterialsLattice> {
println!("Starting materials optimization with Quantum Zeno annealing");
let (ising_model, variable_map) = self.to_ising_model()?;
let zeno_config = ZenoConfig {
measurement_frequency: 2.0,
total_evolution_time: 20.0,
evolution_time_step: 0.05,
..Default::default()
};
let mut zeno_annealer = QuantumZenoAnnealer::new(zeno_config);
let result = zeno_annealer.solve(&ising_model).map_err(|e| {
ApplicationError::OptimizationError(format!("Zeno annealing failed: {e:?}"))
})?;
let solution = result
.map_err(|e| ApplicationError::OptimizationError(format!("Zeno solver error: {e}")))?;
self.solution_to_lattice(&solution, &variable_map)
}
pub fn solve_with_adiabatic_shortcuts(&self) -> ApplicationResult<MaterialsLattice> {
println!("Starting materials optimization with adiabatic shortcuts");
let (ising_model, variable_map) = self.to_ising_model()?;
let shortcuts_config = ShortcutsConfig::default();
let mut shortcuts_optimizer = AdiabaticShortcutsOptimizer::new(shortcuts_config);
let result = shortcuts_optimizer.solve(&ising_model).map_err(|e| {
ApplicationError::OptimizationError(format!("Adiabatic shortcuts failed: {e:?}"))
})?;
let solution = result.map_err(|e| {
ApplicationError::OptimizationError(format!("Shortcuts solver error: {e}"))
})?;
self.solution_to_lattice(&solution, &variable_map)
}
pub fn solve_with_error_correction(&self) -> ApplicationResult<MaterialsLattice> {
if let Some(ref qec_framework) = self.qec_framework {
println!("Starting noise-resilient materials optimization");
let (ising_model, variable_map) = self.to_ising_model()?;
let error_config = ErrorMitigationConfig::default();
let mut error_manager = ErrorMitigationManager::new(error_config).map_err(|e| {
ApplicationError::OptimizationError(format!(
"Failed to create error manager: {e:?}"
))
})?;
let params = AnnealingParams::default();
let annealer = QuantumAnnealingSimulator::new(params.clone()).map_err(|e| {
ApplicationError::OptimizationError(format!("Failed to create annealer: {e:?}"))
})?;
let annealing_result = annealer.solve(&ising_model).map_err(|e| {
ApplicationError::OptimizationError(format!("Annealing failed: {e:?}"))
})?;
let error_mitigation_result =
crate::quantum_error_correction::error_mitigation::AnnealingResult {
solution: annealing_result
.best_spins
.iter()
.map(|&x| i32::from(x))
.collect(),
energy: annealing_result.best_energy,
num_occurrences: 1,
chain_break_fraction: 0.0,
timing: std::collections::HashMap::new(),
info: std::collections::HashMap::new(),
};
let mitigation_result = error_manager
.apply_mitigation(&ising_model, error_mitigation_result, ¶ms)
.map_err(|e| {
ApplicationError::OptimizationError(format!("Error mitigation failed: {e:?}"))
})?;
let solution = &mitigation_result.mitigated_result.solution;
self.solution_to_lattice(&solution, &variable_map)
} else {
Err(ApplicationError::InvalidConfiguration(
"Quantum error correction not enabled".to_string(),
))
}
}
pub fn optimize_lattice_parameters(&self) -> ApplicationResult<HashMap<String, f64>> {
println!("Optimizing lattice parameters with Bayesian optimization");
let objective = |params: &[f64]| -> f64 {
let temperature = params[0];
let lattice_constant = params[1];
let field_strength = params[2];
let thermal_energy = temperature * 0.001; let strain_energy = (lattice_constant - 1.0).powi(2) * 10.0; let field_energy = field_strength * 0.1;
thermal_energy + strain_energy + field_energy
};
let best_params = optimize_annealing_parameters(objective, Some(40)).map_err(|e| {
ApplicationError::OptimizationError(format!("Bayesian optimization failed: {e:?}"))
})?;
let mut result = HashMap::new();
result.insert("optimal_temperature".to_string(), best_params[0]);
result.insert("optimal_lattice_constant".to_string(), best_params[1]);
result.insert("optimal_field_strength".to_string(), best_params[2]);
Ok(result)
}
fn to_ising_model(&self) -> ApplicationResult<(IsingModel, HashMap<String, usize>)> {
let total_sites = self.lattice.sites.len();
let mut ising = IsingModel::new(total_sites);
let mut variable_map = HashMap::new();
let site_positions: Vec<_> = self.lattice.sites.keys().copied().collect();
for (i, pos) in site_positions.iter().enumerate() {
variable_map.insert(format!("site_{}_{}_{}_{}", pos.x, pos.y, pos.z, i), i);
}
for (i, (pos, site)) in self.lattice.sites.iter().enumerate() {
let mut bias = site.local_energy;
for objective in &self.objectives {
match objective {
MaterialsObjective::MinimizeEnergy => {
bias += site.local_energy;
}
MaterialsObjective::MinimizeDefects => {
if site.defect_type.is_some() {
bias += 10.0; }
}
MaterialsObjective::OptimizeMagnetism => {
if let Some(spin) = site.spin {
let spin_magnitude = spin[2]
.mul_add(spin[2], spin[0].mul_add(spin[0], spin[1] * spin[1]))
.sqrt();
bias -= spin_magnitude; }
}
_ => {
bias += 0.1;
}
}
}
ising
.set_bias(i, bias)
.map_err(|e| ApplicationError::OptimizationError(e.to_string()))?;
}
for (i, (pos1, site1)) in self.lattice.sites.iter().enumerate() {
let neighbors = pos1.neighbors(self.lattice.lattice_type);
for neighbor_pos in neighbors {
if let Some((j, (_, site2))) = self
.lattice
.sites
.iter()
.enumerate()
.find(|(_, (pos, _))| **pos == neighbor_pos)
{
if i < j {
let coupling = self.lattice.interaction_energy(site1, site2);
ising
.set_coupling(i, j, coupling)
.map_err(|e| ApplicationError::OptimizationError(e.to_string()))?;
}
}
}
}
Ok((ising, variable_map))
}
fn solution_to_lattice(
&self,
solution: &[i32],
variable_map: &HashMap<String, usize>,
) -> ApplicationResult<MaterialsLattice> {
let mut optimized_lattice = self.lattice.clone();
for (pos, site) in &mut optimized_lattice.sites {
if let Some(&var_index) =
variable_map.get(&format!("site_{}_{}_{}_0", pos.x, pos.y, pos.z))
{
if var_index < solution.len() {
let spin_value = solution[var_index];
if site.spin.is_some() {
let spin_direction = if spin_value > 0 { 1.0 } else { -1.0 };
site.spin = Some([0.0, 0.0, spin_direction]);
}
site.occupation = spin_value > 0;
}
}
}
let positions: Vec<_> = optimized_lattice.sites.keys().copied().collect();
for pos in positions {
let local_energy = self.calculate_local_energy(&pos, &optimized_lattice);
if let Some(site) = optimized_lattice.sites.get_mut(&pos) {
site.local_energy = local_energy;
}
}
Ok(optimized_lattice)
}
fn calculate_local_energy(&self, pos: &LatticePosition, lattice: &MaterialsLattice) -> f64 {
let mut energy = 0.0;
if let Some(site) = lattice.sites.get(pos) {
if let Some(ref defect) = site.defect_type {
energy += lattice.defect_energy(defect);
}
let neighbors = pos.neighbors(lattice.lattice_type);
for neighbor_pos in neighbors {
if let Some(neighbor_site) = lattice.sites.get(&neighbor_pos) {
energy += lattice.interaction_energy(site, neighbor_site) / 2.0;
}
}
}
energy
}
}
impl OptimizationProblem for MaterialsOptimizationProblem {
type Solution = MaterialsLattice;
type ObjectiveValue = f64;
fn description(&self) -> String {
format!(
"Materials science lattice optimization: {:?} lattice, dimensions {:?}, {} sites",
self.lattice.lattice_type,
self.lattice.dimensions,
self.lattice.sites.len()
)
}
fn size_metrics(&self) -> HashMap<String, usize> {
let mut metrics = HashMap::new();
metrics.insert("total_sites".to_string(), self.lattice.sites.len());
metrics.insert("x_dimension".to_string(), self.lattice.dimensions[0]);
metrics.insert("y_dimension".to_string(), self.lattice.dimensions[1]);
metrics.insert("z_dimension".to_string(), self.lattice.dimensions[2]);
let occupied_sites = self.lattice.sites.values().filter(|s| s.occupation).count();
metrics.insert("occupied_sites".to_string(), occupied_sites);
let defect_sites = self
.lattice
.sites
.values()
.filter(|s| s.defect_type.is_some())
.count();
metrics.insert("defect_sites".to_string(), defect_sites);
metrics
}
fn validate(&self) -> ApplicationResult<()> {
if self.lattice.sites.is_empty() {
return Err(ApplicationError::DataValidationError(
"Lattice must have at least one site".to_string(),
));
}
let total_sites =
self.lattice.dimensions[0] * self.lattice.dimensions[1] * self.lattice.dimensions[2];
if total_sites > 10_000 {
return Err(ApplicationError::ResourceLimitExceeded(
"Lattice too large for current implementation".to_string(),
));
}
for constraint in &self.constraints {
match constraint {
MaterialsConstraint::ChargeNeutrality => {
let total_charge: f64 = self
.lattice
.sites
.values()
.filter_map(|s| s.species.as_ref().map(|sp| sp.charge))
.sum();
if total_charge.abs() > 1e-6 {
return Err(ApplicationError::ConstraintViolation(format!(
"Charge neutrality violated: total charge = {total_charge}"
)));
}
}
MaterialsConstraint::MaxDefectDensity(max_density) => {
let defect_count = self
.lattice
.sites
.values()
.filter(|s| s.defect_type.is_some())
.count();
let defect_density = defect_count as f64 / self.lattice.sites.len() as f64;
if defect_density > *max_density {
return Err(ApplicationError::ConstraintViolation(format!(
"Defect density {defect_density} exceeds maximum {max_density}"
)));
}
}
_ => {
}
}
}
Ok(())
}
fn to_qubo(&self) -> ApplicationResult<(crate::ising::QuboModel, HashMap<String, usize>)> {
let (ising, variable_map) = self.to_ising_model()?;
let qubo = ising.to_qubo();
Ok((qubo, variable_map))
}
fn evaluate_solution(
&self,
solution: &Self::Solution,
) -> ApplicationResult<Self::ObjectiveValue> {
Ok(solution.calculate_total_energy())
}
fn is_feasible(&self, solution: &Self::Solution) -> bool {
for constraint in &self.constraints {
match constraint {
MaterialsConstraint::ChargeNeutrality => {
let total_charge: f64 = solution
.sites
.values()
.filter_map(|s| s.species.as_ref().map(|sp| sp.charge))
.sum();
if total_charge.abs() > 1e-6 {
return false;
}
}
MaterialsConstraint::MaxDefectDensity(max_density) => {
let defect_count = solution
.sites
.values()
.filter(|s| s.defect_type.is_some())
.count();
let defect_density = defect_count as f64 / solution.sites.len() as f64;
if defect_density > *max_density {
return false;
}
}
_ => {
}
}
}
true
}
}
impl IndustrySolution for MaterialsLattice {
type Problem = MaterialsOptimizationProblem;
fn from_binary(problem: &Self::Problem, binary_solution: &[i8]) -> ApplicationResult<Self> {
let solution_i32: Vec<i32> = binary_solution.iter().map(|&x| i32::from(x)).collect();
let variable_map = HashMap::new(); problem.solution_to_lattice(&solution_i32, &variable_map)
}
fn summary(&self) -> HashMap<String, String> {
let mut summary = HashMap::new();
summary.insert(
"lattice_type".to_string(),
format!("{:?}", self.lattice_type),
);
summary.insert("dimensions".to_string(), format!("{:?}", self.dimensions));
summary.insert("total_sites".to_string(), self.sites.len().to_string());
summary.insert(
"temperature".to_string(),
format!("{:.2} K", self.temperature),
);
summary.insert(
"total_energy".to_string(),
format!("{:.6}", self.calculate_total_energy()),
);
summary.insert(
"order_parameter".to_string(),
format!("{:.6}", self.calculate_order_parameter()),
);
let occupied_sites = self.sites.values().filter(|s| s.occupation).count();
summary.insert("occupied_sites".to_string(), occupied_sites.to_string());
let defect_sites = self
.sites
.values()
.filter(|s| s.defect_type.is_some())
.count();
summary.insert("defect_sites".to_string(), defect_sites.to_string());
summary
}
fn metrics(&self) -> HashMap<String, f64> {
let mut metrics = HashMap::new();
metrics.insert("total_energy".to_string(), self.calculate_total_energy());
metrics.insert(
"order_parameter".to_string(),
self.calculate_order_parameter(),
);
metrics.insert("temperature".to_string(), self.temperature);
let occupied_fraction =
self.sites.values().filter(|s| s.occupation).count() as f64 / self.sites.len() as f64;
metrics.insert("occupation_fraction".to_string(), occupied_fraction);
let defect_density = self
.sites
.values()
.filter(|s| s.defect_type.is_some())
.count() as f64
/ self.sites.len() as f64;
metrics.insert("defect_density".to_string(), defect_density);
metrics
}
fn export_format(&self) -> ApplicationResult<String> {
let mut output = String::new();
output.push_str("# Materials Science Lattice Configuration\n");
let _ = writeln!(output, "Lattice Type: {:?}", self.lattice_type);
let _ = writeln!(output, "Dimensions: {:?}", self.dimensions);
let _ = writeln!(output, "Lattice Constants: {:?}", self.lattice_constants);
let _ = writeln!(output, "Temperature: {:.2} K", self.temperature);
let _ = write!(
output,
"Total Energy: {:.6}\n",
self.calculate_total_energy()
);
let _ = write!(
output,
"Order Parameter: {:.6}\n",
self.calculate_order_parameter()
);
if let Some(field) = self.external_field {
let _ = writeln!(output, "External Field: {field:?}");
}
output.push_str("\n# Site Details\n");
for (pos, site) in &self.sites {
if site.occupation {
let _ = write!(output, "Site ({}, {}, {}): ", pos.x, pos.y, pos.z);
if let Some(ref species) = site.species {
let _ = write!(output, "{} ", species.symbol);
}
if let Some(spin) = site.spin {
let _ = write!(
output,
"spin=({:.3}, {:.3}, {:.3}) ",
spin[0], spin[1], spin[2]
);
}
if let Some(ref defect) = site.defect_type {
let _ = write!(output, "defect={defect:?} ");
}
let _ = write!(output, "energy={:.6}", site.local_energy);
output.push('\n');
}
}
Ok(output)
}
}
pub fn create_benchmark_problems(
size: usize,
) -> ApplicationResult<
Vec<Box<dyn OptimizationProblem<Solution = MaterialsLattice, ObjectiveValue = f64>>>,
> {
let mut problems = Vec::new();
let dimensions = match size {
s if s <= 10 => [4, 4, 1], s if s <= 50 => [5, 5, 2], _ => [8, 8, 2], };
let lattice_types = [
LatticeType::SimpleCubic,
LatticeType::FaceCenteredCubic,
LatticeType::Graphene,
];
for (i, &lattice_type) in lattice_types.iter().enumerate() {
let mut lattice = MaterialsLattice::new(lattice_type, dimensions);
let fe_atom = AtomicSpecies::new("Fe".to_string(), 26, 55.845)
.with_magnetic_moment(2.2)
.with_charge(0.0);
for (pos, site) in &mut lattice.sites {
if (pos.x + pos.y + pos.z) % 2 == 0 {
site.species = Some(fe_atom.clone());
site.occupation = true;
site.spin = Some([0.0, 0.0, 1.0]); }
}
if size > 10 {
let defect_pos = LatticePosition::new(2, 2, 0);
lattice.create_defect(defect_pos, DefectType::Vacancy).ok();
}
let mut problem = MaterialsOptimizationProblem::new(lattice);
match i {
0 => problem = problem.add_objective(MaterialsObjective::MinimizeEnergy),
1 => problem = problem.add_objective(MaterialsObjective::OptimizeMagnetism),
2 => problem = problem.add_objective(MaterialsObjective::MinimizeDefects),
_ => problem = problem.add_objective(MaterialsObjective::MaximizeStability),
}
problems.push(Box::new(problem)
as Box<
dyn OptimizationProblem<Solution = MaterialsLattice, ObjectiveValue = f64>,
>);
}
Ok(problems)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_lattice_creation() {
let lattice = MaterialsLattice::new(LatticeType::SimpleCubic, [3, 3, 3]);
assert_eq!(lattice.sites.len(), 27);
assert_eq!(lattice.dimensions, [3, 3, 3]);
}
#[test]
fn test_atomic_species() {
let fe_atom = AtomicSpecies::new("Fe".to_string(), 26, 55.845)
.with_magnetic_moment(2.2)
.with_charge(2.0);
assert_eq!(fe_atom.symbol, "Fe");
assert_eq!(fe_atom.atomic_number, 26);
assert_eq!(fe_atom.magnetic_moment, Some(2.2));
assert_eq!(fe_atom.charge, 2.0);
}
#[test]
fn test_lattice_neighbors() {
let pos = LatticePosition::new(1, 1, 1);
let neighbors = pos.neighbors(LatticeType::SimpleCubic);
assert_eq!(neighbors.len(), 6); }
#[test]
fn test_defect_creation() {
let mut lattice = MaterialsLattice::new(LatticeType::SimpleCubic, [2, 2, 2]);
let pos = LatticePosition::new(0, 0, 0);
let result = lattice.create_defect(pos, DefectType::Vacancy);
assert!(result.is_ok());
let site = lattice
.sites
.get(&pos)
.expect("site should exist at position after defect creation");
assert!(!site.occupation);
assert!(site.defect_type.is_some());
}
#[test]
fn test_energy_calculation() {
let mut lattice = MaterialsLattice::new(LatticeType::SimpleCubic, [2, 2, 2]);
let fe_atom = AtomicSpecies::new("Fe".to_string(), 26, 55.845);
let pos = LatticePosition::new(0, 0, 0);
lattice
.add_atom(pos, fe_atom)
.expect("should add Fe atom at position");
let energy = lattice.calculate_total_energy();
assert!(energy >= 0.0); }
#[test]
fn test_problem_validation() {
let lattice = MaterialsLattice::new(LatticeType::SimpleCubic, [3, 3, 3]);
let problem = MaterialsOptimizationProblem::new(lattice);
assert!(problem.validate().is_ok());
}
#[test]
fn test_ising_conversion() {
let lattice = MaterialsLattice::new(LatticeType::SimpleCubic, [2, 2, 2]);
let problem = MaterialsOptimizationProblem::new(lattice);
let (ising, variable_map) = problem
.to_ising_model()
.expect("should convert lattice problem to Ising model");
assert_eq!(ising.num_qubits, 8); assert!(!variable_map.is_empty());
}
}