Created: 2021-04-03 sáb 01:44
Dado Un programa \(P\), generar un programa \(P'\) que sea:
(analisis / sintesis de programas)
Considere detectar que una rama no ocurre:
int x,y,z; y:=read(file); x:= y * y;
if x >= 0 then z := 1 else z:= 0
y la multiplicación abstracta \(*_\alpha : {D_\alpha}^2 \to D_\alpha\) definido por:
\(*_\alpha\) | \([-]\) | \([+]\) |
---|---|---|
\([-]\) | \([+]\) | \([-]\) |
\([+]\) | \([-]\) | \([+]\) |
y la multiplicación abstracta \(*_\alpha : {D'_\alpha}^2 \to D'_\alpha\) definido por:
\(*_\alpha\) | \([-]\) | \([0]\) | \([+]\) |
---|---|---|---|
\([-]\) | \([+]\) | \([0]\) | \([-]\) |
\([0]\) | \([0]\) | \([0]\) | \([0]\) |
\([+]\) | \([-]\) | \([0]\) | \([+]\) |
\(+_\alpha : {D''_\alpha}^2 \to D''_\alpha\) definido por:
\(+_\alpha\) | \([-]\) | \([0]\) | \([+]\) | \(\top\) |
---|---|---|---|---|
\([-]\) | \([-]\) | \([-]\) | \(\top\) | \(\top\) |
\([0]\) | \([-]\) | \([0]\) | \([+]\) | \(\top\) |
\([+]\) | \(\top\) | \([+]\) | \([+]\) | \(\top\) |
\(\top\) | \(\top\) | \(\top\) | \(\top\) | \(\top\) |
También podemos definir (no estrictamente necesario) una función de abstracción (monótona) \[\alpha : \wp(D) \rightarrow D_\alpha\] \(\alpha(d) = \lambda\) si \(\lambda\) es el elemento "mínimo" de \(D_\alpha\) que describe \(d\) [bajo un orden adecuado definido en los elementos de \(D_\alpha\)]
p.ej. en el ejemplo de los "signos", \[ \begin{align} \alpha(\{1, 2, 3\}) &= [+] (no \top) \\ \alpha(\{- 1, −2, −3\}) &= [-] (no \top) \\ \alpha(\{0\}) &= [0] \\ \alpha(\{- 1, 0, 1\}) &= \top \\ \end{align} \]
\(\gamma(\bot)\) | \(=\) | \(\emptyset\) | \(\gamma(\top)\) | \(=\) | \(Z\) | |
\(\gamma([-])\) | \(=\) | \(\{x \in Z \arrowvert x < 0 \}\) | \(\gamma([+])\) | \(=\) | \(\{x \in Z \arrowvert x > 0 \}\) | \(\gamma([0]) = \{0\}\) |
\(\gamma([0^-])\) | \(=\) | \(\{x \in Z \arrowvert x \leq 0 \}\) | \(\gamma([0^+])\) | \(=\) | \(\{x \in Z \arrowvert x \geq 0 \}\) |
finito | cadena finita ascendente |
finito en profundidad | |
\(P = \{ p(f(X)) \leftarrow p(X). \\ p(a). q(a). q(b). \}\)
\(T^\alpha_P(D) = \{p \in S | \exists C \in P, C = h \rightarrow b_1, \ldots, b_n, \\ pred(h) \leftarrow pred(b_1), \ldots , pred(b_n) \equiv p \leftarrow p_1,\ldots , p_n, \\ \mbox{ y } p_1,\ldots , p_n \in D\}\)
\[P = \{p(f(X)) \leftarrow p(X). p(a). r(X) ← t(X,Y). q(a). q(b). \}\]
\[P_\alpha = \{p \leftarrow p. p. r ← t. q.\} \]
\(T^\alpha_P \uparrow 0 = T^\alpha_P(\emptyset) = {p / 1, q / 1}\)
\(T^\alpha_P \uparrow 1 = T^\alpha_P(\{p/1, q/1\}) = \{p/1, q/1\} = T^\alpha_P \uparrow 0 = H^\alpha\)
?- p. h:- p1, ... pn.
check
(default) – Es la semántica intentada, para ser
chequeada, es la especificación del programa, ingresada por el usuario.trust
– semántica real, ingresada por el usuario y creída por
el compilador (es una guía).true
o false
– semántica real, salida del compilador.checked
– validación: es un check
que ha sido probado. (igual
a true
).ejemplo
:- trust pred is(X,Y) => (num(X),numexpr(Y)).
:- check pred p/2 : list(int) * var => list(int) * int.
:- modedef +X : nonvar(X).
:- check pred sortints(+L,-SL) :: list(int) * list(int) + sorted(SL)
# "@var{SL} has same elements as @var{L}.".
Propiedades del estado de éxito. Son similiares en naturaleza a las postcondiciones usadas en verificación de programas
:- success Goal => Postcond.
debe ser interpretada como "para toda llamada de la forma Goal
que
tiene éxito, al momento del éxito Postcond
debería ser verdadero".
Restricción de las aserciones a un subconjunto de las llamadas
:- success Goal : Precond => Postcond.
debe ser interpretada como "para toda llamada de la forma Goal
para la cual Predcond
ocurre, si la llamada
tiene éxito, al momento del éxito Postcond
debería ser verdadero".
Propiedades en el estado de llamada de un predicado que pueden aparecer en tiempo de ejecución.
:- calls Goal : Cond.
se debe interpretar "toda llamada de la forma Goal
debería
satisfacer Cond
".
Propiedades de la computación
:- comp Goal : Precond + Comp_prop.
se debe interpretar "para toda llamada de la forma Goal
para la
cual Precond
ocurre, Comp_prop
debería ocurrir también para la
computación de Goal
".
Para facilitar la escritura una aserción compuesta de un predicado puede ser usado como azúcar sintáctico para las aserciones básicas. La aserción compuesta siguiente
:- pred Pred : Precond => Postcond + Comp_prop.
corresponde a la siguiente aserción de éxito:
:- success Pred : Precond => Postcond.
si la aserción pred
tiene un campo =>
(y un campo
:
). También corresponde a una aserción de computación de la forma:
:- comp Pred : Precond + Comp_prop.
si la aserción pred
tiene los campos +
y :
qsort
. Podemos usar la
siguiente aserción para requerir que la salida del procedimiento
qsort
sea una lista.
:- success qsort(A,B) => list(B).
alternativamente podemos requerir que qsort
es llamado con una
lista en su primer argumento y tiene exito, entonces el segundo
argumento también sera una lista.
:- success qsort(A,B) : list(A) => list(B).
La diferencia reside en que se espera que B
sea una lista en los casos en que A
sea una lista.
Además podemos requerir que en todas las llamadas al predicado
qsort
el primer argumento debe ser una lista:
:- calls qsort(A,B) : list(A).
El procedimiento qsort
debe ordenar cualquier lista. Asi,
requeriremos que todas las llamadas con una lista en el primer
argumento y una variable en el segundo no fallen:
:- comp qsort(A,B) : (list(A) , var(B)) + does_not_fail.
En lugar de todas estas aserciones se puede usar la compuesta:
:- pred qsort(A,B) : (list(A) , var(B)) => list(B) + does_not_fail.
que es equivalente a:
:- calls qsort(A,B) : (list(A), var(B)).
:- success qsort(A,B) : (list(A), var(B)) => list(B).
:- comp qsort(A,B) : (list(A) , var(B)) + does_not_fail.
si queremos llamar a qsort
con algo diferente a una variable en el
segundo argumento se debe agregar:
:- pred qsort(A,B) : (list(A) , var(B)) => list(B) + does_not_fail.
:- pred qsort(A,B) : list(A) => list(B).
que es equivalente a:
:- calls qsort(A,B) : ((list(A), var(B)) ; list(A)).
:- success qsort(A,B) : ((list(A), var(B)) ; list(A)). => list(B).
:- comp qsort(A,B) : (list(A) , var(B)) + does_not_fail.
Tipos Regulares son propiedades cuyas definiciones son "programas regulares". Ejemplos:
:- regtype tree(X) # "X is a tree.".
tree(nil).
tree(t(_,L,R)):-
tree(L),
tree(R).
:- regtype intlist(X) # "X is a list of integers"
intlist([]).
intlist([X|R]) :- int(X), intlist(R).
ejemplo de pred/1
:- pred length(L,N) : list * var => list * integer
# "Computes the length of L.".
:- pred length(L,N) : var * integer => list * integer
# "Outputs L of length N.".
:- pred length(L,N) : list * integer => list * integer
# "Checks that L is of length N.".
ejemplo de pred/2
:- check pred length(L,N) : list * var => list * integer.
ejemplo de comp/1
:- comp append(Xs,Ys,Zs) : var * var * var + not_fail.
test
es similar a success
pero especifica un caso de test como
parte de la especificación del predicado
:- test length(L,N) : ( L = [1,2,5,2] ) => ( N = 4 ).
definición de nuevos modos
:- modedef +A : nonvar(A) # "A is bound upon predicate entry.".
:- pred p(+A,B) : integer(A) => ground(B).
es equivalente a:
:- pred p(A,B) : (nonvar(A),integer(A)) => ground(B)
# "A is bound upon predicate entry.".
documentación
:- doc(Pred,Comment).
:- doc(p(A,B),"A is bound upon predicate entry.").
Entrada
:- module(app, [app/3], [assertions]).
:- entry app(A,B,C) : (list(A), list(B)).
app([],Y,Y).
app([X|Xs], Ys, [X|Zs]) :- app(Xs,Ys,Zs).
Salida
:- true pred app(A,B,C) : ( list(A), list(B), term(C) )
=> ( list(A), list(B), list(C) ).
:- true pred app(A,B,C)
: mshare([[A],[A,B],[A,B,C],[A,C],[B],[B,C],[C]])
=> mshare([[A,B,C],[A,C],[B,C]]).
Entrada
:- module(qsort, [qsort/2], [assertions]).
:- entry qsort(A,B) : (list(num, A), var(B)).
qsort([X|L],R) :-
partition(L,X,L1,L2),
qsort(L2,R2), qsort(L1,R1),
append(R2,[X|R1],R).
qsort([],[]).
partition([],_B,[],[]).
partition([E|R],C,[E|Left1],Right):-
E < C, !, partition(R,C,Left1,Right).
partition([E|R],C,Left,[E|Right1]):-
E >= C, partition(R,C,Left,Right1).
append([],X,X).
append([H|X],Y,[H|Z]):- append(X,Y,Z).
dominio shfr sin el ~:- entry … ~
:- true pred qsort(_A,R)
: mshare([[_A],[_A,R],[R]])
=> mshare([[_A,R]]).
:- true pred partition(_A,_B,Left,Right)
: ( mshare([[_A],[_A,_B],[_B],[Left],[Right]]), var(Left), var(Right) )
=> ( mshare([[_B]]), ground([_A,Left,Right]) ).
:- true pred append(_A,X,_B)
: ( mshare([[X],[X,_B],[_B]]), ground([_A]) )
=> ( mshare([[X,_B]]), ground([_A]) ).
dominio shfr con el :- entry qsort(A,B) : (list(num, A), var(B)).
:- true pred qsort(A,B)
: ( mshare([[B]]), var(B), ground([A]) )
=> ground([A,B]).
:- true pred partition(_A,_B,Left,Right)
: ( mshare([[Left],[Right]]), var(Left), var(Right), ground([_A,_B]) )
=> ground([_A,_B,Left,Right]).
:- true pred append(_A,X,_B)
: ( mshare([[_B]]), var(_B), ground([_A,X]) )
=> ground([_A,X,_B]).
dominio eterms sin :- entry qsort(A,B) : (list(num, A), var(B)).
:- true pred qsort(_A,R)
: ( term(_A), term(R) )
=> ( list(_A), list(R) ).
:- true pred partition(_A,_B,Left,Right)
: ( term(_A), term(_B), term(Left), term(Right) )
=> ( list(arithexpression,_A), term(_B),
list(arithexpression,Left), list(arithexpression,Right) ).
:- true pred append(_A,X,_B)
: ( list(_A), non_empty_list(X), term(_B) )
=> ( list(_A), non_empty_list(X), non_empty_list(_B) ).
dominio eterms con :- entry qsort(A,B) : (list(num, A), var(B)).
:- true pred qsort(A,B)
: ( list(num,A), term(B) )
=> ( list(num,A), list(num,B) ).
:- true pred partition(_A,_B,Left,Right)
: ( list(num,_A), num(_B), term(Left), term(Right) )
=> ( list(num,_A), num(_B), list(num,Left), list(num,Right) ).
:- true pred append(_A,X,_B)
: ( list(num,_A), list1(num,X), term(_B) )
=> ( list(num,_A), list1(num,X), list1(num,_B) ).
Entrada
:- module(qsort, [qsort/2], [assertions]).
:- entry qsort(A,B) : (list(num, A), var(B)).
qsort([X|L],R) :-
partition(L,X,L1,L2),
qsort(L2,R2), qsort(L1,R1),
append(R2,[x|R1],R). % <-- 'x' should be X (variable)
qsort([],[]).
partition([],_B,[],[]).
partition([E|R],C,[E|Left1],Right):-
E < C, !, partition(R,C,Left1,Right).
partition([E|R],C,Left,[E|Right1]):-
E >= C, partition(R,C,Left,Right1).
append([],X,X).
append([H|X],Y,[H|Z]):- append(X,Y,Z).
Salida
:- true pred qsort(A,B)
: ( list(num,A), term(B) )
=> ( list(num,A), list(^(x),B) ).
Entrada
:- module(_, [qsort/2], [assertions]).
:- entry qsort(A,B) : (list(num, A), var(B)).
qsort([X|L],R) :-
partition(L,L1,X,L2), % <-- swapped second and third arguments
qsort(L2,R2), qsort(L1,R1),
append(R2,[X|R1],R).
qsort([],[]).
partition([],_B,[],[]).
partition([e|R],C,[E|Left1],Right):- % <-- 'e' should be E (variable)
E < C, !, partition(R,C,Left1,Right).
partition([E|R],C,Left,[E|Right1]):-
E >= C, partition(R,C,Left,Right1).
append([],X,X).
append([H|X],Y,[H|Z]):- append(X,Y,Z).
Salida
{In /home/claudio/tmp/orgfiles/data/ciaopp/clase2/hacerslides/debugging/qsort2.pl
WARNING (preproc_errors): (lns 4-8) goal qsort2:partition(L,L1,X,L2) at literal 1 does not succeed!
}
{ERROR (ctchecks_messages): error printing:message_clause_incompatible(qsort2:partition/4/2,eterms
,qsort2:partition([e|C],A,[D|E],B),[A,B,C,D,E],[C,Right,R,E,Left1])
}
{In /home/claudio/tmp/orgfiles/data/ciaopp/clase2/hacerslides/debugging/qsort2.pl
WARNING (preproc_errors): (lns 14-15) goal arithmetic:>=(E,C) at
literal 1 does not succeed!
Chequear Aserciones
:- module(qsort3, [qsort/2], [assertions,regtypes,nativeprops]).
:- entry qsort(A,B) : (list(num, A), var(B)).
:- calls qsort(A,B) : list(num, A). % A1
:- success qsort(A,B) => (ground(B), sorted_num_list(B)). % A2
:- calls partition(A,B,C,D) : (ground(A), ground(B)). % A3
:- success partition(A,B,C,D) => (list(num, C),ground(D)). % A4
:- calls append(A,B,C) : (list(num,A),list(num,B)). % A5
:- prop sorted_num_list/1.
sorted_num_list([]).
sorted_num_list([X]):- number(X).
sorted_num_list([X,Y|Z]):-
number(X), number(Y), X=<Y, sorted_num_list([Y|Z]).
qsort([X|L],R) :-
partition(L,X,L1,L2),
qsort(L2,R2), qsort(L1,R1),
append(R2,[x|R1],R).
qsort([],[]).
partition([],_B,[],[]).
partition([E|R],C,[E|Left1],Right):-
E < C, !, partition(R,C,Left1,Right).
partition([E|R],C,Left,[E|Right1]):-
E >= C, partition(R,C,Left,Right1).
append([],X,X).
append([H|X],Y,[H|Z]):- append(X,Y,Z).
Entrada
:- module(_, [dup_first/2], []).
dup_first([X|Xs], Zs) :-
app([X], [X|Xs], Zs).
app([],Y,Y).
app([X|Xs], Ys, [X|Zs]) :-
app(Xs,Ys,Zs).
Salida
:- module(_1,[dup_first/2],[assertions]).
dup_first([A|B],[A,A|B]).
Entrada
:- module(append,[appe/3],[assertions] ) .
:- entry appe(A,B,C).
appe(A,B,C) :- append([1,2,3|A],B,C).
append([],X,X).
append([H|X],Y, [H|Z]):- append(X,Y,Z) .
Salida
:- module(_1,[appe/3],[assertions]).
:- entry appe(A,B,C).
appe([],A,[1,2,3|A]).
appe([B|C],A,[1,2,3,B|D]) :-
append_1(C,A,D).
append_1([],A,A).
append_1([B|C],A,[B|D]) :-
append_1(C,A,D).
Entrada
:- module(exponential_ac, [ent/2], [assertions]) .
:- entry ent(Base,_) : int(Base).
ent(Base,Res) :- exp(Base,3,Res).
exp(Base,Exp,Res):-
exp_ac(Exp,Base,1,Res).
exp_ac(0,_,Res,Res).
exp_ac(Exp,Base,Tmp,Res) :-
Exp > 0,
Expl is Exp - 1,
NTmp is Tmp * Base,
exp_ac(Expl,Base,NTmp,Res).
Salida
:- module(_1,[ent/2],[assertions]).
:- entry ent(Base,_A)
: int(Base).
ent(A,B) :-
C is A,
D is C*A,
E is D*A,
exp_ac_1(A,E,B).
exp_ac_1(_1,A,A).
Entrada
:- module(multiply,_,[assertions]).
:- entry mmultiply(X,Y,Z): (var(Z),list(X,list(num)),list(Y,list(num))).
:- entry mmultiply(X,Y,Z) : (var(Z),ground(X),ground(Y)).
mmultiply([],_,[]).
mmultiply([VO|Rest],V1,[Result|Others]):-
mmultiply(Rest,V1,Others),
multiply(V1,VO,Result).
multiply([],_,[]).
multiply([VO|Rest],VI,[Result|Others]):-
multiply(Rest,VI,Others),
vmul(VO,VI,Result).
vmul([],[],0).
vmul([H1|T1],[H2|T2],Result):-
vmul(T1,T2,Newresult),
Product is H1*H2,
Result is Product+Newresult.
Certificado
:- true pred A is B+C : (mshare([[A]]),var(A),ground([B,C]))
=> (ground([A,B,C])).
:- true pred A is B*C : (mshare([[A]]),var(A),ground([B,C]))
=> (ground([A,B,C])).
:- true pred A is B+C : (term(A),num(B),num(C))
=> (num(A),num(B),num(C)).
:- true pred A is B*C : (term(A),num(B),num(C))
=> (num(A),num(B),num(C)).