Når man beskæftiger sig med matematik i Lean, opstår hurtigt spørgsmålet om, hvordan man håndterer de grundlæggende operationer, såsom beregning, anvendelse af sætninger og ræsonnering om generiske strukturer. I dette kapitel vil vi introducere nogle fundamentale metoder og værktøjer, der er nødvendige for at arbejde effektivt med matematik i Lean.

Matematiske beregninger er noget, vi lærer i en tidlig alder, men ofte uden at betragte dem som beviser. I Lean er en beregning faktisk en form for bevis, da vi skal retfærdiggøre hvert skridt i vores udregning. Dette gør det muligt for os at konstruere beviser, der viser, at venstre side af en beregning er lig med højre side. Når vi erklærer en sætning i Lean, skaber vi samtidig et mål: at bevise sætningen. Dette mål er centralt i Lean’s tilgang til matematik.

Lean tilbyder en række metoder til at udveksle og manipulere matematiske udtryk. Én af de mest grundlæggende værktøjer er rewriting-taktikken, eller rw, som bruges til at erstatte den venstre side af en identitet med den højre. For eksempel, hvis vi arbejder med realtal og ønsker at anvende den associative lov for multiplikation, kan vi bruge sætningen mul_assoc a b c, som udtrykker, at abc=a(bc)a * b * c = a * (b * c). På samme måde gælder den kommutative lov, mul_comm a b, som udtrykker ab=baa * b = b * a. Disse identiteter bruges ofte i Lean uden at blive nævnt eksplicit, da Lean automatiserer de fleste af sådanne beregninger, men de er stadig nyttige til illustration.

Et vigtigt element i Lean er, at multiplikation er venstresidet associativ, hvilket betyder, at vi uden videre kan skrive (ab)c(a * b) * c i stedet for abca * b * c, og resultatet vil være det samme. Når vi skriver beviser i Lean, er det dog en god praksis at være opmærksom på Lean’s notation og ikke bruge parenteser unødvendigt, medmindre det er nødvendigt for klarhedens skyld.

Når man skriver et bevis i Lean, kan man f.eks. starte med et mål, der lyder: abc=b(ac)a * b * c = b * (a * c). For at bevise dette, kan man bruge følgende ræsonnering:

lean
example (a b c : R) : a * b * c = b * (a * c) := by rw [mul_comm a b] rw [mul_assoc b a c]

I dette eksempel bruges rw-kommandoen til at udveksle faktorerne i venstre og højre side af udtrykket. Det er en simpel metode til at manipulere udtryk, men den kan være ekstremt kraftfuld, når man arbejder med komplekse matematiske strukturer.

Lean tilbyder også flere metoder til at udveksle flere udtryk i én operation. Det kan f.eks. gøres ved at oplyse flere identiteter ad gangen i et enkelt rw-kald, som i følgende eksempel:

lean
example (a b c d e f : R) (h : a * b = c * d) (h' : e = f) : a * (b * e) = c * (d * f) := by rw [h', ← mul_assoc, h, mul_assoc]

Lean gør det muligt at arbejde med et komplet matematisk miljø, hvor man kan deklarere variabler globalt for at undgå gentagelser i beviserne. Det betyder, at vi kan erklære de relevante variabler én gang og derefter bruge dem i alle efterfølgende sætninger. Når man arbejder med flere variabler på én gang, kan dette være med til at strømline bevisførelsen og gøre koden mere læsbar og effektiv.

Et andet vigtigt værktøj er #check-kommandoen, som hjælper os med at få indsigt i typer og udtryk i Lean. Denne kommando bruges til at kontrollere, hvilken type et udtryk har, eller hvilken sætning der er involveret i en given operation. Det kan være nyttigt, når vi arbejder med komplekse matematiske objekter, fordi det giver os mulighed for at få en præcis forståelse af de strukturer, vi arbejder med. For eksempel kan vi bruge:

lean
#check mul_comm a b

Denne kommando returnerer den præcise sætning, som beviser kommutativiteten af multiplikation for aa og bb. På samme måde kan vi bruge #check på andre udtryk for at få indsigt i, hvordan de er defineret og hvilke sætninger, de involverer.

