Skip to content

laser.core

laser.core

laser.core.LaserFrame(capacity, initial_count=-1, **kwargs)

The LaserFrame class, similar to a db table or a Pandas DataFrame, holds dynamically allocated data for agents (generally 1-D or scalar) or for nodes|patches (e.g., 1-D for scalar value per patch or 2-D for time-varying per patch).

Initialize a LaserFrame object.

Parameters:

Name Type Description Default
capacity int

The maximum capacity of the frame. Must be a positive integer.

required
initial_count int

The initial number of active elements in the frame. Must be a positive integer <= capacity.

-1
**kwargs dict

Additional keyword arguments to set as attributes of the object.

{}

Raises:

Type Description
ValueError

If capacity or initial_count is not a positive integer, or if initial_count is greater than capacity.

laser.core.LaserFrame.capacity property

Returns the capacity of the laser frame (total possible entries for dynamic properties).

Returns:

Name Type Description
int int

The capacity of the laser frame.

laser.core.LaserFrame.count property

Returns the current count (equivalent to len()).

Returns:

Name Type Description
int int

The current count value.

laser.core.LaserFrame.add(count)

Adds the specified count to the current count of the LaserFrame.

This method increments the internal count by the given count, ensuring that the total does not exceed the frame's capacity. If the addition would exceed the capacity, an assertion error is raised. This method is typically used to add new births during the simulation.

Parameters:

Name Type Description Default
count int

The number to add to the current count.

required

Returns:

Type Description
tuple[int, int]

tuple[int, int]: A tuple containing the [start index, end index) after the addition.

Raises:

Type Description
AssertionError

If the resulting count exceeds the frame's capacity.

laser.core.LaserFrame.add_array_property(name, shape, dtype=np.uint32, default=0)

Adds an array property to the object.

This method initializes a new property with the given name as a multi-dimensional NumPy array.

The array will have the given shape (note that there is no implied dimension of size self._capacity), datatype (default is np.uint32), and default value (default is 0).

Parameters:

Name Type Description Default
name str

The name of the property to be added.

required
shape tuple

The shape of the array.

required
dtype data - type

The desired data-type for the array, default is np.uint32.

uint32
default scalar

The default value to fill the array with, default is 0.

0

Returns:

Type Description
None

None

laser.core.LaserFrame.add_scalar_property(name, dtype=np.uint32, default=0)

Add a scalar property to the class.

This method initializes a new scalar property for the class instance. The property is stored as a 1-D NumPy array (scalar / entry) with a specified data type and default value.

Parameters:

Name Type Description Default
name str

The name of the scalar property to be added.

required
dtype data - type

The desired data type for the property. Default is np.uint32.

uint32
default scalar

The default value for the property. Default is 0.

0

Returns:

Type Description
None

None

laser.core.LaserFrame.add_vector_property(name, length, dtype=np.uint32, default=0)

Adds a vector property to the object.

This method initializes a new property with the given name as a 2-D NumPy array (vector per entry).

The array will have a shape of (length, self._capacity) and will be filled with the specified default value. The data type of the array elements is determined by the dtype parameter.

Parameters:

Name Type Description Default
name str

The name of the property to be added.

required
length int

The length of the vector.

required
dtype data - type

The desired data-type for the array, default is np.uint32.

uint32
default scalar

The default value to fill the array with, default is 0.

0

Returns:

Type Description
None

None

laser.core.LaserFrame.describe(target=None)

Return a formatted string description of the laserframe object, including its attributes and their values.

Parameters:

Name Type Description Default
target string

