Source code for dwave_networkx.utils.decorators

# Copyright 2018 D-Wave Systems Inc.
#
#    Licensed under the Apache License, Version 2.0 (the "License");
#    you may not use this file except in compliance with the License.
#    You may obtain a copy of the License at
#
#        http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS,
#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#    See the License for the specific language governing permissions and
#    limitations under the License.
#
# ================================================================================================
"""
Decorators allow for input checking and default parameter setting for
algorithms.
"""

from decorator import decorator

import dwave_networkx as dnx

__all__ = ['binary_quadratic_model_sampler']


[docs]def binary_quadratic_model_sampler(which_args): """Decorator to validate sampler arguments. Parameters ---------- which_args : int or sequence of ints Location of the sampler arguments of the input function in the form `function_name(args, *kw)`. If more than one sampler is allowed, can be a list of locations. Returns ------- _binary_quadratic_model_sampler : function Caller function that validates the sampler format. A sampler is expected to have `sample_qubo` and `sample_ising` methods. Alternatively, if no sampler is provided (or sampler is None), the sampler set by the `set_default_sampler` function is provided to the function. Examples -------- Decorate functions like this:: @binary_quadratic_model_sampler(1) def maximal_matching(G, sampler, **sampler_args): pass This example validates two placeholder samplers, which return a correct response only in the case of finding an independent set on a complete graph (where one node is always an independent set), the first valid, the second missing a method. >>> import networkx as nx >>> import dwave_networkx as dnx >>> from dwave_networkx.utils import decorators >>> # Create two placeholder samplers >>> class WellDefinedSampler: ... # an example sampler, only works for independent set on complete ... # graphs ... def __init__(self, name): ... self.name = name ... def sample_ising(self, h, J): ... sample = {v: -1 for v in h} ... sample[0] = 1 # set one node to true ... return [sample] ... def sample_qubo(self, Q): ... sample = {v: 0 for v in set().union(*Q)} ... sample[0] = 1 # set one node to true ... return [sample] ... def __str__(self): ... return self.name ... >>> class IllDefinedSampler: ... # an example sampler missing a `sample_qubo` method ... def __init__(self, name): ... self.name = name ... def sample_ising(self, h, J): ... sample = {v: -1 for v in h} ... sample[0] = 1 # set one node to true ... return [sample] ... def __str__(self): ... return self.name ... >>> sampler1 = WellDefinedSampler('sampler1') >>> sampler2 = IllDefinedSampler('sampler2') >>> # Define a placeholder independent-set function with the decorator >>> @dnx.utils.binary_quadratic_model_sampler(1) ... def independent_set(G, sampler, **sampler_args): ... Q = {(node, node): -1 for node in G} ... Q.update({edge: 2 for edge in G.edges}) ... response = sampler.sample_qubo(Q, **sampler_args) ... sample = next(iter(response)) ... return [node for node in sample if sample[node] > 0] ... >>> # Validate the samplers >>> G = nx.complete_graph(5) >>> independent_set(G, sampler1) [0] >>> independent_set(G, sampler2) # doctest: +SKIP --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-35-670b71b268c7> in <module>() ----> 1 independent_set(G, IllDefinedSampler) <decorator-gen-628> in independent_set(G, sampler, **sampler_args) /usr/local/lib/python2.7/dist-packages/dwave_networkx/utils/decorators.pyc in _binary_quadratic_model_sampler(f, *args, **kw) 61 62 if not hasattr(sampler, "sample_qubo") or not callable(sampler.sample_qubo): ---> 63 raise TypeError("expected sampler to have a 'sample_qubo' method") 64 if not hasattr(sampler, "sample_ising") or not callable(sampler.sample_ising): 65 raise TypeError("expected sampler to have a 'sample_ising' method") TypeError: expected sampler to have a 'sample_qubo' method """ @decorator def _binary_quadratic_model_sampler(f, *args, **kw): # convert into a sequence if necessary if isinstance(which_args, int): iter_args = (which_args,) else: iter_args = iter(which_args) # check each sampler for the correct methods new_args = [arg for arg in args] for idx in iter_args: sampler = args[idx] # if no sampler is provided, get the default sampler if it has # been set if sampler is None: # this sampler has already been vetted default_sampler = dnx.get_default_sampler() if default_sampler is None: raise dnx.DWaveNetworkXMissingSampler('no default sampler set') new_args[idx] = default_sampler continue if not hasattr(sampler, "sample_qubo") or not callable(sampler.sample_qubo): raise TypeError("expected sampler to have a 'sample_qubo' method") if not hasattr(sampler, "sample_ising") or not callable(sampler.sample_ising): raise TypeError("expected sampler to have a 'sample_ising' method") # now run the function and return the results return f(*new_args, **kw) return _binary_quadratic_model_sampler