Ano lectivo de 1996/97
O presente texto descreve a proposta de trabalho laboratorial (opcional) da disciplina Métodos Formais de Programação II (obrigatória da Licenciatura em Matemática e Ciências da Computação e opcional da Licenciatura em Engenharia de Sistemas e Informática ), na sua edição de 1996/97. Esta proposta é partilhada pela disciplina Desenvolvimento de Sistemas de Informação (obrigatória da Licenciatura em Engenharia de Sistemas e Informática e opcional da Licenciatura em Matemática e Ciências da Computação ).
O que se pretende neste trabalho é que os alunos adquiram prática laboratorial em ``prototipagem rápida'' e ``cálculo de programas'', as áreas dos métodos formais de especificação e desenvolvimento de aplicações de que a disciplina se ocupa.
O tema do presente projecto laboratorial combina e estende dois problemas que foram abordados nas aulas práticas da disciplina Métodos Formais de Programação I , edição de 96/97: Ex. 2.47 sobre o modelo de dados Orc e Ex. 2.54 sobre o modelo de dados Actplan.
Destes exercícios recorda-se o seguinte:
Orc = Item-> (Nat + SubOrc)onde Item é uma entidade atómica para identificação de ítens orçamentais. Verificou-se então que se podia prescindir da especificação de várias funções sobre Orc por simples reutilização de funções semelhantes já especificadas num outro modelo --- FS ('file system') --- que é ``isomorfo'' ao presente.
SubOrc = Orc
ActPlan = Act -> ActInf; ActInf :: De: Desc S: Span R: Resources Dp: Act-set;
Um escalonamento, definido por
Schedule = Act-> Nat0é uma indicação, para cada tarefa, do instante (medido em e.g. semanas ou dias) em que está previsto a tarefa arrancar. Foi especificado o operador
bestSchedule : ActPlan --> Scheduleque, consultando um mapa de actividades, constrói o melhor escalonamento das suas actividades. Por melhor entende-se aquele em que as tarefas são escalonadas o mais cedo possível, sem violar quaisquer dependências entre si.
O que se pretende neste trabalho é especificar e implementar um sistema que combine, estenda e generalize os dois modelos dados. O resultado final deverá ser uma aplicação capaz de fazer gestão integrada de projectos, nas suas componentes de planeamento, escalonamento, previsão de custos e orçamentação.
Para o efeito foi desenvolvido um pequeno protótipo CAMILA , que faz parte do material disponível para a realização do projecto (Ver Anexo). Este protótipo, que deve ser encarado como um mero ponto de partida, é completamente aberto à extensão ou modificação e consta das partes seguintes:
Recordando o ``ciclo de vida'' para as aplicações, adoptado nesta disciplina,
são os seguintes os requisitos deste trabalho:
Deste exercício saltará a necessidade de melhorar significativamente tal protótipo, incluindo o aumento de funcionalidade e a identificação de invariantes. (Uma actividade interessante a especificar poderá dizer respeito à procura, fixado o tempo de execução de um projecto, de um escalonamento que minimize a flutuação relativa dos recursos envolvidos.)
De tudo isto deve ser realizado um breve relatório e uma demonstração final.
Os grupos devem combinar com o monitor da disciplina a data de entrega do relatório do projecto, e correspondente demo, por forma a que esta se realize até duas semanas antes do lançamento das notas no livro de termos, ie. 16 de Julho de 1997 (época normal) ou 4 de Setembro de 1997 (época de recurso).
Não serão aceites trabalhos em Setembro para melhoria.
;===================================================================== ; `Kit' para trabalho laboratorial M.F.P.II - 96/97 ;--------------------------------------------------------------------- ; Equipa docente: {jno,lsb,fln}@di.uminho.pt ;===================================================================== ; 0. Auxiliary Functions ;--------------------------------------------------------------------- FUNC f870(f:A->(B->C)):AxB->C RETURN PLUS({ let (g=f[a]) in [ < a, b> -> g[b] | b <- dom(g) ] | a <- dom(f) }); FUNC f822(p:AxB):BxA RETURN <p2(p),p1(p)>; FUNC f87x(f:AxB->C):A->(B->C) RETURN let (X=dom(f), Y=p1-set(X)) in [ a -> [ p2(p) -> f[p] | p <- X : p1(p)==a ] | a <- Y ]; FUNC mcup(m:A->NAT,n:A->NAT):A->NAT RETURN monff(m,n,add); FUNC MCUP(l:(A->NAT)-seq):A->NAT RETURN mcup-orio([],l); FUNC monff(m:A->B,n:A->B,o:BxB -> B):A->B RETURN m + n + [ a -> o(m[a],n[a]) | a <- dom(m) * dom(n) ]; FUNC span(i:INT,d:INT):INT-set RETURN { i .+ x .- 1 | x <- inseg(d) }; FUNC mmcup(f1:A->(B->INT),f2:A->(B->INT)): A->(B->INT) RETURN f1 + f2 + [ k -> mcup(f1[k],f2[k]) | k <- dom(f1)*dom(f2) ]; MMCUP(l)=mmcup-orio([],l); PLUS(l)=plus-orio([],l); FUNC MAX(s:INT-set):INT RETURN MAXloop(s,0); FUNC MAXloop(s:INT-set,m:INT):INT RETURN if (s=={}) then m else let (x=choice(s)) in MAXloop(s-{x}, if (x < m) then m else x); /* etc */ ;--------------------------------------------------------------------- ; 1. Actplan ;--------------------------------------------------------------------- ; 1.1. Actplan sorts ;--------------------------------------------------------------------- TYPE ActPlan = Act -> ActInf; ActInf :: De: Desc S: Span R: Resources Dp: Deps; Resources = Res -> INT; Schedule = Act -> INT; ActPlan1 = Act -> ActInf1; ActInf1 :: A: INT B: Span C: Resources ; ResHist = Res -> (Time -> INT); Deps = Act-set; Res = STR; Act = INT; Desc = STR; Span = INT; Time = INT; ENDTYPE ;--------------------------------------------------------------------- ; 1.2. Actplan functions ;--------------------------------------------------------------------- FUNC bestSchedule(db:ActPlan):Schedule RETURN [ a -> bestStart(a,db) | a <- dom(db) ]; FUNC genActPlan1(db:ActPlan,s:Schedule):ActPlan1 RETURN [ a -> let (x=db[a]) in ActInf1(s[a],S(x),R(x)) | a <- dom(db) * dom(s) ]; FUNC bestStart(a:Act,db:ActPlan):INT RETURN let (x=db[a], D=Dp(x)) in if D=={} then 0 else MAX({ bestStart(aa,db) .+ S(db[aa]) | aa <- Dp(x)}); FUNC genResHist(a:ActPlan1):ResHist RETURN let (b=[ t -> let (x=a[t]) in [ i -> C(x) | i <- span(A(x),B(x)) ] | t <- dom(a) ], c=MMCUP(<b[t] | t <- dom(b) >), d=f870(c), e=f87x(f822->*(d))) in e; FUNC ActPlan2TeX(db:ActPlan):TeX RETURN let (a=bestSchedule(db), b=*->S(db)) in < TeXCmd("begin",<"tabular","{l}">) > ^ CONC(< < TeXCmd("rule",<strcat(itoa(a[k]),"cm"),"0mm">), TeXCmd("rule",<strcat(itoa(b[k]),"cm"),"4mm">), TeXCons("\\ ") > | k <- dom(b) >) ^ < TeXCmd("end",<"tabular">) >; /* etc */ ;--------------------------------------------------------------------- ; 2. Orc ;--------------------------------------------------------------------- ; 2.1. Orc sorts ;--------------------------------------------------------------------- TYPE Orc = Item -> Info; Info = Acts | SubOrc; SubOrc :: O: Orc; Acts :: A: Act-set; Item = STR; ENDTYPE ;--------------------------------------------------------------------- ; 2.2. Orc functions ;--------------------------------------------------------------------- FUNC total(db:Orc):Act-set RETURN UNION({ let (x=db[i]) in if is-Acts(x) then A(x) else total(O(x)) | i <- dom(db) }); FUNC rubricas(db:Orc):(Item-seq)-set RETURN UNION({ let (x=db[i]) in if is-Acts(x) then { <i> } else { <i> ^ p | p <- rubricas(O(x)) } | i <- dom(db) }); FUNC cats(db:Orc):(Item-seq)-set RETURN { <> } U UNION({ let (x=db[i]) in if is-Acts(x) then { <> } else { <i> ^ p | p <- cats(O(x)) } | i <- dom(db) }); FUNC novaSubcat(db:Orc,i:Item,c:Item-seq):Orc RETURN novaInfo(db,i,c,SubOrc([])); FUNC novaRubrica(db:Orc,i:Item,c:Item-seq):Orc RETURN novaInfo(db,i,c,Acts({})); FUNC novaInfo(db:Orc,i:Actm,c:Item-seq,y:Info):Orc RETURN if c == <> then (if i in dom(db) then db else db + [ i -> y ]) else let (h=hd(c),t=tl(c)) in if ~(h in dom(db)) then db else let (x=db[h]) in if is-Acts(x) then db else db + [ h -> SubOrc(novaInfo(O(x),i,t,y)) ]; FUNC updateInfo(db:Orc,c:Item-seq,f:InfoxInfo->Info,i:Info):Orc RETURN if c == <> then db else let (h=hd(c),t=tl(c)) in if ~(h in dom(db)) then db else let (x=db[h]) in if is-SubOrc(x) then db + [ h -> if t==<> then f(x,i) else SubOrc(updateInfo(O(x),t,f,i)) ] else if t==<> then db + [ h -> f(x,i) ] else db; FUNC remoInfo(db:Orc,c:Item-seq):Orc RETURN if c == <> then [] else let (h=hd(c),t=tl(c)) in if ~(h in dom(db)) then db else let (x=db[h]) in if is-Acts(x) then (if t==<> then db \ { h } else db) else if t==<> then db \ { h } else db + [ h -> remoInfo(O(x),t) ]; /* etc */ ;--------------------------------------------------------------------- ; 3. Project = Actplan * Orc ;--------------------------------------------------------------------- ; 3.1. Project sorts ;--------------------------------------------------------------------- TYPE Project :: A: ActPlan O: Orc; ENDTYPE ;--------------------------------------------------------------------- ; 3.3. Project functions ;--------------------------------------------------------------------- /* etc */ ;--------------------------------------------------------------------- ; 4. System = Collection of Projects ;--------------------------------------------------------------------- ; 4.1. System sorts ;--------------------------------------------------------------------- TYPE Db = ProjId -> Project; ProjId = STR; ENDTYPE ;--------------------------------------------------------------------- ; 4.2. System functions ;--------------------------------------------------------------------- /* etc */ ;--------------------------------------------------------------------- ; 4.3. System state ;--------------------------------------------------------------------- ; STATE db:Db ;--------------------------------------------------------------------- ; 4.4. System actions ;--------------------------------------------------------------------- FUNC INIT():SYM STATE db <- []; FUNC UPLOAD():SYM STATE db <- [ "Demo" -> Project( [ 0 -> ActInf( "Limpeza do terreno", 1 , [ "Mao de obra"->2 ], {}), 1 -> ActInf( "Fundacoes", 3 , [ "Mao de obra"->5 , "Ferro"->700 , "Massa" ->100 ], { 0 }), 2 -> ActInf( "Estrutura r/c", 5 , [ "Mao de obra"->5 , "Ferro"->800 , "Massa" ->200 ], { 1 }), 3 -> ActInf( "Laje piso", 2 , [ "Mao de obra"->3 , "Ferro"->700 , "Massa" ->100 ], { 2 }), 4 -> ActInf( "Massame r/c", 1 , [ "Mao de obra"->3 , "Massa" ->100 ], { 2,3 }), 5 -> ActInf( "Estrutura andar", 5 , [ "Mao de obra"->5 , "Ferro"->800 , "Massa" ->200 ], { 2 }), 6 -> ActInf( "Divisoes interior r/c", 2 , [ "Mao de obra"->2 , "Tijolo" -> 500 , "Massa" -> 50 ], { 4 }), 7 -> ActInf( "Laje cobertura", 3 , [ "Mao de obra"->5 , "Ferro"->800 , "Massa" ->200 ], { 5 }), 8 -> ActInf( "Divisoes interior andar", 2 , [ ], { 7 }), 9 -> ActInf( "Telha e caleiros", 1 , [ "Mao de obra"->2 , "Tijolo" -> 500 , "Massa" -> 50 ], { 7 }), 10 -> ActInf( "Drenagens e isolamentos", 1 , [ "Mao de obra"->2 , "Tubagens" -> 100 , "Isolante" -> 50 , "Massa" -> 10 ], { 2,5,9 }), 11 -> ActInf( "Portas e vidracas exteriores", 1 , [ "Mao de obra"->2 , "Madeira"-> 200 , "Vidro" -> 50 , "Ferragens" -> 10 ], { 9 }), 12 -> ActInf( "Reboco e pintura exterior", 2 , [ "Mao de obra"->2 , "Tinta" -> 50 , "Massa" -> 50 ], { 9, 10, 11 }), 13 -> ActInf( "Instalacao electrica", 2 , [ "Mao de obra"->2 , "Material electrico" -> 10 ], { 6, 8 }), 14 -> ActInf( "Instalacao sanitaria", 2 , [ "Mao de obra"->2 , "Tubagens" -> 40 ], { 6, 8 }), 15 -> ActInf( "Portas interiores", 2 , [ "Mao de obra"->2 , "Madeira"-> 150 , "Ferragens" -> 10 ], { 13 }), 16 -> ActInf( "Rebocos interiores", 2 , [ "Mao de obra"->2 , "Massa" -> 30 ], { 15, 13, 14 }), 17 -> ActInf( "Soalhos e pavimentos", 2 , [ "Mao de obra"->3 , "Madeira"-> 300 ], { 16 }), 18 -> ActInf( "Pintura interior", 2 , [ "Mao de obra"->2 , "Tinta" -> 30 ], { 16, 17 }), 19 -> ActInf( "Moveis cozinha etc", 2 , [ "Mao de obra"->2 , "Mobiliario" -> 10 ], { 18 }), 20 -> ActInf( "Loucas sanitarias", 2 , [ "Mao de obra"->2 , "Loucas" -> 10 ], { 17 }), 21 -> ActInf( "Limpeza geral", 2 , [ "Mao de obra"->5], { 19 }), 22 -> ActInf( "Arranjos exteriores", 2 , [ ], { 10, 12 }), 23 -> ActInf( "Instalacao de aquecimento", 2 , [ "Mao de obra"->3 , "Tubagens" -> 40, "Radiadores" -> 60, "Fonte de calor" -> 100 ], { 6, 8 }) ], [ "Obra de betao armado"-> Acts( { 1, 2, 3, 5 }), "Limpezas e arranjos"-> Acts( { 0, 22 }), "Obra de massa ou reboco"-> Acts( { 4, 12, 16 }), "Obra de tijolo"-> Acts( { 6, 8 }), "Lajes"-> Acts( { 7 }), "Cobertura"-> Acts( { 9 }), "Isolamentos e drenagens"-> Acts( { 10 }), "Equipamento"-> SubOrc( [ "Sanitario"-> Acts( { 14 }), "Electrico"-> Acts( { 13 }), "Aquecimento"-> Acts( { 23 }), "Cozinha"-> Acts( { 19 }) ]), "Carpintaria"-> SubOrc( [ "Aberturas"-> SubOrc( [ "Janelas e portas"-> Acts( { 11 }), "Portas interiores"-> Acts( { 15 }) ]), "Pavimentos"-> Acts( { 17 }) ]), "Obra de pintor"-> Acts( { 18 }), "Pavimentos"-> Acts( { 1000 }) ]) ]; /* etc */ ;--------------------------------------------------------------------- ; 5. API ;--------------------------------------------------------------------- /* etc (All external calls to the overall application) */