~misterio/BSI-SCC0505

5d049c906ee3f3dd39ecf6f6cd3e824e841a6106 — Gabriel Fontes 9 months ago main
commit inicial
A  => P1/.latexmkrc +1 -0
@@ 1,1 @@
$pdflatex = 'xelatex --shell-escape %O %S'

A  => P1/1b.jff +33 -0
@@ 1,33 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><!--Created with JFLAP 7.1.--><structure>
	<type>pda</type>
	<automaton>
		<!--The list of states.-->
		<state id="0" name="q0">
			<x>140.0</x>
			<y>168.0</y>
			<initial/>
		</state>
		<!--The list of transitions.-->
		<transition>
			<from>0</from>
			<to>0</to>
			<read>1</read>
			<pop>A</pop>
			<push/>
		</transition>
		<transition>
			<from>0</from>
			<to>0</to>
			<read>0</read>
			<pop>A</pop>
			<push>AA</push>
		</transition>
		<transition>
			<from>0</from>
			<to>0</to>
			<read>0</read>
			<pop>Z</pop>
			<push>AA</push>
		</transition>
	</automaton>
</structure>
\ No newline at end of file

A  => P1/2a.jff +80 -0
@@ 1,80 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><!--Created with JFLAP 7.1.--><structure>
	<type>fa</type>
	<automaton>
		<!--The list of states.-->
		<state id="0" name="q0">
			<x>146.0</x>
			<y>160.0</y>
			<initial/>
		</state>
		<state id="1" name="q1">
			<x>223.0</x>
			<y>74.0</y>
		</state>
		<state id="2" name="q2">
			<x>403.0</x>
			<y>220.0</y>
			<final/>
		</state>
		<state id="3" name="q3">
			<x>319.0</x>
			<y>146.0</y>
		</state>
		<!--The list of transitions.-->
		<transition>
			<from>1</from>
			<to>0</to>
			<read>1</read>
		</transition>
		<transition>
			<from>0</from>
			<to>1</to>
			<read>3</read>
		</transition>
		<transition>
			<from>1</from>
			<to>3</to>
			<read>2</read>
		</transition>
		<transition>
			<from>3</from>
			<to>1</to>
			<read>3</read>
		</transition>
		<transition>
			<from>0</from>
			<to>0</to>
			<read>1</read>
		</transition>
		<transition>
			<from>2</from>
			<to>2</to>
			<read>1</read>
		</transition>
		<transition>
			<from>0</from>
			<to>0</to>
			<read>2</read>
		</transition>
		<transition>
			<from>2</from>
			<to>2</to>
			<read>2</read>
		</transition>
		<transition>
			<from>2</from>
			<to>2</to>
			<read>3</read>
		</transition>
		<transition>
			<from>3</from>
			<to>2</to>
			<read>1</read>
		</transition>
		<transition>
			<from>3</from>
			<to>0</to>
			<read>2</read>
		</transition>
	</automaton>
</structure>
\ No newline at end of file

A  => P1/3a.jff +65 -0
@@ 1,65 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><!--Created with JFLAP 7.1.--><structure>
	<type>fa</type>
	<automaton>
		<!--The list of states.-->
		<state id="0" name="q0">
			<x>117.0</x>
			<y>142.0</y>
			<initial/>
			<final/>
		</state>
		<state id="1" name="q1">
			<x>183.0</x>
			<y>85.0</y>
		</state>
		<state id="2" name="q2">
			<x>260.0</x>
			<y>139.0</y>
		</state>
		<state id="3" name="q3">
			<x>188.0</x>
			<y>203.0</y>
		</state>
		<!--The list of transitions.-->
		<transition>
			<from>0</from>
			<to>1</to>
			<read>a</read>
		</transition>
		<transition>
			<from>1</from>
			<to>0</to>
			<read>a</read>
		</transition>
		<transition>
			<from>0</from>
			<to>3</to>
			<read>b</read>
		</transition>
		<transition>
			<from>3</from>
			<to>0</to>
			<read>b</read>
		</transition>
		<transition>
			<from>2</from>
			<to>3</to>
			<read>a</read>
		</transition>
		<transition>
			<from>3</from>
			<to>2</to>
			<read>a</read>
		</transition>
		<transition>
			<from>1</from>
			<to>2</to>
			<read>b</read>
		</transition>
		<transition>
			<from>2</from>
			<to>1</to>
			<read>b</read>
		</transition>
	</automaton>
</structure>
\ No newline at end of file

A  => P1/3c.jff +75 -0
@@ 1,75 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><!--Created with JFLAP 7.1.--><structure>
	<type>pda</type>
	<automaton>
		<!--The list of states.-->
		<state id="0" name="q0">
			<x>258.0</x>
			<y>216.0</y>
			<initial/>
		</state>
		<!--The list of transitions.-->
		<transition>
			<from>0</from>
			<to>0</to>
			<read>a</read>
			<pop>C</pop>
			<push>B</push>
		</transition>
		<transition>
			<from>0</from>
			<to>0</to>
			<read>b</read>
			<pop>C</pop>
			<push>A</push>
		</transition>
		<transition>
			<from>0</from>
			<to>0</to>
			<read>a</read>
			<pop>B</pop>
			<push>C</push>
		</transition>
		<transition>
			<from>0</from>
			<to>0</to>
			<read>b</read>
			<pop>A</pop>
			<push>C</push>
		</transition>
		<transition>
			<from>0</from>
			<to>0</to>
			<read>b</read>
			<pop>B</pop>
			<push>Z</push>
		</transition>
		<transition>
			<from>0</from>
			<to>0</to>
			<read>a</read>
			<pop>A</pop>
			<push>Z</push>
		</transition>
		<transition>
			<from>0</from>
			<to>0</to>
			<read>b</read>
			<pop>Z</pop>
			<push>B</push>
		</transition>
		<transition>
			<from>0</from>
			<to>0</to>
			<read>a</read>
			<pop>Z</pop>
			<push>A</push>
		</transition>
		<transition>
			<from>0</from>
			<to>0</to>
			<read/>
			<pop>Z</pop>
			<push/>
		</transition>
	</automaton>
</structure>
\ No newline at end of file

A  => P1/respostas/respostas.tex +54 -0
@@ 1,54 @@
\documentclass[12pt]{article}
\usepackage{amsmath}
\usepackage{amssymb}
\usepackage{commath}
\usepackage{systeme}
\usepackage{booktabs}
\usepackage{indentfirst}
\usepackage{mathtools}
\usepackage{hyperref}

\usepackage[portuguese]{babel}
\renewcommand{\thesubsection}{\thesection.\alph{subsection}}

\usepackage[small]{titlesec}
\titleformat{\part}[display]
  {\normalfont\large\bfseries}{\partname\ \thepart}{14pt}{\Large}

\title{SCC0505 \\ Introdução à Teoria da Computação \\ Prova 1}
\author{Gabriel Silva Fontes | 10856803}

\begin{document}
\maketitle

\section{}
\subsection{}
\[
    S \rightarrow 0S1|011
\]

\subsection{}
É possível com o autômato de pilha (APN), está no arquivo 1b.jff.

\section{}
\subsection{}
É possível, está no arquivo 2a.jff.
\subsection{}
\[(1+2+3) *+321+(1+2+3) *\]

\section{}
\subsection{}
Está no arquivo 3a.jff.
\subsection{}
\begin{align*}
    S &\rightarrow aA | bC | \lambda \\
    A &\rightarrow aS | bB \\
    B &\rightarrow bA | aC \\
    C &\rightarrow aB | bS
\end{align*}
\subsection{}
Está no arquivo 3c.jff.

É não determinístico. Ao processar o símbolo \(a\) ou \(b\) com um \(Z\) na pilha, além das transições \(a,Z,A\) e \(b,Z,B\), a transição \(\lambda,Z,\lambda\) também é possível.

\end{document}

A  => P2/.envrc +1 -0
@@ 1,1 @@
use nix

A  => P2/.latexmkrc +1 -0
@@ 1,1 @@
$pdflatex = 'xelatex --shell-escape %O %S'