Det er også muligt at anvende skift i sætninger for at vise, hvordan identiteter kan transformeres gennem flere skridt, og hvordan vi kan anvende de relevante teoremers egenskaber. Lean gør det muligt at arbejde med udtryk som:

lean
example : (a + b) * (a + b) = a * a + 2 * (a * b) + b * b := by rw [add_mul]

Her bruges en distributiv lov som en måde at omforme udtrykket og opnå den ønskede form. Ved at kombinere Lean’s automatisering og fleksibilitet, bliver det muligt at arbejde effektivt med selv meget komplekse matematiske udtryk.

Når man arbejder med Lean, er det vigtigt at forstå, hvordan forskellige matematiske objekter er relateret til hinanden. Hver erklæring, man laver, hver identitet, man anvender, og hver teorem, man beviser, bidrager til at bygge en stadig større og mere detaljeret forståelse af de strukturer, man beskæftiger sig med. Det kræver en grundig forståelse af både de konkrete matematiske objekter og de logiske regler, der styrer deres anvendelse.

Lean er en kraftfuld måde at arbejde med matematik på, men det kræver også en god forståelse af de underliggende logiske mekanismer og de værktøjer, der er tilgængelige. Når man bliver fortrolig med at bruge Lean’s funktioner effektivt, bliver det muligt at udtrykke komplekse matematiske ideer præcist og med høj grad af formalitet, hvilket gør det muligt at udføre matematiske beviser på en mere struktureret og fejlfri måde.

Hvordan man håndterer dårlig diamanter i matematisk struktur i Lean

I den abstrakte verden af algebra og kategori teori, som vi ofte stifter bekendtskab med i formelle beviser og programmering, står vi over for adskillige udfordringer, der kan være uventede og problematiske. Et af de mere vanskelige problemer, som opstår, når man arbejder med Lean – et program for formelle beviser – er det, der kaldes en "dårlig diamant". Dette er en situation, der relaterer sig til den måde, hvorpå typer og strukturer er bundet sammen gennem hierarkier i matematikken.

En af de første ting, der er vigtige at forstå, når man arbejder med matematiske strukturer i Lean, er konceptet om moduler og abelske grupper. Hvis man tager Z som et eksempel, er Z en abelsk gruppe og kan også ses som et modul over sig selv, da Z er en ring. Dette virker måske som en simpel sammenkobling af strukturer, men der er subtile problemer, som ikke er umiddelbart indlysende. De to modulstrukturer, som Z repræsenterer, svarer nemlig til den samme abelske gruppe, men det er ikke umiddelbart klart, at de deler den samme skalarmultiplikation. De gør det faktisk, men dette kræver en formel bevisførelse.

Denne situation kan føre til problemer i Lean, når programmet forsøger at afgøre, hvilken type klasseinstans der skal vælges. Hvis du for eksempel direkte beder Lean om at finde en instans, vil programmet vælge én, og du kan se, hvilken en ved at bruge:
#synth Module1 Z Z -- abGrpModule Z.
Problemet opstår dog, når Lean uafhængigt vælger den anden instans i en mere indirekte sammenhæng og derved bliver forvirret. Denne type forvirring kaldes en "dårlig diamant". Udtrykket "dårlig diamant" refererer ikke til operationen, vi talte om tidligere, men snarere til den måde, hvorpå man kan tegne forbindelser mellem Z og dens Module1 Z gennem enten AddCommGroup3 Z eller Ring3 Z.

Det er afgørende at forstå, at ikke alle diamanter er dårlige. Faktisk er diamanter ret almindelige i Mathlib, og de findes i flere steder i dette kapitel. For eksempel så vi allerede i begyndelsen, at man kan gå fra Monoid1 α til Dia1 α gennem enten Semigroup1 α eller DiaOneClass1 α, og takket være arbejdet med klassekommandoen, er de resulterende Dia1 α-instansers definitionelt ens. Når en diamant involverer en Prop-værdi, kan vi være sikre på, at den ikke er dårlig, da enhver to beviser af den samme udsagn er definitionelt ens. Men når vi taler om moduler og den skalarmultiplikation (smul), der er data, ikke beviser, er det et helt andet problem, som kan føre til fejl i implementeringen.

