Loop Example: Rectangles

Home, Up: Loop and Script Examples

 

In this example:

Inline Loops, Reading Data from File, 2-dimensional Array, Accumulation Mode, Buffer.

 

As always, the question mark at the beginning of a line is Hypatia's input prompt, you do not type it.

 

On the page "HY and Accumulation Mode" in chapter "Results" we had a "floor plan" example where we added up the areas of rooms, that is, we computed the sum of the products of their lenghts and widths.

Here we want to read the data from a file. Let's not be concerned with the individual products here, we just want the sum.

In more general terms, we have a two-dimensional array of data -- two colums, and an unknown number of rows. (It would be easy to generalize this to more than two columns, or to different calculations.)

Let's use the data from the "accumulation mode" example, and let's assume we have them in a file rectangles (you can create it with the command EDIT rectangles):

2 1.5

4 3

5 3

6 4

This file could have any number of lines, in this example we stay with these four.

 

When Hypatia reads this file the line breaks are lost, and we have a one-dimensional list of data:

2 1.5 4 3 5 3 6 4

To treat this as a two-dimensional array -- that is, to match lenghts and widths of the rectangles as we process the data -- we have to use our own line and row indexes. We can easily compute them from the loop index I:

The line index is I 2 * 1 - (the first item in the list is the length of the first rectangle, the third item is the length of the second rectange, etc.)

The row index is I 2 * (the first item in the list is the length of the first rectangle, the third item is the length of the second rectange, etc.)

Before we calculate the sum of the products of lengths and widths we should read the data file into a user defined element, to make the loop faster.

Then, we have to set $ to 0, and we can use an inline loop for our calculation.

For the second ITEM operator we need the vertical bar n-argument delimiter | to let it know where its list of items begins.

 

? @data = (rectangles)

? 0

? DO * :: @data I 2 * 1 - ITEM | @data I 2 * ITEM * $ +

Loop exit condition met in pass 4

= 54

 

The loop exit condition is the fact that the last item in the list has been addressed. Some other messages are not shown here.

Alternatively, we could use the loop not to calculate the sum of the products, but to write the individual products (rectangle areas) into a result file.

Both for speed, but also to better be able to work with the results, we use buffer mode, and save the products to a file areas.

 

? @data = (rectangles)

? BUFFER START

? DO * :: @data I 2 * 1 - ITEM | @data I 2 * ITEM * &

Loop exit condition met in pass 4

= 24

? BUFFER SAVE areas

? BUFFER DISCARD

? (areas) SUM

= 54

 

The result 24 is the loop's last calculation result, we can ignore it. The areas of the individual rectangles are now in the file areas -- we calculated the sum, but we can also calculate the mean, see how many rectangles (data rows) we had, what size the smallest one had, etc.:

? (areas) MEAN

= 13.5

? (areas) N

= 4

? (areas) MIN

= 3

 

If we want to do this calculation more often with different data, we can use a script instead of an inline loop.

To show how things can be done in different ways, instead of saving the content of the buffer (that is, the products of our data pairs) to a file we will copy its content to a new user defined element (of course, instead of discarding the buffer you could still save it

In the first loop pass we not only read the data file into a user defined element, we also check whether it has an even number of numbers.

You have to adapt the first line in the script if the data file has a different name than rectangles.

This is how the script, let's call it areasum, could look:

 

I1: @data = (rectangles)

I1: IF @data N 2 MULTIPLE IS0 THEN # Error: number of data is not even

I1: ALSO: ABORT

I1: BUFFER START

$length = @data I 2 * 1 - ITEM

$width = @data I 2 * ITEM

$length $width * &

I*: @areas = (buffer)

I*: BUFFER DISCARD

I*: $n = @areas N

I*: $total = @areas SUM

I*: $mean = @areas MEAN

I*: # number of rectangles, total sum of areas, mean size:

I*: SHOW $n $total $mean

 

To calculate the total area of the rectangles and their mean size call the script in an infinite loop:

? _*areasum

Buffer deleted, buffer mode is now OFF

  # number of rectangles, total sum of areas, mean size:

$n = 4

$total = 54

$mean = 13.5

Loop exit condition met in pass 4

= 24

 

(Again, at the end of the loop the last calculation result $ will be displayed, whether we need it or not.)

This example that reads two-dimensional data with 2 columns can easily be generalized to more than 2 columns and to different or more complex calculations.

With the help of line breaks in accumulation mode Hypatia can also generate 2-dimensional output.

What Hypatia cannot do, though, is update individual array elements -- to achieve this, the whole array has to be re-written to hy or (preferably, because much faster) to the buffer.

 

Home, Up: Loop and Script Examples, Prev: Loop Example: Body Mass Index, Next: Loop Example: Centimeters-Feet-Inches Table