Initializing help system before first use

Euler knight tour problem


Type: Euler knight tour
Rating: 3 (intermediate)
Description: Euler knight tour problem:
  • 'all-different' and generic binary constraints; branching strategy for variables (eulerkn.mos).
  • Alternative implementation using subtour elimination constraints with 'implies' (eulerkn2.mos).
  • Third model formulation using a 'cycle' constraint in its simplest form (eulerkn3.mos) or with successor and predecessor variables (eulerkn3b.mos).
File(s): eulerkn.mos, eulerkn2.mos, eulerkn2_graph.mos, eulerkn3.mos, eulerkn3b.mos


eulerkn.mos
(!****************************************************************
   CP example problems
   ===================
   
   file eulerkn.mos
   ````````````````
   Euler knight problem.
   Finding a tour on a chess-board for a knight figure, 
   such that the knight moves through every cell exactly 
   once and returns to its origin.

   Model formulation for 8x8 chessboard:
   We number the cells of the chessboard from 0 to 63 (64 cells)
   
      A  B  C  D  E  F  G  H
     +--+--+--+--+--+--+--+--+
   8 |0 |1 |2 |3 |4 |5 |6 |7 |
     +--+--+--+--+--+--+--+--+
   7 |8 |9 |10|11|12|13|14|15|
     +--+--+--+--+--+--+--+--+
   6 |16|17|18|19|20|21|22|23|
     +--+--+--+--+--+--+--+--+
   5 |24|25|26|27|28|29|30|31|
     +--+--+--+--+--+--+--+--+
   4 |32|33|34|35|36|37|38|39|
     +--+--+--+--+--+--+--+--+
   3 |40|41|42|43|44|45|46|47|
     +--+--+--+--+--+--+--+--+
   2 |48|49|50|51|52|53|54|55|
     +--+--+--+--+--+--+--+--+
   1 |56|57|58|59|60|61|62|63|
     +--+--+--+--+--+--+--+--+
  
   The path that the knight will follow is represented by 64 variables "pos" 
   that can take values from 0 to 63.
   For example, pos[12] = 45 means that the 12th cell visited by the knight 
   is the cell F:3
  
   Constraint 1: each cell is visited only once.
   ---------------------------------------------
   We simply post an all_different constraint on all the path variables
  
   Constraint 2: the path of the knight must follow the chess rules.
   -----------------------------------------------------------------
  
   The knight (Kn) can move to the crossed cells (xx):
   
   +--+--+--+--+--+
   |  |xx|  |xx|  |
   +--+--+--+--+--+
   |xx|  |  |  |xx|
   +--+--+--+--+--+
   |  |  |Kn|  |  |
   +--+--+--+--+--+
   |xx|  |  |  |xx|
   +--+--+--+--+--+
   |  |xx|  |xx|  |
   +--+--+--+--+--+
  
   If the knight is in the cell numbered c, it is authorized to move to the 
   following cells:
    c + 1 - 16  [One cell right, two cells up  ]
    c - 1 - 16  [One cell left, two cells up   ]
    c + 1 + 16  [One cell right, two cells down]
    c - 1 + 16  [One cell left, two cells down ]
    c + 2 - 8   [Two cells right, one cell up  ]
    c - 2 - 8   [Two cells left, one cell up   ]
    c + 2 + 8   [Two cells right, one cell down]
    c - 2 + 8   [Two cells left, one cell down ]
  
   This constraint is represented by a generalized binary constraint,
   the function valid_knight_move defined in the model provides the 
   evaluation for pairs of values.

   *** This model cannot be run with a Community Licence 
       for the default data instance ***

   (c) 2008 Artelys S.A. and Fair Isaac Corporation
       Creation: 2005, rev. Sep 2018       
*****************************************************************!)

