Dear Doug,

Thank you for taking the time to look at this. In actuality, the W matrix 
is a spatial weight matrix which defines who is a neighbor to whom. I think 
the "symmetric" verbiage in the code is not technically correct. The 
"standardized" means that  the rows of the W matrix sum to 1. This ensures 
that the (In -rho*W) matrix is positive definite as you state.

The following matrix would not technically be a proper spatial weight 
matrix because the 4th row has 1 neighbor and the 5th row has three 
neighbors when in fact they should all have 2 neighbors (actually there can 
be a different number of neighbors but I'm choosing 2 just for an 
illustration).

julia> full(W)
5x5 Array{Float64,2}:
 0.0  0.5  0.5  0.0  0.0
 0.5  0.0  0.0  0.0  0.5
 0.5  0.0  0.0  0.0  0.5
 0.0  0.0  0.0  0.0  0.5
 0.0  0.5  0.5  0.5  0.0

The original matrix I posted was a proper nearest neighbor spatial weight 
matrix:

>> full(W)

ans =

         0    0.5000    0.5000         0         0
    0.5000         0         0         0    0.5000
    0.5000         0         0         0    0.5000
         0    0.5000         0         0    0.5000
         0         0    0.5000    0.5000         0 

Each row represent a geographic entity and the columns represent their 
neighbors. The diagonal elements are zero because no geographic entity is a 
neighbor to itself. The 0.5's represent the row-normalization and in this 
case the value is .5 because there are 2 neighbors.

I guess the bottom line is that the code you provided works but I would 
need it to work for a non-symmetric W matrix.

Can the above code be altered to deal with the non-symmetric W case?

Thank you again for taking the time to look at this. I truly appreciate the 
help and education.

Regards,
Don


