Related
I have a movie database with terms like
movie(blood_simple, 1984).
movie(the_cotton_club, 1984).
movie(american_beauty, 1999).
...
I'd like to write a function which returns true if the two given movies were released in the same year and false if they were not.
I have problem with comparing two values, my function always returns false.
Here is my code:
sameyear(Movie1,Movie2):-
movie(Movie1,Year1),
movie(Movie2,Year2).
% here I tried comparing Year1 with Year2 like: Year1 == Year2, Year1 =:= Year2, nothing worked.
Another code:
sameyear(Movie1,Movie2):-
movie(Movie1,Year1),
movie(Movie2,Year1). % here I expected that it would return true if the movies were released at the
same year, because Year1 has already got a value at *movie(Movie1,Year1)*, but that didn't happen
Can you help me?
You wrote a dot (.) at the end of the movie(Movie2, Year2) clause. THis thus means that you end the predicate. If you then write Year1 == Year2., then this is another rule.
You thus should use a comma, which is semantically close to the logical and:
sameyear(Movie1,Movie2):-
movie(Movie1,Year1),
movie(Movie2,Year2), % ← added a comma
Year1 == Year2.
This then produces:
?- sameyear(M1, M2).
M1 = M2, M2 = blood_simple ;
M1 = blood_simple,
M2 = the_cotton_club ;
M1 = the_cotton_club,
M2 = blood_simple ;
M1 = M2, M2 = the_cotton_club ;
M1 = M2, M2 = american_beauty.
So i have these facts:
border(germany, france).
border(france, spain).
border(spain, portugal).
And a few other borders that can get me from portugal to russia (theres too many facts to post here, but it is in fact possible to go from portugal to russia).
And i made this predicate that tells you the number of countries you crossed when you go from P1 to P2:
crossedCountries(P1,P2,0):- (border(P1,P2);border(P2,P1)).
crossedCountries(P1,P2,Num):-
(border(P1,Z);border(Z,P1)),
(crossedCountries(Z,P2,Num1);crossedCountries(P2,Z,Num1)),!,
Num is Num1 + 1.
All goes well when i have to cross, 3, or 4, or 5 countries, but if it is too far, it just gives me the error
ERROR: Out of local stack
Can someone give me a direction?
This problem is a classic graph traversal problem where you want to know the the different unique paths from one specific node to another (or in this case, just the count of countries in between).
The loop problem occurs because you can end up visiting the same country ("node") more than once when determining a route. So if there's a route from A to B to C to D, you might end up doing A to B to A to B to C to B to C to B to A ... and never get to D.
A solution that doesn't account for this might look like:
border(germany, france).
border(france, spain).
border(spain, portugal).
border(germany, austria).
border(austria, slovakia).
border(slovakia, poland).
border(poland, germany).
bordering(Country1, Country2) :-
border(Country1, Country2).
bordering(Country1, Country2) :-
border(Country2, Country1).
crossedCountries(C1, C2, 0):-
bordering(C1, C2).
crossedCountries(C1, C2, Num):-
bordering(C1, Z),
crossedCountries(Z, C2, Num1),
Num is Num1 + 1.
And you get a result like this:
| ?- crossedCountries(germany, spain, N).
N = 1 ? ;
N = 3 ? ;
N = 5 ? ;
...
This is because valid paths are germany-france-spain, germany-france-germany-france-spain, etc.
The common remedy is to keep track of visited countries ("nodes"). This can be done by adding an argument to track them. Also, to make the results clearer, I've added a Path argument to see the actual solution route through the countries (you can omit this argument if needed):
crossedCountries(P1, P2, [P1|Path], Num) :-
crossedCountries(P1, P2, [P1], Path, Num).
crossedCountries(P1, P2, Visited, [P2], 0) :-
neighbors(P1, P2),
\+ member(P2, Visited).
crossedCountries(P1, P2, Visited, [Z|Path], Num) :-
neighbors(P1, Z),
\+ member(Z, Visited),
crossedCountries(Z, P2, [Z|Visited], Path, Num1),
Num is Num1 + 1.
Now the query results in this:
| ?- crossedCountries(germany, spain, Path, N).
N = 1
Path = [germany,france,spain] ? ;
no
| ?- crossedCountries(germany, poland, Path, N).
N = 0
Path = [germany,poland] ? a
N = 2
Path = [germany,austria,slovakia,poland]
no
| ?-
Etc.
The first what i noticed is the forth line of code fragment#2:
(crossedCountries(Z,P2,Num1);crossedCountries(P2,Z,Num1)),!,
The symmetry is already handled earlier and i see it's just the cause of at least looping, but most likely stack overflow error.
border(germany, france).
border(france, spain).
border(spain, portugal).
crossedCountries(P1,P2,0):-
border(P1,P2);
border(P2,P1).
crossedCountries(P1,P2,Num):-
(
border(P1,Z);
border(Z,P1)
),
crossedCountries(Z,P2,Num1),
Num is Num1 + 1.
I have a function that uses 4 parameters, called tile . It is designed to work the following way :
tile(?E, ?S, ?W, ?N, ?ID)
I would like a getter function that given an ID, it returns the first 4 parameters: E, S, W and N.
I have tried something like:
coordonates(tile(E,S,W,N,L), (E,S,W,N)).
But it does not return the actual values, only true.
If I type tile(E, S, W, N, #1) in the terminal I get the desired result but I do not know what exactly is returned (a list maybe?).
Let's suppose our facts describing tile looks as follows:
tile(p1,p2,p3,p4,id1).
tile(q1,q2,q3,q4,id2).
tile(r1,r2,r3,r4,id3).
In this we have a finite number of facts. That can be checked by the most general query for tile:
?- tile(E,S,W,N,I).
E = p1,
S = p2,
W = p3,
N = p4,
I = id1 ; % <---- user input ; to continue
E = q1,
S = q2,
W = q3,
N = q4,
I = id2 ; % <---- user input ; to continue
E = r1,
S = r2,
W = r3,
N = r4,
I = id3. % <---- toplevel outputs . -- we're done
So in theory, we could define coordonates as follows:
coordonates(id1, t(p1, p2, p3, p4)).
coordonates(id2, t(q1, q2, q3, q4)).
coordonates(id3, t(r1, r2, r3, r4)).
which could be queried for id2 as follows:
?- coordonates(id2,X).
X = t(q1, q2, q3, q4).
I used the functor t to group the solution, to make clear that it is not the predicate tile we defined earlier. There's also a lot of repetition in this definition which is already a hint, that we can do better. What we are looking for is a rule which tells us how, given we have a answer for tile, we can describe coordonates. In logical terms, this is written as an implication of the form: goal1 ∧ ... ∧ goalN → head. which means "Suppose I know that goal1 to goalN is true, then I also know that head is true." In Prolog, this is written backwards:
head :-
goal1,
% ...
goalN.
Let's go back to our task: we know something about a tile and we want to describe how the projection looks like. This means, our code looks as follows:
coordonates( ... ) :-
% ...
tile(E,S,W,N,I).
The body tile(E,S,W,N,I) is the most general form we can write (see our query above) and can be read as "suppose I have any tile at coordinates E S W N with id I". Now we only need to fill in, how coordonates should look like. We know it has two arguments, because it relates the id with the four other elements. Lets give them names, say Id and Coords:
coordonates(Id, Coords) :-
% ...
tile(E,S,W,N,I).
Now we only need to find out how to relate E,S,E,N and I with Id and Coords. One is easy: Id is just I. The other one is also not too hard, we just need to group the coordinates into one term. We can pick an arbitrary one, but already above decided to take t, so we will stick with it:
coordonates(Id, Coords) :-
Id = I,
Coords = t(E,S,W,N),
tile(E,S,W,N,I).
This already works as we expect:
?- coordonates(X,Y).
X = id1,
Y = t(p1, p2, p3, p4) ;
X = id2,
Y = t(q1, q2, q3, q4) ;
X = id3,
Y = t(r1, r2, r3, r4).
Now we can make one observation: if two terms are equal, we can use one instead of the other. So instead of writing Id = I, we can just reuse Id. The same goes for Coords and t(E,S,W,N):
coordonates(I, t(E,S,W,N)) :-
tile(E,S,W,N,I).
It couldn't be much shorter :-)
You have to declare 'E, S, W and N' so that prolog can unify those parameters with the input when you make the query. Something like (In the most basic case):
tile(['cordE1','cordS1','cordW1','cordN1'],1).
tile(['cordE2','cordS2','cordW2','cordN2'],2).
tile(['cordE3','cordS3','cordW3','cordN3'],3).
Query:
?- tile(C,2).
C = [cordE2, cordS2, cordW2, cordN2].
?- tile(C,1).
C = [cordE1, cordS1, cordW1, cordN1].
?- tile(C,3).
C = [cordE3, cordS3, cordW3, cordN3].
This question already has answers here:
Why is division in Ruby returning an integer instead of decimal value?
(7 answers)
Closed 6 years ago.
I've been trying to code a Point of Intersection calculator for myself. For some reason my calculator has either been coded completely wrong or the intended order of operations are not working. Allow me to elaborate.
def point_of_intersection (m1, b1, m2, b2)
if m1 == m2 || m1 - m2 == 0
puts "No Solution"
elsif m1 == m2 || b1 == b2
puts "Infinite Solutions"
end
x = -1 * (b1 - b2) / (m1 - m2)
y = (m1 * x) + b1
puts "The Point Of Intersection is: (#{x}, #{y})"
end
As you can see, the method point_of_intersection takes four parameters:
The slope of the first linear equation (m1) and its y-intercept (b1)
and the slope of the second linear equation (m2) and its y-intercept (b2)
This calculator has worked correctly for me for some cases but for some others it seems to output the wrong numbers. Here are the results of some of my tests
point_of_intersection(1, 4, 2, 6) #Gives (-2,2) which is correct
point_of_intersection(0,5,2,0) #Gives (2,5) when it should be (2.5, 5)
point_of_intersection(1,2,5,3) #Gives (-1, 1) when it should be (-0.25, 1.75)
I know some people may be quick to question whether or not the formula that -1 times the difference in y-intercept divided by the difference in the value of the slopes is right or not. I can guarantee that for every test I performed on the text editor, I also used the exact same formula on paper and got different results.
My best guess is that my computer is somehow performing the order of operations for
x = -1 * (b1 - b2) / (m1 - m2)
however I am not experienced enough to identify how the computer could screw up the operation.
I would appreciate all of your help thank you.
You need to work with floats:
x = (-1 * (b1 - b2) / (m1 - m2)).to_f
y = ((m1 * x) + b1).to_f
Convert your arguments to floats:
def point_of_intersection (m1, b1, m2, b2)
m1 = m1.to_f
b1 = b1.to_f
m2 = m2.to_f
b2 = b2.to_f
if m1 == m2 || m1 - m2 == 0
puts "No Solution"
elsif m1 == m2 || b1 == b2
puts "Infinite Solutions"
end
x = -1 * (b1 - b2) / (m1 - m2)
y = (m1 * x) + b1
puts "The Point Of Intersection is: (#{x}, #{y})"
end
Examples:
point_of_intersection(1, 4, 2, 6)
#The Point Of Intersection is: (-2.0, 2.0)
point_of_intersection(0, 5, 2, 0)
#The Point Of Intersection is: (2.5, 5.0)
point_of_intersection(1, 2, 5, 3)
#The Point Of Intersection is: (-0.25, 1.75)
I'm trying to compare two triangles by two point and height.
compare_tri( triangle ( point(X1,Y1), point(X2,Y2), H1),
triangle( point(X3,Y3), point(X4,Y4), H2)) :-
A1 is ((X2-X1)*(X2-X1)),
B1 is ((Y2-Y1)*(Y2-Y1)),
C1 is (A1+B1),
D1 is (sqrt(C1)),
S1 is (D1*H1),
A2 is ((X4-X3)*(X4-X3)),
B2 is ((Y4-Y3)*(Y4-Y3)),
C2 is (A2+B2),
D2 is (sqrt(C2)),
S2 is (D2*H2),
( (S1 < S2)
-> (S1 is 2), (S2 is 1)
; (S2 is 2), (S1 is 1)
),
write(S1), write('bigger than '), write(S2).
but I get the error message 'syntax operator : operator expected'
What's the problem?
There must be no space between triangle and next brace: change triangle ( point(X1,Y1) to triangle( point(X1,Y1) and the error will be gone.
apart the syntax error, already addressed by Sergey, a general advice: attempt to write reusable code in first place. It's easier to debug, to read, to remember....
triangle_area(triangle(point(X1,Y1), point(X2,Y2), H), S1) :-
A1 is ((X2-X1)*(X2-X1)),
B1 is ((Y2-Y1)*(Y2-Y1)),
C1 is (A1+B1),
D1 is (sqrt(C1)),
S1 is (D1*H1).
compare_tri(T1,T2) :-
triangle_area(T1,S1),
triangle_area(T2,S2), etc etc...