Necessary and Sufficient vs Soundness and Completeness - logic

I am trying to learn proof. I came across these 4 terms. I am trying to relate all.
A: X>Y B: Y<X
Necessary Condition
B implies A
Sufficient Condition
A implies B
And
A = { set of statements} Q= a statement
Soundness
if A derives Q then A is a logical consequence of Q
Completeness
if A is a logical consequence of Q then A derives Q.
What is relation between all?
Help is appreciated.

Necessary / sufficient doesn't have much to do with soundness and completeness so I'll explain the two concepts separately.
Necessary / sufficient:
In your example, the two statements are equivalent: X>Y if and only if Y<X. So it is indeed the case that B implies A and A implies B. A better example would perhaps be:
A: X>Y+1
B: X>Y
Here A would imply B, i.e. A would be sufficient for B to hold. The other way would not hold: B does not imply A (since you could have X=10 and Y=9 in which case only B would hold). This means that A is not necessary for B.
Completeness/soundness:
This took a while for me to wrap my head around when I first encountered it. But it's really simple!
Suppose you have the following:
A = { X>Y, Y>Z }
Q = X>Z
Now, soundsess says that we can't reach crazyness by sticking to the statements of A. More formally, if Q does not hold, it can't be derived from A. Or, only valid things can be derived from A.
It's easy to create an unsound set of statements. Take for instance
A = { x<Y, X>Y }
They contradict each other, so we can for instance derive X>X (which is false) by using proof by contradiction.
Completeness says the dual: All valid things can be derived from A. Suppose that X, Y and Z are the only variables in the world, and > is the only relation in the world. Then a set of statements such as
A = { X>Y, Y>Z }
is complete, since for any two given variables, a and b, we can derive a>b if and only if a>b in fact holds.
If we would only have
A = { X>Y } (and no knowledge about Z)
then the set of statements would not be complete since there would be true statements about Z which we could say nothing about.
In a nutshell: Soundness says that you can't come to crazy conclusions, and completeness says that you can reach all sensible conclusions.

Related

Combine boolean and integer logic in linear arithmetic using the Z3 Solver?

I would like to solve problems combining boolean and integer logic in linear arithmetic with a SAT/SMT solver. At first glance, Z3 seems promising.
First of all, is it at all possible to solve the following problem? This answer makes it seem like it works.
int x,y,z
boolean a,b,c
( (3x + y - 2z >= 10) OR (A AND (NOT B OR C)) OR ((A == C) AND (x + y >= 5)) )
If so, how does Z3 solve this kind of problem in theory and is there any documentation about it?
I could think of two ways to solve this problem. One would be to convert the Boolean operations into a linear integer expression. Another solution I read about is to use the Nelson-Oppen Combination Method described in [Kro 08].
I found a corresponding documentation in chapter 3.2.2. Solving Arithmetical Fragments, Table 1 a listing of the implemented algorithms for a certain logic.
Yes, SMT solvers are quite good at solving problems of this sort. Your problem can be expressed using z3's Python interface like this:
from z3 import *
x, y, z = Ints('x y z')
A, B, C = Bools('A B C')
solve (Or(3*x + y - 2*z >= 10
, And(A, Or(Not(B), C))
, And(A == C, x + y >= 5)))
This prints:
[A = True, z = 3, y = 0, B = True, C = True, x = 5]
giving you a (not necessarily "the") model that satisfies your constraints.
SMT solvers can deal with integers, machine words (i.e., bit-vectors), reals, along with many other data types, and there are efficient procedures for combinations of linear-integer-arithmetic, booleans, uninterpreted-functions, bit-vectors amongst many others.
See http://smtlib.cs.uiowa.edu for many resources on SMT solving, including references to other work. Any given solver (i.e., z3, yices, cvc etc.) will be a collection of various algorithms, heuristics and tactics. It's hard to compare them directly as each shine in their own way for certain sublogics, but for the base set of linear-integer arithmetic, booleans, and bit-vectors, they should all perform fairly well. Looks like you already found some good references, so you can do further reading as necessary; though for most end users it's neither necessary nor that important to know how an SMT solver internally works.

representing large binary vector as problog fact/rule