A  => P2/Q1P2.jff +64 -0
@@ 1,64 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><!--Created with JFLAP 7.1.--><structure>
	<type>turing</type>
	<automaton>
		<!--The list of states.-->
		<state id="0" name="q0">
			<x>43.0</x>
			<y>187.0</y>
			<initial/>
		</state>
		<state id="1" name="q1">
			<x>156.0</x>
			<y>190.0</y>
		</state>
		<state id="2" name="q2">
			<x>282.0</x>
			<y>188.0</y>
		</state>
		<state id="3" name="q3">
			<x>403.0</x>
			<y>188.0</y>
		</state>
		<state id="4" name="qa">
			<x>516.0</x>
			<y>189.0</y>
			<final/>
		</state>
		<!--The list of transitions.-->
		<transition>
			<from>2</from>
			<to>2</to>
			<read>1</read>
			<write>1</write>
			<move>R</move>
		</transition>
		<transition>
			<from>2</from>
			<to>3</to>
			<read>2</read>
			<write>2</write>
			<move>R</move>
		</transition>
		<transition>
			<from>3</from>
			<to>4</to>
			<read/>
			<write/>
			<move>R</move>
		</transition>
		<transition>
			<from>0</from>
			<to>1</to>
			<read>0</read>
			<write>0</write>
			<move>R</move>
		</transition>
		<transition>
			<from>1</from>
			<to>2</to>
			<read>1</read>
			<write>1</write>
			<move>R</move>
		</transition>
	</automaton>
</structure>

A  => P2/Q2P2.jff +185 -0
@@ 1,185 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><!--Created with JFLAP 7.1.--><structure>
	<type>turing</type>
	<automaton>
		<!--The list of states.-->
		<state id="0" name="q0">
			<x>106.0</x>
			<y>164.0</y>
			<initial/>
		</state>
		<state id="1" name="q1">
			<x>237.0</x>
			<y>164.0</y>
		</state>
		<state id="2" name="q2">
			<x>369.0</x>
			<y>163.0</y>
		</state>
		<state id="3" name="q3">
			<x>444.0</x>
			<y>87.0</y>
		</state>
		<state id="4" name="q4">
			<x>533.0</x>
			<y>171.0</y>
		</state>
		<state id="5" name="q5">
			<x>443.0</x>
			<y>260.0</y>
		</state>
		<state id="6" name="q6">
			<x>304.0</x>
			<y>265.0</y>
		</state>
		<state id="7" name="q7">
			<x>183.0</x>
			<y>264.0</y>
		</state>
		<state id="8" name="qa">
			<x>69.0</x>
			<y>265.0</y>
			<final/>
		</state>
		<!--The list of transitions.-->
		<transition>
			<from>4</from>
			<to>5</to>
			<read>$</read>
			<write>$</write>
			<move>R</move>
		</transition>
		<transition>
			<from>0</from>
			<to>1</to>
			<read>#</read>
			<write>#</write>
			<move>R</move>
		</transition>
		<transition>
			<from>4</from>
			<to>4</to>
			<read>a</read>
			<write>a</write>
			<move>L</move>
		</transition>
		<transition>
			<from>4</from>
			<to>4</to>
			<read>b</read>
			<write>b</write>
			<move>L</move>
		</transition>
		<transition>
			<from>4</from>
			<to>4</to>
			<read>c</read>
			<write>c</write>
			<move>L</move>
		</transition>
		<transition>
			<from>4</from>
			<to>4</to>
			<read>@</read>
			<write>@</write>
			<move>L</move>
		</transition>
		<transition>
			<from>5</from>
			<to>6</to>
			<read>b</read>
			<write>%</write>
			<move>R</move>
		</transition>
		<transition>
			<from>6</from>
			<to>6</to>
			<read>b</read>
			<write>%</write>
			<move>R</move>
		</transition>
		<transition>
			<from>3</from>
			<to>3</to>
			<read>@</read>
			<write>@</write>
			<move>R</move>
		</transition>
		<transition>
			<from>3</from>
			<to>3</to>
			<read>c</read>
			<write>c</write>
			<move>R</move>
		</transition>
		<transition>
			<from>3</from>
			<to>3</to>
			<read>b</read>
			<write>b</write>
			<move>R</move>
		</transition>
		<transition>
			<from>2</from>
			<to>2</to>
			<read>a</read>
			<write>a</write>
			<move>R</move>
		</transition>
		<transition>
			<from>7</from>
			<to>7</to>
			<read>@</read>
			<write>@</write>
			<move>R</move>
		</transition>
		<transition>
			<from>3</from>
			<to>4</to>
			<read>a</read>
			<write>@</write>
			<move>L</move>
		</transition>
		<transition>
			<from>2</from>
			<to>3</to>
			<read>b</read>
			<write>b</write>
			<move>R</move>
		</transition>
		<transition>
			<from>1</from>
			<to>2</to>
			<read>a</read>
			<write>$</write>
			<move>R</move>
		</transition>
		<transition>
			<from>7</from>
			<to>7</to>
			<read>c</read>
			<write>*</write>
			<move>R</move>
		</transition>
		<transition>
			<from>5</from>
			<to>2</to>
			<read>a</read>
			<write>$</write>
			<move>R</move>
		</transition>
		<transition>
			<from>6</from>
			<to>7</to>
			<read>c</read>
			<write>*</write>
			<move>R</move>
		</transition>
		<transition>
			<from>7</from>
			<to>8</to>
			<read>d</read>
			<write>d</write>
			<move>L</move>
		</transition>
	</automaton>
</structure>

A  => P2/Q3P2.jff +165 -0
@@ 1,165 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><!--Created with JFLAP 7.1.--><structure>
	<type>turing</type>
	<tapes>2</tapes>
	<automaton>
		<!--The list of states.-->
		<state id="0" name="q0">
			<x>110.0</x>
			<y>206.0</y>
			<initial/>
		</state>
		<state id="1" name="q1">
			<x>265.0</x>
			<y>203.0</y>
		</state>
		<state id="2" name="q2">
			<x>416.0</x>
			<y>207.0</y>
		</state>
		<state id="3" name="q3">
			<x>555.0</x>
			<y>209.0</y>
		</state>
		<!--The list of transitions.-->
		<transition>
			<from>2</from>
			<to>3</to>
			<read tape="1">1</read>
			<write tape="1">1</write>
			<move tape="1">L</move>
			<read tape="2">0</read>
			<write tape="2"/>
			<move tape="2">L</move>
		</transition>
		<transition>
			<from>3</from>
			<to>2</to>
			<read tape="1">0</read>
			<write tape="1">0</write>
			<move tape="1">L</move>
			<read tape="2">1</read>
			<write tape="2"/>
			<move tape="2">L</move>
		</transition>
		<transition>
			<from>1</from>
			<to>1</to>
			<read tape="1">0</read>
			<write tape="1">0</write>
			<move tape="1">R</move>
			<read tape="2"/>
			<write tape="2"/>
			<move tape="2">S</move>
		</transition>
		<transition>
			<from>1</from>
			<to>1</to>
			<read tape="1">1</read>
			<write tape="1">1</write>
			<move tape="1">R</move>
			<read tape="2"/>
			<write tape="2"/>
			<move tape="2">S</move>
		</transition>
		<transition>
			<from>0</from>
			<to>0</to>
			<read tape="1">1</read>
			<write tape="1"/>
			<move tape="1">R</move>
			<read tape="2"/>
			<write tape="2">1</write>
			<move tape="2">R</move>
		</transition>
		<transition>
			<from>0</from>
			<to>0</to>
			<read tape="1">0</read>
			<write tape="1"/>
			<move tape="1">R</move>
			<read tape="2"/>
			<write tape="2">0</write>
			<move tape="2">R</move>
		</transition>
		<transition>
			<from>1</from>
			<to>2</to>
			<read tape="1"/>
			<write tape="1"/>
			<move tape="1">L</move>
			<read tape="2"/>
			<write tape="2"/>
			<move tape="2">L</move>
		</transition>
		<transition>
			<from>3</from>
			<to>3</to>
			<read tape="1">1</read>
			<write tape="1">1</write>
			<move tape="1">L</move>
			<read tape="2">1</read>
			<write tape="2"/>
			<move tape="2">L</move>
		</transition>
		<transition>
			<from>3</from>
			<to>3</to>
			<read tape="1">0</read>
			<write tape="1">1</write>
			<move tape="1">L</move>
			<read tape="2">0</read>
			<write tape="2"/>
			<move tape="2">L</move>
		</transition>
		<transition>
			<from>2</from>
			<to>2</to>
			<read tape="1">0</read>
			<write tape="1">1</write>
			<move tape="1">L</move>
			<read tape="2">1</read>
			<write tape="2"/>
			<move tape="2">L</move>
		</transition>
		<transition>
			<from>2</from>
			<to>2</to>
			<read tape="1">0</read>
			<write tape="1">0</write>
			<move tape="1">L</move>
			<read tape="2">0</read>
			<write tape="2"/>
			<move tape="2">L</move>
		</transition>
		<transition>
			<from>2</from>
			<to>2</to>
			<read tape="1">1</read>
			<write tape="1">0</write>
			<move tape="1">L</move>
			<read tape="2">1</read>
			<write tape="2"/>
			<move tape="2">L</move>
		</transition>
		<transition>
			<from>3</from>
			<to>3</to>
			<read tape="1">1</read>
			<write tape="1">0</write>
			<move tape="1">L</move>
			<read tape="2">0</read>
			<write tape="2"/>
			<move tape="2">L</move>
		</transition>
		<transition>
			<from>0</from>
			<to>1</to>
			<read tape="1">B</read>
			<write tape="1">B</write>
			<move tape="1">R</move>
			<read tape="2"/>
			<write tape="2"/>
			<move tape="2">S</move>
		</transition>
	</automaton>
