You are on page 1of 2

Option Explicit

Option Base 1
Function SimultEqNL(equations, variables, constants)
'Newton iteration method to find roots of nonlinear simultaneous equations
Dim I As Integer, J As Integer, K As Integer, N As Integer
Dim NIterations As Integer
Dim R As Integer, C As Integer
Dim VarAddr() As String, FormulaString() As String
Dim con() As Double, A() As Double, B() As Double
Dim V() As Double
Dim Y1 As Double, Y2 As Double
Dim tolerance As Double, incr As Double
N = equations.Rows.Count
K = variables.Rows.Count
If K = 1 Then K = variables.Columns.Count
If K <> N Then SimultEqNL = CVErr(xlErrRef): Exit Function
ReDim VarAddr(N), FormulaString(N), V(N), con(N)
ReDim A(N, N + 1), B(N, N + 1)
tolerance = 0.000000000001 'Convergence criterion.
incr = 0.0000000001 'Increment for numerical differentiation.
NIterations = 50
For I = 1 To N
VarAddr(I) = variables(I).Address
Next
'Initial values
For I = 1 To N
con(I) = constants(I).Value
V(I) = variables(I).Value: If V(I) = 0 Then V(I) = 1
Next
For J = 1 To NIterations
'Create N x N matrix of partial derivatives.
For R = 1 To N
For C = 1 To N
'Formulastring is formula in which all but one variable in each equation
'is replaced by current values.
FormulaString(R) = Application.ConvertFormula(equations(R).Formula, xlA1, xlA1,
xlAbsolute)
For I = 1 To N
If I <> C Then FormulaString(R) = Application.Substitute(FormulaString(R), VarAd
dr(I), V(I))
Next I
'Calculate partial derivative (central differences).
Y2 = Evaluate(Application.Substitute(FormulaString(R), VarAddr(C), V(C) * (1 + i
ncr)))
Y1 = Evaluate(Application.Substitute(FormulaString(R), VarAddr(C), V(C) * (1 - i
ncr)))
A(R, C) = (Y2 - Y1) / (2 * incr * V(C))
Next C
Next R
'Augment matrix of derivatives with vector of constants.
For R = 1 To N
FormulaString(R) = Application.ConvertFormula(equations(R).Formula, xlA1, xlA1,
xlAbsolute)
For C = 1 To N

FormulaString(R) = Application.Substitute(FormulaString(R), VarAddr(C), V(C))


Next C
A(R, N + 1) = con(R) - Evaluate(FormulaString(R))
Next R
For I = 1 To N
If Abs((A(I, N + 1)) / V(I)) > tolerance Then GoTo Refine
Next I
SimultEqNL = Application.Transpose(V)
Exit Function
Refine: Call GaussJordan3(N, A, B)
'Update V values
For I = 1 To N
V(I) = V(I) + A(I, N + 1)
Next I
Next J
' Exit here if no convergence after 50 cycles of iteration
SimultEqNL = CVErr(xlErrNA)
End Function
Sub GaussJordan3(N, AugMatrix, TempMatrix)
Dim I As Integer, J As Integer, K As Integer, L As Integer, P As Integer
Dim pivot As Double, temp As Double
For K = 1 To N
' Locate largest matrix element, use as pivot.
pivot = AugMatrix(K, K): P = K
For L = K + 1 To N
If Abs(AugMatrix(L, K)) < Abs(pivot) Then GoTo EndOfLoop
pivot = AugMatrix(L, K)
P = L
EndOfLoop: Next L
' Swap rows
For J = 1 To N + 1
temp = AugMatrix(K, J)
AugMatrix(K, J) = AugMatrix(P, J)
AugMatrix(P, J) = temp
Next J
' Normalize pivot row
For J = 1 To N + 1
TempMatrix(K, J) = AugMatrix(K, J) / pivot
Next J
' Do the Gauss elimination.
For I = 1 To N
If I = K Then GoTo EndOfLoop2
For J = 1 To N + 1
TempMatrix(I, J) = AugMatrix(I, J) - AugMatrix(I, K) * TempMatrix(K, J)
Next J
EndOfLoop2: Next I
For I = 1 To N
For J = 1 To N + 1
AugMatrix(I, J) = TempMatrix(I, J)
Next J
Next I
Next K
End Sub

You might also like