Diamond inheritance demonstration

This notebook demonstrates creating a hybrid acceleration engine from two engines. This is a necessary step in order to compose the functionality of multiple acceleration engines, because coheriq allows at most a single engine to be active per domain.

This example is contrived in the sense that the intended behavior of the function changes when acceleration is enabled. This is used to demonstrate the general workings of code replacement, even though the general goal of coheriq is not to change the end-user results, but rather to accelerate a calculation with the goal of obtaining the same results.

Domain (addon) code

In the case of this example, there are two functions that are marked as candidates for acceleration, along with their default implementations.

[ ]:
from coheriq import AccelerationDomain

_domain = AccelerationDomain("mylib-foo")
_acceleration_candidate = _domain.acceleration_candidate


@_acceleration_candidate
def approximate_pi():
    return 3.14


@_acceleration_candidate
def approximate_e():
    return 2.72


_domain.materialize()

Acceleration engine 1 code

[2]:
from coheriq import AccelerationEngine

_engine = AccelerationEngine("mylib-foo", "bar")
_override = _engine.override


@_override(name="approximate_pi")
def approximate_pi_hpc():
    from math import pi

    return pi


_engine.materialize()

Acceleration engine 2 code

[3]:
_engine = AccelerationEngine("mylib-foo", "baz")
_override = _engine.override


@_override(name="approximate_e")
def approximate_e_hpc():
    from math import e

    return e


_engine.materialize()

Define a hybrid engine

Because only a single engine can be activated …

[4]:
_engine3 = AccelerationEngine(
    "mylib-foo",  # Domain
    "hybrid",  # Name of engine being declared
    ["bar", "baz"],  # Base engines (in MRO order)
)
_engine3.materialize()

End-user code

[ ]:
import coheriq

coheriq.enable_engine("mylib-foo", "hybrid")
[6]:
approximate_pi()
[6]:
3.141592653589793
[7]:
approximate_e()
[7]:
2.718281828459045