Function Repository Resource:

InactiveSumOfPowers

Source Notebook

Express an integer as a sum of one or more integer powers

Contributed by: Christopher Stover

ResourceFunction["InactiveSumOfPowers"][n,{p1,,pk}]

gives an Inactive expression p1n1+p2n2+pknk such that n=p1n1+p2n2+pknk.

ResourceFunction["InactiveSumOfPowers"][n,m]

gives an Inactive expression mn1+mn2+mnk such that n=mn1+mn2+mnk.

ResourceFunction["InactiveSumOfPowers"][n]

is equivalent to ResourceFunction["InactiveSumOfPowers"][n,2].

Details and Options

ResourceFunction["InactiveSumOfPowers"] allows an integer, infinite quantity or List of such quantities to be decomposed as a sum of powers of one or more integers.
InactiveSumOfPowers threads over its first argument so that ResourceFunction["InactiveSumOfPowers"][{n1,,nk},bases] gives a List of Inactive expression equivalent to {ResourceFunction["InactiveSumOfPowers"][n1,bases],,ResourceFunction["InactiveSumOfPowers"][nk,bases]}.
ResourceFunction["InactiveSumOfPowers"][list] is equivalent to ResourceFunction["InactiveSumOfPowers"][#,2]&/@list.
For integers n, ResourceFunction["InactiveSumOfPowers"][n,list] requires that list consist only of integers greater than 1.
For positive integers n, ResourceFunction["InactiveSumOfPowers"][-n,list] effectively returns -1 times the factorization returned by ResourceFunction["InactiveSumOfPowers"][n,list].
ResourceFunction["InactiveSumOfPowers"][0,{p1,,pk}] returns the inactivated sum p1-++pk-.
ResourceFunction["InactiveSumOfPowers"][Infinity,list] and ResourceFunction["InactiveSumOfPowers"][-Infinity,list] both work whenever list consists only of integers greater than 1. ResourceFunction["InactiveSumOfPowers"][Infinity,{p1,,pk}] returns the inactivated sum p1++pk and ResourceFunction["InactiveSumOfPowers"][-Infinity,{p1,,pk}] returns -1 times that.
ResourceFunction["InactiveSumOfPowers"][n,{m}] is equivalent to ResourceFunction["InactiveSumOfPowers"][n,m].
ResourceFunction["InactiveSumOfPowers"] accepts the following options (which may tweak the above-mentioned algorithm):
"CollectLikeTerms"Falsewhether like terms in the decomposition should be collected
"FactorNegative"Falsewhether existing negative signs should be "factored out" of the resulting decomposition
"HoldListProducts"Falsewhether the above-described algorithm should halt when a product of list elements is reached

Examples

Basic Examples (3) 

Decompose 25 as a sum of powers of 3 and 4:

In[1]:=
ResourceFunction["InactiveSumOfPowers"][25, {3, 4}]
Out[1]=

Expand 7, 11 and 13 to the twentieth power and take the sum:

In[2]:=
sum = Total[{7, 11, 13}^20]
Out[2]=

Recover the representation of this sum using bases 7, 11 and 13:

In[3]:=
ResourceFunction["InactiveSumOfPowers"][sum, {7, 11, 13}]
Out[3]=

Get a random integer:

In[4]:=
int0 = RandomInteger[{10^15, 10^20}]
Out[4]=

Express it as a sum of powers of 7, 11 and 13:

In[5]:=
sum0 = ResourceFunction["InactiveSumOfPowers"][int0, {7, 11, 13}]
Out[5]=

Confirm the result:

In[6]:=
Activate[sum0] == int0
Out[6]=

Scope (6) 

InactiveSumOfPowers works with negative numbers:

In[7]:=
neg = -RandomInteger[{10^15, 10^20}]
Out[7]=
In[8]:=
negsum = ResourceFunction["InactiveSumOfPowers"][neg, {3, 19}]
Out[8]=
In[9]:=
Activate[negsum] == neg
Out[9]=

InactiveSumOfPowers[0,…] works with both non-List and List second arguments. In the prior case, InactiveSumOfPowers[0,q] returns an Inactive version of Power[q,-Infinity]:

In[10]:=
zerosuma = ResourceFunction["InactiveSumOfPowers"][0, 791]
Out[10]=
In[11]:=
Activate[zerosuma]
Out[11]=

In the latter case, InactiveSumOfPowers[0,{a1,…,an}] returns an Inactive form of Power[a1,-Infinity]+⋯+Power[an,-Infinity]:

In[12]:=
zerosumb = ResourceFunction["InactiveSumOfPowers"][0, Prime /@ Range[5]]
Out[12]=
In[13]:=
Activate[zerosumb]
Out[13]=

InactiveSumOfPowers[Infinity,…] and InactiveSumOfPowers[-Infinity,…] both work as expected. Here are some computations with Infinity:

In[14]:=
ResourceFunction["InactiveSumOfPowers"][Infinity, Prime /@ Range[2, 7]]
Out[14]=
In[15]:=
Activate[%]
Out[15]=
In[16]:=
ResourceFunction["InactiveSumOfPowers"][Infinity, 12321]
Out[16]=
In[17]:=
Activate[%]
Out[17]=
In[18]:=
ResourceFunction["InactiveSumOfPowers"][Infinity]
Out[18]=
In[19]:=
Activate[%]
Out[19]=

Here are some with -Infinity:

In[20]:=
ResourceFunction["InactiveSumOfPowers"][-Infinity, Fibonacci /@ Range[3, 7]]
Out[20]=
In[21]:=
Activate[%]
Out[21]=
In[22]:=
ResourceFunction["InactiveSumOfPowers"][-Infinity, 1111]
Out[22]=
In[23]:=
Activate[%]
Out[23]=
In[24]:=
ResourceFunction["InactiveSumOfPowers"][-Infinity]
Out[24]=
In[25]:=
Activate[%]
Out[25]=

Both Infinity and -Infinity work as elements of first-argument lists as well:

In[26]:=
Join[{{Style["input", Bold], "   ", Style["decomp", Bold], "   ", Style["equal?", Bold]}}, {Activate[#], "   ", #, "   ", Activate[# == #]} & /@ ResourceFunction[
    "InactiveSumOfPowers"][{75, -Infinity, -91, Infinity, 0}, Fibonacci /@ Range[3, 7]]] // Grid[#, Dividers -> {False, All}, FrameStyle -> Dotted] &
Out[26]=

InactiveSumOfPowers[list1,list2] threads over list1 and equals InactiveSumOfPowers[#,list2]&/@list1:

In[27]:=
list1 = {55, 79, 123}; list2 = {2, 3, 5};
In[28]:=
ResourceFunction["InactiveSumOfPowers"][list1, list2] // Column
Out[28]=
In[29]:=
ResourceFunction["InactiveSumOfPowers"][#, list2] & /@ list1 // Column
Out[29]=

In all cases, the the Inactive output equals the input when activated:

In[30]:=
Activate[
  ResourceFunction["InactiveSumOfPowers"][list1, list2]] == list1
Out[30]=

InactiveSumOfPowers[list,q] threads over list when q is an Integer:

In[31]:=
{#, ResourceFunction["InactiveSumOfPowers"][#, 3]} & /@ Factorial[Range[14, 17]] // Column
Out[31]=

Confirm the results:

In[32]:=
Grid[{#, ResourceFunction["InactiveSumOfPowers"][#, 3], If[Activate[ResourceFunction["InactiveSumOfPowers"][#, 3] == #], "They're equal!", "Oh no!"]} & /@ Factorial[Range[14, 17]], Frame -> All, ItemSize -> {{10, Automatic, 10}}]
Out[32]=

InactiveSumOfPowers[list] is equivalent to InactiveSumOfPowers[list,2]:

In[33]:=
{ResourceFunction["InactiveSumOfPowers"][#], If[Activate[
      ResourceFunction["InactiveSumOfPowers"][#] == ResourceFunction["InactiveSumOfPowers"][#, 2]], "equals", "is saddened by"], ResourceFunction["InactiveSumOfPowers"][#, 2]} & /@ Prime[Range[Factorial[11], Factorial[11] + 3]] // Grid[#, Frame -> All] &
Out[33]=

Options (8) 

CollectLikeTerms (2) 

With "CollectLikeTerms"->False (the default), repeated terms remain uncombined:

In[34]:=
ResourceFunction["InactiveSumOfPowers"][32123, 17]
Out[34]=
In[35]:=
ResourceFunction["InactiveSumOfPowers"][32123, 17, "CollectLikeTerms" -> False]
Out[35]=

With "CollectLikeTerms"->True, repeated terms are combined together:

In[36]:=
ResourceFunction["InactiveSumOfPowers"][32123, 17, "CollectLikeTerms" -> True]
Out[36]=

In both cases, the activated version of the output equals the input:

In[37]:=
Activate[ResourceFunction["InactiveSumOfPowers"][32123, 17]] == Activate[
  ResourceFunction["InactiveSumOfPowers"][32123, 17, "CollectLikeTerms" -> True]] == 32123
Out[37]=

If no like terms are produced during the decomposition, "CollectLikeTerms"->True has no effect on the output:

In[38]:=
ResourceFunction["InactiveSumOfPowers"][121, 3]
Out[38]=
In[39]:=
ResourceFunction["InactiveSumOfPowers"][121, 3, "CollectLikeTerms" -> True]
Out[39]=

FactorNegative (3) 

Given an input n<0, InactiveSumOfPowers[n,…] produces negative signs in the output. Setting "FactorNegative"->False (the default) specifies that each term in the sum is made negative:

In[40]:=
ResourceFunction["InactiveSumOfPowers"][-2047, 2]
Out[40]=
In[41]:=
ResourceFunction["InactiveSumOfPowers"][-2047, 2, "FactorNegative" -> False]
Out[41]=

With "FactorNegative"->True, a single negative is "factored out" of the sum so the individual summands remain positive:

In[42]:=
ResourceFunction["InactiveSumOfPowers"][-2047, 2, "FactorNegative" -> True]
Out[42]=

In both cases, the activated version of the output equals the input:

In[43]:=
Activate[ResourceFunction["InactiveSumOfPowers"][-2047, 2]] == Activate[
  ResourceFunction["InactiveSumOfPowers"][-2047, 2, "FactorNegative" -> True]] == -2047
Out[43]=

HoldListProducts (3) 

If n is a product of powers of the elements of list, then the output of InactiveSumOfPowers[n,list,…,"HoldListProducts"->True] will be an Inactive factorization of n. This uses the resource function InactiveFactorInteger in the backend:

In[44]:=
ResourceFunction["InactiveSumOfPowers"][2^9*3^15*5, {2, 3, 5}, "HoldListProducts" -> True]
Out[44]=

Conversely, using "HoldListProducts"->False (the default) will result in the usual decomposition:

In[45]:=
ResourceFunction["InactiveSumOfPowers"][2^9*3^15*5, {2, 3, 5}, "HoldListProducts" -> False]
Out[45]=
In[46]:=
ResourceFunction["InactiveSumOfPowers"][2^9*3^15*5, {2, 3, 5}]
Out[46]=

In both cases, the activated version of the output equals the input:

In[47]:=
Activate[
  ResourceFunction["InactiveSumOfPowers"][2^9*3^15*5, {2, 3, 5}]] == Activate[
  ResourceFunction["InactiveSumOfPowers"][2^9*3^15*5, {2, 3, 5}, "HoldListProducts" -> True]] == 2^9*3^15*5
Out[47]=

Applications (7) 

InactiveSumOfPowers[n,q] can be used to mimic the output of BaseForm[n,q]. First, define a random n and q:

In[48]:=
n = RandomInteger[{10^4, 10^8}]
Out[48]=
In[49]:=
q = RandomInteger[{2, 36}]
Out[49]=

Apply InactiveSumOfPowers:

In[50]:=
basesum = ResourceFunction["InactiveSumOfPowers"][n, q]
Out[50]=

Strip away the excess and see which powers are present and which are missing in the sum:

In[51]:=
existingpowers = (Tally[basesum /. {Inactive[Plus] -> List}][[All, 1]]) /. {Inactive[Power][a_, b_] :> b}
Out[51]=
In[52]:=
missingpowers = Complement[Range[0, Max[existingpowers]], existingpowers]
Out[52]=

Use Tally to figure out how many copies of each term exist inside the sum (including the ones with coefficient 0):

In[53]:=
firsttally = Tally[basesum /. {h___[a_, b_] :> b, Inactive[Plus] -> List}]
Out[53]=
In[54]:=
realtally = ReverseSortBy[
  Join[firsttally, Transpose[{missingpowers, ConstantArray[0, Length[missingpowers]]}]], First]
Out[54]=

Now, collect the data:

In[55]:=
tallies = realtally[[All, 2]]
Out[55]=

Apply BaseForm to it:

In[56]:=
BaseForm[tallies, q]
Out[56]=

The result is effectively the same as BaseForm[n,q]:

In[57]:=
BaseForm[n, q]
Out[57]=

Properties and Relations (4) 

Define an integer:

In[58]:=
int1 = 12345;

Express it as the sum of powers of 4:

In[59]:=
sum1 = ResourceFunction["InactiveSumOfPowers"][int1, 4]
Out[59]=

Confirm the result:

In[60]:=
Activate[sum1] == int1
Out[60]=

The same result can be achieved using {4} as a second argument instead of 4:

In[61]:=
Activate[sum1] == int1 == Activate[ResourceFunction["InactiveSumOfPowers"][int1, {4}]]
Out[61]=

Define a new (large) integer:

In[62]:=
int2 = 2*3*Factorial[1234];

Express it as the sum of (many) powers of 2 using a two-argument form and use Shallow to show a small snippet of the result:

In[63]:=
sum2 = ResourceFunction["InactiveSumOfPowers"][int2, 2];
Shallow[sum2]
Out[60]=

The same can be achieved using the one-argument form:

In[64]:=
sum2b = ResourceFunction["InactiveSumOfPowers"][int2];
Shallow[sum2b]
Out[52]=

Confirm the results:

In[65]:=
Activate[sum2] == int2 == Activate[sum2b]
Out[65]=

If n is a product of powers of the elements of list, then the output of InactiveSumOfPowers[n,list,…,"HoldListProducts"->True] will be an Inactive factorization of n:

In[66]:=
ResourceFunction["InactiveSumOfPowers"][4^9*7^15*71, {2, 7, 71}, "HoldListProducts" -> True]
Out[66]=

This is equivalent to the result returned by the resource function InactiveFactorInteger:

In[67]:=
ResourceFunction["InactiveFactorInteger"][4^9*7^15*71]
Out[67]=

It is also equivalent to the result returned by the resource function FormatFactorization, though the latter is formatted differently:

In[68]:=
ResourceFunction["FormatFactorization"][4^9*7^15*71]
Out[68]=

The equivalence of all three forms can be verified with a combination of Activate and ReleaseHold:

In[69]:=
Activate[
  ResourceFunction["InactiveSumOfPowers"][4^9*7^15*71, {2, 7, 71}, "HoldListProducts" -> True]] == Activate[ResourceFunction["InactiveFactorInteger"][4^9*7^15*71]] == Activate[
  ReleaseHold[ResourceFunction["FormatFactorization"][4^9*7^15*71]]]
Out[69]=

If a single base is given then InactiveSumOfPowers is equivalent to IntegerDigits:

In[70]:=
ResourceFunction["InactiveSumOfPowers"][12345, 7, "CollectLikeTerms" -> True]
Out[70]=

Compare to the result of IntegerDigits with some post-processing to show explicit powers:

In[71]:=
Inner[Times, IntegerDigits[12345, 7], Table[Inactive[Power][7, k], {k, IntegerLength[12345, 7] - 1, 0, -1}], Inactive[Plus]]
Out[71]=

Possible Issues (3) 

InactiveSumOfPowers remains unevaluated for a number of input types. The first element must be an integer, a List of integers, Infinity or -Infinity:

In[72]:=
ResourceFunction["InactiveSumOfPowers"][Pi]
Out[72]=
In[73]:=
ResourceFunction["InactiveSumOfPowers"][a + b]
Out[73]=
In[74]:=
ResourceFunction["InactiveSumOfPowers"][1.25]
Out[74]=

If the second argument is a List, all of its elements must be integer quantities greater than 1:

In[75]:=
ResourceFunction["InactiveSumOfPowers"][2*3*5*7, {1, 2}]
Out[75]=

The main use case for defining this function originally was to write a given integer as a sum of powers of primes. For example, this will express Factorial2[25]=7905853580625 as the sum of powers of 5 and 7:

In[76]:=
factorial2 = ResourceFunction["InactiveSumOfPowers"][Factorial2[25], {5, 7}]
Out[76]=

Given complicated sums like this, collecting like terms is a natural desire. As such, the functionality for "CollectLikeTerms"->True was built in:

In[77]:=
factorial2b = ResourceFunction["InactiveSumOfPowers"][Factorial2[25], {5, 7}, "CollectLikeTerms" -> True]
Out[77]=

The outcome is that factorial2b now has coefficients which are no longer in the list {5,7} of desired bases. Here are the coefficients not in the list {5,7}:

In[78]:=
undesiredcoeffs = DeleteCases[
  factorial2b /. {Inactive[Plus] -> List, Inactive[Times][a_, b_] :> a}, Inactive[Power][_, _]]
Out[78]=

This is a desired outcome of the algorithm, but it could ostensibly be an issue for some users.


Regardless of what is chosen for "HoldListProducts", InactiveSumOfPowers[p1n1p2n2pknk,list,…] results in the usual decomposition if any factor pi is not present in list. This is because the algorithm used in InactiveSumOfPowers looks for list to contain all of the pi when considering whether n=p1n1p2n2pknk is a "list product":

In[79]:=
ResourceFunction["InactiveSumOfPowers"][2^9*3^15*5, {2, 3}, "HoldListProducts" -> False]
Out[79]=
In[80]:=
ResourceFunction["InactiveSumOfPowers"][2^9*3^15*5, {2, 3}, "HoldListProducts" -> True]
Out[80]=

On the other hand, if list contains all of the factors p1,p2,…,pk plus additional items, "HoldListProducts"->False returns a different (though equivalent) factorization than "HoldListProducts"->True:

In[81]:=
ResourceFunction["InactiveSumOfPowers"][2^9*3^15*5, {2, 3, 5, 7}, "HoldListProducts" -> False]
Out[81]=
In[82]:=
ResourceFunction["InactiveSumOfPowers"][2^9*3^15*5, {2, 3, 5, 7}, "HoldListProducts" -> True]
Out[82]=

Neat Examples (3) 

As n increases, the number of terms in InactiveSumOfPowers[n] displays an interesting quasi-periodic pattern. First, compute the lengths:

In[83]:=
vals = Table[
   Length[ResourceFunction["InactiveSumOfPowers"][i, 2]], {i, 1, 10^3,
     1}];

Plot the values to observe the pattern:

In[84]:=
ListPlot[vals]
Out[84]=

For fixed n, the number of terms in InactiveSumOfPowers[n,m] tends to increase as m increases. First, declare a (large-ish) integer:

In[85]:=
large = 849761218
Out[85]=

Compute the lengths:

In[86]:=
lengths = Table[Length[ResourceFunction["InactiveSumOfPowers"][large, i]], {i,
     2, 150}];

Plot them:

In[87]:=
ListPlot[lengths]
Out[87]=

The growth appears to be roughly linear. Test that observation:

In[88]:=
lm = LinearModelFit[lengths, x, x]
Out[88]=

Check the goodness of fit, visually:

In[89]:=
Show[{
  ListPlot[lengths],
  Plot[lm[x], {x, 0, 150}, PlotStyle -> Red]
  }]
Out[89]=

Check the goodness of fit mathematically as well:

In[90]:=
lm["RSquared"]
Out[90]=
In[91]:=
lm["AdjustedRSquared"]
Out[91]=

Create a multiplication table where InactiveSumOfPowers (and a little formatting) has been applied to each product. First, create the data:

In[92]:=
nums = # & /@ Table[Times[i, j], {i, 0, 12}, {j, 0, 12}] /. {a_Integer :> Style[a, FontWeight -> Bold]};
sums = ResourceFunction["InactiveSumOfPowers"][#, {2, 3}] & /@ Table[Times[i, j], {i, 0, 12}, {j, 0, 12}];
table = Table[
    Transpose[{%%[[i]], %[[i]]}], {i, 1, 13}] /. {List[Style[a_Integer, Rule[FontWeight, Bold]], b_] :> Column[List[Style[a, Rule[FontWeight, Bold]], b]]};

Then, display a stylized version of the table:

In[93]:=
fulltable = TextGrid[
  Join[{Join[{Item[Style["\[Times]", Larger], Background -> Lighter@ Orange, Alignment -> Center]}, Table[i, {i, 0, 12}]]}, MapIndexed[Prepend[#1, First[#2] + 0 - 1] & , table]],
  Frame -> All, FrameStyle -> Directive[GrayLevel[0.6]], Background -> {1 -> Lighter@LightOrange, 1 -> Lighter@LightOrange}, ItemSize -> {{{2, ConstantArray[13, 13] /. {List -> Sequence}}}}, Alignment -> {Left, Top}, Spacings -> {1, Automatic}]
Out[93]=

Check the activated version for correctness:

In[94]:=
Activate[
 fulltable /. {(ItemSize -> _) -> (ItemSize -> {{Join[{2}, ConstantArray[3, 13]]}})}]
Out[94]=

Publisher

therealcstover

Version History

  • 1.0.0 – 15 July 2022

Related Resources

Author Notes

Implementation Notes

By default, InactiveSumOfPowers[n,{p1,,pk}] generally performs the following algorithm to determine the factorization of n:
Determine the largest integers α1,,αk for which p1α1,,pkαk all divide n.
Compute m1=Max[p1α1,,pkαk]. m1 is the first term of the factorization of n.
Repeat the the process for n1=n-m1 to find the second term of the factorization.
Continue iterating until the resulting integer nβ either equals 0 or 1.

v1.0.0

In future versions, better handling of the "power of list" case will be included. For instance, I would argue that
In[1]:=
InactiveSumOfPowers[2^9*3^15*5, {2, 3, 5, 7}, "HoldListProducts" -> True]

should actually be something like

In[2]:=
\!\(
TagBox[
StyleBox[
RowBox[{
RowBox[{"Inactive", "[", "Times", "]"}], "[", 
RowBox[{
RowBox[{
RowBox[{"Inactive", "[", "Power", "]"}], "[", 
RowBox[{"2", ",", "9"}], "]"}], ",", 
RowBox[{
RowBox[{"Inactive", "[", "Power", "]"}], "[", 
RowBox[{"3", ",", "15"}], "]"}], ",", 
RowBox[{
RowBox[{"Inactive", "[", "Power", "]"}], "[", 
RowBox[{"5", ",", "1"}], "]"}], ",", 
RowBox[{
RowBox[{"Inactive", "[", "Power", "]"}], "[", 
RowBox[{"7", ",", "0"}], "]"}]}], "]"}],
ShowSpecialCharacters->False,
ShowStringCharacters->True,
NumberMarks->True,
"NodeID" -> 88],
FullForm]\)

instead.

I already have a fix written for this. Whenever I implement it, I’ll be sure to edit info in "Options", D&O and any other places.
Design changes may be implemented to change the behavior discussed in "Possible Issues":
In[3]:=
InactiveSumOfPowers[2^9*3^15*5, {2, 3}, "HoldListProducts" -> True]
In[4]:=
InactiveSumOfPowers[2^9*3^15*5, {2, 3}, "HoldListProducts" -> False]
In[5]:=
InactiveSumOfPowers[2^9*3^15*5, {2, 3, 5, 7}, "HoldListProducts" -> True]
In[6]:=
InactiveSumOfPowers[2^9*3^15*5, {2, 3, 5, 7}, "HoldListProducts" -> False]
Perhaps these scenarios should be handled the same? Or perhaps the first situation should be handled differently if "HoldListProducts" and "CollectLikeTerms" are both set to True?
For non-infinite n, I may extend InactiveSumOfPowers[n,list] to allow list to contain 1. I don't have strong opinions about this currently but it may happen in the future.

License Information