def get_gate_data(gatename): """Return number of qubits and number of rows or columns of native gate.""" if isinstance(gatename, QGate): shape = (gatename.size, 2**gatename.size) else: name, arg1, arg2, arg3, invert = prs.get_gate_data(gatename) if arg1 is None: arg1 = 0 if arg2 is None: arg2 = 0 if arg3 is None: arg3 = 0 if "SWAP" in name or name == "XX" or name == "YY" or name == "ZZ": shape = (2, 4) else: qgate = ct.c_void_p(_cGetQGate(ct.c_char_p(name.encode()), ct.c_double(arg1), ct.c_double(arg2), ct.c_double(arg3), ct.c_int(int(invert)))) # NOTNULLPTR and True = True, NOTNULLPTR or False = NOTNULLPTR if (qgate or False) == qgate: nqubits = int(_cGetQGateQubits(qgate)) size = int(_cGetQGateSize(qgate)) shape = (nqubits, size) else: shape = None print("Error while getting the specified gate!") return shape
def get_gate(gate_name): """Return the matrix of the specified gate.""" name, arg1, arg2, arg3, invert = prs.get_gate_data(gate_name) if arg1 is None: arg1 = 0 if arg2 is None: arg2 = 0 if arg3 is None: arg3 = 0 qgate = ct.c_void_p(_cGetQGate(ct.c_char_p(name.encode()), ct.c_double(arg1), ct.c_double(arg2), ct.c_double(arg3), ct.c_int(int(invert)))) # NOTNULLPTR and True = True, NOTNULLPTR or False = NOTNULLPTR if (qgate or False) == qgate: size = int(_cGetQGateSize(qgate)) plainmatrix2d = _cGet2dGate(qgate)[:size*size*2] rematrix2d = plainmatrix2d[:size*size] immatrix2d = plainmatrix2d[size*size:size*size*2] matrix = np.array([complex(rematrix2d[i], immatrix2d[i]) for i in range(size * size)]) matrix = matrix.reshape(size, size) else: matrix = None print("Error while getting the specified gate!") return matrix
def _invert_str_gate(gatename): """Invert the given native gate.""" selfinvert = ["X", "Y", "Z", "H", "SWAP", "I"] name, arg1, arg2, arg3, invert = prs.get_gate_data(gatename) if name not in selfinvert: if invert: gatename = gatename[:-2] else: gatename += "-1" return gatename
def _get_qubit_arg(gatename): """Get arguments from string with gate name.""" args = None if isinstance(gatename, str): qubitargs = ["XX", "YY", "ZZ"] name, arg1, arg2, arg3, invert = prs.get_gate_data(gatename) if name in qubitargs or "SWAP" in name: if name in qubitargs: args = set([arg2, arg3]) else: args = set([arg1, arg2]) return args
def _rebuild_gate_name(gate): """Standarize name of native gate and return tuple with gate data. Positional arguments: gate: string with name of a native gate OR list containing 0: string with name of a native gate 1 (optional): control qubit or list of control qubits ids 2 (optional): anticontrol qubit or list of anticontrol qubits ids Return: list containing 0: string with standarized name of a native gate 1: set of control qubits ids (can be empty) 2: set of anticontrol qubits ids (can be empty) """ cons = set() acons = set() gatename = gate if not isinstance(gate, str) and isinstance(gate, Iterable): gatename = gate[0] if (len(gate) > 1): if gate[1] is not None: if isinstance(gate[1], Iterable) and len(gate[1]) > 0: cons = set(gate[1]) elif not isinstance(gate[1], Iterable): cons = set([gate[1]]) if (len(gate) > 2): if gate[2] is not None: if isinstance(gate[2], Iterable) and len(gate[2]) > 0: acons = set(gate[2]) elif not isinstance(gate[2], Iterable): acons = set([gate[2]]) if not isinstance(gatename, QGate): if gatename is not None and gatename.lower() != "i": name, arg1, arg2, arg3, invert = prs.get_gate_data(gatename) if arg1 is not None: name += "(" + str(arg1) if arg2 is not None: name += "," + str(arg2) if arg3 is not None: name += "," + str(arg3) + ")" elif arg1 is not None: name += ")" if invert: name += "-1" else: name = None else: name = gatename return [name, cons, acons] if name is not None else None
def _add_qubit_offset(gatename, offset): """Return the gate name string adding the offset to any id argument.""" qubitargs = ["XX", "YY", "ZZ"] name, arg1, arg2, arg3, invert = prs.get_gate_data(gatename) if name in qubitargs or "SWAP" in name: arg2 += offset if name in qubitargs: arg3 += offset else: arg1 += offset if arg1 is not None: name += "(" + str(arg1) if arg2 is not None: name += str(arg2) if arg3 is not None: name += str(arg3) + ")" if invert: name += "-1" gatename = name return gatename
def apply_gate(self, gate, qubit=0, control=None, anticontrol=None, optimize=True): """Apply specified gate to specified qubit with specified controls. Positional arguments: gate: string with the name of the gate to apply, or a QGate Keyworded arguments: qubit: id of the least significant qubit the gate will target control: id or list of ids of the qubit that will act as controls anticontrol: id or list of ids of the qubit that will act as anticontrols optimize: only for QGates. Whether to use optimized lines or user defined lines """ if (np.issubdtype(type(qubit), np.integer) and qubit < self.get_num_qubits() and qubit >= 0): if (not isinstance(control, Iterable) and type(control) != int and not (control is None)): raise ValueError("Control must be an int, " + "a list of ints or None!") elif (not isinstance(anticontrol, Iterable) and type(anticontrol) != int and not (anticontrol is None)): raise ValueError("Anticontrol must be an int, " + "a list of ints or None!") elif (isinstance(control, Iterable) and isinstance(anticontrol, Iterable) and len(set(control) & set(anticontrol)) > 0): raise ValueError("A control can't be an anticontrol!") else: allOk = True clen = 0 if np.issubdtype(type(control), np.integer): int_array = ct.c_int * 1 control = int_array(control) clen = 1 elif control is None or len(control) == 0: control = c_int_p() clen = 0 else: control = set(control) clen = len(control) int_array = ct.c_int * clen control = int_array(*control) allOk = all(0 <= id < self.get_num_qubits() for id in control) aclen = 0 if np.issubdtype(type(anticontrol), np.integer): int_array = ct.c_int * 1 anticontrol = int_array(control) aclen = 1 elif anticontrol is None or len(anticontrol) == 0: anticontrol = c_int_p() aclen = 0 else: anticontrol = set(anticontrol) aclen = len(anticontrol) int_array = ct.c_int * aclen anticontrol = int_array(*anticontrol) allOk = allOk and all(0 <= id < self.get_num_qubits() for id in anticontrol) if allOk: if type(gate) == str: name, arg1, arg2, arg3, invert = get_gate_data(gate) if arg1 is None: arg1 = 0 if arg2 is None: arg2 = 0 if arg3 is None: arg3 = 0 if (name.lower() == "swap"): _swap_qubits(self.reg, arg1, arg2, False, False, invert, control, clen, anticontrol, aclen) elif (name.lower() == "iswap"): _swap_qubits(self.reg, arg1, arg2, True, False, invert, control, clen, anticontrol, aclen) elif (name.lower() == "sqrtswap"): _swap_qubits(self.reg, arg1, arg2, False, True, invert, control, clen, anticontrol, aclen) elif (name.lower() == "xx"): _ising_qubits(self.reg, 0, arg1, arg2, arg3, invert, control, clen, anticontrol, aclen) elif (name.lower() == "yy"): _ising_qubits(self.reg, 1, arg1, arg2, arg3, invert, control, clen, anticontrol, aclen) elif (name.lower() == "zz"): _ising_qubits(self.reg, 2, arg1, arg2, arg3, invert, control, clen, anticontrol, aclen) else: if int( _cApplyGate(self.reg, ct.c_char_p(name.encode()), ct.c_double(arg1), ct.c_double(arg2), ct.c_double(arg3), ct.c_int(int(invert)), ct.c_int(qubit), control, ct.c_int(clen), anticontrol, ct.c_int(aclen))) == 0: print("Error applying gate to specified QuBit") else: gate._apply_gate(self, qubit, control[:clen], anticontrol[:aclen], optimize=optimize) else: print("The ids must be between 0 and " + str(self.get_num_qubits())) else: if not np.issubdtype(type(qubit), np.integer): print("Qubit must be of integer type!") elif qubit >= self.get_num_qubits() or qubit < 0: print("The specified qubit doesn't exist!")
def apply_gate(self, *args, **kwargs): """Apply specified gate to specified qubit with specified controls. There are two variants for this method, depending on the number of gates you want to apply. One gate: Positional arguments: gate: string with the name of the gate to apply, or a QGate Keyworded arguments: qubit: id of the least significant qubit the gate will target control: id or list of ids of the qubit that will act as controls anticontrol: id or list of ids of the qubit that will act as anticontrols optimize: only for QGates. Whether to use optimized lines or user defined lines Multiple gates: Positional arguments: comma separated gates, their sizes must match the number of qubits in the system. Sorted by their least significant target qubit id. """ optimize = True if "optimize" in kwargs: optimize = kwargs["optimize"] if (len(args) == 1 or (len(args) == 2 and np.issubdtype(type(args[1]), np.integer) and "qubit" not in kwargs)): for key in kwargs: if (key != "qubit" and key != "control" and key != "anticontrol" and key != "optimize"): raise ValueError('Apart from the gates, you can only ' + 'specify "qubit", "control", ' + '"anticontrol" (lowercase) and/or ' + '"optimize"') gate = args[0] if type(gate) == QGate: gate = (gate, gate.size) elif gate == "I" or gate is None: return else: gate = (gate, get_gate_data(gate)[0]) qubit = kwargs.get("qubit", self.usable[0]) if len(args) == 2: qubit = args[1] control = kwargs.get("control", []) if control is None: control = [] if not isinstance(control, Iterable): control = [control] anticontrol = kwargs.get("anticontrol", []) if anticontrol is None: anticontrol = [] if not isinstance(anticontrol, Iterable): anticontrol = [anticontrol] if isinstance(qubit, Iterable): for qid in qubit: self.apply_gate(gate[0], qubit=qid, control=control, anticontrol=anticontrol, optimize=optimize) else: name = "" if type(gate[0]) != QGate: name, arg1, arg2, arg3, invert = prs.get_gate_data(gate[0]) invstring = "" if invert: invstring = "-1" qubits = set(control).union(anticontrol) # All affected qubits if "SWAP" in name: qubit = arg1 qubits.add(arg2) elif name == "XX" or name == "YY" or name == "ZZ": qubit = arg2 qubits.add(arg3) else: qubits.update([qubit + i for i in range(1, gate[1])]) rid = self.qubitMap[qubit] for qid in qubits: self._superposition(rid, self.qubitMap[qid]) reg, idlist = self.regs[rid] regmap = {idlist[i]: i for i in range(len(idlist))} newqubit = regmap[qubit] newcontrol = [regmap[qid] for qid in control] newanticontrol = [regmap[qid] for qid in anticontrol] if type(gate[0]) == QGate: reg.apply_gate(gate[0], qubit=newqubit, control=newcontrol, anticontrol=newanticontrol, optimize=optimize) else: if "SWAP" in name: gate = (name + "(" + str(regmap[arg1]) + "," + str(regmap[arg2]) + ")" + invstring, gate[1]) if name == "XX" or name == "YY" or name == "ZZ": gate = (name + "(" + str(arg1) + "," + str(regmap[arg2]) + "," + str(regmap[arg3]) + ")" + invstring, gate[1]) reg.apply_gate(gate[0], qubit=newqubit, control=newcontrol, anticontrol=newanticontrol, optimize=optimize) elif len(kwargs) == 0 and len(args) > 0: nq = 0 gates = [] for arg in args: if type(arg) == QGate: gatenq = (arg, arg.size) elif arg == "I" or arg is None: gatenq = (None, 1) else: gatenq = (arg, get_gate_data(arg)[0]) nq += gatenq[1] gates.append(gatenq) if nq == self.get_num_qubits(): qid = 0 for gate in gates: if gate[0] is not None: self.apply_gate(gate[0], qubit=qid, optimize=optimize) qid += gate[1] else: print("You have to specify a gate for each QuBit", "(or None if you don't want to operate with it)") elif len(args) == 0: print("You must specify at least one gate") else: print("You can't apply more than one gate when using", '"qubit", "control" or "anticontrol"')