Repository: dwavesystems/dimod

Issue:
Unembedding fails for bqms that are a subset of the source graph
**Description**

Unembedding fails when the embedding has more variables than the BQM.

**To Reproduce**
```
import numpy as np
import dimod

response = dimod.Response(np.rec.array([([-1,  1, -1,  1, -1,  1, -1,  1], -1.4, 1),
           ([-1,  1, -1, -1, -1,  1, -1, -1], -1.4, 1),
           ([ 1, -1, -1, -1,  1, -1, -1, -1], -1.6, 1),
           ([ 1, -1,  1,  1,  1, -1,  1,  1], -1.6, 1),
           ([-1,  1, -1,  1, -1,  1, -1,  1], -1.4, 1),
           ([ 1, -1, -1, -1,  1, -1, -1, -1], -1.6, 1),
           ([-1,  1,  1,  1, -1,  1,  1,  1], -1.4, 1),
           ([-1,  1,  1,  1, -1,  1,  1,  1], -1.4, 1),
           ([ 1, -1,  1, -1,  1, -1,  1, -1], -1.6, 1),
           ([ 1, -1, -1, -1,  1, -1, -1, -1], -1.6, 1)],
          dtype=[('sample', 'i1', (8,)), ('energy', '<f8'), ('num_occurrences', '<i8')]), [0, 1, 2, 3, 4, 5, 6, 7], {}, 'SPIN')
embedding = {0: {0, 4}, 1: {1, 5}, 2: {2, 6}, 3: {3, 7}}
bqm = dimod.BinaryQuadraticModel({0: 0.1, 1: 0.2}, {(0, 1): 1.5}, 0.0, dimod.SPIN)

dimod.unembed_response(response, embedding, source_bqm=bqm)
```
Traceback:
```
KeyError                                  Traceback (most recent call last)
<ipython-input-6-d819b61114e6> in <module>()
     16 bqm = dimod.BinaryQuadraticModel({0: 0.1, 1: 0.2}, {(0, 1): 1.5}, 0.0, dimod.SPIN)
     17 
---> 18 dimod.unembed_response(response, embedding, source_bqm=bqm)

~/projects/ocean/system/venv37/lib/python3.7/site-packages/dimod/embedding/transforms.py in unembed_response(target_response, embedding, source_bqm, chain_break_method)
    434     unembedded, idxs = chain_break_method(record.sample, chain_idxs)
    435 
--> 436     lin, (i, j, quad), off = source_bqm.to_numpy_vectors(variable_order=variables)
    437     energies = unembedded.dot(lin) + (unembedded[:, i]*unembedded[:, j]).dot(quad) + off
    438 

~/projects/ocean/system/venv37/lib/python3.7/site-packages/dimod/binary_quadratic_model.py in to_numpy_vectors(self, variable_order, dtype, index_dtype, sort_indices)
   2171         labels = {v: idx for idx, v in enumerate(variable_order)}
   2172 
-> 2173         lin = np.array([linear[v] for v in variable_order], dtype=dtype)
   2174 
   2175         if quadratic:

~/projects/ocean/system/venv37/lib/python3.7/site-packages/dimod/binary_quadratic_model.py in <listcomp>(.0)
   2171         labels = {v: idx for idx, v in enumerate(variable_order)}
   2172 
-> 2173         lin = np.array([linear[v] for v in variable_order], dtype=dtype)
   2174 
   2175         if quadratic:

KeyError: 2
```

**Environment:**
 - OS: Ubuntu 16.04.5 LTS
 - Python version: 3.7.0


Discussion:

Patch:
diff --git a/dimod/embedding/transforms.py b/dimod/embedding/transforms.py
index 491c3a4a..b72dbda6 100644
--- a/dimod/embedding/transforms.py
+++ b/dimod/embedding/transforms.py
@@ -416,13 +416,15 @@ def unembed_response(target_response, embedding, source_bqm, chain_break_method=
         Sample(sample={'x2': 0, 'x1': 0, 'z': 1}, energy=3.0)
 
     """
-    if any(v not in embedding for v in source_bqm):
-        raise ValueError("given bqm does not match the embedding")
 
     if chain_break_method is None:
         chain_break_method = majority_vote
 
-    variables, chains = zip(*embedding.items())
+    variables = list(source_bqm)
+    try:
+        chains = [embedding[v] for v in variables]
+    except KeyError:
+        raise ValueError("given bqm does not match the embedding")
 
     if target_response.label_to_idx is None:
         chain_idxs = [list(chain) for chain in chains]


Test patch:
diff --git a/tests/test_embedding_transforms.py b/tests/test_embedding_transforms.py
index 2470acd5..f022020d 100644
--- a/tests/test_embedding_transforms.py
+++ b/tests/test_embedding_transforms.py
@@ -184,6 +184,24 @@ class TestUnembedResponse(unittest.TestCase):
         for sample, energy in response.data(['sample', 'energy']):
             self.assertEqual(bqm.energy(sample), energy)
 
+    def test_embedding_superset(self):
+        # source graph in the embedding is a superset of the bqm
+        response = dimod.Response(np.rec.array([([-1,  1, -1,  1, -1,  1, -1,  1], -1.4, 1),
+                                                ([-1,  1, -1, -1, -1,  1, -1, -1], -1.4, 1),
+                                                ([+1, -1, -1, -1,  1, -1, -1, -1], -1.6, 1),
+                                                ([+1, -1, -1, -1,  1, -1, -1, -1], -1.6, 1)],
+                                  dtype=[('sample', 'i1', (8,)), ('energy', '<f8'), ('num_occurrences', '<i8')]),
+                                  [0, 1, 2, 3, 4, 5, 6, 7], {}, 'SPIN')
+        embedding = {0: {0, 4}, 1: {1, 5}, 2: {2, 6}, 3: {3, 7}}
+        bqm = dimod.OrderedBinaryQuadraticModel.from_ising([.1, .2], {(0, 1): 1.5}, 0.0)
+
+        unembedded = dimod.unembed_response(response, embedding, source_bqm=bqm)
+
+        arr = np.rec.array([([-1,  1], -1.4, 1), ([-1,  1], -1.4, 1), ([+1, -1], -1.6, 1), ([+1, -1], -1.6, 1)],
+                           dtype=[('sample', 'i1', (2,)), ('energy', '<f8'), ('num_occurrences', '<i8')])
+
+        np.testing.assert_array_equal(arr, unembedded.record)
+
 
 class TestEmbedBQM(unittest.TestCase):
     def test_embed_bqm_empty(self):