Skip to content

Commit

Permalink
Fix circular imports
Browse files Browse the repository at this point in the history
  • Loading branch information
arcondello committed Dec 10, 2020
1 parent 48f10ab commit c50f7f0
Show file tree
Hide file tree
Showing 6 changed files with 152 additions and 143 deletions.
10 changes: 8 additions & 2 deletions dwave/plugins/networkx/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
from dwave.plugins.networkx.algorithms import *

import dwave.plugins.networkx.utils

import dwave.plugins.networkx.exceptions
from dwave.plugins.networkx.exceptions import *

import dwave.plugins.networkx.default_sampler
Expand All @@ -27,5 +29,9 @@
import dwave.plugins.networkx.drawing
from dwave.plugins.networkx.drawing import *

from dwave.plugins.networkx.package_info import __version__, __author__, \
__authoremail__, __description__
from dwave.plugins.networkx.package_info import (
__version__,
__author__,
__authoremail__,
__description__,
)
7 changes: 5 additions & 2 deletions dwave/plugins/networkx/algorithms/clique.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@
# limitations under the License.

import networkx as nx
import dwave.plugins.networkx as dnx

from dwave.plugins.networkx.algorithms.independent_set import maximum_independent_set
from dwave.plugins.networkx.utils import binary_quadratic_model_sampler


__all__ = ["maximum_clique", "clique_number", "is_clique"]


@binary_quadratic_model_sampler(1)
def maximum_clique(G, sampler=None, lagrange=2.0, **sampler_args):
"""
Expand Down Expand Up @@ -87,7 +89,7 @@ def maximum_clique(G, sampler=None, lagrange=2.0, **sampler_args):
# finding the maximum clique in a graph is equivalent to finding
# the independent set in the complementary graph
complement_G = nx.complement(G)
return dnx.maximum_independent_set(complement_G, sampler, lagrange, **sampler_args)
return maximum_independent_set(complement_G, sampler, lagrange, **sampler_args)


@binary_quadratic_model_sampler(1)
Expand Down Expand Up @@ -145,6 +147,7 @@ def clique_number(G, sampler=None, lagrange=2.0, **sampler_args):
"""
return len(maximum_clique(G, sampler, lagrange, **sampler_args))


def is_clique(G, clique_nodes):
"""Determines whether the given nodes form a clique.
Expand Down
134 changes: 132 additions & 2 deletions dwave/plugins/networkx/default_sampler.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,145 @@
[0]
"""
from decorator import decorator

from dwave.plugins.networkx.utils.decorators import binary_quadratic_model_sampler
from dwave.plugins.networkx.exceptions import DWaveNetworkXMissingSampler

__all__ = ['set_default_sampler', 'get_default_sampler', 'unset_default_sampler']
__all__ = ['set_default_sampler',
'get_default_sampler',
'unset_default_sampler',
]


_SAMPLER = None


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.plugins.networkx as dnx
>>> from dwave.plugins.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.plugins.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 = get_default_sampler()
if default_sampler is None:
raise 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


@binary_quadratic_model_sampler(0)
def set_default_sampler(sampler):
"""Sets a default binary quadratic model sampler.
Expand Down
4 changes: 4 additions & 0 deletions dwave/plugins/networkx/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@

from networkx import NetworkXException

__all__ = ['DWaveNetworkXException',
'DWaveNetworkXMissingSampler',
]


class DWaveNetworkXException(NetworkXException):
"""Base class for exceptions in DWaveNetworkX."""
Expand Down
3 changes: 1 addition & 2 deletions dwave/plugins/networkx/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,5 @@
# 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.
#
# ================================================================================================

from dwave.plugins.networkx.utils.decorators import *
137 changes: 2 additions & 135 deletions dwave/plugins/networkx/utils/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,139 +12,6 @@
# 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.
"""
# this submodule is kept for backwards compatibility

from decorator import decorator

import dwave.plugins.networkx as dnx

__all__ = ['binary_quadratic_model_sampler']


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.plugins.networkx as dnx
>>> from dwave.plugins.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.plugins.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
from dwave.plugins.networkx.default_sampler import binary_quadratic_model_sampler

0 comments on commit c50f7f0

Please sign in to comment.