SAS Do Over Macro - Backwards - arrays

I am using the Macro Arrays and Do Over Macro.
I would like to rewrite this code with a do over macro:
if mysequence > 4 then grammar_last_5 = grammar_last_4;
if mysequence > 3 then grammar_last_4 = grammar_last_3;
if mysequence > 2 then grammar_last_3 = grammar_last_2;
if mysequence > 1 then grammar_last_2 = grammar_last_1;
So my Do Over would look something like:
%do_over(values=2-5, phrase= if mysequence > %eval(6-?) then grammar_last_%eval(7-?) = grammar_last_%eval(6-?);)
But that doesn't work.
Does anyone know how this can be done?
Thanks!!
Adam

For others wondering, the macros appear to be available here: http://www.sascommunity.org/wiki/Tight_Looping_with_Macro_Arrays
You've got a problem though. You're trying to pass in %eval(6-?) and other functions like text to the %do_over macro. Its going to try to compute that function and pass the result to the macro, and because its finding a character in what should be a mathematical operation, I'm guessing it subsequently is throwing a bit of a tantrum.
What's more, a way to do what you want doesn't seem like it would be forthcoming, because you'd need to mask the function from the macro compiler as you're feeding it in as an argument, but then unmask it to the macro compiler as its actually being used by do_over, and I'm guessing do_over isn't going to understand what you want without rewriting its logic even if you succeeded.
May I humbly suggest your own macro code as a starting solution. Something like:
%do i = 5 %to 2 %by -1;
if mysequence > %eval(&i - 1) then grammar_last_&i = grammar_last_%eval(&i - 1);
%end;
This should produce the text you want, though you would need to put it in your own macro, and call it in a data step, as it wouldn't make much sense anywhere else.
If you're going to want something more generalized, you're going to have to get your hands much much messier...

I took a quick look at the macro and it looks like they use macro quoting functions which could be interfering with the execution of your %eval functions.
If this is the case then you would have to custom edit %do_over() so that it didn't do this. If so then it's probably not worth the effort. It would be easier to write your own one-off macro to achieve your goal.

You don't need a macro for that, unless you've got something you're not telling us.
if mysequence > 4 then grammar_last_5 = grammar_last_4;
if mysequence > 3 then grammar_last_4 = grammar_last_3;
if mysequence > 2 then grammar_last_3 = grammar_last_2;
if mysequence > 1 then grammar_last_2 = grammar_last_1;
->
array grammars grammar_last:;
do _t = 4 to 1 by -1; *or, _t = dim(grammars)-1 to 1 by -1;
if mysequence > _t then grammars[_t+1]=grammars[_t];
end;

Related

Looping on a database with Clojure

I just got started with Clojure on Heroku, first reading this introduction.
Now in the phase of getting my hands dirty, I am facing this issue handling a database in a loop.
This is working:
(for
[s (db/query (env :database-url)
["select * from My_List"])]
; here one can do something with s, for example:
; print out (:field s)
)
But it is not enough to update variables inside the loop as I want.
Reading on the subject, I understand that Clojure having its own way of handling variables I need to use a loop pattern.
Here is what I tried:
(loop [a 0 b 1
s (db/query (env :database-url)
["select * from My_List"])]
; here I want to do something with s, for example
; print out (:field s)
; and do the following ... but it does not work!
(if (> (:otherField s) 5)
(:otherField s)
(recur (+ a (:otherField s)) b s))
)
Since I tried various ways of doing before writing this post, I know that the code above works except for the fact that I am doing something wrong concerning the database.
So here comes my question: What do I need to change to make it work?
I see, that it's hard to get to the functional thinking at first, when you're used to a different paradigm.
I don't think there is a correct explanation on “how to do this loop right”, because it's not right to do a loop here.
The two things that feel most incorrect to me:
Never do a SELECT * FROM table. This is not how relational databases are ment to be used. For example when you want the sum of all values greater than 5 you should do: SELECT SUM(field) FROM my_list WHERE field > 5
Don't think in loops (how to do it) but in what you want to do with the data:
I want to work on field :otherFIeld
I am only interested in values bigger than 5
I want the sum of all the remaining values
Then you come to something like this:
(reduce +
(filter #(> % 5)
(map :otherField
(db/query (env :database-url) ["select * from My_List"]))))
(No loop at all.)

Find conditional evaluation in for loop using libclang

