Search code examples
pythonpython-3.xoptimizationmathematical-optimization

Optimization problem in Python - like Goal Seek


I've just started using Python and have run into a challenge that I think should be straightforward but i can't seem to figure it out. In Excel there is a Goal Seek option where you can optimize a value by changing another value. I'm wondering if a similar optimization problem can be solved efficiently in Python, but with the ability to chaneg multiple values at once.

A minimal example :

I have two arrays

x = np.array([2, 3, 5, 6, 2, 2])
y = np.array([3, 2, 1, 4, 4, 2])

I'm trying to find the values in y that will set the result of the below formula to 5 using only values [1, 2, 3]/

np.sqrt(sum((x-y)**2))

I know the correct values should be :

[1, 1, 2, 3, 1, 1]

I realize there may be multiple solutions so being able to set some constraints around this would be good.

Are there any particular packages that would allow me to do this ? The above is just a toy example and in this case I could just try all possilbe combinations of [1, 2, 3] but I'm really looking for something that would scale to much bigger datasets.


Solution

  • Getting closer with root. But cannot figure out how to select only 1,2, and 3.

    import numpy as np
    import scipy.optimize as opt
    
    x = np.array([2, 3, 5, 6, 2, 2])
    y = np.array([1, 1, 1, 1, 1, 1])
    
    def func(y):
        x = np.array([2, 3, 5, 6, 2, 2])
        z = np.sqrt(np.sum((x-y)**2)) - 5
        return  np.zeros(x.shape[0],) + z
    
    r = opt.root(func, x0=y, method='hybr')
    print(r.x)
    # array([1.51287563, 2.93792864, 2.41974376, 1.82313836, 1.49719936, 1.36584456])
    
    print(np.sqrt(np.sum((x-r.x)**2)))
    # 5.0
    

    This is a working progress. I have to figure out how to constrain it to 1, 2, and 3. I will update my answer when I hit a breakthrough.

    Update

    To use any given array,

    X = np.array([3, 4, 5, 6, 7])
    y = np.array([1, 1, 1, 1, 1])
    
    def func(y, given=X):
    
        z = np.sqrt(np.sum((given-y)**2)) - 5
        return  np.zeros(given.shape[0],) + z
    
    r = opt.root(func, x0=y, method='hybr')
    print(r.x)
    # array([1.97522498 3.47287981 5.1943792  2.10120135 4.09593969])
    
    print(np.sqrt(np.sum((X-r.x)**2)))
    # 5.0