model "Euler Knight Moves"
 uses "kalis"

 parameters
  S = 8                                   ! Number of rows/columns
  NBSOL = 1                               ! Number of solutions sought 
 end-parameters
 
 forward procedure print_solution(sol: integer)
 forward public function valid_knight_move(a:integer, b:integer): boolean

 N:= S * S                                ! Total number of cells
 setparam("KALIS_DEFAULT_LB", 0)
 setparam("KALIS_DEFAULT_UB", N-1)

 declarations
  PATH = 1..N                            ! Cells on the chessboard
  pos: array(PATH) of cpvar              ! Cell at position p in the tour
 end-declarations

! Fix the start position
 pos(1) = 0

! Each cell is visited once
 all_different(pos, KALIS_GEN_ARC_CONSISTENCY)

! The path of the knight obeys the chess rules for valid knight moves
 forall(i in 1..N-1)
  generic_binary_constraint(pos(i), pos(i+1), "valid_knight_move")
 generic_binary_constraint(pos(N), pos(1), "valid_knight_move")

! Setting enumeration parameters
 cp_set_branching(probe_assign_var(KALIS_SMALLEST_MIN, KALIS_MAX_TO_MIN,
                                   pos, 14))

! Search for up to NBSOL solutions
 solct:= 0
 while (solct<NBSOL and cp_find_next_sol) do
  solct+=1
  cp_show_stats
  print_solution(solct)
 end-do


! **** Test whether the move from position a to b is admissible ****
 public function valid_knight_move(a:integer, b:integer): boolean
  declarations
   xa,ya,xb,yb,delta_x,delta_y: integer
  end-declarations

  xa := a div S
  ya := a mod S
  xb := b div S
  yb := b mod S
  delta_x := abs(xa-xb)
  delta_y := abs(ya-yb)
  returned := (delta_x<=2) and (delta_y<=2) and (delta_x+delta_y=3)
 end-function

!****************************************************************
! Solution printing
 procedure print_solution(sol: integer)
  writeln("Solution ", sol, ":")
  forall(i in PATH)
   write(getval(pos(i)), if(i mod 10 = 0, "\n ", ""), " -> ")
  writeln("0")
 end-procedure

end-model

eulerkn2.mos
(!****************************************************************
   CP example problems
   ===================
   
   file eulerkn2.mos
   `````````````````
   Euler knight problem.
   Finding a tour on a chess-board for a knight figure, 
   such that the knight moves through every cell exactly 
   once and returns to its origin.
   - Alternative implementation using subtour elimination -

   *** This model cannot be run with a Community Licence 
       for the default data instance ***

   (c) 2008 Artelys S.A. and Fair Isaac Corporation
       Creation: 2005, rev. Mar. 2013       
*****************************************************************!)

model "Euler Knight Moves"
 uses "kalis"

 parameters
  S = 8                                   ! Number of rows/columns
  NBSOL = 1                               ! Number of solutions sought 
 end-parameters
 
 forward procedure calculate_successors(p: integer)
 forward procedure print_solution(sol: integer)

 N:= S * S                                ! Total number of cells
 setparam("KALIS_DEFAULT_LB", 0)
 setparam("KALIS_DEFAULT_UB", N)

 declarations
  PATH = 0..N-1                           ! Cells on the chessboard
  succ: array(PATH) of cpvar              ! Successor of cell p
  y: array(PATH) of cpvar                 ! Position of p in the tour
 end-declarations

 forall(p in PATH) y(p) >= 1

! Calculate set of possible successors
 forall(p in PATH) calculate_successors(p)

! Each cell is visited once
 all_different(succ, KALIS_GEN_ARC_CONSISTENCY)

! Exclude subtours
 forall(p in PATH, q in 1..N-1 | p<>q) 
  implies(succ(p) = q, y(q) = y(p) + 1)

! Search for up to NBSOL solutions
 solct:= 0
 while (solct<NBSOL and cp_find_next_sol) do
  solct+=1
  cp_show_stats
  print_solution(solct)
 end-do


! **** Calculate possible successors ****
 procedure calculate_successors(p: integer)
  declarations
   SuccSet: set of integer                ! Set of successors
  end-declarations

  xp := p div S
  yp := p mod S
    
  forall(q in PATH) do
   xq := q div S
   yq := q mod S
   delta_x := abs(xp-xq)
   delta_y := abs(yp-yq)  
   if (delta_x<=2) and (delta_y<=2) and (delta_x+delta_y=3) then
    SuccSet +={q}
   end-if
  end-do
 
  setdomain(succ(p), SuccSet)
 end-procedure

!****************************************************************
! **** Solution printing ****
 procedure print_solution(sol: integer)
  writeln("Solution ", sol, ":")
  thispos:=0
  nextpos:=getval(succ(0))
  ct:=1
  while (nextpos<>0) do
   write(thispos, if(ct mod 10 = 0, "\n ", ""), " -> ") 
   val:=getval(succ(thispos))
   thispos:=nextpos
   nextpos:=getval(succ(thispos))
   ct+=1
  end-do
  writeln("0")
 end-procedure

end-model

eulerkn2_graph.mos
(!****************************************************************
   CP example problems
   ===================
   
   file eulerkn2_graph.mos
   ```````````````````````
   Euler knight problem.
   Finding a tour on a chess-board for a knight figure, 
   such that the knight moves through every cell exactly 
   once and returns to its origin.
   - Alternative implementation using subtour elimination -
   - Graphical solution representation -

   *** This model cannot be run with a Community Licence 
       for the default data instance ***

   (c) 2008 Artelys S.A. and Fair Isaac Corporation
       Creation: 2005, rev. Sep. 2017       
*****************************************************************!)

