# Log of products to sum of logs

I have a log of products: $$\log \left(\prod _{i=1}^n \left( g(a(i,i)) \prod _{k=1}^i f(a(i,k))\right)\right)$$

That I turn into a sum of logs (I know everything involved is nice enough): $$\sum _{i=1}^n \left(\sum _{k=1}^i \log (f(a(i,k)))+\log (g(a(i,i)))\right)$$

I had to use a custom rule for this:

Log[Product[g[a[i, i]] Product[f[a[i, k]], {k, 1, i}], {i, 1, n}]] //.
{Log[Product[expr_, range_]] :> Sum[Log[expr], range],
Log[Times[a_, b_]] :> Log[a] + Log[b],
Log[Power[a_, n_]] :> n Log[a]}


Some observations:

FullSimplify does nothing, even with assumptions:

FullSimplify[
Log[Product[g[a[i, i]] Product[f[a[i, k]], {k, 1, i}], {i, 1, n}]],
{a[_, _] > 0 && g[_] > 0 && a[_, _] > 0 && f[_] > 0}]


Not even with penalty for Product does it do anything:

FullSimplify[
Log[Product[a[i], {i, 1, n}]],
a[_] > 0,
ComplexityFunction ->
(20 Count[#, _Product, Infinity] + LeafCount[#] &)]


But for Times it works:

FullSimplify[
Log[a b c],
a > 0 && b > 0 && c > 0,
ComplexityFunction ->
(20 Count[#, _Times, Infinity] + LeafCount[#] &)]
(* Log[a] + Log[b] + Log[c] *)


Unless I use a[i]

FullSimplify[
Log[a a a ],
a[_] > 0 , (* a>0 && a>0 && a>0 works *)
ComplexityFunction -> (20 Count[#, _Times, Infinity] + LeafCount[#] &)]


Is there a more general way to do this that does not rely on making up a bunch of manual transformations?

• Do you know n? I can get it to expand easily if n is known... – rm -rf Mar 29 '13 at 18:31
• @rm-rf No, that's unknown – ssch Mar 29 '13 at 18:35
• Ok, because for the examples shown later, Log[a b c] // PowerExpand works and also for the original expression if n is known, but not otherwise... – rm -rf Mar 29 '13 at 18:39
• @rm-rf Interesting, perhaps in the case with known n the Product gets evaluated early and that's why it works – ssch Mar 29 '13 at 18:48
• Your typesetting of the opening expression is confusing. It appears as: Log[ Product[blah] Product[bleh] ], whereas what you have entered further down is: Log[Product[ blah * Product[bleh] ]. Easily fixed by adding some ( ) ... – wolfies Mar 29 '13 at 19:04

I don't think there is any in-built way of doing this with Mathematica using FullSimplify etc, other than as you have suggested. These issues arise quite often when solving symbolic maximum likelihood estimator problems, so we added this functionality years ago into the mathStatica add-on for Mathematica, which is done by activating SuperLog, which enhances Mathematica's Log function to make such conversions automatically. Since your example is a bit more unusual than the norm, I thought I'd just try it out ... Here's the syntax: A more typical problem would be something like: • That's just the use case I have, great function name :D – ssch Mar 29 '13 at 19:43
• Maybe I'm blind, but I couldn't find a link to the code anywhere. The one on the answer here works :) – Andreas Storvik Strauman Feb 2 '17 at 19:24

Here is a concise way to do the transformation :

(* your expression : *)
exp00 = Log[Product[
g[a[i, i]] Product[
f[a[i, k]],
{k, 1, i}
],
{i, 1, n}]
];

(* your rules expressed as functions : *)
transformationFunction1 = (# /. Log[Product[expr_,range_]] :> Sum[Log[expr],range]) &;
transformationFunction2 = PowerExpand;

(* the transformation : *)
FixedPoint[(# // transformationFunction1 // transformationFunction2) &, exp00];


It gives :
$$\sum _{i=1}^n \left(\text{Log}[g[a[i,i]]]+\sum _{k=1}^i \text{Log}[f[a[i,k]]]\right)$$

With Simplify, the solution is :

Simplify[
exp00,
TransformationFunctions -> {
Automatic,
transformationFunction1,
transformationFunction2
},
ComplexityFunction -> (200 Count[#, _Product, Infinity] +
20 Count[#, _Times, Infinity] + LeafCount[#] &)
]


Simplify[] is hmm... complicated and useless in this case.

When not to use Simplify[] ?. Here is my rule of thumb : In a Simplify[], if the transformationFunctions can be applied everywhere in the expression and the transformation goes in the right direction (ie no backtrack on a earlier goal in the future) or does nothing, get rid of Simplify[] and use FixedPoint[(# //TransformationFunction1 //TransformationFunction2 ...)&,exp]

Moreover :
- Simplify[] can stop on a local minimum of a ComplexityFunction
- Here the term 20 Count[#, _Times, Infinity] in the ComplexityFunction limits strongly the generality of the transformation.

Beyond this point, for those interested : How to waste time with Simplify[]

I have detailed the trial and error path that leads to the code. Hope my explanations could simplify the path for others.

We want to automatically transform :

$$\text{exp00}=\text{Log}\left[\prod _{i=1}^n \left(g[a[i,i]] \prod _{k=1}^i f[a[i,k]]\right)\right]$$

(equivalent to : exp00 = Log[ Product[g[a[i, i]] Product[f[a[i, k]], {k, 1, i}], {i, 1, n}]] )

in : $$\sum _{i=1}^n \left(\text{Log}[g[a[i,i]]]+\sum _{k=1}^i \text{Log}[f[a[i,k]]]\right)$$

First, one must know (unfortunately) that Mathematica doesn't simplify $\text{Log}\left[\prod _{k=1}^i x[i]\right]$. So one tries the rule : Log[Product[expr_, range_]] :> Sum[Log[expr], range] and obtains : $$\sum _{i=1}^n \text{Log}\left[g[a[i,i]] \prod _{k=1}^i f[a[i,k]]\right]$$ which goes in the right direction.

Then comes to the mind the idea that this rule should always be used, so that one get rid of the second Product, or maybe every product for this kind of problem. The point is that the rule transforms a expression into a expression which is equal (in the meaning of the user, depending of the context : Real, Complex etc...), so it can be applied everywhere (because we don't know yet how will be the expression when the rule will be applied)

To apply semi-automatically such rules which conserves a expression, there is Simplify[exp, TransformationFunctions -> {# /. conservativeRule1 &,# /. conservativeRule1 & ...} ].

Simplify[] has built-in conservative rules (which are unknown). To use them, add Automatic at the beginning of the list of TransformationFunctions.

So we try :

Simplify[
exp00,
TransformationFunctions -> {
Automatic,
# /. Log[Product[expr_, range_]] :> Sum[Log[expr], range] &
}
]


and we see that it gives : $$\sum _{i=1}^n \text{Log}\left[g[a[i,i]] \prod _{k=1}^i f[a[i,k]]\right]$$

It's not better than applying the Rule directly, but we have hope to resolve the second Product later. Here the problem is apparently that Mathematica doesn't transform Log[a b] in Log[a]+ Log[b]. Once again one must (unfortunately) know that PowerExpand is the (hard to find) solution :

Log[a b] // PowerExpand
(* Log[a] + Log[b] *)


So one add PowerExpand to the TransformationFunctions :

Simplify[
exp00,
TransformationFunctions -> {
Automatic,
# /. Log[Product[expr_, range_]] :> Sum[Log[expr], range] &,
PowerExpand
}
]


This gives : $$\sum _{i=1}^n \text{Log}\left[g[a[i,i]] \prod _{k=1}^i f[a[i,k]]\right]$$

It doesn't work !

We expected something like : $$\sum _{i=1}^n \text{Log}[g[a[i,i]]]+\text{Log}\left[ \prod _{k=1}^i f[a[i,k]]\right]$$

The reason is that Mathematica doesn't consider that what we expected is simpler than the input expression."simpler" is a very subjective notion. The option that determine the criterion "simple" is : ComplexityFunction-> {LeafCount} (Default).
Here we want to get rid of Times (because $\text{FullForm}\left[g[a[i,i]] \prod _{k=1}^i f[a[i,k]]\right]$ is Times[g[a[i, i]], Product[f[a[i, k]], List[k, 1, i]]])

So we add the option : ComplexityFunction -> (20 Count[#, _Times, Infinity] + LeafCount[#] &). The coefficient 20 is strong to get rid of all Times in the expression. Here,there is only one. Very dangerous if other expression (1).

It gives : $$\text{Log}\left[\prod _{i=1}^n g[a[i,i]] \prod _{k=1}^i f[a[i,k]]\right]$$

It doesn't work. We are back to the first expression !! Simplifydoesn't want to eliminate Product. As we know that it can do it, we must complete the ComplexityFunction List by specifiying that we do not want any Product at all (coefficient 200) :

Simplify[
exp00,
TransformationFunctions -> {
Automatic,
# /. Log[Product[expr_, range_]] :> Sum[Log[expr], range] &,
PowerExpand
},
ComplexityFunction ->
(200 Count[#, _Product, Infinity] +
20 Count[#, _Times, Infinity] +
LeafCount[#] &
)
]


It gives : $$\sum _{i=1}^n \left(\text{Log}[g[a[i,i]]]+\sum _{k=1}^i \text{Log}[f[a[i,k]]]\right)$$

This is what we want.

Nicely, the second Product has vanished.