def simulate(self, variables, *args, **kwargs): """ Simulate the expectationvalue. Parameters ---------- variables: variables to supply to the unitary. args kwargs Returns ------- numpy array: the result of simulation. """ self.update_variables(variables) result = [] for H in self.H: final_E = 0.0 # The hamiltonian can be defined on more qubits as the unitaries qubits_h = H.qubits qubits_u = self.U.abstract_qubits all_qubits = list( set(qubits_h) | set(qubits_u) | set(range(self.U.abstract_circuit.max_qubit() + 1))) keymap = KeyMapSubregisterToRegister(subregister=qubits_u, register=all_qubits) # TODO inefficient, let the backend do it if possible or interface some library simresult = self.U.simulate(variables=variables, *args, **kwargs) wfn = simresult.apply_keymap(keymap=keymap) final_E += wfn.compute_expectationvalue(operator=H) result.append(to_float(final_E)) return numpy.asarray(result)
def make_excitation_generator( self, indices: typing.Iterable[typing.Tuple[int, int]]) -> QubitHamiltonian: """ Notes ---------- Creates the transformed hermitian generator of UCC type unitaries: M(a^\dagger_{a_0} a_{i_0} a^\dagger{a_1}a_{i_1} ... - h.c.) where the qubit map M depends is self.transformation Parameters ---------- indices : typing.Iterable[typing.Tuple[int, int]] : List of tuples [(a_0, i_0), (a_1, i_1), ... ] - recommended format, in spin-orbital notation (alpha odd numbers, beta even numbers) can also be given as one big list: [a_0, i_0, a_1, i_1 ...] Returns ------- type 1j*Transformed qubit excitation operator, depends on self.transformation """ # check indices and convert to list of tuples if necessary if len(indices) == 0: raise TequilaException( "make_excitation_operator: no indices given") elif not isinstance(indices[0], typing.Iterable): if len(indices) % 2 != 0: raise TequilaException( "make_excitation_generator: unexpected input format of indices\n" "use list of tuples as [(a_0, i_0),(a_1, i_1) ...]\n" "or list as [a_0, i_0, a_1, i_1, ... ]\n" "you gave: {}".format(indices)) converted = [(indices[2 * i], indices[2 * i + 1]) for i in range(len(indices) // 2)] else: converted = indices # convert to openfermion input format ofi = [] dag = [] for pair in converted: assert (len(pair) == 2) ofi += [ (int(pair[0]), 1), (int(pair[1]), 0) ] # openfermion does not take other types of integers like numpy.int64 dag += [(int(pair[0]), 0), (int(pair[1]), 1)] op = openfermion.FermionOperator(tuple(ofi), 1.j) # 1j makes it hermitian op += openfermion.FermionOperator(tuple(reversed(dag)), -1.j) qop = QubitHamiltonian(qubit_hamiltonian=self.transformation(op)) # check if the operator is hermitian and cast coefficients to floats # in order to avoid trouble with the simulation backends assert qop.is_hermitian() for k, v in qop.qubit_operator.terms.items(): qop.qubit_operator.terms[k] = to_float(v) qop = qop.simplify() return qop
def __init__(self, abstract_circuit: QCircuit, variables, use_mapping=True, noise=None, *args, **kwargs): self.op_lookup = { 'I': (pyquil.gates.I), 'X': (pyquil.gates.X, pyquil.gates.CNOT, pyquil.gates.CCNOT), 'Y': (pyquil.gates.Y,), 'Z': (pyquil.gates.Z, pyquil.gates.CZ), 'H': (pyquil.gates.H,), 'Rx': pyquil.gates.RX, 'Ry': pyquil.gates.RY, 'Rz': pyquil.gates.RZ, 'Phase': pyquil.gates.PHASE, 'SWAP': (pyquil.gates.SWAP, pyquil.gates.CSWAP), } self.match_par_to_dummy = {} self.counter = 0 super().__init__(abstract_circuit=abstract_circuit, variables=variables, noise=noise, use_mapping=use_mapping, *args, **kwargs) if self.noise is not None: self.noise_lookup = { 'amplitude damp': amp_damp_map, 'phase damp': phase_damp_map, 'bit flip': bit_flip_map, 'phase flip': phase_flip_map, 'phase-amplitude damp': phase_amp_damp_map, 'depolarizing': depolarizing_map } self.circuit = self.build_noisy_circuit(self.circuit, self.noise) if len(self.match_par_to_dummy.keys()) is None: self.match_dummy_to_value = None self.resolver = None else: self.match_dummy_to_value = {'theta_{}'.format(str(i)): k for i, k in enumerate(self.match_par_to_dummy.keys())} self.resolver = {k: [to_float(v(variables))] for k, v in self.match_dummy_to_value.items()}
def simulate(self, variables, *args, **kwargs): self.update_variables(variables) result = [] for H in self.H: final_E = 0.0 if self.use_mapping: # The hamiltonian can be defined on more qubits as the unitaries qubits_h = H.qubits qubits_u = self.U.qubits all_qubits = list( set(qubits_h) | set(qubits_u) | set(range(self.U.abstract_circuit.max_qubit() + 1))) keymap = KeyMapSubregisterToRegister(subregister=qubits_u, register=all_qubits) else: if H.qubits != self.U.qubits: raise TequilaException( "Can not compute expectation value without using qubit mappings." " Your Hamiltonian and your Unitary do not act on the same set of qubits. " "Hamiltonian acts on {}, Unitary acts on {}".format( H.qubits, self.U.qubits)) keymap = KeyMapSubregisterToRegister(subregister=self.U.qubits, register=self.U.qubits) # TODO inefficient, let the backend do it if possible or interface some library simresult = self.U.simulate(variables=variables, *args, **kwargs) wfn = simresult.apply_keymap(keymap=keymap) final_E += wfn.compute_expectationvalue(operator=H) result.append(to_float(final_E)) return numpy.asarray(result)
def do_compile_trotterized_gate(generator, steps, factor, randomize, control): """ Todo: Jakob, plz write """ assert (generator.is_hermitian()) circuit = QCircuit() factor = factor / steps for index in range(steps): paulistrings = generator.paulistrings if randomize: numpy.random.shuffle(paulistrings) for ps in paulistrings: coeff = to_float(ps.coeff) if len(ps._data) == 0 and len(control) > 0: circuit += Phase(target=control[0], control=control[1:], phi=-factor * coeff / 2) elif len(ps._data) > 0: circuit += ExpPauli(paulistring=ps.naked(), angle=factor * coeff, control=control) else: # ignore global phases pass return circuit
def is_hermitian(self): try: for k, v in self.qubit_operator.terms.items(): self.qubit_operator.terms[k] = to_float(v) return True except TypeError: return False
def array_to_objective_dict(objective, array, passives=None) -> typing.Dict[Variable, float]: """ reformats a numpy array of parameters to a dictionary in so that objective might use it as variables. Parameters ---------- objective: Objective: an Objective, whose parameters the array is meant to represent array: numpy.ndarray a numpy array of parameters. passives: optional: a dictionary of passive parameters to suppled the suggested parameters of array. Default means no passives involved. Returns ------- dict: dictinary of formatted parameters for use by objective """ op = objective.extract_variables() if passives is not None: for i, thing in enumerate(op): if thing in passives.keys(): op.remove(thing) back = {v: array[:, i] for i, v in enumerate(op)} if passives is not None: for k, v in passives.items(): back[k] = v back = {k: to_float(v) for k, v in back.items()} return back
def simulate(self, variables, *args, **kwargs): """ Simulate the expectationvalue. Parameters ---------- variables: variables to supply to the unitary. args kwargs Returns ------- numpy array: the result of simulation. """ self.update_variables(variables) result = [] for H in self.H: final_E = 0.0 # TODO inefficient, # Always better to overwrite this function wfn = self.U.simulate(variables=variables, *args, **kwargs) final_E += wfn.compute_expectationvalue(operator=H) result.append(to_float(final_E)) return numpy.asarray(result)
def update_variables(self, variables): """ overwriting the underlying code so that noise gets added when present """ if self.match_dummy_to_value is not None: self.resolver = {k: [to_float(v(variables))] for k, v in self.match_dummy_to_value.items()} else: self.resolver = None
def sample(self, variables, samples, *args, **kwargs) -> numpy.array: self.update_variables(variables) result = [] for H in self.H: E = 0.0 for ps in H.paulistrings: E += self.sample_paulistring(samples=samples, paulistring=ps, *args, **kwargs) result.append(to_float(E)) return numpy.asarray(result)
def update_variables(self, variables): """ overriding the underlying base to make sure this stuff remains noisy """ if self.sympy_to_tq is not None: self.resolver = { k: to_float(v(variables)) for k, v in self.sympy_to_tq.items() } else: self.resolver = None
def update_variables(self, variables): """ Update circuit variables for use in simulation or sampling Parameters ---------- variables: a new set of variables for use in the circuit. Returns ------- None """ if self.pars_to_tq is not None: self.resolver = {k: to_float(v(variables)) for k, v in self.pars_to_tq.items()} else: self.resolver = None
def do_compile_trotterized_gate(generator, steps, factor, randomize, control): assert (generator.is_hermitian()) circuit = QCircuit() factor = factor / steps for index in range(steps): paulistrings = generator.paulistrings if randomize: numpy.random.shuffle(paulistrings) for ps in paulistrings: if len(ps._data) == 0: print("ignoring constant term in trotterized gate") continue coeff = to_float(ps.coeff) circuit += ExpPauli(paulistring=ps.naked(), angle=factor * coeff, control=control) return circuit
def update_variables(self, variables): """ Update the variables for resolution in simulation or sampling. Parameters ---------- variables: dict: dictionary of tequila variables and values to resolve for simulation. Returns ------- None """ if self.match_dummy_to_value is not None: self.resolver = { k: [to_float(v(variables))] for k, v in self.match_dummy_to_value.items() } else: self.resolver = None
def sample(self, variables, samples, *args, **kwargs) -> numpy.array: """ sample the expectationvalue. Parameters ---------- variables: dict: variables to supply to the unitary. samples: int: number of samples to perform. args kwargs Returns ------- numpy.ndarray: a numpy array, the result of sampling. """ self.update_variables(variables) result = [] for H in self._reduced_hamiltonians: E = 0.0 if len(H.qubits) == 0: E = sum([ps.coeff for ps in H.paulistrings]) elif H.is_all_z(): E = self.U.sample_all_z_hamiltonian(samples=samples, hamiltonian=H, variables=variables, *args, **kwargs) else: for ps in H.paulistrings: E += self.U.sample_paulistring(samples=samples, paulistring=ps, variables=variables, *args, **kwargs) result.append(to_float(E)) return numpy.asarray(result)
def __init__(self, abstract_circuit: QCircuit, variables, qubit_map=None, noise=None, device=None, *args, **kwargs): """ Parameters ---------- abstract_circuit: QCircuit: the circuit to be compiled to qiskit. variables: dict: variables to compile the circuit with qubit_map: dictionary: a qubit map which maps the abstract qubits in the abstract_circuit to the qubits on the backend there is no need to initialize the corresponding backend types the dictionary should simply be {int:int} (preferred) or {int:name} if None the default will map to qubits 0 ... n_qubits -1 in the backend noise: noise to apply to the circuit. device: device on which to (perhaps, via emulation) execute the circuit. args kwargs """ self.op_lookup = { 'I': (lambda c: c.iden), 'X': (lambda c: c.x, lambda c: c.cx, lambda c: c.ccx), 'Y': (lambda c: c.y, lambda c: c.cy, lambda c: c.ccy), 'Z': (lambda c: c.z, lambda c: c.cz, lambda c: c.ccz), 'H': (lambda c: c.h, lambda c: c.ch, lambda c: c.cch), 'Rx': (lambda c: c.rx, lambda c: c.mcrx), 'Ry': (lambda c: c.ry, lambda c: c.mcry), 'Rz': (lambda c: c.rz, lambda c: c.mcrz), 'Phase': (lambda c: c.u1, lambda c: c.cu1), 'SWAP': (lambda c: c.swap, lambda c: c.cswap), } self.resolver = {} self.tq_to_pars = {} self.counter = 0 if qubit_map is None: n_qubits = len(abstract_circuit.qubits) else: n_qubits = max(qubit_map.values()) + 1 self.q = qiskit.QuantumRegister(n_qubits, "q") self.c = qiskit.ClassicalRegister(n_qubits, "c") super().__init__(abstract_circuit=abstract_circuit, variables=variables, noise=noise, device=device, qubit_map=qubit_map, *args, **kwargs) self.classical_map = self.make_classical_map(qubit_map=self.qubit_map) if noise != None: self.noise_lookup = { 'phase damp': qiskitnoise.phase_damping_error, 'amplitude damp': qiskitnoise.amplitude_damping_error, 'bit flip': get_bit_flip, 'phase flip': get_phase_flip, 'phase-amplitude damp': qiskitnoise.phase_amplitude_damping_error, 'depolarizing': qiskitnoise.depolarizing_error } if isinstance(noise, str): if noise == 'device': if device is not None: self.noise_model = qiskitnoise.NoiseModel.from_backend( self.device) else: raise TequilaException( 'cannot get device noise without specifying a device!' ) else: raise TequilaException( 'The only allowed string for noise is \'device\'; recieved {}. Please try again!' .format(str(noise))) else: nm = self.noise_model_converter(noise) self.noise_model = nm else: self.noise_model = None if len(self.tq_to_pars.keys()) is None: self.pars_to_tq = None self.resolver = None else: self.pars_to_tq = {v: k for k, v in self.tq_to_pars.items()} self.resolver = { k: to_float(v(variables)) for k, v in self.pars_to_tq.items() }
def __init__(self, abstract_circuit: QCircuit, variables, qubit_map=None, noise=None, device=None, *args, **kwargs): """ Parameters ---------- abstract_circuit: QCircuit: Tequila unitary to compile to Pyquil. variables: dict: values of all variables in the circuit, to compile with. qubit_map: dictionary: a qubit map which maps the abstract qubits in the abstract_circuit to the qubits on the backend there is no need to initialize the corresponding backend types the dictionary should simply be {int:int} (preferred) or {int:name} if None the default will map to qubits 0 ... n_qubits -1 in the backend noise: Noise to apply to the circuit. device: device on which to emulatedly execute all sampling. args kwargs """ self.op_lookup = { 'I': (pyquil.gates.I), 'X': (pyquil.gates.X, pyquil.gates.CNOT, pyquil.gates.CCNOT), 'Y': (pyquil.gates.Y, ), 'Z': (pyquil.gates.Z, pyquil.gates.CZ), 'H': (pyquil.gates.H, ), 'Rx': pyquil.gates.RX, 'Ry': pyquil.gates.RY, 'Rz': pyquil.gates.RZ, 'Phase': pyquil.gates.PHASE, 'SWAP': (pyquil.gates.SWAP, pyquil.gates.CSWAP), } self.match_par_to_dummy = {} self.counter = 0 if device is not None: self.compiler_arguments['cc_max'] = True super().__init__(abstract_circuit=abstract_circuit, variables=variables, noise=noise, device=device, qubit_map=qubit_map, *args, **kwargs) if self.noise is not None: self.noise_lookup = { 'amplitude damp': amp_damp_map, 'phase damp': phase_damp_map, 'bit flip': bit_flip_map, 'phase flip': phase_flip_map, 'phase-amplitude damp': phase_amp_damp_map, 'depolarizing': depolarizing_map } if isinstance(self.noise, str): if self.noise == 'device': pass else: raise TequilaException( 'noise was a string: {}, which is not \'device\'. This is not allowed!' .format(self.noise)) else: self.circuit = self.build_noisy_circuit( self.circuit, self.noise) if len(self.match_par_to_dummy.keys()) is None: self.match_dummy_to_value = None self.resolver = None else: self.match_dummy_to_value = { 'theta_{}'.format(str(i)): k for i, k in enumerate(self.match_par_to_dummy.keys()) } self.resolver = { k: [to_float(v(variables))] for k, v in self.match_dummy_to_value.items() }
def __init__(self, abstract_circuit: QCircuit, variables, use_mapping=True, noise=None, *args, **kwargs): self.op_lookup = { 'I': (lambda c: c.iden), 'X': (lambda c: c.x, lambda c: c.cx, lambda c: c.ccx), 'Y': (lambda c: c.y, lambda c: c.cy, lambda c: c.ccy), 'Z': (lambda c: c.z, lambda c: c.cz, lambda c: c.ccz), 'H': (lambda c: c.h, lambda c: c.ch, lambda c: c.cch), 'Rx': (lambda c: c.rx, lambda c: c.mcrx), 'Ry': (lambda c: c.ry, lambda c: c.mcry), 'Rz': (lambda c: c.rz, lambda c: c.mcrz), 'Phase': (lambda c: c.u1, lambda c: c.cu1), 'SWAP': (lambda c: c.swap, lambda c: c.cswap), } if use_mapping: qubits = abstract_circuit.qubits else: qubits = range(abstract_circuit.n_qubits) if noise != None: self.noise_lookup = { 'phase damp': qiskitnoise.phase_damping_error, 'amplitude damp': qiskitnoise.amplitude_damping_error, 'bit flip': get_bit_flip, 'phase flip': get_phase_flip, 'phase-amplitude damp': qiskitnoise.phase_amplitude_damping_error, 'depolarizing': qiskitnoise.depolarizing_error } nm = self.noise_model_converter(noise) self.noise_model = nm n_qubits = len(qubits) self.q = qiskit.QuantumRegister(n_qubits, "q") self.c = qiskit.ClassicalRegister(n_qubits, "c") self.classical_map = {i: self.c[j] for j, i in enumerate(qubits)} self.qubit_map = {i: self.q[j] for j, i in enumerate(qubits)} self.resolver = {} self.tq_to_sympy = {} self.counter = 0 super().__init__(abstract_circuit=abstract_circuit, variables=variables, noise=self.noise_model, use_mapping=use_mapping, *args, **kwargs) if len(self.tq_to_sympy.keys()) is None: self.sympy_to_tq = None self.resolver = None else: self.sympy_to_tq = {v: k for k, v in self.tq_to_sympy.items()} self.resolver = { k: to_float(v(variables)) for k, v in self.sympy_to_tq.items() } if self.noise_model is None: self.ol = 1 else: self.ol = 0
def __init__(self, abstract_circuit: QCircuit, variables, use_mapping=True, noise=None, device=None, *args, **kwargs): """ Parameters ---------- abstract_circuit: QCircuit: the circuit to be compiled to qiskit. variables: dict: variables to compile the circuit with use_mapping: bool: whether or not to build mappings. noise: noise to apply to the circuit. device: device on which to (perhaps, via emulation) execute the circuit. args kwargs """ self.op_lookup = { 'I': (lambda c: c.iden), 'X': (lambda c: c.x, lambda c: c.cx, lambda c: c.ccx), 'Y': (lambda c: c.y, lambda c: c.cy, lambda c: c.ccy), 'Z': (lambda c: c.z, lambda c: c.cz, lambda c: c.ccz), 'H': (lambda c: c.h, lambda c: c.ch, lambda c: c.cch), 'Rx': (lambda c: c.rx, lambda c: c.mcrx), 'Ry': (lambda c: c.ry, lambda c: c.mcry), 'Rz': (lambda c: c.rz, lambda c: c.mcrz), 'Phase': (lambda c: c.u1, lambda c: c.cu1), 'SWAP': (lambda c: c.swap, lambda c: c.cswap), } if use_mapping: qubits = abstract_circuit.qubits else: qubits = range(abstract_circuit.n_qubits) n_qubits = len(qubits) self.q = qiskit.QuantumRegister(n_qubits, "q") self.c = qiskit.ClassicalRegister(n_qubits, "c") self.classical_map = {i: self.c[j] for j, i in enumerate(qubits)} self.qubit_map = {i: self.q[j] for j, i in enumerate(qubits)} self.resolver = {} self.tq_to_pars = {} self.counter = 0 super().__init__(abstract_circuit=abstract_circuit, variables=variables, noise=noise, device=device, use_mapping=use_mapping, *args, **kwargs) if noise != None: self.noise_lookup = { 'phase damp': qiskitnoise.phase_damping_error, 'amplitude damp': qiskitnoise.amplitude_damping_error, 'bit flip': get_bit_flip, 'phase flip': get_phase_flip, 'phase-amplitude damp': qiskitnoise.phase_amplitude_damping_error, 'depolarizing': qiskitnoise.depolarizing_error } if isinstance(noise, str): if noise == 'device': if device is not None: self.noise_model = qiskitnoise.NoiseModel.from_backend( self.device) else: raise TequilaException( 'cannot get device noise without specifying a device!' ) else: raise TequilaException( 'The only allowed string for noise is \'device\'; recieved {}. Please try again!' .format(str(noise))) else: nm = self.noise_model_converter(noise) self.noise_model = nm else: self.noise_model = None if len(self.tq_to_pars.keys()) is None: self.pars_to_tq = None self.resolver = None else: self.pars_to_tq = {v: k for k, v in self.tq_to_pars.items()} self.resolver = { k: to_float(v(variables)) for k, v in self.pars_to_tq.items() }
def __init__(self, abstract_circuit: QCircuit, variables, use_mapping=True, noise=None, device=None, *args, **kwargs): """ Parameters ---------- abstract_circuit: QCircuit: Tequila unitary to compile to Pyquil. variables: dict: values of all variables in the circuit, to compile with. use_mapping: bool: whether or not to use a mapping that eliminates unnecessary qubits from the circuit. noise: Noise to apply to the circuit. device: device on which to emulatedly execute all sampling. args kwargs """ self.op_lookup = { 'I': (pyquil.gates.I), 'X': (pyquil.gates.X, pyquil.gates.CNOT, pyquil.gates.CCNOT), 'Y': (pyquil.gates.Y, ), 'Z': (pyquil.gates.Z, pyquil.gates.CZ), 'H': (pyquil.gates.H, ), 'Rx': pyquil.gates.RX, 'Ry': pyquil.gates.RY, 'Rz': pyquil.gates.RZ, 'Phase': pyquil.gates.PHASE, 'SWAP': (pyquil.gates.SWAP, pyquil.gates.CSWAP), } self.match_par_to_dummy = {} self.counter = 0 if device is not None: self.compiler_arguments['cc_max'] = True super().__init__(abstract_circuit=abstract_circuit, variables=variables, noise=noise, device=device, use_mapping=use_mapping, *args, **kwargs) if self.noise is not None: self.noise_lookup = { 'amplitude damp': amp_damp_map, 'phase damp': phase_damp_map, 'bit flip': bit_flip_map, 'phase flip': phase_flip_map, 'phase-amplitude damp': phase_amp_damp_map, 'depolarizing': depolarizing_map } if isinstance(self.noise, str): if self.noise == 'device': pass else: raise TequilaException( 'noise was a string: {}, which is not \'device\'. This is not allowed!' .format(self.noise)) else: self.circuit = self.build_noisy_circuit( self.circuit, self.noise) if len(self.match_par_to_dummy.keys()) is None: self.match_dummy_to_value = None self.resolver = None else: self.match_dummy_to_value = { 'theta_{}'.format(str(i)): k for i, k in enumerate(self.match_par_to_dummy.keys()) } self.resolver = { k: [to_float(v(variables))] for k, v in self.match_dummy_to_value.items() }