Search code examples
prologclpfdpythagorean

Prolog pythagorean triplet


I'm trying to solve project Euler problem 9 using prolog. I'm a 100% n00b with prolog and I'm just trying to understand the basics right now.

I'm trying to use findall to get all triplets that would add up to 1000, but I can't really figure out the syntax.

What I'm hoping for is something like:

pythag_trip(A, B, C, D) :- D is (A * A) + (B * B) + (C * C).
one_thou_pythag(A, B, C) :- pythag_trip(A, B, C, 1000).
product_trip(A, B, C, D) :- D is A * B * C.
findall([A, B, C], one_thou_pythag(A, B, C) , Bag)).
writeln(Bag).

I know that doesn't work because it's saying Bag is not instantiated. But there are still some basics that I don't understand about the language, too.

1: can I even do this? With multiple moving pieces at once? Can I find all triplets satisfying a condition? Do I need to go down a completely different like like using clpfd?

2: What is supposed to be going in that last argument where I put Bag?

3: Is it possible to create data types? I was thinking it might be good to create a triplet set type and an operation to get the pythagorean triplet sum of them if I have to find some way to generate all the possibilities on my own

Basically those questions and then, I could use some pointing in the right direction if anyone has tips


Solution

  • Sorry but I don't answer your questions. It seems to me that you're trying not a prolog-like approach.

    You should try to solve it logically.

    So do this problem from the top to bottom. We want to have 3 numbers that sum to 1000.

    between(1,1000,A), between(A,1000,B), between(B,1000,C), C is 1000-A-B.
    

    In that case, we will have them sorted and we won't take permutations.

    So let's go a step further. We want them to be pythagorem triplet.

    between(1,1000,A), between(A,1000,B), between(B,1000,C), C is 1000-A-B, is_triplet(A,B,C).
    

    But we don't have is_triplet/3 predicate, so let's create it

    is_triplet(A,B,C) :- D is C*C - A*A -B*B, D=0.
    

    And that's actually it.

    So let's sum it up

    is_triple(A, B, C) :- D is C*C - A*A - B*B, D = 0.
    triplet(A,B,C) :- between(1,1000,A), between(A,1000,B), C is 1000-A-B, between(B,1000,C), C is 1000-A-B, is_triple(A,B,C). 
    

    When you call triplet(A,B,C) you should get an answer.

    Notice one thing, that at the end I've swapped C is 1000-A-B with between(B,1000,C). It makes the program much faster, try to think why.