beanmachine.ppl.compiler.bmg_types module

class beanmachine.ppl.compiler.bmg_types.AlwaysMatrix(bound: beanmachine.ppl.compiler.bmg_types.BMGMatrixType)

Bases: beanmachine.ppl.compiler.bmg_types.BaseRequirement

bound: beanmachine.ppl.compiler.bmg_types.BMGMatrixType
class beanmachine.ppl.compiler.bmg_types.AnyRealMatrix

Bases: beanmachine.ppl.compiler.bmg_types.BaseRequirement

long_name: str
short_name: str
class beanmachine.ppl.compiler.bmg_types.AnyRequirement

Bases: beanmachine.ppl.compiler.bmg_types.BaseRequirement

long_name: str
short_name: str
class beanmachine.ppl.compiler.bmg_types.BMGElementType(short_name: str, long_name: str)

Bases: object

long_name: str
short_name: str
class beanmachine.ppl.compiler.bmg_types.BMGLatticeType(short_name: str, long_name: str)

Bases: object

is_singleton() bool
long_name: str
short_name: str
class beanmachine.ppl.compiler.bmg_types.BMGMatrixType(element_type: beanmachine.ppl.compiler.bmg_types.BMGElementType, short_name: str, long_name: str, rows: int, columns: int)

Bases: beanmachine.ppl.compiler.bmg_types.BMGLatticeType

columns: int
element_type: beanmachine.ppl.compiler.bmg_types.BMGElementType
is_singleton() bool
rows: int
abstract with_dimensions(rows: int, columns: int) beanmachine.ppl.compiler.bmg_types.BMGMatrixType
with_size(size: torch.Size) beanmachine.ppl.compiler.bmg_types.BMGMatrixType
class beanmachine.ppl.compiler.bmg_types.BaseRequirement(short_name: str, long_name: str)

Bases: object

long_name: str
short_name: str
class beanmachine.ppl.compiler.bmg_types.BooleanMatrix(*args)

Bases: beanmachine.ppl.compiler.bmg_types.BroadcastMatrixType

columns: int
element_type: beanmachine.ppl.compiler.bmg_types.BMGElementType
long_name: str
rows: int
short_name: str
with_dimensions(rows: int, columns: int) beanmachine.ppl.compiler.bmg_types.BMGMatrixType
class beanmachine.ppl.compiler.bmg_types.BroadcastMatrixType(element_type: beanmachine.ppl.compiler.bmg_types.BMGElementType, rows: int, columns: int)

Bases: beanmachine.ppl.compiler.bmg_types.BMGMatrixType

columns: int
element_type: beanmachine.ppl.compiler.bmg_types.BMGElementType
long_name: str
rows: int
short_name: str
class beanmachine.ppl.compiler.bmg_types.NaturalMatrix(*args)

Bases: beanmachine.ppl.compiler.bmg_types.BroadcastMatrixType

columns: int
element_type: beanmachine.ppl.compiler.bmg_types.BMGElementType
long_name: str
rows: int
short_name: str
with_dimensions(rows: int, columns: int) beanmachine.ppl.compiler.bmg_types.BMGMatrixType
class beanmachine.ppl.compiler.bmg_types.NegativeRealMatrix(*args)

Bases: beanmachine.ppl.compiler.bmg_types.BroadcastMatrixType

columns: int
element_type: beanmachine.ppl.compiler.bmg_types.BMGElementType
long_name: str
rows: int
short_name: str
with_dimensions(rows: int, columns: int) beanmachine.ppl.compiler.bmg_types.BMGMatrixType
class beanmachine.ppl.compiler.bmg_types.OneHotMatrix(*args)

Bases: beanmachine.ppl.compiler.bmg_types.BMGMatrixType

columns: int
element_type: beanmachine.ppl.compiler.bmg_types.BMGElementType
long_name: str
rows: int
short_name: str
with_dimensions(rows: int, columns: int) beanmachine.ppl.compiler.bmg_types.BMGMatrixType
class beanmachine.ppl.compiler.bmg_types.PositiveRealMatrix(*args)

Bases: beanmachine.ppl.compiler.bmg_types.BroadcastMatrixType

columns: int
element_type: beanmachine.ppl.compiler.bmg_types.BMGElementType
long_name: str
rows: int
short_name: str
with_dimensions(rows: int, columns: int) beanmachine.ppl.compiler.bmg_types.BMGMatrixType
class beanmachine.ppl.compiler.bmg_types.ProbabilityMatrix(*args)

Bases: beanmachine.ppl.compiler.bmg_types.BroadcastMatrixType

