Spinors

Spinors in General Relativity

Alfonso García-Parrado Gómez-Lobo
alfonso@math.uminho.pt
Universidade do Minho, Portugal

José M. Martín-García
jose@xact.es

(c) 2006-2021, under GPL

http://www.xAct.es/
http://groups.google.com/group/xAct

Spinors is a package for spinor computations on a curved 4d Lorentzian spacetime.

Spinors is distributed under the GNU General Public License, and runs on top of xTensor, a free package for fast manipulation of abstract tensor expressions. Both can be downloaded from http://www.xact.es/

DateList[]

xAct`Spinors`$xTensorVersionExpected={"1.1.1",{2014,9,28}};
xAct`Spinors`$Version={"1.0.6",{2021,2,28}}

1. Initialization

1.0. TODO list

1.1. GPL

(* Spinors: spinor calculus in General Relativity *)

(* Copyright (C) 2006-2020 Alfonso Garcia-Parrado Gomez-Lobo and Jose M. Martin-Garcia *)

(* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License,or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place-Suite 330, Boston, MA 02111-1307, USA. 
*)

1.2. Info package

(* :Title: Spinors *)

(* :Author: Alfonso Garcia-Parrado Gomez-Lobo and Jose M. Martin-Garcia *)

(* :Summary: spinor calculus in General Relativity *)

(* :Brief Discussion:
   - Spinors extends xAct to perform spinor computations on 4d Lorentzian spacetimes.
   - Defines spin structures, spinors, spin connections and their curvature spinors.
   - Allows conversion from tensors to spinors and viceversa.
   - The documentation explains how to construct the Newman-Penrose and
    Geroch-Held-Penrose formalism.
*)
  
(* :Context: xAct`Spinors` *)

(* :Package Version: 1.0.6 *)

(* :Copyright: Alfonso Garcia-Parrado Gomez-Lobo and Jose M. Martin-Garcia (2006-2020) *)

(* :History: See Spinors.History *)

(* :Keywords: *)

(* :Source: Spinors.nb *)

(* :Warning: *)

(* :Mathematica Version: 6.0 and later *)

(* :Limitations:
	- 4d Lorentzian spacetime only *)

1.3. BeginPackage

