Exemplo n.º 1
0
def test_ChargeArray_reshape_raises():
    Ds = [8, 9, 10, 11]
    indices = [
        Index(U1Charge.random(dimension=Ds[n], minval=-5, maxval=5), False)
        for n in range(4)
    ]
    arr = ChargeArray.random(indices)

    with pytest.raises(ValueError, match=r"The shape \(2, 4, 9, 2, 5, 11\)"):
        arr.reshape([2, 4, 9, 2, 5, 11])

    with pytest.raises(ValueError, match="A tensor with"):
        arr.reshape([64, 65])

    arr2 = arr.reshape([72, 110])
    with pytest.raises(
            ValueError,
            match=r"The shape \(9, 8, 10, 11\) is incompatible with the"
            r" elementary shape \(8, 9, 10, 11\) of the tensor."):

        arr2.reshape([9, 8, 10, 11])

    Ds = [8, 9, 0, 11]
    indices = [
        Index(U1Charge.random(dimension=Ds[n], minval=-5, maxval=5), False)
        for n in range(4)
    ]
    arr3 = ChargeArray.random(indices)
    with pytest.raises(ValueError):
        arr3.reshape([72, 0])
Exemplo n.º 2
0
def test_tensordot_raises():
    R1 = 3
    R2 = 3
    R3 = 3
    dtype = np.float64
    np.random.seed(10)
    Ds1 = np.arange(2, 2 + R1)
    Ds2 = np.arange(2 + R1, 2 + R1 + R2)
    Ds3 = np.arange(2 + R1, 2 + R1 + R3)
    is1 = [
        Index(U1Charge.random(dimension=Ds1[n], minval=-5, maxval=5), False)
        for n in range(R1)
    ]
    is2 = [
        Index(U1Charge.random(dimension=Ds2[n], minval=-5, maxval=5), False)
        for n in range(R2)
    ]
    is3 = [
        Index(U1Charge.random(dimension=Ds3[n], minval=-5, maxval=5), False)
        for n in range(R3)
    ]
    A = BlockSparseTensor.random(is1, dtype=dtype)
    B = BlockSparseTensor.random(is2, dtype=dtype)
    C = BlockSparseTensor.random(is3, dtype=dtype)
    with pytest.raises(ValueError, match="same length"):
        tensordot(A, B, ([0, 1, 2, 3], [1, 2]))
    with pytest.raises(ValueError, match="same length"):
        tensordot(A, B, ([0, 1], [0, 1, 2, 3]))
    with pytest.raises(ValueError, match="same length"):
        tensordot(A, B, ([0], [1, 2]))
    with pytest.raises(ValueError, match='invalid input'):
        tensordot(A, B, [0, [1, 2]])
    with pytest.raises(ValueError, match="incompatible elementary flows"):
        tensordot(A, B, ([0, 0], [1, 2]))
    with pytest.raises(ValueError):
        tensordot(A, B, ([0, 1], [1, 1]))
    with pytest.raises(ValueError, match="rank of `tensor1` is smaller than "):
        tensordot(A, B, ([0, 4], [1, 2]))
    with pytest.raises(ValueError, match="rank of `tensor2` is smaller than "):
        tensordot(A, B, ([0, 1], [0, 4]))
    with pytest.raises(ValueError):
        tensordot(A, B, ([0, 4], [1, 4]))
    with pytest.raises(ValueError):
        tensordot(A, B, ([0, 1], [0, 1]))
    with pytest.raises(ValueError):
        tensordot(A, A, ([0, 1], [0, 1]))
    with pytest.raises(ValueError):
        tensordot(A, A.conj(), ([0, 1], [1, 0]))
    with pytest.raises(ValueError,
                       match="is incompatible with `tensor1.shape"):
        tensordot(A, A.conj(), ([0, 1, 2, 3], [0, 1, 2, 3]))
    with pytest.raises(ValueError,
                       match="is incompatible with `tensor1.shape"):
        tensordot(A, C, ([0, 1, 2, 3], [0, 1, 2, 3]))
