Tuesday, November 11, 2008

Control Theory

In the last post I mentioned that we programmers don't generally get training in control theory. This is too bad, because I think learning to recognize the behavioral modes of feedback-controlled systems can have a lot of practical benefit for us.

Suppose that you have the following two Java classes, B and Main. Without running this, can you tell how it will behave?

If you do run it, you'll see that the output is spread across a range of numbers. Without changing class B, how would you make that range smaller? What properties of the code determine the range?

This program is an analog of an elementary problem in control theory, so basic that even my espresso machine implements a solution to it. But I suspect that most computer programmers, coming upon behavior like this while performance-tuning an application, wouldn't immediately recognize it.


public class B implements Runnable {
private static final int ELEMENTS = 100;
private double[] v = new double[ELEMENTS];
private boolean state;
private volatile boolean done = false;

public void run() {
while (!done) {
synchronized(this) {
v[0] = state ? 200.0 : 0.0;
// propagate gradually through the array
int i;
for (i = 1; i < v.length - 1; ++i) {
v[i] = (v[i - 1] + v[i] + v[i + 1]) / 3.0;
}
v[i] = (v[i - 1] + v[i]) / 2.0;
}
try {
Thread.sleep(1);
} catch (InterruptedException e) {}
}
}

public synchronized int get() {
return (int)v[v.length - 1];
}

public synchronized void set(boolean state) {
this.state = state;
}

public void finish() {
done = true;
}
}


public class Main {
final Object l = new Object();
final long end = System.currentTimeMillis() + 60000; // 1 minute

public static void main(String[] args) {
new Main().run();
}

private void run() {
B b = new B();
new Thread(b).start();

while (System.currentTimeMillis() < end) {
double t = b.get();
boolean state = t < 50.0;
System.out.println("t = " + t +
" - state is " + (state ? "true" : "false"));

b.set(t < 50.0);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {}
}
b.finish();
}
}

No comments: