Download
# Licenced under CC-BY-4.0 : http://creativecommons.org/licenses/by/4.0/
MAIN MODEL Main_MagicSquare

  DECLARATION SECTION 

    PARAMETER:
       identifier   :  N
       initial data :  4 ;

    PARAMETER:
       identifier   :  N2
       definition   :  N*N ;

    PARAMETER:
       identifier   :  UseSymmetry1
       range        :  binary
       initial data :  0
       comment      :  "To use the constraint Symmetry1 or not." ;

    PARAMETER:
       identifier   :  UseSymmetry2
       range        :  binary
       initial data :  0 ;

    PARAMETER:
       identifier   :  UseSymmetry3
       range        :  binary
       initial data :  0 ;

    PARAMETER:
       identifier   :  UseSymmetry4
       range        :  binary
       initial data :  0 ;

    PARAMETER:
       identifier   :  UseFreeTotal
       range        :  binary
       initial data :  0
       comment      :  "If Total should be = TotalP or calculated." ;

    SET:
       identifier   :  ij
       subset of    :  Integers
       indices      :  i, j
       definition   :  ElementRange(1,N) ;

    VARIABLE:
       identifier   :  x
       index domain :  (i,j)
       range        :  {1..N2} ;

    CONSTRAINT:
       identifier   :  Alldifferent
       definition   :  cp::AllDifferent((i,j), x(i,j)) ;

    VARIABLE:
       identifier   :  Total
       range        :  {0..inf} ;

    VARIABLE:
       identifier   :  NumSolutions
       range        :  integer
       definition   :  GMP::Solution::Count('MagicSquarePlan') ;

    PARAMETER:
       identifier   :  TotalP
       definition   :   ( N * (N*N + 1)) / 2 ;

    CONSTRAINT:
       identifier   :  EqTotals
       definition   :  if (not UseFreeTotal) then
                         Total = TotalP
                       endif ;

    CONSTRAINT:
       identifier   :  Sum1
       index domain :  i
       definition   :  Sum(j, x(i,j)) = Total ;

    CONSTRAINT:
       identifier   :  Sum2
       index domain :  (j)
       definition   :  Sum(i, x(i,j)) = Total ;

    CONSTRAINT:
       identifier   :  SumDiagonal1
       definition   :  Sum(i, x(i,i)) = Total ;

    CONSTRAINT:
       identifier   :  SumDiagonal2
       definition   :  Sum(i, x(i,N-i-1)) = Total ;

    CONSTRAINT:
       identifier   :  Symmetry1
       definition   :  if (UseSymmetry1) then
                          x(1,1) = 1
                       endif ;

    CONSTRAINT:
       identifier   :  Symmetry2
       definition   :  if (UseSymmetry2) then
                          x(1,1) < x(1,N)
                       endif ;

    CONSTRAINT:
       identifier   :  Symmetry3
       definition   :  if (UseSymmetry3) then
                         x(1,N) < x(N,1)
                       endif ;

    CONSTRAINT:
       identifier   :  Symmetry4
       definition   :  if (UseSymmetry4) then
                         x(1,1) < x(N,N)
                       endif ;

    MATHEMATICAL PROGRAM:
       identifier   :  MagicSquarePlan
       direction    :  minimize
       constraints  :  AllConstraints
       variables    :  AllVariables
       type         :  CSP ;

  ENDSECTION  ;

  PROCEDURE
    identifier :  MainInitialization

  ENDPROCEDURE  ;

  PROCEDURE
    identifier :  MainExecution
    body       :  
      ShowProgressWindow;
      solve MagicSquarePlan;
      NumSolutions:=GMP::Solution::Count('MagicSquarePlan');
      if (MagicSquarePlan.ProgramStatus <> 'Optimal') then
           empty x, Total;
      endif;
      
      DialogMessage(NumSolutions + " solutions");

  ENDPROCEDURE  ;

  PROCEDURE
    identifier :  MainTermination
    body       :  
      if ( CaseSaveAll( confirm:2 ) = 1 ) then
          return 1;
      else
          return 0;
      endif ;

  ENDPROCEDURE  ;

ENDMODEL Main_MagicSquare ;