def do_simulate(self, variables, initial_state: int = None, *args, **kwargs) -> QubitWaveFunction: qubits = dict() count = 0 for q in self.abstract_circuit.qubits: qubits[q] = count count +=1 n_qubits = len(self.abstract_circuit.qubits) if initial_state is None: initial_state = QubitWaveFunction.from_int(i=0, n_qubits=n_qubits) elif isinstance(initial_state, int): initial_state = QubitWaveFunction.from_int(initial_state, n_qubits=n_qubits) result = initial_state for g in self.abstract_circuit.gates: result = self.apply_gate(state=result, gate=g, qubits=qubits, variables=variables) wfn = QubitWaveFunction() if self.convert_to_numpy: for k,v in result.items(): wfn[k] = numpy.complex(v) else: wfn = result return wfn
def apply_on_standard_basis(cls, gate: QGate, basisfunction: BitString, qubits:dict, variables) -> QubitWaveFunction: basis_array = basisfunction.array if gate.is_controlled(): do_apply = True check = [basis_array[qubits[c]] == 1 for c in gate.control] for c in check: if not c: do_apply = False if not do_apply: return QubitWaveFunction.from_int(basisfunction) if len(gate.target) > 1: raise Exception("Multi-targets not supported for symbolic simulators") result = QubitWaveFunction() for tt in gate.target: t = qubits[tt] qt = basis_array[t] a_array = copy.deepcopy(basis_array) a_array[t] = (a_array[t] + 1) % 2 current_state = QubitWaveFunction.from_int(basisfunction) altered_state = QubitWaveFunction.from_int(BitString.from_array(a_array)) fac1 = None fac2 = None if gate.name == "H": fac1 = (sympy.Integer(-1) ** qt * sympy.sqrt(sympy.Rational(1 / 2))) fac2 = (sympy.sqrt(sympy.Rational(1 / 2))) elif gate.name.upper() == "CNOT" or gate.name.upper() == "X": fac2 = sympy.Integer(1) elif gate.name.upper() == "Y": fac2 = sympy.I * sympy.Integer(-1) ** (qt) elif gate.name.upper() == "Z": fac1 = sympy.Integer(-1) ** (qt) elif gate.name.upper() == "RX": angle = sympy.Rational(1 / 2) * gate.parameter(variables) fac1 = sympy.cos(angle) fac2 = -sympy.sin(angle) * sympy.I elif gate.name.upper() == "RY": angle = -sympy.Rational(1 / 2) * gate.parameter(variables) fac1 = sympy.cos(angle) fac2 = +sympy.sin(angle) * sympy.Integer(-1) ** (qt + 1) elif gate.name.upper() == "RZ": angle = sympy.Rational(1 / 2) * gate.parameter(variables) fac1 = sympy.exp(-angle * sympy.I * sympy.Integer(-1) ** (qt)) else: raise Exception("Gate is not known to simulators, " + str(gate)) if fac1 is None or fac1 == 0: result += fac2 * altered_state elif fac2 is None or fac2 == 0: result += fac1 * current_state elif fac1 is None and fac2 is None: raise Exception("???") else: result += fac1 * current_state + fac2 * altered_state return result
def test_hadamard(qubit, init): gate = gates.H(target=qubit) iwfn = QubitWaveFunction.from_int(i=init, n_qubits=qubit + 1) wfn = simulate(gate, initial_state=init) test = 1.0 / numpy.sqrt(2) * (iwfn.apply_qubitoperator(paulis.Z(qubit)) + iwfn.apply_qubitoperator(paulis.X(qubit))) assert (wfn.isclose(test))
def test_rotations(rot, qubit, angle, init): pauli = rot[1](qubit) gate = rot[0](target=qubit, angle=angle) iwfn = QubitWaveFunction.from_int(i=init, n_qubits=qubit + 1) wfn = simulate(gate, initial_state=init) test = numpy.cos(-angle / 2.0) * iwfn + 1.0j * numpy.sin( -angle / 2.0) * iwfn.apply_qubitoperator(pauli) assert (wfn.isclose(test))
def do_sample(self, samples, circuit, noise_model=None, initial_state=None, *args, **kwargs) -> QubitWaveFunction: """ Helper function for performing sampling. Parameters ---------- samples: int: the number of samples to be taken. circuit: the circuit to sample from. noise_model: optional: noise model to be applied to the circuit. initial_state: sampling supports initial states for qulacs. Indicates the initial state to which circuit is applied. args kwargs Returns ------- QubitWaveFunction: the results of sampling, as a Qubit Wave Function. """ n_qubits = max(self.highest_qubit + 1, self.n_qubits, self.abstract_circuit.max_qubit() + 1) if initial_state is not None: if isinstance(initial_state, int): wave = QubitWaveFunction.from_int(i=initial_state, n_qubits=n_qubits) elif isinstance(initial_state, str): wave = QubitWaveFunction.from_string( string=initial_state).to_array() elif isinstance(initial_state, QubitWaveFunction): wave = initial_state elif isinstance(initial_state, np.ndarray): wave = QubitWaveFunction.from_array( arr=initial_state, n_qubits=n_qubits) # silly but necessary else: raise TequilaQiboException( 'received an unusable initial state of type {}'.format( type(initial_state))) state = wave.to_array() result = circuit(state, nshots=samples) else: result = circuit(nshots=samples) back = self.convert_measurements(backend_result=result) return back
def map_state(self, state: list, *args, **kwargs) -> list: """ Expects a state in spin-orbital ordering Returns the corresponding qubit state in the class encoding :param state: basis-state as occupation number vector in spin orbitals sorted as: [0_up, 0_down, 1_up, 1_down, ... N_up, N_down] with N being the number of spatial orbitals :return: basis-state as qubit state in the corresponding mapping """ """Does a really lazy workaround ... but it works :return: Hartree-Fock Reference as binary-number Parameters ---------- reference_orbitals: list: give list of doubly occupied orbitals default is None which leads to automatic list of the first n_electron/2 orbitals Returns ------- """ # default is a lazy workaround, but it workds n_qubits = 2 * self.n_orbitals spin_orbitals = sorted([i for i, x in enumerate(state) if int(x) == 1]) string = "1.0 [" for i in spin_orbitals: string += str(i) + "^ " string += "]" fop = openfermion.FermionOperator(string, 1.0) op = self(fop) from tequila.wavefunction.qubit_wavefunction import QubitWaveFunction wfn = QubitWaveFunction.from_int(0, n_qubits=n_qubits) wfn = wfn.apply_qubitoperator(operator=op) assert (len(wfn.keys()) == 1) key = list(wfn.keys())[0].array return key
def do_simulate(self, variables, initial_state=None, *args, **kwargs): """ Helper function to perform simulation. Parameters ---------- variables: dict: variables to supply to the circuit. initial_state: information indicating the initial state on which the circuit should act. args kwargs Returns ------- QubitWaveFunction: QubitWaveFunction representing result of the simulation. """ n_qubits = max(self.highest_qubit + 1, self.n_qubits, self.abstract_circuit.max_qubit() + 1) if initial_state is not None: if isinstance(initial_state, int) or isinstance( initial_state, np.int): wave = QubitWaveFunction.from_int(i=initial_state, n_qubits=n_qubits) elif isinstance(initial_state, str): wave = QubitWaveFunction.from_string( string=initial_state).to_array() elif isinstance(initial_state, QubitWaveFunction): wave = initial_state elif isinstance(initial_state, np.ndarray): wave = QubitWaveFunction.from_array(initial_state) else: raise TequilaQiboException( 'could not understand initial state of type {}'.format( type(initial_state))) state = wave.to_array() result = self.circuit(state) else: result = self.circuit() back = QubitWaveFunction.from_array(arr=result.numpy()) return back
def test_pauli_gates(paulis, qubit, init): iwfn = QubitWaveFunction.from_int(i=init, n_qubits=qubit + 1) wfn = simulate(paulis[0](qubit), initial_state=init) iwfn = iwfn.apply_qubitoperator(paulis[1](qubit)) assert (iwfn.isclose(wfn))