Escolar Documentos
Profissional Documentos
Cultura Documentos
PROGRAMA DE PÓS-GRADUAÇÃO EM
ENGENHARIA ELÉTRICA
http://member.acm.org/∼fabiogaluppo
São Paulo
2013
AGRADECIMENTOS
Desejo agradecer minha famı́lia pelo apoio dado até o momento: Anna Maria Razzo
Galuppo (mãe), Fernando Razzo Galuppo (irmão) e Janete Teodoro Leite (esposa). Em
especial, a Francisco Galuppo (pai, in memoriam), por ter me incentivado e inspirado no
belo caminho da Computação e da Matemática.
Aos meus amigos, Luis Fábio Mandina Pereira - simplesmente por ser um segundo
irmão e amigo de longa data, e Rogério Wagner - por ser outro grande amigo e ter me
incentivado a procurar um programa de Mestrado em Ciência da Computação. Gostaria
de estender estes agradecimentos aos meus amigos e colegas do Mestrado da UPM, dos
grupos de usuários (em especial, do C/C++ Brasil) e da BM&F Bovespa, seria uma lista
extensa se eu colocasse o nome de todos eles, porém o mais importante é que eles sabe
quem são.
Esta obra tem como essência a aplicação das técnicas denominadas coletivamente de me-
taheurı́stica paralela no contexto do Problema do Caixeiro Viajante (PCV), um dos pro-
blemas de otimização combinatória mais importantes. A abordagem desta obra contém
uma proposta composicional que permite a criação de pipelines para endereçar o problema.
Estas técnicas extraı́das da Computação Paralela associadas aos algoritmos de busca da
Inteligência Artificial possibilitam grandes oportunidades para a exploração do espaço
de estados do problema em questão. Usando as combinações propostas, boas soluções
ou, até mesmo ótimas soluções, emergirão dentro de um tempo de processamento sa-
tisfatório, possibilitando suas aplicações na resolução de problemas reais semelhantes. É
fundamental revisitar as soluções existentes e fornecer para a indústria as melhores opções
para resolução do PCV utilizando as capacidades computacionais contemporâneas e as
variedades de equipamentos disponı́veis. Nesta obra, estão incluı́dos a implementação, a
análise e a medição de algoritmos aplicados ao contexto referenciado.
This work has as its essence the application of techniques collectively called parallel me-
taheuristic in the context of a Travelling Salesman Problem (TSP), one of the most
important problems in combinatorial optimization. The approach of this work contains
a compositional proposal that allows the creation of pipelines to address the problem.
These techniques extracted from the Parallel Computing associated with the search algo-
rithms of Artificial Intelligence allow great opportunities for exploring the state space of
the problem in question. Using the proposed combinations, good solutions or even opti-
mal solutions will emerge within a satisfactory processing time, allowing its application in
real-world problems. It is essential to revisit the existing solutions and provide the best
alternatives for the industry to solve the TSP using contemporary computing capabilities
and varieties of available equipments. In this work, are included the implementation,
analysis and measurement algorithms applied to the referenced context.
6 SOLUÇÕES PROPOSTAS 43
6.1 Resolução Metaheurı́stica por Simulated Annealing (SA) e 2-OPT com
Computação Paralela . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
6.2 Resolução Metaheurı́stica por Algoritmo Genético (GA) e 2-OPT com
Computação Paralela . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
6.3 Resolução Metaheurı́stica por Otimização por Colônia de Formigas (ACO)
e 2-OPT com Computação Paralela . . . . . . . . . . . . . . . . . . . . . . 48
6.4 Considerações sobre o Modelo Composicional . . . . . . . . . . . . . . . . . 49
7 RESULTADOS OBTIDOS 51
7.1 Resultados obtidos com o Pipeline 1 (SA) . . . . . . . . . . . . . . . . . . 51
7.2 Comportamento monotonicamente decrescente . . . . . . . . . . . . . . . . 57
7.3 Resultados obtidos em uma distribuição aleatória com 250 cidades . . . . . 59
7.4 Resultados obtidos com o Pipeline 2 (GA) . . . . . . . . . . . . . . . . . . 62
7.5 Resultados obtidos com o Pipeline 3 (ACO) . . . . . . . . . . . . . . . . . 65
REFERÊNCIAS BIBLIOGRÁFICAS 76
ANEXOS 77
1 INTRODUÇÃO
Apesar da compreensão do PCV ser simples, ele é um dos problemas mais comple-
xos (GAREY, 1979a) e intesivamente investigados em Matemática Computacional. Sua
simplicidade e intratabilidade tornam o PCV um modelo ideal para o desenvolvimento
1
de idéias e técnicas para a investigação de problemas computacionais em geral (APPLE-
GATE, 2007).
Uma outra abordagem, que não é o foco principal desta obra, é a busca das soluções
ótimas do PCV (TSP@GATECH, 2007). No entanto, estas soluções podem demorar anos
para serem encontradas.
2
1.4 Proposta de Pesquisa
A proposta de pesquisa desta obra está alinhada com os objetivos descritos na próxima
seção. Ela inclui a implementação, a análise e a medição dos algoritmos relacionados a
seguir: Simulated Annealing (SA), Algoritmos Genético (AG), Otimização por Colônia
de Formigas (ACO) e Otimização por Busca Local (OBL).
Os objetivos desta obra são estabelecer conexões entre as técnicas de busca da Inte-
ligência Artificial que utilizam metaheurı́stica e a aplicação dos recursos e das abstrações
oferecidas através da Computação Paralela. Bem como, analisar e medir o comportamento
destes algoritmos isolados ou na forma de composição utilizando diversas configurações de
processamento. O objetivo central é implementar os algoritmos selecionados e aplicá-los
ao Problema do Caixeiro Viajante de acordo com os detalhes apresentados nesta obra.
3
1.6 Metodologia
As análises e representações dos dados produzidos foram feitos através das ferramentas
Wolfram Mathematica e/ou Microsoft Excel. Dentre os recursos de computação paralela
não distribuı́da, foram utilizados uma combinação de threads na CPU e as extensões de
processamento vetorial existentes nos processadores modernos. Logo, o principal objetivo
foi extrair o máximo e medir o comportamento dos recursos computacionais presentes
nestes equipamentos multicores (ASANOVIC, 2009) para entender o comportamento re-
lacionado a exploração do espaço de estados do problema em questão.
Na coleta de dados foram utilizados marcadores e pontos bem definidos que permiti-
ram a verificação de desempenho de um determinado algoritmo em relação ao tempo de
processamento e/ou a qualidade do resultado(s) gerado(s). Alguns dos algoritmos selecio-
nados foram executados e medidos em um trabalho conjunto através de algum modelo de
composição, como por exemplo, em uma cadeia de execução (pipeline). Em alguns casos,
4
somente um pseudocódigo possuem as informações relativas ao contexto do problema ou
a um eventual esclarecimento.
Os dados que foram utilizados para os testes com o PCV simétrico e euclidiano bidi-
mensional foram obtidos: a) aleatoriamente através de geradores de números randômicos
ou b) de fontes já existentes, tais como, TSPLIB (REINELT, 1991a) ou TSP Test Data
(TSP@GATECH, 2009).
Para execução dos testes e suas respectivas análises foram utilizados os recursos com-
putacionais de acordo com as especificações indicadas na figura 1. Todos os equipamentos
são de propriedade do autor:
Foram reportados os principais procedimentos dos testes. Isso foi obtido através dos
indicadores, tais como: gráficos contextuais, tabelas e grafos denotando os ciclos encon-
trados. Todos os códigos fontes produzidos e utilizados estão relacionados e encontram-se
na seção de anexos deste trabalho.
5
1.7 Próximos Capı́tulos
6
2 O PROBLEMA DO CAIXEIRO VIAJANTE
7
Figura 3: Grafo não-direcionado com cinco vértices e seus respectivos pesos.
A origem do PCV remete a um jogo inventado em 1857 por Sir William Rowan
Hamiltom, criador da matemática dos quaternions, o Jogo Icosiano (APPLEGATE, 2007).
Este jogo tinha como objetivo encontrar um ciclo através de 20 vértices distribuidos
em quatro pentágonos concêntricos, onde cada vértice continha três adjacentes (algumas
destas conexões ligando um pentágono mais externo a outro mais interno). No plano
tridimensional, a figura geométrica do jogo Icosiano é um dodecaedro. Em outro momento,
o tipo de solução oferecida pelo desafio do jogo fora denominada de ciclo hamiltoniano,
em homenagem ao seu criador. No entanto, somente no ano de 1930, o problema se
caracterizou como PCV por Merrill Flood da Universidade de Princeton e da RAND
Corporation. E seu desafio continua até os dias atuais. Sendo assim, o modelo abstrato
do PCV é de um problema de otimização combinatória relacionado a determinação de um
ciclo hamiltoniano em um grafo qualquer (direcionado ou não), cujo objetivo é encontrar
um ciclo de peso (custo ou comprimento) mı́nimo, ou seja, um problema de minimização
(APPLEGATE, 2007).
É possı́vel representar uma das soluções ou um dos ciclos de uma instância do problema
PCV, utilizando subgrafos, matrizes de adjacência, listas de adjacência ou até mesmo ca-
minhos de uma estrutura de dados do tipo árvore, onde o nó final contém intrı́nsecamente
uma referência ao nó inicial. Uma vez que resultados variados são derivados da confi-
8
guração de um PCV, este resultado, ou seja, o ciclo estabelecido como solução, também
pode ser denominado como uma instância da solução do PCV proposto.
9
As restrições do problema indicadas na figura 4 em (1) e (2) determinam que cada nó
seja visitado uma única vez e a restrição (3) impede que ocorra a formação de sub-rotas.
10
Figura 6: Resolução do PCV através de força bruta.
11
Figura 7: Valores de referência para exemplo do PCV através de força bruta.
No entanto, a pergunta a ser respondida é: Quantos ciclos precisariam ser verificados
para resolver este problema para N cidades (ou vértices)?
12
figura 8). Isto é, através da teoria da complexidade computacional, significa que ele é um
problema decidı́vel e classificado como polinomial não-determinı́stico (NP) da classe NP-
Completo ou NP-Difı́cil, de acordo com as métricas utilizadas (GAREY, 1979b). Neste
caso, dependendo do poder computacional, é possı́vel resolver por força bruta instâncias
do problema com máximo entre 20 a 30 cidades.
13
que um novo assinante apareça, se este for auxiliado por um algortimo para determinar
suas visitas, este algoritmo deve ser eficiente e adaptativo, ou seja, fornecer um boa rota
dentro de um perı́odo aceitável de tempo.
Através do uso de heurı́sticas, não há garantias, mas uma solução tende a convergir
para um bom resultado com complexidade de tempo polinomial (P). No caso do PCV, uma
heurı́stica aceitável é do vizinho mais próximo. Ela é uma técnica de algoritmo guloso,
onde a partir de uma determinada cidade, a próxima será a cidade não visitada com menor
distância entre elas. Este tipo de abordagem possui complexidade algoritimica de O(N2 ).
É uma solução eficiente, embora, assim como o Hill Climbling (RUSSELL, 2009), ela pode
ficar presa no mı́nimo local e seu sucesso depende muito da forma do espaço de estados
associado. Para superar este aspecto do algoritmo, pode ser utilizada uma heurı́stica
de troca de vizinhos, onde usualmente é aplicado algum comportamento aleatório para
determinar quais os vizinhos serão trocados. Neste caso, é imprático manter todos as
instâncias previamente encontradas, o que corre no risco destas instâncias serem visitadas
novamente, portanto o espaço de busca voltará a ser Γ(N ). Isto também é válido para os
casos assimétricos do PCV.
14
com metaheurı́sticas são basicamente técnicas inteligentes de busca, onde algumas delas
são baseadas em sistemas adaptativos naturais. Para alguns problemas de otimização
combinatória, como no caso do PCV, é possı́vel resolvê-los de uma maneira menos que
perfeita, porém com um considerável valor prático ou aplicado. Sendo, os tipos de al-
goritmos implementados para este propósito chamados de algoritmos de aproximação -
comuns em soluções IA que utilizam metaheurı́stica. Eles estão baseados no fato de que
em muitos casos uma solução pouco menos que ótima, dentro de uma escala de tempo
satisfatória, é melhor que nenhuma solução (HAREL, 2012b).
15
3 RESOLUÇÃO DE SISTEMAS COMPLEXOS
16
A seguir são apresentadas algumas tarefas que representam operações de ordem cres-
cente descritas anteriormente (Figura 11). Elas estão em formas de funções acumuladoras,
codificadas na linguagem de programação F# (FSHARP, 2013).
17
Obtendo a classificação com relação a sua ordem de crescimento, é possı́vel estimar
qual o comportamento e o tempo de processamento de um determinado algoritmo se o
número de elementos computáveis crescer. Ou seja, o objetivo é saber as caracteristicas
do algoritmo com base numa determinada medida de eficiência (na maioria dos casos, o
tempo de processamento - velocidade) e em quanto tempo um resultado (correto) será
produzido. No entanto, há alguns problemas que não possuem uma solução eficiente
conhecida, tais problemas são denominados NP-completo (CORMEN, 2009). Com isto,
uma hierarquia de complexidade emerge.
18
3.1 Resolução Metaheurı́stica por Simulated Annealing (SA)
19
nal, depende primariamente da qualidade do gerador de números randômicos, ao qual tem
uma influência positiva ou negativa sobre os resultados da solução (KLIMASAUSKAS,
2002). Benoı̂t Mandelbrot, criador da matemática dos fractais, associa a qualidade de
aleatoriedade com um coeficiente, denominado de coeficiente de Hurst (H). O H indica
um ı́ndice de dependência relativo a uma série de valores no decorrer do tempo (série tem-
poral). Se o H estiver entre maior que 0.5 e 1, significa que existe um alta probalidade de
um número alto (ou baixo) ser seguido por outro número de mesma caracterı́stica (com-
portamento persistente). Se o valor estiver entre 0 e menor que 0.5 significa que existe
um alta probabilidade de um alternação entre os número da série, se o número atual é
um valor alto, o próximo será baixo, ou vice e versa (comportamento anti-persistente).
No entanto, se H for igual a 0.5, o comportamento da sequência é incerta, portanto im-
previsı́vel (MANDELBROT, 2004) - o que é muito bom para a caracterı́stica exploratória
da solução com SA.
20
A função SIMULATED-ANNEALING apresenta em pseudocódigo o método do SA
descrito anteriormente:
21
3.2 Resolução Metaheurı́stica por Algoritmo Genético (GA)
A avaliação de um resultado superior é feita por uma função de aptidão (ou de fitness)
ou função de recompensa. No caso do PCV, a função objetivo do problema é baseada no
tipo de problema a ser investigado, por exemplo, em sua versão simétrica e bidimensional,
o valor a ser medido pode ser a distância euclidiana. Esta função de fitness poderá
indicar mais do que se o problema foi resolvido ou não, ela servirá também para avaliar
qual a proximidade de uma solução ideal, orientando no processo de seleção e geração de
22
populações com soluções candidatas ao PCV.
A operação de seleção é responsável pela escolha dos indivı́duos (ou das soluções
candidatas do PCV) que formarão a próxima população.
2. A seleção das duas melhores soluções candidatas (com menor ciclo) na população.
Elas serão os pais, onde serão recombinado para gerar duas novas soluções candidatas
ou dois novos filhos. Esses filhos poderão, na maioria das vezes, serem melhores que
os pais;
23
sultados inferiores (com maior ciclo).
24
3.3 Resolução Metaheurı́stica por Otimização por Colônia de
Formigas (ACO)
O algoritmo do ACO pode ser aplicado como heurı́stica por uma grande quantidade de
problemas (DORIGO, 2006)(BLUM, 2005), principalmente aqueles do tipo que possuem
uma estrutura naturalmente modelada como um grafo. A primeira aplicação do ACO foi
com o PCV, em sua forma original denominada de Ant System (AS) (DORIGO, 1996).
25
Quando as formigas completam um ciclo, a função de fitness é avaliada e o nı́vel de
feromônio do grafo é atualizado. Ao passar do tempo, as melhores arestas do grafo, que
determinarão um ciclo mı́nimo possuirão um nı́vel de feromônio maior, portanto existerá
a convergência, ou seja o maior número de formigas percorrendo o mesmo circuito.
Existem duas ações atuando sob o nı́vel de feromônio depositado no grafo são elas:
a intesificação e a evaporação. As ações de intensificação e evaporação são regidas pelas
seguintes equações:
26
Outra equação que faz parte do ACO é a de probabilidade para a seleção de caminho,
onde o objetivo é definir qual será a próxima cidade (ou vértice) visitada. Ela é obtida
através da relação a seguir:
27
3.4 Resolução Heurı́stica por Busca Local 2-OPT
A heurı́stica de busca local 2-Opt para resolução do PCV (CROES, 1958) serve para
ajustar um circuito de uma instância do problema. Esta heurı́stica busca o melhor resul-
tado local, eliminando os cruzamentos entre as arestas. Percorrendo todos os pares das
arestas não adjacentes e alterando suas conexões é possı́vel alcançar o mı́nimo local do
circuito, conforme descrito nos passos do algoritmo em pseudocódigo a seguir:
28
4 DESEMPENHO E ALGORITMOS PARALELOS
“As soon as an Analytic Engine exists, it will necessarily guide the future
course of the science. Whenever any result is sought by its aid, the question
will arise - By what course of calculation can these results be arrived at by the
machine in the shortest time? (BABBAGE, 1864)”
Segundo David Harel, no livro Algorithmics, paralelismo tem se tornado cada vez mais
crucial, em grande parte por causa da tendência da construção destes novos hardwares
(processadores com capacidade de computação paralela). Onde computadores com quatro
29
núcleos são comuns hoje em dia. Para tomar vantagem destes tipos de processadores,
novos algoritmos e técnicas de programação são necessárias. Uma das técnicas populares
é a map-reduce, inspirada pela programação funcional (HAREL, 2012a). Onde o objetivo
é dividir, conquistar e muitas vezes consolidar, isto é também conhecido como fork-join
ou divide-conquer. Por exemplo, o MERGE-SORT (CORMEN, 2009), é estruturado
adequadamente para a aplicação desta técnica:
Figura 19: Pseudocódigo do MERGE-SORT, algoritmo criado por von Neumann, e adap-
tado de Cormen (CORMEN, 2009).
30
Portanto, seu objetivo é a composição destes algoritmos com técnicas de computação pa-
ralela para reduzir o tempo de processamento e utilizar os diversos tipos de processadores
(CPUs e/ou GPUs) no máximo de suas capacidades.
Ao explorar o espaço de estados através buscas com SA, existem duas possı́veis abor-
dagens de busca com metaheurı́stica paralela: independente, onde cada entidade paralela
executa sua computação e procedimentos, ao final a melhor solução é selecionada; ou
cooperativa, onde etapas do algoritmo são separadas em fases e atuam em cadeia, as enti-
dades paralelas deste modelo trocam informações durante o processamento para selecionar
a melhor solução encontrada (CZECH, 2010). As buscas, independente e cooperativa, são
modelos aplicativos dos padrões de programação paralela Divide and Conquer e Pipeline
respectivamente. Estes padrões são descritos no capı́tulo 4 do Patterns for Parallel Pro-
gramming (MATTSON, 2004) ou em catálogos de padrões como o mantido pelo grupo do
Parallel Computing Laboratory da UC Berkeley (PARLAB@BERKELEY, 2010).
Uma variação do padrão Divide and Conquer é o Fork/Join, ele consiste no pro-
cesso de espalhar (dividir) uma tarefa em diversos segmentos paralelos para resolução do
problema (conquistar). Ao final, estas entidades paralelas já completadas são sincroni-
zadas. Com o MERGE-SORT, a última etapa é a execução do último MERGE e por
consequência a ordenação completa do vetor. Já no SA em paralelo com busca indepen-
dente, a última etapa é seleção da melhor solução encontrada no momento. Portanto,
ambos compartilham o mesmo tipo de abstração paralela para alcançar um desempenho
superior.
31
Outro modelo que está presente nos computadores atuais e deve ser considerado, é o
processamento vetorial. Este tipo de processamento está presente nos processadores con-
vencionais e processadores paralelos massivos, tais como, aceleradoras gráficas discretas
ou Graphical Processing Units (GPUs). A computação processada por este tipo de dis-
positivo é classificada através da taxonomia de Flynn como Single Instruction, Multiple
Data (SIMD) ou Multiple Instruction, Multiple Data (MIMD) (AKHTER, 2006).
O objetivo desta obra é abordar o PCV por meio da composição dos algoritmos de
busca da Inteligência Artificial, da aplicação de paralelismo e da utilização de recursos
computacionais de alto-desempenho. Mapeando quais são as vantagens, ganhos e desafios
com relação a construção de algoritmos sequenciais. As abordagens aqui apresentadas per-
mitirão serem adaptadas ou servirem de base para resolução de outros tipos de problemas
intratáveis.
32
Figura 20: Exemplo de paralelismo em C++ com a API do OpenMP 3.0 retirado do
padrão (OPENMP, 2008).
33
No ISO C++ 11 (ISOCPP, 2011), a linguagem de programação adotada na imple-
mentação desta obra, é permitido um ajuste mais customizável e moderno na expressão
do paralelismo e da sincronização, isto é feito com uma combinação entre std::vector,
std::async e std::future, como ilustrado no fragmento a seguir:
34
5 MODELO COMPOSICIONAL PARA RESOLUÇÃO
DO PCV
Como descrito nos capı́tulos 3 e 4 sobre as técnicas selecionadas nesta obra relativas
a resolução de sistemas complexos e aos padrões de computação paralela. Aqui será
apresentado o modelo proposto de resolução do PCV através de composição. A figura 23
denota de forma geral a idéia composicional proposta para abordagem do problema:
35
(PCV) e produzir um contradomı́nio (PCV). Em uma categoria esse tipo de morfismo re-
cebe o nome de endomorfismo. Esse endomorfismo poderá ser concretizado, por exemplo,
através da aplicação de uma função representando um algoritmo de SA. Ela receberá uma
instância do PCV com uma determinada configuração e produzirá um objeto destino, de
preferência, igual ou melhor ao objeto de origem.
A seguir a notação usada para os objetos e o(s) morfismo(s). Neste caso, uma operação
contendo objeto de origem, morfismo e objeto de destino:
O tipo paramétrico Monad em Haskell possui uma interface contendo três membros
são eles: um construtor de tipo, uma operação para binding e uma função de unidade. O
construtor de tipo serve para obter ou instanciar o tipo monádico. A função de unidade
mapeia um valor simples para um valor do tipo monádico correspondente, no caso do PCV,
o que é deseja é um tipo PCV monádico, portanto uma estrutura de dados do tipo PCV
sofre uma aplicação de uma função de unidade para ser transformado em um tipo PCV
36
monádico. A operação de binding é responsável por mapear um valor monádico em outro,
onde poderá possuir o mesmo tipo do objeto de origem. Na figura 26 é apresentada a
classe Monad do Haskell e seus membros (HUGHES, 1998). É possı́vel interpretá-la como
uma abstração que encapsula um tipo e sua computação:
Para um tipo ser qualificado como monad torna-se essencial que três axiomas sejam
satisfeitos: o axioma da associatividade, o axioma da identidade à esquerda ou aplicação
da função de unidade à esquerda e o axioma da identidade à direita ou aplicação da função
de unidade à direita. Estes axiomas são conhecidos como as leis da monad (WADLER,
1995) e estão formalizados na notação do cálculo lambda (λ calculus) como segue:
37
como por exemplo IO Monad que sabe lidar com computações que envolvem operações
E/S ou Error Monad que sabe lidar com computações que envolvem operações as quais po-
dem falhar ou disparar uma exceção. O conceito de monad em linguagens de programação
não é mais exclusivo da linguagem Haskell (MICROSOFT, 2013a)(MICROSOFT, 2013b)(SCALA-
LANG.ORG, 2013), estando presente cada vez mais em outras linguagens ou capacitadas
de ser reproduzidas, desde que existam construções fundamentais disponı́veis, como por
exemplo, high-order functions. Para esta obra foi concebido a TSP Monad, um tipo que
sabe lidar com o PCV de forma composicional. Seus principais membros, implementados
na linguagem de programação C++, são apresentados a seguir:
38
A TSP Monad proposta na figura 28 fornece um construtor de tipo, uma função
de unidade a partir da função ret e uma operação de binding a partir da função bnd.
Para evitar uma sintaxe convoluta, o método map foi adicionado - esta abordagem é
semelhante a construção da função flatMap da linguagem Scala (SCALA-LANG.ORG,
2013). Para fazer parte da categoria das monads é fundamental esse tipo obedecer as
três leis referenciadas na figura 27. As provas relativas as leis citadas são apresentadas
a seguir. Elas são apresentadas em duas versões, uma utilizando um notação funcional e
outra uma notação orientada a objetos:
39
Figura 31: TSP Monad e a terceira lei.
Portanto, conforme demonstrado, a TSP Monad (figura 28) é uma autêntica monad !
O método map ou a função bnd da TSP Monad são os pontos de entrada para os
morfismos, ou seja, são membros que recebem funções transformadoras - elas manipulam
uma instância da estrutura TSP e geram um tipo monádico TSP. Por exemplo, a cons-
trução de um pipeline simples contendo o encadeamento do Simulated Annealing (SA) e
40
do 2-OPT é descrito na figura 32 abaixo:
Se aplicado a uma instância do PCV, o pipeline indicado na figura 32, após processa-
mento, produzirá um resultado semelhante como segue:
41
Os functors, ou as funções transformadoras, tais como para aplicação do Simulated
Annealing (functor SA) ou do 2-OPT (functor 2OPT ), também foram implementadas
para outros algoritmos e estruturas, como por exemplo, Otimização por Colônia de Formi-
gas, Algoritmo Genético, Fork/Join (fragmento apresentado na figura 22), entre outros.
Estes elementos permitirão a construção dos pipelines ou modelos composicionais para
explorar o PCV juntamente com Computação Paralela e Inteligência Artificial. O modelo
destas funções transformadoras seguem uma determinada assinatura correspondente ao
fragmento central da operação de binding, permitindo que outras funções sejam criadas
para agregar e participar de novas composições ou de alguma já existente. Abaixo dois
exemplos completos de functors simples descritos em C++:
42
6 SOLUÇÕES PROPOSTAS
A resolução hı́brida desta seção possui uma composição monádica similar a indicada
na figura 25. Uma composição de SA e 2-OPT iniciada por uma heurı́stica construtiva, no
caso, do algoritmo do vizinho mais próximo, juntamente com computação paralela. Essa
composição produzirá uma notável forma de resolução hı́brida para explorar o PCV. Mo-
delos hı́bridos similares são adotados em problemas complexos a um certo tempo (AYDIN,
2005), mostrando ser um caminho promissor para exploração do problema.
43
conforme fora ilustrada na figura 25.
As etapas indicadas na figura 25 serão executadas por iterações, onde o resultado se-
lecionado da iteração anterior será a entrada da nova iteração, exceto na primeira iteração
onde a instância do PCV entrado é gerado pela heuristica construtiva. Estas iterações
permitirão o ajuste ou a melhoria do resultado desejado com a compensação de um tempo
maior de processamento. O modelo elitista e iterativo referenciado aqui é inspirado da
estrutura do Algoritmo Genético (GA) (HOLLAND, 1992b). Um resumo da arquitetura
hı́brida em paralelo proposta é ilustrada na figura 36.
44
s+p
poderá ser alcançado é s (SUTTER, 2008). No caso da abordagem clássica do SA, a
porção sequencial do código, ou seja, as iterações existentes são dependentes - a iteração
externa determina o ajuste de temperatura do sistema, e a iteração interna determina
a atualização da solução candidata que utiliza o valor da temperatura, este trecho da
implementação não é trivial de ser adaptado para usar paralelismo, ficando limitado, em
termos de desempenho, a lei de Amdahl.
45
aproximação, como no caso do SA, é colocar uma sobrecarga de processamento com o
objetivo de obter um número maior de soluções candidatas, ficando apenas com a melhor
delas no final. Esta estratégia, nas devidas proporções, é similar ao que está descrito
na seção ”Massive parallelism, scale-out, and speed ”do artigo sobre a implementação de
paralelismo (embarrassingly parallel ) no DeepQA da IBM, a infraestrutura de software
que roda por trás do supercomputador Watson ganhador do Jeopardy! (FERRUCCI,
2012).
A solução proposta nesta seção possui a mesma estrutura da solução anterior, porém
ao invés do SA, ela é uma composição de GA e 2-OPT. Portanto, as mesmas considerações
serão válidas aqui. Ou seja, estruturalmente são equivalentes, exceto pelo comportamento
do algoritmo metaheurı́stico atuante no processo. Os elementos variantes são os valores
encontrados e o tempo de processamento, esses detalhes são indicados nos resultado ob-
tidos adiante. A seguir a composição da solução proposta:
46
Figura 38: Solução 2. Correspondente ao Pipeline da figura 37.
47
6.3 Resolução Metaheurı́stica por Otimização por Colônia de
Formigas (ACO) e 2-OPT com Computação Paralela
A solução proposta nesta seção possui a mesma estrutura das soluções anteriores,
ao invés do SA ou do GA, ela é uma composição de ACO e 2-OPT. Contudo, as todas
as considerações anteriores serão válidas aqui. Os elementos variantes serão os valores
encontrados e o tempo de processamento. A seguir a composição da solução proposta:
48
6.4 Considerações sobre o Modelo Composicional
49
exemplo abaixo:
São construções válidas, a aplicação de pipelines contendo functors que utilizem pro-
cessamento heterogêneo e/ou execução adaptativa:
Diante disso é possı́vel concluir que através do modelo proposto existe uma grande
flexibilidade para customização de soluções para explorar o PCV de forma simples ou
hı́brida. Conforme demonstrado neste capı́tulo, os modelos propostos são de resoluções
hı́bridas em paralelo.
50
7 RESULTADOS OBTIDOS
Nesta seção, estão descritos os resultados obtidos relacionados às soluções propostas
dos capı́tulos anteriores.
Algumas das abordagens para validação dos testes do PCV consistem na utilização da
geração aleatória das coordenadas ou na aplicação de cenários já conhecidos e organizados
na TSPLIB (REINELT, 1991b).
Os resultados apresentados nesta seção consistem nas duas estratégias citadas para
certificar a qualidade dos valores obtidos. As instâncias do PCV, aleatórias e seleciona-
das da TSPLIB, consistem na análise do problema em sua formulação simétrica, onde o
objetivo é obter a distância euclidiana bidimensional minı́ma do percurso. As instâncias
aleatórias utilizam uma distribuição uniforme para determinar onde serão posicionadas as
coordenadas das cidades (ou vértices) do problema. Enquanto, as instâncias da TSPLIB
possuem as coordenadas pré-definidas.
Na figura 47 são apresentados alguns dos resultados obtidos em testes com proces-
samento paralelo da composição SA e 2-OPT, utilizando 32 tarefas independentes para
explorar a capacidade computacional de oito núcleos de processamento. Seis problemas
distintos da TSPLIB foram avaliados: cinco deles contendo 100 cidades (ou vértices) e um
com 48 cidades (ou vértices). Segundo os resultados apresentados nesta tabela, fica claro
concluir quando as instâncias são submetidas a um número de 32 tarefas paralelas e/ou
concorrentes, mesmo utilizando técnicas heurı́sticas onde o objetivo é buscar resultados
próximos dos valores ótimos com tempo de processamento satisfatório, após uma deter-
minada quantidade de iterações, este modelo hı́brido obtém o resultado ótimo indicado
na literatura.
51
Figura 47: Resultado do Pipeline 1 (figura 35) com 32 tarefas concorrentes.
Resultados semelhantes utilizando paralelismo nas diversas formas podem ser encon-
trados em outros trabalhos (O’NEIL, 2011). Os resultados apresentados na figura 47
são obtidos através do uso de CPUs, já os apresentados por O’Neil, Tamir e Burtscher
(O’NEIL, 2011) são através de GPUs. No entanto, ambas aplicam abordagens heurı́sticas
com paralelismo para alcançarem uma qualidade superior, no caso encontrar a solução
ótima das instâncias. No caso da instância kroE100 do PCV, catalogada na TSLIB, é
válido destacar que na versão hı́brida em paralelo, com SA e 2-OPT, assim como a des-
crita pelos outros autores (O’NEIL, 2011), ao qual utiliza Iterative Hill Climbing (IHC) e
2-OPT, foram necessários ajustes na configuração do algoritmo, pois o problema se desta-
cou como o mais desafiador em comparação aos outros relacionados na análise. Os valores
aplicados aos parâmetros do SA dos resultados apresentados na figura 47 são indicados
como segue:
52
Figura 48: Parâmetros atuais do algoritmo SA para as instâncias do PCV.
53
Figura 49: Resultados da aplicação do modelo hı́brido em paralelo proposto com oito
tarefas.
54
fino em forma de argumentos dos métodos/funções ou através do número de iterações.
Este tipo de reconfiguração é exigida e deve ser analisada individualmente. Em uma
das verificações e validações do problema, um certo grupo de valores executados através
do modelo hı́brido proposto na instância att48 do PCV da TSPLIB apresentavam um
comportamento estacionário ao alcançar um mı́nimo local correspondente a 33.600,60 - as
soluções encontradas não ultrapassavam este valor. Porém, ao ser efetuada alterações ou
ajustes em seus parâmetros atuais, e conforme indicado na figura 50, o resultado ótimo foi
encontrado (33.523,70). A figura 50 destaca as conexões dissemelhantes entre os grafos.
55
Os outros resultados deste pipeline, contendo a execução de 16, quatro e duas tarefas
são apresentados a seguir:
56
Figura 52: Resultado do Pipeline 1 (figura 35) com 4 tarefas concorrentes.
57
é verdadeira em relação a um percurso e a sua reversão. Os testes foram submetidos a 35
iterações, sendo que a iteração do melhor resultado selecionado está indicado na coluna
Iteração das tabelas 1 e 2. Por se tratar de uma solução que envolve aleatoriedade e da
qualidade do gerador randômico estes valores são suscetı́veis à variação.
Na comparação dos resultados através das 35 iterações de uma das soluções com as
configurações de oito e 32 tarefas em paralelo da instância kroA100 do PCV da TSPLIB
é possı́vel extrair um gráfico onde a curva é não monotônica, caso o modelo iterativo acei-
tasse valores inferiores entre as iterações. No entanto, é possı́vel obter a curva monotônica,
gerada pela seleção do melhor valor conhecido entre as iterações. As figuras 54 e 55 ilus-
tram estas iterações e suas respectivas curvas. Logo, as curvas da solução hı́brida em
paralelo indicadas nas figuras 54 e 55 são as indicadas pelo traçado pontilhado [kroA100
32 (1)* e kroA100 8 (1)* ] onde existe a sobreposição dos valores atuais [kroA100 32 (1)
e kroA100 8 (1)], tornando a solução proposta monoticamente decrescente entre as suas
iterações.
58
Outro exemplo do comportamento monotonicamente decrescente é ilustrado na fi-
gura 55:
Uma outra série de testes para validação da qualidade da solução foram efetuadas
com a mesma distribuição de tarefas paralelas indicadas anteriormente. Neste caso, o
procedimento aplicado foi para 250 cidades (ou vértices) distribuı́das aleatoriamente, cujas
coordenadas bidimensionais variam por uma distribuição uniforme discreta entre 0 a 100.
A seguir é apresentado um dos grafos com valor inicial e final da solução hı́brida em
paralelo, este é um dos resultados extraı́do da solução indicada pelo valor da primeira
linha na coluna com 32 tarefas da figura 56. Na figura 57 é fácil notar que a configuração
inicial apresenta um grafo com uma distribuição de arestas que se cruzam por diversas
vezes, tornando densa a figura impressa. O grafo da melhor solução entre as candidatas
exibe uma caracterı́stica esparsa, não havendo cruzamentos entre o conjunto de arestas,
denotando em um resultado visivelmente superior.
59
Figura 56: Resultados das diversas execuções e configurações de paralelismo do PCV
aleatório com 250 cidades.
Figura 57: PCV aleatório com 250 cidades - configuração inicial e final da execução um
com 32 tarefas.
60
Figura 58: Média e Desvio Padrão dos testes do PCV aleatório com 250 cidades.
Figura 59: Distribuição normal dos testes do PCV aleatório com 250 cidades.
61
7.4 Resultados obtidos com o Pipeline 2 (GA)
62
Figura 62: Resultado do Pipeline 2 (figura 37) com 8 tarefas concorrentes.
63
Figura 64: Resultado do Pipeline 2 (figura 37) com 2 tarefas concorrentes.
Os resultados acima (figuras 60, 61, 62, 63 e 64) reforçam as observações e as inter-
pretações obtidas com os resultados apresentandos anteriormente através das avaliações
do pipeline 1. De um modo geral, quanto maior for o paralelismo aplicado na distri-
buição e exploração, melhores serão as possibilidades de resultados superiores emergirem
como solução. É possı́vel notar que os resultados com 32 tarefas são melhores do que
com 16 tarefas, e assim sucessivamente. Há casos onde a uma quantidade menor de
tarefas explorando o mesmo espaço de estados se saiu melhor, isto é por causa das abor-
dagens heurı́sticas não serem exatas, elas dependem de aleatoriedade e as vezes os valores
randômicos gerados não são tão bons. Outro ponto, é que o comportamento da abor-
dagem proposta é generalista, poderá haver casos de insucesso em outros cenários, pois
ajustar um pipeline, dependerá do tipo de problema, da seleção de um conjunto correto
de algoritmos e os ajustes finos em seus parâmetros. No entanto, os resultados atingidos
são significativos e a arquitetura do modelo composicional se mostrou eficiente gerando
bons resultados na abordagem dos problemas avaliados.
64
7.5 Resultados obtidos com o Pipeline 3 (ACO)
Figura 65: Resultados do Pipeline 3 com a instância kroB200 da TSPLIB contendo 200
cidades.
65
A seguir são apresentados os grafos correspondentes aos ciclos do resultado em desta-
que da figura 65:
66
Figura 68: Ciclo do resultado em destaque relativo a figura 65 com 8 tarefas.
67
Figura 70: Ciclo do resultado em destaque relativo a figura 65 com 32 tarefas.
68
8 CONCLUSÃO E TRABALHOS FUTUROS
• Análise e ajustes finos dos argumentos das funções associados aos algoritmos me-
taheurı́sticos aplicados (SA, GA e ACO);
• Adaptação desta abordagem para outros problemas complexos, como por exemplo
o Problema da Mochila (PM) ou o Problema de Roteamento de Veı́culos (PRV).
69
REFERÊNCIAS BIBLIOGRÁFICAS
70
CECILIA, J. Enhancing data parallelism for ant colony optimization on gpus. J. Parallel
Distrib. Comput., Academic Press, Inc., Orlando, FL, USA, v. 73, n. 1, p. 42–51, jan.
2013. ISSN 0743-7315. Disponı́vel em: <http://dx.doi.org/10.1016/j.jpdc.2012.01.002>.
DORIGO, M. Ant Colony Optimization. Scituate, MA, USA: Bradford Company, 2004.
ISBN 0262042193.
71
FERRUCCI, D. A. Introduction to ”this is watson”. IBM Journal of Research and
Development, v. 56, n. 3–4, p. 1:1–1:15, 2012. Acesso em: 01 de Maio de 2013.
GOMEZ, J. Grisland: a parallel genetic algorithm for finding near optimal solutions
to the traveling salesman problem. In: Proceedings of the 11th Annual Conference
Companion on Genetic and Evolutionary Computation Conference: Late Breaking
Papers. New York, NY, USA: ACM, 2009. (GECCO ’09), p. 2035–2040. ISBN
978-1-60558-505-5. Disponı́vel em: <http://doi.acm.org/10.1145/1570256.1570272>.
72
HOLLAND, J. H. Genetic Algorithms: Computer programs that evolve in ways that
resemble natural selection can solve complex problems even their creators do not fully
understand. Scientific American, v. 267, p. 66–72, 1992.
LUCCI, S. Ant colony optimization. In: LUCCI, S.; KOPEC, D. (Ed.). Artificial
Intelligence in the 21st Century. 1. ed. Dulles, VA, USA: Mercury Learning and
Information, 2012. p. 382–386. ISBN 1936420236, 9781936420230.
73
MICROSOFT. Computation Expressions in FSharp. 2013. http://msdn.microsoft.
com/en-us/library/dd233182.aspx. Acesso em: 10 de Dezembro de 2013.
NEUMANN, J. von. First draft of a report on the edvac. IEEE Ann. Hist. Comput.,
IEEE Educational Activities Department, Piscataway, NJ, USA, v. 15, n. 4, p. 27–75,
out. 1993. ISSN 1058-6180. Disponı́vel em: <http://dx.doi.org/10.1109/85.238389>.
74
ROBERT, C. P. Introducing Monte Carlo Methods with R (Use R). 1. ed. Berlin,
Heidelberg, Germany: Springer-Verlag, 2009. 167–197 p. ISBN 1441915753,
9781441915757.
ROCKI, K. Accelerating 2-opt and 3-opt local search using gpu in the travelling salesman
problem. In: Proceedings of the 2012 12th IEEE/ACM International Symposium on
Cluster, Cloud and Grid Computing (ccgrid 2012). Washington, DC, USA: IEEE
Computer Society, 2012. (CCGRID ’12), p. 705–706. ISBN 978-0-7695-4691-9. Disponı́vel
em: <http://dx.doi.org/10.1109/CCGrid.2012.133>.
75
TSP@GATECH. Optimal Tours. 2007. http://www.tsp.gatech.edu/optimal/index.
html. Acesso em: 01 de Maio de 2013.
VOSS, S. Meta-heuristics: The state of the art. In: LOCAL SEARCH FOR PLANNING
AND SCHEDULING. [s.n.], 2006. Acesso em: 18 de Novembro 2013. Disponı́vel em:
<http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.203.4989>.
76
ANEXOS
Nesta seção são listados os anexos do trabalho. Através deles foram gerados as si-
mulações e obtidos os resultados apresentados.
Basicamente, eles são os códigos fontes contendo o modelo proposto desta obra com
seus respectivos artefatos. O código fonte é apresentado em C++ 11 em forma de header
files (.hpp) ou source files (.cpp). Abaixo segue a lista de arquivos anexados:
• tsp.hpp
• randomizers.hpp
• genetic algorithm.hpp
• nearest neighbour.hpp
• simulated annealing.hpp
• two opt.hpp
• tsp monad.hpp
• tsp functors.hpp
• tsp algo.hpp
• tsp support.hpp
• tsp.hpp
• program.cpp
77
C:\Users\Fabio Galuppo\Documents\Visual Studio 2012\Projects\TSPSolution\TSPSolution\src\tsp.hpp 1
1 //Sample provided by Fabio Galuppo
2 //Compositional TSP Solver version 0.1
3 //October 2013
4
5 #pragma once
6 #ifndef _tsp_class_
7 #define _tsp_class_
8
9 #include <vector>
10 #include <string>
11
12 #include <cmath>
13 #include <functional>
14
15 struct tsp_class
16 {
17 typedef std::pair<int /* x */, int /* y */> city_location;
18 typedef std::function<int()> rand_function;
19
20 struct city_info
21 {
22 int id;
23 city_location location;
24 };
25
26 typedef std::vector<city_info> cities_type;
27
28 typedef std::wstring description_type;
29
30 cities_type cities;
31 description_type description;
32
33 //Semiregular:
34 tsp_class()
35 {
36 }
37
38 tsp_class(const tsp_class& that)
39 {
40 cities = that.cities;
41 }
42
43 tsp_class& operator=(const tsp_class& that)
44 {
45 if (this != &that)
46 cities = that.cities;
47 return *this;
48 }
49
50 ~tsp_class()
51 {
52 }
53
54 //Regular:
55 friend bool operator==(const tsp_class& lhs, const tsp_class& rhs)
56 {
57 if (lhs.cities.size() == rhs.cities.size())
58 {
59 auto x = lhs.cities.cbegin();
60 auto y = rhs.cities.cbegin();
61
62 while(x != lhs.cities.cend() || y != rhs.cities.cend())
63 {
64 bool a = x>id != y>id,
65 b = x>location.first != y>location.first,
66 c = x>location.second != y>location.second;
C:\Users\Fabio Galuppo\Documents\Visual Studio 2012\Projects\TSPSolution\TSPSolution\src\tsp.hpp 2
67
68 if (a || b || c)
69 return false;
70
71 ++x;
72 ++y;
73 }
74
75 return true;
76 }
77
78 return false;
79 }
80
81 friend bool operator!=(const tsp_class& lhs, const tsp_class& rhs)
82 {
83 return !(lhs == rhs);
84 }
85
86 //
87 double do_cycle_length() const
88 {
89 cities_type::size_type N = cities.size();
90
91 double temp = euclidean_distance(cities[N 1].location, cities[0].location);
92
93 for (int i = 0, l = N 1; i < l; ++i)
94 temp += euclidean_distance(cities[i].location, cities[i + 1].location);
95
96 return temp;
97 }
98
99 //perturb_first: false means don't perturb starting/ending city
100 void do_pertubation(rand_function rnd_city, bool perturb_first)
101 {
102 int c1, c2;
103 do
104 {
105 c1 = rnd_city();
106 do c2 = rnd_city(); while(c1 == c2);
107 } while(!perturb_first && (0 == c1 || 0 == c2));
108
109 std::swap(cities[c1], cities[c2]);
110 }
111
112 static double euclidean_distance(city_location c1, city_location c2)
113 {
114 auto x1 = c1.first;
115 auto y1 = c1.second;
116 auto x2 = c2.first;
117 auto y2 = c2.second;
118 auto dx = std::abs(x1 x2);
119 auto dy = std::abs(y1 y2);
120 return std::sqrt(static_cast<double>(dx * dx + dy * dy));
121 }
122 };
123
124 #include <iostream>
125
126 void mathematica_graph_plot(tsp_class& tsp_instance, bool vertexLabeling = false, bool plotLabel =
true)
127 {
128 auto LEN = tsp_instance.cities.size() 1;
129
130 std::cout << "GraphPlot[{";
131 for (int i = 0, l = LEN; i < l; ++i)
C:\Users\Fabio Galuppo\Documents\Visual Studio 2012\Projects\TSPSolution\TSPSolution\src\tsp.hpp 3
132 std::cout << i << " > " << i + 1 << ", ";
133 std::cout << LEN << " > " << 0 << "}, ";
134
135 if (plotLabel)
136 std::cout << "PlotLabel > " << "\"" << tsp_instance.do_cycle_length() << "\", ";
137
138 std::cout << "Frame > True, ";
139
140 std::cout << "VertexLabeling > " << (vertexLabeling ? "True" : "False") << ", ";
141
142 std::cout << "VertexCoordinateRules > {";
143 for (int i = 0, l = LEN; i < l; ++i)
144 {
145 auto& city = tsp_instance.cities[i];
146 std::cout << i << " > {" << city.location.first << ", " << city.location.second << "}, ";
147 }
148 auto& city = tsp_instance.cities[LEN];
149 std::cout << LEN << " > {" << city.location.first << ", " << city.location.second << "}}]" << std:
:endl;
150 }
151
152 void display(tsp_class& tsp_instance, bool emit_mathematica_graph_plot = false)
153 {
154 for(auto city = tsp_instance.cities.cbegin(); city != tsp_instance.cities.cend(); ++city)
155 std::cout << "[" << city>id << "]" << "(" << city>location.first << ", " << city>location.
second << ") : ";
156 std::cout << tsp_instance.do_cycle_length() << std::endl;
157
158 if(emit_mathematica_graph_plot)
159 mathematica_graph_plot(tsp_instance);
160 }
161
162 #endif /* _tsp_class_ */
C:\Users\Fabio Galuppo\Documents\Visual Studio ...\TSPSolution\TSPSolution\src\randomizers.hpp 1
1 //Sample provided by Fabio Galuppo
2 //Compositional TSP Solver version 0.1
3 //October 2013
4
5 #pragma once
6 #ifndef _randomizers_
7 #define _randomizers_
8
9 #include <memory>
10 #include <random>
11 #include <ctime>
12
13 struct random_functor
14 {
15 random_functor(int min_inclusive, int max_inclusive, unsigned seed = static_cast<unsigned>(std::time
(nullptr))) :
16 Engine_(new std::default_random_engine(seed)),
17 Rnd_(new std::uniform_int_distribution<int>(min_inclusive, max_inclusive))
18 {
19 }
20
21 random_functor(int max_exclusive, unsigned seed = static_cast<unsigned>(std::time(nullptr))) :
22 Engine_(new std::default_random_engine(seed)),
23 Rnd_(new std::uniform_int_distribution<int>(0, max_exclusive 1))
24 {
25 }
26
27 //[0; max_inclusive]
28 auto operator()() const > int { return (*Rnd_)(*Engine_); }
29
30 private:
31 std::shared_ptr<std::default_random_engine> Engine_;
32 std::shared_ptr<std::uniform_int_distribution<int>> Rnd_;
33 };
34
35 struct double_random_functor
36 {
37 double_random_functor(unsigned seed = static_cast<unsigned>(std::time(nullptr))) :
38 Engine_(new std::default_random_engine(seed)),
39 Rnd_(new std::uniform_real_distribution<double>())
40 {
41 }
42
43 //[0.0; 1.0]
44 auto operator()() const > double { return (*Rnd_)(*Engine_); }
45
46 private:
47 std::shared_ptr<std::default_random_engine> Engine_;
48 std::shared_ptr<std::uniform_real_distribution<double>> Rnd_;
49 };
50
51 #endif /* _randomizers_ */
C:\Users\Fabio Galuppo\Documents\Visual Studio ...\src\algorithms\ant_colony_optimization.hpp 1
1 //Sample provided by Fabio Galuppo
2 //Compositional TSP Solver version 0.1
3 //October 2013
4
5 #pragma once
6 #ifndef _ant_colony_optimization_
7 #define _ant_colony_optimization_
8
9 #include "..\tsp.hpp"
10 #include "..\randomizers.hpp"
11
12 #include <cmath>
13 #include <memory>
14 #include <algorithm>
15 #include <utility>
16 #include <limits>
17
18 typedef std::vector<std::vector<double>> pheromones_type;
19
20 struct ant_class;
21
22 typedef std::vector<std::shared_ptr<ant_class>> ants_type;
23
24 struct ant_class
25 {
26 typedef std::vector<bool> tabu_type;
27 typedef std::vector<unsigned short> tour_type;
28
29 ant_class(int size, int city,
30 const pheromones_type& pheromones,
31 const tsp_class& tsp_instance,
32 std::unique_ptr<double_random_functor> random_func = std::unique_ptr<double_random_functor>(new
double_random_functor())) :
33 referential_city(city),
34 pheromones(pheromones),
35 tsp_instance(tsp_instance),
36 random_func(std::move(random_func))
37 {
38 tabu.resize(size);
39 tour.resize(size);
40 reset();
41 }
42
43 void reset()
44 {
45 current_city = referential_city;
46
47 tabu_type::size_type N = tabu.size();
48 for (tabu_type::size_type i = 0; i < N; ++i)
49 {
50 tabu[i] = false;
51 tour[i] = 0;
52 }
53
54 tabu[current_city] = true;
55 tour[0] = current_city;
56 tour_index = 1;
57 tour_length = 0.0;
58 }
59
60 tour_type tour;
61
62 private:
63 tabu_type tabu;
64
65 int current_city;
C:\Users\Fabio Galuppo\Documents\Visual Studio ...\src\algorithms\ant_colony_optimization.hpp 2
66 int next_city;
67 tour_type::size_type tour_index;
68 double tour_length;
69 const pheromones_type& pheromones;
70 const tsp_class& tsp_instance;
71 std::unique_ptr<double_random_functor> random_func;
72
73 bool move(const double alpha /* favor pheromone level over distance */, const double beta /* favor
distance over pheromone level */)
74 {
75 tour_type::size_type N = tour.size();
76 if (tour_index < N)
77 {
78 take_next_city(alpha, beta);
79 return true;
80 }
81
82 return false;
83 }
84
85 void take_next_city(const double alpha /* favor pheromone level over distance */, const double beta
/* favor distance over pheromone level */)
86 {
87 double total_for_non_visited_cities = 0.0;
88 tsp_class::cities_type::size_type from = current_city, to = 0;
89 for(auto i = tabu.cbegin(); i != tabu.cend(); ++i, ++to)
90 if (*i == 0)
91 total_for_non_visited_cities += product_of_pheronome_level_and_distance(tsp_instance,
pheromones, from, to, alpha, beta);
92
93 to = 0;
94 tabu_type::size_type N = tabu.size();
95 unsigned short max_iteration_guard = std::numeric_limits<unsigned short>::max();
96 while (max_iteration_guard > 0)
97 {
98 if (!tabu[to])
99 {
100 const double current_product_of_pheronome_level_and_distance =
product_of_pheronome_level_and_distance(tsp_instance, pheromones, from, to, alpha, beta);
101 const double visitProbability = current_product_of_pheronome_level_and_distance /
total_for_non_visited_cities;
102
103 if ((*random_func)() < visitProbability)
104 break;
105 else
106 max_iteration_guard--;
107 }
108
109 to = (to + 1) % N;
110 }
111
112 next_city = to;
113 tabu[next_city] = true;
114 tour[tour_index++] = next_city;
115
116 tour_length += tsp_class::euclidean_distance(tsp_instance.cities[current_city].location,
tsp_instance.cities[next_city].location);
117 if (tour_index == N)
118 tour_length += tsp_class::euclidean_distance(tsp_instance.cities[N-1].location,
tsp_instance.cities[0].location);
119
120 current_city = next_city;
121 }
122
123 static double product_of_pheronome_level_and_distance(const tsp_class& tsp_instance, const
pheromones_type& pheromones, pheromones_type::size_type from, pheromones_type::size_type to, double
C:\Users\Fabio Galuppo\Documents\Visual Studio ...\src\algorithms\ant_colony_optimization.hpp 3
alpha, double beta)
124 {
125 const auto level_of_pheronome_between_current_and_candidate_location = std::pow(pheromones
[from][to], alpha);
126 const auto distance_between_current_and_candidate_location = std::pow((1.0 / tsp_class::
euclidean_distance(tsp_instance.cities[from].location, tsp_instance.cities[to].location)), beta);
127 return level_of_pheronome_between_current_and_candidate_location *
distance_between_current_and_candidate_location;
128 }
129
130 friend static void update_pheromone_trails(const tsp_class&, pheromones_type&, const ants_type&,
const double, const double, const double);
131 friend static void take_min_cycle(tsp_class&, const ants_type&);
132 friend static void ant_colony_optimization(tsp_class&, double, unsigned int, const ants_type::
size_type, const double, const double, const double, const double, const unsigned int);
133
134 private:
135 unsigned short referential_city;
136 };
137
138 void update_pheromone_trails(const tsp_class& tsp_instance, pheromones_type& pheromones, const
ants_type& ants, const double base_pheromone, const double rho, const double qval)
139 {
140 const tsp_class::cities_type::size_type N = tsp_instance.cities.size();
141
142 //evaporate
143 for (tsp_class::cities_type::size_type i = 0; i < N; ++i)
144 {
145 for (tsp_class::cities_type::size_type j = 0; j < N; ++j)
146 {
147 pheromones[i][j] *= (1.0 - rho);
148 if (pheromones[i][j] < 0.0)
149 pheromones[i][j] = base_pheromone;
150 }
151 }
152
153 const ants_type::size_type A = ants.size();
154
155 //intensify
156 for(auto ant = ants.cbegin(); ant != ants.end(); ++ant)
157 {
158 for (tsp_class::cities_type::size_type i = 0; i < N; ++i)
159 {
160 int from = (*ant)->tour[i];
161 int to = (*ant)->tour[((i+1) % N)];
162
163 pheromones[from][to] += ((qval / (*ant)->tour_length) * rho);
164 pheromones[to][from] = pheromones[from][to];
165 }
166 }
167 }
168
169 void take_min_cycle(tsp_class& tsp_instance, const ants_type& ants)
170 {
171 std::vector<std::pair<int, double>> tours_lenght;
172 tours_lenght.resize(ants.size());
173
174 int i = 0;
175 std::transform(ants.cbegin(), ants.cend(), tours_lenght.begin(), [&i](const std::shared_ptr
<ant_class>& a)
176 {
177 return std::make_pair(i++, (*a).tour_length);
178 });
179
180 std::sort(tours_lenght.begin(), tours_lenght.end(), [](const std::pair<int, double>& lhs, const std
::pair<int, double>& rhs)
C:\Users\Fabio Galuppo\Documents\Visual Studio ...\src\algorithms\ant_colony_optimization.hpp 4
181 {
182 return lhs.second < rhs.second;
183 });
184
185 auto best_tour = *tours_lenght.begin();
186 ant_class& best_ant = *(ants[best_tour.first].get());
187
188 tsp_class temp = tsp_instance;
189 i = 0;
190 for(auto iter = best_ant.tour.cbegin(); iter != best_ant.tour.cend(); ++iter)
191 temp.cities[i++] = tsp_instance.cities[*iter];
192
193 if (temp.do_cycle_length() <= tsp_instance.do_cycle_length())
194 tsp_instance = temp;
195 }
196
197 void ant_colony_optimization(tsp_class& tsp_instance,
198 const double base_pheromone,
199 unsigned int iterations,
200 const ants_type::size_type number_of_ants,
201 const double favor_pheromone_level_over_distance,
202 const double favor_distance_over_pheromone_level,
203 const double value_for_intensification_and_evaporation,
204 const double pheronome_distribution,
205 const unsigned int rnd_seed)
206 {
207 const auto N = tsp_instance.cities.size();
208 random_functor rnd_Q(static_cast<int>(pheronome_distribution), 100, rnd_seed);
209 double Q = rnd_Q();
210
211 pheromones_type pheromones;
212 ants_type ants;
213 {
214 random_functor delay(1, number_of_ants * 2);
215 std::vector<std::unique_ptr<double_random_functor>> double_random_functors;
216 for (ants_type::size_type i = 0; i < number_of_ants; ++i)
217 double_random_functors.push_back(std::unique_ptr<double_random_functor>(new
double_random_functor(rnd_seed + i * delay())));
218
219 for (std::vector<std::shared_ptr<ant_class>>::size_type a = 0; a < number_of_ants; ++a)
220 ants.push_back(std::shared_ptr<ant_class>(new ant_class(N, a % N, pheromones, tsp_instance,
std::move(double_random_functors[a]))));
221 }
222
223 pheromones.reserve(N * N);
224 for (tsp_class::cities_type::size_type i = 0; i < N; ++i)
225 {
226 std::vector<double> v;
227 for (tsp_class::cities_type::size_type j = 0; j < N; ++j)
228 v.push_back(base_pheromone);
229 pheromones.push_back(v);
230 }
231
232 while (iterations-- > 0)
233 {
234 int moved = 0;
235 for (auto a = ants.begin(); a != ants.end(); ++a)
236 moved += (*a)->move(favor_pheromone_level_over_distance,
favor_distance_over_pheromone_level) ? 1 : 0;
237 if (0 == moved)
238 {
239 //update_pheromone_trails(tsp_instance, pheromones, ants, base_pheromone,
value_for_intensification_and_evaporation, pheronome_distribution);
240 update_pheromone_trails(tsp_instance, pheromones, ants, base_pheromone,
value_for_intensification_and_evaporation, Q);
241
C:\Users\Fabio Galuppo\Documents\Visual Studio ...\src\algorithms\ant_colony_optimization.hpp 5
242 if (iterations > 0)
243 {
244 take_min_cycle(tsp_instance, ants);
245 for (auto a = ants.begin(); a != ants.end(); ++a)
246 (*a)->reset();
247 }
248 }
249 }
250 }
251
252 #endif /* _ant_colony_optimization_ */
C:\Users\Fabio Galuppo\Documents\Visual Studio ...\TSPSolution\src\algorithms\genetic_algorithm.hpp 1
1 //Sample provided by Fabio Galuppo
2 //Compositional TSP Solver version 0.1
3 //October 2013
4
5 #pragma once
6 #ifndef _genetic_algorithm_
7 #define _genetic_algorithm_
8
9 #include "..\tsp.hpp"
10 #include "..\randomizers.hpp"
11
12 #include <iostream>
13 #include <utility>
14 #include <vector>
15 #include <algorithm>
16 #include <functional>
17 #include <limits>
18
19 typedef std::pair<typename tsp_class::cities_type::size_type /* id */, double /* distance */>
distance_value_type;
20 typedef std::vector<distance_value_type> distance_collection_type;
21
22 struct tour
23 {
24 typedef std::pair<unsigned int, unsigned int> connection;
25 typedef std::vector<connection> connections_type;
26
27 connections_type connections;
28
29 tour(const tsp_class& tsp_instance) :
30 Fitness_(0.0),
31 TspInstance_(tsp_instance)
32 {
33 }
34
35 tour(const tour& that) :
36 TspInstance_(that.TspInstance_)
37 {
38 connections = that.connections;
39 Fitness_ = do_fitness();
40 }
41
42 tour& operator=(const tour& that)
43 {
44 if (this != &that)
45 {
46 connections = that.connections;
47 const_cast<tsp_class&>(TspInstance_) = that.TspInstance_;
48 Fitness_ = do_fitness();
49 }
50 return *this;
51 }
52
53 ~tour()
54 {
55 }
56
57 void resize_and_reset()
58 {
59 connections.resize(TspInstance_.cities.size());
60 for (auto i = connections.begin(); i != connections.end(); ++i)
61 {
62 *i = std::make_pair(std::numeric_limits<unsigned int>::max(),
63 std::numeric_limits<unsigned int>::max());
64 }
65 }
C:\Users\Fabio Galuppo\Documents\Visual Studio ...\TSPSolution\src\algorithms\genetic_algorithm.hpp 2
66
67 const std::pair<bool, bool> has_connection(connections_type::size_type index) const
68 {
69 const auto& i = connections[index];
70 return std::make_pair(i.first != no_connection(),
71 i.second != no_connection());
72 }
73
74 double do_fitness()
75 {
76 double fitness = 0.0;
77 unsigned int previous_city = 0, next_city = connections[0].first;
78
79 for (auto i = connections.begin(); i != connections.end(); ++i)
80 {
81 fitness += tsp_class::euclidean_distance(TspInstance_.cities[previous_city].location,
82 TspInstance_.cities[next_city].location);
83
84 bool x = previous_city != connections[next_city].first;
85 previous_city = next_city;
86 next_city = x ? connections[next_city].first : connections[next_city].second;
87 }
88
89 Fitness_ = fitness;
90
91 return fitness;
92 }
93
94 const double fitness() const { return Fitness_; }
95
96 static unsigned int no_connection()
97 {
98 return std::numeric_limits<unsigned int>::max();
99 }
100
101 private:
102 double Fitness_;
103 const tsp_class& TspInstance_;
104 };
105
106 std::vector<distance_collection_type>
107 make_closest_cities_table(const tsp_class& tsp_instance,
108 distance_collection_type::size_type closest_cities_maxcount)
109 {
110 std::vector<distance_collection_type> distance_table;
111
112 tsp_class::cities_type::size_type i_idx = 0;
113 for (auto i = tsp_instance.cities.cbegin(); i != tsp_instance.cities.cend(); ++i, ++i_idx)
114 {
115 distance_collection_type distances;
116 distances.reserve(tsp_instance.cities.size() 1 /* (*) */);
117
118 tsp_class::cities_type::size_type j_idx = 0;
119 for (auto j = tsp_instance.cities.cbegin(); j != tsp_instance.cities.cend(); ++j, ++j_idx)
120 {
121 if (j_idx != i_idx) //excluding self (*)
122 {
123 auto distance = tsp_class::euclidean_distance(i>location, j>location);
124 distances.push_back(std::make_pair(j_idx, distance));
125 }
126 }
127
128 std::sort(distances.begin(), distances.end(), [] (const distance_value_type& lhs, const
distance_value_type& rhs)
129 {
130 return lhs.second < rhs.second;
C:\Users\Fabio Galuppo\Documents\Visual Studio ...\TSPSolution\src\algorithms\genetic_algorithm.hpp 3
131 });
132
133 if (distances.size() > closest_cities_maxcount) distances.resize(closest_cities_maxcount);
134
135 distance_table.push_back(std::move(distances));
136 }
137
138 return distance_table;
139 }
140
141 unsigned int& first_ref(const tour& t, tsp_class::cities_type::size_type index)
142 {
143 return const_cast<unsigned int&>(t.connections[index].first);
144 }
145
146 unsigned int& second_ref(const tour& t, tsp_class::cities_type::size_type index)
147 {
148 return const_cast<unsigned int&>(t.connections[index].second);
149 }
150
151 tsp_class tour_to_tsp_class(const tsp_class& tsp_instance, const tour& t)
152 {
153 tsp_class result;
154 result.cities.reserve(tsp_instance.cities.size());
155
156 unsigned int previous_city = 0, next_city = first_ref(t, 0);
157
158 for (tour::connections_type::size_type i = 0, l = t.connections.size(); i < l; ++i)
159 {
160 result.cities.push_back(tsp_instance.cities[next_city]);
161 bool x = previous_city != first_ref(t, next_city);
162 previous_city = next_city;
163 next_city = x ? first_ref(t, next_city) : second_ref(t, next_city);
164 }
165
166 return result;
167 }
168
169 typedef std::vector<tour> population_type;
170
171 population_type make_population_via_selection(const tsp_class& tsp_instance,
172 tour& best_tour,
173 unsigned int population_size,
174 std::vector<distance_collection_type>
closest_cities_table,
175 double closest_city_probability,
176 tsp_class::rand_function rnd_tsp,
177 std::function<double()> rnd_probability,
178 tsp_class::rand_function rnd_closest_city)
179 {
180 const auto N = tsp_instance.cities.size();
181
182 population_type population;
183 population.reserve(population_size);
184
185 int begin_city, end_city;
186 for (unsigned int i = 0; i < population_size; ++i)
187 {
188 tour new_tour(tsp_instance);
189 new_tour.resize_and_reset();
190
191 begin_city = rnd_tsp();
192 end_city = begin_city;
193
194 int next_city;
195 for (unsigned int j = 0; j < N 1; ++j)
C:\Users\Fabio Galuppo\Documents\Visual Studio ...\TSPSolution\src\algorithms\genetic_algorithm.hpp 4
196 {
197 do next_city = (rnd_probability() < closest_city_probability) && (closest_cities_table[j].
size() > 0) ?
198 closest_cities_table[j][rnd_closest_city()].first : rnd_tsp();
199 while (new_tour.has_connection(next_city).second || (next_city == end_city));
200
201 second_ref(new_tour, end_city) = next_city;
202 first_ref(new_tour, next_city) = end_city;
203 end_city = next_city;
204 second_ref(new_tour, end_city) = begin_city;
205 first_ref(new_tour, begin_city) = end_city;
206 }
207
208 //new_tour will execute do_fitness() in copy constructor when it's copied to population
209 population.push_back(new_tour);
210 }
211
212 best_tour = *std::min_element(population.begin(), population.end(), [](const tour& lhs, const tour&
rhs) {
213 return lhs.fitness() < rhs.fitness();
214 });
215
216 return population;
217 }
218
219 bool has_valid_connection(const tsp_class& tsp_instance,
220 tour& t,
221 std::vector<tsp_class::cities_type::size_type>& city_usage,
222 tsp_class::cities_type::size_type first_city,
223 tsp_class::cities_type::size_type second_city)
224 {
225
226 if ((first_city == second_city) || (2 == city_usage[first_city]) || (2 == city_usage[second_city]))
227 return false;
228
229 if ((0 == city_usage[first_city]) || (0 == city_usage[second_city]))
230 return true;
231
232 for (unsigned int i = 0; i < 2; ++i)
233 {
234 tsp_class::cities_type::size_type last_city = first_city;
235 auto connection = i == 0 ? first_ref(t, first_city) : second_ref(t, first_city);
236
237 tsp_class::cities_type::size_type tour_count = 0;
238 while ((connection != tour::no_connection()) && (connection != second_city) && (tour_count <
tsp_instance.cities.size() 2))
239 {
240 ++tour_count;
241
242 if (last_city != first_ref(t, connection))
243 {
244 last_city = connection;
245 connection = first_ref(t, connection);
246 }
247 else
248 {
249 last_city = connection;
250 connection = second_ref(t, connection);
251 }
252 }
253
254 if (tour_count >= tsp_instance.cities.size() 2)
255 return true;
256
257 if (connection == second_city)
258 return false;
C:\Users\Fabio Galuppo\Documents\Visual Studio ...\TSPSolution\src\algorithms\genetic_algorithm.hpp 5
259 }
260
261 return true;
262 }
263
264 void connect_cities(tour& t,
265 std::vector<tsp_class::cities_type::size_type>& city_usage,
266 tsp_class::cities_type::size_type first_city,
267 tsp_class::cities_type::size_type second_city)
268 {
269 if (t.connections[first_city].first == tour::no_connection())
270 t.connections[first_city].first = second_city;
271 else
272 t.connections[first_city].second = second_city;
273
274 if (t.connections[second_city].first == tour::no_connection())
275 t.connections[second_city].first = first_city;
276 else
277 t.connections[second_city].second = first_city;
278
279 ++city_usage[first_city];
280 ++city_usage[second_city];
281 }
282
283 unsigned int find_next_city(const tsp_class& tsp_instance,
284 tour& parent,
285 tour& child,
286 std::vector<tsp_class::cities_type::size_type>& city_usage,
287 int city)
288 {
289 if (has_valid_connection(tsp_instance, child, city_usage, city, first_ref(parent, city)))
290 return first_ref(parent, city);
291
292 if (has_valid_connection(tsp_instance, child, city_usage, city, second_ref(parent, city)))
293 return second_ref(parent, city);
294
295 return tour::no_connection();
296 }
297
298 tour crossover(const tsp_class& tsp_instance,
299 tour& first_parent,
300 tour& second_parent,
301 const random_functor& rnd)
302 {
303 tour child(tsp_instance);
304 child.resize_and_reset();
305
306 std::vector<tsp_class::cities_type::size_type> city_usage;
307 city_usage.resize(tsp_instance.cities.size());
308 std::fill(city_usage.begin(), city_usage.end(), 0);
309
310 tsp_class::cities_type::size_type next_city = 0;
311 for (tsp_class::cities_type::size_type city = 0; city != tsp_instance.cities.size(); ++city)
312 {
313 if (city_usage[city] < 2)
314 {
315 auto& a = first_ref(first_parent, city);
316 auto& b = second_ref(first_parent, city);
317 auto& c = first_ref(second_parent, city);
318 auto& d = second_ref(second_parent, city);
319
320 if (a == c)
321 {
322 next_city = a;
323 if (has_valid_connection(tsp_instance, child, city_usage, city, next_city))
324 connect_cities(child, city_usage, city, next_city);
C:\Users\Fabio Galuppo\Documents\Visual Studio ...\TSPSolution\src\algorithms\genetic_algorithm.hpp 6
325 }
326
327 if (b == d)
328 {
329 next_city = b;
330 if (has_valid_connection(tsp_instance, child, city_usage, city, next_city))
331 connect_cities(child, city_usage, city, next_city);
332
333 }
334
335 if (a == d)
336 {
337 next_city = a;
338 if (has_valid_connection(tsp_instance, child, city_usage, city, next_city))
339 connect_cities(child, city_usage, city, next_city);
340 }
341
342 if (b == c)
343 {
344 next_city = b;
345 if (has_valid_connection(tsp_instance, child, city_usage, city, next_city))
346 connect_cities(child, city_usage, city, next_city);
347 }
348 }
349 }
350
351 for (tsp_class::cities_type::size_type city = 0; city != tsp_instance.cities.size(); ++city)
352 {
353 if (city_usage[city] < 2)
354 {
355 if (city % 2 == 1)
356 {
357 next_city = find_next_city(tsp_instance, first_parent, child, city_usage, city);
358 if (next_city == tour::no_connection())
359 next_city = find_next_city(tsp_instance, second_parent, child, city_usage, city);
360 }
361 else
362 {
363 next_city = find_next_city(tsp_instance, second_parent, child, city_usage, city);
364 if (next_city == tour::no_connection())
365 next_city = find_next_city(tsp_instance, first_parent, child, city_usage, city);
366 }
367
368 if (next_city != tour::no_connection())
369 {
370 connect_cities(child, city_usage, city, next_city);
371
372 if (city_usage[city] == 1)
373 {
374 if (city % 2 != 1)
375 {
376 next_city = find_next_city(tsp_instance, first_parent, child, city_usage, city)
;
377 if (next_city == tour::no_connection())
378 next_city = find_next_city(tsp_instance, second_parent, child, city_usage,
city);
379 }
380 else
381 {
382 next_city = find_next_city(tsp_instance, second_parent, child, city_usage,
city);
383 if (next_city == tour::no_connection())
384 next_city = find_next_city(tsp_instance, first_parent, child, city_usage,
city);
385 }
386
C:\Users\Fabio Galuppo\Documents\Visual Studio ...\TSPSolution\src\algorithms\genetic_algorithm.hpp 7
387 if (next_city != tour::no_connection())
388 connect_cities(child, city_usage, city, next_city);
389 }
390 }
391 }
392 }
393
394 for (tsp_class::cities_type::size_type city = 0; city != tsp_instance.cities.size(); ++city)
395 {
396 while (city_usage[city] < 2)
397 {
398 do next_city = rnd();
399 while (!has_valid_connection(tsp_instance, child, city_usage, city, next_city));
400 connect_cities(child, city_usage, city, next_city);
401 }
402 }
403
404 return child;
405 }
406
407 void mutate(tour& t, const random_functor& rnd)
408 {
409 int city_number = rnd();
410 auto& connection = t.connections[city_number];
411
412 int temp = connection.second;
413
414 if (first_ref(t, connection.first) == city_number)
415 {
416 if (first_ref(t, connection.second) == city_number)
417 first_ref(t, connection.second) = connection.first;
418 else
419 second_ref(t, connection.second) = connection.first;
420
421 first_ref(t, connection.first) = temp;
422 }
423 else
424 {
425 if (first_ref(t, connection.second) == city_number)
426 first_ref(t, connection.second) = connection.first;
427 else
428 second_ref(t, connection.second) = connection.first;
429
430 second_ref(t, connection.first) = temp;
431 }
432
433 int other_city_number = 1;
434 do other_city_number = rnd(); while (other_city_number == city_number);
435 auto& other_connection = t.connections[other_city_number];
436
437 temp = other_connection.second;
438 connection.second = other_connection.second;
439 connection.first = other_city_number;
440 other_connection.second = city_number;
441
442 if (first_ref(t, temp) == other_city_number)
443 first_ref(t, temp) = city_number;
444 else
445 second_ref(t, temp) = city_number;
446 }
447
448 tour do_crossover_and_mutation(const tsp_class& tsp_instance,
449 tour& current_best_tour,
450 tour& first_parent,
451 tour& second_parent,
452 population_type::size_type mutation,
C:\Users\Fabio Galuppo\Documents\Visual Studio ...\TSPSolution\src\algorithms\genetic_algorithm.hpp 8
453 const random_functor& rnd_tour,
454 const random_functor& rnd_accept_mutation_percentage)
455 {
456 auto new_tour = crossover(tsp_instance, first_parent, second_parent, rnd_tour);
457 if (static_cast<unsigned int>(rnd_accept_mutation_percentage()) < mutation)
458 {
459 mutate(new_tour, rnd_tour);
460 new_tour.do_fitness();
461 }
462
463 if (new_tour.fitness() < current_best_tour.fitness())
464 current_best_tour = new_tour;
465
466 return new_tour;
467 }
468
469 void make_children_via_genetic_operation(const tsp_class& tsp_instance,
470 tour& current_best_tour,
471 population_type& population,
472 population_type::size_type group_size,
473 population_type::size_type mutation,
474 const random_functor& rnd_population,
475 const random_functor& rnd_tour,
476 const random_functor& rnd_accept_mutation_percentage)
477 {
478 std::vector<population_type::size_type> tours;
479 tours.reserve(group_size);
480
481 for (unsigned int i = 0; i != group_size; ++i)
482 tours.push_back(rnd_population());
483
484 std::sort(tours.begin(), tours.end(), [&population](const population_type::size_type& lhs, const
population_type::size_type& rhs) {
485 return population[lhs].fitness() < population[rhs].fitness();
486 });
487
488 population[tours[group_size 1]] =
489 do_crossover_and_mutation(
490 tsp_instance,
491 current_best_tour,
492 population[tours[0]],
493 population[tours[1]],
494 mutation,
495 rnd_tour,
496 rnd_accept_mutation_percentage);
497
498 population[tours[group_size 2]] =
499 do_crossover_and_mutation(
500 tsp_instance,
501 current_best_tour,
502 population[tours[1]],
503 population[tours[0]],
504 mutation,
505 rnd_tour,
506 rnd_accept_mutation_percentage);
507 }
508
509 void genetic_algorithm(tsp_class& tsp_instance,
510 const unsigned int population_size,
511 const unsigned int mutation_percentage,
512 const unsigned int group_size,
513 const unsigned int number_of_generations,
514 const unsigned int nearby_cities,
515 const double nearby_cities_percentage,
516 const unsigned int seed)
517 {
C:\Users\Fabio Galuppo\Documents\Visual Studio ...\TSPSolution\src\algorithms\genetic_algorithm.hpp 9
518 auto closest_cities_table = make_closest_cities_table(tsp_instance, nearby_cities);
519 random_functor rnd_tour(static_cast<int>(tsp_instance.cities.size()), seed);
520
521 tour best_tour(tsp_instance);
522 auto population = make_population_via_selection(tsp_instance, best_tour,
523 population_size, closest_cities_table, nearby_cities_percentage,
524 rnd_tour, double_random_functor(), random_functor(nearby_cities));
525
526 random_functor rnd_population(static_cast<int>(population.size()), seed);
527 random_functor rnd_accept_mutation_percentage(100, seed);
528
529 for(unsigned int g = 0; g < number_of_generations; ++g)
530 make_children_via_genetic_operation(tsp_instance, best_tour, population, group_size,
mutation_percentage,
531 rnd_population, rnd_tour, rnd_accept_mutation_percentage);
532
533 tsp_instance = tour_to_tsp_class(tsp_instance, best_tour);
534 }
535
536 #endif /* _genetic_algorithm_ */
C:\Users\Fabio Galuppo\Documents\Visual Studio ...\TSPSolution\src\algorithms\nearest_neighbour.hpp 1
1 //Sample provided by Fabio Galuppo
2 //Compositional TSP Solver version 0.1
3 //October 2013
4
5 #pragma once
6 #ifndef _nearest_neighbour_
7 #define _nearest_neighbour_
8
9 #include "..\tsp.hpp"
10
11 #include <algorithm>
12
13 void nearest_neighbour(tsp_class& tsp_instance)
14 {
15 auto xs = tsp_instance.cities;
16 tsp_instance.cities.clear();
17
18 auto x = *xs.begin();
19 tsp_instance.cities.push_back(x);
20 xs.erase(xs.begin());
21
22 while(xs.size() > 0)
23 {
24 auto nearest = std::min_element(xs.begin(), xs.end(), [&x](const tsp_class::city_info& i, const
tsp_class::city_info& j) {
25 return tsp_class::euclidean_distance(x.location, i.location) < tsp_class::euclidean_distance
(x.location, j.location);
26 });
27
28 x = *nearest;
29 tsp_instance.cities.push_back(x);
30 xs.erase(nearest);
31 }
32 }
33
34 #endif /* _nearest_neighbour_ */
C:\Users\Fabio Galuppo\Documents\Visual Studio ...TSPSolution\src\algorithms\simulated_annealing.hpp 1
1 //Sample provided by Fabio Galuppo
2 //Compositional TSP Solver version 0.1
3 //October 2013
4
5 #pragma once
6 #ifndef _simulated_annealing_
7 #define _simulated_annealing_
8
9 #include "..\tsp.hpp"
10
11 #include <cmath>
12
13 void simulated_annealing(const double initial_temperature,
14 const double stopping_criteria_temperature,
15 const double decreasing_factor,
16 const int monte_carlo_steps,
17 tsp_class& tsp_instance,
18 tsp_class::rand_function rnd_tsp,
19 std::function<double()> rnd_probability)
20 {
21 double temperature = initial_temperature;
22
23 while(temperature > stopping_criteria_temperature)
24 {
25 double cycle_length = tsp_instance.do_cycle_length();
26 tsp_class temp_tsp_instance = tsp_instance;
27
28 int i = monte_carlo_steps;
29 while(i > 0)
30 {
31 temp_tsp_instance.do_pertubation(rnd_tsp, false);
32 double temp_cycle_length = temp_tsp_instance.do_cycle_length();
33
34 double dE = temp_cycle_length cycle_length;
35
36 bool update = false;
37 if(dE < 0.0)
38 {
39 update = true;
40 }
41 else
42 {
43 //Inferior solution can be allowed to move from local optimal solution
44 //using probability of acceptance based on Boltzmann's function
45 auto boltzmannFunction = std::exp(dE / temperature);
46 auto acceptanceProbability = rnd_probability();
47 update = boltzmannFunction > acceptanceProbability;
48 }
49
50 if(update)
51 {
52 tsp_instance = temp_tsp_instance;
53 cycle_length = temp_cycle_length;
54 }
55 }
56
57 temperature *= decreasing_factor;
58 }
59 }
60
61 #endif /* _simulated_annealing_ */
C:\Users\Fabio Galuppo\Documents\Visual Studio ...TSPSolution\TSPSolution\src\algorithms\two_opt.hpp 1
1 //Sample provided by Fabio Galuppo
2 //Compositional TSP Solver version 0.1
3 //October 2013
4
5 #pragma once
6 #ifndef _two_opt_
7 #define _two_opt_
8
9 #include "..\tsp.hpp"
10
11 #include <algorithm>
12 #include <cmath>
13
14 tsp_class two_opt_swap(const tsp_class& tsp_instance,
15 tsp_class::cities_type::size_type i,
16 tsp_class::cities_type::size_type k)
17 {
18 tsp_class temp_tsp_instance = tsp_instance;
19 std::reverse(temp_tsp_instance.cities.begin() + i, temp_tsp_instance.cities.begin() + k + 1);
20 return temp_tsp_instance;
21 }
22
23 #define DISTANCE_COMPARISON(v) static_cast<long>(std::floor(10000 * (v)))
24
25 void two_opt_all(tsp_class& tsp_instance)
26 {
27 bool can_continue;
28 do
29 {
30 can_continue = false;
31 auto best_distance = DISTANCE_COMPARISON(tsp_instance.do_cycle_length());
32
33 for(tsp_class::cities_type::size_type i = 1; i < tsp_instance.cities.size() 1; ++i)
34 {
35 for(tsp_class::cities_type::size_type k = i + 1; k < tsp_instance.cities.size(); ++k)
36 {
37 auto new_route = two_opt_swap(tsp_instance, i, k);
38 auto new_distance = DISTANCE_COMPARISON(new_route.do_cycle_length());
39 if (new_distance < best_distance)
40 {
41 tsp_instance = new_route;
42 can_continue = true;
43 break;
44 }
45 }
46
47 if (can_continue) break;
48 }
49 } while(can_continue);
50 }
51
52 #endif /* _two_opt_ */
C:\Users\Fabio Galuppo\Documents\Visual Studio 2012\Projects\TSPSolution\TSPSolution\src\tsp_monad.hpp 1
1 //Sample provided by Fabio Galuppo
2 //Compositional TSP Solver version 0.1
3 //October 2013
4
5 #pragma once
6 #ifndef _tsp_monad_
7 #define _tsp_monad_
8
9 /*
10 class Monad m where
11 (>>=) :: m a > (a > m b) > m b
12 return :: a > m a
13 */
14
15 //The monad laws the three fundamental laws:
16 //(return x) >>= f == f x
17 //m >>= return == m
18 //(m >>= f) >>= g == m >>= (\x > f x >>= g)
19
20 //The first law requires that return is a leftidentity with respect to >>=
21 //The second law requires that return is a rightidentity with respect to >>=
22 //The third law is a kind of associativity law for >>=
23
24 #include "tsp.hpp"
25
26 #include <memory>
27 #include <utility>
28
29 struct base_args
30 {
31 base_args(int id) : Id_(id)
32 {
33 }
34
35 virtual ~base_args()
36 {
37 }
38
39 int get_id() const
40 {
41 return Id_;
42 }
43
44 private:
45 int Id_;
46 };
47
48 typedef std::pair<std::shared_ptr<tsp_class>, base_args*> Maybe;
49
50 Maybe just(tsp_class t) { return std::make_pair(std::make_shared<tsp_class>(t), nullptr); }
51 Maybe nothing() { std::shared_ptr<tsp_class> t(nullptr); return std::make_pair(t, nullptr); }
52 bool has_value(Maybe m) { return m.first.get() != nullptr; }
53 tsp_class& ref(Maybe m) { return *m.first; }
54 const tsp_class& cref(Maybe m) { return *m.first; }
55
56 //t: shared_ptr<tsp_class> <=> Maybe
57 //ret : t > TSP t
58 //bnd : TSP t > (t > TSP t) > TSP t
59 struct TSP
60 {
61 typedef Maybe T;
62 typedef std::function<TSP(T)> transformer_type;
63
64 explicit TSP(T t) : t(t)
65 {
66 }
C:\Users\Fabio Galuppo\Documents\Visual Studio 2012\Projects\TSPSolution\TSPSolution\src\tsp_monad.hpp 2
67
68 //TODO: Semiregular
69
70 //Regular:
71 friend bool operator==(const TSP& lhs, const TSP& rhs)
72 {
73 if (!has_value(lhs.t) && !has_value(rhs.t))
74 return true;
75
76 return *(lhs.t.first) == *(rhs.t.first);
77 }
78
79 friend bool operator!=(const TSP& lhs, const TSP& rhs)
80 {
81 return !(lhs == rhs);
82 }
83
84 //map
85 TSP map(transformer_type transformer) const
86 {
87 return bnd(*this, transformer);
88 }
89
90 //map
91 template <typename U>
92 U map(std::function<U(T)> transformer) const
93 {
94 return bnd(*this, transformer);
95 }
96
97 //return
98 static friend TSP ret(T a)
99 {
100 return TSP(just(*a.first));
101 }
102
103 //bind
104 static friend TSP bnd(TSP a, transformer_type transformer)
105 {
106 auto aa = a.t;
107 if (has_value(aa))
108 return transformer(aa);
109 return TSP(nothing());
110 }
111
112 //bind
113 template <typename U>
114 static friend U bnd(TSP a, std::function<U(T)> transformer)
115 {
116 if (has(a))
117 return transformer(a.t);
118 return U();
119
120 }
121
122 static friend tsp_class& ref(TSP a)
123 {
124 return ::ref(a.t);
125 }
126
127 static friend bool has(TSP a)
128 {
129 return has_value(a.t);
130 }
131
132 private:
C:\Users\Fabio Galuppo\Documents\Visual Studio 2012\Projects\TSPSolution\TSPSolution\src\tsp_monad.hpp 3
133 T t;
134 };
135
136 Maybe just(TSP t) { return just(ref(t)); }
137
138 #endif /* _tsp_monad_ */
C:\Users\Fabio Galuppo\Documents\Visual Studio ...\TSPSolution\TSPSolution\src\tsp_functors.hpp 1
1 //Sample provided by Fabio Galuppo
2 //Compositional TSP Solver version 0.1
3 //October 2013
4
5 #pragma once
6 #ifndef _tsp_functors_
7 #define _tsp_functors_
8
9 #include "tsp.hpp"
10 #include "tsp_monad.hpp"
11
12 TSP Propagator(const TSP& oldValue, const TSP& newValue, bool propagate_inferior_results = false)
13 {
14 //accept inferior results (if it's an inferior result!)
15 if (propagate_inferior_results)
16 return newValue;
17
18 //do not propagate inferior results
19 if (ref(oldValue).do_cycle_length() > ref(newValue).do_cycle_length())
20 return newValue;
21
22 return oldValue;
23 };
24
25 enum base_args_id
26 {
27 FORK_JOIN_ARGS_ID = 1
28 };
29
30 struct Chain
31 {
32 typedef TSP::transformer_type F;
33
34 Chain(F f0)
35 {
36 Funcs_.push_back(f0);
37 }
38
39 Chain(F f0, F f1)
40 {
41 Funcs_.push_back(f0);
42 Funcs_.push_back(f1);
43 }
44
45 Chain(F f0, F f1, F f2)
46 {
47 Funcs_.push_back(f0);
48 Funcs_.push_back(f1);
49 Funcs_.push_back(f2);
50 }
51
52 Chain(F f0, F f1, F f2, F f3)
53 {
54 Funcs_.push_back(f0);
55 Funcs_.push_back(f1);
56 Funcs_.push_back(f2);
57 Funcs_.push_back(f3);
58 }
59
60 Chain(F f0, F f1, F f2, F f3, F f4)
61 {
62 Funcs_.push_back(f0);
63 Funcs_.push_back(f1);
64 Funcs_.push_back(f2);
65 Funcs_.push_back(f3);
66 Funcs_.push_back(f4);
C:\Users\Fabio Galuppo\Documents\Visual Studio ...\TSPSolution\TSPSolution\src\tsp_functors.hpp 2
67 }
68
69 Chain(F f0, F f1, F f2, F f3, F f4, F f5)
70 {
71 Funcs_.push_back(f0);
72 Funcs_.push_back(f1);
73 Funcs_.push_back(f2);
74 Funcs_.push_back(f3);
75 Funcs_.push_back(f4);
76 Funcs_.push_back(f5);
77 }
78
79 //...
80
81 TSP operator()(TSP::T t)
82 {
83 for(auto f = Funcs_.cbegin(); f != Funcs_.cend(); ++f)
84 (*f)(t);
85 return TSP(t);
86 }
87
88 private:
89 std::vector<F> Funcs_;
90 };
91
92 struct ForkJoin_args : public base_args
93 {
94 ForkJoin_args(unsigned int i, unsigned int number_of_tasks_in_parallel) :
95 base_args(FORK_JOIN_ARGS_ID),
96 i(i),
97 number_of_tasks_in_parallel(number_of_tasks_in_parallel) {}
98 const unsigned int i;
99 const unsigned int number_of_tasks_in_parallel;
100 };
101
102 #include <future>
103 #include <memory>
104
105 struct ForkJoin
106 {
107 typedef TSP::transformer_type F;
108
109 ForkJoin(unsigned int number_of_tasks_in_parallel, F f, bool propagate_inferior_results = false) :
110 NumberOfTasksInParallel_(number_of_tasks_in_parallel),
111 Func_(f),
112 PropagateInferiorResults_(propagate_inferior_results)
113 {
114 }
115
116 TSP operator()(TSP::T t)
117 {
118 if (0 == NumberOfTasksInParallel_)
119 return TSP(t);
120
121 std::vector<std::future<tsp_async_state>> tsp_solutions;
122
123 std::cout << "START SOLUTION:" << std::endl;
124
125 auto tsp_instance = ref(t);
126 display_solution(tsp_instance);
127
128 for (unsigned int i = 0; i < NumberOfTasksInParallel_; ++i)
129 {
130 //async
131 tsp_solutions.push_back(std::async(std::launch::async, [&, i, tsp_instance]
132 {
C:\Users\Fabio Galuppo\Documents\Visual Studio ...\TSPSolution\TSPSolution\src\tsp_functors.hpp 3
133 Maybe a = just(tsp_instance);
134 std::unique_ptr<ForkJoin_args> args(new ForkJoin_args(i, NumberOfTasksInParallel_));
135 a.second = args.get();
136 return tsp_async_state(Func_(a));
137 }));
138 }
139
140 std::cout << "CANDIDATE SOLUTIONS:" << std::endl;
141 std::vector<tsp_class> candidate_solutions;
142 int i = 0;
143 for (auto& tsp_solution : tsp_solutions)
144 {
145 //async result
146 auto candidate = tsp_solution.get();
147 if (has(candidate.state))
148 {
149 candidate_solutions.push_back(ref(candidate.state));
150 display(ref(candidate.state), false);
151 }
152 }
153
154 std::cout << "CANDIDATE LENGTHS:" << std::endl;
155 for (auto& solution : candidate_solutions)
156 std::cout << solution.do_cycle_length() << std::endl;
157
158 std::sort(candidate_solutions.begin(), candidate_solutions.end(),
159 [](const tsp_class& left, const tsp_class& right)
160 { return left.do_cycle_length() < right.do_cycle_length(); });
161
162 std::cout << "CANDIDATE LENGTHS (ORDERED):" << std::endl;
163 for (auto& solution : candidate_solutions)
164 std::cout << solution.do_cycle_length() << std::endl;
165
166 std::cout << "SELECTED SOLUTION:" << std::endl;
167 auto result = Propagator(TSP(t), TSP(just(*candidate_solutions.begin())),
PropagateInferiorResults_);
168 display_solution(ref(result));
169 return result;
170 }
171
172 private:
173 unsigned int NumberOfTasksInParallel_;
174 F Func_;
175 bool PropagateInferiorResults_;
176
177 static void display_solution(tsp_class& tsp_instance)
178 {
179 display(tsp_instance, true);
180 std::cout << tsp_instance.do_cycle_length() << std::endl;
181 }
182
183 struct tsp_async_state
184 {
185 tsp_async_state()
186 : state(TSP(nothing())) {}
187 explicit tsp_async_state(const TSP& state)
188 : state(state) {}
189 TSP state;
190 };
191 };
192
193 struct Generations
194 {
195 typedef TSP::transformer_type F;
196
197 Generations(unsigned int number_of_generations, F f) :
C:\Users\Fabio Galuppo\Documents\Visual Studio ...\TSPSolution\TSPSolution\src\tsp_functors.hpp 4
198 NumberOfGenerations_(number_of_generations),
199 Func_(f)
200 {
201 }
202
203 TSP operator()(TSP::T t)
204 {
205 TSP::T result = t;
206 for(unsigned int g = 0; g < NumberOfGenerations_; ++g)
207 {
208 std::cout << "GENERATION:" << g + 1 << std::endl;
209 auto new_result = Func_(result);
210 result = just(new_result);
211 }
212 return TSP(result);
213 }
214
215 private:
216 unsigned int NumberOfGenerations_;
217 F Func_;
218 };
219
220 struct Identity
221 {
222 TSP operator()(TSP::T t)
223 {
224 return TSP(t);
225 }
226 };
227
228 #include <atomic>
229
230 struct Circular
231 {
232 typedef TSP::transformer_type F;
233
234 Circular(F f0) :
235 MaxCount_(1)
236 {
237 Counter_ = 0;
238 Funcs_.push_back(f0);
239 }
240
241 Circular(F f0, F f1) :
242 MaxCount_(2)
243 {
244 Counter_ = 0;
245 Funcs_.push_back(f0);
246 Funcs_.push_back(f1);
247 }
248
249 Circular(F f0, F f1, F f2) :
250 MaxCount_(3)
251 {
252 Counter_ = 0;
253 Funcs_.push_back(f0);
254 Funcs_.push_back(f1);
255 Funcs_.push_back(f2);
256 }
257
258 Circular(F f0, F f1, F f2, F f3) :
259 MaxCount_(4)
260 {
261 Counter_ = 0;
262 Funcs_.push_back(f0);
263 Funcs_.push_back(f1);
C:\Users\Fabio Galuppo\Documents\Visual Studio ...\TSPSolution\TSPSolution\src\tsp_functors.hpp 5
264 Funcs_.push_back(f2);
265 Funcs_.push_back(f3);
266 }
267
268 Circular(F f0, F f1, F f2, F f3, F f4) :
269 MaxCount_(5)
270 {
271 Counter_ = 0;
272 Funcs_.push_back(f0);
273 Funcs_.push_back(f1);
274 Funcs_.push_back(f2);
275 Funcs_.push_back(f3);
276 Funcs_.push_back(f4);
277 }
278
279 Circular(F f0, F f1, F f2, F f3, F f4, F f5) :
280 MaxCount_(6)
281 {
282 Counter_ = 0;
283 Funcs_.push_back(f0);
284 Funcs_.push_back(f1);
285 Funcs_.push_back(f2);
286 Funcs_.push_back(f3);
287 Funcs_.push_back(f4);
288 Funcs_.push_back(f5);
289 }
290
291 //...
292
293 TSP operator()(TSP::T t)
294 {
295 Funcs_[Counter_++ % MaxCount_](t);
296 return TSP(t);
297 }
298
299 private:
300 std::vector<F> Funcs_;
301 std::atomic_int Counter_;
302 const unsigned int MaxCount_;
303 };
304
305 #endif /* _tsp_functors_ */
C:\Users\Fabio Galuppo\Documents\Visual Studio 2012\Projects\TSPSolution\TSPSolution\src\tsp_algo.hpp 1
1 //Sample provided by Fabio Galuppo
2 //Compositional TSP Solver version 0.1
3 //October 2013
4
5 #pragma once
6 #ifndef _tsp_algo_
7 #define _tsp_algo_
8
9 #include "tsp.hpp"
10 #include "tsp_monad.hpp"
11 #include "tsp_functors.hpp"
12 #include "algorithms\ant_colony_optimization.hpp"
13 #include "algorithms\simulated_annealing.hpp"
14 #include "algorithms\nearest_neighbour.hpp"
15 #include "algorithms\two_opt.hpp"
16 #include "algorithms\genetic_algorithm.hpp"
17 #include "randomizers.hpp"
18
19 void get_base_args(unsigned int& i, unsigned int& n, base_args* args)
20 {
21 if (nullptr != args)
22 {
23 if (args>get_id() == base_args_id::FORK_JOIN_ARGS_ID)
24 {
25 auto ptr = dynamic_cast<ForkJoin_args*>(args);
26 i = ptr>i;
27 n = ptr>number_of_tasks_in_parallel;
28 }
29 }
30 }
31
32 struct SA
33 {
34 SA(const double initial_temperature,
35 const double stopping_criteria_temperature,
36 const double decreasing_factor,
37 const int monte_carlo_steps) :
38 InitialTemperature_(initial_temperature),
39 StoppingCriteriaTemperature_(stopping_criteria_temperature),
40 DecreasingFactor_(decreasing_factor),
41 MonteCarloSteps_(monte_carlo_steps)
42 {
43 }
44
45 TSP operator()(TSP::T t)
46 {
47 unsigned int i = 0, n = 1;
48 get_base_args(i, n, t.second);
49
50 const auto N = ref(t).cities.size();
51 random_functor delay(1, static_cast<int>(n * 2));
52 auto seed = static_cast<unsigned>(std::time(nullptr));
53 auto rnd_tsp(random_functor(N, seed + i * delay()));
54
55 simulated_annealing(InitialTemperature_, StoppingCriteriaTemperature_,
56 DecreasingFactor_, MonteCarloSteps_, ref(t),
57 rnd_tsp, double_random_functor());
58 return TSP(t);
59 }
60
61 private:
62 const double InitialTemperature_;
63 const double StoppingCriteriaTemperature_;
64 const double DecreasingFactor_;
65 const int MonteCarloSteps_;
66 };
C:\Users\Fabio Galuppo\Documents\Visual Studio 2012\Projects\TSPSolution\TSPSolution\src\tsp_algo.hpp 2
67
68 #include <vector>
69
70 struct ACO
71 {
72 ACO(const unsigned int aco_iterations,
73 const ants_type::size_type number_of_ants,
74 const double base_pheromone,
75 const double favor_pheromone_level_over_distance,
76 const double favor_distance_over_pheromone_level,
77 const double value_for_intensification_and_evaporation,
78 const double pheronome_distribution) :
79 ACOIterations_(aco_iterations),
80 NumberOfAnts_(number_of_ants),
81 BasePheromone_(base_pheromone),
82 FavorPheromoneLevelOverDistance_(favor_pheromone_level_over_distance),
83 FavorDistanceOverPheromoneLevel_(favor_distance_over_pheromone_level),
84 ValueForIntensificationAndEvaporation_(value_for_intensification_and_evaporation),
85 PheronomeDistribution_(pheronome_distribution)
86 {
87 }
88
89 TSP operator()(TSP::T t)
90 {
91 unsigned int i = 0, n = 1;
92 get_base_args(i, n, t.second);
93
94 auto seed = static_cast<unsigned>(std::time(nullptr));
95 random_functor delay(1, static_cast<int>(n * 10));
96
97 ant_colony_optimization(ref(t), BasePheromone_, ACOIterations_, NumberOfAnts_,
98 FavorPheromoneLevelOverDistance_, FavorDistanceOverPheromoneLevel_,
99 ValueForIntensificationAndEvaporation_, PheronomeDistribution_, seed +
i * delay());
100 return TSP(t);
101 };
102
103 private:
104 const double BasePheromone_;
105 const unsigned int ACOIterations_;
106 const ants_type::size_type NumberOfAnts_;
107 const double FavorPheromoneLevelOverDistance_;
108 const double FavorDistanceOverPheromoneLevel_;
109 const double ValueForIntensificationAndEvaporation_;
110 const double PheronomeDistribution_;
111 };
112
113 struct _2OPT
114 {
115 TSP operator()(TSP::T t)
116 {
117 two_opt_all(ref(t));
118 return TSP(t);
119 }
120 };
121
122 struct NN
123 {
124 TSP operator()(TSP::T t)
125 {
126 nearest_neighbour(ref(t));
127 return TSP(t);
128 };
129 };
130
131 struct GA
C:\Users\Fabio Galuppo\Documents\Visual Studio 2012\Projects\TSPSolution\TSPSolution\src\tsp_algo.hpp 3
132 {
133 GA(const unsigned int population_size,
134 const unsigned int mutation_percentage,
135 const unsigned int group_size,
136 const unsigned int number_of_generations,
137 const unsigned int nearby_cities,
138 const double nearby_cities_percentage) :
139 PopulationSize_(population_size),
140 MutationPercentage_(mutation_percentage),
141 GroupSize_(group_size),
142 NumberOfGenerations_(number_of_generations),
143 NearbyCities_(nearby_cities),
144 NearbyCitiesPercentage_(nearby_cities_percentage)
145 {
146 }
147
148 TSP operator()(TSP::T t)
149 {
150 unsigned int i = 0, n = 1;
151 get_base_args(i, n, t.second);
152
153 auto seed = static_cast<unsigned>(std::time(nullptr));
154 random_functor delay(1, static_cast<int>(n * 10));
155
156 genetic_algorithm(ref(t), PopulationSize_, MutationPercentage_,
157 GroupSize_, NumberOfGenerations_, NearbyCities_, NearbyCitiesPercentage_, seed + i * delay
());
158 return TSP(t);
159 }
160
161 private:
162 const unsigned int PopulationSize_;
163 const unsigned int MutationPercentage_;
164 const unsigned int GroupSize_;
165 const unsigned int NumberOfGenerations_;
166 const unsigned int NearbyCities_;
167 const double NearbyCitiesPercentage_;
168 };
169
170 #endif /* _tsp_algo_ */
C:\Users\Fabio Galuppo\Documents\Visual Studio ...\TSPSolution\TSPSolution\src\_tsp_support.hpp 1
1 //Sample provided by Fabio Galuppo
2 //Compositional TSP Solver version 0.1
3 //October 2013
4
5 #pragma once
6 #ifndef __tsp_support_
7 #define __tsp_support_
8
9 struct GeneralArgs
10 {
11 GeneralArgs(const unsigned int number_of_iterations_or_generations, const unsigned int
number_of_tasks_in_parallel) :
12 number_of_iterations_or_generations(number_of_iterations_or_generations),
13 number_of_tasks_in_parallel(number_of_tasks_in_parallel)
14 {
15 }
16
17 const unsigned int number_of_iterations_or_generations;
18 const unsigned int number_of_tasks_in_parallel;
19 };
20
21 struct SAArgs
22 {
23 SAArgs(const double initial_temperature,
24 const double stopping_criteria_temperature,
25 const double decreasing_factor,
26 const int monte_carlo_steps) :
27 initial_temperature(initial_temperature),
28 stopping_criteria_temperature(stopping_criteria_temperature),
29 decreasing_factor(decreasing_factor),
30 monte_carlo_steps(monte_carlo_steps)
31 {
32 }
33
34 const double initial_temperature;
35 const double stopping_criteria_temperature;
36 const double decreasing_factor;
37 const int monte_carlo_steps;
38 };
39
40 struct ACOArgs
41 {
42 ACOArgs(const unsigned int aco_iterations,
43 const ants_type::size_type number_of_ants,
44 const double base_pheromone,
45 const double favor_pheromone_level_over_distance,
46 const double favor_distance_over_pheromone_level,
47 const double value_for_intensification_and_evaporation,
48 const double pheronome_distribution) :
49 aco_iterations(aco_iterations),
50 number_of_ants(number_of_ants),
51 base_pheromone(base_pheromone),
52 favor_pheromone_level_over_distance(favor_pheromone_level_over_distance),
53 favor_distance_over_pheromone_level(favor_distance_over_pheromone_level),
54 value_for_intensification_and_evaporation(value_for_intensification_and_evaporation),
55 pheronome_distribution(pheronome_distribution)
56 {
57 }
58
59 const unsigned int aco_iterations;
60 const ants_type::size_type number_of_ants;
61 const double base_pheromone;
62 const double favor_pheromone_level_over_distance;
63 const double favor_distance_over_pheromone_level;
64 const double value_for_intensification_and_evaporation;
65 const double pheronome_distribution;
C:\Users\Fabio Galuppo\Documents\Visual Studio ...\TSPSolution\TSPSolution\src\_tsp_support.hpp 2
66 };
67
68 struct GAArgs
69 {
70 GAArgs(const unsigned int population_size,
71 const unsigned int mutation_percentage,
72 const unsigned int group_size,
73 const unsigned int number_of_generations,
74 const unsigned int nearby_cities,
75 const double nearby_cities_percentage) :
76 population_size(population_size),
77 mutation_percentage(mutation_percentage),
78 group_size(group_size),
79 number_of_generations(number_of_generations),
80 nearby_cities(nearby_cities),
81 nearby_cities_percentage(nearby_cities_percentage)
82 {
83 }
84
85 const unsigned int population_size;
86 const unsigned int mutation_percentage;
87 const unsigned int group_size;
88 const unsigned int number_of_generations;
89 const unsigned int nearby_cities;
90 const double nearby_cities_percentage;
91 };
92
93 typedef GeneralArgs General_args_type;
94 typedef SAArgs SA_args_type;
95 typedef ACOArgs ACO_args_type;
96 typedef GAArgs GA_args_type;
97
98 General_args_type
99 make_General_args(const unsigned int number_of_iterations_or_generations, const unsigned int
number_of_tasks_in_parallel)
100 {
101 return General_args_type(number_of_iterations_or_generations, number_of_tasks_in_parallel);
102 }
103
104 SA_args_type
105 make_SA_args(const double initial_temperature,
106 const double stopping_criteria_temperature,
107 const double decreasing_factor,
108 const int monte_carlo_steps)
109 {
110 return SA_args_type(initial_temperature, stopping_criteria_temperature, decreasing_factor,
monte_carlo_steps);
111 }
112
113 ACO_args_type
114 make_ACO_args(const unsigned int aco_iterations,
115 const ants_type::size_type number_of_ants,
116 const double base_pheromone,
117 const double favor_pheromone_level_over_distance,
118 const double favor_distance_over_pheromone_level,
119 const double value_for_intensification_and_evaporation,
120 const double pheronome_distribution)
121 {
122 return ACO_args_type(aco_iterations, number_of_ants, base_pheromone,
123 favor_pheromone_level_over_distance, favor_distance_over_pheromone_level,
124 value_for_intensification_and_evaporation, pheronome_distribution);
125 }
126
127 GA_args_type
128 make_GA_args(const unsigned int population_size,
129 const unsigned int mutation_percentage,
C:\Users\Fabio Galuppo\Documents\Visual Studio ...\TSPSolution\TSPSolution\src\_tsp_support.hpp 3
130 const unsigned int group_size,
131 const unsigned int number_of_generations,
132 const unsigned int nearby_cities,
133 const double nearby_cities_percentage)
134 {
135 return GA_args_type(population_size, mutation_percentage, group_size,
136 number_of_generations, nearby_cities, nearby_cities_percentage);
137 }
138
139 #include <vector>
140 typedef std::vector<General_args_type> General_args_type_collection;
141 typedef std::vector<SA_args_type> SA_args_type_collection;
142 typedef std::vector<ACO_args_type> ACO_args_type_collection;
143 typedef std::vector<GA_args_type> GA_args_type_collection;
144
145 void display_args(const char* description,
146 const General_args_type_collection& gs,
147 const SA_args_type_collection& sas,
148 const ACO_args_type_collection& acos,
149 const GA_args_type_collection& gas)
150 {
151 std::cout << "SOLUTION ARGUMENTS:" << std::endl;
152
153 std::cout << description << std::endl;
154
155 if (gs.size() > 0)
156 {
157 std::cout << "GENERAL ARGUMENTS:" << std::endl;
158 int count = 0;
159 for(auto i = gs.cbegin(); i != gs.cend(); ++i)
160 {
161 std::cout << " #" << ++count << ":"<< std::endl;
162 std::cout << " Number of Iterations or Generations = " << i->
number_of_iterations_or_generations << std::endl;
163 std::cout << " Number of Tasks in Parallel = " << i->number_of_tasks_in_parallel << std::
endl;
164 //std::cout << "Propagate Inferior Results Across Generations = " << (p ? "true" : "false")
<< std::endl;
165 }
166 }
167
168 if (sas.size() > 0)
169 {
170 std::cout << "SIMULATED ANNEALING ARGUMENTS:" << std::endl;
171 int count = 0;
172 for(auto i = sas.cbegin(); i != sas.cend(); ++i)
173 {
174 std::cout << " #" << ++count << ":"<< std::endl;
175 std::cout << " Initial Temperature = " << i->initial_temperature << std::endl;
176 std::cout << " Stopping Criteria Temperature = " << i->stopping_criteria_temperature <<
std::endl;
177 std::cout << " Decreasing Factor = " << i->decreasing_factor << std::endl;
178 std::cout << " Monte Carlo Steps = " << i->monte_carlo_steps << std::endl;
179 }
180 }
181
182 if (acos.size() > 0)
183 {
184 std::cout << "ANT COLONY OPTIMIZATION ARGUMENTS:" << std::endl;
185 int count = 0;
186 for(auto i = acos.cbegin(); i != acos.cend(); ++i)
187 {
188 std::cout << " #" << ++count << ":"<< std::endl;
189 std::cout << " ACO Iterations = " << i->aco_iterations << std::endl;
190 std::cout << " Number of Ants = " << i->number_of_ants << std::endl;
191 std::cout << " Base Pheromone = " << i->base_pheromone << std::endl;
C:\Users\Fabio Galuppo\Documents\Visual Studio ...\TSPSolution\TSPSolution\src\_tsp_support.hpp 4
192 std::cout << " Favor Pheromone Level over Distance = " << i->
favor_pheromone_level_over_distance << std::endl;
193 std::cout << " Favor Distance over Pheromone Level = " << i->
favor_distance_over_pheromone_level << std::endl;
194 std::cout << " Intensification and Evaporation Value = " << i->
value_for_intensification_and_evaporation << std::endl;
195 std::cout << " Pheromone Distribution = " << i->pheronome_distribution << std::endl;
196 }
197 }
198
199 if (gas.size() > 0)
200 {
201 std::cout << "GENETIC ALGORITHM ARGUMENTS:" << std::endl;
202 int count = 0;
203 for(auto i = gas.cbegin(); i != gas.cend(); ++i)
204 {
205 std::cout << " #" << ++count << ":"<< std::endl;
206 std::cout << " Population Size = " << i->population_size << std::endl;
207 std::cout << " Mutation Percentage = " << i->mutation_percentage << std::endl;
208 std::cout << " Group Size = " << i->group_size << std::endl;
209 std::cout << " Number of Generations = " << i->number_of_generations << std::endl;
210 std::cout << " Nearby Cities = " << i->nearby_cities << std::endl;
211 std::cout << " Nearby Cities Percentage = " << i->nearby_cities_percentage << std::endl;
212 }
213 }
214
215 std::cout << "--------------------------------------------------" << std::endl;
216 }
217
218 template <typename A>
219 struct Args
220 {
221 typedef std::vector<A> collection_type;
222
223 operator collection_type() const
224 {
225 return collection;
226 }
227
228 Args()
229 {
230 }
231
232 Args(A a0)
233 {
234 collection.push_back(a0);
235 }
236
237 Args(A a0, A a1)
238 {
239 collection.push_back(a0);
240 collection.push_back(a1);
241 }
242
243 Args(A a0, A a1, A a2)
244 {
245 collection.push_back(a0);
246 collection.push_back(a1);
247 collection.push_back(a2);
248 }
249
250 Args(A a0, A a1, A a2, A a3)
251 {
252 collection.push_back(a0);
253 collection.push_back(a1);
254 collection.push_back(a2);
C:\Users\Fabio Galuppo\Documents\Visual Studio ...\TSPSolution\TSPSolution\src\_tsp_support.hpp 5
255 collection.push_back(a3);
256 }
257
258 Args(A a0, A a1, A a2, A a3, A a4)
259 {
260 collection.push_back(a0);
261 collection.push_back(a1);
262 collection.push_back(a2);
263 collection.push_back(a3);
264 collection.push_back(a4);
265 }
266
267 Args(A a0, A a1, A a2, A a3, A a4, A a5)
268 {
269 collection.push_back(a0);
270 collection.push_back(a1);
271 collection.push_back(a2);
272 collection.push_back(a3);
273 collection.push_back(a4);
274 collection.push_back(a5);
275 }
276
277 //...
278
279 typename collection_type::const_reference operator[](typename collection_type::size_type index)
const
280 {
281 return collection[index];
282 }
283
284 typename collection_type::reference operator[](typename collection_type::size_type index)
285 {
286 return collection[index];
287 }
288
289 collection_type collection;
290 };
291
292 #endif /* __tsp_support_ */
C:\Users\Fabio Galuppo\Documents\Visual Studio 2012\Projects\TSPSolution\TSPSolution\src\_tsp.hpp 1
1 //Sample provided by Fabio Galuppo
2 //Compositional TSP Solver version 0.1
3 //October 2013
4
5 #pragma once
6 #ifndef __tsp_
7 #define __tsp_
8
9 #include "tsp.hpp"
10 #include "tsp_algo.hpp"
11
12 enum struct DisplayFlags
13 {
14 None = 0,
15 EmitMathematicaGraphPlot = 1,
16 DisplaySeparator = 2,
17 All = EmitMathematicaGraphPlot | DisplaySeparator
18 };
19
20 struct Display
21 {
22 Display(const char* text, DisplayFlags flags = DisplayFlags::None)
23 : Text_(text), DisplayFlags_(flags)
24 {
25 }
26
27 TSP operator()(TSP::T t)
28 {
29 std::cout << Text_ << ":" << std::endl;
30 display(ref(t), has_flag(DisplayFlags::EmitMathematicaGraphPlot));
31 if (has_flag(DisplayFlags::DisplaySeparator))
32 std::cout << "" << std::endl;
33 return TSP(t);
34 }
35
36 private:
37 bool has_flag(DisplayFlags flag)
38 {
39 return static_cast<unsigned int>(flag) == (static_cast<unsigned int>(DisplayFlags_) &
static_cast<unsigned int>(flag));
40 }
41
42 const char* Text_;
43 DisplayFlags DisplayFlags_;
44 };
45
46 #include <chrono>
47
48 struct stop_watch
49 {
50 stop_watch() :
51 Start_(now())
52 {
53 }
54
55 std::chrono::milliseconds elapsed_ms() const
56 {
57 return std::chrono::duration_cast<std::chrono::milliseconds>(now() Start_);
58 }
59
60 void restart() { Start_ = now(); }
61
62 private:
63 static std::chrono::high_resolution_clock::time_point now()
64 {
65 return std::chrono::high_resolution_clock::now();
C:\Users\Fabio Galuppo\Documents\Visual Studio 2012\Projects\TSPSolution\TSPSolution\src\_tsp.hpp 2
66 }
67
68 std::chrono::high_resolution_clock::time_point Start_;
69 };
70
71 struct Measure
72 {
73 typedef TSP::transformer_type F;
74
75 Measure(F f, F p = Identity()) : AlgoFunc_(f), PrintFunc_(p)
76 {
77 }
78
79 TSP operator()(TSP::T t)
80 {
81 stop_watch sw;
82 auto result = AlgoFunc_(t);
83 auto elapsed_ms = sw.elapsed_ms().count();
84 bnd(result, PrintFunc_);
85 std::cout << elapsed_ms << " ms" << std::endl;
86 std::cout << "" << std::endl;
87 return result;
88 }
89
90 private:
91 F AlgoFunc_, PrintFunc_;
92 };
93
94 #include <cstdlib>
95
96 tsp_class read_tsp_instance()
97 {
98 tsp_class tsp_instance;
99
100 //read an instance of tsp
101 int N;
102 std::cin >> N;
103 if (N > 1)
104 {
105 int city_number = 0;
106 for(int i = 0; i < N; ++i)
107 {
108 int x, y;
109 std::cin >> x >> y;
110 tsp_class::city_info info = { ++city_number, std::make_pair(x, y) };
111 tsp_instance.cities.push_back(info);
112 }
113 }
114 else
115 {
116 std::cerr << "N must be greater than 1" << std::endl;
117 std::exit(1);
118 }
119
120 return tsp_instance;
121 }
122
123 #include "_tsp_support.hpp"
124
125 #endif /* __tsp_ */
C:\Users\Fabio Galuppo\Documents\Visual Studio 2012\Projects\TSPSolution\TSPSolution\program.cpp 1
1 //Sample provided by Fabio Galuppo
2 //Compositional TSP Solver version 0.1
3 //November 2013
4
5 #include "src\_tsp.hpp"
6
7 tsp_class read_att48_tsp()
8 {
9 int coords[] = {
10 6734, 1453,
11 2233, 10,
12 5530, 1424,
13 401, 841,
14 3082, 1644,
15 7608, 4458,
16 7573, 3716,
17 7265, 1268,
18 6898, 1885,
19 1112, 2049,
20 5468, 2606,
21 5989, 2873,
22 4706, 2674,
23 4612, 2035,
24 6347, 2683,
25 6107, 669,
26 7611, 5184,
27 7462, 3590,
28 7732, 4723,
29 5900, 3561,
30 4483, 3369,
31 6101, 1110,
32 5199, 2182,
33 1633, 2809,
34 4307, 2322,
35 675, 1006,
36 7555, 4819,
37 7541, 3981,
38 3177, 756,
39 7352, 4506,
40 7545, 2801,
41 3245, 3305,
42 6426, 3173,
43 4608, 1198,
44 23, 2216,
45 7248, 3779,
46 7762, 4595,
47 7392, 2244,
48 3484, 2829,
49 6271, 2135,
50 4985, 140,
51 1916, 1569,
52 7280, 4899,
53 7509, 3239,
54 10, 2676,
55 6807, 2993,
56 5185, 3258,
57 3023, 1942
58 };
59
60 tsp_class tsp_instance;
61 int N = sizeof(coords) / sizeof(int);
62 int city_number = 0;
63 for(int i = 0; i < N; i+=2)
64 {
65 int x = coords[i], y = coords[i+1];
66 tsp_class::city_info info = { ++city_number, std::make_pair(x, y) };
C:\Users\Fabio Galuppo\Documents\Visual Studio 2012\Projects\TSPSolution\TSPSolution\program.cpp 2
67 tsp_instance.cities.push_back(info);
68 }
69
70 return tsp_instance;
71 }
72
73 /*
74 getopt
75 declaration: http://svnweb.freebsd.org/base/stable/9/include/unistd.h?view=markup
76 definition: http://svnweb.freebsd.org/base/stable/9/lib/libc/stdlib/getopt.c?view=markup
77 */
78 #include <stdio.h>
79 #include <stdlib.h>
80 #include <string.h>
81
82 int opterr = 1, optind = 1, optopt, optreset;
83 char *optarg;
84
85 #define BADCH (int)'?'
86 #define BADARG (int)':'
87 #define EMSG ""
88
89 /*
90 * getopt --
91 * Parse argc/argv argument vector.
92 */
93 int getopt(int nargc, char * const nargv[], const char *ostr)
94 {
95 static char *place = EMSG; /* option letter processing */
96 char *oli; /* option letter list index */
97
98 if (optreset || *place == 0) { /* update scanning pointer */
99 optreset = 0;
100 place = nargv[optind];
101 if (optind >= nargc || *place++ != '-') {
102 /* Argument is absent or is not an option */
103 place = EMSG;
104 return (-1);
105 }
106 optopt = *place++;
107 if (optopt == '-' && *place == 0) {
108 /* "--" => end of options */
109 ++optind;
110 place = EMSG;
111 return (-1);
112 }
113 if (optopt == 0) {
114 /* Solitary '-', treat as a '-' option
115 if the program (eg su) is looking for it. */
116 place = EMSG;
117 if (strchr(ostr, '-') == NULL)
118 return (-1);
119 optopt = '-';
120 }
121 } else
122 optopt = *place++;
123
124 /* See if option letter is one the caller wanted... */
125 //if (optopt == ':' || (oli = strchr(ostr, optopt)) == NULL) {
126 if (optopt == ':' || (oli = const_cast<char*>(strchr(ostr, optopt))) == NULL) {
127 if (*place == 0)
128 ++optind;
129 if (opterr && *ostr != ':')
130 (void)fprintf(stderr,
131 //"%s: illegal option -- %c\n", _getprogname(),
132 "%s: illegal option -- %c\n", "getopt",
C:\Users\Fabio Galuppo\Documents\Visual Studio 2012\Projects\TSPSolution\TSPSolution\program.cpp 3
133 optopt);
134 return (BADCH);
135 }
136
137 /* Does this option need an argument? */
138 if (oli[1] != ':') {
139 /* don't need argument */
140 optarg = NULL;
141 if (*place == 0)
142 ++optind;
143 } else {
144 /* Option-argument is either the rest of this argument or the
145 entire next argument. */
146 if (*place)
147 optarg = place;
148 else if (nargc > ++optind)
149 optarg = nargv[optind];
150 else {
151 /* option-argument absent */
152 place = EMSG;
153 if (*ostr == ':')
154 return (BADARG);
155 if (opterr)
156 (void)fprintf(stderr,
157 "%s: option requires an argument -- %c\n",
158 //_getprogname(), optopt);
159 "getopt", optopt);
160 return (BADCH);
161 }
162 place = EMSG;
163 ++optind;
164 }
165 return (optopt); /* return option letter */
166 }
167
168 #include <iostream>
169
170 void usage(void)
171 {
172 std::cerr << "usage: tspsolution -p:N -g:N -n:N" << std::endl;
173 std::cerr << "where" << std::endl;
174 std::cerr << " p: pipeline number" << std::endl;
175 std::cerr << " g: number of generations" << std::endl;
176 std::cerr << " n: number of tasks" << std::endl;
177 std::cerr << " N: an integer greater than 0" << std::endl;
178
179 exit(1);
180 }
181
182 void get_args(int& argc, char* argv[], unsigned int& p, unsigned int& g, unsigned int& n)
183 {
184 int ch;
185 setlocale(LC_CTYPE, "");
186 while ((ch = getopt(argc, argv, "p:g:n:")) != -1)
187 {
188 switch((char)ch)
189 {
190 case 'p': //pipeline #
191 ++optarg;
192 p = static_cast<unsigned int>(atol(optarg));
193 break;
194 case 'g': //generations #
195 ++optarg;
196 g = static_cast<unsigned int>(atol(optarg));
197 break;
198 case 'n': //tasks #
C:\Users\Fabio Galuppo\Documents\Visual Studio 2012\Projects\TSPSolution\TSPSolution\program.cpp 4
199 ++optarg;
200 n = static_cast<unsigned int>(atol(optarg));
201 break;
202 case '?':
203 default:
204 usage();
205 }
206 }
207
208 if (0 == p || 0 == g || 0 == n)
209 usage();
210
211 argv += optind;
212 argc -= optind;
213 }
214
215 #include <utility>
216 #include <functional>
217 #include <vector>
218
219 typedef std::function<void(tsp_class&, unsigned int, unsigned int)> pipeline_type;
220
221 TSP make_TSP(const tsp_class& tsp_instance) { return TSP(just(tsp_instance)); }
222
223 void MonadicLawsProofing()
224 {
225 //Scala notation: unit(x) flatMap f == f(x)
226 {
227 //Left Identity (1st Law)
228 auto x = just(read_att48_tsp());
229
230 auto f = [](TSP::T t){ return ref(t).do_cycle_length(); };
231
232 double fun_result = bnd<double>(ret(x), f); //functional composition
233 double oo_result = ret(x).map<double>(f); //object-oriented
234
235 bool fun_holds = fun_result == f(x);
236 bool oo_holds = oo_result == f(x);
237
238 std::cout << "1st Law (Left Identity) " << (fun_holds ? "holds" : "doesn't hold") << std::endl;
239 std::cout << "1st Law (Left Identity) " << (oo_holds ? "holds" : "doesn't hold") << std::endl;
240 }
241
242 //Scala notation: m flatMap unit == m
243 {
244 //Right Identity (2nd Law)
245 auto m = make_TSP(read_att48_tsp());
246
247 auto fun_result = bnd(m, ret);
248 auto oo_result = m.map(ret);
249
250 bool fun_holds = fun_result == m;
251 bool oo_holds = oo_result == m;
252
253 std::cout << "2nd Law (Right Identity) " << (fun_holds ? "holds" : "doesn't hold") << std::endl
;
254 std::cout << "2nd Law (Right Identity) " << (oo_holds ? "holds" : "doesn't hold") << std::endl;
255 }
256
257 //Scala notation: m flatMap f flatMap g == m flatMap (x => f(x) flatMap g)
258 {
259 //Associativity (3rd Law)
260 auto m = make_TSP(read_att48_tsp());
261
262 auto f = [](TSP::T t) -> TSP
263 {
C:\Users\Fabio Galuppo\Documents\Visual Studio 2012\Projects\TSPSolution\TSPSolution\program.cpp 5
264 auto u = ref(t);
265 std::swap(u.cities[0], u.cities[1]);
266 return make_TSP(u);
267 };
268
269 auto g = [](TSP::T t) -> TSP
270 {
271 auto u = ref(t);
272 std::swap(u.cities[2], u.cities[3]);
273 return make_TSP(u);
274 };
275
276 auto fun_result_1 = bnd(bnd(m, f), g);
277 auto fun_result_2 = bnd(m, [&](TSP::T t) {
278 return bnd(f(t), g);
279 });
280
281 auto oo_result_1 = m.map(f).map(g);
282 auto oo_result_2 = m.map([&](TSP::T t) {
283 return f(t).map(g);
284 });
285
286 bool fun_holds = fun_result_1 == fun_result_2;
287 bool oo_holds = oo_result_1 == oo_result_2;
288
289 std::cout << "3rd Law (Associativity) " << (fun_holds ? "holds" : "doesn't hold") << std::endl;
290 std::cout << "3rd Law (Associativity) " << (oo_holds ? "holds" : "doesn't hold") << std::endl;
291 }
292 }
293
294 //TSP -> NN -> Generations( g, ForkJoin ( n, SA -> 2-OPT ) ) -> TSP'
295 void Pipeline1(tsp_class& tsp_instance, unsigned int number_of_tasks, unsigned int
number_of_generations)
296 {
297 #pragma region "PipelineConfiguration"
298 auto a = Args<General_args_type>(make_General_args(number_of_generations, number_of_tasks));
299 auto sa = Args<SA_args_type>(make_SA_args(1000.0, 0.00001, 0.999, 400));
300 auto aco = Args<ACO_args_type>();
301 auto ga = Args<GA_args_type>();
302
303 const char* pipeline_description = "TSP -> NN -> Generations( g, ForkJoin ( n, SA -> 2-OPT ) ) ->
TSP'";
304 display_args(pipeline_description, a, sa, aco, ga);
305
306 auto g = a[0].number_of_iterations_or_generations;
307 auto n = a[0].number_of_tasks_in_parallel;
308 auto _TSP = TSP(just(tsp_instance));
309 auto _DisplayInput = Display("TSP INPUT", DisplayFlags::All);
310 auto _NN = Measure(NN(), Display("NEAREST NEIGHBOUR", DisplayFlags::EmitMathematicaGraphPlot));
311 auto _SA_2OPT = Chain(SA(sa[0].initial_temperature, sa[0].stopping_criteria_temperature,
312 sa[0].decreasing_factor, sa[0].monte_carlo_steps), _2OPT());
313 auto _ForkJoin = [](unsigned int n, TSP::transformer_type map_fun){ return Measure(ForkJoin(n,
map_fun)); };
314 auto _DisplayOutput = Display("TSP OUTPUT", DisplayFlags::EmitMathematicaGraphPlot);
315 #pragma endregion
316
317 //TSP -> NN -> Generations( g, ForkJoin ( n, SA -> 2-OPT ) ) -> TSP'
318 auto result = _TSP
319 .map(_DisplayInput)
320 .map(_NN)
321 .map(Generations(g, _ForkJoin(n, _SA_2OPT)))
322 .map(_DisplayOutput);
323 }
324
325 //TSP -> NN -> Generations( g, ForkJoin ( n, GA -> 2-OPT ) ) -> TSP'
326 void Pipeline2(tsp_class& tsp_instance, unsigned int number_of_tasks,
C:\Users\Fabio Galuppo\Documents\Visual Studio 2012\Projects\TSPSolution\TSPSolution\program.cpp 6
327 unsigned int number_of_generations)
328 {
329 #pragma region "PipelineConfiguration"
330 auto a = Args<General_args_type>(make_General_args(number_of_generations, number_of_tasks));
331 auto sa = Args<SA_args_type>();
332 auto aco = Args<ACO_args_type>();
333 auto ga = Args<GA_args_type>(make_GA_args(1000, 10, 5, 50000, 10, 0.9));
334
335 const char* pipeline_description = "TSP -> NN -> Generations( g, ForkJoin ( n, GA -> 2-OPT ) ) ->
TSP'";
336 display_args(pipeline_description, a, sa, aco, ga);
337
338 auto g = a[0].number_of_iterations_or_generations;
339 auto n = a[0].number_of_tasks_in_parallel;
340 auto _TSP = TSP(just(tsp_instance));
341 auto _DisplayInput = Display("TSP INPUT", DisplayFlags::All);
342 auto _NN = Measure(NN(), Display("NEAREST NEIGHBOUR", DisplayFlags::EmitMathematicaGraphPlot));
343 auto _GA_2OPT = Chain(GA(ga[0].population_size, ga[0].mutation_percentage, ga[0].group_size,
344 ga[0].number_of_generations, ga[0].nearby_cities, ga[0].
nearby_cities_percentage), _2OPT());
345 auto _ForkJoin = [](unsigned int n, TSP::transformer_type map_fun){ return Measure(ForkJoin(n,
map_fun)); };
346 auto _DisplayOutput = Display("TSP OUTPUT", DisplayFlags::EmitMathematicaGraphPlot);
347 #pragma endregion
348
349 //TSP -> NN -> Generations( g, ForkJoin ( n, GA -> 2-OPT ) ) -> TSP'
350 auto result = _TSP
351 .map(_DisplayInput)
352 .map(_NN)
353 .map(Generations(g, _ForkJoin(n, _GA_2OPT)))
354 .map(_DisplayOutput);
355 }
356
357 //TSP -> NN -> Generations( g, ForkJoin ( n, ACO -> 2-OPT ) ) -> TSP'
358 void Pipeline3(tsp_class& tsp_instance, unsigned int number_of_tasks,
359 unsigned int number_of_generations)
360 {
361 #pragma region "PipelineConfiguration"
362 auto a = Args<General_args_type>(make_General_args(number_of_generations, number_of_tasks));
363 auto sa = Args<SA_args_type>();
364 auto ga = Args<GA_args_type>();
365
366 const int aco_iterations = static_cast<int>(tsp_instance.cities.size() * 100);
367 const ants_type::size_type number_of_ants = tsp_instance.cities.size();
368 const double BASE_PHEROMONE = 1.0f / static_cast<double>(tsp_instance.cities.size());
369 const double ALPHA = 1.0;
370 const double BETA = 1.0;
371 const double RHO = 0.9;
372 const double QVAL = 70;
373 auto aco = Args<ACO_args_type>(make_ACO_args(aco_iterations, number_of_ants,
374 BASE_PHEROMONE, ALPHA, BETA, RHO, QVAL));
375
376 const char* pipeline_description = "TSP -> NN -> Generations( g, ForkJoin ( n, ACO -> 2-OPT ) ) ->
TSP'";
377 display_args(pipeline_description, a, sa, aco, ga);
378
379 auto g = a[0].number_of_iterations_or_generations;
380 auto n = a[0].number_of_tasks_in_parallel;
381 auto _TSP = TSP(just(tsp_instance));
382 auto _DisplayInput = Display("TSP INPUT", DisplayFlags::All);
383 auto _NN = Measure(NN(), Display("NEAREST NEIGHBOUR", DisplayFlags::EmitMathematicaGraphPlot));
384 auto _ACO_2OPT = Chain(ACO(aco[0].aco_iterations, aco[0].number_of_ants, aco[0].base_pheromone,
385 aco[0].favor_pheromone_level_over_distance,
386 aco[0].favor_distance_over_pheromone_level,
387 aco[0].value_for_intensification_and_evaporation,
388 aco[0].pheronome_distribution), _2OPT());
C:\Users\Fabio Galuppo\Documents\Visual Studio 2012\Projects\TSPSolution\TSPSolution\program.cpp 7
389 auto _ForkJoin = [](unsigned int n, TSP::transformer_type map_fun){ return Measure(ForkJoin(n,
map_fun)); };
390 auto _DisplayOutput = Display("TSP OUTPUT", DisplayFlags::EmitMathematicaGraphPlot);
391 #pragma endregion
392
393 //TSP -> NN -> Generations( g, ForkJoin ( n, ACO -> 2-OPT ) ) -> TSP'
394 auto result = _TSP
395 .map(_DisplayInput)
396 .map(_NN)
397 .map(Generations(g, _ForkJoin(n, _ACO_2OPT)))
398 .map(_DisplayOutput);
399 }
400
401 //tsplibreader ..\_tsplib\att48.tsp | tspsolution -p:1 -g:2 -n:4 > tsp_result.txt
402 int main(int argc, char* argv[])
403 {
404 //MonadicLawsProofing();
405
406 unsigned int p = 0, g = 0, n = 0;
407 get_args(argc, argv, p, g, n);
408
409 std::vector<pipeline_type> pipelines;
410 pipelines.push_back(Pipeline1); //TSP -> NN -> Generations( g, ForkJoin ( n, SA -> 2-OPT ) ) ->
TSP'
411 pipelines.push_back(Pipeline2); //TSP -> NN -> Generations( g, ForkJoin ( n, GA -> 2-OPT ) ) ->
TSP'
412 pipelines.push_back(Pipeline3); //TSP -> NN -> Generations( g, ForkJoin ( n, ACO -> 2-OPT ) ) ->
TSP'
413
414 if (p > pipelines.size())
415 {
416 std::cerr << "Invalid pipeline #" << p
417 << ", max # of pipelines = " << pipelines.size() << std::endl;
418 exit(1);
419 }
420
421 auto tsp_instance = read_tsp_instance();
422 pipelines[p - 1](tsp_instance, n, g);
423 }
12/11/13 Curr culo!do!Sistema!de!Curr culos!Lattes!(Fabio!Razzo!Galuppo)
Identificaç#o
Nome Fabio Razzo Galuppo
Nome em citaç!es bibliogr"ficas GALUPPO, F. R.
Endereço
Formaç#o acadêmica/titulaç#o
2012 Mestrado em andamento em Engenharia Elétrica (Conceito CAPES 4).
Universidade Presbiteriana Mackenzie, MACKENZIE, Brasil.
T!tulo: Resoluç"es do Problema do Caixeiro Viajante Aplicando Algoritmos de
Aproximaç#o, Randomizaç#o e Heur!sticas da Inteligência Artificial com
Computaç#o Paralela,Orientador: Nizam Omar.
Palavras-chave: Computaç#o Paralela e Concorrente; Metaheur!stica Paralela;
Inteligência Artificial; Otimizaç#o Combinat$ria; Algoritmos; Programaç#o
Heterogênea.
Grande %rea: Ciências Exatas e da Terra / &rea: Ciência da Computaç#o /
Sub%rea: Inteligência Artificial.
Grande &rea: Ciências Exatas e da Terra / &rea: Matem%tica / Sub%rea:
Otimizaç#o Combinat$ria.
2004 - 2007 Graduaç#o em Ciência da Computaç#o.
Universidade Ibirapuera, UNIB, Brasil.
T!tulo: Abstraç"es para Programaç#o de Sistemas com Multiprocessamento
Simétrico.
Orientador: Floriano Ferreira dos Reis Filho.
Formaç#o Complementar
2013 - 2013 Pattern-Oriented Software Architectures.
Coursera.
2013 - 2013 Coding the Matrix: Linear Algebra through Computer.
Coursera.
2012 - 2012 Heterogeneous Parallel Programming.
Coursera.
buscatextual.cnpq.br/buscatextual/visualizacv.do?id=K4484791D3 1/3
12/11/13 Curr culo!do!Sistema!de!Curr culos!Lattes!(Fabio!Razzo!Galuppo)
&reas de atuaç#o
Idiomas
Inglês Compreende Bem, Fala Bem, Lê Bem, Escreve Bem.
Produç"es
Produç#o bibliogr"fica
Apresentaç!es de Trabalho
1. GALUPPO, F. R. . C++ 11 e o futuro do C++. 2013. (Apresentaç#o de Trabalho/Conferência ou palestra).
Produç#o técnica
1. GALUPPO, F. R. . C++ Renaissance < Functional Revolution. 2011; Tema: Desenvolvimento de Software. (Blog).
buscatextual.cnpq.br/buscatextual/visualizacv.do?id=K4484791D3 2/3