Design Computation
Render as Slideshow | Accordion

Multiplicity

We want to be able to control not just single things at a time, but many things. The power of computational machines is most directly seen when we ask the machine to execute small pieces of code repeatedly. If we can parameterize the repetition and built rules about how to change the process slightly with each iteration, we can begin to produce complexity from very simple rules.

Repetition and Variation

A computational system is best at replicating and producing patterns of processes. Once we can codify a process into a simple set of executable instructions, we can begin to manipulate a set of parameters in an iterative way. Slight changes in how we handle these instructions, in both the values of our data and the rules that govern them, can result in a richness of complexity that stems from a simple change in a simple repeated process.

Parameterized Multiplicity

So far, we have parameterized form a very particular way. We use variables to hold numeric values that are used to create geometries. We have rules that govern the appropriate values for these “parameters,” so called because of how they are used in our sketches. The next stage is to see the rules and parameters that can govern the handling of many things. How do we parameterize multiplicity so we can control the number of things we are modeling, their behaviors, and even the rules that create, destroy, and changes those things?

Reading

  1. All
    In Processing, read
    “Control 2: Repetition”, pgs 61-68 and “Shape 2: Vertices” pgs 69-77
    “Data 4: Arrays”, pgs 301-313
  2. Supplementary
    For the assignment, in Processing, read:
    “Image 1: Display, Tint”, pgs 95-99
    “Typography 1: Display”, pgs 111-116
    “Input 1: Mouse I”, pgs 205-215
    “Input 2: Keyboard”, pgs 223-227
    “Input 3: Events”, pgs 229-236

Assignment

Find here the multiplicity assignment

Arrays

  1. Arrays
    1. Taming Multiplicity
    2. Names as mechanisms of control
    3. Example of singularity
    4. Example of multiplicity
    5. Basics of arrays

Taming Multiplicity

Changing single variables works to make geometry dynamic, but what about a hundred geometries, or a thousand?

Multiplicity always been easy on the mind and hard on the hand.

In a way, computer science and computation are forms of idealized engineering. You can make thousands of the same object, all differentiated in some way, with ease. The problem of production has been solved.

This is great as long as you don’t need a physical realization of that object, but in architecture, that is ultimately our primary concern. A bridge to the physical world still being developed by various industries (3D printers, CNC machines, etc.).

Names as a Mechanism of Control

We’re all special to our parents. But to the government, we’re all just numbers.

The cost of multiplicity is in referencing the objects to control.

Variables are the mechanism for control in computation. We choose a name for a value, associate that value with a geometry, object, or behavior, and we can consequently control that geometry, object, or behavior.

Control

What do you call the one circled in red?

The act of naming is a referencing mechanism in the real world. By naming a pet, we can establish a means of communication, and ultimately one means of control. We name things that are truly singular or unique, like people, pets, ships, countries, etc.

We have been naming individual variables so far, but that only works to a point. But if we need a thousand objects, we don’t necessarily want thousands of variables, each with a different name.

Other Means of Reference

However much we may wish license plates were about individuality, they are fundamentally a means of mass control.

But naming isn’t the only way to reference things. What is the name of your second dining room chair? It doesn’t have a name, but you don’t have a problem referencing it.

Next we will learn how to apply the productive power of the machine to the production of names.

Example of Singularity

A single circle moving in a sinuisoidal fashion.

Creating one object and making it move is what we have been implementing so far.


float startX, startY;
float x, y;
float rot, amp, speed, radius;
color c;  // "color" is a Processing data type.
float t;

void setup() {
  size(700, 400);
  smooth();

  radius = 20 + random(20);
  startX = random(width);
  startY = random(height);
  c = color(random(255), random(255), 
               random(255), 150); // line break!
  rot = random(TWO_PI);
  amp = 20 + random(100);
  speed = random(1, 10);
  t = 0;
  
  noStroke();
}

