Example #1
0
def _read_parameter_expression_v3(file_obj, vectors):
    data = formats.PARAMETER_EXPR(
        *struct.unpack(formats.PARAMETER_EXPR_PACK,
                       file_obj.read(formats.PARAMETER_EXPR_SIZE)))
    from sympy.parsing.sympy_parser import parse_expr

    if _optional.HAS_SYMENGINE:
        import symengine

        expr = symengine.sympify(
            parse_expr(file_obj.read(data.expr_size).decode(common.ENCODE)))
    else:
        expr = parse_expr(file_obj.read(data.expr_size).decode(common.ENCODE))
    symbol_map = {}
    for _ in range(data.map_elements):
        elem_data = formats.PARAM_EXPR_MAP_ELEM_V3(*struct.unpack(
            formats.PARAM_EXPR_MAP_ELEM_V3_PACK,
            file_obj.read(formats.PARAM_EXPR_MAP_ELEM_V3_SIZE),
        ))
        symbol_key = type_keys.Value(elem_data.symbol_type)

        if symbol_key == type_keys.Value.PARAMETER:
            symbol = _read_parameter(file_obj)
        elif symbol_key == type_keys.Value.PARAMETER_VECTOR:
            symbol = _read_parameter_vec(file_obj, vectors)
        else:
            raise exceptions.QpyError(
                "Invalid parameter expression map type: %s" % symbol_key)

        elem_key = type_keys.Value(elem_data.type)
        binary_data = file_obj.read(elem_data.size)
        if elem_key == type_keys.Value.INTEGER:
            value = struct.unpack("!q", binary_data)
        elif elem_key == type_keys.Value.FLOAT:
            value = struct.unpack("!d", binary_data)
        elif elem_key == type_keys.Value.COMPLEX:
            value = complex(*struct.unpack(formats.COMPLEX_PACK, binary_data))
        elif elem_key in (type_keys.Value.PARAMETER,
                          type_keys.Value.PARAMETER_VECTOR):
            value = symbol._symbol_expr
        elif elem_key == type_keys.Value.PARAMETER_EXPRESSION:
            value = common.data_from_binary(binary_data,
                                            _read_parameter_expression_v3,
                                            vectors=vectors)
        else:
            raise exceptions.QpyError(
                "Invalid parameter expression map type: %s" % elem_key)
        symbol_map[symbol] = value

    return ParameterExpression(symbol_map, expr)
Example #2
0
    def assign(cls, obj):
        if isinstance(obj, range):
            return cls.RANGE
        if isinstance(obj, tuple):
            return cls.TUPLE

        raise exceptions.QpyError(
            f"Object type '{type(obj)}' is not supported in {cls.__name__} namespace."
        )
Example #3
0
    def assign(cls, obj):
        if isinstance(obj, QuantumCircuit):
            return cls.CIRCUIT
        if isinstance(obj, ScheduleBlock):
            return cls.SCHEDULE_BLOCK

        raise exceptions.QpyError(
            f"Object type '{type(obj)}' is not supported in {cls.__name__} namespace."
        )
Example #4
0
    def assign(cls, obj):
        if isinstance(obj, Waveform):
            return cls.WAVEFORM
        if isinstance(obj, SymbolicPulse):
            return cls.SYMBOLIC_PULSE
        if isinstance(obj, Channel):
            return cls.CHANNEL

        raise exceptions.QpyError(
            f"Object type '{type(obj)}' is not supported in {cls.__name__} namespace."
        )
Example #5
0
    def retrieve(cls, type_key):
        if type_key == cls.LEFT:
            return AlignLeft
        if type_key == cls.RIGHT:
            return AlignRight
        if type_key == cls.SEQUENTIAL:
            return AlignSequential
        if type_key == cls.EQUISPACED:
            return AlignEquispaced

        raise exceptions.QpyError(
            f"A class corresponding to type key '{type_key}' is not found in {cls.__name__} namespace."
        )
Example #6
0
    def assign(cls, obj):
        if isinstance(obj, AlignLeft):
            return cls.LEFT
        if isinstance(obj, AlignRight):
            return cls.RIGHT
        if isinstance(obj, AlignSequential):
            return cls.SEQUENTIAL
        if isinstance(obj, AlignEquispaced):
            return cls.EQUISPACED

        raise exceptions.QpyError(
            f"Object type '{type(obj)}' is not supported in {cls.__name__} namespace."
        )
