Example #1
0
 def __init__(self, node_names, approximate_energy=0):
     self.node_number = len(node_names)
     self.state_vector = Tensor(node_names,
                                [2
                                 for _ in range(self.node_number)]).randn()
     self.bonds = []
     self.energy = 0.
     self.approximate_energy = abs(approximate_energy)
Example #2
0
 def _create_tensor(self, l1: int, l2: int) -> Tensor:
     name_list = ["Left", "Right", "Up", "Down"]
     if l1 == 0:
         name_list.remove("Up")
     if l2 == 0:
         name_list.remove("Left")
     if l1 == self.L1 - 1:
         name_list.remove("Down")
     if l2 == self.L2 - 1:
         name_list.remove("Right")
     dimension_list = [2, *[self.D for _ in name_list]]
     name_list = ["Phy", *name_list]
     result = Tensor(name_list, dimension_list)
     result.block()[:] = np.random.rand(*dimension_list)
     return result
Example #3
0
    # print(fuse_leg_A)
    # print(fuse_leg_B)

    name_list_A = [f"A.{i}" for i in range(rank_A)]
    name_list_B = [f"B.{i}" for i in range(rank_B)]
    for i in range(rank_fuse):
        name_list_A[fuse_leg_A[i]] = f"{i}"
        name_list_B[fuse_leg_B[i]] = f"{i}"

    dim_A = np.random.randint(1, max_random, rank_A).tolist()
    dim_B = np.random.randint(1, max_random, rank_B).tolist()
    for i in range(rank_total):
        dim_A[total_leg_A[i]] = dim_B[total_leg_B[i]] = np.random.randint(
            2, max_random)

    A = Tensor(name_list_A, dim_A).test()
    B = Tensor(name_list_B, dim_B).test()
    C = A.contract(
        B, {(f"A.{contract_leg_A[i]}", f"B.{contract_leg_B[i]}")
            for i in range(rank_contract)})
    # print(repr(A))
    # print(repr(B))
    # print(repr(C))
    a = A.block[{}]
    b = B.block[{}]

    index_A = [chr(ord('a') + i) for i in range(rank_A)]
    index_B = [chr(ord('A') + i) for i in range(rank_B)]
    index_C = []
    for i in range(rank_total):
        index_A[total_leg_A[i]] = index_B[total_leg_B[i]]
