• Nenhum resultado encontrado

3 Trabalhos Relacionados

4.3 Propostas de Alocação Dinâmica

4.3.1 TransCand: Transgenético com Candidatos

O TransCand é uma heurística para alocação de tarefas que usa o conceito de po- pulação de endossimbiontes (soluções) candidatos. A ideia principal é criar, a partir de uma solução de alocação atual que está sendo simulada, um conjunto (ou população) de soluções candidatas. Nessa população, cada solução terá o seu fitness avaliado e a melhor será a que irá substituir a solução atual. Contudo, ela só substituirá se ela também for melhor que a solução atual. A Figura 16 apresenta o esquemático da otimização aplicada

por essa proposta.

Figura 16: Esquemático da otimização aplicada pela heurística TransCand.

No ambiente de otimização (ou célula hospedeira) representado na Figura 16, o Banco de Informações Genéticas (BIG) contém como informação apenas as tarefas que serão alocadas em um determinado instante. Essas tarefas contidas em BIG estão ordenadas de acordo com o peso de suas comunicações com outras tarefas já alocadas ou não. Dentro da célula do indivíduo hospedado (célula dos endossimbiontes), temos a aplicação apenas de um plasmídeo, o qual é o agente responsável pela inserção das tarefas contidas em BIG no endossimbionte. Veja que nessa abordagem temos apenas um endossimbionte, e é a partir dele que é gerada a população de soluções candidatas também representada na Figura 16. Por fim, temos um procedimento de avaliação das soluções candidatas, o qual irá substituir a solução atual por aquela solução candidata que apresenta melhor fitness, inclusive melhor que a solução atual.

Diferente dos algoritmos math-heurísticos propostos (ver seção 4.2), o cálculo da fun- ção fitness aqui considerado é o produto entre fluxo e distância em vez do roteamento dado pelo modelo do PMR. Isso é devido as propostas aqui apresentadas serem aplicadas no contexto de mapeamento dinâmico, o qual requer um tempo de geração de soluções muito menor do que o mapeamento estático.

No Algoritmo 4 é apresentado o pseudocódigo do TransCand. O algoritmo tem como entrada as tarefas a serem alocadas TP A, os núcleos do sistema N , as comunicações entre

todas as tarefas já alocadas ou que serão alocadas (as contidas em TP A) Comm, a matriz

dos fluxos de informações F , a matriz de distâncias entre os núcleos D, a solução atual sol, dois vetores binários que indicam quais tarefas e quais núcleos estão alocados na solução atual, sendo eles map_t e map_c, respectivamente, e por fim a quantidade de soluções candidatas a serem consideradas pop_size. O algoritmo retorna como resultado a atualização da solução de alocação sol com a inclusão das novas tarefas alocadas, a atualização dos vetores binários map_t e map_c, indicando quais tarefas foram alocadas e quais núcleos receberam tarefas, respectivamente.

No pseudocódigo apresentado no Algoritmo 4, temos primeiramente a inicialização (linha 1) e a inserção de carga genética (linha 2) no BIG. A maneira como é feita essa inserção de carga genética no BIG será descrita em detalhes no Algoritmo 5. Se existe alguma informação em BIG, ou seja, se existe pelo menos uma tarefa a ser alocada, o algoritmo continua seu processo de otimização, caso contrário ele para. Inicializa-se três diferentes vetores com pop_size posições cada um (linhas 4, 5 e 6). Cada um desses veto- res irá armazenar as configurações das soluções (cand), tarefas alocadas (cand_map_t) e núcleos usados (cand_map_c) para cada uma das pop_size soluções candidatas. Após isso, esses vetores são inicializados com os valores atuais de sol, map_t e map_c, respec- tivamente (linha 7 à 11). Na linha 12, o valor de fitness da solução atual sol, considerando no cálculo as alocação já contida na estrutura da solução, é armazenado em cost_best. Como citado anteriormente, o valor do fitness é calculado considerando o produto dos flu- xos (F ) e distâncias (D). Após isso é inicializado com −1 a variável que irá armazenar o índice do vetor cand que contém a solução com melhor fitness. Para cada uma das soluções candidatas (índice i variando de 0 até pop_size − 1), os seguintes passos são realizados (da linha 14 à 25): Da linha 15 à 19, para cada tarefa a ser alocada, obtida de acordo com sua ordenação armazenada em BIG, é aplicado o PlasmídeoCand (linha 16), o qual faz a inserção da carga genética considerando alguns critérios de alocação. Mais detalhes sobre esse plasmídeo serão apresentados no Algoritmo 6. Depois disso, nas linhas 17 e 18 são atualizadas as configurações de alocação da solução atual, considerando a tarefa atualmente alocada t. Essa atualização serve para manter a solução corrente atualizada, uma vez que se ela for melhor do que as outras soluções candidatas geradas, nenhuma modificação adicional será necessária, pois ela continuará a ser a solução simulada. Na linha 20, o custo da solução candidata gerada é calculado e armazenado na variável cost. Nos passos seguintes (da linha 21 à 24) é feita a verificação se o valor de custo da solu-

Algoritmo 4: TransCand

Input: TP A, N , Comm, F , D, sol, map_t, map_c, pop_size.

Output: Atualização de sol, map_t e map_c.

1: BIG ← ∅

2: BIG ← LoadGeneticInf ormation(TP A, |sol|, Comm, map_t)

3: if (BIG 6= ∅) then 4: cand[pop_size] ← ∅

5: cand_map_t[pop_size] ← ∅ 6: cand_map_c[pop_size] ← ∅ 7: for (i = 0 até pop_size − 1) do

8: cand[i] ← sol

9: cand_map_t[i] ← map_t 10: cand_map_c[i] ← map_c

11: end for

12: cost_best ← getCost(F, D, sol, TP A)

13: index_best ← −1

14: for (i = 0 até pop_size − 1) do

15: for each (t ∈ BIG) do

16: P lasmideoCand(cand[i], cand_map_t[i], cand_map_c[i], t.target, t.f ather, N )

17: map_t[t] ← 1 18: map_c[sol[t]] ← 1

19: end for

20: cost ← getCost(F, D, cand[i], TP A)

21: if (cost < cost_best) then

22: cost_best ← cost 23: index_best ← i 24: end if 25: end for 26: if (index_best 6= −1) then 27: sol ← cand[index_best] 28: map_t ← cand_map_t[index_best] 29: map_c ← cand_map_c[index_best] 30: end if 31: end if

ção gerada é melhor do que o custo da melhor solução gerada até o momento. Caso seja melhor, o cost_best e index_best são atualizados com o novo melhor custo e o índice no vetor de soluções cand que representa esse custo, respectivamente (linhas 22 e 23). Por fim, é feita a atualização de sol (da linha 26 à 30) caso o valor da variável que armazena o índice da melhor solução index_best seja diferente de −1. Nesse caso, sol é atualizado com a solução de melhor custo, e map_t e map_c são atualizados com as tarefas que foram alocadas e os núcleos que receberam tarefas, respectivamente.

4.3.1.1 Carregamento do BIG

Como já mencionado, o Banco de Informações Genéticas (BIG) armazena as tarefas a serem alocadas de forma ordenada. Essa ordenação leva em consideração a quantidade de fluxo transferido nas comunicações entre cada uma dessas tarefas e as outras tarefas já alocadas ou não. Para isso, é feita uma ordenação decrescente das comunicações e, baseando-se nessa ordenação, as tarefas são inseridas no BIG. O Algoritmo 5 descreve o pseudocódigo deste procedimento.

Algoritmo 5: LoadGeneticInformation Input: TP A, n, Comm, map_t.

Output: BIG. 1: if (TP A 6= ∅) then 2: traversed[n] ← ∅ 3: in_BIG[n] ← ∅ 4: for (i = 0 até n − 1) do 5: traversed[i] ← 0 6: in_BIG[i] ← 0 7: if (map_t[i] = 1) then 8: traversed[i] ← 1 9: end if 10: end for 11: DescreasingSort(Comm) 12: while (|BIG| < |TP A|) do

13: for each (c ∈ Comm) do

14: if (traversed[c.src] = 1 and traversed[c.dst] = 0) then

15: in_BIG[c.dst] ← 1 16: traversed[c.dst] ← 1 17: t ← ∅ 18: t.target ← c.dst 19: t.f ather ← c.src 20: BIG.insert(t) 21: end if

22: if (traversed[c.src] = 0 and traversed[c.dst] = 1) then

23: in_BIG[c.src] ← 1 24: traversed[c.src] ← 1 25: t ← ∅ 26: t.target ← c.src 27: t.f ather ← c.dst 28: BIG.insert(t) 29: end if 30: end for 31: end while 32: end if

O procedimento descrito no Algoritmo 5 toma como entrada o conjunto de tarefas a serem alocadas TP A, o tamanho do problema n (quantidade máxima de tarefas que

podem ser alocadas), as comunicações ativas Comm (o que inclui as comunicações entre as tarefas já alocadas e também as que irão ser alocadas) e o vetor binário que indica quais tarefas estão alocadas até o momento map_t. O procedimento retorna como resultado o BIG.

No procedimento de carregamento do BIG, inicialmente é verificado se existe alguma tarefa a ser alocada (linha 1) e caso exista, os próximos passos do algoritmo são realizados, caso contrário, o algoritmo para, retornando o BIG vazio. Nas linhas 2 e 3 são inicializados dois vetores binários que indicam quais tarefas já foram percorridas traversed e quais tarefas já estão inseridas em BIG in_BIG. A inicialização desses vetores é feita nas linhas de 4 à 10, onde cada posição de ambos é inicializada com 0. Caso uma determinada tarefa i já esteja mapeada, ela é indicada como já percorrida no vetor traversed (linhas de 7 à 9). Na linha 11 é feita a ordenação das comunicações através do procedimento DecreasingSort(Comm). Esse procedimento toma como entrada a lista de comunicações ativas e retorna essa lista ordenada da maior comunicação para a menor. Após isso, enquanto a quantidade de elementos contidos em BIG for menor do que a quantidade de tarefas que devem ser alocadas, os passos da linha 12 até 32 são aplicados.

Para cada comunicação c da lista ordenada Comm, os passos da linha 13 até 31 são aplicados. Na linha 14 é verificado se a tarefa de origem da comunicação c já foi percorrida e se a tarefa de destino ainda não foi percorrida. Se esse for o caso, a posição dela em in_BIG é marcada como inserida em BIG (linha 15); a tarefa é marcada com percorrida em traversed (linha 16); e a variável t é inicializada (linhas 17 a 19), a qual irá armazenar em t.target a tarefa de destino da comunicação (tarefa a ser alocada) e em t.f ather a tarefa de origem (tarefa pai). Por fim, t é inserido na posição final de BIG (linha 20). Os passos da linha 22 a 29 são similares aos da linha 14 à 21, mudando apenas qual tarefa que deve ser inserida em BIG, pois neste caso é a tarefa de origem da comunicação c.

4.3.1.2 PlasmídeoCand

A ideia principal do plasmídeo aplicado na heurística TransCand é alocar uma deter- minada tarefa em um núcleo disponível que esteja mais próximo da tarefa pai. Contudo, como pode existir mais de um núcleo disponível, a escolha de qual núcleo receberá a tarefa é feita aleatoriamente dentre os núcleos com menores distâncias em hops (ou distância de Manhattan).

Observe que neste plasmídeo não é feito o cálculo do custo da alocação. Esse cálculo, como já mencionado, é realizado no procedimento principal, descrito no Algoritmo 4, quando cada solução candidata já estiver totalmente completa. Além disso, essa foi uma tomada de decisão de projeto deste algoritmo, com o objetivo de minimizar o custo de aplicação do plasmídeo, uma vez que ele é aplicado várias vezes (|T_PA| vezes, mais especificamente) para cada solução candidata gerada. No Algoritmo 6 é apresentado o pseudocódigo.

Algoritmo 6: PlasmideoCand

Input: cand, cand_map_t, cand_map_c, target, f ather, N . Output: Atualização de cand, cand_map_t, cand_map_c.

1: cores ← getM anhattanM in(cand[f ather], cand_map_c, N )

2: c ← choose(cores)

3: applyM apping(target, c, cand, cand_map_t, cand_map_c)

O plasmídeo do TransCand descrito no Algoritmo 6, tem como entrada uma so- lução candidata cand, os vetores binários de tarefas alocadas e núcleos selecionados cand_map_t e cand_map_c, respectivamente, a tarefa a ser alocada target, a tarefa pai da tarefa a ser alocada f ather e o conjunto de núcleos N . O algoritmo retorna a solução candidata cand com a nova posição da tarefa target, e a atualização dos vetores cand_map_t e cand_map_c.

Inicialmente é obtido o conjunto de núcleos com a menor distância em hops de onde a tarefa pai foi alocada (linha 1). Após isso, é escolhido aleatoriamente qual dos núcleos que deverá receber a tarefa (linha 2). Por fim, é aplicada a alocação da tarefa target no núcleo c escolhido anteriormente. Com isso, é atualizada a posição da tarefa a ser alocada na estrutura da solução sol, bem como cand_map_t e cand_map_c.