Exemple #1
0
def fermion_propagator():
    """ Calculate expression for first-order corrected fermion propagator. """

    latex = Latex()

    # 1. Write out amplitude  TODO include regulator terms
    m = []

    ind = "\sigma_1"
    sum_terms = [Sub("p", ind), C("m")]
    m.append(Frac(Prod([Sum(sum_terms), Gamma(ind)]), Term("p^2 - m^2 + i\\epsilon")))

    m.append(Integral("k", norm=True))
    m.append(I())
    m.append(C("e"))
    m.append(Term("\\gamma^\\mu"))

    ind = "\sigma_2"
    sum_terms = [Sub("p", ind), Sub("(-k)", ind), C("m")]
    m.append(Frac(Prod([Sum(sum_terms), Gamma(ind)]), Term("(p - k)^2 - m^2 + i\\epsilon")))
    m.append(I())
    m.append(C("e"))
    m.append(Term("\\gamma^\\nu"))
    m.append(Term("D_{\\mu \\nu}(k)"))

    ind = "\sigma_3"
    sum_terms = [Sub("p", ind), C("m")]
    m.append(Frac(Prod([Sum(sum_terms), Gamma(ind)]), Term("p^2 - m^2 + i\\epsilon")))

    latex.add(" ".join([t.latex() for t in m]))

    # 2. Use Feynman parameterization to rewrite propagators
    m_ = []
    ds = []
    for term in m:
        if term.is_fraction():
            # TODO
            m_.append(term.numer)
            ds.append(term.denom)
        else:
            m_.append(term)

    # Integrals
    for i, d in enumerate(ds):
        a = Term("0")
        b = Term("1" + "".join([" - z_{0}".format(j + 1) for j in range(i)]))
        m_.append(Integral("z_{0}".format(i+1), norm=True, limits=(a, b)))

    # Frac
    denom = ""
    denom += "\\left["
    ds_ = []
    for i, d in enumerate(ds):
        ds_.append("\\left(" + d.latex() + "\\right) " + "z_{0}".format(i + 1))
    denom += " + ".join(ds_)
    denom += "\\right]"
    denom += "^{0}".format(len(ds))
    frac = Frac(Term("1"), Term(denom))
    m_.append(frac)

    m = m_
    latex.add(" ".join([t.latex() for t in m]))

    # 3. Distribute numerators (p + m) ish terms
    # 4. Solve each internal momenta integral
    # 5. Move terms independent of z's to left
    # 6. Groan.  Solve.
    # 7. Solve remaining integrals, contract metrics, etc.
    # 8. (OPTIONAL) Evaluate traces for non-Abelian theories.

    latex.render()
