Eigen/MinPack: non linear optimization#

Multidimensional Rootfinding: Powell Hybrid#

ctxboost.PowellHybrid(f, fjac, guess)#

This is a modified version of Powell’s Hybrid method as implemented in the hybrj algorithm in minpack. The Hybrid algorithm retains the fast convergence of Newton’s method but will also reduce the residual when Newton’s method is unreliable. The algorithm uses a generalized trust region to keep each step under control.

See also: Moré et al. [439], Eigen [223], Wikipedia [1558], Powell [498].

Parameters:

f:

a callback matrix function defining the system.

fjac:

a callback matrix function defining the Jacobian of the system system.

guess:

a matrix containing the initial guess for the solution

Results:

x1:

a matrix containing the solution.

Example:

This is an example from the original manual of MINPACK (Moré et al. [439]).

The routine in Python:

def demo_PowellHybridCtx(ctx):

    # The function to optimize
    def XmatHybrd(x, fvec):
        n = x.size
        for k in range(n):
            temp = (3.0 - 2.0 * x[k]) * x[k]
            temp1 = ctx.zero()
            if (k!=0): temp1 = x[k-1]
            temp2 = ctx.zero()
            if (k != n-1): temp2 = x[k+1]
            fvec[k] = temp - temp1 - 2.0*temp2 + 1.0

    # The Jacobi function
    def XmatHybrdJ(x, fjac):
        n = x.size
        for k in range(n):
            for j in range(n):
                fjac[k, j] = ctx.zero()
            fjac[k, k] = 3.0 - 4.0 * x[k]
            if (k != 0): fjac[k, k - 1] = -1
            if (k != n - 1): fjac[k, k + 1] = -2

    # This defines the start vector
    n = 9
    matInput = ctx.matZeros(n,1)
    matInput[0] = 1
    matInput[1] = 2  # entries 2 .. 8 are 0.
    print('matInput: \n', matInput)

    # This executes the PowellHybrd solver
    matRes = ctx.powellHybrd(XmatHybrd, XmatHybrdJ, matInput)

    # Check the result
    Y = ctx.matZeros(n,1)
    XmatHybrd(matRes, Y)
    print('matRes: \n', matRes)
    print('Y: \n', Y)

The same routine in Visual Basic:

 Public Sub XmatHybrd(x As xrealMatrix, fvec As xrealMatrix)
     Dim n As Int32 = x.size
     For k As Int32 = 0 To n - 1
         Dim temp = (3.0 - 2.0 * x(k)) * x(k)
         Dim temp1 = xreal.Zero()
         If (k<>0) Then temp1 = x(k-1)
         Dim temp2 = xreal.Zero()
         If (k <> n-1) Then temp2 = x(k+1)
         fvec(k) = temp - temp1 - 2.0*temp2 + 1.0
     Next
 End Sub

 Public Sub XmatHybrdJ(x As xrealMatrix, fjac As xrealMatrix)
     Dim n As Int32 = x.size
     For k As Int32 = 0 To n - 1
         For j As Int32 = 0 To n - 1
             fjac(k, j) = 0
         Next
         fjac(k, k) = 3.0 - 4.0 * x(k)
         if (k <> 0) Then fjac(k, k - 1) = -1
         if (k <> n - 1) Then fjac(k, k + 1) = -2
     Next
 End Sub

 Sub DemoPowellHybrdClassxreal()
     Dim n As Int32 = 9
     Dim matInput = xreal.MatZeros(n,1)
     matInput(0) = 1
     matInput(1) = 2  ' entries 2 .. 8 are 0.
     Dim matX = xreal.PowellHybrd(AddressOf XmatHybrd, AddressOf XmatHybrdJ, matInput)
     Console.WriteLine("")
     matX.print("X (solution):", 10)
     Dim matEval = xreal.MatZeros(n,1)
     XmatHybrd(matX, matEval)
     matEval.print("matEval =  F(X=solution):", 10)
End Sub

The output of these routines:

Hello DemoPowellHybrdClassDbl()

X (solution):
-0.570654511600659,
-0.681628342291231,
-0.701732452563471,
-0.704212940083752,
-0.701369047627289,
-0.691865643379914,
-0.665792012154689,
-0.596034201280817,
-0.416412062998472,

matEval =  F(X=solution):
6.56011067690088E-09,
-4.17547307840493E-09,
-5.19316567526573E-09,
-2.39601338769546E-09,
2.02249372804886E-09,
4.81791939677123E-09,
2.57950016901987E-09,
-3.88373844195655E-09,
-1.35886191188206E-10,

Nonlinear LeastSquares: Levenberg-Marquardt#

ctxboost.LevenbergMarquardt(f, fjac, matInput)#

This is a robust and efficient version of the Levenberg-Marquardt algorithm as implemented in the scaled lmder routine in minpack. The algorithm uses a generalized trust region to keep each step under control.

See also: Moré et al. [439], Eigen [223], Wikipedia [1552].

Parameters:

f:

a callback matrix function defining the system.

fjac:

a callback matrix function defining the Jacobian of the system system.

guess:

a matrix containing the initial guess for the solution

