For Programmers: Free Programming Magazines  


Home > Archive > Mathematica > March 2006 > Grouping similar indices together in an expression









You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

 

Author Grouping similar indices together in an expression
David Sanders

2006-03-21, 7:58 am

Hi,

I am a newbie in Mathematica, and am trying to do the following.

I have terms which look like
a[i] a[j] b[i] b[j]

I need to apply a function F, for which I need to group the different
indices (by which I mean i, j) together as follows:

F(a[i] a[j] b[i] b[j]) = F(a[i] b[i]) F(a[j] b[j])

I do not in general know how many different indices there might be in a
term. E.g. I might have
a[i] a[j] a[k] b[j]

Could somebody please give me a hint as to how to do this?

Thanks,
David.

Andrzej Kozlowski

2006-03-22, 8:12 am


On 21 Mar 2006, at 13:46, David Sanders wrote:

> Hi,
>
> I am a newbie in Mathematica, and am trying to do the following.
>
> I have terms which look like
> a[i] a[j] b[i] b[j]
>
> I need to apply a function F, for which I need to group the different
> indices (by which I mean i, j) together as follows:
>
> F(a[i] a[j] b[i] b[j]) = F(a[i] b[i]) F(a[j] b[j])
>
> I do not in general know how many different indices there might be
> in a
> term. E.g. I might have
> a[i] a[j] a[k] b[j]
>
> Could somebody please give me a hint as to how to do this?
>
> Thanks,
> David.
>

As long as you do not mind the order of the terms being re-arranged,
the following should do what you want:


GroupTerms[m_Times, f_] := Times @@ Apply[f, Split[Sort[List @@ m,
OrderedQ[{#1[[1]], #2[[1]]}] & ],
#1[[1]] === #2[[1]] & ], {1}]

For example:



GroupTerms[a[1]*a[2]*b[1]*b[2]*c[1]*c[3]
, f]


f[c[3]]*f[a[2], b[2]]*f[a[1], b[1], c[1]]


which separates all terms according to the "index" .

Andrzej Kozlowski






Peter Pein

2006-03-22, 8:12 am

David Sanders schrieb:
> Hi,
>
> I am a newbie in Mathematica, and am trying to do the following.
>
> I have terms which look like
> a[i] a[j] b[i] b[j]
>
> I need to apply a function F, for which I need to group the different
> indices (by which I mean i, j) together as follows:
>
> F(a[i] a[j] b[i] b[j]) = F(a[i] b[i]) F(a[j] b[j])
>
> I do not in general know how many different indices there might be in a
> term. E.g. I might have
> a[i] a[j] a[k] b[j]
>
> Could somebody please give me a hint as to how to do this?
>
> Thanks,
> David.
>


Hi David,

the function

combineCommonIndices[lst_,f_:Plus,g_:Tim
es]:=Module[{hds=Union[Head/@lst]},
g@@f@@@(Through[hds[#]]&/@
(Intersection@@(Pick[First/@lst,lst,Blank[#]]&/@ hds)))]

works at least for these examples:

examples =
{{a[i],a[j],b[i],b[j]},
{a[i],a[j],a[k],b[j]},
{a[i],a[j],a[k],b[g],b[h],b[i],b[j]}};

combineCommonIndices[#, F] & /@ examples
-->
{F[a[i],b[i]] F[a[j],b[j]],
F[a[j],b[j]],
F[a[i],b[i]] F[a[j],b[j]]}

and even the slightly confusing example

lst=Union@@Outer[#1[#2]&,#,#]&[{a,b,c}]
--> {a[a],a[b],a[c],b[a],b[b],b[c],c[a],c[b]
,c[c]}

combineCommonIndices[lst,F,List]
--> {F[a[a],b[a],c[a]], F[a[b],b[b],c[b]], F[a[c],b[c],c[c]]}

gives the expectes result.

Greetings,
Peter

P.S.: If you've got a term t = a[i] a[j] b[i] b[j], then use
combineCommonIndices[List @@ t, F] or modify this function
according to your needs.

Peter Pein

2006-03-22, 8:12 am

David Sanders schrieb:
> Hi,
>
> I am a newbie in Mathematica, and am trying to do the following.
>
> I have terms which look like
> a[i] a[j] b[i] b[j]
>
> I need to apply a function F, for which I need to group the different
> indices (by which I mean i, j) together as follows:
>
> F(a[i] a[j] b[i] b[j]) = F(a[i] b[i]) F(a[j] b[j])
>
> I do not in general know how many different indices there might be in a
> term. E.g. I might have
> a[i] a[j] a[k] b[j]
>
> Could somebody please give me a hint as to how to do this?
>
> Thanks,
> David.
>


Hi David,

maybe you don't want the "intersection of indices"?

Then try this one:

example3=a[i] a[j] a[k] b[g] b[h] b[i] b[j];

Times@@F@@@Split[Sort[List@@example3,Ord
eredQ[First/@{##}]&],
SameQ@@(First/@{##})&]

--> F[a[k]] F[b[g]] F[b[h]] F[a[i],b[i]] F[a[j],b[j]]

Peter

Bob Hanlon

2006-03-22, 8:12 am

I'm not sure that I understand what you want but here goes

Clear[f];
f[x_?(Length[Union[Cases[#,_,{2}]]]>1&)]:=
Module[{g,indices},
indices=Union[Cases[g[x],_,{3}]];
Times@@(f/@(Times@@Cases[g[x],_[#],{2}]&/@indices))];

f[a[i] b[i]]

f[a[i]*b[i]]

f[a[i] b[j]]

f[a[i]]*f[b[j]]

f[a[i] a[j] b[i] b[j]]

f[a[i]*b[i]]*f[a[j]*b[j]]

f[a[i] a[j] a[k] b[j]]

f[a[i]]*f[a[k]]*f[a[j]*b[j]]

f[a[i] a[j] a[k] b[l]]

f[a[i]]*f[a[j]]*f[a[k]]*f[b[l]]


Bob Hanlon

>
> From: "David Sanders" <dpsanders@gmail.com>
> Subject: Grouping similar indices together in an expression
>
> Hi,
>
> I am a newbie in Mathematica, and am trying to do the following.
>
> I have terms which look like
> a[i] a[j] b[i] b[j]
>
> I need to apply a function F, for which I need to group the different
> indices (by which I mean i, j) together as follows:
>
> F(a[i] a[j] b[i] b[j]) = F(a[i] b[i]) F(a[j] b[j])
>
> I do not in general know how many different indices there might be in a
> term. E.g. I might have
> a[i] a[j] a[k] b[j]
>
> Could somebody please give me a hint as to how to do this?
>
> Thanks,
> David.
>
>


Bill Rowe

2006-03-22, 8:12 am

On 3/21/06 at 7:46 AM, dpsanders@gmail.com (David Sanders) wrote:

>I am a newbie in Mathematica, and am trying to do the following.


>I have terms which look like a[i] a[j] b[i] b[j]


>I need to apply a function F, for which I need to group the
>different indices (by which I mean i, j) together as follows:


>F(a[i] a[j] b[i] b[j]) = F(a[i] b[i]) F(a[j] b[j])


>I do not in general know how many different indices there might be
>in a term. E.g. I might have a[i] a[j] a[k] b[j]


>Could somebody please give me a hint as to how to do this?


It would be very useful to be able to see what Mathematica code you have tried to better understand what you are trying to do. I will offer a few comments. But without seeing the code, I've no idea how appropriate my comments will be.

First, note in Mathematica, the syntax a[j] does not refer to an indexed variable. Instead Mathematica sees this as a function named "a" to be evaluated at j. When you write something like

a[1]=10

you are defining the function a to have value 10 when evaluated at 1.

For what you are describing, it would be better to define a and b as lists of values, i.e.,

In[1]:=
a = Table[Subscript[a, n], {n, 3}];
b = Table[Subscript[b, n], {n, 3}];

Here, I've used subscripts for clarity in what follows.

Given the data as lists then

In[5]:=
Times @@ MapThread[f, {a, b}]

Out[5]=
f[Subscript[a, 1], Subscript[b, 1]]*
f[Subscript[a, 2], Subscript[b, 2]]*
f[Subscript[a, 3], Subscript[b, 3]]

does what you seem to be asking for
--
To reply via email subtract one hundred and four

David Park

2006-03-22, 8:12 am

David,

Your question isn't totally clear, but I'll take the Subject heading as the
definition.

expr = a[i] a[j] b[i] b[j]

As a newbie you will probably not like the following solution.

Times @@ F /@ Times @@@ MapThread[Cases[expr, _[#]] &, {{i, j}}]
F[a[i] b[i]] F[a[j] b[j]]

So I will take it apart. If we want all the factors in the term that contain
the index i we could use.

Cases[expr, _[i]]
{a[i], b[i]}

where _[i] is a pattern for an expression with any head and the single
argument i.

We want separate lists for each index. To obtain that we use MapThread that
evaluates a Cases statement for each of a list of indices. (With this
approach you have to know what the list of indices is.) The Cases statement
is turned into a pure function where # stands for the particular index that
will be used. Look up Function in Help.

MapThread[Cases[expr, _[#]] &, {{i, j}}]
{{a[i], b[i]}, {a[j], b[j]}}

Now copy and paste and then evaluate the following code in a Mathematica
notebook to see what each step in the expression does.

Print["Group factors with similar indices in following expression"]
expr = a[i] a[j] b[i] b[j]
Print["Generate lists of common index factors using Cases and MapThread"]
step1 = MapThread[Cases[expr, _[#]] &, {{i, j}}]
Print["Apply Times to each of the inner lists - 4th note in Apply Help"]
step2 = Times @@@ step1
Print["Map F onto the grouped factors - check Map Help"]
step3 = F /@ step2
Print["Convert the list to a product - check Apply again"]
Times @@ step3

I wouldn't be shocked if someone comes up with a much simpler method;
nevertheless, welcome to Mathematica's functional programming.

David Park
djmp@earthlink.net
http://home.earthlink.net/~djmp/



From: David Sanders [mailto:dpsanders@gmail.com]


Hi,

I am a newbie in Mathematica, and am trying to do the following.

I have terms which look like
a[i] a[j] b[i] b[j]

I need to apply a function F, for which I need to group the different
indices (by which I mean i, j) together as follows:

F(a[i] a[j] b[i] b[j]) = F(a[i] b[i]) F(a[j] b[j])

I do not in general know how many different indices there might be in a
term. E.g. I might have
a[i] a[j] a[k] b[j]

Could somebody please give me a hint as to how to do this?

Thanks,
David.


Paul Abbott

2006-03-22, 8:12 am

In article <dvosko$j5k$1@smc.vnet.net>,
"David Sanders" <dpsanders@gmail.com> wrote:

> I am a newbie in Mathematica, and am trying to do the following.
>
> I have terms which look like
> a[i] a[j] b[i] b[j]
>
> I need to apply a function F, for which I need to group the different
> indices (by which I mean i, j) together as follows:
>
> F(a[i] a[j] b[i] b[j]) = F(a[i] b[i]) F(a[j] b[j])


What is the application? Knowing this might help construct the "best"
solution.

> I do not in general know how many different indices there might be in a
> term. E.g. I might have
> a[i] a[j] a[k] b[j]
>
> Could somebody please give me a hint as to how to do this?


Essentially, you want to sort the expression by its index. You could use
pattern-matching to do this. Alternatively, Sort can be used for this
with a suitable ordering function. However, Times is Orderless so you
need to change the head of the expression to, say, List:

Sort[List @@ (a[i] a[j] a[k] b[j]), OrderedQ[{First[#1], First[#2]}] &]

Now you can use Split to split up the expression whenever the index
changes:

Split[%, First[#1] === First[#2] &]

Putting these together, the function IndexCollect applies f to each
grouping of indices:

IndexCollect[f_, x_] := Head[x] @@ f /@ Head[x] @@@
Split[Sort[List @@ x, OrderedQ[{First[#1], First[#2]}] &],
First[#1] === First[#2] &]

For example,

IndexCollect[f, a[i] a[j] b[i] b[j]]

f[a[i] b[i]] f[a[j] b[j]]

IndexCollect[f, a[i] a[j] a[k] b[j]]

f[a[i]] f[a[k]] f[a[j] b[j]]

Also, if you have addition instead of multiplication, this operation is
preserved (via Head[x] in the definition of IndexCollect):

IndexCollect[f, a[i]+a[j]+a[k]+b[j]]

f[a[i]] + f[a[k]] + f[a[j] + b[j]]

Cheers,
Paul

________________________________________
_______________________________
Paul Abbott Phone: 61 8 6488 2734
School of Physics, M013 Fax: +61 8 6488 1014
The University of Western Australia (CRICOS Provider No 00126G)
AUSTRALIA http://physics.uwa.edu.au/~paul

David Sanders

2006-03-23, 7:10 pm

Hi,

Thanks very much to everyone for their replies. I've certainly learnt a
lot about Mathematica by looking at them!

I apologise for not explaining the problem clearly; I was trying to
reduce it to its essentials, but went too far.

The "indices" i, j etc. represent positions, and are integers. a[i]
etc. are random variables associated to those positions. The random
variables at different positions (with different indices) are
independent, but those at the same position are not. The function
which I wrote as "F" is an expectation; I will now write it as Ex.

What I need to calculate is the expectation of terms such as
a[i]^2 a[i+1] b[i] b[i+1].
This is a product of random variables which take real values.
The terms can be raised to positive integer powers and the indices can
be things like i+1, representing the position next to position i.

I thus need
Ex[ a[i]^2 a[i+1] b[i] b[i+1] ] = Ex[ a[i]^2 b[i] ] Ex[ a[i+1] b[i+1]
]

Using everybody's suggestions, I have put together the following code
to do this:

ExtractIndex[term_] := If[Head[term]===Power, term[[1,1]], term[[1]]]

ExtractIndices[expr_] :=
If[Head[expr] =!= Times, {ExtractIndex[expr]},
Union[Map[ExtractIndex, Apply[List, expr]]]]

MakeList[expr_] := If[Head[expr] === Times, Apply[List, expr], {expr}]

ExtractTerms[expr_, index_] :=
Ex[Apply[Times,Select[MakeList[expr], ExtractIndex[#] \[Equal]
index&]]]

Expec[expr_] :=
Apply[Times,MapThread[ExtractTerms[expr,
#]&,
{ExtractIndices[expr]}]]

Expec[a_+b_] := Expec[a] + Expec[b]


Then

Expec[ a[i] a[j] b[i] b[j] + a[i+1] a[j] b[i+1] b[j] ]

gives

Ex[a[i]^2 b[i]] Ex[a[j] b[j]] + Ex[a[1+i] b[1+i]] Ex[a[j] b[j]]

as desired.
-------

Now what I need to do is tell Mathematica the rules for computing the
expectations at a site. For simplicity let us suppose that they
factorise, even though in my real application that is not the case.

Then I want something like
Ex[a[i_]^alpha_ b[i_]^beta_] = A^alpha B^beta

But this does not capture e.g. Ex[a[i] b[i]]. How can I include these
without giving them explicitly?

Apologies for the length of this post,
Best wishes,

David.

Sponsored Links







Also available: Server administration forum archive | Web Design forum archive | Software forum archive | Hardware reviews archive

Copyright 2008 codecomments.com