</structure>
\ No newline at end of file

A  => P2/respostas/respostas.tex +57 -0
@@ 1,57 @@
\documentclass[12pt]{article}
\usepackage{amsmath}
\usepackage{amssymb}
\usepackage{commath}
\usepackage{systeme}
\usepackage{booktabs}
\usepackage{indentfirst}
\usepackage{mathtools}
\usepackage{hyperref}
\usepackage{bm}

\usepackage[portuguese]{babel}
\renewcommand{\thesubsection}{\thesection.\alph{subsection}}

\usepackage[small]{titlesec}
\titleformat{\part}[display]
  {\normalfont\large\bfseries}{\partname\ \thepart}{14pt}{\Large}

\title{SCC0505 \\ Introdução à Teoria da Computação \\ Prova 2}
\author{Gabriel Silva Fontes | 10856803}

\begin{document}
\maketitle

\section{}
\subsection{}
\emph{Incluído no arquivo Q1P2.jff}
\subsection{}
\(-\), \(\bm{q_0}\), \(0112\)

\(0\), \(\bm{q_1}\), \(112\)

\(01\), \(\bm{q_2}\), \(12\)

\(011\), \(\bm{q_2}\), \(2\)

\(0112\), \(\bm{q_3}\), \(-\)

\(0112\), \(\bm{q_a}\), \(-\)

\section{}
\subsection{}
\(S \rightarrow aSa | aBa\)

\(B \rightarrow bB | bC\)

\(C \rightarrow cC | c \)
\subsection{}
\emph{Incluído no arquivo Q2P2.jff}

\section{}
\emph{Incluído no arquivo Q3P2.jff}

\section{}
A linguagem \(L_d\) é indecidível, igual o problema da parada, pois esta não é recursivamente enumerável. Isso significa que não existe máquina de Turing capaz de decidir onde parar ao processar essa linguagem. Visto que essas apenas processam linguagens recursivamente enumeráveis, do tipo 0.

\end{document}

A  => P2/shell.nix +10 -0
@@ 1,10 @@
{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
  nativeBuildInputs = with pkgs; [
    # Texlive medium, com titlesec e xstring
    (texlive.combine {
      #inherit (texlive) scheme-medium titlesec xstring minted fvextra pgfplots catchfile upquote framed;
      inherit (texlive) scheme-medium xstring titlesec;
    })
  ];
}

A  => T1/.gitignore +1 -0
@@ 1,1 @@
Relatorio.pdf

A  => T1/ManualT1.txt +18 -0
@@ 1,18 @@
- Como executar?

Incluimos o executável "ExecutavelWindows.exe"

Basta executar como qualquer outro programa de terminal.

Abra seu cmd, use cd pra chegar até o diretório, digite o nome do arquivo, e aperte enter. Basta digitar as entradas (como especificadas na proposta do trabalho), e o output aparecerá no terminal.



- Onde está o código?
Os arquivos de código fonte estão localizados na pasta "Programa", dentro da pasta "src".



- Como compilar? (OPCIONAL)

Caso prefira compilar ao invés de usar o executável pré-compilado, você pode baixar o Rust em https://rust-lang.org. Daí basta entrar na pasta "Programa", e usar o comando "cargo build --release". O executável aparecerá no diretório "target/release/"

A  => T1/Programa/.gitignore +1 -0
@@ 1,1 @@
target

A  => T1/Programa/Cargo.lock +46 -0
@@ 1,46 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "autocfg"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"

[[package]]
name = "fixedbitset"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d"

[[package]]
name = "hashbrown"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04"

[[package]]
name = "indexmap"
version = "1.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3"
dependencies = [
 "autocfg",
 "hashbrown",
]

[[package]]
name = "petgraph"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7"
dependencies = [
 "fixedbitset",
 "indexmap",
]

[[package]]
name = "scc050-t1"
version = "0.1.0"
dependencies = [
 "petgraph",
]

A  => T1/Programa/Cargo.toml +10 -0
@@ 1,10 @@
[package]
name = "scc050-t1"
version = "0.1.0"
authors = ["Gabriel Fontes <eu@misterio.me>"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
petgraph = "0.5"

A  => T1/Programa/src/automaton.rs +145 -0
@@ 1,145 @@
use std::collections::HashMap;

use petgraph::graph::NodeIndex;
use petgraph::visit::EdgeRef;
use petgraph::{Direction, Graph};

use crate::{AutomatonError, Result};

/// Um autômato
pub struct Automaton {
    /// Estados e transições
    ///
    /// Cada nó é uma tupla com um estado (inteiro positivo, nulo no caso do estado inicial), e uma
    /// boolean que indica se aquele estado é um estado final aceitável
    /// Cada aresta é um caractere (ou um nulo, no caso de epsilon), que é um símbolo do alfabeto da
    /// linguagem
    graph: Graph<(Option<u16>, bool), Option<char>>,
    /// Estado(s) iniciais (são armazenados índices p/ nós do grafo)
    initial_state: NodeIndex,
}

impl Automaton {
    /// Cria um novo autômato, dado vetor de estados (u16), símbolos (char),
    /// estados iniciais (u16), estados aceitos (u16) e transições (tripla u16, char, u16)
    pub fn new(
        states: &[u16],
        initial_states: &[u16],
        accepted_states: &[u16],
        transitions: &[(u16, char, u16)],
    ) -> Result<Automaton> {
        // Criar um grafo, com tamanho do número de estados (+ o inicial), e quantidade de arestas igual ao
        // número de transições
        let mut transitions_graph =
            Graph::with_capacity(states.len()+1, transitions.len());

        // Estado inicial real do autômato. Os estados iniciais passados pelo usuário na verdade
        // serão filhos desse, com uma transição epsilon
        let initial_state_index = transitions_graph.add_node((None, false));

        // Vamos guardar os índices dos estados no  grafo num mapa hash temporário,
        // pra facilitar na hora de marcar as transições
        let mut index = HashMap::new();

        // Adicionar todos os estados em nós do grafo
        for state in states {
            // Ver se o estado é um dos aceitos
            let is_accepted = accepted_states.contains(state);
            // Adicionar o estado ao grafo (e se é aceito), e guardar seu índice
            let state_index = transitions_graph.add_node((Some(*state), is_accepted));

            // Adicionar o estado e seu índice no nosso hashmap
            index.insert(state, state_index);

            // Caso o estado seja um dos iniciais
            if initial_states.contains(&state) {
                // Adicionar uma conexão do estado inicial pra esse que acabamos de criar
                // Cujo símbolo é None (epsilon)
                transitions_graph.add_edge(initial_state_index, state_index, None);
            }
        }

        // Adicionar todos as transições em arestas do grafo
        for transition in transitions.iter() {
            // Pegar estado pré, símbolo, e estado pós
            let (q0, x, q1) = transition;

            // Verificar que o estado pré existe
            let q0 = *index.get(q0).ok_or(AutomatonError::InvalidTransition(*q0))?;
            // Verificar que o estado pós existe
            let q1 = *index.get(q1).ok_or(AutomatonError::InvalidTransition(*q1))?;
            // Verificar se o símbolo é epsilon
            let x = match x {
                // Caso seja epsilon, colocar None
                '-' => None,
                // Caso contrário, desreferenciar o símbolo
                x => Some(*x),
            };
            // Adicionar aresta ao grafo
            transitions_graph.add_edge(q0, q1, x);
        }

        // Retornar autômato criado
        Ok(Automaton {
            graph: transitions_graph,
            initial_state: initial_state_index,
        })
    }
    /// Dado uma cadeia, retorna se ela é válida ou não dentro da linguagem
    pub fn verify_chain(&self, chain: &[char]) -> bool {
        // Caso a cadeia contenha '-' (indica epsilon), transformar num slice vazio
        let chain = if chain.contains(&'-') {
            &[]
        } else {
            chain
        };
        // Chamar função recursiva de verificação
        self.verify_chain_inner(&self.initial_state, Vec::new(), chain)
    }
    /// Função recursiva de verificação (função interna)
    fn verify_chain_inner(&self, current: &NodeIndex, visited: Vec<&NodeIndex>, chain: &[char]) -> bool {
        // Caso não tenha mais símbolos na cadeia, e a posição atual é uma das aceitas
        if chain.is_empty() && self.graph[*current].1 {
            // Aceitar cadeia
            return true;
        }

        // Pegar todas as transições saindo do estado atual
        let edges = self
            .graph
            .edges_directed(*current, Direction::Outgoing)
            .filter(|edge| !visited.contains(&&edge.target()));

        // Caso ainda tenha símbolos para seguir
        if !chain.is_empty() {
            // Pegar as arestas que contém o elemento atual da cadeia
            let matching_edges = edges.clone().filter(|edge| *edge.weight() == Some(chain[0]));
            // Para cada aresta que é possível seguir
            for edge in matching_edges {
                // Seguir no vértice, tirando o elemento atual da cadeia
                if self.verify_chain_inner(&edge.target(), visited.clone(), &chain[1..]) {
                    // Caso em algum desses esteja verificado, propagar isso
                    return true;
                }
            }
        }

        // Tentar agora com as transições epsilon
        let epsilon_edges = edges.clone().filter(|edge| *edge.weight() == None);
        // Para cada aresta epsilon
        for edge in epsilon_edges {
            // Chamar ele, com a cadeia intacta (o elemento não é consumido ao entrar num epsilon)
            let mut visited = visited.clone();
            visited.push(current);
            if self.verify_chain_inner(&edge.target(), visited, chain) {
                // Caso em algum desses esteja verificado, propagar isso
                return true;
            }
        }

        // Se chegou aqui, é pq não tem nenhum aresta (nem mesmo epsilon) para seguir
        // E nenhum dos que tentamos seguir caíram num nó aceito
        // Nesse caso, retornar false
        false
    }
}

A  => T1/Programa/src/error.rs +44 -0
@@ 1,44 @@
use std::fmt;

/// Possíveis erros que podem ocorrer
#[derive(Debug)]
pub enum AutomatonError {
    /// Ocorre quando uma transição não é válida
    InvalidTransition(u16),
    /// Ocorre com erros relacionados a leitura de input
    Io(std::io::Error),
    /// Ocorre quando o usuário digita algo que não é número
    NotANumber(std::num::ParseIntError),
}

impl fmt::Display for AutomatonError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            AutomatonError::InvalidTransition(q) => {
                write!(f, "A transição é inválida, pois o estado {} não existe", q)
            }
            AutomatonError::Io(e) => {
                write!(f, "Erro de leitura: {:?}", e)
            }
            AutomatonError::NotANumber(e) => {
                write!(f, "Entrada inválida, digite um número ({:?})", e)
            }
        }
    }
}

