1,197 views

Skip to first unread message

Oct 14, 2011, 2:56:58 PM10/14/11

to xAct Tensor Computer Algebra

Hi all,

I ran into some unexpected behaviour with MakeRule and repeated

dummies today, and decided to share my findings. Consider this code:

=====

(* Define manifold and metric *)

DefManifold[M, 4, IndexRange[a, l]]

DefMetric[-1, metric[-a, -b], CD]

(* Define tensor for which we'll make rules *)

DefTensor[T[-a, -b], M]

DefTensor[S[], M]

(* Make two rules sending S to the same combination of T's *)

LHS = S[]

goodRHS = T[-a, -b] T[a, b] + T[-c, c] T[-d, d] // Validate

goodRule = MakeRule[Evaluate[{LHS,goodRHS}]]

wrongRHS = T[-a, -b] T[a, b] + T[-a, a] T[-b, b] // Validate

wrongRule= MakeRule[Evaluate[{LHS,wrongRHS}]]

(* Applying the wrong rule gives repeated dummy indices xAct can't

handle *)

S[] S[] /. wrongRule // Simplification

(* Applying the good rule works as expected *)

S[] S[] /. goodRule // Simplification

=====

The point is that, to be on the safe side, it's better to make rules

for tensors that have a different symbol for every dummy pair in the

RHS. Note that

MakeRule[Evaluate[{LHS, ReplaceDummies[wrongRHS]}]]

also doesn't produce a good rule, because ReplaceDummies replaces the

pairs of identical dummies in wrongRHS with a new set of identical

pairs.

Jose, can ReplaceDummies be updated to work as (I) expected in this

case, i.e. treat sums a bit differently? And if updated, should it be

used automatically in MakeRule, or should we let the user worry about

this?

Best,

Teake Nutma

I ran into some unexpected behaviour with MakeRule and repeated

dummies today, and decided to share my findings. Consider this code:

=====

(* Define manifold and metric *)

DefManifold[M, 4, IndexRange[a, l]]

DefMetric[-1, metric[-a, -b], CD]

(* Define tensor for which we'll make rules *)

DefTensor[T[-a, -b], M]

DefTensor[S[], M]

(* Make two rules sending S to the same combination of T's *)

LHS = S[]

goodRHS = T[-a, -b] T[a, b] + T[-c, c] T[-d, d] // Validate

goodRule = MakeRule[Evaluate[{LHS,goodRHS}]]

wrongRHS = T[-a, -b] T[a, b] + T[-a, a] T[-b, b] // Validate

wrongRule= MakeRule[Evaluate[{LHS,wrongRHS}]]

(* Applying the wrong rule gives repeated dummy indices xAct can't

handle *)

S[] S[] /. wrongRule // Simplification

(* Applying the good rule works as expected *)

S[] S[] /. goodRule // Simplification

=====

The point is that, to be on the safe side, it's better to make rules

for tensors that have a different symbol for every dummy pair in the

RHS. Note that

MakeRule[Evaluate[{LHS, ReplaceDummies[wrongRHS]}]]

also doesn't produce a good rule, because ReplaceDummies replaces the

pairs of identical dummies in wrongRHS with a new set of identical

pairs.

Jose, can ReplaceDummies be updated to work as (I) expected in this

case, i.e. treat sums a bit differently? And if updated, should it be

used automatically in MakeRule, or should we let the user worry about

this?

Best,

Teake Nutma

Oct 14, 2011, 7:44:58 PM10/14/11

to xAct Tensor Computer Algebra

Hi Teake,

Thanks for the example. There is an issue here, but it is not what you

think it is. The problem is the following:

You start with the expression

S[] S[]

and then apply the rules. However, before the rules are applied,

Mathematica has already transformed that product into

S[]^2

Therefore when you replace S[] by a tensorial expression with indices

you are effectively writing something like T[a,-a]^2, which is

syntactically incorrect because it is equivalent to T[a,-a] T[a,-a].

There is an easy solution for this type of issue: wrap the tensorial

expressions with Scalar. That is, change your wrongRHS to

wrongRHS = Scalar[ T[-a, -b] T[a, b] + T[-a, a] T[-b, b] ]

and then everything should work fine. After performing the

replacement, you can get rid of the Scalar head using NoScalar:

S[] S[] /. wrongRule // NoScalar // Simplification

Concerning your suggestion, having ReplaceDummies in the RHS of a rule

would be redundant: that is precisely what the Module is for.

Cheers,

Jose.

Thanks for the example. There is an issue here, but it is not what you

think it is. The problem is the following:

You start with the expression

S[] S[]

and then apply the rules. However, before the rules are applied,

Mathematica has already transformed that product into

S[]^2

Therefore when you replace S[] by a tensorial expression with indices

you are effectively writing something like T[a,-a]^2, which is

syntactically incorrect because it is equivalent to T[a,-a] T[a,-a].

There is an easy solution for this type of issue: wrap the tensorial

expressions with Scalar. That is, change your wrongRHS to

wrongRHS = Scalar[ T[-a, -b] T[a, b] + T[-a, a] T[-b, b] ]

and then everything should work fine. After performing the

replacement, you can get rid of the Scalar head using NoScalar:

S[] S[] /. wrongRule // NoScalar // Simplification

Concerning your suggestion, having ReplaceDummies in the RHS of a rule

would be redundant: that is precisely what the Module is for.

Cheers,

Jose.

Oct 15, 2011, 3:15:50 AM10/15/11

to xAct Tensor Computer Algebra

Hi Jose,

Thanks for the reply! Let me try to recap what you said:

* The Module in the rule takes care of repeated dummy indices (because

for every replacement it generates a new one).

* This only fails if Mathematica rewrites two tensors as one

expression.

* But this only happens for products of identical scalars, for which

the above problem can be circumvented with a PutScalar.

In my example, an 'good' RHS can also be obtained by doing

NoScalar[PutScalar[wrongRHS]]. I'm guessing this equivalent to keeping

the Scalar head in the rule and getting rid of it after replacement,

right?

There's still one thing that bugs me about this issue, and that's the

fact that Validate doesn't approve of repeated indices on different

tensors, but does of repeated indices on identical tensors:

U[-a, -b, b] + T[b, -b] // Validate (* problem *)

U[-a, -b, b] + U[b, -b, -a] // Validate (* ok *)

Normally I wouldn't write down either one of those two lines, and

would like to see Validate reject them both. Is there a reason why the

last line is accepted?

Cheers,

Teake

Thanks for the reply! Let me try to recap what you said:

* The Module in the rule takes care of repeated dummy indices (because

for every replacement it generates a new one).

* This only fails if Mathematica rewrites two tensors as one

expression.

* But this only happens for products of identical scalars, for which

the above problem can be circumvented with a PutScalar.

In my example, an 'good' RHS can also be obtained by doing

NoScalar[PutScalar[wrongRHS]]. I'm guessing this equivalent to keeping

the Scalar head in the rule and getting rid of it after replacement,

right?

There's still one thing that bugs me about this issue, and that's the

fact that Validate doesn't approve of repeated indices on different

tensors, but does of repeated indices on identical tensors:

U[-a, -b, b] + T[b, -b] // Validate (* problem *)

U[-a, -b, b] + U[b, -b, -a] // Validate (* ok *)

Normally I wouldn't write down either one of those two lines, and

would like to see Validate reject them both. Is there a reason why the

last line is accepted?

Cheers,

Teake

Oct 15, 2011, 6:13:57 AM10/15/11

to JMM, xAct Tensor Computer Algebra

On a related note, the same type of problem arises with

RicciScalarCD[]^2 // ChangeCurvature

or the old RiemannToChristoffel. This can be fixed by modifying

changeRicciScalar in Sec. 11.1.6, 4c) of xTensor.nb. It would read:

changeRicciScalar[covd1_, covd2_, metricofcovd1_][] :=

Module[{a = DummyIn[TangentBundleOfCovD[covd1]],

b = DummyIn[TangentBundleOfCovD[covd1]]},

Scalar[ Inv[metricofcovd1][a, b] changeRicci[covd1, covd2,

HELLO][-a, -b] ] ];

RicciScalarCD[]^2 // ChangeCurvature

or the old RiemannToChristoffel. This can be fixed by modifying

changeRicciScalar in Sec. 11.1.6, 4c) of xTensor.nb. It would read:

changeRicciScalar[covd1_, covd2_, metricofcovd1_][] :=

Module[{a = DummyIn[TangentBundleOfCovD[covd1]],

b = DummyIn[TangentBundleOfCovD[covd1]]},

Scalar[ Inv[metricofcovd1][a, b] changeRicci[covd1, covd2,

HELLO][-a, -b] ] ];

Best,

Leo

Oct 15, 2011, 11:01:07 AM10/15/11

to xAct Tensor Computer Algebra

Hi again Teake,

> Thanks for the reply! Let me try to recap what you said:

>

> * The Module in the rule takes care of repeated dummy indices (because

> for every replacement it generates a new one).

We have to be more precise here. The Module is there to avoid what I

call "dummy collisions": If you start with a syntactically correct

product of two tensors (scalars or not) and you replace both of them

by expressions containing dummy indices then it might happen that you

end up with a tensor product with a repeated pair of dummy, say T[a,-

a] U[a,-a]. That is a dummy collision and must be avoided. The way

this works in xTensor is by producing a new dummy index any time that

a rule dealing with dummies is used. This is done by abusing Module to

produce b$12031 from b, with a different number in each call. Execute

this line in Mathematica:

{ a, a } /. a :> Module[ { b }, b ]

The important thing there is not that we change a to b, but that b has

a different number after the dollar each time the rule is used.

Now, concerning "index repetition", let also try to fix the terms of

the discussion:

1) The expression T[ a, -a ] does not contain repeated indices. The

indices a and -a are different, but they both form a dummy pair.

2) The expression T[ a, -a ] + U[ a, -a ] does not contain repeated

