     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

    //! Functions for balancing a matrix.

    use alga::general::RealField;
    use std::ops::{DivAssign, MulAssign};

    use crate::allocator::Allocator;
    use crate::base::dimension::{Dim, U1};
    use crate::base::storage::Storage;
    use crate::base::{DefaultAllocator, MatrixN, VectorN};

    /// Applies in-place a modified Parlett and Reinsch matrix balancing with 2-norm to the matrix `m` and returns
    /// the corresponding diagonal transformation.
    ///
    /// See https://arxiv.org/pdf/1401.5766.pdf
    pub fn balance_parlett_reinsch<N: RealField, D: Dim>(m: &mut MatrixN<N, D>) -> VectorN<N, D>
    where DefaultAllocator: Allocator<N, D, D> + Allocator<N, D> {
        assert!(m.is_square(), "Unable to balance a non-square matrix.");

        let dim = m.data.shape().0;
        let radix: N = crate::convert(2.0f64);
        let mut d = VectorN::from_element_generic(dim, U1, N::one());

        let mut converged = false;

        while !converged {
            converged = true;

            for i in 0..dim.value() {
                let mut c = m.column(i).norm_squared();
                let mut r = m.row(i).norm_squared();
                let mut f = N::one();

                let s = c + r;
                c = c.sqrt();
                r = r.sqrt();

                if c.is_zero() || r.is_zero() {
                    continue;
                }

                while c < r / radix {
                    c *= radix;
                    r /= radix;
                    f *= radix;
                }

                while c >= r * radix {
                    c /= radix;
                    r *= radix;
                    f /= radix;
                }

                let eps: N = crate::convert(0.95);
                if c * c + r * r < eps * s {
                    converged = false;
                    d[i] *= f;
                    m.column_mut(i).mul_assign(f);
                    m.row_mut(i).div_assign(f);
                }
            }
        }

        d
    }

    /// Computes in-place `D * m * D.inverse()`, where `D` is the matrix with diagonal `d`.
    pub fn unbalance<N: RealField, D: Dim>(m: &mut MatrixN<N, D>, d: &VectorN<N, D>)
    where DefaultAllocator: Allocator<N, D, D> + Allocator<N, D> {
        assert!(m.is_square(), "Unable to unbalance a non-square matrix.");
        assert_eq!(m.nrows(), d.len(), "Unbalancing: mismatched dimensions.");

        for j in 0..d.len() {
            let mut col = m.column_mut(j);
            let denom = N::one() / d[j];

            for i in 0..d.len() {
                col[i] *= d[i] * denom;
            }
        }
    }

# Help

## Keyboard Shortcuts

`?`
  Show this help dialog
`S`
  Focus the search field
`↑`
  Move up in search results
`↓`
  Move down in search results
`↹`
  Switch tab
`⏎`
  Go to active search result
`+`
  Expand all sections
`-`
  Collapse all sections

## Search Tricks

Prefix searches with a type followed by a colon (e.g., `fn:`) to restrict the search to a given type.

Accepted types are: `fn`, `mod`, `struct`, `enum`, `trait`, `type`, `macro`, and `const`.

Search functions by type signature (e.g., `vec -> usize` or `* -> vec`)

Search multiple things at once by splitting your query with comma (e.g., `str,u8` or `String,struct:Vec,test`)