You are on page 1of 6

On the Reverse Engineering of Boolean Logic

By David Legg, 10/25/2015

While it is relatively trivial to invert a statement such as pq through exhaustive search of the

domains of p and q , (namely, to search through B = { T , F } ), this process becomes expensive

computationally for large numbers of logical variables. Such was the initial motivation of my pursuit of

a computationally efficient way to invert Boolean statements. However, this in turn led to a larger quest

to do so in a way that is moderately extensible to other, arbitrary functions (moderately, because I

exempt myself from trying, for instance, to efficiently invert cryptographic hashes).

This pursuit has led to the following creations and discoveries. These are not grouped by the

order I came up with them, but rather by their pertinence to each other. As such, there are distinct

sections to this paper, which trace different, often completely separate, lines of reasoning. This is not

intended to be a coherent argument, but rather a digital record of my thoughts and work in a moderately

polished (if unfinished) form.

The Discovery of Linear Complexity Inversion of Or

To begin, let us consider the expression pq . There are three cases in which this holds:

p =T, q = F; p = F, q =T; p= T, q= T

This approach, to assign all possible values in all possible combinations, is simple but suffers

from O(3n ) complexity on the number of operators. The same could be said of , by just negating

the overall expression. The next idea that I had, to decrease the complexity slightly, was to group the

above cases into the following:

p { T }, q B; p B, q { T }

This reduces the complexity to O(2n ) , but that is of course not a significant improvement,

because it still scales exponentially. To consider the final phase, by which there is only a single case, it

is necessary to understand that the values of p and q are interrelated, and to build that interrelation
into the expression of their values:

p { T , q }, q { T , p }

The only problem this introduces is that the time of evaluation of a variable is important; that is,

one must preserve the relatedness of these until a value is known which allows one to narrow the scope.

To explain, if one were to ask what values p might be in the current context, the following operations

should take place (with some abuse of notation):

p { T , q }
{ T , } { T , p }
{T , F, p }
B

The final step is a recognition that p { p } is a tautology, and thus p may take on any value

in it's domain. That this domain happens to already have been included is not, for sake of discussion,

pertinent. Now, consider if a second fact q = F were introduced:

q = F
q {F }
q { T , p }
q { F } { T , p }
( { F } { T }) ( { F } { p })
{ F } {p }

Note that, in this manipulation, the ending condition is not that q { F } . Rather, this state

leaves open the possibility that q , if p = F . This is actually an appropriate behavior, as it would

indicate a contradiction, i.e., that there exists no values for q that would make the expression true.

However, in this case, we may attempt to plug this expression in that for p , as follows:

p { T , q }
{ T } ( { F } { p })
{ T } ( { T } { p })
{ T } ({ T } B )
{T }{T }
{T }

Noting that, when { p } is encountered in an expression for the set of values for p , this is
equivalent to the domain of p . Finally, this new expression for p can be plugged into that for q :

q { F } {p }
{ F } { T }
{F }

And thus, we have arrived at the correct conclusion.

The Creation of a Concrete Inversion of And

This leads directly to the next observation: given the use of variables in the sets of values, can

we build a single expression that encapsulates all cases, rather than a single case for each value of the

result of the operation? To start, we'll examine the following truth table, for pq = r :

q r { p}
T T {T }
T F {F }
F T
F F {T ,F }
Where { p } is the set of values p can take on such that pq = r still holds. From this, it

was observed that one could define an inverse of as follows:

1 (q , r ) = { T , r } {F , qr }

Similarly, for p q = r , we may define the following:

1h (q, r) = { T , r } { F , q r } ,
1c ( p , r ) = { F , r } { T , p r }

For completeness, we may also define the inverse of :


1
(q , r ) = { F , r } { T , qr } , where is the exclusive or operation.

And finally, we should note that , , and are all involutive.

A More General Study of Inversion and Pseudo-Inversion

It occurred to me that, while the above definitions are valid, they are special cases. Thus, to

better understand the problem I was attempting to break down, I tried defining better how to invert
functions in general. Now, it is well-known that only one-to-one, onto functions (bijections) have true

