Exemplo n.º 1
0
def test_inverse_of_linear_vector_transforms(free_alg: Drudge):
    """Test automatic inversion of linear vector transformations.

    Here, we also have good coverage on the conversion of linear transformations
    in matrix and definitions forms.
    """

    dr = free_alg
    p = dr.names
    v = p.v

    a = Vec('a')
    b = Vec('b')

    defs = [dr.define(a, v + 1), dr.define(b, v - 1)]
    res = dr.lvt_inv(defs)

    assert len(res) == 2
    half = Rational(1, 2)
    one_checked = False
    v_checked = False
    for i in res:
        if i.lhs == 1:
            assert (i - half * a + half * b).simplify() == 0
            one_checked = True
        elif i.lhs == v:
            assert (i - half * a - half * b).simplify() == 0
            v_checked = True
        else:
            assert False
        continue

    assert one_checked and v_checked
Exemplo n.º 2
0
def test_vecs_has_basic_properties():
    """Tests the basic properties of vector instances."""

    base = Vec('v')
    v_ab = Vec('v', indices=['a', 'b'])
    v_ab_1 = base['a', 'b']
    v_ab_2 = (base['a'])['b']

    indices_ref = (sympify('a'), sympify('b'))
    hash_ref = hash(v_ab)
    str_ref = 'v[a, b]'
    repr_ref = "Vec('v', (a, b))"

    for i in [v_ab, v_ab_1, v_ab_2]:
        assert i.label == base.label
        assert i.base == base
        assert i.indices == indices_ref
        assert hash(i) == hash_ref
        assert i == v_ab
        assert str(i) == str_ref
        assert repr(i) == repr_ref

        # Vectors should not be sympified.
        with pytest.raises(SympifyError):
            sympify(i)
Exemplo n.º 3
0
def test_canonicalization_of_vectors_w_symm(free_alg):
    """Test the canonicalization when vectors are given (anti-)symmetries.
    """

    dr = free_alg
    p = dr.names
    x = IndexedBase('x')
    r = p.R
    i, j = p.i, p.j

    vs = Vec('vs')
    dr.set_symm(vs, Perm([1, 0]), valence=2)
    tensor = dr.sum((i, r), (j, r), x[i, j] * vs[j, i])
    res = tensor.simplify()
    assert res.n_terms == 1
    term = res.local_terms[0]
    assert term.sums == ((i, r), (j, r))
    assert term.amp == x[i, j]
    assert term.vecs == (vs[i, j], )

    va = Vec('va')
    dr.set_symm(va, Perm([1, 0], NEG), valence=2)
    tensor = dr.sum((i, r), (j, r), x[i, j] * va[j, i])
    res = tensor.simplify()
    assert res.n_terms == 1
    term = res.local_terms[0]
    assert term.sums == ((i, r), (j, r))
    assert term.amp == -x[i, j]
    assert term.vecs == (va[i, j], )
Exemplo n.º 4
0
def test_drs_symb_call(spark_ctx):
    """Test calling methods by drs symbols."""
    class TestCls:
        def meth(self):
            return 'meth'

        @property
        def prop(self):
            return 'prop'

    obj = TestCls()
    meth = DrsSymbol(None, 'meth')
    assert meth(obj) == 'meth'
    prop = DrsSymbol(None, 'prop')
    assert prop(obj) == 'prop'
    invalid = DrsSymbol(None, 'invalid')
    with pytest.raises(NameError):
        invalid(obj)
    with pytest.raises(AttributeError) as exc:
        prop.lhs
    assert exc.value.args[0].find('prop') > 0

    # Test automatic raising to tensors.
    v = Vec('v')
    tensor_meth = 'local_terms'
    assert not hasattr(v, tensor_meth)  # Or the test just will not work.
    assert DrsSymbol(Drudge(spark_ctx), tensor_meth)(v) == [
        Term(sums=(), amp=Integer(1), vecs=(v, ))
    ]
