def q_if(operation, num_ctrl_qubits=1, label=None): """Return controlled version of gate using controlled rotations Args: operation (Gate or Controlledgate): gate to create ControlledGate from num_ctrl_qubits (int): number of controls to add to gate (default=1) label (str): optional gate label Returns: ControlledGate: controlled version of gate. This default algorithm uses num_ctrl_qubits-1 ancillae qubits so returns a gate of size num_qubits + 2*num_ctrl_qubits - 1. Raises: QiskitError: gate contains non-gate in definitionl """ from math import pi # pylint: disable=cyclic-import import qiskit.circuit.controlledgate as controlledgate from qiskit.circuit.quantumregister import QuantumRegister from qiskit.circuit.quantumcircuit import QuantumCircuit # pylint: disable=unused-import import qiskit.extensions.standard.multi_control_rotation_gates import qiskit.extensions.standard.multi_control_toffoli_gate import qiskit.extensions.standard.multi_control_u1_gate q_control = QuantumRegister(num_ctrl_qubits, name='control') q_target = QuantumRegister(operation.num_qubits, name='target') q_ancillae = None # TODO: add qc = QuantumCircuit(q_control, q_target) if operation.name == 'x' or (isinstance(operation, controlledgate.ControlledGate) and operation.base_gate_name == 'x'): qc.mct(q_control[:] + q_target[:-1], q_target[-1], None, mode='noancilla') elif operation.name == 'rx': qc.mcrx(operation.definition[0][0].params[0], q_control, q_target[0], use_basis_gates=True) elif operation.name == 'ry': qc.mcry(operation.definition[0][0].params[0], q_control, q_target[0], q_ancillae, use_basis_gates=True) elif operation.name == 'rz': qc.mcrz(operation.definition[0][0].params[0], q_control, q_target[0], use_basis_gates=True) else: bgate = _unroll_gate(operation, ['u1', 'u3', 'cx']) # now we have a bunch of single qubit rotation gates and cx for rule in bgate.definition: if rule[0].name == 'u3': theta, phi, lamb = rule[0].params if phi == -pi / 2 and lamb == pi / 2: qc.mcrx(theta, q_control, q_target[rule[1][0].index], use_basis_gates=True) elif phi == 0 and lamb == 0: qc.mcry(theta, q_control, q_target[rule[1][0].index], q_ancillae, mode='noancilla', use_basis_gates=True) elif theta == 0 and phi == 0: qc.mcrz(lamb, q_control, q_target[rule[1][0].index], use_basis_gates=True) else: qc.mcrz(lamb, q_control, q_target[rule[1][0].index], use_basis_gates=True) qc.mcry(theta, q_control, q_target[rule[1][0].index], q_ancillae, use_basis_gates=True) qc.mcrz(phi, q_control, q_target[rule[1][0].index], use_basis_gates=True) elif rule[0].name == 'u1': qc.mcu1(rule[0].params[0], q_control, q_target[rule[1][0].index]) elif rule[0].name == 'cx': qc.mct(q_control[:] + [q_target[rule[1][0].index]], q_target[rule[1][1].index], None, mode='noancilla') else: raise QiskitError('gate contains non-controllable intructions') instr = qc.to_instruction() if isinstance(operation, controlledgate.ControlledGate): new_num_ctrl_qubits = num_ctrl_qubits + operation.num_ctrl_qubits base_name = operation.base_gate_name base_gate = operation.base_gate base_gate_name = operation.base_gate_name else: new_num_ctrl_qubits = num_ctrl_qubits base_name = operation.name base_gate = operation.__class__ base_gate_name = operation.name # In order to maintain some backward compatibility with gate names this # uses a naming convention where if the number of controls is <=2 the gate # is named like "cc<base_gate_name>", else it is named like # "c<num_ctrl_qubits><base_name>". if new_num_ctrl_qubits > 2: ctrl_substr = 'c{0:d}'.format(new_num_ctrl_qubits) else: ctrl_substr = ('{0}' * new_num_ctrl_qubits).format('c') new_name = '{0}{1}'.format(ctrl_substr, base_name) cgate = controlledgate.ControlledGate(new_name, instr.num_qubits, operation.params, label=label, num_ctrl_qubits=new_num_ctrl_qubits, definition=instr.definition) cgate.base_gate = base_gate cgate.base_gate_name = base_gate_name return cgate
def control( operation: Union[Gate, ControlledGate], num_ctrl_qubits: Optional[int] = 1, label: Optional[Union[None, str]] = None, ctrl_state: Optional[Union[None, int, str]] = None) -> ControlledGate: """Return controlled version of gate using controlled rotations. This function first checks the name of the operation to see if it knows of a method from which to generate a controlled version. Currently these are `x`, `rx`, `ry`, and `rz`. If a method is not directly known, it calls the unroller to convert to `u1`, `u3`, and `cx` gates. Args: operation: The gate used to create the ControlledGate. num_ctrl_qubits: The number of controls to add to gate (default=1). label: An optional gate label. ctrl_state: The control state in decimal or as a bitstring (e.g. '111'). If specified as a bitstring the length must equal num_ctrl_qubits, MSB on left. If None, use 2**num_ctrl_qubits-1. Returns: Controlled version of gate. Raises: CircuitError: gate contains non-gate in definition """ from math import pi # pylint: disable=cyclic-import import qiskit.circuit.controlledgate as controlledgate # pylint: disable=unused-import import qiskit.circuit.library.standard_gates.multi_control_rotation_gates # check args if num_ctrl_qubits == 0: return operation elif num_ctrl_qubits < 0: raise CircuitError('number of control qubits must be positive integer') q_control = QuantumRegister(num_ctrl_qubits, name='control') q_target = QuantumRegister(operation.num_qubits, name='target') q_ancillae = None # TODO: add qc = QuantumCircuit(q_control, q_target) if operation.name == 'x' or (isinstance(operation, controlledgate.ControlledGate) and operation.base_gate.name == 'x'): qc.mct(q_control[:] + q_target[:-1], q_target[-1], q_ancillae) elif operation.name == 'rx': qc.mcrx(operation.definition[0][0].params[0], q_control, q_target[0], use_basis_gates=True) elif operation.name == 'ry': qc.mcry(operation.definition[0][0].params[0], q_control, q_target[0], q_ancillae, mode='noancilla', use_basis_gates=True) elif operation.name == 'rz': qc.mcrz(operation.definition[0][0].params[0], q_control, q_target[0], use_basis_gates=True) else: bgate = _unroll_gate(operation, ['u1', 'u3', 'cx']) # now we have a bunch of single qubit rotation gates and cx for rule in bgate.definition: if rule[0].name == 'u3': theta, phi, lamb = rule[0].params if phi == -pi / 2 and lamb == pi / 2: qc.mcrx(theta, q_control, q_target[rule[1][0].index], use_basis_gates=True) elif phi == 0 and lamb == 0: qc.mcry(theta, q_control, q_target[rule[1][0].index], q_ancillae, use_basis_gates=True) elif theta == 0 and phi == 0: qc.mcrz(lamb, q_control, q_target[rule[1][0].index], use_basis_gates=True) else: qc.mcrz(lamb, q_control, q_target[rule[1][0].index], use_basis_gates=True) qc.mcry(theta, q_control, q_target[rule[1][0].index], q_ancillae, use_basis_gates=True) qc.mcrz(phi, q_control, q_target[rule[1][0].index], use_basis_gates=True) elif rule[0].name == 'u1': qc.mcu1(rule[0].params[0], q_control, q_target[rule[1][0].index]) elif rule[0].name == 'cx': qc.mct(q_control[:] + [q_target[rule[1][0].index]], q_target[rule[1][1].index], q_ancillae) else: raise CircuitError( 'gate contains non-controllable instructions') instr = qc.to_instruction() if isinstance(operation, controlledgate.ControlledGate): new_num_ctrl_qubits = num_ctrl_qubits + operation.num_ctrl_qubits new_ctrl_state = operation.ctrl_state << num_ctrl_qubits | ctrl_state base_name = operation.base_gate.name base_gate = operation.base_gate else: new_num_ctrl_qubits = num_ctrl_qubits new_ctrl_state = ctrl_state base_name = operation.name base_gate = operation # In order to maintain some backward compatibility with gate names this # uses a naming convention where if the number of controls is <=2 the gate # is named like "cc<base_gate.name>", else it is named like # "c<num_ctrl_qubits><base_name>". if new_num_ctrl_qubits > 2: ctrl_substr = 'c{0:d}'.format(new_num_ctrl_qubits) else: ctrl_substr = ('{0}' * new_num_ctrl_qubits).format('c') new_name = '{0}{1}'.format(ctrl_substr, base_name) cgate = controlledgate.ControlledGate(new_name, instr.num_qubits, operation.params, label=label, num_ctrl_qubits=new_num_ctrl_qubits, definition=instr.definition, ctrl_state=new_ctrl_state) cgate.base_gate = base_gate return cgate
def control( operation: Union[Gate, ControlledGate], num_ctrl_qubits: Optional[int] = 1, label: Optional[Union[None, str]] = None, ctrl_state: Optional[Union[None, int, str]] = None, ) -> ControlledGate: """Return controlled version of gate using controlled rotations. This function first checks the name of the operation to see if it knows of a method from which to generate a controlled version. Currently these are `x`, `rx`, `ry`, and `rz`. If a method is not directly known, it calls the unroller to convert to `u1`, `u3`, and `cx` gates. Args: operation: The gate used to create the ControlledGate. num_ctrl_qubits: The number of controls to add to gate (default=1). label: An optional gate label. ctrl_state: The control state in decimal or as a bitstring (e.g. '111'). If specified as a bitstring the length must equal num_ctrl_qubits, MSB on left. If None, use 2**num_ctrl_qubits-1. Returns: Controlled version of gate. Raises: CircuitError: gate contains non-gate in definition """ from math import pi # pylint: disable=cyclic-import import qiskit.circuit.controlledgate as controlledgate q_control = QuantumRegister(num_ctrl_qubits, name="control") q_target = QuantumRegister(operation.num_qubits, name="target") q_ancillae = None # TODO: add controlled_circ = QuantumCircuit(q_control, q_target, name="c_{}".format(operation.name)) if isinstance(operation, controlledgate.ControlledGate): original_ctrl_state = operation.ctrl_state global_phase = 0 if operation.name == "x" or (isinstance(operation, controlledgate.ControlledGate) and operation.base_gate.name == "x"): controlled_circ.mct(q_control[:] + q_target[:-1], q_target[-1], q_ancillae) if operation.definition is not None and operation.definition.global_phase: global_phase += operation.definition.global_phase else: basis = ["p", "u", "x", "z", "rx", "ry", "rz", "cx"] if isinstance(operation, controlledgate.ControlledGate): operation.ctrl_state = None unrolled_gate = _unroll_gate(operation, basis_gates=basis) if unrolled_gate.definition.global_phase: global_phase += unrolled_gate.definition.global_phase definition = unrolled_gate.definition bit_indices = { bit: index for bits in [definition.qubits, definition.clbits] for index, bit in enumerate(bits) } for gate, qargs, _ in definition.data: if gate.name == "x": controlled_circ.mct(q_control, q_target[bit_indices[qargs[0]]], q_ancillae) elif gate.name == "rx": controlled_circ.mcrx( gate.definition.data[0][0].params[0], q_control, q_target[bit_indices[qargs[0]]], use_basis_gates=True, ) elif gate.name == "ry": controlled_circ.mcry( gate.definition.data[0][0].params[0], q_control, q_target[bit_indices[qargs[0]]], q_ancillae, mode="noancilla", use_basis_gates=True, ) elif gate.name == "rz": controlled_circ.mcrz( gate.definition.data[0][0].params[0], q_control, q_target[bit_indices[qargs[0]]], use_basis_gates=True, ) elif gate.name == "p": from qiskit.circuit.library import MCPhaseGate controlled_circ.append( MCPhaseGate(gate.params[0], num_ctrl_qubits), q_control[:] + [q_target[bit_indices[qargs[0]]]], ) elif gate.name == "cx": controlled_circ.mct( q_control[:] + [q_target[bit_indices[qargs[0]]]], q_target[bit_indices[qargs[1]]], q_ancillae, ) elif gate.name == "u": theta, phi, lamb = gate.params if num_ctrl_qubits == 1: if theta == 0 and phi == 0: controlled_circ.cp(lamb, q_control[0], q_target[bit_indices[qargs[0]]]) else: controlled_circ.cu(theta, phi, lamb, 0, q_control[0], q_target[bit_indices[qargs[0]]]) else: if phi == -pi / 2 and lamb == pi / 2: controlled_circ.mcrx(theta, q_control, q_target[bit_indices[qargs[0]]], use_basis_gates=True) elif phi == 0 and lamb == 0: controlled_circ.mcry( theta, q_control, q_target[bit_indices[qargs[0]]], q_ancillae, use_basis_gates=True, ) elif theta == 0 and phi == 0: controlled_circ.mcrz(lamb, q_control, q_target[bit_indices[qargs[0]]], use_basis_gates=True) else: controlled_circ.mcrz(lamb, q_control, q_target[bit_indices[qargs[0]]], use_basis_gates=True) controlled_circ.mcry( theta, q_control, q_target[bit_indices[qargs[0]]], q_ancillae, use_basis_gates=True, ) controlled_circ.mcrz(phi, q_control, q_target[bit_indices[qargs[0]]], use_basis_gates=True) elif gate.name == "z": controlled_circ.h(q_target[bit_indices[qargs[0]]]) controlled_circ.mcx(q_control, q_target[bit_indices[qargs[0]]], q_ancillae) controlled_circ.h(q_target[bit_indices[qargs[0]]]) else: raise CircuitError( "gate contains non-controllable instructions: {}".format( gate.name)) if gate.definition is not None and gate.definition.global_phase: global_phase += gate.definition.global_phase # apply controlled global phase if global_phase: if len(q_control) < 2: controlled_circ.p(global_phase, q_control) else: controlled_circ.mcp(global_phase, q_control[:-1], q_control[-1]) if isinstance(operation, controlledgate.ControlledGate): operation.ctrl_state = original_ctrl_state new_num_ctrl_qubits = num_ctrl_qubits + operation.num_ctrl_qubits new_ctrl_state = operation.ctrl_state << num_ctrl_qubits | ctrl_state base_name = operation.base_gate.name base_gate = operation.base_gate else: new_num_ctrl_qubits = num_ctrl_qubits new_ctrl_state = ctrl_state base_name = operation.name base_gate = operation # In order to maintain some backward compatibility with gate names this # uses a naming convention where if the number of controls is <=2 the gate # is named like "cc<base_gate.name>", else it is named like # "c<num_ctrl_qubits><base_name>". if new_num_ctrl_qubits > 2: ctrl_substr = "c{:d}".format(new_num_ctrl_qubits) else: ctrl_substr = ("{0}" * new_num_ctrl_qubits).format("c") new_name = "{}{}".format(ctrl_substr, base_name) cgate = controlledgate.ControlledGate( new_name, controlled_circ.num_qubits, operation.params, label=label, num_ctrl_qubits=new_num_ctrl_qubits, definition=controlled_circ, ctrl_state=new_ctrl_state, base_gate=base_gate, ) return cgate
def control( operation: Union[Gate, ControlledGate], num_ctrl_qubits: Optional[int] = 1, label: Optional[Union[None, str]] = None, ctrl_state: Optional[Union[None, int, str]] = None) -> ControlledGate: """Return controlled version of gate using controlled rotations. This function first checks the name of the operation to see if it knows of a method from which to generate a controlled version. Currently these are `x`, `rx`, `ry`, and `rz`. If a method is not directly known, it calls the unroller to convert to `u1`, `u3`, and `cx` gates. Args: operation: The gate used to create the ControlledGate. num_ctrl_qubits: The number of controls to add to gate (default=1). label: An optional gate label. ctrl_state: The control state in decimal or as a bitstring (e.g. '111'). If specified as a bitstring the length must equal num_ctrl_qubits, MSB on left. If None, use 2**num_ctrl_qubits-1. Returns: Controlled version of gate. Raises: CircuitError: gate contains non-gate in definition """ from math import pi # pylint: disable=cyclic-import import qiskit.circuit.controlledgate as controlledgate q_control = QuantumRegister(num_ctrl_qubits, name='control') q_target = QuantumRegister(operation.num_qubits, name='target') q_ancillae = None # TODO: add controlled_circ = QuantumCircuit(q_control, q_target, name='c_{}'.format(operation.name)) global_phase = 0 if operation.name == 'x' or (isinstance(operation, controlledgate.ControlledGate) and operation.base_gate.name == 'x'): controlled_circ.mct(q_control[:] + q_target[:-1], q_target[-1], q_ancillae) if operation.definition is not None and operation.definition.global_phase: global_phase += operation.definition.global_phase else: basis = ['u1', 'u3', 'x', 'rx', 'ry', 'rz', 'cx'] unrolled_gate = _unroll_gate(operation, basis_gates=basis) for gate, qreg, _ in unrolled_gate.definition.data: if gate.name == 'x': controlled_circ.mct(q_control, q_target[qreg[0].index], q_ancillae) elif gate.name == 'rx': controlled_circ.mcrx(gate.definition.data[0][0].params[0], q_control, q_target[qreg[0].index], use_basis_gates=True) elif gate.name == 'ry': controlled_circ.mcry(gate.definition.data[0][0].params[0], q_control, q_target[qreg[0].index], q_ancillae, mode='noancilla', use_basis_gates=True) elif gate.name == 'rz': controlled_circ.mcrz(gate.definition.data[0][0].params[0], q_control, q_target[qreg[0].index], use_basis_gates=True) elif gate.name == 'u1': controlled_circ.mcu1(gate.params[0], q_control, q_target[qreg[0].index]) elif gate.name == 'cx': controlled_circ.mct(q_control[:] + [q_target[qreg[0].index]], q_target[qreg[1].index], q_ancillae) elif gate.name == 'u3': theta, phi, lamb = gate.params if phi == -pi / 2 and lamb == pi / 2: controlled_circ.mcrx(theta, q_control, q_target[qreg[0].index], use_basis_gates=True) elif phi == 0 and lamb == 0: controlled_circ.mcry(theta, q_control, q_target[qreg[0].index], q_ancillae, use_basis_gates=True) elif theta == 0 and phi == 0: controlled_circ.mcrz(lamb, q_control, q_target[qreg[0].index], use_basis_gates=True) else: controlled_circ.mcrz(lamb, q_control, q_target[qreg[0].index], use_basis_gates=True) controlled_circ.mcry(theta, q_control, q_target[qreg[0].index], q_ancillae, use_basis_gates=True) controlled_circ.mcrz(phi, q_control, q_target[qreg[0].index], use_basis_gates=True) else: raise CircuitError( 'gate contains non-controllable instructions: {}'.format( gate.name)) if gate.definition is not None and gate.definition.global_phase: global_phase += gate.definition.global_phase # apply controlled global phase if ((operation.definition is not None and operation.definition.global_phase) or global_phase): if len(q_control) < 2: controlled_circ.u1( operation.definition.global_phase + global_phase, q_control) else: controlled_circ.mcu1( operation.definition.global_phase + global_phase, q_control[:-1], q_control[-1]) if isinstance(operation, controlledgate.ControlledGate): new_num_ctrl_qubits = num_ctrl_qubits + operation.num_ctrl_qubits new_ctrl_state = operation.ctrl_state << num_ctrl_qubits | ctrl_state base_name = operation.base_gate.name base_gate = operation.base_gate else: new_num_ctrl_qubits = num_ctrl_qubits new_ctrl_state = ctrl_state base_name = operation.name base_gate = operation # In order to maintain some backward compatibility with gate names this # uses a naming convention where if the number of controls is <=2 the gate # is named like "cc<base_gate.name>", else it is named like # "c<num_ctrl_qubits><base_name>". if new_num_ctrl_qubits > 2: ctrl_substr = 'c{0:d}'.format(new_num_ctrl_qubits) else: ctrl_substr = ('{0}' * new_num_ctrl_qubits).format('c') new_name = '{0}{1}'.format(ctrl_substr, base_name) cgate = controlledgate.ControlledGate(new_name, controlled_circ.num_qubits, operation.params, label=label, num_ctrl_qubits=new_num_ctrl_qubits, definition=controlled_circ, ctrl_state=new_ctrl_state) cgate.base_gate = base_gate return cgate
def control( operation: Union[Gate, ControlledGate], num_ctrl_qubits: Optional[int] = 1, label: Optional[Union[None, str]] = None, ctrl_state: Optional[Union[None, int, str]] = None) -> ControlledGate: """Return controlled version of gate using controlled rotations Args: operation: gate to create ControlledGate from num_ctrl_qubits: number of controls to add to gate (default=1) label: optional gate label ctrl_state: The control state in decimal or as a bitstring (e.g. '111'). If specified as a bitstring the length must equal num_ctrl_qubits, MSB on left. If None, use 2**num_ctrl_qubits-1. Returns: Controlled version of gate. Raises: CircuitError: gate contains non-gate in definition """ from math import pi # pylint: disable=cyclic-import import qiskit.circuit.controlledgate as controlledgate # pylint: disable=unused-import import qiskit.extensions.standard.multi_control_rotation_gates import qiskit.extensions.standard.multi_control_toffoli_gate import qiskit.extensions.standard.multi_control_u1_gate q_control = QuantumRegister(num_ctrl_qubits, name='control') q_target = QuantumRegister(operation.num_qubits, name='target') q_ancillae = None # TODO: add qc = QuantumCircuit(q_control, q_target) if operation.name == 'x' or (isinstance(operation, controlledgate.ControlledGate) and operation.base_gate.name == 'x'): qc.mct(q_control[:] + q_target[:-1], q_target[-1], None, mode='noancilla') elif operation.name == 'rx': qc.mcrx(operation.definition[0][0].params[0], q_control, q_target[0], use_basis_gates=True) elif operation.name == 'ry': qc.mcry(operation.definition[0][0].params[0], q_control, q_target[0], q_ancillae, use_basis_gates=True) elif operation.name == 'rz': qc.mcrz(operation.definition[0][0].params[0], q_control, q_target[0], use_basis_gates=True) else: bgate = _unroll_gate(operation, ['u1', 'u3', 'cx']) # now we have a bunch of single qubit rotation gates and cx for rule in bgate.definition: if rule[0].name == 'u3': theta, phi, lamb = rule[0].params if phi == -pi / 2 and lamb == pi / 2: qc.mcrx(theta, q_control, q_target[rule[1][0].index], use_basis_gates=True) elif phi == 0 and lamb == 0: qc.mcry(theta, q_control, q_target[rule[1][0].index], q_ancillae, mode='noancilla', use_basis_gates=True) elif theta == 0 and phi == 0: qc.mcrz(lamb, q_control, q_target[rule[1][0].index], use_basis_gates=True) else: qc.mcrz(lamb, q_control, q_target[rule[1][0].index], use_basis_gates=True) qc.mcry(theta, q_control, q_target[rule[1][0].index], q_ancillae, use_basis_gates=True) qc.mcrz(phi, q_control, q_target[rule[1][0].index], use_basis_gates=True) elif rule[0].name == 'u1': qc.mcu1(rule[0].params[0], q_control, q_target[rule[1][0].index]) elif rule[0].name == 'cx': qc.mct(q_control[:] + [q_target[rule[1][0].index]], q_target[rule[1][1].index], None, mode='noancilla') else: raise CircuitError( 'gate contains non-controllable instructions') instr = qc.to_instruction() if isinstance(operation, controlledgate.ControlledGate): new_num_ctrl_qubits = num_ctrl_qubits + operation.num_ctrl_qubits base_name = operation.base_gate.name base_gate = operation.base_gate else: new_num_ctrl_qubits = num_ctrl_qubits base_name = operation.name base_gate = operation # In order to maintain some backward compatibility with gate names this # uses a naming convention where if the number of controls is <=2 the gate # is named like "cc<base_gate.name>", else it is named like # "c<num_ctrl_qubits><base_name>". if new_num_ctrl_qubits > 2: ctrl_substr = 'c{0:d}'.format(new_num_ctrl_qubits) else: ctrl_substr = ('{0}' * new_num_ctrl_qubits).format('c') new_name = '{0}{1}'.format(ctrl_substr, base_name) cgate = controlledgate.ControlledGate(new_name, instr.num_qubits, operation.params, label=label, num_ctrl_qubits=new_num_ctrl_qubits, definition=instr.definition, ctrl_state=ctrl_state) cgate.base_gate = base_gate return cgate