Exemple #1
0
def generate_eqm(H,
                 c_ops,
                 t,
                 independent=True,
                 max_order=2,
                 discard_unresolved=True):
    """
    Generate a set of semiclassical equations of motion from a Hamiltonian
    and set of collapse operators. Equations of motion for all operators that
    are included in either the Hamiltonian or the list of collapse operators
    will be generated, as well as any operators that are included in the
    equations of motion for the orignal operators. If the system of equations
    for the averages of operators does not close, the highest order operators
    will be truncated and removed from the equations.
    """
    op_eqm = {}

    #get_ops = lambda expr: extract_operator_products(
    get_ops = lambda expr: extract_all_operators(
        normal_ordered_form(expr, independent=independent).doit().expand())

    ops = get_ops(H + sum(c_ops))

    if debug:
        print("Hamiltonian operators: ", ops)

    while ops:
        order, idx = min(
            (val, idx)
            for (idx, val) in enumerate([operator_order(op) for op in ops]))
        if order > max_order:
            print("Warning: system did not close with max_order =", max_order)
            break

        op = ops.pop(idx)
        lhs, rhs = operator_master_equation(op, t, H, c_ops, use_eq=False)

        op_eqm[op] = normal_ordered_form(
            rhs.doit(independent=independent).expand(),
            independent=independent)

        new_ops = get_ops(op_eqm[op])

        for new_op in new_ops:
            if new_op not in op_eqm and new_op not in ops:
                if debug:
                    print(new_op, "not included, adding")
                ops.append(new_op)

    unresolved_ops = ops
    if debug:
        print("unresolved ops: ", unresolved_ops)

    if discard_unresolved:
        for op, eqm in op_eqm.items():
            op_eqm[op] = drop_terms_containing(eqm, unresolved_ops)

    # in python 3.6+ dictionaries are sorted
    op_eqm = {op: op_eqm[op] for op in operator_sort_by_order(op_eqm.keys())}
    return op_eqm, unresolved_ops
Exemple #2
0
def extract_operator_products(e, independent=False):
    """
    Return a list of unique normal-ordered quantum operator products in the
    expression e.
    """
    ops = []

    if isinstance(e, Operator):
        ops.append(e)

    elif isinstance(e, Add):
        for arg in e.args:
            ops += extract_operator_products(arg, independent=independent)

    elif isinstance(e, Mul):
        c, nc = e.args_cnc()
        if nc: ops.append(Mul(*nc))
    else:
        if debug:
            print("Unrecongized type: %s: %s" % (type(e), str(e)))

    no_ops = []
    for op in ops:
        no_op = normal_ordered_form(op.expand(), independent=independent)
        if isinstance(no_op, (Mul, Operator, Pow)):
            no_ops.append(no_op)
        elif isinstance(no_op, Add):
            no_ops += extract_operator_products(no_op, independent=independent)
        else:
            raise ValueError("Unsupported type in loop over ops: %s: %s" %
                             (type(no_op), no_op))

    return list(set(no_ops))
Exemple #3
0
def test_normal_ordered_form():
    a = BosonOp("a")

    c = FermionOp("c")

    assert normal_ordered_form(Dagger(a) * a) == Dagger(a) * a
    assert normal_ordered_form(a * Dagger(a)) == 1 + Dagger(a) * a
    assert normal_ordered_form(a**2 * Dagger(a)) == 2 * a + Dagger(a) * a**2
    assert normal_ordered_form(a**3 * Dagger(a)) == 3 * a**2 + Dagger(a) * a**3

    assert normal_ordered_form(Dagger(c) * c) == Dagger(c) * c
    assert normal_ordered_form(c * Dagger(c)) == 1 - Dagger(c) * c
    assert normal_ordered_form(c**2 * Dagger(c)) == Dagger(c) * c**2
    assert normal_ordered_form(c**3 * Dagger(c)) == c**2 - Dagger(c) * c**3
