(* ::Package:: *)

(************************************************************************)
(* This file was generated automatically by the Mathematica front end.  *)
(* It contains Initialization cells from a Notebook file, which         *)
(* typically will have the same name as this file except ending in      *)
(* ".nb" instead of ".m".                                               *)
(*                                                                      *)
(* This file is intended to be loaded into the Mathematica kernel using *)
(* the package loading commands Get or Needs.  Doing so is equivalent   *)
(* to using the Evaluate Initialization Cells menu command in the front *)
(* end.                                                                 *)
(*                                                                      *)
(* DO NOT EDIT THIS FILE.  This entire file is regenerated              *)
(* automatically each time the parent Notebook file is saved in the     *)
(* Mathematica front end.  Any changes you make to this file will be    *)
(* overwritten.                                                         *)
(************************************************************************)



BeginPackage["matcher`"]


ComputeRGEModeltoEFT::usage="";
GetFinalRuleOrdered::usage="";
GenerateSymmetries::usage="";
CheckLinearDependence::usage="";
CheckGreenSol::usage="CheckGreenSol[full,eft,greensol] checks is the solution in the green basis given by greensol solves all amplitudes in the matching of UV model full onto EFT eft";
RenameOneLoopWC::usage="";
RemoveUnderscore::usage="";
PutUnderscore::usage="";
ImposeHermiticity::usage="";
GetSpecificAmplitude::usage="";
GetSpecificAmplitudeNew::usage="";
MiGetSpecificAmplitudeNew::usage="";
GetSpecificAmplitudeNewNew::usage="";
GenericMatchEFT::usage="";
MatchEFT::usage="";
AlphasInSolQ::usage="";
TensorMultiply::usage="";
SolveMinimalLinearSystem::usage="";
SortByType::usage="";
ComputeWilsonCoefficients::usage="";
ComputeWilsonCoefficientsNew::usage="";
MatchModeltoEFT::usage="";
ComputeWilsonCoefficientsNewNew::usage="";
MatchOneAmplitude::usage="";
MyCoefficientList::usage="";
CheckIsZero::usage="";
DummyZeroQ::usage="";
EliminateRepeated::usage="";
positionDuplicates::usage="";
PrepareAmplitude::usage="";
GetTensorsAndIndicesAndOrdering::usage="";
GetFunctionNameAndArguments::usage="";
powerProductFormToList::usage="";
GetKinematics::usage="";
GetDictionary::usage="GetDictionary[modelname] returns a list of two dictionaries -associations- that return, for a list of input particles, a list of two entries, the simplified amplitude and the definition of the extra symbols to compute it. The first dictionary corresponds to tree level and the second one to one loop. If only tree level results are present then the list is of length one.";
EliminateSelfFromRule::usage="";
PrettyShow::usage="return a nice print of the Wilson coefficients in the warsaw basis";
ComputeWilsonCoefficients::usage="";
CheckWardIdentities::usage="";
SimpleShow::usage="";
InitializeModel::usage="";
CompareTwoMatches::usage="CompareTwoMatches[list1_,list2_] compares two lists of rules and checks if they are equal independently of order and naming of dummy indices";
SumExpandIndicesEfficient::usage="";
miSumExpandIndices::usage="";
Splitter::usage="";
GetAlphas::usage="";
GetAlphasGeneral::usage="";
GetAlphasWithArguments::usage="";
GetAlphasWithArgumentsFromDict::usage="";
GetFunctionsFromRules::usage="";
GiveAllChanges::usage="";
GetRelevantRules::usage="";
ReduceFlavorSymmetry::usage="";
EliminatParenthesisInAlphas::usage="";
PutParenthesisInAlphas::usage="";

CheckOneAmplitude::usage="";
ComputesSSPower::usage="";
ComplexConjugate::usage="";
GetIndices::usage="";
TreatDummyFlavor::usage="";
TreatDummyFlavorGeneral::usage="";


Begin["`Private`"]


$matchmakerpath="REPLACEPATH"

$effdiranddimlist={{"L2SM",2},{"L4SM",4},{"L6SM_0F",6},{"L6SM_2F_0S_3D",6},{"L6SM_2F_1S_2D",6},{"L6SM_2F_2S_1D",6},{"L6SM_2F_3S_0D",6},{"L6SM_4F_LLLL",6},{"L6SM_4F_LLRR_LRRL",6},{"L6SM_4F_LRLR",6},{"L6SM_4F_RRRR",6}};

$wieffdiranddimlist={{"L4SM",4},{"L6SM_0F",6},{"L6SM_2F_0S_3D",6},{"L6SM_2F_1S_2D",6},{"L6SM_2F_2S_1D",6}};


fli=Table[ToExpression["Global`fl"<>ToString[i]],{i,30}];
miflis=Table[ToExpression["Global`mif"<>ToString[i]],{i,30}];
FLi=Table[ToExpression["Global`FL"<>ToString[i]],{i,30}];
MIFLi=Table[ToExpression["Global`MIFL"<>ToString[i]],{i,30}];
mifl2MIFL=MapThread[Rule,{miflis,MIFLi}];


