On Fri, Aug 5, 2016 at 10:47 AM, <vava...@uwaterloo.ca> wrote: > In an earlier post, I asked how to use spqr (C language subroutines that > are part of the Julia base) to obtain the R factor of a sparse QR > factorization. Based on the lack of response, I assume that this has not > been tried before. So now I'm requesting help on how to use ccall, which I > have not used previously. The C-routine that I think I need is below (in > the Julia comments). This C function, as far as I understand, returns its > outputs via pointers-to-pointers. In particular, the caller is supposed to > pass in a location in which a pointer to the answer is to be stored, or > else 0 if the caller discards that output. > > My wrapper function below did not work. The C-function appears to have > run, because rk has the correct value. But the values printed for nrow, > ncol, nzmax are garbage, i.e., the code does not correctly retrieve R. > Furthermore, the call to finalizer gave an error message ("Objects of type > Ptr{...} cannot be finalized"). I cribbed the finalizer invocations from > spqr.jl but evidently not correctly. >
It's really unclear from your code below what you are trying to do. (maybe someone with more experience with suitsparse would). You'll be better off trying ccall on a few simple functions. >From your description above, I'm guessing you have a c function that looks like ``` void f(void **p) { *p = new object; } ``` The way to call this is ``` pp = Ref{Ptr{Void}}() ccall(:f, Void, (Ptr{Ptr{Void}},), pp) p = pp[] ``` You can't add finalizer to a bare pointer. There are mutiple ways to manage memory returned by C functions. 1. If the pointer is pointing to a buffer of known size and can be free with `free`, use `unsafe_wrap(Array)` to get an array 2. If the pointer is merely used to return a small amount of information, you can eagerly convert that info to a julia object 3. If the pointer is an opaque object or if you need exactly the same pointer later for interacting with the C library, put the pointer in a mutable type. Define `unsafe_convert` and `cconvert` on that type to convert the julia object to pointer argument and add finalizer on the julia object that frees the pointer. > -- Steve Vavasis > > > > module test_qr_fac > > > import Base.SparseMatrix.CHOLMOD.common > import Base.SparseMatrix.CHOLMOD.C_Sparse > import Base.SparseMatrix.CHOLMOD.Sparse > import Base.SparseMatrix.CHOLMOD.free! > > > #SuiteSparse_long SuiteSparseQR_C /* returns rank(A) estimate, (-1) if > failure */ > #( > # /* inputs: */ > # int ordering, /* all, except 3:given treated as 0:fixed > */ > # double tol, /* columns with 2-norm <= tol treated as > 0 */ > # SuiteSparse_long econ, /* e = max(min(m,econ),rank(A)) */ > # int getCTX, /* 0: Z=C (e-by-k), 1: Z=C', 2: Z=X > (e-by-k) */ > # cholmod_sparse *A, /* m-by-n sparse matrix to factorize */ > # cholmod_sparse *Bsparse, /* sparse m-by-k B */ > # cholmod_dense *Bdense, /* dense m-by-k B */ > # /* outputs: */ > # cholmod_sparse **Zsparse, /* sparse Z */ > # cholmod_dense **Zdense, /* dense Z */ > # cholmod_sparse **R, /* e-by-n sparse matrix */ > # SuiteSparse_long **E, /* size n column perm, NULL if identity */ > # cholmod_sparse **H, /* m-by-nh Householder vectors */ > # SuiteSparse_long **HPinv, /* size m row permutation */ > # cholmod_dense **HTau, /* 1-by-nh Householder coefficients */ > # cholmod_common *cc /* workspace and parameters */ > #) ; > > function qr_fac_get_r(A, tol, ordering = Base.SparseMatrix.SPQR. > ORDERING_DEFAULT) > Aw = Sparse(A,0) > s = unsafe_load(Aw.p) > if s.stype != 0 > throw(ArgumentError("stype must be zero")) > end > R = Ptr{C_Sparse{Float64}}(C_NULL) > ptr_R = Ptr{Void}(R) > E = Ptr{Clong}(C_NULL) > ptr_E = Ptr{Void}(E) > > rk = ccall((:SuiteSparseQR_C, :libspqr), Clong, > (Cint, #ordering > Cdouble, #tol > Clong, #econ > Cint, #getCTX > Ptr{C_Sparse{Float64}}, # A > Ptr{Void}, #Bsparse > Ptr{Void}, #Bdense > Ptr{Void}, #Zsparse > Ptr{Void}, #Zdense > Ptr{Void}, #R > Ptr{Void}, #E > Ptr{Void}, #H > Ptr{Void}, #HPInv > Ptr{Void}, #HTau > Ptr{Void}), #cc > ordering, #ordering > tol, #tol > 1000000000, #econ > 0, #getCTX > get(Aw.p), # A > C_NULL, #Bsparse > C_NULL, #Bdense > C_NULL, #Zsparse > C_NULL, #Zdense > ptr_R, #R > ptr_E, #E > C_NULL, #H > C_NULL, #HPInv > C_NULL, #HTau > common()) #cc > println("rk = ", rk) > R1 = unsafe_load(R) > println("nrow = ", R1.nrow, " ncol = ", R1.ncol, " nzmax = ", R1.nzmax) > finalizer(R, free!) > finalizer(E, free!) > nothing > end > > > end > >