GRAFO - graph editor

Ulisses Cordeiro Pereira
08/02/2010


  1. Introdução
  2. Conceitos
  3. Interface
  4. Plugins
  5. Passo a Passo
  6. Considerações finais
  7. Referências Bibliograficas
  8. Apêndices


Agradecimentos

Primeiramente gostaria de agradecer aos meus pais pela formação que eles me deram. O que proporcionou, apesar das dificuldades, concluir a universidade. Gostaria de agradecer também a minha namorada Gizelle Marques pelo incentivo, motivação e carinho sempre nos momentos certos. Agradeço também ao Oliver Matias van Kaick que mesmo fazendo doutorado no Canada foi prestativo em responder dúvidas e em dar dicas para que eu pudesse iniciar o trabalho com o GRAFO. E por final agradeço ao professor André Luiz Pires Guedes por ter aceitado realizar a minha orientação mesmo não tendo realizado orientação do meu trabalho de graduação I.

1. Introdução

Esse documento tem a intenção de ser um tutorial para se trabalhar com o GRAFO - graph editor. O GRAFO é uma ferramenta de ensino e de testes para trabalhos com grafos. Ele proporciona a construção, edição, manipulação de grafos e testes de algoritmos. Através da sua interface de plugins pode-se facilmente construir um novo algoritmo e testa-lo. O usuário não precisa se preocupar com a interface gráfica, esta é fornecida pelo GRAFO. Com isso ganha-se em tempo e produtividade. Também neste trabalho foi introduzido a possibilidade de construção de algoritmos passo a passo. Esta funcionalidade fornece ao usuário a possibilidade de interagir e depurar os algoritmos por ele construídos.

1.1. Histórico

O GRAFO surgiu em 2003 com uma idéia de Murilo Vicente Goncalves da Silva de construir um programa que facilitasse os testes de algoritmos. A primeira versão do programa possuía uma interface OpenGL e alguns poucos algoritmos nativos.

Algum tempo depois a idéia foi encampada por Oliver Matias van Kaick. Nesta época o Murilo Vicente e o Oliver Matias eram do PET (Programa de Educação Tutorial) do curso de Ciência da computação da UFPR (Universidade Federal do Paraná). A dedicação dos dois somadas a tutoria e experiência do professor André Luiz Pires Guedes permiti-os a construção de toda base que existe atualmente: Interface GTK e OpenGL, comunicação com o GraphViz, utilização de plugins, diferentes layouts para desenho de grafos, rótulos e pesos em vértices e arestas, entre outros.

Em 2008, motivado por esse trabalho e junto com o professor André Guedes decidimos colocar o GRAFO de novo em ação realizando algumas manutenções e implementando as estruturas que possibilitassem a execução de algoritmos Passo a Passo. Entretanto as primeiras investigações sobre o GRAFO abriram outras possibilidades até então não exploradas que se refletem na parte de documentação que também está sendo coberta por este trabalho.

1.2. Organização deste trabalho

O que veremos nos próximos capítulos dará ao leitor uma noção de teoria de grafos, um detalhamento da interface e funcionalidades e um HowTo - Como Fazer para construir plugins e implementar algoritmos passo a passo. Além disso esta documentação serve como ponto de referência para futuras manutenção e ou implementações nas funcionalidades do GRAFO.

Este trabalho está organizado em 7 capítulos:

2. Conceitos

Neste capítulo será dada uma breve introdução sobre teoria dos grafos. Essa introdução tem por objetivo contextualizar o leitor para trabalhar com a nomenclatura utilizada no GRAFO.

Tanto em matemática quanto em ciência da computação, a teoria dos grafos estuda a estrutura matemática grafo que são utilizados para modelar a relação entre objetos de uma certa coleção. Neste contexto um grafo é uma coleção de vértices (nodos) e arestas conectando um par de vértices. WIKIPEDIA (2008).

2.1. Grafo

Segundo GAGNON (2001) e SZWARCFITER (1984) um grafo G é um par ordenado G = (V, E) que está sujeito as seguintes condições:

2.2. Representação gráfica de um grafo

A figura 2.1 traz a representação gráfica do grafo G acima, onde, G = ({v0, v1, v2, v3, v4, v5}, {(v0, v3), (v0, v2), (v0, v3), (v1, v2), (v2, v3), (v3, v4)}).

Os seus vértices correspondem a pontos distintos do plano em posição aleatória e suas arestas correspondem a retas ou curvas que unem estes pontos. SZWARCFITER (1984).

(figura 2.1)

2.3. Incidência, grau e adjacência

Uma aresta incide aos dois vértices que conecta. Um vértice é incidente a uma aresta a ele conectada. O grau de um vértice é dado pelo número de arestas incidentes a ele. SZWARCFITER (1984). Na figura 2.1 temos como grau dos vértices o seguinte: v0 = 2, v1 = 1, v2 = 3, v3 = 3, v4 = 1, v5 = 0.

Os vértices adjacentes são vértices unidos por uma aresta, na figura 2.1 os pares de vértices não ordenados (v0, v2), (v0, v3), (v1, v2), (v2, v3) e (v3, v4) são adjacentes. Duas arestas são adjacentes quando compartilham um mesmo vértice. No exemplo os pares de arestas não ordenadas (e0, e1), (e0, e2), (e0, e3), (e1, e3), (e1, e4), (e2, e3) e (e3, e4) são adjacentes.

2.4. Peso de vértices e arestas

Peso é um valor associado a vértices e arestas de um grafo. Por exemplo um custo, uma distância, uma capacidade ou algo que mensure ir de um vértice a outro utilizando uma determinada aresta ou passando por um determinado vértice. SZWARCFITER (1984).

2.5. Caminho, trajeto, ciclo

É denominado caminho em um grafo uma seqüencia de vértices onde para cada vértice existe uma aresta que o conecta ao vértice seguinte. Um caminho de K vértices possui um caminho de comprimento K-1. Se os vértices do caminho não se repetirem a seqüencia recebe o nome de caminho simples. Se as arestas forem únicas a seqüencia recebe o nome de trajeto. Um ciclo é um caminho que começa em um vértice e retorna ao mesmo vértice. SZWARCFITER (1984).

2.6. Tipos de Grafos

Neste tópico serão exemplificado alguns tipos de grafos citados na interface do GRAFO. São eles: Grafo completo, Grafo bipartite, Grafo regular, Grafo estrela.

2.6.1. Grafo completo

Em um grafo completo todo par de vértice é ligado por uma aresta, isto significa que o grafo possui o máximo de arestas possíveis. GAGNON (2001).

Um grafo com n vértices é nomeado Kn. K1 um grafo com um único vértice e chamado trivial. K2 é um grafo com 2 vértices e uma aresta. K3 é um grafo com 3 vértices e 3 arestas e assim sucessivamente. O número de arestas de um grafo completo é dado por n(n-1)/2.

A figura 2.2 traz o exemplo de um K8 que é um grafo com 8 vértices e 28 arestas.

2.6.2. Grafo bipartite

Em um grafo bipartite os vértices são divididos em dois grupos. Sendo que cada vértice do primeiro grupo é adjacente a somente vértices do segundo grupo e vice-versa. De uma maneira mais formal em um grafo bipartite não existe ciclo de comprimento ímpar. SZWARCFITER (1984).

A figura 2.3 traz um exemplo de um grafo bipartite com 5 vértices no primeiro grupo e 3 vértices no segundo.

2.6.3. Grafo regular

É denominado um grafo regular um grafo onde todos os vértice tem o mesmo grau. Como no exemplo da figura 2.4 que traz um grafo regular com 10 vértices e onde todos os vértices possuem grau 2. GAGNON (2001).

2.6.4. Grafo estrela

Um grafo estrela é um grafo onde existe um vértice central que é adjacente a todos os outros vértices do grafo. Como na figura 2.5.

(figura 2.2) (figura 2.3)
(figura 2.4) (figura 2.5)

2.7. Representação computacional de um grafo

Neste tópico será abordado uma das maneiras de se representar um grafo em um computador. Esta não é a única maneira de representação de um grafo, porem, é a maneira utilizada internamente pelo GRAFO. Por GAGNON (2001) e SZWARCFITER (1984).

2.7.1. Matriz de Adjacência

Dado o grafo G = (V, E) de n vértices v0, v1, v2..vn a matriz de adjacências M = (mjk) é uma matriz n x n sujeito as seguintes condições:

  1. mjk = 1 se o par de vértices (vj, vk) pertence a E.

  2. mjk = 0 se não pertence.

    Como exemplo a tabela 2.1 que representa a matriz de adjacência do grafo da figura 2.1.

-- v0 v1 v2 v3 v4 v5
v0 0 0 1 1 0 0
v1 0 0 1 0 0 0
v2 1 1 0 1 0 0
v3 1 0 1 0 1 0
v4 0 0 0 1 0 0
v5 0 0 0 0 0 0

(tabela 2.1)

3. Interface

Neste capitulo será detalhado a interface que o GRAFO provem ao seu usuário, como menus, botões, opções, configurações e tudo que possa sofrer a interação do usuário. A expansão desta interface, com a criação de novos plugins, será abordada nos capítulos 4 e 5.

A interface do grafo, figura 3.1, possui quatro divisões básicas. São elas:

  1. Menus

    Oferece ao usuário a acesso operações de entrada e saída, edição, manipulação de grafos, vértices e arestas, execução de algoritmos e configurações do ambiente do GRAFO. Destacado em amarelo na figura 3.1.

  2. Barra de ferramentas

    Contem alguns botões de atalhos para operações básicas de entrada e saída e botões para interação em algoritmos com suporte a passo a passo. Destacado em vermelho na figura 3.1.

  3. Área de trabalho

    Área onde o usuário desenha e interage com o seu grafo. Como a inclusão e exclusão de vértices e arestas, edição de propriedades como rótulos e pesos entre outros. Também e a área em que o usuário vê o resultado da ação de um algoritmo em um grafo. Como destaque de vértice e arestas, a inclusão e exclusão de componentes, a alterações de layout e outros ações sofridas pelo grafo da área de trabalho. Destacado em azul na figura 3.1.

  4. Barra de status

    Exibe instruções e informações ao usuário e também o resultado de algoritmos. Destacado em verde na figura 3.1.

    (figura 3.1)

