Faza 01 · lecția 19

Numere complexe pentru inteligența artificială

Scopul lecției: Rădăcina pătrată a lui -1 nu este „imaginară” în sensul obișnuit al cuvântului. Este cheia rotațiilor, a frecvențelor și a unei mari părți din prelucrarea semnalelor.

Versiunea curentă AlexBred.com: primele 100 de lecții ale programului în limba română.

Curs
AI Engineering from Scratch
Fază
Fundamente matematice
Lectură
20 min.
Verificat
Cuprinsul lecției
  1. Obiective de învățare
  2. Problema
  3. Conceptul
  4. Ce este un număr complex?
  5. Aritmetica numerelor complexe
  6. Planul complex
  7. Forma polară
  8. Formula lui Euler
  9. De ce contează formula lui Euler în învățarea automată
  10. Legătura cu rotațiile 2D
  11. Fazori și semnale rotitoare
  12. Rădăcinile unității
  13. Legătura cu DFT
  14. De ce i nu este „imaginar”
  15. Exponențiale complexe față de funcții trigonometrice
  16. Legătura cu arhitecturile Transformer
  17. Construiți soluția
  18. Pasul 1: clasa Complex
  19. Pasul 2: conversia polară și formula lui Euler
  20. Pasul 3: rotația
  21. Pasul 4: DFT prin aritmetică complexă
  22. Pasul 5: DFT inversă
  23. Pasul 6: rădăcinile unității
  24. Folosiți soluția
  25. Livrați rezultatul
  26. Exerciții
  27. Termeni-cheie
  28. Lecturi suplimentare

Rădăcina pătrată a lui -1 nu este „imaginară” în sensul obișnuit al cuvântului. Este cheia rotațiilor, a frecvențelor și a unei mari părți din prelucrarea semnalelor.

Tip: Învățare Limbaj: Python Cerințe preliminare: Faza 1, lecțiile 01–04 (algebră liniară, calcul diferențial și integral) Durată: ~60 de minute

Obiective de învățare

  • Efectuați operații cu numere complexe — adunare, înmulțire, împărțire și conjugare — atât în formă algebrică, cât și în formă polară
  • Aplicați formula lui Euler pentru a converti între exponențiale complexe și funcții trigonometrice
  • Implementați transformata Fourier discretă folosind rădăcinile complexe ale unității
  • Explicați cum stau rotațiile complexe la baza RoPE și a codificărilor poziționale sinusoidale din arhitecturile Transformer

Problema

Deschideți o lucrare despre transformate Fourier și vedeți i peste tot. Analizați codificările poziționale dintr-un Transformer și întâlniți sin și cos la frecvențe diferite — părțile imaginară și reală ale exponențialelor complexe. Citiți despre calculul cuantic și găsiți totul exprimat în spații vectoriale complexe.

Numerele complexe par abstracte. Un sistem numeric construit pe rădăcina pătrată a lui -1 poate părea un artificiu matematic. Dar nu este un artificiu. Este limbajul natural al rotațiilor și oscilațiilor. Ori de câte ori ceva se rotește, vibrează sau oscilează, numerele complexe sunt un instrument potrivit.

Fără o înțelegere a numerelor complexe, transformata Fourier discretă și algoritmul FFT rămân greu de înțeles în profunzime. La fel se întâmplă cu RoPE (Rotary Position Embedding) din modelele lingvistice moderne și cu alegerea frecvențelor din codificările poziționale sinusoidale ale lucrării Transformer originale.

În această lecție veți construi de la zero aritmetica numerelor complexe, o veți lega de geometrie și veți vedea exact unde apar numerele complexe în învățarea automată.

Conceptul

Ce este un număr complex?

Un număr complex are două componente: una reală și una imaginară.

z = a + bi

unde:
  a este partea reală
  b este partea imaginară
  i este unitatea imaginară, definită prin i^2 = -1

Atât. Extindeți axa numerelor într-un plan. Numerele reale se află pe una dintre axe, iar numerele imaginare pe cealaltă. Fiecare număr complex este un punct în acest plan.

Aritmetica numerelor complexe

Adunare. Adunați separat părțile reale și părțile imaginare.

(a + bi) + (c + di) = (a + c) + (b + d)i

Exemplu: (3 + 2i) + (1 + 4i) = 4 + 6i

