Skip to main content

qualia_core_db/
quantum_dft.rs

1//! Quantum Chemistry & Density Functional Theory (DFT)
2//! Bounded pure Rust approximations replacing external C-FFI quantum solvers.
3//! Enhanced with orthomodular lattice operations for quantum propositional logic.
4
5use crate::NQuin;
6use std::collections::HashMap;
7
8/// Represents a bounded electron density approximation matrix.
9pub struct ElectronDensity {
10    pub grid_resolution: usize,
11    pub density_matrix: Vec<f64>,
12}
13
14impl ElectronDensity {
15    pub fn new(resolution: usize) -> Self {
16        Self {
17            grid_resolution: resolution,
18            density_matrix: vec![0.0; resolution * resolution * resolution],
19        }
20    }
21
22    /// Thomas-Fermi orbital-free DFT with LDA exchange on a 3D cubic grid.
23    /// Runs a self-consistent field (SCF) loop until the total energy converges.
24    pub fn calculate_ground_state_energy(&mut self, quins: &[NQuin]) -> f64 {
25        let n_electrons = quins
26            .iter()
27            .filter(|q| q.predicate == crate::q_hash("HAS_ELECTRON"))
28            .count();
29        if n_electrons == 0 {
30            return 0.0;
31        }
32
33        let n = n_electrons as f64;
34        let z = n; // Neutral atom: nuclear charge Z = N
35        let res = self.grid_resolution.max(2);
36        let grid_size = res * res * res;
37
38        // Physical box: L³ bohr, centred on nucleus; L = 12 Z^(1/3) captures >99% of TF density
39        let l: f64 = 12.0 * z.powf(1.0 / 3.0);
40        let h: f64 = l / (res as f64);
41        let dv: f64 = h * h * h;
42
43        // Thomas-Fermi kinetic energy constant:  C_TF = (3/10)(3π²)^(2/3) a.u.
44        let c_tf: f64 = 0.3 * (3.0 * std::f64::consts::PI * std::f64::consts::PI).powf(2.0 / 3.0);
45        // Dirac–Slater exchange constant: C_X = -(3/4)(3/π)^(1/3) a.u.
46        let c_x: f64 = -(3.0 / 4.0) * (3.0 / std::f64::consts::PI).powf(1.0 / 3.0);
47
48        // Precompute |r| at every grid point (nucleus at box centre)
49        let ctr = l / 2.0;
50        let r_grid: Vec<f64> = (0..grid_size)
51            .map(|idx| {
52                let iz = idx / (res * res);
53                let iy = (idx / res) % res;
54                let ix = idx % res;
55                let rx = (ix as f64 + 0.5) * h - ctr;
56                let ry = (iy as f64 + 0.5) * h - ctr;
57                let rz = (iz as f64 + 0.5) * h - ctr;
58                (rx * rx + ry * ry + rz * rz).sqrt().max(h * 0.5) // clamp to avoid r = 0
59            })
60            .collect();
61
62        // Initialise with hydrogen-like exponential decay, normalised to N electrons
63        let alpha = 2.0 * z;
64        let raw_sum: f64 = r_grid.iter().map(|&r| (-alpha * r).exp()).sum::<f64>() * dv;
65        self.density_matrix = r_grid
66            .iter()
67            .map(|&r| (-alpha * r).exp() * n / raw_sum.max(1e-30))
68            .collect();
69
70        let max_iter = 100usize;
71        let mix = 0.40_f64;
72        let tol = 1e-9_f64;
73        let mut prev_e = f64::MAX;
74
75        for _iter in 0..max_iter {
76            // Enforce N-electron normalisation
77            let norm: f64 = self.density_matrix.iter().sum::<f64>() * dv;
78            if norm > 1e-30 {
79                let s = n / norm;
80                self.density_matrix.iter_mut().for_each(|r| *r *= s);
81            }
82
83            // ── Energy components ────────────────────────────────────────────
84            let t_tf: f64 = self
85                .density_matrix
86                .iter()
87                .map(|&rho| c_tf * rho.powf(5.0 / 3.0))
88                .sum::<f64>()
89                * dv;
90            let e_xc: f64 = self
91                .density_matrix
92                .iter()
93                .map(|&rho| c_x * rho.powf(4.0 / 3.0))
94                .sum::<f64>()
95                * dv;
96            let e_ne: f64 = r_grid
97                .iter()
98                .zip(self.density_matrix.iter())
99                .map(|(&r, &rho)| (-z / r) * rho)
100                .sum::<f64>()
101                * dv;
102            // Mean-field Hartree: classical self-energy of uniform sphere of charge N
103            let rho_avg = n / (l * l * l);
104            let r_ws = (3.0 / (4.0 * std::f64::consts::PI * rho_avg)).powf(1.0 / 3.0);
105            let e_h = 0.5 * n * n / r_ws;
106
107            let e_total_ha = t_tf + e_xc + e_ne + e_h;
108            let e_total_ev = e_total_ha * 27.2114; // Hartree → eV
109
110            if (e_total_ev - prev_e).abs() < tol {
111                return e_total_ev;
112            }
113            prev_e = e_total_ev;
114
115            // ── Density update via TF inversion ─────────────────────────────
116            // Chemical potential μ: set from the average-density point
117            let v_tf_avg = (5.0 / 3.0) * c_tf * rho_avg.powf(2.0 / 3.0);
118            let v_xc_avg = (4.0 / 3.0) * c_x * rho_avg.powf(1.0 / 3.0);
119            let mu = v_tf_avg + v_xc_avg + n / r_ws - z / r_ws; // v_H + v_ne cancel for neutral atom
120
121            // ρ_new(r) = [(μ − v_eff(r)) / ((5/3)C_TF)]^(3/2), clamped to ≥ 0
122            let new_rho: Vec<f64> = r_grid
123                .iter()
124                .zip(self.density_matrix.iter())
125                .map(|(&r, &rho_i)| {
126                    let v_xc_i = (4.0 / 3.0) * c_x * rho_i.powf(1.0 / 3.0);
127                    let v_eff_i = (-z / r) + (n / r_ws) + v_xc_i;
128                    let arg = (mu - v_eff_i) / ((5.0 / 3.0) * c_tf);
129                    if arg > 0.0 {
130                        arg.powf(1.5)
131                    } else {
132                        0.0
133                    }
134                })
135                .collect();
136
137            // Linear mixing to stabilise convergence
138            for (rho, rho_new) in self.density_matrix.iter_mut().zip(new_rho.iter()) {
139                *rho = (1.0 - mix) * *rho + mix * rho_new;
140            }
141        }
142
143        prev_e
144    }
145}
146
147/// Orthomodular lattice for quantum propositional logic
148/// Implements non-distributive quantum logic with orthocomplementation
149#[derive(Debug, Clone, PartialEq, Eq)]
150pub struct QuantumLattice {
151    pub propositions: HashMap<u64, QuantumProposition>,
152    pub lattice_order: Vec<u64>, // Partial order representation
153}
154
155#[derive(Debug, Clone, PartialEq, Eq)]
156pub struct QuantumProposition {
157    pub id: u64,
158    pub truth_value: QuantumTruthValue,
159    pub orthocomplement: Option<u64>, // Reference to orthocomplement proposition
160    pub measurement_basis: String,
161}
162
163#[derive(Debug, Clone, PartialEq, Eq)]
164pub enum QuantumTruthValue {
165    True,
166    False,
167    Superposed, // Quantum superposition state
168    Uncertain,  // Measurement uncertainty
169}
170
171impl QuantumLattice {
172    /// Create a new quantum lattice with orthomodular structure
173    pub fn new() -> Self {
174        Self {
175            propositions: HashMap::new(),
176            lattice_order: Vec::new(),
177        }
178    }
179
180    /// Add a quantum proposition to the lattice
181    pub fn add_proposition(&mut self, prop: QuantumProposition) {
182        self.lattice_order.push(prop.id);
183        self.propositions.insert(prop.id, prop);
184    }
185
186    /// Compute orthocomplement of a proposition (quantum NOT)
187    pub fn orthocomplement(&self, prop_id: u64) -> Option<u64> {
188        self.propositions.get(&prop_id)?.orthocomplement
189    }
190
191    /// Check if two propositions are compatible (commuting observables)
192    pub fn are_compatible(&self, prop1_id: u64, prop2_id: u64) -> bool {
193        if let (Some(prop1), Some(prop2)) = (
194            self.propositions.get(&prop1_id),
195            self.propositions.get(&prop2_id),
196        ) {
197            // propositions are compatible if they share the same measurement basis
198            prop1.measurement_basis == prop2.measurement_basis
199        } else {
200            false
201        }
202    }
203
204    /// Quantum AND operation (meet in orthomodular lattice)
205    pub fn quantum_and(&self, prop1_id: u64, prop2_id: u64) -> Option<u64> {
206        // For compatible propositions, use classical AND
207        if self.are_compatible(prop1_id, prop2_id) {
208            if let (Some(prop1), Some(prop2)) = (
209                self.propositions.get(&prop1_id),
210                self.propositions.get(&prop2_id),
211            ) {
212                match (&prop1.truth_value, &prop2.truth_value) {
213                    (QuantumTruthValue::True, QuantumTruthValue::True) => Some(prop1_id),
214                    _ => self.orthocomplement(prop1_id), // Simplified quantum logic
215                }
216            } else {
217                None
218            }
219        } else {
220            // For incompatible propositions, result is undefined in quantum logic
221            None
222        }
223    }
224
225    /// Quantum OR operation (join in orthomodular lattice)
226    pub fn quantum_or(&self, prop1_id: u64, prop2_id: u64) -> Option<u64> {
227        if self.are_compatible(prop1_id, prop2_id) {
228            if let (Some(prop1), Some(prop2)) = (
229                self.propositions.get(&prop1_id),
230                self.propositions.get(&prop2_id),
231            ) {
232                match (&prop1.truth_value, &prop2.truth_value) {
233                    (QuantumTruthValue::True, _) | (_, QuantumTruthValue::True) => Some(prop1_id),
234                    _ => self.orthocomplement(prop2_id),
235                }
236            } else {
237                None
238            }
239        } else {
240            None
241        }
242    }
243
244    /// Apply measurement to collapse superposition
245    pub fn measure(&mut self, prop_id: u64) -> Option<QuantumTruthValue> {
246        if let Some(prop) = self.propositions.get_mut(&prop_id) {
247            match prop.truth_value {
248                QuantumTruthValue::Superposed => {
249                    // Deterministic collapse on proposition-id parity (NOT a
250                    // probabilistic 50/50 measurement — this is a toy
251                    // orthomodular-logic model, not a physical simulator).
252                    prop.truth_value = if (prop.id % 2) == 0 {
253                        QuantumTruthValue::True
254                    } else {
255                        QuantumTruthValue::False
256                    };
257                    Some(prop.truth_value.clone())
258                }
259                _ => Some(prop.truth_value.clone()),
260            }
261        } else {
262            None
263        }
264    }
265}
266
267/// Convert quantum lattice state to NQuin for storage
268pub fn quantum_lattice_to_quin(lattice: &QuantumLattice, context: u64) -> Vec<NQuin> {
269    let mut quins = Vec::new();
270
271    for (id, prop) in &lattice.propositions {
272        let mut quin = NQuin {
273            subject: *id,
274            predicate: crate::q_hash("has_quantum_state"),
275            object: match prop.truth_value {
276                QuantumTruthValue::True => 1,
277                QuantumTruthValue::False => 0,
278                QuantumTruthValue::Superposed => 2,
279                QuantumTruthValue::Uncertain => 3,
280            },
281            context,
282            metadata: 0,
283            parity: 0,
284        };
285
286        // Set orthocomplement in metadata if present
287        if let Some(ortho_id) = prop.orthocomplement {
288            quin.metadata = ortho_id;
289        }
290
291        quin.parity = quin.subject ^ quin.predicate ^ quin.object ^ quin.context;
292        quins.push(quin);
293    }
294
295    quins
296}
297
298/// Predicts physical states natively using a bounded Physics-Informed Neural Network (PINN) abstraction.
299pub fn pinn_predict_receptor_binding(molecule_quins: &[NQuin], receptor_quins: &[NQuin]) -> f64 {
300    // Pure Rust semantic graph evaluation simulating a trained localized model binding affinity
301    if molecule_quins.is_empty() || receptor_quins.is_empty() {
302        return 0.0;
303    }
304
305    // Mock binding affinity calculation
306    let mut affinity = -5.0; // kcal/mol base
307    for mq in molecule_quins {
308        for rq in receptor_quins {
309            if mq.predicate == rq.predicate {
310                affinity -= 1.2; // Affinity increases (becomes more negative) for geometric matches
311            }
312        }
313    }
314    affinity
315}
316
317#[cfg(test)]
318mod tests {
319    use super::*;
320
321    #[test]
322    fn test_quantum_lattice_creation() {
323        let mut lattice = QuantumLattice::new();
324
325        let prop_a = QuantumProposition {
326            id: 1,
327            truth_value: QuantumTruthValue::True,
328            orthocomplement: Some(2),
329            measurement_basis: "computational".to_string(),
330        };
331
332        let prop_b = QuantumProposition {
333            id: 2,
334            truth_value: QuantumTruthValue::False,
335            orthocomplement: Some(1),
336            measurement_basis: "computational".to_string(),
337        };
338
339        lattice.add_proposition(prop_a);
340        lattice.add_proposition(prop_b);
341
342        assert_eq!(lattice.propositions.len(), 2);
343        assert_eq!(lattice.orthocomplement(1), Some(2));
344        assert_eq!(lattice.orthocomplement(2), Some(1));
345    }
346
347    #[test]
348    fn test_quantum_compatibility() {
349        let mut lattice = QuantumLattice::new();
350
351        let prop_x = QuantumProposition {
352            id: 10,
353            truth_value: QuantumTruthValue::Superposed,
354            orthocomplement: Some(11),
355            measurement_basis: "pauli_x".to_string(),
356        };
357
358        let prop_z = QuantumProposition {
359            id: 20,
360            truth_value: QuantumTruthValue::Superposed,
361            orthocomplement: Some(21),
362            measurement_basis: "pauli_z".to_string(),
363        };
364
365        lattice.add_proposition(prop_x);
366        lattice.add_proposition(prop_z);
367
368        // Same basis propositions should be compatible
369        assert!(lattice.are_compatible(10, 10));
370
371        // Different basis propositions should be incompatible
372        assert!(!lattice.are_compatible(10, 20));
373    }
374
375    #[test]
376    fn test_quantum_measurement() {
377        let mut lattice = QuantumLattice::new();
378
379        let prop = QuantumProposition {
380            id: 100,
381            truth_value: QuantumTruthValue::Superposed,
382            orthocomplement: None,
383            measurement_basis: "test".to_string(),
384        };
385
386        lattice.add_proposition(prop);
387
388        // Measurement should collapse superposition
389        let result = lattice.measure(100);
390        assert!(result.is_some());
391        assert!(result.unwrap() != QuantumTruthValue::Superposed);
392    }
393
394    #[test]
395    fn test_quantum_operations() {
396        let mut lattice = QuantumLattice::new();
397
398        let prop_true = QuantumProposition {
399            id: 1,
400            truth_value: QuantumTruthValue::True,
401            orthocomplement: Some(2),
402            measurement_basis: "test".to_string(),
403        };
404
405        let prop_false = QuantumProposition {
406            id: 2,
407            truth_value: QuantumTruthValue::False,
408            orthocomplement: Some(1),
409            measurement_basis: "test".to_string(),
410        };
411
412        lattice.add_proposition(prop_true);
413        lattice.add_proposition(prop_false);
414
415        // Test quantum AND
416        let and_result = lattice.quantum_and(1, 1);
417        assert_eq!(and_result, Some(1)); // True AND True = True
418
419        // Test quantum OR
420        let or_result = lattice.quantum_or(1, 2);
421        assert_eq!(or_result, Some(1)); // True OR False = True
422    }
423
424    #[test]
425    fn test_quantum_lattice_to_quin() {
426        let mut lattice = QuantumLattice::new();
427
428        let prop = QuantumProposition {
429            id: 42,
430            truth_value: QuantumTruthValue::Superposed,
431            orthocomplement: Some(43),
432            measurement_basis: "test".to_string(),
433        };
434
435        lattice.add_proposition(prop);
436
437        let quins = quantum_lattice_to_quin(&lattice, 123);
438        assert_eq!(quins.len(), 1);
439
440        let quin = &quins[0];
441        assert_eq!(quin.subject, 42);
442        assert_eq!(quin.object, 2); // Superposed = 2
443        assert_eq!(quin.context, 123);
444        assert_eq!(quin.metadata, 43); // orthocomplement stored in metadata
445    }
446}