Search code examples
python-3.xnumerical-methodssolver

back solve for a variable using python


I'm trying to write a function to back solve for a variable from another function in python, kind of like what Excel solver does.

To simplify my example, I have a function takes in several variables then calculate a price. I will be passing actual values (a,b,c,d,x) into this function so it returns a numeric value.

def calc_price(a,b,c,d,x):
    value = a+b*c-d + x
    return value

Now I'm given a target price, and a,b,c,d. Only unknown is variable x, so I want to back solve variable x. I want to build this into a function that takes into the same variables as calc_price, with an additional variable target_price.

def solve(target_price, a,b,c,d):
    #this function takes in values for target_price, a,b,c,d
    #and should do something like this:
    target_price = calc_price(a,b,c,d,x)
    solve for x   <---------this is the part I'm not sure how to do
    return x

I created a function like this below to back solve the value x by a loop but it's inefficient in calculating large datasets, so I'm looking for a more efficient solution.

def solve(target_price,a,b,c,d):
    x = 0.01
    while x < 1:
        if abs(target_price - calc_price(a,b,c,d,x)) < 0.001:
             return x
        x += 0.001

Thank you!


Solution

  • Consider this a demo (as your task is still a bit unclear to me) and make sure to read scipy's docs to learn about the basic guarantees these method provides.

    One could argue, that an approach based on root-finding is more appropriate (we are minimizing a function here; therefore the abs-construction in the residual-function), but this approach here does not need you to give some bracketing-interval.

    Code:

    import numpy as np
    from scipy.optimize import minimize_scalar
    np.random.seed(0)
    
    """ Utils """
    def calc_price(x, a, b, c, d):
        value = a+b*c-d + x
        return value
    
    def calc_price_res(x, target, a, b, c, d):
        value = a+b*c-d + x
        return abs(value - target)  # we are looking for f(x) == 0
    
    """ Create fake-data (typically the job of OP!) """
    a, b, c, d, x = np.random.random(size=5)
    fake_target = calc_price(x, a, b, c, d)
    
    print('a, b, c, d: ', a, b, c, d)
    print('real x: ', x)
    print('target: ', fake_target)
    print('noisy obj (just to be sure): ', calc_price_res(x, fake_target, a, b, c, d))
    
    """ Solve """
    res = minimize_scalar(calc_price_res, args=(fake_target, a, b, c, d))
    
    print('optimized x: ', res.x)
    print('optimized fun: ', res.fun)
    

    Output:

    a, b, c, d:  0.548813503927 0.715189366372 0.602763376072 0.544883182997
    real x:  0.423654799339
    target:  0.858675077275
    noisy obj (just to be sure):  0.0
    optimized x:  0.423654796297
    optimized fun:  3.04165614917e-09