I'm using Prolog to solve simple geometrical equations.
For example, I can define all points p3 on a line passing trough two points p1 and p2 as:
line((X1, Y1, Z1), (X2, Y2, Z2), T, (X3, Y3, Z3)) :-
{(X2 - X1) * T = X3},
{(Y2 - Y1) * T = Y3},
{(Z2 - Z1) * T = Z3}.
And then a predicate like line((0, 0, 0), (1, 1, 1), _, (2, 2, 2)) is true.
But what I'd really want is to write down something like this:
line(P1, P2, T, P3) :- {(P2 - P1) * T = P3}.
Where P1, P2, and P3 are real vectors.
What's the best way of arriving at something similar? The best I found so far is to rewrite my own add, subtract and multiply predicates, but that's not as conveniant.
Here is a solution where you still have to write a bit of code for each operator you want to handle, but which still provides nice syntax at the point of use.
Let's start with a notion of evaluating an arithmetic expression on vectors to a vector. This essentially applies arithmetic operations component-wise. (But you could add a dot product or whatever you like.)
:- use_module(library(clpr)).
vectorexpr_value((X,Y,Z), (X,Y,Z)).
vectorexpr_value(V * T, (X,Y,Z)) :-
vectorexpr_value(V, (XV,YV,ZV)),
{ X = XV * T },
{ Y = YV * T },
{ Z = ZV * T }.
vectorexpr_value(L + R, (X,Y,Z)) :-
vectorexpr_value(L, (XL,YL,ZL)),
vectorexpr_value(R, (XR,YR,ZR)),
{ X = XL + XR },
{ Y = YL + YR },
{ Z = ZL + ZR }.
vectorexpr_value(L - R, (X,Y,Z)) :-
vectorexpr_value(L, (XL,YL,ZL)),
vectorexpr_value(R, (XR,YR,ZR)),
{ X = XL - XR },
{ Y = YL - YR },
{ Z = ZL - ZR }.
So for example:
?- vectorexpr_value(A + B, Result).
A = (_1784, _1790, _1792),
B = (_1808, _1814, _1816),
Result = (_1832, _1838, _1840),
{_1808=_1832-_1784},
{_1814=_1838-_1790},
{_1816=_1840-_1792} .
Given this, we can now define "equality" of vector expressions by "evaluating" both of them and asserting pointwise equality on the results. To make this look nice, we can define an operator for it:
:- op(700, xfx, ===).
This defines === as an infix operator with the same priority as the other equality operators =, =:=, etc. Prolog doesn't allow you to overload operators, so we made up a new one. You can think of the three = signs in the operator as expressing equality in three dimensions.
Here is the corresponding predicate definition:
ExprL === ExprR :-
vectorexpr_value(ExprL, (XL,YL,ZL)),
vectorexpr_value(ExprR, (XR,YR,ZR)),
{ XL = XR },
{ YL = YR },
{ ZL = ZR }.
And we can now define line/4 almost as you wanted:
line(P1, P2, T, P3) :-
(P2 - P1) * T === P3.
Tests:
?- line((0,0,0), (1,1,1), Alpha, (2,2,2)).
Alpha = 2.0 ;
false.
?- line((0,0,0), (1,1,1), Alpha, (2,3,4)).
false.
Related
I have the following code:
f=tan(x)*x**2
q=Wild('q')
s=f.match(tan(q))
s={q_ : x}
How to work with the result of the "wild"? How to not address the array, for example, s[0], s{0}?
Wild can be used when you have an expression which is the result of some complicated calculation, but you know it has to be of the form sin(something) times something else. Then s[q] will be the sympy expression for the "something". And s[p] for the "something else". This could be used to investigate both p and q. Or to further work with a simplified version of f, substituting p and q with new variables, especially if p and q would be complex expressions involving multiple variables.
Many more use cases are possible.
Here is an example:
from sympy import *
from sympy.abc import x, y, z
p = Wild('p')
q = Wild('q')
f = tan(x) * x**2
s = f.match(p*tan(q))
print(f'f is the tangent of "{s[q]}" multiplied by "{s[p]}"')
g = f.xreplace({s[q]: y, s[p]:z})
print(f'f rewritten in simplified form as a function of y and z: "{g}"')
h = s[p] * s[q]
print(f'a new function h, combining parts of f: "{h}"')
Output:
f is the tangent of "x" multiplied by "x**2"
f rewritten in simplified form as a function of y and z: "z*tan(y)"
a new function h, combining parts of f: "x**3"
If you're interested in all arguments from tan that appear in f written as a product, you might try:
from sympy import *
from sympy.abc import x
f = tan(x+2)*tan(x*x+1)*7*(x+1)*tan(1/x)
if f.func == Mul:
all_tan_args = [a.args[0] for a in f.args if a.func == tan]
# note: the [0] is needed because args give a tupple of arguments and
# in the case of tan you'ld want the first (there is only one)
elif f.func == tan:
all_tan_args = [f.args[0]]
else:
all_tan_args = []
prod = 1
for a in all_tan_args:
prod *= a
print(f'All the tangent arguments are: {all_tan_args}')
print(f'Their product is: {prod}')
Output:
All the tangent arguments are: [1/x, x**2 + 1, x + 2]
Their product is: (x + 2)*(x**2 + 1)/x
Note that neither method would work for f = tan(x)**2. For that, you'ld need to write another match and decide whether you'ld want to take the same power of the arguments.
I want to verify a formula of the form:
Exists p . ForAll x != 0 . f(x, p) > 0 and g(x, p) < 0
All variables are reals.
As suggested here, I add this list to the solver:
[ForAll([x0, x1],
Implies(Or(x0 != 0, x1 != 0),
And(P0*x0*x0 + P1*x0*x1 + P2*x0*x1 + P3*x1*x1 > 0,
-2*P0*x0*x1 + P1*x0*x0 - P1*x0*x1 - P1*x1*x1 + P2*x0*x0 - P2*x0*x1 - P2*x1*x1 + 2*P3*x0*x1 - 2*P3*x1*x1 < 0
)
)
)
]
The solver with the above formula returns unsat. A possible solution is for P to be [[1.5, -0.5], [-0.5, 1]] and in fact, by substituting those values, the formula is satisfied:
And(3/2*x0*x0 - 1*x0*x1 + x1*x1 > 0,
-1*x0*x0 - 1*x1*x1 < 0)
Is there a way to actually compute such a p? If it's hard for z3, is there any alternative for this problem?
When you say 'Exists' followed by 'Forall', then you are saying that the formula should be true for every such x0, x1. And Z3 is telling you that is simply not the case.
If you are interested in finding one such P, and corresponding x values, simply drop the quantification and make everything a top-level variable:
from z3 import *
def f(x0, x1, P0, P1, P2, P3):
return P0*x0*x0 + P1*x0*x1 + P2*x0*x1 + P3*x1*x1
def g(x0, x1, P0, P1, P2, P3):
return -2*P0*x0*x1 + P1*x0*x0 - P1*x0*x1 - P1*x1*x1 + P2*x0*x0 - P2*x0*x1 - P2*x1*x1 + 2*P3*x0*x1 - 2*P3*x1*x1
p0, p1, p2, p3 = Reals('p0 p1 p2 p3')
x0, x1 = Reals('x0 x1')
fmls = [Implies(Or(x0 != 0, x1 != 0), And(f(x0, x1, p0, p1, p2, p3) > 0, g(x0, x1, p0, p1, p2, p3) < 0))]
while True:
s = Solver()
s.add(fmls)
res = s.check()
print res
if res == sat:
m = s.model()
print m
fmls += [Or(p0 != m[p0], p1 != m[p1])]
else:
print "giving up"
break
When I run this, I get:
sat
[x0 = 1/8, p0 = -1/2, p1 = -1/2, x1 = 1/2, p2 = 1, p3 = 1]
and many others; which is I believe what you're after.
Note that you can also do some programming to get rid of the existential quantification depending on where you are; i.e., start with the quantified version, if you get an unsat, then switch to a new solver and use the unquantified version to automate this process. Of course, this is just programming and doesn't really have anything to do with z3 at this point.
I'm a beginner to Prolog and have two requirements:
f(1) = 1
f(x) = 5x + x^2 + f(x - 1)
rules:
f(1,1).
f(X,Y) :-
Y is 5 * X + X * X + f(X-1,Y).
query:
f(4,X).
Output:
ERROR: is/2: Arguments are not sufficiently instantiated
How can I add value of f(X-1)?
This can be easily solved by using auxiliary variables.
For example, consider:
f(1, 1).
f(X, Y) :-
Y #= 5*X + X^2 + T1,
T2 #= X - 1,
f(T2, T1).
This is a straight-forward translation of the rules you give, using auxiliary variables T1 and T2 which stand for the partial expressions f(X-1) and X-1, respectively. As #BallpointBen correctly notes, it is not sufficient to use the terms themselves, because these terms are different from their arithmetic evaluation. In particular, -(2,1) is not the integer 1, but 2 - 1 #= 1 does hold!
Depending on your Prolog system, you may ned to currently still import a library to use the predicate (#=)/2, which expresses equality of integer expressesions.
Your example query now already yields a solution:
?- f(4, X).
X = 75 .
Note that the predicate does not terminate universally in this case:
?- f(4, X), false.
nontermination
We can easily make it so with an additional constraint:
f(1, 1).
f(X, Y) :-
X #> 1,
Y #= 5*X + X^2 + T1,
T2 #= X - 1,
f(T2, T1).
Now we have:
?- f(4, X).
X = 75 ;
false.
Note that we can use this as a true relation, also in the most general case:
?- f(X, Y).
X = Y, Y = 1 ;
X = 2,
Y = 15 ;
X = 3,
Y = 39 ;
X = 4,
Y = 75 ;
etc.
Versions based on lower-level arithmetic typically only cover a very limited subset of instances of such queries. I therefore recommend that you use (#=)/2 instead of (is)/2. Especially for beginners, using (is)/2 is too hard to understand. Take the many related questions filed under instantiation-error as evidence, and see clpfd for declarative solutions.
The issue is that you are trying to evaluate f(X-1,Y) as if it were a number, but of course it is a predicate that may be true or false. After some tinkering, I found this solution:
f(1,1).
f(X,Y) :- X > 0, Z is X-1, f(Z,N), Y is 5*X + X*X + N.
The trick is to let it find its way down to f(1,N) first, without evaluating anything; then let the results bubble back up by satisfying Y is 5*X + X*X + N. In Prolog, order matters for its search. It needs to satisfy f(Z,N) in order to have a value of N for the statement Y is 5*X + X*X + N.
Also, note the condition X > 0 to avoid infinite recursion.
I have this jsbin that shows my working.
In the jsbin, I am trying to draw a line through the altitude through point A (1, 1) that is perpendicular to Line BC which has points B (6, 18) and C (14, 6).
The way I have worked this out is to try and get 2 equations into the form y = mx + c and then rearrange them to y -mx = c and then solve them through simultaneous equations using matrices.
I have this altitude function that does the work:
function altitude(vertex, a, b) {
var slope = gradient(a, b),
x1 = - slope,
y1 = 1,
c1 = getYIntercept(a, slope),
perpendicularSlope = perpendicularGradient(a, b),
x2 = - perpendicularSlope,
y2 = 1,
c2 = getYIntercept(vertex, perpendicularSlope);
var matrix = [
[x1, y1],
[x2, y2]
];
var result = solve(matrix, [c1, c2]);
var g = svg.append('g');
g.append('line')
.style('stroke', 'red')
.attr('class', 'line')
.attr('x1', xScale(vertex.x))
.attr('y1', yScale(vertex.y))
.attr('x2', xScale(result.x))
.attr('y2', yScale(result.y));
}
I first of all get the gradient of BC using this function
var gradient = function(a, b) {
return (b.y - a.y) / (b.x - a.x);
};
Which is -1.5 and from that I can get the perpendicular gradient using this function:
var perpendicularGradient = function (a, b) {
return -1 / gradient(a, b);
};
I make that to be 0.66666 or (2/3).
I get the 2 equations to look like this:
y + 1.5 = 27
y -0.6666666666666666 = 0.33333333333333337
I have some functions in the jsbin that will solve these simultaneously using matrices and cramer's rule, the main one being solve:
function solve(matrix, r) {
var determinant = det(matrix);
var x = det([
[r[0], matrix[0][1]],
[r[1], matrix[1][1]]
]) / determinant;
var y = det([
[matrix[0][0], r[0]],
[matrix[1][0], r[1]]
]) / determinant;
return {x: Math.approx(x), y: Math.approx(y)};
}
function det(matrix) {
return (matrix[0][0]*matrix[1][1])-(matrix[0][1]*matrix[1][0]);
}
I get the coordinates of the intercept to be roughly (12.31, 8.54).
The problem is, it does not look right on the diagram.
Have I taken a wrong step somewhere? I think my calculations are right but I would not rule out them being wrong. It might be down to scale perhaps.
You want to find projection of point A onto line BC.
Let's make vectors
Q = C - B
P = A - B
normalized (unit length):
uQ = Q/ |Q|
Needed projection point D is
D = B + uQ * DotProduct(P, uQ)
For your example A(1,1), B(6,18), C(14,6)
Q = (8, -12)
|Q| = Sqrt(8*8+12*12)~14.4
uQ= (0.55, -0.83)
P=(-5,-17)
DotProduct(P, uQ)=0.55*(-5) -(0.83*-17)=11.39
D = (6+0.55*11.39, 18-0.83*11.39) = (12.26, 8,54)
So your calculation gives right result (though approach is not very efficient), but picture is not exact - different scales of X and Y axes deform angles.
P.S: Second line width = 660 - margin.left - margin.right, makes the picture more reliable
My first Fortran lesson is to plot the probability density function of the radial Sturmian functions. In case you are interested, the radial Sturmian functions are used to graph the momentum space eigenfunctions for the hydrogen atom.
In order to produce these radial functions, one needs to first produce some polynomials called the Gegenbauer polynomials, denoted
Cba(x),
where a and b should be stacked atop each other. One needs these polynomials because the Sturmians (let's call them R_n,l) are defined like so,
R_n,l(p) = N pl⁄(p2 + k2)l+2 Cn - l - 1l + 1(p2 - k2⁄p2 + k2),
where N is a normalisation constant, p is the momentum, n is the principle quantum number, l is the angular momentum and k is a constant. The normalisation constant is there so that when I come to square this function, it will produce a probability distribution for the momentum of the electron in a hydrogen atom.
Gegenbauer polynomials are generated using the following recurrence relation:
Cnl(x) = 1⁄n[2(l + n - 1) x Cn - 1l(x) - (2l + n - 2)Cn - 2l(x)],
with C0l(x) = 1 and C1l(x) = 2lx, as you may have noticed, l is fixed but n is not. At the start of my program, I will specify both l and n and work out the Gegenbauer polynomial I need for the radial function I wish to plot.
The problems I am having with my code at the moment are all in my subroutine for working out the value of the Gegenbauer polynomial Cn-l-1l+1(p2 - k2⁄p2 + k2) for incremental values of p between 0 and 3. I keep getting the error
Unclassified statement at (1)
but I cannot see what the issue is.
program Radial_Plot
implicit none
real, parameter :: pi = 4*atan(1.0)
integer, parameter :: top = 1000, l = 50, n = 100
real, dimension(1:top) :: x, y
real increment
real :: a=0.0, b = 2.5, k = 0.3
integer :: i
real, dimension(1:top) :: C
increment = (b-a)/(real(top)-1)
x(1) = 0.0
do i = 2, top
x(i) = x(i-1) + increment
end do
Call Gegenbauer(top, n, l, k, C)
y = x*C
! y is the function that I shall be plotting between values a and b.
end program Radial_Plot
Subroutine Gegenbauer(top1, n1, l1, k1, CSub)
! This subroutine is my attempt to calculate the Gegenbauer polynomials evaluated at a certain number of values between c and d.
implicit none
integer :: top1, i, j, n1, l1
real :: k1, increment1, c, d
real, dimension(1:top1) :: x1
real, dimension(1:n1 - l1, 1:top1) :: C1
real, dimension(1:n1 - l1) :: CSub
c = 0.0
d = 3.0
k1 = 0.3
n1 = 50
l1 = 25
top1 = 1000
increment1 = (d - c)/(real(top1) - 1)
x1(1) = 0.0
do i = 2, top1
x1(i) = x1(i-1) + increment1
end do
do j = 1, top1
C1(1,j) = 1
C1(2,j) = 2(l1 + 1)(x1(i)^2 - k1^2)/(x1(i)^2 + k1^2)
! All the errors occurring here are all due to, and I quote, 'Unclassifiable statement at (1)', I can't see what the heck I have done wrong.
do i = 3, n1 - l1
C1(i,j) = 2(((l1 + 1)/n1) + 1)(x1(i)^2 - k1^2)/(x1(i)^2 + k1^2)C1(i,j-1) - ((2(l1+1)/n1) + 1)C1(i,j-2)
end do
CSub(j) = Cn(n1 - l1,j)^2
end do
return
end Subroutine Gegenbauer
As francesalus correctly pointed out, the problem is because you use ^ instead of ** for exponentiation. Additionally, you do not put * between the terms you are multiplying.
C1(1,j) = 1
C1(2,j) = 2*(l1 + 1)*(x1(i)**2 - k1**2)/(x1(i)**2 + k1**2)
do i = 3, n1 - l1
C1(i,j) = 2 * (((l1 + 1)/n1) + 1) * (x1(i)**2 - k1**2) / &
(x1(i)**2 + k1**2)*C1(i,j-1) - ((2(l1+1)/n1) + 1) * &
C1(i,j-2)
end do
CSub(j) = Cn(n1 - l1,j)**2
Since you are beginning I have some advice. Learn to put all subroutines and functions to modules (unless they are internal). There is no reason for the return statement at the and of the subroutine, similarly as a stop statement isn't necessary at the and of the program.