Как получить результат из расчета z3py? - PullRequest
0 голосов
/ 23 февраля 2020

Я хочу использовать z3py, чтобы проиллюстрировать следующее генеалогическое упражнение (pa - «родитель», а grpa - «прародитель»)

pa (Роб, Кев) ∧ pa (Роб, Сама) ∧ pa ( Сама, То) Па (Дор, Джим) Па (Бор, Джим) Па (Бор, Эли) Па (Джим, То) Па (Сама, Саму) Па (Джим, Саму) Па (Зел , Макс) ∧ pa (Саму, Макс)

∀X, Y, Z pa (X, Z) ∧ pa (Z, Y) → grpa (X, Y)

Упражнение состоит в том, чтобы определить, для какого значения X есть следующее:

∃X grpa (Rob, X) ∧ pa (X, Max)

(Ответ: для X == Саму .) Я хотел бы переписать эту проблему в z3py, поэтому я ввел новый вид Hum (для «людей») и написал следующее:

import z3

Hum = z3.DeclareSort('Hum')
pa = z3.Function('pa',Hum,Hum,z3.BoolSort())
grpa = z3.Function('grpa',Hum,Hum,z3.BoolSort())
Rob,Kev,Sama,Tho,Dor,Jim,Bor,Eli,Samu,Zel,Max = z3.Consts('Rob Kev Sama Tho Dor Jim Bor Eli Samu Zel Max', Hum)
s=z3.Solver()
for i,j in ((Rob,Kev),(Rob,Sama),(Sama,Tho),(Dor,Jim),(Bor,Jim),(Bor,Eli),(Jim,Tho),(Sama,Samu),(Jim,Samu),(Zel,Max),(Samu,Max)):
    s.add(pa(i,j))
x,y,z=z3.Consts('x y z',Hum)
whi=z3.Const('whi',Hum)
s.add(z3.ForAll([x,y,z],z3.Implies(z3.And(pa(x,z),pa(z,y)),grpa(x,y))))
s.add(z3.Exists(whi,z3.And(grpa(Rob,whi),pa(whi,Max))))

Код принят Python и для

print(s.check())

Я получаю

sat

Теперь я знаю, что есть решение. Проблема в том, как мне получить значение whi?

Когда я спрашиваю print(s.model()[whi]), я получаю None. Когда я спрашиваю s.model().evaluate(whi), я получаю whi, что не очень помогает.

Как я могу получить информацию о том, что whi должно быть Samu, чтобы последняя формула была истинной?

(Дополнительный вопрос: почему нет разницы между константами и переменными? I Я немного озадачен, когда я определяю x,y,z как константы, хотя они являются переменными. Почему я не могу написать x=Hum('x'), чтобы показать, что x является переменной типа Hum?)

1 Ответ

1 голос
/ 23 февраля 2020

Когда вы пишете что-то вроде:

X, Y = Const('X Y', Hum)

Это не означает, что вы объявляете две константы с именами X и Y сорта Hum. (Да, это действительно сбивает с толку! Особенно, если вы исходите из фона, похожего на Пролог!)

Вместо этого все, что это означает, это то, что вы говорите, что есть два объекта X и Y, которые принадлежат к роду Hum. Это даже не означает, что X и Y различны. Они вполне могут быть одинаковыми, если вы явно не укажете это, например:

s.assert(z3.Distinct([X, Y]))

Это также может объяснить вашу путаницу в отношении констант и переменных. В вашей модели все является переменной; вы вообще не объявили никаких констант.

