Overview

Creation of models

Note

This section assumes that the classes and functions from matchingtools.operators that it uses are in the namespace. To import all the classes and functions that appear here do:

from matchingtools.operators import (
    Tensor, Operator, OperatorSum
    TensorBuilder, FieldBuilder, D, Op, OpSum,
    number_op, power_op)

The construction of a model is done in two steps: the creation of the tensors and fields and the definition of the interaction Lagrangian.

The basic building block for a Lagrangian is tensor, an object of the class Tensor. Direct usage of the Tensor constructor obscures the code. There are two classes defined to make the process of creating tensors easier and cleaner, TensorBuilder and FieldBuilder.

When a field has covariant derivatives applied to it, that is represented internally in the attributes of its representative Tensor object. For aesthetical reasons and easeness of usage, instead of manually modifying the attributes, it’s better to use the function D to create covariant derivatives of fields.

MatchingTools handles Lagrangians that are polynomials of the fields. They are thus a sum of terms that are products of tensors. They are represented as OperatorSum objects, with only one attribute: a list of its terms. Each term should be an operator, that is, a product of tensors represented by an Operator object with only one attribute: a list of its factors.

Instead of using the constructors for both classes, the functions OpSum and Op are available to make the definitions clearer.

Minus signs are defined in the library for operators ( Operator.__minus__()) and operator sums (OperatorSum.__minus__()). Multiplication * is defined for operators too (as the concatenation of the tensors they contain, see Operator.__mul__()).

MatchingTools treats in a special way tensors whose name starts and ends with square or curly brakets. A tensor name enclosed in square brakets is understood as a (complex) number to be read from the name using float(name[1:-1]). The function number_op() is to be used to create operators with such tensors inside.

When the name of a tensor starts and ends with curly brakets it’s it represents some symbolic constant that appears exponentiated. The name should be of the form "{base^exponent}". Curly brakets allow for the summation of the exponents of tensors that appear in the same tensor and have the same base and indices. This is used mainly to produce more readable results. The function designed to create operators containing such tensors is power_op().

Creation of tensors

Create a tensor as:

my_tensor = TensorBuilder("my_tensor")

and then use it inside an operator:

Op(..., my_tensor(ind1, ind2, ...), ...)

with ind1, ind2, … being integers.

Creation of fields

Create a field as:

my_field = FieldBuilder("my_field", dimension, statistics)

where dimension (float) represents the energy dimensions of the field and statistics is either equal to matchingtools.algebra.boson or matchingtools.algebra.fermion. Then use it inside an operator:

Op(..., my_field(ind1, ind2, ...), ...)

with ind1, ind2, … being integers.

Definition of the Lagrangian

Define the interaction Lagrangian as an operator sum:

int_lag = OpSum(op1, op2, ...)

Each argument to the function matchingtools.operators.OpSum() should be an operator defined as:

op1 = Op(tens1(ind1, ind2, ...), field1(ind3, ind4, ...), ...)

The arguments of the function matchingtools.operators.Op() are tensors (and fields). Their indices are integer numbers. Negative integers are reserved for free indices. Free indices are not meant to be used in the operators appearing in the Lagrangian, but later in the definition of their transformations.

Non-negative integers represent contracted indices. Contraction is expressed by repetition of indices.

To introduce the covariant derivative with index ind of a tensor tens inside an operator, use the function matchingtools.operators.D() in the following way:

D(ind, tens(ind1, ind2, ...))

If a numeric coefficient num is needed for some operator op it can be introduced as:

number_op(num) * op

A symbolic constant s to some power p can multiply an operator as:

power_op("s", p) * op

Integration

Note

This section assumes that the classes and functions from matchingtools.integration that it uses are in the namespace. To import all the classes and functions that appear here do:

from matchingtools.integration import (
    RealScalar, ComplexScalar, RealVector, ComplexVector,
    VectorLikeFermion, MajoranaFermion, integrate)

To integrate some heavy fields out of a previously constructed Lagrangian the heavy fields should be specified first. The heavy fields should be objects of any of the following classes:

Create a heavy field using the constructors of these classes.

heavy_field = HeavyFieldClass("field_name", ...)

Then collect the heavy fields in a list and use the function integrate() to perform the integration:

heavy_fields = [heavy_field_1, heavy_field_2, ...]
eff_lag = integrate(heavy_fields, int_lag, max_dim=...)

Transformations of the effective Lagrangian

Note

