# Transfer a Sparse Matrix to a C Function

**URL:** <https://discourse.julialang.org/t/transfer-a-sparse-matrix-to-a-c-function/67883>\
**Category:** General Usage\
**Tags:** linearalgebra, sparse, c\
**Created:** [September 8, 2021, 6:04pm UTC](https://discourse.julialang.org/t/transfer-a-sparse-matrix-to-a-c-function/67883 "2021-09-08T18:04:15Z")\
**Posts on this page:** 14\
**Page:** 1

<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:** [September 8, 2021, 6:04pm UTC](https://discourse.julialang.org/t/transfer-a-sparse-matrix-to-a-c-function/67883/1 "2021-09-08T18:04:15Z")

</div>

I have a C function (See [`IncompleteCholeskyDecomposition.c`](https://github.com/RoyiAvital/IncompleteCholeskyDecomposition/blob/master/IncompleteCholeskyDecomposition.c)) which accepts a Sparse Matrix in CSC format (Actually 2 matrices).

I wonder, how do I extract the data, row index and column pointer from a given Julia Sparse Matrix?  
I want this to be efficient so I also wonder if I can allocate a matrix with no values, get the pointers and edit the values and indices.

Is there an example for that?

---

<div class="post-metadata">

**Author:** ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)\
**Post date:** [September 8, 2021, 6:15pm UTC](https://discourse.julialang.org/t/transfer-a-sparse-matrix-to-a-c-function/67883/2 "2021-09-08T18:15:41Z")

</div>

This is actually pretty easy because the data, row indices, and column pointers are already stored as plain arrays inside a Julia `SparseMatrixCSC`. You just need to convert them to the appropriate integer and floating-point types (if your `C` code uses something different) and subtract 1 from all the indices. The OSQP and SCS optimization wrappers do this internally:

[https://github.com/jump-dev/SCS.jl/blob/500e75d8f3a3467b8ae2814a49e41aa05c31439e/src/types.jl#L60-L62](https://github.com/jump-dev/SCS.jl/blob/500e75d8f3a3467b8ae2814a49e41aa05c31439e/src/types.jl#L60-L62)

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [September 8, 2021, 6:47pm UTC](https://discourse.julialang.org/t/transfer-a-sparse-matrix-to-a-c-function/67883/3 "2021-09-08T18:47:10Z")

</div>

Note that the manual is quite explicit and clear on this one (no need to dig into the implementation):

[https://docs.julialang.org/en/v1/stdlib/SparseArrays/#man-csc](https://docs.julialang.org/en/v1/stdlib/SparseArrays/#man-csc)

---

<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:** [September 8, 2021, 9:07pm UTC](https://discourse.julialang.org/t/transfer-a-sparse-matrix-to-a-c-function/67883/4 "2021-09-08T21:07:24Z")

</div>

Won’t those conversions make a copy?  
What I want is to access the values in `C` as they are and update them.  
I will handle the 1 vs. 0 in the `C` code.

It is assumed the Julia matrix is either `Float32` or `Float64`.

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [September 8, 2021, 9:25pm UTC](https://discourse.julialang.org/t/transfer-a-sparse-matrix-to-a-c-function/67883/5 "2021-09-08T21:25:51Z")

</div>

```julia
struct SparseMatrixCSC{Tv,Ti<:Integer} <: AbstractSparseMatrixCSC{Tv,Ti}
    m::Int # Number of rows
    n::Int # Number of columns
    colptr::Vector{Ti} # Column j is in colptr[j]:(colptr[j+1]-1)
    rowval::Vector{Ti} # Row indices of stored values
    nzval::Vector{Tv} # Stored values, typically nonzeros
end

```

m and n are the dimensions. Ti is an integer type to handle indexes, and Tv may be of any type, according to the type of data. The pointers of the vectors of this structure can be passed to a C routine without copying.

---

<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:** [September 8, 2021, 9:56pm UTC](https://discourse.julialang.org/t/transfer-a-sparse-matrix-to-a-c-function/67883/6 "2021-09-08T21:56:13Z")

</div>

I guess my question is exactly how to create this call with the pointers to those vectors.

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [September 8, 2021, 9:58pm UTC](https://discourse.julialang.org/t/transfer-a-sparse-matrix-to-a-c-function/67883/7 "2021-09-08T21:58:31Z")

</div>

They are just Julia arrays, and then you can use:

[https://docs.julialang.org/en/v1/manual/calling-c-and-fortran-code/](https://docs.julialang.org/en/v1/manual/calling-c-and-fortran-code/)

with a good understanding of C you probably will undertand that section relatively easy (which is not my case, by the way).

---

<div class="post-metadata">

**Author:** ![abulak](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/abulak/32/28314_2.png) [@abulak](https://discourse.julialang.org/u/abulak)\
**Post date:** [September 10, 2021, 9:48am UTC](https://discourse.julialang.org/t/transfer-a-sparse-matrix-to-a-c-function/67883/8 "2021-09-10T09:48:35Z")

</div>

Yes, they will make a copy, since the matrix is passed only once from julia → SCS and SCS wants 0-based indices;

If you want to handle it on your own just make sure the struct layout is compatible with what C library expects and pass it through Ref as @lmiq suggested

---

<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:** [September 10, 2021, 11:07am UTC](https://discourse.julialang.org/t/transfer-a-sparse-matrix-to-a-c-function/67883/9 "2021-09-10T11:07:36Z")

</div>

There are 2 optimizations I’m after:

1. How to send the `C` function a pointer to `colptr`, `rowval` and `nzval`.
2. How to make my whole Julia setup work with `32 Bit` indices for the sparse matrix (See [Convert a Current Installation of Julia to Use `BlasInt = `Int32`](https://discourse.julialang.org/t/convert-a-current-installation-of-julia-to-use-blasint-int32/67915)).

In (2) the problem I have is that most non trivial algorithms on Sparse Matrix (Decomposition) will gain from having indices in `32 Bit` yet I don’t know about the other eco system (`MKL Sparse`, `Suite Sparse`, etc…). If I set my matrix to be `32 Bit`, does it mean any call to a function of those libraries will create a conversion step?

I hope we have / we’ll have a way to configure all to be coherent. At the moment I don’t see a way to set `MKL`, `MKL Sparse`, `Pardiso` and other Intel based libraries to use `LP64` mode (Some has but it will go away with Julia 1.7). I have no idea about `SuiteSparse`. It seems some of the algorithms support `32 Bit` indices but it is not system wide.

---

<div class="post-metadata">

**Author:** ![abulak](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/abulak/32/28314_2.png) [@abulak](https://discourse.julialang.org/u/abulak)\
**Post date:** [September 10, 2021, 11:18am UTC](https://discourse.julialang.org/t/transfer-a-sparse-matrix-to-a-c-function/67883/10 "2021-09-10T11:18:44Z")

</div>

```julia
M = SparseMatrixCSC{Float64, Int32}(rand(4,3));
ccall(
    (:function_name, :libname),
    ReturnType, 
    (Clong, Clong, Ref{Cint}, Ref{Cint}, Ref{Cdouble}),
    M.m, # nrows
    M.n, # ncols
    M.colptr,
    M.rowval,
    M.nzval,
)

```

`Ref` here just indicates that memory is managed by julia;

We compile `SCS_GPU` with Int32s since that’s what’s supported/required by cudaBLAS. What doesn’t work (in julia) with `Int32` indices?

---

<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:** [September 11, 2021, 6:00pm UTC](https://discourse.julialang.org/t/transfer-a-sparse-matrix-to-a-c-function/67883/11 "2021-09-11T18:00:06Z")

</div>

> [@abulak](#):
>
> We compile `SCS_GPU` with Int32s since that’s what’s supported/required by cudaBLAS. What doesn’t work (in julia) with `Int32` indices?

Let’s say I build a sparse matrix with `Int32` indices. For example:

```julia
numRows = 10_000;
numNnz = 1_000;
mA = sparse(rand(Int32.(1:numRows), numNnz), rand(Int32.(1:numRows), numNnz), rand(numNnz), numRows, numRows);

```

Now, assume I use `MKLSparse` or any other `C` / `Fortran` library which has option to have indices wither as `Int32` or `Int64`. Currently, `Julia` use the interface which is defined by `BlasInt`. On 64 bit systems it is set to `Int64`.

So when I call: `mA * vA` where `vA` is a dense vector behind the scene Julia converts my sparse matrix to `Int64`. Not only the conversion takes time, the whole indexing arithmetic is now done with `Int64` which means performance is degraded.

Think of algorithms like Factorization / Decomposition which are huge on indices arithmetic. They get slower because of that.

I wish that with the all Trampoline overhaul in Julia `1.7.x` someone would also take care of this. There is no reason not to have access to both kind of implementations. For instance, on `MKL` it means to have both `LP64` and `ILP64` exposed and used according to the user defined matrix.

---

<div class="post-metadata">

**Author:** ![ericphanson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ericphanson/32/215186_2.png) [@ericphanson](https://discourse.julialang.org/u/ericphanson)\
**Post date:** [September 11, 2021, 6:12pm UTC](https://discourse.julialang.org/t/transfer-a-sparse-matrix-to-a-c-function/67883/12 "2021-09-11T18:12:18Z")

</div>

> [@RoyiAvital](#):
>
> I wish that with the all Trampoline overhaul in Julia `1.7.x` someone would also take care of this. There is no reason not to have access to both kind of implementations.

Did you see the JuliaCon talk? They cover exactly this: [https://youtu.be/t6hptekOR7s](https://youtu.be/t6hptekOR7s) (skip to minute 6 for a demo with 32-bit OpenBLAS and MKL).

---

<div class="post-metadata">

**Author:** ![abulak](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/abulak/32/28314_2.png) [@abulak](https://discourse.julialang.org/u/abulak)\
**Post date:** [September 11, 2021, 6:47pm UTC](https://discourse.julialang.org/t/transfer-a-sparse-matrix-to-a-c-function/67883/13 "2021-09-11T18:47:38Z")

</div>

I even remember watching the talk during juliacon, but somehow forgot that this part was featured there!

---

<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:** [September 11, 2021, 7:48pm UTC](https://discourse.julialang.org/t/transfer-a-sparse-matrix-to-a-c-function/67883/14 "2021-09-11T19:48:26Z")

</div>

Yes. I have watched it. Though what I’m talking is mainly for the Sparse Matrices.  
Namely, what I’m asking is if both paths exist at once and if Julia chose the `LP` path for Sparse Matrices built with `Int32`.

The code on `MKLSparse` currently use `BlasInt` to chose the code path. It doesn’t even look at the matrix itself.  
This is what I’m talking about (Though I’d say the 3-4 last comments should appear on [Convert a Current Installation of Julia to Use `BlasInt = `Int32`](https://discourse.julialang.org/t/convert-a-current-installation-of-julia-to-use-blasint-int32/67915)).

The solution has 2 stages:

1. Allow, at the same time, accessing BLAS / LAPCAK / Sparse BLAS / LAPACK libraries with `Int32` and `Int64` API.
2. For Sparse Matrices chose the path based on the type of the indices. Go for `LP64` for Sparse Matrices with `Int32` / `UInt32` indices. Use the `ILP64` path for matrices built with `Int64` / `UInt64`. One could even say that the path can have AUTO mode for matrices with less than `2 ^ 31 - 1` elements (Be Sparse or Dense).

It will bring performance and memory optimization for the eco system.
