How is this MATLAB code (involving colon operator) resolved? - matlab

Recently, I wanted to calculate the next multiple of 5 of several values.
I was very confused by the output of this code, which should have done the trick:
7:11 - mod(7:11, 5) + 5
ans =
7 8 9 10 11 12 13 14
While the actual working solution was this:
(7:11) - mod(7:11, 5) + 5
ans =
10 10 10 15 15
So this seems to be related to operator precedence! But what exactly does the first command do, and why does it output a (1,8) vector?
Addendum: I have found that the first command can also be written as:
7:(11 - mod(7:11, 5) + 5)
Which already hints towards the explanation of the observed result, but I am still curious about the whole explanation.

Here's the list of MATLAB operator precedence
As you can see, parentheses, (), are solved first, meaning that mod(7:11,5) will be done first. Then point 6), the addition and subtraction are taken care of from left to right, i.e. 11-mod(7:11,5) and then 11-mod(7:11,5)+5. Then point 7), the colon, :, gets evaluated, thus 7:11-mod(7:11,5)+5.
As you noted correctly 7:11 - mod(7:11, 5) + 5 is the same as 7:(11 - mod(7:11, 5) + 5), as seen above using operator precedence.
Now to the second part: why do you obtain 8 values, rather than 5? The problem here is "making an array with an array". Basically:
1:3
ans =
1 2 3
1:(3:5)
ans =
1 2 3
This shows what's going on. If you initialise an array with the colon, but have the end point as an array, MATLAB uses only the first value. As odd as it may sound, it's documented behaviour.
mod(7:11,5) generates an array, [2 3 4 0 1]. This array is then subtracted from 11 and 5 is added [14 13 12 16 15]. Now, as we see in the documentation, only the first element is then considered. 7:[14 13 12 16 15] gets parsed as 7:14 and will result in 8 values, as you've shown.
Doing (7:11) - mod(7:11, 5) + 5 first creates two arrays: 7:11 and mod(7:11,5). It then subtracts the two arrays elementwise and adds 5 to each of the elements. Interesting to note here would be that 7:12 - mod(7:11, 5) + 5 would work, whereas (7:12) - mod(7:11, 5) + 5 would result in an error due to incompatible array sizes.

Related

KDB - Automatic function argument behavior with Iterators

I'm struggling to understand the behavior of the arguments in the below scan function. I understand the EWMA calc and have made an Excel worksheet to match in an attempt to try to understand but the kdb syntax is throwing me off in terms of what (and when) is x,y and z. I've referenced Q for Mortals, books and https://code.kx.com/q/ref/over/ and I do understand whats going on in the simpler examples provided.
I understand the EWMA formula based on the Excel calc but how is that translated into the function below?
x = constant, y= passed in values (but also appears to be prior result?) and z= (prev period?)
ewma: {{(y*1-x)+(z*x)} [x]\[y]};
ewma [.25; 15 20 25 30 35f]
15 16.25 18.4375 21.32813 24.74609
Rearranging terms makes it easier to read but if I were write this in Excel, I would incorrectly reference the y value column in the addition operator instead of correctly referencing the prev EWMA value.
ewma: {{y+x*z-y} [x]\[y]};
ewma [.25; 15 20 25 30 35f]
15 16.25 18.4375 21.32813 24.74609
EWMA in Excel formula for auditing
0N! is useful in these cases for determining variables passed. Simply add to start of function to display variable in console. EG. to show what z is being passed in as each run:
q)ewma: {{0N!z;(y*1-x)+(z*x)} [x]\[y]};
q)ewma [.25; 15 20 25 30 35f]
15f
16.25
18.4375
21.32812
//Or multiple at once
q)ewma: {{0N!(x;y;z);(y*1-x)+(z*x)} [x]\[y]};
q)
q)ewma [.25; 15 20 25 30 35f]
0.25 15 20
0.25 16.25 25
0.25 18.4375 30
0.25 21.32812 35
Edit:
To think about why z is holding 'y' values it is best to think about below simplified example using just x/y.
//two parameters specified in beginning.
//x initialised as 1 then takes the function result for next run
//y takes value of next value in list
q){0N!(x;y);x+y}\[1;2 3 4]
1 2
3 3
6 4
3 6 10
//in this example only one parameter is passed
//but q takes first value in list as x in this special case
q){0N!(x;y);x+y}\[1 2 3 4]
1 2
3 3
6 4
1 3 6 10
A similar occurrence is happening in your example. x is not being passed to the the iterator and therefore will assume the same value in each run.
The inner function y value will be initilised taking the first value of the outer y variable (15f in this case) like above simplified example. Then the z takes the 2nd value of the list for it's initial run. y then takes the result of previous function run and z takes the next value in the list until how list has bee passed to function.

Applying adverb to colon operator

