声振论坛

 找回密码
 我要加入

QQ登录

只需一步,快速开始

查看: 2741|回复: 2

[稳定性与分岔] 非线性代数方程组零点计算Codim=1的实例[附代码]

[复制链接]
发表于 2019-1-7 11:04 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?我要加入

x
本帖最后由 mxlzhenzhu 于 2019-1-7 11:06 编辑

坛子里那么多高手,却不愿意分享自己的代码,遮遮掩掩,小弟初学,愿意分享给大家一个代码,计算非线性代数方程的Fold的实例文件,Predictor-Corrector算法,只能处理Codim=1的情况,Codim=2的情况太难了,还在学习中:
  1. %% Predictor-Solver Method verification
  2. %% mxl.2018-12-6
  3. %% 总结:本程序非常成功,测试下面的三个例子都没有问题.

  4. clear
  5. clc
  6. %   %---------------------------------------------------------------------%
  7. %   (1)设计非线性函数
  8. %   %---------------------------------------------------------------------%
  9. syms u Lambda
  10. f=@(u,Lambda)(u-1).^3.*(2*u-5)+u.*Lambda;
  11. Gu=@(u,Lambda)Lambda + 2*(u - 1)^3 + 3*(2*u - 5)*(u - 1)^2;
  12. Gy=@(u)u;

  13. % f=@(u,Lambda)(u.^2-1).*(u.^2-4)+Lambda*u.^2.*exp(0.1*u);
  14. % Gu=@(u,Lambda)2*u*(u^2 - 1) + 2*u*(u^2 - 4) + 2*Lambda*u*exp(u/10) + (Lambda*u^2*exp(u/10))/10;
  15. % Gy=@(u)u.^2.*exp(0.1*u);

  16. % f=@(u,Lambda)u.^2-4*u+Lambda;
  17. % Gu=@(u,Lambda)2*u-4;
  18. % Gy=@(u)1;




  19. u0=1;Lambda0=0;
  20. h=1e-3;%计算这个零点

  21. ds=3e-3;
  22. Maximum_dS=10*ds;%允许的超曲线最大增量
  23. Ill_Condition_TOL=1e-5;%小于这个值认为是病态
  24. TOL=1e-8;%小于这个值认为是收敛的.
  25. MaxTimes=500;
  26. direction='Positive';
  27. N=floor(5/h);



  28. x=zeros(N,2);%保存
  29. x(1,:)=[u0,Lambda0];
  30. Jx=[Gu(u0,Lambda0),Gy(u0)];

  31. tv0=Compute_Tangent_Vector(Jx,[],direction);
  32. % Step_Ratio=0.6;%不能太冒进
  33. tv=[];
  34. if abs(f(u0,Lambda0))>TOL
  35.     error('Incorrect I.C.')
  36. end
  37. for loop=2:N
  38.    
  39.     %----Predictor
  40.     Jx=[Gu(u0,Lambda0),Gy(u0)];
  41.     tv=Compute_Tangent_Vector(Jx,tv,direction);
  42.     if dot(tv,tv0)>0
  43.         tv0=tv;
  44.     else
  45.         tv=-tv;
  46.     end
  47.     A=[Jx;tv.'];
  48.     B=inv(A);%计算第一次
  49.     dx=B*[-Gy(u0);ds];
  50.     Step_Ratio=ds/norm(dx);
  51. %     if Step_Ratio<1
  52.         dx=Step_Ratio*dx/10;
  53. %     end
  54. %     if ~strcmp(direction,'Positive')
  55. %         up=u0+dx(1:end-1);
  56. %         Lambda1=Lambda0+dx(end);
  57. %     else
  58.         up=u0-dx(1:end-1);
  59.         Lambda1=Lambda0-dx(end);
  60. %     end
  61.    
  62.     if ~tv(end)
  63.         disp('It''s a Fold.');
  64.     end

  65.     %----Corrector
  66.     for loopi=1:MaxTimes
  67.         if loopi>1
  68.             xk0=[xk1(1);Lambda0];
  69.             xk1=xk2;            
  70.         else
  71.             xk0=[u0;Lambda0];
  72.             xk1=[up;Lambda1];            
  73.         end     
  74.         %----迭代计算xk2,收敛以后保存
  75.         r=xk1-xk0;
  76.         delta=[f(xk1(1),xk1(2))-f(xk0(1),xk0(2));r.'*tv-ds];%% 采用 常数h迭代的时候,在达到LP的时候,这里是不正确的,要么修改h,要么想法计算得到LP。

  77.         temp=dot(r,r);
  78.         if temp
  79.            c=(delta-A*r)/temp;
  80.            A=A+c*r.';
  81.         else
  82.            break;
  83.         end
  84.         temp=r.'*B*delta;
  85.         if temp
  86.            B=B+(r-B*delta)*r.'*B/temp;
  87.         end
  88.         v=B*[f(xk1(1),xk1(2));0];
  89.         xk2=xk1-v;
  90.         if norm(v)>Maximum_dS
  91.             xk2=xk1-v;            
  92.         end

  93.         if max(norm(v),norm(f(xk2(1),xk2(2))))<TOL           
  94.             break;
  95.         end
  96.       
  97.     end % for 继续迭代
  98.    
  99.     if loopi<MaxTimes
  100.         x(loop,:)=xk2.';
  101.         u0=xk2(1:end-1);
  102.         Lambda0=xk2(end);
  103.     else
  104.         warning('Diverged');
  105.         %----当前迭代步无解,需要新的算法,改变分叉参数增量方向
  106. %         error('Sub-routine1')
  107.         if strcmp(direction,'Positvie')   
  108.             direction='Negative';
  109.         else
  110.             direction='Positvie';
  111.         end
  112. %         error('Diverged')
  113.     end
  114.    
  115. end
  116. plot(x(:,end),x(:,1),'b')
  117. hold on
  118. scatter(x(:,end),x(:,1),'r')
  119. hold off
复制代码
上面这个是主程序,再贴一个计算切向向量的子程序:
  1. function tv=Compute_Tangent_Vector(Jx,tv,varargin)
  2. %% 根据Jx矩阵和初始化或者上一步切向向量Tv,计算新的切向向量.
  3. %% 该程序只适用于亏秩1的矩阵,Example: Jx=[0 0]会失败
  4. %% 迭代次数很少的。
  5. [~,n]=size(Jx);% n-1 X n

  6. if isempty(tv)
  7.     tv=rand(n,1);
  8. end

  9. if nargin==3
  10.     direction=varargin{1};
  11. else
  12.     direction='Positive';
  13. end

  14. b=zeros(n,1);
  15. b(end)=1;
  16. for loop=1:3
  17.     A=[Jx;tv.'];
  18.    
  19.     tv=A\b;
  20.     tv=tv./norm(tv);
  21. end

  22. if det(A)<0
  23.         tv=-tv;
  24. elseif det(A)==0
  25.     warning('Matrix A is singular.')
  26. else
  27.     % nothing, keep det(A) positive
  28. end

  29. if ~strcmp(direction,'Positive')
  30.     tv=-tv;
  31. end

  32. end
复制代码


哈哈哈,就这么点吧,希望版主加精





补充内容 (2019-1-17 21:49):
1)定义了匿名函数f; 2)定义了函数的导数Gu;3)定义了弧长参数导数Gy; 未知数为 u, 增广向量为 x=[u,Lambda], Lambda是弧长参数。程序功能比较简单,能够跟踪计算非线性方程的零点。

补充内容 (2019-1-17 21:51):
这个Script,要求Gy&和Gu是已知的; 如果不能显式求导,你必需写代码,用有限差分算法获取导数Gu&Gy。

补充内容 (2019-1-17 21:52):
这里并没有包含分叉探测,以及分支转换等代码内容,请自己往上面添加。这里只是简单的Predictor-Corrector算法。

补充内容 (2019-1-17 21:56):
Jx=[Gu,Gy]是一个Jacobian矩阵,n x (n+1)的矩阵,因此有左右零空间向量。计算切向向量的那个函数,可以输入direction='Positive'或者其他,也就是可以计算正反两个方向的切向向量。
回复
分享到:

使用道具 举报

发表于 2019-1-7 17:03 | 显示全部楼层
楼主无私奉献精神值得尊重!必须顶!
发表于 2021-4-14 10:27 | 显示全部楼层
赞!相互学习,共同进步。
您需要登录后才可以回帖 登录 | 我要加入

本版积分规则

QQ|小黑屋|Archiver|手机版|联系我们|声振论坛

GMT+8, 2024-12-27 21:11 , Processed in 0.120333 second(s), 18 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表