With[{xAct`Spinors`Private`SpinorsSymbols=DeleteCases[Join[Names["xAct`Spinors`*"],Names["xAct`Spinors`Private`*"]],"$Version"|"xAct`Spinors`$Version"|"$xTensorVersionExpected"|"xAct`Spinors`$xTensorVersionExpected"]},
Unprotect/@xAct`Spinors`Private`SpinorsSymbols;
Clear/@xAct`Spinors`Private`SpinorsSymbols;
]

If[Unevaluated[xAct`xCore`Private`$LastPackage]===xAct`xCore`Private`$LastPackage,xAct`xCore`Private`$LastPackage="xAct`Spinors`"];

xAct`xCore`Private`$LastPackage

Explicit (not hidden) import of xTensor, xPerm and xCore:

BeginPackage["xAct`Spinors`",{"xAct`xTensor`","xAct`xPerm`","xAct`xCore`"}]

If[Not@OrderedQ@Map[Last,{xAct`Spinors`$xTensorVersionExpected,xAct`xTensor`$Version}],Throw@Message[General::versions,"xTensor",xAct`xTensor`$Version,xAct`Spinors`$xTensorVersionExpected]]

Print[xAct`xCore`Private`bars]
Print["Package xAct`Spinors`  version ",xAct`Spinors`$Version[[1]],", ",xAct`Spinors`$Version[[2]]];
Print["CopyRight (C) 2006-2020, Alfonso Garcia-Parrado Gomez-Lobo and Jose M. Martin-Garcia, under the General Public License."];

We specify the context xAct`Spinors` to avoid overriding the Disclaimer of the other packages. However we need to turn off the message General:shdw temporarily:

Off[General::shdw]
xAct`Spinors`Disclaimer[]:=Print["These are points 11 and 12 of the General Public License:\n\nBECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM `AS IS´ WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\nIN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES."]
On[General::shdw]

If Spinors is not being called from other package then write this GPL short disclaimer:

If[xAct`xCore`Private`$LastPackage==="xAct`Spinors`",
Unset[xAct`xCore`Private`$LastPackage];
Print[xAct`xCore`Private`bars];
Print["These packages come with ABSOLUTELY NO WARRANTY; for details type Disclaimer[]. This is free software, and you are welcome to redistribute it under certain conditions. See the General Public License for details."];
Print[xAct`xCore`Private`bars]]

Note that symbols in the Global` context cannot be accessed right now.

$ContextPath

$Context

Established connection to external executable?

$xpermQ

Private functions of xTensor used here :
      FrozenMetricQ
      FindFreeAndDummyIndices
      TransposeDaggerPairs
      SignedVBundleOfIndex
      MakeLinearDerivative
      $MultiIndexCovDs
      SymbolRelations

1.4. Non-standard setup

Screen all dollar indices:

$PrePrint=ScreenDollarIndices;

We shall allow metric contractions everywhere:

SetOptions[ContractMetric,AllowUpperDerivatives->True]

SetOptions[MakeRule,MetricOn->All,ContractMetrics->True]

Timings will be shown if they are above 1 Second (Only for this notebook; this is not included in the package):

<<xAct/ShowTime1.m

$ShowTimeThreshold

We also read the package (this is not automatic in xCore anymore since its version 0.6.2). This is not included in the package.

<<xAct/ExpressionManipulation.m

1.5. Usage messages

(* Definition of spin structures *)
DefSpinStructure::usage="DefSpinStructure[g, VB, {A,B,C,...}, epsilon, sigma, CDe,  options] defines a spin structure on the manifold in which the metric g[-a, -b] is defined, creating the inner vbundle VB with abstract indices {A,B,C,...}. Currently it only works on 4-dimensional Lorentzian manifolds, and so VB is defined as 2-dimensional and complex. The spin metric is epsilon[-A, -B] and the soldering form is sigma[a, -B, -B†]. The spin covariant derivative CDe,  compatible with sigma and epsilon, is defined on this vbundle extending the Levi-Civita connection of g. We adopt the convention of taking the head of the soldering form as the symbol representing the spin structure.";
UndefSpinStructure::usage="UndefSpinStructure[sp] removes the spin structure associated to the symbol sp and all its dependent objects (servants). The symbol sp can be the soldering form, the vector bundle or the extended covariant derivative.";
$SolderingForms::usage="$SolderingForms is a list containing the set of soldering forms (spin structures) existing in the session.";
SpinorPrefix::usage="SpinorPrefix is an option for DefSpinStructure giving the symbol to be prepended when constructing the spinor equivalent of a tensor or viceversa. By default it is Identity, which is replaced by the soldering form defined with the SpinStructure. SpinorPrefix[sigma] stores that symbol as an upvalue for the soldering form sigma.";
SpinorMark::usage="SpinorMark is an option for DefSpinStructure specifying how to modify the PrintAs string of a tensor when constructing its spinor equivalent. It can be a string (to be prepended to the  PrintAs string) or a function (acting on it). By default it is PrintAs, which is replaced by a delayed call to PrintAs[sigma] for the soldering form sigma. SpinorMark[sigma] stores the value of the option as an upvalue for the soldering form sigma.";
DefSpinor::usage="DefSpinor is a renaming of DefTensor with the option Dagger->Complex, for the sake of clarity.";
UndefSpinor::usage="UndefSpinor is a renaming of UndefTensor, for the sake of clarity.";
Sigma::usage="Sigma[sigma] is automatically transformed into the symbol Sigmasigma, where sigma is a soldering form. The symbol Sigmasigma is the head used to represent the quantity sigma[a,-A,-A†]sigma[b,-B,A†] which often appears in the transformation of spinor expressions into tensor ones.";
PrintDaggerAs::usage="PrintDaggerAs is an optional function for DefSpinor that specifies how the PrintAs string for the complex conjugate spinor should be generated from the PrintAs string for the original spinor.";
AddDagger::usage="Built-in option value for PrintDaggerAs. This option value simply appends the $DaggerCharacter to the string chosen for PrintAs.";
AddBar::usage="Built-in option value for PrintDaggerAs. This option value adds an overbar to the string chosen for PrintAs.";
AddTilde::usage="Built-in option value for PrintDaggerAs. This option value adds a tilde on top of the string chosen for PrintAs.";

(* Info functions *)
TangentBundleOfSolderingForm::usage="TangentBundleOfSolderingForm[sigma] returns the tangent bundle on which the soldering sigma has been defined.";
SpinMetricOfSolderingForm::usage="SpinMetricOfSolderingForm[sigma] returns the antisymmetric spin metric associated to the soldering form sigma.";
VBundleOfSolderingForm::usage="VBundleOfSolderingForm[sigma] returns the inner vbundle (spin bundle) on which the soldering form sigma has been defined.";
SolderingFormOfVBundle::usage="SolderingFormOfVBundle[vbundle] returns the soldering form defined on the vbundle, or Null otherwise.";
SpinCovDsOfSolderingForm::usage="SpinCovDsOfSolderingForm[sigma] returns a list of all covariant derivatives which are compatible with the soldering form sigma.";
SolderingFormOfSpinCovD::usage="SolderingFormOfSpinCovD[SpinCovD] returns the soldering form which is compatible with the covariant derivative SpinCovD";

(* Relations between tensors and spinors *)
DefSpinorOfTensor::usage="DefSpinorOfTensor[sp[inds1],tn[inds2],sigma] defines the spinor counterpart sp[inds1] of the already present tensor tn[inds2] with respect to the spin structure associated to the soldering form sigma. Spinor indices in the sequence inds1 must be sorted according to the pattern index,Dagger[index]. The symmetries of the spinor sp are automatically computed from those of the tensor tn.";
DefTensorOfSpinor::usage="DefTensorOfSpinor[tn[inds1],sp[inds2],sigma] defines the tensor counterpart tn[inds1] of the already present spinor sp[inds2] with respect to the spin structure associated to the soldering form sigma. Spinor indices in the sequence inds2 must be sorted according to the pattern index,Dagger[index]. The symmetries of the tensor tn are automatically computed from those of the spinor sp.";
SpinorOfTensor::usage="SpinorOfTensor[tensor,sigma] gives the spinor counterpart of the tensor named tensor with respect to the spin structure associated to the soldering for sigma.";
TensorOfSpinor::usage="TensorOfSpinor[spinor,sigma] gives the tensor counterpart of the spinor named spinor with respect to the spin structure associated to the soldering for sigma.";

(* Decomposition of a spinor into irreducible parts *)
IrreducibleDecomposition::usage="IrreducibleDecomposition[spinor[inds]] returns the decomposition of the spinor spinor[inds] into totally symmetric irreducible spinors. These are multiplied by apropriate factors of the antisymmetric metric. The irreducible spinors are constructed by appending the TF to the head spinor and using label indices to distinguish the different irreducible spinors intervening in the decomposition";

(* The soldering form *)
PutSolderingForm::usage="PutSolderingForm[expr, inds, sigma] contracts free indices of expr with the soldering form sigma. The free indices are specified by means of the second argument, which can be given in several formats: an index, an IndexList of indices, a conjugated pair Pair[A,A†], a vbundle, a tensor, a covd or an IndicesOf expression with selectors (see xTensor documentation). Both the second and third arguments are sequentially folded over lists. PutSolderingForm[expr, inds] is converted into PutSolderingForm[expr, inds, $SolderingForms]. PutSolderingForm[expr] is converted into PutSolderingForm[expr, IndicesOf[]], adding soldering forms to all possible indices and pairs.";
ContractSolderingForm::usage="ContracSolderingForm[expr, inds] replaces the contracted product of subexpressions in expr with one or several soldering forms by a new expression in which tensor or spinor indices have been inserted appropriately. This process may require the definition of a new tensor or spinor which is handled by the system automatically. The second argument enables us to single out specific soldering forms by selecting the dummy indices in the contracted product, and can be given in several formats: an index, an IndexList of indices, a vbundle, a tensor or an IndicesOf expression with selectors (see xTensor documentation).";
SeparateSolderingForm::usage="SeparateSolderingForm[sigma, basis][expr, inds] separates from expr a number of soldering sigma, creating new dummy indices in the given basis. This may require the definition of a new tensor or spinor, which is carried out automatically. The indices to separate are specified through the inds argument, which can be given in several formats: an index, an IndexList of indices, a vbundle, a tensor, a covd, or an IndicesOf expression with selectors (see xTensor documentation). The default for basis is AIndex, which introduces abstract dummy indices. The sigma argument is folded over lists, and its default is $SolderingForm. SeparateSolderingForm[][expr] is converted into SeparateSolderingForm[][expr, IndicesOf[]], separating all possible soldering forms from expr.";

(* Spinor derivatives and curvature spinors *)
DefSpinCovD::usage="DefSpinCovD[cd[-a],sigma,{post,pre}] defines a spin-compatible covariant derivative cd with respect to the spin structure associated to the soldering form sigma. This covariant derivative will be represented in StandardForm using the character pre in PreFix notation and the character post in PostFix notation. DefSpinCovD supports similar options as the xTensor command DefSpinCovD.";
UndefSpinCovD::usage="UndefSpinCov[scd] undefines the spin-compatible covariant derivative scd.";
SpinCovDQ::usage="SpinCovDQ[cd] returns True if the symbol cd has been declared as a spin covariant derivative using DefSpinCovD, and False otherwise.";
Chi::usage="Chi is a reserved symbol in Spinors denoting the first curvature spinor.";
Phi::usage="Phi is a reserved symbol in Spinors denoting the second curvature spinor.";
Psi::usage="Psi is a reserved symbol in Spinors denoting the Weyl spinor.";
Lambda::usage="Lambda is a reserved symbol in Spinors denoting the Lambda scalar.";
Omega::usage="Omega is a reserved symbol in Spinors denoting the torsion spinor";
$ChiSign::usage="$ChiSign is a global variable which sets the sign convention adopted to define the first curvature spinor. Its default value is +1.";
$PhiSign::usage="$PhiSign is a global variable which sets the sign convention adopted to define the second curvature spinor. Its default value is +1.";
$PsiSign::usage="$PsiSign is a global variable which sets the sign convention adopted to define the Weyl spinor. Its default value is +1.";
$LambdaSign::usage="$LambdaSign is a global variable which sets the sign convention adopted to define the Lambda scalar. Its default value is +1.";
$OmegaSign::usage="$OmegaSign is a global variable which sets the sign convention adopted to define the torsion spinor. Its default value is +1.";
Decomposition::usage="Decomposition[expr, object, covd] decomposes curvature tensors of covd in expr according to predefined rules. Possible objects are Riemann, Ricci, TFRicci, Weyl, RicciScalar, FRiemann or Chi.";
BoxToCovD::usage="BoxToCovD[expr,boxcd] expands all instances of boxcd into symmetrized second covariant derivatives, according to the definition of the box operator.";
BoxToCurvature::usage="BoxToCurvature[expr,boxcd] expands all instances of boxcd into expressions which are linear in the curvature spinors of the spin covariant derivative cd.";
SortSpinCovDs::usage="SortSpinCovDs[expr,spincovd] performs a function similar to SortCovDs for 2-index spin covariant derivatives. The basic identity used to re-order the spin covariant derivatives is their commutator in terms of the box operator";

1.6. Begin private

Begin["`Private`"]

There are 42 reserved words in version 1.0.5 :

Names["xAct`Spinors`*"]

%//Length

$ContextPath

$Context

Now this is not being used. Deactivated cell :

BeginExamples[]:=(Set[$Context,"Global`"];Global`symbols=Names["Global`*"];Null)
Global`EndExamples[]:=(If[#=!={},Print["There are new symbols in Global`:",#]];Set[$Context,"xAct`Spinors`Private`"];Null)&@Complement[Names["Global`*"],Global`symbols]

2. Spin structures

2.1. Definition

A spin structure is a composite abstract type formed by several objects. It is constructed from a previously defined manifold with metric, and constructs
	- an inner vbundle on that manifold,
	- the epsilon antisymmetric metric,
	- the soldering form sigma, and
	- a covariant derivative CDe extending the Levi-Civita of the metric.
The properties of epsilon and sigma are different for different manifold-dimensions and different metric-signatures. At the moment we only consider 4d Lorentzian spacetimes. See appendix to Penrose & Rindler.

We start by checking the properties of the preexisting metric

CheckMetric[metric_,tbundle_]:=
Which[
!MetricQ[metric],Throw@Message[DefSpinStructure::unknown,"metric",metric],xAct`xTensor`Private`FrozenMetricQ[metric],Throw@Message[DefSpinStructure::error,"A frozen metric cannot be used."],
TangentBundleOfManifold@BaseOfVBundle@tbundle=!=tbundle,
Throw@Message[DefSpinStructure::error,"The metric must be defined on a tangent bundle."],
DimOfVBundle[tbundle]=!=4,
Throw@Message[DefSpinStructure::notyet,"non 4d manifolds"],
SignDetOfMetric[metric]=!=-1,
Throw@Message[DefSpinStructure::invalid,metric,"Lorentzian metric"],
SignatureOfMetric[metric]=!={1,3,0},
Throw@Message[DefSpinStructure::invalid,metric,"metric of signature +,-,-,-."]
];

Something annoying in Mathematica is that With cannot replace pattern names whitin Set, Rule and similar constructs. We want to pass correct indices to our definitions and so we define intermediate holding heads isetdelayed, itagset and itagsetdelayed to fool Mathematica during the evaluation of With:

SetAttributes[{isetdelayed,itagset,itagsetdelayed},HoldAll];
isetdelayed=SetDelayed;
itagset=TagSet;
itagsetdelayed=TagSetDelayed;

Global variable storing all defined soldering forms. It is used by ContractSolderingForm:

$SolderingForms={};

Sigma spinor, square of the soldering form :

Sigma[sigma_Symbol]:=GiveSymbol[Sigma,sigma];
GiveOutputString[Sigma,sigma_Symbol]:=StringJoin["Σ",PrintAs[sigma]];
SetNumberOfArguments[Sigma,1];
Protect[Sigma];

Main function :
      - It is difficult to do name validation in this function because there are many names to validate.
      - We cannot pass the PrintAs values of vbundle, epsilon and sigma. Do that later by hand.
      - epsdag is constructed before eps is validated. We trust the user in this point...

?DefSpinStructure

(* Options for formatting *)
Options[DefSpinStructure]:={
SpinorPrefix->Identity,
SpinorMark->PrintAs,
DefInfo->{"spin structure",""}
};
(* Backwards compatibility *)
DefSpinStructure[metric_,vbundle_,vbinds_,eps_,sigma_,cd_,cdsymbols:{_String,_String},options:OptionsPattern[]]:=DefSpinStructure[metric,vbundle,vbinds,eps,sigma,cd,SymbolOfCovD->cdsymbols,options];
(* Main *)
DefSpinStructure[metric_Symbol,vbundle_Symbol,vbinds_List,eps_Symbol,sigma_Symbol,cd_Symbol,options:OptionsPattern[]]:=Catch@With[{tbundle=VBundleOfMetric[metric]},
CheckMetric[metric,tbundle];
With[
{base=BaseOfVBundle[tbundle],
covd=CovDOfMetric[metric]},

(* 1. Create 2d complex inner vbundle *)
DefVBundle[vbundle,base,2,vbinds,Dagger->Complex,FilterRules[{options},Options[DefVBundle]]];

(* 2. Relations in the spin structure *)
VBundleOfSolderingForm[sigma]^=vbundle;
SolderingFormOfVBundle[vbundle]^=sigma;
TangentBundleOfSolderingForm[sigma]^=tbundle;
SpinMetricOfSolderingForm[sigma]^=eps;
SpinCovDsOfSolderingForm[sigma]^={};(*{cd};*)
SolderingFormOfSpinCovD[cd]^=sigma;

(* 3. Construct indices and feed them with With *)
Module[{Ai,Adi,Bi,Bdi,Ci,Cdi,Di,Ddi,ai,bi,ci,di,ei,fi},
{Ai,Bi,Ci,Di}=GetIndicesOfVBundle[vbundle,4,{}];
{Adi,Bdi,Cdi,Ddi}=DaggerIndex/@{Ai,Bi,Ci,Di};
{ai,bi,ci,di,ei,fi}=GetIndicesOfVBundle[tbundle,6,{}];
With[{A=Ai,Ad=Adi,B=Bi,Bd=Bdi,C=Ci,Cd=Cdi,D=Di,Dd=Ddi,a=ai,b=bi,c=ci,d=di,e=ei,f=fi,vbundledag=Dagger[vbundle],epsdag=MakeDaggerSymbol[eps]},

(* 4. Define the soldering form *)
DefTensor[sigma[a,-C,-Dd],base,Dagger->Hermitian,ProtectNewSymbol->False,Master->vbundle,DefInfo->{"soldering form",""},FilterRules[{options},Options[DefTensor]]];
AppendTo[$SolderingForms,sigma];

(* 5. Define eps and its conjugate *)
DefTensor[eps[-A,-B],base,Antisymmetric[{1,2}],Dagger->Complex,ProtectNewSymbol->False,Master->sigma,DefInfo->{"spin metric",""},FilterRules[{options},Options[DefTensor]]];
(* Metric properties *)
MetricQ[eps]^=True;
MetricQ[epsdag]^=True;
xUpAppendTo[MetricsOfVBundle[vbundle],eps];
xUpAppendTo[MetricsOfVBundle[vbundledag],epsdag];
VBundleOfMetric[eps]^=vbundle;
VBundleOfMetric[epsdag]^=vbundledag;
$Metrics=Join[$Metrics,{eps,epsdag}];
InducedFrom[eps]^=Null;
InducedFrom[epsdag]^=Null;
(* Conversion into delta for mixed abstract indices *)
isetdelayed[eps[A_Symbol,-B_Symbol],delta[A,-B]];
isetdelayed[eps[-A_Symbol,B_Symbol],delta[-A,B]];
isetdelayed[epsdag[A_Symbol,-B_Symbol],delta[A,-B]];
isetdelayed[epsdag[-A_Symbol,B_Symbol],delta[-A,B]];

(* 6. Spinor construction *)
Module[{sigmaprefix,sigmamark},
{sigmaprefix,sigmamark}=OptionValue[{DefSpinStructure,DefCovD},{options},{SpinorPrefix,SpinorMark}];
SpinorPrefix[sigma]^=If[sigmaprefix===Identity,sigma,sigmaprefix];
SpinorMark[sigma]^=If[sigmamark===PrintAs,PrintAs[sigma],sigmamark];
];

(* 7. Products of two sigma *)
With[{vQ=xAct`xTensor`Private`VBundleIndexPMQ[vbundle],vdQ=xAct`xTensor`Private`VBundleIndexPMQ[vbundledag]},
itagset[sigma,sigma[a_,A_,Dd_]sigma[-a_,C_,Cd_],eps[A,C]epsdag[Dd,Cd]];
AutomaticRules[sigma,MakeRule[{sigma[a,-B,-Dd]sigma[b,B,Dd],metric[a,b]},MetricOn->All,ContractMetrics->False,TestIndices->False],Verbose->False]
];
With[{Sigmaname=GiveSymbol[Sigma,sigma],Tetraname=Tetra[metric]},
DefTensor[Sigmaname[a,b,-A,-B],base,StrongGenSet[{1},GenSet[-xAct`xPerm`Cycles[{1,2},{3,4}]]],PrintAs:>GiveOutputString[Sigma,sigma],Dagger->Complex,Master->sigma,FilterRules[{options},Options[DefTensor]]];
Sigmaname[a_,b_,C_,-C_]:=-metric[a,b];
Sigmaname[a_,b_,-C_,C_]:=metric[a,b];
Sigmaname[a_,-a_,C_,D_]:=-2eps[C,D];
Sigmaname[-a_,a_,C_,D_]:=-2eps[C,D];
With[{Sigmanamedag=Dagger[Sigmaname],Tetranamedag=Dagger[Tetraname]},
Sigmanamedag[a_,b_,Cd_,-Cd_]:=-metric[a,b];
Sigmanamedag[a_,b_,-Cd_,Cd_]:=metric[a,b];
Sigmanamedag[a_,-a_,Cd_,Dd_]:=-2epsdag[Cd,Dd];
Sigmanamedag[-a_,a_,Cd_,Dd_]:=-2epsdag[Cd,Dd];
AutomaticRules[Sigmaname,MakeRule[{Sigmaname[a,b,A,B]Sigmaname[c,d,C,-B],-Tetraname[b,d,-e,a]Sigmaname[e,c,A,C]},MetricOn->{a,b,c,d,A,C},ContractMetrics->True],Verbose->False];
AutomaticRules[Sigmanamedag,MakeRule[{Sigmanamedag[a,b,Ad,Dd]Sigmanamedag[c,d,Cd,-Dd],-Tetranamedag[b,d,-e,a]Sigmanamedag[e,c,Ad,Cd]},MetricOn->{a,b,c,d,Ad,Cd},ContractMetrics->True],Verbose->False];

itagsetdelayed[Sigmaname,Tetraname[a_,b_,c_,d_]Sigmaname[e_,f_,C_,D_],Condition[metric[a,b]eps[C,D],PairQ[c,e]&&PairQ[d,f]||PairQ[c,f]&&PairQ[d,e]]];
itagsetdelayed[Sigmaname,Tetraname[c_,d_,a_,b_]Sigmaname[e_,f_,C_,D_],Condition[metric[a,b]eps[C,D],PairQ[c,e]&&PairQ[d,f]||PairQ[c,f]&&PairQ[d,e]]];

itagsetdelayed[Sigmanamedag,Tetranamedag[a_,b_,c_,d_]Sigmanamedag[e_,f_,Cd_,Dd_],Condition[metric[a,b]epsdag[Cd,Dd],PairQ[c,e]&&PairQ[d,f]||PairQ[c,f]&&PairQ[d,e]]];
itagsetdelayed[Sigmanamedag,Tetranamedag[c_,d_,a_,b_]Sigmanamedag[e_,f_,Cd_,Dd_],Condition[metric[a,b]epsdag[Cd,Dd],PairQ[c,e]&&PairQ[d,f]||PairQ[c,f]&&PairQ[d,e]]];
];
];

(* 8. Define the spinor equivalent of the metric tensor and the volume element *)
With[{MetricName=AddSpinorPrefix[metric,SpinorPrefix[sigma]],EpsilonSpin=AddSpinorPrefix[epsilon@metric,SpinorPrefix[sigma]]},
DefSpinorOfTensor[MetricName[A,Cd,B,Dd],metric[-a,-b],sigma,FilterRules[{options},Options[DefTensor]]];
itagset[MetricName,MetricName[A_,Cd_,B_,Dd_],eps[A,B]epsdag[Cd,Dd]];
DefSpinorOfTensor[EpsilonSpin[A,Ad,B,Bd,C,Cd,D,Dd],epsilon[metric][-a,-b,-c,-d],sigma,options];
itagsetdelayed[EpsilonSpin,EpsilonSpin[A_,Ad_,B_,Bd_,C_,Cd_,D_,Dd_],epsilonOrientation[metric,AIndex] I (-eps[A,D]eps[B,C]epsdag[Ad,Cd]epsdag[Bd,Dd]+eps[A,C]eps[B,D]epsdag[Ad,Dd]epsdag[Bd,Cd])];
];

(* 9. Define the covariant derivative (and the curvature spinors) *)
DefSpinCovD[cd[-a],sigma,Torsion->TorsionQ@covd,ExtendedFrom->covd,Master->sigma,ProtectNewSymbol->False,FilterRules[{options},Options[DefSpinCovD]]];
(* Compatibility with metric, for all index configurations *)
isetdelayed[cd[a__][eps[A_,B_]],0];
isetdelayed[cd[a__][epsdag[A_,B_]],0];
CovDOfMetric[eps]^=cd;
CovDOfMetric[epsdag]^=cd;

]
]
]
];
SetNumberOfArguments[DefSpinStructure,{7,Infinity}];
Protect[DefSpinStructure];

Alfonso: in the formula which gives the decomposition of the spinor couterpart of the volume element there is a sign discrepancy between our formula and the formula of Penrose & Rindler. I think that this has to do with some convention when defining the volume element.

2.2. Undefinition

To undefine a spin structure, undefine its soldering form (preferred), vbundle or covd.

UndefSpinStructure[vbundle_?VBundleQ]:=UndefSpinStructure[SolderingFormOfVBundle[vbundle]];
UndefSpinStructure[covd_?CovDQ]:=UndefSpinStructure[SolderingFormOfSpinCovD[covd]];
UndefSpinStructure[sigma_?xTensorQ]:=With[{newlist=DeleteCases[$SolderingForms,sigma]},
UndefVBundle[VBundleOfSolderingForm[sigma]];
$SolderingForms=newlist;]/;MemberQ[$SolderingForms,sigma];
UndefSpinStructure[x_]:=Throw@Message[UndefSpinStructure::unknown,"spin structure", x];
SetNumberOfArguments[UndefSpinStructure,1];
Protect[UndefSpinStructure];

Just one comment : we compute initially the new list $SolderingForms, while sigma still exists, and store it in newlist. We then remove the spin structure, checking that everything goes smoothly. Finally, we update the value of the symbol $SolderingForms. Otherwise, we could find problems during removal after having lost track of the soldering-form character of sigma:

3. Tensors and spinors

3.0. Comments

A spinor is actually a tensor with indices on the inner vbundle. Hence, it can be defined/undefined using DefTensor/UndefTensor. However, for aesthetic reasons, we include these two heads:

Some built-in options for PrintDaggerAs. Code supplied by Thomas Bäckdahl.
Jose: I think these two are the functions Overline[...] and TildeString[...] of xCore`, acting on the PrintAs forms of Dagger[T]. Beware that this T is already a daggered object, so the Dagger@ here is needed to recover the original undaggered object.

AddBar[T_?xTensorQ]:=StringJoin["\!\(","\*OverscriptBox[\(",PrintAs@Evaluate@Dagger[T],"\),\(_\)]","\)"];
AddTilde[T_?xTensorQ]:=StringJoin["\!\(","\*OverscriptBox[\(",PrintAs@Evaluate@Dagger@T,"\),\(~\)]","\)"];
AddDagger[T_?xTensorQ]:=StringJoin[PrintAs@Evaluate@Dagger@T,$DaggerCharacter];

Thomas Bäckdahl code to include printing options for dagger spinors.

Options[DefSpinor]={PrintDaggerAs->AddDagger};
DefSpinor[spinor_[inds___],deps_,options:OptionsPattern[{DefSpinor,DefTensor}]]:=(DefTensor[spinor[inds],deps,FilterRules[{options},Options[DefTensor]],Dagger->Complex,DefInfo->{"spinor",""}];
If[Dagger@spinor=!=spinor,
xAct`xTensor`Private`SetPrintAs[Dagger@spinor,xAct`xTensor`Private`PrintAsString[Dagger@spinor,OptionValue[PrintDaggerAs]]]
];);

DefSpinor[spinor_[inds___],deps_,sym_,options:OptionsPattern[{DefSpinor,DefTensor}]]:=(DefTensor[spinor[inds],deps,sym,FilterRules[{options},Options[DefTensor]],Dagger->Complex,DefInfo->{"spinor",""}];
If[Dagger@spinor=!=spinor,
xAct`xTensor`Private`SetPrintAs[Dagger@spinor,xAct`xTensor`Private`PrintAsString[Dagger@spinor,OptionValue[PrintDaggerAs]]]
];);
UndefSpinor=UndefTensor;
SetNumberOfArguments[DefSpinor,{2,Infinity}];
Protect[DefSpinor,UndefSpinor];

There is no function SpinorQ, though it might be introduced, probably performing additional checks to xTensorQ.

Any tensor (real or complex) has an associated spinor (Hermitian or complex, respectively). However, not any spinor has an associated tensor. Only those spinors with equal number of indices in VB and Dagger[VB] can have an associated tensor. We shall follow the convention that the indices in a spinor are paired in the following way: the first index of VB is paired with the first index of Dagger[VB], the second with the second, etc. Indeed, we have a more restrictive convention [ A, A†, B, B†, ... ]

3.1. Spinor / tensor equivalents

Given a tensor (spinor) we want to construct its spinor (tensor) equivalent with respect to a given soldering-form.  We need to deal with five different issues:
        - The name of the spinor: we link a prefix symbol and the tensor symbol. There is the possibility of having already the prefix at the beginning of the tensor symbol, meaning that the symbol itself comes from a spinor. Then we would remove the prefix. Anyway, the names will be related finally through TensorOfSpinor and SpinorOfTensor, and this can be changed by the user and he/she likes.
        - The output of the spinor: we use the spinor mark
        - The symmetry of the spinor: This is a difficult point. Currently we trust everything is consistent and do not perform checks.
        - The relations among the slots of the tensor and the spinor. We follow the convention above of having corresponding sequences of indices in TM, VB and Dagger[VB].
        - Due to the see-saw rule, it is not enough to say that the spinor of T[a] is ξ[A,A†] porque ξ[A,A†]σ[a,-A,-A†] has a changed sign with respect to ξ[A,-A†]σ[a,-A,A†], and so it is not obvious which one must be declared to be T[a]. We will solve this by establishing that the configuration in SlotsOfTensor[ξ] is priviledged and has no sign in the conversion to a tensor.

ReplaceFrees[expr_,inds_IndexList]:=With[{all=xAct`xTensor`Private`FindFreeAndDummyIndices[expr]},With[{frees=First@all,dummies=Last@all},
ReplaceIndex[expr,Inner[Rule,frees,DeleteCases[inds,Alternatives@@dummies][[Range@Length@frees]],List]]
]
];

1) Names of the spinors

These two linking functions are defined in xCore:

?LinkSymbols

?UnlinkSymbol

The function AddSpinorPrefix is rather general, including the possibility of removing the prefix as well. This must be a private function; the user driver is the pair TensorOfSpinor and SpinorOfTensor.

AddSpinorPrefix[object_Symbol,prefix_Symbol]:=ASP[UnlinkSymbol[object],prefix];
ASP[{prefix_,other__},prefix_]:=LinkSymbols[{other}];
ASP[{other__},prefix_]:=LinkSymbols[{prefix,other}];

The functions SpinorOfTensor and TensorOfSpinor will be used through upvalues, but return a default name, together with a message. These two functions can be used to prepare in advance any alternative way of naming the spinor and tensor equivalents:

SpinorOfTensor::name="Spinor of `1` not defined. Prepending `2`.";
TensorOfSpinor::name="Tensor of `1` not defined. Prepending `2`.";
SpinorOfTensor[tensor_,sigma_]:=With[{prefix=SpinorPrefix[sigma]},Message[SpinorOfTensor::name,tensor,prefix];AddSpinorPrefix[tensor,prefix]];
TensorOfSpinor[spinor_,sigma_]:=With[{prefix=SpinorPrefix[sigma]},Message[TensorOfSpinor::name,spinor,prefix];AddSpinorPrefix[spinor,prefix]];
(* Default choice of spinor prefix *)
SpinorPrefix[sigma_]:=sigma;
SetNumberOfArguments[SpinorPrefix,1];
SetNumberOfArguments[SpinorOfTensor,2];
SetNumberOfArguments[TensorOfSpinor,2];
Protect[SpinorPrefix,SpinorOfTensor,TensorOfSpinor];

2) Formatting

Then we need to worry about output formatting. The private function AddSpinorMark adds a mark to a string, returning another string . Two possibilities:

AddSpinorMark[character_String,mark_String]:=StringJoin[mark,character];
AddSpinorMark[character_String,function_]:=function[character];

Examples :

AddSpinorMark["▽",ColorString["S",Red]]

AddSpinorMark["▽",OverTilde]

AddSpinorMark["R",Function[TildeString[#,1,Blue]]]

3) Relations among indices

We need to check that the indices of the spinor and the tensor are consistent, and we need to find out their mutual relations. The output of indRules is a list of rules of the form nt->nv indicating that slot nt of the tensor corresponds to slot nv of the spinor, or rules of the form nt->{nv,nv+1} indicating that slot nt of tensor corresponds to a pair of slots in the spinor. The function proceeds analyzing index by index:

(* Same index: shift slots *)
indRules[f_,{vbundle_,nv_,IndexList[A_,spinds___]},{tbundle_,nt_,IndexList[A_,inds___]},rules_List]:=indRules[f,{vbundle,nv+1,IndexList[spinds]},{tbundle,nt+1,IndexList[inds]},Append[rules,nt->nv]];
(* tbundle index corresponds to a pair of vbundle/vbundledag indices *)
indRules[f_,{vbundle_,nv_,IndexList[A_,Bd_,spinds___]},{tbundle_,nt_,IndexList[a_,inds___]},rules_List]:=
indRules[f,{vbundle,nv+2,IndexList[spinds]},{tbundle,nt+1,IndexList[inds]},Append[rules,nt->{nv,nv+1}]]/;AIndexQ[A,vbundle]&&AIndexQ[Bd,Dagger[vbundle]]&&AIndexQ[a,tbundle];
(* Exit point *)
indRules[f_,{_,_,IndexList[]},{_,_,IndexList[]},rules_List]:=rules;
(* Other case: error *)
General::incomp="Indices `1` and `2` are incompatible.";
indRules[DefSpinorOfTensor,{_,_,spinds_},{_,_,inds_},_]:=Throw@Message[DefSpinorOfTensor::incomp,spinds,inds];
indRules[DefTensorOfSpinor,{_,_,spinds_},{_,_,inds_},_]:=Throw@Message[DefTensorOfSpinor::incomp,inds,spinds];

QUESTION : Is there any overlapping between this function and TransposeDagger?

4) Symmetry

Given the symmetry of the tensor we construct the symmetry of its spinorial equivalent. We assume that the slots in the spinor are in correspondence with those in the tensor, as specified by the list of rules. Note that we are using the full form of SymmetryGroupOfTensor, feeding the indices, but probably these commands can be used for a tensor with a variable number of indices, because the spinorial equivalent will not inherit that property.

(* This assumes a GenSet in cyclic form *)
SpinorSymmetry[tensor_[inds___],rules_List]:=SymmetryGroupOfTensor[tensor[inds]]/.StrongGenSet[base_,genset_]:>StrongGenSet[first/@(base/.rules),genset/.perm_Cycles:>spinorCycles[rules]/@perm];
first[i_Integer]:=i;
first[list_List]:=First[list];
spinorCycles[rules_List][cycle_List]:=spinorCyclesTranspose[cycle/.rules];
spinorCyclesTranspose[cycle:{__Integer}]:=cycle;
spinorCyclesTranspose[cycle:{{_,_}..}]:=Sequence@@Transpose[cycle];
spinorCyclesTranspose[cycle_]:=Throw@Message[DefSpinorOfTensor::error,"Symmetry of tensor incompatible with indices."];

(* This assumes a GenSet in cyclic form *)
SymmetryOfTensor[spinor_[spinds___],rules_List]:=With[{firstrules=Map[first,rules,{2}]},
SymmetryGroupOfTensor[spinor[spinds]]/.StrongGenSet[base_,genset_]:>StrongGenSet[Cases[base,Alternatives@@(First/@firstrules)]/.firstrules,genset/.perm_Cycles:>tensorCycles[firstrules]/@perm]
];
tensorCycles[firstrules_List][cycle_List]:=Which[
Complement[cycle,First/@firstrules]==={},cycle/.firstrules,
Intersection[cycle,First/@firstrules]==={},{},
True,Throw@Message[DefTensorOfSpinor::error,"Symmetry of spinor cannot be reduced to tensor."]];

5) DefSpinorOfTensor and DefTensorOfSpinor

This is the function which defines the spinorial equivalent of a tensor:

DefSpinorOfTensor[spinor_Symbol[spinds___],tensor_Symbol[inds___],sigma_Symbol,options:OptionsPattern[]]:=Catch@Module[{vbundle,tbundle,rules,sym},

(* Check tensor *)
If[!xTensorQ[tensor],Throw@Message[DefSpinorOfTensor::unknown,"tensor",tensor]];

(* VBundles *)
vbundle=VBundleOfSolderingForm[sigma];
tbundle=TangentBundleOfSolderingForm[sigma];

(* Check index compatibility and construct rules *)
rules=indRules[DefSpinorOfTensor,{vbundle,1,IndexList[spinds]},{tbundle,1,IndexList[inds]},{}];
sym=SpinorSymmetry[tensor[inds],rules];

(* Define spinor. Do not give master *)
DefTensor[spinor[spinds],DependenciesOfTensor[tensor],sym,Dagger:>If[DaggerQ[tensor],Complex,Hermitian],Master->Null,FilterRules[{options},Options[DefTensor]],
PrintAs:>AddSpinorMark[PrintAs[tensor],SpinorMark[sigma]],DefInfo->{"spinor","Equivalent of tensor "<>ToString[tensor],"Equivalent of tensor "<>ToString[Dagger[tensor]]}];

(* Register *)
RegisterSpinorOfTensor[spinor,tensor,sigma];
SetVisitorHost[spinor,tensor,sigma];
If[DaggerQ@tensor,
RegisterSpinorOfTensor[Dagger[spinor],Dagger[tensor],sigma];
(* SetVisitorHost[Dagger[spinor],Dagger[tensor],sigma]*)];

];
SetNumberOfArguments[DefSpinorOfTensor,{3,Infinity}];
Protect[DefSpinorOfTensor];

JMM : The Hosts/Visitors assignments on the complex conjugated tensor/spinor gives problems. Now deactivated.

RegisterSpinorOfTensor[spinor_,tensor_,sigma_]:=(
xTagSet[{tensor,SpinorOfTensor[tensor,sigma]},spinor];
xTagSet[{spinor,TensorOfSpinor[spinor,sigma]},tensor];
);
SetVisitorHost[visitor_,host_,sigma_]:=(
xUpAppendTo[HostsOf[visitor],sigma];
xUpAppendTo[HostsOf[visitor],host];
xUpAppendTo[VisitorsOf[sigma],visitor];
xUpAppendTo[VisitorsOf[host],visitor];
);

And this is the parallel structure to define a tensor from a spinor :

DefTensorOfSpinor[tensor_Symbol[inds___],spinor_Symbol[spinds___],sigma_Symbol,options:OptionsPattern[]]:=Catch@Module[{vbundle,tbundle,rules,sym},

(* Check spinor *)
If[!xTensorQ[spinor],Throw@Message[DefTensorOfSpinor::unknown,"spinor",spinor]];

(* VBundles *)
vbundle=VBundleOfSolderingForm[sigma];
tbundle=TangentBundleOfSolderingForm[sigma];

(* Check index compatibility and construct rules *)
rules=Reverse/@indRules[DefTensorOfSpinor,{vbundle,1,IndexList[spinds]},{tbundle,1,IndexList[inds]},{}];
sym=SymmetryOfTensor[spinor[spinds],rules];

(* Define tensor. Do not give master *)
DefTensor[tensor[inds],DependenciesOfTensor[spinor],sym,Dagger:>If[HermitianQ[spinor],Real,Complex],Master->Null,FilterRules[{options},Options[DefTensor]],
PrintAs:>AddSpinorMark[PrintAs[spinor],SpinorMark[sigma]],DefInfo->{"tensor","Equivalent of spinor "<>ToString[spinor],"Equivalent of spinor "<>ToString[Dagger[spinor]]}];

(* Register *)
RegisterSpinorOfTensor[spinor,tensor,sigma];
SetVisitorHost[tensor,spinor,sigma];
If[DaggerQ[tensor],
RegisterSpinorOfTensor[Dagger[spinor],Dagger[tensor],sigma];
(* SetVisitorHost[Dagger[spinor],Dagger[tensor],sigma]*);
];

];
SetNumberOfArguments[DefTensorOfSpinor,{3,Infinity}];
Protect[DefTensorOfSpinor];

3.2. Pairs of complex indices

The functions ContractSolderingForm / SeparateSolderingForm /PutSolderingForm can manipulate pairs of indices, and not only indices. We need a function which can extract the default pairs from an expression, following some conventions: indices of a pair belong to the same tensor, or to the same spin covd. The user can, however, specify pairs of indices not following that rule.

FindPairs returns a List of pairs (each a List of two indices). Note that there is nothing yet for Bracket. There is the danger of confusing a pair of indices with a BC-index. The function TransposeDaggerPairs contains the convention of pairing indices in order (first of V with first in V*, etc).
Note the final IndexList@@, in spite of having Join[IndexList[...], ...]. The problem is that Join[] gives {} and we need to convert it into IndexList[].

(* Return an IndexList of Pair pairs *)
FindPairs[expr_,vbs_List]:=IndexList@@Apply[Join,
xAct`xTensor`Private`TransposeDaggerPairs[#,vbs,False]&/@Join[
FindAllOfType[expr,Tensor],Cases[FindAllOfType[expr,CovD],_Symbol?SpinCovDQ[a_,b_][_]->IndexList[a,b]]
]
];
(* Separate pairs in the given indices list *)
FindPairs[expr_,vbs_List,indices_IndexList]:=With[{pairs=FindPairs[expr,vbs]},
Flatten[{List@@Complement[indices,Flatten[Apply[IndexList,pairs,1],1]],Cases[pairs,pair_/;Intersection[IndexList@@pair,indices]=!=IndexList[]]},1]
];

With three arguments we split the indices list into pairs and the rest.

3.3. PutSolderingForm

This command enables us to transform tensors into spinors by means of the contraction with the soldering form.

?PutSolderingForm

User driver :

(* Shortcuts for the third argument *)
PutSolderingForm[expr_]:=PutSolderingForm[expr,IndicesOf[]];
PutSolderingForm[expr_,inds_]:=PutSolderingForm[expr,inds,$SolderingForms];
PutSolderingForm[expr_,inds_,list_List]:=Fold[PutSolderingForm[#1,inds,#2]&,expr,list];
(* Second argument *)
PutSolderingForm[expr_,ind_?GIndexQ,sigma_Symbol]:=PutSolderingForm[expr,IndexList[ind],sigma];
PutSolderingForm[expr_,list_List,sigma_Symbol]:=Fold[PutSolderingForm[#1,#2,sigma]&,expr,list];
PutSolderingForm[expr_,master:(_Symbol?VBundleQ|_Symbol?xTensorQ|_Symbol?CovDQ),sigma_Symbol]:=PutSolderingForm[expr,IndicesOf[Free,master],sigma];
PutSolderingForm[expr_,f_IndicesOf,sigma_Symbol]:=PutSolderingForm[expr,DeleteDuplicates[Prepend[f,Free]][expr],sigma];
(* Actual working function. Two entry points *)
PutSolderingForm[expr_,pair_Pair,sigma_Symbol]:=PutSolderingForm1[VBundleOfSolderingForm[sigma],sigma][expr,pair];
PutSolderingForm[expr_,inds_IndexList,sigma_Symbol]:=With[{vbundle=VBundleOfSolderingForm[sigma]},Fold[PutSolderingForm1[vbundle,sigma],expr,FindPairs[expr,{vbundle,Dagger[vbundle]},inds]]
];
(* Other *)
SetNumberOfArguments[PutSolderingForm,{1,3}];
Protect[PutSolderingForm];

Put soldering-form contracting both spin indices. A spacetime free index is generated:

PutSolderingForm1[vbundle_,sigma_][expr_,Pair[index1_,index2_]]:=
With[{indices=FindIndices[expr]},
(* Some Checks *)
If[Or[
VBundleOfIndex[index1]=!=vbundle,
VBundleOfIndex[index2]=!=Dagger[vbundle],
FreeQ[indices,index1],
FreeQ[indices,index2]
],
(* Problem: do nothing *)
expr,
(* Do Put *)
Module[{A1=DummyAs[index1],A2=DummyAs[index2],a=If[UpIndexQ[index1],UpIndex,DownIndex]@First@GetIndicesOfVBundle[TangentBundleOfManifold@BaseOfVBundle[vbundle],1,UpIndex/@FindIndices@expr]},
ReplaceIndex[expr,{index1->A1,index2->A2}]sigma[a,-A1,-A2]
]
]
];

Put soldering form contracting the spacetime index. A pair of free indices in the spin vbundle and its conjugate are generated:

PutSolderingForm1[vbundle_,sigma_][0,AnyIndices]:=0;
PutSolderingForm1[vbundle_,sigma_][expr_,index_]:=
With[{indices=FindIndices[expr]},
(* Some Checks *)
If[Or[
VBundleOfIndex[index]=!=TangentBundleOfManifold@BaseOfVBundle[vbundle],
FreeQ[indices,index]
],
(* Problem: do nothing *)
expr,
(* Do Put *)
Module[{a,A,inds=UpIndex/@indices},
a=DummyAs[index];
inds=Union[inds,DaggerIndex/@inds];
A=If[UpIndexQ[index],UpIndex,DownIndex]@First@GetIndicesOfVBundle[vbundle,1,inds];
ReplaceIndex[expr,index->a]sigma[-a,A,DaggerIndex[A]]
]
]
];

3.4. ContractSolderingForm

This is a complicated function, mostly due to the fact that there are actually two different functions here: contraction of the soldering form on the tbundle index and contraction on the pair of vbundle indices. We separate the code in seven parts.

Note that ContractSolderingForm is an index - driven function, and not a soldering-form - driven function, as we might have anticipated. In this sense, it is more similar to ContractBasis (also index - driven) than to ContractMetric (which is metric - driven). This is the result of the intermediate state of allowing a choice for the soldering-form (like a metric choice), but then working with a single soldering-form (like the single Basis tensor). This is partially solved allowing a tensor (which could be the soldering-form itself) as second argument.

1) This is the user driver:

(* Single option *)
Options[ContractSolderingForm]:={OverDerivatives->True};
(* Shortcuts *)
ContractSolderingForm[expr_,options:OptionsPattern[]]:=ContractSolderingForm[expr,IndicesOf[],options];
ContractSolderingForm[expr_,tensor_Symbol?xTensorQ,options:OptionsPattern[]]:=ContractSolderingForm[expr,IndicesOf[tensor],options];
ContractSolderingForm[expr_,vbundle_Symbol?VBundleQ,options:OptionsPattern[]]:=ContractSolderingForm[expr,IndicesOf[vbundle],options];
ContractSolderingForm[expr_,index_?GIndexQ,options:OptionsPattern[]]:=ContractSolderingForm[expr,IndexList[index],options];
ContractSolderingForm[expr_,f_IndicesOf,options:OptionsPattern[]]:=ContractSolderingForm[expr,f[expr],options];
(* Main definition *)
ContractSolderingForm[expr_,list_IndexList,options:OptionsPattern[]]:=Fold[CSF1[OptionValue[OverDerivatives],list],Expand[expr],$SolderingForms];
(* Other *)
SetNumberOfArguments[ContractSolderingForm,{1,Infinity}];
Protect[ContractSolderingForm];

2) CSF1 folds over lists of indices, calling CSF2, which will introduce heads SpinorTMP and TensorTMP, which are finally removed with RemoveTMP. The motivation for the TMP heads is the following: in general a tensor will have several indices to contract; we introduce the TMP heads when contracting the first index, and remove it after contracting the last one.

(* Plus: thread *)
CSF1[TF_,inds_IndexList][expr_Plus,sigma_]:=CSF1[TF,inds][#,sigma]&/@expr;
CSF1[TF_,inds_IndexList][0,sigma_]:=0;
CSF1[TF_,inds_IndexList][expr_,sigma_]:=RemoveTMP@Fold[CSF2[TF,sigma],expr,inds];
RemoveTMP[expr_]:=expr/.new:(SpinorTMP|TensorTMP)[__][___]:>ArrangeSpinTMP[new];

3) There are two possibilities : either the index to contract is a real index on the tangent vbundle or it is a complex index on the inner vbundle. We separate those two cases to avoid many useless rules. This also allow us to know whether we will be converting a tensor into a spinor or viceversa. Note that from the user's point of view this can be controlled by specifying a vbundle in the second argument of the second pair of brackets.

CSF2[TF_,sigma_][expr_,i_]:=CSF2[TF,sigma][expr,i,ChangeIndex[i],DaggerIndex[i]===i];

It would be nicer to code up this part with a single function CSF, and not two.

4a) Recall that the tindex-contracted product of two sigmas gives a product of epsilons automatically. Hence we do not need a tensor=!=sigma check here. Also, when contracting the soldering form we need to check whether the master object is the spinor being acted upon or its dagger. This is to ensure that our conventions which establish the sorting of  spinor indices are met at any time.

(* Contraction with tensors and derivatives *)
CSF2[False,sigma_][expr_,i_?ABIndexQ,ic_,True]:=Expand[expr/.{
sigma[i,a_,b_]tensor_?xTensorQ[i1___,ic,i2___]:>If[HasDaggerCharacterQ[tensor],
SpinorTMP[tensor,sigma][i1,b,a,i2],SpinorTMP[tensor,sigma][i1,a,b,i2]],sigma[ic,a_,b_]tensor_?xTensorQ[i1___,i,i2___]:>If[HasDaggerCharacterQ[tensor],SpinorTMP[tensor,sigma][i1,b,a,i2],SpinorTMP[tensor,sigma][i1,a,b,i2]],
sigma[i,a_,b_]covd_Symbol?SpinCovDQ[ic][expr1_]:>covd[a,b][expr1],
sigma[ic,a_,b_]covd_Symbol?SpinCovDQ[i][expr1_]:>covd[a,b][expr1]}
];
(* Recursion through covariant derivatives *)
CSF2[True,sigma_][expr_,i_?AIndexQ,ic_,True]:=Expand[CSF2[False,sigma][expr,i,ic,True]/.rest_.sigma[i,a_,b_]covd_Symbol?CovDQ[inds__][expr1_]:>rest covd[inds][CSF2[True,sigma][sigma[i,a,b]expr1,i,ic,True]]/;IsIndexOf[expr1,ic]&&SolderingFormOfSpinCovD[covd]===sigma];
(* For other types of indices, do nothing *)
CSF2[_,_][expr_,_,_,True]:=expr;

4b) Note the structure of the function SST: the original expression sigma[a,i,j]*spinor[i1,ic,jc,i2] is being converted into tensor[i1,a,i2].

SST[sigma_,a_][spinor_,{i1___},{ic_,jc_},{i2___}]:=TensorTMP[spinor,sigma,a:>Sequence[ic,jc]][i1,a,i2];

(* Contraction with tensors and 2-index derivatives *)
CSF2[False,sigma_][expr_,i_?EIndexQ,ic_,False]:=Expand[expr/.{
sigma[a_,j_,i]sigma[b_,k_,ic?UpIndexQ]:>Sigma[sigma][a,b,j,k],
sigma[a_,i,j_]sigma[b_,ic?UpIndexQ,k_]:>Dagger[Sigma[sigma]][a,b,j,k],
(sigma[a_,j_,i]|sigma[a_,i,j_])spinor_?xTensorQ[i1___,ic,jc_,i2___]:>SST[sigma,a][spinor,{i1},{ic,jc},{i2}]/;PairQ[j,jc],
(sigma[a_,jc_,ic]|sigma[a_,ic,jc_])spinor_?xTensorQ[i1___,i,j_,i2___]:>SST[sigma,a][spinor,{i1},{i,j},{i2}]/;PairQ[j,jc],
(sigma[a_,i,j_]|sigma[a_,j_,i])spinor_?xTensorQ[i1___,jc_,ic,i2___]:>SST[sigma,a][spinor,{i1},{jc,ic},{i2}]/;PairQ[j,jc],
(sigma[a_,jc_,ic]|sigma[a_,ic,jc_])spinor_?xTensorQ[i1___,j_,i,i2___]:>SST[sigma,a][spinor,{i1},{j,i},{i2}]/;PairQ[j,jc],
sigma[a_,i,j_]covd_?SpinCovDQ[ic,jc_][expr1_]:>CovDSpinSign[ic,jc]covd[a][expr1]/;PairQ[j,jc],
sigma[a_,ic,jc_]covd_?SpinCovDQ[i,j_][expr1_]:>CovDSpinSign[i,j]covd[a][expr1]/;PairQ[j,jc],
sigma[a_,j_,i]covd_?SpinCovDQ[jc_,ic][expr1_]:>CovDSpinSign[jc,ic]covd[a][expr1]/;PairQ[j,jc],
sigma[a_,jc_,ic]covd_?SpinCovDQ[j_,i][expr1_]:>CovDSpinSign[j,i]covd[a][expr1]/;PairQ[j,jc]}
];
(* Recursion through covariant derivatives *)
CSF2[True,sigma_][expr_,i_?AIndexQ,ic_,False]:=Expand[CSF2[False,sigma][expr,i,ic,False]/.rest_.(sig:(sigma[a_,i,j_]|sigma[a_,j_,i]))covd_Symbol?CovDQ[inds__][expr1_]:>rest covd[inds][CSF2[True,sigma][sig expr1,i,ic,False]]/;IsIndexOf[expr1,ic]&&IsIndexOf[expr1,ChangeIndex[j]]&&SolderingFormOfSpinCovD[covd]===sigma];
(* For other types of indices, do nothing *)
CSF2[_,_][expr_,_,_,False]:=expr;

5) There is nothing yet for OverDerivatives -> True, and there is nothing yet for Lie brackets.

6) The heads SpinorTMP and TensorTMP mark those objects which are being transformed from tensors to spinors or viceversa, respectively. They contain the name of the object being transformed, the name of the soldering form being used for the transformation and then a sequence of rules with the indices being transformed. This sequence can be empty.

(* Generalize some Q-functions *)
SpinorTMP/:HasDaggerCharacterQ[SpinorTMP[tensor_,sigma_,___]]:=HasDaggerCharacterQ[tensor];
SpinorTMP/:xTensorQ[SpinorTMP[tensor_,sigma_,___]]:=xTensorQ[tensor];
TensorTMP/:xTensorQ[TensorTMP[spinor_,sigma_,___]]:=xTensorQ[spinor];
(* IsIndexOf *)
SpinorTMP/:IsIndexOf[SpinorTMP[__][inds__],ind_,_]:=MemberQ[{inds},ind];
TensorTMP/:IsIndexOf[TensorTMP[__][inds__],ind_,_]:=MemberQ[{inds},ind];
(* Recursion *)
SpinorTMP[SpinorTMP[tensor_,sigma_,rules1___],sigma_,rules2___]:=SpinorTMP[tensor,sigma,rules1,rules2];
TensorTMP[TensorTMP[spinor_,sigma_,rules1___],sigma_,rules2___]:=TensorTMP[spinor,sigma,rules1,rules2];
SpinorTMP[SpinorTMP[__],__]:=Throw@Message[ContractSolderingForm::error,"Cannot contract two different soldering forms on the same tensor."];
TensorTMP[TensorTMP[__],__]:=Throw@Message[ContractSolderingForm::error,"Cannot contract two different soldering forms on the same spinor."];

7) These functions return the new objects, creating them if they do not exist yet:

ArrangeSpinTMP[SpinorTMP[tensor_,sigma_,rules___][spinds___]]:=With[{spinor=SpinorOfTensor[tensor,sigma]},
If[!xTensorQ[spinor],DefSpinorOfTensor[spinor[spinds],Apply[tensor,DummyIn/@SlotsOfTensor[tensor]],sigma]];
SpinorSign[spinor,rules][spinds]spinor[spinds]];

Converting a spinor into a tensor we need to worry about the index characters, because the global sign of the final expression depends on those, through the see - saw rule.

ArrangeSpinTMP[TensorTMP[spinor_,sigma_,rules___][tinds___]]:=With[{tensor=TensorOfSpinor[spinor,sigma]},
If[!xTensorQ[tensor],DefTensorOfSpinor[tensor[tinds],Apply[spinor,DummyIn/@SlotsOfTensor[spinor]],sigma]];
TensorSign[spinor,rules][tinds]tensor[tinds]];

Here is how we do it :

(* Derivatives: correct character is covariant *)
CovDSpinSign[i_,j_]:=If[UpIndexQ[i],-1,1]If[UpIndexQ[j],-1,1];
(* Transforming spinor into tensor *)
TensorSign[spinor_][___]:=1;
TensorSign[spinor_,rules__][tinds___]:=Apply[SpinorSign[spinor,rules],IndexList[tinds]/.{rules}];
(* Transforming tensor into spinor *)
SpinorSign[spinor_][___]:=1;
SpinorSign[spinor_,rules__][spinds___]:=With[{repinds=Last/@{rules}},
Inner[checkVB,xAct`xTensor`Private`SignedVBundleOfIndex/@repinds,SlotsOfTensor[spinor][[Flatten[Position[{spinds},#]&/@repinds]]],Times]];
(* Check vbundles are correct *)
checkVB[vb_,-vb_]:=-1;
checkVB[-vb_,vb_]:=-1;
checkVB[vb_,vb_]:=1;
checkVB[_,_]:=Throw@Message[ContractSolderingForm::error,"Internal inconsistency. Tell JMM."];

3.5. SeparateSolderingForm

This is the inverse operation to ContractSolderingForm. We will follow its same complicated structure in steps:

1) This is the user driver. It has four arguments in general:
          - the expression in which to separate
          - the indices to separate, with a number of shortcuts, all giving an IndexList at the end
          - the soldering-form to separate
          - the basis of the dummy index introduced, with AIndex as default.

(* To four arguments *)
SeparateSolderingForm[args___][expr_]:=SeparateSolderingForm[args][expr,All];
SeparateSolderingForm[][expr_,inds_]:=SeparateSolderingForm[$SolderingForms,AIndex][expr,inds];
SeparateSolderingForm[sigma_][expr_,inds_]:=SeparateSolderingForm[sigma,AIndex][expr,inds];
(* Four arguments *)
SeparateSolderingForm[list_List,basis_][expr_,inds_]:=Fold[SeparateSolderingForm[#2,basis][#1,inds]&,expr,list];
SeparateSolderingForm[sigma_Symbol,basis_][expr_,All]:=SeparateSolderingForm[sigma,basis][expr,IndicesOf[]];
SeparateSolderingForm[sigma_Symbol,basis_][expr_,vb_Symbol?VBundleQ]:=SeparateSolderingForm[sigma,basis][expr,IndicesOf[vb]];
SeparateSolderingForm[sigma_Symbol,basis_][expr_,covd_Symbol?CovDQ]:=SeparateSolderingForm[sigma,basis][expr,IndicesOf[covd]];
SeparateSolderingForm[sigma_Symbol,basis_][expr_,ind_?GIndexQ]:=SeparateSolderingForm[sigma,basis][expr,IndexList[ind]];
(* Thread over sums, before using IndicesOf *)
SeparateSolderingForm[sigma_Symbol,basis_][expr_Plus,inds_]:=SeparateSolderingForm[sigma,basis][#,inds]&/@expr;
SeparateSolderingForm[sigma_Symbol,basis_][expr_,f_IndicesOf]:=SeparateSolderingForm[sigma,basis][expr,f[expr]];
(* Expand list of indices *)
SeparateSolderingForm[sigma_Symbol,basis_][expr_,list_IndexList]:=RemoveTMP@Fold[SSF1[sigma,basis],expr,FindPairs[expr,{VBundleOfSolderingForm[sigma]},list]];
(* Errors *)
SeparateSolderingForm[x__][_,_IndexList]:=Throw@Message[SeparateSolderingForm::invalid,{x},"sigma or basis info"];
SeparateSolderingForm[_,_][_,x__]:=Message[SeparateSolderingForm::"argrx",SeparateSolderingForm,2+Length[{x}],2];
Protect[SeparateSolderingForm];

2) Now we separate those cases with an index on a tangent vbundle and an index on an inner vbundle :

SSF1[sigma_,basis_][expr_,pair_Pair]:=SSFInner[sigma,basis][expr,pair];
SSF1[sigma_,basis_][0,AnyIndices]:=0;
SSF1[sigma_,basis_][expr_,index_]:=SSFTangent[sigma,basis][expr,index]/;DaggerIndex[index]===index;
SSF1[__][expr_,_]:=expr;

3) Separation of soldering form for a tbundle index :

SSFTangent[sigma_,basis_][expr_,index_]:=With[{ivb=VBundleOfIndex[index],svb=VBundleOfSolderingForm[sigma]},
If[ivb=!=TangentBundleOfManifold@BaseOfVBundle@svb,Throw@Message[SeparateSolderingForm::invalid,sigma,"soldering form for index "<>ToString[index]]];
expr/.{
tensor_?xTensorQ[a___,index,b___]:>Module[{A=If[UpIndexQ[index],1,-1]DummyIn[svb,basis],Ad},
Ad=DaggerIndex[A];
If[HasDaggerCharacterQ[tensor],
SpinorTMP[tensor,sigma,index:>Sequence[Ad,A]][a,Ad,A,b],
SpinorTMP[tensor,sigma,index:>Sequence[A,Ad]][a,A,Ad,b]
]sigma[index,-A,-Ad]
]/;tensor=!=sigma,
covd_Symbol?CovDQ[a___,index,b___][expr1_]:>Module[{A=If[UpIndexQ[index],1,-1]DummyIn[svb,basis],Ad},
Ad=DaggerIndex[A];
CovDSpinSign[A,Ad]covd[a,A,Ad,b][expr1]sigma[index,-A,-Ad]]
}
];

4) Separation of soldering form for an inner index :

SSFInner[sigma_,basis_][expr_,Pair[i1_,i2_]]:=With[{tbundle=TangentBundleOfManifold@BaseOfVBundle@VBundleOfIndex[i1],ii1=If[HasDaggerCharacterQ[i2],i1,i2],ii2=If[HasDaggerCharacterQ[i2],i2,i1]},
expr/.{
spinor_?xTensorQ[a___,ii1,ii2,b___]:>Module[{dummy=If[UpIndexQ[ii1],1,-1]DummyIn[tbundle,basis]},TensorTMP[spinor,sigma][a,dummy,b]sigma[-dummy,ii1,ii2]]/;spinor=!=sigma,
spinor_?xTensorQ[a___,ii2,ii1,b___]:>Module[{dummy=If[UpIndexQ[ii1],1,-1]DummyIn[tbundle,basis]},TensorTMP[spinor,sigma][a,dummy,b]sigma[-dummy,ii1,ii2]]/;spinor=!=sigma,
covd_Symbol?CovDQ[ii1,ii2][expr1_]:>Module[{dummy=If[UpIndexQ[ii1],1,-1]DummyIn[tbundle,basis]},covd[dummy][expr1]sigma[-dummy,ii1,ii2]]
}];

3.6. IrreducibleDecomposition

In this section we create a command to decompose any spinor into irreducible parts, according to the result of e. g.  proposition 3.3.54 of vol. I of Penrose & Rindler.

User driver :

(* We should check that these are indeed spin-indices *)
IrreducibleDecomposition[tensor_Symbol?xTensorQ[inds__]]:=IrreducibleDecomposition[tensor[inds],First@Union@Sort[VBundleOfIndex/@IndexList@inds]];
(* Scalar case *)
IrreducibleDecomposition[tensor_Symbol?xTensorQ[],_]:=tensor[];
(* Vector case *)
IrreducibleDecomposition[tensor_Symbol?xTensor[a_],_]:=tensor[a];
(* General case: create TF tensor and separate VB and VBdagger *)
IrreducibleDecomposition[tensor_Symbol?xTensorQ[inds__],spinVB_]:=With[{pos1=SlotsOfVBundle[tensor[inds],spinVB],pos2=SlotsOfVBundle[tensor[inds],Dagger@spinVB],epsilon=First@MetricsOfVBundle@spinVB,tft=SymbolJoin["TF",tensor]},
If[!xTensorQ[tft],
DefTensor[tft[LI["TF"],AnyIndices@spinVB,AnyIndices@Dagger@spinVB],BaseOfVBundle[spinVB],Dagger->Complex,Master->tensor,ProtectNewSymbol->False]
];
SymmetryGroupOfTensor[tft[inds1__]]^:=JoinSGS[Symmetric[SlotsOfVBundle[tft[inds1 ],spinVB]],Symmetric[SlotsOfVBundle[tft[inds1],Dagger@spinVB]]];
tft[___,a_,___,-a_,___]:=0; 
tft[___,-a_,___,a_,___]:=0;Apply[Plus,DecoBuild[tft,{inds},epsilon,Dagger@epsilon]/@DecoOuter[pos1,pos2,Length[{inds}]]]
];

SlotsOfVBundle[list_,vbundle_]:=Flatten@Position[list,_?(AIndexQ[#,vbundle]&),{1}];

Internal code :

(* Given a list of slots, return all possible pairs, sorted *)
DecoPairs[list_]:=Union@Map[Sort,Partition[#,2]&/@Permutations[list],2];
(* Given a list of slots, return all possibe groups of 2n slots *)
DecoGroups[list_]:=Flatten[Table[DecoPairs/@Subsets[list,{n}],{n,0,Length@list,2}],2];
(* Given spin slots and spindag slots, return all combinations and the complementary slots *)
DecoOuter[list1_,list2_,length_]:=Flatten[Outer[DecoArrange[length],DecoGroups[list1],DecoGroups[list2],1],1];
DecoArrange[n_][list1_,list2_]:={list1,list2,Complement[Range[n],Flatten@list1,Flatten@list2]};
(* Construct actual TFT tensor and product of epsilons *)
DecoBuild[tft_,inds_,eps_,epsdag_][{list1_,list2_,list_}]:=
tft[LI@Join[list1,list2],Sequence@@(inds[[list]])]Times@@Apply[eps,Part[inds,#]&/@list1,1]Times@@Apply[epsdag,Part[inds,#]&/@list2,1];

4. Spin derivatives and curvature spinors

4.1. SpinCovDs

This function defines a spin derivative associated to a previously defined spin-structure. That means that this derivative vanish on its soldering form, but not necessarily on its epsilon spinor. Here we define both the action of the derivative on the tangent bundle and on the inner bundle of the spin-structure.

There are several important options affecting the "tangent" derivative: Torsion, Curvature, FromMetric and ExtendedFrom. Note that FromMetric could refer to any metric on the base manifold, not necessarily the metric of the spin-structure, but currently if it is not the sps-metric (which is always the first-metric of the base manifold) then we throw an error. The order of priorities is the following: 
	- If ExtendedFrom is not Null (call it cde) then the properties on the base are those of cde and Torsion / Curvature / FromMetric have no effect.
	- If cde is the Levi-Civita connection of the sps-metric, then we are defining a metric-compatible connection. Note that we do not impose here compatibility with the epsilon spinor of the spin-structure.
	- If cde is not the Levi-Civita connection of the sps-metric then the only accepted possibility is that cde has no associated metric.
	- If ExtendedFrom is Null then we create a fully new derivative:
	- If FromMetric is not Null then the new derivative will be compatible with that metric, and we check again that this metric is that of the spin-structure. If not, the metric association is simply removed.
	- If FromMetric is Null then the new derivative is not metric compatible.

Options[DefCovD]

Note that $SpinCovDs is private. We do not need it to be public. It is only used in Decomposition and UndefSpinCovD.

Options[DefSpinCovD]:={
Torsion->False,
FromMetric->Null,
ExtendedFrom->Null,
Master->Null,
ProtectNewSymbol->$ProtectNewSymbols,
DefInfo->{"spin covariant derivative",""}
};
$SpinCovDs:=Apply[Join,SpinCovDsOfSolderingForm/@$SolderingForms];
DefSpinCovD[covd_[-a_],sigma_,symbols_,options:OptionsPattern[]]:=Catch@Module[{metric,ef,newsymbols,a1,A1,A1d,B1,B1d},
{a1}=GetIndicesOfVBundle[VBundleOfIndex[a],1];
{A1,B1}=GetIndicesOfVBundle[VBundleOfSolderingForm[sigma],2];
{A1d,B1d}=DaggerIndex/@{A1,B1};
{metric,ef}=OptionValue[{FromMetric,ExtendedFrom}];

(* If extended, the properties of covd are those of ef (forget options) *)
If[ef=!=Null,metric=MetricOfCovD[ef]];

(* Check metric argument *)
If[metric=!=Null,
If[BaseOfVBundle@VBundleOfMetric[metric]=!=BaseOfVBundle@VBundleOfSolderingForm[sigma],Throw@Message[DefSpinCovD::error,"Incompatible vbundles of metric and soldering form."]];
(* Association to a frozen metric is removed 
If[xAct`xTensor`Private`FrozenMetricQ[metric],Message[DefSpinCovD::error,"A frozen metric cannot be used."];metric=Null]*)
];

(* Define derivative. How do we pass the options? *)
DefCovD[covd[-a],VBundleOfSolderingForm[sigma],symbols,FilterRules[{options},Options[DefCovD]]];
SpinCovDQ[covd]^=True;
(* Relations between the covariant derivative and the soldering form *)
SolderingFormOfSpinCovD[covd]^=sigma;
xUpAppendTo[SpinCovDsOfSolderingForm[sigma],covd];

(* If ef===Null then use the trick of extending from covd *)
If[ef===Null,ef=covd];

(* Construct associated curvature spinors *)
ConstructRTSpinors[covd,ef,sigma,metric,options];

(* Define associated box operators *)
DefBox[covd];

(* Compatibility with the spin structure *)
If[metric===Null,
covd[__][sigma[b_Symbol,-F_,-G_]]:=0;
covd[__][sigma[-b_,F_Symbol,G_Symbol]]:=0,
covd[__][sigma[b_,F_,G_]]:=0
];

(* Definitions as 2-index derivative *)
xAct`xTensor`Private`MakeLinearDerivative[{covd[F_,G_],covd[F,G]},True];

(* Relations between 2-index derivative and spacetime derivative *)
SpinorToTensor[covd,sigma]:=MakeRule[{covd[A1,A1d]@expr_,sigma[a1,A1,A1d]covd[-a1]@expr},UseSymmetries->False,Evaluate->True];
TensorToSpinor[covd,sigma]:=MakeRule[{covd[a1]@expr_,sigma[a1,A1,A1d]covd[-A1,-A1d]@expr},UseSymmetries->False,Evaluate->True];

(* Behaviour under complex conjugation: "Hermitian" *)
xAct`xTensor`Private`DaggerCovD[covd[inds__]]^:=Apply[covd,TransposeDagger@DaggerIndex@IndexList[inds]];

];
SetNumberOfArguments[DefSpinCovD,{3,Infinity}];
Protect[DefSpinCovD];

