From c71fe2979215727bf7aa20293ec2467147cd1b38 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 26 Jun 2015 16:20:13 +0200 Subject: [PATCH] simplify unit system and use floats by default --- artiq/__init__.py | 4 +- artiq/coredevice/core.py | 6 +- artiq/devices/lda/driver.py | 24 +-- artiq/devices/thorlabs_tcube/driver.py | 33 ++-- artiq/gui/moninj.py | 3 +- artiq/language/core.py | 2 +- artiq/language/units.py | 259 +------------------------ artiq/master/worker.py | 3 +- artiq/protocols/pyon.py | 9 - artiq/test/full_stack.py | 35 +--- artiq/test/lda.py | 6 +- artiq/test/thorlabs_tcube.py | 2 +- artiq/test/transforms.py | 14 +- artiq/transforms/lower_units.py | 190 ------------------ artiq/transforms/tools.py | 18 +- benchmarks/rpc_timing.py | 2 +- examples/master/ddb.pyon | 9 +- 17 files changed, 43 insertions(+), 576 deletions(-) delete mode 100644 artiq/transforms/lower_units.py diff --git a/artiq/__init__.py b/artiq/__init__.py index 934cfbf49..ebdb62601 100644 --- a/artiq/__init__.py +++ b/artiq/__init__.py @@ -1,6 +1,4 @@ from artiq.language.core import * from artiq.language.experiment import Experiment from artiq.language.db import * -from artiq.language.units import check_unit -from artiq.language.units import ps, ns, us, ms, s -from artiq.language.units import Hz, kHz, MHz, GHz +from artiq.language.units import * diff --git a/artiq/coredevice/core.py b/artiq/coredevice/core.py index 2467980f5..7f7549115 100644 --- a/artiq/coredevice/core.py +++ b/artiq/coredevice/core.py @@ -5,7 +5,6 @@ from artiq.language.db import * from artiq.language.units import ns from artiq.transforms.inline import inline -from artiq.transforms.lower_units import lower_units from artiq.transforms.quantize_time import quantize_time from artiq.transforms.remove_inter_assigns import remove_inter_assigns from artiq.transforms.fold_constants import fold_constants @@ -61,13 +60,10 @@ class Core(AutoDB): def transform_stack(self, func_def, rpc_map, exception_map, debug_unparse=_no_debug_unparse): - lower_units(func_def, rpc_map) - debug_unparse("lower_units", func_def) - remove_inter_assigns(func_def) debug_unparse("remove_inter_assigns_1", func_def) - quantize_time(func_def, self.ref_period.amount) + quantize_time(func_def, self.ref_period) debug_unparse("quantize_time", func_def) fold_constants(func_def) diff --git a/artiq/devices/lda/driver.py b/artiq/devices/lda/driver.py index 3f5aaa2e2..c198f04c7 100644 --- a/artiq/devices/lda/driver.py +++ b/artiq/devices/lda/driver.py @@ -2,7 +2,7 @@ import logging import ctypes import struct -from artiq.language.units import dB, check_unit, Quantity +from artiq.language.units import dB logger = logging.getLogger("lda") @@ -47,14 +47,7 @@ class Ldasim: """ step = self.get_att_step_size() - - if isinstance(attenuation, Quantity): - check_unit(attenuation, "dB") - att = attenuation - else: - att = attenuation*dB - - att = round(att/step)*step + att = round(attenuation/step)*step if att > self.get_att_max(): raise ValueError("Cannot set attenuation {} > {}" @@ -62,7 +55,7 @@ class Ldasim: elif att < 0*dB: raise ValueError("Cannot set attenuation {} < 0".format(att)) else: - att = round(att.amount*4)/4. * dB + att = round(att*4)/4. * dB self._attenuation = att def ping(self): @@ -218,14 +211,7 @@ class Lda: """ step = self.get_att_step_size() - - if isinstance(attenuation, Quantity): - check_unit(attenuation, "dB") - att = attenuation - else: - att = attenuation*dB - - att = round(att/step)*step + att = round(attenuation/step)*step if att > self.get_att_max(): raise ValueError("Cannot set attenuation {} > {}" @@ -233,7 +219,7 @@ class Lda: elif att < 0*dB: raise ValueError("Cannot set attenuation {} < 0".format(att)) else: - self.set(0x8d, bytes([int(round(att.amount*4))])) + self.set(0x8d, bytes([int(round(att*4))])) def ping(self): try: diff --git a/artiq/devices/thorlabs_tcube/driver.py b/artiq/devices/thorlabs_tcube/driver.py index b3403a03d..e7e759d5a 100644 --- a/artiq/devices/thorlabs_tcube/driver.py +++ b/artiq/devices/thorlabs_tcube/driver.py @@ -4,7 +4,7 @@ import struct as st import serial -from artiq.language.units import V, strip_unit +from artiq.language.units import V logger = logging.getLogger(__name__) @@ -302,7 +302,7 @@ class Tcube: class Tpz(Tcube): def __init__(self, serial_dev): Tcube.__init__(self, serial_dev) - self.voltage_limit = self.get_tpz_io_settings()[0].amount + self.voltage_limit = self.get_tpz_io_settings()[0] def handle_message(self, msg): msg_id = msg.id @@ -372,8 +372,6 @@ class Tpz(Tcube): between the three values 75 V, 100 V and 150 V. """ - voltage = strip_unit(voltage, "V") - if voltage < 0 or voltage > self.voltage_limit: raise ValueError("Voltage must be in range [0;{}]" .format(self.voltage_limit)) @@ -390,7 +388,7 @@ class Tpz(Tcube): get_msg = self.send_request(MGMSG.PZ_REQ_OUTPUTVOLTS, [MGMSG.PZ_GET_OUTPUTVOLTS], 1) - return st.unpack("` method. """ - output = strip_unit(output, "V") volt = round(output*32767/self.voltage_limit) payload = st.pack("` for the meaning of those parameters. - :rtype: a 2 elements tuple (Quantity, int) + :rtype: a 2 elements tuple (int, int) """ get_msg = self.send_request(MGMSG.PZ_REQ_TPZ_IOSETTINGS, [MGMSG.PZ_GET_TPZ_IOSETTINGS], 1) voltage_limit, hub_analog_input = st.unpack(" new rpc number - self.rpc_remap = defaultdict(lambda: len(self.rpc_remap)) - self.variable_units = dict() - - def visit_Name(self, node): - try: - unit = self.variable_units[node.id] - except KeyError: - pass - else: - if unit is not None: - node.unit = unit - return node - - def visit_BoolOp(self, node): - self.generic_visit(node) - us = [getattr(value, "unit", None) for value in node.values] - if not all(u == us[0] for u in us[1:]): - raise units.DimensionError - return node - - def visit_Compare(self, node): - self.generic_visit(node) - u0 = getattr(node.left, "unit", None) - us = [getattr(comparator, "unit", None) - for comparator in node.comparators] - if not all(u == u0 for u in us): - raise units.DimensionError - return node - - def visit_UnaryOp(self, node): - self.generic_visit(node) - if hasattr(node.operand, "unit"): - node.unit = node.operand.unit - return node - - def visit_BinOp(self, node): - self.generic_visit(node) - op = type(node.op) - left_unit = getattr(node.left, "unit", None) - right_unit = getattr(node.right, "unit", None) - if op in (ast.Add, ast.Sub, ast.Mod): - unit = units.addsub_dimension(left_unit, right_unit) - elif op == ast.Mult: - unit = units.mul_dimension(left_unit, right_unit) - elif op in (ast.Div, ast.FloorDiv): - unit = units.div_dimension(left_unit, right_unit) - else: - if left_unit is not None or right_unit is not None: - raise units.DimensionError - unit = None - if unit is not None: - node.unit = unit - return node - - def visit_Attribute(self, node): - self.generic_visit(node) - if node.attr == "amount" and hasattr(node.value, "unit"): - del node.value.unit - return node.value - else: - return node - - def visit_List(self, node): - self.generic_visit(node) - if node.elts: - us = [getattr(elt, "unit", None) for elt in node.elts] - if not all(u == us[0] for u in us[1:]): - raise units.DimensionError - node.unit = us[0] - return node - - def visit_ListComp(self, node): - self.generic_visit(node) - if hasattr(node.elt, "unit"): - node.unit = node.elt.unit - return node - - def visit_Call(self, node): - self.generic_visit(node) - if node.func.id == "Quantity": - amount, unit = node.args - amount.unit = unit.s - return amount - elif node.func.id in ("now", "cycles_to_time"): - node.unit = "s" - elif node.func.id == "syscall": - # only RPCs can have units - if node.args[0].s == "rpc": - unit_list = tuple(getattr(arg, "unit", None) - for arg in node.args[2:]) - rpc_n = node.args[1].n - node.args[1].n = self.rpc_remap[(rpc_n, (unit_list))] - else: - if any(hasattr(arg, "unit") for arg in node.args): - raise units.DimensionError - elif node.func.id in ("delay", "at", "time_to_cycles", "watchdog"): - if getattr(node.args[0], "unit", None) != "s": - raise units.DimensionError - elif node.func.id == "check_unit": - self.generic_visit(node) - elif node.func.id in embeddable_func_names: - # must be last (some embeddable funcs may have units) - if any(hasattr(arg, "unit") for arg in node.args): - raise units.DimensionError - return node - - def visit_Expr(self, node): - self.generic_visit(node) - if (isinstance(node.value, ast.Call) - and node.value.func.id == "check_unit"): - call = node.value - if (isinstance(call.args[1], ast.NameConstant) - and call.args[1].value is None): - if hasattr(call.value.args[0], "unit"): - raise units.DimensionError - elif isinstance(call.args[1], ast.Str): - if getattr(call.args[0], "unit", None) != call.args[1].s: - raise units.DimensionError - else: - raise NotImplementedError - return None - else: - return node - - def _update_target(self, target, unit): - if isinstance(target, ast.Name): - if target.id in self.variable_units: - if self.variable_units[target.id] != unit: - raise TypeError( - "Inconsistent units for variable '{}': '{}' and '{}'" - .format(target.id, - self.variable_units[target.id], - unit)) - else: - self.variable_units[target.id] = unit - - def visit_Assign(self, node): - node.value = self.visit(node.value) - unit = getattr(node.value, "unit", None) - for target in node.targets: - self._update_target(target, unit) - return node - - def visit_AugAssign(self, node): - value = self.visit_BinOp(ast.BinOp( - op=node.op, left=node.target, right=node.value)) - unit = getattr(value, "unit", None) - self._update_target(node.target, unit) - return node - - # Only dimensionless iterators are supported - def visit_For(self, node): - self.generic_visit(node) - self._update_target(node.target, None) - return node - - -def lower_units(func_def, rpc_map): - ul = _UnitsLowerer(rpc_map) - ul.visit(func_def) - original_map = copy(rpc_map) - for (original_rpcn, unit_list), new_rpcn in ul.rpc_remap.items(): - rpc_map[new_rpcn] = _add_units(original_map[original_rpcn], unit_list) diff --git a/artiq/transforms/tools.py b/artiq/transforms/tools.py index d9daf838f..1b68fd0f3 100644 --- a/artiq/transforms/tools.py +++ b/artiq/transforms/tools.py @@ -11,7 +11,7 @@ embeddable_funcs = ( core_language.syscall, core_language.watchdog, range, bool, int, float, round, len, core_language.int64, core_language.round64, - Fraction, units.Quantity, units.check_unit, core_language.EncodedException + Fraction, core_language.EncodedException ) embeddable_func_names = {func.__name__ for func in embeddable_funcs} @@ -61,11 +61,6 @@ def value_to_ast(value): for kg in core_language.kernel_globals: if value is getattr(core_language, kg): return ast.Name(kg, ast.Load()) - if isinstance(value, units.Quantity): - return ast.Call( - func=ast.Name("Quantity", ast.Load()), - args=[value_to_ast(value.amount), ast.Str(value.unit)], - keywords=[], starargs=None, kwargs=None) raise NotASTRepresentable(str(value)) @@ -88,14 +83,6 @@ def eval_constant(node): numerator = eval_constant(node.args[0]) denominator = eval_constant(node.args[1]) return Fraction(numerator, denominator) - elif funcname == "Quantity": - amount, unit = node.args - amount = eval_constant(amount) - try: - unit = getattr(units, unit.id) - except: - raise NotConstant - return units.Quantity(amount, unit) else: raise NotConstant else: @@ -105,8 +92,7 @@ def eval_constant(node): _replaceable_funcs = { "bool", "int", "float", "round", "int64", "round64", "Fraction", - "time_to_cycles", "cycles_to_time", - "Quantity" + "time_to_cycles", "cycles_to_time" } diff --git a/benchmarks/rpc_timing.py b/benchmarks/rpc_timing.py index b14da820a..33e8152d9 100644 --- a/benchmarks/rpc_timing.py +++ b/benchmarks/rpc_timing.py @@ -22,7 +22,7 @@ class RPCTiming(Experiment, AutoDB): t1 = self.core.get_rtio_time() self.nop(10) t2 = self.core.get_rtio_time() - self.ts[i] = float(t2.amount - t1.amount) + self.ts[i] = t2 - t1 def run(self): self.bench() diff --git a/examples/master/ddb.pyon b/examples/master/ddb.pyon index 75c17fec8..ff6772fcb 100644 --- a/examples/master/ddb.pyon +++ b/examples/master/ddb.pyon @@ -60,22 +60,19 @@ "type": "local", "module": "artiq.coredevice.dds", "class": "DDS", - "arguments": {"sysclk": Quantity(Fraction(1000000000, 1), "Hz"), - "channel": 0} + "arguments": {"sysclk": 1e9, "channel": 0} }, "dds1": { "type": "local", "module": "artiq.coredevice.dds", "class": "DDS", - "arguments": {"sysclk": Quantity(Fraction(1000000000, 1), "Hz"), - "channel": 1} + "arguments": {"sysclk": 1e9, "channel": 1} }, "dds2": { "type": "local", "module": "artiq.coredevice.dds", "class": "DDS", - "arguments": {"sysclk": Quantity(Fraction(1000000000, 1), "Hz"), - "channel": 2} + "arguments": {"sysclk": 1e9, "channel": 2} }, "qc_q1_0": {