indices, and it is perfectly syntactically correct. Dummies in

different terms of a sum are independent. The danger of collision is

always in the products (and in the powers, which represent products).

3) The expression T[ a, a, b, -b ] contains repeated free indices. It

is syntactically incorrect.

4) The expression T[ a, -a, b ] U[ a, -a, c ] contains repeated dummy

indices (a dummy collision). It is syntactically incorrect.

> * This only fails if Mathematica rewrites two tensors as one

> expression.

I don't understand such very general statement. There is nothing wrong

in Mathematica converting S[] S[] into S[]^2, or S[] + S[] into 2 S[].

Mathematica is an eager evaluator and will try to advance your

computation as much as possible as soon as possible. That is a very

good thing in general, and xTensor follows that principle as well.

However, there is the (unrelated) issue of using rules scalar ->

tensor_with_dummies on products and powers, and there xTensor is

designed so that the user has to decide whether to use Scalar or not.

Perhaps MakeRule or even IndexRule should send a warning message

reporting the fact that such rules might be dangerous in some

scenarios.

> * But this only happens for products of identical scalars, for which

> the above problem can be circumvented with a PutScalar.

Scalar is a general solution to a more general problem. Scalar fully

shields dummies so that the expression Scalar[ v[a] v[-a] ] can be

treated as s[]. Think for example of the expression 1 / (1 + s[] ) and