Exemplo n.º 3
0
def test_eigs_raises():
    np.random.seed(10)
    dtype = np.float64
    backend = symmetric_backend.SymmetricBackend()
    D = 16
    index = Index(U1Charge.random(D, 0, 0), True)
    indices = [index, index.copy().flip_flow()]

    H = BlockSparseTensor.random(indices, dtype=dtype)
    init = BlockSparseTensor.random([index], dtype=dtype)

    with pytest.raises(ValueError,
                       match='which = SI is currently not supported.'):
        backend.eigs(lambda x: x, [H], initial_state=init, which='SI')
    with pytest.raises(ValueError,
                       match='which = LI is currently not supported.'):
        backend.eigs(lambda x: x, [H], initial_state=init, which='LI')
    with pytest.raises(
            ValueError,
            match="if no `initial_state` is passed, then `shape` and"
            "`dtype` have to be provided"):
        backend.eigs(lambda x: x, [H])
    with pytest.raises(ValueError, match="`num_krylov_vecs`"):
        backend.eigs(lambda x: x, [H], numeig=3, num_krylov_vecs=3)
    with pytest.raises(TypeError, match="Expected a"):
        backend.eigs(lambda x: x, [H], initial_state=[])
Exemplo n.º 4
0
def test_flat_meta_data():
    i1 = Index([U1Charge.random(-2, 2, 20),
                U1Charge.random(-2, 2, 20)],
               flow=[True, False])

    i2 = Index([U1Charge.random(-2, 2, 20),
                U1Charge.random(-2, 2, 20)],
               flow=[False, True])
    expected_charges = [
        i1._charges[0], i1._charges[1], i2._charges[0], i2._charges[1]
    ]
    expected_flows = [True, False, False, True]
    charges, flows = get_flat_meta_data([i1, i2])
    np.testing.assert_allclose(flows, expected_flows)
    for n, c in enumerate(charges):
        assert charge_equal(c, expected_charges[n])
Exemplo n.º 5
0
def test_tn_reshape(dtype):
    np.random.seed(10)
    Ds = [8, 9, 10, 11]
    indices = [
        Index(U1Charge.random(dimension=Ds[n], minval=-5, maxval=5), False)
        for n in range(4)
    ]
    arr = BlockSparseTensor.random(indices, dtype=dtype)
    arr2 = reshape(arr, [72, 110])
    for n in range(2):
        for m in range(2):
            assert charge_equal(arr2.charges[n][m], indices[n * 2 + m].charges)
    np.testing.assert_allclose(arr2.shape, [72, 110])
    np.testing.assert_allclose(arr2._order, [[0, 1], [2, 3]])
    np.testing.assert_allclose(arr2.flows, [[False, False], [False, False]])
    assert arr2.ndim == 2
    arr3 = reshape(arr, Ds)
    for n in range(4):
        assert charge_equal(arr3.charges[n][0], indices[n].charges)

    np.testing.assert_allclose(arr3.shape, Ds)
    np.testing.assert_allclose(arr3._order, [[0], [1], [2], [3]])
    np.testing.assert_allclose(arr3.flows,
                               [[False], [False], [False], [False]])
    assert arr3.ndim == 4
Exemplo n.º 6
0
def test_BlockSparseTensor_init():
    np.random.seed(10)
    D = 10
    rank = 4
    flows = np.random.choice([True, False], size=rank, replace=True)
    charges = [
        U1Charge.random(dimension=D, minval=-5, maxval=5) for _ in range(rank)
    ]
    fused = fuse_charges(charges, flows)
    data = np.random.uniform(0,
                             1,
                             size=len(
                                 np.nonzero(fused == np.zeros((1, 1)))[0]))
    order = [[n] for n in range(rank)]
    arr = BlockSparseTensor(data, charges, flows, order=order)
    np.testing.assert_allclose(data, arr.data)
    for c1, c2 in zip(charges, arr.charges):
        assert charge_equal(c1, c2[0])
    for c1, c2 in zip(charges, arr._charges):
        assert charge_equal(c1, c2)
    data = np.random.uniform(
        0, 1, size=len(np.nonzero(fused == np.zeros((1, 1)))[0]) + 1)
    with pytest.raises(ValueError):
        arr = BlockSparseTensor(data,
                                charges,
                                flows,
                                order=order,
                                check_consistency=True)
