[Push] division and tangent instructions

Lee Spector lspector at hampshire.edu
Sun Jun 27 17:06:44 EDT 2010


Not silly at all, but also not obvious (to me) what the right way to go is. There's a big discussion on the Clojure list about auto-promotion and related issues, and some of the issues raised there would apply here too (plus evolution-related issues).

I guess my own perspective comes in part from working mostly at high levels of abstraction and wanting my "integers" to be like mathematical integers, with the underlying bit-level representation being something I don't want to have to know about or care about. So although I know there are performance reasons not to do this, my general preference is that integers should behave as mathematical integers and just work correctly, regardless of size.

It'd be possible to have different types for 32 bit ints, 64 bit ints, BigInts, etc, with a variety of possible schemes for manual or automatic promotion/translation. And one could conceivably designate one of the types as the source for indices for instructions that need them. My own preference would be to start with a single integer type that acts as close to mathematical integers as possible, which I guess means that it auto-promotes to BigInts, and to use this type for all things that need integers (unless there's a good reason to create another integer type for a specific application).

Maybe the uses of integers are ultimately restricted to arithmetic computation and addressing.... or maybe not. But even with just arithmetic computation and addressing it can be handy to have both uses work with the same type/stack, with arbitrary sized integers. For example, consider this evolved solution to the "odd" problem, which is to determine if an integer is odd (taking the input from the integer stack and leaving the result on the boolean stack):

((code.nth) code.atom)

This works by using the input value, which is a number on which we think we want to perform arithmetic computations, as an index/address. It indexes into the program's code itself, which will have been pushed onto the code stack prior to execution. Because nth takes its integer argument modulo the length of the list the call to code.nth will leave code.atom on top of the code stack if the input is odd, and (code.nth) on top of the code stack if the input is even. The call to code.atom will therefore push true onto the boolean stack in the former case and false onto the boolean stack in the latter case, producing the correct answer. Note that the integer input is being used simultaneously as fodder for arithmetic computation and as an index here. Note also that it would work perfectly well with inputs that exceed 64 bits. I'm sure one could express (and evolve) solutions in the context of other schemes for representing integers, even if "addressing" and "arithmetic" uses are separated into two different types. But this elegant little program presumably wouldn't work.

 -Lee

On Jun 27, 2010, at 4:09 AM, PerPlex Ed wrote:

> I guess integer in Push like in other languages are used in two and only two ways: arithmetic computation and addressing. Unless I'm overlooking something.
> 
> You use integers to compute 2 + 2 or 3 * 405 or 100*99*98*97*96... etc. because you are looking for that value as a result or you use integers because you want to yank the nth (integer) element from one of the stacks or because you want the nth (integer) element of a Sequence instruction etc.
> 
> In the first case you may need BigInts. In the second case it's very unlikely that you need address a stack that is orders of magnitudes bigger than your virtual memory.
> I guess that the two kind of integers, even if their are represented by the same platform data type could in theory be stored in different stack and allowed to be "converted" and passed from a stack to the other just like you do with the Code and Exec stack. Not that you need to do this but I guess that it's possible and it would not hurt the power and expressivity and applicability of Push.
> 
> Separating the "purely arithmetic integers" from the "addressing integers" could even cause slightly better programs to be generated.
> 
> So I guess the basic integer type and stack should be 32 bit or 64 bit, depending on the machine and maybe configurable on some implementations. And an additional type and stack for BigInts should be provided. You may require that a Push implementation always provide BigInts, if you think it's appropriate. I guess they are supported in most of the current platforms so it's not a big effort for someone writing a software implementation. For a Push hardware processor it may be different.
> 
> Then if the items in the BigInts stack (think of it as the "purely arithmetic integer stack" as opposed to the "addressing integer stack") are always represented as BigInts or sometimes as int and then promoted automatically is an implementation detail that you not need necessarily to care about when doing genetic programming in Push.
> 
> I hope what I wrote is not silly. I think I *almost* managed to make my first symbolic regression yesterday. :) I'm fixing some problem in my implementation to check and semplify the result. 
> 
> PerPlexEd.
> 
> Lee said:
>> I agree that it'd be just as well to add ratios and/or arbitrary 
> precision floats as new, independent types. Integers are different, 
> because integer is a core type that figures in a lot of standard 
> instructions for other types.
> 
> 
> 
> 
> 
> _______________________________________________
> Push mailing list
> Push at lists.hampshire.edu
> https://lists.hampshire.edu/mailman/listinfo/push

--
Lee Spector, Professor of Computer Science
School of Cognitive Science, Hampshire College
893 West Street, Amherst, MA 01002-3359
lspector at hampshire.edu, http://hampshire.edu/lspector/
Phone: 413-559-5352, Fax: 413-559-5438

Check out Genetic Programming and Evolvable Machines:
http://www.springer.com/10710 - http://gpemjournal.blogspot.com/



More information about the Push mailing list