impl From<std::io::Error> for AutomatonError {
    fn from(e: std::io::Error) -> Self {
        AutomatonError::Io(e)
    }
}

impl From<std::num::ParseIntError> for AutomatonError {
    fn from(e: std::num::ParseIntError) -> Self {
        AutomatonError::NotANumber(e)
    }
}

impl std::error::Error for AutomatonError {}

pub type Result<T> = std::result::Result<T, AutomatonError>;

A  => T1/Programa/src/lib.rs +5 -0
@@ 1,5 @@
pub mod automaton;
pub use automaton::Automaton;

pub mod error;
pub use error::{AutomatonError, Result};

A  => T1/Programa/src/main.rs +135 -0
@@ 1,135 @@
use scc050_t1::Automaton;
use scc050_t1::Result;

use std::io::{stdin, BufRead};

fn main() -> Result<()> {
    // Inicializar stdin
    let stdin = stdin();
    // Travar stdin e ler input
    let input = Input::from_reader(&mut stdin.lock())?;

    // Criar automato com os dados recebidos
    let automaton = Automaton::new(
        &input.states,
        &input.initial_states,
        &input.accepted_states,
        &input.transitions,
    )?;

    // Para cada cadeia
    for chain in input.chains {
        // Verificar se aceita ou rejeita
        if automaton.verify_chain(&chain) {
            println!("aceita")
        } else {
            println!("rejeita")
        }
    }

    Ok(())
}

/// Representa a entrada do programa
/// Inclui tudo nescessário para iniciar e alimentar o autômato
struct Input {
    states: Vec<u16>,
    initial_states: Vec<u16>,
    accepted_states: Vec<u16>,
    transitions: Vec<(u16, char, u16)>,
    chains: Vec<Vec<char>>,
}
impl Input {
    /// Partindo de um BufRead (por exemplo, entrada padrão), lê e retorna a estrutura Input
    fn from_reader(reader: &mut (dyn BufRead)) -> Result<Input> {
        // Linhas do input
        let mut lines = reader.lines();

        // Quantidade de estados
        let state_qty: u16 = lines
            .next()
            .expect("Digite um número de estados válido")?
            .parse()
            .expect("O número de estados deve ser numérico");

        // Símbolos. Serão ignorados, pq as transições já ditam quais símbolos temos
        let _symbols = lines.next();

        // Qtde de estados iniciais
        let initial_states_qty: u16 = lines
            .next()
            .expect("Digite um número de estados iniciais válido")?
            .parse()
            .expect("O número de estados iniciais deve ser numérico");

        // Estados aceitáveis
        let accepted_states: Vec<u16> = lines
            .next()
            .expect("Digite um número de estados aceitáveis válido")?
            .split_whitespace()
            .skip(1)
            .map(|word| word.parse().expect("O estado deve ser numérico"))
            .collect();

        // Qtde de transições
        let transitions_qty: u16 = lines
            .next()
            .expect("Digite um número de transições válido")?
            .parse()
            .expect("O número de transições deve ser numérico");

        // Transições
        let transitions: Vec<(u16, char, u16)> = lines
            .by_ref()
            // Pegar as próximas linhas igual ao numero de transições
            .take(transitions_qty as usize)
            .map(|line| {
                // Para cada linha
                let line = line?;
                // Cortar nos espaços
                let mut words = line.split_whitespace();
                let source = words
                    .next()
                    .expect("Digite o ponto inicial da transição")
                    .parse()
                    .expect("O ponto inicial da transição deve ser numérico");
                let symbol = words
                    .next()
                    .expect("Digite o símbolo da transição")
                    .chars()
                    .next()
                    .expect("Digite um símbolo válido");
                let target = words
                    .next()
                    .expect("Digite o ponto final da transição")
                    .parse()
                    .expect("O ponto final da transição deve ser numérico");
                Ok((source, symbol, target))
            })
            .collect::<Result<Vec<(u16, char, u16)>>>()?;

        // Qtde de cadeias
        let chains_qty: u16 = lines
            .next()
            .expect("Digite um número de cadeias válido")?
            .parse()
            .expect("O número de cadeias deve ser numérico");

        // Cadeias
        let chains: Vec<Vec<char>> = lines
            .by_ref()
            // Pegar as próximas linhas igual ao numero de cadeias
            .take(chains_qty as usize)
            // Para cada linha, transformar em chars e coletar num vetor
            .map(|line| Ok(line?.chars().collect::<Vec<char>>()))
            .collect::<Result<Vec<Vec<char>>>>()?;

        Ok(Input {
            states: (0..state_qty).collect(),
            accepted_states,
            initial_states: (0..initial_states_qty).collect(),
            transitions,
            chains,
        })
    }
}

A  => T1/Relatorio/.gitignore +288 -0
@@ 1,288 @@
## Core latex/pdflatex auxiliary files:
*.aux
*.lof
*.log
*.lot
*.fls
*.out
*.toc
*.fmt
*.fot
*.cb
*.cb2
.*.lb

## Intermediate documents:
*.dvi
*.xdv
*-converted-to.*
# these rules might exclude image files for figures etc.
# *.ps
# *.eps
# *.pdf

## Generated if empty string is given at "Please type another file name for output:"
.pdf

## Bibliography auxiliary files (bibtex/biblatex/biber):
*.bbl
*.bcf
*.blg
*-blx.aux
*-blx.bib
*.run.xml

## Build tool auxiliary files:
*.fdb_latexmk
*.synctex
*.synctex(busy)
*.synctex.gz
*.synctex.gz(busy)
*.pdfsync

## Build tool directories for auxiliary files
# latexrun
latex.out/

## Auxiliary and intermediate files from other packages:
# algorithms
*.alg
*.loa

# achemso
acs-*.bib

# amsthm
*.thm

# beamer
*.nav
*.pre
*.snm
*.vrb

# changes
*.soc

# comment
*.cut

