1 | initial version |

The documentation of `random_matrix`

contains the information:

```
Random matrices with predictable echelon forms. The
"algorithm='echelonizable'" keyword, along with a requested rank
("rank") and optional size control ("upper_bound") will return a
random matrix in echelon form. When the base ring is "ZZ" or "QQ"
the result has integer entries, whose magnitudes can be limited by
the value of "upper_bound", and the echelon form of the matrix also
has integer entries. Other exact rings may be also specified, but
there is no notion of controlling the size. Square matrices of
full rank generated by this function always have determinant one,
and can be constructed with the "unimodular" keyword.
```

So the matrix `A`

constructed above is a matrix with entries in $\mathbb Z$ (and base ring $\mathbb Q$) and determinant
$$\det A = 1\ .$$
Since the inverse of $A$ is the "adjoint matrix", `A.adjoint()`

, we have the information that the entries of $A^{-1}$ are integers. This information is important in the context of the question, since we get first and approximative inverse, having entries very closed to some integers, then we round.

In an explicit example:

This time i have got:

```
sage: A = random_matrix(QQ, 6, algorithm='echelonizable', rank=6, upper_bound=9)
sage: A
[ 1 0 2 2 -2 5]
[-1 0 -2 -3 3 -5]
[-1 -1 0 -4 5 5]
[ 0 1 -1 4 -5 -5]
[ 0 0 2 6 -5 5]
[ 1 1 0 -1 -1 1]
```

As promised:

```
sage: A.inverse() == A.adjoint()
True
```

but we do not print either one... Instead, let us associate:

```
sage: B = A.change_ring(RDF)
sage: U, S, V = B.SVD()
```

The matrices $U,V$ are orthogonal, so the transposed are the inverses:

```
sage: (U*U.transpose()).round()
[ 1.0 -0.0 -0.0 0.0 0.0 -0.0]
[-0.0 1.0 0.0 -0.0 0.0 0.0]
[-0.0 0.0 1.0 0.0 -0.0 0.0]
[ 0.0 -0.0 0.0 1.0 -0.0 0.0]
[ 0.0 0.0 -0.0 -0.0 1.0 0.0]
[-0.0 0.0 0.0 0.0 0.0 1.0]
sage: (V*V.transpose()).round()
[ 1.0 -0.0 0.0 0.0 0.0 -0.0]
[-0.0 1.0 0.0 0.0 0.0 0.0]
[ 0.0 0.0 1.0 -0.0 -0.0 0.0]
[ 0.0 0.0 -0.0 1.0 -0.0 0.0]
[ 0.0 0.0 -0.0 -0.0 1.0 0.0]
[-0.0 0.0 0.0 0.0 0.0 1.0]
```

The matrix $S$ contains on the diagonal the singular values, we can check for instance:

```
sage: B.singular_values()
[13.351058796439338,
11.46537265710543,
2.4430917321568475,
1.1384557335300527,
0.1717356340018411,
0.013676651355763396]
sage: S.round()
[13.0 0.0 0.0 0.0 0.0 0.0]
[ 0.0 11.0 0.0 0.0 0.0 0.0]
[ 0.0 0.0 2.0 0.0 0.0 0.0]
[ 0.0 0.0 0.0 1.0 0.0 0.0]
[ 0.0 0.0 0.0 0.0 0.0 0.0]
[ 0.0 0.0 0.0 0.0 0.0 0.0]
```

(No space to show $S$ here...) Inverting $S$ is easy. So we build the inverse of $B=USV'$, which is $VS^{-1}U'$. The entries of this matrix are

sage: C = V*S.inverse()*U.transpose()
sage: C

```
[-28.000000000000274 -17.000000000000092 -7.0000000000001155 -12.000000000000169 5.000000000000092 5.000000000000067]
[ -18.0000000000002 -7.000000000000057 -6.000000000000087 -10.000000000000128 6.000000000000075 5.000000000000055]
[ 28.000000000000302 17.00000000000011 6.000000000000119 11.000000000000178 -5.000000000000096 -5.000000000000072]
[-26.000000000000284 -14.000000000000098 -7.000000000000118 -12.000000000000174 6.000000000000098 5.000000000000072]
[-25.000000000000263 -13.000000000000085 -7.000000000000111 -12.000000000000163 6.000000000000092 5.0000000000000675]
[ -5.000000000000057 -3.0000000000000213 -1.000000000000022 -2.0000000000000333 1.000000000000018 1.0000000000000135]
```

and we round:

```
sage: C.round()
[-28.0 -17.0 -7.0 -12.0 5.0 5.0]
[-18.0 -7.0 -6.0 -10.0 6.0 5.0]
[ 28.0 17.0 6.0 11.0 -5.0 -5.0]
[-26.0 -14.0 -7.0 -12.0 6.0 5.0]
[-25.0 -13.0 -7.0 -12.0 6.0 5.0]
[ -5.0 -3.0 -1.0 -2.0 1.0 1.0]
sage: C.round().change_ring(ZZ)
[-28 -17 -7 -12 5 5]
[-18 -7 -6 -10 6 5]
[ 28 17 6 11 -5 -5]
[-26 -14 -7 -12 6 5]
[-25 -13 -7 -12 6 5]
[ -5 -3 -1 -2 1 1]
sage: C.round().change_ring(ZZ) == A.inverse()
True
```

2 | No.2 Revision |

The documentation of `random_matrix`

contains the information:

```
Random matrices with predictable echelon forms. The
"algorithm='echelonizable'" keyword, along with a requested rank
("rank") and optional size control ("upper_bound") will return a
random matrix in echelon form. When the base ring is "ZZ" or "QQ"
the result has integer entries, whose magnitudes can be limited by
the value of "upper_bound", and the echelon form of the matrix also
has integer entries. Other exact rings may be also specified, but
there is no notion of controlling the size. Square matrices of
full rank generated by this function always have determinant one,
and can be constructed with the "unimodular" keyword.
```

So the matrix `A`

constructed above is a matrix with entries in $\mathbb Z$ (and base ring $\mathbb Q$) and determinant
$$\det A = 1\ .$$
Since the inverse of $A$ is the "adjoint matrix", `A.adjoint()`

, we have the information that the entries of $A^{-1}$ are integers. This information is important in the context of the question, since we get first and approximative inverse, having entries very closed to some integers, then we round.

In an explicit example:

This time i have got:

```
sage: A = random_matrix(QQ, 6, algorithm='echelonizable', rank=6, upper_bound=9)
sage: A
[ 1 0 2 2 -2 5]
[-1 0 -2 -3 3 -5]
[-1 -1 0 -4 5 5]
[ 0 1 -1 4 -5 -5]
[ 0 0 2 6 -5 5]
[ 1 1 0 -1 -1 1]
```

As promised:

```
sage: A.inverse() == A.adjoint()
True
```

but we do not print either one... Instead, let us associate:

```
sage: B = A.change_ring(RDF)
sage: U, S, V = B.SVD()
```

The matrices $U,V$ are orthogonal, so the transposed are the inverses:

```
sage: (U*U.transpose()).round()
[ 1.0 -0.0 -0.0 0.0 0.0 -0.0]
[-0.0 1.0 0.0 -0.0 0.0 0.0]
[-0.0 0.0 1.0 0.0 -0.0 0.0]
[ 0.0 -0.0 0.0 1.0 -0.0 0.0]
[ 0.0 0.0 -0.0 -0.0 1.0 0.0]
[-0.0 0.0 0.0 0.0 0.0 1.0]
sage: (V*V.transpose()).round()
[ 1.0 -0.0 0.0 0.0 0.0 -0.0]
[-0.0 1.0 0.0 0.0 0.0 0.0]
[ 0.0 0.0 1.0 -0.0 -0.0 0.0]
[ 0.0 0.0 -0.0 1.0 -0.0 0.0]
[ 0.0 0.0 -0.0 -0.0 1.0 0.0]
[-0.0 0.0 0.0 0.0 0.0 1.0]
```

The matrix $S$ contains on the diagonal the singular values, we can check for instance:

```
sage: B.singular_values()
[13.351058796439338,
11.46537265710543,
2.4430917321568475,
1.1384557335300527,
0.1717356340018411,
0.013676651355763396]
sage: S.round()
[13.0 0.0 0.0 0.0 0.0 0.0]
[ 0.0 11.0 0.0 0.0 0.0 0.0]
[ 0.0 0.0 2.0 0.0 0.0 0.0]
[ 0.0 0.0 0.0 1.0 0.0 0.0]
[ 0.0 0.0 0.0 0.0 0.0 0.0]
[ 0.0 0.0 0.0 0.0 0.0 0.0]
```

(No space to show $S$ here...) Inverting $S$ is easy. So we build the inverse of $B=USV'$, which is $VS^{-1}U'$. The entries of this matrix are

`sage: C = `~~V~~*S.inverse()*U.transpose()
sage: C ```
V*S.inverse()*U.transpose()
sage: C
[-28.000000000000274 -17.000000000000092 -7.0000000000001155 -12.000000000000169 5.000000000000092 5.000000000000067]
[ -18.0000000000002 -7.000000000000057 -6.000000000000087 -10.000000000000128 6.000000000000075 5.000000000000055]
[ 28.000000000000302 17.00000000000011 6.000000000000119 11.000000000000178 -5.000000000000096 -5.000000000000072]
[-26.000000000000284 -14.000000000000098 -7.000000000000118 -12.000000000000174 6.000000000000098 5.000000000000072]
[-25.000000000000263 -13.000000000000085 -7.000000000000111 -12.000000000000163 6.000000000000092 5.0000000000000675]
[ -5.000000000000057 -3.0000000000000213 -1.000000000000022 -2.0000000000000333 1.000000000000018 1.0000000000000135]
```

and we round:

```
sage: C.round()
[-28.0 -17.0 -7.0 -12.0 5.0 5.0]
[-18.0 -7.0 -6.0 -10.0 6.0 5.0]
[ 28.0 17.0 6.0 11.0 -5.0 -5.0]
[-26.0 -14.0 -7.0 -12.0 6.0 5.0]
[-25.0 -13.0 -7.0 -12.0 6.0 5.0]
[ -5.0 -3.0 -1.0 -2.0 1.0 1.0]
sage: C.round().change_ring(ZZ)
[-28 -17 -7 -12 5 5]
[-18 -7 -6 -10 6 5]
[ 28 17 6 11 -5 -5]
[-26 -14 -7 -12 6 5]
[-25 -13 -7 -12 6 5]
[ -5 -3 -1 -2 1 1]
sage: C.round().change_ring(ZZ) == A.inverse()
True
```

` `

` `

` `

` `

```
Copyright Sage, 2010. Some rights reserved under creative commons license. Content on this site is licensed under a Creative Commons Attribution Share Alike 3.0 license.
```