On Thursday, July 31, 2014 4:49:21 PM UTC-4, Douglas Bates wrote:
>
> Rats, I had a reply with code and examples then Google groups croaked and 
> when it reloaded my draft reply was gone.
>
> On Thursday, July 31, 2014 2:13:36 PM UTC-5, Donald Lacombe wrote:
>>
>> Dear Doug,
>>
>> I've created a small example to show what the MATLAB code is actually 
>> doing. Here is the output with some comments:
>>
>> % Create random coordinates
>> >> xc = randn(5,1);
>> >> yc = randn(5,1);
>>
>> % Create 2 nearest neighbor weight matrix
>> >> W = make_neighborsw(xc,yc,2);
>> >> W
>>
>> W =
>>
>>    (2,1)       0.5000
>>    (3,1)       0.5000
>>    (1,2)       0.5000
>>    (4,2)       0.5000
>>    (1,3)       0.5000
>>    (5,3)       0.5000
>>    (5,4)       0.5000
>>    (2,5)       0.5000
>>    (3,5)       0.5000
>>    (4,5)       0.5000
>>
>> % Full version
>> >> full(W)
>>
>> ans =
>>
>>          0    0.5000    0.5000         0         0
>>     0.5000         0         0         0    0.5000
>>     0.5000         0         0         0    0.5000
>>          0    0.5000         0         0    0.5000
>>          0         0    0.5000    0.5000         0
>>
>
> Notice that this matrix is not symmetric but the description of the 
> arguments for indetfull below says that W should be symmetric.  I am going 
> to assume that W should be symmetric and the allowable values of rho are 
> such that I - rho*W is positive-definite. I will use the matrix  
>
> julia> W = sparse([2,3,1,5,1,5,5,2,3,4],[1,1,2,2,3,3,4,5,5,5],0.5)
> 5x5 sparse matrix with 10 Float64 entries:
> [2, 1]  =  0.5
> [3, 1]  =  0.5
> [1, 2]  =  0.5
> [5, 2]  =  0.5
> [1, 3]  =  0.5
> [5, 3]  =  0.5
> [5, 4]  =  0.5
> [2, 5]  =  0.5
> [3, 5]  =  0.5
> [4, 5]  =  0.5
>
> julia> issym(W)
> true
>
> julia> full(W)
> 5x5 Array{Float64,2}:
>  0.0  0.5  0.5  0.0  0.0
>  0.5  0.0  0.0  0.0  0.5
>  0.5  0.0  0.0  0.0  0.5
>  0.0  0.0  0.0  0.0  0.5
>  0.0  0.5  0.5  0.5  0.0
>
>
> for illustration.
>
>
>> % Find colamd
>> >> z = speye(n) - 0.1*sparse(W)
>>
>> z =
>>
>>    (1,1)       1.0000
>>    (2,1)      -0.0500
>>    (3,1)      -0.0500
>>    (1,2)      -0.0500
>>    (2,2)       1.0000
>>    (4,2)      -0.0500
>>    (1,3)      -0.0500
>>    (3,3)       1.0000
>>    (5,3)      -0.0500
>>    (4,4)       1.0000
>>    (5,4)      -0.0500
>>    (2,5)      -0.0500
>>    (3,5)      -0.0500
>>    (4,5)      -0.0500
>>    (5,5)       1.0000
>>
>> % Full z
>> >> full(z)
>>
>> ans =
>>
>>     1.0000   -0.0500   -0.0500         0         0
>>    -0.0500    1.0000         0         0   -0.0500
>>    -0.0500         0    1.0000         0   -0.0500
>>          0   -0.0500         0    1.0000   -0.0500
>>          0         0   -0.0500   -0.0500    1.0000
>>
>> >> p = colamd(z)
>>
>> p =
>>
>>      4     3     1     2     5
>>
>> What I'm looking for is the "p" vector above. The full MATLAB code for 
>> the routine is as follows:
>>
>
> You don't need colamd for the calculations in indetfull.  Julia has a 
> logdet function with a method for the sparse Cholesky factorization so the 
> core calculation becomes
>
> julia> rho = 0.1
> 0.1
>
> julia> cf = cholfact(speye(W) - rho*W);
>
> julia> logdet(cf)
> -0.012566124059126464
>
> You don't need it but for interest, the 0-based permutation is stored as 
> the .Perm member of the cf object.  To make it 1-based we add 1 to it
>
> julia> show(cf.Perm .+ 1)
> [4,5,1,3,2]
>
> As with most sparse matrix operations the Cholesky factorization is done 
> as a symbolic phase followed by a numeric phase. If you are just modfiying 
> rho you don't need to do the symbolic phase over and over.  You can save 
> the factor from the first one and do the subsequent factorizations in place.
>
> function indetfull(W::SparseMatrixCSC,lmin,lmax)
>     issym(W) || error("Sparse matrix W must be symmetric")
>     rhos = lmin:0.01:lmax
>     I = speye(W)
>     cf = cholfact(I - lmin*W)
>     hcat(rhos, [logdet(cholfact!(cf,I-rho*W))::Float64 for rho in rhos])
> end
>
> (By the way, be careful not to use lmin = 0. or else change the code so 
> that cf is defined using lmax instead of lmin.  The pattern of I - 0.*W is 
> the pattern of the identity, after you have dropped the zero values, and is 
> different from the pattern of I - rho*W for non-zero rho. It is important 
> that the pattern be the same for all values of rho.)
>
> Here is an example of its use
>
> julia> indetfull(W,0.01,0.1)
> 10x2 Array{Float64,2}:
>  0.01  -0.000125007
>  0.02  -0.000500105
>  0.03  -0.00112553 
>  0.04  -0.00200168 
>  0.05  -0.00312911 
>  0.06  -0.00450853 
>  0.07  -0.00614082 
>  0.08  -0.00802701 
>  0.09  -0.0101683  
>  0.1   -0.0125661  
>
>
>
>
>
>> function out=lndetfull(W,lmin,lmax)
>> % PURPOSE: computes Pace and Barry's grid for log det(I-rho*W) using 
>> sparse matrices
>> % -----------------------------------------------------------------------
>> % USAGE: out = lndetfull(W,lmin,lmax)
>> % where:    
>> %             W     = symmetric spatial weight matrix (standardized)
>> %             lmin  = lower bound on rho
>> %             lmax  = upper bound on rho
>> % -----------------------------------------------------------------------
>> % RETURNS: out = a structure variable
>> %          out.lndet = a vector of log determinants for 0 < rho < 1
>> %          out.rho   = a vector of rho values associated with lndet values
>> % -----------------------------------------------------------------------
>> % NOTES: should use 1/lambda(max) to 1/lambda(min) for all possible rho 
>> values
>> % -----------------------------------------------------------------------
>> % References: % R. Kelley Pace and  Ronald Barry. 1997. ``Quick
>> % Computation of Spatial Autoregressive Estimators'', Geographical 
>> Analysis
>> % -----------------------------------------------------------------------
>>  
>> % written by:
>> % James P. LeSage, Dept of Economics
>> % University of Toledo
>> % 2801 W. Bancroft St,
>> % Toledo, OH 43606
>>
>>
>> rvec = lmin:.01:lmax;
>> spparms('tight'); 
>> [n junk] = size(W);
>> z = speye(n) - 0.1*sparse(W);
>> p = colamd(z);
>> niter = length(rvec);
>> dettmp = zeros(niter,2);
>> for i=1:niter;
>>     rho = rvec(i);
>>     z = speye(n) - rho*sparse(W);
>>     [l,u] = lu(z(:,p));
>>     dettmp(i,1) = rho;
>>     dettmp(i,2) = sum(log(abs(diag(u))));
>> end;
>>
>> out.lndet = dettmp(:,2);
>> out.rho = dettmp(:,1);
>>
>> The code will be very easy to convert once I figure out this one command,
>>
>> Thank you in advance for any help that you are able or willing to 
>> provide. I'm not an expert as sparse matrices but these routines come in 
>> very handy for these types of calculations.
>>
>> Thanks,
>> Don
>>
>>
>> On Thursday, July 31, 2014 10:42:55 AM UTC-4, Douglas Bates wrote:
>>>
>>> On Wednesday, July 30, 2014 8:10:37 PM UTC-5, Donald Lacombe wrote:
>>>>
>>>> Dear Julia Users:
>>>>
>>>> I am attempting to speed up some code regarding some Bayesian spatial 
>>>> econometric models and would like to translate some MATLAB code for 
>>>> computing the log determinant term in the log-likelihood function. 
>>>> Specifically, I'm interested in the Pace and Barry approximation to the 
>>>> log-determinant term as in R. Kelley Pace and Ronald Barry. (1997) "Quick 
>>>> Computation 
>>>> of Spatial Autoregressive Estimators''. The term in question is det(In - 
>>>> rho*W) which has to be calculated through each iteration of the 
>>>> Metropolis-Hastings algorithm I'm using.
>>>>
>>>> The MATLAB code for this has the command "colamd" which MATLAB's help 
>>>> defines as "P = colamd(S) returns the column approximate minimum 
>>>> degree permutation vector for the sparse matrix S".
>>>>
>>>
>>> colamd is indirectly available in the Cholmod module but I don't think 
>>> there is a direct way of calling it.  It is a method for determining a 
>>> fill-reducing permutation for a sparse, symmetric matrix of the form X'X 
>>> directly from X.  There are several other approaches implemented in amd, 
>>> Metis, Scotch, MUMPS, etc. for dealing with the symmetric matrix itself. 
>>>  All of these just use the pattern of nonzeros in the matrix as they are 
>>> part of the symbolic stage of the sparse Cholesky or sparse QR 
>>> factorization. 
>>>
>>> Can you be more specific about how it is to be used?   In particular, is 
>>> it important to work with the pattern of X rather than the pattern of X'X?
>>>
>>>
>>>> Is there an equivalent Julia command? I've tried looking at "symperm" 
>>>> but I do not think I am using it correctly and more importantly I have no 
>>>> real clue.
>>>>
>>>> Any help would be appreciated and if I successfully code this I would 
>>>> be happy to share with anyone who is interested.
>>>>
>>>> Thanks,
>>>> Don 
>>>>
>>>

Reply via email to