Exemple #4
0
def test_normal_ordered_form():
    a = BosonOp('a')

    c = FermionOp('c')

    assert normal_ordered_form(Dagger(a) * a) == Dagger(a) * a
    assert normal_ordered_form(a * Dagger(a)) == 1 + Dagger(a) * a
    assert normal_ordered_form(a ** 2 * Dagger(a)) == \
        2 * a + Dagger(a) * a ** 2
    assert normal_ordered_form(a ** 3 * Dagger(a)) == \
        3 * a ** 2 + Dagger(a) * a ** 3

    assert normal_ordered_form(Dagger(c) * c) == Dagger(c) * c
    assert normal_ordered_form(c * Dagger(c)) == 1 - Dagger(c) * c
    assert normal_ordered_form(c ** 2 * Dagger(c)) == Dagger(c) * c ** 2
    assert normal_ordered_form(c ** 3 * Dagger(c)) == \
        c ** 2 - Dagger(c) * c ** 3
Exemple #5
0
def qsimplify(e_orig, _n=0):
    """
    Simplify an expression containing operators.
    """
    if _n > 15:
        warnings.warn("Too high level or recursion, aborting")
        return e_orig

    e = normal_ordered_form(e_orig)

    if isinstance(e, Add):
        return Add(*(qsimplify(arg, _n=_n+1) for arg in e.args))

    elif isinstance(e, Pow):
        return Pow(*(qsimplify(arg, _n=_n+1) for arg in e.args))

    elif isinstance(e, exp):
        return exp(*(qsimplify(arg, _n=_n+1) for arg in e.args))

    elif isinstance(e, Mul):
        args1 = tuple(arg for arg in e.args if arg.is_commutative)
        args2 = tuple(arg for arg in e.args if not arg.is_commutative)
        #x = 1
        #for y in args2:
        #    x = x * y

        x = 1
        for y in reversed(args2):
            x = y * x

        if isinstance(x, Mul):
            args2 = x.args
            x = 1
            for y in args2:
                x = x * y

        e_new = simplify(Mul(*args1)) * x

        if e_new == e:
            return e
        else:
            return qsimplify(e_new.expand(), _n=_n+1)

    if e == e_orig:
        return e
    else:
        return qsimplify(e, _n=_n+1).expand()
def test_normal_ordered_form():
    a = BosonOp('a')
    b = BosonOp('b')

    c = FermionOp('c')
    d = FermionOp('d')

    assert normal_ordered_form(Dagger(a) * a) == Dagger(a) * a
    assert normal_ordered_form(a * Dagger(a)) == 1 + Dagger(a) * a
    assert normal_ordered_form(a ** 2 * Dagger(a)) == \
        2 * a + Dagger(a) * a ** 2
    assert normal_ordered_form(a ** 3 * Dagger(a)) == \
        3 * a ** 2 + Dagger(a) * a ** 3

    assert normal_ordered_form(Dagger(c) * c) == Dagger(c) * c
    assert normal_ordered_form(c * Dagger(c)) == 1 - Dagger(c) * c
    assert normal_ordered_form(c ** 2 * Dagger(c)) == Dagger(c) * c ** 2
    assert normal_ordered_form(c ** 3 * Dagger(c)) == \
        c ** 2 - Dagger(c) * c ** 3
Exemple #7
0
def extract_all_operators(e_orig):
    """
    Extract all unique operators in the normal ordered for of a given
    operator expression, including composite operators. The resulting list
    of operators are sorted in increasing order.
    """
    if debug:
        print("extract_all_operators: ", e_orig)

    if isinstance(e_orig, Operator):
        return [e_orig]

    e = drop_c_number_terms(
        normal_ordered_form(e_orig.expand(), independent=True))

    if isinstance(e, Pow) and isinstance(e.base, Operator):
        return [e]

    ops = []

    if isinstance(e, Add):
        for arg in e.args:
            ops += extract_all_operators(arg)

    if isinstance(e, Mul):
        op_f = [
            f for f in e.args if (isinstance(f, Operator) or (
                isinstance(f, Pow) and isinstance(f.base, Operator)))
        ]
        ops.append(Mul(*op_f))
        ops += op_f

    unique_ops = list(set(ops))

    sorted_unique_ops = sorted(unique_ops, key=operator_order)

    return sorted_unique_ops
