What minimal change to my code would make it preserve logical purity? - prolog

I posted the code below as an answer to this question and user "repeat" answered and commented that it's not logically pure and "if you are interested in a minimal change to your code that makes it preserve logical-purity, I suggest posting a new question about that. I'd be glad to answer it :)".
% minset_one(1 in D1, 1 in D2, D1, D2, D1Len, D2Len, T).
minset_one_(true, false, D1, _, _, _, D1).
minset_one_(false, true, _, D2, _, _, D2).
minset_one_(true, true, _, D2, D1Len, D2Len, D2) :- D1Len >= D2Len.
minset_one_(true, true, D1, _, D1Len, D2Len, D1) :- D1Len < D2Len.
minset_one(D1, D2, T) :-
(member(1, D1) -> D1check = true ; D1check = false),
(member(1, D2) -> D2check = true ; D2check = false),
length(D1, D1Len),
length(D2, D2Len),
minset_one_(D1check, D2check, D1, D2, D1Len, D2Len, T).
e.g.
?- D1 = [X,Y,Z], D2 = [U,V], minset_one(D1,D2,T).
D1 = [1, Y, Z],
D2 = T, T = [1, V],
U = X, X = 1 ;
false
there are more solutions possible. member(1, D1) is not backtracking through [1, Y, Z], then [X, 1, Z] then [X, Y, 1].

The Problem with (->)/2 (and friends)
Consider the following goal:
(member(1,D1) -> D1check = true ; D1check = false)
(->)/2 commits to the first answer of member(1,D1)—other answers are disregarded.
Can alternatives to (->)/2—like (*->)/2 (SWI, GNU) or if/3 (SICStus)—help us here?
No. These do not ignore alternative answers to make member(1,D1) succeed, but they do not consider that the logical negation of member(1,D1) could also have succeeded.
Back to basics: "If P then Q else R" ≡ "(P ∧ Q) ∨ (¬P ∧ R)"
So let's rewrite (If -> Then ; Else) as (If, Then ; Not_If, Else):
(member(1,D1), D1check = true ; non_member(1,D1), D1check = false)
How should we implement non_member(X,Xs)—can we simply write \+ member(X,Xs)?
No! To preserve logical purity we better not build upon "negation as finite failure".
Luckily, combining maplist/2 and dif/2 does the job here:
non_member(X,Xs) :-
maplist(dif(X),Xs).
Putting it all together
So here's the minimum change I propose:
minset_one_(true, false, D1, _, _, _, D1).
minset_one_(false, true, _, D2, _, _, D2).
minset_one_(true, true, _, D2, D1Len, D2Len, D2) :- D1Len >= D2Len.
minset_one_(true, true, D1, _, D1Len, D2Len, D1) :- D1Len < D2Len.
non_member(X,Xs) :-
maplist(dif(X),Xs).
minset_one(D1, D2, T) :-
(member(1,D1), D1check = true ; non_member(1,D1), D1check = false),
(member(1,D2), D2check = true ; non_member(1,D2), D2check = false),
length(D1, D1Len),
length(D2, D2Len),
minset_one_(D1check, D2check, D1, D2, D1Len, D2Len, T).
Running the sample query we now get:
?- D1 = [X,Y,Z], D2 = [U,V], minset_one(D1,D2,T).
D1 = [1,Y,Z], X = U, U = 1, D2 = T, T = [1,V]
; D1 = [1,Y,Z], X = V, V = 1, D2 = T, T = [U,1]
; D1 = T, T = [1,Y,Z], X = 1, D2 = [U,V], dif(U,1), dif(V,1)
; D1 = [X,1,Z], Y = U, U = 1, D2 = T, T = [1,V]
; D1 = [X,1,Z], Y = V, V = 1, D2 = T, T = [U,1]
; D1 = T, T = [X,1,Z], Y = 1, D2 = [U,V], dif(U,1), dif(V,1)
; D1 = [X,Y,1], Z = U, U = 1, D2 = T, T = [1,V]
; D1 = [X,Y,1], Z = V, V = 1, D2 = T, T = [U,1]
; D1 = T, T = [X,Y,1], Z = 1, D2 = [U,V], dif(U,1), dif(V,1)
; D1 = [X,Y,Z], D2 = T, T = [1,V], U = 1, dif(X,1), dif(Y,1), dif(Z,1)
; D1 = [X,Y,Z], D2 = T, T = [U,1], V = 1, dif(X,1), dif(Y,1), dif(Z,1)
; false.
Better. Sure looks to me like there's nothing missing.