3.1. Menus

Os menus do GRAFO são divididos em cinco categorias: File, Edit, Graph, Algorithms e Options. Estas por sua vez estão subdivididas de maneira a conter operações correlatas.

3.1.1. File

Esta opção de menu, figura 3.2, contém as operações de entrada e saída para o GRAFO.

(figura 3.2)

3.1.2. Edit

Esta opção de menu contem as operações para construção de um grafo e a edição de atributos e propriedades. Figura 3.6.

(figura 3.6)

(figura 3.7) (figura 3.8)

(figura 3.9) (figura 3.10)

3.1.3. Graph

Esta opção de menu oferece manipulações sobre o grafo já construído através do menu Edit. Também traz um wizard para geração de novos grafos e opções para redesenhar grafo em edição com um novo layout. A figura 3.11 traz o menu de opções.

(figura 3.11)

3.1.3.1. Reset Graph - Ctrl+R

Limpa as estruturas internas e a área de trabalho preparando o ambiente do GRAFO para uma nova edição.

3.1.3.2. Reset marked edges - Ctrl+E

Limpa as arestas destacadas. Como exemplo temos a figura 3.13 quando executado o Reset marked edges sobre o grafo da figura 3.12.

3.1.3.3. Reset marked vertices - Ctrl+V

Limpa os vertices destacados. Como exemplo temos a figura 3.14 quando executado o Resete marked vertices sobre o grafo da figura 3.13.

(figura 3.12) (figura 3.13) (figura 3.14)

3.1.3.4. Vertex label

Exibe os vértices nomeados de acordo com a opção selecionada. Figura 3.15. Nas figuras 3.9 e 3.10 foram utilizadas a opção de exibição de label ou rótulos nos vértices. Estes vértices representam as cidades Londrina, Curitiba, Cascavel.

3.1.3.5. Edge label

Exibe as arestas nomeadas de acordo com a opção selecionada. Figura 3.16. Nas figuras 3.9 e 3.10 foram utilizadas a opção de exibição de label ou rótulos nas arestas. Estas arestas representam nomes de rodovias, PR-487, PR-548 e PR-878, que ligam as cidades.

(figura 3.15) (figura 3.16)

3.1.3.6. Generate Graph

Gera grafos pré determinados de acordo com um conjunto de parâmetros informados. A figura 3.17 mostra o menu de opções.

(figura 3.17)

(figura 3.23) (figura 3.24)
(figura 3.25) (figura 3.26)

3.1.3.7. Redraw graph

Redesenha o grafo em um novo layout porem mantendo inalterado o seu conjunto de vértices e arestas.

(figura 3.27) (figura 3.28)

3.1.3.8. Toggle graph/digraph - T

Altera o tipo do grafo entre Grafo e Digrafo. Esta opção está desabilitada no menu por não estar implementada. No capítulo 6 será abordada a possibilidade de finalização ao suporte a digrafos.

3.1.4. Algorithms

Esta opção de menu, figura 3.29, exibe o elenco de algoritmos disponíveis para utilização no GRAFO. Os algoritmos estão distribuídos nas categorias de Teste, Resultado, Passo a Passo, Transformação e Busca. O GRAFO possui algoritmos nativos ou fornecidos através de plugins. Os algoritmos disponibilizados através de plugins são uma expansão da interface e estão destacados com ícone de plug ( ).

(figura 3.29)

3.1.5. Options

Este menu agrupa as preferências do usuário, configurações, informações sobre plugins e modo de visualização

(figura 3.30)

3.2. Barra de Ferramentas

A barra de ferramentas, figura 3.36, traz os comandos básicos de entrada e saída e opções para a manipulação dos algoritmos passo a passo. A utilização dos botões do passo a passo serão detalhadas no capitulo 5.

(figura 3.36)

3.3. Área de trabalho

É na área de trabalho que o usuário edita os seus grafos, recebe o resultado de execução dos algoritmos como o destaque de vértices e arestas e a criação e exclusão de componentes do grafo.

3.4. Barra de Status

A barra de status serve como canal de comunicação entre o GRAFO e o usuário. É nela que o GRAFO dá instruções, mostra resultados e interage de forma escrita com o usuário. Como por exemplo a figura 3.37 onde o usuário é instruído a clicar na área de trabalho para criar um vértice. Na figura 3.38 o usuário é instruído a clicar em um vértice e arrasta-lo para que este seja movido. E na figura 3.39 o usuário é informado que o grafo por ele escolhido não é cordal.

(figura 3.37)

(figura 3.38)

(figura 3.39)

4. Plugins

Este capítulo é um tutorial prático para construção de plugins. Ele começa explorando os headers e estruturas internas ao GRAFO que precisão ser conhecidas antes da construção. Depois através de um exemplo simples, Hello World, é explorado a estrutura de um plugin: headers necessários, protótipo das funções e corpo das funções. Utilizando-se do Hello World também é abordo compilação, instalação e execução de um plugin. O capitulo termina detalhando através do exemplo Get some parameter como se faz para receber parâmetros. Pelo exemplo Generate Star Graph como se cria vértices e arestas. E finalmente utilizando-se dos plugins Highest Degree e Some Edge como se faz respectivamente para destacar os vértices e arestas na interface do grafo.

Os plugins são bibliotecas carregadas dinamicamente pelo GRAFO no momento da inicialização. Cada plugin pode ter um ou mais algoritmos. A cada algoritmo criado recebe uma nova entrada no menu Algorithms de acordo com a sua categoria. São elas:

  1. Test
  2. Result
  3. Step by step
  4. Tranformations
  5. Search

Sem dúvida a construção de plugins é que torna o GRAFO realmente poderoso. Com eles pode-se facilmente implementar um novo algoritmo e acompanhar visualmente o seu resultado.

4.1. Headers

Para a construção de plugins é preciso conhecer algumas estruturas internas do GRAFO e os headers onde estão declaradas. São Elas:

graph.h

No header graph.h estão declaradas as estruturas que representam um vértice, uma aresta e um grafo dentro do ambiente. Bem como as funções utilizadas para manipula-los.

Vertex struct - Estrutura de um vértice

A estrutura Vertex (tabela 4.1) contém as informações necessárias para a representação de um vértice são elas: Identificador, nome dado ao vértice, o seu peso, a sua posição (x,y) no plano cartesiano, sua cor, informações se o vértice está conectado, se está marcado, grau do vértice, grau de entrada e grau de saída.

Obs.: A propriedade degree só é utilizada em grafos enquanto que propriedades indegree e outdegree em Digrafos.

Nome Tipo Descrição
id int Identificador auto incremental e único
label char * Texto (nome) associado ao vértice
weight Weight Peso da aresta - typedef float
x float Posição X em 2D
y float Posição Y em 2D
color Color Cor do vértice - typedef int
concomp int Se 1 o vértice está conectado
mark char Se 1 o vértice está marcado
degree int Grau do vértice
indegree int Grau de entrada
outdegree int Grau de saída

(tabela 4.1)

Edge - Matriz de adjacência

Um aresta é representada pela matriz de adjacência e sua unidade básica é typedef char Edge. Neste caso assume 0 (zero) ou 1 (um). Na tabela 4.3 onde descrito as propriedades de um grafo pode ser visto que o Edge é declarado como Edge **, ou seja uma matriz bidimensional.

Edge_prop struct - Estrutura das propriedades de uma aresta

A estrutura Edge_prop (tabela 4.2) vem complementar a matriz de adjacência Edge. As informações complementares são: Nome associado a aresta, o seu peso, a sua cor, informações se a aresta está marcada e os pontos de controle utilizados para gerar arestas curvas.

Nome Tipo Descrição
label char * Texto (nome) associado a aresta
weight Weight Peso da aresta - typedef float
color Color Cor da aresta - typedef int
mark char Se 1 a aresta está marcada
ctrlpoints float [4][3] Pontos de controle

(tabela 4.2)

Graph struct - Estrutura de um grafo

A estrutura Graph (tabela 4.3) contém as informações necessárias para a representação de um grafo. São elas: O seu tipo, a quantidade de vértices, o identificador do próximo vértice, a quantidade de vértices para o tipo grafo, a quantidade de arestas para o tipo digrafo, o espaço em memória alocado, a lista de vértices, a matriz de adjacência, a matriz de propriedade dos vértices, o número de componentes conexos e o número de cores utilizadas.

Obs.: As propriedades ncomp, ncolor e encolor não são inicializadas ou atualizadas automaticamente. Caso deseje utiliza-las é necessário que as faça manualmente.

Nome Tipo Descrição
type GraphType Informa o tipo do grafo - typedef enum (GRAPH,DIGRAPH)
size int Quantidade de vértices do grafo
nextid int Identificador a ser recebido pelo próximo vértice
nedges int Quantidade de vértices (Grafos)
narcs int Quantidade de arcos (Digrafos)
allocated_size int Espaço alocado
vertex Vertex * Lista de vértices
edge Edge ** Matriz de adjacência - typedef char
prop Edge_prop ** Propriedades da matriz de adjacência
ncomp int Número de componentes conexos
ncolor int Número de cores utilizadas (Não é número cromático)
encolor int Número de cores utilizadas pelas arestas

(tabela 4.3)

SEdge struct - Estrutura de uma aresta simples

A estrutura SEdge (tabela 4.4) contem a informação do par ordenado que forma uma aresta. Esta estrutura será e incluída será utilizada na lista de destaque de aresta. Vide tabela 4.18 para maiores detalhes.

Obs.: As estruturas SEdge e SVertex são auxiliares e são necessárias para destaque de vértices e arestas na interface do GRAFO.

Nome Tipo Descrição
u SVertex Vértice U - typedef int
v SVertex Vértice V - typedef int

(tabela 4.4)

Functions - Funções para manipulação de um grafo

A tabela 4.5 traz a lista de funções para manipulação do grafo. Com elas pode-se alocar e liberar memória para um grafo, inicializar as estruturas internas, copiar um grafo em outro, adicionar e remover vértices, arestas e arcos. E também limpar o status de marcado (mark) de vértices e arestas.

