Producer#

relationalai
class Producer

Instances of the Producer class act as variables in a rule or query context. When the context is evaluated, all possible values for the variable are produced. Instead of constructing Producer instances directly, they are returned as the result of various operations.

The Producer class is the base class for different kinds of producers, including:

Methods#

The following methods support mathematical operations on producers:

NameDescriptionReturns
__add__()Supports the + operator between producers and other values.Expression
__sub__()Supports the - operator between producers and other values.Expression
__mul__()Supports the * operator between producers and other values.Expression
__truediv__()Supports the / operator between producers and other values.Expression
__floordiv__()Supports the // operator between producers and other values.Expression
__pow__()Supports the ** operator between producers and other values.Expression
__mod__()Supports the % operator between producers and other values.Expression

The following methods support comparison operations on producers:

NameDescriptionReturns
__eq__()Supports == comparison between producers and other values.Expression
__ne__()Supports != comparison between producers and other values.Expression
__ge__()Supports >= comparison between producers and other values.Expression
__gt__()Supports > comparison between producers and other values.Expression
__le__()Supports <= comparison between producers and other values.Expression
__lt__()Supports < comparison between producers and other values.Expression

Instances of Producer support arbitrary attribute access and can be used as a context manager in a with statement:

NameDescriptionReturns
__getattribute__()Get a property of an object.InstanceProperty
__enter__()Enter the producer’s context.None
__exit__()Exit the producer’s context.None

Example#

The key idea behind the Producer class is that it is used to represent a variable in a rule or query context:

import relationalai as rai

# Create a model named 'people' with Person and Adult types.
model = rai.Model("people")
Person = model.Type("Person")
Adult = model.Type("Adult")

# Add some people to the model.
with model.rule():
    # Type.add() returns an Instance, which is a producer.
    alice = Person.add(name="Alice", age=8)
    bob = Person.add(name="Bob", age=36)
    # Instance producers have a .set() method for setting properties and
    # additional types on objects.
    bob.set(parent_of=alice)


# Create a rule that sets the Adult type on each person whose age is at least 18.
with model.rule():
    # Calling a type returns an Instance producer.
    person = Person()  # person produces Person objects.
    # person.age returns an InstanceProperty, which is also a producer.
    # Comparing the age to 18 returns an Expression, yet another producer.
    person.age >= 18  # Filter to people who are 18 or older.
    person.set(Adult)  # Set the adult type on the people who pass the filter.

You can think of the rule as executing once for each Person object in the model. Each line in the rule describes a step in a pipeline that the objects produced by person pass through:

  1. person Produces a Person object.
  2. person.age >= 18 only lets through objects with an age of 18 or more.
  3. person.set(Adult) sets the Adult type on the objects that pass through.

The object for Alice never reaches the last step because her age is less than 18. But the object for Bob does reach the last step, and the Adult type is set on it.

Multiple producers may be mixed in the same rule or query:

# Get pairs of people where the first person is younger than the second.
with model.query() as select:
    person1, person2 = Person(), Person()
    person1.age < person2.age
    response = select(person1.name, person2.name)

print(response.results)
# Output:
#    name1  name2
# 0  Alice    Bob

Both person1 and person2 produce Person objects. The query is evaluated for each pair of possible values for person1 and person2, of which there are four:

Only the pair (Alice, Bob) passes through the comparison and into select() since Alice is 8 and Bob is 36.

Producers can be used as context managers. This is especially useful for Expression producers, which can be used to create a subcontext that applies to a subset of objects:

Minor = model.Type("Minor")

with model.rule():
    person = Person()
    # If the person's age is less than 18, set the Minor type.
    with person.age < 18:
        person.set(Minor)
    # If the person's age is at least 18, set the Adult type.
    with person.age >= 18
        person.set(Adult)

Thinking of the rule as a pipeline, the with statement creates a subcontext whose contents only apply to objects for which the Expression is true, but doesn’t block objects from passing through to the rest of the rule.

For example, the Alice object passes through the first with statement and gets the Minor type set on it since she is 8. Her object still passes through to the second with statement, but the Adult type is not set on her because the expression is false. Bob, on the other hand, passes through the first with statement without setting the Minor type, but the Adult type is set on him in the second with statement.

See Also#