-- test_simeq_newton5.adb solve nonlinear system of equations -- method: newton iteration using Jacobian -- use list for higher order terms -- -- Given problem A X = Y where X may have terms x1, x2, x3, x4, ... -- and nonlinear such as: x1*x2, x1^2*x3, x3/x2, x3^3/x2^2 ... -- A sparse matrix may be used, coefficients given -- Y is vector of real, given -- independent unknowns are x1, ... , xn -- a maximal term can have up to power of 3 divided by power of 2 -- in this implementation (if we had symbolic differentiation, no limit) -- a term could be x1 , x1*x3 , x2/x5 , x1*x2*x3/(x4*x5) , x2^3/x4^2 -- -- Solve by initial guess at values of x1, x2, x3, x4 computing products -- X_next = X_initial - J_initial^-1 * (A * X_initial - Y) -- in general X_next = X_prev - (J_prev^-1 * (A * X_prev - Y))*b -- where 0 < b < 1, often 0.5, for stability -- -- solved when abs sum each row A * X_next -Y < epsilon -- -- There may be no solution -- It may stall, stop if abs(X_next-X_prev)0 then Put("*"&Xnames(Var1(J))); end if; if Var2(J)>0 then Put("*"&Xnames(Var2(J))); end if; if Var3(J)>0 then Put("*"&Xnames(Var3(J))); end if; if Vari1(J)>0 then Put("/("&Xnames(Vari1(J))); end if; if Vari2(J)>0 then Put("*"&Xnames(Vari2(J))); end if; if Vari1(J)>0 or Vari2(J)>0 then Put(")"); end if; if J /= n+nlin then Put_Line("+"); else New_Line; end if; end loop; Put_Line(" = Y(i)"); New_Line; end Print_Equation; procedure test_case1 is n : integer := 2; -- number of linear unknowns nlin : integer := 2; -- number of non linear terms Var1 : integer_vector(1..n+nlin); Var2 : integer_vector(1..n+nlin); Var3 : integer_vector(1..n+nlin); Vari1 : integer_vector(1..n+nlin); Vari2 : integer_vector(1..n+nlin); A : real_matrix(1..n,1..n+nlin); Y : real_vector(1..n); X : real_vector(1..n+nlin); X_soln : real_vector(1..n+nlin); err, aerr : real; -- error from test solution begin Put_line("test_case_1"); -- build test case for i in 1..n loop for j in 1..n+nlin loop A(i,j) := 1.0; end loop; end loop; A(1,4) := 0.0; -- x + y + x^2 = 4 A(2,3) := 0.0; -- x + y + y^2 = 7 -- debug print for i in 1..n loop for j in 1..n+nlin loop Put("A("); Put(i,2); Put(","); Put(j,2); Put(")="); Put(A(i,j),3,6); new_line; end loop; end loop; new_line; -- setup definition of linear and nonlinear terms Var1 := (1, 2, 1, 2); Var2 := (0, 0, 1, 2); Var3 := (0, 0, 0, 0); Vari1 := (0, 0, 0, 0); Vari2 := (0, 0, 0, 0); -- choose x1=1 x2=2 , compute x1*x2, etc. X_soln(1) := 1.0; X_soln(2) := 2.0; -- compute dependent terms for I in n+1..n+nlin loop X_Soln(I) := 1.0; if Var1(I) > 0 then X_soln(i) := X_soln(Var1(i)); end if; if Var2(i) > 0 then X_soln(i) := X_soln(i) * X_soln(Var2(i)); end if; if Var3(i) > 0 then X_soln(i) := X_soln(i) * X_soln(Var3(i)); end if; if Vari1(i) > 0 then X_soln(i) := X_soln(i) / X_soln(Vari1(i)); end if; if Vari2(i) > 0 then X_soln(i) := X_soln(i) / X_soln(Vari2(i)); end if; end loop; -- debug print for i in 1..n loop Put("X_soln("); Put(i,2); Put(")="); Put(X_soln(i),3,6); new_line; end loop; new_line; -- set up Y for i in 1..n loop Y(i) := 0.0; for j in 1..n+nlin loop Y(i) := Y(i) + A(i,j)*X_soln(j); end loop; end loop; -- debug print for i in 1..n loop Put("Y("); Put(i,2); Put(")="); Put(Y(i),3,6); new_line; end loop; new_line; Print_Equation(n, nlin, Var1, Var2, Var3, Vari1, Vari2); -- initial condition X(1) := 0.5; X(2) := 0.5; -- higher terms not needed -- debug print Put_Line("initial guess"); for i in 1..n loop Put("X("); Put(i,2); Put(")="); Put(X(i),3,6); new_line; end loop; new_line; simeq_newton5(n, nlin, A, Y, Var1, Var2, Var3, Vari1, Vari2, X); -- check solution Put_line("test case1 solution"); err := 0.0; for i in 1..n loop Put("X("); Put(i,2); Put(")= "); Put(X(i)); Put(", soln="); Put(X_Soln(i)); Put(", err="); Put(X_Soln(i)-X(i)); new_line; aerr := 0.0; for j in 1..n+nlin loop aerr := aerr + A(i,j)*X(j); end loop; aerr := aerr-Y(i); err := err + abs(aerr); end loop; new_line; Put(" residual= "); Put(err); new_line; new_line; end test_case1; procedure test_case2 is n : integer := 3; -- number of linear unknowns nlin : integer := 4; -- number of non linear terms Var1 : integer_vector(1..n+nlin); Var2 : integer_vector(1..n+nlin); Var3 : integer_vector(1..n+nlin); Vari1 : integer_vector(1..n+nlin); Vari2 : integer_vector(1..n+nlin); A : real_matrix(1..n,1..n+nlin); Y : real_vector(1..n); X : real_vector(1..n+nlin); X_soln : real_vector(1..n+nlin); err, aerr : real; -- error from test solution begin Put_line("test_case_2"); -- build test case for i in 1..n loop for j in 1..n+nlin loop A(i,j) := Real(Random(S)); end loop; end loop; -- debug print for i in 1..n loop for j in 1..n+nlin loop Put("A("); Put(i,2); Put(","); Put(j,2); Put(")="); Put(A(i,j),3,6); new_line; end loop; end loop; new_line; -- setup definition of linear and nonlinear terms Var1 := (1, 2, 3, 1, 3, 2, 1); Var2 := (0, 0, 0, 2, 2, 0, 1); Var3 := (0, 0, 0, 0, 2, 0, 1); Vari1 := (0, 0, 0, 0, 0, 3, 3); Vari2 := (0, 0, 0, 0, 0, 0, 3); -- choose x1=1.1 x2=1.2 , compute x1*x2, etc. X_soln(1) := 1.1; X_soln(2) := 1.2; X_Soln(3) := 1.4; -- compute dependent terms for I in n+1..n+nlin loop X_Soln(I) := 1.0; if Var1(I) > 0 then X_soln(i) := X_soln(Var1(i)); end if; if Var2(i) > 0 then X_soln(i) := X_soln(i) * X_soln(Var2(i)); end if; if Var3(i) > 0 then X_soln(i) := X_soln(i) * X_soln(Var3(i)); end if; if Vari1(i) > 0 then X_soln(i) := X_soln(i) / X_soln(Vari1(i)); end if; if Vari2(i) > 0 then X_soln(i) := X_soln(i) / X_soln(Vari2(i)); end if; end loop; -- debug print for i in 1..n loop Put("X_soln("); Put(i,2); Put(")="); Put(X_soln(i),3,6); new_line; end loop; new_line; -- set up Y for i in 1..n loop Y(i) := 0.0; for j in 1..n+nlin loop Y(i) := Y(i) + A(i,j)*X_soln(j); end loop; end loop; -- debug print for i in 1..n loop Put("Y("); Put(i,2); Put(")="); Put(Y(i),3,6); new_line; end loop; new_line; Print_Equation(n, nlin, Var1, Var2, Var3, Vari1, Vari2); -- initial condition X(1) := 1.0; X(2) := 1.0; X(3) := 1.0; -- higher terms not needed -- debug print Put_Line("initial guess"); for i in 1..n loop Put("X("); Put(i,2); Put(")="); Put(X(i),3,6); new_line; end loop; new_line; simeq_newton5(n, nlin, A, Y, Var1, Var2, Var3, Vari1, Vari2, X); -- check solution Put_line("test case2 solution"); err := 0.0; for i in 1..n loop Put("X("); Put(i,2); Put(")= "); Put(X(i)); Put(", soln="); Put(X_Soln(i)); Put(", err="); Put(X_Soln(i)-X(i)); new_line; aerr := 0.0; for j in 1..n+nlin loop aerr := aerr + A(i,j)*X(j); end loop; aerr := aerr-Y(i); err := err + abs(aerr); end loop; new_line; Put(" residual= "); Put(err); new_line; new_line; end test_case2; procedure test_case3 is n : integer := 4; -- number of linear unknowns nlin : integer := 3; -- number of non linear terms Var1 : integer_vector(1..n+nlin); Var2 : integer_vector(1..n+nlin); Var3 : integer_vector(1..n+nlin); Vari1 : integer_vector(1..n+nlin); Vari2 : integer_vector(1..n+nlin); A : real_matrix(1..n,1..n+nlin); Y : real_vector(1..n); X : real_vector(1..n+nlin); X_soln : real_vector(1..n+nlin); err, aerr : real; -- error from test solution begin Put_line("test_case_3"); -- build test case for i in 1..n loop for j in 1..n+nlin loop A(i,j) := udrnrt; end loop; end loop; -- debug print for i in 1..n loop for j in 1..n+nlin loop Put("A("); Put(i,2); Put(","); Put(j,2); Put(")="); Put(A(i,j),3,6); new_line; end loop; end loop; new_line; -- setup definition of linear and nonlinear terms Var1 := (1, 2, 3, 4, 1, 1, 4); Var2 := (0, 0, 0, 0, 2, 1, 4); Var3 := (0, 0, 0, 0, 0, 3, 4); Vari1 := (0, 0, 0, 0, 0, 0, 0); Vari2 := (0, 0, 0, 0, 0, 0, 0); -- choose x1=1.1 x2=1.2 x3=1.4 x4 =1.5, compute x1*x2, etc. X_soln(1) := 1.1; X_soln(2) := 1.2; X_soln(3) := 1.4; X_soln(4) := 1.5; -- X_soln(5..7) := -- computed from "Var's" -- compute dependent terms for I in n+1..n+nlin loop X_Soln(I) := 1.0; if Var1(I) > 0 then X_soln(i) := X_soln(Var1(i)); end if; if Var2(i) > 0 then X_soln(i) := X_soln(i) * X_soln(Var2(i)); end if; if Var3(i) > 0 then X_soln(i) := X_soln(i) * X_soln(Var3(i)); end if; if Vari1(i) > 0 then X_soln(i) := X_soln(i) / X_soln(Vari1(i)); end if; if Vari2(i) > 0 then X_soln(i) := X_soln(i) / X_soln(Vari2(i)); end if; end loop; -- debug print for i in 1..n loop Put("X_soln("); Put(i,2); Put(")="); Put(X_soln(i),3,6); new_line; end loop; new_line; -- set up Y for i in 1..n loop Y(i) := 0.0; for j in 1..n+nlin loop Y(i) := Y(i) + A(i,j)*X_soln(j); end loop; end loop; -- debug print for i in 1..n loop Put("Y("); Put(i,2); Put(")="); Put(Y(i),3,6); new_line; end loop; new_line; Print_Equation(n, nlin, Var1, Var2, Var3, Vari1, Vari2); -- initial condition X(1) := 1.0; X(2) := 1.0; X(3) := 1.0; X(4) := 1.0; -- debug print Put_Line("initial guess"); for i in 1..n loop Put("X("); Put(i,2); Put(")="); Put(X(i),3,6); new_line; end loop; new_line; simeq_newton5(n, nlin, A, Y, Var1, Var2, Var3, Vari1, Vari2, X); -- check solution Put_line("test case3 solution"); err := 0.0; for i in 1..n loop Put("X("); Put(i,2); Put(")= "); Put(X(i)); Put(", soln="); Put(X_Soln(i)); Put(", err="); Put(X_Soln(i)-X(i)); new_line; aerr := 0.0; for j in 1..n+nlin loop aerr := aerr + A(i,j)*X(j); end loop; aerr := aerr-Y(I); err := err + abs(aerr); end loop; new_line; Put(" residual= "); Put(err); new_line; new_line; end test_case3; procedure test_case4 is n : integer := 4; -- number of linear unknowns nlin : integer := 6; -- number of non linear terms Var1 : integer_vector(1..n+nlin); Var2 : integer_vector(1..n+nlin); Var3 : integer_vector(1..n+nlin); Vari1 : integer_vector(1..n+nlin); Vari2 : integer_vector(1..n+nlin); A : real_matrix(1..n,1..n+nlin); Y : real_vector(1..n); X : real_vector(1..n+nlin); X_soln : real_vector(1..n+nlin); err, aerr : real; -- error from test solution begin Put_line("test_case_4"); -- build test case for i in 1..n loop for j in 1..n+nlin loop A(i,j) := udrnrt; end loop; end loop; -- debug print for i in 1..n loop for j in 1..n+nlin loop Put("A("); Put(i,2); Put(","); Put(j,2); Put(")="); Put(A(i,j),3,6); new_line; end loop; end loop; new_line; -- setup definition of linear and nonlinear terms Var1 := (1, 2, 3, 4, 1, 2, 3, 4, 1, 2); Var2 := (0, 0, 0, 0, 1, 2, 3, 4, 2, 3); Var3 := (0, 0, 0, 0, 1, 2, 3, 4, 3, 4); Vari1 := (0, 0, 0, 0, 0, 0, 0, 0, 0, 0); Vari2 := (0, 0, 0, 0, 0, 0, 0, 0, 0, 0); -- choose x1=1.1 x2=1.2 x3=1.4 x4 =1.5, compute x1*x2, etc. X_soln(1) := 1.1; X_soln(2) := 1.2; X_soln(3) := 1.4; X_soln(4) := 1.5; -- X_soln(5..10) := -- computed from "Var's" -- compute dependent terms for I in n+1..n+nlin loop X_Soln(I) := 1.0; if Var1(I) > 0 then X_soln(i) := X_soln(Var1(i)); end if; if Var2(i) > 0 then X_soln(i) := X_soln(i) * X_soln(Var2(i)); end if; if Var3(i) > 0 then X_soln(i) := X_soln(i) * X_soln(Var3(i)); end if; if Vari1(i) > 0 then X_soln(i) := X_soln(i) / X_soln(Vari1(i)); end if; if Vari2(i) > 0 then X_soln(i) := X_soln(i) / X_soln(Vari2(i)); end if; end loop; -- debug print for i in 1..n loop Put("X_soln("); Put(i,2); Put(")="); Put(X_soln(i),3,6); new_line; end loop; new_line; -- set up Y for i in 1..n loop Y(i) := 0.0; for j in 1..n+nlin loop Y(i) := Y(i) + A(i,j)*X_soln(j); end loop; end loop; -- debug print for i in 1..n loop Put("Y("); Put(i,2); Put(")="); Put(Y(i),3,6); new_line; end loop; new_line; Print_Equation(n, nlin, Var1, Var2, Var3, Vari1, Vari2); -- initial condition X(1) := 0.7; X(2) := 0.75; X(3) := 0.8; X(4) := 0.85; -- debug print Put_Line("initial guess"); for i in 1..n loop Put("X_init("); Put(i,2); Put(")="); Put(X(i),3,6); new_line; end loop; new_line; simeq_newton5(n, nlin, A, Y, Var1, Var2, Var3, Vari1, Vari2, X, 12, 1.0e-5, 1); -- check solution Put_line("test case4 solution"); err := 0.0; for i in 1..n loop Put("X("); Put(i,2); Put(")= "); Put(X(i)); Put(", soln="); Put(X_Soln(i)); Put(", err="); Put(X_Soln(i)-X(i)); new_line; aerr := 0.0; for j in 1..n+nlin loop aerr := aerr + A(i,j)*X(j); end loop; aerr := aerr-Y(I); err := err + abs(aerr); end loop; new_line; Put(" sum of errors= "); Put(err); new_line; new_line; end test_case4; procedure test_case5 is n : integer := 5; -- number of linear unknowns nlin : integer := 15; -- number of non linear terms Var1 : integer_vector(1..n+nlin); Var2 : integer_vector(1..n+nlin); Var3 : integer_vector(1..n+nlin); Vari1 : integer_vector(1..n+nlin); Vari2 : integer_vector(1..n+nlin); A : real_matrix(1..n,1..n+nlin); Y : real_vector(1..n); X : real_vector(1..n+nlin); X_soln : real_vector(1..n+nlin); err, aerr : real; -- error from test solution begin Put_line("test_case_5"); -- build test case, first and last equation solved for i in 1..n loop for j in 1..n+nlin loop A(i,j) := 0.0; end loop; A(i,i) := 1.0; end loop; for i in 2..n-1 loop for j in n+1..n+nlin loop A(i,j) := udrnrt; end loop; end loop; -- debug print for i in 1..n loop for j in 1..n+nlin loop Put("A("); Put(i,2); Put(","); Put(j,2); Put(")="); Put(A(i,j),3,6); new_line; end loop; end loop; new_line; -- setup definition of linear and nonlinear terms Var1 := (1, 2, 3, 4, 5, 2, 2, 2, 3, 3, 4, 2, 2, 2, 3, 3, 3, 4, 4, 4); Var2 := (0, 0, 0, 0, 0, 2, 3, 4, 3, 4, 4, 2, 2, 2, 3, 3, 3, 4, 4, 4); Var3 := (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 4, 2, 3, 4, 2, 3, 4); Vari1 := (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); Vari2 := (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); -- choose x1=1.1 x2=1.2 x3=1.4 x4 =1.5, compute x1*x2, etc. X_soln(1) := 1.1; X_soln(2) := 1.2; X_soln(3) := 1.4; X_soln(4) := 1.5; X_soln(5) := 1.7; -- compute dependent terms for I in n+1..n+nlin loop X_Soln(I) := 1.0; if Var1(I) > 0 then X_soln(i) := X_soln(Var1(i)); end if; if Var2(i) > 0 then X_soln(i) := X_soln(i) * X_soln(Var2(i)); end if; if Var3(i) > 0 then X_soln(i) := X_soln(i) * X_soln(Var3(i)); end if; if Vari1(i) > 0 then X_soln(i) := X_soln(i) / X_soln(Vari1(i)); end if; if Vari2(i) > 0 then X_soln(i) := X_soln(i) / X_soln(Vari2(i)); end if; end loop; -- debug print for i in 1..n loop Put("X_soln("); Put(i,2); Put(")="); Put(X_soln(i),3,6); new_line; end loop; new_line; -- set up Y for i in 1..n loop Y(i) := 0.0; for j in 1..n+nlin loop Y(i) := Y(i) + A(i,j)*X_soln(j); end loop; end loop; -- debug print for i in 1..n loop Put("Y("); Put(i,2); Put(")="); Put(Y(i),3,6); new_line; end loop; new_line; Print_Equation(n, nlin, Var1, Var2, Var3, Vari1, Vari2); -- initial condition for i in 1..n loop X(i) := 1.0; end loop; -- debug print Put_Line("initial guess"); for i in 1..n loop Put("X_init("); Put(i,2); Put(")="); Put(X(i),3,6); new_line; end loop; new_line; simeq_newton5(n, nlin, A, Y, Var1, Var2, Var3, Vari1, Vari2, X, 24, 1.0e-4, 1); -- check solution Put_line("test case5 solution, computed, expected not unique"); err := 0.0; for i in 1..n loop Put("X("); Put(i,2); Put(")= "); Put(X(i)); Put(", soln="); Put(X_Soln(i)); Put(", err="); Put(X_Soln(i)-X(i)); new_line; aerr := 0.0; for j in 1..n+nlin loop aerr := aerr + A(i,j)*X(j); end loop; aerr := aerr-Y(I); err := err + abs(aerr); end loop; new_line; Put(" sum of errors= "); Put(err); new_line; new_line; Put_Line("check when given solution as initial condition"); -- initial condition for i in 1..n loop X(i) := X_Soln(i); end loop; simeq_newton5(n, nlin, A, Y, Var1, Var2, Var3, Vari1, Vari2, X, 4, 1.0e-4, 1); new_line; end test_case5; procedure test_case6 is n : integer := 5; -- number of linear unknowns nlin : integer := 1; -- number of non linear terms Var1 : integer_vector(1..n+nlin); Var2 : integer_vector(1..n+nlin); Var3 : integer_vector(1..n+nlin); Vari1 : integer_vector(1..n+nlin); Vari2 : integer_vector(1..n+nlin); A : real_matrix(1..n,1..n+nlin); Y : real_vector(1..n); X : real_vector(1..n+nlin); X_soln : real_vector(1..n+nlin); err, aerr : real; -- error from test solution begin Put_line("test_case_6"); -- build test case for i in 1..n loop for j in 1..n+nlin loop A(i,j) := udrnrt; end loop; end loop; -- debug print for i in 1..n loop for j in 1..n+nlin loop Put("A("); Put(i,2); Put(","); Put(j,2); Put(")="); Put(A(i,j),3,6); new_line; end loop; end loop; new_line; -- setup definition of linear and nonlinear terms Var1 := (1, 2, 3, 4, 5, 1); Var2 := (0, 0, 0, 0, 0, 2); Var3 := (0, 0, 0, 0, 0, 3); Vari1 := (0, 0, 0, 0, 0, 4); Vari2 := (0, 0, 0, 0, 0, 5); -- choose x1=1.1 x2=1.2 x3=1.4 x4=1.5, x5=1.9 X_soln(1) := 1.1; X_soln(2) := 1.2; X_soln(3) := 1.4; X_soln(4) := 1.5; X_soln(5) := 1.9; -- X_soln(6) := -- computed from "Var's" -- compute dependent terms for I in n+1..n+nlin loop X_Soln(I) := 1.0; if Var1(I) > 0 then X_soln(i) := X_soln(Var1(i)); end if; if Var2(i) > 0 then X_soln(i) := X_soln(i) * X_soln(Var2(i)); end if; if Var3(i) > 0 then X_soln(i) := X_soln(i) * X_soln(Var3(i)); end if; if Vari1(i) > 0 then X_soln(i) := X_soln(i) / X_soln(Vari1(i)); end if; if Vari2(i) > 0 then X_soln(i) := X_soln(i) / X_soln(Vari2(i)); end if; end loop; -- debug print for i in 1..n loop Put("X_soln("); Put(i,2); Put(")="); Put(X_soln(i),3,6); new_line; end loop; new_line; -- set up Y for i in 1..n loop Y(i) := 0.0; for j in 1..n+nlin loop Y(i) := Y(i) + A(i,j)*X_soln(j); end loop; end loop; -- debug print for i in 1..n loop Put("Y("); Put(i,2); Put(")="); Put(Y(i),3,6); new_line; end loop; new_line; Print_Equation(n, nlin, Var1, Var2, Var3, Vari1, Vari2); -- initial condition X(1) := 0.7; X(2) := 0.75; X(3) := 0.5; X(4) := 0.9; X(5) := 0.6; -- debug print Put_Line("initial guess"); for i in 1..n loop Put("X_init("); Put(i,2); Put(")="); Put(X(i),3,6); new_line; end loop; new_line; simeq_newton5(n, nlin, A, Y, Var1, Var2, Var3, Vari1, Vari2, X, 24, 1.0e-3, 1); -- check solution Put_line("test case6 solution"); err := 0.0; for i in 1..n loop Put("X("); Put(i,2); Put(")= "); Put(X(i)); Put(", soln="); Put(X_Soln(i)); Put(", err="); Put(X_Soln(i)-X(i)); new_line; aerr := 0.0; for j in 1..n+nlin loop aerr := aerr + A(i,j)*X(j); end loop; aerr := aerr-Y(I); err := err + abs(aerr); end loop; new_line; Put(" sum of errors= "); Put(err); new_line; new_line; end test_case6; begin Put_line("test_simeq_newton5.adb running"); Put_Line("a random number="&Float'Image(Random(S))); test_case1; test_case2; test_case3; test_case4; -- close but fails test_case5; -- tough test_case6; -- stress max nonlinear Put_line("end test_simeq_newton5"); end test_simeq_newton5;