Ваш вопрос о том, почему whi не является Samu, немного сложнее объяснить, но это связано с тем фактом, что все, что у вас есть, это переменные, а не постоянные на всех. Кроме того, whi при использовании в качестве количественной переменной никогда не будет иметь значения в модели: если вы хотите получить значение для переменной, это должна быть объявленная переменная верхнего уровня со своими собственными утверждениями. Обычно это сбивает с толку тех, кто плохо знаком с z3py: когда вы выполняете количественную оценку по переменной, объявление верхнего уровня - это просто уловка, позволяющая просто получить имя в области видимости, оно на самом деле не относится к количественной переменной. Если вы находите, что это сбивает с толку, вы не одиноки: это «хак», который, возможно, в конечном итоге оказался более запутанным, чем полезным для новичков. Если вам интересно, это подробно объясняется здесь: https://theory.stanford.edu/~nikolaj/programmingz3.html#sec -quantifiers-and-lambda-binding Но я бы рекомендовал просто принять это на веру в то, что связанная переменная whi и что вы объявленные на верхнем уровне как whi это просто две разные переменные. Как только вы ознакомитесь с принципами работы z3py, вы сможете изучить детали и причины этого взлома.

Возвращаясь к вашему вопросу моделирования: вы действительно хотите, чтобы эти константы присутствовали в вашей модели. В частности, вы хотите сказать, что это люди в моей вселенной и никто другой, и все они разные. (Вроде как предположение Пролога о замкнутом мире.) Такого рода вещи выполняются с помощью так называемой нумерации в z3py. Вот как я бы go смоделировал вашу проблему:

from z3 import *

# Declare an enumerated sort. In this declaration we create 'Human' to be a sort with
# only the elements as we list them below. They are guaranteed to be distinct, and further
# any element of this sort is guaranteed to be equal to one of these.
Human, (Rob, Kev, Sama, Tho, Dor, Jim, Bor, Eli, Samu, Zel, Max) \
   = EnumSort('Human', ('Rob', 'Kev', 'Sama', 'Tho', 'Dor', 'Jim', 'Bor', 'Eli', 'Samu', 'Zel', 'Max'))

# Uninterpreted functions for parent/grandParent relationship.
parent      = Function('parent',      Human, Human, BoolSort())
grandParent = Function('grandParent', Human, Human, BoolSort())

s = Solver()

# An axiom about the parent and grandParent functions. Note that the variables
# x, y, and z are merely for the quantification reasons. They don't "live" in the
# same space when you see them at the top level or within a ForAll/Exists call.
x, y, z = Consts('x y z', Human)
s.add(ForAll([x, y, z], Implies(And(parent(x, z), parent(z, y)), grandParent(x, y))))

# Express known parenting facts. Note that unlike Prolog, we have to tell z3 that
# these are the only pairs of "parent"s available.
parents = [ (Rob, Kev), (Rob, Sama), (Sama, Tho),  (Dor, Jim)  \
          , (Bor, Jim), (Bor, Eli), (Jim, Tho),  (Sama, Samu)  \
          , (Jim, Samu), (Zel, Max), (Samu, Max)               \
          ]

s.add(ForAll([x, y], Implies(parent(x, y), Or([And(x==i, y == j) for (i, j) in parents]))))

# Find what makes Rob-Max belong to the grandParent relationship:
witness = Const('witness', Human)
s.add(grandParent(Rob, Max))
s.add(grandParent(Rob, witness))
s.add(parent(witness, Max))

# Let's see what witness we have:
print s.check()
m = s.model()
print m[witness]

Для этого z3 говорит:

sat
Samu

, чего, я считаю, вы и добились.

Обратите внимание, что Horn-logi c из z3 может express решить такие проблемы приятнее. Об этом см. Здесь: https://rise4fun.com/Z3/tutorialcontent/fixedpoints. Это расширение, которое поддерживает z3, недоступное в решателях SMT, что делает его более подходящим для задач реляционного программирования.

Сказав это, в то время как действительно возможно express такого рода отношений с использованием SMT решатель, такие проблемы на самом деле не предназначены для решателей SMT. Они гораздо больше подходят для фрагментов логики без количественных показателей, которые включают в себя арифметику c, битовые векторы, массивы, неинтерпретированные функции, числа с плавающей точкой и т. Д. c. Всегда полезно испытывать подобные проблемы в качестве учебного упражнения, но если проблема такого рода - то, что вас действительно волнует, вам следует придерживаться Prolog и его вариантов, которые гораздо больше подходят для такого типа моделирования.

...