Skip to main content

pacr_types/
ets.rs

1//! Pillar: II. PACR field: Ω (Resource Triple).
2//!
3//! Three physically coupled resource axes that cannot be simultaneously
4//! minimised — the Energy-Time-Space trilemma:
5//!
6//!   E — energy consumed (joules)          conservation of energy
7//!   T — execution time (seconds)          Margolus–Levitin: T ≥ πℏ/2E
8//!   S — memory/storage used (bytes)       Bremermann / Holevo–von Neumann
9//!
10//! These three axes lie on a 2-D constraint surface, not three independent axes.
11//! Storing them together as `ResourceTriple` makes their coupling explicit and
12//! enables the Margolus–Levitin consistency check at every append.
13
14use crate::estimate::Estimate;
15use crate::landauer::LandauerCost;
16use crate::landauer::H_BAR;
17
18// ── Core type ─────────────────────────────────────────────────────────────────
19
20/// The resource constraint triple (E, T, S) for a computation event.
21///
22/// All three values use `Estimate<f64>` to carry measurement uncertainty.
23/// See [`ResourceTriple::validate_physics`] for the physical consistency checks.
24///
25/// PACR field Ω. Derived from Pillar II (conservation laws + Margolus–Levitin).
26#[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)]
27pub struct ResourceTriple {
28    /// Actual energy consumed (joules). Must satisfy `energy.point ≥ Λ.point`.
29    pub energy: Estimate<f64>,
30    /// Actual execution duration (seconds). Must satisfy Margolus–Levitin bound.
31    pub time: Estimate<f64>,
32    /// Actual memory/storage used (bytes, as f64 for SI-unit consistency).
33    pub space: Estimate<f64>,
34}
35
36impl ResourceTriple {
37    /// Validates physical consistency of this triple.
38    ///
39    /// Returns every violation found; an empty `Vec` means the record is clean.
40    /// A physically invalid record is still storable (measurement errors happen),
41    /// but violations must be flagged for the Landauer auditor to investigate.
42    #[must_use]
43    pub fn validate_physics(&self) -> Vec<PhysicsViolation> {
44        let mut v: Vec<PhysicsViolation> = Vec::new();
45
46        if self.energy.point < 0.0 {
47            v.push(PhysicsViolation::NegativeEnergy);
48        }
49        if self.time.point <= 0.0 {
50            v.push(PhysicsViolation::NonPositiveTime);
51        }
52        if self.space.point < 0.0 {
53            v.push(PhysicsViolation::NegativeSpace);
54        }
55
56        // Margolus–Levitin: T ≥ π·ℏ / (2·E)
57        // Checked for completeness; macroscopically relevant at femtojoule scale
58        // and for future sub-quantum extensions.
59        if self.energy.point > 0.0 {
60            let t_min = std::f64::consts::PI * H_BAR / (2.0 * self.energy.point);
61            if self.time.point < t_min {
62                v.push(PhysicsViolation::MargolusLevitinViolated {
63                    actual_s: self.time.point,
64                    minimum_s: t_min,
65                });
66            }
67        }
68
69        v
70    }
71
72    /// Thermodynamic waste = E − Λ with conservative uncertainty propagation.
73    ///
74    /// Uncertainty is propagated as:
75    ///   `waste.lower = energy.lower − λ.upper`  (minimum possible waste)
76    ///   `waste.upper = energy.upper − λ.lower`  (maximum possible waste)
77    #[must_use]
78    pub fn thermodynamic_waste(&self, landauer: &LandauerCost) -> Estimate<f64> {
79        Estimate {
80            point: self.energy.point - landauer.point,
81            lower: self.energy.lower - landauer.upper,
82            upper: self.energy.upper - landauer.lower,
83        }
84    }
85}
86
87// ── Violation enum ────────────────────────────────────────────────────────────
88
89/// A physical-law violation detected in a [`ResourceTriple`].
90#[derive(Debug, Clone, thiserror::Error)]
91#[non_exhaustive]
92pub enum PhysicsViolation {
93    /// Energy is negative — violates conservation of energy.
94    #[error("energy is negative — violates conservation of energy")]
95    NegativeEnergy,
96
97    /// Time is non-positive — violates causality.
98    #[error("time is non-positive — violates causality")]
99    NonPositiveTime,
100
101    /// Space is negative — physically impossible.
102    #[error("space is negative — physically impossible")]
103    NegativeSpace,
104
105    /// Margolus–Levitin theorem violated: T < π·ℏ / (2·E).
106    #[error("Margolus–Levitin violated: T={actual_s:.3e} s < T_min={minimum_s:.3e} s")]
107    MargolusLevitinViolated {
108        /// Measured execution time (seconds).
109        actual_s: f64,
110        /// Minimum allowed time (seconds) at this energy.
111        minimum_s: f64,
112    },
113}
114
115// ── Unit tests ────────────────────────────────────────────────────────────────
116
117#[cfg(test)]
118mod tests {
119    use super::*;
120    use crate::estimate::Estimate;
121
122    fn valid_triple() -> ResourceTriple {
123        ResourceTriple {
124            energy: Estimate::exact(1e-19),
125            time: Estimate::exact(1e-9),
126            space: Estimate::exact(128.0),
127        }
128    }
129
130    #[test]
131    fn valid_triple_has_no_violations() {
132        assert!(valid_triple().validate_physics().is_empty());
133    }
134
135    #[test]
136    fn negative_energy_is_flagged() {
137        let mut t = valid_triple();
138        t.energy = Estimate {
139            point: -1.0,
140            lower: -2.0,
141            upper: 0.0,
142        };
143        let v = t.validate_physics();
144        assert!(v
145            .iter()
146            .any(|e| matches!(e, PhysicsViolation::NegativeEnergy)));
147    }
148
149    #[test]
150    fn zero_time_is_flagged() {
151        let mut t = valid_triple();
152        t.time = Estimate::exact(0.0);
153        let v = t.validate_physics();
154        assert!(v
155            .iter()
156            .any(|e| matches!(e, PhysicsViolation::NonPositiveTime)));
157    }
158
159    #[test]
160    fn negative_space_is_flagged() {
161        let mut t = valid_triple();
162        t.space = Estimate {
163            point: -1.0,
164            lower: -2.0,
165            upper: 0.0,
166        };
167        let v = t.validate_physics();
168        assert!(v
169            .iter()
170            .any(|e| matches!(e, PhysicsViolation::NegativeSpace)));
171    }
172
173    #[test]
174    fn thermodynamic_waste_propagates_uncertainty() {
175        let triple = ResourceTriple {
176            energy: Estimate::new(1e-19, 0.8e-19, 1.2e-19).unwrap(),
177            time: Estimate::exact(1e-9),
178            space: Estimate::exact(0.0),
179        };
180        let lambda = Estimate::new(1e-20, 0.5e-20, 2.0e-20).unwrap();
181        let waste = triple.thermodynamic_waste(&lambda);
182
183        assert!((waste.point - (1e-19 - 1e-20)).abs() < 1e-30);
184        // lower = energy.lower - lambda.upper = 0.8e-19 - 2.0e-20
185        assert!((waste.lower - (0.8e-19 - 2.0e-20)).abs() < 1e-30);
186        // upper = energy.upper - lambda.lower = 1.2e-19 - 0.5e-20
187        assert!((waste.upper - (1.2e-19 - 0.5e-20)).abs() < 1e-30);
188    }
189}