Please help me with colon : operator, I'm stuck on how it works. It works as an assignment, assignment through x+:1, global assignment/view ::, I/O 0:, 1:, to return value from the middle of the function :r, and to get an unary form of operator #:.
But what happend if one apply an adverb to it? I tried this way:
$ q
KDB+ 3.6 2019.04.02 Copyright (C) 1993-2019 Kx Systems
q)(+')[100;2 3 4]
102 103 104
q)(:')[x;2 3 4]
'x
[0] (:')[x;2 3 4]
^
q)(:')[100;2 3 4]
2 3 4
I expect evaluations in order: x:2, then x:3, then x:4. To get x:4 as a result. But I've got an error. And also :' works with a number 100 for some unknown reason.
What :' is actually doing?
q)parse "(:')[100;2 3 4]"
(';:)
100
2 3 4
Parsing didn't shed much light to me, so I'm asking for your help.
When modified by an iterator (also known as an adverb in q speak), : behaves just like any other binary operator. In your example
q)(:')[100;2 3 4]
2 3 4
an atom 100 is extended to a conformant list 100 100 100 and then : is applied to elements of the two lists pairwise. The final result is returned. It might look confusing (: tries to modify a constant value, really?) but if you compare this to any other binary operator and notice that they never modify their operands but return a result of expression everything should click into place.
For example, compare
q)+'[100; 2 3 4]
102 103 104
and
q)(:')[100;2 3 4]
2 3 4
In both cases an a temporary vector 100 100 100 is created implicitly and an operator is applied to it and 2 3 4. So the former is semantically equivalent to
(t[0]+2;t[1]+2;t[2]+4)
and the latter to
(t[0]:2;t[1]:2;t[2]:4)
where t is that temporary vector.
This explains why (:')[x;2 3 4] gives an error -- if x doesn't exist kdb can't extend it to a list.

create a new matrix from values obtained iterating through other matricies

In Matlab I have 4 matricies which are all 1(row) by 4(coloumns) (ABDC, EFGH, IJKL, MNOP)
Their names are also stored in a list
Stock_List2 = {'ABCD' 'EFGH' 'IJKL' 'MNOP'} and is a 1 by 4 cell.
I want to iterate through the list and create a new matrix called "display" which takes the values of the indvidual matricies and places them underneath each other)
I am trying something like
for e = 1:length(Stock_List2)
display(e) = eval(strcat(Stock_List2)(e))
end
Error: ()-indexing must appear last in an index expression.
However getting the following error expression which truthfully may well just be that I'm way off the mark.
As an example if the orginal matricies are as follows:
ABCD 1 2 3 4
DEFG 5 6 7 8
HIJK 9 8 7 6
LMNO 5 4 3 2
I would like the final output ie the 'display matrix to be a 4 by 4 matrix looking like
display
1 2 3 4
5 6 7 8
9 8 7 6
5 4 3 2
If I understood right you want to concatenate vertically the matrices ABDC, EFGH, IJKL and MNOP saving them in the matrix "display".
You could do:
display = [ABDC; EFGH; IJKL; MNOP]
or:
for i=1:length(Stock_List2)
display(i,:) = Stock_List2{i}
end
Apologies if what I wanted wasnt clear - I've got the following from a colleague which achieves the desired result
for e=1:length(Stock_List2)
eval(strcat('display_mat(e,:) = ',Stock_List2{e}));
end

Reshape (#) doesn't work with a dynamic argument

To form a matrix consisting of identical rows, one could use
x:1 2 3
2 3#x,x
which produces (1 2 3i;1 2 3i) as expected. However, attempting to generalise this thus:
2 (count x)#x,x
produces a type error although the types are equal:
(type 3) ~ type count x
returns 1b. Why doesn't this work?
The following should work.
q)(2;count x)#x,x
1 2 3
1 2 3
If you look at the parse tree of both your statements you can see that the second is evaluated differently. In the second only the result of count is passed as an argument to #.
q)parse"2 3#x,x"
#
2 3
(,;`x;`x)
q)parse"2 (count x)#x,x"
2
(#;(#:;`x);(,;`x;`x))
If you're looking to build matrices with identical rows you might be better off using
rownum#enlist x
q)x:100000?100
q)\ts do[100;v1:5 100000#x,x]
157 5767696j
q)\ts do[100;v2:5#enlist x]
0 992j
q)v1~v2
1b
I for one find this more natural (and its faster!)

String concatenation and string repetition operators

I am trying to understand why does the following:
say 4 x 2.5 * 2;
produce
88
instead of
44444
as the following:
say 4 x (2.5 * 2);
The way I tried to explain the second one is that since operator x expects a number as right argument 2.5 * 2 gets computed into number 5 and then 4 is treated as string which yields "44444". But I can't explain the 1st one! Changing it to print does not matter, either.
print 4 x 2.5 * 2 . "\n"
also gives
88
I am not about to write such code, of course. I'm just trying to understand the behavior.
The repetition operator x and the multiplication * have the same precedence. Both are also left-associative. Therefore, the correct parenthezisation for
4 x 2.5 * 2
is
(4 x 2.5) * 2
Because the 2nd argument for x must be an integer, this is equivalent to
(4 x 2) * 2
Which does "44" * 2. There we have our 88.
If in doubt, use explicit parens to make your intentions clear to the compiler:
say 4 x (2.5 * 2);