In ProbLog, how do I represent the following as p-fact/rule :
A binary vector of size N, where P bits are 1 ? i.e. a bit is ON with probability P/N, where N > 1000
i come up with this, but it seem iffy :
0.02::one(X) :- between(1,1000,X).
Want to use it later to make calculations on what happens if i apply two-or-more operations of bin-vec such as : AND,OR,XOR,count,overlap, hamming distance, but do it like Modeling rather than Simulation
F.e. if I ORed random 10 vec's, what is the probable overlap-count of this unionized vector and a new rand vec
... or what is the probability that they will overlap by X bits
.... questions like that
PS> I suspect cplint is the same.
Another try, but dont have idea how to query for 'single' result
1/10::one(X,Y) :- vec(X), between(1,10,Y). %vec: N=10, P=?
vec(X) :- between(1,2,X). %num of vecs
%P=2 ??
two(A,B,C,D) :- one(1,A), one(2,B), A =\= B, one(1,C), one(2,D), C =\= D.
based on #damianodamiono , so far :
P/N::vec(VID,P,N,_Bit).
prob_on([],[],_,_).
prob_on([H1|T1],[H2|T2],P,N):-
vec(1,P,N,H1), vec(2,P,N,H2),
prob_on(T1,T2,P,N).
query(prob_on([1],[1],2,10)).
query(prob_on([1,2,3,5],[1,6,9,2],2,10)).
I'm super happy to see that someone uses Probabilistic Logic Programming! Anyway, usually you do not need to create a list with 1000 elements and then attach 1000 probabilities. For example, if you want to state that each element of the list has a probabilty to be true of P/N (suppose 0.8), you can use (cplint and ProbLog have almost the same syntax, so you can run the programs on both of them):
0.8::on(_).
in the recursion.
For example:
8/10::on(_).
prob_on([]). prob_on([H|T]):-
on(H),
prob_on(T).
and then ask (in cplint)
?- prob(prob_on([1,2,3]),Prob).
Prob = Prob = 0.512
in ProbLog, you need to add query(prob_on([1,2,3])) in the program. Note the usage of the anonymous variable in the probabilistic fact on/1 (is needed, the motivation may be complicated so I omit it). If you want a probability that depends on the lenght of the list and other variables, you can use flexible probabilities:
P/N::on(P,N).
and then call it in your predicate with
...
on(P,N),
...
where both P and N are ground when on/2 is called. In general, you can add also a body in the probabilistic fact (turning it into a clause), and perform whatever operation you want.
With two lists:
8/10::on_1(_).
7/10::on_2(_).
prob_on([],[]).
prob_on([H1|T1],[H2|T2]):-
on_1(H1),
on_2(H2),
prob_on(T1,T2).
?- prob(prob_on([1,2,3,5],[1,6,9,2]),Prob).
Prob = 0.09834496
Hope this helps, let me know if something is still not clear.

Is it possible to generate an equality function based on the data to be compared?

