David M. Cooke wrote:
Tim Hochberg <tim.hochberg@cox.net> writes:
That makes sense. One thought I had with respect to the various numpy functions (sin, cos, pow, etc) was to just have the bytecodes:
call_unary_function, function_id, store_in, source call_binary_function, function_id, store_in, source1, source2 call_trinary_function, function_id, store_in, source1, source2, source3
Then just store pointers to the functions in relevant tables. In it's most straightforward form, you'd need 6 character chunks of bytecode instead of four. However, if that turns out to slow everything else down I think it could be packed down to 4 again. The function_ids could probably be packed into the opcode (as long as we stay below 200 or so functions, which is probably safe), the other way to pack things down is to require that one of the sources for trinary functions is always a certain register (say register-0). That requires a bit more cleverness at the compiler level, but is probably feasible.
That's along the lines I'm thinking of. It seems to me that if evaluating the function requires a function call (and not an inlined machine instruction like the basic ops), then we may as well dispatch like this (plus, it's easier :). This could also allow for user extensions.
Hmm. If we are going to allow user extensions, we should think about this now. I was thinking of just putting all of the functions in a big table and doing a lookup based on bytecode. I'm not sure how this should work if we are allowing user extensions though.
Binary and trinary (how many of those do we have??)
I'm sure there are more that I'm not thinking of, but the main function that I am concerned with is arctan2. For trinary, the main one is which.
could maybe be handled by storing the extra arguments in a separate array.
If there really are only a few functions, we could give them their own opcodes. That means binary function still fit in 4 characters without a problem. That is: OP_ATAN2 R0, R1, R2 would compute: R0[:] = arctan2(R1, R2) Trinary could be defined as using their input as one of the arguments. This would sometimes require an extra copy and some cleverness in the compiler, but I think it would be reasonable. Thus OP_WHICH R0, R1, R2 would compute: R0[:] = which(R0, R1, R2) since the first argument of 'which' is often thrown away anyway, for instance 'which (a < 1, b, c)', the extra copy could often be avoided if we're smart. This might be a bad idea if there turns out to be several more trinary functions that I'm not thinking of or if there are quaternary functions we want to support. (I can't think of any though).
I'm going to look at adding more smarts to the compiler, too. Got a couple books on them :-)
Do you have any recomendations?
Different data types could be handled by separate input arrays, and a conversion opcode ('int2float', say).
That'd be cool. At some point I want to handle complex, but I'm going to wait till the main issues with floats shake themselves out. -tim