Obs.: Funções internas de controle não estão documentadas. A princípio elas não são necessárias para a construção de plugins.

Declaração Descrição
void AllocGraph(Graph *G) Aloca espaço para um grafo e as estruturas que o compõem (vértices, arestas, matriz de adjacência, etc)
void FreeGraph(Graph *G) Libera espaço alocado para grafo e suas estruturas
void InitGraph(Graph *G, GraphType type) Inicializa um grafo e suas estruturas
void InitEdges(Graph *G) Inicializa somente a matriz de adjacência e suas propriedades
void CopyGraph(Graph *H, Graph *G) Aloca o grafo H e copia o G nele
void AddPoint(Graph *G, float x, float y) Adiciona a vértice na posição (x,y)
void RemovePoint(Graph *G, int p) Remove o vértice o P vértice do grafo
void AddEdge(Graph *G, int x, int y) Adiciona um aresta entre os vértices X e Y
void RemoveEdge(Graph *G, int x, int y) Remove a aresta entre os vértices X e Y
void AddArc(Graph *G, int x, int y) Adciona o arco entre os vértice X para Y
void RemoveArc(Graph *G, int x, int y) Remove a aresta direcionada do vértice X para Y
void ClearMarkedVerts(Graph *G) Limpa a propriedade mark dos vértices
void ClearMarkedEdges(Graph *G) Limpa a propriedade mark das arestas

(tabela 4.5)

pgin.h

No header pgin.h estão declarados a estrutura para a lista de algoritmos bem como funções para entrada de parâmetros.

Pgin struct - Estrutura da lista de funções

A estrutura Pgin é uma lista de funções (algoritmos) disponíveis em um plugin. Cada plugin deve possuir no mínimo uma função sempre terminada pelo tipo PGIN_LIST_END ao final do capítulo 4 a criação de plugins de exemplo irão abordar a correta construção da lista de algoritmos disponíveis em um plugin. A tabela 4.6 detalha os campos da estrutura. São eles: Tipo do algoritmo, nome para o menu, nome da função principal do algoritmo e flags de controle para o GRAFO.

Nome Tipo Descrição
type int Determina o tipo do plugin na lista de algoritmos
label char * Determina o nome do algoritmo. Este é nome que irá aparecer na entrada do menu Algorithms
name char * Determina o nome da função do algoritmo dentro do plugin
flags int Passa informações ao GRAFO de como tratar esse algoritmo após a sua execução

(tabela 4.6)

A tabela 4.7 detalha o valor para o campo type na lista de algoritimos.

Nome Descrição
PGIN_TEST_ALG Informa que o algoritmo é de testes
PGIN_RESULT_ALG Informa que o algoritmo é de resultado
PGIN_STEP_ALG Informa que o algoritmo é de passo a passo
PGIN_TRANSF_ALG Informa que o algoritmo é de transformação
PGIN_SEARCH_ALG Informa que o algoritmo é de busca
PGIN_LIST_END Final da lista de algoritmos

(tabela 4.7)

O campo flag detalhado na tabela 4.8 informa ao GRAFO como ele deve redesenhar o grafo resultante ao termino da execução de um algoritmo de transformação. Os demais tipos de plugins não são sensíveis a estes flags e os grafos não serão redesenhados ao término da execução destes plugin.

Nome Descrição
PGIN_FLAG_NOREDRAW Não redesenha o grafo. O construtor do plugin é responsável por determinar a posição dos vértices
PGIN_FLAG_REDRAWASCIRCLE Redesenha o grafo automaticamente em circulo
PGIN_FLAG_REDRAWWITHCENTEREDVERTEX Redesenha o grafo com o primeiro vértice no centro

(tabela 4.8)

Functions - Funções de entrada de dados a um plugin

A tabela 4.9 traz a lista de funções para manipulação de entrada de dados para os plugins. Com elas é possível fazer a leitura dos tipos de dados: Inteiro, Double e String.

Declaração Descrição
int pgin_read_int(char *name, char *label,
int def, int min, int max, int inc)
Cria janela para leitura de um tipo de dado inteiro
double pgin_read_double(char *name, char *label,
double def, double min, double max, double inc, int digits)
Cria janela para leitura de um tipo de dado double
char *pgin_read_string(char *name, char *label,
char *def, int max_len)
Cria janela para leitura de uma tipo de dado string

(tabela 4.9)

A tabela 4.10 detalha os parâmetros das funções de entrada de dados descritas na tabela 4.9.

Parâmetros Descrição
name Nome da janela
label Texto informativo
def Valor padrão
min Mínimo valor permitido
max Máximo valor permitido
inc Incremento para int e double
digits Número de casas decimais
max_len Tamanho máximo da string

(tabela 4.10)

alghandler.h

No header alghandler.h estão declarados as estruturas das listas de algoritmos bem como as funções utilizadas para manipula-las.

A tabela 4.11 detalha a função RunAlgorithm que pode ser utilizada para chamar qualquer algoritmo existente no grafo sendo ele nativo ou não. As listas especiais de destaque arc_edges e verts serão abordadas neste capítulo no tópico Estrutura de um plugin.

Declaração Descrição
int RunAlgorithm(char *name, Graph *G, char *s,
int x, List *arc_edges, List *verts)
Chama qualquer algoritmo disponível sendo ele nativo ou por plugins

(tabela 4.11)

list.h

No header list.h estão declarados as estruturas de pilha e lista. Bem como as funções utilizadas para manipula-las. Elas são necessárias no destaque de vértices e arestas. Vide o tópico Destacando vértices e arestas neste capítulo.

Node struct - Estrutura de um nodo

A estrutura Node na tabela 4.12 contém um nodo genérico onde o campo data pode apontar para qualquer tipo de dado. O nodo pode ser utilizado tanto em uma lista ou em uma pilha.

Nome Tipo Descrição
data void * Aponta para o dado do Node
size int Tamanho alocado para o dado apontado
next Node * Aponta para o próximo nodo
prev Node * Aponta para o nodo anterior

(tabela 4.12)

Functions - Funções para manipulação de um nodo

A tabela 4.13 traz a lista de funções para criação e destruição de um nodo.

Declaração Descrição
Node MakeNode(void *data, int size) Cria um nodo apontando para um dado informado com o tamanho de size
void DestroyNode(Node n) Destrói o nodo informado

(tabela 4.13)

List struct - Estrutura de uma lista

A estrutura List (tabela 4.14) contém os dados necessários para se trabalhar com o tipo de dado lista.

Nome Tipo Descrição
size int Número de nodes
head Node Primeiro node
tail Node Último node

(tabela 4.14)

Functions - Funções para manipulação de uma lista

A tabela 4.15 contém a lista de funções para manipulação da estrutura list podendo-se com elas: Criar e inicializar uma lista, inserir e remover um nodo, mover, copiar e limpar uma lista.

Declaração Descrição
List *CreateList(void) Cria uma lista
void InitList(List *list) Inicializa a lista informada
void InsertNode(List *list, Node node) Insere um nodo na lista informada
Node RemoveNode(List *list, Node node) Remove o nodo na lista informada
void MoveList(List *l1, List *l2) Copia a L2 em L1 destruindo L2; L1 deve estar inicializada
void CleanList(List *list) Remove todos os nodos de uma lista
void CopyList(List *l1, List *l2) Copia a L2 em L1; L1 deve estar inicializada

(tabela 4.15)

Stack struct - Estrutura de uma pilha

A estrutura Stack (tabela 4.16) contém os dados necessários para se trabalhar com o tipo de dado pilha no GRAFO.

Nome Tipo Descrição
size int Número de nodes
top Node Topo da pilha

(tabela 4.16)

Functions - Funções para manipulação de uma pilha

A tabela 4.17 contém a lista de funções para manipulação da estrutura Stack podendo-se com elas: Criar e inicializar uma pilha, inserir e remover um nodo e limpar a pilha.

Declaração Descrição
Stack *CreateStack(void) Cria uma pilha
void InitStack(Stack *stk) Inicializa a pilha informada
void PushNode(Stack *stk, Node node) Insere o nodo na pilha
Node PopNode(Stack *stk) Remove o nodo da pilha
void CleanStack(Stack *stk) Remove todos os nodos da pilha

(tabela 4.17)

4.2. Estrutura de um plugin

Neste tópico será abortado a criação do plugin Hello World e também o detalhamento da estrutura e divisões de um plugin. O código fonte completo do plugin Hello Word encontra-se no Apêndice B.

O plugin é dividido em 3 partes básicas. São elas:

  1. Inclusão de headers
  2. Protótipo das funções
  3. Corpo das funções

4.2.1. headers

Na primeira parde deve-se incluir os headers da linguagem C e os headers obrigatórios para os plugins:

27
28
29
30
31
32
33
34
35
36
/* headers da linguagem C */
#include <stdio.h>
#include <stdlib.h>

/* headers do GRAFO  */
/* Informacoes da estrutura de plugins */
#include "../pgin.h"

/* Informacoes da estrutura do GRAFO */
#include "../graph.h"

Obs.: Os headers do grafo foram incluídos pressupondo que a diretório plugins está um nível abaixo do diretório do GRAFO.

4.2.2. Protótipo das funções

Na segunda parte deve-se declarar o protótipo para a função obrigatória pgin_info o protótipo para as funções de algoritmos e outras funções internas ao plugin. Como função de algoritmo foi declarado o tradicional HelloWorld.

38
39
40
41
42
43
44
45
46
/* Funcao obrigatoria pgin_info */
Pgin *pgin_info(void);

/* Funcoes de algoritmos */
int HelloWorld(Graph *G, char *mess);

/* Funcoes internas ao plugin*/
...
...

As funções de algoritmos possuem uma assinatura diferente para a lista de parâmetros de acordo com o seu tipo. Essa diferença deve ser observada ao incluir o algoritmo na lista de funções do plugin.

  1. Test
      int TestAlgorithm(Graph *G, char *mess)
    
  2. Result
      int ResultAlgorithm(Graph *G, char *mess, List *arc_edges, List *verts)
    
  3. Step by step
      int StepAlgorithm(Graph *G, char *mess, int indx, List *arc_edges, List *verts)
    
  4. Tranformations
      int Transformation(Graph *G, char *mess)
    
  5. Search
      int SearchAlgorithm(Graph *G, char *mess, int indx, List *arc_edges, List *verts)
    

    A tabela 4.18 traz o detalhamento dos parâmetros passados as funções de algoritmos.

