Magic Square 
Author Message
 Magic Square

Well well, another interesting problem :o)

So simple (in C,Java,etc,etc) but yet
so hard (in PROLOG)

Magic Squares. For those that dont know what one
is well here is a definition I grabbed off the
net:

"A magic square is an arrangement of the numbers from
1 to n^2 (n-squared) in an nxn matrix, with each number
occurring exactly once, and such that the sum of the
entries of any row, any column, or any main diagonal is
the same. It is not hard to show that this
sum must be n(n^2+1)/2."

Examples (used code below to create):
order of 3              order of 5
8 1 6                   17 24 1  8  15
3 5 7                   23 5  7  14 16
4 9 2                   4  6  13 20 22
                        10 12 19 21 3
                        11 18 25 2  9

The code below (in C) will create these magic squares
of the odd numbers.

void odd_num(int n) {
   int i,j,num=1;
   int nn=n*3/2;
   for(i=0; i < n; i++)
      for(j=0; j < n; j++)
         m[(j-i+nn)%n][(i*2-j+n)%n]=num++;

Quote:
}

Well basically my question is, in Prolog, how is it
(or it is) possible to have an two demensional array
m[int][int] and then be able to input numbers into this
array? i.e in "random" spots

From my prolog experience I dont think this is possible
is it?

I can see how I could use recursion to do the for loops
but once i go to pop in the number I'm stuck.

Thanks for any help again

Alex



Tue, 13 Aug 2002 03:00:00 GMT  
 Magic Square

Quote:

> Well well, another interesting problem :o)
> So simple (in C,Java,etc,etc) but yet
> so hard (in PROLOG)
> Magic Squares. For those that dont know what one
> is well here is a definition I grabbed off the
> net:
> "A magic square is an arrangement of the numbers from
> 1 to n^2 (n-squared) in an nxn matrix, with each number
> occurring exactly once, and such that the sum of the
> entries of any row, any column, or any main diagonal is
> the same. It is not hard to show that this
> sum must be n(n^2+1)/2."
> Examples (used code below to create):
> order of 3         order of 5
> 8 1 6                      17 24 1  8  15
> 3 5 7                      23 5  7  14 16
> 4 9 2                      4  6  13 20 22
>                    10 12 19 21 3
>                    11 18 25 2  9
> The code below (in C) will create these magic squares
> of the odd numbers.
> void odd_num(int n) {
>    int i,j,num=1;
>    int nn=n*3/2;
>    for(i=0; i < n; i++)
>       for(j=0; j < n; j++)
>          m[(j-i+nn)%n][(i*2-j+n)%n]=num++;
> }
> Well basically my question is, in Prolog, how is it
> (or it is) possible to have an two demensional array
> m[int][int] and then be able to input numbers into this
> array? i.e in "random" spots
> From my prolog experience I dont think this is possible
> is it?

for a two-dimensional array of n x m you could use a functor
with arity n, and then you let each argument be a term with functor m;
accessing then needs two arg/3 operations.

E.g.: 3x3 array: f(f(_,_,_),f(_,_,_),f(_,_,_)).

A generic access predicate for twodimensional `arrays':
access(X,Y,Term,Arg) :-
   arg(X,Term,Ys),
   arg(Y,Ys,Arg).

It gets more complicated if you need to be able to alter values as
well.

--
Gertjan van Noord Alfa-informatica, RUG,  Postbus 716, 9700 AS Groningen
vannoord at let dot rug dot nl            http://www.let.rug.nl/~vannoord/



Tue, 13 Aug 2002 03:00:00 GMT  
 Magic Square
<snip my old message>

Quote:
> for a two-dimensional array of n x m you could use a functor
> with arity n, and then you let each argument be a term with functor m;
> accessing then needs two arg/3 operations.

> E.g.: 3x3 array: f(f(_,_,_),f(_,_,_),f(_,_,_)).

> A generic access predicate for twodimensional `arrays':
> access(X,Y,Term,Arg) :-
>    arg(X,Term,Ys),
>    arg(Y,Ys,Arg).

> It gets more complicated if you need to be able to alter values as
> well.

Wow, I havent heard of functor before, or anything your
talking about ;o)  
Its hard to me to learn Prolog, cause I do not have a good
book (any book for that matter).  I am relying on internet
sites to help me through it.

I'll *try* to figure that stuff out :o)

Thanks

Alex

Quote:

> --
> Gertjan van Noord Alfa-informatica, RUG,  Postbus 716, 9700 AS Groningen
> vannoord at let dot rug dot nl            http://www.let.rug.nl/~vannoord/



