Problem with simple recursion task in Prolog - recursion

I'm currently solving some problems in prolog and I can't seem to get it work with one question regarding recursion, I have been presented with this table: Gryffindor Table.
Given that information, I made my own KB with this content:
/*
This order represents how they are sit from left to right
parvati_patil is left to lavender_brown,
lavender_brown is left to neville_longbottom
and so on, until we reach parvati again at the end.
*/
seatedTogether(parvati_patil, lavender_brown).
seatedTogether(lavender_brown, neville_longbottom).
seatedTogether(neville_longbottom, alicia_spinnet).
seatedTogether(alicia_spinnet, fred_weasley).
seatedTogether(fred_weasley, george_weasley).
seatedTogether(george_weasley, lee_jordan).
seatedTogether(lee_jordan, dennis_creevey).
seatedTogether(dennis_creevey, dean_thomas).
seatedTogether(dean_thomas, ginny_weasley).
seatedTogether(ginny_weasley, angelina_johnson).
seatedTogether(angelina_johnson, seamus_finnigan).
seatedTogether(seamus_finnigan, colin_creevey).
seatedTogether(colin_creevey, harry_potter).
seatedTogether(harry_potter, hermione_granger).
seatedTogether(hermione_granger, ron_weasley).
seatedTogether(ron_weasley, natalie_mcdonald).
seatedTogether(natalie_mcdonald, katie_bell).
seatedTogether(katie_bell, parvati_patil).
% X is left to Y if they are seatedTogether(X,Y)
isAtLeft(X,Y):-seatedTogether(X,Y).
% X is right to Y if they are seatedTogether(Y,X)
isAtRight(X,Y):-seatedTogether(Y,X).
/*
This rule just tells us who X is two places away from Y,
X is two places away from Y if
X is seatedTogether(X,Z)
and that Z is seatedTogether(Z,Y).
*/
twoPlacesAway(X,Y):-seatedTogether(X, Z), seatedTogether(Z,Y).
/*
This rule just tells us whos sitting # the table
by just unifying X with the values of seatedTogether(X,Y)
without regarding Y.
*/
atTable(X):-seatedTogether(X,_).
/*
Between two:
Its supposed to tell us whos Z is between X and Y
The perfect case (for me) would be that X and Y are sitting
together, so they have no one in the middle.
The other way around would be that
X is not equal to Y
X1 is sitting left to X,
and then we call it again with
X1, Y and Z1 as args,
after each call, we equal
Z to X1 value.
*/
betweenTwo(X,Y,Z):-isAtLeft(X,Y),isAtRight(Y,X).
betweenTwo(X,Y,Z):-
X \= Y,
isAtLeft(X, X1),
betweenTwo(X1, Y, Z1),
Z = X1.
The problem comes with the last rule definition, if I call it like this:
betweenTwo(ron_weasley, alicia_spinnet, Z).
The value of Z should be:
natalie_mcdonald,
katie_bell,
parvati_patil,
lavender_brown,
neville_longbottom.
But Z only unifies with the value of
natalie_mcdonald.
I believe I'm super close to it, but I'm really lost on what's going wrong with that rule. I defined it so X step by step equals the value of Y, but with the value before Y it should fall in the perfect case and stop moving, and unify the rest of elements before it. Any ideas?

First: your base case (what you call "perfect case") says "if X is at left of Y, and Y is at right of X, then every Z is between them", instead of "no one is between them" (the conditions are redundant as well). The base case should say when the predicate holds (that is, when some Z is between X and Y), not when it doesn't. See also this answer: https://stackoverflow.com/a/3001941/9204
Second: in the non-base case, you have
isAtLeft(X, X1),
betweenTwo(X1, Y, Z1),
Z = X1.
When Prolog searches for X1 in isAtLeft(ron_weasley, X1), the only answer is natalie_mcdonald, and later Z = X1 forces Z to be natalie_mcdonald too.
So this part of your code is equivalent to
isAtLeft(X, Z),
betweenTwo(Z, Y, Z1).
or in words "Z is between X and Y if: X is not equal to Y, X is directly to the left of Z, and some Z1 is between Z and Y", which doesn't make sense.
You should note the warning about singleton variable Z1, too.

