Source code for tequila_code.simulators.simulator_symbolic

from tequila.simulators.simulator_base import BackendExpectationValue, BackendCircuit
from tequila.wavefunction.qubit_wavefunction import QubitWaveFunction
from tequila.circuit.circuit import QCircuit
from tequila.circuit.gates import QGate
from tequila import BitString
import numpy
import copy
import sympy

"""
Simple Symbolic Simulator for debugging purposes
"""

[docs] class BackendCircuitSymbolic(BackendCircuit): # compiler instructions compiler_arguments = { "trotterized": True, "swap": True, "multitarget": True, "controlled_rotation": False, "generalized_rotation": True, "exponential_pauli": True, "controlled_exponential_pauli": True, "phase": True, "power": True, "hadamard_power": True, "controlled_power": True, "controlled_phase": True, "toffoli": True, "phase_to_z": True, "cc_max": True } convert_to_numpy = True
[docs] def create_circuit(self, abstract_circuit: QCircuit, variables=None): return abstract_circuit
[docs] def update_variables(self, variables): pass
[docs] @classmethod def apply_gate(cls, state: QubitWaveFunction, gate: QGate, qubits: dict, variables) -> QubitWaveFunction: result = QubitWaveFunction() n_qubits = len(qubits.keys()) for s, v in state.items(): s.nbits = n_qubits result += v * cls.apply_on_standard_basis(gate=gate, basisfunction=s, qubits=qubits, variables=variables) return result
[docs] @classmethod 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
[docs] 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] = complex(v) else: wfn = result return wfn
[docs] class BackendExpectationValueSymbolic(BackendExpectationValue): BackendCircuitType = BackendCircuitSymbolic