This commit is contained in:
Oystein Kristoffer Tveit 2021-08-29 19:57:57 +02:00
parent dcdd3e78e5
commit b06a6e58f9
36 changed files with 1962 additions and 0 deletions

277
exam/.vscode/latex.code-snippets vendored Normal file
View File

@ -0,0 +1,277 @@
{
"Exc": {
"scope": "latex",
"prefix": ["\\exc"],
"body":
[
"\\exc{}",
"\\begin{subexcs}",
" \\subexc{}",
" $0",
"\\end{subexcs}"
],
"description": "Adds new exc with subexcs",
},
"Subexc": {
"scope": "latex",
"prefix": ["\\subexc"],
"body":
[
"\\subexc{}",
"\\begin{ssubexcs}",
" \\ssubexc{}",
" $0",
"\\end{ssubexcs}"
],
"description": "Adds new subexc with ssubexcs",
},
"Diagram": {
"scope": "latex",
"prefix": ["dia"],
"body": "\\includeDiagram[caption={}, width=1\\linewidth]{graphics/$0.tex}",
"description": "Include a diagram",
},
"Graph Table": {
"scope": "latex",
"prefix": ["graph-table"],
"body":
[
"\\begin{figure}[H]",
" \\center",
" \\begin{tabular}{c|cc}",
" $A$ & \\multicolumn{2}{c}{$v$} \\\\",
" \\hline",
" & $a$ & $b$ \\\\",
" \\hline",
" $s_0$ & $s_$ & $s_$ \\\\",
" $s_1$ & $s_$ & $s_$ \\\\",
" $s_2$ & $s_$ & $s_$ \\\\",
" \\end{tabular}",
"\\end{figure}"
],
"description": "Adds graph-table",
},
"Graph Table Double": {
"scope": "latex",
"prefix": ["graph-dtable"],
"body":
[
"\\begin{figure}[H]",
" \\center",
" \\begin{tabular}{c|cc}",
" $A$ & \\multicolumn{2}{c}{$v$} \\\\",
" \\hline",
" & $a$ & $b$ \\\\",
" \\hline",
" $s_0$ & $s_$ & $s_$ \\\\",
" $s_1$ & $s_$ & $s_$ \\\\",
" $s_2$ & $s_$ & $s_$ \\\\",
" \\end{tabular}",
"\\end{figure}"
],
"description": "Adds graph-table",
},
"Graph Table Line": {
"scope": "latex",
"prefix": ["gtl"],
"body": " $s_$ & $s_$ & $s_$ \\\\",
"description": "Adds line inside graph-table",
},
"Graph Table Double Line": {
"scope": "latex",
"prefix": ["gtdl"],
"body": " $s_$ & $s_$ & $s_$ & $s_$ & $s_$ \\\\",
"description": "Adds line inside a double graph-table",
},
"Induction Proof": {
"scope": "latex",
"prefix": ["prove-induction"],
"body": [
"Base case:",
"",
"\\begin{align*}",
"",
"\\end{align*}",
"",
"Assume that",
"",
"\\[ $1 \\]",
"",
"Then",
"",
"\begin{align*}",
" &= $1 + \\\\",
" &=",
"\\end{align*}",
"",
"\\qed"
],
"description": "Template for induction proof",
},
"Injective Proof": {
"scope": "latex",
"prefix": ["prove-injective"],
"body": [
"In order for $f(x)$ to be injective, it has to hold that",
"",
"\\[ f(a) = f(b) \\Rightarrow a = b \\]",
"",
"\\begin{align*}",
" f(a) &= f(b) \\\\",
" $0",
"\\end{align*}",
"",
"Hence $f(x)$ is injective."
],
"description": "Template for injective proof",
},
"Surjective Proof": {
"scope": "latex",
"prefix": ["prove-surjective"],
"body": [
"In order for $f(x)$ to be surjective, it has to hold that",
"",
"\\[ \\forall x \\in SET \\exists y \\in SET [f(x) = y] \\]",
"",
"\\begin{align*}",
" y &= $1 \\\\",
"",
" x &= \\\\" ,
"\\end{align*}",
"",
"$ $ makes up all the elements in SET",
"",
"\\begin{align*}",
" f(y) &= \\\\",
"",
"\\end{align*}",
"",
"Hence $f(x)$ is surjective"
],
"description": "Template for surjective proof",
},
"Bijective Function Proof": {
"scope": "latex",
"prefix": ["prove-bijective"],
"body": [
"\\textbf{Injective:}",
"",
"In order for $f(x)$ to be injective, it has to hold that",
"",
"\\[ f(a) = f(b) \\Rightarrow a = b \\]",
"",
"\\begin{align*}",
" f(a) &= f(b) \\\\",
" $0",
"\\end{align*}",
"",
"Hence $f(x)$ is injective.",
"",
"",
"\\textbf{Surjective:}",
"",
"In order for $f(x)$ to be surjective, it has to hold that",
"",
"\\[ \\forall x \\in SET \\exists y \\in SET [f(x) = y] \\]",
"",
"\\begin{align*}",
" y &= $1 \\\\",
"",
" x &= \\\\" ,
"\\end{align*}",
"",
"$ $ makes up all the elements in SET",
"",
"\\begin{align*}",
" f(y) &= \\\\",
"",
"\\end{align*}",
"",
"Hence $f(x)$ is surjective",
"",
"",
"\\textbf{Inverse:}",
"",
"The inverse is the same as the expression which makes up $x$ which we used to prove that $f(x)$ is surjective. Hence",
"",
"\\[ f^{-1}(x) = \\]",
],
"description": "Template for bijective proof",
},
"Equivalence Relation Proof": {
"scope": "latex",
"prefix": ["prove-eq-rel"],
"body": [
"In order for this relation to be an equivalence equation, it has to be reflexive, symmetric and transitive.",
"",
"\\textbf{Reflexive:}",
"",
"\\[ \\]",
"",
"\\textbf{Symmetric:}",
"",
"\\[ \\]",
"",
"\\textbf{Transitive:}",
"",
"\\[ \\]",
"",
"Hence the relation is an equivalence relation",
],
"description": "Template for equivalence relation proof",
},
"Partial Order Proof": {
"scope": "latex",
"prefix": ["prove-poset"],
"body": [
"In order for this relation to be a partial order, it has to be reflexive, antisymmetric and transitive.",
"",
"\\textbf{Reflexive:}",
"",
"\\[ \\]",
"",
"\\textbf{Antisymmetric:}",
"",
"\\[ \\]",
"",
"\\textbf{Transitive:}",
"",
"\\[ \\]",
"",
"Hence the relation is a partial order",
],
"description": "Template for poset proof",
},
"Poset MinMax": {
"scope": "latex",
"prefix": ["minmax-poset"],
"body": [
"Minimal elements:",
" \\[ \\{ $0 \\} \\]",
"Maximal elements:",
" \\[ \\{ \\} \\]"
],
"description": "Minimal maximal elements for poset",
},
"Binomial Coefficient": {
"scope": "latex",
"prefix": ["binom-co"],
"body": "\\[ \nCr{$0}{$1}x^{$2}y^{$1} = $3 x^{$2}y^{$1}\\]",
"description": "Formula for a binomial coefficient",
},
}

16
exam/.vscode/makefile.code-snippets vendored Normal file
View File

@ -0,0 +1,16 @@
{
"hasse": {
"scope": "makefile",
"prefix": ["hasse"],
"body": "python ../../python/Hasse.py graphics/src/$1.txt graphics/$1.tex",
"description": "Add hasse diagram",
},
"FSA": {
"scope": "makefile",
"prefix": ["fsa"],
"body": "python ../../python/FSA.py graphics/src/$1.txt graphics/$1.tex",
"description": "Add FSA diagram",
}
}

