LabVIEW Idea Exchange

cancel
Showing results for 
Search instead for 
Did you mean: 
altenbach

Looping over multiple dimensions with one loop

Status: Declined

Any idea that has received less than 8 kudos within 8 years after posting will be automatically declined.

I currently have a 3D array that I need to remap to some strange looking discret calibration data by linear interpolation (there is no good model function, not even polynomial!)

 

(1) This requires deeply stacked FOR loops (image top).

 

(2) In many cases it would simplify code if we could use a single FOR loop, but specify to loop over all scalar elements in all dimensions. (SUGGESTION: right-click tunnel, select "index over all scalar elements" -> different tunnel look). This would cause the autoindexing output tunnels of scalars to produce a multidimensional array of the same size as the autoindexing input. In all respects it should act the same as if we would stack as many FOR loops as needed to strip the input down to a scalar array element (center image). The index terminal [i] would output an array of all current indices (3 elements in this case). I am not sure what to do about N. If it would accept an array, we need to make sure the size (=# of dimensions) is defined elsewhere if there are no autoindexing inputs for example).

 

Case (2) could be useful in many situations, especially for more complicated code than shown here. It would work for all situations where only the innermost loop contains real code.

 

(3) In this particular case, the "interpolate array" function could of course be made polymorphic to accept multidimensional arrays and produce outputs if the same size as shown at the bottom of the image. Case (3) is a more general suggestion. Many existing functions could be made "more polymorphic" to do the same operation on each element of an array such as shown here. Since all operations are independent, it could even be automatically parallelized internally to take advantage of multiple CPU cores. Good candidates are functions that have scalar inputs and output a single scalar. If I have time, I will go over the palettes and identify more candidates. It might even turn into a seperate idea here in this forum. 😉

 

 

Message Edited by altenbach on 06-05-2009 05:25 PM
Message Edited by altenbach on 06-05-2009 05:25 PM
4 Comments
GregSands
Active Participant

I've got a similar idea here for accessing arrays of any dimension as a 1D array using the In Place Element Structure.  I agree something needs to be done about array handling, especially where all the data can stay in place, and it's only the addressing that changes.

Array Reshape.png

MathGuy
Member

I feel your pain. The topic (which I refer to as vectorization) is extremely difficult for a polymorphic language to handle because each dimension and/or each argument that can be vectorized introduces a level of ambiguity. Let me try to explain this by example.

 

1. Consider a unary operator like Summation. There's a natural (canonical) definition when the input argument is a 1D numeric array. Just add up the elements. Now, bring in a 2D array. The same concept can be applied in either direction - by rows or by columns.

 

Here's where the ambiguous choice comes in. LabVIEW supports row major storage (each element in a row is stored next to each other). This is one reason why auto-indexing in a FOR loop indexing by rows. It's just more efficient that way. Now, consider if the 2D array input is actually a matrix.

 

By definition in Linear Algebra, a matrix is a transformation which can be viewed as a set of vectors that span a vector space. While the vectors in the set can be defined by the rows or the columns, the standard interpretation uses the columns of the matrix. Enter the first conflict.

 

Here we have two viable domains (one drive by data type storage and the other by an popular application space) where choosing one vectorization scheme conflicts with the other. Do we choose performance or usability? How do we address an input of dimension higher than 2?

 

2. Now let's consider what happens when more than one input argument can be vectorized. Let's look at multiplication. Immediately, we can get into the same interpretation issue between storage and application domain but it gets uglier.

 

Suppose I perform a multiplication of two 2D arrays. Currently, if the 2D array is defined as a matrix (typedef'd 2D array), the operator performs a matrix multiplication. If the 2D array is not interpreted as a matrix, then the result is an element-wise scalar multiplication of elements that exist in both inputs. It produces a 2D array with the smallest dimensions of the inputs.

 

In LabVIEW, many users use a 1D array to represent a vector. Should multiplying two vectors be treated as a dot product (inner product of a matrices with one row and one column respectively), an outer product (product of matrices of one column and one row respectively), or the default element-wise scalar multiplication.

 

Go one step further and consider what happens when you multiply a 1D array by a 2D array or vice versa. The combinations grow quickly. Who gets vectorized in this case (none - matrix-vector operation, the 1D input - multiple scalar times matrix or 2D array, the 2D input - vector times multiple vectors or vector times 2D set of scalars, ...)?

 

Observations

While vectorization seems like a fairly straightforward mechanism to add to a language like G, there are many landmines once you consider all of the functionality that could/would/should support that mechanism.

 

The reality is that we have a wealth of functionality built into LabVIEW and any extensions to G should apply to each when it makes sense. The problem is what makes sense to one customer may not show up on the radar screen of another.

 

In my examples above, you may be led down the path that introducing new data types resolves these issues but that's actually a red hering. Even with an exhaustive set of types that appear complete, fundament issues still arise.

 

At the heart of this debate is readability of the code which, in my opinion, is crucial to dataflow programming. I welcome ways in which the user can avoid unnecessary syntax. In this case, though, I think the vectorization of an argument is semantically important so enforcing that in the language syntax is important.

 

I find the use of a structure to handle vectorization one that addresses the potential problems with readability, but I don't see how it avoids the complexity issue as the options of vectorizing (across dimension or argument list) grows. Each time I see a light such as this at the end of the tunnel, someone starts messing with the switch.

rgvdh@rdf
Member

I don't think what's being asked for above requires vectorization.

Both are looking at the special case where each element of the array is going to have some (possibly complex) thing done to it in isolation.  In this case you don't care about row versus column or anything of that nature.  You just want a method that's fast & easy (both for programmer and for CPU) to say "take each element, and replace it with the result of such-and-such operation performed on it."

 

Three nested for loops doesn't strike me as that big a deal, but I suppose if you have to do it a lot of times, or if you're working in more dimensions, it could get tiresome. 

 

This should be easy to define for the in-place-element structure, and that's where the big performance benefit potential is.

 

Trying to define it as a for-loop variant gets into a lot of difficulty really quickly for any case other than "one array in, n identically sized arrays out." And what to do about "i"?  Make it an array equal to the dimension of the array coming in? Just don't show it because it's too hard to define sensibly?  Something that allows precisely one array to be autoindexed, and has no "N" and no "i" might be a useful structure, but it's getting to be its own special thing rather than an enhanced for loop.

Darren
Proven Zealot
Status changed to: Declined

Any idea that has received less than 8 kudos within 8 years after posting will be automatically declined.