Search code examples
pythontuplesmemoization

How to make an index-agnostic 2-tuple?


I am implementing a function with 2 arguments and caching the result for performance ("Memoization" technique). But I see duplications in the caching function. For example:

@memoize
def fn(a,b):
    #do something.

The problem is that I know in advance that fn(a,b) == fn(b,a), so I would like it to understand that the argument tuple (a,b) is equivalent to (b,a) in this case, but this function presently caches them as 2 separate entries.

Do I need to make a new class for that purpose or is there any other more elegant way? Although I know that I can cache the same function return value for both the tuples, but I would really want to know how to implement "index-agnostic" tuples.

This memoization code is just an example, I want my tuple object to be extremely general purpose which can be used in other situations also.


Solution

  • You can split it into two functions. The public function takes arguments in any order, and calls an internal function with the arguments sorted. The inner function is the one with the cache.

    def fn(*args):
        return cached_fn(*sorted(args))
    
    @memoize
    def cached_fn(*args)
        # do something
    

    This is a time-space tradeoff -- there some extra function calls in order to cut the size of the cache in half. Hopefully you don't have functions with really long argument lists, so the sorting should not add too much overhead.

    This solution requires that the datatype of the arguments have a comparison function so they can be sorted. I can't think of a way to write this in a general way without such a prerequisite. When dealing with certain types you may be able to devise a custom method to canonicalize the order. Or you may be able to use your own hashing function in the cache, and make it order-agnostic.