Search code examples
kdb

How to understand an adverb / for dyadic function that returns a list of two elements?


The question arises from an example found in this article, а shift function:

shift: {[t;c]{(0,t*x)+x,y}/c}

In order to understand what excactly is going on I tried to simplify this function. Let's say t:1 and c:1 2 3. Then it seems that function {(0,x)+x,y}/1 2 3 is the same as {(0,x)+(x,y)}/1 2 3 which is the same as {(x,y+x)}/1 2 3.

But it is not:

q){(0,x)+x,y}/1 2 3
1 4 6
q){(0,x)+(x,y)}/1 2 3
1 4 6
q){(x,y+x)}/1 2 3
1 3 4 6

So it stands pretty clear that this simplification does something different, ant I have a gap in understanding of some concepts.

Could you please point out my mistake - why (0,x)+(x,y) is not the same as (x,y+x)?


Solution

  • When scanning in this manner the output of each iteration is used as the x variable for the next. I would strongly recommend reading through the documentation on accumulators. The nature of how binary accumulators works is demonstrated nicely in the whitepaper on iterators

    r[0]:f[x;   y 0; z 0]
    r[1]:f[r 0; y 1; z 1]
    r[2]:f[r 1; y 2; z 2]
    

    So for your case, the important distinction is that (0,x)+(x,y) is the addition of two vectors, (x,y+x) is the joining of two atoms. Consider the second iteration where x is (1,3) and y is 2 for all of the lambdas you have created. We can expose what the values are by using 0N!

    q)x:1 3
    q)y:2
    q)(0,x)+(x,y)
    1 4 5
    q)(0N!0,x)+(0N!x,y)
    1 3 2
    0 1 3
    1 4 5
    q)(x),(y+x)
    1 3 3 5
    q)(0N!x),(0N!y+x)
    3 5
    1 3
    1 3 3 5
    

    So the final lambda is creating longer vectors as it is essentially joining two vectors of length x, and the length of x increases each iteration.

    If you want to get a better understanding of iterators, you can output the intermediate results using \

    q){(0,x)+(x,y)}\[1 2 3 4]
    1
    1 3
    1 4 6
    1 5 10 10
    q){x,(y+x)}\[1 2 3 4]
    1
    1 3
    1 3 4 6
    1 3 4 6 5 7 8 10
    

    So for both lambdas the first two outputs are the same. The first is just outputting the first input x, and the second is the joining of the first input and the second, which are both of the same lengths.

    So the big take away here is that the past output is used for the next iteration, each iteration runs through the final value