import Erdos1135.KrasikovLagarias.EliminationPolicy

/-!
# Selected-lift potentials for KL elimination

The original capped policy retained lift zero when all three auxiliary lifts
were dominated.  At higher ternary levels a single globally fixed lift can
create positive cycles.  The mathematically relevant requirement is weaker:
for each auxiliary row, retain one lift certified to decrease the adjusted
potential.  This module isolates that certificate interface.

No finite payload or level-specific theorem is introduced here.  The selected
lift is part of the proof-carrying potential, so downstream termination code
can use it without making an unverified minimization choice.
-/

namespace Erdos1135
namespace KrasikovLagarias
namespace AdaptiveEliminationPolicy

open EliminationPolicy
open EliminationResidue

/-- A bounded residue potential together with one certified fallback lift for
each D1 and D3 row. -/
structure ForcedPotential (k : Nat) (hk : 2 ≤ k) where
  value : PrincipalIndex k → Nat
  bound : Nat
  value_le_bound : ∀ index, value index ≤ bound
  principal_le : ∀ index,
    value (fourIndex (Nat.le_trans (by omega) hk) index) ≤ value index + 6
  d1Lift : ∀ (index : PrincipalIndex k),
    rowKind index = FiniteCertificate.RowKind.l1 → LiftIndex
  d1Selected_le : ∀ (index : PrincipalIndex k)
      (hrow : rowKind index = FiniteCertificate.RowKind.l1),
    value (d1PrincipalLift hk index hrow (d1Lift index hrow)) ≤ value index + 1
  d3Lift : ∀ (index : PrincipalIndex k),
    rowKind index = FiniteCertificate.RowKind.l3 → LiftIndex
  d3Selected_le : ∀ (index : PrincipalIndex k)
      (hrow : rowKind index = FiniteCertificate.RowKind.l3),
    value (d3PrincipalLift hk index hrow (d3Lift index hrow)) + 2 ≤ value index

/-- The adaptive auxiliary policy retains every ordinary survivor.  Only when
all three source lifts are dominated does it use the lift selected by the
finite potential certificate. -/
inductive AllowedAuxiliary {k : Nat} {hk : 2 ≤ k}
    (potential : ForcedPotential k hk) (parent : State k) : Label k → Prop where
  | d1Survivor
      (hrow : rowKind parent.current.index = FiniteCertificate.RowKind.l1)
      (lift : LiftIndex)
      (hsurvives : Survives parent.history (parent.current.d1Child hk hrow lift)) :
      AllowedAuxiliary potential parent (parent.current.d1Child hk hrow lift)
  | d1Forced
      (hrow : rowKind parent.current.index = FiniteCertificate.RowKind.l1)
      (hall : ∀ lift : LiftIndex,
        Dominated parent.history (parent.current.d1Child hk hrow lift)) :
      AllowedAuxiliary potential parent
        (parent.current.d1Child hk hrow
          (potential.d1Lift parent.current.index hrow))
  | d3Survivor
      (hrow : rowKind parent.current.index = FiniteCertificate.RowKind.l3)
      (lift : LiftIndex)
      (hsurvives : Survives parent.history (parent.current.d3Child hk hrow lift)) :
      AllowedAuxiliary potential parent (parent.current.d3Child hk hrow lift)
  | d3Forced
      (hrow : rowKind parent.current.index = FiniteCertificate.RowKind.l3)
      (hall : ∀ lift : LiftIndex,
        Dominated parent.history (parent.current.d3Child hk hrow lift)) :
      AllowedAuxiliary potential parent
        (parent.current.d3Child hk hrow
          (potential.d3Lift parent.current.index hrow))

/-- Child-to-parent orientation of one legal edge for the adaptive policy. -/
inductive LegalChild {k : Nat} {hk : 2 ≤ k}
    (potential : ForcedPotential k hk) : State k → State k → Prop where
  | principal (parent : State k) (hadvanced : 0 ≤ parent.current.value) :
      LegalChild potential
        (parent.descend
          (parent.current.principalChild (Nat.le_trans (by omega) hk))) parent
  | auxiliary (parent : State k) (hadvanced : 0 ≤ parent.current.value)
      {child : Label k} (hallowed : AllowedAuxiliary potential parent child) :
      LegalChild potential (parent.descend child) parent