Example #4
0
class TwoDimensionHeisenberg:
    raw_base: List[Tensor] = [Tensor(["Phy"], [2]) for _ in range(2)]
    raw_base[0].block()[:] = [1, 0]
    raw_base[1].block()[:] = [0, 1]

    hamiltonian = Tensor("I0 I1 O0 O1".split(" "), [2, 2, 2, 2])
    hamiltonian.block()[:] = np.array([
        1 / 4., 0, 0, 0, 0, -1 / 4., 2 / 4., 0, 0, 2 / 4., -1 / 4., 0, 0, 0, 0,
        1 / 4.
    ]).reshape([2, 2, 2, 2])

    hamiltonian_square = hamiltonian.contract(hamiltonian, {("I0", "O0"),
                                                            ("I1", "O1")})

    identity = Tensor("I0 I1 O0 O1".split(" "), [2, 2, 2, 2])
    identity.block()[:] = np.array(
        [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]).reshape([2, 2, 2, 2])

    __slots__ = [
        "L1", "L2", "D", "lattice", "spin", "_auxiliaries", "_lattice_spin",
        "environment"
    ]

    def _create_tensor(self, l1: int, l2: int) -> Tensor:
        name_list = ["Left", "Right", "Up", "Down"]
        if l1 == 0:
            name_list.remove("Up")
        if l2 == 0:
            name_list.remove("Left")
        if l1 == self.L1 - 1:
            name_list.remove("Down")
        if l2 == self.L2 - 1:
            name_list.remove("Right")
        dimension_list = [2, *[self.D for _ in name_list]]
        name_list = ["Phy", *name_list]
        result = Tensor(name_list, dimension_list)
        result.block()[:] = np.random.rand(*dimension_list)
        return result

    def _initialize_spin(self) -> None:
        for l1 in range(self.L1):
            for l2 in range(self.L2):
                self.spin[l1][l2] = (l1 + l2) % 2

    @staticmethod
    def _two_line_to_one_line(udlr_name: List[str], line_1: List[Tensor],
                              line_2: List[Tensor], cut: int) -> List[Tensor]:
        [up, down, left, right] = udlr_name
        up1 = up + "1"
        up2 = up + "2"
        down1 = down + "1"
        down2 = down + "2"
        left1 = left + "1"
        left2 = left + "2"
        right1 = right + "1"
        right2 = right + "2"

        length = len(line_1)
        if len(line_1) != len(line_2):
            raise Exception("Different Length in Two Line to One Line")
        double_line = []
        for i in range(length):
            double_line.append(line_1[i].edge_rename({
                left: left1,
                right: right1
            }).contract(line_2[i].edge_rename({
                left: left2,
                right: right2
            }), {(down, up)}))

        for i in range(length - 1):
            "虽然实际上是range(length - 2), 但是多计算一个以免角标merge的麻烦"
            [u, s, v] = double_line[i].svd({right1, right2}, left, right)
            double_line[i] = v
            double_line[i + 1] = double_line[i + 1].contract(
                u, {(left1, right1), (left2, right2)}).multiple(s, left, 'u')

        for i in reversed(range(length - 1)):
            [u, s, v] = double_line[i].edge_rename({up: up1, down: down1}) \
                .contract(double_line[i + 1].edge_rename({up: up2, down: down2}), {(right, left)}) \
                .svd({left, up1, down1}, right, left, cut)
            double_line[i + 1] = v.edge_rename({up2: up, down2: down})
            double_line[i] = u.multiple(s, right, 'u').edge_rename({
                up1: up,
                down1: down
            })

        return double_line

    def _get_auxiliaries(self, kind: str, l1: int, l2: int,
                         cut: int) -> Tensor:
        if (kind, l1, l2) not in self._auxiliaries:
            if kind == "up-to-down":
                if l1 == -1:
                    for j in range(self.L2):
                        self._auxiliaries[kind, l1, j] = Tensor(1)
                elif -1 < l1 < self.L1:
                    line_1 = [
                        self._get_auxiliaries(kind, l1 - 1, j, cut)
                        for j in range(self.L2)
                    ]
                    line_2 = [
                        self._get_lattice_spin(l1, j) for j in range(self.L2)
                    ]
                    result = self._two_line_to_one_line(
                        ["Up", "Down", "Left", "Right"], line_1, line_2, cut)
                    for j in range(self.L2):
                        self._auxiliaries[kind, l1, j] = result[j]
                else:
                    raise Exception("Wrong Auxiliaries Position")
            elif kind == "down-to-up":
                if l1 == self.L1:
                    for j in range(self.L2):
                        self._auxiliaries[kind, l1, j] = Tensor(1)
                elif -1 < l1 < self.L1:
                    line_1 = [
                        self._get_auxiliaries(kind, l1 + 1, j, cut)
                        for j in range(self.L2)
                    ]
                    line_2 = [
                        self._get_lattice_spin(l1, j) for j in range(self.L2)
                    ]
                    result = self._two_line_to_one_line(
                        ["Down", "Up", "Left", "Right"], line_1, line_2, cut)
                    for j in range(self.L2):
                        self._auxiliaries[kind, l1, j] = result[j]
                else:
                    raise Exception("Wrong Auxiliaries Position")
            elif kind == "left-to-right":
                if l2 == -1:
                    for i in range(self.L1):
                        self._auxiliaries[kind, i, l2] = Tensor(1)
                elif -1 < l2 < self.L2:
                    line_1 = [
                        self._get_auxiliaries(kind, i, l2 - 1, cut)
                        for i in range(self.L1)
                    ]
                    line_2 = [
                        self._get_lattice_spin(i, l2) for i in range(self.L1)
                    ]
                    result = self._two_line_to_one_line(
                        ["Left", "Right", "Up", "Down"], line_1, line_2, cut)
                    for i in range(self.L1):
                        self._auxiliaries[kind, i, l2] = result[i]
                else:
                    raise Exception("Wrong Auxiliaries Position")
            elif kind == "right-to-left":
                if l2 == self.L2:
                    for i in range(self.L1):
                        self._auxiliaries[kind, i, l2] = Tensor(1)
                elif -1 < l2 < self.L2:
                    line_1 = [
                        self._get_auxiliaries(kind, i, l2 + 1, cut)
                        for i in range(self.L1)
                    ]
                    line_2 = [
                        self._get_lattice_spin(i, l2) for i in range(self.L1)
                    ]
                    result = self._two_line_to_one_line(
                        ["Right", "Left", "Up", "Down"], line_1, line_2, cut)
                    for i in range(self.L1):
                        self._auxiliaries[kind, i, l2] = result[i]
                else:
                    raise Exception("Wrong Auxiliaries Position")
            elif kind == "up-to-down-3":
                if l1 == -1:
                    self._auxiliaries[kind, l1, l2] = Tensor(1)
                elif -1 < l1 < self.L1:
                    """
                    D1 D2 D3
                    |  |  |
                    """
                    self._auxiliaries[kind, l1, l2] = self._get_auxiliaries(kind, l1 - 1, l2, cut) \
                        .contract(self._get_auxiliaries("left-to-right", l1, l2 - 1, cut), {("Down1", "Up")}).edge_rename({"Down": "Down1"}) \
                        .contract(self._get_lattice_spin(l1, l2), {("Down2", "Up"), ("Right", "Left")}).edge_rename({"Down": "Down2"}) \
                        .contract(self._get_auxiliaries("right-to-left", l1, l2 + 1, cut), {("Down3", "Up"), ("Right", "Left")}).edge_rename({"Down": "Down3"})
                else:
                    raise Exception(
                        "Wrong Auxiliaries Position In Three Line Type")
            elif kind == "down-to-up-3":
                if l1 == self.L1:
                    self._auxiliaries[kind, l1, l2] = Tensor(1)
                elif -1 < l1 < self.L1:
                    """
                    |  |  |
                    U1 U2 U3
                    """
                    self._auxiliaries[kind, l1, l2] = self._get_auxiliaries(kind, l1 + 1, l2, cut) \
                        .contract(self._get_auxiliaries("left-to-right", l1, l2 - 1, cut), {("Up1", "Down")}).edge_rename({"Up": "Up1"}) \
                        .contract(self._get_lattice_spin(l1, l2), {("Up2", "Down"), ("Right", "Left")}).edge_rename({"Up": "Up2"}) \
                        .contract(self._get_auxiliaries("right-to-left", l1, l2 + 1, cut), {("Up3", "Down"), ("Right", "Left")}).edge_rename({"Up": "Up3"})
                else:
                    raise Exception(
                        "Wrong Auxiliaries Position In Three Line Type")
            elif kind == "left-to-right-3":
                if l2 == -1:
                    self._auxiliaries[kind, l1, l2] = Tensor(1)
                elif -1 < l2 < self.L2:
                    """
                    R1 -
                    R2 -
                    R3 -
                    """
                    self._auxiliaries[kind, l1, l2] = self._get_auxiliaries(kind, l1, l2 - 1, cut) \
                        .contract(self._get_auxiliaries("up-to-down", l1 - 1, l2, cut), {("Right1", "Left")}).edge_rename({"Right": "Right1"}) \
                        .contract(self._get_lattice_spin(l1, l2), {("Right2", "Left"), ("Down", "Up")}).edge_rename({"Right": "Right2"}) \
                        .contract(self._get_auxiliaries("down-to-up", l1 + 1, l2, cut), {("Right3", "Left"), ("Down", "Up")}).edge_rename({"Right": "Right3"})
                else:
                    raise Exception(
                        "Wrong Auxiliaries Position In Three Line Type")
            elif kind == "right-to-left-3":
                if l2 == self.L2:
                    self._auxiliaries[kind, l1, l2] = Tensor(1)
                elif -1 < l2 < self.L2:
                    """
                    - L1
                    - L2
                    - L3
                    """
                    self._auxiliaries[kind, l1, l2] = self._get_auxiliaries(kind, l1, l2 + 1, cut) \
                        .contract(self._get_auxiliaries("up-to-down", l1 - 1, l2, cut), {("Left1", "Right")}).edge_rename({"Left": "Left1"}) \
                        .contract(self._get_lattice_spin(l1, l2), {("Left2", "Right"), ("Down", "Up")}).edge_rename({"Left": "Left2"}) \
                        .contract(self._get_auxiliaries("down-to-up", l1 + 1, l2, cut), {("Left3", "Right"), ("Down", "Up")}).edge_rename({"Left": "Left3"})
                else:
                    raise Exception(
                        "Wrong Auxiliaries Position In Three Line Type")
            else:
                raise Exception("Wrong Auxiliaries Kind")
        return self._auxiliaries[kind, l1, l2]

    def _try_to_delete_auxiliaries(self, index: str, i: int, j: int) -> bool:
        if (index, i, j) in self._auxiliaries:
            del self._auxiliaries[index, i, j]
            return True
        else:
            return False

    def _refresh_auxiliaries(self, l1: int, l2: int) -> None:
        self._lattice_spin[l1][l2] = None
        self._refresh_line("right", l2)
        self._refresh_line("left", l2)
        self._refresh_line("down", l1)
        self._refresh_line("up", l1)
        for i in range(self.L1):
            if i < l1:
                self._try_to_delete_auxiliaries("down-to-up-3", i, l2)
            elif i > l1:
                self._try_to_delete_auxiliaries("up-to-down-3", i, l2)
            else:
                self._try_to_delete_auxiliaries("down-to-up-3", i, l2)
                self._try_to_delete_auxiliaries("up-to-down-3", i, l2)
        for j in range(self.L2):
            if j < l2:
                self._try_to_delete_auxiliaries("right-to-left-3", l1, j)
            elif j > l2:
                self._try_to_delete_auxiliaries("left-to-right-3", l1, j)
            else:
                self._try_to_delete_auxiliaries("right-to-left-3", l1, j)
                self._try_to_delete_auxiliaries("left-to-right-3", l1, j)

    def _refresh_line(self, kind: str, index: int) -> None:
        if kind == "right":
            if index != self.L2:
                flag = False
                for i in range(self.L1):
                    flag = self._try_to_delete_auxiliaries(
                        "left-to-right", i, index)
                    self._try_to_delete_auxiliaries("up-to-down-3", i,
                                                    index + 1)
                    self._try_to_delete_auxiliaries("down-to-up-3", i,
                                                    index + 1)
                if flag:
                    self._refresh_line(kind, index + 1)
        elif kind == "left":
            if index != -1:
                flag = False
                for i in range(self.L1):
                    flag = self._try_to_delete_auxiliaries(
                        "right-to-left", i, index)
                    self._try_to_delete_auxiliaries("up-to-down-3", i,
                                                    index - 1)
                    self._try_to_delete_auxiliaries("down-to-up-3", i,
                                                    index - 1)
                if flag:
                    self._refresh_line(kind, index - 1)
        elif kind == "down":
            if index != self.L1:
                flag = False
                for j in range(self.L2):
                    flag = self._try_to_delete_auxiliaries(
                        "up-to-down", index, j)
                    self._try_to_delete_auxiliaries("left-to-right-3",
                                                    index + 1, j)
                    self._try_to_delete_auxiliaries("right-to-left-3",
                                                    index + 1, j)
                if flag:
                    self._refresh_line(kind, index + 1)
        elif kind == "up":
            if index != -1:
                flag = False
                for j in range(self.L2):
                    flag = self._try_to_delete_auxiliaries(
                        "down-to-up", index, j)
                    self._try_to_delete_auxiliaries("left-to-right-3",
                                                    index - 1, j)
                    self._try_to_delete_auxiliaries("right-to-left-3",
                                                    index - 1, j)
                if flag:
                    self._refresh_line(kind, index + 1)
        else:
            raise Exception("Wrong Type in Refresh Line")

    def __init__(self, L1: int = 4, L2: int = 4, D: int = 4):
        self.L1: int = L1
        self.L2: int = L2
        self.D: int = D

        self.lattice: List[List[Tensor]] = [[
            self._create_tensor(l1, l2) for l2 in range(self.L2)
        ] for l1 in range(self.L1)]

        self.spin: List[List[int]] = [[0 for _ in range(self.L2)]
                                      for _ in range(self.L1)]
        self._initialize_spin()

        self._lattice_spin: List[List[Optional[Tensor]]] = [
            [None for _ in range(self.L2)] for _ in range(self.L1)
        ]

        self._auxiliaries: Dict[Tuple[str, int, int], Tensor] = {}

        self.environment: Dict[Tuple[str, int, int], Singular] = {}

    def _absorb_environment(self,
                            *,
                            remove: bool = True,
                            division: bool = False) -> None:
        self.refresh_all_auxiliaries()
        for direction in ["Right", "Down"]:
            for l1 in range(self.L1):
                for l2 in range(self.L2):
                    if (direction, l1, l2) in self.environment:
                        self.lattice[l1][l2].multiple(
                            self.environment[direction, l1, l2], direction,
                            "u", division)
                        if remove:
                            del self.environment[direction, l1, l2]

    def _single_term_simple_update(self, updater: Tensor, direction: str,
                                   l1: int, l2: int) -> None:
        if direction == "Right":
            """
             22
            1LR1
             33
            """
            left = self.lattice[l1][l2]
            if ("Right", l1, l2 - 1) in self.environment:
                left.multiple(self.environment["Right", l1, l2 - 1], "Left",
                              "v")
            if ("Down", l1 - 1, l2) in self.environment:
                left.multiple(self.environment["Down", l1 - 1, l2], "Up", "v")
            if ("Down", l1, l2) in self.environment:
                left.multiple(self.environment["Down", l1, l2], "Down", "u")
            if ("Right", l1, l2) in self.environment:
                left.multiple(self.environment["Right", l1, l2], "Right", "u")
            right = self.lattice[l1][l2 + 1]
            if ("Right", l1, l2 + 1) in self.environment:
                right.multiple(self.environment["Right", l1, l2 + 1], "Right",
                               "u")
            if ("Down", l1 - 1, l2 + 1) in self.environment:
                right.multiple(self.environment["Down", l1 - 1, l2 + 1], "Up",
                               "v")
            if ("Down", l1, l2 + 1) in self.environment:
                right.multiple(self.environment["Down", l1, l2 + 1], "Down",
                               "u")
            u: Tensor
            s: Singular
            v: Tensor
            u, s, v = left.edge_rename({"Up": "Up1", "Down": "Down1", "Phy": "Phy0"}) \
                .contract(right.edge_rename({"Up": "Up2", "Down": "Down2", "Phy": "Phy1"}), {("Right", "Left")}) \
                .contract(updater, {("Phy0", "I0"), ("Phy1", "I1")}) \
                .svd({"Left", "Up1", "Down1", "O0"}, "Right", "Left", self.D)
            u /= u.norm_max()
            v /= v.norm_max()
            s /= s.norm_max()
            self.environment["Right", l1, l2] = s
            self.lattice[l1][l2] = u.edge_rename({
                "Up1": "Up",
                "Down1": "Down",
                "O0": "Phy"
            })
            if ("Right", l1, l2 - 1) in self.environment:
                self.lattice[l1][l2].multiple(
                    self.environment["Right", l1, l2 - 1], "Left", "v", True)
            if ("Down", l1 - 1, l2) in self.environment:
                self.lattice[l1][l2].multiple(
                    self.environment["Down", l1 - 1, l2], "Up", "v", True)
            if ("Down", l1, l2) in self.environment:
                self.lattice[l1][l2].multiple(self.environment["Down", l1, l2],
                                              "Down", "u", True)
            self.lattice[l1][l2 + 1] = v.edge_rename({
                "Up2": "Up",
                "Down2": "Down",
                "O1": "Phy"
            })
            if ("Right", l1, l2 + 1) in self.environment:
                self.lattice[l1][l2 + 1].multiple(
                    self.environment["Right", l1, l2 + 1], "Right", "u", True)
            if ("Down", l1 - 1, l2 + 1) in self.environment:
                self.lattice[l1][l2 + 1].multiple(
                    self.environment["Down", l1 - 1, l2 + 1], "Up", "v", True)
            if ("Down", l1, l2 + 1) in self.environment:
                self.lattice[l1][l2 + 1].multiple(
                    self.environment["Down", l1, l2 + 1], "Down", "u", True)
        elif direction == "Down":
            """
             1
            2U3
            2D3
             1
            """
            up = self.lattice[l1][l2]
            if ("Down", l1 - 1, l2) in self.environment:
                up.multiple(self.environment["Down", l1 - 1, l2], "Up", "v")
            if ("Right", l1, l2 - 1) in self.environment:
                up.multiple(self.environment["Right", l1, l2 - 1], "Left", "v")
            if ("Right", l1, l2) in self.environment:
                up.multiple(self.environment["Right", l1, l2], "Right", "u")
            if ("Down", l1, l2) in self.environment:
                up.multiple(self.environment["Down", l1, l2], "Down", "u")
            down = self.lattice[l1 + 1][l2]
            if ("Down", l1 + 1, l2) in self.environment:
                down.multiple(self.environment["Down", l1 + 1, l2], "Down",
                              "u")
            if ("Right", l1 + 1, l2 - 1) in self.environment:
                down.multiple(self.environment["Right", l1 + 1, l2 - 1],
                              "Left", "v")
            if ("Right", l1 + 1, l2) in self.environment:
                down.multiple(self.environment["Right", l1 + 1, l2], "Right",
                              "u")
            u: Tensor
            s: Singular
            v: Tensor
            u, s, v = up.edge_rename({"Left": "Left1", "Right": "Right1", "Phy": "Phy0"}) \
                .contract(down.edge_rename({"Left": "Left2", "Right": "Right2", "Phy": "Phy1"}), {("Down", "Up")}) \
                .contract(updater, {("Phy0", "I0"), ("Phy1", "I1")}) \
                .svd({"Up", "Left1", "Right1", "O0"}, "Down", "Up", self.D)
            u /= u.norm_max()
            v /= v.norm_max()
            s /= s.norm_max()
            self.environment["Down", l1, l2] = s
            self.lattice[l1][l2] = u.edge_rename({
                "Left1": "Left",
                "Right1": "Right",
                "O0": "Phy"
            })
            if ("Down", l1 - 1, l2) in self.environment:
                self.lattice[l1][l2].multiple(
                    self.environment["Down", l1 - 1, l2], "Up", "v", True)
            if ("Right", l1, l2 - 1) in self.environment:
                self.lattice[l1][l2].multiple(
                    self.environment["Right", l1, l2 - 1], "Left", "v", True)
            if ("Right", l1, l2) in self.environment:
                self.lattice[l1][l2].multiple(
                    self.environment["Right", l1, l2], "Right", "u", True)
            self.lattice[l1 + 1][l2] = v.edge_rename({
                "Left2": "Left",
                "Right2": "Right",
                "O1": "Phy"
            })
            if ("Down", l1 + 1, l2) in self.environment:
                self.lattice[l1 + 1][l2].multiple(
                    self.environment["Down", l1 + 1, l2], "Down", "u", True)
            if ("Right", l1 + 1, l2 - 1) in self.environment:
                self.lattice[l1 + 1][l2].multiple(
                    self.environment["Right", l1 + 1, l2 - 1], "Left", "v",
                    True)
            if ("Right", l1 + 1, l2) in self.environment:
                self.lattice[l1 + 1][l2].multiple(
                    self.environment["Right", l1 + 1, l2], "Right", "u", True)
        else:
            raise Exception("Wrong direction in Simple Update")

    def _single_simple_update(self, updater: Tensor) -> None:
        # LR
        for l1 in range(self.L1):
            for l2 in range(self.L2 - 1):
                self._single_term_simple_update(updater, "Right", l1, l2)
        # UD
        for l2 in range(self.L2):
            for l1 in range(self.L1 - 1):
                self._single_term_simple_update(updater, "Down", l1, l2)
        # DU
        for l2 in reversed(range(self.L2)):
            for l1 in reversed(range(self.L1 - 1)):
                self._single_term_simple_update(updater, "Down", l1, l2)
        # RL
        for l1 in reversed(range(self.L1)):
            for l2 in reversed(range(self.L2 - 1)):
                self._single_term_simple_update(updater, "Right", l1, l2)

    def simple_update(self,
                      time: int,
                      delta_t: float,
                      *,
                      new_D: Optional[int] = None):
        if new_D is not None:
            self.D = new_D
        updater = self.identity - delta_t * self.hamiltonian - delta_t * delta_t * self.hamiltonian_square / 2
        for step in range(time):
            self._single_simple_update(updater)
            print(step)
        return self

    def _get_lattice_spin(self, l1: int, l2: int, index: int = -1) -> Tensor:
        if index == -1:
            if not self._lattice_spin[l1][l2]:
                self._lattice_spin[l1][l2] = self.lattice[l1][l2].contract(
                    self.raw_base[self.spin[l1][l2]], {("Phy", "Phy")})
            return self._lattice_spin[l1][l2]
        else:
            return self.lattice[l1][l2].contract(self.raw_base[index],
                                                 {("Phy", "Phy")})

    def save(self, file_name: str):
        with open(file_name, "wb") as file:
            pickle.dump(self, file)

    def gradient_descent(self,
                         time: int,
                         markov_chain_length: int,
                         cut: int,
                         *,
                         log: Optional[str] = None,
                         energy_only: bool = False):
        if log:
            file = open(log, "a")
        if energy_only:
            self._absorb_environment(remove=False, division=False)
        else:
            self._absorb_environment(remove=True, division=False)
        # AdaDelta
        gradient_s = [[j.same_shape().zero() for j in i] for i in self.lattice]
        gradient_delta = [[j.same_shape().zero() for j in i]
                          for i in self.lattice]
        rho = 0.9
        eps = 1e5
        # AdaDelta
        for step in range(time):
            energy, gradient = self._markov_chain(markov_chain_length, cut,
                                                  energy_only)
            if not energy_only:
                for l1 in range(self.L1):
                    for l2 in range(self.L2):
                        # AdaDelta
                        gradient_s[l1][l2] = rho * gradient_s[l1][l2] + (
                            1 - rho) * gradient[l1][l2] * gradient[l1][l2]
                        g = ((gradient_delta[l1][l2] + eps) /
                             (gradient_s[l1][l2] +
                              eps)).sqrt() * gradient[l1][l2]
                        self.lattice[l1][l2] -= g
                        gradient_delta[l1][l2] = rho * gradient_delta[l1][
                            l2] + (1 - rho) * g * g
                        # AdaDelta
                self.refresh_all_auxiliaries()
            if log:
                print(energy / (self.L1 * self.L2), file=file)
            print(step, energy / (self.L1 * self.L2))
        if energy_only:
            self._absorb_environment(remove=False, division=True)
        if log:
            file.close()
        return self

    def refresh_all_auxiliaries(self) -> None:
        for l1 in range(self.L1):
            for l2 in range(self.L2):
                self._refresh_auxiliaries(l1, l2)

    def _markov_chain(self, markov_chain_length: int, cut: int,
                      energy_only: bool) -> Tuple[float, List[List[Tensor]]]:
        summation_of_spin_energy = 0.
        summation_of_spin_gradient = [[j.same_shape().zero() for j in i]
                                      for i in self.lattice]
        summation_of_product = [[j.same_shape().zero() for j in i]
                                for i in self.lattice]

        for _ in range(markov_chain_length):
            energy, gradient = self._single_markov_chain(cut, energy_only)
            summation_of_spin_energy += energy
            if not energy_only:
                for l1 in range(self.L1):
                    for l2 in range(self.L2):
                        this_gradient = gradient[l1][l2].contract(
                            self.raw_base[self.spin[l1][l2]], set())
                        summation_of_spin_gradient[l1][l2] += this_gradient
                        summation_of_product[l1][l2] += this_gradient * energy

        energy = summation_of_spin_energy / markov_chain_length
        if energy_only:
            return energy, [[]]
        else:
            return energy, \
                   [[2 * summation_of_product[l1][l2] / markov_chain_length - 2 * energy * summation_of_spin_gradient[l1][l2] / markov_chain_length \
                     for l2 in range(self.L2)] for l1 in range(self.L1)]

    def _get_wss(self, point1: Tuple[int, int], point2: Tuple[int, int],
                 cut: int, new_index) -> float:
        p1l1, p1l2 = point1
        p2l1, p2l2 = point2
        if p1l1 == p2l1:
            if p2l2 != p1l2 + 1:
                raise Exception("Hopping Style Not Implement")
            wss = self._get_auxiliaries("left-to-right-3", p1l1, p1l2 - 1, cut) \
                .contract(self._get_auxiliaries("up-to-down", p1l1 - 1, p1l2, cut), {("Right1", "Left")}).edge_rename({"Right": "Right1"}) \
                .contract(self._get_lattice_spin(p1l1, p1l2, new_index[0]), {("Right2", "Left"), ("Down", "Up")}).edge_rename({"Right": "Right2"}) \
                .contract(self._get_auxiliaries("down-to-up", p1l1 + 1, p1l2, cut), {("Right3", "Left"), ("Down", "Up")}).edge_rename({"Right": "Right3"}) \
                .contract(self._get_auxiliaries("up-to-down", p2l1 - 1, p2l2, cut), {("Right1", "Left")}).edge_rename({"Right": "Right1"}) \
                .contract(self._get_lattice_spin(p2l1, p2l2, new_index[1]), {("Right2", "Left"), ("Down", "Up")}).edge_rename({"Right": "Right2"}) \
                .contract(self._get_auxiliaries("down-to-up", p2l1 + 1, p2l2, cut), {("Right3", "Left"), ("Down", "Up")}).edge_rename({"Right": "Right3"}) \
                .contract(self._get_auxiliaries("right-to-left-3", p2l1, p2l2 + 1, cut), {("Right1", "Left1"), ("Right2", "Left2"), ("Right3", "Left3")}).value()
            return wss
        else:
            if p1l2 != p2l2 or p1l1 + 1 != p2l1:
                raise Exception("Hopping Style Not Implement")
            wss = self._get_auxiliaries("up-to-down-3", p1l1 - 1, p1l2, cut) \
                .contract(self._get_auxiliaries("left-to-right", p1l1, p1l2 - 1, cut), {("Down1", "Up")}).edge_rename({"Down": "Down1"}) \
                .contract(self._get_lattice_spin(p1l1, p1l2, new_index[0]), {("Down2", "Up"), ("Right", "Left")}).edge_rename({"Down": "Down2"}) \
                .contract(self._get_auxiliaries("right-to-left", p1l1, p1l2 + 1, cut), {("Down3", "Up"), ("Right", "Left")}).edge_rename({"Down": "Down3"}) \
                .contract(self._get_auxiliaries("left-to-right", p2l1, p2l2 - 1, cut), {("Down1", "Up")}).edge_rename({"Down": "Down1"}) \
                .contract(self._get_lattice_spin(p2l1, p2l2, new_index[1]), {("Down2", "Up"), ("Right", "Left")}).edge_rename({"Down": "Down2"}) \
                .contract(self._get_auxiliaries("right-to-left", p2l1, p2l2 + 1, cut), {("Down3", "Up"), ("Right", "Left")}).edge_rename({"Down": "Down3"}) \
                .contract(self._get_auxiliaries("down-to-up-3", p2l1 + 1, p2l2, cut), {("Down1", "Up1"), ("Down2", "Up2"), ("Down3", "Up3")}).value()
            return wss

    def _try_hop(self,
                 point1: Tuple[int, int],
                 point2: Tuple[int, int],
                 cut: int,
                 ws: Optional[float] = None) -> float:
        p1l1, p1l2 = point1
        p2l1, p2l2 = point2
        if p1l1 == p2l1:
            """
            X X X X
            X 1 2 X
            X X X X
            """
            if p2l2 != p1l2 + 1:
                raise Exception("Hopping Style Not Implement")
            if ws is None:
                ws = self._get_auxiliaries("left-to-right-3", p1l1, p1l2, cut) \
                    .contract(self._get_auxiliaries("right-to-left-3", p2l1, p2l2, cut),
                              {("Right1", "Left1"), ("Right2", "Left2"), ("Right3", "Left3")}).value()
            new_index = np.random.randint(2, size=[2])
            wss = self._get_wss(point1, point2, cut, new_index)
            if wss**2 / ws**2 > np.random.rand():
                if self.spin[p1l1][p1l2] != new_index[0]:
                    self.spin[p1l1][p1l2] = new_index[0]
                    self._refresh_auxiliaries(p1l1, p1l2)
                if self.spin[p2l1][p2l2] != new_index[1]:
                    self.spin[p2l1][p2l2] = new_index[1]
                    self._refresh_auxiliaries(p2l1, p2l2)
                return wss
            else:
                return ws
        else:
            """
            X X X
            X 1 X
            X 2 X
            X X X
            """
            if p1l2 != p2l2 or p1l1 + 1 != p2l1:
                raise Exception("Hopping Style Not Implement")
            if ws is None:
                ws = self._get_auxiliaries("up-to-down-3", p1l1, p1l2, cut) \
                    .contract(self._get_auxiliaries("down-to-up-3", p2l1, p2l2, cut),
                              {("Down1", "Up1"), ("Down2", "Up2"), ("Down3", "Up3")}).value()
            new_index = np.random.randint(2, size=[2])
            wss = self._get_wss(point1, point2, cut, new_index)
            if wss**2 / ws**2 > np.random.rand():
                if self.spin[p1l1][p1l2] != new_index[0]:
                    self.spin[p1l1][p1l2] = new_index[0]
                    self._refresh_auxiliaries(p1l1, p1l2)
                if self.spin[p2l1][p2l2] != new_index[1]:
                    self.spin[p2l1][p2l2] = new_index[1]
                    self._refresh_auxiliaries(p2l1, p2l2)
                return wss
            else:
                return ws

    def _single_markov_chain(
            self, cut: int,
            energy_only: bool) -> Tuple[float, List[List[Tensor]]]:
        ws: Optional[float] = None
        # LR
        for l1 in range(self.L1):
            for l2 in range(self.L2 - 1):
                ws = self._try_hop((l1, l2), (l1, l2 + 1), cut, ws)
        # UD
        for l2 in range(self.L2):
            for l1 in range(self.L1 - 1):
                ws = self._try_hop((l1, l2), (l1 + 1, l2), cut, ws)
        # DU
        for l2 in reversed(range(self.L2)):
            for l1 in reversed(range(self.L1 - 1)):
                ws = self._try_hop((l1, l2), (l1 + 1, l2), cut, ws)
        # RL
        for l1 in reversed(range(self.L1)):
            for l2 in reversed(range(self.L2 - 1)):
                ws = self._try_hop((l1, l2), (l1, l2 + 1), cut, ws)
        # collect data
        """
         1  0  0  0
         0 -1  2  0
         0  2 -1  0
         0  0  0  1
        /4
        """
        energy = 0.
        for l1 in range(self.L1):
            for l2 in range(self.L2 - 1):
                if self.spin[l1][l2] == self.spin[l1][l2 + 1]:
                    energy += ws / 4
                else:
                    energy -= ws / 4
                    wss = self._get_wss(
                        (l1, l2), (l1, l2 + 1), cut,
                        [self.spin[l1][l2 + 1], self.spin[l1][l2]])
                    energy += wss * 2 / 4
        for l2 in range(self.L2):
            for l1 in range(self.L1 - 1):
                if self.spin[l1][l2] == self.spin[l1 + 1][l2]:
                    energy += ws / 4
                else:
                    energy -= ws / 4
                    wss = self._get_wss(
                        (l1, l2), (l1 + 1, l2), cut,
                        [self.spin[l1 + 1][l2], self.spin[l1][l2]])
                    energy += wss * 2 / 4
        energy /= ws
        if energy_only:
            return energy, [[]]
        else:
            gradient = [[
                self._get_auxiliaries("up-to-down-3", l1 - 1, l2, cut) \
                    .contract(self._get_auxiliaries("left-to-right", l1, l2 - 1, cut), {("Down1", "Up")}) \
                    .contract(self._get_auxiliaries("down-to-up-3", l1 + 1, l2, cut), {("Down", "Up1")}) \
                    .contract(self._get_auxiliaries("right-to-left", l1, l2 + 1, cut), {("Down3", "Up"), ("Up3", "Down")}) \
                    .edge_rename({"Down2": "Up", "Up2": "Down", "Left": "Right", "Right": "Left"}) / ws
                for l2 in range(self.L2)] for l1 in range(self.L1)]
            return energy, gradient

    def end(self):
        pass

    @staticmethod
    def load(file_name: str):
        with open(file_name, "rb") as file:
            return pickle.load(file)
