Restrições Globais - Escalonamento Para além das restrições globais de Sequenciação, existem outras restrições importantes em problemas de escalonamento (de tarefas, horários, etc). Algumas restrições importantes são • Garantir que uma tarefa se executa antes de outra • Garantir que duas tarefas não se sobrepõem no tempo (por exemplo, por usarem o mesmo recurso) • Garantir que o número de tarefas que utiliza os mesmos recursos nunca excede um dado número (a quantidade de recurso disponível) 1 Restrições de Precedência Precedência Em geral, para cada tarefa i podemos considerar um tempo de início da tarefa Ti e a sua duração Di. Com estes pressupostos a precedência da tarefa i em relação à tarefa j é naturalmente expressa pela restrição before(Ti, Di, Tj) :Ti + Di #=< Tj. 2 Restrições de Precedência Precedência Sendo as restrições primitivas restrição “indexicais”, a restrição de precedência pode ser indexicais Ti + Di #=< Tj expressa directamente before(Ti, Ti in Di in Tj in através dos Di, Tj)+: inf .. max(Tj)-min(Di) inf .. max(Tj)-min(Ti) min(Ti)+min(Di) .. sup 3 Restrições de Não-Sobreposição A não sobreposição de duas tarefas ém equivalente a uma disjunção de duas restrições de precedência: Ou a tarefa i é anterior à tarefa j , Ou a tarefa j é anterior à tarefa i . Há várias formas de implementar esta disjunção, nomeadamente através: 1. de retrocesso, 2. do operador de cardinalidade com compromisso mínimo, 3. de disjunção construtiva 4. de restrições globais 4 Restrições de Não-Sobreposição Exemplo Suponhamos as 4 tarefas do grafo, em que são indicadas as precedências e a exclusão mútua. As durações são indicadas nos nós. Pretende-se determinar quais os escalonamentos de tarefas que permitem terminar T4 até ao instante 10. T1/2 T2/4 T3/3 T4/1 project([T1,T2,T3,T4]):domain([T1,T2,T3,T4], 1, 10), before(T1, 2, T2), before(T1, 2, T3), before(T2, 4, T4), before(T3, 3, T4), no_overlap(T2, 4, T3, 3). 5 Restrições de Não-Sobreposição Retrocesso A disjunção pode ser retrocesso (a la Prolog): implementada através do no_overlap(T1, D1, T2, _):before(T1, D1, T2). no_overlap(T1, _, T2, D2):before(T2, D2, T1). No entanto, esta implementação tenta sempre colocar primeiro T1 antes de T2, o que pode ser impossível ou indesejável. Este compromisso máximo pode pois colocar problemas de eficiência (em grandes e complexos problemas). 6 Restrições de Não-Sobreposição Cardinal A disjunção pode ser implementada através do operador de “cardinalidade”: no_overlap(T1,D1,T2,D2):exactly(1, [T1 + D1 #=< T2, T2 + D2 #=< T1]). exactly(0,[]). exactly(N, [H|T]):call(H #<=> B), N #= M+B, exactly(M, T). Esta implementação já não tenta colocar T1 antes de T2. Quando a enumeração começar, um dos disjuntos é escolhido e o outro negado. No entanto, não se eliminam valores que são eliminados em qualquer dos disjuntos. 7 Restrições de Não-Sobreposição Disjunção Construtiva Com a disjunção construtiva pretende eliminar-se os valores que não pertencem a nenhum dos disjuntos, sem optar por nenhum deles. no_overlap3(T1, D1, T2, D2)+: T1 in (inf..max(T2)-min(D1)) \/ (min(T2)+min(D2)..sup), T2 in (inf..max(T1)-min(D2)) \/ (min(T1)+min(D1)..sup), D1 in (inf..max(T2)-min(T1)) \/ (min(D1) .. max(D1)), D2 in (inf..max(T1)-min(T2)) \/ (min(D2) .. max(D2)) Esta implementação da disjunção construtiva é garantida pela semântica das restrições indexicais primitivas. 8 Restrições de Não-Sobreposição Restrição Global serialized/2 Neste problema, as 4 tarefas acabam por ser realizadas disjuntivamente. Neste caso pode adoptar-se uma restrição global primitiva, serialized(T,D) que garante que todas as tarefas começadas no instante Ti com duração Di não se sobrepõem. no_overlap([T1,T2,T3,T4],[2,4,3,1]):serialized([T1,T2,T3,T4],[2,4,3,1],[edge_finder(true)]) De notar a opção edge_finder, que implementa um algoritmo, baseado em [CaPi94], para melhor restringir o início de cada tarefadetectar implementação da disjunção construtiva é garantida pela semântica das restrições indexicais primitivas. 9 Restrições de Não-Sobreposição Resultados Com a opção de retrocesso são apresentadas as duas soluções em alternativa. De notar que como em cada alternativa é imposta uma ordenação (não existente no problema inicial) os domínios das variáveis são muito restringidos. |? T in 1..10, project(T). |? T in 1..11, project(T). T1 = 1 ,T2 = 3, T1 in 1..2, T2 in 3..4, T3 = 7, T4 = 10 ? ; T3 in 7..8, T4 in 10..11 ? ; T1 = 1 ,T2 = 6, T1 in 1..2, T2 in 6..7, T3 = 3, T4 = 10 ? ; T3 in 3..4, T4 in 10..11 ? ; no no 10 Restrições de Não-Sobreposição Resultados Com a opção de compromisso mínimo, não se obtem muitos cortes. Apenas se descobrem sequências T1, T2 e T4 e T1, T3 e T4, separadas, pelo que os cortes no fim de T1 e no início de T4 não são tão significativos como antes. |?- T in 1..10, project(T). T1 in 1 .. 4, T2 in 3 .. 6, T3 in 3 .. 7, T4 in 7 .. 10 ? ; no | ?T1 T2 T3 T4 no T in in 1 in 3 in 3 in 7 1..11, project(T). .. 5, .. 7, .. 8, .. 11 ? ; 11 Restrições de Não-Sobreposição Resultados Com a opção de disjunção construtiva, obtem-se os mesmos cortes em T1 e T4. Adicionalmente, a disjunção construtiva elimina valores de T2 e T3 que não podem pertencer a nenhuma solução. |?- T in 1..10, project(T). T1 in 1 .. 4, T2 in{3} \/ {6}, T3 in{3} \/ {7}, T4 in 7.. 10 ? ; no | ?T1 T2 T3 T4 no T in 1..11, project(T). in 1 .. 5, in(3..4) \/ (6..7), in(3..4) \/ (7..8), in 7 .. 11 ? ; 12 Restrições de Não-Sobreposição Resultados Com a opção de serialização, conseguem-se não só os resultados da disjunção construtiva, como se restringem os valores de T1 (mas não de T4) por se considerarem as sequências T1, T2, T3 e T4 ou T1, T3, T2 e T4. |?- T in 1..10, project(T). T1 = 1, T2 in{3}\/{6}, T3 in{3}\/{7}, T4 = 10 ? ; no | ?T1 T2 T3 T4 no T in 1..11, project(T). in 1..2, in(3..4)\/(6..7), in(3..4)\/(7..8), in 7..11 ? ; 13 Restrições de Não-Sobreposição Redundância Nem mesmo a opção de serialização consegue inferir na totalidade os cortes nos domínios das variáveis. O resolvedor de restrições pode ser auxiliado neste objectivo pela explicitação de restrições redundantes. Com efeito, as tarefas 2 e 3 nunca podem terminar antes de se esgotarem as duas durações após o início da primeira tarefa. Assim a tarefa T4 nunca poderá começar antes de min(min(T2),min(T3))+D2+D3 14 Restrições Redundantes Redundância No SICStus, tal pode ser expresso da seguinte forma. 1. Cria-se um intervalo cujo limite inferior seja o pretendido. Assim para o limite inferior min(min(T2),min(T3))+D2+D3 cria-se o intervalo E in (min(T2)+D2+D3..sup)\/(min(T3)+D2+D3..sup)) 2. Garante-se que a tarefa 4 se executa neste intervalo (pode considerar-se esta intervalo como o início de uma tarefa de duração nula e garantir que esta é anterior a T4) before(E, 0, T4) 15 Restrições Redundantes Um procedimento semelhante pode ser tomado para garantir que a tarefa T1 não começa “tarde de mais”. Combinando as duas inferências 1. Determinam-se os limites (“edges”) das tarefas 2 e 3 com a chamada edges(T2,4,T3,3,Edge23_lo,Edge23_up) 2. Impõem-se limites às tarefas 1 e 4 com base nos limites assim definidos before(Edge23_up, 0, T4), before(T1, 2, Edge23_lo), 16 Restrições Redundantes A definição dos “edges” das tarefas 2 e 3 combinadas é feita como indicado antes edges(T2,D2,T3,D3,Lo,Up)+: Lo in ((inf..max(T2)-D3) \/ (inf..max(T3)-D2)), Up in ((min(T2)+D2+D3..sup) \/ (min(T3)+D2+D3..sup)). já que min(min(T2),min(T3))+D2+D3 corresponde a Up in ((min(T2)+D2+D3..sup) \/ (min(T3)+D2+D3..sup)) e que max(max(T2+D2),max(T3+D3))-D2-D3 corresponde a Lo in ((inf..max(T2)-D3) \/ (inf..max(T3)-D2)) 17 Restrições Redundantes Resultados Com a opção de compromisso mínimo, não se obtem cortes na disjunção das tarefas T2 e T3, mas os limites de T1 e T4 são bem delimitados. |?- T in 1..10, project(T). T1 = 1, T2 in 3 .. 6, T3 in 3 .. 7, T4 = 10 ? ; no | ?T1 T2 T3 T4 no T in 1..11, project(T). in 1 .. 2, in 3 .. 7, in 3 .. 8, in 10.. 11 ? ; 18 Restrições Redundantes Resultados Com a opção de disjunção construtiva, além de se obterem cortes na disjunção das tarefas T2 e T3, obtêm-se os limites correctos de T1 e T4. |?- T in 1..10, project(T). T1 = 1, T2 in{3}\/{6}, T3 in{3}\/{7}, T4 = 10 ? ; no | ?T1 T2 T3 T4 no T in 1..11, project(T). in 1 .. 2, in(3..4) \/ (6..7), in(3..4) \/ (7..8), in 10 .. 11 ? ; 19 Restrição Global - Cumulative A restrição global serialized(T,D), que impõe a não sobreposição de tarefas Ti com durações Di, é um caso particular da restrição global cumulative(T,D,R,L), que para um conjunto de tarefas Ti com durações Di e que utilizam uma quantidade Ri de um recurso, garante que a utilização desse recurso nunca excede L unidades. Nestas condições serialized(T,D) cumulative(T,D,R,1) em que R = [1,1,...1]. Como cada tarefa utiliza a única unidade de recurso disponível, a serialização das tarefas é garantida. 20 Restrição Global - Cumulative A restrição global cumulative/4, permite não só raciocinar de uma forma global sobre a duração das tarefas, mas também especificar este tipo de restrições, cuja decomposição em restrições mais simples é muito pouco prática. Sejam a = min i (Ti) e b = maxi(Ti+Di). Seja ainda Si,k = Ri se Ti =< tk =< Ti+Di ou 0 no caso contrário. cumulative(T,D,R,L) Si,k L k[a,b] i 21 Restrição Global - Cumulative A restrição global cumulative/4, foi inicialmente introduzida na linguagem CHIP [AgBe94] tendo em vista a execução eficiente de vários problemas, nomeadamente 1. escalonamento temporal de tarefas disjuntas 2. escalonamento de tarefas com limitação de recursos 3. colocação de componentes A sua implementação não é apresentada no artigo referido. No entanto, uma generalização da restrição global (com tarefas incluindo recursos negativos para modelar processos de produção e consumo) é explicada num artigo mais recente [BeCa02]. 22 Escalonamento de Tarefas - Cumulative Exemplo: São dadas 7 tarefas (A a G) com as durações e o consumo de recursos (por exemplo número de trabalhadores necessárias para a efectuar) indicados na seguinte tabela. D=[2,4,3,2,1,2,2] R=[4,1,3,1,2,3,2] Gráficamente Pretende determinar-se se as tarefas podem ser todas concluídas num dado tempo máximo (Tmax), se estiver disponível um número de trabalhadores Rmax. 23 Escalonamento de Tarefas - Cumulative Com a restrição global cumulative/4, o problema anterior pode ser facilmente especificado (o predicado latest garante que todas as tarefas terminam antes de Tmax) plan1(Tmax,Rmax, T):T = [T1,T2,T3,T4,T5,T6,T7], D = [ 2, 4, 3, 2, 1, 2, 2], R = [ 4, 1, 3, 1, 2, 3, 2], domain(T, 1, 15), cumulative(T,D,R,Rmax), latest(T,D,Tmax), labeling([ff],T). Nota: A “área” de todas as tarefas é 35, donde o problema só é possível se Tmax * Rmax >= 35 24 Restrições Global - Cumulative Resultados Com Tmax = 9 e Rmax = 4 obtém-se várias respostas, nomeadamente R 4 1 3 3 7 9 6 8 3 2 t 1 1 2 3 4 5 6 7 8 9 8 1 3 5 7 1 6 6 1 1 8 5 8 4 25 Restrições Global - Cumulative Resultados Com Tmax = 7 e Rmax = 5 (neste caso não há tempos livres) continuam-se a obter várias respostas, tais como 1 1 3 3 5 6 6 4 4 1 6 3 6 1 26 Restrições Global - Cumulative Resultados Com Tmax = 6 e Rmax = 6 (neste caso há 1 tempo livre) ainda se continuam a obter várias respostas, tais como 1 1 3 1 6 5 3 5 3 2 5 1 1 3 Questão: E com Tmax = 5 e Rmax = 7 ? 27 Escalonamento de Tarefas Versáteis As tarefas são “versáteis” quando permitem troca de tempo por recursos. Por exemplo, uma tarefa pode ser feita por 2 pessoas em 3 horas ou por 3 pessoas em 2 horas. Tarefas versáteis podem “encaixar-se” melhor na “área” disponível. O escalonamento dessas tarefas pode ser feito como anteriormente. No entanto, se antes havia constantes Kdi e Kri para a duração e recursos requeridos pela tarefa i, agora passamos a ter variáveis Di e Ri tais que Di * Ri #= Kdi * Kri 28 Escalonamento de Tarefas - Cumulative O programa é semelhante ao anterior, igualmente fazendo uso da restrição global cumulative/4. As diferenças são a versatilidade das tarefas (listas D e R), restringida pelo predicado constrain_tasks/2. A enumeração deve agora ser feita não só nas variáveis T mas também nas D (ou R). plan2(Tmax,Rmax, T, D, R):T = [T1,T2,T3,T4,T5,T6,T7], domain([T1,T2,T3,T4,T5,T6,T7], 1, 15), D = [D1,D2,D3,D4,D5,D6,D7], Dc = [ 2, 4, 3, 2, 1, 2, 2], R = [R1,R2,R3,R4,R5,R6,R7], Rc = [ 4, 1, 3, 1, 2, 3, 2], constrain_tasks(D,R,Dc,Rc), cumulative(T,D,R,Rmax), latest(T,D,Tmax), append(T,D,V), labeling([ff],V). 29 Escalonamento de Tarefas - Cumulative O predicado constrain_tasks/2 é implementado como abaixo indicado. As variáveis D e R são inicializadas com o domínio 1..9), e é imposta para cada tarefa a restrição que define a sua versatilidade. constrain_tasks(D,R,Dc,Rc):domain(D, 1, 9), domain(R, 1, 9), set_cons(D,R,Dc,Rc). set_cons([],[],[],[]). set_cons([D1|Dt1],[R1|Rt1],[D2|Dt2],[R2|Rt2]):D1 * R1 #= D2 * R2, set_cons(Dt1,Rt1,Dt2,Rt2). 30 Escalonamento de Tarefas - Cumulative Resultados Com Tmax = 6 e Rmax = 6 (neste caso há 1 tempo livre) obtêem-se novas respostas, tais como D R T 2 1 3 1 1 2 2 4 4 3 2 2 3 2 4 6 1 5 6 1 3 31 Escalonamento de Tarefas - Cumulative Com Tmax = 5 e Rmax = 7 (sem resposta anteriormente) existem agora várias respostas. De notar que, na segunda resposta não só há uma rotação como ocorre uma transformação (4*1 2*2). D R T 2 4 3 1 1 2 2 4 1 3 2 2 3 2 4 2 1 1 1 2 4 D R T 2 2 3 1 1 2 2 4 2 3 2 2 3 2 1 4 1 5 3 4 3 32 Job Shop - Cumulative O problema de “job shop” consiste em executar as várias tarefas de vários trabalhos garantindo-se que não são excedidos os recursos disponíveis. Dentro de cada trabalho existem várias tarefas, com uma dada duração. Dentro de cada trabalho, as tarefas têm de ser feitas na sua sequência natural, sendo aceites intervalos entre o fim de uma tarefa e o início da próxima. Tarefas de trabalhos diferentes são independentes a menos da utilização de recursos (máquinas). Cada tarefa deve ser realizada numa máquina de um determinado tipo. O número de máquinas de cada tipo é limitado. 33 Job Shop - Cumulative Denotando por JXYZ a Y-ésima tarefa do trabalho X que deve ser executada na máquina Z, e tem uma duração D, uma instância do problema 10*10 é a seguinte (cada máquina só aceita uma tarefa de cada vez) Y X M, D 1 2 3 4 5 6 7 8 9 a 1 1, 29 1, 43 2, 91 2, 81 3, 14 3, 84 2, 46 3, 31 1, 76 2, 85 2 2, 78 3, 90 1, 85 3, 95 1, 6 2, 2 1, 37 1, 86 2, 69 1, 13 3 3, 9 5, 75 4, 39 1, 71 2, 22 6, 52 4, 61 2, 46 4, 76 3, 61 4 4, 36 a, 11 3, 74 5, 99 6, 61 4, 95 3, 13 6, 74 6, 51 7, 7 5 5, 49 4, 69 9, 90 7, 9 4, 26 9, 48 7, 32 5, 32 3, 85 9, 64 6 6, 11 2, 28 6, 10 9, 52 5, 69 a, 72 6, 21 7, 88 a, 11 a, 76 7 7, 62 7, 46 8, 12 8, 85 9, 21 1, 47 a, 32 9, 19 7, 40 6, 47 8 8, 56 6, 46 7, 89 4, 98 8, 49 7, 65 9, 89 a, 48 8, 89 4, 52 9 9, 44 8, 72 a, 45 a, 22 a, 72 5, 6 8, 30 8, 36 5, 26 5, 90 a a, 21 9, 30 5, 33 6, 43 7, 53 8, 25 5, 55 4, 79 9, 74 8, 45 34 Job Shop - Cumulative Esta instância foi proposta Scheduling [MuTh63]. no livro Industrial Durante 20 anos não se obteve a solução óptima (do ponto de vista do “makespan”, isto é, da terminação mais rápida). Por volta de 1980, a melhor solução era 935 (unidades de tempo). Em 1985, um limite inferior de 930 foi obtido para o óptimo. Em 1987 o problema foi resolvido com um algoritmo altamente especializado, obtendo-se o óptimo de 930. Com a utilização de restrição cumulative/4, o problema foi resolvido em 1506 segundos (SUN/SPARC). 35 Job Shop - Cumulative Uma instância mais simples deste problema é dado pelo quadro abaixo ( com a respectiva representação gráfica). De notar que nesta instância se assume que cada tarefa requer uma unidade do recurso indicado, mas que existem 2 recursos do tipo 1 e outros 2 do tipo 2. X M, D 1 2 3 4 1 2,1 3,1 5,1 3,1 Y 2 4,2 4,2 3,2 3,2 J1 3 7,1 5,1 3,2 4,2 J2 1 2 1 J3 J4 3 2 1 1 3 2 2 3 3 36 Job Shop - Cumulative Esta instância do problema pode ser facilmente resolvida como seguinte programa SICStus: jobs([J1,J2,J3,J4]):% definição dos vários trabalhos J1 = [S111,S122,S131]-[2,4,7]-[1,2,1], J2 = [S211,S222,S231]-[3,4,5]-[1,2,1], J3 = [S311,S322,S332]-[5,3,3]-[1,2,2], J4 = [S411,S422,S432]-[3,3,4]-[1,2,2], % declaração de domínios domain([S111,S122,S131],0,15), domain([S211,S222,S231],0,15), domain([S311,S322,S332],0,15), domain([S411,S422,S432],0,15), % restrições de precedência % restrições de limitação de recursos % restrições sobre a terminação dos vários trabalhos % enumeração do início das diversas tarefas 37 Job Shop - Cumulative As restrições são as seguintes: % restrições de precedência S122#>=S111+2, S131#>=S122+4, S222#>=S211+3, S231#>=S222+4, S322#>=S311+5, S332#>=S322+3, S422#>=S411+3, S432#>=S422+3, % restrições de limitação de recursos cumulative([S111,S131,S211,S231,S311,S411],[2,7,3,5,5,3], [1,1,1,1,1,1],2), cumulative([S122,S222,S322,S332,S422,S432],[4,4,3,3,3,4], [1,1,1,1,1,1],2), % restrições sobre a terminação dos vários trabalhos E #>= S131+7, E #>= S231+5, E #>= S332+3, E #>= S432+4, E #=< 13, % enumeração do início das diversas tarefas labeling([ff], [S111, S122, S131, S211, S222, S231, S311, S322, S332, S411, S422, S432]). 38 Job Shop - Cumulative Os resultados obtidos (com terminação naterior a 13) são os seguintes: | ?- jobs(J). J=[[0,2, 6]-[2,4,7]-[1,2,1], 0 1 2 3 4 1 1 5 6 7 8 9 1 3 1 3 10 11 [0,3, 7]-[3,4,5]-[1,2,1], 2 2 [2,7,10]-[5,3,3]-[1,2,2], 2 3 2 3 [3,6, 9]-[3,3,4]-[1,2,2]]? ; J=[[0,2, 6]-[2,4,7]-[1,2,1], 1 [0,3, 8]-[3,4,5]-[1,2,1], [2,7,10]-[5,3,3]-[1,2,2], 1 1 3 1 3 2 2 2 3 2 3 [3,6, 9]-[3,3,4]-[1,2,2]]? ; no 39 12 Colocação de Componentes Vários problemas de grande importância económica envolvem restrições de colocação, ou seja como colocar vários componentes num determinado espaço. Alguns desses problemas são • Cortes de peças de madeira de pranchas grandes e padronizadas; • Corte de peças de um rolo de tecido; • Colocação de pacotes em contentores. Os primeiros dois problemas são a 2 dimensões enquanto que o terceiro é a 3 dimensões. Vamo-nos restringir a problemas de 2 dimensões em que todos os elementos são rectangulares. 40 Colocação de Componentes Uma constatação imediata é o paralelismo entre estes problemas 2D e os de escalonamento de tarefas, considerando-se • O tempo como a dimensão X (abcissas); • Os recursos como dimensão Y (ordenadas); • A duração de uma tarefa como a sua dimensão X • Os recursos da tarefa como a sua dimensão Y Assim os programas utilizados anteriormente podem aparentemente continuar a sê-lo com esta nova interpretação. 41 Colocação de Componentes Exemplo: São dados 11 peças rectângulares (A a K) que é necessário obter através do corte de uma prancha rectangular. Os rectângulos têm as (comprimento-W e altura-H) seguintes dimensões W = [ 1, 2, 1, 3, 1, 2, 4, 5, 2, 3, 3] H = [ 2, 1, 3, 1, 4, 2, 1, 1, 3, 2, 3] Gráficamente D A E F G C I B J K H 42 Colocação de Componentes place(Comprimento,Altura, Time):- % definição dos rectângulos X = [Ax,Bx,Cx,Dx,Ex,Fx,Gx,Hx,Ix,Jx,Kx], W = [ 2, 1, 1, 3, 1, 2, 4, 5, 2, 3, 3], H = [ 1, 2, 3, 1, 4, 2, 1, 1, 3, 2, 3], domain(X, 1, Comprimento), % restrições em altura e comprimento nos X maximo(X,W,Comprimento), cumulative(X,W,H,Altura), % enumeração da origem-X dos rectângulos labeling([ffc], X). 43 Colocação de Componentes Infelizmente, os resultados obtidos não têm uma leitura directa. Por exemplo uma das soluções obtidas com um rectângulo de 8 * 6 são X = [ 6, 7, 5, 1, 4, 5, 1, 1, 7, 6, 1] que pode ser lida como (???) ou como F K I E A D C G B J H D A E F G C I B H J K 44 Colocação de Componentes Desta forma há que garantir a fixação da origem de cada peça igualmente no eixo das ordenadas (Y). Esta fixação pode ser feita tendo em atenção que ao rodarmos os rectângulos iniciais em 90º (e fizermos uma simetria vertical), os eixos do X e do Y ficam trocados. Assim o tratamento do eixo dos Y pode ser feito como o do eixo do X, obtendo-se um programa semelhante ao anterior. 45 Colocação de Componentes place(Comprimento,Altura, Time):% definição dos rectângulos % restrições em altura e comprimento nos X % enumeração da origem-X dos rectângulos % determinação das origens-Y dos rectângulos Y = [Ay,By,Cy,Dy,Ey,Fy,Gy,Hy,Iy,Jy,Ky], domain(Y, 1, Altura), % restrições em altura e comprimento nos Y maximo(Y,H,Altura), cumulative(Y,H,W,Comprimento), % enumeração da origem-Y dos rectângulos labeling([ff], Y). 46 Colocação de Componentes Infelizmente, os resultados obtidos ainda não são os esperados. Por exemplo, a primeira solução obtida é X-Y = [7-4,6-2,5-1,1-5,4-1,5-4,1-1,1-6,7-1,6-5,1-2] correspondendo a ????? Analisando-se a causa do problema é fácil concluir que não foi imposta nenhuma “não-sobreposição” entre os componentes ! D A E F G C I B H J K 47 Não-Sobreposição de Componentes A não-sobreposição de elementos com características (X1,Y1,W1,H1) e (X2,Y2,W2,H2) é garantida desde que uma das seguintes restrições seja satisfeita X1+W1 =< X2 O elemento 1 está à esquerda do 2 X2+W2 =< X1 O elemento 1 está à direita do 2 Y1+H1 =< Y2 O elemento 1 está abaixo do 2 Y2+H2 =< Y1 O elemento 1 está acima do 2 Em vez de impôr uma destas condições e testar as alternativas por retrocesso, podemos impô-las através do compromisso mínimo, com um operador do tipo do operador cardinalidade. 48 Não-Sobreposição de Componentes none_overlap([],[],[],[]). none_overlap([Hx|Tx], [Hy|Ty], [Hd|Td], [Hr|Tr]):no_overlap_each(Hx, Hy, Hd, Hr, Tx, Ty, Td, Tr), none_overlap(Tx, Ty, Td, Tr). no_over (_,_,_,_,[],[],[],[]). no_over (X1,Y1,D1,R1,[X2|Tx],[Y2|Ty],[D2|Td],[R2|Tr]):disj(X1,Y1,D1,R1,X2,Y2,D2,R2), no_over (X1,Y1,D1,R1,Tx, Ty, Td, Tr). disj(X1,Y1,D1,R1,X2,Y2,D2,R2):sat(M,[X1+D1#=<X2,X2+D2#=<X1,Y1+R1#=<Y2,Y2+R2#=<Y1]), M #>=1. sat(0,[]). sat(N,[H|T]):call(H #<=> B), N #= M + B,satisfy(M, T). 49 Não-Sobreposição de Componentes Podemos agora apresentar o programa completo para colocação de componentes, salientando a simetria em relação aos eixos dos X e dos Y place(Comp,Altura, Time):% definição dos rectângulos X = [Ax ... Kx], Y = [Ay ... Ky], W = [ 1 ... 3], H = [ 2 ... 3], domain(X, 1, Comp), domain(Y, 1, Altura), % restrições em altura e comprimento maximo(X,W,Comp), maximo(Y,H,Altura), % restrições cumulativas redundantes cumulative(Y,H,W,Comp), cumulative(X,W,H,Altura), % restrições de não sobreposição none_overlap(X,Y,D,R), % enumeração das origens dos rectângulos app(X,Y,Z), labeling([ffc], Z). 50 Colocação de Componentes De notar ainda que • a enumeração deve ser feita quer nos Xi quer nos Yj, donde a sua junção numa só lista Z; • Há várias heurísticas possíveis para enumeração das variáveis. A escolhida (para a variável), ffc, é “clássica”. • Outra hipótese é ir colocando um rectângulo (o “maior”) na primeira casa não ocupada num “canto” (todas as casas têm de ser ocupadas). • As restrições Cumulative não são estritamente necessárias, já que os limites ficam assegurados pelas restrições de limites em ambos os eixos. • No, entanto, elas são muito úteis como restrições redundantes! 51 Colocação de Componentes Os resultados obtidos mostram bem a importância de se utilizar a restrição global cumulative/4 como restrição redundante. Com efeito, testando o programa anterior com e sem estas restrições redundantes obtemos os seguintes resultados em 40 ms c/ cumulative em 24.465 ms sem cumulative D A E F G C I B H J K 52 Colocação de Componentes com Rotação Uma limitação óbvia dos programas feitos até agora é a sua impossibilidade de rodarem os componentes de 90º de forma a poderem “encaixar” melhor no espaço disponível. Por vezes só através destas rotações é que é possível colocar os componentes pretendidos. As alterações a fazer aos programas anteriores são pequenas. Dadas dimensões constantes Wc - Hc em comprimento e altura, apenas há que permitir que as dimensões “reais” dos componentes W-H ou são as indicadas ou são as “trocadas”. Dadas as dimensões constantes, essa flexibilidade é obtida pelo valor do parametro Modo (fixo/roda) 53 Colocação de Componentes com Rotação Exemplo: ... Wc = [ 6, 6, 5, 5, 4, 4, 3, 3, 2, 2], Hc = [ 2, 1, 2, 1, 2, 1, 2, 1, 2, 1], domains(Modo,W,H,Wc,Hc), ... ======================= domains(fixo, [],[],[],[]). domains(fixo, [W|Wt],[H|Ht],[Wc|Wtc],[Hc|Htc]):W = Wc, H = Hc, domains(fixo,Td,Tr,Tdc,Trc). domains(roda, [],[],[],[]). domains(roda,[Hd|Td],[Hr|Tr],[Hdc|Tdc],[Hrc|Trc]):Hd in {Hdc}\/{Hrc}, Hr in {Hdc}\/{Hrc}, Hr * Hd #= Hdc * Hrc, domains(roda, Td,Tr,Tdc,Trc). 54 Colocação de Componentes com Rotação Na enumeração há agora que ter em conta a rotação ou não do componente. Para isso basta enumerar uma das dimensões (W), para além da enumeração das origens X e Y de cada componente. Uma heurística possível é tentar colocar primeiro os componentes mais “difíceis”. Aqui consideramo-los como os que têm uma dimensão mais comprida e ordenamo-los como indicado atrás. Assim esta heurística de enumeração implementada através das chamadas pode ser merge( X, Y, Z), labeling([], Z), labeling([ffc], W), 55 Colocação de Componentes com Rotação Exemplo: São dados 10 rectangulos (A a J) que é necessário colocar numa prancha rectangular com área total de 60, podendo eventualmente ser rodados. Os rectângulos têm as (comprimento-W e altura-H) seguintes dimensões Wc = [ 6, 6, 5, 5, 4, 4, 3, 3, 2, 2], Hc = [ 2, 1, 2, 1, 2, 1, 2, 1, 2, 1], Gráficamente A C E G I B D F H J 56 Colocação de Componentes com Rotação Resultados em modo fixo (tempos em ms): Comp Larg 2 30 3 20 4 15 5 12 6 10 10 6 12 5 15 4 20 3 30 2 ms 532 542 542 542 552 40 40 50 40 120 X-Y no no no no no [1-1,1-3,1-4,1-6,7-1,7-3,6-4,6-6,9-4,9-6] [1-1,1-3,1-4,6-5,7-1,6-4,10-3,7-3,11-1,11-5] [1-1,1-3,7-1,1-4,12-1,7-3,11-3,6-4,14-3,9-4] [1-1,1-3,7-1,7-3,12-1,12-3,16-1,16-3,19-1,19-3] [1-1,7-1,17-1,7-2,22-1,13-1,26-1,12-2,29-1,15-2] A C E G I B D F H J 57 Colocação de Componentes com Rotação Resultados c/ rotação (a vermelho as peças rodadas): Comp Larg 2 30 3 20 4 15 5 12 6 10 10 6 12 5 15 4 20 3 30 2 ms 301 191 190 60 60 60 70 250 50 261 X-Y [1-1,1-7,1-16,2-7,1-21,2-12,1-25,1-13,1-28,1-30] [1-1,1-7,1-13,3-13,2-7,3-1,1-18,1-20,2-11,3-5] [1-1,1-7,2-7,4-5,3-1,4-10,2-14,1-13,2-12,3-5] [1-1,1-7,2-7,3-1,4-1,2-12,4-7,3-6,4-10,4-5] [1-1,1-3,1-4,1-6,1-7,3-7,3-8,6-4,5-8,5-10 [1-1,1-3,1-4,1-6,6-4,6-6,7-1,10-4,9-1,9-3] [1-1,1-3,1-4,6-4,7-1,7-3,11-1,6-5,11-4,9-5] [1-1,1-3,7-1,1-4,9-3,15-1,12-1,6-4,13-3,7-3] [1-1,1-3,7-1,7-3,12-1,12-3,16-1,16-3,19-1,19-3] [1-1,7-1,16-1,7-2,21-1,12-2,25-1,13-1,28-1,30-1] A C E G I B D F H J 58