2

I'm stuck getting a generalized version of a "Magic Square" program in SWI-prolog to work. This is my approach:

:- use_module(library(clpfd)).

sumok(Sum, Lst) :-
    sum_list(Lst, Sum).

solve(Size, Grid) :-
    length(Grid, Size), maplist(same_length(Grid), Grid),
    append(Grid, Cells),

    MaxVal #= Size * Size,
    Cells ins 1..MaxVal,
    all_distinct(Cells),

    RowColSum is round((1 + MaxVal) / 2 * MaxVal / Size),
    format("The sum in each row and column is ~d.\n", [RowColSum]),

    maplist(sumok(RowColSum), Grid),
    transpose(Grid, TransposedGrid),
    maplist(sumok(RowColSum), TransposedGrid),
    !.

run :-
    solve(4, Solution),
    write(Solution).

The problem is, that while summing up the rows in "sumok" none of the variables are initialized. So I get this error message:

ERROR: Arguments are not sufficiently instantiated
ERROR: In:
ERROR:   [16] _33164 is 0+_33172
ERROR:   [15] lists:sum_list([_33210,_33216|...],0,34) at c:/program files/swipl/library/lists.pl:650
ERROR:   [12] '__aux_maplist/2_sumok+1'([[_33254|...],...|...],34) at prolog/magic_square_4x4.prolog:6
ERROR:   [11] solve(4,[[_33298|...],...|...]) at prolog/magic_square_4x4.prolog:17
ERROR:   [10] run at prolog/magic_square_4x4.prolog:23

Of course I could insert a "labeling" after calculating the RowColSum, but then the program runs until my laptop battery is dead. Which is the correct (i.e. the CLPFD-) way, to make this work?

Hennes
  • 1,340
  • 1
  • 10
  • 26
  • 2
    `sum_list` fails because you haven't yet run `label`, so the variables are still indeterminate - instead, can use clpfd's https://www.swi-prolog.org/pldoc/doc_for?object=clpfd%3Asum/3 – brebs Oct 17 '22 at 07:48
  • 2
    This cut is never a good idea in the context of constraints. – false Oct 17 '22 at 07:54

1 Answers1

2

Now it works, thanks to brebs' comment:

:- use_module(library(clpfd)).

sumok(Sum, Lst) :-
    sum(Lst, #=, Sum).   % <-- Corrected line

solve(Size, Grid) :-
    length(Grid, Size), maplist(same_length(Grid), Grid),
    append(Grid, Cells),

    MaxVal #= Size * Size,
    Cells ins 1..MaxVal,
    all_distinct(Cells),

    RowColSum is round((1 + MaxVal) / 2 * MaxVal / Size),
    format("The sum in each row and column is ~d.\n", [RowColSum]),

    maplist(sumok(RowColSum), Grid),
    transpose(Grid, TransposedGrid),
    maplist(sumok(RowColSum), TransposedGrid),

    label(Cells).

run :-
    solve(4, Solution),
    write(Solution).
Hennes
  • 1,340
  • 1
  • 10
  • 26