So Im working with magic squares. I've created conditions for a regular magic square. Now I need to add the constraints to make it associative.
I'm using the z3 python module. To be associative, the sum of the opposite numbers need to be equal to the same number 't'. the sum of all the rows and columns and diagonals need to be equal to this number t as well. So I'm struggling with accessing the numbers individually from each list in the list of lists.
For example, these are the constraints I have for a regular magic square:
t = Int('t')
Square = [ [ Int("x_%s_%s" % (i+1, j+1)) for j in range(n) ] for i in range(n) ]
distinct = [ Distinct([ Square[i][j] for i in range(n) for j in range(n) ]) ]
cell = [ And(1 <= Square[i][j], Square[i][j] <= n**2) for i in range(n) for j in range(n) ]
row = [(sum(Square[i]) == t) for i in range(n)]
col = [(sum([Square[j][i] for j in range(n)]) == t) for i in range(n)]
firstDiagonal = [ (sum([Square[i][i] for i in range(n)]) == t) ]
secondDiagonal = [ (sum([Square[n-i-1][i] for i in range(n)]) == t) ]
So how do I associative conditions?
I amended your model and added associative constraints:
from z3 import *
def ShowSquare(model, square, rows, cols):
print()
print("Square")
for row in range(rows):
s = ""
for col in range(cols):
s = s + str(model.eval(square[row][col])).ljust(4)
print(s)
s = Solver()
n = 3
t = Int('t')
magicSquare = [ [ Int("x_%s_%s" % (i+1, j+1)) for j in range(n) ] for i in range(n) ]
distinctConstraints = [ Distinct([ magicSquare[i][j] for i in range(n) for j in range(n) ]) ]
cellConstraints = [ And(1 <= magicSquare[i][j], magicSquare[i][j] <= n**2) for i in range(n) for j in range(n) ]
rowConstraints = [(sum(magicSquare[i]) == t) for i in range(n)]
colConstraints = [(sum([magicSquare[j][i] for j in range(n)]) == t) for i in range(n)]
firstDiagConstraints = [ (sum([magicSquare[i][i] for i in range(n)]) == t) ]
secondDiagConstraints = [ (sum([magicSquare[n-i-1][i] for i in range(n)]) == t) ]
AssocSum = Int('AssocSum')
assocRowConstraints = [((magicSquare[0][i] + magicSquare[n-1][n-i-1]) == AssocSum) for i in range(n) ]
assocColConstraints = [((magicSquare[i][0] + magicSquare[n-i-1][n-1]) == AssocSum) for i in range(1, n-1) ]
# performance tweak
# the magic sum is known in advance
s.add(2*t == n*(n*n+1))
s.add(distinctConstraints)
s.add(cellConstraints)
s.add(rowConstraints)
s.add(colConstraints)
s.add(firstDiagConstraints)
s.add(secondDiagConstraints)
s.add(assocRowConstraints)
s.add(assocColConstraints)
print(s.check())
model = s.model()
print("magic sum %s" % model.eval(t))
print("assoc sum %s" % model.eval(AssocSum))
ShowSquare(model, magicSquare, n, n)
The result is a transposed version of the Lo Shu Square linked in the question:
sat
magic sum 15
assoc sum 10
Square
4 3 8
9 5 1
2 7 6
For n=5
, a solution is:
magic sum 65
assoc sum 26
Square
8 7 12 15 23
17 20 22 1 5
16 2 13 24 10
21 25 4 6 9
3 11 14 19 18