En robust løsning på dette problem er at sikre, at overgangen fra en rig struktur til en fattig struktur altid sker ved at "glemme" data i stedet for at definere nye data. Denne kendte metode kaldes "glemmende arv" og er blevet grundigt diskuteret i forskellige matematiske værker. I vores konkrete tilfælde kan vi ændre definitionen af AddMonoid3 til at inkludere et nsmul-datadomæne og nogle Prop-værdi-felter, der sikrer, at operationen er den, vi tidligere har konstrueret. Dette gør det muligt at arbejde effektivt med Z og samtidigt løse problemerne med dårlig diamanter.

For eksempel kan vi implementere en opdateret version af AddMonoid4, hvor vi definerer en nsmul-funktion, der håndterer multiplikationen med naturlige tal. Dette giver os mulighed for at lave en speciel instans for Z, hvor skalarmultiplikationen defineres som en multiplikation på Z, og vi kan tilbyde specifikke værdier i stedet for at stole på standarddefinitioner.

Dette handler ikke kun om at definere monoid- eller gruppestrukturer; det er også et spørgsmål om at håndtere algebraiske strukturer på en effektiv måde. I Lean håndterer man strukturer som Monoid, Group, Ring og Module på en hierarkisk måde, men det kræver, at man forstår, hvordan data og operationer hænger sammen i systemet. Selvom definitionerne kan være komplekse, er de grundlæggende principper blevet forklaret i denne gennemgang. Når man bevæger sig videre i Mathlib, vil man støde på flere eksempler, hvor man bygger videre på de fundamentale ideer som her er præsenteret.

