Registry of Updaters, Dividers, and Serializers

You should interpret words and phrases that appear fully capitalized in this document as described in RFC 2119. Here is a brief summary of the RFC:

  • “MUST” indicates absolute requirements. Vivarium may not work correctly if you don’t follow these.

  • “SHOULD” indicates strong suggestions. You might have a valid reason for deviating from them, but be careful that you understand the ramifications.

  • “MAY” indicates truly optional features that you can include or exclude as you wish.

Updaters

Each updater is defined as a function whose name begins with update_. Vivarium uses these functions to apply updates to variables. Updater names are registered in updater_registry, which maps these names to updater functions.

Updater API

An updater function SHOULD have a name that begins with update_. The function MUST accept exactly three positional arguments: the first MUST be the current value of the variable (i.e. before applying the update), the second MUST be the value associated with the variable in the update, and the third MUST be either a dictionary of states from the simulation hierarchy or None if no port_mapping key was specified in the updater definition. The function SHOULD not accept any other parameters. The function MUST return the updated value of the variable only.

Dividers

Each divider is defined by a function that follows the API we describe below. Vivarium uses these dividers to generate daughter cell states from the mother cell’s state. Divider names are registered in divider_registry, which maps these names to divider functions.

Divider API

Each divider function SHOULD have a name prefixed with divide_. The function MUST accept a single positional argument, the value of the variable in the mother cell. It SHOULD accept no other arguments. The function MUST return either:

  1. A list with two elements: the values of the variables in each of the daughter cells.

  2. None, in which case division will be skipped for that variable.

Note

Dividers MAY not be deterministic and MAY not be symmetric. For example, a divider splitting an odd, integer-valued value may randomly decide which daughter cell receives the remainder.

Serializers

Each serializer is defined as a class that follows the API we describe below. Vivarium uses these serializers to convert emitted data into a BSON-compatible format for database storage. Serializer names are registered in serializer_registry, which maps these names to serializer subclasses.

Serializer API

For maximum performance, serializers SHOULD represent a 1-to-1 mapping between Python and BSON types. These types of serializers MUST each define the following:

  1. One or more class attributes of the type bson.codec_options.TypeCodec or one of its subclasses

  2. The vivarium.core.registry.Serializer.get_codecs() method

If it is necessary to serialize objects of the same Python type differently, assign custom serializers to the stores containing objects of the affected type(s) using the _serializer ports schema key. The best practice is to define a TypeCodec-based serializer to handle a given type and only make use of the _serializer key for rare exceptions to the rule. Serializer(s) for these exceptions MUST override:

  1. vivarium.core.registry.Serializer.serialize(),

  2. vivarium.core.registry.Serializer.can_deserialize()

  3. vivarium.core.registry.Serializer.deserialize()

If it is necessary to deserialize objects of the same BSON type differently, the corresponding serializer(s) MUST override:

  1. vivarium.core.registry.Serializer.can_deserialize()

  2. vivarium.core.registry.Serializer.deserialize()

class vivarium.core.registry.Registry[source]

Bases: object

A Registry holds a collection of functions or objects.

access(key)[source]

Get an item by key from the registry.

list()[source]
register(key, item, alternate_keys=())[source]

Add an item to the registry.

Parameters
  • key – Item key.

  • item – The item to add.

  • alternate_keys

    Additional keys under which to register the item. These keys will not be included in the list returned by Registry.list().

    This may be useful if you want to be able to look up an item in the registry under multiple keys.

class vivarium.core.registry.Serializer(name='')[source]

Bases: object

Base serializer class.

Serializers work together to convert Python objects, which may be collections of many different kinds of objects, into BSON-compatible representations. Those representations can then be deserialized to recover the original object.

Serializers should define one or more class attributes of the type bson.codec_options.TypeCodec. If a store is assigned a custom serializer using the _serializer key, serialization occurs instead via the vivarium.core.registry.Serializer.serialize() method and will be much slower.

Deserialization is handled by PyMongo if the included codecs have the bson_type attribute and transform_bson() method. If not, the vivarium.core.registry.Serializer.deserialize() method is called instead and will be much slower.

