7
$\begingroup$

I am trying to use CenterDot and Superscript, in conjunction with Apply to write out the prime factorization of any given integer. Everything works well UNLESS the prime factorization of the number contains only one prime (to some power). This is because CenterDot must have two arguments I guess.

So let's get going here...

primeFactorForm[n_] := CenterDot[Apply[Superscript, FactorInteger[n], {1}]]
primeFactorForm[9]

gives me

CenterDot[3^2]

and I don't want that obviously. So I created another function to avoid this problem, and put it before my primeFactorForm function that I created....

myCenterDot[{a_^b_}] := a^b
myCenterDot[x_] := Apply[CenterDot, x]

and then I changed my original function

primeFactorForm[n_] :=
myCenterDot[Apply[Superscript, FactorInteger[n], {1}]]

So now it SHOULD just return a^b IF the input is in the form {a^b}, but it still returns

CenterDot[3^2]

instead of just writing it out like i want it to. What have I done wrong? Just some minor syntax errors I hope! Thanks very much in advance!

EDIT: Sorry guys, I should have also mentioned this: when I suggested to my instructor that I add an If statement, he said that doing what I did (creating two myCenterDot functions) would create the same end result without the need of creating an If statement. So he basically said that I can avoid the use of an If statement by doing this that way....hmmm....

$\endgroup$
3
  • 1
    $\begingroup$ You're right to suspect that CenterDot is getting tripped up over the fact that it needs two or more arguments. Adding an If statement to handle that case is one way to fix it. $\endgroup$ Sep 25, 2014 at 19:36
  • $\begingroup$ LonelyMathematician, please see my answer. I demonstrate that you do not need an If statement or two definitions, only a simple replacement to handle the case of a "singleton" in CenterDot. I also demonstrate how an actual formatting wrapper is created. $\endgroup$
    – Mr.Wizard
    Oct 2, 2014 at 17:34
  • $\begingroup$ You may be interested in the Performance section that I just appended to my answer. $\endgroup$
    – Mr.Wizard
    Oct 22, 2014 at 21:18

6 Answers 6

6
$\begingroup$

The existing answers work but I offer two improvements:

  • terse code via pattern replacement

  • making an actual formatting wrapper

This replacement rule strips the heads of any expressions with only one argument:

foo[1]    /. _[x_] :> x
foo[1, 2] /. _[x_] :> x
1

foo[1, 2]

Format is used to describe the output format without losing the original expression.

Proposal:

Format[primeFactorForm[n_Integer]] := 
  CenterDot @@ Superscript @@@ FactorInteger[n] /. _[x_] :> x

Now:

primeFactorForm[9]

$3^2$

out = primeFactorForm[5067678515625]

$3^3\cdot 5^8\cdot 11^3\cdot 19^2$

Look at the FullForm of out:

FullForm[out]
primeFactorForm[5067678515625]

You can therefore get the original integer with:

First @ out
5067678515625

Exponent one

If you wish to eliminate exponent one then you may use this instead:

Format[primeFactorForm[n_Integer]] := 
  CenterDot @@ Superscript @@@ FactorInteger[n] //. _[x_] | _[x_, 1] :> x

Example:

primeFactorForm[602744404968]

$2^3\cdot 3^2\cdot 41\cdot 131\cdot 307\cdot 5077$


Performance with large integers

Since I put the actual factorization in the formatting function my method will result in the same delay every time the expression is displayed. If you would prefer to optimize any re-display by recalling the earlier result we can add memorization of the Format function. (I discovered a small problem in that my usual mem : syntax does not work here as it interferes with formatting.) For example:

Format[primeFactorForm[n_Integer]] := Format[primeFactorForm[n]] =
  CenterDot @@ Superscript @@@ FactorInteger[n] //. _[x_] | _[x_, 1] :> x

Now the first display of primeFactorForm[int] takes a few seconds:

SeedRandom[0];
int = RandomInteger[1*^55];

primeFactorForm[int]

But a second display is instantaneous.

This of course consumes memory and it should not be used if a great many integers are to be displayed in this format in a given session.

$\endgroup$
2
  • $\begingroup$ this wins my vote. If exponent 1 to be suppressed, perhaps, CenterDot @@ (Superscript @@@ FactorInteger[n] /.Superscript[w_, 1] :> w) /. _[x_] :> x $\endgroup$
    – ubpdqn
    Oct 3, 2014 at 5:49
  • $\begingroup$ @ubpdqn Thanks for the vote. I appended your method to my answer, in my own style. $\endgroup$
    – Mr.Wizard
    Oct 3, 2014 at 8:47
5
$\begingroup$
primeFactorForm[n_Integer] := Module[{fact = FactorInteger[n]},
  If[Length[fact] == 1,
   Superscript @@ fact[[1]],
   CenterDot @@ Superscript @@@ fact]]

primeFactorForm[9]

enter image description here

primeFactorForm[72]

enter image description here

$\endgroup$
1
  • $\begingroup$ Very very smart +1 $\endgroup$
    – eldo
    Sep 25, 2014 at 19:28
3
$\begingroup$

One option is to define the formatting of CenterDot for the one argument case:

Format[CenterDot[a_]] := Format[a]

In[13]:= CenterDot @@ Apply[Superscript, FactorInteger[9], {1}]

Out[13]= $3^2$

Note that the FullForm of this output is CenterDot[Subscript[3,2]].

$\endgroup$
1
  • $\begingroup$ Good point. You could even just define CenterDot[a_] := a if you don't have other need of that operator. $\endgroup$
    – Mr.Wizard
    Oct 2, 2014 at 21:43
2
$\begingroup$

Another almost identical way:

primeFactorForm[n_] := 
  If[Length@# == 1, First@#, CenterDot @@ #] &[
   Superscript @@@ FactorInteger[n]];

Example output:

Column[primeFactorForm /@ RandomInteger[{0, 10000}, 10]]

enter image description here

$\endgroup$
2
$\begingroup$
stf[{_, 1}] := StringTemplate["`1`"];
stf[{_, _}] := 
  StringTemplate["\!\(\*SuperscriptBox[\(`1`\), \(`2`\)]\)"];
funcn[u_] := 
 StringJoin[
  Riffle[TemplateApply[stf[#], #] & /@ FactorInteger[u], 
   "\[CenterDot]"]]

Testing:

Grid[Style[#, 20] & /@ ({#, "=", funcn[#]}) & /@ Range[100]]

enter image description here

$\endgroup$
2
$\begingroup$

I prefer Mr Wizard's answer, but here is a method using the properties of Power and Times to deal with exponent 1 and single prime factors. Specifically:

  • Power[x, 1] gives x

  • Times[x] gives x

The prime factors are wrapped in Defer to prevent any further evaluation.

So:

primeFactorForm = 
 Times @@ Power @@@ MapAt[Defer, FactorInteger@#, {All, 1}] /. Times -> CenterDot &

primeFactorForm[121]
primeFactorForm[750]

$11^2$

$2\cdot 3\cdot 5^3$

$\endgroup$
1
  • $\begingroup$ Very nice; I always like solutions leveraging the properties of System functions. A bit more compact: Tr[Defer[#]^#2 & @@@ FactorInteger@#] /. Plus -> CenterDot & $\endgroup$
    – Mr.Wizard
    Oct 3, 2014 at 14:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.