Merge branch 'main' of github.com:hhu-adam/lean4game

pull/43/head
Alexander Bentkamp 4 years ago
commit ada40dcf34

@ -77,7 +77,7 @@ function LeftPanel({ spells, inventory, showSidePanel, setShowSidePanel }) {
<ListItemIcon sx={{minWidth: 0, mr: open ? 3 : 'auto', justifyContent: 'center' }}> <ListItemIcon sx={{minWidth: 0, mr: open ? 3 : 'auto', justifyContent: 'center' }}>
<FontAwesomeIcon icon={faHammer}></FontAwesomeIcon> <FontAwesomeIcon icon={faHammer}></FontAwesomeIcon>
</ListItemIcon> </ListItemIcon>
<ListItemText primary="Tactics" sx={{ display: showSidePanel ? null : "none" }} /> <ListItemText primary="Known Tactics" sx={{ display: showSidePanel ? null : "none" }} />
</ListItemButton> </ListItemButton>
{spells && spells.length > 0 && {spells && spells.length > 0 &&
<Paper sx={{ px: 2, py: 1, display: showSidePanel ? null : "none" }} elevation={0} > <Paper sx={{ px: 2, py: 1, display: showSidePanel ? null : "none" }} elevation={0} >
@ -89,7 +89,7 @@ function LeftPanel({ spells, inventory, showSidePanel, setShowSidePanel }) {
<ListItemIcon sx={{minWidth: 0, mr: open ? 3 : 'auto', justifyContent: 'center' }}> <ListItemIcon sx={{minWidth: 0, mr: open ? 3 : 'auto', justifyContent: 'center' }}>
<FontAwesomeIcon icon={faBook}></FontAwesomeIcon> <FontAwesomeIcon icon={faBook}></FontAwesomeIcon>
</ListItemIcon> </ListItemIcon>
<ListItemText primary="Lemmas" sx={{ display: showSidePanel ? null : "none" }} /> <ListItemText primary="Known Lemmas" sx={{ display: showSidePanel ? null : "none" }} />
</ListItemButton> </ListItemButton>
{inventory && inventory.length > 0 && {inventory && inventory.length > 0 &&
<Paper sx={{ px: 2, py: 1, mt: 2, display: showSidePanel ? null : "none" }} elevation={0} > <Paper sx={{ px: 2, py: 1, mt: 2, display: showSidePanel ? null : "none" }} elevation={0} >

@ -9,6 +9,11 @@ import { MathJax } from "better-react-mathjax";
import List from '@mui/material/List'; import List from '@mui/material/List';
import ListItem from '@mui/material/ListItem'; import ListItem from '@mui/material/ListItem';
import { Paper, Box, Typography, Alert, FormControlLabel, FormGroup, Switch, Collapse } from '@mui/material'; import { Paper, Box, Typography, Alert, FormControlLabel, FormGroup, Switch, Collapse } from '@mui/material';
import { Accordion, AccordionSummary, AccordionDetails, Divider } from '@mui/material';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faArrowPointer } from '@fortawesome/free-solid-svg-icons'
// TODO: Dead variables (x✝) are not displayed correctly. // TODO: Dead variables (x✝) are not displayed correctly.
@ -46,27 +51,82 @@ function Goal({ goal }) {
{hasHints && {hasHints &&
<FormControlLabel <FormControlLabel
control={<Switch checked={showHints} onChange={handleHintsChange} />} control={<Switch checked={showHints} onChange={handleHintsChange} />}
label="Help" label="More Help?"
/>} />}
{hints.map((hint) => <Collapse in={showHints}><Alert severity="warning" sx={{ mt: 1 }}><MathJax><ReactMarkdown>{hint.message}</ReactMarkdown></MathJax></Alert></Collapse>)} {hints.map((hint) => <Collapse in={showHints}><Alert severity="info" sx={{ mt: 1 }}><MathJax><ReactMarkdown>{hint.message}</ReactMarkdown></MathJax></Alert></Collapse>)}
</Box>) </Box>)
} }
/* Function to display a goal that is not the main goal. */
function OtherGoal({ goal }) {
const hasObject = typeof goal.objects === "object" && goal.objects.length > 0
const hasAssumption = typeof goal.assumptions === "object" && goal.assumptions.length > 0
return (
<Accordion>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Typography color="primary" sx={{ ml: 0 }}> {goal.goal}</Typography>
</AccordionSummary>
<AccordionDetails sx={{ backgroundColor: "aliceblue" }}>
{hasObject &&
<Box>
<Typography>Objects</Typography>
<List>
{goal.objects.map((item) =>
<ListItem key={item.userName}>
<Typography color="primary" sx={{ mr: 1 }}>{item.userName}</Typography> :
<Typography color="secondary" sx={{ ml: 1 }}>{item.type}</Typography>
</ListItem>)}
</List>
</Box>}
{hasAssumption &&
<Box>
<Typography>Assumptions</Typography>
<List>
{goal.assumptions.map((item) =>
<ListItem key={item}>
<Typography color="primary" sx={{ mr: 1 }}>{item.userName}</Typography> :
<Typography color="secondary" sx={{ ml: 1 }}>{item.type}</Typography>
</ListItem>)}
</List>
</Box>}
<Typography>Prove:</Typography>
<Typography color="primary" sx={{ ml: 2 }}>{goal.goal}</Typography>
</AccordionDetails>
</Accordion>)
}
function TacticState({ goals, diagnostics, completed }) { function TacticState({ goals, diagnostics, completed }) {
const hasError = typeof diagnostics === "object" && diagnostics.length > 0 const hasError = typeof diagnostics === "object" && diagnostics.length > 0
const hasGoal = goals !== null && goals.length > 0 const hasGoal = goals !== null && goals.length > 0
const hasManyGoal = hasGoal && goals.length > 1 const hasManyGoal = hasGoal && goals.length > 1
return ( return (
<Box sx={{ height: "100%" }}> <Box sx={{ height: "100%" }}>
{goals === null && <Typography variant="h6">No goals at cursor position</Typography>} {hasGoal &&
{hasGoal && <Paper sx={{ pt: 1, pl: 2, pr: 3, pb: 1, height: "100%" }}><Typography variant="h5">Main goal at cursor</Typography> <Goal goal={goals[0]} /></Paper>} <Paper sx={{ pt: 1, pl: 2, pr: 3, pb: 1, height: "100%" }}>
<Typography variant="h5">Main Goal
(at <FontAwesomeIcon icon={faArrowPointer}></FontAwesomeIcon>)
</Typography>
<Goal goal={goals[0]} />
</Paper>}
{!(hasGoal || completed) &&
<Typography variant="h6">
No goals
(at <FontAwesomeIcon icon={faArrowPointer}></FontAwesomeIcon>)
</Typography>}
{completed && <Typography variant="h6">Level completed ! 🎉</Typography>} {completed && <Typography variant="h6">Level completed ! 🎉</Typography>}
{hasError && <Paper sx={{ pt: 1, pl: 2, pr: 3, pb: 1, height: "100%" }}> {hasError &&
{diagnostics.map(({severity, message}) => <Typography color={{1: "red", 2:"orange", 3:"blue", 4:"gray"}[severity]}>{message}</Typography>)} <Paper sx={{ pt: 1, pl: 2, pr: 3, pb: 1, height: "100%" }}>
<Typography variant="h5" sx={{ mb: 2 }}>Lean says</Typography>
{diagnostics.map(({severity, message}) =>
<Alert severity={{1: "error", 2:"warning", 3:"info", 4:"success"}[severity]} sx={{ mt: 1 }}>{message}</Alert>
// TODO: When does Lean give severity=4? Had colour `gray` before. Make custom theme for that
)}
</Paper>} </Paper>}
{hasManyGoal && <Paper sx={{ pt: 1, pl: 2, pr: 3, pb: 1, mt: 1 }}> {hasManyGoal && <Paper sx={{ pt: 1, pl: 2, pr: 3, pb: 1, mt: 1 }}>
<Typography variant="h6" sx={{ mb: 2 }}>Other goals</Typography> <Typography variant="h5" sx={{ mb: 2 }}>Further Goals</Typography>
{goals.slice(1).map((goal, index) => <Paper><Goal key={index} goal={goal} /></Paper>)} {goals.slice(1).map((goal, index) => <Paper><OtherGoal key={index} goal={goal} /></Paper>)}
</Paper>} </Paper>}
</Box> </Box>
) )

@ -11,23 +11,30 @@ Introduction
Willkommen zum Lean-Crashkurs wo du lernst wie man mathematische Beweise vom Computer Willkommen zum Lean-Crashkurs wo du lernst wie man mathematische Beweise vom Computer
unterstützt und verifiziert schreiben kann. unterstützt und verifiziert schreiben kann.
Ein Beweis besteht in Lean aus verschiedenen **Taktiken**, welche ungefähr einem *Rechts* siehst den Status des Beweis. Unter **Main Goal** steht, was du im Moment am Beweisen
logischen Schritt entsprechen, den man auf Papier aufschreiben würde. bist. Falls es mehrere Subgoals gibt, werden alle weiteren darunter unter **Further Goals**
aufgelistet, diese musst du dann später auch noch zeigen.
Rechts im **Infoview** siehst den Status des aktuellen Beweis.
Du siehst ein oder mehrere offene **Goals** (mit einem `⊢` davor), die du noch zeigen musst. Ein Beweis besteht aus mehreren **Taktiken**. Das sind einzelne Beweisschritte, ähnlich wie
Wenn du eine Taktik hinschreibst, dann versucht Lean diesen Schritt beim man auf Papier argumentieren würde. Manche Taktiken können ganz konkret etwas kleines machen,
ersten offenen Goal zu machen. andere sind stark und lösen ganze Probleme automatisiert. Du findest die Taktiken *Links* an der
Wenn der Beweis komplett ist, erscheint \"goals accomplished\". Seite.
Wenn der Beweis komplett ist, erscheint \"Level Completed! 🎉\".
Deine erste Taktik ist `rfl`, welche dazu da ist, ein Goal der Form `X = X` zu schliessen.
Gib die Taktik ein gefolgt von Enter ⏎.
" "
Statement "Zeige $ 42 = 42 $." : 42 = 42 := by Statement "Zeige $ 42 = 42 $." : 42 = 42 := by
rfl rfl
Message : 42 = 42 => Message : 42 = 42 =>
"Die erste Taktik ist `rfl`, die ein Goal von der Form `A = A` beweist." "Die Taktik `rfl` beweist ein Goal der Form `X = X`."
Hint : 42 = 42 => Hint : 42 = 42 =>
"Man schreibt eine Taktik pro Zeile, also gib 'rfl' ein gefolgt von ENTER." "Man schreibt eine Taktik pro Zeile, also gib 'rfl' ein und geh mit Enter ⏎ auf eine neue Zeile."
Conclusion "Bravo!" Conclusion "Bravo!"
Tactics rfl

@ -8,22 +8,20 @@ Title "Definitionally equal"
Introduction Introduction
" "
Achtung: `rfl` kann auch Gleichungen beweisen, wenn die beiden Terme Lean-intern gleich **Vorsicht:** `rfl` kann auch Gleichungen beweisen, wenn die beiden Terme Lean-intern gleich
definiert sind, auch wenn diese unterschiedlich dargestellt werden. definiert sind, auch wenn diese unterschiedlich dargestellt werden. Das kann anfänglich
So sind `1 + 1` und `2` per Definition das Gleiche, da sie beide von Lean als `0.succ.succ` zu Verwirrung führen.
gelesen werden.
Das kann anfänglich verwirrend sein und das Verhalten hängt von der Lean-Implementation ab. So sind `2` definiert als `1 + 1`, deshalb funktioniert `rfl` auch hier.
" "
Statement "Zeige dass eins plus eins zwei ist." : 1 + 1 = 2 := by Statement "Zeige dass $1 + 1$ zwei ist." : 1 + 1 = 2 := by
rfl rfl
Conclusion Conclusion
" "
Im weiteren führen die meisten anderen Taktiken `refl` automatisch am Ende aus, **Notiz:** Die meisten anderen Taktiken versuchen am Schluss automatisch `rfl`
deshalb musst du dieses häufig gar nicht mehr schreiben. aufzurufen, deshalb brauchst du das nur noch selten.
" "
Tactics rfl Tactics rfl
Lemmas zero_add

@ -8,13 +8,14 @@ Title "Annahmen"
Introduction Introduction
" "
Mathematische Aussagen haben Annahmen. Das sind zum einen Objekte, wie \"sei `n` eine Um Aussagen zu formulieren brauchen wir Annahmen. Das sind zum einen Objekte, wie \"sei `n` eine
natürliche Zahl\", oder auch wahre Aussagen über diese Objekte, wie zum Beispiel natürliche Zahl\", und Annahmen über diese Objekte, von denen wir wissen, dass sie wahr sind.
Zum Beispiel
\"und angenommen, dass `n` strikt grösser als `1` ist\". \"und angenommen, dass `n` strikt grösser als `1` ist\".
In Lean schreibt man beides mit dem gleichen Syntax: `(n : ) (h : 1 < n)` definiert In Lean schreibt man beides mit dem gleichen Syntax: `(n : ) (h : 1 < n)` definiert
zuerst `n` als natürliche Zahl und kreeirt eien Annahme, dass `1 < n`. Dieser Annahme geben wir zuerst eine natürliche Zahl `n` und eine Annahme dass `1 < n` (die Annahme kriegt
den Namen `h`. den Namen `h`).
Wenn das Goal genau einer Annahme entspricht, kann man diese mit `assumption` beweisen. Wenn das Goal genau einer Annahme entspricht, kann man diese mit `assumption` beweisen.
" "
@ -24,6 +25,9 @@ Statement triviale_angelegenheit
(n : ) (h : 1 < n) : 1 < n := by (n : ) (h : 1 < n) : 1 < n := by
assumption assumption
Message (n : ) (h : 1 < n) : 1 < n =>
"`assumption` sucht nach einer Annahme, die dem Goal entspricht."
Conclusion "" Conclusion ""
Tactics assumption Tactics assumption

@ -9,18 +9,22 @@ Title "Logische Aussagen: `Prop`"
Introduction Introduction
" "
Eine allgemeine logische Aussage definiert man mit `(A : Prop)`. Damit sagt man noch nicht, Eine allgemeine logische Aussage definiert man mit `(A : Prop)`.
ob die Aussage `A` wahr oder falsch ist. Mit einer Annahme `(hA : A)` nimmt man an, dass
`A` wahr ist: `hA` ist ein Beweis der Aussage `A`. Damit sagt man noch nicht, ob die Aussage `A` wahr oder falsch ist.
Mit einer Annahme `(hA : A)` nimmt man an, dass `A` wahr ist:
`hA` ist sozusagen ein Beweis von `A`.
" "
-- TODO: Macht es Sinn mehrere Aufgaben auf einer Seite zu haben?
Statement mehr_triviales Statement mehr_triviales
"Sei $ A $ eine logische Aussage und sei `hA` ein Beweis für $A$. "Sei $ A $ eine logische Aussage und sei `hA` ein Beweis für $A$.
Zeige, dass $ A $ wahr ist." Zeige, dass $ A $ wahr ist."
(A : Prop) (hA : A) : A := by (A : Prop) (hA : A) : A := by
assumption assumption
Hint (A : Prop) (hA : A) : A =>
"Auch hier kann `assumption` den Beweis von `A` finden."
Conclusion "" Conclusion ""
Tactics assumption Tactics assumption

@ -12,39 +12,41 @@ Introduction
Oft sind aber die Annahmen nicht genau das, was man zeigen will, sondern man braucht Oft sind aber die Annahmen nicht genau das, was man zeigen will, sondern man braucht
mehrere Schritte im Beweis. mehrere Schritte im Beweis.
Wenn man eine Annahme `(h : X = Y)` hat die sagt, dass `X` und `Y` gleich sind, Wenn man eine Annahme `(h : X = Y)` hat,
kann man die Taktik `rw` (steht für 'rewrite') brauchen um im Goal kann die Taktik `rw [h]` im Goal `X` durch `Y` ersetzen.
das eine durch das andere zu ersetzen. (`rw` steht für *rewrite*)
" "
Statement umschreiben Statement umschreiben
" "Angenommen man hat die Gleichheiten
Angenommen man hat die Gleichheiten $a = b$, $a = d$, $c = d$.
`a = b`, `a = d`, `c = d`. Zeige dass $b = c$."
Zeige dass `b = c`.
"
(a b c d : ) (h₁ : c = d) (h₂ : a = b) (h₃ : a = d) : b = c := by (a b c d : ) (h₁ : c = d) (h₂ : a = b) (h₃ : a = d) : b = c := by
rw [h₁] rw [h₁]
rw [←h₂] rw [←h₂]
assumption assumption
-- Gleich am Anfang anzeigen.
Message (a : ) (b : ) (c : ) (d : ) (h₁ : c = d) (h₂ : a = b) (h₃ : a = d) : b = c => Message (a : ) (b : ) (c : ) (d : ) (h₁ : c = d) (h₂ : a = b) (h₃ : a = d) : b = c =>
"Wenn man eine Annahme `(h₁ : c = d)` hat, kann man mit `rw [h₁]` (oder `rewrite [h₁]`) das erste "Die kleinen Zahlen `h₁ h₂ h₃` werden in Lean oft verwendet und man tippt diese mit
`c` im Goal mit `d` ersetzen." `\\1`, `\\2`, `\\3`, …"
Hint (a : ) (b : ) (c : ) (d : ) (h₁ : c = d) (h₂ : a = b) (h₃ : a = d) : b = c => Hint (a : ) (b : ) (c : ) (d : ) (h₁ : c = d) (h₂ : a = b) (h₃ : a = d) : b = c =>
"Die kleinen Zahlen `h₁ h₂ h₃` werden in Lean oft verwendet und man schreibt diese mit "Im Goal kommt `c` vor und `h₁` sagt `c = d`.
`\\1`, `\\2`, `\\3`, …" Probiers doch mit `rw [h₁]`."
Message (a : ) (b : ) (c : ) (d : ) (h₁ : c = d) (h₂ : a = b) (h₃ : a = d) : b = d => Message (a : ) (b : ) (c : ) (d : ) (h₁ : c = d) (h₂ : a = b) (h₃ : a = d) : b = d =>
"Mit `rw [← h₂]` (`\\l`, also klein L wie \"left\") kann man eine Hypotheses " Man kann auch rückwärts umschreiben: `h₂` sagt `a = b` mit
`(h₂ : a = b)` rückwärts anwenden und `b` durch `a` ersetzen." `rw [←h₂]` ersetzt man im Goal `b` durch `a` (`\\l`, also ein kleines L)"
Hint (a : ) (b : ) (h : a = b) : a = b =>
"Schau mal durch die Annahmen durch."
-- TODO: Muss ich das wirklich mehrmals auflisten? -- -- TODO: Muss ich das wirklich mehrmals auflisten?
Message (x : ) : x = x => -- Message (x : ) : x = x =>
"Der Hauptunterschied zwischen `rw` und `rewrite` ist, dass das erste automatisch versucht, -- "Der Hauptunterschied zwischen `rw` und `rewrite` ist, dass das erste automatisch versucht,
anschliessend `rfl` anzuwenden. Bei `rewrite` musst du `rfl` explizit noch aufrufen." -- anschliessend `rfl` anzuwenden. Bei `rewrite` musst du `rfl` explizit noch aufrufen."
Conclusion "Übrigens, mit `rw [h₁] at h₂` kann man auch eine andere Annahme umschreiben Conclusion "Übrigens, mit `rw [h₁] at h₂` kann man auch eine andere Annahme umschreiben
anstatt dem Goal." anstatt dem Goal."

@ -8,7 +8,9 @@ Level 6
Title "Implikation" Title "Implikation"
Introduction Introduction
" "Als nächstes widmen wir uns der Implikation &A \\Rightarrow B&. TODO
Logische Aussagen `(A : Prop)`, `(B : Prop)`
Wie wir schon gesehen haben, wir eine logische Aussage als `(A : Prop)` geschrieben, und Wie wir schon gesehen haben, wir eine logische Aussage als `(A : Prop)` geschrieben, und
die Annahme, dass `A` wahr ist als `(hA : A)`, also `hA` ist sozusagens ein Beweis der die Annahme, dass `A` wahr ist als `(hA : A)`, also `hA` ist sozusagens ein Beweis der
Aussage `A`. Aussage `A`.
@ -18,8 +20,7 @@ Logische Aussagen können einander implizieren. Wir kennen hauptsächlich zwei Z
Wenn man Aussage `B` beweisen will und eine Implikationsannahme `(h : A → B)` hat, dann kann man Wenn man Aussage `B` beweisen will und eine Implikationsannahme `(h : A → B)` hat, dann kann man
diese mit `apply h` anwenden. diese mit `apply h` anwenden.
Auf Papier würde man schreiben, \"es genügt zu zeigen, dass `A` stimmt, denn `A` impliziert `B`\". Auf Papier würde man schreiben, \"es genügt zu zeigen, dass `A` stimmt, denn `A` impliziert `B`\"."
"
Statement Statement
"Seien `A`, `B` logische Aussagen, wobei `A` wahr ist und `A` impliziert `B`. "Seien `A`, `B` logische Aussagen, wobei `A` wahr ist und `A` impliziert `B`.
@ -32,5 +33,4 @@ Message (A : Prop) (B : Prop) (hA : A) (g : A → B) : A =>
"Nachdem du die Implikation `A → B` angewendet hast, musst du nur noch `A` zeigen, "Nachdem du die Implikation `A → B` angewendet hast, musst du nur noch `A` zeigen,
dafür hast du bereits einen Beweis in den Annahmen." dafür hast du bereits einen Beweis in den Annahmen."
Tactics apply Tactics apply assumption
Tactics assumption

Loading…
Cancel
Save