0

I am a beginner in Prolog, and I've searched a lot but cannot solve the problem. The question is giving me a list given the head of the list, such as [20,_,_,_].

  1. The length of the list is unknown. For example, it could be [30,_,_,_,_,_].
  2. the _ is the distinct factor, which only consists of the digit from 1 to 9. For example, [20,_,_,_] could generate [1,4,5] and its combination.
  3. The list could be filled with a number first. For example, [20,_,4,_]. The output would be still [1,4,5] and [5,4,1].

What I've tried is to rip off the head of the list, and try to generate the rest of the elements back to the original list, but I failed, and cannot understand the debugger and its trace information.

removeHead([Head|Tail],Tail).

get_head_element([],_).
get_head_element([Head|Rest],Head).

divide(1,[],_).
divide(Number,[Head|List],Result):-
    0 is mod(Number,Head),
    Quotient is Number/Head,
    divide(Quotient,List,Result).

solve_multiply(Row,RestRow):-
    get_head_element(Row, Goal),
    removeHead(Row,RestRow),
    all_distinct(RestRow),
    RestRow ins 1..9,
    divide(Goal,RestRow,RestRow).

Any hint of resource that I can keep approaching this question? Thanks.

EDIT: I think it another way that the elements multiplied in the list would be the same at the head, so I wrote a multiply predicate.

%% multiply(+List,-Result)
%
% for calling the multiply(+List,+PrevResult,+Result) with accumulator set to 1
multiply(List,Result):-
    multiply(List,1,Result).

%% multiply(+List,+PrevResult,+Result)
%
% multiply each element in the list
multiply([Element|RestList],PrevResult,Result):-
    NextResult is PrevResult * Element,
    multiply(RestList,NextResult, Result).

%% multiply([], -Result, -Result).
%
% multiply predicate stops when all the elements have been multiplied
multiply([], Result, Result).

%% solve_multiply(+Row,-RestRow)
solve_multiply(Row,RestRow):-
    get_head_element(Row, Goal),
    removeHead(Row,RestRow),
    RestRow ins 1..9,
    multiply(RestRow,Goal), % get the Arguments not sufficiently instantiated message
    all_distinct(RestRow).
Woden
  • 1,054
  • 2
  • 13
  • 26
  • 1
    Why the clpfd tag. I don't see any use of clpfd. Which Prolog are you using, e.g. SWI-Prolog. – Guy Coder Apr 10 '21 at 10:26
  • @Guy Coder Yes, I am using SWI prolog. the all_distinct is used in the code, I consider it related to clpfd. – Woden Apr 10 '21 at 10:42
  • 1
    As a suggestion think about creating a [conical form](https://en.wikipedia.org/wiki/Canonical_form) for the result and how the expected answer and the generated answers can be converted and compared to a conical form. – Guy Coder Apr 10 '21 at 11:46
  • Thank you for the information, I'll try to understand it. – Woden Apr 10 '21 at 11:54
  • 1
    I have not written any code to test my ideas as I am busy with something else and only posted during the few seconds of waiting. I think you will also need something like [Subsets in Prolog](https://stackoverflow.com/questions/4912869/subsets-in-prolog) and [Deleting anonymous variables in a list](http://swi-prolog.996271.n3.nabble.com/Deleting-anonymous-variables-in-a-list-tp4400p4402.html) – Guy Coder Apr 10 '21 at 12:52
  • 1
    Another way would be to just use member/2 and remove the known factors of the smaller list from the larger list of factors and see if the list is empty when done. Then you know all of the factors from the smaller list are in the larger list. – Guy Coder Apr 10 '21 at 13:00
  • 1
    @GuyCoder: Question applies to SICStus, Scryer as well. – false Apr 11 '21 at 07:44
  • I am trying to think it another way, but haven't figured it out yet. I wrote a multiply function to multiply the elements in the `RestRow`, which is `multiply(+List, -Result)`. Next, I compare it to the head, `multiply(RestRow, Goal)`, but got `Arguments not sufficiently instantiated.` I'll update the post. – Woden Apr 11 '21 at 08:29
  • I figured it out!!! I'll post an answer :) – Woden Apr 11 '21 at 08:46

1 Answers1

0

The simplest way to find the solution is to:

  1. Compare the multiplied elements to the head element.
  2. Use the constraint provided by clpfd.

Therefore, the code should be:

multiply(List,Result):-
    multiply(List,1,Result).

multiply([Element|RestList],PrevResult,Result):-
    NextResult #= PrevResult * Element, % constraint that works for both side ?X #= ?Y
    multiply(RestList,NextResult, Result). % tail recursion

multiply([], Result, Result).

solve_multiply(Row,RestRow):-
    get_head_element(Row, Goal),
    removeHead(Row,RestRow),
    RestRow ins 1..9,
    multiply(RestRow,Goal),
    all_distinct(RestRow).

When calling the solve_multiply([20,_,_,_],X), labeling([],X). The result is:

X = [1, 4, 5] ;
X = [1, 5, 4] ;
X = [4, 1, 5] ;
X = [4, 5, 1] ;
X = [5, 1, 4] ;
X = [5, 4, 1] ;
false.

When calling the solve_multiply([20,_,1,_],X), labeling([],X). The result is:

X = [4, 1, 5] ;
X = [5, 1, 4].
Woden
  • 1,054
  • 2
  • 13
  • 26