Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prolog check list of numbers are in order

Tags:

prolog

I would like to be able to take a list of numbers and get the largest sequence of numbers that are in order. For example:

?- in_order([1,2,3,4,5],N).
N = 5.                              % expected result

?- in_order([1,2,5,6,7,8,4],N).
N = 4.                              % expected result

I have so far produced some basic code that counts up the length of a sequence of numbers but once the list is empty, it back tracks, hence the number returned N, is the same as the first element in the list. I know that I need to stop back tracking but can't seem to do it. Would someone be kind enough to point me in the correct direction.

My code so far (all be it be a bit hacky):

in_order([],_) :-
   !.
in_order([H|T],N):-
   (  var(N), 
      N is H 
   ;  true
   ),
   H = N,
   M is N+1,
   in_order(T,M).

I do understand that my current solution would not work in the 2nd example given, and pointers for that aspect would again be helpful, as I'm not too sure how to tackle that aspect. I'm using SICStus Prolog.

Many thanks in advance!

like image 752
clangers Avatar asked Dec 30 '25 03:12

clangers


2 Answers

Let me call that relation zs_maxInOrder/2, it is based on clpfd and uses reified constraints:

:- use_module(library(clpfd)).

zs_maxInOrder([]    ,0).
zs_maxInOrder([Z|Zs],N) :-
    zs_prev_n_max0_max(Zs,Z,1,1,N).            % use "lagging" 

zs_prev_n_max0_max([]     ,_ ,_ ,M ,M).
zs_prev_n_max0_max([Z1|Zs],Z0,N0,M0,M) :-
    Z1 #= Z0 + 1 #<=> B,                       % with SWI-Prolog use `(#<==>)/2`
    N1 #= N0 * B + 1,
    M1 #= max(M0,N1),
    zs_prev_n_max0_max(Zs,Z1,N1,M1,M).

Let's see it in action using SICStus Prolog 4.3.1:

?- zs_maxInOrder([1,2,3,4,5],N).
N = 5 ? ;
no
?- zs_maxInOrder([1,2,5,6,7,8,4],N).
N = 4 ? ;
no

What about corner cases?

?- zs_maxInOrder([1],N).
N = 1 ? ;
no
?- zs_maxInOrder([],N).
N = 0 ? ;
no
like image 140
repeat Avatar answered Dec 31 '25 17:12

repeat


Here is a rather brute force solution to the problem :P ( I know I'll get criticized, but I couldn't resist playing with the higher-order predicates ).

my_prefix(List,Prefix) :- 
   append(Prefix,_,List).

my_suffix(List,Suffix) :- 
   append(_,Suffix,List).

my_sublist(List,Sublist) :-
   my_suffix(List,Suffix),
   my_prefix(Suffix,Sublist).

all_sublists(List,AllSublists) :- 
   findall(Sub,my_sublist(List,Sub),AllSublists).

good_list([]) :- 
   !.
good_list([H]) :- 
   !.
good_list([H1,H2|T]) :- 
   H1 is H2-1,
   good_list([H2|T]),
   !.

in_order(List,Length) :-
   all_sublists(List,AllSublists),
   findall(L,(member(Sublist,AllSublists),
              good_list(Sublist),
              length(Sublist,L)),
             InOrderSizes),
   max_list(InOrderSizes,Length).
like image 42
ssbarbee Avatar answered Dec 31 '25 19:12

ssbarbee



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!