Example #7
0
    def assign(cls, obj):
        if isinstance(obj, PauliEvolutionGate):
            return cls.PAULI_EVOL_GATE
        if isinstance(obj, ControlledGate):
            return cls.CONTROLLED_GATE
        if isinstance(obj, Gate):
            return cls.GATE
        if isinstance(obj, Instruction):
            return cls.INSTRUCTION

        raise exceptions.QpyError(
            f"Object type '{type(obj)}' is not supported in {cls.__name__} namespace."
        )
Example #8
0
def loads_value(type_key, binary_data, version, vectors):
    """Deserialize input binary data to value object.

    Args:
        type_key (ValueTypeKey): Type enum information.
        binary_data (bytes): Data to deserialize.
        version (int): QPY version.
        vectors (dict): ParameterVector in current scope.

    Returns:
        any: Deserialized value object.

    Raises:
        QpyError: Serializer for given format is not ready.
    """
    # pylint: disable=too-many-return-statements

    if isinstance(type_key, bytes):
        type_key = type_keys.Value(type_key)

    if type_key == type_keys.Value.INTEGER:
        return struct.unpack("!q", binary_data)[0]
    if type_key == type_keys.Value.FLOAT:
        return struct.unpack("!d", binary_data)[0]
    if type_key == type_keys.Value.COMPLEX:
        return complex(*struct.unpack(formats.COMPLEX_PACK, binary_data))
    if type_key == type_keys.Value.NUMPY_OBJ:
        return common.data_from_binary(binary_data, np.load)
    if type_key == type_keys.Value.STRING:
        return binary_data.decode(common.ENCODE)
    if type_key == type_keys.Value.NULL:
        return None
    if type_key == type_keys.Value.PARAMETER_VECTOR:
        return common.data_from_binary(binary_data,
                                       _read_parameter_vec,
                                       vectors=vectors)
    if type_key == type_keys.Value.PARAMETER:
        return common.data_from_binary(binary_data, _read_parameter)
    if type_key == type_keys.Value.PARAMETER_EXPRESSION:
        if version < 3:
            return common.data_from_binary(binary_data,
                                           _read_parameter_expression)
        else:
            return common.data_from_binary(binary_data,
                                           _read_parameter_expression_v3,
                                           vectors=vectors)

    raise exceptions.QpyError(
        f"Serialization for {type_key} is not implemented in value I/O.")
Example #9
0
def loads_value(type_key, binary_data, version, vectors):
    """Deserialize input binary data to value object.

    Args:
        type_key (ValueTypeKey): Type enum information.
        binary_data (bytes): Data to deserialize.
        version (int): QPY version.
        vectors (dict): ParameterVector in current scope.

    Returns:
        any: Deserialized value object.

    Raises:
        QpyError: Serializer for given format is not ready.
    """
    if isinstance(type_key, bytes):
        type_key = TypeKey(type_key)

    if type_key == TypeKey.INTEGER:
        obj = struct.unpack("!q", binary_data)[0]
    elif type_key == TypeKey.FLOAT:
        obj = struct.unpack("!d", binary_data)[0]
    elif type_key == TypeKey.COMPLEX:
        obj = complex(*struct.unpack(formats.COMPLEX_PACK, binary_data))
    elif type_key == TypeKey.NUMPY_OBJ:
        obj = common.data_from_binary(binary_data, np.load)
    elif type_key == TypeKey.STRING:
        obj = binary_data.decode(ENCODE)
    elif type_key == TypeKey.NULL:
        obj = None
    elif type_key == TypeKey.PARAMETER_VECTOR:
        obj = common.data_from_binary(binary_data,
                                      _read_parameter_vec,
                                      vectors=vectors)
    elif type_key == TypeKey.PARAMETER:
        obj = common.data_from_binary(binary_data, _read_parameter)
    elif type_key == TypeKey.PARAMETER_EXPRESSION:
        if version < 3:
            obj = common.data_from_binary(binary_data,
                                          _read_parameter_expression)
        else:
            obj = common.data_from_binary(binary_data,
                                          _read_parameter_expression_v3,
                                          vectors=vectors)
    else:
        raise exceptions.QpyError(
            f"Serialization for {type_key} is not implemented in value I/O.")

    return obj
