# Pinv not Type Stable?

**URL:** <https://discourse.julialang.org/t/pinv-not-type-stable/103885>\
**Category:** Performance\
**Tags:** question\
**Created:** [September 15, 2023, 9:45am UTC](https://discourse.julialang.org/t/pinv-not-type-stable/103885 "2023-09-15T09:45:10Z")\
**Posts on this page:** 1\
**Showing post:** 10

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [September 15, 2023, 1:02pm UTC](https://discourse.julialang.org/t/pinv-not-type-stable/103885/10 "2023-09-15T13:02:35Z")

</div>

`pinv` reassigns `tol` after it is captured by a closure, I think that’s the reason. Closures [often ruin inferrability](https://docs.julialang.org/en/v1/manual/performance-tips/#man-performance-captured) because it’s understandably hard to infer a variable shared by 2 separate functions that get compiled separately. I don’t know all the cases where it is inferred (guaranteed reassignment before closure instantiation) and where it is not (conditional reassignment before closure, any reassignment after the closure).

I `@eval`ed a `pinv2` into `LinearAlgebra` that replaced the closure with a function that doesn’t capture `tol`: `B[indB] .= ((x, toll) -> abs(x) > toll ? pinv(x) : zero(x)).(dA, tol)`. I haven’t compared the performance of these anonymous functions in isolation, so I don’t think it’s optimal. But the box vanished:

```julia
julia> @code_warntype LinearAlgebra.:(var"#pinv2#251")(0.0, (eps(real(float(1.1)))*min(3, 5))*iszero(0.0), LinearAlgebra.pinv2,rand(3, 5))
MethodInstance for LinearAlgebra.var"#pinv2#251"(::Float64, ::Float64, ::typeof(LinearAlgebra.pinv2), ::Matrix{Float64})
  from var"#pinv2#251"(atol::Real, rtol::Real, ::typeof(LinearAlgebra.pinv2), A::AbstractMatrix{T}) where T in LinearAlgebra at REPL[16]:1
...
Locals
...
  index::BitVector
...
  tol::Float64

```

EDIT: the least disruptive change to accomplish the same inferability would be to keep the closure, but alter the captured variable so it’s not reassigned afterward.

```julia
        tol_diag_branch = max(rtol * maxabsA, atol)
...
        B[indB] .= (x -> abs(x) > tol_diag_branch ? pinv(x) : zero(x)).(dA)
        # do not reassign tol_diag_branch, so parser lets compiler infer it

```

---

_[View the full topic](https://discourse.julialang.org/t/pinv-not-type-stable/103885)._