def test_eigsh_lanczos_sanity_check_2(dtype):
    np.random.seed(10)
    D = 16
    backend = symmetric_backend.SymmetricBackend()
    index = Index(U1Charge.random(D, 0, 0), True)
    indices = [index, index.copy().flip_flow()]

    H = BlockSparseTensor.random(indices, dtype=dtype)
    H = H + H.conj().T

    def mv(x, mat):
        return mat @ x

    eta1, U1 = backend.eigsh_lanczos(mv, [H],
                                     shape=(H.sparse_shape[1].flip_flow(), ),
                                     dtype=dtype)
    eta2, U2 = np.linalg.eigh(H.todense())
    v1 = np.reshape(U1[0].todense(), (D))
    v1 = v1 / sum(v1)

    v2 = U2[:, 0]
    v2 = v2 / sum(v2)

    np.testing.assert_allclose(eta1[0], min(eta2))
    np.testing.assert_allclose(v1, v2)
def test_eigsh_lanczos_reorthogonalize_sanity_check(dtype, numeig):
    np.random.seed(10)
    D = 24
    backend = symmetric_backend.SymmetricBackend()
    index = Index(U1Charge.random(D, 0, 0), True)
    indices = [index, index.copy().flip_flow()]

    H = BlockSparseTensor.random(indices, dtype=dtype)
    H = H + H.conj().T

    def mv(x, mat):
        return mat @ x

    eta1, U1 = backend.eigsh_lanczos(mv, [H],
                                     shape=(H.sparse_shape[1].flip_flow(), ),
                                     dtype=dtype,
                                     numeig=numeig,
                                     num_krylov_vecs=D,
                                     reorthogonalize=True,
                                     ndiag=1,
                                     tol=10**(-12),
                                     delta=10**(-12))
    eta2, U2 = np.linalg.eigh(H.todense())

    np.testing.assert_allclose(eta1[0:numeig], eta2[0:numeig])
    for n in range(numeig):
        v2 = U2[:, n]
        v2 /= np.sum(v2)  #fix phases
        v1 = np.reshape(U1[n].todense(), (D))
        v1 /= np.sum(v1)

        np.testing.assert_allclose(v1, v2, rtol=10**(-5), atol=10**(-5))
def test_eigsh_valid_init_operator_with_shape(dtype):
    np.random.seed(100)
    backend = symmetric_backend.SymmetricBackend()
    np_backend = numpy_backend.NumPyBackend()
    D = 16
    index = Index(U1Charge.random(D, -1, 1), True)
    indices = [index, index.copy().flip_flow()]

    a = BlockSparseTensor.random(indices, dtype=dtype)
    H = a + a.T.conj()

    def mv(vec, mat):
        return mat @ vec

    init = BlockSparseTensor.random([index], dtype=dtype)
    # note: this will only find eigenvalues in the charge (0,0)
    # block of H because `init` only has non-zero values there.
    # To find eigen values in other sectors we need to support non-zero
    # divergence for block-sparse tensors
    eta1, U1 = backend.eigsh_lanczos(mv, [H], init)
    eta2, U2 = np_backend.eigsh_lanczos(mv, [H.todense()], init.todense())

    v1 = np.reshape(U1[0].todense(), (D))
    v1 = v1 / sum(v1)
    v1 /= np.linalg.norm(v1)
    v2 = np.reshape(U2[0], (D))
    v2 = v2 / sum(v2)
    v2[np.abs(v2) < 1E-12] = 0.0
    v2 /= np.linalg.norm(v2)

    np.testing.assert_allclose(eta1[0], min(eta2))
    np.testing.assert_allclose(v1, v2)
def test_ChargeArray_reshape_raises():
    Ds = [8, 9, 10, 11]
    indices = [Index(U1Charge.random(-5, 5, Ds[n]), False) for n in range(4)]
    arr = ChargeArray.random(indices)
    with pytest.raises(ValueError):
        arr.reshape([64, 65])

    arr2 = arr.reshape([72, 110])
    with pytest.raises(ValueError):
        arr2.reshape([9, 8, 10, 11])

    Ds = [8, 9, 0, 11]
    indices = [Index(U1Charge.random(-5, 5, Ds[n]), False) for n in range(4)]
    arr3 = ChargeArray.random(indices)
    with pytest.raises(ValueError):
        arr3.reshape([72, 0])
Exemplo n.º 11
0
def test_tn_conj(dtype):
    np.random.seed(10)
    indices = [
        Index(U1Charge.random(dimension=10, minval=-5, maxval=5), False)
        for _ in range(4)
    ]
    a = BlockSparseTensor.randn(indices, dtype=dtype)
    b = conj(a)
    np.testing.assert_allclose(b.data, np.conj(a.data))