Exemplo n.º 5
0
def test_tensors_can_be_rewritten(free_alg):
    """Test the amplitude rewriting facility for given vector patterns."""

    dr = free_alg
    p = dr.names
    v = Vec('v')
    a, b = p.R_dumms[:2]

    x = IndexedBase('x')
    o = IndexedBase('o')
    y = IndexedBase('y')
    z = IndexedBase('z')

    tensor = dr.einst(x[a] * v[a] + o[a, b] * y[b] * v[a] +
                      z[b] * v[b]  # Terms to rewrite.
                      + z[a, b] * v[a] * v[b]  # Terms to keep.
                      )

    w = Wild('w')
    r = IndexedBase('r')
    rewritten, defs = tensor.rewrite(v[w], r[w])

    assert rewritten == dr.einst(z[a, b] * v[a] * v[b] + r[a] * v[a] +
                                 r[b] * v[b])
    assert len(defs) == 2
    assert r[a] in defs
    assert defs[r[a]] == dr.einst(x[a] + o[a, b] * y[b])
    assert r[b] in defs
    assert defs[r[b]] == dr.sum(z[b])
Exemplo n.º 6
0
def test_tensors_can_substitute_strings_of_vectors(free_alg, full_balance,
                                                   full_simplify):
    """Test vector substitution facility for strings of tensors."""

    dr = free_alg
    p = dr.names

    x = IndexedBase('x')
    t = IndexedBase('t')
    u = IndexedBase('u')
    i, j = p.i, p.j
    v = p.v
    w = Vec('w')

    orig = dr.sum((i, p.R), x[i] * v[i] * v[i])
    vivi_def = dr.einst(t[i, j] * w[j] + u[i, j] * w[j])

    dr.full_simplify = full_simplify
    res = orig.subst(v[i] * v[i], vivi_def,
                     full_balance=full_balance).simplify()
    dr.full_simplify = True

    expected = dr.einst(x[i] * t[i, j] * w[j] +
                        x[i] * u[i, j] * w[j]).simplify()
    assert res == expected

    # Check that it does not wrongly substitute vectors that cannot match the
    # pattern.
    orig = dr.einst(x[i, j] * v[i] * v[j])
    res = orig.subst(v[i] * v[i], vivi_def)
    assert res == orig
Exemplo n.º 7
0
def test_assume_comm(spark_ctx):
    """
    Test the case where vectors are assumed to commute if there commutator
    is not specified.
    """

    v1 = Vec(r'v_1')
    v2 = Vec(r'v_2')

    dr = GenQuadLatticeDrudge(spark_ctx,
                              order=(v1, v2),
                              comms={},
                              assume_comm=True)
    tensor = dr.sum(v1 | v2)

    assert tensor.simplify() == Integer(0)
Exemplo n.º 8
0
def free_alg(spark_ctx):
    """Initialize the environment for a free algebra."""

    dr = Drudge(spark_ctx)

    r = Range('R')
    dumms = sympify('i, j, k, l, m, n')
    dr.set_dumms(r, dumms)

    s = Range('S')
    s_dumms = symbols('alpha beta')
    dr.set_dumms(s, s_dumms)

    dr.add_resolver_for_dumms()

    # For testing the Einstein over multiple ranges.
    a1, a2 = symbols('a1 a2')
    dr.add_resolver({a1: (r, s), a2: (r, s)})
    dr.set_name(a1, a2)

    v = Vec('v')
    dr.set_name(v)

    m = IndexedBase('m')
    dr.set_symm(m, Perm([1, 0], NEG))

    h = IndexedBase('h')
    dr.set_symm(h, Perm([1, 0], NEG | CONJ))

    rho = IndexedBase('rho')
    dr.set_symm(rho, Perm([1, 0, 3, 2]), valence=4)

    dr.set_tensor_method('get_one', lambda x: 1)

    return dr