Results:

x1:

a matrix containing the solution.

Example:

This is an example from the original manual of MINPACK (\(Moré1980\)).

The routine in Python:

def demo_LevenbergCtx(ctx):

    # The function to optimize
    def XmatLM(x, fvec):
        m = 15
        y = ctx.matZeros(m,1)
        y[0] = 1.4e-1
        y[1] = 1.8e-1
        y[2] = 2.2e-1
        y[3] = 2.5e-1
        y[4] = 2.9e-1
        y[5] = 3.2e-1
        y[6] = 3.5e-1
        y[7] = 3.9e-1
        y[8] = 3.7e-1
        y[9] = 5.8e-1
        y[10] = 7.3e-1
        y[11] = 9.6e-1
        y[12] = 1.34e0
        y[13] = 2.1e0
        y[14] = 4.39e0
        for i in range(m):
            tmp1 = i + 1
            tmp2 = m - i
            tmp3 = tmp1
            if (i >= 8): tmp3 = tmp2
            fvec[i] = y[i] - (x[0] + tmp1/(x[1]*tmp2 + x[2]*tmp3))

    # The Jacobi function
    def XmatLMJ(x, fjac):
        m = 15
        for i in range(m):
            tmp1 = i + 1
            tmp2 = m - i
            tmp3 = tmp1
            if (i >= 8): tmp3 = tmp2
            tmp4 = (x[1] * tmp2 + x[2] * tmp3)
            tmp4 = tmp4 * tmp4
            fjac[i, 0] = -1
            fjac[i, 1] = tmp1 * tmp2 / tmp4
            fjac[i, 2] = tmp1 * tmp3 / tmp4

    # This defines the start vector
    n = 3; m = 15
    matInput = ctx.matZeros(n,1)
    matInput[0] = 1
    matInput[1] = 2  # entries 2 .. 8 are 0.
    print('matInput: \n', matInput)
    # This executes the Levenberg solver
    matRes = ctx.levenberg(XmatLM, XmatLMJ, matInput)
    # Check the result
    Y = ctx.matZeros(m,1)
    XmatLM(matRes, Y)
    print('matRes: \n', matRes)
    print('Y: \n', Y)

The same routine in Visual Basic:

Public Sub XmatLM(x As xrealMatrix, fvec As xrealMatrix)
    Dim m As Int32 = 15
    Dim y = xreal.MatZeros(m,1)
    y(0) = 1.4e-1
    y(1) = 1.8e-1
    y(2) = 2.2e-1
    y(3) = 2.5e-1
    y(4) = 2.9e-1
    y(5) = 3.2e-1
    y(6) = 3.5e-1
    y(7) = 3.9e-1
    y(8) = 3.7e-1
    y(9) = 5.8e-1
    y(10) = 7.3e-1
    y(11) = 9.6e-1
    y(12) = 1.34e0
    y(13) = 2.1e0
    y(14) = 4.39e0
    For i As Int32 = 0 To m - 1
        Dim tmp1 = i + 1
        Dim tmp2 = m - i
        Dim tmp3 = tmp1
        If (i >= 8) Then tmp3 = tmp2
        fvec(i) = y(i) - (x(0) + tmp1/(x(1)*tmp2 + x(2)*tmp3))
    Next
End Sub

Public Sub XmatLMJ(x As xrealMatrix, fjac As xrealMatrix)
    Dim m As Int32 = 15
    For i As Int32 = 0 To m - 1
        Dim tmp1 = i + 1
        Dim tmp2 = m - i
        Dim tmp3 = tmp1
        If (i >= 8) Then tmp3 = tmp2
        Dim tmp4 = (x(1) * tmp2 + x(2) * tmp3)
        tmp4 = tmp4 * tmp4
        fjac(i, 0) = -1
        fjac(i, 1) = tmp1 * tmp2 / tmp4
        fjac(i, 2) = tmp1 * tmp3 / tmp4
    Next
End Sub

Sub DemoLevenbergClassxreal()
    Dim n As Int32 = 3
    Dim m As Int32 = 15
    Dim matInput = xreal.MatZeros(n,1)
    matInput(0) = 1
    matInput(1) = 2  ' entries 2 .. 8 are 0.
    Dim matRes = xreal.Levenberg(AddressOf XmatLM, AddressOf XmatLMJ, matInput)
    Console.WriteLine("")
    matRes.print("X (solution):", 10)
    Dim Y = xreal.MatZeros(m,1)
    XmatLM(matRes, Y)
    Y.print("Y =  F(X=solution):", 10)
End Sub

This produces the following output:

Hello DemoLevenbergClassDbl()

X (solution):
0.0824105765758334,
1.1330366534715,
2.34369463894115,

matEval =  F(X=solution):
0.00588109515673704,
0.000265360346254795,
-0.000274673051589042,
-0.00654152299741256,
0.000823003778696318,
0.00129950005693674,
0.00446310734534455,
0.0199629386905548,
-0.0822160569476201,
0.0182119488681469,
0.0148111570102206,
0.0147099692233311,
0.0112079895785155,
0.00420403028888439,
-0.00680784758001085,