Parâmetros Descrição
Graph *G Aponta para grafo na área de trabalho
char *mess Aponta para a mensagem na barra de status
int indx Número do vértice inicial de buscas
List *arc_edges Lista com as arestas destacadas do grafo na área de trabalho
List *verts Lista com os vértices destacados do grafo na área de trabalho

(tabela 4.18)

É importante destacar que o grafo G passado como parâmetro aponta para a estrutura do grafo que será desenhada na área de trabalho. E as listas arc_edges e verts apontam para as estruturas de destaque de vértices e arestas. Ao iniciar o GRAFO estas estruturas são alocadas e disponibilizadas para utilização. Um plugin pode reinicializa-las com InitGraph, InitEdges e CleanList. Porem NÃO deve liberar a memória alocadas a elas.

4.2.3. Corpo das funções

Na terceira parte deve-se criar o corpo para a função obrigatória pgin_info e implementar as funções do algoritmo.

pgin_info - Função obrigatória

A pgin_info é responsável por inicializar a lista de funções existentes no plugin. No exemplo abaixo incluímos a função HelloWorld do tipo PGIN_TEST_ALG.

47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
/* A funcao pgin_info() deve sempre estar presente. O GRAFO ira chama-la
 * para recuperar as informacoes do plugin.
 */
Pgin *pgin_info(void){
Pgin *pgin;

    /* Aloca espaco para o HelloWorld e o PGIN_LIST_END */
    pgin = (Pgin *) malloc(2 * sizeof(Pgin));

    /* Inclui HelloWorld como primeiro algoritmo do plugin */
    pgin[0].type = PGIN_TEST_ALG;
    pgin[0].label = "Hello World!";
    pgin[0].name = "HelloWorld";
    pgin[0].flags = 0;

    /* Indica o final da lista de algoritmos */
    pgin[1].type = PGIN_LIST_END;
    pgin[1].label = 0;
    pgin[1].name = 0;
    pgin[1].flags = 0;

    return pgin;
}

Como já foi dito um plugin pode conter vários algoritmos, para isso basta incluí-los na lista. Por exemplo se o algoritmo HelloUniverse estivesse no mesmo plugin que o HelloWorld a função pgin_info deveria ser:

47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
/* A funcao pgin_info() deve sempre estar presente. O GRAFO ira chama-la
 * para recuperar as informacoes do plugin.
 */
Pgin *pgin_info(void){
Pgin *pgin;

    /* Aloca espaco para o HelloWorld, HelloUniverse e o PGIN_LIST_END */
    /* Observe que agora o malloc aloca um espaco a mais para o HelloUniverse */
    pgin = (Pgin *) malloc(3 * sizeof(Pgin));

    /* Inclui HelloWorld como primeiro algoritimo do plugin */
    pgin[0].type = PGIN_TEST_ALG;
    pgin[0].label = "Hello World!";
    pgin[0].name = "HelloWorld";
    pgin[0].flags = 0;

    /* Inclui HelloUniverse como primeiro algoritmo do plugin */
    pgin[1].type = PGIN_TEST_ALG;
    pgin[1].label = "Hello Universe!!!";
    pgin[1].name = "HelloUniverse";
    pgin[1].flags = 0;

    /* Indica o final da lista de algoritmos */
    pgin[2].type = PGIN_LIST_END;
    pgin[2].label = 0;
    pgin[2].name = 0;
    pgin[2].flags = 0;

    return pgin;
}

HelloWorld - Funções de algoritmos

E finalmente a implementação da função de algoritmo. Quando o nosso exemplo for executado será escrito na barra de status Hello World!.

71
72
73
74
75
76
77
/* Esta e a funcao principal do plugin */
int HelloWorld(Graph *G, char *mess){

    sprintf(mess, "Hello World!");

    return 1;
}

4.3. Compilação e Instalação

Para que o plugin seja reconhecido pelo GRAFO devemos criar uma biblioteca dinâmica e inclui-lo no diretório destinado aos plugins.

  1. Compilação

    Para compilar o plugin de exemplo HelloWorld que está no arquivo hw.c utilizamos a linha de comando abaixo:

      gcc -Wall -fPIC -shared hw.c -o hw.so
    
  2. Instalação

    Para instalar o plugin basta copiar a biblioteca construída (hw.so) para o diretório de plugins. O diretório configurado pode ser consultado/alterado em Options > Preferences... > Default paths > Plugins path. Vide o capítulo 3 para maiores detalhes.

4.4. Execução

Ao abrir o GRAFO os plugins serão carregados e um item de menu criado para cada função neles contidas. No nosso exemplo o plugin HelloWorld criou a entrada de menu abaixo. Figura 4.1:

(figura 4.1)

Ao clicar no menu Hello World! o GRAFO chama a função de algoritmo associado a ele. E ao termino atualiza a área de trabalho e a barra de status com os resultados. No nosso exemplo simplesmente escreve na barra de status. Figura 4.2.

(figura 4.2)

4.5. Recebendo parâmetros

Neste tópico será abordado a criação do plugin Get some parameters que ilustra a utilização das funções de entrada de dados para o GRAFO. O código fonte completo do plugin Get some parameters encontra-se no Apêndice B.

Os plugins podem receber 3 tipos de dados.

  1. Inteiro
  2. Double
  3. String

    Abaixo segue a função principal no arquivo getsp.c. O detalhamento das funções pgin_read_int, pgin_read_double e pgin_read_string pode ser visto na tabela 4.9.

    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    int getsp(Graph *G, char *mess){
    int i;
    double d;
    char *s;
    
        i = pgin_read_int("Get some parameters", "Give me an int",
                    10, 1, 2000000, 1);
        d = pgin_read_double("Get some parameters", "Give me a double",
                    0.0, -10.0, 10.0, 0.1, 1);
        s = pgin_read_string("Get some parameters", "Give me a string",
                    "I'm a string", 40);
    
        sprintf(mess, "I got: %d, %f and '%s'. Thanks!", i, d, s);
        free(s);
    
        return 1;
    }
    

Como resultado obtemos os seguintes diálogos de entrada de dados. Para um inteiro figura 4.3. Para um double figura 4.4. Para uma string figura 4.5.

(figura 4.3) (figura 4.4) (figura 4.5)

E os valores recebidos pelos diálogos são escritos na barra de status. Vide figura 4.6

(figura 4.6)

4.6. Criando vértices e arestas

Neste tópico será abordado a criação do plugin Generate Star Graph que ilustra a utilização das funções AddPoint e AddEdge detalhadas na tabela 4.5. Abaixo segue a função principal no arquivo stargraphexample.c. O código fonte completo do plugin Generate Star Graph encontra-se no Apêndice B.

59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
int stargraph(Graph *G, char *mess){
int i, n;

    /* Le o numero de vertices do grafo */
    n = pgin_read_int("Generate Star Graph", "Number of vertices",
                5, 1, 2000000, 1);

    /* Inicializar o grafo da area de trabalho */
    InitGraph(G, G->type);

    /* Adiciona N vertices na posicao (0,0) */
    for (i = 0; i < n; i++)
        AddPoint(G, 0, 0);

    /* Adiciona N arestas comecando no vertice 0 ate N-1 */
    for (i = 1; i < n; i++) { 
        AddEdge(G, 0, i);
    }

    return 1;
}

Como pode ser observado o algoritmo não se preocupa em posicionar de maneira elegante os vértices na tela. Adicionando todos os vértices sempre na posição (0,0).

67
68
69
70
71
72
73
    ...

    /* Adiciona N vertices na posicao (0,0) */
    for (i = 0; i < n; i++)
        AddPoint(G, 0, 0);

    ...

Isto é possível porque o plugin de transformação criado está utilizando o flag PGIN_FLAG_REDRAWWITHCENTEREDVERTEX. E com isso o grafo gerado será redesenhado automaticamente com o primeiro vértice no centro. Se estivéssemos utilizando o flag PGIN_FLAG_NOREDRAW o plugin deve responsável por posicionar os vértices corretamente na área de trabalho.

Como resultado a geração de um grafo estrela com 20 vértices. Figura 4.7:

(figura 4.7)

4.7. Destacando vértices e arestas

Neste tópico será abordado a construção do plugin Highest Degree que ilustra a utilização da lista especial verts e a construção do plugin Some Edge que ilustra a utilização da lista especial arc_edges. O destaque de vértices e arestas utilizam as listas especiais passadas como parâmetros aos plugins. A lista verts contém os vértices destacados em um grafo. A lista arc_edges contém as arestas e arcos destacados em um {di,}grafo. Para o destaque deve-se simplesmente inserir um nodo nas listas a ao encerrar a execução do algoritmo o GRAFO se encarrega de destacar na interface os nodos inseridos. O detalhamento sobre as funções para manipulação de nodos e listas estão respectivamente nas tabelas 4.13 e 4.15.

4.7.1. Destacando um vértice

Abaixo segue a função principal no arquivo vertexexample.c responsável pelo plugin Highest Degree que ilustra a utilização da lista especial verts. O código fonte completo do plugin Highest Degree encontra-se no Apêndice B.

 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
int MaxDegree(Graph *G, char *mess, List *arc_edges, List *verts){
Node N;
int i,maxdeg;

    /* Testa se o grafo esta vazio */
    if (G->size < 1) {
        sprintf(mess, "%s", "Empty graph!");
        return 1;
    }

    /* Procurar pelo vertice de maior grau */
    maxdeg = 0;
    for (i = 1; i < G->size; i++) {
        if (G->vertex[i].degree > G->vertex[maxdeg].degree) {
            maxdeg = i;
        }
    }

    /* Coloca em um novo nodo o vertice de maior grau */
    N = MakeNode(&maxdeg, sizeof(int));

    /* Coloca o nodo na lista de vertices especiais */
    InsertNode(verts, N);

    return 1;
}