This section assumes that the functions from matchingtools.transformations and matchingtools.transformations that it uses are in the namespace. To import all the functions that appear here do:

from matchingtools.operators import tensor_op, flavor_tensor_op

from matchingtools.transformations import (
    simplify, apply_rules)

An effective Lagrangian obtained from integration of heavy fields usually contains operators that aren’t independent. Several transformations can be applied to them to write the Lagrangian in terms of a set of operators (a basis) that spans the space of effective operators.

These transformations are such as Fierz identities or substitutions of the equations of motion of the light particles. All of them consist of the subsitution of operators or parts of them by sums of other operators. The operations described in this section applied to effective Lagrangians or to any other kind of operators sum.

The first step to simplify an effective Lagrangian is to collect and multiply numeric coefficients and constant tensors that appear several times inside the same operator. To do this, use:

simplified_lag_1 = simplify(effective_lagrangian)

Then we can define a set of rules as a list of pairs (pattern, replacement) where pattern is an operator and replacement is an operator sum:

rules = [(Op(...), OpSum(...)), (Op(...), OpSum(...)), ...]

pattern may contain tensors with negative indices corresponding to indices that are not contracted inside pattern. In that case, the operators in replacement should also contain the same negative indices. When pattern is substituted inside an operator op, the indices in op outside pattern that are contracted with indices inside pattern appear as contracted with the corresponding ones in the operators of replacement. For example, to replace \(t_{ij}r_{ik}\) by \(-s_{mnk}u_{nmj}\) we would write the rule:

(Op(t(1, -1), r(1, -2)), OpSum(-Op(s(1, 2, -2), u(2, 1, -1))))

The operators of the basis should be represented by tensor with a name identifing the operator. They can be defined using matchingtools.operators.tensor_op() when they don’t have free indices and matchingtools.operators.flavor_tensor_op() when they do. So we usually define:

Op1 = tensor_op("Op1")
Op2 = tensor_op("Op2")
...

Opf1 = flavor_tensor_op("Opf1")
Opf2 = flavor_tensor_op("Opf1")
...

and then specify how to identify them using rules:

op_def_rules = [(Op(...), OpSum(Op1)),
                (Op(...), OpSum(Op2)),
                ...
                (Op(...), OpSum(Opf1(i1, i2, ...))),
                (Op(...), OpSum(Opf2(i1, i2, ...)))
                ...]

Then we are ready to apply the rules using apply_rules():

simplified_lag_2 = apply_rules_until(
    simplified_lag_1, rules + op_def_rule, max_iter)

where max_iter is the maximum number of applications of all the rules to each operator.

Output of the results

Note

This section assumes that the class matchingtools.output.Writer that it uses is in the namespace. To import it, do:

from matchingtools.output import Writer

It’s usually convenient to organize the final results by presenting the coefficient to each operator of the effective Lagrangian. When a set of rules has been applied to the effective Lagrangian so that it is written as an matchingtools.operators.OperatorSum whose elements are matchingtools.operators.Operator objects each of which contains one tensor representing the actual operator in the basis and other tensors representing the coefficient the operator has.

To output the results in this form in a human readable format, the Writer is provided. If op_names is a list of the names of the tensors representing the operators in the basis and lag is the Lagrangian that we want to write, we do:

lag_writer = Writer(eff_lag, op_names)

To write the results to a file in plain text, just use:

lag_writer.write_text_file("filename")

To write it in LaTeX two python dictionaries expressing how the tensors that appear in the coefficients and how the name of the coefficients for the operators should be written in LaTeX:

tensors_latex = {"tensor1": r"latexrep", "tensor2": ..., ...}
ops_latex = {"op1": r"latexrep", ...}

The values of the dictionary should be code to be written inside some LaTeX equation environment. It is recommended to use r"..." instead of "..." to easily write instructions as \instr instead of the form \\instr that would be needed for the case with just "...". The placeholders for the indices should be written in python’s str.format style "{}". This implies that whenever curly braces are needed for the LaTeX code, double braces {{...}} should be used.

The symbols to de used to represent indices should be given also as a list of strings containing the LaTeX code representing them:

indices_latex = ["i", "j", ...]

Finally we can write the LaTeX document using:

lag_writer.write_latex("filename", tensors_latex, ops_latex, indices_latex)

Or we can instead use Writer.show_latex() to write it, compile it and show it all in method:

lag_writer.show_latex("filename", pdf_viewer, tensors_latex,
                      ops_latex, indices_latex)