UndefSpinCovD[covd_]:=(
If[FreeQ[$SpinCovDs,covd],Throw@Message[SpinCovDs::unknown,"spin covd",covd]];
Undef/@Flatten[VisitorsOf/@ServantsOf[covd]];
UndefCovD[covd];
);
SetNumberOfArguments[UndefSpinCovD,1];
Protect[DefSpinCovD];

Default for the private function SpinCovDQ :

SpinCovDQ[covd_]:=False;

Multi-index covariant derivatives are still first - order derivatives in this context :

Unprotect[FirstDerQ];
FirstDerQ[_Symbol?SpinCovDQ[__]]:=True;
Protect[FirstDerQ];

4.2. Curvature spinors

Given a covariant derivative compatible with a spin structure, we need to construct the associated curvature and torsion spinors. Note that when the derivative is an extension of the Levi-Civita derivative of the metric of the spin-structure, then the curvature spinors are all uniquely defined by the base Levi-Civita connection, and the only freedom left in the extended derivative is in the AChristoffel tensor.

Output form for the curvature spinors (we do not mark them with the spin-structure) :

GiveOutputString[Chi,covd_]:=StringJoin["Χ","[",SymbolOfCovD[covd][[2]],"]"];
GiveOutputString[Phi,covd_]:=StringJoin["Φ","[",SymbolOfCovD[covd][[2]],"]"];
GiveOutputString[Psi,covd_]:=StringJoin["Ψ","[",SymbolOfCovD[covd][[2]],"]"];
GiveOutputString[Lambda,covd_]:=StringJoin["Λ","[",SymbolOfCovD[covd][[2]],"]"];