inverses. Thus, to attain a wider (and more practical) range of functions to work with, I will be

considering a pseudo-inverse technique, whereby the output of the inverse is the set of all values that

map to the given output. More on this later. First, some definitions:

Let : F n F 1 , where F i denotes the set of functions of arity i . We may say that

( f )( x1 ) = f 1 such that f 1 (x 2 , , xn ) = f ( x1 , x 2 , , x n ) . The importance of this rather trivial

closure function is that, through repeated application, any function may be reduced to a composition of

unary functions. Thus, for all further discussion, we may consider all functions to effectively be unary.

Next, let : F 1 F 1 such that for f : X Y , (f ) : Y P( X ) where P( X ) is the power

set of X . To complete the definition, we say that (f )( y) = { x | f ( x) = y } . We refer to as the

pseudo-inverse function, because it generates a function which maps any output to the set of all input

for that output. However, this introduces a challenge, as the output of a pseudo-inverse function is no

longer in the domain of the original function.

To solve this, let (f ) : P( X) P(Y ) , such that (f )( X ' ) = { f ( x) | x X ' } . This is not

strictly stated in most papers, as the slight abuse of notation by which f : P( X ) P(Y ) is implied

and accepted, but for this the precision is important. Notice that now, (f ) has, as domain, the target

of (f ) , but the target of (f ) is no longer the domain of (f ) . To solve this, temporarily, we may

use ( )(f ) as our new pseudo-inverse. However, this presents the same challenges as those that

inspired in the first place.

The solution is to use, for the full pseudo-inverse function, (f ) = (( )(f )) . That is to

say, (f )(Y ') = (f )( y ) = { x | f ( x) Y ' } . Thus, (f ) : P(Y ) P( X ) , and the domain and
y Y '

target of (modified) function (f ) align with the target and domain of the full pseudo-inverse (f ) ,

such that (f ) (f ) and (f ) ( f ) are at least semantically possible.

It is worth noting, however, that these are still pseudo-inverses, and that as such,
( (f ) (f ))(Y ') Y ' , as might be expected. Rather, ( (f ) (f ))(Y ') Y ' , because any value

in Y ' for which there is no correspondence in X will be lost in applying the full pseudo-inverse. As

such, it is worth noting that ( (f ) (f ))(Y ) will return the range of f in Y . Similarly,

( (f ) (f ))( X ' ) X ' , because, in the case that f is many-to-one, and one of the outputs of

(f )( X ' ) has other inputs that map to it, outside of X ' , those extra inputs will be returned by (f ) .

Note that for any function f which is well-defined over its domain X , ( (f ) (f ))( X ) = X .

To continue, we consider the application of the above operators on compositions of functions.

To start, consider (f g) , for f : Y Z and g : X Y . To examine what this would be, it is

necessary to consider its application (f g)( X ') . Solving,

(f g)( X ') = { ( f g)( x) | x X ' }


= { f ( g( x )) | x X ' }
= ( f )({ g( x) | x X ' })
= ( f )( ( g)( X ' ))
= ( ( f ) (g))( X ')

Thus, we may conclude that (f g) = ( f ) (g) .

Next, consider (f g) . Arguably, this function ought to map Z P( X) , such that for any

output in Z it returns all usable input in X . To do this, it would be sensible to have it map any output

to every intermediate input in Y , then map all of those intermediate inputs to their corresponding

inputs in X . In other words, (f g) = ( g) ( f ) , intuitively.

Finally, consider (f g) . It should map a set of outputs in Z to their corresponding inputs in

X . That is, (f g) : P(Z) P( X) . Applying the definition of ,

(f g) = (( )(f g ))
= ( (g ) (f ))
= ( )( g) ( )( f )

Intuitively, this makes a sort of sense: ( )(f ) : P( Z) P 2 (Y ) , that is, each element of a

set of output maps to a set of intermediate inputs. Next, ( )(g) : P 2 (Y ) P 2 ( X ) , that is, each set

of intermediate inputs is mapped to a set of original inputs. Finally, U : P 2 ( X ) P( X) , condensing


the set of input sets into a single input set.

You might also like