Source code for dimod.core.composite

"""
Samplers can be composed. The `composite pattern <https://en.wikipedia.org/wiki/Composite_pattern>`_
allows layers of pre- and post-processing to be applied to binary quadratic programs without needing
to change the underlying sampler implementation.

We refer to these layers as `composites`. Each composed sampler must
include at least one sampler, and possibly many composites.

Each composed sampler is itself a dimod sampler with all of the
included methods and parameters. In this way complex samplers
can be constructed.

The dimod :class:`.ComposedSampler` abstract base class inherits from :class:`.Sampler` class
its abstract methods, properties, and mixins (for example, a `sample_Ising` method) and from
:class:`.Composite` class the `children` property and `child` mixin (`children` being a list of
supported samplers with `child` providing the first).

Examples:
    The dimod package's spin_transform.py reference example creates a composed
    sampler, `SpinReversalTransformComposite(Sampler, Composite)`, that performs
    spin reversal transforms ("gauge transformations") as a preprocessing step for
    a given sampler. The reference example implements the pseudocode below:

    .. code-block:: python

        class SpinReversalTransformComposite(Sampler, Composite):

            # Updates to inherited sampler properties and parameters
            # Definition of the composite's children (i.e., supported samplers):
            children = None
            def __init__(self, child):
                self.children = [child]

            # The composite's implementation of spin-transformation functionality:
            def sample(self, bqm, num_spin_reversal_transforms=2, spin_reversal_variables=None, **kwargs):
                response = None
                # Preprocessing code that includes instantiation of a sampler:
                # flipped_response = self.child.sample(bqm, **kwargs)
                return response

    Given a sampler, `sampler1`, the composed sampler is used as any dimod sampler.
    For example, the composed sampler inherits an Ising sampling method:

    >>> composed_sampler = dimod.SpinReversalTransformComposite(sampler1) # doctest: +SKIP
    >>> h = {0: -1, 1: 1} # doctest: +SKIP
    >>> response = composed_sampler.sample_ising(h, {}) # doctest: +SKIP

"""
import abc

from six import add_metaclass

from dimod.core.sampler import Sampler

__all__ = ['Composite', 'ComposedSampler']


[docs]@add_metaclass(abc.ABCMeta) class Composite: """Abstract base class for dimod composites. Provides the :attr:`~.Composite.child` mixin property and defines the :attr:`~.Composite.children` abstract property to be implemented. These define the supported samplers for the composed sampler. """ @abc.abstractproperty def children(self): """list[ :obj:`.Sampler`]: List of samplers (or composed samplers). This abstract property must be implemented. Examples: These examples define the supported samplers for the composed sampler upon instantiation. .. code-block:: python class MyComposite(dimod.Composite): def __init__(self, *children): self._children = list(children) @property def children(self): return self._children .. code-block:: python class AnotherComposite(dimod.Composite): self.children = None def __init__(self, child_sampler): self.children = [child_sampler] """ pass @property def child(self): """First child in :attr:`~.Composite.children`. Examples: This example pseudocode defines a composed sampler that uses the first supported sampler in a composite's list of samplers on a binary quadratic model. .. code-block:: python class MyComposedSampler(Sampler, Composite): children = None parameters = None properties = None def __init__(self, child): self.children = [child] self.parameters = child.parameters.copy() # propagate parameters self.parameters['my_additional_parameter'] = [] self.properties = child.properties.copy() # propagate properties # Implementation of the composite's functionality def sample(self, bqm, my_additional_parameter, **kwargs): # Overwrite the abstract sample method. # Additional parameters must have defaults # Samples are obtained from the sampler by using the `child` property: # response = self.child.sample(bqm, **kwargs) raise NotImplementedError """ try: return self.children[0] except IndexError: raise RuntimeError("A Composite must have at least one child Sampler")
[docs]class ComposedSampler(Sampler, Composite): """Abstract base class for dimod composed samplers. Inherits from :class:`.Sampler` and :class:`.Composite`. """ pass