now try to replace s[] by v[a]v[-a]. Suddenly we find dummies in a

denominator, and that might confuse xTensor quite seriously. Imagine

an operation like (T[b, -a] v[a] ) / ( v[a] v[-a ] ) in which both

numerator and denominator are well defined, but Mathematica is going

to destroy that expression immediately. If you wrap the denominator

with Scalar, then it works fine.

> In my example, an 'good' RHS can also be obtained by doing

> NoScalar[PutScalar[wrongRHS]]. I'm guessing this equivalent to keeping

> the Scalar head in the rule and getting rid of it after replacement,

> right?

Not really. The Scalar head must be there at the moment of using the

rule. That is, PutScalar must be used before using the rule and

NoScalar must be used after using the rule. If you are telling me that

both PutScalar and NoScalar are in the delayed RHS of the rule (i.e.

inside the Module) then it might also work, but it is unnecessarily

complicated.

> There's still one thing that bugs me about this issue, and that's the

> fact that Validate doesn't approve of repeated indices on different

> tensors, but does of repeated indices on identical tensors:

>

> U[-a, -b, b] + T[b, -b] // Validate (* problem *)

Isn't this a problem because the free indices are inhomogeneous? I

mean, change T[b,-b] to T[b,-b,-a] and it should work, as I said

above. Are you working with any graded algebra allowing addition of

tensors of different ranks? xTensor does not support such a thing.

> U[-a, -b, b] + U[b, -b, -a] // Validate (* ok *)

>

> Normally I wouldn't write down either one of those two lines, and

