Examples

Rosenbrock Function

We can optimize the Rosenbrock function by building it sequentially.

from pyObjective import Variable, Model



"""
We can start by defining the objective function to minimize.

In this example, we use the classic Rosenbrock function, defined as

f(x,y) = (a - x)^2 + b(y - x^2)^2

where the minima lies at (x,y) = (a, a^2).


We can start by defining the variables
"""
x = Variable(name='x', value=1.5, bounds=(-2, 2))
y = Variable(name='y', value=1.5, bounds=(-1, 3))

"""
Since this method uses simulated annealing, the initial guess value is not needed, 
but helps in checking if the function is being evaluated correctly.

Next, we create a model. The model contains the core functionality to evaluate and optimize the function. 

"""

m = Model()

"""
Now, we must tell the model which variables to optimize over. 
Internally, it maintains a list of variables that are to be optimized. If a variable is created but not added 
to the model, it remains fixed at the prescribed value. """

m.add_var(x)
m.add_var(y)

"""
Next, we define the cost function. Notice, all the variables are defined as calls, using x() instead of x. 
"""


def cost():
    a = 1
    b = 100
    return (a - x()) ** 2 + b * (y() - x() ** 2) ** 2

"""
We can check that the cost is being evaluated correctly, simply by calling the cost.
"""

print(f"The cost is {cost()}")

"""
Finally, we must associate the cost function with the optimizer. 
Notice, here the cost is passed without the brackets.
"""

m.objective = cost

"""Solve. The solution gets saved within the model"""

m.solve()

"""
We can print the results neatly. """

m.display_results()

Example using classes

The user can also define classes and use them instead.

from pyObjective import Variable, Model
import numpy as np

"""This example script is written to demonstrate the use of classes, and how more complicated models can be built, 
and still passed to the solver. As a rudimentary example, it has two cubes and a sphere, and we are trying to find 
the dimensions such that the cube1 - cube2 + sphere volume is minimized, subject to the bounds. """


# define a new class
class Cube:

    def __init__(self, model):
        self.x = Variable('x', 1, (0.5, 2), "cube length x")
        self.y = Variable('y', 1, (0.5, 2))
        self.z = Variable('z', 1, (0.5, 2))

        model.add_var(self.x)
        model.add_var(self.y)
        model.add_var(self.z)

    def volume(self):
        return self.x() * self.y() * self.z()


# define a sphere, but keep the variable definition on the outside. For fun
class Sphere:

    def __init__(self, radius):
        self.r = radius

    def volume(self):
        return (4 / 3) * np.pi * self.r() ** 3  # unfortunate brackets needed in here, and not before :(


# define simulation model
m = Model()

# create cube
c1 = Cube(m)
c2 = Cube(m)

# define the sphere radius
r = Variable("r", 1, (0.5, 2), "sphere radius")

m.add_var(r)  # try commenting this line, and you will see that it was removed from the optimization

s = Sphere(r)


# define objective function (to be minimized)
def cost():
    return c1.volume() - c2.volume() + s.volume()


m.objective = cost

# solve
m.solve()

# display results
m.display_results()