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 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 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 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 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 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