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)
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." )
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." )
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." )
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." )
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." )
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." )
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.")
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
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." )
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." )
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." )
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." )
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." )
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." )
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." )
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
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." )
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