Repository: dwavesystems/dimod
Issue: VartypeView.relabel_variables can return model with wrong vartype

**Description**
`VartypeView.relabel_variable` acts on base model and returns a wrong (base) vartype if `base.vartype != view.vartype`.

**Steps To Reproduce**
```
In [1]: import dimod

In [2]: view = dimod.BQM.from_ising({0: 1}, {}).binary

In [3]: rel = view.relabel_variables({0: 0}, inplace=False)

In [4]: rel == view
Out[4]: False

In [5]: view
Out[5]: BinaryView({0: 2}, {}, -1, 'BINARY')

In [6]: rel
Out[6]: BinaryQuadraticModel({0: 1}, {}, 0, 'SPIN')
```

**Expected Behavior**
```
In [1]: import dimod

In [2]: view = dimod.BQM.from_ising({0: 1}, {}).binary

In [3]: rel = view.relabel_variables({0: 0}, inplace=False)

In [4]: rel == view
Out[4]: True

In [5]: view
Out[5]: BinaryView({0: 2}, {}, -1, 'BINARY')

In [6]: rel
Out[6]: BinaryView({0: 2}, {}, -1, 'BINARY')
```

**Additional Context**
Causes https://github.com/dwavesystems/dwave-system/issues/333.


Changed files:
dimod/core/bqm.py, tests/test_bqm.py

diff --git a/dimod/core/bqm.py b/dimod/core/bqm.py
index cd062e8e..fdfe61d1 100644
--- a/dimod/core/bqm.py
+++ b/dimod/core/bqm.py
@@ -1361,9 +1361,6 @@ class VartypeView(BQM):
         for u, v, _ in self._bqm.iter_quadratic(variables):
             yield u, v, self.get_quadratic(u, v)
 
-    def relabel_variables(self, *args, **kwargs):
-        return self._bqm.relabel_variables(*args, **kwargs)
-
 
 class BinaryView(VartypeView):
     @property
@@ -1393,6 +1390,9 @@ class BinaryView(VartypeView):
     def copy(self):
         return self._bqm.change_vartype(Vartype.BINARY, inplace=False)
 
+    def relabel_variables(self, *args, **kwargs):
+        return self._bqm.relabel_variables(*args, **kwargs).binary
+
     def get_linear(self, v):
         bqm = self._bqm
         return 2 * bqm.get_linear(v) - 2 * sum(b for _, _, b in bqm.iter_quadratic(v))
@@ -1458,6 +1458,9 @@ class SpinView(VartypeView):
     def copy(self):
         return self._bqm.change_vartype(Vartype.SPIN, inplace=False)
 
+    def relabel_variables(self, *args, **kwargs):
+        return self._bqm.relabel_variables(*args, **kwargs).spin
+
     def get_linear(self, v):
         bqm = self._bqm
         return (bqm.get_linear(v) / 2
diff --git a/tests/test_bqm.py b/tests/test_bqm.py
index 1174d6ec..821ba653 100644
--- a/tests/test_bqm.py
+++ b/tests/test_bqm.py
@@ -2041,6 +2041,62 @@ class TestVartypeViews(unittest.TestCase):
         self.assertEqual(view.spin, copy.spin)
         self.assertEqual(view.binary, copy.binary)
 
+    @parameterized.expand([(cls.__name__, cls, inplace)
+                           for (cls, inplace)
+                           in itertools.product(BQM_SUBCLASSES, [False, True])])
+    def test_relabel_variables_binary(self, name, BQM, inplace):
+        # to get a BinaryView, construct in SPIN, and ask for binary
+        linear = {0: 1, 1: -3, 2: 2}
+        quadratic = {(0, 1): -5, (1, 2): 6}
+        offset = 16
+        vartype = dimod.SPIN
+        view = BQM(linear, quadratic, offset, vartype).binary
+
+        # relabel view
+        mapping = {0: 'a', 1: 'b', 2: 'c'}
+        new = view.relabel_variables(mapping, inplace=inplace)
+        assert_consistent_bqm(new)
+        if inplace:
+            self.assertIs(view, new)
+        else:
+            self.assertIsNot(view, new)
+
+        # check that new model is correct
+        linear = {'a': 1, 'b': -3, 'c': 2}
+        quadratic = {'ab': -5, 'bc': 6}
+        offset = 16
+        vartype = dimod.SPIN
+        test = BQM(linear, quadratic, offset, vartype).binary
+        self.assertEqual(new, test)
+
+    @parameterized.expand([(cls.__name__, cls, inplace)
+                           for (cls, inplace)
+                           in itertools.product(BQM_SUBCLASSES, [False, True])])
+    def test_relabel_variables_spin(self, name, BQM, inplace):
+        # to get a SpinView, construct in BINARY, and ask for spin
+        linear = {0: 1, 1: -3, 2: 2}
+        quadratic = {(0, 1): -5, (1, 2): 6}
+        offset = 16
+        vartype = dimod.BINARY
+        view = BQM(linear, quadratic, offset, vartype).spin
+
+        # relabel view
+        mapping = {0: 'a', 1: 'b', 2: 'c'}
+        new = view.relabel_variables(mapping, inplace=inplace)
+        assert_consistent_bqm(new)
+        if inplace:
+            self.assertIs(view, new)
+        else:
+            self.assertIsNot(view, new)
+
+        # check that new model is correct
+        linear = {'a': 1, 'b': -3, 'c': 2}
+        quadratic = {'ab': -5, 'bc': 6}
+        offset = 16
+        vartype = dimod.BINARY
+        test = BQM(linear, quadratic, offset, vartype).spin
+        self.assertEqual(new, test)
+
 
 class TestToNumpyVectors(unittest.TestCase):
     @parameterized.expand([(cls.__name__, cls) for cls in BQM_SUBCLASSES])