I'm using clang (via libclang via the Python bindings) to put together a code-review bot. I've been making the assumption that all FOR_STMT cursors will have 4 children; INIT, EVAL, INC, and BODY..
for( INIT; EVAL; INC )
BODY;
which would imply that I could check the contents of the evaluation expression with something in python like:
forLoopComponents = [ c for c in forCursor.get_children() ]
assert( len( forLoopComponents ) == 4 )
initExpressionCursor = forLoopComponents[ 0 ]
evalExpressionCursor = forLoopComponents[ 1 ]
incExpressionCursor = forLoopComponents[ 2 ]
bodyExpressionCursor = forLoopComponents[ 3 ]
errorIfContainsAssignment( evalExpressionCursor ) # example code style rule
This approach seems...less than great to begin with, but I just accepted it as a result of libclang, and the Python bindings especially, being rather sparse. However I've recently noticed that a loop like:
for( ; a < 4; a-- )
;
will only have 3 children -- and the evaluation will now be the first one rather than the second. I had always assumed that libclang would just return the NULL_STMT for any unused parts of the FOR_STMT...clearly, I was wrong.
What is the proper approach for parsing the FOR_STMT? I can't find anything useful for this in libclang.
UPDATE: Poking through the libclang source, it looks like these 4 components are dumbly added from the clang::ForStmt class using a visitor object. The ForStmt object should be returning null statement objects, but some layer somewhere seems to be stripping these out of the visited nodes vector...?
The same here, as a workaround I replaced the first empty statement with a dummy int foo=0 statement.
I can imagine a solution, which uses Cursor's get_tokens to match the parts of the statement.
The function get_tokens can help in situations, where clang is not enough.

Do loop index changing on its own

I have a couple hundred line program (including functions) in essentially free-form Fortran. At one point, I have a pair of nested do loops that call functions and store results in matrices. However, I don't believe any of that is the problem (although I could be wrong).
Immediately after the first do loop starts, I define an array using a column of another array. Immediately after that, the index is always set to 3. I haven't been able to find any useful information in the usual places. I've included a fragment of the code below.
do i = 1,n
print *, 'i:',i ! Gives i = 1
applyto = eig_vec(:,i)
print *, i ! Gives i = 3
state1 = create_state(ground,applyto,state,bin_state,num_s,ns)
first = destroy_state(ground,state1,state,bin_state,num_s,ns)
state1 = destroy_state(ground,applyto,state,bin_state,num_s,ns)
second = create_state(ground,state1,state,bin_state,num_s,
1 ns)
do j = 1,n
bra = eig_vec(:,j)
a_matrix(j,i) = sum(bra*first + bra*second)
matrix(j,i) = sum(bra*first - bra*second
end do
end do
Is this a bug? Am I missing something obvious? I am compiling the code with a high level of optimization, if that could potentially be a source of problems. I'm relatively new to Fortran, so debugging flags or commands (for gdb - I believe that's all I have available) would be welcome.

Does anybody know how to define a function with several statements in ML?

I am trying to write a function in CPN ML which changes 3 variables, but I don't know how, I just can write one statement. My function should be something like this:
fun T1() =
x=x+1;
y=y+2;
k=k-1;
when I write this lines of code, I get an error.
Caveat: I don't know anything about CPN ML, but based on this I guess it has syntax similar to Standard ML?
In that case, you would need to group the statements in parentheses:
fun T1 () =
(x=x+1;
y=y+2;
k=k-1)
In SML, expressions can also be separated by semicolons in the body of a let expression, like this:
fun T1() =
let in
x=x+1;
y=y+2;
k=k-1
end
Some people prefer this to parentheses because it looks more block-structured. It also gives you a place to insert declarations (in the let .. in part), which is a common way for a function to evolve.
Of course, since this is a functional language, you either need to be using reference cells (x := !x + 1) or declaring new variables (val x = x + 1) to do what you have in the body of your function. There aren't really "statements" like in C and all variables are immutable.

Dynamically creating and naming an array

Consider the following code snippet
for i = 1:100
Yi= x(i:i + 3); % i in Yi is not an index but subscript,
% x is some array having sufficient values
i = i + 3
end
Basically I want that each time the for loop runs the subscript changes from 1 to 2, 3, ..., 100. SO in effect after 100 iterations I will be having 100 arrays, starting with Y1 to Y100.
What could be the simplest way to implement this in MATLAB?
UPDATE
This is to be run 15 times
Y1 = 64;
fft_x = 2 * abs(Y1(5));
For simplicity I have taken constant inputs.
Now I am trying to use cell based on Marc's answer:
Y1 = cell(15,1);
fft_x = cell(15,1);
for i = 1:15
Y1{i,1} = 64;
fft_x{i,1} = 2 * abs(Y1(5));
end
I think I need to do some changes in abs(). Please suggest.
It is impossible to make variably-named variables in matlab. The common solution is to use a cell array for Y:
Y=cell(100,1);
for i =1:100
Y{i,1}= x(i:i+3);
i=i+3;
end
Note that the line i=i+3 inside the for-loop has no effect. You can just remove it.
Y=cell(100,1);
for i =1:100
Y{i,1}= x(i:i+3);
end
It is possible to make variably-named variables in matlab. If you really want this do something like this:
for i = 1:4:100
eval(['Y', num2str((i+3)/4), '=x(i:i+3);']);
end
How you organize your indexing depends on what you plan to do with x of course...
Yes, you can dynamically name variables. However, it's almost never a good idea and there are much better/safer/faster alternatives, e.g. cell arrays as demonstrated by #Marc Claesen.
Look at the assignin function (and the related eval). You could do what asked for with:
for i = 1:100
assignin('caller',['Y' int2str(i)],rand(1,i))
end
Another related function is genvarname. Don't use these unless you really need them.

Resources