I have been experimenting with the GRAYCODE function within an IML program and thought I would post my experiences for the benefit of others.
I was expecting to be able to define a vector x = j(1, 4, 0), set k = -1 and then call
rc = graycode(k, x);
in a loop, where x would cycle through all the combinations (effectively a representation of the binary numbers 0 to 15 in a minimum change order). If I do that, I get an unhelpful error insisting that the first argument k should be binary, I think I can see now why I get this, but not the first few times. It seems the only way to use it, is to provide a list of scalars that have all been pre-initialised. So the following does work:
k = -1;
a = 0; b = 0; c = 0; d = 0;
do i=1 to 2##4;
rc = graycode(k, a, b, c, d);
print i k a b c d rc;
end;
the only problem is that I am thinking of putting this in an algorithm with 2^19 iterations, and managing 19 scalars is cumbersome to say the least. Wouldn't it make much more sense to get the scalars returned as a row vector? My solution is to create the row vector myself using the return codes, and just feed in zeros rather than scalars. This is far from intuitive, but does do what I want.
k = 0;
x = j(1, 4, 0);
rc = 0;
print x rc;
do i=2 to 2##4;
rc = graycode(k, 0, 0, 0, 0);
x[rc] = 1 - x[rc];
print x rc;
end;
I also tried rc = graycode(k, , , , ) but regretted it!
I understand your frustration. I have blogged about the problem of calling Base SAS functions that require a list of parameters, and have provided a method that I often use to handle INPUT parameters: Calling Base SAS functions from SAS/IML: How to handle argument lists? - The DO Loop
In this case, the Base SAS function is providing multiple OUTPUT parameters, so you can't use my trick. However, you can solve your problem by using the CALL GRAYCODE subroutine rather than the GRAYCODE function. It's not clear from your description whether you need a numerical vector or whether a character string will suffice. In the following statements, s is a character string; if you need a numerical vector, use the new functionality of the SUBSTR function to convert the string to a vector:
s='0000';
n=length(s);
k=countc(s, '0');
do i=2 to 2##n;
call graycode(k, s, n, '01');
x = num(substr(s, 1:n, 1)); /* necessary */
print i k s x;
end;
BTW, when the initial string has 19 characters (s='0000000000000000000';) the program completes in less than a second, so it appears to be sufficiently efficient.
I understand your frustration. I have blogged about the problem of calling Base SAS functions that require a list of parameters, and have provided a method that I often use to handle INPUT parameters: Calling Base SAS functions from SAS/IML: How to handle argument lists? - The DO Loop
In this case, the Base SAS function is providing multiple OUTPUT parameters, so you can't use my trick. However, you can solve your problem by using the CALL GRAYCODE subroutine rather than the GRAYCODE function. It's not clear from your description whether you need a numerical vector or whether a character string will suffice. In the following statements, s is a character string; if you need a numerical vector, use the new functionality of the SUBSTR function to convert the string to a vector:
s='0000';
n=length(s);
k=countc(s, '0');
do i=2 to 2##n;
call graycode(k, s, n, '01');
x = num(substr(s, 1:n, 1)); /* necessary */
print i k s x;
end;
BTW, when the initial string has 19 characters (s='0000000000000000000';) the program completes in less than a second, so it appears to be sufficiently efficient.
Many thanks for your tips Rick.
Registration is now open for SAS Innovate 2025 , our biggest and most exciting global event of the year! Join us in Orlando, FL, May 6-9.
Sign up by Dec. 31 to get the 2024 rate of just $495.
Register now!
Learn how to run multiple linear regression models with and without interactions, presented by SAS user Alex Chaplin.
Find more tutorials on the SAS Users YouTube channel.