0
$\begingroup$

I am searching for an optimization solution, which is a 8d vector representing 4 complex elements, where each element is within the complex circle with maximal radius 1.2.

The objective function is:

$$f: \left\|\mathbf{c}_{ref}-\mathbf{c}\right\|_{2}+\left|2-\|\mathbf{c}\|_{2}\right|$$

I am using the scipy.optimize.basinhopping module.

import numpy as np
from scipy import optimize

class MyBounds(object):
    def __init__(self, xmax=[360, 360, 360, 360, 1.2, 1.2, 1.2, 1.2], xmin=[0, 0, 0, 0, 0, 0, 0, 0] ):
        self.xmax = np.array(xmax)
        self.xmin = np.array(xmin)

    def __call__(self, **kwargs):
        x    = kwargs["x_new"]
        tmax = bool(np.all(x <= self.xmax))
        tmin = bool(np.all(x >= self.xmin))
        return tmax and tmin

class MyTakeStep(object):
    def __init__(self, stepsize=45):
        self.stepsize = stepsize
    def __call__(self, x):
        s = self.stepsize
        x[0] += np.random.uniform(0, 1*s)
        x[1] += np.random.uniform(0, 2*s)
        x[2] += np.random.uniform(0, 3*s)
        x[3] += np.random.uniform(0, 4*s)
        s = 1
        x[4] += np.random.uniform(0, 1*s)
        x[5] += np.random.uniform(0, 1*s)
        x[6] += np.random.uniform(0, 1*s)
        x[7] += np.random.uniform(0, 1*s)
        return x

def f(input_list):
    polar_form = [rphi for rphi in zip(input_list[4:], input_list[:4])]
    x          = np.array([z(e[0], e[1]) for e in polar_form])
    # objective function componenets
    result  = abs(2 - np.linalg.norm(x, 2)) + np.linalg.norm(cref-x, 2)
    return result

def hopping_solver(min_f, min_x):
    minimizer_kwargs = {"method":'Nelder-Mead'}
    comb             = np.array([0, 0, 0, 0, 0, 0, 0, 0])
    # define bounds
    mybounds   = MyBounds()
    mytakestep = MyTakeStep()
    optimal_c  = optimize.basinhopping(f, x0 = comb, niter=50000, T=45, stepsize=1, minimizer_kwargs=minimizer_kwargs, take_step=None, accept_test=mybounds, callback=None, interval=5000, disp=False, niter_success=None)

    min_x, min_f = optimal_c['x'], optimal_c['fun']
    print(optimal_c)
    return min_x, min_f

min_f = 10**10
min_x = []
min_x, min_f = hopping_solver(min_f, min_x)

My questions relate to the step essentially: My first elements are angles in [0, 360] and the others are in [0, 1.2]. What is a suitable way to define a good step here to balance between precision and fast processing?

I am aware that this code does not return the global minimum.

Also here I chose the center of my solutions space as $x_0$, are there recommendations on how to choose the starting point?

$\endgroup$
  • 1
    $\begingroup$ I would suggest you change from degrees to radians since it would give a better scaling of your problem, although I am not that sure it matters for Nelder-Mead. You could also use a higher order method when you are far away from the kinks in your objective function. $\endgroup$ – nicoguaro Mar 21 at 13:44
  • 1
    $\begingroup$ Actually, I think that the polar representation of complex numbers is singularly unsuitable to the problem here. It makes the problem non-unique (because you can add $2\pi$ to the angles and get another solution), and the spacing of points separated by a certain $(dr,d\phi)$ is non-uniform depending on where you are in the complex plane. $\endgroup$ – Wolfgang Bangerth Mar 21 at 14:17
  • $\begingroup$ @nicoguaro Thank you for the suggestion, I am currently experimenting with angles in radians, which helped a bit with the scalibility. However, I still cannot get the correct solution despite trying different steps and the scipy iterations terminate successfully but do not get close enough to my solution. For example final f(x) = 1.34 where as it should get close to 0. $\endgroup$ – SuperKogito Mar 21 at 16:35
  • $\begingroup$ @WolfgangBangerth well I agree but if you take a look at my bounds you will notice that I am limiting my solution's space to complex numbers with amplitude =< 1.2 and phases within [0, 360]. So I am only interested in solutions in that space and those should be unique. $\endgroup$ – SuperKogito Mar 21 at 16:37
  • 1
    $\begingroup$ But step length determination becomes more complicated in polar coordinates. And you have to deal with bounds. When you have a bounds limited problem, you may also end up with multiple local minima where before you had only one global minimum. $\endgroup$ – Wolfgang Bangerth Mar 21 at 17:10
3
$\begingroup$

Geometrically, you are trying to find a point that is (i) as close as possible to the point $\mathbf c_{ref}$ and (ii) as close as possible to the sphere of radius 2. Your objective function is the sum of these two distances. The solution is that point $\mathbf c$ that is half-way between $\mathbf c_{ref}$ and the (closest point on the) sphere of radius 2, i.e., the solution if the vector $$ \mathbf c = \frac 12 \left( \mathbf c_{ref} + 2 \frac{\mathbf c_{ref}}{\|\mathbf c_{ref}\|}\right). $$ Written differently, you get that $$ \mathbf c = \left( \frac 12 + \frac{1}{\|\mathbf c_{ref}\|}\right) \mathbf c_{ref}. $$

$\endgroup$
  • $\begingroup$ Actually, any point on the connecting line between $\mathbf c_{ref}$ and the closest point on the sphere of radius 2 is a solution. $\endgroup$ – Wolfgang Bangerth Mar 20 at 22:26
  • $\begingroup$ Well thank you for you suggestion, but it doesn't answer my question. Actually, my function is more complex than what I included, therefore my main concern here is proper initialization of the parameters. According to your solution my c is just $c_{ref}$ since I already have $\|c_{ref}\|_{2} = 2$. $\endgroup$ – SuperKogito Mar 21 at 12:42
  • $\begingroup$ Well, then yes, that's even simpler. $\endgroup$ – Wolfgang Bangerth Mar 21 at 14:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.