Vaguery / klapaucius

A clean, tested, maintainable Push interpreter written in Clojure.
MIT License
31 stars 2 forks source link

reconcile tagspace lookups with vector and stack lookups #141

Closed Vaguery closed 7 years ago

Vaguery commented 7 years ago

It strikes me that the way we use scalar-to-index (or whatever) at the moment pushes all numbers in the range of feasible values first using modulo, and then picks a place and rounds. This is reasonable, and traditionally Push-like.

But :tagspace lookups use open-ended search, with any lookup value larger than the max key returning the first key, and also any lookup value smaller than the min key. That is, we almost always get the first key, for any out-of-range value.

Instead of doing that, I think we should take the index :scalar modulo the range of $k_max - k_min$, and the use upward-sliding on that.

And of course this would only apply to lookups. For insertions, the literal value would still work fine. Any value specified will create (or overwrite) a new key-value pair at exactly that scalar key.

Vaguery commented 7 years ago

Done in 5568e10

:tagspace lookups involve a rather complicated-seeming process that is justified for the sake of consistency only. Ignoring edge cases, it works like this

  1. find the max and min keys in the :tagspace; call them high and low
  2. find the range between those
  3. find the average gap in the :tagspace by dividing the range by (dec (count keys))
  4. Reduce the lookup value by (+ low (mod (- lookup low) (+ range average-gap)))
  5. Look up the value per the usual (prior) :tagspace lookup method

So for example if the keys are [1 3 7 13], the range is 12 and the average gap is 4. Lookup values are therefore reduced by (+ 1 ((mod (- lookup 1) 16))).

And (because mod) that's all the "modded-index" values we can have.

Edge cases:

However this introduces an inconsistency in the way lookups are performed in ordered collections.

Therefore, lookups in vector and :code and all the other ordered collections I could find are now scaled upwards, rather than downwards, as with :tagspace.

For a collection of five items, here is the "modded index" for various values now:

  1. 0 => 0
  2. 0.1 => 1
  3. 1 => 1
  4. 1.1 => 2
  5. 3.9 => 4
  6. 4 => 4
  7. 4.1 => 0
  8. 5.1 => 1
  9. -0.1 => 4
  10. -1.1 => 3

In other words, we just round up now, not down.

That way, every indexed lookup in Klapaucius now uses "round up and around".

In fact, all key-value lookup (by scalar value) in Klapaucius also uses the average gap-size as a "buffer" on the wrap-around. When we say that the "modded index" of a five-item vector is calculated modulo the length of the vector, we are implicitly adding 1.0 to the range between the max index 4 and the min index 0. Since the gap between every pair of index values for a vector is 1 exactly, then we are in fact still adding the average gap size to the range.

boom consistency