-
Notifications
You must be signed in to change notification settings - Fork 343
Feature/Replace qc.Loop with for loop using iPython magic #723
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature/Replace qc.Loop with for loop using iPython magic #723
Conversation
|
Cool Can we have an explicit example? I assumed that the code you were meant to write would be The code is only python 3.6 compatible because of the fstrings. We will likely break python 3.5 support soon but in the mean time it would be good to wrap the import in a check for python 3.6 and up. |
|
@jenshnielsen I almost copied the Python for loop structure, but I don't instantiate a variable ( As an explicit example, say we have initialized parameter %%measurement test_measurement
for p.sweep(0, 10, step=1):
pwhich would translate to loop = qc.Loop(p.sweep(0, 10, step=1)).each(
p)
data = loop.get_data_set('test_measurement')I'll add a check for Python 3.6 |
|
Yes I have figured out how it works, but your docstring could be more clear. I think you will need to document it with an explicit example. |
|
@jenshnielsen Yeah good point, I should've made it clearer. I'd love if we could actually use the setpoints as variables in a loop, in which case it would make sense to follow the same syntax as python for loops. I'll update the docstring to make this more clear. Other than that any comments? |
|
I think the current version is a great start. I am hoping that when I finally get back to the new dataset which will be more disentangled from the loop that we can use for loops in a better way. Perhaps replace the magic with a context manager? Only one tiny nitpick detail: it's actually IPython not iPython since it's not an apple product :) |
|
@jenshnielsen I'm all for disentangling the dataset from the loop
construct! As for context manager, I'm not seeing how we can use it for
this type of manipulation, from my understanding it is only capable of
performing actions before/after a piece of code, not actually altering the
code itself. Can you elaborate?
…On Thu, 14 Sep 2017 at 18:31 Jens Hedegaard Nielsen < ***@***.***> wrote:
I think the current version is a great start. I am hoping that when I
finally get back to the new dataset which will be more disentangled from
the loop that we can use for loops in a better way. Perhaps replace the
magic with a context manager?
Only one tiny nitpick detail ist actually IPython not iPython since it's
not an apple product :)
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#723 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AGgLHfcfAhq6masdXC0OZHLQjFCWlCEjks5siORigaJpZM4PMaTq>
.
|
|
I agree, My thinking is more in the direction of actually running the for loops as they are but having a context manager that takes care of all the dataset setup and so on but this will require quite some work and I am not sure if its even possible at this stage |
|
I am new to this tread so please forgive me if I am being ignorant.
For the loop structure, what about a design as follows:
Have a "sweep" method on the Parameter class which returns a generator. For
each time "next" is called on this generator, the Parameter is set to the
next value. To clarify, here is come mock code:
for voltage in device.gate.sweep(np.linspace(0, 1, 10)):
current = device.source_drain_current()
And in the sweep code we have:
def sweep(iterable):
for value in iterable:
self._set(value)
yield value
The nice thing about this is that we have a Python for loop with all its
associated flexibility. We can extend this concept to two-D and n-D looping
construct quite easily as well. How about doing stuff like:
for voltage1, voltage2 in qczip(device.gate1, device.gate2).sweep(gate1=np.linspace(0, 1, 10), gate2=np.linspace(-1, 1,
15)):
current = divice.source_drain_current()
Have a look at itertools for inspiration:
https://docs.python.org/2/library/itertools.html
We can build things like measure functions and classes on top of this
design. Maybe we can talk about this more in depth later? Love to hear from
you guys.
Sohail
…On Fri, Sep 15, 2017 at 9:18 AM, Jens Hedegaard Nielsen < ***@***.***> wrote:
I agree, My thinking is more in the direction of actually running the for
loops as they are but having a context manager that takes care of all the
dataset setup and so on but this will require quite some work and I am not
sure if its even possible at this stage
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#723 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AJ-GjLgUxmJO7w-WKf-wjQ2TXFGKq4L1ks5siiTHgaJpZM4PMaTq>
.
|
|
Why do we want to couple QCodes so tightly with IPython notebooks? What if we do not want to use notebooks as a way of running our experiments (as is indeed the talk here in Delft, that is that we should switch to regular python scripts)? |
|
@sohailc, generally, we don't want this strong coupling. QCoDeS should be useable without a notebook, and that is also the current state of affairs. In Copenhagen some people use Spyder in the lab. I agree with you that QCoDeS core functionality (drivers, datasets, loops) should not depend on the notebooks, but I think it is fine if people make notebook extensions of QCoDeS (like widgets or this magic). |
|
That is true. But I was under the impression that we want to get rid of the
current looping construct in QCodes (right?) and instead want to make
something new. I got the impression that that new way of looping would be
dependent on IPython magic.
But yes, I agree its totally fine to make IPython shortcuts :-)
…On Fri, Sep 15, 2017 at 1:13 PM, William H.P. Nielsen < ***@***.***> wrote:
@sohailc <https://github.com/sohailc>, generally, we don't want this
strong coupling. QCoDeS should be useable without a notebook, and that is
also the current state of affairs. I agree with you that QCoDeS core
functionality (drivers, datasets, loops) should not depend on the
notebooks, but I think it is fine if people make notebook extensions of
QCoDeS (like widgets).
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#723 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AJ-GjOqaZ9Kcj6axIBHRi44dremLA4MZks5silvjgaJpZM4PMaTq>
.
|
|
yes the title of this pull request is slightly miss leading. Its not a replacement but an alternative |
|
Ok cool.
Do you or anyone else have comments on my suggestion of an alternative
looping framework with generators?
…On Fri, Sep 15, 2017 at 1:28 PM, Jens Hedegaard Nielsen < ***@***.***> wrote:
yes the title of this pull request is slightly miss leading. Its not a
replacement but an alternative
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#723 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AJ-GjFdZRQ9zLefvUMDEORbeDk1UVwswks5sil9IgaJpZM4PMaTq>
.
|
|
Its the way we want to go and also my original suggestion. My point is that we need a smart way to ensure that the data is captured and stored correctly so that when you do a for loop in a measurement you dont have to write too much boilerplate code to capture the data and setup plotting and what not |
|
Cool, I guess we came up with a similar idea independently. Looking forward
to working with you guys.
…On Fri, Sep 15, 2017 at 2:19 PM, Jens Hedegaard Nielsen < ***@***.***> wrote:
Its the way we want to go and also my original suggestion. My point is
that we need a smart way to ensure that the data is captured and stored
correctly so that when you do a for loop in a measurement you dont have to
write too much boilerplate code to capture the data and setup plotting and
what not
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#723 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AJ-GjOpzQcasFzU0xSHJqDH7gxHx1Dv8ks5simtlgaJpZM4PMaTq>
.
|
|
@sohailc being able to use iterators/generators with a simple for loop structure would definitely result in measurements feeling much more Pythonic. I'm wondering how this can be implemented though. It seems to me -that meta information about the measurements is needed, such as its structure, the loop dimensionality etc. This enables creating an accompanying dataset. Since a for loop is a statement, it cannot be converted to an object, and so I'm not seeing how meta information can be gathered from this. Any thoughts? |
|
Hi @nulinspiratie thank you for your interesting thoughts and comments. I think this can be accomplished by the sweep generator yielding a stateful object instead of just measurement numbers. What about doing somethings like this: (A class method on the Parameter class): def sweep(self, iterable):
for value in iterable:
self.set(iterable):
yield self.instrumentIn this case instrument is a stateful object. If we want to make a measurement dataset, we could make a measurement class which can be different for different measurement types. This measurement class takes as argument a generator which it will unrole when calling "run". The init method of this class can accept as argument a list of properties or methods which will enable it to extract measurement data from the stateful object for each time the generator yields the next value. For instance: class Measurement:
def init(self, properties): # and other useful info about the measurement, like data format
self._properties = properties
def run(self, generator):
for instrument in generator():
for property in self._properties:
value = instrument.get(property)
.... # code to store the property and value at this time. So the complete measurement looks like: m = qc.Measurement(["gate1", "sd1"])
m.run(instrument.sweep(gate1=np.linspace(0, 1, 10)))I know this looks a bit like what we have already, but i think what is better about this design is that the run method can except any generator. Consider for example this: m.run((instrument.set(value) for value in [0, 1, 2]))Assuming that the set method returns "self". Another interesting thing you could do is perform non-linear sweeps. For example, finding the resonance frequency by stepping the frequency and iteratively finding the maximum value with newtons method: def find_max_frequency(instrument, init):
max_estimate = init
while(True): # yield values until we have found the max
.... # code to update the estimate of the max by measuring a local derivative. Adaptive stepping!
yield instrumentMy idea's have not matured, but consider how we could "zip" such a generator with a linear sweep to, for instance, flexibly program a measurement which finds a resonance at each gate voltage (for example). |
|
Another thing I should have pointed out is that I intended for the measurement class to be subclassed for each measurement type. So we can have (for example) "ResonanceMeasurement" and "MicrowaveMeasurement". So it should be easy to subclass the measurement class for non-programmers. If we try to make a one-size-fits all class, I think we will fail. |
|
Hi @sohailc very interesting ideas about future measurements, and thanks for taking the time to explain them! I've got a couple of questions related to it, I was hoping you could clarify. First of all, what exactly is this stateful instrument that a parameter sweep returns? Is it an actual Please correct me if I'm wrong, but is the main issue that's trying to be solved that we want to be able to specify the sweeping values adaptively, and that these may depend on previous measurement results? If so, the added benefit of an instrument is unclear to me. Related to this, why would the Measurement be sublassed? Would it not make sense to simply create Measurement instances, such as the qc.Loop. Each instance would perform a specific measurement, such as measuring the resonance frequency. These can then be combined for more complex measurements. Please let me know if anything is unclear, looking forward to your thoughts! |
|
@jenshnielsen @WilliamHPNielsen @sohailc As for the PR, is this something we want to include in QCoDeS, or not? If so, I'll update the docstring to include a more concrete example |
|
Im happy to include it. In this form it's optional and I can see it's usefulness. In the future we may be able to do something similar in a more clever way |
|
@nulinspiratie @jenshnielsen Is this still relevant? I guess we're waiting for the docstring update. |
|
@WilliamHPNielsen I think so, I still use it all the time. I forgot about
the docstring though, I'll do it early next week
…On Mon, Oct 16, 2017, 11:00 PM William H.P. Nielsen < ***@***.***> wrote:
@nulinspiratie <https://github.com/nulinspiratie> @jenshnielsen
<https://github.com/jenshnielsen> Is this still relevant? I guess we're
waiting for the docstring update.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#723 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AGgLHR0EvbzIagaNsyU3F6Mgbrd8L6m5ks5ss0V5gaJpZM4PMaTq>
.
|
|
@WilliamHPNielsen @jenshnielsen I updated the docstring to mention the differing syntax. If you guys approve, I think it's ready to be merged |
|
@jenshnielsen @WilliamHPNielsen any verdict? |
|
I haven't found the time to try it out, but since this is a parallel feature that people can use or ignore, I think it would not hurt merging it. @jenshnielsen do you disagree with that? |
|
I think it's ok to merge |
Codecov Report
@@ Coverage Diff @@
## master #723 +/- ##
=======================================
Coverage 78.63% 78.63%
=======================================
Files 33 33
Lines 4536 4536
=======================================
Hits 3567 3567
Misses 969 969 |
WilliamHPNielsen
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's go!
Author: Serwan Asaad <[email protected]> Feature/Replace qc.Loop with for loop using iPython magic (#723)
Author: Serwan Asaad <[email protected]> Feature/Replace qc.Loop with for loop using iPython magic (#723)
This PR adds the possibility to create QCoDeS loops using the Python for loop structure, which makes writing a Loop feel more Pythonic.
This is achieved using python cell magic: a measurement cell should be started with
%%measurement(see below for an example).The cell magic internally converts the for loop in a cell to the qc.Loop construct before executing the code.
Since iPython magic is used, it unfortunately only works in iPython (easiest in Jupyter Notebook).
The magic command has additional options, such as printing the executed code.
Example of new looping method
Old method to create a loop
Creating a Loop typically starts with creating a Loop object using qc.Loop.
After this, a dataset is created with the measurement_name
Using for loops
This can be replaced with for loops.
The first line should start with
%%measurementfollowed by the measurement_name (and possible options).After this, the Loop can be created by a for loop. Loops can also be nested same as you would nest for loops.
Additional changes
The PR contains some additional changes related to magic. These are mainly to create a construct such that any future magic can be nicely integrated into QCoDeS
%%measurementmagic, it is contained in the magics class QCoDeSMagic. This is done to have access to additional magic-related features, such as parsing. It also makes it easier to stop a specific magic from being registeredregister_magic_classis added, which handles the registering of a Magics class. The kwargmagic_commandsallows only specific magics to be registered.register_magicis added to config.core. It can be set to True, False, or a list (True by default).register_magicis not set to False and if the kernel is iPython. If so, then it will register magics. Ifregister_magic=True, it will register all the magics in QCoDeSMagic. Ifregister_magicis a list, it will only register those that are in the list.@giulioungaretti @jenshnielsen @WilliamHPNielsen @core