Înmulțire. Folosiți distributivitatea și rețineți că i^2 = -1.

(a + bi)(c + di) = ac + adi + bci + bdi^2
                 = ac + adi + bci - bd
                 = (ac - bd) + (ad + bc)i

Exemplu: (3 + 2i)(1 + 4i) = 3 + 12i + 2i + 8i^2
                             = 3 + 14i - 8
                             = -5 + 14i

Conjugare. Schimbați semnul părții imaginare.

conjugatul lui (a + bi) = a - bi

Produsul dintre un număr complex și conjugatul său este întotdeauna real și nenegativ:

(a + bi)(a - bi) = a^2 + b^2

Împărțire. Înmulțiți numărătorul și numitorul cu conjugatul numitorului.

(a + bi) / (c + di) = (a + bi)(c - di) / (c^2 + d^2)

Astfel eliminați partea imaginară din numitor și obțineți un număr complex în formă algebrică, dacă numitorul inițial este nenul.

Planul complex

Planul complex asociază fiecărui număr complex un punct bidimensional. Axa orizontală este axa reală, iar cea verticală este axa imaginară.

z = 3 + 2i  corespunde punctului (3, 2)
z = -1 + 0i corespunde punctului (-1, 0) de pe axa reală
z = 0 + 4i  corespunde punctului (0, 4) de pe axa imaginară

Un număr complex este simultan un punct și un vector care pornește din origine. Această dublă interpretare face numerele complexe utile în geometrie.

Forma polară

Orice punct nenul din plan poate fi descris prin distanța față de origine și un argument față de semiaxa reală pozitivă. Argumentul nu este unic: unghiurile care diferă prin multipli întregi ai lui 2*pi descriu același număr; atan2 alege de regulă argumentul principal.

z = r * (cos(theta) + i*sin(theta))

unde:
  r = |z| = sqrt(a^2 + b^2)     (mărime sau modul)
  theta = atan2(b, a)             (fază sau argument principal)

Notă tehnică a traducerii: originalul sugerează că numai originea ridică o problemă de unicitate a unghiului. Pentru orice z != 0, argumentul este definit modulo 2*pi; originea nu are argument definit, iar atan2 returnează o valoare principală aleasă într-un interval convențional.

Forma algebrică, a + bi, este potrivită pentru adunare. Forma polară, (r, theta), este potrivită pentru înmulțire.

Înmulțirea în formă polară. Înmulțiți modulele și adunați unghiurile.

z1 = r1 * e^(i*theta1)
z2 = r2 * e^(i*theta2)

z1 * z2 = (r1 * r2) * e^(i*(theta1 + theta2))

Acesta este motivul pentru care numerele complexe sunt ideale pentru rotații. Înmulțirea cu un număr complex de modul 1 este o rotație pură.

Formula lui Euler

Puntea dintre exponențialele complexe și trigonometrie este:

e^(i*theta) = cos(theta) + i*sin(theta)

Aceasta este formula cea mai importantă din lecție. Pentru theta = pi:

e^(i*pi) = cos(pi) + i*sin(pi) = -1 + 0i = -1

Prin urmare: e^(i*pi) + 1 = 0

Cinci constante fundamentale — e, i, pi, 1 și 0 — sunt legate într-o singură ecuație.

De ce contează formula lui Euler în învățarea automată

Formula lui Euler arată că e^(i*theta) parcurge cercul unitate pe măsură ce theta variază. Pentru theta = 0, vă aflați în (1, 0). Pentru theta = pi/2, vă aflați în (0, 1). Pentru theta = pi, ajungeți în (-1, 0). Pentru theta = 3*pi/2, ajungeți în (0, -1). O rotație completă corespunde lui theta = 2*pi.

Prin urmare, exponențialele complexe reprezintă rotații. Iar rotațiile apar peste tot în prelucrarea semnalelor și în învățarea automată.

Legătura cu rotațiile 2D

Înmulțirea numărului complex (x + yi) cu e^(i*theta) rotește punctul (x, y) cu unghiul theta în jurul originii.

Rotație prin înmulțire complexă:
  (x + yi) * (cos(theta) + i*sin(theta))
  = (x*cos(theta) - y*sin(theta)) + (x*sin(theta) + y*cos(theta))i

