Tuesday, April 24, 2012

3D Distance Formula As C# Lambda Expression

Bad programmers add math to primitive objects. They do that because they think that is the best optimization technique. They also do that for minimal cost: the best bang for the buck. It makes them look good. That methods works until you need pure primitive objects again. If those objects are not primitive enough, they are limited in their usage, especially stand-alone, and that effects that portability of the entire program. With that in mind, let's jump right into code, and look at how I accessed the Vector() and Scalar() functions of the Point3D primitive class.

Here is the 3D distance function:

    Func    distance =
        (u,v) => u.Vector( v, (a,b) => a - b ).Scalar( (x,y,z) => Math.Sqrt( x*x + y*y + z*z ) ) ;

The Vector() and Scalar() functions let me pass the lambda expression to the primitive. The Vector() function accesses the members of the primitive like any mathematical vector expression, and it returns with the new vector. The Scalar() accesses the members of the primitive by scalar expressions, and it returns with the new value. Point3D has the members named X, Y, and Z.

The distance formula, above, looked complex until you see how simpler Point3D looks:

public struct Point3D
public T X ;
public T Y ;
public T Z ;

public Point3D Vector( Point3D operand, System.Func expression )
return new Point3D
expression( X, operand.X ),
expression( Y, operand.Y ),
expression( Z, operand.Z )

public T Scalar( System.Func expression )
return expression( X, Y, Z ) ;

As you can see, both functions take the input operands and applies the mathematical expressions on the members X, Y, and Z. What seems complex here is how we can pass the expression into the function rather than the values alone, as mathematical functions are usually defined by input values and output values. In lambda functions, we can pass the expressions as input, so it is not limited by only input values.

The distance() function above takes two Point3D objects (u,v), performs the subtraction (a-b) on each member, results in an intermediate vector, which then scales the accumulation of squares for each member into the square root function as the final value.

What I want in C# is the compiler feature that accepts the more graphic mathematical expression of the distance() function I have above such that we can see the graphic (math) notation for Vector() and Scalar(); "why" I used these names for those functions, then, makes sense. We are this close in the kind of automatic expression evaluation where we do not need the bad programmer's interpretation of mathematical expressions. We prefer code that self-documents itself, and the more graphical version accomplishes that easier than loads of comments that interrupt each line of code.

For example, I have drawn the graphic version of the above distance() function:

That may optimize to bitwise operators for faster computation with lower precision. I have seen others use that formula, even on primitives.

For greater accuracy, I have drawn this graphic version with cubes instead of squares:

You may write your own more accurate 3D distance() function based on that formula. I imagined the quantum mechanic version that used radians instead of roots such that it handles more than three dimensions in the vectors, and the accuracy is as easy as pi. Note that the value of pi that equals the irrational number that starts with "3.14159265" is inaccurate and slow, yet it has been quite phenomenal by many even if proven imaginary. That matters with accurate physical simulations, especially if strictly conservative.