columns: int
element_type: beanmachine.ppl.compiler.bmg_types.BMGElementType
long_name: str
rows: int
short_name: str
with_dimensions(rows: int, columns: int) beanmachine.ppl.compiler.bmg_types.BMGMatrixType
class beanmachine.ppl.compiler.bmg_types.RealMatrix(*args)

Bases: beanmachine.ppl.compiler.bmg_types.BroadcastMatrixType

columns: int
element_type: beanmachine.ppl.compiler.bmg_types.BMGElementType
long_name: str
rows: int
short_name: str
with_dimensions(rows: int, columns: int) beanmachine.ppl.compiler.bmg_types.BMGMatrixType
class beanmachine.ppl.compiler.bmg_types.SimplexMatrix(*args)

Bases: beanmachine.ppl.compiler.bmg_types.BMGMatrixType

columns: int
element_type: beanmachine.ppl.compiler.bmg_types.BMGElementType
long_name: str
rows: int
short_name: str
with_dimensions(rows: int, columns: int) beanmachine.ppl.compiler.bmg_types.BMGMatrixType
beanmachine.ppl.compiler.bmg_types.Untypable = <beanmachine.ppl.compiler.bmg_types.BMGLatticeType object>

When converting from an accumulated graph that uses Python types, we can express the rules concisely by defining a type lattice. A type lattice is a DAG which meets these conditions:

  • Nodes are types

  • Edges are directed from “larger” types to “smaller” types. (Note that there is no requirement for a total order.)

  • There is a function called “supremum” which takes two types and returns the unique type that is the smallest type that is bigger than both arguments.

  • There is a function called “infimum” which similarly is the unique largest type smaller than both arguments. (Right now we do not actually need this function in our type analysis so it is not implemented.)

For matrix types with a single column and any number of rows r, and columns c, the type lattice is:

T (Tensor unsupported by BMG) |

MR[r,c] (Real matrix) | | | MR+[r,c] (Positive real matrix)

MR-[r,c] | | (Negative real matrix)
| |
MN[r,c] | (Natural matrix)
| MP[r,c] (Probability matrix)
| | |
MB[r,c] | (Boolean matrix)
| | S[r,c] (Row-simplex matrix)
| | |
| OH[r,c] (One-hot matrix)
| |
Z[r,c] | (All-zero matrix)

BOTTOM (the bottom type)

OH – one-hot – is not a type in the BMG type system; we use it only when analyzing the accumulated graph. The OH type is used to track the situation where a constant matrix can be converted to both a Boolean and a simplex matrix; if the rows are “one hot” – all false (or 0) except for one true (or 1) – then the matrix is convertable to both Boolean and simplex.

Similarly, Z – the all-zero matrix – is not a type in the BMG type system. We use it to track cases where a matrix is convertible to both Boolean and negative real.

Similarly, T (tensor) – the top type – is not found in the BMG type system. The top type is the type more general than all other types, and is used for situations such as attempting to resolve situations such as “what is the type that is more general than both a 1x2 matrix and a 2x2 matrix?” or to represent matrix types not supported in BMG such as 3-dimensional matrices.

The BOTTOM type is the type that has no values; it is similarly used as a convenience when you need a type more specific than any other type; it is not in the BMG type system.

Why is this useful?

Our goal is to generate a graph that meets all the requirements of the BMG type system. In order to do so, we compute a requirement object for each edge in the graph.

There are two kinds of requirements: “input must be exactly type X” and “input must be type X or smaller”. The first kind of requirement we call an “exact requirement” and the latter is an “upper bound requirement”.

(We do not at this time have any scenarios that need “lower bound requirements” but if we need them we can add them.)

Once we know the requirements on the incoming edges to a node, we can check to see if the requirements are met by the nodes. * If they are, then we’re good. * If not then we can do a graph mutation which causes the requirements to be met. * If there is no such mutation then we can report an error.

How do we compute the requirements for an edge? It depends on the kind of graph node that the edge is attached to. A Bernoulli node, for example, requires that its input be “exactly P”. A “to real” node requires that its input be “R or smaller”.

Some nodes however introduce more complex requirements. The requirements of a multiplication node, for instance, are:

  • the input types must be greater than or equal to P

  • the input types must be exactly the same

We do not have a requirement object for either “greater than or equal”, or for “this edge must be the same as that edge”. And we have one more factor to throw in: the output type of a multiplication is the same as its input types, so we wish to find the smallest possible restriction on the input types so that the multiplication’s type is minimized.