Utiliza-se da função MakeNode para criar um novo nodo e depois da função InsertNode para inserir um nodo com o vértice de maior grau na lista verts.

Como resultado o destaque do vértice 1 de grau 5 no grafo abaixo. Figura 4.8:

(figura 4.8)

4.7.2. Destacando uma aresta

Abaixo segue a função principal no arquivo edgeexample.c responsável pelo plugin Some Edge que ilustra a utilização da lista especial arc_edges. O código fonte completo do plugin Some Edge encontra-se no Apêndice B.

 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
int MaxMinEdge(Graph *G, char *mess, List *arc_edges, List *verts){
SEdge E; /* Aresta simples */
Node N;
int i,maxdeg,mindeg;

    /* Testa se o grafo esta vazio */
    if (G->size < 1) {
        sprintf(mess, "%s", "Empty graph!");
        return 1;
    }

    /* Procurar pelo vertice de maior grau */
    maxdeg = 0;
    for (i = 1; i < G->size; i++) {
        if (G->vertex[i].degree > G->vertex[maxdeg].degree) {
            maxdeg = i;
        }
    }

    /* Procura pelo vertice de menor grau adjacente ao de maior */
    mindeg = -1;
    for (i = 0; i < G->size; i++) {
        if (G->edge[maxdeg][i]) {
            if (mindeg == -1) {
                mindeg = i;
            } else if (G->vertex[i].degree < G->vertex[mindeg].degree) {
                mindeg = i;
            }
        }
    }

    /* Atribui maxdeg e o mindeg a aresta simples */
    E.u = maxdeg;
    E.v = mindeg;

    /* Coloca em um novo nodo a aresta simples  */
    N = MakeNode(&E, sizeof(SEdge));

    /* Coloca o nodo na lista de arestas especiais */
    InsertNode(arc_edges, N);

    return 1;
}

Como no exemplo do vértice também se utiliza a função MakeNode para criar um novo nodo. Porem o nodo criado contém como dado uma aresta simples (SEdge). E depois utiliza-se da função InsertNode para inserir o nodo com a aresta encontrada na lista arc_edges.

Como resultado o destaque da aresta entre o vértice 1 de grau 5 e o vértice 3 de grau 2. Figura 4.9:

(figura 4.9)

5. Passo a Passo

Neste capítulo, inicialmente, é feito um comparativo entre a execução de um algoritmo normal; recurso já existente no GRAFO; e a execução de um algoritmo passo a passo, novo recurso introduzido por este trabalho. também são explicados os recursos existentes no passo a passo e como o usuário pode interagir com um algoritmo. Em seguida é abordado como o este foi implementado e o que motivou esta abordagem. O capítulo termina mostrando um tutorial prático de como se realiza a implementação um plugin com funcionalidade passo a passo. Para tanto abordou-se neste tema também os headers necessários, as estruturas internas e os cuidados que devem ser tomados para sua construção.

5.1. Como estava

O que é o passo a passo? É a possibilidade de interagir com a execução do algoritmo. E com isso conseguir uma visão melhor de como e o que ele faz do seu início ao fim.

A possibilidade de execução de algoritmos passo a passo veio preencher uma lacuna deixada pelo GRAFO. Na estrutura de execução que existia até então era difícil observar o que se passava entre o início (click no menu) e o fim do algoritmo (atualização da área de trabalho).

Observemos a execução do algoritmo Depth First - Busca em profundidade, sem suporte a passo a passo, no menu Algorithms > Search algorithms > Depth First.

Na figura (5.1) observa-se um grafo em árvore com 6 vértices. Ao executar o algoritmo em segundos todos os vértices e arestas da árvore são destacados. Vide figura (5.2). Como a árvore foi completamente destacada? Qual a ordem que os vértices foram destacados? Quantos passos têm esse algoritmo? Sem o conhecimento prévio de como funciona a busca em profundidade em uma árvore é impossível responder a tais perguntas.

(figura 5.1) (figura 5.2)

5.2. Como ficou

Foi justamente com o objetivo de responder a estas perguntas que entra a execução de algoritmo passo a passo na interface do GRAFO. Ele vem auxiliar a compreensão e o entendimento da execução de algoritmos de uma maneira visual e interativa.

Observemos a execução do mesmo algoritmo Depth First - Busca em profundidade, porém com suporte a passo a passo, no menu Algorithms > Algorithms step by step > Depth First.

Na figura 5.3 observa-se o mesmo grafo em árvore com 6 vértices. Ao executar o algoritmo o grafo vai lentamente sendo destacado. Vide figura 5.4 até figura 5.9. Com esta visualização mesmo um leitor leigo consegue responder as perguntas feitas.

Como a árvore foi completamente destacada?

Qual a ordem que os vértices foram destacados?

Quantos passos tem esse algoritmo?