Example #10
0
    def assign(cls, obj):
        if isinstance(obj, DriveChannel):
            return cls.DRIVE
        if isinstance(obj, ControlChannel):
            return cls.CONTROL
        if isinstance(obj, MeasureChannel):
            return cls.MEASURE
        if isinstance(obj, AcquireChannel):
            return cls.ACQURE
        if isinstance(obj, MemorySlot):
            return cls.MEM_SLOT
        if isinstance(obj, RegisterSlot):
            return cls.REG_SLOT

        raise exceptions.QpyError(
            f"Object type '{type(obj)}' is not supported in {cls.__name__} namespace."
        )
Example #11
0
    def retrieve(cls, type_key):
        if type_key == cls.DRIVE:
            return DriveChannel
        if type_key == cls.CONTROL:
            return ControlChannel
        if type_key == cls.MEASURE:
            return MeasureChannel
        if type_key == cls.ACQURE:
            return AcquireChannel
        if type_key == cls.MEM_SLOT:
            return MemorySlot
        if type_key == cls.REG_SLOT:
            return RegisterSlot

        raise exceptions.QpyError(
            f"A class corresponding to type key '{type_key}' is not found in {cls.__name__} namespace."
        )
Example #12
0
    def assign(cls, obj):
        """Assign type key to given object.

        Args:
            obj (any): Arbitrary object to evaluate.

        Returns:
            ContainerTypeKey: Corresponding key object.

        Raises:
            QpyError: if object type is not defined in QPY. Likely not supported.
        """
        if isinstance(obj, QuantumCircuit):
            return cls.CIRCUIT

        raise exceptions.QpyError(
            f"Object type {type(obj)} is not supported in {cls.__name__} namespace."
        )
Example #13
0
    def retrieve(cls, type_key):
        if type_key == cls.ACQUIRE:
            return Acquire
        if type_key == cls.PLAY:
            return Play
        if type_key == cls.DELAY:
            return Delay
        if type_key == cls.SET_FREQUENCY:
            return SetFrequency
        if type_key == cls.SHIFT_FREQUENCY:
            return ShiftFrequency
        if type_key == cls.SET_PHASE:
            return SetPhase
        if type_key == cls.SHIFT_PHASE:
            return ShiftPhase
        if type_key == cls.BARRIER:
            return RelativeBarrier

        raise exceptions.QpyError(
            f"A class corresponding to type key '{type_key}' is not found in {cls.__name__} namespace."
        )
Example #14
0
    def assign(cls, obj):
        if isinstance(obj, Acquire):
            return cls.ACQUIRE
        if isinstance(obj, Play):
            return cls.PLAY
        if isinstance(obj, Delay):
            return cls.DELAY
        if isinstance(obj, SetFrequency):
            return cls.SET_FREQUENCY
        if isinstance(obj, ShiftFrequency):
            return cls.SHIFT_FREQUENCY
        if isinstance(obj, SetPhase):
            return cls.SET_PHASE
        if isinstance(obj, ShiftPhase):
            return cls.SHIFT_PHASE
        if isinstance(obj, RelativeBarrier):
            return cls.BARRIER

        raise exceptions.QpyError(
            f"Object type '{type(obj)}' is not supported in {cls.__name__} namespace."
        )
Example #15
0
    def assign(cls, obj):
        """Assign type key to given object.

        Args:
            obj (any): Arbitrary object to evaluate.

        Returns:
            CircuitInstructionTypeKey: Corresponding key object.

        Raises:
            QpyError: if object type is not defined in QPY. Likely not supported.
        """
        if isinstance(obj, PauliEvolutionGate):
            return cls.PAULI_EVOL_GATE
        if isinstance(obj, Gate):
            return cls.GATE
        if isinstance(obj, CircuitInstruction):
            return cls.INSTRUCTION

        raise exceptions.QpyError(
            f"Object type {type(obj)} is not supported in {cls.__name__} namespace."
        )
Example #16
0
    def assign(cls, obj):
        if isinstance(obj, int):
            return cls.INTEGER
        if isinstance(obj, float):
            return cls.FLOAT
        if isinstance(obj, complex):
            return cls.COMPLEX
        if isinstance(obj, (np.integer, np.floating, np.complexfloating, np.ndarray)):
            return cls.NUMPY_OBJ
        if isinstance(obj, ParameterVectorElement):
            return cls.PARAMETER_VECTOR
        if isinstance(obj, Parameter):
            return cls.PARAMETER
        if isinstance(obj, ParameterExpression):
            return cls.PARAMETER_EXPRESSION
        if isinstance(obj, str):
            return cls.STRING
        if obj is None:
            return cls.NULL

        raise exceptions.QpyError(
            f"Object type '{type(obj)}' is not supported in {cls.__name__} namespace."
        )
Example #17
0
def dumps_value(obj):
    """Serialize input value object.

    Args:
        obj (any): Arbitrary value object to serialize.

    Returns:
        tuple: TypeKey and binary data.

    Raises:
        QpyError: Serializer for given format is not ready.
    """
    type_key = type_keys.Value.assign(obj)

    if type_key == type_keys.Value.INTEGER:
        binary_data = struct.pack("!q", obj)
    elif type_key == type_keys.Value.FLOAT:
        binary_data = struct.pack("!d", obj)
    elif type_key == type_keys.Value.COMPLEX:
        binary_data = struct.pack(formats.COMPLEX_PACK, obj.real, obj.imag)
    elif type_key == type_keys.Value.NUMPY_OBJ:
        binary_data = common.data_to_binary(obj, np.save)
    elif type_key == type_keys.Value.STRING:
        binary_data = obj.encode(common.ENCODE)
    elif type_key == type_keys.Value.NULL:
        binary_data = b""
    elif type_key == type_keys.Value.PARAMETER_VECTOR:
        binary_data = common.data_to_binary(obj, _write_parameter_vec)
    elif type_key == type_keys.Value.PARAMETER:
        binary_data = common.data_to_binary(obj, _write_parameter)
    elif type_key == type_keys.Value.PARAMETER_EXPRESSION:
        binary_data = common.data_to_binary(obj, _write_parameter_expression)
    else:
        raise exceptions.QpyError(
            f"Serialization for {type_key} is not implemented in value I/O.")

    return type_key, binary_data
Example #18
0
    def assign(cls, obj):
        """Assign type key to given object.

        Args:
            obj (any): Arbitrary object to evaluate.

        Returns:
            ValueTypeKey: Corresponding key object.

        Raises:
            QpyError: if object type is not defined in QPY. Likely not supported.
        """
        if isinstance(obj, int):
            return cls.INTEGER
        if isinstance(obj, float):
            return cls.FLOAT
        if isinstance(obj, complex):
            return cls.COMPLEX
        if isinstance(
                obj,
            (np.integer, np.floating, np.ndarray, np.complexfloating)):
            return cls.NUMPY_OBJ
        if isinstance(obj, ParameterVectorElement):
            return cls.PARAMETER_VECTOR
        if isinstance(obj, Parameter):
            return cls.PARAMETER
        if isinstance(obj, ParameterExpression):
            return cls.PARAMETER_EXPRESSION
        if isinstance(obj, str):
            return cls.STRING
        if obj is None:
            return cls.NULL

        raise exceptions.QpyError(
            f"Object type {type(obj)} is not supported in {cls.__name__} namespace."
        )
