Math 350 - Lecture 3

Structure of expressions and changing heads

Expressions

Consider the following:

a + b+ c

2 + 3 + 5

{a,b,c}

{2, 3, 5}

a b c

2 3 5

Each of these is an expression. We can look at the internal structure of these expressions using the command FullForm

FullForm[a + b + c]

FullForm[2 + 3 + 5]

Plus[2, 3, 5]

FullForm[{a, b, c}]

List[2, 3, 5]

FullForm[ a b c]

Times[2, 3, 5]

The “Plus”, “List”, or “Times” that we see in these expressions is called the head of the expressions. One of the most useful things we can do with expressions is to change the head.

Head[{a,b,c}]

Head[{a, {b, c}, { a, {a, b}}}]

The Apply function

Consider this command.

Apply[Plus, {a,b,c}]

Apply[Plus, {2, 3, 5}]

{2, 3, 5}//Head

Apply[Plus, a b c]

Plus is not a function, it is a type of expression head. The command Apply has replaced the existing head of {a, b, c}, which is List, with Plus. The effect 
of this change is to produce the sum of the data contained in the list.

Shorthand for Apply is @@.

Times @@ {a,b,c} (* switches List for Times *)

Plus@@ {a,b,c} (* switches List for Plus *)

Plus @@{{2, 3}, {3, 5}, {7,6}}

{Plus @@{2, 3}, Plus @@{3, 5}, Plus@@ {7,6}}

Plus @@@ {{2, 3}, {3, 5}, {7,6}}

Problem: Compute the sum of reciprocals of the first 10 factorials.

Range[10]

Range[10]! (* factorial is listable *)

1/Range[10]!

?Sum

?Plus

Plus @@ 1/Range[10]!

Apply[Plus, 1/Range[10]!]

Plus @@ (1/Range[10]!)

Apply[Plus, 1/Range[10]!]

Perfect numbers

Let’s consider the perfect numbers - that is, positive integers that are the sum of their proper divisors. The first is 6, as 1 + 2 + 3 =6. Suppose we ask Mathematica to find more of them.

Divisors[6]

Here, we can play with the myriad list manipulation commands. Most, with no parameters, will output all of a list minus the last element.

?Most

Most[Divisors[6]] //Head

Apply[Plus, Most[Divisors[6]]]

Alternatively,

Plus @@ Most[Divisors[6]]

Now, let’s turn this into a function

Plus @@ Most[Divisors[#]]&@10

Finally, we can use this function to find the perfect numbers by making it Boolean.

Plus @@ Most[Divisors[#]]==#&/@{6, 7, 8, 27, 28} (* perfect number finder*)

Select[Range[10000], Plus @@ Most[Divisors[#]]==#&]

Plus@@Most[Divisors[8128]]

Practical numbers

A positive integer is a practical number if every smaller integer can be formed as  sum of its divisors. Let’s try to find the practical numbers less than 100. As before, we’ll start with an example. 8 is a practical number, as 3 = 1 + 2, 5 = 1 + 4, 6 = 2 + 4, 7 = 1 + 2 + 4. How can we produce the set of possible sums with Mathematica?

Divisors[8]

{a,b,c}

Subsets[{a,b,c}] (* finds the power set of {a, b, c} *)

We can take advantage the fact that Apply can be used at different levels of a list. First, we’ll need to know all the possible combinations of divisors where each divisor can be appear at most one time. This can be done by finding all of the possible subsets.

Subsets[Most[Divisors[8]]]

Now, we’d like to find the sums of these lists inside the big list. So we’ll change heads, but at level 1 - that is, change the heads of sublists.

Plus @@@ Subsets[Most[Divisors[8]]]//Union

Organize the list into a set

possibleSums = Plus @@@ Subsets[Most[Divisors[8]]]//Union//Rest

Putting the union after the computation of the list of possible sums is an example of “piping” output with //, and typically makes calculations easier to read and debug.

Finally, we’ll check that the integers 1, ..., 7 are inside the list of possible sums of the divisors using the ContainsAll command.

?ContainsAll

ContainsAll[{1, 2, 3}, {1,2}]

ContainsAll[possibleSums,Range[8-1]]

Find all practical numbers from 1 to 100. Homework exercise.

Piping output

A constant concern with coding, and especially mathematical coding, is making functions easy to read and easy to debug. We saw an example of piping output on the previous slide.

2 // Sin

2 // Sin //N

MatrixForm[RowReduce[{{3, 2}, {1, 3},{1,1}}]]

{{3, 2}, {1,3}, {1, 1}}//RowReduce//MatrixForm

One use of // is to allow “afterthought” functions to be applied to outputs, instead of having to introduce a new function and brackets into the mix.

Table[{n, n^2, n^3}, {n, 1, 6}] //TableForm

We can also pull apart complicated nested functions into chains of logic. Here’s an approach to Exercise 3.3 along those lines.

OddQ[Select[Table[((m+3)^3+1)/(3m), {m, 1, 500}], IntegerQ]]

Table[((m+3)^3+1)/(3m), {m, 1, 500}]//Select[#, IntegerQ]&//Length

Table[((m+3)^3+1)/(3m), {m, 1, 500}]//Select[#, IntegerQ]&//OddQ