def test_from_dict_per_class(self): """Test Qobj and its subclass representations given a dictionary.""" test_parameters = { Qobj: (self.valid_qobj, self.valid_dict), QobjConfig: (QobjConfig(shots=1, memory_slots=2), { 'shots': 1, 'memory_slots': 2 }), QobjExperiment: (QobjExperiment(instructions=[ QobjInstruction(name='u1', qubits=[1], params=[0.4]) ]), { 'instructions': { 'name': 'u1', 'qubits': [1], 'params': [0.4] } }), QobjInstruction: (QobjInstruction(name='u1', qubits=[1], params=[0.4]), { 'name': 'u1', 'qubits': [1], 'params': [0.4] }) } for qobj_class, (qobj, expected_dict) in test_parameters.items(): with self.subTest(msg=str(qobj_class)): self.assertEqual(qobj, qobj_class.from_dict(expected_dict))
def setUp(self): self.valid_qobj = Qobj( qobj_id='12345', header={}, config=QobjConfig(shots=1024, memory_slots=2, max_credits=10), experiments=[ QobjExperiment(instructions=[ QobjInstruction(name='u1', qubits=[1], params=[0.4]), QobjInstruction(name='u2', qubits=[1], params=[0.4, 0.2]) ]) ] ) self.valid_dict = { 'qobj_id': '12345', 'type': 'QASM', 'schema_version': '1.0.0', 'header': {}, 'config': {'max_credits': 10, 'memory_slots': 2, 'shots': 1024}, 'experiments': [ {'instructions': [ {'name': 'u1', 'params': [0.4], 'qubits': [1]}, {'name': 'u2', 'params': [0.4, 0.2], 'qubits': [1]} ]} ], } self.bad_qobj = copy.deepcopy(self.valid_qobj) self.bad_qobj.experiments = None # set experiments to None to cause the qobj to be invalid
def measure_instr(qubits, memory, registers=None): """Create a multi-qubit measure instruction""" if len(qubits) != len(memory): raise ValueError("Number of qubits does not match number of memory") if registers is None: return QobjInstruction(name='measure', qubits=qubits, memory=memory) # Case where we also measure to registers if len(qubits) != len(registers): raise ValueError("Number of qubits does not match number of registers") return QobjInstruction(name='measure', qubits=qubits, memory=memory, register=registers)
def _run_job(self, job_id, qobj): """Run a Qobj on the backend.""" self._validate(qobj) final_state_key = 32767 # Internal key for final state snapshot # Add final snapshots to circuits for experiment in qobj.experiments: experiment.instructions.append( QobjInstruction(name='snapshot', params=[final_state_key]) ) result = super()._run_job(job_id, qobj) # Replace backend name with current backend result.backend_name = self.name # Extract final state snapshot and move to 'statevector' data field for experiment_result in result.results.values(): snapshots = experiment_result.snapshots if str(final_state_key) in snapshots: final_state_key = str(final_state_key) # Pop off final snapshot added above final_state = snapshots.pop(final_state_key, None) final_state = final_state['statevector'][0] # Add final state to results data experiment_result.data['statevector'] = final_state # Remove snapshot dict if empty if snapshots == {}: experiment_result.data.pop('snapshots', None) return result
def _run_job(self, job_id, qobj): """Run a Qobj on the backend.""" self._validate(qobj) final_state_key = 32767 # Internal key for final state snapshot # Add final snapshots to circuits for experiment in qobj.experiments: experiment.instructions.append( QobjInstruction(name='snapshot', params=[final_state_key], label='MISSING', type='MISSING') ) result = super()._run_job(job_id, qobj) # Remove added snapshot from qobj for experiment in qobj.experiments: del experiment.instructions[-1] # Extract final state snapshot and move to 'statevector' data field for experiment_result in result.results: snapshots = experiment_result.data.snapshots.to_dict() if str(final_state_key) in snapshots: final_state_key = str(final_state_key) # Pop off final snapshot added above final_state = snapshots.pop(final_state_key, None) final_state = final_state['statevector'][0] # Add final state to results data experiment_result.data.statevector = final_state # Remove snapshot dict if empty if snapshots == {}: delattr(experiment_result.data, 'snapshots') return result
def _run_job(self, qobj): """Run a Qobj on the backend.""" self._validate(qobj) final_state_key = 32767 # Internal key for final state snapshot # Add final snapshots to circuits for experiment in qobj.experiments: experiment.instructions.append( QobjInstruction(name='snapshot', params=[final_state_key])) result = super()._run_job(qobj)._result # Replace backend name with current backend result['backend'] = self._configuration['name'] # Extract final state snapshot and move to 'statevector' data field for res in result['result']: snapshots = res['data']['snapshots'] if str(final_state_key) in snapshots: final_state_key = str(final_state_key) # Pop off final snapshot added above final_state = snapshots.pop(final_state_key, None) final_state = final_state['statevector'][0] # Add final state to results data res['data']['statevector'] = final_state # Remove snapshot dict if empty if snapshots == {}: res['data'].pop('snapshots', None) return Result(result)
def test_create_qobj(self): """Test creation of a Qobj based on the individual elements.""" config = QobjConfig(max_credits=10, shots=1024, memory_slots=2) instruction_1 = QobjInstruction(name='u1', qubits=[1], params=[0.4]) instruction_2 = QobjInstruction(name='u2', qubits=[1], params=[0.4, 0.2]) instructions = [instruction_1, instruction_2] experiment_1 = QobjExperiment(instructions=instructions) experiments = [experiment_1] qobj = Qobj(id='12345', config=config, experiments=experiments, header={}) expected = { 'id': '12345', 'type': 'QASM', 'schema_version': '1.0.0', 'header': {}, 'config': { 'max_credits': 10, 'memory_slots': 2, 'shots': 1024 }, 'experiments': [{ 'instructions': [{ 'name': 'u1', 'params': [0.4], 'qubits': [1] }, { 'name': 'u2', 'params': [0.4, 0.2], 'qubits': [1] }] }], } self.assertEqual(qobj.as_dict(), expected)
def test_create_qobj(self): """Test creation of a Qobj based on the individual elements.""" config = QobjConfig(max_credits=10, shots=1024, backend_name='backend') circuit_config = QobjExperimentConfig( seed=1234, basis_gates='u1,u2,u3,cx,id,snapshot', coupling_map=None, layout=None) circuit_config.seed = 1234 instruction_1 = QobjInstruction(name='u1', qubits=[1], params=[0.4]) instruction_2 = QobjInstruction(name='u2', qubits=[1], params=[0.4, 0.2]) instructions = [instruction_1, instruction_2] compiled_circuit = QobjCompiledCircuit(header=None, operations=instructions) experiment_1 = QobjExperiment(name='circuit1', config=circuit_config, compiled_circuit=compiled_circuit, compiled_circuit_qasm='compiled_qasm') experiments = [experiment_1] qobj = Qobj(id='12345', config=config, circuits=experiments) expected = {'id': '12345', 'type': 'QASM', 'config': {'max_credits': 10, 'shots': 1024, 'backend_name': 'backend'}, 'circuits': [ { 'name': 'circuit1', 'config': { 'seed': 1234, 'basis_gates': 'u1,u2,u3,cx,id,snapshot', 'coupling_map': None, 'layout': None}, 'compiled_circuit': { 'header': None, 'operations': [ {'name': 'u1', 'params': [0.4], 'qubits': [1]}, {'name': 'u2', 'params': [0.4, 0.2], 'qubits': [1]}] }, 'compiled_circuit_qasm': 'compiled_qasm' } ]} self.assertEqual(qobj.as_dict(), expected)
def new_fake_qobj(): """Create fake `Qobj` and backend instances.""" backend = FakeBackend() return Qobj( qobj_id='test-id', config=QobjConfig(shots=1024, memory_slots=1, max_credits=100), header=QobjHeader(backend_name=backend.name()), experiments=[ QobjExperiment( instructions=[QobjInstruction(name='barrier', qubits=[1])], header=QobjExperimentHeader(compiled_circuit_qasm='fake-code'), config=QobjItem(seed=123456)) ])
def snapshot_instr(snapshot_type, label, qubits=None, params=None): """Create a snapshot qobj item. Args: snapshot_type (str): the snapshot type identifier label (str): the snapshot label string qubits (list[int]): qubits snapshot applies to (optional) params (custom): optional parameters for special snapshot types. See additional information. Returns: QobjInstruction: The qobj item for the snapshot instruction. Additional Information: Snapshot types: "statevector" -- returns the current statevector for each shot "memory" -- returns the current memory hex-string for each shot "register" -- returns the current register hex-string for each shot "probabilities" -- returns the measurement outcome probabilities averaged over all shots, but conditioned on the current memory value. This requires the qubits field to be set. "expval_pauli" -- returns the expectation value of an operator averaged over all shots, but conditioned on the current memory value. This requires the qubits field to be set and the params field to be set. "expval_matrix" -- same as expval_pauli but with different params Pauli expectation value params: These are a list of terms [complex_coeff, pauli_str] where string is in little endian: pauli_str CBA applies Pauli A to qubits[0], B to qubits[1] and C to qubits[2]. Example for op 0.5 XX + 0.7 IZ we have [[0.5, 'XX'], [0.7, 'IZ']] Matrix expectation value params: TODO """ snap = {"name": "snapshot", "type": snapshot_type, "label": str(label)} if qubits is not None: snap["qubits"] = list(qubits) if params is not None: snap["params"] = params # Check if single-matrix expectation value if snapshot_type in ["expval", "expval_matrix"] and \ isinstance(params, np.ndarray): snap["name"] = "expval_matrix" snap["params"] = [[1.0, qubits, params]] # TODO: implicit conversion for Pauli expval params return QobjInstruction(**snap)
def new_fake_qobj(): """Create fake `Qobj` and backend instances.""" backend = FakeQasmSimulator() return Qobj(qobj_id='test-id', config=QobjConfig(shots=1024, memory_slots=1, max_credits=100), header=QobjHeader(backend_name=backend.name()), experiments=[ QobjExperiment(instructions=[ QobjInstruction(name='barrier', qubits=[1]) ], header=QobjExperimentHeader(), config=QobjExperimentConfig(seed=123456)) ], type=QobjType.QASM.value)
def unitary_instr(mat, qubits, label=None): """Create a unitary gate QobjInstruction. Args: mat (matrix_like): an n-qubit unitary matrix qubits (list[int]): qubits to apply the matrix to. label (str): optional string label for the untiary matrix Returns: QobjInstruction: The qobj item for the unitary instruction. Raises: ValueError: if the input matrix is not unitary Additional Information: Qubit Ordering: The n-qubit matrix is ordered in little-endian with respect to the qubits in the label string. For example. If M is a tensor product of single qubit matrices `M = kron(M_(n-1), ..., M_1, M_0)` then `M_0` is applied to `qubits[0]`, `M_1` to `qubits[1]` etc. Label string: The string label is used for identifying the matrix in a noise model so that noise may be applied to the implementation of this matrix. """ array = np.array(mat, dtype=complex) dim = 2 ** len(qubits) if array.shape not in [(dim, dim), (1, dim)]: raise ValueError("Invalid") instruction = {"name": "unitary", "qubits": list(qubits), "params": np.array(mat, dtype=complex)} if label is not None: instruction["label"] = str(label) return QobjInstruction(**instruction)
def reset_instr(qubits): """Create a multi-qubit reset instruction""" return QobjInstruction(name='reset', qubits=qubits)
def barrier_instr(num_qubits): """Create a barrier QobjInstruction.""" return QobjInstruction(name='barrier', qubits=list(range(num_qubits)))
def circuits_to_qobj(circuits, user_qobj_header=None, run_config=None, qobj_id=None, backend_name=None, config=None, shots=None, max_credits=None, basis_gates=None, coupling_map=None, seed=None, memory=None): """Convert a list of circuits into a qobj. Args: circuits (list[QuantumCircuits] or QuantumCircuit): circuits to compile user_qobj_header (QobjHeader): header to pass to the results run_config (RunConfig): RunConfig object qobj_id (int): identifier for the generated qobj backend_name (str): TODO: delete after qiskit-terra 0.8 config (dict): TODO: delete after qiskit-terra 0.8 shots (int): TODO: delete after qiskit-terra 0.8 max_credits (int): TODO: delete after qiskit-terra 0.8 basis_gates (str): TODO: delete after qiskit-terra 0.8 coupling_map (list): TODO: delete after qiskit-terra 0.8 seed (int): TODO: delete after qiskit-terra 0.8 memory (bool): TODO: delete after qiskit-terra 0.8 Returns: Qobj: the Qobj to be run on the backends """ user_qobj_header = user_qobj_header or QobjHeader() run_config = run_config or RunConfig() if isinstance(circuits, QuantumCircuit): circuits = [circuits] if backend_name: warnings.warn('backend_name is not required anymore', DeprecationWarning) user_qobj_header.backend_name = backend_name if config: warnings.warn( 'config is not used anymore. Set all configs in ' 'run_config.', DeprecationWarning) if shots: warnings.warn('shots is not used anymore. Set it via run_config.', DeprecationWarning) run_config.shots = shots if basis_gates: warnings.warn('basis_gates was unused and will be removed.', DeprecationWarning) if coupling_map: warnings.warn('coupling_map was unused and will be removed.', DeprecationWarning) if seed: warnings.warn('seed is not used anymore. Set it via run_config', DeprecationWarning) run_config.seed = seed if memory: warnings.warn('memory is not used anymore. Set it via run_config', DeprecationWarning) run_config.memory = memory if max_credits: warnings.warn('max_credits is not used anymore. Set it via run_config', DeprecationWarning) run_config.max_credits = max_credits userconfig = QobjConfig(**run_config.to_dict()) experiments = [] max_n_qubits = 0 max_memory_slots = 0 for circuit in circuits: # header stuff n_qubits = 0 memory_slots = 0 qubit_labels = [] clbit_labels = [] qreg_sizes = [] creg_sizes = [] for qreg in circuit.qregs: qreg_sizes.append([qreg.name, qreg.size]) for j in range(qreg.size): qubit_labels.append([qreg.name, j]) n_qubits += qreg.size for creg in circuit.cregs: creg_sizes.append([creg.name, creg.size]) for j in range(creg.size): clbit_labels.append([creg.name, j]) memory_slots += creg.size # TODO: why do we need creq_sizes and qreg_sizes in header # TODO: we need to rethink memory_slots as they are tied to classical bit # TODO: when no more backends use the compiled_circuit_qasm lets delete it form header experimentheader = QobjExperimentHeader( qubit_labels=qubit_labels, n_qubits=n_qubits, qreg_sizes=qreg_sizes, clbit_labels=clbit_labels, memory_slots=memory_slots, creg_sizes=creg_sizes, name=circuit.name, compiled_circuit_qasm=circuit.qasm()) # TODO: why do we need n_qubits and memory_slots in both the header and the config experimentconfig = QobjExperimentConfig(n_qubits=n_qubits, memory_slots=memory_slots) instructions = [] for opt in circuit.data: current_instruction = QobjInstruction(name=opt.name) if opt.qargs: qubit_indices = [ qubit_labels.index([qubit[0].name, qubit[1]]) for qubit in opt.qargs ] current_instruction.qubits = qubit_indices if opt.cargs: clbit_indices = [ clbit_labels.index([clbit[0].name, clbit[1]]) for clbit in opt.cargs ] current_instruction.memory = clbit_indices if opt.params: params = list(map(lambda x: x.evalf(), opt.params)) current_instruction.params = params # TODO: I really dont like this for snapshot. I also think we should change # type to snap_type if opt.name == "snapshot": current_instruction.label = str(opt.params[0]) current_instruction.type = str(opt.params[1]) if opt.control: mask = 0 for clbit in clbit_labels: if clbit[0] == opt.control[0].name: mask |= (1 << clbit_labels.index(clbit)) current_instruction.conditional = QobjConditional( mask="0x%X" % mask, type='equals', val="0x%X" % opt.control[1]) instructions.append(current_instruction) experiments.append( QobjExperiment(instructions=instructions, header=experimentheader, config=experimentconfig)) if n_qubits > max_n_qubits: max_n_qubits = n_qubits if memory_slots > max_memory_slots: max_memory_slots = memory_slots userconfig.memory_slots = max_memory_slots userconfig.n_qubits = max_n_qubits return Qobj(qobj_id=qobj_id or str(uuid.uuid4()), config=userconfig, experiments=experiments, header=user_qobj_header)
def iden_instr(qubit): """Create a barrier QobjInstruction.""" return QobjInstruction(name='id', qubits=[qubit])
def assemble_circuits(circuits, run_config=None, qobj_header=None, qobj_id=None): """Assembles a list of circuits into a qobj which can be run on the backend. Args: circuits (list[QuantumCircuits] or QuantumCircuit): circuits to assemble run_config (RunConfig): RunConfig object qobj_header (QobjHeader): header to pass to the results qobj_id (int): identifier for the generated qobj Returns: Qobj: the Qobj to be run on the backends """ qobj_header = qobj_header or QobjHeader() run_config = run_config or RunConfig() if isinstance(circuits, QuantumCircuit): circuits = [circuits] userconfig = QobjConfig(**run_config.to_dict()) experiments = [] max_n_qubits = 0 max_memory_slots = 0 for circuit in circuits: # header stuff n_qubits = 0 memory_slots = 0 qubit_labels = [] clbit_labels = [] qreg_sizes = [] creg_sizes = [] for qreg in circuit.qregs: qreg_sizes.append([qreg.name, qreg.size]) for j in range(qreg.size): qubit_labels.append([qreg.name, j]) n_qubits += qreg.size for creg in circuit.cregs: creg_sizes.append([creg.name, creg.size]) for j in range(creg.size): clbit_labels.append([creg.name, j]) memory_slots += creg.size # TODO: why do we need creq_sizes and qreg_sizes in header # TODO: we need to rethink memory_slots as they are tied to classical bit experimentheader = QobjExperimentHeader(qubit_labels=qubit_labels, n_qubits=n_qubits, qreg_sizes=qreg_sizes, clbit_labels=clbit_labels, memory_slots=memory_slots, creg_sizes=creg_sizes, name=circuit.name) # TODO: why do we need n_qubits and memory_slots in both the header and the config experimentconfig = QobjExperimentConfig(n_qubits=n_qubits, memory_slots=memory_slots) instructions = [] for opt in circuit.data: current_instruction = QobjInstruction(name=opt.name) if opt.qargs: qubit_indices = [ qubit_labels.index([qubit[0].name, qubit[1]]) for qubit in opt.qargs ] current_instruction.qubits = qubit_indices if opt.cargs: clbit_indices = [ clbit_labels.index([clbit[0].name, clbit[1]]) for clbit in opt.cargs ] current_instruction.memory = clbit_indices if opt.params: params = list(map(lambda x: x.evalf(), opt.params)) params = [ sympy.matrix2numpy(x, dtype=complex) if isinstance( x, sympy.Matrix) else x for x in params ] if len(params) == 1 and isinstance(params[0], numpy.ndarray): # TODO: Aer expects list of rows for unitary instruction params; # change to matrix in Aer. params = params[0] current_instruction.params = params # TODO (jay): I really dont like this for snapshot. I also think we should change # type to snap_type if opt.name == "snapshot": current_instruction.label = str(opt.params[0]) current_instruction.type = str(opt.params[1]) if opt.control: mask = 0 for clbit in clbit_labels: if clbit[0] == opt.control[0].name: mask |= (1 << clbit_labels.index(clbit)) current_instruction.conditional = QobjConditional( mask="0x%X" % mask, type='equals', val="0x%X" % opt.control[1]) instructions.append(current_instruction) experiments.append( QobjExperiment(instructions=instructions, header=experimentheader, config=experimentconfig)) if n_qubits > max_n_qubits: max_n_qubits = n_qubits if memory_slots > max_memory_slots: max_memory_slots = memory_slots userconfig.memory_slots = max_memory_slots userconfig.n_qubits = max_n_qubits return Qobj(qobj_id=qobj_id or str(uuid.uuid4()), config=userconfig, experiments=experiments, header=qobj_header, type=QobjType.QASM.value)