Example #5
0
 def _get_auxiliaries(self, kind: str, l1: int, l2: int,
                      cut: int) -> Tensor:
     if (kind, l1, l2) not in self._auxiliaries:
         if kind == "up-to-down":
             if l1 == -1:
                 for j in range(self.L2):
                     self._auxiliaries[kind, l1, j] = Tensor(1)
             elif -1 < l1 < self.L1:
                 line_1 = [
                     self._get_auxiliaries(kind, l1 - 1, j, cut)
                     for j in range(self.L2)
                 ]
                 line_2 = [
                     self._get_lattice_spin(l1, j) for j in range(self.L2)
                 ]
                 result = self._two_line_to_one_line(
                     ["Up", "Down", "Left", "Right"], line_1, line_2, cut)
                 for j in range(self.L2):
                     self._auxiliaries[kind, l1, j] = result[j]
             else:
                 raise Exception("Wrong Auxiliaries Position")
         elif kind == "down-to-up":
             if l1 == self.L1:
                 for j in range(self.L2):
                     self._auxiliaries[kind, l1, j] = Tensor(1)
             elif -1 < l1 < self.L1:
                 line_1 = [
                     self._get_auxiliaries(kind, l1 + 1, j, cut)
                     for j in range(self.L2)
                 ]
                 line_2 = [
                     self._get_lattice_spin(l1, j) for j in range(self.L2)
                 ]
                 result = self._two_line_to_one_line(
                     ["Down", "Up", "Left", "Right"], line_1, line_2, cut)
                 for j in range(self.L2):
                     self._auxiliaries[kind, l1, j] = result[j]
             else:
                 raise Exception("Wrong Auxiliaries Position")
         elif kind == "left-to-right":
             if l2 == -1:
                 for i in range(self.L1):
                     self._auxiliaries[kind, i, l2] = Tensor(1)
             elif -1 < l2 < self.L2:
                 line_1 = [
                     self._get_auxiliaries(kind, i, l2 - 1, cut)
                     for i in range(self.L1)
                 ]
                 line_2 = [
                     self._get_lattice_spin(i, l2) for i in range(self.L1)
                 ]
                 result = self._two_line_to_one_line(
                     ["Left", "Right", "Up", "Down"], line_1, line_2, cut)
                 for i in range(self.L1):
                     self._auxiliaries[kind, i, l2] = result[i]
             else:
                 raise Exception("Wrong Auxiliaries Position")
         elif kind == "right-to-left":
             if l2 == self.L2:
                 for i in range(self.L1):
                     self._auxiliaries[kind, i, l2] = Tensor(1)
             elif -1 < l2 < self.L2:
                 line_1 = [
                     self._get_auxiliaries(kind, i, l2 + 1, cut)
                     for i in range(self.L1)
                 ]
                 line_2 = [
                     self._get_lattice_spin(i, l2) for i in range(self.L1)
                 ]
                 result = self._two_line_to_one_line(
                     ["Right", "Left", "Up", "Down"], line_1, line_2, cut)
                 for i in range(self.L1):
                     self._auxiliaries[kind, i, l2] = result[i]
             else:
                 raise Exception("Wrong Auxiliaries Position")
         elif kind == "up-to-down-3":
             if l1 == -1:
                 self._auxiliaries[kind, l1, l2] = Tensor(1)
             elif -1 < l1 < self.L1:
                 """
                 D1 D2 D3
                 |  |  |
                 """
                 self._auxiliaries[kind, l1, l2] = self._get_auxiliaries(kind, l1 - 1, l2, cut) \
                     .contract(self._get_auxiliaries("left-to-right", l1, l2 - 1, cut), {("Down1", "Up")}).edge_rename({"Down": "Down1"}) \
                     .contract(self._get_lattice_spin(l1, l2), {("Down2", "Up"), ("Right", "Left")}).edge_rename({"Down": "Down2"}) \
                     .contract(self._get_auxiliaries("right-to-left", l1, l2 + 1, cut), {("Down3", "Up"), ("Right", "Left")}).edge_rename({"Down": "Down3"})
             else:
                 raise Exception(
                     "Wrong Auxiliaries Position In Three Line Type")
         elif kind == "down-to-up-3":
             if l1 == self.L1:
                 self._auxiliaries[kind, l1, l2] = Tensor(1)
             elif -1 < l1 < self.L1:
                 """
                 |  |  |
                 U1 U2 U3
                 """
                 self._auxiliaries[kind, l1, l2] = self._get_auxiliaries(kind, l1 + 1, l2, cut) \
                     .contract(self._get_auxiliaries("left-to-right", l1, l2 - 1, cut), {("Up1", "Down")}).edge_rename({"Up": "Up1"}) \
                     .contract(self._get_lattice_spin(l1, l2), {("Up2", "Down"), ("Right", "Left")}).edge_rename({"Up": "Up2"}) \
                     .contract(self._get_auxiliaries("right-to-left", l1, l2 + 1, cut), {("Up3", "Down"), ("Right", "Left")}).edge_rename({"Up": "Up3"})
             else:
                 raise Exception(
                     "Wrong Auxiliaries Position In Three Line Type")
         elif kind == "left-to-right-3":
             if l2 == -1:
                 self._auxiliaries[kind, l1, l2] = Tensor(1)
             elif -1 < l2 < self.L2:
                 """
                 R1 -
                 R2 -
                 R3 -
                 """
                 self._auxiliaries[kind, l1, l2] = self._get_auxiliaries(kind, l1, l2 - 1, cut) \
                     .contract(self._get_auxiliaries("up-to-down", l1 - 1, l2, cut), {("Right1", "Left")}).edge_rename({"Right": "Right1"}) \
                     .contract(self._get_lattice_spin(l1, l2), {("Right2", "Left"), ("Down", "Up")}).edge_rename({"Right": "Right2"}) \
                     .contract(self._get_auxiliaries("down-to-up", l1 + 1, l2, cut), {("Right3", "Left"), ("Down", "Up")}).edge_rename({"Right": "Right3"})
             else:
                 raise Exception(
                     "Wrong Auxiliaries Position In Three Line Type")
         elif kind == "right-to-left-3":
             if l2 == self.L2:
                 self._auxiliaries[kind, l1, l2] = Tensor(1)
             elif -1 < l2 < self.L2:
                 """
                 - L1
                 - L2
                 - L3
                 """
                 self._auxiliaries[kind, l1, l2] = self._get_auxiliaries(kind, l1, l2 + 1, cut) \
                     .contract(self._get_auxiliaries("up-to-down", l1 - 1, l2, cut), {("Left1", "Right")}).edge_rename({"Left": "Left1"}) \
                     .contract(self._get_lattice_spin(l1, l2), {("Left2", "Right"), ("Down", "Up")}).edge_rename({"Left": "Left2"}) \
                     .contract(self._get_auxiliaries("down-to-up", l1 + 1, l2, cut), {("Left3", "Right"), ("Down", "Up")}).edge_rename({"Left": "Left3"})
             else:
                 raise Exception(
                     "Wrong Auxiliaries Position In Three Line Type")
         else:
             raise Exception("Wrong Auxiliaries Kind")
     return self._auxiliaries[kind, l1, l2]
