def _target_quantum_state(self) -> Union[Statevector, DensityMatrix]: """Return the state tomography target""" # Check if circuit contains measure instructions # If so we cannot return target state circuit_ops = self._circuit.count_ops() if "measure" in circuit_ops: return None try: circuit = self._permute_circuit() if "reset" in circuit_ops or "kraus" in circuit_ops or "superop" in circuit_ops: state = DensityMatrix(circuit) else: state = Statevector(circuit) except QiskitError: # Circuit couldn't be simulated return None if self._meas_qubits is None: return state non_meas_qargs = list(range(len(self._meas_qubits), self._circuit.num_qubits)) if non_meas_qargs: # Trace over non-measured qubits state = partial_trace(state, non_meas_qargs) return state
def general_test(self, pauli, num_qubits=None, seed=None): """General test case""" pauli_qubits = list(range(len(pauli))) if num_qubits is None: num_qubits = len(pauli_qubits) # Prepare random N-qubit product input state # from seed rng = np.random.default_rng(seed) params = rng.uniform(-1, 1, size=(num_qubits, 3)) init_circ = QuantumCircuit(num_qubits) for i, par in enumerate(params): init_circ.u3(*par, i) # Compute the target expectation value rho = DensityMatrix.from_instruction(init_circ) op = Operator.from_label(pauli) target = np.trace(Operator(rho).compose(op, pauli_qubits).data) # Simulate expectation value qc = init_circ.copy() qc.snapshot_expectation_value('final', [(1, pauli)], pauli_qubits) qobj = assemble(qc) result = self.SIMULATOR.run( qobj, backend_options=self.BACKEND_OPTS).result() self.assertSuccess(result) snapshots = result.data(0).get('snapshots', {}) self.assertIn('expectation_value', snapshots) self.assertIn('final', snapshots['expectation_value']) expval = snapshots.get('expectation_value', {})['final'][0]['value'] self.assertAlmostEqual(expval, target)
def _target_quantum_state(self) -> Union[Statevector, DensityMatrix]: """Return the state tomography target""" # Check if circuit contains measure instructions # If so we cannot return target state circuit_ops = self._circuit.count_ops() if "measure" in circuit_ops: return None perm_circ = self._permute_circuit() try: if "reset" in circuit_ops or "kraus" in circuit_ops or "superop" in circuit_ops: state = DensityMatrix(perm_circ) else: state = Statevector(perm_circ) except QiskitError: # Circuit couldn't be simulated return None total_qubits = self._circuit.num_qubits if self._meas_qubits: num_meas = len(self._meas_qubits) else: num_meas = total_qubits if num_meas == total_qubits: return state # Trace out non-measurement qubits tr_qargs = range(num_meas, total_qubits) return partial_trace(state, tr_qargs)
def set_density_matrix(self, state): """Set the density matrix state of the simulator. Args: state (DensityMatrix): a density matrix. Returns: QuantumCircuit: with attached instruction. Raises: ExtensionError: If the density matrix is the incorrect size for the current circuit. .. note: This instruction is always defined across all qubits in a circuit. """ qubits = default_qubits(self) if not isinstance(state, DensityMatrix): state = DensityMatrix(state) if not state.num_qubits or state.num_qubits != len(qubits): raise ExtensionError( "The size of the density matrix for the set state" " instruction must be equal to the number of qubits" f" in the circuit (state.num_qubits ({state.num_qubits})" f" != QuantumCircuit.num_qubits ({self.num_qubits})).") return self.append(SetDensityMatrix(state), qubits)
def initialize_density_matrix(self): # Evaluate density matrix and list of states for key in self.ensemble.keys(): theta = key[0] phi = key[1] state = np.array([ np.cos(theta / 2), np.sin(theta / 2) * np.exp(phi * complex(1, 0)) ]) self.rho = self.rho + self.ensemble[key] * np.outer(state, state) # Evaluate spectrum self.rho: np.ndarray v, w = np.linalg.eig(self.rho) s0 = Statevector(w[:, 0]) s1 = Statevector(w[:, 1]) self.rho = DensityMatrix(self.rho) # Evaluate entropy and typical basis if state_fidelity(s0, self.rho) > state_fidelity(s1, self.rho): self.s0 = s0 self.s1 = s1 else: self.s0 = s1 self.s1 = s0 self.entropy = -np.real(sum([p * np.log2(p) for p in v])) self.m = int(np.ceil(self.entropy * self.n))
def _instruction_states(instructions: List[Instruction]) -> List[np.ndarray]: """Construct preparation density matrices from instructions""" states = [] num_qubits = instructions[0].num_qubits init = DensityMatrix.from_int(0, 2**num_qubits) for inst in instructions: states.append(init.evolve(inst).data) return states
def test_quantum_info_input(self): """Test passing quantum_info.Operator and Statevector as input.""" mark = Statevector.from_label('001') diffuse = 2 * DensityMatrix.from_label('000') - Operator.from_label('III') grover_op = GroverOperator(oracle=mark, zero_reflection=diffuse) self.assertGroverOperatorIsCorrect(grover_op, oracle=np.diag((-1) ** mark.data), zero_reflection=diffuse.data)
def test_qsphere_bad_dm_input(): """Tests the qsphere raises when passed impure dm""" qc = QuantumCircuit(3) qc.h(0) qc.cx(0, 1) qc.cx(1, 2) dm = DensityMatrix.from_instruction(qc) pdm = partial_trace(dm, [0, 1]) with pytest.raises(KaleidoscopeError): assert qsphere(pdm)
def _instruction_povms(instructions: List[Instruction]) -> List[Dict[int, np.ndarray]]: """Construct measurement outcome POVMs from instructions""" basis = [] for inst in instructions: inst_inv = inst.inverse() basis_dict = { i: DensityMatrix.from_int(i, 2**inst.num_qubits).evolve(inst_inv).data for i in range(2**inst.num_qubits) } basis.append(basis_dict) return basis
def __init__(self, state): """Create new instruction to set the density matrix state of the simulator. Args: state (DensityMatrix): a density matrix. Raises: ExtensionError: if the input density matrix is not valid. .. note:: This set instruction must always be performed on the full width of qubits in a circuit, otherwise an exception will be raised during simulation. """ if not isinstance(state, DensityMatrix): state = DensityMatrix(state) if not state.num_qubits or not state.is_valid(): raise ExtensionError("The input state is not valid") super().__init__('set_density_matrix', state.num_qubits, 0, [state.data])
def _run_analysis(self, experiment_data, **options): # Extract tomography measurement data outcome_data, shot_data, measurement_data, preparation_data = self._fitter_data( experiment_data.data()) # Get tomography options measurement_basis = options.pop("measurement_basis") preparation_basis = options.pop("preparation_basis", None) rescale_positive = options.pop("rescale_positive") rescale_trace = options.pop("rescale_trace") target_state = options.pop("target") # Get target state from circuit metadata if target_state == "default": metadata = experiment_data.metadata target_state = metadata.get("target", None) # Get tomography fitter function fitter = self._get_fitter(options.pop("fitter", None)) try: t_fitter_start = time.time() state, fitter_metadata = fitter( outcome_data, shot_data, measurement_data, preparation_data, measurement_basis, preparation_basis, **options, ) t_fitter_stop = time.time() if fitter_metadata is None: fitter_metadata = {} state = Choi(state) if preparation_basis else DensityMatrix(state) fitter_metadata["fitter"] = fitter.__name__ fitter_metadata["fitter_time"] = t_fitter_stop - t_fitter_start analysis_results = self._postprocess_fit( state, metadata=fitter_metadata, target_state=target_state, rescale_positive=rescale_positive, rescale_trace=rescale_trace, qpt=bool(preparation_basis), ) except AnalysisError as ex: raise AnalysisError( f"Tomography fitter failed with error: {str(ex)}") from ex return analysis_results, []
def _format_povms(povms: Sequence[any]) -> Tuple[Tuple[np.ndarray, ...], ...]: """Format sequence of basis POVMs""" formatted_povms = [] # Convert from operator/channel to POVM effects for povm in povms: if isinstance(povm, (list, tuple)): # POVM is already an effect formatted_povms.append(povm) continue # Convert POVM to operator of quantum channel try: chan = Operator(povm) except QiskitError: chan = SuperOp(povm) adjoint = chan.adjoint() dims = adjoint.input_dims() dim = np.prod(dims) effects = tuple(DensityMatrix.from_int(i, dims).evolve(adjoint) for i in range(dim)) formatted_povms.append(effects) # Format POVM effects to density matrix matrices return tuple(tuple(DensityMatrix(effect).data for effect in povm) for povm in formatted_povms)
def _process_result(self, x: np.array) -> Dict: """Transforms the optimization result to a friendly format Args: x: the optimization result vector Returns: The final GST data, as dictionary. """ E, rho, G_matrices = self._split_input_vector(x) result = {} result['E'] = Operator(self._convert_from_ptm(E)) result['rho'] = DensityMatrix(self._convert_from_ptm(rho)) for i in range(len(self.Gs)): result[self.Gs[i]] = PTM(G_matrices[i]) return result
def _target_quantum_channel(self) -> Union[Choi, Operator]: """Return the process tomography target""" # Check if circuit contains measure instructions # If so we cannot return target state circuit_ops = self._circuit.count_ops() if "measure" in circuit_ops: return None try: circuit = self._permute_circuit() if "reset" in circuit_ops or "kraus" in circuit_ops or "superop" in circuit_ops: channel = Choi(circuit) else: channel = Operator(circuit) except QiskitError: # Circuit couldn't be simulated return None total_qubits = self._circuit.num_qubits num_meas = total_qubits if self._meas_qubits is None else len(self._meas_qubits) num_prep = total_qubits if self._prep_qubits is None else len(self._prep_qubits) # If all qubits are prepared or measurement we are done if num_meas == total_qubits and num_prep == total_qubits: return channel # Convert channel to a state to project and trace out non-tomography # input and output qubits if isinstance(channel, Operator): chan_state = Statevector(np.ravel(channel, order="F")) else: chan_state = DensityMatrix(channel.data) # Get qargs for non measured and prepared subsystems non_meas_qargs = list(range(num_meas, total_qubits)) non_prep_qargs = list(range(total_qubits + num_prep, 2 * total_qubits)) # Project non-prepared subsystems on to the zero state if non_prep_qargs: proj0 = Operator([[1, 0], [0, 0]]) for qarg in non_prep_qargs: chan_state = chan_state.evolve(proj0, [qarg]) # Trace out indices to remove tr_qargs = non_meas_qargs + non_prep_qargs chan_state = partial_trace(chan_state, tr_qargs) channel = Choi(chan_state.data, input_dims=[2] * num_prep, output_dims=[2] * num_meas) return channel
def _state_result( cls, fit: np.ndarray, make_positive: bool = False, trace: Optional[float] = None, input_dims: Optional[Tuple[int, ...]] = None, output_dims: Optional[Tuple[int, ...]] = None, ) -> AnalysisResultData: """Convert fit data to state result data""" # Get eigensystem of state fit raw_eigvals, eigvecs = cls._state_eigensystem(fit) # Optionally rescale eigenvalues to be non-negative if make_positive and np.any(raw_eigvals < 0): eigvals = cls._make_positive(raw_eigvals) fit = eigvecs @ (eigvals * eigvecs).T.conj() rescaled_psd = True else: eigvals = raw_eigvals rescaled_psd = False # Optionally rescale fit trace fit_trace = np.sum(eigvals) if trace is not None and not np.isclose( fit_trace - trace, 0, atol=1e-12): scale = trace / fit_trace fit = fit * scale eigvals = eigvals * scale else: trace = fit_trace # Convert class of value if input_dims and np.prod(input_dims) > 1: value = Choi(fit, input_dims=input_dims, output_dims=output_dims) else: value = DensityMatrix(fit, dims=output_dims) # Construct state result extra metadata extra = { "trace": trace, "eigvals": eigvals, "raw_eigvals": raw_eigvals, "rescaled_psd": rescaled_psd, "eigvecs": eigvecs, } return AnalysisResultData("state", value, extra=extra)
def _run_analysis(self, experiment_data): # Extract tomography measurement data outcome_data, shot_data, measurement_data, preparation_data = self._fitter_data( experiment_data.data()) # Get tomography fitter function fitter = self._get_fitter(self.options.fitter) try: t_fitter_start = time.time() state, fitter_metadata = fitter( outcome_data, shot_data, measurement_data, preparation_data, self.options.measurement_basis, self.options.preparation_basis, **self.options.fitter_options, ) t_fitter_stop = time.time() if fitter_metadata is None: fitter_metadata = {} state = Choi( state) if self.options.preparation_basis else DensityMatrix( state) fitter_metadata["fitter"] = fitter.__name__ fitter_metadata["fitter_time"] = t_fitter_stop - t_fitter_start analysis_results = self._postprocess_fit( state, metadata=fitter_metadata, target_state=self.options.target, rescale_positive=self.options.rescale_positive, rescale_trace=self.options.rescale_trace, qpt=bool(self.options.preparation_basis), ) except AnalysisError as ex: raise AnalysisError( f"Tomography fitter failed with error: {str(ex)}") from ex return analysis_results, []
def optimize_circuit_sgd(self, qc, quantum_circuit_parameter, angle_degrees, cost_function='mse', learning_rate = 2): ''' This function is used for optimizing the values of angle_degrees, using Gradient Descent method. Parameters: ----------- qc : Quantum Circuit object quantum_circuit_parameter : parameter object angle_degrees : Angle(in degrees) by which the parameterised gates will rotate cost_function : The type of cost function to be used[default: mse] learning_rate : The learning rate for optimization[default: 2] ''' i = 0 max_i = 500 previous_step_size = 1 precision = -1 loss_function = [] vn_entropy = [] epochs = [] epoch_var = 0 while i<max_i and previous_step_size>precision: #iterating over until the error converges epoch_var+=1 epochs.append(epoch_var) theta_radians = radians(angle_degrees) #converting the degrees to radians previous_angle = angle_degrees bell_state = execute(qc, backend = Aer.get_backend('statevector_simulator'), shots = self.shots, parameter_binds=[{quantum_circuit_parameter: theta_radians}]).result().get_statevector() #counts = job.result().get_counts() psi = Statevector(bell_state) counts = psi.probabilities_dict() print(counts) D = DensityMatrix(bell_state) vn_entropy_val = entropy(D, base=2) vn_entropy.append(vn_entropy_val) #print(counts) try: prob_avg_01 = counts['00'] except: prob_avg_01 = 0 try: prob_avg_10 = counts['11'] except: prob_avg_10 = 0 if cost_function == 'mse': loss_function.append(self.mse_cost_function(prob_avg_01, prob_avg_10)) angle_degrees = angle_degrees - learning_rate*self.mse_cost_function(prob_avg_01, prob_avg_10) if cost_function == 'unsymmetrical': angle_degrees = angle_degrees - learning_rate*self.unsymmetrical_cost_function(prob_avg_01, prob_avg_10) previous_step_size = abs(angle_degrees - previous_angle) i+=1 print(angle_degrees) return angle_degrees, counts, epochs, vn_entropy, loss_function
basis_gates=noise_model.basis_gates) counts_corrected = job.result().get_counts() # Plot QASM simulation data plot_histogram([counts_noisy, counts_corrected], title='3-Qubit Error Correction $(P_{error} = ' + str(error_prob) + ')$', legend=['w/o code', 'with code'], figsize=(12, 9), bar_labels=False) plt.subplots_adjust(left=0.15, right=0.72, top=0.9, bottom=0.15) plt.show() # Initialize fidelity simulation objects job = execute(circ + qecc.encoder_ckt, backend=svsm) init_state = DensityMatrix(job.result().get_statevector()) job = execute(qecc.syndrome_ckt, backend=unit) syndrome_op = Kraus(job.result().get_unitary()) # Initialize fidelity simulation parameters p_error = [0.05 * i for i in range(11)] f1 = [] f2 = [] # Evolve initial state for p in p_error: # Build noise channel bit_flip_channel = Kraus([[[0, np.sqrt(p)], [np.sqrt(p), 0]], [[np.sqrt(1 - p), 0], [0, np.sqrt(1 - p)]]]) bit_flip_channel = bit_flip_channel.tensor(bit_flip_channel).tensor(
def sys_evolve_den(nsites, excitations, total_time, dt, hop, U, trotter_steps): #Check for correct data types of input if not isinstance(nsites, int): raise TypeError("Number of sites should be int") if np.isscalar(excitations): raise TypeError("Initial state should be list or numpy array") if not np.isscalar(total_time): raise TypeError("Evolution time should be scalar") if not np.isscalar(dt): raise TypeError("Time step should be scalar") if not isinstance(trotter_steps, int): raise TypeError("Number of trotter slices should be int") numq = 2 * nsites num_steps = int(total_time / dt) print('Num Steps: ', num_steps) print('Total Time: ', total_time) data = [] for t_step in range(0, num_steps): #Create circuit with t_step number of steps q = QuantumRegister(numq) c = ClassicalRegister(numq) qcirc = QuantumCircuit(q, c) #=========USE THIS REGION TO SET YOUR INITIAL STATE============== #Loop over each excitation for flip in excitations: qcirc.x(flip) #qcirc.h(flip) # qcirc.z(flip) #=============================================================== qcirc.barrier() #Append circuit with Trotter steps needed qc_evolve(qcirc, nsites, t_step * dt, dt, hop, U, trotter_steps) den_mtrx_obj = DensityMatrix.from_instruction(qcirc) den_mtrx = den_mtrx_obj.to_operator().data state_vector = qi.Statevector.from_instruction(qcirc) #data.append(state_vector.data) data.append(den_mtrx) #Measure the circuit for i in range(numq): qcirc.measure(i, i) ''' #Choose provider and backend provider = IBMQ.get_provider() #backend = Aer.get_backend('statevector_simulator') backend = Aer.get_backend('qasm_simulator') #backend = provider.get_backend('ibmq_qasm_simulator') #backend = provider.get_backend('ibmqx4') #backend = provider.get_backend('ibmqx2') #backend = provider.get_backend('ibmq_16_melbourne') shots = 8192 max_credits = 10 #Max number of credits to spend on execution job_exp = execute(qcirc, backend=backend, shots=shots, max_credits=max_credits) job_monitor(job_exp) result = job_exp.result() counts = result.get_counts(qcirc) print(result.get_counts(qcirc)) print("Job: ",t_step+1, " of ", num_steps," complete.") ''' return data
def __init__( self, name: str, instructions: Optional[Sequence[Instruction]] = None, default_states: Optional[Sequence[Union[Statevector, DensityMatrix]]] = None, qubit_states: Optional[Dict[int, Sequence[Union[Statevector, DensityMatrix]]]] = None, ): """Initialize a fitter preparation basis. Args: name: a name to identity the basis. instructions: list of 1-qubit instructions for preparing states from the :math:`|0^{\\otimes n}\\rangle` state. default_states: Optional, default density matrices prepared by the input instructions. If None these will be determined by ideal simulation of the preparation instructions. qubit_states: Optional, a dict with physical qubit keys and a list of density matrices prepared by the list of basis instructions for a specific qubit. The default states will be used for any qubits not specified in this dict. Raises: QiskitError: if input states or instructions are not valid, or no instructions or states are provided. """ if instructions is None and default_states is None and qubit_states is None: raise QiskitError( "LocalPreparationBasis must define at least one of instructions, " "default_states, or qubit_states." ) super().__init__(name) # Internal variables self._instructions = tuple() self._size = None self._default_states = None self._default_dim = None self._qubit_states = {} self._qubit_dim = {} self._qubits = set() self._custom_defaults = True # Format instructions so compatible types can be converted to # Instruction instances. if instructions is not None: self._instructions = _format_instructions(instructions) self._size = len(instructions) if default_states is None: default_states = self._instructions self._custom_defaults = False # Construct default states if default_states is not None: self._default_states = tuple(DensityMatrix(i).data for i in default_states) self._default_dim = self._default_states[0].shape[0] if self._size is None: self._size = len(self._default_states) elif len(self._default_states) != self._size: raise QiskitError( "Number of instructions and number of default states must be equal." ) # Construct states of specific qubits if provided qubit_states = qubit_states or {} for qubit, states in qubit_states.items(): if self._size is None: self._size = len(states) elif len(states) != self._size: raise QiskitError("Number of instructions and number of states must be equal.") qstates = tuple(DensityMatrix(i).data for i in states) self._qubit_states[qubit] = qstates self._qubit_dim[qubit] = qstates[0].shape[0] self._qubits.add(qubit) # Pseudo hash value to make basis hashable for LRU cached functions self._hash = hash( ( type(self), self._name, self._size, self._default_dim, self._custom_defaults, tuple(self._qubits), tuple(self._qubit_dim.values()), (type(i) for i in self._instructions), ) )
def __init__(self, initial_state: InitialState, operator: Optional[BaseOperator] = None, q: Optional[float] = 0.5, num_ancillae: Optional[int] = 0, var_form: Optional[VariationalForm] = None, optimizer: Optional[Optimizer] = None, initial_point: Optional[np.ndarray] = None, max_evals_grouped: int = 1, callback: Optional[Callable[[int, np.ndarray, float, float], None]] = None, quantum_instance: Optional[Union[QuantumInstance, BaseBackend]] = None) -> None: """ Constructor. Args: initial_state (InitialState): The state to be diagonalized operator (BaseOperator): The density matrix of the initial state q (int): Free parameter that ones to tailer the VQSD method num_ancillae (int): The number of ancillae qubits if the initial state is a mixed state var_form: A parameterized variational form (ansatz). optimizer: A classical optimizer. initial_point: An optional initial point (i.e. initial parameter values) for the optimizer. If ``None`` then VQE will look to the variational form for a preferred point and if not will simply compute a random one. max_evals_grouped: Max number of evaluations performed simultaneously. Signals the given optimizer that more than one set of parameters can be supplied so that potentially the expectation values can be computed in parallel. Typically this is possible when a finite difference gradient is used by the optimizer such that multiple points to compute the gradient can be passed and if computed in parallel improve overall execution time. callback: a callback that can access the intermediate data during the optimization. Four parameter values are passed to the callback as follows during each evaluation by the optimizer for its current set of parameters as it works towards the minimum. These are: the evaluation count, the optimizer parameters for the variational form, the evaluated global cost, local cost and weighted cost quantum_instance: Quantum Instance or Backend """ validate_min('max_evals_grouped', max_evals_grouped, 1) validate_range('num_ancillae', num_ancillae, 0, initial_state._num_qubits - 1) validate_range('q', q, 0.0, 1.0) if var_form is None: # TODO after ansatz refactor num qubits can be set later so we do not have to have # an operator to create a default if initial_state is not None: var_form = RY(initial_state._num_qubits - num_ancillae) if optimizer is None: optimizer = SLSQP() if operator is None: initial_state_vector = initial_state.construct_circuit(mode='vector') mat = np.outer(initial_state_vector, np.conj(initial_state_vector)) operator = DensityMatrix(mat) # TODO after ansatz refactor we may still not be able to do this # if num qubits is not set on var form if initial_point is None and var_form is not None: initial_point = var_form.preferred_init_points self._max_evals_grouped = max_evals_grouped super().__init__(var_form=var_form, optimizer=optimizer, cost_fn=self._cost_evaluation, initial_point=initial_point, quantum_instance=quantum_instance) self._callback = callback self._use_simulator_snapshot_mode = None self._ret = None self._eval_time = None self._eval_count = 0 logger.info(self.print_settings()) self._var_form_params = None if self.var_form is not None: self._var_form_params = ParameterVector('θ', self.var_form.num_parameters) self._parameterized_circuits = None self._initial_state = initial_state self._q = q self._num_ancillae = num_ancillae self._num_working_qubits = initial_state._num_qubits - num_ancillae self._operator = operator self.initial_state = initial_state # TODO : Verify that if the ancillae qubits form an orthonormal basis # Compute state purity if self._num_ancillae > 0: # pylint: disable=import-outside-toplevel from qiskit.quantum_info import purity, partial_trace rho = self._operator.data ancillae_idx = list(set(range(self._initial_state._num_qubits)) - set(range(self._num_ancillae))) self._operator = partial_trace(rho, ancillae_idx) self._purity = purity(self._operator) else: self._purity = 1.0