Nonlinear Programming in IronPython QuickStart Sample

Illustrates solving nonlinear programs (optimization problems with linear or nonlinear constraints) using the NonlinearProgram and related classes in IronPython.

View this sample in: C# Visual Basic F#

```Python
import numerics

from System import Array
from math import log, exp

# Vectors and matrices are in the Extreme.Mathematics namespace
from Extreme.Mathematics import *
from Extreme.Mathematics.LinearAlgebra import *

# The nonlinear programming classes reside in a namespace with
# other optimization-related classes.
from Extreme.Mathematics.Optimization import *

# Illustrates solving nonlinear programming problems
# using the classes in the Extreme.Mathematics.Optimization
# namespace of Numerics.NET.

# This QuickStart Sample illustrates the two ways to create a Nonlinear Program.

# The first is in terms of matrices. The coefficients
# are supplied as a matrix. The cost vector, right-hand side
# and constraints on the variables are supplied as a vector.

print "Problem with only linear constraints:"

# The variables are the concentrations of each chemical compound:
# H, H2, H2O, N, N2, NH, NO, O, O2, OH

# The objective function is the free energy, which we want to minimize:
c = Vector.Create[float](\
    -6.089, -17.164, -34.054, -5.914, -24.721, \
    -14.986, -24.100, -10.708, -26.662, -22.179)
objectiveFunction = lambda x: x.DotProduct(c + Vector.Log(x).AddInPlace(-log(x.Sum())))
def g1(x,y): 
    s = x.Sum()
    (c + Vector.Log(x).AddInPlace(1.0 - log(s)) - x / s).CopyTo(y)
    return y
objectiveGradient = g1

# The constraints are the mass balance relationships for each element. 
# The rows correspond to the elements H, N, and O.
# The columns are the index of the variable.
# The value is the number of times the element occurs in the
# compound corresponding to the variable:
# H, H2, H2O, N, N2, NH, NO, O, O2, OH
# All this is stored in a sparse matrix, so 0 values are omitted: 
A = Matrix.CreateSparse(3, 10, \
    Array[int]([ 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2 ]), \
    Array[int]([ 0, 1, 2, 5, 9, 3, 4, 5, 6, 2, 6, 7, 8, 9 ]), \
    Array[float]([ 1, 2, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1 ]))
# The right-hand sides are the atomic weights of the elements
# in the mixture.
b = Vector.Create[float](2, 1, 1)

# The number of moles for each compound must be positive.
l = Vector.CreateConstant(10, 1e-6)
u = Vector.CreateConstant(10, float.PositiveInfinity)
            
# We create the nonlinear program with the specified constraints:
# Because we have variable bounds, we use the constructor
# that lets us do this.
nlp1 = NonlinearProgram(objectiveFunction, objectiveGradient, A, b, b, l, u)

# We could add more (linear or nonlinear) constraints here, # but this is all we have in our problem.

nlp1.InitialGuess = Vector.CreateConstant(10, 0.1)
solution = nlp1.Solve()
print "Solution: {0:.3f}".format(solution)
print "Optimal value:   {0:.5f}".format(nlp1.OptimalValue)
print "# iterations:", nlp1.SolutionReport.IterationsNeeded
print 

# The second method is building the nonlinear program from scratch.

print "Problem with nonlinear constraints:"

# We start by creating a nonlinear program object. We supply 
# the number of variables in the constructor.
nlp2 = NonlinearProgram(2)

nlp2.ObjectiveFunction = lambda x: exp(x[0]) * (4 * x[0] * x[0] + 2 * x[1] * x[1] + 4 * x[0] * x[1] + 2 * x[1] + 1)
def g2(x, y):
    exp1 = exp(x[0]) 
    y[0] = exp1 * (4 * x[0] * x[0] + 2 * x[1] * x[1] + 4 * x[0] * x[1] + 8 * x[0] + 6 * x[1] + 1) 
    y[1] = exp1 * (4 * x[0] + 4 * x[1] + 2) 
    return y
nlp2.ObjectiveGradient = g2

# Add constraint x0*x1 - x0 -x1 <= -1.5
def c2gradient(x, y):
    y[0] = x[1] - 1
    y[1] = x[0] - 1 
    return y
nlp2.AddNonlinearConstraint(lambda x: x[0] * x[1] - x[0] - x[1] + 1.5, \
    ConstraintType.LessThanOrEqual, 0.0, c2gradient)
            
# Add constraint x0*x1 >= -10
# If the gradient is omitted, it is approximated using divided differences.
nlp2.AddNonlinearConstraint(lambda x: x[0] * x[1], ConstraintType.GreaterThanOrEqual, -10.0)

nlp2.InitialGuess = Vector.Create[float]( -1, 1 )
            
solution = nlp2.Solve()
print "Solution: {0:.6f}".format(solution)
print "Optimal value:   {0:.6f}".format(nlp2.OptimalValue)
print "# iterations:", nlp2.SolutionReport.IterationsNeeded
```