model "Euler Knight Moves"
 uses "kalis", "mmsvg"

 parameters
  S = 8                                   ! Number of rows/columns
  NBSOL = 5                               ! Number of solutions sought 
 end-parameters
 
 forward procedure calculate_successors(p: integer)
 forward procedure print_solution(sol: integer)
 forward procedure draw_solution(sol: integer)

 N:= S * S                                ! Total number of cells
 setparam("KALIS_DEFAULT_LB", 0)
 setparam("KALIS_DEFAULT_UB", N)

 declarations
  PATH = 0..N-1                           ! Cells on the chessboard
  succ: array(PATH) of cpvar              ! Successor of cell p
  y: array(PATH) of cpvar                 ! Position of p in the tour
 end-declarations

 forall(p in PATH) y(p) >= 1

! Calculate set of possible successors
 forall(p in PATH) calculate_successors(p)

! Each cell is visited once
 all_different(succ, KALIS_GEN_ARC_CONSISTENCY)

! Exclude subtours
 forall(p in PATH, q in 1..N-1 | p<>q) 
  implies(succ(p) = q, y(q) = y(p) + 1)

! Search for up to NBSOL solutions
 solct:= 0; svgrefresh
 while (solct<NBSOL and not svgclosing and cp_find_next_sol) do
  solct+=1
  cp_show_stats
  print_solution(solct)
  draw_solution(solct)
 end-do

 svgwaitclose("Close browser window to terminate model execution.", 1)

! **** Calculate possible successors ****
 procedure calculate_successors(p: integer)
  declarations
   SuccSet: set of integer                ! Set of successors
  end-declarations

  xp := p div S
  yp := p mod S
    
  forall(q in PATH) do
   xq := q div S
   yq := q mod S
   delta_x := abs(xp-xq)
   delta_y := abs(yp-yq)  
   if (delta_x<=2) and (delta_y<=2) and (delta_x+delta_y=3) then
    SuccSet +={q}
   end-if
  end-do
 
  setdomain(succ(p), SuccSet)
 end-procedure

