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
126 template<typename OtherDerived>
127 inline std::pair<IntervalMatrix,Interval>
128 cofactor_matrix_enclosure(const Eigen::MatrixBase<OtherDerived>& A) {
129 assert_release(A.is_squared());
130
131 Index N = A.cols();
132 auto A_ = A.template cast<Interval>();
133
134 Eigen::FullPivLU<Matrix> lu(A_.mid());
135 /* FullPiv is used to get the ``best'' pivoting strategy */
136 auto P = lu.permutationP();
137 auto Q = lu.permutationQ();
138
139 IntervalMatrix pMq = P*A_*Q;
140 /* preconditioning ?
141 we use L and U to compute
142 L-1 pMq U-1
143 and include L-1 and U-1 in the computation of the cofactor matrix
144 */
145 Matrix mLU = lu.matrixLU();
146 double threshold=lu.maxPivot()*lu.threshold();
147 for (int i=0;i<N;i++) {
148 if (std::fabs(mLU(i,i))<threshold) {
149 mLU(i,i)=(mLU(i,i)<0.0 ? -threshold : threshold);
150 }
151 }
152 IntervalMatrix ImLU
153 = IntervalMatrix::Zero(N,N);
154 for (int c=0;c<N;c++) {
155 for (int r=c+1;r<N;r++) {
156 Interval s(mLU(r,c));
157 for (int k=c+1;k<r;k++) {
158 s += mLU(r,k)*ImLU(k,c);
159 }
160 ImLU(r,c)=-s;
161 }
162 }
163 for (int c=0;c<N;c++) {
164 int r;
165 ImLU(c,c)=Interval(1.0)/mLU(c,c);
166 r=c-1;
167 for (;r>=0;r--) {
168 Interval s(mLU(r,c));
169 s/=mLU(c,c);
170 for (int k=r+1;k<c;k++) {
171 s += mLU(r,k)*ImLU(k,c);
172 }
173 ImLU(r,c)=-s/mLU(r,r);
174 }
175 }
176 IntervalMatrix InvL =
177 IntervalMatrix::Identity(N,N);
178 InvL.triangularView<Eigen::StrictlyLower>() = ImLU;
179 IntervalMatrix InvU =
180 IntervalMatrix::Identity(N,N);
181 InvU.triangularView<Eigen::Upper>() = ImLU;
182 pMq = InvL * pMq * InvU;
183
184
185
186 IntervalMatrix Linv = IntervalMatrix::Identity(N,N);
187 IntervalMatrix Uinv = IntervalMatrix::Identity(N,N);
188 /* partial inversion of pMq is done, i.e.
189 we build a such that Linv * pMq * Uinv is equal
190 ( D 0 ) ( Id 0 )
191 ( 0 Id ) * ( 0 <eps ). The comatrix of the second part is :
192 is ( d 0 )
193 ( 0 w ) with d = (max nrm)^a (a = size of eps block)
194 w = (max nrm)^(a-1) */
195 Index c=0;
196 while (c<N-1) {
197 Interval pivot = pMq(c,c);
198 if (pivot.contains(0)) break; /* or if the mig is too low */
199 Linv.block(c+1,0,N-1-c,c+1) -=
200 pMq.block(c+1,c,N-1-c,1)*Linv.block(c,0,1,c+1)/pivot;
201 Uinv.block(0,c+1,c+1,N-1-c) -=
202 Uinv.block(0,c,c+1,1)*pMq.block(c,c+1,1,N-1-c)/pivot;
203 pMq.bottomRightCorner(N-1-c,N-1-c) -=
204 pMq.block(c+1,c,N-1-c,1)*pMq.block(c,c+1,1,N-1-c)/pivot;
205 pMq.block(c+1,c,N-1-c,1).fill(0.0);
206 pMq.block(c,c+1,1,N-1-c).fill(0.0);
207 c++;
208 }
209 Index lastcol=c;
210 Interval det=1.0;
211 /* build the comatrix for the diagonal part of pMq
212 (note: built in place) */
213 if (lastcol==N-1) lastcol=N; /* the inversion succeeded completely,
214 pMq is diagonal (but the last coef may contains 0) */
215 Index a = N-lastcol;
216 IntervalVector tmp = IntervalVector::Zero(lastcol);
217 tmp[0]=1.0;
218 for (Index c=0;c<lastcol-1;c++) {
219 tmp[c+1] = tmp[c]*pMq(c,c);
220 }
221 det = tmp[lastcol-1]*pMq(lastcol-1,lastcol-1);
222 for (Index c=lastcol-1;c>=1;c--) {
223 std::swap(tmp[c],pMq(c,c));
224 pMq(c,c)*=tmp[0];
225 tmp[0]*=tmp[c];
226 }
227 pMq(0,0)=tmp[0];
228 /* special case: a=2 */
229 if (a==2) {
230 Interval det2 = pMq(N-1,N-1)*pMq(N-2,N-2)-pMq(N-1,N-2)*pMq(N-2,N-1);
231 for (Index l=0;l<lastcol;l++) {
232 pMq(l,l)*=det2;
233 }
234 pMq.bottomRightCorner(2,2) *= det;
235 std::swap(pMq(N-1,N-1),pMq(N-2,N-2));
236 std::swap(pMq(N-1,N-2),pMq(N-2,N-1));
237 pMq(N-1,N-2)=-pMq(N-1,N-2);
238 pMq(N-2,N-1)=-pMq(N-2,N-1);
239 det *= det2;
240 } else if (a>2) {
241 /* build the cofactor matrix */
242 Interval eps=0.0;
243 for (Index c=lastcol;c<N;c++) {
244 Interval nrm = pMq.block(lastcol,c,a,1).norm();
245 if (nrm.ub()>eps.ub()) eps=nrm;
246 }
247 Interval v1 = pow(eps,(int)a)*Interval(-1.0,1.0);
248 Interval d1 = v1*eps;
249 for (Index l=0;l<lastcol;l++) {
250 pMq(l,l)*=d1;
251 }
252 pMq.bottomRightCorner(a,a).fill(v1*det);
253 det *= d1;
254 }
255 pMq = InvL.transpose()*Linv.transpose()*pMq*Uinv.transpose()*InvU.transpose();
256 return {
257 P.determinant()*Q.determinant()*
258 ((IntervalMatrix)(P.transpose())*pMq*(IntervalMatrix(Q.transpose()))),
259 P.determinant()*Q.determinant()*det
260 };
261 }
262
263}
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:128
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