Aussie AI
Approximate Tests
-
Book Excerpt from "Generative AI in C++"
-
by David Spuler, Ph.D.
Approximate Tests
Many algorithms can be improved by avoiding complex calculations with a fast preliminary test that is often successful. This is a special type of common and simple case optimization combined. This method is only worthwhile when avoiding the complicated test is highly probable; if avoiding it is unlikely, the extra simple test reduces efficiency because it adds (slightly) to the run-time cost.
Zero skipping. In an AI engine, a common example is “zero skipping.” A low-cost test of a weight against zero can avoid the complexity of computing vector and matrix operations with that weight.
Bounding Sphere Tests in Ray Tracing. As an example in 3D graphics, to implement a ray tracing algorithm for graphical image rendering, it is necessary to determine whether a ray strikes an object. Since the objects are often complex and more often than not the ray will miss an object by a large amount of space, a simple test can be used to quickly identify rays that are close enough to the object to intersect with it. A good simple test is to determine if the ray intersects with the bounding sphere of an object, as it is relatively efficient to determine this. If the ray does intersect the sphere, the more expensive tests are applied to determine if the ray intersects with the object. If the ray does not intersect with the sphere, the cost of the more expensive tests has been avoided. Interestingly, the simplicity of testing the intersection of a ray with a sphere helps explain why there are so many ray-traced images of spherical objects.
Bounding-box 2D collision detection. The similar idea of a bounding rectangle is useful for collision detection in coding 2D arcade games. Collision detection usually involves testing many pairs of objects in a two-dimensional setting, and the tests are complicated because of the different shapes of the objects. The more complicated tests can be avoided by examining whether the bounding rectangles of each object are intersecting. If they do intersect, then a closer examination of whether the objects have pixels that overlap is carried out.
Rectangle Shapes.
For yet another example of using a simple test to avoid complicated tests, consider the
problem of a GUI-based drawing program.
Typically, the user can select a vertex (e.g. the end
of a line segment) by clicking “close” to the vertex. In other words, the user must click
the mouse within a specified radius of the point. Hence, when the mouse is clicked, the
program must compare the mouse location with all the currently active vertices.
The
obvious method is to use the distance formula for two points and apply the following test
on the x
and y
coordinates of the mouse and all points:
const float DISTANCE = 2.0f; float diffx = xMouse - xPoint; float diffy = yMouse - yPoint; float distance = sqrtf( diffx * diffx + diffy * diffy); if (distance <= DISTANCE) { // clicked! ... }
Firstly, the efficiency of this test can be improved simply by avoiding the calculation of the square root. Squaring both sides of the equation gives the equivalent test:
float distance_squared = diffx * diffx + diffy * diffy; if (distance_squared <= DISTANCE * DISTANCE) { // clicked! ... }
However, the multiplications involved in computing the squares of the two sub-expressions on the left are quite expensive, although the square on the right-hand side will
be a compile-time constant. A simple test can be used to avoid the expensive multiplications in
most cases. If the difference between either the x
or the y
coordinates is greater than
DISTANCE
, then the points cannot be close enough. Although the cost of these tests is
quite high because the absolute value of the difference must be found, it should still cost
less than two multiplications, and will be more efficient if there are many widely spaced
points to be tested. The code using this idea is:
bool check_point_clicked(int xm, int ym, int xp, int yp) { const float DISTANCE = 2.0f; int xd = xp >= xm ? xp - xm : xm - xp; if (xd > DISTANCE) return false; int yd = yp >= ym ? yp - ym : ym - yp; if (yd > DISTANCE) return false; return xd * xd + yd * yd <= DISTANCE * DISTANCE; }
Of course, algorithm improvements are even more effective. The best way of improving the efficiency of this program is to avoid the need for multiplications entirely, by changing the program specifications (!) so that the definition of clicking “close enough” to a vertex with a mouse refers to clicking within a square around the point, instead of a circle. Squares don't need multiplication.
• Next: • Up: Table of Contents |
The new AI programming book by Aussie AI co-founders:
Get your copy from Amazon: Generative AI in C++ |