Tue, 13 Aug 2002 03:00:00 GMT  
 Magic Square

Quote:


> <snip my old message>
> > for a two-dimensional array of n x m you could use a functor
> > with arity n, and then you let each argument be a term with functor m;
> > accessing then needs two arg/3 operations.

> > E.g.: 3x3 array: f(f(_,_,_),f(_,_,_),f(_,_,_)).

> > A generic access predicate for twodimensional `arrays':
> > access(X,Y,Term,Arg) :-
> >    arg(X,Term,Ys),
> >    arg(Y,Ys,Arg).

> > It gets more complicated if you need to be able to alter values as
> > well.

> Wow, I havent heard of functor before, or anything your
> talking about ;o)
> Its hard to me to learn Prolog, cause I do not have a good
> book (any book for that matter).  I am relying on internet
> sites to help me through it.

> I'll *try* to figure that stuff out :o)

Okay, starting to narrow things down.
Here's what I have/know now.
If I have
f(f(1,2,3),f(4,5,6),f(7,8,9)).
I can use:
show(A,B,C) :- f(A,B,C).
to show the values like so:
?- show(A,B,C).

A = f(1, 2, 3)
B = f(4, 5, 6)
C = f(7, 8, 9)

Yes
?-

Okay, so thats perfect.
But I still have one problem, which is getting values
into the functor.

Going back to my original problem of the magic squares.

I still dont know how to get values INTO the 'array'.

Like, how do I start with a empty 3x3 array and place
values into it, say put 1 into f(1,2) and 5 into
f(3,2) and so on.  Using my formula to calculate where
the values for the magic square go.

Could I have something like this:

magic(N, f(f(_,_,_),f(_,_,_),f(_,_,_))) :- A = 5, B=1,C=2,
                        insert( A , f, B, C).
% insert 5 into f(1,2) like
% f(f(_,5,_),f(_,_,_),f(_,_,_))

insert(A, f, B, C) :- I dont even know where to start

So then my magic sqaures would look something like this:
/*************************************************/
/* C code of what I want to accomplish           */
/*                                               */
/* void odd_num(int n) {                         */
/*   int i,j,num=1;                              */
/*   int nn=n*3/2;                               */
/*   for(i=0; i < n; i++)                     */
/*      for(j=0; j < n; j++)                  */
/*         m[(j-i+nn)%n][(i*2-j+n)%n]=num++;     */
/* }                                             */
/*************************************************/

magic(N , f) :-         NN is (N*3/2),
                        Num is Num+1,
                        I <= N,
                        I is I+1,
                        J <= N,
                        J is J+1,
                        magic(N,f), % to do first loop
                        magic(N,f), % to do second loop
                        S1 is ((j-i+nn) mod n),
                        S2 is ((i*2-j+n) mod n),
                        insert(Num, f, S1, S2).

Thats my basic idea.  I know it dont work :o(
Also what is mod (remainder) in prolog?

Damn, the more I think the more questions

Thanks

Alex

- Show quoted text -

Quote:

> Thanks

> Alex

> > --
> > Gertjan van Noord Alfa-informatica, RUG,  Postbus 716, 9700 AS Groningen
> > vannoord at let dot rug dot nl            http://www.let.rug.nl/~vannoord/



Tue, 13 Aug 2002 03:00:00 GMT  
 Magic Square

What if you base your array structure as the following..

makelist(0,[]) :- !.

makelist(Dim, [[]|MoreList]) :- !, DimLeft is Dim - 1,
                                makelist(Dim,MoreList).

createarray([],[]).

createarray([Dim],[Array]) :- !, makelist(Dim,Array).

createarray([Dim|MoreDim], [Front|Array]) :- !, makelist(Dim,Front),
                                        createarray(MoreDim,Array).

this would create an `empty' array comprised of `lists-of-lists' that can
represent the data.

for example, to create a 3 x 3 array, one would do.

createarray([3,3],X).

X = [ [ [], [], [] ] , [ [], [], [] ] ]

that could be used to put in numbers in random spots...

Quote:

> Well well, another interesting problem :o)

> So simple (in C,Java,etc,etc) but yet
> so hard (in PROLOG)

> Magic Squares. For those that dont know what one
> is well here is a definition I grabbed off the
> net:

> "A magic square is an arrangement of the numbers from
> 1 to n^2 (n-squared) in an nxn matrix, with each number
> occurring exactly once, and such that the sum of the
> entries of any row, any column, or any main diagonal is
> the same. It is not hard to show that this
> sum must be n(n^2+1)/2."