!****************************************************************
! **** Solution printing ****
 procedure print_solution(sol: integer)
  writeln("Solution ", sol, ":")
  thispos:=0
  nextpos:=getval(succ(0))
  ct:=1
  while (nextpos<>0) do
   write(thispos, if(ct mod 10 = 0, "\n ", ""), " -> ") 
   val:=getval(succ(thispos))
   thispos:=nextpos
   nextpos:=getval(succ(thispos))
   ct+=1
  end-do
  writeln("0")
 end-procedure
 
! **** Solution drawing ****
 procedure draw_solution(sol: integer)
  svgerase                       ! Clean up previous solution
  
  ! Draw the board
  svgaddgroup("B", "Board")
  forall(i in 1..S+1) svgaddline(i-0.5, 0.5, i-0.5, S+0.5)
  forall(i in 1..S+1) svgaddline(0.5, i-0.5, S+0.5, i-0.5)
  
  ! Draw the knight's tour
  svgaddgroup("Sol", "Knight tour", SVG_ORANGE)  
  svgsetstyle(SVG_STROKEWIDTH,2)
  thispos:=0
  nextpos:=getval(succ(0))
  while (nextpos<>0) do
   svgaddarrow(1+ thispos div S, 1+ thispos mod S,
               1+ nextpos div S, 1+ nextpos mod S)
   val:=getval(succ(thispos))
   thispos:=nextpos
   nextpos:=getval(succ(thispos))
  end-do

  svgsetgraphscale(50)

  svgsave("eulerkn.svg")
  svgrefresh
 ! Uncomment to pause at every iteration to view the solution:         
  if sol<NBSOL then svgpause; end-if

 end-procedure

end-model

