Skip to content

Commit

Permalink
Merge pull request #38 from arcondello/feature/planar-docs
Browse files Browse the repository at this point in the history
Add PlanarGraphSolver to the docs
  • Loading branch information
arcondello authored Nov 14, 2022
2 parents 6bcf4e2 + 01990d8 commit b2034df
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 35 deletions.
20 changes: 20 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ that run either remotely (for example, in D-Wave's
`binary quadratic models <https://docs.ocean.dwavesys.com/en/stable/concepts/bqm.html>`_
(BQM):

* Planar: an exact solver for planar Ising problems with no linear biases.
* Random: a sampler that draws uniform random samples.
* `Simulated Annealing`_: a probabilistic heuristic for optimization and approximate
Boltzmann sampling well suited to finding good solutions of large problems.
Expand All @@ -34,6 +35,25 @@ that run either remotely (for example, in D-Wave's
* `Tabu`_: a heuristic that employs local search with methods to escape local minima.
* `Tree Decomposition`_: an exact solver for problems with low treewidth.

Planar
======

There are polynomial-time algorithms for finding the ground state of a planar
Ising model [#]_.

.. [#] Nicol Schraudolph, Dmitry Kamenetsky. *Efficient Exact Inference in Planar Ising Models*.
Advances in Neural Information Processing Systems 21 (NIPS 2008).
>>> from dwave.samplers import PlanarGraphSolver
>>> solver = PlanarGraphSolver()

Get the ground state of a planar Ising model

>>> h = {}
>>> J = {(0, 1): -1, (1, 2): -1, (0, 2): 1}

>>> sampleset = solver.sample_ising(h, J)

Random
======

Expand Down
28 changes: 28 additions & 0 deletions docs/reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,34 @@ Reference Documentation

.. currentmodule:: dwave.samplers

Planar
======

PlanarGraphSolver
-----------------

.. autoclass:: PlanarGraphSolver

Attributes
~~~~~~~~~~

.. autosummary::
:toctree: generated/

~PlanarGraphSolver.parameters
~PlanarGraphSolver.properties

Methods
~~~~~~~

.. autosummary::
:toctree: generated/

~PlanarGraphSolver.sample
~PlanarGraphSolver.sample_ising
~PlanarGraphSolver.sample_qubo


Random
=======

Expand Down
43 changes: 14 additions & 29 deletions dwave/samplers/planar/sampler.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,48 +11,33 @@
# WITHOUT WARRANTIES OR CONDITIONS F ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import copy
import typing

import dimod
import networkx as nx

from dwave.samplers.planar.planar import rotation_from_coordinates, plane_triangulate, expanded_dual
from dwave.samplers.planar.util import bqm_to_multigraph

__all__ = ["PlanarGraphSampler"]

__all__ = ["PlanarGraphSolver"]

class PlanarGraphSampler(dimod.Sampler, dimod.Initialized):
"""A (weighted) max-cut sampler, specifically for planar-graphs

In "planar graphs, the Maximum-Cut Problem is dual to the route inspection
problem (the problem of finding a shortest tour that visits each edge of a
graph at least once), in the sense that the edges that do not belong to a
maximum cut-set of a graph G are the duals of the edges that are doubled in
an optimal inspection tour of the dual graph of G. The optimal inspection
tour forms a self-intersecting curve that separates the plane into two
subsets, the subset of points for which the winding number of the curve is
even and the subset for which the winding number is odd; these two subsets
form a cut that includes all of the edges whose duals appear an odd number
of times in the tour. The route inspection problem may be solved in polynomial
time, and this duality allows the maximum cut problem to also be solved in
polynomial time for planar graphs."
Ref: https://en.wikipedia.org/wiki/Maximum_cut
"""
parameters = None
class PlanarGraphSolver(dimod.Sampler, dimod.Initialized):
"""An exact solver for planar Ising problems with no linear biases."""
parameters: typing.Dict[str, typing.Sequence[str]] = dict(pos=tuple())
"""Keyword arguments accepted by the sampling methods."""
properties = None
properties: typing.Dict[str, typing.Any] = dict()
"""Values for parameters accepted by the sampling methods."""

def __init__(self):
self.parameters = {
'pos': []
}
self.properties = {}
self.parameters = copy.deepcopy(self.parameters)
self.properties = copy.deepcopy(self.properties)

def sample(self,
bqm: dimod.BinaryQuadraticModel,
pos: dict = None,
pos: typing.Optional[typing.Mapping[dimod.typing.Variable, typing.Tuple[float, float]]] = None,
**kwargs) -> dimod.SampleSet:
"""Sample from a binary quadratic model.
Expand All @@ -62,13 +47,13 @@ def sample(self,
Examples:
>>> import dimod
>>> from dwave.samplers.planar import PlanarGraphSampler
>>> from dwave.samplers.planar import PlanarGraphSolver
>>> bqm = dimod.BinaryQuadraticModel.empty(dimod.SPIN)
>>> bqm.add_interaction('a', 'b', +1.0)
>>> bqm.add_interaction('b', 'c', +1.0)
>>> bqm.add_interaction('c', 'a', +1.0)
>>> pos = {'a': (0, 0), 'b': (1, 0), 'c': (0, 1)}
>>> sample = PlanarGraphSampler().sample(bqm, pos)
>>> sample = PlanarGraphSolver().sample(bqm, pos)
>>> sample.first
Sample(sample={'a': 1, 'b': -1, 'c': -1}, energy=0, num_occurrences=1)
Expand Down
3 changes: 3 additions & 0 deletions releasenotes/notes/planar-67a711e1020b9f03.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---
features:
- Add ``PlanarGraphSolver``, an exact solver for planar Ising problems with no linear biases.
12 changes: 6 additions & 6 deletions tests/test_planar_sampler.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

import dimod

from dwave.samplers.planar import PlanarGraphSampler
from dwave.samplers.planar import PlanarGraphSolver


class TestGroundStateBQM(unittest.TestCase):
Expand All @@ -27,7 +27,7 @@ def test_noPosProvided_threeVariables(self):
bqm.add_interaction('b', 'c', +1.0)
bqm.add_interaction('c', 'a', +1.0)

sample = PlanarGraphSampler().sample(bqm)
sample = PlanarGraphSolver().sample(bqm)
self.assertDictEqual(sample.first.sample, {'a': 1, 'b': -1, 'c': -1})

def test_noPosProvided_tenVariables(self):
Expand All @@ -36,7 +36,7 @@ def test_noPosProvided_tenVariables(self):
for i in range(0, 10):
bqm.add_interaction(i, i+1, 1)

sample = PlanarGraphSampler().sample(bqm)
sample = PlanarGraphSolver().sample(bqm)
self.assertDictEqual(sample.first.sample,
{0: 1, 1: -1, 2: 1, 3: -1, 4: 1, 5: -1, 6: 1, 7: -1, 8: 1, 9: -1, 10: 1}
)
Expand All @@ -50,7 +50,7 @@ def test_NAE3SAT_bqm(self):

pos = {'a': (0, 0), 'b': (1, 0), 'c': (0, 1)}

sample = PlanarGraphSampler().sample(bqm, pos)
sample = PlanarGraphSolver().sample(bqm, pos)
self.assertDictEqual(sample.first.sample, {'a': 1, 'b': -1, 'c': -1})

def test_grid_15x15(self):
Expand All @@ -62,7 +62,7 @@ def test_grid_15x15(self):
bqm.add_interaction((x, y), (x + 1, y + 1), 1)
bqm.add_interaction((x, y), (x, y + 1), 1)

sample = PlanarGraphSampler().sample(bqm)
sample = PlanarGraphSolver().sample(bqm)

self.assertEqual(set(sample.first.sample.values()), {-1, +1})
self.assertDictEqual(
Expand Down Expand Up @@ -109,7 +109,7 @@ def test_grid_15x15_ferromagnet(self):
bqm.add_interaction((x, y), (x + 1, y + 1), -1)
bqm.add_interaction((x, y), (x, y + 1), -1)

sample = PlanarGraphSampler().sample(bqm)
sample = PlanarGraphSolver().sample(bqm)

# should all be the same
self.assertEqual(set(sample.first.sample.values()), {-1})
Expand Down

0 comments on commit b2034df

Please sign in to comment.