Yichao,

That's great, thanks very much!  It's almost working now (revised code 
below).  I still have two issues, which are perhaps best answered by 
someone familiar with SPQR.  First, although the comments in the SPQR 
package say that E is  "column permutation", in fact I am getting back a 
vector containing many 1's  (and a few other integers in the range 2...n), 
so it is apparently not a permutation.  Anyone know what E is?  I couldn't 
find anything about E in the PDF manuals for SPQR.

Also, I don't know how to free the memory associated with E (a C array of 
integers).

-- Steve

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
    ptr_R = Ref{Ptr{C_Sparse{Float64}}}()
    ptr_E = Ref{Ptr{Clong}}()
    
    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)
    R = ptr_R[]
    E = ptr_E[]
    if E != C_NULL
        colprm = pointer_to_array(E, size(A,2), false) + 1
    else
        colprm = collect(1:size(A,2))
    end
    R1 = unsafe_load(R)
    if R1.stype != 0
        throw(ArgumentError("matrix has stype != 0. Convert to matrix with 
stype == 0 before converting to SparseMatrixCSC"))
    end
    
    R_cvt = SparseMatrixCSC(R1.nrow, 
                            R1.ncol, 
                            increment(pointer_to_array(R1.p, (R1.ncol + 
1,), false)), 
                            increment(pointer_to_array(R1.i, (R1.nzmax,), 
false)), 
                            copy(pointer_to_array(R1.x, (R1.nzmax,), 
false)))
    free_sparse!(R)
    R_cvt, colprm
end
    
On Thursday, August 4, 2016 at 11:00:55 PM UTC-4, Yichao Yu wrote:

>
>
> On Fri, Aug 5, 2016 at 10:47 AM, <[email protected] <javascript:>> 
> 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
>>
>>
>

Reply via email to