Adám
Adám

Reputation: 7671

APL2-style inner product in Dyalog APL

Consider this Boolean matrix which indicates, for each of 7 products, which of the 5 resources are needed:

      ⎕←cross←7 5⍴1 1,(4/0),1 0 1 0 1,(6/0),1 0 1 0 1 0 0 1 0 0 1 1 0 0,(3/1),0
1 1 0 0 0
0 1 0 1 0
1 0 0 0 0
0 0 1 0 1
0 1 0 0 1
0 0 1 1 0
0 1 1 1 0

And this matrix shows the available capacity of 5 resources for each of 8 weeks:

      ⎕←avail←5 8↑5 7⍴0 100,(5/150),0 150 200 200,(3/300),5 0 30 40,(3/90),0 50 0 60 30 0 45 0 30 40 30 0 101 99
0 100 150 150 150 150 150 0
0 150 200 200 300 300 300 0
5   0  30  40  90  90  90 0
0  50   0  60  30   0  45 0
0  30  40  30   0 101  99 0

Each week, the possible production of a product is limited by the least available needed resource. We can compute this in APL2 (or APL+ or APLX) as follows, using a single inner product (.):

      ∇r←x R y
[1]   r←x/y
[2]   ∇
      cross ⌊.R avail
0 100 150 150 150 150 150 0
0  50   0  60  30   0  45 0
0 100 150 150 150 150 150 0
0   0  30  30   0  90  90 0
0  30  40  30   0 101  99 0
0   0   0  40  30   0  45 0
0   0   0  40  30   0  45 0

We had to wrap replicate (/) in a function R because it is strictly an operator and never a function, but this is immaterial here.

However, in Dyalog APL (and NARS2000 and GNU APL), this fails due to a slightly different definition of the inner product (/ is a function in this context, so there's no need to wrap it; doing so gives the same result):

         cross ⌊./ avail
┌┬┬┬┬┬┬┬┐
│││││││││
├┼┼┼┼┼┼┼┤
│││││││││
├┼┼┼┼┼┼┼┤
│││││││││
├┼┼┼┼┼┼┼┤
│││││││││
├┼┼┼┼┼┼┼┤
│││││││││
├┼┼┼┼┼┼┼┤
│││││││││
├┼┼┼┼┼┼┼┤
│││││││││
└┴┴┴┴┴┴┴┘

Per APL Wiki, we can define an inner product operator, matching APL2's definition, thus computing the desired result:

      IP←{⍺⍺/¨ (⊂[⍴⍴⍺]⍺)∘.⍵⍵ ⊂[⎕IO]⍵}
      cross ⌊IP/ avail
0 100 150 150 150 150 150 0
0  50   0  60  30   0  45 0
0 100 150 150 150 150 150 0
0   0  30  30   0  90  90 0
0  30  40  30   0 101  99 0
0   0   0  40  30   0  45 0
0   0   0  40  30   0  45 0

Is there an elegant way to directly compute this result in Dyalog APL, without having to model APL2?

Upvotes: 1

Views: 136

Answers (1)

Essie Rivers
Essie Rivers

Reputation: 61

To avoid the differences in dialects here, primarily the fact g in f.g has an implicit each in Dyalog APL, you can instead use:

cross⌊/⍤,./avail

The concatenate is applied repeatedly through the elements of every column after the filter, removing empty values and depth, at each step the minimum is taken and then the concatenation resumes.

For further investigation dissect the evaluation of:

cross((⌊/⍤,⌿(/¨⍤¯1))⍤1 2)avail

which is a direct and more verbose model.

Alternatively:

cross(⌊⌿⍤⌿⍤1 2)avail

is a significantly more performant version on large arguments, since there are no intermediary nested values.

Upvotes: 4

Related Questions