(figura 5.3)
(figura 5.4) (figura 5.5) (figura 5.6
(figura 5.7) (figura 5.8) (figura 5.9)

5.3. Interagindo com o algoritmo

Através da barra de ferramentas, figura 5.10, é possível uma interação básica com o algoritmo. Ao acionar o algoritmo pelo menu ele lentamente vai sendo executado, porem é possível através dos botões ir direto ao resultado final, voltar ao começo, ir somente um passo a diante, retroceder um passo ou colocá-lo para executar passo a passo novamente.

(figura 5.10)

5.4. Como foi implementado

A idéia inicial foi implementar a interface passo a passo de uma forma genérica sem que fosse necessária intervenção explícitas nos algoritmo. E assim todo e qualquer algoritmo no GRAFO poderia ser executado com ou sem o passo a passo, porem devido a modularidade do programa fez com que essa abordagem não fosse possível. No GRAFO existe uma clara divisão entre o que é interface com o usuário, estrutura de desenho, estrutura de grafos e estrutura de plugins e algoritmos. Os algoritmos nativos ou por plugins não têm acesso direto a interface com o usuário e a estrutura de desenho. Ao serem executados eles se preocupam em manipular grafos, arestas e vértices. O reflexo desta alterações ao usuário é feito pela estrutura de desenho em conjunto com a interface.

A estratégia adotada foi de que os algoritmos continuassem a manipular somente o que eles conhecem, que são grafos, arestas e vértices, para isto, foi criado um mecanismo de gravação e reprodução de estados. A cada estado interessante o algoritmo explicitamente grava a situação do grafo e das listas de destaque de vértices e arestas. Ao concluir a execução temos um filme com os passos relevantes para a compreensão do algoritmo. E este filme é disponibilizado ao usuário.

5.5. Headers

Para criar o mecanismo de gravação e reprodução utilizou-se uma lista onde cada nodo contém em que contexto está o grafo, arestas e vértices em destaque no momento que se instrui a gravação. Abaixo segue as estruturas e funções implementadas para tratar o passo a passo.

step.h

O header step.h deve ser incluído em um plugin sempre que se desejar que este tenha os recursos do passo a passo

Step struct - Estrutura de um passo

A estrutura Step (tabela 5.1) contém as informações necessárias a um passos que são: O seu identificador, uma cópia do grafo, os vértices em destaque, as arestas em destaque e uma mensagem associada ao passo salvo.

Nome Tipo Descrição
id int Identificador do passo. Auto incremental e único
G Graph Grafo associado ao passo
SpecEdges List * Lista de destaque de arestas associadas ao passo
SpecVerts List * Lista de destaque de vértices associados ao passo
status_string char[1000] Mensagem para a barra de status associada ao passo

(tabela 5.1)

StepStruct struct - Estrutura de múltiplos passos

A estrutura StepStruct (tabela 5.2) contém as informações necessárias para a reprodução dos passo: A quantidade de passos salvos, o passo atual, a lista de passos salvos e o status da execução do passo a passo.

Nome Tipo Descrição
size int Número de passos gravados
index int Contador de passo. Informa o passo atual
steps Step[MAX_STEPS] Lista contendo os passos gravados
exec_state char Status de execução (EXECUTING_STEPS, NOT_EXECUTING_STEPS)

(tabela 5.2)

Functions - Funções para manipulação do passo a passo

A tabela 5.3 traz a lista de funções para manipulação do passo a passo. A função AddStep é a única de uso externo, através de plugins, as demais são de uso interno a implementação do passo a passo. Um algoritmo somente deve-se preocupar em salvar os passos através do AddStep a inicialização da estrutura Step e StepStruct e o início automático da execução são atribuições da interface do GRAFO.

Declaração Descrição
void InitStepStruct(void) Inicializa a estrutura passo a passo
void AddStep(Graph *G, List *arc_edges, List *verts) Adiciona o grafo G e as listas arc_edges e verts no próximo passo livre
void ShowStep(Graph *G, List *arc_edges, List *verts, int step) Vai para o passo informado e o copia para a interface o grafo G e as listas arc_edges e verts
void FirstStep(Graph *G, List *arc_edges, List *verts) Vai para o primeiro passo gravado e o copia para a interface o grafo G e as listas arc_edges e verts
void PreviousStep(Graph *G, List *arc_edges, List *verts) Vai para o passo anterior e o copia para a interface o grafo G e as listas arc_edges e verts
void NextStep(Graph *G, List *arc_edges, List *verts) Vai para o próximo passo e o copia para a interface o grafo G e as listas arc_edges e verts
void LastStep(Graph *G, List *arc_edges, List *verts) Vai para o último passo e o copia para a interface o grafo G e as listas arc_edges e verts
int GetLastStep(void) Retorna o número de passos gravados
char GetExecStateStep(void) Retorna se o passo a passo está em execução (EXECUTING_STEPS, NOT_EXECUTING_STEPS)
void SetExecStateStep(char state) Inicia e termina a execução do passo a passo (START_EXEC_STEPS, STOP_EXEC_STEPS)

(tabela 5.3)

5.6. Construindo um algoritmo passo a passo

Como exemplo prático será construído o plugin Select odd que tem como característica destacar todos os vértices ímpares e todas as arestas que conectam vértices ímpares. O código fonte completo do plugin Select odd encontra-se no Apêndice B.

No capítulo 4 foi abordada a construção de plugins. Neste capítulo iremos complementá-la com a possibilidade de plugins passo a passo. Como no plugin comum o passo a passo também é dividido em 3 partes. São elas:

  1. Inclusão de headers
  2. Protótipo das funções
  3. Corpo das funções

5.6.1. headers

Na primeira parte deve-se incluir os headers da linguagem C e os headers obrigatórios para todos os plugins e mais o header step.h obrigatório para o passo a passo:

31
32
33
34
35
36
37
38
39
40
41
42
43
/* headers da linguagem C */
#include <stdio.h>
#include <stdlib.h>

/* headers do GRAFO  */
/* Informacoes da estrutura de plugins */
#include "../pgin.h"

/* Informacoes da estrutura do GRAFO */
#include "../graph.h"

/* Informacoes da estrutura do Passo a Passo */
#include "../step.h"

5.6.2. Protótipo das funções

Na segunda parte declara-se o protótipo para a função obrigatória pgin_info e o protótipo para as funções de algoritmos e outras funções. Como função de algoritmo foi declarada a SelectOdd.

45
46
47
48
49
50
51
52
53
/* Funcao obrigatoria pgin_info */
Pgin *pgin_info(void);

/* Funcoes de algoritmos */
int SelectOdd(Graph *G, char *mess, int indx, List *arc_edges, List *verts);

/* Funcoes internas ao plugin*/
...
...

Como mencionado no capítulo 4 cada tipo de algoritmo possui uma assinatura diferente para a lista de parâmetros (tabela 5.4). Para algoritmos passo a passo temos:

  1. Step by step

      int StepAlgorithm(Graph *G, char *mess, int indx, List *arc_edges, List *verts)
    

Parâmetros Descrição
Graph *G Aponta para grafo na área de trabalho
char *mess Aponta para a mensagem na barra de status
int indx Número do vértice inicial de buscas
List *arc_edges Lista com as arestas destacadas do grafo na área de trabalho
List *verts Lista com os vértices destacados do grafo na área de trabalho

(tabela 5.4)

5.6.3. Corpo das funções

Análogo a algoritmos tradicionais a terceira parte deve-se criar o corpo para a função obrigatória pgin_info e implementar as funções do algoritmo.

pgin_info - Função obrigatória

A pgin_info deve adicionar a lista de algoritmos com o tipo correto para algoritmos passo a passo que é PGIN_STEP_ALG.

54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
/* A funcao pgin_info() deve sempre estar presente. O GRAFO ira chama-la
 * para recuperar as informacoes do plugin.
 */
Pgin *pgin_info(void){
Pgin *pgin;

    /* Aloca espaco para o SelectOdd e o PGIN_LIST_END */
    pgin = (Pgin *) malloc(2 * sizeof(Pgin));

    /* Inclui SelectOdd como primeiro algoritmo do plugin */
    pgin[0].type = PGIN_STEP_ALG;
    pgin[0].label = "Select odd";
    pgin[0].name = "SelectOdd";
    pgin[0].flags = 0;

    /* Indica o final da lista de algoritmos */
    pgin[1].type = PGIN_LIST_END;
    pgin[1].label = 0;
    pgin[1].name = 0;
    pgin[1].flags = 0;

    return pgin;
}

SelectOdd - Funções de algoritmos

A função SelectOdd deve-se preocupar em gravar passos que ilustram a execução do algoritmo, os passos gravados que serão disponibilizado para a interação do usuário.

 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
int SelectOdd(Graph *G, char *mess, int indx, List *arc_edges, List *verts) {
SEdge E; /* Single Edge */
Node N;
int i, j,oddvertex;

    /* Testa se o grafo e vazio */
    if (G->size < 1) {
        sprintf(mess, "%s", "Empty graph!");
        return 1;
    }

    /* Seta para falso (0) a propriede 'mark' em todos os vertices */
    ClearMarkedVerts(G);

    /* Adiciona o primeiro passo - Nada destacado */
    AddStep(G, arc_edges, verts);

    /* Procura e destaca os vertices impares */
    oddvertex = 0;
    for (i = 1; i < G->size; i++) {

        /* Verifica se i e um numero impar */
        if ((i % 2)) {
            /* Marca o vertices para uso futuro */
            G->vertex[i].mark = 1;
            oddvertex = i;

            /* Coloca em um novo nodo o vertice impar */
            N = MakeNode(&oddvertex, sizeof(int));

            /* Coloca o nodo na lista de vertices especiais */
            InsertNode(verts, N);

            /* Adiciona novo passo - Salva o vertice destacado */
            AddStep(G, arc_edges, verts);
        }
    }

    /* Seta para falso (0) a propriede 'mark' em todas as arestas */    
    ClearMarkedEdges(G);

    /* Procura por um vertice impar adjacente a outro vertice impar */
    for (i = 0; i < G->size; i++) {
        for (j = 0; j < G->size; j++) {

            /* Evita o salvamento do passo [j,i] porque o passo [i,j] ja foi salvo */
            if (!G->prop[j][i].mark && \

                /* Verdadeiro se o vertex[i] e adjacente ao vertex[j] */
                G->edge[i][j] && \

                /* Verdadeiro se o vertex[i] e um vertice impar */
                G->vertex[i].mark && \

                /* Verdadeiro se o vertex[j] e um vertice impar */
                G->vertex[j].mark) {

                /* Marca a aresta para uso futuro */
                G->prop[i][j].mark = 1;

                /* Atribui um vertice impar adjacente a outro vertice impar no vertice simples */
                E.u = i;
                E.v = j;

                /* Coloca em um novo nodo a aresta simples  */
                N = MakeNode(&E, sizeof(SEdge));

                /* Coloca o nodo na lista de arestas especiais */
                InsertNode(arc_edges, N);

                /* Adiciona novo passo - Salva a aresta destacada */
                AddStep(G, arc_edges, verts);
            }
        }
    }

    return 1;
}

No algoritmo Select odd foi utilizado três vezes a chamada da função AddStep. A primeira vez se preocupa em salvar contexto do grafo sem o destaque de vértices e arestas. A segunda chamada se preocupa em salvar o momento que vértices ímpares são inseridos na lista especial verts. A terceira chamada se preocupa em salvar o momento em que as arestas são inseridas na lista especial arc_edges. A segunda chamada da função AddStep poderia ser suprimida. E com isso os vértices e arestas apareceriam em destaque no passo a passo em conjunto. Com isso concluímos que o posicionamento da chamada AddStep no algoritmo é essencial para sua compreensão. No exemplo o que se deseja é mostrar que primeiramente todos os vértices impares são destacados e depois que todas as arestas entre vértices ímpares são destacadas.

Um outro cuidado que se deve ter é de não salvar passos adicionais ou repetidos que não acrescentem em nada a compreensão do algoritmo. No exemplo utiliza-se a propriedade mark para informar que uma aresta já foi destacada. Por exemplo se foi salvo o passo quando a aresta (1,3) é destacada não existe a necessidade de salvar o passo (3,1) pois a aresta é a mesma. Abaixo segue o trecho de código que faz este controle.

118
119
120
121
122
123
            ...
            ...

            /* Evita o salvamento do passo [j,i] porque o passo [i,j] ja foi salvo */
            if (!G->prop[j][i].mark && \
                ...

128
129
130
131
132
133
134
                ...

                /* Marca a aresta para uso futuro */
                G->prop[i][j].mark = 1;

                ...
                ...

5.7. Compilação e Instalação

O procedimento de compilação deve ser reproduzido para os plugins passo a passo.

  1. Compilação

    Para compilar o plugin de exemplo SelectOdd que está no arquivo selectoddexample.c utilizamos:

      gcc -Wall -fPIC -shared selectoddexample.c -o selectoddexample.so
    
  2. Instalação

    Para instalar copiamos a biblioteca gerada (selectoddexample.so) para o diretório de plugins.

5.8. Execução

Ao abrir o GRAFO o novo plugin estará disposto abaixo do menu Algorithms > Algorithms step by step vide figura 5.11.

(figura 5.11)

Ao clicar no menu Select odd o GRAFO chama a função de algoritmo associado a ele, o algoritmo é executado gravando todos os passos relevantes, e ao término o GRAFO exibe lentamente o resultado (Figura 5.12 até 5.20). Observando-se os passos pode-se ter uma idéia de como o algoritmo Select odd foi construído. Primeiro são destacados todos os vértices ímpares do menor para o maior {1, 3, 5, 7}. E depois todas as arestas entre vértices ímpares do menor vértice para o maior {(1,7), (3,5), (3,7), (5,7)}.

(figura 5.12) (figura 5.13) (figura 5.14)
(figura 5.15) (figura 5.16) (figura 5.17)
(figura 5.18) (figura 5.19) (figura 5.20)

6. Considerações finais

A evolução de um software é um processo contínuo que envolve manutenções corretivas, implementação de novas funcionalidades e documentação. Este capítulo detalha o que foi realizado por este trabalho e expõem algumas idéias na intenção de convidar ao leitor a novas possibilidades de implementações e/ou manutenções no GRAFO.

6.1. O que foi realizado

Durante a confecção deste trabalho foram realizadas algumas manutenções corretivas e a implementação de novas funcionalidades como o passo a passo e este documento que serve como documentação para os trabalhos futuros. Tais implementações serão citadas uma a uma nos itens 6.1.1, 6.1.2 e 6.1.3 para que o leitor possa acompanhar e perceber a dimensão deste trabalho.

6.1.1. Manutenções corretivas

6.1.2. Novas funcionalidades

6.1.3. Documentação

6.2. O que há por vir

Além do que já foi realizado por este trabalho, foram observados outros pontos onde existe a possibilidade de manutenção corretiva e oportunidades de melhorias.

6.2.1. Manutenções Corretivas

6.2.2. Novas funcionalidades

6.3. Software livre

O GRAFO é um software livre sobre a GPL versão 2. Porem ele está restrito ao ambiente da UFPR. Como um software livre qualquer um pode contribuir para o seu desenvolvimento. Encontrar um repositório público e disponibiliza-lo para a comunidade dará longevidade ao software. O Apêndice A detalha como é possível obter os fontes a partir do repositório na UFPR.

6.4. Conclusão

Com este trabalho conseguiu-se cumprir com algumas estapas do processo de evolução do GRAFO. Fazendo-se manutenções corretivas, implementando-se novas funcionalidades e melhorando a documentação. A expectativa é que agora outros venham a cumprir outras etapas no processo, como realizado por Murilo Vicente, Oliver Matias e por mim.

7. Referências Bibliograficas

  1. Bodnar, Jan. The GTK+ tutorial. http://zetcode.com/tutorials/gtktutorial/, Programação com o Toolkit GTK+. Acessado em maio de 2008.

  2. GAGNON, Michel. CI065 - Algoritmos e teoria dos grafos - Notas de Aula - 2001, http://www.inf.ufpr.br/andre/Disciplinas/BSc/CI065/michel/grafos.html. Algoritmos e teoria dos grafos. Acessado em junho de 2008.

  3. SZWARCFITER, Jayme Luiz. Grafos e Algoritmos Computacionais. 1° Edição. Rio de Janeiro: Campus, 1984.

  4. WIKIPEDIA. Graph theory, http://en.wikipedia.org/wiki/Graph_theory. Teoria dos Grafos. Acessado em junho de 2008.

  5. Wheeler, David A. Program Library HOWTO, http://www.dwheeler.com/program-library/Program-Library-HOWTO/index.html. Bibliotecas Dinâmicas. Acessado em abril de 2008.

8. Apêndices

8.1. Apêndice A - Compilando o GRAFO

Esse capitulo tem a intenção de auxiliar a quem vier a fazer uma futura manutenção ou melhoria no GRAFO. Mostra de maneira simplificada a estrutura de diretórios e o conteúdo de cada arquivo e os pacotes de dependência do GRAFO e onde pode-se obter os arquivos fontes.

8.1.1. Obtenção dos Fontes

Os fontes devem ser obtidos através do Subversion do AlgLab para isto deve-se solicitar a inclusão de sua chave pública ao professor André Guedes <andre@inf.upfr.br>.

8.1.2. Pacotes necessários

Os pacotes abaixo relacionados são necessários para a compilação. Em muitos ambientes alguns destes já virão instalados por padrão. Esta lista foi obtida a partir de um Linux Ubuntu 7.10 com a sua instalação padrão.

8.1.3. Compilação, Execução e Instalação

8.1.4. Estrutura e conteúdo de diretórios

A seguir segue a estrutura de diretório e uma breve descrição do conteúdo dos arquivos que compõem o GRAFO.

8.1.5. Descrição e conteúdo dos arquivos

8.2. Apêndice B - Fontes dos plugins de exemplo

8.2.1. Hello Word! - (hw.c)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
/*
 *  grafo - graph editor
 *  Copyright (c) 2003
 *      Murilo Vicente Goncalves da Silva <murilo@pet.inf.ufpr.br>
 *      Oliver Matias van Kaick <oliver@pet.inf.ufpr.br>
 *      Ulisses Cordeiro Pereira <ulisses@cordeiropereira.com.br>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 * 
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *  See the GNU General Public License for more details (file COPYING).
 */ 


/* ******** */
/* * hw.c * */
/* ******** */


/* Plugin example: hello world */

/* C language headers */
#include <stdio.h>
#include <stdlib.h>

/* Here the GRAFO headers */
/* Add plugins information */
#include "../pgin.h"

/* Add graph struct information */
#include "../graph.h"

/* Mandatory function pgin_info */
Pgin *pgin_info(void);

/* algorithm function */
int HelloWorld(Graph *G, char *mess);

/* Others functions */


/* The pgin_info() function should always be present. GRAFO will call
 * it to get the plugin information.
 */
Pgin *pgin_info(void){
Pgin *pgin;

    /* Alocate space for HelloWorld and PGIN_LIST_END */
    pgin = (Pgin *) malloc(2 * sizeof(Pgin));

    /* Includes HelloWorld as the first algorithm of plugin */
    pgin[0].type = PGIN_TEST_ALG;
    pgin[0].label = "Hello World!";
    pgin[0].name = "HelloWorld";
    pgin[0].flags = 0;

    /* It indicates the end of the list of algorithms */
    pgin[1].type = PGIN_LIST_END;
    pgin[1].label = 0;
    pgin[1].name = 0;
    pgin[1].flags = 0;

    return pgin;
}

/* This is the plugin's main function */
int HelloWorld(Graph *G, char *mess){

    sprintf(mess, "Hello World!");

    return 1;
}

/* ******* */
/* * End * */
/* ******* */

8.2.2. Get some parameters - (getsp.c)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
/*
 *  grafo - graph editor
 *  Copyright (c) 2003
 *      Murilo Vicente Goncalves da Silva <murilo@pet.inf.ufpr.br>
 *      Oliver Matias van Kaick <oliver@pet.inf.ufpr.br>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 * 
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *  See the GNU General Public License for more details (file COPYING).
 */


/* *********** */
/* * getsp.c * */
/* *********** */


/* Plugin example: get some input parameters */

#include <stdio.h>
#include <stdlib.h>
/* Here the GRAFO headers */
#include "../pgin.h"
#include "../graph.h"


Pgin *pgin_info(void);
int getsp(Graph *G, char *mess);


Pgin *pgin_info(void){
Pgin *pgin;

    pgin = (Pgin *) malloc(2 * sizeof(Pgin));

    pgin[0].type = PGIN_TEST_ALG;
    pgin[0].label = "Get some parameters";
    pgin[0].name = "getsp";

    pgin[1].type = PGIN_LIST_END;
    pgin[1].label = 0;
    pgin[1].name = 0;

    return pgin;
}


int getsp(Graph *G, char *mess){
int i;
double d;
char *s;

    i = pgin_read_int("Get some parameters", "Give me an int",
                10, 1, 2000000, 1);
    d = pgin_read_double("Get some parameters", "Give me a double",
                0.0, -10.0, 10.0, 0.1, 1);
    s = pgin_read_string("Get some parameters", "Give me a string",
                "I'm a string", 40);

    sprintf(mess, "I got: %d, %f and '%s'. Thanks!", i, d, s);
    free(s);

    return 1;
}


/* ******* */
/* * End * */
/* ******* */

8.2.3. Generate Star Graphs - (stargraphexample.c)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
/*
 *  grafo - graph editor
 *  Copyright (c) 2003-2008
 *      Ulisses Cordeiro Pereira <ulisses@cordeiropereira.com.br>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 * 
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *  See the GNU General Public License for more details (file COPYING).
 */ 


/* ******************* */
/* * stargraphexample.c * */
/* ******************* */

/* Plugin example: Generate a strar graph */

#include <stdio.h>
#include <stdlib.h>

/* Here the GRAFO headers */
/* Add plugins information */
#include "../pgin.h"

/* Add graph struct information */
#include "../graph.h"

/* Prototype functions */
Pgin *pgin_info(void);
int stargraph(Graph *G, char *mess);


/* This function returns the plugin info */
Pgin *pgin_info(void){
Pgin *pgin;

    pgin = (Pgin *) malloc(2 * sizeof(Pgin));

    pgin[0].type = PGIN_TRANSF_ALG;
    pgin[0].label = "Generate Star Graph";
    pgin[0].name = "stargraph";
    pgin[0].flags = PGIN_FLAG_REDRAWWITHCENTEREDVERTEX;

    pgin[1].type = PGIN_LIST_END;
    pgin[1].label = 0;
    pgin[1].name = 0;
    pgin[1].flags = 0;

    return pgin;
}

/* This is the plugin's main function */
int stargraph(Graph *G, char *mess){
int i, n;

    /* Get number of vertices */
    n = pgin_read_int("Generate Star Graph", "Number of vertices",
                5, 1, 2000000, 1);

    /* Generate graph */
    InitGraph(G, G->type);

    /* Adds N vertices in the position (0,0) */
    for (i = 0; i < n; i++)
        AddPoint(G, 0, 0);

    /* Adds N edges starting at the vertex 0 to N-1 */
    for (i = 1; i < n; i++) { 
        AddEdge(G, 0, i);
    }

    return 1;
}

/* ******* */
/* * End * */
/* ******* */

8.2.4. Highest Degree - (vertexexample.c)

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
/*
 *  grafo - graph editor
 *  Copyright (c) 2003-2008
 *      Murilo Vicente Goncalves da Silva <murilo@pet.inf.ufpr.br>
 *      Oliver Matias van Kaick <oliver@pet.inf.ufpr.br>
 *      Ulisses Cordeiro Pereira <ulisses@cordeiropereira.com.brr>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 * 
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *  See the GNU General Public License for more details (file COPYING).
 */ 


/* ******************* */
/* * vertexexample.c * */
/* ******************* */

/* Plugin example: This program does not compute anything useful.
 * It is an example of how to use the "special vertex" list. 
 * The vertices in this list will be highlighted in the GRAFO 
 * interface.
 */ 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Here the GRAFO headers */
#include "../pgin.h"
#include "../graph.h"
#include "../list.h"

/* You have to fill the pgin struct with information about your plugins.
 * Each position of the pgin struct is related with some function you
 * have programed. Below one example where you programmed five functions:
 * 
 * Pgin pgin[6] = {
 *     { PGIN_RESULT_ALG, "Find a Hamilton Path", "HPath", 0 },
 *     { PGIN_TEST_ALG, "Test Planarity", "PlanarGraph", 0 },
 *     { PGIN_TEST_ALG, "Test Bergeness", "BergeGraph", 0 },
 *     { PGIN_TRANSF, "Compute the complement", "Compl", PGIN_FLAG_NOREDRAW },
 *     { PGIN_TRANSF, "Line Graph", "LineGraph", 0 },
 *     { PGIN_LIST_END, NULL, NULL, 0 },
 * };
 *
 * In the last position you should put { PGIN_LIST_END, NULL, NULL }, to
 * end the list of plugins.
 * You have to put four pieces of information in the pgin struct:
 * -> The first is the class of your algorithm. The first entry
 * above is a Result Algorithm, so you have to put PGIN_RESULT_ALG
 * -> The second (in this case "Highest Degree") is the name that will 
 * appear in the menu of GRAFO. 
 * -> The third is the name of the function in the code (in this 
 * case "MaxDegree").
 * -> The fourth is a set of plugin flags. In the example of the 
 * fouth funtion the flag prevents that GRAFO redraws the resulting graph.
 * If you do not know what is a "plugin flag", only put 0 in this field.
 */


/* Plugin Information */
Pgin pgin[2] = {
    { PGIN_RESULT_ALG, "Highest Degree", "MaxDegree" },
    { PGIN_LIST_END, NULL, NULL },
};



/* The pgin_info() function should always be present. GRAFO will call
 * it to get the plugin information.
 */
Pgin *pgin_info(void);

Pgin *pgin_info(void){

    return pgin;
}

/* Plugin example: This program does not compute anything useful.
 * It is an example of how to use the "special vertex" list. 
 * Here this list have the name verts. The vertices in this list will 
 * be highlighted in the GRAFO interface.

 * In this example, the function finds the vertex with the highest 
 * degree (acctualy one of them) and put it in the verts list. */

int MaxDegree(Graph *G, char *mess, List *arc_edges, List *verts);

int MaxDegree(Graph *G, char *mess, List *arc_edges, List *verts){
Node N;
int i,maxdeg;

    /* Test if graph is empty */
    if (G->size < 1) {
        sprintf(mess, "%s", "Empty graph!");
        return 1;
    }

    /* Find the vertex with max degree */
    maxdeg = 0;
    for (i = 1; i < G->size; i++) {
        if (G->vertex[i].degree > G->vertex[maxdeg].degree) {
            maxdeg = i;
        }
    }

    /* Place maxdeg in the Node */
    N = MakeNode(&maxdeg, sizeof(int));

    /* Place the node in the list of "special vertex" */
    InsertNode(verts, N);

    return 1;
}


/* ******* */
/* * End * */
/* ******* */

8.2.5. Some Edge - (edgeexample.c)

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/*
 *  grafo - graph editor
 *  Copyright (c) 2003-2008
 *      Murilo Vicente Goncalves da Silva <murilo@pet.inf.ufpr.br>
 *      Oliver Matias van Kaick <oliver@pet.inf.ufpr.br>
 *      Ulisses Cordeiro Pereira <ulisses@cordeiropereira.com.br>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 * 
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *  See the GNU General Public License for more details (file COPYING).
 */ 


/* ***************** */
/* * edgeexample.c * */
/* ***************** */

/* Plugin example: This program does not compute anything useful.
 * It is an example of how to use the "special edge" list. 
 * The edges in this list will be highlighted in the GRAFO 
 * interface.
 *
 */ 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Here the GRAFO headers */
#include "../pgin.h"
#include "../graph.h"
#include "../list.h"


/* You have to fill the pgin struct with information about your plugins.
 * Each position of the pgin struct is related with some function you
 * have programed. Below one example where you programmed five functions:
 *
 * Pgin pgin[6] = {
 *     { PGIN_RESULT_ALG, "Find a Hamilton Path", "HPath", 0 },
 *     { PGIN_TEST_ALG, "Test Planarity", "PlanarGraph", 0 },
 *     { PGIN_TEST_ALG, "Test Bergeness", "BergeGraph", 0 },
 *     { PGIN_TRANSF, "Compute the complement", "Compl", PGIN_FLAG_NOREDRAW },
 *     { PGIN_TRANSF, "Line Graph", "LineGraph", 0 },
 *     { PGIN_LIST_END, NULL, NULL, 0 },
 * };
 *
 * In the last position you should put { PGIN_LIST_END, NULL, NULL }, to
 * end the list of plugins.
 * You have to put four pieces of information in the pgin struct:
 * -> The first is the class of your algorithm. The first entry
 * above is a Result Algorithm, so you have to put PGIN_RESULT_ALG
 * -> The second (in this case "Some Edge") is the name that will 
 * appear in the menu of GRAFO. 
 * -> The third is the name of the function in the code.
 * -> The fourth is a set of plugin flags. In the example of the 
 * fouth funtion the flag prevents that GRAFO redraws the resulting graph.
 */


/* Plugin Information */
Pgin pgin[2] = {
    { PGIN_RESULT_ALG, "Some Edge", "MaxMinEdge",0 },
    { PGIN_LIST_END, NULL, NULL, 0 },
};


/* The pgin_info() function should always be present. GRAFO will call
 * it to get the plugin information.
 */
Pgin *pgin_info(void);

Pgin *pgin_info(void){

    return pgin;
}


/* The plugin example: It is an example of how to use the "special edge" list.
 * Here the list have the name arc_edges. The edges in this list will 
 * be highlighted in the GRAFO interface.
 * 
 * The following edge will be put in the list: 
 * Let the egde be called E. We will define it now: Let v be one vertex of the 
 * graph such that no other vertex has degree greater than v. Let 
 * u be the vertex adjacent to v with the lowest degree. The
 * edge E links u to v. */

int MaxMinEdge(Graph *G, char *mess, List *arc_edges, List *verts);

int MaxMinEdge(Graph *G, char *mess, List *arc_edges, List *verts){
SEdge E; /* Single Edge */
Node N;
int i,maxdeg,mindeg;

    /* Test if graph is empty */
    if (G->size < 1) {
        sprintf(mess, "%s", "Empty graph!");
        return 1;
    }

    /* Find the vertex with max degree */
    maxdeg = 0;
    for (i = 1; i < G->size; i++) {
        if (G->vertex[i].degree > G->vertex[maxdeg].degree) {
            maxdeg = i;
        }
    }

    /* Find the vertex with min degree adjacent with max degree */
    mindeg = -1;
    for (i = 0; i < G->size; i++) {
        if (G->edge[maxdeg][i]) {
            if (mindeg == -1) {
                mindeg = i;
            } else if (G->vertex[i].degree < G->vertex[mindeg].degree) {
                mindeg = i;
            }
        }
    }

    /* Assign maxdeg and mindeg in a single edge */
    E.u = maxdeg;
    E.v = mindeg;

    /* Place the "single edge" in the Node */
    N = MakeNode(&E, sizeof(SEdge));

    /* Place the node in the list of "special edges" */
    InsertNode(arc_edges, N);

    return 1;
}


/* ******* */
/* * End * */
/* ******* */

8.2.6. Select odd - (selectoddexample.c)

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
/*
 *  grafo - graph editor
 *  Copyright (c) 2008
 *      Ulisses Cordeiro Pereira <ulisses@cordeiropereira.com.br>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 * 
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *  See the GNU General Public License for more details (file COPYING).
 */ 


/* ********************** */
/* * selectoddexample.c * */
/* ********************** */

/* Plugin example: This program does not compute anything useful.
 * It is an example of how to use the "step by step" structure. 
 * The odd vertex and edges between odd vertex will be highlighted in the GRAFO 
 * interface.
 *
 */ 

/* Plugin example: Select odd */

/* C language headers */
#include <stdio.h>
#include <stdlib.h>

/* Here the GRAFO headers */
/* Add plugins information */
#include "../pgin.h"

/* Add graph struct information */
#include "../graph.h"

/* Add step by step struct information */
#include "../step.h"

/* Mandatory function pgin_info */
Pgin *pgin_info(void);

/* algorithm function */
int SelectOdd(Graph *G, char *mess, int indx, List *arc_edges, List *verts);

/* Others functions */


/* The pgin_info() function should always be present. GRAFO will call
 * it to get the plugin information.
 */
Pgin *pgin_info(void){
Pgin *pgin;

    /* Alocate space for SelectOdd and PGIN_LIST_END */
    pgin = (Pgin *) malloc(2 * sizeof(Pgin));

    /* Includes SelectOdd as the first algorithm of plugin */    
    pgin[0].type = PGIN_STEP_ALG;
    pgin[0].label = "Select odd";
    pgin[0].name = "SelectOdd";
    pgin[0].flags = 0;

    /* It indicates the end of the list of algorithms */
    pgin[1].type = PGIN_LIST_END;
    pgin[1].label = 0;
    pgin[1].name = 0;
    pgin[1].flags = 0;

    return pgin;
}

/* This is the plugin's main function */
int SelectOdd(Graph *G, char *mess, int indx, List *arc_edges, List *verts) {
SEdge E; /* Single Edge */
Node N;
int i, j,oddvertex;

    /* Test if graph is empty */
    if (G->size < 1) {
        sprintf(mess, "%s", "Empty graph!");
        return 1;
    }

    /* Set to False (0) the property 'mark' in all vertices */
    ClearMarkedVerts(G);

    /* Add first step - No highlights */
    AddStep(G, arc_edges, verts);

    /* Find and mark oddvertex */
    oddvertex = 0;
    for (i = 1; i < G->size; i++) {

        /* Check if i is a odd number */
        if ((i % 2)) {
            /* Mark the vertex for future use */
            G->vertex[i].mark = 1;
            oddvertex = i;

            /* Place oddvertex in the Node */
            N = MakeNode(&oddvertex, sizeof(int));

            /* Place the node in the list of "special vertex" */
            InsertNode(verts, N);

            /* Add new step - Save highlight vertex */
            AddStep(G, arc_edges, verts);
        }
    }

    /* Set to False (0) the property 'mark' in all vertices */
    ClearMarkedEdges(G);

    /* Find the odd vertex adjacent with other odd vertex */
    for (i = 0; i < G->size; i++) {
        for (j = 0; j < G->size; j++) {

                /* Avoid saving the step [j,i] because [i,j] have been saved */
            if (!G->prop[j][i].mark && \
                /* True if vertex[i] is adjacent vertex[j] */
                G->edge[i][j] && \
                /* True if vertex[i] is a odd vertex */
                G->vertex[i].mark && \
                /* True if vertex[j] is a odd vertex */
                G->vertex[j].mark) {

                /* Mark the edge for future use */
                G->prop[i][j].mark = 1;

                /* Assign odd vertex adjacent with other odd vertex in a single edge */
                E.u = i;
                E.v = j;

                /* Place the "single edge" in the Node */
                N = MakeNode(&E, sizeof(SEdge));

                /* Place the node in the list of "special edges" */
                InsertNode(arc_edges, N);

                /* Add new step - Save highlight edge */
                AddStep(G, arc_edges, verts);
            }
        }
    }

    return 1;
}


/* ******* */
/* * End * */
/* ******* */