15
exam/Makefile Normal file
View File

@ -0,0 +1,15 @@
.DEFAULT_GOAL := default
.PHONY: default python
default: python
pdflatex main.tex
SRC_DIR := $(shell find graphics/src -type f -printf "%f\n" -name *.txt | cut -d '.' -f1)
python:
@for f in $(SRC_DIR); \
do \
echo -e "\033[33mCOMPILING $$f.tex\033[0m"; \
python ../exam_template/python/run.py graphics/src/$$f.txt graphics/$$f.tex; \
echo ""; \
done

24
exam/graphics/14.tex Normal file
View File

@ -0,0 +1,24 @@
\begin{tikzpicture}
\tikzset{
->, % makes the edges directed
>=Stealth, % makes the arrow heads bold
node distance=5cm, % specifies the minimum distance between two nodes. Change if necessary.
every state/.style={thick, fill=white}, % sets the properties for each state node
initial text=$ $, % sets the text that appears on the start arrow
}
\node[state, ] (s0) {$s_0$};
\node[state, right of=s0] (s1) {$s_1$};
\node[state, right of=s1] (s2) {$s_2$};
\draw (s0) edge[bend right, below] node{$a,0$} (s1);
\draw (s0) edge[above] node{$c,1$} (s1);
\draw (s0) edge[loop,above] node{b,1} (s0);
\draw (s1) edge[above] node{$a,1$} (s2);
\draw (s1) edge[bend right, above] node{$b,0$} (s0);
\draw (s1) edge[bend right, above] node{$c,0$} (s0);
\draw (s2) edge[bend right, above] node{$a,0$} (s1);
\draw (s2) edge[bend left, below] node{$b,1$} (s0);
\draw (s2) edge[loop,above] node{c,0} (s2);
\end{tikzpicture}

24
exam/graphics/14mod.tex Normal file
View File

@ -0,0 +1,24 @@
\begin{tikzpicture}
\tikzset{
->, % makes the edges directed
>=Stealth, % makes the arrow heads bold
node distance=5cm, % specifies the minimum distance between two nodes. Change if necessary.
every state/.style={thick, fill=white}, % sets the properties for each state node
initial text=$ $, % sets the text that appears on the start arrow
}
\node[state, ] (s0) {$s_0$};
\node[state, right of=s0] (s1) {$s_1$};
\node[state, right of=s1] (s2) {$s_2$};
\draw (s0) edge[bend right, above] node{$a,0$} (s1);
\draw (s0) edge[above] node{$c,1$} (s1);
\draw (s0) edge[loop,above] node{b,1} (s0);
\draw (s1) edge[above] node{$a,1$} (s2);
\draw (s1) edge[bend right=60, above] node{$b,0$} (s0);
\draw (s1) edge[bend right, above] node{$c,0$} (s0);
\draw (s2) edge[bend right, above] node{$a,0$} (s1);
\draw (s2) edge[bend left, below] node{$b,1$} (s0);
\draw (s2) edge[loop,above] node{c,0} (s2);
\end{tikzpicture}

22
exam/graphics/16.tex Normal file
View File

