:- module(_1,[pds/2],[assertions,regtypes,nativeprops]).

:- entry pds(X,Y) : ( num(X), var(Y) ).
:- pred pds(X,Y) : ( num(X), var(Y) ).

pds(X, Y) :- pds_(X, Y).

:- pred pds_(Ord, Set) : (num(Ord), var(Set)) => numlist(Set).

pds_(Order,[0|Ans]) :-
        N is Order*(Order+1)+1,
        iota(N,[0|List]),
        pds1(List,[0],Ans,N).

pdsbm(N) :-
        pds_(N,[0,1|_X]).

mymember(X,[X|_Xs]).
mymember(X,[_1|Xs]) :-
        mymember(X,Xs).

:- pred iota(N, List) : num(N) => numlist(List).

iota(N,List) :-
        iota1(0,N,List).

:- pred iota1/3 : num * num * term => num * num * numlist.

iota1(K,K,[]) :- !.
iota1(K,N,[K|List]) :-
        K1 is K+1,
        iota1(K1,N,List).

:- pred dif/5 : numlist * num * num * term    * term
             => numlist * num * num * numlist * numlist.

dif([],_1,_2,[],[]).
dif([S|Ss],Val,Mod,[D|Ds],[D2|D2s]) :-
        D is Val-S,
        D2 is Mod-D,
        dif(Ss,Val,Mod,Ds,D2s).

:- pred rev(L1, Acc, LRev) : (numlist(L1), numlist(Acc)) => numlist(LRev).

rev([],L,L).
rev([X|Xs],Y,L) :-
        rev(Xs,[X|Y],L).

:- pred mergedelete(L1, Acc, L2) : (numlist(L1), numlist(Acc)) => numlist(L2).

mergedelete([],L,L).
mergedelete([D|Ds],[D|R],L2) :-
        mergedelete(Ds,R,L2).
mergedelete([D|Ds],[X|R],[X|L2]) :-
        D@>X,
        mergedelete([D|Ds],R,L2).

:- pred check/5 : numlist * num * numlist * var  * num
               => numlist * num * numlist * numlist * num.

check([],_1,L,L,_2) :- !.
check(S,Choice,Old,L3,Modulus) :-
        dif(S,Choice,Modulus,Ds,Dds),
        mergedelete(Ds,Old,L2),
        rev(Dds,[],Rds),
        mergedelete(Rds,L2,L3),
        !.

:- pred pds1/4 : numlist * numlist * term * num
              => numlist * numlist * numlist * num.

pds1([],_1,[],_2) :- !.
pds1(Unused,List,[Choice|Rest],Mod) :-
        mymember(Choice,Unused),
        check(List,Choice,Unused,U3,Mod),
        pds1(U3,[Choice|List],Rest,Mod).

:- regtype numlist/1.

numlist([]).
numlist([A|B]) :-
        num(A),
        numlist(B).