> Examples (used code below to create):
> order of 3         order of 5
> 8 1 6                      17 24 1  8  15
> 3 5 7                      23 5  7  14 16
> 4 9 2                      4  6  13 20 22
>                    10 12 19 21 3
>                    11 18 25 2  9

> The code below (in C) will create these magic squares
> of the odd numbers.

> void odd_num(int n) {
>    int i,j,num=1;
>    int nn=n*3/2;
>    for(i=0; i < n; i++)
>       for(j=0; j < n; j++)
>          m[(j-i+nn)%n][(i*2-j+n)%n]=num++;
> }

> Well basically my question is, in Prolog, how is it
> (or it is) possible to have an two demensional array
> m[int][int] and then be able to input numbers into this
> array? i.e in "random" spots

> From my prolog experience I dont think this is possible
> is it?

> I can see how I could use recursion to do the for loops
> but once i go to pop in the number I'm stuck.

> Thanks for any help again

> Alex



Tue, 13 Aug 2002 03:00:00 GMT  
 Magic Square

Quote:



> > <snip my old message>
> > > for a two-dimensional array of n x m you could use a functor
> > > with arity n, and then you let each argument be a term with functor m;
> > > accessing then needs two arg/3 operations.

> > > E.g.: 3x3 array: f(f(_,_,_),f(_,_,_),f(_,_,_)).

> > > A generic access predicate for twodimensional `arrays':
> > > access(X,Y,Term,Arg) :-
> > >    arg(X,Term,Ys),
> > >    arg(Y,Ys,Arg).

> > > It gets more complicated if you need to be able to alter values as
> > > well.

> > Wow, I havent heard of functor before, or anything your
> > talking about ;o)
> > Its hard to me to learn Prolog, cause I do not have a good
> > book (any book for that matter).  I am relying on internet
> > sites to help me through it.

> > I'll *try* to figure that stuff out :o)
> Okay, starting to narrow things down.
> Here's what I have/know now.
> If I have
> f(f(1,2,3),f(4,5,6),f(7,8,9)).
> I can use:
> show(A,B,C) :- f(A,B,C).
> to show the values like so:
> ?- show(A,B,C).
> A = f(1, 2, 3)
> B = f(4, 5, 6)
> C = f(7, 8, 9)
> Yes
> ?-
> Okay, so thats perfect.
> But I still have one problem, which is getting values
> into the functor.

that's what access/4 was supposed to accomplish.
e.g.

suppose F=f(f(_,_,_),f(_,_,_),f(_,_,_)), then

access(1,3,F,27) will bind F to:

F=f(f(_,_,27),f(_,_,_),f(_,_,_))

etc.

but, reading an introductory book on Prolog might be the best way
to proceed. In the old days, there used to be buildings (called
`libraries') where you could read books (almost) for free...

Gj

--
Gertjan van Noord Alfa-informatica, RUG,  Postbus 716, 9700 AS Groningen
vannoord at let dot rug dot nl            http://www.let.rug.nl/~vannoord/



Wed, 14 Aug 2002 03:00:00 GMT  
 Magic Square

Alex asked :
...

Quote:

> Well basically my question is, in Prolog, how is it
> (or it is) possible to have an two demensional array
> m[int][int] and then be able to input numbers into this
> array? i.e in "random" spots

> From my prolog experience I dont think this is possible
> is it?

 Yes it is.
At least, I can do it for a 3 * 3 array.
I show you how below.

Its not obvious, but its easy when you know how.

Quote:

> I can see how I could use recursion to do the for loops
> but once i go to pop in the number I'm stuck.

No, don't use recursion, far too complicated.
Use "fail" instead of using recursion.

If you have a magic square three columns wide,
lets use variables "A1, A2, A3, B1, B2, B3, C1, C2, C3"
for the 9 positions.

Like this :-

number( 0 ).
number( 1 ).
number( 2 ).
number( 3 ).
number( 4 ).
number( 5 ).
number( 6 ).
number( 7 ).
... etc. ...
number( 15 ).

find_all_possible_numbers :-
    number( A1 ),
    number( A2 ),
    number( A3 ),
    number( B1 ),
    number( B2 ),
    number( B3 ),
    number( C1 ),
    number( C2 ),
    number( C3 ),
    % Now write the numbers.
    nl,
    write( A1, ' ', A2, ' ', A3 ),
    write( B1, ' ', B2, ' ', B3 ),
    write( C1, ' ', C2, ' ', C3 ),
    % Now go on to find the next set of numbers.
    fail.

