How to add mathematical function as argument in python function

Tags: , ,



I know there are similar questions about passing functions into functions, but I’m not clear on the effective solution for my particular problem.

The following function works but the formula is static. It only works on a fixed function, namely (in mathy pseudocode) f(a) = 3^a mod 17 = b where f(11) = 7

def get_a(b):
    '''
    Get preimage a from A for f(a) = b where b in B
    '''
    a = 1
    while(1):
            x = pow(3, a) % 17
            if x == b:
                return a
            if a > 10000:
                return -1
            a += 1


def main():
    b = 7
    a = get_a(7)
    print(F'The preimage a of b={b} is: {a}')


if __name__ == '__main__':
    main()

I want to make a user pass in any given function. To start with, I implemented something just a little more complex but still pretty simple.

def get_a_variable(b, base, mod):
    '''
    Get preimage a from A for f(a) = b where b in B
    '''
    a = 1
    while(1):
        # print(F'a:{a}, b{b}')
        x = pow(base, a) % mod
        # print(F'x:{x}')
        if x == b:
            return a
        if a > 10000:
            return -1
        a += 1

def main():
    b = 7
    a = get_a(7)
    print(F'The preimage a of b={b} is: {a}')
    a = get_a_variable(7,3,17)
    print(F'Again, the preimage a of b={b} is: {a}')

This works but I want to make it even more dynamic.

To try implement this, I created a new function that can be passed as an argument:

def power_mod_function(base, x, mod):
  return power(base, x) % mod

I’m not exactly sure how the trial value arg x should be handled or if it should even be in this function.

Then I “forked” the “get_a(b)” function that takes a callback I believe

def get_a_dynamic(b, crypt_func):
    '''
    Get preimage a from A for f(a) = b where b in B
    '''
    a = 1
    while(1):
            x = crypt_func() # Not sure how to manage the arg passing here
            if x == b:
                return a
            if a > 10000:
                return -1
            a += 1

Then I updated main():

def main():
    b = 7
    a = get_a(7)
    print(F'The preimage a of b={b} is: {a}')
    a = get_a_dynamic(b, power_mod_function(3, x, 17)) # Not sure how to pass my middle arg!! 
    print(F'Again the preimage a of b={b} is: {a}')

I’m getting the following error messages:

 python pre_img_finder.py
The preimage a of b=7 is: 11
Traceback (most recent call last):
  File "pre_img_finder.py", line 45, in <module>
    main()
  File "pre_img_finder.py", line 41, in main
    a = get_a_dynamic(b, power_mod_function(3, x, 17))
NameError: name 'x' is not defined

I don’t know how to set it up right and do the variable passing so that I can pass the static variables once in main and the middle test variable x will always increment and eventually find the results I want.

Perhaps I just need to receive a function that begins with a “type” argument that acts as a kind of switch, and then takes a variable number of arguments depending on the type. For example, we could call the above a base-power-mod function or (bpm), where “power” is the answer we’re looking for, i.e. a is the pre-image of b in technical terms. Then just call

main():
    a = get_a_dynamic(7, ("bpm", 3,17))

And then implement it that way? Thanks for your help!

Answer

Use *args to pass additional arbitrary number of arguments to the function.

def get_a_dynamic(b, crypt_func, *args):
    '''
    Get preimage a from A for f(a) = b where b in B
    '''
    a = 1
    while(1):
            x = crypt_func(*args) 
            if x == b:
                return a
            if a > 10000:
                return -1
            a += 1

Then call it in your main like this

def main():
    b = 7
    a = get_a(7)
    print(F'The preimage a of b={b} is: {a}')
    a = get_a_dynamic(b, power_mod_function, 3, x, 17) 
    print(F'Again the preimage a of b={b} is: {a}')


Source: stackoverflow