So, kernels have a hierarchical structure. They live inside of each other in this

sort of tree, right? And so, the terminology is that a kernel K

and F is a level-0 kernel if it contains no kernels inside of it except itself.

What that means is that if you were to apply a kerneling operation to it, you

wouldn't find anything new. Just kind of get yourself back with a

co-kernel of 1. And a level n kernel is level n if it

contains at least one level n minus 1 kernel, and no other level n kernels

except itself. So, level-1 kernels can have level-0

kernels inside them. Level-2 kernels can have level-1 kernels,

and also level-0 kernels. Right.

And you can start with F, and it turns out you can extract all of these kernels in

this very simple hierarchical manner. So, that turns out to be a really useful

insight. Now, that's my first result.

Here's my second result. Another result from Brayton in France.

Co-kernels of a billion expression in sum of products form correspond to

intersections of two of the more cubes in the constituent SOP form.

So, intersections here, means, specifically that we regarded cube is a

set of literals. And we look at common subsets, right?

So, this is not like ANDing for products, this is just simple common sub-expression.

So, if I had a function here, ace plus bce plus de plus g, if you intersect ace and

bce, you just get ce. If you intersect ace into bce and de, you

just get e. And what that means is that, that's a

potential co-kernel. Right.

So, you want to know where the co-kernels come from?

Intersect the cubes in the Boolean expression in algebraic form.

You want to have some sense of how the kernels arrange themselves.

There is a hierarchy of them inside the function.

That turns out to give us everything we need for a surprisingly straightforward

algorithm. So, how do you use those two results?

We're going to find their kernels recursively.

Again, you should not be surprised. This is just such a big, important

concept. And whenever we find one, we will call our

FindKernels algorithm on it to see if there's any lower level kernels inside.

And we're going to use algebraic division to divide the function by potential

co-kernels to drive the recursion. But we're going to be smart.

And so, we're just going to organize the computation to look only, only at the

intersections of the cubes. And if there's at least 2 cubes, we'll

look at the intersections of those cubes and we'll use that intersected result as

our potential co-kernel. And one technical point is that, you know,

we're supposed to start this with a cube-free function F to make things work

out nice. If it's not cube-free, you should just go

find the biggest common cube in the function and cross it out, and then, then

start. So, here's the algorithm.

And just as previously, I'm going to walk through the pseudocode of this algorithm,

but then, I am also going to show you a little kind of diagrammatic form how the

algorithm works, which I hope will clear things up.

So, find kernels is our algorithm, and it's recursive.

So, you start with a cube-free expression for F.

And the first thing you say is, alright, look.

I don't know anything, so the set k of kernels is empty.

And then, for every variable in x, I say, are there at least 2 cubes in F that have

that variable? If so, then, that's a potential co-kernel.

And what we know is that the way you get a kernel is by dividing F by a co-kernel and

what Brayton just told us is that you want to find a co-kernel?

Those are intersections of the cube. So, this is what I'm doing.

But I'm doing this, driving this process one variable at a time.

So, if there's at least 2 cubes in F that have this variable, let big S be the cubes

that have that variable in them. Let co be the cube that results from

intersecting all those cubes. That's a potential co-kernel.

Then, what we're going to do is take F and algebraically divide it by co, and that's

going to be a kernel, we think. And that'll be returned at the end.

But what we're going to do is recursively take F, divide it by that co-kernel, take

that new kernel and say, hey, let's go look and see if there's anything inside

that. And when we're done, sort of exploring

down the kernel hierarchy, as we come back up from the recursion.

The last thing that we'll do is actually return that kernel that we found.

Stick it on the set. Return it back up.

So, the algorithm may seem a little bit complicated, but it's actually pretty

straight forward if you just sort of build this little tree-like representation to

see how things work. So, let's just do this.

We have an example F equals ace plus bce plus de plus g.

And we're basically going to divide F by each of its variables and use that to

start the recursion. So, think of this as we're looking for

co-kernels that start with this one variable in them, and then, by sort of

recursing down, we'll be able to find everything.

So, we take F and the first thing we say is, alright, let's go look for all the

cubes that have an a in them. And the answer is there's only one cube

with an A in it and what we know from you know, the theory that we've got right now

is that if there's not at least two cubes There's nothing worth doing, and so

there's no work to do, and so we stop there.

What about cubes that have a b in them? Well, there's only one of those.

What about cubes that have a c in them? There's 2 cubes that have a c in them.

Those cubes are in fact ace and bce. So, you know, since we know that

co-kernels are intersections of cubes and we have at least 2 cubes, we have

something we can intersect. And so, we can see what's going on.

If we intersect them, we get ce and that is a co-kernel candidate.

So, we're going to divide F by our co-kernel candidate to get a plus b.

Well, that turns out to be cube-free and, you know, that's good.

That's actually a kernel. And the way this is going to work is we're

going to recurse further on that. Right, we're going to call the function on

this a plus b and we're going to reduce the same thing.

We're going to say, so, is there any as in it, any bs, any cs?

And we're going to do it. And we'll actually get a plus b on the way

back from that recursion. Next, you know, we got to the d variable.

Are there more than 1 cube with ds in it? No, alright, well then, we can stop that.

How about e? Are they any cubes with es in it?

Yes, actually, there are 3 cubes with e's in it.

And if you look, there are ace, bce and de, if we intersect them, we get a

co-kernel candidate e. F divided by the co-kernel candidate e is