Related

3D Ploting in Scilab: Weird plot behaviour

I want to plot a function in scilab in order to find the maximum over a range of numbers:
function y=pr(a,b)
m=1/(1/270000+1/a);
n=1/(1/150000+1/a);
y=5*(b/(n+b)-b/(m+b))
endfunction
x=linspace(10,80000,50)
y=linspace(10,200000,50)
z=feval(x,y,pr)
surf(x,y,z);
disp( max(z))
For these values this is the plot:
It's obvious that increasing the X axis will not increase the maximum but Y axis will.
However from my tests it seems the two axis are mixed up. Increasing the X axis will actually double the max Z value.
For example, this is what happens when I increase the Y axis by a factor of ten (which intuitively should increase the function value):
It seems to increase the other axis (in the sense that z vector is calculated for y,x pair of numbers instead of x,y)!
What am I doing wrong here?
With Scilab's surf you have to use transposed z if comming from feval. It is easy so realize if you use a different number of points in X and Y directions, as surf will complain about the size of the third argument. So in your case, use:
surf(x,y,z')
For more information see the help page of surf.
Stephane's answer is correct, but I thought I'd try to explain better why / what is happening.
From the help surf page (emphasis mine):
X,Y:
two vectors of real numbers, of lengths nx and ny ; or two real matrices of sizes ny x nx: They define the data grid (horizontal coordinates of the grid nodes). All grid cells are quadrangular but not necessarily rectangular. By default, X = 1:size(Z,2) and Y = 1:size(Z,1) are used.
Z:
a real matrix explicitly defining the heights of nodes, of sizes ny x nx.
In other words, think of surf as surf( Col, Row, Z )
From the help feval page (changed notation for convenience):
z=feval(u,v,f):
returns the matrix z such as z(i,j)=f(u(i),v(j))
In other words, in your z output, the i become rows (and therefore u should represent your rows), and j becomes your columns (and therefore v should represent your columns).
Therefore, you can see that you've called feval with the x, y arguments the other way round. In a sense, you should have designed pr so that it should have expected to be called as pr(y,x) instead, so that when passed to feval as feval(y,x,pr), you would end up with an output whose rows increase with y, and columns increase with x.
Then you could have called surf(x, y, z) normally, knowing that x corresponds to columns, and y corresponds to rows.
However, if you don't want to change your whole function just for this, which presumably you don't want to, then you simply have to transpose z in the call to surf, to ensure that you match x to the columns or z' (i.e, the rows of z), and y to the rows of z' (i.e. the columns of z).
Having said all that, it would probably be much better to make your function vectorized, and just use the surf(x, y, pr) syntax directly.

Prolog recursively multiply

I'm trying to multiply two numbers in Prolog recursively i.e. 3*4 = 3+3+3+3 = 12.
My code is :
mult(0,Y,Y).
mult(X,Y,Z) :-
NewX is X-1,
Z is Y + mult(NewX,Y,Z).
but I keep either in an infinite loop or being told mult is not a function.
What you here constructed is a predicate. A predicate is not the same as a function in computer science, you can not write A is B + some_pred(C), or at least not as far as I know in ISO Prolog, and definitely not without adding some extra logic.
In order to pass values, one uses variables. We can thus call the mult/3 predicate recursively, and use a variable that will be unified with the result. We can then perform arithmetic with it, like:
mult(0, _, 0).
mult(X, Y, Z) :-
X1 is X - 1,
mult(X1, Y, Z1),
Z is Y + Z1.
Note that you can not reassign a (different) value to a variable. So if, like you did in the question, use Z twice, then given Y is not 0, this will fail.
The above is however still not sufficient, since it will produce a result, but then get stuck in an infinite loop since if it calls (eventually) mult(0, 4, Z) (4 is here just a value), there are two ways to resolve this: with the base case, and with the recursive case.
We thus need a "guard" for the second case, like:
mult(0, _, 0).
mult(X, Y, Z) :-
X > 0,
X1 is X - 1,
mult(X1, Y, Z1),
Z is Y + Z1.
We then obtain for example:
?- mult(14, 25, Z).
Z = 350 ;
false.
One can improve the speed of this mult/3 predicate by implementing a version with an accumulator. I leave this as an exercise.

How to derive a pseudo random number, given a parent/seed number - which fits all criteria the parent number has

I need some help with maths. I am generating a derived seed value from a parent seed value.
I need to derive a number y given a number x which follows the following rules.
x = math.random(1000, 9999)
for a given x, y is constant. ie. y = f(x)
y doesnt necessarily follows x. ie y doesnt needs to grow when x grows and y doesnt needs to reduce when x reduces.
eg. if x = 1234 and in the next iteration x = 3456 then y also doesnt needs to grow. in fact y would better be a pseudo random number.
y also is in the range (1000, 9999)
Early on i went for the following function:
y = tonumber(string.reverse(x))
ie. if x = 1234 then y = 4321
However there is a direct correlation between the two numbers and my terrain is looking way too symmetric as a result.
You could pass the generated value of x back into the math.randomseed function. The RNG will always generate the same value of y for same value of x passed to seed.
So, something like:
math.randomseed(os.time())
local r = math.random
local x = r(1000, 9999)
math.randomseed(x)
local y = r(1000, 9999)
to test whether it works, as an example, you could use 5668 as seed (or x), and for y you'll always get back 3612. You can even test it on https://lua.org/demo.html

Efficient way to store 3D normal vector using two floats

I need to store 3D normal vectors, that is vectors (x, y, z) such that x^2 + y^2 + z^2 = 1. But due to space constraints I can only use 2 floats to store it.
So by storing only x and y, the third component can be computed as sqrt(1 - x^2 - y^2), i.e. one square root, two products and two subtractions.
What would be the most efficient way to store the vectors, so that reading them is as fast as possible, and if possible without bias towards one spatial direction?
Edit
Now using the values (a, b) with a = x - y and b = x + y.
You could satisfy your space constraint by storing the vectors via spherical coordinates. As is well known, each point on the unit sphere, i.e., each unit vector, has at least one pair of spherical coordinates characterizing it.
Or if you want something convoluted: The complex square function maps the unit disk to a double cover of it. So you could use the left half-disk for the upper half-sphere and the right half-disk for the lower half-sphere.
SphereFromDisk(a,b)
a2=a*a; b2=b*b; r2=a2+b2; // assert r2 <= 1
x = a2 - b2;
y = 2*a*b
z = sqrt(1-r2*r2)
if(a<0 or (a=0 and b<0) z=-z
return (x,y,z)

Add random spread to directional vector

Let's say I have a unit vector a = Vector(0,1,0) and I want to add a random spread of something between x = Vector(-0.2,0,-0.2) and y = Vector(0.2,0,0.2), how would I go about doing that?
If I were to simply generate a random vector between x and y, I'd get a value somewhere in the bounds of a square:
What I'd like instead is a value within the circle made up by x and y:
This seems like a simple problem but I can't figure out the solution right now. Any help would be appreciated.
(I didn't ask this on mathoverflow since this isn't really a 'research level mathematics question')
If I read your question correctly, you want a vector in a random direction that's within a particular length (the radius of your circle).
The formula for a circle is: x2 + y2 = r2
So, if you have a maximum radius, r, that constrains the vector length, perhaps proceed something like this:
Choose a random value for x, that lies between -r and +r
Calculate a limit for randomising y, based on your chosen x, so ylim = sqrt(r2 - x2)
Finally, choose a random value of y between -ylim and +ylim
That way, you get a random direction in x and a random direction in y, but the vector length will remain within 0 to r and so will be constrained within a circle of that radius.
In your example, it seems that r should be sqrt(0.22) which is approximately 0.28284.
UPDATE
As 3D vector has length (or magnitude) sqrt(x2+y2+z2) you could extend the technique to 3D although I would probably favour a different approach (which would also work for 2D).
Choose a random direction by choosing any x, y and z
Calculate the magnitude m = sqrt(x2+y2+z2)
Normalise the direction vector (by dividing each element by its magnitude), so x = x/m, y = y/m, z=z/m
Now choose a random length, L between 0 and r
Scale the direction vector by the random length. So x = x * L, y = y * L, z = z * L

Resources