Source code for qubiter.Controls

from qubiter.CktEmbedder import *
import copy as cp

[docs]class Controls: """ This class stores a dictionary called self.bit_pos_to_kind containing key-value pairs of the form (a control's qubit number: its kind). Kinds can be either a bool or a non-negative integer. Kind is True if control is ``P_1 = n = |1><1|``. Kind is False if control is ``P_0 = nbar = |0><0|``. Kind is a non-negative integer for MP_Y and DIAG controls. Attributes ---------- bit_pos : list[int] This is the key's half if you unzip bit_pos_to_kind, in decreasing order bit_pos_to_kind : dict[int, bool|int] Dictionary matching control bit position with its kind. The domain of the map bit_pos_to_kind is a subset of range(num_qbits) kinds : list[bool|int] this is the value's half if you unzip bit_pos_to_kind. num_qbits : int number of qubits in full quantum circuit """ # combines my JAVA classes Control, TFControls, MultiControls
[docs] def __init__(self, num_qbits, bit_pos_to_kind=None): """ Constructor Parameters ---------- num_qbits : int bit_pos_to_kind : dict Returns ------- """ self.num_qbits = num_qbits # num_controls = len(bit_pos_to_kind) = len(bit_pos) = len(kinds) self.bit_pos = [] self.kinds = [] if not bit_pos_to_kind: self.bit_pos_to_kind = {} else: self.bit_pos_to_kind = bit_pos_to_kind self.refresh_lists()
[docs] @staticmethod def copy(old, extra_bits=0): """ Create a copy of self but add extra_bit many uncontrolled bits at the end. Parameters ---------- old : Controls extra_bits : int Returns ------- Controls """ new = Controls(old.num_qbits + extra_bits) new.bit_pos_to_kind = cp.copy(old.bit_pos_to_kind) new.bit_pos = cp.copy(old.bit_pos) new.kinds = cp.copy(old.kinds) return new
[docs] def set_control(self, bit_pos, kind, do_refresh=False): """ Add key-value pair (bit_pos: kind) to self.bit_pos_to_kind dictionary. Parameters ---------- bit_pos : int kind : bool|int do_refresh : bool Returns ------- None """ assert -1 < bit_pos < self.num_qbits, \ "bit position is out of range" self.bit_pos_to_kind[bit_pos] = kind if do_refresh: self.refresh_lists()
[docs] def refresh_lists(self): """ Replace the 2 lists bit_pos and kinds by unzipping (actually zip() does both zip and unzip) the dictionary bit_pos_to_kind. Returns ------- None """ # li is list of tuples. # sort li items so that in decreasing order of first entry of tuples if not self.bit_pos_to_kind: self.bit_pos = [] self.kinds = [] return li = sorted( self.bit_pos_to_kind.items(), key=lambda t: t[0], reverse=True) self.bit_pos, self.kinds = zip(*li)
[docs] @staticmethod def new_single_trol(num_qbits, bit_pos, kind): """ Returns a single control. Parameters ---------- num_qbits : int bit_pos : int kind : bool|int Returns ------- Controls """ new = Controls(num_qbits) new.set_control(bit_pos, kind) new.refresh_lists() return new
[docs] def is_control(self, bit_pos): """ True if bit_pos in the keys of bit_pos_to_kind. False otherwise. Parameters ---------- bit_pos : int Returns ------- bool """ return bit_pos in self.bit_pos
[docs] def get_workspace_bit_pot(self, target_bit_pos): """ Find a bit that is neither the target bit nor one of the controls. Make it as big as possible. Parameters ---------- target_bit_pos : int Returns ------- int """ num_controls = len(self.bit_pos_to_kind) # must have room for num_controls + one target + one workspace bit assert self.num_qbits >= num_controls + 2,\ "must have more qubits to find a working space bit" li = [target_bit_pos] + self.bit_pos for k in reversed(range(self.num_qbits)): if k not in li: break return k
[docs] def get_num_int_controls(self): """ Find number of controls that are not of boolean kind. Returns ------- int """ num = 0 num_controls = len(self.kinds) for k in range(num_controls): if not isinstance(self.kinds[k], bool): num += 1 return num
[docs] def new_embedded_self(self, emb): """ In bit_pos_to_kind, replace each key by a new key emb.bit_map[key]. Also add extra controls carried by emb. Parameters ---------- emb : CktEmbedder Returns ------- Controls """ if emb.is_identity_map(): return self if not self.bit_pos_to_kind: return self assert self.num_qbits == emb.num_qbits_bef new = Controls(emb.num_qbits_aft) self.refresh_lists() bef_num_controls = len(self.bit_pos) new.bit_pos_to_kind = {emb.aft(self.bit_pos[c]): self.kinds[c] for c in range(bef_num_controls)} # embedding can add new controls extra_trols = emb.extra_controls.bit_pos_to_kind if extra_trols: new.bit_pos_to_kind.update(extra_trols) new.refresh_lists() return new
if __name__ == "__main__": def main(): print(5) main()