The following should be True
for any function x
:
Sum[x[i], {i, 2, n - 1}] == Sum[x[j], {j, 2, n - 1}]
Reduce
and Simplify
do not seem to recognize this.
Is there an appropriate way to get Wolfram Language to reduce this to True
?
Mathematica Stack Exchange is a question and answer site for users of Wolfram Mathematica. It only takes a minute to sign up.
Sign up to join this communityThe following should be True
for any function x
:
Sum[x[i], {i, 2, n - 1}] == Sum[x[j], {j, 2, n - 1}]
Reduce
and Simplify
do not seem to recognize this.
Is there an appropriate way to get Wolfram Language to reduce this to True
?
As we can read in "Details and Options" of Sum
documentation:
The iteration variable i is treated as local, effectively using
Block
.
So index of summation is dynamically scoped, thus Sum[x[i], {i, 2, n - 1}]
can give different result than Sum[x[j], {j, 2, n - 1}]
if i
or j
is present in body of x
function, e.g.:
ClearAll[x, i]
x[arg_] := arg + i
Sum[x[i], {i, 2, n - 1}]
(* -2 - n + n^2 *)
Sum[x[j], {j, 2, n - 1}]
(* 1/2 (-2 - 4 i - n + 2 i n + n^2) *)
If we want to be sure that summation index will not interfere with any symbols coming from evaluation of x[i]
we should manually localize summation indices using lexical scoping construct: Module
:
Module[{i}, Sum[x[i], {i, 2, n - 1}]]
(* 1/2 (-2 - 4 i - n + 2 i n + n^2) *)
Module[{j}, Sum[x[j], {j, 2, n - 1}]]
(* 1/2 (-2 - 4 i - n + 2 i n + n^2) *)
but this will not help with equation simplifications.
Sum
normalizationTo help Mathematica in simplifying expressions involving Sum
we can manually "normalize" sums by renaming summation indices and shifting summation bounds. Following implementation renames variables lexically present in Sum
expression, so it automatically ensures lexical scoping for renamed variables, similarly as Module
in above examples. In some situations this may be unwanted, so make sure to understand difference between dynamic and lexical scoping, in this context, before using following functions.
NormalizeSum
function will replace consecutive dummy variables in Sum
expressions with SummationIndex[1]
, SummationIndex[2]
, etc. which will be formatted as i₁
, i₂
, ...
Lower summation bound, if finite will be shifted to value of "DefaultBound"
option (by default 0
), otherwise upper bound, if finite, will be shifted to default bound, if nothing is known about finiteness of both bounds they are not shifted.
BeginPackage["SumNormalization`"];
Unprotect["`*"];
ClearAll["`*"]
NormalizeSum::usage = "NormalizeSum[expr] \
normalizes dummy sumation indices in Sum expressions present in expr. \
i-th dummy index is renamed to SummationIndex[i], \
summation bounds are shifted such that, \
if lower bound is finite, then new lower bound is zero, \
otherwise if upper bound is finite, then new upper bound is zero.";
SummationIndex::usage = "SummationIndex[i] \
represents i-th dummy summation index in Sum expression.";
Begin["`Private`"];
ClearAll["`*"]
finiteQ[_DirectedInfinity] = False;
finiteQ[x_] := TrueQ@Refine[x != ComplexInfinity]
shiftBounds[i_, min_?finiteQ, max_, default_] :=
{i + min - default, default, max - min + default}
shiftBounds[i_, min_, max_?finiteQ, default_] :=
{i + max - default, min - max + default, default}
shiftBounds[i_, min_, max_, _] := {i, min, max}
NormalizeSum // Options = {"DefaultBound" -> 0};
NormalizeSum[expr_, opts : OptionsPattern[]] := expr /.
(h : Sum | Inactive[Sum])[x_, iterators__, sumOpts : OptionsPattern[]] :>
Module[
{
default = OptionValue[NormalizeSum, opts, "DefaultBound"],
assumpt = OptionValue[Sum, sumOpts, Assumptions],
rules = {}, usedIndices = {}, heldIterators
},
heldIterators = Join @@ Replace[Unevaluated@{iterators}, {
{i_, min_:1, max_} :>
RuleCondition@Module[{newIndex, newMin, newMax, replIndex},
newIndex = SummationIndex[Length@rules +1];
{newMin, newMax} = Unevaluated@{min, max} /. rules;
{replIndex, newMin, newMax} =
Assuming[
assumpt && Element[usedIndices, Complexes],
shiftBounds[newIndex, newMin, newMax, default]
];
AppendTo[usedIndices, newIndex];
AppendTo[rules, HoldPattern@i -> replIndex];
Hold@Evaluate@{newIndex, newMin, newMax}
],
i_ :> Hold@i
}, {1}];
h @@ (Join[Hold[x] /. rules, heldIterators, Hold[sumOpts]])
]
call : NormalizeSum[__, nonOpt : Except@OptionsPattern[], OptionsPattern[]] /;
Message[NormalizeSum::nonopt,
HoldForm@nonOpt, HoldForm@1, HoldForm@call
] :=
"NeverReached"
NormalizeSum[] /;
Message[NormalizeSum::argx, HoldForm@NormalizeSum, HoldForm@0] :=
"NeverReached"
NormalizeSum // SyntaxInformation =
{"ArgumentsPattern" -> {_, OptionsPattern[]}};
NormalizeSum // Protect;
$summationIndexDisplayFunction = StyleBox[SubscriptBox["i", #], Italic]&;
SummationIndex /: MakeBoxes[
index : SummationIndex[i_Integer?Positive],
form : StandardForm | TraditionalForm
] :=
TemplateBox[{MakeBoxes[i, form]}, "SummationIndex",
DisplayFunction -> $summationIndexDisplayFunction,
InterpretationFunction -> (RowBox[{"SummationIndex", "[", #, "]"}]&)
]
call : SummationIndex@Except[i_Integer?Positive] /;
Message[SummationIndex::intp, HoldForm@call, HoldForm@1] :=
"NeverReached"
SummationIndex[args : PatternSequence[] | PatternSequence[_, __]] /;
Message[SummationIndex::argx,
HoldForm@SummationIndex, HoldForm@Evaluate@Length@Hold[args]] :=
"NeverReached"
SummationIndex // SyntaxInformation = {"ArgumentsPattern" -> {_}};
End[];
EndPackage[];
Example of sum with one non-dummy index j
and three dummy indices: i
with both bounds symbolic, and k
with upper symbolic bound and implicit lower bound, by default equal to 1
, and l
with lower bound depending on other index i
. We assign values to indices to make sure there's no evaluation leak. Sum is normalized assuming that lower symbolic bound is an integer (thus it's finite).
ClearAll[f, i, j, k, n, m, o]
i = 100; j = 200; k = 300; l = 400;
Sum[f[i] j + k, {i, m, n}, j, {k, o}, {l, i, p}]
(* Sum[k + j*f[i], {i, m, n}, j, {k, o}, {l, i, p}] *)
Assuming[n \[Element] Integers, % // NormalizeSum]
(* Sum[1 + j*f[n + SummationIndex[1]] + SummationIndex[2],
{SummationIndex[1], m - n, 0}, j, {SummationIndex[2], 0, -1 + o},
{SummationIndex[3], 0, -n + p - SummationIndex[1]}] *)
(* Use some example numeric values of bounds to check that un-normalized and normalized sums represent same mathematical expression. *)
{%%, %} /. {m -> 9, n -> 11, o -> 2, p -> 12}
(* {800 (3 + 199 f[9]) + 600 (3 + 199 f[10]) + 400 (3 + 199 f[11]),
800 (3 + 199 f[9]) + 600 (3 + 199 f[10]) + 400 (3 + 199 f[11])} *)
SameQ @@ %
(* True *)
Now back to original problem:
ClearAll[x, n]
Sum[x[i], {i, 2, n - 1}] == Sum[x[j], {j, 2, n - 1}] // NormalizeSum
(* True *)
Here is a very naive attempt to do this (thanks to Xavier's comment for the suggestion of using a local variable to handle more general cases):
ClearAll[sumsEqualQ]
sumsEqualQ[
Sum[expr1_, {iterVar1_, min1_, max1_}],
Sum[expr2_, {iterVar2_, min2_, max2_}]
] := Module[{iter, exprsEqual},
exprsEqual = (expr1 /. iterVar1 -> iter) === (expr2 /.
iterVar2 -> iter);
Which[
(* same expressions, same boundaries *)
exprsEqual && min1 === min2 && max1 === max2,
True,
(* same expressions, different boundaries *)
exprsEqual && (min1 =!= min2 || max1 =!= max2),
False,
(* different expressions *)
! exprsEqual,
False
]
]
which correctly gives
In[78]:= sumsEqualQ[
Sum[x[i], {i, 2, n - 1}],
Sum[x[j], {j, 2, n - 1}]
]
Out[78]= True
In[127]:= sumsEqualQ[
Sum[x[i], {i, 2, n - 1}],
Sum[y[j], {j, 2, n - 1}]
]
Out[127]= False
In[130]:= sumsEqualQ[
Sum[i x[i], {i, 2, n - 1}],
Sum[i y[j], {j, 2, n - 1}]
]
Out[130]= False
sumsEqualQ[
Sum[x[i], {i, 2, n - 1}],
Sum[x[j], {j, 2, n}]
]
False
sumsEqualQ[Sum[x[i], {i, 2, n - 1}], Sum[x[j], {j, 2, n}]]
yields True
.
$\endgroup$
– corey979
Sep 9 '16 at 22:21
Sum[x[i], {i, 1, n}]
will result different from Sum[x[i+1],{i,0,n-1}]
. To properly handle all of such instances (not just this example I mean) would be quite a non-trivial task, I guess.
$\endgroup$
– glS
Sep 9 '16 at 22:41
If the function is defined, then the two sums are identified as equal. Here are five variations, three are pure functions and two are regular (impure) function. All return True
:
Sum[Function[u, 3 + u^2][i], {i, 2, n - 1}] ==
Sum[Function[v, 3 + v^2][j], {j, 2, n - 1}]
Sum[(3 + #) &, {i, 2, n - 1}] == Sum[(3 + #) &, {j, 2, n - 1}]
f = (3 + #) &;
Sum[f[i], {i, 2, n - 1}] == Sum[f[j], {j, 2, n - 1}]
g[n_] := 5*n^2 - Log[n];
Sum[g[i], {i, 2, n - 1}] == Sum[g[j], {j, 2, n - 1}]
h[n_] := Sqrt[n];
Sum[h[i], {i, -n, n}] == Sum[h[j], {j, -n, n}]
The final one might be a little overzealous in returning True
, since the Sqrt
is multiply defined.
Sum
expressions. If we use slightly more complicated function, then equality will remain unevaluated: f = Floor@*Log; Sum[f[i], {i, 1, n}] == Sum[f[j], {j, 1, n}]
$\endgroup$
– jkuczm
Sep 10 '16 at 18:30
Sum[x[i], {i, 1, 1000}] == Sum[x[j], {j, 1, 1000}]
returns True. $\endgroup$ – bill s Sep 9 '16 at 23:06expression /. i->j
$\endgroup$ – mikado Sep 11 '16 at 9:33x[1]+x[2]+...+x[1000]
in both cases $\endgroup$ – mikado Sep 11 '16 at 9:35