# Pure-Julia Sparse Cholesky

**URL:** <https://discourse.julialang.org/t/pure-julia-sparse-cholesky/131293>\
**Category:** Numerics\
**Created:** [August 1, 2025, 3:08pm UTC](https://discourse.julialang.org/t/pure-julia-sparse-cholesky/131293 "2025-08-01T15:08:18Z")\
**Posts on this page:** 12\
**Page:** 2

<div class="post-metadata">

**Author:** ![user664303](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/user664303/32/37843_2.png) [@user664303](https://discourse.julialang.org/u/user664303)\
**Post date:** [August 4, 2025, 6:48am UTC](https://discourse.julialang.org/t/pure-julia-sparse-cholesky/131293/21 "2025-08-04T06:48:41Z")

</div>

This sounds great. I’m currently using LDLFactorizations as the sparse solver in for large scale non-linear least squares optimization in my [NLLSsolver.jl](https://github.com/ojwoodford/NLLSsolver.jl) package. This sounds like it might be an improvement.

Is there a way to separate the symbolic phase of the decomposition from the numeric phase? LDLFactorizations provides the [ldl\_analyze](https://jso.dev/LDLFactorizations.jl/stable/reference/#LDLFactorizations.ldl_analyze) method to do this. This is useful in optimization where the structure of the sparse matrix doesn’t change across iterations, but the values do, allowing the symbolic phase to be done only once at the start. The documentation for your package suggests this isn’t currently possible.

---

<div class="post-metadata">

**Author:** ![samuelsonric](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/samuelsonric/32/216687_2.png) [@samuelsonric](https://discourse.julialang.org/u/samuelsonric)\
**Post date:** [August 4, 2025, 12:03pm UTC](https://discourse.julialang.org/t/pure-julia-sparse-cholesky/131293/22 "2025-08-04T12:03:46Z")

</div>

I need to update the docs. Make sure to update to the most recent version (`1.9.2`).

```julia-auto
symb = CliqueTrees.symbolic(matrix)
fact = CliqueTrees.cholesky(matrix, symb)

```

---

<div class="post-metadata">

**Author:** ![samuelsonric](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/samuelsonric/32/216687_2.png) [@samuelsonric](https://discourse.julialang.org/u/samuelsonric)\
**Post date:** [August 4, 2025, 2:15pm UTC](https://discourse.julialang.org/t/pure-julia-sparse-cholesky/131293/23 "2025-08-04T14:15:56Z")

</div>

Hi @user664303,

Perhaps this is not quite what you are looking for. `symbolic` performs the symbolic factorization, but it does not allocate memory for the numerical factorization, so each call to

```julia-auto
CliqueTrees.cholesky(matrix, symb)

```

will re-allocate. Do you want the memory to be allocated one time and then re-used?

---

<div class="post-metadata">

**Author:** ![RoyiAvital](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/royiavital/32/571_2.png) [@RoyiAvital](https://discourse.julialang.org/u/RoyiAvital)\
**Post date:** [August 4, 2025, 3:13pm UTC](https://discourse.julialang.org/t/pure-julia-sparse-cholesky/131293/24 "2025-08-04T15:13:33Z")

</div>

It would be great to have the concept of [`FastLapackInterface.jl`](https://github.com/DynareJulia/FastLapackInterface.jl) where there is a service function to pre allocate a workspace.  
Then it can be used by the functions if given (Not mandatory) to prevent allocations.

---

<div class="post-metadata">

**Author:** ![samuelsonric](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/samuelsonric/32/216687_2.png) [@samuelsonric](https://discourse.julialang.org/u/samuelsonric)\
**Post date:** [August 4, 2025, 3:32pm UTC](https://discourse.julialang.org/t/pure-julia-sparse-cholesky/131293/25 "2025-08-04T15:32:32Z")

</div>

That should be doable…

---

<div class="post-metadata">

**Author:** ![user664303](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/user664303/32/37843_2.png) [@user664303](https://discourse.julialang.org/u/user664303)\
**Post date:** [August 4, 2025, 10:11pm UTC](https://discourse.julialang.org/t/pure-julia-sparse-cholesky/131293/26 "2025-08-04T22:11:38Z")

</div>

> [@samuelsonric](#):
>
> Do you want the memory to be allocated one time and then re-used?

I’m not sure if ldl\_analyze does this. I’ll check. But yes, having the option to preallocate memory would be nice.

---

<div class="post-metadata">

**Author:** ![samuelsonric](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/samuelsonric/32/216687_2.png) [@samuelsonric](https://discourse.julialang.org/u/samuelsonric)\
**Post date:** [August 5, 2025, 1:52am UTC](https://discourse.julialang.org/t/pure-julia-sparse-cholesky/131293/27 "2025-08-05T01:52:15Z")

</div>

@user664303 @RoyiAvital How do you feel about this? You will have to `dev` CliqueTrees.jl to try it. The variable `cholwork` is a workspace.

```julia-repl
julia> using BenchmarkTools, CliqueTrees, MatrixMarket, SuiteSparseMatrixCollection

julia> ssmc = ssmc_db(); name = "nasasrb";

julia> matrix = mmread(joinpath(fetch_ssmc(ssmc[ssmc.name .== name, :]; format="MM")[1], "$(name).mtx"));

julia> symbfact = CliqueTrees.symbolic(matrix)
SymbFact{Int64}:
    nnz: 10692891

julia> cholfact, cholwork = CliqueTrees.cholinit(matrix, symbfact);

julia> @btime CliqueTrees.cholesky!(cholfact, cholwork, matrix);
  163.623 ms (0 allocations: 0 bytes)

```

versus LDLFactorizations.jl:

```julia-repl
julia> using LDLFactorizations

julia> ldlfact = LDLFactorizations.ldl_analyze(matrix);

julia> @btime LDLFactorizations.ldl_factorize!(matrix, ldlfact);
  1.367 s (0 allocations: 0 bytes)

```

---

<div class="post-metadata">

**Author:** ![user664303](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/user664303/32/37843_2.png) [@user664303](https://discourse.julialang.org/u/user664303)\
**Post date:** [August 6, 2025, 1:16pm UTC](https://discourse.julialang.org/t/pure-julia-sparse-cholesky/131293/28 "2025-08-06T13:16:09Z")

</div>

Looks great to me. Thank you! I’m in the process to putting a benchmark together to see how this performs on my class of problem.

---

<div class="post-metadata">

**Author:** ![user664303](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/user664303/32/37843_2.png) [@user664303](https://discourse.julialang.org/u/user664303)\
**Post date:** [August 6, 2025, 5:14pm UTC](https://discourse.julialang.org/t/pure-julia-sparse-cholesky/131293/29 "2025-08-06T17:14:45Z")

</div>

> [@samuelsonric](#):
>
> `CliqueTrees.cholesky!(cholfact, cholwork, matrix, symbfact)`

I think this should be:

`CliqueTrees.cholesky!(cholfact, cholwork, matrix)`

I’ve now tried it on my problems, but unfortunately my matrices are not guaranteed to be positive definite. That’s why I use LDLFactorizations.jl. Can your super-nodal approach also be applied to an LDL factorization, that will work on non-positive definite matrices?

---

<div class="post-metadata">

**Author:** ![RoyiAvital](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/royiavital/32/571_2.png) [@RoyiAvital](https://discourse.julialang.org/u/RoyiAvital)\
**Post date:** [August 6, 2025, 5:23pm UTC](https://discourse.julialang.org/t/pure-julia-sparse-cholesky/131293/30 "2025-08-06T17:23:12Z")

</div>

Can you also apply the option to serve pre allocated buffers to the symbolic stage.  
Preferably an option to apply the whole procedure without any allocations.

---

<div class="post-metadata">

**Author:** ![samuelsonric](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/samuelsonric/32/216687_2.png) [@samuelsonric](https://discourse.julialang.org/u/samuelsonric)\
**Post date:** [August 6, 2025, 5:51pm UTC](https://discourse.julialang.org/t/pure-julia-sparse-cholesky/131293/31 "2025-08-06T17:51:37Z")

</div>

Hi! Thank you for trying it out. I have been thinking about the indefinite case as well.

In principle, there is no problem. In practice, I need a fast way to compute an un-pivoted LDL factorization of a dense matrix. There does not seem to be a LAPACK routine for this?

I could also publish a pivoted LDL, which would be slower / more stable. A little trickier to implement.

---

<div class="post-metadata">

**Author:** ![user664303](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/user664303/32/37843_2.png) [@user664303](https://discourse.julialang.org/u/user664303)\
**Post date:** [August 6, 2025, 10:01pm UTC](https://discourse.julialang.org/t/pure-julia-sparse-cholesky/131293/32 "2025-08-06T22:01:33Z")

</div>

There seems to be a [C++ implementation of unpivoted LDL here](https://bootstrapcollaboration.gitlab.io/elemental-web/documentation/dev/lapack_like/factor/LDL/dense/unpivoted.html). Perhaps this could be translated into a pure Julia implementation.

Alternatively,

> [@LDLt factorization for full matrices](https://discourse.julialang.org/t/ldlt-factorization-for-full-matrices/75356/6):
>
> If you don’t care about stability\*, just run `lu` without pivoting and extract the diagonal `D` from the diagonal of `U`. If it’s symmetric (and no pivoting is used), then `U = DL'`.

[Previous page](https://discourse.julialang.org/t/pure-julia-sparse-cholesky/131293.md?page=1)
