I just wonder which part of xTensor that takes so long time for you that
you have to parallelize.
Is it MakeRule, or is it many things?
I myself have problems with MakeRule took long time when I had
expressions with many indices with a lot of contractions and symmetries.
This was because very many rules had to be generated. I wrote a new
MakeCompareRule that generates only one rule that cares about the index
configuration only at "apply time". With this I managed to cut my
computational time for some things 100 times or so. It is still not very
well written, and my current implementation can only handle tensors or
product of tensors in the left hand side. I will have to write something
more to handle derivatives, but this can be done.
I am happy to post the code if you think this could solve some of your
problems.
Still it would be very nice if everything can be parallelized anyway.
Regards
Thomas
Here I post the code for my MakeCompareRule, even though this thread
might not be the right place for this.
It is unfortunately not well written and is a bit complicated.
It is based on EqualExpressionsQ to determine if two tensor expressions
are equal if one would change the indices.
SpecialEqualExpressionsQ does basically the same thing as
EqualExpressionsQ, but it also gives information about how expr1 and
expr2 are related. (sign changes, index changes etc.) I think this code
can be improved a bit, but I have not looked at it in a while.
SpecialEqualExpressionsQ[expr1_, expr2_] :=
Module[{inds1, frees1, frees2, dummies1, dummies2, sortedfrees2,
dummies1slots, frees1slots, slotrules1, expr1SGS, stabilizerGS,
transversal1, indstoslotnumbers, freesym1, perms1, arrexpr2,
newexpr2,
count, result = False, perm = {}, xxx, equation,
solution = 0},
(* Indices of expr1 *)
inds1 = FindIndices[expr1];
dummies1 = List @@ xAct`xTensor`Private`TakeEPairs@inds1;
frees1 = List @@ xAct`xTensor`Private`TakeFrees@inds1;
(* Indices of expr2 *)
{frees2, dummies2} =
List @@ xAct`xTensor`Private`FindFreeAndDummyIndices[expr2];
If[Length[frees1] == Length[frees2],
sortedfrees2 = List @@ IndexSort[frees2];
dummies2 = List @@ dummies2;
inds1 = List @@ inds1;
{slotrules1, expr1SGS} = List @@ Take[SymmetryOf@expr1, -2];
indstoslotnumbers = (Reverse /@ slotrules1) /.
xAct`xTensor`Private`slot[x_] -> x;
dummies1slots = dummies1 /. indstoslotnumbers;
frees1slots = frees1 /. indstoslotnumbers;
xAct`xTensor`Private`checkChangeFreeIndices[frees1, sortedfrees2];
(* Computing permutations of the free indices of expr1 *)
(* One coud use perms1=Permutations[List@@frees1],
but this can be reduced by considering the symmetries of the \
free indices of expr1 *)
(* The stabilizer of the dummies for the symmetry of expr1 gives \
a subset of the symmetry on dummies1.
The numbers in the group correspond to the position of the index \
in frees1. *)
stabilizerGS =
Stabilizer[dummies1slots, Last@expr1SGS] /.
Thread@Rule[frees1slots, Range@Length@frees1];
(* If the stabilizer is trivial, we will have all permutations. *)
If[Length@stabilizerGS == 0,
perms1 = Permutations[List @@ frees1],
(* The code for the transversal is probably not optimal. *)
transversal1 = RightTransversal[stabilizerGS, Length@frees1];
(* Translate this to permutations of the same kind as \
Permutations[List@@frees1] gives. *)
perms1 =
TranslatePerm[transversal1, {Perm, Length@frees1}] /.
Perm[{x___}] -> {x} /.
Thread@Rule[Range@Length@frees1, frees1];
];
(* Remove collisions between frees1 and dummies2 *)
arrexpr2 =
xAct`xTensor`Private`arrangedummies[expr2, dummies2, frees1];
DefConstantSymbol[xxx, DefInfo -> False];
Do[
newexpr2 =
xAct`xTensor`Private`changeFreeIndices[arrexpr2, sortedfrees2,
perms1[[count]]];
equation = ToCanonical[expr1 - xxx newexpr2];
solution = First[xxx /. Solve[equation == 0, xxx]];
If[ConstantQ[solution], result = True;
perm = Inner[Rule, perms1[[count]], sortedfrees2, List];
Break[]],
{count, Length[perms1]}]];
{result, solution, sortedfrees2, perm}
];
SetNumberOfArguments[SpecialEqualExpressionsQ, 2];
Protect[SpecialEqualExpressionsQ];
Make a rule that looks for a tensors and replaces it with a properly
reformulated RHS, if tensora[indsa] is equal to tensora[indsaeq].
The expressions are compared with SpecialEqualExpressionsQ
SetAttributes[MakeCompareRule, HoldFirst];
For a single tensor:
MakeCompareRule[{tensora_?xTensorQ[indsaeq___], RHS_}, ___] :=
With[{dummieseq = xAct`xTensor`Private`TakeEPairs[{indsaeq}]},
With[{numdummiesaeq = Length@Intersection[dummieseq, {indsaeq}]},
RuleDelayed[tensora[indsa___],
With[{dummies = xAct`xTensor`Private`TakeEPairs[{indsa}],
frees = xAct`xTensor`Private`TakeFrees[{indsa}]},
Module[{equalexpr, sign, sortedfrees,
perm}, {equalexpr, sign, sortedfrees, perm} =
SpecialEqualExpressionsQ[tensora[indsaeq], tensora[indsa]];
With[{arrexpr2 = ReplaceDummies[RHS]}, (sign*arrexpr2 /. perm)] /;
equalexpr] /;
Length@Intersection[dummies, {indsa}] == numdummiesaeq]]]]
A similar thing for a product of tensors:
MakeCompareRule[{LHS : Times[_?xTensorQ[___], _?xTensorQ[___] ...],
RHS_}, ___] :=
With[{indslist =
ToExpression[StringJoin["tinds", ToString[#]] & /@ Range[Length@LHS]]},
With[{rulelhs = MapIndexed[#1[[0]][First@indslist[[#2]]] &, LHS],
rulelhspattern =
MapIndexed[#1[[0]][
With[{patterninds = First@indslist[[#2]]},
Pattern[patterninds, BlankNullSequence[]]]] &, LHS]},
RuleDelayed[rulelhspattern,
With[{rulelhsinds = FindIndices[rulelhs]},
With[{dummieslhs = xAct`xTensor`Private`TakeEPairs[rulelhsinds],
freeslhs = xAct`xTensor`Private`TakeFrees[rulelhsinds]},
Module[{equalexpr, sign, sortedfrees,
perm}, {equalexpr, sign, sortedfrees, perm} =
SpecialEqualExpressionsQ[LHS, rulelhs];
Module[{arrexpr2 = ReplaceDummies[RHS]}, (sign*arrexpr2 /.
perm)] /;
equalexpr]]]]]]
A code that handles derivatives is missing. I should probably write that
some time.
ApplyCompareRule is used to make rules from equations.
ApplyCompareRule[expr_] := MakeCompareRule[Evaluate[List @@ expr]]
Please tell me if you find the code useful.
Regards
Thomas B�ckdahl
On 2012-02-24 20:45, Edu Serna wrote:
> Hi Thomas,
>
> I doubt my MakeRules are there the problem as I mostly replace the
> contraction of two vectors with scalar quantities (I imagine i could
> write my own cheaper rules but I doubt its worth the effort) as I
> calculate scattering amplitudes. The thing is just that my expressions
> are VERY long (hundreds of thousands of terms) so I need to do it in
> parallel.
>
> I would like to see that code just to see how you did it but I doubt
> that is my problem
>
> Thanks so much anyways.
>
>
> 1) First use Expand[ texpr ] if there are nonexpanded products of sums
> of tensors.
> 2) Use SameDummies on the result of 1). This will try to simplify the
> expression by minimizing the number of different dummies, without
> actually calling group-theoretical algorithms.
> 3) Map ToCanonical to each term, or use a Do loop to monitor timings
> of individual canonicalizations. If the result is much smaller than
> the input, it might be useful to add intermediate results to an
> accumulator variable, instead of doing a big sum at the end.
It is very important, in item 3, when using a Do loop (which seems to be less
memory consuming in general), to store the result of ToCanonical acting on
each term into a list, and not a Plus-type expression. Indeed, the command
Plus tries to perform operations that can take time (reordering, flattening,
etc.) if a sum is very lengthy. It is thus much more efficient not to add
canonicalized terms to partials sum at each step, but to achieve the summation
only at the end.
I also advise to prepare the expressions with as many Scalar as possible.
For very long sums of monomials made of a lot of factors, this can make the
computation less memory consuming, specially when the tensors that are involved
in the expressions have only one or two indices (scalar products of vectors).
Using the strategy proposed by José María and the two tricks described above,
I can manipulate hundreds of thousand tensorial terms in a few minutes. I need
to make parallel computation only when I have to apply to each term of my sum
a very time consuming operation (typically an integration).
Yours,
Guillaume.
>
> using /.MakeRule[{v1[a] v1[-a], Scalar1[] }, MetricOn -> All,
> ContractMetrics -> True];
>
> so that my term end up something like
>
> Scalar1[].. ScalarN[] vi[m] vj[n]
>
> I was wondering whether I should do
This is a possible solution. You may also want to use the general command
PutScalar to introduce Scalar objects. It is worthy when your monomials
involve factors Scalar1[]^q1 ... ScalarN[]^qn with q1, ... or qn much greater
than 1. You may alternatively prefer having your own faster version of
PutScalar specifically adapted to your problem (I chose the latter approach).
>
>> 2) Use SameDummies on the result of 1). This will try to simplify the
>> expression by minimizing the number of different dummies, without
>> actually calling group-theoretical algorithms.
As for me, I combine both strategies (Scalar approach + avoiding to use
ToCanonical except at the very final stage, if needed). This makes my
computations *at least* twice faster (for lengthy expressions). [The time
reduction factor can be significantly greater than 2.]
Yours,
Guillaume.
--
You received this message because you are subscribed to the Google Groups "xAct Tensor Computer Algebra" group.
To unsubscribe from this group and stop receiving emails from it, send an email to xact+uns...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.