pythondiscrete-mathematics

Idiomatic Python implementation for finite sets, images, and preimages of finite functions?


Suppose I have a finite concrete function between finite sets. Of course, Python has sets implemented natively.

But what is the best way to implement the idea of a finite function between sets, precisely? A wrapped dictionary? Also, how would one implement the calculations of images and preimages? [See below.]

For images I can use map, clearly. For preimages I can loop over the domain set and filter. Still, I'm wondering about the more pythonic idiomatic solution.

Wikipedia: Images (mathematics)


Solution

  • For arbitrary images from a set to another, I would use a Python dictionary. For example, f(n)=n^2 on a set of {1,2,3,4}, I can do this:

    preimage = set([1,2,3,4])
    mapping = {x: x*x for x in preimage}
    image = set(mapping.values())
    assert set(mapping.keys()) == preimage
    function = lambda x: mapping[x] # so you can now have y = function(x)
    check_image = set([function(x) for x in preimage])
    assert check_image == image
    

    Of course, this only works if your finite set is really finite with respect to the memory you have.

    The above is the most generic case that you define the function as mapping. But in case for simpler function which you can have a Python expression to represent it, you can skip the dictionary:

    preimage = set([1,2,3,4])
    function = lambda x: x*x
    image = set([function(x) for x in preimage])
    check_preimage = set([y for x in image for y in preimage if function(y)==x])
    assert check_preimage == preimage
    

    And if further, you have an inverse function available for the domain:

    import math
    preimage = set([1,2,3,4])
    function = lambda x: x*x
    inv_func = lambda x: int(math.sqrt(x))
    image = set([function(x) for x in preimage])
    check_preimage = set([inv_func(x) for x in image])
    assert check_preimage == preimage
    

    Note that, the three different code snippet above, only the first will guarantee your function(x) to allow only those x in the predefined preimage.

    Speaking of the idiomic python: I don't think Python is really such a mathematical language (compare to, say, Wolfram's mathematica) so we do not have the concept of image, mapping, etc. built-in. However, you can see my code above with the list comprehension. Indeed, I just made the thing more explicit to use set keyword as in set([function(x) for x in preimage]) but you can save a few keystroke with {function(x) for x in preimage}.