0
votes

I'm trying to use Prolog to reason about constraints and then query the knowledgebase to pass these constraints on to a solver (can't use clpfd).

%a first example would be constrainsquare(Row,Col,Val)
constrainsquare(1,1,3).
constrainsquare(1,2,2).

and I can then query all constraints using something like bagof/3. This is not statisfactory because I also want to be able to write

 constrainsquare(3,4,8):-constrainsquare(3,3,7).

The ability to say that if the solution has a 7 at position 3,3; it necessarily has an 8 at position 3,4. Now you can no longer gather all constraints using something like bagof/3.

How would you do this ideomatically in prolog?

Note that I cannot simply do

constrainsquare(L) :-
  member(cs(1,1,3),L),
  member(cs(1,2,2),L),
  member(cs(3,4,8),L),
  member(cs(3,3,7),L).

because I'm receiving new facts about the solution periodically and cannot alter existing facts.

At the moment I'm thinking about using a list of constraints and doing something like

info(cell(1,1,3)).
info(cell(1,2,2)).
constrainsquare(I,[I]).
partialinfo(cell(3,4,8),cell(3,3,7)).
....

and then query it by running bagoff to obtain [cell(1,1,3)],[cell(1,2,2)]... and then folding/appending to [cell(1,1,3),cell(1,2,2)] but this feels a bit 'meh'. I want to know the "proper" way.

1
Can you show an example of how you were expecting to call bagof/3 and why it doesn't work? If I assert facts constrainsquare(1,1,3)., constrainsquare(1,2,2)., constrainsquare(3,3,7). and the rule constrainsquare(3,4,8):-constrainsquare(3,3,7). and query, bagof([A,B,C], constrainsquare(A,B,C), L), I get all of the expected solutions listed in L. So I don't quite understand the problem. - lurker
Ah yes, if you assert constrainsquare(3,3,7) first, then that rule will work. The issue here is that the real solution doesn't need to have a 7 at position 3,3. The only information given is that if there is a 7 there, there necessarily also has to be an 8 at position 3,4. I can't find an 'elegant' workaround and this usually means that I'm doing something fundamentally the wrong way, so I'm asking what the right way is. :) - camel
I guess I'm not following what you man by gathering all constraints with bagof/3. bagof/3 doesn't gather constraints, but rather it gathers known solutions assuming the currently asserted facts and rules. - lurker
What you could do is say (im on mobile, don't see how i can do code tags) "hasto(cell(1,2,3)). hasto(cell(3,4,5))." And then with bagof you can obtain a list containing all requirements [cell(1,2,3),cell(3,4,5)]. So i could query my knowledgebase to obtain the constrains to pass on to a solver. - camel
I have a feeling I'm not very clear in my question, but I'm not sure what I can change to make it better. All I want is to supply facts about the solution, including conditional facts, and then gather what the possible solutions can be. - camel

1 Answers

1
votes

Let's suppose you had query, we'll call it Q, that you wished to run on a set of hypothetical facts. We'll call the set of facts, Facts. You could write a predicate which would run the query on those facts dynamically as follows:

what_if_query(Q, Facts) :-
    maplist(assertz, Facts),
    call(Q),
    maplist(retract, Facts).

If Q takes one argument for results, R, then we could write:

what_if_query(Q, Facts, R) :-
    maplist(assertz, Facts),
    call(Q, R),
    maplist(retract, Facts).

Then, if you had a list of scenarios of facts, you could write:

what_if_scenarios(Scenarios, Q, Results) :-
    maplist(what_if_query(Q), Scenarios, Results).

A "fact" can be any assertable Prolog term, and so could also be a rule: (Head :- P1, P2, ..., Pn). For example, your list of "facts" could be:

[cs(1,1,3), cs(1,2,2), (cs(3,4,8) :- cs(3,3,7))]