> would like to see Validate reject them both. Is there a reason why the

> last line is accepted?

The last line is perfectly OK, assuming your vector space has a

metric. Sums are never a problem with dummies.

Cheers,

Jose.

> Thanks for the reply! Let me try to recap what you said:

>

> * The Module in the rule takes care of repeated dummy indices (because

> for every replacement it generates a new one).

call "dummy collisions": If you start with a syntactically correct

product of two tensors (scalars or not) and you replace both of them

by expressions containing dummy indices then it might happen that you

end up with a tensor product with a repeated pair of dummy, say T[a,-

a] U[a,-a]. That is a dummy collision and must be avoided. The way

this works in xTensor is by producing a new dummy index any time that

a rule dealing with dummies is used. This is done by abusing Module to

produce b$12031 from b, with a different number in each call. Execute

this line in Mathematica:

{ a, a } /. a :> Module[ { b }, b ]

The important thing there is not that we change a to b, but that b has

a different number after the dollar each time the rule is used.

Now, concerning "index repetition", let also try to fix the terms of

the discussion:

1) The expression T[ a, -a ] does not contain repeated indices. The

indices a and -a are different, but they both form a dummy pair.

2) The expression T[ a, -a ] + U[ a, -a ] does not contain repeated

indices, and it is perfectly syntactically correct. Dummies in

different terms of a sum are independent. The danger of collision is

always in the products (and in the powers, which represent products).

3) The expression T[ a, a, b, -b ] contains repeated free indices. It

is syntactically incorrect.

4) The expression T[ a, -a, b ] U[ a, -a, c ] contains repeated dummy

indices (a dummy collision). It is syntactically incorrect.

> * This only fails if Mathematica rewrites two tensors as one

> expression.

in Mathematica converting S[] S[] into S[]^2, or S[] + S[] into 2 S[].

Mathematica is an eager evaluator and will try to advance your

computation as much as possible as soon as possible. That is a very

good thing in general, and xTensor follows that principle as well.

However, there is the (unrelated) issue of using rules scalar ->

tensor_with_dummies on products and powers, and there xTensor is

designed so that the user has to decide whether to use Scalar or not.

Perhaps MakeRule or even IndexRule should send a warning message

reporting the fact that such rules might be dangerous in some

scenarios.

> * But this only happens for products of identical scalars, for which

> the above problem can be circumvented with a PutScalar.

shields dummies so that the expression Scalar[ v[a] v[-a] ] can be

treated as s[]. Think for example of the expression 1 / (1 + s[] ) and

now try to replace s[] by v[a]v[-a]. Suddenly we find dummies in a

denominator, and that might confuse xTensor quite seriously. Imagine

an operation like (T[b, -a] v[a] ) / ( v[a] v[-a ] ) in which both

numerator and denominator are well defined, but Mathematica is going

to destroy that expression immediately. If you wrap the denominator

with Scalar, then it works fine.

> In my example, an 'good' RHS can also be obtained by doing

> NoScalar[PutScalar[wrongRHS]]. I'm guessing this equivalent to keeping

> the Scalar head in the rule and getting rid of it after replacement,

> right?

rule. That is, PutScalar must be used before using the rule and

NoScalar must be used after using the rule. If you are telling me that

both PutScalar and NoScalar are in the delayed RHS of the rule (i.e.

inside the Module) then it might also work, but it is unnecessarily

complicated.

> There's still one thing that bugs me about this issue, and that's the

> fact that Validate doesn't approve of repeated indices on different

> tensors, but does of repeated indices on identical tensors:

>

> U[-a, -b, b] + T[b, -b] // Validate (* problem *)

mean, change T[b,-b] to T[b,-b,-a] and it should work, as I said

above. Are you working with any graded algebra allowing addition of

tensors of different ranks? xTensor does not support such a thing.

> U[-a, -b, b] + U[b, -b, -a] // Validate (* ok *)

>

> Normally I wouldn't write down either one of those two lines, and

> would like to see Validate reject them both. Is there a reason why the

> last line is accepted?

metric. Sums are never a problem with dummies.

Cheers,

Jose.

Oct 15, 2011, 11:07:55 AM10/15/11

to xAct Tensor Computer Algebra

Thanks Leo,

Yes. This is a good example of a rule scalar_without_indices :>

