===== Status ===== ^ Nome ^ T1 ^ T2 ^ T3 ^ T4 ^ T5 ^ | Garren | ✓✓ | ✓✓ | ✓✓ | ✓✓ | | | Germano | ✓✓ | ✓✓ | | | | | Guilherme | ✓✓ | ✓✓ | ✓✓ | ✓✓ | ✓✓ | | Ivan | ✓✓ | ✓✓ | ✓✓ | ✓✓ | ✓✓ | | Lucas Oliveira | ✓✓ | ✓✓ | ✓✓ | ✓✓ | ✓✓ | | Lucas Santos | ✓✓ | ✓✓ | | | | | Marco | ✓✓ | ✓✓ | ✓✓ | ✓✓ | ✓✓ | | Rafael | ✓✓ | ✓✓ | ✓✓ | ✓✓ | ✓✓ | | Rodrigo | ✓✓ | | | | | ✓: recebido. ✓✓: avaliado. ===== Trabalho 1 (Heaps k-ários e algoritmo de Dijkstra) ===== Entrega: 7 de dezembro 2022. === Objetivos === * Implementar um heap k-ário. * Implementar o algoritmo de Dijkstra usando o heap implementado. * Determinar o valor de k tal que o algoritmo de Dijkstra com um heap k-ário tem o melhor desempenho. * Comparar a complexidade teórica pessimista com a complexidade real. Em particular verificar que a complexidade real respeita o limite teórico. * Avaliar o escalonamento do algoritmo Dijkstra. === Casos de teste === * Verificação da complexidade do Dijkstra: usar o gerador de casos de testes abaixo. * Verificação do escalonamento: o caso de teste é o rede de trânsito de New York e dos EUA (distance), que pode ser baixado na [[http://www.dis.uniroma1.it/~challenge9/download.shtml|página do DIMACS challenge]]. * Para testar em geral: Gerar um número suficiente (>30) de pares aleatórias de vértices origem e destino e medir o tempo de execução e o número de operações "insert", "deletemin" e "decreasekey". * Exemplo de um {{:inf05016:testplan20211.pdf|plano de teste}}. === Observações === * Como o grafo possui 23,947,347 vértices é necessário usar uma representação esparsa. Uma matriz de adjacência, em particular, não serve. === Convenções === * As implementações do algoritmo de Dijkstra devem aceitar um grafo no formato da DIMACS challenge na entrada padrão (stdin), os índices de dois vértices origem e destino na linha de comando e imprimir o valor do caminho mais curto na saída padrão (stdout). Caso não existo caminho entre os dois vértices imprimir "inf". Exemplo (em UNIX) > ./dijkstra 1 2 < NY.gr 803 === Entregáveis === * Um relatorio explicando a) possíveis detalhes relevantes da implementação, b) o ambiente de teste, c) o resultado dos experimentos, e d) uma análise * O código fonte da implementação * Arquivos csv com todos dados experimentais === Materiais === ==== Gerador de casos de teste ==== /** * \file gen.cpp * \author Marcus Ritt * \date Time-stamp: <2011-08-24 15:17:49 ritt> */ #include #include using namespace std; #include #include #include using namespace boost; // information stored in vertices struct VertexInformation { unsigned component; }; // information stored in edges struct EdgeInformation { unsigned weight; }; const unsigned maxweight = 1000; // graph is an adjacency list represented by vectors typedef adjacency_list Graph; typedef graph_traits::vertex_descriptor Node; typedef graph_traits ::edge_descriptor Edge; int main(int argc, char *argv[]) { assert(argc == 3); unsigned n = atoi(argv[1]); double p = atof(argv[2]); srand48(time(0)); // (1) generate random graph Graph g; for(unsigned i=0; i dist(n); vector pred(n); dijkstra_shortest_paths(g,src,weight_map(get(&EdgeInformation::weight,g)).distance_map(&dist[0]).predecessor_map(&pred[0])); cerr << "Distance between " << src+1 << " and " << dst+1 << " is " << dist[dst] << endl; // (3) print out in DIMACS challenge format cout << "p sp " << num_vertices(g) << " " << num_edges(g) << endl; graph_traits::edge_iterator eb, ee; for ( tie(eb, ee)=edges(g); eb != ee; eb++) cout << "a " << source(*eb,g)+1 << " " << target(*eb, g)+1 << " " << g[*eb].weight << endl; } ==== Leitura (Exemplo) ==== void read_dimacs(std::istream& in, unsigned& n, unsigned& m, MyGraph& a) { std::string line="", dummy; while (line.substr(0,4) != "p sp") getline(in,line); // (1) get nodes and edges std::stringstream linestr; linestr.str(line); linestr >> dummy >> dummy >> n >> m; a.resize(n); unsigned i=0; while (i> ac >> u >> v >> w; // processar arco (u,v) com peso w i++; } } } ===== Trabalho 2 (Fluxo s-t máximo) ===== Entrega: 18 de janeiro de 2023. === Objetivos === * Implementar o algoritmo push-relabel (Goldberg, Tarjan) para encontrar o fluxo máximo s-t. * Verificar a complexidade do algoritmo experimentalmente. === Casos de teste === * Um gerador de casos de teste em formato DIMACS em C é disponível {{http://www.inf.ufrgs.br/~mrpritt/washington.c|aqui}}. * Novo: Uma versão melhor do {{http://www.inf.ufrgs.br/~mrpritt/aa/new_washington_test_dir.tar.gz|gerador}}. * Documentação: To use: cc washington.c -o gengraph gengraph function arg1 arg2 arg3 Command line arguments have the following meanings: function: index of desired graph type arg1, arg2, arg3: meanings depend on graph type (briefly listed below: see code comments for more info) Mesh Graph: 1 rows cols maxcapacity Random Level Graph: 2 rows cols maxcapacity Random 2-Level Graph:3 rows cols maxcapacity Matching Graph: 4 vertices degree Square Mesh: 5 side degree maxcapacity Basic Line: 6 rows cols degree Exponential Line: 7 rows cols degree Double Exponential 8 rows cols degree DinicBadCase: 9 vertices (causes n augmentation phases) GoldBadCase 10 vertices Cheryian 11 dim1 dim2 range (last 2 are bad for goldberg's algorithm) ^ No. ^ Nome ^ Parâmetros ^ Descrição ^ n ^ m ^ | 1 | Mesh | r,c | Grade, 3 viz. 1 direita | rc+2 | 3r(c-1) | | 2 | Random level | r,c | Grade, 3 viz. rand. 1 direita | rc+2 | 3r(c-1) | | 3 | Random 2-level | r,c | Grade, 3 viz. rand. 2 direita | rc+2 | 3r(c-1) | | 4 | Matching | n,d | Bipart. n-n, d viz. rand. | 2n+2 | n(d+2) | | 5 | Square Mesh | d,D | Quadr. mesh dxd, grau D | d*d+2 | (d-1)dD+2d | | 6 | BasicLine | n,m,D | Linha, grau D| nm+2 | nmD+2m | | 7 | ExpLine | n,m,D | Linha, grau D | nm+2 | nmD+2m | | 8 | DExpLine | n,m,D | Linha, grau D | nm+2 | nmD+2m | | 9 | DinicBad | n | Linha | n | 2n-3| | 10 | GoldBad | n | | 3n+3 | 4n+1 | === Convenções === * As implementações do algoritmo devem aceitar uma instância no formato {{http://lpsolve.sourceforge.net/5.5/DIMACS_maxf.htm|DIMACS}} na entrada padrão (stdin) e imprimir o valor do fluxo máximo na saída padrão (stdout). ==== Gerador de casos de teste ==== * O seguinte código calcula o fluxo máximo. Para compilar: Usar C++ e {{http://www.boost.org|Boost}}. /** * \file maxflow.cpp * \author Marcus Ritt * \date Time-stamp: <2015-09-22 21:17:31 ritt> * * Read a maximum flow problem in DIMACS format and output the maximum flow. * */ #include #include using namespace std; #include #include #include using namespace boost; // graph element descriptors typedef adjacency_list_traits::vertex_descriptor DiNode; typedef adjacency_list_traits::edge_descriptor Edge; // a directed graph with reverse edges struct VertexInformation {}; typedef unsigned Capacity; struct EdgeInformation { Capacity edge_capacity; Capacity edge_residual_capacity; Edge reverse_edge; }; typedef adjacency_list DiGraph; int main(int argc, char *argv[]) { // (0) read graph DiGraph g; DiNode s,t; read_dimacs_max_flow(g, get(&EdgeInformation::edge_capacity,g), get(&EdgeInformation::reverse_edge,g), s, t); // (1) determine maximum flow cout << push_relabel_max_flow(g, s, t, get(&EdgeInformation::edge_capacity,g), get(&EdgeInformation::edge_residual_capacity,g), get(&EdgeInformation::reverse_edge,g), get(boost::vertex_index, g)); } ===== Trabalho 3 (Open pit mining) ===== {{https://upload.wikimedia.org/wikipedia/commons/8/83/Udachnaya_pipe.JPG?320}} Entrega: 03/02/2023 ==== Objetivos ==== * Aplicar o algoritmo de fluxo máximo desenvolvido no trabalho 2 para resolver o problema de "open pit mining". * Uma descrição do problema está disponível {{http://www.inf.ufrgs.br/~mrpritt/aa/opm.pdf|aqui}}. * Apresentar as soluções das 6 instâncias de teste abaixo no relatório (como figuras). ==== Exemplo ==== {{http://www.inf.ufrgs.br/~mrpritt/aa/Ie.png}} {{http://www.inf.ufrgs.br/~mrpritt/aa/Se.png}} ==== Casos de teste ==== * Um gerador de casos de teste em C++ é disponível {{http://www.inf.ufrgs.br/~mrpritt/aa/opm.cpp|aqui}}. * Documentação: Gerar uma instância aleatória: ./opm --w 10 --h 10 --ins test.ins; display opm.pbm Visualizar uma solução: ./opm --ins test.ins --sol test.sol --pbm vis.pbm; display vis.pbm Converter PBM para PNG (Linux/ImageMagick): convert vis.pbm vis.png * Casos de teste: {{http://www.inf.ufrgs.br/~mrpritt/aa/I1.ins|I1}}, {{http://www.inf.ufrgs.br/~mrpritt/aa/I2.ins|I2}}, {{http://www.inf.ufrgs.br/~mrpritt/aa/I3.ins|I3}}, {{http://www.inf.ufrgs.br/~mrpritt/aa/I4.ins|I4}}, {{http://www.inf.ufrgs.br/~mrpritt/aa/I5.ins|I5}}, {{http://www.inf.ufrgs.br/~mrpritt/aa/I6.ins|I6}} === Convenções === * As implementações do algoritmo devem aceitar uma instância na entrada padrão (stdin), imprimir a solução na saída padrão (stdout), e imprimir o lucro total na saíde de erro (stderr). * Formato da instância: uma largura w, uma altura h, e lucros pij, com -128 < pij < 128, e pij != 0: w h p11 p12 ... p1w p21 p22 ... p2w ... ph1 ph2 ... phw * Formato da solução: uma largura w, uma altura h, e booleanos sij que indicam se a celula ij é extraída ou não w h s11 s12 ... s1w s21 s22 ... s2w ... sh1 sh2 ... shw ===== Trabalho 4 (Emparelhamentos) ===== Entrega: 10/03/2023 === Objetivos === * Implementar o algoritmo Húngaro que resolve o problema do emparelhamento de maior peso em grafos bi-partidos ponderados. * Documentar a implementação, em particular as estruturas de dados para a representação do problema. * Conduzir testes, que demonstram que a complexidade do algoritmo é O(n(m+n log n)), usando o algoritmo de Johnson para busca de caminhos aumentantes. === Casos de teste === * Gerar grafos bi-partidos completos com pesos aleatórios escolhidos uniformemente no intervalo [0,n^2]. * {{http://www.inf.ufrgs.br/~mrpritt/aa/data.tgz|Casos de teste com soluções}} para a emparelhamento ponderado perfeito mínimo (para comparar com emparelhamento perfeito máximo: multiplicar os valores por -1). O formato corresponde com o que está descrito nas convenções abaixo com a última linha informando o peso total da solução correta. === Convenções === * As implementações do algoritmo devem aceitar um grafo bi-partido não-direcionado completo na entrada padrão (stdin) e imprimir o maior peso de um emparelhamento na saída padrão (stdout). O formato é n p11 p12 p13 ... p1n p21 p22 p23 ... p2n ... pn1 pn2 pn3 ... pnn com pij o peso entre vértice i do primeiro parte do grafo e vértice j do segundo parte. === Entregáveis === * Um relatorio explicando a) possíveis detalhes relevantes da implementação, b) o ambiente de teste, c) o resultado dos experimentos, e d) uma análise * O código fonte da implementação * Arquivos csv com todos dados experimentais === Material auxiliar == * [[http://www.inf.ufrgs.br/~mrpritt/aa/Hungarian.pdf|Como manter um potential]] ===== Trabalho 5 (Teste de primalidade) ===== Entrega: 31/03/2023 === Objetivos === * Implementar o teste de primalidade de Miller & Rabin. * Analisar a complexidade do algoritmo em função de log₂(n) experimentalmente. * Analisar a probabilidade de responder erradamente "sim" experimentalmente. === Casos de teste === * Números inteiros positivos aleatórios. === Convenções === * As implementações do algoritmo devem ler um número decimal com até 1000 dígitos da entrada padrão e imprimir "s" na saída padrão caso o número é considerado primo e "n" caso contrário. === Dicas === * Usa a biblioteca [[http://gmplib.org|GNU MP]] para representar números grandes. Ela tem interfaces para [[http://en.wikipedia.org/wiki/GNU_Multiple_Precision_Arithmetic_Library#Language_bindings|diversas linguagens]] de programação. Um exemplo em C++: #include using namespace std; #include int main(int argc, char *argv[]) { mpz_class a; cin >> a; cout << "O quadrado de " << a << " é " << a*a << endl; }