• 1000 1007 *
Однако, если я добавлю s.add (ans6 == 4), а также s.add (ans9 == 3) piror к s.pu sh (), модель будет правильной как unsat.
Это ошибка или я неправильно использую Z3? Я думал, что это может быть выражено мягкими ограничениями, но в документации не упоминается.
полный исходный код выглядит следующим образом:
#!/usr/bin/env python
# coding: utf-8
from z3 import *
# ten multiple choices
ans = [Int('ans%d' % (i)) for i in range(10)]
letters = {}
for i in range(5):
letters[i] = "0ABCD"[i]
choice_a = 1
choice_b = 2
choice_c = 3
choice_d = 4
choice_shitty = 999
choices = [choice_a, choice_b, choice_c, choice_d]
s = Solver()
for i in range(10):
s.add(Or(ans[i] == choice_a, ans[i] == choice_b, ans[i] == choice_c, ans[i] == choice_d))
#2
s.add(Or(And(ans[1] == choice_a, ans[4] == choice_c),
And(ans[1] == choice_b, ans[4] == choice_d),
And(ans[1] == choice_c, ans[4] == choice_a),
And(ans[1] == choice_d, ans[4] == choice_b)))
#3
s.add(Or(And(ans[2] == choice_a, And(ans[2] != ans[5], ans[5] == ans[1], ans[1] == ans[3])),
And(ans[2] == choice_b, And(ans[5] != ans[2], ans[2] == ans[1], ans[1] == ans[3])),
And(ans[2] == choice_c, And(ans[1] != ans[2], ans[2] == ans[5], ans[5] == ans[3])),
And(ans[2] == choice_d, And(ans[3] != ans[5], ans[2] == ans[5], ans[5] == ans[1]))))
#4
s.add(Or(And(ans[3] == choice_a, ans[0] == ans[4]),
And(ans[3] == choice_b, ans[1] == ans[6]),
And(ans[3] == choice_c, ans[0] == ans[8]),
And(ans[3] == choice_d, ans[5] == ans[9])))
#5
s.add(Or(And(ans[4] == choice_a, ans[4] == ans[7]),
And(ans[4] == choice_b, ans[4] == ans[3]),
And(ans[4] == choice_c, ans[4] == ans[8]),
And(ans[4] == choice_d, ans[4] == ans[6])))
#6
s.add(Or(And(ans[5] == choice_a, And(ans[1] == ans[3], ans[3] == ans[7])),
And(ans[5] == choice_b, And(ans[0] == ans[5], ans[5] == ans[7])),
And(ans[5] == choice_c, And(ans[2] == ans[9], ans[9] == ans[7])),
And(ans[5] == choice_d, And(ans[4] == ans[8], ans[8] == ans[7]))))
#7
#8
s.add(Or(And(ans[7] == choice_a, Not(Or(ans[0] - ans[6] == 1, ans[0] - ans[6] == -1))),
And(ans[7] == choice_b, Not(Or(ans[0] - ans[4] == 1, ans[0] - ans[4] == -1))),
And(ans[7] == choice_c, Not(Or(ans[0] - ans[1] == 1, ans[0] - ans[1] == -1))),
And(ans[7] == choice_d, Not(Or(ans[0] - ans[9] == 1, ans[0] - ans[9] == -1)))))
#9
s.add(Or(And(ans[8] == choice_a, Or(And((ans[0] == ans[5]), Not(ans[5] == ans[4])),
And(Not(ans[0] == ans[5]), (ans[5] == ans[4])))),
And(ans[8] == choice_b, Or(And((ans[0] == ans[5]), Not(ans[9] == ans[4])),
And(Not(ans[0] == ans[5]), (ans[9] == ans[4])))),
And(ans[8] == choice_c, Or(And((ans[0] == ans[5]), Not(ans[1] == ans[4])),
And(Not(ans[0] == ans[5]), (ans[1] == ans[4])))),
And(ans[8] == choice_d, Or(And((ans[0] == ans[5]), Not(ans[8] == ans[4]))),
And(Not(ans[0] == ans[5]), (ans[8] == ans[4])))))
#10
# max - min count
#for c in s.assertions():
# print (c)
#s.check()
#print (s.model())
#s.add(ans[6] == 4)
#s.add(ans[9] == 3)
result = []
while True:
if s.check() == unsat:
print ("no solution or search done(?)")
print ("RESULT FOUND = ", len(result))
break
elif s.check() == sat:
m = s.model()
#print (m)
# prevent next model from using the SAME assignment as a previous model
block = []
for cond in m:
clause = cond()
block.append(clause != m[cond])
#print(block)
# special case: #7和#10
s.push()
cnt = {}
for c in choices:
cnt[c] = sum([1 for a in ans if m[a] == c])
mincnt_choice = min(cnt, key=cnt.get)
maxcnt_choice = max(cnt, key=cnt.get)
mincnt = cnt[mincnt_choice]
maxcnt = cnt[maxcnt_choice]
diff = maxcnt - mincnt
print ('ANSWER LETTER COUNTS: ', cnt, 'MIN: ', letters[mincnt_choice], 'MAX: ', letters[maxcnt_choice])
print ('DIFF for #10:', diff)
#7
if mincnt_choice == choice_a:
s.add(ans[6] == choice_c)
elif mincnt_choice == choice_b:
s.add(ans[6] == choice_b)
elif mincnt_choice == choice_c:
s.add(ans[6] == choice_a)
elif mincnt_choice == choice_d:
s.add(ans[6] == choice_d)
else:
# impossible
s.add(ans[6] == choice_shitty)
#10
if diff == 3:
s.add(ans[9] == choice_a)
elif diff == 2:
s.add(ans[9] == choice_b)
elif diff == 4:
s.add(ans[9] == choice_c)
elif diff == 1:
s.add(ans[9] == choice_d)
else:
# impossible
s.add(ans[9] == choice_shitty)
for c in s.assertions():
print (c)
if s.check() == unsat:
print ("#7/#10 constraint failed\n")
s.pop()
s.add(Or(block))
elif s.check() == sat:
print ('SOLUTION: -------------------\n')
print (m)
#for i in range(10):
# sys.stdout.write (str(i+1)+". "+letters[int(str(m[ans[i]]))]+"\n")
#print ("\n")
result.append(m)
# prevent next model from using the SAME assignment as a previous model
block = []
for cond in m:
clause = cond()
block.append(clause != m[cond])
s.pop()
s.add(Or(block))
else:
print ("exception")
else:
print ("exception")