Exemple #2
0
def calculate(config_str, internal_momenta):
    """ Calculate expression for configuration. """

    latex = Latex()

    ################################################
    ########     CONSTRUCT AMPLITUDE      ##########
    ################################################

    try:
        internal_momenta = internal_momenta.split()
        config, amp = make_amplitude(config_str, internal_momenta)
    except:
        raise ParseException("Error while parsing.")

    # Render
    latex.add_text("\\section*{Raw amplitude}")
    amp.latex_add(latex)
    if RENDER_ALL:
        latex.render()

    ################################################
    ########   SIMPLIFY NUMERATOR         ##########
    ################################################

    amp.numer = amp.numer.expand()

    # Render
    latex.add_text("\\section*{Simplified numerator}")
    amp.latex_add(latex)
    if RENDER_ALL:
        latex.render()

    ################################################
    ########      FEYNMAN'S TRICK         ##########
    ################################################

    denom_ = []
    for arg in amp.denom.args:
        if type(arg) == sy.Pow:
            base, power = arg.args
            for _ in range(power):
                denom_.append(base)
        else:
            denom_.append(arg)

    n = len(denom_)
    amp.const *= gamma(n)

    zs = [sy.Symbol("{{ z_{{ {0} }} }}".format(i + 1)) for i in range(n)]
    amp.denom = sum([d * z for (d, z) in zip(denom_, zs)]).expand()**n
    for i, z in enumerate(zs):
        a = 0
        b = 1 - sum(zs[:i])
        amp.integrals_zs.append((z, a, b))

    # Render
    latex.add_text("\\section*{Feynman parameterization}")
    latex.add_text("Here, we perform the following expansion:")
    latex.add_text("""$$
    \\frac{1}{A_1} \\cdots \\frac{1}{A_n} = (n-1)! \\int\\limits_0^1 dz_1
                                                   \\int\\limits_0^{1-z_1} dz_2
                                                   \\cdots
                                                   \\int\\limits_0^{1-z_1-\\cdots-z_{n-1}} dz_n
                                                   \\frac{1}{(z_1 A_1 + \\cdots + z_n A_n)^n}
    $$""")
    latex.add_text(
        "We use this form because a single denominator raised to a power can be simplified with the Golden Integral."
    )
    amp.latex_add(latex)
    if RENDER_ALL:
        latex.render()

    ################################################
    ######## SPLIT NUMERATOR INTO TERMS   ##########
    ################################################
    amps = []
    for numer_ in sy.Add.make_args(amp.numer):
        amp_ = amp.copy()
        amp_.numer = numer_
        amps.append(amp_)

    # Render
    latex.add_text("\\section*{Expanded numerator}")
    latex.add_text(
        "We split the numerator into additive terms, to process individually.  The following is a list of such terms:"
    )
    for amp_ in amps:
        amp_.latex_add(latex)
    if RENDER_ALL:
        latex.render()

    ################################################
    ########     EVAL. INTERNAL MOMENTA   ##########
    ################################################

    # TODO evaluate internal momenta integrals
    # At this point we stop with numer and denom and combine them into
    # one expression, `inner`, which is a sum of fractions.
    # TODO update this comment

    # Render an explanation
    latex.add_text("\\section*{{Golden Integral}}")
    latex.add_text("We resolve internal momentas with this transformation:")
    latex.add_text("""
    $$\\int \\frac{d^d q}{(2 \pi)^d} \\frac{(q^2)^a}{(q^2 + D)^b} = i \\frac{\\Gamma (b-a-\\frac{1}{2}d) \\Gamma (a + \\frac{1}{2} d)}{(4 \\pi)^{d/2} \\Gamma(b) \\Gamma(\\frac{1}{2}d)} D^{-(b-a-d/2)}$$
    """)
    latex.add_text(
        "After this section, all internal momenta should disappear.  We will now resolve each term in a queue.  Each term may produce additional terms, which are pushed to the back of the queue and resolved later."
    )

    integrated_amps = []

    #for i, amp_ in enumerate(amps):
    i = 0
    while len(amps) > 0:
        # Pop off one amplitude
        amp_ = amps[0]
        amps = amps[1:]
        i += 1

        latex.add_text(
            "\\section*{{Evaluating internal momenta in this term ({0} terms left)}}"
            .format(len(amps)))
        amp_.latex_add(latex)
        if RENDER_ALL:
            latex.render()

        # Find an internal momenta
        if len(amp_.integrals_internal) > 0:
            (k, _, _) = amp_.integrals_internal[0]
            latex.add_text("Integrating over ${0}$\\\\".format(k))

            # TODO cleanup weird namespacing
            k_down_dummy = Momentum(k, "DUMMY", 0)
            k_up_dummy = Momentum(k, "DUMMY", 1)
            k2_dummy = k_down_dummy * k_up_dummy

            # Decompose denominator
            # denom = denom_nopow ^ b
            denom_nopow, b = amp_.denom.args[0], amp_.denom.args[1]

            # Completing the square
            # Denominator is always quadratic in momenta
            G = denom_nopow  # aliasing for convenience

            latex.add_text("Completing the square\\")

            A = G.collect(k2_dummy).coeff(k2_dummy)
            G = sy.simplify(G - A * k2_dummy)
            B_up = G.collect(k_down_dummy).coeff(k_down_dummy)
            B_down = G.collect(k_up_dummy).coeff(k_up_dummy)
            B = B_up + Amplitude.flip_variant(B_down)
            G = sy.simplify(G - B_up * k_down_dummy - B_down * k_up_dummy)
            C = G
            D = -(B_up * Amplitude.flip_variant(B_up)) / (4 * A) + C

            latex.add("A = " + latex.get(A))
            latex.add("B = " + latex.get(B))
            latex.add("C = " + latex.get(C))
            """ 
                The denominator is in the form:

                    A k^2 + Bk + C

                We define a new variable, q, such that

                    q = A^(1/2) k + B / (2 A^(1/2))

                and replace k:

                    k = q / A^(1/2) - B / (2A)
                    d^d k = (1 / A^(1/2)) d^d q

                The substitution k -> q yields:

                    A k^2 + Bk + C |-> q^2 + D

                where we define D = C - B^2 / (4A)
            """

            # Prepare to replace numerator
            k_name = k
            q_name = "q_{0}".format(len(amp_.qs) + 1)  # TODO sloppy af
            amp_.qs.append(q_name)

            q_up = Momentum(q_name, "DUMMY", 1)
            q_down = Momentum(q_name, "DUMMY", 0)

            any_name = sy.Wild("a")
            any_ind = sy.Wild("b")
            any_variant = sy.Wild("c")

            any_B_up = B_up.replace(Momentum(any_name, "DUMMY", any_variant),
                                    Momentum(any_name, any_ind, any_variant))
            any_B_down = Amplitude.flip_variant(any_B_up)

            # Actually replace numerator
            amp_.numer = amp_.numer.replace(
                Momentum(k_name, any_ind, 1),
                Momentum(q_name, any_ind, 1) / (A**0.5) - any_B_up / (2 * A))

            amp_.numer = amp_.numer.replace(
                Momentum(k_name, any_ind, 0),
                Momentum(q_name, any_ind, 0) / (A**0.5) - any_B_down / (2 * A))

            amp_.numer = sy.simplify(amp_.numer)

            # Replace denominator
            amp_.denom = (q_down * q_up + D)**b

            # Replace integral
            # TODO replace integral
            amp_.integrals_internal[0] = (q_name, _, _)
            amp_.numer /= A**0.5

            latex.add_text("After ${0} \\to {1}$ substitutions".format(
                k_name, q_name))
            amp_.latex_add(latex)
            if RENDER_ALL:
                latex.render()

            # Expand the numerator into different amplitudes and multiply them
            # back in the end
            amps__ = []
            for numer in sy.Add.make_args(amp_.numer.expand()):
                new_amp = amp_.copy()
                new_amp.numer = numer
                amps__.append(new_amp)

            # Render
            latex.add_text(
                "\\section*{{Expanding numerator into {0} term(s)}}".format(
                    len(amps__)))
            for amp__ in amps__:
                amp__.latex_add(latex)
            if RENDER_ALL:
                latex.render()

            # Finish q_name integration for each amplitude separately
            for amp__ in amps__:
                prod = sy.Mul.make_args(amp__.numer)

                # Get k-vectors
                # TODO Figure out a way to collect qs nicely
                qs = [
                    q for q in prod
                    if isinstance(q, Momentum) and q.args[0].name == q_name
                ]

                latex.add_text("\\subsection*{Integrating this term:}")
                amp__.latex_add(latex)
                latex.add_text(
                    "Found {0} q-vector terms in the numerator.\\\\".format(
                        len(qs)))

                # Simplify q vectors

                # Ward identity for odd tensors
                if len(qs) % 2 == 1:
                    # TODO integral evaluates to zero
                    latex.add_text("Term vanishes due to Ward identity\\\\")
                    amp__.const = 0
                    continue

                if len(qs) > 0:
                    # TODO convert higher-order even tensor integral to
                    #      scalar integral
                    pass
                else:
                    # TODO Assume a = 0 for now
                    # This is obviously wrong in general but will be easier
                    # to fix with a good test case
                    a = 0

                    # Golden integral
                    #c, a = term.as_coeff_exponent(sy.Symbol(k2))
                    c_ = sy.I * gamma(b - a -
                                      (4 - EPS) / 2) * gamma(a + (4 + EPS) / 2)
                    c_ /= gamma(b)
                    c_ /= (4 * sy.pi)**2
                    # Part of the Golden integral d^q factor
                    c_ *= (2 * sy.pi)**4
                    amp__.const *= c_

                    amp__.denom = D**(b - a - 2
                                      )  # TODO generalize to d-dimensions
                    # with 2 -> D / 2

                    # Add to amps if nonzero
                    amps.append(amp__)

                    # Remove internal integral
                    amp__.integrals_internal = amp__.integrals_internal[1:]

                    # Render
                    latex.add_text("Apply golden integral")
                    amp__.latex_add(latex)
                if RENDER_ALL:
                    latex.render()
        else:
            integrated_amps.append(amp_)

        ## Compress inners by term
        #inners_dict = {}
        #for (c_, expr_) in amp.inners:
        #    if expr_ not in inners_dict:
        #        inners_dict[expr_] = 0
        #    inners_dict[expr_] += c_
        #amp.inners = [(v, k) for (k, v) in inners_dict.items()]
        #amp.latex_add2(latex)

    amps = integrated_amps

    latex.add_text("\\section*{Final amplitudes after momenta integration}")
    for amp_ in amps:
        amp_.latex_add(latex)

    if RENDER_ALL:
        latex.render()

    ##########################################
    ########  CUTOFF INTEGRATIONS   ##########
    ##########################################
    latex.add_text("\\section*{Integrating cutoffs}")
    latex.add_text(
        "Here we integrate all $t$-variables, which represent the upper and lower cutoffs."
    )
    uv = sy.Symbol(config["Lamb"])

    integrated_amps = []

    for amp_ in amps:
        latex.add_text("\\subsection*{Integrating this term}")
        amp_.latex_add(latex)

        expr_ = 1 / amp_.denom

        latex.add_text("Denominator only")
        latex.add(latex.get(expr_))
        if RENDER_ALL:
            latex.render()

        # Integrate cutoffs
        for (t, a, b) in amp_.integrals_cutoffs:
            # Integrate w.r.t. cutoff
            expr_ = sy.integrate(expr_, (t, a, b))

            latex.add_text("Integrating wrt ${0}$...".format(t))
            latex.add(latex.get(expr_))
            if RENDER_ALL:
                latex.render()

            # Collecting highest order term
            old_expr = expr_
            while True:
                old_expr = expr_

                expr_ = sy.expand_log(expr_, force=True)
                expr_ = get_highest_log_term(expr_, uv)
                expr_ = sy.simplify(expr_)

                if old_expr == expr_:
                    # No more changes
                    break

            latex.add_text("Keeping only highest order term...")
            latex.add(latex.get(expr_))
            if RENDER_ALL:
                latex.render()

            amp_.numer *= expr_
            amp_.denom = 1

        amp_.integrals_cutoffs = []
        integrated_amps.append(amp_)

    amps = integrated_amps

    ######################################
    ########   Z INTEGRATIONS   ##########
    ######################################
    latex.add_text("\\section*{Integrating $z$-variables}")
    latex.add_text(
        "Here we integrate all $z$-variables, the Feynman parameters.")

    integrated_amps = []

    for amp_ in amps:
        latex.add_text("\\subsection*{Integrating this term}")
        amp_.latex_add(latex)

        # Integrate cutoffs
        expr_ = amp_.numer

        for (z, a, b) in amp_.integrals_zs[::-1]:
            # Integrate w.r.t. cutoff
            # Rationalize decimal powers first, or sympy breaks
            expr_ = sy.nsimplify(expr_, tolerance=0.001, rational=True)
            expr_ = sy.integrate(expr_, (z, a, b))

            latex.add_text("Integrating wrt ${0}$...".format(z))
            latex.add(latex.get(expr_))
            if RENDER_ALL:
                latex.render()

        amp_.numer = expr_
        amp_.integrals_zs = []

        integrated_amps.append(amp_)

    amps = integrated_amps

    latex.add_text(
        "\\section*{Final amplitudes after $z$-variable integration}")
    for amp_ in amps:
        amp_.latex_add(latex)

    if RENDER_ALL:
        latex.render()

    ################################################
    ########  EVALUATE SPINS AND GAMMAS   ##########
    ################################################

    latex.add_text("\\section*{Evaluating spins and gamma matrices}")
    #latex.add_text("TODO jk do it yourself you slags, here's the sum, have fun.  Don't forget to take traces/multiply by -1 for internal fermion loops.")
    latex.add_text("TODO.  Here's the sum for now:")

    latex.add("\\; + \\;".join([amp_.get_latex(latex) for amp_ in amps]))

    if RENDER_ALL:
        latex.render()

    ################################################
    ########            RENDER            ##########
    ################################################

    #amp.latex_add2(latex)
    latex.render()

    return "\\; + \\;".join([amp_.get_latex(latex) for amp_ in amps])