Wednesday's Lecture

Emergent Complexity

wondrous.c

// Some beautiful, wondrous numbers!
// 2017-08-30    Jashank Jeremy <{jashankj,z5017851}@cse.unsw.edu.au>
//
// In the space of positive integers, the Wondrous numbers are those
// numbers produced from two simple rules:
//
//  - for even numbers, n / 2
//  - for odd numbers, 3n + 1.
//
// And, as we saw, this gives us some interesting patterns: all
// numbers tend to converge, after some number of steps, to 4, 2, 1,
// where they would cycle forever.
//
// This forms an interesting unsolved problem in mathematics, known as
// the Collatz Conjecture: will all positive integers reduce back to
// this sequence.

#include <stdio.h>
#include <stdlib.h>

int wondrous (int number);

int main (int argc, char *argv[]) {
    int start = 1;
    while (start < 100) {
        int number = start;
        printf ("%d: ", number);
        int steps = 0;
        while (number != 1) {
            printf ("%d, ", number);
            number = wondrous (number);
            steps++;
        }

        printf ("1. %d steps.\n", steps);
        start++;
    }

    return EXIT_SUCCESS;
}

int wondrous (int number) {
    if (number % 2 == 0) {
        number = number / 2;
    } else {
        number = 3 * number + 1;
    }
    return number;
}
$ ./wondrous
1: 1. 0 steps.
2: 2, 1. 1 steps.
3: 3, 10, 5, 16, 8, 4, 2, 1. 7 steps.
4: 4, 2, 1. 2 steps.
5: 5, 16, 8, 4, 2, 1. 5 steps.
6: 6, 3, 10, 5, 16, 8, 4, 2, 1. 8 steps.
7: 7, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1. 16 steps.
8: 8, 4, 2, 1. 3 steps.
9: 9, 28, 14, 7, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1. 19 steps.
10: 10, 5, 16, 8, 4, 2, 1. 6 steps.
11: 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1. 14 steps.
12: 12, 6, 3, 10, 5, 16, 8, 4, 2, 1. 9 steps.
13: 13, 40, 20, 10, 5, 16, 8, 4, 2, 1. 9 steps.
14: 14, 7, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1. 17 steps.
15: 15, 46, 23, 70, 35, 106, 53, 160, 80, 40, 20, 10, 5, 16, 8, 4, 2, 1. 17 steps.
16: 16, 8, 4, 2, 1. 4 steps.
17: 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1. 12 steps.
18: 18, 9, 28, 14, 7, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1. 20 steps.
19: 19, 58, 29, 88, 44, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1. 20 steps.
20: 20, 10, 5, 16, 8, 4, 2, 1. 7 steps.
21: 21, 64, 32, 16, 8, 4, 2, 1. 7 steps.
22: 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1. 15 steps.
23: 23, 70, 35, 106, 53, 160, 80, 40, 20, 10, 5, 16, 8, 4, 2, 1. 15 steps.
24: 24, 12, 6, 3, 10, 5, 16, 8, 4, 2, 1. 10 steps.
25: 25, 76, 38, 19, 58, 29, 88, 44, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1. 23 steps.
... and many, many more.

rules.c

This is closely related to a challenge exercise, so the full code for this demo won’t be available. Instead, you should go check out the Cellular Automaton activity on WebCMS3. You might like to play with it, and expand the things you do with that activity… here are some hints to help out.

// Simple 1-D cellular automaton rules.
// 2017-03-30    Jashank Jeremy <{jashankj,z5017851}@cse.unsw.edu.au>
// 2017-08-30    Jashank Jeremy <{jashankj,z5017851}@cse.unsw.edu.au>
//
// You might like to try exploring other rules, and here's a fragment
// of code to set up an array of other rules.  Change the `#define`d
// value `RULE` to a value from 0 to 255, to explore some other rules.
//
// Rule 30, for example, goes something like:
//
//     ### | ##  | # # | #   |  ## |  #  |   # |
//      0  |  0  |  0  |  1  |  1  |  1  |  1  |  0
//
// And, as those of you who are bit-wise (ho, ho, ho) this is the
// binary representation of thirty, and each of the cells there
// corresponds to a cell in the array.
//
// The next state of the grid, then, looks like:
//
//     (prevline[i-1] * 4) + (prevline[i] * 2) + (prevline[i+1] * 1)
//
// ... which gives an index into the `rule` array, for the particular
// value that we care about.

