def setUp(self): qasm_filename = self._get_resource_path('qasm/example.qasm') qasm_ast = Qasm(filename=qasm_filename).parse() qasm_dag = Unroller(qasm_ast, DAGBackend()).execute() qasm_json = DagUnroller(qasm_dag, JsonBackend(qasm_dag.basis)).execute() qr = QuantumRegister(2, 'q') cr = ClassicalRegister(2, 'c') qc = QuantumCircuit(qr, cr) qc.h(qr[0]) qc.measure(qr[0], cr[0]) qc_dag = DAGCircuit.fromQuantumCircuit(qc) qc_json = DagUnroller(qc_dag, JsonBackend(qc_dag.basis)).execute() # create qobj compiled_circuit1 = QobjExperiment.from_dict(qc_json) compiled_circuit2 = QobjExperiment.from_dict(qasm_json) self.qobj = Qobj(qobj_id='test_qobj', config=QobjConfig(shots=2000, memory_slots=1, max_credits=3, seed=1111), experiments=[compiled_circuit1, compiled_circuit2], header=QobjHeader(backend_name='qasm_simulator')) self.qobj.experiments[0].header.name = 'test_circuit1' self.qobj.experiments[1].header.name = 'test_circuit2' self.backend = QasmSimulator()
def setUp(self): self.seed = 88 self.qasm_filename = self._get_resource_path('qasm/example.qasm') self.qasm_circ = QuantumCircuit.from_qasm_file(self.qasm_filename) qr = QuantumRegister(2, 'q') cr = ClassicalRegister(2, 'c') qc = QuantumCircuit(qr, cr) qc.h(qr[0]) qc.measure(qr[0], cr[0]) self.qc = qc # create qobj dag = DAGCircuit.fromQuantumCircuit(self.qc) json_circuit = DagUnroller(dag, JsonBackend(dag.basis)).execute() compiled_circuit1 = QobjExperiment.from_dict(json_circuit) dag = DAGCircuit.fromQuantumCircuit(self.qasm_circ) json_circuit = DagUnroller(dag, JsonBackend(dag.basis)).execute() compiled_circuit2 = QobjExperiment.from_dict(json_circuit) self.qobj = Qobj(qobj_id='test_qobj', config=QobjConfig(shots=2000, memory_slots=1, max_credits=3, seed=1111), experiments=[compiled_circuit1, compiled_circuit2], header=QobjHeader(backend_name='qasm_simulator')) self.qobj.experiments[0].header.name = 'test_circuit1' self.qobj.experiments[0].config = QobjItem( basis_gates='u1,u2,u3,cx,id') self.qobj.experiments[1].header.name = 'test_circuit2' self.qobj.experiments[1].config = QobjItem( basis_gates='u1,u2,u3,cx,id') self.backend = QasmSimulator()
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 run_histogram_test(self, single_experiment, mock_result1, mock_result2, expected_histogram, expected_histogram_prob, expected_memory): self.mock_api.set(mock_result1, mock_result2) jobs = self._basic_job_dictionary measurements = QuantumInspireBackend._collect_measurements( QobjExperiment.from_dict(single_experiment)) user_data = { 'name': 'name', 'memory_slots': 2, 'creg_sizes': [['c1', 2]], 'measurements': measurements } jobs['user_data'] = json.dumps(user_data) self.mock_api.get_jobs_from_project.return_value = [jobs] job = QIJob('backend', '42', self.mock_api) result = self.simulator.get_experiment_results(job) number_of_shots = jobs['number_of_shots'] self.assertEqual(1, len(result)) first_experiment = first_item(result) actual = first_experiment.data.counts.to_dict() self.assertDictEqual(expected_histogram, actual) probabilities = first_experiment.data.probabilities.to_dict() self.assertTrue( len(expected_histogram_prob.keys() - probabilities.keys()) == 0) for key in set(probabilities.keys()) & set( expected_histogram_prob.keys()): self.assertTrue( np.isclose(expected_histogram_prob[key], probabilities[key])) self.assertTrue(len(first_experiment.data.memory) == number_of_shots) self.assertListEqual(expected_memory, first_experiment.data.memory)
def test_unitary_simulator(self): """test generation of circuit unitary""" unroller = unroll.Unroller( qasm.Qasm(filename=self.qasm_filename).parse(), unroll.JsonBackend([])) circuit = unroller.execute() # strip measurements from circuit to avoid warnings circuit['instructions'] = [ op for op in circuit['instructions'] if op['name'] != 'measure' ] circuit = QobjExperiment.from_dict(circuit) circuit.config = QobjItem(coupling_map=None, basis_gates=None, layout=None, seed=self.seed) circuit.header.name = 'test' qobj = Qobj( id='unitary', config=QobjConfig(shots=1, register_slots=6, max_credits=None), experiments=[circuit], header=QobjHeader(backend_name='local_unitary_simulator_py')) # numpy.savetxt currently prints complex numbers in a way # loadtxt can't read. To save file do, # fmtstr=['% .4g%+.4gj' for i in range(numCols)] # np.savetxt('example_unitary_matrix.dat', numpyMatrix, fmt=fmtstr, # delimiter=',') expected = np.loadtxt( self._get_resource_path('example_unitary_matrix.dat'), dtype='complex', delimiter=',') result = UnitarySimulatorPy().run(qobj).result() self.assertTrue( np.allclose(result.get_unitary('test'), expected, rtol=1e-3))
def _dags_2_qobj_parallel(dag, config=None, basis_gates=None, coupling_map=None): """Helper function for dags to qobj in parallel (if available). Args: dag (DAGCircuit): DAG to compile config (dict): dictionary of parameters (e.g. noise) used by runner basis_gates (list[str])): basis gates for the experiment coupling_map (list): coupling map (perhaps custom) to target in mapping Returns: Qobj: Qobj to be run on the backends """ json_circuit = DagUnroller(dag, JsonBackend(dag.basis)).execute() # Step 3a: create the Experiment based on json_circuit experiment = QobjExperiment.from_dict(json_circuit) # Step 3b: populate the Experiment configuration and header experiment.header.name = dag.name # TODO: place in header or config? experiment_config = deepcopy(config or {}) experiment_config.update({ 'coupling_map': coupling_map, 'basis_gates': basis_gates, 'layout': dag.layout, 'memory_slots': sum(dag.cregs.values()), # TODO: `n_qubits` is not part of the qobj spec, but needed for the simulator. 'n_qubits': sum(dag.qregs.values())}) experiment.config = QobjItem(**experiment_config) # set eval_symbols=True to evaluate each symbolic expression # TODO: after transition to qobj, we can drop this experiment.header.compiled_circuit_qasm = dag.qasm( qeflag=True, eval_symbols=True) # Step 3c: add the Experiment to the Qobj return experiment
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.seed = 88 self.qasm_filename = self._get_resource_path('qasm/example.qasm') with open(self.qasm_filename, 'r') as qasm_file: self.qasm_text = qasm_file.read() self.qasm_ast = qiskit.qasm.Qasm(data=self.qasm_text).parse() self.qasm_be = qiskit.unroll.CircuitBackend(['u1', 'u2', 'u3', 'id', 'cx']) self.qasm_circ = qiskit.unroll.Unroller(self.qasm_ast, self.qasm_be).execute() qr = QuantumRegister(2, 'q') cr = ClassicalRegister(2, 'c') qc = QuantumCircuit(qr, cr) qc.h(qr[0]) qc.measure(qr[0], cr[0]) self.qc = qc # create qobj compiled_circuit1 = QobjExperiment.from_dict( transpile(DAGCircuit.fromQuantumCircuit(self.qc), format='json')) compiled_circuit2 = QobjExperiment.from_dict( transpile(DAGCircuit.fromQuantumCircuit(self.qasm_circ), format='json')) self.qobj = Qobj( qobj_id='test_qobj', config=QobjConfig( shots=2000, memory_slots=1, max_credits=3, seed=1111 ), experiments=[compiled_circuit1, compiled_circuit2], header=QobjHeader(backend_name='local_qasm_simulator_cpp') ) self.qobj.experiments[0].header.name = 'test_circuit1' self.qobj.experiments[0].config = QobjItem(basis_gates='u1,u2,u3,cx,id') self.qobj.experiments[1].header.name = 'test_circuit2' self.qobj.experiments[1].config = QobjItem(basis_gates='u1,u2,u3,cx,id') # Simulator backend try: self.backend = QasmSimulatorCpp() except FileNotFoundError as fnferr: raise unittest.SkipTest( 'cannot find {} in path'.format(fnferr))
def new_fake_qobj(): """Create fake `Qobj` and backend instances.""" backend = FakeBackend() return Qobj(id='test-id', config=QobjConfig(shots=1024, memory_slots=1, max_credits=100), header=QobjHeader(backend_name=backend.name), experiments=[ QobjExperiment(instructions=[], header=QobjExperimentHeader( compiled_circuit_qasm='fake-code'), config=QobjItem(seed=123456)) ])
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=QobjItem(seed=123456)) ])
def setUp(self): self.qp = None self.seed = 88 qasm_filename = self._get_resource_path('qasm/example.qasm') unroller = unroll.Unroller( qasm.Qasm(filename=qasm_filename).parse(), unroll.JsonBackend([])) circuit = QobjExperiment.from_dict(unroller.execute()) circuit.config = QobjItem(coupling_map=None, basis_gates='u1,u2,u3,cx,id', layout=None, seed=self.seed) circuit.header.name = 'test' self.qobj = Qobj( id='test_sim_single_shot', config=QobjConfig(shots=1024, memory_slots=6, max_credits=3), experiments=[circuit], header=QobjHeader(backend_name='local_qasm_simulator_py'))
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 setUp(self): self.seed = 88 self.backend = QasmSimulatorPy() backend_basis = self.backend.configuration().basis_gates qasm_filename = self._get_resource_path('qasm/example.qasm') qasm_ast = Qasm(filename=qasm_filename).parse() qasm_dag = Unroller(qasm_ast, DAGBackend()).execute() qasm_dag = DagUnroller(qasm_dag, DAGBackend(backend_basis)).expand_gates() qasm_json = DagUnroller(qasm_dag, JsonBackend(qasm_dag.basis)).execute() compiled_circuit = QobjExperiment.from_dict(qasm_json) compiled_circuit.header.name = 'test' self.qobj = Qobj( qobj_id='test_sim_single_shot', config=QobjConfig( shots=1024, memory_slots=6, max_credits=3, seed=self.seed ), experiments=[compiled_circuit], header=QobjHeader(backend_name='qasm_simulator_py') )
def _circuit_to_experiment(circuit, config=None, basis_gates=None, coupling_map=None): """Helper function for dags to qobj in parallel (if available). Args: circuit (QuantumCircuit): QuantumCircuit to convert into qobj experiment config (dict): dictionary of parameters (e.g. noise) used by runner basis_gates (list[str])): basis gates for the experiment coupling_map (list): coupling map (perhaps custom) to target in mapping Returns: Qobj: Qobj to be run on the backends """ # pylint: disable=unused-argument # TODO: if arguments are really unused, consider changing the signature # TODO: removed the DAG from this function from qiskit.converters import circuit_to_dag from qiskit.unroll import DagUnroller, JsonBackend dag = circuit_to_dag(circuit) json_circuit = DagUnroller(dag, JsonBackend(dag.basis)).execute() # Step 3a: create the Experiment based on json_circuit experiment = QobjExperiment.from_dict(json_circuit) # Step 3b: populate the Experiment configuration and header experiment.header.name = circuit.name experiment_config = deepcopy(config or {}) experiment_config.update({ 'memory_slots': sum([creg.size for creg in dag.cregs.values()]), 'n_qubits': sum([qreg.size for qreg in dag.qregs.values()]) }) experiment.config = QobjItem(**experiment_config) # set eval_symbols=True to evaluate each symbolic expression # TODO: after transition to qobj, we can drop this experiment.header.compiled_circuit_qasm = circuit.qasm() # Step 3c: add the Experiment to the Qobj return experiment
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 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)
def compile(circuits, backend, config=None, basis_gates=None, coupling_map=None, initial_layout=None, shots=1024, max_credits=10, seed=None, qobj_id=None, hpc=None, pass_manager=None): """Compile a list of circuits into a qobj. Args: circuits (QuantumCircuit or list[QuantumCircuit]): circuits to compile backend (BaseBackend): a backend to compile for config (dict): dictionary of parameters (e.g. noise) used by runner basis_gates (str): comma-separated basis gate set to compile to coupling_map (list): coupling map (perhaps custom) to target in mapping initial_layout (list): initial layout of qubits in mapping shots (int): number of repetitions of each circuit, for sampling max_credits (int): maximum credits to use seed (int): random seed for simulators qobj_id (int): identifier for the generated qobj hpc (dict): HPC simulator parameters pass_manager (PassManager): a pass_manager for the transpiler stage Returns: Qobj: the Qobj to be run on the backends Raises: TranspilerError: in case of bad compile options, e.g. the hpc options. """ if isinstance(circuits, QuantumCircuit): circuits = [circuits] backend_conf = backend.configuration backend_name = backend_conf['name'] # Step 1: create the Qobj, with empty experiments. # Copy the configuration: the values in `config` have prefern qobj_config = deepcopy(config or {}) # TODO: "register_slots" is required by the qobj schema in the top-level # qobj.config. In this implementation, is overridden by the individual # experiment.config entries (hence the 0 should never be used). qobj_config.update({ 'shots': shots, 'max_credits': max_credits, 'register_slots': 0 }) qobj = Qobj(id=qobj_id or str(uuid.uuid4()), config=QobjConfig(**qobj_config), experiments=[], header=QobjHeader(backend_name=backend_name)) if seed: qobj.config.seed = seed # Check for valid parameters for the experiments. if hpc is not None and \ not all(key in hpc for key in ('multi_shot_optimization', 'omp_num_threads')): raise TranspilerError('Unknown HPC parameter format!') basis_gates = basis_gates or backend_conf['basis_gates'] coupling_map = coupling_map or backend_conf['coupling_map'] # Step 2 and 3: transpile and populate the circuits for circuit in circuits: # TODO: A better solution is to have options to enable/disable optimizations num_qubits = sum((len(qreg) for qreg in circuit.get_qregs().values())) if num_qubits == 1 or coupling_map == "all-to-all": coupling_map = None # Step 2a: circuit -> dag dag_circuit = DAGCircuit.fromQuantumCircuit(circuit) # TODO: move this inside the mapper pass # pick a good initial layout if coupling_map is not already satisfied # otherwise keep it as q[i]->q[i] if (initial_layout is None and not backend_conf['simulator'] and not _matches_coupling_map(circuit.data, coupling_map)): initial_layout = _pick_best_layout(backend, num_qubits, circuit.get_qregs()) # Step 2b: transpile (dag -> dag) dag_circuit, final_layout = transpile(dag_circuit, basis_gates=basis_gates, coupling_map=coupling_map, initial_layout=initial_layout, get_layout=True, seed=seed, pass_manager=pass_manager) # Step 2c: dag -> json # the compiled circuit to be run saved as a dag # we assume that transpile() has already expanded gates # to the target basis, so we just need to generate json list_layout = [[k, v] for k, v in final_layout.items() ] if final_layout else None json_circuit = DagUnroller(dag_circuit, JsonBackend(dag_circuit.basis)).execute() # Step 3a: create the Experiment based on json_circuit experiment = QobjExperiment.from_dict(json_circuit) # Step 3b: populate the Experiment configuration and header experiment.header.name = circuit.name # TODO: place in header or config? experiment_config = deepcopy(config or {}) experiment_config.update({ 'coupling_map': coupling_map, 'basis_gates': basis_gates, 'layout': list_layout, 'register_slots': sum(register.size for register in circuit.get_cregs().values()) }) experiment.config = QobjItem(**experiment_config) # set eval_symbols=True to evaluate each symbolic expression # TODO after transition to qobj, we can drop this experiment.header.compiled_circuit_qasm = dag_circuit.qasm( qeflag=True, eval_symbols=True) # Step 3c: add the Experiment to the Qobj qobj.experiments.append(experiment) return qobj
def _dags_2_qobj(dags, backend_name, config=None, shots=None, max_credits=None, qobj_id=None, basis_gates=None, coupling_map=None, seed=None): """Convert a list of dags into a qobj. Args: dags (list[DAGCircuit]): dags to compile backend_name (str): name of runner backend config (dict): dictionary of parameters (e.g. noise) used by runner shots (int): number of repetitions of each circuit, for sampling max_credits (int): maximum credits to use qobj_id (int): identifier for the generated qobj basis_gates (list[str])): basis gates for the experiment coupling_map (list): coupling map (perhaps custom) to target in mapping seed (int): random seed for simulators Returns: Qobj: the Qobj to be run on the backends """ # TODO: the following will be removed from qobj and thus removed here: # `basis_gates`, `coupling_map` # Step 1: create the Qobj, with empty experiments. # Copy the configuration: the values in `config` have preference qobj_config = deepcopy(config or {}) # TODO: "memory_slots" is required by the qobj schema in the top-level # qobj.config, and is user-defined. At the moment is set to the maximum # number of *register* slots for the circuits, in order to have `measure` # behave properly until the transition is over; and each circuit stores # its memory_slots in its configuration. qobj_config.update({ 'shots': shots, 'max_credits': max_credits, 'memory_slots': 0 }) qobj = Qobj(qobj_id=qobj_id or str(uuid.uuid4()), config=QobjConfig(**qobj_config), experiments=[], header=QobjHeader(backend_name=backend_name)) if seed: qobj.config.seed = seed for dag in dags: json_circuit = DagUnroller(dag, JsonBackend(dag.basis)).execute() # Step 3a: create the Experiment based on json_circuit experiment = QobjExperiment.from_dict(json_circuit) # Step 3b: populate the Experiment configuration and header experiment.header.name = dag.name # TODO: place in header or config? experiment_config = deepcopy(config or {}) experiment_config.update({ 'coupling_map': coupling_map, 'basis_gates': basis_gates, 'layout': dag.layout, 'memory_slots': sum(dag.cregs.values()), # TODO: `n_qubits` is not part of the qobj spec, but needed for the simulator. 'n_qubits': sum(dag.qregs.values()) }) experiment.config = QobjItem(**experiment_config) # set eval_symbols=True to evaluate each symbolic expression # TODO: after transition to qobj, we can drop this experiment.header.compiled_circuit_qasm = dag.qasm(qeflag=True, eval_symbols=True) # Step 3c: add the Experiment to the Qobj qobj.experiments.append(experiment) # Update the `memory_slots` value. # TODO: remove when `memory_slots` can be provided by the user. qobj.config.memory_slots = max(experiment.config.memory_slots for experiment in qobj.experiments) # Update the `n_qubits` global value. # TODO: num_qubits is not part of the qobj specification, but needed # for the simulator. qobj.config.n_qubits = max(experiment.config.n_qubits for experiment in qobj.experiments) return qobj
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 _compile_single_circuit(circuit, backend, config=None, basis_gates=None, coupling_map=None, initial_layout=None, seed=None, pass_manager=None): """Compile a single circuit into a QobjExperiment. Args: circuit (QuantumCircuit): circuit to compile backend (BaseBackend): a backend to compile for config (dict): dictionary of parameters (e.g. noise) used by runner basis_gates (str): comma-separated basis gate set to compile to coupling_map (list): coupling map (perhaps custom) to target in mapping initial_layout (list): initial layout of qubits in mapping seed (int): random seed for simulators pass_manager (PassManager): a pass_manager for the transpiler stage Returns: QobjExperiment: the QobjExperiment to be run on the backends """ # TODO: A better solution is to have options to enable/disable optimizations num_qubits = sum((len(qreg) for qreg in circuit.get_qregs().values())) if num_qubits == 1 or coupling_map == "all-to-all": coupling_map = None # Step 2a: circuit -> dag dag_circuit = DAGCircuit.fromQuantumCircuit(circuit) # TODO: move this inside the mapper pass # pick a good initial layout if coupling_map is not already satisfied # otherwise keep it as q[i]->q[i] if (initial_layout is None and not backend.configuration['simulator'] and not _matches_coupling_map(circuit.data, coupling_map)): initial_layout = _pick_best_layout(backend, num_qubits, circuit.get_qregs()) # Step 2b: transpile (dag -> dag) dag_circuit, final_layout = transpile(dag_circuit, basis_gates=basis_gates, coupling_map=coupling_map, initial_layout=initial_layout, get_layout=True, seed=seed, pass_manager=pass_manager) # Step 2c: dag -> json # the compiled circuit to be run saved as a dag # we assume that transpile() has already expanded gates # to the target basis, so we just need to generate json list_layout = [[k, v] for k, v in final_layout.items()] if final_layout else None json_circuit = DagUnroller(dag_circuit, JsonBackend(dag_circuit.basis)).execute() # Step 3a: create the Experiment based on json_circuit experiment = QobjExperiment.from_dict(json_circuit) # Step 3b: populate the Experiment configuration and header experiment.header.name = circuit.name # TODO: place in header or config? experiment_config = deepcopy(config or {}) experiment_config.update({ 'coupling_map': coupling_map, 'basis_gates': basis_gates, 'layout': list_layout, 'memory_slots': sum(register.size for register in circuit.get_cregs().values()) }) experiment.config = QobjItem(**experiment_config) # set eval_symbols=True to evaluate each symbolic expression # TODO after transition to qobj, we can drop this experiment.header.compiled_circuit_qasm = dag_circuit.qasm( qeflag=True, eval_symbols=True) return experiment
def test_if_statement(self): self.log.info('test_if_statement_x') shots = 100 max_qubits = 3 qr = QuantumRegister(max_qubits, 'qr') cr = ClassicalRegister(max_qubits, 'cr') circuit_if_true = QuantumCircuit(qr, cr, name='test_if_true') circuit_if_true.x(qr[0]) circuit_if_true.x(qr[1]) circuit_if_true.measure(qr[0], cr[0]) circuit_if_true.measure(qr[1], cr[1]) circuit_if_true.x(qr[2]).c_if(cr, 0x3) circuit_if_true.measure(qr[0], cr[0]) circuit_if_true.measure(qr[1], cr[1]) circuit_if_true.measure(qr[2], cr[2]) circuit_if_false = QuantumCircuit(qr, cr, name='test_if_false') circuit_if_false.x(qr[0]) circuit_if_false.measure(qr[0], cr[0]) circuit_if_false.measure(qr[1], cr[1]) circuit_if_false.x(qr[2]).c_if(cr, 0x3) circuit_if_false.measure(qr[0], cr[0]) circuit_if_false.measure(qr[1], cr[1]) circuit_if_false.measure(qr[2], cr[2]) basis_gates = [] # unroll to base gates unroller = unroll.Unroller( qasm.Qasm(data=circuit_if_true.qasm()).parse(), unroll.JsonBackend(basis_gates)) ucircuit_true = QobjExperiment.from_dict(unroller.execute()) unroller = unroll.Unroller( qasm.Qasm(data=circuit_if_false.qasm()).parse(), unroll.JsonBackend(basis_gates)) ucircuit_false = QobjExperiment.from_dict(unroller.execute()) # Customize the experiments and create the qobj. ucircuit_true.config = QobjItem(coupling_map=None, basis_gates='u1,u2,u3,cx,id', layout=None, seed=None) ucircuit_true.header.name = 'test_if_true' ucircuit_false.config = QobjItem(coupling_map=None, basis_gates='u1,u2,u3,cx,id', layout=None, seed=None) ucircuit_false.header.name = 'test_if_false' qobj = Qobj(id='test_if_qobj', config=QobjConfig(max_credits=3, shots=shots, memory_slots=max_qubits), experiments=[ucircuit_true, ucircuit_false], header=QobjHeader(backend_name='local_qasm_simulator_py')) result = QasmSimulatorPy().run(qobj).result() result_if_true = result.get_data('test_if_true') self.log.info('result_if_true circuit:') self.log.info(circuit_if_true.qasm()) self.log.info('result_if_true=%s', result_if_true) result_if_false = result.get_data('test_if_false') self.log.info('result_if_false circuit:') self.log.info(circuit_if_false.qasm()) self.log.info('result_if_false=%s', result_if_false) self.assertTrue(result_if_true['counts']['111'] == 100) self.assertTrue(result_if_false['counts']['001'] == 100)
def compile(circuits, backend, config=None, basis_gates=None, coupling_map=None, initial_layout=None, shots=1024, max_credits=10, seed=None, qobj_id=None, hpc=None, pass_manager=None): """Compile a list of circuits into a qobj. Args: circuits (QuantumCircuit or list[QuantumCircuit]): circuits to compile backend (BaseBackend): a backend to compile for config (dict): dictionary of parameters (e.g. noise) used by runner basis_gates (str): comma-separated basis gate set to compile to coupling_map (list): coupling map (perhaps custom) to target in mapping initial_layout (list): initial layout of qubits in mapping shots (int): number of repetitions of each circuit, for sampling max_credits (int): maximum credits to use seed (int): random seed for simulators qobj_id (int): identifier for the generated qobj hpc (dict): HPC simulator parameters pass_manager (PassManager): a pass_manager for the transpiler stage Returns: Qobj: the Qobj to be run on the backends Raises: TranspilerError: in case of bad compile options, e.g. the hpc options. """ if isinstance(circuits, QuantumCircuit): circuits = [circuits] backend_conf = backend.configuration backend_name = backend_conf['name'] # Step 1: create the Qobj, with empty circuits qobj = Qobj(id=qobj_id or str(uuid.uuid4()), config=QobjConfig(max_credits=max_credits, shots=shots, backend_name=backend_name), circuits=[]) # Check for valid parameters for the experiments. if hpc is not None and \ not all(key in hpc for key in ('multi_shot_optimization', 'omp_num_threads')): raise TranspilerError('Unknown HPC parameter format!') basis_gates = basis_gates or backend_conf['basis_gates'] coupling_map = coupling_map or backend_conf['coupling_map'] for circuit in circuits: # Step 1: create the experiment configuration. config = config or {} circuit_config = copy.deepcopy(config) # TODO: A better solution is to have options to enable/disable optimizations num_qubits = sum((len(qreg) for qreg in circuit.get_qregs().values())) if num_qubits == 1 or coupling_map == "all-to-all": coupling_map = None circuit_config["coupling_map"] = coupling_map circuit_config["basis_gates"] = basis_gates circuit_config["seed"] = seed circuit_config["layout"] = None # set during step 3. # Step 2: create the QobjExperiment, with empty compiled circuits. experiment = QobjExperiment( name=circuit.name, config=QobjExperimentConfig(**circuit_config), compiled_circuit=None, compiled_circuit_qasm=None) # Step 3: populate the circuit `instructions` after compilation # Step 3a: circuit -> dag dag_circuit = DAGCircuit.fromQuantumCircuit(circuit) # TODO: move this inside the mapper pass # pick a good initial layout if coupling_map is not already satisfied # otherwise keep it as q[i]->q[i] if (initial_layout is None and not backend_conf['simulator'] and not _matches_coupling_map(circuit.data, coupling_map)): initial_layout = _pick_best_layout(backend, num_qubits, circuit.get_qregs()) # Step 3b: transpile (dag -> dag) dag_circuit, final_layout = transpile(dag_circuit, basis_gates=basis_gates, coupling_map=coupling_map, initial_layout=initial_layout, get_layout=True, seed=seed, pass_manager=pass_manager) # Step 3c: dag -> json # the compiled circuit to be run saved as a dag # we assume that transpile() has already expanded gates # to the target basis, so we just need to generate json list_layout = [[k, v] for k, v in final_layout.items() ] if final_layout else None experiment.config.layout = list_layout json_circuit = DagUnroller(dag_circuit, JsonBackend(dag_circuit.basis)).execute() experiment.compiled_circuit = QobjCompiledCircuit.from_dict( json_circuit) # set eval_symbols=True to evaluate each symbolic expression # TODO after transition to qobj, we can drop this experiment.compiled_circuit_qasm = dag_circuit.qasm(qeflag=True, eval_symbols=True) # add job to the qobj qobj.circuits.append(experiment) return qobj