def multiContraction(node1: tn.Node, node2: tn.Node, edges1, edges2, nodeName=None, cleanOr1=False, cleanOr2=False, isDiag1=False, isDiag2=False) -> tn.Node: if node1 is None or node2 is None: return None if edges1[len(edges1) - 1] == '*': copy1 = copyState([node1], conj=True)[0] edges1 = edges1[0:len(edges1) - 1] else: copy1 = copyState([node1])[0] if edges2[len(edges2) - 1] == '*': copy2 = copyState([node2], conj=True)[0] edges2 = edges2[0:len(edges2) - 1] else: copy2 = copyState([node2])[0] if cleanOr1: tn.remove_node(node1) if cleanOr2: tn.remove_node(node2) if isDiag1 and isDiag2: return tn.Node(copy1.tensor * copy2.tensor) elif isDiag1 and not isDiag2: return contractDiag(copy2, copy1.tensor, int(edges2[0])) elif isDiag2 and not isDiag1: return contractDiag(copy1, copy2.tensor, int(edges1[0])) for i in range(len(edges1)): copy1[int(edges1[i])] ^ copy2[int(edges2[i])] return tn.contract_between(copy1, copy2, name=nodeName)
def getOverlap(psi1Orig: List[tn.Node], psi2Orig: List[tn.Node]): psi1 = copyState(psi1Orig) psi2 = copyState(psi2Orig, conj=True) psi1[0][0] ^ psi2[0][0] psi1[0][1] ^ psi2[0][1] contracted = tn.contract_between(psi1[0], psi2[0], name='contracted') for i in range(1, len(psi1) - 1): psi1[i][1] ^ psi2[i][1] contracted[0] ^ psi1[i][0] contracted[1] ^ psi2[i][0] contracted = tn.contract_between( tn.contract_between(contracted, psi1[i]), psi2[i]) psi1[len(psi1) - 1][1] ^ psi2[len(psi1) - 1][1] psi1[len(psi1) - 1][2] ^ psi2[len(psi1) - 1][2] contracted[0] ^ psi1[len(psi1) - 1][0] contracted[1] ^ psi2[len(psi1) - 1][0] contracted = tn.contract_between( tn.contract_between(contracted, psi1[len(psi1) - 1]), psi2[len(psi1) - 1]) result = contracted.tensor tn.remove_node(contracted) removeState(psi1) removeState(psi2) return result
def test_remove_after_flatten(backend): a = tn.Node(np.ones((2, 2)), backend=backend) b = tn.Node(np.ones((2, 2)), backend=backend) tn.connect(a[0], b[0]) tn.connect(a[1], b[1]) tn.flatten_all_edges({a, b}) tn.remove_node(a)
def toEnvOperator(op): result = bops.unifyLegs( bops.unifyLegs( bops.unifyLegs( bops.unifyLegs(bops.permute(op, [0, 4, 1, 5, 2, 6, 3, 7]), 6, 7), 4, 5), 2, 3), 0, 1) tn.remove_node(op) return result
def unifyLegs(node: tn.Node, leg1: int, leg2: int, cleanOriginal=True) -> tn.Node: shape = node.get_tensor().shape newTensor = np.reshape( node.get_tensor(), list(shape[:leg1]) + [shape[leg1] * shape[leg2]] + list(shape[leg2 + 1:])) if cleanOriginal: tn.remove_node(node) return tn.Node(newTensor)
def assignNewSiteTensors(psi, k, M, dir, getOrthogonal=False): [sitek, sitekPlus1, truncErr] = svdTruncation(M, [M[0], M[1]], [M[2], M[3]], dir, \ leftName=('site' + str(k)), rightName=('site' + str(k+1)), edgeName = ('v' + str(k+1))) tn.remove_node(psi[k]) psi[k] = sitek # if k > 0: # psi[k-1][2] ^ psi[k] tn.remove_node(psi[k + 1]) psi[k + 1] = sitekPlus1 # if k+2 < len(psi): # psi[k+1][2] ^ psi[k+2][0] return [psi, truncErr]
def permute(node: tn.Node, permutation) -> tn.Node: if node is None: return None axisNames = [] for i in range(len(permutation)): axisNames.append(node.edges[permutation[i]].name) result = tn.Node(np.transpose(node.tensor, permutation)) if len(set(axisNames)) == len(axisNames): result.add_axis_names(axisNames) for i in range(len(axisNames)): result.get_edge(i).set_name(axisNames[i]) result.set_name(node.name) tn.remove_node(node) return result
def test_remove_node(backend): a = tn.Node(np.eye(2), backend=backend) b = tn.Node(np.eye(2), backend=backend) tn.connect(a[0], b[0]) broken_edges_by_name, broken_edges_by_axis = tn.remove_node(b) assert broken_edges_by_name == {"0": a[0]} assert broken_edges_by_axis == {0: a[0]}
def test_remove_node_trace_edge(backend): a = tn.Node(np.ones((2, 2, 2)), backend=backend) b = tn.Node(np.ones(2), backend=backend) tn.connect(a[0], b[0]) tn.connect(a[1], a[2]) _, broken_edges = tn.remove_node(a) assert 0 in broken_edges assert 1 not in broken_edges assert 2 not in broken_edges assert broken_edges[0] is b[0]
def addNodes(node1, node2, cleanOr1=False, cleanOr2=False): # TODO asserts if node1 is None: if node2 is None: res = None else: res = node2 else: if node2 is None: res = node1 else: result = copyState([node1])[0] result.set_tensor(result.get_tensor() + node2.get_tensor()) res = result if cleanOr1: tn.remove_node(node1) if cleanOr2: tn.remove_node(node2) return res
def localVecsEstimate(psi: List[tn.Node], vs: List[List[np.array]], half='left'): vs = np.round(vs, 10) n = len(vs) result = 1 for copy in range(n): if half == 'left': NA = len(vs[0]) curr = bops.multiContraction(psi[NA], psi[NA], '12', '12*') sites = range(NA - 1, -1, -1) elif half == 'right': NA = len(psi) - len(vs[0]) curr = bops.multiContraction(psi[len(psi) - NA - 1], psi[len(psi) - NA - 1], '01', '01*') sites = range(NA, len(psi)) psiCopy = bops.copyState(psi) for alpha in sites: toEstimate = np.outer(vs[copy][alpha - NA], np.conj(vs[np.mod(copy + 1, n)][alpha - NA])) psiCopy[alpha] = bops.permute(bops.multiContraction(psiCopy[alpha], tn.Node(toEstimate), \ '1', '1'), [0, 2, 1]) if half == 'left': curr = bops.multiContraction(bops.multiContraction( psiCopy[alpha], curr, '2', '0', cleanOr2=True), psi[alpha], '12', '12*', cleanOr1=True) elif half == 'right': curr = bops.multiContraction(bops.multiContraction( curr, psiCopy[alpha], '0', '0', cleanOr2=True), psi[alpha], '01', '01*', cleanOr1=True) # psiCopy = bops.shiftWorkingSite(psiCopy, alpha, '<<') result *= np.trace(curr.tensor) tn.remove_node(curr) bops.removeState(psiCopy) return result
def stateEnergy(psi: List[tn.Node], H: HOp): E = 0 for i in range(len(psi)): psiCopy = bops.copyState(psi) single_i = bops.copyState([H.singles[i]])[0] psiCopy[i] = bops.permute(tn.contract(psiCopy[i][1] ^ single_i[0], name=('site' + str(i))), [0, 2, 1]) E += bops.getOverlap(psiCopy, psi) bops.removeState(psiCopy) tn.remove_node(single_i) for i in range(len(psi) - 1): psiCopy = bops.copyState(psi) r2l = bops.copyState([H.r2l[i+1]])[0] l2r = bops.copyState([H.l2r[i]])[0] psiCopy[i][2] ^ psiCopy[i+1][0] psiCopy[i][1] ^ l2r[0] r2l[0] ^ psiCopy[i+1][1] l2r[2] ^ r2l[2] M = tn.contract_between(psiCopy[i], \ tn.contract_between(l2r, tn.contract_between(r2l, psiCopy[i+1]))) if bops.multiContraction(M, M, '0123', '0123*').tensor != 0: [psiCopy, te] = bops.assignNewSiteTensors(psiCopy, i, M, '>>') E += bops.getOverlap(psiCopy, psi) bops.removeState(psiCopy) tn.remove_node(r2l) tn.remove_node(l2r) return E
def shiftWorkingSite(psi: List[tn.Node], k, dir, maxBondDim=None): if dir == '<<': pair = multiContraction(psi[k - 1], psi[k], [2], [0], cleanOr1=True, cleanOr2=True) if maxBondDim is None: [l, r, I] = svdTruncation(pair, [0, 1], [2, 3], '<<') else: [l, r, I] = svdTruncation(pair, [0, 1], [2, 3], '<<', maxBondDim=maxBondDim) psi[k - 1] = l psi[k] = r tn.remove_node(pair) else: pair = tn.contract(psi[k][2] ^ psi[k + 1][0]) [l, r, I] = svdTruncation(pair, [0, 1], [2, 3], '>>', maxBondDim=maxBondDim) psi[k] = l psi[k + 1] = r tn.remove_node(pair) return psi
def randomMeasurement(psi, startInd, endInd): d = psi[0].tensor.shape[1] res = [-1] * (endInd - startInd) psiCopy = bops.copyState(psi) for k in [len(psiCopy) - 1 - i for i in range(len(psiCopy) - startInd - 1)]: psiCopy = bops.shiftWorkingSite(psiCopy, k, '<<') for i in range(startInd, endInd): rho = bops.multiContraction(psiCopy[i], psiCopy[i], '02', '02*') measurement = np.random.uniform(low=0, high=1) covered = 0 for s in range(len(rho.tensor)): if covered < measurement < covered + rho.tensor[s, s]: res[i - startInd] = s break covered += rho.tensor[s, s] projectorTensor = np.zeros((d, d), dtype=complex) projectorTensor[res[i - startInd], res[i - startInd]] = 1 projector = tn.Node(projectorTensor, backend=None) bops.applySingleSiteOp(psiCopy, projector, i) psiCopy = bops.shiftWorkingSite(psiCopy, i, '>>') psiCopy[i + 1].tensor /= np.sqrt(bops.getOverlap(psiCopy, psiCopy)) tn.remove_node(rho) bops.removeState(psiCopy) return res
def test_remove_node(backend): a = tn.Node(np.ones((2, 2, 2)), axis_names=["test", "names", "ignore"], backend=backend) b = tn.Node(np.ones((2, 2)), backend=backend) c = tn.Node(np.ones((2, 2)), backend=backend) tn.connect(a["test"], b[0]) tn.connect(a[1], c[0]) broken_edges_name, broken_edges_axis = tn.remove_node(a) assert "test" in broken_edges_name assert broken_edges_name["test"] is b[0] assert "names" in broken_edges_name assert broken_edges_name["names"] is c[0] assert "ignore" not in broken_edges_name assert 0 in broken_edges_axis assert 1 in broken_edges_axis assert 2 not in broken_edges_axis assert broken_edges_axis[0] is b[0] assert broken_edges_axis[1] is c[0]
def svdTruncation(node: tn.Node, leftEdges: List[tn.Edge], rightEdges: List[tn.Edge], \ dir: str, maxBondDim=1024, leftName='U', rightName='V', edgeName=None): maxBondDim = getAppropriateMaxBondDim(maxBondDim, leftEdges, rightEdges) if dir == '>>': leftEdgeName = edgeName rightEdgeName = None else: leftEdgeName = None rightEdgeName = edgeName [U, S, V, truncErr] = tn.split_node_full_svd(node, leftEdges, rightEdges, max_singular_values=maxBondDim, \ left_name=leftName, right_name=rightName, \ left_edge_name=leftEdgeName, right_edge_name=rightEdgeName) if dir == '>>': l = copyState([U])[0] r = copyState([tn.contract_between(S, V, name=V.name)])[0] else: l = copyState([tn.contract_between(U, S, name=U.name)])[0] r = copyState([V])[0] tn.remove_node(U) tn.remove_node(S) tn.remove_node(V) return [l, r, truncErr]
def svdTruncation(node: tn.Node, leftEdges: List[int], rightEdges: List[int], dir: str, maxBondDim=128, leftName='U', rightName='V', edgeName='default', normalize=False, maxTrunc=8): maxBondDim = getAppropriateMaxBondDim(maxBondDim, [node.edges[e] for e in leftEdges], [node.edges[e] for e in rightEdges]) if dir == '>>': leftEdgeName = edgeName rightEdgeName = None else: leftEdgeName = None rightEdgeName = edgeName [U, S, V, truncErr] = tn.split_node_full_svd(node, [node.edges[e] for e in leftEdges], [node.edges[e] for e in rightEdges], max_singular_values=maxBondDim, left_name=leftName, right_name=rightName, left_edge_name=leftEdgeName, right_edge_name=rightEdgeName) s = S S = tn.Node(np.diag(S.tensor)) tn.remove_node(s) norm = np.sqrt(sum(S.tensor**2)) if maxTrunc > 0: meaningful = sum(np.round(S.tensor / norm, maxTrunc) > 0) S.tensor = S.tensor[:meaningful] U.tensor = np.transpose(np.transpose(U.tensor)[:meaningful]) V.tensor = V.tensor[:meaningful] if normalize: S = multNode(S, 1 / norm) for e in S.edges: e.name = edgeName if dir == '>>': l = copyState([U])[0] r = multiContraction(S, V, '1', '0', cleanOr1=True, cleanOr2=True, isDiag1=True) elif dir == '<<': l = multiContraction(U, S, [len(U.edges) - 1], '0', cleanOr1=True, cleanOr2=True, isDiag2=True) r = copyState([V])[0] elif dir == '>*<': v = V V = copyState([V])[0] tn.remove_node(v) u = U U = copyState([U])[0] tn.remove_node(u) return [U, S, V, truncErr] tn.remove_node(U) tn.remove_node(S) tn.remove_node(V) return [l, r, truncErr]
def removeState(psi): for i in range(len(psi)): tn.remove_node(psi[i])
def bmpsRowStep(gammaL, lambdaMid, gammaR, lambdaSide, envOp): row = bops.multiContraction(bops.multiContraction(bops.multiContraction( bops.multiContraction(lambdaSide, gammaL, '1', '0', isDiag1=True), lambdaMid, '2', '0', cleanOr1=True, cleanOr2=True, isDiag2=True), gammaR, '2', '0', cleanOr1=True, cleanOr2=True), lambdaSide, '3', '0', cleanOr1=True, isDiag2=True) opRow = bops.permute( bops.multiContraction(row, envOp, '12', '01', cleanOr1=True), [0, 2, 4, 5, 1, 3]) [U, S, V, truncErr] = bops.svdTruncation(opRow, [0, 1, 2], [3, 4, 5], dir='>*<', maxBondDim=chi) newLambdaMid = bops.multNode(S, 1 / np.sqrt(sum(S.tensor**2))) lambdaSideInv = tn.Node( np.array([1 / val if val > 1e-15 else 0 for val in lambdaSide.tensor], dtype=complex)) newGammaL = bops.multiContraction(lambdaSideInv, U, '1', '0', cleanOr2=True, isDiag1=True) splitter = tn.Node( bops.getLegsSplitterTensor(newGammaL[0].dimension, newGammaL[1].dimension)) newGammaL = bops.unifyLegs(newGammaL, 0, 1) newGammaR = bops.multiContraction(V, lambdaSideInv, '2', '0', cleanOr1=True, cleanOr2=True, isDiag2=True) newGammaR = bops.unifyLegs(newGammaR, 2, 3) newLambdaSide = bops.multiContraction(bops.multiContraction(lambdaSide, splitter, '1', '0', cleanOr1=True, isDiag1=True), splitter, '01', '01', cleanOr1=True, cleanOr2=True) temp = newLambdaSide newLambdaSide = tn.Node(np.diag(newLambdaSide.tensor)) tn.remove_node(temp) return newGammaL, newLambdaMid, newGammaR, newLambdaSide