scalar_with_indices, and needs Scalar on the RHS to make it safe in

all scenarios.

Will be fixed in the next version.

Thanks again,

Jose.

Yes. This is a good example of a rule scalar_without_indices :>

scalar_with_indices, and needs Scalar on the RHS to make it safe in

all scenarios.

Will be fixed in the next version.

Thanks again,

Jose.

Oct 15, 2011, 11:54:25 AM10/15/11

to xAct Tensor Computer Algebra

Hi Jose,

Thanks for the clarifications.

> However, there is the (unrelated) issue of using rules scalar ->

> tensor_with_dummies on products and powers, and there xTensor is

> designed so that the user has to decide whether to use Scalar or not.

> Perhaps MakeRule or even IndexRule should send a warning message

> reporting the fact that such rules might be dangerous in some

> scenarios.

A warning would be nice, that would have saved me some trouble. But

why not be on the safe side and automatically put a Scalar in

MakeRule[{lhs_without_indices,rhs_with_indices}]?

>> U[-a, -b, b] + T[b, -b] // Validate (* problem *)

>

> Isn't this a problem because the free indices are inhomogeneous?

Yes, that was a typo. Doh.

Btw, my solution to this problem was

MakeRule[Evaluate[{

lhs_without_indices,

rhs_with_indices /. x_Plus :> ReplaceDummies /@ x

}]

and it seems to work fine. But I guess the PutScalar / NoScalar is a

bit more elegant.

Cheers,

Teake

Oct 15, 2011, 12:55:14 PM10/15/11

to xAct Tensor Computer Algebra

> A warning would be nice, that would have saved me some trouble. But

> why not be on the safe side and automatically put a Scalar in

> MakeRule[{lhs_without_indices,rhs_with_indices}]?

That is not the only case in which Scalar is needed. I have mentioned
> why not be on the safe side and automatically put a Scalar in

> MakeRule[{lhs_without_indices,rhs_with_indices}]?

problems with denominators. Imagine you are working with logarithms of

scalars and at some point you want to convert the sum of logarithms

into a logarithm of the product. Again you might run into dummy

collisions. Think of any expression of the form function[ scalar ] and

now you differentiate it with your own derivative operator using the

chain rule. More possible dummy collisions. There are many different

cases in which Scalar could be needed. It is impossible that MakeRule

is able to detect all of them and introduce Scalar where it is needed.

I never like partial solutions to problems, because they are

misleading. "Use Scalar wherever needed" is a general solution.

> Btw, my solution to this problem was

>

> MakeRule[Evaluate[{

> lhs_without_indices,

> rhs_with_indices /. x_Plus :> ReplaceDummies /@ x

>

> }]

>

> and it seems to work fine. But I guess the PutScalar / NoScalar is a

> bit more elegant.

Plus. As I said, the problem is not related to Plus. Think of this

example:

S[]^2 /. MakeRule[ { S[], T[a,-a] } }

Cheers,

Jose.

Oct 15, 2011, 2:35:07 PM10/15/11

to xAct Tensor Computer Algebra

> I never like partial solutions to problems, because they are

> misleading. "Use Scalar wherever needed" is a general solution.

Point taken. But then the user must know he needs to use Scalar :).
> misleading. "Use Scalar wherever needed" is a general solution.

> Think of this example:

>

> S[]^2 /. MakeRule[ { S[], T[a,-a] } }

result gives it a Scalar). Hence I discarded a similar expression when

tracing the source of my original problem, which put me onto the path

of expressions with Plus'es.

Cheers,

Teake

Oct 15, 2011, 3:11:23 PM10/15/11

to xAct Tensor Computer Algebra

> > S[]^2 /. MakeRule[ { S[], T[a,-a] } }

>

> Hmm, this example just works for me (using Simplification on the

> result gives it a Scalar). Hence I discarded a similar expression when

> tracing the source of my original problem, which put me onto the path

> of expressions with Plus'es.

I see. ToCanonical takes the liberty to put Scalar in simple cases
>

> Hmm, this example just works for me (using Simplification on the

> result gives it a Scalar). Hence I discarded a similar expression when

> tracing the source of my original problem, which put me onto the path

> of expressions with Plus'es.

that are obviously wrong though still with a "more or less" uniquely

defined meaning. But again, ToCanonical does not (it cannot) fix all

wrong cases. This is another partial solution and was misleading you.

