import Erdos1135.ND.LogTime.ND16
import Erdos1135.ND.Density.FiniteV2Transfer
import Erdos1135.Tao.Syracuse.LogTimeCollatzBridge

/-!
# Logarithmic-time ND13

The finite two-adic density transfer is unchanged.  Its pointwise inclusion
now retains the raw Collatz clock supplied by the quantitative deterministic
Syracuse bridge.
-/

namespace Erdos1135
namespace ND

noncomputable section

/-- Uniform raw-Collatz clock obtained from a Syracuse clock. -/
noncomputable def collatzLogTimeConstant (Csyr : ℝ) : ℝ :=
  3 * Csyr + 1 / Real.log 2

theorem collatzLogTimeConstant_pos {Csyr : ℝ} (hCsyr : 0 < Csyr) :
    0 < collatzLogTimeConstant Csyr := by
  unfold collatzLogTimeConstant
  have hlogTwo : 0 < Real.log (2 : ℝ) := Real.log_pos (by norm_num)
  exact add_pos (mul_pos (by norm_num) hCsyr)
    (div_pos (by norm_num) hlogTwo)

/-- The unconditional raw clock used by the final ND chain. -/
noncomputable def ndCollatzLogTimeConstant : ℝ :=
  collatzLogTimeConstant ndSyracuseLogTimeConstant

theorem ndCollatzLogTimeConstant_pos :
    0 < ndCollatzLogTimeConstant := by
  exact collatzLogTimeConstant_pos ndSyracuseLogTimeConstant_pos

/-- A bounded-time strict Syracuse hit from an odd input gives a bounded-time
strict raw Collatz hit from every dyadic multiple. -/
theorem collatzLogTimeHit_powTwo_mul_of_syracuseLogTimeHit
    {Csyr : ℝ} (hCsyr : 0 ≤ Csyr)
    {M : ℕ} (hM : Odd M) (a : ℕ) {b : ℝ}
    (hHit : ∃ k : ℕ,
      (k : ℝ) ≤ Csyr * Real.log (M : ℝ) ∧
        ((Tao.syracuse^[k]) M : ℝ) < b) :
    ∃ j : ℕ,
      (j : ℝ) ≤ collatzLogTimeConstant Csyr *
        Real.log (((2 : ℕ) ^ a * M : ℕ) : ℝ) ∧
      ((collatzStep^[j]) ((2 : ℕ) ^ a * M) : ℝ) < b := by
  rcases hHit with ⟨k, hkTime, hkBelow⟩
  let W := Tao.taoTupleWeight
    (Tao.syracuseValuationPNatList k M hM)
  refine ⟨a + k + W, ?_, ?_⟩
  · have htime := Tao.powTwo_syracuseRawTime_cast_le
      a k M hM hCsyr hkTime
    simpa only [W, collatzLogTimeConstant] using htime
  · have hiterate :=
      Tao.collatz_iterate_powTwo_mul_syracuseValuationTime a k M hM
    simpa only [W, hiterate] using hkBelow

/-- The timed finite-two-adic transfer preserves density one, changing only
the explicit clock constant. -/
theorem nd13LogTimeStatement_of_nd16LogTimeStatement
    {Csyr : ℝ} (hCsyr : 0 ≤ Csyr)
    (h16 : ND16LogTimeStatement Csyr) :
    ND13LogTimeStatement (collatzLogTimeConstant Csyr) := by
  intro f hf
  let G : ℕ → Set ℕ := fun a =>
    {M : ℕ | Odd M ∧
      ∃ k : ℕ,
        (k : ℝ) ≤ Csyr * Real.log (M : ℝ) ∧
          ((Tao.syracuse^[k]) M : ℝ) <
            f ((2 : ℕ) ^ a * M)}
  refine hasNatDensity_one_of_powTwo_odd_dilates
    (A := {N : ℕ | 0 < N ∧ ∃ j : ℕ,
      (j : ℝ) ≤ collatzLogTimeConstant Csyr * Real.log (N : ℝ) ∧
        ((collatzStep^[j]) N : ℝ) < f N})
    G ?_ ?_ ?_
  · intro a M hM
    exact hM.1
  · intro a
    have ha :=
      h16 (fun M => f ((2 : ℕ) ^ a * M))
        (growsOnOddsToInfinity_powTwo_mul hf a)
    simpa [HasOddRelativeNatDensityOne, G] using ha
  · intro a N hN
    rcases (Tao.mem_natDilate_iff_exists_mul
        (Nat.pow_pos (by norm_num : 0 < (2 : ℕ)))).mp hN with
      ⟨M, hM, rfl⟩
    change Odd M ∧
      ∃ k : ℕ,
        (k : ℝ) ≤ Csyr * Real.log (M : ℝ) ∧
          ((Tao.syracuse^[k]) M : ℝ) <
            f ((2 : ℕ) ^ a * M) at hM
    refine ⟨Nat.mul_pos
      (Nat.pow_pos (by norm_num : 0 < (2 : ℕ)))
      (Odd.pos hM.1), ?_⟩
    exact collatzLogTimeHit_powTwo_mul_of_syracuseLogTimeHit
      hCsyr hM.1 a hM.2

/-- Unconditional logarithmic-time ND13. -/
theorem ndRhinND13LogTimeStatement :
    ND13LogTimeStatement ndCollatzLogTimeConstant := by
  exact nd13LogTimeStatement_of_nd16LogTimeStatement
    ndSyracuseLogTimeConstant_pos.le ndRhinND16LogTimeStatement

end

end ND
end Erdos1135
