Diary for 01:090:101:21, Experimental Math, fall 2008

The eighth meeting, 10/27/2008


Discussion
I hope that students will present some of the results obtained from considering Mr. Rowland's problems. But then ... Actually, and better than I had planned, we spent essentially the whole time discussing matters related to Mr. Rowland's problems. I am very happy this happened. Several people contributed some witty observations. And I tried to record the essentials of the discussion here. But if students are curious what we might have discussed, read what is below. Next week, PICTURES!

Fame! Immortality!! Power!!! money?
When I thought about this seminar during the late summer, one goal was to have students send sequences to Neil Sloane's Encyclopedia of Integer Sequences. This was my idea for a "term paper" which was mentioned at the first meeting. I tried to think of suitable hints, in case students lacked ideas. Here are some things I tried, and the results. I confess that a certain amount of ... well, a diplomatic word would be "enthusiasm" but perhaps a more descriptive term would be "craziness" ... developed as I worked on this. You'll see.

Chopping up 1+2+...+n
My first attempt was to look at a topic that we considered early in the course. We had found a formula for computing the sum 1+2+3+...+(n-1)+n. The result was n(n+1)/2. So I thought about this, and said that maybe sometimes we could chop up 1+2+3+...+(n-1)+n into two chunks, let's say 1+2+3+...+k and (k+1)+(k+2)+...+n, and these pieces would have equal size. A sort of illustration is shown to the right below. Then I used Maple to experiment and find some n's for which this would be true.

First, I defined the formula for the sum of the integers. These sums are called triangular numbers. I then checked it.

> formula:=n->n*(n+1)/2;
              formula := n -> 1/2 n (n + 1)
> formula(6);add(j,j=1..6);
                           21
                           21

Now I tried to detect if we could chop the triangular sum as I mentioned.

chop := proc(n)
local k;
    for k to n do 
       if formula(k) = 1/2*formula(n) 
            then print(n) 
       end if
    end do
end proc
This command would print n if the sum could be "chopped" as I indicated, and otherwise it would print nothing. And then I ran the command seq(chop(j),j=1..10000);. The results slowly trickled out. They were
     3     20     119     696     4059
We checked the Encyclopedia and found A001652 which had a very long description, and part of it was Solution to a(a+1)=2b(b+1) in natural numbers including 0; and this was certainly our sequence. I was sad. I wanted to find new sequences, and show students some possibilities for new sequences. Actually, a(a+1)=2b(b+1) is a form of Pell's equation which was studied in Europe about 250 years ago. In fact, individuals in India had found methods of solution a thousand years before that, and special cases had been investigated in Greece and India even two thousand years ago. There have been smart (and crazy!) people around for quite a while.

Or really reaching into 1+2+...+n
I didn't want to give up. Or maybe I shouldn't give up so soon. We could look a bit more carefully into the triangular number setup. Maybe instead of chopping so simply into two "separate" parts, we could look instead at selecting numbers from the collection {1,2,3,4,...,n-1,n}. So we could group them into two parts and look for parts which have the same sum.
I looked first for some example, so that I could better understand my own imprecise question. So consider the integers from 1 to 8:
     1     2     3     4     5     6     7     8
and now "split up" these integers into two groups. So consider the numbers 1     2     3     4     8 which have sum equal to 18, while the other numbers, 5     6     7, also have sum equal to 18.

I wanted to try to detect such situations. But honestly I was getting a bit scared. I am certainly not a terrific computer programmer (as you certainly know by now), and as I contemplated how to search for these "dissections" with equal sums I decided, hey, maybe it is too complicated. I wanted help so after a while I typed help(subset) and read some of the results, and looked at the command subsets, which is part of the package combinat (an abbreviation for the word "combinatorial"). There's an important lesson here, independent of this topic and even independent of the seminar. You are at the pyramid of a huge amount of human effort -- take advantage of what's been done if this is at all possible. Be clever -- you don't need to invent the wheel if someone else has already done it.

Using subsets
If you read the help page carefully, you can see that subsets actually makes a program to list the subsets of the set. I didn't read the page very carefully. I skimmed it and looked directly at the example given (bad habit, but it is what I usually do). So here is a piece of computer code I "wrote" after reading the help page for subsets, followed by the result.

> with(combinat):
> S:=subsets({frog,toad,cow}): 
> while not S[finished] do S[nextvalue]() end do;
                         {}
                        {cow}
                       {frog}
                       {toad}
                     {frog, cow}
                     {toad, cow}
                     {frog, toad}
                  {frog, toad, cow}