void draw() {
  background(255);

  fill(c);
  x = t*amp*cos(rot) + startX;
  y = t*amp*sin(rot) + startY;
  ellipse(x, y, radius, radius);
  
  t = sin( radians( speed*frameCount ) );
}

Example of Multiplicity

500 sinuisoidal circles moving at the same time.

If you want 500 moving circles, it’s best not to declare 500 * 10 or 5000 variables. So we use a data structure called “arrays” to help us.

The next few pages are on how arrays and loops work together to provide our first means of multiplicity and mass control.


int numBalls = 500;

float[] startX = new float[numBalls];
float[] startY = new float[numBalls];
float[] x = new float[numBalls];
float[] y = new float[numBalls];
float[] rot = new float[numBalls];
float[] amp = new float[numBalls];
float[] speed = new float[numBalls];
float[] radius = new float[numBalls];
color[] c = new color[numBalls];
float[] t = new float[numBalls];

void setup() {
  size(700, 400);
  smooth();

  for( int i=0; i < numBalls; i++ ){
    radius[i] = 20 + random(20);
    startX[i] = random(width);
    startY[i] = random(height);
    c[i] = color(random(255), random(255), 
       random(255), 150);
    rot[i] = random(TWO_PI);
    amp[i] = 20 + random(100);
    speed[i] = random(1, 10);
    t[i] = 0;
  }
  
  noStroke();
}

void draw() {
  background(255);

  for( int i=0; i < numBalls; i++ ){
    fill( c[i] );
    x[i] = t[i]*amp[i]*cos(rot[i]) + startX[i];
    y[i] = t[i]*amp[i]*sin(rot[i]) + startY[i];
    ellipse(x[i], y[i], radius[i], radius[i]);
    
    t[i] = sin( radians( speed[i]*frameCount ) );
  }
  
}

Basics of Arrays

Arrays are a way of taking a lot of variables and referring to them with a single name.

Arrays names here are an indexed reference mechanism.

The idea is simple:

  1. pick a name for this this “array” or collection of values, then
  2. reference each item by an integer, called an “index.”

Each bucket or place for data in an array is called an “element”. An array is then made of multiple elements of a particular data type. We can have an array of integers, floats (floating-point numbers), Strings, colors, etc. We cannot mix data types in an array.

Declaration Syntax

The brackets below tell us we’re working with an array.


TYPE[] NAME = new TYPE[ NUMBER_OF_ELEMENTS ];

Example:

int[] counts = new int[ 50 ];

This example produces an array of 50 integers. The number of elements (in this case, 50) must always be a positive integer.

Notice the use of the keyword “new”, that tells Processing to produce a new array. This keyword isn’t necessary for regular variables. It tells Processing to set aside a new block of memory that is large enough to contain exactly 50 integers.

Assigning and Reference Syntax


NAME[INDEX] = VALUE;
OTHER_VARIABLE = ARRAY_NAME[INDEX];

Example:


counts[3] = 25;
int x = counts[3];

Notes

x[i] is read as “ex sub eye”. Indices begin at zero, which means the last index is always equal to number of elements – 1.

ARRAY_NAME.length is equal to the “length” of the array, which is the number of elements.


int[] counts = new int[ 10 ];
counts[3] = 25;        // Initialize the value.
println( counts[3] );  // Output to the console.
int x = counts[3];     // Copy the value into
                       // another variable.

counts[3] = 12;        // Assign a new value.
println( x );          // x is still 25.

// Print the number of elements in the array.
println( counts.length ); // equals 10

// You can use a variable to put in place of the
// index. This allows us to automate the process
// of accessing array elements.
int i = 7;
counts[i] = 15;
println( counts[i] );  // Prints 15.

Loops

  1. Loops
    1. “For” loops
    2. More complex moving graphics
    3. “For” loops and arrays
  2. Loops and Arrays are Powerful
  3. More On Arrays
    1. Parallel Arrays
    2. Multi-Dimensional Arrays

“For” Loops

A “for-loop” is a counting mechanism. It executes and a series of steps, then changes the value of the iterating variable. It continues to execute the code block repeatedly until the condition in the loop equals false.

Loops are mechanisms to leverage the power of automation and multiplicity.

“For-loops” are a great way to repeat a set of commands many times and get a variable to change. If you want to draw ten squares, for instance, you can either write ten rect() commands, or write a single for-loop to draw all ten for you.
HOW THEY WORK

Try this:


size( 500,200 );
for( int i=0; i < 10; i++ ){
  rect( i*30, 10, 20, 20 );
}

Here’s an interpretation of what the for-loop statement means:


for( int i=0; i < 10; i++ ){ 
  // CODE HERE
}

1) Define a variable i, make it store an integer, start at 0.

2) Continue the loop while the value of “i” is less than 10. (This is known a “condition”, which we haven’t discussed in detail yet. For now, just use this format, and place to the right of the less-than sign a maximum value you don’t want the variable to exceed.)

3) Do the stuff between the braces each loop: { … }

4) At the end of each loop, increase “i” by 1.

Notes

You can use any variable name, not only “i”, but it is the most common variable used with arrays, which we will experiment with on the next page.

This is a mechanism that falls under “control flow,” which refers to the means that a programming language provides to control how the more salient statements are executed. A “for-loop” really doesn’t do anything substantial by itself – it’s really just a way of executing a pre-defined set of statements repetitively.

A previous example, simplified by a for-loop.


void setup(){
  size(700, 350);
}

void draw(){
  background(255);
  stroke( 0, 0, 0, 100 );
  
  for( int i=0; i < 90; i++ ){
    bezier( i*10, 50, 100, 100, 200, 300, 300+i, 300 );
  }
}

Try counting by a different number:


for( float t=0.0; t < TWO_PI; t+=0.1 ){
  line( 200, 100, 200 + 100*cos(t), 100 + 100*sin(t) );
}

Loops and Arrays Are Powerful

With loops added, now we have a better idea of what’s going on here when we look at the code.

This example is called “looping over an array”. With one loop, you can fill/update/whatever any array of any size.


int counts[] = new int[6];

for( int i=0; i < counts.length; i++ ) {
  counts[i] = i * i;
}

This example results in an array that contains { 0, 1, 4, 9, 16, 25 }. There is no “36” here, since we start counting at 0 and have 6 elements, we get to 5 and that’s it.

Parallel Arrays

One way of producing multiplicity is to utilize “parallel arrays.” This data structure uses several arrays with different names but identical lengths to store related information by index.

Below, all the information about each ball is spread over 10 arrays. If we want information about ball #41, we can ask each array using index = 41.


int numBalls = 500;

float[] startX = new float[numBalls];
float[] startY = new float[numBalls];
float[] x = new float[numBalls];
float[] y = new float[numBalls];
float[] rot = new float[numBalls];
float[] amp = new float[numBalls];
float[] speed = new float[numBalls];
float[] radius = new float[numBalls];
color[] c = new color[numBalls];
float[] t = new float[numBalls];

void setup() {
  size(700, 400);
  smooth();

  for( int i=0; i < numBalls; i++ ){
    radius[i] = 20 + random(20);
    startX[i] = random(width);
    startY[i] = random(height);
    c[i] = color(random(255), random(255), random(255), 150);
    rot[i] = random(TWO_PI);
    amp[i] = 20 + random(100);
    speed[i] = random(1, 10);
    t[i] = 0;
  }
  
  noStroke();
}

void draw() {
  background(255);

  for( int i=0; i < numBalls; i++ ){
    fill( c[i] );
    x[i] = t[i]*amp[i]*cos(rot[i]) + startX[i];
    y[i] = t[i]*amp[i]*sin(rot[i]) + startY[i];
    ellipse(x[i], y[i], radius[i], radius[i]);
    
    t[i] = sin( radians( speed[i]*frameCount ) );
  }
}