Example #6
0
# along with this program.  If not, see <https://www.gnu.org/licenses/>.
#

import numpy as np
from TAT.Tensor import DNo as Tensor

max_random = 8

for _ in range(100):
    rank_A = np.random.randint(2, max_random)
    rank_B = np.random.randint(2, max_random)
    rank_contract = np.random.randint(1, np.min([rank_A, rank_B]))
    # print(rank_A, rank_B, rank_contract)

    contract_name_A = np.random.choice(range(rank_A), rank_contract, False)
    contract_name_B = np.random.choice(range(rank_B), rank_contract, False)

    dim_A = np.random.randint(1, max_random, size=rank_A)
    dim_B = np.random.randint(1, max_random, size=rank_B)
    dim_contract = np.random.randint(1, max_random, size=rank_contract)

    dim_A = [j if i not in contract_name_A else dim_contract[contract_name_A.tolist().index(i)] for i, j in enumerate(dim_A)]
    dim_B = [j if i not in contract_name_B else dim_contract[contract_name_B.tolist().index(i)] for i, j in enumerate(dim_B)]

    A = Tensor([f"A.{i}" for i in range(rank_A)], dim_A).randn()
    B = Tensor([f"B.{i}" for i in range(rank_B)], dim_B).randn()
    v_t = A.contract(B, {(f"A.{i}", f"B.{j}") for i, j in zip(contract_name_A, contract_name_B)}).block[{}]
    v_n = np.tensordot(A.block[{}], B.block[{}], [contract_name_A, contract_name_B])
    v_d = v_t - v_n
    print(np.max(np.abs(v_d)))
Example #7
0
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.
#

import numpy as np
from TAT.Tensor import DNo as Tensor

max_random = 8

for _ in range(1000):
    rank_A = np.random.randint(2, max_random)
    rank_contract = np.random.randint(1, rank_A)
    U_leg = np.random.choice(range(rank_A), rank_contract, False)

    dim_A = np.random.randint(1, max_random, size=rank_A)

    A = Tensor([f"A.{i}" for i in range(rank_A)], dim_A.tolist()).randn()

    U, S, V = A.svd({f"A.{i}" for i in U_leg}, "SVD.U", "SVD.V")
    re_A = U.multiple(S, "SVD.U", "U").contract(V, {("SVD.U", "SVD.V")})
    diff = re_A - A

    UTU = U.contract_all_edge(U.edge_rename({"SVD.U": "new"})).block[{}]
    VTV = V.contract_all_edge(V.edge_rename({"SVD.V": "new"})).block[{}]

    diff_U = UTU - np.identity(len(UTU))
    diff_V = VTV - np.identity(len(VTV))

    print(np.max([diff.norm_max(), np.max(np.abs(diff_U)), np.max(np.abs(diff_V))]))
Example #8
0
for _ in range(1000):
    rank_A = np.random.randint(3, max_random)
    rank_trace = np.random.randint(1, rank_A // 2 + 1)
    pair_leg = np.random.choice(range(rank_A), [rank_trace, 2], False)

    name_list = [f"A.{i}" for i in range(rank_A)]
    dim_list = np.random.randint(2, max_random, rank_A)
    dim_trace = np.random.randint(2, max_random, rank_trace)
    for i, (j, k) in enumerate(pair_leg):
        dim_list[j] = dim_trace[i]
        dim_list[k] = dim_trace[i]

    trace_conf = {(f"A.{i}", f"A.{j}") for i, j in pair_leg}

    A = Tensor(name_list, dim_list.tolist()).test()
    B = A.trace(trace_conf)

    res = A.block[{}]
    for i in range(rank_trace):
        res = res.trace(0, pair_leg[i, 0], pair_leg[i, 1])
        for j in range(i + 1, rank_trace):
            if pair_leg[j, 0] > pair_leg[i, 0]:
                pair_leg[j, 0] -= 1
            if pair_leg[j, 1] > pair_leg[i, 0]:
                pair_leg[j, 1] -= 1
            if pair_leg[i, 1] > pair_leg[i, 0]:
                pair_leg[i, 1] -= 1
            if pair_leg[j, 0] > pair_leg[i, 1]:
                pair_leg[j, 0] -= 1
            if pair_leg[j, 1] > pair_leg[i, 1]: