summaryrefslogtreecommitdiff
path: root/modules/polynomials/src/fortran/bezstp.f
blob: 1c3672b6f3a85559913fba5c191098a845263454 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
c Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
c Copyright (C) ????-2008 - INRIA
c
c This file must be used under the terms of the CeCILL.
c This source file is licensed as described in the file COPYING, which
c you should have received as part of this distribution.  The terms
c are also available at
c http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
      subroutine bezstp(p1,n1,p2,n2,a,na,u,nu,l,x,v,w,best,ipb,errr)
      double precision a(na,*),u(nu,*),x(na,*),v(nu,*),p1(*),p2(*)
      integer ipb(6)
      double precision w(*),best(*),errr
      double precision dt0,z,fact
      double precision c,s,errd,mm,eps,erri
      double precision dlamch,ddot
c
      eps=dlamch('p')
      n0=max(n1,n2)+1
      m1=max(n1-n2,0)
      m2=max(n2-n1,0)
      ll=2*l
      iuv=1
      ixy=iuv+ll
      iw1=ixy+ll
      iw=iw1+n0
      ifree=iw+2*n0
c     The matrix A is an upper triangular matrix catenated with a first full row
c     [A(1,1) ... A(1,n0-1) A(1,n0)
c      A(2,1) ... A(2,n0-1) A(2,n0)
c      A(3,1) ... A(3,n0-1)    0
c      A(4,1) ...    0         0
c      ...    ...   ...      ...   ]
c      
c     make it upper triangular by a sequence of givens rotations
      do 10 k=1,l
c     .  compute rotation that zeros a(k+1,n0+1-k)
         call giv(a(k,n0+1-k),a(k+1,n0+1-k),c,s)
c     .  apply it to the rows k and k+1 of a
         call drot(n0,a(k,1),na,a(k+1,1),na,c,s)
         a(k+1,n0+1-k)=0.0d+0
c     .  accumulate transformation in u
         call drot(ll,u(k,1),nu,u(k+1,1),nu,c,s)
         if(k.eq.1.and.l.lt.n0) then
c     .     store second row of a in x (that is right part of row 0 of a)
c     .     A=[[0 x]
c     .          At ]
            call dcopy(n0-1,a(2,1),na,x,na)
c     .     store second row of u in v (that is right part of row 0 of u)
            call dcopy(ll,u(2,1),nu,v,nu)
         endif
 10   continue
c
      call dcopy(ll,u(l,1),nu,w(iuv),1)
      call dcopy(ll,u(l+1,1),nu,w(ixy),1)

c
      if(l.le.abs(n1-n2)) then
c     .  The dimension of the image of the linear application is too
c     .  small, skip the errors computations
c     .  increase the space dimension
         goto 99
      endif
c     Get the highest degree coefficient of the CGD candidate
      fact=a(l,n0-l+1)

c     decrease the [u,v] degree using a linear combinaison with [x y]
      if(l.gt.1) then
         mm=w(ixy+2*m1)**2+w(ixy+1+2*m2)**2
         z=w(iuv+2*m1)*w(ixy+2*m1)+w(iuv+1+2*m2)*w(ixy+1+2*m2)
      else
         mm=w(ixy+2*m1)**2
         z=w(iuv+2*m1)*w(ixy+2*m1)
      endif
      if (mm.ne.0.0d+0) then
c     on abaisse le degre de [u,v]
         z=-z/mm
         call daxpy(ll,z,w(ixy),1,w(iuv),1)
      endif
c
      if (fact.eq.0.0d+0) then
c     .  the highest degree coefficient of the GCD candidate is zero. It is
c     .  possible to find a lower degree one, increase the space dimension
         goto 99
      endif
c     normalize the u and v componants of the unimodular matrix  to make
c     CGD candidate higher degree coefficient equal to 1
      call dscal(ll,1.0d+0/fact,w(iuv),1)
c     compute the determinant of the unimodular matrix (the determinant
c     of its degree 0 coefficient
      dt0=w(ixy+2*(l-1))*w(iuv+2*l-1)-w(ixy+2*l-1)*w(iuv+2*(l-1))
      if(dt0.eq.0.0d+0) then
c     .  the determinant of the unimodular matrix is 0,
c     .  increase the space dimension
         goto 99
      endif
c     normalize the x and y components of the unimodular matrix to make
c     it's determinant equal to 1
      call dscal(ll,1.0d+0/dt0,w(ixy),1)
      dt0=1.0d0
c
c     Estimate the forward error:
c     first compute ||p1*x-p2*y||
c     p1*x
      call dcopy(l-m1,w(ixy+2*m1),2,w(iw1),-1)
      call dpmul1(p1,n1,w(iw1),l-1-m1,w(iw))
      nw=n1+l-1-m1
c     p1*x+p2*y
      call dcopy(l-m2,w(ixy+1+2*m2),2,w(iw1),-1)
      call dpmul(p2,n2,w(iw1),l-1-m2,w(iw),nw)
      errd=ddot(nw+1,w(iw),1,w(iw),1)
c     now compute ||p1*u-p2*v-p||
c     p1*u
      if(l-1-m1.gt.0) then
         call dcopy(l-1-m1,w(iuv+2+2*m1),2,w(iw1),-1)
         call dpmul1(p1,n1,w(iw1),l-2-m1,w(iw))
         nw=n1+l-2-m1
      else
         call dpmul1(p1,n1,w(iuv+2*m1),0,w(iw))
         nw=n1
      endif
c     p1*u+p2*v
      if(l-1-m2.gt.0) then
         call dcopy(l-1-m2,w(iuv+3+2*m2),2,w(iw1),-1)
         call dpmul(p2,n2,w(iw1),l-2-m2,w(iw),nw)
      else
         call dpmul(p2,n2,w(iuv+1+2*m2),0,w(iw),nw)
      endif
c     p
      np=n0-l
      call dcopy(np+1,a(l,1),na,w(iw1),1)
      call daxpy(np,z,a(l+1,1),na,w(iw1),1)
      call dscal(np+1,1.0d+0/fact,w(iw1),1)
c     p1*u+p2*v-p
      call ddif(np+1,w(iw1),1,w(iw),1)
      errd=errd+ddot(nw+1,w(iw),1,w(iw),1)
c
c     Estimate the backward error
c     ------------------------------
c     first ||p*y+p1||
c     y
      call dcopy(n1-np+1,w(ixy+1+2*m2),2,w(iw),-1)
c     p*y+p1
      call dpmul1(w(iw1),np,w(iw),n1-np,w(iw))
      call dadd(n1+1,p1,1,w(iw),1)
      erri=ddot(n1+1,w(iw),1,w(iw),1)
c     now ||p*x-p2||
c     x
      call dcopy(n2-np+1,w(ixy+2*m1),2,w(iw),-1)
c     p*x
      call dpmul1(w(iw1),np,w(iw),n2-np,w(iw))
c     p*x-p2
      call ddif(n2+1,p2,1,w(iw),1)
      erri=erri+ddot(n2+1,w(iw),1,w(iw),1)

      if(max(erri,errd).lt.errr) then
c     .  A better solution found
         errr=max(erri,errd)
         nb=max(0,n0-l)
c     .  preserve the gcd and unimodular matrix candidates
c        best contains [gcd u,v,x,y],
c        the ipb array give info to split best.
         ipb(1)=1
c     .  store gcd candidate into best
         call dcopy(nb+1,a(l,1),na,best(ipb(1)),1)
         if(l.gt.1) then
            call daxpy(nb+1,z,a(l+1,1),na,best(ipb(1)),1)
         endif
         call dscal(nb+1,1.0d+0/fact,best(ipb(1)),1)
         ipb(2)=ipb(1)+nb+1

c     .  store the unimodular matrix candidate into best
         if(l.gt.1) then
            nn=max(n2-nb,1)
            call dcopy(nn,w(iuv+2*(l-nn)),2,best(ipb(2)),-1)
            ipb(3)=ipb(2)+nn
            nn=max(n1-nb,1)
            call dcopy(nn,w(iuv+1+2*(l-nn)),2,best(ipb(3)),-1)
            ipb(4)=ipb(3)+nn
         else
            best(ipb(2))=w(iuv)
            ipb(3)=ipb(2)+1
            best(ipb(3))=w(iuv+1)
            ipb(4)=ipb(3)+1
         endif
         nn=n2+1-nb
         call dcopy(nn,w(ixy+2*(l-nn)),2,best(ipb(4)),-1)
         ipb(5)=ipb(4)+nn
         nn=n1+1-nb
         call dcopy(nn,w(ixy+1+2*(l-nn)),2,best(ipb(5)),-1)
         ipb(6)=ipb(5)+nn
      endif
c
 99   continue
c     increase the dimension of the space
      return
      end