Exemplo n.º 9
0
def test_tensor_math_ops(free_alg):
    """Test tensor math operations.

    Mainly here we test addition, multiplication, and division.
    """

    dr = free_alg
    p = dr.names
    r = p.R
    v = p.v
    w = Vec('w')
    x = IndexedBase('x')
    i, j, k = p.R_dumms[:3]
    a = sympify('a')

    v1 = dr.sum((i, r), x[i] * v[i])
    w1 = dr.sum((i, r), x[i] * w[i])
    assert v1.n_terms == 1
    assert w1.n_terms == 1

    v1_neg = -v1
    assert v1_neg == dr.sum((i, r), -x[i] * v[i])

    v1_1 = v1 + 2
    assert v1_1.n_terms == 2
    assert v1_1 == 2 + v1

    w1_1 = w1 + a
    assert w1_1.n_terms == 2
    assert w1_1 == a + w1

    prod = v1_1 * w1_1
    # Test scalar multiplication here as well.
    expected = (2 * a + a * v1 + 2 * w1 + dr.sum(
        (i, r), (j, r), x[i] * x[j] * v[i] * w[j]))
    assert prod.simplify() == expected.simplify()

    # Test the commutator operation.
    comm_v1v1 = v1 | v1
    assert comm_v1v1.simplify() == 0
    # Here the tensor subtraction can also be tested.
    comm_v1w1 = v1 | w1
    expected = (dr.sum((i, r), (j, r), x[i] * x[j] * v[i] * w[j]) - dr.sum(
        (i, r), (j, r), x[j] * x[i] * w[i] * v[j]))
    assert comm_v1w1.simplify() == expected.simplify()

    alpha = symbols('alpha')
    assert alpha not in v1.free_vars
    tensor = v1 / alpha
    assert tensor.n_terms == 1
    terms = tensor.local_terms
    assert len(terms) == 1
    term = terms[0]
    assert term.sums == ((i, r), )
    assert term.amp == x[i] / alpha
    assert term.vecs == (v[i], )
    assert alpha in tensor.free_vars
Exemplo n.º 10
0
def test_pickling_tensors(free_alg):
    """Test tensors and definitions can be correctly pickled and unpickled."""

    dr = free_alg
    p = dr.names
    x = IndexedBase('x')
    v = Vec('v')
    b = Vec('b')

    tensor = dr.einst(x[p.i] * v[p.i])
    def_ = dr.define(b, tensor)
    serialized = pickle.dumps([tensor, def_])

    with pytest.raises(ValueError):
        pickle.loads(serialized)

    with dr.pickle_env():
        res = pickle.loads(serialized)

    assert res[0] == tensor
    assert res[1] == def_
Exemplo n.º 11
0
def test_basic_handling_range_with_variable_bounds(spark_ctx):
    """Test the treatment of ranges with variable bounds.

    Here we use a simple example that slightly resembles the angular momentum
    handling in quantum physics.  Here we concentrate on basic operations of
    dummy resetting and mapping of scalar functions.
    """

    dr = Drudge(spark_ctx)

    j1, j2 = symbols('j1 j2')
    m1, m2 = symbols('m1, m2')
    j_max = symbols('j_max')
    j = Range('j', 0, j_max)
    m = Range('m')
    dr.set_dumms(j, [j1, j2])
    dr.set_dumms(m, [m1, m2])

    v = Vec('v')
    x = IndexedBase('x')
    tensor = dr.sum((j2, j), (m2, m[0, j2]), x[j2, m2] * v[j2, m2])

    reset = tensor.reset_dumms()
    assert reset.n_terms == 1
    term = reset.local_terms[0]
    assert len(term.sums) == 2
    if term.sums[0][1].label == 'j':
        j_sum, m_sum = term.sums
    else:
        m_sum, j_sum = term.sums
    assert j_sum[0] == j1
    assert j_sum[1].args == j.args
    assert m_sum[0] == m1
    assert m_sum[1].label == 'm'
    assert m_sum[1].lower == 0
    assert m_sum[1].upper == j1  # Important!
    assert term.amp == x[j1, m1]
    assert term.vecs == (v[j1, m1], )

    # Test that functions can be mapped to the bounds.
    repled = reset.map2scalars(lambda x: x.xreplace({j_max: 10}),
                               skip_ranges=False)
    assert repled.n_terms == 1
    term = repled.local_terms[0]
    checked = False
    for _, i in term.sums:
        if i.label == 'j':
            assert i.lower == 0
            assert i.upper == 10
            checked = True
        continue
    assert checked
Exemplo n.º 12
0
def test_sum_prod_utility():
    """Test the summation and product utility."""

    v = Vec('v')
    vecs = [v[i] for i in range(3)]
    v0, v1, v2 = vecs

    # The proxy object cannot be directly compared.
    assert parse_terms(sum_(vecs)) == parse_terms(v0 + v1 + v2)
    assert parse_terms(prod_(vecs)) == parse_terms(v0 * v1 * v2)

    assert sum_([]) == 0
    assert prod_([]) == 1
Exemplo n.º 13
0
def test_simple_terms_can_be_canonicalized():
    """Test the canonicalization of very simple terms.

    In this test, all the terms has very simple appearance.  So rather than
    testing the canonicalization really canonicalizes all the equivalent
    forms, here we check if the canonicalized form is the most intuitive form
    that we expect.
    """

    l = Range('L')
    x = IndexedBase('x')
    i, j = sympify('i, j')

    # A term without the vector part, canonicalization without symmetry.
    term = sum_term([(j, l), (i, l)], x[i, j])[0]
    res = term.canon()
    expected = sum_term([(i, l), (j, l)], x[i, j])[0]
    assert res == expected

    # A term without the vector part, canonicalization with symmetry.
    m = Range('M')
    term = sum_term([(j, m), (i, l)], x[j, i])[0]
    for neg, conj in itertools.product([IDENT, NEG], [IDENT, CONJ]):
        acc = neg | conj
        group = Group([Perm([1, 0], acc)])
        res = term.canon(symms={x: group})
        expected_amp = x[i, j]
        if neg == NEG:
            expected_amp *= -1
        if conj == CONJ:
            expected_amp = conjugate(expected_amp)
        expected = sum_term([(i, l), (j, m)], expected_amp)[0]
        assert res == expected
        continue

    # In the absence of symmetry, the two indices should not be permuted.
    res = term.canon()
    expected = sum_term([(i, l), (j, m)], x[j, i])[0]
    assert res == expected

    # Now we add vectors to the terms.
    v = Vec('v')
    term = sum_term([(i, l), (j, l)], v[i] * v[j])[0]

    # Without anything added, it should already be in the canonical form.
    assert term.canon() == term

    # When we flip the colour of the vectors, we should get something different.
    res = term.canon(vec_colour=lambda idx, vec, term: -idx)
    expected = sum_term([(j, l), (i, l)], v[i] * v[j])[0]
    assert res == expected
Exemplo n.º 14
0
def test_advanced_manipulations(free_alg):
    """Test advanced manipulations of tensors."""
    dr = free_alg
    p = dr.names
    i, j, k = p.i, p.j, p.k

    u = IndexedBase('u')
    v = IndexedBase('v')
    f = Vec('f')

    tensor = dr.einst(u[i, j] * f[j] + v[i, j] * f[j])
    assert tensor.n_terms == 2

    def has_u(term):
        """Test if a term have u tensor."""
        return term.amp.has(u)

    expect = dr.sum((j, p.R), u[i, j] * f[j])
    for res in [
            tensor.filter(has_u),
            tensor.bind(lambda x: [x] if has_u(x) else [])
    ]:
        assert res.n_terms == 1
        assert res == expect

    def subst_i(term):
        """Substitute i index in the terms."""
        return Term(term.sums, term.amp.xreplace({i: k}), term.vecs)

    expect = dr.sum((j, p.R), u[k, j] * f[j] + v[k, j] * f[j])
    for res in [
            tensor.map(subst_i),
            tensor.bind(lambda x: [subst_i(x)]),
            tensor.map2scalars(lambda x: x.xreplace({i: k}))
    ]:
        assert res.n_terms == 2
        assert res == expect

    alpha, beta = symbols('alpha beta')
    assert tensor.bind(
        lambda x: [Term(x.sums, x.amp * i_, x.vecs)
                   for i_ in [alpha, beta]]) == (tensor * alpha +
                                                 tensor * beta)

    assert tensor.map2scalars(lambda x: x.xreplace({j: k})) == dr.sum(
        (j, p.R), u[i, k] * f[k] + v[i, k] * f[k])

    assert tensor.map2scalars(lambda x: x.xreplace({j: k}),
                              skip_vecs=True) == dr.sum(
                                  (j, p.R), u[i, k] * f[j] + v[i, k] * f[j])
Exemplo n.º 15
0
def test_simple_drs(free_alg):
    """Test a simple drudge script."""
    dr = free_alg
    p = dr.names
    env = dr.exec_drs(TEST_SIMPLE_DRS)

    x = Vec('x')
    i = p.i
    def_ = dr.define_einst(x[i], Rational(1, 2) * p.m[i] * p.v[i])
    assert env['x'] == def_
    assert env['_x'] == x
    assert env['y'] == 45
    assert env['n'] == 1
    dr.unset_name(def_)

    # Test some drudge script specials about the free algebra environment.
    assert env['DRUDGE'] is dr
    assert env['sum_'] is sum
