use std::f64::consts::PI;
#[derive(Debug, Clone)]
pub struct TopologicalEdgeState {
pub energy: f64,
pub localization_xi: f64,
pub chirality: i8,
pub gap_center: f64,
}
impl TopologicalEdgeState {
pub fn new(energy: f64, localization_xi: f64, chirality: i8, gap_center: f64) -> Self {
Self {
energy,
localization_xi,
chirality,
gap_center,
}
}
pub fn localization_profile(&self, n_sites: usize) -> Vec<f64> {
if n_sites == 0 || self.localization_xi <= 0.0 {
return vec![0.0; n_sites];
}
let decay_per_site = (-2.0 / self.localization_xi).exp();
let norm = if decay_per_site < 1.0 - 1e-15 {
1.0 - decay_per_site
} else {
1.0 / n_sites as f64
};
(0..n_sites)
.map(|n| norm * ((-2.0 * n as f64) / self.localization_xi).exp())
.collect()
}
pub fn penetration_depth_m(&self, lattice_constant_m: f64) -> f64 {
self.localization_xi * lattice_constant_m
}
pub fn is_midgap(&self, gap_width: f64) -> bool {
(self.energy - self.gap_center).abs() < gap_width / 4.0
}
pub fn is_chiral(&self) -> bool {
self.chirality != 0
}
pub fn backscattering_suppressed(&self) -> bool {
self.is_chiral()
}
}
#[derive(Debug, Clone)]
pub struct PhotonicTopologicalInsulator {
pub n_left: i32,
pub n_right: i32,
pub frequency_gap: (f64, f64),
}
impl PhotonicTopologicalInsulator {
pub fn new(n_left: i32, n_right: i32, frequency_gap: (f64, f64)) -> Self {
Self {
n_left,
n_right,
frequency_gap,
}
}
pub fn n_interface_states(&self) -> i32 {
(self.n_right - self.n_left).abs()
}
pub fn midgap_frequency(&self) -> f64 {
(self.frequency_gap.0 + self.frequency_gap.1) / 2.0
}
pub fn bandwidth_hz(&self) -> f64 {
self.frequency_gap.1 - self.frequency_gap.0
}
pub fn is_protected(&self) -> bool {
self.n_interface_states() > 0
}
pub fn edge_mode_group_velocity(&self, freq_hz: f64) -> f64 {
let _ = freq_hz; let a = 1e-6; let delta_omega = 2.0 * PI * self.bandwidth_hz();
let bz_size = 2.0 * PI / a; delta_omega / bz_size }
pub fn backscattering_suppressed(&self) -> bool {
self.is_protected()
}
pub fn fractional_bandwidth(&self) -> f64 {
let centre = self.midgap_frequency();
if centre.abs() < 1e-30 {
return 0.0;
}
self.bandwidth_hz() / centre
}
}
#[derive(Debug, Clone)]
pub struct AnomalousQhpc {
pub lattice: &'static str,
pub chern_number: i32,
pub band_gap_fraction: f64,
}
impl AnomalousQhpc {
pub fn new(lattice: &'static str, chern_number: i32, band_gap_fraction: f64) -> Self {
Self {
lattice,
chern_number,
band_gap_fraction,
}
}
pub fn honeycomb_gyrotropic() -> Self {
Self {
lattice: "honeycomb",
chern_number: 1,
band_gap_fraction: 0.10,
}
}
pub fn kagome_flat_band() -> Self {
Self {
lattice: "kagome",
chern_number: 1,
band_gap_fraction: 0.05,
}
}
pub fn square_double_chern() -> Self {
Self {
lattice: "square",
chern_number: 2,
band_gap_fraction: 0.08,
}
}
pub fn unidirectional_edge_mode_count(&self) -> i32 {
self.chern_number.abs()
}
pub fn transmission_backscattering_immune(&self) -> bool {
self.chern_number != 0
}
pub fn is_topologically_non_trivial(&self) -> bool {
self.chern_number != 0
}
pub fn edge_mode_q_factor(&self) -> f64 {
if self.band_gap_fraction < 1e-15 {
return 0.0;
}
1.0 / self.band_gap_fraction
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn edge_state_localization_profile_normalised() {
let state = TopologicalEdgeState::new(0.0, 3.0, 1, 0.0);
let profile = state.localization_profile(50);
let total: f64 = profile.iter().sum();
assert!((total - 1.0).abs() < 0.05, "Total probability = {total}");
}
#[test]
fn edge_state_profile_decays_exponentially() {
let state = TopologicalEdgeState::new(0.0, 2.0, 1, 0.0);
let profile = state.localization_profile(20);
for i in 1..profile.len() {
assert!(
profile[i] <= profile[i - 1] + 1e-15,
"Profile not monotone at index {i}: {} > {}",
profile[i],
profile[i - 1]
);
}
}
#[test]
fn edge_state_penetration_depth() {
let state = TopologicalEdgeState::new(0.0, 4.0, 1, 0.0);
let a = 500e-9; let depth = state.penetration_depth_m(a);
assert!((depth - 4.0 * a).abs() < 1e-20, "depth = {depth}");
}
#[test]
fn edge_state_is_midgap() {
let state = TopologicalEdgeState::new(0.05, 3.0, 1, 0.0);
assert!(state.is_midgap(1.0)); assert!(!state.is_midgap(0.1)); }
#[test]
fn edge_state_chirality() {
let chiral = TopologicalEdgeState::new(0.0, 3.0, 1, 0.0);
let non_chiral = TopologicalEdgeState::new(0.0, 3.0, 0, 0.0);
assert!(chiral.is_chiral());
assert!(chiral.backscattering_suppressed());
assert!(!non_chiral.is_chiral());
assert!(!non_chiral.backscattering_suppressed());
}
#[test]
fn pti_n_interface_states() {
let pti = PhotonicTopologicalInsulator::new(0, 1, (190e12, 210e12));
assert_eq!(pti.n_interface_states(), 1);
}
#[test]
fn pti_n_interface_states_chern_difference() {
let pti = PhotonicTopologicalInsulator::new(-1, 2, (190e12, 210e12));
assert_eq!(pti.n_interface_states(), 3);
}
#[test]
fn pti_midgap_frequency() {
let pti = PhotonicTopologicalInsulator::new(0, 1, (190e12, 210e12));
assert!((pti.midgap_frequency() - 200e12).abs() < 1e6);
}
#[test]
fn pti_is_protected() {
let protected = PhotonicTopologicalInsulator::new(0, 1, (190e12, 210e12));
let trivial = PhotonicTopologicalInsulator::new(1, 1, (190e12, 210e12));
assert!(protected.is_protected());
assert!(!trivial.is_protected());
}
#[test]
fn pti_bandwidth() {
let pti = PhotonicTopologicalInsulator::new(0, 1, (190e12, 210e12));
assert!((pti.bandwidth_hz() - 20e12).abs() < 1.0);
}
#[test]
fn pti_group_velocity_positive() {
let pti = PhotonicTopologicalInsulator::new(0, 1, (190e12, 210e12));
let vg = pti.edge_mode_group_velocity(200e12);
assert!(vg > 0.0, "Group velocity should be positive, got {vg}");
}
#[test]
fn aqhpc_honeycomb_gyrotropic() {
let phc = AnomalousQhpc::honeycomb_gyrotropic();
assert_eq!(phc.lattice, "honeycomb");
assert_eq!(phc.chern_number, 1);
assert!(phc.transmission_backscattering_immune());
}
#[test]
fn aqhpc_unidirectional_edge_modes() {
let phc = AnomalousQhpc::square_double_chern();
assert_eq!(phc.unidirectional_edge_mode_count(), 2);
}
#[test]
fn aqhpc_q_factor_positive() {
let phc = AnomalousQhpc::honeycomb_gyrotropic();
let q = phc.edge_mode_q_factor();
assert!(q > 0.0, "Q factor should be positive, got {q}");
}
}