(That is: if we have a multiplication of a natural by a probability, we do not wish to require that both be converted to reals, because then the multiplication node could not be used in a context where a positive real was required. We want the smallest type that works: positive real.)

How are we going to do this?

We generate the edge requirements for a multiplication as follows:

The requirement on both input edges is that they be exactly equal to the supremum of the infimum types of the two inputs.

The infimum type is the smallest type that each node in the graph could possibly be. We call this type the “infimum type” of the node because it is the infimum – the greatest lower bound – in the lattice.

It might not be clear why that works. Let’s work through an example.

Suppose we have a sample from a beta; it’s infimum type is Probability because that’s the only type a sample from a beta can be. And suppose we have a sample from a binomial; it’s infimum type is Natural, again, because that’s the only type it can be.

Now suppose we multiply them. What restrictions go on the left and right input edges of the multiplication?

The supremum of Natural and Probability is PositiveReal, so we put an “exactly PositiveReal” restriction on the two edges. During the “fix problems” phase, we see that we have an edge from a multiplication to a sample of type Probability, but there is a requirement that it be a PositiveReal, so we insert a ToPositiveRealNode between the multiplication and the sample. And then similarly for the sample of type Natural.

The result is that we have a multiplication node that meets its requirements; the input types are the same, and the output type is the smallest type it could possibly be: PositiveReal.

class beanmachine.ppl.compiler.bmg_types.UpperBound(bound: beanmachine.ppl.compiler.bmg_types.BMGLatticeType)

Bases: beanmachine.ppl.compiler.bmg_types.BaseRequirement

bound: beanmachine.ppl.compiler.bmg_types.BMGLatticeType
class beanmachine.ppl.compiler.bmg_types.ZeroMatrix(*args)

Bases: beanmachine.ppl.compiler.bmg_types.BMGMatrixType

columns: int
element_type: beanmachine.ppl.compiler.bmg_types.BMGElementType
long_name: str
rows: int
short_name: str
with_dimensions(rows: int, columns: int) beanmachine.ppl.compiler.bmg_types.BMGMatrixType
beanmachine.ppl.compiler.bmg_types.always_matrix(bound: beanmachine.ppl.compiler.bmg_types.BMGMatrixType) Union[beanmachine.ppl.compiler.bmg_types.BMGLatticeType, beanmachine.ppl.compiler.bmg_types.BaseRequirement]
beanmachine.ppl.compiler.bmg_types.is_atomic(t: beanmachine.ppl.compiler.bmg_types.BMGLatticeType) bool
beanmachine.ppl.compiler.bmg_types.is_convertible_to(source: beanmachine.ppl.compiler.bmg_types.BMGLatticeType, target: beanmachine.ppl.compiler.bmg_types.BMGLatticeType) bool
beanmachine.ppl.compiler.bmg_types.is_one(v: Any) bool
beanmachine.ppl.compiler.bmg_types.is_zero(v: Any) bool
beanmachine.ppl.compiler.bmg_types.lattice_to_bmg(t: beanmachine.ppl.compiler.bmg_types.BMGLatticeType) beanmachine.ppl.compiler.bmg_types.BMGLatticeType
beanmachine.ppl.compiler.bmg_types.must_be_matrix(r: Union[beanmachine.ppl.compiler.bmg_types.BMGLatticeType, beanmachine.ppl.compiler.bmg_types.BaseRequirement]) bool

Does the requirement indicate that the edge must be a matrix?

beanmachine.ppl.compiler.bmg_types.requirement_to_type(r: Union[beanmachine.ppl.compiler.bmg_types.BMGLatticeType, beanmachine.ppl.compiler.bmg_types.BaseRequirement]) beanmachine.ppl.compiler.bmg_types.BMGLatticeType
beanmachine.ppl.compiler.bmg_types.supremum(*ts: beanmachine.ppl.compiler.bmg_types.BMGLatticeType) beanmachine.ppl.compiler.bmg_types.BMGLatticeType

Takes any number of BMG types; returns the smallest type that is greater than or equal to all of them.

beanmachine.ppl.compiler.bmg_types.type_of_value(v: Any) beanmachine.ppl.compiler.bmg_types.BMGLatticeType

This computes the smallest BMG type that a given value fits into.

beanmachine.ppl.compiler.bmg_types.upper_bound(bound: Union[beanmachine.ppl.compiler.bmg_types.BMGLatticeType, beanmachine.ppl.compiler.bmg_types.BaseRequirement]) beanmachine.ppl.compiler.bmg_types.BaseRequirement