Exemplo n.º 16
0
def test_drudge_has_names(free_alg):
    """Test the name archive for drudge objects.

    Here selected names are tested to makes sure all the code are covered.
    """

    p = free_alg.names

    # Range and dummy related.
    assert p.R == Range('R')
    assert len(p.R_dumms) == 6
    assert p.R_dumms[0] == p.i
    assert p.R_dumms[-1] == p.n

    # Vector bases.
    assert p.v == Vec('v')

    # Scalar bases.
    assert p.m == IndexedBase('m')
Exemplo n.º 17
0
def test_special_substitution_of_identity(free_alg):
    """Test the special substitution of integer one standing for identity.
    """

    dr = free_alg
    p = dr.names

    x = IndexedBase('x')
    t = IndexedBase('y')
    a = IndexedBase('a')
    i, j = p.i, p.j
    v = p.v
    w = Vec('w')

    orig = dr.sum((i, p.R), x[i] * v[i] + a[i])
    ident_def = dr.define(1, dr.einst(t[i] * w[i]))

    res = orig.subst_all([ident_def])
    assert dr.simplify(res - dr.einst(x[i] * v[i]) -
                       dr.sum((i, p.R), (j, p.R), a[i] * t[j] * w[j])) == 0
Exemplo n.º 18
0
def test_numbers_can_substitute_vectors(free_alg, full_balance):
    """Test substituting vectors with numbers."""

    dr = free_alg
    p = dr.names

    x = IndexedBase('x')
    y = IndexedBase('y')
    r = p.R
    i, j, k, l = symbols('i j k l')
    v = p.v
    w = Vec('w')

    orig = dr.sum((i, r), (j, r),
                  x[i, j] * v[i] * w[j] + y[i, j] * v[i] * v[j])

    res = orig.subst(v[k], 0, full_balance=full_balance).simplify()
    assert res == 0
    res = orig.subst(v[i], 1, full_balance=full_balance).simplify()
    assert res == dr.sum((i, r), (j, r), x[j, i] * w[i] + y[i, j])
Exemplo n.º 19
0
def test_clifford_drudge_by_quaternions(spark_ctx):
    """Test basic functionality of Clifford drudge by quaternions.
    """

    dr = CliffordDrudge(spark_ctx,
                        inner=lambda v1, v2: -inner_by_delta(v1, v2))
    e_ = Vec('e')

    i_ = dr.sum(e_[2] * e_[3]).simplify()
    j_ = dr.sum(e_[3] * e_[1]).simplify()
    k_ = dr.sum(e_[1] * e_[2]).simplify()

    for i in [i_, j_, k_]:
        assert (i * i).simplify() == -1

    assert (i_ * j_ * k_).simplify() == -1

    assert (i_ * j_).simplify() == k_
    assert (j_ * k_).simplify() == i_
    assert (k_ * i_).simplify() == j_
Exemplo n.º 20
0
def test_sums_can_be_expanded(spark_ctx):
    """Test the summation expansion facility.

    Here we have essentially a direct product of two ranges and expand it.  The
    usage here also includes some preliminary steps typical in the usage
    paradigm.
    """

    dr = Drudge(spark_ctx)

    comp = Range('P')
    r1, r2 = symbols('r1, r2')
    dr.set_dumms(comp, [r1, r2])

    a = IndexedBase('a')
    v = Vec('v')

    # A simple thing written in terms of composite indices.
    orig = dr.sum((r1, comp), (r2, comp), a[r1] * a[r2] * v[r1] * v[r2])

    # Rewrite the expression in terms of components.  Here, r1 should be
    # construed as a simple Wild.
    rewritten = orig.subst_all([(a[r1], a[x(r1), y(r1)]),
                                (v[r1], v[x(r1), y(r1)])])

    # Expand the summation over r.
    x_dim = Range('X')
    y_dim = Range('Y')
    x1, x2 = symbols('x1 x2')
    dr.set_dumms(x_dim, [x1, x2])
    y1, y2 = symbols('y1 y2')
    dr.set_dumms(y_dim, [y1, y2])

    res = rewritten.expand_sums(
        comp, lambda r: [(Symbol(str(r).replace('r', 'x')), x_dim, x(r)),
                         (Symbol(str(r).replace('r', 'y')), y_dim, y(r))])

    assert (res - dr.sum(
        (x1, x_dim), (y1, y_dim), (x2, x_dim), (y2, y_dim),
        a[x1, y1] * a[x2, y2] * v[x1, y1] * v[x2, y2])).simplify() == 0