#include <stdio.h>
#include <stdlib.h>

#define RULE 30

int main (int argc, char *argv[]) {
    int rule[8] = { 0 };

    int num = RULE;
    int i = 0;
    while (num != 0) {
        rule[i] = num % 2;
        num /= 2;
        i++;
    }

    printf ("### | ##  | # # | #   |  ## |  #  |   # |     \n");
    printf (" %d  |  %d  |  %d  |  %d  |  %d  |  %d  |  %d  |  %d  \n",
        rule[7], rule[6], rule[5], rule[4],
        rule[3], rule[2], rule[1], rule[0]);

    return EXIT_SUCCESS;
}

Here’s a very, very small region of rule 30:

[rule.c: the 1-D cellular automaton, rule 30]

Here’s a screenshot of 900 columns, 300 rows of rule 30.

[rule.c: the 1-D cellular automaton, rule 30]

Try some other rules! We saw rule 17, 110, 254, and 255 during the lecture and the break.

At no point, of course, did I put anything resembling a triangle in.

arg.c

// No argument here.
// 2017-08-30   Jashank Jeremy <{jashankj,z5017851}@cse.unsw.edu.au>
//
// This simple program prints out its command-line arguments from the
// "argument vector", `argv`.

#include <stdio.h>
#include <stdlib.h>

int main (int argc, char *argv[]) {
    int i = 0;
    while (i < argc) {
        printf ("%s\n", argv[i]);
        i++;
    }
}

If I now go and run this:

$ dcc -o arg arg.c
$ ./arg
./arg
$ ./arg aoeu id htns
./arg
aoeu
id
htns
$ ./arg -o arg arg.c
./arg
-o
arg
arg.c

arg2.c

// No argument here.
// 2017-08-30   Jashank Jeremy <{jashankj,z5017851}@cse.unsw.edu.au>
//
// This simple program takes the first value in the argument vector,
// scans it in as a decimal using the `sscanf` function, and prints it
// out in hexadecimal.

#include <stdio.h>
#include <stdlib.h>

int main (int argc, char *argv[]) {
    if (argc < 2) {
        printf ("Uh, no, you've misused this program.\n");
        return EXIT_FAILURE;
    }

    int i = -1;
    sscanf (argv[1], "%d", &i);
    printf ("%x\n", i);

    return EXIT_SUCCESS;
}

scanf and sscanf will match, character for character, the format string, except for the format codes, introduced with the % character, and will snap back into exactly matching once it cannot read more of the format.

array.h

// Hip, hip, array!
// 2017-08-30   Jashank Jeremy <{jashankj,z5017851}@cse.unsw.edu.au>
//
// A header file allows us to keep `#define`s, `typedef`s, `struct`s,
// and function prototypes -- the things that would usually appear in
// the prelude of a C file -- in a separate file...

#ifndef _ARRAY_H_
#define _ARRAY_H_

#define ARRAY_SIZE 16

void printArray (int array[ARRAY_SIZE][ARRAY_SIZE]);

#endif
Aside: typedef and arrays

I could, though I didn’t during the lecture, typedef this array, so I could change its type more readily:

typedef int triangle[ARRAY_SIZE][ARRAY_SIZE];

This is a bit confusing, so I’ll break it down: here’s the portion of this typedef that is the existing type name:

typedef int triangle[ARRAY_SIZE][ARRAY_SIZE];
//      ^~~         ^~~~~~~~~~~~~~~~~~~~~~~~

