Documentation

Formalizations.MusicTheory.MelodicWord

A direction-sensitive invariant of melodic words #

For a word xs : List (ZMod 12) and an odd function f : ZMod 12 → M into an additive group, W f xs sums f over the successive steps x (j+1) - x j. Reversing the word negates W, and repeating a note does not change it. In contrast, order-blind statistics such as the step coefficients are invariant under reversal.

Main results #

Directed steps of a melodic word. #

The consecutive directed intervals of a melodic word: steps [x₀,…,xₙ] = [x₁−x₀, …, xₙ−xₙ₋₁]. Each entry step_j = x_{j+1} − x_j is the directed melodic interval (sign = up/down).

Equations
Instances For
    @[simp]
    theorem MusicTheory.MelodicWord.steps_cons_cons (a b : ZMod 12) (rest : List (ZMod 12)) :
    steps (a :: b :: rest) = (b - a) :: steps (b :: rest)
    def MusicTheory.MelodicWord.W {M : Type u_1} [AddCommGroup M] (f : ZMod 12 → M) (xs : List (ZMod 12)) :
    M

    The directed winding statistic. W f xs = Σ_j f(step_j) over the directed steps.

    Equations
    Instances For
      @[simp]
      theorem MusicTheory.MelodicWord.W_nil {M : Type u_1} [AddCommGroup M] (f : ZMod 12 → M) :
      W f [] = 0
      @[simp]
      theorem MusicTheory.MelodicWord.W_singleton {M : Type u_1} [AddCommGroup M] (f : ZMod 12 → M) (a : ZMod 12) :
      W f [a] = 0
      theorem MusicTheory.MelodicWord.W_cons_cons {M : Type u_1} [AddCommGroup M] (f : ZMod 12 → M) (a b : ZMod 12) (rest : List (ZMod 12)) :
      W f (a :: b :: rest) = f (b - a) + W f (b :: rest)

      Oddness ⇒ f 0 = 0 (the concrete ℝ-valued sin invariant; needs 2-torsion-freeness). #

      theorem MusicTheory.MelodicWord.f_zero {f : ZMod 12 → ℝ} (Hodd : ∀ (m : ZMod 12), f (-m) = -f m) :
      f 0 = 0

      From oddness f (−m) = − f m, at m = 0 we get f 0 = − f 0, hence f 0 = 0. Stated for the real-valued case (the concrete sin(2π·/12) invariant), where 2-torsion-freeness is automatic.

      Helper: how steps interacts with prepending a single LEADING note. #

      steps peels notes off the FRONT. Prepending a note z to a NONEMPTY word (a :: l) PREPENDS one new first step a − z to steps, leaving the rest unchanged. This single fact drives steps_reverse via concat (reverseRecOn) induction, since (xs ++ [z]).reverse = z :: xs.reverse.

      theorem MusicTheory.MelodicWord.steps_cons (z a : ZMod 12) (l : List (ZMod 12)) :
      steps (z :: a :: l) = (a - z) :: steps (a :: l)

      Prepending a note z before a NONEMPTY word (a :: l) prepends the step a − z: steps (z :: a :: l) = (a − z) :: steps (a :: l). (Just unfolds the recursion.)

      theorem MusicTheory.MelodicWord.steps_reverse (xs : List (ZMod 12)) :
      steps xs.reverse = (List.map (fun (s : ZMod 12) => -s) (steps xs)).reverse

      The retrograde step law. The directed steps of the reversed word are the negated steps of the word, in reversed order: steps xs.reverse = ((steps xs).map (-·)).reverse. Reversing a melody flips every directed interval (x_{j+1}−x_j ↦ x_j−x_{j+1} = −step_j) AND their order.

      Proof by concat induction (reverseRecOn): appending a trailing note z to xs is, after reversing, prepending z to xs.reverse.

      theorem MusicTheory.MelodicWord.sum_map_neg {M : Type u_1} [AddCommGroup M] (g : ZMod 12 → M) (l : List (ZMod 12)) :
      (List.map (fun (s : ZMod 12) => -g s) l).sum = -(List.map g l).sum

      Summing a list of negated terms negates the sum: (l.map (fun s => -g s)).sum = -(l.map g).sum.

      Theorem 1 — Retrograde antisymmetry. #

      theorem MusicTheory.MelodicWord.W_reverse {M : Type u_1} [AddCommGroup M] {f : ZMod 12 → M} (Hodd : ∀ (m : ZMod 12), f (-m) = -f m) (xs : List (ZMod 12)) :
      W f xs.reverse = -W f xs

      RETROGRADE ANTISYMMETRY. Reversing a melodic word negates its winding statistic: W f xs.reverse = − W f xs, for any ODD f. (Each directed step negates under retrograde — steps_reverse — and f odd turns each f(−s) into −f(s); the sum then negates.)

      Theorem 2 — Repetition / reparametrization invariance. #

      theorem MusicTheory.MelodicWord.W_cons_dup {M : Type u_1} [AddCommGroup M] {f : ZMod 12 → M} (hf0 : f 0 = 0) (a : ZMod 12) (rest : List (ZMod 12)) :
      W f (a :: a :: rest) = W f (a :: rest)

      Repeat the HEAD note. Inserting an immediate repeat of the first note inserts a step of 0, which f 0 = 0 kills: W f (a :: a :: rest) = W f (a :: rest).

      theorem MusicTheory.MelodicWord.W_cons_cons_dup {M : Type u_1} [AddCommGroup M] {f : ZMod 12 → M} (hf0 : f 0 = 0) (a b : ZMod 12) (rest : List (ZMod 12)) :
      W f (a :: b :: b :: rest) = W f (a :: b :: rest)

      Repeat an INTERIOR note (the step on each side is unaffected; the inserted middle step is 0). W f (a :: b :: b :: rest) = W f (a :: b :: rest).

      theorem MusicTheory.MelodicWord.W_dup_general {M : Type u_1} [AddCommGroup M] {f : ZMod 12 → M} (hf0 : f 0 = 0) (a : ZMod 12) (pre rest : List (ZMod 12)) :
      W f (pre ++ a :: a :: rest) = W f (pre ++ a :: rest)

      REPETITION / REPARAMETRIZATION INVARIANCE (general). Duplicating the note a at ANY position of a melodic word leaves W unchanged: W f (pre ++ a :: a :: rest) = W f (pre ++ a :: rest). The duplicated note inserts a single directed step a − a = 0, killed by f 0 = 0; all other steps are untouched. This is the "tempo / note-value is irrelevant" law — W sees the PATH, not its parametrization.

      Specialization (the concrete sin invariant): f 0 = 0 comes for free from oddness over a #

      2-torsion-free codomain (e.g. ℝ, where `NoZeroSMulDivisors ℕ ℝ` holds). 
      
      theorem MusicTheory.MelodicWord.W_reverse_odd {M : Type u_2} [AddCommGroup M] {f : ZMod 12 → M} (Hodd : ∀ (m : ZMod 12), f (-m) = -f m) (xs : List (ZMod 12)) :
      W f xs.reverse = -W f xs

      Retrograde antisymmetry needing ONLY oddness, over a 2-torsion-free codomain (ℝ): f 0 = 0 free.

      theorem MusicTheory.MelodicWord.W_dup_general_odd {f : ZMod 12 → ℝ} (Hodd : ∀ (m : ZMod 12), f (-m) = -f m) (a : ZMod 12) (pre rest : List (ZMod 12)) :
      W f (pre ++ a :: a :: rest) = W f (pre ++ a :: rest)

      Repetition invariance (general) needing ONLY oddness, for the real-valued sin invariant.

      Order-blindness of the pitch-class DFT #

      The DFT coefficient a_k of a melodic word is a SUM over the notes of a per-note quantity φ(xᵢ); the SUMMAND depends on each pitch class alone, never on its neighbours. Hence a_k factors through the MULTISET of pitch classes and is invariant under retrograde (reverse) AND under any permutation. The crucial point: this needs NOTHING about the exponential — it is pure list-sum invariance. We give it in two layers.

      Layer (a) — ABSTRACT, over any AddCommMonoid codomain. The whole content is List.sum_reverse (through List.map_reverse) and List.Perm.sum_eq (through List.Perm.map).

      theorem MusicTheory.MelodicWord.sum_map_reverse {N : Type u_2} [AddCommMonoid N] (φ : ZMod 12 → N) (xs : List (ZMod 12)) :
      (List.map φ xs.reverse).sum = (List.map φ xs).sum

      Reverse-invariance of a list-sum-of-a-pointwise-function (any AddCommMonoid codomain). Σᵢ φ(xᵢ) is unchanged by reversing the list: order is invisible to a sum of per-element terms.

      theorem MusicTheory.MelodicWord.sum_map_perm {N : Type u_2} [AddCommMonoid N] {φ : ZMod 12 → N} {xs ys : List (ZMod 12)} (h : xs.Perm ys) :
      (List.map φ xs).sum = (List.map φ ys).sum

      Permutation-invariance of a list-sum-of-a-pointwise-function (any AddCommMonoid codomain). Σᵢ φ(xᵢ) depends only on the MULTISET of xs: any reordering gives the same sum.

      Layer (b) — SPECIALIZE to the actual pc-DFT character. The exact exponent is irrelevant to the two laws (only that the summand is a function of the single note x); we use the standard kernel exp(−2πi·k·x/12). acoef is noncomputable (it uses Complex.exp); the theorems are pure.

      noncomputable def MusicTheory.MelodicWord.acoef (k : ℕ) (xs : List (ZMod 12)) :

      The pc-DFT coefficient a_k of a melodic WORD: a_k(xs) = Σⱼ exp(−2πi·k·xⱼ/12). Built as a list-sum of a per-note kernel, so it is order-blind by construction (see acoef_reverse/_perm).

      Equations
      Instances For
        theorem MusicTheory.MelodicWord.acoef_reverse (k : ℕ) (xs : List (ZMod 12)) :
        acoef k xs.reverse = acoef k xs

        The DFT cannot see direction. a_k is invariant under RETROGRADE: acoef k xs.reverse = acoef k xs. Immediate specialization of sum_map_reverse.

        theorem MusicTheory.MelodicWord.acoef_perm {k : ℕ} {xs ys : List (ZMod 12)} (h : xs.Perm ys) :
        acoef k xs = acoef k ys

        The DFT cannot see order at all. a_k factors through the multiset of pitch classes: xs ~ ys → acoef k xs = acoef k ys. Immediate specialization of sum_map_perm.

        Directional ⊥ a_k : the harmonic axis CANNOT separate a word from its retrograde, #

        yet the directed axis `W` CAN.
        

        a_k is retrograde-blind (previous section), so ANY functional of the WHOLE a_k-vector is retrograde-blind too (acoef_blind_to_retrograde): the entire harmonic profile is the same forwards and backwards. The directed winding statistic W, by contrast, FLIPS SIGN under retrograde (W_reverse), so it strictly distinguishes a word from its reverse whenever it is nonzero over a 2-torsion-free codomain (W_separates_retrograde). The two axes are orthogonal-on-direction: harmonic content is symmetric, directed motion is antisymmetric.

        theorem MusicTheory.MelodicWord.acoef_blind_to_retrograde {β : Type u_2} (g : (ℕ → ℂ) → β) (xs : List (ZMod 12)) :
        (g fun (k : ℕ) => acoef k xs.reverse) = g fun (k : ℕ) => acoef k xs

        No functional of the a_k-vector separates a word from its retrograde. For ANY g on the full coefficient vector (k ↦ a_k), the forward and retrograde words give the SAME value. (The two coefficient vectors are equal pointwise by acoef_reverse, hence equal as functions.)

        theorem MusicTheory.MelodicWord.W_separates_retrograde {M : Type u_2} [AddCommGroup M] [NoZeroSMulDivisors ℕ M] {f : ZMod 12 → M} (Hodd : ∀ (m : ZMod 12), f (-m) = -f m) (xs : List (ZMod 12)) (hne : W f xs ≠ 0) :
        W f xs.reverse ≠ W f xs

        W strictly separates a word from its retrograde when nonzero. Over a 2-torsion-free AddCommGroup (NoZeroSMulDivisors ℕ M, e.g. ℝ), if the directed winding W f xs ≠ 0 then the retrograde value W f xs.reverse = −W f xs differs from W f xs. So W SEES the direction that the entire harmonic a_k-vector is blind to.

        The tritone obstruction #

        f 0 = 0 (the existing f_zero) is only the FIRST of the 2-torsion obstructions. ℤ/12 has EXACTLY two solutions of m = −m: the identity 0 and the tritone 6 (6 + 6 = 12 ≡ 0). Both are forced to vanish for any odd f over a 2-torsion-free codomain. The tritone 6 is the same central element T₆ that recurs throughout the corpus: the unique nonzero element fixed by inversion, the centre of 6-30, the fixed axis of the rhythmic oddity property, and the tritone anomaly of the interval vector.

        The unique nonzero 2-torsion point of ℤ/12 is the tritone. m = −m ↔ m = 0 ∨ m = 6.

        theorem MusicTheory.MelodicWord.odd_vanishes_at_tritone {f : ZMod 12 → ℝ} (Hodd : ∀ (m : ZMod 12), f (-m) = -f m) :
        f 6 = 0

        The TRITONE obstruction. Any odd f over a 2-torsion-free codomain (here ℝ, the concrete sin(2π·/12) invariant) must VANISH at the tritone: f 6 = 0. Since −6 = 6 in ℤ/12, oddness gives f 6 = f(−6) = −f 6, and 2-torsion-freeness forces f 6 = 0 — exactly mirroring f_zero at the second (and only other) self-inverse point.

        A concrete witness: a genuinely odd f on ℤ/12 with W direction-sensitive. #

        fsign m = (if m.val ≤ 6 then m.val else m.val − 12 : ℤ) is the signed representative in [−5,6]… but 6 ↦ 6 and −6 = 6 so that exact map is NOT odd at the tritone. The clean odd integer model is g m = m.val − 6·(…); rather than fight the tritone we exhibit oddness abstractly: any f built as f m = h m − h (−m) is odd, and sin(2π·/12) is the analytic instance. We record the small arithmetic witness that the directed step really does flip sign, which is the whole point.