Computing the Distance Around a Path Defined by Points#

In this article, we will compute the distance around a path that is defined by a set of points. Our goal is to calculate the total distance, including looping back to the first point from the last one. The specific arrangement of points does not matter; all we require is the total distance.

Problem Setup#

To begin, we will utilize a set of points known from the problem description that should yield a distance of 12. This serves as a sanity check for our computation.

p  (¯1.5 ¯1.5) (1.5 2.5) (1.5 ¯1.5)

Defining the Lambda Function#

We can start by creating a Lambda function to apply to the points. We will refer to the argument on the right side as Omega. The idea is to connect the last element with the first element, allowing us to measure the distance around the loop.

  1. We extract the first function for the first element and need it enclosed to fit into our input format of vectors.

{} p

Output:

¯1.5 ¯1.5
  1. Next, we append the first element to our original input, setting up the calculation for adjacent elements.

{,⊂⊃} p

Output:

┌─────────┬───────┬────────┬─────────┐
│¯1.5 ¯1.5│1.5 2.5│1.5 ¯1.5│¯1.5 ¯1.5│
└─────────┴───────┴────────┴─────────┘

Now we have two elements to measure the distance between them and, consequently, the total distance.

Calculating Distances#

To compute the distances, we will use a form of reduction that employs adjacent differences. Essentially, this involves:

  • Subtracting adjacent points.

  • Reducing this to get three results.

{2-/,⊂⊃} p

Output:

┌─────┬───┬───┐
│¯3 ¯4│0 4│3 0│
└─────┴───┴───┘

Using Trigonometry#

We know that in a right-angled triangle, the diagonal (hypotenuse) can be computed using the Pythagorean theorem:

[ \(c = \sqrt{a^2 + b^2}\) ]

For our scenario, moving three steps in one direction and four steps in another gives:

[ \(\sqrt{3^2 + 4^2} = \sqrt{9 + 16} = \sqrt{25} = 5\) ]

For each pair of points, we create a new Lambda function and use the each operator to map our computations.

Implementing the Function#

As a next step, we will perform the following operations:

  1. Square both elements.

  2. Add these squared values.

  3. Take the square root of the sum.

To streamline this, we can create a named function for potential speed comparisons later.

F  {+/{((2*)+(2*⊃⌽))*0.5}¨2-/,⊂⊃} 
{+/{((2*)+(2*))*0.5}2-/,⊂⊃} p

Output:

12

Optimizing the Function#

We can optimize our approach by removing unnecessary loops and rethinking our calculations:

  • We can work directly with pairs of points instead of creating an additional vector.

  • This reduction is as simple as preparing our pairs in advance.

Even further, we can pre-process our right arguments using a reciprocal to maintain a clean symmetry in our computations.

Embracing Array Operations#

Advanced array capabilities can help us avoid nested structures. For example, using APL’s mix function allows us to turn our points into a simple array. With that, we can:

  • Subtract points using matrix operations.

  • Sum rows without explicit looping.

{+/2*÷+2*-1} p

Output:

12

Through these operations, we can keep our computations optimized and efficient.

Performance Comparisons#

Now, to evaluate the performance of our implementations, we can generate some test data:

points  1000 2 random  1

We will then use the execution comparison tools to see how our different implementations fare.

  1. Prepare same operations for the different methods.

  2. Run comparisons to investigate the efficiency of the different approaches.

'cmpx'⎕CY'dfns' 
cmpx'F q' 'G q' 'H q'

Results Summary#

By switching to handling data in a flat array rather than nested vectors, we effectively reduced computation time significantly—eliminating almost 80% of the resources previously used.

Conclusion#

In conclusion, for performance-oriented problems such as calculating distances, using flattened data structures can vastly improve processing time. Always keep in mind: to optimize your computations, think flat!

Thank you for reading this article!