And here is the new type name.

typedef int triangle[ARRAY_SIZE][ARRAY_SIZE];
//          ^~~~~~~~

So I could change all my functions to be the much less scary, and much quicker and easier to type:

void printArray (triangle array);

array.c

// Hip, hip, array!
// 2017-08-30   Jashank Jeremy <{jashankj,z5017851}@cse.unsw.edu.au>
//
// ... that may then be `#include`d into multiple other files, like
// this one, and the two `printArray` variants here.

#include <stdio.h>
#include <stdlib.h>

#include "array.h"

void adder (int x, int y, int array[ARRAY_SIZE][ARRAY_SIZE]);

int main (int argc, char *argv[]) {
    // Create a square array, and seed it with an initial value.
    int array[ARRAY_SIZE][ARRAY_SIZE] = 0;
    array[0][ARRAY_SIZE / 2] = 1;

    int x = 1;
    while (x < ARRAY_SIZE) {
        int y = 1;
        while (y < ARRAY_SIZE - 1) {
            adder (x, y, array);
            y++;
        }
        x++;
    }
    printArray (array);

    return EXIT_SUCCESS;
}

void adder (int x, int y, int array[ARRAY_SIZE][ARRAY_SIZE]) {
    array[x][y] = array[x - 1][y - 1] + array[x - 1][y + 1];
}

printArray.c

// Print an array.
// 2017-08-30   Jashank Jeremy <{jashankj,z5017851}@cse.unsw.edu.au>
//
// Simple, clean, and to the point.  We can reuse this function again
// and again, and it will print out a two-dimensional array.

#include <stdio.h>
#include <stdlib.h>

#include "array.h"

void printArray (int array[ARRAY_SIZE][ARRAY_SIZE]) {
    int x = 0;
    while (x < ARRAY_SIZE) {
        int y = 0;
        while (y < ARRAY_SIZE) {
            printf ("\t%d", array[x][y]);
            y++;
        }
        printf ("\n");
        x++;
    }
}

printArrayWithoutZeros.c

// Print an array
// 2017-08-30   Jashank Jeremy <{jashankj,z5017851}@cse.unsw.edu.au>
//
// This variant hides values if they're zero, but otherwise conforms
// to the same interface that we have for printing out an array.

#include <stdio.h>
#include <stdlib.h>

#include "array.h"

void printArray (int array[ARRAY_SIZE][ARRAY_SIZE]) {
    int x = 0;
    while (x < ARRAY_SIZE) {
        int y = 0;
        while (y < ARRAY_SIZE) {
            printf ("\t");
            if (array[x][y] != 0) {
                printf ("%d", array[x][y]);
            }
            y++;
        }
        printf ("\n");
        x++;
    }
}

printArrayModThree.c

// Print an array
// 2017-08-30   Jashank Jeremy <{jashankj,z5017851}@cse.unsw.edu.au>
//
// This one uses a magic escape code to highlight numbers where the
// number is a divisor of three.  It also shows only the smallest
// seven digits of the number.

#include <stdio.h>
#include <stdlib.h>

#include "array.h"

void printArray (int array[ARRAY_SIZE][ARRAY_SIZE]) {
    int x = 0;
    while (x < ARRAY_SIZE) {
        int y = 0;
        while (y < ARRAY_SIZE) {
            printf ("\t");
            if (array[x][y] != 0 && array[x][y] % 3 == 0) {
                printf ("\033[7m%7d\033[0m", array[x][y] % 10000000);
            } else if (array[x][y] != 0) {
                printf ("%7d", array[x][y] % 10000000);
            }
            y++;
        }
        printf ("\n\n");
        x++;
    }
}
$ dcc -o array array.c printArrayModThree.c
$ ./array
many, many numbers, some highlighted...

[array.c + printArrayModThree.c: a Pascal's triangle]

What if I do it modulo 5?

[array.c + printArrayModFive.c: a Pascal's triangle]

TRIANGLES! AGAIN!