I think it would be:
add:
:- use_module(library(reif)).
... and replace:
%(member(1, D1) -> D1check = true ; D1check = false),
%(member(1, D2) -> D2check = true ; D2check = false),
memberd_t(1, D1, D1check),
memberd_t(1, D2, D2check),
Example of the difference between member and memberd_t:
?- member(X, [A, B, C]).
X = A ;
X = B ;
X = C.
?- memberd_t(X, [A, B, C], IsMember).
X = A,
IsMember = true ;
X = B,
IsMember = true,
dif(A,B) ;
X = C,
IsMember = true,
dif(A,C),
dif(B,C) ;
IsMember = false,
dif(A,X),
dif(B,X),
dif(C,X).
?- memberd_t(X, [A, B, C], IsMember), X = 5, A = 5, C = 5.
X = A, A = C, C = 5,
IsMember = true ;
false.
So, memberd_t is itself adding the dif/2 constraints. To aid performance slightly, it loops through the list only once.
The definition of memberd_t is at e.g. https://github.com/meditans/reif/blob/master/prolog/reif.pl#L194 and https://www.swi-prolog.org/pack/file_details/reif/prolog/reif.pl?show=src

Related

Representing uniqueness on a restricted domain

Given some functions:
define foo(x,y) (x > y) end.
define bar(x) (foo x x) end.
define baz(x,y) (foo x y) end.
I am not interested in the exact values that a function takes/returns however I would like to know about how the sign of an input affects the output.
To model the greater than function I use the atoms zero_int which is interpreted as 0, pos_int which is interpreted as all integers greater than 0 and neg_int interpreted as all integers less than 0.
%% pos_int greater then ...
%% i.e forall n,m : (n > 0) & (m = 0) => n is_greater_than m
gt(pos_int,zero_int,true).
gt(pos_int,neg_int,true).
gt(pos_int, pos_int, X) :- boolean(X). % return either true or false.
%% zero greater than ...
gt(zero_int, pos_int, false).
gt(zero_int,zero_int,false).
gt(zero_int, neg_int, true).
%% neg int greater than...
gt(neg_int, pos_int, false).
gt(neg_int, zero_int, false).
gt(neg_int, neg_int, X) :- boolean(X).
the boolean/1 predicate is used to return either true or false when there is a choice point. i.e comparing n > m where n > 0 and m > 0 may be be either true or false. As we do not know the actual (integer) values of n and m assume that both cases are true.
%% define booleans
boolean(true).
boolean(false).
Now I encode the functions in the following way:
foo(X,Y,Return) :- gt(X,Y,Return).
bar(X,Return) :- foo(X,X,Return).
baz(X,Y,Return) :- foo(X,Y,Return).
testing foo (and baz) we get expected results:
?- foo(X,Y,Return).
X = pos_int,
Y = zero_int,
Return = true ;
X = pos_int,
Y = neg_int,
Return = true ;
X = Y, Y = pos_int,
Return = true ;
X = Y, Y = pos_int,
Return = false ;
X = zero_int,
Y = pos_int,
Return = false ;
...
My issue is that because bar calls gt with a single value - I would like for it to always return false as it is never the case than n > n
?- bar(X,Return).
X = pos_int,
Return = true ;
X = pos_int,
Return = false ;
X = zero_int,
Return = false ;
X = neg_int,
Return = true ;
X = neg_int,
Return = false.
I am interested in how one might encode this. I have explored using pairs of variables as inputs that would allow for labels which could be compared.
You could try something like
boolean(true).
boolean(false).
gt2((_, pos_int), (_, zero_int), (_,true)).
gt2((_, pos_int), (_, neg_int), (_,true)).
gt2((L1, pos_int), (L2, pos_int), (_,X)) :- not(L1 == L2), boolean(X).
%% zero greater than ...
gt2((_, zero_int), (_, pos_int), (_,false)).
gt2((_, zero_int), (_, zero_int), (_,false)).
gt2((_, zero_int), (_, neg_int), (_,true)).
%% neg int greater than...
gt2((_, neg_int), (_, pos_int), (_,false)).
gt2((_, neg_int), (_, zero_int), (_,false)).
gt2((L1, neg_int), (L2, neg_int), (_,X)) :- not(L1 == L2), boolean(X).
gt2((L,pos_int),(L,pos_int),(_,false)).
gt2((L,neg_int),(L,neg_int),(_,false)).
foo(X,Y,Return) :- gt2(X,Y,Return).
bar(X,Return) :- foo(X,X,Return).
baz(X,Y,Return) :- foo(X,Y,Return).
This uses the idea of labels which allow us to tag inputs such that we can encode equality. Basically if the labels match then the input is strictly equal. (ie given two inputs that within the set of positive integers, if they have the same label, then they are the same integer.
which would give the results:
?- bar(X,R).
X = (_31408, zero_int),
R = (_31414, false) ;
X = (_31408, pos_int),
R = (_31414, false) ;
X = (_31408, neg_int),
R = (_31414, false).
?- foo(X,Y,R).
X = (_31852, pos_int),
Y = (_31858, zero_int),
R = (_31864, true) ;
X = (_31852, pos_int),
Y = (_31858, neg_int),
R = (_31864, true) ;
X = (_31852, pos_int),
Y = (_31858, pos_int),
R = (_31864, true) ;
X = (_31852, pos_int),
Y = (_31858, pos_int),
R = (_31864, false) ;
X = (_31852, zero_int),
Y = (_31858, pos_int),
R = (_31864, false) ;
X = (_31852, zero_int),
Y = (_31858, zero_int),
R = (_31864, false) ;
X = (_31852, zero_int),
Y = (_31858, neg_int),
R = (_31864, true) ;
X = (_31852, neg_int),
Y = (_31858, pos_int),
R = (_31864, false) ;
X = (_31852, neg_int),
Y = (_31858, zero_int),
R = (_31864, false) ;
X = (_31852, neg_int),
Y = (_31858, neg_int),
R = (_31864, true) ;
X = (_31852, neg_int),
Y = (_31858, neg_int),
R = (_31864, false) ;
X = Y, Y = (_31852, pos_int),
R = (_31864, false) ;
X = Y, Y = (_31852, neg_int),
R = (_31864, false).
notice that foo generates an extra input for when the labels are the same.

Prolog singleton variable in branch

I have the below code:
loc_sucs(R, C, result(A, S)) :-
loc_sucs(R, C, S),
Rm is R - 1,
A \= move-north;
R = 0;
o(Rm, C);
r(Rm, C, S);
Rp is R + 1,
dim(Z, _),
A \= move-south;
R = Z;
o(Rp, C);
r(Rp, C, S);
Cp is C + 1,
dim(_, W),
A \= move-east;
C = W;
o(R, Cp);
r(R, Cp, S);
Cm is C - 1,
A \= move-west;
C = 0;
o(R, Cm);
r(R, Cm, S).
And I'm getting the singleton warning for Rm, Cm, Rp, Cp, Z and W. Why am I getting this warning if all of these variables are used more than once?

Unwanted evaluation on prolog

I was making a prolog knowledge base to implement geometry rules. When testing if a rectangle had a right angle, I found two answers.
?- rect_tri(triangle(line(point(0,0),point(0,1)),line(point(0,1),point(1,0)),line(point(1,0),point(0,0)))).
true ;
false.
Here is the kwnoledge base:
point(X,Y).
line(X,Y) :- X = point(A,B), Y = point(C,D), not(X = Y).
len(X,R) :- X = line(P,Q), P = point(A,B), Q = point(C,D), not(P = Q),
R is sqrt((A - C) * (A - C) + (B - D) * (B - D)).
triangle(X,Y,Z) :- X = point(A,B), Y = point(C,D), Z = point(E,F),
not(X = Y), not(X = Z), not(Y = Z),
L1 = line(X,Y), L2 = line(X,Z), L3 = line(Y,Z),
len(L1,G), len(L2,H), len(L3,I),
G + H > I, G + I > H, H + I > G.
triangle(X,Y,Z) :- X = line(A,B), Y = line(B,C), line(A,C),
len(X,G), len(Y,H), len(Z,I),
G + H > I, G + I > H, H + I > G.
rect_tri(X) :- X = triangle(A,B,C), len(A,G), len(B,H), len(C,I),
(G is sqrt(H * H + I * I);
H is sqrt(G * G + I * I);
I is sqrt(H * H + G * G)).
When tracing, I found that the answer true comes when prolog hits the line H is sqrt(G * G + I * I), and false when it evaluates the last line.
I don't want the last evaluation to occur, because I want it to exit when a true has been found.
Daniel comment probably shows the most sensible way to solve your problem. Some other option...
in modern compilers there is the if/then/else construct:
rect_tri(X) :- X = triangle(A,B,C), len(A,G), len(B,H), len(C,I),
( G is sqrt(H * H + I * I)
-> true
; H is sqrt(G * G + I * I)
-> true
; I is sqrt(H * H + G * G)
).
You could as well use cuts (old fashioned way, somewhat more readable here):
rect_tri(X) :- X = triangle(A,B,C), len(A,G), len(B,H), len(C,I),
( G is sqrt(H * H + I * I), !
; H is sqrt(G * G + I * I), !
; I is sqrt(H * H + G * G)
).

NMinimize is very slow

You are my last hope.
In my university there are no people able to answer my question.
I've got a function quite complex depending on 6 paramethers a0,a1,a2,b0,b1,b2 that minimize the delta of pression, volume liquid and volume vapor calculated by a rather new equation of state.
NMinimize is very slow and I could not do any considerations about this equation because timing is very high.
In the code there are some explanations and some problems concerning my code.
On my knees I pray you to help me.
I'm sorry, but after 4 months on construction of these equation I could not test it. And frustration is increasing day after day!
Clear["Global`*"];
data = {{100., 34.376, 0.036554, 23.782}, {105., 56.377, 0.037143,
15.116}, {110., 88.13, 0.037768, 10.038}, {115., 132.21, 0.038431,
6.9171}, {120., 191.43, 0.039138, 4.9183}, {125., 268.76,
0.039896, 3.5915}, {130., 367.32, 0.040714, 2.6825}, {135.,
490.35, 0.0416, 2.0424}, {140., 641.18, 0.042569, 1.5803}, {145.,
823.22, 0.043636, 1.2393}, {150., 1040., 0.044825,
0.98256}, {155., 1295., 0.046165, 0.78568}, {160., 1592.1,
0.047702, 0.63206}, {165., 1935.1, 0.0495, 0.51014}, {170.,
2328.3, 0.051667, 0.41163}, {175., 2776.5, 0.054394,
0.33038}, {180., 3285.2, 0.058078, 0.26139}, {185., 3861.7,
0.063825, 0.19945}, {190., 4518.6, 0.079902, 0.12816}};
tvector = data[[All, 1]];(*K*)
pvector =
data[[All, 2]];(*KPa*)
vlvector = data[[All, 3]];(*L/mol*)
vvvector =
data[[All, 4]];
(*L/mol.*)
r = 8.314472;
tc = 190.56;
avvicinamento = Length[tvector] - 3;
trexp = Take[tvector, avvicinamento]/tc;
vlexp = Take[vlvector, avvicinamento];
vvexp = Take[vvvector, avvicinamento];
zeri = Table[i*0., {i, avvicinamento}];
pexp = Take[pvector, avvicinamento];
(*Function for calculation of Fugacity of CSD Equation*)
(*Function for calculation of Fugacity of CSD Equation*)
fug[v_, p_, t_, a_, b_] :=
Module[{y, z, vbv, vb, f1, f2, f3, f4, f}, y = b/(4 v);
z = (p v)/(r t);
vbv = Log[(v + b)/v];
vb = v + b;
f1 = (4*y - 3*y^2)/(1 - y)^2;
f2 = (4*y - 2*y^2)/(1 - y)^3;
f3 = (2*vbv)/(r t*b)*a;
f4 = (vbv/b - 1/vb)/(r t)*a;
f = f1 + f2 - f3 + f4 - Log[z];
Exp[f]]
(*g Minimize the equality of fugacity*)
g[p_?NumericQ, t_?NumericQ, a0_?NumericQ, a1_?NumericQ, a2_?NumericQ,
b0_?NumericQ, b1_?NumericQ, b2_?NumericQ] := Module[{},
a = a0*Exp[a1*t + a2*t^2];
b = b0 + b1*t + b2*t^2;
csd = a/(r*t*(b + v)) - (-(b^3/(64*v^3)) + b^2/(16*v^2) +
b/(4*v) + 1)/(1 - b/(4*v))^3 + (p*v)/(r*t);
vol = NSolve[csd == 0 && v > 0, v, Reals];
sol = v /. vol;
(*If[Length[sol]==1,Interrupt[];Print["Sol==1"]];*)
vliquid = Min[sol];
vvapor = Max[sol];
fl = fug[vliquid, p, t, a, b];
fv = fug[vvapor, p, t, a, b];
(*Print[{t,p,vol,Abs[fl-fv]}];*)
Abs[fl - fv]];
(*This function minimize the pcalc-pexp and vcalc-vexp *)
hope[a0_?NumericQ, a1_?NumericQ, a2_?NumericQ, b0_?NumericQ,
b1_?NumericQ, b2_?NumericQ] :=
Module[{},
pp[a0, a1, a2, b0, b1, b2] :=
Table[FindRoot[{g[p, tvector[[i]], a0, a1, a2, b0, b1, b2]},
{p,pvector[[i]]}],{i,avvicinamento}];
pressioni1 = pp[a0, a1, a2, b0, b1, b2];
pcalc = p /. pressioni1;
differenza = ((pcalc - pexp)/pexp)^2;
If[MemberQ[differenza, 0.],
differenza = zeri + RandomReal[{100000, 500000}];(*
First problem:
As I've FindRoot that finds the solutions equal to the starting \
point, I don't want these kind of solutions and with this method - \
+RandomReal[{100000,500000}] -
a keep away this solutions.Is it right? *)
deltap = Total[differenza],
differenzanonzero = Select[differenza, # > 0 &];
csd1[a_, b_, p_, t_] :=
a/(r*t*(b + v)) - (-(b^3/(64*v^3)) + b^2/(16*v^2) + b/(4*v) +
1)/(1 - b/(4*v))^3 + (p*v)/(r*t);(*Funzione CSD*)
volumi =
Table[NSolve[csd1[a, b, pcalc[[i]], tvector[[i]]], v, Reals], {i,
avvicinamento}];
soluzioni = v /. volumi;
vvcalc = Table[Max[soluzioni[[i]]], {i, avvicinamento}];
vlcalc = Table[Min[soluzioni[[i]]], {i, avvicinamento}];
deltavl = Total[((vlexp - vlcalc)/vlcalc)^2];
deltavv = Total[((vvexp - vvcalc)/vvcalc)^2];
deltap = Total[differenza];
Print[a0, " ", b0, " ", delta];
delta = 0.1*deltavl + 0.1*deltavv + deltap]];
NMinimize[{hope[a0, a1, a2, b0, b1, b2],
500 < a0 < 700 && -0.01 < a1 < -1.0*10^-5 && -10^-5 < a2 < -10^-7 &&
0.0010 < b0 < 0.1 && -0.0010 < b1 < -1.0*10^-5 &&
10^-9 < b2 < 10^-7}, {a0, a1, a2, b0, b1, b2}]
Thanks in advance!
Mariano Pierantozzi
PhD Student in chemical Engineering

Sorting Erlang records in a list?

I have a record in erlang:
-record(myrec,
{
id = 0,
price = 0,
quantity = 0
}).
I then have a list of records that I want to sort by id and price, both in descending and ascending order, where price is the first key and if two records have the same price I want to sort those by id.
How can I define a fun for this?
I'm a newb at Erlang :)
thanks,
nisbus
This is a shorter solution than what has been suggested so far. First define your record:
1> rd(myrec, {id=0, price=0, quantity=0}).
myrec
Then let's invent 3 of them:
2> A = #myrec{id=1, price=10, quantity=2}, B = #myrec{id=2, price=4, quantity=3}, C = #myrec{id=3, price=10, quantity=1}.
#myrec{id = 3,price = 10,quantity = 1
Now we need a comparison function. This is where the solution is shorter. Erlang can compare terms of a tuple in the order they appear, so if we want to sort by price, then by id, we just have to compare two tuples of the form {PriceA, IdA} < {PriceB, IdB}:
3> F = fun(X, Y) -> {X#myrec.price, X#myrec.id} < {Y#myrec.price, Y#myrec.id} end.
#Fun<erl_eval.12.113037538>
And plug it in lists:sort/2:
4> lists:sort(F, [C,B,A]).
[#myrec{id = 2,price = 4,quantity = 3},
#myrec{id = 1,price = 10,quantity = 2},
#myrec{id = 3,price = 10,quantity = 1}]
The order is now [B, A, C] and your list is sorted.
Note that if you wanted to sort by descending id instead, You could trick it by reversing the ids in the tuples as follows:
5> G = fun(X, Y) -> {X#myrec.price, Y#myrec.id} < {Y#myrec.price, X#myrec.id} end.
#Fun<erl_eval.12.113037538>
6> lists:sort(G, [C,B,A]).
[#myrec{id = 2,price = 4,quantity = 3},
#myrec{id = 3,price = 10,quantity = 1},
#myrec{id = 1,price = 10,quantity = 2}]
Giving us [B, C, A]. This is not obvious to the reader, so you'd better document it or use Dustin's solution in this case. The advantage of the solution presented here is that there is no nesting required. By setting elements in either tuple in the comparison, you can pretty much compare as many of them as you want without making the code that much longer.
First, you figure out how to compare your records:
-spec compare(#myrec{}, #myrec{}) -> boolean().
compare(A, B) ->
case A#myrec.price == B#myrec.price of
true ->
A#myrec.id < B#myrec.id;
_ ->
B#myrec.price < A#myrec.price
end.
Then, you just use the normal lists:sort function with your comparison function to get what you want (this is an eunit test of the above I ran to make sure I did something that made sense):
compare_test() ->
R1 = #myrec{id=5, price=3, quantity=2},
R2 = #myrec{id=6, price=5, quantity=1},
R3 = #myrec{id=7, price=5, quantity=0},
false = compare(R1, R2),
true = compare(R2, R1),
true = compare(R2, R3),
false = compare(R3, R2),
false = compare(R1, R3),
true = compare(R3, R1),
% Run a sort with the above comparator.
[R2, R3, R1] = lists:sort(fun compare/2, [R1, R2, R3]).
% 3723064
-module(t).
-export([record_sort/0, price_cmp/2, qty_cmp/2]).
-record (item, {id = 0, price = 0, quantity = 0}).
price_cmp(A, B) ->
A#item.price < B#item.price.
qty_cmp(A, B) ->
A#item.quantity < B#item.quantity.
record_sort() ->
Items = [
#item{id=1, price=10, quantity=5},
#item{id=2, price=50, quantity=0},
#item{id=3, price=30, quantity=3},
#item{id=4, price=60, quantity=9}
],
io:format("Unsorted Items: ~p~n", [Items]),
io:format("By Price: ~p~n", [lists:sort({t, price_cmp}, Items)]),
io:format("By Quantity: ~p~n", [lists:sort({t, qty_cmp}, Items)]).
% Alternatively use anonymous functions:
% io:format("By Price: ~p~n", [lists:sort(
% fun(A, B) -> A#item.price < B#item.price end, Items)]),
%
% io:format("By Quantity: ~p~n", [lists:sort(
% fun(A, B) -> A#item.quantity < B#item.quantity end, Items)]).
This will yield (assuming example file t.erl):
1> c(t).
{ok,t}
2> t:record_sort().
Unsorted Items: [{item,1,10,5},{item,2,50,0},{item,3,30,3},{item,4,60,9}]
By Price: [{item,1,10,5},{item,3,30,3},{item,2,50,0},{item,4,60,9}]
By Quantity: [{item,2,50,0},{item,3,30,3},{item,1,10,5},{item,4,60,9}]
ok

Resources