add MultiScanManager

This commit is contained in:
Sebastien Bourdeauducq 2016-06-18 16:30:34 +08:00
parent 80cf321233
commit ec3e7792dc
2 changed files with 61 additions and 4 deletions

View File

@ -0,0 +1,17 @@
from artiq.experiment import *
class MultiScan(EnvExperiment):
def build(self):
self.setattr_argument("a", Scannable(default=LinearScan(0, 10, 4)))
self.setattr_argument("b", Scannable(default=LinearScan(0, 10, 4)))
self.setattr_argument("c", Scannable(default=LinearScan(0, 10, 4)))
def run(self):
msm = MultiScanManager(
("a", self.a),
("b", self.b),
("c", self.c),
)
for point in msm:
print("a={} b={} c={}".format(point.a, point.b, point.c))

View File

@ -3,7 +3,8 @@ Implementation and management of scan objects.
A scan object (e.g. :class:`artiq.language.scan.LinearScan`) represents a
one-dimensional sweep of a numerical range. Multi-dimensional scans are
constructed by combining several scan objects.
constructed by combining several scan objects, for example using
:class:`artiq.language.scan.MultiScanManager`.
Iterate on a scan object to scan it, e.g. ::
@ -14,12 +15,11 @@ Iterating multiple times on the same scan object is possible, with the scan
yielding the same values each time. Iterating concurrently on the
same scan object (e.g. via nested loops) is also supported, and the
iterators are independent from each other.
Scan objects are supported both on the host and the core device.
"""
import random
import inspect
from itertools import product
from artiq.language.core import *
from artiq.language.environment import NoDefault, DefaultMissing
@ -28,7 +28,7 @@ from artiq.language import units
__all__ = ["ScanObject",
"NoScan", "LinearScan", "RandomScan", "ExplicitScan",
"Scannable"]
"Scannable", "MultiScanManager"]
class ScanObject:
@ -222,3 +222,43 @@ class Scannable:
d["global_max"] = self.global_max
d["ndecimals"] = self.ndecimals
return d
class MultiScanManager:
"""
Makes an iterator that returns elements from the first scan object until
it is exhausted, then proceeds to the next iterable, until all of the
scan objects are exhausted. Used for treating consecutive scans as a
single scan.
Scan objects must be passed as a list of tuples (name, scan_object).
Íteration produces scan points that have attributes that correspond
to the names of the scan objects, and have the last value yielded by
that scan object.
"""
def __init__(self, *args):
self.names = [a[0] for a in args]
self.scan_objects = [a[1] for a in args]
class ScanPoint:
def __init__(self, **kwargs):
self.attr = set()
for k, v in kwargs.items():
setattr(self, k, v)
self.attr.add(k)
def __repr__(self):
return ("<ScanPoint " +
" ".join("{}={}".format(k, getattr(self, k))
for k in self.attr) +
">")
self.scan_point_cls = ScanPoint
def _gen(self):
for values in product(*self.scan_objects):
d = {k: v for k, v in zip(self.names, values)}
yield self.scan_point_cls(**d)
def __iter__(self):
return self._gen()