Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
is called after, very fragile.
:param progs: List of Programs.
:return: None
:rtype: NoneType"""
def get_allocated_qubits(*progs):
qubits_to_progs = {}
for prog in progs:
for inst in prog:
if inst[0] == ACTION_INSTANTIATE_QUBIT:
qubits_to_progs[inst[1]] = [prog]
return qubits_to_progs
qubits_to_progs = get_allocated_qubits(*progs)
for prog in progs:
for inst in prog:
if isinstance(inst[1], Gate):
for arg in inst[1].arguments:
if isinstance(arg, Qubit):
qubits_to_progs[arg].append(prog)
equiv_classes = list(qubits_to_progs.values())
repeat = True
while repeat:
repeat = False
for i, equiv_class in enumerate(equiv_classes):
for j, other_equiv_class in enumerate(equiv_classes):
if j <= i:
continue
if set(equiv_class).intersection(set(other_equiv_class)):
equiv_classes[i] = set(equiv_class).union(other_equiv_class)
equiv_classes.remove(other_equiv_class)
repeat = True
"""
Add a gate to the program.
.. note::
The matrix elements along each axis are ordered by bitstring. For two qubits the order
is ``00, 01, 10, 11``, where the the bits **are ordered in reverse** by the qubit index,
i.e., for qubits 0 and 1 the bitstring ``01`` indicates that qubit 0 is in the state 1.
See also :ref:`the related docs in the WavefunctionSimulator Overview `.
:param name: The name of the gate.
:param params: Parameters to send to the gate.
:param qubits: Qubits that the gate operates on.
:return: The Program instance
"""
return self.inst(Gate(name, params, [unpack_qubit(q) for q in qubits]))
return program
if qubit_mapping is None:
qubit_mapping = {qp: Qubit(i) for i, qp in enumerate(qubits)}
else:
if all(isinstance(v, Qubit) for v in qubit_mapping.values()):
pass # we good
elif all(isinstance(v, int) for v in qubit_mapping.values()):
qubit_mapping = {k: Qubit(v) for k, v in qubit_mapping.items()}
else:
raise ValueError("Qubit mapping must map to type Qubit or int (but not both)")
result = []
for instr in program:
# Remap qubits on Gate, Measurement, and ResetQubit instructions
if isinstance(instr, Gate):
remapped_qubits = [qubit_mapping[q] for q in instr.qubits]
gate = Gate(instr.name, instr.params, remapped_qubits)
gate.modifiers = instr.modifiers
result.append(gate)
elif isinstance(instr, Measurement):
result.append(Measurement(qubit_mapping[instr.qubit], instr.classical_reg))
elif isinstance(instr, ResetQubit):
result.append(ResetQubit(qubit_mapping[instr.qubit]))
elif isinstance(instr, Pragma):
new_args = []
for arg in instr.args:
# Pragmas can have arguments that represent things besides qubits, so here we
# make sure to just look up the QubitPlaceholders.
if isinstance(arg, QubitPlaceholder):
new_args.append(qubit_mapping[arg])
else:
:return: A sequence of Gate objects encapsulating all gates compatible with the ISA.
:rtype: Sequence[Gate]
"""
gates = []
for q in isa.qubits:
if q.dead:
# TODO: dead qubits may in the future lead to some implicit re-indexing
continue
if q.type in ["Xhalves"]:
gates.extend([
Gate("I", [], [unpack_qubit(q.id)]),
Gate("RX", [np.pi / 2], [unpack_qubit(q.id)]),
Gate("RX", [-np.pi / 2], [unpack_qubit(q.id)]),
Gate("RX", [np.pi], [unpack_qubit(q.id)]),
Gate("RX", [-np.pi], [unpack_qubit(q.id)]),
Gate("RZ", [THETA], [unpack_qubit(q.id)]),
])
else: # pragma no coverage
raise ValueError("Unknown qubit type: {}".format(q.type))
for e in isa.edges:
if e.dead:
continue
targets = [unpack_qubit(t) for t in e.targets]
if e.type in ["CZ", "ISWAP"]:
gates.append(Gate(e.type, [], targets))
gates.append(Gate(e.type, [], targets[::-1]))
elif e.type in ["CPHASE"]:
gates.append(Gate(e.type, [THETA], targets))
gates.append(Gate(e.type, [THETA], targets[::-1]))
else: # pragma no coverage
raise ValueError("Unknown edge type: {}".format(e.type))
def RX(angle: ParameterDesignator, qubit: QubitDesignator) -> Gate:
"""Produces the RX gate::
RX(phi) = [[cos(phi / 2), -1j * sin(phi / 2)],
[-1j * sin(phi / 2), cos(phi / 2)]]
This gate is a single qubit X-rotation.
:param angle: The angle to rotate around the x-axis on the bloch sphere.
:param qubit: The qubit apply the gate to.
:returns: A Gate object.
"""
return Gate(name="RX", params=[angle], qubits=[unpack_qubit(qubit)])
elif q.type == "WILDCARD":
gates.extend([Gate("_", "_", [unpack_qubit(q.id)])])
else: # pragma no coverage
raise ValueError("Unknown qubit type: {}".format(q.type))
for e in isa.edges:
if e.dead:
continue
targets = [unpack_qubit(t) for t in e.targets]
edge_type = e.type if isinstance(e.type, list) else [e.type]
if "CZ" in edge_type:
gates.append(Gate("CZ", [], targets))
gates.append(Gate("CZ", [], targets[::-1]))
continue
if "ISWAP" in edge_type:
gates.append(Gate("ISWAP", [], targets))
gates.append(Gate("ISWAP", [], targets[::-1]))
continue
if "CPHASE" in edge_type:
gates.append(Gate("CPHASE", [THETA], targets))
gates.append(Gate("CPHASE", [THETA], targets[::-1]))
continue
if "XY" in edge_type:
gates.append(Gate("XY", [THETA], targets))
gates.append(Gate("XY", [THETA], targets[::-1]))
continue
if "WILDCARD" in e.type:
gates.append(Gate("_", "_", targets))
gates.append(Gate("_", "_", targets[::-1]))
continue
raise ValueError("Unknown edge type: {}".format(e.type))
def _run_program(self, program):
program = program.copy()
if self.qpu:
# time to go through the compiler. whee!
pragma = Program([Pragma('INITIAL_REWIRING', ['"PARTIAL"']), RESET()])
program = pragma + program
program = self._wrap_program(program)
nq_program = self._qc.compiler.quil_to_native_quil(program)
gate_count = sum(1 for instr in nq_program if isinstance(instr, Gate))
executable = self._qc.compiler.native_quil_to_executable(nq_program)
results = self._qc.run(executable=executable)
else:
program = self._wrap_program(program)
gate_count = len(program)
results = self._qc.run(program)
info = {
'gate_count': gate_count # compiled length for qpu, uncompiled for qvm
}
return results, info
modifier_qubits.append(qubits[len(modifier_qubits)])
base_qubits = qubits[len(modifier_qubits) :]
# Each FORKED doubles the number of parameters,
# e.g. FORKED RX(0.5, 1.5) 0 1 has two.
forked_offset = len(params) >> modifiers.count("FORKED")
base_params = params[:forked_offset]
if gate_name in QUANTUM_GATES:
if base_params:
gate = QUANTUM_GATES[gate_name](*base_params, *base_qubits)
else:
gate = QUANTUM_GATES[gate_name](*base_qubits)
else:
gate = Gate(gate_name, base_params, base_qubits)
# Track the last param used (for FORKED)
for modifier in modifiers[::-1]:
if modifier == "CONTROLLED":
gate.controlled(modifier_qubits.pop())
elif modifier == "DAGGER":
gate.dagger()
elif modifier == "FORKED":
gate.forked(modifier_qubits.pop(), params[forked_offset : (2 * forked_offset)])
forked_offset *= 2
else:
raise ValueError(f"Unsupported gate modifier {modifier}.")
self.result.append(gate)
def apply_noise_model(prog: "Program", noise_model: NoiseModel) -> "Program":
"""
Apply a noise model to a program and generated a 'noisy-fied' version of the program.
:param prog: A Quil Program object.
:param noise_model: A NoiseModel, either generated from an ISA or
from a simple decoherence model.
:return: A new program translated to a noisy gateset and with noisy readout as described by the
noisemodel.
"""
new_prog = _noise_model_program_header(noise_model)
for i in prog:
if isinstance(i, Gate):
try:
_, new_name = get_noisy_gate(i.name, tuple(i.params))
new_prog += Gate(new_name, [], i.qubits)
except NoisyGateUndefined:
new_prog += i
else:
new_prog += i
return new_prog