Endvidere er det nødvendigt at have en dybere forståelse af, hvordan typer og operationer spiller sammen i abstrakt algebra. For eksempel, når man arbejder med funktioner og morfisme, bør man være opmærksom på forskellen mellem at definere en morfisme ved hjælp af et predikat og at pakke funktioner og predikater i en struktur. Morfisme defineres ofte som en funktion, der opfylder specifikke egenskaber, som f.eks. f 1 = 1 og f (g * g') = f g * f g'. At pakke disse funktioner i strukturer gør det lettere at arbejde med dem, især når de skal anvendes i et hierarki af algebraiske strukturer.

Hvordan Matrix Invers og Basis fungerer i Lineær Algebra

I lineær algebra er begreberne matrixinvers og basis fundamentale for at forstå forskellige operationer og strukturer. Matrices, der er kvadratiske, kan have en invers, men det kræver specifikke betingelser for at denne invers eksisterer. Den generelle funktion Ring.inverse, der anvendes på et ringelement, giver et værktøj til at beregne inverse elementer i enhver ring. For en matrix AA defineres dens inverse som A1=1det(A)AadjugeretA^{ -1} = \frac{1}{\text{det}(A)} \cdot A^\text{adjugeret}. Denne definition af matrixinversen er kun anvendelig, når determinanten af matrixen ikke er nul. Når determinanten er nul, siges matrixen at være singulær, og derfor findes der ikke en invers.

Cramers regel giver en vigtig metode til at finde løsninger på lineære systemer ved hjælp af matrixinverser, og reglerne fungerer netop når determinanten af matrixen er forskellig fra nul. Et simpelt eksempel på en matrix og dens inverse kunne være matrixen

A=(1234)A = \begin{pmatrix} 1 & 2 \\ 3 & 4 \end{pmatrix}

dvs. en 2×22 \times 2-matrix. Dens inverse findes ved først at beregne determinanten og derefter bruge adjugeret matrix.

Det er vigtigt at forstå, at selvom definitionen af inverse matrixer er relativt simpel, er det kun for inverterbare matriser, at denne operation giver mening og er anvendelig. For at hjælpe med at håndtere disse typer matriser, anvender vi et begreb som Invertible, der er en generel typeklasse. Denne typeklasse gør det muligt at fange det faktum, at en matrix er inverterbar og giver en strukturel ramme for at anvende matrixinverser i matematiske systemer som Lean.

Når man arbejder med matriser, kan det være nødvendigt at ændre, hvordan vi definerer indeksering af rækker og kolonner. I de fleste praktiske situationer indekseres matrixens rækker og kolonner med naturlige tal, men i nogle tilfælde, som når man arbejder med grafteori, kan det være mere praktisk at indeksere en matrix med elementer fra en hvilken som helst endelig mængde. For eksempel, i tilfældet med en tilstødelsesmatrix for en graf, vil rækkernes og kolonnernes indekser være de specifikke hjørner af grafen. Her kan man bruge enhver type mængde for indekserne, hvilket giver større fleksibilitet i beregningerne.

Når man bevæger sig videre til begrebet basis i et vektorrum, er det vigtigt at bemærke, at basis spiller en central rolle i lineær algebra. En basis i et vektorrum er en mængde af lineært uafhængige vektorer, der spænder rummet, hvilket betyder, at enhver vektor i rummet kan skrives som en entydig lineær kombination af basisvektorerne. En vigtig egenskab ved basis er, at den giver et lineært isomorfisme med en potentiel kraft af det underliggende felt KK. I praksis kan man bruge dette isomorfisme til at forstå og analysere vektorrummet ved hjælp af de koefficienter, der relaterer sig til basisvektorerne.

Der er flere måder at definere en basis på, men den mest anvendte metode i avanceret matematik er at benytte en såkaldt repræsentation, der forholder sig til en lineær isomorfisme med et modellandskab. I Lean-matematiksystemet anvendes en sådan repræsentation gennem funktionen Basis.repr, som gør det muligt at beregne komponenterne af en vektor i forhold til en given basis.

Den vigtigste opmærksomhedspunkt vedrørende basis i uendelige dimensioner er, at de kun giver mening, når vi arbejder med endelige lineære kombinationer. Dette betyder, at når vi definerer basis i et uendeligt vektorrum, skal vi bruge et begreb som direkte summation i stedet for direkte produkt, da dette sikrer, at funktionerne, vi arbejder med, kun har støtte i en endelig mængde.

Som et resultat af dette kan man definere basis for vektorrum, uanset om dimensionen er endelig eller uendelig, ved hjælp af funktioner, der er endeligt understøttede, eller ved hjælp af specielle basisvektorer, der kun har støtte i et enkelt punkt, afhængigt af indekseringssystemet. For et uendeligt mængdeindekseret vektorrum, f.eks. et rum af funktioner med endelig støtte, anvendes det passende koncept af finit støtte, som er fundamentalt i arbejdet med basis.

Endelig er det essentielt at forstå, at mens basis giver os mulighed for at udtrykke enhver vektor som en lineær kombination af basisvektorer, er det ikke altid trivielt at arbejde med uendelige dimensioner uden at sikre, at vi har et passende rammeværk, der håndterer de særlige egenskaber, som uendelige vektorrum kræver.

Hvordan Konvergens og Kontinuitet Virker i Metriske Rum

Når man arbejder med sekvenser og funktioner i matematik, er det essentielt at forstå, hvordan begreberne konvergens og kontinuitet spiller sammen, især når vi bevæger os fra de reelle tal til mere generelle metriske rum. En af de grundlæggende byggeklodser i denne forståelse er metriske rum, som er en generalisering af de reelle tal ved hjælp af afstandsfunktioner.

For at begynde, lad os definere en metrik på et rum X. En metrik er en funktion, der måler afstanden mellem to punkter i X. Dette kan ses som en udvidelse af den velkendte funktion f(x,y)=xyf(x, y) = |x - y| fra de reelle tal til mere generelle rum. For en metrik dist:X×XR\text{dist}: X \times X \rightarrow \mathbb{R} skal følgende egenskaber være opfyldt:

  1. dist(a,b)0\text{dist}(a, b) \geq 0 for alle a,bXa, b \in X (ikke-negativitet),

  2. dist(a,b)=0\text{dist}(a, b) = 0 hvis og kun hvis a=ba = b (identitet),

  3. dist(a,b)=dist(b,a)\text{dist}(a, b) = \text{dist}(b, a) for alle a,bXa, b \in X (symmetri),

  4. dist(a,c)dist(a,b)+dist(b,c)\text{dist}(a, c) \leq \text{dist}(a, b) + \text{dist}(b, c) for alle a,b,cXa, b, c \in X (trekantulighed).

Dette giver os den nødvendige struktur til at definere konvergens af sekvenser og kontinuitet af funktioner.

Konvergens i Metriske Rum

For en sekvens u:NXu: \mathbb{N} \to X i et metrisk rum XX siger vi, at uu konvergerer til et punkt xXx \in X, hvis for hver ϵ>0\epsilon > 0 findes et NNN \in \mathbb{N}, således at for alle nNn \geq N gælder dist(un,x)<ϵ\text{dist}(u_n, x) < \epsilon. Dette kan formelt skrives som:

Tendsto u atTop (Nx)    ϵ>0,N,nN,dist(un,x)<ϵ.\text{Tendsto } u \text{ atTop } (N x) \iff \forall \epsilon > 0, \exists N, \forall n \geq N, \text{dist}(u_n, x) < \epsilon.

Denne definition beskriver, at for hver vilkårlig lille afstand ϵ\epsilon, vil der være en tærskel NN, så alle termer i sekvensen efter NN ligger inden for en afstand ϵ\epsilon af punktet xx.

En vigtig observation her er, at konvergens i metriske rum ikke er begrænset til de reelle tal, men kan anvendes på enhver metrik, der opfylder de tidligere nævnte egenskaber.

Kontinuitet af Funktioner

Kontinuitet af en funktion f:XYf: X \to Y mellem to metriske rum XX og YY er defineret som, at for hvert punkt xXx \in X og for hver ϵ>0\epsilon > 0, findes et δ>0\delta > 0, således at hvis dist(x,x)<δ\text{dist}(x, x') < \delta, så gælder dist(f(x),f(x))<ϵ\text{dist}(f(x), f(x')) < \epsilon.

