简体   繁体   中英

Finding the minima/maxima of a multi-variable polynomial in python

I have the following polynomial equation that I would like to find the local minima and maxima for.

多项式方程

I defined the function as follows. It uses a flatten function to flatten the nested list, I'll include it for testing purposes (found it here http://rightfootin.blogspot.com/2006/09/more-on-python-flatten.html )

flatten list

from itertools import combinations
import math

def flatten(l, ltypes=(list, tuple)):
    ltype = type(l)
    l = list(l)
    i = 0
    while i < len(l):
        while isinstance(l[i], ltypes):
            if not l[i]:
                l.pop(i)
                i -= 1
                break
            else:
                l[i:i + 1] = l[i]
        i += 1
    return ltype(l)
   

my polynomial

   def poly(coefficients, factors):
  
       #quadratic terms
       constant = 1
       singles = factors
       products = [math.prod(c) for c in combinations(factors, 2)]
       squares = [f**2 for f in factors]

       sequence = flatten([constant, singles, products, squares])

       z = sum([math.prod(i) for i in zip(coefficients, sequence)])


       return z

The arguments it takes is a list of coefficients, for example:

coefs = [12.19764959, -1.8233151, 2.50952816,-1.56344375, 1.00003828, -1.72128301, -2.54254877, -1.20377309, 5.53510616, 2.94755653, 4.83759279, -0.85507208, -0.48007208, -3.70507208, -0.27007208]

And a list of factor or variable values:

factors = [0.4714, 0.4714, -0.4714, 0.4714]

Plug these in and it calculates the result of the polynomial. The reason I wrote it like this is because the number of variables (factors) changes from fit to fit, so I wanted to keep it flexible. I now want to find the combination of "factors" values within a certain range (let's say between -1 and 1) where the function reaches its maximum and minimum values. If the function was "hard coded" I could use scipy.optimize, but I can't figure out how to make it works as is.

Another option is a brute force grid search (which I use at the moment), but it's very slow as soon as you have more than 2 variables, especially with small step sizes. There may be no true minima/maxima where slope == 0 within the bounds, but as long as I can get the maximum and minimum values that is OK.

Ok, I figured it out. It was two really silly things:

  1. the order of the arguments in the function had to be reversed, so that the first argument (the one I wanted to optimize for) were the "factors" or the X values, followed by the coefficients. That way an array of the same size could be used as the X0 and the coefficients could be used as args.

  2. That wassn't enough, as the function would return an array if an array was the input. I just added a factors = list(factors) to the function itself to put it into the correct shape.

The new function:

def poly(factors, coefficients):
   
   factors = list(factors)
   
   #quadratic terms
   constant = 1
   singles = factors
   products = [math.prod(c) for c in combinations(factors, 2)]
   squares = [f**2 for f in factors]

   sequence = flatten([constant, singles, products, squares])

   z = sum([math.prod(i) for i in zip(coefficients, sequence)])


   return z

And the optimization:

coefs = [4.08050532, -0.47042713, -0.08200181, -0.54184481, -0.18515675, 
-0.96751856, -1.10814625, -1.7831592, 5.2763512, 2.83505438, 4.7082153, 
0.22988773, 1.06488773, -0.70011227, 1.42988773]
x0 = [0.1, 0.1, 0.1, 0.1]
minimize(poly,x0 = x0, args = coefs, bounds = ((-1,1),(-1,1),(-1,1),(-1,1)))

Which returns:

fun: -1.6736636102536673
hess_inv: <4x4 LbfgsInvHessProduct with dtype=float64>
jac: array([-2.10611305e-01,  2.19138777e+00, -8.16990766e+00, -1.11022302e-07])
message: 'CONVERGENCE: NORM_OF_PROJECTED_GRADIENT_<=_PGTOL'
nfev: 85
nit: 12
njev: 17
status: 0
success: True
x: array([1., -1.,1., 0.03327357])

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM