Summary

Code

Executable on S2

Videos

Let’s summarize what we did in the last topic “Piecewise Linear Functions”. Given the speed of the rabbit at any point in time, we can compute the distance that it travels at the time \(t\). Or, speaking the math language, we say: Given the speed function, we compute the distance function.

The speed function is:

\(
v(t)=
\begin{cases}
1.0 * t, & t < 5.0 \\
5.0 * t, & 5.0 \leq t < 10.0 \\
3.0 * t, & t \geq 10.0
\end{cases}
\)

This block of math is simply saying when time \(t\) is before 5 s, the speed is 1 m/s. When time is between 5 s and 10 s, the speed is 5 m/s. Starting from the 10 s onward, the speed is 3 m/s.

It is rather difficult to understand what it means just by looking at the equations. Visualization helps. We plot the speed function so we can see it. We first code up the speed function.

// the three-leg speed function
fun speed(t : Double): Double { // t = time
    if (t < 5.0) {
        return 1.0;
    }
    else if (t < 10.0) { // t >= 5.0
        return 5.0;
    }
    else { // t >= 10.0
        return 3.0;
    }
}

Then the plotting code.

// plot the speed curve over time
val t = (0..20)

%use plotly
Plotly.plot {
    scatter {
        x.set(t)
        y.set(t.map { speed(it.toDouble()) })
    }
}
the speed function

However, there is a problem with this graph. It seems to suggest that the speed at time 4.5 s is about 3 m/s. That is not what the equations say. The problem is that we did not plot the curve with enough resolution. We used only 20 points. Specifically, there was no point between \(t = 4\) and \(t = 5\). The computer simply joined these two points together using a straight line. To fix this problem, we plot the graph again using a higher resolution, i.e., more points.

// plot the distance curve over time
val t = (0..200) // in decisecond or ds

Plotly.plot {
    scatter {
        x.set(t)
        y.set(t.map { speed(it.toDouble() / 10.0) })
    }
    
    layout{
        title = "speed function"
        yaxis {
            title = "y"
            range = 0.0..5.0
        }
    }
}

Here we plot 200 points. Note that the time now runs from 0 to 200 where the 200th point represents \(t = 20 \text{ s}\). Therefore, there is a conversion between the point indices to the actual times. Now, one point interval represents a deci-second, or one-tenth of a second. The 200 decisecond points together make 20 seconds. The graph now looks much closer to what the equations say.

the speed function, at deciseconds

Sum up Rectangles

To compute the distance that the rabbit travels at this speed function, we can use the “sum-up-rectangles” method. Specificially, before the 5 s, the distance \(d\) is simply the product of the (constant) speed 1 m/s^2 times the time \(t\).

\(d = 1 * t\)

If we think of the speed as the height of a rectangle and time the width, then \(d\) in the above equation is simply the product of height and width or namely the area of the rectangle.

distance = rectangle area

It is easier to see if we draw the picture to represent the process. The curve (blue) line represents the speed at any time \(t\). The yellow box has the area equal to \(1 * t\), which is also the distance travelled by the rabbit. Therefore, the rectangle area is the same as the distance travelled when we pair the speed as height and time as width. It may appear weird to think of the distance as an area. Indeed, distance and area are not the same thing. The idea is here is that the formula to compute the distance travelled is the same as the formula to compute the area of a rectangle. They are both just the products of the two quantities, height and width vs. speed and time.

When \(t = 5\), we have:

t = 5

The distance or the rectangle area is \(1 \times 5 = 5\).

When time > 5 s, we will need two rectangles. For example, when \(t = 8\), we have:

t = 8

The yellow rectangle represents that the rabbit spends the first 5 seconds running at the speed 1 m/s. The red rectangle represents that the rabbit spends another 3 seconds running at the speed 5 m/s. The distance travelled is therefore equal to:

\(d = 1 \times 5 + 5 \times 3 = 20\)

Note that \(d = 1 \times 5 = 5\) is the same as the 1-by-5 yellow rectangle area, and \(5 \times 3 = 15\) the same as the 5-by-3 red rectangle area. The total area is \(d = 1 \times 5 + 5 \times 3 = 20\) which is the same as the distance.

When time > 10 s, we will need three rectangles. For example, when \(t = 20\), we have:

t = 20

The yellow rectangle represents that the rabbit spends the first 5 seconds running at the speed 1 m/s. The red rectangle represents that the rabbit spends another 5 seconds running at the speed 5 m/s. The green rectangle represents that the rabbit spends yet another 10 seconds running at the speed of 3 m/s. The distance travelled is therefore equal to:

\(d = 1 \times 5 + 5 \times 5 + 3 \times 10 = 60\)

Note that \(1 \times 5 = 5\) is the same as the 1-by-5 yellow rectangle area, and \(5 \times 5 = 25\) the same as the 5-by-5 red rectangle area, and \(3 \times 10 = 30\) the same as the 3-by-10 green rectangle area. The total area is \(d = 1 \times 5 + 5 \times 5 + 3 \times 10 = 60\) which is the same as the distance.

We can code this up to write the distance function.

// the distance function for the whole process
// another way to code this function
fun distance_123a(t : Double): Double { // t = time
    // the speeds in different periods
    val v1 = 1.0; // 1 m/s
    val v2 = 5.0; // 5 m/s    
    val v3 = 3.0; // 3 m/s
    
    // the times when the speed changes
    val t2 = 5.0; // 5 s
    val t3 = 10.0; // 10 s

    if (t < 5.0) {
        return v1 * t;
    }
    else if (t < 10.0) { // t >= 5.0
        return v1 * t2 + v2 * (t - t2);
    }
    else { // t > 10.0
        return v1 * t2 + v2 * (t3 - t2) + v3 * (t - t3);
    }
}

To plot the distance curve:

// plot the distance curve over time
val t = (0..20)

Plotly.plot {
    scatter {
        x.set(t)
        y.set(t.map { distance_123a(it.toDouble()) })
    }
}
the distance curve

The curve agrees with some of our computations at a few time points we computed before.

We have an observation: the distance travelled by an object is the same as the area under its speed function. The area can be computed by filling the area using rectangles. In other words, the distance curve at any point in time is simply the area covered or under the speed curve at that time point.

We can pair the speed curve and the distance curve to visualize this.

the relationship between the speed and distance curves

Sum up Small Rectangles

In general, given any speed function or curve, we can always find the distance travelled by computing the area covered by the speed curve at any time point. The speed function that we have in the above example is easy because it is composed of three flat line segments (constant 1 m/s, constant 5 m/s, constant 3 m/s). In general, a speed curve may take any shape so a large rectangle may not fit well under the curve. For example, there is no rectangle that can fit perfectly well under the following linearly increasing curve. This is the speed curve when the object is accelerating at 1 m/s², adding 1 m/s to its speed every second.

a linearly increasing function

What we can do, however, is to use small rectangle to try to fit them under the curve as much as possible, much like doing mosaics. For example,

using small rectangles to fit the area under a curve

In general, the smaller the rectangles are, the better we can do the fitting and the smaller the computation error is. Those little bits above the line are the computation errors. (Note that we usually use rectangles of the same width to keep calculations simple but this is not a must.)

We can apply the same idea to the rabbit example above. Instead of fitting under the speed curve using three big rectangles, we can use many small rectangles instead.

using small rectangles to fit the area under a curve

For the distance travelled up to any time \(t\), we simply compute the area covered by the small rectangles up to time \(t\). It is rather easy to compute the area covered by the rectangles. It is simply the sum of the small rectangles. For each small rectangle, the area is simply

\(\Delta A = v(t) * \Delta t \tag{eq 1}\)

In mathematics, the symbol \(\Delta\) means “small”. \(\Delta A\) means “small A” or “small area” or “small distance” in our example. Likewise, \(\Delta t\) means “small time period” or “small time increment” because time always increases. \(v(t)\) is the speed at time \(t\). What this equation says is that small distance or small area equals to the product of speed and how much time in a (small) period. To compute the area covered, we simply sum up all these small areas to get the total area. That is,

TOTAL AREA = sum of small areas

In mathematics, we write:

\(A \simeq \sum \Delta A\)

The big \(A\) represents the total area or total distance. The symbol \(\sum\) means “sum up”. The symbol \(\Delta A\) means small areas as in the above. The symbol \(\simeq\) means “approximately equal” but not quite equal. The whole equation says, summing up all the small areas to get the (approximate) total area. We will see why it is only an approximation and not exact very shortly.

We can replace \(\Delta A\) using \(\text{eq 1}\).

\(A \simeq \sum v(t)\Delta t\)

(In Algebra, we usually do not write the times or multiplication symbol.)

Using this “sum-up-small-rectangles” method, we can code it up to compute the rabbit distance at any time.

// the distance function for the whole process
// another way to code this function by summing up rectangles
fun distance_123b(t : Int): Double { // t = time
    var total_distance = 0.0;
    
    val dt = 1.0;
    for (i in 1..t) {
        val v = speed(i.toDouble()); // get the speed at the current time i
        val dd = v * dt; // a small rectangle
        total_distance = total_distance + dd; // sum up the new small rectangle
    }
    
    return total_distance; // the total sum
}

We test it out to see if it works.

distance_123b(10)
32.0

It does not seem right. The distance at time = 10 s should be 30 m.

Let’s plot out the graph to see for all times.

// plot the distance curve over time
val t = (0..20)

Plotly.plot {
    scatter {
        x.set(t)
        y.set(t.map { distance_123b(it) })
    }
}
the (approximate) distance curve, when dt = 1

Although the shape looks OK, the points do not agree with what we have before, close but not exactly.

We note that the “sum-up-small-rectangles” method is only an approximation method that gives an approximate answer. If we use rectangles that are too big to fit perfectly under the curve, the answer will be off. This is exactly what we are see here. The rectangles that we use are too big. For this particular code, the width of the small rectangles are 1.0 (val dt = 1.0). The computation errors come from the “little bits” above the speed curve.

We can try to use small rectangles, i.e., small width, to do the approximation again to see if the result improves. Well, it will! Because we are reducing the areas coming from the “little bits” above. We fit better under the curve using small rectangles.

// the distance function for the whole process
// another way to code this function by summing up rectangles
fun distance_123c(t : Int, w : Double): Double { // t = time, w = width
    var total_distance = 0.0;
    
    val dt = w; // the rectangle width
    var i = 0.0; // starting time
    while (i < t + 1e-8) { // loop until the current time is bigger than t
        val v = speed(i); // get the speed at the current time i
        val dd = v * dt; // a small rectangle
        total_distance = total_distance + dd; // sum up the new small rectangle
        
        i = i + dt; // increase the clock
    }
    
    return total_distance; // the total sum
}

The code now takes the width (w) as a parameter. The small w is, the smaller the rectangles, the more rectangles that we need to add up, the better the fit, the more accurate the answer is. The while-loop keeps adding up small rectangles until the current time is bigger than the input time, when we stop.

Let’s plot the curve to see the new result. We use w = 0.1. We use 10x more rectangles.

// plot the distance curve over time
val t = (0..20)

Plotly.plot {
    scatter {
        x.set(t)
        y.set(t.map { distance_123c(it, 0.1) })
    }
}
the (approximate) distance curve, when dt = 0.1

The result clearly improves. It goes from 32 (w = 1) to 30.1 (w = 0.1). The error reduces from 2.0 to 0.1.

We can try a even smaller rectangle width to pad smaller and more rectangles under the curve to further improve the result. We use w = 0.01. We use 100x more rectangles.

// plot the distance curve over time
val t = (0..20)

Plotly.plot {
    scatter {
        x.set(t)
        y.set(t.map { distance_123c(it, 0.01) }) // w = 0.01
    }
}
the (approximate) distance curve, when dt = 0.01

The result now (A = 30.01) is even closer to the true value (A = 30.0). In general, the small the width (w or dt), the more accurate the result is, because we use higher resolution of using many more smaller rectangles.

Integration as in Calculus

This method of summing up small rectangles to compute the area under a curve has a fancy name. It is called integration. Integration literally means summing up. The formula is rather simple. It is again:

\(A \simeq \sum\Delta A \simeq \sum v \Delta t\)

It connects the two concepts, “rate of change” and “total change” together in one formula. The \(v\) in this equation is the rate of change. For example, speed is the rate of change in distance per time. The \(A\) in this equation is the total change. For example, it is the total area of the small areas. In other words, each small area is the small change of the process under \(v\) for a small amount of time \(\delta t\). It is the small distance change during this small time period. If we sum up these small (distance) changes across all times, then we get the total (distance) change.

The main idea of integration is that to compute the total change, we first break it down into many small changes and then sum them up. To compute each small change, we simply compute the area of the rectangle. Mathematically, let \(v\) be the rate of change per time \(t\). That is,

\(v = \frac{change}{time}\)

Then small change \(\Delta A = v \times \) small time \( = v \times \Delta t\). This is a linear function in \(\Delta t\) assuming that \(v\) does not change during this small time period. Essentially, what integration does is to break down the rate function curve, like the speed function curve, into many small linear functions for each small time period. In other words, we approximiate the original function curve by conjoining many small linear functions or a piece-wise linear function!

approximate the curve using a piecewise step function

For our example of an accelerating rabbit, its speed function is a (strictly) increasing function. By breaking each small period into a small rectangle, we essentially approxiate the speed fucntion by a stair case function. During each small time period \(\Delta t\), we assume the approximation is no longer increasing or changing. The approximation assumes that during \(\Delta t\), the function is a constant. Of course, the constant or step is different for each time period.

After we have the values for each small change, then we sum up all these small changes to get the total change.

\(A \simeq \sum\Delta A \simeq \sum v \Delta t\), a sum of simple products or a sum of linear functions.

In general, the smaller the rectangles that we use, the more accurate the answer is. One would wonder, what if we keep shrinking the time interval (OK, we don’t call it time period anymore. Mathematicians call it time interval. Let’s be more professional.) until it goes to very, very, very small, say, infinitesimally small. To understand this concept of infinitesimally small, let’s compare it to infinity, which is easier to understand. Infinity is not a number. It is a notion that means something that is bigger than any given number. It just keeps on going and going and never stops. Infinitesimally small, on the other hand, means something that is positive (bigger than 0) but is smaller than any given number. It is moving closer and closer toward 0 but never quite get there. Intuitively, if we can shrink the rectangle width to infinitesimally small, we perhaps will get the correct answer. And this is exactly the idea of doing integration in Calculus. Mathematically, we write:

\(A = \lim_{dt \to 0} \sum v(t)dt\)

Again, \(dt\) is the rectangle width. The symbol \(\lim_{dt \to 0}\) means we take \(dt\) to as much close to 0 as to the limit possible, or to infinitesimally small. One very important change is that we no longer use the approximation equal \(\simeq\). We now use the exact equal sign. The area A is indeed equal to the limit sum of all those infinitesimally small rectangle. There is an official symbol for this limit (so we don’t need to keep writing the lim symbol and sum symbol over and over again.

\(A = \int v(t)dt\)

You will see the integral sign \(\int\) over and over in your life if you do just about any science. It appears in everywhere from classical mechanics to relativity field theory!

This idea of integration to do calculation (breaking down into small pieces and then summing them up) is the most important concept in the history of mathematics. It was invented by Isaac Newton and Gottfried Leibniz. It is the foundation of all higher mathematics. It is ubiquitous in almost all branches of mathematics. This is Calculus!