/- Copyright (c) 2025 Harmonic. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -/ import Langlib.Automata.DeterministicPushdown.Inclusion.Pushdown open PDA variable {Q T S : Type} [Fintype Q] [Fintype T] [Fintype S] namespace DPDA /-- Construct the **complement DPDA** by replacing the set of accepting states with its complement. This is a syntactic operation that swaps which states are accepting. -/ def complement (M : DPDA Q T S) : DPDA Q T S where initial_state := M.initial_state start_symbol := M.start_symbol final_states := M.final_statesᶜ transition := M.transition epsilon_transition := M.epsilon_transition no_mixed := M.no_mixed @[simp] theorem complement_final_states (M : DPDA Q T S) : M.complement.final_states = M.final_statesᶜ := rfl @[simp] theorem complement_transition (M : DPDA Q T S) : M.complement.transition = M.transition := rfl @[simp] theorem complement_epsilon_transition (M : DPDA Q T S) : M.complement.epsilon_transition = M.epsilon_transition := rfl @[simp] theorem complement_initial_state (M : DPDA Q T S) : M.complement.initial_state = M.initial_state := rfl @[simp] theorem complement_start_symbol (M : DPDA Q T S) : M.complement.start_symbol = M.start_symbol := rfl @[simp] theorem complement_complement (M : DPDA Q T S) : M.complement.complement.initial_state = M.initial_state ∧ M.complement.complement.start_symbol = M.start_symbol ∧ M.complement.complement.final_states = M.final_states ∧ M.complement.complement.transition = M.transition ∧ M.complement.complement.epsilon_transition = M.epsilon_transition := by simp [complement] @[simp] theorem complement_toPDA (M : DPDA Q T S) : M.complement.toPDA.initial_state = M.toPDA.initial_state := rfl /-- The complement DPDA has the same transition functions as the original. -/ theorem complement_toPDA_transition_fun (M : DPDA Q T S) : M.complement.toPDA.transition_fun = M.toPDA.transition_fun := rfl /-- The complement DPDA has the same ε-transition functions as the original. -/ theorem complement_toPDA_transition_fun' (M : DPDA Q T S) : M.complement.toPDA.transition_fun' = M.toPDA.transition_fun' := rfl /-- The multi-step reachability relation is the same for a DPDA and its complement, because the step function depends only on the transitions, not the accepting states. -/ theorem complement_toPDA_reaches (M : DPDA Q T S) (q q' : Q) (w : List T) (γ γ' : List S) : @PDA.Reaches _ _ _ _ _ _ M.complement.toPDA ⟨q, w, γ⟩ ⟨q', [], γ'⟩ ↔ @PDA.Reaches _ _ _ _ _ _ M.toPDA ⟨q, w, γ⟩ ⟨q', [], γ'⟩ := by constructor · intro h exact PDA.reaches_of_same_transitions M.complement.toPDA M.toPDA (complement_toPDA_transition_fun M) (complement_toPDA_transition_fun' M) ⟨q, w, γ⟩ ⟨q', [], γ'⟩ h · intro h exact PDA.reaches_of_same_transitions M.toPDA M.complement.toPDA (complement_toPDA_transition_fun M).symm (complement_toPDA_transition_fun' M).symm ⟨q, w, γ⟩ ⟨q', [], γ'⟩ h /-- For a DPDA that decides every input, the complemented DPDA accepts precisely the complement of the original language. -/ theorem complement_acceptsByFinalState (M : DPDA Q T S) (h : M.DecidesEveryInput) : M.complement.acceptsByFinalState = (M.acceptsByFinalState)ᶜ := by obtain ⟨htotal, hconsistent⟩ := h unfold DPDA.acceptsByFinalState PDA.acceptsByFinalState ext w change (∃ q ∈ M.final_statesᶜ, ∃ γ : List S, @PDA.Reaches Q T S _ _ _ M.complement.toPDA ⟨M.initial_state, w, [M.start_symbol]⟩ ⟨q, [], γ⟩) ↔ ¬(∃ q ∈ M.final_states, ∃ γ : List S, @PDA.Reaches Q T S _ _ _ M.toPDA ⟨M.initial_state, w, [M.start_symbol]⟩ ⟨q, [], γ⟩) constructor · rintro ⟨q, hq_not_final, γ, hreach⟩ rw [complement_toPDA_reaches] at hreach rintro ⟨q', hq'_final, γ', hreach'⟩ exact hq_not_final ((hconsistent w q q' γ γ' hreach hreach').mpr hq'_final) · intro h_not_accept obtain ⟨q, γ, hreach⟩ := htotal w refine ⟨q, ?_, γ, (complement_toPDA_reaches M M.initial_state q w [M.start_symbol] γ).mpr hreach⟩ intro hq_final exact h_not_accept ⟨q, hq_final, γ, hreach⟩ end DPDA