def wrapper(gate, **kwargs): if hasattr(gate, "gates"): result = QCircuit() for g in gate.gates: result += f(gate=g, **kwargs) return result elif hasattr(gate, 'U'): cU = QCircuit() for g in gate.U.gates: cU += f(gate=g, **kwargs) return type(gate)(U=cU, H=gate.H) elif hasattr(gate, 'transformation'): compiled = [] for E in gate.args: if hasattr(E, 'name'): compiled.append(E) else: cU = QCircuit() for g in E.U.gates: cU += f(gate=g, **kwargs) compiled.append(type(E)(U=cU, H=E.H)) return type(gate)(args=compiled, transformation=gate._transformation) else: return f(gate=gate, **kwargs)
def wrapper(gate, **kwargs): if hasattr(gate, "gates"): result = QCircuit() for g in gate.gates: result += f(gate=g, **kwargs) return result elif hasattr(gate, 'U'): cU = QCircuit() for g in gate.U.gates: cU += f(gate=g, **kwargs) return type(gate)(U=cU, H=gate.H) elif hasattr(gate, 'transformations'): outer = [] for args in gate.argsets: compiled = [] for E in args: if hasattr(E, 'name'): compiled.append(E) else: cU = QCircuit() for g in E.U.gates: cU += f(gate=g, **kwargs) compiled.append(type(E)(U=cU, H=E.H)) outer.append(compiled) if isinstance(gate, Objective): return type(gate)(args=outer[0], transformation=gate._transformation) if isinstance(gate, VectorObjective): return type(gate)(argsets=outer, transformations=gate._transformations) else: return f(gate=gate, **kwargs)
def compile_exponential_pauli_gate(gate) -> QCircuit: """ Returns the circuit: exp(i*angle*paulistring) primitively compiled into X,Y Basis Changes and CNOTs and Z Rotations :param paulistring: The paulistring in given as tuple of tuples (openfermion format) like e.g ( (0, 'Y'), (1, 'X'), (5, 'Z') ) :param angle: The angle which parametrizes the gate -> should be real :returns: the above mentioned circuit as abstract structure """ if hasattr(gate, "paulistring"): angle = gate.paulistring.coeff * gate.parameter circuit = QCircuit() # the general circuit will look like: # series which changes the basis if necessary # series of CNOTS associated with basis changes # Rz gate parametrized on the angle # series of CNOT (inverted direction compared to before) # series which changes the basis back ubasis = QCircuit() ubasis_t = QCircuit() cnot_cascade = QCircuit() last_qubit = None previous_qubit = None for k, v in gate.paulistring.items(): pauli = v qubit = [k] # wrap in list for targets= ... # see if we need to change the basis axis = 2 if pauli.upper() == "X": axis = 0 elif pauli.upper() == "Y": axis = 1 ubasis += change_basis(target=qubit, axis=axis) ubasis_t += change_basis(target=qubit, axis=axis, daggered=True) if previous_qubit is not None: cnot_cascade += X(target=qubit, control=previous_qubit) previous_qubit = qubit last_qubit = qubit reversed_cnot = cnot_cascade.dagger() # assemble the circuit circuit += ubasis circuit += cnot_cascade circuit += Rz(target=last_qubit, angle=angle, control=gate.control) circuit += reversed_cnot circuit += ubasis_t return circuit else: return QCircuit.wrap_gate(gate)
def compile_power_base(gate): """ Base case of compile_power_gate: convert a 1-qubit parametrized power gate into rotation gates. Parameters ---------- gate: the gate. Returns ------- A QCircuit; the result of compilation. """ if not isinstance(gate, PowerGateImpl): return QCircuit.wrap_gate(gate) if gate.is_controlled(): return QCircuit.wrap_gate(gate) power = gate.power if gate.name.lower() in ['h', 'hadamard']: ### off by global phase of Exp[ pi power /2] theta = power * numpy.pi result = QCircuit() result += Ry(angle=-numpy.pi / 4, target=gate.target) result += Rz(angle=theta, target=gate.target) result += Ry(angle=numpy.pi / 4, target=gate.target) elif gate.name == 'X': ### off by global phase of Exp[ pi power /2] ''' if we wanted to do it formally we would use the following a=-numpy.pi/2 b=numpy.pi/2 theta = power*numpy.pi result = QCircuit() result+= Rz(angle=b,target=gate.target) result+= Ry(angle=theta,target=gate.target) result+= Rz(angle=a,target=gate.target) ''' result = Rx(angle=power * numpy.pi, target=gate.target) elif gate.name == 'Y': ### off by global phase of Exp[ pi power /2] theta = power * numpy.pi result = QCircuit() result += Ry(angle=theta, target=gate.target) elif gate.name == 'Z': ### off by global phase of Exp[ pi power /2] a = 0 b = power * numpy.pi theta = 0 result = QCircuit() result += Rz(angle=b, target=gate.target) else: raise TequilaException('passed a gate with name ' + gate.name + ', which cannot be handled!') return result
def compile_toffoli(gate) -> QCircuit: if gate.name.lower != 'x': return QCircuit.wrap_gate(gate) control = gate.control c1 = control[1] c0 = control[0] target = gate.target result = QCircuit() result += H(target) result += CNOT(c1, target) result += T(target).dagger() result += CNOT(c0, target) result += T(target) result += CNOT(c1, target) result += T(target).dagger() result += CNOT(c0, target) result += T(c1) result += T(target) result += CNOT(c0, c1) result += H(target) result += T(c0) result += T(c1).dagger() result += CNOT(c0, c1) return (result)
def compile_to_cc(gate) -> QCircuit: if not gate.is_controlled: return QCircuit.wrap_gate(gate) cl = len(gate.control) target = gate.target control = gate.control if cl <= 2: return QCircuit.wrap_gate(gate) name = gate.name back = QCircuit() if name in ['X', 'x', 'Y', 'y', 'Z', 'z', 'H', 'h']: if isinstance(gate, PowerGateImpl): power = gate.parameter else: power = 1.0 new = PowerGateImpl(name=name, power=power, target=target, control=control) back += compile_power_gate(gate=new, cut=True) elif isinstance(gate, RotationGateImpl): partial = compile_controlled_rotation(gate=gate) back += compile_to_cc(gate=partial) elif isinstance(gate, PhaseGateImpl): partial = compile_controlled_phase(gate=gate) back += compile_to_cc(gate=partial) else: print(gate) raise TequilaException('frankly, what the f**k is this gate?') return back
def compile_controlled_phase(gate) -> QCircuit: if not isinstance(gate, PhaseGateImpl): return QCircuit.wrap_gate(gate) if len(gate.control) == 0: return QCircuit.wrap_gate(gate) count = len(gate.control) result = QCircuit() phase = gate.parameter if count == 1: result += H(target=gate.target) result += CNOT(gate.control, gate.target) result += H(target=gate.target) result += Phase(gate.parameter + numpy.pi, target=gate.target) elif count == 2: result += Rz(angle=phase / (2**2), target=gate.control[0]) result += Rz(angle=phase / (2**(1)), target=gate.control[1], control=gate.control[0]) result += Rz(angle=phase, target=gate.target, control=gate.control) elif count >= 3: result += Rz(angle=phase / (2**count), target=gate.control[0]) for i in range(1, count): result += Rz(angle=phase / (2**(count - i)), target=gate.control[i], control=gate.control[0:i]) result += Rz(angle=phase, target=gate.target, control=gate.control) return result
def compile_controlled_rotation(gate: RotationGateImpl) -> QCircuit: """ Recompilation of a controlled-rotation gate Basis change into Rz then recompilation of controled Rz, then change basis back :param gate: The rotational gate :return: set of gates wrapped in QCircuit class """ if not gate.is_controlled(): return QCircuit.wrap_gate(gate) if not isinstance(gate, RotationGateImpl): return QCircuit.wrap_gate(gate) if len(gate.target) > 1: return compile_controlled_rotation(gate=compile_multitarget(gate=gate)) target = gate.target control = gate.control k = len(control) cind = _pattern(k) + [k - 1] result = QCircuit() result += change_basis(target=target, axis=gate._axis) coeff = -1 / pow(2, k) for i, ci in enumerate(cind): coeff *= -1 result += Rz(target=target, angle=coeff * gate.parameter) result += CNOT(control[ci], target) result += change_basis(target=target, axis=gate._axis, daggered=True) result.n_qubits = result.max_qubit() + 1 return result
def hadamard_axbxc(gate) -> QCircuit: """ Decompose 1 control parametrized hadamard into single qubit rotation and CNOT. Parameters ---------- gate: the gate Returns ------- QCircuit, the result of compilation. """ if not isinstance(gate, PowerGateImpl) or gate.name not in [ 'H', 'h', 'hadamard' ]: return QCircuit.wrap_gate(gate) power = gate.parameter target = gate.target a = power.wrap(a_calc) b = power.wrap(b_calc) theta = power.wrap(theta_calc) phase = power * jnp.pi / 2 result = QCircuit() result += Rz((a - b) / 2, target) result += CNOT(gate.control, target) result += Rz(-(a + b) / 2, target) result += Ry(-theta / 2, target) result += CNOT(gate.control, target) result += Ry(theta / 2, target) result += Rz(a, target) result += Phase(numpy.pi * power / 2, gate.control) return result
def compile_controlled_power(gate: PowerGateImpl) -> QCircuit: """ Recompilation of a controlled-power gate Basis change into Z then recompilation of controled Z, then change basis back :param gate: The power gate :return: set of gates wrapped in QCircuit class """ if not gate.is_controlled(): return QCircuit.wrap_gate(gate) if not isinstance(gate, PowerGateImpl): return QCircuit.wrap_gate(gate) if len(gate.target) > 1: return compile_controlled_power(gate=compile_multitarget(gate=gate)) power = gate.power target = gate.target control = gate.control result = QCircuit() result += Phase(target=control[0], control=control[1:], phi=power * pi / 2) result += change_basis(target=target, name=gate.name) result += Rz(target=target, control=control, angle=power * pi) result += change_basis(target=target, name=gate.name, daggered=True) result.n_qubits = result.max_qubit() + 1 return result
def compile_trotterized_gate(gate, compile_exponential_pauli: bool = False): if not hasattr(gate, "generators") or not hasattr(gate, "steps"): return QCircuit.wrap_gate(gate) c = 1.0 result = QCircuit() if gate.join_components: for step in range(gate.steps): if gate.randomize_component_order: numpy.random.shuffle(gate.generators) for i, g in enumerate(gate.generators): if gate.angles is not None: c = gate.angles[i] result += do_compile_trotterized_gate(generator=g, steps=1, factor=c / gate.steps, randomize=gate.randomize, control=gate.control) else: if gate.randomize_component_order: numpy.random.shuffle(gate.generators) for i, g in enumerate(gate.generators): if gate.angles is not None: c = gate.angles[i] result += do_compile_trotterized_gate(generator=g, steps=gate.steps, factor=c, randomize=gate.randomize, control=gate.control) if compile_exponential_pauli: return compile_exponential_pauli_gate(result) else: return result
def compile_controlled_rotation(gate: RotationGateImpl, angles: list = None) -> QCircuit: """ Recompilation of a controlled-rotation gate Basis change into Rz then recompilation of controled Rz, then change basis back :param gate: The rotational gate :param angles: new angles to set, given as a list of two. If None the angle in the gate is used (default) :return: set of gates wrapped in QCircuit class """ if not gate.is_controlled(): return QCircuit.wrap_gate(gate) if not isinstance(gate, RotationGateImpl): return QCircuit.wrap_gate(gate) if angles is None: angles = [gate.parameter / 2, -gate.parameter / 2] if len(gate.target) > 1: return compile_controlled_rotation(gate=compile_multitarget(gate=gate), angles=angles) target = gate.target control = gate.control result = QCircuit() result += change_basis(target=target, axis=gate._axis) result += RotationGateImpl(axis="z", target=target, angle=angles[0]) result += QGateImpl(name="X", target=target, control=control) result += RotationGateImpl(axis="Z", target=target, angle=angles[1]) result += QGateImpl(name="X", target=target, control=control) result += change_basis(target=target, axis=gate._axis, daggered=True) result.n_qubits = result.max_qubit() + 1 return result
def change_basis(target, axis, daggered=False): """ helper function; returns circuit that performs change of basis. Parameters ---------- target: the qubit having its basis changed axis: The axis of rotation to shift into. daggered: bool: adjusts the sign of the gate if axis = 1, I.E, change of basis about Y axis. Returns ------- QCircuit that performs change of basis on target qubit onto desired axis """ if isinstance(axis, str): axis = RotationGateImpl.string_to_axis[axis.lower()] if axis == 0: return H(target=target) elif axis == 1 and daggered: return Rx(angle=-numpy.pi / 2, target=target) elif axis == 1: return Rx(angle=numpy.pi / 2, target=target) else: return QCircuit()
def hadamard_base(gate) -> QCircuit: """ base case for hadamard compilation; returns powers of hadamard as sequence of single qubit rotations. Parameters ---------- gate: the gate. Returns ------- A QCircuit; the result of compilation. """ if not isinstance(gate, PowerGateImpl) or gate.name not in [ 'H', 'h', 'hadamard' ]: return QCircuit.wrap_gate(gate) power = gate.parameter a = power.wrap(a_calc) b = power.wrap(b_calc) theta = power.wrap(theta_calc) result = QCircuit() result += Rz(angle=b, target=gate.target) result += Ry(angle=theta, target=gate.target) result += Rz(angle=a, target=gate.target) return result
def compile_multitarget(gate, variables=None) -> QCircuit: targets = gate.target # don't compile real multitarget gates if hasattr(gate, "generator") or hasattr(gate, "generators") or hasattr( gate, "paulistring"): return QCircuit.wrap_gate(gate) if isinstance(gate, ExponentialPauliGateImpl) or isinstance( gate, TrotterizedGateImpl): return QCircuit.wrap_gate(gate) if len(targets) == 1: return QCircuit.wrap_gate(gate) if isinstance(gate, MeasurementImpl): return QCircuit.wrap_gate(gate) if gate.name.lower() in ["swap", "iswap"]: return QCircuit.wrap_gate(gate) result = QCircuit() for t in targets: gx = copy.deepcopy(gate) gx._target = (t, ) result += gx return 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 compile_phase(gate) -> QCircuit: """ Compile phase gates into Rz gates and cnots, if controlled Parameters ---------- gate: the gate Returns ------- QCircuit, the result of compilation. """ if not isinstance(gate, PhaseGateImpl): return QCircuit.wrap_gate(gate) phase = gate.parameter result = QCircuit() if len(gate.control) == 0: return Rz(angle=phase, target=gate.target) if len(gate.control) == 1: result += Rz(angle=phase / 2, target=gate.control, control=None) result += Rz(angle=phase, target=gate.target, control=gate.control) return result else: return compile_controlled_phase(gate)
def compile_controlled_phase(gate) -> QCircuit: """ Compile multi-controlled phase gates to 1q - phase gate and multi-controlled Rz gates. Parameters ---------- gate: the gate. Returns ------- QCircuit, the result of compilation. """ if not isinstance(gate, PhaseGateImpl): return QCircuit.wrap_gate(gate) if len(gate.control) == 0: return QCircuit.wrap_gate(gate) phase = gate.parameter result = QCircuit() result += Phase(target=gate.control[0], control=gate.control[1:], phi=phase / 2) result += Rz(target=gate.target, control=gate.control, angle=phase) return compile_controlled_phase(result)
def sample_paulistring(self, samples: int, paulistring, variables, *args, **kwargs) -> numbers.Real: """ Sample an individual pauli word (pauli string) and return the average result thereof. Parameters ---------- samples: int: how many samples to evaluate. paulistring: the paulistring to be sampled. args kwargs Returns ------- float: the average result of sampling the chosen paulistring """ not_in_u = [ q for q in paulistring.qubits if q not in self.abstract_qubits ] reduced_ps = paulistring.trace_out_qubits(qubits=not_in_u) if reduced_ps.coeff == 0.0: return 0.0 if len(reduced_ps._data.keys()) == 0: return reduced_ps.coeff # make basis change and translate to backend basis_change = QCircuit() qubits = [] for idx, p in reduced_ps.items(): qubits.append(idx) basis_change += change_basis(target=idx, axis=p) # add basis change to the circuit # deepcopy is necessary to avoid changing the circuits # can be circumvented by optimizing the measurements # on construction: tq.ExpectationValue(H=H, U=U, optimize_measurements=True) circuit = self.create_circuit(circuit=copy.deepcopy(self.circuit), abstract_circuit=basis_change) # run simulators counts = self.sample(samples=samples, circuit=circuit, read_out_qubits=qubits, variables=variables, *args, **kwargs) # compute energy E = 0.0 n_samples = 0 for key, count in counts.items(): parity = key.array.count(1) sign = (-1)**parity E += sign * count n_samples += count assert n_samples == samples E = E / samples * paulistring.coeff return E
def sample_paulistring(self, samples: int, paulistring, *args, **kwargs) -> numbers.Real: # make basis change and translate to backend basis_change = QCircuit() not_in_u = [ ] # all indices of the paulistring which are not part of the circuit i.e. will always have the same outcome qubits = [] for idx, p in paulistring.items(): if idx not in self.abstract_qubit_map: not_in_u.append(idx) else: qubits.append(idx) basis_change += change_basis(target=idx, axis=p) # check the constant parts as <0|pauli|0>, can only be 0 or 1 # so we can do a fast return of one of them is not Z for i in not_in_u: pauli = paulistring[i] if pauli.upper() != "Z": return 0.0 # make measurement instruction measure = QCircuit() if len(qubits) == 0: # no measurement instructions for a constant term as paulistring return paulistring.coeff else: measure += Measurement(target=qubits) #measure += Measurement(name=str(paulistring), target=qubits) circuit = self.circuit + self.create_circuit(basis_change + measure) # run simulators counts = self.do_sample(samples=samples, circuit=circuit, *args, **kwargs) # compute energy E = 0.0 n_samples = 0 for key, count in counts.items(): parity = key.array.count(1) sign = (-1)**parity E += sign * count n_samples += count E = E / samples * paulistring.coeff return E
def hadamard_recursor(gate) -> QCircuit: if not isinstance(gate, PowerGateImpl) or gate.name not in [ 'H', 'h', 'hadamard' ]: return QCircuit.wrap_gate(gate) result = QCircuit() cl = 0 if gate.is_controlled(): cl = len(gate.control) if cl == 0: return hadamard_base(gate) if cl == 1: return hadamard_axbxc(gate) if cl == 2: v = type(gate)(name=gate.name, power=gate.parameter / 2, target=gate.target, control=gate.control[1]) result += hadamard_axbxc(v) result += CNOT(gate.control[0], gate.control[1]) vdag = type(gate)(name=gate.name, power=gate.parameter / 2, target=gate.target, control=gate.control[1]).dagger() result += hadamard_axbxc(vdag) result += CNOT(gate.control[0], gate.control[1]) again = type(gate)(name=gate.name, power=gate.parameter / 2, target=gate.target, control=gate.control[0]) result += hadamard_axbxc(again) else: v = type(gate)(name=gate.name, power=gate.parameter / 2, target=gate.target, control=gate.control[-1]) result += hadamard_axbxc(v) result += CNOT(target=gate.control[cl - 1], control=gate.control[0:cl - 1]) vdag = type(gate)(name=gate.name, power=gate.parameter / 2, target=gate.target, control=gate.control[-1]).dagger() result += hadamard_axbxc(vdag) result += CNOT(target=gate.control[cl - 1], control=gate.control[0:cl - 1]) rebuild = type(gate)(name=gate.name, power=gate.parameter / 2, target=gate.target, control=gate.control[:cl - 1]) result += hadamard_recursor(rebuild) return result
def change_basis(target, axis, daggered=False): if isinstance(axis, str): axis = RotationGateImpl.string_to_axis[axis.lower()] if axis == 0: return H(target=target) elif axis == 1 and daggered: return Rx(angle=-numpy.pi / 2, target=target) elif axis == 1: return Rx(angle=numpy.pi / 2, target=target) else: return QCircuit()
def compile_phase(gate) -> QCircuit: if not isinstance(gate, PhaseGateImpl): return QCircuit.wrap_gate(gate) phase = gate.parameter result = QCircuit() if len(gate.control) == 0: return Rz(angle=phase, target=gate.target) if len(gate.control) == 1: result += Rz(angle=phase / 2, target=gate.control, control=None) result += Rz(angle=phase, target=gate.target, control=gate.control) return result else: return compile_controlled_phase(gate)
def compile_power_base(gate): if not isinstance(gate, PowerGateImpl): return QCircuit.wrap_gate(gate) power = gate.parameter if gate.name in ['H', 'h', 'Hadamard', 'hadamard']: return compile_h_power(gate=gate) if gate.name == 'X': ### off by global phase of Exp[ pi power /2] ''' if we wanted to do it formally we would use the following a=-numpy.pi/2 b=numpy.pi/2 theta = power*numpy.pi result = QCircuit() result+= Rz(angle=b,target=gate.target) result+= Ry(angle=theta,target=gate.target) result+= Rz(angle=a,target=gate.target) ''' result = Rx(angle=power * numpy.pi, target=gate.target) elif gate.name == 'Y': ### off by global phase of Exp[ pi power /2] theta = power * numpy.pi result = QCircuit() result += Ry(angle=theta, target=gate.target) elif gate.name == 'Z': ### off by global phase of Exp[ pi power /2] a = 0 b = power * numpy.pi theta = 0 result = QCircuit() result += Rz(angle=b, target=gate.target) else: raise TequilaException('passed a gate with name ' + gate.name + ', which cannot be handled!') return result
def hadamard_base(gate) -> QCircuit: if not isinstance(gate, PowerGateImpl) or gate.name not in [ 'H', 'h', 'hadamard' ]: return QCircuit.wrap_gate(gate) power = gate.parameter a = power.wrap(a_calc) b = power.wrap(b_calc) theta = power.wrap(theta_calc) result = QCircuit() result += Rz(angle=b, target=gate.target) result += Ry(angle=theta, target=gate.target) result += Rz(angle=a, target=gate.target) return result
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 change_basis(target, axis=None, name=None, daggered=False): """ helper function; returns circuit that performs change of basis. Parameters ---------- target: the qubit having its basis changed axis: The axis of rotation to shift into. daggered: bool: adjusts the sign of the gate if axis = 1, I.E, change of basis about Y axis. Returns ------- QCircuit that performs change of basis on target qubit onto desired axis """ if axis is None and name is None: raise TequilaException('axis or name must be given.') if name: name = name.lower() if name in ['h', 'hadamard'] and daggered: return Ry(angle=numpy.pi / 4, target=target) elif name in ['h', 'hadamard']: return Ry(angle=-numpy.pi / 4, target=target) else: name_to_axis = {'rx': 0, 'ry': 1, 'rz': 2} axis = name_to_axis.get(name, name) if isinstance(axis, str): axis = RotationGateImpl.string_to_axis[axis.lower()] if axis == 0 and daggered: return Ry(angle=numpy.pi / 2, target=target) elif axis == 0: return Ry(angle=-numpy.pi / 2, target=target) elif axis == 1 and daggered: return Rx(angle=-numpy.pi / 2, target=target) elif axis == 1: return Rx(angle=numpy.pi / 2, target=target) else: return QCircuit()
def compile_to_single_control(gate) -> QCircuit: """ break down a gate into a sequence with no more than single-controlled gates. Parameters ---------- gate: the gate. Returns ------- A QCircuit; the result of compilation. """ if not gate.is_controlled: return QCircuit.wrap_gate(gate) cl = len(gate.control) target = gate.target control = gate.control if cl <= 1: return QCircuit.wrap_gate(gate) name = gate.name back = QCircuit() if name in ['X', 'x', 'Y', 'y', 'Z', 'z', 'H', 'h']: if isinstance(gate, PowerGateImpl): power = gate.parameter else: power = 1.0 new = PowerGateImpl(name=name, power=power, target=target, control=control, generator=gate.make_generator()) partial = compile_power_gate(gate=new) back += compile_to_single_control(gate=partial) elif isinstance(gate, RotationGateImpl): partial = compile_controlled_rotation(gate=gate) back += compile_to_single_control(gate=partial) elif isinstance(gate, PhaseGateImpl): partial = compile_controlled_phase(gate=gate) back += compile_to_single_control(gate=partial) else: print(gate) raise TequilaException('frankly, what the f**k is this gate?') return back
def compile_multitarget(gate, variables=None) -> QCircuit: """ If a gate is 'trivially' multitarget, split it into single target gates. Parameters ---------- gate: the gate in question variables: Todo: Jakob plz write Returns ------- QCircuit, the result of compilation. """ targets = gate.target # don't compile real multitarget gates if hasattr(gate, "generator") or hasattr(gate, "generators") or hasattr( gate, "paulistring"): return QCircuit.wrap_gate(gate) if isinstance(gate, ExponentialPauliGateImpl) or isinstance( gate, TrotterizedGateImpl): return QCircuit.wrap_gate(gate) if len(targets) == 1: return QCircuit.wrap_gate(gate) if isinstance(gate, MeasurementImpl): return QCircuit.wrap_gate(gate) if gate.name.lower() in ["swap", "iswap"]: return QCircuit.wrap_gate(gate) result = QCircuit() for t in targets: gx = copy.deepcopy(gate) gx._target = (t, ) result += gx return result
def compile_toffoli(gate) -> QCircuit: """ break down a toffoli gate into a sequence of CNOT and single qubit gates. Parameters ---------- gate: the gate. Returns ------- A QCircuit; the result of compilation. """ if gate.name.lower != 'x': return QCircuit.wrap_gate(gate) control = gate.control c1 = control[1] c0 = control[0] target = gate.target result = QCircuit() result += H(target) result += CNOT(c1, target) result += T(target).dagger() result += CNOT(c0, target) result += T(target) result += CNOT(c1, target) result += T(target).dagger() result += CNOT(c0, target) result += T(c1) result += T(target) result += CNOT(c0, c1) result += H(target) result += T(c0) result += T(c1).dagger() result += CNOT(c0, c1) return (result)