namespace ForcedPotential

/-- Real-valued path potential combining the exact shift and finite residue
potential. -/
noncomputable def adjusted {k : Nat} {hk : 2 ≤ k}
    (potential : ForcedPotential k hk) (label : Label k) : Real :=
  3 * label.value + potential.value label.index

theorem principal_adjusted_le {k : Nat} {hk : 2 ≤ k}
    (potential : ForcedPotential k hk) (label : Label k) :
    potential.adjusted
        (label.principalChild (Nat.le_trans (by omega) hk)) ≤
      potential.adjusted label := by
  rw [adjusted, adjusted, Label.principalChild_value]
  have hpotential :
      (potential.value
          (label.principalChild (Nat.le_trans (by omega) hk)).index : Real) ≤
        potential.value label.index + 6 := by
    exact_mod_cast potential.principal_le label.index
  linarith

/-- The selected D1 fallback decreases the adjusted potential by the same
uniform irrationality gap used by the lift-zero certificate. -/
theorem d1Selected_adjusted_add_gap_le {k : Nat} {hk : 2 ≤ k}
    (potential : ForcedPotential k hk) (label : Label k)
    (hrow : rowKind label.index = FiniteCertificate.RowKind.l1) :
    potential.adjusted
          (label.d1Child hk hrow (potential.d1Lift label.index hrow)) +
        (5 - 3 * alpha) ≤ potential.adjusted label := by
  rw [adjusted, adjusted, Label.d1Child_value]
  have hpotential :
      (potential.value
          (label.d1Child hk hrow
            (potential.d1Lift label.index hrow)).index : Real) ≤
        potential.value label.index + 1 := by
    exact_mod_cast potential.d1Selected_le label.index hrow
  linarith

/-- The selected D3 fallback decreases the adjusted potential by the same
uniform irrationality gap used by the lift-zero certificate. -/
theorem d3Selected_adjusted_add_gap_le {k : Nat} {hk : 2 ≤ k}
    (potential : ForcedPotential k hk) (label : Label k)
    (hrow : rowKind label.index = FiniteCertificate.RowKind.l3) :
    potential.adjusted
          (label.d3Child hk hrow (potential.d3Lift label.index hrow)) +
        (5 - 3 * alpha) ≤ potential.adjusted label := by
  rw [adjusted, adjusted, Label.d3Child_value]
  have hpotential :
      (potential.value
          (label.d3Child hk hrow
            (potential.d3Lift label.index hrow)).index : Real) + 2 ≤
        potential.value label.index := by
    exact_mod_cast potential.d3Selected_le label.index hrow
  linarith

theorem d1Selected_adjusted_lt {k : Nat} {hk : 2 ≤ k}
    (potential : ForcedPotential k hk) (label : Label k)
    (hrow : rowKind label.index = FiniteCertificate.RowKind.l1) :
    potential.adjusted
        (label.d1Child hk hrow (potential.d1Lift label.index hrow)) <
      potential.adjusted label := by
  have hgap := three_mul_alpha_lt_five
  linarith [potential.d1Selected_adjusted_add_gap_le label hrow]

theorem d3Selected_adjusted_lt {k : Nat} {hk : 2 ≤ k}
    (potential : ForcedPotential k hk) (label : Label k)
    (hrow : rowKind label.index = FiniteCertificate.RowKind.l3) :
    potential.adjusted
        (label.d3Child hk hrow (potential.d3Lift label.index hrow)) <
      potential.adjusted label := by
  have hgap := three_mul_alpha_lt_five
  linarith [potential.d3Selected_adjusted_add_gap_le label hrow]

end ForcedPotential
end AdaptiveEliminationPolicy
end KrasikovLagarias
end Erdos1135