Exemple #8
0
def bch_expansion(A,
                  B,
                  N=6,
                  collect_operators=None,
                  independent=False,
                  expansion_search=True):

    # Use BCH expansion of order N

    if debug:
        print("bch_expansion: ", A, B)

    cno = split_coeff_operator(A)
    if isinstance(cno, list):
        nvar = len(cno)
        c_list = []
        o_list = []
        for n in range(nvar):
            c_list.append(cno[n][0])
            o_list.append(cno[n][1])
    else:
        nvar = 1
        c_list, o_list = [cno[0]], [cno[1]]

    if debug:
        print("A coefficient: ", c_list)

    rep_list = []
    var_list = []

    for n in range(nvar):
        rep_list.append(Dummy())

        coeff, sym = c_list[n].as_coeff_Mul()
        if isinstance(sym, Mul):
            sym_ = simplify(sym)
            if I in sym_.args:
                var_list.append(sym_ / I)
            elif any([isinstance(arg, exp) for arg in sym_.args]):
                nexps = Mul(
                    *[arg for arg in sym_.args if not isinstance(arg, exp)])
                exps = Mul(*[arg for arg in sym_.args if isinstance(arg, exp)])

                if I in simplify(exps).exp.args:
                    var_list.append(nexps)
                else:
                    var_list.append(sym_)
            else:
                var_list.append(sym_)
        else:
            var_list.append(sym)

    A_rep = A.subs({var_list[n]: rep_list[n] for n in range(nvar)})

    e_bch_rep = _bch_expansion(A_rep, B, N=N).doit(independent=independent)

    if debug:
        print("simplify: ")

    e = qsimplify(
        normal_ordered_form(e_bch_rep.expand(),
                            recursive_limit=25,
                            independent=independent).expand())
    if debug:
        print("extract operators: ")

    ops = extract_operator_products(e, independent=independent)

    # make sure that product operators comes first in the list
    ops = list(reversed(sorted(ops, key=lambda x: len(str(x)))))

    if debug:
        print("operators in expression: ", ops)

    if collect_operators:
        e_collected = collect(e, collect_operators)
    else:
        e_collected = collect(e, ops)

    if debug:
        print("search for series expansions: ", expansion_search)

    if debug:
        print("e_collected: ", e_collected)

    if expansion_search and c_list:
        e_collected = _expansion_search(e_collected, rep_list, N)
        e_collected = e_collected.subs(
            {rep_list[n]: var_list[n]
             for n in range(nvar)})

        return e_collected
    else:
        return e_collected.subs(
            {rep_list[n]: var_list[n]
             for n in range(nvar)})
Exemple #9
0
def bch_expansion(A,
                  B,
                  N=6,
                  collect_operators=None,
                  independent=False,
                  expansion_search=True):

    # Use BCH expansion of order N
    if debug: print("bch_expansion: A =", A, "   B =", B)

    A = A.expand()

    if isinstance(A, Add):
        args = A.args
    else:
        args = [A]
    cnc = [arg.args_cnc() for arg in args]
    c_list, o_list = zip(*[(Mul(*c), Mul(*nc)) for c, nc in cnc])

    if debug: print("A coefficient: ", c_list, "    A operator: ", o_list)

    var_list = []
    for coeff, sym in (c.as_coeff_Mul() for c in c_list):
        if isinstance(sym, Mul):
            sym_ = simplify(sym)
            if I in sym_.args:
                var_list.append(sym_ / I)
            elif any([isinstance(arg, exp) for arg in sym_.args]):
                nexps = Mul(*[a for a in sym_.args if not isinstance(a, exp)])
                exps = Mul(*[a for a in sym_.args if isinstance(a, exp)])

                if I in simplify(exps).exp.args:
                    var_list.append(nexps)
                else:
                    var_list.append(sym_)
        else:
            var_list.append(sym)

    rep_list = [Dummy() for _ in range(len(var_list))]
    A_rep = A.subs({var_list[i]: rep_list[i] for i in range(len(var_list))})
    if debug: print("A_rep: ", A_rep)

    e_bch_rep = _bch_expansion(A_rep, B, N=N).doit(independent=independent)

    e = qsimplify(
        normal_ordered_form(e_bch_rep.expand(),
                            recursive_limit=25,
                            independent=independent).expand())
    if debug: print("simplify: ", e)

    ops = extract_operator_products(e, independent=independent)
    if debug: print("extract operators: ", ops)

    # make sure that product operators comes first in the list
    ops = list(reversed(sorted(ops, key=lambda x: len(str(x)))))
    if debug: print("operators in expression: ", ops)

    if collect_operators:
        e_collected = qcollect(e, collect_operators)
    else:
        e_collected = qcollect(e, ops)
    if debug: print("e_collected: ", e_collected)

    if debug: print("search for series expansions: ", expansion_search)
    if expansion_search and rep_list:
        e_collected = _expansion_search(e_collected, rep_list, N)

    return e_collected.subs(
        {rep_list[i]: var_list[i]
         for i in range(len(var_list))})
