/- Copyright (c) 2025 Harmonic. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -/ import Mathlib import Langlib.Automata.Pushdown.Definition /-! # Deterministic Pushdown Automata (DPDAs) This file introduces deterministic pushdown automata (DPDAs). The embedding of DPDAs into nondeterministic PDAs lives in `Langlib.Automata.DeterministicPushdown.Inclusion.Pushdown`. Complement-closure results live in `Langlib.Automata.DeterministicPushdown.ClosureProperties.Complement`. -/ /-- A **Deterministic Pushdown Automaton (DPDA)** over state type `Q`, input alphabet `T`, and stack alphabet `S`. The key difference from a (nondeterministic) PDA is that the transition functions return `Option` values instead of `Set` values, enforcing at most one transition per configuration. The `no_mixed` field additionally requires that ε-transitions and input-reading transitions are mutually exclusive for each `(state, stack-top)` pair. **Determinism guarantee.** Given a configuration `(q, a :: w, Z :: γ)`: - If `M.epsilon_transition q Z = some (p, β)`, then the unique possible move is to go to `(p, a :: w, β ++ γ)` (the `no_mixed` condition ensures no input-reading transition is available). - Otherwise, if `M.transition q a Z = some (p, β)`, the unique possible move is `(p, w, β ++ γ)`. - If neither transition is defined, the machine is stuck (halts). -/ structure DPDA (Q T S : Type) [Fintype Q] [Fintype T] [Fintype S] where /-- Initial state -/ initial_state : Q /-- Initial stack symbol -/ start_symbol : S /-- Set of accepting (final) states -/ final_states : Set Q /-- Transition on reading input symbol `a` with stack top `Z`. Returns `some (p, β)` where `p` is the new state and `β` replaces `Z` on the stack, or `none` if no transition is defined. -/ transition : Q → T → S → Option (Q × List S) /-- ε-transition (no input consumed) with stack top `Z`. Returns `some (p, β)` where `p` is the new state and `β` replaces `Z` on the stack, or `none` if no transition is defined. -/ epsilon_transition : Q → S → Option (Q × List S) /-- **Determinism constraint**: if an ε-transition is defined for `(q, Z)`, then no input-reading transition is defined for `(q, a, Z)` for any input symbol `a`. -/ no_mixed : ∀ q Z, epsilon_transition q Z ≠ none → ∀ a, transition q a Z = none namespace DPDA variable {Q T S : Type} [Fintype Q] [Fintype T] [Fintype S] /-- Embed a DPDA into the nondeterministic PDA framework by converting each `Option` transition to the corresponding singleton or empty set. -/ noncomputable def toPDA (M : DPDA Q T S) : PDA Q T S where initial_state := M.initial_state start_symbol := M.start_symbol final_states := M.final_states transition_fun q a Z := match M.transition q a Z with | some p => {p} | none => ∅ transition_fun' q Z := match M.epsilon_transition q Z with | some p => {p} | none => ∅ finite q a Z := by cases M.transition q a Z with | none => exact Set.toFinite ∅ | some p => exact Set.toFinite {p} finite' q Z := by cases M.epsilon_transition q Z with | none => exact Set.toFinite ∅ | some p => exact Set.toFinite {p} /-- Language accepted by a DPDA via **final-state acceptance**: a word `w` is accepted iff the DPDA, starting from its initial configuration, can reach a configuration with empty input and an accepting state (with any remaining stack contents). -/ def acceptsByFinalState (M : DPDA Q T S) : Language T := M.toPDA.acceptsByFinalState /-- A DPDA **decides every input** if: 1. **Totality**: for each word `w`, the DPDA can reach some configuration with empty input from the initial configuration. 2. **Acceptance consistency**: all reachable empty-input configurations for a given word `w` agree on whether the state is accepting or not. -/ def DecidesEveryInput (M : DPDA Q T S) : Prop := (∀ w : List T, ∃ q γ, @PDA.Reaches Q T S _ _ _ M.toPDA ⟨M.initial_state, w, [M.start_symbol]⟩ ⟨q, [], γ⟩) ∧ (∀ (w : List T) (q₁ q₂ : Q) (γ₁ γ₂ : List S), @PDA.Reaches Q T S _ _ _ M.toPDA ⟨M.initial_state, w, [M.start_symbol]⟩ ⟨q₁, [], γ₁⟩ → @PDA.Reaches Q T S _ _ _ M.toPDA ⟨M.initial_state, w, [M.start_symbol]⟩ ⟨q₂, [], γ₂⟩ → (q₁ ∈ M.final_states ↔ q₂ ∈ M.final_states)) end DPDA variable {T : Type} [Fintype T] /-- A language over a finite terminal alphabet is accepted by some DPDA via final-state acceptance. -/ def is_DPDA (L : Language T) : Prop := ∃ (Q S : Type) (_ : Fintype Q) (_ : Fintype S) (M : DPDA Q T S), M.acceptsByFinalState = L /-- The class of DPDA-recognizable languages. -/ def DPDA.Class : Set (Language T) := setOf is_DPDA