What I try to do is look at the examples in the help message, and maybe modify them slightly so I can pretend to understand them. More importantly, I can use the command without understanding what's inside it and without understanding how it is written. Of course, a critic could declare I've changed the worry to "Why should I trust the creators of this code?" but that sort of worry could occur each time I step into an elevator. Here is a version of my next procedure.
> test:=proc(n) T:={seq(j,j=1..n)}; total:=add(j,j=T);print(T,total);
> S:=subsets(T); while not S[finished] do Q:=S[nextvalue]();
> A:=add(j,j=Q);if total-A=A then print(A,Q) end if end do end proc;
Warning, `T` is implicitly declared local to procedure `test`
Warning, `total` is implicitly declared local to procedure `test`
Warning, `S` is implicitly declared local to procedure `test`
Warning, `Q` is implicitly declared local to procedure `test`
Warning, `A` is implicitly declared local to procedure `test`
test := proc(n)
local T, total, S, Q, A;
    T := {seq(j, j = 1 .. n)};
    total := add(j, j = T);
    print(T, total);
    S := combinat:-subsets(T);
    while not S[finished] do
        Q := S[nextvalue]();
        A := add(j, j = Q);
        if total - A = A then print(A, Q) end if
    end do
end proc
Notice that Maple cleaned up my presentation, and declared the names I used inside the program as local. My work almost always needs such help. Now I tried the program twice.
> test(5);
                              {1, 2, 3, 4, 5}, 15
> test(8);
                         {1, 2, 3, 4, 5, 6, 7, 8}, 36
                                 18, {3, 7, 8}
                                 18, {4, 6, 8}
                                 18, {5, 6, 7}
                               18, {1, 2, 7, 8}
                               18, {1, 3, 6, 8}
                               18, {1, 4, 5, 8}
                               18, {1, 4, 6, 7}
                               18, {2, 3, 5, 8}
                               18, {2, 3, 6, 7}
                               18, {2, 4, 5, 7}
                               18, {3, 4, 5, 6}
                              18, {1, 2, 3, 4, 8}
                              18, {1, 2, 3, 5, 7}
                              18, {1, 2, 4, 5, 6}