Exemplo n.º 21
0
def test_tensors_can_substitute_vectors(free_alg, full_balance, full_simplify):
    """Test vector substitution facility for tensors."""

    dr = free_alg
    p = dr.names

    x = IndexedBase('x')
    t = IndexedBase('t')
    u = IndexedBase('u')
    i, j = p.i, p.j
    v = p.v
    w = Vec('w')

    orig = dr.einst(x[i] * v[i])
    v_def = dr.einst(t[i, j] * w[j] + u[i, j] * w[j])

    dr.full_simplify = full_simplify
    res = orig.subst(v[i], v_def, full_balance=full_balance).simplify()
    dr.full_simplify = True

    expected = dr.einst(x[i] * t[i, j] * w[j] +
                        x[i] * u[i, j] * w[j]).simplify()
    assert res == expected
Exemplo n.º 22
0
def mprod():
    """A fixture for a term looking like a matrix product.

    This can be used to test some basic operations on terms.
    """

    i, j, k = sympify('i, j, k')
    n = sympify('n')
    l = Range('L', 1, n)
    a = IndexedBase('a', shape=(n, n))
    b = IndexedBase('b', shape=(n, n))
    v = Vec('v')

    prod = sum_term([(i, l), (j, l), (k, l)], a[i, j] * b[j, k] * v[i] * v[k])

    assert len(prod) == 1
    return prod[0], types.SimpleNamespace(i=i,
                                          j=j,
                                          k=k,
                                          l=l,
                                          a=a,
                                          b=b,
                                          v=v,
                                          n=n)
Exemplo n.º 23
0
def test_tensor_has_basic_operations(free_alg):
    """Test some of the basic operations on tensors.

    Tested in this module:

        1. Addition.
        2. Merge.
        3. Free variable.
        4. Dummy reset.
        5. Equality comparison.
        6. Expansion
        7. Mapping to scalars.
        8. Base presence testing.
    """

    dr = free_alg
    p = dr.names
    i, j, k, l, m = p.R_dumms[:5]
    x = IndexedBase('x')
    r = p.R
    v = p.v
    tensor = (dr.sum((l, r), x[i, l] * v[l]) + dr.sum((m, r), x[j, m] * v[m]))

    # Without dummy resetting, they cannot be merged.
    assert tensor.n_terms == 2
    assert tensor.merge().n_terms == 2

    # Free variables are important for dummy resetting.
    free_vars = tensor.free_vars
    assert free_vars == {x.label, i, j}

    # Reset dummy.
    reset = tensor.reset_dumms()
    expected = (dr.sum((k, r), x[i, k] * v[k]) + dr.sum(
        (k, r), x[j, k] * v[k]))
    assert reset == expected
    assert reset.local_terms == expected.local_terms

    # Merge the terms.
    merged = reset.merge()
    assert merged.n_terms == 1
    term = merged.local_terms[0]
    assert term == Term(((k, r), ), x[i, k] + x[j, k], (v[k], ))

    # Slightly separate test for expansion.
    c, d = symbols('c d')
    tensor = dr.sum((i, r), x[i] * (c + d) * v[i])
    assert tensor.n_terms == 1
    expanded = tensor.expand()
    assert expanded.n_terms == 2
    # Make sure shallow expansion does not delve into the tree.
    shallowly_expanded = tensor.shallow_expand()
    assert shallowly_expanded.n_terms == 1

    # Make sure shallow expansion does the job on the top-level.
    y = IndexedBase('y')
    tensor = dr.sum((i, r), (x[i] * (c + d) + y[i]) * v[i])
    assert tensor.n_terms == 1
    expanded = tensor.expand()
    assert expanded.n_terms == 3
    shallowly_expanded = tensor.shallow_expand()
    assert shallowly_expanded.n_terms == 2

    # Here we also test concrete summation facility.
    expected = dr.sum((i, r), (j, [c, d]), x[i] * j * v[i])
    assert expected == dr.sum((i, r),
                              x[i] * c * v[i] + x[i] * d * v[i]).expand()

    # Test mapping to scalars.
    tensor = dr.sum((i, r), x[i] * v[i, j])
    y = IndexedBase('y')
    substs = {x: y, j: c}
    res = tensor.map2scalars(lambda x: x.xreplace(substs))
    assert res == dr.sum((i, r), y[i] * v[i, c])
    res = tensor.map2scalars(lambda x: x.xreplace(substs), skip_vecs=True)
    assert res == dr.sum((i, r), y[i] * v[i, j])
    assert res == tensor.map2amps(lambda x: x.xreplace(substs))

    # Test base presence.
    tensor = dr.einst(x[i] * v[i])
    assert tensor.has_base(x)
    assert tensor.has_base(v)
    assert not tensor.has_base(IndexedBase('y'))
    assert not tensor.has_base(Vec('w'))

    # Test Einstein summation over multiple ranges.
    a1, a2 = p.a1, p.a2
    summand = x[a1, a2] * v[a1, a2]
    res = dr.einst(summand).simplify()
    assert res.n_terms == 4
    ranges = (p.R, p.S)
    assert res == dr.sum((a1, ranges), (a2, ranges), summand).simplify()