# cprotect
*.cpt

# elsarticle (documentclass of Elsevier journals)
*.spl

# endnotes
*.ent

# fixme
*.lox

# feynmf/feynmp
*.mf
*.mp
*.t[1-9]
*.t[1-9][0-9]
*.tfm

#(r)(e)ledmac/(r)(e)ledpar
*.end
*.?end
*.[1-9]
*.[1-9][0-9]
*.[1-9][0-9][0-9]
*.[1-9]R
*.[1-9][0-9]R
*.[1-9][0-9][0-9]R
*.eledsec[1-9]
*.eledsec[1-9]R
*.eledsec[1-9][0-9]
*.eledsec[1-9][0-9]R
*.eledsec[1-9][0-9][0-9]
*.eledsec[1-9][0-9][0-9]R

# glossaries
*.acn
*.acr
*.glg
*.glo
*.gls
*.glsdefs
*.lzo
*.lzs

# uncomment this for glossaries-extra (will ignore makeindex's style files!)
# *.ist

# gnuplottex
*-gnuplottex-*

# gregoriotex
*.gaux
*.glog
*.gtex

# htlatex
*.4ct
*.4tc
*.idv
*.lg
*.trc
*.xref

# hyperref
*.brf

# knitr
*-concordance.tex
# TODO Uncomment the next line if you use knitr and want to ignore its generated tikz files
# *.tikz
*-tikzDictionary

# listings
*.lol

# luatexja-ruby
*.ltjruby

# makeidx
*.idx
*.ilg
*.ind

# minitoc
*.maf
*.mlf
*.mlt
*.mtc[0-9]*
*.slf[0-9]*
*.slt[0-9]*
*.stc[0-9]*

# minted
_minted*
*.pyg

# morewrites
*.mw

# newpax
*.newpax

# nomencl
*.nlg
*.nlo
*.nls

# pax
*.pax

# pdfpcnotes
*.pdfpc

# sagetex
*.sagetex.sage
*.sagetex.py
*.sagetex.scmd

# scrwfile
*.wrt

# sympy
*.sout
*.sympy
sympy-plots-for-*.tex/

# pdfcomment
*.upa
*.upb

# pythontex
*.pytxcode
pythontex-files-*/

# tcolorbox
*.listing

# thmtools
*.loe

# TikZ & PGF
*.dpth
*.md5
*.auxlock

# todonotes
*.tdo

# vhistory
*.hst
*.ver

# easy-todo
*.lod

# xcolor
*.xcp

# xmpincl
*.xmpi

# xindy
*.xdy

# xypic precompiled matrices and outlines
*.xyc
*.xyd

# endfloat
*.ttt
*.fff

# Latexian
TSWLatexianTemp*

## Editors:
# WinEdt
*.bak
*.sav

# Texpad
.texpadtmp

# LyX
*.lyx~

# Kile
*.backup

# gummi
.*.swp

# KBibTeX
*~[0-9]*

# TeXnicCenter
*.tps