% Now write "Finished."
find_all_possible_numbers :-
    n,
    write( 'Finished.' ).

/*
Now you need to write a similar program,
but exclude most combinations of numbers,
so only valid magic squares are printed.
Something like this :
*/

program :-
    number( A1 ),
    number( A2 ),
    number( A3 ),
    number( B1 ),
    number( B2 ),
    number( B3 ),
    number( C1 ),
    number( C2 ),
    number( C3 ),
    % Add up the numbers.
    Row_A_total is A1 + A2 + A3,
    Row_B_total is B1 + B2 + B3,
    Row_C_total is C1 + C2 + C3,

    % Fail if the totals are not equal.
    Row_A_total == Row_B_total,
    Row_A_total == Row_C_total,

    % Now write the numbers.
    nl,
    write( A1, ' ', A2, ' ', A3 ),
    write( B1, ' ', B2, ' ', B3 ),
    write( C1, ' ', C2, ' ', C3 ),
    % Now go on to find the next set of numbers.
    fail.
program :-
    n,
    write( 'Finished.' ).

/* You also need to allow for column totals,
to make sure they are all identical too.
So put this code in the program too :

    Column_1_total is A1 + B1 + C1,
    Column_2_total is A2 + B2 + C2,
    Column_3_total is A3 + B3 + C3,
    Column_1_total == Row_A_total,
    Column_2_total == Row_A_total,
    Column_3_total == Row_A_total,

Then do the diagonals in a similar way.

Diagonal_1 is A1 + B2 + C3,
Diagonal_2 is A3 + B2 + C1,
Diagonal_1 == Row_A_total,
Diagonal_2 == Row_B_total,

*/

/*
This is quite simple.
But I really don't know how to make a version
to find magic squares of any size.

I'd need to write a different program for each size of square.
*/

By the way, you can't learn Prolog from the web!
I strongly recommend this book as your first book on Prolog :
"Prolog Programming for Artificcial Intelligence" by Ivan Bratko,
published by Addison-Wesley, in paperback.

    Martin Sondergaard,
    London.



Thu, 15 Aug 2002 03:00:00 GMT  
 Magic Square

Quote:
> Well well, another interesting problem :o)

Hardly. You are merely trying to apply one known algorithm (of many) to compute
a solution for magic squares of odd orders. What is interesting with this
mathematical curiosity is finding the number of solutions, excluding mirroring
and turning, for a given order. We know that there is1 solution for a MS of the
3rd order and 880 for the 4th order. For a MS of the 5th order there are thought
to be in excess of 13 million solutions.

Quote:
> So simple (in C,Java,etc,etc) but yet
> so hard (in PROLOG)

Not necessarily so (see below).

[snipped]

Quote:
> The code below (in C) will create these magic squares
> of the odd numbers.

> void odd_num(int n) {
>    int i,j,num=1;
>    int nn=n*3/2;
>    for(i=0; i < n; i++)
>       for(j=0; j < n; j++)
>          m[(j-i+nn)%n][(i*2-j+n)%n]=num++;
> }

You can apply a for-next loop in Prolog too. Let's mimic your C code (keeping a
0-based indexing scheme):

    odd_num(N):-
        N1 = N - 1,
        NN = N * 3 // 2,
        for(0,N1,I),  % row
            for(0,N1,J),  % column
                I1 is (J - I + NN) mod N,  % row offset
                J1 is (I * 2 -J + N) mod N,  % column offset
                Num is I * N + J + 1,  % offset cell's value
                assert(cell(I1,J1,Num)),
            next(J,N1),
        next(I,N1).
    odd_num(_).

    for(N,_,N).
    for(Start,Stop,NumOut):-
        Start1 is Start + 1,
        Start1 =< Stop,
        for(Start1,Stop,NumOut).

     next(X,X).

Quote:
> Well basically my question is, in Prolog, how is it
> (or it is) possible to have an two demensional array
> m[int][int] and then be able to input numbers into this
> array? i.e in "random" spots

> From my prolog experience I dont think this is possible
> is it?

Of course it is. Although Prolog doesn't have arrays, we can mimic them in a
number of ways:

1. Single elements: cell(Row,Col,Value)
2. Row elements: row(Row,ColumnValues)
3. Whole array: array(Cells)

and variations of these. Which one of these you choose to use will primarily
depend upon how values are to be accessed. Single elements are interesting when
you often need to access single cells, row elements and the whole array when you
often operate on groups of cells.