Two Booleans are equal if the're the same value, two numbers similarly. Two sets are equal if they have the same elements. In case of checking two sets for equality we can use the following scheme/racket function:
(define (same-set? l1 l2)
(and (subset? l1 l2) (subset? l2 l1)))
How would such a function be generated automatically? Can it be generated for arbitrary data type?
The basic properties of an equivalence relation are:
Substitution property: For any quantities a and b and any expression F(x), if a = b, then F(a) = F(b) (if both sides make sense, i.e. are well-formed).
Some specific examples of this are:
For any real numbers a, b, and c, if a = b, then a + c = b + c (here F(x) is x + c);
For any real numbers a, b, and c, if a = b, then a − c = b − c (here F(x) is x − c);
For any real numbers a, b, and c, if a = b, then ac = bc (here F(x) is xc);
For any real numbers a, b, and c, if a = b and c is not zero, then a/c = b/c (here F(x) is x/c).
Reflexive property: For any quantity a, a = a.
Symmetric property: For any quantities a and b, if a = b, then b = a.
Transitive property: For any quantities a, b, and c, if a = b and b = c, then a = c.
Is it possible to generate a function that obeys the above properties? Would that be enough? Could knowing the type of data help?
If you have any ideas on how to improve this question or tag it please comment.
I just want to expand on #Sorawee Porncharoenwase's answer a bit. They mentioned two kinds of equality, referential equality with eq?, and structural equality with equal?.
These different notions of equality should all follow the basic requirements of reflexivity, symmetry, and transitivity. But what sets them apart from each other is the guarantees that they give when they return true or false.
Some useful classes of equality to keep in mind are are reference-equality, structural-equality for all-time, structural-equality for the current time, and domain-specific equivalences.
Reference equality
The eq? function implements reference equality, and it has the strongest guarantees when it returns true, but when it returns false you haven't learned much.
(eq? x y) implies that x and y are literally the same object, and that any operation on x could be replaced with the same on y, including mutation. One thing that helped explain this to me was in the book Realm of Racket, saying that if you shave x, then y will also be shaved because it's the same object.
However, when (eq? x y) returns false that's pretty weak sauce. On the many data structures that involve allocating memory, eq? can return false simply because the pointers are different, even if they're immutable and everything else is the same.
This can be provided automatically by the programming language because it's really not much more than pointer-equality, and it doesn't have to generate any new behavior for new data structures.
Structural Equality for All-Time
This notion of equality is not currently well-supported by base Racket or standard Scheme, although libraries such as Rackjure can provide limited versions of this with functions like egal?. It implements reference equality on mutable data structures, but structural equality on immutable data structures.
This is meant to provide the guarantee that if (egal? x y) returns true now, then it has been true in the past and will continue to be true in the future as long as x and y both exist.
This can be provided automatically by the programming language as long as the language allows you to specify which data structures are immutable vs mutable, and enforces the immutability.
I'm not sure, but chaperone-of? may also be an example of following the ideas of "Structural Equality for All-Time", except that chaperone-of? isn't symmetric (and a naive symmetric-closure would lose transitivity).
If you want to read more, see Types of Equality in Pyret or Equal Rights for Functional Objects.
Structural Equality for the Current Time
The equal? function implements structural equality for the current time. This means two mutable data structures can be equal now if they currently have all equal components, even if they weren't equal in the past or won't be in the future due to mutation.
This can be provided automatically by the programming language as long as it always knows all the sub-parts of data contained within the data-structures.
Domain-specific Equivalences
For example for the domain of numbers and math, you might want the inexact number 2.0 to be equivalent to the exact integer 2. For the domain of string search, you might want case-insensitive equivalence for strings and characters so that A and a are equivalent. For the domain of sets, you might want order to be irrelevant so that (a b) and (b a) are equivalent.
Each domain is different, so this requires more effort on each domain. The programming language can't read your mind.
Two Booleans are equal if the're the same value, two numbers similarly. Two sets are equal if they have the same elements.
These are useful equalities, but they are not the only equalities that you can create. For instance, you can consider two numbers to be equal when their parities (odd/even) are the same. Or you can consider every number to be equal to each other.
How would such a function be generated automatically?
In general, it's not possible, because it depends on your intention. And no one can read your mind.
Is it possible to generate a function that obeys the above properties?
The answer is trivially yes. At the very least, you have (lambda (x y) #t), which says that every object is equal to every other object. It satisfies the equivalence relation properties, though it's totally useless.
For a non-trivial equality that works on all kinds of values, you have referential equality eq? which obeys the equivalence relation property (it could give you a weird result if you are using the unsafe API IIUC, but that's off-topic).
equal? can be used for structural equality on several values such as lists and those that are instances of a default transparent struct, and it also cooperates with custom equality that users provide. This is usually what you want to use in Racket.
Yes, it is definitely possible. Some programming languages allow for automatic equality function synthesis. Swift is a such example.
Without automatic synthesis, the developer has to write code for the equality, e.g., consider a struct:
struct Country: Equatable {
let name: String
let capital: String
var visited: Bool
static func == (lhs: Country, rhs: Country) -> Bool {
return lhs.name == rhs.name &&
lhs.capital == rhs.capital &&
lhs.visited == rhs.visited
}
}
With Swift 4.1 and higher, this is no longer necessary. The compiler generates the equality function for you:
struct Country: Equatable { // It's enough to just declare that the type is `Equatable` and the compiler do the rest
let name: String
let capital: String
var visited: Bool
}
Let's test it:
let france = Country(name: "France", capital: "Paris", visited: true)
let spain = Country(name: "Spain", capital: "Madrid", visited: true)
if france == spain { ... } // false
Update:
Even after Swift 4.1, it's possible to override the default implementation with own, custom logic. For example:
struct Country: Equatable {
let name: String
let countryCode: String
let capital: String
var visited: Bool
static func == (lhs: Country, rhs: Country) -> Bool {
return lhs.countryCode == rhs.countryCode
}
}
So, the developer is always in control. The equality won't be synthesised automatically, the developer has to add Equatable to the struct declaration. If after that they're not satisfied with the default implementation, or if it couldn't be inferred, there is always an option to override compiler's intention and provide a customized variant.

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.

how to construct truth table for not gate in 3-satisfiability circuit?

Having a lot of trouble understanding this relatively simple concept. So I'm proving that the 3-satisfiability problem is NP-Complete, and part of that involves transforming boolean gates (for example, the NOT gate) into conjunctive normal functions.
So if one gate is a "NOT" gate and takes input a, and returns b = NOT(a), apparently the right answer is that we can enforce the two clauses: a or b, and NOT(a) and NOT(b).
This can be done by a truth table, but I can't seem to figure out how this truth table works. If anyone can explain that would be VERY helpful.
Define a "consistency function" C taking 2 arguments a and b, which is True(1) if and only if the values of a and b are consistent with the definition of a NOT gate.
In your case,
C(0,0) = 0 (since a=0 b=0 is inconsistent with a=NOT(b) )
C(0,1) = 1
C(1,0) = 1
C(1,1) = 0
which is the desired truth table.
Now you can obtain expression for C = a.b + (a').(b') = (a + b).(a' + b')

Resources