# auto folder when using emacs and auctex
./auto/*
*.el

# expex forward references with \gathertags
*-tags.tex

# standalone packages
*.sta

# Makeindex log files
*.lpz

# xwatermark package
*.xwm

# REVTeX puts footnotes in the bibliography by default, unless the nofootinbib
# option is specified. Footnotes are the stored in a file with suffix Notes.bib.
# Uncomment the next line to have this generated file ignored.
#*Notes.bib

A  => T1/Relatorio/.latexmkrc +1 -0
@@ 1,1 @@
$pdflatex = 'xelatex --shell-escape %O %S'

A  => T1/Relatorio/relatorio.tex +149 -0
@@ 1,149 @@
\documentclass[12pt]{article}
\usepackage{amsmath}
\usepackage{amssymb}
\usepackage{commath}
\usepackage{systeme}
\usepackage{booktabs}
\usepackage{indentfirst}
\usepackage{mathtools}
\usepackage{minted}
\usepackage{hyperref}


\usepackage[portuguese]{babel}
\DeclarePairedDelimiter{\ceil}{\lceil}{\rceil}

\usepackage[small]{titlesec}
\titleformat{\part}[display]
  {\normalfont\large\bfseries}{\partname\ \thepart}{14pt}{\Large}

\title{SCC0505 \\ Introdução à Teoria da Computação \\ Trabalho 1}
\author{Gabriel Silva Fontes | 10856803
        \and
        Amanda Lindoso Figueiredo | 10784306
        \and
        Rafael Doering Soares | 10408410
        \and
        Felipe Moreira Neves de Souza | 10734651}

\begin{document}
\maketitle
\section{Sobre a solução}
A solução é robusta e funciona com DFAs e NFAs. Suportando um número de estados, símbolos, e transições praticamente infinito (dentro dos limites da memória do computador).

Fomos um passo além, e demos suporte também a cadeias e transições vazias (\(\epsilon\)). Suportando, assim, um NFA-\(\epsilon\).

É possível refatorar o programa para que o autômato aceite qualquer tipo de dado genérico como estado e símbolo. Podendo assim, talvez, ser utilizado para resolver problemas computacionais interessantes.

\section{O código}
\subsection{Linguagem e paradigma}
O código foi construído com a linguagem Rust, principalmente com o paradigma de Programação Orientada a Objetos, e algumas funcionalidades comumente presente em linguagens funcionais (iteradores, closures, etc).

\subsection{Estrutura Automaton}
No arquivo src/automaton.rs, temos a estrutura e métodos do autômato.
A definição da estrutura é:

\begin{minted}{rust}
pub struct Automaton {
    graph: Graph<(Option<u16>, bool), Option<char>>,
    initial_state: NodeIndex,
}
\end{minted}

Ela é formada por um grafo, cujos nós são uma tupla Option\footnote{No Rust, Option representa um tipo nulável. O valor do nó é nulável para dar suporte ao estado inicial, que não tem um valor. Também usamos nas arestas, onde o nulo representa uma aresta \(\epsilon\)} u16\footnote{u16 significa unsigned integer com 16 bits} e boolean. O u16 representa o estado, e a boolean marca se ele é ou não um estado final aceitável. As arestas são compostas por Option char, representando um símbolo na linguagem.

Também temos o índice do grafo onde está localizado o estado inicial.

\subsection{Construtor}
Essa classe possui um construtor (método new), cuja assinatura é:

\begin{minted}{rust}
    pub fn new(
        states: &[u16],
        initial_states: &[u16],
        accepted_states: &[u16],
        transitions: &[(u16, char, u16)],
    ) -> Result<Automaton>
\end{minted}

Esse método toma um vetor de estados, um vetor de estados iniciais, um vetor de estados aceitáveis, e um vetor de transições. Retornando um Automaton construído.

O construtor se encarrega de alocar e inicializar o grafo, adicionar o nó inicial (os nós ``iniciais'' passados pelo usuário serão ligados a este por \(\epsilon\)), adicionar os nós de estados, e relacionar eles com as arestas (transições).

\subsection{Método de verificação}

Nossa classe oferece o componente de simulação como um método. Sua parte pública tem a seguinte assinatura:
\begin{minted}{rust}
pub fn verify_chain(&self, chain: &[char]) -> bool
\end{minted}

Esse método se encarrega de ser o caller inicial de um outro método (recursivo, por isso separado), com o nó (estado) inicial.

A função recursiva interna tem a seguinte assinatura:
\begin{minted}{rust}
fn verify_chain_inner(&self, current &NodeIndex, visited: Vec<&NodeIndex>, chain: &[char]) -> bool
\end{minted}

Tomando um nó inicial, um vetor listando os nós que foram deixados por uma transição \(\epsilon\) (para evitar que uma transição \(\epsilon\) faça um loop infinito) e a cadeia a ser verificada, essa função trabalha de maneira recursiva para buscar qualquer caminho que lhe proporcionaria alcançar um nó aceito ao finalizar a cadeia.

Primeiro, é feita uma verificação se a cadeia chegou ao fim \textbf{e} o estado atual é aceitável, nesse caso retornamos true, sinalizando que a cadeia foi aceita.

Caso isso não aconteça, buscamos as arestas que correspondem ao símbolo atual, chamando a função novamente nos estados que vêm depois de todas essas (e propagando a aceitação, caso ocorra).

Depois desses casos (ou seja, menor preferência), filtramos apenas as arestas \(\epsilon\) saindo do nosso nó atual, e então chamamos a função nos estados que seguem estas transições (novamente, propagando a aceitação, caso ocorra). Nesse caso, passamos para a função o vetor de visitas, adicionando o nó que estamos deixando (para evitar retornar à ele e causar uma recursão infinita e stack overflow, como mencionado).

No fim de tudo isso (ou seja, não temos mais \(\epsilon\) ou símbolo na cadeia para seguir, e não estamos num nó aceito), retornamos false, sinalizando rejeição daquela tentativa.


Pela natureza recursiva, esse método conseguirá verificar de forma exaustiva aquela cadeia. Incluindo possibilidades como passar por um \(\epsilon\), ir e voltar de um nó, etc.

\subsection{Arquivo main}
Por uma questão de organização e encapsulamento, a lógica que se refere à entrada do usuário é contida no arquivo src/main.rs.

Esse código tem acesso à estrutura e métodos de Automaton, e se encarrega de ler, analisar, e chamar os métodos construtores e de verificação da estrutura Automaton.

Aqui temos uma estrutura representando a entrada, e um método para a receber da entrada padrão. Após sua leitura, iteramos pelas cadeias, chamando o método verify\_chain em cada uma, e imprimindo na tela se são aceitas ou não:

\begin{minted}{rust}
fn main() -> Result<()> {
    // Inicializar stdin
    let stdin = stdin();
    // Travar stdin e ler input
    // (estados, estados iniciais, estados aceitos, transições, e cadeias)
    let input = Input::from_reader(&mut stdin.lock())?;

    // Criar automato com os dados recebidos
    let automaton = Automaton::new(
        &input.states,
        &input.initial_states,
        &input.accepted_states,
        &input.transitions,
    )?;

    // Para cada cadeia
    for chain in input.chains {
        // Verificar se aceita ou rejeita
        if automaton.verify_chain(&chain) {
            println!("aceita")
        } else {
            println!("rejeita")
        }
    }

    Ok(())
}
\end{minted}
\section{Qualidade e eficiência}
Como mencionado anteriormente, é trivial alterar o programa para se obter uma implementação com Generics, permitindo o uso de qualquer tipo primitivo ou estrutura de dados no lugar dos estados e dos símbolos, sendo possível reutilizar o programa para  problemas potencialmente interessantes.

Sobre a linguagem, Rust emprega um verificador de memória conhecido como \textit{borrow checker}. Esta funcionalidade garante destrução da memória sem um garbage collector, e ótimas verificações (null pointer, dangling pointers, etc) já na compilação. Temos assim um código relativamente enxuto e intuitivo, com a mesma performance de linguagens com menos verificações de segurança.

A utilização de um grafo com acesso aleatório (em tempo \(O(1)\)) e tamanho pré-determinado permite uma grande eficiência ao inserir, acessar, buscar e filtrar arestas e nós da estrutura.

Na criação do autômato, percorremos uma única vez os estados e as arestas, sendo assim, esta operação tem complexidade (sendo \(e\) o número de estados e \(t\) o número de transições) \(O(e+t)\).

O método de verificação é um pouco mais complicado. Pela natureza recursiva, o pior caso, pode potencialmente visitar cada nó, para cada nó. Sendo assim, assume-se \(O(e^2)\).

A complexidade de espaço é a mínima possível. O armazenamento mais significativo na memória é o grafo, que contém os dados dos nós e arestas, apenas. Logo \(O(e+t)\).

\end{document}

A  => T2/.envrc +1 -0
@@ 1,1 @@
use nix

A  => T2/.gitignore +3 -0
@@ 1,3 @@
*.pdf
*.zip
*.exe

A  => T2/Programa/.gitignore +1 -0
@@ 1,1 @@
target

A  => T2/Programa/Cargo.lock +7 -0
@@ 1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3

[[package]]
name = "scc050-t2"
version = "0.1.0"

A  => T2/Programa/Cargo.toml +9 -0
@@ 1,9 @@
[package]
name = "scc050-t2"
version = "0.1.0"
authors = ["Gabriel Fontes <eu@misterio.me>"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]

A  => T2/Programa/src/lib.rs +2 -0
@@ 1,2 @@
pub mod turingmachine;
pub use turingmachine::{Direction, TuringMachine};

A  => T2/Programa/src/main.rs +171 -0
@@ 1,171 @@
use scc050_t2::{Direction, TuringMachine};
use std::io::{stdin, BufRead};

fn main() {
    // Lockar stdin
    let stdin = stdin();
    // Ler entrada com info da maquina
    let input = Input::from_reader(&mut stdin.lock());
    // Ler fitas
    let tapes = read_tapes(&mut stdin.lock());

    // Criar máquina de turing a partir do input
    let turing_machine = TuringMachine::from(input);

    // Para cada fita
    for tape in tapes {
        // Testar a fita e ver se aceita ou rejeita
        if turing_machine.run_tape(tape) {
            println!("aceita")
        } else {
            println!("rejeita")
        }
    }
}

/// Representa a entrada do programa, baseado nas especificações
/// As especificações são um pouco menos genericas do que a nossa maquina,
/// logo essa estrutura cuida de ler e facilitar na conversão
struct Input {
    number_of_states: u16,
    input_symbols: Vec<char>,
    tape_symbols: Vec<char>,
    accepting_state: u16,
    transitions: Vec<(u16, char, u16, char, Direction)>,
}

impl Input {
    /// Partindo de um BufRead (por exemplo, entrada padrão), lê e retorna a estrutura Input
    fn from_reader(reader: &mut (dyn BufRead)) -> Input {
        let mut lines = reader.lines();

        // Primeira linha
        let number_of_states = lines
            .next()
            .expect("Não foi possível ler entrada")
            .expect("Não foi possível ler entrada")
            .parse()
            .expect("O número de estados deve ser numérico");

        // Segunda linha
        let input_symbols = lines
            .next()
            .expect("Não foi possível ler entrada")
            .expect("Não foi possível ler entrada")
            .split_whitespace()
            .skip(1)
            .map(|word| word.chars().next().expect("Digite um símbolo válido"))
            .collect();

        // Terceira linha
        let tape_symbols = lines
            .next()
            .expect("Não foi possível ler entrada")
            .expect("Não foi possível ler entrada")
            .split_whitespace()
            .skip(1)
            .map(|word| word.chars().next().expect("Digite um símbolo válido"))
            .collect();

        // Quarta linha
        let accepting_state = lines
            .next()
            .expect("Não foi possível ler entrada")
            .expect("Não foi possível ler entrada")
            .parse()
            .expect("O estado de aceitação deve ser numérico");

        // Quinta linha
        let transitions_qty = lines
            .next()
            .expect("Não foi possível ler entrada")
            .expect("Não foi possível ler entrada")
            .parse()
            .expect("O número de transições deve ser numérico");

        // Transições
        let transitions = lines
            .by_ref()
            .take(transitions_qty)
            .map(|line| {
                let line = line.expect("Não foi possível ler entrada");
                let mut words = line.split_whitespace();
                let source_state = words
                    .next()
                    .expect("Não foi possível ler entrada")
                    .parse()
                    .expect("O estado origem da transição deve ser numérico");
                let source_symbol = words
                    .next()
                    .expect("Não foi possível ler entrada")
                    .chars()
                    .next()
                    .expect("O símbolo da transição ser um caractere válido");
                let target_state = words
                    .next()
                    .expect("Não foi possível ler entrada")
                    .parse()
                    .expect("O estado destino da transição deve ser numérico");
                let target_symbol = words
                    .next()
                    .expect("Não foi possível ler entrada")
                    .chars()
                    .next()
                    .expect("O símbolo destino da transição deve ser um caractere válido");
                let direction = words
                    .next()
                    .expect("Não foi possível ler entrada")
                    .chars()
                    .next()
                    .expect("Digite a direção da transição")
                    .into();
                (source_state, source_symbol, target_state, target_symbol, direction)
            }).collect();

        Input {
            number_of_states,
            input_symbols,
            tape_symbols,
            accepting_state,
            transitions,
        }
    }
}

impl From<Input> for TuringMachine {
    /// Converter o input para nossa turing machine
    fn from(input: Input) -> TuringMachine {
        TuringMachine {
            input_symbols: input.input_symbols.into_iter().collect(),
            tape_symbols: input.tape_symbols.into_iter().collect(),
            blank_symbol: 'B',
            states: (0..input.number_of_states).collect(),
            initial_state: 0,
            accepting_states: vec![input.accepting_state].into_iter().collect(),
            transitions: input.transitions.into_iter().map(|transition| {
                let (src_st, src_sy, dst_st, dst_sy, dir) = transition;
                ((src_st, src_sy), (dst_st, dst_sy, dir))
            }).into_iter().collect(),
        }
    }
}

/// Ler fitas do input
fn read_tapes(reader: &mut (dyn BufRead)) -> Vec<Vec<char>> {
    let mut lines = reader.lines();
    // Qtde de fitas
    let tapes_qty = lines
        .next()
        .expect("Não foi possível ler entrada")
        .expect("Não foi possível ler entrada")
        .parse()
        .expect("O número de fitas deve ser numérico");

    // Fitas
    lines.by_ref()
        // Pegar as próximas linhas igual ao numero de fitas
        .take(tapes_qty)
        // Para cada linha, transformar em chars e coletar num vetor
        .map(|line| line.unwrap().chars().collect::<Vec<char>>())
        .collect()
}

A  => T2/Programa/src/turingmachine.rs +122 -0
@@ 1,122 @@
use std::collections::HashMap as Map;
use std::collections::HashSet as Set;

type Symbol = char;
type State = u16;

/// Direções em que podemos nos mover
#[derive(Debug, Copy, Clone)]
pub enum Direction {
    /// Mover p/ esquerda
    Left,
    /// Mover p/ direita
    Right,
    /// Não mover
    None,
}

/// Transformar caractere em direção
impl From<char> for Direction {
    fn from(f: char) -> Direction {
        match f {
            'R'|'r' => Direction::Right,
            'L'|'l' => Direction::Left,
            _ => Direction::None,
        }
    }
}

/// Representa uma máquina de turing
#[derive(Debug)]
pub struct TuringMachine {
    /// Conjunto de símbolos de entrada
    pub input_symbols: Set<Symbol>,
    /// Conjunto de símbolos possíveis, além dos de entrada
    pub tape_symbols: Set<Symbol>,
    /// Símbolo que representa o vazio
    pub blank_symbol: Symbol,
    /// Conjunto de estados possíveis
    pub states: Set<State>,
    /// Estado inicial
    pub initial_state: State,
    /// Conjunto de estados finais aceitáveis
    pub accepting_states: Set<State>,
    /// Representa a função de transição
    /// Implementado como um mapa
    pub transitions: Map<(State, Symbol), (State, Symbol, Direction)>,
}

impl TuringMachine {
    /// Executa a máquina de turing na fita inicial dada
    pub fn run_tape(&self, tape: Vec<Symbol>) -> bool {
        // Tomar posse da fita, como mutável
        let mut tape = tape;

        // Caso seja apenas "-", trocar pelo vetor vazio
        if tape.len() == 1 && tape[0] == '-' {
            tape = Vec::new();
        }

        // Verificar se algum símbolo na fita inicial não está nos permitidos
        if tape.iter().any(|s| !self.input_symbols.contains(s)) {
            return false;
        }

        // Iniciar na ponta esquerda da fita
        let mut index = 0;
        // Iniciar no estado inicial
        let mut current_state = self.initial_state;

        // Caso a fita esteja vazia, criar uma posição com vazio nela
        if tape.is_empty() {
            tape.push(self.blank_symbol);
        }

        loop {
            // Chamar a transição para ver para onde vamos
            let transition = self.transition(current_state, tape[index]);
            // Caso a transição leve a algum lugar
            if let Some(transition) = transition {
                let (next_state, write_symbol, direction) = transition;
                // Escrever símbolo na posição atual da fita
                tape[index] = write_symbol;
                // Guardar o novo estado
                current_state = next_state;
                // Andar com a fita
                match direction {
                    Direction::Left => {
                        // Caso nosso movimento passe do limite esquerdo
                        if index == 0 {
                            tape.insert(0, self.blank_symbol);
                        } else {
                            index -= 1;
                        }
                    }
                    Direction::Right => {
                        // Caso nosso movimento passe do limite direito
                        index += 1;
                        if index == tape.len() {
                            tape.push(self.blank_symbol);
                        }
                    }
                    Direction::None => {}
                }
            }
            // Caso não tenha para onde ir
            else {
                // Halt
                // Verificar se o estado atual é aceito, e retornar
                break self.accepting_states.contains(&current_state);
            }
        }
    }
    /// Dado estado e símbolo atual da fita, retorna o novo estado, símbolo a ser escrito, e
    /// direção que se deve seguir
    fn transition(
        &self,
        state: State,
        symbol: Symbol,
    ) -> Option<(State, Symbol, Direction)> {
        self.transitions.get(&(state, symbol)).copied()
    }
}

A  => T2/Programa/tests/test1.rs +47 -0
@@ 1,47 @@
use scc050_t2::{Direction, TuringMachine};

#[test]
fn test1() {
    // Caso teste 1 passado no enunciado
    let tm = TuringMachine {
        input_symbols: vec!['a', 'b', 'c'].into_iter().collect(),
        tape_symbols: vec!['#', '*', '@', 'B'].into_iter().collect(),
        blank_symbol: 'B',
        states: vec![0, 1, 2, 3, 4, 5].into_iter().collect(),
        initial_state: 0,
        accepting_states: vec![5].into_iter().collect(),
        transitions: vec![
            ((0, 'a'), (1, '#', Direction::Right)),
            ((1, '#'), (1, '#', Direction::Right)),
            ((1, 'a'), (1, 'a', Direction::Right)),
            ((1, '*'), (1, '*', Direction::Right)),
            ((1, 'b'), (2, '*', Direction::Right)),
            ((2, 'b'), (2, 'b', Direction::Right)),
            ((2, '@'), (2, '@', Direction::Right)),
            ((2, 'c'), (3, '@', Direction::Left)),
            ((3, '#'), (3, '#', Direction::Left)),
            ((3, '*'), (3, '*', Direction::Left)),
            ((3, '@'), (3, '@', Direction::Left)),
            ((3, 'b'), (3, 'b', Direction::Left)),
            ((3, 'a'), (1, '#', Direction::Right)),
            ((3, 'B'), (4, 'B', Direction::Right)),
            ((4, '#'), (4, '#', Direction::Right)),
            ((4, '*'), (4, '*', Direction::Right)),
            ((4, '@'), (4, '@', Direction::Right)),
            ((4, 'B'), (5, 'B', Direction::Right)),
        ]
        .into_iter()
        .collect(),
    };

    assert!(!tm.run_tape("abbcca".chars().collect()));
    assert!(tm.run_tape("aabbcc".chars().collect()));
    assert!(!tm.run_tape("bac".chars().collect()));
    assert!(!tm.run_tape("aaabbbcccc".chars().collect()));
    assert!(!tm.run_tape("-".chars().collect()));
    assert!(!tm.run_tape("abcabc".chars().collect()));
    assert!(tm.run_tape("abc".chars().collect()));
    assert!(!tm.run_tape("abcc".chars().collect()));
    assert!(!tm.run_tape("c".chars().collect()));
    assert!(!tm.run_tape("aaabbbbccc".chars().collect()));
}

A  => T2/Relatorio/.gitignore +288 -0
@@ 1,288 @@
## Core latex/pdflatex auxiliary files:
*.aux
*.lof
*.log
*.lot
*.fls
*.out
*.toc
*.fmt
*.fot
*.cb
*.cb2
.*.lb

## Intermediate documents:
*.dvi
*.xdv
*-converted-to.*
# these rules might exclude image files for figures etc.
# *.ps
# *.eps
# *.pdf

## Generated if empty string is given at "Please type another file name for output:"
.pdf

## Bibliography auxiliary files (bibtex/biblatex/biber):
*.bbl
*.bcf
*.blg
*-blx.aux
*-blx.bib
*.run.xml

## Build tool auxiliary files:
*.fdb_latexmk
*.synctex
*.synctex(busy)
*.synctex.gz
*.synctex.gz(busy)
*.pdfsync

## Build tool directories for auxiliary files
# latexrun
latex.out/

## Auxiliary and intermediate files from other packages:
# algorithms
*.alg
*.loa

# achemso
acs-*.bib

# amsthm
*.thm

# beamer
*.nav
*.pre
*.snm
*.vrb

# changes
*.soc

# comment
*.cut

# cprotect
*.cpt

# elsarticle (documentclass of Elsevier journals)
*.spl

# endnotes
*.ent

# fixme
*.lox

# feynmf/feynmp
*.mf
*.mp
*.t[1-9]
*.t[1-9][0-9]
*.tfm

#(r)(e)ledmac/(r)(e)ledpar
*.end
*.?end
*.[1-9]
*.[1-9][0-9]
*.[1-9][0-9][0-9]
*.[1-9]R
*.[1-9][0-9]R
*.[1-9][0-9][0-9]R
*.eledsec[1-9]
*.eledsec[1-9]R
*.eledsec[1-9][0-9]
*.eledsec[1-9][0-9]R
*.eledsec[1-9][0-9][0-9]
*.eledsec[1-9][0-9][0-9]R

# glossaries
*.acn
*.acr
*.glg
*.glo
*.gls
*.glsdefs
*.lzo
*.lzs

# uncomment this for glossaries-extra (will ignore makeindex's style files!)
# *.ist

# gnuplottex
*-gnuplottex-*

# gregoriotex
*.gaux
*.glog
*.gtex

# htlatex
*.4ct
*.4tc
*.idv
*.lg
*.trc
*.xref

# hyperref
*.brf

# knitr
*-concordance.tex
# TODO Uncomment the next line if you use knitr and want to ignore its generated tikz files
# *.tikz
*-tikzDictionary

# listings
*.lol

# luatexja-ruby
*.ltjruby

# makeidx
*.idx
*.ilg
*.ind

# minitoc
*.maf
*.mlf
*.mlt
*.mtc[0-9]*
*.slf[0-9]*
*.slt[0-9]*
*.stc[0-9]*

# minted
_minted*
*.pyg

# morewrites
*.mw

# newpax
*.newpax

# nomencl
*.nlg
*.nlo
*.nls

# pax
*.pax

# pdfpcnotes
*.pdfpc

# sagetex
*.sagetex.sage
*.sagetex.py
*.sagetex.scmd

# scrwfile
*.wrt

# sympy
*.sout
*.sympy
sympy-plots-for-*.tex/

# pdfcomment
*.upa
*.upb

# pythontex
*.pytxcode
pythontex-files-*/