BTW, there's nothing "random" about calculating an offset.

[snipped]

To display your array you would implement something like this:

    print_array(N):-
        N1 = N - 1,
        for(0,N1,I),  % row
            nl,
            for(0,N1,J),  % column
                retract(cell(I,J,V)),
                justify(V,Spaces),
                write(Spaces), write(V), write(' '),
            next(J,N1),
        next(I,N1).
    print_array(_):-
        nl, nl.

    justify(N,'   '):- N < 10, !.
    justify(N, '  '):- N < 100, !.
    justify(N,  ' '):- N < 1000, !.
    justify(_,   '').

To tie it all together:

    magic_square(N):-
        (0 is N mod 2
         -> fail
         ;  odd_num(N),
            print_array(N)
        ).

And, finally, to run a query:

    | ?- magic_square(11).

Well, that's a solution for magic squares of odd orders out of the way. It
becomes slightly more interesting with even orders.

Daniel



Thu, 15 Aug 2002 03:00:00 GMT  
 Magic Square

[snipped]

Quote:
>     % Add up the numbers.
>     Row_A_total is A1 + A2 + A3,
>     Row_B_total is B1 + B2 + B3,
>     Row_C_total is C1 + C2 + C3,

>     % Fail if the totals are not equal.
>     Row_A_total == Row_B_total,
>     Row_A_total == Row_C_total,
[snipped]
> /* You also need to allow for column totals,
> to make sure they are all identical too.
> So put this code in the program too :

>     Column_1_total is A1 + B1 + C1,
>     Column_2_total is A2 + B2 + C2,
>     Column_3_total is A3 + B3 + C3,
>     Column_1_total == Row_A_total,
>     Column_2_total == Row_A_total,
>     Column_3_total == Row_A_total,

> Then do the diagonals in a similar way.

> Diagonal_1 is A1 + B2 + C3,
> Diagonal_2 is A3 + B2 + C1,
> Diagonal_1 == Row_A_total,
> Diagonal_2 == Row_B_total,

The sum of a row, column and main diagonal must be:

    (N^3 + N) / 2

where N is the magic square's order and ^ is "to the power of".

[snipped]

Quote:
> By the way, you can't learn Prolog from the web!
> I strongly recommend this book as your first book on Prolog :
> "Prolog Programming for Artificcial Intelligence" by Ivan Bratko,
> published by Addison-Wesley, in paperback.

Very good advice and an excellent choice of book (ISBN 0-201-41606-9).

Daniel



Thu, 15 Aug 2002 03:00:00 GMT  
 Magic Square

Quote:

> So simple (in C,Java,etc,etc) but yet so hard (in PROLOG).

I don't agree.

Quote:
> Magic Squares. For those that dont know what one is well here is a
> definition I grabbed off the net:
> "A magic square is an arrangement of the numbers from
> 1 to n^2 (n-squared) in an nxn matrix, with each number
> occurring exactly once, and such that the sum of the
> entries of any row, any column, or any main diagonal is
> the same. It is not hard to show that this
> sum must be n(n^2+1)/2."

This can easily be expressed in clp(FD), ie. a extension availible for
various Prolog-systems that allows you to work with
"constraints over a finite-domain".

In the following I will give a translation of the definition above for
magic-squares of size 3. This code can easily be extended to an
arbitrary problem-size.

magicsquare3(Mss) :-
        magicsquare3_(Mss, Zs),
        labeling([ffc], Zs).

magicsquare3_([[M11,M12,M13],[M21,M22,M23],[M31,M32,M33]], Zs) :-
        Zs = [M11,M12,M13,M21,M22,M23,M31,M32,M33],
        domain(Zs, 1, 9),
        all_different(Zs),
        M11+M12+M13 #= Sum,             % rows
        M21+M22+M23 #= Sum,
        M31+M32+M33 #= Sum,
        M11+M21+M31 #= Sum,             % columns
        M12+M22+M32 #= Sum,
        M13+M23+M33 #= Sum,
        M11+M22+M33 #= Sum,             % diagonals
        M31+M22+M13 #= Sum,
        Sum #= 15.                      

Quote:
> [code omitted]

This will construct ONE solution for the problem, given a problem-size N.

Using Prolog (and clpfd) you can not only generate one solution, but also:
        . check if some given square is a magic square.
        . work with partial instatiation (some parts of the square are
                already known, others are still unknown).
        . "create" all solutions to the problem.

If you want to do the same in C, you would have to implement some
algorithm for constraint-satisfaction search (+ backtracking).

Conclusion:
        . Think about the various relations that can be identified.
          Think of WHAT you want to express.
          Do not think of HOW this should be executed by the computer.
          (Remember: Prolog is a declarative language, not an imperative one)

        . Do NOT try to translate a program from C or another imperative
          language. This will almost always be a waste of time.

        . Do NOT use: fail, assert, retract, write, format, !, functor, arg.
          This list is -- of course -- incomplete...
          Some of these "predicates" require profund knowledge of
          prolog-internals. Others indicate a poor programming-style.

ciao,
Stefan



Thu, 15 Aug 2002 03:00:00 GMT  
 Magic Square

Quote:


> >> void odd_num(int n) {
> >>    int i,j,num=1;
> >>    int nn=n*3/2;
> >>    for(i=0; i < n; i++)
> >>       for(j=0; j < n; j++)
> >>          m[(j-i+nn)%n][(i*2-j+n)%n]=num++;
> >> }

> >You can apply a for-next loop in Prolog too.

> Yes, as the saying goes, real programmers can write fortran in _any_
> language.

> But using assert/1 and failure-driven loops is not a very
> elegant or efficient style for Prolog programming, I believe.
> Using recursion tends to lead to more elegant code, IMHO,
> and avoiding the use of assert/1 often improves efficiency.

On a general level I agree, although IMHO it's a disservice to newcomers to
blindly preach this gospel. To reiterate a statement from one of my recent
postings, a good craftsman maintains and uses the right tools for the work in
hand. I venture to suggest this is one of those cases where use of
failure-driven loops and the internal database can be justified. It provides for
short and highly readable code and it is relatively efficient, although there
are a couple of places that warrant minor improvements. It's also very fast - a
magical square of 21st order is displayed IMMEDIATELY, despite 441 asserts and
retracts (and the handicap of running on the Windows' platform).

- Show quoted text -

Quote:
> So I'd suggest using recursion, and using functor/3 and arg/3 to access
> the array.  Note that in the code that follows, I've kept the variable
> names the same as in the original example, to make it easier to see
> the correspondence.  But I would suggest that using more meaningful
> names (e.g. `Array' rather than `M') would make this code easier to
> understand.

> % mode odd_num(in, out) is det.
> odd_num(N, M) :-
> make_array(N, M),
> NN is N * 3 // 2,
> odd_num_1(N, NN, 0, 1, M).

> % recursive loop over I
> % mode odd_num_1(in, in, in, in, partial -> ground) is det.
> odd_num_1(N, NN, I, Num0, M) :-
> ( I = N ->
> true
> ;
> odd_num_2(N, NN, I, 0, Num0, Num1, M),
> I1 is I + 1,
> odd_num_1(N, NN, I1, Num1, M)
> ).

> % recursive loop over J
> % mode odd_num_2(in, in, in, in, in, out, partial -> ground) is det.
> odd_num_2(N, NN, I, J, Num0, Num, M) :-
> ( J = N ->
> Num = Num0
> ;
> X is (J - I + NN) mod N + 1,
> Y is (I * 2 - J + N) mod N + 1,
> arg(X, M, Vector),
> arg(Y, Vector, Num0),
> Num1 is Num0 + 1,
> J1 is J + 1,
> odd_num_2(N, NN, I, J1, Num1, Num, M)
> ).

> % make_array(N, Array) creates an 2-dimensional NxN array,
> % whose elements are unbound variables.
> % mode make_array(in, out(partial)) is det.
> make_array(N, Array) :-
> functor(Array, array, N),
> make_array_args(1, N, Array).

> % mode make_array_args(in, in, partial -> partial) is det.
> make_array_args(I, N, Array) :-
> ( I > N ->
> true
> ;
> arg(I, Array, Row),
> functor(Row, row, N),
> I1 is I + 1,
> make_array_args(I1, N, Array)
> ).

> Note that I documented the mode and determinism of each procedure
> (using Mercury-style mode declarations, as it happens).
> For production code I would recommend also documenting the data
> representation and the types of each predicate's arguments.

Unfortunately, you have not written a complete program, which would serve as a
comparison. We can, however, note a considerable increase in code volume and
complexity. I therefore have my doubts that a newcomer would benefit from being
served such code; indeed, IMO it's much more likely to scare newcomers away from
Prolog. (Did I hear a "hurra" from the Mozart/Oz camp?)

- Show quoted text -

Quote:
> >> Well basically my question is, in Prolog, how is it
> >> (or it is) possible to have an two demensional array
> >> m[int][int] and then be able to input numbers into this
> >> array? i.e in "random" spots

> >> From my prolog experience I dont think this is possible
> >> is it?

> Yes, you can do this using functor/3 and arg/3, see the code above.
> Note that this only works for cases where you only need write-once,
> but that is indeed all you need for this example.

> >BTW, there's nothing "random" about calculating an offset.

> I think Alex McAskill means "random" in the sense of
> "random access" as opposed to "sequential access".

Mmmm...

[snipped]

Quote:
> >To display your array you would implement something like this:

[snipped]
 > The side-effect there is a rather {*filter*} -- what happens if you

Quote:
> want to display the array twice?

Again, on a general level I agree with you but doubt very much that this is
applicable here. Anyway, there is nothing to stop you retracting the facts
elsewhere, f.ex. on termination of the program, should you so prefer.

Daniel



Fri, 16 Aug 2002 03:00:00 GMT  
 Magic Square

Quote:


>> But using assert/1 and failure-driven loops is not a very
>> elegant or efficient style for Prolog programming, I believe.
>> Using recursion tends to lead to more elegant code, IMHO,
>> and avoiding the use of assert/1 often improves efficiency.
> On a general level I agree, although IMHO it's a disservice to
> newcomers to blindly preach this gospel.

No. IMO, newcomers should be taught the "core parts" of prolog
programming (Recursion, universal termination, declarative
reading of programs, program-development methodology, ...). After
some time they can be confronted with the procedural aspects of
Prolog. (existential termination, procedural reading of programs,
chronological backtracking).

Quote:
> To reiterate a statement from one of my recent postings, a good
> craftsman maintains and uses the right tools for the work in hand.

If you do not need to save information over backtracking, using
"assert/retract" is NOT the right tool. (use a data-structure instead)

Quote:
> I venture to suggest this is one of those cases where
> use of failure-driven loops and the internal database can be
> justified. It provides for short and highly readable code [...]

Code that is purely based on side-effects is a nightmare to debug.
Some code that uses imperative language-features has no declarative
reading; it can only be read procedurally.

Quote:
> and it is relatively efficient ...

I believe you. But this is not a matter of efficiency (since this
algorithm is in P anyway) ...

Quote:
> Again, on a general level I agree with you but doubt very much that
> this is applicable here. Anyway, there is nothing to stop you
> retracting the facts elsewhere, f.ex. on termination of the program,
> should you so prefer.

"cleanup" is another issue when using "assert/retract". How should
one handle code that uses both exceptions AND "assert/retract"?

ciao,
Stefan



Fri, 16 Aug 2002 03:00:00 GMT  
 Magic Square

Quote:


> >> But using assert/1 and failure-driven loops is not a very
> >> elegant or efficient style for Prolog programming, I believe.
> >> Using recursion tends to lead to more elegant code, IMHO,
> >> and avoiding the use of assert/1 often improves efficiency.

> > On a general level I agree, although IMHO it's a disservice to
> > newcomers to blindly preach this gospel.
> No. IMO, newcomers should be taught the "core parts" of prolog
> programming (Recursion, universal termination, declarative
> reading of programs, program-development methodology, ...). After
> some time they can be confronted with the procedural aspects of
> Prolog. (existential termination, procedural reading of programs,
> chronological backtracking).

Oh no, not another person with blinkers/blinders? A person with previous
programming experience in an imperative programming language will quickly find
him/herself "at home" by first reviewing the procedural aspects of the Prolog
language. When this is combined with alternative examples of declarative
programming the advantages of programming "the Prolog way" become transparent.
The result is increased motivation for continued learning.

Quote:
> > To reiterate a statement from one of my recent postings, a good
> > craftsman maintains and uses the right tools for the work in hand.
> If you do not need to save information over backtracking, using
> "assert/retract" is NOT the right tool. (use a data-structure instead)

In this case we did need to save information over backtracking (having chosen to
implement failure-driven for-next loops).

Quote:
> > I venture to suggest this is one of those cases where
> > use of failure-driven loops and the internal database can be
> > justified. It provides for short and highly readable code [...]
> Code that is purely based on side-effects is a nightmare to debug.

Agreed, but hardly applicable in this case.

Quote:
> Some code that uses imperative language-features has no declarative
> reading; it can only be read procedurally.

Is that so bad? Just because one is programming in Prolog doesn't mean that one
shouldn't program procedurally where this may be seen to be appropriate.
Honestly, I don't know whether to laugh or cry at such "tunnel"' ways of
thinking.

Quote:
> > and it is relatively efficient ...
> I believe you. But this is not a matter of efficiency (since this
> algorithm is in P anyway) ...

So what?

Quote:
> > Again, on a general level I agree with you but doubt very much that
> > this is applicable here. Anyway, there is nothing to stop you
> > retracting the facts elsewhere, f.ex. on termination of the program,
> > should you so prefer.
> "cleanup" is another issue when using "assert/retract". How should
> one handle code that uses both exceptions AND "assert/retract"?

Again, hardly applicable in this case. The internal database is merely being
used as a temporary container for "global variables". In the case where the
generated data is to be subsequently used there are many options available. One
could, f.ex., collect and store the data in a balanced binary tree (to
facilitate fast random access), and then program "the Prolog way".

Perhaps it's time to throw your blinkers/blinders away?

Daniel



Fri, 16 Aug 2002 03:00:00 GMT  
 Magic Square


|> Oh no, not another person with blinkers/blinders? A person with previous
|> programming experience in an imperative programming language will quickly find
|> him/herself "at home" by first reviewing the procedural aspects of the Prolog
|> language.

Let me try to see whether I understand this by putting it in a different context ...

A person with previous programming experience in assembly language programming, when
introduced to Pascal, will quickly find him/herself "at home" by first reviewing the
Pascal "goto" statement.

Yeah, sounds very reasonable to me.

Of course, you'll have to spend a lifetime later to explain that goto is considered harmful ...

And when a Brittish person starts to drive in Belgium, why not let him drive on the left
side for a while, so that he feels "at home" at first. Maybe he should also wear
blinkers/blinders at the beginning - just a matter of ignoring better what's going on in the
rest of the world.

Oh, and while we are at it, the preferred way to teach parachute jumping to a benjee jumper,
is of course to tie the parachute to his feet - this way is much more familiar to him !

Cheers

Bart Demoen



Fri, 16 Aug 2002 03:00:00 GMT  
 Magic Square

Quote:


>> No. IMO, newcomers should be taught the "core parts" of prolog.
>> [...] After some time they can be confronted with procedural aspects...
> Oh no, not another person with blinkers/blinders?

Learning a programming language (and a new paradigma) is just like
learning to play guitar. An error made in the early stages of the
learning process can hardly be corrected (or only with huge efforts)
in the later stages.

It is thus evident that the "core parts" MUST be taught/learned first.
You certainly agree with me that the imperative parts are not a
part of the "core" of prolog.

Quote:
> A person with previous programming experience in an imperative
> programming language will quickly find him/herself "at home" by
> first reviewing the procedural aspects of the Prolog language.

People SHOULD not feel "too much at home" until they have really
understood the very basics.

Quote:
> [Procedural aspects] Is that so bad?

No, it is not. But it is only a crutch, not more.
Remember that Prolog was intended to be a way of "programming in logic".

Quote:
> Just because one is programming in Prolog doesn't mean that one
> shouldn't program procedurally where this may be seen to be appropriate.

Estimating that requires a person to understand the basics.

Quote:
> Honestly, I don't know whether to laugh or cry at such "tunnel"' ways ...

If I were you, I'd rather laugh than cry...

Quote:
>> > and it is relatively efficient ...
>> I believe you. But this is not a matter of efficiency ...
> So what?

So "Speed" and "Optimization" is irrelevant.

Quote:
>> "cleanup" is another issue when using "assert/retract". How should
>> one handle code that uses both exceptions AND "assert/retract"?
> Again, hardly applicable in this case.

My statement did not refer to this concrete problem.

Quote:
> The internal database is merely being used as a temporary container
> for "global variables".

Even in an imperative language the use of global variables should be
avoided whenever possible.

Quote:
> Perhaps it's time to throw your blinkers/blinders away?

You call it blinders.  I call it "focussing on the problem".
And -- IMHO -- that is what Prolog is all about.

ciao,
Stefan



Fri, 16 Aug 2002 03:00:00 GMT  
 
 [ 31 post ]  Go to page: [1] [2] [3]

 Relevant Pages 

1. Magic squares for J

2. Magic Squares

3. Help Please! Magic Square

4. Magic Squares

5. Magic Squares

6. f77 magic square code

7. Fill a table (like a magic square)

8. Solving Magic Squares

9. any1 done a magic square in c++ using class

10. Magic square

11. Heuristic search routine for Magic-N Squares puzzle?

12. Icetips Magic Entries & Magic Buttons demo

 

 
Powered by phpBB® Forum Software