Rotație prin înmulțire matricială:
  [cos(theta)  -sin(theta)] [x]   [x*cos(theta) - y*sin(theta)]
  [sin(theta)   cos(theta)] [y] = [x*sin(theta) + y*cos(theta)]

Cele două calcule produc rezultate identice. Înmulțirea complexă este o rotație 2D atunci când multiplicatorul are modul 1. Matricea de rotație este aceeași operație scrisă în notație matricială.

Диаграмма к уроку «Numere complexe pentru inteligența artificială»

Fazori și semnale rotitoare

O exponențială complexă e^(i*omega*t) este un punct care se rotește pe cercul unitate cu frecvența unghiulară omega. Pe măsură ce t crește, punctul descrie cercul.

Partea reală a acestui punct rotitor este cos(omega*t). Partea imaginară este sin(omega*t). Un semnal sinusoidal poate fi văzut ca proiecția unui număr complex rotitor.

e^(i*omega*t) = cos(omega*t) + i*sin(omega*t)

Partea reală:      cos(omega*t)    -- o undă cosinusoidală
Partea imaginară: sin(omega*t)    -- o undă sinusoidală

Aceasta este reprezentarea fazorială. În loc să urmăriți o undă sinusoidală care oscilează, urmăriți o săgeată care se rotește uniform. Defazajele devin decalaje unghiulare. Modificările amplitudinii devin modificări ale modulului. Adunarea semnalelor devine adunare vectorială.

Rădăcinile unității

Rădăcinile de ordinul N ale unității sunt N puncte distribuite uniform pe cercul unitate:

w_k = e^(2*pi*i*k/N)    pentru k = 0, 1, 2, ..., N-1

Pentru N = 4, rădăcinile sunt 1, i, -1, -i, adică cele patru puncte cardinale. Pentru N = 8, obțineți cele patru puncte cardinale și cele patru diagonale.

Rădăcinile unității stau la baza transformatei Fourier discrete. DFT descompune un semnal în componente asociate celor N frecvențe discrete.

Legătura cu DFT

Transformata Fourier discretă a unui semnal x[0], x[1], ..., x[N-1] este:

X[k] = sum_{n=0}^{N-1} x[n] * e^(-2*pi*i*k*n/N)

Fiecare X[k] măsoară proiecția semnalului pe exponențiala complexă de frecvență k. Cu definiția pozitivă a rădăcinilor w_k de mai sus, nucleul DFT folosește conjugatele lor, adică w_k^{-n}. DFT exprimă semnalul prin N fazori eșantionați și furnizează coeficienții complecși din care se deduc amplitudinea și faza fiecărei componente.

Notă tehnică a traducerii: Originalul numește direct nucleul cu exponent negativ „rădăcina de ordinul k” după ce definește rădăcinile cu exponent pozitiv. Cele două convenții sunt conjugate. Semnul exponențialei și normalizarea diferă între convențiile DFT, dar transformata și inversa trebuie să folosească semne opuse în mod consecvent.

De ce i nu este „imaginar”

Cuvântul „imaginar” este un accident istoric. Descartes l-a folosit în sens depreciativ. Dar i nu este mai puțin legitim decât erau numerele negative când oamenii le respingeau. Numerele negative răspund la întrebarea „ce obțineți dacă scădeți 5 din 3?”. Unitatea imaginară răspunde la întrebarea „ce trebuie să ridicați la pătrat pentru a obține -1?”.

Mai util spus, i este un operator de rotație cu 90 de grade în planul complex. Înmulțiți o dată un număr real cu i și îl rotiți cu 90 de grade pe axa imaginară. Înmulțiți încă o dată cu i, adică aplicați i^2, și îl rotiți cu alte 90 de grade: acum indică direcția reală negativă. De aceea i^2 = -1. Nu este ceva misterios, ci o jumătate de rotație compusă din două sferturi de rotație.

Acesta este motivul pentru care numerele complexe apar peste tot în inginerie. Fenomenele care implică rotații sau faze — unde electromagnetice, stări cuantice, oscilații ale semnalelor și unele codificări poziționale — sunt descrise natural cu numere complexe.

Exponențiale complexe față de funcții trigonometrice

În notația trigonometrică, inginerii scriu semnalele ca A*cos(omega*t + phi): amplitudinea A, frecvența unghiulară omega și faza phi. Notația funcționează, dar poate face aritmetica greoaie. Adunarea a două cosinusuri cu faze diferite necesită identități trigonometrice.

