silvio package

Submodules

silvio.config module

silvio.config.DATADIR = PosixPath('/home/docs/checkouts/readthedocs.org/user_builds/silvio/checkouts/latest/src/silvio/data')

silvio.events module

Events that serve as communication for and between host modules.

class silvio.events.Event[source]

Bases: abc.ABC

Events are changes to the Host that will be handled by the Modules.

_abc_impl = <_abc._abc_data object>
silvio.events.EventEmitter = typing.Callable[[silvio.events.Event], NoneType]
silvio.events.EventLogger = typing.Callable[[str], NoneType]

silvio.experiment module

Experiment is the top-most scope. It includes all hosts and registries and acts as a global namespace.

class silvio.experiment.Experiment(seed: Union[int, numpy.random.bit_generator.SeedSequence, None] = None)[source]

Bases: abc.ABC

The basic experiment will hold the hosts and a random-generator.

_abc_impl = <_abc._abc_data object>
bind_host(host: silvio.host.Host) → None[source]

Keep the host accessible via the experiment.

exception silvio.experiment.ExperimentException[source]

Bases: Exception

Exception that is triggered by an experiment.

silvio.host module

An host is a unit that can take in any number of host modules. It serves as the container of all modules and allows for obverser-event communication between the modules. In addition, it is capable of properly copying itself and it’s modules. It also provides some facilities for pseudo-random generation to allow deterministic generation.

In technical terms, the Host uses composition-over-inheritance to define all behaviours that Modules may add to it. In addition to the usual forwarding methods, the Host is also an observable that can be used by each module to communicate with other modules.

class silvio.host.Host(ref: Optional[Host] = None, name: str = None, seed: Optional[int] = None, **kwargs)[source]

Bases: abc.ABC

A host usually contains 3 types of content:

  • core params : Parameters that are used by all hosts.
  • modules : Zero or more modules inside the host.
  • extra params : Zero or more extra params used by the host extension.

Host creation happens can happen in 2 variations of steps:

  • make > sync
  • copy

The steps are responsible for:

  • make : The initial params are set for a host created from scratch. The extending host
  • copy : The complete (copies have no sync step) params are set using another host as reference.
  • sync : The host call out each module to sync.
_abc_impl = <_abc._abc_data object>
build_clone_attrs() → [<class 'str'>, <class 'int'>][source]

Generate attributes for a possible clone.

[ name, seed ]
name: A hierarchical name is generated. seed: A stable seed is generated.
copy(ref: silvio.host.Host) → None[source]

Make a copy of the host params and modules by using another similar Host as a reference. The code inside this method should provide a good copy where shallow and deep copies are used appropriately.

Extending Hosts should have the following structure on their method:

emit(event: silvio.events.Event, chain: List[silvio.host.ListenerEntry] = []) → None[source]

Trigger all listeners for a given Event.

Uses a chain of listener entries to keep track of which has already been called and to abort loops that may result. Each listener callback may only execute once for each event chain.

The Host also provides an EventEmitter to each listener callback in order to hide the functionality of listener chains from the modules. If they want to emit events they need to use the method provided by the host.

log(text: str, depth: Optional[int] = 1) → None[source]

Log a message in the event log.

make() → None[source]

Make a new host from scratch with the help of arguments. Set possible params and modules.

Extending Host should have the following structure on their method:

make_generator() → silvio.random.Generator[source]

Construct a random number generator with the same seed stored in the host.

observe(evtype: Type[silvio.events.Event], run: Callable[[silvio.events.Event, Callable[[silvio.events.Event], None], Callable[[str], None]], Optional[str]]) → None[source]

Bind a new listener for a type of event.

print_event_log() → None[source]
sync() → None[source]

Run the sync procedure on this host. It usually only calls the sync of each module using a helper method for that.

Extending Hosts should have the following structure on their method:

sync_modules(modules: List[Module]) → None[source]

Sync all modules as modules may emit some events or do load up calculations when they start. After creating all modules you should call this method with those modules. This cannot be included inside the module __init__ because all listeners have to be set.

exception silvio.host.HostException[source]