Optional string for the report header (generally the name of the LaserFrame variable, e.g., "People". Unlike functions, we can't get the name of a variable automatically).

None

Returns:

Name Type Description
str str

A formatted string describing the laserframe object, including its capacity, count, and details of its scalar, vector, and other properties.

laser.core.LaserFrame.load_snapshot(path, cbr, nt) classmethod

Load a LaserFrame and optional extras from an HDF5 snapshot file.

Parameters:

Name Type Description Default
path str

Path to the HDF5 snapshot file.

required
cbr ndarray

A 2D NumPy array of crude birth rates with shape (num_timesteps, num_nodes), in units of births per 1000 individuals per year. If provided, nt must also be provided, and capacity will be estimated to accommodate projected population growth. If None, capacity is set to the current count only.

required
nt int

Number of timesteps (days). Must be provided together with cbr, or both must be None.

required

Returns:

Name Type Description
frame LaserFrame

The loaded LaserFrame object.

results_r ndarray or None

A 2D array of recovered counts with shape (time, nodes), or None if not present in the snapshot.

pars dict

Dictionary of model parameters stored in the snapshot, or empty if none are found.

Raises:

Type Description
ValueError

If only one of cbr or nt is provided.

ValueError

If required fields (like 'node_id') are missing.

ValueError

If array shapes do not align across cbr, recovered, and node_id.

Notes
  • Snapshots must contain a per-agent 'node_id' property.
  • The recovered array is assumed to be in (time, node) layout.
  • The capacity estimate includes both current and recovered agents at t=0.

laser.core.LaserFrame.save_snapshot(path, results_r=None, pars=None)

Save this LaserFrame and optional extras to an HDF5 snapshot file.

Parameters:

Name Type Description Default
path Path

Destination file path

required
results_r ndarray

Optional 2D numpy array of recovered counts

None
pars PropertySet or dict

Optional PropertySet or dict of parameters

None

laser.core.LaserFrame.sort(indices, verbose=False)

Sorts the elements of the object's numpy arrays based on the provided indices.

Parameters:

Name Type Description Default
indices ndarray

An array of indices used to sort the numpy arrays. Must be of integer type and have the same length as the frame count (self._count).

required
verbose bool

If True, prints the sorting progress for each numpy array attribute. Defaults to False.

False

Raises:

Type Description
AssertionError

If indices is not an integer array or if its length does not match the frame count of active elements.

laser.core.LaserFrame.squash(indices, verbose=False)

Reduces the active count of the internal numpy arrays keeping only elements True in the provided boolean indices.

Parameters:

Name Type Description Default
indices ndarray

A boolean array indicating which elements to keep. Must have the same length as the current frame active element count.

required
verbose bool

If True, prints detailed information about the squashing process. Defaults to False.

False

Raises:

Type Description
AssertionError

If indices is not a boolean array or if its length does not match the current frame active element count.

Returns:

Type Description
None

None

laser.core.PropertySet(*bags)

A class that can be used to store properties in a dictionary-like object with .property access to properties.

Examples

Basic Initialization:

::

1
2
3
4
5
6
from laser.core import PropertySet
ps = PropertySet()
ps['infection_status'] = 'infected'
ps['age'] = 35
print(ps.infection_status)  # Outputs: 'infected'
print(ps['age'])            # Outputs: 35

Combining two PropertySets:

::

1
2
3
4
5
ps1 = PropertySet({'immunity': 'high', 'region': 'north'})
ps2 = PropertySet({'infectivity': 0.7})
combined_ps = ps1 + ps2
print(combined_ps.to_dict())
# Outputs: {'immunity': 'high', 'region': 'north', 'infectivity': 0.7}

Creating a PropertySet from a dictionary:

::

1
2
3
4
5
ps = PropertySet({'mything': 0.4, 'that_other_thing': 42})
print(ps.mything)            # Outputs: 0.4
print(ps.that_other_thing)   # Outputs: 42
print(ps.to_dict())
# Outputs: {'mything': 0.4, 'that_other_thing': 42}

Save and load:

::

1
2
3
ps.save('properties.json')
loaded_ps = PropertySet.load('properties.json')
print(loaded_ps.to_dict())  # Outputs the saved properties

Property access and length:

::

1
2
3
4
ps['status'] = 'susceptible'
ps['exposure_timer'] = 5
print(ps['status'])          # Outputs: 'susceptible'
print(len(ps))               # Outputs: 4

In-Place addition (added keys must not exist in the destination PropertySet):

::

1
2
3
ps += {'new_timer': 10, 'susceptibility': 0.75}
print(ps.to_dict())
# Outputs: {'mything': 0.4, 'that_other_thing': 42, 'status': 'susceptible', 'exposure_timer': 5, 'new_timer': 10, 'susceptibility': 0.75}

In-place update (keys must already exist in the destination PropertySet):

::

1
2
3
ps <<= {'exposure_timer': 10, 'infectivity': 0.8}
print(ps.to_dict())
# Outputs: {'mything': 0.4, 'that_other_thing': 42, 'status': 'susceptible', 'exposure_timer': 10, 'infectivity': 0.8}

In-place addition or update (no restriction on incoming keys):

::

1
2
3
ps |= {'new_timer': 10, 'exposure_timer': 8}
print(ps.to_dict())
# Outputs: {'mything': 0.4, 'that_other_thing': 42, 'status': 'susceptible', 'exposure_timer': 8, 'new_timer': 10}

Initialize a PropertySet to manage properties in a dictionary-like structure.

Parameters:

Name Type Description Default
bags Union[PropertySet, list, tuple, dict]

A sequence of key-value pairs (e.g., lists, tuples, dictionaries) to initialize the PropertySet. Keys must be strings, and values can be any type.

()

laser.core.PropertySet.__add__(other)

Add another PropertySet to this PropertySet.

This method allows the use of the + operator to combine two PropertySet instances.

Parameters:

Name Type Description Default
other PropertySet

The other PropertySet instance to add.

required

Returns:

Name Type Description
PropertySet PropertySet

A new PropertySet instance that combines the properties of both instances.

laser.core.PropertySet.__contains__(key)

Check if a key is in the property set.

Parameters:

Name Type Description Default
key str

The key to check for existence in the property set.

required

Returns:

Name Type Description
bool bool

True if the key exists in the property set, False otherwise.

laser.core.PropertySet.__eq__(other)

Check if two PropertySet instances are equal.

Parameters:

Name Type Description Default
other PropertySet

The other PropertySet instance to compare.

required

Returns:

Name Type Description
bool bool

True if the two instances are equal, False otherwise.

laser.core.PropertySet.__getitem__(key)

Retrieve the attribute of the object with the given key (e.g., ps[key]).

Parameters:

Name Type Description Default
key str

The name of the attribute to retrieve.

required

Returns:

Name Type Description
Any any

The value of the attribute with the specified key.

Raises:

Type Description
AttributeError

If the attribute with the specified key does not exist.

laser.core.PropertySet.__iadd__(other)

Implements the in-place addition (+=) operator for the class.

This method allows the instance to be updated with attributes from another instance of the same class or from a dictionary. If other is an instance of the same class, its attributes are copied to the current instance. If other is a dictionary, its key-value pairs are added as attributes to the current instance.

Parameters:

Name Type Description Default
other Union[type(self), dict]

The object or dictionary to add to the current instance.

required

Returns:

Name Type Description
self PropertySet

The updated instance with the new attributes.

Raises:

Type Description
AssertionError

If other is neither an instance of the same class nor a dictionary.

ValueError

If other contains keys already present in the PropertySet.

laser.core.PropertySet.__ilshift__(other)

Implements the <<= operator on PropertySet to override existing values with new values.

Parameters:

Name Type Description Default
other Union[type(self), dict]

The object or dictionary with overriding values.

required

Returns:

Name Type Description
self PropertySet

The updated instance with the overrides from other.

Raises:

Type Description
AssertionError

If other is neither an instance of the same class nor a dictionary.

ValueError

If other contains keys not present in the PropertySet.

laser.core.PropertySet.__ior__(other)

Implements the |= operator on PropertySet to override existing values with new values.

Parameters:

Name Type Description Default
other Union[type(self), dict]

The object or dictionary with overriding values.

required

Returns:

Name Type Description
self PropertySet

The updated instance with all the values of self with new or overriding values from other.

Raises:

Type Description
AssertionError

If other is neither an instance of the same class nor a dictionary.

laser.core.PropertySet.__len__()

Return the number of attributes in the instance.

This method returns the number of attributes stored in the instance's dict attribute, which represents the instance's namespace.

Returns:

Name Type Description
int int

The number of attributes in the instance.

laser.core.PropertySet.__lshift__(other)

Implements the << operator on PropertySet to override existing values with new values.

Parameters:

Name Type Description Default
other Union[type(self), dict]

The object or dictionary with overriding values.

required

Returns:

Name Type Description
PropertySet PropertySet

A new PropertySet with all the values of the first PropertySet with overrides from the second PropertySet.

Raises:

Type Description
AssertionError

If other is neither an instance of the same class nor a dictionary.

ValueError

If other contains keys not present in the PropertySet.

laser.core.PropertySet.__or__(other)

Implements the | operator on PropertySet to add new or override existing values with new values.

Parameters:

Name Type Description Default
other Union[type(self), dict]

The object or dictionary with overriding values.

required

Returns:

Name Type Description
PropertySet PropertySet

A new PropertySet with all the values of the first PropertySet with new or overriding values from the second PropertySet.

Raises:

Type Description
AssertionError

If other is neither an instance of the same class nor a dictionary.

laser.core.PropertySet.__repr__()

Return a string representation of the PropertySet instance.

The string representation includes the class name and the dictionary of the instance's attributes.

Returns:

Name Type Description
str str

A string representation of the PropertySet instance.

laser.core.PropertySet.__setitem__(key, value)

Set the value of an attribute. This method allows setting an attribute of the instance using the dictionary-like syntax (e.g., ps[key] = value).

Parameters:

Name Type Description Default
key str

The name of the attribute to set.

required
value any

The value to set for the attribute.

required

laser.core.PropertySet.__str__()

Returns a string representation of the object's dictionary.

This method is used to provide a human-readable string representation of the object, which includes all the attributes stored in the object's __dict__.

Returns:

Name Type Description
str str

A string representation of the object's dictionary.

laser.core.PropertySet.load(filename) staticmethod

Load a PropertySet from a specified file.

Parameters:

Name Type Description Default
filename str

The path to the file where the PropertySet is saved.

required

Returns:

Name Type Description
PropertySet PropertySet

The PropertySet instance loaded from the file.

laser.core.PropertySet.save(filename)

Save the PropertySet to a specified file.

Parameters:

Name Type Description Default
filename str

The path to the file where the PropertySet will be saved.

required

laser.core.PropertySet.to_dict()

Convert the PropertySet to a dictionary.

laser.core.SortedQueue(capacity, values)

A sorted (priority) queue implemented using NumPy arrays and sped-up with Numba.

Using the algorithm from the Python heapq module.

init with an existing array of sorting values

push with an index into sorting values

pop returns the index of the lowest sorting value and its value

Initializes a new instance of the class with a specified capacity and reference to existing, sortable values.

This implementation is specific to LASER and the expectation of tracking 10s or 100s of millions of agents.

We expect the sortable (or priority) values to already be in a NumPy array, usually a property of a LaserFrame object.

The push() and pop() will take indices into this array and will sort on values[i]. This avoids making copies of the sort values.

Parameters:

Name Type Description Default
capacity int

The maximum number of elements the queue can hold.

required
values ndarray

A reference to an array of values to be accessed by the queue.

required

laser.core.SortedQueue.__len__()

Return the number of elements in the sorted queue.

Returns:

Name Type Description
int int

The number of elements in the sorted queue.

laser.core.SortedQueue.__pop()

Removes the smallest value element from the sorted queue.

Raises:

Type Description
IndexError

If the sorted queue is empty.

Side effects
  • Decreases the size of the sorted queue by one.
  • Reorganizes the internal structure of the sorted queue to maintain the heap property.

laser.core.SortedQueue.peeki()

Returns the index of the smallest value element in the sorted queue without removing it.

Raises:

Type Description
IndexError

If the sorted queue is empty.

Returns:

Type Description
uint32

np.uint32: The index of the smallest value element.

laser.core.SortedQueue.peekiv()

Returns the index and value of the smallest value element in the sorted queue without removing it.

Returns:

Type Description
tuple[uint32, Any]

tuple[np.uint32, Any]: A tuple containing the index and value of the smallest value element.

Raises:

Type Description
IndexError

If the sorted queue is empty.

laser.core.SortedQueue.peekv()

Return the smallest value from the sorted queue without removing it.

Raises:

Type Description
IndexError

If the sorted queue is empty.

Returns:

Name Type Description
Any Any

The value with the smallest value in the sorted queue.

laser.core.SortedQueue.popi()

Removes and returns the index of the smallest value element in the sorted queue.

This method first retrieves the index of the smallest value element using peeki(), then removes the element from the queue using pop(), and finally returns the index.

Returns:

Type Description
uint32

np.uint32: The index of the smallest value element in the sorted queue.

laser.core.SortedQueue.popiv()

Removes and returns the index and value of the smallest value element in the sorted queue.

This method first retrieves the index and value of the smallest value element using peekiv(), then removes the element from the queue using pop(), and finally returns the index and value.

Returns:

Type Description
tuple[uint32, Any]

tuple[np.uint32, Any]: A tuple containing the index and value of the smallest value element.

laser.core.SortedQueue.popv()

Removes and returns the value at the front of the sorted queue.

This method first retrieves the value at the front of the queue without removing it by calling peekv(), and then removes the front element from the queue by calling pop(). The retrieved value is then returned.

Returns:

Name Type Description
Any Any

The value at the front of the sorted queue.

laser.core.SortedQueue.push(index)

Insert an element into the sorted queue.

This method adds an element at the back of the sorted queue and then ensures the heap property is maintained by sifting the element forward to its correct position.

Parameters:

Name Type Description Default
index int

The index of the element to be added to the sorted queue.

required

Raises:

Type Description
IndexError

If the sorted queue is full.