eulerkn3.mos
(!****************************************************************
   CP example problems
   ===================
   
   file eulerkn3.mos
   `````````````````
   Euler knight problem.
   Finding a tour on a chess-board for a knight figure, 
   such that the knight moves through every cell exactly 
   once and returns to its origin.
   - Alternative implementation using a 'cycle' constraint -

   *** This model cannot be run with a Community Licence 
       for the default data instance ***

   (c) 2008 Artelys S.A. and Fair Isaac Corporation
       Creation: 2007, rev. Mar. 2013       
*****************************************************************!)

model "Euler Knight Moves"
 uses "kalis"

 parameters
  S = 8                                   ! Number of rows/columns
  NBSOL = 1                               ! Number of solutions sought 
 end-parameters
 
 forward procedure calculate_successors(p: integer)
 forward procedure print_solution(sol: integer)

 N:= S * S                                ! Total number of cells
 setparam("KALIS_DEFAULT_LB", 0)
 setparam("KALIS_DEFAULT_UB", N)

 declarations
  PATH = 0..N-1                           ! Cells on the chessboard
  succ: array(PATH) of cpvar              ! Successor of cell p
 end-declarations

! Calculate set of possible successors
 forall(p in PATH) calculate_successors(p)

! Each cell is visited once, no subtours
 cycle(succ)

! Search for up to NBSOL solutions
 solct:= 0
 while (solct<NBSOL and cp_find_next_sol) do
  solct+=1
  cp_show_stats
  print_solution(solct)
 end-do


! **** Calculate possible successors ****
 procedure calculate_successors(p: integer)
  declarations
   SuccSet: set of integer                ! Set of successors
  end-declarations

  xp := p div S
  yp := p mod S
    
  forall(q in PATH) do
   xq := q div S
   yq := q mod S
   delta_x := abs(xp-xq)
   delta_y := abs(yp-yq)  
   if (delta_x<=2) and (delta_y<=2) and (delta_x+delta_y=3) then
    SuccSet +={q}
   end-if
  end-do
 
  setdomain(succ(p), SuccSet)
 end-procedure

!****************************************************************
! **** Solution printing ****
 procedure print_solution(sol: integer)
  writeln("Solution ", sol, ":")
  thispos:=0
  nextpos:=getval(succ(0))
  ct:=1
  while (nextpos<>0) do
   write(thispos, if(ct mod 10 = 0, "\n ", ""), " -> ") 
   val:=getval(succ(thispos))
   thispos:=nextpos
   nextpos:=getval(succ(thispos))
   ct+=1
  end-do
  writeln("0")
 end-procedure

end-model

eulerkn3b.mos
(!****************************************************************
   CP example problems
   ===================
   
   file eulerkn3b.mos
   ``````````````````
   Euler knight problem.
   Finding a tour on a chess-board for a knight figure, 
   such that the knight moves through every cell exactly 
   once and returns to its origin.
   - Alternative implementation using a 'cycle' constraint 
     with successor and predecessor variables -

   *** This model cannot be run with a Community Licence 
       for the default data instance ***

   (c) 2008 Artelys S.A. and Fair Isaac Corporation
       Creation: 2007, rev. Mar. 2013       
*****************************************************************!)

model "Euler Knight Moves"
 uses "kalis"

 parameters
  S = 8                                   ! Number of rows/columns
  NBSOL = 1                               ! Number of solutions sought 
 end-parameters
 
 forward procedure calculate_successors(p: integer)
 forward procedure print_solution(sol: integer)

 N:= S * S                                ! Total number of cells
 setparam("KALIS_DEFAULT_LB", 0)
 setparam("KALIS_DEFAULT_UB", N)

 declarations
  PATH = 0..N-1                           ! Cells on the chessboard
  succ: array(PATH) of cpvar              ! Successor of cell p
  pred: array(PATH) of cpvar              ! Predecessor of cell p
  predsucc: cpvarlist
 end-declarations

! Calculate set of possible successors
 forall(p in PATH) calculate_successors(p)

! Each cell is visited once, no subtours
 cycle(succ, pred)

! Branching strategy
 forall(p in PATH) do 
  predsucc += succ(p)
  predsucc += pred(p)
 end-do
 cp_set_branching(assign_var(KALIS_SMALLEST_DOMAIN,KALIS_MIN_TO_MAX,predsucc))

! Search for up to NBSOL solutions
 solct:= 0
 while (solct<NBSOL and cp_find_next_sol) do
  solct+=1
  cp_show_stats
  print_solution(solct)
 end-do


! **** Calculate possible successors ****
 procedure calculate_successors(p: integer)
  declarations
   SuccSet: set of integer                ! Set of successors
  end-declarations

  xp := p div S
  yp := p mod S
    
  forall(q in PATH) do
   xq := q div S
   yq := q mod S
   delta_x := abs(xp-xq)
   delta_y := abs(yp-yq)  
   if (delta_x<=2) and (delta_y<=2) and (delta_x+delta_y=3) then
    SuccSet +={q}
   end-if
  end-do
 
  setdomain(succ(p), SuccSet)
  setdomain(pred(p), SuccSet)
 end-procedure

!****************************************************************
! **** Solution printing ****
 procedure print_solution(sol: integer)
  writeln("Solution ", sol, ":")
  thispos:=0
  nextpos:=getval(succ(0))
  ct:=1
  while (nextpos<>0) do
   write(thispos, if(ct mod 10 = 0, "\n ", ""), " -> ") 
   val:=getval(succ(thispos))
   thispos:=nextpos
   nextpos:=getval(succ(thispos))
   ct+=1
  end-do
  writeln("0")
 end-procedure

end-model

© 2001-2020 Fair Isaac Corporation. All rights reserved. This documentation is the property of Fair Isaac Corporation (“FICO”). Receipt or possession of this documentation does not convey rights to disclose, reproduce, make derivative works, use, or allow others to use it except solely for internal evaluation purposes to determine whether to purchase a license to the software described in this documentation, or as otherwise set forth in a written software license agreement between you and FICO (or a FICO affiliate). Use of this documentation and the software described in it must conform strictly to the foregoing permitted uses, and no other use is permitted.