ac + bc+ d that's cube-free. So that, that's actually, that's a kernel,

and again, well recursed by doing the same thing.

Call the function on itself on ac + bd + e and check every single variable and see

what we can find. So, when that returns, we'll go back,

we'll check the last variable g, there's only 1 cube with a g, so there's no work.

So, this is what happens at the first layer of the recursive calls, let's go

look on the next slide and see what happens when each of those boxes that

suggests there's more recursion actually recurses.

So, what's happening at the next level of the hierarchy?

Well, you know, here we found a plus b is a good kernel.

And then, we recursed down further, and so, we would actually call the recursion

with a plus b on it, and we would discover there's no work to be done on any

variable. And so, what would happen is we'd return a

plus b with a co-kernel ce. And that's how that branch would finish

itself. On the other hand, over here when we did

ac plus bd, bc plus d and we did the recursion there is actually some work.

When we looked at a, there's no work to be done, there's only one cube with an a,

only one cube with a b, and similarly only one cube with a de, and a g.

But there are a couple of cubes, there are two cubes, with this a c in them, ac and

bc, we intersect them to get a co-kernel candidate, c.

We take F and algebraically divide it by co, we get a plus b, it turns out we get a

plus b again. Right, again, we find this same kernel

with a co-kernel ce, only what's interesting is that when we found it

previously, we found it by immediately finding the co-kernel ce and this time we

found it by first finding the co-kernel e, and then second, finding the co-kernel c.

Okay, that's a little awkward, but it's not wrong, it gets the right answer.

So, we'll recurse on a plus b, we'll discover there's no more work and a plus b

will come back, saying, hey no more kernels living inside of it, we're done

with that path of the recursion or will return everything up the tree.

So, we get ac plus bc plus d and we get a plus b.

So, with this algorithm, you can find all the kernels and the co kernels too.

And you get the kernels by ANDing the divisor co cubes up the recursion tree.

There's one tiny problem, you're going to visit the same kernel multiple times.

And the solution is just, you have to remember which variables you've already

tried as you go down the paths of the recursion tree.

So the problem is the kernel you get for co-kernel abc is the kernel, the same

kernel you get for kernel cba. The kernel algorithm doesn't know this.

It's going to find it multiple times. There's a little extra bookkeeping to

solve this, but I'm just not going to worry about it.

Now, this is a fabulous result because it turns out that the kernels and the

co-kernels are exactly the right component pieces for doing what we see here on this

diagram. If I want to extract a single cube divisor

from multiple expressions, I'd like to know where to go look.

If I'd like to extract a multiple cube divisor from multiple expressions, I'd

like to know where to look. So, if I have F and G as nodes in a

Boolean network logic model, I would like to pull out divisors which are either a

single-cube or multiple-cube. So, a single-cube is like abc.

A multiple-cube is like abc plus def. And use those extracted divisors to

simplify the internal structure of the F and the G node.

And when we started this lecture, you had no ideal about the, the, the Boolean

network model, you had no idea about the algebraic model, you had know idea about

algebraic division, you had no ideal about factoring, you didn't know how toe extract

them. And now, you know a remarkable amount, you

know that it turns out that the only place to look for multiple cube divisors in

intersections of the kernels. And the good place to look for single-cube

divisors is in the co-kernels. And you know that kernels live in a

hierarchy inside this Boolean expression. So, you want to go find a single-cube

divisor, go look at the co-kernels, you want to find a good multiple-cube divisor,

go look at the kernels. And algorithmically, we know how to do

that in a simple deterministic manner. There's only one thing you really don't

know how to do yet and that's how do you deal with something that's got, like a

thousand Boolean network nodes in it. Well, alright, that's, that's what we're

actually going to go do in the next sequence of lectures.

So what's our overall summary for Multilevel Synthesis Models?

The Boolean network model, it's like a gate network, but each node is in, in the

network is a sum of products formed. It supports many operations to add, reduce

or simplify nodes in the network. The algebraic model and algebraic division

are big new ideas. They simplify Boolean functions to behave

like polynomials of a real numbers. We can one boolean function by another.

F equals D times Q plus R. Kernels and Co-kernels of a function F in

the algebraic form, the kernel is a cube-free quotient obtained by dividing by

a single cube which is called a co-kernel. Intersections of the F and G kernels are

all multiple-cube common divisors. There are, is only one place to look for

good divisors, and that's looking in the intersections of the kernels.

That's an amazing big, practical result of engineering consequence.

We're going to talk about how to use that. The problem, the big thing you don't know,

is that you don't know what are the best common divisors to get?

You know that, that the algebraic model and the kerneling operation kind of tell

you what the right pieces are. But you don't really know how to deal with

something with like a large Boolean network model with lots of lots of nodes.

And that's what we're going to talk about next.

I'll just say, also by, as an aside, the algebraic model and algebraic division are

not the only options in Multilevel Logic. There are some Boolean division models and

algorithms. And there are also some things that are

sort of more expressive than the algebraic model, but less expressive than a full,

complete Boolean model but these things are more complex.

There's a really interesting and rich universe of models and methods here.

There's a couple of good references to read about these things.

The paper by Bob Brayton, Rick Rudell and Alberto Sangiovanni-Vincentelli and Albert

Wang MIS: A Multiple-Level Logic Optimization System from 1987.

That's a really good primary source for the sort of the early historical evolution

of these things. And also, Giovanni De Micheli's Synthesis

and Optimization book from McGraw-Hill, that's another really good place to look.