Example #19
0
def read_circuit(file_obj, version):
    """Read a single QuantumCircuit object from the file like object.

    Args:
        file_obj (FILE): The file like object to read the circuit data from.
        version (int): QPY version.

    Returns:
        QuantumCircuit: The circuit object from the file.

    Raises:
        QpyError: Invalid register.
    """
    vectors = {}
    if version < 2:
        header, name, metadata = _read_header(file_obj)
    else:
        header, name, metadata = _read_header_v2(file_obj, version, vectors)

    global_phase = header["global_phase"]
    num_qubits = header["num_qubits"]
    num_clbits = header["num_clbits"]
    num_registers = header["num_registers"]
    num_instructions = header["num_instructions"]
    out_registers = {"q": {}, "c": {}}
    if num_registers > 0:
        circ = QuantumCircuit(name=name,
                              global_phase=global_phase,
                              metadata=metadata)
        if version < 4:
            registers = _read_registers(file_obj, num_registers)
        else:
            registers = _read_registers_v4(file_obj, num_registers)

        for bit_type_label, bit_type, reg_type in [
            ("q", Qubit, QuantumRegister),
            ("c", Clbit, ClassicalRegister),
        ]:
            register_bits = set()
            # Add quantum registers and bits
            for register_name in registers[bit_type_label]:
                standalone, indices, in_circuit = registers[bit_type_label][
                    register_name]
                indices_defined = [x for x in indices if x >= 0]
                # If a register has no bits in the circuit skip it
                if not indices_defined:
                    continue
                if standalone:
                    start = min(indices_defined)
                    count = start
                    out_of_order = False
                    for index in indices:
                        if index < 0:
                            out_of_order = True
                            continue
                        if not out_of_order and index != count:
                            out_of_order = True
                        count += 1
                        if index in register_bits:
                            # If we have a bit in the position already it's been
                            # added by an earlier register in the circuit
                            # otherwise it's invalid qpy
                            if not in_circuit:
                                continue
                            raise exceptions.QpyError(
                                "Duplicate register bits found")

                        register_bits.add(index)

                    num_reg_bits = len(indices)
                    # Create a standlone register of the appropriate length (from
                    # the number of indices in the qpy data) and add it to the circuit
                    reg = reg_type(num_reg_bits, register_name)
                    # If any bits from qreg are out of order in the circuit handle
                    # is case
                    if out_of_order or not in_circuit:
                        for index, pos in sorted(enumerate(x for x in indices
                                                           if x >= 0),
                                                 key=lambda x: x[1]):
                            if bit_type_label == "q":
                                bit_len = len(circ.qubits)
                            else:
                                bit_len = len(circ.clbits)
                            if pos < bit_len:
                                # If we have a bit in the position already it's been
                                # added by an earlier register in the circuit
                                # otherwise it's invalid qpy
                                if not in_circuit:
                                    continue
                                raise exceptions.QpyError(
                                    "Duplicate register bits found")
                            # Fill any holes between the current register bit and the
                            # next one
                            if pos > bit_len:
                                bits = [
                                    bit_type() for _ in range(pos - bit_len)
                                ]
                                circ.add_bits(bits)
                            circ.add_bits([reg[index]])
                        if in_circuit:
                            circ.add_register(reg)
                    else:
                        if bit_type_label == "q":
                            bit_len = len(circ.qubits)
                        else:
                            bit_len = len(circ.clbits)
                        # If there is a hole between the start of the register and the
                        # current bits and standalone bits to fill the gap.
                        if start > len(circ.qubits):
                            bits = [bit_type() for _ in range(start - bit_len)]
                            circ.add_bits(bit_len)
                        if in_circuit:
                            circ.add_register(reg)
                        out_registers[bit_type_label][register_name] = reg
                else:
                    for index in indices:
                        if bit_type_label == "q":
                            bit_len = len(circ.qubits)
                        else:
                            bit_len = len(circ.clbits)
                        # Add any missing bits
                        bits = [bit_type() for _ in range(index + 1 - bit_len)]
                        circ.add_bits(bits)
                        if index in register_bits:
                            raise exceptions.QpyError(
                                "Duplicate register bits found")
                        register_bits.add(index)
                    if bit_type_label == "q":
                        bits = [circ.qubits[i] for i in indices]
                    else:
                        bits = [circ.clbits[i] for i in indices]
                    reg = reg_type(name=register_name, bits=bits)
                    if in_circuit:
                        circ.add_register(reg)
                    out_registers[bit_type_label][register_name] = reg
        # If we don't have sufficient bits in the circuit after adding
        # all the registers add more bits to fill the circuit
        if len(circ.qubits) < num_qubits:
            qubits = [Qubit() for _ in range(num_qubits - len(circ.qubits))]
            circ.add_bits(qubits)
        if len(circ.clbits) < num_clbits:
            clbits = [Clbit() for _ in range(num_qubits - len(circ.clbits))]
            circ.add_bits(clbits)
    else:
        circ = QuantumCircuit(
            num_qubits,
            num_clbits,
            name=name,
            global_phase=global_phase,
            metadata=metadata,
        )
    custom_instructions = _read_custom_instructions(file_obj, version, vectors)
    for _instruction in range(num_instructions):
        _read_instruction(file_obj, circ, out_registers, custom_instructions,
                          version, vectors)
    for vec_name, (vector, initialized_params) in vectors.items():
        if len(initialized_params) != len(vector):
            warnings.warn(
                f"The ParameterVector: '{vec_name}' is not fully identical to its "
                "pre-serialization state. Elements "
                f"{', '.join([str(x) for x in set(range(len(vector))) - initialized_params])} "
                "in the ParameterVector will be not equal to the pre-serialized ParameterVector "
                f"as they weren't used in the circuit: {circ.name}",
                UserWarning,
            )

    return circ