Here we should place the output form for the torsion spinors :

GiveOutputString[Omega,covd_]:=StringJoin["Ω","[",SymbolOfCovD[covd][[2]],"]"];

Symbols of the curvature spinors and the torsion.

Chi[covd_Symbol?CovDQ]:=GiveSymbol[Chi,covd];
Phi[covd_Symbol?CovDQ]:=GiveSymbol[Phi,covd];
Psi[covd_Symbol?CovDQ]:=GiveSymbol[Psi,covd];
Lambda[covd_Symbol?CovDQ]:=GiveSymbol[Lambda,covd];
Omega[covd_Symbol?CovDQ]:=GiveSymbol[Omega,covd];

Message on the decomposition rules of a tensor  (now deactivated);

compumessage[covd_,tensor_]:=Print["** Computing ",tensor," Decomposition rules for ",covd];

compumessage[covd_,tensor_]:=Null;

Default value for those global variables fixing our conventions for the definition of the curvature spinors and the torsion.

xAct`xTensor`Private`DefSign[$ChiSign,"(Subscript[s, Χ])",1];
xAct`xTensor`Private`DefSign[$PhiSign,"(Subscript[s, Φ])",1];
xAct`xTensor`Private`DefSign[$PsiSign,"(Subscript[s, Ψ])",1];
xAct`xTensor`Private`DefSign[$LambdaSign,"(Subscript[s, Λ])",1];
xAct`xTensor`Private`DefSign[$OmegaSign,"(Subscript[s, Ω])",1];

This is an important private function: covd is the derivative being defined; ef is the derivative we are extending from (when Null it is converted into covd); metric is the metric associated to covd, and currently it is either the sps-metric or Null.

Torsion tensors are created if *and only if* the derivative has torsion.

ConstructRTSpinors[covd_,ef_,sigma_,metric_,options:OptionsPattern[]]:=With[{
RiemannName=AddSpinorPrefix[Riemann[ef],SpinorPrefix[sigma]],
RicciName=AddSpinorPrefix[Ricci[ef],SpinorPrefix[sigma]],
WeylName=If[metric=!=Null,AddSpinorPrefix[Weyl[ef],SpinorPrefix[sigma]]],
TFRicciName=If[metric=!=Null,AddSpinorPrefix[TFRicci[ef],SpinorPrefix[sigma]]],

TorsionName=If[TorsionQ[covd],AddSpinorPrefix[Torsion[ef],SpinorPrefix[sigma]]],

FRiemannName=AddSpinorPrefix[FRiemann[covd],SpinorPrefix[sigma]],

ChiName=Chi[covd],
PhiName=Phi[covd],
PsiName=If[metric=!=Null,Psi[covd]],
LambdaName=If[metric=!=Null,Lambda[covd]],

OmegaName=If[TorsionQ[covd],Omega[covd]],

vbundle=VBundleOfSolderingForm[sigma],
vbundledag=Dagger@VBundleOfSolderingForm[sigma],
base=BaseOfVBundle@VBundleOfSolderingForm[sigma],
tbundle=TangentBundleOfSolderingForm[sigma],
eps=SpinMetricOfSolderingForm[sigma],
epsdag=Dagger@SpinMetricOfSolderingForm[sigma],

LeviCivitaQ=metric=!=Null&&!TorsionQ[covd],
LeviCivitaTorsionQ=metric=!=Null&&TorsionQ[covd]
},

Module[{A,B,F,G,Ad,Bd,Fd,Gd,a,b,c,d,PsiNamedag,FRiemannNamedag,ChiNamedag,PhiNamedag,OmegaNamedag,MakeRuleOptions},
{A,B,F,G}=GetIndicesOfVBundle[vbundle,4,{}];
{Ad,Bd,Fd,Gd}=DaggerIndex/@{A,B,F,G};
{a,b,c,d}=GetIndicesOfVBundle[tbundle,4,{}];

(* Change temporarily default options for MakeRule *)
MakeRuleOptions=Options[MakeRule];
SetOptions[MakeRule,UseSymmetries->False,ContractMetrics->False];

(* Definition of curvature spinors (we check that the original inner curvature is different from zero *)
If[FRiemann[covd][-a,-b,-F,-G]=!=0,
DefSpinorOfTensor[FRiemannName[-A,-Ad,-B,-Bd,-F,-G],FRiemann[covd][-a,-b,-F,-G],sigma,Dagger->Complex,options];
FRiemannNamedag=Dagger[FRiemannName];

DefTensor[ChiName[-A,-B,-F,-G],base,Which[LeviCivitaTorsionQ,StrongGenSet[{1,3},GenSet[xAct`xPerm`Cycles[{1,2}],xAct`xPerm`Cycles[{3,4}]]],LeviCivitaQ,StrongGenSet[{1,3},GenSet[xAct`xPerm`Cycles[{1,2}],xAct`xPerm`Cycles[{3,4}],xAct`xPerm`Cycles[{1,3},{2,4}]]],True,Symmetric[{3,4}]],Dagger->Complex,PrintAs:>GiveOutputString[Chi,covd],Master->covd,FilterRules[{options},Options[DefTensor]],DefInfo->{"curvature spinor",""}];
ChiNamedag:=Dagger[ChiName];

DefTensor[PhiName[-A,-B,-Fd,-Gd],base,If[LeviCivitaQ,StrongGenSet[{1,3},GenSet[xAct`xPerm`Cycles[{1,2}],xAct`xPerm`Cycles[{3,4}]]],Symmetric[{3,4}]],If[LeviCivitaQ,Dagger->Hermitian,Dagger->Complex],PrintAs:>GiveOutputString[Phi,covd],Master->covd,FilterRules[{options},Options[DefTensor]],DefInfo->{"curvature spinor",""}];
PhiNamedag=Dagger[PhiName];
];
(*Computation of the decomposition rules for the curvature spinors*)
compumessage[covd,FRiemann];
If[xTensorQ@FRiemannName,
covd/:DecompositionRules[covd,FRiemann]=Flatten[{MakeRule[{FRiemannName[-A,-Ad,-B,-Bd,-F,-G],$ChiSign ChiName[-F,-G,-A,-B]epsdag[-Ad,-Bd]+eps[-A,-B]$PhiSign PhiName[-F,-G,-Ad,-Bd]}],MakeRule[{Evaluate@FRiemannNamedag[-Ad,-A,-Bd,-B,-Fd,-Gd],$ChiSign ChiNamedag[-Fd,-Gd,-Ad,-Bd]eps[-A,-B]+epsdag[-Ad,-Bd]$PhiSign PhiNamedag[-Fd,-Gd,-A,-B]}]}]
];

If[LeviCivitaQ,

DefTensor[LambdaName[],base,Dagger->Real,PrintAs:>GiveOutputString[Lambda,covd],Master->covd,FilterRules[{options},Options[DefTensor]],DefInfo->{"spinor scalar curvature",""}];

DefTensor[PsiName[-A,-B,-F,-G],base,Symmetric[{1,2,3,4}],Dagger->Complex,PrintAs:>GiveOutputString[Psi,covd],Master->covd,FilterRules[{options},Options[DefTensor]],DefInfo->{"Weyl spinor",""}];
PsiNamedag=Dagger[PsiName];

compumessage[covd,Chi];
(*SymmetryGroupOfTensor[ChiName]^=StrongGenSet[{1,3},GenSet[Cycles[{1,2}],Cycles[{3,4}]]];*)
covd/:DecompositionRules[covd,Chi]=Flatten[{MakeRule[{ChiName[-A,-B,-F,-G],($LambdaSign/$ChiSign) LambdaName[](eps[-A,-G]eps[-B,-F]+eps[-A,-F]eps[-B,-G])+(($PsiSign/$ChiSign)) PsiName[-A,-B,-F,-G]}],MakeRule[{Evaluate[ChiNamedag[-Ad,-Bd,-Fd,-Gd]], ($LambdaSign/$ChiSign)LambdaName[](epsdag[-Ad,-Gd]epsdag[-Bd,-Fd]+epsdag[-Ad,-Fd]epsdag[-Bd,-Gd])+(($PsiSign/$ChiSign))PsiNamedag[-Ad,-Bd,-Fd,-Gd]}]}];

];

(* This part will be executed only if the Torsion spinor has not been defined *)
If[xTensorQ[TorsionName],
If[$DefInfoQ,Print["** DefSpinCovD:  Torsion spinor for tangent derivative ",ef," already defined"]],

DefSpinorOfTensor[TorsionName[-A,-Ad,-B,-Bd,-F,-Fd],Torsion[ef][-a,-b,-c],sigma,options];
];

(* Define the torsion spinor *)
If[TorsionQ@covd,
DefTensor[OmegaName[-Ad,-A,-B,-F],base,Symmetric[{3,4}],Dagger->Complex,PrintAs:>GiveOutputString[Omega,covd],Master->covd,FilterRules[{options},Options[DefTensor]],DefInfo->{"torsion spinor",""}];

OmegaNamedag=Dagger[OmegaName];

covd/:DecompositionRules[covd,Torsion]=
MakeRule[{TorsionName[-A,-Ad,-B,-Bd,-F,-Fd],epsdag[-Bd,-Fd]$OmegaSign OmegaName[-Ad,-A,-B,-F]+eps[-B,-F]$OmegaSign OmegaNamedag[-A,-Ad,-Bd,-Fd]}];
];

(* The remaining part will be executed only if the Riemann spinor has not been defined and if the Riemann and Ricci tensors do not vanish *)
If[xTensorQ[RiemannName]&&(Riemann[ef][-a,-b,-c,-d]=!=0)&&(Ricci[ef][-a,-b]=!=0),
If[$DefInfoQ,Print["** DefSpinCovD:  Curvature spinors for tangent derivative ",ef," already defined"]],

DefSpinorOfTensor[RiemannName[-A,-Ad,-B,-Bd,-F,-Fd,-G,-Gd],Riemann[ef][-a,-b,-c,-d],sigma,options];

DefSpinorOfTensor[RicciName[-A,-Ad,-B,-Bd],Ricci[ef][-a,-b],sigma,options];
If[!LeviCivitaQ&&xTensorQ@RiemannName,
compumessage[covd,Riemann];
covd/:DecompositionRules[covd,Riemann]=MakeRule[{RiemannName[-A,-Ad,-B,-Bd,-F,-Fd,-G,-Gd],eps[-F,-G]FRiemannNamedag[-Ad,-A,-Bd,-B,-Gd,-Fd]+epsdag[-Fd,-Gd]FRiemannName[-A,-Ad,-B,-Bd,-G,-F]}]];
If[LeviCivitaQ,

PsiNamedag=Dagger[PsiName];

DefSpinorOfTensor[WeylName[-A,-Ad,-B,-Bd,-F,-Fd,-G,-Gd],Weyl[ef][-a,-b,-c,-d],sigma,options];

DefSpinorOfTensor[TFRicciName[-A,-Ad,-B,-Bd],TFRicci[ef][-a,-b],sigma,options];

compumessage[covd,Riemann];
covd/:DecompositionRules[covd,Riemann]=MakeRule[{RiemannName[-A,-Ad,-B,-Bd,-F,-Fd,-G,-Gd],-2(-eps[-A,-F]eps[-B,-G]epsdag[-Ad,-Fd]epsdag[-Bd,-Gd]+eps[-A,-G]eps[-B,-F]epsdag[-Ad,-Gd]epsdag[-Bd,-Fd])$LambdaSign LambdaName[]-eps[-G,-F]epsdag[-Ad,-Bd]$PhiSign PhiName[-A,-B,-Gd,-Fd]-eps[-A,-B]epsdag[-Gd,-Fd]$PhiSign PhiName[-G,-F,-Ad,-Bd]-epsdag[-Ad,-Bd]epsdag[-Gd,-Fd]$PsiSign PsiName[-A,-B,-G,-F]-eps[-A,-B]eps[-G,-F]$PsiSign PsiNamedag[-Ad,-Bd,-Gd,-Fd]}];

compumessage[covd,Ricci];
covd/:DecompositionRules[covd,Ricci]=MakeRule[{RicciName[-A,-Ad,-B,-Bd],6$LambdaSign LambdaName[]eps[-A,-B]epsdag[-Ad,-Bd]-2$PhiSign PhiName[-A,-B,-Ad,-Bd]}];

compumessage[covd,TFRicci];
covd/:DecompositionRules[covd,TFRicci]=MakeRule[{TFRicciName[-A,-Ad,-B,-Bd],-2$PhiSign PhiName[-A,-B,-Ad,-Bd]}];

(* We use the RicciScalar and not its spinor *)
compumessage[covd,RicciScalar];
covd/:DecompositionRules[covd,RicciScalar]=MakeRule[{Evaluate[RicciScalar[ef][]],24$LambdaSign LambdaName[]}];

compumessage[covd,Weyl];
covd/:DecompositionRules[covd,Weyl]=MakeRule[{WeylName[-A,-Ad,-B,-Bd,-F,-Fd,-G,-Gd],-epsdag[-Ad,-Bd]epsdag[-Gd,-Fd]$PsiSign PsiName[-A,-B,-G,-F]-eps[-A,-B]eps[-G,-F]$PsiSign PsiNamedag[-Ad,-Bd,-Gd,-Fd]}];

]
];
(* Return to original options *)
Options[MakeRule]=MakeRuleOptions;

]
];

We define next the rules implementing the decomposition in irreducible parts of certain curvature objects.

User function :

?Decomposition

Decomposition[expr_]:=Decomposition[expr,{FRiemann,Riemann,Ricci,TFRicci,RicciScalar,Weyl,Torsion}];
Decomposition[expr_,object_]:=Decomposition[expr,object,$SpinCovDs];
Decomposition[expr_,objects_List,covd_]:=Fold[Decomposition[#1,#2,covd]&,expr,objects];
Decomposition[expr_,object_,covds_List]:=Fold[Decomposition[#1,object,#2]&,expr,covds];
Decomposition[expr_,object_,covd_]:=expr/.DecompositionRules[covd,object];
DecompositionRules[covd_,object_]:={};
SetNumberOfArguments[Decomposition,{1,3}];
Protect[Decomposition];

4.3. Box operator

This is the Box operator of a spincovd. We do not define the conjugated symbol DaggerBox because it is possible (and simpler) to work with just one symbol. Whether we are using one or the other is encoded in the indices.

In spite of being a symmetrized second derivative, this operator is actually a first derivative, and so it can be defined using the type CovD. Note that it is CovD and not SpinCovD. However, we do not use DefCovD to define it. We can use UndefCovD to undefine it, because UndefCovD knows what to do with the objects in the private list $MultiIndexCovDs.

DefBox[covd_Symbol]:=With[{boxcd=SymbolJoin["Box",covd]},
CovDQ[boxcd]^=True;
AppendTo[xAct`xTensor`Private`$MultiIndexCovDs,boxcd];
xAct`xTensor`Private`MakeLinearDerivative[{boxcd[A_,B_],boxcd[A,B]},True];
SymmetryGroupOfCovD[boxcd]^=Symmetric[{1,2},xAct`xPerm`Cycles];
ManifoldOfCovD[boxcd]^=ManifoldOfCovD[covd];
VBundlesOfCovD[boxcd]^=VBundlesOfCovD[covd];
DependenciesOfCovD[boxcd]^=DependenciesOfCovD[covd];
CovDOfBox[boxcd]^=covd;
boxcd/:Dagger[boxcd[A_,B_][expr_]]:=boxcd[DaggerIndex[A],DaggerIndex[B]][Dagger[expr]];
SymbolOfCovD[boxcd]^={First[SymbolOfCovD[covd]],StringJoin["□","[",Part[SymbolOfCovD@covd,2],"]"]};
xAct`xTensor`Private`SymbolRelations[boxcd,covd,{}];
Protect[boxcd];
];