Dette kan skrives som:

Kontinuitet af f    xX,ϵ>0,δ>0,xX,dist(x,x)<δ    dist(f(x),f(x))<ϵ.\text{Kontinuitet af } f \iff \forall x \in X, \forall \epsilon > 0, \exists \delta > 0, \forall x' \in X, \text{dist}(x', x) < \delta \implies \text{dist}(f(x'), f(x)) < \epsilon.

Det betyder, at funktionens værdi ændrer sig kontinuerligt i nærheden af xx, hvilket er den intuitive forståelse af, hvad det vil sige for en funktion at være kontinuerlig.

Relationer Mellem Konvergens og Kontinuitet

Konvergens og kontinuitet er tæt forbundne, og deres relation kan udforskes gennem en række teoremer og lemmer. Et af de centrale begreber er, at kontinuitet bevarer konvergens. Det vil sige, at hvis en sekvens unu_n konvergerer til xx, og ff er en kontinuerlig funktion, så vil f(un)f(u_n) konvergere til f(x)f(x). Dette er et fundamentalt resultat i analysen og kan bruges til at bevise mange andre resultater i metriske rum.

Desuden kan vi også definere lokal kontinuitet, hvor en funktion er kontinuerlig i et punkt xXx \in X, men ikke nødvendigvis globalt. Dette skaber en yderligere nuance i analysen af funktioner mellem metriske rum.

Baller og Åbne Mængder

En vigtig geometrisk idé i metriske rum er definitionen af åbne og lukkede baller. En åben ball med radius rr omkring et punkt aa i et metriske rum er mængden af alle punkter bXb \in X, som opfylder dist(a,b)<r\text{dist}(a, b) < r. En lukket ball er den mængde, hvor dist(a,b)r\text{dist}(a, b) \leq r. Disse begreber er grundlæggende for at definere åbne og lukkede mængder, hvilket er essentielle værktøjer i topologi og analyse.

Når vi arbejder med åbne og lukkede mængder, kan vi også formulere konvergens og kontinuitet på en mere geometrisk måde, hvor man ser på hvordan punkter tæt på hinanden opfører sig i forhold til funktioner og sekvenser.

For eksempel, når man arbejder med en sekvens unu_n, og unu_n tilhører en given mængde MM for tilstrækkeligt store nn, så kan man vise, at hvis sekvensen konvergerer til et punkt xx, så vil xx nødvendigvis være en del af mængdens lukning, closure(M)\text{closure}(M). Dette er et simpelt, men vigtigt eksempel på, hvordan konvergens og mængder interagerer i metriske rum.