Exemplo n.º 12
0
def test_flat_flows():
  Ds = [10, 11, 12, 13]
  charges = [U1Charge.random(Ds[n], -5, 5) for n in range(4)]
  flows = [True, False, True, False]
  inds = [Index(c, flows[n]) for n, c in enumerate(charges)]
  a = BlockSparseTensor.random(inds, dtype=np.float64)
  order = [0, 3, 1, 2]
  a = a.transpose(order)
  np.testing.assert_allclose(a.flat_flows, [a._flows[o] for o in a.flat_order])
Exemplo n.º 13
0
def test_norm(dtype):
  np.random.seed(10)
  Ds = np.asarray([8, 9, 10, 11])
  rank = Ds.shape[0]
  flows = np.random.choice([True, False], size=rank, replace=True)
  indices = [Index(U1Charge.random(-5, 5, Ds[n]), flows[n]) for n in range(4)]
  arr = BlockSparseTensor.random(indices, dtype=dtype)
  dense_norm = np.linalg.norm(arr.todense())
  np.testing.assert_allclose(norm(arr), dense_norm)
Exemplo n.º 14
0
def test_truediv_raises():
    np.random.seed(10)
    indices = [
        Index(U1Charge.random(dimension=10, minval=-5, maxval=5), False)
        for _ in range(4)
    ]
    a = BlockSparseTensor.randn(indices)
    with pytest.raises(TypeError):
        _ = a / np.array([1, 2])
Exemplo n.º 15
0
def test_sign():
    np.random.seed(10)
    Ds = np.array([8, 9, 10, 11])
    flows = [True, False, True, False]
    indices = [
        Index(U1Charge.random(dimension=Ds[n], minval=-5, maxval=5), flows[n])
        for n in range(4)
    ]
    arr = BlockSparseTensor.random(indices)
    np.testing.assert_allclose(sign(arr).data, np.sign(arr.data))
def test_ChargeArray_transpose_raises():
    Ds = np.array([8, 9, 10, 11])
    flows = [True, False, True, False]
    indices = [
        Index(U1Charge.random(-5, 5, Ds[n]), flows[n]) for n in range(4)
    ]
    arr = ChargeArray.random(indices)
    order = [2, 1, 0]
    with pytest.raises(ValueError):
        arr.transpose(order)
Exemplo n.º 17
0
def test_ChargeArray_conj(dtype):
    Ds = np.array([8, 9, 10, 11])
    flows = [True, False, True, False]
    indices = [
        Index(U1Charge.random(dimension=Ds[n], minval=-5, maxval=5), flows[n])
        for n in range(4)
    ]
    arr = ChargeArray.random(indices, dtype=dtype)
    conj = arr.conj()
    np.testing.assert_allclose(conj.data, np.conj(arr.data))
def test_ChargeArray_init_raises():
    np.random.seed(10)
    D = 10
    rank = 4
    charges = [U1Charge.random(-5, 5, D) for _ in range(rank)]
    data = np.random.uniform(0, 1, size=D**rank)
    flows = np.random.choice([True, False], size=rank, replace=True)
    order = [[n + 10] for n in range(rank)]
    with pytest.raises(ValueError):
        ChargeArray(data, charges, flows, order=order)
Exemplo n.º 19
0
def test_flat_charges():
    Ds = [10, 11, 12, 13]
    charges = [U1Charge.random(Ds[n], -5, 5) for n in range(4)]
    flows = [True, False, True, False]
    inds = [Index(c, flows[n]) for n, c in enumerate(charges)]
    a = BlockSparseTensor.random(inds, dtype=np.float64)
    order = [0, 3, 1, 2]
    a = a.transpose(order)
    for n, o in enumerate(a.flat_order):
        charge_equal(a.flat_charges[n], a._charges[o])
Exemplo n.º 20
0
def test_fromdense_raises():
    np.random.seed(10)
    Ds = [8, 9, 10, 11]
    rank = len(Ds)
    flows = np.random.choice([True, False], size=rank, replace=True)
    charges = [U1Charge.random(Ds[n], -5, 5) for n in range(rank)]
    indices = [Index(charges[n], flows[n]) for n in range(rank)]

    dense = np.random.random_sample([8, 9, 9, 11])
    with pytest.raises(ValueError):
        _ = BlockSparseTensor.fromdense(indices, dense)
