def rule_op(V, R, r, d, totalistic=False, hamiltonian=False): """ Operator for rule R, activation V, and neighborhood radius r, and dimension d. hamiltonian flag for simultaion type (hamiltonian=analog, unitary=digital) """ N = 2 * r * d OP = np.zeros((2 ** (N + 1), 2 ** (N + 1)), dtype=complex) if totalistic: R2 = mx.dec_to_bin(R, N + 1)[::-1] else: R2 = mx.dec_to_bin(R, 2 ** N)[::-1] for elnum, Rel in enumerate(R2): if totalistic: K = elnum * [1] + (N - elnum) * [0] hoods = list(set([perm for perm in permutations(K, N)])) hoods = map(list, hoods) else: hoods = [mx.dec_to_bin(elnum, N)] for hood in hoods: OP += rule_element(V, Rel, hood, hamiltonian=hamiltonian) if hamiltonian: assert mx.isherm(OP) else: # unitaty assert mx.isU(OP) return OP
def boundary_rule_ops(V, R, r, BC_conf, totalistic=False, hamiltonian=False): """ Special operators for boundaries (of which there are 2r). BC_conf is a string "b0b1...br...b2r" where each bj is either 0 or 1. Visiually, BC_conf represents the fixed boundaries from left to right: |b0>|b1>...|br> |psi>|b2r-r>|b2r-r+1>...|b2r>. """ # split BC configuration into left and reverse-right boundaries BC_conf = [BC_conf[:r], BC_conf[r::][::-1]] N = 2 * r OPs = [] for j, BC in enumerate(BC_conf): for e in range(r): dim = r + 1 + e if j == 0: # left boundary lslice = slice(r - e, r) rslice = slice(r, N) cslice = slice(0, r - e) elif j == 1: # right boundary lslice = slice(0, r) rslice = slice(r, r + e) cslice = slice(r + e, N) OP = np.zeros((2**dim, 2**dim), dtype=complex) if totalistic: R2 = mx.dec_to_bin(R, N + 1)[::-1] for elnum, Rel in enumerate(R2): K = elnum * [1] + (N - elnum) * [0] hoods = list(set([perm for perm in permutations(K, N)])) hoods = map(list, hoods) for hood in hoods: if BC[e:r] == hood[cslice]: OP += rule_element( V, Rel, hood, lslice=lslice, rslice=rslice, hamiltonian=hamiltonian, ) else: # non-totalistic R2 = mx.dec_to_bin(R, 2**N)[::-1] for elnum, Rel in enumerate(R2): hood = mx.dec_to_bin(elnum, N) if BC[e:r] == hood[cslice]: OP += rule_element( V, Rel, hood, lslice=lslice, rslice=rslice, hamiltonian=hamiltonian, ) if hamiltonian: assert mx.isherm(OP) else: # unitaty assert mx.isU(OP) OPs.append(OP) return OPs[:r], OPs[r:][::-1]
def boundary_rule_ops(V, R, r, d, BC_conf, totalistic=False, hamiltonian=False): """ Special operators for boundaries (of which there are 2r). BC_conf is a string "b0b1...br...b2r" where each bj is either 0 or 1. Visiually, BC_conf represents the fixed boundaries from left to right: |b0>|b1>...|br> |psi>|b2r-r>|b2r-r+1>...|b2r>. """ BC_conf = np.array([int(s) for s in BC_conf]) OPs = [] N = 2 * r * d if totalistic: R2 = mx.dec_to_bin(R, N + 1)[::-1] else: R2 = mx.dec_to_bin(R, 2 ** N)[::-1] indsj = [np.arange(r), np.array([r]), np.arange(r+1, 2*r+1)] dj = 2*r + 1 if d == 2: indsk = indsj dk = 2*r + 1 elif d ==1: indsk = [[0]] dk =1 OPs = [] for J, js in enumerate(indsj): for K, ks in enumerate(indsk): OPs_region = [] for j in js: OPs_row = [] for k in ks: mask = make_mask(j, k, dj, dk, r, d, BC_type="1") clip = np.logical_not(mask) if np.sum(clip) > 0: dim = np.sum(mask)+1 OP = np.zeros((2 ** dim, 2 ** dim), dtype=complex) for elnum, Rel in enumerate(R2): if totalistic: tot = elnum * [1] + (N - elnum) * [0] hoods = list(set([perm for perm in permutations(tot, N)])) hoods = map(np.array, hoods) else: hoods = np.array([mx.dec_to_bin(elnum, N)]) for hood in hoods: if np.all(BC_conf[clip] == hood[clip]): OP += rule_element( V, Rel, hood[mask], hamiltonian=hamiltonian, ) if hamiltonian: assert mx.isherm(OP) else: # unitaty assert mx.isU(OP) OPs_row.append(OP) OPs_region.append(OPs_row) if len(OPs_region[0]) > 0: OPs.append(OPs_region) return OPs
def make_H(L, R, V): H = np.zeros((2**L, 2**L), dtype=np.complex128) if type(V) is not str: ops['V'] = V V = 'V' bulks = [] lbs = [] rbs = [] for s, b in enumerate(mx.dec_to_bin(R, 4)[::-1]): if b: r = mx.dec_to_bin(s, 2) if r[1] == 0: rbs += [str(r[0]) + V] if r[0] == 0: lbs += [V + str(r[1])] bulks += [str(r[0]) + V + str(r[1])] #print('rule', R, mx.dec_to_bin(R, 4), lbs, bulks, rbs) for i in range(1, L - 1): l = i - 1 r = L - 3 - l left = np.eye(2**l) right = np.eye(2**r) for bulk in bulks: bulk = mx.listkron([ops[o] for o in bulk]) H += mx.listkron([left, bulk, right]) # boundaries end = np.eye(2**(L - 2)) for rb in rbs: rb = mx.listkron([ops[o] for o in rb]) #H += mx.listkron([end, rb]) for lb in lbs: lb = mx.listkron([ops[o] for o in lb]) #H += mx.listkron([lb, end]) assert mx.isherm(H) return H