@ -0,0 +1,22 @@
\newcommand{\arrow}[2]{\path [-{Latex[scale=1]}] (#1) edge (#2);}
\begin{tikzpicture}
\begin{scope}[every node/.style={shape=circle, fill=white, draw, inner sep=2pt}]
\node (A) at (0,2.5) {$A$};
\node (B) at (-2.37764,0.77254) {$B$};
\node (C) at (-1.46946,-2.02254) {$C$};
\node (D) at (1.46946,-2.02254) {$D$};
\node (E) at (2.37764,0.77254) {$E$};
\end{scope}
\begin{scope}[every draw/.style={}]
\draw (A) -- (B);
\draw (A) -- (C);
\draw (A) -- (E);
\draw (B) -- (D);
\draw (B) -- (E);
\draw (D) -- (E);
\end{scope}
\end{tikzpicture}

37
exam/graphics/17.tex Normal file
View File

@ -0,0 +1,37 @@
\newcommand{\point}[4]{
\node [label=#3:#4] (#1) at #2 {};
}
\newcommand{\wpath}[3]{
\draw (#1) -- (#2) node [midway, above, sloped] (Tx#1#2) {{\tiny $#3$}};
}
\begin{tikzpicture}[]
\begin{scope}[every node/.style={fill=black, shape=circle, inner sep=1pt}]
\point{1}{(0,1)}{left}{$v_1$}
\point{2}{(1,2)}{above}{$v_2$}
\point{3}{(1,0)}{below}{$v_3$}
\point{4}{(3,2)}{above left}{$v_4$}
\point{5}{(3,0)}{below right}{$v_5$}
\point{6}{(5,2)}{above left}{$v_6$}
\point{7}{(5,0)}{above left}{$v_7$}
\point{8}{(6,1)}{above right}{$v_8$}
\end{scope}
\wpath{1}{3}{1}
\wpath{2}{3}{2}
\wpath{7}{8}{2}
\wpath{3}{5}{3}
\wpath{4}{5}{4}
\wpath{6}{8}{5}
\wpath{5}{6}{6}
\wpath{6}{7}{7}
\wpath{5}{7}{8}
\wpath{4}{6}{9}
\wpath{2}{5}{10}
\wpath{2}{4}{11}
\wpath{1}{2}{12}
\end{tikzpicture}

31
exam/graphics/17_2.tex Normal file
View File

@ -0,0 +1,31 @@
\newcommand{\point}[4]{
\node [label=#3:#4] (#1) at #2 {};
}
\newcommand{\wpath}[3]{
\draw (#1) -- (#2) node [midway, above, sloped] (Tx#1#2) {{\tiny $#3$}};
}
\begin{tikzpicture}[]
\begin{scope}[every node/.style={fill=black, shape=circle, inner sep=1pt}]
\point{1}{(0,1)}{left}{$v_1$}
\point{2}{(1,2)}{above}{$v_2$}
\point{3}{(1,0)}{below}{$v_3$}
\point{4}{(3,2)}{above left}{$v_4$}
\point{5}{(3,0)}{below right}{$v_5$}
\point{6}{(5,2)}{above left}{$v_6$}
\point{7}{(5,0)}{above left}{$v_7$}
\point{8}{(6,1)}{above right}{$v_8$}
\end{scope}
\wpath{1}{3}{1}
\wpath{2}{3}{2}
\wpath{7}{8}{2}
\wpath{3}{5}{3}
\wpath{4}{5}{4}
\wpath{6}{8}{5}
\wpath{5}{6}{6}
\end{tikzpicture}

10
exam/graphics/3.tex Normal file
View File

@ -0,0 +1,10 @@
\begin{truthtable}
{c|c|e|c|e}
{$p$ & $q$ & $ \neg p$ & $p \wedge q$ & $ \neg (p \wedge q)$}
\T & \T & \F & \T & \F \\
\T & \F & \F & \F & \T \\
\F & \T & \T & \F & \T \\
\F & \F & \T & \F & \T \\
\end{truthtable}

27
exam/graphics/5.tex Normal file
View File

@ -0,0 +1,27 @@
In order for this relation to be an equivalence equation, it has to be reflexive, symmetric and transitive.
\textbf{Reflexive:}
All elements are related to themself
\[ DD, AA, CC, BB \]
\textbf{Symmetric:}
All relations has its symmetric counterpart
\begin{gather*}
CD\text{ and }DC
\end{gather*}
\textbf{Transitive:}
All pair of relations where $xRy$ and $yRz$ has its transitive counterpart
\begin{gather*}
DC\text{ and }CD\text{ with }DD \\
CD\text{ and }DC\text{ with }CC
\end{gather*}
Hence the relation is an equivalence relation

15
exam/graphics/6.tex Normal file
View File

@ -0,0 +1,15 @@
\begin{tikzpicture}
\tikzset{every node/.style={shape=circle,draw,fill=white,inner sep=2pt}}
\node (3) at (0, 0) {$3$};
\node (4) at (1, 0) {$4$};
\node (6) at (0, 1) {$6$};
\node (12) at (0, 2) {$12$};
\node (20) at (1, 1) {$20$};
\draw (3) -- (6);
\draw (4) -- (12);
\draw (4) -- (20);
\draw (6) -- (12);
\end{tikzpicture}

14
exam/graphics/src/14.txt Normal file
View File

@ -0,0 +1,14 @@
# FSA
0
1 r0
2 r1
0 a,0 )d 1
0 c,1 u 1
o b,1 u 0
1 a,1 u 2
1 b,0 )u 0
1 c,0 )u 0
2 a,0 )u 1
2 b,1 (d 0
o c,0 u 2

8
exam/graphics/src/16.txt Normal file
View File

@ -0,0 +1,8 @@
# Graph
matrix
01101
10011
10000
01001
11010

2
exam/graphics/src/3.txt Normal file
View File

@ -0,0 +1,2 @@
# Truthtable
p, q, E not p, p and q, E not (p and q)

4
exam/graphics/src/5.txt Normal file
View File

@ -0,0 +1,4 @@
# Relations
proveEquivalence
AA BB CC CD DD DC

View File

@ -0,0 +1,7 @@
def genDivPosetFrom(s):
return set((s1,s2) for s1 in s for s2 in s if s2 % s1 == 0 and s1 != s2)
s = set([3,4,6,12,20])
poset = genDivPosetFrom(s)
print('\n'.join(str(x) for x in poset))

348
exam/main.tex Normal file
View File

@ -0,0 +1,348 @@
\documentclass[12pt]{article}
\usepackage{ntnu}
\usepackage{ntnu-math}
\usepackage{ntnu-code}
\author{10112}
\title{MA0301 Spring 2021}
\usetikzlibrary{automata, positioning, arrows.meta}
\newcommand{\I}{\Huge\textbf{I}}
\newcommand{\II}{\Huge\textbf{I\!I}}
\newcommand{\III}{\Huge\textbf{I\!I\!I}}
\usepackage{listings}
\usepackage{blkarray}
\renewcommand{\theenumi}{\arabic{enumi}}
\renewcommand{\theenumii}{(\arabic{enumii})}
\renewcommand{\theenumiii}{\alph{enumiii})}
\newcommand{\checkEdge}[3]{
Find next edge with the minimum weight. \\
The edge between #1 and #2 has weight #3. \\
Does adding it connect two separate subgraphs? \\
}
\newcommand{\yes}{\textbf{Yes. Add edge} \\[2ex]}
\newcommand{\no}{\textbf{No. Discard edge} \\[2ex]}
\begin{document}
%%%%%%%% 2
\begin{align*}
\neg (\exists x \forall y (\neg P(x,y) \wedge Q(x,y))) \\
\forall x \exists y \neg(\neg P(x,y) \wedge Q(x,y)) \\
\forall x \exists y (\neg \neg P(x,y) \vee \neg Q(x,y)) \\
\forall x \exists y (P(x,y) \vee \neg Q(x,y)) \\
\end{align*}
%%%%%%%% 3
\break
1.
\input{graphics/3.tex}
2.
By looking at the truthtable, we can see that $\neg p \not\equiv \neg(p \wedge q)$ \\
3.
\begin{gather*}
(p \downarrow q) \downarrow (p \downarrow q) \\
\neg ( \neg (p \wedge q) \wedge \neg (p \wedge q)) \\
\neg ( (\neg p \vee \neg q) \wedge (\neg p \vee \neg q)) \\
\neg (\neg p \vee \neg q) \vee \neg (\neg p \vee \neg q)) \\
\neg \neg p \vee \neg \neg q \vee \neg \neg p \vee \neg \neg q \\
p \vee q \vee p \vee q \\
p \vee q \\
\end{gather*}
\[ (p \downarrow q) \downarrow (p \downarrow q) \equiv p \vee q \]
%%%%%%%% 5
\break
\[ R := \{ (0,0), (1,1), (2,2), (2,3) \} \]
$R$ is not an equivalence relation. \\
For reflexivity, it's missing one relation
\[ (3,3) \]
For symmetry, it's missing one relation
\[ (3,2) \]
For transitivity, it will by now have all missing elements \\
\[ (2,3) \text{ and } (3,2) \rightarrow (2,2) \]
\[ (3,2) \text{ and } (2,3) \rightarrow (3,3) \]
\[ R := \{ (0,0),(1,1),(2,2),(2,3), (3,2), (3,3) \} \]
%%%%%%%% 6
\break
\[ A := \{3, 4, 6, 12, 20 \} \]
\includeDiagram[scale=2, width=5cm]{graphics/6.tex}
\center
By looking at the hasse diagram, we can see that
\[ \text{Minimal elements: } \{ 3, 4 \} \]
\[ \text{Maximal elements: } \{ 12, 20 \} \]
%%%%%%%% 7
\break
Base case:
\begin{align*}
\sum^3_{i=3} 3^i = \frac{3(3^3-9)}{2} \\[2ex]
3^3 = \frac{3(27-9)}{2} \\[2ex]
27 = \frac{3(18)}{2} \\[2ex]
27 = 9 \cdot 3 \\[2ex]
27 = 27 \\[2ex]
\end{align*}
Assume that
\[ \sum^n_{i=3} 3^i = \frac{3(3^n-9)}{2} \qquad \text{for } n > 2 \]
Then
\begin{align*}
\sum^{n+1}_{i=3} 3^i &= 3^3 + 3^4 + \ldots + 3^n + 3^{n+1} \\[2ex]
&= \frac{3(3^n-9)}{2} + 3^{n+1} \\[2ex]
&= \frac{3^{n+1} - 3 \cdot 9 + 2 \cdot 3^{n+1}}{2} \\[2ex]
&= \frac{3 \cdot 3^{n+1} - 3 \cdot 9}{2} \\[2ex]
&= \frac{3(3^{n+1} - 9)}{2} \\[2ex]
\end{align*}
\qed
%%%%%%%% 8
\break
\[
\{ a_n \}_{n>0} =
\begin{cases}
a_1 = 3 \\
a_2 = 6 \\
a_n = a_n + a_{n-1} \quad \text{for } n > 2 \\
\end{cases}
\]
\textbf{Base case:}
For $a_3$, we have that
\begin{align*}
a_3 &= a_2 + a_1 \\
&= 6 + 3 \\
&= 3(3) \\
&\Rightarrow a_3 \bmod 3 = 0
\end{align*}
For $a_4$, we have that
\begin{align*}
a_4 &= a_3 + a_2 \\
&= 9 + 6 \\
&= 3(5) \\
&\Rightarrow a_4 \bmod 3 = 0
\end{align*}
\textbf{Inductive step:}
Assume that for $k_1 \in \N$, $k_2 \in \N$:
\begin{align*}
a_n &= 3(k_1) \\
a_{n-1} &= 3(k_2) \\
\end{align*}
Then
\begin{align*}
a_{n+1} &= a_n + a_{n-1} \\
&= 3(k_1) + 3(k_2) \\
&= 3(k_1 + k_2) \\
&\Rightarrow a_{n+1} \bmod 3 = 0
\end{align*}
\qed
%%%%%%%% 10
\break
\[ f : \Z \rightarrow \Z \]
\[ f(x) = x-7 \]
\textbf{Injective:}
In order for $f(x)$ to be injective, it has to hold that
\[ f(a) = f(b) \Rightarrow a = b \]
\begin{align*}
f(a) &= f(b) \\
a - 7 &= b - 7 \\
a &= b \\
\end{align*}
Hence $f(x)$ is injective. \\
\textbf{Surjective:}
In order for $f(x)$ to be surjective, it has to hold that
\[ \forall x \in \Z \exists y \in \Z [f(x) = y] \]
\begin{align*}
y &= x - 7 \\
x &= y + 7 \\
\end{align*}
$ x = y + 7 $ makes up all the elements in $\Z$
\begin{align*}
f(x) &= x - 7 \\
&= (y + 7) - 7 \\
&= y
\end{align*}
Hence $f(x)$ is surjective \\
\textbf{Conclusion:}
Since $f(x)$ is both injective and surjective, it is by definition bijective
%%%%%%%% 11
\break
There are no $x^6y^6$ in the expansion of $(3x^5 + 2y)^6$ \\
For $x^{10}y^4$, there is
\[ \binom{6}{4}(3x^5)^{6-4}(2y)^4 = 2160 x^{10}y^4 \]
%%%%%%%% 12
\break
The number of permutations of the letters "ALLTALK" is
\[ \frac{7!}{(7-7)!2!3!} = 420 \]
If all of the Ls has to be together, we can think of this block like one letter. \\
That leaves us with 5 letters, where one of them is repeated once. \\
\[ \frac{5!}{(5-5)!2!} = 60 \]
%%%%%%%% 14
\break
\includeDiagram{graphics/14mod.tex}
Assuming the automation is starting at $s_0$, the output for $acabacab$ would be
\begin{gather*}
s_0 \xrightarrow{a,0} s_1 \\
s_1 \xrightarrow{c,0} s_0 \\
s_0 \xrightarrow{a,0} s_1 \\
s_1 \xrightarrow{b,0} s_0 \\
s_0 \xrightarrow{a,0} s_1 \\
s_1 \xrightarrow{c,0} s_0 \\
s_0 \xrightarrow{a,0} s_1 \\
s_1 \xrightarrow{b,0} s_0 \\
\end{gather*}
\[ 00000000 \]
%%%%%%%% 15
\break
$L$ is a language that only contains words which fits the regular expresson $r$, where
\[ r = b^*ab^*ab^* \]
or described with words, \\
\center "$L$ is a language that only has words that contain exactly two of the letter $a$"
%%%%%%%% 16
\break
\[
\begin{blockarray}{cccccc}
& A & B & C & D & E \\
\begin{block}{c[ccccc]}
A & 0 & 1 & 1 & 0 & 1 \\
B & 1 & 0 & 0 & 1 & 1 \\
C & 1 & 0 & 0 & 0 & 0 \\
D & 0 & 1 & 0 & 0 & 1 \\
E & 1 & 1 & 0 & 1 & 0 \\
\end{block}
\end{blockarray}
\]
\includeDiagram{graphics/16.tex}
%%%%%%%% 17
\break
\includeDiagram[scale=1.6]{graphics/17.tex}
Performed Kruskal's algorithm as follows: \\[2ex]
\textbf{Remove all edges} \\
\checkEdge{1}{3}{1}
\yes
\checkEdge{2}{3}{2}
\yes
\checkEdge{7}{8}{2}
\yes
\checkEdge{3}{5}{3}
\yes
\checkEdge{4}{5}{4}
\yes
\checkEdge{6}{8}{5}
\yes
\checkEdge{5}{6}{6}
\yes
By now, the graph is already spanning so there aren't any more disconnected subgraphs to connect, but I'll check the last ones anyway, like for-looping over the set of edges in a computer program would. \\
\checkEdge{6}{7}{7}
\no
\checkEdge{5}{7}{8}
\no
\checkEdge{4}{6}{9}
\no
\checkEdge{2}{5}{10}
\no
\checkEdge{2}{4}{11}
\no
\checkEdge{1}{2}{12}
\no
\break{}
\textbf{Result: }
\includeDiagram[scale=1.6]{graphics/17_2.tex}
\end{document}

80
exam/python/FSA.py Normal file
View File

@ -0,0 +1,80 @@
from sys import argv
from pathlib import Path
import re
from common import replaceContent
placementChart = {
'a': 'above',
'b': 'below',
'l': 'left',
'r': 'right'
}
def generateEdge(inputLine):
s_src, msg, opts, s_dest = inputLine.split(' ')
out_options = []
if '(' in opts or ')' in opts:
out_options.append('bend left' if '(' in opts else 'bend right')
if any(x in opts for x in 'udlr'):
out_options.append(
'above' if 'u' in opts else \
'below' if 'd' in opts else \
'left' if 'l' in opts else \
'right' if 'r' in opts else ''
)
if s_src == 'o':
return f'\draw (s{s_dest}) edge[loop,{",".join(out_options)}] node{{{msg}}} (s{s_dest});'
else:
return f'\draw (s{s_src}) edge[{", ".join(out_options)}] node{{${msg}$}} (s{s_dest});'
def generateNode(inputLine):
s_src, opts = inputLine.split(' ')
out_opts = []
if 's' in opts:
out_opts.append('initial')
if 'f' in opts:
out_opts.append('accepting')
if place := re.search('[udlr]\d+', opts):
out_opts.append(placementChart[place.group()[0]] + ' of=s' + place.group()[1])
return f'\\node[state, {", ".join(out_opts)}] (s{s_src}) {{$s_{s_src}$}};'
def generate_latex(inputLines):
nodes, edges = inputLines.split('\n\n')
output=[]
for node in nodes.split('\n'):
output.append(generateNode(node))
output.append('')
for edge in edges.split('\n'):
output.append(generateEdge(edge))
return '\n'.join(output)
def processFileContent(raw):
content = generate_latex(raw)
return replaceContent(content, 'FSA')
if __name__ == '__main__':
pass
# filename = argv[1]
# with open(filename) as file:
# content = generate_latex(file.read())
# with open(str(Path(__file__).parent.absolute()) + '/tex_templates/FSA.tex') as template:
# with open(argv[2], 'w') as destination_file:
# destination_file.write(template.read().replace('%CONTENT', content))

261
exam/python/Graph.py Normal file
View File

@ -0,0 +1,261 @@
from sys import argv
from pathlib import Path
from math import sin, cos, pi
from common import printc, printerr, replaceContent
class Matrix:
""" Adjacency matrix which supports 0 and 1 """
def __init__(self, matrix):
self.matrix = matrix
def __iter__(self):
return iter(self.matrix)
def __len__(self):
return len(self.matrix)
def __eq__(self, other):
return self.matrix == other
def __str__(self):
return "\n".join(' '.join('\033[32m1\033[0m' if b else '\033[31m0\033[0m' for b in line) for line in self)
def __getitem__(self, key):
return self.matrix[key]
def __setitem__(self, key, item):
self.matrix[key] = item
@classmethod
def fromGraph(cls, graph):
return graph.toMatrix()
@classmethod
def fromString(cls, string):
matrix = []
for line in string.split('\n'):
matrix.append([True if char == '1' else False for char in line])
if len(matrix) != len(matrix[0]):
raise ValueError('Matrix not covering all points')
return cls(matrix)
def toGraph(self):
nodes = [chr(i + 65) for i in range(len(self))]
edges = []
for i, line in enumerate(self):
edges += [(nodes[i],nodes[j]) for j, b in enumerate(line) if b]
return Graph(nodes, edges)
def toLaTeX(self):
return '\\begin{pmatrix}\n' \
+ '\n'.join(' ' + ' & '.join('1' if b else '0' for b in line) + ' \\\\' for line in self.matrix) \
+ '\n\\end{pmatrix}'
class Graph:
def __init__(self, nodes, edges): # Nodes = str, Edges = (str,str)
self.nodes = nodes
self.edges = edges
def __str__(self):
printc('Is undirected: ' + str(self.isUndirected()))
return \
f'Nodes: {" ".join(self.nodes)}\n' \
+ f'Edges: {" ".join(x+y for x,y in (self.undirectedEdgeSet() if self.isUndirected() else self.edges))}'
@classmethod
def fromMatrix(cls, matrix):
return matrix.toGraph()
@classmethod
def fromString(cls, string):
splitData = string.split('\n\n')
if splitData[0] == 'complete':
data1 = 'undirected'
nodes = [chr(i + 65) for i in range(int(splitData[1]))]
data2 = ' '.join(nodes)
data3 = '\n'.join([a+b for a in nodes for b in nodes if a != b])
elif splitData[0] == 'matrix':
return Graph.fromMatrix(Matrix.fromString(splitData[1]))
else:
data1, data2, data3 = splitData
graphType = data1
nodes = data2.split(' ')
edges = [(x,y) for x,y in data3.split('\n')]
if graphType == 'undirected':
edges = [(a,b) for a in nodes for b in nodes if (a,b) in edges or (b,a) in edges]
return cls(nodes, edges)
def toMatrix(self):
rows = []
for node in self.nodes:
rows.append([(node,node2) in self.edges for node2 in self.nodes])
return Matrix(rows)
def isUndirected(self):
matrix = self.toMatrix()
flipv = lambda matrix: list(reversed(matrix))
rot90cc = lambda matrix: list(list(x) for x in zip(*reversed(matrix)))
return matrix == rot90cc(flipv(matrix)) \
and all(matrix[i][i] == 0 for i in range(len(matrix)))
def undirectedEdgeSet(self):
edges = self.edges
if self.isUndirected():
edges = sorted(list(set((x,y) if x < y else (y,x) for x,y in edges)))
return edges
# def latexifyEulerPath(self):
# degrees = [sum(line) for line in self.toMatrix()]
# def latexifyEulerCircuit():
# pass
def getKruskalsSpanningTree(self, weigths): # weights = dict[str, int]
edges = []
connected_subgraphs = [set(v) for v in self.nodes]
if not all(n in ''.join(x+y for x,y in self.edges) for n in self.nodes):
printerr('Not all nodes are connected. There is no spanning tree to be made')
return
def find_subgraph_containing(v):
return [x for x in connected_subgraphs if v in x][0]
def merge_subgraphs_that_contains(u, v):
subgraph_v = find_subgraph_containing(v)
new_connected_subgraphs = [x for x in connected_subgraphs if v not in x]
new_connected_subgraphs = [subgraph_v.union(x) if u in x else x for x in new_connected_subgraphs]
return new_connected_subgraphs
sorted_edges = [ e for e in sorted(self.edges, key=lambda e: weigths[e[0] + e[1]]) ]
for u,v in sorted_edges:
if find_subgraph_containing(u) != find_subgraph_containing(v):
edges += [(u, v)]
connected_subgraphs = merge_subgraphs_that_contains(u, v)
edges += [(y,x) for x,y in edges]
return Graph(self.nodes, edges)
def toLaTeX(self):
zippedNodes = zip(self.nodes, generateNodeCoords(len(self.nodes)))
nodeString = '\n'.join(f'\\node ({name}) at ({x},{y}) {{${name}$}};' for name,(x,y) in zippedNodes)
if self.isUndirected():
edgeString = '\n'.join(f'\\draw ({x}) -- ({y});' for x,y in self.undirectedEdgeSet())
else:
edgeString = '\n'.join(
f'\\draw [-{{Latex[scale=1]}}, bend left=8] ({x}) to ({y});' if y != x and (y,x) in self.edges
else f'\\draw [-{{Latex[scale=1]}}] ({x}) to [{generateLoopInOutAngle(x, self.nodes)},looseness=8] ({y});' if x == y
else f'\\draw [-{{Latex[scale=1]}}] ({x}) to ({y});'
for x,y in self.edges
)
return (nodeString, edgeString)
def toLaTeXWithWeights(self, weights):
zippedNodes = zip(self.nodes, generateNodeCoords(len(self.nodes)))
nodeString = '\n'.join(f'\\node ({name}) at ({x},{y}) {{${name}$}};' for name,(x,y) in zippedNodes)
if self.isUndirected():
edgeString = '\n'.join(f'\\draw ({x}) -- ({y}) node [midway, above, sloped] (Tx{x+y}) {{{weights[x+y]}}};' for x,y in self.undirectedEdgeSet())
return (nodeString, edgeString)
def generateLoopInOutAngle(node, nodes):
baseAngle = 360 / len(nodes)
nodeNum = [i for i,n in enumerate(nodes) if n == node][0]
angle = nodeNum * baseAngle + 90
return f'out={angle + 15},in={angle - 15}'
def generateNodeCoords(n):
vectorLength = n / 2
degreeToTurn = (2 * pi) / n
nodeCoords = [(0, vectorLength)]
for node in range(n):
prev_x = nodeCoords[-1][0]
prev_y = nodeCoords[-1][1]
nodeCoords.append((
round(cos(degreeToTurn) * prev_x - sin(degreeToTurn) * prev_y, 5),
round(sin(degreeToTurn) * prev_x + cos(degreeToTurn) * prev_y, 5)
))
return nodeCoords
def extractWeights(string):
weights = dict()
lines = string.split('\n')
for i in range(4, len(lines)):
edge, weight = lines[i].split(' ')
weights[edge] = int(weight)
weights[edge[1] + edge[0]] = int(weight)
lines[i] = edge
return ('\n'.join(lines), weights)
def processFileContent(raw):
lines = raw.split('\n')
lines.pop(1)
outputType = lines.pop(0)
if lines[0] == 'kruskals':
lines[0] = 'undirected'
string, weights = extractWeights('\n'.join(lines))
graph1 = Graph.fromString(string)
graph2 = graph1.getKruskalsSpanningTree(weights)
return replaceContent(
(graph1.toLaTeXWithWeights(weights), graph2.toLaTeXWithWeights(weights)),
'Kruskals',
replaceF = lambda temp, cont:
temp.replace('%NODES1', cont[0][0])
.replace('%EDGES1', cont[0][1])
.replace('%NODES2', cont[1][0])
.replace('%EDGES2', cont[1][1])
)
graph = Graph.fromString('\n'.join(lines))
print(graph)
print(graph.toMatrix())
if outputType == 'toGraph':
content = graph.toLaTeX()
return replaceContent(
content,
'Graph',
replaceF = lambda temp, cont: temp.replace('%NODES', cont[0]).replace('%EDGES', cont[1])
)
else:
content = graph.toMatrix().toLaTeX()
return replaceContent(content, 'Matrix')
if __name__ == '__main__':
g = Graph.fromString('complete\n\n6')
print(g)
import random
d = dict()
for e in g.edges:
d[str(e)] = random.randint(0, 10)
print(g.getKruskalsSpanningTree(d))

View File

@ -0,0 +1,46 @@
from itertools import combinations
def latexifyCondition(condition):
return condition[0] if condition[1] else f'\\overline{{{condition[0]}}}'
def latexify(listOfConditions): # [(str,bool)]
lines = []
for n in range(1, len(listOfConditions) + 1):
line = []
for x in combinations(listOfConditions, n):
line.append(''.join(latexifyCondition(c) for c in x))
lines.append(line)
linestrs = []
for line in lines:
linestr = ' + '.join(f'N({x})' for x in line)
if len(line) > 1:
linestr = f'\\left[ {linestr} \\right]'
linestrs.append(linestr)
b = False
result = '\\begin{align*}\nN'
for l in linestrs:
result += ' &+ ' if b else ' &- '
result += l + ' \\\\\n'
b = not b
result += '\\end{align*}'
return result
def parseInput(string):
result = []
for x in string.split(' '):
if x.startswith('!'):
result.append((x[1:], False))
else:
result.append((x, True))
return result
def processFileContent(raw):
listOfConditions = parseInput(raw)
content = latexify(listOfConditions)
return content
if __name__ == '__main__':
pass

64
exam/python/Powerset.py Normal file
View File

@ -0,0 +1,64 @@
from itertools import combinations
from common import replaceContent
class Set:
def __init__(self, elements):
self.elements = set(elements)
def __str__(self):
if len(self) == 0: return "\\emptyset"
return f"\\{{ {', '.join(sorted(self.elements))} \\}}"
def __iter__(self):
return list(sorted(self.elements))
def __len__(self):
return len(self.elements)
def __gt__(self, value):
if len(self) != len(value):
return len(self) > len(value)
return self.elements > value.elements
def __ge__(self, value):
return self > value
def __lt__(self, value):
return not self > value
def __le__(self, value):
return self < value
@classmethod
def fromString(cls, string):
return cls(string.split(' '))
def cardinality(self):
return len(self)
def powerset(self):
powerset = []
for i in range(len(self) + 1):
for subset in combinations(self.elements, i):
powerset.append(Set(list(subset)))
return Set(powerset)
def to_vertical_latex(self):
column = []
for e in sorted(self.elements):
column.append(str(e) + ' \\\\')
return '\\{\n' + '\n'.join(column) + '\n\\}'
def processFileContent(raw):
s = Set.fromString(raw)
content = s.powerset().to_vertical_latex()
return replaceContent(content, 'Powerset')
#TODO: make process input func
if __name__ == "__main__":
print(Set(['a', 'b', 'c']).powerset().to_vertical_latex())
# print(a for a in Set(['A', 'B', 'C']).powerset())

26
exam/python/Python.py Normal file
View File

@ -0,0 +1,26 @@
import tempfile
import subprocess
import os
import sys
from common import replaceContent
def makeTmpFile(content):
fd, path = tempfile.mkstemp()
while ('_' in path):
fd, path = tempfile.mkstemp()
with os.fdopen(fd, 'w') as tmp:
tmp.write(content)
return path
def grabOutput(path):
return subprocess.check_output(['python', path]).decode(sys.stdout.encoding)
def processFileContent(content):
path = makeTmpFile(content)
output = grabOutput(path)
return replaceContent(
(path, output),
'Python',
lambda temp, cont: temp.replace('%CODEFILE', cont[0]).replace('%OUTPUT', cont[1])
)

298
exam/python/Relations.py Normal file
View File

@ -0,0 +1,298 @@
from sys import argv
from pathlib import Path
from common import printc, printerr, replaceContent
import Graph
# Increase if hasse diagram becomes too clobbered
def pairToString(pair):
if str(pair[0]).isdigit() or str(pair[1]).isdigit():
return f'({pair[0]},{pair[1]})'
else:
return pair[0] + pair[1]
def stringToPair(string):
if string[0] == '(':
return tuple([string.split(',')[0][1:], string.split(',')[0][:-1]])
else:
return tuple(list(string))
def textLatex(string):
return '\\text{' + string + '}'
def mathModeListLatex(elements):
if len(elements) > 7 or len(elements) and max(len(str(e)) for e in elements) > 10:
return '\\begin{gather*}\n' \
+ ' \\\\\n'.join(elements) + '\n' \
+ '\\end{gather*}'
else:
return f'\\[ {", ".join(elements)} \\]'
class Relation:
def __init__(self, pairs): # pair = (str,str)
self.pairs = set(pairs)
def __str__(self):
return f'\\{{ {", ".join(x + y for x,y in self.pairs)} \}}'
@classmethod
def fromString(cls, string):
relations = (stringToPair(x) for x in string.split(' '))
return cls(relations)
@classmethod
def fromDivisibilityPosetTo(cls, n):
pairs = set()
for dst in range(n):
pairs.add((dst, dst))
for src in range(1, dst):
if dst % src == 0:
pairs.add((src, dst))
return cls(pairs)
def isReflexive(self, verbose=False):
elements = set(list(sum(self.pairs, ())))
result = all((x,x) in self.pairs for x in elements)
if not result:
printc('Not reflexive, missing following pairs:', color='green')
missingPairs = [(x,x) for x in elements if (x,x) not in self.pairs]
print(f'\\[ {", ".join(pairToString(p) for p in missingPairs)} \\]')
if verbose:
return (False, missingPairs)
if verbose:
return (True, [(x,x) for x in elements if (x,x) in self.pairs])
return result
def isSymmetric(self, verbose=False):
result = all((y,x) in self.pairs for x,y in self.pairs)
if not result:
printc('Not symmetric, missing following pairs:', color='green')
missingPairs = [(x,y) for x,y in self.pairs if (y,x) not in self.pairs]
print(f'\\[ {", ".join(pairToString(p) for p in missingPairs)} \\]')
if verbose:
return (False, missingPairs)
if verbose:
return (True, [((x,y), (y,x)) for x,y in self.pairs if (y,x) in self.pairs and x < y])
return result
def isAntiSymmetric(self, verbose=False):
result = not any((y,x) in self.pairs and y != x for x,y in self.pairs)
if not result:
printc('Not antisymmetric, following pairs are symmetric:', color='green')
symmetricPairs = [((x,y), (y,x)) for x,y in self.pairs if (y,x) in self.pairs and y > x]
print(f'\\[ {", ".join(f"""{pairToString(p)}{textLatex(" and ")}{pairToString(q)}""" for p,q in symmetricPairs)} \\]')
if verbose:
return (False, symmetricPairs)
if verbose:
return (True, [])
return result
def isTransitive(self, verbose=False):
result = True
transitivePairs = []
nonTransitivePairs = []
for x,y in self.pairs:
for z,w in self.pairs:
if not (y != z or ((x,w) in self.pairs)):
nonTransitivePairs.append(((x,y), (z,w)))
result = False
elif (y == z and x != y != w and ((x,w) in self.pairs)):
transitivePairs.append(((x,y), (z,w)))
if not result:
printc('Not transitive, following pairs are missing its transitive counterpart:', color='green')
print(f'\\[ {", ".join(f"""{pairToString(p)}{textLatex(" and ")}{pairToString(q)}{textLatex(" without ")}{pairToString((p[0], q[1]))}""" for p,q in nonTransitivePairs)} \\]')
if verbose:
return (False, nonTransitivePairs)
if verbose:
return (True, transitivePairs)
return result
def isEquivalenceRelation(self, verbose=False):
if verbose:
isReflexive, reflexivePairs = self.isReflexive(verbose=True)
isSymmetric, symmetricPairs = self.isSymmetric(verbose=True)
isTransitive, transitivePairs = self.isTransitive(verbose=True)
if not isReflexive:
return 'The relation is not an equivalence relation, because it is not reflexive.'
+ ' The following elements should be related:\n\n'
+ f'\\[ {", ".join(pairToString(p) for p in reflexivePairs)} \\]'
if not isSymmetric:
return 'The relation is not an equivalence relation, because it is not symmetric.'
+ ' It is missing the following symmetric pairs of relations\n\n'
+ f'\\[ {", ".join(f"""{pairToString(p)}{textLatex(" and ")}{pairToString(q)}""" for p,q in symmetricPairs)} \\]'
if not isTransitive:
return 'The relation is not an equivalence relation, because it is not transitive.'
+ ' The following pairs of relations are missing its transitive counterpart\n\n'
+ f'\\[ {", ".join(f"""{pairToString(p)}{textLatex(" and ")}{pairToString(q)}{textLatex(" without ")}{pairToString((p[0], q[1]))}""" for p,q in transitivePairs)} \\]'
rxStr = mathModeListLatex([pairToString(p) for p in reflexivePairs])
smStr = mathModeListLatex([f"""{pairToString(p)}{textLatex(" and ")}{pairToString(q)}""" for p,q in symmetricPairs])
trStr = mathModeListLatex([f"""{pairToString(p)}{textLatex(" and ")}{pairToString(q)}{textLatex(" with ")}{pairToString((p[0], q[1]))}""" for p,q in transitivePairs])
return replaceContent(
(rxStr, smStr, trStr),
'Relations/EquivalenceProof',
lambda temp, cont: temp.replace('%REFLEXIVE', cont[0]).replace('%SYMMETRIC', cont[1]).replace('%TRANSITIVE', cont[2])
)
return self.isReflexive() and self.isSymmetric() and self.isTransitive()
def isPartialOrder(self, verbose=False):
result = self.isReflexive() and self.isAntiSymmetric() and self.isTransitive()
if result:
hasse= self.getHassePairs(checkIfPartialOrder=False)
min_el = set(a for a,b in hasse if a not in list(zip(*hasse))[1])
printc(f"Minimal elements: $\{{ {', '.join(str(e) for e in min_el)} \}}$ \\\\")
max_el = set(v for k,v in hasse if v not in (x for x,_ in hasse))
printc(f"Maximal elements: $\{{ {', '.join(str(e) for e in max_el)} \}}$" )
if verbose:
isReflexive, reflexivePairs = self.isReflexive(verbose=True)
isAntiSymmetric, antiSymmetricPairs = self.isAntiSymmetric(verbose=True)
isTransitive, transitivePairs = self.isTransitive(verbose=True)
if not isReflexive:
return 'The relation is not a partial order, because it is not reflexive.'
+ ' The following elements should be related:\n\n'
+ f'\\[ {", ".join(pairToString(p) for p in reflexivePairs)} \\]'
if not isAntiSymmetric:
return 'The relation is not a partial order, because it is not antisymmetric.'
+ ' The following relations are symmetric\n\n'
+ f'\\[ {", ".join(f"""{pairToString(p)}{textLatex(" and ")}{pairToString(q)}""" for p,q in antiSymmetricPairs)} \\]'
if not isTransitive:
return 'The relation is not a partial order, because it is not transitive.'
+ ' The following pairs of relations are missing its transitive counterpart\n\n'
+ f'\\[ {", ".join(f"""{pairToString(p)}{textLatex(" and ")}{pairToString(q)}{textLatex(" without ")}{pairToString((p[0], q[1]))}""" for p,q in transitivePairs)} \\]'
rxStr = mathModeListLatex([pairToString(p) for p in reflexivePairs])
trStr = mathModeListLatex([f"""{pairToString(p)}{textLatex(" and ")}{pairToString(q)}{textLatex(" with ")}{pairToString((p[0], q[1]))}""" for p,q in transitivePairs])
return replaceContent(
(rxStr, trStr),
'Relations/PosetProof',
lambda temp, cont: temp.replace('%REFLEXIVE', cont[0]).replace('%TRANSITIVE', cont[1])
)
return result
def getHassePairs(self, checkIfPartialOrder=True):
if checkIfPartialOrder and not self.isPartialOrder():
printerr('This is not a partial order')
return
nonReflexivePairs = set((x,y) for x,y in self.pairs if x != y)
hassePairs = set()
for x1, y1 in nonReflexivePairs:
for x2, y2 in nonReflexivePairs:
if y1 == x2:
hassePairs.add((x1, y2))
return nonReflexivePairs - hassePairs
def latexifyHasseDiagram(self):
hasse = self.getHassePairs()
keys = set(item for tup in hasse for item in tup)
y_pos = dict.fromkeys(keys, 0)
i = 0
while len(next_row := [val for key,val in hasse if key in [x for x,y in y_pos.items() if y == i] ]) != 0:
for item in next_row:
y_pos[item] = i + 1
i += 1
inv_ypos = dict()
for key in set(y_pos.values()):
inv_ypos[key] = [x for x,y in y_pos.items() if y == key]
output = []
for y in inv_ypos.keys():
for i, n in enumerate(inv_ypos[y]):
output.append(f'\\node ({n}) at ({i - len(inv_ypos[y])/2}, {y * 0.5 * (len(hasse) ** 0.4)}) {{${n}$}};')
output.append('')
for x,y in hasse:
output.append(f'\\draw ({x}) -- ({y});')
return '\n'.join(output)
def latexifyGraph(self):
if self.isEquivalenceRelation():
graphType = 'undirected'
pairs = [(x,y) for x,y in self.pairs if x != y]
else:
graphType = 'directed'
pairs = self.pairs
nodes = set()
for x,y in pairs:
nodes.add(x)
nodes.add(y)
edges = "\n".join(pairToString(p) for p in pairs)
processingString = f'toGraph\n\n{graphType}\n\n{ " ".join(nodes) }\n\n{edges}'
return Graph.processFileContent(processingString)
def processFileContent(raw):
outputType, inp = raw.split('\n\n')
if inp.startswith('divisibilityPosetTo'):
n = int(inp.split(' ')[1])
relation = Relation.fromDivisibilityPosetTo(n)
else:
relation = Relation.fromString(inp)
if outputType == 'proveEquivalence':
content = relation.isEquivalenceRelation(verbose=True)
return content
elif outputType == 'provePoset':
content = relation.isPartialOrder(verbose=True)
return content
elif outputType == 'hasseDiagram':
content = relation.latexifyHasseDiagram()
return replaceContent(content, 'Relations/Hasse')
elif outputType == 'graph':
content = relation.latexifyGraph()
return content
if __name__ == '__main__':
pass
relations = [(x,y) for x in range(-5, 5) for y in range(-5, 5)]
relations = [(chr(70+x), chr(70+y)) for x,y in relations if x*y >= 0]
for x in range(-5 ,5):
print(str(x) + ' - '+ chr(70 + x))
print(Relation(relations).isTransitive())
# inp = 'AA BB CC DD AB ACj
# relations = [stringToPair(p) for p in inp.split(' ')]
# # print(Relation(relations).isEquivalenceRelation())
# print(Relation(relations).isPartialOrder())
# print(Relation.fromDivisibilityPosetTo(30).isPartialOrder())

111
exam/python/Truthtable.py Normal file
View File

@ -0,0 +1,111 @@
from sys import argv
from pathlib import Path
from common import printerr, replaceContent
try:
from tabulate import tabulate
except:
printerr('Couldn\'t find tabulate. Do you have it installed?')
def parseExpressionList(inputData):
return [e.strip() for e in inputData.split(',')]
class OverloadedBool:
"""Overloads the bool in order to make Implies and Iff functions"""
def __init__(self, val):
self.val = val
def __bool__(self):
val = self.val
while(type(val) is OverloadedBool):
val = val.val
return val
def __str__(self):
return str(self.val)
def __add__(self, bool2):
""" Implies """
return OverloadedBool(not self.val or bool2)
def __sub__(self, bool2):
""" Iff """
return OverloadedBool((not self.val or bool2) and (not bool2 or self.val))
def flattenImpliesIff(exps):
return [exp.replace('implies', '+').replace('iff', '-').replace('E', '') for exp in exps]
def generateTruthTable(exps):
exps = flattenImpliesIff(exps)
boolvars = [e for e in exps if len(e) == 1]
truthtable = []
for x in reversed(range(2 ** len(boolvars))):
for i,digit in enumerate('{0:b}'.format(x).zfill(len(boolvars))):
exec(f'{boolvars[i]} = OverloadedBool({digit == "1"})', globals())
def calculateGridLine():
line = []
for exp in exps:
exec(f'line.append(({exp}))')
return line
truthtable.append(calculateGridLine())
return truthtable
def latexify(exps, truthtable):
latex_expressions = \
[ (
'E' in exp,
exp
.replace('not', '\\neg')
.replace('and', '\\wedge')
.replace('or', '\\vee')
.replace('implies', '\\Rightarrow')
.replace('iff', '\\Leftrightarrow')
.replace('E', ''
.strip())
)
for exp in exps]
return \
"""
\\begin{{truthtable}}
{{{}}}
{{{}}}
{}
\\end{{truthtable}}
""".format(
'|'.join('e' if e else 'c' for e,_ in latex_expressions),
' & '.join(f'${exp}$' for _,exp in latex_expressions),
'\n'.join(' ' + ' & '.join('\\T' if b else '\\F' for b in line) + ' \\\\' for line in truthtable)
)
def printTruthtable(exps, truthtable):
stringTable = [ ['\033[32mT\033[0m ' if b else '\033[31mF\033[0m' for b in line] for line in truthtable]
try:
print(tabulate(stringTable, headers=exps))
except:
pass
def processFileContent(raw):
exps = parseExpressionList(raw)
truthtable = generateTruthTable(exps)
printTruthtable(exps, generateTruthTable(exps))
content = latexify(exps, truthtable)
return replaceContent(content, 'Truthtable')
if __name__ == '__main__':
pass

21
exam/python/common.py Normal file
View File

@ -0,0 +1,21 @@
from pathlib import Path
clear = '\033[0m'
colors = {
'red': '\033[31m',
'green': '\033[32m',
'yellow': '\033[33m',
'blue': '\033[34m',
'purple': '\033[35m',
'cyan': '\033[36m',
}
def printc(text, color='blue'):
print(f'{colors[color]}{text}{clear}')
def printerr(text):
print(f'\033[31;5m[ERROR] {text}{clear}')
def replaceContent(content, template, replaceF = lambda temp, cont: temp.replace("%CONTENT", cont)):
with open(str(Path(__file__).parent.absolute()) + f'/tex_templates/{template}.tex') as template:
return replaceF(template.read(), content)

48
exam/python/run.py Normal file
View File

@ -0,0 +1,48 @@
from sys import argv
from pathlib import Path
import FSA
import Graph
import Truthtable
import Relations
import InclusionExclusion
import Python
from common import printerr
def fetchContentType(content):
new_content = content.split('\n')
contentType = new_content.pop(0)[2:]
return (contentType, '\n'.join(new_content))
def processContent(content):
contentType, content = fetchContentType(content)
if contentType == 'FSA':
result = FSA.processFileContent(content)
elif contentType == 'Graph':
result = Graph.processFileContent('toGraph\n\n' + content)
elif contentType == 'Matrix':
result = Graph.processFileContent('toMatrix\n\n' + content)
elif contentType == 'Relations':
result = Relations.processFileContent(content)
elif contentType == 'Truthtable':
result = Truthtable.processFileContent(content)
elif contentType == 'InclusionExclusion':
result = InclusionExclusion.processFileContent(content)
elif contentType == 'Python':
result = Python.processFileContent(content)
else:
printerr('DIDN\'T RECOGNIZE FILE TYPE')
exit(1)
return result
if __name__ == '__main__':
filename = argv[1]
with open(filename) as file:
content = processContent(file.read())
with open(argv[2], 'w') as destination_file:
destination_file.write(content)

View File

@ -0,0 +1,12 @@
\begin{tikzpicture}
\tikzset{
->, % makes the edges directed
>=Stealth, % makes the arrow heads bold
node distance=5cm, % specifies the minimum distance between two nodes. Change if necessary.
every state/.style={thick, fill=white}, % sets the properties for each state node
initial text=$ $, % sets the text that appears on the start arrow
}
%CONTENT
\end{tikzpicture}

View File

@ -0,0 +1,13 @@
\newcommand{\arrow}[2]{\path [-{Latex[scale=1]}] (#1) edge (#2);}
\begin{tikzpicture}
\begin{scope}[every node/.style={shape=circle, fill=white, draw, inner sep=2pt}]
%NODES
\end{scope}
\begin{scope}[every draw/.style={}]
%EDGES
\end{scope}
\end{tikzpicture}

View File

@ -0,0 +1,37 @@
\begin{mgraphbox}[width=\linewidth]
\begin{figure}[H]
\begin{center}
\begin{tikzpicture}
\begin{scope}[every node/.style={shape=circle, fill=white, draw, inner sep=2pt}]
%NODES1
\end{scope}
\begin{scope}[every draw/.style={}]
%EDGES1
\end{scope}
\end{tikzpicture}
\end{center}
\end{figure}
\end{mgraphbox}
Minimal spanning tree:
\begin{mgraphbox}[width=\linewidth]
\begin{figure}[H]
\begin{center}
\begin{tikzpicture}
\begin{scope}[every node/.style={shape=circle, fill=white, draw, inner sep=2pt}]
%NODES2
\end{scope}
\begin{scope}[every draw/.style={}]
%EDGES2
\end{scope}
\end{tikzpicture}
\end{center}
\end{figure}
\end{mgraphbox}

View File

@ -0,0 +1,5 @@
\begin{figure}[H]
\[
%CONTENT
\]
\end{figure}

View File

View File

@ -0,0 +1,8 @@
\codeFile{%CODEFILE}{python}
Output:
\begin{lstlisting}[breaklines=true, basicstyle=\small]
%OUTPUT
\end{lstlisting}

View File

@ -0,0 +1,22 @@
In order for this relation to be an equivalence equation, it has to be reflexive, symmetric and transitive.
\textbf{Reflexive:}
All elements are related to themself
%REFLEXIVE
\textbf{Symmetric:}
All relations has its symmetric counterpart
%SYMMETRIC
\textbf{Transitive:}
All pair of relations where $xRy$ and $yRz$ has its transitive counterpart
%TRANSITIVE
Hence the relation is an equivalence relation

View File

@ -0,0 +1,6 @@
\begin{tikzpicture}
\tikzset{every node/.style={shape=circle,draw,fill=white,inner sep=2pt}}
%CONTENT
\end{tikzpicture}

View File

@ -0,0 +1,22 @@
In order for this relation to be a partial order, it has to be reflexive, antisymmetric and transitive.
\textbf{Reflexive:}
All elements are related to themself
%REFLEXIVE
\textbf{Antisymmetric:}
No relation have a symmetric counterpart \\
(Listing the ones that don't have a symmetric counterpart would just be listing the whole set) \\
\textbf{Transitive:}
All pair of relations where $xRy$ and $yRz$ has its transitive counterpart
%TRANSITIVE
Hence the relation is a partial order

View File

@ -0,0 +1 @@
%CONTENT