import Spa.Language.Semantics
import Spa.Language.Graphs

namespace Spa

inductive Trace (g : Graph) : g.Index → g.Index → Env → Env → Prop
  | single {ρ₁ ρ₂ : Env} {idx : g.Index} :
      EvalBasicStmts ρ₁ (g.nodes idx) ρ₂ → Trace g idx idx ρ₁ ρ₂
  | edge {ρ₁ ρ₂ ρ₃ : Env} {idx₁ idx₂ idx₃ : g.Index} :
      EvalBasicStmts ρ₁ (g.nodes idx₁) ρ₂ → (idx₁, idx₂) ∈ g.edges →
      Trace g idx₂ idx₃ ρ₂ ρ₃ → Trace g idx₁ idx₃ ρ₁ ρ₃

theorem Trace.concat {g : Graph} {idx₁ idx₂ idx₃ idx₄ : g.Index}
    {ρ₁ ρ₂ ρ₃ : Env} (tr₁ : Trace g idx₁ idx₂ ρ₁ ρ₂)
    (he : (idx₂, idx₃) ∈ g.edges) (tr₂ : Trace g idx₃ idx₄ ρ₂ ρ₃) :
    Trace g idx₁ idx₄ ρ₁ ρ₃ := by
  induction tr₁ with
  | single hbs => exact Trace.edge hbs he tr₂
  | edge hbs he' _ ih => exact Trace.edge hbs he' (ih he tr₂)

inductive EndToEndTrace (g : Graph) (ρ₁ ρ₂ : Env) : Prop
  | intro (idx₁ : g.Index) (idx₁_mem : idx₁ ∈ g.inputs)
      (idx₂ : g.Index) (idx₂_mem : idx₂ ∈ g.outputs)
      (trace : Trace g idx₁ idx₂ ρ₁ ρ₂) : EndToEndTrace g ρ₁ ρ₂

end Spa
