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) */