0

I'm new to Prolog and I'm trying to write fully working magic square program, but to say the truth I don't really know how to do, I have started but I feel that I'm doing it wrong. I'm sharing my code and I hope someone will help me, now when numbers are good I get true, but when they are not I get like out of stack error... (here is only checking rows and columns I know about obliquely check) thanks for your attention!

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

magicSq(List, N) :-
   Number is N * N,
   belongs(Number ,List), % check if numbers are correct.
   all_different(List), % check if numbers not occur.
   Suma is N*(N*N + 1)/2,
   checkC(List,N,N,Suma), % check column
   checkR(List,1,N,Suma). % check row

belongs(0, _).
belongs(N, List) :- member(N,List) , Index is N - 1 , belongs(Index, List).

consecutiveSum(_, 0 , _,0).
consecutiveSum(List, HowMuch , From,Sum):-
    Index is HowMuch - 1,
    From1 is From +1,
    nth1(From, List,Element),
    consecutiveSum(List,Index,From1,Z),
    Sum is Z + Element,!.

sumObliCol(0,_, [], _,_). % sums by columns or obliquely
sumObliCol(X,Number, [H|T], Ind, Residue) :-
   Index is Ind + 1,
   Y is mod(Index,Number),
   Y =:= Residue,
   sumObliCol(Z,Number, T, Index,Residue),
   X is Z + H, !.
sumObliCol(X,Number, [_|T], Ind,Residue) :-
   Index is Ind + 1,
   sumObliCol(X,Number, T, Index,Residue).


checkC(_,0,_,_).  % check column
checkC(List,N, Number,Answ):-
   N1 is N-1,
   checkC(List,N1, Number,Answ),
   sumObliCol(Ats,Number,List,0,N1),Ats is Answ,!.

checkR(_,N,Number,_):- N>(Number*Number). % check row
checkR(List,N,Number,Answ):-
    consecutiveSum(List,Number,N,Sum), Sum is Answ,
    N1 is N + Number,
    checkR(List,N1, Number,Answ),!.
Guy Coder
  • 24,501
  • 8
  • 71
  • 136
EasyCode
  • 47
  • 1
  • 8
  • Are you trying to generate a magic square, or check if an inputted square is magic? – bendl Nov 15 '16 at 20:58
  • What are the rules for your magic square? Looking at your code I can sort of guess them, but it wouldn't hurt to write them down explicitly. –  Nov 15 '16 at 21:01
  • 2
    Another thing: this is a bad way to ask a question. It would be much better if you actually point out a particular problem, _in as little code as possible_, explain how you tried to solve it, and why you can't. At the moment it is more of a "code review" question and this doesn't belong on Stackoverflow. –  Nov 15 '16 at 21:02
  • 2
    Yet another thing: you seem to plan to use library(clpfd), but you don't use it at all in the code. Simplifying your code and replacing all arithmetic with CLP(FD) constraints might solve your problem. –  Nov 15 '16 at 21:04

1 Answers1

3

In programming one often assumes that

everything is deeply intertwingled ... since the cross-connections among the myriad topics of this world/program simply cannot be divided up neatly.1

But in Prolog, sometimes, we can divide things up much more neatly. In particular, if you concentrate on a single property like non-termination. So let's consider magic squares of size one — very magic indeed! Like so using a :

?- magicSq(Xs,1), false.

magicSq(List, N) :-
   Number is N * N,
   belongs(Number ,List), false, 
   all_different(List),
   Suma is N*(N*N + 1)/2,
   checkC(List,N,N,Suma),
   checkR(List,1,N,Suma).

belongs(0, _) :- false.
belongs(N1, List) :-
   member(N1,List), false,
   N2 is N1 - 1,
   belongs(N2, List).

That's all you need to understand! Evidently, the List is unconstrained and thus the goal member(N1, List) cannot terminate. That's easy to fix, adding a goal length(List, Number). And still, the program does not terminate but in a different area:

?- magicSq(Xs,1), false.

magicSq(List, N) :-
   Number is N * N,
   length(List, Number),
   belongs(Number ,List), false, 
   all_different(List),
   Suma is N*(N*N + 1)/2,
   checkC(List,N,N,Suma),
   checkR(List,1,N,Suma).

belongs(0, _) :- false.
belongs(N1, List) :-
   member(N1,List),
   N2 is N1 - 1,
   belongs(N2, List), false.

Now this does not terminate, for N1 may be negative, too. We need to improve that adding N1 > 0.

Now, considering the program with a false in front of all_different/1, I get:

?- time(magicSq(List, 3)).
% 8,571,007 inferences

That looks like an awful lot of inferences! In fact, what you are doing is to enumerate all possible configurations first. Thus, you do not use the powers of constraint programming. Please go through tutorials on this. Start here.

However, the problems do not stop here! There is much more to it, but the remaining program is very difficult to understand, for you are using the ! in completely unrelated places.

false
  • 10,264
  • 13
  • 101
  • 209