(* The system of equations has to be such that the equations are equated to 0
For instance for a system {{a1 x + b1 y\[Equal]c1},{a2 x + b2 y\[Equal]c2}}} we have
to call SolveMinimalLinearSystem[{{a1 x + b1 y-c1},{a2 x + b2 y-c2}}},{x,y}] *)
SolveMinimalLinearSystem[eqs_List,vars_List]:=Block[{sys,systmp,indices,i,minimaleqs,sol,check},
If[Length[vars]>0,
sys=Normal[CoefficientArrays[eqs,vars][[2]]];
systmp={sys[[1]]};
indices={1};
Do[
If[MatrixRank[Join[systmp,{sys[[i]]}]]>MatrixRank[systmp],systmp=Join[systmp,{sys[[i]]}];AppendTo[indices,i]]
,{i,2,Length[sys]}];
minimaleqs=Part[eqs,#]==0&/@indices;
Off[Solve::svars];
Off[Solve::trace];
sol=Solve[minimaleqs,vars][[1]];
On[Solve::svars];
On[Solve::trace];
check=DeleteCases[Simplify[eqs/.sol],0];,
sol={};
check=eqs;];
(*If[Length[check]>0,Print["Problems!!!",sol,check,eqs,vars];];*)
{sol,check}
]


(*GetDictionary[modelname] returns a list of two dictionaries -associations- that return, for a list of input particles, a list of two entries, the simplified amplitude and the definition of the extra symbols to compute it. The first dictionary corresponds to tree level and the second one to one loop. If only tree level results are present then the list is of length one *)
GetDictionary[modeldir_,replsym_:{}]:=Block[{lista,listaout,input,amp,res,lista0,lista1,input0,input1,amp0,amp1,res0,res1},
lista={FileNames[modeldir<>"/FORM/proc_0loop/*log.mat"],FileNames[modeldir<>"/FORM/proc_1loop/*log.mat"]};
listaout={FileNames[modeldir<>"/FORM/proc_0loop/*out.mat"],FileNames[modeldir<>"/FORM/proc_1loop/*out.mat"]};
If[Length[lista[[2]]]==0,lista={lista[[1]]}];
input=Table[StringSplit[StringReplace[StringSplit[#,"/"][[-1]],{".log.mat"->""}],"_"]&/@lista[[i]],{i,Length[lista]}];
amp=Table[ToExpression[StringJoin["ampl",#]]&/@StringJoin/@input[[i]],{i,Length[input]}];
res=Table[Association[Table[input[[i,j]]->{amp[[i,j]]/.Get[lista[[i,j]]]/.Global`dd[n_,a_,b_]:>ToExpression["Global`dd"<>ToString[n]][a,b],(If[MemberQ[listaout[[i]],StringReplace[lista[[i,j]],"log.mat"->"out.mat"]],Get[StringReplace[lista[[i,j]],"log.mat"->"out.mat"]],{}])/.Global`G[a_]->a},{j,Length[input[[i]]]}](*/.replsym*)/.{Log[a_]->Log[a/Global`\[Mu]^2]}],{i,Length[input]}];
(*ReduceFlavorSymmetry[#,replsym][[1]]&/@res*)
ReduceFlavorSymmetry[#,replsym]&/@res
];



GetParameters[modeldirx_]:=Block[{varsx,counts},
varsx=Join[Import[modeldirx<>"/QGRAF/model_data/newsymbols","Words"],Import[modeldirx<>"/QGRAF/model_data/newfunctions","Words"]];
counts=Counts[StringReplace[#,"bar"->""]&/@varsx];
{Extract[Keys[counts],Position[Values[counts],1]],Extract[Keys[counts],Position[Values[counts],2]]}];


GetGaugeData[modeldir_]:=StringSplit/@ReadList[modeldir<>"/QGRAF/model_data/gaugedatanew",Record];

GetGaugeIndicesAndRanges[modeldir_]:=Block[{data},
data=GetGaugeData[modeldir];
Drop[#,2]&/@DeleteCases[data,a_/;Length[a]<4]];

GetGaugeIndices[modeldir_]:=Block[{res},
res=GetGaugeIndicesAndRanges[modeldir];If[Length[res]>0,res=Transpose[res][[1]]];
res]


ddeerule[indrx_]:=Module[{res},If[Length[indrx]>0,res=Join[ToExpression["Global`dd"<>#]->SparseArray[IdentityMatrix[ToExpression[#]]]&/@Transpose[indrx][[2]],
ToExpression["Global`ee"<>#]->SparseArray[LeviCivitaTensor[ToExpression[#]]]&/@Transpose[indrx][[2]]],res={}];
res];
ddeenogaugerule[indrx_]:=Module[{res},If[Length[indrx]>0,res=Join[ToExpression["Global`dd"<>#][___]->1&/@Transpose[indrx][[2]],
ToExpression["Global`ee"<>#][___]->1&/@Transpose[indrx][[2]]],res={}];
res];



RenameOneLoopWC[allpars_]:=Block[{},
MapThread[Rule,{ToExpression/@allpars,ToExpression[StringReplace[ToString[#],"alpha"->"WC"]]&/@allpars}]]



InitializeModel[modelname_]:=Block[{symmfile,hermiticityfile,redfile,SMrepfile,repgaugefile,realpars,complexpars,complexify,runogauge,dilist,groupdata,indranges,indi,mireplacegaugedata,mirunogauge,symblist,funclist,vars2one,listareplacesymmetry={},listahermiticity={},finalruleordered={},SMreplacement={},replacegaugedata={}},
symmfile=FileNameJoin[{modelname,"QGRAF","model_data","listareplacesymmetry"}];
If[FileExistsQ[symmfile],listareplacesymmetry=Get[symmfile];(*listareplacesymmetry=Global`listareplacesymmetry;*)];
hermiticityfile=FileNameJoin[{modelname,"QGRAF","model_data","listahermiticity"}];
If[FileExistsQ[hermiticityfile],Get[hermiticityfile];listahermiticity=Global`listahermiticity;];
redfile=FileNameJoin[{modelname,"QGRAF","model_data","redundancies.dat"}];
If[FileExistsQ[redfile],Get[redfile];finalruleordered=Global`finalruleordered;];
SMrepfile=FileNameJoin[{modelname,"QGRAF","model_data","SMreplacements.dat"}];
If[FileExistsQ[SMrepfile],Get[SMrepfile];SMreplacement=Global`SMreplacement;];
repgaugefile=FileNameJoin[{modelname,"QGRAF","model_data","replacegaugedata"}];
If[FileExistsQ[repgaugefile],Get[repgaugefile];replacegaugedata=Global`replacegaugedata;];
realpars=Union[GetParameters[modelname][[1]]];
complexpars=Union[GetParameters[modelname][[2]]];complexify=Join[Table[ToExpression[complexpars[[i]]]->ToExpression[complexpars[[i]]<>"bar"],{i,Length[complexpars]}],Table[ToExpression[complexpars[[i]]<>"bar"]->ToExpression[complexpars[[i]]],{i,Length[complexpars]}]];
dilist=GetDictionary[modelname,listareplacesymmetry];
groupdata=GetGaugeData[modelname];
indranges=GetGaugeIndicesAndRanges[modelname];
indi=GetGaugeIndices[modelname];mireplacegaugedata=Join[Table[Rule[(Global`replacegaugedata[[i,1]]),(Global`replacegaugedata[[i,2]])],{i,Length[Global`replacegaugedata]}],ddeerule[indranges]];mirunogauge=Join[Table[mireplacegaugedata[[i,1]][___]->1,{i,Length[mireplacegaugedata]}],ddeenogaugerule[indranges]];
symblist=Flatten[{Import[FileNameJoin[{modelname,"QGRAF","model_data","newsymbols"}]]}];
If[Length[symblist]>0,symblist=Rule[#,1]&/@ToExpression/@symblist];
funclist=Import[FileNameJoin[{modelname,"QGRAF","model_data","newfunctions"}]];
If[Length[funclist]>0,funclist=Rule[#,1]&/@(ToExpression/@(StringJoin[#,"[a__]"]&/@Flatten[{funclist}])),funclist={}];
(*If[Length[funclist]>0,funclist=Rule[#,1]&/@ToExpression/@Flatten[{funclist}],funclist={}];*)
vars2one=Join[symblist,funclist,ddeenogaugerule[indranges],{Global`ddF[___]->1,Global`invepsilonbar->1}];
{realpars,complexpars,complexify,dilist,groupdata,indranges,indi,mireplacegaugedata,mirunogauge,vars2one,{listahermiticity,finalruleordered,replacegaugedata,listareplacesymmetry}}]


CheckLinearDependence[modelname_]:=Block[{result},
MatchEFT[modelname];
result=DeleteCases[Global`EFTMatching[[2]]/.Global`Coeff[a___]->0,Rule[a_,0]];
If[Length[result]==0,Print["The operators in EFT ",modelname," are linearly independent."];,
Print["The operators in EFT ",modelname," are not linearly dependent."]; Print["Here are the relations between their coefficients: ",result]]]


MatchEFT[modelname_]:=Block[{EFTMatchingfile,EFTMatching},
EFTMatchingfile=FileNameJoin[{modelname,"QGRAF","model_data","EFTMatching.dat"}];
If[FileExistsQ[EFTMatchingfile],Get[EFTMatchingfile],Print["Model ",modelname," has not been matched yet, recreating the matching"];Global`EFTMatching=GenericMatchEFT[modelname];Save[EFTMatchingfile,Global`EFTMatching]];
Global`EFTMatching]


GenericMatchEFT[eft_]:=Block[{realpars,complexpars,complexify,dilist,groupdata,indranges,indi,mireplacegaugedata,mirunogauge,vars2one,hermiticitylist,finalruleordered,replacegaugedata,diE0,pars,system,sols0,sols,eamp0,eamp,newsys,newvars,ferms,kineticrule={},listareplacesymmetry},{realpars,complexpars,complexify,dilist,groupdata,indranges,indi,mireplacegaugedata,mirunogauge,vars2one,{hermiticitylist,finalruleordered,replacegaugedata,listareplacesymmetry}}=InitializeModel[eft];
ferms=Import[FileNameJoin[{eft,"QGRAF","model_data","listlightfermions"}],"CSV"][[1]];
diE0=dilist[[1,1]];
pars=Keys[diE0];
system={};
sols0={};
Do[
(*Print[pars[[cual]]];*)
eamp0=MyCoefficientList[PrepareAmplitude[dilist[[1,1]][pars[[cual]]],indranges,mirunogauge,mireplacegaugedata,False],Global`sSS];
eamp=Table[Flatten[{eamp0[[i]]}],{i,Length[eamp0]}];
If[Length[pars[[cual]]]==2,
AppendTo[kineticrule,pars[[cual]]->GetAlphasWithArguments[eamp[[(3-Boole[MemberQ[ferms,pars[[cual,1]]]])]],ToString/@Flatten[GetAlphas[eamp[[(3-Boole[MemberQ[ferms,pars[[cual,1]]]])]]]]]]];
kins=Table[GetKinematics[eamp[[i]],vars2one],{i,Length[eamp]}];
Do[(*Print["icual=",icual];*)
If[Length[eamp[[icual]]]>0,
AppendTo[system,EliminatParenthesisInAlphas/@Flatten[Table[Table[res=If[NumericQ[kins[[icual,j]]],eamp[[icual,i]],Coefficient[eamp[[icual,i]],kins[[icual,j]]]];
If[res===0, res,res-Global`Coeff[pars[[cual]],icual,i,kins[[icual,j]]]],{i,Length[eamp[[icual]]]}],{j,Length[kins[[icual]]]}]]];
AppendTo[sols0,SolveMinimalLinearSystem[system[[-1]],Union[Flatten[GetAlphas/@system[[-1]]]]][[1]]];],{icual,Length[eamp]}];
,{cual,Length[pars]}];
If[AlphasInSolQ[Flatten[sols0]],
Print["Not al WCs were matched, trying harder"];
newsys=Flatten[sols0]/.Rule[a_,b_]:>a-b;
newvars=Union[Flatten[GetAlphas/@newsys]];
sols0=SolveMinimalLinearSystem[newsys,newvars][[1]];
];
If[AlphasInSolQ[Flatten[sols0]],Print["Not all Wilson Coefficients can be computed, consider adding more amplitudes to the EFT"],Print["All WCs have been matched"]];
Global`kineticrule=kineticrule;
Save[FileNameJoin[{eft,"QGRAF","model_data","kineticrule"}],Global`kineticrule];
{system,Flatten[Union[sols0]]/.Rule[a_,b_]:>Rule[PutParenthesisInAlphas[a],b]}
]


GetSpecificAmplitudeNewNew[amp_,ppow_,in_,kix_]:=Block[{temp,res,mimanitobarescaldo},
If[amp==={{0}},temp=0,temp=amp[[ppow,in]]];
res=Coefficient[mimanitobarescaldo temp,mimanitobarescaldo kix];
res
]


GetSpecificAmplitudeNew[dic_,indrangesF_,mirunogaugeF_,mireplacegaugedataF_,repl_,parx_,ppow_,in_,kix_]:=Block[{temp,res,mimanitobarescaldo},
temp=(Flatten[{#}]&/@(MyCoefficientList[PrepareAmplitude[dic[parx],indrangesF,mirunogaugeF,mireplacegaugedataF,True]/.repl,Global`sSS]));
If[temp==={{0}}||Length[temp]<ppow,temp=0,temp=temp[[ppow,in]]];
res=Coefficient[mimanitobarescaldo temp,mimanitobarescaldo kix];
res
]


MiGetSpecificAmplitudeNew[dic_,indrangesF_,mirunogaugeF_,mireplacegaugedataF_,repl_,parx_,ppow_,in_,kix_]:=Block[{temp,res,mimanitobarescaldo},
temp=(Flatten[{#}]&/@(MyCoefficientList[PrepareAmplitude[dic[parx],indrangesF,mirunogaugeF,mireplacegaugedataF,True,kix]/.repl,Global`sSS]));
If[temp==={{0}}||Length[temp]<ppow,temp=0,temp=temp[[ppow,in]]];
res=Coefficient[mimanitobarescaldo temp,mimanitobarescaldo kix];
res
]


GetSpecificAmplitude[dic_,indrangesF_,mirunogaugeF_,mireplacegaugedataF_,repl_,parx_,ppow_,in_,kix_]:=Block[{temp,res},
temp=(Flatten[{#}]&/@(MyCoefficientList[PrepareAmplitude[dic[parx],indrangesF,mirunogaugeF,mireplacegaugedataF,True]/.repl,Global`sSS]));
(*Print[NumericQ[kix]];*)
(*If[temp\[Equal]{{0}},res=0,res=If[NumericQ[kix],temp[[ppow,in]],Coefficient[temp[[ppow,in]],kix]]];*)
If[
temp=={{0}};
,
res=0;
,
If[NumericQ[kix]
,
res=temp[[ppow,in]];
,
res=Coefficient[temp[[ppow,in]],kix];
]];
res
]


GetKinematics[amplitude_,vars2onelist_]:=Block[{amplist,varlistrule},
amplist=DeleteCases[Flatten[{Expand[amplitude]/.Plus->List}/.vars2onelist]/.Log[_]->1,0];
varlistrule=Rule[#,1]&/@Variables[amplist];
Union[amplist/(amplist/.varlistrule)]
]


InitializeModelOLD[modelname_]:=Block[{realpars,complexpars,complexify,runogauge,diElist,diFlist,groupdata,indranges,indi,mireplacegaugedata,mirunogauge},
Get[$matchmakerpath<>"core/listareplacesymmetry"];
Get[$matchmakerpath<>"core/kinematicdir"];
Get[$matchmakerpath<>"core/totalredundancies.dat"];
Get[$matchmakerpath<>"core/SMreplacements.dat"];
realpars=Union[Join[GetParameters[modelname][[1]],Union[Flatten[Transpose[Table[GetParameters[$matchmakerpath<>"models/"<>$effdiranddimlist[[i,1]]],{i,Length[$effdiranddimlist]}]][[1]]]]]];complexpars=Union[Join[GetParameters[modelname][[2]],Union[Flatten[Transpose[Table[GetParameters[$matchmakerpath<>"models/"<>$effdiranddimlist[[i,1]]],{i,Length[$effdiranddimlist]}]][[2]]]]]];complexify=Join[Table[ToExpression[complexpars[[i]]]->ToExpression[complexpars[[i]]<>"bar"],{i,Length[complexpars]}],Table[ToExpression[complexpars[[i]]<>"bar"]->ToExpression[complexpars[[i]]],{i,Length[complexpars]}]];Get[modelname<>"/QGRAF/model_data/replacegaugedata"];diElist=Table[GetDictionary[$matchmakerpath<>"models/"<>$effdiranddimlist[[i,1]],Global`listareplacesymmetry],{i,Length[$effdiranddimlist]}];diFlist=GetDictionary[modelname];groupdata=GetGaugeData[modelname];indranges=GetGaugeIndicesAndRanges[modelname];indi=GetGaugeIndices[modelname];mireplacegaugedata=Join[Table[Rule[(Global`replacegaugedata[[i,1]]),(Global`replacegaugedata[[i,2]])],{i,Length[Global`replacegaugedata]}],ddeerule[indranges]];mirunogauge=Join[Table[mireplacegaugedata[[i,1]][___]->1,{i,Length[mireplacegaugedata]}],ddeenogaugerule[indranges]];
{realpars,complexpars,complexify,diElist,diFlist,groupdata,indranges,indi,mireplacegaugedata,mirunogauge}]


GetAlphas[exp_]:=Union[ToExpression/@DeleteCases[StringSplit[StringReplace[ToString[exp],{"["->" ","("->" ","]"->" ",")"->" ","-"->" "}]],a_/;StringFreeQ[ToString[a],"alpha"]]];

GetAlphasGeneral[exp_,listofalphas_:"alpha"]:=Union[ToExpression/@DeleteCases[StringSplit[StringReplace[ToString[exp],{"["->" ","("->" ","]"->" ",")"->" ","-"->" "}]],a_/;StringFreeQ[ToString[a],listofalphas]]];

GetFunctionsFromRules[rulelist_]:=Module[{res={}},If[Length[rulelist]>0,res=ToString/@Union[Transpose[GetFunctionNameAndArguments/@DeleteCases[Flatten[(rulelist/.{-1->1}/.Rule->List)],0]][[1]]]];
res];

GetAlphasWithArguments[exp_,listofalphas_]:=Union[ToExpression/@DeleteCases[StringSplit[StringReplace[ToString[exp],{"("->" ",", "->",",")"->" ","-"->" ","*"->" "}]],a_/;StringFreeQ[ToString[a],listofalphas]]];

GetAlphasWithArgumentsFromDict[di_,symlist_]:=Block[{vals,listofalphas},
vals=Values[di];
If[Length[symlist]>0,listofalphas=ToString/@GetFunctionsFromRules[symlist],listofalphas="alpha"];
Union[Flatten[Table[GetAlphasWithArguments[vals[[i]][[1]]//.vals[[i]][[2]],listofalphas],{i,Length[vals]}]]]
]


GiveAllChanges[exp_,sy_]:=Block[{yea,re,allre,allrefinal},
yea=sy[[#]]&/@Flatten[Table[Tuples[Range[Length[sy]],n],{n,6}],1];
(*Print[yea];*)
allre={};
Do[
re=exp;
Do[re=re/.yea[[j,i]];,{i,Length[yea[[j]]]}];
AppendTo[allre,exp->re];
,{j,Length[yea]}];
Union[allre]
];

GetRelevantRules[listofalphas_,listofsymmetries_]:=Block[{sol,redrules,changes,result,listofalphasfromsymmetries},
sol={};
listofalphasfromsymmetries=ToString/@GetFunctionsFromRules[listofsymmetries];
Do[
redrules=Select[listofsymmetries,MemberQ[GetAlphasGeneral[listofalphas[[i]],listofalphasfromsymmetries],GetAlphasGeneral[#[[1]],listofalphasfromsymmetries][[1]]]&];
changes=GiveAllChanges[listofalphas[[i]],redrules];
(*Print["i=",i,"  ",listofalphas[[i]],"  ",redrules,"  ",changes];*)
result={};
If[Length[changes]>0,result=Transpose[changes/.Rule->List][[2]]/.{-1->1}];
AppendTo[sol,{listofalphas[[i]],changes,result}];
,{i,Length[listofalphas]}];
sol];

ReduceFlavorSymmetry[diEFT_,listofsymmetries_]:=Block[{listofalphas,indlist={},redlist={},rulesi},
listofalphas=GetAlphasWithArgumentsFromDict[diEFT,listofsymmetries];
If[Length[listofalphas]>0,AppendTo[indlist,listofalphas[[1]]]];
rulesi=GetRelevantRules[listofalphas,listofsymmetries];
Do[
If[Or@@(MemberQ[indlist,#]&/@(rulesi[[i,3]])),AppendTo[redlist,listofalphas[[i]]->(listofalphas[[i]]/.rulesi[[i,2]])],AppendTo[indlist,listofalphas[[i]]]],{i,2,Length[listofalphas]}];
{indlist,redlist};
{diEFT/.redlist,redlist}];


(* SortByType takes a list of rules of the form alphaXxxx \[Rule] ... and a list of "types of operators" of the form {"S","O", ...}, where these correspond to the possible values of X in the order we want the listrules to be returned *)
SortByType[listrules_,typeordering_]:=Block[{replace,pad},
pad=Length[IntegerDigits[Length[typeordering]]];
replace=Join[{"["->"0"},MapThread[Rule,{typeordering,StringPadLeft[#,pad,"0"]&/@ToString/@Range[Length[typeordering]]}]];
SortBy[listrules,StringReplace[ToString[#[[1]]],replace]&]
]


(* EliminateRepeated[sollist] takes as an input a dimension 1 list of the form {alphaxxx \[Rule] xxx,...},
checks if there are repeated entries, including non-trivial index swapping, and eliminates the repeated
ones

positionDuplicates[list] gives the position of repeated entries in a list
*) 

positionDuplicates[list_]:=GatherBy[Range@Length[list],list[[#]]&];

EliminateRepeated[sollist_,replacementlist_:{}]:=Module[{rep,listtodrop,differ},
listtodrop={};
rep=DeleteCases[positionDuplicates[Flatten[GetAlphas/@(sollist/.Rule[a_,b_]:>a)]],{_}];
Do[Do[
differ=Simplify[(sollist[[rep[[i,1]]]][[2]])-(ToExpression[StringReplace[ToString[sollist[[rep[[i,1]]]][[1]]],"_"->""]]/.sollist[[rep[[i,j]]]](*/.replacementlist*))];If[DummyZeroQ[differ,replacementlist]===0,AppendTo[listtodrop,{rep[[i,j]]}],Print["Huston we have a problem ",sollist[[rep[[i,1]]]][[1]],"eo",{differ,replacementlist,DummyZeroQ[differ,replacementlist]},"oe"]]
,{j,2,Length[rep[[i]]]}];
,{i,Length[rep]}];
Delete[sollist,listtodrop]
]

EliminateRepeatedOld[sollist_,replacementlist_:{}]:=Module[{rep,listtodrop,differ},
listtodrop={};
rep=DeleteCases[positionDuplicates[Flatten[GetAlphas/@(sollist/.Rule[a_,b_]:>a)]],{_}];
Do[Do[
differ=Simplify[(sollist[[rep[[i,1]]]][[2]])-(ToExpression[StringReplace[ToString[sollist[[rep[[i,1]]]][[1]]],"_"->""]]/.sollist[[rep[[i,j]]]]/.replacementlist)];If[CheckIsZero[differ],AppendTo[listtodrop,{rep[[i,j]]}](*,Print["Huston we have a problem ",sollist[[rep[[i,1]]]][[1]],"eo",{differ},"oe"]*)]
,{j,2,Length[rep[[i]]]}];
,{i,Length[rep]}];
Delete[sollist,listtodrop]
]


(* CheckIsZero[exp] takes exp, sums over internal indices up to 3 and checks if the result is 0
this is useful to check if two expressions are the same but they don't seem to be because of a
different naming in dummy indices *)
CheckIsZero[exp_]:=Block[{sexp,ind,check,max,res},
max=3;
res=False;
sexp=Splitter[exp];
check=0;
Do[
ind=ToExpression[GetIndices[sexp[[j]]][[1]]];
If[Length[ind]>0,
check=check+Apply[Sum[sexp[[j]],##]&,Transpose[Join[{ind},{Table[max,{i,Length[ind]}]}]]];,
check=check+sexp[[j]]]
,{j,Length[sexp]}];
If[check==0,res=True];
res
]


(*
GenerateNumericalSymmetries[symlist_,maxx_] generates a list to 
reduce the WC appearing in the symmetry list symlist with 
numerical values of the indices up to maxx to a minimal set
*)
GenerateNumericalSymmetries[symlist_,maxx_]:=Block[{expr,ind,li,res={}},
Do[
expr=RemoveUnderscore[symlist[[iiGNS,1]]];
ind=ToExpression/@GetIndices[expr][[2]];
li=Flatten[Apply[Table[expr,##]&,Transpose[Join[{ind},{Table[maxx,{i,Length[ind]}]}]]]];
Do[If[FreeQ[Values[res],li[[iii]]],AppendTo[res,Rule[li[[iii]],li[[iii]]/.symlist]]],{iii,Length[li]}];
,{iiGNS,Length[symlist]}];
res/.Rule[a_,-a_]:>Rule[a,0]];


(*
GenerateSymmetries[exp,replsym] takes an expression exp and a list of replacement rules replsym
and generates a list of replacement rules to reduce the functions appearing in exp to a minimal set
*)
GenerateSymmetries[exp_,replsym_:{}]:=Block[{funclist,res={}},
funclist=GetAlphasWithArguments[exp,GetFunctionsFromRules[replsym]];
Do[
If[FreeQ[Values[res],funclist[[iiGS]]],AppendTo[res,Rule[funclist[[iiGS]],funclist[[iiGS]]/.replsym]]]
,{iiGS,Length[funclist]}];
res
]


(* DummyZeroQ[exp] takes exp, sums over internal indices up to 3 and checks if the result is 0, if it's zero it returns 0 otherwise it retuns exp. This is useful to check if two expressions are the same but they don't seem to be because of a different naming in dummy indices *)
DummyZeroQ[exp_,replsym_:{}]:=Block[{sexp,ind,check,max=3,res,symrules,symrulesanalytic},
If[TreatDummyFlavorGeneral[exp]===0,res=0,
(*Print["notzero=",exp];*)
symrules=GenerateNumericalSymmetries[replsym,max];
res=exp;
(*Print["replsym=",replsym];*)
symrulesanalytic=GenerateSymmetries[exp,replsym];
sexp=Splitter[exp];
check=0;
Do[
ind=ToExpression[GetIndices[sexp[[jjj]]][[1]]];
If[Length[ind]>0,
check=check+Apply[Sum[sexp[[jjj]],##]&,Transpose[Join[{ind},{Table[max,{iii,Length[ind]}]}]]];,
check=check+sexp[[jjj]]]
,{jjj,Length[sexp]}];
(*Print["check/.symrules=",check/.symrules];
Print["symrulesanalytic=",symrulesanalytic];*)
check=check/.symrules/.symrulesanalytic;
If[check==0,res=0];];
res
]

DummyZeroQold[exp_]:=Block[{sexp,ind,check,max=3,res},
res=exp;
sexp=Splitter[exp];
check=0;
Do[
ind=ToExpression[GetIndices[sexp[[j]]][[1]]];
If[Length[ind]>0,
check=check+Apply[Sum[sexp[[j]],##]&,Transpose[Join[{ind},{Table[max,{i,Length[ind]}]}]]];,
check=check+sexp[[j]]]
,{j,Length[sexp]}];
If[check==0,res=0];
res
]


EliminatParenthesisInAlphas[exp_]:=Block[{exp2,allist},
allist=GetAlphas[exp];
exp2=exp;
Do[
exp2=exp2/.ToExpression[allist[[i]]][a_,b_]:>ToExpression[StringReplace[ToString[allist[[i]][a,b]],{"["->"","]"->"",","->""," "->""}]];
exp2=exp2/.ToExpression[allist[[i]]][a_,b_,c_,d_]:>ToExpression[StringReplace[ToString[allist[[i]][a,b,c,d]],{"["->"","]"->"",","->""," "->""}]];
,{i,Length[allist]}];
exp2
];



PutParenthesisInAlphas[exp_]:=Block[{exp0,wherefs,res},
If[StringQ[exp],exp0=exp,exp0=ToString[exp]];
wherefs=StringPosition[exp0,"fl"];
res=exp0;
If[Length[wherefs]>0,
res=StringInsert[res,"[",wherefs[[1,1]]];
res=StringInsert[res,",",wherefs[[2,1]]+1];
If[Length[wherefs]==4,
res=StringInsert[res,",",wherefs[[3,1]]+2];
res=StringInsert[res,",",wherefs[[4,1]]+3];
];
res=res<>"]"];
ToExpression[StringReplace[res,{"fl99"->"fl99_","fl98"->"fl98_","fl97"->"fl97_","fl96"->"fl96_","fl95"->"fl95_","fl94"->"fl94_","fl93"->"fl93_","fl92"->"fl92_","fl91"->"fl91_"}]]
];


(* 
AddToListOfRules[listofrules,extralist] takes a list of rules listofrules={a\[Rule]a1,b\[Rule]b1, ...} and a list extrlist={a2,b2, ...} and returns
{a\[Rule]a1+a2,b\[Rule]b1+b2, ...}
*)
AddToListOfRules[listofrules_,extralist_]:=Table[listofrules[[i,1]]->listofrules[[i,2]]+extralist[[i]],{i,Length[listofrules]}]


(* 
EliminateSelfFromRule[rulex] takes a rule of the form alXYY\[Rule]alphaXYY+... and returns the RHS of the rule with alphaXYY removed 
*)
EliminateSelfFromRule[rulex_]:=rulex[[2]]/.{ToExpression[StringInsert[ToString[rulex[[1]]],"pha",3]]->0}


(* Splitter *)
Splitter[exp_]:=Block[{res},
res=DeleteCases[Level[Expand[exp]+"REMOVETHIS",1],"REMOVETHIS"];
res];



(* GetFunctionNameAndArguments[f[a,b,c,...] returns the following list {f,{a,b,c,...}}*) 

GetFunctionNameAndArguments[ff_[x__]]:={ff,x//List};






(* GetTensorsAndIndicesAndOrdering[expi] returns a list with three entries 
{{list of tensor names},{list of pairs of repeated indices},{permutation needed to put the external indices in alphabetical order}}*)
(* IMPORTANT NOTES: For this function to work it needs expi to be a product of tensors with indices (no sum, no extra non-tensorial structures)
Also the permutation given by the third entry of the output is the one needed in Transpose[tensor,permutation] to put the tensor with the external
indices in alphabetical order (so that for instance Transpose[T[k,j,i],permutation]=T[i,j,k])
*)

powerProductForm[expr_]:=With[{expanded=Inactivate[expr/.Power[u_,n_Integer?Positive]:>Inactive[Times]@@ConstantArray[u,n],Times]/.prod:Inactive[Times][__]:>Flatten[prod]},Activate@HoldForm[expanded]];
powerProductFormToList[expr_]:=With[{expanded=Inactivate[expr/.Power[u_,n_Integer?Positive]:>Inactive[Times]@@ConstantArray[u,n],Times]/.prod:Inactive[Times][__]:>Flatten[prod]},ReleaseHold[(Activate@HoldForm[expanded])/.Times->List]];

GetTensorsAndIndicesAndOrdering[expi_]:=Module[{expii,inter,Tnames,indexlist,internals,externals},
(*If[ToString[Head[expi]]=="Times",expii=(expi/.head_[arg__]:>List[arg]),expii=Flatten[List[expi]]];
Print["expiinGetTensor1=",expii];*)
expii=Flatten[{powerProductFormToList[expi]}];
(*Print["expiinGetTensor2=",expii];*)
inter=Transpose[DeleteCases[GetFunctionNameAndArguments/@expii,GetFunctionNameAndArguments[_]]];
Tnames=inter[[1]];
indexlist=Flatten[inter[[2]]];
externals=Select[GatherBy[Range@Length[indexlist],indexlist[[#]]&],Length[#]==1&];
internals=Select[GatherBy[Range@Length[indexlist],indexlist[[#]]&],Length[#]>1&];
Join[Tnames,{internals},{InversePermutation[Ordering[Part[indexlist,#]&/@Flatten[externals]]]}]
]


(* TensorMultiply[A,B,C, ...,pairs,rearr] returns with tensor product of A B C ... with the indices in
pairs contracted and the external indices ordered according to the permutation rearr. When rearr is the
permutation computed in GetTensorsAndIndicesAndOrdering the external indices are ordered according to
alphabetical order *)
TensorMultiply[A__,pairs_,rearr_]:=Module[{temp0,res},
temp0=Activate@TensorContract[Inactive[TensorProduct][A],pairs];
If[Length[rearr]>0,res=Transpose[temp0,rearr],res=temp0];
res]
(*TensorMultiply[A__,pairs_,rearr_]:=Transpose[Activate@TensorContract[Inactive[TensorProduct][A],pairs],rearr];*)
(* GetRangeFromIndex[index,indrx] returns the dimension of the corresponding index *)
GetRangeFromIndex[index_,indrx_]:=indrx[[Position[indrx,{ToString[IndexType[index]],_}][[1,1]],2]];



miSumExpandIndices[exp0_,indr0_,runogaugex_,replacelistgauge_]:=Module[{expi0(*,ru0*),ru1,exp(*,resp*)},
expi0=(exp0/.runogaugex);
ru1={expi0->1};
exp=(exp0/.ru1);
(*expi0=TreatDummyFlavorGeneral[expi0];*)If[ToString[exp]!="1",expi0=expi0(TensorMultiply@@(GetTensorsAndIndicesAndOrdering[exp]/.replacelistgauge));];Remove[ru1];
expi0
]


(* IndexType *)

IndexType[in_]:=Block[{res,tostring,tostringnonumbers},
tostring=StringPartition[ToString[in],1];
tostringnonumbers=DeleteCases[tostring,a_/;DigitQ[a]];
ToExpression[StringDelete[StringJoin[tostringnonumbers],"minus"]]
];



SumExpandIndicesEfficient[exp_,indr_,runogaugex_,replacelistgauge_]:=Module[{expi,expi0,iii,res,ru0,ru1},
Off[Part::partd];
expi=Splitter[exp/.Global`samb[a___]->0];
If[Length[expi]>100000,
With[{expii=expi},
DistributeDefinitions[SumExpandIndices];
res=ParallelSum[
SumExpandIndices[expii[[iii]],indr,runogaugex],{iii,Length[expii]}]],
res=Sum[
If[Mod[iii,20000000]==0,Print[DateString[],"  ",iii," Maxmemory= ",MaxMemoryUsed[]/1024.^2,"  memorynow=",MemoryInUse[]/1024.^2]];
miSumExpandIndices[expi[[iii]],indr,runogaugex,replacelistgauge]
(*miSumExpandIndices[TreatDeltaEps[expi[[iii]],indr],indr,runogaugex,replacelistgauge]*),{iii,Length[expi]}]];
On[Part::partd];
(*Print["res=",res];*)
(*Print[DateString[],"  Ending SumExpand"];*)
If[ListQ[res],
Union[Simplify[Flatten[res]]],res]
];


CompareTwoMatches[list1_,list2_]:=Module[{ke1,ke2,res},
ke1=ToExpression[StringReplace[ToString[list1/.Rule[a_,b_]->a],"_"->""]];
ke2=ToExpression[StringReplace[ToString[list2/.Rule[a_,b_]->a],"_"->""]];
If[Sort[ke1]==Sort[ke2],
res=Union[CheckIsZero/@Simplify[((ke1/.list1)-(ke1/.list2))]],
res={False}];
And@@res
]


(*RemoveUnderscore[exp_]:=Block[{ind},
ind=GetIndices[exp];
ToExpression[StringReplace[ToString[InputForm[exp]],Table[ind[[2]][[i]]\[Rule]StringReplace[ind[[2]][[i]],"_"\[Rule]""],{i,Length[ind[[2]]]}]]]];

MultiplyLeftRight[term_,ind_,mul_]:=Block[{multi,dummy},
dummy=Global`MIF1;
If[mul[[2]]\[Equal]1,multi=mul[[1]][ind,dummy],multi=mul[[1]][dummy,ind]];
((term/.{ToExpression[ind]\[Rule]dummy})multi)];

wc2fieldsdic[modelnameE_]:=Association[((StringSplit[#,"  "]&/@StringSplit[Import[FileNameJoin[{modelnameE,"QGRAF","model_data","wc2fields.txt"}]],"\n"])/.{a_,b_}:>{Rule[ToExpression[a],ToExpression[StringSplit[b," "]]]})];

(* GetKineticWCdic returns a dictionary with the fields present in the EFT as keys 
and a list with {K,in,HasIndices}, where K in the WC corresponding to the kinetic term, in is the order it appears in the kinetic term (1 for real or for complex bar, 2 for complex without conjugation) and HasIndices is True if the field has flavour indices and False if it doesnt *)

GetKineticWCdic[modelnameE_]:=Block[{hasin,isreal,li,lile,al,res,kineticrulex},
Get[FileNameJoin[{modelnameE,"QGRAF","model_data","kineticrule"}]];
kineticrulex=Global`kineticrule;
res=Table[
hasin=If[Length[GetIndices[kineticrulex[[cualx,2]][[1]]][[2]]]>0,True,False];
isreal=If[Length[Union[kineticrulex[[cualx,1]]]]\[Equal]1,True,False];
li=ToExpression/@kineticrulex[[cualx,1]];
If[isreal,li=Union[li]];
lile=Length[li];
al=GetAlphas[kineticrulex[[cualx,2,1]]][[1]];
Transpose[{li,Table[al,lile],Range[lile],Table[hasin,lile]}]
,{cualx,Length[kineticrulex]}];
res=Flatten[res,1];
Association[Table[res[[ii,1]]\[Rule]Drop[res[[ii]],1],{ii,Length[res]}]]];

CanonicalNormalization[modelnameE_,wc_]:=Block[{nwc,in,kidi,listKs,wc2fieldsdicx,particles,particleswithindices,particleswithoutindices,repl,res},
kidi=GetKineticWCdic[modelnameE];
listKs=Union[Transpose[Values[kidi]][[1]]];
wc2fieldsdicx=wc2fieldsdic[modelnameE];
nwc=RemoveUnderscore[wc];
If[MemberQ[listKs,GetAlphas[nwc][[1]]],
res=2nwc,
in=ToExpression/@GetIndices[nwc][[2]];
particles=wc2fieldsdicx[GetAlphas[nwc][[1]]];
particleswithindices=DeleteCases[wc2fieldsdicx[GetAlphas[nwc][[1]]](Boole/@(kidi[#][[3]]&/@wc2fieldsdicx[GetAlphas[nwc][[1]]])),0];
particleswithoutindices=DeleteCases[wc2fieldsdicx[GetAlphas[nwc][[1]]](1-Boole/@(kidi[#][[3]]&/@wc2fieldsdicx[GetAlphas[nwc][[1]]])),0];
repl=Take[#,2]&/@(kidi/@particleswithindices);
(*Print["wc=",wc,"  nwc=",nwc];
Print["parin=",particleswithindices," parnoin=",particleswithoutindices];
Print["in=",in," repl=",repl];*)
res=Sum[
MultiplyLeftRight[nwc,in[[ii]],repl[[ii]]]
,{ii,Length[repl]}];
repl=Take[#,1]&/@(kidi/@particleswithoutindices);
(*Print["particles=",particles];
Print["particlesind=",particleswithindices];
Print["particlesnoind=",particleswithoutindices];*)
res=res+Sum[nwc repl[[ii]][[1]],{ii,Length[repl]}];
(*ToExpression["delta"<>ToString[wc]]\[Rule]-1/2res*)
];
wc\[Rule]-1/2res
];

GenerateNormalizationList[modelnameE_,complexifyx_]:=Block[{CanonicalNormalizationfile,listaalphas,listanor,listanorbar,listanorfinal},
CanonicalNormalizationfile=FileNameJoin[{modelnameE,"QGRAF","model_data","canonicalnormalization.dat"}];
If[FileExistsQ[CanonicalNormalizationfile],Print["Getting information on canonical normalization for model ",modelnameE];Get[CanonicalNormalizationfile];,
Print["Canonical normalization for model ",modelnameE," has not been computed yet, recreating it"];
Get[FileNameJoin[{modelnameE,"QGRAF","model_data","EFTMatching.dat"}]];
listaalphas=ToExpression/@Select[ToString/@(Union[Global`EFTMatching[[2]]/.Rule[a_,b_]\[RuleDelayed]a]),!StringContainsQ[#,"bar"]&];
listanor=Table[CanonicalNormalization[modelnameE,listaalphas[[i]]],{i,Length[listaalphas]}];
listanorbar=listanor/.complexifyx;
listanorfinal=Union[Join[listanor,listanorbar]]/.Rule[a_,b_]\[RuleDelayed]Rule[ToExpression["delta"<>ToString[a]],b];
Global`alldeltalist0=listanorfinal;
Save[CanonicalNormalizationfile,Global`alldeltalist0]];
Global`alldeltalist0
];

GenerateClassicalDimension[modelnameE_]:=Block[{wc2fieldsdicx,ClassicalDimensionfile,classicalandims},
wc2fieldsdicx=wc2fieldsdic[modelnameE];
ClassicalDimensionfile=FileNameJoin[{modelnameE,"QGRAF","model_data","classicaldimension.dat"}];
If[FileExistsQ[ClassicalDimensionfile],Print["Getting information on the classical anomalous dimension of the couplings for model ",modelnameE];Get[ClassicalDimensionfile],
Print["Classical anomalous dimensions for model ",modelnameE," have not been computed yet, recreating them"];
classicalandims=Join[(Rule@@@Import[FileNameJoin[{modelnameE,"QGRAF","model_data","gaugecouplingsandbosons.dat"}]])/.Rule[a_,b_]\[RuleDelayed]Rule[ToExpression[a],1],Normal[wc2fieldsdicx]/.{Rule[a_,b_]\[RuleDelayed]Rule[a,Length[b]-2]}];
Global`classicalandims=classicalandims;
Save[ClassicalDimensionfile,Global`classicalandims]];
]

*)


PutUnderscore[exp_]:=Block[{ind},
ind=ToString/@GetIndices[exp][[2]];
ToExpression[StringReplace[ToString[InputForm[exp]],Table[ind[[i]]->ind[[i]]<>"_",{i,Length[ind]}]]]];


RemoveUnderscore[exp_]:=Block[{ind},
ind=GetIndices[exp];
ToExpression[StringReplace[ToString[InputForm[exp]],Table[ind[[2]][[i]]->StringReplace[ind[[2]][[i]],"_"->""],{i,Length[ind[[2]]]}]]]];

MultiplyLeftRight[term_,ind_,mul_]:=Block[{multi,dummy},
dummy=Global`MIF1;
If[mul[[2]]==1,multi=mul[[1]][ind,dummy],multi=mul[[1]][dummy,ind]];
((term/.{ToExpression[ind]->dummy})multi)];

wc2fieldsdic[modelnameE_]:=Association[((StringSplit[#,"  "]&/@StringSplit[Import[FileNameJoin[{modelnameE,"QGRAF","model_data","wc2fields.txt"}]],"\n"])/.{a_,b_}:>{Rule[ToExpression[a],GatherBy[ToExpression[StringSplit[b," "]],NumberQ]]})];

(* GetKineticWCdic returns a dictionary with the fields present in the EFT as keys 
and a list with {K,in,HasIndices}, where K in the WC corresponding to the kinetic term, in is the order it appears in the kinetic term (1 for real or for complex bar, 2 for complex without conjugation) and HasIndices is True if the field has flavour indices and False if it doesnt *)

GetKineticWCdic[modelnameE_]:=Block[{hasin,isreal,li,lile,al,res,kineticrulex},
Get[FileNameJoin[{modelnameE,"QGRAF","model_data","kineticrule"}]];
kineticrulex=Global`kineticrule;
res=Table[
hasin=If[Length[GetIndices[kineticrulex[[cualx,2]][[1]]][[2]]]>0,True,False];
isreal=If[Length[Union[kineticrulex[[cualx,1]]]]==1,True,False];
li=ToExpression/@kineticrulex[[cualx,1]];
If[isreal,li=Union[li]];
lile=Length[li];
al=GetAlphas[kineticrulex[[cualx,2,1]]][[1]];
Transpose[{li,Table[al,lile],Range[lile],Table[hasin,lile]}]
,{cualx,Length[kineticrulex]}];
res=Flatten[res,1];
Association[Table[res[[ii,1]]->Drop[res[[ii]],1],{ii,Length[res]}]]];


CanonicalNormalization[modelnameE_,wc_]:=Block[{nwc,in,kidi,listKs,wc2fieldsdicx,particles,indexorder,particleswithindices,particleswithoutindices,repl,correctrepl,res},
kidi=GetKineticWCdic[modelnameE];
listKs=Union[Transpose[Values[kidi]][[1]]];
wc2fieldsdicx=wc2fieldsdic[modelnameE];
nwc=RemoveUnderscore[wc];
If[MemberQ[listKs,GetAlphas[nwc][[1]]],
res=2nwc,
in=ToExpression/@GetIndices[nwc][[2]];
particles=wc2fieldsdicx[GetAlphas[nwc][[1]]][[1]];
If[Length[wc2fieldsdicx[GetAlphas[nwc][[1]]]]==1,indexorder={},indexorder=wc2fieldsdicx[GetAlphas[nwc][[1]]][[2]]];
particleswithindices=DeleteCases[wc2fieldsdicx[GetAlphas[nwc][[1]]][[1]](Boole/@(kidi[#][[3]]&/@(wc2fieldsdicx[GetAlphas[nwc][[1]]][[1]]))),0];
particleswithoutindices=DeleteCases[wc2fieldsdicx[GetAlphas[nwc][[1]]][[1]](1-Boole/@(kidi[#][[3]]&/@wc2fieldsdicx[GetAlphas[nwc][[1]]][[1]])),0];
repl=Take[#,2]&/@(kidi/@particleswithindices);
correctrepl=Permute[repl,indexorder];
res=Sum[
MultiplyLeftRight[nwc,in[[ii]],correctrepl[[ii]]]
,{ii,Length[correctrepl]}];
repl=Take[#,1]&/@(kidi/@particleswithoutindices);
(*Print["particles=",particles];
Print["particlesind=",particleswithindices];
Print["particlesnoind=",particleswithoutindices];*)
res=res+Sum[nwc repl[[ii]][[1]],{ii,Length[repl]}];
(*ToExpression["delta"<>ToString[wc]]\[Rule]-1/2res*)
];
wc->-1/2res
];

GenerateNormalizationList[modelnameE_,complexifyx_]:=Block[{CanonicalNormalizationfile,listaalphas,listanor,listanorbar,listanorfinal},
CanonicalNormalizationfile=FileNameJoin[{modelnameE,"QGRAF","model_data","canonicalnormalization.dat"}];
If[FileExistsQ[CanonicalNormalizationfile],Print["Getting information on canonical normalization for model ",modelnameE];Get[CanonicalNormalizationfile];,
Print["Canonical normalization for model ",modelnameE," has not been computed yet, recreating it"];
Get[FileNameJoin[{modelnameE,"QGRAF","model_data","EFTMatching.dat"}]];
listaalphas=ToExpression/@Select[ToString/@(Union[Global`EFTMatching[[2]]/.Rule[a_,b_]:>a]),!StringContainsQ[#,"bar"]&];
listanor=Table[CanonicalNormalization[modelnameE,listaalphas[[i]]],{i,Length[listaalphas]}];
listanorbar=listanor/.complexifyx;
listanorfinal=Union[Join[listanor,listanorbar]]/.Rule[a_,b_]:>Rule[ToExpression["delta"<>ToString[a]],b];
Global`alldeltalist0=listanorfinal;
Save[CanonicalNormalizationfile,Global`alldeltalist0]];
Global`alldeltalist0
];

GenerateClassicalDimension[modelnameE_]:=Block[{wc2fieldsdicx,ClassicalDimensionfile,classicalandims},
wc2fieldsdicx=wc2fieldsdic[modelnameE];
ClassicalDimensionfile=FileNameJoin[{modelnameE,"QGRAF","model_data","classicaldimension.dat"}];
If[FileExistsQ[ClassicalDimensionfile],Print["Getting information on the classical anomalous dimension of the couplings for model ",modelnameE];Get[ClassicalDimensionfile],
Print["Classical anomalous dimensions for model ",modelnameE," have not been computed yet, recreating them"];
classicalandims=Join[(Rule@@@Import[FileNameJoin[{modelnameE,"QGRAF","model_data","gaugecouplingsandbosons.dat"}]])/.Rule[a_,b_]:>Rule[ToExpression[a],1],Normal[wc2fieldsdicx]/.{Rule[a_,b_]:>Rule[a,Length[b[[1]]]-2]}];
Global`classicalandims=classicalandims;
Save[ClassicalDimensionfile,Global`classicalandims]];
]




(* Gets the maximum sSS power of the EFT amplitude *)
ComputesSSPower[eftamplitude_]:=Exponent[eftamplitude[[1]]//.eftamplitude[[2]],Global`sSS];

(* GetsSSOrder[exp,x] gets the coefficient of the term of order sSS^x of exp. For x\[LessEqual]0 we give the result of operators of dimension four or less *)
GetsSSOrder[exp_,x_]:=If[x<=0,exp/.Global`sSS->0,Coefficient[exp,Global`sSS^x]];




RecursiveRuleList[t_List]:=Block[{a,b},t//.Rule[a_,b_]:>Rule[a,b/.t]]


PrepareAmplitude[amp_,indranges_,runogauge_,mireplacegaugedata_,UVPoles_,kix_:1]:=Block[{res0,res,reamp2,reamp2kin},
reamp2=RecursiveRuleList[amp[[2]]];
If[kix===1,reamp2kin=reamp2,reamp2kin=reamp2/.Rule[a_,b_]:>Rule[a,Coefficient[(b/.Dot[aa_,Power[bb_,n_]]->Power[Dot[aa,bb],n]),kix]kix]];
res0=Normal[SumExpandIndicesEfficient[amp[[1]],indranges,runogauge,mireplacegaugedata]]//.reamp2kin/.Global`DEN[a_,b_]->1/(a^2-b^2)/.Global`FourPi->4Pi/.Dot[a_,Power[b_,n_]]->Power[Dot[a,b],n]/.Global`ddF[a_,b_,c_]->KroneckerDelta[b,c];
(*
If[UVPoles,
res=Coefficient[res0,Global`invepsilonbar],
res=res0/.{Global`invepsilonbar\[Rule]0}
];
we now give the full answer, pole and finite*)
res0
]


MyCoefficientList[mat_,var_]:=Block[{maxpow,res},
maxpow=Max[Exponent[mat,var]];
res={mat/.var->0};
If[maxpow>0,res=Join[res,Table[Coefficient[mat,var^iix],{iix,maxpow}]]];
res
]


AlphasInSolQ[sols_]:=Length[Flatten[GetAlphas/@Transpose[sols/.Rule[a_,b_]:>{a,b}][[2]]]]>0


MatchOneAmplitude[ampdiff_,vars2oneall_,replacements_:{}]:=Block[{diff00,diff0,diff,kins,system,systemi,sols0,sols,res,check,ord=1},
(*ord=1 corresponds to the finite part, if UVPoles is True then we take ord=2 which does the 1/epsbar term*)
(*If[UVPoles,ord=2];
diff00=MyCoefficientList[ampdiff,Global`invepsilonbar][[ord]];*)
diff0=MyCoefficientList[ampdiff,Global`sSS];
diff=Table[DeleteCases[Union[Flatten[{diff0[[i]]}]],0],{i,Length[diff0]}];
kins=Table[GetKinematics[diff[[i]],vars2oneall],{i,Length[diff]}];
system={};
sols0={};
Do[
If[Length[diff[[icual]]]>0,
AppendTo[system,EliminatParenthesisInAlphas/@Flatten[Table[Table[If[NumericQ[kins[[icual,j]]],diff[[icual,i]],Coefficient[diff[[icual,i]],kins[[icual,j]]]],{i,Length[diff[[icual]]]}],{j,Length[kins[[icual]]]}]]];
AppendTo[sols0,SolveMinimalLinearSystem[system[[-1]],Union[Flatten[GetAlphas/@system[[-1]]]]][[1]]];
],{icual,Length[diff]}];
(*Print["system=",system];*)
sols0=Flatten[sols0];
sols=Simplify[Table[PutParenthesisInAlphas[sols0[[i,1]]]->sols0[[i,2]],{i,Length[sols0]}]/.Global`ddF[a_,b_,c_]->KroneckerDelta[b,c]];
If[!AlphasInSolQ[sols],
sols=EliminateRepeated[sols,replacements]];
(*{res,check}={sols,Union[{Simplify[Flatten[diff]/.List\[Rule]Plus/.Global`ddF[a_,b_,c_]\[Rule]KroneckerDelta[b,c]/.sols]}]};*)
{res,check}={sols,Union[(DummyZeroQ/@Flatten[{diff/.Global`ddF[a_,b_,c_]->KroneckerDelta[b,c]/.sols/.replacements}])]};
(*If[!(Length[check]\[GreaterEqual]0&&Length[DeleteCases[check,0]]\[Equal]0),Print["Something is wrong with amplitude ",StringReplace[ToString[particles],{"{"\[Rule]"","}"\[Rule]"",","\[Rule]" "}],check]];*)(*Print[res];*)
{res,check}
]


Options[CheckOneAmplitude]={Verbose->False};

CheckOneAmplitude[WC_,ampE_,ampF_,indranges_,runogauge_,mireplacegaugedata_,particles_,opts:OptionsPattern[]]:=Module[{system0,system,kins,sols,sols0,res,check},
If[OptionValue[Verbose],Print[DateString[],": computing system0"]];
system0=GetsSSOrder[#,ComputesSSPower[ampE]]&/@(DeleteCases[Union[Flatten[{Normal[SumExpandIndicesEfficient[ampE[[1]]-ampF[[1]],indranges,runogauge,mireplacegaugedata]]}]],0]//.ampE[[2]]//.ampF[[2]]/.Global`DEN[a_,b_]->1/(a^2-b^2)/.Global`FourPi->4Pi/.Global`listareplacesymmetry/.Dot[a_,Power[b_,n_]]->Power[Dot[a,b],n](*/.Global`ddF[a_,b_,c_]\[Rule]KroneckerDelta[b,c]*));
Union[Simplify[TreatDummyFlavorGeneral/@(system0/.Global`ddF[a_,b_,c_]->KroneckerDelta[b,c]/.WC)]]
]


GetIndices[exp_,indref_:{}]:=Block[{mons,int,ext,monshere,iii,allindices,counts},
mons=Splitter[exp];
int={};
ext={};
Do[
allindices=StringSplit[StringReplace[StringRiffle[StringCases[ToString[InputForm[mons[[iii]]/.Power[a_[c___],2]:>Dot@@Table[a[c],2]]],"["~~s:Except["["|"]"]...~~"]":>s],","]," "->""],","];
(*Print["allinds=",allindices];*)
counts=Counts[allindices];
AppendTo[ext,Keys[Select[counts,#==1&]]];
AppendTo[int,Keys[Select[counts,#>1&]]];
(*If[MemberQ[Values[counts],1],AppendTo[ext,PositionIndex[counts][1]],AppendTo[int,PositionIndex[counts][2]]];*)
(*If[MemberQ[Values[counts],2],AppendTo[int,PositionIndex[counts][2]]];*)
,{iii,Length[mons]}];
{DeleteDuplicates[Flatten[int]],DeleteDuplicates[Flatten[ext]]}];


TreatDummyFlavor[exp_]:=Module[{sys,dummyindices,flindices},
sys=Splitter[exp];
Sum[
dummyindices=ToExpression/@(GetIndices[sys[[j]]][[1]]);
flindices=Select[dummyindices,MemberQ[fli,#]&];
sys[[j]]/.MapThread[Rule,{flindices,Take[FLi,Length[flindices]]}]/.MapThread[Rule,{FLi,fli}],{j,Length[sys]}]]


ComplexConjugate[exp_,complexifyx_]:=Conjugate[exp/.complexifyx]//.{Conjugate[a_+b_]->Conjugate[a]+Conjugate[b],Conjugate[a_*b_]->Conjugate[a]Conjugate[b]}/.Conjugate[a_]->a;



ImposeHermiticity[wclist_,complexifyx_,complexifyFx_]:=Module[{ke,prob,newrules,newruleske},
ke=wclist/.Rule[a_,b_]:>a;
prob=DeleteCases[Tally[ke],{_,1}];
If[Length[prob]>0,prob=Transpose[prob][[1]]];
newrules=EliminateRepeated[Table[Rule[prob[[i]],ComplexConjugate[(ComplexConjugate[RemoveUnderscore[prob[[i]]]/.wclist,complexifyFx]+ComplexConjugate[RemoveUnderscore[prob[[i]]],complexifyx]/.wclist)/2//Simplify,complexifyFx]],{i,Length[prob]}]];
newruleske=newrules/.Rule[a_,b_]:>a;
{Join[Select[wclist,!MemberQ[newruleske,Keys[#]]&],newrules],Select[wclist,MemberQ[newruleske,Keys[#]]&]}
]


noSpuriousE={Global`alphaE12[Global`mif1,Global`mif2]->0,Global`alphaE13[Global`mif1,Global`mif2]->0,Global`alphaE14[Global`mif1,Global`mif2]->0,Global`alphaE15[Global`mif1,Global`mif2]->0,Global`alphaE16[Global`mif1,Global`mif2]->0,Global`alphaE17[Global`mif1,Global`mif2]->0,Global`alphaE18[Global`mif1,Global`mif2]->0,Global`alphaE19[Global`mif1,Global`mif2]->0,Global`alphaE20[Global`mif1,Global`mif2]->0,Global`alphaE21[Global`mif1,Global`mif2]->0,Global`alphaE12bar[Global`mif1,Global`mif2]->0,Global`alphaE13bar[Global`mif1,Global`mif2]->0,Global`alphaE14bar[Global`mif1,Global`mif2]->0,Global`alphaE15bar[Global`mif1,Global`mif2]->0,Global`alphaE16bar[Global`mif1,Global`mif2]->0,Global`alphaE17bar[Global`mif1,Global`mif2]->0,Global`alphaE18bar[Global`mif1,Global`mif2]->0,Global`alphaE19bar[Global`mif1,Global`mif2]->0,Global`alphaE20bar[Global`mif1,Global`mif2]->0,Global`alphaE21bar[Global`mif1,Global`mif2]->0};

WCxfnames={(*Global`alS01\[Rule]"\[Delta]ZB",Global`alS02\[Rule]"\[Delta]ZW",Global`alS03\[Rule]"\[Delta]ZG",Global`alS04\[Rule]"\[Delta]Zq",Global`alS05\[Rule]"\[Delta]Zl",Global`alS06\[Rule]"\[Delta]Zu",Global`alS07\[Rule]"\[Delta]Zd",Global`alS08\[Rule]"\[Delta]Ze",Global`alS09\[Rule]"\[Delta]ZH",Global`alS10\[Rule]"\[Delta]mH^2",Global`alS11\[Rule]"\[Delta]\[Lambda]",Global`alS12\[Rule]"\[Delta]Yd",Global`alS13\[Rule]"\[Delta]Ye",Global`alS14\[Rule]"\[Delta]Yu",*)Global`alO01->Global`alphaphiD,Global`alO02->Global`alphaphiBox,Global`alO03->Global`alphaphi,Global`alO04->Global`alphaphiG,Global`alO05->Global`alphaphiGtilde,Global`alO06->Global`alphaphiW,Global`alO07->Global`alphaphiWtilde,Global`alO08->Global`alphaphiB,Global`alO09->Global`alphaphiBtilde,Global`alO10->Global`alphaphiWB,Global`alO11->Global`alphaphiWtildeB,Global`alO12->Global`alphaphiG,Global`alO13->Global`alphaphiGtilde,Global`alO14->Global`alphaphiW,Global`alO15->Global`alphaphiWtilde,Global`alO16->Global`alphaephi,Global`alO17->Global`alphauphi,Global`alO18->Global`alphadphi,Global`alO19->Global`alphaphil1,Global`alO20->Global`alphaphil3,Global`alO21->Global`alphaphie,Global`alO22->Global`alphaphiq1,Global`alO23->Global`alphaphiq3,Global`alO24->Global`alphaphiu,Global`alO25->Global`alphaphid,Global`alO26->Global`alphaphiud,Global`alO27->Global`alphaeB,Global`alO28->Global`alphauB,Global`alO29->Global`alphadB,Global`alO30->Global`alphaeW,Global`alO31->Global`alphauW,Global`alO32->Global`alphadW,Global`alO33->Global`alphauG,Global`alO34->Global`alphadG,Global`alO35->Global`alphale,Global`alO36->Global`alphalu,Global`alO37->Global`alphald,Global`alO38->Global`alphaqe,Global`alO39->Global`alphaqu1,Global`alO40->Global`alphaqu8,Global`alO41->Global`alphaqd1,Global`alO42->Global`alphaqd8,Global`alO43->Global`alphaledq,Global`alO44->Global`alphaquqd1,Global`alO45->Global`alphaquqd8,Global`alO46->Global`alphalequ1,Global`alO47->Global`alphalequ3,Global`alO48->Global`alphall,Global`alO49->Global`alphaqq1,Global`alO50->Global`alphaqq3,Global`alO51->Global`alphalq1,Global`alO52->Global`alphalq3,Global`alO53->Global`alphaee,Global`alO54->Global`alphauu,Global`alO55->Global`alphadd,Global`alO56->Global`alphaeu,Global`alO57->Global`alphaed,Global`alO58->Global`alphaud1,Global`alO59->Global`alphaud8};

(* We use this to turn the result back into the original notation to be able to implement prettynames *)
InverseWCxfnames=WCxfnames/.{Rule[a_,b_]:>Rule[b,a]};

prettynames={Global`alS01->"\[Delta]ZB",Global`alS02->"\[Delta]ZW",Global`alS03->"\[Delta]ZG",Global`alS04->"\[Delta]Zq",Global`alS05->"\[Delta]Zl",Global`alS06->"\[Delta]Zu",Global`alS07->"\[Delta]Zd",Global`alS08->"\[Delta]Ze",Global`alS09->"\[Delta]ZH",Global`alS10->"\[Delta]mH^2",Global`alS11->"\[Delta]\[Lambda]",Global`alS12->"\[Delta]Yd",Global`alS13->"\[Delta]Ye",Global`alS14->"\[Delta]Yu",Global`alO01->"\!\(\*SubscriptBox[\(\[Alpha]\), \(\[Phi]D\)]\)",Global`alO02->"\!\(\*SubscriptBox[\(\[Alpha]\), \(\[Phi]\[EmptySquare]\)]\)",Global`alO03->"\!\(\*SubscriptBox[\(\[Alpha]\), \(\[Phi]\)]\)",Global`alO04->"\!\(\*SubscriptBox[\(\[Alpha]\), \(\[Phi]G\)]\)",Global`alO05->"\!\(\*SubscriptBox[\(\[Alpha]\), \(\[Phi] \*OverscriptBox[\(G\), \(~\)]\)]\)",Global`alO06->"\!\(\*SubscriptBox[\(\[Alpha]\), \(\[Phi]W\)]\)",Global`alO07->"\!\(\*SubscriptBox[\(\[Alpha]\), \(\[Phi] \*OverscriptBox[\(W\), \(~\)]\)]\)",Global`alO08->"\!\(\*SubscriptBox[\(\[Alpha]\), \(\[Phi]B\)]\)",Global`alO09->"\!\(\*SubscriptBox[\(\[Alpha]\), \(\[Phi] \*OverscriptBox[\(B\), \(~\)]\)]\)",Global`alO10->"\!\(\*SubscriptBox[\(\[Alpha]\), \(\[Phi]WB\)]\)",Global`alO11->"\!\(\*SubscriptBox[\(\[Alpha]\), \(\[Phi] \*OverscriptBox[\(W\), \(~\)] B\)]\)",Global`alO12->"\!\(\*SubscriptBox[\(\[Alpha]\), \(G\)]\)",Global`alO13->"\!\(\*SubscriptBox[\(\[Alpha]\), OverscriptBox[\(G\), \(~\)]]\)",Global`alO14->"\!\(\*SubscriptBox[\(\[Alpha]\), \(W\)]\)",Global`alO15->"\!\(\*SubscriptBox[\(\[Alpha]\), OverscriptBox[\(W\), \(~\)]]\)",Global`alO16->"\!\(\*SubscriptBox[\(\[Alpha]\), \(e\[Phi]\)]\)",Global`alO17->"\!\(\*SubscriptBox[\(\[Alpha]\), \(u\[Phi]\)]\)",Global`alO18->"\!\(\*SubscriptBox[\(\[Alpha]\), \(d\[Phi]\)]\)",Global`alO19->"\!\(\*SubsuperscriptBox[\(\[Alpha]\), \(\[Phi]l\), \((1)\)]\)",Global`alO20->"\!\(\*SubsuperscriptBox[\(\[Alpha]\), \(\[Phi]l\), \((3)\)]\)",Global`alO21->"\!\(\*SubscriptBox[\(\[Alpha]\), \(\[Phi]e\)]\)",Global`alO22->"\!\(\*SubsuperscriptBox[\(\[Alpha]\), \(\[Phi]q\), \((1)\)]\)",Global`alO23->"\!\(\*SubsuperscriptBox[\(\[Alpha]\), \(\[Phi]q\), \((3)\)]\)",Global`alO24->"\!\(\*SubscriptBox[\(\[Alpha]\), \(\[Phi]u\)]\)",Global`alO25->"\!\(\*SubscriptBox[\(\[Alpha]\), \(\[Phi]d\)]\)",Global`alO26->"\!\(\*SubscriptBox[\(\[Alpha]\), \(\[Phi]ud\)]\)",Global`alO27->"\!\(\*SubscriptBox[\(\[Alpha]\), \(eB\)]\)",Global`alO28->"\!\(\*SubscriptBox[\(\[Alpha]\), \(uB\)]\)",Global`alO29->"\!\(\*SubscriptBox[\(\[Alpha]\), \(dB\)]\)",Global`alO30->"\!\(\*SubscriptBox[\(\[Alpha]\), \(eW\)]\)",Global`alO31->"\!\(\*SubscriptBox[\(\[Alpha]\), \(uW\)]\)",Global`alO32->"\!\(\*SubscriptBox[\(\[Alpha]\), \(dW\)]\)",Global`alO33->"\!\(\*SubscriptBox[\(\[Alpha]\), \(uG\)]\)",Global`alO34->"\!\(\*SubscriptBox[\(\[Alpha]\), \(dG\)]\)",Global`alO35->"\!\(\*SubscriptBox[\(\[Alpha]\), \(le\)]\)",Global`alO36->"\!\(\*SubscriptBox[\(\[Alpha]\), \(lu\)]\)",Global`alO37->"\!\(\*SubscriptBox[\(\[Alpha]\), \(ld\)]\)",Global`alO38->"\!\(\*SubscriptBox[\(\[Alpha]\), \(qe\)]\)",Global`alO39->"\!\(\*SubsuperscriptBox[\(\[Alpha]\), \(qu\), \((1)\)]\)",Global`alO40->"\!\(\*SubsuperscriptBox[\(\[Alpha]\), \(qu\), \((8)\)]\)",Global`alO41->"\!\(\*SubsuperscriptBox[\(\[Alpha]\), \(qd\), \((1)\)]\)",Global`alO42->"\!\(\*SubsuperscriptBox[\(\[Alpha]\), \(qd\), \((8)\)]\)",Global`alO43->"\!\(\*SubscriptBox[\(\[Alpha]\), \(ledq\)]\)",Global`alO44->"\!\(\*SubsuperscriptBox[\(\[Alpha]\), \(quqd\), \((1)\)]\)",Global`alO45->"\!\(\*SubsuperscriptBox[\(\[Alpha]\), \(quqd\), \((8)\)]\)",Global`alO46->"\!\(\*SubsuperscriptBox[\(\[Alpha]\), \(lequ\), \((1)\)]\)",Global`alO47->"\!\(\*SubsuperscriptBox[\(\[Alpha]\), \(lequ\), \((3)\)]\)",Global`alO48->"\!\(\*SubscriptBox[\(\[Alpha]\), \(ll\)]\)",Global`alO49->"\!\(\*SubsuperscriptBox[\(\[Alpha]\), \(qq\), \((1)\)]\)",Global`alO50->"\!\(\*SubsuperscriptBox[\(\[Alpha]\), \(qq\), \((3)\)]\)",Global`alO51->"\!\(\*SubsuperscriptBox[\(\[Alpha]\), \(lq\), \((1)\)]\)",Global`alO52->"\!\(\*SubsuperscriptBox[\(\[Alpha]\), \(lq\), \((3)\)]\)",Global`alO53->"\!\(\*SubscriptBox[\(\[Alpha]\), \(ee\)]\)",Global`alO54->"\!\(\*SubscriptBox[\(\[Alpha]\), \(uu\)]\)",Global`alO55->"\!\(\*SubscriptBox[\(\[Alpha]\), \(dd\)]\)",Global`alO56->"\!\(\*SubscriptBox[\(\[Alpha]\), \(eu\)]\)",Global`alO57->"\!\(\*SubscriptBox[\(\[Alpha]\), \(ed\)]\)",Global`alO58->"\!\(\*SubsuperscriptBox[\(\[Alpha]\), \(ud\), \((1)\)]\)",Global`alO59->"\!\(\*SubsuperscriptBox[\(\[Alpha]\), \(ud\), \((8)\)]\)"};


WCxfnamesbar={(*Global`alS12bar\[Rule]"\!\(\*SuperscriptBox[\(\[Delta]Yd\), \(*\)]\)",Global`alS13bar\[Rule]"\!\(\*SuperscriptBox[\(\[Delta]Ye\), \(*\)]\)",Global`alS14bar\[Rule]"\!\(\*SuperscriptBox[\(\[Delta]Yu\), \(*\)]\)",*)Global`alO16bar->Global`alphaephibar,Global`alO17bar->Global`alphauphibar,Global`alO18bar->Global`alphadphibar,Global`alO19bar->Global`alphaphil1bar,Global`alO20bar->Global`alphaphil3bar,Global`alO21bar->Global`alphaphiebar,Global`alO22bar->Global`alphaphiq1bar,Global`alO23bar->Global`alphaphiq3bar,Global`alO24bar->Global`alphaphiubar,Global`alO25bar->Global`alphaphidbar,Global`alO26bar->Global`alphaphiudbar,Global`alO27bar->Global`alphaeBbar,Global`alO28bar->Global`alphauBbar,Global`alO29bar->Global`alphadBbar,Global`alO30bar->Global`alphaeWbar,Global`alO31bar->Global`alphauWbar,Global`alO32bar->Global`alphadWbar,Global`alO33bar->Global`alphauGbar,Global`alO34bar->Global`alphadGbar,Global`alO35bar->Global`alphalebar,Global`alO36bar->Global`alphalubar,Global`alO37bar->Global`alphaldbar,Global`alO38bar->Global`alphaqebar,Global`alO39bar->Global`alphaqu1bar,Global`alO40bar->Global`alphaqu8bar,Global`alO41bar->Global`alphaqd1bar,Global`alO42bar->Global`alphaqd8bar,Global`alO43bar->Global`alphaledqbar,Global`alO44bar->Global`alphaquqd1bar,Global`alO45bar->Global`alphaquqd8bar,Global`alO46bar->Global`alphalequ1bar,Global`alO47bar->Global`alphalequ3bar,Global`alO48bar->Global`alphallbar,Global`alO49bar->Global`alphaqq1bar,Global`alO50bar->Global`alphaqq3bar,Global`alO51bar->Global`alphalq1bar,Global`alO52bar->Global`alphalq3bar,Global`alO53bar->Global`alphaeebar,Global`alO54bar->Global`alphauubar,Global`alO55bar->Global`alphaddbar,Global`alO56bar->Global`alphaeubar,Global`alO57bar->Global`alphaedbar,Global`alO58bar->Global`alphaud1bar,Global`alO59bar->Global`alphaud8bar};


(* We use this to turn the result back into the original notation to be able to implement prettynames *)
InverseWCxfnamesbar=WCxfnamesbar/.{Rule[a_,b_]:>Rule[b,a]};

prettynamesbar={Global`alS12bar->"\!\(\*SuperscriptBox[\(\[Delta]Yd\), \(*\)]\)",Global`alS13bar->"\!\(\*SuperscriptBox[\(\[Delta]Ye\), \(*\)]\)",Global`alS14bar->"\!\(\*SuperscriptBox[\(\[Delta]Yu\), \(*\)]\)",Global`alO16bar->"\!\(\*SubscriptBox[OverscriptBox[\(\[Alpha]\), \(_\)], \(e\[Phi]\)]\)",Global`alO17bar->"\!\(\*SubscriptBox[OverscriptBox[\(\[Alpha]\), \(_\)], \(u\[Phi]\)]\)",Global`alO18bar->"\!\(\*SubscriptBox[OverscriptBox[\(\[Alpha]\), \(_\)], \(d\[Phi]\)]\)",Global`alO19bar->"\!\(\*SubsuperscriptBox[OverscriptBox[\(\[Alpha]\), \(_\)], \(\[Phi]l\), \((1)\)]\)",Global`alO20bar->"\!\(\*SubsuperscriptBox[OverscriptBox[\(\[Alpha]\), \(_\)], \(\[Phi]l\), \((3)\)]\)",Global`alO21bar->"\!\(\*SubscriptBox[OverscriptBox[\(\[Alpha]\), \(_\)], \(\[Phi]e\)]\)",Global`alO22bar->"\!\(\*SubsuperscriptBox[OverscriptBox[\(\[Alpha]\), \(_\)], \(\[Phi]q\), \((1)\)]\)",Global`alO23bar->"\!\(\*SubsuperscriptBox[OverscriptBox[\(\[Alpha]\), \(_\)], \(\[Phi]q\), \((3)\)]\)",Global`alO24bar->"\!\(\*SubscriptBox[OverscriptBox[\(\[Alpha]\), \(_\)], \(\[Phi]u\)]\)",Global`alO25bar->"\!\(\*SubscriptBox[OverscriptBox[\(\[Alpha]\), \(_\)], \(\[Phi]d\)]\)",Global`alO26bar->"\!\(\*SubscriptBox[OverscriptBox[\(\[Alpha]\), \(_\)], \(\[Phi]ud\)]\)",Global`alO27bar->"\!\(\*SubscriptBox[OverscriptBox[\(\[Alpha]\), \(_\)], \(eB\)]\)",Global`alO28bar->"\!\(\*SubscriptBox[OverscriptBox[\(\[Alpha]\), \(_\)], \(uB\)]\)",Global`alO29bar->"\!\(\*SubscriptBox[OverscriptBox[\(\[Alpha]\), \(_\)], \(dB\)]\)",Global`alO30bar->"\!\(\*SubscriptBox[OverscriptBox[\(\[Alpha]\), \(_\)], \(eW\)]\)",Global`alO31bar->"\!\(\*SubscriptBox[OverscriptBox[\(\[Alpha]\), \(_\)], \(uW\)]\)",Global`alO32bar->"\!\(\*SubscriptBox[OverscriptBox[\(\[Alpha]\), \(_\)], \(dW\)]\)",Global`alO33bar->"\!\(\*SubscriptBox[OverscriptBox[\(\[Alpha]\), \(_\)], \(uG\)]\)",Global`alO34bar->"\!\(\*SubscriptBox[OverscriptBox[\(\[Alpha]\), \(_\)], \(dG\)]\)",Global`alO35bar->"\!\(\*SubscriptBox[OverscriptBox[\(\[Alpha]\), \(_\)], \(le\)]\)",Global`alO36bar->"\!\(\*SubscriptBox[OverscriptBox[\(\[Alpha]\), \(_\)], \(lu\)]\)",Global`alO37bar->"\!\(\*SubscriptBox[OverscriptBox[\(\[Alpha]\), \(_\)], \(ld\)]\)",Global`alO38bar->"\!\(\*SubscriptBox[OverscriptBox[\(\[Alpha]\), \(_\)], \(qe\)]\)",Global`alO39bar->"\!\(\*SubsuperscriptBox[OverscriptBox[\(\[Alpha]\), \(_\)], \(qu\), \((1)\)]\)",Global`alO40bar->"\!\(\*SubsuperscriptBox[OverscriptBox[\(\[Alpha]\), \(_\)], \(qu\), \((8)\)]\)",Global`alO41bar->"\!\(\*SubsuperscriptBox[OverscriptBox[\(\[Alpha]\), \(_\)], \(qd\), \((1)\)]\)",Global`alO42bar->"\!\(\*SubsuperscriptBox[OverscriptBox[\(\[Alpha]\), \(_\)], \(qd\), \((8)\)]\)",Global`alO43bar->"\!\(\*SubscriptBox[OverscriptBox[\(\[Alpha]\), \(_\)], \(ledq\)]\)",Global`alO44bar->"\!\(\*SubsuperscriptBox[OverscriptBox[\(\[Alpha]\), \(_\)], \(quqd\), \((1)\)]\)",Global`alO45bar->"\!\(\*SubsuperscriptBox[OverscriptBox[\(\[Alpha]\), \(_\)], \(quqd\), \((8)\)]\)",Global`alO46bar->"\!\(\*SubsuperscriptBox[OverscriptBox[\(\[Alpha]\), \(_\)], \(lequ\), \((1)\)]\)",Global`alO47bar->"\!\(\*SubsuperscriptBox[OverscriptBox[\(\[Alpha]\), \(_\)], \(lequ\), \((3)\)]\)",Global`alO48bar->"\!\(\*SubscriptBox[OverscriptBox[\(\[Alpha]\), \(_\)], \(ll\)]\)",Global`alO49bar->"\!\(\*SubsuperscriptBox[OverscriptBox[\(\[Alpha]\), \(_\)], \(qq\), \((1)\)]\)",Global`alO50bar->"\!\(\*SubsuperscriptBox[OverscriptBox[\(\[Alpha]\), \(_\)], \(qq\), \((3)\)]\)",Global`alO51bar->"\!\(\*SubsuperscriptBox[OverscriptBox[\(\[Alpha]\), \(_\)], \(lq\), \((1)\)]\)",Global`alO52bar->"\!\(\*SubsuperscriptBox[OverscriptBox[\(\[Alpha]\), \(_\)], \(lq\), \((3)\)]\)",Global`alO53bar->"\!\(\*SubscriptBox[OverscriptBox[\(\[Alpha]\), \(_\)], \(ee\)]\)",Global`alO54bar->"\!\(\*SubscriptBox[OverscriptBox[\(\[Alpha]\), \(_\)], \(uu\)]\)",Global`alO55bar->"\!\(\*SubscriptBox[OverscriptBox[\(\[Alpha]\), \(_\)], \(dd\)]\)",Global`alO56bar->"\!\(\*SubscriptBox[OverscriptBox[\(\[Alpha]\), \(_\)], \(eu\)]\)",Global`alO57bar->"\!\(\*SubscriptBox[OverscriptBox[\(\[Alpha]\), \(_\)], \(ed\)]\)",Global`alO58bar->"\!\(\*SubsuperscriptBox[OverscriptBox[\(\[Alpha]\), \(_\)], \(ud\), \((1)\)]\)",Global`alO59bar->"\!\(\*SubsuperscriptBox[OverscriptBox[\(\[Alpha]\), \(_\)], \(ud\), \((8)\)]\)"};



TurnToGlobal[exp_]:=ToExpression[StringReplace[ToString[exp,InputForm],{"matcher`Private"->"Global"}]];



TreatDummyFlavorGeneral[exp_,lis_:{"fl"}]:=Block[{listexp,res,internalflavor,externalflavor,miflisnoexternal,numf},
listexp=Splitter[exp];
res=0;
Do[
internalflavor=ToExpression/@GetIndices[listexp[[i]],lis][[1]];
externalflavor=ToExpression/@GetIndices[listexp[[i]],lis][[2]];
miflisnoexternal=Select[miflis,!MemberQ[externalflavor,#]&];
numf=Length[internalflavor];
If[numf>0,
res=res+(listexp[[i]]/.Table[internalflavor[[jj]]->miflisnoexternal[[jj]],{jj,numf}]);,
res=res+listexp[[i]];
];
,{i,Length[listexp]}];
(*Simplify[res]*)
res
];


CanonicallyNormalizeOld[wcredundanttree_List,wcredundantloop_List]:=Block[{SMrenorm,deltalist,deltalist0,iix,wcredundantlooprenormalized},
SMrenorm=Select[wcredundantloop,StringContainsQ[ToString[#[[1]]],"alphaS"]&];deltalist0=Table[Rule[TurnToGlobal[alldeltalist0[[iix,1]]],TreatDummyFlavorGeneral[TurnToGlobal[alldeltalist0[[iix,2]]]/.SMrenorm/.wcredundanttree,{"MIF","mif","fl"}]],{iix,Length[alldeltalist0]}];deltalist=ToExpression[StringReplace[ToString[deltalist0,InputForm],{"matcher`Private"->"Global"}]];
wcredundantlooprenormalized=Table[Rule[wcredundantloop[[iix,1]],Simplify[wcredundantloop[[iix,2]]+ToExpression["delta"<>StringReplace[ToString[wcredundantloop[[iix,1]]],"_"->""]]/.deltalist]],{iix,Length[wcredundantloop]}];{wcredundanttree,wcredundantlooprenormalized}]



Options[ComputeWilsonCoefficients]={FullCheck->False,Parallel->False};



ComputeWilsonCoefficientsNewNew[modelnameF_,modelnameE_]:=Block[{realpars,complexpars,complexify,dilist,groupdata,indranges,indi,mireplacegaugedata,mirunogauge,vars2one,listhermiticity,finalruleordered,replacegaugedata,listhermiticityF,realparsF,complexparsF,complexifyF,dilistF,groupdataF,indrangesF,indiF,mireplacegaugedataF,mirunogaugeF,vars2oneF,finalruleorderedF,replacegaugedataF,diE,diF0,diF1,pars,allsols,dini,dfin,soltemp,sol,newsolbar,newsol,fullsol,allparsF,replF,soltemp2,finalfullsol,listareplacesymmetry,listareplacesymmetryF},
{realpars,complexpars,complexify,dilist,groupdata,indranges,indi,mireplacegaugedata,mirunogauge,vars2one,{listhermiticity,finalruleordered,replacegaugedata,listareplacesymmetry}}=InitializeModel[modelnameE];
EFTMatching=MatchEFT[modelnameE];
{realparsF,complexparsF,complexifyF,dilistF,groupdataF,indrangesF,indiF,mireplacegaugedataF,mirunogaugeF,vars2oneF,{listhermiticityF,finalruleorderedF,replacegaugedataF,listareplacesymmetryF}}=InitializeModel[modelnameF];
allparsF=Join[ToExpression/@realparsF,ToExpression/@complexparsF,(ToExpression/@complexparsF)/.complexifyF];
replF=RenameOneLoopWC[allparsF];
diF0=dilistF[[1,1]];
diF1=dilistF[[2,1]];
dini=DateString[];
Print["Beginning of matching calculation. ",dini];
sol={EFTMatching[[-1]]/.Global`Coeff[a_,b_,c_,d_]:>GetSpecificAmplitudeNewNew[(Flatten[{#}]&/@(MyCoefficientList[PrepareAmplitude[diF0[a],indrangesF,mirunogaugeF,mireplacegaugedataF,True]/.replF,Global`sSS])),b,c,d],EFTMatching[[-1]]/.Global`Coeff[a_,b_,c_,d_]:>GetSpecificAmplitudeNewNew[(Flatten[{#}]&/@(MyCoefficientList[PrepareAmplitude[diF1[a],indrangesF,mirunogaugeF,mireplacegaugedataF,True]/.replF,Global`sSS])),b,c,d]};
dfin=DateString[];
Print["End of matching calculation. ",dfin];
Print["Matching calculation finished. It took "<>ToString[DateDifference[dini,dfin,{"Hour","Minute","Second"}]]];
newsolbar=Table[Table[(sol[[j,i,1]]/.Union[Join[complexify,complexifyF/.replF]])->TreatDummyFlavor[ComplexConjugate[sol[[j,i,2]],Union[Join[complexify,complexifyF/.replF]]]]/.(listhermiticityF/.replF),{i,Length[sol[[j]]]}],{j,Length[sol]}];newsol=Table[Table[(sol[[j,i,1]])->TreatDummyFlavor[sol[[j,i,2]]],{i,Length[sol[[j]]]}],{j,Length[sol]}]/.(listhermiticityF/.replF);
fullsol=Table[EliminateRepeated[Union[Join[newsol[[j]],newsolbar[[j]]]],Join[dilist[[1,2]],dilistF[[j,2]]]],{j,Length[newsol]}];
finalfullsol=ImposeHermiticity[#,complexify,complexifyF]&/@fullsol
]


ComputeWilsonCoefficientsNew[modelnameF_,modelnameE_]:=Block[{realpars,complexpars,complexify,dilist,groupdata,indranges,indi,mireplacegaugedata,mirunogauge,vars2one,listhermiticity,finalruleordered,replacegaugedata,listhermiticityF,realparsF,complexparsF,complexifyF,dilistF,groupdataF,indrangesF,indiF,mireplacegaugedataF,mirunogaugeF,vars2oneF,finalruleorderedF,replacegaugedataF,diE,diF0,diF1,pars,allsols,dini,dfin,dfinfin,soltemp,sol,newsolbar,newsol,fullsol,allparsF,replF,soltemp2,finalfullsol,listareplacesymmetry,listareplacesymmetryF},
Print["Initializing EFT"];
{realpars,complexpars,complexify,dilist,groupdata,indranges,indi,mireplacegaugedata,mirunogauge,vars2one,{listhermiticity,finalruleordered,replacegaugedata,listareplacesymmetry}}=InitializeModel[modelnameE];
EFTMatching=MatchEFT[modelnameE];
Print["Initializing Full Theory"];
{realparsF,complexparsF,complexifyF,dilistF,groupdataF,indrangesF,indiF,mireplacegaugedataF,mirunogaugeF,vars2oneF,{listhermiticityF,finalruleorderedF,replacegaugedataF,listareplacesymmetryF}}=InitializeModel[modelnameF];
allparsF=Join[ToExpression/@realparsF,ToExpression/@complexparsF,(ToExpression/@complexparsF)/.complexifyF];
replF=RenameOneLoopWC[allparsF];
diF0=dilistF[[1,1]];
diF1=dilistF[[2,1]];
dini=DateString[];
Print["Beginning of matching calculation. ",dini];
sol={EFTMatching[[-1]]/.Global`Coeff[a_,b_,c_,d_]:>GetSpecificAmplitudeNew[diF0,indrangesF,mirunogaugeF,mireplacegaugedataF,replF,a,b,c,d],EFTMatching[[-1]]/.Global`Coeff[a_,b_,c_,d_]:>GetSpecificAmplitudeNew[diF1,indrangesF,mirunogaugeF,mireplacegaugedataF,replF,a,b,c,d]};
dfin=DateString[];
Print["End of matching calculation. ",dfin];
Print["Matching calculation finished. It took "<>ToString[DateDifference[dini,dfin,{"Hour","Minute","Second"}]]];
Print["Now tidying up the result"];
newsolbar=Table[Table[(sol[[j,i,1]]/.Union[Join[complexify,complexifyF/.replF]])->TreatDummyFlavor[ComplexConjugate[sol[[j,i,2]],Union[Join[complexify,complexifyF/.replF]]]]/.(listhermiticityF/.replF),{i,Length[sol[[j]]]}],{j,Length[sol]}];newsol=Table[Table[(sol[[j,i,1]])->TreatDummyFlavor[sol[[j,i,2]]],{i,Length[sol[[j]]]}],{j,Length[sol]}]/.(listhermiticityF/.replF);
fullsol=Table[EliminateRepeated[Union[Join[newsol[[j]],newsolbar[[j]]]],Join[dilist[[1,2]],dilistF[[j,2]]]],{j,Length[newsol]}];
finalfullsol=ImposeHermiticity[#,complexify,complexifyF]&/@fullsol;
dfinfin=DateString[];
Print["Complete matching calculation finished. It took "<>ToString[DateDifference[dini,dfin,dfin{"Hour","Minute","Second"}]]];
finalfullsol
]


CanonicallyNormalize[wclist_,modelnameE_,complexifyx_]:=Block[{canorfile,kinrule,kindic,gaugecouplingsandbosonsdic,gaugecouplingrenormalization,alphakin,alphakinbar,alphakinlist,wctreenokin,canorlist,gaugecouplingsandbosonsfile,gaugecouplingsandbosonsdata},
canorfile=FileNameJoin[{modelnameE,"QGRAF","model_data","canonicalnormalization.dat"}];
Get[canorfile];
kinrule=Get[FileNameJoin[{modelnameE,"QGRAF","model_data","kineticrule"}]];
kindic=Association[kinrule/.Rule[a_,b_]:>Rule[a[[1]],b]];
gaugecouplingsandbosonsfile=FileNameJoin[{modelnameE,"QGRAF","model_data","gaugecouplingsandbosons.dat"}];
If[FileExistsQ[gaugecouplingsandbosonsfile],gaugecouplingsandbosonsdata=Import[gaugecouplingsandbosonsfile],
gaugecouplingsandbosonsdata={};
];
If[Length[gaugecouplingsandbosonsdata]>0,
gaugecouplingsandbosonsdic=MapThread[Rule,Transpose[gaugecouplingsandbosonsdata]]/.Rule[a_,b_]:>Rule[ToExpression[a],b];,
gaugecouplingsandbosonsdic={};];
gaugecouplingrenormalization=(gaugecouplingsandbosonsdic/.Rule[a_,b_]:>Rule[a,a(1+Global`oneloop\[Epsilon] kindic[b][[1]]/2)])/.wclist[[2,1]];
alphakin=Flatten[kinrule/.Rule[a_,b_]:>b];
alphakinbar=alphakin/.complexifyx;
alphakinlist=Union[Join[alphakin,alphakinbar]];
wctreenokin=Normal[Complement[Association[wclist[[1,1]]],KeySelect[wclist[[1,1]],MemberQ[alphakinlist,#]&]]];
canorlist=Global`alldeltalist0/.wctreenokin/.wclist[[2,1]];
{{wclist[[1]],{wclist[[2,1]]/.Rule[a_,b_]:>Rule[a,b+(ToExpression[StringReplace["delta"<>ToString[a],"_"->""]]/.canorlist)],wclist[[2,2]]}},gaugecouplingrenormalization}
]


UnifyTreeandLoop[wclist_]:=Block[{dit,dil,ket,kel,res},
dit=Association[wclist[[1,1]]];
dil=Association[wclist[[2,1]]];
ket=Keys[dit];
kel=Keys[dil];
If[Sort[ket]===Sort[kel],
res=Table[Rule[ket[[i]],dit[ket[[i]]]+Global`oneloop\[Epsilon] dil[ket[[i]]]],{i,Length[ket]}],
Print["Keys in tree level and one-loop matching are not the same"];res="Problems"];
res
]


GetFinalRuleOrdered[wclist_,modelnameE_]:=Block[{redfile=FileNameJoin[{modelnameE,"QGRAF","model_data","redundancies.dat"}],res},
If[FileExistsQ[redfile],Get[redfile]];
If[ListQ[Global`finalruleordered]&&Length[Global`finalruleordered]>0,
res=Global`finalruleordered;,
res=wclist[[1,1]]/.Rule[a_,b_]:>Rule[a,RemoveUnderscore[a]];];
res]



GoToPhysicalBasis[wclist_,modelnameE_]:=Block[{redfile=FileNameJoin[{modelnameE,"QGRAF","model_data","redundancies.dat"}],result=UnifyTreeandLoop[wclist]},
If[FileExistsQ[redfile],Get[redfile]];
If[ListQ[Global`finalruleordered]&&Length[Global`finalruleordered]>0,
result=(Global`finalruleordered/.Rule[a_,b_]:>Rule[a,Normal[Series[Expand[b/.UnifyTreeandLoop[wclist]],{Global`oneloop\[Epsilon],0,1}]]]);];
result]



Options[ComputeRGEModeltoEFT]={Verbose->True};


ComputeRGEModeltoEFT[modelnameF_,modelnameE_,opts:OptionsPattern[]]:=Block[{allwilson,wcphysical,wc0,wc1uv,lwc0,lwc1uv,wctreelist,rescalinglist,x,putindices,realpars,complexpars,complexify,dilist,groupdata,indranges,indi,mireplacegaugedata,mirunogauge,vars2one,listhermiticity,finalruleordered,replacegaugedata,allpars,repl,gaugecouplingrenormalization,listareplacesymmetry,classicalandimswithindices,classicalandimsphysical,goodrescalinglist},
If[FileExistsQ[FileNameJoin[{modelnameF,"RGEResult.dat"}]],Print["RGEs for EFT UV model ",modelnameF, " onto EFT ",modelnameE," already computed and stored in file ",FileNameJoin[{modelnameF,"RGEResult.dat"}]];Print["If you want to recreate the calculation please remove that file and run the command again."];Return[]];
Print["Computing the RGEs for EFT UV model ",modelnameF," onto EFT ",modelnameE];
If[!FileExistsQ[FileNameJoin[{modelnameF,"MatchingResult.dat"}]],
MatchModeltoEFT[modelnameF,modelnameE,Evaluate[FilterRules[{opts},Options[MatchModeltoEFT]]]]];
Get[FileNameJoin[{modelnameE,"QGRAF","model_data","classicaldimension.dat"}]];
Get[FileNameJoin[{modelnameF,"MatchingResult.dat"}]];
allwilson=Global`MatchingResult;
Print["Initializing model ",modelnameE];
{realpars,complexpars,complexify,dilist,groupdata,indranges,indi,mireplacegaugedata,mirunogauge,vars2one,{listhermiticity,finalruleordered,replacegaugedata,listareplacesymmetry}}=InitializeModel[modelnameE];
(* we do this to get finalruleordered even if empty*)
finalruleordered=GetFinalRuleOrdered[allwilson[[2]],modelnameE];
allpars=Join[ToExpression/@realpars,ToExpression/@complexpars,(ToExpression/@complexpars)/.complexify];
repl=RenameOneLoopWC[allpars];
wcphysical=allwilson[[3]];
gaugecouplingrenormalization=allwilson[[4]];
wc0=wcphysical/.Global`oneloop\[Epsilon]->0/.Global`epsilonbar->0;
wc1uv=wcphysical/.Global`epsilonbar->0/.Rule[a_,b_]:>Rule[a,Coefficient[b,Global`invepsilonbar Global`oneloop\[Epsilon]]];
lwc0=wc0/.Rule->List;
lwc1uv=wc1uv/.Rule->List;
wctreelist=Table[
If[(lwc1uv[[i,1]]/.wc0)===0,Rule[lwc1uv[[i,1]],RemoveUnderscore[lwc1uv[[i,1]]/.repl]],Rule[lwc1uv[[i,1]],RemoveUnderscore[lwc1uv[[i,1]]/.wc0]]]
,{i,Length[lwc1uv]}];
putindices=Table[Rule[ToExpression[StringSplit[ToString[wctreelist[[i,1]]],"["][[1]]],wctreelist[[i,1]]],{i,Length[wctreelist]}];
rescalinglist=(Global`classicalandims/.Rule[a_,b_]:>Rule[(a/.putindices)/.wctreelist,b])/.Rule[a_,b_]:>Rule[a,RemoveUnderscore[a] x^b];
classicalandimswithindices=Join[Global`classicalandims/.Rule[a_,b_]:>Rule[a[c__],a[c] x^b],Global`classicalandims/.Rule[a_,b_]:>Rule[a,a x^b]];
classicalandimsphysical=finalruleordered/.Rule[a_,b_]:>Rule[a,Exponent[Collect[b/.classicalandimswithindices,x],x]];
goodrescalinglist=Join[(Rule@@@Import[FileNameJoin[{modelnameE,"QGRAF","model_data","gaugecouplingsandbosons.dat"}]])/.Rule[a_,b_]:>Rule[ToExpression[a],x ToExpression[a]],wcphysical/.{Global`epsilonbar->0,Global`oneloop\[Epsilon]->0}/.Rule[a_,b_]:>Rule[PutUnderscore[b],b x^(a/.classicalandimsphysical)]//Union];
(*Print["wctreelist=",wctreelist];
Print["putindices=",putindices];
Print["rescalinglist=",rescalinglist];
Print["goodrescalinglist=",goodrescalinglist];
Print["lwc1uv=",lwc1uv];*)
Print["Computing the beta functions for model " ,modelnameF," onto ",modelnameE];
Global`RGEResult=gaugecouplingrenormalization/.Rule[a_,b_]:>Rule[Global`\[Beta][a],ToExpression[a] D[(Coefficient[b,Global`oneloop\[Epsilon] Global`invepsilonbar]/ToExpression[a])/.goodrescalinglist,x]/.x->1];
Do[
AppendTo[Global`RGEResult,Rule[Global`\[Beta][lwc1uv[[cual,1]]],-Expand[RemoveUnderscore[lwc1uv[[cual,1]]/.wctreelist](D[(lwc1uv[[cual,2]]/RemoveUnderscore[(lwc1uv[[cual,1]]/.wctreelist)])/.goodrescalinglist,x]/.x->1)]]];
,{cual,Length[lwc1uv]}];
(*
Global`RGEResult=Join[gaugecouplingrenormalization/.Rule[a_,b_]\[RuleDelayed]Rule[Global`\[Beta][a],ToExpression[a] D[(Coefficient[b,Global`oneloop\[Epsilon] Global`invepsilonbar]/ToExpression[a])/.rescalinglist,x]/.x\[Rule]1],Table[Rule[Global`\[Beta][lwc1uv[[cual,1]]],-Expand[RemoveUnderscore[lwc1uv[[cual,1]]/.wctreelist](D[(lwc1uv[[cual,2]]/RemoveUnderscore[(lwc1uv[[cual,1]]/.wctreelist)])/.rescalinglist,x]/.x\[Rule]1)]],{cual,Length[lwc1uv]}]];

*)
Print["Saving it on file"];
Save[FileNameJoin[{modelnameF,"RGEResult.dat"}],Global`RGEResult];
Print["RGEs computed, result written in ",FileNameJoin[{modelnameF,"RGEResult.dat"}]];
]


Options[MatchModeltoEFT]={Verbose->True};

MatchModeltoEFT[modelnameF_,modelnameE_,opts:OptionsPattern[]]:=Block[{EFTMatching,alldeltalist0,realpars,complexpars,complexify,dilist,groupdata,indranges,indi,mireplacegaugedata,mirunogauge,vars2one,listhermiticity,finalruleordered,replacegaugedata,listhermiticityF,realparsF,complexparsF,complexifyF,dilistF,groupdataF,indrangesF,indiF,mireplacegaugedataF,mirunogaugeF,vars2oneF,finalruleorderedF,replacegaugedataF,diE,diF0,diF1,pars,allsols,dini,dfin,dfinfin,soltemp,sol,newsolbar,newsol,fullsol,allparsF,replF,soltemp2,finalfullsol,finalfullsolcannor,gaugecouplingrenorm,finalfullphys,listareplacesymmetry,listareplacesymmetryF},
If[FileExistsQ[FileNameJoin[{modelnameF,"MatchingResult.dat"}]],
Print["The matching has already been performed and it is stored in ",FileNameJoin[{modelnameF,"MatchingResult.dat"}],". If you want to recreate it please delete the file and run the command again."];
Return[]];
Print["Initializing EFT"];
{realpars,complexpars,complexify,dilist,groupdata,indranges,indi,mireplacegaugedata,mirunogauge,vars2one,{listhermiticity,finalruleordered,replacegaugedata,listareplacesymmetry}}=InitializeModel[modelnameE];
EFTMatching=MatchEFT[modelnameE];
alldeltalist0=GenerateNormalizationList[modelnameE,complexify];
GenerateClassicalDimension[modelnameE];
Print["Initializing Full Theory"];
{realparsF,complexparsF,complexifyF,dilistF,groupdataF,indrangesF,indiF,mireplacegaugedataF,mirunogaugeF,vars2oneF,{listhermiticityF,finalruleorderedF,replacegaugedataF,listareplacesymmetryF}}=InitializeModel[modelnameF];
allparsF=Join[ToExpression/@realparsF,ToExpression/@complexparsF,(ToExpression/@complexparsF)/.complexifyF];
replF=RenameOneLoopWC[allparsF];
diF0=dilistF[[1,1]];
If[Length[dilistF]==1,AppendTo[dilistF,
{Association[Normal[diF0]/.Rule[a_,b_List]:>Rule[a,{0,{}}]],{}}]];
diF1=dilistF[[2,1]];
dini=DateString[];
Print["Beginning of matching calculation. ",dini];
sol={EFTMatching[[-1]]/.Global`Coeff[a_,b_,c_,d_]:>MiGetSpecificAmplitudeNew[diF0,indrangesF,mirunogaugeF,mireplacegaugedataF,replF,a,b,c,d],EFTMatching[[-1]]/.Global`Coeff[a_,b_,c_,d_]:>MiGetSpecificAmplitudeNew[diF1,indrangesF,mirunogaugeF,mireplacegaugedataF,replF,a,b,c,d]};
dfin=DateString[];
Print["End of matching calculation. ",dfin];
Print["Matching calculation finished. It took "<>ToString[DateDifference[dini,dfin,{"Hour","Minute","Second"}]]];
Print["Now tidying up the result"];
newsolbar=Table[Table[(sol[[j,i,1]]/.Union[Join[complexify,complexifyF/.replF]])->TreatDummyFlavor[ComplexConjugate[sol[[j,i,2]],Union[Join[complexify,complexifyF/.replF]]]]/.(listhermiticityF/.replF),{i,Length[sol[[j]]]}],{j,Length[sol]}];newsol=Table[Table[(sol[[j,i,1]])->TreatDummyFlavor[sol[[j,i,2]]],{i,Length[sol[[j]]]}],{j,Length[sol]}]/.(listhermiticityF/.replF);
(*Print["newsol=",newsol];
Print["newsolbar=",newsolbar];*)
fullsol=Table[EliminateRepeated[Union[Join[newsol[[j]],newsolbar[[j]]]],listareplacesymmetryF/.replF(*Join[dilist[[1,2]],dilistF[[j,2]],listareplacesymmetryF]*)],{j,Length[newsol]}];
Print["Full solution found, now imposing hermiticity. ",DateString[]];
finalfullsol=ImposeHermiticity[#,complexify,complexifyF/.replF]&/@fullsol;
dfinfin=DateString[];
Print["End of the calculation. ",dfinfin];
Print["Complete matching calculation finished. It took "<>ToString[DateDifference[dini,dfinfin,{"Hour","Minute","Second"}]]];
Print["Now canonically normalizing the result"];
{finalfullsolcannor,gaugecouplingrenorm}=CanonicallyNormalize[finalfullsol,modelnameE,complexify];
Print["Now going to the physical basis"];
finalfullphys=GoToPhysicalBasis[finalfullsolcannor,modelnameE];
Global`MatchingResult={finalfullsol,finalfullsolcannor,finalfullphys,gaugecouplingrenorm};
Save[FileNameJoin[{modelnameF,"MatchingResult.dat"}],Global`MatchingResult];
Print["Now checking the results"];
CheckGreenSol[modelnameF,modelnameE,Evaluate[FilterRules[{opts},Options[CheckGreenSol]]]]
]


Options[CheckGreenSol]={Verbose->True};

CheckGreenSol[full_,eft_,opts:OptionsPattern[]]:=Block[{realpars,complexpars,complexify,dilist,groupdata,indranges,indi,mireplacegaugedata,mirunogauge,vars2one,hermiticitylist,finalruleordered,replacegaugedata,realparsF,complexparsF,complexifyF,dilistF,groupdataF,indrangesF,indiF,mireplacegaugedataF,mirunogaugeF,vars2oneF,hermiticitylistF,finalruleorderedF,replacegaugedataF,diE0,diF0,diF1,pars,problist,messloop,messamp,allparsF,replF,teoe,teof,ampdiff,diff,solgreen,listareplacesymmetry,listareplacesymmetryF},
If[!FileExistsQ[FileNameJoin[{full,"MatchingResult.dat"}]],
MatchModeltoEFT[full,eft]];
Get[FileNameJoin[{full,"MatchingResult.dat"}]];
solgreen=Global`MatchingResult[[1]];
{realpars,complexpars,complexify,dilist,groupdata,indranges,indi,mireplacegaugedata,mirunogauge,vars2one,{hermiticitylist,finalruleordered,replacegaugedata,listareplacesymmetry}}=InitializeModel[eft];
{realparsF,complexparsF,complexifyF,dilistF,groupdataF,indrangesF,indiF,mireplacegaugedataF,mirunogaugeF,vars2oneF,{hermiticitylistF,finalruleorderedF,replacegaugedataF,listareplacesymmetryF}}=InitializeModel[full];
allparsF=Join[ToExpression/@realparsF,ToExpression/@complexparsF,(ToExpression/@complexparsF)/.complexifyF];
replF=RenameOneLoopWC[allparsF];
listareplacesymmetryF=listareplacesymmetryF/.replF;
diE0=dilist[[1,1]];
diF0=dilistF[[1,1]];
If[Length[dilistF]==1,AppendTo[dilistF,
{Association[Normal[diF0]/.Rule[a_,b_List]:>Rule[a,{0,{}}]],{}}]];
diF1=dilistF[[2,1]];
pars=Keys[diE0];
problist={};
messloop="";
messamp="";
If[OptionValue[Verbose],
Print[Style[Dynamic[messloop],Large,Blue]];
Print[Style[Dynamic[messamp]]];
];
Do[
messloop=StringJoin@@{"Checking solution at ",ToString[iloop-1]," loops."};
Do[
messamp=StringJoin@@{"Checking amplitude ",StringRiffle[ToString/@pars[[cual]]]," (number ",ToString[cual]," out of ",ToString[Length[pars]],")"};
teoe=PrepareAmplitude[dilist[[1,1]][pars[[cual]]],indranges,mirunogauge,mireplacegaugedata,False];
teof=PrepareAmplitude[dilistF[[iloop,1]][pars[[cual]]],indrangesF,mirunogaugeF,mireplacegaugedataF,True]/.replF;
ampdiff=DummyZeroQ[#,listareplacesymmetryF]&/@Expand[Flatten[{teoe-teof}]/.solgreen[[iloop,1]]];
diff=DeleteCases[ampdiff,0];
If[Length[diff]>0,AppendTo[problist,{iloop,pars[[cual]],ampdiff}];Print["problems"];];
(*If[Length[diff]>0,res={Style["bad",Red],ampdiff},res=Style["good",Blue]];*)
,{cual,Length[pars]}],
{iloop,2}];
If[Length[problist]==0,If[OptionValue[Verbose],Print[Style["All cross-checks are OK!",Blue]];,Print["All cross-checks are OK!"];],If[OptionValue[Verbose],Print[Style["Some cross-checks failed!",Red]," Check ",FileNameJoin[{full,"MatchingProblems.dat"}]," for details."];,Print["Some cross-checks failed! Check ",FileNameJoin[{full,"MatchingProblems.dat"}]," for details."];]];
Global`problist=problist;
Save[FileNameJoin[{full,"MatchingProblems.dat"}],Global`problist];
]


CheckGreenSolOld[full_,eft_,solgreen_]:=Block[{realpars,complexpars,complexify,dilist,groupdata,indranges,indi,mireplacegaugedata,mirunogauge,vars2one,hermiticitylist,finalruleordered,replacegaugedata,realparsF,complexparsF,complexifyF,dilistF,groupdataF,indrangesF,indiF,mireplacegaugedataF,mirunogaugeF,vars2oneF,hermiticitylistF,finalruleorderedF,replacegaugedataF,diE0,diF0,diF1,pars,problist,messloop,messamp,allparsF,replF,teoe,teof,ampdiff,diff,listareplacesymmetry,listareplacesymmetryF},
{realpars,complexpars,complexify,dilist,groupdata,indranges,indi,mireplacegaugedata,mirunogauge,vars2one,{hermiticitylist,finalruleordered,replacegaugedata,listareplacesymmetry}}=InitializeModel[eft];
{realparsF,complexparsF,complexifyF,dilistF,groupdataF,indrangesF,indiF,mireplacegaugedataF,mirunogaugeF,vars2oneF,{hermiticitylistF,finalruleorderedF,replacegaugedataF,listareplacesymmetryF}}=InitializeModel[full];
allparsF=Join[ToExpression/@realparsF,ToExpression/@complexparsF,(ToExpression/@complexparsF)/.complexifyF];
replF=RenameOneLoopWC[allparsF];
diE0=dilist[[1,1]];
diF0=dilistF[[1,1]];
If[Length[dilistF]==1,AppendTo[dilistF,
{Association[Normal[diF0]/.Rule[a_,b_List]:>Rule[a,{0,{}}]],{}}]];
diF1=dilistF[[2,1]];
pars=Keys[diE0];
problist={};
messloop="";
messamp="";
Print[Style[Dynamic[messloop],Large,Blue]];
Print[Style[Dynamic[messamp]]];
Do[
messloop=StringJoin@@{"Checking solution at ",ToString[iloop-1]," loops."};
Do[
messamp=StringJoin@@{"Checking amplitude ",StringRiffle[ToString/@pars[[cual]]]," (number ",ToString[cual]," out of ",ToString[Length[pars]],")"};
teoe=PrepareAmplitude[dilist[[1,1]][pars[[cual]]],indranges,mirunogauge,mireplacegaugedata,False];
teof=PrepareAmplitude[dilistF[[iloop,1]][pars[[cual]]],indrangesF,mirunogaugeF,mireplacegaugedataF,True]/.replF;
ampdiff=DummyZeroQ/@Expand[Flatten[{teoe-teof}]/.solgreen[[iloop,1]]];
diff=DeleteCases[ampdiff,0];
If[Length[diff]>0,AppendTo[problist,{iloop,pars[[cual]],ampdiff}]];
(*If[Length[diff]>0,res={Style["bad",Red],ampdiff},res=Style["good",Blue]];*)
,{cual,Length[pars]}],
{iloop,2}];
If[Length[problist]==0,Print[Style["All cross-checks are OK!",Blue]];,Print[Style["Some cross-checks failed!",Red]];Print[problist]];
]


ComputeWilsonCoefficients[modelnameF_,modelnameE_]:=Block[{mes,mes2,realpars,complexpars,complexify,dilist,groupdata,indranges,indi,mireplacegaugedata,mirunogauge,vars2one,listhermiticity,listhermiticityF,finalruleordered,replacegaugedata,realparsF,complexparsF,complexifyF,dilistF,groupdataF,indrangesF,indiF,mireplacegaugedataF,mirunogaugeF,vars2oneF,finalruleorderedF,replacegaugedataF,diE,diF0,diF1,pars,allsols,dini,dfin,soltemp,sol,newsolbar,newsol,fullsol,allparsF,replF,soltemp2,finalfullsol,listareplacesymmetry,listareplacesymmetryF},
{realpars,complexpars,complexify,dilist,groupdata,indranges,indi,mireplacegaugedata,mirunogauge,vars2one,{listhermiticity,finalruleordered,replacegaugedata,listareplacesymmetry}}=InitializeModel[modelnameE];
{realparsF,complexparsF,complexifyF,dilistF,groupdataF,indrangesF,indiF,mireplacegaugedataF,mirunogaugeF,vars2oneF,{listhermiticityF,finalruleorderedF,replacegaugedataF,listareplacesymmetryF}}=InitializeModel[modelnameF];
allparsF=Join[ToExpression/@realparsF,ToExpression/@complexparsF,(ToExpression/@complexparsF)/.complexifyF];
replF=RenameOneLoopWC[allparsF];
diE=dilist[[1,1]];
diF0=dilistF[[1,1]];
diF1=dilistF[[2,1]];
pars=Keys[diE];
allsols={{},{}};
dini=DateString[];
mes=StringJoin@@{"We are matching ",modelnameF," onto ",modelnameE," at ","0"," loop level."};mes2=StringJoin@@{"Doing amplitude ","1"," out of ",ToString[Length[pars]]};
Print["Beginning of matching calculation. ",dini];
Print[Style[Dynamic[mes],Large,Blue]];Print[Style[Dynamic[mes2],Large,Red]];
Do[
Do[
(* For the eft we always take the finite part so we call PrepareAmplitude with UVPoles= False
For the full theory we take the UV pole or the finite part depending on UVPoles being true or false*)
(* We no longer use UVPole *)
mes=StringJoin@@{"We are matching ",modelnameF," onto ",modelnameE," at ",ToString[iloop-1]," loop level."};mes2=StringJoin@@{"Doing amplitude ",ToString[cual]," out of ",ToString[Length[pars]]};(*Print["iloop=",iloop,"  cual=",cual,"  ",pars[[cual]]];*)
soltemp=MatchOneAmplitude[PrepareAmplitude[dilist[[1,1]][pars[[cual]]],indranges,mirunogauge,mireplacegaugedata,False]-(PrepareAmplitude[dilistF[[iloop,1]][pars[[cual]]],indrangesF,mirunogaugeF,mireplacegaugedataF,UVPoles]/.replF),Join[vars2one,vars2oneF/.replF],Join[dilist[[1,2]],dilistF[[iloop,2]]]];
(*Print[soltemp];*)
soltemp2=Simplify[soltemp[[2]]];
If[!(Length[soltemp2]>=0&&Length[DeleteCases[soltemp2,0]]==0),Print["Something is wrong with amplitude ",StringReplace[ToString[pars[[cual]]],{"{"->"","}"->"",","->" "}]," at order ",ToString[iloop-1]," loops. ",soltemp2]]
AppendTo[allsols[[iloop]],soltemp[[1]]];
,{cual,1,Length[pars]}];
,{iloop,2}];
dfin=DateString[];
Print["End of matching calculation. ",dfin];
Print["Matching calculation finished. It took "<>ToString[DateDifference[dini,dfin,{"Hour","Minute","Second"}]]];
sol={Union[Flatten[allsols[[1]]]],Union[Flatten[allsols[[2]]]]};
newsolbar=Table[Table[(sol[[j,i,1]]/.Union[Join[complexify,complexifyF/.replF]])->TreatDummyFlavor[ComplexConjugate[sol[[j,i,2]],Union[Join[complexify,complexifyF/.replF]]]]/.(listhermiticityF/.replF),{i,Length[sol[[j]]]}],{j,Length[sol]}];
newsol=Table[Table[(sol[[j,i,1]])->TreatDummyFlavor[sol[[j,i,2]]],{i,Length[sol[[j]]]}],{j,Length[sol]}]/.(listhermiticityF/.replF);
(*Print[Union[Join[newsol[[2]],newsolbar[[2]]]]];*)
(*fullsol=Table[EliminateRepeated[Union[Join[newsol[[j]],newsolbar[[j]]]]],{j,Length[newsol]}];*)
(*Print["replacements1=",dilist[[1,2]]];
Print["replacements2=",Join[dilist[[1,2]],dilistF[[1,2]]]];
Print["replacements3=",Join[dilist[[1,2]],dilistF[[2,2]]]];*)
fullsol=Table[EliminateRepeated[Union[Join[newsol[[j]],newsolbar[[j]]]],Join[dilist[[1,2]],dilistF[[j,2]]]],{j,Length[newsol]}];
finalfullsol=ImposeHermiticity[#,complexify,complexifyF]&/@fullsol
]


Options[CheckWardIdentities]={FullCheck->False,Parallel->False};



CheckWardIdentities[modelname_,opts:OptionsPattern[]]:=Block[{WImodelname,WIeffdirlist,didiF,didiElist,commonkeys,ampe,ampf,res,errormessage,relevantdata,mireplacegaugedata,mirunogauge,diElist,diFlist,groupdata,indranges,indi,eftname,eftdim,looplevel,dini,dfin,allsols,allsols0,realpars,complexpars,complexify,tao,sol,newsol,newsolbar,fullsol,fullsolcanor,finalres,runogauge,finalresult,finalfullsol,finalfullsolcanor,yepa,listareplacesymmetry},
WImodelname=FileNameJoin[{modelname,"WI"}];
errormessage="";
If[!FileExistsQ[FileNameJoin[{modelname,"WilsonCoefficients.dat"}]],Print["You need to have matched the model before checking the Ward Identities"];
Return[]];
Get[FileNameJoin[{modelname,"WilsonCoefficients.dat"}]];
Off[Part::pkspec1];
{realpars,complexpars,complexify,diElist,diFlist,groupdata,indranges,indi,mireplacegaugedata,mirunogauge,listareplacesymmetry}=InitializeModel[WImodelname];
WIeffdirlist=Table[FileNameJoin[{$matchmakerpath,"models",$wieffdiranddimlist[[i,1]],"WI"}],{i,Length[$wieffdiranddimlist]}];
didiF=GetDictionary[WImodelname];
didiElist=Table[GetDictionary[WIeffdirlist[[i]]],{i,Length[WIeffdirlist]}];
Do[
Do[
commonkeys=Intersection[Keys[didiElist[[i,1]]],Keys[didiF[[j]]]];
Do[
ampe=didiElist[[i,1]][commonkeys[[k]]];
ampf=didiF[[j]][commonkeys[[k]]];
res=CheckOneAmplitude[Global`WilsonCoefficients[[1,j]],ampe,ampf,indranges,mirunogauge,mireplacegaugedata,commonkeys[[k]]];
If[Length[res]>0&&res!={0},
(*Print["i=",i," j=",j," k=",k];
Print["There's a problem with amplitude ",commonkeys[[k]]];
Print[res];
Print[];*)
errormessage=errormessage<>"There's a problem with amplitude "<>StringRiffle[commonkeys[[k]]]<>" at "<>ToString[j-1]<>" loop level \n";
Print[errormessage];
];
,{k,Length[commonkeys]}];
,{j,2}];
,{i,Length[didiElist]}];
If[errormessage!="",Export[FileNameJoin[{modelname,"WIoutput.txt"}],errormessage]];
(*
allsols={};
{realpars,complexpars,complexify,diElist,diFlist,groupdata,indranges,indi,mireplacegaugedata,mirunogauge}=InitializeModel[modelname];
eftname=ToString[$effdiranddimlist[[1,1]]];
eftdim=ToString[$effdiranddimlist[[1,2]]];
looplevel=ToString[0];
dini=DateString[];
iamp="0";allamp=ToString[Length[Flatten[Table[Intersection[Keys[diElist[[whicheft,1]]],Keys[diFlist[[1]]]],{whicheft,Length[diElist]}],1]]+Length[Flatten[Table[Intersection[Keys[diElist[[whicheft,1]]],Keys[diFlist[[2]]]],{whicheft,Length[diElist]}],1]]];Print["Beginning of the calculation: ",dini];relevantdata=Join[Flatten[Table[Join[{#},{whicheft,0}]&/@Intersection[Keys[diElist[[whicheft,1]]],Keys[diFlist[[1]]]],{whicheft,Length[diElist]}],1],Flatten[Table[Join[{#},{whicheft,1}]&/@Intersection[Keys[diElist[[whicheft,1]]],Keys[diFlist[[2]]]],{whicheft,Length[diElist]}],1]];If[OptionValue[Parallel],
DistributeDefinitions[{MatchOneAmplitude,GetLightScalarsFermionsVectors}];With[{relevantdatai=relevantdata,$effdiranddimlisti=$effdiranddimlist,diElisti=diElist,diFlisti=diFlist,mirunogaugei=mirunogauge,indrangesi=indranges,mireplacegaugedatai=mireplacegaugedata},
allsols=Partition[ParallelTable[
eftname=ToString[$effdiranddimlisti[[relevantdatai[[iiixxx,2]],1]]];
eftdim=ToString[$effdiranddimlisti[[relevantdatai[[iiixxx,2]],2]]];
looplevel=ToString[relevantdatai[[iiixxx,3]]];mes=StringJoin@@{"We are doing ",eftname," at dimension ",eftdim," and ",looplevel," loop level"};MatchOneAmplitude[diElisti[[relevantdatai[[iiixxx,2]],1]],diFlisti[[relevantdatai[[iiixxx,3]]+1]],relevantdatai[[iiixxx,1]],$effdiranddimlisti[[relevantdatai[[iiixxx,2]],2]],indrangesi,mireplacegaugedatai,Global`kinematicdir[$effdiranddimlisti[[relevantdatai[[iiixxx,2]],1]]][relevantdatai[[iiixxx,1]]],mirunogaugei,GetLightScalarsFermionsVectors[modelname],Evaluate[FilterRules[{opts},Options[MatchOneAmplitude]]]]
,{iiixxx,Length[relevantdatai]}],Length[relevantdatai]/2];];
,
allsols=Partition[Table[
eftname=ToString[$effdiranddimlist[[relevantdata[[iiixxx,2]],1]]];
eftdim=ToString[$effdiranddimlist[[relevantdata[[iiixxx,2]],2]]];
looplevel=ToString[relevantdata[[iiixxx,3]]];
iamp=ToString[ToExpression[iamp]+1];
mes=StringJoin@@{"We are doing ",eftname," at dimension ",eftdim," and ",looplevel," loop level"};
mes2=StringJoin@@{"Doing amplitude ",iamp," out of ",allamp,": ",StringReplace[ToString[relevantdata[[iiixxx,1]]],{"{"\[Rule]"","}"\[Rule]"",","\[Rule]" "}]};
(*Print[mes,mes2];*)
MatchOneAmplitude[diElist[[relevantdata[[iiixxx,2]],1]][relevantdata[[iiixxx,1]]],diFlist[[relevantdata[[iiixxx,3]]+1]][relevantdata[[iiixxx,1]]],indranges,mirunogauge,mireplacegaugedata,Global`kinematicdir[$effdiranddimlist[[relevantdata[[iiixxx,2]],1]]][relevantdata[[iiixxx,1]]],relevantdata[[iiixxx,1]]]
,{iiixxx,Length[relevantdata]}],Length[relevantdata]/2];
(*,{iiixxx,91,92+0*Length[relevantdata]}],2+0*Length[relevantdata]/2];*)
];
On[Part::pkspec1];sol={Union[Flatten[allsols[[1]]]],Union[Flatten[allsols[[2]]]]};newsolbar=Table[Table[(sol[[j,i,1]]/.complexify)->TreatDummyFlavor[ComplexConjugate[sol[[j,i,2]],complexify]],{i,Length[sol[[j]]]}],{j,Length[sol]}];newsol=Table[Table[(sol[[j,i,1]])->TreatDummyFlavor[sol[[j,i,2]]],{i,Length[sol[[j]]]}],{j,Length[sol]}];fullsol=Table[EliminateRepeated[Union[Join[newsol[[j]],newsolbar[[j]]]]],{j,Length[newsol]}];
fullsolcanor=CanonicallyNormalize[fullsol[[1]],fullsol[[2]]];finalres={Global`finalruleordered/.{Global`mif1\[Rule]Global`f1,Global`mif2\[Rule]Global`f2,Global`mif3\[Rule]Global`f3,Global`mif4\[Rule]Global`f4}/.fullsolcanor[[1]]/.noSpuriousE/.WCxfnames/.WCxfnamesbar,Global`finalruleordered/.{Global`mif1\[Rule]Global`f1,Global`mif2\[Rule]Global`f2,Global`mif3\[Rule]Global`f3,Global`mif4\[Rule]Global`f4}/.fullsolcanor[[2]]/.noSpuriousE/.WCxfnames/.WCxfnamesbar};
(* We use this to add the effect of the one-loop SM parameters in the EoM to implement the redundancies *)
yepa=(EliminateSelfFromRule/@Global`finalruleordered)/.{Global`mif1\[Rule]Global`f1,Global`mif2\[Rule]Global`f2,Global`mif3\[Rule]Global`f3,Global`mif4\[Rule]Global`f4,Global`mif5\[Rule]Global`f5,Global`mif6\[Rule]Global`f6,Global`mif7\[Rule]Global`f7,Global`mif8\[Rule]Global`f8}/.Global`SMreplacement/.finalres[[2]]/.fullsolcanor[[1]];
dfin=DateString[];
(*finalres[[2]]=AddToListOfRules[finalres[[2]],yepa];*)
Print["End of matching calculation. ",dfin];
mes="Matching calculation finished. It took "<>ToString[DateDifference[dini,dfin,{"Hour","Minute","Second"}]];
Print[mes];
(*{fullsol,fullsolcanor,finalres}*)
(*Save[FileNameJoin[{modelname,"WilsonCoefficients.dat"}],{fullsol,fullsolcanor,finalres}];*)
(*{fullsol,fullsolcanor,{finalres[[1]],AddToListOfRules[finalres[[2]],yepa]},{finalres[[1]],{finalres[[2]],yepa}}}*)
{fullsol,fullsolcanor,{finalres[[1]],AddToListOfRules[finalres[[2]],yepa]}}/.Rule[a_,b_]:>Rule[a,TreatDummyFlavorGeneral[b,{"fl","f"}]]
*)];


PrettyShow[x_]:=x/.InverseWCxfnames/.InverseWCxfnamesbar/.prettynames/.prettynamesbar


SimpleShow[x_]:=Block[{i,j,a},
Table[Select[DeleteCases[x[[i,j]],a_->0],!StringContainsQ[ToString[#[[1]]],"bar"]&],{i,Length[x]},{j,Length[x[[1]]]}]];



End[]


EndPackage[]