So it apparently worked! By the way, I am skipping the inevitable typing errors and even (sigh!) a few logical errors. The program reports there is no way of splitting the positive integers from 1 to 5 into two groups with equal sum. And there are (let's count) 7 ways of breaking up the integers from 1 to 8 into two such groups. Notice that the groups are counted twice. So {3, 7, 8} appears as does what is not in it, {1, 2, 4, 5, 6}. So I'm still trying to get into the Integer Sequence Hall of Fame. What can I do? I could try to create a sequence which counts these solutions.

Counting the equal-summed breakups
Here is my new procedure, exactly as I typed it, and then you can read the "echo" by Maple, which is much prettier and more precise. sigh

> newtest:=proc(n) local T, total, S, Q, A;
> T:={seq(j,j=1..n)}; total:=add(j,j=T); count:=0;
> S:=subsets(T); while not S[finished] do
> Q:=S[nextvalue]();A:=add(j,j=Q);
> if total-A=A then count:=count+j end if end do;
> if count>0 then print(count/2) end if end proc;
Warning, `count` is implicitly declared local to procedure `new_test`
newtest := proc(n)
local T, total, S, Q, A, count;
    T := {seq(j, j = 1 .. n)};
    total := add(j, j = T);
    count := 0;
    S := combinat:-subsets(T);
    while not S[finished] do
        Q := S[nextvalue]();
        A := add(j, j = Q);
        if total - A = A then count := count + 1 end if
    end do;
    if 0 < count then print(count/2) end if
end proc
I had to change print(count) in the original version to print(count/2) if I just wanted to know the number of distinct solutions, since (as we saw) this double counts solutions. Look:
> newtest(8);
                                       7
The running time of this sort of program tends to increase very rapidly with n, because the number of subsets of {1,2,3,...,n} is 2n. For example, newtest(20) returns the number 7636 on my home PC, but takes about 50 seconds. The time is needed because 220 is 1,048,576 which is large if some checking needs to be done at each instance. I tried
>seq(newtest(j),j=1..15);
                                       1
                                       1
                                       4
                                       7
                                      35
                                      62
                                      361
and I looked up this sequence in the Encyclopedia. The result was A124624, which was described as "Erroneous version of A058377." The word "erroneous" was interesting, and the reference to another sequence was more interesting. A058377 is described as "Number of solutions to 1+-2+-3+-...+-n=0." That is, how many ways are there to put + and - signs in front of 1   2   3   ...   n-1   n and end up with 0 (starting with a + in front of the 1). If you think about it a bit, this is exactly the problem we're doing. The +'s put the numbers in one subset, and the -'s put them in another. The result is 0 exactly when the two sets have equal sums.

New uses?
I still wanted to get ways for people to find interesting new sequences. First, I cleaned up the program a bit so it would produce 0's where Sloane wanted them.

newtestB := proc(n)
local T, total, S, Q, A, count;
    T := {seq(j, j = 1 .. n)};
    total := add(j, j = T);
    count := 0;
    S := combinat:-subsets(T);
    while not S[finished] do
        Q := S[nextvalue]();
        A := add(j, j = Q);
        if total - A = A then count := count + 1 end if
    end do;
    count/2
end proc;
and tried it. The result is below and it is exactly as A058377 is presented.
> seq(newtestB(j),j=1..15);
                0, 0, 1, 1, 0, 0, 4, 7, 0, 0, 35, 62, 0, 0, 361
When the procedure ends with the line count/2 the value of that quantity is printed.

Splitting up the squares
We can easily check for splittings of the squares with a small change.

newtestC := proc(n)
local T, total, S, Q, A, count;
    T := {seq(j^2, j = 1 .. n)};
    total := add(j, j = T);
    count := 0;
    S := combinat:-subsets(T);
    while not S[finished] do
        Q := S[nextvalue]();
        A := add(j, j = Q);
        if total - A = A then count := count + 1 end if
    end do;
    count/2
end proc;
I tried it and got
> seq(newtestC(j),j=1..20);
0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 5, 0, 0, 43, 57, 0, 0, 239, 430
This took a while to run on my home PC, and the result is the beginning of A083527. By the way, I hope that students will notice some structure in these sequences -- there are non-zero chunks separated by pools (?) of 0's. What is going on?

When we try cubes and fourth powers, we don't seem to have "collisions". These sequences seem to increase too quickly. By the way, the craziness we are currently discussing, which seems totally unreal and silly, turns out to be closely related to the knapsack problem: how to package "objects" of different sizes. The problem arises in many strange ways and is very important computationally.

We could try even integers, but that would be silly (why?) but how about odd integers? This won't be much additional work. We only need to change the instruction T := {seq(j^2, j = 1 .. n)};. If we replace j^2 by 2*j+1, we will be splitting the odd integers into two pieces and counting the pieces which have equal sums. Here is the result:

 0, 0, 0, 1, 0, 1, 0, 4, 0, 9, 0, 31, 0, 94, 0, 319
I always worry if these things really work. The first 1 is in the fourth place, where we would consider the first four odd numbers, 1   3   5   7. Notice that 3+5=1+7, so, yes, the result checks there. This sequence does not seem to be in the Encyclopedia! Neither is the result for 3*j+2, which starts
 0, 0, 0, 1, 0, 0, 0, 4, 0, 0, 5, 29, 0, 0, 78, 264
and for 5*j+3, which starts
 0, 0, 0, 1, 0, 0, 0, 4, 0, 0, 0, 29, 0, 0, 0, 263

Again, probably more interesting is understanding the zeros and why they are there. But that will involve some thinking so I invite students to do it, while I discuss silly computer pursuits.

Splitting three ways
We could try to group the elements of {1,2,3,4,...,n-1,n} into three chunks which have equal sums. There's more effort involved. I needed to learn a new instruction, minus, which takes elements of one set away from another set.

> {frog,toad,cow,elephant} minus {elephant,tiger};
                               {cow, frog, toad}
Then I needed to look at subsets of certain subsets! Things are getting a bit crazy. What's below finds and counts the number of times the elements of {1,2,3,4,...,n-1,n} can be broken into three parts with equal sums.
newtestD := proc(n)
local T, total, S, Q, A, count, R, S1, Q1, A1;
    T := {seq(j, j = 1 .. n)};
    total := add(j, j = T);
    count := 0;
    S := combinat:-subsets(T);
    while not S[finished] do
        Q := S[nextvalue]();
        A := add(j, j = Q);
        if total/3 = A then
           R:=T minus Q;
           S1:=subsets(R);
           while not S1[finished] do
              Q1:=S1[nextvalue]();  
              A1:=add(j,j=Q1);
              if total/3=A1 then  count := count + 1 end if
           end do;
        end if
    end do;
    count/6
end proc;
The only slightly amusing thing is the division by 6 in the last instruction. That's needed because this remarkably inefficient procedure counts each satisfactory splitting 6 times (just as we counted the splitups into two pieces twice, because each element of each pair was counted in both positions. Here there are three positions, and six possible ways to count.

Here are the first twelve answers.

0, 0, 0, 0, 1, 1, 0, 3, 9, 0, 43, 102
and this is A112972. Maybe it is time to give up! With squares, the first non-zero entry is the thirteenth. We could split up odd numbers into three parts with equal sums. Here is a count of how often that's successful:
0, 0, 0, 0, 0, 1, 0, 0, 2, 4, 0, 32, 41, 0, 332, 822
This isn't in the Encyclopedia! What wonderful, insane joy! Send it in now!!!

Seminar "assignment"
Put a sequence of your own in the Encyclopedia.
You can use one of these if you like.

Next time will be much more relaxed. We will draw some pretty pictures. Maybe the most interesting (?) sequence I found during the browsing which occurred as I prepared this material was A035470, which has description "Number of ways to break {1,2,3,...n} into sets with equal sums." There must (?) be something useful about that sequence.


Maintained by greenfie@math.rutgers.edu and last modified 10/26/2008.