Note that we have not used the symbol Box, which is a Mathematica built-in.

This code expands the box operator into covariant derivatives (formula (4.9.2) of Penrose & Rindler Vol 2).

BoxToCovD[expr_,boxcd_]:=With[{
cd=CovDOfBox@boxcd,
spin=VBundlesOfCovD[boxcd][[2]],spindag=VBundlesOfCovD[boxcd][[3]]},
expr/.{boxcd[A_,B_]@L_:>With[{Cdag=DummyIn[spindag]},xAct`xTensor`Symmetrize[cd[A,-Cdag]@cd[B,Cdag]@L,{A,B}]]/;ABIndexQ[A,spin]&&ABIndexQ[B,spin],boxcd[A_,B_]@L_:>With[{C=DummyIn[spin]},
xAct`xTensor`Symmetrize[cd[-C,A]@cd[C,B]@L,{A,B}]]/;ABIndexQ[A,spindag]&&ABIndexQ[B,spindag]}
];
SetNumberOfArguments[BoxToCovD,2];
Protect[BoxToCovD];

Expansion of the box operator in terms of the curvature spinors (Eqs. (4.9.8)-(4.9.17) of  Penrose & Rindler Vol 2).

BoxToCurvature[expr_,boxcd_]:=With[{spin=VBundlesOfCovD[boxcd][[2]],spindag=VBundlesOfCovD[boxcd][[3]]},expr/.boxcd[A_,B_]@L_:>addCurvatureBox[L,CovDOfBox@boxcd,{A,B},List@@FindFreeIndices[L],spin,spindag]];
SetNumberOfArguments[BoxToCurvature,2];
Protect[BoxToCurvature];