def test_ChargeArray_generic(dtype):
    Ds = [8, 9, 10, 11]
    indices = [Index(U1Charge.random(-5, 5, Ds[n]), False) for n in range(4)]
    arr = ChargeArray.random(indices, dtype=dtype)
    assert arr.ndim == 4
    assert arr.dtype == dtype
    np.testing.assert_allclose(arr.shape, Ds)
    np.testing.assert_allclose(arr.flat_flows, [False, False, False, False])
    for n in range(4):
        assert charge_equal(indices[n]._charges[0], arr.flat_charges[n])
        assert arr.sparse_shape[n] == indices[n]
Exemplo n.º 22
0
def test_tn_transpose():
  np.random.seed(10)
  Ds = np.array([8, 9, 10, 11])
  flows = [True, False, True, False]
  indices = [Index(U1Charge.random(-5, 5, Ds[n]), flows[n]) for n in range(4)]
  arr = BlockSparseTensor.random(indices)
  order = [2, 1, 0, 3]
  arr2 = transpose(arr, order)
  np.testing.assert_allclose(Ds[order], arr2.shape)
  np.testing.assert_allclose(arr2._order, [[2], [1], [0], [3]])
  np.testing.assert_allclose(arr2.flows, [[True], [False], [True], [False]])
def test_ChargeArray_transpose():
    Ds = np.array([8, 9, 10, 11])
    flows = [True, False, True, False]
    indices = [
        Index(U1Charge.random(-5, 5, Ds[n]), flows[n]) for n in range(4)
    ]
    arr = ChargeArray.random(indices)
    order = [2, 1, 0, 3]
    arr2 = arr.transpose(order)
    np.testing.assert_allclose(Ds[order], arr2.shape)
    np.testing.assert_allclose(arr2._order, [[2], [1], [0], [3]])
    np.testing.assert_allclose(arr2.flows, [[True], [False], [True], [False]])
Exemplo n.º 24
0
def test_BlockSparseTensor_contiguous_1():
    Ds = [10, 11, 12, 13]
    charges = [U1Charge.random(Ds[n], -5, 5) for n in range(4)]
    flows = [True, False, True, False]
    inds = [Index(c, flows[n]) for n, c in enumerate(charges)]
    b = BlockSparseTensor.random(inds, dtype=np.float64)
    order = [0, 3, 2, 1]
    b = b.transpose(order)
    b_ = b.contiguous(inplace=False)
    np.testing.assert_allclose(b.flows, b_.flows)
    for n in range(4):
        assert charge_equal(b._charges[order[n]], b_._charges[n])
def test_add_sub_raises(op):
    np.random.seed(10)
    Ds1 = [3, 4, 5, 6]
    Ds2 = [4, 5, 6, 7]

    indices1 = [Index(U1Charge.random(-5, 5, Ds1[n]), False) for n in range(4)]
    indices2 = [Index(U1Charge.random(-5, 5, Ds2[n]), False) for n in range(4)]
    a = BlockSparseTensor.randn(indices1)
    b = BlockSparseTensor.randn(indices2)
    with pytest.raises(TypeError):
        op(a, np.array([1, 2, 3]))
    with pytest.raises(ValueError):
        op(a, b)

    Ds3 = [3, 3, 3, 3]
    Ds4 = [9, 9]
    indices3 = [Index(U1Charge.random(-5, 5, Ds3[n]), False) for n in range(4)]
    indices4 = [Index(U1Charge.random(-5, 5, Ds4[n]), False) for n in range(2)]
    c = BlockSparseTensor.randn(indices3).reshape([9, 9])
    d = BlockSparseTensor.randn(indices4)
    with pytest.raises(ValueError):
        op(c, d)

    Ds5 = [200, 200]
    Ds6 = [200, 200]
    indices5 = [Index(U1Charge.random(-5, 5, Ds5[n]), False) for n in range(2)]
    indices6 = [Index(U1Charge.random(-5, 5, Ds6[n]), False) for n in range(2)]
    e = BlockSparseTensor.randn(indices5)
    f = BlockSparseTensor.randn(indices6)
    with pytest.raises(ValueError):
        op(e, f)
