|
|
|
|
|
|
|
|
|
|
|
|
| use std::fmt;
|
|
|
| #[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
| pub enum Strand {
|
| Curry,
|
| Crystal,
|
| C3,
|
| }
|
|
|
| #[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
| pub enum CrossingSign {
|
| Positive,
|
| Negative,
|
| }
|
|
|
| #[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
| pub enum Generator {
|
| Sigma1,
|
| Sigma2,
|
| Sigma1Inv,
|
| Sigma2Inv,
|
| Sigma12,
|
| Identity,
|
| }
|
|
|
| impl Generator {
|
| pub fn sign(&self) -> CrossingSign {
|
| match self {
|
| Generator::Sigma1 => CrossingSign::Positive,
|
| Generator::Sigma2 => CrossingSign::Positive,
|
| Generator::Sigma12 => CrossingSign::Positive,
|
| Generator::Identity => CrossingSign::Positive,
|
| Generator::Sigma1Inv => CrossingSign::Negative,
|
| Generator::Sigma2Inv => CrossingSign::Negative,
|
| }
|
| }
|
|
|
| pub fn writhe_contribution(&self) -> i32 {
|
| match self.sign() {
|
| CrossingSign::Positive => 1,
|
| CrossingSign::Negative => -1,
|
| }
|
| }
|
| }
|
|
|
| #[derive(Debug, Clone)]
|
| pub struct Crossing {
|
| pub generator: Generator,
|
| pub over_strand: Strand,
|
| pub under_strand: Strand,
|
| pub entropy: f32,
|
| pub rule_name: &'static str,
|
| }
|
|
|
| #[derive(Debug, Clone)]
|
| pub struct BraidState {
|
| pub positions: [Strand; 3],
|
| pub crossings: Vec<Crossing>,
|
| pub writhe: i32,
|
| }
|
|
|
| impl BraidState {
|
| pub fn new() -> Self {
|
| Self {
|
| positions: [Strand::Curry, Strand::Crystal, Strand::C3],
|
| crossings: Vec::new(),
|
| writhe: 0,
|
| }
|
| }
|
|
|
| pub fn apply_crossing(&mut self, crossing: Crossing) -> Result<(), BraidError> {
|
|
|
| if crossing.entropy > 0.20 {
|
| return Err(BraidError::EntropyExceeded {
|
| value: crossing.entropy,
|
| at_crossing: crossing.generator,
|
| });
|
| }
|
|
|
|
|
| match crossing.generator {
|
| Generator::Sigma1 => {
|
| self.positions.swap(0, 1);
|
| }
|
| Generator::Sigma2 => {
|
| self.positions.swap(1, 2);
|
| }
|
| Generator::Sigma1Inv => {
|
| self.positions.swap(0, 1);
|
| }
|
| Generator::Sigma2Inv => {
|
| self.positions.swap(1, 2);
|
| }
|
| Generator::Sigma12 => {
|
| self.positions.swap(0, 1);
|
| self.positions.swap(1, 2);
|
| }
|
| Generator::Identity => {}
|
| }
|
|
|
| self.writhe += crossing.generator.writhe_contribution();
|
| self.crossings.push(crossing);
|
| Ok(())
|
| }
|
|
|
| pub fn authority_holder(&self) -> Strand {
|
| self.positions[0]
|
| }
|
|
|
| pub fn verify_invariant(&self) -> Result<BraidProof, BraidError> {
|
| if self.writhe < 2 {
|
| return Err(BraidError::WritheInsufficient {
|
| expected: 2,
|
| actual: self.writhe,
|
| });
|
| }
|
|
|
| if self.authority_holder() != Strand::C3 {
|
| return Err(BraidError::AuthorityNotTransferred {
|
| holder: self.authority_holder(),
|
| });
|
| }
|
|
|
|
|
| for window in self.crossings.windows(2) {
|
| if cancels(&window[0].generator, &window[1].generator) {
|
| return Err(BraidError::TrivialCrossing);
|
| }
|
| }
|
|
|
| Ok(BraidProof {
|
| word_length: self.crossings.len(),
|
| writhe: self.writhe,
|
| authority: self.authority_holder(),
|
| final_positions: self.positions,
|
| })
|
| }
|
|
|
| pub fn canonical_pipeline() -> Vec<Crossing> {
|
|
|
|
|
| vec![
|
| Crossing {
|
| generator: Generator::Sigma2,
|
| over_strand: Strand::C3,
|
| under_strand: Strand::Crystal,
|
| entropy: 0.0,
|
| rule_name: "R2_NATIVE_BINDING",
|
| },
|
| Crossing {
|
| generator: Generator::Sigma1,
|
| over_strand: Strand::C3,
|
| under_strand: Strand::Curry,
|
| entropy: 0.0,
|
| rule_name: "R1_FFI_C_ABI",
|
| },
|
| ]
|
| }
|
| }
|
|
|
| fn cancels(a: &Generator, b: &Generator) -> bool {
|
| matches!(
|
| (a, b),
|
| (Generator::Sigma1, Generator::Sigma1Inv)
|
| | (Generator::Sigma1Inv, Generator::Sigma1)
|
| | (Generator::Sigma2, Generator::Sigma2Inv)
|
| | (Generator::Sigma2Inv, Generator::Sigma2)
|
| )
|
| }
|
|
|
| #[derive(Debug)]
|
| pub struct BraidProof {
|
| pub word_length: usize,
|
| pub writhe: i32,
|
| pub authority: Strand,
|
| pub final_positions: [Strand; 3],
|
| }
|
|
|
| impl fmt::Display for BraidProof {
|
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
| writeln!(f, "BRAID PROOF — CARRY PIPELINE")?;
|
| writeln!(f, " Word length: {}", self.word_length)?;
|
| writeln!(f, " Writhe: {} (≥2 required)", self.writhe)?;
|
| writeln!(f, " Authority: {:?} (position 0)", self.authority)?;
|
| writeln!(f, " Positions: {:?}", self.final_positions)?;
|
| writeln!(f, " Status: INVARIANT HOLDS")
|
| }
|
| }
|
|
|
| #[derive(Debug)]
|
| pub enum BraidError {
|
| EntropyExceeded { value: f32, at_crossing: Generator },
|
| WritheInsufficient { expected: i32, actual: i32 },
|
| AuthorityNotTransferred { holder: Strand },
|
| TrivialCrossing,
|
| }
|
|
|
| impl fmt::Display for BraidError {
|
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
| match self {
|
| BraidError::EntropyExceeded { value, at_crossing } => {
|
| write!(f, "ENTROPY_GATE: {:.3} > 0.20 at {:?}", value, at_crossing)
|
| }
|
| BraidError::WritheInsufficient { expected, actual } => {
|
| write!(f, "WRITHE_VIOLATION: {} < {} (authority not fully transferred)", actual, expected)
|
| }
|
| BraidError::AuthorityNotTransferred { holder } => {
|
| write!(f, "AUTHORITY_VIOLATION: {:?} holds position 0, expected C3", holder)
|
| }
|
| BraidError::TrivialCrossing => {
|
| write!(f, "TRIVIAL_CROSSING: σ·σ⁻¹ detected (Reidemeister-I cancellation)")
|
| }
|
| }
|
| }
|
| }
|
|
|
| #[cfg(test)]
|
| mod tests {
|
| use super::*;
|
|
|
| #[test]
|
| fn canonical_pipeline_proves() {
|
| let mut braid = BraidState::new();
|
| for crossing in BraidState::canonical_pipeline() {
|
| braid.apply_crossing(crossing).unwrap();
|
| }
|
| let proof = braid.verify_invariant().unwrap();
|
| assert_eq!(proof.authority, Strand::C3);
|
| assert_eq!(proof.writhe, 2);
|
| assert_eq!(proof.final_positions, [Strand::C3, Strand::Curry, Strand::Crystal]);
|
| }
|
|
|
| #[test]
|
| fn entropy_gate_blocks() {
|
| let mut braid = BraidState::new();
|
| let bad_crossing = Crossing {
|
| generator: Generator::Sigma1,
|
| over_strand: Strand::Curry,
|
| under_strand: Strand::Crystal,
|
| entropy: 0.50,
|
| rule_name: "BAD",
|
| };
|
| assert!(braid.apply_crossing(bad_crossing).is_err());
|
| }
|
|
|
| #[test]
|
| fn inverse_cancellation_detected() {
|
| let mut braid = BraidState::new();
|
| let crossings = vec![
|
| Crossing {
|
| generator: Generator::Sigma1,
|
| over_strand: Strand::Curry,
|
| under_strand: Strand::Crystal,
|
| entropy: 0.1,
|
| rule_name: "R1",
|
| },
|
| Crossing {
|
| generator: Generator::Sigma1Inv,
|
| over_strand: Strand::Crystal,
|
| under_strand: Strand::Curry,
|
| entropy: 0.1,
|
| rule_name: "R1_INV",
|
| },
|
| Crossing {
|
| generator: Generator::Sigma2,
|
| over_strand: Strand::Crystal,
|
| under_strand: Strand::C3,
|
| entropy: 0.1,
|
| rule_name: "R2",
|
| },
|
| ];
|
| for c in crossings {
|
| let _ = braid.apply_crossing(c);
|
| }
|
| assert!(braid.verify_invariant().is_err());
|
| }
|
|
|
| #[test]
|
| fn authority_transfer_correct() {
|
| let mut braid = BraidState::new();
|
| assert_eq!(braid.authority_holder(), Strand::Curry);
|
|
|
|
|
| braid.apply_crossing(Crossing {
|
| generator: Generator::Sigma2,
|
| over_strand: Strand::C3,
|
| under_strand: Strand::Crystal,
|
| entropy: 0.05,
|
| rule_name: "R2",
|
| }).unwrap();
|
| assert_eq!(braid.positions, [Strand::Curry, Strand::C3, Strand::Crystal]);
|
|
|
|
|
| braid.apply_crossing(Crossing {
|
| generator: Generator::Sigma1,
|
| over_strand: Strand::C3,
|
| under_strand: Strand::Curry,
|
| entropy: 0.05,
|
| rule_name: "R1",
|
| }).unwrap();
|
| assert_eq!(braid.positions, [Strand::C3, Strand::Curry, Strand::Crystal]);
|
| assert_eq!(braid.authority_holder(), Strand::C3);
|
| }
|
| }
|
|
|