Parameters

name – Name of the serializer. Defaults to the class name.

can_deserialize(data)[source]

This tells vivarium.core.serialize.deserialize_value() whether to call deserialize on data. It should only be overridden if the serialize method was also overridden.

deserialize(data)[source]

This allows for data of the same BSON type to be deserialized differently (see regex matching of strings in vivarium.core.serialize.UnitsSerializer.deserialize() for an example). This should only be overridden if the serialize method was also overridden.

get_codecs()[source]

Get list of codecs in serializer. Codecs are class attributes of type bson.codec_options.TypeCodec that are used by PyMongo to serialize and (optionally) deserialize data.

serialize(data)[source]

This should only overridden in the case that individual stores are assigned custom serializers. For maximum performance, serialization should be left to PyMongo instead of calling this function.

Note that the values returned by this method later undergo another round of serialization under PyMongo’s codec system. This could cause unexpected behavior if serialize returns data of a type that is handled by another codec. The best practice would be for serialize to always return data of a built-in type.

vivarium.core.registry.assert_no_divide(state)[source]

Assert that the variable is never divided

Raises

AssertionError – If the variable is divided

vivarium.core.registry.divide_binomial(state)[source]

Binomial Divider

vivarium.core.registry.divide_null(state)[source]

Divider that causes the variable to be skipped during division.

Returns

None so that no divided values are provided to the daughter cells. This is useful for process objects, which are handled separately during division.

vivarium.core.registry.divide_set(state)[source]

Set Divider

Returns

A list [state, state]. No copying is performed.

vivarium.core.registry.divide_set_value(state, config)[source]

Set Value Divider :param ‘state’: value

Returns

A list [value, value]. No copying is performed.

vivarium.core.registry.divide_split(state)[source]

Split Divider

Parameters

state – Must be an int, a float, or a str of value Infinity.

Returns

A list, each of whose elements contains half of state. If state is an int, the remainder is placed at random in one of the two elements. If state is infinite, the return value is [state, state] (no copying is done).

Raises

Exception – if state is of an unrecognized type.

vivarium.core.registry.divide_split_dict(state)[source]

Split-Dictionary Divider

Returns

A list of two dictionaries. The first dictionary stores the first half of the key-value pairs in state, and the second dictionary stores the rest of the key-value pairs.

Note

Since dictionaries are unordered, you should avoid making any assumptions about which keys will be sent to which daughter cell.

vivarium.core.registry.divide_zero(state)[source]

Zero Divider

Returns

[0, 0] regardless of input

vivarium.core.registry.divider_registry = <vivarium.core.registry.Registry object>

Map divider names to divider functions

vivarium.core.registry.emitter_registry = <vivarium.core.registry.Registry object>

Map serializer names to Emitter classes

vivarium.core.registry.process_registry = <vivarium.core.registry.Registry object>

Maps process names to process classes

vivarium.core.registry.serializer_registry = <vivarium.core.registry.Registry object>

Map serializer names to serializer classes

vivarium.core.registry.update_accumulate(current_value, new_value)[source]

Accumulate Updater

Returns

The sum of current_value and new_value.

vivarium.core.registry.update_dictionary(current, update)[source]

Dictionary Updater Updater that translates _add and _delete -style updates into operations on a dictionary.

Expects current to be a dictionary, with no restriction on the types of objects stored within it, and no defaults values.

vivarium.core.registry.update_merge(current_value, new_value)[source]

Merge Updater

Returns

The merger of current_value and new_value. For any shared keys, the value in new_value is used.

Return type

dict

vivarium.core.registry.update_nonnegative_accumulate(current_value, new_value)[source]

Non-negative Accumulate Updater

Returns

The sum of current_value and new_value if positive, 0 if negative.

vivarium.core.registry.update_null(current_value, new_value)[source]

Null Updater

Returns

The value provided in current_value.

vivarium.core.registry.update_set(current_value, new_value)[source]

Set Updater

Returns

The value provided in new_value.

vivarium.core.registry.updater_registry = <vivarium.core.registry.Registry object>

Map updater names to updater functions