Bases: Exception

Exception that is triggered when a Host cannot be created.

class silvio.host.ListenerEntry(evtype, run)[source]

Bases: tuple

_asdict()

Return a new dict which maps field names to their values.

_field_defaults = {}
_fields = ('evtype', 'run')
classmethod _make(iterable)

Make a new ListenerEntry object from a sequence or iterable

_replace(**kwds)

Return a new ListenerEntry object replacing specified fields with new values

evtype

Alias for field number 0

run

Alias for field number 1

silvio.module module

A Module is an extension of behaviour that can be attached to an Host.

class silvio.module.Module[source]

Bases: abc.ABC

A module usually contains 3 types of content:

  • host : The host this module belongs to.
  • deps* : Zero or more dependent modules this module is using.
  • params* : Zero or more params to build this module.

Module creation happens can happen in 2 variations of steps:

  • make > bind > sync
  • copy > bind

The steps are responsible for:

  • make : The initial params are set for a module created from scratch.
  • copy : The complete (copies have no sync step) params are set using another module as reference.
  • bind : The host and deps are set.
  • sync : The module executes a startup method that may include sending out events and
    using the dependent modules to initiate some data.
_abc_impl = <_abc._abc_data object>
bind(host: Host) → None[source]

Bind this module to its host and deps (dependent modules). Here, the event listeners should also be set.

Extending Modules should have the following structure on their method:

def bind ( self, host, req_mod_1, req_mod_2, ... ) -> None :
    self.host = host
    self.req_mod_1 = req_mod_1
    self.req_mod_2 = req_mod_2
    self.host.observe( EventTypeA, self.listen_event_a )
    self.host.observe( EventTypeB, self.listen_event_b )
copy(ref: silvio.module.Module) → None[source]

Make a copy of the module params by using another similar Module as a reference. The code inside this method should provide a good copy where shallow and deep copies are used appropriately.

Extending Modules should have the following structure on their method:

def copy ( self, ref ) -> None :
    self.simple_param_1 = ref.simple_param_1
    self.complex_model_1 = copy(ref.complex_model_1)
make() → None[source]

Make a new module from scratch with the help of arguments. This will only set the params.

Extending Modules should have the following structure on their method:

def make ( self, param_1, param_2, ... ) -> None :
    self.param_1 = param_1
    self.model_1 = load_model(param1)
    self.param_2 = param_2
sync(emit: Callable[[silvio.events.Event], None], log: Callable[[str], None]) → None[source]

Run the sync procedure on this module. This usually means dispatching some events after the module is made and all other modules have been bound and are listening to event emitters.

Extending Modules should have the following structure on their method:

def sync ( self, emit, log ) -> None :
    log("ModuleX: start sync")
    emit( EventTypeA( event_args ) )
    for i in self.items :
        emit( EventTypeB( event_args_i ) )
exception silvio.module.ModuleException[source]

Bases: Exception

Exception that is triggered when a module cannot be created.

silvio.outcome module

class silvio.outcome.DataOutcome(value: Union[pandas.core.frame.DataFrame, pandas.core.series.Series], error: Optional[str] = None)[source]

Bases: silvio.outcome.Outcome

Holds the dataframe of a simulation. Has methods to access whether it worked successfully, to print the data or to store it in files.

display_data() → None[source]
export_data(filepath) → None[source]
class silvio.outcome.DataWithPlotOutcome(value: Union[pandas.core.frame.DataFrame, pandas.core.series.Series], error: Optional[str] = None)[source]

Bases: silvio.outcome.DataOutcome

display_plot() → None[source]
export_plot(filepath) → None[source]
make_plot() → matplotlib.figure.Figure[source]

Plotting with pyplot is unfortunately unintuitive. You cannot display a single figure by using the object-oriented API. When you do plt.subplots (or create a plot by any other means) it will be stored in the global context. You can only display things from the glbbal context, and displaying it will remove it from there.

class silvio.outcome.Outcome(value: Value, error: Optional[str] = None)[source]

Bases: typing.Generic

Return from operations with any type of result.

