Is Prolog the best language to solve this kind of problem? - prolog

I have this problem containing some inequations and requirement to minimize a value. After doing some research on the Internet, I came to conclusion that using Prolog might be the easiest way to solve it. However, I never used Prolog before, and I would hate to waste my time learning it just to discover that it is not the right tool for this job.
Please, if you know Prolog, take a look at this problem and tell me if Prolog is the right one. Or, if you know of some other language that is really suited for this.
a + b + c >= 100
d + e + f >= 50
g + h >= 30
if (8b + 2e + 7h > 620) then y = 0.8 else y = 1.0
if (d > 35) then x = 0.9 else x = 1.0
5xa + 8yb + 5c + 3xd + 2ye + 2f + 6xg + 7yh = w.
I need to find the values for a, b, c, d, e, f, g and h that minimize w.
Please note that the above is only an example. In real program, I would use up to 10000 variables and up to 20 if..then clauses. This rules out linear programming as an alternative technique because it would take a prohibitive amount of RAM and time to test all LP problems.
I'm not really asking for code, although I'd be grateful for some hint how to tackle this if Prolog is really good for it. Thanks.

You could have a look at Constraint Logic Programming, either CLP(R), CLP(Q) or CLP(FD).
Your problem can be encoded into CLP(R) as follows (I think):
:- use_module(library(clpr)).
test(sol([A,B,C,D,E,F,G,H], [X,Y,W])) :-
{A >=0, B >=0, C>=0, D>=0, E>=0, F>=0, G>=0, H>=0},
{A + B + C >= 100},
{D + E + F >= 50},
{G + H >= 30},
{5*X*A + 8*Y*B + 5*C + 3*X*D + 2*Y*E + 2*F + 6*X*G + 7*Y*H = W},
(({8*B + 2*E + 7*H > 620},{Y=0.8}) ; ({8*B + 2*E + 7*H =35},{X=0.9}) ; ({D=
Using SICStus Prolog, I get the following answer:
| ?- test(A).
A = sol([_A,0.0,_B,0.0,_C,_D,30.0,0.0],[1.0,1.0,780.0]),
{_A=100.0-_B},
{_C=50.0-_D},
{_B==0.0},
{_D>=0.0} ? ;
no

You can solve this using linear programming (LP), but the problem needs some modification before you can chuck it into an LP solver. An LP problem basically involves maximising or minimising a function given some constraints.
First, split the problem into two problems (as LP does not support the two if conditions you have):
Constraints:
a + b + c >= 100
d + e + f >= 50
g + h >= 30
8b + 2e + 7h > 620
Linear function:
5 * 0.8a + 8 * 1.0b + 5c + 3 * 0.8d + 2 * 1.0e + 2f + 6 * 0.8g + 7 * 1.0h = w
And
Constraints:
a + b + c >= 100
d + e + f >= 50
g + h >= 30
d > 35
Linear function:
5 * 1.0a + 8 * 0.9b + 5c + 3 * 1.0d + 2 * 0.9e + 2f + 6 * 1.0g + 7 * 0.9h = w
After you run both separately by the LP solver, the solution will come out with the values of a, b, c, d, e, f, g, h and w. Pick the smaller value of w and the corresponding values of a, b, c, d, e, f, g, h.
How does this work?
The two if conditions are effectively similar to the other constraints listed, just that they entail different values of x and y. Since the two conditions are mutually exclusive (given that both cannot be satisfied as x and y will hence have different values), you can split them into two separate LP problems. As a result, you solve the LP problems individually, and hence you will arrive at a minimised value of w.
For an LP solver, go to the linear programming Wikipedia article as linked above. There are tools like Excel and some others which are easier to use, but if you want a program, then there are numerical languages which are good at this, or general purpose languages like C that can do this with a library like glpk.
Hope this helps!

I haven't worked with similar problems before, so I can't give you any direct suggestions. However, I would not use Prolog for it. Prolog is really good for dealing with symbolic problems (a classic example would be the Einstein puzzle), but its math support is very awkward; it feels like math was tacked on as an afterthought.

Related

Probability of a disjunction on N dependent events in Prolog

Does anybody know where to find a Prolog algorithm for computing the probability of a disjunction for N dependent events? For N = 2 i know that P(E1 OR E2) = P(E1) + P(E2) - P(E1) * P(E2), so one could do:
prob_disjunct(E1, E2, P):- P is E1 + E2 - E1 * E2
But how can this predicate be generalised to N events when the input is a list? Maybe there is a package which does this?
Kinds regards/JCR
The recursive formula from Robert Dodier's answer directly translates to
p_or([], 0).
p_or([P|Ps], Or) :-
p_or(Ps, Or1),
Or is P + Or1*(1-P).
Although this works fine, e.g.
?- p_or([0.5,0.3,0.7,0.1],P).
P = 0.9055
hardcore Prolog programmers can't help noticing that the definition isn't tail-recursive. This would really only be a problem when you are processing very long lists, but since the order of list elements doesn't matter, it is easy to turn things around. This is a standard technique, using an auxiliary predicate and an "accumulator pair" of arguments:
p_or(Ps, Or) :-
p_or(Ps, 0, Or).
p_or([], Or, Or).
p_or([P|Ps], Or0, Or) :-
Or1 is P + Or0*(1-P),
p_or(Ps, Or1, Or). % tail-recursive call
I don't know anything about Prolog, but anyway it's convenient to write the probability of a disjunction of a number of independent items p_m = Pr(S_1 or S_2 or S_3 or ... or S_m) recursively as
p_m = Pr(S_m) + p_{m - 1} (1 - P(S_m))
You can prove this by just peeling off the last item -- look at Pr((S_1 or ... or S_{m - 1}) or S_m) and just write that in terms of the usual formula, writing Pr(A or B) = Pr(A) + Pr(B) - Pr(A) Pr(B) = Pr(B) + Pr(A) (1 - Pr(B)), for A and B independent.
The formula above is item C.3.10 in my dissertation: http://riso.sourceforge.net/docs/dodier-dissertation.pdf It is a simple result, and I suppose it must be an exercise in some textbooks, although I don't remember seeing it.
For any event E I'll write E' for the complementary event (ie E' occurs iff E doesn't).
Then we have:
P(E') = 1 - P(E)
(A union B)' = A' inter B'
A and B are independent iff A' and B' are independent
so for independent E1..En
P( E1 union .. union En ) = 1 - P( E1' inter .. inter En')
= 1 - product{ i<=i<=n | 1 - P(E[i])}

How can I ask Wolfram Alpha to rearrange an equation?

I have an equation (parentheses are used because of VBA code)
Y=(P/(12E((bt^3)/12))*A
and i know every variables but not "b". Is there any way how to ask Wolfram Alpha to "redefine" (not solve) equation so I can see something like following: I tried to do it manually (but result is not OK)
b=((P/EY)*12A))/t^3
I wish to see how right equation will look.
Original equation is on picture below
where
equation in [,] I simplified by A
I'm not sure if there's a way to tell Wolfram|Alpha to rearrange for a particular variable; in general it will usually try to rearrange for x or y.
If I substitute b for x in your equation and use the following query:
solve Y - (P/(12E((xt^3)/12))*A) = 0
then Wolfram Alpha returns the result you're looking for: x (b) expressed in terms of the other variables. Specifically:
x = A P / (E t^3 Y) for tY != 0 and AP != 0
I know that your question was about Wolfram Alpha, that you do not want to "solve", but here is one way you could do it in Mathematica using your real question. I renamed I into J because I is a reserved symbol in Mathematica for the imaginary unit.
J = b t^3/12;
expr = (P / (12 E J) ) (4 L1^3 + 3 R ( 2 Pi L1^2 + Pi R^2 + 8 L1 R ) + 12 L2 (L1 + R)^2)
Solve[ Y == expr , b]
Result
{{b -> (P (4 L1^3 + 12 L1^2 L2 + 24 L1 L2 R + 6 L1^2 \[Pi] R + 24 L1 R^2 + 12 L2 R^2 + 3 \[Pi] R^3))/(E t^3 Y)}}

Maxima: how to reform a equation in a defined format

In Maxima, I want to change the following equation:
ax+b-c-d=0
into the following format
(ax+b)/(c+d)=1
Note:
something like ax+b-c-d+1=1 is not what I want.
Basically I want to have positive elements in one side and negative elements in another side, then divide the positive elements by the negative elements.
Here is a quick attempt. It handles some equations of the form you described, but it's probably easy to find some which it can't handle. Maybe it works well enough, or at least provides some inspiration.
ptermp (e) := symbolp(e) or (numberp(e) and e > 0)
or ((op(e) = "+" or op(e) = "*") and every (ptermp, args(e)));
matchdeclare (pterm, ptermp);
matchdeclare (otherterm, all);
defrule (r1, pterm + otherterm = 0, ratsimp (pterm/(-otherterm)) = 1);
NOTE: the catch-all otherterm must be precede pterm alphabetically! This is a useful, but obscure, consequence of the simplification of "+" expressions and the pattern-matching process ... sorry for the obscurity.
Examples:
apply1 (a*x - b - c + d = 0, r1);
a x + d
------- = 1
c + b
apply1 (a*x - (b + g) - 2*c + d*e*f = 0, r1);
a x + d e f
----------- = 1
g + 2 c + b

how to calculate a quadratic equation that best fits a set of given data

I have a vector X of 20 real numbers and a vector Y of 20 real numbers.
I want to model them as
y = ax^2+bx + c
How to find the value of 'a' , 'b' and 'c'
and best fit quadratic equation.
Given Values
X = (x1,x2,...,x20)
Y = (y1,y2,...,y20)
i need a formula or procedure to find following values
a = ???
b = ???
c = ???
Thanks in advance.
Everything #Bartoss said is right, +1. I figured I just add a practical implementation here, without QR decomposition. You want to evaluate the values of a,b,c such that the distance between measured and fitted data is minimal. You can pick as measure
sum(ax^2+bx + c -y)^2)
where the sum is over the elements of vectors x,y.
Then, a minimum implies that the derivative of the quantity with respect to each of a,b,c is zero:
d (sum(ax^2+bx + c -y)^2) /da =0
d (sum(ax^2+bx + c -y)^2) /db =0
d (sum(ax^2+bx + c -y)^2) /dc =0
these equations are
2(sum(ax^2+bx + c -y)*x^2)=0
2(sum(ax^2+bx + c -y)*x) =0
2(sum(ax^2+bx + c -y)) =0
Dividing by 2, the above can be rewritten as
a*sum(x^4) +b*sum(x^3) + c*sum(x^2) =sum(y*x^2)
a*sum(x^3) +b*sum(x^2) + c*sum(x) =sum(y*x)
a*sum(x^2) +b*sum(x) + c*N =sum(y)
where N=20 in your case. A simple code in python showing how to do so follows.
from numpy import random, array
from scipy.linalg import solve
import matplotlib.pylab as plt
a, b, c = 6., 3., 4.
N = 20
x = random.rand((N))
y = a * x ** 2 + b * x + c
y += random.rand((20)) #add a bit of noise to make things more realistic
x4 = (x ** 4).sum()
x3 = (x ** 3).sum()
x2 = (x ** 2).sum()
M = array([[x4, x3, x2], [x3, x2, x.sum()], [x2, x.sum(), N]])
K = array([(y * x ** 2).sum(), (y * x).sum(), y.sum()])
A, B, C = solve(M, K)
print 'exact values ', a, b, c
print 'calculated values', A, B, C
fig, ax = plt.subplots()
ax.plot(x, y, 'b.', label='data')
ax.plot(x, A * x ** 2 + B * x + C, 'r.', label='estimate')
ax.legend()
plt.show()
A much faster way to implement solution is to use a nonlinear least squares algorithm. This will be faster to write, but not faster to run. Using the one provided by scipy,
from scipy.optimize import leastsq
def f(arg):
a,b,c=arg
return a*x**2+b*x+c-y
(A,B,C),_=leastsq(f,[1,1,1])#you must provide a first guess to start with in this case.
That is a linear least squares problem. I think the easiest method which gives accurate results is QR decomposition using Householder reflections. It is not something to be explained in a stackoverflow answer, but I hope you will find all that is needed with this links.
If you never heard about these before and don't know how it connects with you problem:
A = [[x1^2, x1, 1]; [x2^2, x2, 1]; ...]
Y = [y1; y2; ...]
Now you want to find v = [a; b; c] such that A*v is as close as possible to Y, which is exactly what least squares problem is all about.

Generalizing Fibonacci sequence with SICStus Prolog

I'm trying to find a solution for a query on a generalized Fibonacci sequence (GFS). The query is: are there any GFS that have 885 as their 12th number? The initial 2 numbers may be restricted between 1 and 10.
I already found the solution to find the Nth number in a sequence that starts at (1, 1) in which I explicitly define the initial numbers. Here is what I have for this:
fib(1, 1).
fib(2, 1).
fib(N, X) :-
N #> 1,
Nmin1 #= N - 1,
Nmin2 #= N - 2,
fib(Nmin1, Xmin1),
fib(Nmin2, Xmin2),
X #= Xmin1 + Xmin2.
For the query mentioned I thought the following would do the trick, in which I reuse the fib method without defining the initial numbers explicitly since this now needs to be done dynamically:
fib(N, X) :-
N #> 1,
Nmin1 #= N - 1,
Nmin2 #= N - 2,
fib(Nmin1, Xmin1),
fib(Nmin2, Xmin2),
X #= Xmin1 + Xmin2.
fib2 :-
X1 in 1..10,
X2 in 1..10,
fib(1, X1),
fib(2, X2),
fib(12, 885).
... but this does not seem to work.
Is it not possible this way to define the initial numbers, or am I doing something terribly wrong? I'm not asking for the solution, but any advice that could help me solve this would be greatly appreciated.
Under SWI-Prolog:
:- use_module(library(clpfd)).
fib(A,B,N,X):-
N #> 0,
N0 #= N-1,
C #= A+B,
fib(B,C,N0,X).
fib(A,B,0,A).
task(A,B):-
A in 1..10,
B in 1..10,
fib(A,B,11,885).
Define a predicate gfs(X0, X1, N, F) where X0 and X1 are the values for the base cases 0 and 1.
I'd say you're doing something terribly wrong...
When you call fib(1, X1), the variable X1 is the number that the function fib will return, in this case, it will be 1, because of the base case fib(1, 1)..
Without the base cases, fib/2 has no solution; no matter how you call it in fib2.
Note: if you use recursion, you need at least one base case.
Consider fib(N,F1,F2) so you'll be able to replace fib(Nmin1, Xmin1) and fib(Nmin2, Xmin2) with simple fib(Nmin2, Xmin2, Xmin1).
Maybe not a solution in the strict sense but I will share it never the less. Probably the only gain is to show, that this does neither need a computer nor a calculator to be solved. If you know the trick it can be done on a bearmat.
If F_n ist the n-th Term of the ordinary Fibo-sequence, starting with F_1=F_2=1, then the n-th Term of the generalized sequence will be G_n = F_{n-2}*a+F_{n-1}*b.
Define F_{-1}=1, F_0 = 0
(Indeed, by induction
G_1 = F_{-1}*a+F_0*b = 1*a+0*b=a
G_2 = F_0 * a + F_1 * b = 0*a + 1*b = b
G_{n+1} = F_{n-1}a + F_nb = (F_{n-3} + F_{n-2} )a + (F_{n-2} + F_{n-1})*b = G_n + G_{n-1}
)
Thus G_12 = F_10 * a + F_11 * b = 55a + 89b.
Now you can either search for solutions to the equation 55a + 89b = 885 with your computer
OR
do the math:
Residues mod 11 (explanation):
55a + 89b = 0 + 88b + b = b; 885 = 880 + 5 = 80*11 + 5 = 5
So b = 5 mod 11, but since 1 <= b <= 10, b really is 5. 89 * 5 = 445 and 885-445 = 440. Now, divide by 55 and get a=8.

Resources