Explanation of conversion of CNF to imperative normal form in 2-SAT problem? - algorithm

so this question might seem dumb to many of you but I'm finding it somewhat hard to grasp the conversion of a CNF clause to INF one.
I was going through this article where it states:
First we need to convert the problem to a different form, the so-called implicative normal form. Note that the expression a∨b is equivalent to ¬a⇒b∧¬b⇒a (if one of the two variables is false, then the other one must be true).
Can somebody explain how do we get to this result/how does this conversion makes sense? I've no idea what that " => " sign means, either. Thanks in advance!
Update 1: If in doubt with different logical symbols, refer to this wiki.

=> is implication, with the truth table:
A B | A => B
----+-------
F F | T
F T | T
T F | F
T T | T
In fact, you can show that a => b is equivalent to ~a \/ b. (Just fill out the truth tables.)
Now, we have:
~a => b
= ~(~a) \/ b
= a \/ b
So, it's even stronger: a \/ b is equivalent to ~a => b. You can similarly show it is also equivalent to ~b => a; so taking the conjunction is redundant perhaps, but it doesn't change the equivalence.
If in doubt, always draw the full truth tables, assuming you have 4-5 variables it would be very educational. If you have more variables, use a SAT/SMT solver to prove equivalence. That's what they are good for.

Related

How to get result from z3py calculation?