Exemple #10
0
def semi_classical_eqm(H, c_ops, max_order=2, discard_unresolved=True):
    """
    Generate a set of semiclassical equations of motion from a Hamiltonian
    and set of collapse operators. Equations of motion for all operators that
    are included in either the Hamiltonian or the list of collapse operators
    will be generated, as well as any operators that are included in the
    equations of motion for the orignal operators. If the system of equations
    for the averages of operators does not close, the highest order operators
    will be truncated and removed from the equations.
    """
    op_eqm = {}

    ops = extract_all_operators(H + sum(c_ops))

    if debug:
        print("Hamiltonian operators: ", ops)

    t = symbols("t", positive=True)

    while ops:
        order, idx = min(
            (val, idx)
            for (idx, val) in enumerate([operator_order(op) for op in ops]))
        if order > max_order: break
        op = ops.pop(idx)

        lhs, rhs = operator_master_equation(op, t, H, c_ops, use_eq=False)

        op_eqm[op] = qsimplify(
            normal_ordered_form(rhs.doit(independent=True).expand(),
                                independent=True))

        new_ops = extract_all_operators(op_eqm[op])

        for new_op in new_ops:
            if ((not new_op.is_Number) and new_op not in op_eqm.keys()
                    and new_op not in ops):
                if debug:
                    print(new_op, "not included, adding")
                ops.append(new_op)

    if debug:
        print("unresolved ops: ", ops)

    if discard_unresolved:
        for op, eqm in op_eqm.items():
            op_eqm[op] = drop_terms_containing(op_eqm[op], ops)
        ops_unresolved = []
    else:
        ops_unresolved = ops

    #for op, eqm in op_eqm.items():
    #    for o in extract_all_operators(eqm):
    #        if o not in op_eqm.keys():
    #            print("unresolved operator: %r" % o)

    op_factorization = {}
    sc_eqm = {}
    for op, eqm in op_eqm.items():
        ops = extract_all_operators(eqm)
        sc_eqm[op] = Expectation(eqm).expand(expectation=True)

        for op2 in ops_unresolved:
            if op2 not in op_eqm.keys():
                # need to factor op2
                sub_ops = _sceqm_factor_op(op2, op_eqm.keys())
                factored_expt = Mul(*(Expectation(o) for o in sub_ops))
                op_factorization[Expectation(op2)] = factored_expt
                sc_eqm[op] = sc_eqm[op].subs(Expectation(op2), factored_expt)

    op_func_map = {}
    op_index_map = {}
    for n, op in enumerate(op_eqm):
        op_func_map[op] = Function("A%d" % n)(t)
        op_index_map[op] = n

    if debug:
        print("Operator -> Function map: ", op_func_map)

    sc_ode = {}
    for op, eqm in sc_eqm.items():
        sc_ode[op] = Eq(
            Derivative(_operator_to_func(Expectation(op), op_func_map), t),
            _operator_to_func(eqm, op_func_map))

    ops = operator_sort_by_order(op_func_map.keys())

    #for eqm in op_eqm:
    #    eqm_ops = extract_all_operators(op_eqm[op])

    SemiClassicalEQM = namedtuple('SemiClassicalEQM', [
        'operators', 'operators_unresolved', 'operator_eqs',
        'operator_factorization', 'sc_eqs', 'sc_ode', 'op_func_map',
        'op_index_map', 't'
    ])

    return SemiClassicalEQM(ops, ops_unresolved, op_eqm, op_factorization,
                            sc_eqm, sc_ode, op_func_map, op_index_map, t)