The following program calculates the minimum point of a multi-variable function using direct search method.
Click here to download a ZIP file containing the project files for this program.
The pseudo-code for this algorithm is:
The program prompts you to either use the predefined default input values or to enter the following for each variable:
1. Guess for the minimum point.
2. Initial search step value.
3. The minimum search step value.
In case you choose the default input values, the program displays these values and proceeds to find the optimum point. In the case you select being prompted, the program displays the name of each input variable along with its default value. You can then either enter a new value or simply press Enter to use the default value. This approach allows you to quickly and efficiently change only a few input values if you so desire.
The program displays the following results:
1. The coordinates of the minimum value.
2. The minimum function value.
3. The number of iterations
Here is a sample session to find the minimum of function:
f(x) = 10 + (x1-2)^2 + (x2+5)^2
Using initial values of 0, initial search steps of 0.1 for both variables, and minimum search steps of 1e-5 for both variables. Here is the sample console screen:
Here is the BASIC listing for the main module. The module contains several test functions:
Module Module1 Sub Main() Dim nNumVars As Integer = 2 Dim fX() As Double = {0, 0} Dim fParam() As Double = {0, 0} Dim fStepSize() As Double = {0.1, 0.1} Dim fMinStepSize() As Double = {0.00001, 0.00001} Dim nIter As Integer = 0 Dim I As Integer Dim fBestF As Double Dim sAnswer As String Dim oOpt As CDirectSearch Dim MyFx As MyFxDelegate = AddressOf Fx1 Dim SayFx As SayFxDelegate = AddressOf SayFx1 oOpt = New CDirectSearch Console.WriteLine("Direct Search Optimization") Console.WriteLine("Finding the minimu of function:") Console.WriteLine(SayFx()) Console.Write("Use default input values? (Y/N) ") sAnswer = Console.ReadLine() If sAnswer.ToUpper() = "Y" Then For I = 0 To nNumVars - 1 Console.WriteLine("X({0}) = {1}", I + 1, fX(I)) Console.WriteLine("Step Size({0}) = {1}", I + 1, fStepSize(I)) Console.WriteLine("Min Step Size({0}) = {1}", I + 1, fMinStepSize(I)) Next Else For I = 0 To nNumVars - 1 fX(I) = GetIndexedDblInput("X", I + 1, fX(I)) fStepSize(I) = GetIndexedDblInput("Initial step size(", I + 1, fStepSize(I)) fMinStepSize(I) = GetIndexedDblInput("Minimum step size", I + 1, fMinStepSize(I)) Next End If Console.WriteLine("******** FINAL RESULTS *************") fBestF = oOpt.DirectSearch(nNumVars, fX, fParam, fStepSize, fMinStepSize, nIter, MyFx) Console.WriteLine("Optimum at") For I = 0 To nNumVars - 1 Console.WriteLine("X({0}) = {1}", I + 1, fX(I)) Next Console.WriteLine("Function value = {0}", fBestF) Console.WriteLine("Number of iterations = {0}", nIter) Console.WriteLine() Console.Write("Press Enter to end the program ...") Console.ReadLine() End Sub Function GetDblInput(ByVal sPrompt As String, ByVal fDefInput As Double) As Double Dim sInput As String Console.Write("{0}? ({1}): ", sPrompt, fDefInput) sInput = Console.ReadLine() If sInput.Trim().Length > 0 Then Return Double.Parse(sInput) Else Return fDefInput End If End Function Function GetIndexedDblInput(ByVal sPrompt As String, ByVal nIndex As Integer, ByVal fDefInput As Double) As Double Dim sInput As String Console.Write("{0}({1})? ({2}): ", sPrompt, nIndex, fDefInput) sInput = Console.ReadLine() If sInput.Trim().Length > 0 Then Return Double.Parse(sInput) Else Return fDefInput End If End Function Function SayFx1() As String Return "F(X) = 10 + (X(1) - 2) ^ 2 + (X(2) + 5) ^ 2" End Function Function Fx1(ByVal N As Integer, ByRef X() As Double, ByRef fParam() As Double) As Double Return 10 + (X(0) - 2) ^ 2 + (X(1) + 5) ^ 2 End Function Function SayFx2() As String Return "F(X) = 100 * (X(1) - X(2) ^ 2) ^ 2 + (X(2) - 1) ^ 2" End Function Function Fx2(ByVal N As Integer, ByRef X() As Double, ByRef fParam() As Double) As Double Return 100 * (X(0) - X(1) ^ 2) ^ 2 + (X(1) - 1) ^ 2 End Function Function SayFx3() As String Return "F(X) = X(1) - X(2) + 2 * X(1) ^ 2 + 2 * X(1) * X(2) + X(2) ^ 2" End Function Function Fx3(ByVal N As Integer, ByRef X() As Double, ByRef fParam() As Double) As Double Return X(0) - X(1) + 2 * X(0) ^ 2 + 2 * X(0) * X(1) + X(1) ^ 2 End Function End Module
Notice that the user-defined functions have accompanying helper functions to display the mathematical expression of the function being optimized. For example, function Fx1 has the helper function SayFx1 to list the function optimized in Fx1. Please observe the following rules::
The program uses the following class to optimize the objective function:
Public Delegate Function MyFxDelegate(ByVal nNumVars As Integer, ByRef fX() As Double, ByRef fParam() As Double) As Double Public Delegate Function SayFxDelegate() As String Public Class CDirectSearch Public Function DirectSearch(ByVal nNumVars As Integer, ByRef fX() As Double, ByRef fParam() As Double, _ ByRef fStepSize() As Double, ByRef fMinStepSize() As Double, ByRef nIter As Integer, _ ByVal MyFx As MyFxDelegate) As Double Const StepReduceFactor As Integer = 10 Dim fBestF As Double Dim F, fXX As Double Dim I As Integer Dim bStop, bFound As Boolean fBestF = MyFx(nNumVars, fX, fParam) nIter = 0 Do nIter = nIter + 1 For I = 0 To nNumVars - 1 bFound = False Do fXX = fX(I) fX(I) = fXX + fStepSize(I) F = MyFx(nNumVars, fX, fParam) If F < fBestF Then fBestF = F bFound = True Else fX(I) = fXX - fStepSize(I) F = MyFx(nNumVars, fX, fParam) If F < fBestF Then fBestF = F bFound = True Else fX(I) = fXX If Not bFound Then fStepSize(I) = fStepSize(I) / StepReduceFactor End If Exit Do End If End If Loop Next I bStop = True For I = 0 To nNumVars - 1 If fStepSize(I) >= fMinStepSize(I) Then bStop = False Exit For End If Next I Loop Until bStop Return fBestF End Function End Class
Copyright (c) Namir Shammas. All rights reserved.