I want to use z3py to illustrate the following genealogy exercise (pa is “parent” and grpa is “grand-parent)
pa(Rob,Kev) ∧ pa(Rob,Sama) ∧ pa(Sama,Tho) ∧ pa(Dor,Jim) ∧ pa(Bor,Jim) ∧ pa(Bor,Eli) ∧ pa(Jim,Tho) ∧ pa(Sama,Samu) ∧ pa(Jim,Samu) ∧ pa(Zel,Max) ∧ pa(Samu,Max)
∀X,Y,Z pa(X,Z) ∧ pa(Z,Y) → grpa(X,Y)
The exercise consists in finding for which value of X one has the following:
∃X grpa(Rob,X) ∧ pa(X,Max)
(The answer being: for X == Samu.) I would like to rewrite this problem in z3py, so I introduce a new sort Hum (for “humans”) and write the following:
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))))
The code is accepted by Python and for
print(s.check())
I get
sat
Now I know there is a solution. The problem is: how do I get the value of whi?
When I ask for print(s.model()[whi]) I get None. When I ask for s.model().evaluate(whi) I get whi, which is not very helpful.
How can I get the information that whi must be Samu for the last formula to be true?
(Auxiliary question: why is there no difference between constants and variables? I'm a bit puzzled when I define x,y,z as constants although they are variable.
Why can I not write x=Hum('x') to show that x is a variable of sort Hum?)
When you write something like:
X, Y = Const('X Y', Hum)
It does not mean that you are declaring two constants named X and Y of sort Hum. (Yes, this is indeed confusing! Especially if you're coming from a Prolog like background!)
Instead, all it means is that you are saying there are two objects X and Y, which belong to the sort Hum. It does not even mean X and Y are different. They might very well be the same, unless you explicitly state it, like this:
s.assert(z3.Distinct([X, Y]))
This might also explain your confusion regarding constants and variables. In your model, everything is a variable; you haven't declared any constants at all.
Your question about how come whi is not Samu is a little trickier to explain, but it stems from the fact that all you have are variables and no constants at all. Furthermore, whi when used as a quantified variable will never have a value in the model: If you want a value for a variable, it has to be a top-level declared variable with its own assertions. This usually trips people who are new to z3py: When you do quantification over a variable, the top-level declaration is a mere trick just to get a name in the scope, it does not actually relate to the quantified variable. If you find this to be confusing, you're not alone: It's a "hack" that perhaps ended up being more confusing than helpful to newcomers. If you're interested, this is explained in detail here: https://theory.stanford.edu/~nikolaj/programmingz3.html#sec-quantifiers-and-lambda-binding But I'd recommend just taking it on faith that the bound variable whi and what you declared at the top level as whi are just two different variables. Once you get more familiar with how z3py works, you can look into the details and reasons behind this hack.
Coming back to your modeling question: You really want these constants to be present in your model. In particular, you want to say these are the humans in my universe and nobody else, and they are all distinct. (Kind of like Prolog's closed world assumption.) This sort of thing is done with a so-called enumeration sort in z3py. Here's how I would go about modeling your problem:
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]
For this, z3 says:
sat
Samu
which I believe is what you were trying to achieve.
Note that the Horn-logic of z3 can express such problems in a nicer way. For that see here: https://rise4fun.com/Z3/tutorialcontent/fixedpoints. It's an extension that z3 supports which isn't available in SMT solvers, making it more suitable for relational programming tasks.
Having said that, while it is indeed possible to express these sorts of relationships using an SMT solver, such problems are really not what SMT solvers are designed for. They are much more suitable for quantifier-free fragments of logics that involve arithmetic, bit-vectors, arrays, uninterpreted-functions, floating-point numbers, etc. It's always fun to try these sorts of problems as a learning exercise, but if this sort of problem is what you really care about, you should really stick to Prolog and its variants which are much more suited for this kind of modeling.

Is it possible to represent a context-free grammar with first-order logic?

Briefly, I have a EBNF grammar and so a parse-tree, but I do not know if there is a procedure to translate it in First Order Logic.
For example:
DR ::= E and P
P ::= B | (and P)* | (or P)*
B ::= L | P (and L P)
L ::= a
Yes, there is. The general pattern for translating a production of the form
A ::= B C ... D
is to paraphrase is declaratively as saying
A sequence of terminals s is an A (or: A generates the sequence s, if you prefer that formulation) if:
s is the concatenation of s_1, s_2, ... s_n, and
s_1 is a B / B generates the sequence s_1, and
s_2 is a C / C generates the sequence s_2, and
...
s_n is a D / D generates the sequence s_n.
Assuming we write these in the obvious way using a generates predicate, and that we can write concatenation using a || operator, your first rule becomes (if I am right to guess that E and P are non-terminals and "and" is a terminal symbol) something like
generates(DR,s) ⊃ generates(E,s1)
∧ generates(and,s2)
∧ generates(P,s3)
∧ s = s1 || s2 || s3
To establish the consequent (i.e. prove that s is an A), prove the antecedents. As long as the grammar does actually generate some sentences, and as long as you have some premises defining the "generates" relation for terminal symbols, the proof will be straightforward.
Prolog definite-clause grammars are a beautiful instantiation of this pattern. It takes some of us a while to understand and appreciate the use of difference lists in DCGs, but they handle the partitioning of s into subsequences and the association of the subsequences with the different parts of the right hand side much more elegantly than the simple translation into logic given above.

Can the negation introduction rule of inference "a, b=>¬a / ¬b" be used instead of the usual "b=>a, b=>¬a / ¬b"?

I find the negation introduction rule which I learned at university a bit confusing to reason out and think that "a, b=>¬a / ¬b" makes more sense as it means that if b implies something which is not true, then b is itself not true. I can't seem to find an example of where the usual rule is more useful than the one I would like to use. Is there a reason why "b=>a, b=>¬a / ¬b" is used as a rule?
OK, I think I have a pretty rigorous argument which validates said replacement.
Let's say that we need to introduce a negation on P. So using the usual inference rule, we prove
P => Q
P => ¬Q
and thereby prove ¬P.
Let's say that there is no way to derive both Q and ¬Q if P is not assumed. But then from P we can derive Q /\ ¬Q which will allow us to derive anything, including the negation of a tautology.
So we can prove ¬P using the proposed rule by doing something like this:
1. |P Assumed
... |...
10. |Q
... |...
20. |¬Q
21. |Q /\ ¬Q /\ introduction on line 10 and 20
22. |¬(A => A) Derived from line 21 using contradiction lemma
23. P => ¬(A => A) => introduction on lines 1-22
24. A => A Anything implies itself (a tautology)
25. ¬P ¬ introduction on line 23 and 24
So using tautologies we can always use the proposed rule of inference.
In other words, if you can use the usual rule of inference to introduce a negation, you can use the proposed rule of inference too.

symbolic computation

My problem: symbolic expression manipulation.
A symbolic expression is built starting from integer constants and variable with the help of operators like +, -, *, /, min,max. More exactly I would represent an expression in the following way (Caml code):
type sym_expr_t =
| PlusInf
| MinusInf
| Const of int
| Var of var_t
| Add of sym_expr_t * sym_expr_t
| Sub of sym_expr_t * sym_expr_t
| Mul of sym_expr_t * sym_expr_t
| Div of sym_expr_t * sym_expr_t
| Min of sym_expr_t * sym_expr_t
| Max of sym_expr_t * sym_expr_t
I imagine that in order to perform useful and efficient computation (eg. a + b - a = 0 or a + 1 > a) I need to have some sort of normal form and operate on it. The above representation will probably not work too good.
Can someone point me out how I should approach this? I don't necessary need code. That can be written easily if I know how. Links to papers that present representations for normal forms and/or algorithms for construction/ simplification/ comparison would also help.
Also, if you know of an Ocaml library that does this let me know.
If you drop out Min and Max, normal forms are easy: they're elements of the field of fractions on your variables, I mean P[Vars]/Q[Vars] where P, Q are polynomials. For Min and Max, I don't know; I suppose the simplest way is to consider them as if/then/else tests, and make them float to the top of your expressions (duplicating stuff in the process), for example P(Max(Q,R)) would be rewritten into P(if Q>R then Q else R), and then in if Q>R then P(Q) else P(R).
I know of two different ways to find normal forms for your expressions expr :
Define rewrite rules expr -> expr that correspond to your intuition, and show that they are normalizing. That can be done by directing the equations that you know are true : from Add(a,Add(b,c)) = Add(Add(a,b),c) you will derive either Add(a,Add(b,c)) -> Add(Add(a,b),c) or the other way around. But then you have an equation system for which you need to show Church-Rosser and normalization; dirty business indeed.
Take a more semantic approach of giving a "semantic" of your values : an element in expr is really a notation for a mathematical object that lives in the type sem. Find a suitable (unique) representation for objects of sem, then an evaluation function expr -> sem, then finally (if you wish to, but you don't need to for equality checking for example) a reification sem -> expr. The composition of both transformations will naturally give you a normalization procedure, without having to worry for example about direction of the Add rewriting (some arbitrary choice will arise naturally from your reification function). For example, for polynomial fractions, the semantic space would be something like:
.
type sem = poly * poly
and poly = (multiplicity * var * degree) list
and multiplicity = int
and degree = int
Of course, this is not always so easy. I don't see right know what representation give to a semantic space with Min and Max functions.
Edit: Regarding external libraries, I don't know any and I'm not sure there are. You should maybe look for bindings to other symbolic algebra software, but I haven't heard of it (there was a Jane Street Summer Project about that a few years ago, but I'm not sure there was any deliverable produced).
If you need that for a production application, maybe you should directly consider writing the binding yourselves, eg. to Sage or Maxima. I don't know what it would be like.
The usual approach to such a problem is:
Start with a string, such a as "a + 1 > a"
Go through a lexer, and separate your input into distinct tokens: [Variable('a'); Plus; Number(1); GreaterThan; Variable('a')]
Parse the tokens into a syntax tree (what you have now). This is where you use the operator precedence rules: Max( Add( Var('a'), Const(1)), Var('a'))
Make a function that can interpret the syntax tree to obtain your final result
let eval_expr expr = match expr with
| Number n -> n
| Add a b -> (eval_expr a) + (eval_expr b)
...
Pardon the syntax, I haven't used Ocaml in a while.
About libraries, I don't remember any out of the top of my mind, but there certainly are good ones easily available - this is the kind of task that the FP community loves doing.

Parsing expressions with an undefined number of arguments

I'm trying to parse a string in a self-made language into a sort of tree, e.g.:
# a * b1 b2 -> c * d1 d2 -> e # f1 f2 * g
should result in:
# a
* b1 b2
-> c
* d1 d2
-> e
# f1 f2
* g
#, * and -> are symbols. a, b1, etc. are texts.
Since the moment I know only rpn method to evaluate expressions, and my current solution is as follows. If I allow only a single text token after each symbol I can easily convert expression first into RPN notation (b = b1 b2; d = d1 d2; f = f1 f2) and parse it from here:
a b c -> * d e -> * # f g * #
However, merging text tokens and whatever else comes seems to be problematic. My idea was to create marker tokens (M), so RPN looks like:
a M b2 b1 M c -> * M d2 d1 M e -> * # f2 f1 M g * #
which is also parseable and seems to solve the problem.
That said:
Does anyone have experience with something like that and can say it is or it is not a viable solution for the future?
Are there better methods for parsing expressions with undefined arity of operators?
Can you point me at some good resources?
Note. Yes, I know this example very much resembles Lisp prefix notation and maybe the way to go would be to add some brackets, but I don't have any experience here. However, the source text must not contain any artificial brackets and also I'm not sure what to do about potential infix mixins like # a * b -> [if value1 = value2] c -> d.
Thanks for any help.
EDIT: It seems that what I'm looking for are sources on postfix notation with a variable number of arguments.
I couldn't fully understand your question, but it seems what you want is a grammar definition and a parser generator. I suggest you take a look at ANTLR, it should be pretty straightforward with it to define a grammar for either your original syntax or the RPN.
Edit: (After exercising self-criticism, and making some effort to understand the question details.) Actually, the language grammar is unclear from your example. However, it seems to me, that the advantages of the prefix/postfix notations (i.e. that you need neither parentheses nor a precedence-aware parser) stem from the fact that you know the number of arguments every time you encounter an operator, therefore you know exactly how many elements to read (for prefix notation) or to pop from the stack (for postfix notation). OTOH, I beleive that having operators which can have variable number of arguments makes prefix/postfix notations not simply difficult to parse but outright ambiguous. Take the following expression for example:
# a * b c d
Which of the following three is the canonical form?
(a, *(b, c, d))
(a, *(b, c), d)
(a, *(b), c, d)
Without knowing more about the operators, it is impossible to tell. Of course you could define some sort of greedyness of the operators, e.g. * is greedier than #, so it gobbles up all the arguments. But this would beat the purpose of a prefix notation, because you simply wouldn't be able to write down the second variant from the above three; not without additinonal syntactic elements.
Now that I think of it, it is probably not by sheer chance that none of the programming languages I know support operators with a variable number of arguments, only functions/procedures.

Resources