codac 2.0.0
Loading...
Searching...
No Matches
codac2_inversion.h
Go to the documentation of this file.
1
9
10#pragma once
11
12#include <ostream>
13#include <iostream>
14#include "codac2_Matrix.h"
17
18namespace codac2
19{
20 enum LeftOrRightInv { LEFT_INV, RIGHT_INV };
21
36 template<LeftOrRightInv O=LEFT_INV,typename OtherDerived,typename OtherDerived_>
37 inline IntervalMatrix inverse_correction(const Eigen::MatrixBase<OtherDerived>& A, const Eigen::MatrixBase<OtherDerived_>& B)
38 {
39 assert_release(A.is_squared());
40 assert_release(B.is_squared());
41
42 auto A_ = A.template cast<Interval>();
43 auto B_ = B.template cast<Interval>();
44
45 Index N = A_.rows();
46 assert_release(N==B_.rows());
47
48 auto Id = IntervalMatrix::Identity(N,N);
49 auto erMat = [&]() { if constexpr(O == LEFT_INV) return -B_*A_+Id; else return -A_*B_+Id; }();
50
51 double mrad=0.0;
53 IntervalMatrix Ep = Id+erMat*(Id+E);
54 /* one could use several iterations here, either
55 using mrad, or directly */
56
57 auto res = (O == LEFT_INV) ? IntervalMatrix(Ep*B_) : IntervalMatrix(B_*Ep);
58
59 // We want the presence of non-invertible matrices to
60 // result in coefficients of the form [-oo,+oo].
61 if (mrad==oo) {
62 for (Index c=0;c<N;c++) {
63 for (Index r=0;r<N;r++) {
64 if (Ep(r,c).is_unbounded()) {
65 for (Index k=0;k<N;k++) {
66 if constexpr(O == LEFT_INV)
67 res(r,k) = Interval();
68 else
69 res(k,c) = Interval();
70 }
71 }
72 }
73 }
74 }
75 return res;
76 }
77
88 template<typename OtherDerived>
89 inline IntervalMatrix inverse_enclosure(const Eigen::MatrixBase<OtherDerived>& A)
90 {
91 assert_release(A.is_squared());
92 Index N = A.rows();
93
94 if constexpr(std::is_same_v<typename OtherDerived::Scalar,Interval>)
96 (A.mid()).fullPivLu().solve(Matrix::Identity(N,N)));
97
98 else
100 A.fullPivLu().solve(Matrix::Identity(N,N)));
101 }
102
119
120
128 template<typename OtherDerived>
129 inline std::pair<IntervalMatrix,Interval>
130 cofactor_matrix_enclosure(const Eigen::MatrixBase<OtherDerived>& A) {
131 assert_release(A.is_squared());
132
133 Index N = A.cols();
134 auto A_ = A.template cast<Interval>();
135
136 Eigen::FullPivLU<Matrix> lu(A_.mid());
137 /* FullPiv is used to get the ``best'' pivoting strategy */
138 auto P = lu.permutationP();
139 auto Q = lu.permutationQ();
140
141 IntervalMatrix pMq = P*A_*Q;
142 /* preconditioning ?
143 we use L and U to compute
144 L-1 pMq U-1
145 and include L-1 and U-1 in the computation of the cofactor matrix
146 */
147 Matrix mLU = lu.matrixLU();
148 for (int i=0;i<N;i++) {
149 if (std::fabs(mLU(i,i))<1e-5) { /* FIXME : value of "nonzero" ? */
150 mLU(i,i)=(mLU(i,i)<0.0 ? -1e-5 : 1e-5);
151 }
152 }
153 IntervalMatrix ImLU
154 = IntervalMatrix::Zero(N,N);
155 for (int c=0;c<N;c++) {
156 for (int r=c+1;r<N;r++) {
157 Interval s(mLU(r,c));
158 for (int k=c+1;k<r;k++) {
159 s += mLU(r,k)*ImLU(k,c);
160 }
161 ImLU(r,c)=-s;
162 }
163 }
164 for (int c=0;c<N;c++) {
165 int r;
166 ImLU(c,c)=Interval(1.0)/mLU(c,c);
167 r=c-1;
168 for (;r>=0;r--) {
169 Interval s(mLU(r,c));
170 s/=mLU(c,c);
171 for (int k=r+1;k<c;k++) {
172 s += mLU(r,k)*ImLU(k,c);
173 }
174 ImLU(r,c)=-s/mLU(r,r);
175 }
176 }
177 IntervalMatrix InvL =
178 IntervalMatrix::Identity(N,N);
179 InvL.triangularView<Eigen::StrictlyLower>() = ImLU;
180 IntervalMatrix InvU =
181 IntervalMatrix::Identity(N,N);
182 InvU.triangularView<Eigen::Upper>() = ImLU;
183 pMq = InvL * pMq * InvU;
184
185
186
187 IntervalMatrix Linv = IntervalMatrix::Identity(N,N);
188 IntervalMatrix Uinv = IntervalMatrix::Identity(N,N);
189 /* partial inversion of pMq is done, i.e.
190 we build a such that Linv * pMq * Uinv is equal
191 ( D 0 ) ( Id 0 )
192 ( 0 Id ) * ( 0 <eps ). The comatrix of the second part is :
193 is ( d 0 )
194 ( 0 w ) with d = (max nrm)^a (a = size of eps block)
195 w = (max nrm)^(a-1) */
196 Index c=0;
197 while (c<N-1) {
198 Interval pivot = pMq(c,c);
199 if (pivot.contains(0)) break; /* or if the mig is too low */
200 Linv.block(c+1,0,N-1-c,c+1) -=
201 pMq.block(c+1,c,N-1-c,1)*Linv.block(c,0,1,c+1)/pivot;
202 Uinv.block(0,c+1,c+1,N-1-c) -=
203 Uinv.block(0,c,c+1,1)*pMq.block(c,c+1,1,N-1-c)/pivot;
204 pMq.bottomRightCorner(N-1-c,N-1-c) -=
205 pMq.block(c+1,c,N-1-c,1)*pMq.block(c,c+1,1,N-1-c)/pivot;
206 pMq.block(c+1,c,N-1-c,1).fill(0.0);
207 pMq.block(c,c+1,1,N-1-c).fill(0.0);
208 c++;
209 }
210 Index lastcol=c;
211 Interval det=1.0;
212 /* build the comatrix for the diagonal part of pMq
213 (note: built in place) */
214 if (lastcol==N-1) lastcol=N; /* the inversion succeeded completely,
215 pMq is diagonal (but the last coef may contains 0) */
216 Index a = N-lastcol;
217 IntervalVector tmp = IntervalVector::Zero(lastcol);
218 tmp[0]=1.0;
219 for (Index c=0;c<lastcol-1;c++) {
220 tmp[c+1] = tmp[c]*pMq(c,c);
221 }
222 det = tmp[lastcol-1]*pMq(lastcol-1,lastcol-1);
223 for (Index c=lastcol-1;c>=1;c--) {
224 std::swap(tmp[c],pMq(c,c));
225 pMq(c,c)*=tmp[0];
226 tmp[0]*=tmp[c];
227 }
228 pMq(0,0)=tmp[0];
229 /* special case: a=2 */
230 if (a==2) {
231 Interval det2 = pMq(N-1,N-1)*pMq(N-2,N-2)-pMq(N-1,N-2)*pMq(N-2,N-1);
232 for (Index l=0;l<lastcol;l++) {
233 pMq(l,l)*=det2;
234 }
235 pMq.bottomRightCorner(2,2) *= det;
236 std::swap(pMq(N-1,N-1),pMq(N-2,N-2));
237 std::swap(pMq(N-1,N-2),pMq(N-2,N-1));
238 pMq(N-1,N-2)=-pMq(N-1,N-2);
239 pMq(N-2,N-1)=-pMq(N-2,N-1);
240 det *= det2;
241 } else if (a>2) {
242 /* build the cofactor matrix */
243 Interval eps=0.0;
244 for (Index c=lastcol;c<N;c++) {
245 Interval nrm = pMq.block(lastcol,c,a,1).norm();
246 if (nrm.ub()>eps.ub()) eps=nrm;
247 }
248 Interval v1 = pow(eps,(int)a)*Interval(-1.0,1.0);
249 Interval d1 = v1*eps;
250 for (Index l=0;l<lastcol;l++) {
251 pMq(l,l)*=d1;
252 }
253 pMq.bottomRightCorner(a,a).fill(v1*det);
254 det *= d1;
255 }
256 pMq = InvL.transpose()*Linv.transpose()*pMq*Uinv.transpose()*InvU.transpose();
257 return {
258 P.determinant()*Q.determinant()*
259 ((IntervalMatrix)(P.transpose())*pMq*(IntervalMatrix(Q.transpose()))),
260 P.determinant()*Q.determinant()*det
261 };
262 }
263
264}
Interval class, for representing closed and connected subsets of .
Definition codac2_Interval.h:50
double ub() const
Returns the upper bound of this.
Definition codac2_Interval_impl.h:131
bool contains(const double &x) const
Tests if this contains x.
Definition codac2_Interval_impl.h:226
bool is_unbounded() const
Checks if the interval matrix contains any unbounded intervals.
Definition codac2_MatrixBase_addons_IntervalMatrixBase.h:493
Definition codac2_OctaSym.h:21
std::pair< IntervalMatrix, Interval > cofactor_matrix_enclosure(const Eigen::MatrixBase< OtherDerived > &A)
compute the interval cofactor matrix, as well as the determinant, of a square matrix
Definition codac2_inversion.h:130
IntervalMatrix inverse_enclosure(const Eigen::MatrixBase< OtherDerived > &A)
Enclosure of the inverse of a (non-singular) matrix expression, possibly an interval matrix.
Definition codac2_inversion.h:89
IntervalMatrix inverse_correction(const Eigen::MatrixBase< OtherDerived > &A, const Eigen::MatrixBase< OtherDerived_ > &B)
Correct the approximation of the inverse of a square matrix by providing a reliable enclosure .
Definition codac2_inversion.h:37
Interval pow(const Interval &x, int n)
Returns , .
Definition codac2_Interval_operations_impl.h:33
Eigen::Matrix< Interval,-1, 1 > IntervalVector
Alias for a dynamic-size column vector of intervals.
Definition codac2_IntervalVector.h:25
IntervalMatrix infinite_sum_enclosure(const IntervalMatrix &A, double &mrad)
Compute an upper bound of , with a matrix of intervals as an "error term" (uses only bounds on coeff...
Eigen::Matrix< double,-1,-1 > Matrix
Alias for a dynamic-size matrix of doubles.
Definition codac2_Matrix.h:26
Eigen::Matrix< Interval,-1,-1 > IntervalMatrix
Alias for a dynamic-size matrix of intervals.
Definition codac2_IntervalMatrix.h:25