Exemplo n.º 26
0
def test_tensordot_raises():
    R1 = 3
    R2 = 3
    dtype = np.float64
    np.random.seed(10)
    Ds1 = np.arange(2, 2 + R1)
    Ds2 = np.arange(2 + R1, 2 + R1 + R2)
    is1 = [
        Index(U1Charge.random(dimension=Ds1[n], minval=-5, maxval=5), False)
        for n in range(R1)
    ]
    is2 = [
        Index(U1Charge.random(dimension=Ds2[n], minval=-5, maxval=5), False)
        for n in range(R2)
    ]
    A = BlockSparseTensor.random(is1, dtype=dtype)
    B = BlockSparseTensor.random(is2, dtype=dtype)
    with pytest.raises(ValueError):
        tensordot(A, B, ([0, 1, 2, 3], [1, 2]))
    with pytest.raises(ValueError):
        tensordot(A, B, ([0, 1], [0, 1, 2, 3]))
    with pytest.raises(ValueError):
        tensordot(A, B, ([0], [1, 2]))
    with pytest.raises(ValueError):
        tensordot(A, B, [0, [1, 2]])
    with pytest.raises(ValueError):
        tensordot(A, B, ([0, 0], [1, 2]))
    with pytest.raises(ValueError):
        tensordot(A, B, ([0, 1], [1, 1]))
    with pytest.raises(ValueError):
        tensordot(A, B, ([0, 4], [1, 2]))
    with pytest.raises(ValueError):
        tensordot(A, B, ([0, 4], [1, 4]))
    with pytest.raises(ValueError):
        tensordot(A, B, ([0, 1], [0, 1]))
    with pytest.raises(ValueError):
        tensordot(A, A, ([0, 1], [0, 1]))
    with pytest.raises(ValueError):
        tensordot(A, A.conj(), ([0, 1], [1, 0]))
Exemplo n.º 27
0
def test_tensordot_single_arg():
    R = 3
    dtype = np.float64
    np.random.seed(10)
    Ds = [10, 10, 10]
    inds = [
        Index(U1Charge.random(dimension=Ds[n], minval=-5, maxval=5), False)
        for n in range(R)
    ]
    A = BlockSparseTensor.random(inds, dtype=dtype)
    res = tensordot(A, A.conj(), ([0]))
    dense_res = np.tensordot(A.todense(), A.conj().todense(), ([0], [0]))
    np.testing.assert_allclose(dense_res, res.todense())
Exemplo n.º 28
0
def test_rmul(dtype, num_charges, chargetype):
    np.random.seed(10)
    indices = [
        Index(get_charge(chargetype, num_charges, 20), False) for _ in range(4)
    ]

    indices = [
        Index(U1Charge.random(dimension=10, minval=-5, maxval=5), False)
        for _ in range(4)
    ]
    a = BlockSparseTensor.randn(indices, dtype=dtype)
    b = a * 5
    np.testing.assert_allclose(b.data, a.data * 5)
def test_BlockSparseTensor_transpose_data():
    np.random.seed(10)
    Ds = np.array([8, 9, 10, 11])
    order = [2, 0, 1, 3]
    flows = [True, False, True, False]
    indices = [
        Index(U1Charge.random(-5, 5, Ds[n]), flows[n]) for n in range(4)
    ]
    arr = BlockSparseTensor.random(indices)
    data1 = np.ascontiguousarray(np.transpose(arr.todense(), order))
    data2 = arr.transpose(order).transpose_data().todense()
    np.testing.assert_allclose(data1.strides, data2.strides)
    np.testing.assert_allclose(data1, data2)
def test_qr_decomposition(dtype, R, R1):
    np.random.seed(10)
    D = 30
    charges = [U1Charge.random(-5, 5, D) for n in range(R)]
    flows = [True] * R
    A = BlockSparseTensor.random(
        [Index(charges[n], flows[n]) for n in range(R)], dtype=dtype)

    q, r = decompositions.qr_decomposition(bs, A, R1)
    res = bs.tensordot(q, r, 1)
    q_dense, r_dense = np_decompositions.qr_decomposition(np, A.todense(), R1)
    res2 = np.tensordot(q_dense, r_dense, 1)
    np.testing.assert_almost_equal(res.todense(), res2)