Cu exponențiale complexe, reprezentarea corespunzătoare este A*e^(i*(omega*t + phi)). Adunarea a două reprezentări înseamnă simpla adunare a două numere complexe. Înmulțirea, adică modularea în anumite contexte, înmulțește modulele și adună unghiurile. Defazajele devin adunări de unghiuri. Translațiile de frecvență se exprimă prin înmulțirea cu fazori.

Notația exponențială complexă este folosită pe scară largă în prelucrarea semnalelor deoarece simplifică algebra. Pentru un semnal real reprezentat printr-un semnal complex auxiliar, semnalul real se poate recupera ca partea reală, cu condiția folosirii consecvente a convenției. Partea imaginară păstrează informația de cuadratură necesară calculelor.

Notă tehnică a traducerii: Afirmația originală că „semnalul real este întotdeauna doar partea reală” este prea generală. Aceasta descrie o reprezentare complexă aleasă pentru un semnal real; există și semnale intrinsec complexe, iar reprezentarea analitică a unui semnal real are o structură spectrală specifică.

Legătura cu arhitecturile Transformer

Codificările poziționale sinusoidale din lucrarea Transformer originală:

PE(pos, 2i) = sin(pos / 10000^(2i/d))
PE(pos, 2i+1) = cos(pos / 10000^(2i/d))

Perechile sin și cos sunt componentele imaginară și reală ale exponențialelor complexe la frecvențe diferite. Fiecare frecvență oferă o altă scară pentru codificarea poziției. Frecvențele joase variază lent și surprind poziția la scară grosieră. Frecvențele înalte variază rapid și oferă variații mai fine. Împreună, dimensiunile formează o amprentă multifrecvență a poziției.

RoPE (Rotary Position Embedding) merge mai departe. Metoda rotește perechi bidimensionale de componente ale vectorilor query și key cu unghiuri dependente de poziție. Aceste rotații reale sunt echivalente cu înmulțirea numerelor complexe asociate perechilor. Produsul scalar dintre vectorii rotiți depinde de diferența pozițiilor, ceea ce introduce informația de poziție relativă în mecanismul de atenție.

Notă tehnică a traducerii: Originalul afirmă că RoPE „înmulțește explicit vectorii query și key cu matrice de rotație complexe”. Formularea standard folosește matrice de rotație reale, bloc-diagonale, aplicate perechilor de coordonate; aceeași operație poate fi scrisă elegant ca înmulțire complexă.

Operație Formă algebrică Semnificație geometrică
Adunare (a+c) + (b+d)i Adunare vectorială în plan
Înmulțire (ac-bd) + (ad+bc)i Rotație și scalare
Conjugare a - bi Reflexie față de axa reală
Modul sqrt(a^2 + b^2) Distanță față de origine
Fază atan2(b, a) Unghi față de semiaxa reală pozitivă
Împărțire Înmulțire cu conjugatul și împărțire la modulul pătrat Rotație inversă și scalare reciprocă
Putere r^n * e^(i*n*theta) Rotație de n ori și scalare cu r^n

Диаграмма к уроку «Numere complexe pentru inteligența artificială»

roots-of-unity

Construiți soluția

Pasul 1: clasa Complex

Construiți o clasă pentru numere complexe care acceptă operații aritmetice, modul, fază și conversia între formele algebrică și polară.

import math

class Complex:
    def __init__(self, real, imag=0.0):
        self.real = real
        self.imag = imag

    def __add__(self, other):
        return Complex(self.real + other.real, self.imag + other.imag)

    def __mul__(self, other):
        r = self.real * other.real - self.imag * other.imag
        i = self.real * other.imag + self.imag * other.real
        return Complex(r, i)

    def __truediv__(self, other):
        denom = other.real ** 2 + other.imag ** 2
        r = (self.real * other.real + self.imag * other.imag) / denom
        i = (self.imag * other.real - self.real * other.imag) / denom
        return Complex(r, i)

    def magnitude(self):
        return math.sqrt(self.real ** 2 + self.imag ** 2)

    def phase(self):
        return math.atan2(self.imag, self.real)

    def conjugate(self):
        return Complex(self.real, -self.imag)

Pasul 2: conversia polară și formula lui Euler

def to_polar(z):
    return z.magnitude(), z.phase()

def from_polar(r, theta):
    return Complex(r * math.cos(theta), r * math.sin(theta))

def euler(theta):
    return Complex(math.cos(theta), math.sin(theta))

Verificați cu toleranță numerică: euler(theta).magnitude() ar trebui să fie foarte aproape de 1,0. euler(0) ar trebui să dea (1, 0). euler(pi) ar trebui să fie foarte aproape de (-1, 0).

Notă tehnică a traducerii: Originalul cere egalități exacte. În aritmetica în virgulă mobilă, math.sin(math.pi) nu este exact zero, iar modulul calculat poate diferi foarte puțin de 1. Folosiți math.isclose() sau o toleranță absolută potrivită.

Pasul 3: rotația

Rotirea unui punct (x, y) cu unghiul theta necesită o singură înmulțire complexă:

point = Complex(3, 4)
rotated = point * euler(math.pi / 4)

Modulul rămâne același în limita erorii numerice. Se schimbă numai unghiul.

Pasul 4: DFT prin aritmetică complexă

def dft(signal):
    N = len(signal)
    result = []
    for k in range(N):
        total = Complex(0, 0)
        for n in range(N):
            angle = -2 * math.pi * k * n / N
            total = total + Complex(signal[n], 0) * euler(angle)
        result.append(total)
    return result

Aceasta este DFT cu complexitate O(N^2). Fiecare ieșire X[k] este suma eșantioanelor semnalului înmulțite cu puterile rădăcinilor unității corespunzătoare frecvenței.

Pasul 5: DFT inversă

DFT inversă reconstruiește semnalul original din spectrul său. Față de transformata directă, schimbați semnul exponentului și împărțiți la N.

def idft(spectrum):
    N = len(spectrum)
    result = []
    for n in range(N):
        total = Complex(0, 0)
        for k in range(N):
            angle = 2 * math.pi * k * n / N
            total = total + spectrum[k] * euler(angle)
        result.append(Complex(total.real / N, total.imag / N))
    return result

În aritmetică exactă, reconstrucția este perfectă. În implementarea în virgulă mobilă, aplicați DFT și apoi IDFT și recuperați semnalul original până la erori de rotunjire de ordinul preciziei mașinii. Transformata nu pierde informație în sens matematic.

Pasul 6: rădăcinile unității

def roots_of_unity(N):
    return [euler(2 * math.pi * k / N) for k in range(N)]

Pentru N > 1, verificați cu toleranță două proprietăți:

  • Fiecare rădăcină are modulul 1 în aritmetică exactă.
  • Suma tuturor celor N rădăcini este zero în aritmetică exactă, deoarece se anulează prin simetrie.

Vectorii formați prin eșantionarea puterilor rădăcinilor unității constituie baza ortogonală complexă folosită de DFT, iar ortogonalitatea lor face posibilă formula simplă a inversei.

Notă tehnică a traducerii: Originalul afirmă că fiecare modul este „exact 1” și că suma este zero fără să precizeze N > 1. În codul în virgulă mobilă, ambele proprietăți se verifică numai cu toleranță, iar pentru N = 1 suma este 1. În plus, baza lui C^N este formată din vectorii exponențialelor complexe eșantionate, nu din rădăcinile scalare luate separat.

Folosiți soluția

Python oferă suport integrat pentru numere complexe. Literalul j reprezintă unitatea imaginară.

z = 3 + 2j
w = 1 + 4j

print(z + w)
print(z * w)
print(abs(z))

import cmath
print(cmath.phase(z))
print(cmath.exp(1j * cmath.pi))

Pentru tablouri, NumPy gestionează nativ numerele complexe:

import numpy as np

z = np.array([1+2j, 3+4j, 5+6j])
print(np.abs(z))
print(np.angle(z))
print(np.conj(z))
print(np.real(z))
print(np.imag(z))

signal = np.sin(2 * np.pi * 5 * np.linspace(0, 1, 128))
spectrum = np.fft.fft(signal)
freqs = np.fft.fftfreq(128, d=1/128)

