Search code examples
prologintegergeneratorperfect-square

Prolog - generate and test, how to write a rule square(S)


I have to write a rule square(S) in Prolog that tests if a number S is the square of an integer returning false (ex. square(3)) or true (ex. square(4)). I used already a rule that generates all integers between 0 and M:

isInteger(X,M) :- between(0,M,X).

Using this generator I have to write the rule square(S). How can I do it? Thanks


Solution

  • To solve it your way, you just need to check if S is the product of your generated integer multiplied by itself. So you could do it like this:

    isInteger(X,M) :- between(0,M,X).
    
    square(N) :-
        isInteger(X, N),
        N is X * X.
    

    I came up with another possible solution, using the sqrt arithmetical function from SWI-Prolog but I think there must be a more elegant one.

    I initially expected it would be as simple as X is sqrt(4), integer(X). However, this doesn't work (at least not in SWI-Prolog 7.1.4), because X is unified with the float 2.0 and integer(2.0) is false (since integer is checking the data type, not the value of the number). But this works:

    square_of_integer(N) :-
        Int is rationalize(sqrt(N)),
        integer(Int).
    

    It depends on first giving a representation of N as a rational (which, in SWI-Prolog, 'are represented by the compound term rdiv(N,M)'). 2 is rationalize(2.0), i.e., rationalize evaluates to an integer for round numbers.