addCurvatureBox[expr_,covd_,{A_,B_},frees_,vb_,vbdag_]:=With[{dummy1=DummyIn[vb],dummy2=DummyIn[vbdag],vbQ=xAct`xTensor`Private`VBundleIndexQ[vb],vbdagQ=xAct`xTensor`Private`VBundleIndexQ[vbdag],vbpmQ=xAct`xTensor`Private`VBundleIndexPMQ[vb],vbpmdagQ=xAct`xTensor`Private`VBundleIndexPMQ[vbdag],chicd=Chi[covd],phicd=Phi[covd],omegacd=If[TorsionQ[covd],Omega[covd],Zero]},
Which[ABIndexQ[A,vb]&&ABIndexQ[B,vb]&&TorsionQ@covd,-$ChiSign $RiemannSign Plus@@((chicd[#,-dummy1,A,B] ReplaceIndex[expr,#->dummy1]&)/@Select[frees,vbQ])+$ChiSign $RiemannSign Plus@@((chicd[dummy1,#,A,B] ReplaceIndex[expr,#->-dummy1]&)/@Complement[Select[frees,vbpmQ],Select[frees,vbQ]])-$PhiSign $RiemannSign Plus@@((Dagger[phicd][#,-dummy2,A,B] ReplaceIndex[expr,#->dummy2]&)/@Select[frees,vbdagQ])+$PhiSign $RiemannSign Plus@@((Dagger[phicd][dummy2,#,A,B] ReplaceIndex[expr,#->-dummy2]&)/@Complement[Select[frees,vbpmdagQ],Select[frees,vbdagQ]])-$TorsionSign $OmegaSign omegacd[dummy2,dummy1,A,B]covd[-dummy1,-dummy2]@expr,
ABIndexQ[A,vb]&&ABIndexQ[B,vb]&&!TorsionQ@covd,
-$ChiSign $RiemannSign Plus@@((chicd[-dummy1,#,A,B] ReplaceIndex[expr,#->dummy1]&)/@Select[frees,vbpmQ])-$PhiSign $RiemannSign Plus@@((Dagger[phicd][-dummy2,#,A,B] ReplaceIndex[expr,#->dummy2]&)/@Select[frees,vbpmdagQ]),
ABIndexQ[A,vbdag]&&ABIndexQ[B,vbdag]&&TorsionQ@covd,
-$ChiSign $RiemannSign Plus@@((Dagger[chicd][#,-dummy2,A,B] ReplaceIndex[expr,#->dummy2]&)/@Select[frees,vbdagQ])+$ChiSign $RiemannSign Plus@@((Dagger[chicd][dummy2,#,A,B] ReplaceIndex[expr,#->-dummy2]&)/@Complement[Select[frees,vbpmdagQ],Select[frees,vbdagQ]])-$PhiSign $RiemannSign Plus@@((phicd[#,-dummy1,A,B] ReplaceIndex[expr,#->dummy1]&)/@Select[frees,vbQ])+$PhiSign $RiemannSign Plus@@((phicd[dummy1,#,A,B] ReplaceIndex[expr,#->-dummy1]&)/@Complement[Select[frees,vbpmQ],Select[frees,vbQ]])-$TorsionSign $OmegaSign Dagger[omegacd][dummy1,dummy2,A,B]covd[-dummy1,-dummy2]@expr,
ABIndexQ[A,vbdag]&&ABIndexQ[B,vbdag]&&!TorsionQ@covd,
-$ChiSign $RiemannSign Plus@@((Dagger[chicd][-dummy2,#,A,B] ReplaceIndex[expr,#->dummy2]&)/@Select[frees,vbpmdagQ])-$PhiSign $RiemannSign Plus@@((phicd[-dummy1,#,A,B] ReplaceIndex[expr,#->dummy1]&)/@Select[frees,vbpmQ])
]

];

The commutation of 2-index spin covariant derivatives can be written in terms of the box operator as follows:

SortSpinCovDs[expr1_,cd_?CovDQ]:=expr1/.cd[A_,A†_]@cd[B_,B†_]@expr_:>cd[B,B†]@cd[A,A†]@expr+SpinMetricOfSolderingForm[SolderingFormOfSpinCovD@cd][A,B] SymbolJoin["Box",cd][A†,B†]@expr+Dagger[SpinMetricOfSolderingForm[SolderingFormOfSpinCovD@cd]][A†,B†] SymbolJoin["Box",cd][A,B]@expr/;DisorderedPairQ[A,B];

5. End private and package

End[]
EndPackage[]

6. Examples

The user context is empty :

?Global`*

0) Spacetime setup :

DefManifold[M4,4,{a,b,c,d,e,f}]

DefMetric[{1,3,0},g[-a,-b],CD]

1) The Tetra tensor:

Tetrag[-a,-b,-c,-d]

%/.TetraRule[g]

Tetrag†[-a,-b,-c,-d]

%/.TetraRule[g]

Tetrag[a,b,c,d]-Tetrag[c,d,a,b]//ToCanonical

Tetrag[a,b,c,d]-Tetrag[b,a,d,c]//ToCanonical

Tetrag[-b,c,-d,-c]/.TetraRule[g]//ToCanonical

Tetrag[-c,-d,b,-b]/.TetraRule[g]//ToCanonical

Tetrag[-a,c,-b,d]Tetrag[-e,-c,-f,-d]/.TetraRule[g]//ToCanonical

Tetrag[-a,-b,c,d]Tetrag†[-e,-f,-c,-d]/.TetraRule[g]//ToCanonical

Tetrag[-a,-b,c,d]Tetrag[-e,-d,-c,-f]/.TetraRule[g]//ToCanonical

Tetrag[-a,-b,-c,-d]Tetrag[c,d,-e,-f]-2Tetrag[-b,-a,-e,-f]/.TetraRule[g]//ContractMetric//ToCanonical

2) Spin structure :

We can define a spin structure by specifying the names of the metric, soldering form and covariant derivative:

DefSpinStructure[g,Spin,{A,B,C,D,F,G},ϵ,σ,cd]

Compare with formula 3.4.57 of Penrose and Rindler . This is their tensor U[-a,-b,c,d]:

U[-a_,-b_,c_,d_]=ϵ[-A,D]ϵ[-B,C]ϵ†[-A†,C†]ϵ†[-B†,D†]σ[-a,A,A†]σ[-b,B,B†]σ[c,-C,-C†]σ[d,-D,-D†]//ContractSolderingForm//ToCanonical

This formula is identical to theirs:

%/.TetraRule[g]//ToCanonical

This is their formula 3.4.66 :

U[-a,-b,c,d]U[-c,-d,e,f]/.TetraRule[g]//ContractMetric//ToCanonical

Remove[U];

3) Define spinors and their tensor equivalents :

We define a spinor (note that we do not need to add the option Dagger->Complex; this is introduced by DefSpinor):

DefSpinor[κ[A,A†],M4]

Some other checks :

Catch@DefSpinor[test[A,B,C†],M4,Symmetric[{1,2,3}]]

DefSpinor[test[A,B,C†,D†],M4,GenSet[xAct`xPerm`Cycles[{1,2}],xAct`xPerm`Cycles[{3,4}]]]

UndefSpinor[test]

The κ spinor has a tensorial equivalent, which is complex and hence defines its conjugate. We can choose an arbitrary name for it:

DefTensorOfSpinor[KT[a],κ[-A,A†],σ]

Note the following relations, all having σ and not σ† :

TensorOfSpinor[κ,σ]

TensorOfSpinor[κ†,σ]

SpinorOfTensor[KT,σ]

SpinorOfTensor[KT†,σ]

Note that we shall be using the default choice of PrintAs form :

PrintAs[KT]

This is formula 3.3.31 of Penrose and Rindler, with the same sign convention:

epsilong[-a,-b,-c,-d]//SeparateSolderingForm[]

4) Pairs of conjugated indices :

This is the private function in xTensor in charge of deciding which indices are paired :

xAct`xTensor`Private`TransposeDaggerPairs[κ[A,B,C†,D†]]

%//InputForm

By default it throws an error when the numbers of indices do not coincide :

Catch@xAct`xTensor`Private`TransposeDaggerPairs[κ[A,B,C†,D†,F]]

However, that feature can be deactivated, and then one of the lists is shortened :

xAct`xTensor`Private`TransposeDaggerPairs[κ[A,B,C†,D†,F],Spin,False]

For this function, the order between dagger and nondaggered indices is irrelevant. It only matters the order within each set :

xAct`xTensor`Private`TransposeDaggerPairs[κ[C†,A,D†,B]]

xAct`xTensor`Private`TransposeDaggerPairs[κ[B,C†,D†,A]]

Note that daggered indices are always sorted last in the pairs:

GetIndicesOfVBundle[Spin,20]

xAct`xTensor`Private`TransposeDaggerPairs[κ[G†,G14,C†,D]]

5) Manipulations with the soldering - form :

expr=κ[-A,-A†]

PutSolderingForm[expr]

ContractSolderingForm[%]

We can also use  many other structures in the second argument:

PutSolderingForm[expr,Pair[-A,-A†]]

PutSolderingForm[expr,Spin]

PutSolderingForm[expr,κ]

We assume that Pair always has the non - daggered index first, even when that is not the order in the expression:

PutSolderingForm[expr,Pair[-A†,-A]]

PutSolderingForm[Dagger[expr],Pair[-A,-A†]]

SeparateSolderingForm[][expr]

ContractSolderingForm[%]

It is possible to contract the soldering form on daggered expressions:

expr=κ†[-A†,-B]

PutSolderingForm[expr]

ContractSolderingForm[%]

SeparateSolderingForm[][expr]

6) Define tensors and their spinor equivalents :

We define now a complex tensor.

DefTensor[t[-a,-b],M4,Dagger->Complex]

This tensor has a spinor counterpart.

DefSpinorOfTensor[σt[-A,-A†,-B,-B†],t[-a,-b],σ]

Now we check that everything works as it should

t[-a,-b]

PutSolderingForm[%]

t[-a,-b]σ[a,-A,-C†]σ[b,-B,-D†]

ContractSolderingForm@%

Dagger[SeparateSolderingForm[][%]]

SeparateSolderingForm[][Dagger[%%]]

ContractSolderingForm[%]

t†[-a,-b]

PutSolderingForm@%

ContractSolderingForm@%

SpinorOfTensor[t†,σ]

SpinorOfTensor[t,σ]

SeparateSolderingForm[][t[-a,-b]]

ContractSolderingForm[%]

8) Spin covds :

cd[-C,-D†][t[A]]

SeparateSolderingForm[][%,cd]

ContractSolderingForm[%]

InputForm[%]

Look at this:

expr=cd[-C,-D†][t[a,A]]

SeparateSolderingForm[][expr]

SeparateSolderingForm[][expr,Spin]

SeparateSolderingForm[][expr,TangentM4]

Contraction through derivatives:

ContractSolderingForm[%]

We define another spinor

DefSpinor[ξ[A],M4]

σ[a,-B,-B†]cd[-a][g[]]

ContractSolderingForm[%]

%//InputForm

σ[a,-B,-B†]cd[-a][g[C]]

ContractSolderingForm[%]

More on two - index derivatives :

cd[-A,-B†][g[]+3σ[]]

%//InputForm

9) Decompositions :

This is the Riemann tensor

RiemannCD[-a,-b,-c,-d]

We find the decomposittion of the Riemann tensor by two different procedures and compare the results at the end

%//RiemannToWeyl

The spinor equivalent of this expression is given by

PutSolderingForm[%]

ContractMetric@%

ContractSolderingForm@%

We can find the decomposition of this into irreducible parts

Decomposition[%]//ContractMetric

ToCanonical@%

Collect[%,Lambdacd[],FactorTerms]

exprA=%

The alternative procedure is as follows

PutSolderingForm[RiemannCD[-a,-b,-c,-d]]

ContractSolderingForm@%

%//Decomposition

ToCanonical@ContractMetric@%

Collect[%,Lambdacd[],FactorTerms]

exprB=%

This must be zero using dim-dep relations:

diff=exprA-exprB//ToCanonical

Let us check it. First we generate all possible dim - dep relation, using brute force on the 24 x 24 possible index configurations:

antisym1[{a_,b_,c_,d_,adg_,bdg_,cdg_,ddg_}]:=ToCanonical[3Antisymmetrize[Phicd[-a,-b,-adg,-bdg]ϵ[-c,-d]ϵ†[-cdg,-ddg],{-a,-c,-d}]]

antisym2[{a_,b_,c_,d_,adg_,bdg_,cdg_,ddg_}]:=ToCanonical[3Antisymmetrize[Phicd[-a,-b,-adg,-bdg]ϵ[-c,-d]ϵ†[-cdg,-ddg],{-adg,-cdg,-ddg}]]

Length[list1=antisym1/@Flatten[Outer[Join,Permutations[{A,B,C,D}],Permutations[{A†,B†,C†,D†}],1],1]]

Length[list2=antisym2/@Flatten[Outer[Join,Permutations[{A,B,C,D}],Permutations[{A†,B†,C†,D†}],1],1]]

There are 48 independent relations (actually half of them because all relations are repeated due to a minus sign) in each case:

Length[list1=Union[list1]]

Length[list2=Union[list2]]

Length[list=Union[list1,list2]]

We write our equation as a linear combination of those identities, and then equate the coefficients to zero :

system=Map[#==0&,First/@List@@Collect[diff+Array[c,{96}].list,{Phicd[__],ϵ[__],ϵ†[__]},Simplify]]

There are many solutions :

Solve[system,Array[c,96]]

Length[First[%]]

instance=First@FindInstance[system,Array[c,96]]

Cases[instance,HoldPattern[_->1|-1]]

list.Array[c,96]/.instance

diff+%//ToCanonical

which says that our original expression is a linear combination of the dim-dep identities. Clean up:

Remove[antisym1,antisym2,list1,list2,list,system,diff,instance,exprA,exprB,adg,bdg,cdg,ddg]

With the Ricci tensor :

PutSolderingForm[RicciCD[-a,-b]]

ContractSolderingForm@%

%//InputForm

Decomposition[%]

ToCanonical@ContractMetric@%

We can work out similar calculations for the Weyl tensor :

WeylCD[a,b,c,d]

PutSolderingForm[%]

ContractSolderingForm@%

Decomposition[%,Weyl]

ContractMetric@%

cd[-a][%]

cd[-b][%]

PutSolderingForm[%]

Handling of box operators :

Boxcd[-A,-B][ξ[C]]

BoxToCovD[%,Boxcd]

BoxToCurvature[%%,Boxcd]

Another example

Boxcd[-A,-B]@κ[-F,-F†]

BoxToCovD[%,Boxcd]

BoxToCurvature[%%,Boxcd]

ϵ[D,B]Boxcd[-A,-B][ξ[C]]

ContractMetric[%]

Implode[%]

ToCanonical[%]

Explode[%]

Implode[%]

Explode[%]

Dagger[%]

InputForm[%]

Implode[%]

InputForm[%]

Explode[%%]

Dagger[%]

Boxcd[-A,-B]@Psicd[-F,-C,-D,-G]

Dagger@%

BoxToCurvature[%,Boxcd]

Other objects :

DefSpinor[W[A,A†],M4]

DefSpinCovD[nb[-a],σ,{";","𝔇"}]

σ⎵Riccinb[-A,-A†,-B,-B†]

PutSolderingForm[%,{Pair[-A,-A†],Pair[-B,-B†]}]

ContractSolderingForm[%]

Riccinb[-a,-b]

PutSolderingForm[%]

ContractSolderingForm[%]

DefSpinCovD[nbg[-a],σ,{";","D"},FromMetric->g]

?σ⎵RiemannCD

DefSpinCovD[nbG[-a],σ,{";","D"},ExtendedFrom->CD]

$CovDs

Let us now check contraction of soldering forms:

DefTensor[v[a],M4]

v[a]

DefSpinorOfTensor[σv[A,A†],v[a],σ]

PutSolderingForm[%%]

ContractSolderingForm[%]

?σv

σv[A,B†]σ[a,-A,-B†]

ContractSolderingForm[%]

σv[A,B†]σ[a,-A,-B†]v[b]

ContractSolderingForm[%]

The command must fail in these cases:

v[a]σ[-b,A,B†]

ContractSolderingForm[%]

σv[A,B†]σ[a,-A,-C†]

ContractSolderingForm[%]

Note that there is no check of index consistency in the soldering form :

σv[A,B†]σ[a,-B†,-A]

ContractSolderingForm[%]

Multiple contraction:

σ[a,-A,-A†]σ[b,-B,-B†]σ[c,-C,-C†]σ[d,-D,-D†]RiemannCD[-a,-b,-c,-d]

ContractSolderingForm@%

Contraction of spinorial indices :

σ[a,-A,-A†]σ[b,-B,-B†]σ⎵RicciCD[A,A†,B,B†]

ContractSolderingForm[%]

Intermediate contractions are not acceptable, though ContractSolderingForm does not see it. Use Validate to check the result :

σ[b,-B,-B†]σ⎵RicciCD[A,A†,B,B†]

ContractSolderingForm[%]

Validate[%]

σ[a,-A,-A†]σ[b,-B,-B†]RicciCD[-a,-b]

ContractSolderingForm[%]

% σ[-a,A,A†]σ[-b,B,B†]

ContractSolderingForm[%]

Let us now play with sigma, Sigma and Tetra :

σ[a,-A,-B†]σ[-a,-C,-D†]

σ[a,A,-B†]σ[b,-C,B†]

ContractSolderingForm[%]

Dagger[%%]

ContractSolderingForm[%]

Sigmaσ[-a,-b,B,-B]

Sigmaσ[b,-b,-A,-B]

Tetrag[-a,-b,-c,-d]Sigmaσ[c,d,-A,-B]

Sigmaσ[-a,-b,-A,C]Sigmaσ[-c,-d,-D,-C]

Sigmaσ[-a,-d,A,C]Sigmaσ[-b,-c,-A,-C]

Sigmaσ†[-a,-d,A†,C†]Sigmaσ†[-b,-c,-A†,-C†]

σ[-b,-A,C†]σ[-c,D,-C†]σ[-a,A,B†]σ[-d,-D,-B†]

%//ContractSolderingForm

Remove[expr]

Now we read xCoba:

<<xAct`xCoba`

Catch@DefBasis[basis,Spin,{1,2}]

Catch@DefBasis[basis,Spin,{1,2},Dagger->Complex]

Note that we are working with the C executable for canonicalization:

MathLink/.Options[CanonicalPerm]

DefTensor[T[a],M4]

T[{A,basis}]ϵ[{-A,-basis},{-B,-basis}]//ContractMetric

T[{-A,-basis}]ϵ[{A,basis},{B,basis}]//ContractMetric

ToCanonical[T[{A,basis}]T[{-A,-basis}]]

ToCanonical[T[A]T[-A]]

Now undefine lots of things . First the spinors constructed using the soldering form:

ServantsOf[σ]

VisitorsOf[σ]

Undef/@VisitorsOf[σ];

UndefTensor[v]

Now the derivatives :

UndefCovD[nb]

UndefCovD[nbg]

UndefCovD[nbG]

The basis on the vbundle :

UndefBasis[basis]

UndefTensor[ξ]

UndefTensor[W]

UndefTensor@κ

Undef spin structure through the vbundle :

UndefSpinStructure[σ]

UndefTensor[g]

UndefTensor[T]

UndefTensor@t

$Tensors

$CovDs

UndefManifold[M4]

There are no memory leaks:

?Global`*