Repository: dwavesystems/dimod (python)

Issue:
Incorrect `BQM.relabel_variables()` when mapping is a superset of BQM variables
With latest dimod (0.12.20):
```python
>>> import dimod
>>> bqm = dimod.BinaryQuadraticModel({2: 1, 0: 1}, {}, 0, 'SPIN')
>>> bqm.relabel_variables({0: "a", 1: "b", 2: "c"}, inplace=False)
BinaryQuadraticModel({'c': 1.0, 'b': 1.0}, {}, 0.0, 'SPIN')
```
Expected output:
```python
BinaryQuadraticModel({'c': 1.0, 'a': 1.0}, {}, 0.0, 'SPIN')
```
When the order of variables in BQM is reversed, the output is correct.
Also, when the `mapping` dict contains only BQM variables (`{0: "a", 2: "c"}`), the output is correct.

Pull request description:
Fix Variables._relabel() with supersets
Looking through the logic, I think it would be possible to avoid the copy with a more significant rework. But we already are doing many copies and traversals in that family of functions so IMO the simpler approach is best.


Closes #1408 

Patch:
diff --git a/dimod/__init__.py b/dimod/__init__.py
index 8b62fa7e..5f99aa24 100644
--- a/dimod/__init__.py
+++ b/dimod/__init__.py
@@ -13,7 +13,7 @@
 #    limitations under the License.
 
 # version is used by serialization below so we need it before everything
-__version__ = '0.12.20'
+__version__ = '0.12.19'
 
 from dimod.constrained import *
 import dimod.constrained
diff --git a/dimod/utilities.py b/dimod/utilities.py
index 1a331378..3178a087 100644
--- a/dimod/utilities.py
+++ b/dimod/utilities.py
@@ -366,6 +366,10 @@ def iter_safe_relabels(mapping: collections.abc.Mapping[Variable, Variable],
         A "safe" relabelling.
 
     """
+    # first if the mapping is a superset of existing, we can go ahead and drop
+    # the stuff we don't care about
+    mapping = {old: new for old, new in mapping.items() if old in existing}
+
     # put the new labels into a set for fast lookup, also ensures that the
     # values are valid labels
     # We could use a set, but using a dict makes for nicer error messages later
diff --git a/releasenotes/notes/fix-variables-relabel-c145815df427c55c.yaml b/releasenotes/notes/fix-variables-relabel-c145815df427c55c.yaml
new file mode 100644
index 00000000..0753b4fd
--- /dev/null
+++ b/releasenotes/notes/fix-variables-relabel-c145815df427c55c.yaml
@@ -0,0 +1,7 @@
+---
+fixes:
+  - |
+    Fix ``Variables._relabel()`` method. Previously when given a superset of
+    labels that happen to correspond to valid indices the wrong relabelling
+    would sometimes be applied.
+    See also `#1408 <https://github.com/dwavesystems/dimod/issues/1408>`_.


Test patch:
diff --git a/tests/test_variables.py b/tests/test_variables.py
index 375c67a8..e0d99c4c 100644
--- a/tests/test_variables.py
+++ b/tests/test_variables.py
@@ -210,6 +210,11 @@ class TestRelabel(unittest.TestCase):
 
         self.assertEqual(variables, Variables('ab'))
 
+    def test_superset(self):
+        variables = Variables([2, 0])
+        variables._relabel({0: "a", 1: "b", 2: "c"})
+        self.assertEqual(variables, ["c", "a"])
+
     def test_swap(self):
         variables = Variables([1, 0, 3, 4, 5])
         variables._relabel({5: 3, 3: 5})