diff --git a/.gitignore b/.gitignore index f3204bb..dcdca47 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,6 @@ _region_.tex *.log *.out *.synctex.gz -.projectile \ No newline at end of file +.projectile + +__pycache__ \ No newline at end of file diff --git a/exam_template/.vscode/latex.code-snippets b/exam_template/.vscode/latex.code-snippets new file mode 100644 index 0000000..d8b8f92 --- /dev/null +++ b/exam_template/.vscode/latex.code-snippets @@ -0,0 +1,270 @@ +{ + "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", + }, + + "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-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", + }, + + "Diagram": { + "scope": "latex", + "prefix": ["dia"], + "body": "\\includeDiagram[caption={}, width=1\\linewidth]{graphics/$0.tex}", + "description": "Include a diagram", + }, + +} \ No newline at end of file diff --git a/exam_template/.vscode/makefile.code-snippets b/exam_template/.vscode/makefile.code-snippets new file mode 100644 index 0000000..c715b89 --- /dev/null +++ b/exam_template/.vscode/makefile.code-snippets @@ -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", + } +} \ No newline at end of file diff --git a/exam_template/Makefile b/exam_template/Makefile new file mode 100644 index 0000000..24de973 --- /dev/null +++ b/exam_template/Makefile @@ -0,0 +1,9 @@ +.DEFAULT_GOAL := default +.PHONY: default python + +default: python + pdflatex main.tex + +python: + python python/Hasse.py graphics/src/example1.txt graphics/example1.tex + python python/FSA.py graphics/src/example2.txt graphics/example2.tex diff --git a/exam_template/graphics/example1.tex b/exam_template/graphics/example1.tex new file mode 100644 index 0000000..e17d0ea --- /dev/null +++ b/exam_template/graphics/example1.tex @@ -0,0 +1,16 @@ +\begin{tikzpicture} + \tikzset{every node/.style={shape=circle,draw,inner sep=2pt}} + +\node (a) at (-0.5, 0) {$a$}; +\node (e) at (-1.0, 1) {$e$}; +\node (b) at (0.0, 1) {$b$}; +\node (d) at (-1.0, 2) {$d$}; +\node (c) at (0.0, 2) {$c$}; + +\draw (a) -- (e); +\draw (b) -- (c); +\draw (e) -- (d); +\draw (a) -- (b); +\draw (e) -- (c); + +\end{tikzpicture} \ No newline at end of file diff --git a/exam_template/graphics/example2.tex b/exam_template/graphics/example2.tex new file mode 100644 index 0000000..b58a160 --- /dev/null +++ b/exam_template/graphics/example2.tex @@ -0,0 +1,23 @@ +\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, initial] (s0) {$s_0$}; +\node[state, right of=s0] (s1) {$s_1$}; +\node[state, accepting, right of=s1] (s2) {$s_2$}; +\node[state, right of=s2] (s3) {$s_3$}; + +\draw (s0) edge[above] node{$a$} (s1); +\draw (s0) edge[bend left, above] node{$b$} (s3); +\draw (s1) edge[loop,below] node{a} (s1); +\draw (s1) edge[above] node{$b$} (s2); +\draw (s2) edge[loop,below] node{b} (s2); +\draw (s2) edge[above] node{$a$} (s3); +\draw (s3) edge[loop,above] node{a,b} (s3); + +\end{tikzpicture} \ No newline at end of file diff --git a/exam_template/graphics/src/example1.txt b/exam_template/graphics/src/example1.txt new file mode 100644 index 0000000..4e053bb --- /dev/null +++ b/exam_template/graphics/src/example1.txt @@ -0,0 +1 @@ +ab ac ad ae bc ed ec \ No newline at end of file diff --git a/exam_template/graphics/src/example2.txt b/exam_template/graphics/src/example2.txt new file mode 100644 index 0000000..d1c2613 --- /dev/null +++ b/exam_template/graphics/src/example2.txt @@ -0,0 +1,12 @@ +0 s +1 r0 +2 fr1 +3 r2 + +0 a u 1 +0 b u( 3 +o a d 1 +1 b u 2 +o b d 2 +2 a u 3 +o a,b u 3 \ No newline at end of file diff --git a/exam_template/main.tex b/exam_template/main.tex new file mode 100644 index 0000000..933f700 --- /dev/null +++ b/exam_template/main.tex @@ -0,0 +1,33 @@ +\documentclass[12pt]{article} +\usepackage{ntnu} +\usepackage{ntnu-math} + +\author{TODO: STUDENTNUMMER} +\title{Exam v2021} + +\usetikzlibrary{automata, positioning, arrows.meta} + +\newcommand{\I}{Option 1 is correct} +\newcommand{\II}{Option 2 is correct} +\newcommand{\III}{Option 3 is correct} + +\renewcommand{\theenumi}{\arabic{enumi}} +\renewcommand{\theenumii}{(\arabic{enumii})} +\renewcommand{\theenumiii}{\alph{enumiii})} + +\begin{document} + + \ntnuTitle{} + \break{} + + \tableofcontents + + \begin{excs} + \exc{} + \begin{subexcs} + \subexc{} + + \end{subexcs} + \end{excs} + +\end{document} diff --git a/exam_template/python/FSA.py b/exam_template/python/FSA.py new file mode 100644 index 0000000..462d13a --- /dev/null +++ b/exam_template/python/FSA.py @@ -0,0 +1,74 @@ +from sys import argv +from pathlib import Path +import re + +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) + + +if __name__ == '__main__': + 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)) \ No newline at end of file diff --git a/exam_template/python/Hasse.py b/exam_template/python/Hasse.py new file mode 100644 index 0000000..97662fe --- /dev/null +++ b/exam_template/python/Hasse.py @@ -0,0 +1,82 @@ +from sys import argv +from pathlib import Path + +# Increase if the diagram becomes too clobbered +HEIGHT_SEPARATOR = 1 + +def printred(text): + print(f'\033[31m{text}\033[0m') + +# For manual usage via stdin +def getRels(relations=None): + if relations == None: + relations = input("Write the relations in the following format: ab ac ad bc cd ...\n") + relations = (tuple(list(x)) for x in relations.split(' ')) + return set(relations) + +# Generate divisibility graph by range +def divisibility_graph(n): + E = set() + for dst in range(n): + for src in range( 1, dst ): + if dst % src == 0: + E.add( ( src, dst ) ) + return E + +def hasse_diagram(E): + E2 = set() + for e0 in E: + for e1 in E: + if e0[1] == e1[0]: + E2.add( ( e0[0], e1[1] ) ) + return E - E2 + +def latex_hasse(hasse): + min_el = set(a for a,b in hasse if a not in list(zip(*hasse))[1]) + 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 * HEIGHT_SEPARATOR}) {{${n}$}};') + + output.append('') + + for x,y in hasse: + output.append(f'\\draw ({x}) -- ({y});') + + + printred(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)) + printred(f"Maximal elements: $\{{ {', '.join(str(e) for e in max_el)} \}}$" ) + + return '\n'.join(output) + + +if __name__ == '__main__': + filename = argv[1] + + with open(filename) as file: + rels = getRels(file.read()) + + # rels = getRels() + # rels = divisibility_graph(30) + + content = latex_hasse(hasse_diagram(rels)) + + with open(str(Path(__file__).parent.absolute()) + '/tex_templates/Hasse.tex') as template: + with open(argv[2], 'w') as destination_file: + destination_file.write(template.read().replace('%CONTENT', content)) diff --git a/exam_template/python/tex_templates/FSA.tex b/exam_template/python/tex_templates/FSA.tex new file mode 100644 index 0000000..23b60ac --- /dev/null +++ b/exam_template/python/tex_templates/FSA.tex @@ -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} \ No newline at end of file diff --git a/exam_template/python/tex_templates/Hasse.tex b/exam_template/python/tex_templates/Hasse.tex new file mode 100644 index 0000000..6c3c6e0 --- /dev/null +++ b/exam_template/python/tex_templates/Hasse.tex @@ -0,0 +1,6 @@ +\begin{tikzpicture} + \tikzset{every node/.style={shape=circle,draw,inner sep=2pt}} + +%CONTENT + +\end{tikzpicture} \ No newline at end of file