Repository: Qiskit/qiskit

Issue:
Convert Hamiltonian variables to Hz
<!-- ⚠️ If you do not respect this template, your issue will be closed -->
<!-- ⚠️ Make sure to browse the opened and closed issues -->

### Information

- **Qiskit Terra version**:
- **Python version**:
- **Operating system**:

### What is the current behavior?
All other time-based units are currently defined in terms of seconds/Hertz. The Hamiltonian variables should also be. This may have an effect on the Qiskit-Aer pulse simulator @chriseclectic @DanPuzzuoli.


### Steps to reproduce the problem



### What is the expected behavior?



### Suggested solutions





Discussion:
Is this still open or will it be solved by #3597 ? 
This is still open. Are you interested in taking it on?
I'll get to work and update you when I have something to show :) 
Thank you very much!
Is this still open and what are some suggested modules to look at in order to fix this?
> Is this still open and what are some suggested modules to look at in order to fix this?

Yes, this is still open @ToJen - It fell a bit out of focus for me, so I don't have anything complete yet. You're very welcome to take this over, if you want to! 
I think the modules you should start by looking at are the `qiskit.providers.models.backendconfiguration`, specifically the `PulseHamiltonianSchema` class.
Thanks for letting us know @eembees, I've unassigned you and this issue is now open for someone else to take on.
Is this still open? I can take it on if so. 
@taalexander I am keen to contribute to solving this as one of my first issues. Can I work on this? 
If possible could you share the steps to reproduce this error? Thank you
Hello @arunraja-hub, I believe this is still unassigned. To get started I would look at @eembees comment above. This would be similar to the approach taken with PulseDefaults. Basically make the supplied hamiltonian variables private and expose a property with the converted values.
There is no `PulseHamiltonianSchema` class in qiskit/providers/models/backendconfiguration.py
You're right. There was a relatively major change to providers since @eembees comment. Please see https://github.com/Qiskit/qiskit-terra/blob/fab61d21d105c40142e7d67a8ea7bab602dd4c12/qiskit/providers/models/backendconfiguration.py#L485 for the `hamiltonian` attribute. The `hamiltonian` parameter could be reformatted before setting the `hamiltonian` attribute. See https://github.com/Qiskit/qiskit-terra/blob/fab61d21d105c40142e7d67a8ea7bab602dd4c12/qiskit/providers/models/backendconfiguration.py#L479 for an example.
From my understanding, `hamiltonian` is currently defined in terms of GHz as seen in https://github.com/Qiskit/qiskit-terra/blob/fab61d21d105c40142e7d67a8ea7bab602dd4c12/qiskit/providers/models/backendconfiguration.py#L479
I will have to remove `1e9` to represent the `hamiltonian` in Hz , correct?
The Hamiltonian comes from the backend in GHz, so you will have to add a factor 1e9, to each entry in the `vars` section to convert to Hz.
There is no `vars` in qiskit-terra/qiskit/providers/models/backendconfiguration.py. Should I be looking for it in another file?
Also, sorry if I am asking the obvious here, according to https://github.com/Qiskit/qiskit-terra/blob/fab61d21d105c40142e7d67a8ea7bab602dd4c12/qiskit/providers/models/backendconfiguration.py#L479
aren't we already multiplying the ranges by 1e9?
@taalexander a gentle reminder to help with the issue in the message above
Thank you very much!
My apologies for the delay in getting back to you @arunraja-hub, I do not believe there is a Hamiltonian object, but it arrives with a structure as described in line 158 here https://www.github.com/Qiskit/qiskit-terra/tree/master/qiskit%2Fschemas%2Fbackend_configuration_schema.json. if present it should be a dictionary of this structure. It is this `vars` field that should be modified. 

See page 34 of https://arxiv.org/abs/1809.03452 for more info on the input structure. 
Thank you for your reply, @taalexander 

The `hamiltonian` is initialised here:

https://github.com/Qiskit/qiskit-terra/blob/fab61d21d105c40142e7d67a8ea7bab602dd4c12/qiskit/providers/models/backendconfiguration.py#L399

It is a dictionary of strings. So do I change to a dictionary of integers?

This type hint seems to have been added recently and unfortunately is wrong. This will need to be corrected. I would encourage you to look at the hamiltonian for `ibmq_armonk` with `backend.configuration().hamiltonian` to see the structure that is actually present. This is also another example. https://github.com/Qiskit/qiskit-terra/blob/e265409a4551551feddb4a74928386fd0d27f6df/qiskit/schemas/examples/backend_configuration_openpulse_example.json#L40
I've created #4649 to track this bug. 
@arunraja-hub, are the requirements a bit clearer now?
 https://github.com/Qiskit/qiskit-terra/issues/4649 has been fixed now
 the Hamiltonian specification in https://arxiv.org/pdf/1809.03452.pdf,