# tcolorbox
*.listing

# thmtools
*.loe

# TikZ & PGF
*.dpth
*.md5
*.auxlock

# todonotes
*.tdo

# vhistory
*.hst
*.ver

# easy-todo
*.lod

# xcolor
*.xcp

# xmpincl
*.xmpi

# xindy
*.xdy

# xypic precompiled matrices and outlines
*.xyc
*.xyd

# endfloat
*.ttt
*.fff

# Latexian
TSWLatexianTemp*

## Editors:
# WinEdt
*.bak
*.sav

# Texpad
.texpadtmp

# LyX
*.lyx~

# Kile
*.backup

# gummi
.*.swp

# KBibTeX
*~[0-9]*

# TeXnicCenter
*.tps

# auto folder when using emacs and auctex
./auto/*
*.el

# expex forward references with \gathertags
*-tags.tex

# standalone packages
*.sta

# Makeindex log files
*.lpz

# xwatermark package
*.xwm

# REVTeX puts footnotes in the bibliography by default, unless the nofootinbib
# option is specified. Footnotes are the stored in a file with suffix Notes.bib.
# Uncomment the next line to have this generated file ignored.
#*Notes.bib

A  => T2/Relatorio/.latexmkrc +1 -0
@@ 1,1 @@
$pdflatex = 'xelatex --shell-escape %O %S'

A  => T2/Relatorio/relatorio.tex +102 -0
@@ 1,102 @@
\documentclass[12pt]{article}
\usepackage{amsmath}
\usepackage{amssymb}
\usepackage{commath}
\usepackage{systeme}
\usepackage{booktabs}
\usepackage{indentfirst}
\usepackage{mathtools}
\usepackage{minted}
\usepackage{hyperref}


\usepackage[portuguese]{babel}
\DeclarePairedDelimiter{\ceil}{\lceil}{\rceil}

\usepackage[small]{titlesec}
\titleformat{\part}[display]
  {\normalfont\large\bfseries}{\partname\ \thepart}{14pt}{\Large}

\title{SCC0505 \\ Introdução à Teoria da Computação \\ Trabalho 2}
\author{Gabriel Silva Fontes | 10856803
        \and
        Amanda Lindoso Figueiredo | 10784306
        \and
        Rafael Doering Soares | 10408410
        \and
        Felipe Moreira Neves de Souza | 10734651}

\begin{document}
\maketitle
\section{Sobre a solução}
A nossa implementação do simulador de máquinas de turing suporta fielmente todas as especificações nescessárias, e um pouco mais.

Mais especificamente: não temos limite algum na quantidade de símbolos, transições, ou estados; podemos ter mais que um estado final, o símbolo branco e o estado inicial também são configuráveis.

Assim como no T1, é possível generalizar e utilizar Generics para permitir o uso de qualquer tipo de dado como símbolo e estado.

\section{Código}
\subsection{Linguagem e paradigmas}
Assim como no anterior, desenvolvemos com Rust. Principalmente com Orientação a Objetos e algumas estratégias funcionais (em especial na leitura de input).


\subsection{Tipos usados}
É bem mais fácil expressar as transições num autômato determinístico: um par estado+símbolo vai sempre resultar em uma, e apenas uma, tripla estado, símbolo, direção. Por isso, utilizamos uma estrutura Map (que é um hashmap) para representá-las.

Os conjuntos são representados por uma estrutura Set (que é um hashset).

Os símbolos e estados podem ser editados para outros tipos de dado (ou generalizado para funcionar com todos), mas na nossa implementação estão definidos, respectivamente, como um caractere e um u16\footnote{Inteiro não-negativo de 16 bits}. Além disso, Direction é simplesmente um enum com 3 possibilidades (esquerda, direita, não mover).

\begin{minted}{rust}
type Symbol = char;
type State = u16;

enum Direction {
    Left,
    Right,
    None,
}
\end{minted}

\subsection{Estrutura TuringMachine}

Considerando os tipos explicados acima, essa é a definição da máquina, propositalmente muito similar a definição matemática:

\begin{minted}{rust}
pub struct TuringMachine {
    input_symbols: Set<Symbol>,
    tape_symbols: Set<Symbol>,
    blank_symbol: Symbol,
    states: Set<State>,
    initial_state: State,
    accepting_states: Set<State>,
    transitions: Map<(State, Symbol), (State, Symbol, Direction)>,
}
\end{minted}

\subsection{Método run\_tape}

O método que executa a fita tem a seguinte assinatura:
\begin{minted}{rust}
pub fn run_tape(&self, tape: Vec<Symbol>) -> bool
\end{minted}

Ou seja, em uma turing machine, recebendo uma fita (vetor de símbolos), retornamos se é ou não aceito (boleano).

A função basicamente executa um loop, que em cada iteração verifica qual a próxima transição partindo do nosso estado e símbolo atual.

Caso a transição esteja definida, escrevemos o símbolo, trocamos o estado, e andamos com a cabeça de leitura, expandindo a fita conforme nescessário.

Caso não esteja definida, significa que a máquina alcançou estado de halt. Nesse momento, vemos se o estado atual está ou não contido no conjunto de estados finais aceitos, e retornamos isso.

\subsection{Main}

Assim como no trabalho anterior, a main cuida de ler inputs, tratar esses dados, e os repassar para a TuringMachine, construindo a estrutura.

Feito isso, chamamos run\_tape para cada fita inserida no input, imprimindo aceita ou rejeita de acordo com o retorno da função.

\subsection{Qualidade e eficiência}
A implementação é muito intuitiva e elegante, graças ao determinismo. Acontece simplesmente uma iteração por ação da máquina.

Muito flexível e fácil de expandir, é trivial adicionar funcionalidades interessantes, como imprimir a fita final após o halt.
\end{document}

A  => T2/manualT2.txt +16 -0
@@ 1,16 @@
- Como executar?

Incluimos o executável "executável_windows.exe"

Basta executar como qualquer outro programa de terminal.

No Windows, abra seu cmd, use cd para chegar até o diretório, digite o nome do arquivo, e aperte enter. Basta digitar as entradas (como especificadas na proposta do trabalho), e o output aparecerá no terminal, encerrando o programa.


- Onde está o código?
Os arquivos de código fonte estão localizados dentro da zip "codigo_fonte.zip", na pasta "src". Como explicado no relatório, a lógica principal da máquina fica em "turingmachine.rs", enquanto o tratamento da entrada fica em "main.rs".


- Como compilar? (OPCIONAL)

Caso prefira compilar ao invés de usar o executável pré-compilado, você pode baixar o Rust em https://rust-lang.org. Daí basta deszipar o codigo_fonte.zip, e usar o comando "cargo build --release". O executável aparecerá no diretório "target/release/"

A  => T2/shell.nix +20 -0
@@ 1,20 @@
{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
  nativeBuildInputs = with pkgs; [
    # Texlive medium, com titlesec e xstring
    #(texlive.combine {
      #inherit (texlive) scheme-medium titlesec xstring minted fvextra pgfplots catchfile upquote framed;
    #})
    # Python e pygments
    #(python39.withPackages (ps: with ps; [pygments]))
    # Rust
    rustc
    cargo
    rust-analyzer
    rustfmt
    clippy
    # Zip
    zip
    unzip
  ];
}