Add exam template

master
Oystein Kristoffer Tveit 2021-05-10 17:41:58 +02:00
parent 94abae2905
commit 629e956af5
13 changed files with 557 additions and 1 deletions

4
.gitignore vendored
View File

@ -8,4 +8,6 @@ _region_.tex
*.log
*.out
*.synctex.gz
.projectile
.projectile
__pycache__

View File

@ -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",
},
}

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",
}
}

9
exam_template/Makefile Normal file
View File

@ -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

View File

@ -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}

View File

@ -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}

View File

@ -0,0 +1 @@
ab ac ad ae bc ed ec

View File

@ -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

33
exam_template/main.tex Normal file
View File

@ -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}

View File

@ -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))

View File

@ -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))

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,6 @@
\begin{tikzpicture}
\tikzset{every node/.style={shape=circle,draw,inner sep=2pt}}
%CONTENT
\end{tikzpicture}