0

I am attempting to solve some mutually recursive constraints with SWI-Prolog. These constraints are relatively simple, but querying any of these predicates leads to infinite recursion:

%If X is an animal, then X is a bird or a mammal, and vice-versa.
animal(X) :- 
    (mammal(X);bird(X)),
    (male(X);female(X)).

male(X) :- animal(X).
female(X) :- animal(X).

bird(X) :- (X='parrot';X='pigeon'),animal(X).

mammal(X) :- (X='cat';X='dog'),animal(X).

Would it be possible to solve these constraints in Prolog without making them non-recursive?

I wrote a similar program with several base cases, but the query mammal(X),bird(X) still leads to infinite recursion instead of returning false:

%If X is an animal, then X is a bird or a mammal, and vice-versa.
animal(X) :- 
    (mammal(X);bird(X)).

bird('parrot').
bird('pigeon').
bird(X) :- (X='parrot';X='pigeon'),animal(X).

mammal('cat').
mammal('dog').
mammal(X) :- (X='cat';X='dog'),animal(X).
5
  • 2
    You realize that prolog predicates don't return values like functions do, right? So dif(mammal(X), bird(X)) doesn't do what you probably think it does. In fact, it will always succeed since the terms mammal(X) and bird(X) are always necessarily different for any X. As Scott points out in his "answer", you don't have any facts or base cases. Commented Jul 22, 2016 at 20:35
  • @lurker Yes, the the dif/2 predicates were redundant in this case. I edited the program to correct this problem. Commented Jul 23, 2016 at 19:52
  • They weren't just redundant. They were erroneously used. :p Your existing logic, besides missing base case(s) as Scott points out, is circular. animal/1 is defined in terms lf male/1, female/1 and mammal/1. And male/1, female/1, and mammal/1 are defined in terms of animal/1. Commented Jul 23, 2016 at 20:03
  • @lurker I updated the question again, and I encountered the same problem even after I added several base cases. Commented Jul 23, 2016 at 20:08
  • 1
    The new logic is still circular. mammal defined in terms of animal, and animal defined in terms of mammal. Commented Jul 23, 2016 at 20:17

4 Answers 4

3

Solving a recursive constraint requires one or more base cases; you have not provided any. The problem isn't with Prolog; its with the problem definition.

Sign up to request clarification or add additional context in comments.

4 Comments

Of course, it would be possible to re-write these mutually recursive constraints as non-recursive constraints, but my goal is to solve mutually recursive constraints without manually re-writing them. There is an SMT solver for Prolog that might make this easier.
There is no solver of any kind that can "solve" a recursive problem that does not have any base cases. Adding base cases does not make it non-recursive; base cases are part of a recursive definition.
Q: "Would it be possible to solve these constraints in Prolog without making them non-recursive?"; I explained why the problem is ill-formed & thus cannot be solved.
@ScottHunter I updated the question again, but adding base cases did not completely solve this problem.
3

It is possible to find solutions for mutually recursive constraints using constraint handling rules.

This is a set of mutually recursive constraints:

%If X is an animal, then X is a bird or a mammal, and vice-versa.
:- use_module(library(chr)).

:- chr_constraint mammal/2,bird/2,animal/1,male/1,female/1,species/2.

animal(X) <=> 
    (mammal(X,Species);bird(X,Species)),
    (male(X);female(X)).

male(X),female(X) ==> false.

bird(X,Species) <=> member(Species,[parrot,pigeon,crow]),species(X,Species).
bird(X,Species) ==> animal(X).

mammal(X,Species) <=> member(Species,[cat,dog,bull]),species(X,Species).
mammal(X,Species) ==> animal(X).

species(X,bull) ==> male(X).

...and this is the output of a query for this program:

?- male(X),mammal(X,Species).
male(_G67406)
species(_G67406,cat)
Species = cat

Comments

2

I think what you're trying to get at is that you have birds and you have mammals. And you are further trying to establish that a creature is an animal if it is either a bird or a mammal.

The code currently over-specifies, and has circular logic.

Walking through the code...

animal(X) :- 
    (mammal(X); bird(X)).

This says that X is an animal if X is a mammal or X is a bird. So far, so good.

The description of bird reads:

bird('parrot').
bird('pigeon').

These are facts that indicate that a parrot is a bird and a pigeon is a bird. But then there's this rule:

bird(X) :- (X='parrot';X='pigeon'),animal(X).

Which says that X is a bird if X is either a parrot or pigeon, AND if X is an animal. The prior two facts already establish that parrot and pigeon are birds. Why is this rule necessary? And it further adds the condition that X is an animal, which is, in turn, defined in terms of bird and mammal, so is circular.

Similar holds true for the mammal definition. It has the needed facts for mammals:

mammal('cat').
mammal('dog').

And then overspecifies with circular logic:

mammal(X) :- (X='cat';X='dog'), animal(X).

The essence of what you need is simply:

bird('parrot').
bird('pigeon').

mammal('cat').
mammal('dog').

animal(X) :- 
    mammal(X); bird(X).

This logic defines what creatures are birds or mammals using facts, then provides a rule that says if a creature is known to be a bird or a mammal, then it's an animal.

1 Comment

This solution works in this case, but my goal is to solve mutually recursive constraints without manually rewriting them in a non-recursive form. In order to do this, I might need to use a forward-chaining inference engine like CHR.
2

One solution to such problems is to simply enable your Prolog system's tabling mechanism.

For example, in SWI-Prolog (latest development version), if I simply add the following directives at the start of your program:

:- use_module(library(tabling)).

:- table animal/1.

Then I get for example:

?- animal(X).
false.

?- male(X).
false.

?- bird(X).
false.

So, in these cases, we still do not find any solution, but at least we get answers.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.