The point I was trying to make with that example is that right after

applying the rule the result is syntactically incorrect. Now you add a

ToCanonical at the end: With T[a,-a]^2 ToCanonical decides to fix the

expression by changing it to Scalar[ T[a,-a] ]^2, but if you have a

sum ToCanonical complains instead, because it does not want to lose

time analyzing a potentially large sum of objects. This is certainly

inconsistent behaviour, but only happening on incorrect inputs anyway.

Thanks,

Jose.

Oct 15, 2011, 7:19:03 PM10/15/11

to JMM, xAct Tensor Computer Algebra

I had no idea that ToCanonical did this. It sounds quite dangerous!

As an example, what if you instead had the expression

expr = T[a,-b] T[b,-a]

... later ...

expr /. b->a // ToCanonical

This is a bit contrived, since the indices are being manually

manipulated; nonetheless, the expression

T[a,-a] T[a,-a]

can be interpreted as having arisen in two erroneous ways. One way is

the sum of the squares, and the second is the square of the sum, so to

speak.

As an example, what if you instead had the expression

expr = T[a,-b] T[b,-a]

... later ...

expr /. b->a // ToCanonical

This is a bit contrived, since the indices are being manually

manipulated; nonetheless, the expression

T[a,-a] T[a,-a]

can be interpreted as having arisen in two erroneous ways. One way is

the sum of the squares, and the second is the square of the sum, so to

speak.

Oct 15, 2011, 8:55:53 PM10/15/11

to xAct Tensor Computer Algebra

Yes, that is precisely what I meant by "more or less" in my previous

email. I can imagine easily replacing S[] by T[a,-a] in S[]^2, but

your example is really a forced error. Indices should never be changed

like that. Free indices must be replaced using a product with the

delta, and dummy indices must be replaced using ReplaceDummies. In any

case, T[a,-a]^2 is syntactically incorrect in xTensor, and once that

expression has appeared the result could be very wrong. Garbage in,

garbage out. I see nothing wrong in that.

Perhaps your suggestion is that ToCanonical should complain if it

finds T[a,-a]^2. I might agree with that. But should it complain if it

finds Log[ T[a,-a] ] or actually any other scalar-function on a

scalar? I don't think so. My opinion here is that users must decide

when to put Scalar and when to remove it.

Cheers,

Jose.

On Oct 15, 6:19 pm, Leo Stein <leo.st...@gmail.com> wrote:

> I had no idea that ToCanonical did this. It sounds quite dangerous!

> As an example, what if you instead had the expression

> expr = T[a,-b] T[b,-a]

> ... later ...

> expr /. b->a // ToCanonical

> This is a bit contrived, since the indices are being manually

> manipulated; nonetheless, the expression

> T[a,-a] T[a,-a]

> can be interpreted as having arisen in two erroneous ways. One way is

> the sum of the squares, and the second is the square of the sum, so to

> speak.

>

email. I can imagine easily replacing S[] by T[a,-a] in S[]^2, but

your example is really a forced error. Indices should never be changed

like that. Free indices must be replaced using a product with the

delta, and dummy indices must be replaced using ReplaceDummies. In any

case, T[a,-a]^2 is syntactically incorrect in xTensor, and once that

expression has appeared the result could be very wrong. Garbage in,

garbage out. I see nothing wrong in that.

Perhaps your suggestion is that ToCanonical should complain if it

finds T[a,-a]^2. I might agree with that. But should it complain if it

finds Log[ T[a,-a] ] or actually any other scalar-function on a

scalar? I don't think so. My opinion here is that users must decide

when to put Scalar and when to remove it.

Cheers,

Jose.

On Oct 15, 6:19 pm, Leo Stein <leo.st...@gmail.com> wrote:

> I had no idea that ToCanonical did this. It sounds quite dangerous!

> As an example, what if you instead had the expression

> expr = T[a,-b] T[b,-a]

> ... later ...

> expr /. b->a // ToCanonical

> This is a bit contrived, since the indices are being manually

> manipulated; nonetheless, the expression

> T[a,-a] T[a,-a]

> can be interpreted as having arisen in two erroneous ways. One way is

> the sum of the squares, and the second is the square of the sum, so to

> speak.

>

Reply all

Reply to author

Forward

0 new messages

Search

Clear search

Close search

Google apps

Main menu