error = None
has_error() → bool[source]
succeeded() → bool[source]
exception silvio.outcome.SimulationException[source]

Bases: Exception

Base class for all simulation exceptions.

silvio.outcome.combine_data(outcomes: List[silvio.outcome.DataOutcome]) → silvio.outcome.DataOutcome[source]

Combine multiple DataOutcome into one big table. Can combine multiple Series and Dataframes. TODO: Should it extract the error of each outcome? Right now it is being ignored.

silvio.random module

All operations that generate random numbers may come from this globally defined random generator.

This allows the user to provide a seed and generate the same sequences on every run as long as requests are made in the same order.

The methods it exposes are the same of those from a numpy Generator object, but with typing and slightly altered parameters. https://numpy.org/doc/stable/reference/random/generator.html#numpy.random.Generator

class silvio.random.Generator(seed: Optional[int] = None)[source]

Bases: object

All random methods also exist inside a local generator object.

pick_choices(choices: List[T], amount: int, weights: List[float] = None) → List[T][source]
pick_exponential(beta: float) → float[source]
pick_integer(low: int, high: int) → int[source]
pick_normal(mean: float = 0, sd: float = 0) → float[source]
pick_samples(choices: List[T], amount: int) → List[T][source]
pick_seed() → int[source]
pick_uniform(low: float = 0, high: float = 1) → float[source]
silvio.random.pick_choices(choices: List[T], amount: int, weights: List[float] = None) → List[T][source]

Pick a single value out of a provided list. Can receive a non-normalized weights.

silvio.random.pick_exponential(beta: float) → float[source]

Pick a single number from an exponential distribution.

silvio.random.pick_integer(low: int, high: int) → int[source]

Pick a single integer from a range from low (inclusive) to high (exclusive).

silvio.random.pick_normal(mean: float = 0, sd: float = 0) → float[source]

Pick a single number from a normal distribution.

silvio.random.pick_samples(choices: List[T], amount: int) → List[T][source]

Pick a sample (without repetition) from choices.

silvio.random.pick_seed() → int[source]

Pick a new number that is usable as a seed.

silvio.random.pick_uniform(low: float = 0, high: float = 1) → float[source]

Pick a single float from an uniform distribution between low (inclusive) and high (exclusive).

silvio.random.set_seed(new_seed: int) → None[source]

Sets the seed of the global random generator so that all future random picks follow the same pseudo-random sequence.

silvio.record module

class silvio.record.Record[source]

Bases: abc.ABC

Record is a piece of information that can be indexed in a Registry.

_abc_impl = <_abc._abc_data object>

silvio.registry module

Registries provide an efficient way to store Records that are used by multiple Hosts. That way, each host only needs to store a reference to each registered object (for example a gene) instead to storing and copying the entire gene. When editing an object in the registry, the editor should make sure to practice copy-on-write.

Entries of a registry must be copy-able.

class silvio.registry.Registry[source]

Bases: object

A Registry holds multiple Entries.

clone(rec: silvio.record.Record) → silvio.record.Record[source]

Clone a Record inside the Registry and return it.

insert(rec: silvio.record.Record) → None[source]

Insert a new record into the Registry.

silvio.tool module

Tools are long-standing objects that have to be initialized and that perform calculations on other low-level values, such as sequences, matches, etc.

This class provides some common facilities such as stable randomization.

class silvio.tool.Tool(name: str = None, seed: Optional[int] = None)[source]

Bases: object

The Tool base class includes some basic blocks to enable a stable randomization.

make_generator() → silvio.random.Generator[source]

Construct a random number generator with the same seed stored in the host.

exception silvio.tool.ToolException[source]

Bases: Exception

Exception that is triggered when a Tool has a problem.

silvio.utils module

Contains various utility methods.

silvio.utils.alldef(*arg) → bool[source]

Returns true if all arguments are non-None.

silvio.utils.coalesce(*arg) → Any[source]

Return the first non-null argument given. Emulates a nullish coalesce operator (PEP 505).

silvio.utils.first(array: List[T], criteria: Callable[[T], bool]) → Optional[T][source]

Return the first item that validates the criteria.