Exemplo n.º 24
0
def test_batch_vector_substitutions(free_alg, full_balance, simplify):
    """Test the batch substitutions using the subst_all method
    """

    dr = free_alg
    p = dr.names

    a = IndexedBase('a')
    x = IndexedBase('x')
    y = IndexedBase('y')
    i, j = p.i, p.j
    v = p.v
    v_dag = Vec('v', indices=(CR, ))

    #
    # Spin flipping
    #

    orig1 = dr.sum((i, p.R), (j, p.R), a[i, j] * v[i, UP] * v[j, DOWN])
    defs1 = [dr.define(v[i, UP], v[i, DOWN]), dr.define(v[i, DOWN], v[i, UP])]

    # Sequentially apply the definitions of the substitutions
    expected_sequential = dr.sum((i, p.R), (j, p.R),
                                 a[i, j] * v[i, UP] * v[j, UP])
    res = orig1.subst_all(defs1,
                          simult_all=False,
                          full_balance=full_balance,
                          simplify=simplify)
    assert res == expected_sequential

    # Simultaneously apply the definitions of the substitutions
    expected_simutaneous = dr.sum((i, p.R), (j, p.R),
                                  a[i, j] * v[i, DOWN] * v[j, UP])
    res = orig1.subst_all(defs1,
                          simult_all=True,
                          full_balance=full_balance,
                          simplify=simplify)
    assert res == expected_simutaneous

    #
    # In-place BCS transformation
    #

    orig2 = dr.einst(a[i, j] * v_dag[i, UP] * v[j, UP] +
                     a[i, j] * v_dag[i, DOWN] * v[j, DOWN])
    defs2 = [
        dr.define(v_dag[i, UP], x[i] * v_dag[i, UP] - y[i] * v[i, DOWN]),
        dr.define(v_dag[i, DOWN], x[i] * v_dag[i, DOWN] + y[i] * v[i, UP]),
        dr.define(v[i, UP], x[i] * v[i, UP] - y[i] * v_dag[i, DOWN]),
        dr.define(v[i, DOWN], x[i] * v[i, DOWN] + y[i] * v_dag[i, UP]),
    ]

    # Sequentially apply the definitions of the substitutions
    expected_sequential = orig2
    for def_ in defs2:
        expected_sequential = def_.act(expected_sequential)
    expected_sequential = expected_sequential.simplify()
    res = orig2.subst_all(defs2,
                          simult_all=False,
                          full_balance=full_balance,
                          simplify=simplify).simplify()
    assert res == expected_sequential

    # Simultaneously apply the definitions of the substitutions
    expected_simutaneous = dr.sum(
        (i, p.R), (j, p.R),
        a[i, j] * ((x[i] * v_dag[i, UP] - y[i] * v[i, DOWN]) *
                   (x[j] * v[j, UP] - y[j] * v_dag[j, DOWN]) +
                   (x[i] * v_dag[i, DOWN] + y[i] * v[i, UP]) *
                   (x[j] * v[j, DOWN] + y[j] * v_dag[j, UP]))).simplify()
    res = orig2.subst_all(defs2,
                          simult_all=True,
                          full_balance=full_balance,
                          simplify=simplify).simplify()
    assert res == expected_simutaneous