4

Can someone help me, please? I need to solve this problem in prolog and I don't know how...

"Given a list of integer numbers. Remove all sub-lists formed from decreases elements."

false
  • 10,264
  • 13
  • 101
  • 209
  • 2
    Can you show some attempt? Please read the [Stackoverflow Tour](http://stackoverflow.com/tour) regarding how to ask a proper question. – lurker Dec 02 '14 at 12:04

4 Answers4

3

We remove descending sublists in three steps:

  1. separate decreasing and non-decreasing parts (using splitlistIfAdj/3 and (#=<)/3)

    ?- splitlistIfAdj(#=<,[ 1 , 2 , 3 , 4,3,2,1 , 2 , 3 , 4,3,2,1 , 2 ],Xs1).
    Xs1 =                 [[1],[2],[3],[4,3,2,1],[2],[3],[4,3,2,1],[2]].
    
  2. exclude non-singleton lists (using tfilter/3, Prolog lambdas, and (=)/3)

    ?- tfilter(\[_|T]^(T=[]),[[1],[2],[3],[4,3,2,1],[2],[3],[4,3,2,1],[2]],Xs2).
    Xs2 =                    [[1],[2],[3],          [2],[3],          [2]].
    
  3. map singleton lists to items (using maplist/3 and Prolog lambdas)

    ?- maplist(\[H|_]^H^true,[[1],[2],[3],[2],[3],[2]],Xs).
    Xs =                     [ 1 , 2 , 3 , 2 , 3 , 2 ].
    

Let's put it together!

:- use_module(library(clpfd)).
:- use_module(library(lambda)).

descending_removed(Xs0,Xs) :-
   splitlistIfAdj(#=<,Xs0,Xs1),
   tfilter(\[_|T]^(T=[]),Xs1,Xs2),
   maplist(\[H|_]^H^true,Xs2,Xs).

Here are some queries:

?- descending_removed([1,2,3,4,3,2,1,2,3,4,3,2,1,2],Xs).
Xs = [1,2,3,2,3,2].

?- descending_removed([4,3,2,1,0],Xs).
Xs = [].

?- descending_removed([1,2,3,4],Xs).
Xs = [1,2,3,4].

?- descending_removed([1,2,3,  4,3,3,2,2,1],Xs).
Xs = [1,2,3].

?- descending_removed([1,2,3,4,4,3,3,2,2,1],Xs).
Xs = [1,2,3,4].
Community
  • 1
  • 1
repeat
  • 18,496
  • 4
  • 54
  • 166
3

We can improve this answer by using tchoose/3 instead of tfilter/3 and maplist/3, removing descending sublists in two steps---not three:

  1. separate decreasing and non-decreasing parts (using splitlistIfAdj/3 and (#=<)/3)

    ?- splitlistIfAdj(#=<,[ 1 , 2 , 3 , 4,3,2,1 , 2 , 3 , 4,3,2,1 , 2 ],Xs1).
    Xs1 =                 [[1],[2],[3],[4,3,2,1],[2],[3],[4,3,2,1],[2]].
    
  2. filter singleton lists and map to items (using tchoose/3, Prolog lambdas, and (=)/3)

    ?- tchoose(\[H|T]^H^(T=[]),[[1],[2],[3],[4,3,2,1],[2],[3],[4,3,2,1],[2]],Xs).
    Xs =                       [ 1 , 2 , 3 ,           2 , 3 ,           2 ].
    

Let's put it together!

:- use_module(library(clpfd)).
:- use_module(library(lambda)).

descending_removed(Xs0,Xs) :-
   splitlistIfAdj(#=<,Xs0,Xs1),
   tchoose(\[H|T]^H^(T=[]),Xs1,Xs).

Same queries, same results:

?- descending_removed([1,2,3,4,3,2,1,2,3,4,3,2,1,2],Xs).
Xs = [1,2,3,2,3,2].

?- descending_removed([4,3,2,1,0],Xs).
Xs = [].

?- descending_removed([1,2,3,4],Xs).
Xs = [1,2,3,4].

?- descending_removed([1,2,3,  4,3,3,2,2,1],Xs).
Xs = [1,2,3].

?- descending_removed([1,2,3,4,4,3,3,2,2,1],Xs).
Xs = [1,2,3,4].
Community
  • 1
  • 1
repeat
  • 18,496
  • 4
  • 54
  • 166
  • Which result it provides to query "descending_removed([1,2,3,3,2,4,3,3,2,2,5],R)." ? (sorry, no lambda package to test by myself). – pasaba por aqui Aug 16 '15 at 10:47
  • @pasabaporaqui: Which Prolog system are you using? You should be able to copy-paste to module-free version into any conforming system. – false Aug 17 '15 at 17:58
2

Let's start with some sample list of numbers:

1 2 3 4 3 2 1 2 3 4 3 2 1 2

After eliminating all decreasing sublists we should have

1 2 3 2 3 2

How could this be done? I would propose going through the list and observing how the "output" is generated when looking at group of numbers:

A B C
  1 2   -> output 1
1 2 3   -> output 2
2 3 4   -> output 3
3 4 3   -> output none
4 3 2   -> output none
3 2 1   -> output none
2 1 2   -> output none
1 2 3   -> output 2
2 3 4   -> output 3
3 4 3   -> output none
4 3 2   -> output none
3 2 1   -> output none
2 1 2   -> output none
1 2     -> output 2

What we see is that we output number from middle column B only when A < B < C. So this is what we can do: we can go through entire list and check number triples. If the're sorted then we output B.

remove_dec([], []).
remove_dec(Input, Output) :-
    min_list(Input, Min),
    remove_dec0([ Min | Input ], Output).
remove_dec0([ A, B, C | Input], [ B | Output ]) :-
    A =< B, B =< C,
    remove_dec0([ B, C | Input], Output).
remove_dec0([ _, B, C | Input], Output) :-
    remove_dec0([ B, C | Input], Output).
remove_dec0([A, B], [B]) :-
    A =< B.
remove_dec0([A, B], []) :-
    A > B.

Sample input and output:

?- remove_dec([1,2,3,4,3,2,1,2,3,4,3,2,1,2],R).
R = [1, 2, 3, 2, 3, 2] .

?- remove_dec([4,3,2,1,0],R).
R = [] ;
false.

?- remove_dec([1,2,3,4],R).
R = [1, 2, 3, 4] .
Grzegorz Adam Kowalski
  • 5,243
  • 3
  • 29
  • 40
  • @repeat, the clause you quote doesn't exist. Are you suggesting to reaplce `A =< B, B =< C` with `once(A > B;B > C)`? I've checked and it resulted in giving wrong results. – Grzegorz Adam Kowalski Aug 13 '15 at 11:32
  • 1
    I meant the clause `remove_dec0([ _, B, C | Input], Output) :- remove_dec0([ B, C | Input], Output).` That should better be: `remove_dec0([A,B,C|Input],Output) :- once(A > B;B > C), remove_dec0([B,C|Input],Output).` so this clause and the one above it become mutually exclusive (without using a cut on that level). – repeat Aug 13 '15 at 11:49
  • 1
    @Grzegorz: cut after A =< B, B =< C. – pasaba por aqui Aug 16 '15 at 08:34
1

What about (using same names and test than in previous answers):

descending_removed(L,R) :- dr(a,L,R).

dr(_,[],[]).

dr(DIR,[A|Q],R) :-
  ( [B|_]=Q, A>B ->  
        dr(d,Q,R)
  ;
        dr(a,Q,T), ( DIR=a -> R=[A|T]; R=T )
  ).

verification:

test :-
  descending_removed([1,2,3,4,3,2,1,2,3,4,3,2,1,2],[1,2,3,2,3,2]),
  descending_removed([4,3,2,1,0],[]),
  descending_removed([1,2,3,4],[1,2,3,4]),
  descending_removed([1,2,3,4,3,3,2,2,1],[1,2,3]),
  descending_removed([1,2,3,4,4,3,3,2,2,1],[1,2,3,4]),
  descending_removed([1],[1]).

gives following result:

[debug]  ?- test.
true ;
false.

If we want to cover the case of two consecutive equal values, with the interpretation they doesn't changes the curve tendency, we can define:

descending_removed(L,R) :- dr(a,L,R).

dr(_,[],[]).

dr(DIR,[A|Q],R) :-
  ( [B|_]=Q, A>B ->  
        dr(d,Q,R)
  ; [B|_]=Q, A=B ->  
        dr(DIR,Q,T), ( DIR=a -> R=[A|T]; R=T )   
  ;   
        dr(a,Q,T), ( DIR=a -> R=[A|T]; R=T )
  ).

that produces following answers:

descending_removed([1,2,2,2,3,4,3,3,2,2,1],R).
R = [1, 2, 2, 2, 3] ;
false

descending_removed([1,2,3,3,2,4,3,3,2,2,5],R).
R = [1, 2, 3, 5]
false
pasaba por aqui
  • 3,446
  • 16
  • 40