Notă tehnică a traducerii: np.linspace(0, 1, 128) include implicit ambele capete, astfel încât intervalul real dintre eșantioane este 1/127, nu 1/128, în timp ce fftfreq primește d=1/128. Pentru o grilă periodică coerentă cu acest d, folosiți np.linspace(0, 1, 128, endpoint=False) sau np.arange(128)/128. Blocul executabil a fost păstrat exact.

Livrați rezultatul

Rulați code/complex_numbers.py pentru a genera outputs/skill-complex-arithmetic.md.

Exerciții

  1. Aritmetică complexă manuală. Calculați (2 + 3i) * (4 - i) și verificați rezultatul cu ajutorul codului. Apoi calculați (5 + 2i) / (1 - 3i). Desenați ambele rezultate în planul complex și verificați că înmulțirea a rotit și a scalat primul număr.

  2. Secvență de rotații. Porniți de la punctul (1, 0). Înmulțiți-l de douăsprezece ori cu e^(i*pi/6). Verificați cu toleranță că reveniți la (1, 0) după 12 înmulțiri. Afișați coordonatele la fiecare pas și confirmați că descriu un dodecagon regulat.

  3. DFT pentru un semnal cunoscut. Creați semnalul sin(2*pi*3*t) + 0.5*sin(2*pi*7*t) în cele 32 de puncte t = n/32, pentru n = 0, ..., 31. Rulați DFT. Verificați că spectrul modulului are vârfuri la indicii frecvențelor pozitive 3 și 7, precum și la indicii conjugați 29 și 25 ai frecvențelor negative. Vârful de la frecvența 7 trebuie să aibă jumătate din înălțimea celui de la frecvența 3, în limita erorii numerice.

Notă tehnică a traducerii: Originalul nu precizează grila de eșantionare și menționează numai vârfurile 3 și 7. Pentru un semnal real eșantionat pe o perioadă, DFT are simetrie conjugată și produce și vârfurile oglindite la frecvențele negative. Alegerea t = n/32 evită duplicarea capătului perioadei și scurgerea spectrală artificială.

  1. Vizualizarea rădăcinilor unității. Calculați rădăcinile de ordinul 8 ale unității. Verificați cu toleranță că suma lor este zero. Verificați că înmulțirea oricărei rădăcini cu rădăcina primitivă e^(2*pi*i/8) produce următoarea rădăcină, cu revenire circulară după ultima.

  2. Echivalența cu matricea de rotație. Pentru 10 unghiuri aleatoare și 10 puncte aleatoare, verificați că înmulțirea complexă oferă același rezultat ca înmulțirea matrice–vector cu matricea de rotație 2 × 2. Afișați diferența numerică maximă.

Termeni-cheie

Termen Ce înseamnă
Număr complex Un număr a + bi, unde a este partea reală, b este partea imaginară, iar i^2 = -1
Unitate imaginară Numărul i, definit prin i^2 = -1. Nu este imaginar în sens filozofic; în planul complex, înmulțirea cu i este o rotație cu 90 de grade
Plan complex Planul 2D în care axa x este reală, iar axa y este imaginară. Se mai numește planul Argand
Modul Distanța față de origine: sqrt(a^2 + b^2). Se scrie |z|
Fază (argument) Unghiul față de semiaxa reală pozitivă: atan2(b, a). Se scrie arg(z)
Conjugat Imaginea în oglindă față de axa reală: conjugatul lui a + bi este a - bi
Formă polară Exprimarea lui z ca r * e^(i*theta) în loc de a + bi. Simplifică înmulțirea
Formula lui Euler e^(i*theta) = cos(theta) + i*sin(theta). Leagă exponențialele de trigonometrie
Fazor Un număr complex rotitor e^(i*omega*t) care reprezintă un semnal sinusoidal
Rădăcinile unității Cele N numere complexe e^(2*pi*i*k/N), pentru k de la 0 la N-1: N puncte distribuite uniform pe cercul unitate
DFT Transformata Fourier discretă. Descompune un semnal în componente sinusoidale complexe folosind puteri ale rădăcinilor unității
RoPE Rotary Position Embedding. Folosește rotații 2D, echivalente cu înmulțirea complexă, pentru a introduce poziția relativă în atenția unui Transformer

Lecturi suplimentare


Sursă: Complex Numbers for AI — original

Navigare: înapoi: 01.18 — Optimizare convexă · Faza 1 — Fundamente matematice · Catalog complet · în continuare: 01.20 — Transformata Fourier.