![image](https://user-images.githubusercontent.com/43485111/86874514-17705a80-c113-11ea-94d3-48a116569b5b.png)
Do I multiply each entry in `vars `as follows?:
`"vars" : {"v0": 5.0*1e9, "v1" : 5.25*1e9},`
> #4649 has been fixed now
> the Hamiltonian specification in https://arxiv.org/pdf/1809.03452.pdf,
> ![image](https://user-images.githubusercontent.com/43485111/86874514-17705a80-c113-11ea-94d3-48a116569b5b.png)
> Do I multiply each entry in `vars `as follows?:
> `"vars" : {"v0": 5.0*1e9, "v1" : 5.25*1e9},`

Yes :) 
Since, do I edit the description of `vars` in the hamiltonian dictionary as follows? :
from
https://github.com/Qiskit/qiskit-terra/blob/35db627fbd1c9762d9f394c71a1df129c24797f4/qiskit/schemas/backend_configuration_schema.json#L23
to
                   ` "description": "Variables in the h_str. Multiply by 1e9 to convert from GHz to Hz"},`

If you want to modify the description to something like `"description": "Variables in the h_str in GHz."` this is fine. The description is just for human readers.
Noted. With regards to changing the code to reflect the conversion from GHz to Hz, I am not sure in which file to make this change at
Please see my PR #4728, for an idea of how to handle this in the configuration.
@taalexander  Thank you. 
Do I multiply the values in vars here by 1e9?: https://github.com/Qiskit/qiskit-terra/blob/51b70a7c3a555573c38181c65f61c446dcfc7e90/qiskit/test/mock/utils/configurable_backend.py#L214

ANd can I develop the test here: https://github.com/Qiskit/qiskit-terra/blob/ff5fede2dadf338e7ba36a3efcbf4df6b0e651aa/test/python/mock/test_configurable_backend.py#L104


Resolving patch:
diff --git a/qiskit/providers/models/backendconfiguration.py b/qiskit/providers/models/backendconfiguration.py
--- a/qiskit/providers/models/backendconfiguration.py
+++ b/qiskit/providers/models/backendconfiguration.py
@@ -13,14 +13,15 @@
 """Backend Configuration Classes."""
 import re
 import copy
+import numbers
 import warnings
 from typing import Dict, List, Any, Iterable, Union
 from collections import defaultdict
 
 from qiskit.exceptions import QiskitError
 from qiskit.providers.exceptions import BackendConfigurationError
-from qiskit.pulse.channels import (Channel, DriveChannel, MeasureChannel,
-                                   ControlChannel, AcquireChannel)
+from qiskit.pulse.channels import (AcquireChannel, Channel, ControlChannel,
+                                   DriveChannel, MeasureChannel)
 
 
 class GateConfig:
@@ -530,6 +531,12 @@ def __init__(self,
         self.meas_kernels = meas_kernels
         self.discriminators = discriminators
         self.hamiltonian = hamiltonian
+        if hamiltonian is not None:
+            self.hamiltonian = dict(hamiltonian)
+            self.hamiltonian['vars'] = {
+                k: v * 1e9 if isinstance(v, numbers.Number) else v
+                for k, v in self.hamiltonian['vars'].items()
+            }
 
         self.rep_times = [_rt * 1e-6 for _rt in rep_times]  # convert to sec
 
@@ -605,7 +612,6 @@ def to_dict(self):
             'meas_lo_range': self.meas_lo_range,
             'meas_kernels': self.meas_kernels,
             'discriminators': self.discriminators,
-            'hamiltonian': self.hamiltonian,
             'rep_times': self.rep_times,
             'dt': self.dt,
             'dtm': self.dtm,
@@ -645,6 +651,14 @@ def to_dict(self):
                 [min_range * 1e-9, max_range * 1e-9] for
                 (min_range, max_range) in self.channel_bandwidth]
 
+        if self.hamiltonian:
+            hamiltonian = copy.deepcopy(self.hamiltonian)
+            hamiltonian['vars'] = {
+                k: v * 1e-9 if isinstance(v, numbers.Number) else v
+                for k, v in hamiltonian['vars'].items()
+            }
+            out_dict['hamiltonian'] = hamiltonian
+
         return out_dict
 
     def __eq__(self, other):


Test patch:
diff --git a/test/python/providers/test_backendconfiguration.py b/test/python/providers/test_backendconfiguration.py
--- a/test/python/providers/test_backendconfiguration.py
+++ b/test/python/providers/test_backendconfiguration.py
@@ -44,6 +44,20 @@ def test_hamiltonian(self):
         """Test the hamiltonian method."""
         self.assertEqual(self.config.hamiltonian['description'],
                          "A hamiltonian for a mocked 2Q device, with 1Q and 2Q terms.")
+        ref_vars = {
+            'v0': 5.0 * 1e9,
+            'v1': 5.1 * 1e9,
+            'j': 0.01 * 1e9,
+            'r': 0.02 * 1e9,
+            'alpha0': -0.33 * 1e9,
+            'alpha1': -0.33 * 1e9
+        }
+        self.assertEqual(self.config.hamiltonian['vars'], ref_vars)
+        # Test that on serialization inverse conversion is done.
+        self.assertEqual(
+            self.config.to_dict()['hamiltonian']['vars'],
+            {k: var*1e-9 for k, var in ref_vars.items()}
+        )
         # 3Q doesn't offer a hamiltonian -- test that we get a reasonable response
         backend_3q = self.provider.get_backend('fake_openpulse_3q')
         self.assertEqual(backend_3q.configuration().hamiltonian, None)