spam/0000755000176200001440000000000013574471023011220 5ustar liggesusersspam/NAMESPACE0000644000176200001440000001370213536375066012452 0ustar liggesusersuseDynLib(spam, .registration = TRUE) import(grid) import("dotCall64") importFrom("grDevices", "gray", "heat.colors") importFrom("graphics", "axis", "box", "image.default", "par", "points", "polygon", "text") importFrom("methods", "callGeneric", "is", "new", "slot<-", "validObject") importFrom("stats", "optim", "rnorm", "runif", "rbinom", "var") importFrom("utils", "help") # Next two paragraphs are from Matrix.... # Currently, group generics need to be explicitly imported (Bug?): importFrom("methods", #Arith,Compare, Math, Math2, Summary#, Complex ) S3method("all.equal","spam") #S3method("as.matrix.csr","spam") S3method("as.matrix","spam") S3method("as.vector","spam") S3method("determinant","spam") S3method("determinant","spam.chol.NgPeyton") S3method("chol","spam") S3method("diff","spam") S3method("dim<-","spam") S3method("head","spam") S3method("image","spam") S3method("isSymmetric","spam") S3method("plot","spam") S3method("print","spam") S3method("print","spam.chol.NgPeyton") S3method("solve","spam") #S3method("subset_rows","spam") S3method("subset","spam") S3method("summary","spam") S3method("summary","spam.chol.NgPeyton") S3method("print","summary.spam") S3method("print","summary.spam.chol.NgPeyton") S3method("t","spam") S3method("tail","spam") S3method("update","spam.chol.NgPeyton") S3method("cbind","spam") S3method("rbind","spam") # Generic functions export( "spam_random", "validspamobject", # __DEFUNCT__ "is.spam", "spam.version", "spam.Version", "validate_spam", "nearest.dist", "spam_rdist", "spam_rdist.earth", "as.spam.matrix", "as.spam.numeric", "as.spam.spam", "as.spam.dist", "as.spam.chol.NgPeyton", "as.spam.list", "as.vector.spam", "as.matrix.spam", "spam.list", "spam.numeric", "diag.of.spam", "diag.spam", "spam_diag", "diag<-.spam", "diag.spam<-", "rbind.spam", "cbind.spam", "upper.tri.spam", "lower.tri.spam", "t.spam", "dim<-.spam", "pad<-.spam", "isSymmetric.spam", "all.equal.spam", "kronecker.default", "kronecker.spam", "diff.spam", "circulant.spam", "toeplitz.spam", "determinant.spam", "determinant.spam.chol.NgPeyton", "det",# << "identical" as base - but with correct determinant() "chol.spam", "solve.spam", "forwardsolve.spam", "backsolve.spam", "update.spam.chol.NgPeyton", "norm.spam", "plot.spam", "display.spam", "image.spam", "print.spam", "summary.spam", "print.spam.chol.NgPeyton", "summary.spam.chol.NgPeyton", "apply.spam", "rmvnorm.spam", "rmvnorm.canonical", "rmvnorm.prec", "rmvnorm.const", "rmvnorm.canonical.const", "rmvnorm.prec.const", "precmat", "precmat.RW1", "precmat.RW2", "precmat.RWn", "precmat.season", "precmat.IGMRFreglat", "precmat.IGMRFirreglat", "precmat.GMRFreglat", "covmat", "cov.exp", "cov.sph", "cov.nug", "cov.wu1", "cov.wu2", "cov.wu3", "cov.wend1", "cov.wend2", "cov.mat", "rowSums.spam", "colSums.spam", "rowMeans.spam", "colMeans.spam", "head.spam", "tail.spam", "chol2inv.spam", "mle.spam", "mle.nomean.spam", "neg2loglikelihood.spam", "mle", "mle.nomean", "neg2loglikelihood", "bdiag.spam", "var.spam", "eigen.spam", "eigen_approx", "bandwidth", # ".spam.matmul.mat", # ".spam.matmul", # "solve.spam.mat", # "solve.spam.dummy", "subset.spam", # "subset_rows.spam", "triplet", "as.spam.matrix.csr", # "as.matrix.csr.spam", "as.dgRMatrix.spam", "as.dgCMatrix.spam", "as.spam.dgRMatrix", "as.spam.dgCMatrix", "read.MM", "read.HB", "powerboost", "permutation.spam", "crossprod.spam", "tcrossprod.spam", "map.landkreis", "adjacency.landkreis", "germany.plot", # "germany.info", "grid_trace2", "grid_zoom", "rowpointers<-", "entries<-", "colindices<-", "dimension<-", "cleanup" # "backsolve" ) # export the two classes exportClasses("spam", "spam.chol.NgPeyton") exportMethods( "Math", "Math2", "Summary", # "show", "print", "image", "display", "spam", "as.spam", "isSymmetric", "all.equal", "summary", "length", "length<-", "c", "dim", "dim<-", "pad<-", "rbind", "cbind", "as.spam", "spam", "as.vector", "as.matrix", "determinant", "t", "diag", "diag<-", "upper.tri", "lower.tri", "norm", "rowSums", "rowMeans", "colSums", "colMeans", "head", "tail", "chol", "ordering", "forwardsolve", "backsolve", "solve", "chol2inv", "kronecker", "permutation", "crossprod", "tcrossprod", "[", "[<-", "%*%", "%d*%", "%d+%", "-", "+", "*", "/", "&", "|" ) spam/demo/0000755000176200001440000000000013440250504012133 5ustar liggesusersspam/demo/spam.R0000644000176200001440000000210713440250504013216 0ustar liggesusers# This is file ../spam/demo/spam.R # This file is part of the spam package, # http://www.math.uzh.ch/furrer/software/spam/ # by Reinhard Furrer [aut, cre], Florian Gerber [ctb] # This is a simple demo, wrapping up the functionality of spam. set.seed(14) nrow <- 5 ncol <- 7 fmat <- matrix(rnorm(nrow*ncol),nrow) smat <- as.spam(fmat) smat[1,] smat[,1] <- 0 as.spam(smat) ssmat <- smat %*% t(smat) b <- c(-2:2) solve(ssmat,b) cholssmat <- chol(ssmat) # works also for large matrices: set.seed(14) nz <- 1000 nrow <- 1000 ncol <- 1000 smat <- diag.spam(1,nrow,ncol) smat[cbind(sample(1:(nrow*ncol),size=nz))] <- runif(nz) smat <- smat %*% t(smat) b <- rnorm(nz) smatinvb <- solve(smat,b) cholssmat <- chol(smat) # displaying matrices opar <- par(no.readonly = TRUE) par(ask=interactive() && (.Device %in% c("X11","GTK","gnome","windows","quartz"))) display(smat, main="'scatterplot'-type display, very efficient") options(spam.imagesize=prod(smat@dimension)+1) display(smat, main="'image'-type display, may be slow and heavy") par(opar) spam/demo/cholesky.R0000644000176200001440000001017613440250504014104 0ustar liggesusers# This is file ../spam/demo/cholesky.R # This file is part of the spam package, # http://www.math.uzh.ch/furrer/software/spam/ # by Reinhard Furrer [aut, cre], Florian Gerber [ctb] # We illustrate the Cholesky decompostion approaches set.seed(14) # first start with a full matrix. xn <- 750 fmat1 <- matrix(rnorm(xn*xn),xn,xn) fmat1 <- t( fmat1) %*% fmat1 smat1 <- as.spam(fmat1) smat2 <- smat1 + diag.spam(xn) # Generic Cholesky tmp <- gc(F);Rprof(memory.profiling=TRUE, interval = 0.01) ch1 <- chol( fmat1) Rprof(NULL);print( summaryRprof(memory="both")$by.total) # Sparse Cholesky tmp <- gc(F);Rprof(memory.profiling=TRUE, interval = 0.01) ch1 <- chol( smat1) Rprof(NULL);print( summaryRprof(memory="both")$by.total) # Sparse Cholesky, direct call tmp <- gc(F);Rprof(memory.profiling=TRUE, interval = 0.01) ch1 <- chol.spam( smat1) Rprof(NULL);print( summaryRprof(memory="both")$by.total) # Sparse Cholesky, without symmetry check options(spam.cholsymmetrycheck=FALSE) tmp <- gc(F);Rprof(memory.profiling=TRUE, interval = 0.01) ch1 <- chol.spam( smat1) Rprof(NULL);print( summaryRprof(memory="both")$by.total) # Sparse Cholesky, reusing pivoting tmp <- gc(F);Rprof(memory.profiling=TRUE, interval = 0.01) ch1 <- chol.spam( smat1,pivot=ch1@pivot) Rprof(NULL);print( summaryRprof(memory="both")$by.total) # Sparse Cholesky, updating tmp <- gc(F);Rprof(memory.profiling=TRUE, interval = 0.01) ch1 <- update.spam.chol.NgPeyton( ch1, smat2) Rprof(NULL);print( summaryRprof(memory="both")$by.total) # reset to default options(spam.cholsymmetrycheck=TRUE) # now create a sparse matrix. fmat1[fmat1<3] <- 0 smat1 <- as.spam(fmat1) smat2 <- smat1 + diag.spam(xn) # Generic Cholesky tmp <- gc(F);Rprof(memory.profiling=TRUE, interval = 0.01) ch1 <- chol( fmat1) Rprof(NULL);print( summaryRprof(memory="both")$by.total) # Sparse Cholesky tmp <- gc(F);Rprof(memory.profiling=TRUE, interval = 0.01) ch1 <- chol( smat1) Rprof(NULL);print( summaryRprof(memory="both")$by.total) # Sparse Cholesky, direct call tmp <- gc(F);Rprof(memory.profiling=TRUE, interval = 0.01) ch1 <- chol.spam( smat1) Rprof(NULL);print( summaryRprof(memory="both")$by.total) # Sparse Cholesky, without symmetry check options(spam.cholsymmetrycheck=FALSE) tmp <- gc(F);Rprof(memory.profiling=TRUE, interval = 0.01) ch1 <- chol.spam( smat1) Rprof(NULL);print( summaryRprof(memory="both")$by.total) # Sparse Cholesky, reusing pivoting tmp <- gc(F);Rprof(memory.profiling=TRUE, interval = 0.01) ch1 <- chol.spam( smat1,pivot=ch1@pivot) Rprof(NULL);print( summaryRprof(memory="both")$by.total) # Sparse Cholesky, updating tmp <- gc(F);Rprof(memory.profiling=TRUE, interval = 0.01) ch1 <- update.spam.chol.NgPeyton( ch1, smat2) Rprof(NULL);print( summaryRprof(memory="both")$by.total) # reset to default options(spam.cholsymmetrycheck=TRUE) # now create an even sparser matrix. fmat1 <- fmat1+20*diag(xn) fmat1[fmat1<32] <- 0 smat1 <- as.spam(fmat1) smat2 <- smat1 + 1* diag.spam(xn) # Generic Cholesky tmp <- gc(F);Rprof(memory.profiling=TRUE, interval = 0.01) ch1 <- chol( fmat1) Rprof(NULL);print( summaryRprof(memory="both")$by.total) # Sparse Cholesky tmp <- gc(F);Rprof(memory.profiling=TRUE, interval = 0.01) ch1 <- chol( smat1) Rprof(NULL);print( summaryRprof(memory="both")$by.total) # Sparse Cholesky, direct call tmp <- gc(F);Rprof(memory.profiling=TRUE, interval = 0.01) ch1 <- chol.spam( smat1) Rprof(NULL);print( summaryRprof(memory="both")$by.total) # Sparse Cholesky, without symmetry check options(spam.cholsymmetrycheck=FALSE) tmp <- gc(F);Rprof(memory.profiling=TRUE, interval = 0.01) ch1 <- chol.spam( smat1) Rprof(NULL);print( summaryRprof(memory="both")$by.total) # Sparse Cholesky, reusing pivoting options(spam.cholsymmetrycheck=FALSE) tmp <- gc(F);Rprof(memory.profiling=TRUE, interval = 0.01) ch1 <- chol.spam( smat1,pivot=ch1@pivot) Rprof(NULL);print( summaryRprof(memory="both")$by.total) # Sparse Cholesky, updating options(spam.cholsymmetrycheck=FALSE) tmp <- gc(F);Rprof(memory.profiling=TRUE, interval = 0.01) ch1 <- update.spam.chol.NgPeyton( ch1, smat2) Rprof(NULL);print( summaryRprof(memory="both")$by.total) # reset to default options(spam.cholsymmetrycheck=TRUE) spam/demo/jss15-BYM.R0000644000176200001440000001242313440250504013652 0ustar liggesusers# This is file ../spam/demo/jss15-BYM.R # This file is part of the spam package, # http://www.math.uzh.ch/furrer/software/spam/ # by Reinhard Furrer [aut, cre], Florian Gerber [ctb] # This is the MCMC sampler presented in Section 2.2 of the article: # # Florian Gerber, Reinhard Furrer (2015). Pitfalls in the Implementation # of Bayesian Hierarchical Modeling of Areal Count Data: An Illustration # Using BYM and Leroux Models. Journal of Statistical Software, # Code Snippets, 63(1), 1-32. URL http://www.jstatsoft.org/v63/c01/. # # Note: For illustration we set # number of generated samples: 5'000 # number of burnin samples: 500 # thinning: 10 # This takes 1-2 minutes of computation time. # # In the JSS article we used: # number of generated samples: 300'000 # number of burnin samples: 15'000 # thinning: 20 invisible(readline(prompt = "Type \t to continue : ")) # SETUP: library("spam") options(spam.structurebased=TRUE) # Besag-York-Molie model (BYM) # load data data(Oral); attach(Oral) path <- system.file("demodata/germany.adjacency", package = "spam") A <- adjacency.landkreis(path); n <- dim(A)[1] set.seed(2) # hyper priors hyperA <- c(1, 1); hyperB <- c(0.5, .01) # sampler length, burnin and thinning totalg <- 5000 burnin <- 500 thin <- 10 # variable to store samples upost <- vpost <- array(0, c(totalg, n)) kpost <- array(NA, c(totalg, 2)); accept <- rep(NA, totalg) # initial values upost[1,] <- vpost[1,] <- rep(.001, 544); kpost[1,] <- c(10, 100) # precalculate some quantities eta <- upost[1,] + vpost[1,] C <- exp(eta) * E; diagC <- diag.spam(c(rep(0, n), C)) b <- c( rep(0, n), Y + (eta - 1) * C) Qu <- R <- precmat.IGMRFirreglat(A); pad(Qu) <- c(2 * n, 2 * n) Qv <- as.spam(rbind(cbind( diag(n), -diag(n)), cbind(-diag(n), diag(n)))) Q <- kpost[1,1] * Qu + kpost[1,2] * Qv + diagC # store symbolic cholesky factorization of Q struct <- chol(Q, memory = list(nnzcolindices = 6467)) uRuHalf <- t(upost[1,]) %*% (R %*% upost[1,]) / 2 vvHalf <- t(vpost[1,]) %*% vpost[1,] / 2 postshape <- hyperA + c(n - 1, n) / 2 for (i in 2:totalg) { # update precision kpost[i,] <- rgamma(2, postshape, hyperB + c(uRuHalf, vvHalf)) # find eta tilde etaTilde <- eta for(index in 1:2){ C <- E * exp(etaTilde) diagC <- diag.spam(c(rep(0, n), C)) b <- c(rep(0, 544), Y + (etaTilde - 1) * C) Q <- kpost[i,1] * Qu + kpost[i,2] * Qv + diagC etaTilde <- c(solve.spam(Q, b, Rstruct = struct))[1:n + n] } C <- exp(etaTilde) * E; diagC <- diag.spam(c(rep(0, n), C)) b <- c( rep(0, n), Y + (etaTilde - 1) * C) Q <- kpost[i,1] * Qu + kpost[i,2] * Qv + diagC # simulate proposal x_ <- c(rmvnorm.canonical(1, b, Q, Rstruct = struct)) upost[i,] <- x_[1:n]; eta_ <- x_[1:n + n]; vpost[i,] <- eta_ - upost[i,] uRuHalf_ <- t(upost[i,]) %*% (R %*% upost[i,]) / 2 vvHalf_ <- t(vpost[i,]) %*% vpost[i,] / 2 # calculate acceptance probability etaTilde_ <- eta_ for(index in 1:2){ C_ <- E * exp(etaTilde_) diagC_ <- diag.spam(c(rep(0, n), C_)) b_ <- c(rep(0, 544), Y + (etaTilde_ - 1) * C_) Q_<- kpost[i,1] * Qu + kpost[i,2] * Qv + diagC_ etaTilde_ <- c(solve.spam(Q_, b_, Rstruct = struct))[1:n + n] } C_ <- exp(etaTilde_) * E; diagC_ <- diag.spam(c(rep(0, n), C_)) b_ <- c( rep(0, n), Y + (etaTilde_ - 1) * C_) Q_ <- kpost[i,1] * Qu + kpost[i,2] * Qv + diagC_ logPost_ <- sum(Y * eta_ - E * exp(eta_)) - kpost[i,1] * uRuHalf_ - kpost[i, 2] * vvHalf_ logPost <- sum(Y * eta - E * exp(eta)) - kpost[i,1] * uRuHalf - kpost[i,2] * vvHalf logApproxX_ <- - kpost[i,1] * uRuHalf_ - kpost[i,2] * vvHalf_ - sum(.5 * eta_^2 * C) + sum(b * eta_) logApproxX <- - kpost[i,1] * uRuHalf - kpost[i,2] * vvHalf - sum(.5 * eta^2 * C_) + sum(b_ * eta) logAlpha <- min(0, logPost_ - logPost + logApproxX - logApproxX_) # accept or reject proposal if (log(runif(1)) < logAlpha) { uRuHalf <- uRuHalf_; vvHalf <- vvHalf_ eta <- eta_; b <- b_; C <- C_; accept[i] <- 1 } else{ accept[i] <- 0; upost[i,] <- upost[i-1,]; vpost[i,] <- vpost[i-1,] } # progress report if(i%%500 == 0) cat(paste(i / 50, "%\n", sep = "" )) } ## remove burnin kpost <- kpost[-seq(burnin), ] upost <- upost[-seq(burnin), ] vpost <- vpost[-seq(burnin), ] accept <- accept[-seq(burnin)] ## thinning index <- c(TRUE, rep(FALSE, (thin - 1))) kpost <- kpost[index,] upost <- upost[index,] vpost <- vpost[index,] accept <- accept[index] ## acceptance rate mean(accept) plot(accept, yaxt = "n") axis(2, at = c(0,1), label = c("no", "yes"), las = 2) ## trace and mixing plots for the precision parameters ## kappa_u and kappa_v grid.newpage() grid_trace2(kpost, chain1_lab = expression(log~kappa[u]), chain2_lab = expression(log~kappa[v]), log = TRUE) ## summary statistics of ## kappa_u and kappa_v apply(kpost, 2, summary) par(mfrow = c(1,2)) ## standardized mortality ratios germany.plot(log(Y/E), main = "SMR") ## estimated relative log-risk germany.plot(apply(upost, 2, mean), main = "U | Y, hyper-priors") spam/demo/article-jss-example1.R0000644000176200001440000000041513440250504016210 0ustar liggesusers# This is file ../spam/demo/article-jss-example1.R # This file is part of the spam package, # http://www.math.uzh.ch/furrer/software/spam/ # by Reinhard Furrer [aut, cre], Florian Gerber [ctb] # This demo is depreciated. Please run demo('jss10-example1') spam/demo/jss10-example1.R0000644000176200001440000001255213440250504014735 0ustar liggesusers# This is file ../spam/demo/jss10-example1.R # This file is part of the spam package, # http://www.math.uzh.ch/furrer/software/spam/ # by Reinhard Furrer [aut, cre], Florian Gerber [ctb] # This demo contains the R code of the example in Section 5.1 of the # JSS article: # "spam: A Sparse Matrix R Package with Emphasis on # MCMC Methods for Gaussian Markov Random Fields" # # Compared to the R code given in the article, here we give: # - improved formatting # - more comments # - the R code to construct the figures # SETUP: library("spam") options(spam.structurebased=TRUE) data("UKDriverDeaths") y <- sqrt(c(UKDriverDeaths)) # square root counts n <- length(y) # n=192 m <- 12 # We want to predict for one season. nm <- n+m # Total length of s and t priorshape <- c(4, 1, 1) # alpha's, as in Rue & Held (2005) priorinvscale <- c(4, 0.1, 0.0005) # beta's # Construct the individual block precisions # (based on unit precision parameters kappa, denoted with k): # Qsy, Qty are trivial: Qsy <- diag.spam(n) pad(Qsy) <- c(n+m, n) # previously: dim(Qsy) <- c(n+m, n) Qty <- Qsy Qst <- spam(0, nm, nm) Qst[cbind(1:n, 1:n)] <- rep(1, n) # The form of Qss is given by (Rue and Held equation 3.59). # Qss can be constructed with a loop: Qss <- spam(0, nm, nm) for (i in 0:(nm-m)) { Qss[i+1:m,i+1:m] <- Qss[i+1:m, i+1:m] + matrix(1,m,m) # Qss[i+1:m,i+1:m] <- Qss[i+1:m, i+1:m] + 1 # for older versions of spam } # Note that for the final version we need: # Qss <- k_s * Qss + k_y * diag.spam(nm) # The form of Qtt is given by (Rue and Held equation 3.40). # Similar approaches to construct Qtt: Qtt <- spam(0,nm,nm) Qtt[cbind(1:(nm-1),2:nm)] <- -c(2,rep(4,nm-3),2) Qtt[cbind(1:(nm-2),3:nm)] <- rep(1,nm-2) Qtt <- Qtt + t( Qtt) diag(Qtt) <- c(1,5,rep(6,nm-4),5,1) # Create temporary kappa and precision matrix to illustrate # adjacency matrix and ordering. k <- c(1,1,1) Qst_yk <- rbind(cbind(k[2]*Qss + k[1]*diag.spam(nm), k[1]*Qst), cbind(k[1]*Qst, k[3]*Qtt + k[1]*diag.spam(nm))) struct <- chol(Qst_yk) # Figure 6: display(Qst_yk) display(struct) # Note that we do not provide the exactly the same ordering # algorithms. Hence, the following is sightly different than # Figure RH4.2. cholQst_yk <- chol(Qst_yk,pivot="RCM") P <- ordering(cholQst_yk) display(Qst_yk[P,P]) # Recall: # k=( kappa_y, kappa_s, kappa_t)' # Gibbs sampler ngibbs <- 500 # Is very fast! burnin <- 10 # > 0 totalg <- ngibbs+burnin set.seed(14) # Initialize parameters: spost <- tpost <- array(0, c(totalg, nm)) kpost <- array(0, c(totalg, 3)) # Starting values: kpost[1,] <- c(.5,28,500) tpost[1,] <- 40 # calculation of a few variables: postshape <- priorshape + c( n/2, (n+1)/2, (n+m-2)/2) # GIBBS' ITERATIONS: timing <- system.time({ for (ig in 2:totalg) { Q <- rbind(cbind(kpost[ig-1,2]*Qss + kpost[ig-1,1]*Qst, kpost[ig-1,1]*Qst), cbind(kpost[ig-1,1]*Qst, kpost[ig-1,3]*Qtt + kpost[ig-1,1]*Qst)) b <- c(kpost[ig-1,1]*Qsy %*% y, kpost[ig-1,1]*Qsy %*% y) tmp <- rmvnorm.canonical(1, b, Q, Lstruct=struct) spost[ig,] <- tmp[1:nm] tpost[ig,] <- tmp[1:nm+nm] tmp <- y-spost[ig,1:n]-tpost[ig,1:n] postinvscale <- priorinvscale + # prior contribution c( sum( tmp^2)/2, # Qyy_st is the identity t(spost[ig,]) %*% (Qss %*% spost[ig,])/2, t(tpost[ig,]) %*% (Qtt %*% tpost[ig,])/2) kpost[ig,] <- rgamma(3, postshape, postinvscale) if( (ig%%10)==0) cat(".") } }) # POSTPROCESSING: cat("\nTotal time:",timing[1],"per iteration:",timing[1]/totalg,"\n") # Eliminate burn-in: kpost <- kpost[-c(1:burnin),] spost <- spost[-c(1:burnin),] tpost <- tpost[-c(1:burnin),] print(summary(kpost)) postquant <- apply(spost+tpost, 2, quantile,c(.025,.975)) postmean <- apply(spost+tpost, 2, mean) postmedi <- apply(spost+tpost, 2, median) ###################################################################### # Figure 7: par(mfcol=c(1,1),mai=c(.6,.8,.01,.01)) plot( y^2, ylim=c(800,2900),xlim=c(0,nm),ylab="Counts") #lines( postmean^2, col=2) lines( postmedi^2, col=2) matlines( t(postquant)^2, col=4,lty=1) legend("topright",legend=c("Posterior median", "Quantiles of posterior sample", "Quantiles of predictive distribution"), bty="n",col=c(2,4,3),lty=1) # Constructing a predictive distribution: ypred <- rnorm( ngibbs*nm, c(spost+tpost),sd=rep( 1/sqrt(kpost[,1]), nm)) dim(ypred) <- c(ngibbs,nm) postpredquant <- apply(ypred, 2, quantile,c(.025,.975)) matlines( t(postpredquant)^2, col=3,lty=1) points(y^2) kpostmedian <- apply(kpost,2,median) par(mfcol=c(1,3),mai=c(.65,.65,.01,.01),cex=.85,mgp=c(2.6,1,0)) matplot( log( kpost), lty=1, type="l",xlab="Index") abline(h=log(kpostmedian),col=3) acf( kpost[,3],ylab=expression(kappa[t])) plot(kpost[,2:3],ylab=expression(kappa[t]),xlab=expression(kappa[s]),cex=.8) abline(h=kpostmedian[3],v=kpostmedian[2],col=3) allkappas <- rbind(apply(kpost,2,mean), apply(kpost,2,median), apply(1/kpost,2,mean), apply(1/kpost,2,median)) colnames(allkappas) <- c("kappa_y", "kappa_s", "kappa_t") rownames(allkappas) <- c("Prec (mean)", "Prec (median)", "Var (mean)", "Var (median) ") print(allkappas,4) spam/demo/article-jss.R0000644000176200001440000002713713440250504014510 0ustar liggesusers# This is file ../spam/demo/article-jss.R # This file is part of the spam package, # http://www.math.uzh.ch/furrer/software/spam/ # by Reinhard Furrer [aut, cre], Florian Gerber [ctb] # This demo contains the R code to construct the figures and the table of the # JSS article: # "spam: A Sparse Matrix R Package with Emphasis on # MCMC Methods for Gaussian Markov Random Fields" # The code presented here differs in the following points form the actually used # one: # - Very large grid sizes or very high order neighbor structures are not included # here; # - Instead of (100+1) factorizations only (50+1) are performed here; # - No figure fine-tuning is done here. # - We had a few additional gc(), just to be sure. # - Minor change due to evolved of 'spam' # SETUP: options(spam.structurebased=TRUE) # just to be sure ###################################################################### # Figure 1: i <- c( 2,4,4,5,5) j <- c( 1,1,2,1,3) A <- spam(0,5,5) A[cbind(i,j)] <- rep(.5, length(i)) A <- t( A)+A+diag.spam(5) U <- chol( A) pivot <- U@pivot B <- A[pivot,pivot] R <- chol( B) U@pivot U@snmember U@supernodes U@entries U@colindices U@colpointers U@rowpointers display( A) display( as.spam( chol(as.matrix( A)))) display( B) display( as.spam(R)) abline( h=-U@supernodes+.5,col=3,lty=2) ###################################################################### # Figure 2: theta1 <- .1 theta2 <- .01 n <- dim( UScounties.storder)[1] USmat <- diag.spam(n) + theta1 * UScounties.storder + theta2 * UScounties.ndorder U <- chol( USmat,memory=list(nnzR=146735)) display( as.spam(U)) text(400,-2200,"MMD\nz=146735\nw=30182\ns=1262",adj=0) U <- chol( USmat, pivot="RCM",memory=list(nnzR=256198,nnzcolindices=140960)) display( as.spam(U)) text(400,-2200,"RCM\nz=256198\nw=140960\ns=1706",adj=0) U <- chol( USmat, pivot=FALSE,memory=list(nnzR=689615,nnzcolindices=96463)) display( as.spam(U)) text(400,-2200,"no permutation\nz=689615\nw=96463\ns=711",adj=0) ###################################################################### # Figure 3: # general parameters for the following figures N <- 50 # would be 100 in the article stsel <- 1 # user.self rPsx <- 1 # for function "system.time" rPsy <- 3 # memory usage rPint <- .0001 # small interval theta1 <- .1 theta2 <- .05 xseq <- ceiling(4 + exp(seq(0.5,to=5.5,by=.5))/2) # would be seq(0,to=6,by=.5) in the article xseql <- length(xseq) table <- array(NA,c(xseql,4)) for (ix in 1:xseql) { egdx <- expand.grid(1:xseq[ix],1:xseq[ix]) Cspam <- nearest.dist( egdx, delta=1., upper=NULL) Dspam <- nearest.dist( egdx, delta=1.5,upper=NULL) mat <- diag.spam(xseq[ix]^2) + theta1 * Cspam + theta2 * Dspam Rprof( memory.profiling=TRUE, interval = rPint) table[ix,1] <- system.time( { ch1 <- chol(mat); for (i in 1:N) ch1 <- chol(mat)} )[stsel] Rprof( NULL) table[ix,2] <- summaryRprof( memory="both")$by.total[rPsx,rPsy] Rprof( memory.profiling=TRUE, interval = rPint) table[ix,3] <- system.time( { ch1 <- chol(mat); for (i in 1:N) ch2 <- update(ch1,mat) } )[stsel] Rprof( NULL) table[ix,4] <- summaryRprof( memory="both")$by.total[rPsx,rPsy] } # Since we have a small N, elements in table might be zero. table <- pmax(table, 0.0001) par(mfcol=c(1,2)) plot(xseq, table[,1], type="l", log="xy", ylim=range(table[,c(1,3)]), xlab="L (log scale)", ylab="seconds (log scale)") lines(xseq, table[,3], lty=2) lines(xseq,table[,1]/table[,3],col=4,lty=3) plot(xseq, table[,2], type="l", log="xy", ylim=range(table[,c(2,4)]+0.01), xlab="L (log scale)", ylab="Mbytes (log scale)") lines(xseq, table[,4], lty=2) lines(xseq,table[,2]/table[,4],col=4,lty=3) ###################################################################### # Figure 4: # general parameters for the following figures N <- 50 # would be 100 in the article stsel <- 1 # user.self rPsx <- 1 # for function "system.time" rPsy <- 3 # memory usage rPint <- .0001 # small interval x <- 50 # was 50 in article maxnn <- 6 # was 6 in article egdx <- expand.grid( 1:(maxnn+1), 1:(maxnn+1)) dval <- sort(unique(nearest.dist( egdx, delta=maxnn)@entries))[-1] dvall <- length( dval) egdx <- expand.grid( 1:x, 1:x) table <- array(NA, c(dvall,5)) for (id in 1:dvall) { mat <- nearest.dist( egdx, delta=dval[id],upper=NULL) mat@entries <- exp(-2*mat@entries) # arbitrary values to get a spd precision matrix table[id,5] <- length(Cspam) Rprof( memory.profiling=TRUE, interval = rPint) table[id,1] <- system.time( { ch1 <- chol(mat); for (i in 1:N) ch1 <- chol(mat)} )[stsel] Rprof( NULL) table[id,2] <- summaryRprof( memory="both")$by.total[rPsx,rPsy] Rprof( memory.profiling=TRUE, interval = rPint) table[id,3] <- system.time( { ch1 <- chol(mat); for (i in 1:N) ch2 <- update(ch1,mat) } )[stsel] Rprof( NULL) table[id,4] <- summaryRprof( memory="both")$by.total[rPsx,rPsy] } # If we have a small N, elements in table might be zero. table <- pmax(table, 0.0001) par(mfcol=c(1,2)) plot( dval, table[,1], type="l", log="xy",ylim=range(table[,c(1,3)]), xlab="distance (log scale)", ylab="seconds (log scale)") lines( dval, table[,3],lty=2) lines( dval, table[,1]/table[,3],col=4,lty=3) plot( dval, table[,2], type="l", log="xy",ylim=range(table[,c(2,4)]), xlab="distance (log scale)", ylab="Mbytes (log scale)") lines( dval, table[,4],lty=2) lines( dval, table[,2]/table[,4],col=4,lty=3) ###################################################################### # Figure 5 In <- diag.spam(nrow(UScounties.storder)) struct <- chol(In + .2 * UScounties.storder + .1 * UScounties.ndorder) len.1 <- 90 # in the article, is set to 180 len.2 <- 50 # in the article, is set to 100 theta.1 <- seq(-.225, to=.515, len=len.1) theta.2 <- seq(-.09, to=.235, len=len.2) grid <- array(NA, c(len.1, len.2)) options(spam.cholupdatesingular="null") for (i in 1:len.1) for(j in 1:len.2) grid[i,j] <- !is.null(update(struct, In + theta.1[i]*UScounties.storder + theta.2[j]* UScounties.ndorder)) image(theta.1, theta.2, grid, xlab=expression(theta[1]), ylab=expression(theta[2]), xlim=c(-.3,.6),ylim=c(-.1,.25),col=c(0,"gray")) abline(v=0,h=0, lty=2) ###################################################################### # Table 1: table <- array(NA,c(9,4)) x <- 50 # was 50 in article egdx <- expand.grid(1:x,1:x) # As above hence shortend gridmat <- diag.spam(x^2) + .2 * nearest.dist( egdx, delta=1.,upper=NULL) + .1 * nearest.dist( egdx, delta=1.5,upper=NULL) # USmat was constructed above. # Generic call first: Rprof( memory.profiling=TRUE, interval = rPint) table[1,1] <- system.time( for (i in 1:N) ch1 <- chol(gridmat) )[stsel] Rprof( NULL) table[1,2] <- summaryRprof(memory="both")$by.total[rPsx,rPsy] Rprof( memory.profiling=TRUE, interval = rPint) table[1,3] <- system.time( for (i in 1:N) ch2 <- chol(USmat) )[stsel] Rprof( NULL) table[1,4] <- summaryRprof(memory="both")$by.total[rPsx,rPsy] # Call a chol.spam directly Rprof( memory.profiling=TRUE, interval = rPint) table[2,1] <- system.time( for (i in 1:N) ch1 <- chol.spam(gridmat))[stsel] Rprof( NULL) table[2,2] <- summaryRprof(memory="both")$by.total[rPsx,rPsy] Rprof( memory.profiling=TRUE, interval = rPint) table[2,3] <- system.time( for (i in 1:N) ch2 <- chol.spam(USmat) )[stsel] Rprof( NULL) table[2,4] <- summaryRprof(memory="both")$by.total[rPsx,rPsy] # Less checking: options(spam.safemode=c(FALSE, FALSE, FALSE)) Rprof( memory.profiling=TRUE, interval = rPint) table[3,1] <- system.time( for (i in 1:N) ch1 <- chol( gridmat) )[stsel] Rprof( NULL) table[3,2] <- summaryRprof(memory="both")$by.total[rPsx,rPsy] Rprof( memory.profiling=TRUE, interval = rPint) table[3,3] <- system.time( for (i in 1:N) ch2 <- chol( USmat) )[stsel] Rprof( NULL) table[3,4] <- summaryRprof(memory="both")$by.total[rPsx,rPsy] options(spam.safemode=c(TRUE, TRUE, TRUE)) # lesser checking options(spam.cholsymmetrycheck=FALSE) Rprof( memory.profiling=TRUE, interval = rPint) table[4,1] <- system.time( for (i in 1:N) ch1 <- chol( gridmat) )[stsel] Rprof( NULL) table[4,2] <- summaryRprof(memory="both")$by.total[rPsx,rPsy] Rprof( memory.profiling=TRUE, interval = rPint) table[4,3] <- system.time( for (i in 1:N) ch2 <- chol( USmat) )[stsel] Rprof( NULL) table[4,4] <- summaryRprof(memory="both")$by.total[rPsx,rPsy] options(spam.cholsymmetrycheck=TRUE) # Pass optimal memory parameters (from above) memory1 = summary(ch1)[1:2] memory2 = summary(ch2)[1:2] Rprof( memory.profiling=TRUE, interval = rPint) table[5,1] <- system.time( for (i in 1:N) ch1 <- chol( gridmat,memory=memory1) )[stsel] Rprof( NULL) table[5,2] <- summaryRprof(memory="both")$by.total[rPsx,rPsy] Rprof( memory.profiling=TRUE, interval = rPint) table[5,3] <- system.time( for (i in 1:N) ch2 <- chol( USmat,memory=memory2) )[stsel] Rprof( NULL) table[5,4] <- summaryRprof(memory="both")$by.total[rPsx,rPsy] # All of the above options(spam.cholsymmetrycheck=FALSE, safemode=c(FALSE,FALSE,FALSE)) Rprof( memory.profiling=TRUE, interval = rPint) table[6,1] <- system.time( for (i in 1:N) ch1 <- chol.spam(gridmat,memory=memory1) )[stsel] Rprof( NULL) table[6,2] <- summaryRprof(memory="both")$by.total[rPsx,rPsy] Rprof( memory.profiling=TRUE, interval = rPint) table[6,3] <- system.time( for (i in 1:N) ch2 <- chol.spam(USmat,memory=memory2) )[stsel] Rprof( NULL) table[6,4] <- summaryRprof(memory="both")$by.total[rPsx,rPsy] # supply the permutation pivot1 <- ch1@pivot pivot2 <- ch2@pivot Rprof( memory.profiling=TRUE, interval = rPint) table[7,1] <- system.time( for (i in 1:N) ch1 <- chol.spam(gridmat,pivot=pivot1, memory=memory1) )[stsel] Rprof( NULL) table[7,2] <- summaryRprof(memory="both")$by.total[rPsx,rPsy] Rprof( memory.profiling=TRUE, interval = rPint) table[7,3] <- system.time( for (i in 1:N) ch1 <- chol.spam(USmat,pivot=pivot2, memory=memory2) )[stsel] Rprof( NULL) table[7,4] <- summaryRprof(memory="both")$by.total[rPsx,rPsy] # Do not check the permutation options(spam.cholpivotcheck=FALSE) Rprof( memory.profiling=TRUE, interval = rPint) table[8,1] <- system.time( for (i in 1:N) ch1 <- chol.spam(gridmat,pivot=pivot1, memory=memory1) )[stsel] Rprof( NULL) table[8,2] <- summaryRprof(memory="both")$by.total[rPsx,rPsy] Rprof( memory.profiling=TRUE, interval = rPint) table[8,3] <- system.time( for (i in 1:N) ch2 <- chol.spam(USmat,pivot=pivot2, memory=memory2) )[stsel] Rprof( NULL) table[8,4] <- summaryRprof(memory="both")$by.total[rPsx,rPsy] # Update only Rprof( memory.profiling=TRUE, interval = rPint) table[9,1] <- system.time( for (i in 1:N) ch1 <- update(ch1,gridmat) )[stsel] Rprof( NULL) table[9,2] <- summaryRprof(memory="both")$by.total[rPsx,rPsy] Rprof( memory.profiling=TRUE, interval = rPint) table[9,3] <- system.time( for (i in 1:N) ch2 <- update(ch2,USmat) )[stsel] Rprof( NULL) table[9,4] <- summaryRprof(memory="both")$by.total[rPsx,rPsy] # assemble the table colnames(table) <- c("grid_time","grid_mem","US_time","US_mem") rownames(table) <- c("Generic chol","chol.spam","safemode", "symmetrycheck","memory","all","reusing pivot","best cast","update only") normed.table <- t( round( t(table[-1,])/table[1,],3)) print( t( round( t(table[-1,])/table[1,],3))) spam/demo/article-jss-example2.R0000644000176200001440000000041113440250504016205 0ustar liggesusers# This is file ../spam/demo/article-jss-example2.R # This file is part of the spam package, # http://www.math.uzh.ch/furrer/software/spam/ # by Reinhard Furrer [aut, cre], Florian Gerber [ctb] # This demo is depreciated. Please run demo('jss15-BYM') spam/demo/jss15-Leroux.R0000644000176200001440000001165113440250504014503 0ustar liggesusers# This is file ../spam/demo/jss15-Leroux.R # This file is part of the spam package, # http://www.math.uzh.ch/furrer/software/spam/ # by Reinhard Furrer [aut, cre], Florian Gerber [ctb] # This is the MCMC sampler presented in Section 3.1 of the article: # # Florian Gerber, Reinhard Furrer (2015). Pitfalls in the Implementation # of Bayesian Hierarchical Modeling of Areal Count Data: An Illustration # Using BYM and Leroux Models. Journal of Statistical Software, # Code Snippets, 63(1), 1-32. URL http://www.jstatsoft.org/v63/c01/. # # Note: For illustration we set # number of generated samples: 5'000 # number of burnin samples: 500 # thinning: 10 # This takes only 1-2 minutes of computation time. # # In the JSS article we used: # number of generated samples: 300'000 # number of burnin samples: 15'000 # thinning: 20 invisible(readline(prompt = "Type \t to continue : ")) # SETUP: library("spam") options(spam.structurebased=TRUE) library("truncdist") # Lereux model - one block, no intercept # load data data(Oral) E <- Oral$E Y <- Oral$Y n <- 544 A <- adjacency.landkreis(system.file("demodata/germany.adjacency", package="spam")) A <- as.matrix(A) # tuning parameters # (influence acceptance rate) lambda.proposal.sd <- 0.070992 # sampler length, burnin and thinning totaln <- 5000 burnin <- 500 thin <- 10 # variable to store samples upost <- array(NA, c(totaln, n)) kpost <- rep(NA,totaln) lpost <- rep(NA,totaln) accept <- array(0, c(totaln, 2), list(NULL, c("U", "lambda"))) # initial values upost[1,] <- rep(c(.1,-.1), 544/2) kpost[1] <- 15 lpost[1] <- .9 accept[1,] <- 1 # precaluclate some quantities R <- precmat.IGMRFirreglat(A) eigenR <- eigen(R); eigenR.value <- eigenR$values; Q <- (1 - lpost[1]) * diag.spam(544) + lpost[1] * R Q.det <- sum(log(lpost[1]* eigenR.value + 1 - lpost[1])) Q.struct <- chol.spam(Q) postshape <- 0.5 * n - 1 # start sampler for (i in 2:totaln) { ## u ## find tilde u u.tilde <- upost[i-1,] C <- E * exp(u.tilde) B <- Y + (u.tilde - 1) * C Q.tmp <- diag.spam(C) + kpost[i-1] * Q u.tilde <- c(solve.spam(Q.tmp, B)) C.tilde <- E * exp(u.tilde) B.tilde <- Y + (u.tilde - 1) * C.tilde Q.tilde <- diag.spam(C.tilde) + kpost[i-1] * Q u_ <- c(rmvnorm.canonical(1, B.tilde, Q.tilde, Rstruct = Q.struct)) u.tilde_ <- u_ C_ <- E * exp(u.tilde_) B_ <- Y + (u.tilde_- 1) * C_ Q.tmp_ <- diag.spam(C_) + kpost[i-1] * Q u.tilde_ <- c(solve.spam(Q.tmp_, B_)) C.tilde_ <- E * exp(u.tilde_) B.tilde_ <- Y + (u.tilde_- 1) * C.tilde_ log.alpha.u <- sum(Y * u_) - sum(E*exp(u_)) - sum(Y * upost[i-1,]) + sum(E*exp(upost[i-1,]) ) + sum(upost[i-1,] * B.tilde_) - .5 * t(upost[i-1,]) %*% (diag(C.tilde_) %*% upost[i-1,]) - sum(u_* B.tilde) + .5 * t(u_) %*% (diag(C.tilde) %*% u_) if(exp(log.alpha.u) > runif(1)){ upost[i,] <- u_ accept[i,1] <- 1 } else{ upost[i,] <- upost[i-1,] } ## kappa kpost[i] <- rgamma(1, shape = postshape, rate = .5 * upost[i,] %*% (Q %*% upost[i,])) ## lambda lambda_ <- rtrunc(n=1, spec="norm", a=0, b=1, mean=lpost[i-1], sd=lambda.proposal.sd) Q_ <- (1 - lambda_) * diag.spam(544) + lambda_ * R Q.det_ <- sum(log(lambda_* eigenR.value + 1 - lambda_)) alpha.lambda <- exp(.5 * (Q.det_ - kpost[i]* upost[i,] %*% (Q_ %*% upost[i,]) - Q.det + kpost[i]* upost[i,] %*% (Q %*% upost[i,]) )) if(alpha.lambda > runif(1)){ lpost[i] <- lambda_ Q <- Q_ Q.det <- Q.det_ accept[i,2] <- 1 }else{ lpost[i] <- lpost[i-1] } # progress report if(i%%500 == 0) cat(paste(i / 50, "%\n", sep = "" )) } # remove burnin kpost <- kpost[-seq(burnin)] upost <- upost[-seq(burnin), ] lpost <- lpost[-seq(burnin)] accept <- accept[-seq(burnin),] # thinning index <- c(TRUE, rep(FALSE, (thin - 1))) kpost <- kpost[index] upost <- upost[index,] lpost <- lpost[index] accept <- accept[index,] # acceptance rate apply(accept, 2, mean) par(mfrow = c(1,2)) plot(accept[,1], yaxt = "n", main = expression(beta)) axis(2, at = c(0,1), label = c("no", "yes"), las = 2) plot(accept[,2], yaxt = "n", main = expression(lambda)) axis(2, at = c(0,1), label = c("no", "yes"), las = 2) # trace and mixing plots for the precision parameters # kappa and lambda grid.newpage(); grid_trace2(log(kpost), lpost, chain1_lab = expression(log~kappa), chain2_lab = expression(lambda)) # summary statistics of # kappa and lambda summary(kpost) summary(lpost) par(mfrow = c(1,2)) ## standardized mortality ratios germany.plot(log(Y/E), main = "SMR") ## estimated relative log-risk germany.plot(apply(upost, 2, mean), main = "U | Y, hyper-priors") spam/demo/jss10-example2.R0000644000176200001440000000031113440250504014724 0ustar liggesusers# This is file ../spam/demo/jss10-example2.R # This file is part of the spam package, # http://www.math.uzh.ch/furrer/software/spam/ # by Reinhard Furrer [aut, cre], Florian Gerber [ctb] spam/demo/timing.R0000644000176200001440000000332013440250504013543 0ustar liggesusers# This is file ../spam/demo/timing.R # This file is part of the spam package, # http://www.math.uzh.ch/furrer/software/spam/ # by Reinhard Furrer [aut, cre], Florian Gerber [ctb] # We construct a few large matrices and we compare how much faster (slower) # we are compared to the full matrix analysis. # Since all the calculation are also done with full matrices, we do not # exagerate with the sizes. set.seed(14) compare <- function(expr1,expr2,tag=NULL) { if( !is.null(tag)) cat( "Comparing: ", tag, fill=TRUE) print(data.frame(full=system.time( expr1, TRUE)[1:3], sparse=system.time( expr2, TRUE)[1:3], row.names=c("user","system","elapsed"))) } xn <- 1000 xm <- 1200 # first start with a full matrix. fmat1 <- matrix(rnorm(xn*xm),xn,xm) smat1 <- as.spam(fmat1) compare(fmat2 <- t(fmat1), smat2 <- t(smat1), "Transpose") compare(ffmat <- fmat1 %*% fmat2, ssmat <- smat1 %*% smat2, "multiplication") compare( solve(ffmat), solve(ssmat), "solving") compare(rbind(fmat1,fmat1),rbind(smat1,smat1)) compare(cbind(fmat1,fmat1),cbind(smat1,smat1)) # now create a sparse matrix. fmat1[fmat1<3] <- 0 smat1 <- as.spam(fmat1) compare(fmat2 <- t(fmat1), smat2 <- t(smat1), "Transpose") compare(ffmat <- fmat1 %*% fmat2, ssmat <- smat1 %*% smat2, "multiplication") compare(ffmat <- ffmat + diag(xn), ssmat <- ssmat + diag.spam(xn), "add identity") compare(ffmat <- 1:xn %d+% ffmat, ssmat <- 1:xn %d+% ssmat, "add identity quicker") compare( solve(ffmat), solve(ssmat), "solving") summary(ssmat) # compare a few cbind/rbinds compare(rbind(fmat1,fmat1),rbind(smat1,smat1)) compare(cbind(fmat1,fmat1),cbind(smat1,smat1)) spam/demo/00Index0000644000176200001440000000114713440250504013270 0ustar liggesuserscholesky Illustrates the decompostion of the Cholesky factorization spam Explore some properties of the sparse matrix package timing Compare times required to perform operations on full and sparse matrices article-jss Code to reproduce the figures and the table of the JSS article article-jss-example1 Depreciated article-jss-example2 Depreciated jss10-example1 Code of example 1 of the JSS10 article jss10-example2 Comment about the code of example 2 of the JSS10 article jss15-BYM Code of BYM sampler in Section 2.2 of the JSS15 article jss15-Leroux Code of Leroux sampler in Section 3.1 of the JSS15 article spam/README0000644000176200001440000000161113440250504012066 0ustar liggesusersVersions of `spam` prior to 1.00 included a LICENSE file that described the license of some Fortran routines incompatible with the general R philosophy. The routines are in src/cholmodified.f. For the packages `SparseM` and `spam`, Esmond Ng and Barry Peyton have very kindly given permission to use their routines under an open source license (2012/03/09 and 2014/08/29). They have requested that their code be credited via the following two publications: Esmond G. Ng and Barry W. Peyton, "Block sparse Cholesky algorithms on advanced uniprocessor computers". SIAM J. Sci. Stat. Comput. 14 (1993), pp. 1034-1056. John R. Gilbert, Esmond G. Ng, and Barry W. Peyton, "An efficient algorithm to compute row and column counts for sparse Cholesky factorization". SIAM J. Matrix Anal. Appl. 15 (1994), pp. 1075-1091. The old license file of `spam` versions <1.0 is in ./inst/0LICENCE spam/LICENSE0000644000176200001440000000016713440250503012217 0ustar liggesusersYEAR: 1996-2008 COPYRIGHT HOLDER: D.C. Sorensen, R.B. Lehoucq, C. Yang, and K. Maschhoff ORGANIZATION: Rice University spam/data/0000755000176200001440000000000013527770376012144 5ustar liggesusersspam/data/USprecip.rda0000644000176200001440000027445413440250504014362 0ustar liggesusers7zXZi"6!Xv])TW"nRʟX^#&'ƯNQyeVlٌ-P3)LY|EGre e9<Ĉ]Ϩn:޿̜|0p?f>¿<E#?\5 n`ZU<ذ 3w9ubH_}茩PD Qja07 B@i' 3ƽ*p`3 kўd6$^E^H!^"oUrd_?T7SHc;S:≐f(M!d{D,z"3$I#2 K(7Wπ|lQ卬߲͆3w:[*OaT=I~,4+!!v 3m`aVEbY[ξT͵#.P d]ep4a6][_` ] Q.L8TY SGgKwzxՠ3b,lHnV9un3 P]8^M\.~.Jǀ6Hዴe><=NLat[6g,hXt  ]Z2\jTU[k}swOHcg( hd֥K+;|{;&{X"d%_pZ&Pb<:Pک&0`| 3,(UO #u:5-OSfq*13Lz^RU0JddIg܄jq:W<`fXu" " u#a HZv\FSO_cv~ YS2ޠc>b̳n'/sW =Y[yݒuW+Xb=&+?e hçFV2/̾b$(rMd|n"ez<#S 37US~#URF,j2:A*齐%Z~Cu|COZ%]Xa%^7xh/bGqvBx3*^UXĄ\ lO R.+,"Td9U)9l7nA<}u^(MSwD#gʫOtVhW@ "yh4>Ik Gyɝn¦E0/7>(N]@(>^t2eCQ_X ƯZ;_OТrSK:jfUhlM_rC5z J%kjU ܑ5u HbAwӗ,c\&OpKIA~ZpHv9c'bq_~R~\ySji{2+AMM9G#qe#AU|X|JvM{_ ˋh;_WS\`X{r4ݷ}ۺ=D$v˺dL}[SMc!UbYS5%)r{<"[/]:gSSVhÍ,$BKY_'NJQ4se(בPf{Շ. .7^8g}St!.JVXz@RCTs #qX> +XP+ ( V|KO*@w@&d wZ㡪YQ3MݾGیٲ.xoh252{ݝӳ }_ 3H߼j RL;q;S-Y@]Qp0EzBE&OrAPa޿^(bX_~Cح Jb4<\&*鉈UI0O:AY1/4`P٢7t$'4Ӝ(; ekQg~DJx8Lv3x!iʼOss` t;DV{ 586Bi\<ȭHו7ɵ{#Kc#"bvwƒt3?|Ÿ_D#nS&RXHJ"GjAy]Ra_"$Ҫї. Eͮ0OMfL&jQPUq. P"Nȍ`85|ON?z&?(ϴs$ؖ:kvA}zc˱DNh'Ṳ$P HUt8>INW/a)z&4P-=D^:㉹q vwRzOU>ع^=85;5/Mo_7+6Q뮂]6AHL'c?<$ N-IPmFY\պhQpگOjss &gAf6.Rm6o`elsB 4vxeK-tK1x-l'>])*0}}oЕwнB z\NRI+匒c68j茚]NC;+%̈́O|h<.Kj̋+/olSiO=i{ԗKr-_ii$GTbG^<TtuY^ccO$`L bv`{$^h4gF^PZ{׸!D׺YnGzrgm<{V^tU()=}a3;w oC.q=󂒕~qAh걹r)tfR& #k.rÊU6$7fq{9 G1ƺZ)2 U$QvyQ@=#wez1ʷXw: 82_ӡrGaQ_mw?HMs0J,Ay`>H=Xv@N."#N@ biZ)F%=Gxlc^$x$Z%f.Fgj"# )$S/0 uKHUUȁ185+C8KQçHFtq$Ph7W\vW$l_3KB*&hh p"D~1I oJGB*K@4> <6''/*C!E{DtgP4RV8;x3QMvۊ͸@:&ub|h 4G#U4HڬӈʦUNbO-3aEFFOo__;"%}w9?bO0B\!)tT(4]Y)q3cDx.2w・v}bj(S+bP-_dkP*;¶F[ =,M+劾TH~q$*Aȅ6^q7Cӫ#ԙ-]0Β1_w[}FC<`üwXmΚRYʡ]LFݝ -][HrH~S:+l|NJ7XrQѐOH( ^gCKܷVk؞ᑒl5Cl./D?#]ԝ,#S*9x9i߂Wo됎cݬG{lҦ\#?nx 2hJ^6.fn!#@# ֬<9d%Tr,sz| <Ph"G"QS8뢩JY;y=+w**1)O}WQ,@6fז -}OFE*@7[OMMYE}^oCqW}z|qq"ŝdQZ,eU13僴S k;F,Wl4P^2t^ &ta}*`.!`oVCNl&dN^&[\_賲`%rRh3Crf&f:?oW^CX<ǻ6Yv!t;%KmIhr].28,nPEfFu_3jV 8SV3//+\ S4_Ȳİru +p`0J^3/JFbKz>Aݦ6xQ 2;`vVZ ":8I %vױt*qۺ5 4 cVRp9X>cry&f-xV ֬?Ȭ8w5J8CYfOԡOkNcYRޕNA=!shܪ’8EB戅ŦI&j]G2ŝP `ڮ#x,o_NYyӹbݩ,4ov''9'OYqDLh3ER0ѨNGiDsqX"G4Wr] wgjyk[Ei,v:/9 YaܮQl/>Oc^v"+}'^[ $-Pr2ToWBe5BC]rx%!}ŦII&s|+@ț7KHAP18{ze,eSm7/!述uv7ȾȰtuYaT"Z;C8 m&8ٗgl](*!^5j&6IUfW7&`!C$ n^{?QGh>.3'XZu0Q)箰g(;qEeAwA?&ě*[xh裚b!~B'ٮZ:l`N ibg#gdF6ql S(6hilZ2U^9_v"cC똚DRnqyHw0 ٣;( Gub2lA1 )D;O5/xp@I` 9HdCnh%$'B%yRm b3%U6V,SE<|uJYa˳P)9 UJk,G"E O3Ë,ʩ>/ U*CdyImLxm՟j3Ѹ"IuQQMNwzvIle4mvwQ0[ V$ƚ8II 2SPlQ'u4Ĭүykwh^''Fg|>Yw.T|i"~^L3-N>Njsx--fI 'B}(ItЊAT_O}ÃX'703|5|+s_bm'G*)W m̨5$Xmk`4ӡs}@} ^76&&1 ՟+pDc9U~I 0)hB=rezU)"j7?MZ1Y nte扠$HŻZyyɔg{^{E֖ƾPqZl^J}!2/;咶ߛ4OkHo=K QWz/q%2_{JΪ@uC9IKwLb,ۯ܏o8_tFГ2J!z{$815o;~zB~,֥FLw9Ap`tK%*Yբ_̇otc+DϦ/"swJIGT"*uri/' *ˋ ׳AmtYxiO/l<#RnMaW`i}@A~~b{}g,7cZSP?WUyJK]}TSQPmśw^~C8A⚰g WzR/oz+p1U2;u=3`зŸ]P>m(m ٫`9Lŋy&89E~IJ3ڝy~Ş=O7|#2{!X$`zFߘs^m0gɳz'eKCG͊`'w\9Xy6M[ݏn:W+o0LXvi"N&ۍ̘@'OTοr3΢۽z-5krrXv=;T2HCM"ROEė9L5= SL&۟jLo"0.뷜 3_xI{TT&TquN;eGN9=AɆDX6 zF/T(;uz+xu\X\諉f \bPu,|[1-v (=/[efݚ:Nu [pe-B\99D!i_^N 65\iL)3+UbA6Hhr=q] nw3&Rgr=Bk.-2v\^|w'8z}mu`ڀl]#}9]GK2K37Nw(yS MR[3H2] GK,rJp#0يO;-Shwj"8xF#}wa)&Yn`ZQ۳O,@/ȠhR 9uCȰ|-i;Z:LAoEܢaKܼuU -W"kd-"S\ȉ!;}0%}pBYpӖ;`J`>o 2XVL䡒&IOM_3rH 1r m~H6z48RG#n^b>7YLcPYt/nVP̢DJ)]9Q^I/Pr\L v؉EFyAeT\͌h*]/!Œ![0oE4#wGūFjN9ׇ ]d fm9OLܥ9 kKܷ&!|1}lR QuRũUךdu{T}!LKWj4|=MdC_beeF1*f#,J'T> Ǩ̘Ҫ7`7śT&JyՐTmK}n aVPWc}:`y21lefJbUo9on R=DmQ̀|șk Tl";5oH5MJ'`٣_RXUi˶H6;xw6b,qX`Dx=>Gؼrf6EG8>Wt> W4i^.q/Jۘu>躅aELSc/l ]0ӿ˦KPSQȞE ׺=oWb7> S}s/C-좼okqf-9o}dW"h1?>ѧcwP3Q9x K (|iճ4)BC-˜ɳx7Y|B89EkZ*-?rGbWYݧ>^m31tsL[~joY_l&J+Hf2J 5Jx KO X0G8sgTi] .߬a.kaIa׾ˋ\ꬱem: ̷2EW'ojE>,Ռ6i3zSl&TӫmݟMij +dVC'2֜HF*տR0@Oj_8^  /foݛ.(, .P7Y_RU%y'#i@OlS^j+&=.M %R5[係Ґš+~θ=$\&8,UEŧMJDT#p5Umhᢍv#^ ـo7 FGa`yXoaCVZqU*ORyu7 &OS'tz\-GK4|ʗD| F1bIsٖ(B RˠCL0{ZX?RrPXhфi6uh2 pA G![9E'q+PEPzSsB[o34xX9AHqyQMX8Y$[W#u޷5dO:7רIDkTx՞K$ZMʕ ;jJD&s9ۿ]~jNHpM\ _.Yd4E%nWs4^nf\k%UM<Q6w _r(ҥFjuGu6#k(bu#m~/fRͩ+!9EiA :̽ތMO8+qB/=l`CnUSeAݯɈ  Iˮ'0%.k<+4=5i} h eu7cO:>gF9+2izlF2؊{Qď-- Rtp aOek-VndR?zre1= JC."Vmvtst.CskoͶQ3QD!g߻b+,R$_3#DZ}ý ЦTo)#fՀ E?Ccwձ{dwO;%RH;o:MϤAT 6 p p/^DvsxhOG}I ;_-n:_˱g^ZǍ' H[HY5wgDdo :N/ D _hV뙴̿N㨯aq/_E"ԗB@`rJ/7;.#n\B!KvBOvݤ=Rbqd,/0>IւX?A48^ ^"3]ɂB@ڦMu.u_g@ ff."@5.*m-dҋ*M405-YnelwNu쾴@괻P}G;<4ezpp4IPfim>ݓڀ  WEPf-Z i[>t4w_@5P4?ćJBZEiMˡABWʁ}uרp.zOZl8w~lUBc;x sj"`B$s+Eh$J^C,{|kτXH#nOZ!Gz{J ‚ICP ] Fsx(:qTI5/BY0gc: d6;k>ZA{::UV[̍-r]JJ^@)D']>-X75 }^OZ2XV4KB]D<]4heO~V|nR4{_0<Ē9ҹ{\*W\Q%Y uy',fᕃ5>+|.#uwX$asYT.*w|f}l*+hHDzs`W|Q ^ O']v4kv%z0wJc >FV"Ptiox熓dMh^.}o-[h>ĜOw8XyWo&J룊ہ'NKw S{x6ٖXk߆'S=5Ic>Yo!dM*sX\df.1JI8 BDk|;`5BЙ$kU-Dsg8K5>2ﶱ"6Gz0L1ʚ| g#5o(ܴEm<XCtZԤpԶ 0RPGc/LiIk3{zT]5kBoT3CG_I햑ZEKO΋ŀ﷼PysZtA7a)%-92_b4Io[[Vm11*/Lj0mA@:jB.R\-|5W&32@\wȄ4BaUqCt-[<4$ XND~60xP%3Y(,a?Ž66nenuZO$`KkzkMWbjNѶV!MرO&mR|7P`gKhUC\n74C@MGUdXMY߃s0TPjh0DGlxlɶ8Ube J%fzjgf a`\lk3g??ݹ*̯?i}ʷ3 ? DJ]Y:#>@M]})HC;^C1:}DIUДiI(3T{825@/ʆ*\d6unJ rbq̏nݥ2\K _㪚3!6q͟"mI OQP SCp%e/_Ts}ʥ,isMYXih`vC-=ߓD. *q)f;/ g 61 㙌&35ѷb-{qg6J}}\] īi0xK1e;BAqˬW)۝6m}–ӆ ݾ{5>{/]vEϷ`Egh6@YxN%r y!bKeW>ƸBH3~k2QʣB|_cf;\\G@uVC>WrhʐXFa5՜ TUqhǼ2ՔVqE~R h~[r-E"s20=hOg~\[xQGEͶmY^n5ˡ \mbqU7;8"IF!aߥ2Lfc.=j)ZlcQ8eZE {>]Y"pL^ kKqSTkW򰦿֎B.eUg60{9Vo?Q1~ZΜJ] bλ "q 7%R>F&Xa&G?i0n 0XtdE]͟If<9 q}RH^đ*!eg*(0t1i>(lC; [=,W'z>aBĭT27]Wr= g!u4tw0|}s)҄'FP~ۈBb\7= S#Έm {@*t)&!+fvCȲ 0\q{BE:MW' Mt&ucT[4 ;083XKo2&$ d_v&`B˘t tpP0[GW6BI %g\7h怣B"PEn{`7w+JrK/W glF`V wy#ڜ*ݳA~1J/>TAڊNhx,!^]\ \w*yubQѪ)\O龴|ڦ 8){x%=?eBUpYse@HYmQXdEPyJ->BҶ,'a`츄*viɫ{_X>^=!3Ȱ(ru,ڣ`yG8 r'_31lsoZ[{u[8ԟ1,g8E:M9aG_l26+jFЌ/$j9K+ÂM?$;&D˅fv~ylaS ,΢W8H=Iq11fF0iOa5[@ jTZ|UV4\4Sz6aYc FS۷*a.i,c9ݚ5;QBA]L8X w; qK= ~ wDɬ}پ7v8 c `*L0d(>s:UZ 9<ńܠK,ҺX\ j԰Rm7;Ϸ/7W5U|! "-@G$FśV9&+ <ЗZ˙hPM !"[}oZv$.Oag A|hoNA*,{Ә\q:kPøsOG F0+xS@a/!F"nD+ ۰;ʛv(x%B]!#jUN`.+Ngf\] 2zFbkeM U'[U!p[r7o<3%Ub,Mֶ=J}59zYvSfHPtApB0)/څ.ח|UA_f!TY;f1P4S s:̎J=bs 5tA&ͬCڷ.mU_sP?c1g]/&~r׽s:Oc@Z#)Z+V:|C\{o^[Z Uŵg*fðOUJb87^,9cfoj-fVv=ָ3?33x3,HHM2hԾ kPtT?ȩq=쑜wUwZ{!@k~QӼ9&(I',?P|K iKV2C):st!&c@СJ&Hf=쏀5*\"KytIQM 0HR#,&~Ƞ &F[>8m:Yt0ʲ9-l.jS4w<;;hnSœpnP/|[ kFUư*' ĉ2YwhPgU'kCyﯻңd?Ezl~ib6[wI[)> &nBh7ĮQi/lG5I 4 " Rr=*!eqS}K(5:@0IEgw0T\pvz|<˼Lz<ֆSb\~lAʁ`{rqq*bO2PO-hh̎ˢzob nIv{Y뺆LG"oZ_lFP8EBz7Px q+H墛琥Cvz%Եӆt=ecViRp&%=5Eli઻Qaj<(jV崸{⥝t*W5.Xm!y]}0f+Nlu-YsJGE- iH dJ}Kn3|9d0n(?w)pO+nwUsx1Y0y5Gxf3j$Ѱ}lXAO섀J3*G 4H!MeaN#+He!BS@BV6. QS,yܥAę`HXo%OPƑ.i? ]R&ٵMz7aimvTU$Q N6u8=Ƃ2t%UcjĦ/ El^&yY|dQ^M@/9ݗ5 bAB搓ٜ.dM5t3XV@~]y%,cgDjmZ<{ѓHw+Hdw{%q\[~b6<8PE`N _O)2F>m*MKQNY]2_pXo:-4͹Nyx==ڐFi)+>6wydö#n Ԫ;uG@ڂձB0>~c>OS5VZ(EW8οQ}lS6̨,ϫL- Zףk˜&Og64\BlB#x9m>!N,| ?+<]!8CԚ/dˊo_%~\]t=N2zatR ςb!+MRॠ>nxE %kbLcm!I;@ræfjpHj$T3#bLWn+w2P)k-!#.^QgMƄRGld 93l;y PV(j-7ej[@)OT.Vh IZ$Q 9Y1#٠w`JDGo" X1#7ruuҒ 7Eje~Jb2~Ӟgp1}A[fUeAPHBLEݍ,;F%D&k]3 Xh*e??ϸ& Dˀ yl,?,tl#"-=^[loF•p@p4 ސWmVntO"Z|~jug颈j4=pZ0]+Tyݜm@u0 VzFŰi$֣z'}]섚C="3`Yͅ-6Zg"Zl!WByU*kL=&_]h e\fez~A׹|=RtWņf\ iAHs UX41S 5fjc_;wNRhaVEt Gɯ*_P.{kiu 0%pT=إ Ml@se )(K3BpOFfV;x QB- T@O\ճMYF:i(MTht+ξ:98x_rƟWR쪛0OL҂xI%`uMEVٶS@ŠCC-v ̣7nԂN!–MF&lB XwUR/I9:cSٰM@-ɩ| h>ߨo/SO_&JbĎGS)9%^}ϻ*KY ?˟}. vE֐ 2z~Uq{QtkοAh~NH=ڡ7Mlهm'tMQ!$"/,f<Z|"Vκa.!YG]~];o,ϓR) *GΛSw}JZn?*9Ks`'ir}|n(Z5["#Qg7ECmQcX_?E)fjjiUX%ap\c7c$L]RͼW'}e+ cB4s[_?]$niOVbBԞaUy &4-T1;ByȘBSd>E G$%qD2YH:\ CbdfT-vea5[=:P*d&@@cRjo9!CPO*wc?غjy4{AЫTzt<7^4}ԏ^XM7^⎛!j5$Tx\x(ۺҽg]4<}Ynמ{/\7]u8kg fީqBڴaá@åR j}J }G8 R+Q(}\9JI#ZU1& kYV>f'+Q,hP*BUd-߈šiݴ<x/lg4SϯDR!$O,,RUiZ\lf!Ŵ j΢zZHk`٨O'O< bIk er,0Koz B`8}#qyJD VbUW9uXZǐ yC5Kx3N(ZPHlB*27}@~AH.m\5åg b? /@V*UY ik"ПR,D?-5!;ZۜY#\YNk3Opf"D-XAL6ejWfY]\ raUjߠ-\-+maF(Gd)˰x\c}Nz@6uFFh|-]wEx2j 6~rnhW!W ȣ wsxoYy(B 6NGZeVSev~\c韄=nO&⼚ ks|ݝʥv΃,%F28rQtӢ4ߟ{ِwy{wRH$P#Ŏ!"lL2/aa-p >f܈kmQhרw7>/]9-ZP\M\aP=E=MrYPcU(5!`\@\k _.`& P~\-4ic1s!˦ H&B&EvB\Zwn{V\Cj-0bDL%&(@19 ٓ˲D(vK =39jsuVIDO=c<.9:bv[LxN\7 N?P ыd Wșc(r.#XW 0PJจdaa m7XxrJ@DMđw)[*Tn"棷KC~"I;ǣ8vn4l`i^sh#daU߰D}(l5x+3 kf+"zͤjl/wqJVzMm@ uP ov2'/ xUpW74c{H^,?J_$}m?{_WRɟ'V 0_Bf-.ţE{jgC7s1T_eAf+WI[ VIv- ÏQ Q]ѳ;zwdIE`:[އFRy O<O_<{ӰY?oe@.$m3,Zˁ5'ZăBV8 G\U vs\e ^*dka"1vv-+>g?[?gǧ%,ه!Qcf晰lKKS5@3 kT.;wR( 36mW"j1D"[+k'[ISD-?(zn靧1/ Ajh-o t*'cW4n3[Ut+eCdZŸWc Lj]nz^J( S'=~AiH 21,: z9a:@hʓӸ/z~,!p2t`bry͝ӬmQsTWV/_ݻ^}_Ea,7jmY[^)>0.+<@3XP1ZZVAV1ۙ^߈hB1--ǽRgخ>pМ<21GUkh"DBmjGd?uMg>2 \Ho1 ^`2&{[UH}PV[U U%t()&F{ wQcP1hg}FRBR{*AR+л3mV#N-^\ܲl;(b(TF'sMo ajMzV L!AuMw:cg:oݽCh,]'SV3ߓ)Ӛ[RJs<{(W$]s385*b@>mE뱖{Ԗp8)oOTֈPa => OL;*t%IYT`PnZ xK.#Ȱ7X#779r(Bad ͻZlv 煪*rdY;zion`FFa^waNxauI>AʒQT "^c]9Jnٓed( JT:}A12n>^|k߄{-y3LTiMԥ,QMwa )7q"!0Ddp8 g'oojaZaWAĿM6q3ʛߕ^9 g8x Zzn*L6N7e&V*pe6l]Qy(fA2iK"F,o)QL ǃ?κҸvRZ_YƕDB޳ O&Jj,#aY\a쬧1ul T+Vρ,sPQAlB6Ž}SuWP%wOG.#5 ~JG ]Gd*! #ej5z-a(yImm^ n7|{\G~ #g!$A5j`Cl5W(.yFlT[ ^F;ա7a-Jڸ|H:X QU!$q(FhH .=H8X{~&ICCb0:kգ3=/ړ6^K&2Y{K;4~|JDP1]&q]>C"kCR/$%.I04sDRuc +i|)77\[lXb ;2爻l`` qnw$8:Hh.(*lD71 ]Ҏ*aKڊeōH3Db9av\@tsNAQiΚBHlG2AtÍ/OFYB]rױUt)D2Ìuv{_A{FvWAzw᪝Bo/&(0Cy4ҚS ;dz1ͽVǔ:? >>f/4t8LAa8+$>q&3&OzZJsF6K2oM i KGL xyuwexS`}2q;>2_anO#TK [d ( ۇ iZr1TGQH5w :: 5q|0 DWqH[J^7(C%睊GVU.Ёs $j[6~2ʤt[roB$꡾f9*%'Vqඅr :"S8O8E/<" q~{PH7mTL+0a|8A;'Wg4˕`)HX3jrppM oIa) eNX搿ѳ0nt ]>Kw&. IFP&Rķ #fg[!.!ͼT2"z 2; Fb3@I(6g&][`ܕ"al^̶Bƭ1'N)M0\m6>WEIY]= ,@'ʼn˼{YƏ]C&;5tg9b>kylTğ(XOmaAI^$^yD=W%b:d%Yyfy K/!"`NY^&27%. jD8>3@8d)B53N!o!d*I?I H0ZXU|d-@9XM,$!)MK8 )v!3aDQYDٷ֤6 g/[`Z?j.o#FOTj; 숔o$eˑCL=CFm!#rpQkmc+O>LB5匘mj$7?eV7^`c驲չuow^kԶKQqT߼Ra]ʘpC.t^mp>ި\p cNh3CP>>ڬkm 'ڥAs/eG hYK7]V'\#)' [C3wq+*6: qŪ|_5i*v%=7]}9,+>It6Цs=Yi%%zd|m̻oyzi+H!szK 7$)v;rXroti/!'BdT:j\]g@TU2;@"nv`_0_NEdqt8>:OȨ $hqÅg]'hfˀ&? ::y4IÙLV0Pɜ.)=.Ȉ藼>c`BA'ż+D|[>$&M,Iv):/d5}/R#Ot0xSeJ7(Aj?W@+zr}ꨅ"BXXʹlj:(<^),Ѱ Q%Mֿ􄴾P~i,eE^u{Lb)ss1w7хV%NciizPjюhө N1{slKʕz2HQC+6+_5~yu n-beUgX.'[اaf}p[=n*@DPAM(w+4*cH,`z@MJ6tg=b]*jR^0|9Q;KNpf57-H &Rsq" \6I,ϳ̆.0W6H-{pJwЬ- e/{}z&5!9Lh3Y eJJFM0q!@MCz'߲ Z:kmO{̓Gӫ" ,/(qH*n c'F#Bƻm zYEu tFȴq'P(];~ISf7\2<6$NH51%`BJOe> "{/?r tWy0t. ,3k4:I9n,<[T0ZfL-as.a&էE*–BT^Xiv-b[[s7e0TQE >!:k[=gsQ&X,c#[cH9{ PC$(1OFg} k$,5B\/-"|/g,o,6Ny گwRB|ژH.đ>7+ʼق +N8kVa;oS;P?N'3풣^Dp*|\3&Q¦]ܸ }al'SRNĠqV ! `VZ66{wGVb/`s/3| |{p&Iz3H9ݽiV lOx2Y0Ճ>U'ʍ)Q7b[+97y@ G Ͷ5g%y?o޿.Fqg]/"Jm{u=a.4,!fߟHnGai8v?CewQa:5nM{X=_2#:,loE; e_ S!:^ܼ*u b/,HTQeyNo hOi&O&d^[WLBuP]99Qo,Ii޳  j _8yg/Y+tdr=u_a*B8 8fzCiR$3ybn Ndl Yh띤- li-P:&U9p]3Ը}]q{;}4Rj:=_}DZ%Z|Kmq~0qs)k򲟩,X:R":zMOSk@~}R;c .`*tW趚QXN42hfXOa'<ˡgL{(nEaRWH:ܳ"̯6 ϷDE!꾘3Gc`*uCS x{@,1) Ɂ 7SlV8 lqsCUy6Ʃdt[ o)'W˗6qª#whsnd`mL/B_L/pwSXffȡ"j^P-TV24((Lw41:gJo\Vz7`SH΋ zV= K淇E@k^Տ!6k槶WCHÂL1b@Mߪ"8l |t晘_8 震 u7QZ;Sm aubl*!diIL;cnCO%D+ˀkBD٧w@85 mM-8E FUO.yHUCu7C6rZ#ŸCFQԓV_{5ma7տ@] I(|`,Ep앦ۍgkCXtƅA:Ed+OKsq :Xb]yL?-`{6)MrCpTWGg3Fx?ڟg |,e}Qa]VH9EMYG֏݃,,#9Me~-@.HT9̘޵ /U,g$'x %g]q%FiȹA[\]<`-y ly(z["g!2wuc$%`rADϖ‘Nw~!eor;^jc#BkSLH|36w9qյҦݹp)hgηۨ);% #\\yGxUa\|Z8Ce3ۡbzuB4 tImޔ{;R9S?@-I}ib2l]l}>lYCפ_9 KᨓinVvp,\~XU{.f^mhoyw~ `񒩚³@KQF_r>3- 'v=s3`:َހ]껔ha[^k'Q[UNSUYg?vZ2@pWJf ҳ.䏏@ޱ:ȳB<9a@OBgze>Acpn?$ε,uwwTȐlbIN#ha/[&ēq`o3f8Ifkc(4W` ;!nn{a3۞V%'E*]88k`E+m6^.{߆a[f%bd|.sm tn'1!'ǐsr4/A2-F%@r>;/ql8m̪>3kvayzV.#rU1[8%J勌nqO*re0>#,%1NvYыf N={(YNu+!!] \f8Ir+ao)}O|Pz[?O#5++TE=rhh2oG9; 2tͳG/[1_qߛ&2S8p'I*FH,B %?K|l Mj=:K~+]<0٩Ő9Ya_o]_ޞXwX‚x,9z&zʦc72kvѝpJ3\s;-8M-| m68f4qs5 Y2'E:zGtXɜAsF|?aUSK?|5\"Z/Qj+#4N톑 Cb7G>".x}rr'"Xn'1[x&~I( T/Pc j\uV~bɴK]#ya"]ǵK| 8Ϩ:W%6kob$Ц8U%)z߯ŶBMҒNJdE!! ?]ןzQPwL_']yՃXힽ)/$}eq0lw7é؂ӳJx>^F6@Z.6Ӭ3H`z˔ݢ4M4 "8أ)8>]HA "ܦA84?m$f\PgA[4d|4T#Q[5ҺӛDj?ɇ2Æ+eU?r7o Kro-Y:FeH R %4"?_@_9PK /[5=k.1Q50H\[Dy4  `o,R 3/VdDmP*lv)#XSrW.&*;%r;܊nY,v*8؋edV3΄xZ`]5FIei 'QŁ<?16BCzvoFUJ}eJ'v97jʵ *K{*ߺJ U[ g1)ےOz'xJ/}`! S8o~QQ[c,&i3N(.mͽtY%%!LRJDTThG Egli!%6xPZj&C*!oHˢ&zxىE˝:y'BZyf3ΛC|?,Uo˙hjlG*ƀ8t_~QX Y硝bkOC f`c 7ٴV\CMNݞWcN5Y1 Ѥuj%Nhc~d&1V$J(0qJy~}E1u[jz["U`?>h&g\K@l~FdyvK(ì; 2Me7 sHq #dP*, wdmr;­6,PIT gV1(%b]u4=z^[V@ ;ū4/mC1uwmx >RCX|.AGq?$s9+ pJXMji]XӲX #a HX{E(XN'{o^&i$oD-o\ f!W- ufyiM<_'vKhAΡS6,Q)KkU3ر_<$r!x+3*_LbJXRii<>Ћh?U39MR˜QL|_$-uk> W=P6d`fSyCw/}Ia1hhp1rCUo\| fU:uv nIdڸ ͮZi9p~:`}$jW3Ns!BC z|gc%d b|Uj串0yGhe9 <?ҙk34F\eb5aviaO9xdꝑI!,]yl"E _$qQ}|^; o!,yG䂆hegp5?FBYwb38IF, U^϶qAV],? aJ$c-5z_kDy41xlUU|UkߪM|.YF~7 .4:36+T#WK9tFNm@{]@b]t.cǰcQ) 87+{7P<{aHqR&(ƪFBmDDQ!ИdCPXZ '+= dհ•S8 uYЦMXqPD/ujqG4K A'HKjDuG .{;ԯ(*6ECB FW]|7e3˨5J0gc5H/pQgݼ1V_N9 s!vuMfﮔUթdf"fS+-M?f1&!vtku&~;L-jCY W҂*|ڙd8f|a1ӐWX=*VAk%lF);Lcc.2=K]pڢQ0)^k0 ;XBnw ],ux9R맓h"^M۫F#pz^c9ic[ U5Wj'N5J'u{FLFFo6ӻ\'9s ƐCZf(U49e~hٽ?8Օ u6zbhvimVh ;I5߹Wd/fڤV88&^8%YLњ9^hrlbbˮ`^ wHr?߲ oO_QfZJM8f& aϾ3h]vЧoq2Tu7%B\F6;_rnn{+ \镼I  /Z A9g%*C>$@i*f8!Rpl0 ᨋt] љa$o16ޛhf&29Rw Ym΅[RE,7}hf7C~:/ =M+;)nWFrDEGJ,_s' 4HhşߎeF2mھZQ8mGbDZ ;A .@To˞MCH3ݫle!v`DvAmYOآ tDsˡ&þ"n5g9# SL%dғA薧Lh jᕿq#)-P5l~S?TR%ٜO`T7.nku2Q?Yֱ}R: k3+prh  kqmu ?y+v6"'! Q2j,");Z@Wor OvQ2DFGA61?s0\ 8ȃ^x "L>2YyTRBcS&Ã[%$c~C2hx +jqITnY?W.n R91o[UŦѦ1q3Jtt{p{o`[Zp}Th UYSHg,5ܡk6g(X[s6kAtGI;P},OEOB8[P۪KJsQWW'8-LV.EY)ଧ>BP^BVz$PEtw?L Aח.p2Q>Lc|9*<v%>n=CcY9g|9t`K#,E?q;<3_%쮈и0/\dK/86 CMr hUZu. x aYrXI֏ @GTj±kFog v0^=?K\:C.B^SG[}`ӯByn$9l@,S>M'$r;znYA"HcչD)Ԣt1A]2a[&z洯70TgIQ=y$Wɮc"ڇh3!ے 3\}Uм5M+fF-A(0z7ahXwy60IҊm%̷-؄W } #˛P;lT,:aVb”N2-SyO(_3׏077T]-12ݑFSXG5MuL{HuN`!_axu۩2ꑖ(kW /Lƺ>Dʛ]'KkU ?QWᴈmTgTMܜj]fфu6 @nT lB1S&Y( $cz]sQ0׷O7Nm5KcVl}[& %k[p7}*?<3%B)yLQ 1=/EPd&;v`k %:'GސBvj~EBvz%"'(SQ4r뾔.qA wGdqA.AD$Ar"Cس2YoSɇRDq' ([J9yǘf wv+ԵPTŒ  }eE|~B4|̖e}9hI' W,8z/`Se%I|/r HOp.*b:QdSY׽tRƎMhݧ6`sxu+d!LBIy/ۧ-,ϡNz3"uK][K[?FPk(oW8Zj:7a=WҡZV?dГ &gzpa@͏Cmm9%m)2x^C4 %g'ăʟ73VKH%)YntV+Dz;Zacu o:|vICl(/ shA @znΙlv&-S'< FK904V~d]sl] /tRic`aʘ9ܵʢ.lkYgXDAgit qqׇLUb[M t}s vV}nClE}d|;Newy3&xlߊ'z$ u SٵdH&aD7{|nb3@?l4Ya\.+g25f6ö(8/36I.2av0ɢ9,+31.@eCgo1 >/gY+lk[rf[#liiwĆ#i$`P ;Ɍ/2 4  Ph?/szvj^r-[%DN鋀Z7R6[6|C:X%6+Y dᡄuF6SubbYӖ2}k-2́Fh@O]}0,qh/j_[{gzFnbsY 3GkGOYѠЃ5^U 8 ח+k+/dNv`3eɍ@὏fq3Z4G&&ɝ?P\]% CB£y[w:[\iV0W}&B ȩ󒠻4E2V /ȢM`KPKZQqGYIo5< ~,$;O`R" Qq0=~Ji}ǵ~H,k bBCP&[HVe0 !=U~ .p%IYOK~OP+?FpWwK ډo%{,h X]b8ЫkF|-BSyiR;J.lXїٔiɞy8 Ѯ ҶLX4SZvw_H"h `!M _g7YD]+ FʨnL,=@]Ֆ2ߑ-Z|\i<}faz6 jGz5F0ʛvU^jiKZW_2 I:o^1[,pCe ^Sgj~iIER)Uywcw\lQܡ##ogWly- {ܮ&Ht mr#<2ZuS}F.i%e׌ d0g]&>X W =ϟr p|U ̷ٟq`"S;L]:IG R1)1qxN6S h8(ņw3 ңxfǶưG$.O¼jKt/|;;GBh.z؍gA8ȑB 4(=ϙD +nORc*LCC&tqV^D#WޣmQWZ#pxnG(h($A,>sED@-;Z.5q4A0ɔpjPL'6YytiR@nuuewr~ D$E]zhKN] HMpY Zdvo7YlGMT7Ϭ_fHu !qt5┛8Q<ކyТUۓY)ptZKRbxKdIgi"yhhFzV4`ޙ9iO~@p+ŵE1lVnWy<,ΨNJ𤘝|프$.~r]yM4 )ְ5Z/9$=awWSVfG9/Qqxؐ Y9 "򜉋 8)'H/9ei ͐nGcW ϊXAiN#V%䤊v=]VFZZ=-?@R ` t[*}9hJu9ߚ*EfлWLـ\&<)/+Y%:w#+?aԃR A7N0"z"*v[Z;3BkA K? R_cry%cYsN ǿ쎻 ~?xˆG 0ɾ7f&֙,XKFD |E쐄'b(XnA$UAI,͔HeELw &():@nu4ooX`?LkNv&1V)G\)"΀W* v*-A~^2޼_J=BDB.71 Dd޽~4kcaNx- %veqOҊ } N!Mf_Dt׬%TTV{XEJU3Ot.Q+$y7 [ܽ!=V핉QwFHdĊa5(vOYX"p+('#*z~ڐ<{Ee1WWzhpG/@u! *-ZCg^M}9 #%庪95hu]xRR>%C.*)rh[}`ҽ~OUV-8|Hs|^\UdZ,Bbޑ͐$y'0:%E i;7ՌZm KE̀Q0|`l5ߢv "i*4sB<#V|UFqp}ƙ7sd6[/!!R_ k;) FTfrȘO^V)(,cu -F(7Di%3T*k=Pqarƅ v_V}<2wLɝGt;N)Y& *¶#Y)1ck o;NIiSX"m ݰodmSinW]5<`Aكϊz1 tȓmY1C_zX,-Wrƒl*hSn6Z7VoÒg+@0,*6?F/;bZ~hbalUApՠ A^3QeC;;-4- 4UQ͒=BktZ l_Q٭cS31,ǣ0;hPȐسgEҦB\j=i"Q*Q{˵48]T^nMy0@ƒ_&x-Hl 3"iv?(-aֽyn+A=n[T_} | V<: M4>Wsc8ȌJϐ Yޔ.*Ai [}[[%cގB ܿ#4C<0'o)E АU4"1XИ&[t5\;}rDpd/!4.vm 6B4;m DXWk 3,[td˶Z:7SkD+3qpPņN uq{}ͺlUZ6RpcUX u{YuRi7]"}dо.EI\rs3MT} G~{Bow+V mb\4_n5y%q GŬxU"ƒ݊b;Z0I3#eȤ{Ϗ{cl+A^W'4뤨v&'0DgRzmvЪ0 {ѵՉ/].OWuÞzږ%@4%y2>4*SñjjWGzV*BݞI{Z>a̶\(7ac~4zf.G`s]!t[nH^LRh~鞤_-m"yـ,U3L R D3lG\3x:E*ނ *,y?9\T u0_v"u+aS{yF!z=$--zX>=ÞfSUDZSjSV}r;; ez>xU&y+W Ƃ|ݓ$tfIiL{eJ;EkLIpSAw"/a<Dvܬ+J%`Np?KMn)uv³߮> \HF&["%ou!!ݧ3BdZ/`=dl}a8r%?q]%P{S*l~Vcf^&L\n|j%GDFӥ5D<zbVA*Qt/_j"`Ͳ{^8uT!*57j2L6̦6e GgnݘR~CC%i_`8:JVsy*E 'U4"Y[c~qHɷ ʦ4y 94ǠtR,_;X@bf g§UZ&NH"w 0ZJN3qDxh)M`*.cx] \ _S=wÔmUI:)O] 4M[:_t@,}oLuUTZ%K"WA:7P"5n1Q50Cε!JL!pVR1[R;JIoU դrRw!)2u Zr5irAWu5O8lۂ`ˆ@kX'6 [:ƅJFYЊ_eWqy% 0, ;،xEEZ]efsN}S zWDs8njBJ8 Q3.q8U+Mޭ|LTqebsJN=O G(C7,Xqgbȍa"b#EU:1%*pZFɼ W=q*Dwe;)wXhs[;A;`KdHg6 $)c;:<ϻ1E]1ޡ v}~sO2A]2*3HxI >Xp%ٝGae{ģt% u~Ӧ79ˌcPtQ M:,i *zl{m HyR"aڰkPWh!' /E%k`i5*H%&J۷wͲ׌qwnl ]҉y:Wg NͶ"tQɢ8̣ZS`lk{6ko ao䖼LHJE#9sNi;/zGNc|RgQDpUK{jAH`Û}/lhVT,;I6 yaƐnx"JTؘf?%h YZp"j`F΃k"ǝ^B~W}HZ2B2яݱ=s)W6Nay q}qn|{\qqzտoqV=Zjhm zF9e7f:7 a<쏧=ydMNU<8puuں1" G:$qj*{ħ}NX~8)jQk,'O=>NaGwiߨ/ 0~¹D}Ʃ#%ћQ&Hnդr=MXV_y`RnTh IC+FP$\QrUi\ԥ~ R ,[|בzwT5=p[,h0uO^`aM'eqa-%]4:9's"5mb(.iCy+U< `B6_~lf~ױiAU=͌eΔXH:3WۇqYAƭ/|gQi3. zx#*zpgcb0}833u8G\t \<г@B 苖=Q_Ǣouǂ6FqFo*,6וLvԖNF:6>dVg/Hp 5ϹYP-@\4F2 2*+!4,7է^W}ڧ#&.{wO~L_I9_pYu8;+.I *d&0lChg]ʡ@l=w ~gZyAg-Ҩ^􎼧j|)#x GUw0z$P#vRc/ nH@s=:q޲C),T hSxN7pEZe"r Kqxd*"u4PeFNW"|3"!V~ B4IV_ 1nxa$Z ;6)8:=K̍]li{ƃ?D4_% X멻WkTG49N^&)&m0ŵhUX(Gd+^|sCYǝk#DM0^d='p)-(˯,8pg]SqG*}.21aTAN}Tʰ2AO;$!zrIuSn G̤xi-C&u߀+7DyDP:#X$CŰM5A4hNWJgF8obW|wjgf"1lƀRRZ:1O$ܵ5g}'c\Vt=NI3*;2;bO^N蕙6}q 37.&6Z0:cR.?Uu]3=b~%b{J/IgE58g <وaC qٕ ⑎$ NlP=R+ue9ZSBbW&F)R|uz]dW#ސ}׃eH\B sNߪ Ɛ= fKƵ2v﹇{! )ݰ t0i8H<,ciJ7_Ҳ<{IG_,v2Tbwq{Ү[0Sp<{+ښNQ^TK*Y b5)2WݮɩlzhYu o$4c& wϑ\oQ\-G-ۮJ?Fnn0K^;u [ymhB\GQ$&?>">ʽJ݇s *T'X{8ʀ|K` } C콄{JH1ٷG21ֿU'Xd„2RRġl&Kt^0~*̺HCIX׫f킄uݴZ&D?iw?0:CnnFe}dZH+܁Xj Cز%xLME<3zX;!謍MaD<\P\ω6}yh 2ml9qHJvX:UFw%Gn^b0FLlv7"zh0C[yC׃On|Tx!#h^=Fks6ˉJ|j/;Bދ~aͼ5Nxܮ`T 2꟎5R/Ws JwȤ\ϡhW͟@ak>MtOP`"B4\"DUa9{ t'Y~}B:AD4g'k|I 6`>7bѨ[q$0i>{nj"T=K9P 6f⦣)-Hlz)de;6|sfZ@Ϟvi43{qzf-8& pg0YA jyGnIYĔyZ)֞r`/Rfڅ~z3|\de!@DPQf{YAҶ>T%?_!(B$Ϋw*D3yR~z!-IZ9 rTsSLAU\aOuY&L! kG0vEGpB+س(q{\b5º),F U; &Q:xƻ__Yu,7gb:5q=l-0;NWEQOltD6y3Æcz剆 =diACwt2JpTn{V_f!oM?\U&hՇ+QVb3yT.!ao!q"8 S7^Jrhqiz@.")%>K~SCai.0ĥڛ ovY7-_|H Br&t5+WdLXfaeS=;2ܙg(-pṚMm% rHa>o JQLwa:tC:@*83YokE d] lR &O9Xqqu8vħ(K!4ʻ^52)؛G+ 4$ً&3([ ]4Q׾P OR |  er"g~`w:\KP NSB[" !$$7dX#f:g2}qvG@轓U?_T$2, D#f69.g:@?v`)D=BdhF+Et] #`a q{7:+"+ງU<>&]ç&p_%p}L`~_ٙ'Q*oz}nYJB&_⃨]J2^ٟl_  ŋzzz&YQukU/ĮuaHԢMID,a6|7 t8sRaEDe'JacA BUAB  uCk<1˺I#$>2siաvq 耛ۜ

6f7tw(1]rI&]'N7g;@K_W'tuóP)Ĭ[fռmV޷i: e]Y@-@gdE)4,:u<5S~Ě"&)J1p-%`H ?ɾf#tShMY6OՎ< ԓnȊ{^HR$;kd 〿4ϤX 9,Wy2+ċ̩g%>7vm rH !l7%-OI83]ŝ6-a6p@qp^zj38JA<3tX 7E^tiֈ( 73, uMC7 wGU}!g 25j(n,Fi!;ЩlRUY wż GP(.NYͲvp )_eI2{3sHfrZgGiŬaɽ̰ VbUE1эݯ{VOȲ_ŔtC$Ȇmk)wj4& I֋.f3MuRAtM[ex|jQL"QɛVOj) 7\C 7lW~BԞ@k"AAB!Yr`'^bnA*ofEU3p(mU٤^!pLτ2VqSdOdQſ%hSihtG:E&$G7)Iy͛ݕb@B.@s(t0]ۥ73+:dDcVݲ;J!&z=t7yŞQ-Ω  5!*0trY% _zk;NǨ Q(M6$+ѽXt>FA+oeLҎq$KHS駐`}ihnC!f?dX,j,~@d_S$ D+'A(@8Trj G~m'%cs4lEd>`w$FK_"Rrk':EpDj[pH߻]ቬ7j \T,=BY@'T̨*Wup9 Q3?j hԝd|J(p)VcJCtR0ZP9k/d%Yc.L+4cu$VlLS' Z@'y! Ž>25WäǸ»1 8IČ[5gDb0N *8TDUG_aCԸw%E3)L>#l` eDsD'18$- ݚ%|N-(QL_,?U;2U(!,v!:$ kUN$o56GqjerE u>tҦ&Ȁv X [0d 껆1qm s=U6_1Lx/)3{_հT`]SMwűhMtR//fPf:~$}HҨ'jrdaCR]ytkGBVd vTjgMA+-vԞ0{KҭɞeQZl쵽?3meΔ30lR&PHRaُٷFO\.?Jm:%kӛ" ۹ȟ´_Ӏ%(;IAgdrL-MpXɫD"6>Y)GM1 Aʔgc~0'yE'v›wRY"15@a\aD|#G.em&CB| ށ-uۚou/n&ٖ7f'ȀX8rKێyY}1z ?N(]JКHU~O1HVg ˫g+'ri}8 gW"taӭ{7SÒ]9۲htQ)^MߣxI4<=_)psUTv$ XJ{c _n'G nSEb H.jk6%T͟.9yZ'^$VuȏCIc ՁD@-#ti?xj|fp:xv$_N5IF>е[n풮*"hC9wIM{X ěۧtU:1Gsp0v|3Rѱ"!(4=ˍC\6;]61%4O1)}nϤnH6- dg#>ƥSo`eA,>y܉6PvbJ@UtA/LUf=)_@|-u3&Aui:\O'*h > ˉ,pe3 12YηTCeK_!eϵ=&dn [  G$nXi/6 {{|#ݔxtj?,Ƴ[VS FzOV#0kهp.)e|X0Dv*VmCT (D(/Z8 UNAѣ>}gzN  s,MW r@\=ܿES*Yb :bLC`:5h1] F]V!.ѵl. F =D u)de VTVX̬1L][G.dF8ԠlYfטRFO4YSώ p >q{u*6v@]*&d59rJ2(E D+w` pǵ__q?0eK1w4\h& 9Kɵ]h06"W?8c\}B(^Vcb ̐" T=[ '#SNgKi.8ɲP%x"n5I^fAM27(Ơ=2xŃ#2d{(zdo/`|[U 2h %$< Qϻnl ޿s6DJ}o vńAik4C85wy.1iT(Bb}fǸC;:0: :pyXtR=.G{/XacZEϙ@3m1<]mܣxA#=ޫ'fޑ;S>D#k GoL%J^# %_b.ZTLs2~' e>M|FV5ڸ! G2 α|%*0 r`|hX9@ 1 *pR4-FkmaW{FY%JLĜ#dY(y&9ݭ }i&/ƴ$o/{- "Kţ,#} ЖoEk>|s"wKr dLJQܜ,N']ٜ)=EF۳uɛtL yv}e2m$؍aK6~\[+T[`S"tCU]MmZ2j@FT3n_i%uL<+>7B?2h 7a+bp6x)֕]#YQ /;3p%$/ĕgbQSlghl"OuS o &WHk`ukN}v!lR<,:^è`JepE+li7r4n"[xY?po]nҴPj^}z\.UφJPOw!'a 6%-ҭF{]ܓKt!ji".$l?j:h,} $,)F -E)м+@CmN^ZjΜN֌t4˿y'HKu6& !)d; m:JO"kH? Vˉʽ-[3UmttC)ga>9iE' kOAޥ? s%Gs#Ÿ.J=X ?ScxjA&uK"ȷIpIVө7{CӅPa,܉)͑yU]5HP(Xdu5é@ݽ (9>,oYV-G\74B$4b}e5/r|q}ZFD;Riyҭ Jr=#q#* / AZD.*>Tzc%ab: ᄗRkULJK4/yaIPuq3ڨt\6t(.Y$eT(ZכPȼ!7Mq7@7V_`%$}Ӄ$OjoИ9E@Rw$m$)z;E <5_ȤduY=y2ixOc'KUHP>{܁Gt]ߌ`jC>z*Oղ𞡉aa MA >d@ه^*xβgLn]cg+BIq]_CzRfJl6q] t#x"r!GcOѭڳ3KoNʝS-ml?-|X3Z` bC>p Ί M|K_RXQȝBJ[Ӛ`r!c=([8OFhARuۡ: A-5zƠ\|H$ldGόb}G cbD_c:,~wxCS#Hӆ`$Z+XI$εNN5Ma޲_Wvi=P ҧq$Ũr%37]g,G;üGv^2Pc@\7밗 %zVPǚ#3,ݳ'P7()'p~epRb bM<^v x(}Lưeya*]@- $dk^ dJK|@ءu J{u/B[-%CY`c먾*Pz!:`6B~ۦ]QUNw6_Cde4'QB'8+|e"a]B~DY gPtz̰ <d^T40Qq|:iEdaMsUd`]?uAi @ϯ`OBp)}kUEH`E8vexY.H*CE kq(*kj_<<.X^UϏBjPe~)% XDM`b!T13/\s-iB鲙A%Ea~T%N"wI d_c d~N 0jgY/] 64pZ7]h /iFo+3s fSCwǠ|G!Q"L| S?8Va]9J%4 wJ>Kh;YJ`$kV6^2Kf˵p'_ qs E 7N:k=[} )9R(2ӌrVWtYtOvdyUW+`W'-9%KW6b{*GMδgiG)G^Ų/KP26'Aɯ8wH&r^?̾\\) DToq(w63F+"1n>Q]>P G 7,OJ? a8qEYe9}CN86vfyvFs[]7֣ ' !y:IRkYe^ֳAh5rؑc-1>__HLtw;s(HJ۫g-R5 M1B?&O>X.Φ.#dSۺAsq3e TZ>i` [lIY-'&X1@]lmfPh BcK.`ړ[1 mQẀΝ&L%nu}3 Pf_&tRca6v҉mLłf` J)D}Mp'-௺$DLmL䶃; D$Z$r P&Ng"C8Mh})2WW#XvhYk&w>u H#=|9H R+zHu!Bo#RNLD4A:x?;l|}0`f*}~M5༾Vb .V:U 4W|F8},JD-atWTAWF/09GϜ}Jz4% rcAfR>޷IMy` Cv{ is_Tܤͣ|,7#Jjt}I[3Ur^\g,8Ka0z@ bp'aI}Ԭ|,TuJ>*F".#'~ƚ9YQ`c ׋s Cc(8L4hg*mنc4: O˦!4 &v틵>S*2]I Scz("1kU=YU-LT.!H_pҏ6+z[қsJG$m&1\3lzb'Ų/(X\lO\_镌{p*N7eh"'H6P5PL86I̘B8mCб܀%"]1cNXٖ x,ܠ7[LGn0λŬ|"Ϟ uLr!7ow(.\SS'cPMۍ‡gLk3#tҍFjA#հ:Aj71Ux ;H]`.,zg*elbkd6O1{o}h%3N?A+4k^Q`1Џ(p1 |p(Ys$Rx][HY*!Í]+,-Tg4(HStkF:HlFCy)xݏ~a69*={~;%#GOZ+H=bX~"sȰHob"iYV>Q]qw Rko+RBvb7;ɹnE] x`M-%)``5KnjWYz5Gsn)W#Clax6PgIɌ8q΁{)p~w5-lj>36^J!*$Ļ61@'Z|ϳbTAD: iCjP&?.BЛ.OŧX)C̐hc]c1#s6.~,#ObT 8T\zV݅cO T?Ҕ|zjFk!l\[N+pbZ_oauY5R/֗CÐΰX|Ihgj8ڽ =!*5Zsׇ}&y|MқH+6d`'G}Ew#sRabF>ܡ;imbrb ! =_Y İB26.ܪ+3,7J޿g:&4T8'0PnBRb7 # zX;DJE];)e!XBՃچ05+]10gz] ޣ?T2vAuIfh.sgOZ RA&-:SilHSkҔ|RXg}OVkڵqeWfGRUr--!6 %qES*2t%~Ile1XPOs(KRxŵLPM,1" ˶F|]xƄpڳ唓W'Wq 6+5|F{AMlF5fG׮k4n#ι*ŋmÀ3rC_L_q=bkF&T^w^sv cݎC&oZEg%#$E&,g ./lPK?Q~.`bQ4uYI$@H,=ԦqZRyԔ`"09q3鄡zzmc?3uDbŧy]`JA}I'x$z~m3i5X 1+UcqσYa8\^M8A eaE(F[QMҕ+)4n} P$[ʼA8ibپV3c̄t Ndh~`~Y'+e^k|ۿNQL9+Ƌ"im g`VdO((\x̫/CRSkC_ԥM) T-n{`5W֥UHo  )d"#v? 1+ρڔ~⑕lF0>uD@P/cN#dйL0Qx ukݤA]cY"aݧ`!l+!{hõp/ jo739Ж4$ͤےT( 43!^ɯ̤ì&@\J_gBc̃]̜s/4}Wa]Ec]s%`{?zI"iG (4#8Lq; Y 쳀'W`"JOt5 Bkx) C֩WnO7jbj=OH(q-OGwRVC/뱕Fa@Y0Co4fETK˼SG+;%ٴ|!Gs:l# %AA.Ȥk'pQJWvI=eOg 1 !kEt`t#5-{U;_EN ae|ԧ Sb%dl7AtL(.uiI{F5j6|'!vPJ1LPY1̉@z Xʋ8y'hLKY8\+l}f2~A=KӯuqVņlįm(z^㤳,:xI#Վ8WLF]}k7yCM ?Ul sA`GW NiA))ZǓp?o-,4!({#v+mr^{jjvʵ'rsK(]9DElk3 p \N-e±u/+Ѩ)|ĆwCtt*1G%:h\5}AcOKd0Blqde2xwQqτΌbb"~P܉%}ǛVrC{ ȬR|,HW[ch65;($n,g"Ƽ.?U%$:UC -,xs]+Ni1<&mW[Sk N4_q lˌ@Pv"Z21xMp6IXQ?\fv\6R7_c21@23s\4ʨs#s0i6u&G%RsFSy&VJex 5:%j*scĭ )maM%g4S[RggMY}>)k9z/qGb?ղF?JKED5ETg{^q[O= V ]_^"89eu~@a#9 _ɾ017~u?Þ;Ƽ>:׺ݨ:]ES6_/"ZU H5qO$?b77aMUމ|͠V8irI,F1Uwc68Reê0{ kUPf]mm #{JhÓ}\I ;oU/F@u 1z9Zȥ=u劒6V:Þ]fnqtUGNiW>7jbVKHF݉mfUxTcgp]WCaD}*(c.X;O.Kӡ+ D{&>o^YR- W=y@ڱ^_!;H&2N_DDNV?Z#Or씸NXL[ "nf{C~ipFi1I|Y\]X;:)AjzuI4]FU.-b!ڕ};_P'VDݐޞ.H^ģK퓢 XG F@*"+E#c]T^ @>B1,B9*l -fme!(μ+Rsu/(%}$&=7qy3>0,]9>!3gD;d*w-c\ϵg !֠ 1TۃRY+zP峷T]TV~~]<;Z"Oroz:3`Q&A3034]3YPf)-f.D2?~d;uD(R 06Pv"4Tȑ0l=cBT-lQ_˧*#NJ0ݣ@/64xFqVrÒA*0hY~gGܡF/IP;Q'g \UtkWW.E^]tsO626%5 B?!fQ֌ $6]DXv8K[gVj̤Q+GyŠP+:h#< _#KL5ap5@J¶*N0~ңX*LsY>U[@ Pkif _}mTР+欵^W0v q h O}Dm#PY:紨l&8Z'j"%px9b? 7H+\Ix$vӢtykFqR.evFJ͹H} 8\)uIpR9EGio@Lj* Db@>29uk{e. z+Ӈf#!yJ:c?r; #qhl9ug;y)7NB ]05V9qǘ:oN=Kɰι!8Wy N$ߗWA(,1+kke Q<.E{Ѱrw- ɶ5D[^ N$CrR2+b`2Y=VjW/ ff}vU0f ~n$P8O3l }mP8npb+.֦#,晛6+J n"a>)ED/㕹5*8Ə~C% 47\ssFaqbO ${WkII[ӛ:89-C쎎ӃoЧZ 3K~Li=X*iٹ FI6jlR ׅrq!l >S=.Cu/$-lð 'a!h{z1P*+)#xd F%^1ZiaJ yʿQۉ aihUlvSY@cʴSTԫi0KNg]:=(J^UYپ2O#XX48cp-]wg7\ΰa_(8DO:ͿktCh$cHz~߽\+ [^tJ;cI}^ť0gN0GScZts5ŋ< q>!5 k@?c.B*4n_&9;J tFiv;WY)6Rtia⊩/ViՔ9%{fjIyGGp sŊb;6jH)UpfByX8M"HuZ/J` =˭b@2VbsDžx2 ;'wrdݬx2d0‰jخ9 )(Y5W*"6Eɚ*)i]wUѐ=!]"oCE|y+x֧WCLf dƝZ_( o!HzW[+9b3-h?J@*ag/Ҙ@EGjyU:=slI9%žmi0V؎i[A}nM8IŢ2AQ֘tw7`9;;rzyjS_hirg:+q.L; iWStt]D]}ZBefĪW6&f]7`?mB }{ڡaCxX̺ޓ/3 PfEABaQEYm@Q,K)q^[ū Xh$>rUH ($T_9imQI+3KZ /i=Bj$UC= Ez̀]z"nBbb9 k+ŮL z XxFFV XR %bt$<,7G 1"F3 K؃ s11_;, R^bh #JYHYUE#TN 9eq/>=`}1hp~*AX"Z\D Fp{=6T 'd]m)6":3H)Vt]F5N[UK표]M$Se*'$<{/'?Y03e`-uyêl>8)p O}puc,ɚΕP,˾ ^+XYB(1?n[13nݼ{=Ҵe){FO'q0t ̸imƑ;O'[iF#|9ΤF^ S]l\?WӚva7?ͧƂs绥mT. Y]zo,dQToue-ʿ1]a/]NtUK0L`|wSODKoGjH|i"q!6t3rro]LE)Bpz/i hbCܟ.EM۵ Б9+Ą' m]e#0nfb(JLd lQ,B!o'%M,δ:йwJkѺn w5 [T{*ek<xWL"xՓ?y!VsI )ES`v%FC\e܀PRv9Љ"JC.U8`YȌQe3+Ը\5gqSꟄ,ã~V zjWѕTwU';C%W/A 0z sJlx릃fq l4SK}0.$@OD@MLwSjaW8&o;SXNɯWN&-HO5@%9f#ü%$X!&rtIY_jUSፂMn%SEx\nu7R%7} dsH[614Թ(O[GpD<-o734 J׸Mny*ZS^TP8w[6ei E,_??9gU%EmV^ڟ2g&~r ,?Fxq]>LrZzC7%UZ vTzLm+ Cއ7%Em)9LUIN*uj $. d+B .n*f M%1vƀU`ئG-]B# 'f?Ԯ3ԓԸ%: P8z"/ͮM mHc]V/x(O#'0ZCfˉEdZ3NN=8ǐ:HOl⛵Rsѫxh W>_2ˀZ gݚ|nS<=t(y~β"ҷI(^Mk9Noj תNڭ约(]yv^Rv5*sFbS&^J洰j 2͖1s[5^7O|TW(\2%=/̯qPԀn*Z }}<{\Hz~V! IQ+%D su!K?bv7 C1Y7DV&݄e_ǝ [~B^r:ʇwe!Ǻ o3mX=\;ngVz8߄d ]fGTV#eޓ`7ʲ54}%YG< Xڝt)M.8Y.Ʈ2Ф|y1bd6OfĪE%4F -V!ƭR`TV@ڛ[H_\mh$* ~p`PH s[3}C,ҌE m ˺D +R v z!n;U(|5 3#0y^/S$}x |f(a+,B^5nC؀ c]M:pa +L 4Y -rU~-de߻A0mO'fzQvt{ &Ե"E*$ϔ|}Tڣ-}UArl;KFݞ]Cקsd:l.[ڭ*ݺ3ȡ(jC(~%Etoc؞9éʽMocnCJ}Nn>":ur{Qya`Iya*Cځ,F?4pv٨(rǀH3 ?U8\p_/Jov(& X\`g;8 =A\fʵhZ{c']% LүdKOzM[,/)E 垷R.SE f`=)vԜ]&.z@f lz_L*n0*`_wI)e1<"ARiNG/4ĜfIDhxޛv3̻}3}$*1f.|j !װ,3,qCn|2NY Dϴ1wrvqdԑ8ѸC%\x BW9 ͫ`ܿ`@;vOppi/* 6i昫W_ebxOԵ[`y,[I32rHkN۫: 'wk26mdDe|nMAmsFDbmM/JnurJ*X\=k2QS(l1慚GysT&|*0 tH{[Fe0}5v|8k{*?hdwň#+͒& E҃51`hC%?d&bTSo_άOU0XDRyszm5 p,Mc>X}zKX b'yY`$>0¢u5PЇ#ԇb=!%F@4$٭lq ?u%ʨ ݲ2!S&wJa28A@+/2dEu| j,I"']ϕTO$@L  Z6 6c&!ĤX^ZH&tS ןOSܖ ֲ2J]d?)K$lQnA@mOE=ٺ%%E@;`[@6ò(v9m_MnEp+p5\"Lz^NJLTF,p[nh`ĻXe']Uoit[AGpg擴`f>u&{޸6f_UnxnkC_-nAFu5 )JidnFkX֏o/D@ ?Y>P/Z!_ڢ)2lxC$/BzC4W;(u#P}Y!]:fnPځWXBbķQW>܆fy b9Gqۂ@[LJ5ya,G21DiLYkTT{E@5K^/B:"QSn2kKvuVXnOjKBzٽ͔qq$[U=:\=]*&6d-!cC\&72- x?^Ammj'\ %F=宐] xlgj>9UӘ(8ƖlgDPNi15DQ(> t@<[R]kdr^ ]2Gh,CR.i*a(Mrآ8K"49&Ǡ]/K[0g+'HdUvEf o`R 5+VЄ[&zC1󽙜Spau2{jewy0w?63٭(m,qc{1sT4;svHikO >G܂0]9OjIhKLI5ټ6SQeio]Kh e iۅuOJ=n&J!z_^ä.}C%0`8 l;L?`iMvf'|<R$^~<(ȶ_)o5më 'J(>4%޶OGs`Qve;~c1Otj_v:'] P]~ kq4䟔ѻsWb )AcTs@^Ǝjb6.ezYдIS(5aY|v "@T$y ҢϬyUUR/Ѡ%(C[oGLEtDbDf~Vpw>)}NLF@9{b[CLL S(Y _"9.r~GB!{*]њX z0'0k Ec. QK1̯w=WUH$E'3-*\ .=wbYHj3j"˂ř)x7)C0uI'0q0dl ;@f"ӹG}C=bH#x=Fbd|+]?F8a_@"2\;4CVn~In٣ ).Fj'[*%yK(a<}cu$N{gpdH-aDp]MtamAآҤg2%aw8!ZњJBNk#wG<@AdtrϟG݄fZy΂}$='hPD_ފK{;g2ʖZծǦ%W0$Y,D'ZVQ=usաUԫ #t rckĿjEߺuo\? 2T^f`m`d豫B  =vZP*+C{*+}(@50OmIat$Ӽ/o|g5!m뢊iʜ#9@sI =f8'w{pSƟ"f٘mpȔo΍(H @pXǪ]qQlSH'{8cY=UTSGFok,Ey[.!nϰ(L99i׭UłCKAZpz]ȡ!`7 W5Lذ[:_X85wZPf!U v^`\~[Xj5bz~jVFܣ9/z:J1 Pw };rvңNBW=T=; yL:r I4zEo5 KzX=IHE&KR[ކ.6 h PM^NJ/ͥ͟9&:bxb&~\?/HSiD` M-(L,dM%JuˎQa;R J&pWjWo[ _M>$;(dƹ&Na(.pF ҚU6^& [ mG}?&fFpeEVIA_%cђOeleװ'K`S|CY@a?طʢ@ []1p~]׌nX.37wGmt$Vi:2$'g '$o8wn0s!h14.ݢoKuw_np憜ǚޅE.XG N\)Ew!_ 'e.cpZ;ìطN/r*v`;q9RuU7=$=E:hg6.KS..C=?ɃA>Hw¨x =8;B^??ŘEwyif.8Lp҃ٶ| =i9|CS1eзG^e83V0u Hc2l $LduA1X6T3`Yz!Nbwzf; G}Xj 0w^d nEh"iy'V[8幘ٖSǤ76!߫GBCg 0<./kĆ*EJ< U=nqUk{l0fbX%QUCKI!fi#C1V.w H{gIL-G':ḠlQYGcU{|.$jI4iS[38Y PUތF0+m9}oԩ'lrZφ`b'l!mio`ֶD jXnE,HxÉ+׾X4g -`z|=Z/yu*,bdW*QmlїC> 8zm/nMZcsYYQ4&q6|WrگwVÐ  M9C@L+jTm y$=W]ClLZ!?-()-gTD`*!'zYTIHRHp6J&-1'+uF$E 19٦a8Ual0oenQUB;u>ien021:;/")NQ%mI)f{Ӯi h&ZvZjh>jZ<8j{)lr7^eN!VŨ_\w~E֊Byz繄CDEM W-Z7kU)3B[i}19iPĕ&P۬TUЭ>e7?[8$ y'7,uI䒅$ UWJWֳ+P+8 jE+oDF:IP.KܒI,->BnQ (af&{R)7Sa[a!ǻ_v[9.VI)T4]Ty3JfGOՕ XPWW` -d2Gڙ?/utl1(fH°D`[wkrCBaF50-'E5Η' 3Zp*pK&oVctY :8jlft^)Ɵ%t}@+`[&\~)fAҼ+^! ۭLN'n@2xb?Xǣ=u)nEܛ8iöBo7~rb!X߬9V^bK7t[jq]EbSYNXQdb-[["@sn0#f3h65#xt#E?Τ >L/~=⎉*URz= ):]xC`F3"`S1T2I'EkO^?7%5텞bz4fp(Sg|`$z*^ՠ^{\#T׻i"}-@ė^W(Xs['<=5A ZvU>6.eyu;}J*PeEWUEPFiu栝)*|>w;6'r ٟ(X`Xq,S$#1=͜LpB9heQ[hQG (rK.{m]v8O',5 %4!%ѶYpjg9ޝMEXq`{$h.|w{u1;)BS(~JITŏI]wXcX}u\ݘZܹoL@-!"ʳ/Xrl}H/!$džK1 Hk=&< LR7m5r`ŲvFzN-E^p + zxg7J!JvO(P'Ώ z6m -nnf74t ,"Rk'G[}/L:j@.SѱD~MF_;<Ϣ.$U /DWh P1 +'gjXMe#@zoIiz>~C1G$")LSkaަ-"'$hTU覠1[xb9T߽]-bKk/Ok` LCVEI@4P}&ՅxGymXSb] .<)%:q'궴TTC evaZh7)xg-+]i) N8>z0HCsÂц3!iZ<6(Ħ<’wn):hdo9d: M1Ĝv9Ž7ckR=~|Jf!ˁw( NL;zNoqN$k-0EI4Rg7vN'0Kɦz̵8%fVB~|h_>Ep UQZN^1(PBo([ 5\2K2 o'gi2lɐ1rB=ӽf|rd8[7"ŭ !k X'R䡏ڥ N wyb+̓ ꁓVwഔKsyyȰ=WgAx/UUJ_mx{A,Sn+ˍl j;lH \p|Huˋʝp@t\``l4Xhطxx3S,[`za6˕V^AV0̷hSI-D>~5J%=MKoSM:0HMO,Ņn;zhnTL[S){ N?TV̕N-?pcŞjbcog`ՖݥUwNqRn6u^0:'unG oڸ@Yl'IԔÂx OxRx=p]){Ew}1Np A W0GT;*_$TQH[@ [JIjܦUə̬ȟ}SES-K8Ⲩ1=ܯ88yZEaB.S 7Rm( .Jb `ey)#g^Ex]( e%f 0Yn*ӯ˔ɩv愊+]ɛv+˿jz#W::1bfY%Z?r~WyqGd'V6Y)(ʊ*[#/(;AQ1WeRV)y?֡xd<_>W+0b ѢW<9 4bzb+рb'A\̻6|[|X1͠q2aP;;V5ڏ_D!!K:tvwBeޟ}c:b /9-0|(1/`lͱۖO7 !jUqy6-9W9~ HEdMAi6Qiyq %\#~R脷!d3%Ɓ]J!+Y.Ykl1;]KB{F}As&kސ? ^GPZI.ZŠ*+Ӝjdqk*1ՅONYO ة@b&w%}'S԰k/TAZHnuST-lMrNɲ(H]|>s yU?1ٟ/+Ckh9'z"2@`ҝHotT}yU,``X({] !owE #ᴑL{s0-8!LRس=aKr} O7|)wy$9RJU@FŗvF :xk}'!Cvɔ6[';7cBչo?KAGbDo K1jQ?FUE33 )ΊqSYnÃ;<6<RL}[CJ׿1qħ3wPZ?Q؟ZF$3?5j ?QզsYG&`NZ@35&#Q^wHpLЙ:X_CAV4oꤜ>T5 ∂[HGwsTmeNork-{: r5AY exz؛ox(xy$jtwEL Ul7KYAH#eog7ͯX^]LEa8Fm_ϲ аև~ 7uiD"bLY;-6KEHn8(. e;"u}FtyG` $#ĩxYےV~@~ }U@t >ڔ0ޥZ\!n#$yG-/M﬘WGtfLY5^xG8 ^(e[&wVӷ؎8Ky#Ro+gv {|ni <q͝d3e۔`lP6&6o}XN7} C+^p=c0B,1u+Y"Cp;T-77k#;"@o%KTC"VJcs,_pvq=m1}2TE< 'DP)GDrb1_ ?a@0cI7N>x'cѢmwoCcA_;QV|X;3Q@( TBOMT"Åf6<)gRfe$^sx`nlӦ;1smz7MΓ,^,F:vϽyֶȋ?GۓJ{7EwzYw1 ?[O;,@E(B`m3][E z;nNgkk}_Vd +^Wq6Pvv&=~Ԁ̅ʴ'k1U]Ի2%quN{.  JxaC#`ׅ1=LԦ}>I9 mJa| W8y[==ka^j<֛i.Mо$&+;?s{+EsĮ̅)iN#X;9=3KɨWP"Me!~uyI$ڿ8U<=Iũo橪dGF!8e$t1E7-@<#LfbxQ<=AHTsxt= qΣP[0d3䵧tYWMu&i*U9jƽ',1#L0b5ri:{yqZ52/}yBذ# چˆg02X TFlD3wp2m;0suѤE]+{;Y\~a =Av  54;4{OS3hݏ9GCCycn!XՖc ]能R*=P{MefwgMס<םhލAqA6WH9-`Yݥ5iuzݔw{s }YaGEO3pz^|ǀqw$Z/j Pp9㓊%R?xGu&R2Ml?mۍJpcrd1f{`|x (3v ][WBRn5G8ìvLO:)B OU AJXmgZi8$28}:Zk#@ȭKA!u?;r#y5[~f4zl vd\oh*on)/=?5S80u{r}Fi-1r-a!V`mIC-M$`/:' W&5m+vnG= @}QSyh2'k퓈]Ywp7eZِ؉X(N}"?51at!r F@/Zԁ#}B:)1KU~ݯnެf "!A$PK6 !(<88^68l,K؈g>.fGa5ÎA8yM019uj 2_@ίf<\B0#ԮU^ vyBRq[þH2Vn6M0 'LZ5ձu)*#_;LejdKJUbWzrT6M:VAuk`)#=att l9D0k0m8nxLs QDu $.4bE8Ȩ*ߥϙy^ 4&O UjyՊ-mow,C?t/zQ[p|Ry3ٴ?-"nO9jZKb5T`Ŷ"1w2׫H(x3w1\N }SzY:8Bc@Je](\JPs7tu:Cx oWq*rL^;!O~& c<>M&?VY;گ?Y{/em&?b98{Gz $DÐ%XuoŴ6b+}~5}}4  4/r[tv*D~Ƹ1 NU Zoq5 JDսX["1-^:T@B\Et>28́])}>vFB9ÇiGR{st$qFDY%5>#4yd_[4!kzYHm`}Ut((c׸NBaIaKsY|O7=A}k&K=cd_p" a`i7+a~NAJ/HkbA{F+Nu} ,cz[i=s9[03p4 @'>fJIVS!utch^M6BAUG=+_*!Ƅ4_TV7w8N+@ʵ(TKAoVjm/χT`IK}RX/#KsOQ *GUOYjtۜU;jOۉD-5T!2Fx:Ch:a{͵] jJ #e(\!=]%|tM27 ]۾9h"aC݉!EkM~&_.-;6  >0 YZspam/data/germany.rda0000644000176200001440000015335013440250504014261 0ustar liggesusers7zXZi"6!XI֫])TW"nRʟsef,ť:~ _Mmk*h&]| Vcm4'ZMy֝8^Ir /D~̬|q*U J0$qOC(0 =AdAy 1{Ex.DհL $pSβ[ؕ|<wo7Nw*)vY&\n;[hYcZ00stft*dJHsYhx?972!HO͝Imk% N\ϕOF":ZQl 0c}@ZK_2]Mkbؿ},U\$c}$קW4n sX.Bfvn9<у[JkF9yo5Vv+GwAhԬ3 Y/}F0IǠ(kԀ\ѓʌJ8ݜF8A[OhV]e#BE`io^ ؂ .q>Wd:q(<`k$ܕ&EAta*Ht\3C؄Fg`ܷٺ[뜘A` N6M ?toyaolBS2> u3%AE4yep;xqq•v@Q=K$AH=o]\Zgl_ւы(5H}WlۤRL,8[P=/}#kDT>@qPр[PNfr,zF#Nk^  WٞYax~7HqyK غ "d"ԭqjK!ҋ%?7N0 B #1)V1ގUUJNj6:WU`֎ģ ##M0PAv0WuBcK9\{Kq|,tk$b.w|Rg8=#&4!񍩸\-ALF $Qh'/?ʹ}/L,/9:`zfW*QJh]RMsBbhxՇ_~NL LG&_g 'ow9XAbwB#)pͧ~{gkY=ůхYmQ\ʝFТT+5PNi%Ղ[fj83C^jnou <]Dx&N.l }(W:t.֐S ,A]dHȨW?ul^G4ɒ{JIJ8~0uCvp+3O$4voW'.NtDzt]S<ÝͿ c^ 8 ()sqY Y Pv<e,yN kzCe@ѩݰtΞkafV4 QڬFh4N_`f.- K%$ЂIIzxMGB #`Ὅ%.[ԁE;Gk ֞_)¯.NGh -HzEair"IЪ7l^fEfa˵/`(OZcη`k .3Dj}}>A0`Nw`sxߍbiqY17QI3x-QS=~a2b_戌:bbP䠦21sjPF09:{u"Y<Uza3꽈 ^{aփw0mǒdu ^K_Uqԉcw%T[ǿY(ذÆ e )ؼ2n;/TS)PP NT{7E Ix78}=`ջ+\sH/s%Mݍ !R]G+eIѐ5{]jf$Kݡ Br {b[)m1YeJQlxeWzR:eLVw<:@kRbEt[l̖1|+`Sʊ`/)u%*T;X2)G1=N] p Ź]=!'O+2XU!; %ɃD8@\Մ*: rT֖uב³NJPI3WL]|f4Є+`t K*3ӣqW\$ -~=-Nu{4 Mj>8JOqi^DW >6>(Җu|ns]œsռG WXZ!PL嬡Gt:&"i0 ց81 }bgPLgu-{Cϟs8{NP`Ic%T˘ZϜۅVO'۔zyk@VlWEwi{Iz~:;#S ;r:tٜ^rJsĖW񄙒j{F[U&| nIeC#+׀\Ȍh^ڳ_aIb~åZ?gsB3ݾpGw󫹝%7-jL"nT8f]!ѕ6hXN4xL_3צ.`J J]ël Whp_tQSaL*>M63ȪW m}nRg&C 7M V枘:3Kbm<IVX :ɸ|ti(]xޱB=on9'}44%.#G1=biXfd6Be dJZ~}A;V F]sy|T>{h^VZ?a@B]M~,-)_G]p/&Y:Y_=aȰXu`2˹2o5C+lFt @ݻSզ<8_PiDPx钶漸+#oGTwP?4k7=] t;#\5Yu*8vQIrpCĉ+*N),~s|,e^_eIa1{+CLN}˙8dՓ`Ҍv1*jl8D~a,dCtVki $Y"Cy0LfƊ+~{B3}I Y8'(~[Y4oWq:3ZeFG(-z1ɬ^kVQ/wq>ɦ,Q!^vүsπ(p ҴLk7uwc=_O@O ^YO2t; ۔,n% g"s̀ s< x{Fe!-/xJY#o!gI"GrxևH[2hB5aP.P++ ғ;SY--ܭf P (B|#Z_M8+YRBrbBA0|^wbF$"6Hz:J!!LB͋n {0`0޶A`yWft(F[UoNjzXE aCxީUvb;|9Tʲ=gcm2Z&՚ek#)C7@rɬjෳHg aE%k#{d&RsO}p. !VWjQ -bbK"!إEԖE ]|,Pze6Bڏ),5zYy4[[t$Jlx#9ے[יzF{HrKK5u9 9fS>)GbDBΑz1H k+ʿj`J(/$Bɦ:ң!I"<àPgugˁVM?X mKG+I&l1(y拋*7 *U r_; UlfB_W4hL}h2(˼i~IN,۬I)3d˲fa:q|G09?a8g`Vf^ ކBDzޫ*>@ם;s_i-)`B@Yq1J ?5 R_?" F|w/:ILW75dœ_m@ԴzC-#um,j806b|E` dTA/;@³qT=069fۣ',m [27|cw:MeT˟D/3l-$J'r^1l׀?OV25馷>j_udl\7LJlȵE 3QPki땦l?^st|aω+0 v&vfvoI 1u-F\vQ#vhѭiҧd XKSJTsթo'F K5WHop=o,7s֑ C5C~S#R P "T6al{e;Q{h>a]ߘS'IGa-qש{]Bҫ4+?.օń5Up9}لwzî5$e-J=F,"Z L!)zFB0dN9fusˢER4KHNe}BcHeAʼnFT]{1X[A>;#AYG)xߴ^`=t@b *,_A!Eo ;ߤhXZJ÷)`JdRc b=.a2⽤p >1J&DV΂oа>wqz:qÇc 0 9,Yy;V["#RՈSnmpVlM43ŢS9S!+"d[u{&(L_gW_|ƀXĺܱ~]/*=X tu!`1Mqڨ#hšȮJPpϽɩN JO٧J2 I0|jm^]|3[G1Y>geU_Tp/ Wq5;Jt`U_Ĺ(g6 j >yGsUz Sc\]n Ε(;F@r<'ԕF<ԥ.>8 [5rd':#nWͧIzXb[?qhêoA9N@RhYՇf# =Ag_#s^&?IFA/۾)r35zo&Uף~l.LG}˽ l0x‡ExKd;_ MHϠ 21ym`&ެ;1Li Z-g/&}v1+ H!{L\IJ"[eW,SCPyk]\|{&XPx=qG e;6ՓE%!bRo ]u5h[{jX-5](bt"$QC)%^2DNLF+''L0{hocV\k˽!FQ+cC!5A<ꞽtJ$p4([tG׆ Qw٬-?H/&Cyۤ0-fEbs'H`oX*+%޳ gD)b:$O.O>?lkuLeg  b4 i/yi~!YquSKn.~R9!)F6^HZyT5d-c ո"cVe0C͛p@5\|Tb@մ:E?0Ţգݩ \+Ү\}0lWokl{j)@/3: 2X}g2֛gQvI.  W 7ujnQfv?w#_- 4l;lFdG;YީZykэ)7`^$\vO:9r~&i|\]^e ]3 1.[ sWypD6kA_W^F&E>ߘeDi?x2=Y,;k8as^m82rZ02b&eN^ecY!`T{+ɜ4Y1;V̎qcuV.""Vf;Ci.veⒶڔ=\,wfaLoi]K-3ǐQceR{0OOn1|VXٗEZˣ 050xJ% <9~CJSGx+[+5PzOY =zY=0MƨXE`=XiؽVm$Lҳpe3CoO:ȍی{g3wK{um$g͎ǴLfX(޸BOɸ}W6[Xcod)`@.KibE#Sy7uVK>)54P:TRԂ\;Y2;oja'Pºއ4pLҲdOT"!H;m. z rj$(0Gm B,tLx`~l`tvc$:oٯAJ)4YsM5eO:Zφ+nvx3v?OXG4 hǤIqrHx e { ~(^+O-i7maú  CR 3ҪArRw/epZxƨGx<*o%lW(ټλSʥ gX GG^K=_:R WB&3u\! v`w_lQ q&momUo%  {OK,Qgat^cѢ3@A;XJsаI_AcљsȾe? VAwC|̄:"kV11wDv]VwāzS4j8ƻa9́&{FYV){!_KGO3)TDU74˿ izד! %nZ};!5D.*Oj^Sgvf mK_Ĝh*CXE:{qtz`0pPӕmp≲pdh|~SbrԂZ8ޘhE1 ގ{@\(jz/ ג;=Z l vH*uTk83g &u)t2dm. 3/j\UֺkO3JçkElY.F[qKueBl^-cG埼**w{ދ1[bF=d0UB>n.S+C%)X Avr-D(̄a6-"uWe]b[#jz)y &pHs2_wQf'?Q-f6#1՝<_2Sɽ7b~$LjwG_Kv;/X*C_)s:$΁d-g.7S'\ 8`VluA8D?+xI4~Nf-xF P N@.f0 @|Uu:_H+] |ZF9=oWfo ֓_jPmصCp@AJ7Hf˕4t ޱ3>#Bö:26ƻ;#ާAL! ,B[vEܓAx*ΦΏ ~i찇K\=,$|2O9J_ ̘= $r m༽q,/A(rRq2nq'e&ZNSȋ"QSBFEٰlMb}qՉ)$;H⊸K{tW^a.C&4)lJ聽dʼn+'k>M⼪EWe;qWž6a]FdHq<\j쥂!Nʤ^tW .+7fMPzC(^t>IP~8.@fP;(J4 =YL`m2w#b^_R/,R;Ȳe&|i?͘qB7u?Y@ sk3Y.Yz Je9D'򟊻dA$>kSFuqDQii;R6 Xpn1\M|Z|Z N!u/4*oa8`!W`txBt.sDo4ᄘ֕ŗ} #ad;FP2y"ʮd1∖UDt BO!B-P8x h( h+lii6<7fs 0DbGBQ9gX7[~3<^+bI rwo4pPngHɒ-xmBYrcmL7S^`oh[29؊C?;Mp0wsZ'ѧTGꅭQ0:v$$a/6sCF4 [u痣Th8yŲ,Pf#TFcߌ^,!CyT=\v2̌@*G8F \B ŗ47&u0ܱX43/J `f%i#`2$AifC;Ӟ6l œN/tq^o9s `r&xح *~`@21(əȎ|q@n5#ƘD:}8~[_p6Ǻ}vn=Wx!bַ6~R܈ʁ*9ւ6(HCpODZI"WuiY@ꇄɰ2Jsg 1.i`,$~B§[v߬XrFAy|gܣBa NZCūà4P׃i={wd,.ݩ192{ØtS"hw,Te`+v:)}qo'FbGsa*5.~83ŲH`~>=qYGCPM E( q[iZi@w?$Y-;53ЫZ~+yp7RZ^` [~b@F3J{U'2-y-2݊8pۄjO2mnp9ƧfI!ƃeX1ݼB_8IOaI߰KP¦dJdB2AY_h=}r%iANɷ7n8TӢݫ3xw+( ~V!-OPE+,Q@Ho¤VEG)L!ɢ G3#w EC q&&Q2\ekgCST5ؤ*gkW(k,=UC,K $m/9p#&fh-r-x>BR斶̪mo,u.X]s5H Oi1[ې™T)T"!wk]/,r4~ͲIO4j Vp MLp~IN#N.;͎ H͗E הce9^':Ě`~%亊64M6QoLWq>'5t$֐l]tbRp:RBX`9[oscl>z1|A0U=s?LHk(Ɂl=I=Hހ)T<}[} #z 6E"%R+Zk ɬ1>RHQ$ T$,/2t&~GӶ?Ji2Љu <|NJNNJ;9I%| Al˛:&Z'm =+8D"e -ڹ"^{Wd%P'I3rgWն <쥖nZ*vtzjbCѸlPG($lw#yRL"fr:WY`ʢS Pv>b.ī"IqU܂Jp[S;0:RSPvqA!;1dW$Ҙ3@rd̕iU}HZSGΐ20); 1~1n/g"!\ُVc! :־1A88+p.w,㄂RRR)Uok(ccOIO%;<ۤjyOJF=s$1h6xT`vu46ƾI[ i*d$v_8WҋJ.`FX 닅V^qF΍kg̊Af3mMG= e{UfuchާfUFex] /n`tDH4Na5b'Jݼv= n~x~}&ye^m r<aLfӽC(^>< яQd! <Ϧtt2)Ԩ"ĐHk[9 qkHzJ"tI-=5{ۢDh>y?5ZJ)#Y8k?;y-OB7Xe:K{q {V|le3'OQ}f ,J#!&Ci둓{PrTu8ϑ4)E+>m٠Ā< (QkC=1d3u(+y8@68ㅙ"&W 秹2i4Ep͜3,<GlDz"t5- e&\.zT0޽lt=n\3Py>{ŔGUn10Ő%g!ULOj>?;o%īBiU&Mǣ(1S̆>HUO/?i-fo y?FԝA WpKfbCOfw{:Pę \~j*]񔘠χR TL&sp  tWd?Vhem2! GLit9uRj.vk;@v28Љ❴~H|.[M;X?ɜ|SzσOhHF۠"4OϻMO/?Z9uN"%.Vx8kK 3nzҍi>yyt0v2_mŒً vSYat8ۇ8TZCcz´3|L}[p+NX{8l{-Ӽ3FmxIkP\IJ >U6(UP&C" ^hep$:ڀ[ Ӷ+jx3 6%̌wu̘ a<(\AI*T`b6j"EOz 3cYш_ Eabodaځԁ J'|1h%2 0a# ܄!ٓCnH -p%vś22 Jf' N)"ܤdqDQ]MӀcCQ54w +] ږ'p'޽OV^:酕ўPQsizZv}~w%>L]s'M5ÙJt#K{ێC|H9Q^f&v?]@ke۬sMcef$ Y.3z% cBBI)HpOaa^֮ ऊ[Υ?̋۞2].50,"J+_ ƒ--J6:X -#]ڂV[CVV+=c&27CTjY.wuP;WZ0U^ )>[3EyP7|d#C9]\f\,{M}v,K lgYn"@H `&5HɣO'>3[%=3Yt<#u|PljBlÜA@dm4nΐLh 1҆RX[5 "{M|?zP>ϊ2D.N&9֬uLF.y^cs%=m4:iG&UxZC"{0C$RZ#f%SȱiM)9zXf{ zg@y}R򐆬3wړVX>U".@"Noϟ#qp`|3| 2!}18.Zcv0x=FDަKX^DFvO81C7t4f0fwUKdž-W[+Q+k%ۂT@9ϒGY1'ON]ͭ{5MR"1^3ZAmi*6߃mq'̏ A4 "x"SDުز~Ȅ\/4}@\G9LݞjXJ7 L? HdHEPluk)s.񹋿[Uv9Is/dd< N@DNsoĊ}n~(ĐŬ5P*ovIp#%J?lLDžQP\˚UU{H N4i&<'@|\ӂx[FX!AaN4#-H<gFsKAf0b1Y8@,]o꜊5-3vB|4DxBD4oͲ㱓yoh*i>$q@"D 5(pznT/HIWJ1)pB'-&-Gz{ߘ!3d1\㉐dDAl#}:cAa gE%/~ 2B2dO'NV ؖZ#-cK&#K]V@9^ig\oIW{k6wKjh@dp;[Hk*^[& H+n먯nmْdc{ 8T^jHد:p}(XFx|HgG+u 0^'0,VipLwe$/k2b-TM?, Fq\'}/؋uq? mu8!0QwTr+C}?M摷Vwh@&[;.vF=f܇`jQy!?7!a_z@ϋdkq #*붃J+'p+xw󼪬̍)Öm4i2}YDAo7~S EHTØ@w S{ 4j\cmP^[@`$UEV`!W+~P`^V.7ysmeX*J:ӊuZkǞh9LU@}:َU 4rkhFsKFQ^QӿcYQcN)#7&aɅXհ MkX ;C0ߩ)rҗeΚ//;idͲtL ږ4wt&*[WRށP0|.=BXw5ދ/KvA 8r,.Y B8B% .4`(2`*:]l.ޅX kAHF9ǴWMJU:Aaf r))IR{{xy TdVBڲ78;5X̻SM |}p_Jt2K4|Z(Itj*GQUWY |9zq5Ux.TA 4ӞCY8<ĨyT; /?en_nTE}ARsKSSrIћEŲ~xGil~Mٙ?5_w}t(>NbͭtBߋ$/)vw(4Q{2u=x$&*V9p0 ,&:w ( 4P:,eAQvc5g$giNXؒь;0G}&W%hE%+C^ţ}h tܐK" dnk}hsq\ϛKqxY~x!.Uq)ç3XTTbUc*- &&xprģ4?kT`aAAϭ'{F{7~-0w O$3rpMM PpfO!YFC̸[ZTc=Oa9:Pb~赓{eU\rLD4d 6UKTEYhEl~kxq(ԦHL؈ g+[8b Fڴo'J}rX:FC.7D>G>yhI+`u(ѵ8f+HҊ""puh#[W",jgXцޓu$+-8e/p< BA"dqJ:*2Uѷsۻ-<ohDt[^YiZ'KJ; e8(o0ZqZޖ; ,=ՐK8aqlQ{T깞/N3xwLZF .t@##򁮲L16f`? rU?nOAN<8mQ =}W^by5`W|CiUc~L x6GHkiIS;@I|1r*+MSczHU3O1{=?HE>PiJrPmG>$`pc째#}e`jI<8]-x&ϱrs Nz[~1Kl$A_5ՍpRgƮ_E0. MZ rb[Qoo y1p!8ԏA]&|>1C6C7=Pnns@3 jf;6?Wekp)`F](qmv{/ OeqwHF1xPDAmV;ukW;jlW㟻 &t%Fl L7-]CvZ<׍{}Q={1zdn#Aj *If?Lݾ$8alçgit CgM뭁/k\KIp#-JJ S_OeѻYV2NQ ȤtepXI'g}_P+)x0 _Clxdj"C(qCe.?'M,t5$8AXT3z bL6N4x-ppsw8;1,׫ƱmpLw|ޡᢔ%dUS#;ЊS,j|猟|s:^ԺY7׫!s~{oz җFB]|y'uE!]}ϡ0#~ {Ub<_R٫ͪb։ x>R)-KH693zz6 ZAɩ0;0Khk:7Tyd?Rު(wggH@$]!![XSȺl ╍e.Tc 'aC =B0Xԭeb҆y-,`F?:7Y`?`Uoe3P F5N7mNg|z19FP/A9e1 f va^Adm࿤85Vث$`S+ampʤZX.^M%ܙX:qvf†۪. e@gMAtLĊMO \Kd Ƅl88 ')?O9O@{`P^bAFnw\N[Y8X"]bW^ ꆚRX1c_`֝w׎gk9_;= Ҟ>|)-ե[_ gDt&Խ aN\ <ZiWa-: 򃡈z N)ehW|e|&Zk@Hb8I׮+aa*\9H^TYn亿x{ ԥn-T":W 1"k'-Cu@}tClYtVz׭>q{ I.@ƞmE =KeHMjOVu0hnf=>Lu>@~jk'έfEmϽ^$t_cX.eYcvп{-g -yp@N_3tX KAYiws*|8שڎȂͺY.1FBj9pU+ě"XϺ*Xcv*wg#bs*l2 2m!\MҠ?S^yħ9fۅ o"ou`KIA?ͱ*iJ|QưulvgE&.]!Τ%IeJDC{W3l; yp4 \kQi2 z+sX ҏsD`%$E SڧQuЎ\#_ZϬg1!ґMmsQHڒQ:`T\&6eAנKK|ç >K$}/pPit~l>%MeSڦL{lPTp08@)Z?B=)s !M&YDR+u8:uVE 2i1 q׊^,6ҸI6oQ?C]6ZK _s֩k/ C>m>&~GC {pxorQS@78vO.P8l30PՈɺX;Ј%g| AV-`"ӆFT I6 [?_0u$?Nym;D+zUX빊|PH) bJ=8oo㴨.൳E)L^)!Lw`ဘA#dZ.#rvS?~+ӗAbǽ?C7ovDH3vYLA^{55`Dl}w#LU)Kԯڶ9ܧ*.s\8MxPT퓃gL:unvo:O,bZ| @h1>NyQw.@hU|MEˉ@%y$07 c ot] BiFr5s*lcvCj!FRZĬ^hlGtY(C@wmܑa PXӔyLs)К!mT6-IHJpcG&ˁ3:KmdڠTR+ٜ/> >eK SO1۠g@d k,(c4E|U:U\iKIND=JKn=i$C{ [lehFv⏺8K'oQ`c-\ VOVl(A0!h~n,[f|`V*Acl2Zdo@2jԼįyLiFO bDR.A 1"LA*<4ΈS@}7 a8KGZYy'BA?̿t&*/OHWVY76TRdf"b&@p>z¿],(m A2&DXYhoG#A9n#RGZ`|QފT^9t.CJm_~9X9P81vD\äu~UQ?]NȈBGʏ]F3"#W:;T|'ϙK@QQDu ȟ/$~FOiS1M g#~ꞅG`.:^"R]pLRwd oVy?5d8QhތbwĮA%/O0̈9uocX o ȴç3>%sz9X{gDx[7e=`5譾-j|Ἲ7Z"c$YV6k6LgNun('t ָw˫|.NG`QZrVf\NAu&Z_PDӷ&0^~=S4=R̕n,ql z^C5݈[7!8c}8> JU8U9 \91XqHoh ÊKq 9޻06 IwAO?ß%kKnN,PG|mt'K*QyhC/ɵ:,ȋe"}!pS .&oZzȼSA#\*c)-UO\ka Ps nۖ>RQf!ZnިtOe /@4'{ nF !5r7 yɐZ$'v0B߮vyQ}- l;OvҒ ݹN>MQ+cO{$cm3;Q!.衕0:m0 #tS' }+eX'y\Ai ؖ;&GQv/?%ˠ*ρ)aV,L?ew^tvu6|^;70=}fĥhaSg ,7!Pt>ۘ6oYKrP{ji^WitVěKtL=a粔zea}SWAT;79ώl:"T4>;Wl~Y_ a,5 mJ~JJ^nS~.LLpdI!^\&Vlq_,8îurvPk$01f%3 %&p_eDV|=s?Zgzމ͉`9]?b)Q& wbQA[ xD$KF8&3Xhy'V4SfIFs3GI#(y]OtNשAaN3.ECyk]vYlnRY//&% =L ;ؠKq.JVQi] 5a]Ʌ=Mj`^"2HӃXQ {-pEFD&Px qTrTUT!It#_5(׻甎.!:f}ZCY`Kf/C=4x$O_GXuTR9  ӆSyf&6r?n/,sȱH*܊IF[w^1$i%ƿ+һ܉!WM:?UTeŁCyOUGjl R依 \Y>Xpі\ 63]tg\u].i*l>ş0a]͟g,&~5CgK)\t"=gǪT- 8H&=/;oq?A~:A(@O^/Òj%rw2uX4OWݝy#th1LjV&ë)lk:j4GW1Tmf$I4uMN~#'y#CRw( أQOMXᑂ١tTw/ 5 !*.,|/07EJplAu;$}ҍ67_!jV9k*\extB'$2 }Q-'VAh >Rꈺ?}#񼔊d&y-bBOmQV#Bq7Y .#N{7B3g @n_QykdY2Ap# nLsHm M;G>/֌2w _@ˋмcٓ㶡7<]DUGJ9`30I%[?uvF(KMc.}̫#hcxqzaX -{-j{ße'.K1G:zͤ)L[rE^:(3_7GOlW&6ǕK|U0;zĿ&pjds_yGIF5rB>-$UI #2 ּ;lrmQ߆.0FysR砲m4\áMjQfI2OC -Ag}V_\-6 }MD?=]ۃ_V^`ZɯU YӓNk(L&~mƚi>U؀]fMVL!s+V3ݑFB*GxmbՓvOBs^V߬ƌM&! jBF'{} fTe8R z& n)[^N*W2U*6>Eb/gUܠͬh_}1`[^]SRgdZdyt@ɩ)qP:U|ƫhn!wZL#(֒hh#смreڬtg=^xhk- .k\Z*|C[M"Oq!'=݁|$>D2,fȁZ3`RgVIydJgP[mv%ti[,a ɘ-9T-j8yb/qWGW6ZkC4LkVV] W_:rË|W0l(iEr-rxLp |K{r\^?Ф.d@[#SX7|J+vˡ[hSIC t5Gk_g ^2nNAdum 8`%Vl3E҂y bx죸|3oOiȇUVsmY?%~1հ.  h8,]Tj.?[wf9[F~K`LݢßQJ)\0|pనؤEV :G{FwVاW/ř) Wl'RpxS=UMɋa"vAh.v3aRFEҍѬm ' o'A={'cNřggjF]ru2@‘+zBe8RL$2v.8WQt̒$<`IsV%'x >6ؠZ,|6+"As Z>Y֥=U94>wARXhqLcODq n1fSZ[(zl˛XW@mkR#=5lBUw/Z@)KЃ/{6['diBEiL4ޝeG*ಛ/|aΨ72K3ؔH 1K^%/6_qWr+({>A<6;1+ܤ&~$AO[fd!'Ӳ]qwKSʉ8:CRj͂k8Q ,MwU!抹]Q`C?Rx$ {0Ea8`?aޒGL4q{w2H;fUqn} V»N\d{3Az*rLk.o͢Tْ6B"a`o-r\x {B{s<à"Cݰ4q=7TFi:C d%WPN7 J"3m@ɳ9&^=D?~s P#Ǩ,.f*t1Kqm!94P;\I|B!Dj:I^LʲX_֬6O@)M|GC@$~|j$#] kdmq2"P 4H=)hjs=>Bع>XcisV5Ry*oa~ٍ25,WלReN;`u XgmrrFl%9/d- Ӗ=!d(^$VWV 89ϔn^WTGlWÂ[)5m8G-<`$P;Sxooq  bAKpUyr3,h7ƲŁ@5I[LЛU"(1?VT!80JsIFi>SmG%ﮢlXmNx$Gk.֊CVnx*S Y٩r'_o],+旉?ci4D MFA G8$}o_2~xXD(+KXPL#<f߿zp0E]l\hidz.+?W08:5ݫ+QFݍt+Ibĥ&܃=$KJUJYA/2BAiZ fr&1/`soNwvN5mwf\zoHH3~0p"2fDR~/˕]gs,qp).F;S_v05- @*-~gHFM|D7MErjReQ* [ #EB3 /;>uCYvh\ɕnT{WI^t0M[i&L4XzDr= w;&GLIog,lbe1>דݦc \}e' P82ZՅ|ԑէU"d̶,LՉiI (9GniT\eDq*t8$ 䊒Hwcȿ̀馡QE\`ao^UQD] G]wuk SMG}ft.xʭ @H[;]`9?AP>]hhDt~m ujK #MtU-Jɮvkgs6?6%ۜH *sKjWۚ@kSˈ's!K ~jZDEִ{;Ƌ^i *|$6')TeEg"޼mP>6DCJt is4r xFVV 䰶vDzQBK30Ѐ%WVDgCk {ZݾWϭleD&g]:=d=0ډbE4zd I,JN<hK-_Ynm7?EA@VgtpMu>S?w,CKnes@"|( 9/;2Bx@2%ݯl{ yIpQ(l.oP~x$b\v^2b yt,T1(ڭ%" YCUdoQ}i;xUsxz/5t벊SѲ(h- (t LYF Z]':f?@ vqw]#ZKHϴAcr4J[޲cSDPwmqRp/uoz>8O<&ݗ}ȯ\*rF%H K)J;NdB-LBH$[j@֖ (jL_vrA8stFQB7l3j,Vrx ОG5R596#xGPEva3/CgCm5gc%gh0|, ĵNBOf`H~- &md?F~&<6`od<;s8z@WfHl؛ APE#6 .K 41yQCXB'NGPKߧ;Fw53$+>@o$&xN ( ^'c7&l}*5Eb\Kfx ] F6hl Uv`r,WM#6' Ƒ~]2$b0]Iڮ}T`U`FX^3KX7k2N~|LAD)tpѬϮ2FwMyabꜰgUluzXT-wE};_+݊)8H4'!+*~{6Ra,1M'#EP=GN% ϏqRU[|hqŚNU;T\?Z'Bٵq9KEsN&Q+Nm . 8 ~.Ajvcux۾pDqͿNo lkd]6,}UKyQn0ah+x#w@L}z4f_6b>VEET𬵃24AG2,|.:cϸ6xx"75.B!B])?6vb-UqTcrܛ;3s#e):7N"9m3DST?hK+>vߐ="ƠGlYYp+-M]K /08 w Q/_#Mv3{ h,|qń/]V2n3 )Z b .mO8.$3{. mtY[۵̞le]У'"KTDƮ3Yw=f}LySJ1܏(w_DQJ~9of[ p.一v;bFn 0oX k"ril($;A(䁟J_lbk`3C@//@UxccTG/J,.s;(C|7h!$%_9`z p2_h{8e}2 z{x ΋_*ybz7icli86hWnSEńx6шȨo'0t499s:)N6- n?rja':o>: kjΒY#tWܸ3`jDA |eh~"{1Sr06,b 4O},g`uY*fSJI-ߥzo)݃^rɥ &9Oz8z4>m𥈎r繅xZ~<X"n6Ba#m|}em5ި <^LѦad HIb!sKT$czHbf#i_jz=K@ڛT!ckޢD !Ǣw$hn{ n&qRh]ԀZ&j{t:&FEM }tNd֏))GUb.y=4qa e9E zrVOߝ,LVzR\>0O8%_JRHmN&1{~y*b*@KcV2J!K 19'\euEVj][f}2 Go[GmnփD#r\w ao~$K G9t!U)8/̯(J%HsNĔ*tYEӸlcgo$GIgkG "6۹Ȼ/q 0履 Y>~vQ]{LN.Yތy 1y%,ڊi #>*/$%X%],9ePީQJ't\lZ0q·ͤD9mP*W~QH oYJMxo?3$&R>1v){GAs+YAujvƢȠ 8TL:{k3jB4@?YN4J */Ƃ1cÛDFL74aGng =WW"i>D$eW}Lڲx$L%L(>=8\tx..ˊwP|?F0y̼]8qר xlGlL?Ys XiVJ3z{Q, Kg1"pM8,.~ˌRzQ׽d&#mkQUڤty(ѪT-M /fxP NzƎ͒NcR Qw'F=&aW~F ٭p-0Qf8j}^ͣF:Rc N{C3'ة3 lYZ<8$] *'ںDߎ㞺B`KevwIU]62ߝ~Ǝkw(b>YԩqrOEQ;Lw~H`ž]]Uºls&SxָΝb ϓ{IԺ羵?SeC@i6}m%s _dK~wI$>]VfJ"歰Θ]"~I.^ÌfG<| D{=[<Q@Xy׋CDr?Ceޫ0:okMr$,4&u0}Vw-f3#4)M3*~'ޏ+0K(SGj*Kh6[J*RF&ǎX);%7$*AL9=W[.BAK+\G*eÜ$.H] ;$}A64b-^wLo{Ls$,epdcfq<Ej}fOs(w?rꩻ~Cy54S xIxU5HV)qTw<{{#a#@Pm o RnZF8N[,]Dutq_t%NCsozz+ڃxҁ|.xy., *+ELaWj0|D|t'^ s.7id\H(5h67r'-BYh/SttBʇln%Y6?RcC4#f4_e\ >yFC3,Qܑ aBMs^ʊRs k(xsMFv6w*00'V7Ci4G9 :J2 4:q5B[%3Se'/UxUrRwgT :X`XZ6EPr_@+3kfؔn7WPa&#*U}YE@P6)aAa0]ʛUlZB7 xHzl%r*b,$]Q$v;<ɣl1:lwԑFYnث["TB񯽥VWDC>w+ :T BOEḴʧHPP2\J~( CK$mO1'\{R4*GԠ^0t0)#nq#W^J89Tz/DEФW:$Xٳ/Y,7?$9"zRZTiRD+SYu1]<&!sPLϸvL &A]5p(4mKhliOcE-OFnZn-d 'w>S] @"^QBK1?^dĔyr*"ܚeR3x72qܽ=SHmy7GԼbYzZ˽A%eh%%~V]@즈V?sT1'}]nT,)yY۬V;L&:^}6B\y/3A^Utu&0 &iϩ=F(E W w۩Gk'dI2l(㾌e2z2R^h87wȰ亿Vck/gLǜ| "hӥMogGhLTN?״gR^%>>A)!6`Z6Ai|` G,iK["rt[9i"J wl\)(;D`KM 4}vF $5wEw]N "wQ_0(`*1A|MZȁ!Pլ;pҟJh*iwSeRhI9HL"A3Rxu;' |6H>ͩCrw&>i/б%#cuS[۬]ya( ;g)^6UW<=A 2wH;0g iuNn{W f]:*jE9ϮS^EV28y\L`F #~Ifי|QB(,eN!4"xM:o5# >yB@jɡY0g0˲t?eFe&9we5'Ԩu {F$ZXƿXҽ-BOrȈ1>!ڍ͒N~i[<3=B֙UFK LlR[?t1 εE4 _$gr>7αVX.?4)X}lȦ7jހ1_x0ڕ׿OM0^{3%A#|814aF3 rrG#6A66(,2h|RoNG~> d?t~ݡE"}av]; lt"j8 Kl!e;^7ŜkTG^9{a7 Կ=\p9r) 4ϗ́XaCQq@^rɻ#T d ~ZJ>>m^1 8Bp=݊a>O~TÀwTRHq^Jko T(;0+Dϻ-gX?zM QYv@#ҠYPTi;gt"$;n8D$] in3K7p9W>jցCoF{]fTɽ<fUM(bzxn2j&-7|M{S njIW#Ka (9|Ll7elٵQ҃ <EL*|oKGF~ A|Q* tyeȼJU(B1bs='eC{=F*x4O#E3!|_jHO?Jc2swFj9`@c_V :LhSU\AA̗c{6!){'U ްE'tr/~z22x* (b7kӻAi5\W^lUr=;xłMRtS M} ՙƪ  &Tbwx}1^@jbToz+EJ`kMUЅaMl7F$B1֩K] Oh<媞cd!hsP-n]βAz1[SN=4y20:n.-bxF`8l\0ge:l7Y6K{Ud <iSfY]weKu`nNưmAaj&)0|3 ۜM6< =N͌W㧋@<n.h/~r_zuIB5,xihӍ>VX "?6o˿0eq75;HK+nn-s~ݫp4%w{-q9iǏr2Ʋ+LfݎfZAҗ9W4YBM`FPJ9X.gCe)xDŽ W>g ]%x`ldWۡC@ UQaw?e}u-Cp+QhuˇX*'qeCAaO|TvülbHYݴc !5fڰ\:췡6# E1)F^k#)YDq/=5qɝQ4/Pd!4Dyr^ &2؎rS"9SߝDN/N4V2+ue>- {?dA椄 |,%u:=" <M"| -eɽX*dPIQ#݅k={7|8&] F1œH_S?h]D/>;}m#D6E~ģľu!& ,՟9Huҍ; ` & %5 v+:ߊY}RYFhSLwDYxN 2lV%MJE|.u[%KHé;JvCwm`anpGNxI_NW> E$TOJ=Hc??{/$90ZRD.ˢb"a-75};©92mo};|G}#Ar4͆c@c~ꋴ1Xج> z{eBp{% ǖm0$кxG Ʌӊv9HCE9 (" ^zex] #~q$.d0?nFltsef";I E#·զMGZ޸ dF'1!怒"ZFHPU|qZm^-(jd.ޮzqOMdͫ `lrU!H:BF?H.l7/c, ҃ba0,JNpZΜjnNשPd<:b"9n-,:{vٚH- LXϳd#tLt<5 d"JA1-٢uu/?tsd6qQE{P((g /2.@ w Y" sN;;8u !9C TZJIbHQ#U`z9cTG:d"#%VP:N&9ՈYeH"D`_sΥ/`˪vuܵ D0Vƍv]KӡbfPjE?c(de#0 5Hdsı:$z3eCy J) 7IƺcqulG1ĝ/ߏF8 %^n_}>LA&QP)G&bQV$}14SOo&9yӹO1EL՛c5qSD|uZF~Gh6uME>M% {֟fn|@0vmB\o6_kt">FF|"hgD#e HAPPHA-dz9a[3;jP@WW`j!lٝvsY ycԪUc%Zt[S̱۳4y/jMF M߾S;E,9:_6@>_yR6NS Q5hF-36Huh!V5kQ7g]J+9ڜãg FU{G'SpڢKreʊ5왕sy:DBl qNR~[彩1z7+I17G:ÒZTf{gm w]xr g9(R2bbrսT'd6kkwFy!mX#*Q5/XYK}# <*`p)2AIWbW}'d.8~fN^z8;${^ݜ?>$k?>څ98S;0bw-+LMH}| O""saM@~)N/A -U/& ђ*&)}o{z/B\hWd\,xlB O3KEwkVў{d]!b539I)RaàVn(8.W&`6钥i??^o8s}1` ٴ"5 p2 9:rsߟ^'m-9daJ"0H3afZo=~ɇp$"% Z8;2,2ᅍ#N}BX5Ebxnſ˅[⿔FW$\hs4pSJcvOE^WJH_"?||i:+nx &y\[r0ȓ[E{]sDPH©ɟЙjz/ O(ɷOnIVJT}\"yX| 8J>^c])xc#J/gW8"â<\߄s3ul43=8 _pD׳}.۳zwG5UWZM㻿R Cf&՞!y^q;Ql_mQjOC =\_s+Yۻi`4ʩ`r@hJ6f yX.#&qy<Т CZOG{.Z:vGQ"m_ڰ̄^}1?f/J c69c Ƚʈ/d!3Aq.Xv]%+LNdqF!B:tH4LVzƞA'|ʉά$HĭIp{;ѪFTT"kBnsy2 xw]=l\dcj",>JЌGn ݔفMEo0[:K^Q h_^ڢ{ f~Rc~=j!_e2Knm $-:lYcIt3XkU!:G_Ln2FZ/dhU7$2^ ) YO(ƨ7(o МzKpiflI@pFc#`Gx.~ZdQ+o#2wW.l?嘲,,aZ,z7TD\ME%d=vS"U 6UN˙pCɗ>XRybk z/9h{U;f=Fƒ5xq!P. FV}(` 9bUmv_S9ODbaD9:(D)D*d~!2!58!a1|PX}fhFGz(wnQ;RZ˾Ek8#$N.)48t*H%k)E&9eWscҠk=*:ffz)ҟ~ۼϞDt/:PG MS/5OB^"j"$-\e˔Goz#Ó#ѣޣ#zV=_(7><-n0v8AX;5 /R*wUCBPg7l}>S``{Y4f5-ew~cfm*lbw_P0qln4ZjZN qsy|{oB񏟵j0y*( l[3E 3ӧD*Idk,ZW52Ca4s83096Rr2iҘ|,ݝONyhf4: #&t8~ukx{* QF`zQj*yy*&2ED.mW'U*(sMhTRQ28z\ }kcG%7 -uCy!(? ŭS'WP HyڅIW*nڜ2:|7W<C+&Waz)7+K9%jKFۜ)Ho]U>idLD0#D橦-6Ҕ?FK_&֒A<&FDe㳙wT^N/}Th)NWr Behh< 9bā￐=?Oؖ*#~zXH='eS,k ?ۃqzT jWEqPs-Bfox {hxU O>xܷkǻ۲^6 $"HUYdYpp*OM&gșG32Yt7ے%Xm'/#c;txßSRhKA 3"kuȇ-K;yTIQA7FBVէ0QԠ| m%ܗa1FeQ{N:N/(͠ҷWݹHuqȌzD:JYV?, ipFCBv^3wVqeM9+2Pq怘"8ُͧjsWkc+QӺí-۲'>0 YZspam/data/UScounties.ndorder.rda0000644000176200001440000011314013527770376016371 0ustar liggesusers7zXZi"6!XF)"])TW"nRʟ҅j='Sa .K=|A4=~j#c ,cbq\Mc싮NjmVI U>c¢\Y,$XL ?P, DdȷEU֦q semZ.Ve%S61g@:_t >8ec~34"G@[EHu;ޟ}3 BPgVC'Ϸ3x@l(^{@lt *}};P^K6C_VXXwǁgM[L*O%7ml?81b&#/4l .\%۫N v&{L*Ǔqaݳ+]={vU} 0LcFwT5JVFRTA!,Yn_HקKf"/5NR]a4۵sa\*Nx>TPF{2gWg tʢ1/MR߈I Qfť"GdU~Ў8%4Ú jkN\/>oŬGuͧ|P!:Sw^@-ͽA%3*yxSo sWt{Nr`{Z𑦔x߹9הg /L)>=`÷ RWawQTĝx f1i v =z"،˼z}`8Lxύto{R8xRduւK5]V۩ow;=8 =fps9=0Zċ*-yI0} kv8J&fƒ+K Hcm/y"K(;\a:Ccb ^'hoWEIq ZI[ImVx(4cd$.=[1 :MrӢ3R2~̒]@-Vuiwo5M|?T%4=*]tϬi 6 ,|sT _[. o3񪷄]^`IAWbio0 Do!͈-4qצ.Ghg!>)OY r܋,]?Kxީ6{wV:HB2~dQu(I5?i*G_0Wdyn52{4|^%sWDS Ke"8F{cDFN>c;wzI UW]2-CV(dpB8cu,PHB8?% R7S.kuXV0ws)c"G~7P÷"/lV\.ó"J~^ukX~5;-Y.-2yn)`0ljl*AP}rto5h hf6'od=_o"M*(EdY86q _xtl[{Mܞ/ԙ2 A%ؒw(eVr+0LDn9k!zBvL馉s\[P!' fwFL,Dъ V)^!;'$ 1<4N+,19q}{?5`2]EZ'WoŴ|d>Rxc\bvD,R\L`M FpZMhsߪ+,]CmoBKkڮX]\>p=Ks6Ąd4f|FCVwEǖ:OϨyrc % e#b  e [:qWijê|N`nt8/ O5UR,~K㚐RrR$uZ9ћxbžo>.)C\Љ=֑1}x> !Q+%Ʃ ,,#UDRzB&cm{,ҵ0,D^& D[)~cZ ڢBc#J@֢}e0w# qӑ` Z>2bJT=MKŌk[ 1?,V.^Zg6U{`lq=w" g2 RQϨn$P$X]9mԕlLk4 KdCi%: k BTgyM>V{  q {m_}:SdeQ#uiߏ*}#?)P6֟( 9nR}hҧ4(*8 DJ /[U*]D)  ,S#ixr⇎WR'ȑTl{ckB8%V| 'Sbk'jHށy 4qLiC&,wPࣆ4"3):WL6%p}` O:\O u7g\PSMi IQ48kUIy@Ԑ]ۡ1/OYk2 $>~҉,l[չ#}%-ꖲXM\tMNm_|AӍ|$]S2=p4Y \>f S C,qcM! MU =cw_`1 .s&GFaa$B_(h4F"QCe:3`wke~8=B^OJc>GDĤOEeɂ#={ sfbZ.?uZItVҋU_iIyHK\}T.ӕ4)IřeFqAJ8Qٝىl>K w <-[Ԉ{7f8iw PmxuuբkZlxb\DADj+@gKXS9v$yH\*`qRZ~윤0iЍ!-# @IB066j[ƒHQD+ݩ:K$F3jm*ORv^gk8]?9oZ؈X/r+7btD2l`ј!ƀe%c-O=#ͪrbDJw#-t_VaτZLab4&- 08ϫ}B3sNon ?VN[GWZ ,!ʫ;%ߜXG0jb\ڈ gfk&-vʹ"57;-S%lzSwQGo-6@6ms]yȾp?CLw5R$X}ܱS{>%^(qA`,#.u9_w}[R"mnB2DI];OkԊVYf;]4lq"?` !)bXQdN7pUX j1;D M FV D |ףxCf@ ϒ6JM?Ơ-R^#jJ0L$k:Q &H U5gy9e7[.#Zg&^nH=׏>g+ǖn~ɻZlSyD N ݙ* qKrPO|U.?>~/Rpf`U$?Mge(}1MTti|\2mzKZ!v|cdsm-'6 ~v^9%mig=짒6G@I ]/qNw_$`3J`WeDc iCpbx0%hH@ oksh K>o=V/p֋taSH.²yezrOEtJ[ R㨤m2OsY x 0AN ׽V~+ǫ G\q! ]Cq#m4v[bô^|~TRQ t|ύ7ʥőzS4m(ZETGٛ扺6MYˉ=G2L wި- 98)]?i sT 7c%H֧d:VQh"к"Oh\lasc7r q%Y[F V]IZyA@<tpqIߝY|VLK|uNOe}s盲g`L/8]J@ScG SeVgOA}zv`p ҰҎHyBǗ>/eBE赤J_fBҀ\1mPd>s>i},WEL0YR?ڨ&YY];HbϽZCa+<,z[<&d Y$`o_~3l."~m0NV(N !fb/*^s/=MmU-=m~`+_`N-sTE~:^o%zͰ&d}7<㉁k׈HF7cH&0A?no'4yM{Ʋk:$5J,pI5_WA7ݍH܈l-F>;m)o@WKl L:biVΌHfN94wlBa|Vse=ûRwM@悀k~xz6D6^jj==rꁫ ˸}:DYMMgks%k1net><Jb0%QwV14>qk^8;md [!m8[߻oOV ='sLt:^JtSj4DxG "}m'縙boS]ùL," ZC>3HRi-ohf7>؇"F] fTwQ %[UPIvU'}u QC65'K])8\ɔAp =aԞwD00.-2A^t 0´E4#QyVxqKU"|40w̛O(?[ɞ뷞d, L0-%pO~Ġ-<1Kžaà{~V0TS(u%i o <鲃EjGF&:]5Bblot${nŰm f}2f.>MAF j;L%X7H۲ՄU:McUߑo6hg-to{;ީ(^\Э~Ӑ6THy4Ye6߰j;_K3\fu@!q]p'(GE~6{"j0@k_cM9J\X7LY}qU8L06|p+;'^q?e⫈ :\]1+$%PgQe%㚛›65|l*/t-o _zt/-Lr!;D,Ue ݐ.v"o[ R6y%\M~̟^\6+ij^Ed>w${p|_RkEZ#>i9aM`)> v[-2;?u%*cCRcf! Q3H"+vm2Zf+< R*eoP=PNka%95RunDƎ.˟TP)dN)d*S嘩|#=!;PqyU윻lwR$Ł6*Er#?8Dd;Uxd~>?Rk,: }{&Y80σ,ABg Q6uݿyNmn#C5Lլվb+y]}p WϨ#Am*1hRo(x '@ޡ3Jz}h%03WxA1XTU)2)J+gf ìݟƜ|t95ZR)t#)S:EeF1Gyp˝xv)5.\uo$vq%u)#:ŭXU, CrOL>N%a_bZ5dp{:q]ڹfo:Pƶ@K <uqO3c-k7h=VT$Y ^OkZ+S6>GIz[(HD5NHi#:y=- :#bu&#mC7Xy%LV> A=NXw+Um+E5ǀmBdYJ%B{g7 -:-ߙ }/RO1YDԄ:⿝Ti`a`veII}ÓL#KI#-^ܐHz.4OBwe"Lm,~F c~}d<$؟ ԥTR'k&X=ۡ\zZN:I%(Wh}`[4W oBsc0w{M I0񝾨/M-(սd+iPތ׀o [X[8 d$Ɠt^dA:+OM[ U}mwA1;ܲ_9j%Qo8t1t] N}0@QLļ(I7~^4y5Lj7^O[-N Z9ҍ Qnq?ؑ0- CHoq7ɘ+S lu|qdXÈl:a_{4`/t&PJD(܈Cu^f7=cDb ~3<,K&',8ܐ:X3SUAdiz6;9=6y?c5pT Y՗WN[d1d?3iCv34 K>y;_T+LJ{HJn 2p),QJ8oD" OgZqܖnB\ `l:Q7r>vȔeVrYɼqF쳎sI xLY7cw. V6嵄.7 [豱E"'kG{{1_{k =a#.F~ZDt}DzV>l7 +!nQ嗮qZb܀zAx} N+OfJأw Z!{21*/e.ij.4UfN! ^duR5NselW,kf_ iϏ^^>/衭8 ,gPTl/^j ^,g?m˶P+)z9 <̇Pn͕y,qcW{<5*EĬrJpz!n uITBpwǡڗD}|tYÈI3g/J-;0h1O"QUL_Qb 0K"\*%1JۦHIuûY?E}%KM ~K1٭tSoDGC0F_`ؤ^ia+̟ki.g~US:.f L6N^N w)mLtP{i?H_GyЕ2kNEl5&!w#dA;`ÕfX6X:, 5?D*2|BIuL"q6CD, 'RLI/ӂ̙0= lϐdNޭuI1 [sbyO1԰ ٨ ZSAv,aB h/@9v$g}2V'Tu *5JrF w]9 !>1:da9S} pV "r&Ppv rYMy 3c:JY@ \vZ9jH3`I -:M4y|[21p18P{|Myp5-킰tLf9Za]VU_ZTtRBCbznLX#P'p$3|㔅/b{v>%m*m !sH#Ҡ߸ʁchUGp<(@&EL tz:9U7O|乯xlν;JV h^O{6e@R&DOw__UТEק _e :%]z$w9cmXR+W728-A:k'_: Vctx+ .dd<;66m@WLHEIyBbCH©\ὠc#4>J}'E)'f2?_y-']+郗9-WuJ]PWmBi.Rx~{Iq/d{`0)v$9xJI}.܏CÉGQ_"~/(|pzI31xSf,F C0@SxLaL,LkMQl~V<7;`eKPf8}$ TR"6X4T`dq2:{%.yq#ukOD-]meJV D`\rI-^k!d<< Vܙ{e[u؎MX 1(3=!J!l %9w~T3=Əd_+#wjp ~&k9 )OU 3.ر=_H!t%VY;~=GaWo7D<'N.6U䰽gCZv˧?ɚ"^%CQ eޛ\G:#pAL?B'DU< lQyidgGjN(N˺F(Z rI/: ţ[3[LF7T x(۽Rߗb08G/~<?n(I-XYZ$xSnIޮ% I §"nȴOWcVr]zp7 A_v-<|<LgU):S-/-&]:WIj&[daEv =B@֚49Ve>)ҨW BE f%R[F@^6gɆMۨ6)AQ_-g-\1Si/ åwK1JV>,0D_f@t%JhW3IJ09)sYBC3-o=h['==И6iUWubljT" vX}+R/թimi#ꮏog{ A2$wCXwaʑ\!6b#bO3!ΒfKUGJU}#02s;(1)iEž:[,o ,)a> 6؝Ptt老B82QmS܌CRg'(g UB_za<*o@ǙDREaV!Z8v]E2/u#S$xmQW]"(Lq 4¨-c#66r(%+W,.b¡91 MWBR.)͡9bOWt@.5GTAU!Á{_HqK!0z~n r:fN,&XڶBo]MW| KłZS1pU/ t 'AIFjtŅüm2`< )m | h\cox}y,QMNb x20#fȦg8x]Ѱ&ma_BҒQv؊5iʚ(QyAt.]#öPR1rG~=H~Z52'ӦT,Ɓ[*wVMsb#>꽡:(1W"ـ|}BR21~U^3@=0&3]%:>3$&24 h=Y cUy47v)>DTҝ[4! WbZXn϶%yf ã#,^W䪙Pe@gJgd"{oIl}XeHInV.}JkorS^mQvA2{W9eOJGwW?d}3Sԧ1ge4P0`rQ_ 40҈YYj($f)s2o9kz*L~YHQ@ ~Fcku* N]GdysWmźA/Da%Sm!/g3uuhF_)ZG~hG(zr/(P9ZL+ *A؈69Uؽ+@_zdC6.6G\]PD^dBnt:-z 7tJTV<p)n&:x_4Fs3U<&,>-쪅-\+-6gA, P l7G;=v=|vAlsɔS@SE:SIC@W-,$9K63f֜bBI1F#^*,U:7:,\䥈M l%i;ShLjhNixwtHOjq0!Vfpm)w)ת󶔅:H[>7l9ohA:*հ8*_ݧ!f Oz XNR1Qr.@mfG6\a Hmզh o$q#A-'uXwav--ŽkzK}f6Рw,AF,\eB{{$|-Y8H .Ӕ[lC(8ςZngb SW[J]JEި@Ɩ79'Č?JgJhry]D׹^m 1S-fg?%8vI,-sY3I$@,Ct^t?2V&爔wĐMA`2el%yD>\NI,8u^RbtHdJӬx߻_Olcڵ[4T g@MgbL"" jpk msBtȲҁf) k3G$:ICܮSLظGr*DO8>Rc-3oAťԗZFi3V|%R(d,,1|UE( AЎ慷*)M`j.F`L4rTX\'neGixӻ 2YF#=?r$:.N M G":Z_jR 6CQMb渱H#L障u 9 _ V%P FZpykPy+|!SNrHm%M8}`~F ܋kNR[G8|o7x9hE8+DA2r‰,Xglh_>R4u_ RKZyrbk=qz4bحTh+jo7{NASLo Ju֡; ]#㍬ֿ\=AY>ÅM eQ(?/VHx~ZzuAvLr:V Puv39"ہ",TÒ2>ݔ@:,HvB.ˀeIL\e}K%sHKo Ώq#pV\4.4θlZmM[vEt٨Wig !nFI෣-5y1>  @^~@G A=W1N]NmӽѤ D_  Py*`RdsV apاnW&*rI8s6z EQ_|F6b׆p Wt . HOs 1ߡ=̐ΪA:9-Hjу?ˑ,]G'm9q;oY큯o)/V|5sFf Eb9h~@V܁E<<;vrI߰<= Gߠ`~ Iɽ.Ew\qt|m1vC습E`L4tiV|޸ϟs4zύjSт;:Rq.>0"t'rtT1/ύ,h_EŶn{g> Rb­RpΘ`goz]Etf/PWɁ $PJ&$HlhE% ܖ\P0C %.TCK'c )b+`*рǶD2*W<: \@')E6aXoQ.rZv}9})`\VXa%u d9wzn7BLVa0MBO3|ZI^.ŏ ]Kz>3eŶS=Q!C{h58F3(C1:7|XzX{A:͂6Ync1]'*Bufg^eYVL>٫dK6 `uwG_%>qT[z"?f:-MsE&hi= u˚:f$_Ky]-޳R?{סSM-1eCv7pढuKѣ uz;ۤ7;vHGjnVMGƻ7eLUba 0ԌKP~\H|'qhhPS$G^]a hU߷<xt+fZG̷ߺw,faAT؍7Y(yЪ8PrY LEA0mwf+۳9%'i7v{0bOEc>KD2E!ыǯ8>VfEJ/dr{5,fNqd67_YͲ΂YRL~PQ(.P l$$J\{@'plf\nߞG2/؆]K;h.2=YFfdPh8M(}ك5Z萙Uƭ&;u $,5=Fc(HҰ] ($eh^qvf> I+_5Pᵆm2X;l[2[Y\La# o\HMl`rRB8GH=jݲ0rcqxo58aEVF #wƱ]Z%s-=pҦPchU%+ yœ]'ᥪC^/-T$Ԩ=|wno\SEY1e ؀gԿMX|hxW4r/z#SQQq6YƆ`޷+ڡr xᢲhM qmk}58&8xWA>a*ok XIjbD2*? )Kϊ6%#l@.`( ! nP%UPtxDRgqLs6Px[7E2*,*@5{Ѹ4*nj4u ƕj}X;<>s#;CBkefQ4xctD=LkD: Z*R`yһ^ҔoJu%MV.a 3wQY:Ŵ Y2cБǪ*czq7X%a('vOP'p,r3Mę2:!SOoƹٗu9|5s`'7F@1}F@yքRz8XBд>:Z Ot'{>2h#BeVx!y"Lb u$֛][c31Svq4*X%*6uB,5h5d;nV z8/l)S$iKuiD{z<.׼蓰s zD{@lxsr"N0r1lsB_ZUmb_ʓ$.L='LRH@3Hx1J̒$/yb^ޅUdA-˼0zU'o?;G؍=4'>Gg juy:u8%=}^.k+X*b?43D%ػܵ|s^ޜN۠+'titDH=Mæ3kW &VO bLz%6%,yY61귒f'L&tXB9F'7P[1VZ Qkǟ5ՃCIߋWءԡK^pd8o}y1TLV ba0 %UyL ۥ6}xBV(_7Nk qTK|֏MK7Km;=m/uձg 46uLդy0׋*]ˤ.>]9AOca=Q,#e,߷Y(KR SCBٲSX2cc$g1vlxG}H R4LzB&_B, ='][}sO;Zem^>ÓLaw%>_q@ =)ST(ǍyYM"M'tg$JDu8l2H_}s,i.ۀ$n/rP3?f7YZYc\1 zcaۍ$,CM-Af891:,M+{Hp̀oa(Ɂ2#?d:VP < ڶ>28 m"v;.v'I` 4ZOc_fC3$}aWwuJ*-B!¦IJLP [~(͊n:AϘkl5?b9zN$>4GZ'Qbm`@ق\?%"HiHr\es2Fw0Uw=Xq#-KnjKʫ8v}$3vi*uK|7QRg47_A{~Aingcp( #l9@T\[GfU; +[ +h@'seJ~<8[:|cø0AbD"r5!$[7'Q\T]ʁR~Y]ZD&S AAp'-t3hOi E.囩3eo\/aXS"X(F6]8m3,q:B].0ST6~--_>duxµe4dӳ,Y%u3pc iȺq܀V 贗 yZ،znG"?='u01"%mIaνsZ/(8V3v) U~ϴFt^N~K/a?_}9PhuE*%+f(.XF">;j=*3ɑ:֚R%OH@/Ln4ЄVJY2UzD-que[g~)X& *s{*gΡN2SX%xKa 8jNg9>Ԭbwb~q&I*̶)R5 wcڎd5Qg0'8I/c /p\D!Pj{ymGL> ˡhiCu* [Hw:e=@3#o&޻T-V4E%p*A#yi) ퟃŷw7)g8;zD¥'(bF YkL)3ĩt-"0oVxī:1 QU5y{3lt4VsZ5V!`=E^ucQH*Of$%|m!\eoE1h%|ӈ_(@sWoTF;d=< iՇo(=* ?UίӡCÙu1)|*T˂׆WFjS([dn@[Ӗqӻ[:Xoj?F=qÕ@oDd@^/{nܛu)3&{Q%9e|vu n^Uǜ=eni S ,_N $JUa`.I_It9\ $ĽT[`SEbF2.3{Yc-s[kJ\LgCM! hq2onKW['ɐ5X1M-dO688~Z.g^nhʟ/q]Nk_KMٵE -Uŷ}NZ~0 *6̀`hR73\I>K-[f(ahHހ< ݱrp N\bmS=صN&=m1Ru0jPKXIJ큾ђDp;`E.͛9C" +wi9P&:Te~3HP\*-Hj 4mEk;q~f)&iP >S<9x~4&!iP35R(.΄;>g7׈6CHXb<4I,IpOjBU~!h+2={(gL&)~zfl*-hJk h f?\^t$X~C|gO!1Gi3o3?DiT R330[8ɧq"E_S ҇!,\V辍վCgW/ ~BEdgC1׮b(\FsB>wulBÈ.}}ޝ화A*V:r8O}i}@ nd.Ǩ?^8KVUZ{/S.]K)a/ܽVAWMoC&9.X ņ{LĦ8q˰_4BЊs[=iv+qCM[Fd'A|_~o3DEzTIdr[#lFWaƗh.:` G@z.t'*7K7'#U_/2=p\r9`M֗Z h9GFCxUBx֜m>9G<(v6*-UrVMi?@ND^WL-,U(*Pҡ?R!#A>TG0-{ p6eLFcxfFظG8̥V}cQƠFLXvgA')Ƿ)@A8N XtF~[viSBI +bP#ifQ =I讫 cX@Ke.˜'WlɎp8t*~{5&gwI;>Mԭ+?b%mV+]$A g 4Y&|fB.R $QRD_o;qY"Y{0 75]bgke*ti3U`@{o1&`^R;fЈV aJs0ɘhT.ܶ"W< SKA@49 (LsEEv& d0rZ !l8|MJpTQl9QJ'pV#$E[/L;CL5Ox15c7p<=z%ld'W=O>Wd;[Aī8gRcQ%, wGK6@yQ2+:84_jT)j9׉nƆ\FFEaC7՜#%$ED؈^F&c<|{0J܍>G@pY60iI-pcg2gj0nvd| [*C *f%~3sj8 6n8w-$!5F۷;F&_[sze2~"̂HukZZ6(cc$r~jUꓐu[{@鲞 o%y=i82EuȕU$>Lh |Ew躺$MF+ʱƌ<٩ r[ #T aww'#wCoY)C,In2dU0GfQy_,Wv!3l% XoX 4WTuJWDX-IJ$o1QSb^ܱe9>hM} r: UL ^ʢ3,VM׭%[[Xff!kKZ=-F͏@j_26 YZ"?]~}l3teZZ4@Ōe8EMM.0;-F,0@dIlHY:̊O$ _&L}3rX8ss6 `CrYZoX-)kѵ/BΠ"D&9 B;ߛ9cTkҐ?IZ0"d(O&+8}EMϣ*u&>P=Dk{_@_] YHT/[KEHCǸR'qq# \ WNztH4u]5F8<mʾ|U8OTx|[`7]>#9$=b|֕Zb$kɄO8r6(oeޅN'9ڭn|3IǤ70磶(O~ YkajNjS{^ ?#V-\\z56p%l%8 cPBA,=#J Vi"eO?zo}W?R>:&<޸eUk&xPqozi~1 Ҡ`yKut i-]Mgs~1W; c{D!WpͺɆ+jqe, ^:ںTHߗ͞%@}ݼ1hrm<*7AZT5e ְJFcWAhޫW.PuO/]Rz,0T7ZdG\5brW;/vc7ʕٺ'Q8d[8ǒ*UdJd A~(?!]#lRtmޯ}ÀÂ^oS2B| 5D(8{M(cS1"8ʜ.ˋQAiCQg(!դ)i)#C\oP"hPOh]G?~JLB*maNt&B`hLv7"|">ՁqňD{]MK#Uf-wu,칃e bu铏a`)z(*2.0qekr!KR "D;PtA”9En~z!_x_7{BZtxp`2FsJǰW'< "ʁ l~vhpnԥE%St{Dw7-P|VIz1FЊY*7kBPF񽩐3x>[fi{_^!5pwJQOrڰ'Q6‘ FO o&wڎ@+.{~W:mO7Ы:;uEb9J3d^aZo;jNM>èm,aRki˂<~0ySDl!ԗ˽6=5))[|Rֈ@b _2K%j[1Ȓ /@/IxQo#1h W 㮵 hէ9k@L3©HR5R t|:Nq4EAq32t*B#J{e%V$uj={B"^6Ld_mY)d]o8ơ%+5ϊ90TYs29Ჾtu}4oNS]]n$@QID1v+Yȩ]۩{V<ς,#Ee֙W\!e#cΙ/tN0M!,g5Z<3>m%{$>֝~0Tr3@u\kϹ4 1u#}]RMZ/1 j:2ȳZ|͓,x0Fr@KVO\"s=XFPbakMW05s^zU˓_)/k%q;./ʋX3kTQkxF=1ui#r%W5bNQMh&X;S7hܒnu0*''8T(e3d Јڤ3 <ށ~; w.0@ˆQZoPa "S=}E{;1,ģ!l>l†[blJ۱eOLWX](s6rcA mu0JuОOi *Yo]E2jI' ZSzc4_I+Igz־Wy ̊@hvxiO(UF+/{WSfdy%Neeό0BԨpxϰ"$/Ȁ/pȫ ox]NȚԶ\5zգORo`J@u41>[P#v|O>diI@8p7A5%I"7XlKQ,7#doFlG*Gt'eIvLaЉ (Tnzc8[m[ atO5Es@>(^d? #pmY|7dQv@1=ݴ\F}L1)4D3rN3axsZ.L]Wzzq"/O1h6JIw-nf#s,XSw+2h0%n1LB^TSB{AHFΟ䩣E3QOYZkKVf @q _G)%De~غ z]bħ?WaNi ?Q~>O> }"3H- Q't!JX<x޾M<ၵ8n ͱű GXIJH+dz!|/0MIL*j' 1!ZOi/F4xWȡ?Ҁ'ZT_P@4~sa+OͿB'c, ^PT]  XVAFk0\C^tvwWTt [߫$B\"i(k!cy&ĒjXk4A[pȉs sHܵbzYt9jŭƴW|g XG=em3^seL`jXL'Ry^m@WvwHsCv1֌˛r0X7gK35F~eO ZU?OD.քӳLx!3>ݡ(2!GP9*"d>Bc0Ag|݀`LJZVK~=6#D/C#^+=T(̜h6GdPf`Čbsepd2"5LyQԙ+QQ[ژd Z&v*0\(H^Ӑ/\H"'7qPև!!",9rғF/2[2 dAzL:y%}=N9Z$ wi^9~{+Ȋi/txho,gd,el2,*\[E+~-\V:kR }ފȎcb"x9qg0)7H ; ( $ݾ֥9Ҙ&ocF_WA\/zm|G) <M~ډ\ aAԒđeeOR XBL5ޓ3ƽ\Sxd^ǎ$<Gt9tSĂYu̡Q<.u#Ӷ,E ;<Oݤ@Q Ί?{x޹@c;0L҇ޜ]H W} c]N"BX FSK4likҳNZ055>@B1 ])j;k+޶ +Ӕd{7q6׬9]zlĉ 4k]Lq)jL;2\MDSGy*ATLϭkȼNz..AD4$FSn P {L;OI"z:ms#P,V : Q`C6|%\؏93 ͥ36Do#+g=!oa`;B5"'|r=H Za3`S)~GO<R"f^:'P#:蔵zW֯U9w #f4M_EO'2-"c%zNf(I Psݳ@Y<+0=/D\yk<5tv`sV՘hNg 0DQ+@oM& ɼ PsG uW~]`A89$ժw麗g!}:Mz9XGQ'2f3z1,6uoe8)NEeu|KNy*y2G'N^4gy΋XE DivE6 sצXZ*<={s*`>% ]a=u*ij@m2xNI!ߊS;dޤ, m8Geafǣz=k}" J ڥcp =p;\ \fN<7c 1?麆-3R< Wn֗:47Q̚m[4R1$bS 4L#Q D*V3ӲV!k^Tm `>nGWWwХ2|˒1W~2ӟZmH-'B|?bCrFvl\H^xn-Wb)?X霍eV TڟgHz]D\A @ Ε2sgXA=H*V K7Zsҧokg@vIR~SK!L8e~n W ٜp)tH̽wԃ1:aqv:/JxQ ,ž9'WO)n:58;T&8U8 f6A!gR-esJX}iy| b9x%U^ 'I M3c[RNs`6%)$'PWhTLTVnd^O0S ,"9#NL>ɘbO`Q SJwet72L6jV5:NoAo.y xA=!'e}mzJMu"r.* Q@c̻k3 4=G>0 YZspam/data/Oral.rda0000644000176200001440000002221213440250504013504 0ustar liggesusersmzw8gvٲ>OY٣dg4I* J(R*oR! 'WMWή鹽+]HiW\>Vm GuѬrK,Z7<]}_Tn8Gct'dHƭs$‡7m;pm%& ׿6UE׭"Mhk~%;ܯDSrj> W~Q} ׯmc+tyˋc ߖgErklh3ܦ։6+?o[oKf {܌%G. Z ihB{/ʝD𨶏0CoEv-AÄ7SEhe/0fXq*ڥ}{(?2k++vJYӍBrAy|Ůqcf;ыn*_-*NF y卓]`+#t +$mbUԠa5/h%]ˌ +{7E]Fg/OnE:w*Qc-G~t||n$hL M"e&[eQhj(\yhv+-A{Z}ԝK bxTUq]JhgVˉ3ڥpѸSb 7gٸ^s~J،m4,Yy/,Su* N۞ .GSzkϴx`|D2Wa~}j?(Yڷ)*P~gI;B"Rzg+"QAHW(:a.xNCKhjSp,ʜ<9>+vmTٛc*#ԯ3dݯw>e6@͸v޺ov9X5MS?{vV;Rц_(ARϬh:1yJ3.ʊ&Ty1|.h+EQ?PohVShނ:#FWU@x[4 *]8t~VHےxlEG a49}݊ l#6X&+QkiQkj-`ޟbZ*OPέZ X1'ڀPLdLUgVE͏SbzST??|~"M=cbZF!,Tr-tVJPhB*Z5EÏ4ԡ?-͒Y!rmy" ;ZrP>{+& aԬkgCP3h +e2fT?fyjp dD۬PYcjme9r UuvΜG#4TZo|umh9YGlF>굆zjz>6AS5lрv]W#UDBLOW5+i~AU 2TI8!MUw8AqB I߲*)IS mDwɑWBcϞD)3ICWdPٸmzyj~uz+f~˭b8vA&nG쪼&]He"DhJU*]z25j}jtnG^hFƺ*^=dN9Q{^j\BybE3V>Nw۪*w*eGaV$_P<#\VP"+Pb_^c/T QA9J:797*^_c&#"q:Wps;neB'onDXto(>̻~ n3|53)U#=?TeN۲e~-)yuOZ՞g il]3ϏGDSvuM y}lsU/~;Pm(ضVM9$_ }!Q*{JKy K砹U:4de|z65zNL@'(gK6Gs{{PYa[i2r8yu@ ,?WuP/ìqMR(F騻NCcQ8-ȪQvwg͢lԈ;JPVmLnddu .}WFyW_Ȏ8*iwE(qOV(E{enAh?gk 7/h,'kU.tl+mim'TR櫇?N1gxTVXy{*TM^]J7FWC hT^gj;PuXJ W:W8o-WFm Pr+=U{JQi/u`@o|hF]|(j[\c3[ LoBK`5>ٮY@6(ZU} :5P}oVKwǺZAu=nf׵(v꽈꧸&8Ie ՉKt"Tw$^3BMTOA6!'Vұ|sP9N5[rK+c75(p~g+d-jlW"kw9z|sŀoRsPHRVY<*;o؉; Q'qS(Du**uT+ g %̴mm|Eotg~cF(fK::+ YGQC(y|9}c3y}dϻ2. 9tCμw@;oաTWO3C3<|1j G!wNPA.OF^mBmn,(sMe(z=}%v\Us彧 QB6[[WO+=_zb.{PMLW]c&)Zzѕ(A;ȉDV~C (dM ,l~}V+I4W5-Q B?xQҲEtJ2H/<W[߀Kjȭ#@F'S^cLcgv\zwPu0r?%v5 ȝ<u{ʎoMƅsoAv&) E/@Oȓ@=b|5+?_4d01c[LdAwÄ6C ʦ=;wϧNUnZMJNmP=qu]8lfY|X ]*&@ 8v|a8ޔ a`nRl>1Qq~0d'4s t;^̞(rnP˺{b&»SM5`cv͌Ca.@Mz08qh;EB'*Ǯ<Y>͇W-bOAв=9a0 @(8=Ղob<`WY}1Pei!Wr`_;00a-㲌/ =^v53PKX ?0QYU>joVF>L ՙ| ݹYQ'`(.H M ^'+ 4 \zb GkC`_Pis0qS2 6$gC?%w߃/02y'HS _U%d?Àx[{vS[68ߊ{]J^7r^JwHJ$(:L9 V> FrTB(akя0:Pog%/>&#&n8C~8YS?٪h!01~u&X,-`¯d$>_ݭz&rẒ}+NXʄl -0Y20`,PöDiP6*$U|~Le%ɵ@Q𮴸{&.l1;wヸa |'f|}ښVj3,X2)osQ<ۡOg3 5nCn.>nCB?+v9ҩ@i$#19I7aTM' X'-&B_:Nl5zt?L\Ou_a& :T%^# @v eH0躼 F^ sWd{!px& 2fݝCɔV"LY[} ʀ 60JT\9"6=αQB 0̾-|~N$UHVx-MvD:?|I0Sڏgͺ[\hlֱR'`fʦ:Jwy<<0X>j]g`B~K^ @=]MA ǪԯnoC>UmEǑ|j *)#OcL2W L@*O /o?]ho>, Su:>9{'9<{!#202JW&'LeʘW xw;a-wG'ĸGظ yo T?Cq9%ݞ(LԝJ ~0T49 46g[.xL MaOa@W T-b`;sK0q!Jih=} >FֽԾ 4O~6@}a Vqf_Ȧ_ ֱ+ 3EWl>}Qe^w[um&q=:*8ah;71&ϋ=b^܍].Dl,L|: =2y}asUW& tw[Cԅ K@)bB$-;X~ `E{QP.*Z=+oC7#.0ߎykOUIC﬈3CMhᔂA}0*Ŏ LA[~..eF ?^ t"6üY<1N jO$f3jf:[ܻ h<ܾc-LvWF*%"5-I>VJP_@2 D:_a*fùK0]>0_/f4)@o'Mxo?~,b_߿/'\-V0}!Gl;3w!l6tzC@kb)}F ZiZ8kCkl =cfE0zؘY-hX{VIq:=a94vx̝z>0y&P8Wn? }mSajrYk-;z)ve҉KșgJ}LTeh:k&P6lȅ~ `gQ1LZr #rOh ݒgr|^wϞ Lbsi۵a_:R9ta;Qǒo?LZ3Ы3V*mcOgܲXL/vHӾ׿@q֑g0[%8 VߞU# 3$!j_e@=x#v3yS{lv%; 7b`gx#fA|r iZ|""Y\oy`ZT"6PG*&~Y O.]7,i ]U?Z:4Qm.ҽcrfwW?0ޠwMWadJ hL0Z29xV~Y0%\b{F^i-Q z~)93Bm~F7Bf} P9$+bZ*H{'~HQmU `8֘xp熈Dt2t^Wq%W*>V5s=@ӔLMx6AǼbߚ0yЧYyz#~EPs&kšK(@2rcˬkkzc.g(+_: F܆'ʯOCwd Y}ù @*1Ketw ^_ 5 8;_'pl|̏f;C=Yul=X|W(֛ e;@O_շ399 E+a=;=ia &N6{ޮJ /wvP`FsT/L)lp z"#+|Orb; (xeTnAgj{WA.DT!~I$M0unQ7շtqѤ"-m>84|ù7{1&gwr<4\U<Ԓ!7``GFKq: OkeՀ VQ9W=Q9^PE!.h:&xίn' ߔ3Нcs_4x=ͫR^@i}7ֻӥl^LVh0#ж\ZWXF\ҽ7N+,q_kjwѰAkZAO񞏿)ad ly}`]\qsm|\1a~fy^͵(yQ^D$n2: =߂!ذbN\nc5 vz5 =BO*6ghm(W ʆ6;fQW#*^=X~ܳlRǂ0lwMUBMYX..Xd Q OE?qa+spam/data/UScounties.storder.rda0000644000176200001440000005236413527770376016430 0ustar liggesusers7zXZi"6!XyT])TW"nRʟ҅j='Sa .K=|*O: PBbQ# dAs( W1@Yѿ վG w`\H) AZr2zwEHj8wpMzҲqWȅ!fL&՛n?20vC~]"zDuLtqHCyE⢰Ic \-WZh C\M&*p ߅ n$2e[>ZQd&˂ԒbZ5 }}n2^;PNVO.tuTUޢ&F ʝlw-g7 ]ڴ5xaqLئp5]?)OYĥ85~d?5q?H8#zIU s:eo"Bputl 6Y?^:*P0yZG.)IV40RћD{rMB?.EFX VgA8Rm.n ð]C3z:SҨx/;F~N n R~D39;IM3BGel8V?<~.]`PȲdxU\Y\6wSL[}ifwKVWhDdJz`_󖂼`+H\8*<r^4zӢ7@/paVc "Э%K7`B"Q~E .3c0&jdYq' pd+V -bֿ/t͝苶DŽiuhC?֢>wBiĿs֋v z+-}10dR^ghﳑձe~M)s-`2[Ff:zdfFЛ{'z?:]T83'{ok;8 2iwVMΡ ά@ЕC:Ŭ{W//b\Nڄ܂7<|4kT cvHrP'0<6FD A!t1X?rG27>]vy;*-c~|*.M9Gu٬1>eim,%F,"JBwi(RRX1.> BYXL#۫B6: cx i+ڝb :ȘSvg%i=Al5ovkCf{Q)n}3 li!) [B4߁1 [~!܊H~B~Sz tG!!籓@No~3Z14TeN\ayA1 6De0\P-<('7|EjF߲]z,n&ݨx*(o#n꘍;:"/)BY&J8sbplBPk`QOnFCĴ eֲ7N>RhUDݿB2Rn $135 ק_t򘖐F1#lÜCzZJwlQK!jD,X^W1gunBSyI֠_H({EK7-?Ûp 'k|X}(P C wdSHNZ lzm z@W$xEN.u!L[_x_J7Bz+OAq5%Vb alYLC7B}fDx^srGhx WJQà˙p4`иmp {%/]w;s9V &#0:P0ˑdEp̍NDux%t=j"6 Wz^O-BԈDb8;ɺ_:jK,2PjƷ8:Y2C] \+cmoGڿ!ZCR Ó7qf@8}9Q _XӺPm>oo/ې ˊ5XAsCM)0}9'6dS]pR(?g%"C׆:WH EOdcqNiK43,U9v{Ci`6hқ췃ʓypO"r=%487(G142+~~6b:y}\A|ʬ"W5U~vn<(:+L[(l >FGti KAl ww9H+De[%T0.\Ӡ*7iY0{IVm^­-%=4xi䦄%X[[ợk Lg7}Qu1yA%;ՋŎAu{2ќ)q qٹy@@g'=]ibXtqC]gJ }e 1Ml.M*/ ۡ$alz:+e!Lq0#8sYlk>Eovu2»"{k!~P&ls;xpŽA|_8 mq "EB 6c;iV3b%O{F UR%2L 4Q=%nJ5KCm :q@v&\y T鞘)>LCxr5Q||c3x㗲qhVݬnI n*."YʮSsQeۼc>uy] u0XZm/5ڪC<Łϛ ăfEbYGiQU,GC#8SyUmDlS`| GwȖ٦~`NXN\"!j+Yc>$+}'MGhW}A#r ]G lD{~,1g@~3~GR&m'tVM{*T].11|ݴs+|JK&kiW[Y]Vf[gm1(]U>D[-  ׅ,mzn,ь![p61V H "t&9sVFe-cL,:y=3h^1l٣{J  =^PJ-$))pom3bTN.Tmkɮƽ&Dٔg3|H2x7EGfeEw j򐮉 y/YxxY!˥"L( hV_JMGw&9f>|{ ć k80[_ԄgXC0g>T{f[J ag%4pLٴE|ae:}5 [T5CLߪ|}˰bU܀;A"م~ߡ"qOVvbpʕv 1LU>;Fvj8{F?N>/O$rO|Ob>i'iq"+fJPߥ8i TʵGEq:ЋN+!4pe65WuIB EC70[j:QX]3xq"8B>*ytĒ3I6ﬡءZIJK& tһBlJ dH܎RFna)py`I]Z:i"dtJ2U0n74."Qh/ϴ$q|;YՇB1`T$rTSYb dTH0ݎ[vrve2 "]mSxʔR!6̲ ĐhWf+P'CyO]Ee Y j-Yߩ4PAPPa~{//)Z:epXJs"ňC(?z~(u/=G}|O=*45$}~}$}ށ5qI+>=̨-L.xNXSxasT!kzȗ/_hehW2Ul$dbBYӯޓfR8Mfd9i#a:۟{T>reCZrq}ؘm(G.e65XgTH01rY>61(A(K+Ěn6seΡC enAȯ'!kt\t>HzO'oO9D饆>;b'wlglbڑ;CD=ic+ޘqъ03b<pǓϽ,O k#5,MsJu׈5Т½ʩ+e2nVܤ"M7ΛEa,cKmd!r_??f i *^)0@*uqayDҤ^c/$CE^R`˔dSOG<^#EcE"[ [ۢ2V6u1.P?- p"}N $^ ~BJ(e^a wϰɂ+^DɬǯeI;k-;7\Zcy{2 62hbklpxց1<WWI<'IpaAha(${˞R +S[) Tv"=VuыORR@M|trl[&}URuv*Fxh;?RtvfY5f!gerpn[@sV=-zR0<`)}ӓ 4=-\|,73MbaBD:x&O\ٵ*ɨr5Wډ4_o;ۮcesϢ蟰ZPfM.PTyvVׯmQ"hKVwtUdA"_d RT7ykMZ " ]Z&ߥc-`,QwE!j8@h~Iflu9)K9ܺR1;)F8Bo#ií<1vLqEdNˤV`=*PвOxv=T7oju9!"!]IfFӹhHcθ Ho[\ nl|Ȋm--h9Q1aWX4⏹V;; |tn0b-et~aP IR܈F_๐ 9eN482§36 jȂD4}C:uF>&[0Gqe$(*MI; 6wE\$̕Cl&ɇ9×o~6_W !ukՠ~v9>B;.¢M(f_g^Y܀g]_@#V~rL#th֫s9HW͆ƪPedlH3H[l.]NA~?xy\j'2~ Pp>+<ٚ&lKdYs 'Y0K_JPZ9ٝ'NJoY1URŨïUݷӡR"?✒Wnף~{gnyw'۫Ƴ ҏ%MVnT4#()GRf ʌ NaP&rZb>{o!V_$\H5jMH _DA\v;vHbm>!#|n>`zS{h3 j~/c27x,$VzHdr]X-1{+ղ09}Evq>1Ar8Ýf4ehlC8. R^A+,ERM ӬAkD'XAojs&|,z*ǦMrK^E.M*AC9sꙝdPpi OM)9E5Ğ-8m/#[`b-W.mNj0|Vۄ}Ńu> O*2R2:^BϠ=j`WI[)4O&%p+t$eo)N9%*=9fS:.^ȉvLR!t_="Ȱ$siW(jl8!M/u_PG(Ibokp wy>jZ(\#=`f?Pܙ+6%:Xpj0L(t?\& ,eHK] "d6}.ޏ9NpUrNCkz{3l~ws#dm,#V!hVB|?f$صXK*뉭Kq@#O#M5`ujk'Fñ #`a5%MIit-Zad'nukDDt^sژ\Bsm\>6W^/o]I;z^T3PO9&śEb/ci' Ya=AOvS5޹[d9\w!ML5b:#LyOB'1mujrm,ij$Nvn9|&ժJ>LawrtYЖCv9kAo"bIuD]cO~r34sUi=s!Vɔtp9@j]`!NnrPqO|/Ơ`TTay7B)AfCI, d3hEs'a,PB;€tĢmIDqJ sצOK_*v)ðZюgatwMUG'zcmN;Xg;ԃ< /xTrXDbW6O3} MMtqƩxMMs"b=+ކn-t iK~㋅u,@'PVVxh((3<9" 0̙ 5[w#fM=dU7'"q4wo;&ٝfLa޻u.vGU# ?jvGɑ$^vSY ύC%{ 3d-0>];'ejױ:$A M8uFLFH˗7Zx4 ]R<<~ Yօc0yF9JPzDHZXWvc ]p9:c7aȐMPl j"ב9"iM "?7eX˒L&sF4PC䥓aIPIZgM3"K$ZEbK?u>%\s@`q~jwJKuc Y<=#ѲclpWkZso@8C/Xh7a[Ԙ%0JBYT:4x!;wHU2U3.=zss"1㿑p{K4O)@[u!ۄ(EݸZl!dI2I`ث -)_I8J9De벤{n_Z|΋X.s^R-qƟ>w{z(b~Q +k!JنWȪPW(`U@Ze^BgpISI)Rd n݈ьEF-vvwXOۂ'#b~ۛq<ҩQvc܎'TYo2f&K=if>-vdln̦ w>,#Bz6N#ʸ6}p ^lyZ #ȱh_ 3yӿi}ɉ>14>zoFNe$DrQp=UR7ғ{8/u} ,h98a{#'0R@Wslym:LUƨ*B$7R4vKPtF7W/iW9{мVDr *"xN(¾XԱ [ E9 Z+!QCu=} ȶopz _-}Vs[ILmz®c7f^N#G_}LHFR|큎hhkp "lT3SXSuݏAPgڞ-%%gdNh}j>U?U$*wAsAȹ  pLSG+&K2e2lgȕO)4O;fӋ>ntyl C+bI澔Oe/՜qu< `3IP 7_ 96[mք̰ۊ)XE/M5!?ƼDSPj̳;Kn+u&܄$t9.G閶;acD\c[W揜HP:"h:32qKlAVP|WTrjmFq*wQ`>!ҵ?V`N~ZoQi!:|o&Eǟ\7\MZ"W4<ׁCT@_j1ͿP[{㧏tW ORq9cD OJ MaW +̞%Tvzx76WqmۑJsqy+QyPjYMpcLvd5q,rw J*eSb=\Sd>>fr^Zd`7ssN)(zqj AhKNv3,-!cRNu,9n/'RM޸B= \aY DT m_9)j{/q}˘[v~D剨u}U _h eUuJڻeE^ ?VQLɔ}_˗I7R.O:˦-=9KECVr#%m ՇK[,EȒ"-nkD$Cqdт AZVf7 $_КPd\'bFN-|y鞏$ٕ[.bF#5iuz4=嗊Rfs͞%~4]Jdd?vdʍd&Q_A;WCe -_3~ #-KiS;z$|ݞE;L͇z @k!=xQ`na?3^%Z/!>59mU-Sv)z*:2~cr9??MacIR-K0J iaۭ9M0Jh8!@?$?TuSW*WЧc2\Tg(² 6?!'SSdHFPީrGx_՟ &/~|i`Aމ1!2 &LͶ`_pK\_tqU/b%*t`68X&:cE+@} ep-_GZe2u!M&Qz sU2O4DէZ@Umi^pp$3InQnRǒvƈtwR㠮gYvb.(.!8ˇx\S m!_|dN|qfsg)^S2LukFmӤu0(nG aϐ_VNoQi&'< TTn6NAEDUe}aܻ,xh\ohՠPiByCx`'0Yf3 #IM'*oh2hچnp$0]bEG-RsZq /ixqcJңVɑ%Jl!FO(X5IqA |3vC^ηS Gb._7KYYG J{퐚GqսjTc갓۔F%-\a$MV@[Pnʌ4Y[ qNj#w$D\ 1QmXzg"JŬoF.&?|T hx $^NI;wౌ7wSwOUY<;#17N#Իw_F4E)teqhi(W`[<\K"-˜"aF 'cc?XD~J~U8s=rMqi2x%Xxuw`-E^Tc ഢywNpZLO-F&mx cT.URPkQijc5F9wG%_0X(v WoH&VV$f9-!lM[F~'|巻`aSaQ9`fTn%Z:gXz%p?1݀mgƍ@ x)_LptSy='Y/N4:TSZnr^}>6{41eΈ 'Wp/y'm:(gBd֜ ط7bVU))ܙg KOW(sc6ovycEzi s4.Bx.1ʉ{?eW~' ,*w Bq8 T,x.&z1꿂]\O,-*g;I%y7BI=g?獶M0!~ntW,lmXx-Ãg lߙݺ@|̺fKUmn*Ƿ')!F<.s5fG¶^ivl87nWȌVzNj^>.j%"a UWI ]L0ۻL *–bZqW6 鸁/wfwvp:w8d<Z^-O[>;k`߸5_]f;N$^`JS&z$. Zk\z,̐Eq>OFC)qv'^qp# Iң/@1? %WX9|( QݗɟM,(5%\f{Mui򗗰NR֙H3|XaAuEISkYRP^.P6~+vP:v5<** ٵ+^+rjP= Rj+A.D4֨N'FkNveRb4 _:uazq}\ |xXwgMNRaU-ӳS]ȧq(y^dphF Xx_ ׽ T)2b#>D@d䟤JCOH,E$sE&g{qtcx_I6[O/W^i7EsLWx$7^ou$s q6Nc{e{;ٛ'[3 ;eHҍYH^S朒+*f_Df@?`%Y/RlH%VJ#;? qdѯ>"բ>9@.eS)Jœl6v_~P r dɟ&ksL &IoX2#xqgNXc2䬦7$C۰|0`n($̽ҡx'3M 5:X+f2W,N*c7m9Β«ɖAuuر&tE"D nEE2gcL>9~b'/3F +{7IvH1d)<`٫H!5\R΂;NU{O,E`K,DB놐hʯt}|fd"d4nǧbZZZTθi0:  ;Bs  M)󷰄4 X%s>l>0fe@q1s*3ӥ{XBR:~.)l2ե@GBb4/Ϲ a_tz6L΃m|~>%Pq3CT%D/DY0|q/k d Q9&Lׇ}@6Vo[OtX܉CS MJ`it=(|@4, Lql2}){ݯ׎]PtQnK-ѩ_IeHˢ[v Xw'hA&,8'A y9+QøhZ4L0ԫw6gKcNLwgq5gTqa%1%S{˔1W) ]U[[ 䗇^q=Au~iWBz/W4c=(UYY9(~Lg&]aC#r;`=U"h /atªg#l1q뚻;45+1v^WG0DYdhliH!Y ArDztԊɛͿ .#-sk῰ц+-H go'^5C" 1Ԃヨ%T"@mmO˒ɈoMSmE1lk ^6bڗDS,g:VwS6(Th[&Gxsuz'Bcq`ޯY\*`2iER7{[ǝ O+B%3wSvUӑBixc&ӽQ_9i(Ek>TV-9u(A _ y!gOd' |P,aP/E|6? ?肀tur,FIx|E:rkTjӤt*%m 1>*I+CԪj=03n(!C`g'a$%-0c&~y~lPYl%cl>_16(gO؇j55nUJJY5θ79X1{cXlݮ:ewypɃiOx_/|w6h6&āa$Uǵ{1 &E K9bDR>74bNr+~EJRj:TSH},^Z^9$(iCK|a"?!ƁD+hXVWA<؟՘_B+ªWR hcQf;Z>AMaTGO1o]\f(G* }O8@#s d8s[+Yilox$7aO&qb୬)BHi]y|LBxe}瘰}6v*:usާٳEQpO5QxS﬇ I jpޮ^)!9]\M9Q>N_};F؀`*֮a+W!I/jcrB, 7N DK{˾O[`䡸U^2g"?eWI/Iu9$rUT@_{!}$&$T8Hq|`l(~$| m9ݙVnKNH!#m6ofWl(.}㐨k3 bm{lRx\ h vG L |]癢zOHЀxq?̦O9#C]!J_ ;pz gm "nhz ̿,JBd!w ( =! I%c%6ց&V -n-u"ilc-Rtvx[>kU#{iĸ,;"II 8 xDB|KIHN( +!+҂0`3 _wri :KHmS>}g-O `_O/*"b/yMe}+/F}p0-I|Juiei Lϓl2RPM4[1CލTtiý%&˱5.溾,)}AZBod2"jU٬LwxS&ƛ;9?v)8 <%aJ*#Vܐ[bGtƛD@( 6zw# G04QiO׋I XV$j䵡Hg X3h+,I;yQ1[FaHkFs>ʪ˒Dg4OInEB7߬т\^NB>?ͶV_ՙc^,Ws_g9nʚb>\٬rY'B"ȦhuAt}Ly ?4V쑧DkyAfxA6dBs=^zN~D?N6'pټXq"$II%U&hI=x];|Z1;iR}e匨.\:3[G&2Fz(sK~mh[`7r&_ G ϣ@U;kCt ,kI8a7e?s#.NIi= '}tSyRCj']|HQ{ 0~()CFL˘3q`<V`a6^6_O-Z[KY*v`J5`0T-Q3; n!3M]U͡f- l^[HsX\xTX<TН K ΋&g=-6/WBaݶ@̳^fXa v?eͽ$#>u7R!C먤yMOͅӃ\P5OZX{+K,xJ Y -(O&/>pe1J|߁`9fRo3Z7+UK(Obp6mC}fܯ!O20 KuOT2xw@#n(&5-kA|b]@GQ7:;ގDَɻ<#N3zo}K7a_**]Qƪ"n5'l)FL(le6P2r}J9Ip/H8+HdhOnp)k "0kX-,\~3ecZg?e|S|J?YQ`XL3Z,v6RLqE:("Y;ࣧ *~mdC -;R"فA2,Zr,-H4$ĻB4GʅFw3W%{ԕ zH%5b1"}|GZ3u{Av< ܡ=W-Ζ;/s-򣨫U`:%QjE;Q:ΰ=flJ%Q} Gi!\M5baB?/Lҹ1d'9"Ee.'Fpэ). ޛ ٷ x/sY it'>S1 [ߝQPJ#p98,!9WG -2Jqf2EJbjl:oD@`| jң*o[_MƤjfɹC(m<vAϲBhL[Xh q`c@Ֆ݇k.ʣ\ԤwɆЩ< >0 YZspam/man/0000755000176200001440000000000013571175605011777 5ustar liggesusersspam/man/allequal.Rd0000644000176200001440000000621513536451712014067 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/allequal.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{allequal} \alias{all.equal.spam} \alias{all.equal,matrix,spam-method} \alias{all.equal,spam,matrix-method} \alias{all.equal,spam,spam-method} \title{Test if Two 'spam' Objects are (Nearly) Equal} \description{Utility to compare two \code{spam} objects testing 'near equality'. Depending on the type of difference, comparison is still made to some extent, and a report of the differences is returned.} \usage{ \S3method{all.equal}{spam}(target, current, tolerance = .Machine$double.eps^0.5, scale = NULL, check.attributes = FALSE,...) } \arguments{ \item{target}{a \code{spam} object.} \item{current}{another \code{spam} object to be compared with \code{target}.} \item{tolerance}{numeric >= 0. Differences smaller than \code{tolerance} are not considered.} \item{scale}{numeric scalar > 0 (or \code{NULL}). See \sQuote{Details}.} \item{check.attributes}{currently not yet implemented.} \item{...}{Further arguments for different methods.} } \value{Either \code{TRUE} or a vector of 'mode' \code{"character"} describing the differences between \code{target} and \code{current}. } \details{ Numerical comparisons for \code{scale = NULL} (the default) are done by first computing the mean absolute difference of the two numerical vectors. If this is smaller than \code{tolerance} or not finite, absolute differences are used, otherwise relative differences scaled by the mean absolute difference. If \code{scale} is positive, absolute comparisons are made after scaling (dividing) by \code{scale}. Do not use \code{all.equal.spam} directly in \code{if} expressions: either use \code{isTRUE( all.equal.spam(...))} or \code{identical} if appropriate. Cholesky decomposition routines use this function to test for symmetry. A method for \code{matrix-spam} objects is defined as well. There is the additional catch of a zero matrix being represented by one zero element, see \sQuote{Examples} below. } \seealso{\code{\link{isSymmetric.spam}} and \code{\link{cleanup}}.} \examples{ obj <- diag.spam(2) obj[1,2] <- .Machine$double.eps all.equal( diag.spam(2), obj) all.equal( t(obj), obj) all.equal( t(obj), obj*1.1) # We can compare a spam to a matrix all.equal(diag(2),diag.spam(2)) # the opposite does often not make sense, # hence, it is not implemented. all.equal(diag.spam(2),diag(2)) # A zero matrix contains one element: str(spam(0)) # hence all.equal.spam(spam(0,3,3), diag.spam(0,3) ) norm(spam(0,3,3) - diag.spam(0,3) ) } \author{Reinhard Furrer} \keyword{array} spam/man/import.Rd0000644000176200001440000000546313536451714013607 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/import.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{import} \alias{import} \alias{read.MM} \alias{read.HB} \title{Read External Matrix Formats} \description{ Read matrices stored in the Harwell-Boeing or MatrixMarket formats. } \usage{ read.HB(file) read.MM(file) } \arguments{ \item{file}{the name of the file to read, as a character scalar. Alternatively, \code{read.HB} and \code{read.MM} accept connection objects.} } \value{A sparse matrix of class \code{spam}.} \details{The names of files storing matrices in the Harwell-Boeing format usually end in \code{".rua"} or \code{".rsa"}. Those storing matrices in the MatrixMarket format usually end in \code{".mtx"}. Currently, only real assembled Harwell-Boeing can be read with \code{read.HB}. Reading MatrixMarket formats is more flexible. However, as entries of \code{spam} matrices are of mode \code{double}, integers matrices are coerced to doubles, patterns lead to matrices containing ones and complex are coerced to the real part thereof. In these aforementioned cases, a warning is issued.\cr MatrixMarket also defines an array format, in which case a (possibly) dense \code{spam} object is return (retaining only elements which are larger than \code{options('spam.eps')}. A warning is issued. } \note{ The functions are based on \code{readHB} and \code{readMM} from the library \code{Matrix} to build the connection and read the raw data. At present, \code{read.MM} is more flexible than \code{readMM}. } \references{ \url{http://math.nist.gov/MatrixMarket} \url{https://sparse.tamu.edu/} } \examples{ \dontrun{ image(read.MM(gzcon(url( "ftp://math.nist.gov/pub/MatrixMarket2/Harwell-Boeing/bcspwr/bcspwr01.mtx.gz")))) } \dontrun{ ## Datasets supplied within Matrix str(read.MM(system.file("external/pores_1.mtx",package = "Matrix"))) str(read.HB(system.file("external/utm300.rua", package = "Matrix"))) str(read.MM(system.file("external/lund_a.mtx", package = "Matrix"))) str(read.HB(system.file("external/lund_a.rsa", package = "Matrix"))) } } \author{Reinhard Furrer based on \code{Matrix} functions by Douglas Bates \email{bates@stat.wisc.edu} and Martin Maechler \email{maechler@stat.math.ethz.ch}} \keyword{IO} \keyword{array} \keyword{algebra} spam/man/permutation.Rd0000644000176200001440000000345713536451715014646 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/permutation.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{permutation} \alias{permutation} \alias{permutation.spam} \alias{permutation,spam-method} \alias{permutation,matrix-method} \title{Permute a matrix} \description{Row and/or column permutes a matrix. } \usage{ permutation.spam(A, P=NULL, Q=NULL, ind=FALSE, check=TRUE) } \arguments{ \item{A}{sparse matrix} \item{P}{vector giving the row permutation.} \item{Q}{vector giving the column permutation.} \item{ind}{are the indices given. See examples.} \item{check}{Should rudimentary checks be performed.} } \value{A permuted matrix. } \details{If P and Q are permutation matrices, the result is PAQ. However, it is also possible to specify the indices and to perform in a very efficient way \code{A[rowind, colind]}, see examples. A row permutation is much faster than a colum permutation. For very large matrices, a double transpose might be faster. The spam option \code{spam.checkpivot} determines if the permutation is verified. } %\references{ %} \seealso{\code{\link{ordering}}, \code{\link{spam.options}}.} \examples{ A <- spam(1:12,3) P <- c(3,1,2) Q <- c(2,3,1,4) permutation(A,P,Q)-A[order(P),order(Q)] permutation(A,P,Q,ind=TRUE)-A[P,Q] } \author{Reinhard Furrer} \keyword{array}spam/man/cleanup.Rd0000644000176200001440000000265513536451713013723 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/cleanup.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{cleanup} \alias{cleanup} \title{Cleaning up sparse matrices} \description{ Eliminates an zeros in a sparse matrix.} \usage{ cleanup(x, eps = getOption("spam.eps")) } \arguments{ \item{x}{a sparse matrix of class \code{spam}.} \item{eps}{numeric scalar > 0. Smaller entries are coerced to zero.} } \details{A sparse matrix may still contain zeros. This function (aliased to \code{as.spam}) filters these values.\cr This often causes confusion when testing such matrices for symmetry or comparing apparently equal matrices with \code{all.equal} (see \sQuote{Examples} below. } \seealso{\code{\link{isSymmetric.spam}} and \code{\link{all.equal.spam}}. } \examples{ A <- diag.spam(2) A[1,2] <- 0 all.equal(A, t(A)) isSymmetric.spam(A) all.equal(cleanup(A), diag.spam(2)) } \author{Reinhard Furrer} \keyword{algebra} spam/man/grid_zoom.Rd0000644000176200001440000000733513536451714014266 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/grid_zoom.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{grid_zoom} \alias{grid_zoom} \title{grid_zoom} \description{This function takes a grob object (e.g. created with package grid) and adds a zoom window. } \usage{ grid_zoom(inputGrob = pointsGrob(runif(200),runif(200)), inputViewport = viewport(name='main'), x = 'topleft', y, just, ratio = c(.3,.4), zoom_xlim, zoom_ylim, rect = TRUE, rect_lwd = 1, rect_fill = 'gray92', draw =TRUE, zoom_fill = 'white', zoom_frame_gp = gpar(lwd = 1), zoom_gp = NULL, zoom_xaxis = xaxisGrob(main = FALSE), zoom_yaxis = NULL) } \arguments{ \item{inputGrob}{A grob object, e.g created with package grid.} \item{inputViewport}{Viewport related to \code{inputGrob}.} \item{x}{Specifies the \code{x} coordinate of the zoom window. Alternatively it can be set to 'topleft', 'topright', 'bootmleft' or 'bootmright'} \item{y}{Specifies the \code{y} coordinate of the zoom window. } \item{just}{Specifies the justification of the zoom window. } \item{ratio}{Specifies size of the zoom window relative to the main window. } \item{zoom_xlim}{Specifies xlim value of the zoom window. } \item{zoom_ylim}{Specifies ylim value of the zoom window. } \item{rect}{Logical, if TRUE a rectangle of the zoom region is draw in the main window. } \item{rect_lwd}{lwd of the rectangle. } \item{rect_fill}{fill of the rectangle. } \item{draw}{logical, if TRUE the returned grob object is also drawn.} \item{zoom_fill}{fill color of the zoom window.} \item{zoom_frame_gp}{gpar() of the frame of the zoom window.} \item{zoom_gp}{gpar() of the inputGrob in the zoom viewport.} \item{zoom_xaxis}{xaxisGrob() to draw for the zoom window.} \item{zoom_yaxis}{yaxisGrob() to draw for the zoom window.} } \value{A grob object.} \details{ A zoom plot does only make sense if all objects of the \code{inputGrob} are specified in \code{native} units. Additional caution me be require for certain grobs: e.g. a zoom of a circleGrob() is problematic if the x and y axis are stretched by a different amount. } %\references{} \seealso{grid_trace2} \examples{ ## -- Example 1 -- set.seed(133) grid_zoom(inputGrob = pointsGrob(runif(200), runif(200)), inputViewport = viewport(name = 'main'), zoom_xlim = c(.2, .3), zoom_ylim = c(.2, .3)) ## -- Example 2 -- ## initial plot grid.newpage() vp <- viewport(width=.8, height=.8, clip='on') gt <- gTree(children=gList(polylineGrob(x=c((0:4)/10, rep(.5, 5), (10:6)/10, rep(.5, 5)), y=c(rep(.5, 5), (10:6/10), rep(.5, 5), (0:4)/10), id=rep(1:5, 4), default.units='native', gp=gpar(col=1:5, lwd=3)), pointsGrob(runif(1000), runif(1000),pch='.', gp=gpar(cex=3)), rectGrob(gp=gpar(lwd=3)))) pushViewport(vp) grid.draw(gt) ## plot with zoom window grid.newpage() grid_zoom(inputGrob = gt, inputViewport = vp, x='topright', zoom_xlim=c(.6,.73), zoom_ylim=c(.3,.43),ratio=.4, zoom_xaxis = NULL, zoom_gp = gpar(cex=3)) } \author{Florian Gerber } \keyword{zoom_grid} \keyword{zoom} \keyword{plot} \keyword{grid} spam/man/kronecker.Rd0000644000176200001440000000375313536451714014260 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/kronecker.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{kronecker} \alias{kronecker.default} \alias{kronecker.spam} \alias{kronecker,spam,ANY-method} \alias{kronecker,ANY,spam-method} \alias{kronecker,spam,spam-method} \title{Kronecker Products on Sparse Matrices} \description{Computes the generalised kronecker product of two arrays, \code{X} and \code{Y}.} \usage{ kronecker.spam(X, Y, FUN = "*", make.dimnames = FALSE, ...) } \arguments{ \item{X}{sparse matrix of class \code{spam}, a vector or a matrix.} \item{Y}{sparse matrix of class \code{spam}, a vector or a matrix.} \item{FUN}{a function; it may be a quoted string. See details} \item{make.dimnames}{Provide dimnames that are the product of the dimnames of \code{X} and \code{Y}. } \item{ ...}{optional arguments to be passed to \code{FUN}.} } \value{An array \code{A} with dimensions \code{dim(X) * dim(Y)}.} \details{The sparsity structure is determined by the ordinary \code{\%x\%}. Hence, the result of \code{kronecker(X, Y, FUN = "+")} is different depending on the input. } %\references{} %\seealso{\code{\link{chol}}} \examples{ # Starting with non-spam objects, we get a spam matrix kronecker.spam( diag(2), array(1:4, c(2, 2))) kronecker( diag.spam(2), array(1:4, c(2, 2))) # Notice the preservation of sparsity structure: kronecker( diag.spam(2), array(1:4, c(2, 2)), FUN="+") } \author{Reinhard Furrer} \keyword{array} \keyword{algebra} spam/man/spam-class.Rd0000644000176200001440000001706513536451715014342 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/spam-class.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{spam-class} \docType{class} \alias{spam.class} \alias{spam-class} \alias{as.matrix,spam-method} \alias{as.matrix.spam} \alias{[<-,spam,ANY,ANY,ANY-method} \alias{[<-,spam,matrix,matrix,ANY-method} \alias{[<-,spam,matrix,missing,ANY-method} \alias{[<-,spam,missing,missing,ANY-method} \alias{[<-,spam,missing,vector,ANY-method} \alias{[<-,spam,missing,vector,spam-method} \alias{[<-,spam,spam,missing,ANY-method} \alias{[<-,spam,vector,missing,ANY-method} \alias{[<-,spam,vector,missing,spam-method} \alias{[<-,spam,vector,vector,ANY-method} \alias{[<-,spam,vector,vector,spam-method} \alias{[<-,spam,missing,missing,numeric-method} \alias{[<-,spam,missing,vector,numeric-method} \alias{[<-,spam,vector,missing,numeric-method} \alias{[<-,spam,vector,vector,numeric-method} \alias{[<-,spam,matrix,missing,numeric-method} \alias{[<-,spam,matrix,matrix,numeric-method} \alias{[<-,spam,spam,missing,numeric-method} \alias{[<-,spam,ANY-method} \alias{[,spam,missing,missing,ANY-method} \alias{[,spam,missing,vector,ANY-method} \alias{[,spam,vector,missing,logical-method} \alias{[,spam,vector,missing,missing-method} \alias{[,spam,vector,vector,ANY-method} \alias{[,spam,matrix,missing,missing-method} \alias{[,spam,matrix,missing,logical-method} \alias{[,spam,matrix,matrix,ANY-method} \alias{[,spam,spam,missing,ANY-method} \alias{[,spam,ANY,ANY,ANY-method} \alias{Arith,spam,spam-method} \alias{Arith,spam,ANY-method} \alias{Arith,ANY,spam-method} \alias{Compare,ANY,spam-method} \alias{Compare,spam,ANY-method} \alias{Compare,spam,spam-method} \alias{!,spam-method} \alias{+,spam,missing-method} \alias{-,spam,missing-method} \alias{c,spam-method} \alias{t,spam-method} \alias{length<-,spam-method} \alias{length,spam-method} \alias{lower.tri,spam-method} \alias{plot,spam,missing-method} \alias{plot,spam,spam-method} \alias{show,spam-method} \alias{upper.tri,spam-method} \title{Class "spam"} \description{The \code{spam} class is a representation of sparse matrices.} \section{Objects from the Class}{ Objects can be created by calls of the form \code{new("spam", entries, colindices, rowpointes, dimension)}. The standard "old Yale sparse format" is used to store sparse matrices.\cr The matrix \code{x} is stored in row form. The first element of row \code{i} is \code{x@rowpointers[i]}. The length of row \code{i} is determined by \code{x@rowpointers[i+1]-x@rowpointers[i]}. The column indices of \code{x} are stored in the \code{x@colindices} vector. The column index for element \code{x@entries[k]} is \code{x@colindices[k]}.} \section{Slots}{ \describe{ \item{\code{entries}:}{Object of class \code{"numeric"} contains the nonzero values. } \item{\code{colindices}:}{Object of class \code{"integer"} ordered indices of the nonzero values. } \item{\code{rowpointers}:}{Object of class \code{"integer"} pointer to the beginning of each row in the arrays \code{entries} and \code{colindices}.} \item{\code{dimension}:}{Object of class \code{"integer"} specifying the dimension of the matrix.} } } \section{Methods}{ \describe{ \item{as.matrix}{\code{signature(x = "spam")}: transforming a sparse matrix into a regular matrix.} \item{as.vector}{\code{signature(x = "spam")}: transforming a sparse matrix into a vector (dependings on \code{structurebased}) see \code{\link{as.vector.spam}} for details.} \item{as.spam}{\code{signature(x = "spam")}: cleaning of a sparse matrix.} \item{[<-}{\code{signature(x = "spam", i,j, value)}: assigning a sparse matrix. The negative vectors are not implemented yet. } \item{[}{\code{signature(x = "spam", i, j)}: subsetting a sparse matrix. The negative vectors are not implemented yet. } \item{\%*\%}{\code{signature(x, y)}: matrix multiplication, all combinations of sparse with full matrices or vectors are implemented.} \item{c}{\code{signature(x = "spam")}: vectorizes the sparse matrix and takes account of the zeros. Hence the lenght of the result is \code{prod(dim(x))}.} \item{cbind}{\code{signature(x = "spam")}: binds sparse matrices, see \code{\link{cbind}} for details.} \item{chol}{\code{signature(x = "spam")}: see \code{\link{chol}} for details.} \item{diag}{\code{signature(x = "spam")}: see \code{\link{diag}} for details.} \item{dim<-}{\code{signature(x = "spam")}: rearranges the matrix to reflect a new dimension.} \item{dim}{\code{signature(x = "spam")}: gives the dimension of the sparse matrix.} \item{pad<-}{\code{signature(x = "spam")}: truncates or augments the matrix see \code{\link{dim}} for details.} \item{image}{\code{signature(x = "spam")}: see \code{\link{image}} for details.} \item{display}{\code{signature(x = "spam")}: see \code{\link{display}} for details.} % \item{initialize}{\code{signature(.Object = "spam")}: ... } \item{length<-}{\code{signature(x = "spam")}: Is not implemented and causes an error.} \item{length}{\code{signature(x = "spam")}: gives the number of non-zero elements.} \item{lower.tri}{\code{signature(x = "spam")}: see \code{\link{lower.tri}} for details. } \item{Math}{\code{signature(x = "spam")}: see \code{\link{Math}} for details.} \item{Math2}{\code{signature(x = "spam")}: see \code{\link{Math2}} for details. } \item{norm}{\code{signature(x = "spam")}: calculates the norm of a matrix.} \item{plot}{\code{signature(x = "spam", y)}: same functionality as the ordinary \code{plot}. } \item{print}{\code{signature(x = "spam")}: see \code{\link{print}} for details.} \item{rbind}{\code{signature(x = "spam")}: binds sparse matrices, see \code{\link{cbind}} for details.} % \item{show}{\code{signature(object = "spam")}: ... } \item{solve}{\code{signature(a = "spam")}: see \code{\link{solve}} for details.} \item{summary}{\code{signature(object = "spam")}: small summary statement of the sparse matrix.} \item{Summary}{\code{signature(x = "spam")}: All functions of the \code{Summary} class (like \code{min}, \code{max}, \code{range}...) operate on the vector \code{x@entries} and return the result thereof. See Examples or \code{\link{Summary}} for details. } \item{t}{\code{signature(x = "spam")}: transpose of a sparse matrix.} \item{upper.tri}{\code{signature(x = "spam")}: see \code{\link{lower.tri}} for details.} } } \section{Details}{ The compressed sparse row (CSR) format is often described with the vectors \code{a}, \code{ia}, \code{ja}. To be a bit more comprehensive, we have chosen longer slot names. } \section{Note}{The slots \code{colindices} and \code{rowpointers} are tested for proper integer assignments. This is not true for \code{entries}. } %\references{} \author{Reinhard Furrer, some of the Fortran code is based on A. George, J. Liu, E. S. Ng, B.W Peyton and Y. Saad (alphabetical)} %\note{} %\seealso{} \examples{ showMethods("as.spam") smat <- diag.spam(runif(15)) range(smat) cos(smat) } \keyword{classes} spam/man/diff.Rd0000644000176200001440000000276613536451713013207 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/diff.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{diff} \alias{diff.spam} \alias{diff,spam-method} \title{Lagged Differences} \description{Returns suitably lagged and iterated differences.} \usage{ # diff.spam(x, lag = 1, differences = 1, ...) \S4method{diff}{spam}(x, lag = 1, differences = 1, ...) } \arguments{ \item{x}{a \code{spam} matrix containing the values to be differenced.} \item{lag}{an integer indicating which lag to use.} \item{differences}{an integer indicating the order of the difference.} \item{...}{further arguments to be passed to or from methods.} } \value{A \code{spam} matrix with elements similar to \code{as.spam(diff(as.matrix(x), ...))}. } %\details{ } %\references{} \seealso{\code{diff} in \code{base}, \code{\link{precmat}}.} \examples{ # incidence matrix for a RW(3) model D <- diff.spam(diag.spam(10), lag=1, differences=3) t(D)%*%D } \author{Reinhard Furrer} \keyword{array} \keyword{manip} spam/man/dim.Rd0000644000176200001440000000312313536451713013034 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/dim.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{dim} \alias{dim.spam} \alias{dim<-.spam} \alias{dim<-,spam-method} \title{Dimensions of an Object} \description{ Retrieve or set the dimension of an \code{spam} object. } \usage{ # dim(x) # dim(x) <- value %"dim<-.spam"(x,value) } \arguments{ \item{x}{a \code{spam} matrix} \item{value}{A numeric two-vector, which is coerced to integer (by truncation).} } \value{ \code{dim} retrieves the \code{dimension} slot of the object. It is a vector of mode \code{integer}. The replacemnt method changes the dimension of the object by rearranging. } \details{ In older version of \code{spam}, the behavior of the replacement method was different and is now implemented in \code{\link{pad.spam}}. } %\references{} \seealso{\code{\link{pad.spam}}. } \examples{ x <- diag(4) dim(x)<-c(2,8) x s <- diag.spam(4) dim(s) <- c(2,8) # result is different than x s <- diag.spam(4) pad(s) <- c(7,3) # any positive value can be used } \author{Reinhard Furrer} \keyword{array} spam/man/spam.internal.Rd0000644000176200001440000000256313536451715015047 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/spam.internal.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{spam internal} \alias{dcheck} \alias{icheck} \title{ Spam internal and auxiliary functions } \description{ The functions listed below are auxiliary functions but are exported by the NAMESPACE. The user should not require to call these directly. } \details{The functions are listed here for a better understanding of the code (to fulfill the tutorial style paradigm).\cr \code{validspamobject(object)} A few sanity checks if \code{object} is a proper \code{spam} object. \code{dcheck(x)}, \code{icheck(x)} testing and forcing of \code{x} to doubles and integers. These functions are used when calling Fortran routines. } %\note{The integers \code{int0}, \code{int1} and \code{int2} (0-2) are not % exported. %} \keyword{internal} spam/man/rdist.Rd0000644000176200001440000000514413536451715013417 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/rdist.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{fields wrapper} \alias{spam_rdist} \alias{rdist.dist} \alias{spam_rdist.earth} \title{Wrapper for Distance Matrix Computation} \description{These functions are simple wrappers to \code{nearest.dist} to be used in \code{fields}.} \usage{ spam_rdist( x1, x2, delta = 1) spam_rdist.earth( x1, x2, delta = 1, miles=TRUE, R=NULL) } \arguments{ \item{x1}{Matrix of first set of locations where each row gives the coordinates of a particular point. } \item{x2}{Matrix of second set of locations where each row gives the coordinates of a particular point.} \item{delta}{only distances smaller than \code{delta} are recorded, see Details.} \item{miles}{For great circle distance: If true distances are in statute miles if false distances in kilometers.} \item{R}{Radius to use for sphere to find spherical distances. If \code{NULL} the radius is either in miles or kilometers depending on the values of the miles argument. If \code{R=1} then distances are of course in radians.} } \value{A \code{spam} object containing the distances spanned between zero and \code{delta}. The sparse matrix may contain many zeros (e.g., collocated data). However, to calculate covariances, these zeros are essential.} \details{These functions are wrappers to \code{rdist} and \code{rdist.earth} in \code{fields}. They are used to simplify the use of sparse matrices in functions like \code{mKrig}. \cr For great circle distance, the matrices \code{x1} and \code{x2} contain the degrees longitudes in the first and the degrees latitudes in the second column. \code{delta} is in degrees. Hence to restrict to distances smaller than \code{delta.km}, one has to specify \code{delta=delta.km*360/(6378.388*2*pi)}. } %\references{} \seealso{\code{\link{nearest.dist}}} \examples{ \dontrun{ require(fields) look <- mKrig(x,Y, Covariance="Wendland", dimension=2, k=1, cov.args=list( Distance='spam_rdist')) } } \author{Reinhard Furrer} \keyword{array} spam/man/diag.Rd0000644000176200001440000000542513536451713013176 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/diag.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{diag} \alias{diag} \alias{diag.of.spam} \alias{diag.spam} \alias{spam_diag} \alias{diag,spam-method} \alias{diag,ANY-method} \alias{diag<-} \alias{diag<-,ANY-method} \alias{diag<-,spam-method} \alias{diag<-.spam} \alias{diag.spam<-} \alias{diag.assign,spam-method} \title{Sparse Matrix diagonals} \description{Extract or replace the diagonal of a matrix, or construct a diagonal matrix. } \usage{ ## diag(x) ## diag(x=1, nrow, ncol, names = TRUE) diag(x) <- value diag.spam(x=1, nrow, ncol) spam_diag(x=1, nrow, ncol) diag.spam(x) <- value } \arguments{ \item{x}{a \code{spam} matrix, a vector or a scalar.} \item{nrow, ncol}{Optional dimensions for the result.} \item{value}{either a single value or a vector of length equal to that of the current diagonal.} } \value{ If \code{x} is a spam matrix then \code{diag(x)} returns the diagonal of \code{x}. The assignment form sets the diagonal of the sparse matrix \code{x} to the given value(s).\cr \code{diag.spam} works as \code{diag} for spam matrices: If \code{x} is a vector (or 1D array) of length two or more, then \code{diag.spam(x)} returns a diagonal matrix whose diagonal is \code{x}. \code{spam_diag} is an alias for \code{diag.spam} and in the spirit of the result of \code{diag} is a \code{spam} object. If \code{x} is a vector of length one then \code{diag.spam(x)} returns an identity matrix of order the nearest integer to \code{x}. The dimension of the returned matrix can be specified by \code{nrow} and \code{ncol} (the default is square). The assignment form sets the diagonal of the matrix \code{x} to the given value(s). } \details{Using \code{diag(x)} can have unexpected effects if \code{x} is a vector that could be of length one. Use \code{diag(x, nrow = length(x))} for consistent behaviour. } %\references{} \seealso{\code{\link{upper.tri}}, \code{\link{lower.tri}}. } \examples{ diag.spam(2, 4) # 2*I4 smat <- diag.spam(1:5) diag( smat) diag( smat) <- 5:1 # The last line is equivalent to diag.spam( smat) <- 5:1 # Note that diag.spam( 1:5) <- 5:1 not work of course. } \author{Reinhard Furrer} \keyword{array} \keyword{algebra} spam/man/s3only.Rd0000644000176200001440000000251613536451715013521 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/s3only.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{s3only} \alias{var.spam} \title{Wappers for Sparse Matrices} \description{ These functions are convenient wrappers for \code{spam} objects to classical matrix operations.} \usage{ var.spam(x, \dots) \S3method{var}{spam}(x, \dots) } \arguments{ \item{x}{matrix of class \code{spam}.} \item{\dots}{further arguments passed to or from other methods.} } \value{Depends on function\dots } \details{There is probably no point in fully defining methods here. Typically, these functions do not exploit sparsity structures. Hence, for very large matrices, warnings may be posted.} %\references{} %\note{} \seealso{Option \code{"inefficiencywarning"} in \code{\link{spam.options}}. } \author{Reinhard Furrer} \keyword{algebra} spam/man/mle.Rd0000644000176200001440000001144513536451714013047 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/mle.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{mle} \alias{neg2loglikelihood.spam} \alias{mle.spam} \alias{mle.nomean.spam} \alias{neg2loglikelihood} \alias{mle} \alias{mle.nomean} \title{Maximum likelihood estimates} \description{Maximum likelihood estimates of a simple spatial model} \usage{ neg2loglikelihood.spam(y, X, distmat, Covariance, beta, theta, Rstruct = NULL, ...) neg2loglikelihood(y, X, distmat, Covariance, beta, theta, ...) mle.spam(y, X, distmat, Covariance, beta0, theta0, thetalower, thetaupper, optim.control=NULL, Rstruct = NULL, hessian = FALSE,...) mle(y, X, distmat, Covariance, beta0, theta0, thetalower, thetaupper, optim.control=NULL, hessian = FALSE, ...) mle.nomean.spam(y, distmat, Covariance, theta0, thetalower, thetaupper, optim.control=NULL, Rstruct = NULL, hessian = FALSE, ...) mle.nomean(y, distmat, Covariance, theta0, thetalower, thetaupper, optim.control=NULL, hessian = FALSE, ...) } \arguments{ \item{y}{data vector of length n.} \item{X}{the design matrix of dimension n x p.} \item{distmat}{a distance matrix. Usually the result of a call to \code{nearest.dist}.} \item{Covariance}{function defining the covariance. See example.} \item{beta}{parameters of the trend (fixed effects).} \item{theta}{parameters of the covariance structure.} \item{Rstruct}{the Cholesky structure of the covariance matrix.} \item{beta0,theta0}{inital values.} \item{thetalower,thetaupper}{lower and upper bounds of the parameter \code{theta}.} \item{optim.control}{arguments passed to \code{optim}.} \item{hessian}{Logical. Should a numerically differentiated Hessian matrix be returned?} \item{...}{additional arguments passed to \code{chol}.} } \value{The negative-2-loglikelihood or the output from the function \code{optim}. } \details{ We provide functions to calculate the negative-2-log-likelihood and maximum likelihood estimates for the model y ~ N_n( X beta, Sigma(h;theta) ) in the case of a sparse or ordinary covariance matrices. In the case of the \code{*.spam} versions, the covariance function has to return a \code{spam} object. In the other case, the methods are correctly overloaded and work either way, slightly slower than the \code{*.spam} counterparts though. When working on the sphere, the distance matrix has to be transformed by h -> R / 2 sin(h/2) where R is the radius of the sphere. The covariance function requires that the first argument is the distance matrix and the second the parameters. One can image cases in which the covariance function does not take the entire distance matrix but only some partial information thereof. (An example is the use of a kronecker type covariance structure.) In case of a sparse covariance construction where the argument \code{Rstruct} is not given, the first parameter element needs to be the range parameter. (This results from the fact, that a sparse structure is constructed that is independent of the parameter values to exploit the fast Choleski decomposition.) In the zero-mean case, the \code{neg2loglikelihood} is calculated by setting the parameters \code{X} or \code{beta} to zero. } %\references{} \seealso{\code{\link{covmat}} } \examples{ # True parameter values: truebeta <- c(1,2,.2) # beta = (intercept, linear in x, linear in y) truetheta <- c(.5,2,.02) # theta = (range, sill, nugget) # We now define a grid, distance matrix, and a sample: x <- seq(0,1,l=5) locs <- expand.grid( x, x) X <- as.matrix( cbind(1,locs)) # design matrix distmat <- nearest.dist( locs, upper=NULL) # distance matrix Sigma <- cov.sph( distmat, truetheta) # true covariance matrix set.seed(15) y <- c(rmvnorm.spam(1,X \%*\% truebeta,Sigma)) # construct sample # Here is the negative 2 log likelihood: neg2loglikelihood.spam( y, X, distmat, cov.sph, truebeta, truetheta) # We pass now to the mle: res <- mle.spam(y, X, distmat, cov.sph, truebeta, truetheta,thetalower=c(0,0,0),thetaupper=c(1,Inf,Inf)) # Similar parameter estimates here, of course: mle.nomean.spam(y-X\%*\%res$par[1:3], distmat, cov.sph, truetheta, thetalower=c(0,0,0), thetaupper=c(1,Inf,Inf)) } \author{Reinhard Furrer } \keyword{algebra} spam/man/grid_trace2.Rd0000644000176200001440000000526013536451714014455 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/grid_trace2.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{grid_trace2} \alias{grid_trace2} \title{Two trace plots and a scatter plot.} \description{For two (MCMC) chains of the same length trace plots and a scatter plot are drawn. } \usage{ grid_trace2(chain1, chain2 = NULL, xlim = NULL, ylim1 = NULL, ylim2=NULL, chain1_lab = "", chain2_lab = "", main = "", chain1_yaxis_at = NULL, chain2_yaxis_at = NULL, log = FALSE, cex_points = unit(0.2, "mm"), cex_main = unit(1.2, "mm"), lwd_lines = unit(0.1, "mm"), lwd_frame = unit(0.8, "mm"), draw = TRUE) } \arguments{ \item{chain1}{Numeric vector or a matrix with two columns.} \item{chain2}{Numeric vector of same length as \code{chain1}. (Only used if \code{chain1} is specified as vector).} \item{xlim}{x axis limits of both chains (numeric vector of length 2). } \item{ylim1}{y axis limits of chain 1 (numeric vector of length 2).} \item{ylim2}{y axis limits of chain 2 (numeric vector of length 2).} \item{chain1_lab}{Label of chain 1 (character of length 1). } \item{chain2_lab}{Label of chain 2 (character of length 1). } \item{main}{Title (character of length 1). } \item{chain1_yaxis_at}{Points at which tick-marks are drawn for chain 1.} \item{chain2_yaxis_at}{Points at which tick-marks are drawn for chain 2. } \item{log}{Logical, should the date be log transformed?} \item{cex_points}{Size of points in scatter plot. } \item{cex_main}{Size of the title font. } \item{lwd_lines}{Line width of trace plots. } \item{lwd_frame}{Line width of frames. } \item{draw}{Logical, should the returned grob object be drawn?} } \value{A grob object.} \details{The figure is optimized for a plot of the format x11(width = 10, height = 3).} %\references{} \seealso{grid_zoom} \examples{ grid_trace2(runif(500), runif(500), chain1_yaxis_at = seq(.2, 1, by = .2), chain1_lab = "chain1", chain2_lab = "chain2", main = "Uniform", lwd_lines = unit(.5, "mm")) } \author{Florian Gerber } \keyword{plot} \keyword{trace plot} \keyword{grid} spam/man/spam-package.Rd0000644000176200001440000000750413536451715014625 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/spam-package.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{. SPAM .} \alias{overview} \alias{SPAM} \alias{Spam} \alias{spam-package} \docType{package} \title{SPArse Matrix Package} \description{\code{spam} is a collection of functions for sparse matrix algebra. } \section{Gereral overview}{What is spam and what is it not:\cr While \code{Matrix} seems an overshoot of classes and \code{SparseM} focuses mainly on regression type problem, we provide a minimal set of sparse matrix functions fully functional for everyday spatial statistics life. There is however some emphasize on Markov chain Monte Carlo type calculations within the framework of (Gaussian) Markov random fields. \cr Emphasis is given on a comprehensive, simple, tutorial structure of the code. The code is S4 based but (in a tutorial spirit) the functions are in a S3 structure visible to the user (exported via \code{NAMESPACE}).\cr There exist many methods for sparse matrices that work identically as in the case of ordinary matrices. All the methods are discussed in the help and can be accessed directly via a \code{*.spam} concatenation to the function. For example, \code{help(chol.spam)} calls the help directly. We deliberately avoided aliases according to analogue helps from the base package.\cr Sparseness is used when handling large matrices. Hence, care has been used to provide efficient and fast routines. Essentially, the functions do not transform the sparse structure into full matrices to use standard (available) functionality, followed by a back transform. We agree, more operators, functions, etc. should eventually be implemented. The packages \code{fields} and \code{spam} are closely linked. \cr } \references{Reinhard Furrer, Stephan R. Sain (2010). "spam: A Sparse Matrix R Package with Emphasis on MCMC Methods for Gaussian Markov Random Fields.", \emph{Journal of Statistical Software}, 36(10), 1-25, \url{http://www.jstatsoft.org/v36/i10/}.\cr Florian Gerber, Reinhard Furrer (2015). "Pitfalls in the Implementation of Bayesian Hierarchical Modeling of Areal Count Data: An Illustration Using BYM and Leroux Models.", \emph{Journal of Statistical Software}, Code Snippets, 63(1), 1-32, \url{http://www.jstatsoft.org/v63/c01/}.\cr F. Gerber, K. Moesinger, R. Furrer (2017), "Extending R packages to support 64-bit compiled code: An illustration with spam64 and GIMMS NDVI3g data.", \emph{Computer & Geoscience} 104, 109-119, \url{https://doi.org/10.1016/j.cageo.2016.11.015}." } \seealso{See \code{\link{spam.class}} for a detailed class description, \code{\link{spam}} and \code{\link{spam.ops}} for creation, coercion and algebraic operations.%\cr% % %\code{demo(package='spam')} lists available demos.\cr% %Related packages are \code{\link[fields]{fields}}, % \code{\link[Matrix]{Matrix}} and % \code{\link[SparseM]{SparseM.ontology}}. } \examples{ ## Citations: citation('spam') citation('spam', auto=TRUE) ## History of changes \dontrun{ file.show(system.file("NEWS.md", package = "spam")) } } \author{Reinhard Furrer, with the help of Florian Gerber, Kaspar Moesinger and many others. \cr Some Fortran routines were written by Youcef Saad, Esmond G. Ng, Barry W. Peyton, Joseph W.H. Liu, Alan D. George. } \keyword{documentation} \keyword{package} spam/man/powerboost.Rd0000644000176200001440000000217713536451715014500 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/powerboost.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{powerboost} \alias{powerboost} \title{Specific options Setting} \description{ Sets several options for speed-up. } \usage{ powerboost(flag) } \arguments{ \item{flag}{on or off} } \details{The options turn checking off (\code{"safemode"}, \code{"cholsymmetrycheck"} and \code{"cholpivotcheck"}) and switch to single precision for \code{"eps"}.} \value{ \code{NULL} in any case. } \seealso{\code{\link{spam.options}}. } \author{Reinhard Furrer, after receiving too much C.mc.st adds.} \keyword{environment} spam/man/UScounties.Rd0000644000176200001440000000335213536452261014367 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/UScounties.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{UScounties} \alias{UScounties} \alias{UScounties.storder} \alias{UScounties.ndorder} \docType{data} \title{ Adjacency structure of the counties in the contiguous United States } \description{ First and second order adjacency structure of the counties in the contiguous United States. We consider that two counties are neighbors if they share at least one edge of their polygon description in \code{maps}. } \format{ Two matrices of class \code{spam} \describe{ \item{UScounties.storder}{ Contains a one in the \code{i} and \code{j} element if county \code{i} is a neighbor of county \code{j}. } \item{UScounties.ndorder}{ Contains a one in the \code{i} and \code{j} element if counties \code{i} and \code{j} are a neighbors of county \code{k} and counties \code{i} and \code{j} are not neighbors. } } } %\source{\url{ www.to somethin??}} \seealso{\code{map} from \pkg{maps}.} %\references{} \examples{ # number of counties: n <- nrow( UScounties.storder) \dontrun{ # make a precision matrix Q <- diag.spam( n) + .2 * UScounties.storder + .1 * UScounties.ndorder display( as.spam( chol( Q))) } } \keyword{datasets} spam/man/precmat.Rd0000644000176200001440000000524313536451715013725 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/precmat.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{precmat} \alias{precmat} \alias{precmat.RW1} \alias{precmat.RW2} \alias{precmat.RWn} \alias{precmat.season} \alias{precmat.IGMRFreglat} \alias{precmat.IGMRFirreglat} \title{IGMRF Precision Matrices} \description{ Fast ways to create sparse precision matrices for various IGMRF.} \usage{ precmat(n, season=12, m=n, A=NULL, order=1, ... , type="RW1") precmat.RW1(n) precmat.RW2(n) precmat.RWn(n, order=3) precmat.season(n, season=12) precmat.IGMRFreglat(n, m, order=1, anisotropy=1) precmat.IGMRFirreglat(A, eps=getOption("spam.eps")) } \arguments{ \item{n}{dimension of the field.} \item{type}{the type of the IGMRF.} \item{season}{length of season.} \item{m}{second dimension (in case of a regular lattice).} \item{A}{adjacency matrix (see below).} \item{order}{order for higher order RWs.} \item{anisotropy}{anisotropy factor, between 0 and 2.} \item{eps}{tolerance level.} \item{\dots}{arguments passed to individual functions.} } \details{\code{precmat} is a wrapper that calls the other functions according to the argument \code{type}. \cr Implements many of the precision matrices discussed in Chapter 3 of Rue and Held (2005). For example, \code{precmat.RW1}, \code{precmat.RW2} and \code{precmat.season} are given in equations (3.22), (3.40) and (3.59); \code{precmat.IGMRFreglat} on page 107. Note that for the latter we reverse the order of the dimension here! \cr If adjacency matrix is a regular matrix, it is coerced to a \code{spam} object. Only the structure is used. Make sure, that the diagonal is empty. } \value{A sparse precision matrix.} %\note{There is intentionally no \acronym{S3} distinction between the classes % \code{spam} and \code{spam.chol.}\emph{method}.} \references{Rue and Held (2005). } \seealso{\code{\link{precmat.GMRFreglat}}, \code{\link{rmvnorm.prec}}, \code{\link{adjacency.landkreis}}. } \examples{ n <- 10 Q <- precmat.RW2( n) # rmvnorm.prec(1, Q=Q) # does not work, because the matrix is singular. Q%*%cbind(1,1:n) } % backsolve( chol(as.matrix(V)[ord,ord]),iidsample)[iord,] % \author{Reinhard Furrer} \keyword{algebra} spam/man/bdiag.Rd0000644000176200001440000000362413536451713013337 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/bdiag.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{bdiag} \alias{bdiag} \alias{bdiag.spam} \title{Binds Arrays Corner-to-Corner} \description{Creates a sparse block-diagonal matrix. } \usage{ bdiag.spam(...) } \arguments{ \item{...}{Arrays to be binded together} } \details{ This is a small helper function to create block diagonal sparse matrices. In the two matrix case, \code{bdiag.spam(A,B)}, this is equivalent to a complicated \code{rbind(cbind(A, null), cbind(B, t(null)))}, where \code{null} is a null matrix of appropriate dimension.\cr It is recursively defined. The arrays are coerced to sparse matrices first.\cr This function is similar to the function \code{bdiag} from the package \code{Matrix}. It is also similar to the function \code{adiag} from the package \code{magic}. However, here no padding is done and all the dimnames are stripped. } \value{ Returns a \code{spam} matrix as described above. } %\references{} \seealso{ \code{\link{diag.spam}}. } \examples{ A <- diag.spam(2, 4) # 2*I4 B <- matrix(1,3,3) AB <- bdiag.spam(A,B) # equivalent to: ABalt <- rbind(cbind( A, matrix(0,nrow(A),ncol(B))), cbind( matrix(0,nrow(B),ncol(A)), B)) norm(AB-ABalt) # Matrices do not need to be square: bdiag.spam(1,2:5,6) } \author{Reinhard Furrer} \keyword{array} \keyword{algebra} spam/man/germany.Rd0000644000176200001440000000444013536451713013730 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/germany.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{germany.plot} \alias{germany.plot} \title{Plot administrative districts of Germany} \description{Displaying data over the administrative districts of Germany} \usage{ germany.plot(vect, col=NULL, zlim=range(vect), legend=TRUE, main=NULL, cex.axis=1, cex.main=1.5, add=FALSE, ... ) } \arguments{ \item{vect}{vector of length 544} \item{col}{color scheme to be used. By default uses \code{colorRampPalette(brewer.pal(9,"Blues"))(100)}.} \item{zlim}{the minimum and maximum values for which colors should be plotted, defaulting to the range of \code{data}.} \item{legend}{Should the legend be added, see \sQuote{Details}.} \item{main}{an overall title for the plot.} \item{cex.axis}{label size of legend.} \item{cex.main}{label size of overall plot title.} \item{add}{logical, if true adds to current plot.} \item{\dots}{additional arguments passed to \code{polygon}.} } \references{See also \url{http://de.wikipedia.org/wiki/Amtlicher_Gemeindeschl\%C3\%BCssel} and \url{http://de.wikipedia.org/wiki/Liste_der_Landkreise_in_Deutschland} %The code of \code{map.landkreis} is very similar to %\code{germany.map} from the package \pkg{INLA}.} } \details{The legend is only added, provided (a) function \code{image.plot} is available.\cr The perfect position of the legend is an art per se and depends on various \code{par} parameters. One possiblity for finer control is to not plot it and to manually call the function \code{image.plot} of \pkg{fields}.} \seealso{\code{\link{Oral}}.} \examples{ data( Oral) germany.plot( Oral$Y/Oral$E) # Plot the Bundeslaender: germany.plot(germany.info$id\%/\%1000,col=rep(2:8,3), legend=FALSE) } \author{Reinhard Furrer} \keyword{hplot} spam/man/pad.Rd0000644000176200001440000000337213536451715013037 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/pad.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{pad} \alias{pad} \alias{pad.spam} \alias{pad<-} \alias{pad<-.spam} \alias{pad<-,spam-method} \alias{pad<-,matrix-method} \title{Padding a (sparse) matrix} \description{ Resets the dimension of a (\code{spam}) matrix by truncation or zero padding. } \usage{ pad(x) <- value %"pad<-.spam"(x,value) } \arguments{ \item{x}{a \code{spam} matrix} \item{value}{A numeric two-vector.} } \value{ A (\code{spam}) matrix of dimension \code{value} where trunction or padding has been used. } \details{ It is important to notice the different behavior of the replacement method for ordinary arrays and \code{spam} objects (see \sQuote{Examples}). Here, the elements are not simply rearranged but an entirely new matrix is constructed. If the new column dimension is smaller than the original, the matrix is also cleaned (with \code{option("spam.eps")} as filter). } %\references{} \seealso{\code{\link{dim.spam}}. } \examples{ x <- diag(4) dim(x)<-c(2,8) x s <- diag.spam(4) pad(s) <- c(7,3) # any positive value can be used s <- diag.spam(4) pad(s) <- c(2,8) # result is different than x } \author{Reinhard Furrer} \keyword{array} spam/man/summary.Rd0000644000176200001440000000371013536451715013764 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/summary.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{Summary} \alias{Summary.spam} \alias{Summary,spam-method} \alias{all.spam} \alias{any.spam} \alias{max.spam} \alias{min.spam} \alias{prod.spam} \alias{range.spam} \alias{sum.spam} \alias{all,spam-method} \alias{any,spam-method} \alias{max,spam-method} \alias{min,spam-method} \alias{prod,spam-method} \alias{range,spam-method} \alias{sum,spam-method} \title{Rounding of Numbers} \description{Applies the \code{Math2} group functions to \code{spam} objects } \usage{# max(x,..., na.rm = FALSE) } \arguments{\item{x}{spam object.} \item{na.rm}{a logical indicating whether missing values should be removed.} } \value{If \code{structurebased=TRUE}, all functions operate on the vector \code{x@entries} and return the result thereof.\cr Conversely, if \code{structurebased=FALSE}, the result is identical to one with \code{as.matrix(x)} input. } \details{The \code{na.rm} argument is only meaninful if \code{NAOK=TRUE}. } %\references{ %} \seealso{\code{\link{Math.spam}} and \code{\link{Math2}}.} \examples{ getGroupMembers("Summary") smat <- diag.spam( runif(15)) range(smat) options(spam.structurebased=FALSE) range(smat) \dontrun{ max( log(spam(c(1,-1))), na.rm=TRUE) } # allow 'NA's first: # TODO # options(spam.NAOK=TRUE) # max( log(spam(c(1,-1))), na.rm=TRUE) } \author{Reinhard Furrer} \keyword{manip} % all any max min prod range sum spam/man/math.Rd0000644000176200001440000000623713536451714013226 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/math.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{Math} \alias{Math.spam} \alias{Math,spam-method} \alias{ceiling.spam} \alias{ceiling,spam-method} \alias{floor.spam} \alias{floor,spam-method} \alias{trunc.spam} \alias{trunc,spam-method} \alias{exp.spam} \alias{exp,spam-method} \alias{log.spam} \alias{log,spam-method} \alias{log2.spam} \alias{log2,spam-method} \alias{log10.spam} \alias{log10,spam-method} \alias{sqrt.spam} \alias{sqrt,spam-method} \alias{gamma.spam} \alias{gamma,spam-method} \alias{digamma.spam} \alias{digamma,spam-method} \alias{trigamma.spam} \alias{trigamma,spam-method} \alias{lgamma.spam} \alias{lgamma,spam-method} \alias{abs.spam} \alias{abs,spam-method} \alias{cumprod.spam} \alias{cumprod,spam-method} \alias{cumsum.spam} \alias{cumsum,spam-method} \alias{cummax.spam} \alias{cummax,spam-method} \alias{cummin.spam} \alias{cummin,spam-method} \alias{cos.spam} \alias{cos,spam-method} %\alias{cospi.spam} %\alias{cospi,spam-method} \alias{cosh.spam} \alias{cosh,spam-method} \alias{acos.spam} \alias{acos,spam-method} \alias{acosh.spam} \alias{acosh,spam-method} \alias{sin.spam} \alias{sin,spam-method} \alias{asin.spam} \alias{asin,spam-method} \alias{asinh.spam} \alias{asinh,spam-method} \alias{tan.spam} \alias{tan,spam-method} \alias{atan.spam} \alias{atan,spam-method} \alias{atanh.spam} \alias{atanh,spam-method} \title{Mathematical functions} \description{Applies the \code{Math} group functions to \code{spam} objects } \usage{# ceiling(x) # floor(x) # exp(x, base = exp(1)) # log(x, base = exp(1)) # sqrt(x) # abs(x) # cumprod(x) # cumsum(x) # cos(x) # sin(x) # tan(x) # acosh(x) } \arguments{\item{x}{spam object.} \item{base}{positive number. The base with respect to which logarithms are computed. Defaults to \code{e=exp(1)}.} } \value{If the option \code{spam.structurebased=TRUE}, all functions operate on the vector \code{x@entries} and return the result thereof.\cr Conversely, if \code{structurebased=FALSE}, the result is identical to one with \code{as.matrix(x)} input and an \code{as.spam} purger. } \details{ It is important to note that the zero entries do not enter the evaluation when \code{structurebased=FALSE}. The operations are performed on the stored non-zero elements. This may lead to differences if compared with the same operation on a full matrix. } %\references{ %} \seealso{\code{\link{Summary.spam}}, \code{\link{Ops.spam}} and \code{\link{Math2.spam}} } \examples{ getGroupMembers("Math") mat <- matrix(c( 1,2,0,3,0,0,0,4,5),3) smat <- as.spam( mat) cos( mat) cos( smat) options(spam.structurebased=FALSE) cos( smat) sqrt( smat) } \author{Reinhard Furrer} \keyword{manip} spam/man/lu.tri.Rd0000644000176200001440000000312713536451714013505 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/lu.tri.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{lower.tri} \alias{lower.tri} \alias{upper.tri} \alias{lower.tri.spam} \alias{upper.tri.spam} \title{Lower and Upper Triangular Part of a Sparse Matrix} \description{Returns the lower or upper triangular structure or entries of a sparse matrix. } \usage{ lower.tri(x, diag = FALSE) upper.tri(x, diag = FALSE) } \arguments{ \item{x}{a sparse matrix of class \code{spam}} \item{diag}{logical. Should the diagonal be included?} } \details{Often not only the structure of the matrix is required but the entries as well. For compatibility, the default is only a structure consisting of ones (representing \code{TRUE}s). Setting the flag \code{getOption( "spam.trivalues")} to \code{TRUE}, the function returns the actual values. } \seealso{\code{\link{spam.options}} and \code{\link{diag}}} \examples{ smat <- spam( c( 1,2,0,3,0,0,0,4,5),3) upper.tri( smat) upper.tri( smat, diag=TRUE) options(spam.trivalues=TRUE) upper.tri( smat) } \keyword{array} \keyword{algebra} spam/man/triplet.Rd0000644000176200001440000000312513536451715013752 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/triplet.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{triplet} \alias{triplet} \title{Transform a spam format to triplets} \description{Returns a list containing the indices and elements of a \code{spam} object.} \usage{ triplet(x, tri=FALSE) } \arguments{ \item{x}{sparse matrix of class \code{spam} or a matrix.} \item{tri}{Boolean indicating whether to create individual row and column indices vectors.} } \value{A list with elements \item{indices}{a by two matrix containing the indices if \code{tri=FALSE}.} \item{i,j}{vectors containing the row and column indices if \code{tri=TRUE}.} \item{values}{a vector containing the matrix elements.} } \details{ The elements are row (column) first if \code{x} is a \code{spam} object (matrix).\cr } %\references{} \seealso{ \code{\link{spam.list}} for the inverse operation and \code{foreign} for other transformations.} \examples{ x <- diag.spam(1:4) x[2,3] <- 5 triplet(x) all.equal( spam( triplet(x, tri=TRUE)), x) } \author{Reinhard Furrer} \keyword{array} spam/man/makeprec.Rd0000644000176200001440000000416613536451714014063 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/makeprec.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{makeprec} \alias{precmat.GMRFreglat} \title{Create Precision Matrices} \description{Creates precision matrices for gridded GMRF.} \usage{ precmat.GMRFreglat(n,m, par, model = "m1p1", eps = getOption("spam.eps")) } \arguments{ \item{n}{first dimension of the grid.} \item{m}{second dimension of the grid.} \item{par}{parameters used to construct the matrix.} \item{model}{see details and examples.} \item{eps}{A tolerance parameter: elements of \code{x} such that \code{abs(x) <= eps} set to zero. Defaults to \code{eps = getOption("spam.eps")}} } \value{A \code{spam} matrix of dimension \code{prod(dims)}x\code{prod(dims)}.} \details{The function should be illustrative on how to create precision matrices for gridded GMRF. Hence, no testing (positive definiteness is done). The model specification \code{"m"} determines the complexity and \code{"p"} the number of parameters. Please see the examples on the meaning of the different models. } %\references{} \seealso{\code{\link{precmat}}, \code{\link{toeplitz.spam}}, \code{\link{kronecker.spam}}} \examples{ as.matrix(precmat.GMRFreglat(4, 3, c(.4), 'm1p1')) as.matrix(precmat.GMRFreglat(4, 3, c(.4,.3), 'm1p2')) as.matrix(precmat.GMRFreglat(4, 3, c(.4,.3,.2), 'm2p3')) as.matrix(precmat.GMRFreglat(4, 3, c(.4,.3,.2,.1),'m2p4')) # up to the diagonal, the following are equivalent: cleanup( precmat.IGMRFreglat(3,4) - precmat.GMRFreglat(3,4,1, 'm1p1')) } \author{Reinhard Furrer} \keyword{array} \keyword{algebra} spam/man/Oral.Rd0000644000176200001440000000333513536453331013163 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/Oral.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{Oral} \alias{Oral} \alias{Oral.spam} \alias{oral.spam} \docType{data} \title{Oral Cavity Cancer} \description{Oral cavity cancer counts in 544 districts in Germany over 1986-1990.} \format{\code{Oral} is a dataframe with 3 columns. \describe{ \item{Y}{observed counts} \item{E}{expected counts} \item{SMR}{standardized mortality ratios}} \code{germany} is a list of 544 elements, each describing an individual polygon of the district. } \details{The expected counts depend on the number of people in the region and their age distribution.\cr The regions are ordered according the supplied polygon description and adjacency graph.\cr There is a similar dataset \code{data(Germany)} with larynx cancer cases from the package \pkg{INLA} as well, with an additional smoking covariate. } \source{The data is available from the package \pkg{INLA} distributed from \url{http://www.r-inla.org}. } \references{ Knorr-Held, L. and Rasser, G. (2000) Bayesian Detection of Clusters and Discontinuities in Disease Maps, \emph{Biometrics}, 56, 13--21. } \seealso{\code{\link{germany.plot}}.} \keyword{datasets} spam/man/methods.Rd0000644000176200001440000000216213536451714013731 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/methods.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{spam methods} \alias{methods.spam} \title{Methods for sparse matrices} \description{Methods without any additional parameters for sparse matrices. } \details{If a method for \code{spam} objects takes the same arguments, produces the intuitive output. We do not provide additional help pages. However, such methods are usually linked to a \code{xzy.spam} function, that could also be called directly. } \seealso{Corresponding base help functions. } \author{Reinhard Furrer} \keyword{internal} spam/man/solve.Rd0000644000176200001440000001217213536451715013421 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/solve.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{spam solve} \alias{backsolve} \alias{forwardsolve} \alias{backsolve-methods} \alias{backsolve,ANY-method} \alias{backsolve,spam-method} \alias{backsolve,matrix-method} \alias{backsolve.spam} \alias{forwardsolve-methods} \alias{forwardsolve,ANY-method} \alias{forwardsolve,spam-method} \alias{forwardsolve,matrix-method} \alias{forwardsolve.spam} \alias{chol2inv.spam} \alias{chol2inv,spam-method} \alias{chol2inv,spam.chol.NgPeyton-method} \alias{solve.spam} \alias{solve,ANY-method} \alias{solve,spam-method} \title{Linear Equation Solving for Sparse Matrices} \description{ \code{backsolve} and \code{forwardsolve} solve a system of linear equations where the coefficient matrix is upper or lower triangular. \cr \code{solve} solves a linear system or computes the inverse of a matrix if the right-hand-side is missing. } \usage{ \S4method{solve}{spam}(a, b, Rstruct=NULL, \dots) \S4method{backsolve}{spam}(r, x, \dots) \S4method{forwardsolve}{spam}(l, x, \dots) \S4method{chol2inv}{spam}(x, \dots) } \arguments{ \item{a}{symmetric positive definite matrix of class \code{spam} or a Cholesky factor as the result of a \code{chol} call.} \item{l,r}{object of class \code{spam} or \code{spam.chol.}\emph{method} returned by the function \code{chol}.} \item{x,b}{vector or regular matrix of right-hand-side(s) of a system of linear equations.} \item{Rstruct}{the Cholesky structure of \code{a}.} \item{\dots}{further arguments passed to or from other methods, see \sQuote{Details} below.} } \details{ We can solve \code{A \%*\% x = b} by first computing the Cholesky decomposition \code{A = t(R)\%*\%R)}, then solving \code{t(R)\%*\%y = b} for \code{y}, and finally solving \code{R\%*\%x = y} for \code{x}. \code{solve} combines \code{chol}, a Cholesky decomposition of a symmetric positive definite sparse matrix, with \code{forwardsolve} and then \code{backsolve}.\cr In case \code{a} is from a \code{chol} call, then \code{solve} is an efficient way to calculate \code{backsolve(a, forwardsolve( t(a), b))}. However, for \code{a.spam} and \code{a.mat} from a \code{chol} call with a sparse and ordinary matrix, note that \code{forwardsolve( a.mat, b, transpose=T, upper.tri=T)} is equivalent to \code{forwardsolve( t(a.mat), b)} and \code{backsolve(a.spam, forwardsolve(a.spam, b, transpose=T, upper.tri=T))} yields the desired result. But \code{backsolve(a.spam,forwardsolve(t(a.spam), resid))} is wrong because \code{t(a.spam)} is a \code{spam} and not a \code{spam.chol.NgPeyton} object. \code{forwardsolve} and \code{backsolve} solve a system of linear equations where the coefficient matrix is lower (\code{forwardsolve}) or upper (\code{backsolve}) triangular. Usually, the triangular matrix is result from a \code{chol} call and it is not required to transpose it for \code{forwardsolve}. Note that arguments of the default methods \code{k}, \code{upper.tri} and \code{transpose} do not have any effects here. Notice that it is more efficient to solve successively the linear equations (both triangular solves) than to implement these in the Fortran code. If the right-hand-side in \code{solve} is missing it will compute the inverse of a matrix. For details about the specific Cholsesky decomposition, see \code{\link{chol}}. Recall that the Cholesky factors are from ordered matrices. \code{chol2inv(x)} is a faster way to \code{solve(x)}. } \note{There is intentionally no \acronym{S3} distinction between the classes \code{spam} and \code{spam.chol.}\emph{method}.} \references{See references in \code{\link{chol}}. } \seealso{\code{\link{chol.spam}} and \code{\link{ordering}}. } \examples{ # Generate multivariate form a covariance inverse: # (usefull for GRMF) set.seed(13) n <- 25 # dimension N <- 1000 # sample size Sigmainv <- .25^abs(outer(1:n,1:n,"-")) Sigmainv <- as.spam( Sigmainv, eps=1e-4) Sigma <- solve( Sigmainv) # for verification iidsample <- array(rnorm(N*n),c(n,N)) mvsample <- backsolve( chol(Sigmainv), iidsample) norm( var(t(mvsample)) - Sigma) # compare with: mvsample <- backsolve( chol(as.matrix( Sigmainv)), iidsample, n) #### ,n as patch norm( var(t(mvsample)) - Sigma) # 'solve' step by step: b <- rnorm( n) R <- chol(Sigmainv) norm( backsolve( R, forwardsolve( R, b))- solve( Sigmainv, b) ) norm( backsolve( R, forwardsolve( R, diag(n)))- Sigma ) # 'update': R1 <- update( R, Sigmainv + diag.spam( n)) } % backsolve( chol(as.matrix(V)[ord,ord]),iidsample)[iord,] % \author{Reinhard Furrer, based on Ng and Peyton (1993) Fortran routines} \keyword{algebra} spam/man/coerce.Rd0000644000176200001440000000345513536455271013536 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/coerce.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{coerce-methods} \docType{methods} \alias{coerce.spam} \alias{coerce,spam,logical-method} \alias{coerce,spam,matrix-method} \alias{coerce,spam,vector-method} \alias{coerce,spam,list-method} \alias{coerce,spam,integer-method} \title{Force a \code{spam} Object to Belong to a Class} \description{ These functions manage the relations that allow coercing a \code{spam} object to a given class. } \section{Methods}{ \describe{ \item{\code{signature(from = "spam", to = "matrix")}}{ this is essentially equivalent to \code{as.matrix(object)}. } \item{\code{signature(from = "spam", to = "list")}}{ this is essentially equivalent to \code{triplet(object)}. } \item{\code{signature(from = "spam", to = "vector")}}{ this is essentially equivalent to \code{object@entries} (\code{structurebased=TRUE}) or \code{c(object)}. } \item{\code{signature(from = "spam", to = "logical")}}{ the entries are forced to logicals (nonzeros only in case of \code{structurebased=TRUE}). } \item{\code{signature(from = "spam", to = "integer")}}{ the entries are forced to integers (nonzeros only in case of \code{structurebased=TRUE}). } }} \examples{ ifelse( diag.spam(2)*c(0,1), TRUE, FALSE) } \keyword{methods} spam/man/isSymmetric.Rd0000644000176200001440000000325513536451714014602 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/isSymmetric.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{isSymmetric} \alias{isSymmetric.spam} \alias{isSymmetric,spam-method} \title{Test if a spam matrix is Symmetric} \description{Efficient function to test if 'object' is symmetric or not.} \usage{ # isSymmetric.spam(object, ...) \S3method{isSymmetric}{spam}(object, tol = 100 * .Machine$double.eps, ...)} \arguments{ \item{object}{a \code{spam} matrix.} \item{tol}{numeric scalar >= 0. Smaller differences are not considered, see \code{all.equal.spam}.} \item{...}{further arguments passed to \code{all.equal.spam}.} } \details{symmetry is assessed by comparing the sparsity structure of \code{object} and \code{t(object)} via the function \code{all.equal.spam}. If a difference is detected, the matrix is cleaned with \code{cleanup} and compared again.} \value{ logical indicating if \code{object} is symmetric or not.} \seealso{\code{\link{all.equal.spam}}, \code{\link{cleanup}}.} \examples{ obj <- diag.spam(2) isSymmetric(obj) obj[1,2] <- .Machine$double.eps isSymmetric(obj) all.equal(obj, t(obj)) } \author{Reinhard Furrer} \keyword{array} spam/man/constructors.Rd0000644000176200001440000000262613536451713015042 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/constructors.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{constructors} \alias{rowpointers} \alias{rowpointers<-} \alias{colindices} \alias{colindices<-} \alias{entries} \alias{entries<-} \alias{dimension<-} \alias{constructors} \title{Slot modification} \description{Modify slots of \code{spam} objects } \usage{ rowpointers( x) <- value colindices( x) <- value entries( x) <- value} \arguments{ \item{x}{a \code{spam} matrix} \item{value}{vector of appropriate length.} } \value{Modified \code{spam} object.} \details{Various tests are performed. Thus much slower than direct assignment.\cr Slot \code{dimension} should be changed through \code{pad} or \code{dim} } \examples{ x <- diag.spam( 2) rowpointers( x) <- c(1,1,3) # The last line is equivalent to x@rowpointers <- as.integer( c(1,1,3)) } \author{Reinhard Furrer} \keyword{array} spam/man/random.Rd0000644000176200001440000000504413571175605013551 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/random.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{random} \alias{spam_random} \title{Create Random spam Matrices} \description{Creates random spam matrix given the dimension and other parameters.} \usage{ spam_random(nrow = 1L, ncol = nrow, density = 0.5, distribution = NULL, digits = NULL, sym = FALSE, spd = FALSE, verbose = FALSE, ...) } \arguments{ \item{nrow}{integer value for the number of rows for the \code{spam} matrix to create.} \item{ncol}{integer value for the number of columns. The default value is the same as \code{nrow}.} \item{density}{A numeric value between 0 and 1 specifying the approximate density of matrix. If equal to zero the \code{spam} matrix contains only zeros and if equal to 1 the \code{spam} matrix is full.} \item{distribution}{a random number generating distribution function to sample the entries of the \code{spam} matrix. The function must have an argument with the name \code{n}, possible candidates are \code{rnorm}, \code{rexp}, \code{rpois}, \code{rweibull}, etc..} \item{...}{possible additional arguments for the distribution function if specified with \code{distribution}.} \item{digits}{an integer value for the number of digits the entries should be rounded.} \item{sym}{logical value to specify symmetry of the \code{spam} matrix.} \item{spd}{logical value to specify positive definitness of the \code{spam} matrix, via diagonal dominace criteria. Note, if \code{spd} TRUE, then \code{sym} is overwritten to \code{TRUE} in any case.} \item{verbose}{logical value to specify verbose statments of the function.} } \value{A random matrix in \code{spam} format.} \details{To create a random spam64 matrix, set \code{options(spam.force64 = TRUE)}.} %\references{} \seealso{\code{\link{spam}} and \code{\link{display.spam}}} \examples{ set.seed(42) rspam <- spam_random(500, digits = 2, distribution = rnorm, sd = 2, mean = 10, density = .01) display.spam(rspam, cex = 2) } \author{Florian Gerber, Roman Flury, Reinhard Furrer} spam/man/xybind.Rd0000644000176200001440000000460413536451716013570 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/xybind.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{cbind} \alias{cbind.spam} \alias{rbind.spam} \alias{cbind} \alias{rbind} \alias{cbind,spam-method} \alias{rbind,spam-method} \title{Combine spam Matrices by Rows or Columns} \description{Take a sequence of vector, matrix or \code{spam} object arguments and combine by \emph{c}olumns or \emph{r}ows, respectively.} \usage{ # cbind(\dots, force64 = getOption("spam.force64"), deparse.level = 0) # rbind(\dots, deparse.level = 0) } \arguments{ \item{...}{vectors, matrices or \code{spam} objects. See \sQuote{Details} and \sQuote{Value}} \item{force64}{logical vector of length 1. If \code{TRUE}, a 64-bit spam matrix is returned in any case. If \code{FALSE}, a 32-bit matrix is returned when possible. } \item{deparse.level}{for compatibility reason here. Only \code{0} is implemented.} } \value{a \code{spam} object combining the \code{\dots} arguments column-wise or row-wise. (Exception: if there are no inputs or all the inputs are \code{NULL}, the value is \code{NULL}.)} \details{\code{rbind} and \code{cbind} are not exactly symmetric in how the objects are processed. The former is essentially an concatenation of the slots due to the sparse storage format. Different types of inputs are handled differently. The latter calls a Fortran routine after the input has been coerced to \code{spam} objects. \cr Only two objects at a time are processed. If more than two are present, a loop concatenates them successively. \cr A method is defined for a \code{spam} object as first argument. } %\references{} %\seealso{\code{\link{cbind,spam-method}}.} \examples{ x <- cbind.spam(1:5,6) y <- cbind(x, 7) rbind( x, x) # for some large matrices t( cbind( t(x), t(x))) # might be slightly faster: } \author{Reinhard Furrer} \keyword{array} \keyword{manip} spam/man/rmvnorm.Rd0000644000176200001440000000565113536451715013775 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/rmvnorm.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{rmvnorm} \alias{rmvnorm.spam} \alias{rmvnorm.prec} \alias{rmvnorm.canonical} \title{Draw Multivariate Normals} \description{ Fast ways to draw multivariate normals when the variance or precision matrix is sparse.} \usage{ rmvnorm.spam(n,mu=rep.int(0, dim(Sigma)[1]), Sigma, Rstruct=NULL, ...) rmvnorm.prec(n,mu=rep.int(0, dim(Q)[1]), Q, Rstruct=NULL, ...) rmvnorm.canonical(n, b, Q, Rstruct=NULL, ...) } \arguments{ \item{n}{number of observations.} \item{mu}{mean vector.} \item{Sigma}{covariance matrix of class \code{spam}.} \item{Q}{precision matrix.} \item{b}{vector determining the mean.} \item{Rstruct}{the Cholesky structure of \code{Sigma} or \code{Q}.} \item{\dots}{arguments passed to \code{chol}.} } \details{The functions \code{rmvnorm.prec} and \code{rmvnorm.canonical} do not require sparse precision matrices. For \code{rmvnorm.spam}, the differences between regular and sparse covariance matrices are too significant to be implemented here. \cr Often (e.g., in a Gibbs sampler setting), the sparsity structure of the covariance/precision does not change. In such setting, the Cholesky factor can be passed via \code{Rstruct} in which only updates are performed (i.e., \code{update.spam.chol.NgPeyton} instead of a full \code{chol}). } %\note{There is intentionally no \acronym{S3} distinction between the classes % \code{spam} and \code{spam.chol.}\emph{method}.} \references{See references in \code{\link{chol}}. } \seealso{\code{\link{chol}} and \code{\link{ordering}}. } \examples{ # Generate multivariate from a covariance inverse: # (usefull for GRMF) set.seed(13) n <- 25 # dimension N <- 1000 # sample size Sigmainv <- .25^abs(outer(1:n,1:n,"-")) Sigmainv <- as.spam( Sigmainv, eps=1e-4) Sigma <- solve( Sigmainv) # for verification iidsample <- array(rnorm(N*n),c(n,N)) mvsample <- backsolve( chol(Sigmainv), iidsample) norm( var(t(mvsample)) - Sigma, type="m") # compare with: mvsample <- backsolve( chol(as.matrix( Sigmainv)), iidsample, n) #### ,n as patch norm( var(t(mvsample)) - Sigma, type="m") # 'solve' step by step: b <- rnorm( n) R <- chol(Sigmainv) norm( backsolve( R, forwardsolve( R, b))- solve( Sigmainv, b) ) norm( backsolve( R, forwardsolve( R, diag(n)))- Sigma ) } % backsolve( chol(as.matrix(V)[ord,ord]),iidsample)[iord,] % \author{Reinhard Furrer} \keyword{algebra} spam/man/apply.Rd0000644000176200001440000000654113536451712013416 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/apply.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{apply} \alias{apply.spam} \title{Apply Functions Over Sparse Matrix Margins} \description{Returns a vector or array or list of values obtained by applying a function to margins of a sparse matrix.} \usage{apply.spam(X, MARGIN=NULL, FUN, ...) } \arguments{ \item{X}{the \code{spam} matrix to be used.} \item{MARGIN}{a vector giving the subscripts which the function will be applied over. \code{1} indicates rows, \code{2} indicates columns, \code{NULL} or \code{c(1,2)} indicates rows and columns.} \item{FUN}{the function to be applied.} \item{...}{optional arguments to \code{FUN}.} } \details{This is a handy wrapper to apply a function to the (nonzero) elements of a sparse matrix. For example, it is possible to apply a covariance matrix to a distance matrix obtained by \code{nearest.dist}, see Examples.\cr A call to \code{apply} only coerces the sparse matrix to a regular one.\cr The basic principle is applying the function to \code{@entries}, or to the extracted columns or rows (\code{[,i,drop=F]} or \code{[i,,drop=F]}). It is important to note that an empty column contains at least one zero value and may lead to non intuitive results.\cr This function may evolve over the next few releases. } \value{Similar as a call to \code{apply} with a regular matrix. The most important cases are as follows. The result is a vector (\code{MARGIN} is length 1 and \code{FUN} is scalar) or a matrix (\code{MARGIN} is length 1 and \code{FUN} returns fixed length vectors, or \code{MARGIN} is length 2 and \code{FUN} is scalar) or a list (if \code{FUN} returns vectors of different lengths).} %\references{} \seealso{\code{base:apply} for more details on Value.} \examples{ S <- as.spam(dist(1:5)) S <- apply.spam(S/2, NULL, exp) # instead of # S@entries <- exp( S@entries/2) # Technical detail, a null matrix consists # of one zero element. apply.spam(S,c(1,2),pmax) apply.spam(S,1,range) # A similar example as for the base apply. # However, no dimnames else we would get warnings. x <- as.spam(cbind(x1 = 3, x2 = c(0,0,0, 5:2))) apply.spam(x, 2, mean, trim = .2) col.sums <- apply.spam(x, 2, sum) row.sums <- apply.spam(x, 1, sum) rbind(cbind(x, row.sums), c(col.sums, sum(col.sums))) apply.spam(x, 2, is.vector) # Sort the columns of a matrix # Notice that the result is a list due to the different # lengths induced by the nonzero elements apply.spam(x, 2, sort) # Function with extra args: cave <- function(x, c1, c2) c(mean(x[c1]), mean(x[c2])) apply(x,1, cave, c1=1, c2=c(1,2)) ma <- spam(c(1:4, 0, 0,0, 6), nrow = 2) ma apply.spam(ma, 1, table) #--> a list of length 2 apply.spam(ma, 1, stats::quantile)# 5 x n matrix with rownames } \author{Reinhard Furrer} \keyword{array} \keyword{algebra} spam/man/circulant.Rd0000644000176200001440000000302613536451713014251 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/circulant.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{circulant} \alias{circulant.spam} \title{Create Circulant Matrices} \description{Creates a circulant matrix in \code{spam} format.} \usage{ circulant.spam(x, n = NULL, eps = getOption("spam.eps")) } \arguments{ \item{x}{the first row to form the circulant matrix or a list containing the indices and the nonzero values.} \item{n}{if \code{x} is a list, the dimension of the matrix.} \item{eps}{A tolerance parameter: elements of \code{x} such that \code{abs(x) <= eps} set to zero. Defaults to \code{eps = getOption("spam.eps")}} } \value{The circulant matrix in \code{spam} format.} %\details{The vector \code{y} has to be of the same length as \code{x} % and its first element is discarded. % } %\references{} \seealso{\code{\link[magic]{circulant}} from package \pkg{magic}, \code{\link{toeplitz.spam}}} \examples{ circulant.spam(c(1,.25,0,0,0)) } \author{Reinhard Furrer} \keyword{array} \keyword{algebra} spam/man/spam.creation.Rd0000644000176200001440000001057313536451715015037 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/spam.creation.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{spam} \alias{spam.creation} \alias{initialize,spam-method} \alias{spam} \alias{spam.list} \alias{spam.numeric} \alias{spam,list-method} \alias{spam,numeric-method} %\alias{spam.spam} %\alias{spam,spam-method} \alias{as.spam,matrix-method} \alias{as.spam,numeric-method} \alias{as.spam,spam-method} \alias{as.spam,dist-method} \alias{as.spam,list-method} \alias{as.spam} \alias{as.spam.spam} \alias{as.spam.numeric} \alias{as.spam.matrix} \alias{as.spam.chol.NgPeyton} \alias{as.spam.dist} \alias{as.spam.list} \alias{is.spam} \title{Sparse Matrix Class} \description{ This group of functions evaluates and coerces changes in class structure. } \usage{ spam(x, nrow = 1, ncol = 1, eps = getOption("spam.eps")) % force64 = getOption("spam.force64")) as.spam(x, eps = getOption("spam.eps")) %, force64 = getOption("spam.force64")) is.spam(x) } \value{ A valid \code{spam} object.\cr \code{is.spam} returns \code{TRUE} if \code{x} is a \code{spam} object.} \arguments{ \item{x}{is a matrix (of either dense or sparse form), a list, vector object or a distance object} \item{nrow}{number of rows of matrix } \item{ncol}{number of columns of matrix } %\item{force64}{logical vector of length 1. If \code{TRUE}, a 64-bit % spam matrix is returned in any case. If \code{FALSE}, a 32-bit % matrix is returned when possible. } \item{eps}{A tolerance parameter: elements of \code{x} such that \code{abs(x) < eps} set to zero. Defaults to \code{eps = getOption("spam.eps")} } } \details{ The functions \code{spam} and \code{as.spam} act like \code{matrix} and \code{as.matrix} to coerce an object to a sparse matrix object of class \code{spam}. If \code{x} is a list, it should contain either two or three elements. In case of the former, the list should contain a \code{n} by two matrix of indicies (called \code{ind}) and the values. In case of the latter, the list should contain three vectors containing the row, column indices (called \code{i} and \code{j}) and the values. In both cases partial matching is done. In case there are several triplets with the same \code{i}, \code{j}, the values are added. \code{eps} should be at least as large as \code{.Machine$double.eps}. If \code{getOption("spam.force64")} is \code{TRUE}, a 64-bit spam matrix is returned in any case. If \code{FALSE}, a 32-bit matrix is returned when possible. } \note{The zero matrix has the element zero stored in (1,1).\cr The functions do not test the presence of \code{NA/NaN/Inf}. Virtually all call a Fortran routine with the \code{NAOK=NAOK} argument, which defaults to \code{FALSE} resulting in an error. Hence, the \code{NaN} do not always properly propagate through (i.e. \code{spam} is not IEEE-754 compliant). } \references{Reinhard Furrer, Stephan R. Sain (2010). "spam: A Sparse Matrix R Package with Emphasis on MCMC Methods for Gaussian Markov Random Fields.", \emph{Journal of Statistical Software}, 36(10), 1-25, \url{http://www.jstatsoft.org/v36/i10/.} } \seealso{ \code{\link{SPAM}} for a general overview of the package; \code{\link{spam_random}} to create matrices with a random sparsity pattern; \code{\link{cleanup}} to purge a sparse matrix; \code{\link{spam.options}} for details about the \code{safemode} flag; \code{\link{read.MM}} and \code{\link{foreign}} to create \code{spam} matrices from MatrixMarket files and from certain \pkg{Matrix} or \pkg{SparseM} formats. } \examples{ # old message, do not loop, when you create a large sparse matrix set.seed(13) nz <- 128 ln <- nz^2 smat <- spam(0,ln,ln) is <- sample(ln,nz) js <- sample(ln,nz) system.time(for (i in 1:nz) smat[is[i], js[i]] <- i) system.time(smat[cbind(is,js)] <- 1:nz) getClass("spam") options(spam.NAOK=TRUE) as.spam(c(1, NA)) } \author{Reinhard Furrer} \keyword{algebra} spam/man/validate_spam.Rd0000644000176200001440000000174513536451716015107 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/validate_spam.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{validate_spam} \alias{validate_spam} \title{Validate a spam objects} \description{Checks if the spam object has the correct structure.} \usage{ validate_spam(object) } \arguments{ \item{object}{a spam matrix.} } \value{Returns \code{TRUE} if \code{object} is a valid spam objects. } \seealso{\code{\link{spam.creation}}} \examples{ validate_spam(spam(1, 20)) } spam/man/spam.chol.NgPeyton-class.Rd0000644000176200001440000001124113536451715017016 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/spam.chol.NgPeyton-class.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{spam.chol.NgPeyton-class} \docType{class} \alias{spam.chol.NgPeyton-class} \alias{as.matrix,spam.chol.NgPeyton-method} \alias{as.spam,spam.chol.NgPeyton-method} \alias{backsolve,spam.chol.NgPeyton-method} \alias{c,spam.chol.NgPeyton-method} \alias{determinant,spam.chol.NgPeyton-method} \alias{diag,spam.chol.NgPeyton-method} \alias{dim<-,spam.chol.NgPeyton-method} \alias{dim,spam.chol.NgPeyton-method} \alias{display,spam.chol.NgPeyton-method} \alias{forwardsolve,spam.chol.NgPeyton-method} \alias{image,spam.chol.NgPeyton-method} \alias{length<-,spam.chol.NgPeyton-method} \alias{length,spam.chol.NgPeyton-method} \alias{ordering,spam.chol.NgPeyton-method} \alias{print,spam.chol.NgPeyton-method} \alias{show,spam.chol.NgPeyton-method} \alias{summary,spam.chol.NgPeyton-method} \alias{t,spam.chol.NgPeyton-method} \alias{chol,spam.chol.NgPeyton-method} \title{Class "spam.chol.NgPeyton"} \description{Result of a Cholesky decomposition with the \code{NgPeyton} method} \section{Objects from the Class}{ Objects are created by calls of the form \code{chol(x,method="NgPeyton", ...)} and should not be created directly with a \code{new("spam.chol.NgPeyton", ...)} call.\cr At present, no proper print method is defined. However, the factor can be transformed into a \code{spam} object. } \section{Methods}{ \describe{ \item{as.matrix}{\code{signature(x = "spam.chol.NgPeyton")}: Transform the factor into a regular matrix. } \item{as.spam}{\code{signature(x = "spam.chol.NgPeyton")}: Transform the factor into a \code{spam} object.} \item{backsolve}{\code{signature(r = "spam.chol.NgPeyton")}: solving a triangular system, see \code{\link{solve}}. } \item{forwardsolve}{\code{signature(l = "spam.chol.NgPeyton")}: solving a triangular system, see \code{\link{solve}}. } \item{c}{\code{signature(x = "spam.chol.NgPeyton")}: Coerce the factor into a vector. } \item{determinant}{\code{signature(x = "spam.chol.NgPeyton")}: Calculates the determinant from the factor, see also \code{\link{det}}. } \item{diag}{\code{signature(x = "spam.chol.NgPeyton")}: Extracts the diagonal entries.} % \item{dim<-}{\code{signature(x = "spam.chol.NgPeyton")}: ... } \item{dim}{\code{signature(x = "spam.chol.NgPeyton")}: Retrieve the dimension. Note that \code{"dim<-"} is not implemented.} \item{display}{\code{signature(x = "spam.chol.NgPeyton")}: Transformation to a \code{spam} object and display, see also \code{\link{display}}. } \item{image}{\code{signature(x = "spam.chol.NgPeyton")}: Transformation to a \code{spam} object and display, see also \code{\link{image}}. } % \item{length<-}{\code{signature(x = "spam.chol.NgPeyton")}: ... } \item{length}{\code{signature(x = "spam.chol.NgPeyton")}: Retrieve the dimension. Note that \code{"length<-"} is not implemented. } \item{ordering}{\code{signature(x = "spam.chol.NgPeyton")}: Retrieves the ordering, in \code{\link{ordering}}. } \item{print}{\code{signature(x = "spam.chol.NgPeyton")}: Short description. } \item{show}{\code{signature(object = "spam.chol.NgPeyton")}: Short description. } \item{summary}{\code{signature(object = "spam.chol.NgPeyton")}: Description of the factor, returns (as a list) \code{nnzR}, \code{nnzcolindices}, the density of the factor \code{density}, and fill-in ratio \code{fillin}. For the use of the first two, see \sQuote{Examples} in \code{\link{chol}}.} \item{t}{\code{signature(x = "spam.chol.NgPeyton")}: Transformation to a \code{spam} object and transposition. } \item{chol}{\code{signature(x = "spam.chol.NgPeyton")}: Returns \code{x} unchanged. } } } \references{Ng, E. G. and B. W. Peyton (1993), "Block sparse Cholesky algorithms on advanced uniprocessor computers", \emph{SIAM J. Sci. Comput.}, \bold{14}, pp. 1034-1056. } \author{Reinhard Furrer} \seealso{\code{\link{print.spam}} \code{\link{ordering}} and \code{\link{chol}}} \examples{ x <- spam( c(4,3,0,3,5,1,0,1,4),3) cf <- chol( x) cf as.spam( cf) # Modify at own risk... slotNames(cf) } \keyword{classes} spam/man/bandwidth.Rd0000644000176200001440000000237313536451713014235 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/bandwidth.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{bandwidth} \alias{bandwidth} \title{Bandwidth of a Sparse Matrix} \description{Returns the lower and upper bandwidth of a sparse matrix} \usage{ bandwidth(A) } \arguments{ \item{A}{spam object} } \details{The matrix does not need to be diagonal. Values can be negative indicating the the matrix contains a band cinfined in the upper or lower triangular part. } \value{Integer vector containing the lower and upper bandwidth} %\references{} \seealso{ \code{\link{diag.spam}}. } \examples{ bandwidth(spam(c(0, 1), 3, 2)) bandwidth(spam(c(0, 0, 1, rep(0, 9)), 4, 3)) } \author{Reinhard Furrer} \keyword{array} \keyword{algebra} spam/man/toeplitz.Rd0000644000176200001440000000271413536451715014144 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/toeplitz.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{toeplitz} \alias{toeplitz.spam} \title{Create Toeplitz Matrices} \description{Creates symmetric and asymmetric Toeplitz matrices.} \usage{ toeplitz.spam(x, y = NULL, eps = getOption("spam.eps")) } \arguments{ \item{x}{the first row to form the Toeplitz matrix.} \item{y}{for asymmetric Toeplitz matrices, this contains the first column.} \item{eps}{A tolerance parameter: elements of \code{x} such that \code{abs(x) <= eps} set to zero. Defaults to \code{eps = getOption("spam.eps")}.} } \value{The Toeplitz matrix in \code{spam} format.} \details{The vector \code{y} has to be of the same length as \code{x} and its first element is discarded. } %\references{} \seealso{\code{\link{toeplitz}}, \code{\link{circulant.spam}}} \examples{ toeplitz.spam(c(1,.25,0,0,0)) } \author{Reinhard Furrer} \keyword{array} \keyword{algebra} spam/man/nearestdist.Rd0000644000176200001440000001146013536451714014614 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/nearestdist.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{nearestdist} \alias{dist.spam} \alias{nearest.dist} \alias{distance} \title{Distance Matrix Computation} \description{This function computes and returns specific elements of distance matrix computed by using the specified distance measure.} \usage{ nearest.dist( x, y=NULL, method = "euclidean", delta = 1, upper = if (is.null(y)) FALSE else NULL, p=2, miles=TRUE, R=NULL) } \arguments{ \item{x}{Matrix of first set of locations where each row gives the coordinates of a particular point. See also \sQuote{Details}.} \item{y}{Matrix of second set of locations where each row gives the coordinates of a particular point. If this is missing \code{x} is used. See also \sQuote{Details}.} \item{method}{the distance measure to be used. This must be one of \code{"euclidean"}, \code{"maximum"}, \code{"minkowski"} or \code{"greatcircle"}. Any unambiguous substring can be given.} \item{delta}{only distances smaller than \code{delta} are recorded, see Details.} \item{upper}{Should the entire matrix (\code{NULL}) or only the upper-triagonal (\code{TRUE}) or lower-triagonal (\code{FALSE}) values be calculated.} \item{p}{The power of the Minkowski distance.} \item{miles}{For great circle distance: If true distances are in statute miles if false distances in kilometers.} \item{R}{For great circle distance: Radius to use for sphere to find spherical distances. If \code{NULL} the radius is either in miles or kilometers depending on the values of the miles argument. If \code{R=1} then distances are of course in radians.} % \item{eps}{deprecated. Left for backwards consistency.} % \item{diag}{deprecated. Left for backwards consistency. See \sQuote{Details}.} } \value{A \code{spam} object containing the distances spanned between zero and \code{delta}. The sparse matrix may contain many zeros (e.g., collocated data). However, to calculate covariances, these zeros are essential.} \details{For great circle distance, the matrices \code{x} and \code{y} contain the degrees longitudes in the first and the degrees latitudes in the second column. \code{eps} and \code{delta} are in degrees. Hence to restrict to distances smaller than \code{delta.km}, one has to specify \code{delta=delta.km*360/(6378.388*2*pi)}. The distances are calculated based on spherical law of cosines. Care is needed for `zero' distances due to the final acosin: \code{acos(1-1e-16)}, especially with an actual radius. % The distance is % in single precision (I am still not sure where I lose the double precision in % the Fortran code) and if calculating the entire matrix % \code{upper=NULL} (instead of adding its transpose) it may not % pass the symmetry checks, for example.\cr Default value of Earth's radius is 3963.34miles (6378.388km).\cr There are many other packages providing distance functions. Especially for great circle distances there are considerable differences between the implementations. For high precision results, \code{sp::spDists} is a good candidate. \cr The formerly depreciated arguments \code{eps} and \code{diag} are now eliminated. \code{x} and \code{y} can be any object with an existing \code{as.matrix} method.\cr % A quick scan revealed distance functions in at least 7 packages % (around 2008). The argument names should be as general as possible and % be coherent with many (but not all) available distance functions.\cr The Fortran code is based on a idea of Doug Nychka. } %\references{} \seealso{\code{\link{spam_rdist}}} \examples{ # Note that upper=T and using t(X)+X is quicker than upper=NULL; # upper=T marginally slower than upper=F. # To compare nearest.dist with dist, use as.dist(...) nx <- 4 x <- expand.grid(as.double(1:nx),as.double(1:nx)) sum( ( as.dist(nearest.dist( x, delta=nx*2))- dist(x) )^2) # Create nearest neighbor structures: par(mfcol=c(1,2)) x <- expand.grid(1:nx,1:(2*nx)) display( nearest.dist( x, delta=1)) x <- expand.grid(1:(2*nx),1:nx) display( nearest.dist( x, delta=1)) } \author{Reinhard Furrer} \keyword{array} \keyword{algebra} spam/man/det.Rd0000644000176200001440000000560013536451713013041 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/det.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{det} \alias{det,spam-method} \alias{det,spam.chol.NgPeyton-method} \alias{det.spam} \alias{det} \alias{determinant} %\alias{determinant,spam.chol.NgPeyton-method} \alias{determinant,spam-method} \alias{determinant.spam} \alias{determinant.spam.chol} \alias{determinant.spam.chol.NgPeyton} \title{Calculate the determinant of a positive definite Sparse Matrix} \description{\code{det} and \code{determinant} calculate the determinant of a positive definite sparse matrix. \code{determinant} returns separately the modulus of the determinant, optionally on the logarithm scale, and the sign of the determinant. } \usage{ det(x, ...) determinant(x, logarithm = TRUE, ...) } \arguments{ \item{x}{sparse matrix of class \code{spam} or a Cholesky factor of class \code{spam.chol.NgPeyton}.} \item{logarithm}{logical; if \code{TRUE} (default) return the logarithm of the modulus of the determinant.} \item{...}{Optional arguments. Examples include \code{method} argument and additional parameters used by the method.} } \value{For \code{det}, the determinant of \code{x}. For \code{determinant}, a list with components \item{modulus}{a numeric value. The modulus (absolute value) of the determinant if \code{logarithm} is \code{FALSE}; otherwise the logarithm of the modulus.} \item{sign}{integer; either +1 or -1 according to whether the determinant is positive or negative.} } \details{If the matrix is not positive definite, the function issues a warning and returns \code{NA}. The determinant is based on the product of the diagonal entries of a Cholesky factor, i.e. internally, a Cholesky decomposition is performed. By default, the NgPeyton algorithm with minimal degree ordering us used. To change the methods or supply additonal parameters to the Cholesky factorization function, see the help for \code{\link{chol}}. The determinant of a Cholesky factor is also defined. } \references{ Ng, E. G. and B. W. Peyton (1993) Block sparse Cholesky algorithms on advanced uniprocessor computers, \emph{SIAM J. Sci. Comput.}, \bold{14}, 1034--1056. } \seealso{\code{\link{chol.spam}} } \examples{ x <- spam( c(4,3,0,3,5,1,0,1,4),3) det( x) determinant( x) det( chol( x)) } \author{Reinhard Furrer} \keyword{array} \keyword{algebra} spam/man/operations.Rd0000644000176200001440000001352713536451714014460 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/operations.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{spam operations} \alias{Ops.spam} \alias{spam.ops} \alias{\%*\%-methods} \alias{\%*\%,ANY,ANY-method} \alias{\%*\%,spam,spam-method} \alias{\%*\%,spam,matrix-method} \alias{\%*\%,spam,numeric-method} \alias{\%*\%,matrix,spam-method} \alias{\%*\%,numeric,spam-method} \alias{\%d*\%} \alias{\%d*\%,spam,spam-method} \alias{\%d*\%,spam,ANY-method} \alias{\%d*\%,matrix,spam-method} \alias{\%d*\%,matrix,ANY-method} \alias{\%d*\%,spam,numeric-method} \alias{\%d*\%,numeric,spam-method} \alias{\%d*\%,numeric,matrix-method} \alias{\%d*\%,numeric,numeric-method} \alias{\%d+\%} \alias{\%d+\%,spam,spam-method} \alias{\%d+\%,spam,ANY-method} \alias{\%d+\%,matrix,spam-method} \alias{\%d+\%,matrix,ANY-method} \alias{\%d+\%,spam,numeric-method} \alias{\%d+\%,numeric,matrix-method} \alias{\%d+\%,numeric,spam-method} \alias{\%d+\%,numeric,numeric-method} \alias{+,spam,spam-method} \alias{+,matrix,spam-method} \alias{+,spam,matrix-method} \alias{+,ANY,spam-method} \alias{+,spam,ANY-method} \alias{-,spam,spam-method} \alias{-,matrix,spam-method} \alias{-,spam,matrix-method} \alias{-,ANY,spam-method} \alias{-,spam,ANY-method} \alias{*,spam,spam-method} \alias{*,ANY,spam-method} \alias{*,spam,ANY-method} \alias{/,spam,spam-method} \alias{/,ANY,spam-method} \alias{/,spam,ANY-method} \alias{^,spam,spam-method} \alias{^,ANY,spam-method} \alias{^,spam,ANY-method} \alias{&,spam,ANY-method} \alias{&,spam,spam-method} \alias{&,ANY,spam-method} \alias{|,spam,ANY-method} \alias{|,ANY,spam-method} \alias{|,spam,spam-method} \alias{^,spam-method} \alias{\%\%,spam-method} \alias{\%/\%,spam-method} \alias{>,spam-method} \alias{>=,spam-method} \alias{<,spam-method} \alias{<=,spam-method} \alias{==,spam-method} \alias{!=,spam-method} \alias{norm} \alias{norm.spam} \alias{norm,ANY-method} \alias{norm,spam,character-method} \alias{norm,spam,missing-method} \alias{norm,numeric,missing-method} \alias{norm,numeric,character-method} \alias{norm,matrix,missing-method} \alias{norm,matrix,character-method} %\alias{t,ANY-method} \alias{t.spam} \alias{ncol,spam-method} \alias{nrow,spam-method} \alias{dim,ANY-method} \alias{dim,spam-method} \alias{[.spam} \alias{[<-.spam} \alias{[<-,spam,missing,missing-method} \alias{[<-,spam,missing,vector-method} \alias{[<-,spam,vector,missing-method} \alias{[<-,spam,vector,vector-method} \alias{[<-,spam,matrix,missing-method} \alias{[<-,spam,matrix,matrix-method} \alias{[<-,spam,spam,missing-method} \alias{[<-,spam,ANY,ANY-method} \alias{plot.spam} \alias{subset.spam} \alias{assign.spam} \title{Basic Linear Algebra for Sparse Matrices} \description{Basic linear algebra operations for sparse matrices of class \code{spam}. } %\usage{x \%*\% y %y \%d*\% x %y \%d+\% x %x[i,] %... %} %\arguments{ %\item{x}{matrix of class \code{spam}.} %\item{y}{matrix of class \code{spam} or a dense matrix or vector.} %\item{value}{replacement values.} %\item{i,j}{vectors of elements to extract or replace.} %\item{nrow}{optional number of rows for the result.} %} \details{Linear algebra operations for matrices of class \code{spam} are designed to behave exactly as for regular matrices. In particular, matrix multiplication, transpose, addition, subtraction and various logical operations should work as with the conventional dense form of matrix storage, as does indexing, rbind, cbind, and diagonal assignment and extraction (see for example \code{\link{diag}}). Further functions with identical behavior are \code{dim} and thus \code{nrow}, \code{ncol}. The function \code{norm} calculates the (matrix-)norm of the argument. The argument \code{type} specifies the \code{l1} norm, \code{sup} or max norm (default), or the Frobenius or Hilbert-Schmidt (\code{frobenius/hs}) norm. Partial matching can be used. For example, \code{norm} is used to check for symmetry in the function \code{chol} by computing the norm of the difference between the matrix and its transpose The operator \code{\%d*\%} efficiently multiplies a diagonal matrix (in vector form) and a sparse matrix and is used for compatibility with the package fields. More specifically, this method is used in the internal functions of \code{Krig} to make the code more readable. It avoids having a branch in the source code to handle the diagonal or nondiagonal cases. Note that this operator is not symmetric: a vector in the left argument is interpreted as a diagonal matrix and a vector in the right argument is kept as a column vector. The operator \code{\%d+\%} efficiently adds a diagonal matrix (in vector form) and a sparse matrix, similarly to the operator \code{\%d+\%}. } \references{Some Fortran functions are based on \url{http://people.sc.fsu.edu/~jburkardt/f_src/sparsekit/sparsekit.html} } \seealso{ \code{\link{spam}} for coercion and other class relations involving the sparse matrix classes. } \examples{ # create a weight matrix and scale it: \dontrun{ wij <- distmat # with distmat from a nearest.dist(..., upper=TRUE) call n <- dim(wij)[1] wij@entries <- kernel( wij@entries, h) # for some function kernel wij <- wij + t(wij) + diag.spam(n) # adjust from diag=FALSE, upper=TRUE sumwij <- wij \%*\% rep(1,n) # row scaling: # wij@entries <- wij@entries/sumwij[ wij@colindices] # col scaling: wij@entries <- wij@entries/sumwij[ rep(1:n, diff(wij@rowpointers))] } } \keyword{algebra} spam/man/adjacency.Rd0000644000176200001440000000316713536451712014213 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/adjacency.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{adjacency} \alias{adjacency} \alias{adjacency.spam} \alias{adjacency.landkreis} \alias{germany.graph} \title{Administrative districts of Germany} \description{Constructing the adjacency graph of the administrative districts of Germany} \usage{ adjacency.landkreis( loc) } \arguments{ \item{loc}{location of the graph structure, can be an URL.} } \details{The function is included as an example on how to construct adjacency matrices form a (common) adjacency structure. For the particular example, note that the nodes are not numbered consecutively and that they start from zero.} \value{a sparse matrix in \code{spam} format.} \references{The adjacency data has been provided by Havard Rue and is also available in \pkg{INLA}.} \seealso{\code{\link{germany.plot}} super-seeding \code{map.landkreis} for plotting.\cr \code{\link{Oral}}.} \examples{ \dontrun{ loc <- system.file("demodata/germany.adjacency", package="spam") display( adjacency.landkreis( loc)) } } \author{Reinhard Furrer} \keyword{hplot} spam/man/version.Rd0000644000176200001440000000342713536451716013762 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/version.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{version} \alias{version} \alias{spam.version} \alias{spam.Version} \title{Spam Version Information} \description{ \code{spam.version} is a variable (\code{list}) holding detailed information about the version of \code{spam} loaded. \code{spam.Version()} provides detailed information about the version of \code{spam} running. } \usage{ spam.version } \value{\code{spam.version} is a list with character-string components \item{status}{the status of the version (e.g., \code{"beta"})} \item{major}{the major version number} \item{minor}{the minor version number} \item{year}{the year the version was released} \item{month}{the month the version was released} \item{day}{the day the version was released} \item{version.string}{a \code{character} string concatenating the info above, useful for plotting, etc.} \code{spam.version} is a list of class \code{"simple.list"} which has a \code{print} method. } % \references{} \seealso{See the R counterparts \code{\link[base]{R.version}}. } \author{Reinhard Furrer} \examples{ spam.version$version.string } \keyword{environment} \keyword{sysdata} \keyword{programming} spam/man/foreign.Rd0000644000176200001440000000501613536451713013717 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/foreign.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{foreign} \alias{foreign} \alias{as.spam.matrix.csr} %\alias{as.matrix.csr.spam} \alias{as.dgRMatrix.spam} \alias{as.dgCMatrix.spam} \alias{as.spam.dgRMatrix} \alias{as.spam.dgCMatrix} \title{Transformation to other sparse formats} \description{Transform between the \code{spam} sparse format to the \code{matrix.csr} format of \code{SparseM} and \code{dgRMatrix} format of \code{Matrix}} \usage{ as.spam.matrix.csr(x) as.dgRMatrix.spam(x) as.dgCMatrix.spam(x) as.spam.dgRMatrix(x) as.spam.dgCMatrix(x) } \arguments{ \item{x}{sparse matrix of class \code{spam}, \code{matrix.csr}, \code{dgRMatrix} or \code{dgCMatrix}.} } \value{According to the call, a sparse matrix of class \code{spam}, \code{matrix.csr}, \code{dgRMatrix} or \code{dgCMatrix}.} \details{ We do not provide any \code{S4} methods and because of the existing mechanism a standard \code{S3} does not work.\cr The functions are based on \code{require}.\cr Notice that \code{as.matrix.csr.spam} should read as \code{as."matrix.csr".spam}. } %\references{} \seealso{ \code{\link{triplet}}, \code{\link[Matrix]{Matrix}} or \code{\link[SparseM]{matrix.csr}}} \examples{ \dontrun{ S <- diag.spam(4) R <- as.dgRMatrix.spam( S) C <- as.dgCMatrix.spam( S) as.spam.dgCMatrix(C) slotNames(U) slotNames(R) # For column oriented sparse formats a transpose does not the job, # as the slot names change. # as.spam(R) does not work. } \dontrun{ # for transformations between SparseM and spam: as.matrix.csr.spam <- function(x,...) { newx <- new("matrix.csr") slot(newx,"ra",check=FALSE) <- x@entries slot(newx,"ja",check=FALSE) <- x@colindices slot(newx,"ia",check=FALSE) <- x@rowpointers slot(newx,"dimension",check=FALSE) <- x@dimension return(newx) } U <- as.matrix.csr.spam( S) } \dontrun{ # a dataset contained in Matrix data(KNex) as.spam.dgCMatrix(KNex$mm) } } \author{Reinhard Furrer} \keyword{array} \keyword{manip} spam/man/eigen.Rd0000644000176200001440000001357613565764566013406 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/eigen.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{eigen} \alias{eigen.spam} \alias{eigen_approx} \title{Eigenvalues for Sparse Matrices} \description{ Functions to calculate eigenvalues and eigenvectors of \code{sparse} matrices. It uses the value of \code{spam.options("inefficiencywarning")} to dispatch between \code{base::eigen()} or the Implicitly Restarted Arnoldi Process, using 'ARPACK'. \code{eigen.spam} is a wrapper function of \code{eigen_approx} and transforms its output to \code{base::eigen} like. } \note{ The user is advised to choose the \code{control} options carefully, see \sQuote{Details} for more information. } \usage{ eigen.spam(x, nev = 10, symmetric, only.values = FALSE, control = list()) eigen_approx(x, nev, ncv, nitr, mode, only.values = FALSE, verbose = FALSE, f_routine) } \arguments{ \item{x}{a matrix of class \code{spam} whose \code{nev} eigenvalues and eigenvectors are to be computed.} \item{nev}{number of eigenvalues to calculate.} \item{symmetric}{if TRUE, the matrix is assumed to be symmetric.} \item{only.values}{if TRUE, only \code{nev} eigenvalues are computed and returned, otherwise \code{nev} eigenvalues and eigenvectors are returned.} \item{control}{additional options, see \sQuote{Details}.} \item{ncv}{see \sQuote{Details}, use the \code{control} option for \code{eigen.spam}.} \item{nitr}{see \sQuote{Details}, use the \code{control} option for \code{eigen.spam}.} \item{mode}{see \sQuote{Details}, use the \code{control} option for \code{eigen.spam}.} \item{verbose}{see \sQuote{Details}, use the \code{control} option for \code{eigen.spam}.} \item{f_routine}{only for \code{eigen_approx}, to call the Fortran routine for symmetric matrices set this option to "ds_eigen_f" and for non symmetric to "dn_eigen_f".} } \value{ A vector of the length corresponding to the dimension of the input matrix. Containing the required \code{nev} eigenvalues. If requested also the corresponding eigenvectors. In the non symmetric case, the eigenvalues are returned in a matrix with a column containing the real parts and a column containing the imaginary parts of the eigenvalues. The eigenvectors are then returned in two matrices.} \details{ \describe{ \item{\code{mode = "LM"}:}{ there are different modes available for this function, each mode returns a different range of eigenvalues. Also the available modes are dependent, whether the input matrix is symmetric or not: \describe{ \item{\code{"LM"}:}{Eigenvalues with largest magnitude (sym, non sym), that is, largest eigenvalues in the Euclidean norm of complex numbers.} \item{\code{"SM"}:}{Eigenvalues with smallest magnitude (sym, non sym), that is, smallest eigenvalues in the Euclidean norm of complex numbers.} \item{\code{"LR"}:}{Eigenvalues with largest real part (non sym).} \item{\code{"SR"}:}{Eigenvalues with smallest real part (non sym).} \item{\code{"LI"}:}{Eigenvalues with largest imaginary part (non sym).} \item{\code{"SI"}:}{Eigenvalues with smallest imaginary part (non sym).} \item{\code{"LA"}:}{Eigenvalues with largest algebraic value (sym), that is, largest eigenvalues inclusive of any negative sign.} \item{\code{"SA"}:}{Eigenvalues with smallest algebraic value (syn), that is, smallest eigenvalues inclusive of any negative sign.} }% describe }% item \item{\code{ncv}:}{ the largest number of basis vectors that will be used in the Implicitly Restarted Arnoldi Process. Work per major iteration is proportional to x@dimension[1]*ncv*ncv. The default is set if \code{symmetric} to min(x@dimension[1] + 1, max(2 * nev + 1, 200)) or else to min(x@dimension[1] - 1, max(2 * nev + 1, 100)). Note, this value should not be chosen arbitrary large, but slightly larger than \code{nev}. Otherwise it could lead to memory allocation problems.} \item{\code{nitr}:}{ the maximum number of iterations. The default is set to \code{ncv + 1000}} \item{\code{spamflag = FALSE}:}{ if TRUE, the Implicitly Restarted Arnoldi Process is used, independent of the dimension of the respective matrix.} \item{\code{verbose = FALSE}:}{ print additional information.} \item{\code{cmplxeps}:}{ threshold to determine whether a double value is zero, while transforming the ARPACK output to R class complex. The default is set to \code{.Machine$double.eps}.} }% describe }% details \references{Lehoucq, R. B. and Sorensen, D. C. and Yang, C. (1997) \emph{ARPACK Users Guide: Solution of Large Scale Eigenvalue Problems by Implicitly Restarted Arnoldi Methods}.} \seealso{Option \code{"inefficiencywarning"} in \code{\link{spam.options}} and \code{\link{spam_random}}. } \examples{ set.seed(81) rspam <- spam_random(50^2, density = .0001, spd = TRUE) SPD <- eigen.spam(rspam, nev = 20, control = list(mode = "SM"), only.values = TRUE) tail(SPD$values, 20) isSymmetric(rspam) # hence the matrix is symmetric positiv definit rspam2 <- spam_random(50^2, density = .0001, spd = FALSE, sym = TRUE, distribution = rpois, lambda = 2) SNPDF <- eigen.spam(rspam2, nev = 20, control = list(mode = "SM"), only.values = TRUE) tail(SNPDF$values, 20) isSymmetric(rspam2) # hence the matrix is symmetric but not positiv definit } \author{Roman Flury, Reinhard Furrer} \keyword{algebra} spam/man/rmvnorm.const.Rd0000644000176200001440000000504013536451715015112 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/rmvnorm.const.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{rmvnorm.const} \alias{rmvnorm.const} \alias{rmvnorm.prec.const} \alias{rmvnorm.canonical.const} \title{Draw Constrainted Multivariate Normals} \description{ Fast ways to draw multivariate normals with linear constrains when the variance or precision matrix is sparse.} \usage{ rmvnorm.const(n, mu = rep.int(0, dim(Sigma)[1]), Sigma, Rstruct = NULL, A = array(1, c(1,dim(Sigma)[1])), a=0, U=NULL, ...) rmvnorm.prec.const(n, mu = rep.int(0, dim(Q)[1]), Q, Rstruct = NULL, A = array(1, c(1,dim(Q)[1])), a=0, U=NULL, ...) rmvnorm.canonical.const(n, b, Q, Rstruct = NULL, A = array(1, c(1,dim(Q)[1])), a=0, U=NULL, ...) } \arguments{ \item{n}{number of observations.} \item{mu}{mean vector.} \item{Sigma}{covariance matrix of class \code{spam}.} \item{Q}{precision matrix.} \item{b}{vector determining the mean.} \item{Rstruct}{the Cholesky structure of \code{Sigma} or \code{Q}.} \item{A}{Constrain matrix.} \item{a}{Constrain vector.} \item{U}{see below.} \item{\dots}{arguments passed to \code{chol}.} } \details{The functions \code{rmvnorm.prec} and \code{rmvnorm.canonical} do not requrie sparse precision matrices. For \code{rmvnorm.spam}, the differences between regular and sparse covariance matrices are too significant to be implemented here. \cr Often (e.g., in a Gibbs sampler setting), the sparsity structure of the covariance/precision does not change. In such setting, the Cholesky factor can be passed via \code{Rstruct} in which only updates are performed (i.e., \code{update.spam.chol.NgPeyton} instead of a full \code{chol}). } %\note{There is intentionally no \acronym{S3} distinction between the classes % \code{spam} and \code{spam.chol.}\emph{method}.} \references{See references in \code{\link{chol}}. } \seealso{\code{\link{rmvnorm.spam}}. } \examples{ # to be filled in } % backsolve( chol(as.matrix(V)[ord,ord]),iidsample)[iord,] % \author{Reinhard Furrer} \keyword{algebra} spam/man/cov.Rd0000644000176200001440000000575113536451713013063 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/cov.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{covmat} \alias{covmat} \alias{cov.exp} \alias{cov.sph} \alias{cov.nug} \alias{cov.wu1} \alias{cov.wu2} \alias{cov.wu3} \alias{cov.wend1} \alias{cov.wend2} \alias{cov.mat} \title{Covariance functions} \description{ Evaluate a covariance function.} \usage{ covmat(h, theta, ... , type="sph") cov.exp(h, theta, ... , eps= getOption("spam.eps")) cov.sph(h, theta, ... , eps= getOption("spam.eps")) cov.nug(h, theta, ... , eps= getOption("spam.eps")) cov.wu1(h, theta, ... , eps= getOption("spam.eps")) cov.wu2(h, theta, ... , eps= getOption("spam.eps")) cov.wu3(h, theta, ... , eps= getOption("spam.eps")) cov.wend1(h, theta, ... , eps= getOption("spam.eps")) cov.wend2(h, theta, ... , eps= getOption("spam.eps")) cov.mat(h, theta, ... , eps= getOption("spam.eps")) } \arguments{ \item{h}{object containing the lags.} \item{theta}{parameter of the covariance function, see \sQuote{Details}.} \item{type}{covariance function specification.} \item{\dots}{arguments passed from other methods.} \item{eps}{tolerance level.} } \details{\code{covmat} is a wrapper that calls the other functions according to the argument \code{type}. The nomenclature is similar to \code{premat} \cr The parametrization is (range, partial- sill, [smoothness = 1], [nugget = 0]), where only the range needs to be specified. In case of negative parameter values, a warning is issued and the absolute value is retained. Although more cryptic, having all arguments as a single vector simplifies optimization with \code{optim}. \cr Currently, the functions distinguish between a sparse \code{spam} object \code{h} and any other numeric type. In the future, this might change and appropriate methods will be implemented. } \value{Covariance function evaluated on \code{h}.} %\note{There is intentionally no \acronym{S3} distinction between the classes % \code{spam} and \code{spam.chol.}\emph{method}.} \references{Any classical book about geostatistics.} \seealso{\code{\link{precmat}}.} \examples{ locs <- cbind(runif(10),runif(10)) h <- nearest.dist(locs, delta=.3) Sigma <- cov.sph(h, c(.3, 1, .1)) \dontrun{ h <- seq(0, to=1, length.out=100) plot( h, cov.exp(h, c(1/3,1)), type='l', ylim=c(0,1)) type <- c("sph","wendland1","wendland2","wu1","wu2","wu3") for (i in 1:6) lines( h, covmat(h, 1, type=type[i]), col=i+1) legend('topright',legend=type, col=2:7, lty=1) } } \author{Reinhard Furrer} \keyword{algebra} spam/man/image.Rd0000644000176200001440000000441313536451714013351 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/image.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{image} \alias{image.spam} \alias{image.spam.chol} \alias{image,spam-method} %\alias{image,spam.chol.NgPeyton-method} \title{Display a spam Object as Color Image} \description{The function creates a grid of colored rectangles with colors corresponding to the values in \code{z}. } \usage{ \S4method{image}{spam}(x, cex = NULL, ...) } \arguments{\item{x}{matrix of class \code{spam} or \code{spam.chol.NgPeyton}.} \item{cex}{for very large matrices, the dot size may need to be scaled.} \item{...}{any other arguments passed to \code{image.default} and \code{plot}.} } %\value{} \details{\code{getOption("spam.imagesize")} determines if the sparse matrix is coerced into a matrix and the plotted similarly to \code{image.default} or if the matrix is simply represented as a scatterplot with \code{pch="."}. The points are scaled according to \code{cex*getOption("spam.cex")/(nrow+ncol)}. For some devices or for non-square matrices, \code{cex} needs probably some adjustment.\cr The a zero matrix in \code{spam} format has as (1,1) entry the value zero and only missing entries are interpreted as \code{NA} in the scatter plot. } %\references{} \seealso{\code{\link{display}} and \code{\link{spam.options}}.\cr The code is based on \code{\link[graphics]{image}} of \code{graphics}. } \examples{ set.seed(13) smat <- spam_random(8) par(mfcol=c(1,2),pty='s') options(spam.imagesize=1000) image(smat) # or use better color schemes options(spam.imagesize=10) image(smat, cex=.25) smat <- spam_random(2^14, distribution=rnorm, density=1e-5, verbose=TRUE) par(mfcol=c(1,1), mai=c(.4,.4,.1,.1), pty='s') image(smat) } \author{Reinhard Furrer} \keyword{hplot} spam/man/math2.Rd0000644000176200001440000000310313536451714013275 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/math2.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{Math2} \alias{Math2.spam} \alias{Math2,spam-method} \alias{Math2,spam,numeric-method} \alias{round,spam-method} \alias{signif,spam-method} \alias{round.spam} \alias{signif.spam} \title{Rounding of Numbers} \description{Applies the \code{Math2} group functions to '\code{spam}' objects } \usage{\S4method{round}{spam}(x, digits = 0) \S4method{signif}{spam}(x, digits = 6) } \arguments{\item{x}{spam object.} \item{digits}{integer indicating the precision to be used.} } \value{All functions operate on the vector \code{x@entries} and return the result thereof. } %\details{% Is implemented for R>=2.3.x only. However, % it would be possible to use Martin's proposed workaround: % \url{http://tolstoy.newcastle.edu.au/R/help/05/12/18192.html} %\references{ %} \seealso{\code{\link{Ops.spam}} and \code{\link{Math.spam}}} \examples{ getGroupMembers("Math2") smat <- diag.spam( rnorm(15)) round(smat, 3) } \author{Reinhard Furrer} \keyword{manip} % "round" "signif" spam/man/landkreis.Rd0000644000176200001440000000411413536451714014241 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/landkreis.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{map.landkreis} \alias{map.landkreis} \title{Administrative districts of Germany} \description{Displaying data over the administrative districts of Germany} \usage{ map.landkreis(data, col=NULL, zlim=range(data), add=FALSE, legendpos=c( 0.88,0.9,0.05,0.4)) } \arguments{ \item{data}{vector of length 544} \item{col}{color scheme to be used. By default uses \code{tim.colors} if available or a generic gray scale.} \item{zlim}{the minimum and maximum values for which colors should be plotted, defaulting to the range of \code{data}.} \item{add}{logical, if true adds to current plot.} \item{legendpos}{if package \pkg{fields} is loaded, puts a legend at that position.} } \references{The code of \code{map.landkreis} is very similar to \code{germany.map} from the package \pkg{INLA}.} \details{The function \code{\link{germany.plot}} super-seeds \code{map.landkreis} (it is several factors faster). \cr The perfect position of the legend is an art per se and depends on various \code{par} parameters. See also the source code of the function \code{image.plot} of \pkg{fields}.} \seealso{\code{\link{germany.plot}} super-seeding \code{map.landkreis}.} \examples{ \dontrun{ data( Oral) par( mfcol=c(1,2)) germany.plot( log( Oral$Y), legend=TRUE) map.landkreis( log( Oral$Y)) } } \author{Reinhard Furrer} \keyword{hplot} % dev.off() % dev.off();system.time( for (i in 1:20) map.landkreis(1:544)) % dev.off();system.time( for (i in 1:20) germany.plot(1:544)) spam/man/defunct.Rd0000644000176200001440000000173513536451713013722 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/defunct.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{spam-defunct} \alias{spam-defunct} \alias{validspamobject} \title{Defunct Objects in Package \pkg{spam}} \description{ The functions or variables listed here are defunct, i.e. thorw an error when used. } \usage{ validspamobject(...) } \arguments{ \item{...}{some arguments} } \seealso{ \code{\link{Deprecated}}, \code{\link{Defunct}} } \keyword{misc} spam/man/large_matrix.Rd0000644000176200001440000000377313536451714014755 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/large_matrix.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{large_matrix} \alias{large_matrix} \alias{large matrix} \alias{large_matries} \alias{large matries} \alias{64bit} \alias{64bits} \alias{long vector} \alias{long vectors} \alias{spam64} \title{Large 64-bit matrices require the R package \pkg{spam64}} \description{The R package \pkg{spam} can handle sparse matrices with up to 2^31-1 non-zero elements. For matrices with more non-zero elements it is necessary to load the \pkg{spam64} package in addition. } \details{With the help of the R package \pkg{dotCall64} spam interfaces either the compiled code with 32-bit integers provided in \pkg{spam} or the compiled code with 64-bit integers provided in \pkg{spam64}. } \references{ F. Gerber, K. Moesinger, R. Furrer (2017), Extending R packages to support 64-bit compiled code: An illustration with spam64 and GIMMS NDVI3g data, Computer & Geoscience 104, 109-119, https://doi.org/10.1016/j.cageo.2016.11.015. } \seealso{ \code{\link[spam64]{spam64-package}}, \code{\link[dotCall64]{dotCall64}}. } \examples{ \dontrun{ ## the following matrices are very large, and hence, ## require much memory and cpu time. library("spam64") s1 <- spam(1, ncol=2^30) # 32-bit matrix s1 s2 <- cbind(s1, s1) # 64-bit matrix s2 s3 <- spam(1, ncol=2^31) # 64-bit matrix s3 } } \author{Reinhard Furrer, Florian Gerber, Kaspar Moesinger, Daniel Gerber} \keyword{array} \keyword{algebra} spam/man/headtail.Rd0000644000176200001440000000454713536451714014052 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/headtail.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{head} \alias{head.spam} \alias{head,spam-method} \alias{head,spam.chol.NgPeyton-method} \alias{tail.spam} \alias{tail,spam-method} \alias{tail,spam.chol.NgPeyton-method} \title{ Return the First or Last Part of an Object } \description{ Returns the upper left or lower right part of a \code{\linkS4class{spam}} object. } \usage{ \S4method{head}{spam}(x, n = 6L, m = n, \dots) \S4method{tail}{spam}(x, n = 6L, m = n, addrownums = TRUE, \dots) } \arguments{ \item{x}{a \code{\linkS4class{spam}} object} \item{n}{a single integer. If positive, size for the resulting object: number of elements for a vector (including lists), rows for a matrix or data frame or lines for a function. If negative, all but the \code{n} last/first number of elements of \code{x}.} \item{m}{similar to \code{n} but for the number of columns.} \item{addrownums}{create row and column namves them from the selected elements.} \item{\dots}{arguments to be passed to or from other methods.} } \details{ For matrices, 2-dim tables and data frames, \code{head()} (\code{tail()}) returns the first (last) \code{n} rows and \code{m} columns when \code{n > 0} or all but the last (first) \code{n} rows when \code{n < 0} (with similar behavior for \code{m}). \code{tail()} will add row and column names of the form \code{"[n,]"} and \code{"[,n]"} to the result, so that it looks similar to the last lines and columns of \code{x} when printed. Setting \code{addrownums = FALSE} suppresses this behaviour. A method for \code{\linkS4class{spam.chol.NgPeyton}} objects is exported as well. } \value{ An regular matrix. } \author{ Reinhard Furrer } \examples{ head( precmat.RW2( 10)) tail( precmat.season(n=10, season=3), n=4, m=10) } \keyword{ manip } spam/man/germanydata.Rd0000644000176200001440000000427413554562371014572 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/germanydata.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{germany.data} \alias{germany.data} \alias{germany.info} \alias{germany.poly} \alias{germany.spam} \alias{germany} \docType{data} \title{Meta-data about administrative districts of Germany} \description{Data for the display of data over the administrative districts of Germany} \format{\code{germany.info} is a list with elements \describe{ \item{n}{544 (number of districts around 1990).} \item{xrep,yrep}{representative coordinates of the districts (vectors of length 544)} \item{xlim,ylim}{2-vectors defining the limits of the districts.} \item{polyid}{linking the polygons to the districts (599 vector).} \item{id}{linking the districts to Community Identification Number.}} \code{germany.poly} defines the polygons. It is a 17965 by two matrix, each polygon separated by a row of \code{NA}s, each district by two rows.\cr \code{germany} defines the polygons in form of a list (backwards compatibility). } \references{The meta-data has been constructed based on (essentially) files from the package \pkg{INLA}, see \code{demo(Bym)}.\cr See also \url{http://de.wikipedia.org/wiki/Amtlicher_Gemeindeschl\%C3\%BCssel} and \url{https://en.wikipedia.org/wiki/Districts_of_Germany}} \details{The representative coordinates are calculated based on the mean value of the polygon coordinates. This creates sometimes strange values, e.g., district Leer.} \seealso{\code{\link{germany.plot}} \code{\link{Oral}}.} \examples{ # Plot the Bundeslaender: germany.plot(germany.info$id\%/\%1000,col=rep(2:8,3), legend=FALSE) } \author{Reinhard Furrer} \keyword{hplot} spam/man/rowcolstats.Rd0000644000176200001440000000331213536451715014651 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/rowcolstats.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{rowSums} \alias{rowSums.spam} \alias{colSums.spam} \alias{rowMeans.spam} \alias{colMeans.spam} \alias{rowSums} \alias{colSums} \alias{rowMeans} \alias{colMeans} \alias{rowSums,spam-method} \alias{colSums,spam-method} \alias{rowMeans,spam-method} \alias{colMeans,spam-method} \title{ Form Row and Column Sums and Means } \description{ Form row and column sums and means for sparse \code{\linkS4class{spam}} matrices } \usage{ rowSums(x, na.rm = FALSE, dims = 1, \dots) colSums(x, na.rm = FALSE, dims = 1, \dots) rowMeans(x, na.rm = FALSE, dims = 1, \dots) colMeans(x, na.rm = FALSE, dims = 1, \dots) } \arguments{ \item{x}{a \code{\linkS4class{spam}} object} \item{na.rm}{currently ignored} \item{dims}{ignored as we have only two dimensions.} \item{\dots}{potentially further arguments from other methods.} } \details{ Depending on the flag \code{}. } \value{ Vector of appropriate length. } %\references{} \author{ Reinhard Furrer } %\note{} \seealso{ \code{\link{apply.spam}}, \code{\link{spam.options}}. } \examples{ x <- spam( rnorm(20), 5, 4) rowSums( x) c( x \%*\% rep(1,4)) } \keyword{manip} spam/man/crossprod.Rd0000644000176200001440000000355413536451713014311 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/crossprod.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{crossprod} \alias{crossprod.default} \alias{crossprod.spam} \alias{tcrossprod.spam} \alias{crossprod,spam,missing-method} \alias{tcrossprod,spam,missing-method} \alias{crossprod,ANY,spam-method} \alias{tcrossprod,ANY,spam-method} \alias{crossprod,spam,spam-method} \alias{tcrossprod,spam,spam-method} \alias{crossprod,spam,ANY-method} \alias{tcrossprod,spam,ANY-method} \title{Spam Matrix Crossproduct} \description{ Given matrices \code{x} and \code{y} as arguments, return a matrix cross-product. This is formally equivalent to (but usually slightly faster than) the call \code{t(x) \%*\% y} (\code{crossprod.spam}) or \code{x \%*\% t(y)} (\code{tcrossprod.spam}).} \usage{ crossprod.spam(x, y = NULL) tcrossprod.spam(x, y = NULL) } \arguments{ \item{x, y}{matrices: \code{y = NULL} is taken to be the same matrix as \code{x}. Vectors are promoted to single-column or single-row matrices, depending on the context.} } \value{A double matrix} \note{ When \code{x} or \code{y} are not matrices, they are treated as column or row matrices. } %\references{} %\seealso{\code{\link{chol}}} \examples{ crossprod.spam(diag.spam(2),1:2) } \author{Reinhard Furrer} \keyword{array} \keyword{algebra} spam/man/ordering.Rd0000644000176200001440000000472713536451714014110 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/ordering.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{ordering} \docType{methods} \alias{ordering} \alias{ordering.spam} \alias{ordering-methods} %\alias{ordering,spam.chol.NgPeyton-method} \alias{ordering.spam.chol} \alias{ordering.spam.chol.NgPeyton} \alias{ordering,spam-method} \alias{ordering,matrix-method} \title{Extract the permutation} \description{Extract the (inverse) permutation used by the Cholesky decomposition} \usage{ ordering( x, inv=FALSE) } \arguments{ \item{x}{object of class \code{spam.chol.}\emph{method} returned by the function \code{chol}.} \item{inv}{Return the permutation (default) or inverse thereof.} } \details{ Recall that calculating a Cholesky factor from a sparse matrix consists of finding a permutation first, then calculating the factors of the permuted matrix. The ordering is important when working with the factors themselves.\cr The ordering from a full/regular matrix is \code{1:n}.\cr Note that there exists many different algorithms to find orderings. \cr See the examples, they speak more than 10 lines. } \seealso{\code{\link{chol.spam}}, \code{\link{solve.spam}}. } \examples{ # Construct a pd matrix S to work with (size n) n <- 100 # dimension S <- .25^abs(outer(1:n,1:n,"-")) S <- as.spam( S, eps=1e-4) I <- diag(n) # Identity matrix cholS <- chol( S) ord <- ordering(cholS) iord <- ordering(cholS, inv=TRUE) R <- as.spam( cholS ) # R'R = P S P', with P=I[ord,], # a permutation matrix (rows permuted). RtR <- t(R) \%*\% R # the following are equivalent: as.spam( RtR - S[ord,ord] ) as.spam( RtR[iord,iord] - S ) as.spam( t(R[,iord]) \%*\% R[,iord] - S ) # trivially: as.spam( t(I[iord,]) - I[ord,]) # (P^-1)' = P as.spam( t(I[ord,]) - I[,ord]) # as.spam( I[iord,] - I[,ord]) as.spam( I[ord,]\%*\%S\%*\%I[,ord] - S[ord,ord] ) # pre and post multiplication with P and P' is ordering } \author{Reinhard Furrer} \keyword{algebra} spam/man/complexity.Rd0000644000176200001440000000443513536451713014467 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/complexity.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{complexity} \alias{complexity} \alias{complexities} \title{Complexity for Sparse Matrices} \description{A few results of computational complexities for selected sparse algoritms in \code{spam} } \details{A Cholesky factorization of an n-matrix requires n^3/3 flops. In case of banded matrices (bandwidth p, p< https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{options} \alias{spam.options} \alias{options.spam} \alias{getOption.spam} \title{Options Settings} \description{ Allow the user to set and examine a variety of \emph{options} which affect the way in which \R computes and displays sparse matrix results. } \details{ Invoking \code{options()} with no arguments returns a list with the current values of the options. To access the value of a single option, one should use \code{getOption("spam.eps")}, e.g., rather than \code{options("spam.eps")} which is a \emph{list} of length one.\cr Of course, printing is still subordinate to \code{getOption("max.print")} or similar options. } \value{ For \code{getOption}, the current value set for option \code{x}, or \code{NULL} if the option is unset. For \code{options()}, a list of all set options sorted by category. For \code{options(name)}, a list of length one containing the set value, or \code{NULL} if it is unset. For uses setting one or more options, a list with the previous values of the options changed (returned invisibly). } \section{Options used for the package \code{spam}}{ A short description with the default values follows. \describe{ \item{\code{spam.eps=.Machine$double.eps}:}{values smaller than this are considered as zero. This is only used when creating spam objects.} \item{\code{spam.drop=FALSE}:}{default parameter for \code{drop} when subsetting} \item{\code{spam.printsize=100}:}{the max number of elements of a matrix which we display as regular matrix.} \item{\code{spam.imagesize=10000}:}{the max number of elements of a matrix we display as regular matrix with \code{image} or \code{display}. Larger matrices are represented as dots only.} \item{\code{spam.cex=1200}:}{default dot size for \code{image} or \code{display}.} \item{\code{spam.structurebased=FALSE}:}{should operations be carried out on the nonzero entries (the structure) or including the zeros.} \item{\code{spam.inefficiencywarning=1e6}:}{issue a warning when inefficient operations are performed and the matrix exceeds the specified size. Valid value is a postive integer or a logical. \code{TRUE} corresponds to 1 (always), \code{FALSE} to \code{Inf}.} \item{\code{spam.trivalues=FALSE}:}{a flag whether to return the structure (\code{FALSE}) or the values themselves (\code{TRUE}) when returning the upper and lower triangular part of a matrix.} \item{\code{spam.listmethod="PE"}:}{algorithm for \code{spam.list}. Default is suggestion by Paul Eilers (thanks). Any other specification uses a bubble sort algorithm which is only slightly faster for very sparse matrices. } \item{\code{spam.dopivoting=TRUE}:}{default parameter for "\code{solve}" routines. \code{FALSE} would solve the system without using the permutation.} \item{\code{spam.NAOK=FALSE}:}{logical determines if \code{NA}, \code{NaN} and \code{Inf} are allowed to Fortan. Setting to \code{TRUE} allows to work with these but full functionality has not been tested.} \item{\code{spam.safemodevalidity=TRUE}:}{logical determines if sanity check is peformed when constructing sparse matrices. Default is safer but somewhat slower.} \item{\code{spam.cholsymmetrycheck=TRUE}:}{for the Cholesky factorization, verify if the matrix is symmetric.} \item{\code{spam.cholpivotcheck=TRUE}:}{for the Cholesky factorization, when passing a permutation, should a minimum set of checks be performed?} \item{\code{spam.cholupdatesingular="warning"}:}{for a Cholesky update, what happens if the matrix is singular: \code{"warning"} only and returning the not updated factor, \code{"error"} or return simply \code{"NULL"}.} \item{\code{spam.cholincreasefactor=c(1.25,1.25)}:}{If not enought memory could be allocated, these are the steps to increase it.} \item{\code{spam.nnznearestdistnnz=c(400^2,400)}:}{Memory allocation parameters for \code{nearest.dist}.} \item{\code{spam.nearestdistincreasefactor=1.25}:}{If not enought memory could be allocated, this is the step to increase it. } } } \seealso{Functions influenced by these options include: \code{\link{print.spam}}, \code{\link{display.spam}}, \code{\link{image.spam}}, \code{\link{upper.tri.spam}}, \code{\link{chol.spam}}, \code{\link{nearest.dist}}, etc.\cr \code{\link{powerboost}}\cr } \examples{ smat <- diag.spam( 1:8) smat options(spam.printsize=49) smat # List all spam options: options()[grep("spam",names(options()))] # Reset to default values: options(spam.eps=.Machine$double.eps, spam.drop=FALSE, spam.printsize=100, spam.imagesize=10000, spam.cex=1200, spam.structurebased=FALSE, spam.inefficiencywarning=1e6, spam.trivalues=FALSE, spam.listmethod="PE", spam.NAOK=FALSE, spam.safemodevalidity=TRUE, spam.dopivoting=TRUE, spam.cholsymmetrycheck=TRUE, spam.cholpivotcheck=TRUE, spam.cholupdatesingular="warning", spam.cholincreasefactor=c(1.25,1.25), spam.nearestdistincreasefactor=1.25, spam.nearestdistnnz=c(400^2,400)) } \keyword{IO} \keyword{environment} \keyword{error} \keyword{print} spam/man/coercion.Rd0000644000176200001440000000334513536451713014072 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/coercion.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{Coercion} \docType{class} \alias{as.vector.spam} \alias{as.vector,spam-method} \alias{as.vector,spam.chol.NgPeyton-method} \title{Coercion to a Vector} \description{Coercion of \code{spam} matrices to proper vector objects } \usage{\S4method{as.vector}{spam}(x, mode = "any") } \arguments{\item{x}{spam object.} \item{mode}{character string naming an atomic mode or \code{"any"}/\code{"list"}/\code{"expression"}.} } \value{If \code{structurebased=TRUE}, the vector \code{x@entries}.\cr Conversely, if \code{structurebased=FALSE}, the result is identical to one with \code{as.vector(as.matrix(x))}. } \details{This coercion allows smooth transitions between different matrix formats, see example below.\cr The Cholesky factors are first transformed to a \code{spam} object. } %\references{ %} \seealso{\code{\link{spam.options}}} \examples{ x <- diag(2) ifelse( x, x, 1-x) ifelse( x, as.vector(x), 1-as.vector(x)) x <- diag.spam(2) options(spam.structurebased=FALSE) ifelse( x, as.vector(x), 1-as.vector(x)) options(spam.structurebased=TRUE) ifelse( x, as.vector(x), 1-as.vector(x)) } \author{Reinhard Furrer} \keyword{manip} spam/man/print.Rd0000644000176200001440000000451613536451715013430 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/print.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{print} \docType{methods} \alias{print.spam} \alias{print,spam-method} %\alias{print,spam.chol.NgPeyton-method} \alias{print.spam.chol} \alias{print.spam.chol.NgPeyton} \alias{summary.spam} \alias{summary,spam-method} %\alias{summary,spam.chol.NgPeyton-method} \alias{summary.spam.chol} \alias{summary.spam.chol.NgPeyton} \title{Printing and summarizing sparse matrices} \description{Printing (non-zero elements) of sparse matrices and summarizing the sparsity structure thereof. } \usage{ \S4method{print}{spam}(x, ...) \S4method{summary}{spam}(object, ...) } \arguments{\item{x}{matrix of class \code{spam} or \code{spam.chol.}\emph{method}.} \item{object}{matrix of class \code{spam} or \code{spam.chol.}\emph{method}.} \item{...}{any other arguments passed to \code{print.default}.} } \value{\code{NULL} for \code{print}, because the information is printed with \code{cat} there is no real need to pass any object back. \cr % A list containing the non-zero elements and the density for \code{summary} for class \code{spam}.\cr % A list containing the non-zero elements of the factor, the density and the fill-in for \code{summary} for class \code{spam.chol.NgPeyton}.} \details{\code{getOption('spam.printsize')} determines if the sparse matrix is coerced into a matrix and the printed as an array or if only the non-zero elements of the matrix are given. } %\references{} \seealso{\code{\link{display}} or \code{\link{image}} for a graphical visualization; \code{\link{spam.options}}} \examples{ set.seed(13) smat <- spam_random(8) par(mfcol=c(1,2),pty='s') options(spam.printsize=1000) print(smat) options(spam.printsize=10) print(smat) summary(smat) summary(smat)$nnz } \author{Reinhard Furrer} \keyword{hplot} spam/man/display.Rd0000644000176200001440000000363413536451713013737 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/display.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{display} \alias{display} \alias{display.spam} \alias{display,spam-method} %\alias{display,spam.chol.NgPeyton-method} \title{Graphially Represent the Nonzero Entries} \description{The function represents the nonzero entries in a simple bicolor plot. } \usage{ display(x, ...) } \arguments{\item{x}{matrix of class \code{spam} or \code{spam.chol.NgPeyton}.} \item{...}{any other arguments passed to \code{image.default}/\code{plot}.} } %\value{} \details{\code{spam.getOption("imagesize")} determines if the sparse matrix is coerced into a matrix and the plotted with \code{image.default} or if the matrix is simply represented as a scatterplot with \code{pch="."}. The points are scaled according to \code{cex*getOption("spam.cex")/(nrow + ncol)}. For some devices or for non-square matrices, \code{cex} needs probably some adjustment. } %\references{} \seealso{\code{\link{image}}, \code{\link{spam.options}}} \examples{ set.seed(13) smat <- spam_random(8) par(mfcol=c(1,2), pty='s') options(spam.imagesize = 1000) display(smat) options(spam.imagesize = 10) display(smat, cex=.25) # very large but very sparse matrix smat <- spam_random(2^14, distribution=rnorm, density=1e-5, verbose=TRUE) par(mfcol=c(1, 1), mai=c(.4,.4,.1,.1), pty='s') display(smat) } \author{Reinhard Furrer} \keyword{hplot} spam/man/chol.Rd0000644000176200001440000001510613536451713013214 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/chol.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{chol} \alias{chol.spam} \alias{chol,ANY-method} \alias{chol,matrix-method} \alias{chol,spam-method} \alias{update.spam} \alias{update,spam.chol.NgPeyton-method} \alias{update.spam.chol.NgPeyton} \title{Cholesky Factorization for Sparse Matrices} \description{ \code{chol} performs a Cholesky decomposition of a symmetric positive definite sparse matrix \code{x} of class \code{spam}.} \usage{ # chol(x, \dots) \S4method{chol}{spam}(x, pivot = "MMD", method = "NgPeyton", memory = list(), eps = getOption("spam.eps"), Rstruct=NULL, \dots) %force64 = getOption("spam.force64"),\dots) # update.spam.chol.NgPeyton(object, x,...) \S4method{update}{spam.chol.NgPeyton}(object, x,...) %chol(x, method, ordering, memory, \dots) } \arguments{ \item{x}{symmetric positive definite matrix of class \code{spam}.} \item{pivot}{should the matrix be permuted, and if, with what algorithm, see \sQuote{Details} below.} \item{method}{Currently, only \code{NgPeyton} is implemented.} \item{memory}{Parameters specific to the method, see \sQuote{Details} below.} \item{eps}{threshold to test symmetry. Defaults to \code{getOption("spam.eps")}.} %\item{force64}{logical vector of length 1. If \code{TRUE}, a 64-bit % spam matrix is returned in any case. If \code{FALSE}, a 32-bit % matrix is returned when possible. } \item{Rstruct}{sparsity structure of the factor, see \sQuote{Details} below.} \item{\dots}{further arguments passed to or from other methods.} \item{object}{an object from a previous call to \code{chol}, i.e., sparsity structure of the factor.} } \value{The function returns the Cholesky factor in an object of class \code{spam.chol.}\emph{method}. Recall that the latter is the Cholesky factor of a reordered matrix \code{x}, see also \code{\link{ordering}}. } \details{\code{chol} performs a Cholesky decomposition of a symmetric positive definite sparse matrix \code{x} of class \code{spam}. Currently, there is only the block sparse Cholesky algorithm of Ng and Peyton (1993) implemented (\code{method="NgPeyton"}). To pivot/permute the matrix, you can choose between the multiple minimum degree (\code{pivot="MMD"}) or reverse Cuthill-Mckee (\code{pivot="RCM"}) from George and Lui (1981). It is also possible to furnish a specific permutation in which case \code{pivot} is a vector. For compatibility reasons, \code{pivot} can also take a logical in which for \code{FALSE} no permutation is done and for \code{TRUE} is equivalent to \code{MMD}.\cr Often the sparsity structure is fixed and does not change, but the entries do. In those cases, we can update the Cholesky factor with \code{update.spam.chol.NgPeyton} by suppling a Cholesky factor and the updated matrix. For \code{U <- chol(A)}, \code{update(U, Anew)} and \code{chol(Anew, Rstruct=U)} are equivalent. The option \code{cholupdatesingular} determines how singular matrices are handled by \code{update}. The function hands back an error (\code{"error"}), a warning (\code{"warning"}) or the value \code{NULL} (\code{"null"}).\cr The Cholesky decompositions requires parameters, linked to memory allocation. If the default values are too small the Fortran routine returns an error to \R, which allocates more space and calls the Fortran routine again. The user can also pass better estimates of the allocation sizes to \code{chol} with the argument \code{memory=list(nnzR=..., nnzcolindices=...)}. The minimal sizes for a fixed sparsity structure can be obtained from a \code{summary} call, see \sQuote{Examples}.\cr The output of \code{chol} can be used with \code{forwardsolve} and \code{backsolve} to solve a system of linear equations.\cr Notice that the Cholesky factorization of the package \code{SparseM} is also based on the algorithm of Ng and Peyton (1993). Whereas the Cholesky routine of the package \code{Matrix} are based on \code{CHOLMOD} by Timothy A. Davis (\code{C} code). } \references{ Ng, E. G. and Peyton, B. W. (1993) Block sparse Cholesky algorithms on advanced uniprocessor computers, \emph{SIAM J. Sci. Comput.}, \bold{14}, 1034--1056. Gilbert, J. R., Ng, E. G. and Peyton, B. W. (1994) An efficient algorithm to compute row and column counts for sparse Cholesky factorization, \emph{SIAM J. Matrix Anal. Appl.}, \bold{15}, 1075--1091. George, A. and Liu, J. (1981) \emph{Computer Solution of Large Sparse Positive Definite Systems}, Prentice Hall. } \note{ Although the symmetric structure of \code{x} is needed, only the upper diagonal entries are used. By default, the code does check for symmetry (contrarily to \code{base:::chol}). However, depending on the matrix size, this is a time consuming test. A test is ignored if \code{options("spam.cholsymmetrycheck")} is set to \code{FALSE}. If a permutation is supplied with \code{pivot}, \code{options("spam.cholpivotcheck")} determines if the permutation is tested for validity (defaults to \code{TRUE}). } \seealso{\code{\link{det.spam}}, \code{\link{solve.spam}}, \code{\link{forwardsolve.spam}}, \code{\link{backsolve.spam}} and \code{\link{ordering}}. } \examples{ # generate multivariate normals: set.seed(13) n <- 25 # dimension N <- 1000 # sample size Sigma <- .25^abs(outer(1:n,1:n,"-")) Sigma <- as.spam( Sigma, eps=1e-4) cholS <- chol( Sigma) # cholS is the upper triangular part of the permutated matrix Sigma iord <- ordering(cholS, inv=TRUE) R <- as.spam(cholS) mvsample <- ( array(rnorm(N*n),c(N,n)) \%*\% R)[,iord] # It is often better to order the sample than the matrix # R itself. # 'mvsample' is of class 'spam'. We need to transform it to a # regular matrix, as there is no method 'var' for 'spam' (should there?). norm( var( as.matrix( mvsample)) - Sigma, type='m') norm( t(R) \%*\% R - Sigma) # To speed up factorizations, memory allocations can be optimized: opt <- summary(cholS) # here, some elements of Sigma may be changed... cholS <- chol( Sigma, memory=list(nnzR=opt$nnzR,nnzcolindices=opt$nnzc)) } % backsolve( chol(as.matrix(V)[ord,ord]),iidsample)[iord,] % \author{Reinhard Furrer, based on Ng and Peyton (1993) Fortran routines} \keyword{algebra} spam/man/USprecip.Rd0000644000176200001440000000355113536636243014025 0ustar liggesusers% HEADER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This is file spam/man/USprecip.Rd. % % It is part of the R package spam, % % --> https://CRAN.R-project.org/package=spam % % --> https://CRAN.R-project.org/package=spam64 % % --> https://git.math.uzh.ch/reinhard.furrer/spam % % by Reinhard Furrer [aut, cre], Florian Gerber [aut], % % Roman Flury [aut], Daniel Gerber [ctb], % % Kaspar Moesinger [ctb] % % HEADER END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \name{USprecip} \alias{USprecip} \docType{data} \title{ Monthly total precipitation (mm) for April 1948 in the contiguous United States } \description{ This is a useful spatial data set of moderate to large size consisting of 11918 locations. See \url{https://www.image.ucar.edu/GSP/Data/US.monthly.met/} for the source of these data. } \format{ This data set is an array containing the following columns: \describe{ \item{lon,lat}{ Longitude-latitude position of monitoring stations } \item{raw}{ Monthly total precipitation in millimeters for April 1948 } \item{anomaly}{ Preipitation anomaly for April 1948. } \item{infill}{ Indicator, which station values were observed (5906 out of the 11918) compared to which were estimated. } } } \source{\url{https://www.image.ucar.edu/GSP/Data/US.monthly.met/}} \seealso{\code{\link[fields]{RMprecip}}} \references{ Johns, C., Nychka, D., Kittel, T., and Daly, C. (2003) Infilling sparse records of spatial fields. \emph{Journal of the American Statistical Association}, 98, 796--806. } \examples{ # plot \dontrun{ library(fields) data(USprecip) par(mfcol=c(2,1)) quilt.plot(USprecip[,1:2],USprecip[,3]) US( add=TRUE, col=2, lty=2) quilt.plot(USprecip[,1:2],USprecip[,4]) US( add=TRUE, col=2, lty=2) } } \keyword{datasets} spam/DESCRIPTION0000644000176200001440000000636713574471023012742 0ustar liggesusersPackage: spam Type: Package Title: SPArse Matrix Version: 2.5-1 Date: 2019-12-12 Authors@R: c(person("Reinhard", "Furrer", role = c("aut", "cre"), email = "reinhard.furrer@math.uzh.ch"), person("Florian", "Gerber", role = c("aut"), email = "florian.gerber@math.uzh.ch"), person("Roman", "Flury", role = c("aut"), email = "roman.flury@math.uzh.ch"), person("Daniel", "Gerber", role = "ctb", email = "daniel_gerber_2222@hotmail.com"), person("Kaspar", "Moesinger", role = "ctb", email = "kaspar.moesinger@gmail.com"), person("Youcef", "Saad", role = "ctb", comment = "SPARSEKIT http://www-users.cs.umn.edu/~saad/software/SPARSKIT/"), person(c("Esmond", "G."), "Ng", role = "ctb", comment = "Fortran Cholesky routines"), person(c("Barry", "W."), "Peyton", role = "ctb", comment = "Fortran Cholesky routines"), person(c("Joseph", "W.H."), "Liu", role = "ctb", comment = "Fortran Cholesky routines"), person(c("Alan", "D."), "George", role = "ctb", comment = "Fortran Cholesky routines"), person(c("Lehoucq", "B."), "Rich", role = "ctb", comment = "ARPACK"), person(c("Maschhoff"), "Kristi", role = "ctb", comment = "ARPACK"), person(c("Sorensen", "C."), "Danny", role = "ctb", comment = "ARPACK"), person(c("Yang"), "Chao", role = "ctb", comment = "ARPACK")) Depends: R (>= 3.1), dotCall64, grid, methods Suggests: spam64, fields, SparseM, Matrix, testthat, R.rsp, truncdist, knitr, rmarkdown VignetteBuilder: R.rsp, knitr Description: Set of functions for sparse matrix algebra. Differences with other sparse matrix packages are: (1) we only support (essentially) one sparse matrix format, (2) based on transparent and simple structure(s), (3) tailored for MCMC calculations within G(M)RF. (4) and it is fast and scalable (with the extension package spam64). Documentation about 'spam' is provided by vignettes included in this package, see also Furrer and Sain (2010) ; see 'citation("spam")' for details. LazyData: true License: LGPL-2 | BSD_3_clause + file LICENSE URL: https://www.math.uzh.ch/pages/spam/ BugReports: https://git.math.uzh.ch/reinhard.furrer/spam/issues NeedsCompilation: yes Packaged: 2019-12-12 12:30:52 UTC; roflur Author: Reinhard Furrer [aut, cre], Florian Gerber [aut], Roman Flury [aut], Daniel Gerber [ctb], Kaspar Moesinger [ctb], Youcef Saad [ctb] (SPARSEKIT http://www-users.cs.umn.edu/~saad/software/SPARSKIT/), Esmond G. Ng [ctb] (Fortran Cholesky routines), Barry W. Peyton [ctb] (Fortran Cholesky routines), Joseph W.H. Liu [ctb] (Fortran Cholesky routines), Alan D. George [ctb] (Fortran Cholesky routines), Lehoucq B. Rich [ctb] (ARPACK), Maschhoff Kristi [ctb] (ARPACK), Sorensen C. Danny [ctb] (ARPACK), Yang Chao [ctb] (ARPACK) Maintainer: Reinhard Furrer Repository: CRAN Date/Publication: 2019-12-12 17:00:03 UTC spam/build/0000755000176200001440000000000013574431374012324 5ustar liggesusersspam/build/vignette.rds0000644000176200001440000000037113574431374014664 0ustar liggesusersuPM 0 nN'(-xAyhتLE;QorgpM^^BmBH FMbcLYH_j%6*q5J)# ̄t 4'^Yf%WB U7W[\ꦥIs<fem' https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ # JSS article: # "Pitfalls in the implementation of Bayesian # hierarchical modeling of areal count data. # An illustration using BYM and Leroux models." # # test the MCMC sampler from the paper with 30 iterations. # SETUP: library("spam") options(spam.structurebased=TRUE) # BYM --------------------------------------------- data(Oral); attach(Oral) path <- system.file("demodata/germany.adjacency", package = "spam") A <- adjacency.landkreis(path); n <- dim(A)[1] set.seed(2) hyperA <- c(1, 1); hyperB <- c(0.5, .01) totalg <- 30 upost <- vpost <- array(0, c(totalg, n)) kpost <- array(NA, c(totalg, 2)); accept <- rep(NA, totalg) upost[1,] <- vpost[1,] <- rep(.001, 544); kpost[1,] <- c(10, 100) eta <- upost[1,] + vpost[1,] C <- exp(eta) * E; diagC <- diag.spam(c(rep(0, n), C)) b <- c( rep(0, n), Y + (eta - 1) * C) Qu <- R <- precmat.IGMRFirreglat(A); pad(Qu) <- c(2 * n, 2 * n) Qv <- as.spam(rbind(cbind( diag(n), -diag(n)), cbind(-diag(n), diag(n)))) Q <- kpost[1,1] * Qu + kpost[1,2] * Qv + diagC struct <- chol(Q, memory = list(nnzcolindices = 6467)) uRuHalf <- t(upost[1,]) %*% (R %*% upost[1,]) / 2 vvHalf <- t(vpost[1,]) %*% vpost[1,] / 2 postshape <- hyperA + c(n - 1, n) / 2 for (i in 2:totalg) { kpost[i,] <- rgamma(2, postshape, hyperB + c(uRuHalf, vvHalf)) etaTilde <- eta for(index in 1:2){ C <- E * exp(etaTilde) diagC <- diag.spam(c(rep(0, n), C)) b <- c(rep(0, 544), Y + (etaTilde - 1) * C) Q <- kpost[i,1] * Qu + kpost[i,2] * Qv + diagC etaTilde <- c(solve.spam(Q, b, Rstruct = struct))[1:n + n] } C <- exp(etaTilde) * E; diagC <- diag.spam(c(rep(0, n), C)) b <- c( rep(0, n), Y + (etaTilde - 1) * C) Q <- kpost[i,1] * Qu + kpost[i,2] * Qv + diagC x_ <- c(rmvnorm.canonical(1, b, Q, Rstruct = struct)) upost[i,] <- x_[1:n]; eta_ <- x_[1:n + n]; vpost[i,] <- eta_ - upost[i,] uRuHalf_ <- t(upost[i,]) %*% (R %*% upost[i,]) / 2 vvHalf_ <- t(vpost[i,]) %*% vpost[i,] / 2 etaTilde_ <- eta_ for(index in 1:2){ C_ <- E * exp(etaTilde_) diagC_ <- diag.spam(c(rep(0, n), C_)) b_ <- c(rep(0, 544), Y + (etaTilde_ - 1) * C_) Q_<- kpost[i,1] * Qu + kpost[i,2] * Qv + diagC_ etaTilde_ <- c(solve.spam(Q_, b_, Rstruct = struct))[1:n + n] } C_ <- exp(etaTilde_) * E; diagC_ <- diag.spam(c(rep(0, n), C_)) b_ <- c( rep(0, n), Y + (etaTilde_ - 1) * C_) Q_ <- kpost[i,1] * Qu + kpost[i,2] * Qv + diagC_ logPost_ <- sum(Y * eta_ - E * exp(eta_)) - kpost[i,1] * uRuHalf_ - kpost[i, 2] * vvHalf_ logPost <- sum(Y * eta - E * exp(eta)) - kpost[i,1] * uRuHalf - kpost[i,2] * vvHalf logApproxX_ <- - kpost[i,1] * uRuHalf_ - kpost[i,2] * vvHalf_ - sum(.5 * eta_^2 * C) + sum(b * eta_) logApproxX <- - kpost[i,1] * uRuHalf - kpost[i,2] * vvHalf - sum(.5 * eta^2 * C_) + sum(b_ * eta) logAlpha <- min(0, logPost_ - logPost + logApproxX - logApproxX_) if (log(runif(1)) < logAlpha) { uRuHalf <- uRuHalf_; vvHalf <- vvHalf_ eta <- eta_; b <- b_; C <- C_; accept[i] <- 1 } else{ accept[i] <- 0; upost[i,] <- upost[i-1,]; vpost[i,] <- vpost[i-1,]} } # values of 30th iteration head(eta) tail(b) head(C) tail(accept) tail(upost[30,]) tail(vpost[30,]) sum(accept[-1]) sum(upost) spam/tests/demo_article-jss.R0000644000176200001440000002663213536451710015741 0ustar liggesusers# HEADER #################################################### # This is file spam/tests/demo_article-jss.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ # This demo contains the R code to construct the figures and the table of the # article: # "spam: A Sparse Matrix R Package with Emphasis on # MCMC Methods for Gaussian Markov Random Fields" # submitted to JSS. # The code presented here differs in the following points form the actually used # one: # - Very large grid sizes or very high order neighbor structures are not included # here; # - Instead of (100+1) factorizations only (10+1) are performed here; # - No figure fine-tuning is done here. # - We had a few additional gc(), just to be sure. # The following are tests specific. Not all computers run with profiling. Instead # of commenting, we define dummies. options( echo=FALSE) library( spam, warn.conflict=FALSE) Rprof <- function(memory.profiling=TRUE, interval=0.1) return() summaryRprof <- function(memory="both") return(list(by.total=rbind(1:4))) # Figure 1: i <- c( 2,4,4,5,5) j <- c( 1,1,2,1,3) A <- spam(0,5,5) A[cbind(i,j)] <- rep(.5, length(i)) A <- t( A)+A+diag.spam(5) U <- chol( A) pivot <- U@pivot B <- A[pivot,pivot] R <- chol( B) U@pivot U@snmember U@supernodes U@entries U@colindices U@colpointers U@rowpointers if (F){ display( A) display( as.spam( chol(as.matrix( A)))) display( B) display( as.spam(R)) abline( h=-U@supernodes+.5,col=3,lty=2) } # Figure 2: theta1 <- .1 theta2 <- .01 n <- dim( UScounties.storder)[1] USmat <- diag.spam(n) + theta1 * UScounties.storder + theta2 * UScounties.ndorder U <- chol( USmat,memory=list(nnzR=146735)) if (F) { display( as.spam(U)) text(400,-2200,"MMD\nz=146735\nw=30182\ns=1262",adj=0) } U <- chol( USmat, pivot="RCM",memory=list(nnzR=256198,nnzcolindices=140960)) if (F) { display( as.spam(U)) text(400,-2200,"RCM\nz=256198\nw=140960\ns=1706",adj=0) } U <- chol( USmat, pivot=FALSE,memory=list(nnzR=689615,nnzcolindices=96463)) if (F) { display( as.spam(U)) text(400,-2200,"no permutation\nz=689615\nw=96463\ns=711",adj=0) } # general parameters for the following N <- 10 # would be 100 in the article stsel <- 1 # user.self rPsx <- 1 # for function "system.time" rPsy <- 3 # memory usage rPint <- .0001 # small interval # Figure 3: theta1 <- .1 theta2 <- .05 xseq <- ceiling(4 + exp(seq(0,to=4,by=1))/2) # would be seq(0.5,to=6,by=.5) in the article xseql <- length(xseq) table <- array(NA,c(xseql,4)) for (ix in 1:xseql) { egdx <- expand.grid(1:xseq[ix],1:xseq[ix]) Cspam <- nearest.dist( egdx, delta=1., upper=NULL) Dspam <- nearest.dist( egdx, delta=1.5,upper=NULL) mat <- diag.spam(xseq[ix]^2) + theta1 * Cspam + theta2 * Dspam Rprof( memory.profiling=TRUE, interval = rPint) table[ix,1] <- system.time( { ch1 <- chol(mat); for (i in 1:N) ch1 <- chol(mat)} )[stsel] Rprof( NULL) table[ix,2] <- summaryRprof( memory="both")$by.total[rPsx,rPsy] Rprof( memory.profiling=TRUE, interval = rPint) table[ix,3] <- system.time( { ch1 <- chol(mat); for (i in 1:N) ch2 <- update(ch1,mat) } )[stsel] Rprof( NULL) table[ix,4] <- summaryRprof( memory="both")$by.total[rPsx,rPsy] } if (F) { # Since we have a small N, elements in table might be zero. table <- pmax(table, 0.0001) par(mfcol=c(1,2)) plot(xseq, table[,1], type='l', log='xy', ylim=range(table[,c(1,3)]), xlab="L (log scale)", ylab="seconds (log scale)") lines(xseq, table[,3], lty=2) plot(xseq, table[,2], type='l', log='xy', ylim=range(table[,c(2,4)]+0.01), xlab="L (log scale)", ylab="Mbytes (log scale)") lines(xseq, table[,4], lty=2) } # Figure 4: x <- 20 # was 50 in article maxnn <- 3 # was 6 in article egdx <- expand.grid( 1:(maxnn+1), 1:(maxnn+1)) dval <- sort(unique(nearest.dist( egdx, delta=maxnn)@entries)) dvall <- length( dval) egdx <- expand.grid( 1:x, 1:x) table <- array(NA, c(dvall,5)) for (id in 1:dvall) { mat <- nearest.dist( egdx, delta=dval[id],upper=NULL) mat@entries <- exp(-2*mat@entries) # arbitrary values to get a spd precision matrix table[id,5] <- length(Cspam) Rprof( memory.profiling=TRUE, interval = rPint) table[id,1] <- system.time( { ch1 <- chol(mat); for (i in 1:N) ch1 <- chol(mat)} )[stsel] Rprof( NULL) table[id,2] <- summaryRprof( memory="both")$by.total[rPsx,rPsy] Rprof( memory.profiling=TRUE, interval = rPint) table[id,3] <- system.time( { ch1 <- chol(mat); for (i in 1:N) ch2 <- update(ch1,mat) } )[stsel] Rprof( NULL) table[id,4] <- summaryRprof( memory="both")$by.total[rPsx,rPsy] } if (F) { # Since we have a small N, elements in table might be zero. table <- pmax(table, 0.0001) par(mfcol=c(1,2)) plot( dval, table[,1], type='l', log='xy',ylim=range(table[,c(1,3)]), xlab="distance (log scale)", ylab="seconds (log scale)") lines( dval, table[,3],lty=2) plot( dval, table[,2], type='l', log='xy',ylim=range(table[,c(2,4)]), xlab="distance (log scale)", ylab="Mbytes (log scale)") lines( dval, table[,4],lty=2) } # Table 1: table <- array(NA,c(9,4)) x <- 10 # was 50 in article egdx <- expand.grid(1:x,1:x) # As above hence shortend gridmat <- diag.spam(x^2) + .2 * nearest.dist( egdx, delta=1.,upper=NULL) + .1 * nearest.dist( egdx, delta=1.5,upper=NULL) # USmat was constructed above. # Generic call first: Rprof( memory.profiling=TRUE, interval = rPint) table[1,1] <- system.time( for (i in 1:N) ch1 <- chol(gridmat) )[stsel] Rprof( NULL) table[1,2] <- summaryRprof(memory="both")$by.total[rPsx,rPsy] Rprof( memory.profiling=TRUE, interval = rPint) table[1,3] <- system.time( for (i in 1:N) ch2 <- chol(USmat) )[stsel] Rprof( NULL) table[1,4] <- summaryRprof(memory="both")$by.total[rPsx,rPsy] # Call a chol.spam directly Rprof( memory.profiling=TRUE, interval = rPint) table[2,1] <- system.time( for (i in 1:N) ch1 <- chol.spam(gridmat))[stsel] Rprof( NULL) table[2,2] <- summaryRprof(memory="both")$by.total[rPsx,rPsy] Rprof( memory.profiling=TRUE, interval = rPint) table[2,3] <- system.time( for (i in 1:N) ch2 <- chol.spam(USmat) )[stsel] Rprof( NULL) table[2,4] <- summaryRprof(memory="both")$by.total[rPsx,rPsy] # Less checking: options(spam.safemode=c(FALSE, FALSE, FALSE)) Rprof( memory.profiling=TRUE, interval = rPint) table[3,1] <- system.time( for (i in 1:N) ch1 <- chol( gridmat) )[stsel] Rprof( NULL) table[3,2] <- summaryRprof(memory="both")$by.total[rPsx,rPsy] Rprof( memory.profiling=TRUE, interval = rPint) table[3,3] <- system.time( for (i in 1:N) ch2 <- chol( USmat) )[stsel] Rprof( NULL) table[3,4] <- summaryRprof(memory="both")$by.total[rPsx,rPsy] options(spam.safemode=c(TRUE, TRUE, TRUE)) # lesser checking options(spam.cholsymmetrycheck=FALSE) Rprof( memory.profiling=TRUE, interval = rPint) table[4,1] <- system.time( for (i in 1:N) ch1 <- chol( gridmat) )[stsel] Rprof( NULL) table[4,2] <- summaryRprof(memory="both")$by.total[rPsx,rPsy] Rprof( memory.profiling=TRUE, interval = rPint) table[4,3] <- system.time( for (i in 1:N) ch2 <- chol( USmat) )[stsel] Rprof( NULL) table[4,4] <- summaryRprof(memory="both")$by.total[rPsx,rPsy] options(spam.cholsymmetrycheck=TRUE) # Pass optimal memory parameters (from above memory1 = summary(ch1)[1:2] memory2 = summary(ch2)[1:2] Rprof( memory.profiling=TRUE, interval = rPint) table[5,1] <- system.time( for (i in 1:N) ch1 <- chol( gridmat,memory=memory1) )[stsel] Rprof( NULL) table[5,2] <- summaryRprof(memory="both")$by.total[rPsx,rPsy] Rprof( memory.profiling=TRUE, interval = rPint) table[5,3] <- system.time( for (i in 1:N) ch2 <- chol( USmat,memory=memory2) )[stsel] Rprof( NULL) table[5,4] <- summaryRprof(memory="both")$by.total[rPsx,rPsy] # All of the above options(spam.cholsymmetrycheck=FALSE, safemode=c(FALSE,FALSE,FALSE)) Rprof( memory.profiling=TRUE, interval = rPint) table[6,1] <- system.time( for (i in 1:N) ch1 <- chol.spam(gridmat,memory=memory1) )[stsel] Rprof( NULL) table[6,2] <- summaryRprof(memory="both")$by.total[rPsx,rPsy] Rprof( memory.profiling=TRUE, interval = rPint) table[6,3] <- system.time( for (i in 1:N) ch2 <- chol.spam(USmat,memory=memory2) )[stsel] Rprof( NULL) table[6,4] <- summaryRprof(memory="both")$by.total[rPsx,rPsy] # supply the permutation pivot1 <- ch1@pivot pivot2 <- ch2@pivot Rprof( memory.profiling=TRUE, interval = rPint) table[7,1] <- system.time( for (i in 1:N) ch1 <- chol.spam(gridmat,pivot=pivot1, memory=memory1) )[stsel] Rprof( NULL) table[7,2] <- summaryRprof(memory="both")$by.total[rPsx,rPsy] Rprof( memory.profiling=TRUE, interval = rPint) table[7,3] <- system.time( for (i in 1:N) ch1 <- chol.spam(USmat,pivot=pivot2, memory=memory2) )[stsel] Rprof( NULL) table[7,4] <- summaryRprof(memory="both")$by.total[rPsx,rPsy] # Do not check the permutation options(spam.cholpivotcheck=FALSE) Rprof( memory.profiling=TRUE, interval = rPint) table[8,1] <- system.time( for (i in 1:N) ch1 <- chol.spam(gridmat,pivot=pivot1, memory=memory1) )[stsel] Rprof( NULL) table[8,2] <- summaryRprof(memory="both")$by.total[rPsx,rPsy] Rprof( memory.profiling=TRUE, interval = rPint) table[8,3] <- system.time( for (i in 1:N) ch2 <- chol.spam(USmat,pivot=pivot2, memory=memory2) )[stsel] Rprof( NULL) table[8,4] <- summaryRprof(memory="both")$by.total[rPsx,rPsy] # Update only Rprof( memory.profiling=TRUE, interval = rPint) table[9,1] <- system.time( for (i in 1:N) ch1 <- update(ch1,gridmat) )[stsel] Rprof( NULL) table[9,2] <- summaryRprof(memory="both")$by.total[rPsx,rPsy] Rprof( memory.profiling=TRUE, interval = rPint) table[9,3] <- system.time( for (i in 1:N) ch2 <- update(ch2,USmat) )[stsel] Rprof( NULL) table[9,4] <- summaryRprof(memory="both")$by.total[rPsx,rPsy] # assemble the table colnames(table) <- c("grid_time","grid_mem","US_time","US_mem") rownames(table) <- c("Generic chol","chol.spam","safemode", "symmetrycheck","memory","all","reusing pivot","best cast","update only") normed.table <- t( round( t(table[-1,])/table[1,],3)) if (F) { print( t( round( t(table[-1,])/table[1,],3))) } # Figure 5 In <- diag.spam(nrow(UScounties.storder)) struct <- chol(In + .2 * UScounties.storder + .1 * UScounties.ndorder) len.1 <- 10 # in the article, is set to 180 len.2 <- 5 # in the article, is set to 100 theta.1 <- seq(-.225, to=.515, len=len.1) theta.2 <- seq(-.09, to=.235, len=len.2) grid <- array(NA, c(len.1, len.2)) options(spam.cholupdatesingular='null') for (i in 1:len.1) for(j in 1:len.2) grid[i,j] <- !is.null(update(struct, In + theta.1[i]*UScounties.storder + theta.2[j]* UScounties.ndorder)) options( echo=TRUE) spam/tests/demo_jss15-Leroux.R0000644000176200001440000001272513536451710015740 0ustar liggesusers# HEADER #################################################### # This is file spam/tests/demo_jss15-Leroux.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ options( echo=FALSE) library( spam, warn.conflict=FALSE) # This is the MCMC sampler presented in Section 3.1 of the article: # # Florian Gerber, Reinhard Furrer (2015). Pitfalls in the Implementation # of Bayesian Hierarchical Modeling of Areal Count Data: An Illustration # Using BYM and Leroux Models. Journal of Statistical Software, # Code Snippets, 63(1), 1–32. URL http://www.jstatsoft.org/v63/c01/. # # Note: For illustration we set # number of generated samples: 5'000 # number of burnin samples: 500 # thinning: 10 # This takes only 1-2 minutes of computation time. # # In the JSS article we used: # number of generated samples: 300'000 # number of burnin samples: 15'000 # thinning: 20 ## invisible(readline(prompt = "Type \t to continue : ")) # SETUP: options(spam.structurebased=TRUE) library("truncdist") # Lereux model - one block, no intercept # load data data(Oral) E <- Oral$E Y <- Oral$Y n <- 544 A <- adjacency.landkreis(system.file("demodata/germany.adjacency", package="spam")) A <- as.matrix(A) set.seed(2) # tuning parameters # (influence acceptance rate) lambda.proposal.sd <- 0.070992 # sampler length, burnin and thinning totaln <- 100 burnin <- 500 thin <- 10 # variable to store samples upost <- array(NA, c(totaln, n)) kpost <- rep(NA,totaln) lpost <- rep(NA,totaln) accept <- array(0, c(totaln, 2), list(NULL, c("U", "lambda"))) # initial values upost[1,] <- rep(c(.1,-.1), 544/2) kpost[1] <- 15 lpost[1] <- .9 accept[1,] <- 1 # precaluclate some quantities R <- precmat.IGMRFirreglat(A) eigenR <- eigen(R); eigenR.value <- eigenR$values; Q <- (1 - lpost[1]) * diag.spam(544) + lpost[1] * R Q.det <- sum(log(lpost[1]* eigenR.value + 1 - lpost[1])) Q.struct <- chol.spam(Q) postshape <- 0.5 * n - 1 # start sampler for (i in 2:totaln) { ## u ## find tilde u u.tilde <- upost[i-1,] C <- E * exp(u.tilde) B <- Y + (u.tilde - 1) * C Q.tmp <- diag.spam(C) + kpost[i-1] * Q u.tilde <- c(solve.spam(Q.tmp, B)) C.tilde <- E * exp(u.tilde) B.tilde <- Y + (u.tilde - 1) * C.tilde Q.tilde <- diag.spam(C.tilde) + kpost[i-1] * Q u_ <- c(rmvnorm.canonical(1, B.tilde, Q.tilde, Rstruct = Q.struct)) u.tilde_ <- u_ C_ <- E * exp(u.tilde_) B_ <- Y + (u.tilde_- 1) * C_ Q.tmp_ <- diag.spam(C_) + kpost[i-1] * Q u.tilde_ <- c(solve.spam(Q.tmp_, B_)) C.tilde_ <- E * exp(u.tilde_) B.tilde_ <- Y + (u.tilde_- 1) * C.tilde_ log.alpha.u <- sum(Y * u_) - sum(E*exp(u_)) - sum(Y * upost[i-1,]) + sum(E*exp(upost[i-1,]) ) + sum(upost[i-1,] * B.tilde_) - .5 * t(upost[i-1,]) %*% (diag(C.tilde_) %*% upost[i-1,]) - sum(u_* B.tilde) + .5 * t(u_) %*% (diag(C.tilde) %*% u_) if(exp(log.alpha.u) > runif(1)){ upost[i,] <- u_ accept[i,1] <- 1 } else{ upost[i,] <- upost[i-1,] } ## kappa kpost[i] <- rgamma(1, shape = postshape, rate = .5 * upost[i,] %*% (Q %*% upost[i,])) ## lambda lambda_ <- rtrunc(n=1, spec="norm", a=0, b=1, mean=lpost[i-1], sd=lambda.proposal.sd) Q_ <- (1 - lambda_) * diag.spam(544) + lambda_ * R Q.det_ <- sum(log(lambda_* eigenR.value + 1 - lambda_)) alpha.lambda <- exp(.5 * (Q.det_ - kpost[i]* upost[i,] %*% (Q_ %*% upost[i,]) - Q.det + kpost[i]* upost[i,] %*% (Q %*% upost[i,]) )) if(alpha.lambda > runif(1)){ lpost[i] <- lambda_ Q <- Q_ Q.det <- Q.det_ accept[i,2] <- 1 }else{ lpost[i] <- lpost[i-1] } # progress report if(i%%500 == 0) cat(paste(i / 50, "%\n", sep = "" )) } tail(lpost) tail(kpost) upost[i,100:150] if(FALSE){ # remove burnin kpost <- kpost[-seq(burnin)] upost <- upost[-seq(burnin), ] lpost <- lpost[-seq(burnin)] accept <- accept[-seq(burnin),] # thinning index <- c(TRUE, rep(FALSE, (thin - 1))) kpost <- kpost[index] upost <- upost[index,] lpost <- lpost[index] accept <- accept[index,] # acceptance rate apply(accept, 2, mean) par(mfrow = c(1,2)) plot(accept[,1], yaxt = "n", main = expression(beta)) axis(2, at = c(0,1), label = c("no", "yes"), las = 2) plot(accept[,2], yaxt = "n", main = expression(lambda)) axis(2, at = c(0,1), label = c("no", "yes"), las = 2) # trace and mixing plots for the precision parameters # kappa and lambda grid.newpage(); grid_trace2(log(kpost), lpost, chain1_lab = expression(log~kappa), chain2_lab = expression(lambda)) # summary statistics of # kappa and lambda summary(kpost) summary(lpost) par(mfrow = c(1,2)) ## standardized mortality ratios germany.plot(log(Y/E), main = "SMR") ## estimated relative log-risk germany.plot(apply(upost, 2, mean), main = "U | Y, hyper-priors") } options( echo=TRUE) spam/tests/demo_article-jss.Rout.save0000644000176200001440000000536213574427304017427 0ustar liggesusers R version 3.5.0 (2018-04-23) -- "Joy in Playing" Copyright (C) 2018 The R Foundation for Statistical Computing Platform: x86_64-pc-linux-gnu (64-bit) R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. R is a collaborative project with many contributors. Type 'contributors()' for more information and 'citation()' on how to cite R or R packages in publications. Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. > # HEADER #################################################### > # This is file spam/tests/demo_article-jss.R. # > # It is part of the R package spam, # > # --> https://CRAN.R-project.org/package=spam # > # --> https://CRAN.R-project.org/package=spam64 # > # --> https://git.math.uzh.ch/reinhard.furrer/spam # > # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # > # Roman Flury [aut], Daniel Gerber [ctb], # > # Kaspar Moesinger [ctb] # > # HEADER END ################################################ > > > # This demo contains the R code to construct the figures and the table of the > # article: > # "spam: A Sparse Matrix R Package with Emphasis on > # MCMC Methods for Gaussian Markov Random Fields" > # submitted to JSS. > > > # The code presented here differs in the following points form the actually used > # one: > # - Very large grid sizes or very high order neighbor structures are not included > # here; > # - Instead of (100+1) factorizations only (10+1) are performed here; > # - No figure fine-tuning is done here. > # - We had a few additional gc(), just to be sure. > > > > # The following are tests specific. Not all computers run with profiling. Instead > # of commenting, we define dummies. > options( echo=FALSE) Loading required package: dotCall64 Loading required package: grid Spam version 2.5-1 (2019-12-12) is loaded. Type 'help( Spam)' or 'demo( spam)' for a short introduction and overview of this package. Help for individual functions is also obtained by adding the suffix '.spam' to the function name, e.g. 'help( chol.spam)'. [1] 3 5 1 2 4 [1] 1 2 3 3 3 [1] 1 2 3 6 [1] 1.0000000 0.5000000 0.8660254 0.5773503 0.8164966 0.6123724 0.6123724 [8] 0.7905694 0.1581139 0.7745967 [1] 1 2 2 3 3 4 5 [1] 1 3 5 8 [1] 1 3 5 8 10 11 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL > > proc.time() user system elapsed 5.084 0.220 5.308 spam/tests/demo_jss15-Leroux.Rout.save0000644000176200001440000000517213574427304017427 0ustar liggesusers R version 3.5.0 (2018-04-23) -- "Joy in Playing" Copyright (C) 2018 The R Foundation for Statistical Computing Platform: x86_64-pc-linux-gnu (64-bit) R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. R is a collaborative project with many contributors. Type 'contributors()' for more information and 'citation()' on how to cite R or R packages in publications. Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. > # HEADER #################################################### > # This is file spam/tests/demo_jss15-Leroux.R. # > # It is part of the R package spam, # > # --> https://CRAN.R-project.org/package=spam # > # --> https://CRAN.R-project.org/package=spam64 # > # --> https://git.math.uzh.ch/reinhard.furrer/spam # > # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # > # Roman Flury [aut], Daniel Gerber [ctb], # > # Kaspar Moesinger [ctb] # > # HEADER END ################################################ > > options( echo=FALSE) Loading required package: dotCall64 Loading required package: grid Spam version 2.5-1 (2019-12-12) is loaded. Type 'help( Spam)' or 'demo( spam)' for a short introduction and overview of this package. Help for individual functions is also obtained by adding the suffix '.spam' to the function name, e.g. 'help( chol.spam)'. Loading required package: stats4 Attaching package: 'stats4' The following object is masked from 'package:spam': mle Loading required package: evd [1] 0.9890008 0.9836375 0.9836375 0.9941272 0.9941272 0.9941272 [1] 13.60972 12.22357 14.06278 13.51154 13.66835 12.74985 [1] 0.115752190 -0.242792156 0.009907357 -0.144865999 -0.000139589 [6] -0.028916404 -0.032141235 -0.107868843 0.241070191 0.216479530 [11] 0.215633918 0.121392169 0.132614808 0.087540970 0.009744541 [16] 0.033720642 0.156237348 0.044155379 0.272346531 0.040463545 [21] 0.079639678 0.103953125 0.252556753 0.021593753 0.167167125 [26] 0.164189193 0.100494673 -0.213803862 0.117763888 -0.105802996 [31] 0.105966646 -0.099242014 -0.273013722 -0.048069002 -0.043229426 [36] -0.068403094 -0.213240808 -0.168754977 -0.087376979 -0.159318585 [41] -0.066445680 -0.042490650 -0.225786751 -0.311643655 -0.070018302 [46] -0.197298513 -0.172498476 -0.252130284 0.059552503 0.001103394 [51] 0.221565313 > > proc.time() user system elapsed 2.396 0.252 2.675 spam/tests/testthat/0000755000176200001440000000000013574471023014222 5ustar liggesusersspam/tests/testthat/test-ops.R0000644000176200001440000000444513536451711016132 0ustar liggesusers# HEADER #################################################### # This is file spam/tests/testthat/test-ops.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ rm(list = ls()) source("helper.R") ## library("testthat") ## library("spam64", lib.loc = LIB.LOC) ## library("spam", lib.loc = "../../../lib/") context("test-ops.R") # construct matrices: n <- 10 m <- 5 set.seed(14) tt <- matrix(rnorm(m*n),n,m) rr <- matrix(rnorm(m*n),n,m) tt[tt<0] <- 0 rr[rr>0] <- 0 ss <- as.spam(tt) qq <- as.spam(rr) options(spam.structurebased=FALSE) # test for equivalence! options(spam.NAOK=TRUE) # test for equivalence! test_that("ops", { for (f in rev(getGroupMembers("Arith"))) spamtest_eq( do.call(f, list(ss,qq)), do.call(f, list(tt,rr))) for (f in getGroupMembers("Compare")) spamtest_eq( do.call(f, list(ss,qq)), do.call(f, list(tt,rr)), relative = FALSE) for (f in getGroupMembers("Logic")) spamtest_eq( do.call(f, list(ss,qq)), do.call(f, list(tt,rr)), relative = FALSE) tv <- sv <- ss@entries qv <- qq@entries options(spam.structurebased=TRUE) for (g in getGroupMembers("Ops")) { for (f in getGroupMembers(g)) { expect_equal(do.call(f, list(ss,sv))@entries, as.numeric(do.call(f, list(tv,sv)))) expect_equal(do.call(f, list(sv,ss))@entries, as.numeric(do.call(f, list(sv,tv)))) expect_equal(do.call(f, list(ss,4))@entries, as.numeric(do.call(f, list(tv,4)))) } } expect_error(do.call(f, list(ss,1:2))) }) ##################################################################################### test_that("??", { options(spam.inefficiencywarning=TRUE) options(spam.structurebased=FALSE) expect_equal(diag(2)+diag.spam(2), diag(rep(2,2))) }) spam/tests/testthat/test-xybind.R0000644000176200001440000000735413536451712016631 0ustar liggesusers# HEADER #################################################### # This is file spam/tests/testthat/test-xybind.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ rm(list = ls()) source("helper.R") ## library("testthat") ## library("spam64", lib.loc = LIB.LOC) ## library("spam", lib.loc = "../../../lib/") context("test-xybind.R") options(spam.printsize = 60) ###################################################################### test_that("rbind", { xn <- 3 xm <- 2 yn <- 4 ym <- 2 set.seed(14) X <- array(runif(xn*xm), c( xn,xm)) Y <- array(runif(yn*ym), c( yn,ym)) R <- as.spam(X) S <- as.spam(Y) ## cat("Testing with two matrices:\n") spamtest_eq( rbind( X, Y), rbind.spam( X, Y)) spamtest_eq( rbind( X, Y), rbind.spam( R, Y)) spamtest_eq( rbind( X, Y), rbind( R, Y)) spamtest_eq( rbind( X, Y), rbind.spam( X, S)) spamtest_eq( rbind( X, Y), rbind.spam( R, S)) spamtest_eq( rbind( X, Y), rbind( R, S)) spamtest_eq( rbind( X, Y*0), rbind.spam( X, as.spam(Y*0))) spamtest_eq( rbind( X*0, Y), rbind.spam( as.spam(X*0), S)) spamtest_eq( rbind( X*0, Y*0), rbind.spam( as.spam(X*0), as.spam(Y*0)),rel=F) spamtest_eq( rbind( X*0, Y*0), rbind.spam( X*0, Y*0),rel=F) ## cat("Testing with vectors and scalars:\n") spamtest_eq( rbind( X, 1:xm), rbind.spam( X, 1:xm)) spamtest_eq( rbind( X, 1:xm), rbind.spam( R, 1:xm)) spamtest_eq( rbind( 1:ym, Y), rbind.spam( 1:ym, S)) spamtest_eq( rbind( 1, Y), rbind.spam( 1, S)) spamtest_eq( rbind( X, 1), rbind.spam( X, 1)) ## cat("Testing with NULL:\n") spamtest_eq( rbind( X, NULL), rbind.spam( X, NULL)) spamtest_eq( rbind( NULL, X, NULL), rbind.spam( NULL, X, NULL)) spamtest_eq( rbind( NULL, NULL), rbind.spam( NULL, NULL),rel=F) }) ###################################################################### ###################################################################### test_that("cbind", { xn <- 3 xm <- 2 yn <- 3 ym <- 4 set.seed(14) X <- array(runif(xn*xm), c( xn,xm)) Y <- array(runif(yn*ym), c( yn,ym)) R <- as.spam(X) S <- as.spam(Y) ## cat("Testing with two matrices:\n") spamtest_eq( cbind( X, Y), cbind.spam( X, Y)) spamtest_eq( cbind( X, Y), cbind.spam( R, Y)) spamtest_eq( cbind( X, Y), cbind( R, Y)) spamtest_eq( cbind( X, Y), cbind.spam( X, S)) spamtest_eq( cbind( X, Y), cbind.spam( R, S)) spamtest_eq( cbind( X, Y), cbind( R, S)) spamtest_eq( cbind( X, Y*0), cbind.spam( X, as.spam(Y*0))) spamtest_eq( cbind( X*0, Y), cbind.spam( as.spam(X*0), S)) spamtest_eq( cbind( X*0, Y*0), cbind.spam( as.spam(X*0), as.spam(Y*0)),rel=F) spamtest_eq( cbind( X*0, Y*0), cbind.spam( X*0, Y*0),rel=F) ## cat("Testing with vectors and scalars:\n") spamtest_eq( cbind( X, 1:xn), cbind.spam( X, 1:xn)) spamtest_eq( cbind( X, 1:xn), cbind.spam( R, 1:xn)) spamtest_eq( cbind( 1:yn, Y), cbind.spam( 1:yn, S)) spamtest_eq( cbind( 1, Y), cbind.spam( 1, S)) spamtest_eq( cbind( X, 1), cbind.spam( X, 1)) ## cat("Testing with NULL:\n") spamtest_eq( cbind( X, NULL), cbind.spam( X, NULL)) spamtest_eq( cbind( NULL, X, NULL), cbind.spam( NULL, X, NULL)) spamtest_eq( cbind( NULL, NULL), cbind.spam( NULL, NULL),rel=F) }) spam/tests/testthat/test-overall.R0000644000176200001440000002062713536451711016775 0ustar liggesusers# HEADER #################################################### # This is file spam/tests/testthat/test-overall.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ rm(list = ls()) source("helper.R") ## library("testthat") ## library("spam", lib.loc = LIB.LOC) context("test-overall.R") options(spam.structurebased = FALSE) # construct matrices (should be at least 3x5, with n https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ rm(list = ls()) source("helper.R") ## library("testthat") ## library("spam64", lib.loc = LIB.LOC) ## library("spam", lib.loc = "../../../lib/") context("test-helper.R") ######## set.seed(14) # bdiag.spam: A <- spam(rnorm(10),2) B <- spam(rnorm(16),4) test_that("bdiag.spam", { spamtest_eq( bdiag.spam(A),A) spamtest_eq( bdiag.spam(A,B),rbind(cbind(A,rep(0,8)), cbind(spam(rep(0,20),4),B))) }) n <- 5 Sigma <- .25^abs(outer(1:n,1:n,'-')) Q <- as.spam(solve(Sigma)) b <- 1:n struct <- chol(Q) test_that("rmvnorm", { set.seed(14) tmp1 <- rmvnorm.canonical(10, b, Q) set.seed(14) spamtest_eq( rmvnorm.canonical(10, b, Q, Lstruct=struct), tmp1 ) set.seed(14) spamtest_eq( rmvnorm.prec(10, solve(Q,b), Q), tmp1 ) set.seed(14) spamtest_eq( rmvnorm.prec(10, solve(Q,b), Q, Lstruct=struct), tmp1 ) set.seed(14) ## cat("For rmvnorm.canonical:\n- comparing sample mean with truth:\n") ## for (i in 10^(1:4)) ## cat(' sample size n=',i,' yields Frobenius-norm:', ## norm( apply(rmvnorm.canonical(i, b, Q, Lstruct=struct), 2,mean)- solve(Q,b),'f'),'\n') ## cat("- comparing sample variance with truth:\n") ## for (i in 10^(1:4)){ ## cat(' sample size n=',i,' yields Frobenius-norm:', ## norm( var( rmvnorm.canonical(i, b, Q=Q, Lstruct=struct))- Sigma,'f'),'\n') ## set.seed(14) ## cat("For rmvnorm.prec:\n- comparing sample mean with truth:\n") ## for (i in 10^(1:4)) ## cat(' sample size n=',i,' yields Frobenius-norm:', ## norm( apply(rmvnorm.prec(i, b, Q, Lstruct=struct), 2,mean)- b,'f'),'\n') ## cat("- comparing sample variance with truth:\n") ## for (i in 10^(1:4)){ ## cat(' sample size n=',i,' yields Frobenius-norm:', ## norm( var( rmvnorm.prec(i, Q=Q, Lstruct=struct))- Sigma,'f'),'\n') ## } ## set.seed(14) ## cat("For rmvnorm.spam:\n- comparing sample mean with truth:\n") ## for (i in 10^(1:4)) ## cat(' sample size n=',i,' yields Frobenius-norm:', ## norm( apply(rmvnorm.spam(i, b, as.spam(Sigma), Lstruct=struct), 2,mean)- b,'f'),'\n') ## cat("- comparing sample variance with truth:\n") ## for (i in 10^(1:4)){ ## cat(' sample size n=',i,' yields Frobenius-norm:', ## norm( var( rmvnorm.spam(i, b, as.spam(Sigma), Lstruct=struct))- Sigma,'f'),'\n') ## } }) spam/tests/testthat/test-math.R0000644000176200001440000001211013536451711016246 0ustar liggesusers# HEADER #################################################### # This is file spam/tests/testthat/test-math.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ rm(list = ls()) source("helper.R") ## library("testthat") ## library("spam64", lib.loc = LIB.LOC) ## library("spam", lib.loc = LIB.LOC) context("test-math.R") # see Matrix::rsparsematrix spam_random <- function(n, m=n, nnz=min(m-1,4)*n, fill=rnorm, seed=NULL, ...) { if (!is.null(seed)) set.seed(seed) ind <- sample.int((n*m), size=nnz) # # as.spam( list(i=(ind %% m)+1, j=(ind %/% n)+1, fill(length(ind), ...))) tmp <- matrix(0,n,m) tmp[ind] <- fill(length( ind), ...) as.spam(tmp) } # construct matrices: n <- 10 m <- 5 set.seed(14) tt <- matrix(rnorm(m*n),n,m) tt[tt<0] <- 0 ss <- as.spam(tt) options(spam.structurebased=FALSE) # test for equivalence! # ‘Math’ ‘"abs"’, ‘"sign"’, ‘"sqrt"’, ‘"ceiling"’, ‘"floor"’, # ‘"trunc"’, ‘"cummax"’, ‘"cummin"’, ‘"cumprod"’, ‘"cumsum"’, # ‘"log"’, ‘"log10"’, ‘"log2"’, ‘"log1p"’, ‘"acos"’, ‘"acosh"’, # ‘"asin"’, ‘"asinh"’, ‘"atan"’, ‘"atanh"’, ‘"exp"’, ‘"expm1"’, # ‘"cos"’, ‘"cosh"’, ‘"cospi"’, ‘"sin"’, ‘"sinh"’, ‘"sinpi"’, # ‘"tan"’, ‘"tanh"’, ‘"tanpi"’, ‘"gamma"’, ‘"lgamma"’, # ‘"digamma"’, ‘"trigamma"’ # ‘Math2’ ‘"round"’, ‘"signif"’ # ‘Summary’ ‘"max"’, ‘"min"’, ‘"range"’, ‘"prod"’, ‘"sum"’, ‘"any"’, ‘"all"’ # # ! test_that("math", { A <- diag.spam(4) ; B <- diag(4) spamtest_eq(A, B) spamtest_eq(!A, !B) diag(A)=0 ; diag(B) <- 0 spamtest_eq(!A, !B) # str(A) # is what needs to be expected..., # different to spam:::complement.spam(A) }) test_that("math Summary", { expect_equal(max(ss), max(tt)) expect_equal(min(ss), min(tt)) expect_equal(range(ss), range(tt)) expect_equal(prod(ss), prod(tt)) expect_equal(sum(ss), sum(tt)) expect_warning(anytt <- any(tt), "coercing argument") expect_equal(any(ss), anytt) expect_warning(alltt <- all(tt), "coercing argument") expect_equal(all(ss), alltt) }) test_that("Math2", { spamtest_eq(round(ss), round(tt)) spamtest_eq(signif(ss), signif(tt)) # ‘Math’ ‘"abs"’, ‘"sign"’, ‘"sqrt"’, ‘"ceiling"’, ‘"floor"’, # ‘"trunc"’, ‘"log1p"’ # ‘"asin"’, ‘"asinh"’, ‘"atan"’, ‘"atanh"’, ‘"expm1"’, # ‘"sin"’, ‘"sinh"’, ‘"sinpi"’, # ‘"tan"’, ‘"tanh"’, ‘"tanpi"’, # ‘"cummax"’, ‘"cummin"’, ‘"cumprod"’, ‘"cumsum"’, # ‘"log"’, ‘"log10"’, ‘"log2"’, ‘"acos"’, ‘"acosh"’, # , ‘"exp"’, ‘"cos"’, ‘"cosh"’, ‘"cospi"’ # ‘"gamma"’, ‘"lgamma"’, ‘"digamma"’, ‘"trigamma"’ spamtest_eq(abs(ss), abs(tt)) spamtest_eq(cos(ss), cos(tt)) spamtest_eq(cosh(ss), cosh(tt)) options(spam.NAOK=TRUE) # test for equivalence! expect_equal(suppressWarnings(c(gamma(tt))), suppressWarnings(c(gamma(ss))), rel = FALSE) # expect_equal(c(suppressWarnings(digamma(ss))), suppressWarnings(c(digamma(tt)))) # expect_equal(c(trigamma(ss)), c(trigamma(tt))) spamtest_eq(exp(ss), exp(tt)) spamtest_eq(expm1(ss), expm1(tt)) expect_equal(c(log(ss)), c(log(tt))) spamtest_eq(cummax(ss), cummax(tt)) ## TODO ## for (f in getGroupMembers("Math")) ## spamtest_eq(do.call(f, list(ss)), ## do.call(f, list(tt)), relative = FALSE) for ( i in c(TRUE, FALSE)) { options(spam.structurebased=i) set.seed(122) S1 <- spam_random(5, nnz=10) S2 <- spam_random(5, nnz=10) F1 <- as.matrix(S1) F2 <- as.matrix(S2) spamtest_eq(S1+S2, F1+F2) spamtest_eq(S1+F2, F1+F2) spamtest_eq(F1+S2, F1+F2) spamtest_eq(S1-S2, F1-F2) spamtest_eq(S1-F2, F1-F2) spamtest_eq(F1-S2, F1-F2) S1 <- spam_random(5, nnz=0) S2 <- spam_random(5, nnz=10) F1 <- as.matrix(S1) F2 <- as.matrix(S2) spamtest_eq(S1+S2, F1+F2) spamtest_eq(S1+F2, F1+F2) spamtest_eq(F1+S2, F1+F2) spamtest_eq(S1-S2, F1-F2) spamtest_eq(S1-F2, F1-F2) spamtest_eq(F1-S2, F1-F2) } }) spam/tests/testthat/test-rep_len64.R0000644000176200001440000000273313536451712017126 0ustar liggesusers# HEADER #################################################### # This is file spam/tests/testthat/test-rep_len64.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ rm(list = ls()) source("helper.R") ## library("testthat", lib.loc = LIB.LOC) ## library("spam64", lib.loc = LIB.LOC) ## library("spam", lib.loc = LIB.LOC) context("test-rep_len64.R") options(spam.printsize=6) test_that("rep_len64-force64=FALSE", { options(spam.force64=FALSE) expect_equal(rep_len(1, 10), spam:::rep_len64(1, 10)) expect_equal(rep_len(1L, 10L), spam:::rep_len64(1L, 10L)) expect_equal(rep_len(1:2, 10L), spam:::rep_len64(1:2, 10L)) expect_equal(rep_len(1:3, 16), spam:::rep_len64(1:3, 16)) }) ## test_that("rep_len64-force64=TRUE", { ## options(spam.force64=TRUE) ## expect_equal(rep_len(1, 10), spam:::rep_len64(1, 10)) ## expect_equal(rep_len(1L, 10L), spam:::rep_len64(1L, 10L)) ## expect_equal(rep_len(1:2, 10L), spam:::rep_len64(1:2, 10L)) ## expect_equal(rep_len(1:3, 16), spam:::rep_len64(1:3, 16)) ## }) spam/tests/testthat/test-eigen.R0000644000176200001440000000573113573435622016423 0ustar liggesusers# HEADER #################################################### # This is file spam/tests/testthat/test-eigen.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ rm(list = ls()) source("helper.R") context("test-eigen.R") options(spam.force64 = FALSE) nEV <- 50 prec2020 <- precmat.GMRFreglat(20,20) dn_gmrf <- spam::precmat.GMRFreglat(20, 20, c(.4,.3,.2,.1),'m2p4') dn_gmrf[1:10, 1] <- 100 test_that("check format of return", { spameigen <- eigen.spam(prec2020, nev = nEV, control = list(spamflag = TRUE, mode = 'LM'), only.values = FALSE) nsys_spameigen <- eigen.spam(dn_gmrf, nev = nEV, control = list(spamflag = TRUE, mode = 'LM'), only.values = FALSE) expect_true(is(spameigen, "list")) expect_true(is(spameigen$values, "numeric")) expect_true(is(spameigen$vectors, "matrix")) expect_true(is(nsys_spameigen, "list")) expect_true(is(nsys_spameigen$values, "complex")) expect_true(is(nsys_spameigen$vectors, "matrix")) }) test_that("eigenvalues", { baseeigen <- eigen(prec2020, only.values = TRUE) spameigenL <- eigen.spam(prec2020, nev = nEV, control = list(spamflag = T, mode = 'LM'), only.values = TRUE) spameigenS <- eigen.spam(prec2020, nev = nEV, control = list(spamflag = T, mode = 'SM'), only.values = TRUE) spamtest_eq(head(baseeigen$values, nEV), head(spameigenL$values, nEV), relative = FALSE) spamtest_eq(tail(baseeigen$values, nEV), tail(spameigenS$values, nEV), relative = FALSE) nsys_baseeigen <- eigen(dn_gmrf, only.values = TRUE) nsys_spameigenL <- eigen.spam(dn_gmrf, nev = nEV, control = list(spamflag = T, mode = 'LR', ncv = 400), only.values = TRUE, symmetric = FALSE) nsys_spameigenS <- eigen.spam(dn_gmrf, nev = nEV, control = list(spamflag = T, mode = 'SR'), only.values = TRUE) # spamtest_eq(head(nsys_baseeigen$values, nEV), head(nsys_spameigenL$values, nEV), relative = FALSE) # spamtest_eq(tail(nsys_baseeigen$values, nEV), tail(nsys_spameigenS$values, nEV), relative = TRUE) }) test_that("eigenvectors", { baseeigen <- eigen(prec2020, only.values = FALSE) spameigenL <- eigen.spam(prec2020, nev = nEV, control = list(spamflag = T, mode = 'LM'), only.values = FALSE) spameigenS <- eigen.spam(prec2020, nev = nEV, control = list(spamflag = T, mode = 'SM'), only.values = FALSE) for (i in 1:nEV) {spamtest_eq(sqrt(sum(spameigenL$vectors[, i]^2)), 1) } for (i in 1:nEV) {spamtest_eq(sqrt(sum(spameigenS$vectors[, i]^2)), 1) } for (i in 1:nEV) {spamtest_eq(as.matrix(prec2020)%*%spameigenL$vectors[, i], spameigenL$vectors[, i]*spameigenL$values[i]) } }) spam/tests/testthat/test-constructors.R0000644000176200001440000000425113536451711020074 0ustar liggesusers# HEADER #################################################### # This is file spam/tests/testthat/test-constructors.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ rm(list = ls()) source("helper.R") # source("tests/testthat/helper.R")##### ## library("testthat") ## library("spam64", lib.loc = LIB.LOC) ## library("spam", lib.loc = "../../../lib/") context("test-constructors.R") options(spam.printsize = 60) set.seed(14) n <- 7 ln <- 50 A <- spam(0,n,n) is <- sample(n, ln, replace = TRUE) js <- sample(n, ln, replace = TRUE) A[ unique( cbind(is,js))[1:16,] ] <- 1:8 re <- A@rowpointers rowpointers(A) <- re # following will case error, thus the `try` test_that("test for error messages", { r <- re; r[1:2] <- rev(r[1:2]); expect_error(rowpointers(A) <- r, "row pointers are not monotone increasing") r <- re; r[n+1] <- 2; expect_error(rowpointers(A) <- r, "row pointers are not monotone increasing") r <- re; r[1] <- 0; expect_error(rowpointers(A) <- r, "first element of row pointers is < 1") r <- re; r[n+1] <- 20; expect_error( rowpointers(A) <- r ) r <- c(rep(1,n),n+1); expect_error( rowpointers(A) <- r ) ce <- A@colindices colindices(A) <- ce ## TODO expect error or not ?? currrently does not return an error ## r <- ce; r[1:4] <- rev(r[1:4]); ## expect_error( colindices(A) <- r ) r <- ce; r[1] <- 0; expect_error( colindices(A) <- r ) r <- ce; r[1] <- 20; expect_error( colindices(A) <- r ) entries(A) <- A@entries expect_error( entries(A) <- as.logical(A@entries)) expect_error( entries(A) <- c(r,1)) expect_error( entries(A) <- r[-1]) expect_error( dimension(A) <- c(1,2)) }) spam/tests/testthat/test-spamlist.R0000644000176200001440000000711613536451712017164 0ustar liggesusers# HEADER #################################################### # This is file spam/tests/testthat/test-spamlist.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ rm(list = ls()) source("helper.R") ## library("testthat") ## library("spam64", lib.loc = LIB.LOC) ## library("spam", lib.loc = "../../../lib/") context("test-spamlist.R") ######## test_that("spam.list", { spamtest_eq(spam( list(ind=numeric(0), j=numeric(0), numeric(0)),nrow=4,ncol=3), spam(0,4,3),rel=FALSE) i <- c(1,2,3,4,5) j <- c(5,4,3,2,1) ss3 <- spam(0,5,5) ss3[cbind(i,j)] <- i/j spamtest_eq(spam.list(list(i=i,j=j,i/j)), ss3) pad(ss3) <- c(13,13) spamtest_eq(spam.list(list(i=i,j=j,i/j),13,13), ss3) pad(ss3) <- c(3,3) spamtest_eq(spam.list(list(i=i,j=j,i/j),3,3), ss3) pad(ss3) <- c(2,2) spamtest_eq(spam.list(list(i=i,j=j,i/j),2,2), ss3,rel=F) spamtest_eq({options(spam.listmethod='EP'); spam.list(list(i=i,j=j,i/j),ncol=3)}, {options(spam.listmethod='BS'); method='BS';spam.list(list(i=i,j=j,i/j),ncol=3)}) spamtest_eq({options(spam.listmethod='EP'); spam.list(list(i=i,j=j,i/j),ncol=3,nrow=4)}, {options(spam.listmethod='BS'); spam.list(list(i=i,j=j,i/j),ncol=3,nrow=4)}) spamtest_eq(spam.list(list(i=i,j=j,i/j),ncol=1,nrow=1), 0,rel=F) set.seed(2011) m = 1000 rmax = 30 cmax = 40 i = floor(runif(m) * rmax) + 1 j = floor(runif(m) * cmax) + 1 val = floor(10 * runif(m)) + 1 options(spam.listmethod='EP') ss1 <- spam.list(list(i=i,j=j,val)) options(spam.listmethod='BS') ss2 <- spam.list(list(i=i,j=j,val)) spamtest_eq(ss1,ss2,rel=F) }) test_that("spam with list", { spamtest_eq(spam( list(ind=numeric(0), j=numeric(0), numeric(0)),nrow=4,ncol=3), spam(0,4,3),rel=FALSE) i <- c(1,2,3,4,5) j <- c(5,4,3,2,1) ss3 <- spam(0,5,5) ss3[cbind(i,j)] <- i/j spamtest_eq(spam(list(i=i,j=j,i/j)), ss3) pad(ss3) <- c(13,13) spamtest_eq(spam(list(i=i,j=j,i/j),13,13), ss3) pad(ss3) <- c(3,3) spamtest_eq(spam(list(i=i,j=j,i/j),3,3), ss3) pad(ss3) <- c(2,2) spamtest_eq(spam(list(i=i,j=j,i/j),2,2), ss3,rel=F) spamtest_eq({options(spam.listmethod='EP'); spam(list(i=i,j=j,i/j),ncol=3)}, {options(spam.listmethod='BS'); method='BS';spam(list(i=i,j=j,i/j),ncol=3)}) spamtest_eq({options(spam.listmethod='EP'); spam(list(i=i,j=j,i/j),ncol=3,nrow=4)}, {options(spam.listmethod='BS'); spam(list(i=i,j=j,i/j),ncol=3,nrow=4)}) spamtest_eq(spam(list(i=i,j=j,i/j),ncol=1,nrow=1), 0,rel=F) set.seed(2011) m = 1000 rmax = 30 cmax = 40 i = floor(runif(m) * rmax) + 1 j = floor(runif(m) * cmax) + 1 val = floor(10 * runif(m)) + 1 options(spam.listmethod='EP') ss1 <- spam(list(i=i,j=j,val)) options(spam.listmethod='BS') ss2 <- spam(list(i=i,j=j,val)) spamtest_eq(ss1,ss2,rel=F) }) spam/tests/testthat/test-dist.R0000644000176200001440000001611213536451711016266 0ustar liggesusers# HEADER #################################################### # This is file spam/tests/testthat/test-dist.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ rm(list = ls()) source("helper.R") ## library("testthat") ## library("spam64", lib.loc = LIB.LOC) ## library("spam", lib.loc = "../../../lib/") context("test-dist.R") distmatrix <- function(x1,x2=NULL,upper=NULL,...) { if (is.null(x2)) { tmp <- as.matrix(dist(x1,...)) if (is.null(upper)) return(tmp) if (upper) tmp[row(tmp)col(tmp)] <- -1 return( tmp[tmp>-0.5]) } else return( as.matrix( dist(rbind(x1,x2),...))[1:dim(x1)[1],1:dim(x2)[1]+dim(x1)[1]]) } ######## ## as an aside, comparing nearest.dist with dist, use diag=true, upper=TRUE test_that("comparing nearest.dist with dist, use diag=true, upper=TRUE",{ options(spam.printsize=6) n1 <- as.integer( 4) n2 <- n1 nd <- as.integer(2) set.seed(14) x2 <- x1 <- array(runif(n1*nd), c( n1,nd)) if (F){ # testing the structure distmatrix(x1) nearest.dist( x1, x1, upper=NULL) # and all other possibilities (3[upper]) # with x1,x1 and x1, NULL: par(mfcol=c(3,2)) display( nearest.dist( x1, x1, upper=NULL)) # default display( nearest.dist( x1, x1, upper=FALSE)) display( nearest.dist( x1, x1, upper=TRUE)) display( nearest.dist( x1, upper=NULL)) display( nearest.dist( x1, upper=FALSE)) display( nearest.dist( x1, upper=TRUE)) } # nearest.dist( x1) and nearest.dist( x1,x1) should be identical... expect_equal(nearest.dist( x1, x1, upper=NULL), nearest.dist(x1, upper=NULL) ) expect_equal(nearest.dist( x1, x1, upper=FALSE), nearest.dist(x1, upper=FALSE)) expect_equal(nearest.dist( x1, x1, upper=TRUE), nearest.dist(x1, upper=TRUE) ) # testing Euclidian eta <- 1 o1 <- nearest.dist( x1, upper=NULL) o2 <- distmatrix(x1) expect_equal(o2[o2< eta], o1@entries) o1 <- nearest.dist( x1, upper=!FALSE) # is default... o3 <- distmatrix(x1, upper=!FALSE) expect_equal(o1@entries, o3) x2 <- x1 <- array(runif(n1*nd), c( n1,nd)) o1 <- nearest.dist( x1,x2,upper=NULL) o2 <- distmatrix(x1,x2) expect_equal(o2[o2< eta], o1@entries) ## TODO check test. ## o1 <- nearest.dist( x1, upper=!FALSE) ## expect_equal(o2[o2< eta & lower.tri(o2)], o1@entries) # Should cause error: # nearest.dist(cbind(1,1)) # this is ok: spamtest_eq( nearest.dist(rbind(1,0)), c(0,1,0,0)) spamtest_eq( nearest.dist(cbind(1,1),cbind(1,0)), 1) # testing with dist only spamtest_eq( as.spam( dist(x1)), nearest.dist(x1,delta=2)) # testing some other norms method <- "max" p <- 1.0001 o1 <- nearest.dist( x1,method=method,p=p, upper=TRUE ) o3 <- distmatrix(x1,method=method,p=p, upper=TRUE) expect_equal(o1@entries, o3) if (F){ # system.time is not always available... n1 <- as.integer( 400) set.seed(14) x1 <- array(runif(n1*nd), c( n1,nd)) system.time( o1 <- nearest.dist( x1,method="max",p=p) ) system.time( o1 <- nearest.dist( x1,method="min",p=1) ) system.time( o1 <- nearest.dist( x1,method="min",p=1.5) ) system.time( o1 <- nearest.dist( x1,method="min",p=2) ) system.time( o1 <- nearest.dist( x1,method="euc",p=1) ) system.time( o1 <- dist( x1) ) } # testing GC n1 <- as.integer( 4) n2 <- as.integer(6) set.seed(14) x1 <- array(runif(n1*2,-90,90), c( n1,2)) x2 <- array(runif(n2*2,-90,90), c( n2,2)) if (F){ # structure delta <- 180 par(mfcol=c(3,2)) display( nearest.dist( x1, delta=delta,method="gr", upper=FALSE)) display( nearest.dist( x1, delta=delta,method="gr", upper=TRUE)) display( nearest.dist( x1, delta=delta,method="gr", upper=NULL)) display( nearest.dist( x1,x1, delta=delta,method="gr", upper=FALSE)) display( nearest.dist( x1,x1, delta=delta,method="gr", upper=TRUE)) display( nearest.dist( x1,x1, delta=delta,method="gr", upper=NULL)) } # if (F){ # if fields would be available, the following can be used as well. delta <- 180 o2 <- rdist.earth(x1) o1 <- nearest.dist( x1, method="gr",upper=NULL,delta=delta) spamtest_eq(o2- o1@entries) o2 <- rdist.earth(x1, R=1) o1 <- nearest.dist( x1, method="gr",upper=NULL,delta=delta,R=1) spamtest_eq(o2- o1@entries) delta <- 90 o2 <- rdist.earth(x2,x1,R=1) o1 <- nearest.dist( x1,x2, method="gr",upper=NULL,delta=delta,R=1) spamtest_eq(o2[o2 https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ rm(list = ls()) source("helper.R") ## library("testthat") ## library("spam64", lib.loc = LIB.LOC) ## library("spam", lib.loc = "../../../lib/") context("test-rowcolstats.R") # simple tests: ######################################################################## # construct matrices: n <- 10 m <- 15 set.seed(14) tt <- matrix(rnorm(m*n),n,m) tt[tt<0] <- 0 ss <- as.spam(tt) test_that("rowcolstats", { spamtest_eq(rowSums.spam(ss),rowSums(tt)) spamtest_eq(colSums.spam(ss),colSums(tt)) spamtest_eq(rowSums(ss),rowSums(tt)) spamtest_eq(colSums(ss),colSums(tt)) options(spam.structurebased=FALSE) spamtest_eq(rowMeans.spam(ss),rowMeans(tt)) spamtest_eq(colMeans.spam(ss),colMeans(tt)) spamtest_eq(rowMeans(ss),rowMeans(tt)) spamtest_eq(colMeans(ss),colMeans(tt)) options(spam.structurebased=TRUE) spamtest_eq(rowMeans.spam(ss),rowSums(tt)/apply(tt>0,1,sum)) spamtest_eq(colMeans.spam(ss),colSums(tt)/apply(tt>0,2,sum)) spamtest_eq(rowMeans(ss),rowSums(tt)/apply(tt>0,1,sum)) spamtest_eq(colMeans(ss),colSums(tt)/apply(tt>0,2,sum)) spamtest_eq(rowMeans.spam(ss),apply.spam(ss,1,mean)) spamtest_eq(colMeans.spam(ss),apply.spam(ss,2,mean)) spamtest_eq(rowMeans(ss),apply.spam(ss,1,mean)) spamtest_eq(colMeans(ss),apply.spam(ss,2,mean)) spamtest_eq(rowMeans.spam(spam(0,n,m)),rowMeans(tt*0), relative = FALSE) spamtest_eq(colMeans.spam(spam(0,n,m)),colMeans(tt*0), relative = FALSE) spamtest_eq(rowMeans.spam(as.spam(diag(0,n))),rowMeans(diag(0,n)), relative = FALSE) spamtest_eq(colMeans.spam(as.spam(diag(0,n))),colMeans(diag(0,n)), relative = FALSE) spamtest_eq(rowMeans(spam(0,n,m)),rowMeans(tt*0), relative = FALSE) spamtest_eq(colMeans(spam(0,n,m)),colMeans(tt*0), relative = FALSE) spamtest_eq(rowMeans(as.spam(diag(0,n))),rowMeans(diag(0,n)), relative = FALSE) spamtest_eq(colMeans(as.spam(diag(0,n))),colMeans(diag(0,n)), relative = FALSE) options(spam.structurebased=TRUE) }) spam/tests/testthat/test-diff.R0000644000176200001440000000223613536451711016235 0ustar liggesusers# HEADER #################################################### # This is file spam/tests/testthat/test-diff.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ rm(list = ls()) source("helper.R") ## library("testthat") ## library("spam64", lib.loc = LIB.LOC) ## library("spam", lib.loc = "../../../lib/") context("test-diff.R") options(spam.structurebased=FALSE) # test for equivalence! n <- 10 x <- array(rnorm(n^2),c(n,n)) test_that("diff", { spamtest_eq(diff(x), diff(as.spam(x))) spamtest_eq(diff(x,d=2), diff(as.spam(x), d=2)) spamtest_eq(diff(x,d=4), diff(as.spam(x), d=4)) spamtest_eq(diff(x,2, d=2), diff(as.spam(x),2, d=2)) expect_equal(diff(x,4, d=4), diff(as.spam(x),4, d=4)) }) spam/tests/testthat/test-crossprod.R0000644000176200001440000000324013536451711017337 0ustar liggesusers# HEADER #################################################### # This is file spam/tests/testthat/test-crossprod.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ rm(list = ls()) source("helper.R") ## library("testthat") ## library("spam64", lib.loc = LIB.LOC) ## library("spam", lib.loc = "../../../lib/") context("test-crossprod.R") options(spam.printsize=60) ###################################################################### test_that("crossprod n=1", { set.seed(1) xf <- rnorm(10) xf[xf<0] <- 0 xs <- as.spam(xf) yf <- rnorm(10) yf[yf<0] <- 0 ys <- as.spam(yf) spamtest_eq( crossprod( xf), crossprod.spam( xs)) spamtest_eq( crossprod( xf, yf), crossprod.spam( xs, ys)) spamtest_eq( crossprod( xf, yf), crossprod.spam( xs, yf)) # now dispatching spamtest_eq( crossprod( xf), crossprod( xs)) spamtest_eq( crossprod( xf, yf), crossprod( xs, ys)) spamtest_eq( crossprod( xf, yf), crossprod( xs, yf)) dim(xf) <- c(2,5) dim(yf) <- c(2,5) ys <- as.spam(yf) xs <- as.spam(xf) spamtest_eq( crossprod( xf, yf), crossprod.spam( xs, ys)) # now dispatching spamtest_eq( crossprod( xf, yf), crossprod( xs, ys)) }) spam/tests/testthat/test-profile.R0000644000176200001440000000345313536451711016767 0ustar liggesusers# HEADER #################################################### # This is file spam/tests/testthat/test-profile.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ rm(list = ls()) source("helper.R") ## library("testthat") ## library("spam64", lib.loc = LIB.LOC) ## library("spam", lib.loc = "../../../lib/") context("test-profile.R") test_that(".format.spam()",{ s <- spam(1) # s64 <- spam(1, force64 = TRUE) expect_identical(spam:::.format.spam(s), spam:::.format32) # expect_identical(spam:::.format.spam(s64), spam:::.format64) # expect_identical(spam:::.format.spam(s, s64), spam:::.format64) # expect_identical(spam:::.format.spam(s, s, s, s64), spam:::.format64) # expect_identical(spam:::.format.spam(s64, s64, s64), spam:::.format64) expect_identical(spam:::.format.spam(s, s, s), spam:::.format32) ## test fallback s_corrupt <- s; s_corrupt@colindices <- as.double(s_corrupt@colindices) expect_identical(spam:::.format.spam(s_corrupt), spam:::.format32, info = "test fallback") ## test if validater is called a <- spam(1) a@entries[1] <- NA expect_warning(spam:::.format.spam(a, validate = TRUE), "Slot 'entries' contains non-finite elements.", info = ".format.spam() and validater") }) ## to be added ## test_that(".validate_spam()",{ ## }) spam/tests/testthat/test-permutation.R0000644000176200001440000000405513536451711017675 0ustar liggesusers# HEADER #################################################### # This is file spam/tests/testthat/test-permutation.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ rm(list = ls()) source("helper.R") ## library("testthat") ## library("spam64", lib.loc = LIB.LOC) ## library("spam", lib.loc = "../../../lib/") context("test-permutation.R") ######## set.seed(14) res <- 12.5 grid <- expand.grid(lat=seq(-90+3*res/2,to=90-res,by=res),lon=seq(res/2,to=360,by=res)) dist <- nearest.dist(grid[,2:1],method='gr',upper=NULL, delta=30,R=1) distm <- as.matrix(dist) n <- dim(dist)[1] perm <- sample.int(n,n) test_that("permutation.spam", { spamtest_eq(permutation.spam(dist,P=perm),distm[order(perm),]) spamtest_eq(permutation.spam(dist,Q=perm),distm[,order(perm)]) spamtest_eq(permutation.spam(dist,P=perm,ind=T),distm[perm,]) spamtest_eq(permutation.spam(dist,Q=perm,ind=T),distm[,perm]) spamtest_eq(permutation(dist,P=perm),distm[order(perm),]) spamtest_eq(permutation(dist,Q=perm),distm[,order(perm)]) spamtest_eq(permutation(dist,P=perm,ind=T),distm[perm,]) spamtest_eq(permutation(dist,Q=perm,ind=T),distm[,perm]) spamtest_eq(permutation(distm,P=perm),distm[order(perm),]) spamtest_eq(permutation(distm,Q=perm),distm[,order(perm)]) spamtest_eq(permutation(distm,P=perm,ind=T),distm[perm,]) spamtest_eq(permutation(distm,Q=perm,ind=T),distm[,perm]) spamtest_eq(t(permutation.spam(t(dist),P=perm)),distm[,order(perm)]) spamtest_eq(t(permutation(t(dist),P=perm)),distm[,order(perm)]) spamtest_eq(t(permutation(t(distm),P=perm)),distm[,order(perm)]) }) spam/tests/testthat/helper.R0000644000176200001440000000714513536451711015633 0ustar liggesusers# HEADER #################################################### # This is file spam/tests/testthat/helper.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ require('spam') # For efficient primary testing: # require('spam',lib='lib') ; setwd( 'spam/tests/testthat/') ;require('testthat') # for (i in rev(system('ls', intern=T) )) source(i) spamtest_eq <- function( xtest, xtrue, tol= 1.0e-1, relative=TRUE, label="", ...){ cxtest <- c(xtest); cxtrue <- c(xtrue) if(relative) denom <- mean(abs(cxtrue), na.rm = TRUE) else denom <- 1 test_value <- sum(abs(cxtest - cxtrue), na.rm = TRUE) / denom expect_lt(test_value, tol, label = paste( "[spamtest_eg failed]", label), ...) } spamtest_diff <- function( xtest, xtrue, tol= 1.0e-6, relative=TRUE, label="", ...){ cxtest <- c(xtest); cxtrue <- c(xtrue) if(relative) denom <- mean(abs(cxtrue), na.rm = TRUE) else denom <- 1 test_value <- sum(abs(cxtest - cxtrue), na.rm = TRUE) / denom expect_gt(test_value, tol, label = paste( "[spamtest_diff failed]", label), ...) } LIB.LOC <- "../../../lib" ## reset to inital settings default_options <- list( spam.eps=.Machine$double.eps, # smaller than this is considered as zero spam.force64=FALSE, spam.validate=FALSE, # validate the spam object before calling a native routine for # increased stability. spam.drop=FALSE, # drop passed to subset functions spam.printsize=100, # the max size which we print as regular matrices spam.imagesize=10000, # the max size which we display as regular matrices spam.cex=1200, # scaling factor for scatter displays spam.structurebased=TRUE, # calculating on nonzero entries only... spam.inefficiencywarning=1e6, # tell when something inefficient is done spam.trivalues=FALSE, # with upper./lower/.tri return values (TRUE) or only structure? spam.listmethod="PE", # method to be used when using spam.list spam.NAOK = FALSE, safemodevalidity=TRUE, # verify while S4 construction spam.dopivoting=TRUE, # what type of back/forwardsolve? spam.cholsymmetrycheck=TRUE, # Should symmetry be tested in the cholesky factorization spam.cholpivotcheck=TRUE, # Should the pivot be tested? spam.cholupdatesingular="warning", # ("error", "warning","NULL") spam.cholincreasefactor=c(1.25,1.25), spam.nearestdistincreasefactor=1.3, spam.nearestdistnnz=c(500^2,500) ) # Load the default settings: options(default_options) spam/tests/testthat/test-covmat.R0000644000176200001440000000267213536451711016622 0ustar liggesusers# HEADER #################################################### # This is file spam/tests/testthat/test-covmat.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ rm(list = ls()) source("helper.R") ## library("testthat") ## library("spam64", lib.loc = LIB.LOC) ## library("spam", lib.loc = "../../../lib/") context("test-covmat.R") test_that("cov.*", { h <- nearest.dist(100*1:10, 100*1:10+1:10, delta=10) expect_identical(cov.exp(1:10, 10), cov.exp(h, 10)@entries) expect_identical(cov.sph(1:10, 10), cov.sph(h, 10)@entries) expect_identical(cov.nug(1:10, 10), cov.nug(h, 10)@entries) expect_identical(cov.wu1(1:10, 10), cov.wu1(h, 10)@entries) expect_identical(cov.wu2(1:10, 10), cov.wu2(h, 10)@entries) expect_identical(cov.wu3(1:10, 10), cov.wu3(h, 10)@entries) expect_identical(cov.wend1(1:10, 10), cov.wend1(h, 10)@entries) expect_identical(cov.wend2(1:10, 10), cov.wend2(h, 10)@entries) expect_identical(cov.mat(1:10, 10), cov.mat(h, 10)@entries) }) spam/tests/testthat/test-solve.R0000644000176200001440000001273413536451712016462 0ustar liggesusers# HEADER #################################################### # This is file spam/tests/testthat/test-solve.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ rm(list = ls()) source("helper.R") library("testthat") library("spam", lib.loc = LIB.LOC) context("test-solve.R") # construct spd matrices (should be at least 3x3): n <- 10 set.seed(11) tt <- matrix(rnorm(n*n),n,n) tt <- t(tt) %*% tt tt[tt<0] <- 0 # I have seen that with R version 2.4.0 Patched (2006-11-25 r39997) # on i486-pc-linux-gnu, tt is not symmetric... tt <- tt-(tt-t(tt))/2 ss <- as.spam(tt) css <- chol(ss) ctt <- chol(tt[ordering(css),ordering(css)]) # solving system test_that("'solve' and derivatives", { b <- rnorm(n) spamtest_eq(solve(ss),solve(tt)) spamtest_eq(solve(ss,b),solve(tt,b)) spamtest_eq(t(as.spam(css))%*%as.spam(css), t(ctt)%*%ctt) spamtest_eq(t(as.spam(css))%*%as.spam(css), tt[ordering(css),ordering(css)]) spamtest_eq((t(as.spam(css))%*%as.spam(css))[ordering(css,inv=T),ordering(css,inv=T)], tt) spamtest_eq(backsolve(css,forwardsolve(css,b[ordering(css,inv=T)]))[ordering(css)], backsolve(ctt,forwardsolve(t(ctt),b),n)) #### ,n as patch spamtest_eq(backsolve(css,b[ordering(css,inv=T)])[ordering(css)], backsolve(ctt,b,n)) #### ,n as patch spamtest_eq(forwardsolve(css,b[ordering(css,inv=T)])[ordering(css)], forwardsolve(t(ctt),b)) spamtest_eq(forwardsolve(css,b)[ordering(css)], forwardsolve(t(ctt),b[ordering(css)])) spamtest_eq(forwardsolve(css,tt[ordering(css,inv=T),])[ordering(css),], forwardsolve(t(ctt),tt)) }) test_that("option 'chol.update'", { ss1 <- ss+diag.spam(dim(ss)[1]) spamtest_eq( chol(ss), update.spam.chol.NgPeyton(css, ss)) spamtest_eq( chol(ss, Rstruct=css), update.spam.chol.NgPeyton(css, ss)) sel <- which(ss[1,,drop=TRUE]!=0) ss1[1,sel[-1]] <- 0 ss2 <- ss ss2[n,1] <- .1 options(spam.cholsymmetrycheck=FALSE) spamtest_eq(as.spam(update.spam.chol.NgPeyton(css,ss1)), as.spam( chol(ss1))) spamtest_diff(as.spam(update.spam.chol.NgPeyton(css,ss1)), as.spam( chol(ss2))) }) # spam.options(trivalues=TRUE) # spam.options(trivalues=FALSE) options(spam.cholsymmetrycheck=TRUE) # methods for spam.chol.NgPeyton test_that("'spam.chol.NgPeyton'", { spamtest_eq(as.spam(css), ctt) spamtest_eq(as.matrix(css), as.matrix(ctt)) spamtest_eq(diag(css), diag(ctt)) spamtest_eq(length(css), length(ctt[ctt!=0])) spamtest_eq(dim(css), dim(ctt)) spamtest_eq(c(css), c(ctt)) }) test_that("option 'cholupdatesingular'\n", { ss3 <- spam(rep(1,4),2) ch3 <- chol( ss3+diag.spam(2)) options(spam.cholupdatesingular="null") spamtest_eq(is.null(update(ch3, ss3)),TRUE) options(spam.cholupdatesingular="warning") options(warn=1) expect_warning(update(ch3, ss3), "Singularity problem") options(spam.cholupdatesingular="error") expect_error(update(ch3, ss3), "Singularity problem") options(spam.cholupdatesingular="NULL") expect_error(update(ch3, ss3), "'cholupdatesingular' should be 'error', 'null' or 'warning'") }) # determinants test_that("'det' and derivatives", { spamtest_eq(det(ss),det(tt)) spamtest_eq(det(ss,log=T),det(tt,log=T)) spamtest_eq(determinant(ss)$mod,determinant(tt)$mod) spamtest_eq(determinant(ss,log=F)$mod,determinant(tt,log=F)$mod) spamtest_eq(det(chol(ss)),det(chol(tt))) spamtest_eq(2*sum(log(diag(css))), determinant(tt)$modulus) }) # orderings and derivatives test_that("'ordering' and derivatives", { tt5 <- matrix(c( 2,0,2,0,4,0,2,0,3),3) ss5 <- spam( c( 2,0,2,0,4,0,2,0,3),3) spamtest_eq(ordering(tt5),1:3) spamtest_eq(ordering(ss5),1:3) spamtest_eq(ordering(tt5,inv=T),3:1) spamtest_eq(ordering(ss5,inv=T),3:1) spamtest_eq(ordering(chol(ss5)),c(2,3,1)) spamtest_eq(ordering(chol(ss5),inv=T),c(3,1,2)) }) # spam triangular solves test_that("triangular solves", { ## We need to generate a upper triangular matrix first. ctt <- chol(tt) css <- as.spam(ctt) b <- rnorm(nrow(tt)) # a good way to test that we do not use the lower triangular part: ctt[2:10,1] <- NA # Recall: spamtest_eq(backsolve(ctt,forwardsolve(t(ctt),b),n), solve(tt,b)) # Now do testing: spamtest_eq(forwardsolve(t(css),b), forwardsolve(t(ctt),b)) spamtest_eq(forwardsolve(ss,b), forwardsolve(tt,b)) cs <- ss cs[upper.tri(cs)] <- 0 spamtest_eq(forwardsolve( cs ,b), forwardsolve( ss,b)) #### ,n as patch spamtest_eq(backsolve(css,b), backsolve(ctt,b, n)) spamtest_eq(backsolve(ss,b), backsolve(tt,b, n)) spamtest_eq(backsolve(t(cs),b), backsolve(tt,b, n)) spamtest_eq(backsolve(css,forwardsolve(t(css),b)), backsolve(ctt,forwardsolve(t(ctt),b), n)) }) spam/tests/testthat/test-kronecker.R0000644000176200001440000000434013536451711017306 0ustar liggesusers# HEADER #################################################### # This is file spam/tests/testthat/test-kronecker.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ rm(list = ls()) source("helper.R") ## library("testthat", lib.loc = LIB.LOC) ## library("spam64", lib.loc = LIB.LOC) ## library("spam", lib.loc = LIB.LOC) context("test-kronecker.R") options(spam.printsize=6) xn <- 3 xm <- 2 yn <- 4 ym <- 2 set.seed(14) X <- array(runif(xn*xm), c( xn,xm)) Y <- array(runif(yn*ym), c( yn,ym)) R <- as.spam(X) S <- as.spam(Y) b <- rnorm(5) # with matrices test_that("two matrices:", { spamtest_eq( kronecker( X, Y), kronecker.spam( X, Y) ) spamtest_eq( kronecker( X, Y), kronecker.spam( R, S) ) spamtest_eq( kronecker( X, Y), kronecker( R, S) ) spamtest_eq( kronecker( X, Y), kronecker( R, Y) ) spamtest_eq( kronecker( X, Y), kronecker( X, S) ) }) test_that("matrix vector", { spamtest_eq( kronecker( X, b), kronecker.spam( X, b) ) spamtest_eq( kronecker( b, Y), kronecker.spam( b, S) ) spamtest_eq( kronecker( X, b), kronecker( R, b) ) spamtest_eq( kronecker( b, Y), kronecker( b, S) ) }) test_that("degenerate cases", { spamtest_eq( kronecker( X, 0), kronecker.spam( X, 0),rel=FALSE ) spamtest_eq( kronecker( 0, 0), kronecker.spam( 0, 0),rel=FALSE ) spamtest_eq( kronecker( 0, Y), kronecker( spam(0), Y),rel=FALSE ) }) test_that("different operators", { spamtest_eq( kronecker(X,Y,FUN="+"),kronecker(R,S,FUN="+")) spamtest_eq( kronecker(X,b,FUN="+"),kronecker(R,b,FUN="+")) spamtest_eq( kronecker(c(0,1,0),Y,FUN="+"),kronecker(c(0,1,0),S,FUN="+")) expect_warning(tmp <- kronecker(diag.spam(2),S,FUN="+"), "Sparseness structure of ") spamtest_diff(tmp, kronecker(diag(2),Y,FUN="+")) }) spam/tests/testthat/test-dim.R0000644000176200001440000000266313536451711016102 0ustar liggesusers# HEADER #################################################### # This is file spam/tests/testthat/test-dim.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ rm(list = ls()) source("helper.R") ## library("testthat") ## library("spam64", lib.loc = LIB.LOC) ## library("spam", lib.loc = "../../../lib/") context("test-dim.R") # simple tests: ######################################################################## # construct matrices: n <- 10 m <- 15 set.seed(14) tt <- matrix(rnorm(m*n),n,m) tt[tt<0] <- 0 ss <- as.spam(tt) test_that("dim", { spamtest_eq(ss,tt) dim(ss) <- c(m,n) dim(tt) <- c(m,n) spamtest_eq(ss,tt) dim(ss) <- c(m*n,1) dim(tt) <- c(m*n,1) spamtest_eq(ss,tt) dim(ss) <- c(1, m*n) dim(tt) <- c(1, m*n) spamtest_eq(ss,tt) expect_error( dim(ss) <- c(-1, -m*n), "Indices need to be positive") expect_error( dim(ss) <- c(1, m, n), "dims should be of length 1 or 2") }) spam/tests/testthat/test-mle.R0000644000176200001440000001157013536451711016103 0ustar liggesusers# HEADER #################################################### # This is file spam/tests/testthat/test-mle.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ rm(list = ls()) source("helper.R") ## library("testthat") ## library("spam64", lib.loc = LIB.LOC) ## library("spam", lib.loc = "../../../lib/") context("test-mle.R") ################## _DO NOT CHANGE THE PARAMETERS_ ################# # Optimization uses these values for a quick run through!!! truebeta <- c(1,2,.2) truetheta <- c(.5,2,.02) spherical <- function(distmat, theta, eps = 1e-06) { Sigma <- distmat d <- Sigma@entries/theta[1] Sigma@entries <- ifelse(d < eps, theta[3]+ theta[2], ifelse(d < 1, theta[2]*(1 - 1.5*d + 0.5*d^3), 0)) return( Sigma) } sphericalmat <- function(distmat, theta, eps = 1e-06) { Sigma <- distmat d <- Sigma@entries/theta[1] Sigma@entries <- ifelse(d < eps, theta[3]+ theta[2], ifelse(d < 1, theta[2]*(1 - 1.5*d + 0.5*d^3), 0)) return( as.matrix(Sigma)) } xl <- 10 x <- seq(0,1,l=xl) locs <- expand.grid(x,x) X <- as.matrix(cbind(1,locs)) # design matrix cov.sph.mat <- function(...) as.matrix(cov.sph(...)) # covariance function distmat <- nearest.dist(locs,upper=NULL) # distance matrix Sigma <- cov.sph(distmat,truetheta) # true covariance matrix set.seed(15) y <- c(rmvnorm.spam(1,X%*%truebeta,Sigma)) # construct samples test_that("mle", { spamtest_eq(round(neg2loglikelihood.spam( y, X, distmat, cov.sph, truebeta, truetheta),2), 262.98) spamtest_eq(round(neg2loglikelihood( y, X, distmat, cov.sph, truebeta, truetheta),2), 262.98) spamtest_eq(round(neg2loglikelihood( y, X, distmat, cov.sph.mat, truebeta, truetheta),2), 262.98) # spamtest_eq(round(neg2loglikelihood.spam( y, X, distmat, cov.sph.mat, # truebeta, truetheta),2), 262.98) # expect_warning(round(neg2loglikelihood.spam( y, X, distmat, cov.sph.mat, # truebeta, truetheta),2)) }) # we pass now to the mle: test_that("mle2", { # not that we should set: # ,thetalower=c(0,0,0),thetaupper=c(1,Inf,Inf) # for quicker testing we use res1 <- mle.spam(y, X, distmat, cov.sph, truebeta, truetheta,thetalower=c(0.4,1.5,0.02),thetaupper=c(.6,2.5,.1)) # truebeta, truetheta,thetalower=c(0,0,0),thetaupper=c(1,Inf,Inf)) betahat <- res1$par[1:3] spamtest_eq(round(res1$par,2), c(2.35, 1.45, -0.58, 0.50, 1.70, 0.08)) spamtest_eq(round(res1$val,2), 259.03) if (F){ # takes too long... res2 <- mle(y, X, distmat, cov.sph, truebeta, truetheta,thetalower=c(0.4,1.5,0.02),thetaupper=c(.6,2.5,.1)) # truebeta, truetheta,thetalower=c(0,0,0),thetaupper=c(1,Inf,Inf)) res3 <- mle(y, X, distmat, cov.sph.mat, truebeta, truetheta,thetalower=c(0.4,1.5,0.02),thetaupper=c(.6,2.5,.1)) # truebeta, truetheta,thetalower=c(0,0,0),thetaupper=c(1,Inf,Inf)) spamtest_eq(round(res2$par,2), c(2.35, 1.45, -0.58, 0.50, 1.70, 0.08)) spamtest_eq(round(res2$val,2), 259.03) spamtest_eq(round(res3$par,2), c(2.35, 1.45, -0.58, 0.50, 1.70, 0.08)) spamtest_eq(round(res3$val,2), 259.03) } res1 <- mle.nomean.spam(y-X%*%betahat, distmat, cov.sph, # truetheta,thetalower=c(0,0,0),thetaupper=c(1,Inf,Inf)) truetheta,thetalower=c(0.4,1,0.02),thetaupper=c(.6,2.5,.1)) res2 <- mle.nomean(y-X%*%betahat, distmat, cov.sph, truetheta,thetalower=c(0,0,0),thetaupper=c(1,Inf,Inf)) res3 <- mle.nomean(y-X%*%betahat, distmat, cov.sph.mat, truetheta,thetalower=c(0,0,0),thetaupper=c(1,Inf,Inf)) spamtest_eq(round(res1$par,2), c( 0.50, 1.70, 0.08)) spamtest_eq(round(res1$val,2), 259.03) spamtest_eq(round(res2$par,2), c( 0.50, 1.70, 0.08)) spamtest_eq(round(res2$val,2), 259.03) spamtest_eq(round(res3$par,2), c( 0.50, 1.70, 0.08)) spamtest_eq(round(res3$val,2), 259.03) }) spam/tests/testthat/test-subset.R0000644000176200001440000000623713536451712016640 0ustar liggesusers# HEADER #################################################### # This is file spam/tests/testthat/test-subset.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ rm(list = ls()) source("helper.R") ## library("testthat") ## library("spam", lib.loc = LIB.LOC) context("test-subset.R") # subsetting: ######################################################################## # construct matrices (should be at least 3x5, with n https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ rm(list = ls()) source("helper.R") context("test-random.R") test_that("check arguments", { rspam1 <- spam::spam_random(7, digits = 2, distribution = runif, min = -1, sym = TRUE) expect_identical(spam::isSymmetric.spam(rspam1), TRUE) rspam2 <- spam::spam_random(7, digits = 2, distribution = NULL, sym = FALSE, spd = TRUE) cholrspam2 <- chol(rspam2) expect_identical(spam::isSymmetric.spam(rspam2), TRUE) expect_equivalent(class(cholrspam2), "spam.chol.NgPeyton") }) spam/tests/demo_cholesky.Rout.save0000644000176200001440000000332113574427304017021 0ustar liggesusers R version 3.5.0 (2018-04-23) -- "Joy in Playing" Copyright (C) 2018 The R Foundation for Statistical Computing Platform: x86_64-pc-linux-gnu (64-bit) R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. R is a collaborative project with many contributors. Type 'contributors()' for more information and 'citation()' on how to cite R or R packages in publications. Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. > # HEADER #################################################### > # This is file spam/tests/demo_cholesky.R. # > # It is part of the R package spam, # > # --> https://CRAN.R-project.org/package=spam # > # --> https://CRAN.R-project.org/package=spam64 # > # --> https://git.math.uzh.ch/reinhard.furrer/spam # > # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # > # Roman Flury [aut], Daniel Gerber [ctb], # > # Kaspar Moesinger [ctb] # > # HEADER END ################################################ > > > # We illustrate the Cholesky decompostion approaches > options( echo=FALSE) Loading required package: dotCall64 Loading required package: grid Spam version 2.5-1 (2019-12-12) is loaded. Type 'help( Spam)' or 'demo( spam)' for a short introduction and overview of this package. Help for individual functions is also obtained by adding the suffix '.spam' to the function name, e.g. 'help( chol.spam)'. > > proc.time() user system elapsed 1.008 0.112 1.114 spam/tests/jss_areal_counts.Rout.save0000644000176200001440000001341113574427304017533 0ustar liggesusers R version 3.5.0 (2018-04-23) -- "Joy in Playing" Copyright (C) 2018 The R Foundation for Statistical Computing Platform: x86_64-pc-linux-gnu (64-bit) R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. R is a collaborative project with many contributors. Type 'contributors()' for more information and 'citation()' on how to cite R or R packages in publications. Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. > # HEADER #################################################### > # This is file spam/tests/jss_areal_counts.R. # > # It is part of the R package spam, # > # --> https://CRAN.R-project.org/package=spam # > # --> https://CRAN.R-project.org/package=spam64 # > # --> https://git.math.uzh.ch/reinhard.furrer/spam # > # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # > # Roman Flury [aut], Daniel Gerber [ctb], # > # Kaspar Moesinger [ctb] # > # HEADER END ################################################ > > > # JSS article: > # "Pitfalls in the implementation of Bayesian > # hierarchical modeling of areal count data. > # An illustration using BYM and Leroux models." > # > # test the MCMC sampler from the paper with 30 iterations. > > > # SETUP: > library("spam") Loading required package: dotCall64 Loading required package: grid Spam version 2.5-1 (2019-12-12) is loaded. Type 'help( Spam)' or 'demo( spam)' for a short introduction and overview of this package. Help for individual functions is also obtained by adding the suffix '.spam' to the function name, e.g. 'help( chol.spam)'. Attaching package: 'spam' The following objects are masked from 'package:base': backsolve, forwardsolve > options(spam.structurebased=TRUE) > > # BYM --------------------------------------------- > data(Oral); attach(Oral) > path <- system.file("demodata/germany.adjacency", package = "spam") > A <- adjacency.landkreis(path); n <- dim(A)[1] > > set.seed(2) > hyperA <- c(1, 1); hyperB <- c(0.5, .01) > totalg <- 30 > > upost <- vpost <- array(0, c(totalg, n)) > kpost <- array(NA, c(totalg, 2)); accept <- rep(NA, totalg) > upost[1,] <- vpost[1,] <- rep(.001, 544); kpost[1,] <- c(10, 100) > > eta <- upost[1,] + vpost[1,] > C <- exp(eta) * E; diagC <- diag.spam(c(rep(0, n), C)) > b <- c( rep(0, n), Y + (eta - 1) * C) > Qu <- R <- precmat.IGMRFirreglat(A); pad(Qu) <- c(2 * n, 2 * n) > Qv <- as.spam(rbind(cbind( diag(n), -diag(n)), + cbind(-diag(n), diag(n)))) > Q <- kpost[1,1] * Qu + kpost[1,2] * Qv + diagC > struct <- chol(Q, memory = list(nnzcolindices = 6467)) > uRuHalf <- t(upost[1,]) %*% (R %*% upost[1,]) / 2 > vvHalf <- t(vpost[1,]) %*% vpost[1,] / 2 > postshape <- hyperA + c(n - 1, n) / 2 > > for (i in 2:totalg) { + kpost[i,] <- rgamma(2, postshape, hyperB + c(uRuHalf, vvHalf)) + + etaTilde <- eta + for(index in 1:2){ + C <- E * exp(etaTilde) + diagC <- diag.spam(c(rep(0, n), C)) + b <- c(rep(0, 544), Y + (etaTilde - 1) * C) + Q <- kpost[i,1] * Qu + kpost[i,2] * Qv + diagC + etaTilde <- c(solve.spam(Q, b, + Rstruct = struct))[1:n + n] + } + + C <- exp(etaTilde) * E; diagC <- diag.spam(c(rep(0, n), C)) + b <- c( rep(0, n), Y + (etaTilde - 1) * C) + Q <- kpost[i,1] * Qu + kpost[i,2] * Qv + diagC + + x_ <- c(rmvnorm.canonical(1, b, Q, Rstruct = struct)) + upost[i,] <- x_[1:n]; eta_ <- x_[1:n + n]; vpost[i,] <- eta_ - upost[i,] + uRuHalf_ <- t(upost[i,]) %*% (R %*% upost[i,]) / 2 + vvHalf_ <- t(vpost[i,]) %*% vpost[i,] / 2 + + etaTilde_ <- eta_ + for(index in 1:2){ + C_ <- E * exp(etaTilde_) + diagC_ <- diag.spam(c(rep(0, n), C_)) + b_ <- c(rep(0, 544), Y + (etaTilde_ - 1) * C_) + Q_<- kpost[i,1] * Qu + kpost[i,2] * Qv + diagC_ + etaTilde_ <- c(solve.spam(Q_, b_, + Rstruct = struct))[1:n + n] + } + + C_ <- exp(etaTilde_) * E; diagC_ <- diag.spam(c(rep(0, n), C_)) + b_ <- c( rep(0, n), Y + (etaTilde_ - 1) * C_) + Q_ <- kpost[i,1] * Qu + kpost[i,2] * Qv + diagC_ + + logPost_ <- sum(Y * eta_ - E * exp(eta_)) - + kpost[i,1] * uRuHalf_ - kpost[i, 2] * vvHalf_ + logPost <- sum(Y * eta - E * exp(eta)) - kpost[i,1] * uRuHalf - + kpost[i,2] * vvHalf + logApproxX_ <- - kpost[i,1] * uRuHalf_ - kpost[i,2] * vvHalf_ - + sum(.5 * eta_^2 * C) + sum(b * eta_) + logApproxX <- - kpost[i,1] * uRuHalf - kpost[i,2] * vvHalf - + sum(.5 * eta^2 * C_) + sum(b_ * eta) + logAlpha <- min(0, logPost_ - logPost + logApproxX - logApproxX_) + + if (log(runif(1)) < logAlpha) { + uRuHalf <- uRuHalf_; vvHalf <- vvHalf_ + eta <- eta_; b <- b_; C <- C_; accept[i] <- 1 + } else{ + accept[i] <- 0; upost[i,] <- upost[i-1,]; vpost[i,] <- vpost[i-1,]} + } > > # values of 30th iteration > head(eta) [1] -0.45371922 0.17297575 0.02605778 -0.44984751 -0.36053283 0.01309363 > tail(b) [1] -1.341895 -3.756725 -2.514229 -4.411210 -6.486653 -5.101487 > head(C) [1] 15.05715 53.22751 41.15492 13.16245 19.87138 30.27948 > tail(accept) [1] 0 1 1 1 1 0 > tail(upost[30,]) [1] 0.255439209 -0.299099415 -0.004660022 -0.392147580 -0.318792450 [6] -0.344095560 > tail(vpost[30,]) [1] -0.0152950744 0.0008418105 0.0400659014 -0.0160847172 0.0064331753 [6] -0.0154282422 > sum(accept[-1]) [1] 21 > sum(upost) [1] -780.3814 > > > proc.time() user system elapsed 1.528 0.200 1.725 spam/tests/demo_article-jss-example2.Rout.save0000644000176200001440000002020013574427304021126 0ustar liggesusers R version 3.5.0 (2018-04-23) -- "Joy in Playing" Copyright (C) 2018 The R Foundation for Statistical Computing Platform: x86_64-pc-linux-gnu (64-bit) R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. R is a collaborative project with many contributors. Type 'contributors()' for more information and 'citation()' on how to cite R or R packages in publications. Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. > # HEADER #################################################### > # This is file spam/tests/demo_article-jss-example2.R. # > # It is part of the R package spam, # > # --> https://CRAN.R-project.org/package=spam # > # --> https://CRAN.R-project.org/package=spam64 # > # --> https://git.math.uzh.ch/reinhard.furrer/spam # > # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # > # Roman Flury [aut], Daniel Gerber [ctb], # > # Kaspar Moesinger [ctb] # > # HEADER END ################################################ > > > > # INITALIZE AND FUNCTIONS: > # JSS article: > # "spam: A Sparse Matrix R Package with Emphasis on > # MCMC Methods for Gaussian Markov Random Fields" > > > # Compared to the R code in the article, here we give: > # - improved formatting > # - more comments, e.g. how to run the code using regular matrices > # - the code to construct the figures > # - minor modifcations due to evolvement of spam > > > cat("\nThis demo contains the R code of the second example\nin the JSS article. As pointed out by Steve Geinitz\nand Andrea Riebler, the Gibbs sampler is not correct\nand contains several bugs. \n\nI'll post an updated sampler in a future release.\n\n") This demo contains the R code of the second example in the JSS article. As pointed out by Steve Geinitz and Andrea Riebler, the Gibbs sampler is not correct and contains several bugs. I'll post an updated sampler in a future release. > > > # INITALIZE AND FUNCTIONS: > require("fields", warn.conflict=FALSE) Loading required package: fields Loading required package: spam Loading required package: dotCall64 Loading required package: grid Spam version 2.5-1 (2019-12-12) is loaded. Type 'help( Spam)' or 'demo( spam)' for a short introduction and overview of this package. Help for individual functions is also obtained by adding the suffix '.spam' to the function name, e.g. 'help( chol.spam)'. Attaching package: 'spam' The following objects are masked from 'package:base': backsolve, forwardsolve Loading required package: maps See https://github.com/NCAR/Fields for an extensive vignette, other supplements and source code > options(spam.structurebased=TRUE) > > > # READ DATA: > attach(Oral) > > > > # CONSTRUCT ADJACENCY MATRIX: > loc <- system.file("demodata/germany.adjacency", package="spam") > A <- adjacency.landkreis(loc) > n <- dim(A)[1] > # Verification that we have a symmetric matrix: > # norm(A-t(A)); display(A) > > > # GIBBS SETUP: > set.seed(14) > > # Construct the individual block precisions > # (based on unit precision parameters kappa, denoted with k): > > Q1 <- R <- diag.spam( diff(A@rowpointers)) - A # this is R in (2) > pad(Q1) <- c(2*n,2*n) # previously: dim(Q1) <- c(2*n,2*n) > > Q2 <- rbind(cbind( diag.spam(n), -diag.spam(n)), + cbind(-diag.spam(n), diag.spam(n))) > > # Hence the precision Q in (2) is: > # Q <- kappau*Q1 + kappav*Q2 > > # pre-define > diagC <- as.spam( diag.spam(c(rep(0,n),rep(1,n)))) > > > # Recall: > # k=( kappa_u, kappa_y)' > > # hyperparameters > ahyper <- c( 1, 1) > bhyper <- c( .5, .01) > > > # Gibbs sampler > burnin <- 50 > ngibbs <- 150 > totalg <- burnin+ngibbs > > # Initialize parameters: > upost <- array(0, c(totalg, n)) > npost <- array(0, c(totalg, n)) > kpost <- array(0, c(totalg, 2)) > > # Starting values: > kpost[1,] <- c(40,500) > upost[1,] <- u <- rnorm(n,sd=.2) *1 > npost[1,] <- eta <- u + rnorm(n,sd=.05)*1 > > uRu <- t(u) %*% (R %*% u)/2 > etauetau <- t(eta-u) %*% (eta-u)/2 > > postshape <- ahyper + c(n-1,n)/2 > > accept <- numeric(totalg) > > struct <- chol(Q1 + Q2 + diag.spam(2*n), + memory=list(nnzcolindices=5500)) > > # struct <- NULL # If no update steps are wanted > > # R <- as.matrix(R) # If no spam analysis is wanted. > # Q1 <- as.matrix(Q1) > # Q2 <- as.matrix(Q2) > > > for (ig in 2:totalg) { + + + kstar <- rgamma(2,postshape, bhyper + c(uRu, etauetau)) + + + expeta0E <- exp(eta)*E + expeta0Eeta01 <- expeta0E *(eta-1) + diagC@entries <- expeta0E + Q <- kstar[1]*Q1 + kstar[2]*Q2 + diagC + b <- c( rep(0,n), Y + expeta0Eeta01) + + xstar <- rmvnorm.canonical(1, + # vector b: + b, + # Precision matrix + Q, + Rstruct=struct) + + + ustar <- xstar[1:n] + nstar <- xstar[1:n+n] + + uRustar <- t(ustar) %*% (R %*% ustar)/2 + etauetaustar <- t(nstar-ustar) %*% (nstar-ustar)/2 + + + # we work on the log scale: + # logalpha <- min(0, log(ratios))=min(0, expterm+(...)log(kappa)- + + exptmp <- sum(expeta0Eeta01*(eta-nstar) - E*(exp(eta)-exp(nstar))) - + sum( nstar^2*expeta0E)/2 + sum(eta^2*expeta0E)/2 - + kstar[1] * uRu + kpost[ig-1,1] * uRustar - + kstar[2] * etauetau + kpost[ig-1,2] * etauetaustar + factmp <- (postshape-1)*(log(kstar)-log(kpost[ig-1,1])) + + logalpha <- min(0, exptmp + sum(factmp)) + logU <- log(runif(1)) + + if (logU < logalpha) { # ACCEPT draw + upost[ig,] <- u <- ustar + npost[ig,] <- eta <- nstar + kpost[ig,] <- kstar + uRu <- uRustar + etauetau <- etauetaustar + accept[ig] <- 1 + } else { + upost[ig,] <- upost[ig-1,] + npost[ig,] <- npost[ig-1,] + kpost[ig,] <- kpost[ig-1,] + } + + if( (ig%%10)==0) cat('.') + + } ....................> > > if (FALSE) { + + # POSTPROCESSING: + + accept <- accept[-c(1:burnin)] + cat("\nAcceptance rate:",mean(accept),"\n") + + kpost <- kpost[-c(1:burnin),] + upost <- upost[-c(1:burnin),] + npost <- npost[-c(1:burnin),] + + kpostmean <- apply(kpost,2,mean) + upostmean <- apply(upost,2,mean) + npostmean <- apply(npost,2,mean) + + kpostmedian <- apply(kpost,2,median) + upostmedian <- apply(upost,2,median) + npostmedian <- apply(npost,2,median) + + vpost <- npost-upost + vpostmedian <- apply(vpost,2,median) + + + # + + + + + + ###################################################################### + # Figures + par(mfcol=c(1,3),mai=rep(0,4)) + map.landkreis(log(Y)) + map.landkreis(Y/E,zlim=c(.1,2.4)) + map.landkreis(exp(upostmedian),zlim=c(.1,2.4)) + + + par(mfcol=c(2,4),mai=c(.5,.5,.05,.1),mgp=c(2.3,.8,0)) + hist(kpost[,1],main="",xlab=expression(kappa[u]),prob=TRUE) + lines(density(kpost[,1]),col=2) + tmp <- seq(0,to=max(kpost[,1]),l=500) + lines(tmp,dgamma(tmp,ahyper[1],bhyper[1]),col=4) + abline(v=kpostmedian[1],col=3) + + hist(kpost[,2],main="",xlab=expression(kappa[y]),prob=TRUE) + lines(density(kpost[,2]),col=2) + tmp <- seq(0,to=max(kpost[,2]),l=500) + lines(tmp,dgamma(tmp,ahyper[2],bhyper[2]),col=4) + abline(v=kpostmedian[2],col=3) + + # Trace plots: + plot(kpost[,1],ylab=expression(kappa[u]),type="l") + abline(h=kpostmedian[1],col=3) + plot(kpost[,2],ylab=expression(kappa[y]),type="l") + abline(h=kpostmedian[2],col=3) + + # ACF: + acf(kpost[,1],ylab=expression(kappa[u])) + acf(kpost[,2],ylab=expression(kappa[y])) + + + + # scatter plots + plot(kpost[,1],kpost[,2],xlab=expression(kappa[u]),ylab=expression(kappa[y])) + abline(v=kpostmedian[1],h=kpostmedian[2],col=3) + + + plot(accept+rnorm(ngibbs,sd=.05),pch=".",ylim=c(-1,2),yaxt="n",ylab="") + text(ngibbs/2,1/2,paste("Acceptance rate:",round(mean(accept),3))) + axis(2,at=c(0,1),label=c("Reject","Accept")) + + } > > detach(Oral) > ###################################################################### > > > proc.time() user system elapsed 1.564 0.212 1.777 spam/tests/demo_article-jss-example1.R0000644000176200001440000001323313536451710017444 0ustar liggesusers# HEADER #################################################### # This is file spam/tests/demo_article-jss-example1.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ # JSS article: # "spam: A Sparse Matrix R Package with Emphasis on # MCMC Methods for Gaussian Markov Random Fields" # # Compared to the R code given in the article, here we give: # - improved formatting # - more comments # - the R code to construct the figures # SETUP: library("spam") options(spam.structurebased=TRUE) data("UKDriverDeaths") y <- sqrt(c(UKDriverDeaths)) # square root counts n <- length(y) # n=192 m <- 12 # We want to predict for one season. nm <- n+m # Total length of s and t priorshape <- c(4, 1, 1) # alpha's, as in Rue & Held (2005) priorinvscale <- c(4, 0.1, 0.0005) # beta's # Construct the individual block precisions # (based on unit precision parameters kappa, denoted with k): # Qsy, Qty are trivial: Qsy <- diag.spam(n) pad(Qsy) <- c(n+m, n) # previously: dim(Qsy) <- c(n+m, n) Qty <- Qsy Qst <- spam(0, nm, nm) Qst[cbind(1:n, 1:n)] <- rep(1, n) # The form of Qss is given by (Rue and Held equation 3.59). # Qss can be constructed with a loop: Qss <- spam(0, nm, nm) for (i in 0:(nm-m)) { Qss[i+1:m,i+1:m] <- Qss[i+1:m, i+1:m] + matrix(1,m,m) # Qss[i+1:m,i+1:m] <- Qss[i+1:m, i+1:m]+1 # previously... } # Note that for the final version we need: # Qss <- k_s * Qss + k_y * diag.spam(nm) # The form of Qtt is given by (Rue and Held equation 3.40). # Similar approaches to construct Qtt: Qtt <- spam(0,nm,nm) Qtt[cbind(1:(nm-1),2:nm)] <- -c(2,rep(4,nm-3),2) Qtt[cbind(1:(nm-2),3:nm)] <- rep(1,nm-2) Qtt <- Qtt + t( Qtt) diag(Qtt) <- c(1,5,rep(6,nm-4),5,1) # Create temporary kappa and precision matrix to illustrate # adjacency matrix and ordering. k <- c(1,1,1) Qst_yk <- rbind(cbind(k[2]*Qss + k[1]*diag.spam(nm), k[1]*Qst), cbind(k[1]*Qst, k[3]*Qtt + k[1]*diag.spam(nm))) struct <- chol(Qst_yk) # Note that we do not provide the exactly the same ordering # algorithms. Hence, the following is sightly different than # Figure RH4.2. cholQst_yk <- chol(Qst_yk,pivot="RCM") P <- ordering(cholQst_yk) display(Qst_yk) display(Qst_yk[P,P]) # Recall: # k=( kappa_y, kappa_s, kappa_t)' # Gibbs sampler ngibbs <- 100 # In the original version is 500! burnin <- 10 # > 0 totalg <- ngibbs+burnin set.seed(14) # Initialize parameters: spost <- tpost <- array(0, c(totalg, nm)) kpost <- array(0, c(totalg, 3)) # Starting values: kpost[1,] <- c(.5,28,500) tpost[1,] <- 40 # calculation of a few variables: postshape <- priorshape + c( n/2, (n+1)/2, (n+m-2)/2) for (ig in 2:totalg) { Q <- rbind(cbind(kpost[ig-1,2]*Qss + kpost[ig-1,1]*Qst, kpost[ig-1,1]*Qst), cbind(kpost[ig-1,1]*Qst, kpost[ig-1,3]*Qtt + kpost[ig-1,1]*Qst)) b <- c(kpost[ig-1,1]*Qsy %*% y, kpost[ig-1,1]*Qsy %*% y) tmp <- rmvnorm.canonical(1, b, Q, Lstruct=struct) spost[ig,] <- tmp[1:nm] tpost[ig,] <- tmp[1:nm+nm] tmp <- y-spost[ig,1:n]-tpost[ig,1:n] postinvscale <- priorinvscale + # prior contribution c( sum( tmp^2)/2, # Qyy_st is the identity t(spost[ig,]) %*% (Qss %*% spost[ig,])/2, t(tpost[ig,]) %*% (Qtt %*% tpost[ig,])/2) kpost[ig,] <- rgamma(3, postshape, postinvscale) if( (ig%%10)==0) cat('.') } # Eliminate burn-in: kpost <- kpost[-c(1:burnin),] spost <- spost[-c(1:burnin),] tpost <- tpost[-c(1:burnin),] postquant <- apply(spost+tpost, 2, quantile,c(.025,.975)) postmean <- apply(spost+tpost, 2, mean) postmedi <- apply(spost+tpost, 2, median) if (F){ par(mfcol=c(1,1),mai=c(.6,.8,.01,.01)) plot( y^2, ylim=c(800,2900),xlim=c(0,nm),ylab="Counts") #lines( postmean^2, col=2) lines( postmedi^2, col=2) matlines( t(postquant)^2, col=4,lty=1) legend("topright",legend=c("Posterior median", "Quantiles of posterior sample", "Quantiles of predictive distribution"), bty="n",col=c(2,4,3),lty=1) # Constructing a predictive distribution: ypred <- rnorm( ngibbs*nm, c(spost+tpost),sd=rep( 1/sqrt(kpost[,1]), nm)) dim(ypred) <- c(ngibbs,nm) postpredquant <- apply(ypred, 2, quantile,c(.025,.975)) matlines( t(postpredquant)^2, col=3,lty=1) points(y^2) dev.off() kpostmedian <- apply(kpost,2,median) par(mfcol=c(1,3),mai=c(.65,.65,.01,.01),cex=.85,mgp=c(2.6,1,0)) matplot( log( kpost), lty=1, type="l",xlab="Index") abline(h=log(kpostmedian),col=3) acf( kpost[,3],ylab=expression(kappa[t])) plot(kpost[,2:3],ylab=expression(kappa[t]),xlab=expression(kappa[s]),cex=.8) abline(h=kpostmedian[3],v=kpostmedian[2],col=3) dev.off() allkappas <- rbind(apply(kpost,2,mean), apply(kpost,2,median), apply(1/kpost,2,mean), apply(1/kpost,2,median)) colnames(allkappas) <- c("kappa_y", "kappa_s", "kappa_t") rownames(allkappas) <- c("Prec (mean)", "Prec (median)", "Var (mean)", "Var (median) ") print(allkappas,4) png("example1_m1.png",width=300,height=300) par(mai=c(.5,.5,.05,.05)) display(Qst_yk) dev.off() png("example1_m2.png",width=300,height=300) par(mai=c(.5,.5,.05,.05)) display(struct) dev.off() summary(kpost) } spam/tests/demo_cholesky.R0000644000176200001440000001127113536451710015333 0ustar liggesusers# HEADER #################################################### # This is file spam/tests/demo_cholesky.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ # We illustrate the Cholesky decompostion approaches options( echo=FALSE) library( spam, warn.conflict=FALSE) set.seed(14) # first start with a full matrix. xn <- 50 fmat1 <- matrix(rnorm(xn*xn),xn,xn) fmat1 <- t( fmat1) %*% fmat1 smat1 <- as.spam(fmat1) smat2 <- smat1 + diag.spam(xn) # Generic Cholesky # tmp <- gc(F);Rprof(memory.profiling=TRUE, interval = 0.01) ch1 <- chol( fmat1) # Rprof(NULL);print( summaryRprof(memory="both")$by.total) # Sparse Cholesky # tmp <- gc(F);Rprof(memory.profiling=TRUE, interval = 0.01) ch1 <- chol( smat1) # Rprof(NULL);print( summaryRprof(memory="both")$by.total) # Sparse Cholesky, direct call # tmp <- gc(F);Rprof(memory.profiling=TRUE, interval = 0.01) ch1 <- chol.spam( smat1) # Rprof(NULL);print( summaryRprof(memory="both")$by.total) # Sparse Cholesky, without symmetry check options(spam.cholsymmetrycheck=FALSE) # tmp <- gc(F);Rprof(memory.profiling=TRUE, interval = 0.01) ch1 <- chol.spam( smat1) # Rprof(NULL);print( summaryRprof(memory="both")$by.total) # Sparse Cholesky, reusing pivoting # tmp <- gc(F);Rprof(memory.profiling=TRUE, interval = 0.01) ch1 <- chol.spam( smat1,pivot=ch1@pivot) # Rprof(NULL);print( summaryRprof(memory="both")$by.total) # Sparse Cholesky, updating # tmp <- gc(F);Rprof(memory.profiling=TRUE, interval = 0.01) ch1 <- update.spam.chol.NgPeyton( ch1, smat2) # Rprof(NULL);print( summaryRprof(memory="both")$by.total) # reset to default options(spam.cholsymmetrycheck=TRUE) # now create a sparse matrix. fmat1[fmat1<3] <- 0 smat1 <- as.spam(fmat1) smat2 <- smat1 + diag.spam(xn) # Generic Cholesky # tmp <- gc(F);Rprof(memory.profiling=TRUE, interval = 0.01) ch1 <- chol( fmat1) # Rprof(NULL);print( summaryRprof(memory="both")$by.total) # Sparse Cholesky # tmp <- gc(F);Rprof(memory.profiling=TRUE, interval = 0.01) ch1 <- chol( smat1) # Rprof(NULL);print( summaryRprof(memory="both")$by.total) # Sparse Cholesky, direct call # tmp <- gc(F);Rprof(memory.profiling=TRUE, interval = 0.01) ch1 <- chol.spam( smat1) # Rprof(NULL);print( summaryRprof(memory="both")$by.total) # Sparse Cholesky, without symmetry check options(spam.cholsymmetrycheck=FALSE) # tmp <- gc(F);Rprof(memory.profiling=TRUE, interval = 0.01) ch1 <- chol.spam( smat1) # Rprof(NULL);print( summaryRprof(memory="both")$by.total) # Sparse Cholesky, reusing pivoting # tmp <- gc(F);Rprof(memory.profiling=TRUE, interval = 0.01) ch1 <- chol.spam( smat1,pivot=ch1@pivot) # Rprof(NULL);print( summaryRprof(memory="both")$by.total) # Sparse Cholesky, updating # tmp <- gc(F);Rprof(memory.profiling=TRUE, interval = 0.01) ch1 <- update.spam.chol.NgPeyton( ch1, smat2) # Rprof(NULL);print( summaryRprof(memory="both")$by.total) # reset to default options(spam.cholsymmetrycheck=TRUE) # now create an even sparser matrix. fmat1 <- fmat1+20*diag(xn) fmat1[fmat1<32] <- 0 smat1 <- as.spam(fmat1) smat2 <- smat1 + 1* diag.spam(xn) # Generic Cholesky # tmp <- gc(F);Rprof(memory.profiling=TRUE, interval = 0.01) ch1 <- chol( fmat1) # Rprof(NULL);print( summaryRprof(memory="both")$by.total) # Sparse Cholesky # tmp <- gc(F);Rprof(memory.profiling=TRUE, interval = 0.01) ch1 <- chol( smat1) # Rprof(NULL);print( summaryRprof(memory="both")$by.total) # Sparse Cholesky, direct call # tmp <- gc(F);Rprof(memory.profiling=TRUE, interval = 0.01) ch1 <- chol.spam( smat1) # Rprof(NULL);print( summaryRprof(memory="both")$by.total) # Sparse Cholesky, without symmetry check options(spam.cholsymmetrycheck=FALSE) # tmp <- gc(F);Rprof(memory.profiling=TRUE, interval = 0.01) ch1 <- chol.spam( smat1) # Rprof(NULL);print( summaryRprof(memory="both")$by.total) # Sparse Cholesky, reusing pivoting options(spam.cholsymmetrycheck=FALSE) # tmp <- gc(F);Rprof(memory.profiling=TRUE, interval = 0.01) ch1 <- chol.spam( smat1,pivot=ch1@pivot) # Rprof(NULL);print( summaryRprof(memory="both")$by.total) # Sparse Cholesky, updating options(spam.cholsymmetrycheck=FALSE) # tmp <- gc(F);Rprof(memory.profiling=TRUE, interval = 0.01) ch1 <- update.spam.chol.NgPeyton( ch1, smat2) # Rprof(NULL);print( summaryRprof(memory="both")$by.total) # reset to default options(spam.cholsymmetrycheck=TRUE) options( echo=TRUE) spam/tests/demo_article-jss-example2.R0000644000176200001440000001416213536451710017447 0ustar liggesusers# HEADER #################################################### # This is file spam/tests/demo_article-jss-example2.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ # INITALIZE AND FUNCTIONS: # JSS article: # "spam: A Sparse Matrix R Package with Emphasis on # MCMC Methods for Gaussian Markov Random Fields" # Compared to the R code in the article, here we give: # - improved formatting # - more comments, e.g. how to run the code using regular matrices # - the code to construct the figures # - minor modifcations due to evolvement of spam cat("\nThis demo contains the R code of the second example\nin the JSS article. As pointed out by Steve Geinitz\nand Andrea Riebler, the Gibbs sampler is not correct\nand contains several bugs. \n\nI'll post an updated sampler in a future release.\n\n") # INITALIZE AND FUNCTIONS: require("fields", warn.conflict=FALSE) options(spam.structurebased=TRUE) # READ DATA: attach(Oral) # CONSTRUCT ADJACENCY MATRIX: loc <- system.file("demodata/germany.adjacency", package="spam") A <- adjacency.landkreis(loc) n <- dim(A)[1] # Verification that we have a symmetric matrix: # norm(A-t(A)); display(A) # GIBBS SETUP: set.seed(14) # Construct the individual block precisions # (based on unit precision parameters kappa, denoted with k): Q1 <- R <- diag.spam( diff(A@rowpointers)) - A # this is R in (2) pad(Q1) <- c(2*n,2*n) # previously: dim(Q1) <- c(2*n,2*n) Q2 <- rbind(cbind( diag.spam(n), -diag.spam(n)), cbind(-diag.spam(n), diag.spam(n))) # Hence the precision Q in (2) is: # Q <- kappau*Q1 + kappav*Q2 # pre-define diagC <- as.spam( diag.spam(c(rep(0,n),rep(1,n)))) # Recall: # k=( kappa_u, kappa_y)' # hyperparameters ahyper <- c( 1, 1) bhyper <- c( .5, .01) # Gibbs sampler burnin <- 50 ngibbs <- 150 totalg <- burnin+ngibbs # Initialize parameters: upost <- array(0, c(totalg, n)) npost <- array(0, c(totalg, n)) kpost <- array(0, c(totalg, 2)) # Starting values: kpost[1,] <- c(40,500) upost[1,] <- u <- rnorm(n,sd=.2) *1 npost[1,] <- eta <- u + rnorm(n,sd=.05)*1 uRu <- t(u) %*% (R %*% u)/2 etauetau <- t(eta-u) %*% (eta-u)/2 postshape <- ahyper + c(n-1,n)/2 accept <- numeric(totalg) struct <- chol(Q1 + Q2 + diag.spam(2*n), memory=list(nnzcolindices=5500)) # struct <- NULL # If no update steps are wanted # R <- as.matrix(R) # If no spam analysis is wanted. # Q1 <- as.matrix(Q1) # Q2 <- as.matrix(Q2) for (ig in 2:totalg) { kstar <- rgamma(2,postshape, bhyper + c(uRu, etauetau)) expeta0E <- exp(eta)*E expeta0Eeta01 <- expeta0E *(eta-1) diagC@entries <- expeta0E Q <- kstar[1]*Q1 + kstar[2]*Q2 + diagC b <- c( rep(0,n), Y + expeta0Eeta01) xstar <- rmvnorm.canonical(1, # vector b: b, # Precision matrix Q, Rstruct=struct) ustar <- xstar[1:n] nstar <- xstar[1:n+n] uRustar <- t(ustar) %*% (R %*% ustar)/2 etauetaustar <- t(nstar-ustar) %*% (nstar-ustar)/2 # we work on the log scale: # logalpha <- min(0, log(ratios))=min(0, expterm+(...)log(kappa)- exptmp <- sum(expeta0Eeta01*(eta-nstar) - E*(exp(eta)-exp(nstar))) - sum( nstar^2*expeta0E)/2 + sum(eta^2*expeta0E)/2 - kstar[1] * uRu + kpost[ig-1,1] * uRustar - kstar[2] * etauetau + kpost[ig-1,2] * etauetaustar factmp <- (postshape-1)*(log(kstar)-log(kpost[ig-1,1])) logalpha <- min(0, exptmp + sum(factmp)) logU <- log(runif(1)) if (logU < logalpha) { # ACCEPT draw upost[ig,] <- u <- ustar npost[ig,] <- eta <- nstar kpost[ig,] <- kstar uRu <- uRustar etauetau <- etauetaustar accept[ig] <- 1 } else { upost[ig,] <- upost[ig-1,] npost[ig,] <- npost[ig-1,] kpost[ig,] <- kpost[ig-1,] } if( (ig%%10)==0) cat('.') } if (FALSE) { # POSTPROCESSING: accept <- accept[-c(1:burnin)] cat("\nAcceptance rate:",mean(accept),"\n") kpost <- kpost[-c(1:burnin),] upost <- upost[-c(1:burnin),] npost <- npost[-c(1:burnin),] kpostmean <- apply(kpost,2,mean) upostmean <- apply(upost,2,mean) npostmean <- apply(npost,2,mean) kpostmedian <- apply(kpost,2,median) upostmedian <- apply(upost,2,median) npostmedian <- apply(npost,2,median) vpost <- npost-upost vpostmedian <- apply(vpost,2,median) # ###################################################################### # Figures par(mfcol=c(1,3),mai=rep(0,4)) map.landkreis(log(Y)) map.landkreis(Y/E,zlim=c(.1,2.4)) map.landkreis(exp(upostmedian),zlim=c(.1,2.4)) par(mfcol=c(2,4),mai=c(.5,.5,.05,.1),mgp=c(2.3,.8,0)) hist(kpost[,1],main="",xlab=expression(kappa[u]),prob=TRUE) lines(density(kpost[,1]),col=2) tmp <- seq(0,to=max(kpost[,1]),l=500) lines(tmp,dgamma(tmp,ahyper[1],bhyper[1]),col=4) abline(v=kpostmedian[1],col=3) hist(kpost[,2],main="",xlab=expression(kappa[y]),prob=TRUE) lines(density(kpost[,2]),col=2) tmp <- seq(0,to=max(kpost[,2]),l=500) lines(tmp,dgamma(tmp,ahyper[2],bhyper[2]),col=4) abline(v=kpostmedian[2],col=3) # Trace plots: plot(kpost[,1],ylab=expression(kappa[u]),type="l") abline(h=kpostmedian[1],col=3) plot(kpost[,2],ylab=expression(kappa[y]),type="l") abline(h=kpostmedian[2],col=3) # ACF: acf(kpost[,1],ylab=expression(kappa[u])) acf(kpost[,2],ylab=expression(kappa[y])) # scatter plots plot(kpost[,1],kpost[,2],xlab=expression(kappa[u]),ylab=expression(kappa[y])) abline(v=kpostmedian[1],h=kpostmedian[2],col=3) plot(accept+rnorm(ngibbs,sd=.05),pch=".",ylim=c(-1,2),yaxt="n",ylab="") text(ngibbs/2,1/2,paste("Acceptance rate:",round(mean(accept),3))) axis(2,at=c(0,1),label=c("Reject","Accept")) } detach(Oral) ###################################################################### spam/tests/demo_spam.Rout.save0000644000176200001440000000465213574427304016150 0ustar liggesusers R version 3.5.0 (2018-04-23) -- "Joy in Playing" Copyright (C) 2018 The R Foundation for Statistical Computing Platform: x86_64-pc-linux-gnu (64-bit) R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. R is a collaborative project with many contributors. Type 'contributors()' for more information and 'citation()' on how to cite R or R packages in publications. Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. > # HEADER #################################################### > # This is file spam/tests/demo_spam.R. # > # It is part of the R package spam, # > # --> https://CRAN.R-project.org/package=spam # > # --> https://CRAN.R-project.org/package=spam64 # > # --> https://git.math.uzh.ch/reinhard.furrer/spam # > # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # > # Roman Flury [aut], Daniel Gerber [ctb], # > # Kaspar Moesinger [ctb] # > # HEADER END ################################################ > > > # This is a simple demo, wrapping up the functionality of spam. > options( echo=FALSE) Loading required package: dotCall64 Loading required package: grid Spam version 2.5-1 (2019-12-12) is loaded. Type 'help( Spam)' or 'demo( spam)' for a short introduction and overview of this package. Help for individual functions is also obtained by adding the suffix '.spam' to the function name, e.g. 'help( chol.spam)'. [,1] [,2] [,3] [,4] [,5] [,6] [,7] [1,] -0.6618498 1.231945 -0.3828219 0.8828018 -1.266815 -0.7666105 -1.421992 Class 'spam' (32-bit) [,1] [,2] [,3] [,4] [,5] [,6] [,7] [1,] 0 1.23194518 -0.3828219 0.8828018 -1.2668148 -0.7666105 -1.4219925 [2,] 0 -0.06488077 0.2994216 1.8627490 -0.1985833 1.4433629 -0.3282283 [3,] 0 1.06899373 0.6742398 1.6117253 0.1388658 0.8448793 0.2845701 [4,] 0 -0.37696531 -0.2928163 0.1354795 -0.2793360 -0.3993704 0.7193359 [5,] 0 1.04318309 0.4880534 1.0880860 0.7089194 -1.4277676 0.4324160 Class 'spam' (32-bit) [1] -0.36181804 0.07322929 -0.13634352 0.59605327 0.52252315 > > proc.time() user system elapsed 1.020 0.084 1.092 spam/tests/demo_article-jss-example1.Rout.save0000644000176200001440000001656713574427304021152 0ustar liggesusers R version 3.5.0 (2018-04-23) -- "Joy in Playing" Copyright (C) 2018 The R Foundation for Statistical Computing Platform: x86_64-pc-linux-gnu (64-bit) R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. R is a collaborative project with many contributors. Type 'contributors()' for more information and 'citation()' on how to cite R or R packages in publications. Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. > # HEADER #################################################### > # This is file spam/tests/demo_article-jss-example1.R. # > # It is part of the R package spam, # > # --> https://CRAN.R-project.org/package=spam # > # --> https://CRAN.R-project.org/package=spam64 # > # --> https://git.math.uzh.ch/reinhard.furrer/spam # > # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # > # Roman Flury [aut], Daniel Gerber [ctb], # > # Kaspar Moesinger [ctb] # > # HEADER END ################################################ > > > # JSS article: > # "spam: A Sparse Matrix R Package with Emphasis on > # MCMC Methods for Gaussian Markov Random Fields" > # > # Compared to the R code given in the article, here we give: > # - improved formatting > # - more comments > # - the R code to construct the figures > > > > # SETUP: > library("spam") Loading required package: dotCall64 Loading required package: grid Spam version 2.5-1 (2019-12-12) is loaded. Type 'help( Spam)' or 'demo( spam)' for a short introduction and overview of this package. Help for individual functions is also obtained by adding the suffix '.spam' to the function name, e.g. 'help( chol.spam)'. Attaching package: 'spam' The following objects are masked from 'package:base': backsolve, forwardsolve > options(spam.structurebased=TRUE) > data("UKDriverDeaths") > > y <- sqrt(c(UKDriverDeaths)) # square root counts > > n <- length(y) # n=192 > m <- 12 # We want to predict for one season. > nm <- n+m # Total length of s and t > > > priorshape <- c(4, 1, 1) # alpha's, as in Rue & Held (2005) > priorinvscale <- c(4, 0.1, 0.0005) # beta's > > # Construct the individual block precisions > # (based on unit precision parameters kappa, denoted with k): > > # Qsy, Qty are trivial: > Qsy <- diag.spam(n) > pad(Qsy) <- c(n+m, n) # previously: dim(Qsy) <- c(n+m, n) > > Qty <- Qsy > > Qst <- spam(0, nm, nm) > Qst[cbind(1:n, 1:n)] <- rep(1, n) > > > # The form of Qss is given by (Rue and Held equation 3.59). > # Qss can be constructed with a loop: > Qss <- spam(0, nm, nm) > for (i in 0:(nm-m)) { + Qss[i+1:m,i+1:m] <- Qss[i+1:m, i+1:m] + matrix(1,m,m) + # Qss[i+1:m,i+1:m] <- Qss[i+1:m, i+1:m]+1 # previously... + } > > # Note that for the final version we need: > # Qss <- k_s * Qss + k_y * diag.spam(nm) > > > > > # The form of Qtt is given by (Rue and Held equation 3.40). > # Similar approaches to construct Qtt: > > Qtt <- spam(0,nm,nm) > Qtt[cbind(1:(nm-1),2:nm)] <- -c(2,rep(4,nm-3),2) > Qtt[cbind(1:(nm-2),3:nm)] <- rep(1,nm-2) > Qtt <- Qtt + t( Qtt) > diag(Qtt) <- c(1,5,rep(6,nm-4),5,1) > > > > # Create temporary kappa and precision matrix to illustrate > # adjacency matrix and ordering. > k <- c(1,1,1) > Qst_yk <- rbind(cbind(k[2]*Qss + k[1]*diag.spam(nm), k[1]*Qst), + cbind(k[1]*Qst, k[3]*Qtt + k[1]*diag.spam(nm))) > > struct <- chol(Qst_yk) > > > > # Note that we do not provide the exactly the same ordering > # algorithms. Hence, the following is sightly different than > # Figure RH4.2. > cholQst_yk <- chol(Qst_yk,pivot="RCM") > P <- ordering(cholQst_yk) > display(Qst_yk) Warning message: default value for 'cex' in 'display' might not be the optimal choice > display(Qst_yk[P,P]) Warning message: default value for 'cex' in 'display' might not be the optimal choice > > > > # Recall: > # k=( kappa_y, kappa_s, kappa_t)' > > # Gibbs sampler > ngibbs <- 100 # In the original version is 500! > burnin <- 10 # > 0 > totalg <- ngibbs+burnin > set.seed(14) > > # Initialize parameters: > spost <- tpost <- array(0, c(totalg, nm)) > kpost <- array(0, c(totalg, 3)) > > # Starting values: > kpost[1,] <- c(.5,28,500) > tpost[1,] <- 40 > > # calculation of a few variables: > postshape <- priorshape + c( n/2, (n+1)/2, (n+m-2)/2) > > > for (ig in 2:totalg) { + + Q <- rbind(cbind(kpost[ig-1,2]*Qss + kpost[ig-1,1]*Qst, + kpost[ig-1,1]*Qst), + cbind(kpost[ig-1,1]*Qst, + kpost[ig-1,3]*Qtt + kpost[ig-1,1]*Qst)) + + b <- c(kpost[ig-1,1]*Qsy %*% y, kpost[ig-1,1]*Qsy %*% y) + + tmp <- rmvnorm.canonical(1, b, Q, Lstruct=struct) + + + spost[ig,] <- tmp[1:nm] + + tpost[ig,] <- tmp[1:nm+nm] + + + tmp <- y-spost[ig,1:n]-tpost[ig,1:n] + + postinvscale <- priorinvscale + # prior contribution + c( sum( tmp^2)/2, # Qyy_st is the identity + t(spost[ig,]) %*% (Qss %*% spost[ig,])/2, + t(tpost[ig,]) %*% (Qtt %*% tpost[ig,])/2) + + + kpost[ig,] <- rgamma(3, postshape, postinvscale) + + if( (ig%%10)==0) cat('.') + + } ...........> > > > # Eliminate burn-in: > kpost <- kpost[-c(1:burnin),] > spost <- spost[-c(1:burnin),] > tpost <- tpost[-c(1:burnin),] > > postquant <- apply(spost+tpost, 2, quantile,c(.025,.975)) > postmean <- apply(spost+tpost, 2, mean) > postmedi <- apply(spost+tpost, 2, median) > > if (F){ + + par(mfcol=c(1,1),mai=c(.6,.8,.01,.01)) + + plot( y^2, ylim=c(800,2900),xlim=c(0,nm),ylab="Counts") + #lines( postmean^2, col=2) + lines( postmedi^2, col=2) + matlines( t(postquant)^2, col=4,lty=1) + + legend("topright",legend=c("Posterior median", "Quantiles of posterior sample", + "Quantiles of predictive distribution"), + bty="n",col=c(2,4,3),lty=1) + + + + + # Constructing a predictive distribution: + ypred <- rnorm( ngibbs*nm, c(spost+tpost),sd=rep( 1/sqrt(kpost[,1]), nm)) + dim(ypred) <- c(ngibbs,nm) + postpredquant <- apply(ypred, 2, quantile,c(.025,.975)) + matlines( t(postpredquant)^2, col=3,lty=1) + points(y^2) + dev.off() + + kpostmedian <- apply(kpost,2,median) + + par(mfcol=c(1,3),mai=c(.65,.65,.01,.01),cex=.85,mgp=c(2.6,1,0)) + + matplot( log( kpost), lty=1, type="l",xlab="Index") + abline(h=log(kpostmedian),col=3) + acf( kpost[,3],ylab=expression(kappa[t])) + plot(kpost[,2:3],ylab=expression(kappa[t]),xlab=expression(kappa[s]),cex=.8) + abline(h=kpostmedian[3],v=kpostmedian[2],col=3) + dev.off() + + + allkappas <- rbind(apply(kpost,2,mean), + apply(kpost,2,median), + apply(1/kpost,2,mean), + apply(1/kpost,2,median)) + colnames(allkappas) <- c("kappa_y", "kappa_s", "kappa_t") + rownames(allkappas) <- c("Prec (mean)", "Prec (median)", + "Var (mean)", "Var (median) ") + print(allkappas,4) + + png("example1_m1.png",width=300,height=300) + par(mai=c(.5,.5,.05,.05)) + display(Qst_yk) + dev.off() + + png("example1_m2.png",width=300,height=300) + par(mai=c(.5,.5,.05,.05)) + display(struct) + dev.off() + + + summary(kpost) + + + } > > proc.time() user system elapsed 2.068 0.152 2.214 spam/tests/demo_jss15-BYM.Rout.save0000644000176200001440000000407713574427304016603 0ustar liggesusers R version 3.5.0 (2018-04-23) -- "Joy in Playing" Copyright (C) 2018 The R Foundation for Statistical Computing Platform: x86_64-pc-linux-gnu (64-bit) R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. R is a collaborative project with many contributors. Type 'contributors()' for more information and 'citation()' on how to cite R or R packages in publications. Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. > # HEADER #################################################### > # This is file spam/tests/demo_jss15-BYM.R. # > # It is part of the R package spam, # > # --> https://CRAN.R-project.org/package=spam # > # --> https://CRAN.R-project.org/package=spam64 # > # --> https://git.math.uzh.ch/reinhard.furrer/spam # > # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # > # Roman Flury [aut], Daniel Gerber [ctb], # > # Kaspar Moesinger [ctb] # > # HEADER END ################################################ > > > options( echo=FALSE) Loading required package: dotCall64 Loading required package: grid Spam version 2.5-1 (2019-12-12) is loaded. Type 'help( Spam)' or 'demo( spam)' for a short introduction and overview of this package. Help for individual functions is also obtained by adding the suffix '.spam' to the function name, e.g. 'help( chol.spam)'. [1] -0.45371922 0.17297575 0.02605778 -0.44984751 -0.36053283 0.01309363 [1] -1.341895 -3.756725 -2.514229 -4.411210 -6.486653 -5.101487 [1] 15.05715 53.22751 41.15492 13.16245 19.87138 30.27948 [1] 0 1 1 1 1 0 [1] 0.255439209 -0.299099415 -0.004660022 -0.392147580 -0.318792450 [6] -0.344095560 [1] -0.0152950744 0.0008418105 0.0400659014 -0.0160847172 0.0064331753 [6] -0.0154282422 [1] 21 [1] -780.3814 > > > proc.time() user system elapsed 1.512 0.224 1.737 spam/tests/demo_spam.R0000644000176200001440000000311013536451710014443 0ustar liggesusers# HEADER #################################################### # This is file spam/tests/demo_spam.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ # This is a simple demo, wrapping up the functionality of spam. options( echo=FALSE) library( spam, warn.conflict=FALSE) set.seed(14) nrow <- 5 ncol <- 7 fmat <- matrix(rnorm(nrow*ncol),nrow) smat <- as.spam(fmat) smat[1,] smat[,1] <- 0 as.spam(smat) ssmat <- smat %*% t(smat) b <- c(-2:2) solve(ssmat,b) cholssmat <- chol(ssmat) # works also for large matrices: set.seed(14) nz <- 100 nrow <- 100 ncol <- 100 smat <- diag.spam(1,nrow,ncol) smat[cbind(sample(1:(nrow*ncol),size=nz))] <- runif(nz) smat <- smat %*% t(smat) b <- rnorm(nz) smatinvb <- solve(smat,b) cholssmat <- chol(smat) # displaying matrices if (F) { opar <- par(no.readonly = TRUE) par(ask=interactive() && (.Device %in% c("X11","GTK","gnome","windows","quartz"))) display(smat, main="'scatterplot'-type display, very efficient") options(spam.imagesize=prod(smat@dimension)+1) display(smat, main="'image'-type display, may be slow and heavy") par(opar) } options( echo=TRUE) spam/tests/demo_jss15-BYM.R0000644000176200001440000001360313536451710015105 0ustar liggesusers# HEADER #################################################### # This is file spam/tests/demo_jss15-BYM.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ options( echo=FALSE) library( spam, warn.conflict=FALSE) # This is the MCMC sampler presented in Section 2.2 of the article: # # Florian Gerber, Reinhard Furrer (2015). Pitfalls in the Implementation # of Bayesian Hierarchical Modeling of Areal Count Data: An Illustration # Using BYM and Leroux Models. Journal of Statistical Software, # Code Snippets, 63(1), 1–32. URL http://www.jstatsoft.org/v63/c01/. # # Note: For illustration we set # number of generated samples: 5'000 # number of burnin samples: 500 # thinning: 10 # This takes 1-2 minutes of computation time. # # In the JSS article we used: # number of generated samples: 300'000 # number of burnin samples: 15'000 # thinning: 20 # invisible(readline(prompt = "Type \t to continue : ")) # SETUP: options(spam.structurebased=TRUE) # Besag-York-Molie model (BYM) # load data data(Oral); attach(Oral) path <- system.file("demodata/germany.adjacency", package = "spam") A <- adjacency.landkreis(path); n <- dim(A)[1] set.seed(2) # hyper priors hyperA <- c(1, 1); hyperB <- c(0.5, .01) # sampler length, burnin and thinning totalg <- 30 burnin <- 500 thin <- 10 # variable to store samples upost <- vpost <- array(0, c(totalg, n)) kpost <- array(NA, c(totalg, 2)); accept <- rep(NA, totalg) # initial values upost[1,] <- vpost[1,] <- rep(.001, 544); kpost[1,] <- c(10, 100) # precalculate some quantities eta <- upost[1,] + vpost[1,] C <- exp(eta) * E; diagC <- diag.spam(c(rep(0, n), C)) b <- c( rep(0, n), Y + (eta - 1) * C) Qu <- R <- precmat.IGMRFirreglat(A); pad(Qu) <- c(2 * n, 2 * n) Qv <- as.spam(rbind(cbind( diag(n), -diag(n)), cbind(-diag(n), diag(n)))) Q <- kpost[1,1] * Qu + kpost[1,2] * Qv + diagC # store symbolic cholesky factorization of Q struct <- chol(Q, memory = list(nnzcolindices = 6467)) uRuHalf <- t(upost[1,]) %*% (R %*% upost[1,]) / 2 vvHalf <- t(vpost[1,]) %*% vpost[1,] / 2 postshape <- hyperA + c(n - 1, n) / 2 for (i in 2:totalg) { # update precision kpost[i,] <- rgamma(2, postshape, hyperB + c(uRuHalf, vvHalf)) # find eta tilde etaTilde <- eta for(index in 1:2){ C <- E * exp(etaTilde) diagC <- diag.spam(c(rep(0, n), C)) b <- c(rep(0, 544), Y + (etaTilde - 1) * C) Q <- kpost[i,1] * Qu + kpost[i,2] * Qv + diagC etaTilde <- c(solve.spam(Q, b, Rstruct = struct))[1:n + n] } C <- exp(etaTilde) * E; diagC <- diag.spam(c(rep(0, n), C)) b <- c( rep(0, n), Y + (etaTilde - 1) * C) Q <- kpost[i,1] * Qu + kpost[i,2] * Qv + diagC # simulate proposal x_ <- c(rmvnorm.canonical(1, b, Q, Rstruct = struct)) upost[i,] <- x_[1:n]; eta_ <- x_[1:n + n]; vpost[i,] <- eta_ - upost[i,] uRuHalf_ <- t(upost[i,]) %*% (R %*% upost[i,]) / 2 vvHalf_ <- t(vpost[i,]) %*% vpost[i,] / 2 # calculate acceptance probability etaTilde_ <- eta_ for(index in 1:2){ C_ <- E * exp(etaTilde_) diagC_ <- diag.spam(c(rep(0, n), C_)) b_ <- c(rep(0, 544), Y + (etaTilde_ - 1) * C_) Q_<- kpost[i,1] * Qu + kpost[i,2] * Qv + diagC_ etaTilde_ <- c(solve.spam(Q_, b_, Rstruct = struct))[1:n + n] } C_ <- exp(etaTilde_) * E; diagC_ <- diag.spam(c(rep(0, n), C_)) b_ <- c( rep(0, n), Y + (etaTilde_ - 1) * C_) Q_ <- kpost[i,1] * Qu + kpost[i,2] * Qv + diagC_ logPost_ <- sum(Y * eta_ - E * exp(eta_)) - kpost[i,1] * uRuHalf_ - kpost[i, 2] * vvHalf_ logPost <- sum(Y * eta - E * exp(eta)) - kpost[i,1] * uRuHalf - kpost[i,2] * vvHalf logApproxX_ <- - kpost[i,1] * uRuHalf_ - kpost[i,2] * vvHalf_ - sum(.5 * eta_^2 * C) + sum(b * eta_) logApproxX <- - kpost[i,1] * uRuHalf - kpost[i,2] * vvHalf - sum(.5 * eta^2 * C_) + sum(b_ * eta) logAlpha <- min(0, logPost_ - logPost + logApproxX - logApproxX_) # accept or reject proposal if (log(runif(1)) < logAlpha) { uRuHalf <- uRuHalf_; vvHalf <- vvHalf_ eta <- eta_; b <- b_; C <- C_; accept[i] <- 1 } else{ accept[i] <- 0; upost[i,] <- upost[i-1,]; vpost[i,] <- vpost[i-1,] } # progress report if(i%%500 == 0) cat(paste(i / 50, "%\n", sep = "" )) } # check values head(eta) tail(b) head(C) tail(accept) tail(upost[30,]) tail(vpost[30,]) sum(accept[-1]) sum(upost) if(FALSE){ ## remove burnin kpost <- kpost[-seq(burnin), ] upost <- upost[-seq(burnin), ] vpost <- vpost[-seq(burnin), ] accept <- accept[-seq(burnin)] ## thinning index <- c(TRUE, rep(FALSE, (thin - 1))) kpost <- kpost[index,] upost <- upost[index,] vpost <- vpost[index,] accept <- accept[index] ## acceptance rate mean(accept) plot(accept, yaxt = "n") axis(2, at = c(0,1), label = c("no", "yes"), las = 2) ## trace and mixing plots for the precision parameters ## kappa_u and kappa_v grid.newpage() grid_trace2(kpost, chain1_lab = expression(log~kappa[u]), chain2_lab = expression(log~kappa[v]), log = TRUE) ## summary statistics of ## kappa_u and kappa_v apply(kpost, 2, summary) par(mfrow = c(1,2)) ## standardized mortality ratios germany.plot(log(Y/E), main = "SMR") ## estimated relative log-risk germany.plot(apply(upost, 2, mean), main = "U | Y, hyper-priors") } options( echo=TRUE) spam/tests/testthat.R0000644000176200001440000000124713536451711014351 0ustar liggesusers# HEADER #################################################### # This is file spam/tests/testthat.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ library("testthat") # library("spam") test_check("spam") spam/tests/demo_timing.Rout.save0000644000176200001440000000516613574427304016500 0ustar liggesusers R version 3.5.0 (2018-04-23) -- "Joy in Playing" Copyright (C) 2018 The R Foundation for Statistical Computing Platform: x86_64-pc-linux-gnu (64-bit) R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. R is a collaborative project with many contributors. Type 'contributors()' for more information and 'citation()' on how to cite R or R packages in publications. Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. > # HEADER #################################################### > # This is file spam/tests/demo_timing.R. # > # It is part of the R package spam, # > # --> https://CRAN.R-project.org/package=spam # > # --> https://CRAN.R-project.org/package=spam64 # > # --> https://git.math.uzh.ch/reinhard.furrer/spam # > # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # > # Roman Flury [aut], Daniel Gerber [ctb], # > # Kaspar Moesinger [ctb] # > # HEADER END ################################################ > > > # We construct a few large matrices and we compare how much faster (slower) > # we are compared to the full matrix analysis. > # Since all the calculation are also done with full matrices, we do not > # exagerate with the sizes. > > options( echo=FALSE) Loading required package: dotCall64 Loading required package: grid Spam version 2.5-1 (2019-12-12) is loaded. Type 'help( Spam)' or 'demo( spam)' for a short introduction and overview of this package. Help for individual functions is also obtained by adding the suffix '.spam' to the function name, e.g. 'help( chol.spam)'. Comparing: Transpose Comparing: multiplication Comparing: solving Comparing: Transpose Comparing: multiplication Comparing: add identity Comparing: add identity quicker Comparing: solving Matrix object of class 'spam' of dimension 10x10, with 10 (row-wise) nonzero elements. Density of the matrix is 10%. Class 'spam' (32-bit) > > > > > > # illustrate the new spam x matrix multiply: > if (F){ + n <- 1000 + + A <- spam(0,n,n) + A[cbind(1:(n-1),2:n)] <- -c(2,rep(4,n-3),2) + A[cbind(1:(n-2),3:n)] <- rep(1,n-2) + A <- A + t( A) + diag(A) <- c(1,5,rep(6,n-4),5,1) + + + B <- array(rnorm(n*n),c(n,n)) + + system.time(C1 <- .spam.matmul.mat(A,B)) + system.time(C2 <- .spam.matmul(A,B)) + norm(C1-C2) + + + } > > proc.time() user system elapsed 2.092 0.108 2.186 spam/tests/demo_timing.R0000644000176200001440000000523713536451711015007 0ustar liggesusers# HEADER #################################################### # This is file spam/tests/demo_timing.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ # We construct a few large matrices and we compare how much faster (slower) # we are compared to the full matrix analysis. # Since all the calculation are also done with full matrices, we do not # exagerate with the sizes. options( echo=FALSE) library( spam, warn.conflict=FALSE) set.seed(14) # In the test function, we do not print out the actual times # We would get too many differences pointed out! compare <- function(expr1,expr2,tag=NULL) { if( !is.null(tag)) cat( "Comparing: ", tag, fill=TRUE) invisible(data.frame(full=system.time( expr1, TRUE)[1:3], sparse=system.time( expr2, TRUE)[1:3], row.names=c("user","system","elapsed"))) } xn <- 10 xm <- 12 # first start with a full matrix. fmat1 <- matrix(rnorm(xn*xm),xn,xm) smat1 <- as.spam(fmat1) compare(fmat2 <- t(fmat1), smat2 <- t(smat1), "Transpose") compare(ffmat <- fmat1 %*% fmat2, ssmat <- smat1 %*% smat2, "multiplication") compare( solve(ffmat), solve(ssmat), "solving") compare(rbind(fmat1,fmat1),rbind(smat1,smat1)) compare(cbind(fmat1,fmat1),cbind(smat1,smat1)) # now create a sparse matrix. fmat1[fmat1<3] <- 0 smat1 <- as.spam(fmat1) compare(fmat2 <- t(fmat1), smat2 <- t(smat1), "Transpose") compare(ffmat <- fmat1 %*% fmat2, ssmat <- smat1 %*% smat2, "multiplication") compare(ffmat <- ffmat + diag(xn), ssmat <- ssmat + diag.spam(xn), "add identity") compare(ffmat <- 1:xn %d+% ffmat, ssmat <- 1:xn %d+% ssmat, "add identity quicker") compare( solve(ffmat), solve(ssmat), "solving") summary(ssmat) # compare a few cbind/rbinds compare(rbind(fmat1,fmat1),rbind(smat1,smat1)) compare(cbind(fmat1,fmat1),cbind(smat1,smat1)) options( echo=TRUE) # illustrate the new spam x matrix multiply: if (F){ n <- 1000 A <- spam(0,n,n) A[cbind(1:(n-1),2:n)] <- -c(2,rep(4,n-3),2) A[cbind(1:(n-2),3:n)] <- rep(1,n-2) A <- A + t( A) diag(A) <- c(1,5,rep(6,n-4),5,1) B <- array(rnorm(n*n),c(n,n)) system.time(C1 <- .spam.matmul.mat(A,B)) system.time(C2 <- .spam.matmul(A,B)) norm(C1-C2) } spam/src/0000755000176200001440000000000013574431374012014 5ustar liggesusersspam/src/ds_ARPACK.f0000644000176200001440000052225413574431374013624 0ustar liggesusersc c dseupd.f c dsesrt.f c dsgets.f c dsaupd.f c dsaup2.f c dsconv.f c dsaitr.f c dgetv0.f c dsapps.f c dseigt.f c dstqrb.f c dsortr.f c c c test for equal zero c function eqZERO( a) implicit none logical eqZERO double precision a eqZERO = (abs( a) .LE. 1.1*epsilon( 0.0)) return end function c c test not equal to zero c function neZERO( a) implicit none logical neZERO double precision a neZERO = (abs( a) .GT. 1.1*epsilon( 0.0)) return end function c c c\BeginDoc c c\Name: dseupd c c\Description: c c This subroutine returns the converged approximations to eigenvalues c of A*z = lambda*B*z and (optionally): c c (1) the corresponding approximate eigenvectors, c c (2) an orthonormal (Lanczos) basis for the associated approximate c invariant subspace, c c (3) Both. c c There is negligible additional cost to obtain eigenvectors. An orthonormal c (Lanczos) basis is always computed. There is an additional storage cost c of n*nev if both are requested (in this case a separate array Z must be c supplied). c c These quantities are obtained from the Lanczos factorization computed c by DSAUPD for the linear operator OP prescribed by the MODE selection c (see IPARAM(7) in DSAUPD documentation.) DSAUPD must be called before c this routine is called. These approximate eigenvalues and vectors are c commonly called Ritz values and Ritz vectors respectively. They are c referred to as such in the comments that follow. The computed orthonormal c basis for the invariant subspace corresponding to these Ritz values is c referred to as a Lanczos basis. c c See documentation in the header of the subroutine DSAUPD for a definition c of OP as well as other terms and the relation of computed Ritz values c and vectors of OP with respect to the given problem A*z = lambda*B*z. c c The approximate eigenvalues of the original problem are returned in c ascending algebraic order. The user may elect to call this routine c once for each desired Ritz vector and store it peripherally if desired. c There is also the option of computing a selected set of these vectors c with a single call. c c\Usage: c call dseupd c ( RVEC, HOWMNY, SELECT, D, Z, LDZ, SIGMA, BMAT, N, WHICH, NEV, TOL, c RESID, NCV, V, LDV, IPARAM, IPNTR, WORKD, WORKL, LWORKL, INFO ) c c RVEC LOGICAL (INPUT) c Specifies whether Ritz vectors corresponding to the Ritz value c approximations to the eigenproblem A*z = lambda*B*z are computed. c c RVEC = .FALSE. Compute Ritz values only. c c RVEC = .TRUE. Compute Ritz vectors. c c HOWMNY Character*1 (INPUT) c Specifies how many Ritz vectors are wanted and the form of Z c the matrix of Ritz vectors. See remark 1 below. c = 'A': compute NEV Ritz vectors; c = 'S': compute some of the Ritz vectors, specified c by the logical array SELECT. c c SELECT Logical array of dimension NCV. (INPUT/WORKSPACE) c If HOWMNY = 'S', SELECT specifies the Ritz vectors to be c computed. To select the Ritz vector corresponding to a c Ritz value D(j), SELECT(j) must be set to .TRUE.. c If HOWMNY = 'A' , SELECT is used as a workspace for c reordering the Ritz values. c c D Double precision array of dimension NEV. (OUTPUT) c On exit, D contains the Ritz value approximations to the c eigenvalues of A*z = lambda*B*z. The values are returned c in ascending order. If IPARAM(7) = 3,4,5 then D represents c the Ritz values of OP computed by dsaupd transformed to c those of the original eigensystem A*z = lambda*B*z. If c IPARAM(7) = 1,2 then the Ritz values of OP are the same c as the those of A*z = lambda*B*z. c c Z Double precision N by NEV array if HOWMNY = 'A'. (OUTPUT) c On exit, Z contains the B-orthonormal Ritz vectors of the c eigensystem A*z = lambda*B*z corresponding to the Ritz c value approximations. c If RVEC = .FALSE. then Z is not referenced. c NOTE: The array Z may be set equal to first NEV columns of the c Arnoldi/Lanczos basis array V computed by DSAUPD . c c LDZ Integer. (INPUT) c The leading dimension of the array Z. If Ritz vectors are c desired, then LDZ .ge. max( 1, N ). In any case, LDZ .ge. 1. c c SIGMA Double precision (INPUT) c If IPARAM(7) = 3,4,5 represents the shift. Not referenced if c IPARAM(7) = 1 or 2. c c c **** The remaining arguments MUST be the same as for the **** c **** call to DSAUPD that was just completed. **** c c NOTE: The remaining arguments c c BMAT, N, WHICH, NEV, TOL, RESID, NCV, V, LDV, IPARAM, IPNTR, c WORKD, WORKL, LWORKL, INFO c c must be passed directly to DSEUPD following the last call c to DSAUPD . These arguments MUST NOT BE MODIFIED between c the the last call to DSAUPD and the call to DSEUPD . c c Two of these parameters (WORKL, INFO) are also output parameters: c c WORKL Double precision work array of length LWORKL. (OUTPUT/WORKSPACE) c WORKL(1:4*ncv) contains information obtained in c dsaupd . They are not changed by dseupd . c WORKL(4*ncv+1:ncv*ncv+8*ncv) holds the c untransformed Ritz values, the computed error estimates, c and the associated eigenvector matrix of H. c c Note: IPNTR(8:10) contains the pointer into WORKL for addresses c of the above information computed by dseupd . c ------------------------------------------------------------- c IPNTR(8): pointer to the NCV RITZ values of the original system. c IPNTR(9): pointer to the NCV corresponding error bounds. c IPNTR(10): pointer to the NCV by NCV matrix of eigenvectors c of the tridiagonal matrix T. Only referenced by c dseupd if RVEC = .TRUE. See Remarks. c ------------------------------------------------------------- c c INFO Integer. (OUTPUT) c Error flag on output. c = 0: Normal exit. c = -1: N must be positive. c = -2: NEV must be positive. c = -3: NCV must be greater than NEV and less than or equal to N. c = -5: WHICH must be one of 'LM', 'SM', 'LA', 'SA' or 'BE'. c = -6: BMAT must be one of 'I' or 'G'. c = -7: Length of private work WORKL array is not sufficient. c = -8: Error return from trid. eigenvalue calculation; c Information error from LAPACK routine dsteqr . c = -9: Starting vector is zero. c = -10: IPARAM(7) must be 1,2,3,4,5. c = -11: IPARAM(7) = 1 and BMAT = 'G' are incompatible. c = -12: NEV and WHICH = 'BE' are incompatible. c = -14: DSAUPD did not find any eigenvalues to sufficient c accuracy. c = -15: HOWMNY must be one of 'A' or 'S' if RVEC = .true. c = -16: HOWMNY = 'S' not yet implemented c = -17: DSEUPD got a different count of the number of converged c Ritz values than DSAUPD got. This indicates the user c probably made an error in passing data from DSAUPD to c DSEUPD or that the data was modified before entering c DSEUPD . c c\BeginLib c c\References: c 1. D.C. Sorensen, "Implicit Application of Polynomial Filters in c a k-Step Arnoldi Method", SIAM J. Matr. Anal. Apps., 13 (1992), c pp 357-385. c 2. R.B. Lehoucq, "Analysis and Implementation of an Implicitly c Restarted Arnoldi Iteration", Rice University Technical Report c TR95-13, Department of Computational and Applied Mathematics. c 3. B.N. Parlett, "The Symmetric Eigenvalue Problem". Prentice-Hall, c 1980. c 4. B.N. Parlett, B. Nour-Omid, "Towards a Black Box Lanczos Program", c Computer Physics Communications, 53 (1989), pp 169-179. c 5. B. Nour-Omid, B.N. Parlett, T. Ericson, P.S. Jensen, "How to c Implement the Spectral Transformation", Math. Comp., 48 (1987), c pp 663-673. c 6. R.G. Grimes, J.G. Lewis and H.D. Simon, "A Shifted Block Lanczos c Algorithm for Solving Sparse Symmetric Generalized Eigenproblems", c SIAM J. Matr. Anal. Apps., January (1993). c 7. L. Reichel, W.B. Gragg, "Algorithm 686: FORTRAN Subroutines c for Updating the QR decomposition", ACM TOMS, December 1990, c Volume 16 Number 4, pp 369-377. c c\Remarks c 1. The converged Ritz values are always returned in increasing c (algebraic) order. c c 2. Currently only HOWMNY = 'A' is implemented. It is included at this c stage for the user who wants to incorporate it. c c\Routines called: c dsesrt ARPACK routine that sorts an array X, and applies the c corresponding permutation to a matrix A. c dsortr dsortr ARPACK sorting routine. c ivout ARPACK utility routine that prints integers. c dvout ARPACK utility routine that prints vectors. c dgeqr2 LAPACK routine that computes the QR factorization of c a matrix. c dlacpy LAPACK matrix copy routine. c dlamch LAPACK routine that determines machine constants. c dorm2r LAPACK routine that applies an orthogonal matrix in c factored form. c dsteqr LAPACK routine that computes eigenvalues and eigenvectors c of a tridiagonal matrix. c dger Level 2 BLAS rank one update to a matrix. c dcopy Level 1 BLAS that copies one vector to another . c dnrm2 Level 1 BLAS that computes the norm of a vector. c dscal Level 1 BLAS that scales a vector. c dswap Level 1 BLAS that swaps the contents of two vectors. c\Authors c Danny Sorensen Phuong Vu c Richard Lehoucq CRPC / Rice University c Chao Yang Houston, Texas c Dept. of Computational & c Applied Mathematics c Rice University c Houston, Texas c c\Revision history: c 12/15/93: Version ' 2.1' c c\SCCS Information: @(#) c FILE: seupd.F SID: 2.11 DATE OF SID: 04/10/01 RELEASE: 2 c c\EndLib c c----------------------------------------------------------------------- subroutine dseupd (rvec , howmny, select, d , & z , ldz , sigma , bmat , & n , which , nev , tol , & resid , ncv , v , ldv , & iparam, ipntr , workd , workl, & lworkl, info ) c implicit none c c %------------------% c | Scalar Arguments | c %------------------% c character bmat, howmny, which*2 logical rvec integer info, ldz, ldv, lworkl, n, ncv, nev Double precision & sigma, tol c c %-----------------% c | Array Arguments | c %-----------------% c integer iparam(7), ipntr(11) logical select(ncv) Double precision & d(nev) , resid(n) , v(ldv,ncv), & z(ldz, nev), workd(2*n), workl(lworkl) c c %------------% c | Parameters | c %------------% c Double precision & one, zero parameter (one = 1.0D+0 , zero = 0.0D+0 ) Integer ione parameter (ione = 1) c c %---------------% c | Local Scalars | c %---------------% c character type*6 integer bounds , ierr , ih , ihb , ihd , & iq , iw , j , k , ldh , & ldq , mode , nconv , next , & ritz , irz , ibd , np , ishift, & leftptr, rghtptr, numcnv, jj Double precision & bnorm2 , rnorm, temp, temp1, eps23 logical reord, dseupdtrue c c %----------------------% c | External Subroutines | c %----------------------% c external dcopy , dger , dgeqr2 , dlacpy , dorm2r , dscal , & dsesrt , dsteqr , dswap , dsortr c c %--------------------% c | External Functions | c %--------------------% c Double precision & dnrm2 , dlamch external dnrm2 , dlamch c c %---------------------% c | Intrinsic Functions | c %---------------------% c intrinsic min c c %-----------------------% c | Executable Statements | c %-----------------------% c c %------------------------% c | Set default parameters | c %------------------------% c mode = iparam(7) nconv = iparam(5) info = 0 dseupdtrue = .true. c c %--------------% c | Quick return | c %--------------% c if (nconv .eq. 0) go to 9000 ierr = 0 c if (nconv .le. 0) ierr = -14 if (n .le. 0) ierr = -1 if (nev .le. 0) ierr = -2 if (ncv .le. nev .or. ncv .gt. n) ierr = -3 if (which .ne. 'LM' .and. & which .ne. 'SM' .and. & which .ne. 'LA' .and. & which .ne. 'SA' .and. & which .ne. 'BE') ierr = -5 if (bmat .ne. 'I' .and. bmat .ne. 'G') ierr = -6 if ( (howmny .ne. 'A' .and. & howmny .ne. 'P' .and. & howmny .ne. 'S') .and. rvec ) & ierr = -15 if (rvec .and. howmny .eq. 'S') ierr = -16 c if (rvec .and. lworkl .lt. ncv**2+8*ncv) ierr = -7 c if (mode .eq. 1 .or. mode .eq. 2) then type = 'REGULR' else if (mode .eq. 3 ) then type = 'SHIFTI' else if (mode .eq. 4 ) then type = 'BUCKLE' else if (mode .eq. 5 ) then type = 'CAYLEY' else ierr = -10 end if if (mode .eq. 1 .and. bmat .eq. 'G') ierr = -11 if (nev .eq. 1 .and. which .eq. 'BE') ierr = -12 c c %------------% c | Error Exit | c %------------% c if (ierr .ne. 0) then info = ierr go to 9000 end if c c %-------------------------------------------------------% c | Pointer into WORKL for address of H, RITZ, BOUNDS, Q | c | etc... and the remaining workspace. | c | Also update pointer to be used on output. | c | Memory is laid out as follows: | c | workl(1:2*ncv) := generated tridiagonal matrix H | c | The subdiagonal is stored in workl(2:ncv). | c | The dead spot is workl(1) but upon exiting | c | dsaupd stores the B-norm of the last residual | c | vector in workl(1). We use this !!! | c | workl(2*ncv+1:2*ncv+ncv) := ritz values | c | The wanted values are in the first NCONV spots. | c | workl(3*ncv+1:3*ncv+ncv) := computed Ritz estimates | c | The wanted values are in the first NCONV spots. | c | NOTE: workl(1:4*ncv) is set by dsaupd and is not | c | modified by dseupd . | c %-------------------------------------------------------% c c %-------------------------------------------------------% c | The following is used and set by dseupd . | c | workl(4*ncv+1:4*ncv+ncv) := used as workspace during | c | computation of the eigenvectors of H. Stores | c | the diagonal of H. Upon EXIT contains the NCV | c | Ritz values of the original system. The first | c | NCONV spots have the wanted values. If MODE = | c | 1 or 2 then will equal workl(2*ncv+1:3*ncv). | c | workl(5*ncv+1:5*ncv+ncv) := used as workspace during | c | computation of the eigenvectors of H. Stores | c | the subdiagonal of H. Upon EXIT contains the | c | NCV corresponding Ritz estimates of the | c | original system. The first NCONV spots have the | c | wanted values. If MODE = 1,2 then will equal | c | workl(3*ncv+1:4*ncv). | c | workl(6*ncv+1:6*ncv+ncv*ncv) := orthogonal Q that is | c | the eigenvector matrix for H as returned by | c | dsteqr . Not referenced if RVEC = .False. | c | Ordering follows that of workl(4*ncv+1:5*ncv) | c | workl(6*ncv+ncv*ncv+1:6*ncv+ncv*ncv+2*ncv) := | c | Workspace. Needed by dsteqr and by dseupd . | c | GRAND total of NCV*(NCV+8) locations. | c %-------------------------------------------------------% c c ih = ipntr(5) ritz = ipntr(6) bounds = ipntr(7) ldh = ncv ldq = ncv ihd = bounds + ldh ihb = ihd + ldh iq = ihb + ldh iw = iq + ldh*ncv next = iw + 2*ncv ipntr(4) = next ipntr(8) = ihd ipntr(9) = ihb ipntr(10) = iq c c %----------------------------------------% c | irz points to the Ritz values computed | c | by _seigt before exiting _saup2. | c | ibd points to the Ritz estimates | c | computed by _seigt before exiting | c | _saup2. | c %----------------------------------------% c irz = ipntr(11)+ncv ibd = irz+ncv c c c %---------------------------------% c | Set machine dependent constant. | c %---------------------------------% c eps23 = dlamch ('Epsilon-Machine') eps23 = eps23**(2.0D+0 / 3.0D+0 ) c c %---------------------------------------% c | RNORM is B-norm of the RESID(1:N). | c | BNORM2 is the 2 norm of B*RESID(1:N). | c | Upon exit of dsaupd WORKD(1:N) has | c | B*RESID(1:N). | c %---------------------------------------% c rnorm = workl(ih) if (bmat .eq. 'I') then bnorm2 = rnorm else if (bmat .eq. 'G') then bnorm2 = dnrm2 (n, workd, 1) end if c c if (rvec) then c reord = .false. c c %---------------------------------------------------% c | Use the temporary bounds array to store indices | c | These will be used to mark the select array later | c %---------------------------------------------------% c do 10 j = 1,ncv workl(bounds+j-1) = j select(j) = .false. 10 continue c c %-------------------------------------% c | Select the wanted Ritz values. | c | Sort the Ritz values so that the | c | wanted ones appear at the tailing | c | NEV positions of workl(irr) and | c | workl(iri). Move the corresponding | c | error estimates in workl(bound) | c | accordingly. | c %-------------------------------------% c np = ncv - nev ishift = 0 call dsgets (ishift, which , nev , & np , workl(irz) , workl(bounds), & workl) c c c %-----------------------------------------------------% c | Record indices of the converged wanted Ritz values | c | Mark the select array for possible reordering | c %-----------------------------------------------------% c numcnv = 0 do 11 j = 1,ncv temp1 = max(eps23, abs(workl(irz+ncv-j)) ) jj = INT(workl(bounds + ncv - j)) if (numcnv .lt. nconv .and. & workl(ibd+jj-1) .le. tol*temp1) then select(jj) = .true. numcnv = numcnv + 1 if (jj .gt. nev) reord = .true. endif 11 continue c c %-----------------------------------------------------------% c | Check the count (numcnv) of converged Ritz values with | c | the number (nconv) reported by _saupd. If these two | c | are different then there has probably been an error | c | caused by incorrect passing of the _saupd data. | c %-----------------------------------------------------------% c c if (numcnv .ne. nconv) then info = -17 go to 9000 end if c c %-----------------------------------------------------------% c | Call LAPACK routine _steqr to compute the eigenvalues and | c | eigenvectors of the final symmetric tridiagonal matrix H. | c | Initialize the eigenvector matrix Q to the identity. | c %-----------------------------------------------------------% c call dcopy (ncv-1, workl(ih+1), 1, workl(ihb), 1) call dcopy (ncv, workl(ih+ldh), 1, workl(ihd), 1) c call dsteqr ('Identity', ncv, workl(ihd), workl(ihb), & workl(iq) , ldq, workl(iw), ierr) c if (ierr .ne. 0) then info = -8 go to 9000 end if c if (reord) then c c %---------------------------------------------% c | Reordered the eigenvalues and eigenvectors | c | computed by _steqr so that the "converged" | c | eigenvalues appear in the first NCONV | c | positions of workl(ihd), and the associated | c | eigenvectors appear in the first NCONV | c | columns. | c %---------------------------------------------% c leftptr = 1 rghtptr = ncv c if (ncv .eq. 1) go to 30 c 20 if (select(leftptr)) then c c %-------------------------------------------% c | Search, from the left, for the first Ritz | c | value that has not converged. | c %-------------------------------------------% c leftptr = leftptr + 1 c else if ( .not. select(rghtptr)) then c c %----------------------------------------------% c | Search, from the right, the first Ritz value | c | that has converged. | c %----------------------------------------------% c rghtptr = rghtptr - 1 c else c c %----------------------------------------------% c | Swap the Ritz value on the left that has not | c | converged with the Ritz value on the right | c | that has converged. Swap the associated | c | eigenvector of the tridiagonal matrix H as | c | well. | c %----------------------------------------------% c temp = workl(ihd+leftptr-1) workl(ihd+leftptr-1) = workl(ihd+rghtptr-1) workl(ihd+rghtptr-1) = temp call dcopy (ncv, workl(iq+ncv*(leftptr-1)), 1, & workl(iw), 1) call dcopy (ncv, workl(iq+ncv*(rghtptr-1)), 1, & workl(iq+ncv*(leftptr-1)), 1) call dcopy (ncv, workl(iw), 1, & workl(iq+ncv*(rghtptr-1)), 1) leftptr = leftptr + 1 rghtptr = rghtptr - 1 c end if c if (leftptr .lt. rghtptr) go to 20 c 30 end if c c c %----------------------------------------% c | Load the converged Ritz values into D. | c %----------------------------------------% c call dcopy (nconv, workl(ihd), 1, d(1), 1) c else c c %-----------------------------------------------------% c | Ritz vectors not required. Load Ritz values into D. | c %-----------------------------------------------------% c call dcopy (nconv, workl(ritz), 1, d(1), 1) call dcopy (ncv, workl(ritz), 1, workl(ihd), 1) c end if c c %------------------------------------------------------------------% c | Transform the Ritz values and possibly vectors and corresponding | c | Ritz estimates of OP to those of A*x=lambda*B*x. The Ritz values | c | (and corresponding data) are returned in ascending order. | c %------------------------------------------------------------------% c if (type .eq. 'REGULR') then c c %---------------------------------------------------------% c | Ascending sort of wanted Ritz values, vectors and error | c | bounds. Not necessary if only Ritz values are desired. | c %---------------------------------------------------------% c if (rvec) then call dsesrt ('LA', rvec , nconv, d, ncv, workl(iq), ldq) else call dcopy (ncv, workl(bounds), 1, workl(ihb), 1) end if c else c c %-------------------------------------------------------------% c | * Make a copy of all the Ritz values. | c | * Transform the Ritz values back to the original system. | c | For TYPE = 'SHIFTI' the transformation is | c | lambda = 1/theta + sigma | c | For TYPE = 'BUCKLE' the transformation is | c | lambda = sigma * theta / ( theta - 1 ) | c | For TYPE = 'CAYLEY' the transformation is | c | lambda = sigma * (theta + 1) / (theta - 1 ) | c | where the theta are the Ritz values returned by dsaupd . | c | NOTES: | c | *The Ritz vectors are not affected by the transformation. | c | They are only reordered. | c %-------------------------------------------------------------% c call dcopy (ncv, workl(ihd), 1, workl(iw), 1) if (type .eq. 'SHIFTI') then do 40 k=1, ncv workl(ihd+k-1) = one / workl(ihd+k-1) + sigma 40 continue else if (type .eq. 'BUCKLE') then do 50 k=1, ncv workl(ihd+k-1) = sigma * workl(ihd+k-1) / & (workl(ihd+k-1) - one) 50 continue else if (type .eq. 'CAYLEY') then do 60 k=1, ncv workl(ihd+k-1) = sigma * (workl(ihd+k-1) + one) / & (workl(ihd+k-1) - one) 60 continue end if c c %-------------------------------------------------------------% c | * Store the wanted NCONV lambda values into D. | c | * Sort the NCONV wanted lambda in WORKL(IHD:IHD+NCONV-1) | c | into ascending order and apply sort to the NCONV theta | c | values in the transformed system. We will need this to | c | compute Ritz estimates in the original system. | c | * Finally sort the lambda`s into ascending order and apply | c | to Ritz vectors if wanted. Else just sort lambda`s into | c | ascending order. | c | NOTES: | c | *workl(iw:iw+ncv-1) contain the theta ordered so that they | c | match the ordering of the lambda. We`ll use them again for | c | Ritz vector purification. | c %-------------------------------------------------------------% c call dcopy (nconv, workl(ihd), 1, d(1), 1) call dsortr ('LA', dseupdtrue, nconv, workl(ihd), workl(iw)) if (rvec) then call dsesrt ('LA', rvec , nconv, d, ncv, workl(iq), ldq) else call dcopy (ncv, workl(bounds), 1, workl(ihb), 1) call dscal (ncv, bnorm2/rnorm, workl(ihb), 1) call dsortr ('LA', dseupdtrue, nconv, d, workl(ihb)) end if c end if c c %------------------------------------------------% c | Compute the Ritz vectors. Transform the wanted | c | eigenvectors of the symmetric tridiagonal H by | c | the Lanczos basis matrix V. | c %------------------------------------------------% c if (rvec .and. howmny .eq. 'A') then c c %----------------------------------------------------------% c | Compute the QR factorization of the matrix representing | c | the wanted invariant subspace located in the first NCONV | c | columns of workl(iq,ldq). | c %----------------------------------------------------------% c call dgeqr2 (ncv, nconv , workl(iq) , & ldq, workl(iw+ncv), workl(ihb), & ierr) c c %--------------------------------------------------------% c | * Postmultiply V by Q. | c | * Copy the first NCONV columns of VQ into Z. | c | The N by NCONV matrix Z is now a matrix representation | c | of the approximate invariant subspace associated with | c | the Ritz values in workl(ihd). | c %--------------------------------------------------------% c call dorm2r ('Right', 'Notranspose', n , & ncv , nconv , workl(iq), & ldq , workl(iw+ncv), v , & ldv , workd(n+1) , ierr) call dlacpy ('All', n, nconv, v(1,1), ldv, z, ldz) c c %-----------------------------------------------------% c | In order to compute the Ritz estimates for the Ritz | c | values in both systems, need the last row of the | c | eigenvector matrix. Remember, it`s in factored form | c %-----------------------------------------------------% c do 65 j = 1, ncv-1 workl(ihb+j-1) = zero 65 continue workl(ihb+ncv-1) = one call dorm2r ('Left', 'Transpose' , ncv , & ione , nconv , workl(iq) , & ldq , workl(iw+ncv), workl(ihb), & ncv , temp , ierr) c else if (rvec .and. howmny .eq. 'S') then c c Not yet implemented. See remark 2 above. c end if c if (type .eq. 'REGULR' .and. rvec) then c do 70 j=1, ncv workl(ihb+j-1) = rnorm * abs( workl(ihb+j-1) ) 70 continue c else if (type .ne. 'REGULR' .and. rvec) then c c %-------------------------------------------------% c | * Determine Ritz estimates of the theta. | c | If RVEC = .true. then compute Ritz estimates | c | of the theta. | c | If RVEC = .false. then copy Ritz estimates | c | as computed by dsaupd . | c | * Determine Ritz estimates of the lambda. | c %-------------------------------------------------% c call dscal (ncv, bnorm2, workl(ihb), 1) if (type .eq. 'SHIFTI') then c do 80 k=1, ncv workl(ihb+k-1) = abs( workl(ihb+k-1) ) & / workl(iw+k-1)**2 80 continue c else if (type .eq. 'BUCKLE') then c do 90 k=1, ncv workl(ihb+k-1) = sigma * abs( workl(ihb+k-1) ) & / (workl(iw+k-1)-one )**2 90 continue c else if (type .eq. 'CAYLEY') then c do 100 k=1, ncv workl(ihb+k-1) = abs( workl(ihb+k-1) & / workl(iw+k-1)*(workl(iw+k-1)-one) ) 100 continue c end if c end if c c c %-------------------------------------------------% c | Ritz vector purification step. Formally perform | c | one of inverse subspace iteration. Only used | c | for MODE = 3,4,5. See reference 7 | c %-------------------------------------------------% c if (rvec .and. (type .eq. 'SHIFTI' .or. type .eq. 'CAYLEY')) then c do 110 k=0, nconv-1 workl(iw+k) = workl(iq+k*ldq+ncv-1) & / workl(iw+k) 110 continue c else if (rvec .and. type .eq. 'BUCKLE') then c do 120 k=0, nconv-1 workl(iw+k) = workl(iq+k*ldq+ncv-1) & / (workl(iw+k)-one) 120 continue c end if c if (type .ne. 'REGULR') & call dger (n, nconv, one, resid, 1, workl(iw), 1, z, ldz) c 9000 continue c return c c %---------------% c | End of dseupd | c %---------------% c end c----------------------------------------------------------------------- c\BeginDoc c c\Name: dsesrt c c\Description: c Sort the array X in the order specified by WHICH and optionally c apply the permutation to the columns of the matrix A. c c\Usage: c call dsesrt c ( WHICH, APPLY, N, X, NA, A, LDA) c c\Arguments c WHICH Character*2. (Input) c 'LM' -> X is sorted into increasing order of magnitude. c 'SM' -> X is sorted into decreasing order of magnitude. c 'LA' -> X is sorted into increasing order of algebraic. c 'SA' -> X is sorted into decreasing order of algebraic. c c APPLY Logical. (Input) c APPLY = .TRUE. -> apply the sorted order to A. c APPLY = .FALSE. -> do not apply the sorted order to A. c c N Integer. (INPUT) c Dimension of the array X. c c X Double precision array of length N. (INPUT/OUTPUT) c The array to be sorted. c c NA Integer. (INPUT) c Number of rows of the matrix A. c c A Double precision array of length NA by N. (INPUT/OUTPUT) c c LDA Integer. (INPUT) c Leading dimension of A. c c\EndDoc c c----------------------------------------------------------------------- c c\BeginLib c c\Routines c dswap Level 1 BLAS that swaps the contents of two vectors. c c\Authors c Danny Sorensen Phuong Vu c Richard Lehoucq CRPC / Rice University c Dept. of Computational & Houston, Texas c Applied Mathematics c Rice University c Houston, Texas c c\Revision history: c 12/15/93: Version ' 2.1'. c Adapted from the sort routine in LANSO and c the ARPACK code dsortr c c\SCCS Information: @(#) c FILE: sesrt.F SID: 2.3 DATE OF SID: 4/19/96 RELEASE: 2 c c\EndLib c c----------------------------------------------------------------------- c subroutine dsesrt (which, apply, n, x, na, a, lda) c implicit none c c %------------------% c | Scalar Arguments | c %------------------% c character which*2 logical apply integer lda, n, na c c %-----------------% c | Array Arguments | c %-----------------% c Double precision & x(0:n-1), a(lda, 0:n-1) c c %---------------% c | Local Scalars | c %---------------% c integer i, igap, j Double precision & temp c c %----------------------% c | External Subroutines | c %----------------------% c external dswap c c %-----------------------% c | Executable Statements | c %-----------------------% c igap = n / 2 c if (which .eq. 'SA') then c c X is sorted into decreasing order of algebraic. c 10 continue if (igap .eq. 0) go to 9000 do 30 i = igap, n-1 j = i-igap 20 continue c if (j.lt.0) go to 30 c if (x(j).lt.x(j+igap)) then temp = x(j) x(j) = x(j+igap) x(j+igap) = temp if (apply) call dswap( na, a(1, j), 1, a(1,j+igap), 1) else go to 30 endif j = j-igap go to 20 30 continue igap = igap / 2 go to 10 c else if (which .eq. 'SM') then c c X is sorted into decreasing order of magnitude. c 40 continue if (igap .eq. 0) go to 9000 do 60 i = igap, n-1 j = i-igap 50 continue c if (j.lt.0) go to 60 c if (abs(x(j)).lt.abs(x(j+igap))) then temp = x(j) x(j) = x(j+igap) x(j+igap) = temp if (apply) call dswap( na, a(1, j), 1, a(1,j+igap), 1) else go to 60 endif j = j-igap go to 50 60 continue igap = igap / 2 go to 40 c else if (which .eq. 'LA') then c c X is sorted into increasing order of algebraic. c 70 continue if (igap .eq. 0) go to 9000 do 90 i = igap, n-1 j = i-igap 80 continue c if (j.lt.0) go to 90 c if (x(j).gt.x(j+igap)) then temp = x(j) x(j) = x(j+igap) x(j+igap) = temp if (apply) call dswap( na, a(1, j), 1, a(1,j+igap), 1) else go to 90 endif j = j-igap go to 80 90 continue igap = igap / 2 go to 70 c else if (which .eq. 'LM') then c c X is sorted into increasing order of magnitude. c 100 continue if (igap .eq. 0) go to 9000 do 120 i = igap, n-1 j = i-igap 110 continue c if (j.lt.0) go to 120 c if (abs(x(j)).gt.abs(x(j+igap))) then temp = x(j) x(j) = x(j+igap) x(j+igap) = temp if (apply) call dswap( na, a(1, j), 1, a(1,j+igap), 1) else go to 120 endif j = j-igap go to 110 120 continue igap = igap / 2 go to 100 end if c 9000 continue return c c %---------------% c | End of dsesrt | c %---------------% c end c----------------------------------------------------------------------- c\BeginDoc c c\Name: dsgets c c\Description: c Given the eigenvalues of the symmetric tridiagonal matrix H, c computes the NP shifts AMU that are zeros of the polynomial of c degree NP which filters out components of the unwanted eigenvectors c corresponding to the AMU's based on some given criteria. c c NOTE: This is called even in the case of user specified shifts in c order to sort the eigenvalues, and error bounds of H for later use. c c\Usage: c call dsgets c ( ISHIFT, WHICH, KEV, NP, RITZ, BOUNDS, SHIFTS ) c c\Arguments c ISHIFT Integer. (INPUT) c Method for selecting the implicit shifts at each iteration. c ISHIFT = 0: user specified shifts c ISHIFT = 1: exact shift with respect to the matrix H. c c WHICH Character*2. (INPUT) c Shift selection criteria. c 'LM' -> KEV eigenvalues of largest magnitude are retained. c 'SM' -> KEV eigenvalues of smallest magnitude are retained. c 'LA' -> KEV eigenvalues of largest value are retained. c 'SA' -> KEV eigenvalues of smallest value are retained. c 'BE' -> KEV eigenvalues, half from each end of the spectrum. c If KEV is odd, compute one more from the high end. c c KEV Integer. (INPUT) c KEV+NP is the size of the matrix H. c c NP Integer. (INPUT) c Number of implicit shifts to be computed. c c RITZ Double precision array of length KEV+NP. (INPUT/OUTPUT) c On INPUT, RITZ contains the eigenvalues of H. c On OUTPUT, RITZ are sorted so that the unwanted eigenvalues c are in the first NP locations and the wanted part is in c the last KEV locations. When exact shifts are selected, the c unwanted part corresponds to the shifts to be applied. c c BOUNDS Double precision array of length KEV+NP. (INPUT/OUTPUT) c Error bounds corresponding to the ordering in RITZ. c c SHIFTS Double precision array of length NP. (INPUT/OUTPUT) c On INPUT: contains the user specified shifts if ISHIFT = 0. c On OUTPUT: contains the shifts sorted into decreasing order c of magnitude with respect to the Ritz estimates contained in c BOUNDS. If ISHIFT = 0, SHIFTS is not modified on exit. c c\EndDoc c c----------------------------------------------------------------------- c c\BeginLib c c\Local variables: c xxxxxx real c c\Routines called: c dsortr ARPACK utility sorting routine. c ivout ARPACK utility routine that prints integers. c second ARPACK utility routine for timing. c dvout ARPACK utility routine that prints vectors. c dcopy Level 1 BLAS that copies one vector to another. c dswap Level 1 BLAS that swaps the contents of two vectors. c c\Author c Danny Sorensen Phuong Vu c Richard Lehoucq CRPC / Rice University c Dept. of Computational & Houston, Texas c Applied Mathematics c Rice University c Houston, Texas c c\Revision history: c xx/xx/93: Version ' 2.1' c c\SCCS Information: @(#) c FILE: sgets.F SID: 2.4 DATE OF SID: 4/19/96 RELEASE: 2 c c\Remarks c c\EndLib c c----------------------------------------------------------------------- c subroutine dsgets ( ishift, which, kev, np, ritz, bounds, shifts ) c implicit none c c %------------------% c | Scalar Arguments | c %------------------% c character which*2 integer ishift, kev, np c c %-----------------% c | Array Arguments | c %-----------------% c Double precision & bounds(kev+np), ritz(kev+np), shifts(np) c c %---------------% c | Local Scalars | c %---------------% c integer kevd2 logical dsgetstrue c c %----------------------% c | External Subroutines | c %----------------------% c external dswap, dcopy, dsortr c c %---------------------% c | Intrinsic Functions | c %---------------------% c intrinsic max, min c c %-----------------------% c | Executable Statements | c %-----------------------% c c %-------------------------------% c | Initialize timing statistics | c | & message level for debugging | c %-------------------------------% c dsgetstrue = .true. c if (which .eq. 'BE') then c c %-----------------------------------------------------% c | Both ends of the spectrum are requested. | c | Sort the eigenvalues into algebraically increasing | c | order first then swap high end of the spectrum next | c | to low end in appropriate locations. | c | NOTE: when np < floor(kev/2) be careful not to swap | c | overlapping locations. | c %-----------------------------------------------------% c call dsortr ('LA', dsgetstrue, kev+np, ritz, bounds) kevd2 = kev / 2 if ( kev .gt. 1 ) then call dswap ( min(kevd2,np), ritz(1), 1, & ritz( max(kevd2,np)+1 ), 1) call dswap ( min(kevd2,np), bounds(1), 1, & bounds( max(kevd2,np)+1 ), 1) end if c else c c %----------------------------------------------------% c | LM, SM, LA, SA case. | c | Sort the eigenvalues of H into the desired order | c | and apply the resulting order to BOUNDS. | c | The eigenvalues are sorted so that the wanted part | c | are always in the last KEV locations. | c %----------------------------------------------------% c call dsortr (which, dsgetstrue, kev+np, ritz, bounds) end if c if (ishift .eq. 1 .and. np .gt. 0) then c c %-------------------------------------------------------% c | Sort the unwanted Ritz values used as shifts so that | c | the ones with largest Ritz estimates are first. | c | This will tend to minimize the effects of the | c | forward instability of the iteration when the shifts | c | are applied in subroutine dsapps. | c %-------------------------------------------------------% c call dsortr ('SM', dsgetstrue, np, bounds, ritz) call dcopy (np, ritz, 1, shifts(1), 1) end if c return c c %---------------% c | End of dsgets | c %---------------% c end c----------------------------------------------------------------------- c\BeginDoc c c\Name: dsaupd c c\Description: c c Reverse communication interface for the Implicitly Restarted Arnoldi c Iteration. For symmetric problems this reduces to a variant of the Lanczos c method. This method has been designed to compute approximations to a c few eigenpairs of a linear operator OP that is real and symmetric c with respect to a real positive semi-definite symmetric matrix B, c i.e. c c B*OP = (OP`)*B. c c Another way to express this condition is c c < x,OPy > = < OPx,y > where < z,w > = z`Bw . c c In the standard eigenproblem B is the identity matrix. c ( A` denotes transpose of A) c c The computed approximate eigenvalues are called Ritz values and c the corresponding approximate eigenvectors are called Ritz vectors. c c dsaupd is usually called iteratively to solve one of the c following problems: c c Mode 1: A*x = lambda*x, A symmetric c ===> OP = A and B = I. c c Mode 2: A*x = lambda*M*x, A symmetric, M symmetric positive definite c ===> OP = inv[M]*A and B = M. c ===> (If M can be factored see remark 3 below) c c Mode 3: K*x = lambda*M*x, K symmetric, M symmetric positive semi-definite c ===> OP = (inv[K - sigma*M])*M and B = M. c ===> Shift-and-Invert mode c c Mode 4: K*x = lambda*KG*x, K symmetric positive semi-definite, c KG symmetric indefinite c ===> OP = (inv[K - sigma*KG])*K and B = K. c ===> Buckling mode c c Mode 5: A*x = lambda*M*x, A symmetric, M symmetric positive semi-definite c ===> OP = inv[A - sigma*M]*[A + sigma*M] and B = M. c ===> Cayley transformed mode c c NOTE: The action of w <- inv[A - sigma*M]*v or w <- inv[M]*v c should be accomplished either by a direct method c using a sparse matrix factorization and solving c c [A - sigma*M]*w = v or M*w = v, c c or through an iterative method for solving these c systems. If an iterative method is used, the c convergence test must be more stringent than c the accuracy requirements for the eigenvalue c approximations. c c\Usage: c call dsaupd c ( IDO, BMAT, N, WHICH, NEV, TOL, RESID, NCV, V, LDV, IPARAM, c IPNTR, WORKD, WORKL, LWORKL, INFO ) c c\Arguments c IDO Integer. (INPUT/OUTPUT) c Reverse communication flag. IDO must be zero on the first c call to dsaupd . IDO will be set internally to c indicate the type of operation to be performed. Control is c then given back to the calling routine which has the c responsibility to carry out the requested operation and call c dsaupd with the result. The operand is given in c WORKD(IPNTR(1)), the result must be put in WORKD(IPNTR(2)). c (If Mode = 2 see remark 5 below) c ------------------------------------------------------------- c IDO = 0: first call to the reverse communication interface c IDO = -1: compute Y = OP * X where c IPNTR(1) is the pointer into WORKD for X, c IPNTR(2) is the pointer into WORKD for Y. c This is for the initialization phase to force the c starting vector into the range of OP. c IDO = 1: compute Y = OP * X where c IPNTR(1) is the pointer into WORKD for X, c IPNTR(2) is the pointer into WORKD for Y. c In mode 3,4 and 5, the vector B * X is already c available in WORKD(ipntr(3)). It does not c need to be recomputed in forming OP * X. c IDO = 2: compute Y = B * X where c IPNTR(1) is the pointer into WORKD for X, c IPNTR(2) is the pointer into WORKD for Y. c IDO = 3: compute the IPARAM(8) shifts where c IPNTR(11) is the pointer into WORKL for c placing the shifts. See remark 6 below. c IDO = 99: done c ------------------------------------------------------------- c c BMAT Character*1. (INPUT) c BMAT specifies the type of the matrix B that defines the c semi-inner product for the operator OP. c B = 'I' -> standard eigenvalue problem A*x = lambda*x c B = 'G' -> generalized eigenvalue problem A*x = lambda*B*x c c N Integer. (INPUT) c Dimension of the eigenproblem. c c WHICH Character*2. (INPUT) c Specify which of the Ritz values of OP to compute. c c 'LA' - compute the NEV largest (algebraic) eigenvalues. c 'SA' - compute the NEV smallest (algebraic) eigenvalues. c 'LM' - compute the NEV largest (in magnitude) eigenvalues. c 'SM' - compute the NEV smallest (in magnitude) eigenvalues. c 'BE' - compute NEV eigenvalues, half from each end of the c spectrum. When NEV is odd, compute one more from the c high end than from the low end. c (see remark 1 below) c c NEV Integer. (INPUT) c Number of eigenvalues of OP to be computed. 0 < NEV < N. c c TOL Double precision scalar. (INPUT) c Stopping criterion: the relative accuracy of the Ritz value c is considered acceptable if BOUNDS(I) .LE. TOL*ABS(RITZ(I)). c If TOL .LE. 0. is passed a default is set: c DEFAULT = DLAMCH ('EPS') (machine precision as computed c by the LAPACK auxiliary subroutine DLAMCH ). c c RESID Double precision array of length N. (INPUT/OUTPUT) c On INPUT: c If INFO .EQ. 0, a random initial residual vector is used. c If INFO .NE. 0, RESID contains the initial residual vector, c possibly from a previous run. c On OUTPUT: c RESID contains the final residual vector. c c NCV Integer. (INPUT) c Number of columns of the matrix V (less than or equal to N). c This will indicate how many Lanczos vectors are generated c at each iteration. After the startup phase in which NEV c Lanczos vectors are generated, the algorithm generates c NCV-NEV Lanczos vectors at each subsequent update iteration. c Most of the cost in generating each Lanczos vector is in the c matrix-vector product OP*x. (See remark 4 below). c c V Double precision N by NCV array. (OUTPUT) c The NCV columns of V contain the Lanczos basis vectors. c c LDV Integer. (INPUT) c Leading dimension of V exactly as declared in the calling c program. c c IPARAM Integer array of length 11. (INPUT/OUTPUT) c IPARAM(1) = ISHIFT: method for selecting the implicit shifts. c The shifts selected at each iteration are used to restart c the Arnoldi iteration in an implicit fashion. c ------------------------------------------------------------- c ISHIFT = 0: the shifts are provided by the user via c reverse communication. The NCV eigenvalues of c the current tridiagonal matrix T are returned in c the part of WORKL array corresponding to RITZ. c See remark 6 below. c ISHIFT = 1: exact shifts with respect to the reduced c tridiagonal matrix T. This is equivalent to c restarting the iteration with a starting vector c that is a linear combination of Ritz vectors c associated with the "wanted" Ritz values. c ------------------------------------------------------------- c c IPARAM(2) = LEVEC c No longer referenced. See remark 2 below. c c IPARAM(3) = MXITER c On INPUT: maximum number of Arnoldi update iterations allowed. c On OUTPUT: actual number of Arnoldi update iterations taken. c c IPARAM(4) = NB: blocksize to be used in the recurrence. c The code currently works only for NB = 1. c c IPARAM(5) = NCONV: number of "converged" Ritz values. c This represents the number of Ritz values that satisfy c the convergence criterion. c c IPARAM(6) = IUPD c No longer referenced. Implicit restarting is ALWAYS used. c c IPARAM(7) = MODE c On INPUT determines what type of eigenproblem is being solved. c Must be 1,2,3,4,5; See under \Description of dsaupd for the c five modes available. c c IPARAM(8) = NP c When ido = 3 and the user provides shifts through reverse c communication (IPARAM(1)=0), dsaupd returns NP, the number c of shifts the user is to provide. 0 < NP <=NCV-NEV. See Remark c 6 below. c crc IPARAM(9) = NUMOP, IPARAM(10) = NUMOPB, IPARAM(11) = NUMREO, crc OUTPUT: NUMOP = total number of OP*x operations, crc NUMOPB = total number of B*x operations if BMAT='G', crc NUMREO = total number of steps of re-orthogonalization.c c c IPNTR Integer array of length 11. (OUTPUT) c Pointer to mark the starting locations in the WORKD and WORKL c arrays for matrices/vectors used by the Lanczos iteration. c ------------------------------------------------------------- c IPNTR(1): pointer to the current operand vector X in WORKD. c IPNTR(2): pointer to the current result vector Y in WORKD. c IPNTR(3): pointer to the vector B * X in WORKD when used in c the shift-and-invert mode. c IPNTR(4): pointer to the next available location in WORKL c that is untouched by the program. c IPNTR(5): pointer to the NCV by 2 tridiagonal matrix T in WORKL. c IPNTR(6): pointer to the NCV RITZ values array in WORKL. c IPNTR(7): pointer to the Ritz estimates in array WORKL associated c with the Ritz values located in RITZ in WORKL. c IPNTR(11): pointer to the NP shifts in WORKL. See Remark 6 below. c c Note: IPNTR(8:10) is only referenced by dseupd . See Remark 2. c IPNTR(8): pointer to the NCV RITZ values of the original system. c IPNTR(9): pointer to the NCV corresponding error bounds. c IPNTR(10): pointer to the NCV by NCV matrix of eigenvectors c of the tridiagonal matrix T. Only referenced by c dseupd if RVEC = .TRUE. See Remarks. c ------------------------------------------------------------- c c WORKD Double precision work array of length 3*N. (REVERSE COMMUNICATION) c Distributed array to be used in the basic Arnoldi iteration c for reverse communication. The user should not use WORKD c as temporary workspace during the iteration. Upon termination c WORKD(1:N) contains B*RESID(1:N). If the Ritz vectors are desired c subroutine dseupd uses this output. c See Data Distribution Note below. c c WORKL Double precision work array of length LWORKL. (OUTPUT/WORKSPACE) c Private (replicated) array on each PE or array allocated on c the front end. See Data Distribution Note below. c c LWORKL Integer. (INPUT) c LWORKL must be at least NCV**2 + 8*NCV . c c INFO Integer. (INPUT/OUTPUT) c If INFO .EQ. 0, a randomly initial residual vector is used. c If INFO .NE. 0, RESID contains the initial residual vector, c possibly from a previous run. c Error flag on output. c = 0: Normal exit. c = 1: Maximum number of iterations taken. c All possible eigenvalues of OP has been found. IPARAM(5) c returns the number of wanted converged Ritz values. c = 2: No longer an informational error. Deprecated starting c with release 2 of ARPACK. c = 3: No shifts could be applied during a cycle of the c Implicitly restarted Arnoldi iteration. One possibility c is to increase the size of NCV relative to NEV. c See remark 4 below. c = -1: N must be positive. c = -2: NEV must be positive. c = -3: NCV must be greater than NEV and less than or equal to N. c = -4: The maximum number of Arnoldi update iterations allowed c must be greater than zero. c = -5: WHICH must be one of 'LM', 'SM', 'LA', 'SA' or 'BE'. c = -6: BMAT must be one of 'I' or 'G'. c = -7: Length of private work array WORKL is not sufficient. c = -8: Error return from trid. eigenvalue calculation; c Informatinal error from LAPACK routine dsteqr . c = -9: Starting vector is zero. c = -10: IPARAM(7) must be 1,2,3,4,5. c = -11: IPARAM(7) = 1 and BMAT = 'G' are incompatable. c = -12: IPARAM(1) must be equal to 0 or 1. c = -13: NEV and WHICH = 'BE' are incompatable. c = -9999: Could not build an Arnoldi factorization. c IPARAM(5) returns the size of the current Arnoldi c factorization. The user is advised to check that c enough workspace and array storage has been allocated. c c c\Remarks c 1. The converged Ritz values are always returned in ascending c algebraic order. The computed Ritz values are approximate c eigenvalues of OP. The selection of WHICH should be made c with this in mind when Mode = 3,4,5. After convergence, c approximate eigenvalues of the original problem may be obtained c with the ARPACK subroutine dseupd . c c 2. If the Ritz vectors corresponding to the converged Ritz values c are needed, the user must call dseupd immediately following completion c of dsaupd . This is new starting with version 2.1 of ARPACK. c c 3. If M can be factored into a Cholesky factorization M = LL` c then Mode = 2 should not be selected. Instead one should use c Mode = 1 with OP = inv(L)*A*inv(L`). Appropriate triangular c linear systems should be solved with L and L` rather c than computing inverses. After convergence, an approximate c eigenvector z of the original problem is recovered by solving c L`z = x where x is a Ritz vector of OP. c c 4. At present there is no a-priori analysis to guide the selection c of NCV relative to NEV. The only formal requrement is that NCV > NEV. c However, it is recommended that NCV .ge. 2*NEV. If many problems of c the same type are to be solved, one should experiment with increasing c NCV while keeping NEV fixed for a given test problem. This will c usually decrease the required number of OP*x operations but it c also increases the work and storage required to maintain the orthogonal c basis vectors. The optimal "cross-over" with respect to CPU time c is problem dependent and must be determined empirically. c c 5. If IPARAM(7) = 2 then in the Reverse commuication interface the user c must do the following. When IDO = 1, Y = OP * X is to be computed. c When IPARAM(7) = 2 OP = inv(B)*A. After computing A*X the user c must overwrite X with A*X. Y is then the solution to the linear set c of equations B*Y = A*X. c c 6. When IPARAM(1) = 0, and IDO = 3, the user needs to provide the c NP = IPARAM(8) shifts in locations: c 1 WORKL(IPNTR(11)) c 2 WORKL(IPNTR(11)+1) c . c . c . c NP WORKL(IPNTR(11)+NP-1). c c The eigenvalues of the current tridiagonal matrix are located in c WORKL(IPNTR(6)) through WORKL(IPNTR(6)+NCV-1). They are in the c order defined by WHICH. The associated Ritz estimates are located in c WORKL(IPNTR(8)), WORKL(IPNTR(8)+1), ... , WORKL(IPNTR(8)+NCV-1). c c----------------------------------------------------------------------- c c\Data Distribution Note: c c Fortran-D syntax: c ================ c REAL RESID(N), V(LDV,NCV), WORKD(3*N), WORKL(LWORKL) c DECOMPOSE D1(N), D2(N,NCV) c ALIGN RESID(I) with D1(I) c ALIGN V(I,J) with D2(I,J) c ALIGN WORKD(I) with D1(I) range (1:N) c ALIGN WORKD(I) with D1(I-N) range (N+1:2*N) c ALIGN WORKD(I) with D1(I-2*N) range (2*N+1:3*N) c DISTRIBUTE D1(BLOCK), D2(BLOCK,:) c REPLICATED WORKL(LWORKL) c c Cray MPP syntax: c =============== c REAL RESID(N), V(LDV,NCV), WORKD(N,3), WORKL(LWORKL) c SHARED RESID(BLOCK), V(BLOCK,:), WORKD(BLOCK,:) c REPLICATED WORKL(LWORKL) c c c\BeginLib c c\References: c 1. D.C. Sorensen, "Implicit Application of Polynomial Filters in c a k-Step Arnoldi Method", SIAM J. Matr. Anal. Apps., 13 (1992), c pp 357-385. c 2. R.B. Lehoucq, "Analysis and Implementation of an Implicitly c Restarted Arnoldi Iteration", Rice University Technical Report c TR95-13, Department of Computational and Applied Mathematics. c 3. B.N. Parlett, "The Symmetric Eigenvalue Problem". Prentice-Hall, c 1980. c 4. B.N. Parlett, B. Nour-Omid, "Towards a Black Box Lanczos Program", c Computer Physics Communications, 53 (1989), pp 169-179. c 5. B. Nour-Omid, B.N. Parlett, T. Ericson, P.S. Jensen, "How to c Implement the Spectral Transformation", Math. Comp., 48 (1987), c pp 663-673. c 6. R.G. Grimes, J.G. Lewis and H.D. Simon, "A Shifted Block Lanczos c Algorithm for Solving Sparse Symmetric Generalized Eigenproblems", c SIAM J. Matr. Anal. Apps., January (1993). c 7. L. Reichel, W.B. Gragg, "Algorithm 686: FORTRAN Subroutines c for Updating the QR decomposition", ACM TOMS, December 1990, c Volume 16 Number 4, pp 369-377. c 8. R.B. Lehoucq, D.C. Sorensen, "Implementation of Some Spectral c Transformations in a k-Step Arnoldi Method". In Preparation. c c\Routines called: c dsaup2 ARPACK routine that implements the Implicitly Restarted c Arnoldi Iteration. c dstats ARPACK routine that initialize timing and other statistics c variables. c ivout ARPACK utility routine that prints integers. c second ARPACK utility routine for timing. c dvout ARPACK utility routine that prints vectors. c dlamch LAPACK routine that determines machine constants. c c\Authors c Danny Sorensen Phuong Vu c Richard Lehoucq CRPC / Rice University c Dept. of Computational & Houston, Texas c Applied Mathematics c Rice University c Houston, Texas c c\Revision history: c 12/15/93: Version ' 2.4' c c\SCCS Information: @(#) c FILE: saupd.F SID: 2.8 DATE OF SID: 04/10/01 RELEASE: 2 c c\Remarks c 1. None c c\EndLib c c----------------------------------------------------------------------- c subroutine dsaupd & ( ido, bmat, n, which, nev, tol, resid, ncv, v, ldv, iparam, & ipntr, workd, workl, lworkl, info ) c implicit none c c %------------------% c | Scalar Arguments | c %------------------% c character bmat*1, which*2 integer ido, info, ldv, lworkl, n, ncv, nev Double precision & tol c c %-----------------% c | Array Arguments | c %-----------------% c integer iparam(8), ipntr(11) Double precision & resid(n), v(ldv,ncv), workd(3*n), workl(lworkl) c c %------------% c | Parameters | c %------------% c Double precision & zero parameter (zero = 0.0D+0 ) c c %---------------% c | Local Scalars | c %---------------% c integer bounds, ierr, ih, iq, ishift, iw, & ldh, ldq, mxiter, mode, nb, & nev0, next, np, ritz, j save bounds, ierr, ih, iq, ishift, iw, & ldh, ldq, mxiter, mode, nb, & nev0, next, np, ritz c c %----------------------% c | External Subroutines | c %----------------------% c external dsaup2 c c %--------------------% c | External Functions | c %--------------------% c Double precision & dlamch external dlamch c c %-----------------------% c | Executable Statements | c %-----------------------% c if (ido .eq. 0) then c c %-------------------------------% c | Initialize timing statistics | c | & message level for debugging | c %-------------------------------% c ierr = 0 ishift = iparam(1) mxiter = iparam(3) nb = 1 c c %--------------------------------------------% c | Revision 2 performs only implicit restart. | c %--------------------------------------------% c mode = iparam(7) c c %----------------% c | Error checking | c %----------------% c if (n .le. 0) then ierr = -1 else if (nev .le. 0) then ierr = -2 else if (ncv .le. nev .or. ncv .gt. n) then ierr = -3 end if c c %----------------------------------------------% c | NP is the number of additional steps to | c | extend the length NEV Lanczos factorization. | c %----------------------------------------------% c np = ncv - nev c if (mxiter .le. 0) ierr = -4 if (which .ne. 'LM' .and. & which .ne. 'SM' .and. & which .ne. 'LA' .and. & which .ne. 'SA' .and. & which .ne. 'BE') ierr = -5 if (bmat .ne. 'I' .and. bmat .ne. 'G') ierr = -6 c if (lworkl .lt. ncv**2 + 8*ncv) ierr = -7 if (mode .lt. 1 .or. mode .gt. 5) then ierr = -10 else if (mode .eq. 1 .and. bmat .eq. 'G') then ierr = -11 else if (ishift .lt. 0 .or. ishift .gt. 1) then ierr = -12 else if (nev .eq. 1 .and. which .eq. 'BE') then ierr = -13 end if c c %------------% c | Error Exit | c %------------% c if (ierr .ne. 0) then info = ierr ido = 99 go to 9000 end if c c %------------------------% c | Set default parameters | c %------------------------% c if (nb .le. 0) nb = 1 if (tol .le. zero) tol = dlamch ('EpsMach') c c %----------------------------------------------% c | NP is the number of additional steps to | c | extend the length NEV Lanczos factorization. | c | NEV0 is the local variable designating the | c | size of the invariant subspace desired. | c %----------------------------------------------% c np = ncv - nev nev0 = nev c c %-----------------------------% c | Zero out internal workspace | c %-----------------------------% c do 10 j = 1, ncv**2 + 8*ncv workl(j) = zero 10 continue c c %-------------------------------------------------------% c | Pointer into WORKL for address of H, RITZ, BOUNDS, Q | c | etc... and the remaining workspace. | c | Also update pointer to be used on output. | c | Memory is laid out as follows: | c | workl(1:2*ncv) := generated tridiagonal matrix | c | workl(2*ncv+1:2*ncv+ncv) := ritz values | c | workl(3*ncv+1:3*ncv+ncv) := computed error bounds | c | workl(4*ncv+1:4*ncv+ncv*ncv) := rotation matrix Q | c | workl(4*ncv+ncv*ncv+1:7*ncv+ncv*ncv) := workspace | c %-------------------------------------------------------% c ldh = ncv ldq = ncv ih = 1 ritz = ih + 2*ldh bounds = ritz + ncv iq = bounds + ncv iw = iq + ncv**2 next = iw + 3*ncv c ipntr(4) = next ipntr(5) = ih ipntr(6) = ritz ipntr(7) = bounds ipntr(11) = iw end if c c %-------------------------------------------------------% c | Carry out the Implicitly restarted Lanczos Iteration. | c %-------------------------------------------------------% c call dsaup2 & ( ido, bmat, n, which, nev0, np, tol, resid, mode, & ishift, mxiter, v, ldv, workl(ih), ldh, workl(ritz), & workl(bounds), workl(iq), ldq, workl(iw), ipntr, workd, & info ) c c %--------------------------------------------------% c | ido .ne. 99 implies use of reverse communication | c | to compute operations involving OP or shifts. | c %--------------------------------------------------% c if (ido .eq. 3) iparam(8) = np if (ido .ne. 99) go to 9000 c iparam(3) = mxiter iparam(5) = np c c %------------------------------------% c | Exit if there was an informational | c | error within dsaup2 . | c %------------------------------------% c if (info .lt. 0) go to 9000 if (info .eq. 2) info = 3 c 9000 continue c return c c %---------------% c | End of dsaupd | c %---------------% c end c----------------------------------------------------------------------- c\BeginDoc c c\Name: dsaup2 c c\Description: c Intermediate level interface called by dsaupd. c c\Usage: c call dsaup2 c ( IDO, BMAT, N, WHICH, NEV, NP, TOL, RESID, MODE, IUPD, c ISHIFT, MXITER, V, LDV, H, LDH, RITZ, BOUNDS, Q, LDQ, WORKL, c IPNTR, WORKD, INFO ) c c\Arguments c c IDO, BMAT, N, WHICH, NEV, TOL, RESID: same as defined in dsaupd. c MODE, ISHIFT, MXITER: see the definition of IPARAM in dsaupd. c c NP Integer. (INPUT/OUTPUT) c Contains the number of implicit shifts to apply during c each Arnoldi/Lanczos iteration. c If ISHIFT=1, NP is adjusted dynamically at each iteration c to accelerate convergence and prevent stagnation. c This is also roughly equal to the number of matrix-vector c products (involving the operator OP) per Arnoldi iteration. c The logic for adjusting is contained within the current c subroutine. c If ISHIFT=0, NP is the number of shifts the user needs c to provide via reverse comunication. 0 < NP < NCV-NEV. c NP may be less than NCV-NEV since a leading block of the current c upper Tridiagonal matrix has split off and contains "unwanted" c Ritz values. c Upon termination of the IRA iteration, NP contains the number c of "converged" wanted Ritz values. c c IUPD Integer. (INPUT) c IUPD .EQ. 0: use explicit restart instead implicit update. c IUPD .NE. 0: use implicit update. c removed since unused argument c c V Double precision N by (NEV+NP) array. (INPUT/OUTPUT) c The Lanczos basis vectors. c c LDV Integer. (INPUT) c Leading dimension of V exactly as declared in the calling c program. c c H Double precision (NEV+NP) by 2 array. (OUTPUT) c H is used to store the generated symmetric tridiagonal matrix c The subdiagonal is stored in the first column of H starting c at H(2,1). The main diagonal is stored in the second column c of H starting at H(1,2). If dsaup2 converges store the c B-norm of the final residual vector in H(1,1). c c LDH Integer. (INPUT) c Leading dimension of H exactly as declared in the calling c program. c c RITZ Double precision array of length NEV+NP. (OUTPUT) c RITZ(1:NEV) contains the computed Ritz values of OP. c c BOUNDS Double precision array of length NEV+NP. (OUTPUT) c BOUNDS(1:NEV) contain the error bounds corresponding to RITZ. c c Q Double precision (NEV+NP) by (NEV+NP) array. (WORKSPACE) c Private (replicated) work array used to accumulate the c rotation in the shift application step. c c LDQ Integer. (INPUT) c Leading dimension of Q exactly as declared in the calling c program. c c WORKL Double precision array of length at least 3*(NEV+NP). (INPUT/WORKSPACE) c Private (replicated) array on each PE or array allocated on c the front end. It is used in the computation of the c tridiagonal eigenvalue problem, the calculation and c application of the shifts and convergence checking. c If ISHIFT .EQ. O and IDO .EQ. 3, the first NP locations c of WORKL are used in reverse communication to hold the user c supplied shifts. c c IPNTR Integer array of length 3. (OUTPUT) c Pointer to mark the starting locations in the WORKD for c vectors used by the Lanczos iteration. c ------------------------------------------------------------- c IPNTR(1): pointer to the current operand vector X. c IPNTR(2): pointer to the current result vector Y. c IPNTR(3): pointer to the vector B * X when used in one of c the spectral transformation modes. X is the current c operand. c ------------------------------------------------------------- c c WORKD Double precision work array of length 3*N. (REVERSE COMMUNICATION) c Distributed array to be used in the basic Lanczos iteration c for reverse communication. The user should not use WORKD c as temporary workspace during the iteration !!!!!!!!!! c See Data Distribution Note in dsaupd. c c INFO Integer. (INPUT/OUTPUT) c If INFO .EQ. 0, a randomly initial residual vector is used. c If INFO .NE. 0, RESID contains the initial residual vector, c possibly from a previous run. c Error flag on output. c = 0: Normal return. c = 1: All possible eigenvalues of OP has been found. c NP returns the size of the invariant subspace c spanning the operator OP. c = 2: No shifts could be applied. c = -8: Error return from trid. eigenvalue calculation; c This should never happen. c = -9: Starting vector is zero. c = -9999: Could not build an Lanczos factorization. c Size that was built in returned in NP. c c\EndDoc c c----------------------------------------------------------------------- c c\BeginLib c c\References: c 1. D.C. Sorensen, "Implicit Application of Polynomial Filters in c a k-Step Arnoldi Method", SIAM J. Matr. Anal. Apps., 13 (1992), c pp 357-385. c 2. R.B. Lehoucq, "Analysis and Implementation of an Implicitly c Restarted Arnoldi Iteration", Rice University Technical Report c TR95-13, Department of Computational and Applied Mathematics. c 3. B.N. Parlett, "The Symmetric Eigenvalue Problem". Prentice-Hall, c 1980. c 4. B.N. Parlett, B. Nour-Omid, "Towards a Black Box Lanczos Program", c Computer Physics Communications, 53 (1989), pp 169-179. c 5. B. Nour-Omid, B.N. Parlett, T. Ericson, P.S. Jensen, "How to c Implement the Spectral Transformation", Math. Comp., 48 (1987), c pp 663-673. c 6. R.G. Grimes, J.G. Lewis and H.D. Simon, "A Shifted Block Lanczos c Algorithm for Solving Sparse Symmetric Generalized Eigenproblems", c SIAM J. Matr. Anal. Apps., January (1993). c 7. L. Reichel, W.B. Gragg, "Algorithm 686: FORTRAN Subroutines c for Updating the QR decomposition", ACM TOMS, December 1990, c Volume 16 Number 4, pp 369-377. c c\Routines called: c dgetv0 ARPACK initial vector generation routine. c dsaitr ARPACK Lanczos factorization routine. c dsapps ARPACK application of implicit shifts routine. c dsconv ARPACK convergence of Ritz values routine. c dseigt ARPACK compute Ritz values and error bounds routine. c dsgets ARPACK reorder Ritz values and error bounds routine. c dsortr ARPACK sorting routine. c ivout ARPACK utility routine that prints integers. c second ARPACK utility routine for timing. c dvout ARPACK utility routine that prints vectors. c dlamch LAPACK routine that determines machine constants. c dcopy Level 1 BLAS that copies one vector to another. c ddot Level 1 BLAS that computes the scalar product of two vectors. c dnrm2 Level 1 BLAS that computes the norm of a vector. c dscal Level 1 BLAS that scales a vector. c dswap Level 1 BLAS that swaps two vectors. c c\Author c Danny Sorensen Phuong Vu c Richard Lehoucq CRPC / Rice University c Dept. of Computational & Houston, Texas c Applied Mathematics c Rice University c Houston, Texas c c\Revision history: c 12/15/93: Version ' 2.4' c xx/xx/95: Version ' 2.4'. (R.B. Lehoucq) c c\SCCS Information: @(#) c FILE: saup2.F SID: 2.7 DATE OF SID: 5/19/98 RELEASE: 2 c c\EndLib c c----------------------------------------------------------------------- c subroutine dsaup2 & ( ido, bmat, n, which, nev, np, tol, resid, mode, & ishift, mxiter, v, ldv, h, ldh, ritz, bounds, & q, ldq, workl, ipntr, workd, info ) implicit none c c %----------------------------------------------------% c | Include files for debugging and timing information | c %----------------------------------------------------% c c c %------------------% c | Scalar Arguments | c %------------------% c character bmat*1, which*2 integer ido, info, ishift, ldh, ldq, ldv, mxiter, & n, mode, nev, np Double precision & tol c c %-----------------% c | Array Arguments | c %-----------------% c integer ipntr(3) Double precision & bounds(nev+np), h(ldh,2), q(ldq,nev+np), resid(n), & ritz(nev+np), v(ldv,nev+np), workd(3*n), & workl(3*(nev+np)) c c %------------% c | Parameters | c %------------% c integer ione parameter (ione=1) integer & dsaupzero parameter (dsaupzero = 0) c c %---------------% c | Local Scalars | c %---------------% c character wprime*2 logical cnorm, getv0, initv, update, ushift, dsaup2true integer ierr, iter, j, kplusp, nconv, nevbef, nev0, & np0, nptemp, nevd2, nevm2, dsaup2zero Double precision & rnorm, temp, eps23 save cnorm, getv0, initv, update, ushift, & iter, kplusp, nconv, nev0, np0, & rnorm, eps23 c c %----------------------% c | External Subroutines | c %----------------------% c external dcopy, dgetv0, dsaitr, dscal, dsconv, dseigt, dsgets, & dsapps, dsortr, dswap c c %--------------------% c | External Functions | c %--------------------% c logical, external :: eqZERO Double precision & ddot, dnrm2, dlamch external ddot, dnrm2, dlamch c c %---------------------% c | Intrinsic Functions | c %---------------------% c intrinsic min c c %-----------------------% c | Executable Statements | c %-----------------------% c dsaup2true = .true. dsaup2zero = 0 c if (ido .eq. 0) then c c %---------------------------------% c | Set machine dependent constant. | c %---------------------------------% c eps23 = dlamch('Epsilon-Machine') eps23 = eps23**(2.0D+0/3.0D+0) c c %-------------------------------------% c | nev0 and np0 are integer variables | c | hold the initial values of NEV & NP | c %-------------------------------------% c nev0 = nev np0 = np c c %-------------------------------------% c | kplusp is the bound on the largest | c | Lanczos factorization built. | c | nconv is the current number of | c | "converged" eigenvlues. | c | iter is the counter on the current | c | iteration step. | c %-------------------------------------% c kplusp = nev0 + np0 nconv = 0 iter = 0 c c %--------------------------------------------% c | Set flags for computing the first NEV steps | c | of the Lanczos factorization. | c %--------------------------------------------% c getv0 = .true. update = .false. ushift = .false. cnorm = .false. c if (info .ne. 0) then c c %--------------------------------------------% c | User provides the initial residual vector. | c %--------------------------------------------% c initv = .true. info = 0 else initv = .false. end if end if c c %---------------------------------------------% c | Get a possibly random starting vector and | c | force it into the range of the operator OP. | c %---------------------------------------------% c c 10 continue c if (getv0) then call dgetv0 (ido, bmat, initv, n, ione, v, ldv, resid, rnorm, & ipntr, workd, info) c if (ido .ne. 99) go to 9000 c if (eqZERO(rnorm)) then c c %-----------------------------------------% c | The initial vector is zero. Error exit. | c %-----------------------------------------% c info = -9 go to 1200 end if getv0 = .false. ido = 0 end if c c %------------------------------------------------------------% c | Back from reverse communication: continue with update step | c %------------------------------------------------------------% c if (update) go to 20 c c %-------------------------------------------% c | Back from computing user specified shifts | c %-------------------------------------------% c if (ushift) go to 50 c c %-------------------------------------% c | Back from computing residual norm | c | at the end of the current iteration |dsaup2true c %-------------------------------------% c if (cnorm) go to 100 c c %----------------------------------------------------------% c | Compute the first NEV steps of the Lanczos factorization | c %----------------------------------------------------------% c call dsaitr (ido, bmat, n, dsaupzero, nev0, mode, resid, rnorm, & v, ldv, h, ldh, ipntr, workd, info) c c %---------------------------------------------------% c | ido .ne. 99 implies use of reverse communication | c | to compute operations involving OP and possibly B | c %---------------------------------------------------% c if (ido .ne. 99) go to 9000 c if (info .gt. 0) then c c %-----------------------------------------------------% c | dsaitr was unable to build an Lanczos factorization | c | of length NEV0. INFO is returned with the size of | c | the factorization built. Exit main loop. | c %-----------------------------------------------------% c np = info mxiter = iter info = -9999 go to 1200 end if c c %--------------------------------------------------------------% c | | c | M A I N LANCZOS I T E R A T I O N L O O P | c | Each iteration implicitly restarts the Lanczos | c | factorization in place. | c | | c %--------------------------------------------------------------% c 1000 continue c iter = iter + 1 c c %------------------------------------------------------------% c | Compute NP additional steps of the Lanczos factorization. | c %------------------------------------------------------------% c ido = 0 20 continue update = .true. c call dsaitr (ido, bmat, n, nev, np, mode, resid, rnorm, v, & ldv, h, ldh, ipntr, workd, info) c c %---------------------------------------------------% c | ido .ne. 99 implies use of reverse communication | c | to compute operations involving OP and possibly B | c %---------------------------------------------------% c if (ido .ne. 99) go to 9000 c if (info .gt. 0) then c c %-----------------------------------------------------% c | dsaitr was unable to build an Lanczos factorization | c | of length NEV0+NP0. INFO is returned with the size | c | of the factorization built. Exit main loop. | c %-----------------------------------------------------% c np = info mxiter = iter info = -9999 go to 1200 end if update = .false. c c %--------------------------------------------------------% c | Compute the eigenvalues and corresponding error bounds | c | of the current symmetric tridiagonal matrix. | c %--------------------------------------------------------% c call dseigt (rnorm, kplusp, h, ldh, ritz, bounds, workl, ierr) c if (ierr .ne. 0) then info = -8 go to 1200 end if c c %----------------------------------------------------% c | Make a copy of eigenvalues and corresponding error | c | bounds obtained from _seigt. | c %----------------------------------------------------% c call dcopy(kplusp, ritz, 1, workl(kplusp+1), 1) call dcopy(kplusp, bounds, 1, workl(2*kplusp+1), 1) c c %---------------------------------------------------% c | Select the wanted Ritz values and their bounds | c | to be used in the convergence test. | c | The selection is based on the requested number of | c | eigenvalues instead of the current NEV and NP to | c | prevent possible misconvergence. | c | * Wanted Ritz values := RITZ(NP+1:NEV+NP) | c | * Shifts := RITZ(1:NP) := WORKL(1:NP) | c %---------------------------------------------------% c nev = nev0 np = np0 call dsgets (ishift, which, nev, np, ritz, bounds, workl) c c %-------------------% c | Convergence test. | c %-------------------% c call dcopy (nev, bounds(np+1), 1, workl(np+1), 1) call dsconv (nev, ritz(np+1), workl(np+1), tol, nconv) c c %---------------------------------------------------------% c | Count the number of unwanted Ritz values that have zero | c | Ritz estimates. If any Ritz estimates are equal to zero | c | then a leading block of H of order equal to at least | c | the number of Ritz values with zero Ritz estimates has | c | split off. None of these Ritz values may be removed by | c | shifting. Decrease NP the number of shifts to apply. If | c | no shifts may be applied, then prepare to exit | c %---------------------------------------------------------% c nptemp = np do 30 j=1, nptemp if (eqZERO(bounds(j))) then np = np - 1 nev = nev + 1 end if 30 continue c if ( (nconv .ge. nev0) .or. & (iter .gt. mxiter) .or. & (np .eq. 0) ) then c c %------------------------------------------------% c | Prepare to exit. Put the converged Ritz values | c | and corresponding bounds in RITZ(1:NCONV) and | c | BOUNDS(1:NCONV) respectively. Then sort. Be | c | careful when NCONV > NP since we don't want to | c | swap overlapping locations. | c %------------------------------------------------% c if (which .eq. 'BE') then c c %-----------------------------------------------------% c | Both ends of the spectrum are requested. | c | Sort the eigenvalues into algebraically decreasing | c | order first then swap low end of the spectrum next | c | to high end in appropriate locations. | c | NOTE: when np < floor(nev/2) be careful not to swap | c | overlapping locations. | c %-----------------------------------------------------% c wprime = 'SA' call dsortr (wprime, dsaup2true, kplusp, ritz, bounds) nevd2 = nev0 / 2 nevm2 = nev0 - nevd2 if ( nev .gt. 1 ) then call dswap ( min(nevd2,np), ritz(nevm2+1), 1, & ritz( max(kplusp-nevd2+1,kplusp-np+1) ), 1) call dswap ( min(nevd2,np), bounds(nevm2+1), 1, & bounds( max(kplusp-nevd2+1,kplusp-np+1)), 1) end if c else c c %--------------------------------------------------% c | LM, SM, LA, SA case. | c | Sort the eigenvalues of H into the an order that | c | is opposite to WHICH, and apply the resulting | c | order to BOUNDS. The eigenvalues are sorted so | c | that the wanted part are always within the first | c | NEV locations. | c %--------------------------------------------------% c if (which .eq. 'LM') wprime = 'SM' if (which .eq. 'SM') wprime = 'LM' if (which .eq. 'LA') wprime = 'SA' if (which .eq. 'SA') wprime = 'LA' c call dsortr (wprime, dsaup2true, kplusp, ritz, bounds) c end if c c %--------------------------------------------------% c | Scale the Ritz estimate of each Ritz value | c | by 1 / max(eps23,magnitude of the Ritz value). | c %--------------------------------------------------% c do 35 j = 1, nev0 temp = max( eps23, abs(ritz(j)) ) bounds(j) = bounds(j)/temp 35 continue c c %----------------------------------------------------% c | Sort the Ritz values according to the scaled Ritz | c | esitmates. This will push all the converged ones | c | towards the front of ritzr, ritzi, bounds | c | (in the case when NCONV < NEV.) | c %----------------------------------------------------% c wprime = 'LA' call dsortr(wprime, dsaup2true, nev0, bounds, ritz) c c %----------------------------------------------% c | Scale the Ritz estimate back to its original | c | value. | c %----------------------------------------------% c do 40 j = 1, nev0 temp = max( eps23, abs(ritz(j)) ) bounds(j) = bounds(j)*temp 40 continue c c %--------------------------------------------------% c | Sort the "converged" Ritz values again so that | c | the "threshold" values and their associated Ritz | c | estimates appear at the appropriate position in | c | ritz and bound. | c %--------------------------------------------------% c if (which .eq. 'BE') then c c %------------------------------------------------% c | Sort the "converged" Ritz values in increasing | c | order. The "threshold" values are in the | c | middle. | c %------------------------------------------------% c wprime = 'LA' call dsortr(wprime, dsaup2true, nconv, ritz, bounds) c else c c %----------------------------------------------% c | In LM, SM, LA, SA case, sort the "converged" | c | Ritz values according to WHICH so that the | c | "threshold" value appears at the front of | c | ritz. | c %----------------------------------------------% call dsortr(which, dsaup2true, nconv, ritz, bounds) c end if c c %------------------------------------------% c | Use h( 1,1 ) as storage to communicate | c | rnorm to _seupd if needed | c %------------------------------------------% c h(1,1) = rnorm c c c %------------------------------------% c | Max iterations have been exceeded. | c %------------------------------------% c if (iter .gt. mxiter .and. nconv .lt. nev) info = 1 c c %---------------------% c | No shifts to apply. | c %---------------------% c if (np .eq. 0 .and. nconv .lt. nev0) info = 2 c np = nconv go to 1100 c else if (nconv .lt. nev .and. ishift .eq. 1) then c c %---------------------------------------------------% c | Do not have all the requested eigenvalues yet. | c | To prevent possible stagnation, adjust the number | c | of Ritz values and the shifts. | c %---------------------------------------------------% c nevbef = nev nev = nev + min (nconv, np/2) if (nev .eq. 1 .and. kplusp .ge. 6) then nev = kplusp / 2 else if (nev .eq. 1 .and. kplusp .gt. 2) then nev = 2 end if np = kplusp - nev c c %---------------------------------------% c | If the size of NEV was just increased | c | resort the eigenvalues. | c %---------------------------------------% c if (nevbef .lt. nev) & call dsgets (ishift, which, nev, np, ritz, bounds, & workl) c end if c if (ishift .eq. 0) then c c %-----------------------------------------------------% c | User specified shifts: reverse communication to | c | compute the shifts. They are returned in the first | c | NP locations of WORKL. | c %-----------------------------------------------------% c ushift = .true. ido = 3 go to 9000 end if c 50 continue c c %------------------------------------% c | Back from reverse communication; | c | User specified shifts are returned | c | in WORKL(1:*NP) | c %------------------------------------% c ushift = .false. c c c %---------------------------------------------------------% c | Move the NP shifts to the first NP locations of RITZ to | c | free up WORKL. This is for the non-exact shift case; | c | in the exact shift case, dsgets already handles this. | c %---------------------------------------------------------% c if (ishift .eq. 0) call dcopy (np, workl, 1, ritz(1), 1) cx if (ishift .eq. 0) call dcopy (np, workl, 1, ritz, 1) c c %---------------------------------------------------------% c | Apply the NP0 implicit shifts by QR bulge chasing. | c | Each shift is applied to the entire tridiagonal matrix. | c | The first 2*N locations of WORKD are used as workspace. | c | After dsapps is done, we have a Lanczos | c | factorization of length NEV. | c %---------------------------------------------------------% c call dsapps (n, nev, np, ritz, v, ldv, h, ldh, resid, q, ldq, & workd) c c %---------------------------------------------% c | Compute the B-norm of the updated residual. | c | Keep B*RESID in WORKD(1:N) to be used in | c | the first step of the next call to dsaitr. | c %---------------------------------------------% c cnorm = .true. c call second (t2) if (bmat .eq. 'G') then call dcopy (n, resid, 1, workd(n+1), 1) ipntr(1) = n + 1 ipntr(2) = 1 ido = 2 c c %----------------------------------% c | Exit in order to compute B*RESID | c %----------------------------------% c go to 9000 else if (bmat .eq. 'I') then call dcopy (n, resid, 1, workd(1), 1) end if c 100 continue c c %----------------------------------% c | Back from reverse communication; | c | WORKD(1:N) := B*RESID | c %----------------------------------% c if (bmat .eq. 'G') then rnorm = ddot (n, resid, 1, workd, 1) rnorm = sqrt(abs(rnorm)) else if (bmat .eq. 'I') then rnorm = dnrm2(n, resid, 1) end if cnorm = .false. c 130 continue c c go to 1000 c c %---------------------------------------------------------------% c | | c | E N D O F M A I N I T E R A T I O N L O O P | c | | c %---------------------------------------------------------------% c 1100 continue c mxiter = iter nev = nconv c 1200 continue ido = 99 c c %------------% c | Error exit | c %------------% c 9000 continue return c c %---------------% c | End of dsaup2 | c %---------------% c end c----------------------------------------------------------------------- c\BeginDoc c c\Name: dsconv c c\Description: c Convergence testing for the symmetric Arnoldi eigenvalue routine. c c\Usage: c call dsconv c ( N, RITZ, BOUNDS, TOL, NCONV ) c c\Arguments c N Integer. (INPUT) c Number of Ritz values to check for convergence. c c RITZ Double precision array of length N. (INPUT) c The Ritz values to be checked for convergence. c c BOUNDS Double precision array of length N. (INPUT) c Ritz estimates associated with the Ritz values in RITZ. c c TOL Double precision scalar. (INPUT) c Desired relative accuracy for a Ritz value to be considered c "converged". c c NCONV Integer scalar. (OUTPUT) c Number of "converged" Ritz values. c c\EndDoc c c----------------------------------------------------------------------- c c\BeginLib c c\Routines called: c second ARPACK utility routine for timing. c dlamch LAPACK routine that determines machine constants. c c\Author c Danny Sorensen Phuong Vu c Richard Lehoucq CRPC / Rice University c Dept. of Computational & Houston, Texas c Applied Mathematics c Rice University c Houston, Texas c c\SCCS Information: @(#) c FILE: sconv.F SID: 2.4 DATE OF SID: 4/19/96 RELEASE: 2 c c\Remarks c 1. Starting with version 2.4, this routine no longer uses the c Parlett strategy using the gap conditions. c c\EndLib c c----------------------------------------------------------------------- c subroutine dsconv (n, ritz, bounds, tol, nconv) c c %----------------------------------------------------% c | Include files for debugging and timing information | c %----------------------------------------------------% c implicit none c c %------------------% c | Scalar Arguments | c %------------------% c integer n, nconv Double precision & tol c c %-----------------% c | Array Arguments | c %-----------------% c Double precision & ritz(n), bounds(n) c c %---------------% c | Local Scalars | c %---------------% c integer i Double precision & temp, eps23 c c %-------------------% c | External routines | c %-------------------% c Double precision & dlamch external dlamch c %---------------------% c | Intrinsic Functions | c %---------------------% c intrinsic abs c c %-----------------------% c | Executable Statements | c %-----------------------% c c call second (t0) c eps23 = dlamch('Epsilon-Machine') eps23 = eps23**(2.0D+0 / 3.0D+0) c nconv = 0 do 10 i = 1, n c c %-----------------------------------------------------% c | The i-th Ritz value is considered "converged" | c | when: bounds(i) .le. TOL*max(eps23, abs(ritz(i))) | c %-----------------------------------------------------% c temp = max( eps23, abs(ritz(i)) ) if ( bounds(i) .le. tol*temp ) then nconv = nconv + 1 end if c 10 continue c c call second (t1) c return c c %---------------% c | End of dsconv | c %---------------% c end c----------------------------------------------------------------------- c\BeginDoc c c\Name: dsaitr c c\Description: c Reverse communication interface for applying NP additional steps to c a K step symmetric Arnoldi factorization. c c Input: OP*V_{k} - V_{k}*H = r_{k}*e_{k}^T c c with (V_{k}^T)*B*V_{k} = I, (V_{k}^T)*B*r_{k} = 0. c c Output: OP*V_{k+p} - V_{k+p}*H = r_{k+p}*e_{k+p}^T c c with (V_{k+p}^T)*B*V_{k+p} = I, (V_{k+p}^T)*B*r_{k+p} = 0. c c where OP and B are as in dsaupd. The B-norm of r_{k+p} is also c computed and returned. c c\Usage: c call dsaitr c ( IDO, BMAT, N, K, NP, MODE, RESID, RNORM, V, LDV, H, LDH, c IPNTR, WORKD, INFO ) c c\Arguments c IDO Integer. (INPUT/OUTPUT) c Reverse communication flag. c ------------------------------------------------------------- c IDO = 0: first call to the reverse communication interface c IDO = -1: compute Y = OP * X where c IPNTR(1) is the pointer into WORK for X, c IPNTR(2) is the pointer into WORK for Y. c This is for the restart phase to force the new c starting vector into the range of OP. c IDO = 1: compute Y = OP * X where c IPNTR(1) is the pointer into WORK for X, c IPNTR(2) is the pointer into WORK for Y, c IPNTR(3) is the pointer into WORK for B * X. c IDO = 2: compute Y = B * X where c IPNTR(1) is the pointer into WORK for X, c IPNTR(2) is the pointer into WORK for Y. c IDO = 99: done c ------------------------------------------------------------- c When the routine is used in the "shift-and-invert" mode, the c vector B * Q is already available and does not need to be c recomputed in forming OP * Q. c c BMAT Character*1. (INPUT) c BMAT specifies the type of matrix B that defines the c semi-inner product for the operator OP. See dsaupd. c B = 'I' -> standard eigenvalue problem A*x = lambda*x c B = 'G' -> generalized eigenvalue problem A*x = lambda*M*x c c N Integer. (INPUT) c Dimension of the eigenproblem. c c K Integer. (INPUT) c Current order of H and the number of columns of V. c c NP Integer. (INPUT) c Number of additional Arnoldi steps to take. c c MODE Integer. (INPUT) c Signifies which form for "OP". If MODE=2 then c a reduction in the number of B matrix vector multiplies c is possible since the B-norm of OP*x is equivalent to c the inv(B)-norm of A*x. c c RESID Double precision array of length N. (INPUT/OUTPUT) c On INPUT: RESID contains the residual vector r_{k}. c On OUTPUT: RESID contains the residual vector r_{k+p}. c c RNORM Double precision scalar. (INPUT/OUTPUT) c On INPUT the B-norm of r_{k}. c On OUTPUT the B-norm of the updated residual r_{k+p}. c c V Double precision N by K+NP array. (INPUT/OUTPUT) c On INPUT: V contains the Arnoldi vectors in the first K c columns. c On OUTPUT: V contains the new NP Arnoldi vectors in the next c NP columns. The first K columns are unchanged. c c LDV Integer. (INPUT) c Leading dimension of V exactly as declared in the calling c program. c c H Double precision (K+NP) by 2 array. (INPUT/OUTPUT) c H is used to store the generated symmetric tridiagonal matrix c with the subdiagonal in the first column starting at H(2,1) c and the main diagonal in the second column. c c LDH Integer. (INPUT) c Leading dimension of H exactly as declared in the calling c program. c c IPNTR Integer array of length 3. (OUTPUT) c Pointer to mark the starting locations in the WORK for c vectors used by the Arnoldi iteration. c ------------------------------------------------------------- c IPNTR(1): pointer to the current operand vector X. c IPNTR(2): pointer to the current result vector Y. c IPNTR(3): pointer to the vector B * X when used in the c shift-and-invert mode. X is the current operand. c ------------------------------------------------------------- c c WORKD Double precision work array of length 3*N. (REVERSE COMMUNICATION) c Distributed array to be used in the basic Arnoldi iteration c for reverse communication. The calling program should not c use WORKD as temporary workspace during the iteration !!!!!! c On INPUT, WORKD(1:N) = B*RESID where RESID is associated c with the K step Arnoldi factorization. Used to save some c computation at the first step. c On OUTPUT, WORKD(1:N) = B*RESID where RESID is associated c with the K+NP step Arnoldi factorization. c c INFO Integer. (OUTPUT) c = 0: Normal exit. c > 0: Size of an invariant subspace of OP is found that is c less than K + NP. c c\EndDoc c c----------------------------------------------------------------------- c c\BeginLib c c\Local variables: c xxxxxx real c c\Routines called: c dgetv0 ARPACK routine to generate the initial vector. c ivout ARPACK utility routine that prints integers. c dmout ARPACK utility routine that prints matrices. c dvout ARPACK utility routine that prints vectors. c dlamch LAPACK routine that determines machine constants. c dlascl LAPACK routine for careful scaling of a matrix. c dgemv Level 2 BLAS routine for matrix vector multiplication. c daxpy Level 1 BLAS that computes a vector triad. c dscal Level 1 BLAS that scales a vector. c dcopy Level 1 BLAS that copies one vector to another . c ddot Level 1 BLAS that computes the scalar product of two vectors. c dnrm2 Level 1 BLAS that computes the norm of a vector. c c\Author c Danny Sorensen Phuong Vu c Richard Lehoucq CRPC / Rice University c Dept. of Computational & Houston, Texas c Applied Mathematics c Rice University c Houston, Texas c c\Revision history: c xx/xx/93: Version ' 2.4' c c\SCCS Information: @(#) c FILE: saitr.F SID: 2.6 DATE OF SID: 8/28/96 RELEASE: 2 c c\Remarks c The algorithm implemented is: c c restart = .false. c Given V_{k} = [v_{1}, ..., v_{k}], r_{k}; c r_{k} contains the initial residual vector even for k = 0; c Also assume that rnorm = || B*r_{k} || and B*r_{k} are already c computed by the calling program. c c betaj = rnorm ; p_{k+1} = B*r_{k} ; c For j = k+1, ..., k+np Do c 1) if ( betaj < tol ) stop or restart depending on j. c if ( restart ) generate a new starting vector. c 2) v_{j} = r(j-1)/betaj; V_{j} = [V_{j-1}, v_{j}]; c p_{j} = p_{j}/betaj c 3) r_{j} = OP*v_{j} where OP is defined as in dsaupd c For shift-invert mode p_{j} = B*v_{j} is already available. c wnorm = || OP*v_{j} || c 4) Compute the j-th step residual vector. c w_{j} = V_{j}^T * B * OP * v_{j} c r_{j} = OP*v_{j} - V_{j} * w_{j} c alphaj <- j-th component of w_{j} c rnorm = || r_{j} || c betaj+1 = rnorm c If (rnorm > 0.717*wnorm) accept step and go back to 1) c 5) Re-orthogonalization step: c s = V_{j}'*B*r_{j} c r_{j} = r_{j} - V_{j}*s; rnorm1 = || r_{j} || c alphaj = alphaj + s_{j}; c 6) Iterative refinement step: c If (rnorm1 > 0.717*rnorm) then c rnorm = rnorm1 c accept step and go back to 1) c Else c rnorm = rnorm1 c If this is the first time in step 6), go to 5) c Else r_{j} lies in the span of V_{j} numerically. c Set r_{j} = 0 and rnorm = 0; go to 1) c EndIf c End Do c c\EndLib c c----------------------------------------------------------------------- c subroutine dsaitr & (ido, bmat, n, k, np, mode, resid, rnorm, v, ldv, h, ldh, & ipntr, workd, info) implicit none c c %------------------% c | Scalar Arguments | c %------------------% c character bmat*1 integer ido, info, k, ldh, ldv, n, mode, np Double precision & rnorm c c %-----------------% c | Array Arguments | c %-----------------% c integer ipntr(3) Double precision & h(ldh,2), resid(n), v(ldv,k+np), workd(3*n) c c %------------% c | Parameters | c %------------% c Double precision & one, zero parameter (one = 1.0D+0, zero = 0.0D+0) logical fls parameter (fls = .false.) c c %---------------% c | Local Scalars | c %---------------% c logical first, orth1, orth2, rstart, step3, step4 integer i, ierr, ipj, irj, ivj, iter, itry, j, & infol, jj Double precision & rnorm1, wnorm, safmin, temp1 save orth1, orth2, rstart, step3, step4, & ierr, ipj, irj, ivj, iter, itry, j, & rnorm1, safmin, wnorm c c %-----------------------% c | Local Array Arguments | c %-----------------------% c cs Double precision cs & xtemp(2) c c %----------------------% c | External Subroutines | c %----------------------% c external daxpy, dcopy, dscal, dgemv, dgetv0, & dlascl c c %--------------------% c | External Functions | c %--------------------% c Double precision & ddot, dnrm2, dlamch external ddot, dnrm2, dlamch c c %-----------------% c | Data statements | c %-----------------% c data first / .true. / c c %-----------------------% c | Executable Statements | c %-----------------------% c if (first) then first = .false. c c %--------------------------------% c | safmin = safe minimum is such | c | that 1/sfmin does not overflow | c %--------------------------------% c safmin = dlamch('safmin') end if c if (ido .eq. 0) then c c %-------------------------------% c | Initialize timing statistics | c | & message level for debugging | c %-------------------------------% c c call second (t0) c c %------------------------------% c | Initial call to this routine | c %------------------------------% c info = 0 step3 = .false. step4 = .false. rstart = .false. orth1 = .false. orth2 = .false. c c %--------------------------------% c | Pointer to the current step of | c | the factorization to build | c %--------------------------------% c j = k + 1 c c %------------------------------------------% c | Pointers used for reverse communication | c | when using WORKD. | c %------------------------------------------% c ipj = 1 irj = ipj + n ivj = irj + n end if c c %-------------------------------------------------% c | When in reverse communication mode one of: | c | STEP3, STEP4, ORTH1, ORTH2, RSTART | c | will be .true. | c | STEP3: return from computing OP*v_{j}. | c | STEP4: return from computing B-norm of OP*v_{j} | c | ORTH1: return from computing B-norm of r_{j+1} | c | ORTH2: return from computing B-norm of | c | correction to the residual vector. | c | RSTART: return from OP computations needed by | c | dgetv0. | c %-------------------------------------------------% c if (step3) go to 50 if (step4) go to 60 if (orth1) go to 70 if (orth2) go to 90 if (rstart) go to 30 c c %------------------------------% c | Else this is the first step. | c %------------------------------% c c %--------------------------------------------------------------% c | | c | A R N O L D I I T E R A T I O N L O O P | c | | c | Note: B*r_{j-1} is already in WORKD(1:N)=WORKD(IPJ:IPJ+N-1) | c %--------------------------------------------------------------% c 1000 continue c c %---------------------------------------------------------% c | Check for exact zero. Equivalent to determing whether a | c | j-step Arnoldi factorization is present. | c %---------------------------------------------------------% c if (rnorm .gt. zero) go to 40 c c %---------------------------------------------------% c | Invariant subspace found, generate a new starting | c | vector which is orthogonal to the current Arnoldi | c | basis and continue the iteration. | c %---------------------------------------------------% c c %---------------------------------------------% c | ITRY is the loop variable that controls the | c | maximum amount of times that a restart is | c | attempted. NRSTRT is used by stat.h | c %---------------------------------------------% c itry = 1 20 continue rstart = .true. ido = 0 30 continue c c %--------------------------------------% c | If in reverse communication mode and | c | RSTART = .true. flow returns here. | c %--------------------------------------% c call dgetv0 (ido, bmat, fls, n, j, v, ldv, & resid, rnorm, ipntr, workd, ierr) if (ido .ne. 99) go to 9000 if (ierr .lt. 0) then itry = itry + 1 if (itry .le. 3) go to 20 c c %------------------------------------------------% c | Give up after several restart attempts. | c | Set INFO to the size of the invariant subspace | c | which spans OP and exit. | c %------------------------------------------------% c info = j - 1 ido = 99 go to 9000 end if c 40 continue c c %---------------------------------------------------------% c | STEP 2: v_{j} = r_{j-1}/rnorm and p_{j} = p_{j}/rnorm | c | Note that p_{j} = B*r_{j-1}. In order to avoid overflow | c | when reciprocating a small RNORM, test against lower | c | machine bound. | c %---------------------------------------------------------% c call dcopy (n, resid, 1, v(1,j), 1) if (rnorm .ge. safmin) then temp1 = one / rnorm call dscal (n, temp1, v(1,j), 1) call dscal (n, temp1, workd(ipj), 1) else c c %-----------------------------------------% c | To scale both v_{j} and p_{j} carefully | c | use LAPACK routine SLASCL | c %-----------------------------------------% c call dlascl ('General', i, i, rnorm, one, n, 1, & v(1,j), n, infol) call dlascl ('General', i, i, rnorm, one, n, 1, & workd(ipj), n, infol) end if c c %------------------------------------------------------% c | STEP 3: r_{j} = OP*v_{j}; Note that p_{j} = B*v_{j} | c | Note that this is not quite yet r_{j}. See STEP 4 | c %------------------------------------------------------% c step3 = .true. call dcopy (n, v(1,j), 1, workd(ivj), 1) ipntr(1) = ivj ipntr(2) = irj ipntr(3) = ipj ido = 1 c c %-----------------------------------% c | Exit in order to compute OP*v_{j} | c %-----------------------------------% c go to 9000 50 continue c c %-----------------------------------% c | Back from reverse communication; | c | WORKD(IRJ:IRJ+N-1) := OP*v_{j}. | c %-----------------------------------% c step3 = .false. c c %------------------------------------------% c | Put another copy of OP*v_{j} into RESID. | c %------------------------------------------% c call dcopy (n, workd(irj), 1, resid(1), 1) c c %-------------------------------------------% c | STEP 4: Finish extending the symmetric | c | Arnoldi to length j. If MODE = 2 | c | then B*OP = B*inv(B)*A = A and | c | we don't need to compute B*OP. | c | NOTE: If MODE = 2 WORKD(IVJ:IVJ+N-1) is | c | assumed to have A*v_{j}. | c %-------------------------------------------% c if (mode .eq. 2) go to 65 c call second (t2) if (bmat .eq. 'G') then step4 = .true. ipntr(1) = irj ipntr(2) = ipj ido = 2 c c %-------------------------------------% c | Exit in order to compute B*OP*v_{j} | c %-------------------------------------% c go to 9000 else if (bmat .eq. 'I') then call dcopy(n, resid, 1 , workd(ipj), 1) end if 60 continue c c %-----------------------------------% c | Back from reverse communication; | c | WORKD(IPJ:IPJ+N-1) := B*OP*v_{j}. | c %-----------------------------------% c step4 = .false. c c %-------------------------------------% c | The following is needed for STEP 5. | c | Compute the B-norm of OP*v_{j}. | c %-------------------------------------% c 65 continue if (mode .eq. 2) then c c %----------------------------------% c | Note that the B-norm of OP*v_{j} | c | is the inv(B)-norm of A*v_{j}. | c %----------------------------------% c wnorm = ddot (n, resid, 1, workd(ivj), 1) wnorm = sqrt(abs(wnorm)) else if (bmat .eq. 'G') then wnorm = ddot (n, resid, 1, workd(ipj), 1) wnorm = sqrt(abs(wnorm)) else if (bmat .eq. 'I') then wnorm = dnrm2(n, resid, 1) end if c c %-----------------------------------------% c | Compute the j-th residual corresponding | c | to the j step factorization. | c | Use Classical Gram Schmidt and compute: | c | w_{j} <- V_{j}^T * B * OP * v_{j} | c | r_{j} <- OP*v_{j} - V_{j} * w_{j} | c %-----------------------------------------% c c c %------------------------------------------% c | Compute the j Fourier coefficients w_{j} | c | WORKD(IPJ:IPJ+N-1) contains B*OP*v_{j}. | c %------------------------------------------% c if (mode .ne. 2 ) then call dgemv('T', n, j, one, v, ldv, workd(ipj), 1, zero, & workd(irj), 1) else if (mode .eq. 2) then call dgemv('T', n, j, one, v, ldv, workd(ivj), 1, zero, & workd(irj), 1) end if c c %--------------------------------------% c | Orthgonalize r_{j} against V_{j}. | c | RESID contains OP*v_{j}. See STEP 3. | c %--------------------------------------% c call dgemv('N', n, j, -one, v, ldv, workd(irj), 1, one, & resid(1), 1) c c %--------------------------------------% c | Extend H to have j rows and columns. | c %--------------------------------------% c h(j,2) = workd(irj + j - 1) if (j .eq. 1 .or. rstart) then h(j,1) = zero else h(j,1) = rnorm end if c call second (t4) c orth1 = .true. iter = 0 c c call second (t2) if (bmat .eq. 'G') then call dcopy (n, resid, 1, workd(irj), 1) ipntr(1) = irj ipntr(2) = ipj ido = 2 c c %----------------------------------% c | Exit in order to compute B*r_{j} | c %----------------------------------% c go to 9000 else if (bmat .eq. 'I') then call dcopy (n, resid, 1, workd(ipj), 1) end if 70 continue c c %---------------------------------------------------% c | Back from reverse communication if ORTH1 = .true. | c | WORKD(IPJ:IPJ+N-1) := B*r_{j}. | c %---------------------------------------------------% c orth1 = .false. c c %------------------------------% c | Compute the B-norm of r_{j}. | c %------------------------------% c if (bmat .eq. 'G') then rnorm = ddot (n, resid, 1, workd(ipj), 1) rnorm = sqrt(abs(rnorm)) else if (bmat .eq. 'I') then rnorm = dnrm2(n, resid, 1) end if c c %-----------------------------------------------------------% c | STEP 5: Re-orthogonalization / Iterative refinement phase | c | Maximum NITER_ITREF tries. | c | | c | s = V_{j}^T * B * r_{j} | c | r_{j} = r_{j} - V_{j}*s | c | alphaj = alphaj + s_{j} | c | | c | The stopping criteria used for iterative refinement is | c | discussed in Parlett's book SEP, page 107 and in Gragg & | c | Reichel ACM TOMS paper; Algorithm 686, Dec. 1990. | c | Determine if we need to correct the residual. The goal is | c | to enforce ||v(:,1:j)^T * r_{j}|| .le. eps * || r_{j} || | c %-----------------------------------------------------------% c if (rnorm .gt. 0.717*wnorm) go to 100 c c %---------------------------------------------------% c | Enter the Iterative refinement phase. If further | c | refinement is necessary, loop back here. The loop | c | variable is ITER. Perform a step of Classical | c | Gram-Schmidt using all the Arnoldi vectors V_{j} | c %---------------------------------------------------% c 80 continue c c %----------------------------------------------------% c | Compute V_{j}^T * B * r_{j}. | c | WORKD(IRJ:IRJ+J-1) = v(:,1:J)'*WORKD(IPJ:IPJ+N-1). | c %----------------------------------------------------% c call dgemv ('T', n, j, one, v, ldv, workd(ipj), 1, & zero, workd(irj), 1) c c %----------------------------------------------% c | Compute the correction to the residual: | c | r_{j} = r_{j} - V_{j} * WORKD(IRJ:IRJ+J-1). | c | The correction to H is v(:,1:J)*H(1:J,1:J) + | c | v(:,1:J)*WORKD(IRJ:IRJ+J-1)*e'_j, but only | c | H(j,j) is updated. | c %----------------------------------------------% c call dgemv ('N', n, j, -one, v, ldv, workd(irj), 1, & one, resid(1), 1) c if (j .eq. 1 .or. rstart) h(j,1) = zero h(j,2) = h(j,2) + workd(irj + j - 1) c orth2 = .true. c call second (t2) if (bmat .eq. 'G') then call dcopy (n, resid, 1, workd(irj), 1) ipntr(1) = irj ipntr(2) = ipj ido = 2 c c %-----------------------------------% c | Exit in order to compute B*r_{j}. | c | r_{j} is the corrected residual. | c %-----------------------------------% c go to 9000 else if (bmat .eq. 'I') then call dcopy (n, resid, 1, workd(ipj), 1) end if 90 continue c c %---------------------------------------------------% c | Back from reverse communication if ORTH2 = .true. | c %---------------------------------------------------% c c %-----------------------------------------------------% c | Compute the B-norm of the corrected residual r_{j}. | c %-----------------------------------------------------% c if (bmat .eq. 'G') then rnorm1 = ddot (n, resid, 1, workd(ipj), 1) rnorm1 = sqrt(abs(rnorm1)) else if (bmat .eq. 'I') then rnorm1 = dnrm2(n, resid, 1) end if c c %-----------------------------------------% c | Determine if we need to perform another | c | step of re-orthogonalization. | c %-----------------------------------------% c if (rnorm1 .gt. 0.717*rnorm) then c c %--------------------------------% c | No need for further refinement | c %--------------------------------% c rnorm = rnorm1 c else c c %-------------------------------------------% c | Another step of iterative refinement step | c | is required. NITREF is used by stat.h | c %-------------------------------------------% c rnorm = rnorm1 iter = iter + 1 if (iter .le. 1) go to 80 c c %-------------------------------------------------% c | Otherwise RESID is numerically in the span of V | c %-------------------------------------------------% c do 95 jj = 1, n resid(jj) = zero 95 continue rnorm = zero end if c c %----------------------------------------------% c | Branch here directly if iterative refinement | c | wasn't necessary or after at most NITER_REF | c | steps of iterative refinement. | c %----------------------------------------------% c 100 continue c rstart = .false. orth2 = .false. c c %----------------------------------------------------------% c | Make sure the last off-diagonal element is non negative | c | If not perform a similarity transformation on H(1:j,1:j) | c | and scale v(:,j) by -1. | c %----------------------------------------------------------% c if (h(j,1) .lt. zero) then h(j,1) = -h(j,1) if ( j .lt. k+np) then call dscal(n, -one, v(1,j+1), 1) else call dscal(n, -one, resid(1), 1) end if end if c c %------------------------------------% c | STEP 6: Update j = j+1; Continue | c %------------------------------------% c j = j + 1 if (j .gt. k+np) then ido = 99 c go to 9000 end if c c %--------------------------------------------------------% c | Loop back to extend the factorization by another step. | c %--------------------------------------------------------% c go to 1000 c c %---------------------------------------------------------------% c | | c | E N D O F M A I N I T E R A T I O N L O O P | c | | c %---------------------------------------------------------------% c 9000 continue return c c %---------------% c | End of dsaitr | c %---------------% c end c----------------------------------------------------------------------- c\BeginDoc c c\Name: dsapps c c\Description: c Given the Arnoldi factorization c c A*V_{k} - V_{k}*H_{k} = r_{k+p}*e_{k+p}^T, c c apply NP shifts implicitly resulting in c c A*(V_{k}*Q) - (V_{k}*Q)*(Q^T* H_{k}*Q) = r_{k+p}*e_{k+p}^T * Q c c where Q is an orthogonal matrix of order KEV+NP. Q is the product of c rotations resulting from the NP bulge chasing sweeps. The updated Arnoldi c factorization becomes: c c A*VNEW_{k} - VNEW_{k}*HNEW_{k} = rnew_{k}*e_{k}^T. c c\Usage: c call dsapps c ( N, KEV, NP, SHIFT, V, LDV, H, LDH, RESID, Q, LDQ, WORKD ) c c\Arguments c N Integer. (INPUT) c Problem size, i.e. dimension of matrix A. c c KEV Integer. (INPUT) c INPUT: KEV+NP is the size of the input matrix H. c OUTPUT: KEV is the size of the updated matrix HNEW. c c NP Integer. (INPUT) c Number of implicit shifts to be applied. c c SHIFT Double precision array of length NP. (INPUT) c The shifts to be applied. c c V Double precision N by (KEV+NP) array. (INPUT/OUTPUT) c INPUT: V contains the current KEV+NP Arnoldi vectors. c OUTPUT: VNEW = V(1:n,1:KEV); the updated Arnoldi vectors c are in the first KEV columns of V. c c LDV Integer. (INPUT) c Leading dimension of V exactly as declared in the calling c program. c c H Double precision (KEV+NP) by 2 array. (INPUT/OUTPUT) c INPUT: H contains the symmetric tridiagonal matrix of the c Arnoldi factorization with the subdiagonal in the 1st column c starting at H(2,1) and the main diagonal in the 2nd column. c OUTPUT: H contains the updated tridiagonal matrix in the c KEV leading submatrix. c c LDH Integer. (INPUT) c Leading dimension of H exactly as declared in the calling c program. c c RESID Double precision array of length (N). (INPUT/OUTPUT) c INPUT: RESID contains the the residual vector r_{k+p}. c OUTPUT: RESID is the updated residual vector rnew_{k}. c c Q Double precision KEV+NP by KEV+NP work array. (WORKSPACE) c Work array used to accumulate the rotations during the bulge c chase sweep. c c LDQ Integer. (INPUT) c Leading dimension of Q exactly as declared in the calling c program. c c WORKD Double precision work array of length 2*N. (WORKSPACE) c Distributed array used in the application of the accumulated c orthogonal matrix Q. c c\EndDoc c c----------------------------------------------------------------------- c c\BeginLib c c\Local variables: c xxxxxx real c c\References: c 1. D.C. Sorensen, "Implicit Application of Polynomial Filters in c a k-Step Arnoldi Method", SIAM J. Matr. Anal. Apps., 13 (1992), c pp 357-385. c 2. R.B. Lehoucq, "Analysis and Implementation of an Implicitly c Restarted Arnoldi Iteration", Rice University Technical Report c TR95-13, Department of Computational and Applied Mathematics. c c\Routines called: c ivout ARPACK utility routine that prints integers. c second ARPACK utility routine for timing. c dvout ARPACK utility routine that prints vectors. c dlamch LAPACK routine that determines machine constants. c dlartg LAPACK Givens rotation construction routine. c dlacpy LAPACK matrix copy routine. c dlaset LAPACK matrix initialization routine. c dgemv Level 2 BLAS routine for matrix vector multiplication. c daxpy Level 1 BLAS that computes a vector triad. c dcopy Level 1 BLAS that copies one vector to another. c dscal Level 1 BLAS that scales a vector. c c\Author c Danny Sorensen Phuong Vu c Richard Lehoucq CRPC / Rice University c Dept. of Computational & Houston, Texas c Applied Mathematics c Rice University c Houston, Texas c c\Revision history: c 12/16/93: Version ' 2.4' c c\SCCS Information: @(#) c FILE: sapps.F SID: 2.6 DATE OF SID: 3/28/97 RELEASE: 2 c c\Remarks c 1. In this version, each shift is applied to all the subblocks of c the tridiagonal matrix H and not just to the submatrix that it c comes from. This routine assumes that the subdiagonal elements c of H that are stored in h(1:kev+np,1) are nonegative upon input c and enforce this condition upon output. This version incorporates c deflation. See code for documentation. c c\EndLib c c----------------------------------------------------------------------- c subroutine dsapps & ( n, kev, np, shift, v, ldv, h, ldh, resid, q, ldq, workd ) c c %----------------------------------------------------% c | Include files for debugging and timing information | c %----------------------------------------------------% c implicit none c c %------------------% c | Scalar Arguments | c %------------------% c integer kev, ldh, ldq, ldv, n, np c c %-----------------% c | Array Arguments | c %-----------------% c Double precision & h(ldh,2), q(ldq,kev+np), resid(n), shift(np), & v(ldv,kev+np), workd(2*n) c c %------------% c | Parameters | c %------------% c Double precision & one, zero parameter (one = 1.0D+0, zero = 0.0D+0) c c %---------------% c | Local Scalars | c %---------------% c integer i, iend, istart, itop, j, jj, kplusp logical first Double precision & a1, a2, a3, a4, big, c, epsmch, f, g, r, s save epsmch, first c c c %----------------------% c | External Subroutines | c %----------------------% c external daxpy, dcopy, dscal, dlacpy, dlartg, dlaset, & dgemv c c %--------------------% c | External Functions | c %--------------------% c Double precision & dlamch external dlamch c c %----------------------% c | Intrinsics Functions | c %----------------------% c intrinsic abs c c %----------------% c | Data statments | c %----------------% c data first / .true. / c c %-----------------------% c | Executable Statements | c %-----------------------% c if (first) then epsmch = dlamch('Epsilon-Machine') first = .false. end if itop = 1 c c %-------------------------------% c | Initialize timing statistics | c | & message level for debugging | c %-------------------------------% c kplusp = kev + np c c %----------------------------------------------% c | Initialize Q to the identity matrix of order | c | kplusp used to accumulate the rotations. | c %----------------------------------------------% c call dlaset ('All', kplusp, kplusp, zero, one, q, ldq) c c %----------------------------------------------% c | Quick return if there are no shifts to apply | c %----------------------------------------------% c if (np .eq. 0) go to 9000 c c %----------------------------------------------------------% c | Apply the np shifts implicitly. Apply each shift to the | c | whole matrix and not just to the submatrix from which it | c | comes. | c %----------------------------------------------------------% c do 90 jj = 1, np c istart = itop c c %----------------------------------------------------------% c | Check for splitting and deflation. Currently we consider | c | an off-diagonal element h(i+1,1) negligible if | c | h(i+1,1) .le. epsmch*( |h(i,2)| + |h(i+1,2)| ) | c | for i=1:KEV+NP-1. | c | If above condition tests true then we set h(i+1,1) = 0. | c | Note that h(1:KEV+NP,1) are assumed to be non negative. | c %----------------------------------------------------------% c 20 continue c c %------------------------------------------------% c | The following loop exits early if we encounter | c | a negligible off diagonal element. | c %------------------------------------------------% c do 30 i = istart, kplusp-1 big = abs(h(i,2)) + abs(h(i+1,2)) if (h(i+1,1) .le. epsmch*big) then h(i+1,1) = zero iend = i go to 40 end if 30 continue iend = kplusp 40 continue c if (istart .lt. iend) then c c %--------------------------------------------------------% c | Construct the plane rotation G'(istart,istart+1,theta) | c | that attempts to drive h(istart+1,1) to zero. | c %--------------------------------------------------------% c f = h(istart,2) - shift(jj) g = h(istart+1,1) call dlartg (f, g, c, s, r) c c %-------------------------------------------------------% c | Apply rotation to the left and right of H; | c | H <- G' * H * G, where G = G(istart,istart+1,theta). | c | This will create a "bulge". | c %-------------------------------------------------------% c a1 = c*h(istart,2) + s*h(istart+1,1) a2 = c*h(istart+1,1) + s*h(istart+1,2) a4 = c*h(istart+1,2) - s*h(istart+1,1) a3 = c*h(istart+1,1) - s*h(istart,2) h(istart,2) = c*a1 + s*a2 h(istart+1,2) = c*a4 - s*a3 h(istart+1,1) = c*a3 + s*a4 c c %----------------------------------------------------% c | Accumulate the rotation in the matrix Q; Q <- Q*G | c %----------------------------------------------------% c do 60 j = 1, min(istart+jj,kplusp) a1 = c*q(j,istart) + s*q(j,istart+1) q(j,istart+1) = - s*q(j,istart) + c*q(j,istart+1) q(j,istart) = a1 60 continue c c c %----------------------------------------------% c | The following loop chases the bulge created. | c | Note that the previous rotation may also be | c | done within the following loop. But it is | c | kept separate to make the distinction among | c | the bulge chasing sweeps and the first plane | c | rotation designed to drive h(istart+1,1) to | c | zero. | c %----------------------------------------------% c do 70 i = istart+1, iend-1 c c %----------------------------------------------% c | Construct the plane rotation G'(i,i+1,theta) | c | that zeros the i-th bulge that was created | c | by G(i-1,i,theta). g represents the bulge. | c %----------------------------------------------% c f = h(i,1) g = s*h(i+1,1) c c %----------------------------------% c | Final update with G(i-1,i,theta) | c %----------------------------------% c h(i+1,1) = c*h(i+1,1) call dlartg (f, g, c, s, r) c c %-------------------------------------------% c | The following ensures that h(1:iend-1,1), | c | the first iend-2 off diagonal of elements | c | H, remain non negative. | c %-------------------------------------------% c if (r .lt. zero) then r = -r c = -c s = -s end if c c %--------------------------------------------% c | Apply rotation to the left and right of H; | c | H <- G * H * G', where G = G(i,i+1,theta) | c %--------------------------------------------% c h(i,1) = r c a1 = c*h(i,2) + s*h(i+1,1) a2 = c*h(i+1,1) + s*h(i+1,2) a3 = c*h(i+1,1) - s*h(i,2) a4 = c*h(i+1,2) - s*h(i+1,1) c h(i,2) = c*a1 + s*a2 h(i+1,2) = c*a4 - s*a3 h(i+1,1) = c*a3 + s*a4 c c %----------------------------------------------------% c | Accumulate the rotation in the matrix Q; Q <- Q*G | c %----------------------------------------------------% c do 50 j = 1, min( i+jj, kplusp ) a1 = c*q(j,i) + s*q(j,i+1) q(j,i+1) = - s*q(j,i) + c*q(j,i+1) q(j,i) = a1 50 continue c 70 continue c end if c c %--------------------------% c | Update the block pointer | c %--------------------------% c istart = iend + 1 c c %------------------------------------------% c | Make sure that h(iend,1) is non-negative | c | If not then set h(iend,1) <-- -h(iend,1) | c | and negate the last column of Q. | c | We have effectively carried out a | c | similarity on transformation H | c %------------------------------------------% c if (h(iend,1) .lt. zero) then h(iend,1) = -h(iend,1) call dscal(kplusp, -one, q(1,iend), 1) end if c c %--------------------------------------------------------% c | Apply the same shift to the next block if there is any | c %--------------------------------------------------------% c if (iend .lt. kplusp) go to 20 c c %-----------------------------------------------------% c | Check if we can increase the the start of the block | c %-----------------------------------------------------% c do 80 i = itop, kplusp-1 if (h(i+1,1) .gt. zero) go to 90 itop = itop + 1 80 continue c c %-----------------------------------% c | Finished applying the jj-th shift | c %-----------------------------------% c 90 continue c c %------------------------------------------% c | All shifts have been applied. Check for | c | more possible deflation that might occur | c | after the last shift is applied. | c %------------------------------------------% c do 100 i = itop, kplusp-1 big = abs(h(i,2)) + abs(h(i+1,2)) if (h(i+1,1) .le. epsmch*big) then h(i+1,1) = zero end if 100 continue c c %-------------------------------------------------% c | Compute the (kev+1)-st column of (V*Q) and | c | temporarily store the result in WORKD(N+1:2*N). | c | This is not necessary if h(kev+1,1) = 0. | c %-------------------------------------------------% c if ( h(kev+1,1) .gt. zero ) & call dgemv ('N', n, kplusp, one, v, ldv, & q(1,kev+1), 1, zero, workd(n+1), 1) c c %-------------------------------------------------------% c | Compute column 1 to kev of (V*Q) in backward order | c | taking advantage that Q is an upper triangular matrix | c | with lower bandwidth np. | c | Place results in v(:,kplusp-kev:kplusp) temporarily. | c %-------------------------------------------------------% c do 130 i = 1, kev call dgemv ('N', n, kplusp-i+1, one, v, ldv, & q(1,kev-i+1), 1, zero, workd(1), 1) call dcopy (n, workd, 1, v(1,kplusp-i+1), 1) 130 continue c c %-------------------------------------------------% c | Move v(:,kplusp-kev+1:kplusp) into v(:,1:kev). | c %-------------------------------------------------% c call dlacpy ('All', n, kev, v(1,np+1), ldv, v, ldv) c c %--------------------------------------------% c | Copy the (kev+1)-st column of (V*Q) in the | c | appropriate place if h(kev+1,1) .ne. zero. | c %--------------------------------------------% c if ( h(kev+1,1) .gt. zero ) & call dcopy (n, workd(n+1), 1, v(1,kev+1), 1) c c %-------------------------------------% c | Update the residual vector: | c | r <- sigmak*r + betak*v(:,kev+1) | c | where | c | sigmak = (e_{kev+p}'*Q)*e_{kev} | c | betak = e_{kev+1}'*H*e_{kev} | c %-------------------------------------% c call dscal (n, q(kplusp,kev), resid(1), 1) c if (h(kev+1,1) .gt. zero) & call daxpy (n, h(kev+1,1), v(1,kev+1), 1, resid, 1) c 9000 continue return c c %---------------% c | End of dsapps | c %---------------% c end c----------------------------------------------------------------------- c\BeginDoc c c\Name: dseigt c c\Description: c Compute the eigenvalues of the current symmetric tridiagonal matrix c and the corresponding error bounds given the current residual norm. c c\Usage: c call dseigt c ( RNORM, N, H, LDH, EIG, BOUNDS, WORKL, IERR ) c c\Arguments c RNORM Double precision scalar. (INPUT) c RNORM contains the residual norm corresponding to the current c symmetric tridiagonal matrix H. c c N Integer. (INPUT) c Size of the symmetric tridiagonal matrix H. c c H Double precision N by 2 array. (INPUT) c H contains the symmetric tridiagonal matrix with the c subdiagonal in the first column starting at H(2,1) and the c main diagonal in second column. c c LDH Integer. (INPUT) c Leading dimension of H exactly as declared in the calling c program. c c EIG Double precision array of length N. (OUTPUT) c On output, EIG contains the N eigenvalues of H possibly c unsorted. The BOUNDS arrays are returned in the c same sorted order as EIG. c c BOUNDS Double precision array of length N. (OUTPUT) c On output, BOUNDS contains the error estimates corresponding c to the eigenvalues EIG. This is equal to RNORM times the c last components of the eigenvectors corresponding to the c eigenvalues in EIG. c c WORKL Double precision work array of length 3*N. (WORKSPACE) c Private (replicated) array on each PE or array allocated on c the front end. c c IERR Integer. (OUTPUT) c Error exit flag from dstqrb. c c\EndDoc c c----------------------------------------------------------------------- c c\BeginLib c c\Local variables: c xxxxxx real c c\Routines called: c dstqrb ARPACK routine that computes the eigenvalues and the c last components of the eigenvectors of a symmetric c and tridiagonal matrix. c second ARPACK utility routine for timing. c dvout ARPACK utility routine that prints vectors. c dcopy Level 1 BLAS that copies one vector to another. c c\Author c Danny Sorensen Phuong Vu c Richard Lehoucq CRPC / Rice University c Dept. of Computational & Houston, Texas c Applied Mathematics c Rice University c Houston, Texas c c\Revision history: c xx/xx/92: Version ' 2.4' c c\SCCS Information: @(#) c FILE: seigt.F SID: 2.4 DATE OF SID: 8/27/96 RELEASE: 2 c c\Remarks c None c c\EndLib c c----------------------------------------------------------------------- c subroutine dseigt & ( rnorm, n, h, ldh, eig, bounds, workl, ierr ) c c %----------------------------------------------------% c | Include files for debugging and timing information | c %----------------------------------------------------% c implicit none c c %------------------% c | Scalar Arguments | c %------------------% c integer ierr, ldh, n Double precision & rnorm c c %-----------------% c | Array Arguments | c %-----------------% c Double precision & eig(n), bounds(n), h(ldh,2), workl(3*n) c c %---------------% c | Local Scalars | c %---------------% c integer k c c %----------------------% c | External Subroutines | c %----------------------% c external dcopy, dstqrb c c %-----------------------% c | Executable Statements | c %-----------------------% c c %-------------------------------% c | Initialize timing statistics | c | & message level for debugging | c %-------------------------------% c c call second (t0) c c call dcopy (n, h(1,2), 1, eig(1), 1) call dcopy (n-1, h(2,1), 1, workl(1), 1) call dstqrb (n, eig, workl, bounds, workl(n+1), ierr) if (ierr .ne. 0) go to 9000 c c %-----------------------------------------------% c | Finally determine the error bounds associated | c | with the n Ritz values of H. | c %-----------------------------------------------% c do 30 k = 1, n bounds(k) = rnorm*abs(bounds(k)) 30 continue c c call second (t1) c 9000 continue return c c %---------------% c | End of dseigt | c %---------------% c end c----------------------------------------------------------------------- c\BeginDoc c c\Name: dstqrb c c\Description: c Computes all eigenvalues and the last component of the eigenvectors c of a symmetric tridiagonal matrix using the implicit QL or QR method. c c This is mostly a modification of the LAPACK routine dsteqr. c See Remarks. c c\Usage: c call dstqrb c ( N, D, E, Z, WORK, INFO ) c c\Arguments c N Integer. (INPUT) c The number of rows and columns in the matrix. N >= 0. c c D Double precision array, dimension (N). (INPUT/OUTPUT) c On entry, D contains the diagonal elements of the c tridiagonal matrix. c On exit, D contains the eigenvalues, in ascending order. c If an error exit is made, the eigenvalues are correct c for indices 1,2,...,INFO-1, but they are unordered and c may not be the smallest eigenvalues of the matrix. c c E Double precision array, dimension (N-1). (INPUT/OUTPUT) c On entry, E contains the subdiagonal elements of the c tridiagonal matrix in positions 1 through N-1. c On exit, E has been destroyed. c c Z Double precision array, dimension (N). (OUTPUT) c On exit, Z contains the last row of the orthonormal c eigenvector matrix of the symmetric tridiagonal matrix. c If an error exit is made, Z contains the last row of the c eigenvector matrix associated with the stored eigenvalues. c c WORK Double precision array, dimension (max(1,2*N-2)). (WORKSPACE) c Workspace used in accumulating the transformation for c computing the last components of the eigenvectors. c c INFO Integer. (OUTPUT) c = 0: normal return. c < 0: if INFO = -i, the i-th argument had an illegal value. c > 0: if INFO = +i, the i-th eigenvalue has not converged c after a total of 30*N iterations. c c\Remarks c 1. None. c c----------------------------------------------------------------------- c c\BeginLib c c\Local variables: c xxxxxx real c c\Routines called: c daxpy Level 1 BLAS that computes a vector triad. c dcopy Level 1 BLAS that copies one vector to another. c dswap Level 1 BLAS that swaps the contents of two vectors. c lsame LAPACK character comparison routine. c dlae2 LAPACK routine that computes the eigenvalues of a 2-by-2 c symmetric matrix. c dlaev2 LAPACK routine that eigendecomposition of a 2-by-2 symmetric c matrix. c dlamch LAPACK routine that determines machine constants. c dlanst LAPACK routine that computes the norm of a matrix. c dlapy2 LAPACK routine to compute sqrt(x**2+y**2) carefully. c dlartg LAPACK Givens rotation construction routine. c dlascl LAPACK routine for careful scaling of a matrix. c dlaset LAPACK matrix initialization routine. c dlasr LAPACK routine that applies an orthogonal transformation to c a matrix. c dlasrt LAPACK sorting routine. c dsteqr LAPACK routine that computes eigenvalues and eigenvectors c of a symmetric tridiagonal matrix. c xerbla LAPACK error handler routine. c c\Authors c Danny Sorensen Phuong Vu c Richard Lehoucq CRPC / Rice University c Dept. of Computational & Houston, Texas c Applied Mathematics c Rice University c Houston, Texas c c\SCCS Information: @(#) c FILE: stqrb.F SID: 2.5 DATE OF SID: 8/27/96 RELEASE: 2 c c\Remarks c 1. Starting with version 2.5, this routine is a modified version c of LAPACK version 2.0 subroutine SSTEQR. No lines are deleted, c only commeted out and new lines inserted. c All lines commented out have "c$$$" at the beginning. c Note that the LAPACK version 1.0 subroutine SSTEQR contained c bugs. c c\EndLib c c----------------------------------------------------------------------- c subroutine dstqrb ( n, d, e, z, work, info ) c implicit none c c %------------------% c | Scalar Arguments | c %------------------% c integer info, n c c %-----------------% c | Array Arguments | c %-----------------% c Double precision & d( n ), e( n-1 ), z( n ), work( 2*n-2 ) c Double precision & zero, one, two, three parameter ( zero = 0.0D+0, one = 1.0D+0, & two = 2.0D+0, three = 3.0D+0 ) c integer izero parameter (izero=0 ) c integer maxit parameter ( maxit = 30 ) c integer i, icompz, ii, iscale, j, jtot, k, l, l1, & lendm1, lendp1, lendsv, lm1, lsv, m, mm, mm1, & nm1, nmaxit, lend Double precision & anorm, b, c, eps, eps2, f, g, p, r, rt1, rt2, & s, safmax, safmin, ssfmax, ssfmin, tst c .. c .. external functions .. logical, external :: neZERO, eqZERO logical lsame Double precision & dlamch, dlanst, dlapy2 external lsame, dlamch, dlanst, dlapy2 c .. c .. external subroutines .. external dlae2, dlaev2, dlartg, dlascl, dlaset, dlasr, & dlasrt, dswap, xerbla c .. c .. intrinsic functions .. intrinsic abs, max, sign, sqrt c .. c .. executable statements .. c c test the input parameters. c info = 0 c c *** New starting with version 2.5 *** c icompz = 2 c ************************************* c c quick return if possible c if( n.eq.0 ) $ return c if( n.eq.1 ) then if( icompz.eq.2 ) z( 1 ) = one return end if c c determine the unit roundoff and over/underflow thresholds. c eps = dlamch( 'e' ) eps2 = eps**2 safmin = dlamch( 's' ) safmax = one / safmin ssfmax = sqrt( safmax ) / three ssfmin = sqrt( safmin ) / eps2 c c compute the eigenvalues and eigenvectors of the tridiagonal c matrix. c c *** New starting with version 2.5 *** c if ( icompz .eq. 2 ) then do 5 j = 1, n-1 z(j) = zero 5 continue z( n ) = one end if c ************************************* c nmaxit = n*maxit jtot = 0 c c determine where the matrix splits and choose ql or qr iteration c for each block, according to whether top or bottom diagonal c element is smaller. c l1 = 1 nm1 = n - 1 c 10 continue if( l1.gt.n ) $ go to 160 if( l1.gt.1 ) $ e( l1-1 ) = zero if( l1.le.nm1 ) then do 20 m = l1, nm1 tst = abs( e( m ) ) if (eqZERO( tst)) $ go to 30 if( tst.le.( sqrt( abs( d( m ) ) )*sqrt( abs( d( m+ $ 1 ) ) ) )*eps ) then e( m ) = zero go to 30 end if 20 continue end if m = n c 30 continue l = l1 lsv = l lend = m lendsv = lend l1 = m + 1 if( lend.eq.l ) $ go to 10 c c scale submatrix in rows and columns l to lend c anorm = dlanst( 'i', lend-l+1, d( l ), e( l ) ) iscale = 0 if (eqZERO( anorm)) $ go to 10 if( anorm.gt.ssfmax ) then iscale = 1 call dlascl( 'g', izero, izero, anorm, ssfmax, lend-l+1, 1, $ d( l ), n, info ) call dlascl( 'g', izero, izero, anorm, ssfmax, lend-l, 1, $ e( l ), n, info ) c else if( anorm.lt.ssfmin ) then iscale = 2 call dlascl( 'g', izero, izero, anorm, ssfmin, lend-l+1, 1, $ d( l ), n, info ) call dlascl( 'g', izero, izero, anorm, ssfmin, lend-l, 1, $ e( l ), n, info ) c end if c c choose between ql and qr iteration c if( abs( d( lend ) ).lt.abs( d( l ) ) ) then lend = lsv l = lendsv end if c if( lend.gt.l ) then c c ql iteration c c look for small subdiagonal element. c 40 continue if( l.ne.lend ) then lendm1 = lend - 1 do 50 m = l, lendm1 tst = abs( e( m ) )**2 if( tst.le.( eps2*abs( d( m ) ) )*abs( d( m+1 ) )+ $ safmin )go to 60 50 continue end if c m = lend c 60 continue if( m.lt.lend ) $ e( m ) = zero p = d( l ) if( m.eq.l ) $ go to 80 c c if remaining matrix is 2-by-2, use dlae2 or dlaev2 c to compute its eigensystem. c if( m.eq.l+1 ) then if( icompz.gt.0 ) then call dlaev2( d( l ), e( l ), d( l+1 ), rt1, rt2, c, s ) work( l ) = c work( n-1+l ) = s c c *** New starting with version 2.5 *** c tst = z(l+1) z(l+1) = c*tst - s*z(l) z(l) = s*tst + c*z(l) c ************************************* else call dlae2( d( l ), e( l ), d( l+1 ), rt1, rt2 ) end if d( l ) = rt1 d( l+1 ) = rt2 e( l ) = zero l = l + 2 if( l.le.lend ) $ go to 40 go to 140 end if c if( jtot.eq.nmaxit ) $ go to 140 jtot = jtot + 1 c c form shift. c g = ( d( l+1 )-p ) / ( two*e( l ) ) r = dlapy2( g, one ) g = d( m ) - p + ( e( l ) / ( g+sign( r, g ) ) ) c s = one c = one p = zero c c inner loop c mm1 = m - 1 do 70 i = mm1, l, -1 f = s*e( i ) b = c*e( i ) call dlartg( g, f, c, s, r ) if( i.ne.m-1 ) $ e( i+1 ) = r g = d( i+1 ) - p r = ( d( i )-g )*s + two*c*b p = s*r d( i+1 ) = g + p g = c*r - b c c if eigenvectors are desired, then save rotations. c if( icompz.gt.0 ) then work( i ) = c work( n-1+i ) = -s end if c 70 continue c c if eigenvectors are desired, then apply saved rotations. c if( icompz.gt.0 ) then mm = m - l + 1 c c *** New starting with version 2.5 *** c call dlasr( 'r', 'v', 'b', 1, mm, work( l ), & work( n-1+l ), z( l ), 1 ) c ************************************* end if c d( l ) = d( l ) - p e( l ) = g go to 40 c c eigenvalue found. c 80 continue d( l ) = p c l = l + 1 if( l.le.lend ) $ go to 40 go to 140 c else c c qr iteration c c look for small superdiagonal element. c 90 continue if( l.ne.lend ) then lendp1 = lend + 1 do 100 m = l, lendp1, -1 tst = abs( e( m-1 ) )**2 if( tst.le.( eps2*abs( d( m ) ) )*abs( d( m-1 ) )+ $ safmin )go to 110 100 continue end if c m = lend c 110 continue if( m.gt.lend ) $ e( m-1 ) = zero p = d( l ) if( m.eq.l ) $ go to 130 c c if remaining matrix is 2-by-2, use dlae2 or dlaev2 c to compute its eigensystem. c if( m.eq.l-1 ) then if( icompz.gt.0 ) then call dlaev2( d( l-1 ), e( l-1 ), d( l ), rt1, rt2, c, s ) c c *** New starting with version 2.5 *** c tst = z(l) z(l) = c*tst - s*z(l-1) z(l-1) = s*tst + c*z(l-1) c ************************************* else call dlae2( d( l-1 ), e( l-1 ), d( l ), rt1, rt2 ) end if d( l-1 ) = rt1 d( l ) = rt2 e( l-1 ) = zero l = l - 2 if( l.ge.lend ) $ go to 90 go to 140 end if c if( jtot.eq.nmaxit ) $ go to 140 jtot = jtot + 1 c c form shift. c g = ( d( l-1 )-p ) / ( two*e( l-1 ) ) r = dlapy2( g, one ) g = d( m ) - p + ( e( l-1 ) / ( g+sign( r, g ) ) ) c s = one c = one p = zero c c inner loop c lm1 = l - 1 do 120 i = m, lm1 f = s*e( i ) b = c*e( i ) call dlartg( g, f, c, s, r ) if( i.ne.m ) $ e( i-1 ) = r g = d( i ) - p r = ( d( i+1 )-g )*s + two*c*b p = s*r d( i ) = g + p g = c*r - b c c if eigenvectors are desired, then save rotations. c if( icompz.gt.0 ) then work( i ) = c work( n-1+i ) = s end if c 120 continue c c if eigenvectors are desired, then apply saved rotations. c if( icompz.gt.0 ) then mm = l - m + 1 c c *** New starting with version 2.5 *** c call dlasr( 'r', 'v', 'f', 1, mm, work( m ), work( n-1+m ), & z( m ), 1 ) c ************************************* end if c d( l ) = d( l ) - p e( lm1 ) = g go to 90 c c eigenvalue found. c 130 continue d( l ) = p c l = l - 1 if( l.ge.lend ) $ go to 90 go to 140 c end if c c undo scaling if necessary c 140 continue if( iscale.eq.1 ) then call dlascl( 'g', izero, izero, ssfmax, anorm, lendsv-lsv+1, $ 1, d( lsv ), n, info ) call dlascl( 'g', izero, izero, ssfmax, anorm, lendsv-lsv, $ 1, e( lsv ), n, info ) c else if( iscale.eq.2 ) then call dlascl( 'g', izero, izero, ssfmin, anorm, lendsv-lsv+1, $ 1, d( lsv ), n, info ) call dlascl( 'g', izero, izero, ssfmin, anorm, lendsv-lsv, $ 1, e( lsv ), n, info ) c end if c c check for no convergence to an eigenvalue after a total c of n*maxit iterations. c if( jtot.lt.nmaxit ) $ go to 10 do 150 i = 1, n - 1 if(neZERO( e( i ))) $ info = info + 1 150 continue go to 190 c c order eigenvalues and eigenvectors. c 160 continue if( icompz.eq.0 ) then c c use quick sort c call dlasrt( 'i', n, d, info ) c else c c use selection sort to minimize swaps of eigenvectors c do 180 ii = 2, n i = ii - 1 k = i p = d( i ) do 170 j = ii, n if( d( j ).lt.p ) then k = j p = d( j ) end if 170 continue if( k.ne.i ) then d( k ) = d( i ) d( i ) = p c c *** New starting with version 2.5 *** c p = z(k) z(k) = z(i) z(i) = p c ************************************* end if 180 continue end if c 190 continue return c c %---------------% c | End of dstqrb | c %---------------% c end c c c\BeginDoc c c\Name: dsortr c c\Description: c Sort the array X1 in the order specified by WHICH and optionally c applies the permutation to the array X2. c c\Usage: c call dsortr c ( WHICH, APPLY, N, X1, X2 ) c c\Arguments c WHICH Character*2. (Input) c 'LM' -> X1 is sorted into increasing order of magnitude. c 'SM' -> X1 is sorted into decreasing order of magnitude. c 'LA' -> X1 is sorted into increasing order of algebraic. c 'SA' -> X1 is sorted into decreasing order of algebraic. c c APPLY Logical. (Input) c APPLY = .TRUE. -> apply the sorted order to X2. c APPLY = .FALSE. -> do not apply the sorted order to X2. c c N Integer. (INPUT) c Size of the arrays. c c X1 Double precision array of length N. (INPUT/OUTPUT) c The array to be sorted. c c X2 Double precision array of length N. (INPUT/OUTPUT) c Only referenced if APPLY = .TRUE. c c\EndDoc c c----------------------------------------------------------------------- c c\BeginLib c c\Author c Danny Sorensen Phuong Vu c Richard Lehoucq CRPC / Rice University c Dept. of Computational & Houston, Texas c Applied Mathematics c Rice University c Houston, Texas c c\Revision history: c 12/16/93: Version ' 2.1'. c Adapted from the sort routine in LANSO. c c\SCCS Information: @(#) c FILE: sortr.F SID: 2.3 DATE OF SID: 4/19/96 RELEASE: 2 c c\EndLib c c----------------------------------------------------------------------- c subroutine dsortr (which, apply, n, x1, x2) c implicit none c c %------------------% c | Scalar Arguments | c %------------------% c character which*2 logical apply integer n c c %-----------------% c | Array Arguments | c %-----------------% c Double precision & x1(0:n-1), x2(0:n-1) c c %---------------% c | Local Scalars | c %---------------% c integer i, igap, j Double precision & temp c c %-----------------------% c | Executable Statements | c %-----------------------% c igap = n / 2 c if (which .eq. 'SA') then c c X1 is sorted into decreasing order of algebraic. c 10 continue if (igap .eq. 0) go to 9000 do 30 i = igap, n-1 j = i-igap 20 continue c if (j.lt.0) go to 30 c if (x1(j).lt.x1(j+igap)) then temp = x1(j) x1(j) = x1(j+igap) x1(j+igap) = temp if (apply) then temp = x2(j) x2(j) = x2(j+igap) x2(j+igap) = temp end if else go to 30 endif j = j-igap go to 20 30 continue igap = igap / 2 go to 10 c else if (which .eq. 'SM') then c c X1 is sorted into decreasing order of magnitude. c 40 continue if (igap .eq. 0) go to 9000 do 60 i = igap, n-1 j = i-igap 50 continue c if (j.lt.0) go to 60 c if (abs(x1(j)).lt.abs(x1(j+igap))) then temp = x1(j) x1(j) = x1(j+igap) x1(j+igap) = temp if (apply) then temp = x2(j) x2(j) = x2(j+igap) x2(j+igap) = temp end if else go to 60 endif j = j-igap go to 50 60 continue igap = igap / 2 go to 40 c else if (which .eq. 'LA') then c c X1 is sorted into increasing order of algebraic. c 70 continue if (igap .eq. 0) go to 9000 do 90 i = igap, n-1 j = i-igap 80 continue c if (j.lt.0) go to 90 c if (x1(j).gt.x1(j+igap)) then temp = x1(j) x1(j) = x1(j+igap) x1(j+igap) = temp if (apply) then temp = x2(j) x2(j) = x2(j+igap) x2(j+igap) = temp end if else go to 90 endif j = j-igap go to 80 90 continue igap = igap / 2 go to 70 c else if (which .eq. 'LM') then c c X1 is sorted into increasing order of magnitude. c 100 continue if (igap .eq. 0) go to 9000 do 120 i = igap, n-1 j = i-igap 110 continue c if (j.lt.0) go to 120 c if (abs(x1(j)).gt.abs(x1(j+igap))) then temp = x1(j) x1(j) = x1(j+igap) x1(j+igap) = temp if (apply) then temp = x2(j) x2(j) = x2(j+igap) x2(j+igap) = temp end if else go to 120 endif j = j-igap go to 110 120 continue igap = igap / 2 go to 100 end if c 9000 continue return c c %---------------% c | End of dsortr | c %---------------% c end spam/src/dn_eigen.f0000644000176200001440000000550213574431374013735 0ustar liggesusersc subroutine dn_eigen_f(maxnev, ncv, maxitr, & n, iwhich, & na, a, ja, ia, & v, dr, di, iparam) c implicit none c integer maxnev, ncv, n, na, & iwhich, maxitr c %--------------% c | Local Arrays | c %--------------% c integer iparam(8), ipntr(14), & ja(*), ia(na+1) c logical select(ncv) c Double precision & dr(maxnev+1), di(maxnev+1), resid(n), & v(n, ncv), workd(3*n), & workev(3*ncv), & workl(3*ncv**2+6*ncv), & a(*) c c %---------------% c | Local Scalars | c %---------------% c character bmat*1, which*2 integer ido, lworkl, info, & ierr, ishfts, mode Double precision & tol, sigmar, sigmai c c %------------% c | Parameters | c %------------% c Double precision & zero parameter (zero = 0.0D+0) c bmat = 'I' c lworkl = 3*ncv*ncv+6*ncv tol = zero ido = 0 info = 0 c ishfts = 1 mode = 1 c iparam(1) = ishfts iparam(3) = maxitr iparam(7) = mode c if (iwhich .eq. 1) then which = 'LM' else if (iwhich .eq. 2) then which = 'SM' else if (iwhich .eq. 3) then which = 'LR' else if (iwhich .eq. 4) then which = 'SR' else if (iwhich .eq. 5) then which = 'LI' else if (iwhich .eq. 6) then which = 'SI' else c goto 9000 end if c c 10 continue c c %---------------------------------------------% c | Repeatedly call the routine DNAUPD and take | c | actions indicated by parameter IDO until | c | either convergence is indicated or maxitr | c | has been exceeded. | c %---------------------------------------------% c call dnaupd ( ido, bmat, n, which, maxnev, tol, resid, & ncv, v, n, iparam, ipntr, workd, workl, lworkl, & info ) c if (ido .eq. -1 .or. ido .eq. 1) then c call d_ope (na, workd(ipntr(1)), workd(ipntr(2)), & a, ja, ia) c go to 10 c end if c if ( info .lt. 0 ) then c goto 9000 c else c call dneupd ( .true., 'A', select, dr, di, v, n, & sigmar, sigmai, workev, bmat, n, which, maxnev, tol, & resid, ncv, v, n, iparam, ipntr, workd, workl, & lworkl, ierr ) c if ( ierr .lt. 0 ) then c goto 9000 c end if c endif c 9000 continue c end c spam/src/xybind.f0000644000176200001440000000155513574431374013466 0ustar liggesusersc system("R CMD SHLIB ../src/xybind.f") subroutine cbindf(xncol,nrow, a,ia,ja, b,ib,jb, & c,ic,jc) implicit none integer xncol, nrow integer ia(*), ja(*), ib(*), jb(*), ic(*), jc(*) double precision a(*), b(*), c(*) integer j,j1,i,k k=1 do j = 1,nrow jc(j)=ja(j)+jb(j)-1 j1=j+1 if (ja(j) .lt. ja(j1)) then do i=ja(j),ja(j1)-1 c(k)=a(i) ic(k)=ia(i) k=k+1 c if (k.gt.clen) return enddo endif if (jb(j) .lt. jb(j1)) then do i=jb(j),jb(j1)-1 c(k)=b(i) ic(k)=ib(i)+xncol k=k+1 c if (k.gt.clen) return enddo endif enddo j=nrow+1 jc(j)=ja(j)+jb(j)-1 return end spam/src/bckslvmodified.f0000644000176200001440000001530613574431374015155 0ustar liggesusersc Changes Oct 2019: to address gcc-10 issues with Rank missmatch: c in `call blksb[lf]`: b(1,j) -> b(:,j); newrhs -> newrhs(:) subroutine backsolvef(m,nsuper,nrhs,lindx,xlindx,lnz, & xlnz,xsuper,b) c see below... implicit none integer m,nsuper,nrhs,lindx(*),xlindx(m+1), & xlnz(m+1),xsuper(m+1) double precision lnz(*),b(m,nrhs) integer j do j = 1,nrhs call blkslb(nsuper,xsuper,xlindx,lindx,xlnz,lnz,b(:,j)) enddo return end subroutine forwardsolvef(m,nsuper,nrhs,lindx,xlindx, & lnz,xlnz,xsuper,b) c INPUT: c m -- the number of column in the matrix c lindx -- an nsub-vector of interger which contains, in c column major oder, the row subscripts of the nonzero c entries in L in a compressed storage format c xlindx -- an nsuper-vector of integer of pointers for lindx c lnz -- First contains the non-zero entries of d; later c contains the entries of the Cholesky factor c xlnz -- column pointer for L stored in lnz c xsuper -- array of length m+1 containing the supernode c partitioning c b -- the rhs of the equality constraint c OUTPUT: c b -- the solution implicit none integer m,nsuper,nrhs,lindx(*),xlindx(m+1), & xlnz(m+1),xsuper(m+1) double precision lnz(*),b(m,nrhs) integer j c do j = 1,nrhs call blkslf(nsuper,xsuper,xlindx,lindx,xlnz,lnz,b(:,j)) enddo return end C*********************************************************************** C*********************************************************************** C C Version: 0.4 C Last modified: December 27, 1994 C Authors: Esmond G. Ng and Barry W. Peyton C Slight modification by Reinhard Furrer C C Mathematical Sciences Section, Oak Ridge National Laboratory C C*********************************************************************** C*********************************************************************** C C*********************************************************************** subroutine pivotforwardsolve(m,nsuper,nrhs,lindx,xlindx,lnz, & xlnz,invp,perm,xsuper,newrhs,sol,b) c Sparse least squares solver via Ng-Peyton's sparse Cholesky c factorization for sparse symmetric positive definite c INPUT: c m -- the number of column in the design matrix X c nsubmax -- upper bound of the dimension of lindx c lindx -- an nsub-vector of interger which contains, in c column major oder, the row subscripts of the nonzero c entries in L in a compressed storage format c xlindx -- an nsuper-vector of integer of pointers for lindx c lnz -- First contains the non-zero entries of d; later c contains the entries of the Cholesky factor c xlnz -- column pointer for L stored in lnz c invp -- an m-vector of integer of inverse permutation c vector c perm -- an m-vector of integer of permutation vector c xsuper -- array of length m+1 containing the supernode c partitioning c newrhs -- extra work vector for right-hand side and c solution c sol -- the least squares solution c b -- an m-vector, usualy the rhs of the equality constraint c X'a = (1-tau)X'e in the rq setting c OUTPUT: c y -- an m-vector of least squares solution c WORK ARRAYS: c b -- an m-vector, usually the rhs of the equality constraint c X'a = (1-tau)X'e in the rq setting implicit none integer m,nsuper,nrhs,lindx(*),xlindx(m+1), & invp(m),perm(m),xlnz(m+1), xsuper(m+1) integer i,j double precision lnz(*),b(m,nrhs),newrhs(m),sol(m,nrhs) do j = 1,nrhs do i = 1,m newrhs(i) = b(perm(i),j) enddo call blkslf(nsuper,xsuper,xlindx,lindx,xlnz,lnz,newrhs(:)) do i = 1,m sol(i,j) = newrhs(invp(i)) enddo enddo return end C*********************************************************************** subroutine pivotbacksolve(m,nsuper,nrhs,lindx,xlindx,lnz, & xlnz,invp,perm,xsuper,newrhs,sol,b) c see above implicit none integer m, nsuper,nrhs,lindx(*),xlindx(m+1), & invp(m),perm(m),xlnz(m+1), xsuper(m+1) double precision lnz(*),b(m,nrhs),newrhs(m),sol(m,nrhs) integer i,j do j = 1,nrhs do i = 1,m newrhs(i) = b(perm(i),j) enddo call blkslb(nsuper,xsuper,xlindx,lindx,xlnz,lnz,newrhs) do i = 1,m sol(i,j) = newrhs(invp(i)) enddo enddo return end C*********************************************************************** subroutine backsolves(m,nsuper,nrhs,lindx,xlindx,lnz, & xlnz,invp,perm,xsuper,newrhs,sol,b) c Sparse least squares solver via Ng-Peyton's sparse Cholesky c factorization for sparse symmetric positive definite c INPUT: c m -- the number of column in the design matrix X c nsubmax -- upper bound of the dimension of lindx c lindx -- an nsub-vector of interger which contains, in c column major oder, the row subscripts of the nonzero c entries in L in a compressed storage format c xlindx -- an nsuper-vector of integer of pointers for lindx c nnzlmax -- the upper bound of the non-zero entries in c L stored in lnz, including the diagonal entries c lnz -- First contains the non-zero entries of d; later c contains the entries of the Cholesky factor c xlnz -- column pointer for L stored in lnz c invp -- an m-vector of integer of inverse permutation c vector c perm -- an m-vector of integer of permutation vector c xsuper -- array of length m+1 containing the supernode c partitioning c newrhs -- extra work vector for right-hand side and c solution c sol -- the least squares solution c b -- an m-vector, usualy the rhs of the equality constraint c X'a = (1-tau)X'e in the rq setting c OUTPUT: c y -- an m-vector of least squares solution c WORK ARRAYS: c b -- an m-vector, usually the rhs of the equality constraint c X'a = (1-tau)X'e in the rq setting implicit none integer m,nsuper,nrhs,lindx(*),xlindx(m+1), & invp(m),perm(m),xlnz(m+1), xsuper(m+1) double precision lnz(*),b(m,nrhs),newrhs(m),sol(m,nrhs) integer i,j do j = 1,nrhs do i = 1,m newrhs(i) = b(perm(i),j) enddo call blkslv(nsuper,xsuper,xlindx,lindx,xlnz,lnz,newrhs(:)) do i = 1,m sol(i,j) = newrhs(invp(i)) enddo enddo return end spam/src/init.c0000644000176200001440000002677113574431374013140 0ustar liggesusers#include #include #include #include // for NULL #include /* to get all functions: nm -g ./lib/spam/libs/spam.so | grep " T " */ /* .Fortran calls */ extern void F77_NAME(cholstepwise )(void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *); // 16 extern void F77_NAME(updatefactor )( void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *); // 15 extern void F77_NAME(amub )( void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *); // 14 extern void F77_NAME(aplsb1 )( void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *); extern void F77_NAME(closestdist )( void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *); // 13 extern void F77_NAME(aemub )( void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *); extern void F77_NAME(submat )( void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *); extern void F77_NAME(pivotforwardsolve)( void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *); extern void F77_NAME(pivotbacksolve )( void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *); extern void F77_NAME(backsolves )( void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *); extern void F77_NAME(kroneckerf )( void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *); extern void F77_NAME(dn_eigen_f )( void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *); // 12 extern void F77_NAME(amask )( void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *); extern void F77_NAME(subass )( void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *); extern void F77_NAME(kroneckermult )( void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *); extern void F77_NAME(ds_eigen_f )( void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *); // 11 extern void F77_NAME(getblock )( void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *); extern void F77_NAME(cbindf )( void *, void *, void *, void *, void *, void *, void *, void *, void *, void *, void *); // 10 extern void F77_NAME(getdia )( void *, void *, void *, void *, void *, void *, void *, void *, void *, void *); extern void F77_NAME(amubdg )( void *, void *, void *, void *, void *, void *, void *, void *, void *, void *); extern void F77_NAME(reducedim )( void *, void *, void *, void *, void *, void *, void *, void *, void *, void *); extern void F77_NAME(triplet3csr )( void *, void *, void *, void *, void *, void *, void *, void *, void *, void *); extern void F77_NAME(triplet2csr )( void *, void *, void *, void *, void *, void *, void *, void *, void *, void *); // 9 extern void F77_NAME(aplbdg )( void *, void *, void *, void *, void *, void *, void *, void *, void *); extern void F77_NAME(getlines )( void *, void *, void *, void *, void *, void *, void *, void *, void *); extern void F77_NAME(dperm )( void *, void *, void *, void *, void *, void *, void *, void *, void *); extern void F77_NAME(backsolvef )( void *, void *, void *, void *, void *, void *, void *, void *, void *); extern void F77_NAME(forwardsolvef )( void *, void *, void *, void *, void *, void *, void *, void *, void *); // 8 extern void F77_NAME(spamdnscsr )( void *, void *, void *, void *, void *, void *, void *, void *); extern void F77_NAME(transpose )( void *, void *, void *, void *, void *, void *, void *, void *); extern void F77_NAME(colmeans )( void *, void *, void *, void *, void *, void *, void *, void *); extern void F77_NAME(amuxmat )( void *, void *, void *, void *, void *, void *, void *, void *); extern void F77_NAME(toeplitz )( void *, void *, void *, void *, void *, void *, void *, void *); extern void F77_NAME(notzero )( void *, void *, void *, void *, void *, void *, void *, void *); extern void F77_NAME(getallelem )( void *, void *, void *, void *, void *, void *, void *, void *); extern void F77_NAME(cperm )( void *, void *, void *, void *, void *, void *, void *, void *); extern void F77_NAME(rperm )( void *, void *, void *, void *, void *, void *, void *, void *); // 7 extern void F77_NAME(calcja )( void *, void *, void *, void *, void *, void *, void *); extern void F77_NAME(spamback )( void *, void *, void *, void *, void *, void *, void *); extern void F77_NAME(spamforward )( void *, void *, void *, void *, void *, void *, void *); extern void F77_NAME(circulant )( void *, void *, void *, void *, void *, void *, void *); extern void F77_NAME(setdiagmat )( void *, void *, void *, void *, void *, void *, void *); extern void F77_NAME(diagaddmat )( void *, void *, void *, void *, void *, void *, void *); extern void F77_NAME(getelem )( void *, void *, void *, void *, void *, void *, void *); extern void F77_NAME(getl )( void *, void *, void *, void *, void *, void *, void *); extern void F77_NAME(getu )( void *, void *, void *, void *, void *, void *, void *); // 6 extern void F77_NAME(rowmeans )( void *, void *, void *, void *, void *, void *); extern void F77_NAME(amux )( void *, void *, void *, void *, void *, void *); extern void F77_NAME(disttospam )( void *, void *, void *, void *, void *, void *); extern void F77_NAME(subfullsparse )( void *, void *, void *, void *, void *, void *); // 5 extern void F77_NAME(colsums )( void *, void *, void *, void *, void *); extern void F77_NAME(getdiag )( void *, void *, void *, void *, void *); extern void F77_NAME(spamcsrdns )( void *, void *, void *, void *, void *); extern void F77_NAME(addsparsefull )( void *, void *, void *, void *, void *); extern void F77_NAME(subsparsefull )( void *, void *, void *, void *, void *); extern void F77_NAME(cleanspam )( void *, void *, void *, void *, void *); extern void F77_NAME(getbwd )( void *, void *, void *, void *, void *); // 4 extern void F77_NAME(rowsums )( void *, void *, void *, void *); extern void F77_NAME(sortrows )( void *, void *, void *, void *); extern void F77_NAME(constructia )( void *, void *, void *, void *); extern void F77_NAME(diagmua )( void *, void *, void *, void *); static const R_FortranMethodDef FortranEntries[] = { {"cholstepwise", (DL_FUNC) &F77_NAME(cholstepwise ),20}, {"updatefactor", (DL_FUNC) &F77_NAME(updatefactor ),16}, {"amub", (DL_FUNC) &F77_NAME(amub ),15}, {"aplsb1", (DL_FUNC) &F77_NAME(aplsb1 ),14}, {"closestdist", (DL_FUNC) &F77_NAME(closestdist ),14}, {"pivotbacksolve", (DL_FUNC) &F77_NAME(pivotbacksolve ),13}, {"pivotforwardsolve", (DL_FUNC) &F77_NAME(pivotforwardsolve ),13}, {"backsolves", (DL_FUNC) &F77_NAME(backsolves ),13}, {"submat", (DL_FUNC) &F77_NAME(submat ),13}, {"aemub", (DL_FUNC) &F77_NAME(aemub ),13}, {"kroneckerf", (DL_FUNC) &F77_NAME(kroneckerf ),13}, {"dn_eigen_f", (DL_FUNC) &F77_NAME(dn_eigen_f ),13}, {"subass", (DL_FUNC) &F77_NAME(subass ),12}, {"amask", (DL_FUNC) &F77_NAME(amask ),12}, {"kroneckermult", (DL_FUNC) &F77_NAME(kroneckermult ),12}, {"ds_eigen_f", (DL_FUNC) &F77_NAME(ds_eigen_f ),12}, {"getblock", (DL_FUNC) &F77_NAME(getblock ),11}, {"cbindf", (DL_FUNC) &F77_NAME(cbindf ),11}, {"getdia", (DL_FUNC) &F77_NAME(getdia ),10}, {"amubdg", (DL_FUNC) &F77_NAME(amubdg ),10}, {"reducedim", (DL_FUNC) &F77_NAME(reducedim ),10}, {"triplet3csr", (DL_FUNC) &F77_NAME(triplet3csr ),10}, {"triplet2csr", (DL_FUNC) &F77_NAME(triplet2csr ),10}, {"aplbdg", (DL_FUNC) &F77_NAME(aplbdg ), 9}, {"getlines", (DL_FUNC) &F77_NAME(getlines ), 9}, {"dperm", (DL_FUNC) &F77_NAME(dperm ), 9}, {"backsolvef", (DL_FUNC) &F77_NAME(backsolvef ), 9}, {"forwardsolvef", (DL_FUNC) &F77_NAME(forwardsolvef ), 9}, {"spamdnscsr", (DL_FUNC) &F77_NAME(spamdnscsr ), 8}, {"transpose", (DL_FUNC) &F77_NAME(transpose ), 8}, {"colmeans", (DL_FUNC) &F77_NAME(colmeans ), 8}, {"amuxmat", (DL_FUNC) &F77_NAME(amuxmat ), 8}, {"toeplitz", (DL_FUNC) &F77_NAME(toeplitz ), 8}, {"notzero", (DL_FUNC) &F77_NAME(notzero ), 8}, {"getallelem", (DL_FUNC) &F77_NAME(getallelem ), 8}, {"cperm", (DL_FUNC) &F77_NAME(cperm ), 8}, {"rperm", (DL_FUNC) &F77_NAME(rperm ), 8}, {"spamback", (DL_FUNC) &F77_NAME(spamback ), 7}, {"spamforward", (DL_FUNC) &F77_NAME(spamforward ), 7}, {"calcja", (DL_FUNC) &F77_NAME(calcja ), 7}, {"circulant", (DL_FUNC) &F77_NAME(circulant ), 7}, {"setdiagmat", (DL_FUNC) &F77_NAME(setdiagmat ), 7}, {"diagaddmat", (DL_FUNC) &F77_NAME(diagaddmat ), 7}, {"getelem", (DL_FUNC) &F77_NAME(getelem ), 7}, {"getl", (DL_FUNC) &F77_NAME(getl ), 7}, {"getu", (DL_FUNC) &F77_NAME(getu ), 7}, {"rowmeans", (DL_FUNC) &F77_NAME(rowmeans ), 6}, {"amux", (DL_FUNC) &F77_NAME(amux ), 6}, {"disttospam", (DL_FUNC) &F77_NAME(disttospam ), 6}, {"subfullsparse", (DL_FUNC) &F77_NAME(subfullsparse ), 6}, {"colsums", (DL_FUNC) &F77_NAME(colsums ), 5}, {"getdiag", (DL_FUNC) &F77_NAME(getdiag ), 5}, {"spamcsrdns", (DL_FUNC) &F77_NAME(spamcsrdns ), 5}, {"addsparsefull", (DL_FUNC) &F77_NAME(addsparsefull ), 5}, {"subsparsefull", (DL_FUNC) &F77_NAME(subsparsefull ), 5}, {"cleanspam", (DL_FUNC) &F77_NAME(cleanspam ), 5}, {"getbwd", (DL_FUNC) &F77_NAME(getbwd ), 5}, {"rowsums", (DL_FUNC) &F77_NAME(rowsums ), 4}, {"sortrows", (DL_FUNC) &F77_NAME(sortrows ), 4}, {"constructia", (DL_FUNC) &F77_NAME(constructia ), 4}, {"diagmua", (DL_FUNC) &F77_NAME(diagmua ), 4}, {NULL, NULL, 0} }; void R_init_spam(DllInfo *dll) { R_registerRoutines(dll, NULL, NULL, FortranEntries, NULL); R_useDynamicSymbols(dll, FALSE); } spam/src/rowcolstats.f0000644000176200001440000000776413574431374014565 0ustar liggesusers c----------------------------------------------------------------------- subroutine rowsums(a, ia, nrw, rs) c----------------------------------------------------------------------- c purpose: c -------- c c c Reinhard Furrer 2012-04-04 c----------------------------------------------------------------------- c parameters: c ----------- c on entry: c---------- c a, ia = the matrix a in compressed sparse row format (input). c nrw = number of rows c c on return: c----------- c rs = rowsums of a c c note: c------ c no error testing is done. It is assumed that b has enough space c allocated. c----------------------------------------------------------------------- implicit none integer ia(*), nrw double precision a(*), rs(*) c c local variables. c integer irw, jja c do irw = 1,nrw do jja = ia(irw),ia(irw+1)-1 rs(irw) = rs(irw)+a(jja) enddo c end irw, we've cycled over all lines enddo return c--------end-of-rowsums------------------------------------------------ c----------------------------------------------------------------------- end c----------------------------------------------------------------------- subroutine rowmeans(a, ia, nrw, ncl, flag, rs) c----------------------------------------------------------------------- c purpose: c -------- c see above c c Reinhard Furrer 2012-04-04 c----------------------------------------------------------------------- implicit none integer ia(*), nrw, ncl, flag double precision a(*), rs(*) c c local variables. c integer irw, jja c do irw = 1,nrw do jja = ia(irw),ia(irw+1)-1 rs(irw) = rs(irw)+a(jja) enddo if (flag.eq.1) then if ((ia(irw+1)-ia(irw)).gt.0) then rs(irw) = rs(irw)/(ia(irw+1)-ia(irw)) endif else rs(irw) = rs(irw)/ncl endif c end irw, we've cycled over all lines enddo return c--------end-of-rowmeans------------------------------------------------ c----------------------------------------------------------------------- end c----------------------------------------------------------------------- subroutine colsums(a,ja,ia, nrw, cs) c----------------------------------------------------------------------- c purpose: c -------- c see above c c Reinhard Furrer 2012-04-04 c----------------------------------------------------------------------- implicit none integer ia(*),ja(*), nrw double precision a(*), cs(*) c c local variables. c integer ij c do ij = 1,ia(nrw+1)-1 cs( ja( ij)) = cs( ja( ij)) + a(ij) enddo return c--------end-of-colsums------------------------------------------------ c----------------------------------------------------------------------- end c----------------------------------------------------------------------- subroutine colmeans(a,ja,ia, nrw, ncl, flag, cs,nnzc) c----------------------------------------------------------------------- c purpose: c -------- c see above c c nnzc needs to be initialized by R!!!! c Reinhard Furrer 2012-04-04 c----------------------------------------------------------------------- implicit none integer ia(*),ja(*), nrw, ncl, flag, nnzc(ncl) double precision a(*), cs(*) c c local variables. c integer ij c do ij = 1,ia(nrw+1)-1 cs( ja( ij)) = cs( ja( ij)) + a(ij) nnzc( ja( ij)) = nnzc( ja( ij)) + 1 enddo if (flag.eq.1) then do ij = 1, ncl if (nnzc(ij).gt.0) then cs(ij)=cs(ij)/ nnzc(ij) endif enddo else do ij = 1, ncl cs(ij)=cs(ij)/nrw enddo endif return c--------end-of-colmeans------------------------------------------------ c----------------------------------------------------------------------- end spam/src/Makevars0000644000176200001440000000030313574431374013504 0ustar liggesusersPKG_LIBS = $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS) # Fortran 77 flags: # PKG_FCFLAGS = -fopenmp # Fortran 9x flags: # PKG_FFLAGS = -fopenmp # C-Flags # PKG_CFLAGS = -fopenmp # PKG_LIBS = -fopenmp spam/src/dgetv0.f0000644000176200001440000002713413574431374013363 0ustar liggesusersc\BeginDoc c c\Name: dgetv0 c c\Description: c Generate a random initial residual vector for the Arnoldi process. c Force the residual vector to be in the range of the operator OP. c c\Usage: c call dgetv0 c ( IDO, BMAT, ITRY, INITV, N, J, V, LDV, RESID, RNORM, c IPNTR, WORKD, IERR ) c c\Arguments c IDO Integer. (INPUT/OUTPUT) c Reverse communication flag. IDO must be zero on the first c call to dgetv0. c ------------------------------------------------------------- c IDO = 0: first call to the reverse communication interface c IDO = -1: compute Y = OP * X where c IPNTR(1) is the pointer into WORKD for X, c IPNTR(2) is the pointer into WORKD for Y. c This is for the initialization phase to force the c starting vector into the range of OP. c IDO = 2: compute Y = B * X where c IPNTR(1) is the pointer into WORKD for X, c IPNTR(2) is the pointer into WORKD for Y. c IDO = 99: done c ------------------------------------------------------------- c c BMAT Character*1. (INPUT) c BMAT specifies the type of the matrix B in the (generalized) c eigenvalue problem A*x = lambda*B*x. c B = 'I' -> standard eigenvalue problem A*x = lambda*x c B = 'G' -> generalized eigenvalue problem A*x = lambda*B*x c c ITRY Integer. (INPUT) c ITRY counts the number of times that dgetv0 is called. c It should be set to 1 on the initial call to dgetv0. c c INITV Logical variable. (INPUT) c .TRUE. => the initial residual vector is given in RESID. c .FALSE. => generate a random initial residual vector. c c N Integer. (INPUT) c Dimension of the problem. c c J Integer. (INPUT) c Index of the residual vector to be generated, with respect to c the Arnoldi process. J > 1 in case of a "restart". c c V Double precision N by J array. (INPUT) c The first J-1 columns of V contain the current Arnoldi basis c if this is a "restart". c c LDV Integer. (INPUT) c Leading dimension of V exactly as declared in the calling c program. c c RESID Double precision array of length N. (INPUT/OUTPUT) c Initial residual vector to be generated. If RESID is c provided, force RESID into the range of the operator OP. c c RNORM Double precision scalar. (OUTPUT) c B-norm of the generated residual. c c IPNTR Integer array of length 3. (OUTPUT) c c WORKD Double precision work array of length 2*N. (REVERSE COMMUNICATION). c On exit, WORK(1:N) = B*RESID to be used in SSAITR. c c IERR Integer. (OUTPUT) c = 0: Normal exit. c = -1: Cannot generate a nontrivial restarted residual vector c in the range of the operator OP. c c\EndDoc c c----------------------------------------------------------------------- c c\BeginLib c c\Local variables: c xxxxxx real c c\References: c 1. D.C. Sorensen, "Implicit Application of Polynomial Filters in c a k-Step Arnoldi Method", SIAM J. Matr. Anal. Apps., 13 (1992), c pp 357-385. c 2. R.B. Lehoucq, "Analysis and Implementation of an Implicitly c Restarted Arnoldi Iteration", Rice University Technical Report c TR95-13, Department of Computational and Applied Mathematics. c c\Routines called: c second ARPACK utility routine for timing. c dvout ARPACK utility routine for vector output. c dlarnv LAPACK routine for generating a random vector. c dgemv Level 2 BLAS routine for matrix vector multiplication. c dcopy Level 1 BLAS that copies one vector to another. c ddot Level 1 BLAS that computes the scalar product of two vectors. c dnrm2 Level 1 BLAS that computes the norm of a vector. c c\Author c Danny Sorensen Phuong Vu c Richard Lehoucq CRPC / Rice University c Dept. of Computational & Houston, Texas c Applied Mathematics c Rice University c Houston, Texas c c\SCCS Information: @(#) c FILE: getv0.F SID: 2.7 DATE OF SID: 04/07/99 RELEASE: 2 c c\EndLib c c----------------------------------------------------------------------- c subroutine dgetv0 & ( ido, bmat, initv, n, j, v, ldv, resid, rnorm, & ipntr, workd, ierr ) c c %----------------------------------------------------% c | Include files for debugging and timing information | c %----------------------------------------------------% implicit none c c %------------------% c | Scalar Arguments | c %------------------% c character bmat*1 logical initv integer ido, ierr, j, ldv, n Double precision & rnorm c c %-----------------% c | Array Arguments | c %-----------------% c integer ipntr(3) Double precision & resid(n), v(ldv,j), workd(2*n) c c %------------% c | Parameters | c %------------% c Double precision & one, zero parameter (one = 1.0D+0, zero = 0.0D+0) c c %------------------------% c | Local Scalars & Arrays | c %------------------------% c logical first, inits, orth integer idist, iseed(4), iter, jj Double precision & rnorm0 save first, iseed, inits, iter, orth, rnorm0 c c %----------------------% c | External Subroutines | c %----------------------% c external dlarnv, dcopy, dgemv c c %--------------------% c | External Functions | c %--------------------% c Double precision & ddot, dnrm2 external ddot, dnrm2 c c %---------------------% c | Intrinsic Functions | c %---------------------% c intrinsic abs, sqrt c c %-----------------% c | Data Statements | c %-----------------% c data inits /.true./ c c %-----------------------% c | Executable Statements | c %-----------------------% c c c %-----------------------------------% c | Initialize the seed of the LAPACK | c | random number generator | c %-----------------------------------% c if (inits) then iseed(1) = 1 iseed(2) = 3 iseed(3) = 5 iseed(4) = 7 inits = .true. end if c if (ido .eq. 0) then c c %-------------------------------% c | Initialize timing statistics | c | & message level for debugging | c %-------------------------------% c ierr = 0 iter = 0 first = .FALSE. orth = .FALSE. c c %-----------------------------------------------------% c | Possibly generate a random starting vector in RESID | c | Use a LAPACK random number generator used by the | c | matrix generation routines. | c | idist = 1: uniform (0,1) distribution; | c | idist = 2: uniform (-1,1) distribution; | c | idist = 3: normal (0,1) distribution; | c %-----------------------------------------------------% c if (.not.initv) then idist = 2 call dlarnv (idist, iseed, n, resid) end if c c %----------------------------------------------------------% c | Force the starting vector into the range of OP to handle | c | the generalized problem when B is possibly (singular). | c %----------------------------------------------------------% c if (bmat .eq. 'G') then ipntr(1) = 1 ipntr(2) = n + 1 call dcopy (n, resid, 1, workd, 1) ido = -1 go to 9000 end if end if c c %-----------------------------------------% c | Back from computing OP*(initial-vector) | c %-----------------------------------------% c if (first) go to 20 c c %-----------------------------------------------% c | Back from computing B*(orthogonalized-vector) | c %-----------------------------------------------% c if (orth) go to 40 c c %------------------------------------------------------% c | Starting vector is now in the range of OP; r = OP*r; | c | Compute B-norm of starting vector. | c %------------------------------------------------------% c first = .TRUE. if (bmat .eq. 'G') then call dcopy (n, workd(n+1), 1, resid, 1) ipntr(1) = n + 1 ipntr(2) = 1 ido = 2 go to 9000 else if (bmat .eq. 'I') then call dcopy (n, resid, 1, workd(:), 1) end if c 20 continue c first = .FALSE. if (bmat .eq. 'G') then rnorm0 = ddot (n, resid, 1, workd, 1) rnorm0 = sqrt(abs(rnorm0)) else if (bmat .eq. 'I') then rnorm0 = dnrm2(n, resid, 1) end if rnorm = rnorm0 c c %---------------------------------------------% c | Exit if this is the very first Arnoldi step | c %---------------------------------------------% c if (j .eq. 1) go to 50 c c %---------------------------------------------------------------- c | Otherwise need to B-orthogonalize the starting vector against | c | the current Arnoldi basis using Gram-Schmidt with iter. ref. | c | This is the case where an invariant subspace is encountered | c | in the middle of the Arnoldi factorization. | c | | c | s = V^{T}*B*r; r = r - V*s; | c | | c | Stopping criteria used for iter. ref. is discussed in | c | Parlett's book, page 107 and in Gragg & Reichel TOMS paper. | c %---------------------------------------------------------------% c orth = .TRUE. 30 continue c call dgemv ('T', n, j-1, one, v, ldv, workd(:), 1, & zero, workd(n+1), 1) call dgemv ('N', n, j-1, -one, v, ldv, workd(n+1), 1, & one, resid(n), 1) c c %----------------------------------------------------------% c | Compute the B-norm of the orthogonalized starting vector | c %----------------------------------------------------------% c if (bmat .eq. 'G') then call dcopy (n, resid, 1, workd(n+1), 1) ipntr(1) = n + 1 ipntr(2) = 1 ido = 2 go to 9000 else if (bmat .eq. 'I') then call dcopy (n, resid, 1, workd, 1) end if c 40 continue c if (bmat .eq. 'G') then rnorm = ddot (n, resid, 1, workd, 1) rnorm = sqrt(abs(rnorm)) else if (bmat .eq. 'I') then rnorm = dnrm2(n, resid, 1) end if c c %--------------------------------------% c | Check for further orthogonalization. | c %--------------------------------------% c if (rnorm .gt. 0.717*rnorm0) go to 50 c iter = iter + 1 if (iter .le. 5) then c c %-----------------------------------% c | Perform iterative refinement step | c %-----------------------------------% c rnorm0 = rnorm go to 30 else c c %------------------------------------% c | Iterative refinement step "failed" | c %------------------------------------% c do 45 jj = 1, n resid(jj) = zero 45 continue rnorm = zero ierr = -1 end if c 50 continue c ido = 99 c 9000 continue return c c %---------------% c | End of dgetv0 | c %---------------% c end spam/src/kronecker.f0000644000176200001440000000340313574431374014146 0ustar liggesusers subroutine kroneckermult(xnrow,xent,xcol,xrow, & ynrow,yncol,yent,ycol,yrow, & ent, col, row) implicit none integer xnrow,ynrow,yncol, xcol(*), xrow(*) integer ycol(*), yrow(*), col(*), row(*) double precision xent(*), yent(*), ent(*) integer i,k,j,l,n,nr,xdiffi,ydiffk n = 1 nr = 2 row(1) = 1 do i = 1,xnrow xdiffi = xrow(i+1)-xrow(i) do k = 1,ynrow ydiffk = yrow(k+1)-yrow(k) do j = 1,xdiffi do l = 1,ydiffk ent(n) = xent(j+xrow(i)-1)*yent(l+yrow(k)-1) col(n) = ycol(l+yrow(k)-1)+ & (xcol(j+xrow(i)-1)-1)*yncol n=n+1 enddo enddo row(nr) = n nr = nr+1 enddo enddo return end subroutine kroneckerf(xnrow,xent,xcol,xrow, & ynrow,yncol,yent,ycol,yrow, & ent1, ent2, col, row) implicit none integer xnrow,ynrow,yncol, xcol(*), xrow(*) integer ycol(*), yrow(*), col(*), row(*) double precision xent(*), yent(*), ent1(*), ent2(*) integer i,k,j,l,n,nr,xdiffi,ydiffk n = 1 nr = 2 row(1) = 1 do i = 1,xnrow xdiffi = xrow(i+1)-xrow(i)-1 do k = 1,ynrow ydiffk = yrow(k+1)-yrow(k)-1 do j = 0,xdiffi do l = 0,ydiffk ent1(n) = xent(j+xrow(i)) ent2(n)= yent(l+yrow(k)) col(n) = ycol(l+yrow(k))+ & (xcol(j+xrow(i))-1)*yncol n=n+1 enddo enddo row(nr) = n nr = nr+1 enddo enddo return end spam/src/permutation.f0000644000176200001440000003346513574431374014545 0ustar liggesusersc It has been tested that embedding the loop over the right hand c side into the backsolve routine is not faster. c----------------------------------------------------------------------- subroutine getbwd(n, ja,ia,ml,mu) c----------------------------------------------------------------------- c gets the bandwidth of lower part and upper part of A. c does not assume that A is sorted. c----------------------------------------------------------------------- c on entry: c---------- c n = integer = the row dimension of the matrix c ja, ia = matrix in compressed sparse row format. c c on return: c----------- c ml = integer. The bandwidth of the strict lower part of A c mu = integer. The bandwidth of the strict upper part of A c c Notes: c ===== ml and mu are allowed to be negative or return. This may be c useful since it will tell us whether a band is confined c in the strict upper/lower triangular part. c indeed the definitions of ml and mu are c c ml = max ( (i-j) s.t. a(i,j) .ne. 0 ) c mu = max ( (j-i) s.t. a(i,j) .ne. 0 ) c----------------------------------------------------------------------c c Y. Saad, Sep. 21 1989 | simplified by R. Furrer Sept. 2016 c c----------------------------------------------------------------------c implicit none c double precision a(*) integer n,ja(*),ia(n+1),ml,mu integer ldist,i,k ml = - n mu = - n do 3 i=1,n do 31 k=ia(i),ia(i+1)-1 ldist = i-ja(k) ml = max(ml,ldist) mu = max(mu,-ldist) 31 continue 3 continue return c---------------end-of-getbwd ------------------------------------------ c----------------------------------------------------------------------- end c functions slightly modified from sparsekit: c cperm,rperm,dperm: job argument is eliminated c----------------------------------------------------------------------- c----------------------------------------------------------------------- subroutine rperm (nrow,a,ja,ia,ao,jao,iao,perm) implicit none integer nrow,ja(*),ia(nrow+1),jao(*),iao(nrow+1),perm(nrow) double precision a(*),ao(*) c----------------------------------------------------------------------- c this subroutine permutes the rows of a matrix in CSR format. c rperm computes B = P A where P is a permutation matrix. c the permutation P is defined through the array perm: for each j, c perm(j) represents the destination row number of row number j. c Youcef Saad -- recoded Jan 28, 1991. c----------------------------------------------------------------------- c on entry: c---------- c n = dimension of the matrix c a, ja, ia = input matrix in csr format c perm = integer array of length nrow containing the permutation arrays c for the rows: perm(i) is the destination of row i in the c permuted matrix. c ---> a(i,j) in the original matrix becomes a(perm(i),j) c in the output matrix. c c c------------ c on return: c------------ c ao, jao, iao = input matrix in a, ja, ia format c----------------------------------------------------------------------c c Y. Saad, May 2, 1990 c c----------------------------------------------------------------------c integer i,j,k,ko,ii c determine pointers for output matix. c do 50 j=1,nrow i = perm(j) iao(i+1) = ia(j+1) - ia(j) 50 continue c c get pointers from lengths c iao(1) = 1 do 51 j=1,nrow iao(j+1)=iao(j+1)+iao(j) 51 continue c c copying c do 100 ii=1,nrow c c old row = ii -- new row = iperm(ii) -- ko = new pointer c ko = iao(perm(ii)) do 60 k=ia(ii), ia(ii+1)-1 jao(ko) = ja(k) ao(ko) = a(k) ko = ko+1 60 continue 100 continue c return c---------end-of-rperm ------------------------------------------------- c----------------------------------------------------------------------- end c----------------------------------------------------------------------- subroutine cperm (nrow,a,ja,ia,ao,jao,iao,perm) implicit none integer nrow,ja(*),ia(nrow+1),jao(*),iao(nrow+1),perm(*) double precision a(*), ao(*) c----------------------------------------------------------------------- c this subroutine permutes the columns of a matrix a, ja, ia. c the result is written in the output matrix ao, jao, iao. c cperm computes B = A P, where P is a permutation matrix c that maps column j into column perm(j), i.e., on return c a(i,j) becomes a(i,perm(j)) in new matrix c Y. Saad, May 2, 1990 / modified Jan. 28, 1991. c----------------------------------------------------------------------- c on entry: c---------- c nrow = row dimension of the matrix c c a, ja, ia = input matrix in csr format. c c perm = integer array of length ncol (number of columns of A c containing the permutation array the columns: c a(i,j) in the original matrix becomes a(i,perm(j)) c in the output matrix. c c c------------ c on return: c------------ c ao, jao, iao = input matrix in a, ja, ia format c c Notes: c------- c 1. if job=1 then ao, iao are not used. c 2. This routine is in place: ja, jao can be the same. c 3. If the matrix is initially sorted (by increasing column number) c then ao,jao,iao may not be on return, hence a call to csort. c c----------------------------------------------------------------------c c local parameters: integer k, i, nnz c nnz = ia(nrow+1)-1 do 100 k=1,nnz jao(k) = perm(ja(k)) 100 continue c c done with ja array. c do 1 i=1, nrow+1 iao(i) = ia(i) 1 continue c do 2 k=1, nnz ao(k) = a(k) 2 continue c call sortrows(nrow,ao,jao,iao) c call csort (nrow,ao,jao,iao,iwork) _does not work_ return c---------end-of-cperm-------------------------------------------------- c----------------------------------------------------------------------- end c----------------------------------------------------------------------- subroutine dperm (nrow,a,ja,ia,ao,jao,iao,pperm,qperm) implicit none integer nrow,ja(*),ia(nrow+1),jao(*),iao(nrow+1),pperm(nrow), + qperm(*) double precision a(*),ao(*) c----------------------------------------------------------------------- c This routine permutes the rows and columns of a matrix stored in CSR c format. i.e., it computes P A Q, where P, Q are permutation matrices. c P maps row i into row perm(i) and Q maps column j into column qperm(j): c a(i,j) becomes a(pperm(i),qperm(j)) in new matrix c note that qperm should be of length ncol (number of columns) but this c is not checked. c----------------------------------------------------------------------- c Y. Saad, Sep. 21 1989 / recoded Jan. 28 1991. c----------------------------------------------------------------------- c on entry: c---------- c n = dimension of the matrix c a, ja, c ia = input matrix in a, ja, ia format c pperm = integer array of length n containing the permutation arrays c for the rows: pperm(i) is the destination of row i in the c permuted matrix c c qperm = same thing for the columns. c iwork = working array passed to cperm c c on return: c----------- c ao, jao, iao = input matrix in a, ja, ia format c c Notes: c------- c 1) algorithm is in place c----------------------------------------------------------------------c c local variables c c permute rows first c call rperm (nrow,a,ja,ia, ao,jao,iao,pperm) c c then permute columns c c call cperm (nrow,ao,jao,iao,ao,jao,iao,qperm) c return c-------end-of-dperm---------------------------------------------------- c----------------------------------------------------------------------- end c----------------------------------------------------------------------- subroutine dvperm (n, x, perm) implicit none integer n integer perm(n) double precision x(n) c----------------------------------------------------------------------- c this subroutine performs an in-place permutation of a real vector x c according to the permutation array perm(*), i.e., on return, c the vector x satisfies, c c x(perm(j)) :== x(j), j=1,2,.., n c c----------------------------------------------------------------------- c on entry: c--------- c n = length of vector x. c perm = integer array of length n containing the permutation array. c x = input vector c c on return: c---------- c x = vector x permuted according to x(perm(*)) := x(*) c c----------------------------------------------------------------------c c Y. Saad, Sep. 21 1989 c c----------------------------------------------------------------------c c local variables integer init,next,k, ii, j double precision tmp, tmp1 c init = 1 tmp = x(init) ii = perm(init) perm(init)= -perm(init) k = 0 c c loop c 6 k = k+1 c c save the chased element -- c tmp1 = x(ii) x(ii) = tmp next = perm(ii) if (next .lt. 0 ) goto 65 c c test for end c if (k .gt. n) goto 101 tmp = tmp1 perm(ii) = - perm(ii) ii = next c c end loop c goto 6 c c reinitilaize cycle -- c 65 init = init+1 if (init .gt. n) goto 101 if (perm(init) .lt. 0) goto 65 tmp = x(init) ii = perm(init) perm(init)=-perm(init) goto 6 c 101 continue do 200 j=1, n perm(j) = -perm(j) 200 continue c return c-------------------end-of-dvperm--------------------------------------- c----------------------------------------------------------------------- end c----------------------------------------------------------------------- subroutine ivperm (n, ix, perm) implicit none integer n, perm(n+1), ix(n) c----------------------------------------------------------------------- c this subroutine performs an in-place permutation of an integer vector c ix according to the permutation array perm(*), i.e., on return, c the vector x satisfies, c c ix(perm(j)) :== ix(j), j=1,2,.., n c c----------------------------------------------------------------------- c on entry: c--------- c n = length of vector x. c perm = integer array of length n containing the permutation array. c ix = input vector c c on return: c---------- c ix = vector x permuted according to ix(perm(*)) := ix(*) c c----------------------------------------------------------------------c c Y. Saad, Sep. 21 1989 c c----------------------------------------------------------------------c c local variables integer ii,k,j,next,init,tmp, tmp1 c init = 1 tmp = ix(init) ii = perm(init) perm(init)= -perm(init) k = 0 c c loop c 6 k = k+1 c c save the chased element -- c tmp1 = ix(ii) ix(ii) = tmp next = perm(ii) if (next .lt. 0 ) goto 65 c c test for end c if (k .gt. n) goto 101 tmp = tmp1 perm(ii) = - perm(ii) ii = next c c end loop c goto 6 c c reinitilaize cycle -- c 65 init = init+1 if (init .gt. n) goto 101 if (perm(init) .lt. 0) goto 65 tmp = ix(init) ii = perm(init) perm(init)=-perm(init) goto 6 c 101 continue do 200 j=1, n c if (perm(j) .lt. 0) then perm(j) = -perm(j) c endif 200 continue c return c-------------------end-of-ivperm--------------------------------------- c----------------------------------------------------------------------- end c c----------------------------------------------------------------------- subroutine aplbdg (nrow,ncol,ja,ia,jb,ib,ndegr,nnz,iw) implicit none integer nrow, ncol, nnz integer ja(*),jb(*),ia(nrow+1),ib(nrow+1),iw(ncol),ndegr(nrow) c----------------------------------------------------------------------- c gets the number of nonzero elements in each row of A+B and the total c number of nonzero elements in A+B. c----------------------------------------------------------------------- c on entry: c --------- c nrow = integer. The row dimension of A and B c ncol = integer. The column dimension of A and B. c c a, c ja, c ia = Matrix A in compressed sparse row format. c c b, c jb, c ib = Matrix B in compressed sparse row format. c c iw,nnz,ngegr = zero content c c on return: c---------- c ndegr = integer array of length nrow containing the degrees (i.e., c the number of nonzeros in each row of the matrix A + B. c c nnz = total number of nonzero elements found in A * B c c work arrays: c------------ c iw = integer work array of length equal to ncol. c c----------------------------------------------------------------------- integer k,j,ii,jr,last,ldg,jc do 7 ii=1,nrow ldg = 0 c c end-of-linked list c last = -1 c c row of A c do 5 j = ia(ii),ia(ii+1)-1 jr = ja(j) c c add element to the linked list c ldg = ldg + 1 iw(jr) = last last = jr 5 continue c c row of B c do 6 j=ib(ii),ib(ii+1)-1 jc = jb(j) if (iw(jc) .eq. 0) then c c add one element to the linked list c ldg = ldg + 1 iw(jc) = last last = jc endif 6 continue c done with row ii. ndegr(ii) = ldg c c reset iw to zero c do 61 k=1,ldg j = iw(last) iw(last) = 0 last = j 61 continue c----------------------------------------------------------------------- 7 continue c do 8 ii=1, nrow nnz = nnz+ndegr(ii) 8 continue return c----------------end-of-aplbdg ----------------------------------------- c----------------------------------------------------------------------- end spam/src/dn_ARPACK.f0000644000176200001440000057050713574431374013623 0ustar liggesusersc c dneupd.f c dnaupd.f c dnaup2.f c dnapps.f c dnconv.f c dsortc.f c dneigh.f c dlaqrb.f c dngets.f c dgetv0.f c dnaitr.f c c\BeginDoc c c\Name: dneupd c c\Description: c c This subroutine returns the converged approximations to eigenvalues c of A*z = lambda*B*z and (optionally): c c (1) The corresponding approximate eigenvectors; c c (2) An orthonormal basis for the associated approximate c invariant subspace; c c (3) Both. c c There is negligible additional cost to obtain eigenvectors. An orthonormal c basis is always computed. There is an additional storage cost of n*nev c if both are requested (in this case a separate array Z must be supplied). c c The approximate eigenvalues and eigenvectors of A*z = lambda*B*z c are derived from approximate eigenvalues and eigenvectors of c of the linear operator OP prescribed by the MODE selection in the c call to DNAUPD . DNAUPD must be called before this routine is called. c These approximate eigenvalues and vectors are commonly called Ritz c values and Ritz vectors respectively. They are referred to as such c in the comments that follow. The computed orthonormal basis for the c invariant subspace corresponding to these Ritz values is referred to as a c Schur basis. c c See documentation in the header of the subroutine DNAUPD for c definition of OP as well as other terms and the relation of computed c Ritz values and Ritz vectors of OP with respect to the given problem c A*z = lambda*B*z. For a brief description, see definitions of c IPARAM(7), MODE and WHICH in the documentation of DNAUPD . c c\Usage: c call dneupd c ( RVEC, HOWMNY, SELECT, DR, DI, Z, LDZ, SIGMAR, SIGMAI, WORKEV, BMAT, c N, WHICH, NEV, TOL, RESID, NCV, V, LDV, IPARAM, IPNTR, WORKD, WORKL, c LWORKL, INFO ) c c\Arguments: c RVEC LOGICAL (INPUT) c Specifies whether a basis for the invariant subspace corresponding c to the converged Ritz value approximations for the eigenproblem c A*z = lambda*B*z is computed. c c RVEC = .FALSE. Compute Ritz values only. c c RVEC = .TRUE. Compute the Ritz vectors or Schur vectors. c See Remarks below. c c HOWMNY Character*1 (INPUT) c Specifies the form of the basis for the invariant subspace c corresponding to the converged Ritz values that is to be computed. c c = 'A': Compute NEV Ritz vectors; c = 'P': Compute NEV Schur vectors; c = 'S': compute some of the Ritz vectors, specified c by the logical array SELECT. c c SELECT Logical array of dimension NCV. (INPUT) c If HOWMNY = 'S', SELECT specifies the Ritz vectors to be c computed. To select the Ritz vector corresponding to a c Ritz value (DR(j), DI(j)), SELECT(j) must be set to .TRUE.. c If HOWMNY = 'A' or 'P', SELECT is used as internal workspace. c c DR Double precision array of dimension NEV+1. (OUTPUT) c If IPARAM(7) = 1,2 or 3 and SIGMAI=0.0 then on exit: DR contains c the real part of the Ritz approximations to the eigenvalues of c A*z = lambda*B*z. c If IPARAM(7) = 3, 4 and SIGMAI is not equal to zero, then on exit: c DR contains the real part of the Ritz values of OP computed by c DNAUPD . A further computation must be performed by the user c to transform the Ritz values computed for OP by DNAUPD to those c of the original system A*z = lambda*B*z. See remark 3 below. c c DI Double precision array of dimension NEV+1. (OUTPUT) c On exit, DI contains the imaginary part of the Ritz value c approximations to the eigenvalues of A*z = lambda*B*z associated c with DR. c c NOTE: When Ritz values are complex, they will come in complex c conjugate pairs. If eigenvectors are requested, the c corresponding Ritz vectors will also come in conjugate c pairs and the real and imaginary parts of these are c represented in two consecutive columns of the array Z c (see below). c c Z Double precision N by NEV+1 array if RVEC = .TRUE. and HOWMNY = 'A'. (OUTPUT) c On exit, if RVEC = .TRUE. and HOWMNY = 'A', then the columns of c Z represent approximate eigenvectors (Ritz vectors) corresponding c to the NCONV=IPARAM(5) Ritz values for eigensystem c A*z = lambda*B*z. c c The complex Ritz vector associated with the Ritz value c with positive imaginary part is stored in two consecutive c columns. The first column holds the real part of the Ritz c vector and the second column holds the imaginary part. The c Ritz vector associated with the Ritz value with negative c imaginary part is simply the complex conjugate of the Ritz vector c associated with the positive imaginary part. c c If RVEC = .FALSE. or HOWMNY = 'P', then Z is not referenced. c c NOTE: If if RVEC = .TRUE. and a Schur basis is not required, c the array Z may be set equal to first NEV+1 columns of the Arnoldi c basis array V computed by DNAUPD . In this case the Arnoldi basis c will be destroyed and overwritten with the eigenvector basis. c c LDZ Integer. (INPUT) c The leading dimension of the array Z. If Ritz vectors are c desired, then LDZ >= max( 1, N ). In any case, LDZ >= 1. c c SIGMAR Double precision (INPUT) c If IPARAM(7) = 3 or 4, represents the real part of the shift. c Not referenced if IPARAM(7) = 1 or 2. c c SIGMAI Double precision (INPUT) c If IPARAM(7) = 3 or 4, represents the imaginary part of the shift. c Not referenced if IPARAM(7) = 1 or 2. See remark 3 below. c c WORKEV Double precision work array of dimension 3*NCV. (WORKSPACE) c c **** The remaining arguments MUST be the same as for the **** c **** call to DNAUPD that was just completed. **** c c NOTE: The remaining arguments c c BMAT, N, WHICH, NEV, TOL, RESID, NCV, V, LDV, IPARAM, IPNTR, c WORKD, WORKL, LWORKL, INFO c c must be passed directly to DNEUPD following the last call c to DNAUPD . These arguments MUST NOT BE MODIFIED between c the the last call to DNAUPD and the call to DNEUPD . c c Three of these parameters (V, WORKL, INFO) are also output parameters: c c V Double precision N by NCV array. (INPUT/OUTPUT) c c Upon INPUT: the NCV columns of V contain the Arnoldi basis c vectors for OP as constructed by DNAUPD . c c Upon OUTPUT: If RVEC = .TRUE. the first NCONV=IPARAM(5) columns c contain approximate Schur vectors that span the c desired invariant subspace. See Remark 2 below. c c NOTE: If the array Z has been set equal to first NEV+1 columns c of the array V and RVEC=.TRUE. and HOWMNY= 'A', then the c Arnoldi basis held by V has been overwritten by the desired c Ritz vectors. If a separate array Z has been passed then c the first NCONV=IPARAM(5) columns of V will contain approximate c Schur vectors that span the desired invariant subspace. c c WORKL Double precision work array of length LWORKL. (OUTPUT/WORKSPACE) c WORKL(1:ncv*ncv+3*ncv) contains information obtained in c dnaupd . They are not changed by dneupd . c WORKL(ncv*ncv+3*ncv+1:3*ncv*ncv+6*ncv) holds the c real and imaginary part of the untransformed Ritz values, c the upper quasi-triangular matrix for H, and the c associated matrix representation of the invariant subspace for H. c c Note: IPNTR(9:13) contains the pointer into WORKL for addresses c of the above information computed by dneupd . c ------------------------------------------------------------- c IPNTR(9): pointer to the real part of the NCV RITZ values of the c original system. c IPNTR(10): pointer to the imaginary part of the NCV RITZ values of c the original system. c IPNTR(11): pointer to the NCV corresponding error bounds. c IPNTR(12): pointer to the NCV by NCV upper quasi-triangular c Schur matrix for H. c IPNTR(13): pointer to the NCV by NCV matrix of eigenvectors c of the upper Hessenberg matrix H. Only referenced by c dneupd if RVEC = .TRUE. See Remark 2 below. c ------------------------------------------------------------- c c INFO Integer. (OUTPUT) c Error flag on output. c c = 0: Normal exit. c c = 1: The Schur form computed by LAPACK routine dlahqr c could not be reordered by LAPACK routine dtrsen . c Re-enter subroutine dneupd with IPARAM(5)=NCV and c increase the size of the arrays DR and DI to have c dimension at least dimension NCV and allocate at least NCV c columns for Z. NOTE: Not necessary if Z and V share c the same space. Please notify the authors if this error c occurs. c c = -1: N must be positive. c = -2: NEV must be positive. c = -3: NCV-NEV >= 2 and less than or equal to N. c = -5: WHICH must be one of 'LM', 'SM', 'LR', 'SR', 'LI', 'SI' c = -6: BMAT must be one of 'I' or 'G'. c = -7: Length of private work WORKL array is not sufficient. c = -8: Error return from calculation of a real Schur form. c Informational error from LAPACK routine dlahqr . c = -9: Error return from calculation of eigenvectors. c Informational error from LAPACK routine dtrevc . c = -10: IPARAM(7) must be 1,2,3,4. c = -11: IPARAM(7) = 1 and BMAT = 'G' are incompatible. c = -12: HOWMNY = 'S' not yet implemented c = -13: HOWMNY must be one of 'A' or 'P' if RVEC = .true. c = -14: DNAUPD did not find any eigenvalues to sufficient c accuracy. c = -15: DNEUPD got a different count of the number of converged c Ritz values than DNAUPD got. This indicates the user c probably made an error in passing data from DNAUPD to c DNEUPD or that the data was modified before entering c DNEUPD c c\BeginLib c c\References: c 1. D.C. Sorensen, "Implicit Application of Polynomial Filters in c a k-Step Arnoldi Method", SIAM J. Matr. Anal. Apps., 13 (1992), c pp 357-385. c 2. R.B. Lehoucq, "Analysis and Implementation of an Implicitly c Restarted Arnoldi Iteration", Rice University Technical Report c TR95-13, Department of Computational and Applied Mathematics. c 3. B.N. Parlett & Y. Saad, "Complex Shift and Invert Strategies for c Real Matrices", Linear Algebra and its Applications, vol 88/89, c pp 575-595, (1987). c c\Routines called: c ivout ARPACK utility routine that prints integers. c dmout ARPACK utility routine that prints matrices c dvout ARPACK utility routine that prints vectors. c dgeqr2 LAPACK routine that computes the QR factorization of c a matrix. c dlacpy LAPACK matrix copy routine. c dlahqr LAPACK routine to compute the real Schur form of an c upper Hessenberg matrix. c dlamch LAPACK routine that determines machine constants. c dlapy2 LAPACK routine to compute sqrt(x**2+y**2) carefully. c dlaset LAPACK matrix initialization routine. c dorm2r LAPACK routine that applies an orthogonal matrix in c factored form. c dtrevc LAPACK routine to compute the eigenvectors of a matrix c in upper quasi-triangular form. c dtrsen LAPACK routine that re-orders the Schur form. c dtrmm Level 3 BLAS matrix times an upper triangular matrix. c dger Level 2 BLAS rank one update to a matrix. c dcopy Level 1 BLAS that copies one vector to another . c ddot Level 1 BLAS that computes the scalar product of two vectors. c dnrm2 Level 1 BLAS that computes the norm of a vector. c dscal Level 1 BLAS that scales a vector. c c\Remarks c c 1. Currently only HOWMNY = 'A' and 'P' are implemented. c c Let trans(X) denote the transpose of X. c c 2. Schur vectors are an orthogonal representation for the basis of c Ritz vectors. Thus, their numerical properties are often superior. c If RVEC = .TRUE. then the relationship c A * V(:,1:IPARAM(5)) = V(:,1:IPARAM(5)) * T, and c trans(V(:,1:IPARAM(5))) * V(:,1:IPARAM(5)) = I are approximately c satisfied. Here T is the leading submatrix of order IPARAM(5) of the c real upper quasi-triangular matrix stored workl(ipntr(12)). That is, c T is block upper triangular with 1-by-1 and 2-by-2 diagonal blocks; c each 2-by-2 diagonal block has its diagonal elements equal and its c off-diagonal elements of opposite sign. Corresponding to each 2-by-2 c diagonal block is a complex conjugate pair of Ritz values. The real c Ritz values are stored on the diagonal of T. c c 3. If IPARAM(7) = 3 or 4 and SIGMAI is not equal zero, then the user must c form the IPARAM(5) Rayleigh quotients in order to transform the Ritz c values computed by DNAUPD for OP to those of A*z = lambda*B*z. c Set RVEC = .true. and HOWMNY = 'A', and c compute c trans(Z(:,I)) * A * Z(:,I) if DI(I) = 0. c If DI(I) is not equal to zero and DI(I+1) = - D(I), c then the desired real and imaginary parts of the Ritz value are c trans(Z(:,I)) * A * Z(:,I) + trans(Z(:,I+1)) * A * Z(:,I+1), c trans(Z(:,I)) * A * Z(:,I+1) - trans(Z(:,I+1)) * A * Z(:,I), c respectively. c Another possibility is to set RVEC = .true. and HOWMNY = 'P' and c compute trans(V(:,1:IPARAM(5))) * A * V(:,1:IPARAM(5)) and then an upper c quasi-triangular matrix of order IPARAM(5) is computed. See remark c 2 above. c c\Authors c Danny Sorensen Phuong Vu c Richard Lehoucq CRPC / Rice University c Chao Yang Houston, Texas c Dept. of Computational & c Applied Mathematics c Rice University c Houston, Texas c c\SCCS Information: @(#) c FILE: neupd.F SID: 2.7 DATE OF SID: 09/20/00 RELEASE: 2 c c\EndLib c c----------------------------------------------------------------------- subroutine dneupd (rvec , howmny, select, dr , di, & z , ldz , sigmar, sigmai, workev, & bmat , n , which , nev , tol, & resid, ncv , v , ldv , iparam, & ipntr, workd , workl , lworkl, info) c implicit none c c %------------------% c | Scalar Arguments | c %------------------% c character bmat, howmny, which*2 logical rvec integer info, ldz, ldv, lworkl, n, ncv, nev Double precision & sigmar, sigmai, tol c c %-----------------% c | Array Arguments | c %-----------------% c integer iparam(8), ipntr(14) logical select(ncv) Double precision & dr(nev+1) , di(nev+1), resid(n) , & v(ldv,ncv) , z(ldz,*) , workd(3*n), & workl(lworkl), workev(3*ncv) c c %------------% c | Parameters | c %------------% c Double precision & one, zero parameter (one = 1.0D+0 , zero = 0.0D-5 ) c integer & ione parameter (ione = 1) c c %---------------% c | Local Scalars | c %---------------% c character type*6 integer bounds, ierr , ih , ihbds , & iheigr, iheigi, iconj , nconv , & invsub, iuptri, iwev , iwork(1), & j , k , ldh , ldq , & mode , outncv, ritzr , & ritzi , wri , wrr , irr , & iri , ibd , ishift, numcnv , & np , jj logical reord Double precision & conds , rnorm, sep , temp, & vl(1,1), temp1, eps23 c c %----------------------% c | External Subroutines | c %----------------------% c external dcopy , dger , dgeqr2 , dlacpy , & dlahqr , dlaset , dorm2r , & dtrevc , dtrmm , dtrsen , dscal c c %--------------------% c | External Functions | c %--------------------% c Double precision & dlapy2 , dnrm2 , dlamch , ddot external dlapy2 , dnrm2 , dlamch , ddot c c %---------------------% c | Intrinsic Functions | c %---------------------% c intrinsic abs, min, sqrt c c %-----------------------% c | Executable Statements | c %-----------------------% c c %------------------------% c | Set default parameters | c %------------------------% c mode = iparam(7) nconv = iparam(5) info = 0 c c %---------------------------------% c | Get machine dependent constant. | c %---------------------------------% c eps23 = dlamch ('Epsilon-Machine') eps23 = eps23**(2.0D+0 / 3.0D+0 ) c c %--------------% c | Quick return | c %--------------% c ierr = 0 c if (nconv .le. 0) then ierr = -14 else if (n .le. 0) then ierr = -1 else if (nev .le. 0) then ierr = -2 else if (ncv .le. nev+1 .or. ncv .gt. n) then ierr = -3 else if (which .ne. 'LM' .and. & which .ne. 'SM' .and. & which .ne. 'LR' .and. & which .ne. 'SR' .and. & which .ne. 'LI' .and. & which .ne. 'SI') then ierr = -5 else if (bmat .ne. 'I' .and. bmat .ne. 'G') then ierr = -6 else if (lworkl .lt. 3*ncv**2 + 6*ncv) then ierr = -7 else if ( (howmny .ne. 'A' .and. & howmny .ne. 'P' .and. & howmny .ne. 'S') .and. rvec ) then ierr = -13 else if (howmny .eq. 'S' ) then ierr = -12 end if c if (mode .eq. 1 .or. mode .eq. 2) then type = 'REGULR' else if (mode .eq. 3 .and. (abs(sigmai) .le. zero)) then type = 'SHIFTI' else if (mode .eq. 3 ) then type = 'REALPT' else if (mode .eq. 4 ) then type = 'IMAGPT' else ierr = -10 end if if (mode .eq. 1 .and. bmat .eq. 'G') ierr = -11 c c %------------% c | Error Exit | c %------------% c if (ierr .ne. 0) then info = ierr go to 9000 end if c c %--------------------------------------------------------% c | Pointer into WORKL for address of H, RITZ, BOUNDS, Q | c | etc... and the remaining workspace. | c | Also update pointer to be used on output. | c | Memory is laid out as follows: | c | workl(1:ncv*ncv) := generated Hessenberg matrix | c | workl(ncv*ncv+1:ncv*ncv+2*ncv) := real and imaginary | c | parts of ritz values | c | workl(ncv*ncv+2*ncv+1:ncv*ncv+3*ncv) := error bounds | c %--------------------------------------------------------% c c %-----------------------------------------------------------% c | The following is used and set by DNEUPD . | c | workl(ncv*ncv+3*ncv+1:ncv*ncv+4*ncv) := The untransformed | c | real part of the Ritz values. | c | workl(ncv*ncv+4*ncv+1:ncv*ncv+5*ncv) := The untransformed | c | imaginary part of the Ritz values. | c | workl(ncv*ncv+5*ncv+1:ncv*ncv+6*ncv) := The untransformed | c | error bounds of the Ritz values | c | workl(ncv*ncv+6*ncv+1:2*ncv*ncv+6*ncv) := Holds the upper | c | quasi-triangular matrix for H | c | workl(2*ncv*ncv+6*ncv+1: 3*ncv*ncv+6*ncv) := Holds the | c | associated matrix representation of the invariant | c | subspace for H. | c | GRAND total of NCV * ( 3 * NCV + 6 ) locations. | c %-----------------------------------------------------------% c ih = ipntr(5) ritzr = ipntr(6) ritzi = ipntr(7) bounds = ipntr(8) ldh = ncv ldq = ncv iheigr = bounds + ldh iheigi = iheigr + ldh ihbds = iheigi + ldh iuptri = ihbds + ldh invsub = iuptri + ldh*ncv ipntr(9) = iheigr ipntr(10) = iheigi ipntr(11) = ihbds ipntr(12) = iuptri ipntr(13) = invsub wrr = 1 wri = ncv + 1 iwev = wri + ncv c c %-----------------------------------------% c | irr points to the REAL part of the Ritz | c | values computed by _neigh before | c | exiting _naup2. | c | iri points to the IMAGINARY part of the | c | Ritz values computed by _neigh | c | before exiting _naup2. | c | ibd points to the Ritz estimates | c | computed by _neigh before exiting | c | _naup2. | c %-----------------------------------------% c irr = ipntr(14)+ncv*ncv iri = irr+ncv ibd = iri+ncv c c %------------------------------------% c | RNORM is B-norm of the RESID(1:N). | c %------------------------------------% c rnorm = workl(ih+2) workl(ih+2) = zero c c if (rvec) then c reord = .false. c c %---------------------------------------------------% c | Use the temporary bounds array to store indices | c | These will be used to mark the select array later | c %---------------------------------------------------% c do 10 j = 1,ncv workl(bounds+j-1) = j select(j) = .false. 10 continue c c %-------------------------------------% c | Select the wanted Ritz values. | c | Sort the Ritz values so that the | c | wanted ones appear at the tailing | c | NEV positions of workl(irr) and | c | workl(iri). Move the corresponding | c | error estimates in workl(bound) | c | accordingly. | c %-------------------------------------% c np = ncv - nev ishift = 0 call dngets (ishift , which , nev , & np , workl(irr), workl(iri), & workl(bounds)) c c c %-----------------------------------------------------% c | Record indices of the converged wanted Ritz values | c | Mark the select array for possible reordering | c %-----------------------------------------------------% c numcnv = 0 do 11 j = 1,ncv temp1 = max(eps23, & dlapy2 ( workl(irr+ncv-j), workl(iri+ncv-j) )) jj = INT(workl(bounds + ncv - j)) if (numcnv .lt. nconv .and. & workl(ibd+jj-1) .le. tol*temp1) then select(jj) = .true. numcnv = numcnv + 1 if (jj .gt. nev) reord = .true. endif 11 continue c c %-----------------------------------------------------------% c | Check the count (numcnv) of converged Ritz values with | c | the number (nconv) reported by dnaupd. If these two | c | are different then there has probably been an error | c | caused by incorrect passing of the dnaupd data. | c %-----------------------------------------------------------% c c if (numcnv .ne. nconv) then info = -15 go to 9000 end if c c %-----------------------------------------------------------% c | Call LAPACK routine dlahqr to compute the real Schur form | c | of the upper Hessenberg matrix returned by DNAUPD . | c | Make a copy of the upper Hessenberg matrix. | c | Initialize the Schur vector matrix Q to the identity. | c %-----------------------------------------------------------% c call dcopy (ldh*ncv, workl(ih), int(ione, kind=4), & workl(iuptri), int(ione, kind=4)) call dlaset ('All', ncv, ncv, & zero , one, workl(invsub), & ldq) call dlahqr (.true., .true. , ncv, & int(ione, kind=4), ncv, workl(iuptri), & ldh , workl(iheigr), workl(iheigi), & int(ione, kind=4), ncv, workl(invsub), & ldq , ierr) call dcopy (ncv, workl(invsub+ncv-1), int(ldq, kind=4), & workl(ihbds), 1) c if (ierr .ne. 0) then info = -8 go to 9000 end if c if (reord) then c c %-----------------------------------------------------% c | Reorder the computed upper quasi-triangular matrix. | c %-----------------------------------------------------% c call dtrsen ('None' , 'V' , & select , ncv , & workl(iuptri), ldh , & workl(invsub), ldq , & workl(iheigr), workl(iheigi), & nconv , conds , & sep , workl(ihbds) , & ncv , iwork , & 1 , ierr) c if (ierr .eq. 1) then info = 1 go to 9000 end if c end if c c %---------------------------------------% c | Copy the last row of the Schur vector | c | into workl(ihbds). This will be used | c | to compute the Ritz estimates of | c | converged Ritz values. | c %---------------------------------------% c call dcopy (ncv, workl(invsub+ncv-1), int(ldq, kind=4), & workl(ihbds), int(ione, kind=4)) c c %----------------------------------------------------% c | Place the computed eigenvalues of H into DR and DI | c | if a spectral transformation was not used. | c %----------------------------------------------------% c if (type .eq. 'REGULR') then call dcopy (nconv, workl(iheigr), 1, dr(ione), 1) call dcopy (nconv, workl(iheigi), 1, di(ione), 1) end if c c %----------------------------------------------------------% c | Compute the QR factorization of the matrix representing | c | the wanted invariant subspace located in the first NCONV | c | columns of workl(invsub,ldq). | c %----------------------------------------------------------% c call dgeqr2 (ncv, nconv , workl(invsub), & ldq, workev, workev(ncv+1), & ierr) c c %---------------------------------------------------------% c | * Postmultiply V by Q using dorm2r . | c | * Copy the first NCONV columns of VQ into Z. | c | * Postmultiply Z by R. | c | The N by NCONV matrix Z is now a matrix representation | c | of the approximate invariant subspace associated with | c | the Ritz values in workl(iheigr) and workl(iheigi) | c | The first NCONV columns of V are now approximate Schur | c | vectors associated with the real upper quasi-triangular | c | matrix of order NCONV in workl(iuptri) | c %---------------------------------------------------------% c call dorm2r ('Right', 'Notranspose', n , & ncv , nconv , workl(invsub), & ldq , workev , v , & ldv , workd(n+1) , ierr) call dlacpy ('All', n, nconv, v(1,1), ldv, z, ldz) c do 20 j=1, nconv c c %---------------------------------------------------% c | Perform both a column and row scaling if the | c | diagonal element of workl(invsub,ldq) is negative | c | I'm lazy and don't take advantage of the upper | c | quasi-triangular form of workl(iuptri,ldq) | c | Note that since Q is orthogonal, R is a diagonal | c | matrix consisting of plus or minus ones | c %---------------------------------------------------% c if (workl(invsub+(j-1)*ldq+j-1) .lt. zero) then call dscal (nconv, -one, workl(iuptri+j-1), & int(ldq, kind=4)) call dscal (nconv, -one, workl(iuptri+(j-1)*ldq), & int(ione, kind=4)) end if c 20 continue c if (howmny .eq. 'A') then c c %--------------------------------------------% c | Compute the NCONV wanted eigenvectors of T | c | located in workl(iuptri,ldq). | c %--------------------------------------------% c do 30 j=1, ncv if (j .le. nconv) then select(j) = .true. else select(j) = .false. end if 30 continue c call dtrevc ('Right', 'Select' , select , & ncv , workl(iuptri), ldq , & vl, ione, workl(invsub), & ldq , ncv , outncv , & workev(1) , ierr) c if (ierr .ne. 0) then info = -9 go to 9000 end if c c %------------------------------------------------% c | Scale the returning eigenvectors so that their | c | Euclidean norms are all one. LAPACK subroutine | c | dtrevc returns each eigenvector normalized so | c | that the element of largest magnitude has | c | magnitude 1; | c %------------------------------------------------% c iconj = 0 do 40 j=1, nconv c if ( abs( workl(iheigi+j-1) ) .le. zero ) then c c %----------------------% c | real eigenvalue case | c %----------------------% c temp = dnrm2 ( ncv, workl(invsub+(j-1)*ldq), & int(ione, kind=4)) call dscal ( ncv, one / temp, & workl(invsub+(j-1)*ldq), int(ione, kind=4) ) c else c c %-------------------------------------------% c | Complex conjugate pair case. Note that | c | since the real and imaginary part of | c | the eigenvector are stored in consecutive | c | columns, we further normalize by the | c | square root of two. | c %-------------------------------------------% c if (iconj .eq. 0) then temp = dlapy2 (dnrm2 (ncv, & workl(invsub+(j-1)*ldq), & 1), & dnrm2 (ncv, & workl(invsub+j*ldq), & 1)) call dscal (ncv, one/temp, & workl(invsub+(j-1)*ldq), & int(ione, kind=4)) call dscal (ncv, one/temp, & workl(invsub+j*ldq), & int(ione, kind=4) ) iconj = 1 else iconj = 0 end if c end if c 40 continue c call dgemv ('T', ncv, nconv, one, workl(invsub), & ldq, workl(ihbds), int(ione, kind=4), & zero, workev(ione), 1) c iconj = 0 do 45 j=1, nconv if (workl(iheigi+j-1) .le. zero) then c c %-------------------------------------------% c | Complex conjugate pair case. Note that | c | since the real and imaginary part of | c | the eigenvector are stored in consecutive | c %-------------------------------------------% c if (iconj .eq. 0) then workev(j) = dlapy2 (workev(j), workev(j+1)) workev(j+1) = workev(j) iconj = 1 else iconj = 0 end if end if 45 continue c c %---------------------------------------% c | Copy Ritz estimates into workl(ihbds) | c %---------------------------------------% c call dcopy (nconv, workev, 1, workl(ihbds), 1) c c %---------------------------------------------------------% c | Compute the QR factorization of the eigenvector matrix | c | associated with leading portion of T in the first NCONV | c | columns of workl(invsub,ldq). | c %---------------------------------------------------------% c call dgeqr2 (ncv, nconv , workl(invsub), & ldq, workev, workev(ncv+1), & ierr) c c %----------------------------------------------% c | * Postmultiply Z by Q. | c | * Postmultiply Z by R. | c | The N by NCONV matrix Z is now contains the | c | Ritz vectors associated with the Ritz values | c | in workl(iheigr) and workl(iheigi). | c %----------------------------------------------% c call dorm2r ('Right', 'Notranspose', n , & ncv , nconv , workl(invsub), & ldq , workev , z , & ldz , workd(n+1) , ierr) c call dtrmm ('Right' , 'Upper' , 'No transpose', & 'Non-unit', n , nconv , & one , workl(invsub), ldq , & z , ldz) c end if c else c c %------------------------------------------------------% c | An approximate invariant subspace is not needed. | c | Place the Ritz values computed DNAUPD into DR and DI | c %------------------------------------------------------% c call dcopy (nconv, workl(ritzr), 1, dr(ione), 1) call dcopy (nconv, workl(ritzi), 1, di(ione), 1) call dcopy (nconv, workl(ritzr), 1, workl(iheigr), 1) call dcopy (nconv, workl(ritzi), 1, workl(iheigi), 1) call dcopy (nconv, workl(bounds), 1, workl(ihbds), 1) end if c c %------------------------------------------------% c | Transform the Ritz values and possibly vectors | c | and corresponding error bounds of OP to those | c | of A*x = lambda*B*x. | c %------------------------------------------------% c if (type .eq. 'REGULR') then c if (rvec) & call dscal (ncv, rnorm, workl(ihbds), int(ione, kind=4)) c else c c %---------------------------------------% c | A spectral transformation was used. | c | * Determine the Ritz estimates of the | c | Ritz values in the original system. | c %---------------------------------------% c if (type .eq. 'SHIFTI') then c if (rvec) & call dscal (ncv, rnorm, workl(ihbds), int(ione, kind=4)) c do 50 k=1, ncv temp = dlapy2 ( workl(iheigr+k-1), & workl(iheigi+k-1) ) workl(ihbds+k-1) = abs( workl(ihbds+k-1) ) & / temp / temp 50 continue c else if (type .eq. 'REALPT') then c do 60 k=1, ncv 60 continue c else if (type .eq. 'IMAGPT') then c do 70 k=1, ncv 70 continue c end if c c %-----------------------------------------------------------% c | * Transform the Ritz values back to the original system. | c | For TYPE = 'SHIFTI' the transformation is | c | lambda = 1/theta + sigma | c | For TYPE = 'REALPT' or 'IMAGPT' the user must from | c | Rayleigh quotients or a projection. See remark 3 above.| c | NOTES: | c | *The Ritz vectors are not affected by the transformation. | c %-----------------------------------------------------------% c if (type .eq. 'SHIFTI') then c do 80 k=1, ncv temp = dlapy2 ( workl(iheigr+k-1), & workl(iheigi+k-1) ) workl(iheigr+k-1) = workl(iheigr+k-1)/temp/temp & + sigmar workl(iheigi+k-1) = -workl(iheigi+k-1)/temp/temp & + sigmai 80 continue c call dcopy (nconv, workl(iheigr), 1, dr(ione), 1) call dcopy (nconv, workl(iheigi), 1, di(ione), 1) c else if (type .eq. 'REALPT' .or. type .eq. 'IMAGPT') then c call dcopy (nconv, workl(iheigr), 1, dr(ione), 1) call dcopy (nconv, workl(iheigi), 1, di(ione), 1) c end if c end if c c %-------------------------------------------------% c | Eigenvector Purification step. Formally perform | c | one of inverse subspace iteration. Only used | c | for MODE = 2. | c %-------------------------------------------------% c if (rvec .and. howmny .eq. 'A' .and. type .eq. 'SHIFTI') then c c %------------------------------------------------% c | Purify the computed Ritz vectors by adding a | c | little bit of the residual vector: | c | T | c | resid(:)*( e s ) / theta | c | NCV | c | where H s = s theta. Remember that when theta | c | has nonzero imaginary part, the corresponding | c | Ritz vector is stored across two columns of Z. | c %------------------------------------------------% c iconj = 0 do 110 j=1, nconv c if (workl(iheigi+j-1) .eq. zero) then if (abs(workl(iheigi+j-1)) .le. zero) then workev(j) = workl(invsub+(j-1)*ldq+ncv-1) / & workl(iheigr+j-1) else if (iconj .eq. 0) then temp = dlapy2 ( workl(iheigr+j-1), workl(iheigi+j-1) ) workev(j) = ( workl(invsub+(j-1)*ldq+ncv-1) * & workl(iheigr+j-1) + & workl(invsub+j*ldq+ncv-1) * & workl(iheigi+j-1) ) / temp / temp workev(j+1) = ( workl(invsub+j*ldq+ncv-1) * & workl(iheigr+j-1) - & workl(invsub+(j-1)*ldq+ncv-1) * & workl(iheigi+j-1) ) / temp / temp iconj = 1 else iconj = 0 end if 110 continue c c %---------------------------------------% c | Perform a rank one update to Z and | c | purify all the Ritz vectors together. | c %---------------------------------------% c call dger (n, nconv, one, resid, 1, workev, 1, z, ldz) c end if c 9000 continue c return c c %---------------% c | End of DNEUPD | c %---------------% c end c\BeginDoc c c\Name: dnaupd c c\Description: c Reverse communication interface for the Implicitly Restarted Arnoldi c iteration. This subroutine computes approximations to a few eigenpairs c of a linear operator "OP" with respect to a semi-inner product defined by c a symmetric positive semi-definite real matrix B. B may be the identity c matrix. NOTE: If the linear operator "OP" is real and symmetric c with respect to the real positive semi-definite symmetric matrix B, c i.e. B*OP = (OP`)*B, then subroutine dsaupd should be used instead. c c The computed approximate eigenvalues are called Ritz values and c the corresponding approximate eigenvectors are called Ritz vectors. c c dnaupd is usually called iteratively to solve one of the c following problems: c c Mode 1: A*x = lambda*x. c ===> OP = A and B = I. c c Mode 2: A*x = lambda*M*x, M symmetric positive definite c ===> OP = inv[M]*A and B = M. c ===> (If M can be factored see remark 3 below) c c Mode 3: A*x = lambda*M*x, M symmetric semi-definite c ===> OP = Real_Part{ inv[A - sigma*M]*M } and B = M. c ===> shift-and-invert mode (in real arithmetic) c If OP*x = amu*x, then c amu = 1/2 * [ 1/(lambda-sigma) + 1/(lambda-conjg(sigma)) ]. c Note: If sigma is real, i.e. imaginary part of sigma is zero; c Real_Part{ inv[A - sigma*M]*M } == inv[A - sigma*M]*M c amu == 1/(lambda-sigma). c c Mode 4: A*x = lambda*M*x, M symmetric semi-definite c ===> OP = Imaginary_Part{ inv[A - sigma*M]*M } and B = M. c ===> shift-and-invert mode (in real arithmetic) c If OP*x = amu*x, then c amu = 1/2i * [ 1/(lambda-sigma) - 1/(lambda-conjg(sigma)) ]. c c Both mode 3 and 4 give the same enhancement to eigenvalues close to c the (complex) shift sigma. However, as lambda goes to infinity, c the operator OP in mode 4 dampens the eigenvalues more strongly than c does OP defined in mode 3. c c NOTE: The action of w <- inv[A - sigma*M]*v or w <- inv[M]*v c should be accomplished either by a direct method c using a sparse matrix factorization and solving c c [A - sigma*M]*w = v or M*w = v, c c or through an iterative method for solving these c systems. If an iterative method is used, the c convergence test must be more stringent than c the accuracy requirements for the eigenvalue c approximations. c c\Usage: c call dnaupd c ( IDO, BMAT, N, WHICH, NEV, TOL, RESID, NCV, V, LDV, IPARAM, c IPNTR, WORKD, WORKL, LWORKL, INFO ) c c\Arguments c IDO Integer. (INPUT/OUTPUT) c Reverse communication flag. IDO must be zero on the first c call to dnaupd. IDO will be set internally to c indicate the type of operation to be performed. Control is c then given back to the calling routine which has the c responsibility to carry out the requested operation and call c dnaupd with the result. The operand is given in c WORKD(IPNTR(1)), the result must be put in WORKD(IPNTR(2)). c ------------------------------------------------------------- c IDO = 0: first call to the reverse communication interface c IDO = -1: compute Y = OP * X where c IPNTR(1) is the pointer into WORKD for X, c IPNTR(2) is the pointer into WORKD for Y. c This is for the initialization phase to force the c starting vector into the range of OP. c IDO = 1: compute Y = OP * X where c IPNTR(1) is the pointer into WORKD for X, c IPNTR(2) is the pointer into WORKD for Y. c In mode 3 and 4, the vector B * X is already c available in WORKD(ipntr(3)). It does not c need to be recomputed in forming OP * X. c IDO = 2: compute Y = B * X where c IPNTR(1) is the pointer into WORKD for X, c IPNTR(2) is the pointer into WORKD for Y. c IDO = 3: compute the IPARAM(8) real and imaginary parts c of the shifts where INPTR(14) is the pointer c into WORKL for placing the shifts. See Remark c 5 below. c IDO = 99: done c ------------------------------------------------------------- c c BMAT Character*1. (INPUT) c BMAT specifies the type of the matrix B that defines the c semi-inner product for the operator OP. c BMAT = 'I' -> standard eigenvalue problem A*x = lambda*x c BMAT = 'G' -> generalized eigenvalue problem A*x = lambda*B*x c c N Integer. (INPUT) c Dimension of the eigenproblem. c c WHICH Character*2. (INPUT) c 'LM' -> want the NEV eigenvalues of largest magnitude. c 'SM' -> want the NEV eigenvalues of smallest magnitude. c 'LR' -> want the NEV eigenvalues of largest real part. c 'SR' -> want the NEV eigenvalues of smallest real part. c 'LI' -> want the NEV eigenvalues of largest imaginary part. c 'SI' -> want the NEV eigenvalues of smallest imaginary part. c c NEV Integer. (INPUT/OUTPUT) c Number of eigenvalues of OP to be computed. 0 < NEV < N-1. c c TOL Double precision scalar. (INPUT) c Stopping criterion: the relative accuracy of the Ritz value c is considered acceptable if BOUNDS(I) .LE. TOL*ABS(RITZ(I)) c where ABS(RITZ(I)) is the magnitude when RITZ(I) is complex. c DEFAULT = DLAMCH('EPS') (machine precision as computed c by the LAPACK auxiliary subroutine DLAMCH). c c RESID Double precision array of length N. (INPUT/OUTPUT) c On INPUT: c If INFO .EQ. 0, a random initial residual vector is used. c If INFO .NE. 0, RESID contains the initial residual vector, c possibly from a previous run. c On OUTPUT: c RESID contains the final residual vector. c c NCV Integer. (INPUT) c Number of columns of the matrix V. NCV must satisfy the two c inequalities 2 <= NCV-NEV and NCV <= N. c This will indicate how many Arnoldi vectors are generated c at each iteration. After the startup phase in which NEV c Arnoldi vectors are generated, the algorithm generates c approximately NCV-NEV Arnoldi vectors at each subsequent update c iteration. Most of the cost in generating each Arnoldi vector is c in the matrix-vector operation OP*x. c NOTE: 2 <= NCV-NEV in order that complex conjugate pairs of Ritz c values are kept together. (See remark 4 below) c c V Double precision array N by NCV. (OUTPUT) c Contains the final set of Arnoldi basis vectors. c c LDV Integer. (INPUT) c Leading dimension of V exactly as declared in the calling program. c c IPARAM Integer array of length 11. (INPUT/OUTPUT) c IPARAM(1) = ISHIFT: method for selecting the implicit shifts. c The shifts selected at each iteration are used to restart c the Arnoldi iteration in an implicit fashion. c ------------------------------------------------------------- c ISHIFT = 0: the shifts are provided by the user via c reverse communication. The real and imaginary c parts of the NCV eigenvalues of the Hessenberg c matrix H are returned in the part of the WORKL c array corresponding to RITZR and RITZI. See remark c 5 below. c ISHIFT = 1: exact shifts with respect to the current c Hessenberg matrix H. This is equivalent to c restarting the iteration with a starting vector c that is a linear combination of approximate Schur c vectors associated with the "wanted" Ritz values. c ------------------------------------------------------------- c c IPARAM(2) = No longer referenced. c IPARAM(3) = MXITER c On INPUT: maximum number of Arnoldi update iterations allowed. c On OUTPUT: actual number of Arnoldi update iterations taken. c c IPARAM(4) = NB: blocksize to be used in the recurrence. c The code currently works only for NB = 1. c c IPARAM(5) = NCONV: number of "converged" Ritz values. c This represents the number of Ritz values that satisfy c the convergence criterion. c c IPARAM(6) = IUPD c No longer referenced. Implicit restarting is ALWAYS used. c c IPARAM(7) = MODE c On INPUT determines what type of eigenproblem is being solved. c Must be 1,2,3,4; See under \Description of dnaupd for the c four modes available. c c IPARAM(8) = NP c When ido = 3 and the user provides shifts through reverse c communication (IPARAM(1)=0), dnaupd returns NP, the number c of shifts the user is to provide. 0 < NP <=NCV-NEV. See Remark c 5 below. c crc IPARAM(9) = NUMOP, IPARAM(10) = NUMOPB, IPARAM(11) = NUMREO, crc OUTPUT: NUMOP = total number of OP*x operations, crc NUMOPB = total number of B*x operations if BMAT='G', crc NUMREO = total number of steps of re-orthogonalization. c c IPNTR Integer array of length 14. (OUTPUT) c Pointer to mark the starting locations in the WORKD and WORKL c arrays for matrices/vectors used by the Arnoldi iteration. c ------------------------------------------------------------- c IPNTR(1): pointer to the current operand vector X in WORKD. c IPNTR(2): pointer to the current result vector Y in WORKD. c IPNTR(3): pointer to the vector B * X in WORKD when used in c the shift-and-invert mode. c IPNTR(4): pointer to the next available location in WORKL c that is untouched by the program. c IPNTR(5): pointer to the NCV by NCV upper Hessenberg matrix c H in WORKL. c IPNTR(6): pointer to the real part of the ritz value array c RITZR in WORKL. c IPNTR(7): pointer to the imaginary part of the ritz value array c RITZI in WORKL. c IPNTR(8): pointer to the Ritz estimates in array WORKL associated c with the Ritz values located in RITZR and RITZI in WORKL. c c IPNTR(14): pointer to the NP shifts in WORKL. See Remark 5 below. c c Note: IPNTR(9:13) is only referenced by dneupd. See Remark 2 below. c c IPNTR(9): pointer to the real part of the NCV RITZ values of the c original system. c IPNTR(10): pointer to the imaginary part of the NCV RITZ values of c the original system. c IPNTR(11): pointer to the NCV corresponding error bounds. c IPNTR(12): pointer to the NCV by NCV upper quasi-triangular c Schur matrix for H. c IPNTR(13): pointer to the NCV by NCV matrix of eigenvectors c of the upper Hessenberg matrix H. Only referenced by c dneupd if RVEC = .TRUE. See Remark 2 below. c ------------------------------------------------------------- c c WORKD Double precision work array of length 3*N. (REVERSE COMMUNICATION) c Distributed array to be used in the basic Arnoldi iteration c for reverse communication. The user should not use WORKD c as temporary workspace during the iteration. Upon termination c WORKD(1:N) contains B*RESID(1:N). If an invariant subspace c associated with the converged Ritz values is desired, see remark c 2 below, subroutine dneupd uses this output. c See Data Distribution Note below. c c WORKL Double precision work array of length LWORKL. (OUTPUT/WORKSPACE) c Private (replicated) array on each PE or array allocated on c the front end. See Data Distribution Note below. c c LWORKL Integer. (INPUT) c LWORKL must be at least 3*NCV**2 + 6*NCV. c c INFO Integer. (INPUT/OUTPUT) c If INFO .EQ. 0, a randomly initial residual vector is used. c If INFO .NE. 0, RESID contains the initial residual vector, c possibly from a previous run. c Error flag on output. c = 0: Normal exit. c = 1: Maximum number of iterations taken. c All possible eigenvalues of OP has been found. IPARAM(5) c returns the number of wanted converged Ritz values. c = 2: No longer an informational error. Deprecated starting c with release 2 of ARPACK. c = 3: No shifts could be applied during a cycle of the c Implicitly restarted Arnoldi iteration. One possibility c is to increase the size of NCV relative to NEV. c See remark 4 below. c = -1: N must be positive. c = -2: NEV must be positive. c = -3: NCV-NEV >= 2 and less than or equal to N. c = -4: The maximum number of Arnoldi update iteration c must be greater than zero. c = -5: WHICH must be one of 'LM', 'SM', 'LR', 'SR', 'LI', 'SI' c = -6: BMAT must be one of 'I' or 'G'. c = -7: Length of private work array is not sufficient. c = -8: Error return from LAPACK eigenvalue calculation; c = -9: Starting vector is zero. c = -10: IPARAM(7) must be 1,2,3,4. c = -11: IPARAM(7) = 1 and BMAT = 'G' are incompatable. c = -12: IPARAM(1) must be equal to 0 or 1. c = -9999: Could not build an Arnoldi factorization. c IPARAM(5) returns the size of the current Arnoldi c factorization. c c\Remarks c 1. The computed Ritz values are approximate eigenvalues of OP. The c selection of WHICH should be made with this in mind when c Mode = 3 and 4. After convergence, approximate eigenvalues of the c original problem may be obtained with the ARPACK subroutine dneupd. c c 2. If a basis for the invariant subspace corresponding to the converged Ritz c values is needed, the user must call dneupd immediately following c completion of dnaupd. This is new starting with release 2 of ARPACK. c c 3. If M can be factored into a Cholesky factorization M = LL` c then Mode = 2 should not be selected. Instead one should use c Mode = 1 with OP = inv(L)*A*inv(L`). Appropriate triangular c linear systems should be solved with L and L` rather c than computing inverses. After convergence, an approximate c eigenvector z of the original problem is recovered by solving c L`z = x where x is a Ritz vector of OP. c c 4. At present there is no a-priori analysis to guide the selection c of NCV relative to NEV. The only formal requrement is that NCV > NEV + 2. c However, it is recommended that NCV .ge. 2*NEV+1. If many problems of c the same type are to be solved, one should experiment with increasing c NCV while keeping NEV fixed for a given test problem. This will c usually decrease the required number of OP*x operations but it c also increases the work and storage required to maintain the orthogonal c basis vectors. The optimal "cross-over" with respect to CPU time c is problem dependent and must be determined empirically. c See Chapter 8 of Reference 2 for further information. c c 5. When IPARAM(1) = 0, and IDO = 3, the user needs to provide the c NP = IPARAM(8) real and imaginary parts of the shifts in locations c real part imaginary part c ----------------------- -------------- c 1 WORKL(IPNTR(14)) WORKL(IPNTR(14)+NP) c 2 WORKL(IPNTR(14)+1) WORKL(IPNTR(14)+NP+1) c . . c . . c . . c NP WORKL(IPNTR(14)+NP-1) WORKL(IPNTR(14)+2*NP-1). c c Only complex conjugate pairs of shifts may be applied and the pairs c must be placed in consecutive locations. The real part of the c eigenvalues of the current upper Hessenberg matrix are located in c WORKL(IPNTR(6)) through WORKL(IPNTR(6)+NCV-1) and the imaginary part c in WORKL(IPNTR(7)) through WORKL(IPNTR(7)+NCV-1). They are ordered c according to the order defined by WHICH. The complex conjugate c pairs are kept together and the associated Ritz estimates are located in c WORKL(IPNTR(8)), WORKL(IPNTR(8)+1), ... , WORKL(IPNTR(8)+NCV-1). c c----------------------------------------------------------------------- c c\Data Distribution Note: c c Fortran-D syntax: c ================ c Double precision resid(n), v(ldv,ncv), workd(3*n), workl(lworkl) c decompose d1(n), d2(n,ncv) c align resid(i) with d1(i) c align v(i,j) with d2(i,j) c align workd(i) with d1(i) range (1:n) c align workd(i) with d1(i-n) range (n+1:2*n) c align workd(i) with d1(i-2*n) range (2*n+1:3*n) c distribute d1(block), d2(block,:) c replicated workl(lworkl) c c Cray MPP syntax: c =============== c Double precision resid(n), v(ldv,ncv), workd(n,3), workl(lworkl) c shared resid(block), v(block,:), workd(block,:) c replicated workl(lworkl) c c CM2/CM5 syntax: c ============== c c----------------------------------------------------------------------- c c include 'ex-nonsym.doc' c c----------------------------------------------------------------------- c c\BeginLib c c\Local variables: c xxxxxx real c c\References: c 1. D.C. Sorensen, "Implicit Application of Polynomial Filters in c a k-Step Arnoldi Method", SIAM J. Matr. Anal. Apps., 13 (1992), c pp 357-385. c 2. R.B. Lehoucq, "Analysis and Implementation of an Implicitly c Restarted Arnoldi Iteration", Rice University Technical Report c TR95-13, Department of Computational and Applied Mathematics. c 3. B.N. Parlett & Y. Saad, "Complex Shift and Invert Strategies for c Real Matrices", Linear Algebra and its Applications, vol 88/89, c pp 575-595, (1987). c c\Routines called: c dnaup2 ARPACK routine that implements the Implicitly Restarted c Arnoldi Iteration. c ivout ARPACK utility routine that prints integers. c second ARPACK utility routine for timing. c dvout ARPACK utility routine that prints vectors. c dlamch LAPACK routine that determines machine constants. c c\Author c Danny Sorensen Phuong Vu c Richard Lehoucq CRPC / Rice University c Dept. of Computational & Houston, Texas c Applied Mathematics c Rice University c Houston, Texas c c\Revision history: c 12/16/93: Version '1.1' c c\SCCS Information: @(#) c FILE: naupd.F SID: 2.10 DATE OF SID: 08/23/02 RELEASE: 2 c c\Remarks c c\EndLib c c----------------------------------------------------------------------- c subroutine dnaupd & ( ido, bmat, n, which, nev, tol, resid, ncv, v, ldv, iparam, & ipntr, workd, workl, lworkl, info ) c implicit none c c %------------------% c | Scalar Arguments | c %------------------% c character bmat*1, which*2 integer ido, info, ldv, lworkl, n, ncv, nev Double precision & tol c c %-----------------% c | Array Arguments | c %-----------------% c integer iparam(8), ipntr(14) Double precision & resid(n), v(ldv,ncv), workd(3*n), workl(lworkl) c c %------------% c | Parameters | c %------------% c Double precision & zero parameter (zero = 0.0D+0) c c %---------------% c | Local Scalars | c %---------------% c integer bounds, ierr, ih, iq, ishift, iupd, iw, & ldh, ldq, levec, mode, mxiter, nb, & nev0, next, np, ritzi, ritzr, j save bounds, ih, iq, ishift, iupd, iw, ldh, ldq, & levec, mode, mxiter, nb, nev0, next, & np, ritzi, ritzr c c %----------------------% c | External Subroutines | c %----------------------% c external dnaup2 c c %--------------------% c | External Functions | c %--------------------% c Double precision & dlamch external dlamch c c %-----------------------% c | Executable Statements | c %-----------------------% c if (levec .gt. 10000000) then goto 9000 end if c if (ido .eq. 0) then c c %-------------------------------% c | Initialize timing statistics | c | & message level for debugging | c %-------------------------------% c c %----------------% c | Error checking | c %----------------% c ierr = 0 ishift = iparam(1) c levec = iparam(2) mxiter = iparam(3) c nb = iparam(4) nb = 1 c c %--------------------------------------------% c | Revision 2 performs only implicit restart. | c %--------------------------------------------% c iupd = 1 mode = iparam(7) c if (n .le. 0) then ierr = -1 else if (nev .le. 0) then ierr = -2 else if (ncv .le. nev+1 .or. ncv .gt. n) then ierr = -3 else if (mxiter .le. 0) then ierr = 4 else if (which .ne. 'LM' .and. & which .ne. 'SM' .and. & which .ne. 'LR' .and. & which .ne. 'SR' .and. & which .ne. 'LI' .and. & which .ne. 'SI') then ierr = -5 else if (bmat .ne. 'I' .and. bmat .ne. 'G') then ierr = -6 else if (lworkl .lt. 3*ncv**2 + 6*ncv) then ierr = -7 else if (mode .lt. 1 .or. mode .gt. 4) then ierr = -10 else if (mode .eq. 1 .and. bmat .eq. 'G') then ierr = -11 else if (ishift .lt. 0 .or. ishift .gt. 1) then ierr = -12 end if c c %------------% c | Error Exit | c %------------% c if (ierr .ne. 0) then info = ierr ido = 99 go to 9000 end if c c %------------------------% c | Set default parameters | c %------------------------% c if (nb .le. 0) nb = 1 if (tol .le. zero) tol = dlamch('EpsMach') c c %----------------------------------------------% c | NP is the number of additional steps to | c | extend the length NEV Lanczos factorization. | c | NEV0 is the local variable designating the | c | size of the invariant subspace desired. | c %----------------------------------------------% c np = ncv - nev nev0 = nev c c %-----------------------------% c | Zero out internal workspace | c %-----------------------------% c do 10 j = 1, 3*ncv**2 + 6*ncv workl(j) = zero 10 continue c c %-------------------------------------------------------------% c | Pointer into WORKL for address of H, RITZ, BOUNDS, Q | c | etc... and the remaining workspace. | c | Also update pointer to be used on output. | c | Memory is laid out as follows: | c | workl(1:ncv*ncv) := generated Hessenberg matrix | c | workl(ncv*ncv+1:ncv*ncv+2*ncv) := real and imaginary | c | parts of ritz values | c | workl(ncv*ncv+2*ncv+1:ncv*ncv+3*ncv) := error bounds | c | workl(ncv*ncv+3*ncv+1:2*ncv*ncv+3*ncv) := rotation matrix Q | c | workl(2*ncv*ncv+3*ncv+1:3*ncv*ncv+6*ncv) := workspace | c | The final workspace is needed by subroutine dneigh called | c | by dnaup2. Subroutine dneigh calls LAPACK routines for | c | calculating eigenvalues and the last row of the eigenvector | c | matrix. | c %-------------------------------------------------------------% c ldh = ncv ldq = ncv ih = 1 ritzr = ih + ldh*ncv ritzi = ritzr + ncv bounds = ritzi + ncv iq = bounds + ncv iw = iq + ldq*ncv next = iw + ncv**2 + 3*ncv c ipntr(4) = next ipntr(5) = ih ipntr(6) = ritzr ipntr(7) = ritzi ipntr(8) = bounds ipntr(14) = iw c end if c c %-------------------------------------------------------% c | Carry out the Implicitly restarted Arnoldi Iteration. | c %-------------------------------------------------------% c call dnaup2 & ( ido, bmat, n, which, nev0, np, tol, resid, mode, & ishift, mxiter, v, ldv, workl(ih), ldh, workl(ritzr), & workl(ritzi), workl(bounds), workl(iq), ldq, workl(iw), & ipntr, workd, info ) c c %--------------------------------------------------% c | ido .ne. 99 implies use of reverse communication | c | to compute operations involving OP or shifts. | c %--------------------------------------------------% c if (ido .eq. 3) iparam(8) = np if (ido .ne. 99) go to 9000 c iparam(3) = mxiter iparam(5) = np c c %------------------------------------% c | Exit if there was an informational | c | error within dnaup2. | c %------------------------------------% c if (info .lt. 0) go to 9000 if (info .eq. 2) info = 3 c c %--------------------------------------------------------% c | Version Number & Version Date are defined in version.h | c %--------------------------------------------------------% c 9000 continue c return c c %---------------% c | End of dnaupd | c %---------------% c end c\BeginDoc c c\Name: dnaup2 c c\Description: c Intermediate level interface called by dnaupd. c c\Usage: c call dnaup2 c ( IDO, BMAT, N, WHICH, NEV, NP, TOL, RESID, MODE, IUPD, c ISHIFT, MXITER, V, LDV, H, LDH, RITZR, RITZI, BOUNDS, c Q, LDQ, WORKL, IPNTR, WORKD, INFO ) c c\Arguments c c IDO, BMAT, N, WHICH, NEV, TOL, RESID: same as defined in dnaupd. c MODE, ISHIFT, MXITER: see the definition of IPARAM in dnaupd. c c NP Integer. (INPUT/OUTPUT) c Contains the number of implicit shifts to apply during c each Arnoldi iteration. c If ISHIFT=1, NP is adjusted dynamically at each iteration c to accelerate convergence and prevent stagnation. c This is also roughly equal to the number of matrix-vector c products (involving the operator OP) per Arnoldi iteration. c The logic for adjusting is contained within the current c subroutine. c If ISHIFT=0, NP is the number of shifts the user needs c to provide via reverse comunication. 0 < NP < NCV-NEV. c NP may be less than NCV-NEV for two reasons. The first, is c to keep complex conjugate pairs of "wanted" Ritz values c together. The second, is that a leading block of the current c upper Hessenberg matrix has split off and contains "unwanted" c Ritz values. c Upon termination of the IRA iteration, NP contains the number c of "converged" wanted Ritz values. c c IUPD Integer. (INPUT) c IUPD .EQ. 0: use explicit restart instead implicit update. c IUPD .NE. 0: use implicit update. c c V Double precision N by (NEV+NP) array. (INPUT/OUTPUT) c The Arnoldi basis vectors are returned in the first NEV c columns of V. c c LDV Integer. (INPUT) c Leading dimension of V exactly as declared in the calling c program. c c H Double precision (NEV+NP) by (NEV+NP) array. (OUTPUT) c H is used to store the generated upper Hessenberg matrix c c LDH Integer. (INPUT) c Leading dimension of H exactly as declared in the calling c program. c c RITZR, Double precision arrays of length NEV+NP. (OUTPUT) c RITZI RITZR(1:NEV) (resp. RITZI(1:NEV)) contains the real (resp. c imaginary) part of the computed Ritz values of OP. c c BOUNDS Double precision array of length NEV+NP. (OUTPUT) c BOUNDS(1:NEV) contain the error bounds corresponding to c the computed Ritz values. c c Q Double precision (NEV+NP) by (NEV+NP) array. (WORKSPACE) c Private (replicated) work array used to accumulate the c rotation in the shift application step. c c LDQ Integer. (INPUT) c Leading dimension of Q exactly as declared in the calling c program. c c WORKL Double precision work array of length at least c (NEV+NP)**2 + 3*(NEV+NP). (INPUT/WORKSPACE) c Private (replicated) array on each PE or array allocated on c the front end. It is used in shifts calculation, shifts c application and convergence checking. c c On exit, the last 3*(NEV+NP) locations of WORKL contain c the Ritz values (real,imaginary) and associated Ritz c estimates of the current Hessenberg matrix. They are c listed in the same order as returned from dneigh. c c If ISHIFT .EQ. O and IDO .EQ. 3, the first 2*NP locations c of WORKL are used in reverse communication to hold the user c supplied shifts. c c IPNTR Integer array of length 3. (OUTPUT) c Pointer to mark the starting locations in the WORKD for c vectors used by the Arnoldi iteration. c ------------------------------------------------------------- c IPNTR(1): pointer to the current operand vector X. c IPNTR(2): pointer to the current result vector Y. c IPNTR(3): pointer to the vector B * X when used in the c shift-and-invert mode. X is the current operand. c ------------------------------------------------------------- c c WORKD Double precision work array of length 3*N. (WORKSPACE) c Distributed array to be used in the basic Arnoldi iteration c for reverse communication. The user should not use WORKD c as temporary workspace during the iteration !!!!!!!!!! c See Data Distribution Note in DNAUPD. c c INFO Integer. (INPUT/OUTPUT) c If INFO .EQ. 0, a randomly initial residual vector is used. c If INFO .NE. 0, RESID contains the initial residual vector, c possibly from a previous run. c Error flag on output. c = 0: Normal return. c = 1: Maximum number of iterations taken. c All possible eigenvalues of OP has been found. c NP returns the number of converged Ritz values. c = 2: No shifts could be applied. c = -8: Error return from LAPACK eigenvalue calculation; c This should never happen. c = -9: Starting vector is zero. c = -9999: Could not build an Arnoldi factorization. c Size that was built in returned in NP. c c\EndDoc c c----------------------------------------------------------------------- c c\BeginLib c c\Local variables: c xxxxxx real c c\References: c 1. D.C. Sorensen, "Implicit Application of Polynomial Filters in c a k-Step Arnoldi Method", SIAM J. Matr. Anal. Apps., 13 (1992), c pp 357-385. c 2. R.B. Lehoucq, "Analysis and Implementation of an Implicitly c Restarted Arnoldi Iteration", Rice University Technical Report c TR95-13, Department of Computational and Applied Mathematics. c c\Routines called: c dgetv0 ARPACK initial vector generation routine. c dnaitr ARPACK Arnoldi factorization routine. c dnapps ARPACK application of implicit shifts routine. c dnconv ARPACK convergence of Ritz values routine. c dneigh ARPACK compute Ritz values and error bounds routine. c dngets ARPACK reorder Ritz values and error bounds routine. c dsortc ARPACK sorting routine. c ivout ARPACK utility routine that prints integers. c second ARPACK utility routine for timing. c dmout ARPACK utility routine that prints matrices c dvout ARPACK utility routine that prints vectors. c dlamch LAPACK routine that determines machine constants. c dlapy2 LAPACK routine to compute sqrt(x**2+y**2) carefully. c dcopy Level 1 BLAS that copies one vector to another . c ddot Level 1 BLAS that computes the scalar product of two vectors. c dnrm2 Level 1 BLAS that computes the norm of a vector. c dswap Level 1 BLAS that swaps two vectors. c c\Author c Danny Sorensen Phuong Vu c Richard Lehoucq CRPC / Rice University c Dept. of Computational & Houston, Texas c Applied Mathematics c Rice University c Houston, Texas c c\SCCS Information: @(#) c FILE: naup2.F SID: 2.8 DATE OF SID: 10/17/00 RELEASE: 2 c c\Remarks c 1. None c c\EndLib c c----------------------------------------------------------------------- c subroutine dnaup2 & ( ido, bmat, n, which, nev, np, tol, resid, mode, & ishift, mxiter, v, ldv, h, ldh, ritzr, ritzi, bounds, & q, ldq, workl, ipntr, workd, info ) c c %----------------------------------------------------% c | Include files for debugging and timing information | c %----------------------------------------------------% c implicit none c c %------------------% c | Scalar Arguments | c %------------------% c character bmat*1, which*2 integer ido, info, ishift, mode, ldh, ldq, ldv, mxiter, & n, nev, np Double precision & tol c c %-----------------% c | Array Arguments | c %-----------------% c integer ipntr(13) Double precision & bounds(nev+np), h(ldh,nev+np), q(ldq,nev+np), resid(n), & ritzi(nev+np), ritzr(nev+np), v(ldv,nev+np), & workd(3*n), workl( (nev+np)*(nev+np+3) ) c c %------------% c | Parameters | c %------------% c Double precision & zero parameter (zero = 0.0D+0) integer & dnazero, ione parameter (dnazero = 0, ione = 1) c c %---------------% c | Local Scalars | c %---------------% c character wprime*2 logical cnorm , getv0, initv, update, ushift, dnatrue integer ierr , iter , j , kplusp, nconv, & nevbef, nev0 , np0 , nptemp, numcnv Double precision & rnorm , temp , eps23 save cnorm , getv0, initv, update, ushift, & rnorm , iter , eps23, kplusp, nconv , & nevbef, nev0 , np0 , numcnv c c %-----------------------% c | Local array arguments | c %-----------------------% c c %----------------------% c | External Subroutines | c %----------------------% c external dcopy , dgetv0, dnaitr, dnconv, dneigh, & dngets, dnapps c & dngets, dnapps, second c c %--------------------% c | External Functions | c %--------------------% c c Double precision & ddot, dnrm2, dlapy2, dlamch external ddot, dnrm2, dlapy2, dlamch c c %---------------------% c | Intrinsic Functions | c %---------------------% c intrinsic min, max, abs, sqrt c c %-----------------------% c | Executable Statements | c %-----------------------% c dnatrue = .true. c if (ido .eq. 0) then c c %-------------------------------------% c | Get the machine dependent constant. | c %-------------------------------------% c eps23 = dlamch('Epsilon-Machine') eps23 = eps23**(2.0D+0 / 3.0D+0) c nev0 = nev np0 = np c c %-------------------------------------% c | kplusp is the bound on the largest | c | Lanczos factorization built. | c | nconv is the current number of | c | "converged" eigenvlues. | c | iter is the counter on the current | c | iteration step. | c %-------------------------------------% c kplusp = nev + np nconv = 0 iter = 0 c c %---------------------------------------% c | Set flags for computing the first NEV | c | steps of the Arnoldi factorization. | c %---------------------------------------% c getv0 = .true. update = .false. ushift = .false. cnorm = .false. c if (info .ne. 0) then c c %--------------------------------------------% c | User provides the initial residual vector. | c %--------------------------------------------% c initv = .true. info = 0 else initv = .false. end if end if c c %---------------------------------------------% c | Get a possibly random starting vector and | c | force it into the range of the operator OP. | c %---------------------------------------------% c c 10 continue c if (getv0) then call dgetv0 (ido, bmat, initv, n, ione, v, ldv, resid, rnorm, & ipntr, workd, info) c if (ido .ne. 99) go to 9000 c if (abs(rnorm) .le. zero) then c if (rnorm .eq. zero) then c c %-----------------------------------------% c | The initial vector is zero. Error exit. | c %-----------------------------------------% c info = -9 go to 1100 end if getv0 = .false. ido = 0 end if c c %-----------------------------------% c | Back from reverse communication : | c | continue with update step | c %-----------------------------------% c if (update) go to 20 c c %-------------------------------------------% c | Back from computing user specified shifts | c %-------------------------------------------% c if (ushift) go to 50 c c %-------------------------------------% c | Back from computing residual norm | c | at the end of the current iteration | c %-------------------------------------% c if (cnorm) go to 100 c c %----------------------------------------------------------% c | Compute the first NEV steps of the Arnoldi factorization | c %----------------------------------------------------------% c call dnaitr (ido, bmat, n, dnazero, nev, mode, resid, rnorm, & v, ldv, h, ldh, ipntr, workd, info) c c %---------------------------------------------------% c | ido .ne. 99 implies use of reverse communication | c | to compute operations involving OP and possibly B | c %---------------------------------------------------% c if (ido .ne. 99) go to 9000 c if (info .gt. 0) then np = info mxiter = iter info = -9999 go to 1200 end if c c %--------------------------------------------------------------% c | | c | M A I N ARNOLDI I T E R A T I O N L O O P | c | Each iteration implicitly restarts the Arnoldi | c | factorization in place. | c | | c %--------------------------------------------------------------% c 1000 continue c iter = iter + 1 c c %-----------------------------------------------------------% c | Compute NP additional steps of the Arnoldi factorization. | c | Adjust NP since NEV might have been updated by last call | c | to the shift application routine dnapps. | c %-----------------------------------------------------------% c np = kplusp - nev c c %-----------------------------------------------------------% c | Compute NP additional steps of the Arnoldi factorization. | c %-----------------------------------------------------------% c ido = 0 20 continue update = .true. c call dnaitr (ido , bmat, n , nev, np , mode , resid, & rnorm, v , ldv, h , ldh, ipntr, workd, & info) c c %---------------------------------------------------% c | ido .ne. 99 implies use of reverse communication | c | to compute operations involving OP and possibly B | c %---------------------------------------------------% c if (ido .ne. 99) go to 9000 c if (info .gt. 0) then np = info mxiter = iter info = -9999 go to 1200 end if update = .false. c c %--------------------------------------------------------% c | Compute the eigenvalues and corresponding error bounds | c | of the current upper Hessenberg matrix. | c %--------------------------------------------------------% c call dneigh (rnorm, kplusp, h, ldh, ritzr, ritzi, bounds, & q, ldq, workl, ierr) c if (ierr .ne. 0) then info = -8 go to 1200 end if c c %----------------------------------------------------% c | Make a copy of eigenvalues and corresponding error | c | bounds obtained from dneigh. | c %----------------------------------------------------% c call dcopy(kplusp, ritzr, 1, workl(kplusp**2+1), 1) call dcopy(kplusp, ritzi, 1, workl(kplusp**2+kplusp+1), 1) call dcopy(kplusp, bounds, 1, workl(kplusp**2+2*kplusp+1), 1) c c %---------------------------------------------------% c | Select the wanted Ritz values and their bounds | c | to be used in the convergence test. | c | The wanted part of the spectrum and corresponding | c | error bounds are in the last NEV loc. of RITZR, | c | RITZI and BOUNDS respectively. The variables NEV | c | and NP may be updated if the NEV-th wanted Ritz | c | value has a non zero imaginary part. In this case | c | NEV is increased by one and NP decreased by one. | c | NOTE: The last two arguments of dngets are no | c | longer used as of version 2.1. | c %---------------------------------------------------% c nev = nev0 np = np0 numcnv = nev call dngets (ishift, which, nev, np, ritzr, ritzi, & bounds) if (nev .eq. nev0+1) numcnv = nev0+1 c c %-------------------% c | Convergence test. | c %-------------------% c call dcopy (nev, bounds(np+1), 1, workl(2*np+1), 1) call dnconv (nev, ritzr(np+1), ritzi(np+1), workl(2*np+1), & tol, nconv) c c %---------------------------------------------------------% c | Count the number of unwanted Ritz values that have zero | c | Ritz estimates. If any Ritz estimates are equal to zero | c | then a leading block of H of order equal to at least | c | the number of Ritz values with zero Ritz estimates has | c | split off. None of these Ritz values may be removed by | c | shifting. Decrease NP the number of shifts to apply. If | c | no shifts may be applied, then prepare to exit | c %---------------------------------------------------------% c nptemp = np do 30 j=1, nptemp c if (bounds(j) .eq. zero) then if (abs( bounds(j) ) .le. zero) then np = np - 1 nev = nev + 1 end if 30 continue c if ( (nconv .ge. numcnv) .or. & (iter .gt. mxiter) .or. & (np .eq. 0) ) then c c c %------------------------------------------------% c | Prepare to exit. Put the converged Ritz values | c | and corresponding bounds in RITZ(1:NCONV) and | c | BOUNDS(1:NCONV) respectively. Then sort. Be | c | careful when NCONV > NP | c %------------------------------------------------% c c %------------------------------------------% c | Use h( 3,1 ) as storage to communicate | c | rnorm to _neupd if needed | c %------------------------------------------% h(3,1) = rnorm c c %----------------------------------------------% c | To be consistent with dngets, we first do a | c | pre-processing sort in order to keep complex | c | conjugate pairs together. This is similar | c | to the pre-processing sort used in dngets | c | except that the sort is done in the opposite | c | order. | c %----------------------------------------------% c if (which .eq. 'LM') wprime = 'SR' if (which .eq. 'SM') wprime = 'LR' if (which .eq. 'LR') wprime = 'SM' if (which .eq. 'SR') wprime = 'LM' if (which .eq. 'LI') wprime = 'SM' if (which .eq. 'SI') wprime = 'LM' c call dsortc (wprime, dnatrue, kplusp, ritzr, ritzi, bounds) c c %----------------------------------------------% c | Now sort Ritz values so that converged Ritz | c | values appear within the first NEV locations | c | of ritzr, ritzi and bounds, and the most | c | desired one appears at the front. | c %----------------------------------------------% c if (which .eq. 'LM') wprime = 'SM' if (which .eq. 'SM') wprime = 'LM' if (which .eq. 'LR') wprime = 'SR' if (which .eq. 'SR') wprime = 'LR' if (which .eq. 'LI') wprime = 'SI' if (which .eq. 'SI') wprime = 'LI' c call dsortc(wprime, dnatrue, kplusp, ritzr, ritzi, bounds) c c %--------------------------------------------------% c | Scale the Ritz estimate of each Ritz value | c | by 1 / max(eps23,magnitude of the Ritz value). | c %--------------------------------------------------% c do 35 j = 1, numcnv temp = max(eps23,dlapy2(ritzr(j), & ritzi(j))) bounds(j) = bounds(j)/temp 35 continue c c %----------------------------------------------------% c | Sort the Ritz values according to the scaled Ritz | c | esitmates. This will push all the converged ones | c | towards the front of ritzr, ritzi, bounds | c | (in the case when NCONV < NEV.) | c %----------------------------------------------------% c wprime = 'LR' call dsortc(wprime, dnatrue, numcnv, bounds, ritzr, ritzi) c c %----------------------------------------------% c | Scale the Ritz estimate back to its original | c | value. | c %----------------------------------------------% c do 40 j = 1, numcnv temp = max(eps23, dlapy2(ritzr(j), & ritzi(j))) bounds(j) = bounds(j)*temp 40 continue c c %------------------------------------------------% c | Sort the converged Ritz values again so that | c | the "threshold" value appears at the front of | c | ritzr, ritzi and bound. | c %------------------------------------------------% c call dsortc(which, dnatrue, nconv, ritzr, ritzi, bounds) c c c %------------------------------------% c | Max iterations have been exceeded. | c %------------------------------------% c if (iter .gt. mxiter .and. nconv .lt. numcnv) info = 1 c c %---------------------% c | No shifts to apply. | c %---------------------% c if (np .eq. 0 .and. nconv .lt. numcnv) info = 2 c np = nconv go to 1100 c else if ( (nconv .lt. numcnv) .and. (ishift .eq. 1) ) then c c %-------------------------------------------------% c | Do not have all the requested eigenvalues yet. | c | To prevent possible stagnation, adjust the size | c | of NEV. | c %-------------------------------------------------% c nevbef = nev nev = nev + min(nconv, np/2) if (nev .eq. 1 .and. kplusp .ge. 6) then nev = kplusp / 2 else if (nev .eq. 1 .and. kplusp .gt. 3) then nev = 2 end if np = kplusp - nev c c %---------------------------------------% c | If the size of NEV was just increased | c | resort the eigenvalues. | c %---------------------------------------% c if (nevbef .lt. nev) & call dngets (ishift, which, nev, np, ritzr, ritzi, & bounds) c end if c if (ishift .eq. 0) then c c %-------------------------------------------------------% c | User specified shifts: reverse comminucation to | c | compute the shifts. They are returned in the first | c | 2*NP locations of WORKL. | c %-------------------------------------------------------% c ushift = .true. ido = 3 go to 9000 end if c 50 continue c c %------------------------------------% c | Back from reverse communication; | c | User specified shifts are returned | c | in WORKL(1:2*NP) | c %------------------------------------% c ushift = .false. c if ( ishift .eq. 0 ) then c c %----------------------------------% c | Move the NP shifts from WORKL to | c | RITZR, RITZI to free up WORKL | c | for non-exact shift case. | c %----------------------------------% c call dcopy (np, workl, 1, ritzr(1), 1) call dcopy (np, workl(np+1), 1, ritzi(1), 1) end if c c c %---------------------------------------------------------% c | Apply the NP implicit shifts by QR bulge chasing. | c | Each shift is applied to the whole upper Hessenberg | c | matrix H. | c | The first 2*N locations of WORKD are used as workspace. | c %---------------------------------------------------------% c call dnapps (n, nev, np, ritzr, ritzi, v, ldv, & h, ldh, resid, q, ldq, workl, workd) c c %---------------------------------------------% c | Compute the B-norm of the updated residual. | c | Keep B*RESID in WORKD(1:N) to be used in | c | the first step of the next call to dnaitr. | c %---------------------------------------------% c cnorm = .true. if (bmat .eq. 'G') then call dcopy (n, resid, 1, workd(n+1), 1) ipntr(1) = n + 1 ipntr(2) = 1 ido = 2 c c %----------------------------------% c | Exit in order to compute B*RESID | c %----------------------------------% c go to 9000 else if (bmat .eq. 'I') then call dcopy (n, resid, 1, workd(1), 1) end if c 100 continue c c %----------------------------------% c | Back from reverse communication; | c | WORKD(1:N) := B*RESID | c %----------------------------------% c if (bmat .eq. 'G') then rnorm = ddot (n, resid, 1, workd, 1) rnorm = sqrt(abs(rnorm)) else if (bmat .eq. 'I') then rnorm = dnrm2(n, resid, 1) end if cnorm = .false. c go to 1000 c c %---------------------------------------------------------------% c | | c | E N D O F M A I N I T E R A T I O N L O O P | c | | c %---------------------------------------------------------------% c 1100 continue c mxiter = iter nev = numcnv c 1200 continue ido = 99 c c %------------% c | Error Exit | c %------------% c 9000 continue c c %---------------% c | End of dnaup2 | c %---------------% c return end c----------------------------------------------------------------------- c\BeginDoc c c\Name: dnapps c c\Description: c Given the Arnoldi factorization c c A*V_{k} - V_{k}*H_{k} = r_{k+p}*e_{k+p}^T, c c apply NP implicit shifts resulting in c c A*(V_{k}*Q) - (V_{k}*Q)*(Q^T* H_{k}*Q) = r_{k+p}*e_{k+p}^T * Q c c where Q is an orthogonal matrix which is the product of rotations c and reflections resulting from the NP bulge chage sweeps. c The updated Arnoldi factorization becomes: c c A*VNEW_{k} - VNEW_{k}*HNEW_{k} = rnew_{k}*e_{k}^T. c c\Usage: c call dnapps c ( N, KEV, NP, SHIFTR, SHIFTI, V, LDV, H, LDH, RESID, Q, LDQ, c WORKL, WORKD ) c c\Arguments c N Integer. (INPUT) c Problem size, i.e. size of matrix A. c c KEV Integer. (INPUT/OUTPUT) c KEV+NP is the size of the input matrix H. c KEV is the size of the updated matrix HNEW. KEV is only c updated on ouput when fewer than NP shifts are applied in c order to keep the conjugate pair together. c c NP Integer. (INPUT) c Number of implicit shifts to be applied. c c SHIFTR, Double precision array of length NP. (INPUT) c SHIFTI Real and imaginary part of the shifts to be applied. c Upon, entry to dnapps, the shifts must be sorted so that the c conjugate pairs are in consecutive locations. c c V Double precision N by (KEV+NP) array. (INPUT/OUTPUT) c On INPUT, V contains the current KEV+NP Arnoldi vectors. c On OUTPUT, V contains the updated KEV Arnoldi vectors c in the first KEV columns of V. c c LDV Integer. (INPUT) c Leading dimension of V exactly as declared in the calling c program. c c H Double precision (KEV+NP) by (KEV+NP) array. (INPUT/OUTPUT) c On INPUT, H contains the current KEV+NP by KEV+NP upper c Hessenber matrix of the Arnoldi factorization. c On OUTPUT, H contains the updated KEV by KEV upper Hessenberg c matrix in the KEV leading submatrix. c c LDH Integer. (INPUT) c Leading dimension of H exactly as declared in the calling c program. c c RESID Double precision array of length N. (INPUT/OUTPUT) c On INPUT, RESID contains the the residual vector r_{k+p}. c On OUTPUT, RESID is the update residual vector rnew_{k} c in the first KEV locations. c c Q Double precision KEV+NP by KEV+NP work array. (WORKSPACE) c Work array used to accumulate the rotations and reflections c during the bulge chase sweep. c c LDQ Integer. (INPUT) c Leading dimension of Q exactly as declared in the calling c program. c c WORKL Double precision work array of length (KEV+NP). (WORKSPACE) c Private (replicated) array on each PE or array allocated on c the front end. c c WORKD Double precision work array of length 2*N. (WORKSPACE) c Distributed array used in the application of the accumulated c orthogonal matrix Q. c c\EndDoc c c----------------------------------------------------------------------- c c\BeginLib c c\Local variables: c xxxxxx real c c\References: c 1. D.C. Sorensen, "Implicit Application of Polynomial Filters in c a k-Step Arnoldi Method", SIAM J. Matr. Anal. Apps., 13 (1992), c pp 357-385. c c\Routines called: c ivout ARPACK utility routine that prints integers. c second ARPACK utility routine for timing. c dmout ARPACK utility routine that prints matrices. c dvout ARPACK utility routine that prints vectors. c dlabad LAPACK routine that computes machine constants. c dlacpy LAPACK matrix copy routine. c dlamch LAPACK routine that determines machine constants. c dlanhs LAPACK routine that computes various norms of a matrix. c dlapy2 LAPACK routine to compute sqrt(x**2+y**2) carefully. c dlarf LAPACK routine that applies Householder reflection to c a matrix. c dlarfg LAPACK Householder reflection construction routine. c dlartg LAPACK Givens rotation construction routine. c dlaset LAPACK matrix initialization routine. c dgemv Level 2 BLAS routine for matrix vector multiplication. c daxpy Level 1 BLAS that computes a vector triad. c dcopy Level 1 BLAS that copies one vector to another . c dscal Level 1 BLAS that scales a vector. c c\Author c Danny Sorensen Phuong Vu c Richard Lehoucq CRPC / Rice University c Dept. of Computational & Houston, Texas c Applied Mathematics c Rice University c Houston, Texas c c\Revision history: c xx/xx/92: Version ' 2.4' c c\SCCS Information: @(#) c FILE: napps.F SID: 2.4 DATE OF SID: 3/28/97 RELEASE: 2 c c\Remarks c 1. In this version, each shift is applied to all the sublocks of c the Hessenberg matrix H and not just to the submatrix that it c comes from. Deflation as in LAPACK routine dlahqr (QR algorithm c for upper Hessenberg matrices ) is used. c The subdiagonals of H are enforced to be non-negative. c c\EndLib c c----------------------------------------------------------------------- c subroutine dnapps & ( n, kev, np, shiftr, shifti, v, ldv, h, ldh, resid, q, ldq, & workl, workd ) implicit none c c %------------------% c | Scalar Arguments | c %------------------% c integer kev, ldh, ldq, ldv, n, np c c %-----------------% c | Array Arguments | c %-----------------% c Double precision & h(ldh,kev+np), resid(n), shifti(np), shiftr(np), & v(ldv,kev+np), q(ldq,kev+np), workd(2*n), workl(kev+np) c c %------------% c | Parameters | c %------------% c Double precision & one, zero parameter (one = 1.0D+0, zero = 0.0D+0) integer ione parameter (ione = 1) c c %------------------------% c | Local Scalars & Arrays | c %------------------------% c integer i, iend, ir, istart, j, jj, kplusp, nr logical cconj, first Double precision & c, f, g, h11, h12, h21, h22, h32, ovfl, r, s, sigmai, & sigmar, smlnum, ulp, unfl, u(3), t, tau, tst1 save first, ovfl, smlnum, ulp, unfl c c %----------------------% c | External Subroutines | c %----------------------% c external daxpy, dcopy, dscal, dlacpy, dlarfg, dlarf, & dlaset, dlabad, dlartg c c %--------------------% c | External Functions | c %--------------------% c c Double precision & dlamch, dlanhs, dlapy2 external dlamch, dlanhs, dlapy2 c c %----------------------% c | Intrinsics Functions | c %----------------------% c intrinsic abs, max, min c c %----------------% c | Data statments | c %----------------% c data first / .true. / c c %-----------------------% c | Executable Statements | c %-----------------------% c if (first) then c c %-----------------------------------------------% c | Set machine-dependent constants for the | c | stopping criterion. If norm(H) <= sqrt(OVFL), | c | overflow should not occur. | c | REFERENCE: LAPACK subroutine dlahqr | c %-----------------------------------------------% c unfl = dlamch( 'safe minimum' ) ovfl = one / unfl call dlabad( unfl, ovfl ) ulp = dlamch( 'precision' ) smlnum = unfl*( n / ulp ) first = .false. end if c c %-------------------------------% c | Initialize timing statistics | c | & message level for debugging | c %-------------------------------% c c call second (t0) kplusp = kev + np c c %--------------------------------------------% c | Initialize Q to the identity to accumulate | c | the rotations and reflections | c %--------------------------------------------% c call dlaset ('All', kplusp, kplusp, zero, one, q, ldq) c c %----------------------------------------------% c | Quick return if there are no shifts to apply | c %----------------------------------------------% c if (np .eq. 0) go to 9000 c c %----------------------------------------------% c | Chase the bulge with the application of each | c | implicit shift. Each shift is applied to the | c | whole matrix including each block. | c %----------------------------------------------% c cconj = .false. do 110 jj = 1, np sigmar = shiftr(jj) sigmai = shifti(jj) c c %-------------------------------------------------% c | The following set of conditionals is necessary | c | in order that complex conjugate pairs of shifts | c | are applied together or not at all. | c %-------------------------------------------------% c if ( cconj ) then c c %-----------------------------------------% c | cconj = .true. means the previous shift | c | had non-zero imaginary part. | c %-----------------------------------------% c cconj = .false. go to 110 else if ( jj .lt. np .and. abs( sigmai ) .gt. zero ) then c c %------------------------------------% c | Start of a complex conjugate pair. | c %------------------------------------% c cconj = .true. else if ( jj .eq. np .and. abs( sigmai ) .gt. zero ) then c c %----------------------------------------------% c | The last shift has a nonzero imaginary part. | c | Don't apply it; thus the order of the | c | compressed H is order KEV+1 since only np-1 | c | were applied. | c %----------------------------------------------% c kev = kev + 1 go to 110 end if istart = 1 20 continue c c %--------------------------------------------------% c | if sigmai = 0 then | c | Apply the jj-th shift ... | c | else | c | Apply the jj-th and (jj+1)-th together ... | c | (Note that jj < np at this point in the code) | c | end | c | to the current block of H. The next do loop | c | determines the current block ; | c %--------------------------------------------------% c do 30 i = istart, kplusp-1 c c %----------------------------------------% c | Check for splitting and deflation. Use | c | a standard test as in the QR algorithm | c | REFERENCE: LAPACK subroutine dlahqr | c %----------------------------------------% c tst1 = abs( h( i, i ) ) + abs( h( i+1, i+1 ) ) c if( tst1.eq.zero ) if( abs(tst1) .le. zero ) & tst1 = dlanhs( '1', kplusp-jj+1, h, ldh, workl ) if( abs( h( i+1,i ) ).le.max( ulp*tst1, smlnum ) ) then iend = i h(i+1,i) = zero go to 40 end if 30 continue iend = kplusp 40 continue c c %------------------------------------------------% c | No reason to apply a shift to block of order 1 | c %------------------------------------------------% c if ( istart .eq. iend ) go to 100 c c %------------------------------------------------------% c | If istart + 1 = iend then no reason to apply a | c | complex conjugate pair of shifts on a 2 by 2 matrix. | c %------------------------------------------------------% c if ( istart + 1 .eq. iend .and. abs( sigmai ) .gt. zero ) & go to 100 c h11 = h(istart,istart) h21 = h(istart+1,istart) if ( abs( sigmai ) .le. zero ) then c c %---------------------------------------------% c | Real-valued shift ==> apply single shift QR | c %---------------------------------------------% c f = h11 - sigmar g = h21 c do 80 i = istart, iend-1 c c %-----------------------------------------------------% c | Contruct the plane rotation G to zero out the bulge | c %-----------------------------------------------------% c call dlartg (f, g, c, s, r) if (i .gt. istart) then c c %-------------------------------------------% c | The following ensures that h(1:iend-1,1), | c | the first iend-2 off diagonal of elements | c | H, remain non negative. | c %-------------------------------------------% c if (r .lt. zero) then r = -r c = -c s = -s end if h(i,i-1) = r h(i+1,i-1) = zero end if c c %---------------------------------------------% c | Apply rotation to the left of H; H <- G'*H | c %---------------------------------------------% c do 50 j = i, kplusp t = c*h(i,j) + s*h(i+1,j) h(i+1,j) = -s*h(i,j) + c*h(i+1,j) h(i,j) = t 50 continue c c %---------------------------------------------% c | Apply rotation to the right of H; H <- H*G | c %---------------------------------------------% c do 60 j = 1, min(i+2,iend) t = c*h(j,i) + s*h(j,i+1) h(j,i+1) = -s*h(j,i) + c*h(j,i+1) h(j,i) = t 60 continue c c %----------------------------------------------------% c | Accumulate the rotation in the matrix Q; Q <- Q*G | c %----------------------------------------------------% c do 70 j = 1, min( i+jj, kplusp ) t = c*q(j,i) + s*q(j,i+1) q(j,i+1) = - s*q(j,i) + c*q(j,i+1) q(j,i) = t 70 continue c c %---------------------------% c | Prepare for next rotation | c %---------------------------% c if (i .lt. iend-1) then f = h(i+1,i) g = h(i+2,i) end if 80 continue c c %-----------------------------------% c | Finished applying the real shift. | c %-----------------------------------% c else c c %----------------------------------------------------% c | Complex conjugate shifts ==> apply double shift QR | c %----------------------------------------------------% c h12 = h(istart,istart+1) h22 = h(istart+1,istart+1) h32 = h(istart+2,istart+1) c c %---------------------------------------------------------% c | Compute 1st column of (H - shift*I)*(H - conj(shift)*I) | c %---------------------------------------------------------% c s = 2.0*sigmar t = dlapy2 ( sigmar, sigmai ) u(1) = ( h11 * (h11 - s) + t * t ) / h21 + h12 u(2) = h11 + h22 - s u(3) = h32 c do 90 i = istart, iend-1 c nr = min ( 3, iend-i+1 ) c c %-----------------------------------------------------% c | Construct Householder reflector G to zero out u(1). | c | G is of the form I - tau*( 1 u )' * ( 1 u' ). | c %-----------------------------------------------------% c call dlarfg ( nr, u(1), u(2), 1, tau ) c if (i .gt. istart) then h(i,i-1) = u(1) h(i+1,i-1) = zero if (i .lt. iend-1) h(i+2,i-1) = zero end if u(1) = one c c %--------------------------------------% c | Apply the reflector to the left of H | c %--------------------------------------% c call dlarf ('Left', nr, kplusp-i+1, u, 1, tau, & h(i,i), ldh, workl) c c %---------------------------------------% c | Apply the reflector to the right of H | c %---------------------------------------% c ir = min ( i+3, iend ) call dlarf ('Right', ir, nr, u, 1, tau, & h(1,i), ldh, workl) c c %-----------------------------------------------------% c | Accumulate the reflector in the matrix Q; Q <- Q*G | c %-----------------------------------------------------% c call dlarf ('Right', kplusp, nr, u, 1, tau, & q(1,i), ldq, workl) c c %----------------------------% c | Prepare for next reflector | c %----------------------------% c if (i .lt. iend-1) then u(1) = h(i+1,i) u(2) = h(i+2,i) if (i .lt. iend-2) u(3) = h(i+3,i) end if c 90 continue c c %--------------------------------------------% c | Finished applying a complex pair of shifts | c | to the current block | c %--------------------------------------------% c end if c 100 continue c c %---------------------------------------------------------% c | Apply the same shift to the next block if there is any. | c %---------------------------------------------------------% c istart = iend + 1 if (iend .lt. kplusp) go to 20 c c %---------------------------------------------% c | Loop back to the top to get the next shift. | c %---------------------------------------------% c 110 continue c c %--------------------------------------------------% c | Perform a similarity transformation that makes | c | sure that H will have non negative sub diagonals | c %--------------------------------------------------% c do 120 j=1,kev if ( h(j+1,j) .lt. zero ) then call dscal( kplusp-j+1, -one, h(j+1,j), int(ldh, kind=4)) call dscal( min(j+2, kplusp), -one, h(1,j+1), & int(ione, kind=4)) call dscal( min(j+np+1,kplusp), -one, q(1,j+1), & int(ione, kind=4)) cv call dscal( min(j+2, kplusp), -one, h(1,j+1), 1 ) cv call dscal( min(j+np+1,kplusp), -one, q(1,j+1), 1 ) end if 120 continue c do 130 i = 1, kev c c %--------------------------------------------% c | Final check for splitting and deflation. | c | Use a standard test as in the QR algorithm | c | REFERENCE: LAPACK subroutine dlahqr | c %--------------------------------------------% c tst1 = abs( h( i, i ) ) + abs( h( i+1, i+1 ) ) c if( tst1.eq.zero ) if( abs(tst1) .le. zero) & tst1 = dlanhs( '1', kev, h, ldh, workl ) if( h( i+1,i ) .le. max( ulp*tst1, smlnum ) ) & h(i+1,i) = zero 130 continue c c %-------------------------------------------------% c | Compute the (kev+1)-st column of (V*Q) and | c | temporarily store the result in WORKD(N+1:2*N). | c | This is needed in the residual update since we | c | cannot GUARANTEE that the corresponding entry | c | of H would be zero as in exact arithmetic. | c %-------------------------------------------------% c if (h(kev+1,kev) .gt. zero) & call dgemv ('N', n, kplusp, one, v, ldv, q(1,kev+1), 1, zero, & workd(n+1), 1) c c %----------------------------------------------------------% c | Compute column 1 to kev of (V*Q) in backward order | c | taking advantage of the upper Hessenberg structure of Q. | c %----------------------------------------------------------% c do 140 i = 1, kev call dgemv ('N', n, kplusp-i+1, one, v, ldv, & q(1,kev-i+1), 1, zero, workd(1), 1) call dcopy (n, workd, 1, v(1,kplusp-i+1), 1) 140 continue c c %-------------------------------------------------% c | Move v(:,kplusp-kev+1:kplusp) into v(:,1:kev). | c %-------------------------------------------------% c call dlacpy ('A', n, kev, v(1,kplusp-kev+1), ldv, v, ldv) c c %--------------------------------------------------------------% c | Copy the (kev+1)-st column of (V*Q) in the appropriate place | c %--------------------------------------------------------------% c if (h(kev+1,kev) .gt. zero) & call dcopy (n, workd(n+1), 1, v(1,kev+1), 1) c c %-------------------------------------% c | Update the residual vector: | c | r <- sigmak*r + betak*v(:,kev+1) | c | where | c | sigmak = (e_{kplusp}'*Q)*e_{kev} | c | betak = e_{kev+1}'*H*e_{kev} | c %-------------------------------------% c call dscal (n, q(kplusp,kev), resid(1), int(ione, kind=4)) if (h(kev+1,kev) .gt. zero) & call daxpy (n, h(kev+1,kev), v(1,kev+1), 1, resid, 1) c 9000 continue c return c c %---------------% c | End of dnapps | c %---------------% c end c----------------------------------------------------------------------- c\BeginDoc c c\Name: dnconv c c\Description: c Convergence testing for the nonsymmetric Arnoldi eigenvalue routine. c c\Usage: c call dnconv c ( N, RITZR, RITZI, BOUNDS, TOL, NCONV ) c c\Arguments c N Integer. (INPUT) c Number of Ritz values to check for convergence. c c RITZR, Double precision arrays of length N. (INPUT) c RITZI Real and imaginary parts of the Ritz values to be checked c for convergence. c BOUNDS Double precision array of length N. (INPUT) c Ritz estimates for the Ritz values in RITZR and RITZI. c c TOL Double precision scalar. (INPUT) c Desired backward error for a Ritz value to be considered c "converged". c c NCONV Integer scalar. (OUTPUT) c Number of "converged" Ritz values. c c\EndDoc c c----------------------------------------------------------------------- c c\BeginLib c c\Local variables: c xxxxxx real c c\Routines called: c second ARPACK utility routine for timing. c dlamch LAPACK routine that determines machine constants. c dlapy2 LAPACK routine to compute sqrt(x**2+y**2) carefully. c c\Author c Danny Sorensen Phuong Vu c Richard Lehoucq CRPC / Rice University c Dept. of Computational & Houston, Texas c Applied Mathematics c Rice University c Houston, Texas c c\Revision history: c xx/xx/92: Version ' 2.1' c c\SCCS Information: @(#) c FILE: nconv.F SID: 2.3 DATE OF SID: 4/20/96 RELEASE: 2 c c\Remarks c 1. xxxx c c\EndLib c c----------------------------------------------------------------------- c subroutine dnconv (n, ritzr, ritzi, bounds, tol, nconv) implicit none c c %------------------% c | Scalar Arguments | c %------------------% c integer n, nconv Double precision & tol c c %-----------------% c | Array Arguments | c %-----------------% Double precision & ritzr(n), ritzi(n), bounds(n) c c %---------------% c | Local Scalars | c %---------------% c integer i Double precision & temp, eps23 c c %--------------------% c | External Functions | c %--------------------% c Double precision & dlapy2, dlamch external dlapy2, dlamch c %-----------------------% c | Executable Statements | c %-----------------------% c c %-------------------------------------------------------------% c | Convergence test: unlike in the symmetric code, I am not | c | using things like refined error bounds and gap condition | c | because I don't know the exact equivalent concept. | c | | c | Instead the i-th Ritz value is considered "converged" when: | c | | c | bounds(i) .le. ( TOL * | ritz | ) | c | | c | for some appropriate choice of norm. | c %-------------------------------------------------------------% c c %---------------------------------% c | Get machine dependent constant. | c %---------------------------------% c eps23 = dlamch('Epsilon-Machine') eps23 = eps23**(2.0D+0 / 3.0D+0) c nconv = 0 do 20 i = 1, n temp = max( eps23, dlapy2( ritzr(i), ritzi(i) ) ) if (bounds(i) .le. tol*temp) nconv = nconv + 1 20 continue c return c c %---------------% c | End of dnconv | c %---------------% c end c----------------------------------------------------------------------- c\BeginDoc c c\Name: dsortc c c\Description: c Sorts the complex array in XREAL and XIMAG into the order c specified by WHICH and optionally applies the permutation to the c real array Y. It is assumed that if an element of XIMAG is c nonzero, then its negative is also an element. In other words, c both members of a complex conjugate pair are to be sorted and the c pairs are kept adjacent to each other. c c\Usage: c call dsortc c ( WHICH, APPLY, N, XREAL, XIMAG, Y ) c c\Arguments c WHICH Character*2. (Input) c 'LM' -> sort XREAL,XIMAG into increasing order of magnitude. c 'SM' -> sort XREAL,XIMAG into decreasing order of magnitude. c 'LR' -> sort XREAL into increasing order of algebraic. c 'SR' -> sort XREAL into decreasing order of algebraic. c 'LI' -> sort XIMAG into increasing order of magnitude. c 'SI' -> sort XIMAG into decreasing order of magnitude. c NOTE: If an element of XIMAG is non-zero, then its negative c is also an element. c c APPLY Logical. (Input) c APPLY = .TRUE. -> apply the sorted order to array Y. c APPLY = .FALSE. -> do not apply the sorted order to array Y. c c N Integer. (INPUT) c Size of the arrays. c c XREAL, Double precision array of length N. (INPUT/OUTPUT) c XIMAG Real and imaginary part of the array to be sorted. c c Y Double precision array of length N. (INPUT/OUTPUT) c c\EndDoc c c----------------------------------------------------------------------- c c\BeginLib c c\Author c Danny Sorensen Phuong Vu c Richard Lehoucq CRPC / Rice University c Dept. of Computational & Houston, Texas c Applied Mathematics c Rice University c Houston, Texas c c\Revision history: c xx/xx/92: Version ' 2.1' c Adapted from the sort routine in LANSO. c c\SCCS Information: @(#) c FILE: sortc.F SID: 2.3 DATE OF SID: 4/20/96 RELEASE: 2 c c\EndLib c c----------------------------------------------------------------------- c subroutine dsortc (which, apply, n, xreal, ximag, y) c implicit none c c %------------------% c | Scalar Arguments | c %------------------% c character which*2 logical apply integer n c c %-----------------% c | Array Arguments | c %-----------------% c Double precision & xreal(0:n-1), ximag(0:n-1), y(0:n-1) c c %---------------% c | Local Scalars | c %---------------% c integer i, igap, j Double precision & temp, temp1, temp2 c c %--------------------% c | External Functions | c %--------------------% c Double precision & dlapy2 external dlapy2 c c %-----------------------% c | Executable Statements | c %-----------------------% c igap = n / 2 c if (which .eq. 'LM') then c c %------------------------------------------------------% c | Sort XREAL,XIMAG into increasing order of magnitude. | c %------------------------------------------------------% c 10 continue if (igap .eq. 0) go to 9000 c do 30 i = igap, n-1 j = i-igap 20 continue c if (j.lt.0) go to 30 c temp1 = dlapy2(xreal(j),ximag(j)) temp2 = dlapy2(xreal(j+igap),ximag(j+igap)) c if (temp1.gt.temp2) then temp = xreal(j) xreal(j) = xreal(j+igap) xreal(j+igap) = temp c temp = ximag(j) ximag(j) = ximag(j+igap) ximag(j+igap) = temp c if (apply) then temp = y(j) y(j) = y(j+igap) y(j+igap) = temp end if else go to 30 end if j = j-igap go to 20 30 continue igap = igap / 2 go to 10 c else if (which .eq. 'SM') then c c %------------------------------------------------------% c | Sort XREAL,XIMAG into decreasing order of magnitude. | c %------------------------------------------------------% c 40 continue if (igap .eq. 0) go to 9000 c do 60 i = igap, n-1 j = i-igap 50 continue c if (j .lt. 0) go to 60 c temp1 = dlapy2(xreal(j),ximag(j)) temp2 = dlapy2(xreal(j+igap),ximag(j+igap)) c if (temp1.lt.temp2) then temp = xreal(j) xreal(j) = xreal(j+igap) xreal(j+igap) = temp c temp = ximag(j) ximag(j) = ximag(j+igap) ximag(j+igap) = temp c if (apply) then temp = y(j) y(j) = y(j+igap) y(j+igap) = temp end if else go to 60 endif j = j-igap go to 50 60 continue igap = igap / 2 go to 40 c else if (which .eq. 'LR') then c c %------------------------------------------------% c | Sort XREAL into increasing order of algebraic. | c %------------------------------------------------% c 70 continue if (igap .eq. 0) go to 9000 c do 90 i = igap, n-1 j = i-igap 80 continue c if (j.lt.0) go to 90 c if (xreal(j).gt.xreal(j+igap)) then temp = xreal(j) xreal(j) = xreal(j+igap) xreal(j+igap) = temp c temp = ximag(j) ximag(j) = ximag(j+igap) ximag(j+igap) = temp c if (apply) then temp = y(j) y(j) = y(j+igap) y(j+igap) = temp end if else go to 90 endif j = j-igap go to 80 90 continue igap = igap / 2 go to 70 c else if (which .eq. 'SR') then c c %------------------------------------------------% c | Sort XREAL into decreasing order of algebraic. | c %------------------------------------------------% c 100 continue if (igap .eq. 0) go to 9000 do 120 i = igap, n-1 j = i-igap 110 continue c if (j.lt.0) go to 120 c if (xreal(j).lt.xreal(j+igap)) then temp = xreal(j) xreal(j) = xreal(j+igap) xreal(j+igap) = temp c temp = ximag(j) ximag(j) = ximag(j+igap) ximag(j+igap) = temp c if (apply) then temp = y(j) y(j) = y(j+igap) y(j+igap) = temp end if else go to 120 endif j = j-igap go to 110 120 continue igap = igap / 2 go to 100 c else if (which .eq. 'LI') then c c %------------------------------------------------% c | Sort XIMAG into increasing order of magnitude. | c %------------------------------------------------% c 130 continue if (igap .eq. 0) go to 9000 do 150 i = igap, n-1 j = i-igap 140 continue c if (j.lt.0) go to 150 c if (abs(ximag(j)).gt.abs(ximag(j+igap))) then temp = xreal(j) xreal(j) = xreal(j+igap) xreal(j+igap) = temp c temp = ximag(j) ximag(j) = ximag(j+igap) ximag(j+igap) = temp c if (apply) then temp = y(j) y(j) = y(j+igap) y(j+igap) = temp end if else go to 150 endif j = j-igap go to 140 150 continue igap = igap / 2 go to 130 c else if (which .eq. 'SI') then c c %------------------------------------------------% c | Sort XIMAG into decreasing order of magnitude. | c %------------------------------------------------% c 160 continue if (igap .eq. 0) go to 9000 do 180 i = igap, n-1 j = i-igap 170 continue c if (j.lt.0) go to 180 c if (abs(ximag(j)).lt.abs(ximag(j+igap))) then temp = xreal(j) xreal(j) = xreal(j+igap) xreal(j+igap) = temp c temp = ximag(j) ximag(j) = ximag(j+igap) ximag(j+igap) = temp c if (apply) then temp = y(j) y(j) = y(j+igap) y(j+igap) = temp end if else go to 180 endif j = j-igap go to 170 180 continue igap = igap / 2 go to 160 end if c 9000 continue return c c %---------------% c | End of dsortc | c %---------------% c end c----------------------------------------------------------------------- c\BeginDoc c c\Name: dneigh c c\Description: c Compute the eigenvalues of the current upper Hessenberg matrix c and the corresponding Ritz estimates given the current residual norm. c c\Usage: c call dneigh c ( RNORM, N, H, LDH, RITZR, RITZI, BOUNDS, Q, LDQ, WORKL, IERR ) c c\Arguments c RNORM Double precision scalar. (INPUT) c Residual norm corresponding to the current upper Hessenberg c matrix H. c c N Integer. (INPUT) c Size of the matrix H. c c H Double precision N by N array. (INPUT) c H contains the current upper Hessenberg matrix. c c LDH Integer. (INPUT) c Leading dimension of H exactly as declared in the calling c program. c c RITZR, Double precision arrays of length N. (OUTPUT) c RITZI On output, RITZR(1:N) (resp. RITZI(1:N)) contains the real c (respectively imaginary) parts of the eigenvalues of H. c c BOUNDS Double precision array of length N. (OUTPUT) c On output, BOUNDS contains the Ritz estimates associated with c the eigenvalues RITZR and RITZI. This is equal to RNORM c times the last components of the eigenvectors corresponding c to the eigenvalues in RITZR and RITZI. c c Q Double precision N by N array. (WORKSPACE) c Workspace needed to store the eigenvectors of H. c c LDQ Integer. (INPUT) c Leading dimension of Q exactly as declared in the calling c program. c c WORKL Double precision work array of length N**2 + 3*N. (WORKSPACE) c Private (replicated) array on each PE or array allocated on c the front end. This is needed to keep the full Schur form c of H and also in the calculation of the eigenvectors of H. c c IERR Integer. (OUTPUT) c Error exit flag from dlaqrb or dtrevc. c c\EndDoc c c----------------------------------------------------------------------- c c\BeginLib c c\Local variables: c xxxxxx real c c\Routines called: c dlaqrb ARPACK routine to compute the real Schur form of an c upper Hessenberg matrix and last row of the Schur vectors. c second ARPACK utility routine for timing. c dmout ARPACK utility routine that prints matrices c dvout ARPACK utility routine that prints vectors. c dlacpy LAPACK matrix copy routine. c dlapy2 LAPACK routine to compute sqrt(x**2+y**2) carefully. c dtrevc LAPACK routine to compute the eigenvectors of a matrix c in upper quasi-triangular form c dgemv Level 2 BLAS routine for matrix vector multiplication. c dcopy Level 1 BLAS that copies one vector to another . c dnrm2 Level 1 BLAS that computes the norm of a vector. c dscal Level 1 BLAS that scales a vector. c c c\Author c Danny Sorensen Phuong Vu c Richard Lehoucq CRPC / Rice University c Dept. of Computational & Houston, Texas c Applied Mathematics c Rice University c Houston, Texas c c\Revision history: c xx/xx/92: Version ' 2.1' c c\SCCS Information: @(#) c FILE: neigh.F SID: 2.3 DATE OF SID: 4/20/96 RELEASE: 2 c c\Remarks c None c c\EndLib c c----------------------------------------------------------------------- c subroutine dneigh (rnorm, n, h, ldh, ritzr, ritzi, bounds, & q, ldq, workl, ierr) implicit none c c %------------------% c | Scalar Arguments | c %------------------% c integer ierr, n, ldh, ldq Double precision & rnorm c c %-----------------% c | Array Arguments | c %-----------------% c Double precision & bounds(n), h(ldh,n), q(ldq,n), ritzi(n), ritzr(n), & workl(n*(n+3)) c c %------------% c | Parameters | c %------------% c Double precision & one, zero parameter (one = 1.0D+0, zero = 0.0D+0) c integer & ione parameter (ione = 1) c c %------------------------% c | Local Scalars & Arrays | c %------------------------% c c % dneightrue = .true. to adress logical(4)/(8) c % initialization for spam/spam64 c % analogue for dneighone logical select(1), dneightrue integer i, iconj, dneighone Double precision & temp, vl(1) c c %----------------------% c | External Subroutines | c %----------------------% c external dcopy, dlacpy, dlaqrb, dtrevc c c %--------------------% c | External Functions | c %--------------------% c Double precision & dlapy2, dnrm2 external dlapy2, dnrm2 c c %---------------------% c | Intrinsic Functions | c %---------------------% c intrinsic abs c c %-----------------------% c | Executable Statements | c %-----------------------% c c c %-------------------------------% c | Initialize timing statistics | c | & message level for debugging | c %-------------------------------% c dneightrue = .true. dneighone = 1 c c c %-----------------------------------------------------------% c | 1. Compute the eigenvalues, the last components of the | c | corresponding Schur vectors and the full Schur form T | c | of the current upper Hessenberg matrix H. | c | dlaqrb returns the full Schur form of H in WORKL(1:N**2) | c | and the last components of the Schur vectors in BOUNDS. | c %-----------------------------------------------------------% c cx call dlacpy ('All', n, n, h, ldh, workl, n) call dlacpy ('All', n, n, h(1,1), ldh, workl, n) call dlaqrb (dneightrue, n, dneighone, n, workl, n, ritzr, ritzi, & bounds, ierr) if (ierr .ne. 0) go to 9000 c c c %-----------------------------------------------------------% c | 2. Compute the eigenvectors of the full Schur form T and | c | apply the last components of the Schur vectors to get | c | the last components of the corresponding eigenvectors. | c | Remember that if the i-th and (i+1)-st eigenvalues are | c | complex conjugate pairs, then the real & imaginary part | c | of the eigenvector components are split across adjacent | c | columns of Q. | c %-----------------------------------------------------------% c call dtrevc ('R', 'A', select, n, workl, n, vl, n, q, ldq, & n, n, workl(n*n+1), ierr) c if (ierr .ne. 0) go to 9000 c c %------------------------------------------------% c | Scale the returning eigenvectors so that their | c | euclidean norms are all one. LAPACK subroutine | c | dtrevc returns each eigenvector normalized so | c | that the element of largest magnitude has | c | magnitude 1; here the magnitude of a complex | c | number (x,y) is taken to be |x| + |y|. | c %------------------------------------------------% c iconj = 0 do 10 i=1, n if ( abs( ritzi(i) ) .le. zero ) then c c %----------------------% c | Real eigenvalue case | c %----------------------% c temp = dnrm2( n, q(1,i), 1 ) call dscal ( n, one / temp, q(1,i), int(ione, kind=4) ) else c c %-------------------------------------------% c | Complex conjugate pair case. Note that | c | since the real and imaginary part of | c | the eigenvector are stored in consecutive | c | columns, we further normalize by the | c | square root of two. | c %-------------------------------------------% c if (iconj .eq. 0) then temp = dlapy2( dnrm2( n, q(1,i), 1 ), & dnrm2( n, q(1,i+1), 1 ) ) call dscal ( n, one / temp, q(1,i), & int(ione, kind=4) ) call dscal ( n, one / temp, q(1,i+1), & int(ione, kind=4) ) iconj = 1 else iconj = 0 end if end if 10 continue c call dgemv('T', n, n, one, q, ldq, bounds(1), 1, zero, & workl(1), 1) c c c %----------------------------% c | Compute the Ritz estimates | c %----------------------------% c iconj = 0 do 20 i = 1, n if ( abs( ritzi(i) ) .le. zero ) then c c %----------------------% c | Real eigenvalue case | c %----------------------% c bounds(i) = rnorm * abs( workl(i) ) else c c %-------------------------------------------% c | Complex conjugate pair case. Note that | c | since the real and imaginary part of | c | the eigenvector are stored in consecutive | c | columns, we need to take the magnitude | c | of the last components of the two vectors | c %-------------------------------------------% c if (iconj .eq. 0) then bounds(i) = rnorm * dlapy2( workl(i), workl(i+1) ) bounds(i+1) = bounds(i) iconj = 1 else iconj = 0 end if end if 20 continue c 9000 continue return c c %---------------% c | End of dneigh | c %---------------% c end c----------------------------------------------------------------------- c\BeginDoc c c\Name: dlaqrb c c\Description: c Compute the eigenvalues and the Schur decomposition of an upper c Hessenberg submatrix in rows and columns ILO to IHI. Only the c last component of the Schur vectors are computed. c c This is mostly a modification of the LAPACK routine dlahqr. c c\Usage: c call dlaqrb c ( WANTT, N, ILO, IHI, H, LDH, WR, WI, Z, INFO ) c c\Arguments c WANTT Logical variable. (INPUT) c = .TRUE. : the full Schur form T is required; c = .FALSE.: only eigenvalues are required. c c N Integer. (INPUT) c The order of the matrix H. N >= 0. c c ILO Integer. (INPUT) c IHI Integer. (INPUT) c It is assumed that H is already upper quasi-triangular in c rows and columns IHI+1:N, and that H(ILO,ILO-1) = 0 (unless c ILO = 1). SLAQRB works primarily with the Hessenberg c submatrix in rows and columns ILO to IHI, but applies c transformations to all of H if WANTT is .TRUE.. c 1 <= ILO <= max(1,IHI); IHI <= N. c c H Double precision array, dimension (LDH,N). (INPUT/OUTPUT) c On entry, the upper Hessenberg matrix H. c On exit, if WANTT is .TRUE., H is upper quasi-triangular in c rows and columns ILO:IHI, with any 2-by-2 diagonal blocks in c standard form. If WANTT is .FALSE., the contents of H are c unspecified on exit. c c LDH Integer. (INPUT) c The leading dimension of the array H. LDH >= max(1,N). c c WR Double precision array, dimension (N). (OUTPUT) c WI Double precision array, dimension (N). (OUTPUT) c The real and imaginary parts, respectively, of the computed c eigenvalues ILO to IHI are stored in the corresponding c elements of WR and WI. If two eigenvalues are computed as a c complex conjugate pair, they are stored in consecutive c elements of WR and WI, say the i-th and (i+1)th, with c WI(i) > 0 and WI(i+1) < 0. If WANTT is .TRUE., the c eigenvalues are stored in the same order as on the diagonal c of the Schur form returned in H, with WR(i) = H(i,i), and, if c H(i:i+1,i:i+1) is a 2-by-2 diagonal block, c WI(i) = sqrt(H(i+1,i)*H(i,i+1)) and WI(i+1) = -WI(i). c c Z Double precision array, dimension (N). (OUTPUT) c On exit Z contains the last components of the Schur vectors. c c INFO Integer. (OUPUT) c = 0: successful exit c > 0: SLAQRB failed to compute all the eigenvalues ILO to IHI c in a total of 30*(IHI-ILO+1) iterations; if INFO = i, c elements i+1:ihi of WR and WI contain those eigenvalues c which have been successfully computed. c c\Remarks c 1. None. c c----------------------------------------------------------------------- c c\BeginLib c c\Local variables: c xxxxxx real c c\Routines called: c dlabad LAPACK routine that computes machine constants. c dlamch LAPACK routine that determines machine constants. c dlanhs LAPACK routine that computes various norms of a matrix. c dlanv2 LAPACK routine that computes the Schur factorization of c 2 by 2 nonsymmetric matrix in standard form. c dlarfg LAPACK Householder reflection construction routine. c dcopy Level 1 BLAS that copies one vector to another. c drot Level 1 BLAS that applies a rotation to a 2 by 2 matrix. c c\Author c Danny Sorensen Phuong Vu c Richard Lehoucq CRPC / Rice University c Dept. of Computational & Houston, Texas c Applied Mathematics c Rice University c Houston, Texas c c\Revision history: c xx/xx/92: Version ' 2.4' c Modified from the LAPACK routine dlahqr so that only the c last component of the Schur vectors are computed. c c\SCCS Information: @(#) c FILE: laqrb.F SID: 2.2 DATE OF SID: 8/27/96 RELEASE: 2 c c\Remarks c 1. None c c\EndLib c c----------------------------------------------------------------------- c subroutine dlaqrb ( wantt, n, ilo, ihi, h, ldh, wr, wi, & z, info ) c implicit none c c %------------------% c | Scalar Arguments | c %------------------% c logical wantt integer ihi, ilo, info, ldh, n c c %-----------------% c | Array Arguments | c %-----------------% c Double precision & h( ldh, * ), wi( * ), wr( * ), z( * ) c c %------------% c | Parameters | c %------------% c Double precision & zero, one, dat1, dat2 parameter (zero = 0.0D+0, one = 1.0D+0, dat1 = 7.5D-1, & dat2 = -4.375D-1) c integer ione parameter (ione = 1) c c %------------------------% c | Local Scalars & Arrays | c %------------------------% c integer i, i1, i2, itn, its, j, k, l, m, nh, nr integer dlqthree & parameter (dlqthree = 3) Double precision & cs, h00, h10, h11, h12, h21, h22, h33, h33s, & h43h34, h44, h44s, ovfl, s, smlnum, sn, sum, & t1, t2, t3, tst1, ulp, unfl, v1, v2, v3 Double precision & v( 3 ), work( 1 ) c c %--------------------% c | External Functions | c %--------------------% c c Double precision & dlamch, dlanhs external dlamch, dlanhs c c %----------------------% c | External Subroutines | c %----------------------% c external dcopy, dlabad, dlanv2, dlarfg, drot c c c %-----------------------% c | Executable Statements | c %-----------------------% c info = 0 c c % if i2 not initialized; Warning: ‘i2’ may be used uninitialized c % in this function [-Wmaybe-uninitialized] i2 = 0 c c %--------------------------% c | Quick return if possible | c %--------------------------% c if( n.eq.0 ) & return if( ilo.eq.ihi ) then wr( ilo ) = h( ilo, ilo ) wi( ilo ) = zero return end if c c %---------------------------------------------% c | Initialize the vector of last components of | c | the Schur vectors for accumulation. | c %---------------------------------------------% c do 5 j = 1, n-1 z(j) = zero 5 continue z(n) = one c nh = ihi - ilo + 1 c c %-------------------------------------------------------------% c | Set machine-dependent constants for the stopping criterion. | c | If norm(H) <= sqrt(OVFL), overflow should not occur. | c %-------------------------------------------------------------% c unfl = dlamch( 'safe minimum' ) ovfl = one / unfl call dlabad( unfl, ovfl ) ulp = dlamch( 'precision' ) smlnum = unfl*( nh / ulp ) c c %---------------------------------------------------------------% c | I1 and I2 are the indices of the first row and last column | c | of H to which transformations must be applied. If eigenvalues | c | only are computed, I1 and I2 are set inside the main loop. | c | Zero out H(J+2,J) = ZERO for J=1:N if WANTT = .TRUE. | c | else H(J+2,J) for J=ILO:IHI-ILO-1 if WANTT = .FALSE. | c %---------------------------------------------------------------% c if( wantt ) then i1 = 1 i2 = n do 8 i=1,i2-2 h(i1+i+1,i) = zero 8 continue else do 9 i=1, ihi-ilo-1 h(ilo+i+1,ilo+i-1) = zero 9 continue end if c c %---------------------------------------------------% c | ITN is the total number of QR iterations allowed. | c %---------------------------------------------------% c itn = 30*nh c c ------------------------------------------------------------------ c The main loop begins here. I is the loop index and decreases from c IHI to ILO in steps of 1 or 2. Each iteration of the loop works c with the active submatrix in rows and columns L to I. c Eigenvalues I+1 to IHI have already converged. Either L = ILO or c H(L,L-1) is negligible so that the matrix splits. c ------------------------------------------------------------------ c i = ihi 10 continue l = ilo if( i.lt.ilo ) & go to 150 c %--------------------------------------------------------------% c | Perform QR iterations on rows and columns ILO to I until a | c | submatrix of order 1 or 2 splits off at the bottom because a | c | subdiagonal element has become negligible. | c %--------------------------------------------------------------% do 130 its = 0, itn c c %----------------------------------------------% c | Look for a single small subdiagonal element. | c %----------------------------------------------% c do 20 k = i, l + 1, -1 tst1 = abs( h( k-1, k-1 ) ) + abs( h( k, k ) ) if( abs(tst1) .le. zero) & tst1 = dlanhs( '1', i-l+1, h( l, l ), ldh, work ) if( abs( h( k, k-1 ) ).le.max( ulp*tst1, smlnum ) ) & go to 30 20 continue 30 continue l = k if( l.gt.ilo ) then c c %------------------------% c | H(L,L-1) is negligible | c %------------------------% c h( l, l-1 ) = zero end if c c %-------------------------------------------------------------% c | Exit from loop if a submatrix of order 1 or 2 has split off | c %-------------------------------------------------------------% c if( l.ge.i-1 ) & go to 140 c c %---------------------------------------------------------% c | Now the active submatrix is in rows and columns L to I. | c | If eigenvalues only are being computed, only the active | c | submatrix need be transformed. | c %---------------------------------------------------------% c if( .not.wantt ) then i1 = l i2 = i end if c if( its.eq.10 .or. its.eq.20 ) then c c %-------------------% c | Exceptional shift | c %-------------------% c s = abs( h( i, i-1 ) ) + abs( h( i-1, i-2 ) ) h44 = dat1*s h33 = h44 h43h34 = dat2*s*s c else c c %-----------------------------------------% c | Prepare to use Wilkinson's double shift | c %-----------------------------------------% c h44 = h( i, i ) h33 = h( i-1, i-1 ) h43h34 = h( i, i-1 )*h( i-1, i ) end if c c %-----------------------------------------------------% c | Look for two consecutive small subdiagonal elements | c %-----------------------------------------------------% c do 40 m = i - 2, l, -1 c c %---------------------------------------------------------% c | Determine the effect of starting the double-shift QR | c | iteration at row M, and see if this would make H(M,M-1) | c | negligible. | c %---------------------------------------------------------% c h11 = h( m, m ) h22 = h( m+1, m+1 ) h21 = h( m+1, m ) h12 = h( m, m+1 ) h44s = h44 - h11 h33s = h33 - h11 v1 = ( h33s*h44s-h43h34 ) / h21 + h12 v2 = h22 - h11 - h33s - h44s v3 = h( m+2, m+1 ) s = abs( v1 ) + abs( v2 ) + abs( v3 ) v1 = v1 / s v2 = v2 / s v3 = v3 / s v( 1 ) = v1 v( 2 ) = v2 v( 3 ) = v3 if( m.eq.l ) & go to 50 h00 = h( m-1, m-1 ) h10 = h( m, m-1 ) tst1 = abs( v1 )*( abs( h00 )+abs( h11 )+abs( h22 ) ) if( abs( h10 )*( abs( v2 )+abs( v3 ) ).le.ulp*tst1 ) & go to 50 40 continue 50 continue c c %----------------------% c | Double-shift QR step | c %----------------------% c do 120 k = m, i - 1 c c ------------------------------------------------------------ c The first iteration of this loop determines a reflection G c from the vector V and applies it from left and right to H, c thus creating a nonzero bulge below the subdiagonal. c c Each subsequent iteration determines a reflection G to c restore the Hessenberg form in the (K-1)th column, and thus c chases the bulge one step toward the bottom of the active c submatrix. NR is the order of G. c ------------------------------------------------------------ c nr = min( dlqthree, i-k+1 ) if( k.gt.m ) & call dcopy( nr, h( k, k-1 ), 1, v(1), 1 ) call dlarfg( nr, v( 1 ), v( 2 ), 1, t1 ) if( k.gt.m ) then h( k, k-1 ) = v( 1 ) h( k+1, k-1 ) = zero if( k.lt.i-1 ) & h( k+2, k-1 ) = zero else if( m.gt.l ) then h( k, k-1 ) = -h( k, k-1 ) end if v2 = v( 2 ) t2 = t1*v2 if( nr.eq.3 ) then v3 = v( 3 ) t3 = t1*v3 c c %------------------------------------------------% c | Apply G from the left to transform the rows of | c | the matrix in columns K to I2. | c %------------------------------------------------% c do 60 j = k, i2 sum = h( k, j ) + v2*h( k+1, j ) + v3*h( k+2, j ) h( k, j ) = h( k, j ) - sum*t1 h( k+1, j ) = h( k+1, j ) - sum*t2 h( k+2, j ) = h( k+2, j ) - sum*t3 60 continue c c %----------------------------------------------------% c | Apply G from the right to transform the columns of | c | the matrix in rows I1 to min(K+3,I). | c %----------------------------------------------------% c do 70 j = i1, min( k+3, i ) sum = h( j, k ) + v2*h( j, k+1 ) + v3*h( j, k+2 ) h( j, k ) = h( j, k ) - sum*t1 h( j, k+1 ) = h( j, k+1 ) - sum*t2 h( j, k+2 ) = h( j, k+2 ) - sum*t3 70 continue c c %----------------------------------% c | Accumulate transformations for Z | c %----------------------------------% c sum = z( k ) + v2*z( k+1 ) + v3*z( k+2 ) z( k ) = z( k ) - sum*t1 z( k+1 ) = z( k+1 ) - sum*t2 z( k+2 ) = z( k+2 ) - sum*t3 else if( nr.eq.2 ) then c c %------------------------------------------------% c | Apply G from the left to transform the rows of | c | the matrix in columns K to I2. | c %------------------------------------------------% c do 90 j = k, i2 sum = h( k, j ) + v2*h( k+1, j ) h( k, j ) = h( k, j ) - sum*t1 h( k+1, j ) = h( k+1, j ) - sum*t2 90 continue c c %----------------------------------------------------% c | Apply G from the right to transform the columns of | c | the matrix in rows I1 to min(K+3,I). | c %----------------------------------------------------% c do 100 j = i1, i sum = h( j, k ) + v2*h( j, k+1 ) h( j, k ) = h( j, k ) - sum*t1 h( j, k+1 ) = h( j, k+1 ) - sum*t2 100 continue c c %----------------------------------% c | Accumulate transformations for Z | c %----------------------------------% c sum = z( k ) + v2*z( k+1 ) z( k ) = z( k ) - sum*t1 z( k+1 ) = z( k+1 ) - sum*t2 end if 120 continue 130 continue c c %-------------------------------------------------------% c | Failure to converge in remaining number of iterations | c %-------------------------------------------------------% c info = i return 140 continue if( l.eq.i ) then c c %------------------------------------------------------% c | H(I,I-1) is negligible: one eigenvalue has converged | c %------------------------------------------------------% c wr( i ) = h( i, i ) wi( i ) = zero else if( l.eq.i-1 ) then c c %--------------------------------------------------------% c | H(I-1,I-2) is negligible; | c | a pair of eigenvalues have converged. | c | | c | Transform the 2-by-2 submatrix to standard Schur form, | c | and compute and store the eigenvalues. | c %--------------------------------------------------------% c call dlanv2( h( i-1, i-1 ), h( i-1, i ), h( i, i-1 ), & h( i, i ), wr( i-1 ), wi( i-1 ), wr( i ), wi( i ), & cs, sn ) if( wantt ) then c c %-----------------------------------------------------% c | Apply the transformation to the rest of H and to Z, | c | as required. | c %-----------------------------------------------------% c if( i2.gt.i ) & call drot( i2-i, h( i-1, i+1 ), ldh, h( i, i+1 ), ldh, & cs, sn ) call drot( i-i1-1, h( i1, i-1 ), ione, h( i1, i ), ione, & cs, sn ) sum = cs*z( i-1 ) + sn*z( i ) z( i ) = cs*z( i ) - sn*z( i-1 ) z( i-1 ) = sum end if end if c c %---------------------------------------------------------% c | Decrement number of remaining iterations, and return to | c | start of the main loop with new value of I. | c %---------------------------------------------------------% c itn = itn - its i = l - 1 go to 10 150 continue return c c %---------------% c | End of dlaqrb | c %---------------% c end c----------------------------------------------------------------------- c\BeginDoc c c\Name: dngets c c\Description: c Given the eigenvalues of the upper Hessenberg matrix H, c computes the NP shifts AMU that are zeros of the polynomial of c degree NP which filters out components of the unwanted eigenvectors c corresponding to the AMU's based on some given criteria. c c NOTE: call this even in the case of user specified shifts in order c to sort the eigenvalues, and error bounds of H for later use. c c\Usage: c call dngets c ( ISHIFT, WHICH, KEV, NP, RITZR, RITZI, BOUNDS, SHIFTR, SHIFTI ) c c\Arguments c ISHIFT Integer. (INPUT) c Method for selecting the implicit shifts at each iteration. c ISHIFT = 0: user specified shifts c ISHIFT = 1: exact shift with respect to the matrix H. c c WHICH Character*2. (INPUT) c Shift selection criteria. c 'LM' -> want the KEV eigenvalues of largest magnitude. c 'SM' -> want the KEV eigenvalues of smallest magnitude. c 'LR' -> want the KEV eigenvalues of largest real part. c 'SR' -> want the KEV eigenvalues of smallest real part. c 'LI' -> want the KEV eigenvalues of largest imaginary part. c 'SI' -> want the KEV eigenvalues of smallest imaginary part. c c KEV Integer. (INPUT/OUTPUT) c INPUT: KEV+NP is the size of the matrix H. c OUTPUT: Possibly increases KEV by one to keep complex conjugate c pairs together. c c NP Integer. (INPUT/OUTPUT) c Number of implicit shifts to be computed. c OUTPUT: Possibly decreases NP by one to keep complex conjugate c pairs together. c c RITZR, Double precision array of length KEV+NP. (INPUT/OUTPUT) c RITZI On INPUT, RITZR and RITZI contain the real and imaginary c parts of the eigenvalues of H. c On OUTPUT, RITZR and RITZI are sorted so that the unwanted c eigenvalues are in the first NP locations and the wanted c portion is in the last KEV locations. When exact shifts are c selected, the unwanted part corresponds to the shifts to c be applied. Also, if ISHIFT .eq. 1, the unwanted eigenvalues c are further sorted so that the ones with largest Ritz values c are first. c c BOUNDS Double precision array of length KEV+NP. (INPUT/OUTPUT) c Error bounds corresponding to the ordering in RITZ. c c SHIFTR, SHIFTI *** USE deprecated as of version 2.1. *** c c c\EndDoc c c----------------------------------------------------------------------- c c\BeginLib c c\Local variables: c xxxxxx real c c\Routines called: c dsortc ARPACK sorting routine. c dcopy Level 1 BLAS that copies one vector to another . c c\Author c Danny Sorensen Phuong Vu c Richard Lehoucq CRPC / Rice University c Dept. of Computational & Houston, Texas c Applied Mathematics c Rice University c Houston, Texas c c\Revision history: c xx/xx/92: Version ' 2.1' c c\SCCS Information: @(#) c FILE: ngets.F SID: 2.3 DATE OF SID: 4/20/96 RELEASE: 2 c c\Remarks c 1. xxxx c c\EndLib c c----------------------------------------------------------------------- c subroutine dngets ( ishift, which, kev, np, ritzr, ritzi, bounds) c & shiftr, shifti ) c implicit none c c %------------------% c | Scalar Arguments | c %------------------% c character which*2 integer ishift, kev, np c c %-----------------% c | Array Arguments | c %-----------------% c Double precision & bounds(kev+np), ritzr(kev+np), ritzi(kev+np) c c %------------% c | Parameters | c %------------% c Double precision & zero parameter (zero = 0.0) c c %---------------% c | Local Scalars | c %---------------% c logical dngetstrue c c %----------------------% c | External Subroutines | c %----------------------% c external dcopy, dsortc c c %----------------------% c | Intrinsics Functions | c %----------------------% c intrinsic abs c c %-----------------------% c | Executable Statements | c %-----------------------% c c %-------------------------------% c | Initialize timing statistics | c | & message level for debugging | c %-------------------------------% c dngetstrue = .true. c c c %----------------------------------------------------% c | LM, SM, LR, SR, LI, SI case. | c | Sort the eigenvalues of H into the desired order | c | and apply the resulting order to BOUNDS. | c | The eigenvalues are sorted so that the wanted part | c | are always in the last KEV locations. | c | We first do a pre-processing sort in order to keep | c | complex conjugate pairs together | c %----------------------------------------------------% c if (which .eq. 'LM') then call dsortc ('LR', dngetstrue, kev+np, ritzr, ritzi, bounds) else if (which .eq. 'SM') then call dsortc ('SR', dngetstrue, kev+np, ritzr, ritzi, bounds) else if (which .eq. 'LR') then call dsortc ('LM', dngetstrue, kev+np, ritzr, ritzi, bounds) else if (which .eq. 'SR') then call dsortc ('SM', dngetstrue, kev+np, ritzr, ritzi, bounds) else if (which .eq. 'LI') then call dsortc ('LM', dngetstrue, kev+np, ritzr, ritzi, bounds) else if (which .eq. 'SI') then call dsortc ('SM', dngetstrue, kev+np, ritzr, ritzi, bounds) end if c call dsortc (which, dngetstrue, kev+np, ritzr, ritzi, bounds) c c %-------------------------------------------------------% c | Increase KEV by one if the ( ritzr(np),ritzi(np) ) | c | = ( ritzr(np+1),-ritzi(np+1) ) and ritz(np) .ne. zero | c | Accordingly decrease NP by one. In other words keep | c | complex conjugate pairs together. | c %-------------------------------------------------------% c if ( ( abs(ritzr(np+1) - ritzr(np)) .le. zero) & .and. ( abs(ritzi(np+1) + ritzi(np)) .le. zero) ) then np = np - 1 kev = kev + 1 end if c if ( ishift .eq. 1 ) then c c %-------------------------------------------------------% c | Sort the unwanted Ritz values used as shifts so that | c | the ones with largest Ritz estimates are first | c | This will tend to minimize the effects of the | c | forward instability of the iteration when they shifts | c | are applied in subroutine dnapps. | c | Be careful and use 'SR' since we want to sort BOUNDS! | c %-------------------------------------------------------% c call dsortc ( 'SR', dngetstrue, np, bounds, ritzr, ritzi ) end if c return c c %---------------% c | End of dngets | c %---------------% c end c----------------------------------------------------------------------- c\BeginDoc c c\Name: dnaitr c c\Description: c Reverse communication interface for applying NP additional steps to c a K step nonsymmetric Arnoldi factorization. c c Input: OP*V_{k} - V_{k}*H = r_{k}*e_{k}^T c c with (V_{k}^T)*B*V_{k} = I, (V_{k}^T)*B*r_{k} = 0. c c Output: OP*V_{k+p} - V_{k+p}*H = r_{k+p}*e_{k+p}^T c c with (V_{k+p}^T)*B*V_{k+p} = I, (V_{k+p}^T)*B*r_{k+p} = 0. c c where OP and B are as in dnaupd. The B-norm of r_{k+p} is also c computed and returned. c c\Usage: c call dnaitr c ( IDO, BMAT, N, K, NP, NB, RESID, RNORM, V, LDV, H, LDH, c IPNTR, WORKD, INFO ) c c\Arguments c IDO Integer. (INPUT/OUTPUT) c Reverse communication flag. c ------------------------------------------------------------- c IDO = 0: first call to the reverse communication interface c IDO = -1: compute Y = OP * X where c IPNTR(1) is the pointer into WORK for X, c IPNTR(2) is the pointer into WORK for Y. c This is for the restart phase to force the new c starting vector into the range of OP. c IDO = 1: compute Y = OP * X where c IPNTR(1) is the pointer into WORK for X, c IPNTR(2) is the pointer into WORK for Y, c IPNTR(3) is the pointer into WORK for B * X. c IDO = 2: compute Y = B * X where c IPNTR(1) is the pointer into WORK for X, c IPNTR(2) is the pointer into WORK for Y. c IDO = 99: done c ------------------------------------------------------------- c When the routine is used in the "shift-and-invert" mode, the c vector B * Q is already available and do not need to be c recompute in forming OP * Q. c c BMAT Character*1. (INPUT) c BMAT specifies the type of the matrix B that defines the c semi-inner product for the operator OP. See dnaupd. c B = 'I' -> standard eigenvalue problem A*x = lambda*x c B = 'G' -> generalized eigenvalue problem A*x = lambda*M**x c c N Integer. (INPUT) c Dimension of the eigenproblem. c c K Integer. (INPUT) c Current size of V and H. c c NP Integer. (INPUT) c Number of additional Arnoldi steps to take. c c NB Integer. (INPUT) c Blocksize to be used in the recurrence. c Only work for NB = 1 right now. The goal is to have a c program that implement both the block and non-block method. c c RESID Double precision array of length N. (INPUT/OUTPUT) c On INPUT: RESID contains the residual vector r_{k}. c On OUTPUT: RESID contains the residual vector r_{k+p}. c c RNORM Double precision scalar. (INPUT/OUTPUT) c B-norm of the starting residual on input. c B-norm of the updated residual r_{k+p} on output. c c V Double precision N by K+NP array. (INPUT/OUTPUT) c On INPUT: V contains the Arnoldi vectors in the first K c columns. c On OUTPUT: V contains the new NP Arnoldi vectors in the next c NP columns. The first K columns are unchanged. c c LDV Integer. (INPUT) c Leading dimension of V exactly as declared in the calling c program. c c H Double precision (K+NP) by (K+NP) array. (INPUT/OUTPUT) c H is used to store the generated upper Hessenberg matrix. c c LDH Integer. (INPUT) c Leading dimension of H exactly as declared in the calling c program. c c IPNTR Integer array of length 3. (OUTPUT) c Pointer to mark the starting locations in the WORK for c vectors used by the Arnoldi iteration. c ------------------------------------------------------------- c IPNTR(1): pointer to the current operand vector X. c IPNTR(2): pointer to the current result vector Y. c IPNTR(3): pointer to the vector B * X when used in the c shift-and-invert mode. X is the current operand. c ------------------------------------------------------------- c c WORKD Double precision work array of length 3*N. (REVERSE COMMUNICATION) c Distributed array to be used in the basic Arnoldi iteration c for reverse communication. The calling program should not c use WORKD as temporary workspace during the iteration !!!!!! c On input, WORKD(1:N) = B*RESID and is used to save some c computation at the first step. c c INFO Integer. (OUTPUT) c = 0: Normal exit. c > 0: Size of the spanning invariant subspace of OP found. c c\EndDoc c c----------------------------------------------------------------------- c c\BeginLib c c\Local variables: c xxxxxx real c c\References: c 1. D.C. Sorensen, "Implicit Application of Polynomial Filters in c a k-Step Arnoldi Method", SIAM J. Matr. Anal. Apps., 13 (1992), c pp 357-385. c 2. R.B. Lehoucq, "Analysis and Implementation of an Implicitly c Restarted Arnoldi Iteration", Rice University Technical Report c TR95-13, Department of Computational and Applied Mathematics. c c\Routines called: c dgetv0 ARPACK routine to generate the initial vector. c ivout ARPACK utility routine that prints integers. c second ARPACK utility routine for timing. c dmout ARPACK utility routine that prints matrices c dvout ARPACK utility routine that prints vectors. c dlabad LAPACK routine that computes machine constants. c dlamch LAPACK routine that determines machine constants. c dlascl LAPACK routine for careful scaling of a matrix. c dlanhs LAPACK routine that computes various norms of a matrix. c dgemv Level 2 BLAS routine for matrix vector multiplication. c daxpy Level 1 BLAS that computes a vector triad. c dscal Level 1 BLAS that scales a vector. c dcopy Level 1 BLAS that copies one vector to another . c ddot Level 1 BLAS that computes the scalar product of two vectors. c dnrm2 Level 1 BLAS that computes the norm of a vector. c c\Author c Danny Sorensen Phuong Vu c Richard Lehoucq CRPC / Rice University c Dept. of Computational & Houston, Texas c Applied Mathematics c Rice University c Houston, Texas c c\Revision history: c xx/xx/92: Version ' 2.4' c c\SCCS Information: @(#) c FILE: naitr.F SID: 2.4 DATE OF SID: 8/27/96 RELEASE: 2 c c\Remarks c The algorithm implemented is: c c restart = .false. c Given V_{k} = [v_{1}, ..., v_{k}], r_{k}; c r_{k} contains the initial residual vector even for k = 0; c Also assume that rnorm = || B*r_{k} || and B*r_{k} are already c computed by the calling program. c c betaj = rnorm ; p_{k+1} = B*r_{k} ; c For j = k+1, ..., k+np Do c 1) if ( betaj < tol ) stop or restart depending on j. c ( At present tol is zero ) c if ( restart ) generate a new starting vector. c 2) v_{j} = r(j-1)/betaj; V_{j} = [V_{j-1}, v_{j}]; c p_{j} = p_{j}/betaj c 3) r_{j} = OP*v_{j} where OP is defined as in dnaupd c For shift-invert mode p_{j} = B*v_{j} is already available. c wnorm = || OP*v_{j} || c 4) Compute the j-th step residual vector. c w_{j} = V_{j}^T * B * OP * v_{j} c r_{j} = OP*v_{j} - V_{j} * w_{j} c H(:,j) = w_{j}; c H(j,j-1) = rnorm c rnorm = || r_(j) || c If (rnorm > 0.717*wnorm) accept step and go back to 1) c 5) Re-orthogonalization step: c s = V_{j}'*B*r_{j} c r_{j} = r_{j} - V_{j}*s; rnorm1 = || r_{j} || c alphaj = alphaj + s_{j}; c 6) Iterative refinement step: c If (rnorm1 > 0.717*rnorm) then c rnorm = rnorm1 c accept step and go back to 1) c Else c rnorm = rnorm1 c If this is the first time in step 6), go to 5) c Else r_{j} lies in the span of V_{j} numerically. c Set r_{j} = 0 and rnorm = 0; go to 1) c EndIf c End Do c c\EndLib c c----------------------------------------------------------------------- c subroutine dnaitr & (ido, bmat, n, k, np, nb, resid, rnorm, v, ldv, h, ldh, & ipntr, workd, info) implicit none c c %------------------% c | Scalar Arguments | c %------------------% c character bmat*1 integer ido, info, k, ldh, ldv, n, nb, np Double precision & rnorm c c %-----------------% c | Array Arguments | c %-----------------% c integer ipntr(3) Double precision & h(ldh,k+np), resid(n), v(ldv,k+np), workd(3*n) c c %------------% c | Parameters | c %------------% c Double precision & one, zero parameter (one = 1.0D+0, zero = 0.0D+0) logical fls parameter (fls = .false. ) c c %---------------% c | Local Scalars | c %---------------% c logical first, orth1, orth2, rstart, step3, step4 integer ierr, i, infol, ipj, irj, ivj, iter, itry, j, & jj integer dnaitrone parameter (dnaitrone = 1) c integer & ione parameter (ione = 1) c Double precision & betaj, ovfl, temp1, rnorm1, smlnum, tst1, ulp, unfl, & wnorm save first, orth1, orth2, rstart, step3, step4, & ierr, ipj, irj, ivj, iter, itry, j, ovfl, & betaj, rnorm1, smlnum, ulp, unfl, wnorm c c %----------------------% c | External Subroutines | c %----------------------% c external daxpy, dcopy, dscal, dgemv, dgetv0, dlabad c c %--------------------% c | External Functions | c %--------------------% c Double precision & ddot, dnrm2, dlanhs, dlamch external ddot, dnrm2, dlanhs, dlamch c c %---------------------% c | Intrinsic Functions | c %---------------------% c intrinsic abs, sqrt c c %-----------------% c | Data statements | c %-----------------% c data first / .true. / c c %-----------------------% c | Executable Statements | c %-----------------------% c if (nb .gt. 1000) then goto 9000 end if c if (first) then c c %-----------------------------------------% c | Set machine-dependent constants for the | c | the splitting and deflation criterion. | c | If norm(H) <= sqrt(OVFL), | c | overflow should not occur. | c | REFERENCE: LAPACK subroutine dlahqr | c %-----------------------------------------% c unfl = dlamch( 'safe minimum' ) ovfl = one / unfl call dlabad( unfl, ovfl ) ulp = dlamch( 'precision' ) smlnum = unfl*( n / ulp ) first = .false. end if c if (ido .eq. 0) then c c %-------------------------------% c | Initialize timing statistics | c | & message level for debugging | c %-------------------------------% c c call second (t0) cm msglvl = mnaitr c c %------------------------------% c | Initial call to this routine | c %------------------------------% c info = 0 step3 = .false. step4 = .false. rstart = .false. orth1 = .false. orth2 = .false. j = k + 1 ipj = 1 irj = ipj + n ivj = irj + n end if c c %-------------------------------------------------% c | When in reverse communication mode one of: | c | STEP3, STEP4, ORTH1, ORTH2, RSTART | c | will be .true. when .... | c | STEP3: return from computing OP*v_{j}. | c | STEP4: return from computing B-norm of OP*v_{j} | c | ORTH1: return from computing B-norm of r_{j+1} | c | ORTH2: return from computing B-norm of | c | correction to the residual vector. | c | RSTART: return from OP computations needed by | c | dgetv0. | c %-------------------------------------------------% c if (step3) go to 50 if (step4) go to 60 if (orth1) go to 70 if (orth2) go to 90 if (rstart) go to 30 c c %-----------------------------% c | Else this is the first step | c %-----------------------------% c c %--------------------------------------------------------------% c | | c | A R N O L D I I T E R A T I O N L O O P | c | | c | Note: B*r_{j-1} is already in WORKD(1:N)=WORKD(IPJ:IPJ+N-1) | c %--------------------------------------------------------------% 1000 continue c c %---------------------------------------------------% c | STEP 1: Check if the B norm of j-th residual | c | vector is zero. Equivalent to determing whether | c | an exact j-step Arnoldi factorization is present. | c %---------------------------------------------------% c betaj = rnorm if (rnorm .gt. zero) go to 40 c c %---------------------------------------------------% c | Invariant subspace found, generate a new starting | c | vector which is orthogonal to the current Arnoldi | c | basis and continue the iteration. | c %---------------------------------------------------% c %---------------------------------------------% c | ITRY is the loop variable that controls the | c | maximum amount of times that a restart is | c | attempted. NRSTRT is used by stat.h | c %---------------------------------------------% c betaj = zero cp nrstrt = nrstrt + 1 itry = 1 20 continue rstart = .true. ido = 0 30 continue c c %--------------------------------------% c | If in reverse communication mode and | c | RSTART = .true. flow returns here. | c %--------------------------------------% c call dgetv0 (ido, bmat, fls, n, j, v, ldv, & resid, rnorm, ipntr, workd, ierr) if (ido .ne. 99) go to 9000 if (ierr .lt. 0) then itry = itry + 1 if (itry .le. 3) go to 20 c c %------------------------------------------------% c | Give up after several restart attempts. | c | Set INFO to the size of the invariant subspace | c | which spans OP and exit. | c %------------------------------------------------% c info = j - 1 ido = 99 go to 9000 end if c 40 continue c c %---------------------------------------------------------% c | STEP 2: v_{j} = r_{j-1}/rnorm and p_{j} = p_{j}/rnorm | c | Note that p_{j} = B*r_{j-1}. In order to avoid overflow | c | when reciprocating a small RNORM, test against lower | c | machine bound. | c %---------------------------------------------------------% c call dcopy (n, resid, 1, v(1,j), 1) if (rnorm .ge. unfl) then temp1 = one / rnorm call dscal (n, temp1, v(1,j), int(ione, kind=4)) call dscal (n, temp1, workd(ipj), int(ione, kind=4)) else c c %-----------------------------------------% c | To scale both v_{j} and p_{j} carefully | c | use LAPACK routine SLASCL | c %-----------------------------------------% c call dlascl ('General', i, i, rnorm, one, n, 1, & v(1,j), n, infol) call dlascl ('General', i, i, rnorm, one, n, 1, & workd(ipj), n, infol) end if c c %------------------------------------------------------% c | STEP 3: r_{j} = OP*v_{j}; Note that p_{j} = B*v_{j} | c | Note that this is not quite yet r_{j}. See STEP 4 | c %------------------------------------------------------% c step3 = .true. call dcopy (n, v(1,j), 1, workd(ivj), 1) ipntr(1) = ivj ipntr(2) = irj ipntr(3) = ipj ido = 1 c c %-----------------------------------% c | Exit in order to compute OP*v_{j} | c %-----------------------------------% c go to 9000 50 continue c c %----------------------------------% c | Back from reverse communication; | c | WORKD(IRJ:IRJ+N-1) := OP*v_{j} | c | if step3 = .true. | c %----------------------------------% c step3 = .false. c c %------------------------------------------% c | Put another copy of OP*v_{j} into RESID. | c %------------------------------------------% c call dcopy (n, workd(irj), 1, resid(1), 1) c c %---------------------------------------% c | STEP 4: Finish extending the Arnoldi | c | factorization to length j. | c %---------------------------------------% c if (bmat .eq. 'G') then step4 = .true. ipntr(1) = irj ipntr(2) = ipj ido = 2 c c %-------------------------------------% c | Exit in order to compute B*OP*v_{j} | c %-------------------------------------% c go to 9000 else if (bmat .eq. 'I') then call dcopy (n, resid, 1, workd(ipj), 1) end if 60 continue c c %----------------------------------% c | Back from reverse communication; | c | WORKD(IPJ:IPJ+N-1) := B*OP*v_{j} | c | if step4 = .true. | c %----------------------------------% c step4 = .false. c c %-------------------------------------% c | The following is needed for STEP 5. | c | Compute the B-norm of OP*v_{j}. | c %-------------------------------------% c if (bmat .eq. 'G') then wnorm = ddot (n, resid, 1, workd(ipj), 1) wnorm = sqrt(abs(wnorm)) else if (bmat .eq. 'I') then wnorm = dnrm2(n, resid, 1) end if c c %-----------------------------------------% c | Compute the j-th residual corresponding | c | to the j step factorization. | c | Use Classical Gram Schmidt and compute: | c | w_{j} <- V_{j}^T * B * OP * v_{j} | c | r_{j} <- OP*v_{j} - V_{j} * w_{j} | c %-----------------------------------------% c c c %------------------------------------------% c | Compute the j Fourier coefficients w_{j} | c | WORKD(IPJ:IPJ+N-1) contains B*OP*v_{j}. | c %------------------------------------------% c call dgemv ('T', n, j, one, v, ldv, workd(ipj), 1, & zero, h(1,j), 1) c c %--------------------------------------% c | Orthogonalize r_{j} against V_{j}. | c | RESID contains OP*v_{j}. See STEP 3. | c %--------------------------------------% c call dgemv ('N', n, j, -one, v, ldv, h(1,j), 1, & one, resid(1), 1) c if (j .gt. 1) h(j,j-1) = betaj c orth1 = .true. c if (bmat .eq. 'G') then call dcopy (n, resid, 1, workd(irj), 1) ipntr(1) = irj ipntr(2) = ipj ido = 2 c c %----------------------------------% c | Exit in order to compute B*r_{j} | c %----------------------------------% c go to 9000 else if (bmat .eq. 'I') then call dcopy (n, resid, 1, workd(ipj), 1) end if 70 continue c c %---------------------------------------------------% c | Back from reverse communication if ORTH1 = .true. | c | WORKD(IPJ:IPJ+N-1) := B*r_{j}. | c %---------------------------------------------------% c orth1 = .false. c c %------------------------------% c | Compute the B-norm of r_{j}. | c %------------------------------% c if (bmat .eq. 'G') then rnorm = ddot (n, resid, 1, workd(ipj), 1) rnorm = sqrt(abs(rnorm)) else if (bmat .eq. 'I') then rnorm = dnrm2(n, resid, 1) end if c c %-----------------------------------------------------------% c | STEP 5: Re-orthogonalization / Iterative refinement phase | c | Maximum NITER_ITREF tries. | c | | c | s = V_{j}^T * B * r_{j} | c | r_{j} = r_{j} - V_{j}*s | c | alphaj = alphaj + s_{j} | c | | c | The stopping criteria used for iterative refinement is | c | discussed in Parlett's book SEP, page 107 and in Gragg & | c | Reichel ACM TOMS paper; Algorithm 686, Dec. 1990. | c | Determine if we need to correct the residual. The goal is | c | to enforce ||v(:,1:j)^T * r_{j}|| .le. eps * || r_{j} || | c | The following test determines whether the sine of the | c | angle between OP*x and the computed residual is less | c | than or equal to 0.717. | c %-----------------------------------------------------------% c if (rnorm .gt. 0.717*wnorm) go to 100 iter = 0 c c %---------------------------------------------------% c | Enter the Iterative refinement phase. If further | c | refinement is necessary, loop back here. The loop | c | variable is ITER. Perform a step of Classical | c | Gram-Schmidt using all the Arnoldi vectors V_{j} | c %---------------------------------------------------% c 80 continue c c %----------------------------------------------------% c | Compute V_{j}^T * B * r_{j}. | c | WORKD(IRJ:IRJ+J-1) = v(:,1:J)'*WORKD(IPJ:IPJ+N-1). | c %----------------------------------------------------% c call dgemv ('T', n, j, one, v, ldv, workd(ipj), 1, & zero, workd(irj), 1) c c %---------------------------------------------% c | Compute the correction to the residual: | c | r_{j} = r_{j} - V_{j} * WORKD(IRJ:IRJ+J-1). | c | The correction to H is v(:,1:J)*H(1:J,1:J) | c | + v(:,1:J)*WORKD(IRJ:IRJ+J-1)*e'_j. | c %---------------------------------------------% c call dgemv ('N', n, j, -one, v, ldv, workd(irj), 1, & one, resid(1), 1) call daxpy (j, one, workd(irj), 1, h(1,j), 1) c orth2 = .true. if (bmat .eq. 'G') then call dcopy (n, resid, 1, workd(irj), 1) ipntr(1) = irj ipntr(2) = ipj ido = 2 c c %-----------------------------------% c | Exit in order to compute B*r_{j}. | c | r_{j} is the corrected residual. | c %-----------------------------------% c go to 9000 else if (bmat .eq. 'I') then call dcopy (n, resid, 1, workd(ipj), 1) end if 90 continue c c %---------------------------------------------------% c | Back from reverse communication if ORTH2 = .true. | c %---------------------------------------------------% c c %-----------------------------------------------------% c | Compute the B-norm of the corrected residual r_{j}. | c %-----------------------------------------------------% c if (bmat .eq. 'G') then rnorm1 = ddot (n, resid, 1, workd(ipj), 1) rnorm1 = sqrt(abs(rnorm1)) else if (bmat .eq. 'I') then rnorm1 = dnrm2(n, resid, 1) end if c c %-----------------------------------------% c | Determine if we need to perform another | c | step of re-orthogonalization. | c %-----------------------------------------% c if (rnorm1 .gt. 0.717*rnorm) then c c %---------------------------------------% c | No need for further refinement. | c | The cosine of the angle between the | c | corrected residual vector and the old | c | residual vector is greater than 0.717 | c | In other words the corrected residual | c | and the old residual vector share an | c | angle of less than arcCOS(0.717) | c %---------------------------------------% c rnorm = rnorm1 c else c c %-------------------------------------------% c | Another step of iterative refinement step | c | is required. NITREF is used by stat.h | c %-------------------------------------------% c rnorm = rnorm1 iter = iter + 1 if (iter .le. 1) go to 80 c c %-------------------------------------------------% c | Otherwise RESID is numerically in the span of V | c %-------------------------------------------------% c do 95 jj = 1, n resid(jj) = zero 95 continue rnorm = zero end if c c %----------------------------------------------% c | Branch here directly if iterative refinement | c | wasn't necessary or after at most NITER_REF | c | steps of iterative refinement. | c %----------------------------------------------% c 100 continue c rstart = .false. orth2 = .false. c c %------------------------------------% c | STEP 6: Update j = j+1; Continue | c %------------------------------------% c j = j + 1 if (j .gt. k+np) then ido = 99 do 110 i = max(dnaitrone,k), k+np-1 c c %--------------------------------------------% c | Check for splitting and deflation. | c | Use a standard test as in the QR algorithm | c | REFERENCE: LAPACK subroutine dlahqr | c %--------------------------------------------% c tst1 = abs( h( i, i ) ) + abs( h( i+1, i+1 ) ) if( abs(tst1) .le. zero ) & tst1 = dlanhs( '1', k+np, h, ldh, workd(n+1) ) if( abs( h( i+1,i ) ).le.max( ulp*tst1, smlnum ) ) & h(i+1,i) = zero 110 continue c go to 9000 end if c c %--------------------------------------------------------% c | Loop back to extend the factorization by another step. | c %--------------------------------------------------------% c go to 1000 c c %---------------------------------------------------------------% c | | c | E N D O F M A I N I T E R A T I O N L O O P | c | | c %---------------------------------------------------------------% c 9000 continue return c c %---------------% c | End of dnaitr | c %---------------% c end c spam/src/spamown2.f0000644000176200001440000002312213574431374013731 0ustar liggesusers subroutine triplet3csr(nrow,ncol,nnz,a,ir,jc,ao,jao,iao,eps) implicit none double precision a(*),ao(*),eps integer nrow,ncol,nnz,ir(*),jc(*),jao(*),iao(*) integer kk,k,i,j,tmpi, cr(nrow), ig(nrow+1), g(nnz) integer st(nrow+1) double precision tmpa(ncol) C We assume that we have the correct dimensions. c in case we need to determine the max and min c also clean up the vectors containing the elements c provide empty arrays: do kk = 1,nnz g(kk) = 0 enddo do kk = 1,nrow cr(kk) = 0 enddo c row need to be determined k=0 do kk=1, nnz if ((jc(kk).le.ncol).and.(ir(kk).le.nrow)) then k=k+1 if (k.lt.kk) then jc(k)=jc(kk) ir(k)=ir(kk) a(k)=a(kk) endif endif enddo nnz=k do kk = 1,nnz cr(ir(kk)) = cr(ir(kk)) + 1 c jao(ir(kk)) = cr(ir(kk)) enddo c return st(1) = 1 do kk = 1, nrow st(kk+1) = st(kk) + cr(kk) enddo do kk = 1, nrow ig(kk) = st(kk) enddo do k=1,nnz kk = ir(k) g(ig(kk)) = k ig(kk) = ig(kk) +1 enddo c return kk = 0 iao(1)=1 do i = 1,nrow do j=1,ncol tmpa(j)=0.0 enddo do j=1,cr(i) tmpi = g(st(i) + j - 1) tmpa(jc(tmpi)) = tmpa(jc(tmpi)) + a(tmpi) enddo do j=1,ncol if( abs(tmpa(j)).gt.eps) then kk = kk + 1 ao(kk) = tmpa(j) jao(kk) = j endif enddo iao(i+1)= kk+1 enddo nnz = kk return end c----------------------------------------------------------------------- subroutine triplet2csr(nrow,ncol,nnz,a,ir,jc,ao,jao,iao,eps) implicit none double precision a(*),ao(*),eps integer nrow,ncol,nnz,ir(*),jc(*),jao(*),iao(*) integer newnnz, ipos, k, i, j, tmp1, tmp2 double precision tmp c----------------------------------------------------------------------- c Triplet representation to Compressed Sparse Row c Similar to coocsr from sparsekit c----------------------------------------------------------------------- c converts a matrix that is stored in coordinate format c a, ir, jc into a row general sparse ao, jao, iao format. c c on entry: c--------- c nrow = row dimension of matrix c nrow = col dimension of matrix c nnz = number of nonzero elements in matrix c a, c ir, c jc = matrix in coordinate format. a(k), ir(k), jc(k) store the nnz c nonzero elements of the matrix with a(k) = actual real value of c the elements, ir(k) = its row number and jc(k) = its column c number. The order of the elements is arbitrary. c c on return: c----------- c nnz = number of nonzero elements in matrix c ao, jao, iao = matrix in general sparse matrix format with ao c continung the real values, jao containing the column indices, c and iao being the pointer to the beginning of the row, c in arrays ao, jao. c c------------------------------------------------------------------------ c cycle over all entries and count the number of elements in each row c skip if larger than nrow and ncol. newnnz is actual number within c matrix(nrow,ncol). newnnz = 0 do k=1, nnz tmp1 = ir(k) if (tmp1 .le. nrow) then tmp2 = jc(k) if (tmp2 .le. ncol) then if (abs(a(k)) .gt. eps) then iao(tmp1) = iao(tmp1)+1 newnnz = newnnz + 1 if (newnnz.lt.k) then jc(newnnz) = tmp2 ir(newnnz) = tmp1 a(newnnz) = a(k) endif endif endif endif enddo c Starting position of each row, essentially a cumsum of iao k = 1 do j=1,nrow+1 tmp1 = iao(j) iao(j) = k k = k + tmp1 enddo c Go through the structure once more. Fill in output matrix. c iao is miss used. do k=1, newnnz i = ir(k) tmp1 = iao(i) ao(tmp1) = a(k) jao(tmp1) = jc(k) iao(i) = tmp1+1 enddo c Shift back iao do j=nrow,1,-1 iao(j+1) = iao(j) enddo iao(1) = 1 c Sort the individual rows do i = 1, nrow do ipos = iao(i), iao(i+1)-1 do j = iao(i+1)-1, ipos+1, -1 k = j - 1 if (jao(k).eq.jao(j)) then ao(k) = ao(k)+ao(j) ao(j) = 0.0 else if (jao(k).gt.jao(j)) then tmp1 = jao(k) jao(k) = jao(j) jao(j) = tmp1 tmp = ao(k) ao(k) = ao(j) ao(j) = tmp endif endif enddo enddo enddo call cleanspam(nrow,ao,jao,iao,eps) nnz = iao(nrow+1)-1 return c----------------------------------------------------------------------- end subroutine cleanspam(nrow,a,ja,ia,eps) implicit none integer nrow, ia(nrow+1), ja(*) double precision a(*), eps c c this routine removes zero entries. for more complicated cleaning c use the sparsekit2 subroutine clncsr. c c On entry: c---------- c nrow -- row dimension of the matrix c a,ja,ia -- input matrix in CSR format c c On return: c----------- c a,ja,ia -- cleaned matrix c c Notes: c------- c Reinhard Furrer 2006-09-13 c----------------------------------------------------------------------- c c Local integer i,j,k, oldia(nrow+1) do i = 1, nrow+1 oldia(i) = ia(i) enddo k = 1 do i = 1, nrow ia(i) = k do j=oldia(i),oldia(i+1)-1 if (.not.(dabs(a(j)) .le. eps)) then ja(k) = ja(j) a(k) = a(j) k = k + 1 endif enddo enddo ia(nrow+1) = k return c---- end of cleanspam ------------------------------------------------- c----------------------------------------------------------------------- end subroutine circulant(nrow,len, x,j, a,ja,ia) implicit none integer nrow, len, ia(nrow+1), ja(*), j(len) double precision a(*), x(len) c c c c On entry: c---------- c nrow -- row dimension of the matrix c len -- #nnz per line c x,j -- input values and indicies c c On return: c----------- c a,ja,ia -- cleaned circulant matrix c c Notes: c------- c Reinhard Furrer 2011-08-03 c----------------------------------------------------------------------- c c Local integer i,k, kk kk = 1 ia(1) = 1 do i = 1, nrow ia(i+1) = ia(i)+len do k = 1, len ja(kk) = mod( j(k) +i-2, nrow)+1 a(kk) = x(k) kk = kk+1 enddo enddo call sortrows(nrow,a, ja, ia) return c---- end of circulant ------------------------------------------------- c----------------------------------------------------------------------- end subroutine toeplitz(nrow,len, x,j, a,ja,ia,kk) implicit none integer nrow, len, ia(nrow+1), ja(*), j(len), kk double precision a(*), x(len) c c c c On entry: c---------- c nrow -- row dimension of the matrix c len -- total #nnz per line and column c x,j -- input values and indicies (indices are shifted!) c c On return: c----------- c a,ja,ia -- toeplitz matrix c kk -- nonzero elements c c Notes: c------- c Reinhard Furrer 2011-08-03 c----------------------------------------------------------------------- c c Local integer i,k, newj kk = 1 ia(1) = 1 do i = 1, nrow do k = 1, len newj = j(k) + i - nrow if ((newj.ge.1).and.(newj.le.nrow)) then ja(kk) = newj a(kk) = x(k) kk = kk+1 endif enddo ia(i+1) = kk enddo kk = kk - 1 return c---- end of toeplitz ------------------------------------------------- c----------------------------------------------------------------------- end c----------------------------------------------------------------------- subroutine sortrows(nrow,a,ja,ia) implicit none integer nrow integer ia(nrow+1),ja(*) double precision a(*) c c sorts the rows according to column entries c c On entry: c---------- c nrow -- row dimension of the matrix c a,ja,ia -- input matrix in sparse format c c On return: c----------- c a,ja,ia -- cleaned matrix c c Notes: c------- c Reinhard Furrer 2006-09-13 c----------------------------------------------------------------------- c Local variables integer i,j,k,ko,ipos double precision tmp c c c .. order the entries according to column indices c burble-sort is used c do 190 i = 1, nrow do 160 ipos = ia(i), ia(i+1)-1 do 150 j = ia(i+1)-1, ipos+1, -1 k = j - 1 if (ja(k).gt.ja(j)) then ko = ja(k) ja(k) = ja(j) ja(j) = ko tmp = a(k) a(k) = a(j) a(j) = tmp endif 150 continue 160 continue 190 continue return c---- end of sortrows -------------------------------------------------- c----------------------------------------------------------------------- end spam/src/spamown.f0000644000176200001440000015405113574431374013655 0ustar liggesusers subroutine amuxmat (n,m,p, x, y, a,ja,ia) implicit none integer n, m, p, ja(*), ia(*) double precision x(m,p), y(n,p), a(*) c----------------------------------------------------------------------- c Multiplies a sparse matrix by a full matrix using consecutive dot c products, cf. subroutine amux from sparse kit. c Matrix A is stored in compressed sparse row storage. c c on entry: c---------- c n = row dimension of A c p = column dimension of x c x = array of dimension mxp, m column dimension of A. c a, ja, c ia = input matrix in compressed sparse row format. c c on return: c----------- c y = array of dimension nxp, containing the product y=Ax c c Reinhard Furrer c----------------------------------------------------------------------- c local variables c double precision t integer j, i, k c----------------------------------------------------------------------- do j = 1,p do i = 1,n c c compute the inner product of row i with vector x c t = 0.0d0 do k=ia(i), ia(i+1)-1 t = t + a(k)*x(ja(k),j) enddo c y(i,j) = t enddo enddo c return c---------end-of-amuxmat------------------------------------------------ c----------------------------------------------------------------------- end c subroutine notzero (ja,ia,nrow,ncol,nnz,nz,jao,iao) c Return the structure of the zero entries in ra,ja,ia, in c compressed sparse row format via rao, jao, iao. c INPUT: c ja, ia -- sparse structure of the matrix A c nrow -- number of rows in `a' c ncol -- number of columns in `a' c nnz -- number of non-zero elements c nz -- number of zero elements c OUTPUT: c jao, iao -- sparse structure of the zero entries c WORK ARRAY: c colmn -- logical vector of length ncol implicit none integer nrow,ncol,nnz,nz,inz, & ja(nnz),ia(nrow+1),jao(nz),iao(nrow+1) logical colmn(ncol) integer i,j,k inz = 0 iao(1) = 1 do i = 1,nrow iao(i+1) = iao(i) do k = 1,ncol colmn(k) = .true. enddo do j = ia(i),ia(i+1)-1 colmn(ja(j)) = .false. enddo do k = 1,ncol if(colmn(k)) then inz = inz + 1 jao(inz) = k iao(i+1) = iao(i+1) + 1 endif enddo enddo return end subroutine setdiagmat (nrow, n, a, ja, ia, diag, iw) implicit none integer nrow, n double precision a(*), diag(n) integer ja(*), ia(nrow+1), iw(nrow) c----------------------------------------------------------------------- c Sets the diagonal entries of a sparse matrix c----------------------------------------------------------------------- c on entry: c --------- c nrow = integer. The row dimension of A c n = integer. Smallest dimension of A c c a, ja, ia = Matrix A in compressed sparse row format. Sorted. c diag = diagonal matrix stored as a vector diag(1:n) c iw = n vector of zeros. c c on return: c---------- c updated matrix A c iw = iw contains the positions of the diagonal entries in the c output matrix. (i.e., a(iw(k)), ja(iw(k)), k=1,...n, c are the values/column indices of the diagonal elements c of the output matrix. ). c c Reinhard Furrer c----------------------------------------------------------------- logical insert integer i,j, k, k1, k2, icount c c get positions of diagonal elements in data structure. c do 11 i=1,n do 21 j= ia(i),ia(i+1)-1 if (ja(j) .ge. i) then if (ja(j) .eq. i) then iw(i) = j endif goto 11 endif 21 continue 11 continue c c count number of holes in diagonal and add diag(*) elements to c valid diagonal entries. c icount = 0 do 31 i=1, n if (iw(i) .eq. 0) then icount = icount+1 else a(iw(i)) = diag(i) endif 31 continue c c if no diagonal elements to insert return c if (icount .eq. 0) return c c shift the nonzero elements if needed, to allow for created c diagonal elements. c c c copy rows backward c do 5 i=nrow, 1, -1 c c go through row ii c k1 = ia(i) k2 = ia(i+1)-1 ia(i+1) = ia(i+1)+icount if ((i .gt. n) .or. (iw(i) .gt. 0)) then c iw(ii) equal to 0, means no diagonal element in a, we need to insert it c test is thus true. c no fill-in, only copying do 4 k = k2,k1,-1 ja(k+icount)=ja(k) a(k+icount)=a(k) 4 continue iw(i)=-i else insert=.TRUE. if (k2.lt.k1) then ja(k2+icount)=i a(k2+icount)=diag(i) iw(i)=k2+icount icount=icount-1 insert = .FALSE. if (icount .eq. 0) return else do 6 k = k2,k1,-1 if (ja(k).gt. i) then ja(k+icount)=ja(k) a(k+icount)=a(k) else if (insert) then ja(k+icount)=i a(k+icount)=diag(i) iw(i)=k+icount icount=icount-1 insert = .FALSE. if (icount .eq. 0) return endif if (ja(k).lt. i) then ja(k+icount)=ja(k) a(k+icount)=a(k) endif 6 continue c in case there is only one element, larger than i, we still need to c add the diagonal element if (insert) then ja(k+icount)=i a(k+icount)=diag(i) iw(i)=k+icount icount=icount-1 insert = .FALSE. if (icount .eq. 0) return endif endif endif 5 continue return c----------------------------------------------------------------------- c------------end-of-diagaddmat------------------------------------------ end subroutine diagaddmat (nrow, n, a, ja, ia, diag, iw) implicit none integer nrow, n double precision a(*), diag(n) integer ja(*), ia(nrow+1), iw(nrow) c----------------------------------------------------------------------- c Adds a diagonal matrix to a sparse matrix: A = Diag + A c----------------------------------------------------------------------- c on entry: c --------- c nrow = integer. The row dimension of A c n = integer. Smallest dimension of A c c a, ja, ia = Matrix A in compressed sparse row format. Sorted. c diag = diagonal matrix stored as a vector diag(1:n) c iw = n vector of zeros. c c on return: c---------- c updated matrix A c iw = iw contains the positions of the diagonal entries in the c output matrix. (i.e., a(iw(k)), ja(iw(k)), k=1,...n, c are the values/column indices of the diagonal elements c of the output matrix. ). c c Reinhard Furrer c----------------------------------------------------------------- logical insert integer i,j, k, k1, k2, icount c c get positions of diagonal elements in data structure. c do 11 i=1,n do 21 j= ia(i),ia(i+1)-1 if (ja(j) .ge. i) then if (ja(j) .eq. i) then iw(i) = j endif goto 11 endif 21 continue 11 continue c c count number of holes in diagonal and add diag(*) elements to c valid diagonal entries. c icount = 0 do 31 i=1, n if (iw(i) .eq. 0) then icount = icount+1 else a(iw(i)) = a(iw(i)) + diag(i) endif 31 continue c c if no diagonal elements to insert return c if (icount .eq. 0) return c c shift the nonzero elements if needed, to allow for created c diagonal elements. c c c copy rows backward c do 5 i=nrow, 1, -1 c c go through row ii c k1 = ia(i) k2 = ia(i+1)-1 ia(i+1) = ia(i+1)+icount if ((i .gt. n) .or. (iw(i) .gt. 0)) then c iw(ii) equal to 0, means no diagonal element in a, we need to insert it c test is thus true. c no fill-in, only copying do 4 k = k2,k1,-1 ja(k+icount)=ja(k) a(k+icount)=a(k) 4 continue iw(i)=-i else insert=.TRUE. if (k2.lt.k1) then ja(k2+icount)=i a(k2+icount)=diag(i) iw(i)=k2+icount icount=icount-1 insert = .FALSE. if (icount .eq. 0) return else do 6 k = k2,k1,-1 if (ja(k).gt. i) then ja(k+icount)=ja(k) a(k+icount)=a(k) else if (insert) then ja(k+icount)=i a(k+icount)=diag(i) iw(i)=k+icount icount=icount-1 insert = .FALSE. if (icount .eq. 0) return endif if (ja(k).lt. i) then ja(k+icount)=ja(k) a(k+icount)=a(k) endif 6 continue c in case there is only one element, larger than i, we still need to c add the diagonal element if (insert) then ja(k+icount)=i a(k+icount)=diag(i) iw(i)=k+icount icount=icount-1 insert = .FALSE. if (icount .eq. 0) return endif endif endif 5 continue return c----------------------------------------------------------------------- c------------end-of-setdiagmat------------------------------------------ end c----------------------------------------------------------------------- subroutine diagmua (nrow, a, ia, diag) implicit none integer nrow, ia(nrow+1) double precision a(*), diag(nrow), scal c----------------------------------------------------------------------- c performs the matrix by matrix product A = Diag * A (in place) c (diamua from sparsekit provides more functionality) c----------------------------------------------------------------------- c on entry: c --------- c nrow = integer. The row dimension of A c a, ia = Matrix A in compressed sparse row format. c (ja is not needed) c c diag = diagonal matrix stored as a vector diag(1:n) c c on return: c---------- c a, = resulting matrix A in compressed sparse row sparse format. c c Notes: c------- c Reinhard Furrer 2007-06-21 c c----------------------------------------------------------------- c local variables integer ii, k, k1, k2 do 1 ii=1,nrow c c normalize each row c k1 = ia(ii) k2 = ia(ii+1)-1 scal = diag(ii) do 2 k=k1, k2 a(k) = a(k)*scal 2 continue 1 continue c return c----------end-of-diagmua------------------------------------------------ c----------------------------------------------------------------------- end c----------------------------------------------------------------------- c----------------------------------------------------------------------- subroutine getdiag (a,ja,ia,len,diag) implicit none double precision diag(*),a(*) integer len, ia(*), ja(*) c----------------------------------------------------------------------- c This subroutine extracts the main diagonal. c (getdia from sparsekit provides more functionality) c----------------------------------------------------------------------- c c on entry: c---------- c c len= min(nrow, ncol) = min dimension of the matrix a. c a,ja,ia = matrix stored in sorted compressed sparse row a,ja,ia,format c diag = array of zeros. c c on return: c----------- c diag = array of length containing the wanted diagonal. c c Notes: c------- c Reinhard Furrer 2006-11-02 c----------------------------------------------------------------------c c local variables integer i, k c c extract diagonal elements c do 1 i=1, len do k= ia(i),ia(i+1) -1 if (ja(k) .ge. i) then c we are at or beyond the diagonal. if (ja(k) .eq. i) then diag(i)= a(k) endif goto 1 endif enddo 1 continue return c------------end-of-getdiag---------------------------------------------- c----------------------------------------------------------------------- end c Functions that are new or modified. subroutine subsparsefull(nrow,a,ja,ia,b) c c subtracts a sparse matrix from a full one c algorithm is in-place, i.e. b is changed c c c Notes: c------- c Reinhard Furrer 2006-09-21 c----------------------------------------------------------------------- implicit none integer nrow,ja(*),ia(nrow+1) double precision a(*), b(nrow,*) integer i,k do i=1,nrow do k=ia(i),ia(i+1)-1 b(i,ja(k)) = b(i,ja(k))-a(k) enddo enddo return end subroutine subfullsparse(nrow,ncol,a,ja,ia,b) c c subtracts a full matrix from a sparse one c algorithm is in-place, i.e. b is changed c c c Notes: c------- c Reinhard Furrer 2006-09-21 c----------------------------------------------------------------------- implicit none integer nrow,ncol,ja(*),ia(nrow+1) double precision a(*), b(nrow,*) integer i,j,k do i=1,nrow do j=1,ncol b(i,j) = -b(i,j) enddo do k=ia(i),ia(i+1)-1 b(i,ja(k)) = b(i,ja(k))+a(k) enddo enddo return end subroutine addsparsefull(nrow,a,ja,ia,b) c c adds a sparse matrix to a full one c algorithm is in-place, i.e. b is changed c c c Notes: c------- c Reinhard Furrer 2006-09-21 c----------------------------------------------------------------------- implicit none integer nrow,ja(*),ia(nrow+1) double precision a(*), b(nrow,*) integer i,k do i=1,nrow do k=ia(i),ia(i+1)-1 b(i,ja(k)) = b(i,ja(k))+a(k) enddo enddo return end subroutine constructia(nrow,nir,ia,ir) c c constructs from a regular row index vector a sparse ia vector. c note that a regular column index vector corresponds to the c sparse ja vector. for example: c A[ir,jc] => A@ja = jc, A@ia = constructia(nrow,nir,ia,ir)$ia c c nrow: row dimension of A c nir: length of ir c ir: array of length nir+1!!! c c Notes: c------- c _*Row indices have to be ordered!*_ c c Reinhard Furrer 2006-09-13 c----------------------------------------------------------------------- implicit none integer nrow,nir integer ia(nrow+1),ir(*) integer i,k k=1 ia(1)=1 do i=1,nrow 5 continue if (ir(k) .eq. i) then k=k+1 if (k .le. nir) goto 5 endif ia(i+1)=k enddo ia(nrow+1)=nir+1 return end subroutine disttospam(nrow,x,a,ja,ia,eps) implicit none integer nrow, ia(nrow+1), ja(*) double precision x(*), a(*), eps c c Convertion of an R dist object (removes zero entries as well). c c On entry: c---------- c nrow -- row dimension of the matrix c x -- elements of the dist object (is lower diagonal) c n*(i-1) - i*(i-1)/2 + j-i for i < j c c a,ja,ia -- input matrix in CSR format c c On return: c----------- c a,ja,ia -- cleaned matrix c c Notes: c------- c Reinhard Furrer 2008-08-13 c----------------------------------------------------------------------- c c Local integer i,j,k, tmp ia(1) = 1 k = 1 do i = 2, nrow ia(i) = k do j=1 , i-1 tmp = nrow*(j-1)-j*(j-1)/2+i-j if (.not.(dabs(x(tmp)) .le. eps)) then ja(k) = j a(k) = x(tmp) k = k + 1 endif enddo enddo ia(nrow+1) = k return c---- end of disttospam ------------------------------------------------- c----------------------------------------------------------------------- end subroutine setdiaold (nrow,ncol,a,ja,ia,c,jc,ic,cmax,diag,eps) implicit none double precision a(*),c(*),diag(*),eps integer nrow, ncol, ia(*), ja(*), ic(*), jc(*), cmax c c this routine sets the diagonal entries of a matix, provided they c are non-zero. c c On entry: c---------- c nrow,ncol -- dimensions of the matrix c a,ja,ia -- input matrix in CSR format c c,jc,ic -- input matrix in CSR format with enough space, see below c diag -- diagonal values to set c eps -- what is smaller than zero? c c On return: c----------- c c,jc,ic -- matrix with modified diag in CSR format c c Notes: c------- c Reinhard Furrer 2006-10-30 c----------------------------------------------------------------------- c c Local double precision b(nrow) integer i,k, len, ib(nrow+1), jb(nrow) c len=0 ib(1)=1 do i=1,nrow jb(i)=0 enddo do 10 i=1,nrow do 15 k= ia(i),ia(i+1) -1 if (ja(k) .eq. i) then a(k)=diag(i) c(k)=diag(i) ib(i+1)=ib(i) goto 10 endif if (ja(k) .gt. i) then if (diag(i).gt.eps) then len=len+1 jb(len)=i ib(i+1)=ib(i)+1 b(len)=diag(i) else ib(i+1)=ib(i) endif goto 10 endif 15 continue 10 continue if (len .eq. 0) return c c set nonexisiting elements. c call subass(nrow,ncol,a,ja,ia,b,jb,ib,c,jc,ic,cmax) return c------------end of setdia---------------------------------------------- c----------------------------------------------------------------------- end c----------------------------------------------------------------------- c c----------------------------------------------------------------------- subroutine subass(nrow,ncol,a,ja,ia,b,jb,ib,c,jc,ic,nzmax) implicit none integer nrow,ncol,nzmax integer ja(*),jb(*),jc(*),ia(*),ib(*),ic(*) double precision a(*), b(*), c(*) c----------------------------------------------------------------------- c replaces the elements of A with those of B for matrices in sorted CSR c format. we assume that each row is sorted with increasing column c indices. c----------------------------------------------------------------------- c on entry: c --------- c nrow = integer. The row dimension of A and B c ncol = integer. The column dimension of A and B. c c a,ja,ia, c b,jb,ib = Matrices A and B in compressed sparse row format with column c entries sorted ascendly in each row c c nzmax = integer. The max length of the arrays c and jc. c c on return: c---------- c c,jc,ic = resulting matrix C in compressed sparse row sparse format c with entries sorted ascendly in each row. c c Notes: c------- c Reinhard Furrer 2006-09-13, based on sparsekit2 subroutine aplb1 c----------------------------------------------------------------------- c local variables integer i,j1,j2,ka,kb,kc,kamax,kbmax kc = 1 ic(1) = kc c c looping over the rows: do 6 i=1, nrow ka = ia(i) kb = ib(i) kamax = ia(i+1)-1 kbmax = ib(i+1)-1 5 continue c If we have one or more entries then ka <= kamax c If we do not have any entries in both A and B c we will not enter the if clause. In which case c we repeatedly copy ic(i+1) <- ic(i). if (ka .le. kamax .or. kb .le. kbmax) then c j1 and j2 are left hand pointers of the first entry c of A and B. If no entry, they are set to ncol+1 if (ka .le. kamax) then j1 = ja(ka) else j1 = ncol+1 endif if (kb .le. kbmax) then j2 = jb(kb) else j2 = ncol+1 endif c c Three cases: c j1=j2: copy element of b in c, incr. all three pointers c j1j2: copy element of b in c, incr. b and c pointers if (j1 .eq. j2) then c(kc) = b(kb) jc(kc) = j1 ka = ka+1 kb = kb+1 kc = kc+1 else if (j1 .lt. j2) then jc(kc) = j1 c(kc) = a(ka) ka = ka+1 kc = kc+1 else if (j1 .gt. j2) then jc(kc) = j2 c(kc) = b(kb) kb = kb+1 kc = kc+1 endif C the next four lines should not be required... if (kc .gt. nzmax+1) then c write (*,*) "exceeding array capacities...",i,nzmax, c & ka,kb,kc,j1,j2,kamax,kbmax,ncol,jb(kb) return endif goto 5 endif ic(i+1) = kc 6 continue return c------------end-of-subass---------------------------------------------- c----------------------------------------------------------------------- end subroutine spamcsrdns(nrow,a,ja,ia,dns) implicit none integer i,k integer nrow,ja(*),ia(*) double precision dns(nrow,*),a(*) c----------------------------------------------------------------------- c Compressed Sparse Row to Dense c----------------------------------------------------------------------- c c converts a row-stored sparse matrix into a densely stored one c c On entry: c---------- c c nrow = row-dimension of a c a, c ja, c ia = input matrix in compressed sparse row format. c (a=value array, ja=column array, ia=pointer array) c dns = array where to store dense matrix c c on return: c----------- c dns = the sparse matrix a, ja, ia has been stored in dns(nrow,*) c c changes: c--------- c eliminated the ierr c eliminated the filling of zeros: all done with c----------------------------------------------------------------------- do i=1,nrow do k=ia(i),ia(i+1)-1 dns(i,ja(k)) = a(k) enddo enddo return c---- end of csrdns ---------------------------------------------------- c----------------------------------------------------------------------- end c----------------------------------------------------------------------- subroutine spamdnscsr(nrow,ncol,dns,ndns,a,ja,ia,eps) implicit none integer i,j,next integer nrow,ncol,ndns,ia(*),ja(*) double precision dns(ndns,*),a(*),eps c----------------------------------------------------------------------- c Converts a densely stored matrix into a CSR sparse matrix. c----------------------------------------------------------------------- c on entry: c--------- c c nrow = row-dimension of a c ncol = column dimension of a c nzmax = maximum number of nonzero elements allowed. This c should be set to be the lengths of the arrays a and ja. c dns = input nrow x ncol (dense) matrix. c ndns = first dimension of dns. c c on return: c---------- c c a, ja, ia = value, column, pointer arrays for output matrix c c changes: c--------- c eliminated the ierr c introduced epsilon c----------------------------------------------------------------------- next = 1 ia(1) = 1 do i=1,nrow do j=1, ncol if (.not.(dabs(dns(i,j)) .le. eps)) then ja(next) = j a(next) = dns(i,j) next = next+1 endif enddo ia(i+1) = next enddo return c---- end of dnscsr ---------------------------------------------------- c----------------------------------------------------------------------- end c----------------------------------------------------------------------- subroutine getmask(nrow,nnz,ir,jc,jao,iao) c----------------------------------------------------------------------- implicit none integer nrow,nnz,ir(*),jc(*),jao(*),iao(*) integer k,k0,j,i,iad c----------------------------------------------------------------------- c Gets Compressed Sparse Row indices from Coordinate ones c----------------------------------------------------------------------- c Loosely based on coocsr from Sparsekit. c c on entry: c--------- c nrow = dimension of the matrix c nnz = number of nonzero elements in matrix c ir, c jc = matrix in coordinate format. ir(k), jc(k) store the nnz c nonzero index. The order of the elements is arbitrary. c iao = vector of 0 of size nrow+1 c c on return: c----------- c ir is destroyed c c jao, iao = matrix index in general sparse matrix format with c jao containing the column indices, c and iao being the pointer to the beginning of the row c c------------------------------------------------------------------------ c determine row-lengths. do 2 k=1, nnz iao(ir(k)) = iao(ir(k))+1 2 continue c starting position of each row.. k = 1 do 3 j=1,nrow+1 k0 = iao(j) iao(j) = k k = k+k0 3 continue c go through the structure once more. Fill in output matrix. do 4 k=1, nnz i = ir(k) j = jc(k) iad = iao(i) jao(iad) = j iao(i) = iad+1 4 continue c shift back iao do 5 j=nrow,1,-1 iao(j+1) = iao(j) 5 continue iao(1) = 1 return c----------------------------------------------------------------------- end c----------------------------------------------------------------------- subroutine getblock(a,ja,ia, nrw, rw, ncl, cl, bnz, b,jb,ib) c----------------------------------------------------------------------- c purpose: c -------- c this function returns the elements a(rw,cl) of a matrix a, c for any index vector rw and cl. the matrix is assumed to be stored c in compressed sparse row (csr) format. c c c Reinhard Furrer 2006-09-12 c----------------------------------------------------------------------- c parameters: c ----------- c on entry: c---------- c a,ja,ia = the matrix a in compressed sparse row format (input). c nrw,rw c ncl,cl = length of and the vector containing the rows and columns c to extract c c on return: c----------- c bnz = nonzero elements of b c b,jb,ib = the matrix a(rw,cl) in compressed sparse row format. c c note: c------ c no error testing is done. It is assumed that b has enough space c allocated. c----------------------------------------------------------------------- implicit none integer nrw,rw(*), ncl, cl(*) integer bnz, ia(*),ja(*), ib(*),jb(*) double precision a(*),b(*) c c local variables. c integer irw, jcl, jja c c write(*,*) cl(1),cl(2) bnz = 1 ib(1) = 1 do irw = 1,nrw do jcl = 1,ncl do jja = ia(rw(irw)),ia(rw(irw)+1)-1 if (cl(jcl) .eq. ja(jja)) then c we've found one... b(bnz) = a(jja) jb(bnz) = jcl bnz = bnz + 1 endif enddo enddo ib(irw+1) = bnz c end irw, we've cycled over all lines enddo bnz = bnz - 1 c write(*,*) cl(1),cl(2) return c--------end-of-getblock------------------------------------------------ c----------------------------------------------------------------------- end c----------------------------------------------------------------------- subroutine getlines(a,ja,ia, nrw, rw, bnz, b,jb,ib) c----------------------------------------------------------------------- c purpose: c -------- c this function returns the lines rw of a matrix a. c the matrix is assumed to be stored c in compressed sparse row (csr) format. c c c Reinhard Furrer 2012-04-04 c----------------------------------------------------------------------- c parameters: c ----------- c on entry: c---------- c a,ja,ia = the matrix a in compressed sparse row format (input). c nrw,rw = length of and the vector containing the rows and columns c to extract c c on return: c----------- c bnz = nonzero elements of b c b,jb,ib = the matrix a(rw,cl) in compressed sparse row format. c c note: c------ c no error testing is done. It is assumed that b has enough space c allocated. c----------------------------------------------------------------------- implicit none integer nrw,rw(*) integer bnz, ia(*),ja(*), ib(*),jb(*) double precision a(*),b(*) c c local variables. c integer irw, jja c bnz = 1 ib(1) = 1 do irw = 1,nrw do jja = ia(rw(irw)),ia(rw(irw)+1)-1 b(bnz) = a(jja) jb(bnz) = ja(jja) bnz = bnz + 1 enddo ib(irw+1) = bnz c end irw, we've cycled over all lines enddo bnz = bnz - 1 return c--------end-of-getlines------------------------------------------------ c----------------------------------------------------------------------- end c----------------------------------------------------------------------- subroutine getelem(i,j,a,ja,ia,iadd,elem) c----------------------------------------------------------------------- c purpose: c -------- c this function returns the element a(i,j) of a matrix a, c for any pair (i,j). the matrix is assumed to be stored c in compressed sparse row (csr) format. getelem performs a c binary search. c also returns (in iadd) the address of the element a(i,j) in c arrays a and ja when the search is successsful (zero if not). c----------------------------------------------------------------------- c parameters: c ----------- c on entry: c---------- c i = the row index of the element sought (input). c j = the column index of the element sought (input). c a = the matrix a in compressed sparse row format (input). c ja = the array of column indices (input). c ia = the array of pointers to the rows' data (input). c on return: c----------- c elem = value of a(i,j). c iadd = address of element a(i,j) in arrays a, ja if found, c zero if not found. (output) c c note: the inputs i and j are not checked for validity. c----------------------------------------------------------------------- c noel m. nachtigal october 28, 1990 -- youcef saad jan 20, 1991. c c Reinhard Furrer: converted to subroutine and eliminated sorted c many manipulations... last for 0.31; Sept 13 c----------------------------------------------------------------------- implicit none integer i, ia(*), iadd, j, ja(*) double precision a(*),elem c c local variables. c integer ibeg, iend, imid c c initialization c iadd = 0 ibeg = ia(i) iend = ia(i+1)-1 c empty line! test at beginning 10 if (iend .lt. ibeg) return c c begin binary search: c test of bounds if (ja(ibeg).gt.j) return if (ja(iend).lt.j) return if (ja(ibeg).eq.j) then iadd = ibeg goto 20 endif if (ja(iend).eq.j) then iadd = iend goto 20 endif c compute the middle index and test if found imid = ( ibeg + iend ) / 2 if (ja(imid).eq.j) then iadd = imid goto 20 endif c update the interval bounds. if (ja(imid).gt.j) then iend = imid -1 else ibeg = imid +1 endif goto 10 c c set iadd and elem before returning 20 elem = a(iadd) return c--------end-of-getelem------------------------------------------------- c----------------------------------------------------------------------- end subroutine getallelem(nir,ir,jr,a,ja,ia,alliadd,allelem) c----------------------------------------------------------------------- c purpose: c -------- c wrapper to getelem to retrieve several elements. c----------------------------------------------------------------------- c Reinhard Furrer 2006-09-12 c----------------------------------------------------------------------- implicit none integer nir,ir(nir),jr(nir),ja(*),ia(*),alliadd(nir) double precision a(*),allelem(nir) c local vars integer i do i = 1,nir call getelem(ir(i),jr(i),a,ja,ia,alliadd(i),allelem(i)) enddo return c--------end-of-allgetelem---------------------------------------------- c----------------------------------------------------------------------- end c----------------------------------------------------------------------- c----------------------------------------------------------------------- c- c- Modified by P. T. Ng from sparsekit c----------------------------------------------------------------------- c----------------------------------------------------------------------- c subroutine aemub (nrow,ncol,a,ja,ia,amask,jmask,imask, c * c,jc,ic,iw,aw,nzmax,ierr) subroutine aemub (nrow,ncol,a,ja,ia,amask,jmask,imask, * c,jc,ic,nzmax,ierr) c--------------------------------------------------------------------- implicit none integer nrow, ncol real(8) a(*),c(*),amask(*),aw(ncol) integer ia(nrow+1),ja(*),jc(*),ic(nrow+1),jmask(*) integer imask(nrow+1), nzmax, ierr logical iw(ncol) c----------------------------------------------------------------------- c further used variables integer len, k, k1, k2, ii, j c----------------------------------------------------------------------- c Modified from amask by Pin T. Ng on 2/27/03 to perform c element-wise multiplication c----------------------------------------------------------------------- c On entry: c--------- c nrow = integer. row dimension of input matrix c ncol = integer. Column dimension of input matrix. c c a, c ja, c ia = the A matrix in Compressed Sparse Row format c c amask, c jmask, c imask = matrix defining mask stored in compressed c sparse row format. (This is the B matrix) c c nzmax = length of arrays c and jc. see ierr. c c On return: c----------- c c a, ja, ia and amask, jmask, imask are unchanged. c c c c jc, c ic = the output matrix in Compressed Sparse Row format. c c ierr = integer. serving as error message.c c ierr = 1 means normal return c ierr .gt. 1 means that amask stopped when processing c row number ierr, because there was not enough space in c c, jc according to the value of nzmax. c c work arrays: c------------- c iw = logical work array of length ncol. c aw = real work array of length ncol. c c note: c------ the algorithm is in place: c, jc, ic can be the same as c a, ja, ia in which cas the code will overwrite the matrix c c on a, ja, ia c c----------------------------------------------------------------------- ierr = 0 len = 0 do 1 j=1, ncol iw(j) = .false. aw(j) = 0.0 1 continue c unpack the mask for row ii in iw do 100 ii=1, nrow c save pointer and value in order to be able to do things in place do 2 k=imask(ii), imask(ii+1)-1 iw(jmask(k)) = .true. aw(jmask(k)) = amask(k) 2 continue c add umasked elemnts of row ii k1 = ia(ii) k2 = ia(ii+1)-1 ic(ii) = len+1 do 200 k=k1,k2 j = ja(k) if (iw(j)) then len = len+1 if (len .gt. nzmax) then ierr = ii return endif jc(len) = j c(len) = a(k)*aw(j) endif 200 continue c do 3 k=imask(ii), imask(ii+1)-1 iw(jmask(k)) = .false. aw(jmask(k)) = 0.0 3 continue 100 continue ic(nrow+1)=len+1 c return c-----end-of-aemub ----------------------------------------------------- c----------------------------------------------------------------------- end c----------------------------------------------------------------------- subroutine aemub1 (nrow,ncol,a,ja,ia,b,jb,ib,c,jc,ic, * nzmax,ierr) implicit none integer nrow, ncol, nzmax, ierr real(8) a(*), b(*), c(*) integer ja(*),jb(*),jc(*),ia(nrow+1),ib(nrow+1),ic(nrow+1) c----------------------------------------------------------------------- c A modification of aplsb by Pin Ng on 6/12/02 to c perform the element-wise operation C = A*B for matrices in c sorted CSR format. c the difference with aplsb is that the resulting matrix is such that c the elements of each row are sorted with increasing column indices in c each row, provided the original matrices are sorted in the same way. c----------------------------------------------------------------------- c on entry: c --------- c nrow = integer. The row dimension of A and B c ncol = integer. The column dimension of A and B. c c a, c ja, c ia = Matrix A in compressed sparse row format with entries sorted c c b, c jb, c ib = Matrix B in compressed sparse row format with entries sorted c ascendly in each row c c nzmax = integer. The length of the arrays c and jc. c amub will stop if the result matrix C has a number c of elements that exceeds exceeds nzmax. See ierr. c c on return: c---------- c c, c jc, c ic = resulting matrix C in compressed sparse row sparse format c with entries sorted ascendly in each row. c c ierr = integer. serving as error message. c ierr = 0 means normal return, c ierr .gt. 0 means that amub stopped while computing the c i-th row of C with i=ierr, because the number c of elements in C exceeds nzmax. c c Notes: c------- c this will not work if any of the two input matrices is not sorted c----------------------------------------------------------------------- integer i, ka, kb, kc, kamax, kbmax, j1, j2 ierr = 0 kc = 1 ic(1) = kc c c the following loop does a merge of two sparse rows and c multiplies them. c do 6 i=1, nrow ka = ia(i) kb = ib(i) kamax = ia(i+1)-1 kbmax = ib(i+1)-1 5 continue c c this is a while -- do loop -- c if (ka .le. kamax .or. kb .le. kbmax) then c if (ka .le. kamax) then j1 = ja(ka) else c take j1 large enough that always j2 .lt. j1 j1 = ncol+1 endif if (kb .le. kbmax) then j2 = jb(kb) else c similarly take j2 large enough that always j1 .lt. j2 j2 = ncol+1 endif c c three cases c if (j1 .eq. j2) then c(kc) = a(ka)*b(kb) jc(kc) = j1 ka = ka+1 kb = kb+1 kc = kc+1 else if (j1 .lt. j2) then ka = ka+1 else if (j1 .gt. j2) then kb = kb+1 endif if (kc .gt. nzmax) goto 999 goto 5 c c end while loop c endif ic(i+1) = kc 6 continue return 999 ierr = i return c------------end-of-aemub1 --------------------------------------------- c----------------------------------------------------------------------- end c----------------------------------------------------------------------- subroutine aedib (nrow,ncol,job,a,ja,ia,b,jb,ib, * c,jc,ic,nzmax,iw,aw,ierr) implicit none integer nrow, ncol, job, nzmax, ierr real(8) a(*), b(*), c(*), aw(ncol) integer ja(*),jb(*),jc(*),ia(nrow+1),ib(nrow+1),ic(nrow+1), * iw(ncol) c----------------------------------------------------------------------- c performs the element-wise matrix division C = A/B. c Modified from aplsb by Pin Ng on 2/27/03 c----------------------------------------------------------------------- c on entry: c --------- c nrow = integer. The row dimension of A and B c ncol = integer. The column dimension of A and B. c job = integer. Job indicator. When job = 0, only the structure c (i.e. the arrays jc, ic) is computed and the c real values are ignored. c c a, c ja, c ia = Matrix A in compressed sparse row format. c c b, c jb, c ib = Matrix B in compressed sparse row format. c c nzmax = integer. The length of the arrays c and jc. c amub will stop if the result matrix C has a number c of elements that exceeds exceeds nzmax. See ierr. c c on return: c---------- c c, c jc, c ic = resulting matrix C in compressed sparse row sparse format. c c ierr = integer. serving as error message. c ierr = 0 means normal return, c ierr .gt. 0 means that amub stopped while computing the c i-th row of C with i=ierr, because the number c of elements in C exceeds nzmax. c c work arrays: c------------ c iw = integer work array of length equal to the number of c columns in A. c aw = real work array of length equal to the number of c columns in A. c c----------------------------------------------------------------------- logical values integer len, j, ii, ka, kb, k, jpos, jcol values = (job .ne. 0) ierr = 0 len = 0 ic(1) = 1 do 1 j=1, ncol iw(j) = 0 1 continue c do 500 ii=1, nrow c row i do 200 ka=ia(ii), ia(ii+1)-1 len = len+1 jcol = ja(ka) if (len .gt. nzmax) goto 999 jc(len) = jcol if (values) c(len) = a(ka)/0.0 iw(jcol)= len aw(jcol) = a(ka) 200 continue c do 300 kb=ib(ii),ib(ii+1)-1 jcol = jb(kb) jpos = iw(jcol) if (jpos .eq. 0) then len = len+1 if (len .gt. nzmax) goto 999 jc(len) = jcol if (values) c(len) = 0.0 iw(jcol)= len else if (values) c(jpos) = aw(jcol)/b(kb) endif 300 continue do 301 k=ic(ii), len iw(jc(k)) = 0 301 continue ic(ii+1) = len+1 500 continue return 999 ierr = ii return c------------end of aedib ----------------------------------------------- c----------------------------------------------------------------------- end c----------------------------------------------------------------------- subroutine aeexpb (nrow,ncol,job,a,ja,ia,b,jb,ib, * c,jc,ic,nzmax,iw,aw,ierr) implicit none integer nrow, ncol, job, nzmax, ierr real(8) a(*), b(*), c(*), aw(ncol) integer ja(*),jb(*),jc(*),ia(nrow+1),ib(nrow+1),ic(nrow+1), * iw(ncol) c----------------------------------------------------------------------- c performs the element-wise matrix division C = A/B. c Modified from aplsb by Pin Ng on 2/27/03 c----------------------------------------------------------------------- c on entry: c --------- c nrow = integer. The row dimension of A and B c ncol = integer. The column dimension of A and B. c job = integer. Job indicator. When job = 0, only the structure c (i.e. the arrays jc, ic) is computed and the c real values are ignored. c c a, c ja, c ia = Matrix A in compressed sparse row format. c c b, c jb, c ib = Matrix B in compressed sparse row format. c c nzmax = integer. The length of the arrays c and jc. c amub will stop if the result matrix C has a number c of elements that exceeds exceeds nzmax. See ierr. c c on return: c---------- c c, c jc, c ic = resulting matrix C in compressed sparse row sparse format. c c ierr = integer. serving as error message. c ierr = 0 means normal return, c ierr .gt. 0 means that amub stopped while computing the c i-th row of C with i=ierr, because the number c of elements in C exceeds nzmax. c c work arrays: c------------ c iw = integer work array of length equal to the number of c columns in A. c aw = real work array of length equal to the number of c columns in A. c c----------------------------------------------------------------------- logical values integer len, kb, ka, k, jpos, jcol, j, ii values = (job .ne. 0) ierr = 0 len = 0 ic(1) = 1 do 1 j=1, ncol iw(j) = 0 1 continue c do 500 ii=1, nrow c row i do 200 ka=ia(ii), ia(ii+1)-1 len = len+1 jcol = ja(ka) if (len .gt. nzmax) goto 999 jc(len) = jcol if (values) c(len) = 1.0 iw(jcol)= len aw(jcol) = a(ka) 200 continue c do 300 kb=ib(ii),ib(ii+1)-1 jcol = jb(kb) jpos = iw(jcol) if (jpos .eq. 0) then len = len+1 if (len .gt. nzmax) goto 999 jc(len) = jcol if (values) c(len) = 0.0**b(kb) iw(jcol)= len else if (values) c(jpos) = aw(jcol)**b(kb) endif 300 continue do 301 k=ic(ii), len iw(jc(k)) = 0 301 continue ic(ii+1) = len+1 500 continue return 999 ierr = ii return c------------end of aeexpb ----------------------------------------------- c----------------------------------------------------------------------- end SUBROUTINE CALCJA(nrow,nsuper, % xsuper,lindx,xlindx,xlnz, % cholcja) c small function to calculate ja for the cholesky factor c as they use a condensed format. GRATULIERU LIT! c INPUT: c nrow (integer) number of rows c nsuper (integer) number of supernodes c xsuper (integer) supernode partition c xlindx,lindx (integer) row indices for each supernode c xlnz (integer) ia for cholesky factor c c OUTPUT: c cholcja (integer) ja for cholesky factor IMPLICIT NONE INTEGER nrow,nsuper INTEGER xsuper(nrow),lindx(*),xlindx(nrow+1),xlnz(nrow+1) INTEGER cholcja(*) INTEGER k, i, j, m, n k=1 m=1 DO i=1,nsuper DO j=1,( xsuper(i+1)-xsuper(i)) DO n=1,(xlnz(k+1)-xlnz(k)) cholcja(m)=lindx( xlindx(i)+j-2 + n) m=m+1 ENDDO k=k+1 ENDDO ENDDO RETURN END subroutine transpose(n,m,a,ja,ia,ao,jao,iao) implicit none integer n,m,ia(n+1),iao(m+1),ja(*),jao(*) double precision a(*),ao(*) integer i,j,k,next c----------------------------------------------------------------------- c Transposition c similar to csrcsc from sparsekit c----------------------------------------------------------------------- c on entry: c---------- c n = number of rows of CSR matrix. c m = number of columns of CSC matrix. c a = real array of length nnz (nnz=number of nonzero elements in input c matrix) containing the nonzero elements. c ja = integer array of length nnz containing the column positions c of the corresponding elements in a. c ia = integer of size n+1. ia(k) contains the position in a, ja of c the beginning of the k-th row. c c on return: c ---------- c ao = real array of size nzz containing the "a" part of the transpose c jao = integer array of size nnz containing the column indices. c iao = integer array of size n+1 containing the "ia" index array of c the transpose. c c----------------------------------------------------------------------- c----------------- compute lengths of rows of transp(A) ---------------- do i=1, n do k=ia(i), ia(i+1)-1 j = ja(k)+1 iao(j) = iao(j)+1 enddo enddo c---------- compute pointers from lengths ------------------------------ iao(1) = 1 do i=1,m iao(i+1) = iao(i) + iao(i+1) enddo c--------------- now do the actual copying ----------------------------- do i=1,n do k=ia(i),ia(i+1)-1 j = ja(k) next = iao(j) ao(next) = a(k) jao(next) = i iao(j) = next+1 enddo enddo c-------------------------- reshift iao and leave ---------------------- do i=m,1,-1 iao(i+1) = iao(i) enddo iao(1) = 1 c----------------------------------------------------------------------- end c----------------------------------------------------------------------- c----------------------------------------------------------------------- subroutine reducedim(a,ja,ia,eps,bnrow,bncol,k,b,jb,ib) implicit none double precision a(*),b(*),eps integer bnrow, bncol,k integer ia(*),ja(*),ib(*),jb(*) integer i, j, jaj c----------------------------------------------------------------------- c Reduces the dimension of A to (,bnrow,bncol) by copying it to B. c (Hence not in place - for R purposes). c Only elements smaller than eps are copied. c----------------------------------------------------------------------- c on entry: c--------- c c------------------------------------------------------------------------ k=1 do i=1,bnrow ib(i)=k do j=ia(i), ia(i+1)-1 jaj=ja(j) if (jaj .le.bncol) then if (abs( a(j)) .gt. eps) then b(k)=a(j) jb(k)=jaj k=k+1 endif endif enddo enddo ib(bnrow+1)=k return c----------------------------------------------------------------------- end c----------------------------------------------------------------------- c Currently not used... subroutine reducediminplace(eps,nrow,ncol,k,a,ja,ia) implicit none double precision a(*),eps integer nrow, ncol,k integer ia(*),ja(*) integer i, j, jj, itmp c----------------------------------------------------------------------- c Reduces the dimension of A to (nrow,ncol) _in place_ c Only elements smaller than eps are copied. c----------------------------------------------------------------------- c Reinhard Furrer, June 2008 c------------------------------------------------------------------------ k=1 do i=1,nrow itmp = ia(i) ia(i)=k do j=itmp, ia(i+1)-1 jj=ja(j) if (jj .le. ncol) then if (abs( a(jj)) .gt. eps) then a(k)=a(jj) ja(k)=jj k=k+1 endif endif enddo enddo ia(nrow+1)=k return c----------------------------------------------------------------------- end c----------------------------------------------------------------------- c----------------------------------------------------------------------c c T R I A N G U L A R S Y S T E M S O L U T I O N S c c c c spamforward and spamback c c----------------------------------------------------------------------c subroutine spamforward (n,p,x,b,l,jl,il) implicit none integer n, p, jl(*),il(n+1) double precision x(n,p), b(n,p), l(*) integer i, j, k double precision t c----------------------------------------------------------------------- c solves L x = y ; L = lower triang. / CSR format c sequential forward elimination c----------------------------------------------------------------------- c c On entry: c---------- c n,p = integer. dimensions of problem. c b = real array containg the right side. c c l, jl, il, = Lower triangular matrix stored in CSR format. c c On return: c----------- c x = The solution of L x = b. c-------------------------------------------------------------------- c Reinhard Furrer June 2008, April 2012, Sept 2016, Nov 2019 c initialize k for next setting k=0 c if first diagonal element is zero, break if (abs(l(1)) .le. 0.D0) goto 5 c cycle over all columns of b do i=1,p c first row has one element then cycle over all rows x(1,i) = b(1,i) / l(1) do 3 k = 2, n t = b(k,i) do 1 j = il(k), il(k+1)-1 if (jl(j) .lt. k) then t = t-l(j)*x(jl(j),i) else if (jl(j) .eq. k) then if (abs(l(j)) .le. 0.D0) goto 5 c diagonal element is not zero, hence we divide and leave the loop x(k,i) = t / l(j) goto 3 endif endif 1 continue 3 continue enddo return 5 n = -k return end c----------------------------------------------------------------------- subroutine spamback (n,p,x,b,r,jr,ir) implicit none integer n, p, jr(*),ir(n+1) double precision x(n,p), b(n,p), r(*) integer l, j, k double precision t c----------------------------------------------------------------------- c Solves R x = b R = upper triangular. c----------------------------------------------------------------------- c c On entry: c---------- c n,p = integers. dimension of problem. c b = real array containg the right side. c c r, jr, ir, = Upper triangular matrix stored in CSR format. c c On return: c----------- c x = The solution of R x = b . c-------------------------------------------------------------------- c Reinhard Furrer June 2008, April 2012, Sept 2016, Nov 2019 k = n+1 if (abs( r(ir(n+1)-1) ) .le. 0.D0) goto 5 do l=1,p x(n,l) = b(n,l) / r(ir(n+1)-1) do 3 k = n-1,1,-1 t = b(k,l) do 1 j = ir(k+1)-1,ir(k),-1 if (jr(j) .gt. k) then t = t - r(j)*x(jr(j),l) else if (jr(j) .eq. k) then if (abs(r(j)) .le. 0.D0) goto 5 c diagonal element is not zero, hence we divide and leave the loop x(k,l) = t / r(j) goto 3 endif endif 1 continue 3 continue enddo return 5 n = -k return end c----------------------------------------------------------------------- spam/src/cholmodified.f0000644000176200001440000063656013574431374014631 0ustar liggesusers subroutine updatefactor( m,nnzd, & d,jd,id, invp,perm, & lindx,xlindx, nsuper,lnz,xlnz, & snode, xsuper, & cachesize,ierr) implicit none integer m,nnzd integer nsuper,tmpsiz, & ierr, & jd(nnzd),cachesize, & id(m+1),lindx(*),xlindx(*), & invp(m),perm(m),xlnz(m+1), & snode(m),xsuper(m+1) double precision d(nnzd),lnz(*) c temp and working stuff, loops, etc integer iwork(7*m+3) integer split(m) c c Clean L call cleanlnz(nsuper,xsuper,xlnz,lnz) c c Input numerical values into data structures of L call inpnv(id,jd,d,perm,invp,nsuper,xsuper,xlindx,lindx, & xlnz,lnz,iwork) c c Initialization for block factorization call bfinit(m,nsuper,xsuper,snode,xlindx,lindx,cachesize,tmpsiz, & split) c c Numerical factorization call blkfc2(nsuper,xsuper,snode,split,xlindx,lindx,xlnz, & lnz,iwork(1),iwork(nsuper+1),iwork(2*nsuper+1), & iwork(2*nsuper+m+1),tmpsiz,ierr) if (ierr .eq. -1) then ierr = 1 go to 100 elseif (ierr .eq. -2) then ierr = 3 go to 100 endif 100 continue return end subroutine cholstepwise(m,nnzd, & d,jd,id, doperm,invp,perm, & nsub,nsubmax, & lindx,xlindx,nsuper,nnzlmax,lnz,xlnz, & snode,xsuper, & cachsz,ierr) c Modified chol routine c c c Sparse least squares solver via Ng-Peyton's sparse Cholesky c factorization for sparse symmetric positive definite c INPUT: c m -- the number of column in the matrix A c d -- an nnzd-vector of non-zero values of A c jd -- an nnzd-vector of indices in d c id -- an (m+1)-vector of pointers to the begining of each c row in d and jd c nsubmax -- upper bound of the dimension of lindx c lindx -- an nsub-vector of integer which contains, in c column major oder, the row subscripts of the nonzero c entries in L in a compressed storage format c xlindx -- an nsuper-vector of integer of pointers for lindx c nsuper -- the length of xlindx ??? c nnzlmax -- the upper bound of the non-zero entries in c L stored in lnz, including the diagonal entries c lnz -- First contains the non-zero entries of d; later c contains the entries of the Cholesky factor c xlnz -- column pointer for L stored in lnz c invp -- an n-vector of integer of inverse permutation c vector c perm -- an n-vector of integer of permutation vector c colcnt -- array of length m, containing the number of c non-zeros in each column of the factor, including c the diagonal entries c snode -- array of length m for recording supernode c membership c xsuper -- array of length m+1 containing the supernode c partitioning c split -- an m-vector with splitting of supernodes so that c they fit into cache c tmpmax -- upper bound of the dimension of tmpvec c tmpvec -- a tmpmax-vector of temporary vector c cachsz -- size of the cache (in kilobytes) on the target c machine c ierr -- error flag c 1 -- insufficient work space in call to extract c 2 -- (not defined) c 3 -- insufficient storage in iwork when calling sfinit; c 4 -- nnzl > nnzlmax when calling sfinit c 5 -- nsub > nsubmax when calling sfinit c 6 -- insufficient work space in iwork when calling symfct c 7 -- inconsistancy in input when calling symfct c 8 -- tmpsiz > tmpmax when calling symfct; increase tmpmax c 9 -- nonpositive diagonal encountered when calling c blkfct c 10 -- insufficient work storage in tmpvec when calling c blkfct c 11 -- insufficient work storage in iwork when calling c blkfct c OUTPUT: c y -- an m-vector of least squares solution c nsub -- number of subscripts in lindx c WORK ARRAYS: c adjncy -- the indices of non diag elements c iwsiz -- set at 7*m+3 c iwork -- an iwsiz-vector of integer as work space c c implicit none integer m,nnzd,doperm integer nsub,nsuper,nnzl,iwsiz,tmpsiz, & nnzlmax,nsubmax,cachsz,ierr, & adj(m+1),adjncy(nnzd-m+1),jd(nnzd), c fix introduced in 29-3 c & adj(m+1),adjncy(nnzd-m),jd(nnzd), & id(m+1),lindx(nsubmax),xlindx(m+1), & invp(m),perm(m),xlnz(m+1), & colcnt(m),snode(m),xsuper(m+1),split(m) double precision d(nnzd),lnz(nnzlmax) c temp and working stuff, loops, etc integer i,j,k, nnzadj, jtmp, intmp1, intmp2 integer iwork(7*m+3) c iwsiz is used temporalily iwsiz=0 c Create the adjacency matrix: eliminate the diagonal elements from c (d,id,jd) and make two copies: (*,xlindx,lindx),(*,adj,adjncy) c Also to lindx and xlindx, because the matrix structure is destroyed c by the minimum degree ordering routine. nsub = 0 c the adj matrix has m elements less than d nnzadj = nnzd - m k=1 do i=1,m c copy id, but ajust for the missing diagonal. xlindx(i) = id(i)-i+1 adj(i) = xlindx(i) c now cycle over all rows do j=id(i),id(i+1)-1 jtmp=jd(j) if (jtmp.ne.i) then lindx(k) = jtmp adjncy(k) = jtmp k=k+1 else if ( d(j) .le. 0) then ierr = 1 return endif iwsiz = iwsiz + 1 endif enddo enddo jtmp=m+1 xlindx(jtmp) = id(jtmp)-m adj(jtmp) = xlindx(jtmp) c check if we actually had m elements on the diagonal... if ( iwsiz .lt. m) then ierr = 1 return endif c initialize iwsiz to the later used value... iwsiz=7*m+3 c c c reorder the matrix using minimum degree ordering routine. c we call the genmmd function directly. if (doperm.eq.1) then c delta - tolerance value for multiple elimination. c set to 0 below c maxint - maximum machine representable (short) integer c (any smaller estimate will do) for marking c nodes. c set to 32767 below intmp1 = 0 intmp2 = 32767 call genmmd ( m, xlindx,lindx, invp,perm,intmp1, 1 iwork(1), iwork(m+1), iwork(2*m+1), iwork(3*m+1) , 1 intmp2, nsub ) endif if (doperm.eq.2) then call genrcm ( m, nnzadj, xlindx,lindx, perm ) do i=1,m invp(perm(i))=i enddo endif if (doperm.eq.0) then do i=1,m invp(perm(i))=i enddo endif c c Call sfinit: Symbolic factorization initialization c to compute supernode partition and storage requirements c for symbolic factorization. New ordering is a postordering c of the nodal elimination tree c call sfinit(m,nnzadj,adj(1),adjncy(1),perm, & invp,colcnt,nnzl,nsub,nsuper,snode,xsuper,iwsiz, & iwork,ierr) c we do not have to test ierr, as we have hardwired iwsiz to 7*m+3 if (nnzl .gt. nnzlmax) then ierr = 4 go to 100 endif if (nsub .gt. nsubmax) then ierr = 5 go to 100 endif c c Call symfct: Perform supernodal symbolic factorization c iwsiz = nsuper + 2 * m + 1 call symfc2(m,nnzadj,adj(1),adjncy(1),perm,invp, & colcnt,nsuper,xsuper,snode,nsub,xlindx,lindx, & xlnz, & iwork(1), iwork(nsuper+1), iwork(nsuper+m+2) ,ierr) c ierr = -2 "inconsistency in the input" if (ierr .eq. -2) then ierr = 6 go to 100 endif c c Input numerical values into data structures of L call inpnv(id,jd,d,perm,invp,nsuper,xsuper,xlindx,lindx, & xlnz,lnz,iwork) c c Initialization for block factorization call bfinit(m,nsuper,xsuper,snode,xlindx,lindx,cachsz,tmpsiz, & split) c c Numerical factorization call blkfc2(nsuper,xsuper,snode,split,xlindx,lindx,xlnz, & lnz,iwork(1),iwork(nsuper+1),iwork(2*nsuper+1), & iwork(2*nsuper+m+1),tmpsiz,ierr) if (ierr .eq. -1) then ierr = 1 go to 100 elseif (ierr .eq. -2) then ierr = 3 go to 100 endif 100 continue return end C*********************************************************************** C*********************************************************************** C C Authors: Reinhard Furrer, based on inpnv C C C*********************************************************************** C*********************************************************************** C C ------------------------------------------------------ C Clean the array lnz C ------------------------------------------------------ C SUBROUTINE CLEANLNZ (NSUPER, XSUPER, XLNZ, LNZ) C IMPLICIT NONE INTEGER NSUPER INTEGER XSUPER(*), XLNZ(*) DOUBLE PRECISION LNZ(*) C INTEGER II, J, JSUPER C DO 500 JSUPER = 1, NSUPER DO 400 J = XSUPER(JSUPER), XSUPER(JSUPER+1)-1 DO 200 II = XLNZ(J), XLNZ(J+1)-1 LNZ(II) = 0.0 200 CONTINUE 400 CONTINUE C 500 CONTINUE RETURN END C*********************************************************************** C*********************************************************************** C C Version: 0.4 C Last modified: December 27, 1994 C Authors: Esmond G. Ng and Barry W. Peyton C C Mathematical Sciences Section, Oak Ridge National Laboratory C C*********************************************************************** C*********************************************************************** C************ ASSMB .... INDEXED ASSEMBLY OPERATION ************ C*********************************************************************** C*********************************************************************** C C PURPOSE: C THIS ROUTINE PERFORMS AN INDEXED ASSEMBLY (I.E., SCATTER-ADD) C OPERATION, ASSUMING DATA STRUCTURES USED IN SOME OF OUR SPARSE C CHOLESKY CODES. C C INPUT PARAMETERS: C M - NUMBER OF ROWS IN Y. C Q - NUMBER OF COLUMNS IN Y. C Y - BLOCK UPDATE TO BE INCORPORATED INTO FACTOR C STORAGE. C RELIND - RELATIVE INDICES FOR MAPPING THE UPDATES C ONTO THE TARGET COLUMNS. C XLNZ - POINTERS TO THE START OF EACH COLUMN IN THE C TARGET MATRIX. C C OUTPUT PARAMETERS: C LNZ - CONTAINS COLUMNS MODIFIED BY THE UPDATE C MATRIX. C C*********************************************************************** C SUBROUTINE ASSMB ( M , Q , Y , RELIND, XLNZ , & LNZ , LDA ) C C*********************************************************************** implicit none C C ----------- C PARAMETERS. C ----------- C INTEGER LDA , M , Q INTEGER XLNZ(*) INTEGER RELIND(*) DOUBLE PRECISION LNZ(*) , Y(*) C C ---------------- C LOCAL VARIABLES. C ---------------- C INTEGER ICOL , IL1 , IR , IY1 , LBOT1 , & YCOL , YOFF1 C C*********************************************************************** C C YOFF1 = 0 IY1 = 0 DO 200 ICOL = 1, Q YCOL = LDA - RELIND(ICOL) LBOT1 = XLNZ(YCOL+1) - 1 CDIR$ IVDEP DO 100 IR = ICOL, M IL1 = LBOT1 - RELIND(IR) IY1 = YOFF1 + IR LNZ(IL1) = LNZ(IL1) + Y(IY1) Y(IY1) = 0.0D0 100 CONTINUE YOFF1 = IY1 - ICOL 200 CONTINUE C RETURN END C*********************************************************************** C*********************************************************************** C C Version: 0.4 C Last modified: December 27, 1994 C Authors: Joseph W.H. Liu C C Mathematical Sciences Section, Oak Ridge National Laboratory C C*********************************************************************** C*********************************************************************** C****** BETREE ..... BINARY TREE REPRESENTATION OF ETREE ******* C*********************************************************************** C*********************************************************************** C C WRITTEN BY JOSEPH LIU (JUL 17, 1985) C C PURPOSE: C TO DETERMINE THE BINARY TREE REPRESENTATION OF THE ELIMINATION C TREE GIVEN BY THE PARENT VECTOR. THE RETURNED REPRESENTATION C WILL BE GIVEN BY THE FIRST-SON AND BROTHER VECTORS. THE ROOT C OF THE BINARY TREE IS ALWAYS NEQNS. C C INPUT PARAMETERS: C NEQNS - NUMBER OF EQUATIONS. C PARENT - THE PARENT VECTOR OF THE ELIMINATION TREE. C IT IS ASSUMED THAT PARENT(I) > I EXCEPT OF C THE ROOTS. C C OUTPUT PARAMETERS: C FSON - THE FIRST SON VECTOR. C BROTHR - THE BROTHER VECTOR. C C*********************************************************************** C SUBROUTINE BETREE ( NEQNS , PARENT, FSON , BROTHR ) C C*********************************************************************** C implicit none INTEGER BROTHR(*) , FSON(*) , & PARENT(*) C INTEGER NEQNS C C*********************************************************************** C INTEGER LROOT , NODE , NDPAR C C*********************************************************************** C IF ( NEQNS .LE. 0 ) RETURN C DO 100 NODE = 1, NEQNS FSON(NODE) = 0 BROTHR(NODE) = 0 100 CONTINUE LROOT = NEQNS C ------------------------------------------------------------ C FOR EACH NODE := NEQNS-1 STEP -1 DOWNTO 1, DO THE FOLLOWING. C ------------------------------------------------------------ IF ( NEQNS .LE. 1 ) RETURN DO 300 NODE = NEQNS-1, 1, -1 NDPAR = PARENT(NODE) IF ( NDPAR .LE. 0 .OR. NDPAR .EQ. NODE ) THEN C ------------------------------------------------- C NODE HAS NO PARENT. GIVEN STRUCTURE IS A FOREST. C SET NODE TO BE ONE OF THE ROOTS OF THE TREES. C ------------------------------------------------- BROTHR(LROOT) = NODE LROOT = NODE ELSE C ------------------------------------------- C OTHERWISE, BECOMES FIRST SON OF ITS PARENT. C ------------------------------------------- BROTHR(NODE) = FSON(NDPAR) FSON(NDPAR) = NODE ENDIF 300 CONTINUE BROTHR(LROOT) = 0 C RETURN END C*********************************************************************** C*********************************************************************** C C Version: 0.4 C Last modified: December 27, 1994 C Authors: Esmond G. Ng and Barry W. Peyton C C Mathematical Sciences Section, Oak Ridge National Laboratory C C*********************************************************************** C*********************************************************************** C****** BFINIT ..... INITIALIZATION FOR BLOCK FACTORIZATION ****** C*********************************************************************** C*********************************************************************** C C PURPOSE: C THIS SUBROUTINE COMPUTES ITEMS NEEDED BY THE LEFT-LOOKING C BLOCK-TO-BLOCK CHOLESKY FACTORITZATION ROUTINE BLKFCT. C C INPUT PARAMETERS: C NEQNS - NUMBER OF EQUATIONS. C NSUPER - NUMBER OF SUPERNODES. C XSUPER - INTEGER ARRAY OF SIZE (NSUPER+1) CONTAINING C THE SUPERNODE PARTITIONING. C SNODE - SUPERNODE MEMBERSHIP. C (XLINDX,LINDX) - ARRAYS DESCRIBING THE SUPERNODAL STRUCTURE. C CACHSZ - CACHE SIZE (IN KBYTES). C C OUTPUT PARAMETERS: C TMPSIZ - SIZE OF WORKING STORAGE REQUIRED BY BLKFCT. C SPLIT - SPLITTING OF SUPERNODES SO THAT THEY FIT C INTO CACHE. C C*********************************************************************** C SUBROUTINE BFINIT ( NEQNS , NSUPER, XSUPER, SNODE , XLINDX, & LINDX , CACHSZ, TMPSIZ, SPLIT ) C C*********************************************************************** implicit none C INTEGER CACHSZ, NEQNS , NSUPER, TMPSIZ INTEGER XLINDX(*) , XSUPER(*) INTEGER LINDX (*) , SNODE (*) , & SPLIT(*) C C*********************************************************************** C C --------------------------------------------------- C DETERMINE FLOATING POINT WORKING SPACE REQUIREMENT. C --------------------------------------------------- CALL FNTSIZ ( NSUPER, XSUPER, SNODE , XLINDX, LINDX , & TMPSIZ ) C C ------------------------------- C PARTITION SUPERNODES FOR CACHE. C ------------------------------- CALL FNSPLT ( NEQNS , NSUPER, XSUPER, XLINDX, CACHSZ, & SPLIT ) C RETURN END C*********************************************************************** C*********************************************************************** C C Version: 0.3 C Last modified: March 6, 1995 C Authors: Esmond G. Ng and Barry W. Peyton C RF eliminated dependence on SMXPY and MMPY C C Mathematical Sciences Section, Oak Ridge National Laboratoy C C*********************************************************************** C*********************************************************************** C********* BLKFC2 ..... BLOCK GENERAL SPARSE CHOLESKY ********* C*********************************************************************** C*********************************************************************** C C PURPOSE: C THIS SUBROUTINE FACTORS A SPARSE POSITIVE DEFINITE MATRIX. C THE COMPUTATION IS ORGANIZED AROUND KERNELS THAT PERFORM C SUPERNODE-TO-SUPERNODE UPDATES, I.E., BLOCK-TO-BLOCK UPDATES. C C INPUT PARAMETERS: C NSUPER - NUMBER OF SUPERNODES. C XSUPER - SUPERNODE PARTITION. C SNODE - MAPS EACH COLUMN TO THE SUPERNODE CONTAINING C IT. C SPLIT - SPLITTING OF SUPERNODES SO THAT THEY FIT C INTO CACHE. C (XLINDX,LINDX) - ROW INDICES FOR EACH SUPERNODE (INCLUDING C THE DIAGONAL ELEMENTS). C (XLNZ,LNZ) - ON INPUT, CONTAINS MATRIX TO BE FACTORED. C TMPSIZ - SIZE OF TEMPORARY WORKING STORAGE. C C OUTPUT PARAMETERS: C LNZ - ON OUTPUT, CONTAINS CHOLESKY FACTOR. C IFLAG - ERROR FLAG. C 0: SUCCESSFUL FACTORIZATION. C -1: NONPOSITIVE DIAGONAL ENCOUNTERED, C MATRIX IS NOT POSITIVE DEFINITE. C -2: INSUFFICIENT WORKING STORAGE C [TEMP(*)]. C C WORKING PARAMETERS: C LINK - LINKS TOGETHER THE SUPERNODES IN A SUPERNODE C ROW. C LENGTH - LENGTH OF THE ACTIVE PORTION OF EACH C SUPERNODE. C INDMAP - VECTOR OF SIZE NEQNS INTO WHICH THE GLOBAL C INDICES ARE SCATTERED. C RELIND - MAPS LOCATIONS IN THE UPDATING COLUMNS TO C THE CORRESPONDING LOCATIONS IN THE UPDATED C COLUMNS. (RELIND IS GATHERED FROM INDMAP). C TEMP - REAL VECTOR FOR ACCUMULATING UPDATES. MUST C ACCOMODATE ALL COLUMNS OF A SUPERNODE. C C*********************************************************************** C SUBROUTINE BLKFC2 ( NSUPER, XSUPER, SNODE , SPLIT , XLINDX, & LINDX , XLNZ , LNZ , LINK , LENGTH, & INDMAP, RELIND, TMPSIZ, IFLAG ) C C********************************************************************* implicit none C C ----------- C PARAMETERS. C ----------- C INTEGER XLINDX(*) , XLNZ(*) INTEGER INDMAP(*) , LENGTH(*) , & LINDX(*) , LINK(*) , & RELIND(*) , SNODE(*) , & SPLIT(*) , XSUPER(*) INTEGER IFLAG , NSUPER, TMPSIZ DOUBLE PRECISION LNZ(*) C C ---------------- C LOCAL VARIABLES. C ---------------- C INTEGER FJCOL , FKCOL , I , ILEN , ILPNT , & INDDIF, JLEN , JLPNT , JSUP , JXPNT , & KFIRST, KLAST , KLEN , KLPNT , KSUP , & KXPNT , LJCOL , NCOLUP, NJCOLS, NKCOLS, & NXKSUP, NXTCOL, NXTSUP, STORE DOUBLE PRECISION TEMP(TMPSIZ) C RF: put TEMP(*) into a local variable DOUBLE PRECISION MXDIAG INTEGER NTINY C********************************************************************* C IFLAG = 0 NTINY = 0 NXTCOL = 0 C C ----------------------------------------------------------- C INITIALIZE EMPTY ROW LISTS IN LINK(*) AND ZERO OUT TEMP(*). C ----------------------------------------------------------- DO 100 JSUP = 1, NSUPER LINK(JSUP) = 0 100 CONTINUE DO 200 I = 1, TMPSIZ TEMP(I) = 0.0D+00 200 CONTINUE C COMPUTE MAXIMUM DIAGONAL ELEMENT IN INPUT MATRIX MXDIAG = 0.D0 DO 201 I = 1, XSUPER(NSUPER+1)-1 FJCOL = XLNZ(I) MXDIAG = MAX(MXDIAG, LNZ(FJCOL)) 201 CONTINUE C C --------------------------- C FOR EACH SUPERNODE JSUP ... C --------------------------- DO 600 JSUP = 1, NSUPER C C ------------------------------------------------ C FJCOL ... FIRST COLUMN OF SUPERNODE JSUP. C LJCOL ... LAST COLUMN OF SUPERNODE JSUP. C NJCOLS ... NUMBER OF COLUMNS IN SUPERNODE JSUP. C JLEN ... LENGTH OF COLUMN FJCOL. C JXPNT ... POINTER TO INDEX OF FIRST C NONZERO IN COLUMN FJCOL. C ------------------------------------------------ FJCOL = XSUPER(JSUP) NJCOLS = XSUPER(JSUP+1) - FJCOL LJCOL = FJCOL + NJCOLS - 1 JLEN = XLNZ(FJCOL+1) - XLNZ(FJCOL) JXPNT = XLINDX(JSUP) C print *, 'Super Node: ', JSUP, ' first: ', FJCOL, C . ' last: ', LJCOL C C C ----------------------------------------------------- C SET UP INDMAP(*) TO MAP THE ENTRIES IN UPDATE COLUMNS C TO THEIR CORRESPONDING POSITIONS IN UPDATED COLUMNS, C RELATIVE THE THE BOTTOM OF EACH UPDATED COLUMN. C ----------------------------------------------------- CALL LDINDX ( JLEN, LINDX(JXPNT), INDMAP ) C C ----------------------------------------- C FOR EVERY SUPERNODE KSUP IN ROW(JSUP) ... C ----------------------------------------- KSUP = LINK(JSUP) 300 IF ( KSUP .GT. 0 ) THEN NXKSUP = LINK(KSUP) C C ------------------------------------------------------- C GET INFO ABOUT THE CMOD(JSUP,KSUP) UPDATE. C C FKCOL ... FIRST COLUMN OF SUPERNODE KSUP. C NKCOLS ... NUMBER OF COLUMNS IN SUPERNODE KSUP. C KLEN ... LENGTH OF ACTIVE PORTION OF COLUMN FKCOL. C KXPNT ... POINTER TO INDEX OF FIRST NONZERO IN ACTIVE C PORTION OF COLUMN FJCOL. C ------------------------------------------------------- FKCOL = XSUPER(KSUP) NKCOLS = XSUPER(KSUP+1) - FKCOL KLEN = LENGTH(KSUP) KXPNT = XLINDX(KSUP+1) - KLEN C C ------------------------------------------- C PERFORM CMOD(JSUP,KSUP), WITH SPECIAL CASES C HANDLED DIFFERENTLY. C ------------------------------------------- C IF ( KLEN .NE. JLEN ) THEN C C ------------------------------------------- C SPARSE CMOD(JSUP,KSUP). C C NCOLUP ... NUMBER OF COLUMNS TO BE UPDATED. C ------------------------------------------- C DO 400 I = 0, KLEN-1 NXTCOL = LINDX(KXPNT+I) IF ( NXTCOL .GT. LJCOL ) GO TO 500 400 CONTINUE I = KLEN 500 CONTINUE NCOLUP = I C IF ( NKCOLS .EQ. 1 ) THEN C C ---------------------------------------------- C UPDATING TARGET SUPERNODE BY TRIVIAL C SUPERNODE (WITH ONE COLUMN). C C KLPNT ... POINTER TO FIRST NONZERO IN ACTIVE C PORTION OF COLUMN FKCOL. C ---------------------------------------------- KLPNT = XLNZ(FKCOL+1) - KLEN CALL MMPYI ( KLEN, NCOLUP, LINDX(KXPNT), & LNZ(KLPNT), XLNZ, LNZ, INDMAP ) C ELSE C C -------------------------------------------- C KFIRST ... FIRST INDEX OF ACTIVE PORTION OF C SUPERNODE KSUP (FIRST COLUMN TO C BE UPDATED). C KLAST ... LAST INDEX OF ACTIVE PORTION OF C SUPERNODE KSUP. C -------------------------------------------- C KFIRST = LINDX(KXPNT) KLAST = LINDX(KXPNT+KLEN-1) INDDIF = INDMAP(KFIRST) - INDMAP(KLAST) C IF ( INDDIF .LT. KLEN ) THEN C C --------------------------------------- C DENSE CMOD(JSUP,KSUP). C C ILPNT ... POINTER TO FIRST NONZERO IN C COLUMN KFIRST. C ILEN ... LENGTH OF COLUMN KFIRST. C --------------------------------------- ILPNT = XLNZ(KFIRST) ILEN = XLNZ(KFIRST+1) - ILPNT CALL MMPY ( KLEN, NKCOLS, NCOLUP, & SPLIT(FKCOL), XLNZ(FKCOL), & LNZ, LNZ(ILPNT), ILEN ) C ELSE C C ------------------------------- C GENERAL SPARSE CMOD(JSUP,KSUP). C COMPUTE CMOD(JSUP,KSUP) UPDATE C IN WORK STORAGE. C ------------------------------- STORE = KLEN * NCOLUP - NCOLUP * & (NCOLUP-1) / 2 IF ( STORE .GT. TMPSIZ ) THEN IFLAG = -2 RETURN ENDIF CALL MMPY ( KLEN, NKCOLS, NCOLUP, & SPLIT(FKCOL), XLNZ(FKCOL), & LNZ, TEMP, KLEN ) C ---------------------------------------- C GATHER INDICES OF KSUP RELATIVE TO JSUP. C ---------------------------------------- CALL IGATHR ( KLEN, LINDX(KXPNT), & INDMAP, RELIND ) C -------------------------------------- C INCORPORATE THE CMOD(JSUP,KSUP) BLOCK C UPDATE INTO THE TO APPROPRIATE COLUMNS C OF L. C -------------------------------------- CALL ASSMB ( KLEN, NCOLUP, TEMP, RELIND, & XLNZ(FJCOL), LNZ, JLEN ) C ENDIF C ENDIF C ELSE C C ---------------------------------------------- C DENSE CMOD(JSUP,KSUP). C JSUP AND KSUP HAVE IDENTICAL STRUCTURE. C C JLPNT ... POINTER TO FIRST NONZERO IN COLUMN C FJCOL. C ---------------------------------------------- JLPNT = XLNZ(FJCOL) CALL MMPY ( KLEN, NKCOLS, NJCOLS, SPLIT(FKCOL), & XLNZ(FKCOL), LNZ, LNZ(JLPNT), JLEN) NCOLUP = NJCOLS IF ( KLEN .GT. NJCOLS ) THEN NXTCOL = LINDX(JXPNT+NJCOLS) ENDIF C ENDIF C C ------------------------------------------------ C LINK KSUP INTO LINKED LIST OF THE NEXT SUPERNODE C IT WILL UPDATE AND DECREMENT KSUP'S ACTIVE C LENGTH. C ------------------------------------------------ IF ( KLEN .GT. NCOLUP ) THEN NXTSUP = SNODE(NXTCOL) LINK(KSUP) = LINK(NXTSUP) LINK(NXTSUP) = KSUP LENGTH(KSUP) = KLEN - NCOLUP ELSE LENGTH(KSUP) = 0 ENDIF C C ------------------------------- C NEXT UPDATING SUPERNODE (KSUP). C ------------------------------- KSUP = NXKSUP GO TO 300 C ENDIF C C ---------------------------------------------- C APPLY PARTIAL CHOLESKY TO THE COLUMNS OF JSUP. C ---------------------------------------------- CxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPC CALL CHLSUP ( JLEN, NJCOLS, SPLIT(FJCOL), XLNZ(FJCOL), LNZ, & MXDIAG, NTINY) c & MXDIAG, NTINY, IFLAG ) IF ( IFLAG .NE. 0 ) THEN IFLAG = -1 RETURN ENDIF C C ----------------------------------------------- C INSERT JSUP INTO LINKED LIST OF FIRST SUPERNODE C IT WILL UPDATE. C ----------------------------------------------- IF ( JLEN .GT. NJCOLS ) THEN NXTCOL = LINDX(JXPNT+NJCOLS) NXTSUP = SNODE(NXTCOL) LINK(JSUP) = LINK(NXTSUP) LINK(NXTSUP) = JSUP LENGTH(JSUP) = JLEN - NJCOLS ELSE LENGTH(JSUP) = 0 ENDIF C 600 CONTINUE C CxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPC C IF(NTINY .NE. 0) WRITE(6,699) NTINY C 699 FORMAT(1X,' FOUND ',I6,' TINY DIAGONALS; REPLACED WITH INF') C C SET IFLAG TO -1 TO INDICATE PRESENCE OF TINY DIAGONALS C IF(NTINY .NE. 0) IFLAG = -1 CxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPC RETURN END C*********************************************************************** C*********************************************************************** C C Written: October 6, 1996 by SJW. Based on routine BLKSLV of C Esmond G. Ng and Barry W. Peyton. C C Modified: Sept 30, 1999 to improve efficiency in the case C in which the right-hand side and solution are both C expected to be sparse. Happens a lot in "dense" C column handling. C C*********************************************************************** C*********************************************************************** C********* BLKSLB ... BACK TRIANGULAR SUBSTITUTION ********** C*********************************************************************** C*********************************************************************** C C PURPOSE: C GIVEN THE CHOLESKY FACTORIZATION OF A SPARSE SYMMETRIC C POSITIVE DEFINITE MATRIX, THIS SUBROUTINE PERFORMS THE C BACKWARD TRIANGULAR SUBSTITUTION. IT USES OUTPUT FROM BLKFCT. C C INPUT PARAMETERS: C NSUPER - NUMBER OF SUPERNODES. C XSUPER - SUPERNODE PARTITION. C (XLINDX,LINDX) - ROW INDICES FOR EACH SUPERNODE. C (XLNZ,LNZ) - CHOLESKY FACTOR. C C UPDATED PARAMETERS: C RHS - ON INPUT, CONTAINS THE RIGHT HAND SIDE. ON C OUTPUT, CONTAINS THE SOLUTION. C C*********************************************************************** C SUBROUTINE BLKSLB ( NSUPER, XSUPER, XLINDX, LINDX , XLNZ , & LNZ , RHS ) C C*********************************************************************** implicit none C INTEGER NSUPER INTEGER LINDX(*) , XSUPER(*) INTEGER XLINDX(*) , XLNZ(*) DOUBLE PRECISION LNZ(*) , RHS(*) C C*********************************************************************** C INTEGER FJCOL , I , IPNT , IX , IXSTOP, & IXSTRT, JCOL , JPNT , JSUP , LJCOL DOUBLE PRECISION T C C*********************************************************************** C IF ( NSUPER .LE. 0 ) RETURN C ------------------------- C BACKWARD SUBSTITUTION ... C ------------------------- LJCOL = XSUPER(NSUPER+1) - 1 DO 600 JSUP = NSUPER, 1, -1 FJCOL = XSUPER(JSUP) IXSTOP = XLNZ(LJCOL+1) - 1 JPNT = XLINDX(JSUP) + (LJCOL - FJCOL) DO 500 JCOL = LJCOL, FJCOL, -1 IXSTRT = XLNZ(JCOL) IPNT = JPNT + 1 T = RHS(JCOL) CDIR$ IVDEP DO 400 IX = IXSTRT+1, IXSTOP I = LINDX(IPNT) IF (abs(RHS(I)) .GT. 0.D0) T = T - LNZ(IX)*RHS(I) IPNT = IPNT + 1 400 CONTINUE IF(abs(T) .GT. 0.D0) THEN RHS(JCOL) = T/LNZ(IXSTRT) ELSE RHS(JCOL) = 0.D0 ENDIF IXSTOP = IXSTRT - 1 JPNT = JPNT - 1 500 CONTINUE LJCOL = FJCOL - 1 600 CONTINUE C RETURN END C*********************************************************************** C*********************************************************************** C C Written: October 6, 1996 by SJW. Based on routine BLKSLV of C Esmond G. Ng and Barry W. Peyton. C C Modified: Sept 30, 1999 to improve efficiency in the case C in which the right-hand side and solution are both C expected to be sparse. Happens a lot in "dense" C column handling. C C*********************************************************************** C*********************************************************************** C********* BLKSLF ... FORWARD TRIANGULAR SUBSTITUTION ********** C*********************************************************************** C*********************************************************************** C C PURPOSE: C GIVEN THE CHOLESKY FACTORIZATION OF A SPARSE SYMMETRIC C POSITIVE DEFINITE MATRIX, THIS SUBROUTINE PERFORMS THE C FORWARD TRIANGULAR SUBSTITUTIOn. IT USES OUTPUT FROM BLKFCT. C C INPUT PARAMETERS: C NSUPER - NUMBER OF SUPERNODES. C XSUPER - SUPERNODE PARTITION. C (XLINDX,LINDX) - ROW INDICES FOR EACH SUPERNODE. C (XLNZ,LNZ) - CHOLESKY FACTOR. C C UPDATED PARAMETERS: C RHS - ON INPUT, CONTAINS THE RIGHT HAND SIDE. ON C OUTPUT, CONTAINS THE SOLUTION. C C*********************************************************************** C SUBROUTINE BLKSLF ( NSUPER, XSUPER, XLINDX, LINDX , XLNZ , & LNZ , RHS ) C C*********************************************************************** C implicit none INTEGER NSUPER INTEGER LINDX(*) , XSUPER(*) INTEGER XLINDX(*) , XLNZ(*) DOUBLE PRECISION LNZ(*) , RHS(*) C C*********************************************************************** C INTEGER FJCOL , I , IPNT , IX , IXSTOP, & IXSTRT, JCOL , JPNT , JSUP , LJCOL DOUBLE PRECISION T C C*********************************************************************** C IF ( NSUPER .LE. 0 ) RETURN C C ------------------------ C FORWARD SUBSTITUTION ... C ------------------------ FJCOL = XSUPER(1) DO 300 JSUP = 1, NSUPER LJCOL = XSUPER(JSUP+1) - 1 IXSTRT = XLNZ(FJCOL) JPNT = XLINDX(JSUP) DO 200 JCOL = FJCOL, LJCOL IXSTOP = XLNZ(JCOL+1) - 1 IF (abs(RHS(JCOL)) .GT. 0.D0) THEN T = RHS(JCOL)/LNZ(IXSTRT) RHS(JCOL) = T IPNT = JPNT + 1 CDIR$ IVDEP DO 100 IX = IXSTRT+1, IXSTOP I = LINDX(IPNT) RHS(I) = RHS(I) - T*LNZ(IX) IPNT = IPNT + 1 100 CONTINUE ENDIF IXSTRT = IXSTOP + 1 JPNT = JPNT + 1 200 CONTINUE FJCOL = LJCOL + 1 300 CONTINUE C RETURN END C*********************************************************************** C*********************************************************************** C C Version: 0.4 C Last modified: December 27, 1994 C Authors: Esmond G. Ng and Barry W. Peyton C C Mathematical Sciences Section, Oak Ridge National Laboratory C C Modified: Sept 30, 1999 to improve efficiency in the case C in which the right-hand side and solution are both C expected to be sparse. Happens a lot in "dense" C column handling. C C*********************************************************************** C*********************************************************************** C********* BLKSLV ... BLOCK TRIANGULAR SOLUTIONS ********** C*********************************************************************** C*********************************************************************** C C PURPOSE: C GIVEN THE CHOLESKY FACTORIZATION OF A SPARSE SYMMETRIC C POSITIVE DEFINITE MATRIX, THIS SUBROUTINE PERFORMS THE C TRIANGULAR SOLUTION. IT USES OUTPUT FROM BLKFCT. C C INPUT PARAMETERS: C NSUPER - NUMBER OF SUPERNODES. C XSUPER - SUPERNODE PARTITION. C (XLINDX,LINDX) - ROW INDICES FOR EACH SUPERNODE. C (XLNZ,LNZ) - CHOLESKY FACTOR. C C UPDATED PARAMETERS: C RHS - ON INPUT, CONTAINS THE RIGHT HAND SIDE. ON C OUTPUT, CONTAINS THE SOLUTION. C C*********************************************************************** C SUBROUTINE BLKSLV ( NSUPER, XSUPER, XLINDX, LINDX , XLNZ , & LNZ , RHS ) C C*********************************************************************** C implicit none INTEGER NSUPER INTEGER LINDX(*) , XSUPER(*) INTEGER XLINDX(*) , XLNZ(*) DOUBLE PRECISION LNZ(*) , RHS(*) C C*********************************************************************** C INTEGER FJCOL , I , IPNT , IX , IXSTOP, & IXSTRT, JCOL , JPNT , JSUP , LJCOL DOUBLE PRECISION T C C*********************************************************************** C IF ( NSUPER .LE. 0 ) RETURN C C ------------------------ C FORWARD SUBSTITUTION ... C ------------------------ FJCOL = XSUPER(1) DO 300 JSUP = 1, NSUPER LJCOL = XSUPER(JSUP+1) - 1 IXSTRT = XLNZ(FJCOL) JPNT = XLINDX(JSUP) DO 200 JCOL = FJCOL, LJCOL IXSTOP = XLNZ(JCOL+1) - 1 IF (abs(RHS(JCOL)) .GT. 0.D0) THEN T = RHS(JCOL)/LNZ(IXSTRT) RHS(JCOL) = T IPNT = JPNT + 1 CDIR$ IVDEP DO 100 IX = IXSTRT+1, IXSTOP I = LINDX(IPNT) RHS(I) = RHS(I) - T*LNZ(IX) IPNT = IPNT + 1 100 CONTINUE ENDIF IXSTRT = IXSTOP + 1 JPNT = JPNT + 1 200 CONTINUE FJCOL = LJCOL + 1 300 CONTINUE C C ------------------------- C BACKWARD SUBSTITUTION ... C ------------------------- LJCOL = XSUPER(NSUPER+1) - 1 DO 600 JSUP = NSUPER, 1, -1 FJCOL = XSUPER(JSUP) IXSTOP = XLNZ(LJCOL+1) - 1 JPNT = XLINDX(JSUP) + (LJCOL - FJCOL) DO 500 JCOL = LJCOL, FJCOL, -1 IXSTRT = XLNZ(JCOL) IPNT = JPNT + 1 T = RHS(JCOL) CDIR$ IVDEP DO 400 IX = IXSTRT+1, IXSTOP I = LINDX(IPNT) IF(abs(RHS(I)) .GT. 0.D0) T = T - LNZ(IX)*RHS(I) IPNT = IPNT + 1 400 CONTINUE IF (abs(T) .GT. 0.D0) THEN RHS(JCOL) = T/LNZ(IXSTRT) ELSE RHS(JCOL) = 0.D0 ENDIF IXSTOP = IXSTRT - 1 JPNT = JPNT - 1 500 CONTINUE LJCOL = FJCOL - 1 600 CONTINUE C RETURN END C*********************************************************************** C*********************************************************************** C C Version: 0.4 C Last modified: January 12, 1995 C Authors: Esmond G. Ng and Barry W. Peyton C C Mathematical Sciences Section, Oak Ridge National Laboratory C C*********************************************************************** C*********************************************************************** C****** BTREE2 ..... BINARY TREE REPRESENTATION OF ETREE ******* C*********************************************************************** C*********************************************************************** C C PURPOSE: C TO DETERMINE A BINARY TREE REPRESENTATION OF THE ELIMINATION C TREE, FOR WHICH EVERY "LAST CHILD" HAS THE MAXIMUM POSSIBLE C COLUMN NONZERO COUNT IN THE FACTOR. THE RETURNED REPRESENTATION C WILL BE GIVEN BY THE FIRST-SON AND BROTHER VECTORS. THE ROOT OF C THE BINARY TREE IS ALWAYS NEQNS. C C INPUT PARAMETERS: C NEQNS - NUMBER OF EQUATIONS. C PARENT - THE PARENT VECTOR OF THE ELIMINATION TREE. C IT IS ASSUMED THAT PARENT(I) > I EXCEPT OF C THE ROOTS. C COLCNT - COLUMN NONZERO COUNTS OF THE FACTOR. C C OUTPUT PARAMETERS: C FSON - THE FIRST SON VECTOR. C BROTHR - THE BROTHER VECTOR. C C WORKING PARAMETERS: C LSON - LAST SON VECTOR. C C*********************************************************************** C SUBROUTINE BTREE2 ( NEQNS , PARENT, COLCNT, FSON , BROTHR, & LSON ) C implicit none C*********************************************************************** C INTEGER BROTHR(*) , COLCNT(*) , & FSON(*) , LSON(*) , & PARENT(*) C INTEGER NEQNS C C*********************************************************************** C INTEGER LROOT , NODE , NDLSON, NDPAR C C*********************************************************************** C IF ( NEQNS .LE. 0 ) RETURN C DO 100 NODE = 1, NEQNS FSON(NODE) = 0 BROTHR(NODE) = 0 LSON(NODE) = 0 100 CONTINUE LROOT = NEQNS C ------------------------------------------------------------ C FOR EACH NODE := NEQNS-1 STEP -1 DOWNTO 1, DO THE FOLLOWING. C ------------------------------------------------------------ IF ( NEQNS .LE. 1 ) RETURN DO 300 NODE = NEQNS-1, 1, -1 NDPAR = PARENT(NODE) IF ( NDPAR .LE. 0 .OR. NDPAR .EQ. NODE ) THEN C ------------------------------------------------- C NODE HAS NO PARENT. GIVEN STRUCTURE IS A FOREST. C SET NODE TO BE ONE OF THE ROOTS OF THE TREES. C ------------------------------------------------- BROTHR(LROOT) = NODE LROOT = NODE ELSE C ------------------------------------------- C OTHERWISE, BECOMES FIRST SON OF ITS PARENT. C ------------------------------------------- NDLSON = LSON(NDPAR) IF ( NDLSON .NE. 0 ) THEN IF ( COLCNT(NODE) .GE. COLCNT(NDLSON) ) THEN BROTHR(NODE) = FSON(NDPAR) FSON(NDPAR) = NODE ELSE BROTHR(NDLSON) = NODE LSON(NDPAR) = NODE ENDIF ELSE FSON(NDPAR) = NODE LSON(NDPAR) = NODE ENDIF ENDIF 300 CONTINUE BROTHR(LROOT) = 0 C RETURN END C*********************************************************************** C*********************************************************************** C C Version: 0.3 C Last modified: December 27, 1994 C Authors: Esmond G. Ng and Barry W. Peyton C C Modified by RF: Eliminated the MMPYN, SMXPY as arguments C C Mathematical Sciences Section, Oak Ridge National Laboratoy C C*********************************************************************** C*********************************************************************** C****** CHLSUP .... DENSE CHOLESKY WITHIN SUPERNODE ************** C*********************************************************************** C*********************************************************************** C C PURPOSE - THIS ROUTINE PERFORMS CHOLESKY C FACTORIZATION ON THE COLUMNS OF A SUPERNODE C THAT HAVE RECEIVED ALL UPDATES FROM COLUMNS C EXTERNAL TO THE SUPERNODE. C C INPUT PARAMETERS - C M - NUMBER OF ROWS (LENGTH OF THE FIRST COLUMN). C N - NUMBER OF COLUMNS IN THE SUPERNODE. C XPNT - XPNT(J+1) POINTS ONE LOCATION BEYOND THE END C OF THE J-TH COLUMN OF THE SUPERNODE. C X(*) - CONTAINS THE COLUMNS OF OF THE SUPERNODE TO C BE FACTORED. C C EXTERNAL ROUTINES - C MMPY8 - MATRIX-MATRIX MULTIPLY WITH 8 LOOP UNROLLING. C C OUTPUT PARAMETERS - C X(*) - ON OUTPUT, CONTAINS THE FACTORED COLUMNS OF C THE SUPERNODE. C IFLAG - UNCHANGED IF THERE IS NO ERROR. C =1 IF NONPOSITIVE DIAGONAL ENTRY IS ENCOUNTERED. c RF: removed! C C*********************************************************************** C SUBROUTINE CHLSUP ( M, N, SPLIT, XPNT, X, MXDIAG, NTINY) c & IFLAG ) C C*********************************************************************** C implicit none C ----------- C PARAMETERS. C ----------- C EXTERNAL MMPY8 C INTEGER M, N C INTEGER XPNT(*), SPLIT(*) C DOUBLE PRECISION X(*), MXDIAG INTEGER NTINY C C ---------------- C LOCAL VARIABLES. C ---------------- C INTEGER FSTCOL, JBLK , JPNT , MM , NN , & NXTCOL, Q C C*********************************************************************** C JBLK = 0 FSTCOL = 1 MM = M JPNT = XPNT(FSTCOL) C C ---------------------------------------- C FOR EACH BLOCK JBLK IN THE SUPERNODE ... C ---------------------------------------- 100 CONTINUE IF ( FSTCOL .LE. N ) THEN JBLK = JBLK + 1 NN = SPLIT(JBLK) C ------------------------------------------ C ... PERFORM PARTIAL CHOLESKY FACTORIZATION C ON THE BLOCK. C ------------------------------------------ CALL PCHOL ( MM, NN, XPNT(FSTCOL), X, MXDIAG, NTINY) C ---------------------------------------------- C ... APPLY THE COLUMNS IN JBLK TO ANY COLUMNS C OF THE SUPERNODE REMAINING TO BE COMPUTED. C ---------------------------------------------- NXTCOL = FSTCOL + NN Q = N - NXTCOL + 1 MM = MM - NN JPNT = XPNT(NXTCOL) IF ( Q .GT. 0 ) THEN CALL MMPY8( MM, NN, Q, XPNT(FSTCOL), X, X(JPNT), MM ) ENDIF FSTCOL = NXTCOL GO TO 100 ENDIF C RETURN END C*********************************************************************** C*********************************************************************** C C Version: 0.4 C Last modified: December 27, 1994 C Authors: Esmond G. Ng and Barry W. Peyton C C Mathematical Sciences Section, Oak Ridge National Laboratory C C*********************************************************************** C*********************************************************************** C********** CHORDR ..... CHILD REORDERING *********** C*********************************************************************** C*********************************************************************** C C PURPOSE: C REARRANGE THE CHILDREN OF EACH VERTEX SO THAT THE LAST ONE C MAXIMIZES (AMONG THE CHILDREN) THE NUMBER OF NONZEROS IN THE C CORRESPONDING COLUMN OF L. ALSO DETERMINE AN NEW POSTORDERING C BASED ON THE STRUCTURE OF THE MODIFIED ELIMINATION TREE. C C INPUT PARAMETERS: C NEQNS - NUMBER OF EQUATIONS. C C UPDATED PARAMETERS: C (PERM,INVP) - ON INPUT, THE GIVEN PERM AND INVERSE PERM C VECTORS. ON OUTPUT, THE NEW PERM AND C INVERSE PERM VECTORS OF THE NEW C POSTORDERING. C COLCNT - COLUMN COUNTS IN L UNDER INITIAL ORDERING; C MODIFIED TO REFLECT THE NEW ORDERING. C C OUTPUT PARAMETERS: C PARENT - THE PARENT VECTOR OF THE ELIMINATION TREE C ASSOCIATED WITH THE NEW ORDERING. C C WORKING PARAMETERS: C FSON - THE FIRST SON VECTOR. C BROTHR - THE BROTHER VECTOR. C INVPOS - THE INVERSE PERM VECTOR FOR THE C POSTORDERING. C C PROGRAM SUBROUTINES: C BTREE2, EPOST2, INVINV. C C*********************************************************************** C SUBROUTINE CHORDR ( NEQNS , PERM , INVP , & COLCNT, PARENT, FSON , BROTHR, INVPOS ) C C*********************************************************************** C INTEGER BROTHR(*) , & COLCNT(*) , FSON(*) , & INVP(*) , INVPOS(*) , & PARENT(*) , PERM(*) C INTEGER NEQNS C C*********************************************************************** C C ---------------------------------------------------------- C COMPUTE A BINARY REPRESENTATION OF THE ELIMINATION TREE, C SO THAT EACH "LAST CHILD" MAXIMIZES AMONG ITS SIBLINGS THE C NUMBER OF NONZEROS IN THE CORRESPONDING COLUMNS OF L. C ---------------------------------------------------------- CALL BTREE2 ( NEQNS , PARENT, COLCNT, FSON , BROTHR, & INVPOS ) C C ---------------------------------------------------- C POSTORDER THE ELIMINATION TREE (USING THE NEW BINARY C REPRESENTATION. C ---------------------------------------------------- CALL EPOST2 ( NEQNS , FSON , BROTHR, INVPOS, PARENT, & COLCNT, PERM ) C C -------------------------------------------------------- C COMPOSE THE ORIGINAL ORDERING WITH THE NEW POSTORDERING. C -------------------------------------------------------- CALL INVINV ( NEQNS , INVP , INVPOS, PERM ) C RETURN END C*********************************************************************** C*********************************************************************** C C Version: 0.4 C Last modified: December 27, 1994 C Authors: Esmond G. Ng and Barry W. Peyton C C Mathematical Sciences Section, Oak Ridge National Laboratory C C*********************************************************************** C*********************************************************************** C****** DSCAL1 .... SCALE A VECTOR ************** C*********************************************************************** C*********************************************************************** C C PURPOSE - THIS ROUTINE COMPUTES A <-- AX, WHERE A IS A C SCALAR AND X IS A VECTOR. C C INPUT PARAMETERS - C N - LENGTH OF THE VECTOR X. C A - SCALAR MULIPLIER. C X - VECTOR TO BE SCALED. C C OUTPUT PARAMETERS - C X - REPLACED BY THE SCALED VECTOR, AX. C C*********************************************************************** C SUBROUTINE DSCAL1 ( N, A, X ) C C*********************************************************************** C C ----------- C PARAMETERS. C ----------- INTEGER N DOUBLE PRECISION A, X(N) C C ---------------- C LOCAL VARIABLES. C ---------------- INTEGER I C C*********************************************************************** C DO 100 I = 1, N X(I) = A * X(I) 100 CONTINUE RETURN END C*********************************************************************** C*********************************************************************** C C Version: 0.4 C Last modified: December 27, 1994 C Authors: Esmond G. Ng and Barry W. Peyton C C Mathematical Sciences Section, Oak Ridge National Laboratory C C*********************************************************************** C*********************************************************************** C*************** EPOST2 ..... ETREE POSTORDERING #2 *************** C*********************************************************************** C*********************************************************************** C C PURPOSE: C BASED ON THE BINARY REPRESENTATION (FIRST-SON,BROTHER) OF THE C ELIMINATION TREE, A POSTORDERING IS DETERMINED. THE C CORRESPONDING PARENT AND COLCNT VECTORS ARE ALSO MODIFIED TO C REFLECT THE REORDERING. C C INPUT PARAMETERS: C ROOT - ROOT OF THE ELIMINATION TREE (USUALLY IT C IS NEQNS). C FSON - THE FIRST SON VECTOR. C BROTHR - THE BROTHR VECTOR. C C UPDATED PARAMETERS: C PARENT - THE PARENT VECTOR. C COLCNT - COLUMN NONZERO COUNTS OF THE FACTOR. C C OUTPUT PARAMETERS: C INVPOS - INVERSE PERMUTATION FOR THE POSTORDERING. C C WORKING PARAMETERS: C STACK - THE STACK FOR POSTORDER TRAVERSAL OF THE C TREE. C C*********************************************************************** C SUBROUTINE EPOST2 ( ROOT , FSON , BROTHR, INVPOS, PARENT, & COLCNT, STACK ) C C*********************************************************************** C INTEGER BROTHR(*) , COLCNT(*) , & FSON(*) , INVPOS(*) , & PARENT(*) , STACK(*) C INTEGER ROOT C C*********************************************************************** C INTEGER ITOP , NDPAR , NODE , NUM , NUNODE C C*********************************************************************** C NUM = 0 ITOP = 0 NODE = ROOT C ------------------------------------------------------------- C TRAVERSE ALONG THE FIRST SONS POINTER AND PUSH THE TREE NODES C ALONG THE TRAVERSAL INTO THE STACK. C ------------------------------------------------------------- 100 CONTINUE ITOP = ITOP + 1 STACK(ITOP) = NODE NODE = FSON(NODE) IF ( NODE .GT. 0 ) GO TO 100 C ---------------------------------------------------------- C IF POSSIBLE, POP A TREE NODE FROM THE STACK AND NUMBER IT. C ---------------------------------------------------------- 200 CONTINUE IF ( ITOP .LE. 0 ) GO TO 300 NODE = STACK(ITOP) ITOP = ITOP - 1 NUM = NUM + 1 INVPOS(NODE) = NUM C ---------------------------------------------------- C THEN, TRAVERSE TO ITS YOUNGER BROTHER IF IT HAS ONE. C ---------------------------------------------------- NODE = BROTHR(NODE) IF ( NODE .LE. 0 ) GO TO 200 GO TO 100 C 300 CONTINUE C ------------------------------------------------------------ C DETERMINE THE NEW PARENT VECTOR OF THE POSTORDERING. BROTHR C IS USED TEMPORARILY FOR THE NEW PARENT VECTOR. C ------------------------------------------------------------ DO 400 NODE = 1, NUM NUNODE = INVPOS(NODE) NDPAR = PARENT(NODE) IF ( NDPAR .GT. 0 ) NDPAR = INVPOS(NDPAR) BROTHR(NUNODE) = NDPAR 400 CONTINUE C DO 500 NUNODE = 1, NUM PARENT(NUNODE) = BROTHR(NUNODE) 500 CONTINUE C C ---------------------------------------------- C PERMUTE COLCNT(*) TO REFLECT THE NEW ORDERING. C ---------------------------------------------- DO 600 NODE = 1, NUM NUNODE = INVPOS(NODE) STACK(NUNODE) = COLCNT(NODE) 600 CONTINUE C DO 700 NODE = 1, NUM COLCNT(NODE) = STACK(NODE) 700 CONTINUE C RETURN END C*********************************************************************** C*********************************************************************** C C Version: 0.4 C Last modified: December 27, 1994 C Authors: Joseph W.H. Liu C C Mathematical Sciences Section, Oak Ridge National Laboratory C C*********************************************************************** C*********************************************************************** C********** ETORDR ..... ELIMINATION TREE REORDERING *********** C*********************************************************************** C*********************************************************************** C C WRITTEN BY JOSEPH LIU (JUL 17, 1985) C C PURPOSE: C TO DETERMINE AN EQUIVALENT REORDERING BASED ON THE STRUCTURE OF C THE ELIMINATION TREE. A POSTORDERING OF THE GIVEN ELIMINATION C TREE IS RETURNED. C C INPUT PARAMETERS: C NEQNS - NUMBER OF EQUATIONS. C (XADJ,ADJNCY) - THE ADJACENCY STRUCTURE. C C UPDATED PARAMETERS: C (PERM,INVP) - ON INPUT, THE GIVEN PERM AND INVERSE PERM C VECTORS. ON OUTPUT, THE NEW PERM AND C INVERSE PERM VECTORS OF THE EQUIVALENT C ORDERING. C C OUTPUT PARAMETERS: C PARENT - THE PARENT VECTOR OF THE ELIMINATION TREE C ASSOCIATED WITH THE NEW ORDERING. C C WORKING PARAMETERS: C FSON - THE FIRST SON VECTOR. C BROTHR - THE BROTHER VECTOR. C INVPOS - THE INVERSE PERM VECTOR FOR THE C POSTORDERING. C C PROGRAM SUBROUTINES: C BETREE, ETPOST, ETREE , INVINV. C C*********************************************************************** C SUBROUTINE ETORDR ( NEQNS , XADJ , ADJNCY, PERM , INVP , & PARENT, FSON , BROTHR, INVPOS ) C C*********************************************************************** C INTEGER ADJNCY(*) , BROTHR(*) , & FSON(*) , INVP(*) , & INVPOS(*) , PARENT(*) , & PERM(*) C INTEGER XADJ(*) INTEGER NEQNS C C*********************************************************************** C C ----------------------------- C COMPUTE THE ELIMINATION TREE. C ----------------------------- CALL ETREE ( NEQNS, XADJ, ADJNCY, PERM, INVP, PARENT, INVPOS ) C C -------------------------------------------------------- C COMPUTE A BINARY REPRESENTATION OF THE ELIMINATION TREE. C -------------------------------------------------------- CALL BETREE ( NEQNS, PARENT, FSON, BROTHR ) C C ------------------------------- C POSTORDER THE ELIMINATION TREE. C ------------------------------- CALL ETPOST ( NEQNS, FSON, BROTHR, INVPOS, PARENT, PERM ) C C -------------------------------------------------------- C COMPOSE THE ORIGINAL ORDERING WITH THE NEW POSTORDERING. C -------------------------------------------------------- CALL INVINV ( NEQNS, INVP, INVPOS, PERM ) C RETURN END C*********************************************************************** C*********************************************************************** C C Version: 0.4 C Last modified: December 27, 1994 C Authors: Joseph W.H. Liu C C Mathematical Sciences Section, Oak Ridge National Laboratory C C*********************************************************************** C*********************************************************************** C*************** ETPOST ..... ETREE POSTORDERING *************** C*********************************************************************** C*********************************************************************** C C WRITTEN BY JOSEPH LIU (SEPT 17, 1986) C C PURPOSE: C BASED ON THE BINARY REPRESENTATION (FIRST-SON,BROTHER) OF C THE ELIMINATION TREE, A POSTORDERING IS DETERMINED. THE C CORRESPONDING PARENT VECTOR IS ALSO MODIFIED TO REFLECT C THE REORDERING. C C INPUT PARAMETERS: C ROOT - ROOT OF THE ELIMINATION TREE (USUALLY IT C IS NEQNS). C FSON - THE FIRST SON VECTOR. C BROTHR - THE BROTHR VECTOR. C C UPDATED PARAMETERS: C PARENT - THE PARENT VECTOR. C C OUTPUT PARAMETERS: C INVPOS - INVERSE PERMUTATION FOR THE POSTORDERING. C C WORKING PARAMETERS: C STACK - THE STACK FOR POSTORDER TRAVERSAL OF THE C TREE. C C*********************************************************************** C SUBROUTINE ETPOST ( ROOT , FSON , BROTHR, INVPOS, PARENT, & STACK ) C C*********************************************************************** C INTEGER BROTHR(*) , FSON(*) , & INVPOS(*) , PARENT(*) , & STACK(*) C INTEGER ROOT C C*********************************************************************** C INTEGER ITOP , NDPAR , NODE , NUM , NUNODE C C*********************************************************************** C NUM = 0 ITOP = 0 NODE = ROOT C ------------------------------------------------------------- C TRAVERSE ALONG THE FIRST SONS POINTER AND PUSH THE TREE NODES C ALONG THE TRAVERSAL INTO THE STACK. C ------------------------------------------------------------- 100 CONTINUE ITOP = ITOP + 1 STACK(ITOP) = NODE NODE = FSON(NODE) IF ( NODE .GT. 0 ) GO TO 100 C ---------------------------------------------------------- C IF POSSIBLE, POP A TREE NODE FROM THE STACK AND NUMBER IT. C ---------------------------------------------------------- 200 CONTINUE IF ( ITOP .LE. 0 ) GO TO 300 NODE = STACK(ITOP) ITOP = ITOP - 1 NUM = NUM + 1 INVPOS(NODE) = NUM C ---------------------------------------------------- C THEN, TRAVERSE TO ITS YOUNGER BROTHER IF IT HAS ONE. C ---------------------------------------------------- NODE = BROTHR(NODE) IF ( NODE .LE. 0 ) GO TO 200 GO TO 100 C 300 CONTINUE C ------------------------------------------------------------ C DETERMINE THE NEW PARENT VECTOR OF THE POSTORDERING. BROTHR C IS USED TEMPORARILY FOR THE NEW PARENT VECTOR. C ------------------------------------------------------------ DO 400 NODE = 1, NUM NUNODE = INVPOS(NODE) NDPAR = PARENT(NODE) IF ( NDPAR .GT. 0 ) NDPAR = INVPOS(NDPAR) BROTHR(NUNODE) = NDPAR 400 CONTINUE C DO 500 NUNODE = 1, NUM PARENT(NUNODE) = BROTHR(NUNODE) 500 CONTINUE C RETURN END C*********************************************************************** C*********************************************************************** C C Version: 0.4 C Last modified: December 27, 1994 C Authors: Joseph W.H. Liu C C Mathematical Sciences Section, Oak Ridge National Laboratory C C*********************************************************************** C*********************************************************************** C**************** ETREE ..... ELIMINATION TREE ***************** C*********************************************************************** C*********************************************************************** C C WRITTEN BY JOSEPH LIU (JUL 17, 1985) C C PURPOSE: C TO DETERMINE THE ELIMINATION TREE FROM A GIVEN ORDERING AND C THE ADJACENCY STRUCTURE. THE PARENT VECTOR IS RETURNED. C C INPUT PARAMETERS: C NEQNS - NUMBER OF EQUATIONS. C (XADJ,ADJNCY) - THE ADJACENCY STRUCTURE. C (PERM,INVP) - PERMUTATION AND INVERSE PERMUTATION VECTORS C C OUTPUT PARAMETERS: C PARENT - THE PARENT VECTOR OF THE ELIMINATION TREE. C C WORKING PARAMETERS: C ANCSTR - THE ANCESTOR VECTOR. C C*********************************************************************** C SUBROUTINE ETREE ( NEQNS , XADJ , ADJNCY, PERM , INVP , & PARENT, ANCSTR ) C C*********************************************************************** C INTEGER ADJNCY(*) , ANCSTR(*) , & INVP(*) , PARENT(*) , & PERM(*) C INTEGER NEQNS INTEGER XADJ(*) C C*********************************************************************** C INTEGER I , J , JSTOP , JSTRT , NBR , & NEXT , NODE C C*********************************************************************** C IF ( NEQNS .LE. 0 ) RETURN C DO 400 I = 1, NEQNS PARENT(I) = 0 ANCSTR(I) = 0 NODE = PERM(I) C JSTRT = XADJ(NODE) JSTOP = XADJ(NODE+1) - 1 IF ( JSTRT .LE. JSTOP ) THEN DO 300 J = JSTRT, JSTOP NBR = ADJNCY(J) NBR = INVP(NBR) IF ( NBR .LT. I ) THEN C ------------------------------------------- C FOR EACH NBR, FIND THE ROOT OF ITS CURRENT C ELIMINATION TREE. PERFORM PATH COMPRESSION C AS THE SUBTREE IS TRAVERSED. C ------------------------------------------- 100 CONTINUE IF ( ANCSTR(NBR) .EQ. I ) GO TO 300 IF ( ANCSTR(NBR) .GT. 0 ) THEN NEXT = ANCSTR(NBR) ANCSTR(NBR) = I NBR = NEXT GO TO 100 ENDIF C -------------------------------------------- C NOW, NBR IS THE ROOT OF THE SUBTREE. MAKE I C THE PARENT NODE OF THIS ROOT. C -------------------------------------------- PARENT(NBR) = I ANCSTR(NBR) = I ENDIF 300 CONTINUE ENDIF 400 CONTINUE C RETURN END C*********************************************************************** C*********************************************************************** C C Version: 0.4 C Last modified: January 12, 1995 C Authors: Esmond G. Ng and Barry W. Peyton C C Mathematical Sciences Section, Oak Ridge National Laboratory C C*********************************************************************** C*********************************************************************** C************** FCNTHN ..... FIND NONZERO COUNTS *************** C*********************************************************************** C*********************************************************************** C C PURPOSE: C THIS SUBROUTINE DETERMINES THE ROW COUNTS AND COLUMN COUNTS IN C THE CHOLESKY FACTOR. IT USES A DISJOINT SET UNION ALGORITHM. C C TECHNIQUES: C 1) SUPERNODE DETECTION. C 2) PATH HALVING. C 3) NO UNION BY RANK. C C NOTES: C 1) ASSUMES A POSTORDERING OF THE ELIMINATION TREE. C C INPUT PARAMETERS: C (I) NEQNS - NUMBER OF EQUATIONS. C (I) ADJLEN - LENGTH OF ADJACENCY STRUCTURE. C (I) XADJ(*) - ARRAY OF LENGTH NEQNS+1, CONTAINING POINTERS C TO THE ADJACENCY STRUCTURE. C (I) ADJNCY(*) - ARRAY OF LENGTH XADJ(NEQNS+1)-1, CONTAINING C THE ADJACENCY STRUCTURE. C (I) PERM(*) - ARRAY OF LENGTH NEQNS, CONTAINING THE C POSTORDERING. C (I) INVP(*) - ARRAY OF LENGTH NEQNS, CONTAINING THE C INVERSE OF THE POSTORDERING. C (I) ETPAR(*) - ARRAY OF LENGTH NEQNS, CONTAINING THE C ELIMINATION TREE OF THE POSTORDERED MATRIX. C C OUTPUT PARAMETERS: C (I) ROWCNT(*) - ARRAY OF LENGTH NEQNS, CONTAINING THE NUMBER C OF NONZEROS IN EACH ROW OF THE FACTOR, C INCLUDING THE DIAGONAL ENTRY. C (I) COLCNT(*) - ARRAY OF LENGTH NEQNS, CONTAINING THE NUMBER C OF NONZEROS IN EACH COLUMN OF THE FACTOR, C INCLUDING THE DIAGONAL ENTRY. C (I) NLNZ - NUMBER OF NONZEROS IN THE FACTOR, INCLUDING C THE DIAGONAL ENTRIES. C C WORK PARAMETERS: C (I) SET(*) - ARRAY OF LENGTH NEQNS USED TO MAINTAIN THE C DISJOINT SETS (I.E., SUBTREES). C (I) PRVLF(*) - ARRAY OF LENGTH NEQNS USED TO RECORD THE C PREVIOUS LEAF OF EACH ROW SUBTREE. C (I) LEVEL(*) - ARRAY OF LENGTH NEQNS+1 CONTAINING THE LEVEL C (DISTANCE FROM THE ROOT). C (I) WEIGHT(*) - ARRAY OF LENGTH NEQNS+1 CONTAINING WEIGHTS C USED TO COMPUTE COLUMN COUNTS. C (I) FDESC(*) - ARRAY OF LENGTH NEQNS+1 CONTAINING THE C FIRST (I.E., LOWEST-NUMBERED) DESCENDANT. C (I) NCHILD(*) - ARRAY OF LENGTH NEQNS+1 CONTAINING THE C NUMBER OF CHILDREN. C (I) PRVNBR(*) - ARRAY OF LENGTH NEQNS USED TO RECORD THE C PREVIOUS ``LOWER NEIGHBOR'' OF EACH NODE. C C FIRST CREATED ON APRIL 12, 1990. C LAST UPDATED ON JANUARY 12, 1995. C C*********************************************************************** C SUBROUTINE FCNTHN ( NEQNS , ADJLEN, XADJ , ADJNCY, PERM , & INVP , ETPAR , ROWCNT, COLCNT, NLNZ , & SET , PRVLF , LEVEL , WEIGHT, FDESC , & NCHILD, PRVNBR ) C C ----------- C PARAMETERS. C ----------- INTEGER ADJLEN, NEQNS , NLNZ INTEGER ADJNCY(ADJLEN) , COLCNT(NEQNS) , & ETPAR(NEQNS) , FDESC(0:NEQNS), & INVP(NEQNS) , LEVEL(0:NEQNS), & NCHILD(0:NEQNS) , PERM(NEQNS) , & PRVLF(NEQNS) , PRVNBR(NEQNS) , & ROWCNT(NEQNS) , SET(NEQNS) , & WEIGHT(0:NEQNS) INTEGER XADJ(*) C C ---------------- C LOCAL VARIABLES. C ---------------- INTEGER HINBR , IFDESC, J , JSTOP , JSTRT , & K , LAST1 , LAST2 , LCA , LFLAG , & LOWNBR, OLDNBR, PARENT, PLEAF , TEMP , & XSUP C C*********************************************************************** C C -------------------------------------------------- C COMPUTE LEVEL(*), FDESC(*), NCHILD(*). C INITIALIZE XSUP, ROWCNT(*), COLCNT(*), C SET(*), PRVLF(*), WEIGHT(*), PRVNBR(*). C -------------------------------------------------- XSUP = 1 LEVEL(0) = 0 DO 100 K = NEQNS, 1, -1 ROWCNT(K) = 1 COLCNT(K) = 0 SET(K) = K PRVLF(K) = 0 LEVEL(K) = LEVEL(ETPAR(K)) + 1 WEIGHT(K) = 1 FDESC(K) = K NCHILD(K) = 0 PRVNBR(K) = 0 100 CONTINUE NCHILD(0) = 0 FDESC(0) = 0 DO 200 K = 1, NEQNS PARENT = ETPAR(K) WEIGHT(PARENT) = 0 NCHILD(PARENT) = NCHILD(PARENT) + 1 IFDESC = FDESC(K) IF ( IFDESC .LT. FDESC(PARENT) ) THEN FDESC(PARENT) = IFDESC ENDIF 200 CONTINUE C ------------------------------------ C FOR EACH ``LOW NEIGHBOR'' LOWNBR ... C ------------------------------------ DO 600 LOWNBR = 1, NEQNS LFLAG = 0 IFDESC = FDESC(LOWNBR) OLDNBR = PERM(LOWNBR) JSTRT = XADJ(OLDNBR) JSTOP = XADJ(OLDNBR+1) - 1 C ----------------------------------------------- C FOR EACH ``HIGH NEIGHBOR'', HINBR OF LOWNBR ... C ----------------------------------------------- DO 500 J = JSTRT, JSTOP HINBR = INVP(ADJNCY(J)) IF ( HINBR .GT. LOWNBR ) THEN IF ( IFDESC .GT. PRVNBR(HINBR) ) THEN C ------------------------- C INCREMENT WEIGHT(LOWNBR). C ------------------------- WEIGHT(LOWNBR) = WEIGHT(LOWNBR) + 1 PLEAF = PRVLF(HINBR) C ----------------------------------------- C IF HINBR HAS NO PREVIOUS ``LOW NEIGHBOR'' C THEN ... C ----------------------------------------- IF ( PLEAF .EQ. 0 ) THEN C ----------------------------------------- C ... ACCUMULATE LOWNBR-->HINBR PATH LENGTH C IN ROWCNT(HINBR). C ----------------------------------------- ROWCNT(HINBR) = ROWCNT(HINBR) + & LEVEL(LOWNBR) - LEVEL(HINBR) ELSE C ----------------------------------------- C ... OTHERWISE, LCA <-- FIND(PLEAF), WHICH C IS THE LEAST COMMON ANCESTOR OF PLEAF C AND LOWNBR. C (PATH HALVING.) C ----------------------------------------- LAST1 = PLEAF LAST2 = SET(LAST1) LCA = SET(LAST2) 300 CONTINUE IF ( LCA .NE. LAST2 ) THEN SET(LAST1) = LCA LAST1 = LCA LAST2 = SET(LAST1) LCA = SET(LAST2) GO TO 300 ENDIF C ------------------------------------- C ACCUMULATE PLEAF-->LCA PATH LENGTH IN C ROWCNT(HINBR). C DECREMENT WEIGHT(LCA). C ------------------------------------- ROWCNT(HINBR) = ROWCNT(HINBR) & + LEVEL(LOWNBR) - LEVEL(LCA) WEIGHT(LCA) = WEIGHT(LCA) - 1 ENDIF C ---------------------------------------------- C LOWNBR NOW BECOMES ``PREVIOUS LEAF'' OF HINBR. C ---------------------------------------------- PRVLF(HINBR) = LOWNBR LFLAG = 1 ENDIF C -------------------------------------------------- C LOWNBR NOW BECOMES ``PREVIOUS NEIGHBOR'' OF HINBR. C -------------------------------------------------- PRVNBR(HINBR) = LOWNBR ENDIF 500 CONTINUE C ---------------------------------------------------- C DECREMENT WEIGHT ( PARENT(LOWNBR) ). C SET ( P(LOWNBR) ) <-- SET ( P(LOWNBR) ) + SET(XSUP). C ---------------------------------------------------- PARENT = ETPAR(LOWNBR) WEIGHT(PARENT) = WEIGHT(PARENT) - 1 IF ( LFLAG .EQ. 1 .OR. & NCHILD(LOWNBR) .GE. 2 ) THEN XSUP = LOWNBR ENDIF SET(XSUP) = PARENT 600 CONTINUE C --------------------------------------------------------- C USE WEIGHTS TO COMPUTE COLUMN (AND TOTAL) NONZERO COUNTS. C --------------------------------------------------------- NLNZ = 0 DO 700 K = 1, NEQNS TEMP = COLCNT(K) + WEIGHT(K) COLCNT(K) = TEMP NLNZ = NLNZ + TEMP PARENT = ETPAR(K) IF ( PARENT .NE. 0 ) THEN COLCNT(PARENT) = COLCNT(PARENT) + TEMP ENDIF 700 CONTINUE C RETURN END C*********************************************************************** C*********************************************************************** C C Version: 0.4 C Last modified: May 26, 1995 C Authors: Esmond G. Ng and Barry W. Peyton C C Mathematical Sciences Section, Oak Ridge National Laboratory C C*********************************************************************** C*********************************************************************** C**** FNSPLT ..... COMPUTE FINE PARTITIONING OF SUPERNODES ***** C*********************************************************************** C*********************************************************************** C C PURPOSE: C THIS SUBROUTINE DETERMINES A FINE PARTITIONING OF SUPERNODES C WHEN THERE IS A CACHE AVAILABLE ON THE MACHINE. THE FINE C PARTITIONING IS CHOSEN SO THAT DATA RE-USE IS MAXIMIZED. C C INPUT PARAMETERS: C NEQNS - NUMBER OF EQUATIONS. C NSUPER - NUMBER OF SUPERNODES. C XSUPER - INTEGER ARRAY OF SIZE (NSUPER+1) CONTAINING C THE SUPERNODE PARTITIONING. C XLINDX - INTEGER ARRAY OF SIZE (NSUPER+1) CONTAINING C POINTERS IN THE SUPERNODE INDICES. C CACHSZ - CACHE SIZE IN KILO BYTES. C IF THERE IS NO CACHE, SET CACHSZ = 0. C C OUTPUT PARAMETERS: C SPLIT - INTEGER ARRAY OF SIZE NEQNS CONTAINING THE C FINE PARTITIONING. C C*********************************************************************** C SUBROUTINE FNSPLT ( NEQNS , NSUPER, XSUPER, XLINDX, & CACHSZ, SPLIT ) C C*********************************************************************** C C ----------- C PARAMETERS. C ----------- INTEGER CACHSZ, NEQNS , NSUPER INTEGER XSUPER(*), SPLIT(*) INTEGER XLINDX(*) C C ---------------- C LOCAL VARIABLES. C ---------------- INTEGER CACHE , CURCOL, FSTCOL, HEIGHT, KCOL , 1 KSUP , LSTCOL, NCOLS , NXTBLK, USED , 1 WIDTH C C ******************************************************************* C C -------------------------------------------- C COMPUTE THE NUMBER OF 8-BYTE WORDS IN CACHE. C -------------------------------------------- IF ( CACHSZ .LE. 0 ) THEN CACHE = 2 000 000 000 ELSE CACHE = CACHSZ * 116!INT( ( FLOAT(CACHSZ) * 1024. / 8. ) * 0.9 ) ENDIF C C --------------- C INITIALIZATION. C --------------- DO 100 KCOL = 1, NEQNS SPLIT(KCOL) = 0 100 CONTINUE C C --------------------------- C FOR EACH SUPERNODE KSUP ... C --------------------------- DO 1000 KSUP = 1, NSUPER C ----------------------- C ... GET SUPERNODE INFO. C ----------------------- HEIGHT = XLINDX(KSUP+1) - XLINDX(KSUP) FSTCOL = XSUPER(KSUP) LSTCOL = XSUPER(KSUP+1) - 1 WIDTH = LSTCOL - FSTCOL + 1 NXTBLK = FSTCOL C -------------------------------------- C ... UNTIL ALL COLUMNS OF THE SUPERNODE C HAVE BEEN PROCESSED ... C -------------------------------------- CURCOL = FSTCOL - 1 200 CONTINUE C ------------------------------------------- C ... PLACE THE FIRST COLUMN(S) IN THE CACHE. C ------------------------------------------- CURCOL = CURCOL + 1 IF ( CURCOL .LT. LSTCOL ) THEN CURCOL = CURCOL + 1 NCOLS = 2 USED = 4 * HEIGHT - 1 HEIGHT = HEIGHT - 2 ELSE NCOLS = 1 USED = 3 * HEIGHT HEIGHT = HEIGHT - 1 ENDIF C C -------------------------------------- C ... WHILE THE CACHE IS NOT FILLED AND C THERE ARE COLUMNS OF THE SUPERNODE C REMAINING TO BE PROCESSED ... C -------------------------------------- 300 CONTINUE IF ( USED+HEIGHT .LT. CACHE .AND. & CURCOL .LT. LSTCOL ) THEN C -------------------------------- C ... ADD ANOTHER COLUMN TO CACHE. C -------------------------------- CURCOL = CURCOL + 1 NCOLS = NCOLS + 1 USED = USED + HEIGHT HEIGHT = HEIGHT - 1 GO TO 300 ENDIF C ------------------------------------- C ... RECORD THE NUMBER OF COLUMNS THAT C FILLED THE CACHE. C ------------------------------------- SPLIT(NXTBLK) = NCOLS NXTBLK = NXTBLK + 1 C -------------------------- C ... GO PROCESS NEXT BLOCK. C -------------------------- IF ( CURCOL .LT. LSTCOL ) GO TO 200 1000 CONTINUE C RETURN END C*********************************************************************** C*********************************************************************** C C Version: 0.4 C Last modified: December 27, 1994 C Authors: Esmond G. Ng and Barry W. Peyton C C Mathematical Sciences Section, Oak Ridge National Laboratory C C*********************************************************************** C*********************************************************************** C****** FNTSIZ ..... COMPUTE WORK STORAGE SIZE FOR BLKFCT ****** C*********************************************************************** C*********************************************************************** C C PURPOSE: C THIS SUBROUTINE DETERMINES THE SIZE OF THE WORKING STORAGE C REQUIRED BY BLKFCT. C C INPUT PARAMETERS: C NSUPER - NUMBER OF SUPERNODES. C XSUPER - INTEGER ARRAY OF SIZE (NSUPER+1) CONTAINING C THE SUPERNODE PARTITIONING. C SNODE - SUPERNODE MEMBERSHIP. C (XLINDX,LINDX) - ARRAYS DESCRIBING THE SUPERNODAL STRUCTURE. C C OUTPUT PARAMETERS: C TMPSIZ - SIZE OF WORKING STORAGE REQUIRED BY BLKFCT. C C*********************************************************************** C SUBROUTINE FNTSIZ ( NSUPER, XSUPER, SNODE , XLINDX, & LINDX , TMPSIZ ) C C*********************************************************************** C INTEGER NSUPER, TMPSIZ INTEGER XLINDX(*) , XSUPER(*) INTEGER LINDX (*) , SNODE (*) C INTEGER BOUND , CLEN , CURSUP, I , IBEGIN, IEND , & KSUP , LENGTH, NCOLS , NXTSUP, & TSIZE , WIDTH C C*********************************************************************** C C RETURNS SIZE OF TEMP ARRAY USED BY BLKFCT FACTORIZATION ROUTINE. C NOTE THAT THE VALUE RETURNED IS AN ESTIMATE, THOUGH IT IS USUALLY C TIGHT. C C ---------------------------------------- C COMPUTE SIZE OF TEMPORARY STORAGE VECTOR C NEEDED BY BLKFCT. C ---------------------------------------- TMPSIZ = 0 DO 500 KSUP = NSUPER, 1, -1 NCOLS = XSUPER(KSUP+1) - XSUPER(KSUP) IBEGIN = XLINDX(KSUP) + NCOLS IEND = XLINDX(KSUP+1) - 1 LENGTH = IEND - IBEGIN + 1 BOUND = LENGTH * (LENGTH + 1) / 2 IF ( BOUND .GT. TMPSIZ ) THEN CURSUP = SNODE(LINDX(IBEGIN)) CLEN = XLINDX(CURSUP+1) - XLINDX(CURSUP) WIDTH = 0 DO 400 I = IBEGIN, IEND NXTSUP = SNODE(LINDX(I)) IF ( NXTSUP .EQ. CURSUP ) THEN WIDTH = WIDTH + 1 IF ( I .EQ. IEND ) THEN IF ( CLEN .GT. LENGTH ) THEN TSIZE = LENGTH * WIDTH - & (WIDTH - 1) * WIDTH / 2 TMPSIZ = MAX ( TSIZE , TMPSIZ ) ENDIF ENDIF ELSE IF ( CLEN .GT. LENGTH ) THEN TSIZE = LENGTH * WIDTH - & (WIDTH - 1) * WIDTH / 2 TMPSIZ = MAX ( TSIZE , TMPSIZ ) ENDIF LENGTH = LENGTH - WIDTH BOUND = LENGTH * (LENGTH + 1) / 2 IF ( BOUND .LE. TMPSIZ ) GO TO 500 WIDTH = 1 CURSUP = NXTSUP CLEN = XLINDX(CURSUP+1) - XLINDX(CURSUP) ENDIF 400 CONTINUE ENDIF 500 CONTINUE C RETURN END C*********************************************************************** C*********************************************************************** C C Version: 0.4 C Last modified: December 27, 1994 C Authors: Esmond G. Ng and Barry W. Peyton C C Mathematical Sciences Section, Oak Ridge National Laboratory C C*********************************************************************** C*********************************************************************** C**************** FSUP1 ..... FIND SUPERNODES #1 ***************** C*********************************************************************** C*********************************************************************** C C PURPOSE: C THIS SUBROUTINE IS THE FIRST OF TWO ROUTINES FOR FINDING A C MAXIMAL SUPERNODE PARTITION. IT RETURNS ONLY THE NUMBER OF C SUPERNODES NSUPER AND THE SUPERNODE MEMBERSHIP VECTOR SNODE(*), C WHICH IS OF LENGTH NEQNS. THE VECTORS OF LENGTH NSUPER ARE C COMPUTED SUBSEQUENTLY BY THE COMPANION ROUTINE FSUP2. C C METHOD AND ASSUMPTIONS: C THIS ROUTINE USES THE ELIMINATION TREE AND THE FACTOR COLUMN C COUNTS TO COMPUTE THE SUPERNODE PARTITION; IT ALSO ASSUMES A C POSTORDERING OF THE ELIMINATION TREE. C C INPUT PARAMETERS: C (I) NEQNS - NUMBER OF EQUATIONS. C (I) ETPAR(*) - ARRAY OF LENGTH NEQNS, CONTAINING THE C ELIMINATION TREE OF THE POSTORDERED MATRIX. C (I) COLCNT(*) - ARRAY OF LENGTH NEQNS, CONTAINING THE C FACTOR COLUMN COUNTS: I.E., THE NUMBER OF C NONZERO ENTRIES IN EACH COLUMN OF L C (INCLUDING THE DIAGONAL ENTRY). C C OUTPUT PARAMETERS: C (I) NOFSUB - NUMBER OF SUBSCRIPTS. C (I) NSUPER - NUMBER OF SUPERNODES (<= NEQNS). C (I) SNODE(*) - ARRAY OF LENGTH NEQNS FOR RECORDING C SUPERNODE MEMBERSHIP. C C FIRST CREATED ON JANUARY 18, 1992. C LAST UPDATED ON NOVEMBER 11, 1994. C C*********************************************************************** C SUBROUTINE FSUP1 ( NEQNS , ETPAR , COLCNT, NOFSUB, NSUPER, & SNODE ) C C*********************************************************************** C C ----------- C PARAMETERS. C ----------- INTEGER NEQNS , NOFSUB, NSUPER INTEGER COLCNT(*) , ETPAR(*) , & SNODE(*) C C ---------------- C LOCAL VARIABLES. C ---------------- INTEGER KCOL C C*********************************************************************** C C -------------------------------------------- C COMPUTE THE FUNDAMENTAL SUPERNODE PARTITION. C -------------------------------------------- NSUPER = 1 SNODE(1) = 1 NOFSUB = COLCNT(1) DO 300 KCOL = 2, NEQNS IF ( ETPAR(KCOL-1) .EQ. KCOL ) THEN IF ( COLCNT(KCOL-1) .EQ. COLCNT(KCOL)+1 ) THEN SNODE(KCOL) = NSUPER GO TO 300 ENDIF ENDIF NSUPER = NSUPER + 1 SNODE(KCOL) = NSUPER NOFSUB = NOFSUB + COLCNT(KCOL) 300 CONTINUE C RETURN END C*********************************************************************** C*********************************************************************** C C Version: 0.4 C Last modified: December 27, 1994 C Authors: Esmond G. Ng and Barry W. Peyton C C Mathematical Sciences Section, Oak Ridge National Laboratory C C*********************************************************************** C*********************************************************************** C**************** FSUP2 ..... FIND SUPERNODES #2 ***************** C*********************************************************************** C*********************************************************************** C C PURPOSE: C THIS SUBROUTINE IS THE SECOND OF TWO ROUTINES FOR FINDING A C MAXIMAL SUPERNODE PARTITION. IT'S SOLE PURPOSE IS TO C CONSTRUCT THE NEEDED VECTOR OF LENGTH NSUPER: XSUPER(*). THE C FIRST ROUTINE FSUP1 COMPUTES THE NUMBER OF SUPERNODES AND THE C SUPERNODE MEMBERSHIP VECTOR SNODE(*), WHICH IS OF LENGTH NEQNS. C C C ASSUMPTIONS: C THIS ROUTINE ASSUMES A POSTORDERING OF THE ELIMINATION TREE. IT C ALSO ASSUMES THAT THE OUTPUT FROM FSUP1 IS AVAILABLE. C C INPUT PARAMETERS: C (I) NEQNS - NUMBER OF EQUATIONS. C (I) NSUPER - NUMBER OF SUPERNODES (<= NEQNS). C (I) SNODE(*) - ARRAY OF LENGTH NEQNS FOR RECORDING C SUPERNODE MEMBERSHIP. C C OUTPUT PARAMETERS: C (I) XSUPER(*) - ARRAY OF LENGTH NSUPER+1, CONTAINING THE C SUPERNODE PARTITIONING. C C FIRST CREATED ON JANUARY 18, 1992. C LAST UPDATED ON NOVEMEBER 22, 1994. C C*********************************************************************** C SUBROUTINE FSUP2 ( NEQNS , NSUPER, SNODE , XSUPER ) C C*********************************************************************** C C ----------- C PARAMETERS. C ----------- INTEGER NEQNS , NSUPER INTEGER SNODE(*) , & XSUPER(*) C C ---------------- C LOCAL VARIABLES. C ---------------- INTEGER KCOL , KSUP , LSTSUP C C*********************************************************************** C C ------------------------------------------------- C COMPUTE THE SUPERNODE PARTITION VECTOR XSUPER(*). C ------------------------------------------------- LSTSUP = NSUPER + 1 DO 100 KCOL = NEQNS, 1, -1 KSUP = SNODE(KCOL) IF ( KSUP .NE. LSTSUP ) THEN XSUPER(LSTSUP) = KCOL + 1 ENDIF LSTSUP = KSUP 100 CONTINUE XSUPER(1) = 1 C RETURN END C*********************************************************************** C*********************************************************************** C C Version: 0.4 C Last modified: December 27, 1994 C Authors: Joseph W.H. Liu C C Mathematical Sciences Section, Oak Ridge National Laboratory C C*********************************************************************** C*********************************************************************** C--- SPARSPAK-A (ANSI FORTRAN) RELEASE III --- NAME = GENMMD C (C) UNIVERSITY OF WATERLOO JANUARY 1984 C*********************************************************************** C*********************************************************************** C**** GENMMD ..... MULTIPLE MINIMUM EXTERNAL DEGREE ************ C*********************************************************************** C*********************************************************************** C C PURPOSE - THIS ROUTINE IMPLEMENTS THE MINIMUM DEGREE C ALGORITHM. IT MAKES USE OF THE IMPLICIT REPRESENTATION C OF ELIMINATION GRAPHS BY QUOTIENT GRAPHS, AND THE C NOTION OF INDISTINGUISHABLE NODES. IT ALSO IMPLEMENTS C THE MODIFICATIONS BY MULTIPLE ELIMINATION AND MINIMUM C EXTERNAL DEGREE. C --------------------------------------------- C CAUTION - THE ADJACENCY VECTOR ADJNCY WILL BE C DESTROYED. C --------------------------------------------- C C INPUT PARAMETERS - C NEQNS - NUMBER OF EQUATIONS. C (XADJ,ADJNCY) - THE ADJACENCY STRUCTURE. C DELTA - TOLERANCE VALUE FOR MULTIPLE ELIMINATION. C MAXINT - MAXIMUM MACHINE REPRESENTABLE (SHORT) INTEGER C (ANY SMALLER ESTIMATE WILL DO) FOR MARKING C NODES. C C OUTPUT PARAMETERS - C PERM - THE MINIMUM DEGREE ORDERING. C INVP - THE INVERSE OF PERM. C NOFSUB - AN UPPER BOUND ON THE NUMBER OF NONZERO C SUBSCRIPTS FOR THE COMPRESSED STORAGE SCHEME. C C WORKING PARAMETERS - C DHEAD - VECTOR FOR HEAD OF DEGREE LISTS. C INVP - USED TEMPORARILY FOR DEGREE FORWARD LINK. C PERM - USED TEMPORARILY FOR DEGREE BACKWARD LINK. C QSIZE - VECTOR FOR SIZE OF SUPERNODES. C LLIST - VECTOR FOR TEMPORARY LINKED LISTS. C MARKER - A TEMPORARY MARKER VECTOR. C C PROGRAM SUBROUTINES - C MMDELM, MMDINT, MMDNUM, MMDUPD. C C*********************************************************************** C SUBROUTINE GENMMD ( NEQNS, XADJ, ADJNCY, INVP, PERM, 1 DELTA, DHEAD, QSIZE, LLIST, MARKER, 1 MAXINT, NOFSUB ) C C*********************************************************************** C INTEGER ADJNCY(*), DHEAD(*) , INVP(*) , LLIST(*) , 1 MARKER(*), PERM(*) , QSIZE(*) INTEGER XADJ(*) INTEGER DELTA , EHEAD , I , MAXINT, MDEG , 1 MDLMT , MDNODE, NEQNS , NEXTMD, NOFSUB, 1 NUM, TAG C C*********************************************************************** C IF ( NEQNS .LE. 0 ) RETURN C C ------------------------------------------------ C INITIALIZATION FOR THE MINIMUM DEGREE ALGORITHM. C ------------------------------------------------ NOFSUB = 0 CALL MMDINT ( NEQNS, XADJ, DHEAD, INVP, PERM, 1 QSIZE, LLIST, MARKER ) C C ---------------------------------------------- C NUM COUNTS THE NUMBER OF ORDERED NODES PLUS 1. C ---------------------------------------------- NUM = 1 C C ----------------------------- C ELIMINATE ALL ISOLATED NODES. C ----------------------------- NEXTMD = DHEAD(1) 100 CONTINUE IF ( NEXTMD .LE. 0 ) GO TO 200 MDNODE = NEXTMD NEXTMD = INVP(MDNODE) MARKER(MDNODE) = MAXINT INVP(MDNODE) = - NUM NUM = NUM + 1 GO TO 100 C 200 CONTINUE C ---------------------------------------- C SEARCH FOR NODE OF THE MINIMUM DEGREE. C MDEG IS THE CURRENT MINIMUM DEGREE; C TAG IS USED TO FACILITATE MARKING NODES. C ---------------------------------------- IF ( NUM .GT. NEQNS ) GO TO 1000 TAG = 1 DHEAD(1) = 0 MDEG = 2 300 CONTINUE IF ( DHEAD(MDEG) .GT. 0 ) GO TO 400 MDEG = MDEG + 1 GO TO 300 400 CONTINUE C ------------------------------------------------- C USE VALUE OF DELTA TO SET UP MDLMT, WHICH GOVERNS C WHEN A DEGREE UPDATE IS TO BE PERFORMED. C ------------------------------------------------- MDLMT = MDEG + DELTA EHEAD = 0 C 500 CONTINUE MDNODE = DHEAD(MDEG) IF ( MDNODE .GT. 0 ) GO TO 600 MDEG = MDEG + 1 IF ( MDEG .GT. MDLMT ) GO TO 900 GO TO 500 600 CONTINUE C ---------------------------------------- C REMOVE MDNODE FROM THE DEGREE STRUCTURE. C ---------------------------------------- NEXTMD = INVP(MDNODE) DHEAD(MDEG) = NEXTMD IF ( NEXTMD .GT. 0 ) PERM(NEXTMD) = - MDEG INVP(MDNODE) = - NUM NOFSUB = NOFSUB + MDEG + QSIZE(MDNODE) - 2 IF ( NUM+QSIZE(MDNODE) .GT. NEQNS ) GO TO 1000 C ---------------------------------------------- C ELIMINATE MDNODE AND PERFORM QUOTIENT GRAPH C TRANSFORMATION. RESET TAG VALUE IF NECESSARY. C ---------------------------------------------- TAG = TAG + 1 IF ( TAG .LT. MAXINT ) GO TO 800 TAG = 1 DO 700 I = 1, NEQNS IF ( MARKER(I) .LT. MAXINT ) MARKER(I) = 0 700 CONTINUE 800 CONTINUE CALL MMDELM ( MDNODE, XADJ, ADJNCY, DHEAD, INVP, 1 PERM, QSIZE, LLIST, MARKER, MAXINT, 1 TAG ) NUM = NUM + QSIZE(MDNODE) LLIST(MDNODE) = EHEAD EHEAD = MDNODE IF ( DELTA .GE. 0 ) GO TO 500 900 CONTINUE C ------------------------------------------- C UPDATE DEGREES OF THE NODES INVOLVED IN THE C MINIMUM DEGREE NODES ELIMINATION. C ------------------------------------------- IF ( NUM .GT. NEQNS ) GO TO 1000 CALL MMDUPD ( EHEAD, NEQNS, XADJ, ADJNCY, DELTA, MDEG, 1 DHEAD, INVP, PERM, QSIZE, LLIST, MARKER, 1 MAXINT, TAG ) GO TO 300 C 1000 CONTINUE CALL MMDNUM ( NEQNS, PERM, INVP, QSIZE ) RETURN C END C*********************************************************************** C*********************************************************************** C C Version: 0.4 C Last modified: December 27, 1994 C Authors: Esmond G. Ng and Barry W. Peyton C C Mathematical Sciences Section, Oak Ridge National Laboratory C C*********************************************************************** C*********************************************************************** C****** IGATHR .... INTEGER GATHER OPERATION ************** C*********************************************************************** C*********************************************************************** C C PURPOSE - THIS ROUTINE PERFORMS A STANDARD INTEGER GATHER C OPERATION. C C INPUT PARAMETERS - C KLEN - LENGTH OF THE LIST OF GLOBAL INDICES. C LINDX - LIST OF GLOBAL INDICES. C INDMAP - INDEXED BY GLOBAL INDICES, IT CONTAINS THE C REQUIRED RELATIVE INDICES. C C OUTPUT PARAMETERS - C RELIND - LIST RELATIVE INDICES. C C*********************************************************************** C SUBROUTINE IGATHR ( KLEN , LINDX, INDMAP, RELIND ) C C*********************************************************************** C C ----------- C PARAMETERS. C ----------- INTEGER KLEN INTEGER INDMAP(*), LINDX (*), RELIND(*) C C ---------------- C LOCAL VARIABLES. C ---------------- INTEGER I C C*********************************************************************** C CDIR$ IVDEP DO 100 I = 1, KLEN RELIND(I) = INDMAP(LINDX(I)) 100 CONTINUE RETURN END C*********************************************************************** C*********************************************************************** C C Version: 0.4 C Last modified: December 27, 1994 C Authors: Esmond G. Ng and Barry W. Peyton C C Mathematical Sciences Section, Oak Ridge National Laboratory C C*********************************************************************** C*********************************************************************** C C ------------------------------------------------------ C INPUT NUMERICAL VALUES INTO SPARSE DATA STRUCTURES ... C ------------------------------------------------------ C SUBROUTINE INPNV ( XADJF, ADJF, ANZF, PERM, INVP, & NSUPER, XSUPER, XLINDX, LINDX, & XLNZ, LNZ, OFFSET ) C INTEGER XADJF(*), ADJF(*) DOUBLE PRECISION ANZF(*) INTEGER PERM(*), INVP(*) INTEGER NSUPER INTEGER XSUPER(*), XLINDX(*), LINDX(*) INTEGER XLNZ(*) DOUBLE PRECISION LNZ(*) INTEGER OFFSET(*) C INTEGER I, II, J, JLEN, JSUPER, LAST, OLDJ C DO 500 JSUPER = 1, NSUPER C C ---------------------------------------- C FOR EACH SUPERNODE, DO THE FOLLOWING ... C ---------------------------------------- C C ----------------------------------------------- C FIRST GET OFFSET TO FACILITATE NUMERICAL INPUT. C ----------------------------------------------- JLEN = XLINDX(JSUPER+1) - XLINDX(JSUPER) DO 100 II = XLINDX(JSUPER), XLINDX(JSUPER+1)-1 I = LINDX(II) JLEN = JLEN - 1 OFFSET(I) = JLEN 100 CONTINUE C DO 400 J = XSUPER(JSUPER), XSUPER(JSUPER+1)-1 C ----------------------------------------- C FOR EACH COLUMN IN THE CURRENT SUPERNODE, C FIRST INITIALIZE THE DATA STRUCTURE. C ----------------------------------------- c DO 200 II = XLNZ(J), XLNZ(J+1)-1 c LNZ(II) = 0.0 c 200 CONTINUE c The previous lines are not required as R initializes the arrays c Reinhard Furrer, Nov 19, 2007 C C ----------------------------------- C NEXT INPUT THE INDIVIDUAL NONZEROS. C ----------------------------------- OLDJ = PERM(J) LAST = XLNZ(J+1) - 1 DO 300 II = XADJF(OLDJ), XADJF(OLDJ+1)-1 I = INVP(ADJF(II)) IF ( I .GE. J ) THEN LNZ(LAST-OFFSET(I)) = ANZF(II) ENDIF 300 CONTINUE 400 CONTINUE C 500 CONTINUE RETURN END C*********************************************************************** C*********************************************************************** C C Version: 0.4 C Last modified: December 27, 1994 C Authors: Joseph W.H. Liu C C Mathematical Sciences Section, Oak Ridge National Laboratory C C*********************************************************************** C*********************************************************************** C*********** INVINV ..... CONCATENATION OF TWO INVP ************ C*********************************************************************** C*********************************************************************** C C WRITTEN BY JOSEPH LIU (JUL 17, 1985) C C PURPOSE: C TO PERFORM THE MAPPING OF C ORIGINAL-INVP --> INTERMEDIATE-INVP --> NEW INVP C AND THE RESULTING ORDERING REPLACES INVP. THE NEW PERMUTATION C VECTOR PERM IS ALSO COMPUTED. C C INPUT PARAMETERS: C NEQNS - NUMBER OF EQUATIONS. C INVP2 - THE SECOND INVERSE PERMUTATION VECTOR. C C UPDATED PARAMETERS: C INVP - THE FIRST INVERSE PERMUTATION VECTOR. ON C OUTPUT, IT CONTAINS THE NEW INVERSE C PERMUTATION. C C OUTPUT PARAMETER: C PERM - NEW PERMUTATION VECTOR (CAN BE THE SAME AS C INVP2). C C*********************************************************************** C SUBROUTINE INVINV ( NEQNS , INVP , INVP2 , PERM ) C C*********************************************************************** C INTEGER INVP(*) , INVP2(*) , & PERM(*) C INTEGER NEQNS C C*********************************************************************** C INTEGER I , INTERM, NODE C C*********************************************************************** C DO 100 I = 1, NEQNS INTERM = INVP(I) INVP(I) = INVP2(INTERM) 100 CONTINUE C DO 200 I = 1, NEQNS NODE = INVP(I) PERM(NODE) = I 200 CONTINUE C RETURN END C*********************************************************************** C*********************************************************************** C C Version: 0.4 C Last modified: December 27, 1994 C Authors: Esmond G. Ng and Barry W. Peyton C C Mathematical Sciences Section, Oak Ridge National Laboratory C C*********************************************************************** C*********************************************************************** C****** LDINDX .... LOAD INDEX VECTOR ************** C*********************************************************************** C*********************************************************************** C C PURPOSE - THIS ROUTINE COMPUTES THE SECOND INDEX VECTOR C USED TO IMPLEMENT THE DOUBLY-INDIRECT SAXPY-LIKE C LOOPS THAT ALLOW US TO ACCUMULATE UPDATE C COLUMNS DIRECTLY INTO FACTOR STORAGE. C C INPUT PARAMETERS - C JLEN - LENGTH OF THE FIRST COLUMN OF THE SUPERNODE, C INCLUDING THE DIAGONAL ENTRY. C LINDX - THE OFF-DIAGONAL ROW INDICES OF THE SUPERNODE, C I.E., THE ROW INDICES OF THE NONZERO ENTRIES C LYING BELOW THE DIAGONAL ENTRY OF THE FIRST C COLUMN OF THE SUPERNODE. C C OUTPUT PARAMETERS - C INDMAP - THIS INDEX VECTOR MAPS EVERY GLOBAL ROW INDEX C OF NONZERO ENTRIES IN THE FIRST COLUMN OF THE C SUPERNODE TO ITS POSITION IN THE INDEX LIST C RELATIVE TO THE LAST INDEX IN THE LIST. MORE C PRECISELY, IT GIVES THE DISTANCE OF EACH INDEX C FROM THE LAST INDEX IN THE LIST. C C*********************************************************************** C SUBROUTINE LDINDX ( JLEN, LINDX, INDMAP ) C C*********************************************************************** C C ----------- C PARAMETERS. C ----------- INTEGER JLEN INTEGER LINDX(*), INDMAP(*) C C ---------------- C LOCAL VARIABLES. C ---------------- INTEGER CURLEN, J, JSUB C C*********************************************************************** C CURLEN = JLEN DO 200 J = 1, JLEN JSUB = LINDX(J) CURLEN = CURLEN - 1 INDMAP(JSUB) = CURLEN 200 CONTINUE RETURN END C*********************************************************************** C*********************************************************************** C C Version: 0.4 C Last modified: December 27, 1994 C Authors: Joseph W.H. Liu C C Mathematical Sciences Section, Oak Ridge National Laboratory C C*********************************************************************** C*********************************************************************** C--- SPARSPAK-A (ANSI FORTRAN) RELEASE III --- NAME = MMDELM C (C) UNIVERSITY OF WATERLOO JANUARY 1984 C*********************************************************************** C*********************************************************************** C** MMDELM ..... MULTIPLE MINIMUM DEGREE ELIMINATION *********** C*********************************************************************** C*********************************************************************** C C PURPOSE - THIS ROUTINE ELIMINATES THE NODE MDNODE OF C MINIMUM DEGREE FROM THE ADJACENCY STRUCTURE, WHICH C IS STORED IN THE QUOTIENT GRAPH FORMAT. IT ALSO C TRANSFORMS THE QUOTIENT GRAPH REPRESENTATION OF THE C ELIMINATION GRAPH. C C INPUT PARAMETERS - C MDNODE - NODE OF MINIMUM DEGREE. C MAXINT - ESTIMATE OF MAXIMUM REPRESENTABLE (SHORT) C INTEGER. C TAG - TAG VALUE. C C UPDATED PARAMETERS - C (XADJ,ADJNCY) - UPDATED ADJACENCY STRUCTURE. C (DHEAD,DFORW,DBAKW) - DEGREE DOUBLY LINKED STRUCTURE. C QSIZE - SIZE OF SUPERNODE. C MARKER - MARKER VECTOR. C LLIST - TEMPORARY LINKED LIST OF ELIMINATED NABORS. C C*********************************************************************** C SUBROUTINE MMDELM ( MDNODE, XADJ, ADJNCY, DHEAD, DFORW, 1 DBAKW, QSIZE, LLIST, MARKER, MAXINT, 1 TAG ) C C*********************************************************************** C INTEGER ADJNCY(*), DBAKW(*) , DFORW(*) , DHEAD(*) , 1 LLIST(*) , MARKER(*), QSIZE(*) INTEGER XADJ(*) INTEGER ELMNT , I , ISTOP , ISTRT , J , 1 JSTOP , JSTRT , LINK , MAXINT, MDNODE, 1 NABOR , NODE , NPV , NQNBRS, NXNODE, 1 PVNODE, RLMT , RLOC , RNODE , TAG , 1 XQNBR C C*********************************************************************** C C ----------------------------------------------- C FIND REACHABLE SET AND PLACE IN DATA STRUCTURE. C ----------------------------------------------- MARKER(MDNODE) = TAG ISTRT = XADJ(MDNODE) ISTOP = XADJ(MDNODE+1) - 1 C ------------------------------------------------------- C ELMNT POINTS TO THE BEGINNING OF THE LIST OF ELIMINATED C NABORS OF MDNODE, AND RLOC GIVES THE STORAGE LOCATION C FOR THE NEXT REACHABLE NODE. C ------------------------------------------------------- ELMNT = 0 RLOC = ISTRT RLMT = ISTOP DO 200 I = ISTRT, ISTOP NABOR = ADJNCY(I) IF ( NABOR .EQ. 0 ) GO TO 300 IF ( MARKER(NABOR) .GE. TAG ) GO TO 200 MARKER(NABOR) = TAG IF ( DFORW(NABOR) .LT. 0 ) GO TO 100 ADJNCY(RLOC) = NABOR RLOC = RLOC + 1 GO TO 200 100 CONTINUE LLIST(NABOR) = ELMNT ELMNT = NABOR 200 CONTINUE 300 CONTINUE C ----------------------------------------------------- C MERGE WITH REACHABLE NODES FROM GENERALIZED ELEMENTS. C ----------------------------------------------------- IF ( ELMNT .LE. 0 ) GO TO 1000 ADJNCY(RLMT) = - ELMNT LINK = ELMNT 400 CONTINUE JSTRT = XADJ(LINK) JSTOP = XADJ(LINK+1) - 1 DO 800 J = JSTRT, JSTOP NODE = ADJNCY(J) LINK = - NODE if ( NODE < 0 ) then GO TO 400 else if ( NODE == 0 ) then GO TO 900 else GO TO 500 end if 500 CONTINUE IF ( MARKER(NODE) .GE. TAG .OR. 1 DFORW(NODE) .LT. 0 ) GO TO 800 MARKER(NODE) = TAG C --------------------------------- C USE STORAGE FROM ELIMINATED NODES C IF NECESSARY. C --------------------------------- 600 CONTINUE IF ( RLOC .LT. RLMT ) GO TO 700 LINK = - ADJNCY(RLMT) RLOC = XADJ(LINK) RLMT = XADJ(LINK+1) - 1 GO TO 600 700 CONTINUE ADJNCY(RLOC) = NODE RLOC = RLOC + 1 800 CONTINUE 900 CONTINUE ELMNT = LLIST(ELMNT) GO TO 300 1000 CONTINUE IF ( RLOC .LE. RLMT ) ADJNCY(RLOC) = 0 C -------------------------------------------------------- C FOR EACH NODE IN THE REACHABLE SET, DO THE FOLLOWING ... C -------------------------------------------------------- LINK = MDNODE 1100 CONTINUE ISTRT = XADJ(LINK) ISTOP = XADJ(LINK+1) - 1 DO 1700 I = ISTRT, ISTOP RNODE = ADJNCY(I) LINK = - RNODE if ( RNODE < 0 ) then GO TO 1100 else if ( RNODE == 0 ) then GO TO 1800 else GO TO 1200 end if 1200 CONTINUE C -------------------------------------------- C IF RNODE IS IN THE DEGREE LIST STRUCTURE ... C -------------------------------------------- PVNODE = DBAKW(RNODE) IF ( PVNODE .EQ. 0 .OR. 1 PVNODE .EQ. (-MAXINT) ) GO TO 1300 C ------------------------------------- C THEN REMOVE RNODE FROM THE STRUCTURE. C ------------------------------------- NXNODE = DFORW(RNODE) IF ( NXNODE .GT. 0 ) DBAKW(NXNODE) = PVNODE IF ( PVNODE .GT. 0 ) DFORW(PVNODE) = NXNODE NPV = - PVNODE IF ( PVNODE .LT. 0 ) DHEAD(NPV) = NXNODE 1300 CONTINUE C ---------------------------------------- C PURGE INACTIVE QUOTIENT NABORS OF RNODE. C ---------------------------------------- JSTRT = XADJ(RNODE) JSTOP = XADJ(RNODE+1) - 1 XQNBR = JSTRT DO 1400 J = JSTRT, JSTOP NABOR = ADJNCY(J) IF ( NABOR .EQ. 0 ) GO TO 1500 IF ( MARKER(NABOR) .GE. TAG ) GO TO 1400 ADJNCY(XQNBR) = NABOR XQNBR = XQNBR + 1 1400 CONTINUE 1500 CONTINUE C ---------------------------------------- C IF NO ACTIVE NABOR AFTER THE PURGING ... C ---------------------------------------- NQNBRS = XQNBR - JSTRT IF ( NQNBRS .GT. 0 ) GO TO 1600 C ----------------------------- C THEN MERGE RNODE WITH MDNODE. C ----------------------------- QSIZE(MDNODE) = QSIZE(MDNODE) + QSIZE(RNODE) QSIZE(RNODE) = 0 MARKER(RNODE) = MAXINT DFORW(RNODE) = - MDNODE DBAKW(RNODE) = - MAXINT GO TO 1700 1600 CONTINUE C -------------------------------------- C ELSE FLAG RNODE FOR DEGREE UPDATE, AND C ADD MDNODE AS A NABOR OF RNODE. C -------------------------------------- DFORW(RNODE) = NQNBRS + 1 DBAKW(RNODE) = 0 ADJNCY(XQNBR) = MDNODE XQNBR = XQNBR + 1 IF ( XQNBR .LE. JSTOP ) ADJNCY(XQNBR) = 0 C 1700 CONTINUE 1800 CONTINUE RETURN C END C*********************************************************************** C*********************************************************************** C C Version: 0.4 C Last modified: December 27, 1994 C Authors: Joseph W.H. Liu C C Mathematical Sciences Section, Oak Ridge National Laboratory C C*********************************************************************** C*********************************************************************** C--- SPARSPAK-A (ANSI FORTRAN) RELEASE III --- NAME = MMDINT C (C) UNIVERSITY OF WATERLOO JANUARY 1984 C*********************************************************************** C*********************************************************************** C*** MMDINT ..... MULT MINIMUM DEGREE INITIALIZATION *********** C*********************************************************************** C*********************************************************************** C C PURPOSE - THIS ROUTINE PERFORMS INITIALIZATION FOR THE C MULTIPLE ELIMINATION VERSION OF THE MINIMUM DEGREE C ALGORITHM. C C INPUT PARAMETERS - C NEQNS - NUMBER OF EQUATIONS. C (XADJ,ADJNCY) - ADJACENCY STRUCTURE. C C OUTPUT PARAMETERS - C (DHEAD,DFORW,DBAKW) - DEGREE DOUBLY LINKED STRUCTURE. C QSIZE - SIZE OF SUPERNODE (INITIALIZED TO ONE). C LLIST - LINKED LIST. C MARKER - MARKER VECTOR. C C*********************************************************************** C SUBROUTINE MMDINT ( NEQNS, XADJ, DHEAD, DFORW, 1 DBAKW, QSIZE, LLIST, MARKER ) C C*********************************************************************** C INTEGER DBAKW(*) , DFORW(*) , DHEAD(*) , 1 LLIST(*) , MARKER(*), QSIZE(*) INTEGER XADJ(*) INTEGER FNODE , NDEG , NEQNS , NODE C C*********************************************************************** C DO 100 NODE = 1, NEQNS DHEAD(NODE) = 0 QSIZE(NODE) = 1 MARKER(NODE) = 0 LLIST(NODE) = 0 100 CONTINUE C ------------------------------------------ C INITIALIZE THE DEGREE DOUBLY LINKED LISTS. C ------------------------------------------ DO 200 NODE = 1, NEQNS NDEG = XADJ(NODE+1) - XADJ(NODE) + 1 FNODE = DHEAD(NDEG) DFORW(NODE) = FNODE DHEAD(NDEG) = NODE IF ( FNODE .GT. 0 ) DBAKW(FNODE) = NODE DBAKW(NODE) = - NDEG 200 CONTINUE RETURN C END C*********************************************************************** C*********************************************************************** C C Version: 0.4 C Last modified: December 27, 1994 C Authors: Joseph W.H. Liu C C Mathematical Sciences Section, Oak Ridge National Laboratory C C*********************************************************************** C*********************************************************************** C--- SPARSPAK-A (ANSI FORTRAN) RELEASE III --- NAME = MMDNUM C (C) UNIVERSITY OF WATERLOO JANUARY 1984 C*********************************************************************** C*********************************************************************** C***** MMDNUM ..... MULTI MINIMUM DEGREE NUMBERING ************* C*********************************************************************** C*********************************************************************** C C PURPOSE - THIS ROUTINE PERFORMS THE FINAL STEP IN C PRODUCING THE PERMUTATION AND INVERSE PERMUTATION C VECTORS IN THE MULTIPLE ELIMINATION VERSION OF THE C MINIMUM DEGREE ORDERING ALGORITHM. C C INPUT PARAMETERS - C NEQNS - NUMBER OF EQUATIONS. C QSIZE - SIZE OF SUPERNODES AT ELIMINATION. C C UPDATED PARAMETERS - C INVP - INVERSE PERMUTATION VECTOR. ON INPUT, C IF QSIZE(NODE)=0, THEN NODE HAS BEEN MERGED C INTO THE NODE -INVP(NODE); OTHERWISE, C -INVP(NODE) IS ITS INVERSE LABELLING. C C OUTPUT PARAMETERS - C PERM - THE PERMUTATION VECTOR. C C*********************************************************************** C SUBROUTINE MMDNUM ( NEQNS, PERM, INVP, QSIZE ) C C*********************************************************************** C INTEGER INVP(*) , PERM(*) , QSIZE(*) INTEGER FATHER, NEQNS , NEXTF , NODE , NQSIZE, 1 NUM , ROOT C C*********************************************************************** C DO 100 NODE = 1, NEQNS NQSIZE = QSIZE(NODE) IF ( NQSIZE .LE. 0 ) PERM(NODE) = INVP(NODE) IF ( NQSIZE .GT. 0 ) PERM(NODE) = - INVP(NODE) 100 CONTINUE C ------------------------------------------------------ C FOR EACH NODE WHICH HAS BEEN MERGED, DO THE FOLLOWING. C ------------------------------------------------------ DO 500 NODE = 1, NEQNS IF ( PERM(NODE) .GT. 0 ) GO TO 500 C ----------------------------------------- C TRACE THE MERGED TREE UNTIL ONE WHICH HAS C NOT BEEN MERGED, CALL IT ROOT. C ----------------------------------------- FATHER = NODE 200 CONTINUE IF ( PERM(FATHER) .GT. 0 ) GO TO 300 FATHER = - PERM(FATHER) GO TO 200 300 CONTINUE C ----------------------- C NUMBER NODE AFTER ROOT. C ----------------------- ROOT = FATHER NUM = PERM(ROOT) + 1 INVP(NODE) = - NUM PERM(ROOT) = NUM C ------------------------ C SHORTEN THE MERGED TREE. C ------------------------ FATHER = NODE 400 CONTINUE NEXTF = - PERM(FATHER) IF ( NEXTF .LE. 0 ) GO TO 500 PERM(FATHER) = - ROOT FATHER = NEXTF GO TO 400 500 CONTINUE C ---------------------- C READY TO COMPUTE PERM. C ---------------------- DO 600 NODE = 1, NEQNS NUM = - INVP(NODE) INVP(NODE) = NUM PERM(NUM) = NODE 600 CONTINUE RETURN C END C*********************************************************************** C*********************************************************************** C C Version: 0.4 C Last modified: December 27, 1994 C Authors: Joseph W.H. Liu C C Mathematical Sciences Section, Oak Ridge National Laboratory C C*********************************************************************** C*********************************************************************** C--- SPARSPAK-A (ANSI FORTRAN) RELEASE III --- NAME = MMDUPD C (C) UNIVERSITY OF WATERLOO JANUARY 1984 C*********************************************************************** C*********************************************************************** C***** MMDUPD ..... MULTIPLE MINIMUM DEGREE UPDATE ************* C*********************************************************************** C*********************************************************************** C C PURPOSE - THIS ROUTINE UPDATES THE DEGREES OF NODES C AFTER A MULTIPLE ELIMINATION STEP. C C INPUT PARAMETERS - C EHEAD - THE BEGINNING OF THE LIST OF ELIMINATED C NODES (I.E., NEWLY FORMED ELEMENTS). C NEQNS - NUMBER OF EQUATIONS. C (XADJ,ADJNCY) - ADJACENCY STRUCTURE. C DELTA - TOLERANCE VALUE FOR MULTIPLE ELIMINATION. C MAXINT - MAXIMUM MACHINE REPRESENTABLE (SHORT) C INTEGER. C C UPDATED PARAMETERS - C MDEG - NEW MINIMUM DEGREE AFTER DEGREE UPDATE. C (DHEAD,DFORW,DBAKW) - DEGREE DOUBLY LINKED STRUCTURE. C QSIZE - SIZE OF SUPERNODE. C LLIST - WORKING LINKED LIST. C MARKER - MARKER VECTOR FOR DEGREE UPDATE. C TAG - TAG VALUE. C C*********************************************************************** C SUBROUTINE MMDUPD ( EHEAD, NEQNS, XADJ, ADJNCY, DELTA, 1 MDEG, DHEAD, DFORW, DBAKW, QSIZE, 1 LLIST, MARKER, MAXINT, TAG ) C C*********************************************************************** C INTEGER ADJNCY(*), DBAKW(*) , DFORW(*) , DHEAD(*) , 1 LLIST(*) , MARKER(*), QSIZE(*) INTEGER XADJ(*) INTEGER DEG , DEG0 , DELTA , EHEAD , ELMNT , 1 ENODE , FNODE , I , IQ2 , ISTOP , 1 ISTRT , J , JSTOP , JSTRT , LINK , 1 MAXINT, MDEG , MDEG0 , MTAG , NABOR , 1 NEQNS , NODE , Q2HEAD, QXHEAD, TAG C C*********************************************************************** C MDEG0 = MDEG + DELTA ELMNT = EHEAD 100 CONTINUE C ------------------------------------------------------- C FOR EACH OF THE NEWLY FORMED ELEMENT, DO THE FOLLOWING. C (RESET TAG VALUE IF NECESSARY.) C ------------------------------------------------------- IF ( ELMNT .LE. 0 ) RETURN MTAG = TAG + MDEG0 IF ( MTAG .LT. MAXINT ) GO TO 300 TAG = 1 DO 200 I = 1, NEQNS IF ( MARKER(I) .LT. MAXINT ) MARKER(I) = 0 200 CONTINUE MTAG = TAG + MDEG0 300 CONTINUE C --------------------------------------------- C CREATE TWO LINKED LISTS FROM NODES ASSOCIATED C WITH ELMNT: ONE WITH TWO NABORS (Q2HEAD) IN C ADJACENCY STRUCTURE, AND THE OTHER WITH MORE C THAN TWO NABORS (QXHEAD). ALSO COMPUTE DEG0, C NUMBER OF NODES IN THIS ELEMENT. C --------------------------------------------- Q2HEAD = 0 QXHEAD = 0 DEG0 = 0 LINK = ELMNT 400 CONTINUE ISTRT = XADJ(LINK) ISTOP = XADJ(LINK+1) - 1 DO 700 I = ISTRT, ISTOP ENODE = ADJNCY(I) LINK = - ENODE if ( ENODE < 0 ) then GO TO 400 else if ( ENODE == 0 ) then GO TO 800 else GO TO 500 end if C 500 CONTINUE IF ( QSIZE(ENODE) .EQ. 0 ) GO TO 700 DEG0 = DEG0 + QSIZE(ENODE) MARKER(ENODE) = MTAG C ---------------------------------- C IF ENODE REQUIRES A DEGREE UPDATE, C THEN DO THE FOLLOWING. C ---------------------------------- IF ( DBAKW(ENODE) .NE. 0 ) GO TO 700 C --------------------------------------- C PLACE EITHER IN QXHEAD OR Q2HEAD LISTS. C --------------------------------------- IF ( DFORW(ENODE) .EQ. 2 ) GO TO 600 LLIST(ENODE) = QXHEAD QXHEAD = ENODE GO TO 700 600 CONTINUE LLIST(ENODE) = Q2HEAD Q2HEAD = ENODE 700 CONTINUE 800 CONTINUE C -------------------------------------------- C FOR EACH ENODE IN Q2 LIST, DO THE FOLLOWING. C -------------------------------------------- ENODE = Q2HEAD IQ2 = 1 900 CONTINUE IF ( ENODE .LE. 0 ) GO TO 1500 IF ( DBAKW(ENODE) .NE. 0 ) GO TO 2200 TAG = TAG + 1 DEG = DEG0 C ------------------------------------------ C IDENTIFY THE OTHER ADJACENT ELEMENT NABOR. C ------------------------------------------ ISTRT = XADJ(ENODE) NABOR = ADJNCY(ISTRT) IF ( NABOR .EQ. ELMNT ) NABOR = ADJNCY(ISTRT+1) C ------------------------------------------------ C IF NABOR IS UNELIMINATED, INCREASE DEGREE COUNT. C ------------------------------------------------ LINK = NABOR IF ( DFORW(NABOR) .LT. 0 ) GO TO 1000 DEG = DEG + QSIZE(NABOR) GO TO 2100 1000 CONTINUE C -------------------------------------------- C OTHERWISE, FOR EACH NODE IN THE 2ND ELEMENT, C DO THE FOLLOWING. C -------------------------------------------- ISTRT = XADJ(LINK) ISTOP = XADJ(LINK+1) - 1 DO 1400 I = ISTRT, ISTOP NODE = ADJNCY(I) LINK = - NODE IF ( NODE .EQ. ENODE ) GO TO 1400 C.ARITH.if IF ( NODE ) 1000, 2100, 1100 if ( NODE < 0 ) then GO TO 1000 else if ( NODE == 0 ) then GO TO 2100 else GO TO 1100 end if C 1100 CONTINUE IF ( QSIZE(NODE) .EQ. 0 ) GO TO 1400 IF ( MARKER(NODE) .GE. TAG ) GO TO 1200 C ------------------------------------- C CASE WHEN NODE IS NOT YET CONSIDERED. C ------------------------------------- MARKER(NODE) = TAG DEG = DEG + QSIZE(NODE) GO TO 1400 1200 CONTINUE C ---------------------------------------- C CASE WHEN NODE IS INDISTINGUISHABLE FROM C ENODE. MERGE THEM INTO A NEW SUPERNODE. C ---------------------------------------- IF ( DBAKW(NODE) .NE. 0 ) GO TO 1400 IF ( DFORW(NODE) .NE. 2 ) GO TO 1300 QSIZE(ENODE) = QSIZE(ENODE) + 1 QSIZE(NODE) QSIZE(NODE) = 0 MARKER(NODE) = MAXINT DFORW(NODE) = - ENODE DBAKW(NODE) = - MAXINT GO TO 1400 1300 CONTINUE C -------------------------------------- C CASE WHEN NODE IS OUTMATCHED BY ENODE. C -------------------------------------- IF ( DBAKW(NODE) .EQ.0 ) 1 DBAKW(NODE) = - MAXINT 1400 CONTINUE GO TO 2100 1500 CONTINUE C ------------------------------------------------ C FOR EACH ENODE IN THE QX LIST, DO THE FOLLOWING. C ------------------------------------------------ ENODE = QXHEAD IQ2 = 0 1600 CONTINUE IF ( ENODE .LE. 0 ) GO TO 2300 IF ( DBAKW(ENODE) .NE. 0 ) GO TO 2200 TAG = TAG + 1 DEG = DEG0 C --------------------------------- C FOR EACH UNMARKED NABOR OF ENODE, C DO THE FOLLOWING. C --------------------------------- ISTRT = XADJ(ENODE) ISTOP = XADJ(ENODE+1) - 1 DO 2000 I = ISTRT, ISTOP NABOR = ADJNCY(I) IF ( NABOR .EQ. 0 ) GO TO 2100 IF ( MARKER(NABOR) .GE. TAG ) GO TO 2000 MARKER(NABOR) = TAG LINK = NABOR C ------------------------------ C IF UNELIMINATED, INCLUDE IT IN C DEG COUNT. C ------------------------------ IF ( DFORW(NABOR) .LT. 0 ) GO TO 1700 DEG = DEG + QSIZE(NABOR) GO TO 2000 1700 CONTINUE C ------------------------------- C IF ELIMINATED, INCLUDE UNMARKED C NODES IN THIS ELEMENT INTO THE C DEGREE COUNT. C ------------------------------- JSTRT = XADJ(LINK) JSTOP = XADJ(LINK+1) - 1 DO 1900 J = JSTRT, JSTOP NODE = ADJNCY(J) LINK = - NODE C if ( NODE < 0 ) then GO TO 1700 else if ( NODE == 0 ) then GO TO 2000 else GO TO 1800 end if C 1800 CONTINUE IF ( MARKER(NODE) .GE. TAG ) 1 GO TO 1900 MARKER(NODE) = TAG DEG = DEG + QSIZE(NODE) 1900 CONTINUE 2000 CONTINUE 2100 CONTINUE C ------------------------------------------- C UPDATE EXTERNAL DEGREE OF ENODE IN DEGREE C STRUCTURE, AND MDEG (MIN DEG) IF NECESSARY. C ------------------------------------------- DEG = DEG - QSIZE(ENODE) + 1 FNODE = DHEAD(DEG) DFORW(ENODE) = FNODE DBAKW(ENODE) = - DEG IF ( FNODE .GT. 0 ) DBAKW(FNODE) = ENODE DHEAD(DEG) = ENODE IF ( DEG .LT. MDEG ) MDEG = DEG 2200 CONTINUE C ---------------------------------- C GET NEXT ENODE IN CURRENT ELEMENT. C ---------------------------------- ENODE = LLIST(ENODE) IF ( IQ2 .EQ. 1 ) GO TO 900 GO TO 1600 2300 CONTINUE C ----------------------------- C GET NEXT ELEMENT IN THE LIST. C ----------------------------- TAG = MTAG ELMNT = LLIST(ELMNT) GO TO 100 C END C*********************************************************************** C*********************************************************************** C C Version: 0.4 C Last modified: December 27, 1994 C Authors: Esmond G. Ng and Barry W. Peyton C RF: modified mmpy8 dependence C C Mathematical Sciences Section, Oak Ridge National Laboratory C C*********************************************************************** C*********************************************************************** C************** MMPY .... MATRIX-MATRIX MULTIPLY ************** C*********************************************************************** C*********************************************************************** C C PURPOSE - C THIS ROUTINE PERFORMS A MATRIX-MATRIX MULTIPLY, Y = Y + XA, C ASSUMING DATA STRUCTURES USED IN SOME OF OUR SPARSE CHOLESKY C CODES. C C INPUT PARAMETERS - C M - NUMBER OF ROWS IN X AND IN Y. C N - NUMBER OF COLUMNS IN X AND NUMBER OF ROWS C IN A. C Q - NUMBER OF COLUMNS IN A AND Y. C SPLIT(*) - BLOCK PARTITIONING OF X. C XPNT(*) - XPNT(J+1) POINTS ONE LOCATION BEYOND THE C END OF THE J-TH COLUMN OF X. XPNT IS ALSO C USED TO ACCESS THE ROWS OF A. C X(*) - CONTAINS THE COLUMNS OF X AND THE ROWS OF A. C LDY - LENGTH OF FIRST COLUMN OF Y. C C EXTERNAL ROUTINES: C MMPYN - MATRIX-MATRIX MULTIPLY, C WITH LEVEL 8 LOOP UNROLLING. C C UPDATED PARAMETERS - C Y(*) - ON OUTPUT, Y = Y + AX. C C*********************************************************************** C SUBROUTINE MMPY ( M , N , Q , SPLIT , XPNT , & X , Y , LDY ) C C*********************************************************************** C C ----------- C PARAMETERS. C ----------- C EXTERNAL MMPY8 INTEGER LDY , M , N , Q INTEGER SPLIT(*) , XPNT(*) DOUBLE PRECISION X(*) , Y(*) C C ---------------- C LOCAL VARIABLES. C ---------------- C INTEGER BLK , FSTCOL, NN C C*********************************************************************** C BLK = 1 FSTCOL = 1 100 CONTINUE IF ( FSTCOL .LE. N ) THEN NN = SPLIT(BLK) CALL MMPY8 ( M, NN, Q, XPNT(FSTCOL), X, Y, LDY ) FSTCOL = FSTCOL + NN BLK = BLK + 1 GO TO 100 ENDIF RETURN C END C*********************************************************************** C*********************************************************************** C C Version: 0.4 C Last modified: May 26, 1995 C Authors: Esmond G. Ng, Barry W. Peyton, and Guodong Zhang C C Mathematical Sciences Section, Oak Ridge National Laboratory C C*********************************************************************** C*********************************************************************** C************* MMPY8 .... MATRIX-MATRIX MULTIPLY ************** C*********************************************************************** C*********************************************************************** C C PURPOSE - C THIS ROUTINE PERFORMS A MATRIX-MATRIX MULTIPLY, Y = Y + XA, C ASSUMING DATA STRUCTURES USED IN SOME OF OUR SPARSE CHOLESKY C CODES. C C LOOP UNROLLING: LEVEL 8 UPDATING TWO COLUMNS AT A TIME C C INPUT PARAMETERS - C M - NUMBER OF ROWS IN X AND IN Y. C N - NUMBER OF COLUMNS IN X AND NUMBER OF ROWS C IN A. C Q - NUMBER OF COLUMNS IN A AND Y. C XPNT(*) - XPNT(J+1) POINTS ONE LOCATION BEYOND THE C END OF THE J-TH COLUMN OF X. XPNT IS ALSO C USED TO ACCESS THE ROWS OF A. C X(*) - CONTAINS THE COLUMNS OF X AND THE ROWS OF A. C LDY - LENGTH OF FIRST COLUMN OF Y. C C UPDATED PARAMETERS - C Y(*) - ON OUTPUT, Y = Y + AX. C C*********************************************************************** C SUBROUTINE MMPY8 ( M , N , Q , XPNT , X , & Y , LDY ) C C*********************************************************************** C C ----------- C PARAMETERS. C ----------- C INTEGER LDY , M , N , Q INTEGER XPNT(*) DOUBLE PRECISION X(*) , Y(*) C C ---------------- C LOCAL VARIABLES. C ---------------- C INTEGER I , J , K , QQ INTEGER I1 , I2 , I3 , I4 , I5 , & I6 , I7 , I8 INTEGER IYBEG , IYBEG1, IYBEG2, LENY , MM DOUBLE PRECISION A1 , A2 , A3 , A4 , A5 , & A6 , A7 , A8 , A9 , A10 , & A11 , A12 , A13 , A14 , A15 , & A16 DOUBLE PRECISION B1 , B2 , B3 , B4 , B5 , & B6 , B7 , B8 , Y1 , Y2 C C*********************************************************************** C C ---------------------------------------------------- C COMPUTE EACH DIAGONAL ENTRY OF THE ODD COLUMNS OF Y. C ---------------------------------------------------- C MM = M QQ = MIN(M,Q) IYBEG = 1 LENY = LDY - 1 do J = 1, QQ-1 , 2 CDIR$ IVDEP do I = 1, N I1 = XPNT(I+1) - MM A1 = X(I1) Y(IYBEG) = Y(IYBEG) - A1*A1 end do IYBEG = IYBEG + 2*LENY + 1 LENY = LENY - 2 MM = MM - 2 end do C C ------------------------------------------------------- C UPDATE TWO COLUMNS OF Y AT A TIME, EXCEPT THE DIAGONAL C ELEMENT. C NOTE: THE DIAGONAL ELEMENT OF THE ODD COLUMN HAS C BEEN COMPUTED, SO WE COMPUTE THE SAME NUMBER OF C ELEMENTS FOR THE TWO COLUMNS. C ------------------------------------------------------- C MM = M IYBEG = 1 LENY = LDY - 1 C do J = 1, QQ-1, 2 C IYBEG1 = IYBEG IYBEG2 = IYBEG + LENY C do K = 1, N-7, 8 C C ----------------------------------- C EIGHT COLUMNS UPDATING TWO COLUMNS. C ----------------------------------- C I1 = XPNT(K+1) - MM I2 = XPNT(K+2) - MM I3 = XPNT(K+3) - MM I4 = XPNT(K+4) - MM I5 = XPNT(K+5) - MM I6 = XPNT(K+6) - MM I7 = XPNT(K+7) - MM I8 = XPNT(K+8) - MM A1 = X(I1) A2 = X(I2) A3 = X(I3) A4 = X(I4) A5 = X(I5) A6 = X(I6) A7 = X(I7) A8 = X(I8) A9 = X(I1+1) A10 = X(I2+1) A11 = X(I3+1) A12 = X(I4+1) A13 = X(I5+1) A14 = X(I6+1) A15 = X(I7+1) A16 = X(I8+1) C Y(IYBEG1+1) = Y(IYBEG1+1) - & A1*A9 - A2*A10 - A3*A11 - A4*A12 - A5*A13 - & A6*A14 - A7*A15 - A8*A16 C Y(IYBEG2+1) = Y(IYBEG2+1) - & A9*A9 - A10*A10 - A11*A11 - A12*A12 - A13*A13 - & A14*A14 - A15*A15 - A16*A16 C do I = 2, MM-1 Y1 = Y(IYBEG1+I) B1 = X(I1+I) Y1 = Y1 - B1 * A1 Y2 = Y(IYBEG2+I) B2 = X(I2+I) Y2 = Y2 - B1 * A9 Y1 = Y1 - B2 * A2 B3 = X(I3+I) Y2 = Y2 - B2 * A10 Y1 = Y1 - B3 * A3 B4 = X(I4+I) Y2 = Y2 - B3 * A11 Y1 = Y1 - B4 * A4 B5 = X(I5+I) Y2 = Y2 - B4 * A12 Y1 = Y1 - B5 * A5 B6 = X(I6+I) Y2 = Y2 - B5 * A13 Y1 = Y1 - B6 * A6 B7 = X(I7+I) Y2 = Y2 - B6 * A14 Y1 = Y1 - B7 * A7 B8 = X(I8+I) Y2 = Y2 - B7 * A15 Y1 = Y1 - B8 * A8 Y(IYBEG1+I) = Y1 Y2 = Y2 - B8 * A16 Y(IYBEG2+I) = Y2 end do C end do C C ----------------------------- C BOUNDARY CODE FOR THE K LOOP. C ----------------------------- C SELECT CASE( N-K+2 ) CASE(1) GO TO 2000 CASE(2) GO TO 1700 CASE(3) GO TO 1500 CASE(4) GO TO 1300 CASE(5) GO TO 1100 CASE(6) GO TO 900 CASE(7) GO TO 700 CASE(8) GO TO 500 CASE DEFAULT GO TO 2000 END SELECT C 500 CONTINUE C C ----------------------------------- C SEVEN COLUMNS UPDATING TWO COLUMNS. C ----------------------------------- C I1 = XPNT(K+1) - MM I2 = XPNT(K+2) - MM I3 = XPNT(K+3) - MM I4 = XPNT(K+4) - MM I5 = XPNT(K+5) - MM I6 = XPNT(K+6) - MM I7 = XPNT(K+7) - MM A1 = X(I1) A2 = X(I2) A3 = X(I3) A4 = X(I4) A5 = X(I5) A6 = X(I6) A7 = X(I7) A9 = X(I1+1) A10 = X(I2+1) A11 = X(I3+1) A12 = X(I4+1) A13 = X(I5+1) A14 = X(I6+1) A15 = X(I7+1) C Y(IYBEG1+1) = Y(IYBEG1+1) - & A1*A9 - A2*A10 - A3*A11 - A4*A12 - A5*A13 - & A6*A14 - A7*A15 C Y(IYBEG2+1) = Y(IYBEG2+1) - & A9*A9 - A10*A10 - A11*A11 - A12*A12 - A13*A13 - & A14*A14 - A15*A15 C do I = 2, MM-1 Y1 = Y(IYBEG1+I) B1 = X(I1+I) Y1 = Y1 - B1 * A1 Y2 = Y(IYBEG2+I) B2 = X(I2+I) Y2 = Y2 - B1 * A9 Y1 = Y1 - B2 * A2 B3 = X(I3+I) Y2 = Y2 - B2 * A10 Y1 = Y1 - B3 * A3 B4 = X(I4+I) Y2 = Y2 - B3 * A11 Y1 = Y1 - B4 * A4 B5 = X(I5+I) Y2 = Y2 - B4 * A12 Y1 = Y1 - B5 * A5 B6 = X(I6+I) Y2 = Y2 - B5 * A13 Y1 = Y1 - B6 * A6 B7 = X(I7+I) Y2 = Y2 - B6 * A14 Y1 = Y1 - B7 * A7 Y(IYBEG1+I) = Y1 Y2 = Y2 - B7 * A15 Y(IYBEG2+I) = Y2 end do C GO TO 2000 C 700 CONTINUE C C --------------------------------- C SIX COLUMNS UPDATING TWO COLUMNS. C --------------------------------- C I1 = XPNT(K+1) - MM I2 = XPNT(K+2) - MM I3 = XPNT(K+3) - MM I4 = XPNT(K+4) - MM I5 = XPNT(K+5) - MM I6 = XPNT(K+6) - MM A1 = X(I1) A2 = X(I2) A3 = X(I3) A4 = X(I4) A5 = X(I5) A6 = X(I6) A9 = X(I1+1) A10 = X(I2+1) A11 = X(I3+1) A12 = X(I4+1) A13 = X(I5+1) A14 = X(I6+1) C Y(IYBEG1+1) = Y(IYBEG1+1) - & A1*A9 - A2*A10 - A3*A11 - A4*A12 - A5*A13 - & A6*A14 C Y(IYBEG2+1) = Y(IYBEG2+1) - & A9*A9 - A10*A10 - A11*A11 - A12*A12 - A13*A13 - & A14*A14 C do I = 2, MM-1 Y1 = Y(IYBEG1+I) B1 = X(I1+I) Y1 = Y1 - B1 * A1 Y2 = Y(IYBEG2+I) B2 = X(I2+I) Y2 = Y2 - B1 * A9 Y1 = Y1 - B2 * A2 B3 = X(I3+I) Y2 = Y2 - B2 * A10 Y1 = Y1 - B3 * A3 B4 = X(I4+I) Y2 = Y2 - B3 * A11 Y1 = Y1 - B4 * A4 B5 = X(I5+I) Y2 = Y2 - B4 * A12 Y1 = Y1 - B5 * A5 B6 = X(I6+I) Y2 = Y2 - B5 * A13 Y1 = Y1 - B6 * A6 Y(IYBEG1+I) = Y1 Y2 = Y2 - B6 * A14 Y(IYBEG2+I) = Y2 end do C GO TO 2000 C 900 CONTINUE C C ---------------------------------- C FIVE COLUMNS UPDATING TWO COLUMNS. C ---------------------------------- C I1 = XPNT(K+1) - MM I2 = XPNT(K+2) - MM I3 = XPNT(K+3) - MM I4 = XPNT(K+4) - MM I5 = XPNT(K+5) - MM A1 = X(I1) A2 = X(I2) A3 = X(I3) A4 = X(I4) A5 = X(I5) A9 = X(I1+1) A10 = X(I2+1) A11 = X(I3+1) A12 = X(I4+1) A13 = X(I5+1) C Y(IYBEG1+1) = Y(IYBEG1+1) - & A1*A9 - A2*A10 - A3*A11 - A4*A12 - A5*A13 C Y(IYBEG2+1) = Y(IYBEG2+1) - & A9*A9 - A10*A10 - A11*A11 - A12*A12 - A13*A13 C DO 1000 I = 2, MM-1 Y1 = Y(IYBEG1+I) B1 = X(I1+I) Y1 = Y1 - B1 * A1 Y2 = Y(IYBEG2+I) B2 = X(I2+I) Y2 = Y2 - B1 * A9 Y1 = Y1 - B2 * A2 B3 = X(I3+I) Y2 = Y2 - B2 * A10 Y1 = Y1 - B3 * A3 B4 = X(I4+I) Y2 = Y2 - B3 * A11 Y1 = Y1 - B4 * A4 B5 = X(I5+I) Y2 = Y2 - B4 * A12 Y1 = Y1 - B5 * A5 Y(IYBEG1+I) = Y1 Y2 = Y2 - B5 * A13 Y(IYBEG2+I) = Y2 1000 CONTINUE C GO TO 2000 C 1100 CONTINUE C C ---------------------------------- C FOUR COLUMNS UPDATING TWO COLUMNS. C ---------------------------------- C I1 = XPNT(K+1) - MM I2 = XPNT(K+2) - MM I3 = XPNT(K+3) - MM I4 = XPNT(K+4) - MM A1 = X(I1) A2 = X(I2) A3 = X(I3) A4 = X(I4) A9 = X(I1+1) A10 = X(I2+1) A11 = X(I3+1) A12 = X(I4+1) C Y(IYBEG1+1) = Y(IYBEG1+1) - & A1*A9 - A2*A10 - A3*A11 - A4*A12 C Y(IYBEG2+1) = Y(IYBEG2+1) - & A9*A9 - A10*A10 - A11*A11 - A12*A12 C DO 1200 I = 2, MM-1 Y1 = Y(IYBEG1+I) B1 = X(I1+I) Y1 = Y1 - B1 * A1 Y2 = Y(IYBEG2+I) B2 = X(I2+I) Y2 = Y2 - B1 * A9 Y1 = Y1 - B2 * A2 B3 = X(I3+I) Y2 = Y2 - B2 * A10 Y1 = Y1 - B3 * A3 B4 = X(I4+I) Y2 = Y2 - B3 * A11 Y1 = Y1 - B4 * A4 Y(IYBEG1+I) = Y1 Y2 = Y2 - B4 * A12 Y(IYBEG2+I) = Y2 1200 CONTINUE C GO TO 2000 C 1300 CONTINUE C C ----------------------------------- C THREE COLUMNS UPDATING TWO COLUMNS. C ----------------------------------- C I1 = XPNT(K+1) - MM I2 = XPNT(K+2) - MM I3 = XPNT(K+3) - MM A1 = X(I1) A2 = X(I2) A3 = X(I3) A9 = X(I1+1) A10 = X(I2+1) A11 = X(I3+1) C Y(IYBEG1+1) = Y(IYBEG1+1) - & A1*A9 - A2*A10 - A3*A11 C Y(IYBEG2+1) = Y(IYBEG2+1) - & A9*A9 - A10*A10 - A11*A11 C DO 1400 I = 2, MM-1 Y1 = Y(IYBEG1+I) B1 = X(I1+I) Y1 = Y1 - B1 * A1 Y2 = Y(IYBEG2+I) B2 = X(I2+I) Y2 = Y2 - B1 * A9 Y1 = Y1 - B2 * A2 B3 = X(I3+I) Y2 = Y2 - B2 * A10 Y1 = Y1 - B3 * A3 Y(IYBEG1+I) = Y1 Y2 = Y2 - B3 * A11 Y(IYBEG2+I) = Y2 1400 CONTINUE C GO TO 2000 C 1500 CONTINUE C C --------------------------------- C TWO COLUMNS UPDATING TWO COLUMNS. C --------------------------------- C I1 = XPNT(K+1) - MM I2 = XPNT(K+2) - MM A1 = X(I1) A2 = X(I2) A9 = X(I1+1) A10 = X(I2+1) C Y(IYBEG1+1) = Y(IYBEG1+1) - & A1*A9 - A2*A10 C Y(IYBEG2+1) = Y(IYBEG2+1) - & A9*A9 - A10*A10 C do I = 2, MM-1 Y1 = Y(IYBEG1+I) B1 = X(I1+I) Y1 = Y1 - B1 * A1 Y2 = Y(IYBEG2+I) B2 = X(I2+I) Y2 = Y2 - B1 * A9 Y1 = Y1 - B2 * A2 Y(IYBEG1+I) = Y1 Y2 = Y2 - B2 * A10 Y(IYBEG2+I) = Y2 end do C GO TO 2000 C 1700 CONTINUE C C -------------------------------- C ONE COLUMN UPDATING TWO COLUMNS. C -------------------------------- C I1 = XPNT(K+1) - MM A1 = X(I1) A9 = X(I1+1) C Y(IYBEG1+1) = Y(IYBEG1+1) - & A1*A9 C Y(IYBEG2+1) = Y(IYBEG2+1) - & A9*A9 C do I = 2, MM-1 Y1 = Y(IYBEG1+I) B1 = X(I1+I) Y1 = Y1 - B1 * A1 Y2 = Y(IYBEG2+I) Y(IYBEG1+I) = Y1 Y2 = Y2 - B1 * A9 Y(IYBEG2+I) = Y2 end do C GO TO 2000 C C ----------------------------------------------- C PREPARE FOR NEXT PAIR OF COLUMNS TO BE UPDATED. C ----------------------------------------------- C 2000 CONTINUE MM = MM - 2 IYBEG = IYBEG2 + LENY + 1 LENY = LENY - 2 C end do C C ----------------------------------------------------- C BOUNDARY CODE FOR J LOOP: EXECUTED WHENVER Q IS ODD. C ----------------------------------------------------- C IF ( J .EQ. QQ ) THEN CALL SMXPY8 ( MM, N, Y(IYBEG), XPNT, X ) ENDIF C RETURN END C*********************************************************************** C*********************************************************************** C C Version: 0.4 C Last modified: December 27, 1994 C Authors: Esmond G. Ng and Barry W. Peyton C C Mathematical Sciences Section, Oak Ridge National Laboratory C C*********************************************************************** C*********************************************************************** C************* MMPYI .... MATRIX-MATRIX MULTIPLY ************** C*********************************************************************** C*********************************************************************** C C PURPOSE - C THIS ROUTINE PERFORMS A MATRIX-MATRIX MULTIPLY, Y = Y + XA, C ASSUMING DATA STRUCTURES USED IN SOME OF OUR SPARSE CHOLESKY C CODES. C C MATRIX X HAS ONLY 1 COLUMN. C C INPUT PARAMETERS - C M - NUMBER OF ROWS IN X AND IN Y. C Q - NUMBER OF COLUMNS IN A AND Y. C XPNT(*) - XPNT(J+1) POINTS ONE LOCATION BEYOND THE C END OF THE J-TH COLUMN OF X. XPNT IS ALSO C USED TO ACCESS THE ROWS OF A. C X(*) - CONTAINS THE COLUMNS OF X AND THE ROWS OF A. C IY(*) - IY(COL) POINTS TO THE BEGINNING OF COLUMN C RELIND(*) - RELATIVE INDICES. C C UPDATED PARAMETERS - C Y(*) - ON OUTPUT, Y = Y + AX. C C*********************************************************************** C SUBROUTINE MMPYI ( M , Q , XPNT , X , IY , & Y , RELIND ) C C*********************************************************************** C C ----------- C PARAMETERS. C ----------- C INTEGER M , Q INTEGER IY(*) , RELIND(*) , & XPNT(*) DOUBLE PRECISION X(*) , Y(*) C C ---------------- C LOCAL VARIABLES. C ---------------- C INTEGER COL , I , ISUB , K , YLAST DOUBLE PRECISION A C C*********************************************************************** C DO 200 K = 1, Q COL = XPNT(K) YLAST = IY(COL+1) - 1 A = - X(K) CDIR$ IVDEP DO 100 I = K, M ISUB = XPNT(I) ISUB = YLAST - RELIND(ISUB) Y(ISUB) = Y(ISUB) + A*X(I) 100 CONTINUE 200 CONTINUE RETURN C END C*********************************************************************** C*********************************************************************** C C Version: 0.3 C Last modified: December 27, 1994 C Authors: Esmond G. Ng and Barry W. Peyton C C Mathematical Sciences Section, Oak Ridge National Laboratoy C C*********************************************************************** C*********************************************************************** C****** PCHOL .... DENSE PARTIAL CHOLESKY ************** C*********************************************************************** C*********************************************************************** C C PURPOSE - THIS ROUTINE PERFORMS CHOLESKY C FACTORIZATION ON THE COLUMNS OF A SUPERNODE C THAT HAVE RECEIVED ALL UPDATES FROM COLUMNS C EXTERNAL TO THE SUPERNODE. C C INPUT PARAMETERS - C M - NUMBER OF ROWS (LENGTH OF THE FIRST COLUMN). C N - NUMBER OF COLUMNS IN THE SUPERNODE. C XPNT - XPNT(J+1) POINTS ONE LOCATION BEYOND THE END C OF THE J-TH COLUMN OF THE SUPERNODE. C X(*) - CONTAINS THE COLUMNS OF OF THE SUPERNODE TO C BE FACTORED. C C EXTERNAL ROUTINE: C SMXPY8 - MATRIX-VECTOR MULTIPLY WITH 8 LOOP UNROLLING. C C OUTPUT PARAMETERS - C X(*) - ON OUTPUT, CONTAINS THE FACTORED COLUMNS OF C THE SUPERNODE. C C*********************************************************************** C SUBROUTINE PCHOL ( M, N, XPNT, X, MXDIAG, NTINY ) C C*********************************************************************** C C ----------- C PARAMETERS. C ----------- C EXTERNAL SMXPY8 C INTEGER M, N C INTEGER XPNT(*) C CxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPC DOUBLE PRECISION X(*), MXDIAG INTEGER NTINY C C ---------------- C LOCAL VARIABLES. C ---------------- C INTEGER JPNT , JCOL , MM C DOUBLE PRECISION DIAG C C*********************************************************************** C C ------------------------------------------ C FOR EVERY COLUMN JCOL IN THE SUPERNODE ... C ------------------------------------------ MM = M JPNT = XPNT(1) DO 100 JCOL = 1, N C C ---------------------------------- C UPDATE JCOL WITH PREVIOUS COLUMNS. C ---------------------------------- IF ( JCOL .GT. 1 ) THEN CALL SMXPY8 ( MM, JCOL-1, X(JPNT), XPNT, X ) ENDIF C C --------------------------- C COMPUTE THE DIAGONAL ENTRY. C --------------------------- DIAG = X(JPNT) CxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPC IF (DIAG .LE. 1.0D-30*MXDIAG) THEN DIAG = 1.0D+128 NTINY = NTINY+1 ENDIF CxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPCxPC DIAG = SQRT ( DIAG ) X(JPNT) = DIAG DIAG = 1.0D+00 / DIAG C C ---------------------------------------------------- C SCALE COLUMN JCOL WITH RECIPROCAL OF DIAGONAL ENTRY. C ---------------------------------------------------- MM = MM - 1 JPNT = JPNT + 1 CALL DSCAL1 ( MM, DIAG, X(JPNT) ) JPNT = JPNT + MM C 100 CONTINUE C RETURN END C*********************************************************************** C*********************************************************************** C C Version: 0.4 C Last modified: January 12, 1995 C Authors: Esmond G. Ng and Barry W. Peyton C C Mathematical Sciences Section, Oak Ridge National Laboratory C C*********************************************************************** C*********************************************************************** C************** SFINIT ..... SET UP FOR SYMB. FACT. ************ C*********************************************************************** C*********************************************************************** C C PURPOSE: C THIS SUBROUTINE COMPUTES THE STORAGE REQUIREMENTS AND SETS UP C PRELIMINARY DATA STRUCTURES FOR THE SYMBOLIC FACTORIZATION. C C NOTE: C THIS VERSION PRODUCES THE MAXIMAL SUPERNODE PARTITION (I.E., C THE ONE WITH THE FEWEST POSSIBLE SUPERNODES). C C INPUT PARAMETERS: C NEQNS - NUMBER OF EQUATIONS. C NNZA - LENGTH OF ADJACENCY STRUCTURE. C XADJ(*) - ARRAY OF LENGTH NEQNS+1, CONTAINING POINTERS C TO THE ADJACENCY STRUCTURE. C ADJNCY(*) - ARRAY OF LENGTH XADJ(NEQNS+1)-1, CONTAINING C THE ADJACENCY STRUCTURE. C PERM(*) - ARRAY OF LENGTH NEQNS, CONTAINING THE C POSTORDERING. C INVP(*) - ARRAY OF LENGTH NEQNS, CONTAINING THE C INVERSE OF THE POSTORDERING. C IWSIZ - SIZE OF INTEGER WORKING STORAGE. C C OUTPUT PARAMETERS: C COLCNT(*) - ARRAY OF LENGTH NEQNS, CONTAINING THE NUMBER C OF NONZEROS IN EACH COLUMN OF THE FACTOR, C INCLUDING THE DIAGONAL ENTRY. C NNZL - NUMBER OF NONZEROS IN THE FACTOR, INCLUDING C THE DIAGONAL ENTRIES. C NSUB - NUMBER OF SUBSCRIPTS. C NSUPER - NUMBER OF SUPERNODES (<= NEQNS). C SNODE(*) - ARRAY OF LENGTH NEQNS FOR RECORDING C SUPERNODE MEMBERSHIP. C XSUPER(*) - ARRAY OF LENGTH NEQNS+1, CONTAINING THE C SUPERNODE PARTITIONING. C IFLAG(*) - ERROR FLAG. C 0: SUCCESSFUL SF INITIALIZATION. C -1: INSUFFICENT WORKING STORAGE C [IWORK(*)]. C C WORK PARAMETERS: C IWORK(*) - INTEGER WORK ARRAY OF LENGTH 7*NEQNS+3. C C FIRST CREATED ON NOVEMEBER 14, 1994. C LAST UPDATED ON January 12, 1995. C C*********************************************************************** C SUBROUTINE SFINIT ( NEQNS , NNZA , XADJ , ADJNCY, PERM , & INVP , COLCNT, NNZL , NSUB , NSUPER, & SNODE , XSUPER, IWSIZ , IWORK , IFLAG ) C C ----------- C PARAMETERS. C ----------- INTEGER IFLAG , IWSIZ , NNZA , NEQNS , NNZL , & NSUB , NSUPER INTEGER ADJNCY(NNZA) , COLCNT(NEQNS) , & INVP(NEQNS) , IWORK(7*NEQNS+3), & PERM(NEQNS) , SNODE(NEQNS) , & XADJ(NEQNS+1) , XSUPER(NEQNS+1) C C*********************************************************************** C C -------------------------------------------------------- C RETURN IF THERE IS INSUFFICIENT INTEGER WORKING STORAGE. C -------------------------------------------------------- IFLAG = 0 IF ( IWSIZ .LT. 7*NEQNS+3 ) THEN IFLAG = -1 RETURN ENDIF C C ------------------------------------------ C COMPUTE ELIMINATION TREE AND POSTORDERING. C ------------------------------------------ CALL ETORDR ( NEQNS , XADJ , ADJNCY, PERM , INVP , & IWORK(1) , & IWORK(NEQNS+1) , & IWORK(2*NEQNS+1) , & IWORK(3*NEQNS+1) ) C C --------------------------------------------- C COMPUTE ROW AND COLUMN FACTOR NONZERO COUNTS. C --------------------------------------------- CALL FCNTHN ( NEQNS , NNZA , XADJ , ADJNCY, PERM , & INVP , IWORK(1) , SNODE , COLCNT, & NNZL , & IWORK(NEQNS+1) , & IWORK(2*NEQNS+1) , & XSUPER , & IWORK(3*NEQNS+1) , & IWORK(4*NEQNS+2) , & IWORK(5*NEQNS+3) , & IWORK(6*NEQNS+4) ) C C --------------------------------------------------------- C REARRANGE CHILDREN SO THAT THE LAST CHILD HAS THE MAXIMUM C NUMBER OF NONZEROS IN ITS COLUMN OF L. C --------------------------------------------------------- CALL CHORDR ( NEQNS , PERM , INVP , & COLCNT, & IWORK(1) , & IWORK(NEQNS+1) , & IWORK(2*NEQNS+1) , & IWORK(3*NEQNS+1) ) C C ---------------- C FIND SUPERNODES. C ---------------- CALL FSUP1 ( NEQNS , IWORK(1) , COLCNT, NSUB , & NSUPER, SNODE ) CALL FSUP2 ( NEQNS , NSUPER, SNODE, XSUPER ) C RETURN END C*********************************************************************** C*********************************************************************** C C Version: 0.4 C Last modified: December 27, 1994 C Authors: Esmond G. Ng and Barry W. Peyton C C Mathematical Sciences Section, Oak Ridge National Laboratory C C*********************************************************************** C*********************************************************************** C****** SMXPY8 .... MATRIX-VECTOR MULTIPLY ************** C*********************************************************************** C*********************************************************************** C C PURPOSE - THIS ROUTINE PERFORMS A MATRIX-VECTOR MULTIPLY, C Y = Y + AX, ASSUMING DATA STRUCTURES USED IN C RECENTLY DEVELOPED SPARSE CHOLESKY CODES. THE C '8' SIGNIFIES LEVEL 8 LOOP UNROLLING. C C INPUT PARAMETERS - C M - NUMBER OF ROWS. C N - NUMBER OF COLUMNS. C Y - M-VECTOR TO WHICH AX WILL BE ADDED. C APNT - INDEX VECTOR FOR A. APNT(I) POINTS TO THE C FIRST NONZERO IN COLUMN I OF A. C Y - ON OUTPUT, CONTAINS Y = Y + AX. C C*********************************************************************** C SUBROUTINE SMXPY8 ( M, N, Y, APNT, A ) C C*********************************************************************** C C ----------- C PARAMETERS. C ----------- C INTEGER M, N, LEVEL C INTEGER APNT(*) C DOUBLE PRECISION Y(*), A(*) C PARAMETER ( LEVEL = 8 ) C C ---------------- C LOCAL VARIABLES. C ---------------- C INTEGER I, I1, I2, I3, I4, I5, I6, I7, I8, & J, REMAIN C DOUBLE PRECISION A1, A2, A3, A4, A5, A6, A7, A8 C C*********************************************************************** C REMAIN = MOD ( N, LEVEL ) C SELECT CASE ( REMAIN+1 ) CASE(1) GO TO 2000 CASE(2) GO TO 100 CASE(3) GO TO 200 CASE(4) GO TO 300 CASE(5) GO TO 400 CASE(6) GO TO 500 CASE(7) GO TO 600 CASE(8) GO TO 700 CASE DEFAULT GO TO 2000 END SELECT C 100 CONTINUE I1 = APNT(1+1) - M A1 = - A(I1) DO 150 I = 1, M Y(I) = Y(I) + A1*A(I1) I1 = I1 + 1 150 CONTINUE GO TO 2000 C 200 CONTINUE I1 = APNT(1+1) - M I2 = APNT(1+2) - M A1 = - A(I1) A2 = - A(I2) DO 250 I = 1, M Y(I) = ( (Y(I)) & + A1*A(I1)) + A2*A(I2) I1 = I1 + 1 I2 = I2 + 1 250 CONTINUE GO TO 2000 C 300 CONTINUE I1 = APNT(1+1) - M I2 = APNT(1+2) - M I3 = APNT(1+3) - M A1 = - A(I1) A2 = - A(I2) A3 = - A(I3) DO 350 I = 1, M Y(I) = (( (Y(I)) & + A1*A(I1)) + A2*A(I2)) & + A3*A(I3) I1 = I1 + 1 I2 = I2 + 1 I3 = I3 + 1 350 CONTINUE GO TO 2000 C 400 CONTINUE I1 = APNT(1+1) - M I2 = APNT(1+2) - M I3 = APNT(1+3) - M I4 = APNT(1+4) - M A1 = - A(I1) A2 = - A(I2) A3 = - A(I3) A4 = - A(I4) DO 450 I = 1, M Y(I) = ((( (Y(I)) & + A1*A(I1)) + A2*A(I2)) & + A3*A(I3)) + A4*A(I4) I1 = I1 + 1 I2 = I2 + 1 I3 = I3 + 1 I4 = I4 + 1 450 CONTINUE GO TO 2000 C 500 CONTINUE I1 = APNT(1+1) - M I2 = APNT(1+2) - M I3 = APNT(1+3) - M I4 = APNT(1+4) - M I5 = APNT(1+5) - M A1 = - A(I1) A2 = - A(I2) A3 = - A(I3) A4 = - A(I4) A5 = - A(I5) DO 550 I = 1, M Y(I) = (((( (Y(I)) & + A1*A(I1)) + A2*A(I2)) & + A3*A(I3)) + A4*A(I4)) & + A5*A(I5) I1 = I1 + 1 I2 = I2 + 1 I3 = I3 + 1 I4 = I4 + 1 I5 = I5 + 1 550 CONTINUE GO TO 2000 C 600 CONTINUE I1 = APNT(1+1) - M I2 = APNT(1+2) - M I3 = APNT(1+3) - M I4 = APNT(1+4) - M I5 = APNT(1+5) - M I6 = APNT(1+6) - M A1 = - A(I1) A2 = - A(I2) A3 = - A(I3) A4 = - A(I4) A5 = - A(I5) A6 = - A(I6) DO 650 I = 1, M Y(I) = ((((( (Y(I)) & + A1*A(I1)) + A2*A(I2)) & + A3*A(I3)) + A4*A(I4)) & + A5*A(I5)) + A6*A(I6) I1 = I1 + 1 I2 = I2 + 1 I3 = I3 + 1 I4 = I4 + 1 I5 = I5 + 1 I6 = I6 + 1 650 CONTINUE GO TO 2000 C 700 CONTINUE I1 = APNT(1+1) - M I2 = APNT(1+2) - M I3 = APNT(1+3) - M I4 = APNT(1+4) - M I5 = APNT(1+5) - M I6 = APNT(1+6) - M I7 = APNT(1+7) - M A1 = - A(I1) A2 = - A(I2) A3 = - A(I3) A4 = - A(I4) A5 = - A(I5) A6 = - A(I6) A7 = - A(I7) DO 750 I = 1, M Y(I) = (((((( (Y(I)) & + A1*A(I1)) + A2*A(I2)) & + A3*A(I3)) + A4*A(I4)) & + A5*A(I5)) + A6*A(I6)) & + A7*A(I7) I1 = I1 + 1 I2 = I2 + 1 I3 = I3 + 1 I4 = I4 + 1 I5 = I5 + 1 I6 = I6 + 1 I7 = I7 + 1 750 CONTINUE GO TO 2000 C 2000 CONTINUE DO 4000 J = REMAIN+1, N, LEVEL I1 = APNT(J+1) - M I2 = APNT(J+2) - M I3 = APNT(J+3) - M I4 = APNT(J+4) - M I5 = APNT(J+5) - M I6 = APNT(J+6) - M I7 = APNT(J+7) - M I8 = APNT(J+8) - M A1 = - A(I1) A2 = - A(I2) A3 = - A(I3) A4 = - A(I4) A5 = - A(I5) A6 = - A(I6) A7 = - A(I7) A8 = - A(I8) DO 3000 I = 1, M Y(I) = ((((((( (Y(I)) & + A1*A(I1)) + A2*A(I2)) & + A3*A(I3)) + A4*A(I4)) & + A5*A(I5)) + A6*A(I6)) & + A7*A(I7)) + A8*A(I8) I1 = I1 + 1 I2 = I2 + 1 I3 = I3 + 1 I4 = I4 + 1 I5 = I5 + 1 I6 = I6 + 1 I7 = I7 + 1 I8 = I8 + 1 3000 CONTINUE 4000 CONTINUE C RETURN END C*********************************************************************** C*********************************************************************** C C Version: 0.4 C Last modified: February 13, 1995 C Authors: Esmond G. Ng and Barry W. Peyton C C Mathematical Sciences Section, Oak Ridge National Laboratory C C*********************************************************************** C*********************************************************************** C************* SYMFC2 ..... SYMBOLIC FACTORIZATION ************** C*********************************************************************** C*********************************************************************** C C PURPOSE: C THIS ROUTINE PERFORMS SUPERNODAL SYMBOLIC FACTORIZATION ON A C REORDERED LINEAR SYSTEM. IT ASSUMES ACCESS TO THE COLUMNS C COUNTS, SUPERNODE PARTITION, AND SUPERNODAL ELIMINATION TREE C ASSOCIATED WITH THE FACTOR MATRIX L. C C INPUT PARAMETERS: C (I) NEQNS - NUMBER OF EQUATIONS C (I) ADJLEN - LENGTH OF THE ADJACENCY LIST. C (I) XADJ(*) - ARRAY OF LENGTH NEQNS+1 CONTAINING POINTERS C TO THE ADJACENCY STRUCTURE. C (I) ADJNCY(*) - ARRAY OF LENGTH XADJ(NEQNS+1)-1 CONTAINING C THE ADJACENCY STRUCTURE. C (I) PERM(*) - ARRAY OF LENGTH NEQNS CONTAINING THE C POSTORDERING. C (I) INVP(*) - ARRAY OF LENGTH NEQNS CONTAINING THE C INVERSE OF THE POSTORDERING. C (I) COLCNT(*) - ARRAY OF LENGTH NEQNS, CONTAINING THE NUMBER C OF NONZEROS IN EACH COLUMN OF THE FACTOR, C INCLUDING THE DIAGONAL ENTRY. C (I) NSUPER - NUMBER OF SUPERNODES. C (I) XSUPER(*) - ARRAY OF LENGTH NSUPER+1, CONTAINING THE C FIRST COLUMN OF EACH SUPERNODE. C (I) SNODE(*) - ARRAY OF LENGTH NEQNS FOR RECORDING C SUPERNODE MEMBERSHIP. C (I) NOFSUB - NUMBER OF SUBSCRIPTS TO BE STORED IN C LINDX(*). C C OUTPUT PARAMETERS: C (I) XLINDX - ARRAY OF LENGTH NEQNS+1, CONTAINING POINTERS C INTO THE SUBSCRIPT VECTOR. C (I) LINDX - ARRAY OF LENGTH MAXSUB, CONTAINING THE C COMPRESSED SUBSCRIPTS. C (I) XLNZ - COLUMN POINTERS FOR L. C (I) FLAG - ERROR FLAG: C 0 - NO ERROR. C 1 - INCONSISTANCY IN THE INPUT. C C WORKING PARAMETERS: C (I) MRGLNK - ARRAY OF LENGTH NSUPER, CONTAINING THE C CHILDREN OF EACH SUPERNODE AS A LINKED LIST. C (I) RCHLNK - ARRAY OF LENGTH NEQNS+1, CONTAINING THE C CURRENT LINKED LIST OF MERGED INDICES (THE C "REACH" SET). C (I) MARKER - ARRAY OF LENGTH NEQNS USED TO MARK INDICES C AS THEY ARE INTRODUCED INTO EACH SUPERNODE'S C INDEX SET. C C*********************************************************************** C SUBROUTINE SYMFC2 ( NEQNS , ADJLEN, XADJ , ADJNCY, PERM , & INVP , COLCNT, NSUPER, XSUPER, SNODE , & NOFSUB, XLINDX, LINDX , XLNZ , MRGLNK, & RCHLNK, MARKER, FLAG ) C C*********************************************************************** C C ----------- C PARAMETERS. C ----------- INTEGER ADJLEN, FLAG , NEQNS , NOFSUB, NSUPER INTEGER ADJNCY(ADJLEN), COLCNT(NEQNS) , & INVP(NEQNS) , MARKER(NEQNS) , & MRGLNK(NSUPER), LINDX(NOFSUB) , & PERM(NEQNS) , RCHLNK(0:NEQNS), & SNODE(NEQNS) , XSUPER(NSUPER+1) INTEGER XADJ(NEQNS+1) , XLINDX(NSUPER+1), & XLNZ(NEQNS+1) C C ---------------- C LOCAL VARIABLES. C ---------------- INTEGER FSTCOL, HEAD , I , JNZBEG, JNZEND, & JPTR , JSUP , JWIDTH, KNZ , KNZBEG, & KNZEND, KPTR , KSUP , LENGTH, LSTCOL, & NEWI , NEXTI , NODE , NZBEG , NZEND , & PCOL , PSUP , POINT , TAIL , WIDTH C C*********************************************************************** C FLAG = 0 IF ( NEQNS .LE. 0 ) RETURN C C --------------------------------------------------- C INITIALIZATIONS ... C NZEND : POINTS TO THE LAST USED SLOT IN LINDX. C TAIL : END OF LIST INDICATOR C (IN RCHLNK(*), NOT MRGLNK(*)). C MRGLNK : CREATE EMPTY LISTS. C MARKER : "UNMARK" THE INDICES. C --------------------------------------------------- NZEND = 0 HEAD = 0 TAIL = NEQNS + 1 POINT = 1 DO 50 I = 1, NEQNS MARKER(I) = 0 XLNZ(I) = POINT POINT = POINT + COLCNT(I) 50 CONTINUE XLNZ(NEQNS+1) = POINT POINT = 1 DO 100 KSUP = 1, NSUPER MRGLNK(KSUP) = 0 FSTCOL = XSUPER(KSUP) XLINDX(KSUP) = POINT POINT = POINT + COLCNT(FSTCOL) 100 CONTINUE XLINDX(NSUPER+1) = POINT C C --------------------------- C FOR EACH SUPERNODE KSUP ... C --------------------------- DO 1000 KSUP = 1, NSUPER C C --------------------------------------------------------- C INITIALIZATIONS ... C FSTCOL : FIRST COLUMN OF SUPERNODE KSUP. C LSTCOL : LAST COLUMN OF SUPERNODE KSUP. C KNZ : WILL COUNT THE NONZEROS OF L IN COLUMN KCOL. C RCHLNK : INITIALIZE EMPTY INDEX LIST FOR KCOL. C --------------------------------------------------------- FSTCOL = XSUPER(KSUP) LSTCOL = XSUPER(KSUP+1) - 1 WIDTH = LSTCOL - FSTCOL + 1 LENGTH = COLCNT(FSTCOL) KNZ = 0 RCHLNK(HEAD) = TAIL JSUP = MRGLNK(KSUP) C C ------------------------------------------------- C IF KSUP HAS CHILDREN IN THE SUPERNODAL E-TREE ... C ------------------------------------------------- IF ( JSUP .GT. 0 ) THEN C --------------------------------------------- C COPY THE INDICES OF THE FIRST CHILD JSUP INTO C THE LINKED LIST, AND MARK EACH WITH THE VALUE C KSUP. C --------------------------------------------- JWIDTH = XSUPER(JSUP+1) - XSUPER(JSUP) JNZBEG = XLINDX(JSUP) + JWIDTH JNZEND = XLINDX(JSUP+1) - 1 DO 200 JPTR = JNZEND, JNZBEG, -1 NEWI = LINDX(JPTR) KNZ = KNZ+1 MARKER(NEWI) = KSUP RCHLNK(NEWI) = RCHLNK(HEAD) RCHLNK(HEAD) = NEWI 200 CONTINUE C ------------------------------------------ C FOR EACH SUBSEQUENT CHILD JSUP OF KSUP ... C ------------------------------------------ JSUP = MRGLNK(JSUP) 300 CONTINUE IF ( JSUP .NE. 0 .AND. KNZ .LT. LENGTH ) THEN C ---------------------------------------- C MERGE THE INDICES OF JSUP INTO THE LIST, C AND MARK NEW INDICES WITH VALUE KSUP. C ---------------------------------------- JWIDTH = XSUPER(JSUP+1) - XSUPER(JSUP) JNZBEG = XLINDX(JSUP) + JWIDTH JNZEND = XLINDX(JSUP+1) - 1 NEXTI = HEAD DO 500 JPTR = JNZBEG, JNZEND NEWI = LINDX(JPTR) 400 CONTINUE I = NEXTI NEXTI = RCHLNK(I) IF ( NEWI .GT. NEXTI ) GO TO 400 IF ( NEWI .LT. NEXTI ) THEN KNZ = KNZ+1 RCHLNK(I) = NEWI RCHLNK(NEWI) = NEXTI MARKER(NEWI) = KSUP NEXTI = NEWI ENDIF 500 CONTINUE JSUP = MRGLNK(JSUP) GO TO 300 ENDIF ENDIF C --------------------------------------------------- C STRUCTURE OF A(*,FSTCOL) HAS NOT BEEN EXAMINED YET. C "SORT" ITS STRUCTURE INTO THE LINKED LIST, C INSERTING ONLY THOSE INDICES NOT ALREADY IN THE C LIST. C --------------------------------------------------- IF ( KNZ .LT. LENGTH ) THEN NODE = PERM(FSTCOL) KNZBEG = XADJ(NODE) KNZEND = XADJ(NODE+1) - 1 DO 700 KPTR = KNZBEG, KNZEND NEWI = ADJNCY(KPTR) NEWI = INVP(NEWI) IF ( NEWI .GT. FSTCOL .AND. & MARKER(NEWI) .NE. KSUP ) THEN C -------------------------------- C POSITION AND INSERT NEWI IN LIST C AND MARK IT WITH KCOL. C -------------------------------- NEXTI = HEAD 600 CONTINUE I = NEXTI NEXTI = RCHLNK(I) IF ( NEWI .GT. NEXTI ) GO TO 600 KNZ = KNZ + 1 RCHLNK(I) = NEWI RCHLNK(NEWI) = NEXTI MARKER(NEWI) = KSUP ENDIF 700 CONTINUE ENDIF C ------------------------------------------------------------ C IF KSUP HAS NO CHILDREN, INSERT FSTCOL INTO THE LINKED LIST. C ------------------------------------------------------------ IF ( RCHLNK(HEAD) .NE. FSTCOL ) THEN RCHLNK(FSTCOL) = RCHLNK(HEAD) RCHLNK(HEAD) = FSTCOL KNZ = KNZ + 1 ENDIF C C -------------------------------------------- C COPY INDICES FROM LINKED LIST INTO LINDX(*). C -------------------------------------------- NZBEG = NZEND + 1 NZEND = NZEND + KNZ IF ( NZEND+1 .NE. XLINDX(KSUP+1) ) GO TO 8000 I = HEAD DO 800 KPTR = NZBEG, NZEND I = RCHLNK(I) LINDX(KPTR) = I 800 CONTINUE C C --------------------------------------------------- C IF KSUP HAS A PARENT, INSERT KSUP INTO ITS PARENT'S C "MERGE" LIST. C --------------------------------------------------- IF ( LENGTH .GT. WIDTH ) THEN PCOL = LINDX ( XLINDX(KSUP) + WIDTH ) PSUP = SNODE(PCOL) MRGLNK(KSUP) = MRGLNK(PSUP) MRGLNK(PSUP) = KSUP ENDIF C 1000 CONTINUE C RETURN C C ----------------------------------------------- C INCONSISTENCY IN DATA STRUCTURE WAS DISCOVERED. C ----------------------------------------------- 8000 CONTINUE FLAG = -2 RETURN C END subroutine genrcm ( node_num, adj_num, adj_row, adj, perm ) !*****************************************************************************80 ! !! GENRCM finds the reverse Cuthill-Mckee ordering for a general graph. ! ! Discussion: ! ! For each connected component in the graph, the routine obtains ! an ordering by calling RCM. ! ! Modified: ! ! 04 January 2003 ! ! Author: ! ! Alan George, Joseph Liu ! FORTRAN90 version by John Burkardt ! ! Reference: ! ! Alan George, Joseph Liu, ! Computer Solution of Large Sparse Positive Definite Systems, ! Prentice Hall, 1981. ! ! Parameters: ! ! Input, integer NODE_NUM, the number of nodes. ! ! Input, integer ADJ_NUM, the number of adjacency entries. ! ! Input, integer ADJ_ROW(NODE_NUM+1). Information about row I is stored ! in entries ADJ_ROW(I) through ADJ_ROW(I+1)-1 of ADJ. ! ! Input, integer ADJ(ADJ_NUM), the adjacency structure. ! For each row, it contains the column indices of the nonzero entries. ! ! Output, integer PERM(NODE_NUM), the RCM ordering. ! ! Local Parameters: ! ! Local, integer LEVEL_ROW(NODE_NUM+1), the index vector for a level ! structure. The level structure is stored in the currently unused ! spaces in the permutation vector PERM. ! ! Local, integer MASK(NODE_NUM), marks variables that have been numbered. ! implicit none integer adj_num,node_num integer adj(adj_num) integer adj_row(node_num+1) integer i integer iccsze integer mask(node_num) integer level_num integer level_row(node_num+1) integer num integer perm(node_num) integer root do i=1,node_num mask(i) = 1 enddo num = 1 do i = 1, node_num ! ! For each masked connected component... ! if ( mask(i).ne. 0 ) then root = i ! ! Find a pseudo-peripheral node ROOT. The level structure found by ! ROOT_FIND is stored starting at PERM(NUM). ! call root_find ( root, adj_num, adj_row, adj, mask, & level_num, level_row, perm(num), node_num ) ! ! RCM orders the component using ROOT as the starting node. ! call rcm ( root, adj_num, adj_row, adj, mask, perm(num), & iccsze, node_num ) num = num + iccsze ! ! We can stop once every node is in one of the connected components. ! if ( node_num .lt. num ) then return endif endif enddo return end subroutine rcm ( root, adj_num, adj_row, adj, mask, perm, iccsze, & node_num ) !*****************************************************************************80 ! !! RCM renumbers a connected component by the reverse Cuthill McKee algorithm. ! ! Discussion: ! ! The connected component is specified by a node ROOT and a mask. ! The numbering starts at the root node. ! ! An outline of the algorithm is as follows: ! ! X(1) = ROOT. ! ! for ( I = 1 to N-1) ! Find all unlabeled neighbors of X(I), ! assign them the next available labels, in order of increasing degree. ! ! When done, reverse the ordering. ! ! Modified: ! ! 02 January 2007 ! ! Author: ! ! Alan George, Joseph Liu ! FORTRAN90 version by John Burkardt ! ! Reference: ! ! Alan George, Joseph Liu, ! Computer Solution of Large Sparse Positive Definite Systems, ! Prentice Hall, 1981. ! ! Parameters: ! ! Input, integer ROOT, the node that defines the connected component. ! It is used as the starting point for the RCM ordering. ! ! Input, integer ADJ_NUM, the number of adjacency entries. ! ! Input, integer ADJ_ROW(NODE_NUM+1). Information about row I is stored ! in entries ADJ_ROW(I) through ADJ_ROW(I+1)-1 of ADJ. ! ! Input, integer ADJ(ADJ_NUM), the adjacency structure. ! For each row, it contains the column indices of the nonzero entries. ! ! Input/output, integer MASK(NODE_NUM), a mask for the nodes. Only ! those nodes with nonzero input mask values are considered by the ! routine. The nodes numbered by RCM will have their mask values ! set to zero. ! ! Output, integer PERM(NODE_NUM), the RCM ordering. ! ! Output, integer ICCSZE, the size of the connected component ! that has been numbered. ! ! Input, integer NODE_NUM, the number of nodes. ! ! Local Parameters: ! ! Workspace, integer DEG(NODE_NUM), a temporary vector used to hold ! the degree of the nodes in the section graph specified by mask and root. ! implicit none integer adj_num integer node_num integer adj(adj_num) integer adj_row(node_num+1) integer deg(node_num) integer fnbr integer i integer iccsze integer j integer jstop integer jstrt integer k integer l integer lbegin integer lnbr integer lperm integer lvlend integer mask(node_num) integer nbr integer node integer perm(node_num) integer root ! ! Find the degrees of the nodes in the component specified by MASK and ROOT. ! call degree ( root, adj_num, adj_row, adj, mask, deg, iccsze, & perm, node_num ) mask(root) = 0 if ( iccsze .le. 1 ) then return end if lvlend = 0 lnbr = 1 ! ! LBEGIN and LVLEND point to the beginning and ! the end of the current level respectively. ! do while ( lvlend .lt. lnbr ) lbegin = lvlend + 1 lvlend = lnbr do i = lbegin, lvlend ! ! For each node in the current level... ! node = perm(i) jstrt = adj_row(node) jstop = adj_row(node+1) - 1 ! ! Find the unnumbered neighbors of NODE. ! ! FNBR and LNBR point to the first and last neighbors ! of the current node in PERM. ! fnbr = lnbr + 1 do j = jstrt, jstop nbr = adj(j) if ( mask(nbr) .ne. 0 ) then lnbr = lnbr + 1 mask(nbr) = 0 perm(lnbr) = nbr end if end do ! ! If no neighbors, skip to next node in this level. ! cc if ( lnbr .le. fnbr ) then cc cycle cc end if if ( lnbr .gt. fnbr ) then ! ! Sort the neighbors of NODE in increasing order by degree. ! Linear insertion is used. ! k = fnbr do while ( k .lt. lnbr ) l = k k = k + 1 nbr = perm(k) do while ( fnbr .lt. l ) lperm = perm(l) if ( deg(lperm) .le. deg(nbr) ) then exit end if perm(l+1) = lperm l = l - 1 end do perm(l+1) = nbr end do end if end do end do ! ! We now have the Cuthill-McKee ordering. Reverse it. ! k=iccsze/2 l=iccsze do i=1,k lperm=perm(l) perm(l)=perm(i) perm(i)=lperm l=l-1 enddo return end subroutine root_find ( root, adj_num, adj_row, adj, mask, & level_num, level_row, level, node_num ) !*****************************************************************************80 ! !! ROOT_FIND finds a pseudo-peripheral node. ! ! Discussion: ! ! The diameter of a graph is the maximum distance (number of edges) ! between any two nodes of the graph. ! ! The eccentricity of a node is the maximum distance between that ! node and any other node of the graph. ! ! A peripheral node is a node whose eccentricity equals the ! diameter of the graph. ! ! A pseudo-peripheral node is an approximation to a peripheral node; ! it may be a peripheral node, but all we know is that we tried our ! best. ! ! The routine is given a graph, and seeks pseudo-peripheral nodes, ! using a modified version of the scheme of Gibbs, Poole and ! Stockmeyer. It determines such a node for the section subgraph ! specified by MASK and ROOT. ! ! The routine also determines the level structure associated with ! the given pseudo-peripheral node; that is, how far each node ! is from the pseudo-peripheral node. The level structure is ! returned as a list of nodes LS, and pointers to the beginning ! of the list of nodes that are at a distance of 0, 1, 2, ..., ! NODE_NUM-1 from the pseudo-peripheral node. ! ! Modified: ! ! 28 October 2003 ! ! Author: ! ! Alan George, Joseph Liu ! FORTRAN90 version by John Burkardt ! ! Reference: ! ! Alan George, Joseph Liu, ! Computer Solution of Large Sparse Positive Definite Systems, ! Prentice Hall, 1981. ! ! Norman Gibbs, William Poole, Paul Stockmeyer, ! An Algorithm for Reducing the Bandwidth and Profile of a Sparse Matrix, ! SIAM Journal on Numerical Analysis, ! Volume 13, pages 236-250, 1976. ! ! Norman Gibbs, ! Algorithm 509: A Hybrid Profile Reduction Algorithm, ! ACM Transactions on Mathematical Software, ! Volume 2, pages 378-387, 1976. ! ! Parameters: ! ! Input/output, integer ROOT. On input, ROOT is a node in the ! the component of the graph for which a pseudo-peripheral node is ! sought. On output, ROOT is the pseudo-peripheral node obtained. ! ! Input, integer ADJ_NUM, the number of adjacency entries. ! ! Input, integer ADJ_ROW(NODE_NUM+1). Information about row I is stored ! in entries ADJ_ROW(I) through ADJ_ROW(I+1)-1 of ADJ. ! ! Input, integer ADJ(ADJ_NUM), the adjacency structure. ! For each row, it contains the column indices of the nonzero entries. ! ! Input, integer MASK(NODE_NUM), specifies a section subgraph. Nodes ! for which MASK is zero are ignored by FNROOT. ! ! Output, integer LEVEL_NUM, is the number of levels in the level structure ! rooted at the node ROOT. ! ! Output, integer LEVEL_ROW(NODE_NUM+1), LEVEL(NODE_NUM), the ! level structure array pair containing the level structure found. ! ! Input, integer NODE_NUM, the number of nodes. ! implicit none integer adj_num integer node_num integer adj(adj_num) integer adj_row(node_num+1) integer iccsze integer j integer jstrt integer k integer kstop integer kstrt integer level(node_num) integer level_num integer level_num2 integer level_row(node_num+1) integer mask(node_num) integer mindeg integer nabor integer ndeg integer node integer root ! ! Determine the level structure rooted at ROOT. ! call level_set ( root, adj_num, adj_row, adj, mask, level_num, & level_row, level, node_num ) ! ! Count the number of nodes in this level structure. ! iccsze = level_row(level_num+1) - 1 ! ! Extreme case: ! A complete graph has a level set of only a single level. ! Every node is equally good (or bad). ! if ( level_num .eq. 1 ) then return end if ! ! Extreme case: ! A "line graph" 0--0--0--0--0 has every node in its only level. ! By chance, we've stumbled on the ideal root. ! if ( level_num .eq. iccsze ) then return end if ! ! Pick any node from the last level that has minimum degree ! as the starting point to generate a new level set. ! do mindeg = iccsze jstrt = level_row(level_num) root = level(jstrt) if ( jstrt .lt. iccsze ) then do j = jstrt, iccsze node = level(j) ndeg = 0 kstrt = adj_row(node) kstop = adj_row(node+1) - 1 do k = kstrt, kstop nabor = adj(k) if ( 0 .lt. mask(nabor) ) then ndeg = ndeg + 1 end if end do if ( ndeg .lt. mindeg ) then root = node mindeg = ndeg end if end do end if ! ! Generate the rooted level structure associated with this node. ! call level_set ( root, adj_num, adj_row, adj, mask, & level_num2, level_row, level, node_num ) ! ! If the number of levels did not increase, accept the new ROOT. ! if ( level_num2 .le. level_num ) then exit end if level_num = level_num2 ! ! In the unlikely case that ROOT is one endpoint of a line graph, ! we can exit now. ! if ( iccsze .le. level_num ) then exit end if end do return end subroutine level_set ( root, adj_num, adj_row, adj, mask, & level_num, level_row, level, node_num ) !*****************************************************************************80 ! !! LEVEL_SET generates the connected level structure rooted at a given node. ! ! Discussion: ! ! Only nodes for which MASK is nonzero will be considered. ! ! The root node chosen by the user is assigned level 1, and masked. ! All (unmasked) nodes reachable from a node in level 1 are ! assigned level 2 and masked. The process continues until there ! are no unmasked nodes adjacent to any node in the current level. ! The number of levels may vary between 2 and NODE_NUM. ! ! Modified: ! ! 28 October 2003 ! ! Author: ! ! Alan George, Joseph Liu ! FORTRAN90 version by John Burkardt ! ! Reference: ! ! Alan George, Joseph Liu, ! Computer Solution of Large Sparse Positive Definite Systems, ! Prentice Hall, 1981. ! ! Parameters: ! ! Input, integer ROOT, the node at which the level structure ! is to be rooted. ! ! Input, integer ADJ_NUM, the number of adjacency entries. ! ! Input, integer ADJ_ROW(NODE_NUM+1). Information about row I is stored ! in entries ADJ_ROW(I) through ADJ_ROW(I+1)-1 of ADJ. ! ! Input, integer ADJ(ADJ_NUM), the adjacency structure. ! For each row, it contains the column indices of the nonzero entries. ! ! Input/output, integer MASK(NODE_NUM). On input, only nodes with nonzero ! MASK are to be processed. On output, those nodes which were included ! in the level set have MASK set to 1. ! ! Output, integer LEVEL_NUM, the number of levels in the level ! structure. ROOT is in level 1. The neighbors of ROOT ! are in level 2, and so on. ! ! Output, integer LEVEL_ROW(NODE_NUM+1), LEVEL(NODE_NUM), the rooted ! level structure. ! ! Input, integer NODE_NUM, the number of nodes. ! implicit none integer adj_num integer node_num integer adj(adj_num) integer adj_row(node_num+1) integer i integer iccsze integer j integer jstop integer jstrt integer lbegin integer level_num integer level_row(node_num+1) integer level(node_num) integer lvlend integer lvsize integer mask(node_num) integer nbr integer node integer root mask(root) = 0 level(1) = root level_num = 0 lvlend = 0 iccsze = 1 ! ! LBEGIN is the pointer to the beginning of the current level, and ! LVLEND points to the end of this level. ! do lbegin = lvlend + 1 lvlend = iccsze level_num = level_num + 1 level_row(level_num) = lbegin ! ! Generate the next level by finding all the masked neighbors of nodes ! in the current level. ! do i = lbegin, lvlend node = level(i) jstrt = adj_row(node) jstop = adj_row(node+1) - 1 do j = jstrt, jstop nbr = adj(j) if ( mask(nbr) .ne. 0 ) then iccsze = iccsze + 1 level(iccsze) = nbr mask(nbr) = 0 end if end do end do ! ! Compute the current level width (the number of nodes encountered.) ! If it is positive, generate the next level. ! lvsize = iccsze - lvlend if ( lvsize .le. 0 ) then exit end if end do level_row(level_num+1) = lvlend + 1 ! ! Reset MASK to 1 for the nodes in the level structure. ! do i =1 ,iccsze mask(level(i)) = 1 enddo return end subroutine degree ( root, adj_num, adj_row, adj, mask, deg, & iccsze, ls, node_num ) !*****************************************************************************80 ! !! DEGREE computes the degrees of the nodes in the connected component. ! ! Discussion: ! ! The connected component is specified by MASK and ROOT. ! Nodes for which MASK is zero are ignored. ! ! Modified: ! ! 05 January 2003 ! ! Author: ! ! Alan George, Joseph Liu ! FORTRAN90 version by John Burkardt ! ! Reference: ! ! Alan George, Joseph Liu, ! Computer Solution of Large Sparse Positive Definite Systems, ! Prentice Hall, 1981. ! ! Parameters: ! ! Input, integer ROOT, the node that defines the connected component. ! ! Input, integer ADJ_NUM, the number of adjacency entries. ! ! Input, integer ADJ_ROW(NODE_NUM+1). Information about row I is stored ! in entries ADJ_ROW(I) through ADJ_ROW(I+1)-1 of ADJ. ! ! Input, integer ADJ(ADJ_NUM), the adjacency structure. ! For each row, it contains the column indices of the nonzero entries. ! ! Input, integer MASK(NODE_NUM), is nonzero for those nodes which are ! to be considered. ! ! Output, integer DEG(NODE_NUM), contains, for each node in the connected ! component, its degree. ! ! Output, integer ICCSIZE, the number of nodes in the connected component. ! ! Output, integer LS(NODE_NUM), stores in entries 1 through ICCSIZE the nodes ! in the connected component, starting with ROOT, and proceeding ! by levels. ! ! Input, integer NODE_NUM, the number of nodes. ! implicit none integer adj_num integer node_num integer adj(adj_num) integer adj_row(node_num+1) integer deg(node_num) integer i integer iccsze integer ideg integer j integer jstop integer jstrt integer lbegin integer ls(node_num) integer lvlend integer lvsize integer mask(node_num) integer nbr integer node integer root ! ! The sign of ADJ_ROW(I) is used to indicate if node I has been considered. ls(1) = root adj_row(root) = -adj_row(root) lvlend = 0 iccsze = 1 ! ! LBEGIN is the pointer to the beginning of the current level, and ! LVLEND points to the end of this level. do lbegin = lvlend + 1 lvlend = iccsze ! ! Find the degrees of nodes in the current level, ! and at the same time, generate the next level. do i = lbegin, lvlend node = ls(i) jstrt = -adj_row(node) jstop = abs ( adj_row(node+1) ) - 1 ideg = 0 do j = jstrt, jstop nbr = adj(j) if ( mask(nbr) .ne. 0 ) then ideg = ideg + 1 if ( 0 .le. adj_row(nbr) ) then adj_row(nbr) = -adj_row(nbr) iccsze = iccsze + 1 ls(iccsze) = nbr end if end if end do deg(node) = ideg end do ! ! Compute the current level width. lvsize = iccsze - lvlend ! ! If the current level width is nonzero, generate another level. if ( lvsize .eq. 0 ) then exit end if end do ! ! Reset ADJ_ROW to its correct sign and return. do i = 1, iccsze node = ls(i) adj_row(node) = -adj_row(node) end do return end spam/src/dist.f0000644000176200001440000001732013574431374013131 0ustar liggesusersC closestdistXY, distance between x and x or between x and y C C C We have four distances implemented: C c("euclidean", "maximum", "minkowski", "greatcircle") C c In case we need the distance matrix between x and x, then the c following parameters are used as well: c if part=-1, lower tri, part=0 the entire matrix c part= 1, upper tri only. c only values smaller than eta are considered. c p power for minkowski double precision function euclid(x,y,p) implicit none double precision x,y,p p=p ! to avoid: Warning: Unused dummy argument 'p' at (1) euclid=(x-y)**2 return end double precision function minkowski(x,y,p) implicit none double precision x,y,p minkowski=abs(x-y)**p return end subroutine closestdist( ncol, x,nrowx, y, nrowy, & part, p, method, & eta, colindices, rowpointers, entries, nnz, iflag) implicit none double precision euclid, minkowski external euclid, minkowski integer ncol,nrowx, nrowy, nnz, method, part, iflag integer colindices(nnz), rowpointers(nrowx+1) double precision p, x(nrowx,ncol),y(nrowy,ncol) double precision eta, entries(nnz) if (method.eq.1) then p=2.0 call closestEdistXY( ncol, x,nrowx, y, nrowy, & part, p, euclid, & eta, colindices, rowpointers, entries, nnz, iflag) endif if (method.eq.2) then p=1.0 call closestMAXdistXY( ncol, x,nrowx, y, nrowy, & part, & eta, colindices, rowpointers, entries, nnz, iflag) endif if (method.eq.3) then call closestEdistXY( ncol, x,nrowx, y, nrowy, & part, p, minkowski, & eta, colindices, rowpointers, entries, nnz, iflag) endif if (method.eq.4) then call closestGCdistXY( x,nrowx, y, nrowy, & part, p, & eta, colindices, rowpointers, entries, nnz, iflag) endif return end subroutine closestEdistXY( ncol, x,xnrow, y, ynrow, & part, p, distfcn, & eta, colindices, rowpointers, entries, nnz, iflag) implicit none double precision distfcn external distfcn integer ncol,xnrow, ynrow, nnz, part,iflag integer colindices(nnz),rowpointers(xnrow+1) double precision p,x(xnrow,ncol), y(ynrow,ncol) double precision eta, entries(nnz) c local variables integer jja, i,j,k, jfrom, jto double precision etap, tmp,pinv etap=eta**p pinv=1/p jja=1 rowpointers(1)=1 jfrom = 1 jto = ynrow c cycle over all rows of x (independent of part) do i= 1,xnrow if (part .lt. 0) then jto = i endif if (part .gt. 0) then jfrom = i endif do 10 j = jfrom,jto c Start calculating the distance (until delta is exceeded) tmp = 0.0 do k = 1, ncol tmp = tmp + distfcn(x(i,k),y(j,k),p) if( tmp.gt.etap) goto 10 enddo c Delta is not exceeded. c in case nnz was too small, recall line to get a better estimate if( jja .gt. nnz) then iflag = i goto 20 endif colindices(jja) = j if (abs(p-2) .le. 0.D0) then entries(jja) = sqrt(tmp) else if (abs(p-1) .le. 0.D0) then entries(jja) = tmp else entries(jja) = tmp**pinv endif endif jja = jja + 1 10 continue rowpointers(i+1)=jja enddo if (part.gt.0) then rowpointers(xnrow+1)=jja endif nnz=jja-1 20 continue return end subroutine closestMAXdistXY( ncol, x,xnrow, y, ynrow, & part, & eta, colindices, rowpointers, entries, nnz, iflag) implicit none integer ncol,xnrow, ynrow, nnz, part,iflag integer colindices(nnz),rowpointers(xnrow+1) double precision x(xnrow,ncol), y(ynrow,ncol) double precision eta, entries(nnz) c local variables integer jja, i,j,k, jfrom, jto double precision tmp jja=1 rowpointers(1)=1 jfrom = 1 jto = ynrow do i= 1,xnrow if (part .lt. 0) then jto = i endif if (part .gt. 0) then jfrom = i endif do 10 j = jfrom,jto c Start calculating the distance tmp = 0.0 do k = 1, ncol tmp = max(tmp, abs(x(i,k)-y(j,k))) if( tmp.gt.eta) goto 10 enddo c Delta is not exceeded. c (i,j) has a distance smaller than eta. c in case nnz was too small, recall line to get a better estimate if( jja .gt. nnz) then iflag = i goto 20 endif colindices(jja) = j entries(jja) = tmp jja = jja + 1 10 continue rowpointers(i+1)=jja enddo if (part.gt.0) then rowpointers(xnrow+1)=jja endif nnz=jja-1 20 continue return end subroutine closestGCdistXY( x,nx, y, ny, & part,p, & eta, colindices, rowpointers, entries, nnz, iflag) implicit none integer nx, ny, nnz, colindices(nnz),rowpointers(nx+1) integer part, iflag double precision x(nx,2), y(ny,2), p, eta, entries(nnz) c local variables logical equi integer jja, i,j, jfrom, jto double precision etap, tmp, tmp1, tmp2 double precision rad, thres double precision scy12(ny), ccy12(ny), sy2(ny) double precision scx12, ccx12, sx2 parameter (rad = 0.01745329251994329) parameter (thres = 0.99999999999) c Great savings if we know that x=y. c Changes for archaic d... to ... trigonometric fcn if (p .lt. 0) then equi=.TRUE. p=-p else equi= .FALSE. endif jja=1 etap=cos(eta*rad) rowpointers(1)=1 jfrom = 1 jto = ny DO j=1,ny tmp1=y(j,1)*rad tmp2=y(j,2)*rad ccy12(j)=cos(tmp1)*cos(tmp2) scy12(j)=sin(tmp1)*cos(tmp2) sy2(j)=sin(tmp2) ENDDO do i= 1,nx c x2 is missing if equi=.TRUE. and we reuse the y stuff if (equi .eqv. .TRUE.) then ccx12=ccy12(i) scx12=scy12(i) sx2=sy2(i) else tmp1=x(i,1)*rad tmp2=x(i,2)*rad ccx12=cos(tmp1)*cos(tmp2) scx12=sin(tmp1)*cos(tmp2) sx2=sin(tmp2) endif if (part .lt. 0) then jto = i endif if (part .gt. 0) then jfrom = i endif do 10 j = jfrom,jto c Start calculating the distance tmp = ccx12 * ccy12(j) + scx12 * scy12(j) + sx2*sy2(j) if (tmp .lt. etap) goto 10 c Delta is not exceeded. c Due to numerical instabilities, we need the following... 0.15-2: c Patch suggested at code clinics. if (tmp .ge. thres) then tmp = 0.0 else tmp = acos( tmp) endif c (i,j) has a distance smaller than eta. c In case nnz was too small, recall line to get a better estimate if( jja .gt. nnz) then iflag = i goto 20 endif colindices(jja) = j entries(jja) = tmp*p jja = jja + 1 10 continue rowpointers(i+1)=jja enddo if (part.gt.0) then rowpointers(nx+1)=jja endif nnz=jja-1 20 continue return end spam/src/fromsparsekit.f0000644000176200001440000006662613574431374015074 0ustar liggesusersc----------------------------------------------------------------------- subroutine amask (nrow,ncol,a,ja,ia,jmask,imask, * c,jc,ic,nzmax,ierr) c--------------------------------------------------------------------- implicit none real(8) a(*),c(*) integer nrow, ncol integer ia(nrow+1),ja(*),jc(*),ic(nrow+1),jmask(*) integer imask(nrow+1), nzmax, ierr logical iw(ncol) c----------------------------------------------------------------------- c futher used variables integer k, len, ii, j, k1, k2 c----------------------------------------------------------------------- c This subroutine builds a sparse matrix from an input matrix by c extracting only elements in positions defined by the mask jmask, imask c----------------------------------------------------------------------- c On entry: c--------- c nrow = integer. row dimension of input matrix c ncol = integer. Column dimension of input matrix. c c a, c ja, c ia = matrix in Compressed Sparse Row format c c jmask, c imask = matrix defining mask (pattern only) stored in compressed c sparse row format. c c nzmax = length of arrays c and jc. see ierr. c c On return: c----------- c c a, ja, ia and jmask, imask are unchanged. c c c c jc, c ic = the output matrix in Compressed Sparse Row format. c c ierr = integer. serving as error message.c c ierr = 1 means normal return c ierr .gt. 1 means that amask stopped when processing c row number ierr, because there was not enough space in c c, jc according to the value of nzmax. c c work arrays: c------------- c iw = logical work array of length ncol. c c note: c------ the algorithm is in place: c, jc, ic can be the same as c a, ja, ia in which cas the code will overwrite the matrix c c on a, ja, ia c c----------------------------------------------------------------------- ierr = 0 len = 0 do 1 j=1, ncol iw(j) = .false. 1 continue c unpack the mask for row ii in iw do 100 ii=1, nrow c save pointer in order to be able to do things in place do 2 k=imask(ii), imask(ii+1)-1 iw(jmask(k)) = .true. 2 continue c add umasked elemnts of row ii k1 = ia(ii) k2 = ia(ii+1)-1 ic(ii) = len+1 do 200 k=k1,k2 j = ja(k) if (iw(j)) then len = len+1 if (len .gt. nzmax) then ierr = ii return endif jc(len) = j c(len) = a(k) endif 200 continue c do 3 k=imask(ii), imask(ii+1)-1 iw(jmask(k)) = .false. 3 continue 100 continue ic(nrow+1)=len+1 c return c-----end-of-amask ----------------------------------------------------- c----------------------------------------------------------------------- end c----------------------------------------------------------------------- subroutine aplsb1 (nrow,ncol,a,ja,ia,s,b,jb,ib,c,jc,ic, * nzmax,ierr) implicit none real(8) a(*), b(*), c(*), s integer nrow, ncol integer ja(*),jb(*),jc(*),ia(nrow+1),ib(nrow+1),ic(nrow+1) integer nzmax, ierr c----------------------------------------------------------------------- c further used vaeriables integer i, j1, j2, ka, kamax, kb, kbmax, kc c----------------------------------------------------------------------- c performs the operation C = A+s B for matrices in sorted CSR format. c the difference with aplsb is that the resulting matrix is such that c the elements of each row are sorted with increasing column indices in c each row, provided the original matrices are sorted in the same way. c----------------------------------------------------------------------- c on entry: c --------- c nrow = integer. The row dimension of A and B c ncol = integer. The column dimension of A and B. c c a, c ja, c ia = Matrix A in compressed sparse row format with entries sorted c c s = real. scalar factor for B. c c b, c jb, c ib = Matrix B in compressed sparse row format with entries sorted c ascendly in each row c c nzmax = integer. The length of the arrays c and jc. c amub will stop if the result matrix C has a number c of elements that exceeds exceeds nzmax. See ierr. c c on return: c---------- c c, c jc, c ic = resulting matrix C in compressed sparse row sparse format c with entries sorted ascendly in each row. c c ierr = integer. serving as error message. c ierr = 0 means normal return, c ierr .gt. 0 means that amub stopped while computing the c i-th row of C with i=ierr, because the number c of elements in C exceeds nzmax. c c Notes: c------- c this will not work if any of the two input matrices is not sorted c----------------------------------------------------------------------- ierr = 0 kc = 1 ic(1) = kc c c the following loop does a merge of two sparse rows + adds them. c do 6 i=1, nrow ka = ia(i) kb = ib(i) kamax = ia(i+1)-1 kbmax = ib(i+1)-1 5 continue c c this is a while -- do loop -- c if (ka .le. kamax .or. kb .le. kbmax) then c if (ka .le. kamax) then j1 = ja(ka) else c take j1 large enough that always j2 .lt. j1 j1 = ncol+1 endif if (kb .le. kbmax) then j2 = jb(kb) else c similarly take j2 large enough that always j1 .lt. j2 j2 = ncol+1 endif c c three cases c if (j1 .eq. j2) then c(kc) = a(ka)+s*b(kb) jc(kc) = j1 ka = ka+1 kb = kb+1 kc = kc+1 else if (j1 .lt. j2) then jc(kc) = j1 c(kc) = a(ka) ka = ka+1 kc = kc+1 else if (j1 .gt. j2) then jc(kc) = j2 c(kc) = s*b(kb) kb = kb+1 kc = kc+1 endif if (kc .gt. nzmax) goto 999 goto 5 c c end while loop c endif ic(i+1) = kc 6 continue return 999 ierr = i return c------------end-of-aplsb1 --------------------------------------------- c----------------------------------------------------------------------- end c subroutine submat (job,i1,i2,j1,j2,a,ja,ia,nr,nc,ao,jao,iao) implicit none integer job,i1,i2,j1,j2,nr,nc,ia(*),ja(*),jao(*),iao(*) real(8) a(*),ao(*) c----------------------------------------------------------------------- c further used variables integer i, ii, j, k, k1, k2, klen c----------------------------------------------------------------------- c extracts the submatrix A(i1:i2,j1:j2) and puts the result in c matrix ao,iao,jao c---- In place: ao,jao,iao may be the same as a,ja,ia. c-------------- c on input c--------- c n = row dimension of the matrix c i1,i2 = two integers with i2 .ge. i1 indicating the range of rows to be c extracted. c j1,j2 = two integers with j2 .ge. j1 indicating the range of columns c to be extracted. c * There is no checking whether the input values for i1, i2, j1, c j2 are between 1 and n. c a, c ja, c ia = matrix in compressed sparse row format. c c job = job indicator: if job .ne. 1 then the real values in a are NOT c extracted, only the column indices (i.e. data structure) are. c otherwise values as well as column indices are extracted... c c on output c-------------- c nr = number of rows of submatrix c nc = number of columns of submatrix c * if either of nr or nc is nonpositive the code will quit. c c ao, c jao,iao = extracted matrix in general sparse format with jao containing c the column indices,and iao being the pointer to the beginning c of the row,in arrays a,ja. c----------------------------------------------------------------------c c Y. Saad, Sep. 21 1989 c c----------------------------------------------------------------------c nr = i2-i1+1 nc = j2-j1+1 c if ( nr .le. 0 .or. nc .le. 0) return c klen = 0 c c simple procedure. proceeds row-wise... c do 100 i = 1,nr ii = i1+i-1 k1 = ia(ii) k2 = ia(ii+1)-1 iao(i) = klen+1 c----------------------------------------------------------------------- do 60 k=k1,k2 j = ja(k) if (j .ge. j1 .and. j .le. j2) then klen = klen+1 if (job .eq. 1) ao(klen) = a(k) jao(klen) = j - j1+1 endif 60 continue 100 continue iao(nr+1) = klen+1 return c------------end-of submat---------------------------------------------- c----------------------------------------------------------------------- end c subroutine amux (n, x, y, a,ja,ia) implicit none real(8) x(*), y(*), a(*) integer n, ja(*), ia(*) c----------------------------------------------------------------------- c A times a vector c----------------------------------------------------------------------- c multiplies a matrix by a vector using the dot product form c Matrix A is stored in compressed sparse row storage. c c on entry: c---------- c n = row dimension of A c x = real array of length equal to the column dimension of c the A matrix. c a, ja, c ia = input matrix in compressed sparse row format. c c on return: c----------- c y = real array of length n, containing the product y=Ax c c----------------------------------------------------------------------- c local variables c real(8) t integer i, k c----------------------------------------------------------------------- do 100 i = 1,n c c compute the inner product of row i with vector x c t = 0.0d0 do 99 k=ia(i), ia(i+1)-1 t = t + a(k)*x(ja(k)) 99 continue c c store result in y(i) c y(i) = t 100 continue c return c---------end-of-amux--------------------------------------------------- c----------------------------------------------------------------------- end c subroutine amubdg (nrow,ncol,ncolb,ja,ia,jb,ib,ndegr,nnz,iw) implicit none integer nrow, ncol, ncolb integer ja(*),jb(*),ia(nrow+1),ib(ncol+1) integer ndegr(nrow),iw(ncolb) integer nnz c----------------------------------------------------------------------- c further used variables integer ii, j, jc, jr, k, last, ldg c----------------------------------------------------------------------- c gets the number of nonzero elements in each row of A*B and the total c number of nonzero elements in A*B. c----------------------------------------------------------------------- c on entry: c -------- c c nrow = integer. row dimension of matrix A c ncol = integer. column dimension of matrix A = row dimension of c matrix B. c ncolb = integer. the colum dimension of the matrix B. c c ja, ia= row structure of input matrix A: ja = column indices of c the nonzero elements of A stored by rows. c ia = pointer to beginning of each row in ja. c c jb, ib= row structure of input matrix B: jb = column indices of c the nonzero elements of A stored by rows. c ib = pointer to beginning of each row in jb. c c on return: c --------- c ndegr = integer array of length nrow containing the degrees (i.e., c the number of nonzeros in each row of the matrix A * B c c nnz = total number of nonzero elements found in A * B c c work arrays: c------------- c iw = integer work array of length ncolb. c----------------------------------------------------------------------- do 1 k=1, ncolb iw(k) = 0 1 continue do 2 k=1, nrow ndegr(k) = 0 2 continue c c method used: Transp(A) * A = sum [over i=1, nrow] a(i)^T a(i) c where a(i) = i-th row of A. We must be careful not to add the c elements already accounted for. c c do 7 ii=1,nrow c c for each row of A c ldg = 0 c c end-of-linked list c last = -1 do 6 j = ia(ii),ia(ii+1)-1 c c row number to be added: c jr = ja(j) do 5 k=ib(jr),ib(jr+1)-1 jc = jb(k) if (iw(jc) .eq. 0) then c c add one element to the linked list c ldg = ldg + 1 iw(jc) = last last = jc endif 5 continue 6 continue ndegr(ii) = ldg c c reset iw to zero c do 61 k=1,ldg j = iw(last) iw(last) = 0 last = j 61 continue c----------------------------------------------------------------------- 7 continue c nnz = 0 do 8 ii=1, nrow nnz = nnz+ndegr(ii) 8 continue c return c---------------end-of-amubdg ------------------------------------------ c----------------------------------------------------------------------- end c subroutine amub (nrow,ncol,job,a,ja,ia,b,jb,ib, * c,jc,ic,nzmax,iw,ierr) implicit none real(8) a(*), b(*), c(*) integer nrow, ncol, job integer ja(*),jb(*),jc(*),ia(nrow+1),ib(*),ic(*),iw(ncol) integer nzmax, ierr c----------------------------------------------------------------------- c other used variables integer len, k, ka, kb, jpos, jcol, ii, jj, j c----------------------------------------------------------------------- c performs the matrix by matrix product C = A B c----------------------------------------------------------------------- c on entry: c --------- c nrow = integer. The row dimension of A = row dimension of C c ncol = integer. The column dimension of B = column dimension of C c job = integer. Job indicator. When job = 0, only the structure c (i.e. the arrays jc, ic) is computed and the c real values are ignored. c c a, c ja, c ia = Matrix A in compressed sparse row format. c c b, c jb, c ib = Matrix B in compressed sparse row format. c c nzmax = integer. The length of the arrays c and jc. c amub will stop if the result matrix C has a number c of elements that exceeds exceeds nzmax. See ierr. c c on return: c---------- c c, c jc, c ic = resulting matrix C in compressed sparse row sparse format. c c ierr = integer. serving as error message. c ierr = 0 means normal return, c ierr .gt. 0 means that amub stopped while computing the c i-th row of C with i=ierr, because the number c of elements in C exceeds nzmax. c c work arrays: c------------ c iw = integer work array of length equal to the number of c columns in A. c Note: c------- c The row dimension of B is not needed. However there is no checking c on the condition that ncol(A) = nrow(B). c c----------------------------------------------------------------------- real(8) scal logical values values = (job .ne. 0) c the following is not necessary... keep [-Wmaybe-uninitialized] quite scal = 0.0 len = 0 ic(1) = 1 ierr = 0 c initialize array iw. do 1 j=1, ncol iw(j) = 0 1 continue c do 500 ii=1, nrow c row i do 200 ka=ia(ii), ia(ii+1)-1 if (values) scal = a(ka) jj = ja(ka) do 100 kb=ib(jj),ib(jj+1)-1 jcol = jb(kb) jpos = iw(jcol) if (jpos .eq. 0) then len = len+1 if (len .gt. nzmax) then ierr = ii return endif jc(len) = jcol iw(jcol)= len if (values) c(len) = scal*b(kb) else if (values) c(jpos) = c(jpos) + scal*b(kb) endif 100 continue 200 continue do 201 k=ic(ii), len iw(jc(k)) = 0 201 continue ic(ii+1) = len+1 500 continue return c-------------end-of-amub----------------------------------------------- c----------------------------------------------------------------------- end c c------------------------------------------------------------------------ subroutine getl (n,a,ja,ia,ao,jao,iao) implicit none integer n, ia(*), ja(*), iao(*), jao(*) real(8) a(*), ao(*) c------------------------------------------------------------------------ c this subroutine extracts the lower triangular part of a matrix c and writes the result ao, jao, iao. The routine is in place in c that ao, jao, iao can be the same as a, ja, ia if desired. c----------- c on input: c c n = dimension of the matrix a. c a, ja, c ia = matrix stored in compressed sparse row format. c On return: c ao, jao, c iao = lower triangular matrix (lower part of a) c stored in a, ja, ia, format c note: the diagonal element is the last element in each row. c i.e. in a(ia(i+1)-1 ) c ao, jao, iao may be the same as a, ja, ia on entry -- in which case c getl will overwrite the result on a, ja, ia. c c------------------------------------------------------------------------ c local variables real(8) t integer ko, kold, kdiag, k, i c c inititialize ko (pointer for output matrix) c ko = 0 do 7 i=1, n kold = ko kdiag = 0 do 71 k = ia(i), ia(i+1) -1 if (ja(k) .gt. i) goto 71 ko = ko+1 ao(ko) = a(k) jao(ko) = ja(k) if (ja(k) .eq. i) kdiag = ko 71 continue if (kdiag .eq. 0 .or. kdiag .eq. ko) goto 72 c c exchange c t = ao(kdiag) ao(kdiag) = ao(ko) ao(ko) = t c k = jao(kdiag) jao(kdiag) = jao(ko) jao(ko) = k 72 iao(i) = kold+1 7 continue c redefine iao(n+1) iao(n+1) = ko+1 return c----------end-of-getl ------------------------------------------------- c----------------------------------------------------------------------- end c----------------------------------------------------------------------- subroutine getu (n,a,ja,ia,ao,jao,iao) implicit none integer n, ia(*), ja(*), iao(*), jao(*) real(8) a(*), ao(*) c------------------------------------------------------------------------ c this subroutine extracts the upper triangular part of a matrix c and writes the result ao, jao, iao. The routine is in place in c that ao, jao, iao can be the same as a, ja, ia if desired. c----------- c on input: c c n = dimension of the matrix a. c a, ja, c ia = matrix stored in a, ja, ia, format c On return: c ao, jao, c iao = upper triangular matrix (upper part of a) c stored in compressed sparse row format c note: the diagonal element is the last element in each row. c i.e. in a(ia(i+1)-1 ) c ao, jao, iao may be the same as a, ja, ia on entry -- in which case c getu will overwrite the result on a, ja, ia. c c------------------------------------------------------------------------ c local variables real(8) t integer ko, k, i, kdiag, kfirst ko = 0 do 7 i=1, n kfirst = ko+1 kdiag = 0 do 71 k = ia(i), ia(i+1) -1 if (ja(k) .lt. i) goto 71 ko = ko+1 ao(ko) = a(k) jao(ko) = ja(k) if (ja(k) .eq. i) kdiag = ko 71 continue if (kdiag .eq. 0 .or. kdiag .eq. kfirst) goto 72 c exchange t = ao(kdiag) ao(kdiag) = ao(kfirst) ao(kfirst) = t c k = jao(kdiag) jao(kdiag) = jao(kfirst) jao(kfirst) = k 72 iao(i) = kfirst 7 continue c redefine iao(n+1) iao(n+1) = ko+1 return c----------end-of-getu ------------------------------------------------- c----------------------------------------------------------------------- end c- subroutine csrmsr (n,a,ja,ia,ao,jao,wk,iwk) implicit none integer n real(8) a(*),ao(*),wk(n) integer ia(n+1),ja(*),jao(*),iwk(n+1) c----------------------------------------------------------------------- c other used variables integer k, j, iptr, ii, icount, i c----------------------------------------------------------------------- c Compressed Sparse Row to Modified - Sparse Row c Sparse row with separate main diagonal c----------------------------------------------------------------------- c converts a general sparse matrix a, ja, ia into c a compressed matrix using a separated diagonal (referred to as c the bell-labs format as it is used by bell labs semi conductor c group. We refer to it here as the modified sparse row format. c Note: this has been coded in such a way that one can overwrite c the output matrix onto the input matrix if desired by a call of c the form c c call csrmsr (n, a, ja, ia, a, ja, wk,iwk) c c In case ao, jao, are different from a, ja, then one can c use ao, jao as the work arrays in the calling sequence: c c call csrmsr (n, a, ja, ia, ao, jao, ao,jao) c c----------------------------------------------------------------------- c c on entry : c--------- c a, ja, ia = matrix in csr format. note that the c algorithm is in place: ao, jao can be the same c as a, ja, in which case it will be overwritten on it c upon return. c c on return : c----------- c c ao, jao = sparse matrix in modified sparse row storage format: c + ao(1:n) contains the diagonal of the matrix. c + ao(n+2:nnz) contains the nondiagonal elements of the c matrix, stored rowwise. c + jao(n+2:nnz) : their column indices c + jao(1:n+1) contains the pointer array for the nondiagonal c elements in ao(n+1:nnz) and jao(n+2:nnz). c i.e., for i .le. n+1 jao(i) points to beginning of row i c in arrays ao, jao. c here nnz = number of nonzero elements+1 c work arrays: c------------ c wk = real work array of length n c iwk = integer work array of length n+1 c c notes: c------- c Algorithm is in place. i.e. both: c c call csrmsr (n, a, ja, ia, ao, jao, ao,jao) c (in which ao, jao, are different from a, ja) c and c call csrmsr (n, a, ja, ia, a, ja, wk,iwk) c (in which wk, jwk, are different from a, ja) c are OK. c-------- c coded by Y. Saad Sep. 1989. Rechecked Feb 27, 1990. c----------------------------------------------------------------------- icount = 0 c c store away diagonal elements and count nonzero diagonal elements. c do 1 i=1,n wk(i) = 0.0d0 iwk(i+1) = ia(i+1)-ia(i) do 2 k=ia(i),ia(i+1)-1 if (ja(k) .eq. i) then wk(i) = a(k) icount = icount + 1 iwk(i+1) = iwk(i+1)-1 endif 2 continue 1 continue c c compute total length c iptr = n + ia(n+1) - icount c c copy backwards (to avoid collisions) c do 500 ii=n,1,-1 do 100 k=ia(ii+1)-1,ia(ii),-1 j = ja(k) if (j .ne. ii) then ao(iptr) = a(k) jao(iptr) = j iptr = iptr-1 endif 100 continue 500 continue c c compute pointer values and copy wk(*) c jao(1) = n+2 do 600 i=1,n ao(i) = wk(i) jao(i+1) = jao(i)+iwk(i+1) 600 continue return c------------ end of subroutine csrmsr --------------------------------- c----------------------------------------------------------------------- end c subroutine getdia (nrow,ncol,job,a,ja,ia,len,diag,idiag,ioff) implicit none real(8) diag(*),a(*) integer nrow, ncol, job, len, ioff, ia(*), ja(*), idiag(*) c----------------------------------------------------------------------- c further used variables integer izero c----------------------------------------------------------------------- c this subroutine extracts a given diagonal from a matrix stored in csr c format. the output matrix may be transformed with the diagonal removed c from it if desired (as indicated by job.) c----------------------------------------------------------------------- c our definition of a diagonal of matrix is a vector of length nrow c (always) which contains the elements in rows 1 to nrow of c the matrix that are contained in the diagonal offset by ioff c with respect to the main diagonal. if the diagonal element c falls outside the matrix then it is defined as a zero entry. c thus the proper definition of diag(*) with offset ioff is c c diag(i) = a(i,ioff+i) i=1,2,...,nrow c with elements falling outside the matrix being defined as zero. c c----------------------------------------------------------------------- c c on entry: c---------- c c nrow = integer. the row dimension of the matrix a. c ncol = integer. the column dimension of the matrix a. c job = integer. job indicator. if job = 0 then c the matrix a, ja, ia, is not altered on return. c if job.ne.0 then getdia will remove the entries c collected in diag from the original matrix. c this is done in place. c c a,ja, c ia = matrix stored in compressed sparse row a,ja,ia,format c ioff = integer,containing the offset of the wanted diagonal c the diagonal extracted is the one corresponding to the c entries a(i,j) with j-i = ioff. c thus ioff = 0 means the main diagonal c c on return: c----------- c len = number of nonzero elements found in diag. c (len .le. min(nrow,ncol-ioff)-max(1,1-ioff) + 1 ) c c diag = real(8) array of length nrow containing the wanted diagonal. c diag contains the diagonal (a(i,j),j-i = ioff ) as defined c above. c c idiag = integer array of length len, containing the poisitions c in the original arrays a and ja of the diagonal elements c collected in diag. a zero entry in idiag(i) means that c there was no entry found in row i belonging to the diagonal. c c a, ja, c ia = if job .ne. 0 the matrix is unchanged. otherwise the nonzero c diagonal entries collected in diag are removed from the c matrix and therefore the arrays a, ja, ia will change. c (the matrix a, ja, ia will contain len fewer elements) c c----------------------------------------------------------------------c c Y. Saad, sep. 21 1989 - modified and retested Feb 17, 1996. c c----------------------------------------------------------------------c c local variables integer istart, max, iend, i, kold, k, kdiag, ko c izero = 0 istart = max(izero,-ioff) iend = min(nrow,ncol-ioff) len = 0 do 1 i=1,nrow idiag(i) = 0 diag(i) = 0.0d0 1 continue c c extract diagonal elements c do 6 i=istart+1, iend do 51 k= ia(i),ia(i+1) -1 if (ja(k)-i .eq. ioff) then diag(i)= a(k) idiag(i) = k len = len+1 goto 6 endif 51 continue 6 continue if (job .eq. 0 .or. len .eq.0) return c c remove diagonal elements and rewind structure c ko = 0 do 7 i=1, nrow kold = ko kdiag = idiag(i) do 71 k= ia(i), ia(i+1)-1 if (k .ne. kdiag) then ko = ko+1 a(ko) = a(k) ja(ko) = ja(k) endif 71 continue ia(i) = kold+1 7 continue c c redefine ia(nrow+1) c ia(nrow+1) = ko+1 return c------------end-of-getdia---------------------------------------------- c----------------------------------------------------------------------- end c spam/src/ds_eigen.f0000644000176200001440000002315113574431374013742 0ustar liggesusersc subroutine d_ope ( n, x, y, a, ja, ia ) c c ope computes A * x for a sparse matrix A. c implicit none c integer n c real ( kind = 8 ) a(*) integer i integer ia(n+1) integer ja(*) integer k1 integer k2 real ( kind = 8 ) x(*) real ( kind = 8 ) y(*) c c spasrse matrix * vector multiplication c do i=1,n k1 = ia(i) k2 = ia(i+1) -1 y(i) = dot_product ( a(k1:k2), x(ja(k1:k2)) ) end do c return end c c----------------------------------------------------------------------- c subroutine ds_eigen_f (maxnev, ncv, maxitr, & n, iwhich, & na, a, ja, ia, & v, d, & iparam) c implicit none c c %--------------------% c | Input Declarations | c %--------------------% c integer maxnev, ncv, maxitr, n, na, ja(*), ia(na+1), & iparam(8), iwhich c Double precision & a(*), & v(n, ncv), d(maxnev), & workl(ncv*(ncv+8)), workd(3*n), resid(n) c c %---------------% c | Local Scalars | c %---------------% c Double precision & tol, sigma integer ipntr(11) c character bmat*1, which*2 integer ido, info, lworkl, & ishfts, mode1, ierr logical rvec, select(ncv) c c %------------% c | Parameters | c %------------% c Double precision & zero parameter (zero = 0.0D+0) c c c %-----------------------% c | Executable Statements | c %-----------------------% c c %-------------------------------------------------% c | The following include statement and assignments | c | initiate trace output from the internal | c | actions of ARPACK. See debug.doc in the | c | DOCUMENTS directory for usage. Initially, the | c | most useful information will be a breakdown of | c | time spent in the various stages of computation | c | given by setting msaupd = 1. | c %-------------------------------------------------% c c %-------------------------------------------------% c | The following sets dimensions for this problem. | c %-------------------------------------------------% c bmat = 'I' c if (iwhich .eq. 1) then which = 'LM' else if (iwhich .eq. 2) then which = 'SM' else if (iwhich .eq. 7) then which = 'LA' else if (iwhich .eq. 8) then which = 'SA' else if (iwhich .eq. 9) then which = 'BE' else c goto 9000 end if c c %-----------------------------------------------------% c | | c | Specification of stopping rules and initial | c | conditions before calling DSAUPD | c | | c | TOL determines the stopping criterion. | c | | c | Expect | c | abs(lambdaC - lambdaT) < TOL*abs(lambdaC) | c | computed true | c | | c | If TOL .le. 0, then TOL <- macheps | c | (machine precision) is used. | c | | c | IDO is the REVERSE COMMUNICATION parameter | c | used to specify actions to be taken on return | c | from DSAUPD. (See usage below.) | c | | c | It MUST initially be set to 0 before the first | c | call to DSAUPD. | c | | c | INFO on entry specifies starting vector information | c | and on return indicates error codes | c | | c | Initially, setting INFO=0 indicates that a | c | random starting vector is requested to | c | start the ARNOLDI iteration. Setting INFO to | c | a nonzero value on the initial call is used | c | if you want to specify your own starting | c | vector (This vector must be placed in RESID.) | c | | c | The work array WORKL is used in DSAUPD as | c | workspace. Its dimension LWORKL is set as | c | illustrated below. | c | | c %-----------------------------------------------------% c lworkl = ncv * (ncv + 8) tol = zero info = 0 ido = 0 c c %---------------------------------------------------% c | Specification of Algorithm Mode: | c | | c | This program uses the exact shift strategy | c | (indicated by setting PARAM(1) = 1). | c | IPARAM(3) specifies the maximum number of Arnoldi | c | iterations allowed. Mode 1 of DSAUPD is used | c | (IPARAM(7) = 1). All these options can be changed | c | by the user. For details see the documentation in | c | DSAUPD. | c %---------------------------------------------------% c ishfts = 1 mode1 = 1 c iparam(1) = ishfts iparam(3) = maxitr iparam(7) = mode1 c c %------------------------------------------------% c | M A I N L O O P (Reverse communication loop) | c %------------------------------------------------% c 10 continue c c %---------------------------------------------% c | Repeatedly call the routine DSAUPD and take | c | actions indicated by parameter IDO until | c | either convergence is indicated or maxitr | c | has been exceeded. | c %---------------------------------------------% c c call dsaupd ( ido, bmat, n, which, maxnev, tol, resid, & ncv, v, n, iparam, ipntr, workd, workl, & lworkl, info ) c if (ido .eq. -1 .or. ido .eq. 1) then c c %--------------------------------------% c | Perform matrix vector multiplication | c | y <--- OP*x | c | The user should supply his/her own | c | matrix vector multiplication routine | c | here that takes workd(ipntr(1)) as | c | the input, and return the result to | c | workd(ipntr(2)). | c %--------------------------------------% c call d_ope (na, workd(ipntr(1)), workd(ipntr(2)), & a, ja, ia) c c %-----------------------------------------% c | L O O P B A C K to call DSAUPD again. | c %-----------------------------------------% c go to 10 c end if c c %----------------------------------------% c | Either we have convergence or there is | c | an error. | c %----------------------------------------% c if ( info .lt. 0 ) then c c %--------------------------% c | Error message. Check the | c | documentation in DSAUPD. | c %--------------------------% c goto 9000 c else c c %-------------------------------------------% c | No fatal errors occurred. | c | Post-Process using DSEUPD. | c | | c | Computed eigenvalues may be extracted. | c | | c | Eigenvectors may be also computed now if | c | desired. (indicated by rvec = .true.) | c | | c | The routine DSEUPD now called to do this | c | post processing (Other modes may require | c | more complicated post processing than | c | mode1.) | c | | c %-------------------------------------------% c rvec = .true. c call dseupd ( rvec, 'A', select, d, v, n, sigma, & bmat, n, which, maxnev, tol, resid, ncv, v, n, & iparam, ipntr, workd, workl, lworkl, ierr ) c c %----------------------------------------------% c | Eigenvalues are returned in the first column | c | of the two dimensional array D and the | c | corresponding eigenvectors are returned in | c | the first NCONV (=IPARAM(5)) columns of the | c | two dimensional array V if requested. | c | Otherwise, an orthogonal basis for the | c | invariant subspace corresponding to the | c | eigenvalues in D is returned in V. | c %----------------------------------------------% c if ( ierr .ne. 0) then c c %------------------------------------% c | Error condition: | c | Check the documentation of DSEUPD. | c %------------------------------------% c goto 9000 c end if c end if c 9000 continue end c c spam/vignettes/0000755000176200001440000000000013574431374013235 5ustar liggesusersspam/vignettes/jss15.pdf.asis0000644000176200001440000000011213562501663015621 0ustar liggesusers%\VignetteIndexEntry{JSS - Areal count data} %\VignetteEngine{R.rsp::asis}spam/vignettes/spam.Rmd0000644000176200001440000004426113572142203014634 0ustar liggesusers--- title: "Illustrations and Examples" author: "Reinhard Furrer, Roman Flury" date: "`r Sys.Date()`" output: rmarkdown::pdf_document: fig_caption: yes number_sections: true toc: true toc_depth: 2 citation_package: natbib header-includes: - \usepackage{bm} - \usepackage{setspace}\onehalfspacing - \usepackage[labelfont=bf]{caption} - \usepackage{natbib} - \usepackage{hyperref} bibliography: spam.bib vignette: > \usepackage[utf8]{inputenc} %\VignetteEngine{knitr::rmarkdown} %\VignetteIndexEntry{`spam`, a SPArse Matrix package} %\VignetteEncoding{UTF-8} --- ```{r setup, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>", # fig.width = 6, fig.height = 6, fig.align = "center" ) options(digits = 3) ``` ```{r loadpkgs, echo=FALSE, eval=TRUE, message=FALSE} library("spam") ``` # Rational for spam At the core of drawing multivariate normal random variables, calculating or maximizing multivariate normal log-likelihoods, calculating determinants, etc., we need to solve a large (huge) linear system involving a variance matrix, i.e., a symmetric, positive definite matrix. Assume that we have such a symmetric, positive definite matrix $\boldsymbol{Q}$ of size $n\times n$ that contains many zeros (through tapering, @Furr:Gent:Nych:06, @Furr:Beng:07, or through a Markovian conditional construction). Typically, $\boldsymbol{Q}$ contains only $\mathcal{O}(n)$ non-zero elements compared to $\mathcal{O}(n^2)$ for a regular, **full** matrix. To take advantage of the few non-zero elements, special structures to represent the matrix are required, i.e., only the positions of the non-zeros and their values are kept in memory. Further, new algorithms work with these structures are required. The package `spam` provides this functionality, see @Furr:Sain:10 for a detailed exposition. # A Simple Example This first section illustrates with a simple example how to work with `spam`. Within a running R we install and load the current `spam` version from CRAN. ```{r echo=TRUE, eval=FALSE, message=FALSE} install.packages("spam") library("spam") ``` We create a trivial matrix and "coerce" it to a sparse matrix. ```{r trivial} Fmat <- matrix(c(3, 0, 1, 0, 2, 0, 1, 0, 3), nrow = 3, ncol = 3) Smat <- as.spam(Fmat) ``` `spam` is conceptualized such that for many operations, the user proceeds as with ordinary full matrices. For example: ```{r operations} Fmat Smat Smat %*% t(Smat) Fmat %*% t(Smat) ``` Hence, the user should not be worried which objects are sparse matrices and which are not. Of course not all operations result in sparse objects again, ```{r nonspam} rep(1, 3) %*% Smat ``` However, other operations yield to different results when applied to full or sparse matrices ```{r diffbehaviour} range(Fmat) range(Smat) ``` # Creating Sparse Matrices The implementation of `spam` is designed as a trade-off between the following competing philosophical maxims. It should be competitively fast compared to existing tools or approaches in R and it should be easy to use, modify and extend. The former is imposed to assure that the package will be useful and used in practice. The latter is necessary since statistical methods and approaches are often very specific and no single package could cover all potential tools. Hence, the user needs to understand quickly the underlying structure of the implementation of `spam` and to be able to extend it without getting desperate. (When faced with huge amounts of data, sub-sampling is one possibility; using `spam` is another.) This philosophical approach also suggests trying to assure `S3` and `S4` compatibility, @Cham:93, see also @Luml:04. `S4` has higher priority but there are only a handful cases of `S3` discrepancies, which do however not affect normal usage. To store the non-zero elements, `spam` uses the "old Yale sparse format". In this format, a (sparse) matrix is stored with four elements (vectors), which are (1) the nonzero values row by row, (2) the ordered column indices of nonzero values, (3) the position in the previous two vectors corresponding to new rows, given as pointers, and (4) the column dimension of the matrix. We refer to this format as compressed sparse row (CSR) format. Hence, to store a matrix with $z$ nonzero elements we thus need $z$ reals and $z+n+2$ integers compared to $n \times n$ reals. Section Representation describes the format in more details. The package `spam` provides two classes, first, `spam` representing sparse matrices and, second, `spam.chol.NgPeyton` representing Cholesky factors. A class definition specifies the objects belonging to the class, these objects are called slots in R and accessed with the `@` operator, see \citet{Cham:93} for a more thorough discussion. The four vectors of the CSR representation are implemented as slots. In `spam`, all operations can be performed without a detailed knowledge about the slots. However, advanced users may want to work on the slots of the class `spam` directly because of computational savings, for example, changing only the contents of a matrix while maintaining its sparsity structure, see Section Tips. The Cholesky factor requires additional information (e.g., the used permutation) hence the class `spam.chol.NgPeyton` contains more slots, which are less intuitive. There are only very few, specific cases, where the user has to access these slots directly. Therefore, user-visibility has been disregarded for the sake of speed. The two classes are discussed in the more technical Section Representation. # Displaying As seen in Section A Simple Example, printing small matrices result in an expected output, i.e., the content of the matrix plus a line indicating the class of the object: ```{r displ1} Smat ``` For larger objects, not all the elements are printed. For example: ```{r displ2} diag.spam(100) ``` The size of the matrix when switching from the first printing format to the second is a `spam` option, see Section Options. Naturally, we can also use the `str` command which gives us further insight into the individual slots of the `spam` object: ```{r disp3} str(Smat) ``` Alternatively, calling `summary` gives additional information of the matrix. ```{r disp4} summary(Smat) ``` `summary` itself prints on the standard output but also returns a list containing the number of non-zeros (`nnz`) and the density (`density`) (percentage of `nnz` over the total number of elements). Quite often, it is interesting to look at the sparsity structure of a sparse matrix. This is implemented with the command `display`. Again, depending on the size, the structure is shown as proper rectangles or as points. Figure \ref{fig:display_spam} is the result of the following code. ```{r disp5, echo=FALSE, warning=FALSE} nz <- 2^12 Smat1 <- spam(0, nz, nz) Smat1[cbind(sample(nz, nz), sample(nz, nz))] <- rnorm(nz) tmp <- round(summary(Smat1)$density, 3) ``` ```{r disp6, echo=FALSE, warning=FALSE, fig.cap = '\\label{fig:display_spam}Sparsity structure of sparse matrices.'} par(mfcol=c(1,2),pty='s',mai=c(.8,.8,.2,.2)) display(Smat) display(Smat1) ``` Additionally, compare Figures of this document. Depending on the `cex` value, the `image` may issue a warning, meaning that the dot-size is probably not optimal. In fact, visually the density of the matrix `Smat1` seems to be around some percentage whereas the actual density is `r tmp`. The function `image` goes beyond the structure of the matrix by using a specified color scheme for the values. Labels can be added manually or with `image.plot` from the package `fields`. # Solving Linear Systems To be more specific about one of `spam`'s main features, assume we need to calculate $\boldsymbol{A}^{-1}\boldsymbol{b}$ with $\boldsymbol{A}$ a symmetric positive definite matrix featuring some sparsity structure, which is usually accomplished by solving $\boldsymbol{A}\boldsymbol{x}=\boldsymbol{b}$. We proceed by factorizing $\boldsymbol{A}$ into $\boldsymbol{R}^T\boldsymbol{R}$, where $\boldsymbol{R}$ is an upper triangular matrix, called the Cholesky factor or Cholesky triangle of $\boldsymbol{A}$, followed by solving $\boldsymbol{R}^T\boldsymbol{y}=\boldsymbol{b}$ and $\boldsymbol{R}\boldsymbol{x}=\boldsymbol{y}$, called forwardsolve and backsolve, respectively. To reduce the fill-in of the Cholesky factor $\boldsymbol{R}$, we permute the columns and rows of $\boldsymbol{A}$ according to a (cleverly chosen) permutation $\boldsymbol{P}$, i.e., $\boldsymbol{U}^T\boldsymbol{U}=\boldsymbol{P}^T\boldsymbol{A}\boldsymbol{P}$, with $\boldsymbol{U}$ an upper triangular matrix. There exist many different algorithms to find permutations which are optimal for specific matrices %tridiagonal matrices finite element/difference matrices defined on square grids or at least close to optimal with respect to different criteria. Note that $\boldsymbol{R}$ and $\boldsymbol{U}$ cannot be linked through $\boldsymbol{P}$ alone. Figure \ref{fig:ill} illustrates the factorization with and without permutation. For solving a linear system the two triangular solves are performed after the factorization. The determinant of $\boldsymbol{A}$ is the squared product of the diagonal elements of its Cholesky factor $\boldsymbol{R}$. Hence the same factorization can be used to calculate determinants (a necessary and computational bottleneck in the computation of the log-likelihood of a Gaussian model), illustrating that it is very important to have a very efficient integration (with respect to calculation time and storage capacity) of the Cholesky factorization. In the case of GMRF, the off-diagonal non-zero elements correspond to the conditional dependence structure. However, for the calculation of the Cholesky factor, the values themselves are less important than the sparsity structure, which is often represented using a graph with edges representing the non-zero elements or using a "pixel" image of the zero/non-zero structure, see Figure \ref{fig:tree}. ```{r } i <- c(2, 4, 4, 5, 5) j <- c(1, 1, 2, 1, 3) A <- spam(0, nrow = 5, ncol = 5) A[cbind(i, j)] <- rep(0.5, length(i)) A <- t(A) + A + diag.spam(5) A U <- chol(A) ``` ```{r tree, echo=FALSE, results = 'markup', out.width='40%', fig.show='hold', warning=FALSE, fig.cap='\\label{fig:tree}On the left side the associated graph to the matrix $\\boldsymbol{A}$ is visualized. The nodes of the graph are labeled according to $\\boldsymbol{A}$ (upright) and $\\boldsymbol{P}^T\\boldsymbol{A}\\boldsymbol{P}$ (italics). On the right side the sparsity structure of $\\boldsymbol{A}$ and $\\boldsymbol{P}^T\\boldsymbol{A}\\boldsymbol{P}$ (top row) and the Cholesky factors $\\boldsymbol{R}$ and $\\boldsymbol{U}$ of $\\boldsymbol{A}$ and $\\boldsymbol{P}^T\\boldsymbol{A}\\boldsymbol{P}$ respectively are given in the bottom row. The dashed lines in $\\boldsymbol{U}$ indicate the supernode partition.'} knitr::include_graphics(c('figures/tree.png', 'figures/ill.png')) ``` The Cholesky factor of a banded matrix is again a banded matrix. But arbitrary matrices may produce full Cholesky factors. To reduce this so-called *fill-in* of the Cholesky factor $\boldsymbol{R}$, we permute the columns and rows of $\boldsymbol{A}$ according to a (cleverly chosen) permutation $\boldsymbol{P}$, i.e., $\boldsymbol{U}^T\boldsymbol{U}=\boldsymbol{P}^T\boldsymbol{A}\boldsymbol{P}$, with $\boldsymbol{U}$ an upper triangular matrix. There exist many different algorithms to find permutations which are optimal for specific matrices or at least close to optimal with respect to different criteria. The cost of finding a good permutation matrix $\boldsymbol{P}$ is at least of order $\mathcal{O}(n^{3/2})$. However, there exist good, but suboptimal, approaches for $\mathcal{O}(n\log(n))$. A typical Cholesky factorization of a sparse matrix consists of the steps illustrated in the following pseudo code algorithm. Step | Description ---- | --------------------------------------------------------------------------------------------------------------------------- [1] | Determine permutation and permute the input matrix $\boldsymbol{A}$ to obtain $\boldsymbol{P}^T\boldsymbol{A}\boldsymbol{P}$ [2] | Symbolic factorization, where the sparsity structure of $\boldsymbol{U}$ is constructed [3] | Numeric factorization, where the elements of $\boldsymbol{U}$ are computed When factorizing matrices with the same sparsity structure Step 1 and 2 do not need to be repeated. In MCMC algorithms, this is commonly the case, and exploiting this shortcut leads to very considerable gains in computational efficiency (also noticed by @Rue:Held:05, page 51). However, none of the existing sparse matrix packages in R (`SparseM`, `Matrix`) provide the possibility to carry out Step 3 separately and `spam` fills this gap. As for Step 1, there are many different algorithms to find a permutation, for example, the multiple minimum degree (MMD) algorithm, @Liu:85, and the reverse Cuthill-McKee (RCM) algorithm, @Geor:71. The resulting sparsity structure in the permuted matrix determines the sparsity structure of the Cholesky factor. As an illustration, Figure \ref{fig:ch2:factor} shows the sparsity structure of the Cholesky factor resulting from an MMD, an RCM, and no permutation of a precision matrix induced by a second-order neighbor structure of the US counties. How much fill-in with zeros is present depends on the permutation algorithm, in the example of Figure \@ref{fig:ch2:factor} there are $146735$, $256198$ and $689615$ non-zero elements in the Cholesky factors resulting from the MMD, RCM, and no permutation, respectively. Note that the actual number of non-zero elements of the Cholesky factor may be smaller than what the constructed sparsity structure indicates. Here, there are $14111$, $97565$ and $398353$ zero elements (up to machine precision) that are not exploited. ```{r fillin, echo=FALSE, fig.show='hold', warning=FALSE, fig.cap='\\label{fig:ch2:factor}Sparsity structure of the Cholesky factor with MMD, RCM and no permutation of a precision matrix induced by a second-order neighbor structure of the US counties. The values *nnzR* and *fillin* are the number of non-zero elements in the sparsity structure of the factor and the fill-in, respectively.'} knitr::include_graphics(c('figures/fig_ch2_factors.png')) ``` # More about Methods For both sparse classes of `spam` standard methods like `plot`, `dim`, `backsolve`/`forwardsolve`, `determinant` (based on a Cholesky factor) are implemented and behave as in the case of full matrices. Print methods display the sparse matrix as a full matrix in case of small matrices and display only the non-zero values otherwise. The corresponding cutoff value as well as other parameters can be set and read via `spam.options`. ## Methods with Particular Behavior For the `spam` class additional methods are defined, for examples `rbind`/`cbind`, `dim<-`, etc. The group generic functions from `Math`, `Math2` and `Summary` are treated particularly since they operate only on the nonzero entries of the `spam` class. For example, for the matrix `A` presented in the introduction `range(A)` is the vector `c(0.5, 1)`, i.e. the zeros are omitted from the calculation. The help lists further available methods and highlights the (dis-)similarities compared to when applied to regular matrices or arrays. ## Particular Methods with Ordinary Behavior Besides the two sparse classes mentioned above, `spam` does not maintain different classes for different types of sparse matrices, such as symmetric or diagonal matrices. Doing so would result in some storage and computational gain for some matrix operations, at the cost of user visibility. Instead of creating more classes we consider additional specific operators. As an illustration, consider multiplying a diagonal matrix with a sparse matrix. The operator `\%d*\%` uses standard matrix multiplication if both sides are matrices or multiplies each column according the diagonal entry if the left hand side is a diagonal matrix represented by vector. ## Importing Foreign Formats `spam` is not the only R package for sparse matrix algebra. The packages `SparseM` @Koen:Ng:03 and `Matrix` @Bates:06 contain similar functionalities for handling sparse matrices, however, both packages do not provide the possibility to split up the Cholesky factorization as discussed previously. We briefly discuss the major differences with respect to `spam`; for a detailed description see their manual. `SparseM` is also based on the Fortran Cholesky factorization of @Ng:Peyt:93 using the MMD permutation and almost exclusively on `SparseKit`. It was originally designed for large least squares problems and later also ported to `S4` but is in a few cases inconsistent with existing R methods. It supports different sparse storage systems. `Matrix` incorporates many classes for sparse and full matrices and is based on C. For sparse matrices, it uses different storage formats, defines classes for different types of matrices and uses a Cholesky factorization based on UMFPACK, @Davi:04. `spam` has a few functions that allow to transform matrix formats of the different packages. `spam` also contains functions that download matrices from MatrixMarket, a web side that stores many different sparse matrices. The function `read.MM(file)`, very similar to the function `readMM` from `Matrix`, opens a connection, specified by the argument, and reads a matrix market file. However, as entries of `spam` matrices are of mode `double`, integers matrices are coerced to doubles, patterns lead to matrices containing ones and complex are coerced to the real part thereof. In these aforementioned cases, a warning is issued. MatrixMarket also defines an array format, in which case a (possibly) dense `spam` object is return (retaining only elements which are larger than `getOption('spam.eps')`), a warning is issued. Similarly to `read.MM(file)`, the function `read.HB(file)` reads matrices in the Harwell-Boeing format. Currently, only real assembled Harwell-Boeing can be read with `read.HB`. Reading MatrixMarket formats is more flexible. The functions are based on `readHB` and `readMM` from the library `Matrix` to build the connection and read the raw data. At present, `read.MM(file)` is more flexible than `readMM`. For many operations, `spam` is faster than `Matrix` and `SparseM`. It would also be interesting to compare `spam` and the sparse matrix routines of `Matlab` (see Figure 6 of @Furr:Gent:Nych:06 for a comparison between `SparseM` and Matlab). # Bibliography spam/vignettes/spam.bib0000644000176200001440000004460113562501663014654 0ustar liggesusers @ARTICLE{Furr:Beng:07, AUTHOR = {Furrer, R. and Bengtsson, T.}, YEAR = {2007}, TITLE = {Estimation of High-dimensional Prior and Posteriori Covariance Matrices in Kalman Filter Variants}, JOURNAL = {J. Multivariate Anal.}, FJOURNAL = {Journal of Multivariate Analysis}, VOLUME = {98}, NUMBER = {2}, PAGES = {227-255}, DOI = {10.1016/j.jmva.2006.08.003}, } @ARTICLE{Besa:74, author={J. Besag}, title={Spatial Interaction and the Statistical Analysis of Lattice Systems (with discussion)}, sjournal={J Roy. Statist. Soc. Ser. B}, journal={Journal of the Royal Statistical Society, Series B}, volume={36}, number={2}, year={1974}, pages = {192-225}, } @book{Duff:Eris:Reid:86, author = {Iain S Duff and Albert M Erisman and John K Reid}, title = {Direct methods for sparse matrices}, year = {1986}, isbn = {0-198-53408-6}, publisher = {Oxford University Press, Inc.}, address = {New York, NY, USA}, } @phdthesis{Geor:71, author = {John Alan George}, title = {Computer implementation of the finite element method}, year = {1971}, order_no = {AAI7205916}, school = {Stanford University}, address = {Stanford, CA, USA}, } @article{Liu:85, author = {Joseph W. H. Liu}, title = {Modification of the minimum-degree algorithm by multiple elimination}, sjournal = {ACM Trans. Math. Softw.}, journal = {ACM Transactions on Mathematical Software (TOMS)}, volume = {11}, number = {2}, year = {1985}, issn = {0098-3500}, pages = {141--153}, doi = {10.1145/214392.214398}, publisher = {ACM}, address = {New York, NY, USA}, } @article{Geor:Ng:84, author = {Alan George and Esmond Ng}, title = {A new release of SPARSPAK: the Waterloo sparse matrix package}, sjournal = {SIGNUM Newsl.}, journal = {ACM SIGNUM Newsletter}, volume = {19}, number = {4}, year = {1984}, issn = {0163-5778}, pages = {9--13}, doi = {10.1145/1057931.1057933}, publisher = {ACM}, address = {New York, NY, USA}, } @article{Geor:Ng:81, author = {Alan George and Esmond Ng}, title = {A brief description of SPARSPAK Waterloo sparse linear equations package}, sjournal = {SIGNUM Newsl.}, journal = {ACM SIGNUM Newsletter}, volume = {16}, number = {2}, year = {1981}, issn = {0163-5778}, pages = {17--20}, doi = {10.1145/1057562.1057566}, publisher = {ACM}, address = {New York, NY, USA}, } @phdthesis{Sher:75, author = {Andrew Harry Sherman}, title = {On the efficient solution of sparse systems of linear and nonlinear equations.}, year = {1975}, order_no = {AAI7613692}, school = {Yale University}, address = {New Haven, CT, USA}, } @Article{Luml:04, author = {Thomas Lumley}, title = {Programmers' niche: A simple class, in {S3 and S4}}, journal = {R News}, year = {2004}, volume = {4\rm (1)}, number = {1}, pages = {33-36}, } @article{Davi:04, author = {Timothy A. Davis}, title = {{Algorithm 832: UMFPACK V4.3}---an unsymmetric-pattern multifrontal method}, sjournal = {ACM Trans. Math. Softw.}, journal = {ACM Transactions on Mathematical Software (TOMS)}, volume = {30}, number = {2}, year = {2004}, issn = {0098-3500}, pages = {196--199}, doi = {10.1145/992200.992206}, publisher = {ACM}, address = {New York, NY, USA}, } @Manual{Goul:Hu:Scot:05b, author = {N. I. M. Gould and Y. Hu and J. A. Scott}, title = {Complete results for a numerical evaluation of sparse direct solvers for the solution of large, sparse, symmetric linear systems of equations}, year = {2005}, note = {Numerical Analysis Internal Report 2005-1 (revision 2). Rutherford Appleton Laboratory. Available from \url{http://www.numerical.rl.ac.uk/reports/reports.shtml}}, } @TechReport{Goul:Hu:Scot:05a, author = {N. I. M. Gould and Y. Hu and J. A. Scott}, title = {A numerical evaluation of sparse direct symmetric solvers for the solution of large sparse, symmetric linear systems of equations}, institution = {RAL-TR-2005-005. Rutherford Appleton Laboratory}, year = {2005}, note = {Available from \url{http://www.numerical.rl.ac.uk/reports/reports.shtml}}, } @article{Liu:92, author = {Joseph W. H. Liu}, title = {The multifrontal method for sparse matrix solution: theory and practice}, sjournal = {SIAM Rev.}, journal = {SIAM Review}, volume = {34}, number = {1}, year = {1992}, issn = {0036-1445}, pages = {82--109}, doi = {10.1137/1034004}, publisher = {Society for Industrial and Applied Mathematics}, address = {Philadelphia, PA, USA}, } @article{Ng:Peyt:93b, author = {Esmond Ng and Barry W. Peyton}, title = {A supernodal {C}holesky factorization algorithm for shared-memory multiprocessors}, sjournal = {SIAM J. Sci. Comput.}, journal = {SIAM Journal on Scientific Computing}, volume = {14}, number = {4}, year = {1993}, issn = {1064-8275}, pages = {761--769}, doi = {10.1137/0914048}, publisher = {Society for Industrial and Applied Mathematics}, address = {Philadelphia, PA, USA}, } @article{Gilb:Ng:Peyt:94, author = {John R. Gilbert and Esmond G. Ng and Barry W. Peyton}, title = {An Efficient Algorithm to Compute Row and Column Counts for Sparse {C}holesky Factorization}, sjournal = {SIAM J. Matrix Anal. Appl.}, journal = {SIAM Journal on Matrix Analysis and Applications}, volume = {15}, number = {4}, year = {1994}, issn = {0895-4798}, pages = {1075--1091}, doi = {10.1137/S0895479892236921}, publisher = {Society for Industrial and Applied Mathematics}, address = {Philadelphia, PA, USA}, } @article{Liu:Ng:Peyt:93, author = {Joseph W. H. Liu and Esmond G. Ng and Barry W. Peyton}, title = {On finding supernodes for sparse matrix computations}, sjournal = {SIAM J. Matrix Anal. Appl.}, journal = {SIAM Journal on Matrix Analysis and Applications}, volume = {14}, number = {1}, year = {1993}, issn = {0895-4798}, pages = {242--252}, doi = {10.1137/0614019}, publisher = {Society for Industrial and Applied Mathematics}, address = {Philadelphia, PA, USA}, } @article{Ng:Peyt:93, author = {Esmond G. Ng and Barry W. Peyton}, title = {Block sparse {C}holesky algorithms on advanced uniprocessor computers}, sjournal = {SIAM J. Sci. Comput.}, journal = {SIAM Journal on Scientific Computing}, volume = {14}, number = {5}, year = {1993}, issn = {1064-8275}, pages = {1034--1056}, doi = {10.1137/0914063}, publisher = {Society for Industrial and Applied Mathematics}, address = {Philadelphia, PA, USA}, } @Book{golu:vanL:96, author = {Golub and van Loan}, title = {Matrix Computations}, publisher = {Johns Hopkins University Press, Baltimore}, year = {1996}, edition = {3rd}, } @book{Cham:93, author = {John M. Chambers}, title = {Programming with Data: A Guide to the S Language}, year = {1998}, isbn = {0387985034}, publisher = {Springer-Verlag New York, Inc.}, address = {Secaucus, NJ, USA}, } @Book{Rue:Held:05, author = {H. Rue and L. Held}, title = {Gaussian Markov Random Fields: Theory and Applications}, publisher = {Chapman \& Hall, London}, year = {2005}, } @Manual{Saad:94, title = {SPARSEKIT: A basic tool kit for sparse matrix computations}, author = {Saad, Y.}, note = {Available at \url{http://www-users.cs.umn.edu/~saad/software/SPARSKIT/sparskit.html}}, year = {1994}, } @article{Furr:Sain:etal:07, AUTHOR= {Furrer, R. and Sain, S. R. and Nychka, D. W. and Meehl, G. A.}, TITLE= {Multivariate {B}ayesian Analysis of Atmosphere-Ocean General Circulation Models}, YEAR= {2007}, JOURNAL = {Environ. Ecol. Stat.}, FJOURNAL = {Environmental and Ecological Statistics}, VOLUME = {14}, NUMBER = {3}, PAGES = {249-266}, doi={10.1007/s10651-007-0018-z}, } @article{Furr:Knut:etal:07, author = {Furrer, R. and Knutti, R. and Sain, S. R. and Nychka, D. W. and Meehl, G. A.}, title = {Spatial patterns of probabilistic temperature change projections from a multivariate {B}ayesian analysis}, year = {2007}, JOURNAL = {Geophys. Res. Lett.}, FJOURNAL = {Geophysical Research Letters}, VOLUME = {34}, PAGES = {L06711}, doi={10.1029/2006GL027754}, } @book{Scot:92, author = {David W. Scott}, title = {Multivariate Density Estimation: Theory, Practice, and Visualization}, publisher = {John Wiley \& Sons Inc.}, year = {1992}, } @article {Stei:99:PRF, AUTHOR = {Stein, Michael L.}, TITLE = {Predicting random fields with increasing dense observations}, JOURNAL = {Ann. Appl. Probab.}, FJOURNAL = {The Annals of Applied Probability}, VOLUME = {9}, YEAR = {1999}, NUMBER = {1}, PAGES = {242--273}, } @article {Stei:90, AUTHOR = {Stein, Michael L.}, TITLE = {Uniform asymptotic optimality of linear predictions of a random field using an incorrect second-order structure}, JOURNAL = {Ann. Statist.}, FJOURNAL = {The Annals of Statistics}, VOLUME = {18}, YEAR = {1990}, NUMBER = {2}, PAGES = {850--872}, } @article {Stei:93, AUTHOR = {Stein, Michael L.}, TITLE = {A simple condition for asymptotic optimality of linear predictions of random fields}, JOURNAL = {Statist. Probab. Lett.}, FJOURNAL = {Statistics \& Probability Letters}, VOLUME = {17}, YEAR = {1993}, NUMBER = {5}, PAGES = {399--404}, } @Book{Horn:John:94, author = "R. A. Horn and C. R. Johnson", title = "Topics in Matrix Analysis", note = "Corrected reprint of the 1991 original", publisher = "Cambridge University Press", address = "Cambridge", year = "1994", pages = "viii+607", } @article {Wu:95, AUTHOR = {Wu, Zong Min}, TITLE = {Compactly supported positive definite radial functions}, JOURNAL = {Adv. Comput. Math.}, FJOURNAL = {Advances in Computational Mathematics}, VOLUME = {4}, YEAR = {1995}, NUMBER = {3}, PAGES = {283--292}, } @Article{Gnei:99, author = "Gneiting, T", title = "Correlation functions for atmospheric data analysis", fjournal = "Quarterly Journal of the Royal Meteorological Society", journal = "Q. J. Roy. Meteor. Soc.", volume = "125", year = "1999", pages = "2449-2464", } @article {Gnei:02, AUTHOR = {Gneiting, Tilmann}, TITLE = {Compactly supported correlation functions}, SJOURNAL = {J. Multivariate Anal.}, JOURNAL = {Journal of Multivariate Analysis}, VOLUME = {83}, YEAR = {2002}, NUMBER = {2}, PAGES = {493--508}, } @Article{Wend:95, author = {Wendland, H.}, title = {Piecewise polynomial, positive definite and compactly supported radial functions of minimal degree}, journal = {Advances in Computational Mathematics}, sjournal = {Adv. Comput. Math.}, year = {1995}, volume = {4}, pages = {389--396}, } @ARTICLE{Furr:Sain:10, AUTHOR = {Furrer, R. and Sain, S. R.}, YEAR = {2010}, TITLE = {{spam}: {A} Sparse Matrix {R} Package with Emphasis on {MCMC} Methods for {G}aussian {M}arkov Random Fields}, JOURNAL = {Journal of Statistical Software}, FJOURNAL = {Journal of Statistical Software}, VOLUME = {36}, NUMBER = {10}, PAGES = {1--25}, URL = {http://www.jstatsoft.org/v36/i10/}, } @Manual{Nych:07, title = {fields: Tools for spatial data}, author = {Doug Nychka}, year = {2007}, note = {R package version 4.1. \url{http://www.image.ucar.edu/GSP/Software/Fields}}, } @Manual{Mink:06, title = {maps: Draw Geographical Maps}, author = {Thomas P Minka}, year = {2006}, note = {Original S code by Richard A. Becker and Allan R. Wilks. R version by Ray Brownrigg Enhancements by Thomas P Minka. R package version 2.0-31}, } @Manual{Bates:06, title = {Matrix: A Matrix package for R}, author = {Douglas Bates and Martin Maechler}, year = {2006}, note = {R package version 0.995-12}, } @MANUAL{Koen:Ng:03, author = "Roger Koenker and Pin Ng", title = "{SparseM: Sparse Matrix Package for R}", year = 2003, note = {\url{http://www.econ.uiuc.edu/~roger/research/sparse/SparseM.pdf}}, } @Article{Furr:Gent:Nych:06, author = "R. Furrer and M. G. Genton and D. Nychka", title = "Covariance Tapering for Interpolation of Large Spatial Datasets", journal = "J. Comput. Graph. Statist.", fjournal = "Journal of Computational and Graphical Statistics", year = "2006", volume = {15}, number = {3}, pages = {502--523}, } @Book{Cres:93, author = "N. A. C. Cressie", title = "Statistics for Spatial Data", note = "Revised reprint of the 1991 edition, A Wiley-Interscience Publication", publisher = "John Wiley \& Sons Inc.", address = "New York, revised reprint", year = "1993", } @INCOLLECTION{Nych:00, author = "Nychka, D. W", title = "Spatial-process estimates as smoothers", editor = "Schimek, M. G.", booktitle = "Smoothing and Regression: Approaches, Computation, and Application", chapter= 13, pages = "393--424", publisher = "John Wiley \& Sons Inc.", address = "New York", year = 2000, } @Article{Brei:Frie:85, author = "L. Breiman and J. H. Friedman", title = "Estimating optimal transformations for multiple regression and correlations (with discussion)", journal = "J. Amer. Statist. Assoc.", fjournal = "Journal of the American Statistical Association", year = "1985", volume = "80", pages = "580--619", } @Article{Buja:Hast:Tibs:89, author = "A. Buja and T. J. Hastie and R. J. Tibshirani", title = "Linear smoothers and additive models (with discussion)", journal = "Ann. Statist.", fjournal = "Annals of Statistics", year = "1989", volume = "17", pages = "453--555", } @article{Ihak:Gent:96, author = {Ross Ihaka and Robert Gentleman}, title = {R: A Language for Data Analysis and Graphics}, journal = {Journal of Computational and Graphical Statistics}, fjournal = {Journal of Computational and Graphical Statistics}, year = 1996, volume = 5, number = 3, pages = {299--314} } @book {Geor:Liu:81, AUTHOR = {George, Alan and Liu, Joseph W. H.}, TITLE = {Computer solution of large sparse positive definite systems}, NOTE = {Prentice-Hall Series in Computational Mathematics}, PUBLISHER = {Prentice-Hall Inc.}, ADDRESS = {Englewood Cliffs, N. J.}, YEAR = {1981}, PAGES = {xii+324}, } @Book{Stei:99, author = "M. L. Stein", title = "Interpolation of Spatial Data", note = "Some theory for Kriging", publisher = "Springer-Verlag", address = "New York", year = "1999", } @Manual{R:07, title = {R: A Language and Environment for Statistical Computing}, author = {{R Development Core Team}}, organization = {R Foundation for Statistical Computing}, address = {Vienna, Austria}, year = {2007}, note = {{ISBN} 3-900051-07-0, \href{http://www.R-project.org}{\texttt{http://www.R-project.org}}}, } % url = {\href{http://www.R-project.org}{\texttt{http://www.R-project.org}}}, @Book{Mate:60, author = "B. Mat{\'e}rn", title = "Spatial Variation: {S}tochastic Models and their Application to some Problems in Forest Surveys and other Sampling Investigations", publisher = "Meddelanden Fran Statens Skogsforskningsinstitut, Band 49, Nr. 5, Stockholm", year = "1960", pages = "144", MRclass = "62.90 (62.97)", MRnumber = "29 \#6597", mrreviewer = "P. Whittle", } @article{hand:stei:93, author = {Handcock, M. S. and Stein, M. L.}, title = {{A Bayesian Analysis of Kriging}}, journal = {Technometrics}, fjournal = {Technometrics}, year = {1993}, volume = {35}, number = {4}, pages = {403-410} } @Book{Abra:Steg:70, editor = "M. Abramowitz and I. A. Stegun", title = "Handbook of Mathematical Functions", publisher = "Dover", address= "New York", year = "1970", } @Article{Zimm:Cres:92, author = {Zimmerman, D. L. and Cressie, N.}, title = {Mean squared prediction error in the spatial linear model with estimated covariance parameters}, fjournal = {Annals of the Institute of Statistical Mathematics}, journal = {Ann. Inst. Stat. Math.}, year = {1992}, volume = {44}, pages = {27-43}, } @Book{Harv:97, author = "D. A. Harville", title = "Matrix Algebra From a Statistician's Perspective", publisher = "Springer-Verlag", address = "New York", year = "1997", pages = "xviii+630", } @article{Furr:05, author= {Furrer, R.}, year= 2005, title= {Covariance Estimation under Spatial Dependence}, JOURNAL= {J. Multivariate Anal.}, fjournal= {Journal of Multivariate Analysis}, volume= {94}, NUMBER= {2}, PAGES= {366-381}, } @book{Spee:03, editor = {Terry P. Speed}, title = {Statistical analysis of gene expression microarray data}, publisher = {Chapman \& Hall/CRC}, year = 2003, } @ARTICLE{Held:etal:05, AUTHOR = {L. Held and I. Natario and S. Fenton and H. Rue and N. Becker}, TITLE = {Towards joint disease mapping}, JOURNAL = {Statistical Methods in Medical Research}, YEAR = 2005, VOLUME = 14, number = {1}, PAGES = {61-82}, } @ARTICLE{Knor:Rue:02, author = {L. Knorr-Held and H. Rue}, title = {On Block Updating in {M}arkov Random Field Models for Disease Mapping}, journal = {Scandinavian Journal of Statistics}, year = {2002}, volume = {29}, number = {4}, pages = {597--614} } @article{Held:Rass:00, title = {Bayesian Detection of Clusters and Discontinuities in Disease Maps }, author = {Knorr-Held, L. and Ra{\ss}er, G.}, journal = {Biometrics}, volume = {56}, number = {1}, pages = {13--21}, year = {2000}, publisher = {International Biometric Society}, } @article{Besa:York:Moll:91, author = "J. Besag and J. York and A. Molli\'e", title = "{Bayesian} image restoration, with two applications in spatial statistics (with discussion)", journal = "Annals of the Institute of Statistical Mathematics", year = 1991, volume = 43, pages = "1--59", } @INPROCEEDINGS{Moll:96, author = {A Molli\'e}, title = {Bayesian mapping of disease}, editor = {W. R. Gilks and S Richardson and D. J. Spiegelhalter}, booktitle = {Markov Chain Monte Carlo in Practice}, year = 1996, pages = {359--379}, publisher = {Chapman \& Hall, London} } spam/vignettes/figures/0000755000176200001440000000000013562501663014675 5ustar liggesusersspam/vignettes/figures/fig_ch2_factors.png0000644000176200001440000001304513562501663020430 0ustar liggesusersPNG  IHDRHQ(&7 PLTEG2 IDATx흋(E6< {v;1$7uI1   @$H "@D  @$H؊ж))?CSuz"(&J&Sv4 L$K,Źߐ"~(lw(I E+Z$LhwI*ryUnĉ{M)>S "O*ɭb-H֍F$﹯UFG&kDro\bVQ07sh"97.U "31FsR)gHޗiɮ]HLj墢".;$ԋ%YtHV6qzQ"k!'bZN]"MC.DD)iK%xA6 "d!I_"GH&Y4 D osӻB"}@iGqC mƼEZTֱD)I["-U5{J,p`V5(])YtD D m "HQY{V7|($\X"${^cHNDZZ4Yf9(s9/HE+eoqVyW32D6ga5(s9C${)b&QrH .!!R}DXWTO\~?."r4@&=?r`*i@0kDrBٵ;ĭM]˗M\be>#]yM"լH5n!AHxϻΌy.T9FZ^\֘'e39zTdS&"'O޵c.^Ĥ^ޝE*4O6M=OaUvu{V"ޥ^ޙ{tDnxMT䲲HHG}0߽ͼ+Q0MHK֢]ϻH-?-ĵ~=,·(q>ndp&PH\E~ k'= IJoqHJFݳ`.$H}*"ɪHm5vQva~>w.nkIbt ;D7Hb=VBgO6KK "x9Z$IV,cr9H@d1xIT>Cr9Vr"e<~8vrhaE$USaDuX"B ӏSVEJ=9F;40ՍH*00Drbàs RjkǣINΔvdv`.+wIE87=NJg9 ;2;0u7 !kƁ(IC0)s؂40X笘ȀQd[$!2 s$!x"Ǝ|K\ߏHΡ." D.$'ȧ/G.b9rt./"!B^0it. DHaƋt|Y'3kG|OV09fk D~`!„EjX5E lb§&ybb.RESA3)+&D'͔ѷHlrˍ\tt$.ӿ0 B<2)1mAH>a &#E*sy@dP?E (%pcl2j&]CP.%lDRǴA4?zzG(GS IsqW{1?ҥEW*?c5i~.k|^nբcUj\+"DX'ih&ž l<$h~^>"1$KnSpdX C8w^8B3>-8&ZÖK˶C$Fcu, Blr4l(THן3R}saf\—_*S$͑ a}w\r<2|06"10qis9ˈG$_TO8H$ bp˜ڌD) D@0WC󋅥Hiv4Cpvy^S |gnPfcHݿ/ʬ5b.2O;7'90"Z)Y0BLb WwafNPhk<0 ιpgH8^Fh8U][QyyxBsa*>S$c?#XBjM6x" IH.JZM~q]ۅf꼤9GH RRos_!+yi>Z$U.H>oʩTpiJBrќD:8C(l)Q0b f$@E{tʎ#Jˌ#"r &֮}Zz4௚3lc.L0IJ.Dzk7ԁUCJ.5|粈Ѕ9|f\D0$!smGZ3q-e1"FJ<c\ɢ˄]1F#' S~<A"܁Y.> {oD `~\T.) sZV턺nI%BTE#`yN.%"Gj"ϥ㔃\7d""IȥIszdv0DhQTK-DrFwl ѓ ?0;IsiNh"v% RdZrĞCX>&KhaV:ӧwF.%Z0? c"/%fNwz4kwX7;Z$~<2EAoF$T_)=N:4gx]hbb"igMf墝=@:|.$qWϋ⫄̕_wfkmrt\2F~@8ptV:#(Ri.FsOs"{`"9!:w՜yҪJ'釢QiHIT.]V`Ha-Y@j&d20޷;"׺Cp@"qɿYr<"w_eS3fƁH'glkF/rqE2IE2#붍 "ݷ ;Xi-FZua ,\r7ZN8ih.՝Dzw|۩IIۻOk%}W8t.\5/{G`I] Y­Vİ٩z-ko*R$+wЉtWLN"֒6)X;]LrVSD.Ɇp[ wt/ 潸^87"j M {;|H$fk[ ]07U}\ R­R"a1`S'6- D qI^UphKb"1i@(&- ~bߐs<+G :CT.Si OT& 尯:]Pq\dn]!#Y˪mbbO j`RGH"X"468~bҵ,]q޿\RIgH\xZX"4(s_$/+zkhXLWup/Qh\ܮ{/M#%sюH^(HYk[O#4GCD*#k^ y- HGpAP0 oz ?/\S,_ؓlrpY=guG>+:}ÿ8E1i`.o[p' gwHv4+O0V7uddcBM3ƌۦr.+#Z$搉R.Fl6d#&Q)Y+±kH&mu >LzKh]b W&]5HbdEdT,Rê,y-ryJ(ݵNyJ/hDZ/svŴ8&E:^fDHkf\ӓl8 w\)F`%I0V^,M,?jv0;AuFTN/T4di.MckQ0"-KHK(E3)}\rT6^y&0z\2L7z| FOm7>0i\ ?b˂'m D B|s.))HlZ0sHob"]w-6i\ R#W8᤽sH! RȽsHAl6"QSv.[☽h"q+ZwM>檘l ҏI"\"ŀHa RIEA)L$}"=g@pK \OA$ "H1 RB:* ߽C.'E"-U.>GHGpċ,IB.)="P5 еጬхqLB.7lab\~ e:>=er)FH{b.!"MB.l]oޓ '"lryq&"-W(j'r c?0F qƹ@0) D Ɇl0g6dC O_I"s.i\cc>r ߂\WlE"2\^$"oD1҇,lWX. ӸZ1KP0d. ӸZ1KD H "@D D:8::Je]ޑ#k[Ķl."^Y'qdlNj*@..KH`s̍}o+-D~\Z3H Q*""LCl}n rK[FY##oŜoDزk AuFKdB`_ @$H "@D  @$?]IENDB`spam/vignettes/figures/ill.png0000644000176200001440000001465013562501663016171 0ustar liggesusersPNG  IHDR $iCCPiccxڕgPY<@BPC*%Z(ҫ@PEl+4EQ@U)VD((bA7"Wy?g=8X'& 영ALi)OO7z? xo"DDX3+=e/1=<+]fRK|cלo,]z ){T8بlOrTzV $G&DPJGf/GnrAltL:5204gk!FgY߽zس {{t@wOm|:3<@t *K`  |d\ "U4& NNp\mp '@&+ <AX H Rt # YC AP4e@v*: :]nB#h >Ll¾Z8Ns|x7\' |+xa ʈ.FD!d3R#H+ҍ!!2|DaP4D9P|T*j3U:@P"4-A[y@t4: ].G7 { 0fgL&S9i\ b1X,Vz`ðl%v;#pF8G\0. +5.py8^oG7K n~ A`86Bp0JxK$UD/b,q+xx8FHI\R)ttL&kmtnr*MLO'!EZClH5OQp((9rʌ8^\C+&YZMPC"QXYKՠ:P##ԫqBSqi|vZm@IR%%%%%/H Cc$0J8RRZm# ۤ?0edet L[MBjFt'}mngG StYZ[6[Nb\հjJ*̪Jhʹ>l-Q ynjah;qNp^ M}ϡᙣccieg^k\\6\}\\i ܺaw}W'<}O=Yza<^xzz|4-}Oo ( n $ n ]fkYk\'.a݅aτCBC*6,b:*4r2*4j**z_tMLyL,7*Ms\m\GńD\bh$jR|Robrv`NJA0"uH*hL֦uӗ> ͌c֙ՙdKd'eoްkdcэ=ʹr6q6m6o٢%VǷo- 4 [w8h)+Y؟vUKaD"b~ yqwӒC{0{}e̲²wYn\^{p 〰­RrOBULp]u[|ͮjU-t8:z##G^47emjm,j|,&f%eDȉ'Ovֵ1ڊNS^˃Ӯ{ΰϴU?[Nk/:6t:c:]A]\t[v/H^(HqRΥ)gD_Yj^\ݸxj oZÃ< >x8(ћǙlE>ZLYZ M<2G //'&O;N}īW3JYZٿl&,]Vwzf=gO|??WA}>Mg-`*>k}et1qq?.r)ԕ cHRMz&u0`:pQ<PLTE(((***...666+++$$$555000ɾ""")))'''222...%%%///###888Ŀ___|||eee```[[[ W 'a'&`&&&& //ґ--**Ă//44쬯88222((( >>3311ˎ,,Ç..ߣ;;|||XXxxYYY999'''***!!!888444,,,)))###///wwwLLLQQQfffddd___nnnhhhKKQQddIIwwgtg_m_ffA}tRNSDǪwufչʹʹ3"Uٷٷմٷ$bKGDH pHYsHHFk>tIME 3 IDATx흋TRNQZi3-b _((bQ A[" ffM7LH;3w;_&3=IcO8Q`4ऍ'K3" 8^l`)&Eti* & H0`#F0`#/b#X/Fw9Pu;l+eGB ֽWkij8`uZ`]{u#`]{`#zE0C`1^#X?F^xu |@p6>]C]x}xG$s}XҀ]D`#F0`#F0i t~-X^'.c]Kb]k۫`Yl$m΂tv[EWLJ/X^K']Hst6: VDpnضW_:6vڂ/Rm/~q^tF0`#F0`#F0--%p4ǥo{vJ>)2g>&m"{oۥqȬG¡#F0`#F0`#vEA,XCĶ m+ Ы\jlaLr[xz8X--ߞ7X3+KD.WM(* ЫL7UOgr^=#`ͼF0`#F0`#F0IS>- ^ fڽ.Hҋ~agS.\`Z}ݼF0`#F0`#FЃyՈ+`;`Wb2:좥WfGcv2#`ד36T~B~f`>3jĂ =X"F0`#F0`#ַ`_/f4×i* 4`CoL~ {T|ABlL.?-Vɏagس>؄W@+pHKOowF,{ӿ3]xY2( LEP-c0+'poP<C( ZB7\kp}g )x!"t J:#qB<?$@T$ Gv"%H9R4 -OrF ,'PDP \ @ףqh{*=vл(*Dߠ `T)czs0,c[bkڱ^l{ 93c8=2p[qI\7}x]% f|'~?H XM9JH$l&:W ÄIH!HXD&"^!HTɘL # HVeiD#-h&rKG"/Q)kJ%REiܠSST՗@NޢNP?$h:4Z8-vvNkat}/~I!/&-MVKdD(YT]+A4OR=91XVZ bcb q#qoRV3D 'hBc%&C1v27SLSLd0O3&A$,rc%XgYX_R1R{ڥFc;GȰeddt<!;'ǔ˝{*o?&?(࢐Pp]aNhXxYqVdTtE5[e'yeyeW,!%M@Ujjj꼚ZZSu:G=^FnnMiM7<6q-VVCm6G;I}TT'^V.k{Xwx~ŪUhz\l6 }~~[50 M Iic35~y=ߙĘ1yl02mg܌on6kfa^g>ar|8[x {m->[Y ,Zagdj5FsM̚5*֑ BMQmmK;Uhfi67{Оoi`#X8$TY9ιyeUW~177[ۼ~GKOOguk|Ե}OϾ_ZW~F~~ jf-; C B M #5-sZwpTixQs !yå#7GGF,GzG6F.DEExxo+gccccccgW%8$$KtMO\LN:ܑBJH*ڟ6^.̰817g"3{LA`0K+kWDMvms⹩t64w|3n3os_r-- [Q[n+6eI;~)0,(/3xgoB].ڊDEcv!ᇡ=TV]|İdWzG~\w̬>¾}?Y.^W>y@WoWT:$VW\_3Zk_Q'_np#vGKM8QXWMAM9[eKH=!rۖ/kvkt_:̆oqwxۑk|G G?yK϶Nj=|!W_;fK/_>M-WWJ-33gg^zM{v ·O[L>-,qi̧9^Y&.W}J.P cHRMz&u0`:pQ<bKGD̿ pHYsHHFk>tIME !/(IDATx흿+Mut By? $BD KY"Wb;!Ag$D\I <ڻ^{voJϻS]UUbD4O5%\nH7HB4տE/(hIˈ"!d-߾>"!Gk"ESs1EJu=CKHJ~$) vzk@R9yw0[wZAsLĤf3g*2"- "9)6ҢPMt MMƔ?)p !)zu]m~>A8&Ar0UPۺ׺ު%;*{yB<7伆QxHxOQ﮼GI͛Xa1"RuX5%`I I:U$u=!HH7I-(Bshrz؅81pԼS21v?.#D߿ΔT!} Y5rޤv_ߧ40h94`$crx7N"x55eZ 'hX%As$鿌<|mtp DrvOɁ GrZ7DDorf1 ')D}} p C-)(yy~_s$|Էs(_-RI'h!$XoH&՘Iu, Cl%%٣ջz]>A8z#VM[kO$Go15EG>Vџx$ &G.-&MHkvU|nJ(n\$'#KT#1UC AHFĿ\)"4GoDɎڼI%^uGEbz<7c;#u=_AsBr^!6SslulMe^Qӓ6ptFulAZtt)թlٰa7/B#v$[ܶ(,ArptBr."..C_cR6v"@)oeGzw9\.DO_S8aq}3 fU+S^;6&c|^ȟ&pkznN}z}y3uWfmΗ~t=PwF4b׳:+UE֜΂pHUR4|dێ "M|RPO}^{A8ARbކ>UĤ7آ(|=A8 |U_"2DdCM#IH npygSc1QdD$C5 I+DQP^BJ*ʾ>,IQc't=, D>G2ϕ(ٷ]ESwyO1p4Li\6WV (/ FSs8cܻ tTgKLD*5PSR4v{C=( w?՗摌hb_S$$eg/u& I[)g^u&K1񐽻Kd#M, LY/!&(4gb![hrp>ѳwpPF5"9Ջ]xѦ`8ޕ#.1~-\?T>JqN#JH]xx%IbvËQt/4u2A=>@r?T3]t]ȩFlF$Wŏ@>psޙSͨrz~ѯژݫn>7&m$?o>}Eku:+}w%%()IPq/EL T0'u?wI8حH~vRxIJ>S6D8̓bwo#p2vQy3k's 04/HݜjFǝEtm]D>{OhmDtOͥFxv[I|i{&FQ \\`iv$)׿>8 (y)djF$9P㸸N$ҼM,9-$pH;^B !)ُFD7#z4%_|˷}86 9Q9Dݭf?8#HQՓ 'Oh#泞05'Ĺ&XC߼Enh`sn+_4(|8LZB9yZh(f|լʻMSNzXYuñsv fK();LoH 䜵wQdQD=5{BP6FEc*ZHt#wa>`!Ş"^N4;^/?;C"ä:c*j{?D~<ZՔ98y56?d*$FU/b/Y891KZ>w3>fm:1>DCfL4KN%1q+_7h55=oOo}(6̞0\O=LjG$k1**`w-/\o#Q ,]0~xgBz>2(iGcKYri|:E8R8r#1{#q! sSLG߆'B[t~xe"I=_eXbɫi($Db Y$_wW{?fKvNI8$n|[19hoN<TYBs MUsl<)p~GIQV(S=0Gn^ڈ`agk8D83%/)J ~y޼zJXqzj"1eg܈T)Ez̞`k\`8 ))7=*EMV.6?'R6d2<( Bc>TIyCǟd{@m':B{=ΝWDਧq:)=j||M*n yhY.~24ŖDCx(ywqΔݜ⦢Q!ħԔ@w/vī[u콩NNe[KԾZFsr0-XQ Qdl,ypܔ;Sh$缭s6rQS\D"l5Zv `Ș*uv%@/9ȁw[<6"eGQiؔMb4#i_pLħbKgnŠ?L--kNe>=sZ6=KOۀ9e{SBcL}UU>4a:v ӱ!uvA:y:D8lvm H_h EfSbǢ\y>&M3;'~p0vb̖}y)] F`q'[捤߁~ f6 ;󌮵/Lz ݫˠ4u᝝\%CP#_}zp;9;mQga zp0Ȼ|cH\Ò/;_`wa&xf|ӄ"'V’/⯢ 6+T<4%=j攏SLm9RL%9FLK8>Te$˽g<(ͺp ٘#t=%>G8KڙhS=}GTL*?-7_wz<ĝ\őBXAŕlAC-db;u]]nO,nٚnh?%D8u5>Nc 6jb# ާ>(лHNwz, |ðE"R"{-ޝqɼ wtz K5D8Fm~:d(~;OS_JҵlKɎIƬc"9?$"VrhHFĀϋDԔԟu@ Djєp؎) S yܘ)(9ې>)il) MDWDc=RʡDd0UDQjbГC;tz=?|0=(^8EzV9m, }v7М>/pyJvA3Nt=)&Gj?HNgluㄩ+MqPݰ5@i.+s|)*D82vTs0yENDx$Xh@%wa՚) ˾V Jv`^#As ɧ9$!YhuE΍л̪KSq# ;6k?qU_itj]SPag$&^hoά^sHKI.kUXž#6b* Rӽ{NCw=׬ެz6"Δ/; +?4nJ^-=ԝk)\XUª5(x2%68:wa՚CRh[sَMAg|fѩdR([+6$JijJyszpHF{{XsR%bg`K``2,tIC#VkV=p& = DsH(@! &+D>Fsn 4l ! j*U/"xJXTszLe^Q߇%u8j2Nڐ5hi#mizބE5Gh8`{"OF{ջV3ܱx_1޵MzYp]szLm{75TuCm%¿8YpN;#)ؚe ߐnN_[~.YG2;i2 _ũ²3p@~7o``Z9xDãKMx0,XsH4G4t.lB {,Ys8RՅ.i1{OS }.kbcg8zxEAӳ\*9'9!u0l\7mD]2A'J^=|޵{!wwwߐ9JI.uvcIQRAOu=tCIHy[0FƒX_2hy[9lG8$!6 }{69TQE)NӃYpHlo3.1; v!131$b@_N)@QQQ_6le*<(79zGy\υC"".EDqN`X_r% BG~/2 hb4eۭD$hjea4xH@ɱ#{_} (2"~'Q$\E/>0ϛ$@O&!r1^](rv#}iT9;빙xwd=#1;R׳eTp3p 9K2[D- $bjdfM4swGF>{ʒ.&$Y7Yƈu>ph/)z<$!z@_4H.$ף\59j]_c:ZޫzDVi u0!f>QG+BA>%Eۭ%)ڼ9g+®|d1yFlOw9w9DsuNrJ9N h2g %Hރ e0nsHN4iOS miƿrwIJt9L0͡؎srʥK 5;Sm0Dt2.eʦ|YސddBSȡC"і{dv{ShGȞQ%ѧٵxۑ8X6ZpҎaeA8Dޙʈ^Osau!]s@eCW"qWph4e'Š ŊYMjJ^lc2Mئ~zS0mΔ{UuY; \8DY[NSFat%ݸ%jh{zCv=E`VXvv ݎs-¡|qIGh&C "_-q qrBas=MmK4kPNYIٶ.E\gn߃_/1bgQzs!Fq`$餱dlT :95Gj"2~ \ dm`+e)Y51L45%fZ2r9OJ?KJze*ȑҷ2ޞ(gߦwH4HD xBw(zU*КOU# M WS$s8V!]_N\*2gSDaR FJ8Wbj+,$HN/SQ4`A@I;+ (dp>TԒSک%HNAƐx%&~Ih\)-OB?E;94n y4E7+j@QX(`t!eT}KS9wTM;,6Aer[tv ခ<s6c%얝3pCmjܹtJ' 1ivyВi%|^r^N%l1JMj*;gG8/f .i=)Ӻd91bcL-;7:s%u"m}/q"yM/.̺cܨ>ܦk %~FhbPO57%[p u9&Ȋ0r GbVqY9bfOoX< hD^;9tJ`G$"9aT'Dٜ9a.fna(93V[`atKwwpnU0iuؒ7p=$`4;/CGʗmDd2aj6XN$xyGOE1~fz P@ۿH%N7Ș4g9W .'Nʁ ؄wsw=j72W1%GV?ݥ+$Jn_{›"r3lānLm%޹"0E=h~HB›MsTrԴgCz$oA4blk_ \r?9v( I)lg8p^ͪLK>TvSMΛVSW%&e6!)TaEhJp@cHɦ<›qWwQdDӟBo=_@Rcrً5h=E0/[_hv$H]ϗW(R4U{֠#1)5%>:Db(?h9rl7颉T!I8oEBLMoy k**(1sh4%pkHDF-a'GiQhn"+i`bF%tEXtdate:create2018-07-20T13:32:33+02:002%tEXtdate:modify2018-07-20T13:32:33+02:004 tEXtpdf:HiResBoundingBox398x381+0+0tEXtpdf:VersionPDF-1.3 SIENDB`spam/R/0000755000176200001440000000000013571733331011421 5ustar liggesusersspam/R/rep_len64.R0000644000176200001440000000243113536451707013347 0ustar liggesusers# HEADER #################################################### # This is file spam/R/rep_len64.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ rep_len64 <- function(x, length.out, NAOK = getOption("spam.NAOK")){ if(getOption("spam.force64") || length.out > 2147483647){ .format64() return(.C64("rep_len64_c", SIGNATURE = c("double", "int64", "int64", "double"), x = x, lx = length(x), length = length.out, out = numeric_dc(length.out), INTENT = c("r","r","r","w"), NAOK = NAOK, PACKAGE = "spam64" )$out) } return(rep_len(x = x, length.out = length.out)) } spam/R/s4coerce.R0000644000176200001440000000342613536451710013257 0ustar liggesusers# HEADER #################################################### # This is file spam/R/s4coerce.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ # a few coercions that make sense... # showMethods(coerce) setAs("spam","logical", def=function(from) { if(getOption("spam.structurebased")) { return( as.logical(from@entries)) }else{ inefficiencywarning( gettextf("This operation may be inefficient"), prod(dim(from))) return( as.logical(as.matrix(from))) }}) setAs("spam","vector", def=function(from) { if(getOption("spam.structurebased")) { return( as.vector(from@entries)) }else{ inefficiencywarning( gettextf("This operation may be inefficient"), prod(dim(from))) return( as.vector(as.matrix(from))) }}) setAs("spam","integer", def=function(from) { if(getOption("spam.structurebased")) { return( as.integer(from@entries)) }else{ inefficiencywarning( gettextf("This operation may be inefficient"), prod(dim(from))) return( as.integer(as.matrix(from))) }}) setAs("spam","matrix", def=function(from) { inefficiencywarning( gettextf("This operation may be inefficient"), prod(dim(from))) return( as.logical(as.matrix(from))) }) setAs("spam","list", def=function(from) { return( triplet(from)) }) spam/R/definitions.R0000644000176200001440000015171513571446703014075 0ustar liggesusers# HEADER #################################################### # This is file spam/R/definitions.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ # We check that # 1. #colindices equals #entries # 2. class(entries) is "numeric" # 3. rowpointers[1] = 1 and rowpointers[MAX] = #entries + 1 # 4. dimension[1] == #rowpointers - 1 # # --- Test in C --- # c1. rowpointers must be increasing # c2. No NaN/NA/Inf in rowpointer, colindices or entries # c3. colindices are in domain [1, dimension[2]] # # Warning: if class(colindices) != class(rowpointers) validate_spam <- function(object) { # 1 if(length(object@entries) != length(object@colindices)) return("Length of slot 'entries' does not equal to length of slot 'colindices'.") # 2 if(!is.double(object@entries)) return("Slot 'entries' must be of type double (not integer).") # 3 if(object@rowpointers[1] != 1) return("Slot 'rowpointers' must be have 1 on the first position.") if(object@rowpointers[length(object@rowpointers)] != length(object@entries) + 1) return("Last value of rowpointers is incorrect.") # 4 if(length(object@rowpointers) != object@dimension[1] + 1) return("Slot 'rowpointers' has not expected length.") # --- For performance issues, the following tests should be implemented in C --- # c1 result <- any(head(object@rowpointers, n=-1) > object@rowpointers[-1], na.rm=TRUE) if(result == TRUE) return("Slot 'rowpointers' is not increasing.") # c2 if(any(!is.finite(object@rowpointers))) return("Slot 'rowpointers' contains non-finite elements.") if(any(!is.finite(object@colindices))) return("Slot 'colindices' contains non-finite elements.") # raise a warning if any non-finite element is in entries: if(!getOption("spam.NAOK") && any(!is.finite(object@entries))) warning("Slot 'entries' contains non-finite elements.") if(any(object@colindices < 1) | any(object@colindices > object@dimension[2])) return("Slot 'colindices' contains element outside the domain [1, ncol].") return(TRUE) } setClass( Class = "spam", slots = c(entries="numeric", colindices="numeric", rowpointers="numeric", dimension="numeric" ), prototype = prototype(entries=0, colindices=1, rowpointers=c(1,2), dimension=c(1,1) ), validity = validate_spam ) # Internal function to create new spam or spam64 object, depending on the size. .newSpam <- function(entries=0, colindices=1, rowpointers=NULL, dimension=c(1,1), force64=getOption("spam.force64") ) { if(is.null(rowpointers)) { rowpointers <- c(1,rep_len64(2,dimension[1])) } if(force64 || length(colindices) > 2147483647 || length(colindices) > 2147483647 || max(dimension) > 2147483647 ){ newx <- new("spam") slot(newx,"entries",check=FALSE) <- entries entries <- NULL slot(newx,"colindices",check=FALSE) <- as.numeric(colindices) colindices <- NULL slot(newx,"rowpointers",check=FALSE) <- as.numeric(rowpointers) rowpointers <- NULL slot(newx,"dimension",check=FALSE) <- as.numeric(dimension) return(newx) } else { newx <- new("spam") slot(newx,"entries",check=FALSE) <- entries entries <- NULL slot(newx,"colindices",check=FALSE) <- as.integer(colindices) colindices <- NULL slot(newx,"rowpointers",check=FALSE) <- as.integer(rowpointers) rowpointers <- NULL slot(newx,"dimension",check=FALSE) <- as.integer(dimension) return(newx) } } print.spam <- function(x,...) { SS <- .format.spam(x, validate = FALSE) if (prod(x@dimension) < getOption("spam.printsize")) { print(as.matrix.spam(x),...) } else { if ( (length(x@entries)==1) && (x@entries[1]==0)) { cat("Zero matrix of dimension ",x@dimension[1],"x", x@dimension[2],".\n",sep="", fill=TRUE) }else { cat("Matrix of dimension ",x@dimension[1],"x", x@dimension[2], " with (row-wise) nonzero elements:\n",sep="", fill=TRUE) print(x@entries,...) } } cat(paste0("Class 'spam' (", SS$name, ")\n")) invisible(NULL) } setMethod("show","spam", function(object) print.spam(x = object)) setMethod("print","spam", print.spam) setMethod("length<-","spam",function(x,value) stop("operation not allowed on 'spam' object") ) setMethod("length","spam",function(x) length(x@entries) ) ## equivalent to x@rowpointers[x@dimension[1]+1]-1 ## however this resulted in a strange error: ## R version 3.2.1 (2015-06-18) -- "World-Famous Astronaut" ## Platform: x86_64-unknown-linux-gnu (64-bit) ## > require(spam) ## Spam version 1.4-0 (2016-08-29) is loaded. ## > gctorture(TRUE) ## > length(spam(1)) ## Error: unimplemented type 'integer' in 'coerceToInteger' setMethod("c","spam", function(x,...){ if(getOption("spam.force64") || .format.spam(x)$package != "spam") SS <- .format64() else SS <- .format32 dimx <- x@dimension cx <- .C64("spamcsrdns", SIGNATURE = c(SS$signature, "double", SS$signature, SS$signature, "double"), nrow = x@dimension, entries = x@entries, colindices = x@colindices, rowpointers = x@rowpointers, res = vector_dc("double", prod(dimx)), INTENT = c("r", "r", "r", "r", "rw"), NAOK = getOption("spam.NAOK"), PACKAGE = SS$package )$res if (length( list(...)) < 1){ return( cx) }else{ return( c( cx, c(...))) } }) ######################################################################## # diag and derivatives "diag.spam" <- function(x=1, nrow, ncol) { if (is.spam(x)) return( diag.of.spam( x, nrow, ncol)) if (is.array(x) && length(dim(x)) != 1) stop("first argument is array, but not matrix.") if (missing(x)) n <- as.integer(nrow) else if (length(x) == 1 && missing(nrow) && missing(ncol)) { n <- as.integer(x) x <- 1 } else n <- length(x) if (!missing(nrow)) n <- as.integer(nrow) if(missing(ncol)) ncol <- n p <- as.integer(ncol) m <- min(n, p) newx <- new("spam") slot(newx,"entries",check=FALSE) <- vector("double", m) newx@entries[1:m] <- as.double(x) slot(newx,"colindices",check=FALSE) <- 1:m slot(newx,"rowpointers",check=FALSE) <- as.integer(c(1:m,rep(m+1,n+1-m))) slot(newx,"dimension",check=FALSE) <- c(n,p) return(newx) } spam_diag <- function(x=1, nrow, ncol) diag.spam(x=x, nrow, ncol) "diag<-.spam" <- function(x, value) { if(getOption("spam.force64") || .format.spam(x)$package != "spam") SS <- .format64() else SS <- .format32 nrow <- x@dimension[1] minrc <- min( x@dimension) if (length(value)==1) value <- rep(value,minrc) else if (length(value)!=minrc) stop("replacement diagonal has wrong length") #!7# if(2147483647 < minrc + length(x@entries)) SS <- .format64() z <- .C64("setdiagmat", SIGNATURE=c(SS$signature, SS$signature, "double", SS$signature, SS$signature, "double", SS$signature), nrow = nrow, n = minrc, a = c(x@entries, vector("double", minrc)), ja = c(x@colindices, vector(SS$type, minrc)), ia = x@rowpointers, diag = value, iw = vector_dc(SS$type, nrow), #!8# INTENT=c("r", "r", "rw", "rw", "rw", "r", "r"), NAOK= getOption("spam.NAOK"), PACKAGE = SS$package) nz <- z$ia[nrow+1]-1 entries <- z$a colindices <- z$ja rowpointers <- z$ia rm(z) length(entries) <- nz length(colindices) <- nz return(.newSpam( entries=entries, colindices=colindices, rowpointers=rowpointers, dimension=x@dimension )) } "diag.spam<-" <- get("diag<-.spam") diag.of.spam <- function(x, nrow, ncol) { if(getOption("spam.force64") || .format.spam(x)$package != "spam") SS <- .format64() else SS <- .format32 len <- min(x@dimension) result <- .C64("getdiag", SIGNATURE=c("double", SS$signature, SS$signature, SS$signature, "double"), a = x@entries, colindices = x@colindices, rowpointers = x@rowpointers, len = len, diag = vector_dc("double",len), INTENT=c("r", "r", "r", "r", "w"), NAOK = getOption("spam.NAOK"), PACKAGE = SS$package ) return(result$diag) } setMethod("diag","spam",diag.of.spam) setMethod("diag<-","spam",get("diag<-.spam")) ######################################################################## t.spam <- function(x){ # TODO: Check if we need to switch to 64-bit (in case of too many rows/cols) if(getOption("spam.force64") || .format.spam(x)$package != "spam") SS <- .format64() else SS <- .format32 dimx <- x@dimension nz <- x@rowpointers[dimx[1]+1]-1 z <- .C64("transpose", SIGNATURE=c(SS$signature, SS$signature, "double", SS$signature, SS$signature, "double", SS$signature, SS$signature), n = dimx[1], m = dimx[2], a = x@entries, ja = x@colindices, ia = x@rowpointers, entries = vector_dc("double",nz), colindices = vector_dc(SS$type,nz), rowpointers = vector_dc(SS$type,dimx[2]+1), INTENT = c("r", "r", "r", "r", "r", "w", "w", "rw"), NAOK = getOption("spam.NAOK"), PACKAGE = SS$package) return(.newSpam( entries=z$entries, colindices=z$colindices, rowpointers=z$rowpointers, dimension=dimx[2:1] )) } setMethod("t","spam",t.spam) ######################################################################## "is.spam" <- function(x) is(x,"spam") "as.spam" <- function(x, eps = getOption("spam.eps")) stop("coercion not defined form this class") "spam" <- function(x, nrow = 1, ncol = 1, eps = getOption("spam.eps")) stop("argument 'x' should be of mode 'numeric' (or 'spam')") as.spam.spam <- function(x, eps = getOption("spam.eps")) { force64 <- getOption("spam.force64") if(force64) SS <- .format64() else SS <- .format.spam(x) if (eps < .Machine$double.eps) stop("'eps' should not be smaller than machine precision", call.=FALSE) dimx <- x@dimension z <- .C64("cleanspam", SIGNATURE = c(SS$signature, "double", SS$signature, SS$signature, "double"), nrow=dimx[1], entries=x@entries, colindices=x@colindices, rowpointers=x@rowpointers, eps=eps, INTENT=c("r", "rw", "rw", "rw", "r"), NAOK = getOption("spam.NAOK"), PACKAGE = SS$package ) nz <- z$rowpointers[dimx[1]+1]-1 if(nz==0) { return(.newSpam( dimension=dimx, force64 = force64 )) } return(.newSpam( entries=z$entries[1:nz], colindices=z$colindices[1:nz], rowpointers=z$rowpointers[1:(dimx[1]+1)], dimension=dimx, force64=force64 )) } "cleanup" <- function(x, eps = getOption("spam.eps")) { if (is.spam(x)) as.spam.spam(x,eps) else x } as.spam.matrix <- function(x, eps = getOption("spam.eps")) { force64 <- getOption("spam.force64") if (eps<.Machine$double.eps) stop("'eps' should not be smaller than machine precision",call.=FALSE) dimx <- dim(x) nonz <- abs(x) > eps nz <- sum(nonz, na.rm = TRUE) + sum(!is.finite(nonz)) #only zero entries if(nz==0) { return(.newSpam( dimension=dimx, force64=force64 )) } # EXPLICIT-STORAGE-FORMAT: Depending on the length of x, use 32 or 64-bit: SS <- if( force64 || nz > 2147483647 || max(dimx) > 2147483647 ){ .format64() }else{ .format32 } z <- .C64("spamdnscsr", SIGNATURE=c(SS$signature, SS$signature, "double", SS$signature, "double", SS$signature, SS$signature, "double"), nrow = dimx[1], ncol = dimx[2], x = x, dimx[1], entries = vector_dc("double",nz), colindices = vector_dc(SS$type,nz), rowpointers = vector_dc(SS$type,dimx[1]+1), eps = eps, INTENT=c("r", "r", "r", "r", "w", "w", "w", "r"), NAOK = getOption("spam.NAOK"), PACKAGE = SS$package ) return(.newSpam( entries=z$entries, colindices=z$colindices, rowpointers=z$rowpointers, dimension=dimx, force64 = force64)) } "as.spam.numeric" <- function(x, eps = getOption("spam.eps")) { if (eps<.Machine$double.eps) stop("'eps' should not be smaller than machine precision",call.=FALSE) force64 <- getOption("spam.force64") poselements <- (abs(x)>eps) if (any(!is.finite(x))) { poselements[!is.finite(x)] <- TRUE } lx <- length(x) nz <- sum(as.numeric(poselements)) # empty matrix if (identical(nz,0)){ return( .newSpam( # rowpointers = c(1,rep_len64(2,lx)), dimension = c(lx,1), force64 = force64 ) ) } return( .newSpam( entries = as.double(x[poselements]), colindices = rep_len64(1, nz), rowpointers = cumsum(c(1, poselements)), dimension = c(lx,1), force64 = force64 ) ) } as.spam.dist <- function(x, eps = getOption("spam.eps")) { if (eps<.Machine$double.eps) stop("'eps' should not be smaller than machine precision",call.=FALSE) if (any(!is.finite(x))) { warning("'NA/NaN/Inf' coerced to zero") x[!is.finite(x)] <- 0 } dimx <- attr(x,"Size") size <- dimx*(dimx-1)/2 force64 <- getOption("spam.force64") if(force64 || dimx^2 > 2147483647) SS <- .format64() else SS <- .format32 z <- .C64("disttospam", SIGNATURE = c(SS$signature, "double", "double", SS$signature, SS$signature, "double"), nrow=dimx, #r x=as.vector(x,"double"), #r entries=vector_dc("double",size), #w colindices=vector_dc("integer",size), #w rowpointers=vector_dc("integer",dimx+1), #w eps=eps, #r INTENT = c("r", "r", "w", "w", "w", "r"), NAOK=getOption("spam.NAOK"), PACKAGE = SS$package ) nz <- z$rowpointers[dimx+1]-1 if(nz==0) return( .newSpam( # rowpointers = c( 1, rep( 2, dimx)), dimension = c( dimx, dimx), force64 = force64)) return(.newSpam( entries=z$entries[1:nz], colindices=z$colindices[1:nz], rowpointers=z$rowpointers[1:(dimx+1)], dimension=c(dimx,dimx), force64 = force64 )) } "as.spam.list" <- function(x, eps = getOption("spam.eps")) spam.list(x,eps) spam.numeric <- function(x, nrow = 1, ncol = 1, eps = getOption("spam.eps")) { force64 <- getOption("spam.force64") if (eps<.Machine$double.eps) stop("'eps' should not be smaller than machine precision",call.=FALSE) if (any(!is.finite(x))) { warning("'NA/NaN/Inf' coerced to zero") x[!is.finite(x)] <- 0 } lenx <- length( x) if (missing(nrow)) nrow <- ceiling( lenx/ncol) else if (missing(ncol)) ncol <- ceiling( lenx/nrow) dimx <- c(nrow, ncol) if (lenx != prod(nrow, ncol)) { if(lenx==1 && abs(x) eps)) if(is.na(nz) | is.nan(nz)) stop("NA or NaN in matrix.") if(nz==0) { return(.newSpam( dimension=dimx, force64=force64 )) } # EXPLICIT-STORAGE-FORMAT: Depending on the length of x, use 32 or 64-bit: if(force64 || nz > 2147483647 || max(dimx) > 2147483647 ) SS <- .format64() else SS <- .format32 z <- .C64("spamdnscsr", SIGNATURE=c(SS$signature, SS$signature, "double", SS$signature, "double", SS$signature, SS$signature, "double"), nrow = dimx[1], ncol = dimx[2], x = x, dimx[1], entries = vector_dc("double",nz), colindices = vector_dc(SS$type,nz), rowpointers = vector_dc(SS$type,dimx[1]+1), eps = eps, INTENT=c("r", "r", "r", "r", "w", "w", "w", "r"), NAOK = getOption("spam.NAOK"), PACKAGE = SS$package ) entries <- z$entries colindices <- z$colindices rowpointers <- z$rowpointers z <- NULL return( .newSpam( entries = entries, colindices = colindices, rowpointers = rowpointers, dimension = dimx, force64 = force64)) } setOldClass(c("dist", "numeric")) setGeneric("as.spam") setMethod("as.spam","spam", as.spam.spam) setMethod("as.spam","matrix", as.spam.matrix) setMethod("as.spam","numeric",as.spam.numeric) setMethod("as.spam","dist", as.spam.dist) setGeneric("spam") setMethod("spam","numeric",spam.numeric) setMethod("spam","spam",as.spam) triplet <- function(x, tri=FALSE){ # inverse of spam.list dimx <- dim(x) if (length(dimx)!=2) stop("'x' should be a matrix like object of dim 2") if (is.spam(x)) { return(c({ if (tri) list(i=rep(1:dimx[1],diff(x@rowpointers)), j= x@colindices) else list(indices=cbind(rep(1:dimx[1],diff(x@rowpointers)), x@colindices) ) }, list(values=x@entries) ) ) } else { return(c({ if (tri) list(i=rep.int(1:dimx[1],dimx[2]), j=rep.int(1:dimx[2],rep.int(dimx[1],dimx[2]))) else list(indices=cbind(rep.int(1:dimx[1],dimx[2]), rep.int(1:dimx[2],rep.int(dimx[1],dimx[2])))) } , list(values=c(x)) ) ) } } ######################################################################## as.matrix.spam <- function(x, ...) { if( getOption("spam.force64") || .format.spam(x)$package == "spam64") SS <- .format64() else SS <- .format32 dimx <- x@dimension m <- .C64("spamcsrdns", SIGNATURE = c(SS$signature, "double", SS$signature, SS$signature, "double"), nrow = dimx[1], entries = x@entries, colindices = x@colindices, rowpointers = x@rowpointers, res = vector_dc("double", prod(dimx)), INTENT = c("r", "r", "r", "r", "rw"), NAOK = getOption("spam.NAOK"), PACKAGE = SS$package)$res dim(m) <- dimx return(m) } setMethod("as.matrix","spam",as.matrix.spam) "as.vector.spam" <- function(x, mode="any"){ if(getOption("spam.structurebased")) { return( as.vector( x@entries, mode=mode)) } else { inefficiencywarning( gettextf("This `as.vector` coercion operation may be inefficient"), prod(dim(x))) return( as.vector( as.matrix(x), mode=mode)) } } setMethod("as.vector","spam",as.vector.spam) ######################################################################## "complement.spam" <- function(x){ # this function returns the structure of the zeros of the spam object x. force64 <- getOption("spam.force64") nrow <- x@dimension[1] ncol <- x@dimension[2] nnz <- x@rowpointers[nrow+1]-1 nz <- prod(nrow,ncol) - nnz # we work through special cases if(nz == 0){ ## print("1") return( spam(0, nrow, ncol)) } if(nnz == 1 && x@entries == 0){ ## print("2") return( spam(1, nrow, ncol)) } # normal case, proceed to efficient function ## print("3") if( force64 || .format.spam(x)$package == "spam64" || nz > 2147483647 || nrow > 2147483646) SS <- .format64() else SS <- .format32 z <- .C64("notzero", SIGNATURE=c(SS$signature, SS$signature, SS$signature, SS$signature, SS$signature, SS$signature, SS$signature, SS$signature), ja = x@colindices, ia = x@rowpointers, nrow = nrow, ncol = ncol, nnz = nnz, nz = nz, colindices = vector_dc( SS$type, nz), rowpointers = vector_dc( SS$type, nrow+1), INTENT=c("r", "r", "r", "r", "r", "r", "w", "w"), NAOK=getOption("spam.NAOK"), PACKAGE= SS$package ) ## newx <- new("spam") ## slot(newx,"entries",check=FALSE) <- rep.int(1.0,nz) ## slot(newx,"colindices",check=FALSE) <- z$colindices ## slot(newx,"rowpointers",check=FALSE) <- z$rowpointers ## slot(newx,"dimension",check=FALSE) <- x@dimension return(.newSpam( entries = rep_len64(1.0, nz), colindices = z$colindices, rowpointers = z$rowpointers, dimension = x@dimension, force64 = force64 )) } # ASSIGNING: ########################################################################################## # as S3subsetting causes problems, we eliminate this... #"[<-.spam" <- function (x, rw, cl,value) {#cat("qq"); # assign.spam(x,rw,cl,value) } setReplaceMethod("[", signature(x = "spam", i = "missing", j = "missing", value = "ANY"), function (x, i, j, value) {#cat("mm"); assign.spam(x,1:x@dimension[1],1:x@dimension[2],value)}) setMethod("[<-",signature(x="spam",i="vector",j="vector", value = "spam"), function (x, i, j, value) {#### FIXME Highly inefficient! inefficiencywarning( "Performing inefficient replacement...", prod(dim(value))) as.spam(assign.spam(x,i,j,as.matrix(value)))} ) setMethod("[<-",signature(x="spam",i="missing",j="vector", value = "spam"), function (x, i, j, value) {#### FIXME Highly inefficient! inefficiencywarning( "Performing inefficient replacement...", prod(dim(value))) as.spam(assign.spam(x,1:x@dimension[1],j,as.matrix(value)))} ) setMethod("[<-",signature(x="spam",i="vector",j="missing", value = "spam"), function (x, i, j, value) {#### FIXME Highly inefficient! inefficiencywarning( "Performing inefficient replacement...", prod(dim(value))) as.spam(assign.spam(x,i,1:x@dimension[2],as.matrix(value)))} ) setMethod("[<-",signature(x="spam",i="vector",j="missing", value = "ANY"), function (x, i, j, value) {#cat(i); assign.spam(x,i,1:x@dimension[2],value)} ) setMethod("[<-",signature(x="spam",i="vector",j="vector", value = "ANY"), function (x, i, j, value) {#cat("vv"); assign.spam(x,i,j,value)} ) setMethod("[<-",signature(x="spam",i="missing",j="vector", value = "ANY"), function (x, i, j, value) {#cat(j); assign.spam(x,1:x@dimension[1],j,value)} ) setMethod("[<-",signature(x="spam",i="matrix",j="missing", value = "ANY"), function (x, i, j, value) {#cat("Mm"); assign.spam(x,i,NULL,value) }) setMethod("[<-",signature(x="spam",i="matrix",j="matrix",value = "ANY"), function (x, i, j, value) {#cat("MM"); assign.spam(x,cbind(c(i),c(j)),NULL,value) }) setMethod("[<-",signature(x="spam",i="spam",j="missing", value = "ANY"), function (x, i, j, value) { dimx <- x@dimension nrow <- dimx[1] ncol <- dimx[2] if ( i@dimension[1]>nrow | i@dimension[2]>ncol) stop("subscript out of bounds",call.=FALSE) if ( ( (i@rowpointers[i@dimension[1]+1]-1) %%length(value))!= 0) stop("number of items to replace is not a multiple of replacement length") nzmax <- as.integer(min(prod(nrow,ncol), i@rowpointers[i@dimension[1]+1]+x@rowpointers[nrow+1]-2)) if (length(value)!= (i@rowpointers[i@dimension[1]+1]-1) ) value <- rep(value, (i@rowpointers[i@dimension[1]+1]-1) %/%length(value)) ## z <- .Fortran("subass", ## as.integer(nrow), as.integer(ncol), ## as.double(x@entries), as.integer(x@colindices), as.integer(x@rowpointers), ## b=as.double(value), bj=as.integer(i@colindices), bi=as.integer(i@rowpointers), ## c=vector("double",nzmax),jc=vector("integer",nzmax),ic=vector("integer",nrow+1), ## nzmax=as.integer(nzmax), ## PACKAGE="spam") if(getOption("spam.force64") || .format.spam(x)$package != "spam" || .format.spam(i)$package != "spam") SS <- .format64() else SS <- .format32 z <- .C64("subass", ## subroutine subass(nrow,ncol,a,ja,ia,b,jb,ib,c,jc,ic,nzmax) SIGNATURE = c(SS$signature, SS$signature, "double", SS$signature, SS$signature, "double", SS$signature, SS$signature, "double", SS$signature, SS$signature, SS$signature ), nrow, ncol, x@entries, x@colindices, x@rowpointers, b = value, bj = i@colindices, bi = i@rowpointers, c = vector_dc( "double", nzmax), jc = vector_dc( SS$type, nzmax), ic = vector_dc( SS$type, nrow+1), nzmax = nzmax, INTENT = c("r", "r", "r", "r", "r", "r", "r", "r", "w", "w", "w", "r" ), PACKAGE = SS$package) cnz <- z$ic[nrow+1]-1 return(.newSpam( entries = z$c[1:cnz], colindices = z$jc[1:cnz], rowpointers = z$ic[1:(nrow+1)], dimension = c(nrow,ncol))) } ) setMethod("[<-", signature(x = "spam", i = "ANY", j = "ANY", value = "ANY"), function(x,i,j, value){# cat(value,class(value)) stop("invalid or not-yet-implemented 'spam' subassigning")}) "assign.spam" <- function (x, rw, cl,value) { # we separate into cases where: # (A) rw matrix: # 1: logical: transformation to spam and extract structure # 2: two column matrix: extract (i,j) as given by the lines. # 3: all else extract x[ c( rw)] # (B) rw and cl one element: ((i,j) # (C) rw and cl vectors: (i1:i2,j1:j2) [i1<=i2, j1<=j2] # (c(i1,...,ii),c(j1,...,jj)) [arbitrary block] if (!is.numeric(value)) stop(paste("Assignment of numeric structures only, here",class(value))) dimx <- x@dimension nrow <- dimx[1] ncol <- dimx[2] if (is.matrix(rw)) { if (is.logical(rw)) { return( x[as.spam(rw)] <- value) } if (dim(rw)[2]==2) { ir <- rw[,1] jr <- rw[,2] } else { ir <- c(rw-1) %% nrow + 1 jr <- c(rw-1) %/% nrow + 1 rw <- cbind(ir,jr) } if ( (min(ir)<1)|(max(ir)>x@dimension[1])|(min(jr)<1)|(max(jr)>x@dimension[2])) stop("subscript out of bounds",call.=FALSE) if (any(duplicated(cbind(ir,jr)))) stop("only unique index for subassigning",call.=FALSE) nir <- length(ir) if ( (nir%%length(value))!= 0) stop("number of items to replace is not a multiple of replacement length") value <- rep(value, nir%/%length(value)) ord <- order(ir,jr) rw <- rw[ord,,drop=F] ## print("1") ## bia <- .Fortran("constructia", ## as.integer(nrow),as.integer(nir), ## rowpointers=vector("integer",nrow+1), ## ir=as.integer(c(rw[,1],0)), ## PACKAGE="spam")$rowpointers if( getOption("spam.force64") || nrow+1 > 2147483647 ) SS <- .format64() else SS <- .format32 bia <- .C64("constructia", SIGNATURE = c( SS$signature, SS$signature, SS$signature, SS$signature), nrow, nir, rowpointers = vector_dc( SS$type, nrow+1), ir = c(rw[,1],0), INTENT = c("r", "r", "w", "r"), PACKAGE = SS$package)$rowpointers nzmax <- as.integer(min(prod(nrow,ncol), nir+x@rowpointers[nrow+1])+2) ## z <- .Fortran("subass", ## as.integer(nrow),as.integer(ncol), ## as.double(x@entries), as.integer(x@colindices), as.integer(x@rowpointers), ## b=as.vector(value[ord],"double"), ## bj=as.vector(rw[,2],"integer"), bi=as.integer(bia), ## entries=vector("double",nzmax), ## colindices=vector("integer",nzmax), ## rowpointers=vector("integer",nrow+1), ## nzmax=as.integer(nzmax), ## NAOK=getOption("spam.NAOK"),PACKAGE="spam") if( getOption("spam.force64") || .format.spam(x)$package != "spam" || length( bia) > 2147483647 ) SS <- .format64() else SS <- .format32 z <- .C64("subass", SIGNATURE = c(SS$signature, SS$signature, "double", SS$signature, SS$signature, "double", SS$signature, SS$signature, "double", SS$signature, SS$signature, SS$signature ), nrow, ncol, x@entries, x@colindices, x@rowpointers, b = as.vector( value[ord], "double" ), bj = as.vector( rw[,2], "integer" ), bi = bia, entries = vector_dc( "double", nzmax), colindices = vector_dc( SS$type, nzmax), rowpointers = vector_dc( SS$type, nrow+1), nzmax = nzmax, INTENT = c("r", "r", "r", "r", "r", "r", "r", "r", "w", "w", "w", "r" ), NAOK=getOption("spam.NAOK"), PACKAGE = SS$package) cnz <- z$rowpointers[nrow+1]-1 if (cnz<0) { cat("Negative cnz in subassigning, forced to one. Please report.") return( spam(0)) } return(.newSpam( entries = z$entries[1:cnz], colindices = z$colindices[1:cnz], rowpointers = z$rowpointers, dimension = c(nrow,ncol) )) } # negative subsetting: if ( max(rw)<0 ) rw <- seq_len( nrow)[rw] if ( max(cl)<0 ) cl <- seq_len( ncol)[cl] # logical if (is.logical(rw)) rw <- seq_len( nrow)[rw] if (is.logical(cl)) cl <- seq_len( ncol)[cl] # sanity check if (length(rw)==0) stop("You should assign at least one element for the rows",call.=FALSE) if (length(cl)==0) stop("You should assign at least one element for the columns",call.=FALSE) if ( (min(rw)<1)|(max(rw)>x@dimension[1])|(min(cl)<1)|(max(cl)>x@dimension[2])) stop("subscript out of bounds",call.=FALSE) if (is.vector(rw) && is.vector(cl)) { if (any(duplicated(rw))||any(duplicated(cl))) stop("only unique index for subassigning",call.=FALSE) nrw <- length(rw) # length returns an integer, so is a product therof ncl <- length(cl) bnz <- nrw*ncl if ( (bnz%%length(value))!= 0) stop("number of items to replace is not a multiple of replacement length") # we pack the value into a vector _row by row_ value <- c(t(array(as.double(value),c(nrw,ncl))[order(rw),order(cl)])) bia <- vector("integer",nrow) # bia has size of nrow + 1 bia[rw] <- ncl # in each row we have ncl new objects bia <- as.integer(c(1,cumsum(bia)+1)) # we construct now a sparse matrix containing the "value" at positions rw and cl. # then we use the subassign function. nzmax <- as.integer(min(prod(nrow,ncol), bnz+x@rowpointers[nrow+1])+2) ## print("2") ## z <- .Fortran("subass", ## as.integer(nrow),as.integer(ncol), ## as.double(x@entries), as.integer(x@colindices) ,as.integer(x@rowpointers), ## b=as.double(value), ## bj=as.integer(rep(sort(as.integer(cl)),nrw)), ## bi=as.integer(bia), ## entries=vector("double",nzmax),colindices=vector("integer",nzmax), ## rowpointers=vector("integer",nrow+1), ## nzmax=as.integer(nzmax), ## NAOK=getOption("spam.NAOK"),PACKAGE="spam") if( getOption("spam.force64") || .format.spam(x)$package != "spam" || length( bia) > 2147483647 ) SS <- .format64() else SS <- .format32 z <- .C64("subass", SIGNATURE = c(SS$signature, SS$signature, "double", SS$signature, SS$signature, "double", SS$signature, SS$signature, "double", SS$signature, SS$signature, SS$signature ), nrow, ncol, x@entries, x@colindices, x@rowpointers, b = value, bj = rep_len64(sort(as.integer(cl)),nrw*length(cl)), bi = bia, entries = vector_dc( "double", nzmax), colindices = vector_dc( SS$type, nzmax), rowpointers = vector_dc( SS$type, nrow+1), nzmax = nzmax, INTENT = c("r", "r", "r", "r", "r", "r", "r", "r", "w", "w", "w", "r" ), NAOK = getOption("spam.NAOK"), PACKAGE = SS$package) cnz <- z$rowpointers[nrow+1]-1 return(.newSpam( entries = z$entries[1:cnz], colindices = z$colindices[1:cnz], rowpointers = z$rowpointers, dimension = c(nrow,ncol) )) } stop("invalid or not-yet-implemented 'spam' subsetting") } #!8# # x:spam, y:matrix, returns matrix .spam.matmul.mat <- function(x,y) { nrow <- x@dimension[1] ncol <- x@dimension[2] yrow <- dim(y)[1] ycol <- dim(y)[2] # EXPLICIT-STORAGE-FORMAT SS <- .format.spam(x) if( getOption("spam.force64")|| as.numeric(nrow)*as.numeric(ycol) > 2147483647) SS <- .format64() if(yrow != ncol) stop("not conformable for multiplication") z <- .C64("amuxmat", SIGNATURE=c(SS$signature, SS$signature, SS$signature, "double", "double", "double", SS$signature, SS$signature), nrow, yrow, ycol, y, y = vector_dc("double",nrow*ycol), x@entries, x@colindices, x@rowpointers, INTENT=c("r", "r", "r", "r", "w", "r", "r", "r"), NAOK = getOption("spam.NAOK"), PACKAGE = SS$package)$y dim(z) <- c(nrow,ycol) return(z) } .spam.matmul <- function(x,y) { # --- CHANGED --- # Refactored. -> See .spam.matmul.vector if (is.matrix(y)) y <- as.spam(y) if (is.matrix(x)) x <- as.spam(x) #matrix multiply two sparse spam matrices xn <- x@dimension[1] xm <- x@dimension[2] yl <- y@dimension[2] if(xm != y@dimension[1]) stop("matrices not conformable for multiplication") # EXPLICIT-STORAGE-FORMAT SS <- .format.spam(x, y) if( getOption("spam.force64") || as.numeric(xn)*as.numeric(yl) > 2147483647) SS <- .format64() z <- .C64("amubdg", SIGNATURE = rep(SS$signature, 10), xn, xm, yl, x@colindices, x@rowpointers, y@colindices, y@rowpointers, unused2=vector_dc(SS$type, xn), nz = vector_dc(SS$type,1), unused=vector_dc(SS$type, yl), INTENT=c("r", "r", "r", "r", "r", "r", "r", "w", "w", "w"), NAOK = getOption("spam.NAOK"), PACKAGE = SS$package) nzmax <- z$nz z <- NULL # EXPLICIT-STORAGE-FORMAT # As we now know the number of entries, we can decide again if we need 64-bit SS <- .format.spam(x, y) if( getOption("spam.force64") || nzmax > 2147483647) SS <- .format64() z <- .C64("amub", SIGNATURE=c(SS$signature, SS$signature, SS$signature, "double", SS$signature, SS$signature, "double", SS$signature, SS$signature, "double", SS$signature, SS$signature, SS$signature, SS$signature, SS$signature), xn, yl, 1L, x@entries, x@colindices, x@rowpointers, y@entries, y@colindices, y@rowpointers, entries = vector_dc("double",nzmax), colindices = vector_dc(SS$type,nzmax), rowpointers = vector_dc(SS$type,xn+1), nzmax, # TODO: Check if we can get rid of this argument and allocate memory in Fortran: vector_dc(SS$type, yl), ierr = vector_dc(SS$type, 1), INTENT=c("r", "r", "r", "r", "r", "r", "r", "r", "r", "w", "w", "w", "r", "r", "w"), NAOK = getOption("spam.NAOK"), PACKAGE = SS$package) nz <- z$rowpointers[xn+1]-1 if(z$ierr != 0) stop("insufficient space for sparse matrix multiplication") if(nz==0){#trap zero matrix return(.newSpam( dimension=c(xn,yl) )) } entries <- z$entries colindices <- z$colindices rowpointers <- z$rowpointers z <- NULL length(entries) <- nz length(colindices) <- nz z <- .C64("sortrows", SIGNATURE=c(SS$signature, "double", SS$signature, SS$signature), xn, entries=entries, colindices=colindices, rowpointers=rowpointers, INTENT=c("r", "rw", "rw", "rw"), NAOK = getOption("spam.NAOK"), PACKAGE = SS$package) return(.newSpam( entries=z$entries, colindices=z$colindices, rowpointers=z$rowpointers, dimension=c(xn,yl) )) } .spam.matmul.vector <- function(x,y) { # --- CHANGED --- # Refactored the function .spam.matmul into the functions # .spam.matmul and .spam.matmul.vector # if we have x*Y, we calculate t(t(Y)*x) # Use "is.spam(y)" instead of "is.vector(x)" because the later might be # misleading in case that x has any attributes attached. if(is.spam(y)) { A <- t(y) b <- x } else { A <- x b <- y } SS <- .format.spam(A) nrow <- A@dimension[1] ncol <- A@dimension[2] if(length(b) != ncol) stop("not conformable for multiplication") z <- .C64("amux", NAOK = getOption("spam.NAOK"), SIGNATURE=c(SS$signature, "double", "double", "double", SS$signature, SS$signature), nrow, b, y = vector_dc("double",nrow), A@entries, A@colindices, A@rowpointers, INTENT=c("r", "r", "w", "r", "r", "r"), PACKAGE = SS$package)$y if(is.spam(y)) dim(z) <- c(1,nrow) else dim(z) <- c(nrow,1) return(z) } setMethod("%*%",signature(x="spam",y="spam"), .spam.matmul) setMethod("%*%",signature(x="spam",y="matrix"), .spam.matmul.mat) setMethod("%*%",signature(x="spam",y="numeric"), .spam.matmul.vector) setMethod("%*%",signature(x="matrix",y="spam"), .spam.matmul) setMethod("%*%",signature(x="numeric",y="spam"), .spam.matmul.vector) upper.tri.spam <- function(x,diag=FALSE) { dimx <- x@dimension nrow <- dimx[1] SS <- .format.spam(x) z <- .C64("getu", SIGNATURE = c(SS$signature, "double", SS$signature, SS$signature, "double", SS$signature, SS$signature), nrow, x@entries, x@colindices, x@rowpointers, entries = x@entries, colindices = x@colindices, rowpointers = x@rowpointers, INTENT = c("r", "r", "r", "r", "w", "w", "w"), NAOK = getOption("spam.NAOK"), PACKAGE = SS$package ) nz <- z$rowpointers[dimx[1]+1]-1 if (!diag) { z <- .C64("getdia", SIGNATURE = c(SS$signature, SS$signature, SS$signature, "double", SS$signature, SS$signature, SS$signature, "double", SS$signature, SS$signature), n = nrow, m = nrow, job = 1, entries = z$entries[1:nz], colindices = z$colindices[1:nz], rowpointers = z$rowpointers, len = nrow, diag = vector_dc("double", nrow), idiag = vector_dc(SS$type, nrow), ioff = 0, INTENT = c("r", "r", "r", "rw", "rw", "rw", "w", "w", "w", "r"), NAOK = getOption("spam.NAOK"), PACKAGE = SS$package ) nz <- z$rowpointers[nrow+1]-1 } if(getOption("spam.trivalues")){ return(.newSpam( entries = z$entries[1:nz], colindices = z$colindices[1:nz], rowpointers = z$rowpointers, dimension = dimx, )) }else{ return(.newSpam( entries = rep_len64(1,nz), colindices=z$colindices[1:nz], rowpointers=z$rowpointers, dimension=dimx )) } } lower.tri.spam <- function(x,diag=FALSE) { dimx <- x@dimension nrow <- dimx[1] SS <- .format.spam(x) z <- .C64("getl", SIGNATURE = c(SS$signature, "double", SS$signature, SS$signature, "double", SS$signature, SS$signature), nrow, x@entries, x@colindices, x@rowpointers, entries = x@entries, colindices = x@colindices, rowpointers = x@rowpointers, INTENT = c("r", "r", "r", "r", "w", "w", "w"), NAOK = getOption("spam.NAOK"), PACKAGE = SS$package ) nz <- z$rowpointers[nrow+1]-1 if (!diag) { z <- .C64("getdia", SIGNATURE = c(SS$signature, SS$signature, SS$signature, "double", SS$signature, SS$signature, SS$signature, "double", SS$signature, SS$signature), n = nrow, m = nrow, job = 1, entries = z$entries[1:nz], colindices = z$colindices[1:nz], rowpointers = z$rowpointers, len = nrow, diag = vector_dc("double", nrow), idiag = vector_dc(SS$type, nrow), ioff = 0, INTENT = c("r", "r", "r", "rw", "rw", "rw", "w", "w", "w", "r"), NAOK = getOption("spam.NAOK"), PACKAGE = SS$package ) nz <- z$rowpointers[nrow+1]-1 } if(getOption("spam.trivalues")){ return(.newSpam( entries = z$entries[1:nz], colindices = z$colindices[1:nz], rowpointers = z$rowpointers, dimension = dimx, )) }else{ return(.newSpam( entries = rep_len64(1,nz), colindices=z$colindices[1:nz], rowpointers=z$rowpointers, dimension=dimx )) } } setGeneric("upper.tri") setMethod("upper.tri","spam",upper.tri.spam) setGeneric("lower.tri") setMethod("lower.tri","spam",lower.tri.spam) # fields uses the construct of vector representation for a diagonal matrix. # Create a special matrix multiply for diagonal matrices. # Diagonal matrix assumed to be just a vector. # NOTE: this is not a symmetric operation: # when a left vector is given it is a diagonal matrix # when a right vector is given it is a vector. # .spam.diagmulmat <- function(x,y){ nrow <- y@dimension[1] if(length(x) != nrow) stop("not conformable for multiplication") SS <- .format.spam(y) z <- .C64("diagmua", SIGNATURE = c(SS$signature, "double", SS$signature, "double"), nrow, entries = y@entries, y@rowpointers, as.vector(x,"double"), INTENT = c("r", "rw", "r", "r"), NAOK=getOption("spam.NAOK"), PACKAGE = SS$package)$entries y@entries <- z return(y) } .spam.diagaddmat <- function(x,y){ ## subroutine diagaddmat (nrow, n, a, ja, ia, diag, iw) nrow <- y@dimension[1] minrc <- min( y@dimension) if(length(x) != minrc) stop("not conformable for addition") SS <- .format.spam(y) z <- .C64("diagaddmat", SIGNATURE = c( SS$signature, SS$signature, "double", SS$signature, SS$signature, "double", SS$signature), nrow = nrow, n = minrc, a = c(y@entries, rep_len64(0,minrc)), ja = c(y@colindices, rep_len64(0,minrc)), ia = y@rowpointers, diag = x, iw = vector_dc(SS$type, nrow), INTENT = c("r", "r", "rw", "rw", "rw", "r", "rw"), NAOK = getOption("spam.NAOK"), PACKAGE = SS$package ) nz <- z$ia[nrow+1]-1 return(.newSpam( entries = z$a[1:nz], colindices = z$ja[1:nz], rowpointers = z$ia, dimension = y@dimension)) } setGeneric("%d*%",function(x,y,...)standardGeneric("%d*%")) setMethod("%d*%",signature(x="matrix",y="ANY"), function(x,y){x%*%y} ) setMethod("%d*%",signature(x="numeric",y="matrix"), function(x,y){x*y} ) setMethod("%d*%",signature(x="numeric",y="numeric"), function(x,y){cbind(x*y)} ) setMethod("%d*%",signature(x="spam",y="spam"), .spam.matmul ) setMethod("%d*%",signature(x="spam",y="ANY"), .spam.matmul ) setMethod("%d*%",signature(x="numeric",y="spam"), .spam.diagmulmat ) setGeneric("%d+%",function(x,y,...)standardGeneric("%d+%")) setMethod("%d+%",signature(x="matrix",y="ANY"), function(x,y){ x+y } ) setMethod("%d+%",signature(x="numeric",y="matrix"), function(x,y){ diag(x)+y} ) setMethod("%d+%",signature(x="numeric",y="numeric"), function(x,y){ diag(x)+y} ) setMethod("%d+%",signature(x="spam",y="spam"), function(x,y){ x+y}) setMethod("%d+%",signature(x="spam",y="ANY"), function(x,y){ x+y}) setMethod("%d+%",signature(x="numeric",y="spam"), .spam.diagaddmat ) all.equal.spam <- function (target, current, tolerance = .Machine$double.eps^0.5, scale = NULL, check.attributes = FALSE,...) { if (check.attributes) warning("attributes are not supported for 'spam' objects. Ignoring 'check.attributes' argument") if (!is.spam(target)) stop("'target' should be of class 'spam'") if (!is.spam(current)) { return(paste("target is spam, current is ", data.class(current), sep = "")) } msg <- NULL lt <- length(target) lc <- length(current) if (lt != lc) { return(paste("Lengths (", lt, ", ", lc, ") differ", sep = "")) } dt <- target@dimension dc <- current@dimension if ( !all( dt == dc )) return(paste("Dimensions ([",dt[1],",",dt[2],"], [", dc[1],",",dc[2], "]) differ", sep = "")) # --- CHANGED --- # Add suppressWarnings tmp <- suppressWarnings(sum(target@colindices != current@colindices)) if ( tmp>0) msg <- c(msg,paste("Column-sparsity structure differ (at least", tmp,"instance(s))")) tmp <- suppressWarnings(sum(target@rowpointers != current@rowpointers)) if ( tmp>0) msg <- c(msg,paste("Row-sparsity structure differ (at least", tmp,"instance(s))")) xy <- suppressWarnings(mean(abs(target@entries - current@entries))) what <- if (is.null(scale)) { xn <- mean(abs(target@entries)) if (is.finite(xn) && xn > tolerance) { xy <- xy/xn "relative" } else "absolute" } else { xy <- xy/scale "scaled" } if (is.na(xy) || xy > tolerance) msg <- c(msg,paste("Mean", what, "difference:", format(xy))) if (is.null(msg)) TRUE else msg } isSymmetric.spam <- function(object, tol = 100 * .Machine$double.eps, ...) { # very similar to is.Symmetric.matrix test <- all.equal.spam(object, t.spam(object), tolerance = tol, ...) # Possibility that structure is different but not contents if (!isTRUE(test)) { object <- as.spam.spam(object) test <- all.equal.spam(object, t.spam(object), tolerance = tol, ...) } isTRUE(test) } setMethod("all.equal",signature(target="spam",current="spam"), all.equal.spam ) setMethod("all.equal",signature(target="matrix",current="spam"), function (target, current, tolerance = .Machine$double.eps^0.5, scale = NULL, check.attributes = FALSE,eps = getOption("spam.eps"),...) { if (check.attributes) warning("attributes are not supported for 'spam' objects. Ignoring 'check.attributes' argument") msg <- NULL dimx <- dim(target) nz <- length(target) ## z <- .Fortran("spamdnscsr", nrow = as.integer(dimx[1]), ncol = as.integer(dimx[2]), ## x = as.double(target), as.integer(dimx[1]), entries = vector("double", ## nz), colindices = vector("integer", nz), rowpointers = vector("integer", ## dimx[1] + 1), eps = as.double(eps), ## NAOK = getOption("spam.NAOK"), PACKAGE = "spam") if( getOption("spam.force64") || .format.spam(current)$package != "spam" || prod(dimx) > 2147483647) SS <- .format64() else SS <- .format32 z <- .C64("spamdnscsr", SIGNATURE = c(SS$signature, SS$signature, "double", SS$signature, "double", SS$signature, SS$signature, "double"), nrow = dimx[1], ncol = dimx[2], x = target, dimx[1], entries = vector_dc( "double", nz), colindices = vector_dc( SS$type, nz), rowpointers = vector_dc( SS$type, dimx[1] + 1), eps = eps, INTENT = c("r", "r", "r", "r", "w", "w", "w", "r"), NAOK = getOption("spam.NAOK"), PACKAGE = SS$package) lt <- z$rowpointers[dimx[1] + 1] - 1 lc <- length(current) if (lt != lc) { return(paste("Lengths (", lt, ", ", lc, ") differ", sep = "")) } dt <- dim(target) dc <- current@dimension if ( !all( dt == dc )) return(paste("Dimensions ([",dt[1],",",dt[2],"], [", dc[1],",",dc[2], "]) differ", sep = "")) tmp <- sum(z$colindices[1:lt] != current@colindices) if ( tmp>0) msg <- c(msg,paste("Column-sparsity structure differ (at least", tmp,"instance(s))")) tmp <- sum(z$rowpointers != current@rowpointers) if ( tmp>0) msg <- c(msg,paste("Row-sparsity structure differ (at least", tmp,"instance(s))")) xy <- mean(abs(z$entries[1:lt] - current@entries)) what <- if (is.null(scale)) { xn <- mean(abs(z$entries)) if (is.finite(xn) && xn > tolerance) { xy <- xy/xn "relative" } else "absolute" } else { xy <- xy/scale "scaled" } if (is.na(xy) || xy > tolerance) msg <- c(msg,paste("Mean", what, "difference:", format(xy))) if (is.null(msg)) TRUE else msg } ) setMethod("all.equal",signature(target="spam",current="matrix"), function(target, current, ...) { all.equal(current, target, ...) }) setMethod("isSymmetric","spam", isSymmetric.spam) spam/R/subset.R0000644000176200001440000004727113536451710013063 0ustar liggesusers# HEADER #################################################### # This is file spam/R/subset.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ # SUBSETTING ########################################################################################## # notice the drop catch... # I don"t know the best and official way, but it works as it is here... setMethod("[", signature(x = "spam", i = "missing", j = "missing", drop = "ANY"), function (x, i, j,..., drop) { # cat("missmiss") x}) setMethod("[",signature(x="spam",i="vector",j="missing", drop = "logical"), function (x, i, j,..., drop) { #cat(" log call was", deparse(match.call()), "\n") if (nargs()==3) { subset_rows.spam(x, i,drop=drop) } else { subset_rows.spam(x, i,,drop=drop) }} ) setMethod("[",signature(x="spam",i="vector",j="missing", drop = "missing"), function (x, i, j,..., drop) { #cat(" mis call was", deparse(match.call()), "\n") if (nargs()==2) { subset_rows.spam(x, i) } else { subset_rows.spam(x, i,) }}) setMethod("[",signature(x="spam",i="vector",j="vector", drop = "ANY"), function (x, i, j,..., drop) { # cat("vecvec") subset.spam(x,rw=i,cl=j,drop=drop)} ) setMethod("[",signature(x="spam",i="missing",j="vector", drop = "ANY"), function (x, i, j,...,drop) { # cat("missvec") subset.spam(x,rw=1:x@dimension[1],cl=j,drop=drop)} ) setMethod("[",signature(x="spam",i="matrix",j="missing", drop = "missing"), function (x, i, j,..., drop) {subset.spam(x,rw=i) }) setMethod("[",signature(x="spam",i="matrix",j="missing", drop = "logical"), function (x, i, j,..., drop) {subset.spam(x,rw=i,drop=drop) }) setMethod("[",signature(x="spam",i="matrix",j="matrix", drop = "ANY"), function (x, i, j,..., drop) {subset.spam(x,rw=cbind(c(i),c(j)),drop=drop) }) setMethod("[",signature(x="spam",i="spam",j="missing", drop = "ANY"), function (x, i, j,..., drop=getOption("spam.drop")) { # drop is not implemented yet ## print("subset spam spam") dimx <- x@dimension nrow <- dimx[1] ncol <- dimx[2] if ( i@dimension[1]>nrow | i@dimension[2]>ncol) stop("subscript out of bounds",call.=FALSE) ## z <- .Fortran("amask", ## nrow=as.integer(nrow), ## ncol=as.integer(ncol), ## a=as.double(x@entries), ## colindices=as.integer(x@colindices), ## rowpointers=as.integer(x@rowpointers), ## jmask=as.integer(i@colindices), ## imask=as.integer(c(i@rowpointers,rep(i@rowpointers[length(i@rowpointers)],nrow+1-length(i@rowpointers)))), ## c=as.double(x@entries), ## jc=as.integer(x@colindices), ## ic=as.integer(x@rowpointers), ## iw=logical(ncol), ## nzmax=as.integer(length(i@colindices)), ## ierr=0L, ## NAOK=getOption("spam.NAOK"),PACKAGE="spam") # some copying is required!!!! if(.format.spam(x)$package == "spam64") SS <- .format64() else SS <- .format32 z <- .C64("amask", ## subroutine amask (nrow,ncol,a,ja,ia,jmask,imask, ## * c,jc,ic,nzmax,ierr) SIGNATURE = c( SS$signature, SS$signature, "double", SS$signature, SS$signature, SS$signature, SS$signature, "double", SS$signature, SS$signature, SS$signature, SS$signature), nrow = nrow, ncol = ncol, a = x@entries, colindices = x@colindices, rowpointers = x@rowpointers, jmask = i@colindices, imask = c(i@rowpointers, rep_len64(i@rowpointers[length(i@rowpointers)], nrow+1-length(i@rowpointers))), c = x@entries, jc = x@colindices, ic = x@rowpointers, nzmax = length( i@colindices), ierr = 0, INTENT = c( "rw", "rw", "r", "r", "r", "r", "r", "w", "w", "w", "r", "w" ), NAOK = getOption("spam.NAOK"), PACKAGE = SS$package) # some copying is required!!!! nz <- z$ic[nrow+1]-1 if (nz==0) { ## print("nz = 0") return( numeric(0)) } if (drop) { ## print("drop") ic <- unique( z$ic[1:(z$nrow+1)]) dimx <- as.integer(c(length(ic)-1,max(z$jc[1:nz]))) } else { ## print("notdrop") ic <-z$ic[1:(z$nrow+1)] } ## return(new("spam",entries=z$c[1:nz],colindices=z$jc[1:nz],rowpointers=ic, ## dimension=dimx)) return(.newSpam( entries = z$c[1:nz], colindices = z$jc[1:nz], rowpointers = ic, dimension = dimx)) } ) setMethod("[", signature(x = "spam", i = "ANY", j = "ANY", drop = "ANY"), function(x,i,j, drop) stop("Invalid or not-yet-implemented 'spam' subsetting")) # the proper S3 subsetting causes problems... # "[.spam" <- function (x, rw, cl,drop=getOption("spam.drop")) {subset.spam(x,rw=rw,cl=cl,drop) } "subset_rows.spam" <- function (x, i, ..., drop=getOption("spam.drop")) # approach: we extract rows (nargs=2) or elements (nargs=3) # i is a vector of integers or logical! # nargs idea from Matrix! { nA <- nargs()+missing(drop) # cat("subset_rows.spam call was", deparse(match.call())," ",nargs(), " " , nA, "\n") dimx <- x@dimension nrow <- dimx[1] ncol <- dimx[2] mini <- min(i, na.rm=TRUE) maxi <- max(i, na.rm=TRUE) if (mini<0 & maxi>0) stop("Negative and positive subscripts mixed") SS <- .format.spam(x) if(nA==3) { # extract elements if (is.logical(i)) { inefficiencywarning( "Logical subsetting may be inefficient, is this really what you want?", prod(dimx)) return(.C64("spamcsrdns", SIGNATURE = c(SS$signature, "double", SS$signature, SS$signature, "double"), nrow, entries = x@entries, colindices = x@colindices, rowpointers = x@rowpointers, res = vector_dc("double", prod(dimx)), # INTENT = c("r","r","r","r","w"), # not checked !!! NAOK=getOption("spam.NAOK"),PACKAGE = SS$package)$res[i]) } if (mini<0) { inefficiencywarning( "Negative subsetting may be inefficient, is this really what you want?", prod(dimx)) return(.C64("spamcsrdns", SIGNATURE = c(SS$signature, "double", SS$signature, SS$signature, "double"), nrow, entries=x@entries, colindices=x@colindices, rowpointers=x@rowpointers, res=vector_dc("double",prod(dimx)), # INTENT = c("r","r","r","r","w"), # not checked !!! NAOK=getOption("spam.NAOK"),PACKAGE = SS$package)$res[i]) } # eliminate zeros, # force too large to NA, keep NAs i <- i[i>0] ind <- !(is.na(i)|(i> (nrow*ncol))) ii <- i[ind]-1 i <- ii %% nrow+1 j <- ii %/% nrow+1 nir <- length(i) z <- vector("double",length(ind)) z[!ind] <- NA z[ind] <- .C64("getallelem", SIGNATURE = c(SS$signature, SS$signature, SS$signature, "double", SS$signature, SS$signature, SS$signature, "double"), nir, i, j, x@entries, x@colindices, x@rowpointers, iadd = vector_dc(SS$type,nir), allelem = vector_dc("double",nir), ## INTENT = c("r","r","r", ## "r","r","r", ## "w","w"), # not checked !!! NAOK=getOption("spam.NAOK"),PACKAGE=SS$package)$allelem # getallelem(nir,ir,jr,a,ja,ia,alliadd,allelem) return(z) } if(nA==4) { if (is.logical(i)) { # logical if( length(i) > nrow) stop("(subscript) logical subscript too long",call.=FALSE) i <- seq_len( nrow)[i] } else { i <- i[i!=0] # eliminate zero lines if (maxi>x@dimension[1]) stop("subscript out of bounds",call.=FALSE) # negative values: if ( maxi <= 0 ) i <- seq_len( nrow)[i] } ni <- length(i) if (ni==0) return(numeric(0)) # zero elements... if (any(is.na(i))) { stop("'NA's in subsetting vector have been eliminated.") # i <- i[!is.na(i)] } nz <- (sum(x@rowpointers[i+1]-x@rowpointers[i])) if (nz==0) {#trap zero matrix if (drop==TRUE && (ni==1 || ncol==1)) return( vector("double",max(ni,ncol))) else return(new("spam",rowpointers=c(1L,rep.int(2L,ni )), dimension = c(ni,ncol))) } else { # subroutine getlines(a,ja,ia, ni, i, bnz, b,jb,ib) z <- .C64("getlines", SIGNATURE = c("double", SS$signature, SS$signature, SS$signature, SS$signature, SS$signature, "double", SS$signature, SS$signature), x@entries, x@colindices, x@rowpointers, ni, i, newnz=nz, entries=vector_dc("double", nz), colindices=vector_dc(SS$type, nz), rowpointers=vector_dc(SS$typ, ni+1), NAOK=getOption("spam.NAOK"), PACKAGE=SS$package) # print(c(nz,z$newni,is.integer(nz), is.integer(z$newni),z$newni!=ni)) if(z$newnz!=nz) stop(gettextf("Subsetting error, please report %d, %d",z$newnz,nz)) } # print(c(drop,ni,ncol,(drop==TRUE && (ni==1 || ncol==1) ))) if (drop==TRUE && (ni==1 || ncol==1)) # this is essentially a c() call return(.C64("spamcsrdns", SIGNATURE = c(SS$signature, "double", SS$signature, SS$signature, "double"), nrow=ni, entries=z$entries, colindices=z$colindices, rowpointers=z$rowpointers, res=vector_dc("double",prod(ni,ncol)), NAOK=getOption("spam.NAOK"), PACKAGE = SS$package)$res) else { return(.newSpam( entries=z$entries, colindices=z$colindices, rowpointers=z$rowpointers, dimension=c(ni,ncol), force64=getOption("spam.force64"))) } } stop("incorrect number of dimensions") } ## subset_rows.spam <- function(x, i, drop){ ## dimx <- x@dimension ## nrow <- dimx[1] ## ncol <- dimx[2] ## ni <- length(i) ## if (ni==0) return(numeric(0)) # zero elements... ## if (any(is.na(i))) { ## stop(""NA"s in subsetting vector not allowed.") ## } ## nz <- sum(x@rowpointers[i+1]-x@rowpointers[i]) ## if (nz==0) { #trap zero matrix ## if (drop==TRUE && (ni==1 || ncol==1)) ## return( vector("double",max(ni,ncol))) ## else ## return(new("spam",rowpointers=c(1,rep(2L,ni )), ## dimension = c(ni,ncol))) ## } ## SS <- .format.spam(x) ## z <- .C64("getlines", ## SIGNATURE=c("double", SS$signature, SS$signature, SS$signature, ## SS$signature, SS$signature, "double", SS$signature, ## SS$signature), ## x@entries, ## x@colindices, ## x@rowpointers, ## ni, ## i, #int64 ## newnz=nz, ## entries=vector_dc("double",nz), ## colindices=vector_dc(SS$type,nz), ## rowpointers=vector_dc(SS$type,ni+1), ## INTENT=c("r", "r", "r", "r", ## "r", "rw", "w", "w", ## "w"), ## NAOK = getOption("spam.NAOK"), ## PACKAGE=SS$package) ## if(z$newnz!=nz) stop(gettextf("Subsetting error, please report %d, %d",z$newnz,nz)) ## # --- CHANGED --- ## newx <- .newSpam(entries=z$entries, ## colindices=z$colindices, ## rowpointers=z$rowpointers, ## dimension=c(ni,ncol)) ## if (drop==TRUE && (ni==1 || ncol==1)) { ## x <- newx ## SS <- .format.spam(x) ## dimx <- x@dimension ## result <- .C64("spamcsrdns", ## SIGNATURE=c(SS$signature, "double", SS$signature, SS$signature, "double"), ## nrow=dimx[1], ## entries=x@entries, ## colindices=x@colindices, ## rowpointers=x@rowpointers, ## res=vector("double",prod(dimx)), # TODO: Expects zeros, because it ## # only overwrites the non-zero elements! (use RW) ## INTENT=c("r", "r", "r", "r", "rw"), ## NAOK = getOption("spam.NAOK"), ## PACKAGE = SS$package ## ) ## return(result$res) ## }else { ## return(newx) ## } ## stop("incorrect number of dimensions") ## } "subset.spam" <- function (x,rw,cl,...,drop=getOption("spam.drop")) { # we separate into cases where: # (A) rw matrix: # 1: logical: transformation to spam and extract structure # 2: two column matrix: extract (i,j) as given by the lines. # 3: all else extract x[ c( rw)] # (B) rw and cl one element: ((i,j) # (C) rw and cl vectors: (i1:i2,j1:j2) [i1<=i2, j1<=j2] # (c(i1,...,ii),c(j1,...,jj)) [arbitrary block] # if (missing(drop)) drop <- getOption("spam.drop") # print(drop) dimx <- x@dimension nrow <- dimx[1] ncol <- dimx[2] SS <- .format.spam(x) if (is.matrix(rw)) { if (is.logical(rw)) { return( x[as.spam.matrix(rw)] ) } if (dim(rw)[2]==2) { ir <- rw[,1] jr <- rw[,2] } else { ir <- c(rw-1) %% nrow + 1 jr <- c(rw-1) %/% nrow + 1 } if ( (min(ir)<1)|(max(ir)>x@dimension[1])|(min(jr)<1)|(max(jr)>x@dimension[2])) stop("subscript out of bounds",call.=FALSE) nir <- length(ir) return(.C64("getallelem", SIGNATURE = c(SS$signature, SS$signature, SS$signature, "double", SS$signature, SS$signature, SS$signature,"double"), nir, ir, jr, x@entries, x@colindices, x@rowpointers, vector_dc(SS$type, nir), allelem=vector_dc("double",nir), NAOK=getOption("spam.NAOK"), PACKAGE=SS$package)$allelem) } # negative values: if ( max(rw)<0 ) rw <- seq_len( nrow)[rw] if ( max(cl)<0 ) cl <- seq_len( ncol)[cl] # logical if (is.logical(rw)) rw <- seq_len( nrow)[rw] if (is.logical(cl)) cl <- seq_len( ncol)[cl] if (length(cl)==0) stop("You should subset at least one element for the columns",call.=FALSE) if (length(rw)==0) stop("You should subset at least one element for the rows",call.=FALSE) if ( (min(rw)<1)|(max(rw)>x@dimension[1])|(min(cl)<1)|(max(cl)>x@dimension[2])) stop("subscript out of bounds",call.=FALSE) if (length(rw)==1 & length(cl)==1){ # function to extract only one element return(.C64("getelem", SIGNATURE = c(SS$signature, SS$signature, "double", SS$signature, SS$signature, SS$signature, "double"), rw, cl, x@entries, x@colindices, x@rowpointers, iadd=vector(SS$type, 1), elem=vector("double", 1), PACKAGE=SS$package)$elem) } if (is.vector(rw) && is.vector(cl)) { nrw <- length(rw) # length returns an integer, so is a product therof ncl <- length(cl) diffrw <- diff(rw) diffcl <- diff(cl) nz <- ( min( (1+sum(diff(sort(rw))==0))*(1+sum(diff(sort(cl))==0))* length(x@entries), prod(nrw,ncl))) # very pessimistic if (all(diffrw==1) & all(diffcl==1)) { z <- .C64("submat", SIGNATURE = c(SS$signature, SS$signature, SS$signature, SS$signature, SS$signature, "double", SS$signature, SS$signature, SS$signature, SS$signature, "double", SS$signature, SS$signature), job=1, # need values as well i1=rw[1], i2=rw[nrw], j1=cl[1], j2=cl[ncl], x@entries, x@colindices, x@rowpointers, nr=0, nc=0, entries=vector_dc("double",nz), colindices=vector_dc(SS$type,nz), rowpointers=vector_dc(SS$type,nrw+1), NAOK=getOption("spam.NAOK"),PACKAGE = SS$package) nz <- z$rowpointers[z$nr+1]-1 } else { z <- .C64("getblock", SIGNATURE = c("double", SS$signature, SS$signature, SS$signature, SS$signature, SS$signature, SS$signature, SS$signature, "double", SS$signature, SS$signature), x@entries, x@colindices, x@rowpointers, nr=nrw, rw, nc=ncl, cl, nz=nz, entries=vector("double",nz), colindices=vector(SS$type,nz),rowpointers=vector(SS$type,nrw+1), NAOK=getOption("spam.NAOK"), PACKAGE = SS$package) nz <- z$nz } if (nz==0) {#trap zero matrix if (drop==TRUE && (z$nr==1 || z$nc==1)) return( vector("double",max(z$nr,z$nc))) else return(new("spam",rowpointers=c(1L,rep.int(2L,z$nr )), dimension = c(z$nr,z$nc))) } if (drop==TRUE && (z$nr==1 || z$nc==1)) # this is essentially a c() call return(.C64("spamcsrdns", SIGNATURE = c(SS$signature, "double", SS$signature, SS$signature, "double"), nrow=z$nr, entries=z$entries[1:nz], colindices=z$colindices[1:nz], rowpointers=z$rowpointers[1:(z$nr+1)], res=vector_dc("double", prod(z$nr,z$nc)), NAOK=getOption("spam.NAOK"), PACKAGE = SS$package)$res) else { return(.newSpam( entries=z$entries[1:nz], colindices=z$colindices[1:nz], rowpointers=z$rowpointers[1:(z$nr+1)], dimension=c(z$nr,z$nc), force64=getOption("spam.force64"))) } } stop("invalid or not-yet-implemented 'spam' subsetting") } #subset.rows.spam <- function(x, i, ..., drop=getOption("spam.drop")) { subset.rows.spam <- function(...) { .Defunct('spam:::subset_rows.spam', package = 'spam', msg = "'subset.rows.spam' is defunct. Use 'spam:::subset_rows.spam' instead.\n") } spam/R/precmat.R0000644000176200001440000001315213536451707013206 0ustar liggesusers# HEADER #################################################### # This is file spam/R/precmat.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ # construct various precision matrices precmat <- function(n, season=12, m=n, A=NULL, order=1, ... , type="RW1") { avtype <- c("rw1", "rw2", "rwn", "season","igmrfreglat","igmrfirreglat","gmrfreglat") method <- pmatch(tolower(type), avtype) if (is.na(method)) stop("Precision matrix type not implemented yet. Please ask for.") switch(method, return(precmat.RW1(n)), return(precmat.RW2(n)), return(precmat.RWn(n, order)), return(precmat.season(n,season)), return(precmat.IGMRFreglat(n,m,...)), return(precmat.IGMRFirreglat(A,...)), return(precmat.GMRFreglat(n,m,...))) } precmat.IGMRFreglat <- function (n, m, order=1, anisotropy = 1) { if((n<2)|(m<2)) stop("n and m need to be >1") if(order==1) { if (anisotropy < 0 | anisotropy > 2) stop("anisotropy parameter needs to be in [0,2]") return(kronecker(precmat.RW1(m), diag.spam(2-anisotropy, n)) + kronecker(diag.spam(anisotropy, m), precmat.RW1(n))) } else if (order==2) { return(kronecker(precmat.RW2(m), diag.spam(n)) + kronecker(diag.spam( m), precmat.RW2(n))) } if( (order<1)|(order>=min(n,m))) stop("order needs to be between 1 and min(n,m)-1") Dn <- diff.spam(diag.spam(n), lag = 1, differences = order) Dm <- diff.spam(diag.spam(m), lag = 1, differences = order) return(kronecker(t(Dm)%*%Dm, diag.spam(n)) + kronecker(diag.spam( m), t(Dn)%*%Dn)) } precmat.IGMRFirreglat <- function(A, eps= getOption("spam.eps")) { if(!is.spam(A)) A <- as.spam(A, eps) A@entries <- rep.int(1, length(A)) test <- isSymmetric.spam(A, tol = eps * 100) if (!isTRUE(test)) stop("Input matrix not symmetric (up to 100*eps)",call. = FALSE) return(diag.spam( diff(A@rowpointers)) - A) } precmat.RW1 <- function(n) { if(n<2) stop("Dimension 'n' should be larger than two") Q <- spam(0,n,n) Q@entries <- rep(-1,n-1) Q@colindices <- as.integer( seq.int(2, to=n,by=1)) Q@rowpointers <- as.integer(c(seq.int(1,to=n,by=1),n)) return(Q + t(Q) + diag.spam(c(1, rep.int(2, n-2), 1))) } precmat.RW2<- function(n) { if(n<4) stop("Dimension 'n' should be larger than three") Q <- spam(0,n,n) Q@entries <- c(-2,1,rep(c(-4,1),n-3),-2) Q@colindices <- as.integer( c(rep(2:(n-1),each=2)+c(0,1),n)) Q@rowpointers <- as.integer(c(seq.int(1,to=2*(n-1),by=2),2*(n-1),2*(n-1))) return(Q + t(Q) + diag.spam(c(1,5, rep.int(6, n-4), 5,1))) } precmat.RWn <- function(n, order=3) { if( (order<1)|(order>=n)) stop("order needs to be between 1 and n-1") D <- diff.spam(diag.spam(n), lag=1, differences=order) return( t(D)%*%D ) } precmat.season <- function(n, season=12) { if(n<2*season) stop("Dimension 'n' should be larger than twice the season") Q <- spam(0,n,n) m <- season first <- rev( outer(1:(m-1), (m-1):1, "pmin")) mid <- rep.int((m-1):1, n-2*m+2) tmp <- outer(1:(m-1), 1:(m-1), "pmin") last <- rev( tmp[upper.tri(tmp)]) Q@entries <- c( first, mid, last) Q@rowpointers <- as.integer( c( seq.int( 1, length.out=n-m+1, by=m-1), # first and mid (n-m)*(m-1)+1+cumsum((m-1):1), (m-1)*(n-m/2)+1) # last ) Q@colindices <- as.integer( c( rep.int(1:(m-1), n-m+1) + rep.int(1:(n-m+1), rep.int(m-1, n-m+1)), # first and mid n-last+1 ) # last ) return(Q + t(Q) + diag.spam(c(1:m, rep.int(m, n-2*m), m:1))) } "precmat.GMRFreglat" <- function(n,m, par=.1, model = "m1p1", eps = getOption("spam.eps")){ if((n<2)|(m<2)) stop("n and m need to be >1") dims <- c(n,m) if (model=="m1p1"){ x <- numeric(dims[1]) x[1:2] <- c(1,-par[1]) y <- numeric(prod(dims)) y[dims[1]+1] <- -par[1] return( kronecker(diag.spam(dims[2]), toeplitz.spam(x,eps=eps))+toeplitz.spam(y,eps=eps)) } if (model=="m1p2"){ x <- numeric(dims[1]) x[1:2] <- c(1,-par[1]) y <- numeric(prod(dims)) y[dims[1]+1] <- -par[2] return( kronecker(diag.spam(dims[2]), toeplitz.spam(x,eps=eps))+toeplitz.spam(y,eps=eps)) } if (model=="m2p3"){ x <- numeric(dims[1]) x[1:2] <- c(1,-par[1]) y <- numeric(dims[1]) y[1:2] <- c(-par[2],-par[3]) z <- numeric(dims[2]) z[2] <- 1 p1 <- kronecker( diag.spam(dims[2]), toeplitz.spam(x,eps=eps)) p2 <- kronecker( toeplitz.spam(z,eps=eps), toeplitz.spam(y,eps=eps)) return( p1 + p2) } if (model=="m2p4"){ x <- numeric(dims[1]) x[1:2] <- c(1,-par[1]) y <- numeric(dims[1]) y[1:2] <- c(-par[2],-par[3]) w <- numeric(dims[1]) w[1:2] <- c(-par[2],-par[4]) z <- numeric(dims[2]) z[2] <- 1 p1 <- kronecker( diag.spam(dims[2]), toeplitz.spam(x,eps=eps)) p2 <- kronecker( toeplitz.spam(z,rep(0,dims[2]),eps=eps), toeplitz.spam(y,w,eps=eps)) p3 <- kronecker( toeplitz.spam(rep(0,dims[2]),z,eps=eps), toeplitz.spam(w,y,eps=eps)) return( p1 + p2 + p3) } stop("Model not implemented yet!") } spam/R/rowcolstats.R0000644000176200001440000000713213536451710014132 0ustar liggesusers# HEADER #################################################### # This is file spam/R/rowcolstats.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ rowSums.spam <- function(x,...) { ## print("1") if( getOption("spam.force64") ) SS <- .format64() else SS <- .format.spam(x) return(.C64("rowsums", SIGNATURE=c("double", SS$signature, SS$signature, "double"), x@entries, x@rowpointers, x@dimension[1], rs = vector_dc("double", x@dimension[1]), INTENT=c("r", "r", "r", "w"), NAOK = getOption("spam.NAOK"), PACKAGE = SS$package)$rs ) } colSums.spam <- function(x,...) { ## print("2") if( getOption("spam.force64") ) SS <- .format64() else SS <- .format.spam(x) return(.C64("colsums", SIGNATURE=c("double", SS$signature, SS$signature, SS$signature, "double"), x@entries, x@colindices, x@rowpointers, x@dimension[1], cs = vector_dc("double", x@dimension[2]), INTENT=c("r", "r", "r","r", "w"), NAOK = getOption("spam.NAOK"), PACKAGE = SS$package)$cs ) } rowMeans.spam <- function(x,...) { ## print("3") if( getOption("spam.force64") ) SS <- .format64() else SS <- .format.spam(x) return(.C64("rowmeans", SIGNATURE=c("double", SS$signature, SS$signature, SS$signature, SS$signature, "double"), x@entries, x@rowpointers, x@dimension[1], x@dimension[2], getOption("spam.structurebased"), rm = vector_dc("double", x@dimension[1]), INTENT=c("r", "r", "r", "r", "r", "rw"), NAOK = getOption("spam.NAOK"), PACKAGE = SS$package)$rm ) } colMeans.spam <- function(x,...) { ## print("4") if( getOption("spam.force64") ) SS <- .format64() else SS <- .format.spam(x) return(.C64("colmeans", SIGNATURE=c("double", SS$signature, SS$signature, SS$signature, SS$signature, SS$signature, "double", SS$signature), x@entries, x@colindices, x@rowpointers, x@dimension[1], x@dimension[2], getOption("spam.structurebased"), cm = vector_dc("double", x@dimension[2]), vector_dc(SS$type, x@dimension[2]), INTENT=c("r", "r", "r", "r", "r", "r", "rw", "rw"), NAOK = getOption("spam.NAOK"), PACKAGE = SS$package)$cm ) } setMethod("rowSums","spam",rowSums.spam) setMethod("colSums","spam",colSums.spam) setMethod("rowMeans","spam",rowMeans.spam) setMethod("colMeans","spam",colMeans.spam) spam/R/tcrossprod.R0000644000176200001440000000345113536451710013750 0ustar liggesusers# HEADER #################################################### # This is file spam/R/tcrossprod.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ crossprod.spam <- function(x, y=NULL) { dimx <- dim(x) if( is.null(y)) { if(!is.spam(x)) return(crossprod(x)) if(dimx[2]==1L) return(matrix( sum(x@entries^2))) return( t.spam(x) %*% x) } if( (!is.spam(x)) & (!is.spam(y))) return(crossprod(x,y)) return( t(x) %*% y) } tcrossprod.spam <- function(x, y=NULL) { dimx <- dim(x) if( is.null(y)) { if(!is.spam(x)) return(tcrossprod(x)) if(dimx[2]==1L) return(matrix( sum(x@entries^2))) return( x %*% t.spam(x)) } if( (!is.spam(x)) & (!is.spam(y))) return(tcrossprod(x,y)) return( x %*% t(y)) } setMethod("crossprod",signature(x="spam",y="missing"), crossprod.spam) setMethod("crossprod",signature(x="spam",y="spam"), crossprod.spam) setMethod("crossprod",signature(x="spam",y="ANY"), crossprod.spam) setMethod("crossprod",signature(x="ANY",y="spam"), crossprod.spam) setMethod("tcrossprod",signature(x="spam",y="missing"), tcrossprod.spam) setMethod("tcrossprod",signature(x="spam",y="spam"), tcrossprod.spam) setMethod("tcrossprod",signature(x="spam",y="ANY"), tcrossprod.spam) setMethod("tcrossprod",signature(x="ANY",y="spam"), tcrossprod.spam) spam/R/mle.R0000644000176200001440000001263713536451707012337 0ustar liggesusers# HEADER #################################################### # This is file spam/R/mle.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ neg2loglikelihood.spam <- function(y, X, distmat, Covariance, beta, theta, Rstruct = NULL,...) { Sigma <- do.call(Covariance,list(distmat,theta)) if (!is.spam(Sigma)){ warning("\"Covariance\" should return a spam object. Forced to spam.") Sigma <- as.spam(Sigma) } if (is(Rstruct, "spam.chol.NgPeyton")) cholS <- update.spam.chol.NgPeyton(Rstruct, Sigma, ...) else cholS <- chol.spam(Sigma, ...) n <- length(y) resid <- y-X%*%beta return( n * log(2*pi) + 2*c(determinant.spam.chol.NgPeyton(cholS)$modulus) + sum(resid * solve.spam( cholS, resid)) ) } neg2loglikelihood <- function(y, X, distmat, Covariance, beta, theta, ...) { Sigma <- do.call(Covariance,list(distmat,theta)) cholS <- chol(Sigma, ...) logdet <- sum(log(diag(cholS))) n <- length(y) resid <- y-X%*%beta return( n * log(2*pi) + 2*logdet + sum(resid * backsolve(cholS, forwardsolve(cholS, resid, transpose=TRUE, upper.tri=TRUE),n)) ) } mle.spam <- function(y, X, distmat, Covariance, beta0, theta0, thetalower, thetaupper, optim.control=NULL, Rstruct = NULL, hessian = FALSE,...) { if (!is(Rstruct, "spam.chol.NgPeyton")) { Sigma <- do.call(Covariance, list(distmat,c(thetaupper[1],theta0[-1]))) if (!is.spam(Sigma)) stop("\"Covariance\" should return a spam object.") Rstruct <- chol.spam(Sigma, ...) } p <- dim(X)[2] n <- length(y) neg2loglikelihood <- function(fulltheta,...) { Sigma <- do.call(Covariance,list(distmat,fulltheta[-(1:p)])) cholS <- update.spam.chol.NgPeyton(Rstruct, Sigma, ...) resid <- y-X%*%fulltheta[1:p] return( n * log(2*pi) + 2*c(determinant.spam.chol.NgPeyton(cholS)$modulus) + sum(resid * solve.spam( cholS, resid)) ) } return(optim(c(beta0,theta0),neg2loglikelihood, method = "L-BFGS-B",control = optim.control, lower=c(rep(-Inf,p),thetalower), upper=c(rep(Inf,p),thetaupper), hessian = hessian)) } mle <- function(y, X, distmat, Covariance, beta0, theta0, thetalower, thetaupper, optim.control=NULL, hessian = FALSE, ...) { p <- dim(X)[2] n <- length(y) neg2loglikelihood <- function(fulltheta,...) { Sigma <- do.call(Covariance,list(distmat,fulltheta[-(1:p)])) cholS <- chol(Sigma, ...) logdet <- sum(log(diag(cholS))) resid <- y-X%*%fulltheta[1:p] return( n * log(2*pi) + 2*logdet + sum(resid * backsolve(cholS, forwardsolve(cholS, resid, transpose=TRUE, upper.tri=TRUE),n)) ) } return(optim(c(beta0,theta0),neg2loglikelihood, method = "L-BFGS-B",control = optim.control, lower=c(rep(-Inf,p),thetalower), upper=c(rep(Inf,p),thetaupper), hessian = hessian)) } mle.nomean.spam <- function(y, distmat, Covariance, theta0, thetalower, thetaupper, optim.control = NULL, Rstruct = NULL, hessian = FALSE,...) { if (!is(Rstruct, "spam.chol.NgPeyton")) { Sigma <- do.call(Covariance, list(distmat,c(thetaupper[1],theta0[-1]))) if (!is.spam(Sigma)) stop("\"Covariance\" should return a spam object.") Rstruct <- chol.spam(Sigma, ...) } n <- length(y) neg2loglikelihood <- function(theta,...) { Sigma <- do.call(Covariance,list(distmat,theta)) cholS <- update.spam.chol.NgPeyton(Rstruct, Sigma, ...) return( n * log(2*pi) + 2*c(determinant.spam.chol.NgPeyton(cholS)$modulus) + sum(y * solve.spam( cholS, y)) ) } return(optim(theta0,neg2loglikelihood, method = "L-BFGS-B",control = optim.control, lower=thetalower, upper=thetaupper, hessian = hessian)) } mle.nomean <- function(y, distmat, Covariance, theta0, thetalower, thetaupper, optim.control=NULL, hessian = FALSE, ...) { n <- length(y) neg2loglikelihood <- function(theta,...) { Sigma <- do.call(Covariance,list(distmat,theta)) cholS <- chol(Sigma, ...) logdet <- sum(log(diag(cholS))) return( n * log(2*pi) + 2*logdet + sum(y * backsolve(cholS, forwardsolve(cholS, y, transpose=TRUE, upper.tri=TRUE),n)) ) } return(optim(theta0,neg2loglikelihood, method = "L-BFGS-B",control = optim.control, lower=thetalower, upper=thetaupper, hessian = hessian)) } spam/R/toepliz.R0000644000176200001440000001277713536451710013247 0ustar liggesusers# HEADER #################################################### # This is file spam/R/toepliz.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ ######################################################################## "circulant.spam" <- function(x, n=NULL, eps = getOption("spam.eps")) { if (!(is.vector(x)|is.list(x)) ) stop("'x' is not a vector or a list") force64 <- getOption("spam.force64") if( is.list(x)) { if (!identical(length(x),2L)) stop("Argument 'x' needs to be a list with two elements") if (is.null(n)) stop("'n' needs to be given") ind <- x[[1]] x <- x[[2]] sel <- (ind <= n)&(abs(x)>eps) ind <- ind[sel] x <- x[sel] }else{ n <- length(x) ind <- (1:n)[abs(x) > eps] x <- x[ind] } n <- as.integer(n) len <- as.integer(length( ind)[1]) # see ?length@value if(identical(len,0)) return(.newSpam( # rowpointers = c(1, rep_len64(2, n)), dimension = c(n, n), force64 = force64)) # subroutine circulant(nrow,len, x,j, a,ja,ia) nz <- n*len ## z <- .Fortran("circulant", ## as.integer(n), ## as.integer(len), ## as.double(x), ## as.integer(ind), ## entries= vector("double", nz), ## colindices = vector("integer", nz), ## rowpointers = vector("integer", n + 1), ## NAOK = getOption("spam.NAOK"), ## PACKAGE = "spam") if(force64 || nz > 2147483647 || n+1 > 2147483647) SS <- .format64() else SS <- .format32 z <- .C64("circulant", SIGNATURE = c(SS$signature, SS$signature, "double", SS$signature, "double", SS$signature, SS$signature), n, len, x, ind, entries = vector_dc( "double", nz), colindices = vector_dc( SS$type, nz), rowpointers = vector_dc( SS$type, n + 1), INTENT = c("r", "r", "r", "r", "rw", "rw", "rw" ), NAOK = getOption("spam.NAOK"), PACKAGE = SS$package) ## newx <- new("spam") ## slot(newx, "entries", check = FALSE) <- z$entries ## slot(newx, "colindices", check = FALSE) <- z$colindices ## slot(newx, "rowpointers", check = FALSE) <- z$rowpointers ## slot(newx, "dimension", check = FALSE) <- c(n, n) ## return(newx) return(.newSpam( entries = z$entries, colindices = z$colindices, rowpointers = z$rowpointers, dimension = c(n,n), force64 = force64 )) } toeplitz.spam <- function(x,y=NULL, eps = getOption("spam.eps")) { force64 <- getOption("spam.force64") if (!is.vector(x)) stop("'x' is not a vector") n <- length(x) if (!is.null(y)){ if (!identical(length(y),n)) stop("Length of 'y' and 'x' do not match") fullx <- c(rev(y[-1]),x) } else { fullx <- c(rev(x[-1]),x) } ind <- (1:(2*n-1))[abs(fullx) > eps] fullx <- fullx[ind] n <- as.integer(n) len <- as.integer(length( ind)[1]) # see ?length@value if(identical(len,0L)){ ## print("degenerate") return(.newSpam( # rowpointers = c(1, rep_len64(2, n)), dimension = c(n, n), force64 = force64)) ## return(new("spam", rowpointers = c(1L, rep.int(2L, n)), ## dimension = as.integer(c(n, n)))) } # subroutine toeplitz(nrow,len, x,j, a,ja,ia,kk) nz <- n*len ## z <- .Fortran("toeplitz", ## as.integer(n), ## as.integer(len), ## as.double(fullx), ## as.integer(ind), ## entries= vector("double", nz), ## colindices = vector("integer", nz), ## rowpointers = vector("integer", n + 1), ## nnz=as.integer(1), ## NAOK = getOption("spam.NAOK"), PACKAGE = "spam") if(force64 || n+1 > 2147483647 || nz > 2147483647 ) SS <- .format64() else SS <- .format32 z <- .C64("toeplitz", SIGNATURE = c(SS$signature, SS$signature, "double", SS$signature, "double", SS$signature, SS$signature, SS$signature), n, len, fullx, ind, entries = vector_dc("double", nz), colindices = vector_dc( SS$type, nz), rowpointers = vector_dc( SS$type, n + 1), nnz = 1, INTENT = c("r", "r", "r", "r", "w", "w", "w", "rw"), NAOK = getOption("spam.NAOK"), PACKAGE = SS$package) ## newx <- new("spam") ## slot(newx, "entries", check = FALSE) <- z$entries[1:z$nnz] ## slot(newx, "colindices", check = FALSE) <- z$colindices[1:z$nnz] ## slot(newx, "rowpointers", check = FALSE) <- z$rowpointers ## slot(newx, "dimension", check = FALSE) <- c(n, n) ## return(newx) return(.newSpam( entries = z$entries[1:z$nnz], colindices = z$colindices[1:z$nnz], rowpointers = z$rowpointers, dimension = c(n, n), force64 = force64)) } spam/R/spam_solve.R0000644000176200001440000012447113536451710013724 0ustar liggesusers# HEADER #################################################### # This is file spam/R/spam_solve.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ ######################################################################## ######################################################################## # # Contains routines linked to solving spd linear systems. Namely: # chol, solve, backsolve, forwardsolve # determinant (the later because it is based on chol) # # As well as associated S4 elements. # # The key element is a new class: "spam.chol.NgPeyton", the output # of 'chol' # ######################################################################## ######################################################################## setClass("spam.chol.NgPeyton", representation(entries="numeric", colindices="integer", colpointers="integer", rowpointers="integer", dimension="integer", pivot="integer", invpivot="integer", supernodes="integer", snmember="integer", memory="integer", nnzA="integer") ) # lindx= colindices # xlindx= colpointers # xlnz= rowpointers # snode=snmember # xsuper=supernodes # c(... nnztmp,cachesize)= memory #setClass("spam.chol.NgPeyton", # representation(nrow="integer",nnzlindx="integer", # nsuper="integer",lindx="integer",xlindx="integer",nnzl="integer", # lnz="numeric",xlnz="integer",invp="integer",perm="integer", # xsuper="integer"), # the prototype corresponds to the cholesky of '1' # prototype=prototype(nrow=as.integer(1),nnzlindx=as.integer(1), # nsuper=as.integer(1),lindx=as.integer(1),xlindx=as.integer(c(1,2)), # nnzl=as.integer(1),lnz=1.0,xlnz=as.integer(c(1,2)), # invp=as.integer(1),perm=as.integer(1),xsuper=as.integer(c(1,2)) # ) # ) ######################################################################## print.spam.chol.NgPeyton <- function(x,...) { nrow <- x@dimension[1] nnzR <- x@rowpointers[nrow+1]-1 cat("(Upper) Cholesky factor of dimension ", nrow, "x", nrow, " with ",nnzR," nonzero elements.", sep = "", fill=TRUE) cat(" (The object is supposed to be used with: 'as.spam', 'backsolve', 'forwardsolve', etc.)\n", fill=TRUE) cat("Class 'spam.chol.NgPeyton'\n") invisible(NULL) } setMethod("show","spam.chol.NgPeyton", function(object) { nrow <- object@dimension[1] nnzR <- object@rowpointers[nrow+1]-1 cat("(Upper) Cholesky factor of dimension ", nrow, "x", nrow, " with ",nnzR," (row-wise) nonzero elements.", sep = "", fill=TRUE) cat(" (The object is supposed to be used with: 'as.spam', 'backsolve', 'forwardsolve', etc.)\n", fill=TRUE) cat("Class 'spam.chol.NgPeyton'\n") invisible(NULL) }) "diag.of.spam.chol.NgPeyton" <- function(x, nrow, ncol) return( x@entries[x@rowpointers[-(x@dimension[1]+1)]]) setMethod("diag", "spam.chol.NgPeyton", diag.of.spam.chol.NgPeyton) #setMethod("diag<-", "spam.chol.NgPeyton", function(x,...) stop("operation not allowed on 'spam.chol.NgPeyton' object")) setMethod("print", "spam.chol.NgPeyton", print.spam.chol.NgPeyton) # setMethod("summary", "spam.chol.NgPeyton", summary.spam.chol.NgPeyton) # moved to new file setMethod("dim", "spam.chol.NgPeyton",function(x) x@dimension) setMethod("length", "spam.chol.NgPeyton",function(x) x@rowpointers[x@dimension[1]+1]-1) setMethod("length<-","spam.chol.NgPeyton",function(x,value) stop("operation not allowed on 'spam.chol.NgPeyton' object") ) setMethod("dim<-", "spam.chol.NgPeyton",function(x,value) stop("operation not allowed on 'spam.chol.NgPeyton' object") ) setMethod("c","spam.chol.NgPeyton", function(x,...){ nrow <- x@dimension[1] nnzR <- x@rowpointers[nrow+1]-1 ## newx <- new("spam") ## what is this doing here??? TODO nsuper <- as.integer( length(x@supernodes)-1) ## xcolindices <- .Fortran('calcja', ## as.integer(nrow), ## as.integer(nsuper), ## as.integer(x@supernodes), ## as.integer(x@colindices), ## as.integer(x@colpointers), ## as.integer(x@rowpointers), ## xja=vector("integer",nnzR), ## NAOK = getOption("spam.NAOK"), ## PACKAGE = "spam")$xja if( getOption("spam.force64") || .format.spam(x)$package != "spam") SS <- .format64() else SS <- .format32 xcolindices <- .C64('calcja', SIGNATURE = rep(SS$signature, 7), nrow, nsuper, x@supernodes, x@colindices, x@colpointers, x@rowpointers, xja = vector_dc( SS$type, nnzR), INTENT=c("r", "r", "r", "r", "r", "r", "w"), NAOK = getOption("spam.NAOK"), PACKAGE = SS$package)$xja cx <- .C64("spamcsrdns", SIGNATURE = c(SS$signature, "double" , SS$signature, SS$signature, "double"), nrow = nrow, entries = x@entries, colindices = xcolindices, rowpointers = x@rowpointers, res = vector_dc( "double", nrow*nrow), INTENT = c("r", "r", "r", "r", "w"), NAOK=getOption("spam.NAOK"), PACKAGE = SS$package)$res if (length( list(...)) < 1) return( cx) else c( cx,c(...)) }) as.spam.chol.NgPeyton <- function(x, eps = getOption("spam.eps")) { if( getOption("spam.force64") || .format.spam(x)$package != "spam") SS <- .format64() else SS <- .format32 if (eps<.Machine$double.eps) stop("'eps' should not be smaller than machine precision",call.=FALSE) nrow <- x@dimension[1] nnzR <- x@rowpointers[nrow+1]-1 nsuper <- length(x@supernodes)-1 colindices <- .C64('calcja', SIGNATURE=rep(SS$signature, 7), nrow, nsuper, x@supernodes, x@colindices, x@colpointers, x@rowpointers, xja=vector(SS$type, nnzR), #!1# INTENT=c("r", "r", "r", "r", "r", "r", "w"), NAOK = getOption("spam.NAOK"), PACKAGE = SS$package)$xja return(.newSpam( entries=x@entries, colindices=colindices, rowpointers=x@rowpointers, dimension=x@dimension )) } setMethod("as.spam","spam.chol.NgPeyton", as.spam.chol.NgPeyton) ##NB setGeneric("backsolve", def = function(r, x, ...) standardGeneric("backsolve"), # useAsDefault= function(r, x,...) base::backsolve(r, x, ...)) # We have some issues here... hence I postpone the proper implementation!!! # http://r.789695.n4.nabble.com/class-extension-and-documentation-tt4161373.html#none #"backsolve" <- function(r,x, ...) UseMethod("backsolve") #"backsolve.default" <- base::backsolve #setGeneric("backsolve") #setMethod("backsolve","matrix",base::backsolve) #"forwardsolve" <- function(l,x, ...) UseMethod("forwardsolve") #"forwardsolve.default" <- base::forwardsolve #setGeneric("forwardsolve") #setMethod("forwardsolve","matrix",base::forwardsolve) setGeneric("backsolve", def = function(r, x, ...) standardGeneric("backsolve"), useAsDefault= function(r, x, ...) base::backsolve(r, x, ...)) setGeneric("forwardsolve", def = function(l, x, ...) standardGeneric("forwardsolve"), useAsDefault= function(l, x, ...) base::forwardsolve(l, x, ...)) # adapted from methods #setGeneric("forwardsolve", function(l, x, k, upper.tri = FALSE, transpose = FALSE, ...) # standardGeneric("forwardsolve"), # useAsDefault = function(l, x, k = ncol(l), upper.tri = FALSE, transpose = FALSE, ...) # base::forwardsolve(l, x, k = k, upper.tri = upper.tri, transpose = transpose, ... ), # signature = c("l", "x"))#, where = where) ##### setGenericImplicit("forwardsolve")#, restore=FALSE) "ordering.default" <- function(x,inv=FALSE) stop('Operation not defined form this class') #ordering <- function(x,...) stop('Operation not defined form this class') #setGeneric("ordering") setGeneric("ordering",function(x,inv=FALSE)standardGeneric("ordering")) setMethod("ordering","spam.chol.NgPeyton",function(x,inv=FALSE) { if (inv) return(x@invpivot) else return(x@pivot) }) setMethod("ordering","matrix",function(x,inv=FALSE) { if (dim(x)[1]!=dim(x)[2]) stop("ordering is defined for square matrices only") if(inv)return(dim(x)[1]:1) else return(1:dim(x)[1]) }) setMethod("ordering","spam",function(x,inv=FALSE) { if (dim(x)[1]!=dim(x)[2]) stop("ordering is defined for square matrices only") if(inv)return(dim(x)[1]:1) else return(1:dim(x)[1]) }) update.spam.chol.NgPeyton <- function(object,x,...){ ## print("update.spam.chol.NgPeyton") nrow <- object@dimension[1] if (!is.spam(x)) stop("Covariance should be a 'spam' object.") if ((x@rowpointers[nrow+1]-1) != object@nnzA) stop("Updated covariance entries do not match length of original one.") ## u <- .Fortran("updatefactor", ## as.integer(nrow), ## as.integer(object@nnzA), ## d = as.double(x@entries), jd = as.integer(x@colindices), ## id = as.integer(x@rowpointers), ## as.integer(object@invpivot), as.integer(object@pivot), ## lindx=as.integer(object@colindices), xlindx=as.integer(object@colpointers), ## nsuper=as.integer( length(object@supernodes)-1), ## entries = vector("double",length(object@entries)), #lnz ## rowpointers = as.integer(object@rowpointers),#xlnz ## snode=as.integer(object@snmember), xsuper=as.integer(object@supernodes), ## cachesize=as.integer(object@memory[3]), ## ierr = 0L, ## NAOK = getOption("spam.NAOK"),PACKAGE="spam") if( getOption("spam.force64") || .format.spam(object)$package != "spam" || .format.spam(x)$package != "spam" ) SS <- .format64() else SS <- .format32 u <- .C64("updatefactor", ## subroutine updatefactor( m,nnzd, ## & d,jd,id, invp,perm, ## & lindx,xlindx, nsuper,lnz,xlnz, ## & snode, xsuper, ## & cachesize,ierr) SIGNATURE = c(SS$signature, SS$signature, "double", SS$signature, SS$signature, SS$signature, SS$signature, SS$signature, SS$signature, SS$signature, "double", SS$signature, SS$signature, SS$signature, SS$signature, SS$signature ), nrow, object@nnzA, d = x@entries, jd = x@colindices, id = x@rowpointers, object@invpivot, object@pivot, lindx = object@colindices, xlindx = object@colpointers, nsuper = length(object@supernodes)-1, entries = vector_dc( "double", length(object@entries)), #lnz rowpointers = object@rowpointers,#xlnz snode = object@snmember, xsuper = object@supernodes, cachesize = object@memory[3], ierr = 0, ## INTENT = c("r", "r", ## "r", "r", "r", ## "r", "r", "r", "r", "r", ## "rw", "rw", "r", "r", "rw", "rw"), NAOK = getOption("spam.NAOK"), PACKAGE = SS$package) if(u$ierr>1) stop("Internal error in 'update.spam.chol.NgPeyton' code ", u$ierr,call.=FALSE) if(u$ierr == 1) { if (getOption("spam.cholupdatesingular") == "null") return(NULL) else if (getOption("spam.cholupdatesingular") == "error") stop("Singularity problem when updating a Cholesky Factor.") else if (getOption("spam.cholupdatesingular") == "warning") warning("Singularity problem when updating a Cholesky Factor.\n'object' not updated.") else stop("'cholupdatesingular' should be 'error', 'null' or 'warning'.") } else { slot(object, "entries", check = FALSE) <- u$entries } invisible(object) } chol.spam <- function(x, pivot = "MMD", method="NgPeyton", memory=list(), eps = getOption("spam.eps"), Rstruct=NULL, ...){ if (is(Rstruct,"spam.chol.NgPeyton")) invisible( update.spam.chol.NgPeyton(Rstruct,x,...)) force64 <- getOption("spam.force64") if(force64 || prod(dim(x)) > 2147483647) SS <- .format64() else SS <- .format32 #!3# if (eps<.Machine$double.eps) stop("'eps' should not be smaller than machine precision",call.=FALSE) nrow <- x@dimension[1] nnzA <- x@rowpointers[nrow+1]-1 if(nrow!=x@dimension[2]) stop("non-square matrix in 'chol'",call.=FALSE) if (any( diag(x, nrow, nrow) < getOption("spam.eps"))) stop("Input matrix to 'chol' not positive definite (up to eps)",call.=FALSE) # base rule: # `nrow(x) * .Machine$double.neg.eps * max(diag(x)`. if(getOption("spam.cholsymmetrycheck")) { test <- isSymmetric(x, tol = eps*100) # from help of isSymmetric: # isSymmetric(object, tol = 100 * .Machine$double.eps, ...) if (!isTRUE(test)) stop("Input matrix to 'chol' not symmetric (up to 100*eps)",call.=FALSE) } if (method != "NgPeyton") warning(gettextf("method = '%s' is not supported. Using 'NgPeyton'", method), domain = NA) if (length(pivot)==1) { if (pivot==FALSE) { doperm <- 0 pivot <- seq_len(nrow) } else if(pivot==TRUE) { doperm <- 1 pivot <- vector(SS$type,nrow) } else { doperm <- as.integer( switch(match.arg(pivot,c("MMD","RCM")),MMD=1,RCM=2)) pivot <- vector(SS$type, nrow) } } else if (length(pivot)==nrow) { doperm <- 0 if (getOption("spam.cholpivotcheck")) { checkpivot(pivot,nrow) } } else stop("'pivot' should be 'MMD', 'RCM' or a valid permutation") ### IMPROVEME get better parameter values nnzcfact <- c(5,1,5) nnzRfact <- c(5,1,2) # nnzcolindices = length of array holding the colindices if(is.null(memory$nnzcolindices)) { nnzcolindices <- ifelse((nnzA/nrow < 5), # very sparse matrix max(1000,nnzA*(1.05*nnzA/nrow-3.8)), nnzA)*nnzcfact[doperm+1] nnzcolindices <- max(nnzcolindices,nnzA) }else { nnzcolindices <- max(memory$nnzcolindices,nnzA) memory$nnzcolindices <- NULL } # nnzR = length of array holding the nonzero values of the factor if(is.null(memory$nnzR)) { nnzR <- min(max(4*nnzA,floor(.2*nnzA^1.3))*nnzRfact[doperm+1],nrow*(nrow+1)/2) } else { nnzR <- memory$nnzR memory$nnzR <- NULL } #!4# if(is.null(memory$cache)) cache <- 512 else { cache <- memory$cache memory$cache <- NULL } if (length( memory)>0 ) warning("The component(s) ", paste("'",names(memory),"'",sep='',collapse=","), " of the argument 'memory'\npassed to function 'chol' not meaningful and hence ignored.",call.=FALSE) cholstep.intent <- c("r", "r", "r", "r", "r", "r", "rw", "rw", "rw", "r", "rw", "rw", "rw", "rw", "rw", "rw", "rw", "rw", "r", "rw") cholstep.signature <- rep(SS$signature, 20) cholstep.signature[c(3,15)] <- "double" z <- .C64("cholstepwise", SIGNATURE=cholstep.signature, nrow = nrow, nnzA = nnzA, d = x@entries, jd = x@colindices, id = x@rowpointers, #5 doperm = doperm, invp = vector(SS$type,nrow), perm = pivot, nnzlindx = 1L, #9 nnzcolindices = nnzcolindices, lindx = vector(SS$type, nnzcolindices), xlindx = vector(SS$type, nrow+1), nsuper = 1L, #13 nnzR = nnzR, lnz = vector("double",nnzR), xlnz = vector(SS$type, nrow+1), snode = vector(SS$type, nrow), #17 xsuper = vector(SS$type, nrow+1), cachesize = cache, ierr = 0L, INTENT=cholstep.intent, NAOK = getOption("spam.NAOK"), PACKAGE = SS$package) if(z$ierr == 1) stop("Singularity problem when calculating the Cholesky factor.") if(z$ierr == 6) stop("Inconsitency in the input",call.=FALSE) while( z$ierr>1) { if(z$ierr == 4) { tmp <- ceiling(nnzR*getOption("spam.cholincreasefactor")[1]) warning("Increased 'nnzR' with 'NgPeyton' method\n", "(currently set to ",tmp," from ",nnzR,")",call.=FALSE) nnzR <- tmp } if(z$ierr == 5) { tmp <- ceiling(nnzcolindices*getOption("spam.cholincreasefactor")[2]) warning("Increased 'nnzcolindices' with 'NgPeyton' method\n", "(currently set to ",tmp," from ",nnzcolindices,")",call.=FALSE) nnzcolindices <- tmp } z <- .C64("cholstepwise", SIGNATURE=cholstep.signature, nrow = nrow, nnzA = x@rowpointers[nrow+1]-1, d = x@entries, jd = x@colindices, id = x@rowpointers, doperm = doperm, invp = vector(SS$type,nrow), perm = pivot, nnzlindx = vector(SS$type,1), nnzcolindices = nnzcolindices, lindx = vector(SS$type, nnzcolindices), xlindx = vector(SS$type, nrow+1), # nsuper = 1, # nnzR = nnzR,# lnz = vector("double",nnzR), # xlnz = vector(SS$type, nrow+1), # snode = vector(SS$type, nrow), xsuper = vector(SS$type, nrow+1), cachesize = cache, ierr = 0L, INTENT=cholstep.intent, NAOK = getOption("spam.NAOK"), PACKAGE = SS$package) if(z$ierr == 1) stop("Singularity problem when calculating the Cholesky factor.") } nnzR <- z$xlnz[length(z$xlnz)]-1 newx <- new("spam.chol.NgPeyton") slot(newx,"entries",check=FALSE) <- z$lnz[1:nnzR] slot(newx,"colindices",check=FALSE) <- z$lindx[1:z$nnzlindx] slot(newx,"colpointers",check=FALSE) <- z$xlindx[1:(z$nsuper+1)] slot(newx,"rowpointers",check=FALSE) <- z$xlnz slot(newx,"dimension",check=FALSE) <- c(nrow,nrow) slot(newx,"pivot",check=FALSE) <- z$perm slot(newx,"invpivot",check=FALSE) <- z$invp slot(newx,"supernodes",check=FALSE) <- z$xsuper[1:(z$nsuper+1)] slot(newx,"snmember",check=FALSE) <- z$snode slot(newx,"memory",check=FALSE) <- c(nnzcolindices,z$nnzR,cache) slot(newx,"nnzA",check=FALSE) <- nnzA invisible(newx) } solve.spam <- function (a, b, Rstruct = NULL, ...) { nrow <- a@dimension[1] ncol <- a@dimension[2] if (ncol != nrow) stop("only square matrices can be inverted") if (missing(b)) { b <- diag(1, ncol) } else { if(!is.matrix(b)) b <- as.matrix(b) } p <- dim(b)[2] if(nrow!=dim(b)[1])stop("'b' must be compatible with 'a'") # if we have a spam matrix, we calculate the Cholesky factor if (is(a,"spam")) if (is(Rstruct, "spam.chol.NgPeyton")) a <- update.spam.chol.NgPeyton(Rstruct, a, ...) else a <- chol.spam(a, ...) if (is(a,"spam.chol.NgPeyton")) { # The following is a fast way to perform: # z <- backsolve(a,forwardsolve( t(a),b)) ## print("a is spam.chol.NgPeyton in solve.spam") nsuper <- as.integer( length(a@supernodes)-1) ## z <- .Fortran("backsolves", m = nrow, ## as.integer(nsuper), as.integer(p), as.integer(a@colindices), ## as.integer(a@colpointers), as.double(a@entries), ## as.integer(a@rowpointers), as.integer(a@invpivot), as.integer(a@pivot), ## as.integer(a@supernodes), vector("double",nrow), sol = vector("double",nrow*p), ## as.vector(b,"double"), ## NAOK = getOption("spam.NAOK"), ## PACKAGE = "spam")$sol if( getOption("spam.force64") || .format.spam(a)$package != "spam" ) SS <- .format64() else SS <- .format32 z <- .C64("backsolves", SIGNATURE = c(rep(SS$signature,5),"double", rep(SS$signature, 4), rep("double",3)), m = nrow, nsuper, p, a@colindices, a@colpointers, a@entries, a@rowpointers, a@invpivot, a@pivot, a@supernodes, vector_dc("double",nrow), sol = vector_dc("double",nrow*p), as.vector(b,"double"), INTENT = c( rep( "r", 10), rep( "rw", 3)), NAOK = getOption("spam.NAOK"), PACKAGE = SS$package )$sol } else z <- backsolve(a, forwardsolve( t(a),b)) # see the helpfile for a comment about the 't(a)' construct. if ( p!=1) dim(z) <- c(nrow,p) return( z) } chol2inv.spam <- function (x, ...) { ## print("chol2inv.spam") nrow <- x@dimension[1] if (is(x,"spam.chol.NgPeyton")) { ## print("x = spam.chol.NgPeyton") y <- vector("double",nrow*nrow) y[1L + 0L:(nrow - 1L) * (nrow + 1L)] <- 1.0 ## z <- .Fortran("backsolves", m = nrow, ## as.integer( length(x@supernodes)-1), as.integer(nrow), as.integer(x@colindices), ## as.integer(x@colpointers), as.double(x@entries), ## as.integer(x@rowpointers), as.integer(x@invpivot), as.integer(x@pivot), ## as.integer(x@supernodes), vector("double",nrow), sol = vector("double",nrow*nrow), as.double(y), ## NAOK = getOption("spam.NAOK"), ## PACKAGE = "spam")$sol if( getOption("spam.force64") || .format.spam(x)$package !="spam" ) SS <- .format64() else SS <- .format32 ## print(SS$package) z <- .C64("backsolves", ## subroutine backsolves(m,nsuper,nrhs,lindx,xlindx,lnz, ## & xlnz,invp,perm,xsuper,newrhs,sol,b) SIGNATURE = c( rep( SS$signature, 5), "double", rep( SS$signature, 4), rep( "double", 3)), m = nrow, #r length(x@supernodes)-1, #r nrow, #r x@colindices, x@colpointers, x@entries, x@rowpointers, x@invpivot, #r x@pivot, #r x@supernodes, #r vector_dc("double",nrow), #rw sol = vector_dc("double",nrow*nrow), #w y, #r INTENT = c( rep( "r", 10), "rw", "w", "r"), NAOK = getOption("spam.NAOK"), PACKAGE = SS$package)$sol dim(z) <- c(nrow,nrow) } else z <- backsolve.spam(x, forwardsolve.spam( t(x), diag(nrow))) return( z) } backsolve.spam <- function(r, x,...){#, k = NULL, upper.tri = NULL, transpose = NULL){ # r: spam.chol.NgPeyton structure as returned by chol.spam or a spam object # x: rhs a vector or a matrix in dense form # dimensions: ( m x n) ( n x p) if( getOption("spam.force64") || .format.spam(r)$package !="spam" ) SS <- .format64() else SS <- .format32 m <- r@dimension[1] if(is.vector(x)) { n <- length(x) p <- 1 } else { x <- as.matrix(x) n <- dim(x)[1] p <- dim(x)[2] } # we separate between "spam.chol.NgPeyton" and "spam" if (is(r,"spam.chol.NgPeyton")) { if (n!=m) stop("Cholesky factor 'r' not compatible with 'x'") nsuper <- length(r@supernodes)-1 if (!getOption("spam.dopivoting")) { z <- .C64("backsolvef", SIGNATURE=c(SS$signature, SS$signature, SS$signature, SS$signature, SS$signature, "double", SS$signature, SS$signature, "double"), m, nsuper, p, r@colindices, r@colpointers, r@entries, r@rowpointers, r@supernodes, sol = vector("double",m*p), INTENT=c("r", "r", "r", "r", "r", "r", "r", "r", "w"), NAOK = getOption("spam.NAOK"), PACKAGE=SS$package)$sol }else{ z <- .C64("pivotbacksolve", SIGNATURE=c(SS$signature, SS$signature, SS$signature, SS$signature, SS$signature, "double", SS$signature, SS$signature, SS$signature, SS$signature, "double", "double", "double"), m, nsuper, p, r@colindices, r@colpointers, r@entries, r@rowpointers, r@invpivot, r@pivot, r@supernodes, vector("double",m), sol = vector("double",m*p), x, INTENT=c("r", "r", "r", "r", "r", "r", "r", "r", "r", "r", "r", "w", "r"), NAOK = getOption("spam.NAOK"), PACKAGE=SS$package)$sol } } else { if (n!=m) stop("Triangular matrix 'r' not compatible with 'x'") # solve R sol = x z <- .C64("spamback", SIGNATURE=c(SS$signature, SS$signature, "double", "double", "double", SS$signature, SS$signature), m=m, unused=p, sol = vector("double",m*p), x=x, al=r@entries, jal=r@colindices, ial=r@rowpointers, INTENT=c("rw", "rw", "rw", "rw", "rw", "rw", "rw"), NAOK = getOption("spam.NAOK"), PACKAGE=SS$package) if (z$m<0) stop(gettextf("singular matrix in 'backsolve'. Last zero in diagonal [%d]", -z$m), domain = NA) else z <- z$sol } if (p>1) dim(z) <- c(m,p) return(z) } forwardsolve.spam <- function(l, x,...){#, k = NULL, upper.tri = NULL, transpose = NULL){ # l: spam.chol.NgPeyton structure as returned by chol.spam # or an ordinary lower triangular spam matrix # x: rhs a vector a matrix in dense form # dimensions: ( m x n) ( n x p) # if (!any(is.null(c(upper.tri,k,transpose )))) # warning("'k', 'upper.tri' and 'transpose' argument do not have any effect here") if( getOption("spam.force64") || .format.spam(l)$package !="spam" ) SS <- .format64() else SS <- .format32 m <- l@dimension[1] if(is.vector(x)) { n <- length(x) p <- 1L } else { if(!is.matrix(x)) x <- as.matrix(x) n <- dim(x)[1] p <- dim(x)[2] } # we separate between "spam.chol.NgPeyton" and "spam" if (is(l,"spam.chol.NgPeyton")) { if(n!=m) stop("Cholesky factor 'l' not compatible with 'x'") nsuper <- length(l@supernodes)-1 if (!getOption("spam.dopivoting")) { z <- .C64("forwardsolvef", SIGNATURE=c(SS$signature, SS$signature, SS$signature, SS$signature, SS$signature, "double", SS$signature, SS$signature, "double"), m, nsuper, p, l@colindices, l@colpointers, l@entries, l@rowpointers, l@supernodes, sol = vector("double",m*p), INTENT=c("r", "r", "r", "r", "r", "r", "r", "r", "w"), NAOK = getOption("spam.NAOK"), PACKAGE=SS$package)$sol }else{ z <- .C64("pivotforwardsolve", SIGNATURE=c(SS$signature, SS$signature, SS$signature, SS$signature, SS$signature, "double", SS$signature, SS$signature, SS$signature, SS$signature, "double", "double", "double"), m, nsuper, p, l@colindices, l@colpointers, l@entries, l@rowpointers, l@invpivot, l@pivot, l@supernodes, vector("double",m), #!5# sol = vector("double",m*p), x, INTENT=c("r", "r", "r", "r", "r", "r", "r", "r", "r", "r", "r", "w", "r"), PACKAGE=SS$package)$sol } } else { if (n!=m) stop("Triangular matrix 'l' not compatible with 'x'") # solve L sol = x z <- .C64("spamforward", SIGNATURE=c(SS$signature, SS$signature, "double", "double", "double", SS$signature, SS$signature), m=m, p, sol = vector("double",m*p), x=x, al=l@entries, jal=l@colindices, ial=l@rowpointers, INTENT=c("rw", "r", "w", "r", "r", "r", "r"), NAOK = getOption("spam.NAOK"), PACKAGE=SS$package) if (z$m<0) stop(gettextf("singular matrix in 'forwardsolve'. First zero in diagonal [%d]", -z$m), domain = NA) else z <- z$sol } if (p>1) dim(z) <- c(m,p) return(z) } setMethod("chol","spam", chol.spam) setMethod("solve","spam",solve.spam) setMethod("chol2inv","spam", chol2inv.spam) setMethod("chol2inv","spam.chol.NgPeyton", chol2inv.spam) setMethod("backsolve","spam",#signature(r="spam",x='ANY'), backsolve.spam) setMethod("backsolve","spam.chol.NgPeyton",#signature(r="spam.chol.NgPeyton",x='ANY'), backsolve.spam,sealed=TRUE) #setMethod("backsolve","spam.chol.NgPeyton", backsolve.spam) setMethod("forwardsolve","spam", forwardsolve.spam) setMethod("forwardsolve","spam.chol.NgPeyton", forwardsolve.spam) ###################################################################### ###################################################################### determinant.spam <- function(x, logarithm = TRUE, pivot = "MMD",method="NgPeyton", memory=list(),eps = getOption("spam.eps"), ...){ # print("determinant.spam") if (eps<.Machine$double.eps) stop("'eps' should not be smaller than machine precision",call.=FALSE) logdet <- list() #### start from above nrow <- x@dimension[1] nnzA <- as.integer( x@rowpointers[nrow+1]-1) if(nrow!=x@dimension[2]) stop("non-square matrix in 'chol'",call.=FALSE) if(nrow <= 1) { return(determinant(as.matrix(x@entries))) } if(getOption("spam.cholsymmetrycheck")) { test <- isSymmetric.spam(x, tol = eps*100) if (!isTRUE(test)) stop("Input matrix to 'chol' not symmetric (up to 100*eps)",call.=FALSE) } if (method != "NgPeyton") warning(gettextf("method = '%s' is not supported. Using 'NgPeyton'", method), domain = NA) if (length(pivot)==nrow) { doperm <- 0L pivot <- as.vector(pivot,"integer") if (getOption("spam.cholpivotcheck")) { checkpivot(pivot,nrow) } } else if (length(pivot)==1) { if (pivot==FALSE) { doperm <- 0L pivot <- seq_len(nrow) } else if(pivot==TRUE) { doperm <- 1L pivot <- vector("integer",nrow) } else { doperm <- as.integer( switch(match.arg(pivot,c("MMD","RCM")),MMD=1,RCM=2)) pivot <- vector("integer",nrow) } } else stop("'pivot' should be 'MMD', 'RCM' or a permutation") #!6# nnzcfact <- c(5,1,5) nnzRfact <- c(5,1,2) # nnzcolindices = length of array holding the colindices if(is.null(memory$nnzcolindices)) { nnzcolindices <- ifelse((nnzA/nrow < 5), # very sparse matrix max(1000,nnzA*(1.05*nnzA/nrow-3.8)), nnzA)*nnzcfact[doperm+1] nnzcolindices <- max(nnzcolindices,nnzA) }else { nnzcolindices <- max(memory$nnzcolindices,nnzA) memory$nnzcolindices <- NULL } # nnzR = length of array holding the nonzero values of the factor if(is.null(memory$nnzR)) nnzR <- min(max(4*nnzA,floor(.4*nnzA^1.2))*nnzRfact[doperm+1],nrow*(nrow+1)/2) else { nnzR <- memory$nnzR memory$nnzR <- NULL } if(is.null(memory$cache)) cache <- 64 else { cache <- memory$cache memory$cache <- NULL } if (length( memory)>0 ) warning("The component(s) ", paste("'",names(memory),"'",sep='',collapse=","), " of the argument 'memory'\npassed to function 'chol' not meaningful and hence ignored.",call.=FALSE) ## print("determinant.spam") ## z <- .Fortran("cholstepwise", ## nrow = as.integer(nrow) ,nnzA = as.integer(x@rowpointers[nrow+1]-1), ## d = as.double(x@entries),jd = as.integer(x@colindices),id = as.integer(x@rowpointers), ## doperm = as.integer(doperm), invp = vector("integer",nrow), perm = as.integer(pivot), ## nnzlindx = vector("integer",1), ## nnzcolindices = as.integer(nnzcolindices), ## lindx = vector("integer",nnzcolindices), ## xlindx = vector("integer",nrow+1), # ## nsuper = vector("integer",1), # ## nnzR = as.integer(nnzR),# ## lnz = vector("double",nnzR), # ## xlnz = vector("integer",nrow+1), # ## snode = vector("integer",nrow), ## xsuper = vector("integer",nrow+1), ## cachesize = as.integer(cache), ## ierr = 0L, ## NAOK = getOption("spam.NAOK"), PACKAGE = "spam") if( getOption("spam.force64") || prod(dim(x)) > 2147483647) SS <- .format64() else SS <- .format32 cholstep.intent <- c("r", "r", "r", "r", "r", "rw", "rw", "rw", "rw", "rw", "rw", "rw", "rw", "rw", "rw", "rw", "rw", "rw", "rw", "rw") cholstep.signature <- rep(SS$signature, 20) cholstep.signature[c(3,15)] <- "double" z <- .C64("cholstepwise", ## subroutine cholstepwise(m,nnzd, ## & d,jd,id, doperm,invp,perm, ## & nsub,nsubmax, ## & lindx,xlindx,nsuper,nnzlmax,lnz,xlnz, ## & snode,xsuper, ## & cachsz,ierr) SIGNATURE = cholstep.signature, nrow = nrow , nnzA = x@rowpointers[nrow+1]-1, d = x@entries, jd = x@colindices, id = x@rowpointers, doperm = doperm, invp = vector_dc( SS$type, nrow), perm = pivot, nnzlindx = vector_dc( SS$type, 1), nnzcolindices = nnzcolindices, lindx = vector_dc( SS$type, nnzcolindices), xlindx = vector_dc( SS$type,nrow+1), # nsuper = vector_dc( SS$type,1), # nnzR = nnzR,# lnz = vector_dc( "double", nnzR), # xlnz = vector_dc( SS$type, nrow+1), # snode = vector_dc( SS$type, nrow), xsuper = vector_dc( SS$type, nrow+1), cachesize = cache, ierr = 0, ## INTENT = cholstep.intent, NAOK = getOption("spam.NAOK"), PACKAGE = SS$package) if(z$ierr == 1) stop("Singularity problem when calculating the Cholesky factor.") if(z$ierr == 6) stop("Inconsitency in the input",call.=FALSE) while( z$ierr>1) { if(z$ierr == 4) { warning("Increased 'nnzR' with 'NgPeyton' method\n", "(currently set to ",nnzR," from ",ceiling(nnzR*getOption("spam.cholpar")[1]),")",call.=FALSE) nnzR <- ceiling(nnzR*getOption("spam.nnzRinc")) } if(z$ierr == 5) { warning("Increased 'nnzcolindices' with 'NgPeyton' method\n", "(currently set to ",nnzcolindices," from ",ceiling(nnzcolindices*getOption("spam$cholpar")[2]),")",call.=FALSE) nnzcolindices <- ceiling(nnzcolindices*getOption("spam.cholpar")[2]) } print("whileloop in determinant.spam") ##TODO find a case with z$ierr > 1 before migration possible z <- .Fortran("cholstepwise", nrow = nrow,nnzA = as.integer(x@rowpointers[nrow+1]-1), d = as.double(x@entries),jd = x@colindices,id = x@rowpointers, doperm = doperm,invp = vector("integer",nrow), perm = pivot, nnzlindx = vector("integer",1), nnzcolindices = as.integer(nnzcolindices), lindx = vector("integer",nnzcolindices), xlindx = vector("integer",nrow+1), # nsuper = vector("integer",1), # nnzR = as.integer(nnzR),# lnz = vector("double",nnzR), # xlnz = vector("integer",nrow+1), # snode = vector("integer",nrow), xsuper = vector("integer",nrow+1), cachesize = as.integer(cache), ierr = 0L, NAOK = getOption("spam.NAOK"), PACKAGE = "spam") } #### end from above if(z$ierr == 1) { # all other errors trapped warning("singularity problem or matrix not positive definite",call.=FALSE) logdet$modulus <- NA } else{ tmp <- 2* sum( log( z$lnz[ z$xlnz[ -(z$nrow+1)]])) if (logarithm) logdet$modulus <- tmp else logdet$modulus <- exp(tmp) } attr(logdet$modulus,"logarithm") <- logarithm logdet$sign <- ifelse(z$ierr == 1,NA,1) attr(logdet,"class") <- "det" return(logdet) } determinant.spam.chol.NgPeyton <- function(x, logarithm = TRUE,...) { logdet <- list() tmp <- sum( log(x@entries[ x@rowpointers[-(x@dimension[1]+1)]])) if (logarithm) logdet$modulus <- tmp else logdet$modulus <- exp(tmp) attr(logdet$modulus,"logarithm") <- logarithm logdet$sign <- 1 attr(logdet,"class") <- "det" return(logdet) } setMethod("determinant","spam", determinant.spam) setMethod("determinant","spam.chol.NgPeyton", determinant.spam.chol.NgPeyton) ## The ``Right Thing'' to do : ## base::det() calls [base::]determinant(); ## our det() should call our determinant() : det <- base::det environment(det) <- environment()## == asNamespace("Matrix") ###################################################################### ######################################################################## "as.matrix.spam.chol.NgPeyton" <- function(x,...){ ## print("as.matrix.spam.chol.NgPeyton") nrow <- x@dimension[1] nnzR <- x@rowpointers[nrow+1]-1 ## newx <- new("spam") nsuper <- length(x@supernodes)-1 ## xcolindices <- .Fortran('calcja', ## as.integer(nrow), as.integer(nsuper), as.integer(x@supernodes), as.integer(x@colindices), as.integer(x@colpointers), as.integer(x@rowpointers), ## xja=vector("integer",nnzR), ## NAOK = getOption("spam.NAOK"),PACKAGE = "spam")$xja if( getOption("spam.force64") || .format.spam(x)$package != "spam" ) SS <- .format64() else SS <- .format32 xcolindices <- .C64('calcja', SIGNATURE = c(rep(SS$signature,7)), nrow, nsuper, x@supernodes, x@colindices, x@colpointers, x@rowpointers, xja = vector_dc( SS$type, nnzR), INTENT=c("r", "r", "r", "r", "r", "r", "w"), NAOK = getOption("spam.NAOK"), PACKAGE = SS$package)$xja ## return(array(.Fortran("spamcsrdns", ## nrow = as.integer(nrow), ## entries = as.double(x@entries), ## colindices = as.integer(xcolindices), ## rowpointers = as.integer(x@rowpointers), ## res = vector("double",nrow*nrow), ## NAOK=getOption("spam.NAOK"),PACKAGE = "spam")$res, ## c(nrow,nrow)) # we preserve dimensions ## ) return(array(.C64("spamcsrdns", SIGNATURE = c(SS$signature, "double" , SS$signature, SS$signature, "double"), nrow = nrow, entries = x@entries, colindices = xcolindices, rowpointers = x@rowpointers, res = vector_dc( "double", nrow*nrow), INTENT = c("r", "r", "r", "r", "w"), NAOK=getOption("spam.NAOK"), PACKAGE = SS$package)$res, c(nrow,nrow)) # we preserve dimensions ) } setMethod("as.matrix","spam.chol.NgPeyton",as.matrix.spam.chol.NgPeyton) setMethod("as.vector","spam.chol.NgPeyton", function(x){ as.vector.spam(as.spam.chol.NgPeyton(x)) }) ######################################################################## # force to spam matrices. Would not be required with inheritance setMethod("image","spam.chol.NgPeyton", function(x,cex=NULL,...){ image.spam(as.spam.chol.NgPeyton(x),cex=cex,...) }) setMethod("display","spam.chol.NgPeyton", function(x,...){ display.spam(as.spam.chol.NgPeyton(x),...) }) setMethod("t","spam.chol.NgPeyton", function(x){ t.spam(as.spam.chol.NgPeyton(x)) }) setMethod("chol","spam.chol.NgPeyton", function(x){ x }) spam/R/constructors.R0000644000176200001440000000560313536451706014324 0ustar liggesusers# HEADER #################################################### # This is file spam/R/constructors.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ "rowpointers<-" <- function(x, value) { dimx <- x@dimension nnz1 <- x@rowpointers[dimx[1]+1] diffvalue <- diff(value) if ( any(!is.finite(value))) stop("row pointers should be postive integers.") if (!identical( length(x@rowpointers), length(value))) stop("wrong length of row pointers in `rowpointers<-`.", call.=FALSE) if (any(diffvalue<0)) stop("row pointers are not monotone increasing in `rowpointers<-`.", call.=FALSE) if (any(diffvalue>dimx[2])) stop("row pointers have too large leaps in `rowpointers<-`.", call.=FALSE) if (value[1]<1) stop("first element of row pointers is < 1 in `rowpointers<-`.", call.=FALSE) if(value[dimx[1]+1] != nnz1) stop("last element of row pointers does not conform in `rowpointers<-`.", call.=FALSE) x@rowpointers <- as.integer(value) x } "colindices<-" <- function(x, value) { dimx <- x@dimension if ( any(!is.finite(value))) stop("column indices should be postive integers in `colindices<-`.", call.=FALSE) if ( any(value<1) | any(value> dimx[2])) stop("column indices exceed dimension `colindices<-`.", call.=FALSE) diffcolindices <- diff(value) # positive values within each row if (all(diff(x@rowpointers)>1) && length(diffcolindices)>0) # only if we have multiple values if (identical( dimx[1], 1L)) { if ( any(diffcolindices<1)) stop("column indices are not ordered `colindices<-`.", call.=FALSE) } else { if ( any(diffcolindices[-(x@rowpointers[2:dimx[1]]-1)]<1)) stop("column indices are not ordered `colindices<-`.", call.=FALSE) } x@colindices <- as.integer(value) x } "entries<-" <- function(x, value) { if (!identical( length(x@entries), length(value))) stop("wrong length in `entries<-`.", call.=FALSE) if (!getOption("spam.NAOK")) { if (any(!is.finite(value))) stop("\"NA/NaN/Inf\" not allowed in `entries<-`.", call.=FALSE) } if (!is.numeric( value)) stop("numerical required in `entries<-`.", call.=FALSE) x@entries <- as.double(value) x } "dimension<-" <- function(x, value) { stop("modification through dim() or pad()", call.=FALSE) } spam/R/spamlist.R0000644000176200001440000001312013536451710013374 0ustar liggesusers# HEADER #################################################### # This is file spam/R/spamlist.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ as.spam.list <- function(x, eps = getOption("spam.eps")) { spam.list( x, eps=eps) } spam.list <- function(x, nrow, ncol, eps = getOption("spam.eps")) { force64 <- getOption("spam.force64") if (eps<.Machine$double.eps) stop("'eps' should not be smaller than machine precision",call.=FALSE) if (!is.list(x)|(length(x)<2)|(length(x)>3)) stop("Argument 'x' needs to be a list with two or three elements") # two cases: list of length # - two (matrix with two columns called ind* and the elements) # - three (each one column called i*, j*. if (identical(length(x),2L)) { indnr <- pmatch("ind",names(x)) if (is.na(indnr)) stop("Argument 'x' needs an element called 'indices'") elenr <- ifelse( identical( indnr,1L), 2L, 1L) nz <- length( x[[elenr]]) dimx <- dim(x[[indnr]]) if (is.null(dimx)||(dimx[2] != 2)) stop("Indices should have two columns") if (dimx[1] != nz) stop("Number of indices does not match with number of elements") ir <- as.integer(x[[indnr]][,1]) jc <- as.integer(x[[indnr]][,2]) if(force64 || length(x[[elenr]]) > 2147483646) SS <- .format64() else SS <- .format32 } else { inr <- pmatch("i",names(x)) jnr <- pmatch("j",names(x)) if (is.na(inr)||is.na(jnr)) stop("Argument 'x' needs elements called 'i' and 'j'") elenr <- c(1:3)[-c(inr,jnr)] nz <- length( x[[elenr]]) ir <- as.integer(x[[inr]]) jc <- as.integer(x[[jnr]]) if ((length(ir) != nz)||(length(jc) != nz)) stop("Number of indices does not match with number of elements") if(force64 || length(x[[elenr]]) > 2147483646) SS <- .format64() else SS <- .format32 } if (nz == 0) return(.newSpam( # rowpointers = c(1,rep_len64(2, nrow)), dimension = c(nrow,ncol), force64 = force64)) if (any( ir <= 0) || any( jc <= 0)) stop("Indices need to be positive") if (any(!is.finite(x[[elenr]]))) { warning("'NA/NaN/Inf' coerced to zero") x[[elenr]][!is.finite(x[[elenr]])] <- 0 } nrow <- as.integer(ifelse(missing(nrow),max(ir),nrow)) ncol <- as.integer(ifelse(missing(ncol),max(jc),ncol)) ## z <- .Fortran(ifelse(toupper(getOption("spam.listmethod")=="PE"),"triplet3csr","triplet2csr"), ## nrow=as.integer(nrow), ncol=as.integer(ncol), ## nz=as.integer(nz), ## as.double(x[[elenr]]),as.integer(ir),as.integer(jc), ## entries=vector("double",nz), ## colindices=vector("integer",nz), ## rowpointers=vector("integer",nrow+1), as.double(eps), ## NAOK=TRUE, PACKAGE = "spam" ## ) z <- .C64(ifelse(toupper(getOption("spam.listmethod")=="PE"),"triplet3csr","triplet2csr"), ## subroutine triplet3csr(nrow,ncol,nnz,a,ir,jc,ao,jao,iao,eps) ## subroutine triplet2csr(nrow,ncol,nnz,a,ir,jc,ao,jao,iao,eps) SIGNATURE = c( SS$signature, SS$signature, SS$signature, "double", SS$signature, SS$signature, "double", SS$signature, SS$signature, "double"), nrow = nrow, ncol = ncol, nz = nz, x[[elenr]], ir, jc, entries = vector_dc( "double", nz), colindices = vector_dc( SS$type, nz), rowpointers = vector_dc( SS$type, nrow+1), eps, INTENT = c("r", "r", "rw", "rw", "rw", "rw", "rw", "rw", "rw", "r"), NAOK=TRUE, PACKAGE = SS$package ) # print(z) if (z$nz == 0){ ## if (identical(z$nz, 0)){ ## print("special case") return(.newSpam( # rowpointers = c(1, rep_len64(2,nrow)), dimension = c(nrow, ncol), force64 = force64)) ## return(new("spam",rowpointers=c(1L,rep.int(2L,nrow)), dimension=c(nrow,ncol))) } ## newx <- new("spam") ## slot(newx,"entries",check=FALSE) <- z$entries[1:z$nz] ## slot(newx,"colindices",check=FALSE) <- z$colindices[1:z$nz] ## slot(newx,"rowpointers",check=FALSE) <- z$rowpointers ## slot(newx,"dimension",check=FALSE) <- c(nrow,ncol) ## return(newx) return(.newSpam( entries = z$entries[1:z$nz], colindices = z$colindices[1:z$nz], rowpointers = z$rowpointers, dimension = c(nrow,ncol), force64 = force64)) } setMethod("as.spam", "list", as.spam.list) # { function(x,eps) spam.list(x,eps=eps)}) setMethod("spam", "list", spam.list) spam/R/plotting.R0000644000176200001440000001477413536451707013426 0ustar liggesusers# HEADER #################################################### # This is file spam/R/plotting.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ # Similar to misc3D if(! exists(".bincode", envir = .BaseNamespaceEnv)) .bincode <- function(v, breaks, ...) { .C("bincode", as.double(v), length(v), as.double(breaks), length(breaks), code = integer(length(v)), as.logical(TRUE), as.logical(TRUE), nok = TRUE, NAOK = TRUE, PACKAGE = "base")$code } image.spam <- function (x = seq(0, 1, len = nrow(z)), y = seq(0, 1, len = ncol(z)), z, zlim = range(z), xlim = range(x), ylim = range(y), col = heat.colors(12), add = FALSE, xaxs = "i", yaxs = "i", xlab, ylab, breaks, oldstyle = FALSE,cex=NULL, ...) { if (missing(z)) { if (!missing(x)) { if (is.list(x)) { z <- x$z y <- x$y x <- x$x } else { if (is.null(dim(x))) stop("argument must be matrix-like") z <- x x <- seq(0, 1, len = dim(z)[1]) } if (missing(xlab)) xlab <- "" if (missing(ylab)) ylab <- "" } else stop("no 'z' matrix specified") } else if (is.list(x)) { xn <- deparse(substitute(x)) if (missing(xlab)) xlab <- paste(xn, "x", sep = "$") if (missing(ylab)) ylab <- paste(xn, "y", sep = "$") y <- x$y x <- x$x } else { if (missing(xlab)) xlab <- if (missing(x)) "" else deparse(substitute(x)) if (missing(ylab)) ylab <- if (missing(y)) "" else deparse(substitute(y)) } if (any(!is.finite(x)) || any(!is.finite(y))) stop("'x' and 'y' values must be finite and non-missing") if (any(diff(x) <= 0) || any(diff(y) <= 0)) stop("increasing 'x' and 'y' values expected") spamversion <- (prod(z@dimension) > getOption("spam.imagesize")) if (!spamversion){ image.default(x, y, as.matrix(z),...) } else { if (!is.spam(z)) stop("'z' must be a matrix") xx <- x yy <- y if (length(x) > 1 && length(x) == dim(z)[1]) { dx <- 0.5 * diff(x) x <- c(x[1] - dx[1], x[-length(x)] + dx, x[length(x)] + dx[length(x) - 1]) } if (length(y) > 1 && length(y) == dim(z)[2]) { dy <- 0.5 * diff(y) y <- c(y[1] - dy[1], y[-length(y)] + dy, y[length(y)] + dy[length(y) - 1]) } zvals <- z@entries if (missing(breaks)) { nc <- length(col) if (!missing(zlim) && (any(!is.finite(zlim)) || diff(zlim) < 0)) stop("invalid z limits") if (diff(zlim) == 0) zlim <- if (zlim[1] == 0) { c(-1, 1) } else zlim[1] + c(-0.4, 0.4) * abs(zlim[1]) zvals <- (zvals - zlim[1])/diff(zlim) zi <- if (oldstyle) { floor((nc - 1) * zvals + 0.5) } else floor((nc - 1e-05) * zvals + 1e-07) zi[zi < 0 | zi >= nc] <- NA } else { if (length(breaks) != length(col) + 1) stop("must have one more break than colour") if (any(!is.finite(breaks))) stop("breaks must all be finite") # Patch proposed by BR see email. zi <- .bincode(zvals, breaks, TRUE, TRUE) - 1 } if (!add) plot(NA, NA, xlim = xlim, ylim = ylim, type = "n", xaxs = xaxs, yaxs = yaxs, xlab = xlab, ylab = ylab, ...) if (length(xx) != dim(z)[1] || length(yy) != dim(z)[2]) stop("dimensions of z are not length(x) times length(y)") if (missing(cex)) { warning("default value for 'cex' in 'image' might be a bad choice", call.=FALSE) cex <- 1 } points( xx[rep.int((1:dim(z)[1]),diff(z@rowpointers))], yy[z@colindices], pch=".", cex=cex*getOption("spam.cex")/sum(z@dimension), col=col[zi+1]) } box() } display.spam <- function(x,col=c("gray","white"),xlab="column",ylab="row", cex=NULL, main="",...) { nrow <- x@dimension[1] ncol <- x@dimension[2] # For small matrices, we transform them into regular ones and use the image.default # routine. if (prod(nrow,ncol) < getOption("spam.imagesize")) { z <- vector("double", prod(nrow,ncol)) dim(z) <- c(nrow,ncol) z[cbind(rep.int(nrow:1,diff(x@rowpointers)),x@colindices)] <- -1 image.default(x=1:ncol,y=-(nrow:1),t(z), axes=FALSE, col=col, xlab=xlab, ylab=ylab, ...) } else { if (missing(cex)) { warning("default value for 'cex' in 'display' might not be the optimal choice", call.=FALSE) cex <- 1 } plot( x@colindices, rep.int(-(1:nrow),diff(x@rowpointers)), pch=".", cex=cex*getOption("spam.cex")/(ncol+nrow), col=col[1],xlab=xlab,ylab=ylab,axes=FALSE, ylim=c(-nrow,-0)-.5,xlim=c(0,ncol)+.5,xaxs = "i", yaxs = "i",...) } # Adjust axes labels. axis(1,pretty(1:ncol), ...) axis(2,pretty(-(nrow:1)),labels=rev(pretty(1:nrow)), ...) box() } plot.spam <- function(x,y,xlab=NULL,ylab=NULL,...) { lab <- deparse(substitute(x)) #only a few cases are considered # 1st case, a colum vector only if (dim(x)[2]==1) { x <- c(x) return( plot(x,...)) } # 2nd case a matrix tmp <- x[,1:2, drop=FALSE] # extract the first two columns plot(c( tmp[,1]), c(tmp[,2]), xlab=ifelse(missing(xlab),paste(lab,"[,1]",sep=""),xlab), ylab=ifelse(missing(ylab),paste(lab,"[,2]",sep=""),ylab),...) } #setGeneric("image", function(x, ...) standardGeneric("image")) setMethod("image","spam",function(x,cex=NULL,...){image.spam(x,cex=cex,...)}) # the following is unfortunately not possible #setMethod("image",signature(x="numeric",y="numeric",z="spam"),function(x,y,z,cex=NULL,...){image.spam(x,cex=cex,...)}) setGeneric("display",function(x,...)standardGeneric("display")) setMethod("display","spam",display.spam) setMethod("plot", signature(x="spam",y="missing"), plot.spam) setMethod("plot", signature(x="spam",y="spam"), function(x,y,...) { warning("'plot' with two 'spam' objects is not implemented",call.=FALSE) }) spam/R/tailhead.R0000644000176200001440000000402013536451710013312 0ustar liggesusers# HEADER #################################################### # This is file spam/R/tailhead.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ head.spam <- function(x, n = 6L, m = n, ...) { stopifnot(length(n) == 1L, length(m) == 1L) n <- if (n < 0L) max(dim(x)[1] + n, 0L) else min(n, dim(x)[1]) m <- if (m < 0L) max(dim(x)[2] + m, 0L) else min(m, dim(x)[2]) as.matrix(x[seq_len(n), seq_len(m), drop = FALSE]) } tail.spam <- function (x, n = 6L, m = n, addrownums = TRUE, ...) { stopifnot(length(n) == 1L, length(m) == 1L) nrx <- dim(x)[1] ncx <- dim(x)[2] n <- if (n < 0L) max(nrx + n, 0L) else min(n, nrx) m <- if (m < 0L) max(ncx + m, 0L) else min(m, ncx) selr <- seq.int(to = nrx, length.out = n) selc <- seq.int(to = ncx, length.out = n) ans <- as.matrix( x[selr, selc, drop = FALSE]) if (addrownums) { # if (addrownums && is.null(rownames(x))) { # rownames is null by default # rownames(ans) <- paste0("[", selr, ",]") # can be used from R2.15 # colnames(ans) <- paste0("[,", selc, "]") rownames(ans) <- paste("[", selr, ",]", sep = "") colnames(ans) <- paste("[,", selc, "]", sep = "") } ans } setMethod("head","spam",head.spam) setMethod("tail","spam",tail.spam) setMethod("head","spam.chol.NgPeyton", function(x, n = 6L, m = n, ...) head.spam(as.spam(x), n = 6L, m = n, ...)) setMethod("tail","spam.chol.NgPeyton", function(x, n = 6L, m = n, addrownums = TRUE, ...) tail.spam(as.spam(x), n = 6L, m = n, addrownums = TRUE, ...)) spam/R/rmvnorm.R0000644000176200001440000001077513536451707013263 0ustar liggesusers# HEADER #################################################### # This is file spam/R/rmvnorm.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ # Draw from a multivariate normal: # (Algorithm 2.3 from Rue and Held, 2005) rmvnorm.spam <- function(n, mu = rep.int(0, dim(Sigma)[1]), Sigma, Rstruct = NULL, ...) { # taken from ?chol.spam if (is(Rstruct,"spam.chol.NgPeyton")) cholS <- update.spam.chol.NgPeyton( Rstruct, Sigma, ...) else cholS <- chol.spam( Sigma,...) # cholS is the upper triangular part of the permutated matrix Sigma iord <- ordering(cholS, inv=TRUE) N <- dim(Sigma)[1] R <- as.spam(cholS) retval <- as.matrix( ( array(rnorm(n*N),c(n,N)) %*% R)[,iord,drop=F]) # It is often better to order the sample than the matrix # R itself. return(sweep(retval, 2, mu, "+")) } # Draw from a multivariate normal given a precision matrix: # (Algorithm 2.4 from Rue and Held, 2005) rmvnorm.prec <- function(n, mu = rep.int(0, dim(Q)[1]), Q, Rstruct = NULL, ...) { if (is(Rstruct,"spam.chol.NgPeyton")) R <- update.spam.chol.NgPeyton( Rstruct, Q, ...) else R <- chol(Q, ...) # R is the upper triangular part of the permutated matrix Sigma N <- dim(Q)[1] nu <- backsolve(R, array(rnorm(n*N), c(N, n)), k = N) return(t(nu + mu)) } # Draw from the canonical representation of a multivariate normal: # (Algorithm 2.5 from Rue and Held, 2005) rmvnorm.canonical <- function(n, b, Q, Rstruct=NULL, ...) { N=dim(Q)[1] if (is(Rstruct,"spam.chol.NgPeyton")) R <- update.spam.chol.NgPeyton( Rstruct, Q, ...) else R <- chol(Q,...) if(is(R,"spam.chol.NgPeyton")){ mu <- drop(solve.spam( R, b)) } else { mu <- backsolve( R, forwardsolve( t(R), b), k=N) } nu <- backsolve(R, array( rnorm(n*N), c(N, n)), k=N) return(t(nu+mu)) } rmvnorm.const <- function (n, mu = rep.int(0, dim(Sigma)[1]), Sigma, Rstruct = NULL, A = array(1, c(1,dim(Sigma)[1])), a=0, U=NULL, ...) { N <- dim(Sigma)[1] if (!identical(dim(A)[2], N)) stop("Incorrect constraint specification") if (is(Rstruct, "spam.chol.NgPeyton")) cholS <- update.spam.chol.NgPeyton(Rstruct, Sigma, ...) else cholS <- chol.spam(Sigma, ...) iord <- ordering(cholS, inv = TRUE) N <- dim(Sigma)[1] R <- as.spam(cholS) x <- sweep( (array(rnorm(n * N), c(n, N)) %*% R)[, iord, drop = F], 2, mu, "+") if (is.null(U)){ V <- backsolve( R, forwardsolve( R, t(A)), k=N) W <- A %*% V U <- solve(W, t(V)) } correct <- A %*% t(x) - a return(x - t( t(U)%*% correct)) } rmvnorm.prec.const <- function (n, mu = rep.int(0, dim(Q)[1]), Q, Rstruct = NULL, A = array(1, c(1,dim(Q)[1])), a=0, U=NULL, ...) { N = dim(Q)[1] if (!identical(dim(A)[2], N)) stop("Incorrect constraint specification") if (is(Rstruct, "spam.chol.NgPeyton")) R <- update.spam.chol.NgPeyton(Rstruct, Q, ...) else R <- chol(Q, ...) x <- backsolve(R, array(rnorm(n * N), c(N, n)), k=N) + mu if (is.null(U)){ tV <- t( backsolve( R, forwardsolve( R, t(A)), k=N)) W <- tcrossprod(A, tV) U <- solve(W, tV) } correct <- A %*% x - a return(t(x- t(U) %*% correct)) } rmvnorm.canonical.const <- function (n, b, Q, Rstruct = NULL, A = array(1, c(1,dim(Q)[1])), a=0, U=NULL, ...) { N = dim(Q)[1] if (!identical(dim(A)[2], N)) stop("Incorrect constraint specification") if (is(Rstruct, "spam.chol.NgPeyton")) R <- update.spam.chol.NgPeyton(Rstruct, Q, ...) else R <- chol(Q, ...) if (is(R, "spam.chol.NgPeyton")) { mu <- drop(solve.spam(R, b)) } else { mu <- backsolve(R, forwardsolve(t(R), b)) } x <- backsolve(R, array(rnorm(n * N), c(N, n)), k=N) + mu if (is.null(U)){ tV <- t( backsolve( R, forwardsolve( R, t(A)), k=N)) W <- tcrossprod(A, tV) U <- solve(W, tV) } correct <- A %*% x - a return(t(x- t(U) %*% correct)) } spam/R/covmat.R0000644000176200001440000001415613536451706013050 0ustar liggesusers# HEADER #################################################### # This is file spam/R/covmat.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ # construct various precision matrices covmat <- function(h, theta, ... , type="sph") { avtype <- c("exponential", "spherical", "nugget", "wu1","wu2","wu3","wendland1","wendland2", "matern") method <- pmatch(tolower(type), avtype) if (is.na(method)) stop("Covariance function not implemented yet. Please ask for.") switch(method, return(cov.exp(h, theta, ...)), return(cov.sph(h, theta, ...)), return(cov.nug(h, theta, ...)), return(cov.wu1(h, theta, ...)), return(cov.wu2(h, theta, ...)), return(cov.wu3(h, theta, ...)), return(cov.wend1(h, theta, ...)), return(cov.wend2(h, theta, ...)), return(cov.mat(h, theta, ...))) } .par.check.cov <- function(theta,nr=2){ if (any(theta<0)) { warning("Parameters coerced to positive values") theta <- abs(theta) } nt <- length(theta) if (nt < nr) return( c( theta, rep(1, nr-nt), 0)) return( c( theta, 0)[1:(nr+1)]) } cov.sph <- function(h, theta, ... , eps= getOption("spam.eps")) { theta <- .par.check.cov(theta) if (is.spam(h)) { tmp <- h@entries/theta[1] h@entries <- ifelse(tmp < eps, theta[2] + theta[3], ifelse(tmp < 1, theta[2] * (1 - 1.5 * tmp + 0.5 * tmp^3), 0)) return( h) } else { h <- h/theta[1] ifelse(h < eps, theta[2] + theta[3], ifelse(h < 1, theta[2] * (1 - 1.5 * h + 0.5 * h^3), 0)) } } cov.wend1 <- function(h, theta, ... , eps= getOption("spam.eps")) { # is \phi_{3,1} in the 98 paper and \psi_{3,1} in the 95 paper theta <- .par.check.cov(theta) if (is.spam(h)) { tmp <- h@entries/theta[1] h@entries <- ifelse(tmp < eps, theta[2] + theta[3], ifelse(tmp < 1, theta[2] * ((1 - tmp)^4*(4*tmp+1)), 0)) return( h) } else { h <- h/theta[1] ifelse(h < eps, theta[2] + theta[3], ifelse(h < 1, theta[2] * ((1 - h)^4*(4*h+1)), 0)) } } cov.wend2 <- function(h, theta, ... , eps= getOption("spam.eps")) { # is \phi_{3,2} in the 98 paper and \psi_{4,2} in the 95 paper theta <- .par.check.cov(theta) if (is.spam(h)) { tmp <- h@entries/theta[1] h@entries <- ifelse(tmp < eps, theta[2] + theta[3], ifelse(tmp < 1, theta[2] * ((1 - tmp)^6*(35*tmp^2+18*tmp+3))/3, 0)) return( h) } else { h <- h/theta[1] ifelse(h < eps, theta[2] + theta[3], ifelse(h < 1, theta[2] * ((1 - h)^6*(35*h^2+18*h+3))/3, 0)) } } cov.wu1 <- function(h, theta, ... , eps= getOption("spam.eps")) { theta <- .par.check.cov(theta) if (is.spam(h)) { tmp <- h@entries/theta[1] h@entries <- ifelse(tmp < eps, theta[2] + theta[3], ifelse(tmp < 1, theta[2] * ((1 - tmp)^3*(1+3*tmp+tmp^2)), 0)) return( h) } else { h <- h/theta[1] ifelse(h < eps, theta[2] + theta[3], ifelse(h < 1, theta[2] * ((1 - h)^3*(1+3*h+h^2)), 0)) } } cov.wu2 <- function(h, theta, ... , eps= getOption("spam.eps")) { theta <- .par.check.cov(theta) if (is.spam(h)) { tmp <- h@entries/theta[1] h@entries <- ifelse(tmp < eps, theta[2] + theta[3], ifelse(tmp < 1, theta[2] * ((1 - tmp)^4*(4+16*tmp+12*tmp^2+3*tmp^3))/4, 0)) return( h) } else { h <- h/theta[1] ifelse(h < eps, theta[2] + theta[3], ifelse(h < 1, theta[2] * ((1 - h)^4*(4+16*h+12*h^2+3*h^3))/4, 0)) } } cov.wu3 <- function(h, theta, ... , eps= getOption("spam.eps")) { theta <- .par.check.cov(theta) if (is.spam(h)) { tmp <- h@entries/theta[1] h@entries <- ifelse(tmp < eps, theta[2] + theta[3], ifelse(tmp < 1, theta[2] * ((1 - tmp)^6*(1+6*tmp+41/3*tmp^2+12*tmp^3+5*tmp^4+5/6*tmp^5)), 0)) return( h) } else { h <- h/theta[1] ifelse(h < eps, theta[2] + theta[3], ifelse(h < 1, theta[2] * ((1 - h)^6*(1+6*h+41/3*h^2+12*h^3+5*h^4+5/6*h^5)), 0)) } } cov.mat <- function(h, theta, ... , eps= getOption("spam.eps")) { theta <- .par.check.cov(theta,3) if (is.spam(h)) { tmp <- h@entries/theta[1] h@entries <- ifelse(tmp < eps, theta[2] + theta[4], theta[2] * (((2^(-(theta[3] - 1)))/gamma(theta[3])) * (tmp^theta[3]) * besselK(tmp, nu = theta[3]))) return( h) } else { h <- h/theta[1] ifelse(h < eps, theta[2] + theta[4], theta[2] * (((2^(-(theta[3] - 1)))/gamma(theta[3])) * (h^theta[3]) * besselK(h, nu = theta[3]))) } } cov.exp <- function(h, theta, ... , eps= getOption("spam.eps")) { theta <- .par.check.cov(theta,2) if (is.spam(h)) { tmp <- h@entries/theta[1] h@entries <- ifelse(tmp < eps, theta[2] + theta[3], theta[2] * exp( -tmp)) return( h) } else { h <- h/theta[1] ifelse(h < eps, theta[2] + theta[3], theta[2] * exp( -h)) } } cov.nug <- function(h, theta, ... , eps= getOption("spam.eps")) { theta <- .par.check.cov(theta,0) if (is.spam(h)) { h@entries <- ifelse(h@entries < eps, theta[1], 0) return( h) } else { ifelse(h < eps, theta[1], 0) } } spam/R/permutation.R0000644000176200001440000002003213536451707014115 0ustar liggesusers# HEADER #################################################### # This is file spam/R/permutation.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ checkpivot <- function(pivot, len, type="Pivot") { if(is.null(pivot)) return() if(!is.vector(pivot)) stop(paste(type,"is not a vector.")) pivot <- as.vector(pivot,"integer") if (length(pivot) !=len) stop(paste(type,"of wrong length.")) tmp <- sort.int(pivot) if(tmp[1]!=1 || any(tmp-seq_len(len)!=0)) stop(paste("Invalid",type)) return() } "permutation.spam" <- function(A, P=NULL, Q=NULL, ind=FALSE, check=TRUE){ # eliminated .Internal calls as this creates a "Note" on CRAN checks. # Only 1-2% timing loss, see end of the file. if( getOption("spam.force64") ) SS <- .format64() else SS <- .format.spam(A) nrow <- A@dimension[1] ncol <- A@dimension[2] if (is.null(P)&is.null(Q)) stop("At least one permutation should be specified") nz <- A@rowpointers[nrow+1]-1 if (check){ checkpivot(P,nrow,"Permutation") checkpivot(Q,ncol,"Permutation") } if (is.null(Q)) { # subroutine rperm (nrow,a,ja,ia,ao,jao,iao,perm) # B = P A P <- as.integer(P) if(ind) P <- order(P) # if(ind) P <- .Internal(order(T,F,P)) z <- .C64("rperm", ## subroutine rperm (nrow,a,ja,ia,ao,jao,iao,perm) SIGNATURE = c( SS$signature, "double", SS$signature, SS$signature, "double", SS$signature, SS$signature, SS$signature), nrow, A@entries, A@colindices, A@rowpointers, entries = vector_dc( "double", nz), colindices = vector_dc( SS$type, nz), rowpointers = vector_dc( SS$type, nrow + 1), P, INTENT = c("r", "r", "r", "r", "w", "w", "w", "r"), NAOK = getOption("spam.NAOK"), PACKAGE = SS$package) } else { if (is.null(P)){ # subroutine cperm (nrow,a,ja,ia,ao,jao,iao,perm,iwork) # integer nrow,ja(*),ia(nrow+1),jao(*),iao(nrow+1),perm(*), iwork(*) # double precision a(*), ao(*) # B = A Q Q <- as.integer(Q) if(ind) Q <- order(Q) # if(ind) Q <- .Internal(order(T,F,Q)) ## z <- .Fortran("cperm", ## as.integer(nrow), ## A@entries, as.integer(A@colindices), ## as.integer(A@rowpointers), ## entries = vector("double",nz), ## colindices = vector("integer", nz), ## rowpointers = vector("integer", nrow + 1), ## Q, ## NAOK = getOption("spam.NAOK"), PACKAGE = "spam") z <- .C64("cperm", SIGNATURE = c(SS$signature, "double", SS$signature, SS$signature, "double", SS$signature, SS$signature, SS$signature), nrow, A@entries, A@colindices, A@rowpointers, entries = vector_dc( "double", nz), colindices = vector_dc( SS$type, nz), rowpointers = vector_dc( SS$type, nrow + 1), Q, INTENT = c("r", "r", "r", "r", "w", "w", "w", "r"), NAOK = getOption("spam.NAOK"), PACKAGE = SS$package) } else { # subroutine dperm (nrow,a,ja,ia,ao,jao,iao,pperm,qperm,iwork) # B = P A Q Q <- as.integer(Q) # if(ind) Q <- .Internal(order(T,F,Q)) if(ind) Q <- order(Q) P <- as.integer(P) # if(ind) P <- .Internal(order(T,F,P)) if(ind) P <- order(P) ## z <- .Fortran("dperm", ## as.integer(nrow), ## A@entries,as.integer(A@colindices), ## as.integer(A@rowpointers), ## entries = vector("double",nz), ## colindices = vector("integer", nz), ## rowpointers = vector("integer", nrow + 1), ## P,Q, ## NAOK = getOption("spam.NAOK"), PACKAGE = "spam") z <- .C64("dperm", ## subroutine dperm (nrow,a,ja,ia,ao,jao,iao,pperm,qperm) SIGNATURE = c( SS$signature, "double", SS$signature, SS$signature, "double", SS$signature, SS$signature, SS$signature, SS$signature), nrow, A@entries, A@colindices, A@rowpointers, entries = vector_dc( "double", nz), colindices = vector_dc( SS$type, nz), rowpointers = vector_dc( SS$type, nrow + 1), P,Q, INTENT = c("r", "r", "r", "r", "w", "w", "w", "r", "r"), NAOK = getOption("spam.NAOK"), PACKAGE = SS$package) } } ## newx <- new("spam") ## slot(newx, "entries", check = FALSE) <- z$entries ## slot(newx, "colindices", check = FALSE) <- z$colindices ## slot(newx, "rowpointers", check = FALSE) <- z$rowpointers ## slot(newx, "dimension", check = FALSE) <- c(nrow,ncol) return(.newSpam( entries = z$entries, colindices = z$colindices, rowpointers = z$rowpointers, dimension = c(nrow,ncol) )) } permutation.matrix <- function(A, P=NULL, Q=NULL, ind=FALSE, check=TRUE){ nrow <- dim(A)[1] ncol <- dim(A)[1] if (is.null(P)&is.null(Q)) stop("At least one permutation should be specified") if (check){ checkpivot(P,nrow,"Permutation") checkpivot(Q,ncol,"Permutation") } if (ind) { if (is.null(Q)) return(A[P,]) if (is.null(P)) return(A[,Q]) return(A[P,Q]) } else { if (is.null(Q)) return(A[order(P),]) if (is.null(P)) return(A[,order(Q)]) return(A[order(P),order(Q)]) } } setGeneric("permutation",function(A, P=NULL, Q=NULL, ind=FALSE, check=TRUE)standardGeneric("permutation")) setMethod("permutation","matrix",permutation.matrix) setMethod("permutation","spam",permutation.spam) ### ss <- sample(1:100000) ### system.time( for( i in 1:1000) tt<-order(ss)) ### system.time( for( i in 1:1000) tt<-.Internal(order(T,F,ss))) spam/R/dim.R0000644000176200001440000001272313536451707012327 0ustar liggesusers# HEADER #################################################### # This is file spam/R/dim.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ # This is the actual dim... "dim<-.spam" <- function(x, value) { if (is.spam(x)) { dimx <- x@dimension pdim <- prod(dimx) vlen <- prod(value) if( !identical(pdim,vlen)) stop( sprintf("dims [product %d] do not match the length of object [%d]. Do you want `pad`", pdim,vlen)) if (length(value)>2) stop("dims should be of length 1 or 2") if (identical(length(value),1L)) return( c(x) ) if(any(dimx<1)) stop("the dims contain negative values") tmp <- cbind(st=rep(1:dim(x)[1],diff(x@rowpointers)), nd=x@colindices) ind <- tmp[,1]+(tmp[,2]-1)*dimx[1] - 1 slist <- list(i = ind%%value[1] +1, j = ind%/%value[1] +1, x@entries) return( spam.list( slist, nrow=value[1], ncol=value[2], eps = .Machine$double.eps)) } else { dim(x) <- value x } } ######################################################################## # dim and derivatives "pad<-.spam" <- function(x,value) { force64 <- getOption("spam.force64") # check if value is valid if ( (min(value)<1 ) || any(!is.finite(value))) stop("dims should be postive integers.") if (!identical( length(value), 2L)) stop("dims should be of length 2.") dimx <- x@dimension last <- value[1]+1 # In three steps: # 1) Address col truncation # to safe time, we also take into account if we have fewer or equal rows # 2) Augment rows # 3) if fewer rows and more columns, truncate # In any case, dimensions are fixed at the end. # If fewer cols required, we run reducedim if (dimx[2]>value[2]){ # subroutine reducedim(a,ja,ia,eps,bnrow,bncol,k,b,jb,ib) if( force64 || .format.spam(x)$package == "spam64") SS <- .format64() else SS <- .format32 z <- .C64("reducedim", SIGNATURE=c("double", SS$signature, SS$signature, "double", SS$signature, SS$signature, SS$signature, "double", SS$signature, SS$signature), oldra = x@entries, oldja = x@colindices, oldia = x@rowpointers, eps = getOption("spam.eps"), min(value[1],dimx[1]), value[2], nz = 1, entries=vector_dc("double",length(x@entries)), colindices=vector_dc(SS$type,length(x@entries)), rowpointers=vector_dc(SS$type,last), INTENT=c("r", "r", "r", "r", "r", "r", "w", "w", "w", "w"), NAOK = getOption("spam.NAOK"), PACKAGE = SS$package) if (z$nz==1 ){ #was identical( z$nz,1L) ## print("2") return( .newSpam( # entries=x@entries, # colindices=x@colindices, # rowpointers=c(1,rep_len64(2,value[1])), dimension=value, force64=force64 ) ) } nz <- z$nz-1 x <- .newSpam( entries=z$entries[1:nz], colindices=z$colindices[1:nz], rowpointers=z$rowpointers[1:min(last,dimx[1]+1)], dimension=value, #actually here dim 2 = value 2 but dim1 maybe not yet force64=force64 ) } # augment rows if (dimx[1]=value[1])&(dimx[2]<=value[2])) { ## added =, think about it again ## print("4") lastelement <- (x@rowpointers[last]-1) x <- .newSpam( entries= x@entries[1:lastelement], colindices= x@colindices[1:lastelement], rowpointers= x@rowpointers[1:last], dimension=value, force64=force64 ) } #before dim x = value x was here with slot option return(x) } setMethod("dim", "spam", function(x) x@dimension ) setMethod("dim<-", "spam", get("dim<-.spam")) setGeneric("pad<-", function(x, value) standardGeneric("pad<-")) setMethod("pad<-", "spam", get("pad<-.spam")) setMethod("pad<-", "matrix", function(x, value) { if (!identical( length(value), 2L)) stop("dims should be of length 2.") tmp <- matrix(0, value) mr <- 1:min(value[1], dim(x)[1]) mc <- 1:min(value[2], dim(x)[2]) tmp[mr,mc] <- x[mr,mc] return(tmp) }) spam/R/xybind.R0000644000176200001440000002064313536451710013045 0ustar liggesusers# HEADER #################################################### # This is file spam/R/xybind.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ ######################################################################## "rbind.spam" <- function(...,deparse.level=0) { if (deparse.level!=0) warning("Only 'deparse.level=0' implemented, coerced to zero,") addnargs <- ifelse(missing(deparse.level),0,1) nargs <- nargs()-addnargs if (nargs == 0) return( NULL) args <- list(...) if (!is.null( names( args))) { warning("Names of arguments are ignored") names( args) <- NULL } args[which(sapply(args, is.null))] <- NULL # nargs needs an update nargs <- length(args) - addnargs if (nargs == 0) return( NULL) if (nargs == 1) return( args[[1]]) if (nargs == 2) { # we distinguish between the cases: # 1 spam, spam # 2 spam, numeric (scalar, vector, matrix) # 3 numeric, spam # 4 numeric, numeric # Case 1: this is the quick way if( is.spam(args[[1]]) & is.spam(args[[2]])) { if(ncol(args[[1]])!=ncol(args[[2]])) stop("Arguments have differing numbers of columns, in rbind.spam()",call.=FALSE) nrow1 <- args[[1]]@dimension[1] newx <- new("spam") newx@entries <- c(args[[1]]@entries, args[[2]]@entries) newx@colindices <- c(args[[1]]@colindices, args[[2]]@colindices) newx@rowpointers <- c(args[[1]]@rowpointers, args[[2]]@rowpointers[-1]+args[[1]]@rowpointers[nrow1+1]-as.integer(1)) newx@dimension <- c(nrow1+args[[2]]@dimension[1],args[[1]]@dimension[2]) return(newx) } # Case 2: spam, numeric (scalar, vector, matrix) # if scalar, coherce it first to vector of appropriate length, # if vector, attach dimension. if( is.spam(args[[1]]) & is.numeric(args[[2]])) { Xdim <- args[[1]]@dimension Ylen <- length(args[[2]]) if (Ylen==1) { Xlen <- Xdim[2] args[[2]] <- rep( args[[2]], Xlen) dim( args[[2]]) <- c(1,Ylen) } else if (is.vector(args[[2]])) dim(args[[2]]) <- if( Xdim[1]==1) c(Ylen,1) else c(1,Ylen) Ydim <- dim(args[[2]]) if(Xdim[2]!=Ydim[2]) stop("Arguments have differing numbers of columns, in rbind.spam()",call.=FALSE) newx <- new("spam") newx@entries <- c(args[[1]]@entries, as.double(t(args[[2]]))) newx@colindices <- c(args[[1]]@colindices, rep.int(as.integer(1:Ydim[2]),Ydim[1])) newx@rowpointers <- c(args[[1]]@rowpointers, seq.int(args[[1]]@rowpointers[Xdim[1]+1], by=Ydim[2], length.out=Ydim[1]+1)[-1]) newx@dimension <- c(Xdim[1]+Ydim[1],Ydim[2]) return(newx) } # Case 3: numeric (scalar, vector, matrix), spam # similar as above if( is.numeric(args[[1]]) & is.spam(args[[2]])) { Xlen <- length( args[[1]]) Ydim <- args[[2]]@dimension if (Xlen==1) { Xlen <- Ydim[2] args[[1]] <- rep( args[[1]], Xlen) dim( args[[1]]) <- c(1,Xlen) } else if (is.vector(args[[1]])) dim(args[[1]]) <- if ( Ydim[1]==1) c(Xlen,1) else c(1,Xlen) Xdim <- dim(args[[1]]) if(ncol(args[[2]])!=Xdim[2]) stop("Arguments have differing numbers of columns, in rbind.spam()",call.=FALSE) newx <- new("spam") newx@entries <- c(as.double(t(args[[1]])), args[[2]]@entries ) newx@colindices <- c(rep.int(as.integer(1:Xdim[2]),Xdim[1]), args[[2]]@colindices) newx@rowpointers <- c(seq.int(1, by=Xdim[2], length.out=Xdim[1]), args[[2]]@rowpointers + Xlen) newx@dimension <- c(Ydim[1]+Xdim[1],Ydim[2]) return(newx) } # Case 4: numeric,numeric # result is a cleaned spam object. if( is.numeric(args[[1]]) & is.numeric(args[[2]])) return( as.spam.matrix( rbind(args[[1]],args[[2]])) ) stop("Not all argument are of class 'spam' and 'numeric', in rbind.spam()", call.=FALSE) } else { # "recursive" approach only, e.g. no checking tmp <- rbind.spam( args[[1]],args[[2]]) for ( i in 3:nargs) tmp <- rbind.spam( tmp,args[[i]]) return( tmp) } } cbind.spam <- function(..., deparse.level=0) { force64 <- getOption("spam.force64") if (deparse.level!=0) warning("Only 'deparse.level=0' implemented, coerced to zero,") addnargs <- ifelse(missing(deparse.level),0,1) nargs <- nargs()-addnargs if (nargs == 0) return( NULL) args <- list(...) if (!is.null( names( args))) { warning("Names of arguments are ignored") names( args) <- NULL } args[which(sapply(args, is.null))] <- NULL nargs <- length(args) - addnargs if (nargs == 0) return( NULL) if (nargs == 1) return( args[[1]]) if (nargs == 2) { Ydim <- if (is.spam(args[[2]])) args[[2]]@dimension else dim(args[[2]]) if (is.numeric(args[[1]])) { # we do _not_ have a spam object if (is.vector(args[[1]])) { if (is.null(Ydim)) { # if Ydim is NULL, then Y is a vector as well and we need special treatment. args[[1]] <- spam.numeric( args[[1]], max( length(args[[1]]),length(args[[2]]))) } else { # "standard" case, a vector (scalar) with a matrix args[[1]] <- spam.numeric( args[[1]], Ydim[1]) # scalar } } else { # we have a regular matrix args[[1]] <- as.spam.matrix(args[[1]]) } } else if (!is.spam(args[[1]])) { # we have anything stop("Not all argument are of class 'spam' and 'numeric', in cbind.spam()", call.=FALSE) } Xdim <- args[[1]]@dimension # now, X=args[[1]] is a spam, the treatment of Y is easier: if (is.numeric(args[[2]])) { # we do _not_ have a spam object if (is.vector(args[[2]])) args[[2]] <- spam.numeric( args[[2]], Xdim[1]) else args[[2]] <- as.spam.matrix(args[[2]]) } else if (!is.spam(args[[2]])) { stop("Not all argument are of class 'spam' and 'numeric', in cbind.spam()", call.=FALSE) } Ydim <- args[[2]]@dimension if(Xdim[1]!=Ydim[1]) stop("Arguments have differing numbers of rows, in cbind.spam()",call.=FALSE) XYlen <- as.numeric(args[[1]]@rowpointers[Xdim[1]+1])+as.numeric(args[[2]]@rowpointers[Xdim[1]+1])-2 if(force64 || XYlen > 2147483647 || .format.spam(args[[1]])$package =="spam64" || .format.spam(args[[2]])$package =="spam64") SS <- .format64() else SS <- .format32 #xncol,nrow,yncol, clen, #a,ia,ja, b,ib,jb, c,ic,jc z <- .C64("cbindf", SIGNATURE=c(SS$signature, SS$signature, "double", SS$signature, SS$signature, "double", SS$signature, SS$signature, "double", SS$signature, SS$signature), xncol=Xdim[2], nrow=Xdim[1], a=args[[1]]@entries, ia=args[[1]]@colindices, ja=args[[1]]@rowpointers, b=args[[2]]@entries, ib=args[[2]]@colindices, jb=args[[2]]@rowpointers, entries=vector_dc("double", XYlen), colindices=vector_dc(SS$type, XYlen), rowpointers=vector_dc(SS$type, Xdim[1]+1), INTENT=c("r", "r", "r", "r", "r", "r", "r", "r", "w", "w", "w"), NAOK = getOption("spam.NAOK"), PACKAGE = SS$package) return(.newSpam( entries=z$entries, colindices=z$colindices, rowpointers=z$rowpointers, dimension=c(Xdim[1], as.numeric(Xdim[2]) + as.numeric(Ydim[2])), force64=force64)) } else { ## "recursive" approach only tmp <- cbind.spam(args[[1]], args[[2]]) for(i in 3:nargs) tmp <- cbind.spam(tmp, args[[i]]) return(tmp) } } setMethod("rbind","spam",rbind.spam) setMethod("cbind","spam",cbind.spam) spam/R/eigen.R0000644000176200001440000003332513565753455012655 0ustar liggesusers# HEADER #################################################### # This is file spam/R/eigen.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ setMode <- function(sMode, symmetric, silent = FALSE){ if (symmetric) { modes <- c("LM", "SM", "LA", "SA") #,"BE") if (!(sMode %in% modes)) { sMode <- 'LM' if (!silent) { warning(paste("the control option \"mode\" is set to", sMode), call. = FALSE) } } } else { modes <- c("LR", "SR", "LI", "SI", "SM", "LM") if (!(sMode %in% modes)) { sMode <- 'LR' if(!silent) { warning(paste("the control option \"mode\" is set to", sMode), call. = FALSE) } } } if (sMode == 'LM') { imode <- as.integer(1) } if (sMode == 'SM') { imode <- as.integer(2) } if (sMode == 'LR') { imode <- as.integer(3) } if (sMode == 'SR') { imode <- as.integer(4) } if (sMode == 'LI') { imode <- as.integer(5) } if (sMode == 'SI') { imode <- as.integer(6) } if (sMode == 'LA') { imode <- as.integer(7) } if (sMode == 'SA') { imode <- as.integer(8) } if (sMode == 'BE') { imode <- as.integer(9) } return(imode) } mk_cmplxentries <- function(z) { if (dim(z)[2] != 2) stop("wrong format from fortran return: dn_eigen_f") cmplx <- NULL cmplx <- sapply(1:length(z[ , 1]), function(x) { complex(real = z[x, 1], imaginary = z[x, 2]) }) if (is.null(cmplx)) stop("error while aggregating fortran return from two vectors to a complex") return(cmplx) } getEigenval <- function(values, mode, dim, nEig, symmetric){ if (symmetric) { result <- rep(NA, dim) orderedInd <- order(values[1:nEig], decreasing = TRUE) values <- values[orderedInd] # sort works also for complex values if (identical(mode %% 2, 0)) { # even modes are SA, SM, SR, SI result[(dim - nEig + 1):dim] <- values } else { # odd modes are LA, LA, LR, LI result[1:nEig] <- values } } else { result <- matrix(NA, nrow = dim, ncol = 2) orderedInd <- order(values[1:nEig, 1], decreasing = TRUE) values <- values[orderedInd, ] if (identical(mode %% 2, 0)) { result[(dim - nEig + 1):dim, ] <- values } else { result[1:nEig, ] <- values } result <- mk_cmplxentries(result) } return(list("eigenvalues" = result , "order" = orderedInd)) } getEigenvec <- function(v, sym, dimen, nEig, orderind, eigenvalues, cmplxeps){ if (is.null(v)) stop("fortran returned NULL eigenvectors") if (sym) { v <- matrix(v, nrow = dimen, ncol = nEig, byrow = FALSE) v <- v[ , orderind, drop = FALSE] } else { v <- matrix(v[1:(dimen*nEig*2)], nrow = dimen, ncol = nEig*2, byrow = FALSE) v_real <- v[ , seq(1, nEig*2, by = 2)] v_imag <- v[ , seq(2, nEig*2, by = 2)] v_real <- v_real[ , orderind, drop = FALSE] v_imag <- v_imag[ , orderind, drop = FALSE] rm(v) eigenvalues <- stats::na.omit(eigenvalues) v <- matrix(NA, nrow = dimen, ncol = nEig) v <- sapply(1:nEig, function(x) { if (abs(Im(eigenvalues[x])) > cmplxeps) { mk_cmplxentries(cbind(v_real[ , x], v_imag[ , x])) } else { mk_cmplxentries(cbind(v_real[ , x], base::rep.int(0, times = dimen))) } }) } return(v) } eigen_approx <- function(x, nev, ncv, nitr, mode, only.values = FALSE, verbose = FALSE, f_routine){ # check & parse arguments if (x@dimension[1] <= nev) stop("nev: the number of eigenvalues to calculate must be smaller than the matrix dimensions", call. = TRUE) if (f_routine != "ds_eigen_f" && f_routine != "dn_eigen_f") stop("non valid fortran routine is specified", call. = TRUE) f_mode <- setMode(sMode = mode, symmetric = ifelse(identical(f_routine, "ds_eigen_f"), TRUE, FALSE)) fortran_object <- result <- list(NULL) if(getOption("spam.force64") || .format.spam(x)$package != "spam") { SS <- .format64() f_routine <- paste0(f_routine, "64") } else { SS <- .format32 } # Fortran call: symmetric matrices if (identical(f_routine, "ds_eigen_f") || identical(f_routine, "ds_eigen_f64")) { # define upperbound for matrices in spam64, since ARPACK routines rely on BLAS/LAPACK functions # which have no integer/logical's of kind = 8 if (max(x@dimension[1], ncv*(ncv + 8))*3 >= 2^31-1) { stop("the dimension and of the input matrix and/or the required number of eigenvalues is too large for the current eigenvalue decomposition implementation.\n Reducing the argument \"nev\" and\"ncv\" in the contorl options may helps.") } fortran_object <- .C64 (f_routine, SIGNATURE = c("integer", "integer", "integer", "integer", "integer", "integer", "double", SS$signature, SS$signature, "double", "double", "integer"), maxnev = nev, ncv = ncv, maxitr = nitr, n = x@dimension[1], iwhich = f_mode, na = x@dimension[1], a = x@entries, ja = x@colindices, ia = x@rowpointers, v = vector_dc("double", x@dimension[1]*ncv), d = vector_dc("double", nev), iparam = integer_dc(8), INTENT = c("r", "r", "r", "r", "r", "r", "r", "r", "r", "rw", "rw", "rw"), NAOK = getOption("spam.NAOK"), PACKAGE = SS$package) if (is.null(fortran_object)) { stop("error while calling fortran routine, check (control) arguments", call. = TRUE) } result <- list ("nEigenVal" = nev, "Mode" = f_mode, "Eigenvectors" = if (!only.values) { fortran_object$v[1:(x@dimension[1]*nev)] } else { NULL }, "Eigenvalues" = fortran_object$d, "nconv" = fortran_object$iparam[5]) } # Fortran call: nonsymmetric matrices if (identical(f_routine, "dn_eigen_f") || identical(f_routine, "dn_eigen_f64")) { if (max(x@dimension[1], ncv^2+6*ncv)*3 >= 2^31-1) { stop("the dimension and of the input matrix and/or the required number of eigenvalues is too large for the current eigenvalue decomposition implementation.\n Reducing the argument \"nev\" and\"ncv\" in the contorl options may helps.") } fortran_object <- .C64 (f_routine, SIGNATURE = c("integer", "integer", "integer", "integer", "integer", "integer", "double", SS$signature, SS$signature, "double", "double", "double", "integer"), maxnev = nev, ncv = ncv, maxitr = nitr, n = x@dimension[1], iwhich = f_mode, na = x@dimension[1], a = x@entries, ja = x@colindices, ia = x@rowpointers, v = vector_dc("double", x@dimension[1]*ncv), dr = vector_dc("double", nev), di = vector_dc("double", nev), iparam = integer_dc(8), INTENT = c("r", "r", "r", "r", "r", "r", "r", "r", "r", "rw", "rw", "rw", "rw"), NAOK = getOption("spam.NAOK"), PACKAGE = SS$package) if (is.null(fortran_object)) { stop("error while calling fortran routine, check (control) arguments", call. = TRUE) } result <- list ("nEigenVal" = nev, "Mode" = f_mode, "Eigenvectors" = if (!only.values) { fortran_object$v[1:(x@dimension[1]*nev*2)] } else { NULL }, "Eigenvalues" = cbind(fortran_object$dr, fortran_object$di), "nconv" = fortran_object$iparam[5]) } if (verbose) { cat("\n used options/arguments:") if (identical(f_routine, "dn_eigen_f") || identical(f_routine, "dn_eigen_f64")) { issym <- "non symmetric" } else { issym <- "symmetric" } cat(paste("\n FORTRAN routine:", issym, "matrices")) cat(paste("\n nitr:", nitr)) cat(paste("\n ncv:", ncv, "\n")) cat("\n summary FORTRAN return:") cat(paste("\n ", nev, "eigenvalues requested and", result$nconv, "converged\n")) } if (result$nconv < nev) warning(paste("\n only", result$nconv, "instead of", nev ,"eigenvalues converged, try to increase 'control = list(nitr = .., ncv = ..)'"), call. = TRUE) if (is.null(result)) { stop("unpredicted error, check control options of the eigen.spam function.", call. = TRUE) } return(result) } eigen.spam <- function (x, nev = 10, symmetric, only.values = FALSE, control = list()){ con <- list(mode = 'LM', nitr = NULL, ncv = NULL, spamflag = FALSE, verbose = FALSE, cmplxeps = .Machine$double.eps) nmsC <- names(con) con[(namc <- names(control))] <- control if (length(noNms <- namc[!namc %in% nmsC])) warning("unknown names in control: ", paste(noNms, collapse = ", "), call. = TRUE) ifelse(!con$verbose, vFlag <- FALSE, vFlag <- TRUE) # arpack routines cant handle 'small' matrices minDimARPACK <- 100 resContainer <- list(NULL) if (!is.spam(x)) { try(x <- as.spam(x)) } if (missing(symmetric)){ symmetric <- isSymmetric.spam(x) } else { if (!identical(symmetric, isSymmetric.spam(x))) { warning(paste("the input matrix is", ifelse(isSymmetric.spam(x), "symmetric", "not symmetric")), call. = TRUE) } } ## dispatching between base::eigen and ARPACK if ((!con$spamflag && prod(dim(x)) <= getOption("spam.inefficiencywarning")) || (con$spamflag && prod(dim(x)) <= minDimARPACK)) { warning("\n The eigenvalues are calculated with the function 'eigen' from the base package.", call. = TRUE) if (con$spamflag) { warning(paste("\n Even 'spamflag = TRUE', since the matrix dimension is smaller than", minDimARPACK), call. = TRUE) } resContainer <- base::eigen(x = x, symmetric = symmetric, only.values = only.values) resEig <- resContainer$values resVec <- resContainer$vectors } else { # --- using ARPACK -------------------------------------------------------------- # if (!identical(x@dimension[1], x@dimension[2])) stop("non-square matrix in 'eigen'") if (nev >= x@dimension[1] || nev <= 0) stop ("the number of asked eigenvalues is higher or equal the dimension of the input matrix") if (symmetric) { ncvMaxMin <- 100 } else { ncvMaxMin <- 100 } if (con$ncv > x@dimension[1] || con$ncv < nev || is.null(con$ncv)) { con$ncv <- min(x@dimension[1] + 1, max(2 * nev + 1, ncvMaxMin)) } if (is.null(con$nitr)) { con$nitr <- con$ncv + 1000 } # calculate eigenvalues and vectors resContainer <- eigen_approx(x = x, nev = nev, ncv = con$ncv, nitr = con$nitr, mode = con$mode, only.values = only.values, verbose = vFlag, f_routine = ifelse(symmetric, "ds_eigen_f", "dn_eigen_f")) if (is.null(resContainer)) { stop("\n FORTRAN return is empty") } tmpresEig <- getEigenval(values = resContainer$Eigenvalues, mode = setMode(con$mode, symmetric, silent = TRUE), dim = x@dimension[1], nEig = if (resContainer$nconv > nev) { nev } else { resContainer$nconv }, symmetric = symmetric) resEig <- tmpresEig$eigenvalues resVec <- NULL if(!only.values) { resVec <- getEigenvec(v = resContainer$Eigenvectors, sym = symmetric, dimen = x@dimension[1], nEig = if (resContainer$nconv > nev) { nev } else { resContainer$nconv }, orderind = tmpresEig$order, eigenvalues = resEig, cmplxeps = con$cmplxeps) } # ------------------------------------------------------------------------------- # } return (list("values" = resEig, "vectors" = resVec)) } spam/R/math.R0000644000176200001440000006377413536451707012523 0ustar liggesusers# HEADER #################################################### # This is file spam/R/math.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ # `"Ops"": # `"+"", `"-"", `"*"", `"/"", `"^"", `"%%"", `"%/%"" # `"&"", `"|"", `"!"" # `"=="", `"!="", `"<"", `"<="", `">="", `">"" # `Math" `"abs"", `"sign"", `"sqrt"", `"ceiling"", `"floor"", # `"trunc"", `"cummax"", `"cummin"", `"cumprod"", `"cumsum"", # `"log"", `"log10"", `"log2"", `"log1p"", `"acos"", `"acosh"", # `"asin"", `"asinh"", `"atan"", `"atanh"", `"exp"", `"expm1"", # `"cos"", `"cosh"", `"cospi"", `"sin"", `"sinh"", `"sinpi"", # `"tan"", `"tanh"", `"tanpi"", `"gamma"", `"lgamma"", # `"digamma"", `"trigamma"" # `Math2" `"round"", `"signif"" # `Summary" `"max"", `"min"", `"range"", `"prod"", `"sum"", `"any"", `"all"" ############## # Unary operators "+", "-" and "!" are handled with e2 missing... # # Currently, "+", "-" are handled... setMethod("!",signature(x="spam"), function(x){ if(getOption("spam.structurebased")) { x@entries <- as.double(callGeneric(x@entries)) x } else { inefficiencywarning( gettextf("This %s operation may be inefficient",sQuote(.Generic)), prod(dim(x))) spam(as.double( callGeneric(as.matrix(x))), nrow=dim(x)[1]) } }) setMethod("+",signature(e1="spam",e2="missing"), function(e1) e1 ) setMethod("-",signature(e1="spam",e2="missing"), function(e1) { e1@entries <- -e1@entries; e1} ) # `Math2" : setMethod("Math2",signature(x = "spam", digits = "ANY"), function(x, digits){ x@entries <- callGeneric(x@entries, digits = digits); x }) # `Math" : setMethod("Math","spam", function(x){ if(getOption("spam.structurebased")) { x@entries <- callGeneric(x@entries) x }else{ x@entries <- callGeneric(x@entries) as.spam.spam( x) } }) # `Math", where we pass to matrix first... spam_Math <- function(x) { if(getOption("spam.structurebased")) { x@entries <- callGeneric(x@entries) x }else{ inefficiencywarning( gettextf("This %s operation may be inefficient",sQuote(.Generic)), prod(dim(x))) as.spam(callGeneric(as.matrix(x))) }} setMethod("exp","spam", spam_Math ) setMethod("log10","spam", spam_Math ) setMethod("log2","spam", spam_Math ) # from ?log: Do not set S4 methods on `logb" itself. # special case to set base... setMethod("log","spam", function(x,...) { if(getOption("spam.structurebased")) { x@entries <- callGeneric(x@entries,...) x }else{ inefficiencywarning( gettextf("This %s operation may be inefficient",sQuote(.Generic)), prod(dim(x))) as.spam(callGeneric(as.matrix(x),...)) }} ) setMethod("cos","spam", spam_Math ) #setMethod("cospi","spam", spam_Math ) setMethod("cosh","spam", spam_Math ) setMethod("acosh","spam", spam_Math ) setMethod("acos","spam", spam_Math ) setMethod("gamma","spam", spam_Math ) setMethod("digamma","spam", spam_Math ) setMethod("trigamma","spam", spam_Math ) setMethod("lgamma","spam", spam_Math ) setMethod("cummax","spam", spam_Math ) setMethod("cummin","spam", spam_Math ) setMethod("cumprod","spam", spam_Math ) setMethod("cumsum","spam", spam_Math ) # `Summary" : setMethod("Summary","spam", function(x,...,na.rm=FALSE){ if(getOption("spam.structurebased")) { callGeneric(x@entries,...,na.rm=na.rm) }else{ if ( prod( x@dimension) == length( x@entries)) { callGeneric(x@entries,...,na.rm=na.rm) } else { callGeneric(c(0,x@entries),...,na.rm=na.rm) } } } ) logical_Summary <- function( x,...,na.rm=FALSE){ if(getOption("spam.structurebased")) { callGeneric(as.logical(x@entries),...,na.rm=na.rm) }else{ if ( prod( x@dimension) == length( x@entries)) { callGeneric(as.logical(x@entries),...,na.rm=na.rm) } else { callGeneric(as.logical(c(0,x@entries)),...,na.rm=na.rm) } } } setMethod("any","spam", logical_Summary) setMethod("all","spam", logical_Summary) ################################################################################################################################################################################################################################################################################################ # `Ops" `"Arith"", `"Compare"", `"Logic"" # `Logic" `"&"", `"|"". "spam_Logic_vectorspam" <- function(e1, e2) { if(getOption("spam.structurebased")) { if(identical(length(e1),1L) | identical(length(e1), length(e2@entries))) { e2@entries <- as.double( callGeneric(e1, e2@entries)) return(e2) } if( length(e1) == prod(e2@dimension)) return( as.spam( callGeneric(e1, as.matrix(e2))) ) stop(gettextf("incompatible lengths for %s operation.", sQuote(.Generic))) } else { inefficiencywarning( gettextf("This %s operation may be inefficient",sQuote(.Generic)), prod(dim(e2))) return( as.spam( callGeneric(e1, as.matrix(e2))) ) } } "spam_Logic_spamvector" <- function(e1, e2) { if(getOption("spam.structurebased")) { if(identical(length(e2),1L) | identical(length(e2), length(e1@entries))) { e1@entries <- as.double( callGeneric(e1@entries, e2)) return(e1) } if( length(e2)== prod(e1@dimension)) return( as.spam( callGeneric(as.matrix(e1), e2)) ) stop(gettextf("incompatible lengths for %s operation.", sQuote(.Generic))) } else { inefficiencywarning( gettextf("This %s operation may be inefficient",sQuote(.Generic)), prod(dim(e1))) return( as.spam( callGeneric(as.matrix(e1), e2)) ) } } setMethod("|",signature(e1="spam",e2="spam"), function(e1,e2){ z <- spam_add(e1,e2);z@entries <- rep(1,length(z@colindices));z}) setMethod("&",signature(e1="spam",e2="spam"), function(e1,e2){ z <- spam_mult(e1,e2); z@entries <- rep(1,length(z@colindices));z}) setMethod("Logic",signature(e1="spam",e2="vector"), spam_Logic_spamvector) setMethod("Logic",signature(e1="vector",e2="spam"), spam_Logic_vectorspam) ################################################################################################## # `Compare" `"=="", `">"", `"<"", `"!="", `"<="", `">="" "spam_Compare" <- function(e1,e2) { inefficiencywarning( gettextf("This %s operation may be inefficient",sQuote(.Generic)), max(prod(dim(e1)), prod(dim(e2)))) as.spam( callGeneric( as.matrix(e1), as.matrix(e2)) ) } "spam_Compare_spamvector" <- function(e1, e2){ if(getOption("spam.structurebased")) { if(identical(length(e2),1L) | identical(length(e2), length(e1@entries))) { e1@entries <- as.double(callGeneric(e1@entries, e2)) return(e1) } if( length(e2)== prod(e1@dimension)) return( as.spam( callGeneric(as.matrix(e1), e2)) ) stop(gettextf("incompatible lengths for %s operation.", sQuote(.Generic))) } else { inefficiencywarning( gettextf("This %s operation may be inefficient",sQuote(.Generic)), prod(dim(e1))) return( as.spam( callGeneric(as.matrix(e1), e2)) ) } } "spam_Compare_vectorspam" <- function(e1, e2) { if(getOption("spam.structurebased")) { if(identical(length(e1),1L) | identical(length(e1), length(e2@entries))) { e2@entries <- as.double( callGeneric(e1, e2@entries)) return(e2) } if( length(e1) == prod(e2@dimension)) return( as.spam( callGeneric(e1, as.matrix(e2))) ) stop(gettextf("incompatible lengths for %s operation.", sQuote(.Generic))) } else { inefficiencywarning( gettextf("This %s operation may be inefficient",sQuote(.Generic)), prod(dim(e2))) return( as.spam( callGeneric(e1, as.matrix(e2))) ) } } setMethod("Compare",signature(e1="spam",e2="spam"), spam_Compare ) setMethod("Compare",signature(e1="spam",e2="vector"), spam_Compare_spamvector ) setMethod("Compare",signature(e1="vector",e2="spam"), spam_Compare_vectorspam ) ################################################################################################## # `Arith": `"+"", `"-"", `"*"", `"^"", `"%%"", `"%/%"", `"/"" "spam_Arith_vectorspam" <- function(e1, e2){ # cat("spam_Arith_vectorspam") if(getOption("spam.structurebased")) { if(identical(length(e1),1L) | identical(length(e1), length(e2@entries))) { e2@entries <- callGeneric(e1, e2@entries) return(e2) } if( length(e1) == prod(e2@dimension)) return( as.spam( callGeneric(e1, as.matrix(e2))) ) stop(gettextf("incompatible lengths for %s operation.", sQuote(.Generic))) } else { inefficiencywarning( gettextf("This %s operation may be inefficient",sQuote(.Generic)), prod(dim(e1))) return( as.spam( callGeneric(e1, as.matrix(e2))) ) } } "spam_Arith_spamvector" <- function(e1, e2){ # cat("spam_Arith_spamvector") if(getOption("spam.structurebased")) { if(identical(length(e2),1L) | identical(length(e2), length(e1@entries))) { e1@entries <- callGeneric(e1@entries, e2) return(e1) } if( length(e2)== prod(e1@dimension)) return( as.spam( callGeneric(as.matrix(e1), e2)) ) stop(gettextf("incompatible lengths for %s operation.", sQuote(.Generic))) } else { inefficiencywarning( gettextf("This %s operation may be inefficient",sQuote(.Generic)), prod(dim(e1))) return( as.spam( callGeneric(as.matrix(e1), e2)) ) } } spam_Arith <- function(e1,e2) { inefficiencywarning( gettextf("This %s operation may be inefficient",sQuote(.Generic)), max(prod(dim(e1)), prod(dim(e2)))) as.spam( callGeneric( as.matrix(e1), as.matrix(e2))) } setMethod("Arith",signature(e1="spam",e2="spam"), spam_Arith ) setMethod("Arith",signature(e1="spam",e2="vector"), spam_Arith_spamvector) setMethod("Arith",signature(e1="vector",e2="spam"), spam_Arith_vectorspam) setMethod("/",signature(e1="spam",e2="spam"), function(e1,e2){ "/"(e1,as.matrix(e2)) } ) setMethod("^",signature(e1="spam",e2="spam"), function(e1,e2){ "^"(e1,as.matrix(e2)) } ) ###################################################################### # nz <- 128; ln <- nz^2; A <- spam(0,ln,ln); is <- sample(ln,nz); js <- sample(ln,nz);A[cbind(is,js)] <- 1:nz # nz <- 128; ln <- nz^2; A <- spam(0,ln,ln); is <- sample(ln,ln); js <- sample(ln,ln);A[cbind(is,js)] <- 1:ln # system.time( spam:::.spam.addsparsefull(A,1)) ; system.time( as.matrix.spam(A)+1.5) ####################################################################### "spam_add" <- function(A, B, s=1) { # cat("spam_add") nrow <- A@dimension[1] ncol <- A@dimension[2] if(ncol != B@dimension[2] || nrow != B@dimension[1]) stop("non-conformable matrices") if( getOption("spam.force64") || .format.spam(A)$package == "spam64" || .format.spam(B)$package == "spam64") SS <- .format64() else SS <- .format32 nzmax <- .C64("aplbdg", ## subroutine aplbdg (nrow,ncol,ja,ia,jb,ib,ndegr,nnz,iw) SIGNATURE = c(SS$signature, SS$signature, SS$signature, SS$signature, SS$signature, SS$signature, SS$signature, SS$signature, SS$signature), nrow, ncol, A@colindices, A@rowpointers, B@colindices, B@rowpointers, vector_dc(SS$type, nrow), nnz = vector_dc(SS$type, 1), vector_dc(SS$type, ncol), INTENT = c("r", "r", "r", "r", "r", "r", "w", "w", "w"), NAOK=getOption("spam.NAOK"), PACKAGE = SS$package)$nnz z <- .C64("aplsb1", ## subroutine aplsb1 (nrow,ncol,a,ja,ia,s,b,jb,ib,c,jc,ic,nzmax,ierr) SIGNATURE = c(SS$signature, SS$signature, "double", SS$signature, SS$signature, "double", "double", SS$signature, SS$signature, "double", SS$signature, SS$signature, SS$signature, SS$signature), nrow, ncol, A@entries, A@colindices, A@rowpointers, s, B@entries, B@colindices, B@rowpointers, entries = vector_dc("double", nzmax), colindices = vector_dc(SS$type, nzmax), rowpointers = vector_dc(SS$type, nrow+1), nzmax+1, ierr = vector_dc(SS$type, 1), INTENT = c("r", "r", "r", "r", "r", "r", "r", "r", "r", "w", "w", "w", "r", "w" ), NAOK=getOption("spam.NAOK"), PACKAGE = SS$package) if(z$ierr != 0) stop("insufficient space for sparse matrix addition") nz <- z$rowpointers[nrow+1]-1 return(.newSpam( entries = z$entries[1:nz], colindices = z$colindices[1:nz], rowpointers = z$rowpointers, dimension = c(nrow,ncol) )) } setMethod("+",signature(e1="spam",e2="spam"), function(e1,e2){ spam_add(e1, e2) }) setMethod("-",signature(e1="spam",e2="spam"), function(e1,e2){ spam_add(e1, e2, -1)}) ############################################################################### "spam_mult" <- function(e1,e2) { # if(is.vector(e1)) { # if(length(e1) == 1){ # if(e1==0) return( spam(0,nrow(e2),ncol(e2))) # else{ # just a scalar # e2@entries <- e1*e2@entries # return(e2) # } # } else if(length(e1) == nrow(e2)) # return(diag.spam(e1) %*% e2) # else # length(e1) == ncol(e2) is not required # stop("e1 and e2 not conformable for efficient element-by-element multiplication") # } # else if(is.vector(e2)) { # if(length(e2) == 1){ # if(e2==0) return( spam(0,nrow(e1),ncol(e1))) # else { # e1@entries <- e2*e1@entries # return(e1) # } # } # else if(length(e2) == nrow(e1)) # return(diag.spam(e2) %*% e1) # else # stop("e1 and e2 not conformable for efficient element-by-element multiplication") # } # if(is.matrix(e1)) # e1 <- as.spam(e1) # else if(is.matrix(e2)) # e2 <- as.spam(e2) # if(!(is.spam(e1) && is.spam(e2))) # stop("Arguments must be of class: vector, matrix or spam") e1row <- e1@dimension[1] e1col <- e1@dimension[2] if(e1col != e2@dimension[2] | e1row != e2@dimension[1]) stop("non-conformable matrices") nnzmax <- length(intersect(e1@colindices+e1col*(rep(1:e1row,diff(e1@rowpointers))-1), e2@colindices+e2@dimension[2]*(rep(1:e2@dimension[1],diff(e2@rowpointers))-1)))+1 if( getOption("spam.force64") || .format.spam(e1)$package == "spam64" || .format.spam(e2)$package == "spam64") SS <- .format64() else SS <- .format32 z <- .C64("aemub", ## subroutine aemub (nrow,ncol,a,ja,ia,amask,jmask,imask, ## * c,jc,ic,nzmax,ierr) SIGNATURE = c(SS$signature, SS$signature, "double", SS$signature, SS$signature, "double", SS$signature, SS$signature, "double", SS$signature, SS$signature, SS$signature, SS$signature), e1row, e1col, e1@entries, e1@colindices, e1@rowpointers, e2@entries, e2@colindices, e2@rowpointers, entries = vector_dc("double", nnzmax), colindices = vector_dc(SS$type, nnzmax), rowpointers = vector_dc(SS$type, e1row+1), nnzmax, ierr = vector_dc(SS$type,1), INTENT = c("r","r", "r", "r", "r", "r", "r", "r", "w", "w", "w", "r", "w"), NAOK=getOption("spam.NAOK"), PACKAGE = SS$package) ## z <- .Fortran("aemub", ## as.integer(e1row), ## as.integer(e1col), ## as.double(e1@entries), as.integer(e1@colindices), as.integer(e1@rowpointers), ## as.double(e2@entries), as.integer(e2@colindices), as.integer(e2@rowpointers), ## entries = vector("double",nnzmax), ## colindices = vector("integer",nnzmax), ## rowpointers = vector("integer",e1row+1), ## ## integer(e1col), ## double(e1col), ## as.integer(nnzmax), ## ierr = vector("integer",1), ## NAOK=getOption("spam.NAOK"), PACKAGE = "spam") if(z$ierr != 0) stop("insufficient space for element-wise sparse matrix multiplication") nnz <- z$rowpointers[e1row+1]-1 if(identical(z$entries,0L)){#trap zero matrix z$colindices <- 1L z$rowpointers <- c(1L,rep(2L,e1row)) } return(.newSpam( entries=z$entries[1:nnz], colindices=z$colindices[1:nnz], rowpointers=z$rowpointers, dimension=c(e1row,e1col))) } setMethod("*",signature(e1="spam",e2="spam"), spam_mult) ########################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################## "matrix_add_spammatrix" <- function(A,B){ # cat("matrix_add_spammatrix") # A is sparse, B is full # if (missing(B)) return(A) # if (!is.numeric(B)) stop("numeric argument expected") nrow <- A@dimension[1] ncol <- A@dimension[2] pdim <- prod(nrow,ncol) # if (is.matrix(B)) { if(ncol != dim(B)[2] || nrow != dim(B)[1]) stop("non-conformable matrices") # } else { # if(pdim%%length(B)!=0) { # stop("longer object length # is not a multiple of shorter object length") # } else B <- rep(B,pdim %/% length(B)) # } ## print("addsparsefull") if( getOption("spam.force64") ) SS <- .format64() else SS <- .format.spam(A) return(array( .C64("addsparsefull", SIGNATURE = c(SS$signature, "double", SS$signature, SS$signature, "double"), nrow, A@entries, A@colindices, A@rowpointers, b = c(B), INTENT = c("r", "r", "r", "r", "rw"), NAOK=getOption("spam.NAOK"), PACKAGE = SS$package )$b, c(nrow,ncol))) } "matrix_sub_spammatrix" <- function(A,B){ # cat("matrix_sub_spammatrix") # A is sparse, B is full # if (missing(B)) { # A@entries <- -A@entries # return(A) # } # if (!is.numeric(B)) stop("numeric argument expected") nrow <- A@dimension[1] ncol <- A@dimension[2] # pdim <- prod(nrow,ncol) # if (is.matrix(B)) { if(ncol != dim(B)[2] || nrow != dim(B)[1]) stop("non-conformable matrices") # } else { # if(pdim %% length(B)!=0) { # stop("longer object length # is not a multiple of shorter object length") # } else B <- rep(B,pdim %/% length(B)) # } # if (!is.double(B[1])) B <- as.double(B) ## print("subfullsparse") if( getOption("spam.force64") ) SS <- .format64() else SS <- .format.spam(A) return(array( .C64("subfullsparse", SIGNATURE = c( SS$signature, SS$signature, "double", SS$signature, SS$signature, "double"), nrow, ncol, A@entries, A@colindices, A@rowpointers, b = c(B), INTENT = c("r", "r", "r", "r", "r", "rw"), NAOK=getOption("spam.NAOK"), PACKAGE = SS$package)$b, c(nrow,ncol))) } "matrix_sub_matrixspam" <- function(B,A){ # cat("matrix_sub_spammatrix") # A is sparse, B is full if (!is.numeric(B)) stop("numeric argument expected") nrow <- A@dimension[1] ncol <- A@dimension[2] # pdim <- prod(nrow,ncol) # if (is.matrix(B)) { if(ncol != dim(B)[2] || nrow != dim(B)[1]) stop("non-conformable matrices") # } else { # if(pdim %% length(B)!=0) { # stop("longer object length # is not a multiple of shorter object length") # } else B <- rep(B,pdim %/% length(B)) # } # if (!is.double(B[1])) B <- as.double(B) if( getOption("spam.force64") ) SS <- .format64() else SS <- .format.spam(A) return(array( .C64("subsparsefull", SIGNATURE = c(SS$signature, "double", SS$signature, SS$signature, "double"), nrow, A@entries, A@colindices, A@rowpointers, b = c(B), INTENT = c("r", "r", "r", "r", "rw"), NAOK=getOption("spam.NAOK"), PACKAGE = SS$package )$b, c(nrow,ncol))) } # setMethod("+",signature(e1="spam", e2="matrix"), function(e1,e2){ matrix_add_spammatrix(e1,e2)}) setMethod("+",signature(e1="matrix", e2="spam"), function(e1,e2){ matrix_add_spammatrix(e2,e1)}) setMethod("-",signature(e1="matrix", e2="spam"), function(e1,e2){ matrix_sub_matrixspam(e1,e2)}) setMethod("-",signature(e1="spam", e2="matrix"), function(e1,e2){ matrix_sub_spammatrix(e1,e2)}) #"spam_division" <- function(e1,e2) { # Element-wise matrix division of two spams # if(is.numeric(e1) && length(e1) == 1) # { e2@entries <- e1/e2@entries # return(e2) # } else if(is.numeric(e2) && length(e2) == 1) { # e1@entries <- e1@entries/e2 # return(e1) # } # else if(is.spam(e1) || is.spam(e2) || is.matrix(e1) || is.matrix(e2)){ # if(is.matrix(e1)) e1 <- as.spam(e1) # if(is.matrix(e2)) e2 <- as.spam(e2) # nrow <- e1@dimension[1] # ncol <- e1@dimension[2] # if(ncol != e2@dimension[2] | nrow != e2@dimension[1]) # stop("matrices not conformable for element-by-element division") # nzmax <- length(unique(c(e1@colindices+ncol*(rep(1:nrow,diff(e1@rowpointers))-1), # e2@colindices+e2@dimension[2]*(rep(1:e2@dimension[1],diff(e2@rowpointers))-1))))+1 # z <- .Fortran("_aedib_", # does not order the colindicies upon return! # nrow, # ncol, # as.integer(1), # as.double(e1@entries), e1@colindices, e1@rowpointers, # as.double(e2@entries), e2@colindices, e2@rowpointers, # entries = vector("double",nzmax), # colindices = vector("integer",nzmax), # rowpointers = vector("integer",nrow+1), # as.integer(nzmax), # integer(ncol), # double(ncol), # ierr = vector("integer",1), # NAOK=getOption("spam.NAOK"),PACKAGE = "spam" # ) # if(z$ierr != 0) stop("insufficient space for element-wise sparse matrix division") # nz <- z$rowpointers[nrow+1]-1 # return(new("spam",entries=z$entries[1:nz],colindices=z$colindices[1:nz],rowpointers=z$rowpointers, # dimension=c(nrow,ncol))) # } ##"spam_exponent" <- function(e1, e2) #{ # nrow <- e1@dimension[1] # ncol <- e1@dimension[2] # if(ncol != e2@dimension[2] | nrow != e2@dimension[1]) # stop("matrices not conformable for element-wise exponentiation ") # nzmax <- length(unique(c(e1@colindices+ncol*(rep(1:nrow,diff(e1@rowpointers))-1), # e2@colindices+e2@dimension[2]*(rep(1:e2@dimension[1],diff(e2@rowpointers))-1))))+1 # z <- .Fortran("_aeexpb_", does not reorder col indices! # as.integer(nrow), as.integer(ncol), # 1L, # as.double(e1@entries), as.integer(e1@colindices), as.integer(e1@rowpointers), # as.double(e2@entries), as.integer(e2@colindices), as.integer(e2@rowpointers), # entries = vector("double",nzmax), # colindices = vector("integer",nzmax), # rowpointers = vector("integer",nrow+1), # as.integer(nzmax), # integer(ncol), double(ncol), # ierr = vector("integer",1), # NAOK=getOption("spam.NAOK"),PACKAGE = "spam" # ) # if(z$ierr != 0) stop("insufficient space for element-wise exponentiation") # nz <- z$rowpointers[nrow+1]-1 # return(new("spam",entries=z$entries[1:nz],colindices=z$colindices[1:nz],rowpointers=z$rowpointers, # dimension=c(nrow,ncol))) #} ############################# #getClass("numeric") # Extends: "vector" #getClass("matrix") #Extends: Class "vector", by class "array", distance 3, with explicit coerce # Hence we use use vector, especially, to include the NA case that is not of type numeric! spam/R/helper.R0000644000176200001440000003714713536451707013044 0ustar liggesusers# HEADER #################################################### # This is file spam/R/helper.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ ######################################################################## ######################################################################## # a few nice helper functions: bandwidth <- function(A) { if (!is.spam(A)) { warning("Matrix not 'spam' object. Coerced to one") A <- as.spam(A) } if( getOption("spam.force64") ) SS <- .format64() else SS <- .format.spam(A) ret <- .C64("getbwd", SIGNATURE = c( SS$signature, SS$signature, SS$signature, SS$signature, SS$signature), A@dimension[1], A@colindices, A@rowpointers, low = vector_dc(SS$type, 1), upp = vector_dc(SS$type, 1), INTENT = c("r", "r", "r", "w", "w"), NAOK = getOption("spam.NAOK"), PACKAGE = SS$package) return(c(ret$low,ret$upp)) } bdiag.spam <- function(...){ nargs <- nargs() if (nargs == 0) return( NULL) args <- list(...) args[which(sapply(args, is.null))] <- NULL if (nargs == 1) return( args[[1]]) if (nargs == 2) { # Classical case, concatenate two matrices A <- args[[1]] B <- args[[2]] if(!is.spam(A)) A <- as.spam(A) if(!is.spam(B)) B <- as.spam(B) dimA <- A@dimension lenA <- length(A@entries) A@entries <- c(A@entries,B@entries) A@colindices <- c(A@colindices,B@colindices+dimA[2]) A@rowpointers <- c(A@rowpointers,B@rowpointers[-1]+lenA) A@dimension <- dimA+B@dimension return(A) } else { # "recursive" approach only, e.g. no checking tmp <- bdiag.spam( args[[1]], args[[2]]) for ( i in 3:nargs) tmp <- bdiag.spam( tmp, args[[i]]) return( tmp) } } adjacency.landkreis <- function(loc) # this reads the germany graph file provide by # loc <- "http://www.math.ntnu.no/~hrue/GMRF-book/germany.graph" # or # loc <- system.file("demodata/germany.graph", package="INLA") # { n <- as.numeric( readLines(loc, n=1)) nnodes <- nodes <- numeric( n) adj <- list() for (i in 1:n) { tmp <- as.numeric(scan(loc, skip=i, nlines=1, quiet=T, what=list(rep("",13)))[[1]]) nodes[i] <- tmp[1] nnodes[i] <- tmp[2] adj[[i]] <- tmp[-c(1:2)] } adj <- adj[ order(nodes)] nnodes <- nnodes[ order(nodes)] A <- spam(0) A@colindices <- as.integer( unlist(adj)+1) A@rowpointers <- as.integer( c(1,cumsum(lapply(adj, length))+1)) A@entries <- rep(1, length(unlist(adj))) A@dimension <- as.integer( c(n, n)) return(A) } map.landkreis <- function(data, col=NULL, zlim=range(data), add=FALSE, legendpos=c( 0.88,0.9,0.05,0.4)) # This is a stripped-down version of the function provided by the INLA package. # Added color argument, changed "append" to "add". # Legend is tuned for a mai=rep(0,4) call { npoly <- length(spam::germany) ymax <- ymin <- xmax <- xmin <- 1:npoly if (length(data)!=npoly) stop("data has wrong length") if (is.null(col)) { if (requireNamespace("fields", quietly = TRUE)) { col <- fields::tim.colors(64) } else { col <- gray(seq(.05,to=0.95,length=64)) } } ncol <- length(col) polycol <- col[round(((data-zlim[1])/diff(zlim)+1e-6)*(ncol-1))+1] for(i in 1:length(spam::germany)) { xmin[i] <- min(spam::germany[[i]][,2],na.rm=T) xmax[i] <- max(spam::germany[[i]][,2],na.rm=T) ymin[i] <- min(spam::germany[[i]][,3],na.rm=T) ymax[i] <- max(spam::germany[[i]][,3],na.rm=T) } if (!add) plot(c(min(xmin),max(xmax)),c(min(ymin),max(ymax)), type="n", axes=F, xlab="", ylab="") for(k in npoly:1) polygon(spam::germany[[k]][,2],spam::germany[[k]][,3],col=polycol[k]) if (requireNamespace("fields", quietly = TRUE)) fields::image.plot(as.matrix(data), zlim=zlim, legend.only=T, smallplot=legendpos, cex=.2, col=col) invisible() } germany.plot <- function(vect, col=NULL, zlim=range(vect), legend=TRUE, main=NULL, cex.axis=1, cex.main=1.5, add=FALSE, ... ) { if (length(vect) != spam::germany.info$n) stop("data has wrong length") if (!add) { par(mai=c(.1,.1,.1,.3)) plot(0,0, xlim=spam::germany.info$xlim, ylim=spam::germany.info$ylim, type = "n", axes = F, xlab = "", ylab = "") } if (is.null(col)) { ## from: require(RColorBrewer); col <- colorRampPalette(brewer.pal(9,"Blues"))(100) col <- c("#F7FBFF", "#F4F9FE", "#F2F8FD", "#F0F7FD", "#EEF5FC", "#ECF4FB", "#EAF3FB", "#E8F1FA", "#E6F0F9", "#E4EFF9", "#E2EEF8", "#E0ECF7", "#DEEBF7", "#DCEAF6", "#DAE8F5", "#D8E7F5", "#D6E6F4", "#D5E5F4", "#D3E3F3", "#D1E2F2", "#CFE1F2", "#CDDFF1", "#CBDEF0", "#C9DDF0", "#C7DBEF", "#C5DAEE", "#C1D9ED", "#BED7EC", "#BBD6EB", "#B8D5EA", "#B5D3E9", "#B1D2E7", "#AED1E6", "#ABCFE5", "#A8CEE4", "#A4CCE3", "#A1CBE2", "#9ECAE1", "#9AC8E0", "#96C5DF", "#92C3DE", "#8EC1DD", "#89BEDC", "#85BCDB", "#81BADA", "#7DB8DA", "#79B5D9", "#75B3D8", "#71B1D7", "#6DAFD6", "#69ACD5", "#66AAD4", "#62A8D2", "#5FA6D1", "#5CA3D0", "#58A1CE", "#559FCD", "#529DCC", "#4E9ACB", "#4B98C9", "#4896C8", "#4493C7", "#4191C5", "#3E8EC4", "#3C8CC3", "#3989C1", "#3686C0", "#3484BE", "#3181BD", "#2E7EBC", "#2C7CBA", "#2979B9", "#2776B8", "#2474B6", "#2171B5", "#1F6FB3", "#1D6CB1", "#1B69AF", "#1967AD", "#1764AB", "#1562A9", "#135FA7", "#115CA5", "#0F5AA3", "#0D57A1", "#0B559F", "#09529D", "#084F9A", "#084D96", "#084A92", "#08478E", "#08458A", "#084286", "#083F82", "#083D7E", "#083A7A", "#083776", "#083572", "#08326E", "#08306B") } ncol <- length(col) polycol <- (col)[round((((vect) - zlim[1])/diff(zlim) + 1e-06) * (ncol - 1)) + 1] polygon( spam::germany.poly[17965L:1L,], col = (polycol[spam::germany.info$polyid])[599L:1L], ...) if (legend&&requireNamespace("fields", quietly = TRUE)){ legendpos <- c(0.845, 0.89, 0.05, 0.4) fields::image.plot(as.matrix(vect), zlim = zlim, legend.only = TRUE, smallplot = legendpos, axis.args=list(cex.axis=cex.axis,lwd=0, lwd.ticks=1.3), col = col) } if(!is.null(main)) text( min(spam::germany.info$xlim), max(spam::germany.info$ylim), main, cex=cex.main, adj=c(0,1)) invisible() } grid_zoom <- function(inputGrob = pointsGrob(runif(200),runif(200)), inputViewport = viewport(name="main"), x = "topleft", y, just, ratio = c(.3,.4), zoom_xlim, zoom_ylim, rect = TRUE, rect_lwd = 1, rect_fill = "gray92", draw =TRUE, zoom_fill = "white", zoom_frame_gp = gpar(lwd = 1), zoom_gp = NULL, zoom_xaxis = xaxisGrob(main = FALSE), zoom_yaxis = NULL) { ## inputGrob <- pointsGrob(runif(100), runif(100), pch=".", gp=gpar(cex=4),default.units="native",name="cc") ## inputViewort <- viewport(name="main") ## x <- "topleft" ## ratio <- unit(c(.3,.3), "npc") ## zoom_xlim <- c(0.1,.5) ## zoom_ylim <- c(0.1,.5) ## rect <- TRUE ## rect_lwd = 1 ## rect_fill = "gray92" ## zoom_fill = "white" ## zoom_frame_gp = gpar(lwd = 1) ## draw = TRUE ## zoom_gp = NULL # cat("may not work if other units than \"native\" and if the inputGrob has a complex structure. \n") if (!identical(length(ratio), 1)) ratio <- c(ratio, ratio) if(class(x) == "character") switch(x, topleft = {x = 0; y = 1; just = c(0, 1)}, topright = {x = 1; y = 1 ; just = c(1, 1)}, bottomright = {x = 1; y = 0; just = c(1, 0)}, bottomleft = {x = 0; y = 0; just = c(0, 0)}) inputViewport$name <- "main" vp <- vpStack(inputViewport, vpList(viewport(name="zoom", x = unit(x,"npc"), y = unit(y,"npc"), width=unit(ratio[1],"npc"), height=unit(ratio[2],"npc"), just = just, xscale=zoom_xlim, yscale=zoom_ylim, default.units="native", clip = "on"), viewport(name="zoom_noClip", x = unit(x,"npc"), y = unit(y,"npc"), width=unit(ratio[1],"npc"), height=unit(ratio[2],"npc"), just = just, xscale=zoom_xlim, yscale=zoom_ylim, default.units="native", clip = "off"))) inputGrob <- editGrob(inputGrob, name="main", vp="main") zoom_grob <- editGrob(inputGrob, name="zoom", vp="main::zoom") if(!is.null(zoom_gp)) zoom_grob <- editGrob(inputGrob, name="zoom", vp="main::zoom", gp=zoom_gp) if(!is.null(zoom_xaxis)) zoom_xaxis <- editGrob(zoom_xaxis, vp="main::zoom_noClip", name = "xaxis") if(!is.null(zoom_yaxis)) zoom_yaxis <- editGrob(zoom_yaxis, vp="main::zoom_noClip", name = "yaxis") rect <- rectGrob(x = zoom_xlim[1], y = zoom_ylim[1], just = c(0,0), width = diff(zoom_xlim), height = diff(zoom_ylim), default.units = "native", vp = "main", gp = gpar(lwd = rect_lwd, fill=rect_fill)) rect_frame <- rectGrob(x = zoom_xlim[1], y = zoom_ylim[1], just = c(0,0), width = diff(zoom_xlim), height = diff(zoom_ylim), default.units = "native", vp = "main", gp = gpar(lwd = rect_lwd)) gr <- gList(rect, inputGrob, rectGrob(vp="main::zoom", gp=gpar(fill=zoom_fill)), zoom_grob, rectGrob(vp="main::zoom_noClip", gp=zoom_frame_gp), zoom_xaxis, zoom_yaxis, rect_frame) out <- gTree(children=gr, childrenvp = vp) if (draw) grid.draw(out) invisible(out) } grid_trace2 <- function (chain1, chain2 = NULL, xlim = NULL, ylim1 = NULL, ylim2=NULL, chain1_lab = "", chain2_lab = "", main = "", chain1_yaxis_at = NULL, chain2_yaxis_at = NULL, log = FALSE, cex_points = unit(.2, "mm"), cex_main = unit(1.2, "mm"), lwd_lines = unit(.1, "mm"), lwd_frame = unit(.8, "mm"), draw = TRUE) { if (is.null(chain2)) { chain2 <- chain1[, 2] chain1 <- chain1[, 1] } if (log) { chain1 <- log(chain1) chain2 <- log(chain2) } stopifnot(identical(length(chain1), length(chain2))) n <- length(chain1) if(!is.null(xlim)){ stopifnot(length(xlim)==2) chain1.sub <- chain1[xlim[1]:xlim[2]] chain2.sub <- chain2[xlim[1]:xlim[2]] }else{ chain1.sub <- chain1 chain2.sub <- chain2 } if(!is.null(ylim1)) stopifnot(length(ylim1)==2) if(!is.null(ylim2)) stopifnot(length(ylim2)==2) vp1 <- plotViewport(unit(c(2.5, 3, 2.5, 2), "cm"), name = "frame") vp2 <- viewport(layout = grid.layout(nrow = 1, ncol = 3, respect = rbind(c(0, 0, 1)), widths = unit(c(1, 0.3, 1), c("null", "cm", "null"))), name = "lay1") vp3 <- viewport(layout.pos.col = 1, name = "traces") vp4 <- viewport(layout = grid.layout(nrow = 2, ncol = 1), name = "lay2") vp5 <- viewport(layout.pos.row = 1, name = "trace1") vp5data <- dataViewport(xData = 1L:n, yData = chain1, xscale = xlim, yscale = ylim1, extension = c(0.02, 0.03), name = "trace1data", clip="off") vp5data_clip <- dataViewport(xData = 1L:n, yData = chain1, xscale = xlim, yscale = ylim1, extension = c(0.02, 0.03), name = "trace1data_clip", clip="on") vp6 <- viewport(layout.pos.row = 2, name = "trace2") vp6data_clip <- dataViewport(xData = 1L:n, yData = chain2, xscale = xlim, yscale = ylim2, extension = c(0.02, 0.03), name = "trace2data_clip", clip="on") vp6data <- dataViewport(xData = 1L:n, yData = chain2, xscale = xlim, yscale = ylim2, extension = c(0.02, 0.03), name = "trace2data", clip="off") vp7 <- viewport(layout.pos.col = 3, name = "scatter") vp7data_clip <- dataViewport(xData = chain1, yData = chain2, xscale = ylim1, yscale = ylim2, extension = 0.03, name = "scatterData_clip", clip="on") vp7data <- dataViewport(xData = chain1, yData = chain2, xscale = ylim1, yscale = ylim2, extension = 0.03, name = "scatterData", clip="off") vps <- vpStack(vp1, vp2, vpList(vpStack(vp3, vp4, vpList(vpStack(vp5, vp5data, vp5data_clip), vpStack(vp6, vp6data, vp6data_clip))), vpStack(vp7, vp7data, vp7data_clip))) grs <- gList(rectGrob(vp = "frame::lay1::traces::lay2::trace1", gp = gpar(lwd = lwd_frame), name = "rect_trace1"), linesGrob(x = 1L:n, y = chain1, gp = gpar(lty = 1, lwd = lwd_lines), default.units = "native", vp = "frame::lay1::traces::lay2::trace1::trace1data::trace1data_clip", name = "lines_chain1"), yaxisGrob(at = chain1_yaxis_at, vp = "frame::lay1::traces::lay2::trace1::trace1data", name = "yaxis_chain1"), rectGrob(vp = "frame::lay1::traces::lay2::trace2", gp = gpar(lwd = lwd_frame), name = "rect_trace2"), linesGrob(x = 1L:n, y = chain2, gp = gpar(lty = 1, lwd = lwd_lines), default.units = "native", vp = "frame::lay1::traces::lay2::trace2::trace2data::trace2data_clip", name = "lines_chain2"), yaxisGrob(at = chain2_yaxis_at, vp = "frame::lay1::traces::lay2::trace2::trace2data", name = "yaxis_chain2"), xaxisGrob(vp = "frame::lay1::traces::lay2::trace2::trace2data", name = "xaxis_chains"), pointsGrob(x = chain1.sub, y = chain2.sub, pch = 20, gp = gpar(cex = cex_points), default.units = "native", vp = "frame::lay1::scatter::scatterData::scatterData_clip", name = "points_scatter"), rectGrob(vp = "frame::lay1::scatter::scatterData", gp = gpar(lwd = lwd_frame), name = "rect_scatter"), textGrob(chain1_lab, y = unit(-1, "line") - unit(0.2, "cm"), vp = "frame::lay1::scatter", name = "text_scatter_lab1"), textGrob(chain2_lab, x = unit(1, "npc") + unit(0.5, "cm"), rot = 90, vp = "frame::lay1::scatter", name = "text_scatter_lab2"), textGrob(main, x = unit(.5, "npc") + grobHeight(rectGrob())*.5, y = unit(1, "npc") + max(stringHeight("Fg"),unit(.6, "cm")), vp = "frame::lay1::traces", name = "title", just=c(.5, .5), gp=gpar(cex=cex_main)) ) out <- gTree(childrenvp = vps, children = grs) if (draw) grid.draw(out) invisible(out) } spam/R/summary.R0000644000176200001440000000450413536451710013243 0ustar liggesusers# HEADER #################################################### # This is file spam/R/summary.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ summary.spam <- function(object,...) { nz <- length(object@entries) dens <- nz/prod(object@dimension)*100 SS <- .format.spam(object, validate = FALSE) ans <- list(nnz=nz, density=dens, dim=object@dimension, format=SS) class(ans) <- "summary.spam" ans } summary.spam.chol.NgPeyton <- function(object,...) { nrow <- object@dimension[1] nnzR <- object@rowpointers[nrow+1]-1 dens <- nnzR/(nrow^2) nnzc <- length(object@colindices) nnzA <- object@nnzA fill <- nnzR/((nnzA+nrow)/2) ans <- list(nnzR=nnzR, nnzcolindices=nnzc,density=dens,fillin=fill, dim=c(nrow,nrow), nzzA=nnzA) class( ans) <- "summary.spam.chol.NgPeyton" ans } setMethod("summary","spam",summary.spam) setMethod("summary", "spam.chol.NgPeyton", summary.spam.chol.NgPeyton) print.summary.spam <- function(x, ...) { cat("Matrix object of class 'spam' of dimension ",x$dim[1],"x", x$dim[2],",\n",sep="") cat(" with ",x$nnz," (row-wise) nonzero elements.\n",sep="") cat(" Density of the matrix is ",signif(x$dens,3),"%.\n",sep="") cat(paste0("Class 'spam' (", x$format$name, ")\n")) invisible(x) } print.summary.spam.chol.NgPeyton <- function(x,...) { cat("(Upper) Cholesky factor of class 'spam.chol.NgPeyton' of dimension ", x$dim[1], "x", x$dim[1], " with ",x$nnzR," (row-wise) nonzero elements.", sep = "", fill=TRUE) cat(" Density of the factor is ", signif(x$dens * 100, 3),"%.\n", sep = "") cat(" Fill-in ratio is ", signif(x$fill, 3),"\n", sep = "") cat(" (Optimal argument for 'chol' is 'memory=list(nnzR=",x$nnzR, ifelse(x$nnzA https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ ######################################################################## #norm <- function(x, type = "sup", ...){ # typ <- charmatch(tolower(type), c("sup","l1","frobenius","hs")) # if (is.na(typ)) stop("undefined norm "",type,"".",call.=FALSE) # switch(typ, # max(abs(x)), # sum(abs(x)), # sqrt(sum(x^2)),sqrt(sum(x^2)) # ) #} norm.spam <- function(x, type = "m", ...){ typ <- substr(tolower(type),1,1) if (typ %in% c("o", "1")) { return( max( colSums(abs(x)))) } if (typ %in% c("i")) { return( max( rowSums(abs(x)))) } if (typ %in% c("f", "h")) { return( sqrt(sum(x@entries^2))) } if (typ %in% c("m","s")) { return( max(abs(x@entries)) ) } stop("undefined norm '",type,"'.",call.=FALSE) } setMethod("norm",signature(x="spam",type="character"), function(x, type, ...) norm.spam(x, type)) setMethod("norm",signature(x="spam",type="missing"), function(x, type, ...) norm.spam(x, type="O")) setMethod("norm", signature(x = "numeric", type = "character"), function(x, type, ...) base::norm(as.matrix(x), type)) setMethod("norm", signature(x = "numeric", type = "missing"), function(x, type, ...) base::norm(as.matrix(x), type="O")) setMethod("norm", signature(x = "matrix", type = "character"), function(x, type, ...) base::norm(x, type)) setMethod("norm", signature(x = "matrix", type = "missing"), function(x, type, ...) base::norm(x, type="o")) spam/R/random.R0000644000176200001440000000713313571733341013031 0ustar liggesusers# HEADER #################################################### # This is file spam/R/random.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ spam_random <- function(nrow = 1L, ncol = nrow, density = 0.5, distribution = NULL, digits = NULL, sym = FALSE, spd = FALSE, verbose = FALSE, ...) { if (!is.numeric(nrow) || length(nrow) != 1) stop("nrow must be a single numeric value.") if (!is.numeric(ncol) || length(ncol) != 1) stop("ncol must be a single numeric value.") if (!is.numeric(density) || length(density) != 1 || density < 0 || density > 1) stop("density must be a single numeric value, equal or between 0 and 1.") if (!(is.null(distribution) || (is.function(distribution) && any(names(formals(distribution)) == "n")))) stop("distribution must be a function which generates random deviates and must have an argument \"n\".") if (!(is.null(digits) || (is.numeric(digits) && length(digits) == 1 && digits >= 0))) stop("digits must be a single numeric value larger or equal to 0.") if (!is.logical(verbose) || length(verbose) != 1) stop("verbose must be a single locigal value.") if (!is.logical(sym) || length(sym) != 1) stop("sym must be a single locigal value.") if (!is.logical(spd) || length(spd) != 1) stop("spd must be a single locigal value.") if (spd && ((ncol != nrow) || density == 0)) stop("if spd == TRUE, then it must hold that ncol == nrow and density > 0") if (density == 1) npercol <- rep.int(ncol, nrow) else if (density == 0) return(spam(0, nrow, ncol)) else npercol <- as.integer(rbinom(n = nrow, size = ncol, prob = density)) rowp <- c(1L, cumsum(npercol) + 1L) n <- sum(npercol) if (n == 0) { if (sym) if (is.null(distribution)) return(diag.spam(nrow = nrow, ncol = ncol)) else return(diag.spam(x = distribution(min(nrow, ncol), ...), nrow = nrow, ncol = ncol)) else return(spam(0, nrow = nrow, ncol = ncol)) } coli <- integer(n) seqcol <- seq_len(ncol) for (i in seq_len(nrow)) { if (rowp[i] == rowp[i+1L]) next coli[rowp[i]:(rowp[i+1L]-1L)] <- sort(sample(seqcol, npercol[i], replace = FALSE)) } if (is.null(distribution)) entries <- rep.int(1, n) else entries <- distribution(n, ...) if (!is.null(digits)) entries <- round(entries, digits) rspam <- .newSpam(entries, colindices = coli, rowpointers = rowp, dimension = c(nrow, ncol), force64 = getOption("spam.force64")) if (spd) { sym <- TRUE diag.spam(rspam) <- diag.spam(rspam) + 1 } if (sym) { s_t <- t.spam(rspam) rspam <- s_t[lower.tri(s_t, diag = TRUE)] + rspam[upper.tri(rspam, diag = TRUE)] } if (spd) { st <- rspam st@entries <- abs(st@entries) st_dia <- diag.spam(st) st_rs <- rowSums(st) s_diag <- diag(rspam) ind <- 2*st_dia <= st_rs diag.spam(rspam)[ind] <- ifelse(s_diag >=0, st_rs+1, -st_rs-1)[ind] } if(verbose) message("Density is ", round(n/prod(rspam@dimension), 7), ", specified is ", density, " (nnz=",n,").") return(rspam) } spam/R/foreign.R0000644000176200001440000003077013536451707013211 0ustar liggesusers# HEADER #################################################### # This is file spam/R/foreign.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ # Contains two sections: # 1) Routines to transform spam objects to SparseM and Matrix # 2) Functions to read (and write) MM and HB formats. # 1a) spam <-> SparseM as.spam.matrix.csr <- function(x) { # if (is.matrix.csr(x)) { newx <- new("spam") slot(newx,"entries",check=FALSE) <- as.double( x@ra) slot(newx,"colindices",check=FALSE) <- x@ja slot(newx,"rowpointers",check=FALSE) <- x@ia slot(newx,"dimension",check=FALSE) <- x@dimension return(newx) # } else stop("Wrong object passed to "as.spam.matrix.csr"") } # The following should not be necessary because it is # as."matrix.csr".spam and not "as.matrix".csr.spam. # Is there anyway around this? #as.matrix.csr.spam <- function(x,...) { # if (require("SparseM")){ # newx <- new("matrix.csr") # slot(newx,"ra",check=FALSE) <- x@entries # slot(newx,"ja",check=FALSE) <- x@colindices # slot(newx,"ia",check=FALSE) <- x@rowpointers # slot(newx,"dimension",check=FALSE) <- x@dimension # return(newx) # } #} # 1b) spam <-> Matrix as.dgRMatrix.spam <- function(x) { if(.format.spam(x)$package != "spam"){ stop("dgRMatrix structure is not compatible with numeric/large integer type.") } if (requireNamespace("Matrix")) { newx <- new(p=0:0,"dgRMatrix") slot(newx,"x",check=FALSE) <- x@entries slot(newx,"j",check=FALSE) <- x@colindices-1L slot(newx,"p",check=FALSE) <- x@rowpointers-1L slot(newx,"Dim",check=FALSE) <- x@dimension return(newx) } } as.dgCMatrix.spam <- function(x) { if(.format.spam(x)$package != "spam"){ stop("dgCMatrix structure is not compatible with numeric/large integer type.") } if (requireNamespace("Matrix")) { dimx <- x@dimension nz <- x@rowpointers[dimx[1] + 1] - 1 z <- .Fortran("transpose", n = as.integer(dimx[1]), m = as.integer(dimx[2]), a = as.double(x@entries),ja = as.integer(x@colindices), ia = as.integer(x@rowpointers), entries = vector("double",nz), colindices = vector("integer", nz), rowpointers = vector("integer", dimx[2] + 1), NAOK = getOption("spam.NAOK"), PACKAGE = "spam") ## SS <- .format.spam(x) ## z <- .C64("transpose", ## SIGNATURE = c( SS$signature, SS$signature, ## "double", SS$signature, SS$signature, ## "double", SS$signature, SS$signature), ## n = dimx[1], ## m = dimx[2], ## a = x@entries, ## ja = x@colindices, ## ia = x@rowpointers, ## entries = vector_dc("double",nz), ## colindices = vector_dc(SS$type, nz), ## rowpointers = vector_dc(SS$type, dimx[2] + 1), ## INTENT = c("r", "r", ## "r", "r", "r", ## "w", "w", "w"), ## NAOK = getOption("spam.NAOK"), ## PACKAGE = SS$package) newx <- new(p=0:0,"dgCMatrix") slot(newx,"x",check=FALSE) <- z$entries slot(newx,"i",check=FALSE) <- z$colindices-1L slot(newx,"p",check=FALSE) <- z$rowpointers-1L slot(newx,"Dim",check=FALSE) <- dimx return(newx) } } as.spam.dgRMatrix <- function(x) { if (is(x,"dgRMatrix")){ if (identical(length(x@x),0L)) # zero matrix return(new("spam",rowpointers=c(1L,rep.int(2L,x@Dim[1])), dimension=x@Dim)) newx <- new("spam") slot(newx,"entries",check=FALSE) <- x@x slot(newx,"colindices",check=FALSE) <- x@j+1L slot(newx,"rowpointers",check=FALSE) <- x@p+1L slot(newx,"dimension",check=FALSE) <- x@Dim return(newx) } stop("Wrong object passed to 'as.spam.dgRMatrix'") } as.spam.dgCMatrix <- function(x) { if (is(x,"dgCMatrix")){ if (identical(length(x@x),0L)) # zero matrix return(new("spam",rowpointers=c(1L,rep.int(2L,x@Dim[1])), dimension=x@Dim)) nz <- x@p[x@Dim[2] + 1] z <- .Fortran("transpose", n = as.integer(x@Dim[2]), m = as.integer(x@Dim[1]), a = as.double(x@x),ja = as.integer(x@i+1L), ia = as.integer(x@p+1L), entries = vector("double",nz), colindices = vector("integer", nz), rowpointers = vector("integer", x@Dim[1] + 1), NAOK = getOption("spam.NAOK"), PACKAGE = "spam") newx <- new("spam") slot(newx,"entries",check=FALSE) <- z$entries slot(newx,"colindices",check=FALSE) <- z$colindices slot(newx,"rowpointers",check=FALSE) <- z$rowpointers slot(newx,"dimension",check=FALSE) <- x@Dim return(newx) } stop("Wrong object passed to 'as.spam.dgCMatrix'") } # 2) Import and export # taken from Matrix 0.999375-10 and adapted for spam ## Utilities for the Harwell-Boeing and MatrixMarket formats readone <- function(ln, iwd, nper, conv) # By Bates/Maechler from Matrix 0.999375-10 { ln <- gsub("D", "E", ln) inds <- seq(0, by = iwd, length = nper + 1) (conv)(substring(ln, 1 + inds[-length(inds)], inds[-1])) } readmany <- function(conn, nlines, nvals, fmt, conv) # By Bates/Maechler from Matrix 0.999375-10 { if (!grep("[[:digit:]]+[DEFGI][[:digit:]]+", fmt)) stop("Not a valid format") Iind <- regexpr("[DEFGI]", fmt) nper <- as.integer(substr(fmt, regexpr("[[:digit:]]+[DEFGI]", fmt), Iind - 1)) iwd <- as.integer(substr(fmt, Iind + 1, regexpr("[\\.\\)]", fmt) - 1)) rem <- nvals %% nper full <- nvals %/% nper ans <- vector("list", nvals %/% nper) for (i in seq_len(full)) ans[[i]] <- readone(readLines(conn, 1, ok = FALSE), iwd, nper, conv) if (!rem) return(unlist(ans)) c(unlist(ans), readone(readLines(conn, 1, ok = FALSE), iwd, rem, conv)) } read.HB <- function(file) # Adapted from Bates/Maechler Matrix 0.999375-10 version { if (is.character(file)) file <- if (file == "") stdin() else file(file) if (!inherits(file, "connection")) stop("'file' must be a character string or connection") if (!isOpen(file)) { open(file) on.exit(close(file)) } hdr <- readLines(file, 4, ok = FALSE) Title <- sub("[[:space:]]+$", "", substr(hdr[1], 1, 72)) Key <- sub("[[:space:]]+$", "", substr(hdr[1], 73, 80)) totln <- as.integer(substr(hdr[2], 1, 14)) ptrln <- as.integer(substr(hdr[2], 15, 28)) indln <- as.integer(substr(hdr[2], 29, 42)) valln <- as.integer(substr(hdr[2], 43, 56)) rhsln <- as.integer(substr(hdr[2], 57, 70)) if (!(t1 <- substr(hdr[3], 1, 1)) %in% c("C", "R", "P")) stop(paste("Invalid storage type:", t1)) if (t1 != "R") stop("Only numeric sparse matrices allowed") ## _FIXME: Patterns should also be allowed if (!(t2 <- substr(hdr[3], 2, 2)) %in% c("H", "R", "S", "U", "Z")) stop(paste("Invalid storage format:", t2)) if (!(t3 <- substr(hdr[3], 3, 3)) %in% c("A", "E")) stop(paste("Invalid assembled indicator:", t3)) nr <- as.integer(substr(hdr[3], 15, 28)) nc <- as.integer(substr(hdr[3], 29, 42)) nz <- as.integer(substr(hdr[3], 43, 56)) nel <- as.integer(substr(hdr[3], 57, 70)) ptrfmt <- toupper(sub("[[:space:]]+$", "", substr(hdr[4], 1, 16))) indfmt <- toupper(sub("[[:space:]]+$", "", substr(hdr[4], 17, 32))) valfmt <- toupper(sub("[[:space:]]+$", "", substr(hdr[4], 33, 52))) rhsfmt <- toupper(sub("[[:space:]]+$", "", substr(hdr[4], 53, 72))) if (!is.na(rhsln) && rhsln > 0) { h5 <- readLines(file, 1, ok = FALSE) } ptr <- readmany(file, ptrln, nc + 1, ptrfmt, as.integer) ind <- readmany(file, indln, nz, indfmt, as.integer) vals <- readmany(file, valln, nz, valfmt, as.numeric) # Spam related changes: if (t3 =="E") stop("Only assembled Harwell-Boeing formats implemented") z <- .Fortran("transpose", n = as.integer(nc), m = as.integer(nr), a = as.double(vals),ja = as.integer(ind), ia = as.integer(ptr), entries = vector("double",nz), colindices = vector("integer", nz), rowpointers = vector("integer", nr + 1), NAOK = getOption("spam.NAOK"), PACKAGE = "spam") newx <- new("spam") slot(newx,"entries",check=FALSE) <- z$entries slot(newx,"colindices",check=FALSE) <- z$colindices slot(newx,"rowpointers",check=FALSE) <- z$rowpointers slot(newx,"dimension",check=FALSE) <- c(nr, nc) if (t2 %in% c("H", "S")) newx <- newx+t.spam(newx)-diag.spam(spam(newx)) if (t2 =="Z") newx <- newx-t.spam(newx) return(newx) } # alternatives are implementing # http://math.nist.gov/MatrixMarket/mmio/f/mmiof77.html read.MM <- function(file) { if (is.character(file)) file <- if(file == "") stdin() else file(file) if (!inherits(file, "connection")) stop("'file' must be a character string or connection") if (!isOpen(file)) { open(file) on.exit(close(file)) } scan1 <- function(what, ...) scan(file, nmax = 1, what = what, quiet = TRUE, ...) if ((hdr <- tolower(scan1(character()))) != "%%matrixmarket") # RF: added a to lower stop("file is not a MatrixMarket file") if (!(typ <- tolower(scan1(character()))) %in% "matrix") stop("type '", typ, "' not recognized") if (!(repr <- tolower(scan1(character()))) %in% c("coordinate", "array")) stop("representation '", repr, "' not recognized") elt <- tolower(scan1(character())) if (!elt %in% c("real", "complex", "integer", "pattern")) stop("element type '", elt, "' not recognized") sym <- tolower(scan1(character())) if (!sym %in% c("general", "symmetric", "skew-symmetric", "hermitian")) stop("symmetry form '", sym, "' not recognized") nr <- scan1(integer(), comment.char = "%") nc <- scan1(integer()) # code from now on differs from Matrix one... if (repr == "coordinate") { nz <- scan1(integer()) switch(elt, "real" = { what <- list(i= integer(), j= integer(), x= numeric())}, "integer" = { what <- list(i= integer(), j= integer(), x= numeric()) warning("'integer' format coerced to 'double'", call. = FALSE) }, "pattern" = { what <- list(i= integer(), j= integer()) warning("matrix elements assumed as 1 ('pattern' format)", call. = FALSE) }, "complex" = { what <- list(i= integer(), j= integer(), x= numeric(), y= numeric()) warning("retaining only real part of 'complex' format", call. = FALSE) } ) z <- scan(file, nmax = nz, quiet = TRUE, what= what) newx <- spam.list(list(ind=cbind(z$i,z$j),x= if(elt=="pattern") rep.int(1,nz) else z$x ), nr,nc) if (sym %in% c("symmetric", "hermitian")) { dim(newx) <- rep(max(nr,nc),2) newx <- newx+t.spam(newx)-diag.spam(diag(newx)) } if (sym=="skew-symmetric") { dim(newx) <- rep(max(nr,nc),2) newx <- newx-t.spam(newx) } } else { nz <- nr*nc x <- scan(file, nmax = nz, quiet = TRUE, what=numeric()) z <- .Fortran("spamdnscsr", nrow = as.integer(nr), ncol = as.integer(nc), x = as.numeric(x), as.integer(nr), entries = vector("double",nz), colindices = vector("integer", nz), rowpointers = vector("integer",nr + 1), eps = options("spam.eps"), NAOK = TRUE, PACKAGE = "spam") warning("returning a (possibly) dense 'spam' object", call. = FALSE) nz <- z$rowpointers[nr+1]-1 if (identical(nz, 0L)) return(new("spam",rowpointers=c(1L,rep.int(2L,nr)), dimension=c(nr,nc))) newx <- new("spam") slot(newx,"entries",check=FALSE) <- z$entries[1:nz] slot(newx,"colindices",check=FALSE) <- z$colindices[1:nz] slot(newx,"rowpointers",check=FALSE) <- z$rowpointers slot(newx,"dimension",check=FALSE) <- c(nr,nc) } return(newx) } spam/R/dist.R0000644000176200001440000001545213536451707012523 0ustar liggesusers# HEADER #################################################### # This is file spam/R/dist.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ ### in base: # dist(x, method = "euclidean", diag = FALSE, upper = FALSE, p=2) # ### in fields # rdist( x1, x2) # rdist.earth(x1, x2, miles = TRUE, R = NULL) # fields.rdist.near( x1, x2, delta, max.points= NULL) # ### in sp # spDistsN1(pts, pt, longlat=FALSE) # ### in amap ### nbproc integer, Number of subprocess for parallelization # Dist(x, method = "euclidean", nbproc = 1, diag = FALSE, upper = FALSE) # ### in argosfilter # distance(lat1, lat2, lon1, lon2) # gc between two pts in km # distanceTrack(lat,lon) # gc between pts in km # ### in proxy # dist(x, y = NULL, method = NULL, ..., diag = FALSE, upper = FALSE, # pairwise = FALSE, by_rows = TRUE, convert_similarities = TRUE, # auto_convert_data_frames = TRUE) # ### in RFOC # GreatDist(LON1, LAT1, LON2, LAT2, EARTHRAD= 6371) # nearest.dist <- function( x, y=NULL, method = "euclidean", delta = 1, upper = if(is.null(y)) FALSE else NULL, p = 2, miles=TRUE, R=NULL # eps = NULL, diag = NULL ) { # see help for exact parameter meaning # We always include all small distances. Hence, this function # works different than any other spam functions. An addititonal # call to an as.spam would eliminate the small values. # if (!is.null(diag)) warning("Argument "diag" is deprecated") # if (!is.null(eps)) warning("Argument "eps" is deprecated") if (!is.na(pmatch(method, "euclidian"))) method <- "euclidean" METHODS <- c("euclidean", "maximum", "minkowski", "greatcircle") method <- pmatch(method, METHODS) # result is integer if (is.na(method)) stop("invalid distance method") force64 <- getOption("spam.force64") if (method == 4) { if (is.null(R)) p <- ifelse( miles,3963.34,6378.388) else { if (R <= 0) stop("'R' should be postiive") p <- R } if (abs(delta)>180.1) stop("'delta' should be smaller than 180 degrees.") } if (is.null(upper)) part <- 0L else part <- ifelse(upper, 1L ,-1L) if (is.data.frame(x)) x <- as.matrix(x) if (is.list(x)) stop("'x' should be an array or matrix") # as.matrix( list() ) does not work if (!is.matrix(x)) x <- as.matrix(x) nd <- dim(x)[2] n1 <- dim(x)[1] if (!is.null(y)) { # we specify x and y: if (is.data.frame(y)) y <- as.matrix(y) if (is.list(x)) stop("'x' should be an array or matrix") if (!is.matrix(y)) y <- as.matrix(y) if (nd!=dim(y)[2]) stop("'x' and 'y' should have the same number of columns.") n2 <- dim(y)[1] mi <- min(n1,n2) ma <- max(n1,n2) nnz <- min(max(getOption("spam.nearestdistnnz")[1], ma*getOption("spam.nearestdistnnz")[2]), (as.double(mi)*(mi+1)+(ma-mi)^2)/ ifelse( is.null(upper), 1, 2)) # there is an as.double just in case that mi (and n1 below) is > 2^16 } else { # x = y, i.e. proper distance matrix if (n1==1) stop("More than a single point in 'x' is required.") if (method == 4) { p <- -p # we save one variable... } y <- x n2 <- n1 nnz <- min(max(getOption("spam.nearestdistnnz")[1], n1*getOption("spam.nearestdistnnz")[2]), (as.double(n1)*(n1+1))/ ifelse( is.null(upper), 1, 2)) } # EXPLICIT-STORAGE-FORMAT if(max(n1,n2,nnz) > 2147483647 - 1 || force64) SS <- .format64() else SS <- .format32 if(2147483647 < nnz) stop("Distance matrix is too dense (1)") repeat { d <- NULL # Free the memory allocated by a previous attemp d <- .C64("closestdist", ## subroutine closestdist( ncol, x,nrowx, y, nrowy, ## & part, p, method, ## & eta, colindices, rowpointers, entries, nnz, iflag) SIGNATURE=c(SS$signature, "double", SS$signature, "double", SS$signature, SS$signature, "double", SS$signature, "double", SS$signature, SS$signature, "double", SS$signature, SS$signature), nd, x, n1, #w y, n2, #w part, #arg 6 p[1], method, abs( delta[1]), colindices=vector(SS$type, nnz), rowpointers=vector(SS$type, n1+1), #arg 11 entries=vector("double",nnz), nnz=nnz, iflag=0, INTENT = c("r", "r", "r", "r", "r", "r", "rw", "r", "r", "w", "w", "w", "rw", "w"), NAOK = getOption("spam.NAOK"), PACKAGE=SS$package) if (d$iflag==0) break else { nnz <- nnz*getOption("spam.nearestdistincreasefactor")*n1/(d$iflag-1) # EXPLICIT-STORAGE-FORMAT if(max(n1,n2,nnz) > 2147483647 - 1 || force64) SS <- .format64() else SS <- .format32 if(nnz > 2147483647) stop("Distance matrix is too dense (2)") madens <- d$iflag warning(paste("You ask for a 'dense' sparse distance matrix, I require one more iteration.", "\nTo avoid the iteration, increase 'nearestdistnnz' option to something like\n", "'options(spam.nearestdistnnz=c(",d$nnz,",400))'\n(constructed ",madens, " lines out of ",n1,").\n",sep=""), call. = TRUE) } } length(d$entries) <- d$nnz length(d$colindices) <- d$nnz if(d$nnz == 0) { return(.newSpam( dimension=c(n1,n2), force64 = force64 )) } return(.newSpam( entries=d$entries, colindices=d$colindices, rowpointers=d$rowpointers, dimension=c(n1,n2), force64 = force64 )) } # in fields: # rdist <- function (x1, x2) spam_rdist <- function(x1, x2, delta = 1) nearest.dist(x1, y=x2, delta = delta, upper = NULL) # in fields: # rdist.earth <- function (x1, x2, miles = TRUE, R = NULL) spam_rdist.earth <- function(x1, x2, delta=1, miles = TRUE, R = NULL) nearest.dist( x1, y=x2, method = "greatcircle", delta = delta, miles=miles, R=R, upper = NULL) spam/R/diff.R0000644000176200001440000000226413536451707012465 0ustar liggesusers# HEADER #################################################### # This is file spam/R/diff.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ ######################################################################## diff.spam <- function (x, lag = 1, differences = 1, ...) { xlen <- dim(x)[1L] if (length(lag) > 1L || length(differences) > 1L || lag < 1L || differences < 1L) stop("'lag' and 'differences' must be integers >= 1") if (lag * differences >= xlen) return( numeric(0)) for (i in 1L:differences){ x <- x[(1L+lag):xlen,, drop = FALSE] - x[1L:(xlen-lag),, drop = FALSE] xlen <- xlen - lag } return( x) } setMethod("diff","spam",diff.spam) spam/R/apply.R0000644000176200001440000000453313536451706012702 0ustar liggesusers# HEADER #################################################### # This is file spam/R/apply.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ # primitive apply function. apply.spam <- function(X, MARGIN=NULL, FUN, ...){ if (!is.spam(X)) stop("\"X\" must be of type \"spam\"") if (!is.null(dimnames(X))) warning("dimnames are stripped") FUN <- match.fun(FUN) d <- dim(X) d.ans <- d[MARGIN] dn.ans <- NULL if (is.null(MARGIN)|| length(MARGIN)==2){ ans <- FUN(X@entries,...) if (length( ans)!=length( X@entries)) stop("\"FUN\" does not return an appropriate vector") if (any(!is.finite(ans))) { warning("\"NA/NaN/Inf\" coerced to zero") ans[!is.finite(ans)] <- 0 } X@entries <- ans return(X) } ans <- vector("list",d.ans) if (MARGIN==1) { for (i in 1:d[1]) ans[[i]] <- FUN(X[i,,drop=F]@entries,...) } else if (MARGIN==2) { for (i in 1:d[2]) ans[[i]] <- FUN(X[,i,drop=F]@entries,...) } else stop("\"MARGIN\" must be 1, 2 or c(1,2)") # Block very similar to "apply" d2 <- prod(d.ans) ans.list <- is.recursive(ans[[1]]) l.ans <- length(ans[[1]]) ans.names <- names(ans[[1]]) if (!ans.list){ ans.list <- any(unlist(lapply(ans, length)) != l.ans) } if (!ans.list && length(ans.names)) { all.same <- sapply(ans, function(x) identical(names(x), ans.names)) if (!all(all.same)) ans.names <- NULL } len.a <- if (ans.list) d2 else length(ans <- unlist(ans, recursive = FALSE)) if (length(MARGIN) == 1 && len.a == d2) return(ans) if (len.a == d2) return(array(ans, d.ans)) if (len.a > 0 && len.a%%d2 == 0) { dn.ans <- vector(mode = "list", length(d.ans)) dn.ans <- c(list(ans.names), dn.ans) return(array(ans, c(len.a%/%d2, d.ans), if (!all(sapply(dn.ans, is.null))) dn.ans)) } return(ans) } spam/R/s3only.R0000644000176200001440000000137313536451710012776 0ustar liggesusers# HEADER #################################################### # This is file spam/R/s3only.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ var.spam <- function(x, ...) { inefficiencywarning( "This 'var' operation may be inefficient", prod(dim(x))) var(as.matrix(x), ...) } spam/R/profile.R0000644000176200001440000001265113536451707013216 0ustar liggesusers# HEADER #################################################### # This is file spam/R/profile.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ .format32 <- list( name = "32-bit", type = "integer", signature = "integer", package = "spam") .format64 <- list( name = "64-bit", type = "numeric", signature = "int64", package = "spam64") .format64 <- function(){ if (!isNamespaceLoaded("spam64")) { stop("Large (64-bit) sparse matrices detected. Please load the required package 'spam64' and see the help page '?large_matrix'.") } list( name = "64-bit", type = "numeric", signature = "int64", package = "spam64") } .format.spam <- function(x, ... , validate = getOption("spam.validate") ) { objects <- c(list(x), list(...)) if (validate) for(o in objects) stopifnot(validate_spam(o)) for(o in objects){ ## If both pointer vectors are of the same type, ## use this type to determine the format if(identical(typeof(o@colindices), typeof(o@rowpointers))) { if(identical(typeof(o@colindices), "double")){ return(.format64()) } next } ## As fallback use the length of the entries vector and the dimension if(nrow(o) > 2147483647 || ncol(o) > 2147483647 || length(o@entries) > 2147483647){ return(.format64()) } } return(.format32) } spam.Version <- function() { release <- utils::packageDescription("spam",field="Version") date <- utils::packageDescription("spam",field="Date") list(status="", major=sub("-","",substr(release,1,4)), minor=substr(sub("-","",substr(release,5,7)),1,1), year=substr(date,1,4), month=substr(sub("200.-","",date),1,2), day=sub("200.-..-","",date), version.string= paste("Spam version ", utils::packageDescription("spam",field="Version")," (", utils::packageDescription("spam",field="Date"),")",sep="") ) } spam.version <- spam.Version() class(spam.version) <- "simple.list" "inefficiencywarning" <- function(msg,size) { maxsize <- if (is.logical(getOption("spam.inefficiencywarning"))) { ifelse(getOption("spam.inefficiencywarning"),1,Inf) } else { getOption("spam.inefficiencywarning") } if (size>maxsize) warning(msg, call. = FALSE) } ".onAttach" <- function (lib, pkg) { packageStartupMessage( spam.version$version.string," is loaded.", "\nType 'help( Spam)' or 'demo( spam)' for a short introduction ", "\nand overview of this package.", "\nHelp for individual functions is also obtained by ", "adding the\nsuffix '.spam' to the function name, e.g. 'help( chol.spam)'.") } .onLoad <- function(libname, pkgname) { default_options <- list( spam.eps=.Machine$double.eps, # smaller than this is considered as zero spam.force64=FALSE, spam.validate=FALSE, # validate the spam object before calling a native routine for # increased stability. spam.drop=FALSE, # drop passed to subset functions spam.printsize=100, # the max size which we print as regular matrices spam.imagesize=10000, # the max size which we display as regular matrices spam.cex=1200, # scaling factor for scatter displays spam.structurebased=TRUE, # calculating on nonzero entries only... spam.inefficiencywarning=1e6, # tell when something inefficient is done spam.trivalues=FALSE, # with upper./lower/.tri return values (TRUE) or only structure? spam.listmethod="PE", # method to be used when using spam.list spam.NAOK = FALSE, spam.safemodevalidity=TRUE, # verify while S4 construction spam.dopivoting=TRUE, # what type of back/forwardsolve? spam.cholsymmetrycheck=TRUE, # Should symmetry be tested in the cholesky factorization spam.cholpivotcheck=TRUE, # Should the pivot be tested? spam.cholupdatesingular="warning", # ("error", "warning","NULL") spam.cholincreasefactor=c(1.25,1.25), spam.nearestdistincreasefactor=1.3, spam.nearestdistnnz=c(500^2,500) ) # Load the default settings: options(default_options) } powerboost <- function(flag = "on") { if (tolower(flag) %in% c("true","on","an","ein")) { options(spam.NAOK = TRUE, spam.safemodevalidity = FALSE, spam.cholsymmetrycheck = FALSE, spam.cholpivotcheck = FALSE, spam.eps = 1e-8) } else { options(spam.NAOK = FALSE, spam.safemodevalidity = TRUE, spam.cholsymmetrycheck = TRUE, spam.cholpivotcheck = TRUE, spam.eps = .Machine$double.eps) } invisible(NULL) } spam/R/kronecker.R0000644000176200001440000001174013536451707013537 0ustar liggesusers# HEADER #################################################### # This is file spam/R/kronecker.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ kronecker.spam <- function(X,Y,FUN = "*", make.dimnames = FALSE, ...) { ## print("1") if(getOption("spam.force64")) SS <- .format64() else SS <- .format32 if (make.dimnames) warning("dimnames not supported within sparse matrices") lenx <- length(X) leny <- length(Y) kronlen <- lenx*leny if(is.spam(X)){ Xdim <- X@dimension Xentries <- X@entries Xcol <- X@colindices Xrow <- X@rowpointers if(.format.spam(X)$package == "spam64") SS <- .format64() }else if (is.vector(X)){ Xentries <- X Xcol <- rep.int(as.integer(1),lenx) Xdim <- as.integer(c(lenx,1)) Xrow <- seq_len(lenx+1) } else { Xentries <- as.double(t(X)) Xdim <- dim(X) Xcol <- rep.int(as.integer(1:Xdim[2]),Xdim[1]) Xrow <- seq.int(1, by=Xdim[2], length.out=Xdim[1]+1) } if(is.spam(Y)){ Ydim <- Y@dimension Yentries <- Y@entries Ycol <- Y@colindices Yrow <- Y@rowpointers if(.format.spam(Y)$package == "spam64") SS <- .format64() } else if (is.vector(Y)){ Yentries <- Y Ycol <- rep.int(as.integer(1),leny) Ydim <- as.integer(c(leny,1)) Yrow <- seq_len(leny+1) } else { Yentries <- as.double(t(Y)) Ydim <- dim(Y) Ycol <- rep.int(as.integer(1:Ydim[2]),Ydim[1]) Yrow <- seq.int(1, by=Ydim[2], length.out=Ydim[1]+1) } ## kronxy <- new("spam") if (FUN=="*") { z <- .C64("kroneckermult", SIGNATURE = c(SS$signature, "double", SS$signature, SS$signature, SS$signature, SS$signature, "double", SS$signature, SS$signature, "double", SS$signature, SS$signature), Xdim[1], Xentries, Xcol, Xrow, Ydim[1], Ydim[2], Yentries, Ycol, Yrow, entries = vector_dc( "double", kronlen), colindices = vector_dc( SS$type, kronlen), rowpointers = vector_dc( SS$type, Xdim[1]*Ydim[1]+1), INTENT = c( "r", "r", "r", "r", "r", "r", "r", "r", "r", "w", "w", "w"), NAOK=getOption("spam.NAOK"), PACKAGE = SS$package) kronxy <- .newSpam( entries = z$entries) ## slot(kronxy, "entries", check=FALSE) <- z$entries }else { z <- .C64("kroneckerf", SIGNATURE = c(SS$signature, "double", SS$signature, SS$signature, SS$signature, SS$signature, "double", SS$signature, SS$signature, "double", "double", SS$signature, SS$signature), Xdim[1], Xentries, Xcol, Xrow, Ydim[1], Ydim[2], Yentries, Ycol, Yrow, ent1 = vector_dc( "double", kronlen), ent2 = vector_dc( "double", kronlen), colindices = vector_dc( SS$type, kronlen), rowpointers = vector_dc( SS$type, Xdim[1]*Ydim[1]+1), INTENT = c("r", "r", "r", "r", "r", "r", "r", "r", "r", "w", "w", "w", "w"), NAOK=getOption("spam.NAOK"), PACKAGE = SS$package) FUN <- match.fun(FUN) kronxy <- .newSpam( entries = FUN(z$ent1,z$ent2,...) ) ## slot(kronxy, "entries", check=FALSE) <- FUN(z$ent1,z$ent2,...) if (z$rowpointers[Xdim[1]*Ydim[1]+1]-1 < prod(Xdim,Ydim)) warning("Sparseness structure of 'kronecker(X,Y)' preseved when applying 'FUN'.", call. = FALSE) } kronxy <- .newSpam( entries = kronxy@entries, colindices = z$colindices, rowpointers = z$rowpointers, dimension = Xdim*Ydim) ## slot(kronxy, "colindices", check=FALSE) <- z$colindices ## slot(kronxy, "rowpointers", check=FALSE) <- z$rowpointers ## slot(kronxy, "dimension", check=FALSE) <- Xdim*Ydim # no need to use prod return(kronxy) } "kronecker.default" <- base::kronecker setGeneric("kronecker") setMethod("kronecker","spam", kronecker.spam) setMethod("kronecker",signature(X="spam",Y="spam"), kronecker.spam) setMethod("kronecker",signature(X="spam",Y="ANY"), kronecker.spam) setMethod("kronecker",signature(X="ANY",Y="spam"), kronecker.spam) spam/R/defunct.R0000644000176200001440000000140413536451707013200 0ustar liggesusers# HEADER #################################################### # This is file spam/R/defunct.R. # # It is part of the R package spam, # # --> https://CRAN.R-project.org/package=spam # # --> https://CRAN.R-project.org/package=spam64 # # --> https://git.math.uzh.ch/reinhard.furrer/spam # # by Reinhard Furrer [aut, cre], Florian Gerber [aut], # # Roman Flury [aut], Daniel Gerber [ctb], # # Kaspar Moesinger [ctb] # # HEADER END ################################################ validspamobject <- function(...) { .Defunct(new = 'validate_spam', package = 'spam', msg = "validspamobject() is defunct. Use validate_spam()") } spam/NEWS.md0000644000176200001440000003421413574427527012334 0ustar liggesusers# spam 2.5-1 BUG FIXES * fixing warning in linking of fortran code. # spam 2.5-0 SIGNIFICANT USER-VISIBLE CHANGES * improved examples for `spam_random()` and `eigen.spam()`. * Fortran code used by `eigen.spam()` for non-symmetric matrices is now stable. INTERNAL CHANGES * fixing real comparison warnings in Fortran. * removing remaining and unused print/count/timing variables in Fortran. * implement dimension upper bound for `eigen.spam()` due to BLAS/LAPACK routines, which are used in Arnoldi iteration (ARPACK). BUG FIXES * adjusting spam.Rmd vignette to pandoc2.8. * correct class checking for matrices. * cleaning and consolidation of init.c with spam64 (LTO's). # spam 2.4-0 INTERNAL CHANGES * cleaning GCC-10 Fortran warnings. # spam 2.3-0 NEW FEATURES * New function `spam_random()` to create a random spam matrix. SIGNIFICANT USER-VISIBLE CHANGES * Deprecated functions `spam.options()`, `spam.getOption()` are removed. * Deprecated function `validspamobject()` is now defunct. * `todo()` and `spam.history()` are removed. * `summary.spam()` prints whether it is a 32 or 64-bit spam object. INTERNAL CHANGES * Fortran modification to address LTO issues. * Not exported deprecated function `subset.rows.spam()` is now defunct. BUG FIXES * Dataset `UScounties.ndorder` contained no-zeros on the diagonal. Now entire diagonal is zero. # spam 2.2-2 BUG FIXES * in testthat/test-constructors.R, which uses `base::sample()` (http://developer.r-project.org/blosxom.cgi/R-devel/2019/02/26#n2019-02-26). # spam 2.2-1 SIGNIFICANT USER-VISIBLE CHANGES * New vignette including illustrations and examples * Improved documentation for covariance functions like `cov.exp()`. BUG FIXES * `det(spam(1))` bug fix & default of `diag.spam(x)` in `spam_diag()` removed. INTERNAL CHANGES * Spam fit for pkgdown website. * Replacing some internal functions by their primitive equivalent. # spam 2.2-0 SIGNIFICANT USER-VISIBLE CHANGES * Implementation of 'eigen.spam()' and 'eigen_approx()' to calculate eigenvalues and eigenvectors for sparse matrices. # spam 2.1-4 SIGNIFICANT USER-VISIBLE CHANGES * 'germany.plot' has new argument 'cex.main'. BUG FIXES * 'NAOK=TRUE' did not properly dispatch in all matrix multiplications. * '.newSpam()' was not always properly called, causing possible errors when creating empty 'spam' objects. INTERNAL CHANGES * Code cleaning and coherence improvements. # spam 2.1-2 SIGNIFICANT USER-VISIBLE CHANGES * In case 64bits are required, issues an error to load package 'spam64' first. * Minor fixes in help files and other documentation. INTERNAL CHANGES * Improved registering of compiled functions. * Compatibility with new versions of package 'testthat'. # spam 2.1-1 SIGNIFICANT USER-VISIBLE CHANGES * With the addon of the package spam64, we have truly 64 bits available! * Dependency on dotCall64. * Different option handling, we use now the classical R setting. For the moment, the old functionality throws a message but in upcoming versions we use `.Deprecated`. 'spam.options' -> 'options', 'spam.getOption' -> 'getOption' * 'validate_spam' superseeds 'validspamobject'. * Added the list of Fortran contributors. INTERNAL CHANGES * Many... many. More still to come. * Unit testing with testthat. * Change of archaic trig functions to standard. Minor edits to great circle dist. # spam 1.4-0 INTERNAL CHANGES * Fortran modification to address more pedantic compilations. # spam 1.3-0 BUG FIXES * Adding nonsparse to sparse matrices did not always dispatch properly and caused some errors. Thanks to Johan Lindström for pointing out. SIGNIFICANT USER-VISIBLE CHANGES * Help improvements * Added additional method dispatching for 'all.equal'. # spam 1.2-0 and 1.2-1 SIGNIFICANT USER-VISIBLE CHANGES * Renaming of demos from JSS10 paper. * Continuing to implement 'spam_xxx' function names: Like 'spam_rdist' there is now 'spam_diag'. * 'subset.rows.spam' deprecated. There is an internal function 'subset_rows.spam'. INTERNAL CHANGES * Ample minor modifications in 'DESCRIPTION' and 'NAMESPACE' for CRAN check conformity. * Elimination of a few unnecessary functions (not exported). * Minor modifications in tests. # spam 1.1-0 SIGNIFICANT USER-VISIBLE CHANGES * Upload of vignette linked to JSS15 paper. Related demos and tests. * "DUP=FALSE" is deprecated and will be disabled in future versions of R. All "DUP" arguments have been eliminated. You have to expect a slightly slower version of spam. # spam 1.0 and 1.0-1 * This version is up to 'DESCRIPTION' and its implied changes identical to 0.90-1. With the upcoming JSS article "Pitfalls in the implementation of Bayesian hierarchical modeling of areal count data. An illustration using BYM and Leroux models. " a "major" version jump is adequate. * Referencing to spam data through spam::... * Implemented `1.1.3.1 Suggested packages` approach. # spam 0.70/0.80/0.90/0.90-1 SIGNIFICANT USER-VISIBLE CHANGES * Introduction of many as('spam','...') functions. * Coercion function `as.vector` for spam objects. * Wrapper functions `spam_rdist` and 'spam_rdist.earth` for smooth use in `fields`. * The use of `update(A, B)` without assignment has been eliminated. This is one way to address the change in memory handling changes from R 3.0.2 to R 3.1.0. There is a slight overhead in memory. If this causes problems, let me know. * Adjustment of the license. NEW FEATURES * Arguments `diag` and `eps` in `nearest.dist` cause now an error. * Further augmented help pages. BUG FIXES * The demo now points to the new JSS article. INTERNAL CHANGES * Set 'structurebased=TRUE' for the demos. * Link to upcoming JSS article in one of the demos. * 'update.spam.chol.NgPeyton' preserves the structure (pointed out by Chris Paciorek), see above. * Using similar License approach as SparseM. New files `README`, `inst/0LICENSE`. * File renaming (OChangeLog -> 0ChangeLog) * Adjusted error messages for precmat.RW2 # spam 0.60-0 SIGNIFICANT USER-VISIBLE CHANGES * Using the flag 'structurebased', the behavior of spam is now more consistent. * "Arith", "Compare", "Logic" (getGroupMembers("Ops")) have now a consistent behavior. NEW FEATURES * Few new S3 functions for simplicity: 'var.spam', 'eigen.spam', ... * New constructor functions 'colindices<-' etc. Maybe additional tests may be required. * Operators from 'Arith' obey now the structure based calculation. BUG FIXES * 'inefficiencywarning' passes message correctly. INTERNAL CHANGES * many more spam/tests/*. * Consistent use of 'spam' and 'vector' siglist for 'Ops'. * Minor cleaning of Fortran code. * Renaming/restructuring/cleaning of files... * Fortran arguments are copied when updating the cholesky structure. # spam 0.50-0 SIGNIFICANT USER-VISIBLE CHANGES * Using the flag 'structurebased=FALSE', the behavior of spam is now much, much closer to regular matrix calculations. This is illustrated when calculating gamma of a sparse matrix. * Along the same lines, the flag 'NAOK=TRUE' allows the use of the "not finite numbers" (NA, NaN, Inf). We have tested many, many functions but full fledged use is not yet guaranteed. * Currently, we can still guarantee backwards compatibility... NEW FEATURES * New functions 'crossprod' and 'tcrossprod' as well as according method definitions. * New constructor functions 'rowpointers<-' etc. * Better option handling. The option 'safemode' is now 'safemodevalidity'. Additionally, new option 'NAOK'. * Help pages have been improved. * Operators from 'Summary' and 'Math' obey now the structure based calculation. ('Math2' inherently does). BUG FIXES * rmvnorm.[].const now work properly for any number of constraints and n. * Assignment handles properly recycling. * todo() now works properly. INTERNAL CHANGES * eliminated {d,i}check by equivalent coercion. * Consistent use of NAOK in Fortran calls. * Minor cleaning of Fortran code. * Renaming/restructuring of files... # spam 0.42-0 NEW FEATURES * More consistent handling of subsetting. Warning is issued if subsetting with NA BUG FIXES * Fixed several issues when rowsubsetting... INTERNAL CHANGES * Additional tests for positive definiteness in 'chol'. # spam 0.41-0 NEW FEATURES * Functions grid_trace2() received more functionality. BUG FIXES * Eliminated bug in cov.mat(). Pointed out by Joshua French. INTERNAL CHANGES * Updated DESCRIPTION: added Florian Gerber [ctb]. * Minor code and help cleanup. Additional testing files. File header edits. * Addressed Rdevel CMD check --as-cran Notes, especially workaround for DUP=FALSE. # spam 0.40-0 BUG FIXES * A severe bug in subsetting a spam object with a nx2 matrix crept in spam in version 0.29-3. Thanks to Andrew Hong and Beat Briner for pointing out. * To simplify communication, we have switched increased the tenth version number. * All other changes are of cosmetic nature. # spam 0.30-x SIGNIFICANT USER-VISIBLE CHANGES * Added several plots to visualize several MCMC chains ('grid_trace2', 'grid_zoom', ...). NEW FEATURES * New function 'germany.plot' to draw the landkreise. ('map.landkreis' is now obsolete). * Switched from 'tim.colors' to 'colorRampPalette' in 'germany.plot'. * Metadata in 'germany.info', polygon definitions in 'germany.poly' ('germany' kept for backwards compatibility). INTERNAL CHANGES * Switched to mercurial for maintaining the package. * Updated ChangeLog file (hg log). * Increased dependency to >= R 2.15. * Minor code and help cleanup. # spam 0.29-0, 0.29-1, 0.29-2, 0.29-3 SIGNIFICANT USER-VISIBLE CHANGES * There is a generic conflict with 'backsolve' between spam and other packages (e.g., bdsmatrix). To avoid the issue, we use the standard generic implemented in 'methods' which requires an additional argument for version 0.29-0 (see also PR#14883). However to maintain backwards compatibility with packages that depend on spam, this was reverted in 0.29-1. Currently, this conflict is not properly solved. I propose to load 'spam' first then the other packages, followed by manually calling: * setMethod("backsolve","spam.chol.NgPeyton",backsolve.spam) setMethod("backsolve","spam",backsolve.spam) Stay tuned... * Calls like: * mat <- diag.spam(4) diag(mat[-1, ]) <- 3 diag.spam(mat[ , -1]) <-2 now work. They are, however, somewhat inefficient. 'toeplitz.spam' is to be prefered. Pointed out by Florian Gerber. * The Gibbs sampler in the demo article-jss-example2 contains several bugs, pointed out by Steve Geinitz and Andrea Riebler. I'll post an updated sampler in a future release. NEW FEATURES * New functions 'rmvnorm.const', 'rmvnorm.prec.const' and 'rmvnorm.canonical.const' to draw constrained multivariate normal variates. * New functions 'precmat' (wrapper to), 'precmat.RW1', 'precmat.RW2', 'precmat.season', 'precmat.IGMRFreglat' and 'precmat.IGMRFirreglat' to create precision matrices for IGMRF. * New methods 'rowSums', 'colSums' and 'rowMeans', 'colMeans' for 'spam' objects. * New methods 'head' and 'tail' for 'spam' and 'spam.chol.NgPeyton' objects. * New method 'chol2inv' for 'spam' object. * New option 'inefficiencywarning': handling of warnings issued in case of an inefficient calculation. * New option 'structurebased': should operations be performed on the nonzero entries or on including the zeros. Classical example: what should the cosine of a sparse matrix look like? In the near future, all operations from Math and Ops will include this option. Some loss of backwards compatibility might be lost in the future. INTERNAL CHANGES * New much faster approach to extract rows. For not too sparse large matrices improvements over two orders of magnitudes are achieved. * Elininated '.Internal()' calls that induce a 'Note' on CRAN checks. This also implied a minor rewrite of 'image.spam'. * Minor code improvements. * Eliminated non-API calls (29.1). * Rewritten .C("bincode",...) call as suggested by Brian Ripley (29.2). BUG FIXES * Bug fix that occures when multiplying elementwise matrices that have non-intersecting structures (pointed out by Corentin Barbu). * Bug fix in triangular backsolves involving 'spam' objects and rhs matrices. * Bug fix in triangular backsolve causing errors on some architectures. # spam 0.28 NEW FEATURES * New function 'cleanup' (suggested by Simon Barthelme). * Extending help files. * Improved functionality of 'isSymmetric'. INTERNAL CHANGES * Proper storage of data files. * Cleaning up argument names within spam functions. * Cleaning up old Fortran code, i.e., eliminating unnecessary subroutines and write calls. BUG FIXES * Bug fix that may occure when extracting zero elements (pointed out by Corentin Barbu). # spam 0.27 NEW FEATURES * Requires now R2.10 and higher. * Functions to create Toeplitz and circulant matrices. * Function to create precision matrices for gridded GMRF. * Improvements in the mle.* functions. * Method diff for sparse matrices (suggested by Paul Eilers). * Improvement of help pages. * Eliminated some help aliases to base functions (for which no 'usage' is given). INTERNAL CHANGES * Change to iL coding. * Start to using 'identical'. * Code cleaning due to requirement of R2.10 and higher. BUG FIXES * Bug fix in as.spam.list (thanks to Paul Eilers). * Bug fix in demo(spam) (thanks to Thomas Gsponer). # spam 0.24, 0.25 and 0.26 * Devel versions, not released. # spam 0.23 NEW FEATURES * Further improved versions of demos. * Some improvements to meet Rd standards. Adjustments for future R versions. # spam 0.22 NEW FEATURES * Improved versions of demos. Synchronized with the JSS article. * Additional changes and improvements in the help files (thanks to Steve Geinitz). # spam 0.21 NEW FEATURES * New NEWS file, to work better with news() command. The previous is available under ONEWS. * New functions bandwidth, permutation, mle[.nomean][.spam], neg2loglikelihood[.spam]. * Renamed adiag.spam to bdiag.spam. * Cleaned up argument naming with the rmvnorm.* suite. INTERNAL CHANGES * Various Fortran code, R code and help file improvements. BUG FIXES * Minor change in one of the demos (solves a 64bit issue). spam/MD50000644000176200001440000002416713574471023011542 0ustar liggesusers1014301a0038689eb034764e91f202c6 *DESCRIPTION 832b94371b361d542c170b3a2b17cc61 *LICENSE 3f6c306a0c66ee9b588beb0e50c7bf16 *NAMESPACE b076b856bb74a14d08e7d77328eed402 *NEWS.md 7afb00ee63ac82fe2e3cf298e69d3797 *R/apply.R a1135682763f8c8277a299329319adf5 *R/constructors.R b47677289f34a2049434489a966a16c4 *R/covmat.R 69f24dc2c9eadb13a6e6a884a15ef031 *R/definitions.R 087ac1a5bdf2d46fc96118ba135d5eae *R/defunct.R d3fa37b5298f6d58354be30dc1f912d5 *R/diff.R 6e66551357a4de2d430dcc7d565b44d0 *R/dim.R 95625be770773014a75b6618488ae71d *R/dist.R 4bf0b9334e939a81ee85b5bb9829f84a *R/eigen.R 76929b1b9c29daa57c1f2c537c4b3cb0 *R/foreign.R 410caf26ab13ffa7b0a246f817f35947 *R/helper.R d732392d11b5b2cb5ae1f0bd0d30524e *R/kronecker.R e8b40e07631a53e394b494436e2a4de4 *R/math.R 0390ce0616e6d2e0c52ff3149e1fa7fb *R/mle.R 2e8bd316ce737cdeca5f59b4ceb5f5a2 *R/norm.R a3a947ccd4cf5819dc80519b41af7436 *R/permutation.R 2a61076cb1aaaedd4ba2f9a29bb0b005 *R/plotting.R 188e4a17c438d9f2b8485172a6e0017e *R/precmat.R 95ec44a36a6c45432195797a67c92340 *R/profile.R bb338c9beca0b88e4b57126f1f6dfb5a *R/random.R 06eb70b1301c8741241178c46bc1ebd6 *R/rep_len64.R d95c762ac60f8eb85c9d3133833fc2e0 *R/rmvnorm.R f5a47050fdbedbae39e9d7b1cb5b16df *R/rowcolstats.R bbdeb355315602d6941c5c5be5454424 *R/s3only.R 38b65830865b39d6f7a37569a76c785d *R/s4coerce.R 04fb9932822c345b382b67f52426020b *R/spam_solve.R 05dc924bcce7f68bb6abb02ae4ea85a2 *R/spamlist.R b1ea7688011cb1f74fbce42e9a69fb99 *R/subset.R 4aa3215dbd99fcf6fd896a4c6a37186f *R/summary.R 99322d65ca866ac8a7552c0b8fbbad24 *R/tailhead.R 6b6222ff3e6896f8f9b765cc1dcd0808 *R/tcrossprod.R a7c4ab607661cc2cfe23630f19167e32 *R/toepliz.R e07b0b4d0a5576966d50914350a9f2b0 *R/xybind.R 239f312af7e1e1f7cbbb00fc3191994b *README 3c451aae7a7a716896ebee46c6b6f094 *build/vignette.rds c50879b823669ba5e0427e9ced418d04 *data/Oral.rda db4186b5cd751ba759e1d1a766b02588 *data/UScounties.ndorder.rda bb7c9aa74503ca1aca57f5204a792262 *data/UScounties.storder.rda 489f6da5e1ae79ec9036948db29af479 *data/USprecip.rda 9065b4d1e091328000e7270771a227be *data/germany.rda f7f600157daed98d9a3f677575d7bf81 *demo/00Index bb041250dbeb353f62fb0de999efe162 *demo/article-jss-example1.R 7c818cfae73173703f2533facc858f5a *demo/article-jss-example2.R c0e45d6e968acc4b6e5c1383c2a0b7b0 *demo/article-jss.R 0681fbf9205db15ba1e7529e5e693d89 *demo/cholesky.R b88e8d27bb918947c6f4091eaf66e79d *demo/jss10-example1.R 3a33e44d4059a1f350c4ac961bfc9359 *demo/jss10-example2.R b26b5ce4b394fe463046a32737d0562f *demo/jss15-BYM.R ee8ae36fc5ba86eb164515b261d14ccb *demo/jss15-Leroux.R f8de54c7383772f165d062b5421643de *demo/spam.R b21ed11314af2f8b71d2009a1802b876 *demo/timing.R a8073fc0e9c667b814bcf0e5ea35cf96 *inst/0LICENSE 4360bfaec2dab3733a2465f8802cd01c *inst/CITATION 0f7ff8c0275da9085576b25fa7437bfd *inst/demodata/germany.adjacency 699dbb4ab499aefc61c71997cc1a60e3 *inst/doc/jss15.pdf b9f40f1e8d6b44aec98832e5f215a20c *inst/doc/jss15.pdf.asis 5b020759fdd59710c86b26421fdd5159 *inst/doc/spam.R 1fb0e3b7f55ae8edc1f65bf52dd50e26 *inst/doc/spam.Rmd 48226af48f709256c8ee49ace3c4d5bc *inst/doc/spam.pdf 0c089210340bad63296be8dc7586f563 *man/Oral.Rd 57f24377459aa656a145ce466de1ab9c *man/UScounties.Rd 36946542e94cbae4beb67b44b9617468 *man/USprecip.Rd acb1aec430d95c1d89fae4eb3656d047 *man/adjacency.Rd 8db9fa924a508e8f50ba9c59247bb8f5 *man/allequal.Rd 16da1ae2e0ca3212345064f80b7273aa *man/apply.Rd 3044ae22bd0f371b3fdff344b6458e92 *man/bandwidth.Rd 954de7b721c80795585012fd39604ff9 *man/bdiag.Rd 5f7e18e5252ea3fa270db1902e066fa2 *man/chol.Rd a38190f9cc2b79de7887b89a5ad023e2 *man/circulant.Rd e096cd98e67822274e03b9745d6e4b3a *man/cleanup.Rd f319f7a3de756f37714b42f52c1e47fa *man/coerce.Rd 6fa77582e2cce3ba825f286c9e0cc734 *man/coercion.Rd 2410005f19ffcb79ec4e85529cd8ba3d *man/complexity.Rd afd94e793ee059d9a3627cc36d1ee284 *man/constructors.Rd 8ce638cfb0778867747ff14156f03c83 *man/cov.Rd 8fd0538f8da81e2172681f5aabda3541 *man/crossprod.Rd 4fae4b3e5f9d23ef0e78ae5e3be1a18c *man/defunct.Rd 9fdab96019f6f48cfbcf0c283257b11e *man/det.Rd 225a3a826b752f344344dddd768c7fab *man/diag.Rd 56323f60d04a6faaf933b50f286b6516 *man/diff.Rd c319e199322b589958bff56dc2337303 *man/dim.Rd ec44d50a7bc575f221dd0b36e4262a0f *man/display.Rd 7a591439fd0f16e200f7cde51ab284b1 *man/eigen.Rd a53d5a86b93f48071c33ff081684c3fe *man/foreign.Rd d207518254bf3247561cee558cd1e77a *man/germany.Rd d7542811cfece44bd99040dd1680c1c2 *man/germanydata.Rd c6ac4b52ac66e7d5570fdeb1a0662d02 *man/grid_trace2.Rd fc8d0d431308a39bcd610327c69c4844 *man/grid_zoom.Rd 4619d9b254a74fbbe71e36e7156c1220 *man/headtail.Rd 6850ac296eee748c53093c0b389b34ff *man/image.Rd 1f28b86a75e0ce2d212a199e4cae5ecf *man/import.Rd 5ffd7f25838e98e0a973089902e61b7e *man/isSymmetric.Rd 3acf08ba1d003ecce5648eaa118cbab8 *man/kronecker.Rd dd68c283bff77209fbb83183f9b9ee71 *man/landkreis.Rd 04a6338a3efbccbd9676db6f9764d695 *man/large_matrix.Rd 2cdc5b182de8cbc4cf28f72ce9c6a480 *man/lu.tri.Rd 4a820e10f78af441d1d9c0b86ebfa7f6 *man/makeprec.Rd aa156b6cdff33d2764ba4221e82cb768 *man/math.Rd 530176d9dc29af5e7f4474e7e244a491 *man/math2.Rd 91b06f56c038ea26b0a699c07cf309cb *man/methods.Rd 58851f2331c4dcff4e1042dd0b04c090 *man/mle.Rd 601c921714e32f4edd4211e82ff1eb53 *man/nearestdist.Rd ecff763aae9b50152ba96175ffdacd0e *man/operations.Rd 6661fec0442bf10003c71a8bfb979da8 *man/options.Rd e286bd5032fc679f8f315e7643dc1968 *man/ordering.Rd 2e498c5b52a47da5837eddd185c48e8f *man/pad.Rd 4be722f10f93c789ee34e885e4b182d6 *man/permutation.Rd 201eaf143283ff106e59deaeffe2fd5c *man/powerboost.Rd 718cfa69df863510df1afdd9db0d8ccd *man/precmat.Rd 552d4c686e0a624c598706f4843c90a0 *man/print.Rd 509568bd523346b9520f25c11c9bbecb *man/random.Rd b12d75ef40563fba431075ac8a506705 *man/rdist.Rd 9d3c3ba20ea5c733e2d5aa391bc08219 *man/rmvnorm.Rd f1bc0dc383eafff15bccc92b81e424ff *man/rmvnorm.const.Rd d4480b548ea11efdf0f4fa180506a82d *man/rowcolstats.Rd 889ac057db97faa1ae97430a19a8819b *man/s3only.Rd b31a741f763b0722fcb60b6d3b80c164 *man/solve.Rd 093cfb4fd93f8697fc91a04eb58057eb *man/spam-class.Rd 7f35ad88a533f0d0d37ef98919cd37d3 *man/spam-package.Rd f6f39c3dc14684911cec0b5e77339ddf *man/spam.chol.NgPeyton-class.Rd 7da995f061e99b8ef354c0978b37cb18 *man/spam.creation.Rd f4b8bfae738a2b94c868eca0ae3e740a *man/spam.internal.Rd 789a3403f4dce3ed7a2e894776869092 *man/summary.Rd bca390c22fd8dd0783e213e02da662f2 *man/toeplitz.Rd ecb1ec430d099035dd16ef309c5e2096 *man/triplet.Rd 96ecc51b48a10caaa91af617897ccfc7 *man/validate_spam.Rd fd19dcdc82b3a9025b93e9a1455a66d6 *man/version.Rd dfe284d255d6052be85e3c5ef3fdbe44 *man/xybind.Rd 5a05158f37da8ce760e7ce721d3d5021 *src/Makevars 861edb29547b6c79adefafdda07a6e29 *src/bckslvmodified.f 1fc67f26649424eb3fc51e95ad7dc86c *src/cholmodified.f be2695f1ab6d3f3ecbb08977f7c5595a *src/dgetv0.f 880bdb9d2a099ec291536012b34f4bc7 *src/dist.f d2ded21b486a168271d1ee50ee966896 *src/dn_ARPACK.f 7c9224ee4098991ca74424103b31790a *src/dn_eigen.f c993e6759bcb42dd8883a8cdb672af9d *src/ds_ARPACK.f 2f5f102f8d096af9a916435ee7441a49 *src/ds_eigen.f 55b566e7b6ad5e4e36a6491d3e50837c *src/fromsparsekit.f 266165fff22c76bddc1eb58624c286fc *src/init.c 74a55a66d85ccba175fea259b7f34ff1 *src/kronecker.f da6e126c216dd8206ae92f6049c8fc40 *src/permutation.f 130ded550da1c399d446daec86d587c9 *src/rowcolstats.f 7544219d48d4721db03a8fa99e0f228d *src/spamown.f ef45adb64b908fe0102e60c978aa16c8 *src/spamown2.f 85a58bab5f6add47cd053b86c47de3d9 *src/xybind.f e9ed7e508d0bcb4261482d833c639478 *tests/demo_article-jss-example1.R 9afdc1c5e73bfadd60a581537c7fce77 *tests/demo_article-jss-example1.Rout.save d368f0307a14a6949f968f484aa0f3de *tests/demo_article-jss-example2.R c6b5cfb7a94d2e74b7096d70f72d8467 *tests/demo_article-jss-example2.Rout.save 5d9b0d456cf006ee8feae75d0c343f2b *tests/demo_article-jss.R 3f3a4a077c775f4d6fdbb966cf598d34 *tests/demo_article-jss.Rout.save d7bf32a4ce7a5823913fba73ecca11c1 *tests/demo_cholesky.R a6caf978ba27c9e3153ae99eceeb8a69 *tests/demo_cholesky.Rout.save fb9b3a26bd5dadba56cd62e22f3b8c58 *tests/demo_jss15-BYM.R 377a7c8d0aded3fd0d98fd04cfd7ac6e *tests/demo_jss15-BYM.Rout.save c0e3ea822a77a6de20914dcc37abba50 *tests/demo_jss15-Leroux.R cf7da8da20a53142ce03b4cc4d8a123a *tests/demo_jss15-Leroux.Rout.save 2c357144205c377e18a40afa3be913a3 *tests/demo_spam.R 69686eebae32b88915cbb997769947eb *tests/demo_spam.Rout.save 04f2a1b310d4fa550efea5cff6be2af2 *tests/demo_timing.R d223fbabc8377f6f701d3ea9c2686cb1 *tests/demo_timing.Rout.save d6f89b6ca5cc49a70cb2e3c6f1098cc9 *tests/jss_areal_counts.R 28a4dd6f0371ca69779ad1df7cdca3c2 *tests/jss_areal_counts.Rout.save d54561804ff9c61fff72399d03d535e2 *tests/testthat.R 099fb8b8d0ecfd5cea77c007f1cce0a6 *tests/testthat/helper.R 0b0f38ea5bf7e0f74efa2b2b32322010 *tests/testthat/test-constructors.R e410684278f23132a0c26b7fd695ec05 *tests/testthat/test-covmat.R d16e8f68874e8bd82331e23c7e465f8a *tests/testthat/test-crossprod.R 9a8603e656169ff4852e55cb8f556454 *tests/testthat/test-diff.R e57a02c929f6f88637019b69a6ee03ce *tests/testthat/test-dim.R 739898c67fecaf9a3508a928bd446391 *tests/testthat/test-dist.R 22fe57e3609341d6a6b9d44849ee6301 *tests/testthat/test-eigen.R bc325e933e8f0b4cf2937c7f9bf891a4 *tests/testthat/test-helper.R 16340ce345da7c893b74af546de9e69e *tests/testthat/test-kronecker.R 9f1ee2b9e980eabbb0202d13e23a72fc *tests/testthat/test-math.R 786e3858a0b26077552169eb8b1d476e *tests/testthat/test-mle.R 5765be3e3674263bf5996e0aa53b2cd1 *tests/testthat/test-ops.R 461cf34f574cd35aab717c10090962dc *tests/testthat/test-overall.R b5d83665953a49176b1cd0e1e8a23c44 *tests/testthat/test-permutation.R 70d564a05bdc74154dfd00895641210f *tests/testthat/test-profile.R 64c96b2500c422563e90e15d00d0f6a9 *tests/testthat/test-random.R 6b0a4526cc7cb76a3e9d3b39bd3aff6d *tests/testthat/test-rep_len64.R 89a94aeab660d5aa364e9c8b0f52a9f5 *tests/testthat/test-rowcolstats.R 4f638d4aa878356795f25bc8a03796c0 *tests/testthat/test-solve.R 45372f9499d9eddc855ac870dadfcb1f *tests/testthat/test-spamlist.R 21138b7f446d9f6d5a604cf669289487 *tests/testthat/test-subset.R 051a17a655a38a4593b83f6712c85b77 *tests/testthat/test-xybind.R ab0b6d120f75b71055dd9a3b52b2d756 *vignettes/figures/fig_ch2_factors.png 6cd88d497999be2ce3739776a5c57605 *vignettes/figures/ill.png 10cfa74b63bcc0ba5be413d846aad883 *vignettes/figures/tree.png b9f40f1e8d6b44aec98832e5f215a20c *vignettes/jss15.pdf.asis 1fb0e3b7f55ae8edc1f65bf52dd50e26 *vignettes/spam.Rmd 027cd28ed70ee56e6d45b8abfe8c86b8 *vignettes/spam.bib spam/inst/0000755000176200001440000000000013574431374012202 5ustar liggesusersspam/inst/doc/0000755000176200001440000000000013574431374012747 5ustar liggesusersspam/inst/doc/jss15.pdf.asis0000644000176200001440000000011213562501663015333 0ustar liggesusers%\VignetteIndexEntry{JSS - Areal count data} %\VignetteEngine{R.rsp::asis}spam/inst/doc/spam.R0000644000176200001440000000614513574431367014042 0ustar liggesusers## ----setup, include = FALSE---------------------------------------------- knitr::opts_chunk$set( collapse = TRUE, comment = "#>", # fig.width = 6, fig.height = 6, fig.align = "center" ) options(digits = 3) ## ----loadpkgs, echo=FALSE, eval=TRUE, message=FALSE---------------------- library("spam") ## ----echo=TRUE, eval=FALSE, message=FALSE-------------------------------- # install.packages("spam") # # library("spam") ## ----trivial------------------------------------------------------------- Fmat <- matrix(c(3, 0, 1, 0, 2, 0, 1, 0, 3), nrow = 3, ncol = 3) Smat <- as.spam(Fmat) ## ----operations---------------------------------------------------------- Fmat Smat Smat %*% t(Smat) Fmat %*% t(Smat) ## ----nonspam------------------------------------------------------------- rep(1, 3) %*% Smat ## ----diffbehaviour------------------------------------------------------- range(Fmat) range(Smat) ## ----displ1-------------------------------------------------------------- Smat ## ----displ2-------------------------------------------------------------- diag.spam(100) ## ----disp3--------------------------------------------------------------- str(Smat) ## ----disp4--------------------------------------------------------------- summary(Smat) ## ----disp5, echo=FALSE, warning=FALSE------------------------------------ nz <- 2^12 Smat1 <- spam(0, nz, nz) Smat1[cbind(sample(nz, nz), sample(nz, nz))] <- rnorm(nz) tmp <- round(summary(Smat1)$density, 3) ## ----disp6, echo=FALSE, warning=FALSE, fig.cap = '\\label{fig:display_spam}Sparsity structure of sparse matrices.'---- par(mfcol=c(1,2),pty='s',mai=c(.8,.8,.2,.2)) display(Smat) display(Smat1) ## ------------------------------------------------------------------------ i <- c(2, 4, 4, 5, 5) j <- c(1, 1, 2, 1, 3) A <- spam(0, nrow = 5, ncol = 5) A[cbind(i, j)] <- rep(0.5, length(i)) A <- t(A) + A + diag.spam(5) A U <- chol(A) ## ----tree, echo=FALSE, results = 'markup', out.width='40%', fig.show='hold', warning=FALSE, fig.cap='\\label{fig:tree}On the left side the associated graph to the matrix $\\boldsymbol{A}$ is visualized. The nodes of the graph are labeled according to $\\boldsymbol{A}$ (upright) and $\\boldsymbol{P}^T\\boldsymbol{A}\\boldsymbol{P}$ (italics). On the right side the sparsity structure of $\\boldsymbol{A}$ and $\\boldsymbol{P}^T\\boldsymbol{A}\\boldsymbol{P}$ (top row) and the Cholesky factors $\\boldsymbol{R}$ and $\\boldsymbol{U}$ of $\\boldsymbol{A}$ and $\\boldsymbol{P}^T\\boldsymbol{A}\\boldsymbol{P}$ respectively are given in the bottom row. The dashed lines in $\\boldsymbol{U}$ indicate the supernode partition.'---- knitr::include_graphics(c('figures/tree.png', 'figures/ill.png')) ## ----fillin, echo=FALSE, fig.show='hold', warning=FALSE, fig.cap='\\label{fig:ch2:factor}Sparsity structure of the Cholesky factor with MMD, RCM and no permutation of a precision matrix induced by a second-order neighbor structure of the US counties. The values *nnzR* and *fillin* are the number of non-zero elements in the sparsity structure of the factor and the fill-in, respectively.'---- knitr::include_graphics(c('figures/fig_ch2_factors.png')) spam/inst/doc/spam.Rmd0000644000176200001440000004426113572142203014346 0ustar liggesusers--- title: "Illustrations and Examples" author: "Reinhard Furrer, Roman Flury" date: "`r Sys.Date()`" output: rmarkdown::pdf_document: fig_caption: yes number_sections: true toc: true toc_depth: 2 citation_package: natbib header-includes: - \usepackage{bm} - \usepackage{setspace}\onehalfspacing - \usepackage[labelfont=bf]{caption} - \usepackage{natbib} - \usepackage{hyperref} bibliography: spam.bib vignette: > \usepackage[utf8]{inputenc} %\VignetteEngine{knitr::rmarkdown} %\VignetteIndexEntry{`spam`, a SPArse Matrix package} %\VignetteEncoding{UTF-8} --- ```{r setup, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>", # fig.width = 6, fig.height = 6, fig.align = "center" ) options(digits = 3) ``` ```{r loadpkgs, echo=FALSE, eval=TRUE, message=FALSE} library("spam") ``` # Rational for spam At the core of drawing multivariate normal random variables, calculating or maximizing multivariate normal log-likelihoods, calculating determinants, etc., we need to solve a large (huge) linear system involving a variance matrix, i.e., a symmetric, positive definite matrix. Assume that we have such a symmetric, positive definite matrix $\boldsymbol{Q}$ of size $n\times n$ that contains many zeros (through tapering, @Furr:Gent:Nych:06, @Furr:Beng:07, or through a Markovian conditional construction). Typically, $\boldsymbol{Q}$ contains only $\mathcal{O}(n)$ non-zero elements compared to $\mathcal{O}(n^2)$ for a regular, **full** matrix. To take advantage of the few non-zero elements, special structures to represent the matrix are required, i.e., only the positions of the non-zeros and their values are kept in memory. Further, new algorithms work with these structures are required. The package `spam` provides this functionality, see @Furr:Sain:10 for a detailed exposition. # A Simple Example This first section illustrates with a simple example how to work with `spam`. Within a running R we install and load the current `spam` version from CRAN. ```{r echo=TRUE, eval=FALSE, message=FALSE} install.packages("spam") library("spam") ``` We create a trivial matrix and "coerce" it to a sparse matrix. ```{r trivial} Fmat <- matrix(c(3, 0, 1, 0, 2, 0, 1, 0, 3), nrow = 3, ncol = 3) Smat <- as.spam(Fmat) ``` `spam` is conceptualized such that for many operations, the user proceeds as with ordinary full matrices. For example: ```{r operations} Fmat Smat Smat %*% t(Smat) Fmat %*% t(Smat) ``` Hence, the user should not be worried which objects are sparse matrices and which are not. Of course not all operations result in sparse objects again, ```{r nonspam} rep(1, 3) %*% Smat ``` However, other operations yield to different results when applied to full or sparse matrices ```{r diffbehaviour} range(Fmat) range(Smat) ``` # Creating Sparse Matrices The implementation of `spam` is designed as a trade-off between the following competing philosophical maxims. It should be competitively fast compared to existing tools or approaches in R and it should be easy to use, modify and extend. The former is imposed to assure that the package will be useful and used in practice. The latter is necessary since statistical methods and approaches are often very specific and no single package could cover all potential tools. Hence, the user needs to understand quickly the underlying structure of the implementation of `spam` and to be able to extend it without getting desperate. (When faced with huge amounts of data, sub-sampling is one possibility; using `spam` is another.) This philosophical approach also suggests trying to assure `S3` and `S4` compatibility, @Cham:93, see also @Luml:04. `S4` has higher priority but there are only a handful cases of `S3` discrepancies, which do however not affect normal usage. To store the non-zero elements, `spam` uses the "old Yale sparse format". In this format, a (sparse) matrix is stored with four elements (vectors), which are (1) the nonzero values row by row, (2) the ordered column indices of nonzero values, (3) the position in the previous two vectors corresponding to new rows, given as pointers, and (4) the column dimension of the matrix. We refer to this format as compressed sparse row (CSR) format. Hence, to store a matrix with $z$ nonzero elements we thus need $z$ reals and $z+n+2$ integers compared to $n \times n$ reals. Section Representation describes the format in more details. The package `spam` provides two classes, first, `spam` representing sparse matrices and, second, `spam.chol.NgPeyton` representing Cholesky factors. A class definition specifies the objects belonging to the class, these objects are called slots in R and accessed with the `@` operator, see \citet{Cham:93} for a more thorough discussion. The four vectors of the CSR representation are implemented as slots. In `spam`, all operations can be performed without a detailed knowledge about the slots. However, advanced users may want to work on the slots of the class `spam` directly because of computational savings, for example, changing only the contents of a matrix while maintaining its sparsity structure, see Section Tips. The Cholesky factor requires additional information (e.g., the used permutation) hence the class `spam.chol.NgPeyton` contains more slots, which are less intuitive. There are only very few, specific cases, where the user has to access these slots directly. Therefore, user-visibility has been disregarded for the sake of speed. The two classes are discussed in the more technical Section Representation. # Displaying As seen in Section A Simple Example, printing small matrices result in an expected output, i.e., the content of the matrix plus a line indicating the class of the object: ```{r displ1} Smat ``` For larger objects, not all the elements are printed. For example: ```{r displ2} diag.spam(100) ``` The size of the matrix when switching from the first printing format to the second is a `spam` option, see Section Options. Naturally, we can also use the `str` command which gives us further insight into the individual slots of the `spam` object: ```{r disp3} str(Smat) ``` Alternatively, calling `summary` gives additional information of the matrix. ```{r disp4} summary(Smat) ``` `summary` itself prints on the standard output but also returns a list containing the number of non-zeros (`nnz`) and the density (`density`) (percentage of `nnz` over the total number of elements). Quite often, it is interesting to look at the sparsity structure of a sparse matrix. This is implemented with the command `display`. Again, depending on the size, the structure is shown as proper rectangles or as points. Figure \ref{fig:display_spam} is the result of the following code. ```{r disp5, echo=FALSE, warning=FALSE} nz <- 2^12 Smat1 <- spam(0, nz, nz) Smat1[cbind(sample(nz, nz), sample(nz, nz))] <- rnorm(nz) tmp <- round(summary(Smat1)$density, 3) ``` ```{r disp6, echo=FALSE, warning=FALSE, fig.cap = '\\label{fig:display_spam}Sparsity structure of sparse matrices.'} par(mfcol=c(1,2),pty='s',mai=c(.8,.8,.2,.2)) display(Smat) display(Smat1) ``` Additionally, compare Figures of this document. Depending on the `cex` value, the `image` may issue a warning, meaning that the dot-size is probably not optimal. In fact, visually the density of the matrix `Smat1` seems to be around some percentage whereas the actual density is `r tmp`. The function `image` goes beyond the structure of the matrix by using a specified color scheme for the values. Labels can be added manually or with `image.plot` from the package `fields`. # Solving Linear Systems To be more specific about one of `spam`'s main features, assume we need to calculate $\boldsymbol{A}^{-1}\boldsymbol{b}$ with $\boldsymbol{A}$ a symmetric positive definite matrix featuring some sparsity structure, which is usually accomplished by solving $\boldsymbol{A}\boldsymbol{x}=\boldsymbol{b}$. We proceed by factorizing $\boldsymbol{A}$ into $\boldsymbol{R}^T\boldsymbol{R}$, where $\boldsymbol{R}$ is an upper triangular matrix, called the Cholesky factor or Cholesky triangle of $\boldsymbol{A}$, followed by solving $\boldsymbol{R}^T\boldsymbol{y}=\boldsymbol{b}$ and $\boldsymbol{R}\boldsymbol{x}=\boldsymbol{y}$, called forwardsolve and backsolve, respectively. To reduce the fill-in of the Cholesky factor $\boldsymbol{R}$, we permute the columns and rows of $\boldsymbol{A}$ according to a (cleverly chosen) permutation $\boldsymbol{P}$, i.e., $\boldsymbol{U}^T\boldsymbol{U}=\boldsymbol{P}^T\boldsymbol{A}\boldsymbol{P}$, with $\boldsymbol{U}$ an upper triangular matrix. There exist many different algorithms to find permutations which are optimal for specific matrices %tridiagonal matrices finite element/difference matrices defined on square grids or at least close to optimal with respect to different criteria. Note that $\boldsymbol{R}$ and $\boldsymbol{U}$ cannot be linked through $\boldsymbol{P}$ alone. Figure \ref{fig:ill} illustrates the factorization with and without permutation. For solving a linear system the two triangular solves are performed after the factorization. The determinant of $\boldsymbol{A}$ is the squared product of the diagonal elements of its Cholesky factor $\boldsymbol{R}$. Hence the same factorization can be used to calculate determinants (a necessary and computational bottleneck in the computation of the log-likelihood of a Gaussian model), illustrating that it is very important to have a very efficient integration (with respect to calculation time and storage capacity) of the Cholesky factorization. In the case of GMRF, the off-diagonal non-zero elements correspond to the conditional dependence structure. However, for the calculation of the Cholesky factor, the values themselves are less important than the sparsity structure, which is often represented using a graph with edges representing the non-zero elements or using a "pixel" image of the zero/non-zero structure, see Figure \ref{fig:tree}. ```{r } i <- c(2, 4, 4, 5, 5) j <- c(1, 1, 2, 1, 3) A <- spam(0, nrow = 5, ncol = 5) A[cbind(i, j)] <- rep(0.5, length(i)) A <- t(A) + A + diag.spam(5) A U <- chol(A) ``` ```{r tree, echo=FALSE, results = 'markup', out.width='40%', fig.show='hold', warning=FALSE, fig.cap='\\label{fig:tree}On the left side the associated graph to the matrix $\\boldsymbol{A}$ is visualized. The nodes of the graph are labeled according to $\\boldsymbol{A}$ (upright) and $\\boldsymbol{P}^T\\boldsymbol{A}\\boldsymbol{P}$ (italics). On the right side the sparsity structure of $\\boldsymbol{A}$ and $\\boldsymbol{P}^T\\boldsymbol{A}\\boldsymbol{P}$ (top row) and the Cholesky factors $\\boldsymbol{R}$ and $\\boldsymbol{U}$ of $\\boldsymbol{A}$ and $\\boldsymbol{P}^T\\boldsymbol{A}\\boldsymbol{P}$ respectively are given in the bottom row. The dashed lines in $\\boldsymbol{U}$ indicate the supernode partition.'} knitr::include_graphics(c('figures/tree.png', 'figures/ill.png')) ``` The Cholesky factor of a banded matrix is again a banded matrix. But arbitrary matrices may produce full Cholesky factors. To reduce this so-called *fill-in* of the Cholesky factor $\boldsymbol{R}$, we permute the columns and rows of $\boldsymbol{A}$ according to a (cleverly chosen) permutation $\boldsymbol{P}$, i.e., $\boldsymbol{U}^T\boldsymbol{U}=\boldsymbol{P}^T\boldsymbol{A}\boldsymbol{P}$, with $\boldsymbol{U}$ an upper triangular matrix. There exist many different algorithms to find permutations which are optimal for specific matrices or at least close to optimal with respect to different criteria. The cost of finding a good permutation matrix $\boldsymbol{P}$ is at least of order $\mathcal{O}(n^{3/2})$. However, there exist good, but suboptimal, approaches for $\mathcal{O}(n\log(n))$. A typical Cholesky factorization of a sparse matrix consists of the steps illustrated in the following pseudo code algorithm. Step | Description ---- | --------------------------------------------------------------------------------------------------------------------------- [1] | Determine permutation and permute the input matrix $\boldsymbol{A}$ to obtain $\boldsymbol{P}^T\boldsymbol{A}\boldsymbol{P}$ [2] | Symbolic factorization, where the sparsity structure of $\boldsymbol{U}$ is constructed [3] | Numeric factorization, where the elements of $\boldsymbol{U}$ are computed When factorizing matrices with the same sparsity structure Step 1 and 2 do not need to be repeated. In MCMC algorithms, this is commonly the case, and exploiting this shortcut leads to very considerable gains in computational efficiency (also noticed by @Rue:Held:05, page 51). However, none of the existing sparse matrix packages in R (`SparseM`, `Matrix`) provide the possibility to carry out Step 3 separately and `spam` fills this gap. As for Step 1, there are many different algorithms to find a permutation, for example, the multiple minimum degree (MMD) algorithm, @Liu:85, and the reverse Cuthill-McKee (RCM) algorithm, @Geor:71. The resulting sparsity structure in the permuted matrix determines the sparsity structure of the Cholesky factor. As an illustration, Figure \ref{fig:ch2:factor} shows the sparsity structure of the Cholesky factor resulting from an MMD, an RCM, and no permutation of a precision matrix induced by a second-order neighbor structure of the US counties. How much fill-in with zeros is present depends on the permutation algorithm, in the example of Figure \@ref{fig:ch2:factor} there are $146735$, $256198$ and $689615$ non-zero elements in the Cholesky factors resulting from the MMD, RCM, and no permutation, respectively. Note that the actual number of non-zero elements of the Cholesky factor may be smaller than what the constructed sparsity structure indicates. Here, there are $14111$, $97565$ and $398353$ zero elements (up to machine precision) that are not exploited. ```{r fillin, echo=FALSE, fig.show='hold', warning=FALSE, fig.cap='\\label{fig:ch2:factor}Sparsity structure of the Cholesky factor with MMD, RCM and no permutation of a precision matrix induced by a second-order neighbor structure of the US counties. The values *nnzR* and *fillin* are the number of non-zero elements in the sparsity structure of the factor and the fill-in, respectively.'} knitr::include_graphics(c('figures/fig_ch2_factors.png')) ``` # More about Methods For both sparse classes of `spam` standard methods like `plot`, `dim`, `backsolve`/`forwardsolve`, `determinant` (based on a Cholesky factor) are implemented and behave as in the case of full matrices. Print methods display the sparse matrix as a full matrix in case of small matrices and display only the non-zero values otherwise. The corresponding cutoff value as well as other parameters can be set and read via `spam.options`. ## Methods with Particular Behavior For the `spam` class additional methods are defined, for examples `rbind`/`cbind`, `dim<-`, etc. The group generic functions from `Math`, `Math2` and `Summary` are treated particularly since they operate only on the nonzero entries of the `spam` class. For example, for the matrix `A` presented in the introduction `range(A)` is the vector `c(0.5, 1)`, i.e. the zeros are omitted from the calculation. The help lists further available methods and highlights the (dis-)similarities compared to when applied to regular matrices or arrays. ## Particular Methods with Ordinary Behavior Besides the two sparse classes mentioned above, `spam` does not maintain different classes for different types of sparse matrices, such as symmetric or diagonal matrices. Doing so would result in some storage and computational gain for some matrix operations, at the cost of user visibility. Instead of creating more classes we consider additional specific operators. As an illustration, consider multiplying a diagonal matrix with a sparse matrix. The operator `\%d*\%` uses standard matrix multiplication if both sides are matrices or multiplies each column according the diagonal entry if the left hand side is a diagonal matrix represented by vector. ## Importing Foreign Formats `spam` is not the only R package for sparse matrix algebra. The packages `SparseM` @Koen:Ng:03 and `Matrix` @Bates:06 contain similar functionalities for handling sparse matrices, however, both packages do not provide the possibility to split up the Cholesky factorization as discussed previously. We briefly discuss the major differences with respect to `spam`; for a detailed description see their manual. `SparseM` is also based on the Fortran Cholesky factorization of @Ng:Peyt:93 using the MMD permutation and almost exclusively on `SparseKit`. It was originally designed for large least squares problems and later also ported to `S4` but is in a few cases inconsistent with existing R methods. It supports different sparse storage systems. `Matrix` incorporates many classes for sparse and full matrices and is based on C. For sparse matrices, it uses different storage formats, defines classes for different types of matrices and uses a Cholesky factorization based on UMFPACK, @Davi:04. `spam` has a few functions that allow to transform matrix formats of the different packages. `spam` also contains functions that download matrices from MatrixMarket, a web side that stores many different sparse matrices. The function `read.MM(file)`, very similar to the function `readMM` from `Matrix`, opens a connection, specified by the argument, and reads a matrix market file. However, as entries of `spam` matrices are of mode `double`, integers matrices are coerced to doubles, patterns lead to matrices containing ones and complex are coerced to the real part thereof. In these aforementioned cases, a warning is issued. MatrixMarket also defines an array format, in which case a (possibly) dense `spam` object is return (retaining only elements which are larger than `getOption('spam.eps')`), a warning is issued. Similarly to `read.MM(file)`, the function `read.HB(file)` reads matrices in the Harwell-Boeing format. Currently, only real assembled Harwell-Boeing can be read with `read.HB`. Reading MatrixMarket formats is more flexible. The functions are based on `readHB` and `readMM` from the library `Matrix` to build the connection and read the raw data. At present, `read.MM(file)` is more flexible than `readMM`. For many operations, `spam` is faster than `Matrix` and `SparseM`. It would also be interesting to compare `spam` and the sparse matrix routines of `Matlab` (see Figure 6 of @Furr:Gent:Nych:06 for a comparison between `SparseM` and Matlab). # Bibliography spam/inst/doc/jss15.pdf0000644000176200001440000347417313574431364014431 0ustar liggesusers%PDF-1.4 %쏢 40 0 obj <> stream x[I\7r "G1C1QcvUe x^>9t K$r2u6zɣ,'jqu뉦.?g7.t? mFFoˋӛ.ZW*|¡u-9弼iUv*ohQð>6MRN lm/xdW+ۤd7+4h ٺa.FV>G':{܋ 8k :Y<Nf 3GFŞP٤] nw$}偈M\i`7!P_~'>7ޣQ߳db,d8_L$xlȺh'\Qћܳ}Ts#V % rI1Gƾ?9hkRl3k? =/rbw_žg4j7j FgYnuhB`rlԋ3fMlN-ưuei:r 1vj1&>T>|EgsB\Q7Yeܯ-Q`GnKŐ~ Gh|2pZa .QI|ʑB+ h@&"ğB/%??G +21ΐB3,C0Sjnc(;%x } bɔhmVLMdz?d&I?8cڙĂt! a9ƴ}srE`&f).|4 pi!Y|tpINeJp3dwt2䠳b.ZfPO`}Iڰr^"k^w`N ݢM4q&b >P@d#-;[^ hhXu\ @m \8dIz8nmBqNo-a`(Djj& 70Zrg%} P`M4F7(A%Mz@}{ˈ-L`%L@ Trx8P{ j]EUTJÚ]+b-3 - ,?N0[xد $W0MݬqŘP&#-9;<(9JT鲉72kQ[^1ǘ&sxJG,o |bďDF).]h1}'aA"FeK z?ȋXPab0,d()?ŇfTʤ%Y>*枌Agbk> '1e}dcnwW5r_o5TJ!`s}hG\9-L1JDA zqR hK`t۠%&Utr @cosuޭD;\\CԮ2F bM1 \ ƍ@=h=Nh b&d2ԾVT+$7Wf]<>9 l,I'm :P»A%.6*vJ=n, s㸍ӠD&;S'1GHT.CBs-ʚQµQkiwJȻS0җwBj_4l˲eUu%7! 翃*ĎyWZ;Vsx]MW22!~+N]԰8( %Wo?` N_{vرUa]Rl'Z>-RiMʛ%$[D{KyQ~)۰iKs ~F6eE+qn[f dMܴ=.d"ll&ZZTDҟS5rL_K8) E ~y x J*Q8H{o5ˁCgzbSnrn1πRR^ 3TC`&4M*XW3\FAY1,2 xL.!ߠl}5v-N H-qf /z^4|H;HieG6^K o߁ȬY)w# S|}i˚-榊"g[n]Rpb[oGҧ LZbHu# (&W.#\J+ljAՊ2[%w hV)V-sDlWo/NF6l?pK4NL텎9P ;=DغN4"X҃4޼7]3w6=sIVl.)Yl_1eltlCotS͸:kAm;۫]ík#;>0qRR9>#K9>1:pM$k(Chu۳Sf^Ɠp,&Fߨm-v|eMвk䧖={ܱa&'aN>@OB%@җ642@:)Ip UB?Gc_ɛZ oQKI6]@@30UZu 1}^EFJ 6V{VeŶd9ϗ%z!!l!-[M2:/N_)(w!6e] ^n?6@y ytYӑ^'f_Hf|rTRT1ktḄJGfE#1zϫ2C.67v܂u>˵"2oL zgHM?]^MJt_X>SabAmX*#UeH6PԀ#il>iH(C ى=~kz@3_ѵGUV,jbkbU{OnxOEE[oD`|v@QQ {ee* ɮp)G ءӕ}9!"9PŤru#˟$8BhWqf]p|RR9Ogc)/e^Uj}O~$2<#BA*K;x)moV3*+t#2rVL8]ս<Gؑ]%3!J3eK N{Ow}SYYu ,خ0|)ۉnŗH/EYǒǡ >N!'69e< +`v5I"0./U>Eq](R>/F4%(v7#V?k߮=޶6|49| ކɍb /'ncû6jGm CɵgmP˵MqxRc.56Bk hMcɜMAP_63ʛ4qy > d"/s̫\ 7B ѝȾt fC%@M&lC$ NLi ujoHԠrN0_c0&8 =qZ."^&ɰ?%BkóI[M榿rvms>ooPh9ֆmx7O;RQ=l>[ 9z2Q.K?d I'w1/i+Q,dtwӵf^6eDAFӴz74qz]¸s׷-u9/) _^aoִ%xyyzh)[u fBIxq c]?5 m '?o|jG٣2I/|/[oûp6Sğm`bv]61Pn]q1P3Dz҄'?*LvU`PM iZj(_NÑendstream endobj 41 0 obj 5383 endobj 87 0 obj <> stream x]Kq ]6tqpG]*)| ea B0} %H"|_w>3f:h٨gVb: W_~ݣѷ E_<Tœ"ҡp?hl!xrvOodr:K}_vOqw?wqw;//v"K 7b&C%e\r-˛Qv#}zX316S 6]8倀5STc=0#1XK{zupD,_&s\8:p:yArhڕ nR׻ψ:zLHF{bEo( g^6; wSbDtjse:R'-bpzGP-:D:nsW`&NIB»e=׉B:,a<%5X>E[&[[ !lla=3/-ϙZ5_ 9Wt0|dSjԟs H)p,)A$m OJCPӯlwu$s{%ǭWX_hD<75a5<sg>Cz*;d&YLfj!,Oi yB`m:b䕠Yҵ~ +1&tF/  7:p@$+)_k7 ,Cnh>$7 W&&IyLGa uèYK+WP$aIHڸ9v4k|*'K: -挎8KD|,6>M I@C k j^f'Ԃ7HoHͷ;d{ .dRF.CJE~cZt%`IJD30|i&_ ;R ֭%he:0R ;ޢ "n'06(` ,Ij ޕRЩq&EwY &i*-KBJZ+n Q(#"#Ё[dt2,GcF+9t@ݥlIN>o9xM `ќyK*2MTg1z^Q&{idɽܸ]5LuiS H.̪7L\5agHR\ojtl,y@aE[!!%2rk%;SP鳱9]fF!aO ^'hF1V9OS']!t2eu$H!j4? x5)#Oy?yȶ~# &xw'x^{IVvm< lUBg(E3,9PmNOZKYkI4 [[u`mOW+НߙP8Dfm % VwV񇟘"DSz MVhadnXNqdmMzA׻O#Y,pB"|R7Xwep#!0(萌i¢!u'T x*Dp+E_ 8Y3$nNgZf"]'vVb㐆2҆# 9 7#Z` 'vw|&I_)qrWSAt֗Chߗj/lv&buӞ R/#xɋ xaA:ue ?eCn $U;JG=?As7t틓pZHh K0Qu;0\BJ_<L(ً HkSUvv {\ ,Jef,4hmq=Z 3T_5!ME+ђ"#u4Q_7ϳzd>kIMT^\ Ln A0oc*v q}ځ !/$Xc )hK[KbCHr,;{lUXHP c/[0Sn|oq"]F/ 1i~O;=ؽIC 9jrJA -`8IHJ#=kآ<QGt`pwi fa@zXJ$G ExXmi2člBW(Mcj,_̓+mI)P?rna+:ŽZ2?YD+.Z9hC!x}D{%Nv` aܟ @R\/P0tQI{:(RLĕ>R*xAÎ]zf3Z{:k`0,GNԑv!Ҩ|bإ(~)!>bW t`>8M*)hgM)Ϭ4祐meVƳBG \3A.5%@w(.KӪg:Qz)-OaͻJlXwI¢FbTjR3켩BW-HgKoH9R)B/˔'sHln|]g]sL[&d1_BT#>šb 'l M0^-$x]d&Hc c;}7OV>a4+!UA 8ՂBxys-e*˫s-N-3 W{ӹ*-Nѓ AZp% @֫QRZmWG/A.jوXC J4 |} y[bcd 2e$!)d?^؍7hzfъsva gȑ/w]wd;Mj_bhq~-Ge70L*Ry"l8E2 TTcU2#ۢLaX*JЍsʛD:.䰑N~44ǯ"la~A"RfF#-QV] e H&58@(b.o^p9[X -Zy9/IH>vvWrg)o"8v\L-- >rsrg# Y?LŎ,XknW7ܥC+q t h1jCmU}MAvH{8Iw$He$!DN1xU{Cݵ7|G^X0ڎ OGU*Dک?'#cDG܃T[dbv*&pŀڶtxFl:;XId|B3`set)Q2Kv4)~גJ8X7\k8L>bJ1Yaxlt!Ƹٟ LIޭNHeϹ)#ּp12J lj*` r 56XFAMr B`cS@}8a&9|S'm0T'/@͈8L]8W N/sr~t*fr[rUejLfngm}dicQiBS[Fi:a@D)x5>a`% yeq9餛Vߕ!8x-xc3 -6<̯Mf6ۥ: fny16JYVHK>lS^-Nw#v7L$-Z(ܑ TiFz,@( $\`UQ0h3Y^g 8^ GSp1N8l/V6 2D#*M!0I!90 (M0e_Ƚ'6o,lOW i|tP(DJ D's m"OSdȋ8VYXSH0%n#YZmdBr}̈́}݇ͺ!Y6SulGHC 9K+lV#/g0α^3ηh5+ ' 7;1&q:ȹ,~1ίڗH艢r1wԦkuS{fSIUtq00ϔUE õA/7ß b+OL{]pwIdI/]vV$62Οsّҭ0Y\rQeb4L=Iõg-tzιİY;|[eZ :nZTKQb_Ymcl豍A>}˜Έ5% $Wa0V6þVr5Xm,CxM|GUe&8+u>:q&ƨ3*OyljT,gig"A">6o|t$\@IC'B`dlKW& թ'F7ҶX{@+(3*k1"TBMUAq(]:F*Qwe/'/Ͱl[Օ^QAZkiIWX4eJ>ҟ%3ڈnsH^quPKo(mdX[BcYL9A.Wʛ|t=//r 9jEŞtA֘oyKşEqۑ5%)9:YLg^}ZV2S7ch%6g w^U)JgO!4 ~ e} ORe;SN|ƩXDUHꃾԦ_Jd}7gwSX*^; r?teU2_u`vliۭɖa*MO}4.;㴯&hrZn:JU< /dX@rtbtu%䰼&}NWIP$B8SXvl ~QF؎x˭e5v(0$8tͿ ePC Ưlv^pm[Pն;a"oIhJߐڛ9WMkKO+eX@^%nh$_wס(B1n5J10]4[_F+gZ0֢iB5O 2>kwNzߕY=5}zfás%&o̽j>it~v} B:?@vapߠRAV?#Z-.ΪQjZkif3ι b W ?IabɏP,vf)nd>EEK+nqR))JoUfz^[_@&;YU⮃IsU:3 (a[[ C~+ TK/f%cǃҝVpCe٤ObN7;Rd{ݝw.w7TA*z(uqVz y[@hh&}" 6ŰKQ uz6yRkE:JOS\ M/sA5:jߐ{~ŌmӠ0\[po[=_p1?l}Jqd:C/?j`>ϔ2\ԗ_9 ̹^*bOIuM֋nŜc\] Xle^r?}bB;*sma]8ٔ#\:NoM0Y˩$E?6{وzl۔6zra?L7K O}TkIGD=$];mt7R 40TMsxpKTaA*zc*pBƍ}6nb Ԡ}>ДH]ϵLXe\i o Ǘ[ }:Z-^^9mLyl?gsF xexdYZK?]ZLH<6z궀E`P~2@R/C6O)nhM=L, bևtR?OLtu۟3qRS1h XL~?i>v]`}%eA5/PDj_X:y[rH[ԭk1QڢXx2K|/њ0&~zNWg$WWSA;`A;)f׿ėpq ŕVwO-}X?L[B"5xO6 SauhS XsOge fKlHAM!'k93AGLHWcbaϗ\Sy8{`| K ?/ &?f]/ΊTwN2B!HaUYK+# \q*'.L'lVy`rI?$?}eSV׼vT4Cު)r">^'}[IN0̮Mp 4#0=:)8_z9d?zP!z?+U8CRWFI&PQe)t{h;ɳWMAu*؀X[vk )MB F4P~;^DUEzӔכ96ގY?3ifA*RGbgogs6'}Sꑓ&tζ!G%l?Mʠ(rr>Uo{LϏLiendstream endobj 88 0 obj 8900 endobj 109 0 obj <> stream x\YGr_gmv)C ceW 9Mq8:88~ިQo?yul]ͳtuS{j9HތYe9zF];f71[9uhN%>jeCo;5F\^Z3)8Klls> oUF7~@l6mNW8l:9<1aFMny^$S)$@uǞiTl?~82H;$8 tmZoWK6Wo4Q)c=TURum)r(@ߠcf[h`m9YUUč[ـeߣ%S~M.zPn: O4N+>asl[ciCǷ/$ex56@Oj\:ÓƜ cN FEgR^SgA.uY*g9_SO tx̎O: \ ?m Eft2E]8{ܢt{#\MALfi;zsV*M*o`‚)|t+|mrN0PiA<>1OCaS reO(>nD>+"T{.) "#@#*uYM`?&=MFkj>dSi!40A$%c$|E˖PfUzӜPn툝pI;ll>^B9ĶI9L.-q؏I}.[W*!b8S ?drR ,}4u?#8`z%ٻp5d6\; @'t.ډ ctkZ$i=;kk$؏O ]>, mO>_]θla BnGt3V"+c7 !J>) 8͛u?oo}LLs< zYN+(kpFxVTʂ)B)wpu3_Xle۳Gh< uguP@x(쯅sQ]W&PYwi&ǙPN: NcDFZ5 $؃Ϟ:`J䪾V*֑9i3>凉c@-穵P"qDV oko℣e˱ј[[G8^4쉊,FC64PhxAӁcV2'-xpEcihq׎' g/VC`Z0p򥳍d")1Dʕ_GDWv` ĎmS*Kb@ʇv>]WeF9G+Ao(֢Ti`8I<º~HOp. Yd6n )AE^ f]Wh4iltF'#;rQhj4T#*Zl'LC JZN3[c FqOd`l SyC> 5h%zx$SOqreQRuT #&bt [5r @C`4p)`ע,yMC`@q hSeUP[9!\Ħ~OC1kӖ 輑7"/ HJ\U;mJ{3< }1Ji:--pvl&[X!7z\# f[f] OƿV7>_<\LY;A|-%Ռ23mBmrK+Z7QOfUWr#z"<`LtEVR]f8.%f/ qeXn=3.3mpPg!L!6n/!Q$BɥK\qi$4P`&~;%6 52g>1ZE5K8iVo 胅W22MCyM0B4B97_grH ˥M:1%TbMVHVhyH:34s+Vo܋J5U@  /,Q:+h4%eD@osvuSNi>%a3`x%D`]t1} 3υ|JJCq}u,g#7[p:Ch ¸fzhW4XȚ%PUpY)etSE%xXm>ȁk.k.AoQ{: S*ۼB>DSB">YkM_ ksfE.h֤U"ޖ)P{SWg~[`(47M %'4H;⤅BI8DTv&5I `iҊۧΞ `կGxh"ǡ? VlXOoЮH^N6c飙KTr,ʀ3.p"c^$ϦO 9oɅifW%ӂ$f`7j r+T+SDBB`rWt~rKyɕ6Q?j>[h~Kog#Rco3o[ħ O 97S6Q\O,/S}twQMf5g:} iG%HWܨWuZpS)_HVuw㭋T)Q|'P+ިIYůj/ Tb5fR|[3 xvN qc f.fliWZ y}!^ y^. / Bpak`|0Y;q~ |`U){ZYDbAz0\ u DI*L.Lr} -#7?7;n]qQ҆ca_ߏF: ` nnv5ꤵE?w^**`{^+mT$xoV8h̜"K[~p|q qKN19b!~<9IkX/g`٦e|EZU#(]>5w5kPӘ (5ǜqgܮV8PhO_D{N/ߛ]4)&$#)|&$݆a,ǜ&'x/{^3Q~E%?ULuKb כ΂w10,QRթw`Ḏh.i:ck,\iCD+u݆p84mDozmƅ h%I300zuzz"pʷ@йR0& C?Bj/Z'j_+S%GdzC mt %*xoM3) s|B~;陬b-cd;=6o5}r!uvj_<:<H 0Xb?ߔɌVӇrwjc+U㐶(2b9׾$:0gaҰx{>E6.G3azDjE(Z=iwM,@UsCétd9'fn*0 yCa9:ҷ)k}jG}Dz/V>< 礼Rq}te24_3&Snxw/5+7^ivwMVb#E)Ik։.5xAl'y\阅='M1qf&wnT}.Kp BoXۣP֮|_ ZpBҷ1Vul\B=pJgP eWX>ZWYn1PeH矡,J%Dtp߄_5bcD~`=:] Q0CP#g $}&uE]CI=.Ize]~*(9dzendstream endobj 110 0 obj 5746 endobj 131 0 obj <> stream x][qvq9Uv޶[wSe:,d2SIJÒ)<K~}rT,ܺї=̓_˫_}j\_Jпn_O^n>Lab賫xqMAͣW[{9ua^}ᬄ> ؾ/ &پ&$ 'ՙ}Pj=ddzc|kҶ|<+i´Qa 鬧aLO@i.;u(ggLxN݊{䋊j@>\C> |RR 섽݀AEYYn2:*г@TZ]05^#$fgO(:0/np#@]@pC+w*QzwIhe-G"j?n͓K^ @zAۮ9U=tCM=$o=+@Z!,N'MWEgǙsnpĜ|^I`Έ8^{j38H19{6\d*M0V-ڍ^O^q0vFL*)ϵL[]-r31Ĥ4Bz:T6n I"g] iF1т^-Ȗ Rtrj$]Њ6T3ul](^{-lw[N2pmQ    v&o7M,j< !ϰG3\8_zb;{+rrDtqwB{m>̛^ 8U }@F նO:1or^Wc2,ɉ esN&[p'OzNO`uH1^@yh\k-<4htGQ蒾&{"HĈFH!v$C H@eY~-@15A~*4Wt7QN@`zH ֧0 fhVqki&2 a×dj_ځ#1ѻv :W-l Ƈ-ed>g&'8Aulb8|lk0ڏރ9 ` lңY'qG\PKzP86A+-J^KYhn)AER'A`LOv3:j#W6&o&<`(u XNf8V@Әb9N6vBt4w'hS7ypy*sR)qxP>]h\(z+čwYPp.=E-lǥn;f;{+bOPDh PW7ge D.I X @qƨ:Q,Vt/p1Pf≁wbOG#2|1jNLyun+\sIP#C9ÿWHD]WJ¼֕+yo~UFoBLF9\K acVIDZx, m4v}`Ȫ4ˀf[mRp Jb>+ٙ n5e&xRQ+M=6,]&4t[Am_2=OsA&DX~a'Yz3 q#$ȳh- G-t b(sՁ]b.^A QJ\ 1&∪ւ6oDHZ&KA^4 2؁{0rAUHA$+-^To yXǭĀ &n8Bב:Z62\YO6SF?3{ IZ9X6R+=0 6 ~4`xi{j깁3ďoOXGW"LQFH%L|L:& B]Y0]cDB\yELuR|wFtxtQNk).єweR=I{Hq 5fG^E#+9| Y$au92۪m-ꥏ^ޠ5͑0<$ ݘt ՙG#aJL uVn)Y-i/ RzOKT+xY~qF7NU@޺RYW4G"$"xl7^hTq{`}.'</I;Q}qcDH*O vTL߃ztr8@UaȃҘv-Cvg%B@ajEʵSQ&&լ bڰ V$V7%i4di= nJ?e:I]B=B JMdP2ۖcbqŻ'L?YR;`n`7\F >ϱb *71F鍔fEA9*4ؿcwE٫1$S'U7?cRxY`3Nq5gv!ol f1Tr \Zd fiP˽ e>Å* (`g5'zYHB pDzmd3'P6:8,Es `\By=6/6T0`yHSMB4i7pMR&’d"dR-):T:DC'~#pB։<-Ge26w.} ]lE2R:=sѯKbiqoB{tƏy:1e9N1 zL5 tQ9wQqa5F+HHQM x :\c+W0Nm_յ -0z}?i!3oaS$ )ODrY7D'P$5(UϝasM,XÒT.EB*G0Z)Lɬ Vp,u&Kkn:U9>+a@ 6J$n8x7$։ ^y 7q8R"oxL:WTJc%rggEȡɵ9`M6g4BfQEgA\#@X)* L^$SQb(n~9-Y%14~<+Y(vVʰ.ǍGLp)PPm)UHqTU_n}BU. )cw̃?U @ฎuRKxUwAwu\*^ -xz;yugP1qS/`7>T,LQ{A]1 |'7AhWC3p(ᗭ]8Q8igjd`2GVk1C2XE܎ ~7+-DJ yTX:JjH[f|=_ 6xL4#U[/5k⦢&q(z0z=zu省(w(%)'ҔRLbCc7{^Ħ>En}α\y%M+|IbQqV2 b~C**quRnxɄ~.rqdhwQ,גKGs&ɧ+R^0MX,HqcdJʊ;Bru {f0\gx!7KMK-ԘEagF=&MgS-$Wa<.LSm U\mJ_3q` j3oXh/UySI-n1L_-;)ۧR#$;I?J{{7o-䘃䧺t8 ʲBǍo6 zvO kkKnU ?#p?-,0EY:m.NTUoX2u{`0ď70L4b"" ۿS@`^pjTFϲV9\!ow:!#TV]}1i[j_fq.xV[TK7fϑK NruKⲵhU6sh+A":5HzUmփxe;?]8])Yl&i.S,Lmyݕr}fPΊ᥻^fTpx];4HjTW[M$bM# VA0u .fVQX4á-s@к  ~*ﵟy`Oe[o^YNf}!?~R,?lJAQޯ}Z0 p k\g^TvnE%dȪ ݖi)Ehk̮i@rGclz?C4zWHkn%$ፆՅj DjJK&mNe_ŶQy`dvuU5Go.pTn \ۂk r7/- ^1ًϱ1h˻6;i2$ A=rITtrskiAALŖH >?a nq,Hry} v{ L)Dpϣ[oG>h&yFia,лpG2C])" Ԑ`lGZ&Qu[HG3H̺8[9MӢfd&)u _AȇFμkS0xhKR `& L1-T;FK,1JG5=XoKTFRsKM.~X7.%e٨@^ZV> stream x][Q%ux+A@8沑%`[3,iz(v9$fuhljX>q2o葖'Ɠ_?'oN>}L#78yATH5vʜ<~qbZG1ɭvoכqe\o4/qsSfZjBճF8Cxo\d֫#~;zm;JE+XY]ΊiZGڌ4~DNц]_]-e!MTo{Oalһa4 gVfFM}`@ ?yzT\CEwk>7ί**4kże-т]9B0h2xZ|vvlDROay(L/B81*ip=( ˨<j-'ړgD]T{N7-ٙL0hG7LjXo&hC<*/cH`V#fTDdzwF4|nhe j_̇cDv3^ NK8\Fkgaz .YmΎr{4~ZXM'.]f\H{c{:0EkIFEFՀ|;Z|kz~MdL9JO;]ϠR  A߬uflXvX3&)l$߅Y tnRZ0 A{{|%vˀ*^JcΘn';j41mDx(ԑj׃4:Qsq/,(D"fYQܗtDȋgx-I0X O.H`'덱د3ja![Sf"VT|~߲@_oԬ0(8.۴0t8@9,X7!dl `5ȼk[rN۱~JЙeP9Hf G6n )2y75 ' pSf⌓z\Wc=e:SV& myeyuǾN<~wڍN7⮢qsyEv>ݪUf&@8|G^M{C%{4 ĿKjYIdu.A>eR$ Get4,y\kc0Q P+2 (jI'u-/ȫȚdk>0>+X|!\j GW3xI -??x!3;`]^0vo Dƙq4Z-RPݼ* 2Z9E|Vp&OO"`w`&#iJLiuV֙wУ  V < _^Fu&,yxY<ljѵqGh<.Lj{ Ox2BY&[Rr+|?#!Ύ+D:iEѵ<']Rr +8'W85;(v5 .3~]TduE i=Hp 8jfin>3 4aIעITȆTe /b/TkW+1"s 8lݒI5{I+@F.FeL=$ 016S.lf[A}ozh]θwX߀GPE&G(9N{'ٜ]7Hcg*ɤI :z`  7mqnfϻmÎ9ljF[a`XDA;ycfG&*($m$(ZLrAnS(J -p0F*BP"A$D3cށ_ G=λ́Y4iqO$Xt57<39h4LnRL n+ycHx;|O[-mͦ&Q dq>8;Tz:'́;lvӅϻWx}]ߕǷv/K%Np*w]wxp31&}ڄ= $^{;yD݉D%Gq@Oǀ ct9% U<,.&zE; xFߊd.[OFm(K^}3~żC|{(@Wx?dy]y¼ #w&|ǃW]vv}O1go0Nk?;2YzFỈ#y(K 1~]p q9gqisOrcQ\?V3@OP 6@gE^QV~(Ke[k58i4-dkIYNԉ%Ufv"@=g= ۽Խe9 2ʊ[6֪(HMFQ',A)_` KUI7h&J5B+[)!3mqv=JiD#dhi4 E7f@0҄WoٛW aGǠ@X9u澍`TEuӅNʶ"/sDdbbF,11'yɣU@-ORjEaU+!{w)J7|s'I:hT--n`Bv;ǐpGXrbx!do7uF C*R~HE p .M~3k.n&X۸O UTPs{mmҨֲm~ c 98@A8(I1;qBV"S0k7<@9'"u c*v| )䲢r7oKS dbL5[U[x/u+X[T@5HC&Hf>5mk! *c_7;40*(O @LlQ,|u:ǁVax= ΖdPtq\6j*d!v)Mz4?2oc7lh$#~넴zF奬]x!l&_b FsqY$gmu:qH1ΫetX~:lG|.:8:FB_l똪Ȩ_UE +J\*|'*H'YՉ^[+[dq,{A<:5%Si6 Y ۯlXC˞!4/d,XW[U'mHwYxHVu,uGp %^qDEgbT#Ww1lh$g`QO"%?G<\f@ EtNVauέYn5ע|tOhN.TWr\UUrzXAԹ BvQ CZNr~QPRe"-tx`@x LG%!8yz??LYOhǴR>FR݌.LZx1*62TԷ4&կzU+X}}$"9?a-+4.}HIET nJ{8R+XwͶ-x~uAE9u*I޵oJ"ѱaj+L^bktD6 !ZObo۞9qq^.LM`.s+~1'ej.V_P`1쮪aA֦$ڇ!2}R8+9 b!8YW]"Ibk< E}QF(JGhB2ZECܗb+&k!c1Gv-l<6T9(y0_ZO㣣3}梂-fkPX}OmrbtBFk:R%1*8cAplOk7Ep .sݨZc,12]<$A|^"Je|Pg&CU]erJrՁ`9/cN4S h;~7Y>)ʣ,+ 4^b~Z_{Iy'pZR\H8|َM՜( EBKG+8Ch2Q.[H.wӝ;,O&o{Ipv t{sGoZݠ -gVM'sL٣I{Ӿ뿕S2xV;>N</P2ysW;]XF ?bN=>uBNi1Lؘ&dd(5٩ٱ޴^~%~M#E7]pNvDlcc_]w叢NaW?=[ Zf1 r!Z|@^7Ļ{nMb<9:<1|һnn25پVoAA@*zbd#K)wT3{S65mL~N&EjM樂ƙ vA|DnJ1Oj:};^DA&YmgBatcLf&̄6>,m{Ld0{|Ƿ$ceQKM.vn3E֍'þ'xx‚؄8Gb,YZJ5u^4-xJ޲YU aGe=a9jcvW=9B[t7u5HlO:@tPb[ @彟m5;eS@{@95C Yq3,e${.QrH\_Z}rFIz%FB":7q?+j)x qM(_m{N/8Z'@j͉V܍^oUW ]"^qgo*y=Y8ؽoBmc2rvW7m e[kӫ0[]ee_U XB In5F$8Z?Fn#V-Xt _Eq=ú3n]4x\_mo `~hKxIJCGqF++6+-c"E*YXs{ t15?uJSfOǪ(-C!>HEOW)*X4ЂACVEv<<@Ҧ3֋CIPseพK&kK*na]f]PXׯ>tMZo֛Y~G|m9O*Tp%-\zF#"ċ<3`,'Vl;h26OB}iMp\Fƚ{˓Nʙtt˰spK&֘uՏ[HQ!0{c֌$8S\HP,IM;LȇLqXӃ߅tX.`+%%]}<\\xRg^j2Kx&dꮲ#(`fw *jlcQ_a] &կZ'`6D&l6Ѱ, D؇J~Oi4˅>Z&C1,fʽbIG%PR~)'NeL8/%~"Ss(u.! Z3ɥ~'!)M ~,CZQԴ֝Ā!xkm: =endstream endobj 161 0 obj 7155 endobj 178 0 obj <> stream x=K$9y=K#Qm[bLfzwagjvzO'TU{l_|3b3nqsn?_m~[21ӗ7xq AW7[{օ;=n㠅~z|0/%T ks [)Ũ>R( :6o?鬄^ZlL&پ&$M'<,C+l!|8,4xe,-ݠG{=z'(^R ceS6)--K-#C6^?FC~ɶG V^YX037x3jx/j#xfw x|jqRݏ&-@ U.lvn ?Ҫv;!)K 4#êCU,o`nfUl_^z; l<3ﱵ 4 `cv80Eg#(QP lY%D38>-5|E%#y ,l@#?w/Mo%ӛ_Dl6o:D~F7y͹QMSPf8 z@=ҷl/2 J~@  Hy_0R)AԀc2d=c!}`׻^++#4ĮhxGA…`6ݴ:21x/hvJ NVxDG8i rZ !1@edi䅻[<a~kvPz G񸃲b!^6 @+&6ziKG[0aA,Ip֙ ޛ:n,Hkk\ `ҎYK]ܟ&:ց_iaKq:!twqJnBhwvȖH5'$.XnIBrխ@3EaVi]s6NµH._'9[#'t0˓8)!w?0JF"&j8,iYPyto&b5["/Qc|Y.>?̇Єt=x.FMhDa@ufi)jbCB P4 ^"9# )\6W:HGB@ؓj(AcI#@х@VQܨ]W2J#h# d hsMJ}9<1I=k* TS4wlM ,,C)P<Ѳ{w>\`f}0˱=jgc)W2IP(6)Ɂh*^'$Tj޲D6I/9l蛝*ZۘiY 8\ :Aҫ(sF/IwʸϼT&]|>܋Dh@:P˜!xMngPQ8yE8FJ5 '}LNYr a3N/F|_;bA^MڂR #rd$W!|1Ԝ{&JFz`w#r!|#O0t]:Ikb0-:G‚`(5p/9Ь@MM$``3FLl"u jOE i ^1):> M0LbY QF{3`fQ谱pĊͫ86=g7ڹʩ';`XPiV%1z._.=XEe(bd p1q0dW 4y%D%@ima{oj)^e Hbc!N:&4O&A'>XprR<5bϖӜ<0.>6aK#р7ʍn fS3 ir gڶa*t<2ׂm-4ppJvh|ZlG=ɏ+*g)Cwtt5g v";Cڭ[V^); nAgp5nT|j"b{t׏P6+Xʺ{c|>K}l\}ٸ4 降s+j@XtEf4z/a(0 !fkNՊ`fpzS@TE19,C]Ӯf;gU_gCQ`f4ͫ*+Af Z@7Y|6NMd6cF E6+<|dOc]8CG9k1ɍZ3(Sb4@,zAF Arv`RHx Ma4wq3y dxo*I|=_q㌊Y'r@(?QLrȐΛMװ ּIuȪnhS]n!*~*pP '1l 1 VVPפ?Ȓ&_;(gAlo 0@o[.7l+* 5XA6fj]ZpLt8mj)':Cq3QP]MQ| OѤv`mtΗ9x:ѫ ‚*j;஠[TR슽*d礧/ºCtɚӭ aDGD *+5VJa&R`I`@A14}2-m s(d$Bv> :0 GZ<Jbz]a-)!7ju_lHKV`&;VB5m1RUsP|iIdTsEEglXmtxp4(B0';:K+jJ,euSi ZDFt ot Vs#ϧ;Pv3ڨKSєGU#앙vn16#8гH& PNa0xX.PPϝdFh,8 쉇&0m^dEY X/zvc.qpv X1|a0?[ft䆐W|Yݿ (~K[Sfd~,]/BfƎ<7 жR=W)q"H]D gqd.<[(N|3CHe6 DD]`%4iUhZm,2Ev$ysӏ'mK𬃳^}C>T3Ն$AEZ gSRiyؔP< BVy$1"1\F'W$.坯d~䍌%D ';AT]Y[gQuZ`z*l!DMzɓɟcikve:.1e" U_ R`肘0}9XN9[a?hn]ȃI@"PTG tLzz@Bx/$5>n%09R0{ sk\9MaQSVX(E 9pYqG՛Nٷ9tzMQ{Q?(Qė>]qI@4`@TG}<>]ۆjb)HUAO ( ~Yyc2~.,Odƥubqqe$jY ϫ?d*jqc?D,+"ZۓStzT}=k여k'# @H&,Jdu8{& },Gy?a +G];`5a8 Oj}Õuфwؽ1l[c(1\?ŗ 1T{i X~AT91ħXק9?+79ۖEevso:1t:Pss8 Hu{}*BMώ&%, t3pTE%' Ԗx@6ǨXjZ]iJi1}2bś*q*F%qU\}צ MeGG %1]Ȭ"7QY's4+9bRaescV8xaZC}s .֩%As#ڲ5K\ YJ,Ӕf;5ߗ`YoZT[bK$j"z/*O8$AdZioJrrJp W "]JrFP3[P+bZڂ)RyyOԑ3Ej׼iL 9БR\W|@4:t4HcR=?iA J =q RG.0cw=0YXx90L, QrNയk(37QgK9]4Je-J|%m\_ +BC{N)P`Ep z$PjWI&RaQW(E_lLƊ 6P4m|1?ȢnUʓ8Ѯ⧵nli%ָzF^-AS #m᧱%C.R1Z U e \ң!^`[tv5XԸH"՞>w(Dft3t^te <3$.d,ܝ 1mEO,1L ßu0( _ ťTަT`m ̾SXF[) xazeY^9,u}~UB$l's,^j;ksݧ2Da,cA~0`:1h8ƛFsM A(,Lq2$* [^EgK>˂:>(_IYd9$޽(`Hʹ~x5QW,ۅu"">s40l!t(:?FaYYV:ќ-jrmsscQk% kğ#UKFyuet+mx@[ޅq90,_ln5iN/H;qOO}Y$r2RAi]̐t`JMwS>>_tH4hA4f6iܺ7ChFBs’QTܲ#:lQ@.3fYeo\ew%z>Tk&Rll2̓aj N %+Ix悚XV(.6HjUٔ]sŊ2:zx4Kk@o8O8۱AGQ;flb偺:Xe8hT.gH";2'K#U0mTylϦtH{X!21WSF$RN:qQۋ?G!;?gfqw,]dLjsSZx'>vQZ%f ZK'.Ҭ<({@P 5{`D|ܠ0dZ[7x`Czk~6l1ǩkhjz$JtGWNn&8M_Ί<$E ?%H0yXE4UJ4T +4#oVR.#4 :<&iNXq%dK[s'>5hOxHh#_ud=3n3=0Ί>DE(bgnKc|$ Ru8F=MaaStS-_o'~Kka,'hF J㵦`~򸚺v!Rcx6pg`vRi$CF]Ǚ_zhL4Lqq> stream xko/AIx#HA-ZVUk44mKr$R,5J>v8#-9 sYX>;Tbv|ufoxugyi=|v }gB+?ڶ^9k㊛,I|Z˘riX )Ekn(횗Yz'i.aX2j¶i@`ZѠ?MY/0ʼS6欐rfuӜ%E& v$,ls~ *!20QMv7ѳ?kA]tыΏ^e-n1) ~F)a|loޒ BXj ^S7.[1*/bz2i(2zUFo xENl ڹ=/ !q|K~VcrKr54úlI\DkaEҰ&nIF}ڝR#jI~R8(q_v~X xQ@4ygYi(ݥ_O /|=H$$g! C>#BG}Z+Z).G5]XO.RslξU?- /9i5l"ȟ}d 8%!tu["Ȁ@TJ[c_$l$̵#A¡r L*E Yk,qENg ȿ זC4 M]% t€<#^+ꝞQX{]sJ5늚o=&ŕ j@o20 "QDh+PBh&LkK܉a7\FFz"Aba*)ej (Y|` #,`3O-×J:ȂF26_pczüQ 0Zg k[ت֕S¢# ʂx'p1E 4yanPfCv\&\tGۢ_@/LEq+ɫM%i5BC*իdsܹ0K?@2Zb)ȥo.kY@= Ü LwDn (Rxxgu^>@23.ufVԁe!qL`6Xfv-?$a6 Q"c%иDTQ.w \c2Z4"iA$哹;igiirG[1b{^HL6i>%=1)eY{iqZ0|l3ހxl!42.t"IkxAP:'FX e_?Mj.,-qjn̾͛&||F.99[1]]C &uiDUs eW$P.s5dP^Q !Gzg<&@%a Y94t }lc7E_b.=U=X|95^̼?&~߃t1aDG_E+>3b:X;=*nk,K ]% y" u.I!#H Ҟ!!4J' 7.bmC|NZUy<>'e gdwH؎-2pc>(]ܷE5U"FqpmH.t&8dsuAb9Dtjx^CߙN5T5"% ӅLd<^uW<ԋʱ!,7鎽Gx]-ILQc0߰?ij $.SL} ̬ՙY o}vB"{EUpNLabWN۳$ ]gy@^V;zJ+uddwgV~v&##˙mA"Y@ ɂ Nby\k̬fpu+WM-3^d Ih"e wC2SZVί1G}ֵ1Q>>$ХoU 1d  !^nދHj#A@!b XGa2Y5yy=B߱cz(ቍӝU)̎3<ޤjTiTdXybw`8xQg0bsg :swve p:S5IB{C".%|3U% @.P[87`6m~BcNܥV:}u-$޽Q>=P`3c,ƌ= jMevjMBQip Wת(zyGb'407-ȼ$IGQ$pY]'h\M\ }v;lzO] ?$ë2XYѴoHN5LVVۺ@~Q$qbX yN;id'w| /Cݷz xT@tu94}{tendstream endobj 186 0 obj 3884 endobj 190 0 obj <> stream x[OF_vmKhJ( G@T޵c{&k|xe<;;;6ߛMĿƧSn^Oy_Rb,ΰ17%o·G4;![ 0Xҗƹqb]fskd@j3a1TБ>j,rܭ}(!]-מ8Q?(bendstream endobj 191 0 obj 1693 endobj 200 0 obj <> stream x][od7r~W ?@0{>.d7q`bmA5IӒ-4ɯOU=qLy) O O}~{FNI=:= z_(<={u~*OC4[?DmOnO_a-%nuM) F ^VץnZ Nտ Kc֭^g-TfrQ~B1W+6gi0[*b0:03!tnuMXqe]+z¿NrRy0Pqil9U HdzU\x1FnsuPg ,a(.-DnvDl5&18n׸ e>ԡZ#|BG02|Nؐ^@@>O+xaU3!f__Il+)zG8As z`GM3g3emA#w L a\OkBِqW*Gx8+68p0U_hZBf3UAn7k8K}]4lH-cL6xPİ>ܸŠƃ6 q ZdDh+uA* DĈڧE=kp wesA-\6zHA4|EU cafgI8lͻq8Xfp0+?/?.!q7-;nS..# W 9gmw'@c#N[KF{]NK3emZ O?԰cI%}-|Lt0ap" ҏ|6Aޮq N %"GJ!{JD,!Iq?Yg':I՞^61ͩOAH%ӕFӐPh>xg]=Z舿1diODxx'rw_Bl-[Uunug1|-M5]]4f׷7w33`u YOZfaE?*B) #b|y݀`WXUɊ`A};5^'EP:;0 4in@7tR$nxon #aB l!#JT1:;odCY: ) Z$ƭ 1cfȃ?RR$R6L P6#ƹVs&iy[Ivd* U!ݒy`ߗ)c q㶀B*zD:7(fb%Q M'x|8yY( v7. Eu d:Wyt5g|e`T5_):-!pja+ yi>miޏ#?yjK;z]Z 4](3,PSym4cc?Ci>4_ܩ/Ҽsc3\9`QIPK،m%x $ߓ~Ƶ9NaA/^ۋ]||ߣ*Al1X*dw8l2/+Ƽ,yWR- 0@ֹ!Og©[n%8)P&l%ώVsGU8YZhpS О@K)1)ȀT _'lKzY8p~y7@1 e SĽqq۰6 71X)J<.%kw1>J,4VRgSګ2/˱T~L2BǍSֆF\qhFw@HKpbH%理eWN pR]1%ݩ0 :8GXsr1+HI~ġZR *i|ZD{&Zr&|nJV%_gÑQUNa>HCY03@;J-3@d?Za@E#-7za+qch!юu=(]}9<}r$6RG``%F G(IFc8ideNb8BRLm!U*5@M_!p$^t3U;xQ CnRNf!?i5Ed}9cO"+ʇrBX: f=\p4yi87k&+`rRjZzZ)CX2ʿ“CBS8dcإ"j~nx}Y`âogޯǺX;nXez b$<)v"&jC@MD7) C.͙Kw/m’:Uʃ-ow{'YrHx#NϏU"b]^qKc"'ʑ_!^0g>eB&UB p|Țu>@~lqbLß%AEUzP"H mY^0oxml"֠Xqi1T¾ٸ1esY @4%4pq!VƄ4%)0gYul&d2- ?z_e(U\ :GͯH"tpi ;FYk xt~X΋HF6J%ݟpƄj=}V8(Jf(/}IQH?4b_cUX@co:A|BK:q:`H&(y}lA^Me2,X_% -9/܋* |z kY5uUB!ui7-! ^iYTPL?z@Qx=T(-YYknMs2ׯ*q3SK 6A$Zʥ~BLjζʂsKW޴2‹r+1CFT؝Ksczf?Hݮ}qcd 2O@'R.WtvD֝¾|ɒE@ lu!!Ey~8TBbݞӶ%8%W`v d.g~i0[J!GOcx+k`kuꌗ+i[J^d=o50@;XK*GkD?!V1 Љ(k#J-@4Qh D4Z1,E 0.S$_XVƞOuh)G&[lY 6T{yu{J}$| jlneVVF[N#NEڮR-P1ZCj3Xrp3w/\2nśJSJ x 9͜c:ZC\|×.&h:'SK{!Y7(F=BQOSmDˑƺH.#jrik.C#T6s@ *A7B %8"Ցw^d b峿}#ZV\`_G/G6@2GO8P+wdQ5J8Tk6ǚJnP,눘 #ޕ&#n"?kL5{~ -\Hۣ ץ4_]iW4./?ju]c*xl7VcK:vKdldt{cqY_&>.Lw)^wgc#0}]w06S9Wͳ+Xn8_U"& |U/J46 ^Xe8ֱc*34St=j~ nL0S\cQ\oZ(ZK}Kyn4jTuhʾ7MqZ6Y 0@m? ۿ1x2/C ~p> I:dF~f~d8X_]S?5@&b7Z (F]aˮJbaJ} NO7XmiZ߲NugQgV+fI8DQ{da^v77`xw0R0IQDZ{DlL~sV9&eHLT˃CEt *q`h_k!_:Ǹp>Tw-֩8a)K͑^IJ.^FnZdml Ƅdv8qd]A͂7;#U^kŠ`VQծ>Ry# \5!:̒99~%J`8z8b R_`LkAϢS^) ɅAt~ ;/ءWڭh^Cf"/w:h"09 DLz_@0%WmgF䉓tY5WY+9{1#a k:_G7U"/n6^d}uxe{q%L67)% ӞPǿbTi+SHjb<<{Rh@öKoڼ):s<X?ȕ#hO0s<C=Aߩ@>0Xϴ%h I]j=Ѐ> i#˃ϡC~| T'D`ӂ^wK#:6Տj.(o1>x "^c@/ &q{KoxcEw&v}a7F)}ӅMj/Ǟۼ0Mpt'9por0=*hp:ZȯB>+dH)RsA<lL}=q|ua, &%^\K~WzXbh ~T:M0,endstream endobj 201 0 obj 6716 endobj 208 0 obj <> stream xKvv~n~nxg.5USEACBc )|g]ϺHS6_wz߿oZ׿ߞۿ-_?#h{{=+}_F߫?g]J?{kONXs=^̑zO[>?}}ڷѶgq=;.쇥~7nk4;'\~5Ky|ק93GO~M3~u,RR|qwx|=if_O3;L3ʃ}OD.}y^;jig-+;\ jm[<ʪ|o{_)}~`/o)<{mq̣sޱw~|Od–ݰR{t}8x?бGV{#[b9F U#[ LQߞmqu|DߝݽѶǫEiH- ӾP ,_g[cR6Juujq%斏42 jNxVNg$Kd;oP52@#[L k{nݦB?Z+m5ZYSb4ZV}/ogrp֗o-\ ͑%[Jˑ}G~e~ȖRh9+G>!-K@9BM a82 V 4ESBZ//%Q~cr4M |bbɖB꣮ ^n!d~ חo0.~T7CӤ Mǖώ=U}c*[F5F&l{-N_7S-j#[as=#[<wTqm|J~ȀU6xmKhy-[?-+ϡK&Jೖm ?s @Tݶ^˶%JKIsOk֧8mKt@HxQta'qdAl/5kѳ09ÁANm`~ǴÌkdK(|%al{@|ijmt(xJ:Q\uٟ&aM%io=Y$ҷ4Cm@3ʿk27-bRRlonKH/k6}gz?ݤ6X=5W -Yﲥ]4|2|Rwec-7$|B9ϡL-[@;58BWeW[{sia [k8C\(_a:EFs!ؐb^X]fpm 'R4q?i@y%~#ܭu:"Y[qZ:9?ܷ)(|*J$|v₲LBeު$|"_ӭ:j5e09遖mfC_=B~G\ڛP. kos >11̽fp]@L%>"H@zDviM%Zk/#c-\=҈k\\t5C4GE2HU A vqYOJr^X#o5#"l-Gd,B⇒<,2@)J!5qȁ8bG‡n^'DB#X>a (-N6fv=zGJ^9G쑪58Zu EǤgT3]ӖOxc+gH0\2ejbȽZaGBFطo :t-_ώ#!\CGM 5)vK(V ^TEmrxrB!y zM)=彦&yLUIXӮ$cm$+=i̱w(=^eN'?/{d0^qrHn*v4?0Cxj> "bߵʐ,xeX!`n(p(d2ܐ6oEj{}8=BKlQW)qvÞw*=77r1"sOGUﯔJX#b$LH֝LEiH|4F9#Q ?$G/w!Gz0aV"WV&Er|G}TP$n@6@ގ]&` L #+HΆYeHXuHˬFDO< 21&z`HebH9y )Q-/@1_IL|Le}!)e%_p&G[H!Qj od@Hʐ4 $qbHURȼDz,Ґ$T1$F[PV-ĐɯL 釱%\>1 20$j5 "} "9'JdbH4fòF <9aĐ<%T&L "UJI׻?ryqfGJr:7Of!?5?j_,WZpGm#LL^~\B~}wҨc$ԔkK$b- j. =6C_#C2Xȁ-+#2| $z ȭzԌ?Q"D"pD=z #nT6Rqb}IQsGJ3ù'[32#\\&zD}ͷ&zP=b8^eG[{@$ dLq"z%rу|&f_E_E b3 *!$CG"L̙ "H8Abq WAb$AJ*)y"Hu D8שguE4$F'_ A }&d !Z$w4 $7RUǣgB/O 5,.H]6Efޡz&sg} eGF! Ai2/S?Z?~1JeHL˄6K2`$z' #E3akdH@đ sF #qJa#G(Q$Ej@)+~IY5J&\H Go a:i/!I]/ؔN@#%x3$ UW:aGѣzYp*'%ӁN% mOqbIx&dBo,# yrXR{;aZ`R`}~h3 e%DNTdIcy&u,sґW!J҈ ĻF>L8 c=M`һ&L* 4<&$V2\Nє+D4 wf$^4q0"IE9p]OD̃c5?#"I\e&ޞ&lld ABLԒ(60G "I!AJ߉\6}Zf"I\t&T߾&uBSBI?v~~npFPR{ǒۦJ6JPpD 4c&%XucI_7SuK&1 G p3nG8Js]&T)IopRWB"I8!JNy# sBh 0tGUNbu]$%4^0$궻2{ޠh*J4ɺzk&w 4u^DEpeē-#?s1^ĒVE^ kLzeQm*d%iMohK&QWV*V8R8+OGb q 2pr=0bH辀2a$[6aH.LfYT< )`$T0gHM~0+z]K #Hu9SV Tߡ6* )/P-"2$ZZ@WHk&6fu=*]m/R^$BIILQϒb+Ē<ȥJrZָJ *J/8J|"IBIW\>F㊦"(Ēlq F^ $Ո]Q!"I]{I_РI"~P,5M'>/B3pS2U74*ĒXteȖ޿=r-E~re[$Z$9?R52O:ʩH/1/KI> INxTc!ԥk|BG BFq I\ḬJwwKL'\X$XoI#.,n 'T%WʡKBI%ǿ(IxO!TBT9/1IotLB\ӜO(LsDWI " ~BID!04\B0]:X&K. hQ~dA>K 9YJ'ܼ]!.+IR%(.Ē0sxee_g P]B(ɓa HR7Y(9%ggm!$osQ6a,JRвdp^E.X$|X%QB()<$-96OuItoyVg=MbICBXK+ĒXҒ`I\+(I,Kb&" $N2\{k1 hRFMNb!hke Ѥh3O[&7W&U ed*mybI,c)b $jZwBINjJR/H;7 ?bIV!BI. WΑ,ĒޕXup $eP?U]Hր%(;bIW{bI 6sLd-đ+~.đިoDx$^&iyIZI_a!ʭ,Q @$?PW@I#--Ijd\!^ B$zmIoHRy[;"IEZK$IaKHF+$RD`kTHRz)Z=mpRՎN?ʒ|߉&ѡP&`]j0I[)`IϻKrk KHz? $I?T$` h+дJJ %5͸6$W6K}nIREPB$ =Dމv& FXi@R3đ#Hl*|@S*"NJH-(đƛ0Q턑ܡFR/;d#b?滎A t sDK?G\ - C˯*Z14 1á.\zNvCĎ\_CI ew8YǠU8k8Oca!rdRUYDz6*aQ%l }} BH) #b<q-M(8ʯ ðN/pINňB]FFdCWUIU7_^OԫU?ʔlMBp0i34j*ֽz*|uS^|9[: +u"ABmuXrKSi.NNQC\h̫SN ~ Sk̫SF:%%d^2;R)~;:Cc^f]vu ,lb~ 3i4N~:ͫ]; \-:\2fd5U'ÄrXu nVg~_×"<"[?L̏f̫SYZ۴&DWsCA ObeƼ:0c6GLSthuc =:y,0&G8ׇU/cV̀*ͪ_VƬIf0%#WoaՁ,I`fٖK T'KxNIؘTbiĤ:VjéS.NQN9@xds0 㭒h[i[Ƭ:EvׇUtHa̪a`)Ȭ:yêSJ?ocV7}HuvϚywć1Iu<.Nf5A:{B0U;p䃇_Z|LS{:2NqmeA^&`!ϟ&٬:%êS>$?fթRŘV\ CSӗ}hu>NZP̫ij?:zCDbAj]Pb&}P04:+LD~FG:upu02ī*^ëg%Ձ)GWFF4W{({G=qW[1iЬt̫EcF!@cǼ:0 &1 Ձ:Pa&ʼx@:9;8:؋?Xu>y>:puQ&81fmGad1N)2(-xusu JĿbr 4M2d5&)H=i@|jF#.[G/屟fnR_[.ׇ[!PCv1NIT:0b :Uӯv}1N-T@zuJ4fׁ+suj9|]:"]|îSNeׁ?uW}up:i=fש0v:LUcv8=&^rK:.NyasC$xuϙ:؇ZO6Wu  ujw ڡցlij@AJv #r@A: ~ ƒvT̮,`j@"ru0~_з2x)\L(ץ10׈]g]ZA~î_z%_z_}uJK^s35L8DΦ1N'8:k`n\"s@cCOHG|h SSruX0u j"u%_I%t(%W @#u0Q;\y=u`cb'?:\bxZ1Gblxìk3 =T~9Y9:Pt1C~QטYgˣNMG2)2`:XVZCt}W0=L~8:ؔR7yHup#c:E_Rl/jR_Rꔶ\Su:9uxur7AnWjCb#9Y˫c Y'`c^.NYc~xuA3(p(}ëH"A>N]RX~ASna֩%2NMުYvs]fdwtuaV:Ee>:M0`ytHg디wX-X Y%JfA^¢dfw6N%Y3Taց{1mì`^3 xrfK:le`v2|d0>uʥ@2Ήo.L̬scˬ f f5>8-OuraAsvDzG"1ǯ%_7E:HOhbnLS!8:tu`4=68dYtF8y˫W[A+av(X?RN(tڴ: 3GI&#Vm̫SN)0'^Hdyī/=4^eGīdp̫+e^.NWWi$ x̐.W6fpxJQ/\~07J:^.,:A'ՁkīmDī9rLHb=]fScfhDSGHq:ZNMfZ?u0K vu.ZClnjZۡCIsK)vn#f:XÑ#f ^f$L̑cf$Y{Iz0Td3\pP`sjGp?qhrn=:wzX?X:pMjdzc0^|^h|"Cs^dseׁ5u6WN*~;:0-:ؓ1_B`n@/:@P18:eN(jQCQZƮG:7tu=G_l_.Ύ?-J_Bz_jzXz=\%_$6סy׈u9$ܼAI6tڌ,ׁˑ|>ʡׁ5u Ku2ȇ^Y׈^'5^V\zD^f/#+a8]::xxSNׁc~0@*c|:ͥu0a,aع)˰ȮG ;x0@zJͰx-&a_\=` `b1wfQ^_Sˉ; g;+šro v\+&ة͘%ة *KlN2y_C+3Ϙ`ajLI}eE v>z U㼂*}vr9 X}~Jqt^X=Yw6t:"a)wYh'F;;g`!}d$5N^;0N$8&AE eعuJaq]ց̰qnƞa ;Ѻ ;< ;9 ;ZhA0|ðQa? ;>fa ;0 K ;?$;6v .1ivG]34+Of޼;b)*^a٩0geSd.t0P1Xv"{;,;T}̲Sq-L (LO$;IvvdqLdc <$;H $;@LD|&1N~aٹK2iv5L,{󰵘g'q^ HjLs՗h;hD]`ju1caX}yvu#ͳ)5N1ߥٹ`dԘj焯i疡]&$3L;p_=L;7zL;BWCa̴ɴCNO7ΩRD;?u\uv3L;.u,sˢkB#1˴ aځNWaaqQ>H8pX\/E>?vkb1ӎ9~}v0f㩧D^^Üfڹ>eځ^8=fAq%ځ|hWvM  n??lGLsKSn!)>Uyvn8{yv[X̳S˳˳gVsxvnV|D \DRc~vvm߬g4ΩwPt"Oյ*g';)4ԑ1;r8@!:eUP1gzN,g#ókO})!LYULXR$/&)~}vD;QuWw\_Z̳)-QFnz̳an><;7|D;Hy<;"vXg.کfyvr|B&ک022eanlܫ]Z2@(%d:zv#gLs{k.TZNKʯUqu)ML;2MjC߇jȔ8ڹmwj1>J71NMPИi6fAV$?&ڹ%ῈwED;L;U)>L;5BG-?4;s*סف 2 HpYvneٹeٹ}{e'OI_FWpao$;o4&ٹEdv^d^Cso.lqIJHbK7NKÎ}Iv;,;7qYv0b΅NmǓ=,;b,;p̏crXvm <;Eg磪!̼ӭ֡ځ'3fT7ف?4;)>K9A=ف ,W<;\%AH):D;(@iu{r\ #.C5Ms @&A!ځnhVBCyWf`D;:D;Py3 ;2Lӷ|v92 X>T;Ϛj_O"P+jǥ2>T;(Տ̴HV0rv>?v~}vpWf Q~Q32;zKW'B@v3j˴s˶ĴIb2N9_hLsSkAp|*kAA୍f(T:*Ї.\;4 *zvql;l@6àCs˟.c !۹ lD\!ہj&ym'|G\?aacl;L̶ćmMe)amvTm἖fAn|n t;jYCnn9?Ybہs*3xU [^WyUvE-&W :=15HFF GUw>6Ugu-ٽWݑU\uF^W|^:%4PTb Oز-^@c⏊R==ǿb˔5YrfYb?97Z._nrѨ B+vw׈y \75xG7lҐ;"'^G#L$B^ 3f3[8HJ#E횇ܱ"SuЈwDD1{xdz<6`vZ!4A8-D F}'y$+Z;"R7#V$~G~|dǠ~o*O0]N7Q'b1yEt,gGQ>ԓ.)Q818cJMΑlPj =YP7cO~)ĄۈIM|@Ic;tA7ƤFNE! 1h^i~VFe߀ܡcw$Yq;r߈鏷B1iE:ۆc2IW0bG1+ GV:+G卞wl5f!Q`{hiA⸘E"*H##(c-FP OWTzy/ܘAvg0HA_1k aUz0+wEըvy;4ID=4.$ JɀӴdPɕy]pbAhFɀ!RNZ&"$4!Jv,ԶAy-6ƽc=K.(1Xj 63s+j*XVA!S<ڝ(Kє @Fi17lQR1f+2a:ї+zlefL6gD 9Sd01H)17Bc<&r®;1BWgLB*AŀP'jGN&w,R9hL6Q *&qSe1MT8ơH_, lMQ%Hvt^C} h*'&7دG"芉!dvnGo1v]!Da& l1 g9%Ԕŕ-&pQ*Xۉ;Apx:n7QS# P)j{cxGe{.k1P0P*j*J,0@mT e_:$FQj(7ֻފ f8mVL(zĸzDVAhc{Ĭ %VX\oQc nIˌ'8wbTVPϛ(O`E4cOoY0B`c.G8}1>㪰AF8:&cS2hzQ8D)ete{FqbpT\c# H X a Y3bF%fq*B3Tx2c,ʍ_Ph5ISaͳҗ `X1I܉4(@k\j$phPUggLKQ(D 0 AIG<E!1c tmPHLc99. 086"ԁq! mbVrKAz$D:gLy[Wшe(0yMqwD?A魮X=HQ}92Ɉ*˴8R-oa hJtz ,5 B)IPJotHi8Ob.yCɰΘD#%~;(bC[TLjCϯ1%C NĎ c=}K!E5%45U)8&VQ7C$( >yNo dp3Ә{3ə$4ӱUO ށ'&ND Qf/Ze<[(jPF<]6;W̖yDĚ*(DBB Qx^#uނ=&ъC|X(UpQ$Q8b*A궩5 (;cN@{[<<W)Dۯjh!V@=3_pLgLm9NjfpfU/]+(Lf61ʬ|A, Aki%L1:J ‹ _lCn0E8 ueK9h "v~`׭P8)p"g(bsy,bϟ-! A,c߂V,˥ E 8HtwLԊCDMt JL(-C1ǀUlA株(U/73cjY yh Dr rQxxgJ=Vl? DT:AAr1ԺDEn &̨:s#fLܻzo<1X@{PǸFU"ig!k1 :/0(;ȥ%(eA&tvTuVUQ,aZV [ c-#؀G1ctWtPs~,L?,Yjz5A[G<K=t-f*ޗ6`cbP1Pxu#*& BLE\I6FVlOLNa@hQOLλF$1DXU݁;E};q-aNg m34fļpbEK9h-2?}u 1ˆEy|UdbߘX#pO3k:n>Ņ 42n+yl%ZHS1:]cv)z((lDwGzh|OЉ4>m^yϷJaF)P%Ϫ:útȇq@9 łpUu#x<-̴Vw|9(tKU7iib'^ YY, M_g3fa꒑ j@ٜK!;a=1$vp:/pLR I9+(eai1˸T+fSҹ`Щ>}[ G- 2f @w|3Yz!c@(B#V#_+|gxg+&qb1VY`|y"`d,'g)2[b<8Z5r w?ƦʄӟVζuAo ! !Fp)kg[Oj*8}ya 01-ܟ r$݄a`~SuSZ<| f0^15櫳hH #̕'Vm7@ $TwaRsZP{?x9S^WH}bc^_cNF>'*FWD>Ro'D]% ]--ZPe@[x1Ә}5F}i,dl~xnff]O&MgN'S $pbV&tIb\ȳpv buèl4ZЩcT aEH|X&K#\A>Yg#ŝsAzD)Z1 K-U)1Ipl,֡xpD]K<e-~m:ȌWP#i$ ̠Y ADz-A?An;-Qa!*2Ͼs)gIº/GLר0@DoHݱD]0{_sog >(븥hn\,InLm eep1FF sDJ,Q}b:2:,'j?gk5t /4=BF 7r֔:dgg+s1sgLz(՟(X"gbԈGMUvYA ;r\w{^qSvO֠`^xۗ rSSb*n,Jm[ա~l= M (qDC|]HAM:c ×%1##b&фbPa|w0bSuӢa:cz<6d҉l@RA}MK8i),`" JiD52P IWN $H>1cJ/39aNnpQ@BY]R#y*5s+QT#p!.%laQ Ӻ R숔L y; bqܨ]=)ȕpض)=5*Hb1}(;#.) 0-O}xEYȶgnּS>bJ(8>ґ ;l :o# lk陙1B'fL薷枒{@XL#I0fW \_iPM&T֎0)Ǧoz??lm3"#pڛ5?w'+-Tm}%Qh*w? ʾo=ݐ<_@oߟ'Zb_1AٻPuu;s7#?dYjd_~pkAi{{G_?(kN_$l)<%կ<*{@Qظgwӌ5Z%ۻZw tA~yhd}2gcdPj Q ijd|Ϻ 0mtBG;kg`9L&fNHma n}R{|9@W ]{d:J# ë|vf=*v?|6aQxâJb^‘?'6kM5.h]xv[aUZOz4 Gr_+H/v(~ȓ4Rez tiP}I9"R``q#$#C·Óߥ"2kEKoAiX* `G&Ō×4線HvyM-F!!3-e۫j:Gj쉤M- gJhc&{aFft  WC# i΃)ȀMk/5hj-#u hڪshi252 -_q$ @iGk o##CR89O{hF h x)^C+}n7f\Q5Qߥc91n 2CCd^ۯ7Tr4Ȕ]H Ÿ7{]2[=00IŊTE _k}L¾s*Xylj}Ғ>a};Gڊ#]gR*EM"[|iW}.˘d ږgj~]A~ViPG~cn='-@[׮&yd>t6(fגFxy[aҴAn^#  K[!t^ UEUlTH]?KC MN9G34H=d_OAH1$OGb6+66XiFS eK,$=:lwԗ[ OB6-!lۄ҉HA[FKU#Y`X_C/Rlo3gHU-PPjRKɰ˾sj;:\78Wj:]RZI(Gֵhnevi puMl'+ |47@'")a?҈{^֏dAnξ ꖒ>H83u@͖ov z\Z<G-M;KML^L1 Ob5t&K0R4PA@Wdq8p^Ɩay0ljCcjDlѤ[Y#~xׯ QY&_\uJ{K$-ՁU_7by- !R;OBf}K4C1H1Lqpo !0zv!6v嬓.-8+XM v(:ʘmճy*,$I+guF }# MMŨ ml*vJeʜ M58? L9jwNkd=xR>cshc{&'Es7;[m?SK.5UQ(lSGRߚ읭4B]i)8#Yi pa;߀Jv]Ō!uWvU~8=-wVhU%f݇zTj%|<煠sIZ82N՘oY&yZz\B9CjG\4.(;]c=0=Ӵ*&g&屪wJ%@o}7U@xgu:4&?)?Or፷G"qt9CFJQ6{ęn#$hk,*kHO4{Ws/9Ye둒O|ƙPґI$=5T $i%m^M^mѮGeGS[+9դ7ޮ*{(NJ{#1gZ;oN` 쑪e/ljCy/pwx- e ^ҍʨ%`͇/iYE%0'GôA*$4s*=ٶQqߙ,RМ#UyG r i I҈r̽ w徑sY9=R{N3푦T{D\%pSsu#+x)Sg)Ϲ:wӽ4RrQnTQ 9 U9 2#DG)Q|ŒzL+S~!5]~iGGֲCzug(y7PiRΓsD)̅nˌ!&CP۟4354!;GW1;0e@j~hDD42s^QZ\:ڜCN q܆d&2~RVTa v=!7LOR!ka$;U̷Bj"sNfGI-ѣG% igG^mK*@֚48̨g9#@>.l?LJ ܼ|&zd=OhGƟ"|6]vT^]V(.9N4Bz+J7^fbG?*3Ռї ɾ#TS{&xk2&CW4sկeݦ(Pq Q L横Kr5sL;*#IKhe9~xl+Gx4\}e7rބJeGI׏x4t`HȩQ^!gN0(6F\];bG fbGtϻ #\E'B)!UE"nhΟL;O˦Б՝nH҈e%|aZ_DrCȪVSA(l=ou .Dv:'ýi *IY=J_?=>̚z>;<68)LjJ#g56m*ݷl=\6[1iLA6"z$AȈQWK 0f:4?h'1^Bf}F0ru%SyXJ"T(8A#pTފ tHGICVIhj eGִa3EˆQ{k1`GŚNQav =GyHɜ=2ި#z8CVw!x#'z(eGʱ n;}vQ*֟Q>J3TBK2aMЄ#%|T˼-,Q#dzb;aUY G׷/f% Q%J"~DŖ?2~$+GL&EJ&ȫÑ9ev$eY29@ qr6:_w^Sa`i@C+6_r4ㄎB09#B[:b-ErB8k2ѣ$!;sNIɘ㑡v֛c6ܦW ڕ 3 o4jt^rj7A~2SZع,-dYSbͿb>o;7ǹ5$"HUD> S^gFB ;3 zDey c~GJYj0%;zjQ˔}ͼ! qiDng!%vDQ7iK;,=K$Ď YbG3vCG@ ;a'HSD RT0K>5#ۈ<#i|d:0O֙k13#9dG WEUT9?,Ď,4.tQ&V G UĐPGvf2 M!vr숉,F| ~} #Q!U v!x GR*XG\?]f\"fW"A |W#R W"Iy9Hҗ5qb&lB+ G2&'2|h" t8. T#qe^!d$V!~$H*1PZ$e;SՕGC4u)Hux 鍁#y~Su/?`]!TLj~BBHodF [=HYFyid:Grq\+đ NINt~rW!˕FXnKvp_踸R}tMQ ͻ`HT8WW** >MHkjzB1H4©7-Tfd4:W0RwJ#P& DrRCFUt(Đ, &Ž}(VQ9K]CjoI"dw a$&PLXWK5u:QO^+HP.!#xhNd5),,ISGM 8pJD|2 g*#Y" 6Q$C]QLHyD53 8&H$ ee%+h9˼Fj  #W#%ê_u`0`$\ /f~+u{`|q!qY dA1!4!Q/&Y bHv'8wl!0RwXɶR{918/BHI~V$;gW?ǻ!-X}B*,myf@BH]1^J({T…J~OU=1=2Fr[#*WrMzBS iš ?P$â&{sBjɺUz!HS_"9aԃf !#$LWJHjӈ1ά/W}VsTD}l@2ٚE/1M'&=Aɕܲm@ o$䉅 1$f%,>]9/$ <]\z $HG5;TAl W5%-绛s I OL~ԍ?kqkuZRb?7_HL-D(EYB苩ED>I!z qFYAFNI6b޻Z Q;}U`jQVËlv5xɍ볊a{[ 5{t 5ˢOhΏBSPҀ~QGvˊ Ad隑\t 0P)č&\BGCl9#1]!֚|f "G]Ҁϰt)*pfjɃjB5b2/t[č77M.?5vU,8uU4#&_aGC "G_ȳ t͝Q5}SuL^nFtI |Ƕ7rGp>(-F()k;d^1VVϸ^ G:`Z͊ɟ1g>FFbl% O=|#__?n&IJ*ogrs/Z{ DN@}O_Ù_dCxNߓBcr 7 5\819܀Ϟf t:^CF Kjn#s'K%?Ɉ,NGVߏFN{t^JySqUL)7H:HJ=kNaI#unfb+.YYA9F(s0Js DF|fdp9 !Hx. ?R ߡtn9 ʎWt:n\[V5I# nH:ӑߖ4H:&oI:S>Ut*H: ݸI:utV%ISr(>L&,&0jJ qfܴ.&m5jtN1H]sq7Lǘ&I:goW$.AL9si=l}K$bXL mP:\ZJ/Q:gs`ι?H(s._"0 b[ NZ AكI~aa;ayD 3Gfj%C1HKu9rH(@: tp)#P:uܠr4)GL9 3kstt?8-N+QFy(tqQL)2#m q:d&J߲!CAvh:g~a98PNI63$ΙtiCk~thdN3Oy:\7Oix:/@>(uheQ >x:y>x:zDOWNPNg#K82oι.\0_pKt!/N O`eQ<PB9ص49*?f06Gt^7T4N-cDӡ94N2*ɗNftLNGn%mO^o:bpFu^뚁:򘨃q}uJfk::FD o :#tuk:gquΣlqD56s& Ό:4"OxGEaYkgn]:ň*臄98_tӶ/p:p,-f+^*,^Y:|>7t$DNDžBNNt{`ʉg 6Y:/sr>lČY:4JLבTkҡ%=`2a$X:gB8tGx#ι7%x@b#t-i Co鋥s.]@D2VH(>SrK$&p`fI|lӔK6.!tx`MstD0gu{^ofӁLҁ1+ZthF锨xP:El鼞A:!w$ë6#|RL!8:43[:>VB|T7K`Ci]HNG^qt>pӐӟz%$pՀ8:SE: st]fL!FcZ8^<1:\;M1G\34蔠>(@`6PH, &PES(a98bp.oW_X: Jbݺar0,1K}0¸<<ު? UcNHF0h:F7Rˏ("5FDu6EDs"Nryd֚ 0S:xQD*AER+T5dGa'0H>qGHn:zvԁ㚨w#]$C]uuD@}D."i-:s,PG):#SvW l"VL 4sQ`N_7,G1Cl n:n+ ᴖd@?uduJj]M unkPQh3C`u>4G@.12e:< <;^x:\{˛C;PN~8ZBD2*}'"qßҁE9?嚑 zt8#}Cu.!M4MG؛sFlgMGv辀p tN#x*fPxCNM|3p)f(w"HĞAvo]1Mi:%$)M&~J8N#6[aui:}t: \;=n`#GOB(8EDR7к0<9}#5at_!1txGeOGQ&ṙ$$uWtM}u^+:y:cF6X_ : k1X F @: A#^i :|āq"}9uJU`0XDsS&6WiΔ31lg:zg oιCė)v};Pej'e`)H h 4FZ\:|eYu˟$.A)#kA)-@w& R%FgAaMa`_`;L˥ Epu>opu>δ:L.:Ձo吂UGΤ"X[T!UF7}p5HT~C[^v::tHLU+mNSMs]MPudP(ܞЦ 0?)58f(w'=IÎԡY TaC 톦0a:V߆0WTOaPPu^:\N;G svc5x:8S@u_TXlucuF:Q`u wӋX4 =",-qu-X)Mh@XG\d5kyY"PU\8:QCpu4 t60m:?c]A2)wuOFuHӄG.A_2Z ۱f NT&T[֡c:=lbQ 7[Slm3q /W{[GyekYZ`0&lZ$U?u[n:`귦Ks1Hl7[0ZeT/i mKFT [։Gl֡;=l]euxӿ:YZ uAP`uNj 4\~m܎+BBpj6^G V"xUSI|Fx:rsqZסm^:e:2u>u)j :e?l]H5]蜮$Dju$7og?e>Q>:uX基Hx7ߏ3/훈Pw̵*Cϛp\{yt ogP@:2IdՍϓ/|BGPT>>zFޟS19}?+z]SvžS8V H1QmKM~?ft߮r_i&P'[? /’sSZ̙Ex 9o!Z`>qp4罆T d}rf8e + \Fqf/gNa5lӬub(s#"4qENB9AΓ>މug9Glz9`99kdtf͞։1dQ"Ճ)#J!X; i2sf ܘDc#)-LYT1g`i-V\wmO>;bE()ϙ1!9p4"o<!y`弈)K#K44qFMy0`@Wx6̢#lPP#l[U\e<au3cٴvqUlGΞ38iLoLq:[}rn)[}n9BѵeB~r$ȔU 3ur<Q1wr^j53ϼr h2αrA3&.ux9oS,̧Eຕx V 8$2バfY*0gmDVp[ L 2~f)o e]~֚9{?瓙 v)71r q#D9!;i6'0+{^̜x䇉,xo9O*;Ɋ4zc84sBWHТAΒ1re7rBQJA{3szHj <"\:'*04"}&:ba‹IS#Js sϣ-)濔m=+VHsgOY&XY%Yxrj(1#g`P5FL|Qa+RE4o9viء]hшz;HLnti\%'=\l S߀,>sOjϭ9>7eN/ιOs6A-Se>Id7tD@Z&+)rUv{sY9 ^³LK1 |-HgNb :m-'IFc"_[U:dADR!()< $SLAMq23)S7x O+x@sSNƈp,Hr.,RB?&AB< D:EY<>sѕ'`eer1bϱlZgNF.۸r`4vϺhDIǂ"bͲ'2 iZMɟ xHpI@N&PEjVKGV`?\+;oKLלb''ݒ/Jm՝^wVss <7z w}dݮ Jγ}Iɕ1JuxX(pO*ŗ)C&cygr4@x7%tVxbc!d8g'"¢on_dSD" ̤ >)n:eF%=U}Zs 1U2srem9;X"/ܗbWMl,?ps$?5-9!.kx)kϱx0$[Xcݢ^G̊B8 a*[ $Fl ,I#3AT4pYzx9YàӒʙ;On 󲘢P1ޘS*4.r{J%-inh'yH?W P9)($--'az;s<-&9"P$l!̬/I%K-Z5``u_<+'/P>XAT۸>ތ%@̡W1NgqRm=M!?nM'Cw),% 1YVP! جjͼ9G %uJsd,hAh,rYpiI(:4ThӪE˞ PFRR [T#>B-Td+Ԓ"靚IsZ{5ICI|[V`9=~9_JR7g^l}+NҞڬJ@oѭ]IBt;:jst0'Tb?)zp)sw-p5"gE9vDa5@isiIa"0Z龳n6?K+:ǣD.XiV2IӀݞM*VP $,G(mqo>|+:r*dA-n1Y%4Y P`QΉ1plI"I>[{_&Z 'rHKyIPN"KV9X9;hT-aLjV ɒ]|snb({ &^(- Xs!kT21>R3F\W\DZv>~2SU;S-r"VV.~$x8tU$Ѐq%ӓ=8Wo9棯ut&JW9`! 9 pTG;SSAv-H! RI.:Ro^9idtV0BNKu#HAVjt-MzIZCWՄ4Q*Ttld'%@:̜ͱ*ksHÚ޻帲Ppg^E((YXi UU gR{ m㖾5v'I+EN*A(Pqi,8>u҈Xl߬.1 _ ~fIR,E5i=L_tsO:8Kz$!.,qMbMC]h l wHkuf9a$ESe 2|'|0]Y+yE {`Vr,4\9L[ORʹ/:vFV JwoS5m!9A[TRh@}IJE<%YIb bCa>4)Йu+?w)HȂMIBӜY9FnR$֙gtI–"m;U.GRM d#U^g<`*yvΞ:[N$b얒9.-PR&t{琠лh!I落:ՋhR/Jh-Ѵ@kwqGMNXNhN|K/x-ǨLg19QYΝ[n@.D-ÓMg:@0&{ g*Pˑ$T4djWr|t}sIX:jdD?g sP%%=kCwO$/p3ɏ9Va[sC~Oj8~na$F {*Nrbo+ȼ<ɚ3K[Ry&PԤ2NjP[X(i/§4C~}>2ʜ}+tI>*j& I!Zps\V{KbS.u9ӓ S9Ij2ItA$LJV_ 'ca:VN9ugaiV|quLY45$I~fғ lP9,,7KƉč:BHZ'yVUX@9ۨA#dtdQR>}LRU#9h]IBVxSK"s'1,Eb&P`󄒚؂CPcOc2![3C1]CY 6K'ia-Z|G%'Al;hƝD$Tj_#)l!{G+$*߽iS*`Tr#"MCRW~)29lRҺIȳ"=5leKKJ w}n`T! x^h3}:v$ן=Dh[X;-/?'5\S`GЮOL1YDѳ8&uԈ]LΓgvYʣhk*1ș4 d@m ڛn&u=U=scV-畹&v4e؏,iCp2 ]N_isxI:sxyTƒIB)|.9˭{ A$Ŧ)}_x%hw&C'*'):yIdLlUgZur46d8q9Foؓrxt- t͈cIb#-^&i!zf?A[rD:AI i8*ewm!,97 Ym91YWG|HnEb;ĩg֨BLah!p a"fU榥v'\N_R]ޜ*6nShϑ>E$&IHY:>VqQ2y T2IbLKD#V:I ;)]F$,=5G<"]$5f,h, EH b{_9b<ܻ 9E lɥÛLǤ[xmR5 녞I3%J*rX\u?]I{h6IW*vΑ9ˤ@GȩJ2-К\k0 5) `+X aaF dUPQP$i#x%5>]LAO5aXJD?%iX*Ҙ2ZajD?u9s$bb39`J~Nb旧!ےI 8I ~v9& E)AJ"ill2,I|#pפ2je*mhi[B[󤪎VW+gU'2r:XtV`c+ m?\y!)b[⪳Qx(2Yi{)#" zJ*{421(TMo#nI[u@fŽ-@ם`G_/INS #K\vPy$i \@feKQLΩbi:A, eT%ϓ.nj6sTJhD91[TR6Y"oT]As[(,un?t^^9:__j{!ߐ_m?޿OwM6?0AX|s zq9o˿_HH@;GOpGsv%`MdPpo\bX`:,{y!kT^>K=?^BF4( ߨ2gY+ =)I6 ;ޘ^uܘYsBU_ꥯ{  3Jsh6&3^@`|XLPTFܛ#DžFYKtuǁuHFh`秀Ձױ*'.鎟{~lq6FP)a_mmR4rfu|+xY 񞯑͛G?B-N-/-<2@nķ?gw^/wcʢ-Gf~~[|7oa% >w#7_xko|ƌċrșo* tY[9s/޹Kw}{&$#n^8&y XCǑJ f9/R'u\AUxNbF_:Uw+vc]5rfe Hy6n IR;\X3Ff-Fnv^87CuvʻUƜT?u/gIƁ>o>hW<]/4G!mc0 ߏn3}+?;^s&dxp<@9.2f' [ޱjӻ2c;Ô ?Gy;>m̯;wyk ^RU4>#X/Y3M:OoE'y1~=}k?aL>Z"@?scowܯLFF /(nESZzh55u܍;$k{~o|# yqo{ x%˓cegxfhkcj+,m-pCFvzdԯ| K'xCpc%nm?^Ltz1Zgp{ֻ983.Lox4 &W*dbdG9=W2<_#Ko9u \ a]ܞ nv2J/NZgWȍtKΔS6AazvxvC#7C\ΣZju\_5`z}zg>˹'5q oFK3pf\-8yB/)F&Lƚ`ae xV~F S# kyWL!xOuU&⹓%{&R؆FvyP+ 5F,z,w=z͎}^ȀFc{^ݸ`'ޗ=rYNj~b(o2tYn9B 27?#Yt8<K#[f/697nD-{L^#h(;‡]Co)c9]ʽ&R naK͉^\hSŊH %2@[b[WuXlVZyi$̮MlH3^fCViwy4 *LO]oCRwUrFȐw!hqYt^KBfkɡTUi`$X63uL׭p9o} U{3^}k-iwuޜܛo}뮲_#CV3ru]#v4ח͵ea&.t,sg-@lZ^>m?52]_v҃80U.E@H5LR)(Q#UV׿3mJ_2-Sl\rxG+3n'FFLq.?j\hIzi3b⥑fI{!p:Vhr]G,R )x^uNB ytzm|udXa4bR\\ccߝ21o "O?Y$5^#D#grX:0V~ O{o};: z?@IKUo{H0Ȩq;[q6ɀ\,ˆ;鏱x3se+JŸ^r8ptx:#El{͠ףjŶB뭯{L=j@%A%F=eM#]2 b or*j>ȃfhQn tN61}{;@{`8=v6ߩME_Q`Ee1Z[zzY¿9qkey/- 7-:XurҮO2FTXo{.j{B/y2{Q4r62~ {e>3KcY?r-%$Y T.ǚ4_#ә\2g2Ro!@=yyLddqQ3hsebSY/"<2e#\ꑍѧGĀ^OmG<ygydOӥh/=ϊ} t)- l^T|fRγ &,;#{oK5|\~ m~Z8_ETֈ\&dQe?v{4"OPǴ߯8Ι VވM.{Bu3q t=wRdЍae8Rh<5[>cR0@`@Yb;YSK#S]S#Kg)(/m֮52aG-VZίy^e*I=[s`eVozY@Ρq-ӽbځ% tOLϡ ̒9%s[R5tK0Gj1ɊfdǍ>pZl*Dw{>8i^5׾v=Т.[5r]?N268/&o~ d07!Skd3߻KF{ЂDzgBadͫUf!>2[wC6ei@BQ+e[~4͛{ϙ~mVh ݽYQvHKx9lEjgeZ'OQjRj2+QiaV{dp晖]]'Si zaJxՔìI 5ҵb[|X#,p0v<C&!諅Ϥ9NSk);\SsNkMbҡ]elQ#jDW"v uLFL.Zp{dz~l.(p{!**v}Zϗu!Ծ' =r˚`5v뵃+%c:,=/Tc?eCiM ]&>w߰W&3 Yh-ٿF\zM_#7MjJGR2qֹ-uM4f_ !G9#uqݕp(10JoL]}$o^O٪;Bt& 3!&\E!7]q5x/Ek c t_#yhD JkT0dQd5f*.[| (ɀw @ukL0TōG K-{d*]1P5i(4Q"tmi5_xl*qpmT370Zyy3`S?T>Q=ҔO*.n \ˍyF?'͍ƴ_K@cZ' ٘R7R9YoHLƭ"o;C%߮} eM9J+10x$ E,+g&B4&1Hљj+/V_/ ij2+`6_R*y+#ɿkDbPo X?5շ5~D#bGNV<5bh~C\G%+)Cf?:3Hft %?Ŷ&q%ux,jK?ˊ>J$Gח$o݈I?J? F,W H?mܼ6P&Y?VȺBm L ІPDBxmh-#9]sC;7UIN׷,0y|] X ?jvd[k@{ 9cѠeFb2gJ&+'*l5p ^(ѥ&tRg'R|+XoP o3dq[Rp(k g(GƭݲXCl$tg\&OoXϨ/|-H3Ej#<LǷ濵{ė4G~cHUK5D?l5O4(D4ZL3 ?%#i,D @zS D sիBjjkԁ5sO,,DXm?7#(g_zF O{% ?b~ i],2og~XZVk@BGHq#7C[O|IFbͿy?`ӮȐTڀ.A>1o?V9ܖK0W!B'?k3AHl ݜu tt8~1wP0R74="?˾쟎f?1ڐs]FGkKHϐQCz&Tl!T' CɟkD`/UHL9R3ꩇLό4ǀH4ki%r}:+Tp;dXO?u+#'a/|#]׈4})4C?+g0Vn~B7#cEv\#N9Hy #D|x =IP%T ?˺tՖG 5’mކȹJZ?s+LǔLC0G$o=ؿ-#LC|i}O=b~D2b6ҭKlqyIg7Œ ֕[?cHϷX ,^3=4F -?wtx F?:$%ՒnBXo?uCӖhW9t߭\igiR5 /.4Zo?6D.rh>,e$5[Fbyvn",Xgn?k;="U#b&|iFn;F޿!0M_?q,z z X?m0gq$uVk=32P߆ڟ-t?Gⶶ_jPum_j,Κ!zv#reޟSnzpB8Hԟ@|1[͆D1#l _<F$%-X=\J3\j-e<1ޥWx=_~>#\o?E PDGIH-_S|ӳD#H7OdmoWq#*,o~IH {DH!G ?B-羭%Պi^)>xKF0LX}њi2긖cq-GЌK/{DRZa,oj5"?\V튡3DC kĪ{G t])݄_x2>VjNs+(;5R dK#  Yb 7̤g޻GU# m%Gj?2~j{Y2U'ڭeJl%E1vXO a/A ~ =<~ {dѓ3d.ڲ~D6,`kHπ֏:u J׈ } # ,G([LǟJ ϩu#纛S\ݲYxCPBGU"fpdU&V>؞*d{Dlߡ xVV3j [.?eX/џ/헔bm#_#Fj~m6\A`3@Fj@0kծ ax@<?p]u;@ FFt[O 3*اFP"K7Mx-?Ax!P,b0T3I@QrQb@K{0q$  .N2fo5wB>B`@Y1 I '_X%+X#o=, c,*c6!a6n3-bkN`0 0Kx  d{DN!F\{o Ы> 'Xaٿ c'6"br40vdFۣ~ N[) xcJ#*lhK/ѐQDM # {`.9@ȦT]cYa@5  ^XBj$<mA'1Vqo{~kC#$:#䣒7 ={ĥù<|P [#F%b)u;0/g`uPť6 % YiV}.L3 5TzDYk@m(ş7(4=@G((-P-#+aZ@'S w2m&~2 S􈭐E`"G\QtGm aؓE m0O.h! * =z3=hb>#iV܃?bG>5}G!g+gc\C`;xbpj,6c5GxSHvQ|>#O=Unϧ"T>8pEk|}pϮvԿ vQuADo}oW9T?W=%w/\_xM+ ѓz}]4 ( }fo?}D p@Թ #43JzgIGfX3qr'8GX9"`ԡFA%͞Aū9bJ"r "6;QK1F9DSry#0粸N\{jMy.ÓIi1˂NzanB]֖}DIX pgкcG]dbNYlQ'gٹՂ(}rD7?9w?6]n3eM$hX,=gݾ;0CA~G|mdn51E»7d9"Y_!CBI$yG؟qRAQ$C*ݜUs&v~FKߙWDTS bFKh+\5;?%9r6#RoEO1AgΔ8;s^)܌쒳P -p+s^#8c`l2b0SZƠICR HjŽ+g~hˬ]* Metw7't1dY#P5t3_{zLZ68h?%',rW֋Cg e)c9<@>)l7pDT2FΣ¸]iwayeҖ#c/R2PQ`2Q@GOjRSr\(Vrj$a-Qyj> QUcFR29rg8?9"N`\9-`]d|s0axcǃvP?j`6#Ctcӝs[*KڔٹIʜS7 DJj6Ie鈠ZZDZNʝSAD瘱蛪PIN '49; ' @tI]yer ҟhe v|he W#˫w˩[8"Tl |fQNcqDg+ث9GD3"UGS$dQ'ԟqSα PU07NqSԀvYsӠLFUL>b!(G\W4(VN:oKM #; L͊]WsV2bΜ3g4# z&u*3#`(mDYg%-4I3! ^$iҏH><$51,qq3r f6}ɉ+JV"`]9EM܇ rt֠y>aVȓ( h_Nn$+V]hR)5 ȹ#"9Kq 8= sJ9UY)HÈWy:`Ί$/6Zʸ[q#Sa]slz@G;I"bh1+JM?e>#Xy:r@.U6stYmR]oU7m[9G6lSz#tƓA3g!Ub;rn5)e7pDpp6Y#;'58V,(',Zզg%\~ԌDPPr5=wNsDXWJ ͮLN\ViG$6#čҏ ei.w@o rʢp[ՠ+2"#N,6F,(M49~ c,R\O¯_Jf8讋k/BD٬ @J^_;ʂ/edr莨Mg5!QBReiIIu c%U;zs93 U5':yIM["BcOOiA-?b=otTW6 NTJV#* 'KҳMI٨Y%̉kQA hs*g;I?_rRbH!c&Ghn\g1aM-Kk$Ell,*՘UVrgk"1Zw\Yq~ j翓WTYÄ[v_[1I3U_5$T6Ij"z[;*B|[? yM}_uW+ \y/ZPT|c)":&'ds5pN($,w}q5#B² @S/d$ruz6INfLRlJŞMk+3sX;YI\V+t2sp4$0( 8sr,ɳs1P_ $א!x薸xi ޺誝T6->:DwOykZjm f}'_9@YQI#ِHZ9%1.4\ŅLj6"g>'<TȖTBzΖ$1 W։Gܭ+G<̼nrdMTŬ\)v[xGWuPP]|{B9W}]ZW2eņVɷw䴥<+ntnc9H:٧;ǤNTDsoA#9I*,$V#WX+II$5+29#Ji6!b I P<)0o }U%3nU9H99dъX,pځ'5KQpEw-:Y;^"XsQ:Dg@$=rV#֭3ǘh9dQFD Pb+G @QXN1XchIyI/AiqJ@99B2i*!6 w9ɖ*ߦ +kY}M$Tl&ntd3Tql;ѐsz8uiPZ9[5QW΂U:3J1)[*\rt9!NRV-MH:'&1Y[If Gޫ+ck:4⡞M7\~ͤ7n%ɅKT{UDFv?Mj۬&>Q|k9]c8D:JOEjp6y 3϶,l1o<4ͬ șjcyhR;F=p7j#Z3kWk[X|ߦE}[nh4̻6ɶ}zN+ahb/E_D9\Fojۀ$)V4a?g^TI]Od"72z K%hcfP'~/n%c!'ǿ,h A3`gEרqy4*$iVMgh 8 QEZ&|m"MyD^L>=ȶ=Ig5MUĎq\7kQ3`'t>yfxs|­B -}ҟfDE05U rC3n1sXw99@cD#FM.@_}gl[]KM_cFA%0n>*r%\no*93N عL^$0((*𳛖7Fvii_+pVTnXI#D<&w"S>8lS96+OiˁbS6՟]&ne_>ȑډ܊5LgLYj 汳2:]f&3 5l4JD'F0 -W 3!w7c3]nAs`%JbE ekꞱ!sEXHُٓC3.Sph'3fӾψ$7t7W0;ěG{]~4@wѾ'0cb)?lljԘrJ*u1QD6YM6ܛsQ>[&B mLM{Ê_j.7j.ѝ:U-'M}׭EEw+56Ƈc*=,&rFfqs*Ao!ff!\f:t`3d]jk1:'BM$X;hr5z.oÊ')@!-#B W0?KMLk16\* 5MAˆf w Yv-f[ydއRO+Ʌ 5=#ڹ;_1~#G})S> k1c$yR=738l+H#e OdQY lo?&d0댨1=mq2ZN!Sn g\Ϭg)nM?Ì?Ì?s G3!:{,8nG1w‹aO_԰\Փ( vW-*:3 ~ZL I [7k&gOc:&F&bP聓W|cr5޶e=5tDky;V~x^KH'2:ң-\W (@%:HtT ȾdNO()a% 'l A gƼmcTw;2a|-Mt%)Iz\഍W N'+&|tp!x\tTKn\Fc%zZaK  Cٚ $C)PLcZ {2;+)ZSp'k2mHMx)-ɻeیHIܚ2=VGTψ9D҂nu$Yr?oU>ݞGΟ/t5__~Q굺'½&}|:;%5o1#'Pe[W~8G~#f?mu{&p拁eʠ{ 7S}65*!6ڋ7r5B{# B &b]/ݿu/Zg9T׹bM68[:G?j#Sy+[~{N: Y#PȕP'$3FǶrԖ;lt_^ő(*f #ЏY/24Pe \~0wOpd +kz$] 6g.T.>;^3G425ޗ3ośhܴ(%jOq%aj`?7ZdJFmLXvht{☦:oȢCD,=tNMǎ-\W38.踾k"w XJL.d{$G`u5|+oGk/g‘-ep9ؿK{T=.mZLqzlumbbdh2mk%b nNϟ" ŠrWNt1Vi6~"Sj̤$pj@%m^3ŕktWjAwzk{W">Ff$9#>V9jc6вmKrq k u9eSۺ$ иVlfBu<{"Q5ZCK#orUZv'nN8 ^|\! Jl#yķ^^#AIȖ\o GS>;:hChNOM}6%5㜎\n* 46cM %zOGxRPA@<0W)J$GI%rߋ/bB A0PI)Nesګ{! }]|]^-N%0{ z`ttIY,kj-WXDUhR%8kCEIhIB+ylYH"R!mG> m Hzuߪ^9D:_tNK{vS BZDUMtJV@K2(F;rʽ?̉|7$͉t\.]j/OȀ[8ޤ.dãt;*vlz)7ߨ qN8(S'4 Sj0dIMKt<rKn|j˹Ќ+hbZx\v*yu9 u\{B@i \}~ݿBy3:s]#8ȔT71#侦T]O1]" X]^uvW_#ӵEJ/ȕ`<3O}ł&8Z2V=%L~W{za i##@cL.{=~E|PK*GEJ37k:.TG^7C#vqǐ#F8N;x5Cv9n~&F&6xK:z,=дV,]~m uL#Hq(E;v4oxLi)%w ?ogAMf8Bҭg‘›T /~Tعԇ-WBtK{Dn. Gܐh ypҭXVFFUGiQoSsGسg\B<5ȉ7{dvo$p")#]fn6x5IwlJۡӇȑp"PȒ ]p"!ۡGD4GqlJhTF #UV{H\ h\}AEt]  R])ŷD& ]:]~iUݹGDuf38..9fM{dP .H^NIYJ~Br4.]#%<ڥp#l 7‰b)V&Ĕh԰!Z~ɿb$i]H7Y wV#j,‹J4 [ĒN-N 'qtmaFt1K}J %^a,iZb,>5߂P(4@<}-F*?PK:f!ø0D D0jWaXo& +r@$Z "VHRy1p "I4ph@.l*=OĵG ʁ.!0"v^?H%4K#UF…@NF aJ) $w@a II #3F.)H h} DۼcaqM>| #e)EB EWD HUD=ea Ya#D1p{I1ȝ0Z) $11GZr04u10ÊGL{ѤO#]K%ڇ%Ē /A,( &59=MhdIRi14>L$2WX&ej̃ rd4S WI)քv+IY&I(4ISb@I̭G(I=^xR<+ 3"%:#G/)7ja1{bDI/z &!`hDG$;gJf<ᑈHƓ~p뛻t.+q5F"1,)4:@ѤrIաy)LL|FTXFJ'tDfa4z8I5>uA8^& I]|8 'kV#dZJYѾbD;EDIڻfGS&q \㩃# /WFpu iɒؗۮI)|{ _:$+IlC&XH3VĒ$.-XndUƒ,ٕ$AC tE,`z95+IM^wnhR!&IdM"^Co &ѸЬm(AF"ޚPE@2*cI4~e,^/%ӅMPJZS79O{9G"y/3XJ HY/)u.,`RMu)1jXLR_'. &"6grÍ##V[45xK_r(q5Z&Q&z _UE4 9ߚg f&m>Q#'F.O/tE==x1 A Uey .y-fH"$Rw5FF ۡ g ?r6b$NJoɅf *G3m2zDRrTFy[c{xv: QT=p4.gYhe0UmZEp0!H,a0tSQo2Z?*L͑#xKv%_y(5].H*S;)+GЊ`(Z 14BUdaC(獤Q؅]Ԕ}/tY7).R>?m GE3+Rjr9 3 G`C%3TWb@9W_ohޫD&Xz뼇Kܯg y\ E/Gu0|TdM Dq(T%R)&_=X=1xG Fl_7Ed(OU z)`` hD:$9pueCuQg$2^䘹+Eٞ#:_F^]2ѣi)1zTVֲ`(\HI:57:Bca(˅/tFq3zt:ǷQQ4 !ЬF]:e#B?#z~8 y>Q;;JJƟ]:*#r}|kD2yudƎW fs1 D.~+̇K+jOUa Y~RY9ԨpHD"PCG]BA/aHŇC/F=ᙯwF#D_E܈i#nDx.uݓ,ht$8 '$G- Le(2t X:&CGGZ:TU_?'Wƍx8V$=u%#'Ga 0pXIMk5z7WDzH K2hԵ.jG08 _=G3Bd|* ^>u2}{|#l?khA9'CGK̢zxt?yT 7sq:M]o8tsɭߌSt䓗pStȇ *2jWS??):c쒌#rgi??):ϣPttHzxd!j3m'N>`txs0:O흃AH@CH$@lEhoTd<<ȍ %k@o *o CKO0tpBh`@ L0tpdȉN@PtUFGcvGQTt " >t >U-.[tF Nt#F]ptR9dI^"щbO= 7J;->(|[7JKvT?IkP!K*<$MstrKQ$yX:,T񂃥oB NZ|}tRd(TO![t*[>($J7ҁٜ7KQmaSNF 3?Q:kL@3r[|ǵJ& XQ*:(|rnN97 ol 푺A:Qptn?MIσJ\ipTo\?4B%>#Njtrta:PL'q.Q3S@LT t 0NÍa:8``* Lo0l#*~+#@Kvx3Ӂmo0;stpҤ(z^zu›O!@ N8)=ԏP:1otpiN-8tu WJrJ؈QIa#w4=@;0(x599_G<0\A S580ĩtNL&`:%_ 80\̥CӁ!h5A*t4O N>7M77 NAN'QS}[Ӂ#x:eӁҢ2yH8y:<%&? O^t Kt"jvzxx:0tDLZsx:XIpOQO'߄j n^^uT?tpiFOM'94z|Α?I{i(tԈ0KwdJǶA%FppP:Ptr.J'#JJ6xc<Ϧ>B8BDAu# aܜ&MI;8$#%4_YAҁu)ҊH:O!]9l`}SjoNJYU CkL3J3C;J:upNxzĖnNt0R#a˛S8 ` F~yډ=Ot 'X:WK! /'Kn]MtM9=0=RtI @NJ5#m #Ęi4G:0ܹ"('h:PPWuQ)tӕH<899 't(ӁO@P>xDԁQ_Os MtԵNN888dNNq:t5Si|̱CӁ (8A20J=@S8|t Rta ~89r('%X:x5x;C=ONItLCL>L13B6 NV'LDt`: ̰xyR9tinyt^EtJ%7Lg/s)7t#(`:pD76Ёӆ@nI?0j` '`:9w0;t&h:'| NOEo?84X:wJ ӹn.|+< etr:Tɧ P?LϪ(' 57L C7L.<AFev7ga(8NVrtxH `<3 Ƒ;a%}$p:wFG* N稕7M^%xAӹOA%0=Ӂs[9+UN9O%#Gr' 12CҁBO"X:ϑ9Z\o,|ڢ,]KsǽoY:ؚQ @`/7.J|sxFvoΝt`֌,fp7g"OK,k6lvg~X:|]ptMN@d+pq5ٷ(%kG"%:5d(%QJ9q:V>A8܈VEK4-8ȇv/rJtsG4+9nnM#ɤC)it"DIӹ==7N'+I`gL6t^Ðe|IX$w փa>SD\L0"=܁w >Qtx zK¿霰Ѝӹ/܊ӁLNvYxQ$w8wtRbZh7Q,Ё@ J:|+:Op:зyr6tTuo 3'#OP/.>@%37Q'q Xؑ3Ƹ:8(t[Tu*P[XRuT=~:+4Aԁ/FD )i$:e Թ7SVwLRyGHLL SʶԼɺ7S'ԁO3::'{#uԁqC3o-2 ;Nwy:FsMT@uwKoP??:\4oL3 sNqS+=F"LᛩS|3utS)7X u` 5Dhm ]quXvBnSNt @9##⽉:euuMԹ]7Q:}D&:Pr ,Itz`|H|87RA:TV5M uK u|ÛÒ@1WAV:09DS¾1upR @'Aޘ:Pͤ `af@oL|CS'b7S'hpCu[4:w6 ysg6P|3TN<<ɀю };OfԹ Lf@ uQidd TsgfH<#Q uiU~3up|NL hYNQx3upBK8Lx Ot@;JثOk9_WOЄs''\ty:,ҝW{>2E^ЁAu^Q ~ o>u`+]]3򩓩=|ꌼ| ^~;wr/(zMB4!M_O>җ_b}?AU>@е~?hK_Տ-SEo¹ ǖwv?|oieMòg&\{7]>_||.V:嘑 $#s@ڷkDU5dҲcFvBol,w/woFݐiy8hn !sf>p,+qVV3!YPn]rg%ϻFqm$Lnj,oZ2cN ;be$OO&iHԶڥkF1o8L G:oy,7ʹv~W]skeL/>^ gUi;HI /#aЉ(ό$ L} x,Za=vۦd"ie3T(Ճ%=Z{aYxg\1M!|DxY=y<SOVPyz(E#y%4J4a(1< #?$+?\/+M@ypiU)g3/=쐮M Qe۶oJgWKQ69'd{YɑA+]8ڒ'/ *3aMϓ|&.#>-'<*}cY3C'j$[76S)ZD(ަKd-W7k"H*7`kdYw.C7)*RQ{$b=P!N.eJo 8`{? S-)Քmm\fC"[f><1`L@&A~T[ږZNi^T=5^&~l{ 1:8]^h O yyhQ K$Vg&3?)K4DtCP(yJg貲/Z0acA?*u3y@/{ UMpM.$@]Ŷ2\ "+#ؐyCX<07HjyhAlt2הꔃJtI<᫦T)fBPfllhrWيXP gq!'N֦> EBU2+p.jq!. ɶQ'GB(y2)}9l1xp&o4:s5fdfLiW(e)ZɊy/PVQ<̊؋b3A˔nS3pZaɨ*N2ͣ[NlWϳa ުdKj4IlL%@~3U k6qh OjAIqKT{QNOe56)9t' xz$cOOzxP%ud2%Sk\V K-w'&׼dkM^2SԔ_Y-^L)F82MbE@IdeU⅛2.V[Ws'1VM'% "n" $F9ι%ɹcVJl;&.~51ԲylKHHF !*9%{T_&<=~!8T cjo^ nXTg1jF4[W !A9KIT?6c6)!!Ek@ L*Yod>渜P})o-"K&yqk8UEmFmSJ =׈=761جNߨ0YLO!C2Ae챌-'.iЂu읒0N׭:Yy%[65'352  }3@hc 'L򰀇'x+T(C30l%fz]rg$$Lɕ,xHp \vX"\Ց-eUSŃFTr1_0q po`ϫ˄m&UWUkqJ36wj^5ml@oh3^O,a[PvcLٲ<M[fx6!8Z.KuFa6sme_5+]&xj&8F6VlHq&pcq*mypvx0+͔+,09ԉܲ [ =8zՋ exRՀr&  8SÖC~L<[0HdM͘LR/崘R]VA{QxoY\g516jP $OL)rKVK qS[!EYٍ%(.Jԇ|okP(eJ)Ar#ϸJ>dS"oIe.ic\BJG Sst8G &&LYjgCB5ZS] n˓swte塰[2"*z2Y3gjErWόD$ @ w zu=K)lll r0G%iJh#UXluXow]';Ug'u[^!q,ڰbӓ񎢓K"؀̮2A\=P@6N[G*ӶLliFf"BT_P$e2z]wYy?:];UډNGi&hlN_bLѥjlRǼ>C)+ |Yl`kʚ0euaqɎ!2T OAXN[U[r2-X1hLElY[x'*D#EEGxOhh^ܚHz\0b3zEi}ۺj02xσzEuS85"Y[pS)*BdtB 4\Â%d!p7.ױo"a1ʑ 1Й;CK& ,dʛ,vCIA"2]AvF]lGՐ%?6"0UԺ y c\C A@b5X2\ź1@v.Y&fYMT%z4L#x?L=ۈR& |UIꞘ#vZT5<1^fkǒGBP QgWCW눙̟lC4!ULLv9Jٯ; ÒAI<%>k6E6(e/rѤ9mU[L)Z0s$)S]l,S_l9AO11sKFɯ9=~ҤOO 5Z~)5j>FJ;Y@zLcעtGT1u=bf{PWφtp`*0LF r^tMI M!=mQOs<ɾ /T_y^بyؙuDWwSM^w.B֝;O .HzStӫ &c7z|Jx7@y{.i_PYk[C%MDG3_hhfLS`'<pEhfV8Xkn+PDnJCQYMVA=OKNS@^J'U''07{:AWS6 kC)}VTޠy<޼𼘡l[w8cBjOy B׿?}E.wݿh_|./굿|%G>][6_|o{7ʧm9~? WO]Gu_ՏęL@ݳ_||/x"W[ [a~PHߟ{ 7yݬu(6B>>P#?}! ( -ҽi鯿»/{}[wt%>_{A~,%8?_oqk,V]We_~շpuGb4?@˳ŵ~Y>]~暳||kox>~wo_>r⯌5Mi>~mKvS|/ڛRЯ6o_?/,_ __} 4˸gk?Ry5ݗOn/6tA{:zǷz6}f}s\[j0k~Kr_?_a}~WyNħw?>~}B+Ph@VZֿ-/ U>ݿymh o{_phjx:?PwHJZ|==>]!@UWKW~Ze?_ک 7zxZу{9ĬF\kv÷_xZ c Ht{ڋ~k}Liק xzvy@P-~76_e[tix 0Ӹ|7}_}ݸsrBYZ8DB+˫LɷܾW0^w 2èw~=85xxa}!{^moKK<^{q?۟nk)owTR.+f^hn-~{-Y[Z(,}9pi> stream x\o$% @O^`؉wY=JZbI#k7ۯn9l*{ v5Y_}?<_ѯ_u|;GI8w'"DQzT+hⱷ~\}3|H7\P °[0a,+67jt 9.1h;BIeW gzx"i+ oƵ1D; sfÆQ;[ V~x_vRy@DO<*QX 䯰zfm<^k;p7p(5:ckWa[wex]exU~Sfee2 ,hMT'\K($CwexQcޔX2ツᴻY9Pb az1 Q,x}lW2(CFYu)ܖn؋bm*''+e~TL/ 6}]{MWee.斫w][@\u]wlA_bmV fXᳲXhRdzJK-#:5G`񇏙MPx3~j'a4V!#3:La SA|G,ݦ]KwΛǵ&J)*]zgklN ,RW` @Ix́pɻl_` Д'}"= A9p`۽s/Ԑj-4wE%(<$,y⊠EGBlYThjkSJɨ(ޞqtۇL$1&0p .Gц$G0 La;i2~+Mf2lE[S赝deo4C 'Ltqn3r'W=g -:9hdM+ ud)_-F|lKmNiL >&r"D6%5=g9Z˩++ 7yRѬHJAqP@b)˒}ˍ`ҹ݂3 QinS%4?% o-7hCE&U s0!ش*zm9\kVlM8%p\$@5PM9'I=lbÎ)A@ %m}Õ"AbHH'giv-x .3r3ra55( i ,[*dsq *Z%-LvFvk݁,NMŨ ]z;Oka.0e ݏ,K -eCzkH{ f~3Ç۝M_e@b˯7d0?ϻ[/b>0bK6yhRM:VaMr(  ʐV3ʲK֋iOGoߓwAYw_Bzv=om9?kQ]#!vBQ]jLYƹo;>Dl\+O1ɸ0tgYyiwA5ka(fYX*^b]3j,Mϼ}"˵rqª)|96RayY6nJc =nH qy8#DBzMyVJU d3툲@s8e/1TI2C=fj|zIV:I Z.ąWzuZQT ! _Med:,dsq".JlYxf{NӞ l&Y ɱ8Isk7l]8ut}t EJc,XX~x{J =cܝzZrzJu@V1k;/s/SUUSwΌm_27?QM:qfb,i9wR`0A_4X-c *E'h}"<]'\DnَXh.Qqq/'"$֝XJ-,o褰\{$~`ipmڴ} ߜ[qJwcn5  Yi۠4G *aF'[/${j^RRTڕJ%1Z&o CsQ6҅;ZRƑ;L,6\&Z0`[(x9m^ң`oӂbGTa4q uVl!7~;3^pCbIojbykPH[7'-ZG^;;Y)Ra+!yTo@U6O8”O %L4L[rC`pӷ)V*np>|B&ze*;py~;71i֋ G`{yWTi'vr払 M@p&-𫚛Fk!ۥ46e90.,+fdx]vkUUWX?5qVðe9o? a~,ĺO%2It^HG'ee0"MaKD#)2ZͭpsjV藠fn9^6 AE6JK ngKAH;~w,$ߥpB!˸XZY;Ut]6f3ryp>d~AkAxւ1> stream x}[&q/G|mۅ; =dQ&&wJ͝pݙw&HCuLo( ȓ9oyg͛3Szշ7?{j/G17_v&t_\.~99{眥 xٗs{{k._.?P9;db<|%\5H !o[k(v#_Po-uKq-u.qs(%%[og2M.u-Z#G-مH.[?#''4s5?W8gx_|ާ/3cA&Pv4t7}A.T'iQHKZF/xtѢz9O;a=Q½ɕyG R;C7u-S$Nw-SJSݩN2u-S:vhla Z7ZtokĊ%Ç0ըVZjUkhuv 7;a.zZXU4>]4U'iQh^2zA4GѢz5T0d tܗ4%( DJ#\"H}]rI.d 蟢M~S8R$T3NWP;+ (!G ӣ^xPWNZ:=hcF' 3'ÝX=&SSzu.S}xyS 2xy`YDޘlJuw➀`sm!R7G,u {_6[Dx[|w{ګ/$d6*@Ԏ: MOch2@ևܐDZrV?ujsI]nr$$o޵1fy&u ;s(6&\ 0TgOsn]MЎU)1~h7*vEK]m{ZyGBN䙶yGHg6B^ە  Ҍ<&<<O㧜m<6OqFP#yVY#BmQl߭Lcio,6w6/ ~'el\_W{ /.Vky@QnDy$4m@Ms} M6yfy'O}r<ׁ<߁4!<ɦry*3}~;' /02pVQA^ZSc6xq *ggz=kWQfzE@+ Ofuȃ1g4Uwb8@' ey~+m:.;Wjr5G-3yʊ8##`  Aqmzr5 ^SF!/G LźLդюyĈKr5j^!q<&zŊg 0O<Al! @Fۈ8<+'lqci^͌n ,&°yqW n WbiAByK-A^y؄o<+XPE'; hF^'`"aBD}y'篐蕾.&@y f񼵷,(A^(G9+cyBg O6aKͳZ< H93@8Nj0#O61m]3! f'gBlt.@?O Cm6͂o+nWLټyabsp#țmޖ^YlQAޒRp+L$s=γ~!6)3)y/6L ByAV@lA9QA؜mޠjAldL ')^Ml6m&8m5Vq^\l6l+gbSXe̳KzB#o6y yvF^U2j6o@^>y]so;Qy݇Zh& / lUZX?Aɰ֭ uo 8h ``9@%|VL`! X?WVga0 ~J hv3 u sz,\KY 25ֻZ‚A\">7aP$v8;s-e$1hgִ]">K3 QW+'Z/o:Fx|EhdZhƲ X0:~Lh -1%eQs=dу\ @CƦ1r-tc;y47OG#?Ŕp(_Ԭ-ESOFh,|_gtD@p\ELE_ )擵ĿܣgU/h̫/_,t('?N O!]֯uA:_gMϧ{>zL:Xico}|~8I^.G*.O$n.իPKZF/g8 {Ջ} ;A1ퟏgSUhPT'iQ^2zFѢzgSРөퟟ\ڒ>ǻ.XDKBj)JQR鵜"hy~3ZjU/U-G^\zVTZz>zg?&JTSzHg#^-m9iIIעGXhJKr-Pz)Kv34 2ߒ#BP1ڔYv-L Kv/ $Av,`GX BQL|κ9ǰf W ʺ`dzXY$l'8 es':ݳGade /Ԭ=*˒UYY_8{6=d%sqf;Ut#gb 9;5DsH#rS]ٱ8X!24X^J s,e}/,~l~tԏ*&%qTn~_?J\2i2-K(9& qk^C˩^[U'4>Nէ7\- Liexk^T/iQNhP}>hP}>h4Ҝ?X7?~iZ8JIp$~`!2TatdtRuII%K')KF'UN*wEɌQjd۫{~AZ˿ڈXe'^cᗭz_BRKlFuk]\})^'zs/ wQ.ݓ;O-)M]jGV,C eSvDş90pEHC\RZQe%O `JmRJB ('.A%%Г?6 <^wiy~olQAZPW{NF576ZXC ϥn{cw=uxIbs:ޤM˯uֆǠB={C蜏o3ekhM%o|=\6 |2EzKtDh߉|[8C79йL.m?2H;S־EҒ=.*>ƇK|O\hw% a-w wwaٖwx(pQ@Ըb2.u"c;;;rw;w=pgܥ.ğ.ww*wy](|Ϻ  FwT&pD}N/C];w/T]Lp[pgzuǝ'p:2p簶;4-(cqi܀l{‚;p wk=]Y- HsU#ëwYlpg;?pg3[m/ʸ#9%܅^!Хpfa&~Pb+s: :[%CxNԶS| "/CpuQewl;;715pǯsw;d;ܹ0븳(\w.˴7kxhZ \3xgK8# 3]Q<hy-3 w^x' ppx ьf~RI9yu4];@G l2xPE,fNցx UxH ,KFaabS1xp+r?'"<|EUE 3@ N&/ 5gmlU ` wjG3d('AAwB#[ ^Xp'w!p׫2.l]bwTw,K`f\pWp׫wE'Vp%#/­Gp4{p0M<]Z<7w0ꂻ;[s*:ɫi5'FOxpw܅&6^pWV܅^ [p9A&x8IX_.%wP2PQpO { DͲx 9ő~w18OwexQq'D;qwoP!/) Bxf /+ ҂;x] +0QpWB&{$q4eXq4QNG:;n%VPGߧL3yԳ lbǝGKl"́;B;WB`L/!Vl+{gf{g ?‰±ι5Ц(KwAp#*nw~3J~z ٲ?~wv B 9҂;BA;wN)wtd N|u,&k&74 50"zf;5H7 Y |N`1":ފYCkZ=u&K6v,F+9EYEnXw`1Jl,FCF3Xx |Ibt 8Sٰ#X̒$X ,,#pB:.3"X^̆ŜY X,N,=kXdEibW0SV?YTK*>*Q?*5͟jŸx܁I5,~eoIb3~? ?n|;%2aTx]{sG{Z/7|&N$T8f+H#ȩ Ңz)F{zBft-S/ioVgKy >ky G`R;Lz|:)rd[tLzOzKk!CBŒrgNعWR K䘚j;=-@V X%uO%%uG;dltի 脆GdL: 26zI2ܰO`RR^%z |}s{C \vr G1p>ujBOEzX}[Zj7gW:LEcB>QNԡ}Npҽ<'NWI''DMO@]_R2Ѹ󁂪_ a$14[\pWrlw)mF:H86CQّlT%#zlnV!{7p(GT~yeGp6E6-ChLIEIbD_܉qxhjwG{I,m5L ,v9du؉2Y /!HeHZb+>o|@t{)~9ȱP>`39/D"i!IZT9:aq_֧HSFş:QO7"k4(6 7:I՟ntB胧>ҠF'iQӍNh4m;~mk@r-1kbG;[陵H |dq"ib"M`"mQB>Y;fΡ{AI9s% J[ouG+~ՏϹmG>n83mj}%7'l,Y Y=;ߎ3vdjlq>:wxb74G# &bz&h꙽N%&3&B^ ^~r(#Q‹6YHqn]@tH2F*ro nKvsȽɸtvv4 TR[S坮;!=Z˺Pm>]@tS\S%U^Ae 35ް|8 'V25ti`O2D|S[EtGlp[BB>/BZp-1]}95X/% e¦(? /9\>;p殥 6k kzOD*3Fd[HD~wW_b%vKW6_Ii-)hPEO'ZМlB a8%/b?K|]ן;ӛk,^$kw7*ݓrgNJ$U$I쵎 [Iv~,`pJj?w|4˝?щTSf믆8ⱞ h#t}8^ٟ`өB2b3=Bu[#_xRMZ-grv@O׷w]~(ᄑe/^PȀ˃.˻4<˻߷[Ec.?PwCAz\ʼm0La&d|ymMZyyMSt6|G(.3ØwwF|֭5Un[燷T6;{y5E=_M0?ߥ/:|~!VJ٤\Ap;c>_JYhC<|=RuoYhmBeZ:~!c&F}cOH5?k?1Nlk KT?Z~a6z t}UwU r8udxw]|;)O7q&XPr,ق'kNM**j_{2}J2rUj2O%ӸiM#J8ԘZRy0TIcJе};CSCG$pdmW5hs2z>wߌ'}7zWye1z[x [ -J 9p[~A B{VrQ&OMZ=toG4FPUfS_Z66V_3 M(4w4]>ώ2qӪڪb ^Q"-m;ml$_5tGO`!"-*oGr~jhZa0>O]*4l$mwO{'r,S#UQvgnK6՘ޤtˮRi6NWULP1!_iDU]_B]#oFUWJ#xs%I->rJ7anXe~xjQ̚ŀWbĔ=2\k,;J~߇%ej),8bPj<~|\_.nlHjw5brzF>Hw%DdmLeq*xm=3({ ʄ~[x`vhnoHsdk>^yvmq26xocSaj4''yt%x't?6!rA'TZdO&av'ߌ?m~|5~~=~>n!ӄ]~yBg~ҽ.5J}hoe>wO Z}'p$|%سj*?BPt';Zr?yo[<#p^ s=ڡ:bfކiYRHL-ݸbq,n70fgLO͇( Myz: ͣNٙMW}M(xv&sVe&,ZM|40}ЋoEќAfǦՓDž?=5v16W#QgؘEO}BO׼?ueE_)O϶#a_<\FIyq(|6syƲ]JnG< &qR? &ΰ78[:zd\!nbxA HU/uϤ[.:jJ&)e~̜ke8O5zW&RU+n޿Lu-"_6mrKVH˻+u-,`ϯX 9/1.A7;} t"C&ab|痏8ok[vʐWOtu an_bK7)\Oj?h2Gf)"HڡPmW;Bw$SZ9_58LdCyUIb@@͙YZE*bSִt!רv|+}یҔN>DۮAݛS8ϩ |Fz֖ SW9=1~LcxL5=kEI+xWz4#afc#lhU'Yhee"2B!MG⚓u*e[$?uK5 9EVĉfWK|6G6fĦO}2қOrjAUB$t~3Th<^ʖ~)C',<ht?Q2'ڶ 2];Z=d>W;/u'9ʻrKuz//k,IZ}&{Pѯ[WWL4e41̟#ў"ݛmZ?7cFa1j, gE|ͱ /HE{>;2.i_Q1_WK?܎5Ͱ˩tg߹; S%b ,JL.q_7haKPds]1&Tй9Q]dTUUr4"UM`WB!mVP9hkQU@z5rZ @~Mt9C{\vk9SZb#OCiwJ^jOigNi=QLgGn.= Z ( ߍeVuB>.U'iu}ǘUa><r51wuQ]qk$+jo>51z|5@?quMw|ka[oN\<FZ#DUQeRq]OQ{ f=@a!z$&aYǚaFdO ӵx4g~- 3+@jvI~CՐ5-_ oMVa)s^]<{F4~&hz%*1ʛv5VO<+ w⦜t|z.I%WnSrEEtG_mC+Ob)3=IJr]-i2_h>M2~-ۖN_5+Y nH嫓Y> 2ʫub$b%SK _IuU% h k'JSsMN eW.JyMi19eb"5Qkx\Wc{uSeO?_wB%ehY#J^daq*_;h 7oa.riCkL|-DNJ{fЪYZTW,#K@~OG-<%˯oےrPY'9g&cN)mh뮊O߽mal[A>JIH}[i~;]d-4쐢aGN.f3c٧љ Pcij2\=Pj< LOg7K=׮21s+sA }5+Ϥ1})G'.GUl)Յk]:-ntqU8)*|8a\=`q_4Вco5^:a#NԪ*ܸ/bӉŭMumy tM8- hV GxNw70xϹen<YZXGbo=rb7[~fb ͬOG&v&aߖʒ> YHw'Hxx3]h 2CsoᅏS k .1-5f=2>[Z ȭd ɤe{_7A|u3+I TϬ}zZ˳梏7^ KdUTu2G: vncnwȶ DS!)uO 0ffԳy+m@4H 湘j{] 6]wUaD>D+2bx lJ+?bS>n"9HySCߐ;::-cL:P^?Nae|9>_u WޥQ+煮X?:"7ww3wp yO 0!nRݰKSQ!aNcp6zEO> stream x]Iu>EN;E>IE!ɖʇ60 (oɪ|VbuV./%s~ة)?ٙ]]p]ɫoA!w_zg=dwC~w`v:L iyTKZsO_O3lls>LoUF7=_xCu9h&Yv3U9HmJXMQ0Gy:ޞ 8˸8]gL!tN{+K #=?W.t~v"wh?d{um7nX;޼cC·` 7LS^V!op]9˝,.zh ڛ=lӰmV*FwZ%De N9haӷb*_9똰n.klw8̷u ] ta]&Kl`ɫ_R B[x 6f>&iDW*ثK> ݠ1]?=1JLg[5LMGzfe_*n4`9M ρG\6.Q\ 9/ƍu ~H[aS :pqRȯQk#(k5# uku#,l*30O7TCn \#G;нDLI 6"O ~:saÅkUnbᬙJj^x#Q.97 qּ_u?>,g ǍP +D+Ӵy# >x7]r0ƈ^h5T猙 9Tr2L4hJI1rڏA),C~YìU5, f!N7.[ J ,܎᭜ڭ2/}|(k$7GT`&NqQbmey/Hvx{٨,"ER2 I/, Eu4ډV9"IJе!Gʺ!oDp rl^`p>$ZåQf&V :g%Q!EQVZbsg@րzou Ig .~3xJtӱ[ZXxLǃ.BL騪eSe|iVTr1SD$sStqQFF˿B5skEڂJZ0PnE$uҴgirMZ܆Vx,,òI) 5tm捰+kl~Y@i<[: AYv]&^5fռ'gL^P;WP};qֈ P1d40Qa_#Ǽ~WZqv[><8wo3[`opi]-S[ QǾ DT7)q!BQ?Ciq ?P/]NR ǍP#B^bh.5P:5p?00H^'n2[Pi{~<TՑBp놷rp7snV$u̩c w|">9ф6u=J+ݶ]ֶAb

T. ]& \bm8@ 5 /5'/xGTK U=(cFJxڡuQ٦ԘG`9**=+ᒪx]_c}|]Ͱ>.aY7'] 06v./68b- hfyoi}>U},bcDhmxi{QيJJbUO7/ig1N-lѯmH#H".9q,ʹ$y @% M1}ǠьzV\t\/M9)TB`o#HŠCH$S>^YiAe9%Om1,ey-ՌLȼA?A]"tJ~W;dʇEou.AZ 7*zaX@W"^ dh5!g \X&O$ h`D7xC}ouy!N#ݼY yAtg# f#xEP,ˡ͜@TU7 02+?qz bˢ\l*96B&s)ʗ6ml?֩X ,tI&E)~I7jKR6;Vn"VՍ l!Vgu ㌵(Ijiqd3WrnsgCw,5[ƻڏC9Oy[EI}k=-52=);V\7pZ䢉.1kri OؓM 7 4b#U7ƤtȢ$\EaC*`3nl6հ2%Y/_Tt#BŴyOKESYY3Par,Xܸt5zt=ھV>#Ӧ &Z[`Jda+É.=5G"'th 鼳2H8?,JSQH48X25C̮yWg)bC[X (WG)ERa.к)lGp|7vB׵u` S%MDb&keoii^Ž]"o%ڰ յ>slg:jd!_t4)+1fN{iK4ƚ(:Ʃ$&X⪿l~xo c.17?vO5[%OM񮊋G?#ԇy.Aasc[T̐&z<Gx%=JEM»Im\s |Co7n,6Qu֩)6R8-e܉b'>̪SQ4K-c%Ur8ZlV.Mvm쨌LY9Ffg<B8q}8^HrAnsá̎Trkr!Sٗ˲֫9W7"Lll4mR]Xh5δm\e ۙ%5,nEU.W#—>\~Wz̀7i-K!;Yv|"I:(w-H,k#/<5X4*jDH-K|S"^38{Q+}Vympla [EB\:Xf3 +x'V!\o"Wq>"<N8ys<~e8HMWeck Y%c6\LdN. ۶dC]P :ì %Gn.[*~qs<8Gg:|y WaS" d{:d[O;A.$I'x&(g4qv}<K0 Uq8 hܳ( nk7@ǹQ76-O1S2/g_n ^]kircU È w$ehqݱ#"Wmhx6T۶~57"WmEjdSW.b;tXwË6Vx;m`y|I4{ܻd5֑_g^r*'H HS85u&_mxHT]t-9 5Id /_%VFs-9n4<< kAChepo6)!\:8% CP-8huI:-c `Du,!q7aP9mY"<gJU֣0s%&+-c :a]a,aeɯ^R'XdEi&92V#ý0#m%L%ehe%ƩJ@8'ڜNye`|u@ Ax:;v1d0Sd*>Upq2*uYB P]>o[B{.a9QJ$hx4cZ+F Cϡ0a (kk%pk]endstream endobj 264 0 obj 7319 endobj 272 0 obj <> stream x\YsqvzV݇޸Z!^Da),@p<R(fuy|eV6کQ)_Kgv ;^t_w돻op'cVY~W.]q>^ S^zsjvR1OT`~6EpsR>heC0# 0E}zO}ve6Ur oyp2# Ŵ->9hh9`s ޫO?i`9Y`mGlKJ$eFOeA#60P ZqS7N sI) VLA [n:i^9s/~suO;5[U*ɂMY+x)c6l4Mvv>0<;5C8 [=E JQ(;DKHW GRUt4IĨܑ+RYxAa`0Iy؛&Jpd2-BJo-q<.! gqZ/5>͚/ARN>hW<ݥ*JZ8w^c6Ĉ`BzLpêK޴#@C0;g| 1>hȖ&o^phC,%tzxd%{J}2Jwp=t TH_<77duQp&YX88w^З#@?h.%^5 .ms:g9u fFھU@G%v`XH&Ox &X0䵃h pUxUӏl!=q霃TxV"Y^אc4)&o_`GDo1U$ EpM~8=:7{cKG _Gv(JLX8X oq$)uST b/Ϧ|NB1"v"cNLg\!PO/.Mþ~+̉ӤDYQ$p-f2~9`B,BbP l sY5H #Fc~Nz+XM%\ 4N<4DÍ nBAؗi,w3P)lnapr$e?Z.&< *|/y idmĩ0)gC%|ڹtt`X(`Wo\K K/US1f`S4gvїy ֺ{ΞMEӧKlTKBe!MEsw $8{͹{L!XGt3= f +r0$@dqz[0F<!w n'on@ʑO9yʻu,`A-˱ |?#,87 M34d~'S߉h.XO_(jk4hN(9s%N>6+:H/}SWL')9*1 ?4<~ od8ð\ 3)ڂ\[S:i޴zិJ2Gufe+.=e٧Lݎ#়AWY2l(H̭d Zo0&,N(~|h9["ҬHɱH(bwgrLٙ K#<P|ɺiq2Ɨ8~j{|pߠRH ,$@lTkL#kPiqDF(> " *p-?5  ZY74!%n{P+x! ;PT0TN-Bh3!s [1Ȼd%n7Vctx ?_ /8rcY哸b9v[?E7ERvJO.Jk, %ם6b 8(9Cؤge驄?K`H==n%*J}LI8^aǽir҈' U4-Gr #]'yf r\gus*<3YU[vpgn%{!^ thZen4{p^vG]rMxu uU Rg7z,{ (NŋGAV-޼==v&uoj#^Ԗi=qx'{5 yQTyq< NPE x@yRRЬf&c΢,@Cʎlz,XAg$c3lS} (@54 Ƚ">e9P0h;Fҵx)ߤ* CD qu7P)NKnRJDQZAEhp"*ZFQU S'  +e G^ QwE`3䶕YeәL ][I$͑e0FPy96+ް@E6^D.St}\-,wf?`RGd矹jtΡ'".z2P Xۦ1NL˓kV}0-E4N?c>MClbU?X#f#l%Ѷ6$ #bݑdj YWJTA޶VuBݏ]o ;O$ f̢A:1Y-K4>Tgrkui`jq~AL~,u|pINw,:ݰ?dp`*tWsQZGL0Ŷ{kOָʼ*,*a)w KRD?z%InI]uӱ@|Dz5/P.o.Pe5hV ;e nQ\A| q *,"׫BRJ)q@zK%Rli^ 0S^ n# =51vpX0Of%_dgi42wN_9ױgWtJotyb2 6ŢVhڇ@sΦ#$..<66]xZD0)_3d309b>İxn- sq㮳Ky"N5*Kiv+aJ)ibT,#o> (k|&|ɫ+̾uu {YҦٲN4<%.$ݫYzL1+sXnĸhã)¢2, :MEE>v7&f ?2##/\KFfK8ig묭[6qA`αW}pjIή򹜝ZNten0[ѩ"6*F +FŷdDS4*𱂞SVm8N\; QyGT:#T:U1Z"]\I])OD %JՊ>9Lw"6˦8)SxǛ|6΍VDX4ۚ O-qM3Ao\? `aCDG!ص>S5Ƌ}fNѷrh,ϟ}G ڥҠصu LEp`ҽW3\EyJ;=iY#OF(^p F0ީLVA |־nU=тԆx%6ޔ:oۗ1ۗ5c?g+Moj Uc>.˜SuRTХUV K0J ]fxy…#o)YPO^e/&O]c5J`e!܇}zWc@ZF]Ğ2uk“o[_WւF> stream x]K$q6|>=]ADeR+@0](vH?""U VFeF;>-sZ??f9?/r)K1Ps]/ҥpz|zbM<?b>?|s{\Ҳ|?q9{K8p> xFڒ/K>9p7zz;l@X).1Dl/7/N}zuCLpx쯴3sɍۓ~K<-I~r {~tC7O'n-=~{~o?>b!)9YC4u1Ib:~ b5]V**9B2ҋ-Iu%_6Dm19;V^#wr-?a-%(khDɴGzMS8%ЋD&E*JMH4>ĐZ4)$Bt)qz8t3$V˜u2rqq`8j `2T8r{G&⒍9?f沍e4O2M]ߘ,VAKwX>=nV7Qve~6̚l#暅"C}ŻKK#֮;KXA:GϺgRHCRi4H 3q ֜/P(tG2]*baBQRc'm3 KHo// fr堥'>pAALrd L4ɔfDFM"*7`Gm[7Eo"բTJhUB># C.dǾ dGjyyYX;H3żm9$&jܰu;gI-g7=Gc?dvHb IF MɾIۤԴ?hrCv1vp7ScǷmCql>ſegFF? +5Yl2x8=y)+ERiLwॱHÉ$~v|Y$Fdm,{HZ铳}k68/5 GSp"Ja_܅R RJMKq._l~(mPmkGer39(e* a1 J3gHLHN.ˌY;Bd`\!:J(YYp"%x g#JJD[(9QE3GtPJYKaxy-4E*mP*mxR,Ŧ뀐*(B48"JLt, RC:0Sq(a`խ"'LDfJ0qE4Ke,ǜ9A&?T,H JUoE*Jq(ka#0+Q>6!s3DGɜ oE`;AɆƀ~Y%FHS"p+Blƴh{@*iVrvAQh);7SRхT(Y$ %#VKA9DD`d@+ ;c7E\ {i\'޿",dm!(d8$H)!5"lR&:6Slygl!x(H:ѸE#Rinmp@֎hGg@6 ;f,Z8"J1ms"F"Pť/HvDi#B[ vĬF(kɷ8zm'~rˁ"" 86em?g˶rTȡ"ٞU/ ׋3DG %Ekd#̃=LS~r8dXa\q 9g9#2HσZt,3D -,5&ϚGWʓϕ,D"h%8t(4G3G[&l P2#:J(5/gP\n^$ ǑJfz[䶩뀤$E'TX%!cCZ> !CHQvXUXfj3DG %V4A1P)2Hu ߤ{@Hn 鯇73`kmY+`H뼌: 8dm@Nޕˏ < _ AB8ᏨGEZFRQ :JgTZaRE,i`2K"1*)N>9k9 :J(^0a6*:ٺ4E*m ӱv'ϑvpBÐ6ɥq||6A$,Jb4]pM=9zLV=Af";ֿvY#@NYjB-+p#70 5JTp6!YIQD]Pd NN1(3 \j˄*3;WfJ^_BIL>vLJk %E!Ff%^p5\ gT\@acXVu%vf DjՀZp8Ms][:E}sA}DZ1!?6m: sͲvD*m5Y.kkc4E*e50ߌ: +j5="br|\^\\ŏO:WS2"A5er1 B<>H(J (49 4NDCfL ) R9jOaǛ.U* я\Q@H4A*)rQV4|>"ygφ8Uup9:F ]tiH3+ӧ&JS w#*.Bx7C%{>|k2C>!:J(2g?B=6'9Gg2 pq2 ABV T늴= X$H%M&-qK\:F萧1Z(BG'7y(i*L|}!co> :J(!7g5#JV!(1QBbl9!8`fJI/]yIxL)Zt=Cns^.<Z/#x=,Pv x>&s@zs=4Yg,5rTD)آYFQE 3gogJD7ȊtcRv@Fbu\)iCNje>Jޟn gQoj#t.9/儆 ` ǡt3@ LIX=iIrTm%\X#S ↏rS'Zh;zfs!XGXe#b+i뀄(#Ri%1ө_j'>i5`3'ߦ];>a}dF:#%HklZfX7E*mP.%y2*]a zl=hg A"ȸ4JFCRI䜼Gr_~(i"`9}KV \~({ln0S4N\!:JI\hؗX/`fΎp5"lX\)b/Tp2GdGr@\n8 S*pG~, (vxa/D{I^x)h_e#5 !!R: h"t&mv3bFCf V9l T$f"}THiOV%,tQE:׎d(epq4\x*QtCI R)Ѹa*u8ptTKNl1: Y@>g$u$9%riِ 8"6(WQ~#/tO"5 Ct #zKÃG$)m(E#`5E#(m#GRG*% - 2*U I P$L፡)­jO>+hTЏ`gO#hEQ66%W^(s]KK]2ڙ$6~,1:($hmn iwг'O _,]O 9t*yv[|lH9)zZeN7jȥĐ1_x sys4{nȎx4ցӕL؆\οd>;Lm804D| X<|Zmƃai %~rY0qև:}]v"k<].;c;O$thKu& 9IVZ8e%m/dH[{P̻aZʍ-7FU}#dchzC/{C$7zқhH ߣծm xKJlk23ejgBlV m辉 /0[=Frcf+ۙeȶٶaƁ`IwyS4 I߹;\Or>dIڳP 'WM}eTc-\*ΘQ[?QusCO ~]8흁YC{?0x=42T4q<FeO(Bzsb_ Qb[zRI'XJa-/F=9F7An!e>xyγ^k-`6#C,erkqA|VV_o5óiC$5Zܰmh /'~xſ&fnx|:vM+dtKvnl YXV{`iժ_؈v[sѩbUQ}ūEQL2̋b7b-YOnJt7v&МR\%IIƲcD`y(c)K+u_ԠC tx>~Qú6x:9Kơec+BH:o??4=nr"G9ұaȰ z.csچk}|]ʡrkٛOG [6_Sa#^EkZbMpoPE2F "K;|oZ]_yAgVpglӡ4*UO4nmj.8n4ү`qK'Oɰu/w2NqS7Nw,(aE&@W{&l _wFw ^9~ ,"xgu ۟@sn B]Q/]}%d'H*RXeMJp7?RN$|=]&V_h6q&G ?] ~ x ֥nż(_&"?2~K~'xqp'[m/ɣNE8oî'qڕjk:2F#j%F&k$ t+]OvU`S25^H]w Qϓ+a Gyy72Bʻn yb=ۢ^?|endstream endobj 284 0 obj 8600 endobj 292 0 obj <> stream xk%q%c[@$% l<]][H~bEDs문R T7νXO]~JVWUO?5Vtyn~w_ٟ槕fvOso~ⵯWWk-WIZnx6{O4QS};g]3;<+X?y+oE[^q>ޞmis-?? >=gџK6Χly::^2ߵTiͲRnt"_??kn~/rhfS}erH&Ur~u\tUd7WFc eOȥ<}U}7A %租+#_vy7F]<]չn-'EC>e"r]2wuZ][O.f].:`}?J.OL[/-My8JnOyJ{HWe?\^_~ ,2kur]kz?}n]W뚹~eͿrZrYB)E^7nh]nʛ[yO?HnL7ۻ* «Mv?3w5<Ly, X2(dJ_teJF34{ݚ4{ ޭ!4{]fEw'\E.+[pݚ. ״! O_|Euv|H XKOn5W+~&N~lf#E im` y/E,PE, z:SwM/Nxھ/l2틸Z೺D݈.ϮMen[m kd7b+58%Xz÷ޖnNbԃ-5C&qCvgD|)~^$^HRE8%{Em\ZKÞb~z=OQQ~p4<sc9y fFQFr~H_>Mɑ7f:"wmՠȣ)*bSӣ|59n]$ED*#Z\n OCFOY{$.Wٔw8M1HS$`txPd}TqGK\4G59=>F(lzibq%-/+Qa#W…4]+/_5[}YBH{SkHl4\{6[KӖҜ2vBB51Nі.,ɄF:eSրnŀREt+֤DڿnZ%[m z%Mt+[TV)Pu7k/P=EJꭊP7΋*gXZ@h{D7CџsϬ)Ԡ Z8wolQjBvnu A%ͯ^Dt&/(mQڣU_d=޳Hs|]Q+l+=!b{tP=67l~b@KVł $hŕPbtù [9s Q6+XY贲7~J˺Q7Lq!0"%ЩG 5 ~vhwZP6DAq_ǐ'T\1Q/|+ScMEwj/JH uui .L/@QNhhMJmc0 # Cg: GYOEOd6gC,\lzs@my mqT2&QDn9/"|B7vCX`t 0zR bLzC uVjhbczIr!-A$X0*Svo棻ӌ qF,gю孠5,@{?6fydxmKگ`9cma5(Gf`#`Hj ժ =kn ] " [ДŻsfK18i=抦;r LD1n'Ho\=p|Vs݌uT!g0{QĹ1MQ!, ]>8J٢5h `6nag*MzT[A -&qUӢHvm=cv۽D ]oG޵FЏY,#v#3|hm!ϲ⤞64",MuÿT_AF)櫵޾BHaa^hۙ~ڱעHEgrz-JUe6ۊ΁ K `%QZ/S)6jswj|tH+Rgqx$?T\I^lQz?.VZyDL)(/}4l?8j#9\-8"q><4-0QkQ5v^c˚Q;lڗ ~@hJgA6 b!=Rv%URO05WZu_QwaY4>gЭ3QR|j٭`QVc8T+UY(;|] Vh cj~,9Bp9 M1fKcf(!MNs6~>/[>'_!0讛'FAFɎq51 1.׮ݢ3PU˴-)H 6 P&誯.hJP X2%uzO1p/iAnXzG"M*at3³[c{6kVW~jvym1ŠBYpDwF׻ g'Ce^Vd%[OƑ ?yy[rIT.Ioަj|hE]p:y]*%#?~0$67._ν?4F(n_lE>8?|)a+5}:Q{n(~v%O~MA=LhIw|7N{==s5<]-O.% ˯'U۪ٝuU-Zn'U[%mJڻUǓ tNa.pޥNS5s[S? DS9(Z~q rr ss蔒:*Jw()߭|+B]]f88wmֶ fP\0ә-[-AVKiS_%-+ E)q̵,+~X<C cA6 C鶳GY@ᐨحu~Lkb-QʹTɭ9$Dv,Ee[/e-3ٕ k QFmH#{4JJka׆/^*֜Cc@@d᳭aI3V4J7}evJ:>`C^dyqfTܻl8T{!-w5P1TT(OTncQ>e:D`ӯ+ߣtBPmkCv ab)Un8|[jjcmlo1;)%aZY):GƏI;wfqH78k>; ,S)QR! WMWGVi9hLP+cQڦd.`lfqlh\8jow:9 q(]|_ {T9)JluCcJiJhd[Of\*=8n v7#F| ϶h~^fZSqܛ7P ipKNFNX1`)@#<fMap jCxRuj٦tQnaa `*gtx%͢<׏`\m~axm~k.DOrYW)4KG%9"[)/QQQ'x[9#2u{ʙwh].gh6]mϜY"8wUۄ|qt0Y2L>@Q@ |/ 0hm0B;["Ύ+m0N{]Q eߣxz##`}QxD`;9a F@bt*O Hݡ3o.(mq{)-G70ג'k)œ;9Roem1}H}B͆Wz-l=fܘC*@6@8b%#wf+6lW3٨˧ȆMA^9]8bmqՀ&e AW8CJX}bɖ <,(* kjQM,Đ},,%+bUJ܃KA74>icԚO;xҪ5$ zזgύ3! w<pJ^|OPZ6U=U>7ro]2 ݔGʦƯ,P]b՛(b׮JvPGP5,] c\S^25G 6%)EZ2R#yVL n*.'hu=(R"QZߨ?Oj 0g?FX]Tl MۑE],Â_7op8z_1.}p_q[ ؟9}t̠Ĺ!r#<Ta[.-8y;3ғe H09"#) vZ ϔߩTn~VтJUZO\̈́ lP0F RВ`&DE,mqwPLZA&s(Oy#QF' dh8^"^M o@o"[mA^ GRF!\dCdޝ8`6߽G.sn! 09*5 ŸZcI_fC=(yHαeGfFu $ô`feהcWEAw&6 _SdӁd[ Ì*%,Xv4[;p i#-+B)/ srPbEȢs@0?mcHTȯ6h uۢc13F$r@b IzqŠ,,{Gɻ#\Ӓ #[{`fi " k;(|RPʪ^h)#Ug$s̨go3"K|S hUf %%4$*jZ7UhV *h돍^{E\E8~_%༠ mw ^a6t8}xi>h\=9V@r0r| VCf`JQ7>~H'L_u ɡ ڢas_*نD%>BZ ^!N IFRmu{T0 I5^pE9m/,A,[}S547 2@N{SN+R9\ik~ pA0Ya"9"|"UjjiqKm\%'>o$#C~о9Jb)h͎CcDXl=l>>)-C@rq܃ND QC|L㰒(V3ckvʛJZEyk-3J] OwEtkb–Y1ijdsP0~65}ا8اhh=ic?@?v|L5rtJ{O7T g?&7f%0; [0#騍n *xT,On꛵1&keļDYB'ӣ+ ""E#C>}D[jP0g"٪n&ƴ`7.%i-=f >j8{`Reo¹\P$OlNM>sL^]g0&/զ6~C+@,ŧ5Gj29!zhEZw% q*M\ƌL55;p+J8M#|UɻL@4yc2Hh!HbXO,sWh |a]*PJAE^ځ_(!Ė|ƨ nH•]%-}nO{cw,LmS=߆G9r2DaH;wͦfFk!p`SΠ"K)m+}tm9U_<ܔ[_' ΫkTW)9 HaysN,'X#*D*51TeAB3"=k8_(Z3@)׮Gisٲ8K%h9N8 J!O ZZ^Դ6|ene^_9Vz qE5k !o.bzɁ LlIQ{h,^Rbpش6vQ缨P_`BA/+fvH8#Y1 Jv YG jbdw^^3eE+LVOhs`Z eO^UKۯ¨ɯ!WyaVlׅ82waUݔ@͑Ml+;z9uNq<,_,m~U] >h lsDo<#u$h>A ek7я!_ܰ2xt}8 k f#:խ?TZ"lFIi+7QX|6ޮDHX7Z`׵]+J9 |Pm{,=DkЫA5bΚಁS083 k]:%Dbev ͠l9 %z{278rsy0s=[yh7u-.^ rX}}d1 CSP##2>fF1 >5 eo8bMnya|7Ь᫏P,(}rPPkoytoH\k +ۢ"+%dU,|GAcQo[GEfȟ;1dna(oȜ60WlҢ_+%&{kd`ꁽiAyB`􇃖}h!QSj ̔۟7Bd,{uS:>C245FyѲ4)(ֽD~E3ryfE;Ţƻ_#.DTJD!,swW_!>O~zP;j~< bdfReWGZMO\G/v#8c!<̞E ",tm9z{FS~~+--Si3'1M<𴏮ZIu^ niG/rrzj/5O@/5 ć_k}Z0qrr0␻3\{ Fn n !hJE]iȶ"]3-EжF--:RZZ0M1j|#ҵ-ݻ8X㛷RU>-E">?0K}ڱ 'uE,=Xee/,Ed]1KOyS_1,{ nj송Hfi~m?ٹH.kJ*eUG=~$RahQ1n),u▞([ ['p p $-/PJOJeJeJeJeJmB(!ܻ5p½a{kxϝn"amWԌDJFv1oZs(.wGM+}Aut4M#F?kY{[0sTYqEr-`2O2sA*EhYCdhA_^Y9'> AҊG @XaKAOefP3=Mu_k(NhN׾3Eb!Qir}L>ϻBWPZ}!P&ɓD̐/=k^xb" *HےؼN;ROtyY{ZM i1DoCTO[f_Ϩr cm)d+|bIa ystLDb봭dpq>a{\AU<1dyHrY3lQΕ*SuuӴ;(34WR>]QS1j]^R1} z=vAzn zU_͈4sLaAf'd"j翹=Tz)[g 30QBK7LGWꑰŮ-yz$[oyQ@Y&Q"򪝖Ԋt5 J q\m@+܎@'t5Hf6`@3⨣THl #7 QDЬsx_2|gd(í&#F˔2O(J!>% 3-bSp%k )hGu rP y$a/3ڿ;D~F "I-=+=ۇPVnh)r@8uX펖˱z+ZvV M/&m3r2<.v_GaȲًr(mgc%\ -$1`vpoZ*DQE^dVAOK6U׬m,S"m$5Wliڜ),lTw܎4Z:x1 Ӧ 6@+U{ 1oܜC~HL cݻbG.n4`([P :pT66:iu] `> ”i7LÃdKAZ)`)ʴLK}8L[UL64K*zm5 #/!2gtG1}|6ae<#" @h\6qhJ;f/Ar9\G4 VAv,KBX4X8ހRt ,?Co"k /-{w@2׺aηoom|m -jCq+0[rDTPnDo ,I3Zrjjaf@i(J˙/2j5 ك+bR ]>ᰲiRVTQlD/zH>S݀ 0Л0;`JO* M+@Ѷ='ɣĿ:E9%Ly'}-pz)$:od{.CV[Pxh./\ I"=4-1s Ez/] Q`o=qeFUֱyb;7K85]B7.G+QQ'fK6f``X8._IgVswv^Ghi D m5T~@h&N|Ym?g& ʳ[f I`ebJ!˻F&=z! h]3}tJ TxKr;>U82ϛOW7= 絺R |O2fS?ʺY3P2Ԗ}'-HJ{zN'*tSJ-γ@ʒ10Te".ґ6c Y;󀌢eT Ov\@ZF ~Ld񀦓 50ӁZPa%xёiaB&<\.Қ!!0 0N2Wa t/xjF8L!Q!Aږ#6p``H٬sGs#} h6Ov.V. \9+E5OG I[Lcɪ!*퉖)uz7&jvvZ Rw@X3<`2Osd1#}mjL~Jl@ ѴB /4(!MS  #6Ui됦8@G\{&EV=@4UFG4=` Xe exL+R{ g?wpl& Xxr m+UǓm vxr]B[uᙖTOːJh!0+R˖!bciCʁ@iPip;|?(H_xŶ9NCIen:N*HK9D;<:F o6EBZD X [JTI֙Z \iQ3UEMʛRDI5ڰW{ '5DW~C`(# K5eXG[E4DjxrY7~~W˥C) 0QCG]ڴssȨ6sT/hǯ}pÒC`CJcGH6lӱT%3 8Ao&afVExP1ϙ蕋aS#5 Z`ɡf*[7DU 7 E¥f|GPԐ4wC} 萦s` &-cK0iGJh9&iNloZ8ـlӉE.2g7@$ wOWk ܭ+ pa h^ =>|Zo@Y+x ÌeُAZa@eIG]"-R SG4<$́5 iЦ:Y#'I-gt5K3Ȝs02jȦ42yUiGmvNg!Mkdh^gd8+՜~',jϧԦ7 =`ar0Yd( {׊I>!!lÁ O oAi7viﶵP~)ig #oA]b~6e=71hR; oKA$cY)Ww'>A%Yst=";42'PGԔZچ{V`&fX~ w:4/q7dyF>6zޒ8a[WN2nxf={V΀O8USsDCrDzo )ݕ,X>,E4ljD-ՁmAX-ՙ 倛 yd&5:m.#HyMI#iQW84 CVohoJmUb*GE,쩺4٫9Etc76b V0~l84/yTKlv;<P̙Ah#MَR _nʅ!WB斒 xѰLSZmmv\Z>&DY++:,D: Pm[^N>HKIG V,zJAdK$498rϱi@ s~T@(y9 qN6qEŮ,^ǨLބ۔u,ZLk:G`#&oi8@.1KUCᖁjlGv#FgpNJ<-UWu_k9`|tp0[нFVvo KÏa-4K6}6m"9qCaNX٠>fXN #X¢밨4qnKogyҦxڱ|191FQ1kg)=RQlJYy.r@цI!>WyfHiґJY]z<Њ=e\"Q@tGQP+nbOuCgJQ"qL0iړB[q S?k'g18ղ2ڽY9r6+FJ@[*kv١XGP$5ZI!XT ^ 2;bQ+HZ9@vWB7;^6 _cWxm(5IbɨA@+6vP*Ogʋ&b=jF9]Vy8Zd-< 4 ~3Q|f ?K.9)O#k} &rXkRUeV0I/j0{q?0Q6R,Afx +8k`/o,2emf\v1ԄbA^p(Aڵm֎IÏa]q+ F8/c4<ZAPA[o!a{`f! ,q"=ԌښÙrWsl&l#̑8ssZCۊ -۪1IAk-VT]G@635p A( (46ٺ7((4RA J z&65Uba䌞Q]k5HQw#.vIs7[Q5oZh_7W]ĎjR9AOQlmI}Z l^'PAd/8l[4w{ &;9 ![i雊uh xOiJIfj?![DRD[pFzm:Saۏ95ٿvȑamK9( ꞴA>$D2A~ 04h]KΥq4vGKAXZz*Tu0j9iin;hlm:vry9j& =ּ'CS A9X}F[Q~Vj~=Ʀ>x9:Uiyb㐣;@2 2ASԂ؞u"Ľ> 4FxЫ"9 #FRy|WbүsVk%4'05O1 a491~gݡ4ha5Uo T%hzi>:9:_ّe)V9)jaÜd$WӪ!.-_9`7-)jI4mO""TsoT"rCrZ 6LN#>:{p_ڇ"p_m?܏'F0}p_c[ ʃ DQi75ܘFonVFE[Q;nMr}& ȑ$-<[78x- m R'i(5:&uI{M!8O:^!c }- O ,2aK=hpΎ#NzP碝jTN["S`{U 97; Z8iuS%ک9l|Z`k/^s?vz^8N_W_w"'O/~q) ݸ(u+?X/lKJB+oؽ)/kZo޼r^Ǜ˺OeJbE珊[^k<W\T[CEo`RC~$KrJS=!zarn8#~^Nb>_w^d{}sk1?>,\S6MsEQ_Ͽ=||7oS:oPG W+o;i`?Bb>ĚͲۭpwz)&~=[Uȏ_%)Tiqo/8]oPR(N ߠ6|Fǔ4;_Q>g,A\\/$=|2+4u  Yin:vҜ绿ys;Z4kOZONhYh_| ?L|\Omb\|D|w":%mZT"˟3,0T;m<w[q/y.wSJ7erŏߛ p1xy\ @v¿޶܇U)ǎx/y^{)S?߱ER o -% |!}4&G#=paV!ƂآYvsz*ďrY2)|^&bE 5򫌶)&v38D FF|rgC Egaj/g .p'EzQc(BDoNeFr3}H^7J DE̿'ny`&]8}C-lCt&rgOP|\UW39q% %pE`?~!XKW>Br;}OUyŪ%BOU8G_b7;2u ыƖ]MM nG)wj$}QPw*`vcC?}eoO>O];U?>b_Nzc쩜so~3p#=Q]=WS u3(\7h6 sj41]H<kЬ0kDJ)o]_|C"?N%ls7^uX[y4S Zj;ZbP^yߤħv\ٞEyN滋^ncCB>o͒:R_(o^p BK?5h>ߟۦca.crv4!$6,g<,GSu&xxh.Oe tQ v O5__t9yB:yd>\/ayH~=G .{yehS;0Q욯@ڞ*:zñm9wG#]pw7>x5KZ  i]vS4H5 .D?/Z@P=즷PbWoǧ_"`Rݹӯx'.A\aZ1Y Յ:lBėy(΀O`HJVo˺  k"9#.>ܞ 5D>} M0>ܞ{#ᓻ=xr D.@#iPDg>c1~/OMM/4 @84_6p^dw<сH 25;՗췈v{\N*`Mv{>PH:[nxHik :>F || .?ܞ(A'ǻMìInO!qAª=9-oBx>Ǒ}=YV*u_pwUfc~+¹PS"S*&iV@([%lhz.Ǔ,%ѓTt!QX\.>!?&iod0b>xE\O7*S:W"FUz>BKO_a5nk>\e n\6{p>?п*hlo9Y(»f}xWU{$q|.z9b4q ~r&-{$JT G2+#%}[`6v=T&/8tUޗcJgyrP&~Kjқpyb]alv/کft]h[qX:|eB$՗jB5PGWl|Rb+6y7:3!? <|rZh=}ʗG87٣r?ܞlH*ǝ||'Ă( `>@F:[Y=yC'_Epbt}h2$N:J?k'HAxҢRt ?YD:Եv_p9aE"w.VLIsejk`$/|>Q`nTOx'ꊼQyA~=Y6;:|x|> j;k^ݘ+|A]e[XxbKҍ ?Oj/pŏ|RAudZnn6sݩ(*}VĢR?}p?0z/{]p<-x%\"&|e?-hh+ķvYrGUGU儲/FC}vS&(ۣuWGfX J-gH|\{ g鳶'E|0]m.G<i_SAxs@6 L^37˼D-XY|ŋD L]2{cz`{[$E+s?^se0C_SsMi6=0晗K{r8VU4kU?ou7_}=c_ʉ7S[+HM( |o?};woޢn;I2쁢ӷ`=G}!}eU@ȱK' myOn.k:#ޮkYF9 gU.g Bv㖓>MT%{ p+)fq} ɝKH+^RК"x۰dYaTߟL_"Q T(zJŭoH"Qz7^'̬{<\k,6**? hV_J}1>ba~V)x)<>y[~L^7S"RZ>I. uO/o_R=n"'zmFq oKh5Jڄz-~XMuGrNjg~a+,xh(b5tK'n5z} 34%oħ)rq/7f^݈QtXQݜx󪈫=pg]96ƊX~|awU KqŭR{t;k J+nFTn܆\9M\Ϗ/}zĚ7d3`0a˾|fn\"(7oR).z.V0.(\9 cJ) %權oot go-_e5iW}J<+h ;=雛9ȕMn0W=bޗ?6'މ}?^(oBqou_5F~m@u 4qO'^2;gjA{_~6c,zϢU>F{^aaE^SҶ_{wM`Vg*w/&'7^E_^w},;N A_֪&&ݒ/;GKKϵ^)] ] ZuZMk0ߦ_(ӏ;hVx4>JpW|z_)9᛿0X*Ѡ{+ly]^vV"~YXl*lForB0i˜?R񉢺rzst/׶~Bڹh wր~:0ޅ\ho/^o@ro/qYywQ򦓿EJk$?3螞">4 ]rDv,a]^hGc\'g7_OC"endstream endobj 293 0 obj 26318 endobj 318 0 obj <> stream x]IuC E8&|8ʵ2iKKB }h )` HBu%+ʞRBMuV.oR\Ls1Woス}2]\?扡^]Sx"esS6O_>៚ k!|1]xɗ_7q/bڝ/=q_:gq _}HɅ{dgK;B t9ϳ݉?vǻSN~gflN9np4w&cCh`E{zk a =eyA0ǧϟ̼Kť #rwz S0Vww3%o ~%ʻ}#grV@i2@O<i-> ;v6iVۤl&=;%/vg \6#Eϰ7<30{oYޚ^9͇47es1Ԋ Ʉ, K5G^~rj2SH޷݊'p)M!F'E As>OLc_}) %|XH:%{ĔG +ꖇ$SK82K50Y)>d=*V)yFo92]mR*6y6|xM$U_3: A"旂A=-Rs8 k/@m wE8Dz ƤTN+T$YX uAP:S|xdΙm<I8! { x3O0bc7E v|9 s/hKgR0K0;ݲ)vPϣ,wa!`Qg9s~?8-1q 8dwx;L9Ʉ+ Dy0|5 @Ϟ7giwZJMv'4RT`3l.[/{M]Jv [I:G8'|"E*W O9ߍۙp,gU-~!,΋eQMђ L NJ"9),QIr\Iܰz$=p UHqd:kIf˞OlNkWrBoǶ]y{R4wR,q0,YNmoP>ʝ15ySJ眇c7Sh%=hOLA!vALz -4K &J(G:I:)xh3pFՉ|,f#?0doiadm +n͞unސRG.$Id! r`6O]ʘk DlٯțSx{ټe5mV_ WMSk׷/$m[@SZ7ljfxycU8!zAK7nj j ,މ)|G Q) N<khw(e q k9W e<0.00!rށd(F~:OP'V+3Q9S}O0C| 8I~̻Ss=%0Y;W",EՓ8B #R2O,VU>ESIX0KVSU4UT)x,rU0)k~ m3dxDC[zj/-fiwD‘D]KiD qkߐ/!`Cm.×8 "5r;W U{e3'JDCw$Q_.RaoX`X$*0X :Q<ЄFP4AȣɽmqGHh#zum,[<daհ$b&iAaz+Ga}SNEGo#s`=]sիQ]m?[L4.歉bhjd]+uH=fcrIOJ<0[#/9 tH>78}Gusl!܍Rg?m[\PM?FMw^40r w˚~v|݄x2+1p=+8#&%%=ϣ›0{"H=FxM\ϥ>binZI̔"3m2 N^1=M88|~ 3+Wi@zv(A71w_DxNɍnY]aO{/#h \hZv vS\j|iHFa "`#:bc8/篕$yN tB`Oc&M(Lry3Ā;˔Ava2P%D,<\!k6U [pL`5Jf-6[Jgd@SU9=!J$4h Qwy :r"2.SNptx<͝ w]$v_!. }0!/yl,ԊmG%hȖ=) DS=CNK\ @%M8_0cWهTG2#qWt.[aNW)X<_>_v+[E%fcf0#jaRbw*Ix^~iқwc"~3/숰Y&mjYi ڐP< ׍Z1)N* ^e mG>- 211w؆yleNi@!LsLL '\ϵ]zN?zw|׏K|s gJ-S.f-yi7I$Q;-4[I"C5 j?_ժD,=Qf ۮVq ŏ.&R$%!ḿ(MI h;nٿTs3%1.[!fiڹ֩4pR 3fD0v{0iMXQC !SU˪Q%QHR_`9*p{hAbokj^G"p3j ˛rekHa,&uIv c\ /em_H(gNRp˪LN3']bӖ $w5t9BgXXlCr. qlL'iR0md;f6ZVJd_,tIBDaq;&)*_y(E;c؎x/>`>DQ+A|h$%$C*\$ԍT:.qy|k<8.#i]GQ* 'Zzׅ)J\/qr5CUXKJTD1q{kr)z6t!ɐ=7RT-*RY4ּɨԷW;pjj"L/Țո .H}SuRZ} gO'_UK^Gy>Fh+2`q, ȗF KU$-QX9(D6.,x[lxcӰ!)LK=G&}q"XD:̡*tyңrKE>wsJ+]) ..ކ%I|]mo$[%HӉ $ހ9$\9y1AJKk8};jP:0ZV)c]# rρf.\lX.G?Bv30$Q.cGyv~KO=  K6,7j"+\\CiiT)tvq13J[fTߠ[1fir>!71Ų㨲!'e4H&yZ{Mkɳۡ@h^R<κ!k~#='$zی{^6U\} ; |&\.;Yjvy.o]|:6ƍ{d@EťӯWCg >Se"ՇWT")xT}Z~seT&OԞ"%.+v]gm7tjgb01vIzI [j_Ϯ3s̬FKJ@Q7@٩9©H!J4_ 3,lHJ='UU(H@ƫ~7i5c!mO`/'LSO(?(G9T<""2tX ox)#q+$rYhJ7Ճި iYXN+a&>q\NWðXPIhŤC::xN.kgJ2?`~QOɋOj"(\5d$}(:O(32J~h3G>]X 7u.g>f2S$q3R.88t 80^D qQ |r-R}[< \xLY }|%|3c2GzbkBͿHm$T`Hu֣Ō@Zr h)۞9m>n 3"1DѤVÇ1(o+~ǃ &Ѻe׀;'){X~>yc{U}cc[To`D+'um\'K) y'~)Mm I3> H/'[vhcEwICXc?$q\|W.c t_{nr[Lwա2KmX=c$5p|(&E5ҽˇOj_vVlOoZ'E6toV%M,kI~Dp2r8KG8 :೗LɅ2M{(7"5F6NJ)ģ}IE skKzI2: ,؛Hcdr*%j:Y]4,J[rY}gpJ}*M੽kC)ѨI Qh&ֺk:üLGOtR \ōuazx{W0gL|'rxXo;BJY7߄}ZtT$EOdƔJǦ哩5CLtIQ~i\Ćgh Ә!6F-(YaՊyJnD˻Ǡim6:r|Eɖkv$yIyJHNT&ǶQjN vܔ}~*tq9S+weBv(7..v2ڥfq[9]3_ 8eQ/\=c 4=c㱳93:O-4;kbq虀d젤KV|9aG9D_)@, Z3efSCp_!FaxZPDNm5ץ+Y1X(g cYwiVꊟj¸45>"fk#DT;(祤C_}%`#'ޤ氂?pXc7Z&j3Q;Urg[N1ô2Wyl+d7*%5"b}oOgaŧvR&[CGig>V~)L+>g#@< {Np<{V5,ltaS-%c}˕Q^JnJIn/O25cjf*rG-E̅ ar' :޺ń`v5qiVf60U2(>QYn)=&Ƈ0}c($mbW^ ,xh#~M@Nx@fdB5>IiK d7H6~abSʮ6B%XJCh_q%],xȣ?wbml% kQw;6^9`c20+7֯^[pOaD M[髗W+䯬b-䁍gk Pvv=`{d@bOP6t/=wk` qUCRΠ]gx4-#)`}_K @pEl*/YKJ "eLO? lנV笅%~-’h_T;sevFxeYكcRrH-(3.]fܰ_<<.gIhendstream endobj 319 0 obj 8880 endobj 335 0 obj <> stream x]ݓ$Gq~ٰvA  ppF]q{']53'AYۘ_糛> nsuwf6Wg;_7n6>쪩v3~nwӛ-OKKyOߝ]8r-5nSk7~%%۔:k|*ۻ Ub~l&%3<nnn`|̆}c9;-@\78Uxp: |]0>O)$dK`TL 65gqJ\5-4SlMi,p`{Ya7+46kDnhٟ_Ŵ>JJyK[`Q,qH7kȱ@eWa8ju{)v 'Yo+XwŤퟷ8NXCf TMvngREi`_tQ$-@Gy=Kp7l<ݿ ţS{+ v^<5}K`mлq;d12)|vR+ j!]DoU bh#Ji-H񅯞}a\f˖:Zh,*l5ɷO1ȹ/[ ղ}(zɛw1U;_򺍃_ ]j Xk?s=C^]3` `ǫ>m Yjb617vuT - WR*W[65\)&!hfi_u KfפAX B-С4ᄈYWv."vU0S>NLUQ@cTAm͒['5핓F xu!)߃!J?E'.ˮ₠082HvpcV}>Mw![ t&Vb.}u &}hsP0!ڝۑ]l4?B >_E½hgY4$QG/Z,s!T) G`ZX~ ``+iʏ:^VKYsn@x%Ea "ii ti$oiss?o,Nl;Ϳw:CJц̯T`aY*{'4=۔@)͒~ᤵlR;8K?&/o0a;m꣜.ZS vޗPFv[5)zJfԢ ";oǀ,T74%oOY!fxB-ǎ2 xlUMdxN(gjV ]prƦ8\lsr))W|X1mL7A$ȈJ/M('+N|%FcQi, DZQ3 J9ByU|WYW QYxd{zL !4˪}SwL-W2_b&yx!& 䲭B03C@E7z8h\I!7AltI"`: bv@ցp_'SBpdו1GmXև!0݁Ol G]#Dž_v UVYgӺ֗7Bt-kb%2bPQSL7<#0 W-t^@tD{ϽF0E&!tu(v-ދ?sR LC6EmH:U93 r`풢#C%lwHRH'f\5nT^BC̶aEPT ƴfx*o-hDM h/X&i[)N]EZtepn:E/~oUt_g~9RZ_}d4Jo^uV|_t]㜱-ʅk^u9c)0qPlQ6FԢҔ D%g/G }ZxTρA]CRW֘ؼ>wh?e*Џ(0%/OQM06T(2HB R:%U >MXd ":N LB&g=5뛞>HhЂ6D:ْK-#/2 _;hYR{Hi雈o5w;`/YzrkؘU|  %2XzdVzu*shM〨RBh'2*t?e1k&0qN|H V'#:3TP7F8PkB`=Ї^v0YM-uX?@t(Ū$f'ցU'r%bw};BCq Gߥ7[/*ݐtdzŲM2tkޮ'|\,Ee]*2  z^Vm2]fd'.oaF\[=Ć;G0"5=6Ug`u@6KoyMбV8@(v =M@C!mzc` ѻ:ETPCg!a G"~ aX뙶Ą?h9 cHN4"yOv>7 HGsQFYqm G I;u~rk>.`O& w|A9¶?URJ:6B6_PuغNBsLDt{HGn/-i?:nRPgۆ{<Ε8p!QTE.~*1cQW;rM:bBؾZy-~]KsNJFAS]2^TDxʶu!B=ꡬa=׃s4 &$i&ԈDS4,o.Dw!)PQHSF!WR Zz|mԕ~*zRLSlL-EgꏆPc0t.F0KTuW;hR-؂U^߫#ps n<۶gWݦK}STSqG@2\^Owb¡IXZ#b>%`su1̱gi˅(?$ߞ/j*f{*|TFyMeyjyރXGȦ/]T:%pM2d@1%U^FY`NqPwg^9P܇!U=ėNHIoum]LTPLk%^*A[ Z44 ~wQ22{ ^+鱪,&7c}>O'Lx1 G`IY^7 :WN~$aN.atTm+6{,AF e8 RZc6'@#B`17V QǸhM$^0*k)^변.~槼dzjC .`96a:96켛<9e0ŭ!g/Ql: 2@eg[6|Np$XfB3AN'nv7޿gm;t]F Iq,G8+ G\1Y@ޝ93%dRO!Jqă ]N: e+f(NcφcN*SDpd |[]uX7('C 1Q` ,󓇃0'z:qph}yByDgGwgUNj#8OQE+3%&q isxa|\a5]PJw#T+< ${a.-qs_nvL46!SM~k̓1\,I/|aˮU1j81f@s iˬl܏ k^$ԃc;Ix ?}#[-OjjWLY^L/&zk>w2e%w ]@̻3qDjæ\u~ I_T vsjBZQ+"ĵ`"<3+,V/9k# ,uxDAf7ow5F> X\<Wq٭=Aq "s'LB 3h ׋vQgk9IeI6%?/Ͻaq#9RU_=\6c0R'uWnmNcXU@('s YE"nv跫Do? 뱈b`=ǪO:<UFHL)5s3E,-N}OČܙNHcͰm73?9"Cq\9_>Reoƥ/[W,77Ǚ)ȠYl:V%OGmX _LM\LEJL꾗6B&,W>bϹVY~ngg X_ ݦ镟2G7ӥ3xR]p؇(J÷="S"fĪ+В Me-s86"v!}|qZI5jSAe6I@'ףm(Ism5(vRܜA 㞟<.|t"oj -N]K֏\zHc0vsþ0?yNkL cF-ǦBaWbZ e"rrm4eޟx Q\Ixe,՘$jէCوǘ;7;ym!ۯx]{S*yҪ1" 05da>;lQ~S:*p ZUp(FS_rfsĻ6',a4 ;1 cYMnQzQ-"OW*gc5x`?Y.]k[8(*Zq[㣙mޘ X, r;TuΏ9hn?G?ɲŸx A4Q ri F 3}{AE5x[iA#Afr- 0'^\q 1cf3Σߴ'~~ʀ$$ ,aȸ}t8Dnb=|ʨ~uc)$O]=FsX.h3;?[@.%{$D'݀fD b_ݵQ+^+fFyDK ف'|kMb:HڐfqEx7kP_K2x᭏](E_FiPL}! H_bF'akYx}T}wx5a+qSX"yn lGZ9o/y89s^f%F}=cz7[ܵ8lCwD#W)~uk]/Vhr nGNM>tp> stream x]Is$ueCChX[i;d*HCz`H~/3eVH+09Y|v:a'}q}їJl^ޝ˓oOxupty9{q_!dXm;/N0^a3ip{ceLcsRtg9vImX2ڞЁu{kŖ ,f~Owʆ9+$̌}z{:ˍپ&,Fhݓ.`GN‚ݾ_yqJB\v?П i)wHdz˓-goNvJN)ƘTaKe.LI.ߟ 9qV]n{F^=`>6auUE܊W>cKBvwiQeDI=;up|`' f8(zs9-9bl v:$]q$ҹD0+!<(:{-/LnvבFWpY`_o/1!Qv0!=XxI6@:m+m@-ʋ ȿvw~ܶ&~s`q҈$&HAuU`55PX>LxeZpLK[(AK-9X3a܎X~ |2c0\|I%^gSJ 7ڰ`N9Bh ( 5Oit\-}5(-,0 ~y1j9Y hO[4ۢw~DxCC/07>Ą<2!jp#[܆rJ+F+ǚ눇WrϠf\A4Jǂsq! LOr@dG='POEժ()pR5-ՁKdgAG_Հ8 콋a'_[v{c9G_W0 ``M 󽍑,8.ǧQ"2g'q$L $Q6ܴ*OI9PTZ&ଁBnE)A*'sZ;|Cv 4Qd`lyxJў{2eπEĻsF'v[o]<!@5D7*CTPsA!~zZPF13'vY0_u[ W#*jͿ4ePC˼0/Qe !5#F4%񽘎ymHRDB*ETsq{3\9,M-j%b"8%'S002Hsݟ'Y>00JV$l0+0->Fuip@{nq|Qbz8G@7б3K M(0Ҿ v&bqHpR@0+t694,k@r 4`t |;&_ CUU!9EN쇜 ݿp21LKn@a\!IڀXǤV Qv.;(`o3{%xDz9d i4klOv'ǾCXFC/x0K甄z3 4 TޢjBX+Lň'TSJF/O0 T=Y} .`*"H$6UQ4f7gXRq?dZmuB' ̺Lr aYi!7DnBZ՝b=ѻWQ uxNR-/K7'"Qd/r1[‹Ly_eq;ܜR :d-c*3j _1 W]]_sfD!,?lwlxn4(Mk"0V9fV|&@gQߟ'l1X`lw᪊2bW%1fBN1t({+0cZ_2`G 8ـ=ȗiȄp44 +<,{auzJQսv200A"^2H`ѴYSf@$ (.1S6E.9fE bP"+=.QFy蹂@'ugvP=C`01Pu \ H*TPuN2+,4W䢈i0ָԌa9^G=}e ߾ rssӣPp:j{ּ%T! [v|h"X9Qle0PHVA3Fy\E`5-q. ܱ^-&X=rb]ӂda#4/<~O4m$[+DqRi7ʆ}&0#+FQxN7S~~ڡʼ$}S9cVw> zx@ gja^_0aGJ~+ FꚀIxҨ?*. ?>0\ (%%ϥ):wigPyԀ ,xè#sJs0nt:^*yψ!tve..cA0i`lI)a D7t@GD_㰯}ғ>F.QNtX$y*I`q ,Xt(~)-R9tTۯSI.,u^O_= Ѿ`nUp-d7GopUi2 iq^1lȍ/w| ZDH%ү(wFQ~N`/ 5s67ͧs307rmskkp[ o޻ܼܼ͋l.9"4O'6%R]͝>f.?=f_ G ,ͫSE+uMQk3 !a,D \X"7Mr*7.sܼmN:7 5o3eo&|$;9MZ_5G˥M7~/#T^:q+{@!Y/$#)iv(0 qn~-:%"k8.l74yf1f-AXd -*3JԷ͕Ҷ^!6<7?gy9Zͧj#LMxs&r+Ήfy?] C-}{'7l&6M w=_,.Yۉ|/,}xKӧWK<7/}qxZ.MvtGl9גh4,_-'c=$$/il/hקǸL sq,oF)(P㞂>RpgCB,+ʿ{(e y̻;g<c"ܫXкr(C",EF;|H/骒STe/udϸ'Ӑ8:4MZl}08؅z\˯5AЅ۹nbv D\,44-6a~u~hsQnb՜``sZrendstream endobj 348 0 obj 6422 endobj 354 0 obj <> stream x[oؾAmwi"r4ETp&eYEʢ1ҿw7sPI'?4jpw{2uP7 +^^GAik;8˔ZkM^dH#·#y]ê:{v,l6,{'ЅH&"YZTD)\:nW(p̾ W Ic˰l/Ks\z8"EӶUK8• EW@~ u-H`m]iI="d Qj| pҠod`ez+uxx|]Q~U1BmхU*Exo!f##] w [eEMg*u(Zf"Ncg(yWYt0~򦴕FVJ-[WIb (An=2O*'0NK SV,b}/1D+Yأ\̆\_C-Ѧ(-U>փh&n`@).-L'8 [Ɩ | &n y~hm̗E$H n0VA①6`$ 㘧(/BVW{0e-k,j iRyX)smI37 wEvy_㳯#tь" $_"9eys$/Br2+-łSYQd_UzeWs$ɪaWJxdTXAzGkFʻ )kw" !y_B-ߜU $IhO>mZ4^Vn'` .ɶK?N qpOpR>?n@.+}"ռjnSCf+F ?cʗUK:^B[<4m'KmtfmH* A9[%=F!7Cr4>=ly1Ѓ8qF+ ::n( Fe~F -9 А5ʗ8KiJzfa[S OKWoOX*`} QƩFm=f+1$gu4J6f*@3J7$9j$e!0i# ޏqW\>%`U, tͰ6w)Ãϥ5/MKM]PB1qd%UijJ3@p2l[LrBJxk{]!pC(u/p&焫S$xzG7\v1d Rt9(l TBo%"1-5q˹eJIuXlx&~%ѥ/ٷuz]lX9(@M:\y( $dM]`4nC܂r0bb[+~ud6U_]ڜ]GtVIf>}%ͫ`S\.;]Y[#n61 lW.KglMc?PѩS"2$'2&fwG|l1f`/u.;V,>cw[n=M&7qQ^g!xY*I-XisD0)-(/' tcZ6z;(Y}r| W7svV{X=6λ#A>!%;R7Gc%/ y~,{*kޔI5۫d͑\P y yI8n[X=Zr3StŸlg7fl|Vl6= t'O~ GG{Ѡ_[_Aom,׀4)Qɏoj_$*n3DM_ݖYPYOXҽ3v&*Bu-~{ΖFUw`@vu`]NFz/[gq{l\M{vC$ oXl|&DX^"9Go_ yFHJdxȹMN3/AjTsO(+ oV'H(n5YU &VO_nc"9E/p! GC>F}Qp s˴7HIkR]Ʌ!?kV y>ї ^u :$*W`թ!{Uumv芍=QyGޏQXw +S`%!0OY}mwD Ռͷ?P_3e-?&.I%p9+6IȿDUMg2޸Fm?2'~NXӗώQendstream endobj 355 0 obj 3153 endobj 362 0 obj <> stream x\Iu>֗fX9/-@mɆD>pMΐ]-v7G^DF.Gc̎[~*fy*w'_0D^D_O.ޝ fO(<={u^J9xꭟgN^NH7šڅi~„MlVv >0]dnzPR|U~1W[YZG="i+ ;npskaӎv7 -qRP{eoil9U Hdz˓I0z>gk:fukd]:-ӗuxU'Cv6_\?uCY: ]~i(_RDuz/A u[͝ L$·{J_PcCv١D߻\,mZsdJ:|SV|YmџP|[_ _OROXa}רrc'ݹ5 \~'~1ym@;0N@^ )jl+*.^#FEǔ|y{x,4(e je@}bQb8IN=G1c*+ LO#jdz۱n䮘~oْ1?Y.fuȄ>^1~7,٥HM9mScH0 }tӏ sk09 j> P=P2iBs$2&BjFzJ ƗSWOWi$:G@?hO5ۥK`lxv lֻ\ ZaT DWj%n $)=05jd`M{~O1h550A,=!L"Rӽ 28EKexq;] (<@v9ĶX<t7D/e `i I-$_ 'Ѕ6$.` E5 O"(@|%Hu\`'Y#0nG D}ido{b @?-&M"<AiWAr]}P`w֘ySSe3E 7;ӫDlM< Q`98ul=q[Xt70KE¹ ^?$"dVt1 O')MgO߯Z头U&H`_Ĭ$f򲟼ƨ|7>> JLTt'm,OJztmF θFnRv/ڒKGÁ&QUfC-Ϋ OZ/2gkY1VbE\ᒕ&. HKMf(^V{:0Yt3P5Ϟ-^mNzM&:}z`DN d+Pee N.BFMB (@'GXe4:+0x>D `UJa Q$]6.6SL7wIevzF'pKTj0p:c]lA ޻l}Q50eAU8-V.C>U?AD`p:}l\H5͖V3ѳ.N2,[X^c(*s B聈Zv 7/& *dy@KHX蘱JAk4EL0oMQgrBv i2.ciCLa>G֬$ݡ4}"JϝݲqN(9*nҝ\"{F`])/+WJ1 QKqeL\ŋEsh~wUt)z H?'Q$hd8=e: wCp! $ ]sl -:\U$#aerJAp0cF p? 0{v"2_i61)?lJ4m0y ⚧.6W;~ hgp*;(&ࡥ(6_mM 8L'%),f f;|CCbi\)go3Fo*fhz3 ZAk+ЪpZDрkKe.]j[)4C$RTPg&dYuj췞(O@\y6c:JCbFJ: L ל+FvɟJ쎒oaj?**Ÿ`P T(=p36>TuosSqGךg[2I#h \haa\ZMh a=P]ݕ](‘q}Sr&2>9JM(H`?[wqP&%,sK6\tv!.~kH77WOˤaF ~B*ѬB)LBU_n" rܰ* ciXǶ-\[ 2 騦A1y?KVGG}_DV6qe ߗ s}2"UӆaVBxHީn:6tOQ\Cw)!nS&$F΃=R쌍rY8y”*24;ƒPpX._RGO[om(tM}NĢi-)lpK>% ]";6wDd宲syɰY+^K9iNjOk!MpwH??[JMSi3{^F54ORwd7BJv|q7xj&Ar~a:A7( (ΒT8Q]sa7])Li1vȃ~Vkٝw\z;FE8 T`4,ܭa G%Y[iyIj 켾<:"L&QG}uɵ5S3yJ]fnxwy.=W=p[1e6ڿK[jnhAbxܦup+)&*1 Ԇ~FR̳BڧۯYC26Ļ]V6m|HLDZk `gFw_Q5=PS O1MEL&<6:i n{~p])эѧh6tΉoH sn3˴+~#O1VܪV-}kx%R}L?Q&"i|k(+_hn\y{Fs-grp2(77hE=G^_HjGzG+{ES$[ (\pj%ͮ^ "";,lg*+-5,#&>]1RS3t;0*m(We-=K R;C[|12DBR.bSsY 6pXt%0_1Aqenۡj Q˅݇F44ǘ`UK1YuB5N+ڲy'-BIdo3J(SMu/`Ze<ݔ .i֤ha|FzME+j(1A,5F %Պ>[ǜW[? 2lPZ z?Yܐ+>)չ#5??endstream endobj 363 0 obj 5473 endobj 366 0 obj <> stream xۮmu%b=n|))$9,;ڒ$as.[s\~k73}~m|g~>fm|>~ݷ9/>K)y_<5'/~|5W{4=<,s޿ S_rq_-5VݞouAM ~/K}nk4;;\~5Ky|֧G-#'? JIq}.{xLx'S`r~_^]-|޽=u_c}Ǟ?ڜkGMgo?ᅰ+-+)}o~¥򌏾1>sG{o<39?ls̏a`sϨ?'|_8?K#s/|/G9x2?HR:#sӗ>bm-{{K(5֙Kנ[Bb6LT'G y7YЁ ;#e^[Q |с؟4 o?!u~%"z`On ^=4t%$oYZmB_:̪ ",m(Ei[@;( ܒЧFMO$E{ EI~;(KL #idAP'o>lF*f/̞P}w*ֶbV=׶R IvLk+D-p50jP2: $eTZ 9]ɶj`Kձ H֩}F۞NuҒ|^5^-TWpQ;Ffx߰i[;2mhGit!F:Q۫1iu'na5P#z^?fg}K)mi\M aqC^ԝbR ':R~QJB@NE0ʑN\G_밯UwcϬb]12~k&LźUZ(@}VJdqH d{>a(})3ѷ/3;Pjk[Pzyʑ yɞ15Ҥw&J7{D0X|/ $u2.:$0cЏ-t Zwp/J+!5D G6ۖ>^鑦@bȡcVEɰ (MůnֈM{ [G:/7 ܀,ibՆcv<1nߎBeO L'b.o<* %ִ6Qzhݩq]`Ζ6"Xb?э5 o<>=3!ч؏9Xbbj`*:H+P [j:PE#˚a0B-*5Pv!v0R97Fۤgir"lῆ']wɞ1}ˮ;Z`xA[|ne$~R+}HqPWnqQ[FC W9u%50X #/:,Fs0lupDل9"xUN'=-ňį9b4l„D,Լ#E<1M06v/mWCzv=_)mxx2@#N& #P,$+Ux4\¾T60-++'KɃNg-8l.bgumvrr (bL;a*I!Te^S|B: ӜMS\[>.۟"5# I(dO6_Ñ!D/EJ&`5T,ȇ[>} ֚%i|/][>7qT. TQ Ⴣ"R֝W-J3>*?[BFhuPj $-J'Li #3O12PSE촞#J(,LJ s ߬q>ޑ$pK)È<:(ռGҖR"=R@,=й Jn=G\;Sʊ#q6fPQn%7c=lvuw[@;{}HEC'uo2T'{لg5#]x#& EHMD]SӪo8IqB_y&bKR4[@>*ަ3Z+CxIN&G{}EVN&@9鍷Ni">%{MSyIIc(p{+It,[Hqm]FbI W= #jwgX ,{hأ cȜMIq孞Ci!,J4y:·i!rLJ]p8w 5 S*)3x^H:/W'3Dx2'PטJX=' x'I*z}ȁXCUT]L$)J'D)6DJcJz;%)3 [<9sif#gGjoi&D-{f-eHZ6y*Q*a$2$w$1ה$q%"I~v t3$)OV*ac{%1qXvCa*7<6kGr"JHH###`Hҏđ#@bֳ3 H+jP{5+gIջR.˛điAHnF )bJHUCDX5"I7H[ ihMMRQF0җ= ˀ"G5InHLf[HMD8=tl&43̄(Yz(R П B@GBhG8K#QV&T* ''UkMK˴4(F"ut9`$f|6 L_3$}s=,E@Rx3!XT*/Qg.#L#8R.#đqn&4ucđ[!Gh®3q$EݞTbGsGZ&BȐ  (Ap%ՏeBItLxIH 8~6$j"T  A_\B:Q"$̱J38ғbU )1m1e@7iJ&UtݥM_wX #QV_Ht7|Mm #UYZOp7jFqtr Y1Q}6azęlH#Y<0YT\&TL#)#uHIYۭ2GDh"1ط'`%-`G@>^ LUJ7S D5v(!Aol מՠ-TCj < "C"t 7Q&M4S?}ɼ9p?ӚSHLv}T~B Yq^S5KW@bE#qwRՈ1$͞s._w5#,u-K7VhJwLF"ZBHM+D` (1Q$qbDdr=)@1A$Qh "WMG!' @$t1 @neWtԮݝExB@$]?:#Ny&x%#E5@GΓDpI!~Tuͣ_-V#ȓJ#|d_WwYgCȘQ'k`!|Ԥe5GN!Bq dU3'4*GEQ|"\-ďԏ*J"B(-G-v2K^UToӄ["AiW5?Ru5ۣ?3Uf!T{dw $意'; %YO>bn=b w=WYŸ#{??@ш6&##PGҳ=oWᣱMɾˮ;5#ccұuQK!|TL|#x$]L~Z;r@YZ鮡r`G NJ!vCbG,QV,2זZ9oA%ٿ.9ɇ`e.O-dDG,ݫ7ʅ V?r?k e G U$z?^ąQVit,U#/ԖeBåԉI3o]9U34"|ySz>ۡ ,k<Jݫp'gZ97.g{4"|n"e tuA%0 (RrBVOH, Y@ +6GU !|dV|OeU9O a*GG.PH0x9o3\?S8ď,ڊďƗś'P-ďɤ,W!qa&;8ďڻDɷ.UCiށ5gfG/*GT Xv:?_ylR>̋R)_,6rB=ʊ>r%;[1T #sJQY/P~ϙ %I< V!z$#%LȽOF!jrK [y_QQx/Ďt:vكf׮fS a&YڔģVWwa[[$ܫ.tu{!lT}oVI}~ 1#keiAB`F ]bFթQE۔3􍽪Q%W,.(.9?FG0ceJ t#q.᧿a6 y`3;2䂀UU#_޺*_uzɯ_Gۦna{NBzon$}&i3 6?;ԽH"&ѥ_Xrl: t:v鸢NjN%cN!h B*u>w_>xj9:|:fؑmxNЏLyDt:u~Ckԉzt/|:-Nç6vZ/t:m+u:zkMS:;:9vueBk!#uZJ??:roYCS'4t$&t4ԩOrܡԩoPqh;Nˮ:-YiOwsߡMcJD$>:< :W:9SOr i7"^}uu1N+)uZw=8Ȕ:BSO ҥdcJ̺9}p60鯔:eR@}(uZ]R9J9%vȡԁrP v.NjTdPSWoZVr9u [#ԩp`<&̑)-p`|Hu,5Ru s(y_ur2~?@JçfQR=>:/6]Ost V_t1tl:5iLN}MN=dbӁl:l:?sNb=2mСA&`G pԻz=ԑ'N&טN C1t^`DӜutZuө;OttZ02N}ֹtjn7t:%5NjWi`Y2fөEMJMh*s=vj1k?l:-@<7iRsK\åeV%kO\:/ztőb*nC(ƀ/&ȬIqĤSc:L:I=ØID0鴒̉c"ie!1̐%&ԙIg:/Ԡ_L:I2`gtL:K,9(mG| P\`]d"HKp~~͗tD:P$9Jc$eGEu\@[)-D:KM?D:ow16)]LӒHR<>Ħ!i5~b"<,4"ҁAaCoyt ";D:Щ#CnDqttj:QI;L:gtnrtd" !}G|Q?D:n0"ҁfLCwL:ԎQ핦L:t䢛Ix2@&Û>r6βML:<"HD:n9 "3 |с9r94:XpMġi'jPi4: 춹bL?|tg@|KQKx2fp1|1SØF/czS/6#fz!q&pf*ߥ@v5anMcc\3}(tUMwQu8t`jNKpT&QЁkqRpS|9t^!ѩSIt~%ѹޯ9t8:Lcc  8:ݤEN55 t<}!СODPZ}tla<C%CZkx,l8j{{ Ё `vs^8t_8t}gsq9t^9ty4zD{^+ [_Htfġk]HQ?}Щ47LiDB BSES!KTXESa#>S@0p@,r8tbe5!`59t+AN}͘C/2A|Ё[Q|¡SKM0Ré# dLc \ ftS FCcWȅ)j̡sˡ\+.:w3^(3DL#&сP!ѩ5Xǿ!:q$:02_Ht$DjT<&ѹ)KSo!ieF(FŴ?4:2$LJcCS4Gou35a׈FKgF+N˗4:W]*_i/ ܄с=\;jTh8٬9N"$W]k0vȡҩԆKˤ)ҹXҡ@>&8~nb"Hd`h}tꋻD:0Q=}ytnZLTSG^<:G=_xt]̣k9r|> zxt Hj><:<:<:7<:[D:UwXt.%FEHnk=7Loc@ɔ9N&~{DCS_'&!AYh ҡ>1VA9 :jH Šà3Utit3`!h34>Pi>9PIrkff~i?̇&9uc8 NUNG&Q!& Y:/O@cdWttt: :/~tͩ7zà`1-)t`ld v)5^zD:]D@9v@5O@wۙ˟: @(kL^>: @BQ|CàSOeЁ:H :H,4J7Xa > }6GLCoXsnjFsjs%r0輏A~G #JA\[ (0\2t4G]A^blBB:Rй)K<,B;jeSC69tYv>:C]p(Bέ|$:9Dá <;N"r7;9tzYp¡|;̡ _׈C=.T Rf~it5g|:/74:#0g?4:5K;}htaF4:A4$l^i,␠Eˇݜ9jԜNˮ-,: âS;c TyXt^âS}|,:]LpfNjC^yiáSץi'p s@dN=|\Ȗ h̡S::p`:sġC x)t!ٸ:Taсv̢$,:{̢EâJ#"_1/ Lo XSX~O0ԤKNS0wtC2 t`ݴNNKs.&qB!#4NBfqNt4p9uoMk6æSV;d60GF66 E2$"(W.&AGrwtjd:P#ï^å:\:& V)_LigLMcLLg /dXwt 5R~L熑LuLCIOaӁ>_t8l: %deaөP&6H܌æsĦrgG?l:324qN"GR@6 .$?&ӁLA&ӁXg bC2<L9qވK"LO!!ӹA%asC pt9@XuTفtneӁȧL˦B6̦sK.Zæ LD9Ltnc2[tn@<&N}%өܬeqJ!gT9IyHM̦TLŦsCSaCɼgs)/}'Č:62~KSG.{ R'K:̳rar,;*ůD˩ ;0/9S9!9u!թLHu\"a?O*xUFxUUoO $aa_&61&APH 62k<¯gWݑg8ӫuyޫU}]uFޮ۟}Ukvކ5Le׽V/d{ ?& ${z_󯵀6e:5 {^z3˿biN_>dCդeH-[IqGRX!TG;"H'2('L굗89=%p##pCxf`!g؁ʭ;"A~A$#VH8k:oǗ}t@J k>(bp%N =JttԎ?c4D!3eXsp HB^G`i2䣪18bdi<"\ 'lWA%'6!B4O&V1 !,5J|BݟmcxENa(4lɄ) VKM-j:Q'Xn3c$[&s\&CZ'۰L#DXbjS>ӊh1 9JOb6̳ <%h؛@E\a^Yʐ&IzE#U xᎵbeAbb(qE1Rr yY`AK*fanQreA9)kFt\T? Xʶf*jAIWuȆ9:F'EzT=T$|@;R3&I 1D0V^ZTdPXjbGLDϻ sG(+b+OZQ?(Û"18+&iv_kW!z G$T2oL(C2 YPPVp`Iz@cd7T<>1k ]F;c䑇Aw̗tǬ , )&h#OAj`t  A;ԗ5~Z$ڮ1"7DICU6,A!L i,Ax8sG"v(rز40pD|.۬:1+hPǨU!HTauj*[jA[ olA`PRb3uwV-F)"_NS/#)jb-OXEgz ebZp)Jݪh[Zc6uCjEjL#"nPb*0@jS"+E ƪ۸"l MpإzW9Y UTA=bІΤ#~3Zqk#ȹTGYlhTVy+FrKm C6 bQJƏmT(G1hyb$pc r12zŠ.7Ē'gr%E#8Oƕ3Yj S}xrb Yj4>1lKd)mQmP#HJʸ@B0ev>Vud+GHb1>2#1#1ϤT*TOmA}[1v"UBhcĈ9 1z#TSEaIF:qǕieal%C5|nb-y9+sCWЈ,uiTdemKxPrysa}+ cۯbv2Q O:7ӵ0CM74 qfJ+bb@Paڮ2f‹qƝmMEAE\@asApyQ ܍Aa?O+fdǀ(WOeuDK`x4ŰT^6ްVݒ\Wv;S OLdɺcXpm4ژ?-򒐷1ԙaq@p;7!/bTA&=Oh_ƨ2(x12rLR+ dC%qGbQˀ{xERE2(7^<Ꝣ(m[gm( zW&= M\y) tē{15(l[1;·S_TRj`@:NAUGz#&a ]a\Pƨ s|H,3_,M6 %DKۙA|ly즫,1A9(78d,zmJɐwǘ:mϙ :^?lK݃*wtpw{\HTbOIiAyKNA(ǴQg"?dRPPw|ى̠&|剆9 DtacT1Aj1T_655'0?h|CVcXA)B :zQq8D`}N:pnŬ'܆ZrL;apPubܤ?}GձX6f : ctCqFL(pAx;A0CY21{ty 5>S݂M;~|c HW94Mi7 r:Pꮓ̑)JOiL1XֹAF -+&൘zxbkL%d4إvsP Z;aDu :b+!AYb~wrqcPK1|\T^TS)*XKl}j1{a $ -S[kX1ti5v"sLJ9 j RD!TuX{d:kCWPF'6:Gr]tyyAy;& :H\1lmtbTci;lkJ!ca.n1<8.O2or2R?i!u;J%6HA™?HNY €8Q-P{|bs$Ɂ s57++Ac`XxKLrp;FW깉uc .HV-u1&~$3oqğe>]1ƿ>T|gOLWaMlw9U-uF=!22H:J7iΘ<kbQsHxR8(vwMq@L5AP1 .L SsTtnN:oo Q# 2i)|ka=~6)~(}JXbG㠕I牥G!M1$0 fQq IdPZkϺކ56}4t,mBED1d} 7F$VS};QUvPLL(-An'>:H$mVH ; D-{$O2z͌*dȨ-Sr.E[1 I5 a&b:4!\pP^QUuPeqVQ+?$w%CP']ŻA i.1!uOabvZ^.(ggK*I1}6quyv0&98? ȗz+o8]KAFdڶ/jQhl3ZiD#A^UTӃrU&(MKrjf2#.a"KYT}i>G#(|/Cdzi19[bl,pv1Eywdt6[$Rd; "B;17E8jg$^ueZ*nTwv AܝdOPI"&16im1gyT"҂B~U_F5\:7t*jI+7߃ ̎Y"9;}${K uS)j8 e6`5=0h=n B|ԑ2#*tnIR#)/;[tZ(3))78c8D[gLqlXP֭2B!ke m|4NPn!1Q)5Xh- :x'u+`#/ H؆@4;qpHL. 4 @% R߮tC}_KǞǩWKP)BhcX#hXxVйa;,BAwMB Ev34LiLcaDP#,InmУ6-fRR-y4[%]|)Fy5FcY J ӜP$8 [.m)3p@ŜAPdQ']VecŹxxi<}^MAj P`4^U~IMAjC1oGFTo؂/{qC1<*Y]|XSPu;y%!Rٓ8"4 Of+ӻUw7"H#;8qP0R#(߆9:H^Z b)Ammɉ|5 _& Qao + Q ۋ2Rt oɂ2SŰtn:FF1%ĶAA Ortpo)sH(PO찍xtD&ONj:-F6t8&.8xj!҂ْWJ'ȉJG|NBib ڔX%S)bfa|TǓDӂx+A[e . k&HdWՎ7g Tb, >-ˬ.fVP c͕ouSc }3M TNnE أFS Tٌ7W~ѲwLʶ'1ZXA- JhvaL-vF#j% ~ EBƸy81P2,F{TTPTu5Y1Ŝ> d;*&sfo>;~ LyoM^_o{G-Rd쏵#oOݟ~@gg5E7c=~[;/we? ^-bnܲo3~]-__7H {>~vm'eN a{_#C''q)| mfp}4 k v'~Ҟ3T02,t^sd--O#HkV tW5h5* 8tik~5o5A%9i82# J^pne^Ul*/NEϗq1@ĤKXKj#?4iXOq#پx% T|qRyG@GGj9_S# Xi/iL8`P2ZB1<{@_69'VzLm2k@6x.8͗#=1RgTn=[ᕥem!%hw~ί4q[/ya$ t2l7T=zeIޛhCfAF&^xO$̳V U}hH?'>[J1˃3j]_7<#Dtx捭-V5!YԹ103>sL&q><[fo4h\4i%"8ӟ@jmdԲBTi䇚@$iEA5ӻx= ՇU0YFߚ_;TB#P Z_{.݆`y DRۣ~|S #-K}@+o:F:H?ٖ*a/ަJ}rO䑨ʖ {%ssRJEI$3Y(U2kFf}x8(9v8 "Жk$B:([/ #AhetT#ӤUpM 0/&p]W6("M!m-IZ Wm ?H>9B0 8BqDhX\):"+%PhD; +f},ޞ\@* )#"@85lwtD%&nUR6l[@z $Yk Ⱦdr~Hf]h߰y.Æid&O)wum59_d5TJS~NG5@ա>J o @=5³<5ҡ7?}Ŕ NIÞF߅)JB66J#[< K߳O X.74 &FX!#[PoL/[oƭwV[:;;Eҷ _? pA>sdK ]ק[h -/#LHueǂff*76jlՕ5&]t"=#A@ӳ3MldC5O\*m<_;w\i칆Zx:GRh45R>Fzpl٬|ߴQ'HG՟0P}J#SsSN_Â.Z:c}U !ֲ3trqΐ˛_+7EгдQZ #CƿG$P trr-+ C ] !ߓ#ky^,9cTXP=I>EuA 48q zVYp6 ^B6ƚ !Ʊ s )=cS8nOq[v2Ltͤ.НqRvNPȢ"vf$,-A9q,q>GM\+ÑH NK晇}1ru*x E?Zg+Z9׺/|cgOr&wޫ@SnÖłsD5p3:+8Y,##l0΄9wnga+ ';&*/#juIAB 7~9t{o% UўOXk<,Ba3F]8JrVVa+;2=|(=t6BTM#Y:S-?8 -p}b/p9pFVt94ŬWfu9МwRݫG4В4AWfй7'ler[1M=RB{dȅ@+>aQ%UUwdQ%HN$j)ОuD '94Y#&S{dk3e!4RH,w p?p`Jsr6a/k$(nMUXGPxexYkMi f˵;3OsSD)IHƏ=lG#!#!z%ёGKb0yF)Q w'$7nJ'l@, />B&x&aid8p.L"dIM&_ )4`B9A8gΙ9g IP-G$IKh$a=Iʎ+ It#_9R F4k2BIsLAzYU ㅹd"IYVHu6bO&!K,=9+LrC, cT(KB5 1!<"cGXFۮ-sMDʍH&N$))KiCj`-VBIr}zV< gJte.ICx:"s2ZERUlS)/hC dРGw>H*¦Z@jKYJ(`^đc`EfY7HN2̌1đ:8-ʹA]`aL IF_BVJ d+y 85҅F|Gn t`B ,tW2UEɲ,x,:&ӥ#>.#%YR)HII^8Ґ&g8bǗ@'"v7:T(GHb A&XzXoHhCE Q,w(BLf2@fH݈Dr8Dzrb\+ٴrcvjP:G҆_`FĄu"._VJAKs`)9C!dGV#HJHb,A$ @9^@HCzG21${Dđ0)jSWUn^m&i ,Mi}_ JMށ ꙱#YnPß HHDl

jO F'qēǫ,OS63nH(U%, xRو'Y ;IE(1JIk&?0ea} 4BV_3I ٢-CD ofG#",ߢ'g/alG#r5C))n! R*/\"-HȖrRrI( QKHFjij% Kv+mYOJ|eg\jR/IŁ"CXSBDUǿa<K),0:)taceohJ)ZB%5'wdUSڳ:#+ydIсD{@diuYraܘ)׎nd{*e(t| #-i Kwr U~T{ng!:&@-U0M*m=!$PVEWTʲCTdbJ49d=jQR@?!lP*@@(ILFKiS5BesRMل[t( EsN՜NX^%Ը&Q70WtLD)WgK'u5+J_JU: P# )dXR7R%.iޖb !%G BH)BJI_!4SIBJ~0Z<*!g|qF*+O=*7K J%nHi*vȺLu­n+>XMW(ۏBD3}(1+  @>`ժkt5&_|d zPB"JUNGЦQTهp0V(7Q#4SU_+ $fƋ2Y@G"I.P2C@c>8RCtdɢI-r+XjgGreңs ,đp8Rsq꣊KB$j4}$QI?3J #grsM>Z]ӜK`iJT|J0V}gw.>_!T7 yt p$"2A@R g,B##HbmU;k5K\S% IaǪ1$ jneȀ%ω%uc)6=_IĒ7Ϥ|$$˪/KŲK#.[#Iw""L:Bʞ0RV/}Z*_0Ç]/đSn( IwHb ŕ~һ @jx SI GL؅&Ilh=#7\SSD2+h;WG!D#B)kҫGB 7iUQG5]Fv3Me_ÜSM/\ EПN!bGM0n**']Bk~[BHvQ =W!*$T0BHVל~)jcZ !9+><|l3ix%!P44|璡v#?ݗ ش"9 -A)KeIK^a$EG y'5hBrHL .z*g@H,TY>FD8OHIEgbG8Ұs]#1ds9UA0/ ]!xҴFbv(b!?^Mvٱ3y^ 1u'F*P7f1y$WZ|ѰY\Cnw&Zݖqg 钿LS/:}v@ƑDHvh24%G&#)8m$ $q@#RvHZR$HZbհ'aSH(n@\$HRΈ$1Ѭ"пIrq0/u I_̮-nPZ~ :H0'gq{9:Hק(vQ) "!CZ_o%fg Gg-tƐ(j!1 f8jb i|2DѾƎҌg5g?%w,|5KDxn'eTݩ8Es9593ĺ~SoXw9;nw0zU(MC&HfN /"'B/-v",rwPqrn(%j^N9U DhzrchHMq񉶮j958T G ?Nbn #@ ㆁ#ƀ U]g vX&##Gכ{9b6\.X_~OQ#Fz dԨIGQQJ7i-JGVڣyL1nҜbH/èūZ:F]LQknqIp@ghhK ՏIǿ r AhYw%eqq/q!xoYEm:aB8ѸsX?Kwz¦`NI/:ۖ`Kցۼ@5O6^xov侯-*07Gj@h)՞)ujA1[![6D3h1s=9{Ż'wLA`E;o4:tAozD(Auʖ NBr:pbN=Hr;r:]A1SbN W~@uj?:E^^NANQ" P| S:5~P+To:չչ'S.򛩃s瘩S ShFk3:Ee^e:HDh :B 8 ّ~O 3b yWj@u ~Cuʌƀ`bWcv0T$Cujzԃ5>4:r#t/h TD4+M#Tr;Pu*h6\X 3uju(0uޙL):j_ gGNLPD8yT_/UȃU.XRXZCX"쯃չթT:^ u:(y@6StT n:Bn:r_ݚBxWiu:{p`Ձ |nㆼSW<3Wgsu=#/~\w5W_AlNԡt򷛫SB>ha;cpcNefjց$Юlb{  :jlu6p /[)op#cucu6:n1\D"@t?:tGT\ N ]@u534 Cbׁp~u]7x2b7 Nyl91MS!ɘSsE5f: Zة r4bG-rCwF 3ARB&+;1 1aʈ C22;+/z> ;{L؁<Q7_sT'Cz:x5u[unbL:pEmE1:rvu0:)lui7"lA'Y"k߽,C)p_dU+VQu>dWYV+y &Nu~%h*uJwA AodNQu(Q`6n؎|ۂn6[畟ց}1lƑ:mȋa9NmN>l2l=֩Qpz:&}5Zn4N 8pꟘ/I6Φ5?`04c2Zm஧uKZTLuGa1:r߿u02mBxufJxA:*c>hF{,(:#m<)#Uyiu^;:خEh?:?:H<AgG&aYM):1Rxr CPbNy/:=HaSUz:xFpX~3ukt#v}:yRx u0TIHZ_؅PKC{LgN WA_DRKTژ.R#u0a b#Z1RDA,?:Hn:f>ee6ڣ ?:* Rԝ%6j uPr*:e!9Nԁ4P( NYQDwQo3QWχ|:uF J{6d&ju w(&Shb: ":&ĈC7cZj pQEAԡKC1QDw삨SI@?:>D1Q2)QbƎ} QCF0Q~&ɠ 7:{1'`CuSӫNOoQv<l1r`:|%t`-hKďKۤ~dQpK( ksAO7'0R_/LfQP 9@b5,.fPG똥SKdKfy; tfc-l)~>,wC/\0+)"s`:UV^҃adi:RMSt0@@ s F s ^*RL*fWttIeΰj.(: ?85!Q 9t!˨`_/C6UG dbNd7}Du:L .9CaY#t^$*GF |x@`'dvM @輻: @PM}й7OHrsܧsCЩer(-:&SNmrt`!~ RqcB ЅZSvDk`aL)q!c:"tt~.):rF( jy?:x%ATc; 47 ,|;]Bs/ :-Ӫ%Cty :'@t,z(:&cI<Gܺ1:a.0:e"9:P5/Y@ptVV0cK|E Nd6Fʋ*:%sܨC瑞mq;ÌOTpWG'RKFXNG`tIc>1Fb#u 71M'qY")*bt2jGI2$9H; ڣ=@:oS 7H5bZxN: cZ}vt +L1H\ h<r |tcYCt`eNbgB$.֝he9 䇣=+q9s|RW1G@* B5kǎ8 l70So +Cr-8:(wP:a( 08~Ή dfpt;$(o͗ȓ5T@ @R@:us58Pѡ0F$BFSLSh99CJ ʼ?)Vs̑TsGs5G/5Gx9y8:sFp載-KK'(:T$St}Rt-(: s7 : }_Ct ADiFЇlnd'P2@"NE) y)9,l?9t4>cX/?9'shMa:J90s01>u7 %샟s 9@W" -:lx:t>^W_ λ"O=z:+Y8!0[D|tN6!@hAzv CЩ=AAСcU ΐtt"v:Lo6@0Z, )V[@˘sBAy AЁBzz Ό_eFi7s6FW`:p{W$/5:rkΞ* L= hAq~w~l'_7~!Sb5ؑx2蠗U1Egӵw򂢃#Srs0:20:pO>"7䯗LCPt0P;ᘢi5ܧno#D˄ NUK ^F8?RFQFdFGY(ά`W}):p>qLSt2Hn*c:~):o_srF>wc=bvI $@I:x&I:EK90:.C8L_9*Cu` P1:c,0:$e8(5eF;rɹcyf_y 9)܁z|t@П=O): 6(:nj NTC7jpsR1t5hT@tz]%MʥIWb??0:O-]oATΞ4?(:TE)6g_W9㩣*Z>yCWEU(xhϾ?j {7;noF"7yTo);MǾޏyfkl~k~gQg=Fo֙48}_ۯ3;[7Dؑ$R;`@328Qˣzy#ɳ{)w|!F,#em]KRސ8(i0Zʸ(a!1[2nCpIrWIFP57Dd;VE9INdlN!!0@9b3a89)igWщԝ3Vy@1M݅KPA@3.ЄKIJX[)wDȦHw_p4JXc_ቛFٱSUO0JxTr$xH2xa𖜑wei={rdͿ{κVo5~a ޜ5;&W,Xph'8S'޼ds60y#x32-՝O:)qoi G`\WW#o-Us刬䡐 쒣(W|;(99BqMS ˶|ʼn)wch9=ri$@sLKh1ܾ[2ʚݍ2^+xf+scp-ƲzY9)[K k3,]!BSͿGok+Cfo'/ D|9#Se&rf:-r Ҁx~wm9Pс=fFꮬ:RFth-۲xf]Z39wSfκX=GbpR?9atJ'pTi5p%G̓S)9{exs$~<iK,-g# 1bxK~#JY+c8$,õTx8^Zp'磙?heWZoX`!O֊&QwNLG3o嬬[M,|?0w`Qfas=s'"$}Y.(& p;V1edH|uP&'YmZ2x<),Yi +*Rt(_Y+gyIAS DY %Պpl"Eճ"\IFJYR 6M,u2U,ЖsFGࠨ JGYERf.E,+XF;ON8#cO2NϙUčjC-N.SK.BefՒD]ƆƱ^S+YDSV AȁfT ! xH;ab2Nn|m_zƕԒD [p2Ώ 1FўƽRzG"1)MX1=g(VrTDP\|-c0yPZNVg)WuRHE=3n M‹2MޝseB}%W$" /JgKYHbBLŚ㰽[9#;E|^Sy@y^#$,rﴤ))J""gnPWU8"OIGIђke!Yy .iIP$@:Bt 3$]3V[[919W1X)Ή8LS:nӠij9tVV.㓠q1 'z$ +U$nEc"pZNT# ] YIV̭vx4~cr ݷՒ a%ax$oҴ'$K\=9Y86_ ȹe[I89-TUu&Axyqgܱ;:Ҳ跩^ΤÆDfvFQz_x]YQuaXPY_lfuI2oc+'P#I}X LOK|Ol LH:~ 3zR8F8zjf<'5# 9Q†ڳ8_}Ezn%D'%c f$o+bpI,?{>Z+i>eɲ:mpvWI>g,U{9c-R.erU7._̡u?xni&) L36 A$.e)Rzb.: 99_7fx&H"3H–d Hl+<Dz³'͞I@ }[I9JIymqќDbI|L]C%K#MɸgcNF8L[50y6Ug}*ҕ LV쓸$IN@y%E>rNWu zk墟9'H 44oF2ԃD(ɮŵzN=bWvbOPQ>y-٨Qd%q7Y{`v!}O3 vX#A^pNTR '8Xj08\ I󧹿[ޯ`j3]خwiM]i%E:t"yaq:U|;<+f:6 ]g|琗Y0۸<46 D(l$Uvbu\Ļ5O}3S+;M424] 5l@Sڙ<!qi[ꮙJ]`.ʃrqp` $sx]N3DJQ.RI'ј#&ԤA%qOIb='3э<ϩfAx΃Kr'fZOjWX1ƞD63dfaZuté'I^wqC Pd.xr;.R/<9|EѤ^U1z w#xKhe:G%gn; uiiAI7?VrkJ^#xcuגydY-it [WLZ[_QINH7?Չ\ISW$βT!•n> (,A#㈆d8M)9Nֹ Lb$s[I )y IE]IG5 B]iyrޱjtל\#8V1ωh9mo}= +uqt6 ԍɶvL>(fdZRjŠ徚F|_#v~Ii@Bao#^sI($4-t܁]@ӡqw #6UnGْNr^%l69Z[&↙4Bꀡ5Ǫg2Id϶KB'9fL{4yj0ŚWspcڶu;)>G⃯%j\KCHz=uzJKx;NyжGdm\hz1|0Mu~} |jl(d#]s޶/Hg/>~?Ao? #-Yow}-$5alS Tn[@&Soo ]sϿ?t/n뿜^-b7by򔙦ʯr|Gt%~_ӿ?wǸ|oZo{;W[ܥs9Y?/C |)pWg4cB Nv};޹ N55k 8lѪnYz㋋Бn8LűA (Uj7Ɓfld_1q:&-~S004=Wo]P޻e]1 {r[o SN-oPg,/rpW; F 91TMwJ|V;`jA§ϠIhtgRÒC?zciQ] a`Rq P"zkD.@* .sлV$SKă<‹qSOk!t(E_<_{ s(&״sBїj]]c DЮy6/rwhzj(k_qckW{%=-ɞ ?(ql}[R}M-3Ԃ!,5D 6M= p.Jw6hwiz˙o kĈ_#nǍ_e90r_3g3bXV-'x( nj5Enk6MDYq`eJd@V_qW ԲMUrjh/nyY\K;xunD"csqh=?;#b$!>j\-76 Ǭ xChK\czHg%=A]>svw"mJ s 1=t>5!s/-[Ò4jRYɘ8Df~nx{)+ojbڜjB ޭ'Ȝ(LԔn%*-{zRuALzOx)p?– Y%"篼/bj;Cqט{.638<@ K V#aVY-זh{ ereHɦ7^nZ%i +ip _xyu=AiA.(^{>TViPPcBiuZȍ['BbIgK8Gː ʺn xtQ4vK-]r1uAb 1Z或^>Q=X(W@TހKfޢУ&aKrྼזqگF$~;+<57~,)K0'ROdIQWgҒ3~sӒ(M?KZIKRs=I*Z~K*QA һ>ӯ|SJ{ݨ&w[ zP{lI$FKo `b˄c,YZ :D-l5]U<-@-Z AYYR P%HR`S8Y[;5/SNM{@-{GF.P| FA0+I-}[ù  ȓ[J$- AcR<,$) T{`7~bﺷ4$^S5{qCA*|ɛЦ@(_׮# ?8p`%1b[B(=2=ҽB}Hآ(f(0PfS!,^W|M^ZDiHϬ$E>\$.g7lYMD9g-6vF1j"ڲ.5W=sQCjF4,D{_rK٠)%q%Cې^ΏO˰aw#e4XeaZ՜ )=no_\!.MV  DޯwiѤmx(}'tuhrK@_Ek)1CLABl[G9,RO4Px1,pZM^H0g^꛹BW)xP-=%ՁO;sUoأvub̟[\UX-v#KrL׵[@Öa!vR-Q]LHu-ez c7Bw>" eIu 7V7߻#gt)v[4[+[59季V&Uc6Tu}U5 ri$uY DGLD!$Kإk~҇14e T]2BA`:b.cDl,,O$?B--瑩tAjouU@@k % Ht8odoRHZ4 ]kh #i"cIԀ8BQir#`h!2G{#HXjM2-. 1%Q~Ym!1 ,C0?D; : "Uq|@-(Z "] pDg,HV%D=FɘqP5 Ҵ#(e"Q$~HnTkA$ ݝAat4Dh?\66DëL(wjQ!VH-Q]j"-S-C6,>OH nb)85#l3in]슽ck2tiJ!HN~, 6F<$ʗ<2C Q$;c˰onIop7/!Ɛ_k0=DĐ>Z !uҮn1a4F,Aw}z{i~U]؋ꥯBY_aEwna/@c 94"eIgNZd;!A>i:?XďڧQ<6ݏ{y?H\*o(=3-l`*٧F ]~a,=n]|2H6KB -8J@- qi"%є[#W` ŨQ=n۾_^6<m(N.FGYcA$'VHge}vj⽁ P_DmfDr[sA$꯫x+ei@(Rfasͤw ?"{C c64;"1>c@EaQ!(呇1I"OA$'zG"5EqK|5nN{5Ƒ~S#ъ GsƑ]lS$qk#>[̔#ъGz\6ݒR>BIfDX| $um^RHDZ8DĖHe!Bs6~n"[ZZH"v}GTHZ.`fEv>.9 Dn+Ht?"; ]9Ds]/cH#:Jp6!=Z;?~4NI/#H;>We!v˞wc{֣!! qY3#CH~G-SĞttː\D6 12dA&!.f$ݪ߽zeiIA(^TF0-N(a :e ׬}qY{BIAskȒp_cQ-.HכGF?tY14Hl1nE˞Ywqv jHi #)M.{xUCZZ!!!k#9pWB_v} iI>2Tm''[VW>ʁz:T3DYb[bIHuHy762ޛ-'!2BqrY<">Ədj3|d3RG]> ,%䡔 r {sEWÐSU˭@xcH_ GV_Y9kz`Þ ]0C` kocKlzg6]MfDӇbp}BrzvgBQe;L)iWEU=~4Gq ߸ !;GMOՍEnMl=%y4(n5ؕp);r.]TM$:bGQtƎvؕa6 CEw} ]Tg! ?G pghJU /;Fl:cGM&k0wδ }>w$%:@SsM ^Lpt ^p8zBX2!tDEc#Db93Եk^HZ \h;HS{Lӓ֐{IxA D+ $FFWul6j<GzB:HSB}Q Y7#6ܪ[AKv! Ƒ4!3f tZCg-Czniu# mU#aMi-`UvuDW߰R"됝KSvm>Hns=5zЛL؛Hm %;>|6Ģf$7MgBwYŅ9Cn@6 yZzSZEգ3c$Qv9:#IխvFI ̈#%-yצ(!Lwy||?/;/34?'cIM%#T,[50&ї0mSuh5X5-6hDƒd78ہJnScP'_t?^XR$qͰhc(JїyZKt@RsFVIJi\2vdݖtO٥sI 0d}kh䖲#Wr7=H^r1$("MQ$y,0Ruҏ~؏5"I .ҒdbNl !5-dZ!|8!$hv v S1TZ Wj3B0O.}7_ 㒯uFOcbvGP0B9lQ*>,!`"T%"FLc˿y罸kZ K6L-i~")XeC9(Q${j$?\|=:Okq$l`FR0O';ӽ34-9! `}6cHD чRg;HTG0D;]( uƐ45B[60D%^}#z0䈺fCHN]nYRcHtCb:RZ7{:HӉU3dwjq}:3dFA$ ͑(MvkOsSwfj@IcH-!Y]5Χلpna~KA/H)` - !-iuB+AB ijAu>zRu~ U]" R|f*bAo'4 15"HfAR*cH y9?MTZ58'諆]A,Ue__3䪀Nzhڌ uo:A#D1ئABn ngKwHP-JÇ5wA0GռI4K!5GUF~6G}ԎQu5J‡^}*33D39$dҭqAZ+\q^BkE XGxDBNktgɮ$5\Ÿ/mh ׆CiPYҲX}ƭBgAB\GGq0hURԮ*,n+$yB4@^K[@@9@zԂAINнAOg&v޼cbOQzk:Gt/yk^4n_rQE舙tmYe:.<2E=6=&7rK1p458j_#n 4" ]_o}\Q8BVø[V'7z3ltuX3Y"3-q9Vq;VRװ``[ ݲO /i w9Z>Rm*Z~\\8b6^}E(߶Ug+NNhhfX3 O0x^ο׉ЉSu ujmuV=Lu2:[v `TaWux3vDԙmvxcmLY}J*:ED kֿZtQz:PgUyPO%ڀ&}:9u:?  uVs":С/0@KQ'X1* F~` PΦ{ݹpO{T#lՋǬyWdczeu8'YM֡ZRQ:%~R3utuv":n@u>~#JZ3lG-Pb]_`{Td.CD` ׯӝpu۵D\9\}IjCsru8?}|4G~|eV85PWRcuVu`uYy1"0Fd9CA LPz:32JYg5kA`ˍwP@` eU_FHw2vh[a %htu FvLց$5FG~| `Lsu`q]Iz4G~':XȿX;'Yb\X4u(4Mё#"W *5'"G>ZTX8"?JYNu0'4iu}`90:Ҫr0X;:[|أ`j8:+=`cydC\ 3WL.\n-tϗ$?\\ny  pQd0JG}zpeRLq\Gjp;|(GX,u{ Q_)!Y8:P# 1\ M3.:ƺguxׁG Gpu33\u5w`| סJuj+\{:PLסl1]g(ucf@4d.2:3\վp_ bsڷ峔ju F' ѕj~1\y!9PC:}u|u˿WRI53`o 󡹙#-`:joDO:dܢ@"|&pC1GddG:{*ՠ3/$Aց3ؔpj!p;7GGezÈeλ %dsl,LՁLU6:x5:NѢaՁJd :*} :F u` 6LuxcXg>JFΫ&WF/lay4= EՁf:EíN ա"*Wg_Ekfo4\{[&\>J7WGN-0|k:C{]`XQ;v'ȱ7XZQ@Pw@`~r ֡^XGKS L5WQipu&\nQQaum>y`I9L(bõ J/aE宙:fUSvK@egXlO-Ru~Ŝe0Cbz`yc:PLeUV_pu`d%:4DXgFAu9Cy%:ZǥZGi?:ThWDuwֹ [B1IǮP&[[tT7˹:uēYzu(G ۩v$ub8A0&}9:k6C=Q1Y3F`u6"j1YOD֙0:XP-"gmD֡}% Aց:G  D׻ʯ ֡Bա:`suQ:¿Wc:{t]kkO*3W獝W'^b$_, cu8*pa,StT GE(7GQ`աG4au tRƒ8:`B}A^_\ y\ִ x:#u`7`J{u81:r!WM-c`W0X^q l5>dssKpGdi5jNXW@{h6X(Ձ#1WcÉb:}pfd`uҘE7X>JB`uH_#OVn|:ox4:\3?|L^pu \աy"$9@Ga@&(:E_b<["!Cͺ`3֑03IG^$?lLCa~u0vpsp;:0D:pe؂."6\2P P1Fp: C$}Gt>r8%x;Ϧ:tO8pC=Yf:oFu(xCo&2wL9ީ먷iG\&؋.|H u=ڿyc {t{u 0x*q :1c#"f:Da4KgYu$:\3fp٢뼾٠|LRuLh0]c9C{|u8V:ooCG喩|0aNN[u꾄l)'j[Wa[xă-! 22PFpU s2[G95ؑCm:XZ !d4۴i+K=&鈭"U(:e[Bیu­^K":xq@fZu^IuNuK סרARftN ·x 5Ĺ@vDיLʩ9I7: Ӥ(O2^mt35)!Cu0?:PZ@ICx=n\g:d"up[cta/XO1YgvfZu{a۠9´ Ϋa-%au: =@#"#kZp#]OHBau" aUi:X:T)Q1ܺe`\'SuhG}Ly;T8,$I_TuuAy8Su8ɫ;rеP>:8#·X'V X'FT]dkx rpu ?rW,ЍՁ(M*:^`y<:KT'U̜DXx::T"6˩Ln'1hi3DǮfZPuf_Uc-%T5Tq:PP|3r:~Pu8z:̨1Vj^`u0s$aPu!QꜜCyAՉįyb@u):HAY6*:PߌUUd( 0P?:C}Eա!8;ӡؑЖp 8 ZCQQ ]*4UGzYDyO}#>ܢ8.=ەP{0}DtSl@ Ph0=K%:,X ADu p` K:'u`v,:uo E:o=:ܻq;J&`W?ApG@i\Sc:0M2\ q2?p(]0wM8huhI?pz:+%QR&:'ufp:#m^uERJh yC:Ës2]8]z:'uf@]hȇsWgLAFD 4wLyvhxDؙBJ?E=a ;ʸ>ۅv&hZzRRh+`/& ,G{<;;'v"CvcySa ΜI5 Ďj(#v™{;0"$M>uOR f}v> ;bbccg99Ψؙ=afe~9ءd}T@)yc#ߣ^g9ޜ70(;o90;&1;t)h}EPwO340;"2f q>~bcĜ*=Ř׫p j`vN5 dk0Lx"OQK?_שÉCo=L9u @Hc<켊oPv_{dȏYN?ʐπ!;-<2$\aNnafd'!;" ;glsca©gcEƘ}0;=Mȩ8#1f]չNeA5.\ [Z)@;/l#H;Ȥܛ7a7H;ow9cfAv \um&B Cy dCAN9&|^imniK_λnWWH;*㪏'&v?J8ف-8fr>F9[qiiӇ|N|^Qh ޷ϫ>Hݰob[z.|tӿ_gwdz+$'u"'b{ifpq)_.6d PJ/QՋ)o_ oJ'6ܔq&ѭn93.* qW;ĉ̲5yZ0hH#}"}>EF`;1[_JprM(g9r j3 s(Ds52 $YI!ydHcq9wdVnMqkQI͊܈IbpG8" ϙҏȓy3端U̶R ιc}n3|jn8A8w֕2wpnƝѰy.X{)wdN|rӍ'v<9 dd*z^)KػQc&3('{Lxu=Rn#Չ-EC_x; D0/0eRBVI.#S^2tPmSliџ~\?<w-E<&[ ad:d$ Qʶh[*&CcAbd k{\UL"Q<,H&o">i2({OxlWUǷv>%IAf*SF*Ǔ\Lwڰ,$T#IgRSSw! mlPQ]Axh]$e4=&.>M4INʞ|&#={c1A7q݊]SIaOO&֟g+[RēInD8krVx) 830Z ]8Ψ7. 98$&:CDt]z$Y3ƴalLyNd=ўT-x䍞t6C MhUph$bf;Щd=eX`. egЕH"NO]m):.vQ:pe)Ӟ VyLR#h?Ǔna]DeK&A#UӦFwɈMA5)5}v0Z|YF6l.of&Ķ2p=o:y(cTwtW hq'9ӕoOt'pyb4Di>t{cyWO[+,p3Nl$)~_ dUԡdh H'{<-'֐f؂W])Ps e4V<#13V8d&ä5:Σ41wqk/PayUB xt`,o9YHzLGA2Bv)MbσA}cB33"*7[r }/=u[F(`0ʳrf൘2/\'8Me;Oa<4V 1^J%t'3j(d2sRN5&Zc`.Z4y[HHwSebEi]8t ?e05^'+,6G-Cm{ܶU;:`xVcXv NL7%jN8Xؿ;F)փu<&R&';:FGTmS2 Ҿك #GpyFgFDwf8 AAy% Rd$$aMk:bH5pSb=QZND3߉hm="{DW5\H"i鷕u*MMك| nkSLUզl%DA2WrIdm8MA2qۢ7Ж<¾jJ&7斈P5f*waM5*C sH{C6 .=\&o]dҙūnMTָ rՉT@ cxxI;a*\m&P%R=|Р059Ȅ5D OMar W4=4&@>^͔Ǔa!,eSI'9!FKՏ)s9.p0LNBفK w}GhY=y/Aҷe<8.gQHȻ@p2ߊ<0\W)Uo .PPEƃF+0CP#Ψ{X[ꊹdK׏^<O@+=njWv$j7O$EZyJpQWWQ}LsxJb#\tĶgǥܷF`#uǘ  d,8)x ׶_<=Q_0E(096VMx떐a;<.Z| Ok+&k_W>)A'aI".KS 9Z54>#(l9@Xُ^X XMGϹfD/ tuSᮭݞQ@xdm11Fb{ֿ'em-yxZ6E,oȑbگ#%Lwŕa drxZԢBd 2}7=z-]pXÎ+f7PPi"3?[:G5y*eA3}j=0vb_4=7SqL(e5%cLՊc_ұʿZI0I`8PZb1Q rǟQUzY}Z>&'LQ F(D ]=d?`[uz/旁4Ć1Ŵ&kaZ"z hlV1MS,4~ wMBzwOdn!Dl h?6E&ԂvE:2?TfMU{w+$#M-T$_tlstWVjUc5yxD{Ҍ/iygSMǶPDsHMQ2uBP#aSJ.ī{X*U=yP% i[ G"w~o1bAn08 9?j8i[Vdy\%7Mi5e~l::LA?0Ly,OT>2DA0);L2ǨڢS.gDr~LT%ymYosUu$yL=/aP/.KhWܞGĢ;3٩p/*W<. l*L 8&;V:+@$U1bӔGY3kE˜\8犃9Kل? *2StQV҇q(IUW2dg9$bcvN%xbO*"sn+"3y Η*gL2[>.F趽̔ƺԧ"مQ+j&b~$ʌyLo*DKQCb((q<#*)Cاu*/&PI g|.Ijg=RζV @ã=S5ru(cOGsc_sɔ 7-M9AU%NfdLρB6ZN&_bZ#<M5n` /)YFj>M\YP+}Pz(DTb7īi9-q~LrXGn"b2LwP*ɐg4xd(I~VKYxg?؂hCtyRκ>6VS>y8Զ=h(8Z&,8,!ifSاAdG TS1ل+֔̊:OfBS%cR-p6u :L!a ]r,Bq&dS ʢ%VQh=#0Jb2e,&j ӫ,}LS@#LNh21@Y2Sdzģm]P0Uhc}py~M^ቌnѣBWl#M~bBQjWst;E֑'n{'/Vx1GH8UW|lk ղV˱h)Ji[D;)Ok59 %M((5W u/gq-Oo?] di_Not7]Y.ؚVd` ?w?]g5tz?v쭿_J˕n%qc?hvюROi2^OWvQ_ ~{8ogJO<_a7yJX_-y}{x|s 4['_Ԛoy[nHֶ@N|Tg\G|1} rLG폢:G:!FGK)oApd?UȖC> 8 SQJP#}D@ _BFqO-`~9GV^YhmD%m2 -98A:];-pb mvגwyJ v^󮁼e~bpaCEs 57a+. W<#LӰ6` HE#ƈWSz} r?fK$q #;esXCXYBWU{zSEW (DBc : j$k&G9uF#Ȏu81+/-G u{V3BUW(^\|{=2 iZ]nښUON8sbFG {H$적A))C GrFJȊŶd~[]\\gІ#O%Фc`SF6.L(IH:"(ؠ'y#]E1½_{K/#iA``d/R}(&e]x H^ /sUU: D4Tr#Q t$:GjdR ttt3q~̬oU% Q_BGژ=e Dp8f=yP4Hv > QPW OL#+ǶjH0b<Ȥ$c@܊ΘzM<G|kAeh4R} iVx#a^9$ +O!wWjqҷG$&ʞ G_zλhFc {,3~kߋ3{-"^`Ӫ=+x۫TaٌZ2F&'rhR T40ʑ>}K/iv-#hik$k$4Jg"Z^5FJCq\=MI{x\% dcKu?F/UbDN_jdP>Rw |T $,sAAtRE"HB5TkR# [SjstJ߻ FL4dz b}JؗHbu3(.[C=FA9gSkQיY`oNA M E晆Hy?Ҥ]\ODx=\:yܦ{KL*3dM Gn|f{u KuxhL?ڤ%G: qxO&QR,ie[EA1UفLoy ߟa`A%ckW\Z;cf  CbDWFG,&}i/:+EJ}Iӻ HAj`jFh'#2^i#94i#Mq,KdD?I?e,YDO3-,iO{95-M\#+.Bp)8%g^M<!>[.F:uȔҔ6DUoOBP&wD eJ1OGёԚ#| })9)"QŶ'ڤ!{Ṋ~vD*Ddzfi,TwJ:2ў#i=NeJz׀ ڥKEgZ"' /zAiŒi BՊ_PaXI}}r,U›U)OIݵjq,'댸qɟՊ^4,^4e!ˆF8 tB{X]:gI V5:F KQ(3Ԓt/"cH{zM9aL)Khe$5euzgf=ca[p1@@cYSg${"T_q.="BK*`[4"U  SktW,TT=Ҥ=@6F}HMхsة"3 n4s0SE[FpR 8rGje З  SKCr]g)4#UfZXK{ 9|nggȡ0Ѐ2EY+ȡU3S+l$|=ĒCujwo@lhW-Mq /@<`% ,s}Ӡb3IwS2#9G p,="w,#MY#SRSK4IvQJh{D#SONp7]NPE^Sor' sa[- [y*3vڮlCHj`I,(]ሼ d#(nyɛp}{DLf.64U7B33'GX,5hE-$ls?4 wcG]ב H3NE|o'7YGNGki Ng8y 0c<7aUsH #"iJVx"JjHF4 ]Kx=IOᤢ'D8iF"ihMV/N@<3ĸQ]F06HEt1k;D@韤HM{b #vxbD^ONQ8S;E`xP#Kn<@q_nֈ9-DϘhx] "a>9ґV HURRX #Ii+Al457$#uG9"/u8CUS, 8W$@1ReJw50޻/r#o4=^RB+F*1Z0 8gtei. jd, #%i2F [Ms1 G>eF3_rR9 GK,i3㭆_zrAOuIȬ2&O~|6e4=ad1u,I{aasBg4$jyq)J HߧR'j\\@fg俧4 gߤ_s_JK 020.xHđ<[0ą(B) $Ѷ wga IeUAtG78xOa)KgNa0Je0I6cII'Té #%t\*7N"Ѥƒ"ogZ〈9%XMRz~e+ OWz Iy_~a0)KǷQz>Tx.)*&x,y Hidka$|R #I!A$ȡPa iMGp84 $ٙJ+($TI|DxVFv^wDNS]< o1$mz|GD ƒvy|&W~0ѹPf\!Shbq$ZǷ\L5fa4#ݼ0T?~ᤈĀڌ&QhRJ2ɚ #r+ &IhR$hR{{eT ]f*;IȒ[jURv>̊-!W (5"I:ja%XEAaDްe2s"Ɠ`upFR:-tJHI"Y D}NG+>P:dH@[a0#TxSMSDA)cD=SA4s0*-2Uʇl* &%]=FHuiuEJ_rYuA@R",2%N0yI\IR^SrEkt37Va,IKSVx"#XI*YULk_t IBa )#J)($3045$({$Ģ 4Q+`k oB`RZj &%Z єYTRZF#>3dJ4, )1(E͘F.>9$`3!Ɍ wc8) #1#"% 9CV9%G+E2oA,A4||lm)Z %L{ď?[a0TaM,Xc Hw4|PRWJ =_,UZ{9?9t \2"F:WwR:Lz{4ƒ4 %WX0Ĥ3CI< kHTqh3HRh#s#C"7I\sMx|) $0b$ HԕaH2.ǝpjo(a(I#aHb1SZT秅wM:k\ X˻TK 'r1J*oPR֩+C;N9 ^H$s<2N#LA)%"k^^uC"VOI! ʁ`l`RtLqducO(̉ܣpgѤŮ$YzVNZ2Ye^|W'ᤨZ1VOzS]x#>3"i,T'mbƓ+PP•(ҡxRls!$w9P wE^WZa<۩k$ '0j'y Å]ˆREC) #JouHd@)qSYP*rS倀Dk*կURӷ$PRu'~)7aO [qGnq2Xf<&+V8/~DD}o #J[c"əJrJ5@bc1m+'>BƓXQE'I*ΉJxDa@}VPJ,Jz-dƓM!)Od}0T˥>!#I\ ILo/'[ȸq=9Iި*;%2&8΄LRmN 95k2r&1`$)T띢W "IHGP$$,#IoL3W`avG0' $Ƒ/#1FF")0% HMHq˿s#(I]̖32SPQ"`S8O|H_>WOo{Z\g O?C!7_O^̝z/T9k_k8'NyNa`0{G<"vrIILFt\`K0sχWGpIv N3aMW 0W/|Ke?U4vH;%( ~Rv2_P;`j|p<)ngt˯sY;3.bDk'8J/kx% \ N\8X;+#j'tH5bJKv.x(zW>W N)-u@]18b$>^'lыׁ@o KudDxƁ N#>y|D#>z:ت9X:)FR#w>a ΒqX0bD|b ]ONyutr*/]dPDɣ  >?turƾ: ]B;urOx:x=A N\K_)v:'h;4iau` 0\uN[ۥgF3y:yuINF>Tt׊=t ̇sׁ_#?> /t<;tlp]LN~{,N>!}!`/'CSZDE`G^|h-39rCw@`']ZaetNZOlA F~;zu;9E%$ a)]#((QuUta]OGC:~.^)| ^犺׹ΨtǏ^:׃ׁRe#N>֡B7l3z*[ʹ=ց׃#BXgΫʅX%Av:8ޕI:W`E9;r3^Tt:0K|Fp0Wȁp{@ou0wAIuuXSr$\J/u"Eֹ%@ղ>dWPr‡pq3lGh4z8sK}Gp{(!딴':(#>r8&):G!@ >;dʽdgD3B x Aց fOup*R;dO!:گCց8d|2/ZZp "8:%b)`J Lu&":E *&:z[Hz\7:X #=AAAցXaF`t/Rup1`b:` |{ux B}BlX0 Ϧ7'+uJ$K*Yz.Y>jk-0Aց47Ay^AցQAֹKցrh<"% 9r"PEUAlxå ,ݞ:q:4p;+\a_Nu[AHN.gBɷuro鏫VOO }|u`5r:X7 #&B.ir:¶/m`ux{}F1j89m݃)O ^u]2ZWvFSY18As )p*:k ֎:Hyp\'\gޅP4pD:N u =|B>x}:y i!_u:PUFy:*I#0AxJ^Bu| Z .!SPxؾxD^8Nׁ$ :όf<Q, y:|(|5FF  :5#D:xQ%sJs|M^ԡEux;@S N_: ZQ<^KWZ'e_4)7a투0uxsC1.up\i;sQ.[+9Gp낾p6;t]'_ߡ\ݥfu^ " 2Mu*^v߾uuwu F{sׁЛlȳB8yƇpj \eNJp:P$gsH9ׁNpx:/@u#su1ZГa@NupjΘy{9Nxj9\N> >u^VDu:Zu /xX:6^_.^9xu033^ f[n֡Gz:Xy Vɧunuo&:/ua|z`|ru 5uadEAޔ ;d,>dnDrw:t\ K():PybY0 (]7:pP~&:01YkR`u/VaupX|bs3/VJCt@tRp:7Obu0 NL $6J`upCHbu-΍[ yI8's/UQ~vo/$^߁`a@ud M@u?P6ȁH@BǯT.T.>Pk!T#1ꔢܵԁUaez)%.SL8f8iSTZ3Ts:0/Ufs\ʗso~0mEh-o/hCBur:|@3 ɷ@ur?iaL$ -ksàǗ+ϧ@u _Zˠܗs3/f8:П`|CɥoSj_:8@@ExE\2u^20ur:t鷂smɇw:8$SU0u`EIjN^wt:7QBunFPƾWAu0u:TLO@untBu T0N*Qgv:/p:Z&: >X)F]9:A\%HN>չhsݩ gg) ֡X.XZq&D%\!ƏYF.Z%0ya@V&:9Z:ރ֗h`y:7unFE`/hX5uC|E`gh uWoZ^FunEWbֹbǣssM.\'G -t]\$ӡ0=F?aPu7uRɧu`Xl8t[ou:Ya\a%eܜ&\anujj|k%qЌC'wO{:~x``/l6;lbw:~tyYun"ŅI8p[핋_[_u" sb.\z/\gw׹)_sT\i, uEU[_VEuPQt,)0s8/;u[u: Ab PtvT\wz::t*3סa-Jup/pSHpԜ !p!=AyɒCց8un|un%@>d5>S%q=AֹY9J{:,XCYrFAaB_un9%#a\DB<^҃ Up%.T/]@uR0vL@wDtU2 K>P"*ηT³<'%?Te+UZ]&0:/UѼ#ȂCOrPuU'_D8dNd58:/dNCֹ戬('V\K?8hz:/-:Xj H˿~ -#u(:3}6%yC:d~}J5g 7/l |L\Ӈ>> :Gu` 6sTSh?0<:#|;Ǔ񗷼ӧȧO;S3SsO}zOPC8ٻcկߟh|Kf {_K]$2g M vMYiRJ{9Ʈ3g?\CwOԽ >?4FVџW]vqu~Q[s6\Ezœma8I1( #}Iġ[WDZ:]nmX{D?{?TxfzB^&<7F"lpEX0a-w]PjI(ŠtLxs]2-XDInYj։ H>k[ϝj$ܢK`8-<"4"Q OA:xЯM=w5{ lE a T,{QYK;=k)xS,?y0cNX |>,WD-X<u,q7kSZajhհ] F1C~hϮB _ceqmfuފL6P9.q^3/p@B6ucNA\fkDP^ɢ 4t"9X@GD ,l|<!ic+[4Q$h摶#:W~xomkL:p41(es JJ1aZ$yI("Slj0dǣ"0Q82O)+"&[Zfb}lYdB%]AN\ < &kͲ4Sy#oiy[Gp ӳcPV Y&yIJIrRy^<5j{ zyW},_\&-7x" z4K#ye,3AJѠo{At!f0tZDNjُl!A38;XtLL `"V;#y7*oczԻ$hY]e#ٸtPg"F扜ݥO6rDGl{ȐHY7 0  d{N2mj-JaD.^M[InK1[ADz<4*ITƧZ&`2ݒ)XA7f*.{D&zqy;L{lN=Ry, E(RjrKb1ȱռ M2Bh^\vDHcIO((6C@c!eHtKb2DeYs`Em#6Ix@=Q\a6=LPL60b17E:3^&#< @HIspoADݪKEd|`cdn6 [l U1ӻPT(p^@\65O*OK#oIg1>tW LVCةL\J]BLLw}h ͆hV>-⟢۴c1Uܸ8%VdO;ce?Ul6elG{ baD&A1[y*&cW +T`bys?SMPn{RPncO^0 2eF8U=<~#VieV/g{;L^?$2S<'B"i* S7mlʳ OKsۊcbV )2-06>L8g3B+52֪&/f3jjBب ;0kY$9=-[D+*rO]^<* nb栾{X>&9m{\(H#j gTavu.O :SS5 \&t^+ܷ SNE;ENxjKG@L]鶮' [8PCÛU mr(2|^pR~$bYJ>FZDz`CEʈڢ.m@6Qrjd՛K4,[>d%&AS.#-hk(&r/ 7Lh⌙b9Kȱ.NOֳ'P'5?o`¯pT:zY{j'\4󶒗ígE=Ԭ|D0=~HYԡ-!?nƙwa='<' nM-r=@S EcSis='dTu5f*&!YSdW%KMp,*^vξ .I+*dIٔlٱ"婶#+S1zAZ<*T|[PnPۄ>eSQ,rASË2"aC&/ .6Xli41s64pڇ+ hr&c{ =ٳ% ldqSlp&ƛ hfL[df0m2k;#wA3S7 }!{<jGabL̖aI.)o P&̞PYVfUΕGXᖑ3Թ:EfM Q?avjAѰ՜V?(&|1{Zah*V.AوBg?G{ &z5DLέ8L(ӞOjlNT.h3`B&өK<1SX|G i\ik jBTLlթ#X{̪nL&cЪ<)Xps6 :rr$r ] X1O4N \]n7dfVÑwQV35{I='k[/OSSjٶݪ V,u\۬FKv$H4ewvNep}Vmx*k,;Z Kn{4>q% LɧpTʋ W!yPBm(,YHڇH?FWDƄ'%1x,?&o %]S2L=Z;eqiW*cĪD?D lҕZUi6Qٞ{@Z?{L9o{({$?y.Cp5&A畩N98<[!;;&N^>aRI[P˒yQm6z2%O66qjmt @9W C3ck_2TQ247<tCr.ZyDԅ檭4tNO*˖=9Qك1D&u==]a"pQ 1š{tk-z0џW՝ݐ1XQ2IHD Ҍ]6R\U ]kqO!Tpvg9 "nœ̉П"Pl\ (rNB}^#19sm^EwH,l=wgdbfc??_&@ݳ̂[K{yGj߯8eOxk>/?\{|ExzOu\7]& ]y8G|)ٴ[\ p[[>3j3Go;sur3#OQ{A}Kо2>L\H(Ö́g?[~ =r6u<}kdǧ>bZR)z$[{tٍBk/ 'W) `:~[SV#kpendstream endobj 367 0 obj 88516 endobj 373 0 obj <> stream xLOOӯ`E03G٫zU*h⩷~ڞ]qF Rhf+f/ e[lVv36LXǠ`Z %^l6XX fjb0 gE ƧN4kcvAK70(2 n4X}F|BG[A,,ɤO'ON~{ 7'൲s'V)/Uv;Iag/ͩ)`'BHt!:mB "fB:/lc0}+( P ; 1 }AD!e X=MH,'oEm;<"d  (Od hMbt%Il=вciB9ǀ:bH1$E *=qRq8m]sbM!CDJ;tDF8I:~AJ=Nz`|inK(Am۬,JQl*Fi(Z;ݮZ$ )NPS2Nҷvvޢ&M2Y)PskzZB7l{ vI2uMXSӌgMJfNOFOVi(Sd˪()!c~#2`^̋v͏nn~d~D_}!Ks$d^fC0V6++n0Eo)x?f,ΐYAEX[ňʀ~$=#O-405֏?[ Ҋ± "EdpIfLaR"B7mi+<3`:l)t̡@܅.% ruJCji Z^fK@܋0ag*/ӥCyp,cvwJzΊL@ `@!l#sxoM[O"nUt$e͗ƳӣNr<3FbEEƴvq݀l7hoi18V75I.`ztAeZVJJseyZ} Vƙ霤CI/ щznU8R&9փ8`dO+d".i3G}ġr{Bhޔź;WJy6}pɳQ6Kŷ+whZ-~K[i0>ɛk/ڧZI~6"밪e7fſN@kjdH\v1ʓain=_FΪBEkd#^*%5؅X;լV99D$mܕ2K(+ZYU`EpeA355';95+7ƣNJX4+t4kA]Ďk pLg-ˎM/+xZDk vrKnܭWX o]3 h..nmB&ᄘ8Mj֐By)oi)7֠`rv 1%U] ;a;4Ɠ^E'J@4mJʸ=H\¦aDglu[ ;#VQw P+"Ùu0mRkYc]UUTO!Z4jrMEO3vīWm6 TeX` ȭlL˱>ЃUq$c!51?v1⾏)`> SRgUݔ"m2),We=R<!eJLv KU]Mf??Ja[TJ-` ,{B`)9fUˊs覿-YB {gWB/Z:Ȕ􃐜CJwI0@%KQf\6 VL۶"9`!)Zy!qH6G6*}fc eʔ[6|YZab>UnBS.]<ZY`0T3{d%VAX3,e2^gmQF Mo>^o&=Ӆ@S.DK4T?c]VO!߁ִ}A %Q (#%#:ȥ/"N%>1F7}~)gcmu;0|t3$QS) w҂tERcy _T-I0E3UT>}'臩 㼗lƬ^aTz/vϹ[$:BIgf;:qc,Iay4 $r $z(bD(0@X!R1#"TWpY7Bv w]^즰)!(SM{@hY"p%Z̃{U%:nqK1ۥ?N#kzP6V> I& 2BAf.je.S0 I QExG.ok .-i<$ K-39E8`A]1T!|t2' u]bTϯ_~h̐eD(1,^$yaȧ"k'y:n3jY@%m|6Us;%g(+߄(oV EƬ, .rDr{/8A:6#ɻtC;=0K "y :.GIG&-azP?!/Ru,?l|o<=Q~;Q6_436,[-bdX*ur=uwk-?A &5;\/^UMz$a/ &lbsb5KVVJ!Likï{0mx?"G.ώ]x^zhwenmQv?7m8wK){hI>ngmƯڐkvWm+8 o?p?ܘ Y{цgxS6W 7bkzoh Q(n{"@Pm$Qe01ƒorH!oD9OoP܆rHp m5Wm> qn(0j,6dsI}qԛ6'6+81L,a@UƇcŔm4fF|K0crmc/> S_c_nû0\۩:dyD;x6KOYƤ+mMz2:QL7}TK J;EHӀj*]?jU?}!?V'G~YRu^~kɷ8D@(b&<> s> stream x}[&q;G}^_FҔEYtX R,!;LzgVʪYBAm~y2O^o̽1]p7ܼ?_o|/?gH#T{7ڛborǛϿօK%{>ܙ`qۻW>RO4jM~CmJp-&[YSHB7}40f3ٔ?%G3| _x|Ot1<kٵB7Ww2=KJDv>oS+}wL}v4˫`a>nY$ -Z)6Mi,ϼ&{k-tM^i[-M o>G!HoBΙ_zڛ/Y~ͥF9nV&W3;ۻz_3Oɭ|ȵ:߯޽xZo")˟konoiʯ>ٯ'fM;(>>B]]`@$_bJHFi}ZddJ戒] a`ʜ=>$MFi9"]/BcD %Oh1r a#ZTwƈтi!~E5M ٷt%Ç-G ss&%[ F˙5<r"22yZZ* (JHFPB%%#S J8戒Z00e^,?$6{`6:Rz2/\zx_ me3[rb7JURaHa`v}]OCLuG=+BOAW=]i^\@!/&cP/\C|IsKyaA^MfW- LGyn,y|ް-}BH@ȋ  2A-ByeP> Kyϫ2ܒ_jZWa[- 8+%[OLni@[y{y}ylܒG#V ȫNs:*ա^]s4571NE2|Ys,1^X]r_+<' dG )ty#pyYpyG$PcIԙO:Lu nA]9un(OltyQ!FPgF6+ Ϲ-hpyc•KkP'qty^8GPg+ <[r,r <|+kUd32J8 Dyyqy~jA^[:PZ&"J 2 0<+:nNp3CHW\Y$ ˳<# pym.VҬdSi"!y@^Eh8H;NL'vyl< fv l= Wd3d3ja^Z&tyC{, ^a2fU@.n+#\üla9Kd+],Vjρ<汎-L6/V#?Mo I'Ce+y$2wyflFdSB8$2Af"Ӻl6w&+emL,y,iq60'/>J*̳fy)E>7|F@f e7aR~yț9YJ%uKyp؉=306@7m <$XJ"Rf·^}^X}qTls+!Z.>Ob6d0Ϣ` lպ20ύ \*zAި <&<Zy<),l3[7K kXKit ]Hzqk H0JW)3 ࢇ:< 3ϼJ@My)f'~Y7!8kpesu&iwH"by5? p$ 8O;D8UX"*n DsEgA)%sȢH DN\]K*H2 8IfYIfJ2F2s3ywu,V꾸 (.W:Ԫ$\6eElRB7T+MRɯPl1Fɾ (Etq J(CYHRvF\ZĒ+bkq Hu@)&x@@)XP^BȔ0Y5.JծEPLI[wŔeX&˗-S2]Q`Kd%wy wټ.s2I߃.[>{w{^/Hk^رSl9O7׷{=zI?ub㽍W߿?x-o?͛~?t/?ڿzq+qs ?ٱ>MWb@uGSB2ƣ))Rx)5GT6%%O$~>hG>]gttnZgz>eZ.y< smMJJA]JJAmJJ5B}JJuBSJB_it|ԥ/ɗH]h"s"T5sFvӰޝ6b6gX{F阅FIGoYR99TRTc2(Ir#B3;  7K@Ev`ġ0Dw<;J:_:$E@չeNWډMN厈7獍rg;1]"Y c)]טz?6zabN8'0];62L3D>.>Km}(< u8 &N!%fe]uJ/g |:K@]Kiԥ@v.huɎ..ALb:fvefZbF#@]TPO-PUQ-c.D<"Pǩ 礄A`NޠN6uWd'-c\P'uFŮM@ԟ:NdP']g9/P7 ])u;rAJ-?+8Q7|Dd uy`C4ƀ:tMQ`π:h& x!> iF~Y݀YDn0v^\8`Ƌу\ m1a)5ZxqnfTos+5a3tLEfatL%]̯0KfX`V6 :7iT0-F',Wx<\fX 2:FG,f9003 22: faбxf ӹ U0 +aVg~w{#< 8HT ?ʠ'ӽJtiw%aSpӨ NVQM,hob5.dJNTp'FAp7Jw{} f7q7&&jeTEw[qW 8$ܛ{w &AD[ZqNܵN wy'誘oCVQnTw?ScRO3%~Y+K>sw|+ ;!gDD Df+]zF`h;"$i̎;A=-xqm tI 6.Z:V㎹D}˂;5~Ƅk{|3Kf3{l4͊81Qt}̚j}.]xfZC>) 5y&tȷKwh:3'! U ̲Z\Ljɣsif# Lt;d刺{'<י<3B|~`(ZlCw5H4NzN ׎<9 c:žGA^ng!"Ls"/bW#j 6.ʁdG&6zZQ_("> ;cK"~uu/C*ӀMT@8rH #?ƈ=534ε BM{dpDS(fvRERkP 1'QsT>sfVCfdG؞U8Bpjt́b/.HxN虮ZMiuʟ1%; q'wRylܵwftM;%Cah |N/;ܵ;ܵW҂; ; mwV ͇yHF-sn4wܵI+Nr'L;;9]`ήb ݷQ)& ;[4MG?:7Np`BQ7F$411 Flx{MaĹCNYC qt0:`LHgLQIz8LkCnFrF4|#,0ZÈb/p|,8[E_oFmw?|Dp}x(L7̤0 <է??1͜/Z`j8a+"8iacz4Qx1!I< 6E xC3B<( 8חRgu<~!nSJn,傻tx`C@,&4;c:3-a˴B73- |@bo4B Xqxbѣ#g~ϴXIّwWD8< =8Hn_p;yiٙª" w[E|sHćM">tw* Q婈K]i]Nbti[en!^p;Z)Nph; 63Xˑ,Zwŕhʎԙi휙И2wlf!J]pω;lIvDU.]*‹ȣt']wnƁqbV;~;w1"g>p.Ⳓw}F@q$4;xʂՂgݙS6+DbM^Ny#)o>g <Gxi'5S #ʼn\83JSpxJ212gIxLK6$~fi9ϣl#l=FY#<$fizqx&l3zÃץMٚ8S`윞/txcvxDpWPxiMiB7q7[gf% ghKٰ;<J q+UdV8fg$-ǂn9*HFϬt}ȁsḇ'{-fe&PcNɱ`ḵ^ݫfP/>kvׇS+TTpRb=`9ܜzįI\ P|XjjcRY]LKګ n=N9 NUTzI*}I__9^t~l,C+k]ϣ/ [vS2JYNM䥺[N= y fFU`FfOi`< 6 H/z߲\yJ=@:#(<`H=xԲ< ̘ў[Y!EV#/I8DLJّ"TC^Jy%. O) /'NΎ,/VGD~g.&&&'g& d.r9\7BS vvISN-o)ySn~͏?j|W|I̭q7!+ϗ7hǷ_}O8r{+g2z[3䶓G ɈJ()QR%'()RWeJ%TR22NO`Ƚ݃?H! nBcD (#Zse#Zπ4ƈ<1x_WZ.7F^aϚ6bJt["v|9F 9"iYi9Ⱥ my/Sm|P)$#J T; NY3>>kZ,FQ%B;e`E"-RqmD)[$BO"zE0(ɽZZJ jk*1;AJC J `X gy/'299?2!0E|tw \\>}p"9ȈT?jv/Ň-.}F=_X RhlƓGӇ.E lB-ϻxvfJ K۵Yqmcj8Ҟ ,WFn"A eeXC,rH9q@4giߞdӅr~]Oz~/h~}W3qTϖ݌GKX o4 xܚ!cq~6hJ$1{\_מ0j*=w;4י$-N !)heO /\aOn.|a'*uSK4ogs]ǧPBKCUJs7оox ^sQ[%"Qtj +{f\:i~ ̸?tLf>?z嫑#͔{F^OF>1~8s4# >#?xӃTzEeHeDQ)%e00e (nMZJ&>-'h3W60dƳM L<Ȁ6e0dƳM |,sc|3mgi=,>Փig?K[Z|{R"*ǷBHoOADtDTvoOADTDTf H$$%$$$?NF($(ȽX{<'"[t#Hl_O2ԋ1#}ꩄx~ޜЗµ`^ht.z=)ԸXOpL@s'Y/MO]P`C'%M'IfBc[~:oOf[r:߇dxOinŶy& ]*7 cRֲڵ0d62=4e2ŻΓvQYNM{#PYn$]t^V'8h??<7wx*3"uGjbGp^Ǵ9rzqDo/=9 >~r=? EvɻLݚ #J]Z=爒έsDIef"%#J(脠 8Ek,Z9îNiŚq<_N(7xU>!Ĝ:j=XEE|%"خd&UۣNI.yer/Jp :,j<_Gsys'CSλųy&󑲙Oiyj Me~8wކMTxaU|o-oQ9wK= /UԩZ*lV9['_9L=YeǽF9mde^:}ԕ>ܓWx+G,(2O*S#K8_z*l:_w޲xCqz%17'8gqf pgi#iyz+w_&ʭCQ9Nʝ2!54+yWӾo9 k}Q)W{GLD/`^O-s~#I]>g_3QhʽgZ>c}YɎ[k4Wwm$זF];x.cL(m4>Qdžz{L3^3@ n/nKߩ_޽%5YldIp^GݫvDI͕W]O0Hҵ5{?@v{/IKU hz"OG{x0ɓ6Ÿ#>[G ӭ<'}ld"nQ]2VM}EUt2m]KޓX,s}r_͛|=fnqygU%O҂9ZkV'`)U-.8M-Dyߞ#mMJKhenks}m߰Rѽq^u`,]X.g]129}qA;Th:I,ǜ=y蘠#[%6uz'a\$3faSҚMKn?fhLGښKd'639ͻ;A]N;=zC4S]Ec;$jct =k /tq\,esP+ C@$OWn*, +N,oNiƅ&Ld]YO+r@8zؚ7陠@ƻzPt#ݑS“{p;mՏKbm4WZV'6AQ1w׎?<@>MϏtVI seRxf5^ Tz[>>ˠyuJ;v-ҮWi*X]rʫ\xzmH•rwȬ w$`LJ,j74r⡔qpp>Dn WZ'}5wk%k&wC7Fa.P>^u/w0Z)4dLu%R] J7~nNHϕ_4v=E֔駦5[~QΔV}Bp_J٘M^@;ֆF< F ZxxSVd~Mf.3tC]4^7!~PsM!96dfQ^:I_. UT`,!9.lr{# }dLպ܌aޝ:&J2`{ m_[qFCn]ߊ W\eBl=Ufޣ{lMƟ--K0Tϯ?柯`SԘy-kZ=Bk e!'7s' $VR([!w".rd|n.>̩ XZyԝ7M"m#8HZ57WVrAw:M\0yIM. 1<mG~*N]>^2L+~;.l;FdTiǦU-zH͟gr2ٗ3`y#iMa$G4zn

    ~dUeU 'tI(әJ11I:vF$=[{ L4X)r*fzu{R][Ngꊿ=Vࣩ1 GSzWmn!8-_gJVtܜ ^6gT96UF2XĆ֖oYLJ&A'ѤdGh,Op1ބ͇iZ֒_PЇ V|Z)r;ji/"q1-\ 3QdYǴ1a^Ej+uO8:T] Vu5eaKn\;[ mP{: 4B HY'mβ[Yףz1],Ev?]: M /_}Y%~Cb߉g¤nћxew+/MTM N ujr¨2*AcQ$L\z9c`@E=|lxK%R%l4fi/%hsU"엸w-W-[46< }ǒNuX:%fOoHY%q,VE֯0U< K]Tp׎cZS#LU"egN7Wrhm3vZJ5s7?Z*4޴%` 7RP:ƮdMW2Khz|}_yn|K2w|u\ F I}|=?IvT6KnnV,X@ַx-x?3nڏkW}=Ss4skc.NH<ă Yrޫ}jtjt鮥9(Rծ:"6as|/iwOR+V]Pki\cֻ͵\I)Q98|XK-kj&[cvk+qݗ.+{UB+ 觻w{ϵXB^~Պ8yY4˒ѾJ$:ж6v;L<+l$f9SM]_w}/;PS>齙ʤuiZs^khl^S)$Ev+$YtZeUMY)#LJDN`ݬ$ /,tch_Ogprcǽ&:xC=5/w*eBMDq6 [R?tܘ%4N.B9Ç)֨Rj1=K.oýL΢t;w_mY 1k5IN1Dg7I?e"nWͳ,b>ٴ}K<ݿ?W_"$*Dv2wAm&\Q(F<?a^A-9oyi_KQP5U]Q&2XըZI'/nA׭%K CĸD۪RqL4fԺip/;KDrWYF;Vͭ;j=f\tUv\ Q^M1Sl~s^g `)m0|zdW57xikT,'ݸE M?;eZ#- -!=|U{ ~[8zvǜ^XfAhWBƶYԺyT 5_V ݾ+~8{sھNXw o^U}5O6EL^0^C;KZblmM{g`ҥ$v}Ca,}W,1CB5N$iFyb] 6:c܋;/Uqi-hܡ/nG%/gw ;|2fhoYhn ]tw_7+2yƤ[ X=O=?sR'H.:/dw 8ۘ8'ڐ7Թ *X p"}?jRߏ=ju_\6\:VJ,Y“Nj]KOhE 2kS/~6V6v!ArHb>>;etyJY ҭn?K{u1 &[+h0~%ˢY] T9:C4=. 6->Lg+U70$&Z%4hY@#S?6Ix`y{{%UѩGfƽ:~KӪ_q^9Rk`w2 ]wGyPS_ϣ%'$r>wCk})wK!2`Pپ*״9q޲;-ڐ;oӞs)_;wKBR}AQ3~Q7{  Eoc> stream x]KqC(¾Ł;zvt^lqX0 z磺*zv,T3_fej: +ϾtuϏ UW|-R_yGWsم'=v?dWh&z:O9{S i\g7Yc·4!y;ٜ+u6NiFƶ9{ݦĸa26QvS+J&l{:.N[[fi/=rmN)>>ya]{o]8移afJ0ko2,ޖln2̜jF'?\}}zqG]wKЛC2Iv6wx9\i59x-wGvCmq]֑v#MӲ&~`gm-ՉK'cXD.\R;54 \( E #n[EƤvy[ҔfYp0ou1'mri#"=\l;-oN]LZef9TOpT)KÜ;:V4*eMEYuQ?ItϐuLNQ~ yH&d t|KgL|'@сD'JPДa+I VlKt$v Ϩh<{:$0,鷲ϒG$P#.0E2nr N@X_ߴC{|;ߵǯwy:&fBڛsmT Vz0ᯇxQVv,ۚcQeJtX@K'_Ub4"HhMݜB  ~N2PM5]T F SmR̼a;" ~,i֡\Ce ٝQd,X2 ɛIYd7%^a&,hq\p rdeޙvBL PEn䴸}ۛw$8s`*5W2H-FPbлh@@漂<.gj3YAժ&{*Rz޳/zly|.J~ 4G~ Z)6LpPW2;CX$  ;.e{p 6tĽ}#xc \a[\YG6#o$h&yq)z,彚]eFI#&O-.\zD0X=:TCgJlҾdbZYmqCP6ž*Q0e Jzr;dv+d <_9.Nl7ifnx o_ !Qߌ'5Fīdߴ/.Bc&M=2Ly< T_:s GtȧN=:~][*K` -y[a̓ڄz"N77ϝ1M1oSa꽅FeiX|Hg@+i?+9\~~逓sTi!Qݗ f y^27͑GNԇ8mm% *7ayվyeCaHFKʟ$o"<<|Ƥ9! =^-&s?XZC<gE&kBg+P +DF V5ax@\TFͽB9vCta6 $W,lNlXɜgQԀ{d~~g)oV{ J6sh pKyEzG1cDl|r>6 -~%@/U}GnB#7%P% z^_ȴqdlez՜}ѕVB/Ƿ3̱I腜+3,M|ӿ1Sy0P GgDçNgj n =_]\]Fb!n}`NIME>YFϴonNA? 5=3g$_ W"=hxdvBbM9*X%=R_:Vj0 ĕds!)A`;ȗw0gy^\EFISQe2D T!`g&uyYðw0ZqhIs^9YK7:Q'oF S2Ij /5 &Y'x00/Eɧ&ʟ 'y~W~N14yI+œ:sѥB=WEuĹ׃xb "%_aA$н241jO+tDagD_k "A#Qby B6Z:UXRhXi: q)u-|Ѥ"i꜈+Ze))y9lX^爾sApDbLMP0fUΡ>UhNœҊEcH{\?h#BY]NkZ_ &_V o̹2&ۀve>r-0)DdK:nAsgm%Per#PF]^u4ކC#XwD}_a w wQvTDJkn*S]zߌ//Z;R&@x³Ɇm4 'b$/z߰qVDzzy^Sw@RBq'6"MGѺ"왧P=1QzÒy{ ib-4v`W(It0ŐV 2ypñ3iU9@A$PݗMCY%18i]]~Aj$^Fޘl|t62ͻ)K ?sW.]UdxfϲSG\ȓ{GnaȨ q 5GrfG1G|07d֙~4|*NmI{Y/kr{p!=%"n!:7¡g}C”]fUJ@.Sݩ7IUVM[PȪhZ5Bzi{ns6a3+ؒ\׺-Gb$aRmV$Iؒ' xy+&EKyB"t )leJyG8ۙczϔ kP*c˕//fStK̄{N/ yvcFPVY#&Y C94 %ox,2ZNXo!huP]ah#BQOTnKIBcwc ZK~!Zf\@6~9{m@WL2.JnLܳL[Fg]!|(Ngf+\$_PY0N6T# f뵹EV!u:g`my0EcrxƟKW9*!zrF7Jaq<"IHTM_#Ͻ@'] j6..}Ma_H㔒0A::SVgHS D0rxub'zMF3.]&A-10rcρI0eo%7CԹ"Kb庽A!zm=- T(mu _l%Ŕ/ΰjr F%Uɨt' l `$q"f&Zb]md"(_wAF)$r/sNnzA9 k9mcJSl02JLSn8+"E"Հz 8-SZu%F"'zHL[S>n#L)\@YNMWll&K.OsV`OɆ6s[|; JN\v^qqo*9z6s-ȟWWq"}+P \2R‚`Zs'ú_X9!eG_qL>T>ÿ,R=6 [Y*W~%6ɔZ0+W)c+n%+$*Mt b h)RYrE8EkBu3^6?Nzȋ'm(PtnKK, H.er&˺# v"rpxhlKIaP rq<Q}QJM#LMRFԘb&U&8$3 Z1md~`lT 3k[j,ܔ)ʹ*KJՑC-!6IXB rjIiPkHxq8k.LcBQ [ uOȖ׺ɮtD^']&|i@|+E0ꚩhgڅ :% t/x8iu 0t!O  dQأ :уB/x&x BAnCLM$$Qw>]f!: 'Hpug Tڠj[]8KnR^*q$V* @:P3Ţ?O(A< .^m YE$ZIXhKrLWjHd/jlfy;@K{QqdAX`ܩn^j7r/Aޞ : :h^Vm;e:J[]#rZd1y6 -G_V}1`{,Q\2cB Ð0g@?ԿBb2*>!NJB~URfu[:v'A'{p3ST E. vd4ZZ!찲LqGJF~<{g:5]X{\MC_13F{6`S^ɸ,PW!Lb _CTBdx՟SK?_rv@"`<1xRm:X3i:_'A8gOA-*}BUsv#膪rB]G˽͹ ͞w$yFRI BL9EG~y3\׻]@Q& s&JL;@N.1T۰,p#Z6 H4nՎ~̝a:g˹ZϥCs4EYF%k^DB Xx"EMsj< i*h=krڞVqY~Dk'.:p|ٕ=X}t]xŻvMeKTh\) wi5,7de!OA $~߁&3}0{<bRrapii.y DuQ>yKyrS$BBoó>֩E a! [fQO۸ȴUTfP/nkwra^::R皔s&}!j4u7Vꢏ&z/{M؆*uiYc*!;pDf#oQ%sb$!,95^2`RUh;yXz8,%vo -؀y)@U)Z%vU#yUBғƸVlQD%4, !դ EU^RBN폵7KZr5m"8KMʦm[OnUY"v=qL6K>aȇF4< 퍬iF~4S0Yp2*%T6ѷ8&9{SJ8>{:#Ce6-Az܍y>9 z R0/R@*NEJUqo.edk~tV<g9 {4("5AϸVIW\UM_[;/ JENWsx { S@=@B}a`JX[C-j.;Uoܺ@?$Ռ!}ѝq*K-4|._p/gA?>oCE҇ED_}17. ]Tc0A4CѺ.d_D?"ӗ+taJ %tQv*Y3|cO;~2TIN? O꺘@"ii:ci%ݧ_6:WƷ/1}ܸbϔ>H0b."O}.~xg ͕VYHn|U}d 1G?PTpdo_?▥ bY230zIU˖%QLe"RXLk<[\ma 1fcW^;U42ィ:,ʢm~0~4eG1wXÒHF޾;n;,.8ã)USendstream endobj 403 0 obj 8493 endobj 406 0 obj <> stream x[Ko3H- uI$PX`NR+"J-ߧ=ճ3K t`ꫪ滍o9;Q˓w'~ݔί7p7ޜ:O&Mqߜ] &lSYk |pvq|VvTbNV*;Gaؿ9)|4Zِ)2LQ[]ME+Z.'W\ v~> -l.w5066q甍r=>MRFnt,; *+|60wVv  $'4 aGQh_ f1vɏ'6΁n[*<ځڀF (ʛFdP)#O)OU(8Q4!y{ZWu|5oa2AݒDA7ptYDBVLRzf&8krBgbwW-[}ܛv͆冇xt?0cg室3hltYhyWbW{|eNhZ>;`rC 2~C3GϬvVIʀ me4OӗmY[&8fkϚ,CU>^/n㚭\ͦᾁipn7ѥěۼx#U v؁GK* g.W.6] 7 +'.z6 {¶L=XF8",$,~]$-d&j yQԠ`[. mYN}!";yϾ&|2sgYfLA%zKҜj!=U#V\[  v4[#aq:,km|ޙPÓG*gD"L(ˠ;|FVXH@83q4%aJ[ 18ͧ In4æכ*]6` (n}:Q,C6xt iIE hI .ÑN._B9rM^mvXʣ+ ,B\<5Q+I,0RY= 5WZyJW`5Q 9Gop^5\JC 9oK5tˀ^;z=ڛ(8SJo`ʖA[Bz8ЂI9Tƛ< $+|S[ K p1{sehd9;A s07'>G燰:dNK!϶6xͳ!r) .0 TP[-^Pzep9ĀJepE G1F㥏\ME#;XE nPLA!*ϭzf^fa#-tusa mKQź]P *[u59)v0EtDg3V33#cg.SC>D{&F^^UR)>rERHeu3:Q]'0.H(jYEtQ7R\d$ xG-x,"V^0ݟѭe}84E_V&+<Y,↰+gSjV47㬜C*]!8٥iT_Nʐ :ri/e$KĈUO/)į\^*<rF %>y}IMI)ynw%X%Ysmͪ,AɩŇP,RV 9Fxe@ . M=7N/9;G,Z]#ڷy˛eg}ev'?$t6ƀ1#)i2mBf"SOw goRT|&[BʷшfWy@HwrD*+Mvdw %e@~KE8eP34Jc3(r㇐69l|ČyT XI"_U0Mk,'2ZT{9CKQXZ~1!?P7.*Y,xG`EgiR|3A8PPS=K#P2!ؽl.:_)(uZWXv>/ƐZc̔tO5RYd̿bZa_=Ȋ1>m@:n_Р+ۿh@G~ldKV*=bQ(p a=o?۵dwC{|1v^RYou,JfHȆ}NkYp"¾Xv1gT`O!WyT%F"L-PjO:<zOp#E'IZQh@/r!g[$*#BDr `bћmm.t2s*#ݶZE6>e2FF uȫ`Km-rr4Vnxڲw@F{&({z6gI^'8)+)]ỵ+GjbY`oy瑯Ksb^0{וʎ ;u<=#xYw";j%WL6>5w'k y05veX${(HQ&}j|~<pSV8rTe >B홉.ˢ|OWzJpKp|9a> stream x[,Krw~w=جƛ˿?˿7s*8G/ٕB?~W6BUx^/?`_^SO͍ONՖ-_(as21_ ]#ʮvئ_jW=3oeΠ-__lͯ??:įX;J`뿦ڕll1m1_ݷ_CK)/㾾3єW_`ۊ)W2ZUMX1U`b:bV/YL'ZeQVgbyAY~L,[gPI]?(W*3k]X -^^I jCKzO;[58fhE%5&ϙB`@~>1B-%5ֺ]IYNRG"1(ԓ7:ӐDC tc4muֺ^)(Z.ՙt^2K@ɯx4G -u^ϽWdFyڔW3_g,_hZK_"T0C~劭Ī撔 -2Vgb5NYrI>;:~V[:cz Y"109XgFZ5zj'm1C uƪ)W:Z$:_%cYa]+WT!pSgbW#1Ceuֺ^Z"v T\TsRI36D*VcQVgb=9(ZЯIJ嬊 ,>c -fhaXμnRz -W+9p,fhմeuz_N[~jaEϏ\xU1mRVgbz -+W>Z$:U]fFֳ%S3=7L,S!%GNyWtJbF[yb2^Z8G,'"101Dk=;=-^ -:X7Y'^k -ތP@1Z N\\bVnJ7lh1C xƪ9*3ZަZz,fhaX5hH,'O8Xx21_G- -uocZY~>+VMa[f=ZЂ~ /bV>FΚ2hC uƲu̔zlq1_g,3+30,Ү(8;2;U'|C+''IC`{=`{ 3p~T8R Cr_/ ߟx DEQD`5c9wWpe3,XY^Lj -fhXiIaXF8Ffd/GVcmVgX~JY}vЂXWd$*V&rVVgrRm)\$k'8!bF#jL',fh)sƲq`SL4bUfMbF_U*.:cYŅ-C b_ >BX9X+hZة3eUZrjY*Z!pSg vsRZR%pfVM썶:kw> -fdٕL)&_h1C x > c1C&a*Y3_g8 3fz?+bx-C cc>O1YaXf%Qb$NY [rRڷcF -3V/Dgâ5@ kS:KZ_gRТXꀰ}|0#IfbY*3_g,;}Ebhɋ'>$ hVuUIYЪ]^YF Z:cՏ"109##3E[Y5bI3(BBZj*VeH "p01@bhDzhYcX~ L_Z" x#VͤjάH:':qc[! . r)_b~FY~*Z4#fhaspڥY݅Mb%tHh֬Y1_G,^Y"倪yxE׌,7aͤAyX^tl &VuLh1C 'UY ؞(Y(eBZد3V=X"3,5$NCybYY$3p|gu"1֯5ˍw"Uzҳb1C c鉯eO<#tEE%u֬Q~D1S?evN?0񥶡 XºQL,w 8.}猚 AF1!9V}Ǒ1CKMenhUπgb -fhINQVg͚Z:cQEs1=a!Z\*3,mZد3toi,3 -+!Ō *f풤mC u*$ib:C~[&|CKzzJ @b&;CQlU?ԔYfyZn'F -uNHf5r+?WY,bhaXąc1C b9yIDm+*}4-liV=1l VB{b`żЬZ^~:C+Vfbܟ2 uL>K1qWVgb2^Y%P͚5 "g,Y!XЂxŚhC uJaOXJ$άYJ:cQC'd}@0#+͕4k ղ@"v Tʨ戡gs~ǘ%8+88tԾmKВबz[b̪/lZ%ٜjǦCO@ڤXvY.Zة3ߕPEbha,q(31TVgbXЪcEYo,YNjLQ -#VEZ"109<12#+bmVs-fhQvʻjH -uz<&#X@R3$'s٬m)%oB"3ϊB-:cY\-CbslŹg[5i&Z`1C urZ$:7J \1BZwks.%wTAYKK:QEC ck?})֦tW -+XȪsdXBZد3V%"1sԷimbhۃYXϪbՙ,C xƊ\ [$:XVZ{0˺x $Br:jNB88#NZ=BZwiղ:cvH -uyN8nX~V -+*lZx,% H>R zܛΪ%$=EK1N3}=öT,ЂbbY3pXy,zb%bUOYkLZzԳ,fhuĚ!PЂX1\ffh3 nj*%pW\wxYВUǽ:kV/" 84QG ZڱZrY -bhaXnVXA,fhahߞ# Ёs]*U^+fͲ/vb:>SSOgPsF!I>䱹U%uֲ:cQE-C b_f[O}?3CkkNy3i&3beKOc1Ckqkz?״Zد37fdWRj;Z}:1v[6 s-;cH -u 0 f[ -+̢(lZdEi/bhyy]=yp#tM3-fdM{4kX¹:cQE-C cc,n-Ȍ8Ӭv,fhaXTA,Zs>?}Q!ߨZMlty9~j&y-fh 75kߦYD3pg,@,"z6[!p#*I"p(1M`5ˏ&:cɺYb+z?KbQEbd,^fͲ)E:bY^`ڎ,O&y4+Ɋ&~h)c9U?f-Q[hqX~ƒwYvBX뽕9aZ>+P\q1;BȆ[uZ'_q1yC 5CuIJnΏ]rP>vfhR^Yh1CWwYv׶ck\ -bhQX6DzYku͚mC ur{Z<&i_<$\Kv$fho|\81h|G0J035kvE -ޞ882k`ޙͤ5k--fhQYcmCxʣ c1C +֬Z~,XXf8LD -̢* -Hk,BZح3%NYb͚EUhC ur b1Cƨ/&109`VL뙖bbEOh1Cn)bbAYv.gYz}I:DbWYkD(jZ4sYgVrVgsYh1C uJK-C cGizXqzU/c9Fͤ2R $VTh1C x*nSЂXL0CKޒ,Zد3UZR뮤Zgqv}:YY!Bx(S{|ZZeH3i1j" gL,?VBZf3pX~UaX`ڋhfu3_g8*EbhA(11X‡brR w=v#QRgb^]3pXe0%5euz?bUh8x0Ye>BLv>/-G0ItԎQ3>(!q]M:PzX(88g nTsТON!rz.X˹XТs^"1(>dՃfhA&X>= -+ε 3YQ3_g8+EbhQ\:Lmf,ՙXyK -oޘF9Z1r\vX٫O1*&eu&3ʜb|ڊ'3`g*lZ}+V8FfdڬbeZ||H -Jl9ْiVzfb{nK3d(%5$ӥBx3L,7wFZ8Wg,?w ' *Ȃ/,3,xZ "͚Vc eֹQ1ij[%˒eu֬Z1WZ_DfhAs+j&%WΚ5W"EZد3b,fhu5k,BZد3Ha,fhII*<2`f&:c,$j#f!%7KVYIޓ{>Z+ŤRmR ,kHj&VLu@%/{eu֬QE1sUo c.cA,kb0!pB{Y(1C˵V: o[WXQ@¬o1CgoiwY5%B@~4C cqYe4nW:XY3;g7-C c 5<wC+%yΤ2CkX%b<꬝fX:c幁 H -u1?mbh$zRUh1CK~)}Bscm)n82CkﵠYYg3_gZ?bFJXpjBY4C~Vu4| -?-C-:0G")t$NJ zyX}b&VY`1C wƊa-bhaceU~ՙXy܇335kϬZ83VKPQ@ǻ{%j6 $F@@9fdgjlt=e1C uZ/C,fhIfYoY~lY˖V݅bkmCur~-[b1Cs}-;|Zu;ŤEYıXc#qB?_jҬYcA~ 8 -u P294|1W6(1C j5k,."phdG#ZKOj|W`3iP(l)*Ɍ5!Tf}4ub>ZN陫H9y!9IHS`V/Saf):cٱ*b:NpvdⱃBt{>HU=bbR[h&E]`1C "1*NRYk=-!:u i)7#1#ˬhŚe_(hEbPXfh4WL4CZKb͚E -+ !301,cT.ڬ$CkpYf ZТ1X%P;bhޘYY5kE1_?ezob:>g3 Ze\gIN?0lYYf"g5bVVΚe{w"f5bF۽g֬Y1_g8|XТX//}ʯZ)Η853~ږbheJ ,fhXQ-*Vfba<ٖbdYQVcbZrq XBWhC UBWZ4z <@._Qw `@'t8>bgrX;x,fhaXn,XВZZ`1C urc(jZKWdζo!}Z+̥b^C3\: ,fhXa.-C c1I}=FrRKڬZ}i:+};-fhAbbY3pXiAaТ?Xf%YnYY3_gW}-Ck:y#ZXTVgb%b^Y;GZ1JXrs;/ZSh1C uƲ [$:ޏup^ Ь}c':cbV^Ys3_g07c }3_O?~3F^1ReJM]=[Eퟪ:%}/~y~/žC{) {)}`KJ'ٽ\_w$音<~s6(G7KO 4zn7_%fo%ڱ]%H'|_z{)UKhpr_TzE[?}%ׅy/^^(sYcäz` tZ~^ .ky-|=lRL~ %W!'\Cȯhޙooܞ]am7ʍ&?p_a9L5RMd\ÒsX IJ<,?R y*qò m>r 鞇?Ⱦr$ZTU=*r9%|}AN< Rؒ? zfV,|.5> p=|Ax.y>|S5=׫\[yd3<I{gEz&s=L E/>?Z{-=߳}v6?Kgu(d0Z[9u=';sa],j O'L}=̞{hEۉӺxOqtO˷ѕ{hsO7z{Ow'DvB>G+HN{h}'6<ʮS 8"|邿#{m2ɳtO-v;bO=hyw,dtdkLm3{FIeSIۖ4<(`z.ɢd>H 1LPJq>H zLt0{:hS I`6$~`vfA=͓}i^N4|O,MsOl1$r~wOlʺפ{fK G+{瞣\&=s4{pj~ܓ9~o&{sќ1{ќq*s3ឣ{Lff{"L_>lҎs7s7{s!sS Tfgsn&WusS~nTۻ9ϛ,y=7xϛv\gPsTwrϪYU9oYU!s=3֜O}As\0@>]p2/{)L76gєn as!ܽ;btA=.{>]{f.ds+9w{~wks[1hb|A:wtvy~&^joS{\Yڔ.fOy܉{Oצ-%J ?z(&}tG/瞋zkA~&6N;yT-﹨型?3;3wb'Y>JwIV{VZoY)vS_/&EW?I'ӵbO~8~|ផ~?f$+rE%s;LGKw9Km§0W|\jN{ +ĹsritIy ۯ5>Y ιۇιڇI>;s.i7\j.{.Sgkmg>۟ye͟8wf@1z>O?q] 垟O>l{V {O1gӹVƧt^\tٴg{0A| xv> g wol?SRsx?|O^ooxYk|ľmdza8^c]^gwC?}3_DLklJ>\^&bBly=+S)Yo?ZN&oדm틗kGyLOBkնKU-_yǷvz̩-i_$?\`'Y$y98~ӻ%fϓMUYjG)Y?R=ɬQ=7ze H𠭟CjW 7Ͽ?pBۯ?B˿^|J2H$ Y !js:RZ2m$rca9mKY 컬Ѯ6d)VJ54VaXQj"[}_K yL,+˱Dy3@m#:WP2C+"6m5:cjZ< dqf`ɨW,fl -Kj -eu}-M3\O3R-fhX-TZ$:(ycT07xҬj~e:Yy̫昑ed5we5ֺV;tɲ7j 8p sN;UbF֞Kvg:{vEbhas5YYn>blj3$Ē%Ō,#RVcrkl1C.+6mScrY q,e`ٿhiYvlY! [$FݗhfͲZТ~ZpPYmJeC uf9fX$ -bhaXO 30y0D8Cx֣XbhX!@9$=x"8.QD`cS :RpYDgQXN,QXjX,Zد3VH -> rjb`ž23YU-fh5*+3})1ԴC x{GpJmR:k%Ph1C u2Z$:ލ*%{fhդ)}ڣ* $B`@~h非P"*]Jut? -+'lZKZykfXXJ`e1} R -@}+ꅚ%Fd)֮-8-fd=Y,bhxJ c1C cc#Ś5˲"Uf)b: 9#YfX&b*k_ȝk.1hXffXXe5Ȍ,35kY+ElZد3Vc1#%b5Y"c1Cbj(Ufd#4kֳlZد3U,fhIY -bhaX}iŌUYf=Z~r_P b`cYͤ?X%ˠ&eu:?֒88#ظ")F[rbhAXR"101OR3\Y՘Xヲ%.FY}_[Ō,L*e1CegH -uQv$3js:ڬe -α*z?Zد3Vȣ[$::McZpݞ-fh*7- -K~>Z$:8_12#ˬ抵YͻbZ~5NZT z]:k9X:c'vТ.?EC˹u&WLZ-f4%uƲv [$:RJ4ozӑ&oxCq5 ĪgZ3(L,ߗB8U&bYLBgQ-^Z5J^Yiܩܲ:cY*zWZ3_g4W3N5I52 R B5ʝ!TF6:KiL31cL:URgcETbeF6 tn#NNw8\(:cbFyZg)=X~,<%K^I|blVH8vmGv' %fhЎPU%/*YB`@y#@qTRcs(E+vЂXaP KqZO\V6n,4- ck09e –bdL,ZIs;<VRZq ) +)D`c@4aLr+6e=Z3dΚ5j" eGb:gYme5fկSbT"1jƘYfZТ~¬XX8>j3C+3bbɊQYȲa+1[ -+R&lY*QY{mCuʻib]oOsY~(&--wZЧ3VMyC%hY7 ZgX~̬~f.L#ȍ=J0.7E kAe'HEq AF9S4"f`Iorl &V2@Z&yPVgbJOŌ,Z}::"n3kk=8bhxĊe[$F6fZ+E:bw b:YN Js͚3:cY/tt_sYzFZЪ׮{fKYgdF{i֦t* -ـ8)fZТ1\m b1C ccu| SSXW %fhaPUҬu}X-Zح3VE"1[Y5k/6-bhQXi/6b1C5tm MzZn_YVK1rz+@"N=]9bdYbYzaIN@IA$^5k-bhA~̺& -u r*9  5] #W[#KeUJgby^Bv8a$9J9BOAYѻb?bEZ51YYW`1Cx q_^Ь~i3Qf)T1hGWZ1]Ȍf2-!;uJ "1CbjSx2CK^I Ys*E#VZZKk]dXEKRG2χYVNjL,_VI{<+4 -ʹU׸B1CK2P\j;.bp5 twp:pfh2QYgX~XhZ$:N1نsbdE47b`L'Ȓ -y((3⬣ZjT4먰Ebhas#3bYKb -+?sK1|oX}zE:e3ʃ昑m׬u}C!pSg H戡oO{]c<_WfbyU?0%hgw2w q& " 3ܺ)fo, -+fbFOXYZد3V5K"1(qDYg$3gXȂYe&V-e1C xq[$:XYǨY(\YYOmK1_g,y1-C cJ%W:4T.R -4ЬZdh)c}CdiI O::KVDHbV[5Xff - Xnb1#k-YZد3bТX܇=3d5X>ʍe1C u s(lZ;qzt03BfF㫯|-oXr XX NMXSRgbg-β,fdffP.Z83VڋW>5k?1_G<XXY +FZV3ieZЯ3yS"1u3Κex"exb1CbL^@3-B3WjXr-IJ, ,fhIY\(!' fMDbF3_ԬY3CZد3+^XXǸY ݩbbX2s;͚+E -+Β) -u1͢##3{ӬYsA:ce[/j *˨aK1dNΚW1pG,ճf,ЂXPL0CKڬbFk֬BZ4#A,fd3bnZد3XXV=3zX߶:c[ƚE -+>뽿ZxdF~q c;,1 LzG=XW L`fs);h5RsuvD`sDeWXA1#4ks8s/:c][$:T&YDǓBg/X\ ,fh؎Xv.defϥbeY"10{ L,?Z{-m׳e1C wy=+-C cc9#3k:b댕zobF?&0j} C(Wc@jgm\CKrML,Y(Xr/h֮%FhzyXKbM 埱 Rvfk[:cyw\-2#&3F[ާ ,fhaX&wТXpߊqZ{_k&W(;uqUhcAEZ\}IN^iEbFEX~,mXZkzיZ3_gי-C c'@ُ?{'@fb_#s*%QVgRZ3pXe/[b1# jz?˽bUzcoH ->RSBBYݵBȽSRgka(jEb:F-B^'rj'rv:[!"ͥQ4k^k[ТNX#DZCf\_#di}%Q ,YaeXƭa -bٹH -y-(fz[Т~oXXǵ>xW -w5kE?rR z#>mfbvd-F[#NI84dF ,x)JΙ,fh+<9*֬Y1AbY1"YuH՝<6 :'(?:FSbK1SgyVHg.~YN"eZfbV:5k1_g,ۗrP@iO^iiO1d΢ΤA-l))Iۍb^pE3h1#4k.1pX~.Le[fmC u P b1CceYmWe5֬Yˎ1_gZVVg%VdC u{Z;i!tU19q2קڊbd9k,CZ8GG,yXbR+ƯW0#˭boZkc+=:E 5G -u~eu0#˭rc}*ՊK -vX4 z$mufuV9 -+쥣vТXrV˽fh=kͤŜz: ,XZ3,fhz`,fh|EZ$c 嚡LZ,saƨbdY;HY'3pg2&lZ;9zզ`&*5k׋wbeV"1(g4f`YhTk&Ih1C uƒ lh;EvT v>2ӬutV8 -+EbhX֘۷|=_?~3F^?)8^䍣d~%/Я/ԯQ2|/~}+zjHyKdJ b/qB}څ+L miJ_jg};3i}YvxB|/5zY9~?/43zO HF/:mt_omu^a?Fϭ\Ϙ~(s',SE号(4<~> &ϧ4|?gQB;CLsgH~ ܋Ԗ_']ώ_Ϝ,Bx 80vvx?'gLIgΉmTIqLhzK&Ɇ/p=ռ)u)? S '`gT> ekN9a}P༝(g?'xMNd9߳Cg ;,=;s޳C !Fd=DSaI?gD+ }'D{vX١}=;OL%]2jy>٧|<s,?s;cœALrB!FO<њA](1ڽYZ{asG+>|;Z1֡3FL w~{ s"Iٷi+_ϘI$33z(3K܇m@sL=Ǵk=ǴsL+Γ{Y> p݌d9ݳC9p=rb~*',ZY F=AW=iϖ5wy{e✬};'ݳ>{pjܓY?;~E}9:YSvsܓ?g=sݓ?'KNt΄{Woɟ35hjGga=tg~Nַ\뿞\>\ =s5uۜw;zۜ->z"V}mkbdq~s:ys:ys9Yvs|Λ{缽gzλ{缿wN|guΧ{V|r@gp.< s\ w\ͅp^t֎r\|d9o4w~/2{)[sdKDln^$bsR {X*$b&bk ۚcVd[soR ۚ&ܛbyloTz:3ק?HJOdYOuzc݈1ns4O~=T=I D?ȭ=sKyc?(;=whps4I6?(<I|UF=Uk>({s}/{V:}/{ƺ}/{ƺV|/KZr?瞠eKYZZ>'ei۹mVJ=iRŹ{}*5;*KOs{~ewO27A=[[+9\#yor{}%1KეLvj |O:蘆{ܳ 8Mql+^D²~ t7PI-UΎ*OEU/# c즿jUfVLM,eoW lbRF5*s52ZVR[}zj)e*,[kK-+eCђkc$cT&V^^:+lu0Zk/;K-3赪W, :²1XZ32Z5 :S(ΞyTl-ybXBr={:l-u0Zn=bKvb,ek9-\ևcfMѲY}j)e`$gF5Ʋ9ߢ2Z51ecT&ή,[KK-keѲz ֒7D"NHhgsVaEIvj (iN-5{ݛGsi9K=!90fuK-ouL*iQ-C\!:FB2SR1ZѲʫ ˽TbXḱђtZpVyf-{r aRv*3뾽59-e_KFt̬P( É#)_*,wyRFc 42֞X}ͩ5j*(c =Ґp}߹ 3 NRF؜UX*)ssEB㤌ϲG訙Ylx~lWKؔus=sjuK-vkUʐXzAQ{zJit- Amf={C/_eltVa_ѲNȜdfA! QBKBKDthYiN2ZV}sVay.[b,eد1VjUlQ-pkowhj-eد1־_ZFK˭=DhV)lVa_xZ7~cf- 2ZPA"8Oq4(u\׮RAyBSys{g&Q=gd|.VfZTF6(7gV/[h_cr R&Vl޷-Xh_cPEak {.Akg_!ѲN(_5 :Ȫ1": 4Ή2ZVI}SDǪ1N*,y AK-od'i ;[ :Ϸ2\_^=Wy$NF^z'e.EZH|woMZP8ĩNJ%5c}/2X߁='uVaj9X¼&rK-jFǨe`FcŖXh1xMW^5 V>2UYVISLj|r⚶CDgιg٪Zb %}b- bqϚVF\Z:g_9ﶞe+>uK-qe5cc,'ѲCD6g$0Zˊ<'ckG.G"8)pצc]rVafYY`ـVef-S 2Z1V>q5Hg;ZzC)iQ86! 83N>݄+ewӦVefB\C,{2'X鸞#Zh_cc){+BbXV4- kJ,[5H,a_C12Zv~mtVajHbXWFB,ekeuWgfk)O`9>kϾIŠVgfW$Ap朂SSDF>*JH*,[5J,aح1VcӾy|̻2Ee_Tg_VJW{óld-rb*h,ekV8FebYjRXh_c})]cđsjPFk;/Ze&E%QX[e^R Î(%wIaNRU;F~Vafكz~^,\y3Z+ kQX^c,eد1vRkm޷VbXUB,e7vt,OvK-kk*(cY3Sx*USS0:K- tRF}V %Cj6p.%㝒2ZѲ4 ]o`)n0r- XuY6ׁc쇁YYc9Fk￞嫸WRFcb3%c|rk)+XBXҲآ0Z}= ]_!ewK-kj(c uosѲ#Rgf-iܗZ|SP2 CK-{$:~Zhm+jgًBRwU 2'$-JhB!00e?=#D] ؒ`)NK)- %\#Ѻ? Yu*Zh_ceHEakxV:1ZT22gYnAtlTX~-XXV/9 - XC- s,cy:k$Apأ1P|*QHhYYd(Zh_cB!2Zvxrk:-eد1VzEadδXrūcfՅ-e81^Eak-W7Fe;)T2|ƋZh: ˯P;EK-qu> NOh10c]41ZOAZU/*˦c0.s|SDpeUKnP{,a͊5 W-%Ѻ ee]FK5Ċ-b,"@Wl%:ž}=`*cԯhݽ?G3XvKKrfŠ7j9F61RIK,!R eO&Ϊ,~1ZG>B̲LYh_j1K-k?k [Fk{Qe&%ku\\~e)W1Zw_#oWk=czXj>XhXW[c"2Z5?Mʾ(fBX[XՖK-keEK-X}+cK-kj(LԳV+EK-+XhI,/<Z1hEK-0:0RM䢥8J4HgϰSs8{BApgvQ'+u>M9fq-Zhmg_:V`0Z묉\cc̓2Z,[-0ZZZQ'c m.8%0ZobO:V,,=CeW/zKϬŭ3Xڒk3+.Yh_Yj-e8cX3 "N+dEI-jvC)&Dzh nZbr8c L m!YjXhq|cfF12ZeUXjXh_cO!2Z5Lu/~ODzUӮFԴ'ge%bFb =XnA{I;JSBGGC\}(eW*̬XO/ =]w<3+Դ+ZhqcXSEak㺖79FhYYY~]*)z2_S`2^TJhkwVafK-koK-y9K-kuVV: rjZRFK!TzZFKbKPF˦rVaf52ZSҢ0Z5}V{ɔѲyNgfV(G剥 ˮC2GqZj+Zh\ v` [Fƚ s,Jv,Og-EK-vj lQ-/{eu2XmH8/vEK-kʦ,d!F9sDk )Jh3E 3kk fђC榯2VfVȹj)euOH0Xh=ў<vK-kmg Eak/ߞY-( #ȶ}$ezrׯƃk{rHDpdC l!2Z5pqh=zeRFc[F+Ὧ,[5L,a_CK12Z5mʒgmR&7˽SRS:E ǹj8eeOgDK-7֖Xh1bԯz3R6C,hiN^*nr80n6BR(Ū̬GV[俷sus!bB 1羗0eVaf|ЛZh_c,ڗ_IeZ!#}z X_KDpأ1rI-˽IB$ZŞui)7'No=|ZdPZM c=V;0Z2Fk_ڑO,h!8},]gB-"UXbX%?!2Zگ^YZ-,Zh_c$?XZ2VK%5J ~/ âAQj1,F!#Q܇qYa|+cڹ:TR8vYiEHĊI걅Dz c)p,@K-ku\6iQ-j50K 5ƺX[F ԲD;ZvJgi);Ԫ̬u/[EѺW![Z|BˢB,easVaOin)~B;7- 7i+b*%X*,-G 2ZkO˽jdyFcm5Q]ZF{1Xu>߄Y j9F˞!*̬c/;i)Y{MkuK[g{tRFK^!ՒK'}AQs`sa@˷C+l%p%8F^ , 3k)YVA~(-eد1V8FOh1vGvv[7ڟecfZ늖2ZW5qEg)ck%- XV cTFdUX՚EK-k$)iQ-5sgf52Z[ ]h)1ΖbaҎ|Yvc9F c]k;-*+5rqbXkvbhm';ξ b3Zxf-n7 i]̊!g)UY삥~jc)u2Eo{_75J-s- Xs[rVaf0RFεݜUZhqcf3IhmIu,[5{S)X_-y L/3묩RbXW;!- o#e+:%Jvm8$gX0[y8Kh=;3k7te?ou?itKYuUO*̬oK-{[eq%_1VhXccgcTF+WQ)BYpOCԪQ=abM\1(e5’ k>Ktۈg٪FKCɞ걔bqgk1*啩ZuԼ+Zh_cEEab gjXђ~ V b&yyVX 9z+3ֺ֠־Zc a)1&ViMCUX}/\%Apq(;䢈$χ %aqlYaphY²UӸFcXhIZQeв.RFs?jꓴ(cc<ڊcT˒|S֣i)~ `,e=*Y}+HK-kuh,j.8^kM=":rRaf-ed|C<_|&A;ysRay:K-vjPlQ-o6o1Z[ f]-hݟ¬G)D1XvVrYVtr2Zַ+EIcf'12ZYނV:F< // R-% X- *-ij<- 2ZkEakJtS/REpν=쐵f[]*9F/AWMǢ7ƺG7KXKK,eK-k-f1ZvۜUX}Kz,h<ږrz4HGaQF^| -eN<3km^Xbh18VcTFˊx<[O2ZI=j)RFˮYou 2Zkkآ0Z#k{Hr.E1X}T9{M#4_1AtvtRa۫Ѻ'7*̬cgRF :K+i GB[GcY)miX-KitRFIx|W@`\}i%zEthzv,ezk2Z+VlQXK+}Yڱђ~ bͶb,eKo.Y+ ml/TUgֱElDA̬TO'jآ0@e9ђ~ Rqaa֏'.YDy`ճl(bX:c,ekB+1Z`1ZXk[TF˾*,-`)~֚o$- u۷<Dzd8=0Zү!VhK-6x){<ѲJ -{b+1Zkx0dVֵSW]kAe'ƱZMڂ${4Z}Ҝ0Z-e5p-;r"90kPby+*3+h)UTT0sXa|RO"2X}-iEK-kj(csWV^-;-ǽ1zFڜUX{}#Cp+GM"Ź?0Kg4>4-ZhOc֞zb-x_e=˯pFK-kb/hc)e/rk;-eد1VxђwےJ &TQ˾r=3+ObX[Xhl؝UX}Ͱ5ڎ^diQ'oa],?XW[l1cCci@ݫ͟_?֟˯=?*I,+o5󃿗ľ =9'=Y{L;#c'a)/r!$Rx߇N][Ɉ>^2?Q߇>ɓ/_p$:b$%P_xՇOJb^J3Qp>:|.ⴔ$P])8K<|/ej\[l?dM\k ^nM6Kh i{6V 9N` c~umsrOpܭt1'wms?m7=9ݓ=mshX}X}>cw6l-WmLoc_ϏbkgOCO4g/pq"ޢo6#|=_,d8>ZE/n=qeEuMŢjNoWh{m5zV}0Nj%uΗ|mX6,|-t!,ae|}4_߆e{}e?ɚ6^y9_rZ` 2_cb<6kfdsW럯úakpX)?wWʜkfFKtB/CH%r|>_"ݞ/C8߬:8eq/{q+aE?(1X3| 5p~XWi<uqH߰.vuqHo )!8miw| 9_tWa[>Y;sv_ [/o=+tKEmض6l| {Lk`gN5_}W7+C6/=X!nkطdzXݏU;kv\j8ٶ0ǵ|0_8G S8_a\Vov{dRԊÿ߾ 2_Kw`)j'Logd6i 6_yyXyYb z-5(fZpkPK皮A4_bõaY9e{r]KF/U8W .׋է2_WfkMFUgb7UWnj\7=9_/׋ 'zX>ZVuaTeɢ5_>Xl>W]?l>9l>kYD/z 6͛m=NVI/q:ٖ}:ږO }p;|v2_ƴΗL nLq|b7Z=;nL|./q[ `ts 07K>g[/}/q;h\oF+~;6'۱q_lظ⹜xY(?S {a/ˋU-|܎~#WHrlKbٞ`l%c?@l\>ȷ:_3cx Y)?]HYxy|?}k*vg,F|IO|96_km&~h{C.B?BLed{=I}7mҒ+~b.d$de܏%MR9| e1΋>f/L/u/z|z;׫2zX??N!̗ɲ|Y\7y9_ p͗v,U} ]42Q'տ_vf{-b;K%2c-R_?Y ?7Q^sVVK}] ҟSgW{n}IVby7:,?k*[}W!ֳ??/u$,Y,~#_KǟV3]_fPWuXRȞbUV neg_Vc$E݉;V: }Y|1XV^Y132Z%pVaf+䧒qJ9 ֲSTRC\,5( C nn;F˪59)#k~E +uR9VIXk;3|Z`qPG>0UC)eO$g; zCR?IC)eϹ*dGtis}qA-$ׁcbE䲣?ߟ?K.-tԷ :!P0f'*,sy>PR˞'{;󩥌5kP-'ޞ- nѲno_\O-eح1T)ꥡ:P\O-eЭ1ԞB(' EsZ͜(NEܟr2Z[2^_/Et?Raf7ks2ZfVayf$q8cRM)e=UY(UIis5&C)G?1Zcf-QB~PhrVabZ`[c u %ܛƞQD%'fV?R}CmѾh(eYBRC tjU;5AaߋRr1Z^zfw}U1Z!UȒ G8iTJ-;#8|Z`[CZQB9+?ժ,w>N[ccG]h!p=Ir(s*̬.vRF˞Vafyգ2XP`ɜ*˝gμ e پ="83̺Uߞ0ъg߾r,g.w8Fˊn*x1ZVgwVaJu0Xʧj(eja$LUK,w[ժ ZhqC 鹹Ph!8RAWG:XCɅR˅;soebkW/2Z *VK%_jX75IC)PKc2Zv²c nP CC. 8xRK7ֲBY`qxc({XE8GWG}ѱlaN"zt7qP |v7-)=M|Tf=C:K,{0?W2Z}Qs,[6% g~ џJ,GhL/7Be@jtVaf6RCY7(}S9UXK,0PhT² 'Z`[cc[BJ,=V6q 創3~؜_rVa_»X+Dz7u0X1ԕOP`!8B{7sѺ巵cyNϺ{K7'e]!#qJ]|#H'K±lcM% 4 KP`18_91h7ZDzԭ&Z`[crR~ Ϊ,[Kj%5?#h$Apg۸8Fkl3X¬s)a9FWgMPK-KۜUX^N81Rؚ0X 5~v7:Ap+W?AAt:Z*,edhCI`1mܟgtXmI噬F.ڠ2X{Y|65Z[FjBn{+S=u֊j"$AqbKhbk`18<[Z)]ZSh)nT r3=Ǟ VNOpVefm,e8!~iP-Gx,#PXRYӖK,vk u&R+r現yt^-tk u&6(V5fw+.t٘@/;䴗U,+^B~ V-"Ve_ѲY}xT6Ou 2g9'J`j#GzZ#zGVҡ)}X˚NK,vk [vup_e,3Z[M¬A{jL-h '!V9LA¾Kj)WHpVafK,Njk\lP,GX*eNgtݰku+iP,CZ>\Ya}(yViW|%*8Wbkhˍ~O5kS}/VgfֽѺ/,2[7 G8*i(erX\-Zh[c2ؠ0Z 5L|9L'^%=3+ִZ`[c(vp~(.Vafm%'J,eح1Ծ= ϭr[ѲjYuXC* zisE{T)uڇΥVe 5ZwlD(h{ewVa%cЭ1T=5(ֺ 9ϲղi %B5}B{I)Qxnu<N[rwYSJEt¾t#e7uU2PrѲRq*^;,h=%egERFk[}R2IJe!}[GvGJ&rcy2cأ$qا1N9AR)km;֞}#+Rʴxl3P{M?c(ej0Belʲc nXaD(eʿE= ,oehwdϬ 1X RmPeUX|K" 5Z[.+|UYm=BZh[CPIV"?.OevBtVa_UѺ'/*,[%L$8f12X 56Y}ceURF˶ /LމK,j_ C z2s +VMK,j UPhY²UC]5YcyGh嵃J}#Dg]7Ǿ j)wVe٪gb LoB5-BqDeIb*=is,RF)sRF($ AZ-6Dqˋ!oN*쫟D2ZX8/K,o ,6( C#]2XZ<*sT2ZzX= 6[̥ͥLוX-e^ o&K,q bq"4rh=0EyF8,gf>GK,*&F89^BrkAt&bQhciS|YmsNFl-eqa8G;OAp{fsUZvrh)>7$ n$8wLn瘵feR߉gMl9&/5E m7RYg[-:ڗ$ PGoWB^ҡe :90I' s/."sRv awP{eYvK_!TUAajf1qƕѲ򨇳 3+պTbPVc`16 sm*'<k-w90EK,j՟J% :YEK,{j}Iv,OD-gEK- q uD*iP-Fx,(A-W+.={ pQ)iᥫV@R0B͔ yRr,e81TR L=˝O}[[`[cX3AaltVezP=0Z*D,RF ^lѲͣYQbP{Ucjh %BRK.!-XX%!MP*xf%gcЧ1U;kPscx-eku;eń V+gEK,^ C|p%3GxZ.ֽ *^6",e1tX`˅jJ,GkE(P;`iCV bsw2ZKczh)kc{qd|CUB e=VMD8hB C Sn')wk:0;hr2Z|: ηeem1XjXhaPW>OC)XjΒXhU&!cP_kK=ˣU>~YԣC'R4JL Zk-eY DzUkZ% 8JC)P*EQtKCHUg6NO,tW#yF^7YjIӛZ:Ͼm-vx׮c%8{fjN<bYG;2X|د3ZO9r[U<,[OK8jC)eGAʲRh nPACyFyR @s%>HcbaF_12Z)ݞ^ =ó6oRF<3+OjCCm$e6( C#H]V ѺҐ=?ɴ {k)R z;NRF CŽ>B-b;3;"*jߔh#,hAE1Z`2ZkQ̬ k #R޺Ve,e*Vڊ Pğ]'^9GMM 4Djj#)eNg{]#X`WckFlP,8!%R&U3+r"<$Ap~C-?=n:0'[`wKY #|ZG8?0Xu˹/!Th9WlP-f\(e[N^X|!K,vkr VsUY|M[ctCh1P{L?YkM4 5f# c :厗%:Ēm$M= ~/,yfߜ,hѯY՜$Zh=jxfVjgR5q| {;-eЭ14(B_RbuovZ,eesxK,PSBR+%<ժ,w%.RF C]-q P~R,='3jiJ}M5aj38Fx~pzLZz=3+Ճh)eʂ 3+.u 2XH,̬PkGRF S?- PZ#TFڗ+n'-eح1Vٓbz8׃2Z1=52ZsUXKΒX`[quSAajU8Be,tVayNs'=4ƹj&}y7l_GKYo-cj姅gO7Pk{EtRl {f= W w̬CRS5 =*,wCRCYÅRFˊ:o*,wVRC=e'0Zj P :2=BMeX^8geV*r9*̬fNRF~ڜUXzuG"zxz eKw$ Ouiշ=3l`)nV _lVˇ% tˇ:&T ,Q;hsW2ZeVafX2Pi)eek ;2ZK?3֖[KM#gU6cjh n b/Ph!8&Dat:eC8fP#qf6m]ث;8QRFkcjIU TPӱlUb nrR xu=yԱK_V=F,a8!QA`!8z΃2Zv[rVajiLbPV^B$A#3徔#CyRzf\ecDk2-e8Oc{GJ9;ֳ`)e-vgfV;Aj)eQvT qPàL;?hXhOc}PZtVfjUh ūjud(RF ݅V9sH² C]5݉gVejUh n e")8|AʎѺodr{:%A>&N8jrRFvNg{ގ 5B)eoYη\+Xh[cX8Ihq+`8el+guVaf-e=3k5h)żԪ̬DRF 5Z(6(B#㰟{5G gֹ;'wc2a-):ܕub0n.l%nȗ8uY7Μm/rwN\yzj4-NX 吼MrgM +=h^uR[,)-VzvwdW#YBɻ։hoyJޙUٯ]i>Z~.jG9rض~=w[<-[m7m?f7Xpqnv/nY>1bzt=[-fa{gXnOoOonn\쾻Bur]ucMoGܦaGڦ=sӕ*.㘮Y^W[ն5&7W#gM^\-fX;z[-yczreyM:[U|z*u|mzmӥzuLכuWϋ |;gaY+`Uɦ+vy%LWz3,i8BQZQ!c/>oa 9]r.4ºW/y3k|3xogB\A*k|b&}Lךa=kM.2CXK:?bBxtB.-C>XZO(^,(yֳ'F}M2u !J24_I>|M9\{q.29Uwx} i#M[!ϷHC3=)X>ڦ+Q>]ot9]t}`N?M"y]j|g_Zn`:n5]}`S5ݰr7qei 6]ӹU~LWa?k`[r8ɺXc}/#LW͎jtmU/. ;8`imou~?2vN~cOf^{~r g.rù͖:pp9sM׋ĵ|O0]+MQUmw}Ut蘮١oX_t]ev&.a 8] %ͷWe|ɽ;M1xX>+߸.|NWq ӕo\=>cVB7ۛ>]x=s=\oVuQ;9,UnJo1|7wtwfvgyv?VjrravӍGVn}|zqލ1M׻1nrcܧ6m"ihLi1ӅmLa)N15Z93}`.Xc:g ֘5nt}u*[.BKOܜ4]zm.8OVcVn>`}϶`nl`ƶ7۬}Q6f}e;[|#w/@;al;j4]N??1MvRwgvJ 7AK;זN{n(ѡ/x̗9GvNۣ~UWwA@Bڿ_hڎ{هcʳW&j~۫]?ըj6}0mv}Ur~&M2]Ml>vD˞lk?6[ ?TmŊ#,k?<0]CލEb3}be颵3~1c j5j? {{tK忌}L?uY[!wclUi{ >MiO{Ioc*e7M>^/~ﱷ僟{)ƶ´~mDe}Dj_Niߗ4tEz_)&qo[{'k}^0۱Ms6msRm:]|:Q%{mDM>]Bn:|j}e:|ipfC;jv;<[Ɏ-8[%w.s޵-I enWz#˷1]R.$ul7^XEt! >ߖq[t+H|\ت9W+h"=/c|,&֣{:U_V;^ Zտ>Qآ0c-R_?Y ?7UQ/6vϙqZOS??{l6;Zou>Xir\#~;?Ğ}忰}91S0u5lW. 6k-2~.Y=V=zg_V#1X<|UY%JgcfT8V&JaRE#)u/&/o  kr4ע0Xk{iV7hoZnճ^E-e׋j)cbkQ,5Nh^1ZI9Vqѹ6 ̬#2X~|.V)Ѳg{K ku_oqhrUTyeѹAiwRaf{ MKx:%J7ABߓrJfZ`IwX!\s- i.tJis5~RZOS?HIWg}nCY(z<Rސ(3-wS9RYQo:Nu,Dˡ8cL1&9):}yb`jbj'X˜A^mѧ 3K)bVziVO㳝h1hciY~Ԋլno3]64G$2c 3CKrT8noI!pM&P:CRCR_8;:e <(+,fh WVc ,ВNY}̪yl1C\ǩlݾ-f`ĺJH ,ex>2#ҧ}`b)bh$j'K1]6V#S2Hjl51sZr;Xb{E16]XXmN5В BIYQ yXvXH:"1귱*VE ,nCEP')}a>vkIKvvyk`)0NYFZ{k&N ,vUG$FVK0Ū}0ZvXezrXf{=Y{*ZHc:icRcN 07L3wh1j寱ōfYvXٷ'^X<՘&5*K%ƪs&-es ")TTX-@ηH $EYUjjvI1Q6V+̱%VVRYvXѭC#38:HwXc97aL`bVX6bVYYt-fd&SZ?BXGrbŲ}l aV-מE ,jUθ[X˜չZJTPVc9[*KX,b`abŲ},c]8aUfG*jyYvXnɱ%Ҽў7E ,j s,fd3BjmB1]6BZ2RdVJ1'jLn'-Rhb3iybhqU Z t]HЂgNզ)b`QlbF?0mZ!}CLq:#+ #,fhIխ>N l1C+_2Ce.XՕ5-f`ebh9ȞZR'35mVcn3 L~:u`1hcősG$Ų}c}dF1FCZⰒ*'y;>Bpt'eA B[Xmvnb5ƺzX]7AgX{ZvX}Z~#Ym5? K1]6}]4crL1R; k&? -^1\Orhl0 3{Ԓoۏ<dDC2#vgV<4FĞ!pM&PYJx0DP }dߦ&C_k왡qOYNK3VwW{/㵕J?-&$+ʑ.5-Xc)>"3{Rj86@gJÁԇ>vSYnch&+EBϓ#cI5?50C+c٬XɷOh1C+wDGj8vC3b:!T4j/th1ec= h9Ȏ}&83WVcss44V|h9A(uDb2tA 5퓭ꐎe);ũ#CK&e5VE1]&NXˬQ:H1frĜ8Z^?LŌ5*17cZl5VF1hm0 3(cTW}dVtkmcn63Z[U+g-!ZwJ#3 "1b^#-09~ LsbU'2Un-KYUNE ,n{:b2WT_؊u_&5 Hh1Ckʩ)O`)U#CkԦYzYvX2#i] ' !5^֬Z=,b`QslX˜R}@В XFnZvX}YZ;WVcyRd X:338^pKVc-Cm:,1G#; #н%K?>οl1C,/m5V-׫GE ,w+|+ ,eHʨ:|J"Ʉ^bF֬vY{dec=932f:z$ZvXJEǫp(V ՘>tR T>ږӬ/׸=@PR@%WQDˡ(;XNGd2d){i%OUh1ecaEG$ҧe5eF!UX ,jGQ( - 7+3]6VZE33ZYLh1ecwN׋% 3VVcsu%XAYuli1hcs4G$2}O;Q1dǽ$$ ec }!NƤwtb`qttuDb`Q,A?J5B'8a:# ,f`Ql,3U$ R(Xι*f %.hi,G?^AC6oh)Ed ݳ̖bhI"ݭĊJY))$N_(1N*+:P۷f9fhl Sb03L[-EHXВիbʣX^;pa1^VHTy$Z厮׼Ln8[*XLjL,rQ"Nۖđ]%@De5&=XXur߱}|qX.ˍ-8 p =&;3l5&Y\h1ecŞWwl֏Z`1ecő˅G$2u2Kx0CK6՘XgOBZ_+0E}ΑG$ϥ>2C+2ڋj ,jW:"1(/1ܬZe r^jL3 x4Ūuh/SO?KfFp٩VG a^z rnUk$E ,j㼙EG_nArڋ+$NT(1C,SYFRXj=X|,,b`XXqU՚ElOlA5_ӬHX.@В9TQu|6Dpt+̧h~~ C9zXר.G$2}TEFs6ꈞAҜk#2; {:J⾩PT+bd9y$jGײ eccԨ#bQwuiaV%<*K ,j% .Yq|j{u)EbOXВI\`1ecŞ{EG$k_v*=XY6>L|AYJx!A3R CXG`,fd͂D'Eؗb1CKvjzPl|EpXR YFYb`al,NzxDfhb,/O ,jNzZ)T۾ ` 8&<"p0I sDL:ʿ[+߳h:id,($- ()"3(;8:QYSi_,fh:5+bT MjZ|ZrxM<_d|JjiYvXyTzXȚkjVQ[ -b`Ql{ԖXXD=•U1nwRVcbԆ3=r4Vw,b`a& ,e(#3ۥ꘎ BLͪ2E ,Fb2Wiu9nҬZ-ߊ$Dˡ@iA$fh2XzׄPl4v cZ-p(Ee|f列la ,oG:KaǖbhɯgYYu)Ecoccgb1CK^TREmtCm2 DUNEc/d?:}0DieT !pksW"@ZeZɩz%+U:죲Z`1dˍ(<"1xMc.GGv#ڳPbɄ'NbFV9զZЂ, 6K1&VVxDb`Q,dz;aUn$i/v!pM&5jX@Ёb= -f`QlkZG$wPM3YiF1<KX%IYG.E]r0`-F8Cb:-%u/e5&1wpL 6%`VVcnl1ecREG$2^)qgF[lh1eck ^jO ,ju=f,fdͪH֛:LEQ' H ,eb(D}bhɓDW |GAIbh|*1J3ڶl5&5b}6V QxDb`Q,X QA*AX.K^miQpDfhf#/ ,f`Ql,7X\ #v99 s7XF$_ZjL3bVeb1ȭX46VNZ/ (V[3DX.+*:"1(sԧgVϖ֡}'PϖQ f`QTsn>h9eSВG%UT8kO8&(8H]{>QXWfhɯIYu"%ϟne5V{ei,NPuz:ٗFĪH!ph);TC obUkhE ,j5>R ,S'C UW"X.+RXK}Fw U ˏ43RwؚIԫ/K1SK96BGo%5&V i1:W!uDbdUY|,b`qLgpa,f`Q,3ip 왡i&ٗh1CkmaY=sV`1hc]bF/ύ -I)jޅ"ĺ`Xq|GfhjZjZvXopbwcͳ+j%De5Vk1]߉N{bXzYvX~TX7H_nRS1N7hĒJ"_P!qBϠBZ!jUk9,b`ѸXqTXX* -)j;EͲ4X:Fq$ͪ\1]6V9ӜX˞ν)3r89]!1Xmyrs6P &<1(]8{wБX˞b`alpBPtDb`Q,Pr_CKJye5V,y&fKY\,5$ms03A%&4$)Y(1C+rű՘Xn䀁 ,L,?\ELe[ x!)Wh1ec^ B\B#u $f`QL3̧33ʧTQmx8$Á%{)fU7Vh1ec= c1C+$B^ -f`QL,yVGT 0 6hV[?RX.K6Xz>NR|̈*$;Y:#q|/X3F,EdcQ b1CkYm}CrQ6P 5XmzrQ6PpXd6hx20CRVcb]}{=%jȾWOZ}PVcu4buR[tDb`Q,܋_a(VGu$ ,jGX˜8'CKvfjLo3(3z$-K16V:n|x@Dˡ@Ad*X׭,fh<W ?E}|HEG$Ų}# Ȍ,?uiVGudZ ,j/ktDb`qW~1w>#tʢvZR x"[u 2[:h1C瑬X[ ,xL:"1(c>-%YsꨎV`1ec^ h9H,aNȊ O19ߕh9(2#k'/ rQ6Pa$fhJŪճPBj t 3(9KsYS8)YFZ㼒*Dpt<[L$]jձ)Bh1Ckmf4ZfڲXF-Enbɮ:b`>f7ҍ`$֨T1]6索 P {BK6*;՘Xal3tVcYWdhcő)El>0#3,GYF+Eb1#+әY*-b`Qlk<Ū[1]6V^f,f`qM^oyҸJd$,8UyVcrz,ВwmHBX4V&}$`}V&P7/Dr!&̎ZQ-aa> fh5l -f`QlX4Vh1ecžbF_^ -f`QlsX* *fGU?ĒNYЊ\+Vg^ -f`Qm|XВXjG)EG$cج -yRVc%Z1Xyl3*V:Qi -y&+,vX<':"1(t\BǏ{==BZrf%bcg?<"1(b쥡ВڃCz͋sZfXi~X*KYm}PBX.+XW޹rןTPE#•䍡v}b["RjџKgL:ޤWK41江7n3&2\Q~s~,޷a|[?>e*>~if`wZ{LrN5Ĭ ^}= z҆F?[9ѯgysKyڄ|ru> ki}ˤx=x:yB{;c?n.`V^ʬ,`fetYy5!]=vI\:v.vR7cgk?|mg`l}y`.Ow_fՄpng`lB<_t2\|^+s=~|ɞ»r\;\~ !zޯ1_!C| |NJWëx.+N Xy\] CawޯW;qkj{WjiRf \+_<_zw*G_/o]~mex׶0گm}̯<~em`m/̶?Z得XN~S.v}J%O~[f˖iէ{_^M^tN+v<Ӄy^޹Ng~=B_ny姿~/`yRKv~YeGD%r1r&%>mI~vڒʆH/h[,ev塿݃EBRPog|˾p^8f y-q G/:t ǵ_)꼛qleZpnL g,H݌\/ʭ~ܵ]m e;wU~nn ~;7rVܯBYm wsS(ߐ۹)y;72lP.T>T5z6Qpb!\Xy Rl;mc b!B,İ_ V<˯j+¯lگ+$_m~| RzXnE?kZ 2l½_͍?ܓg;dž Vjg?T' ~]^9ӹ~%73\~ϟ짽?Wx%Ksn_՘Ij̵_(bc~ɈK:a͹ӶW27-Z|>\Mj'+`Y*o'ل&RUvK.Udžυ;=X ||}.u4wb{ >չ ٳGܯ[VJe<ٗ)W~[8}Awۮt~a;7hyI~l?^YO>m+ ~a;x:T??xzw0|ڻ+Ys)W1W2(c|!rگ^cY=mX_XY,Z֧|YtT~ګ_O~ע؄dU߯O4?^yh}Qur6!WlQY&iU,'ۯOR.6!>ɛ 4_z7^נ+x|rE4+=^ɠW|4`E;j}.+Q H_;3p}Cv~Eod;{roC#h米.v6+cgIg#[3dP"m_y;hL?_KveP Ƿ~>(}_HQ_z]um׿/Yg^XncX4^6U,fh9iV[_7dX.զXВJ#8&JC YY2ɠZa]Jd)VY>[YSlcX|!XR ,)EKkV[3KF@iG -e^B[}<*[G]k ,jq,f`eY%Pm{F!tM&Pe`@fJ`gdFq5DgYg$ВC%bfe5Vj7EcecZMX>2CMu5Z+ ,j% nP:iuΝ#4sbjc"K1-fbe٬%BˡAU:1se00Cp5ebVnyLeZGբXRPZ- gXRY^l1C hcZmZm{3?">[vX/H -e3Ck-9I]!:뎐|0DP 3JuƂP1bz#ٱZ~8j1ZN-f`QmnWıfqjS%FX.XesVgh)ƊGQZK1 aYE bV.>}WrIG -죍떐X}dsJRl0PlVQZJV}E ,nb{򄱘;ūGw%ٹVgRDZשƤ혈b*5vcVdZzΤXb{E1s؞kZ1ҳ\-83(\TEeպi'[stxG6%JbdLFe5&VѪZВ-8bO&V<-ŌsfG'3]6V+SH ,+jD -bhQLT830='W3:C[ ,j#+de:oϾ"ʾ=XXҖ}K[1|:z ZajZ~uy/`-f`2~pV >!C hcqlGf`ISYQWh1C ecBDRW0BʩcnbA!p$mhLjFJXX']L˺>ʄBGN TT3d]I| Dkfܟ1-: BS&=f=E -fhalSТI߹ɆQݹ)VJbb{3Z,= ,>Xrޞ/Un~[Y׭8b= c1CGVVc=s $BˡF@~$NሁE qv׉'3i,>Zjjg7%\jL:[2:YQm{KB8&(I 8 ujЙ$[YU9Z%XvXm[! -1:+?X.K2-+Zқ -ToBVxsZkl,/EosDbha,u9ǘ 5ÙfNȴEGJG$2'CۀOfhY՘X%Z ,j%s>"1\u$ E3em5Qw˒=[V;ZYdIZWVc# ,fh֞'XgBr&5prluV~k 8((- -eGF8*ӳAIrXO@@-^FeD?Ӛ 5NbhRPVcby'+2%IYzZ|O#CVcWheb9rs^UgV2TQd:HJjL(OX" tE& -)-f`;{AO:{N"w.3dR[u'n #)CjbⲈE2фEeXˆ:޿{T1v$82O:HBZйr#Q b1C c%HPAj{Tq-/R1EZ2$e5&X% Ee5&VY>h1CKyxe5&VlUd1ƚuВQYUkdHE ,nu' ,$YznYvXWχXXs '-fh;y1BXGiDX1F%EFଌc3P"Ɇj{r(f` #[U!E -l%. -ꢞe'KfhkzYZ[vXqe:XZ9'UhG"J#3 b1CSRE9&pCm2@WUFt 6ib>d۳V^CK1='YI륰JfK1d՘XWMfbٲxM,<^[Ve3DK ;e1C+J1i}yP`)$pxe5Vcf# ,f`Ql4X J;OP4 M,:BJVgŒ|rAb˪#'kb]#{,JAڲ՘ݳ,R -RVcb]+lZВHQYu2E痍uY|Db`Q,G%Ebhy7CRjhX՛= -fhQuhiYK1lYm},C ec]##ˍ5VC 8(ȍD0 -eN+^dNfhɓsm5&i^`1fluVFF16VdZ1^ :+3ꨎBX`1ec=9Yn>NR~p ,ju:"1ۑXzYТvXWEcMC, Ək Z%Ce5&VbjQeV0H\1]:V>F֊Zˎl^bUά$Bif0gME3&T03[:Ma`1C ecaG$V3]jyyQYТvXgpa,fha,{:9i*_!bbPlZXMKiVXDl $[H 닲*֨1]&Vzt < hV}E1]6303,wywh5pbSsӼ&հbݩX~G$VSVcXhebQ b1#˫ʪZ# -b`Ql0 3(9% S39_RL^,f`Vgr]eCXiԅX# QuF*pm2cޫQG{::37HSSL+B;+hVF16V% 30zYv#3$VVcՂ4iڥczs,K=a<^0jV] wepnr- %BˁN}/Pr$fhXm(a3d;Ym|O8Aȏ)<10`YLAfho3*:=o -f`QlrEtG{?ONWz =<C|dVVcb h1fb]#] b1C,f*mRd]=S  d]ljaVr.O3d$BH NC[ZN]3rCX46֝{s<"1huΨZnPб]r#W8Y^c3{&B,fd%_K8Dvm2_C#|0),f`Ql8#b ,lx%3C+93+(EʄT`,fhUsj>%e1ecI9b1C|JEd -BpjG*E2#p,kPVg#jY16#C bԄ |:duV,Q#l)VJƊ"RlYefmd$bOK1 @VVcb%Y*u)1|O,CZkKrBXX1"WGfhsk:#O ,f`QlxΗű9q ~@Xow3]6w XВW뭿oe1ecG!bwb#U ,f`QlQ%;\j`1C eccB<"1 y.T Gf2^>L@K1ʪm܍*&VpMU bbISYZ9 u.EcoczUwTVg#% ,fhal, j-qu\fźb#[U_ {FbƲYuY~TvҬؠ,f`Qln#tDb`Aͪ5"E(30m20(VGTLx(C˹ui0õi1hc=H 5B! `WKc,dV$U.m5&YP`1C AXG+:"1X F!0KK 33$DIĉcd?!GfCbZE -juUZ"K#C+W{n/Z>X(3fiA {rՊd,= zZS՘ne@bl ?; y+VಈE2ȬXr\j<* 30lrd"̻'; $fh՘Xa*3"yYFE.cecE'/830T%8UۊiVGE1]6y713r ϚU˵7QB6zFbiOSfhYd]jeزEͲF #_J::6@ѓV FsXZ(ZЂF}'[P33hO;4 xjز]ֱQL3jbVbbiBZRxVVcb3cVO"Z9X'wa,fha,ǘT̿ ^ Dˡ(5 ZE5@ [ul)%ggۙՓwl;369#C c>JE -Xc=ZvXy0G$2K} E1x{%U$K8 s)p3 S^GQ!#w a C_$Ցճb503$G?)G3]6V 3d7ꬶ; -l{ZK_$R$`ĴEH OMX JEA - RVc= -f`Ql<7A,fh^N3]6V)PtDb`a,(}J -Cz%U,94[FYrh#ZF1\3?՘XR? )Z%U$T~&2Q[#4Yꬶ%Dl opТXfCfViޙ՘XMX.|qXLw NOfhbbŞg3]6 CZRnUIs\$p#bƋQշb:iZt0(U}N:|oJy]f~XMVgc7?Ͳ^ԊH -e"nꋄZ\%AY/bh1CTeϟBX4^6SZMXm(3]6%Xfў3Cke3'- !  8HQ;2%/e5/  pͷ[ -2՘XU"X4^6yuDb`B!YZNIF@W/B$fhB 3p%AYGXvXQ# ֪#,bhQTx#Gi ^@Q Ag}1CK&e5&V[ZiV/W30r,>-f`F9fd,FjT"Ɗ# b1C cs!ݭ9 UnYFZvXHXZ3bIIhC ec]b2cʵh =V XB:{يe)rƖ r+SK1}협˵,!v-:Q#K:ki1Kg_[UkE -꣉bƲ}fvn5TUkpPuF86@8H嬼LZOX*V{jeR -w߶+T&%fjrWhC Ɗ=q c1C c>rGf`iV1]69 GA,fhAvbꅩ"ƺzbIJ},3Z;q#ZnJO.TX2 W e ZK;llsZØSVcb#3]6V<{b1KkV[+W ,j̱ ((G$ҳ`:$#J3R39ݳhZRVVcbI=SY^Vg3plf,fhl5V[߳b=H ->.2s5CK~՘XǨ3N꙳~BhckEXbP}dV~YձZ.$:"1(!+=0C˥QkV35_<3]6VmFXǨg3]6Vb_2ͽoO*CG*OI(No/PIǛlc˃\_Og 4վ>1u6B=m?1Li;1޷yicBj>m\Jmwϧ<[v^=4C|Rb=.@Ok2mpCliSFmt\ZIcn)1Vak$OViжTx~xog<~R*YYvxaV.ˮ\3 DW%S23] 8ż`&)9vJv麶KN.׃IW}>qm~=<{[3y֝ή繟gγح|Y?q#mg\.53++Vgy{/-kVr]~l.\w.4 ܯqq+cWV>V =X !'ϋW~c|x}ay$?yfr>ae +f~Sܮ}JձO~M c'W_~ӽ_õqe1tOųb emv=ҚX2Mk:N~{H\flqOVnjٱ+ώfe/3=_+eE2/ nNv Cchg/Ƀ/1`i,YiKv2׷`K6vA,U/L,s4L]y _xOѹ=(mEq9,gCvNn?JP]Ja6aNUrHAvmʲ9esz7-$(Bu<+j8~pbp]nFگy>Yi^Org:~=e\rӗi9}yyK~- z5zr,{/~yc~Irz%xnt ׃UuOVի oYU˫'O=X_F?oYU>^wzh ;'[M&K<}ia=Z|68~CA~=7\ut<+s׹-gJ:c^=`lp,\ܯKaWbOv?ZM#+t,gO eQ=*~:=XJ烥(Q"dm=r, Q>Hx_/^i%?++WڳJiT4("zԡml}^Uw ϓg 9,,G堇S}e, ΋rTXmwڔ߿d'+WG+׷y勌|/K/ 󻿮׿/vWouc>Ў+udU&Ԍ1/G?*Z[e.E\-K߾}|ۯqEŗ?VFOƯwu_(MU>/5Io|){,nyIwF^ _*t}QV~L+Qrq+}:8q_?~yǑo?c_KJ-W?*;å(k_o}|xe{]]V◦T|g*NB-<ϯC)L_0S_vG8B\y'lqW|~lwy#wȾ>S |6?@(:)O}lG:{wtidL}>?c`w]esGڹƏRځ}h|]?e2 }IgYx*^~Y?z]$q{!3IԓNҫ҈z*G~e m>kb(QfSbv Ѽr_z0ܾs_sM3}> stream x]KqC __7|;zva=(Y,a)Ba ,v ,@GuUfu`׻ 8ۨg>ٰ̬3gїO=;<п]=d7 9{jΒ9ø\8{ƦB4)s^xv/;o`|؍S<5Ctۼ.& OiZ367sMEyzOso8+.Z7fk87x `0>43 &-<LtJ.Dێ;?QCm14[?m qܤ?~]BI6$6Olq+ W6FXpXt`m}$wfh\aΛtv.ȧi k&m~I>MƝl\q)= mb_S@0[hcl>ta}&W̿(97-P$Lw'`'84vSጒK u&Onl78 S%VT8rY(ܖߢэI~ 3j{89!-i -](xH2Ժ`AzY3jȝ ;Avgn㞲 #Q`@ z@ 7pQ=XY 9 <`)7 4O737M)EF'K&?{!xVь hA7> 09"ϟ9"%^ƻJsWBay>F!UP1HRte#Ҳ$?Ds#mgQyp*y):\(aEao7Q)٣?X┬~HE!i-)4(LeAadF]/] )JOUǥP^inU]ӆ}:mJK).{_hoj%L5bg< }@s%H~ aW㽨D͑9{:G݉ 9Ѥ ֱv=,cg8aZc L9rU!\GFkx)sҧ&߬z>_v6i/r61ٺpN+Fƃ &eGhsL1d X"ee1{qzU. Ri06AZEf'Jd$W`u2@BBFN7% ^dN$?c[DL5Y'2Y(d ,9 `c-/Y_R]h/O\;`q-U}OF:%5{WCП邮5hsLq|SSiF$|6i-pY8!_3.m~+ąr(/A+1>/'~ ~D|b[n1] Vz.Mr%7IC}S`ɧAI/7JVtΰWm)8RWrG{ 18~j&YGdRӾy4Dr$I,#w0p'k~fv.FlCe 4A)ѯM1$q+G=Kn)c%[weHE&δ:46I(!\EUGi/,mlZz`k3)SNrM9@SB2R=}r^NJ*9?&#yrZ<gkP@ŮUP<+q8ZodF49hZLK f{C'b a{mrU=EB8_{ muYsbÈXP"ez0K]+iN$goeMWx'b6 ٿ%Cv0z"/ @`~@rX%m@s?O[7¤S^WU$c b[2U!%>9]4^vuj T" Œ;/Lny pkJLJHw5 Bc#7]BS92P!eI'ku]%1T 3p79/iK,ңx uuTQDɄGDF@( !_5l c=u7 Mh2!3B(Y8=ط eQ FܵV1#uI_w^BQD0.9f5aܑT IXI LtaěMӪ>Ii (0FM }t2n7/?*޶j08 _> 8pj~R!/%YZ~7:pfK-yjros<{_LiHoV`kiq ?x( OF=xxYpgxM3rPx =:2PŨA&?tڲl+u\y=0@^-E;d5W6}E; NMQaRq65J0`Xf_8&BȽ#ut#wlT{ 羽ZI冬nfS(D'|LoXҨ‰5ze%*~d[ǯ&C ]s[N_%B#cyǎ>ǡ k,QRpj&hd& {^Z6HPl".+$/؟bPutNO5D<7~yӀvLJ)Ǧ`DZx7j;sĊ͉p6@L$"Сag f4{b@}c޸ "ubNM&8 hEgJ5 s],W^d}]iUGFrԼGlr?Q"knʡUsX\#j0.َYO Zm(S%Jdi,V?j 뤌UCƹwqG:O?ٖ-T2'ɜM\\o f`ȁKaR.3oJvD 8\tq{\Yʾb1 S/N!yބgFlʾx7ʈnֈ>&mtLk!/6eFgPDrSxC{ͳV]TknylHp^"`~Oad΂=z_0Dk<5DtfГyRjՈ_m_^dR`[8q@/Fw%, 7';*oNQ8pG,zʧ-1@ʉ:_D 2=LjJOswvЍ%jF#LhӯEDZp_BZP قM6 T2&Bfsӆ6-vw(DI o( fC[yPh+\;\dD\(@*43fx*COp)TL40o!(򉲀^(X󙤬1A~vژtoFGy@vփɢn si "Tr֚%b8tv#r:/2*娘i\jk hK6В(2kMNA})LGldtr;: v~'JIۑ'ʌ>OyXZnHӫs|,M:{MOl%ge,#piYDZv\ǎy2D9ѠrMa`_sl&+5P+XuJ\2ɂyՠBc 5@-4TR ĹdMFItTG/1OPhh.CM% ׋gV[:Ry:z3oflv/. 89:iɫۥly\ 7MaђEsINCc UWX$xSZPu4u:o$8cW6ԫ4XuF 7_ U@A&krA|E$f; ݬ6z!~ ?tm4v3jѹgs7ցwTڎp{&[;3/i1TჯcE )nR26\ޚF(/a^.`3GrI ţ>>FFA׫שc.9Hfʆ &l@Ņ\Qe0Ull; Ukb SΎT&*1Xd41<؍dNѪe6te{- HQEUj }w8?֘OX :2N.ދNzX^BO{7TB>̆z'/T;YcǼhئ 4MobɄ6.cguRO~/`% 쒽ςgcގgMI(2 Xxi]*A#! (ok3)w2`NGfWMI>4%YKs3›IhC =ZD4'`FôMIxF3:I8H[{4MIA>+.X+2YQ!j_Yg )\x 0Le|m Cl!~7aR viKR.~u0Y-[ZњxR(_lN)ry1s|f}_ߔ\(%yT*rNlC]aMCpZ>ʻt* ~XR!+:+8Ⱥ~m#'+УvtSHOC%YtqrZL{'X8cQg)]hW=՜D{yuϪ)ؐd˷W |$e 6FUK>'2 Y/ {#s V]0\DlFAVJEMN3ܝD55ε §?yM:P)w<:&4#Z$IpW6xo^3֍ XT1oL~L@BW[6LC5%`u?Іq `'A{ BPrJ/=xo;?H73`u%_'+:;7d%:9V- Fs]rx.b8fzOh ;.E~h|K8Qꓪ1eE58#֌C9`pR?SP=z6Us'N q5.՝EwkEi[|R~^{%Qxb|**$LS>w/\G6`v+H$\ȍ HёMpPtEq;m4j3px/C.2/~/ 7@iE2#`['rKr5&ا|?<.?jwY_f|ý`w.}yF6^PCPlx 5S䳖TG/Q`[ye`s3pʷ.pŚÏZNtxƘHlǐnu͜*{y mo?Pn0m['0)QZWv>Ð5ߑ8'nVXLq7ek+K?l_bKM _,*hmצ;#\:6Wou:|)MRb3 IT~mcy,!0mY' igmZXKa+ۢOکPsfF#?&DK`A?L\uYŎuK׿w*> stream x]Is7k}ʊӉpmf͡DJ,qiQVy xBrhtDGN{׽iT{/';3E9< iJj;SM{1ΏWiԓ&pz?al^;1z.ϰI8?fJf_EѥwyN)@}603M1Ay?MXvi؊ю`Gu_˼\u^! .{3vut<ξjo߸1zM *8V4&x\O7 JduR#)=rO>a&S>`Bd=:P({q{i) R~wTFQ]n-a8c cZ&0n]Pcx*)`1i#;0qrBFL\MI2s&ֻpU/WU|HׂllRyVB$-t&pD8%LHt{[*_o/u_Y۽}eFg۔R!)Ч7Rk # S.yOtL P!qnOd$8ozO6ˈRCO\%˳0O񷓎6|N, ]'sx 4p_?{{ʑN&t.+ LZlJzp,va? DE-o΂xXyD>F`Cq˃ax̑r0Y:)g(at9tc䩲Ryr&Q8iβs@ `tj% *kPq(3۹1P U])=(П p.J 1iv4k7 D#40u|HN:LjӤTV N%[7/JwJSN-&~ }{qaو*ʠ?704ίP;b +8i`~H BO!E>Z0 XӨoHf/"0NYdʽ5F+AD=R8ytp ŀtČŌyx vMX]ԃ"@0$hkFB61#c puJP"܌$WfcDWRcK~KGw~sS͹m{. :>4qvim~m96/jum5bY;Ywcz֗8*mMS=Vԇ9H4StĹH9ӵ}"KMD:H#&$%dpdÅH7A#; Ik3Ktee8(^B-ұ|~Dq#wfÍ:tW/dBuER& hQT&\;bjqB BbnALP* h"LC˥?&ϾdaV==/oH>h-5,q:a05`A׈)aUyT'Bq=2'E?q|Z/ppPU9d/BpŨbcJvS ~Wk^hHƻ,KW豭F36U&{Dрd%;hYߜVUyў հ^|_jq.F2q@e;' 5^DOY99Qz9|r>P&v%Pyjp-nuݺ1FTAjMy^WjkAml}*HHl!gyg7=5NḻXwG6~pAwV+؉Ԍa0$mS&  U6 =+Om8Pd) #gO1<2ݞV\|=nИɓM7[!1¡M@ 1vkb(x^S2m?ZF薄 RxUNd}& h)~]z$nqWH':CkWppTϠ~SD9sgZ ~15 h[/5PAailk8}f2uF) )N8ywЅ+܆pP; =kG 8҄HWڈ)U7o6 Np V,Ȃs6?OwW56/o_E߳|;nXYLh5>vMǵImR6mn_%~Wr{ցpvt,]/I)ci4J !_&}$A5 9dmxc8:69؞0MD1Vr|VJQ̜ Rp9ZX lskޔYd"!K+O_=Rs,OQ[TOR?y;&aUOx9]2`rhW2#beœN6mRc^2X"ʙQ0@ ;8#) ˳NEԐx]Vհ/IAda@|3O6%yExV,@ycM rodJ0م/, DiJA*KcZ &f&$ c uуw&͹SQ{nƂ]XƾeCF,>@V,%r. @K.%m[L}PaK1wD];vT,e(/I0۟h7M=$M~i>/lG.} 9s.ZvB(•W_NDq=E=\\4a&LeYɢ-Fц=~VVmjkx>*ZXO1#m"9yTq8jGy>ydX2\? [w1&gpRo/sk.Ɯ6˴e F.;p{wUsM᜻~=mm?imOU"F`mUR?ثy[O?{7Evam HB.>+}*Ԃ2zQ8,L{ )Vpԩ߅,hOwptP@F%YC {nsNdqZ.ϛ=(G%oT2DCB)ʁ(=ޱD``YV(q72T?@JlEcԨ|h6ѷ<r-aН_;0&jJdMH"[J[~Z+eΨpgI&1W|}H$2w L,kvb] NDsM\?EE]e9?kKd@/ 1x8c1Y]/H|EIU4XTVA9߫JXEZU++~bEn[GM 'Oz5|(Is-mn x䟜[O QX`MZX+tEYJ]O5zNh<ƛj'd՞N$L$[ M|uԦ+TVm/-b. +tnKUϸWWy[ *RQ|]vrw)k8pB+I) 7|˯p8V ,fk:v}:ldUXѴ c"%YvGv>`t{;HGd *f`O|"b m!2.)d|$S}Qs  @:qi8ɥE:K5=tHצ 騕t jō-( > stream x]I7rӎW¾0b-=Cq4\l><5M~T7q睙@ TU/=/71?No}Ш[֯$AX/cQ<~~+}*<֏Qۃǧ-6!Zk<~vÏ1iV>hN =<^:7^1,*) f -BM_ү6ܚ" /;T?\*@g lc^Qw2|W~=*¯ƠОwò^@yNa ׬{?*H Msl*v,hT'H;|CM +0RrJx2l- 7Z4v+ mg`;mV18{36A!6i QM 3IieN!w/heûel*؟JcѰN>jR-]ahCRa^xy#4" 40'=tZep5&{l1P : 0+VޥKݪi.7%WQNFSZ Xt`m#yO^:A9M+u[_u]QGY =ƲE}6g:N 6dK U 9#A*L .t08"Dt0҈hMt+aon q`Mm@aJx+ALXVE %Jmߘ&p_E8v MQyHU(,}:v 6Q;ay z5T^?ýqCz[ ,LV5 ZsWfo'Hfl\`д\^3c\Y|U2Sݦc$>n4.h,JS8V9XxpYz<Ҩ tw%L ES747)$#eġ\ջhfhZǾ.*09yZG?Aػ~4j[&֌IE:{Fc"LxGdZbCYNea@lO1 62EӢL.e"#A& sHQṔ`8"5]c wn#:Li;sfr^%9k<ߕLc5pFš^ENA׳lFdbdvE_ԿH0E n!*Q6d8L.8;+l/]K7YOQTSvͱ!HSāM=+0l<9ۈ7%~!+)f-߮Llz'ǎj+LZV}٫KN?'kIF8;ȱŨֱǏ##ԦuM 8do:gh3j#$8=ʀUkܫ`Z&ۃ0,dឡh tyxCfG(/ROfl$Z&xL<ԆWmb$>-Z@Iܰl(٭M5@t͍4ȍ"y `nVDo<w%zpVʋujF<0ߍ̔yAWk4m`{ kQ Fq EdQq%*4\'?{J_B ?dRvhRV4y\ppw&7)E#9p#A † )^c= `R,'btݛ:#6~4$%qۭ1Y^]E-W%9[nRr7YVYϔ/g77811KfcMf'5<,$ܵ$Vw G3]QlMU#eg3lڪX|Ja)p;.olIw~6"*N̪>iSH[ 0W~c L ]l`tپ (m<N8:[Gs257x`Z<8.օ@Tĭo,_̌v\Gvb'bc-vjT̔w82f8| {M:/==?R)b$gWn(?fv=;30gL#<CM͹63_/')\;AjGn~BɜXF{1fKBʷeS٘g)({T(<*Ԙu0Und1׀A䑏1_0COIŭlx;hmFg ZADSٱ9!bGQ XDH#!ґG+Pco1KZ<8.֝ȀQމ\["cIQ 23fFGYZ,X(&oUN=,:3XnPI ӗm||;`!~=9v]p>Kbi=gR҉Jj=ʛ0B4!X`c_J?d}[ p̀fױ) !F'M<LWElȋ*^N ]w}yC.}4k)oǩ:sRQab̮O&`,üEJ_ J4 ȁմ/,w4 7Ydӆ9]Z(-V_ JB[g(dVE)s-OF-:*vЦLpSfwfzSp>o f1\W޾6l)rً2/J *ɈJUɰr]xe]l)Rpq@(|vkbK |?}@!rv5`UV40''=*Tt 'gc1D!YD߰<>X1#@ $*Fە8ɔ&O1NRVKe;E{Igrel.Y魹}O]ʚp3ʥh53ư5|)8H*쬟UO/s070bz*ȵo#ihbk5n˫I^Ou7_-XڳY#%Ie_Bsli0Ʃd^{.>kQMVT(0]YHcG{,Xdoɕ08Z O -S&%2Qz*rL`ES_-?\U[[2yY,Zd+uźȼ'_ZEVe-z9u-%%=%*z`я"K9$!d{ /gj`f#'䏥'O/4}(T!\'JCjQTD=/prP;9h:hzވJ0xcoj[`V, &&j2Hq Y&4KZO=iK*`2J @CZ '@Oc 3c&g?TͰ>y8LgVaŪQ~Lm#-1=<j'5?wkt)k `rLcidU ?4L꟎0~&'-q ( %j.F7) a?ӗ;k>4н= 6oh$"^cghRI[6i[ַN\8;o*Wf`A`I[He$KDdʭIyNS}ʶTCV3c"6+frU-`Ҍ'N[1a"; mo eaX|;דˆY~'A~}껝El]jX~UoX//65;C&zv^,^4&_q5ak_Tޒg{tbGl( h'zԌʸfyMYjM.ͿP5K1O0,a"Zq*:{EWgXhhLmƊ {Z'#󙽭1I/2 ;ʲ?mkIi糚Rq,CY_lzioJϓKݸ+3س)x]l"Z8ͅpBzV,_! %Jػ[t3n*ѲJ3V1W8ZW!UwX?)}Ƿ`uUZ.{f!ŮE}2Z a2@ܓ3نxNo`KǮOoQ㮁]/?[#ep`SZ#=38wSC 3QM{ߝF߷yB0.!C_BУq ћ"= QR> stream x]IsǕ:Du}a@Z24%sbBCAJ$@0-Y/Ф *dmS;_=vf;;W9|w)Hz;Sg]glӷw~RkaxMlH|Q)׭toYos Χ;ۜ9|h}>y> ˃lU" *EcafS)axMXy؈ю`G‚M_뼸\gLY! /{迟~g 9>=3Xz}޾~e3 sJ)G8 qnx>p٧< +tfXC = VsLg=j"[)Lp nx|3qq 2B|.nO64-ߕfXCm|a`wh$7M^*DŽV.4.jY"ѱP\l6(HX:> ~]4;)k T8S L k;1yn_en](>= ©?q"=|G|Y@KL!M䖺q5☻]؞m`"ib% I uYƉ!PPY!gU;]\gWRLwh Xz]YA#u?L㌳w`'T8!D=J1C@HOm3a߳G:z a# A2ͰޝQrfyCtphP 4PBԋRV`+Y) 6Gp6K\HSUCl0šÿB[n0Rlڠ v1o쾠G[([ِ*b;;P$ w9bڏ>*Fz7 µ)+mZM!8ds=rs ו;$2`\*80q%ڃ&O9:t+$_Cs K3[ P#ڋySTd4@avFDD#m8A{\R ݰ #A7k j,G9t/ ~:&[(HM;ˡٽiI=.C[imñ`+@@xDF*ٮM(EO0uYy *yPuwaxXDq_?;ps;_vy? oWB+*͙x~yFM(6m>hǭyКZs=áNN|ޚ5[5/ggΎ{2!v8]̮L]kv>׭yњLqYp&>zƢNEdf)@ԿeB7ĂB:c;Q0H~x@*zfP,VdjlQ,z[B_[sۚqk by5_ϊRbv uG{>5BUo>GN=wn`JD]7OthWhtqL^7-<+u^[YkgY'f'aWu"Ȅ25^e%7<8GT wZUá,1A?Pdnq0FORZHKj/x LESm7YhFυłSѪ$ racF *a[f`9s`&OJuP 1B#,.18n5,l#\|; n"n. Dta AlFӅ G)332u)93 HK:vw߫'M"`sj k"`.8rM(8TT0h:\X`t]W-xЏQ!~wYG./mOC*Uy*saDw*unǭ9Lg%wޚ5[Sd_\ζ5jٟͣʾ̔> }yP0> #0aρwNGN'8W\@6dGAd Bj[?4'S/42ʢ`-:SC:ɱizQMa-hNj< -,r3bk!d8F-frmWM/xPC8 %K"p^l&_(oN@[uP[&:M3K0y upUhkw&nC>Zǩo(BΩI*r'MLm? GݥM,fˡd7cvT{,YK]|.aSD%!0el 4) b n%qmU%_^kî@i6p_^i^SN%3?iiO C۾\eSk["_a"9&E^3K5@/ίA@LZ,(\98/T.HAe甊t6/*SHW,Cڈ@]4g[10܊=Rj28,E;dƺ]ؾk^i 0ێ)+[RB |ɂ٠0%&z 2O;zYo'p&ƨ}-"Jdrkj<R9`."5*/&XODo8_ ܔ,%vlɃ魫Ru6B}!N35@dr|A[,'2DZD@xH ոs /8࠺ 6\C#4+#z88jQ΍e`MwN MxtD˛kZFB #NCNIfN-_Ri2Uq=0U%V56?[_70V^ʬɲc^MaF>۸1uxp2dVg7X/T'E Ekqx#s GiY0:˒Pa.#o]#uw`֌2cL?GD FYEHz#9D=ovOa AlvKY]:oy Pҝ32ޒceeͽվz1ÎZ^M^bP_Cq"0pϜIM|gN5(Xi5DnHfNQu]-:.4TP 5hZ9v0l;0{\; +OdEQ,s2̉E#KjbA~__](`M rڳ,% _Tȏ#K]RtiAU5 5XX5$}WO_B6-g4@e!-BzmAURc/hƂ' 2j[2*4G<;7$Nq# LDF\%!K.]=Ws+lu%CxD7<bWLQLE_\^Յ9;܎IKq->GN[Jm#MQ\7 4X{5-)]kXPBʔRd˒  IXWhg"lWJdkX.,̎>&Y!NCA\G,\C)ΔF12\vkxdtFيuys s؜*ysj6\[l9KH?;In}|=%ވ~Rt ׿3WL-`i9\;Q8Vg`9m[t%CzƖݛ0;O[xƻ2q iPlK}KaKeVvAqd *y(%h/1xifA&84t)P=Tl;Ϡ0PX(`<ԸL'^V  kDqU͔"˕r η{e* h4>i#>«^PBϐK1%*ԞeEiE40Ncrep&Ǹt_ lA23OCz2tʃmꦝj,Ok!Uu3?Ӛ8Sk'ֲ3Iz:qʽN8xFj tHYը/;kZTK [&B݋Tt(Loo8} <0FCM9(hݳsdƯoP9eٮ^/&ۣgl]%2zީSչGSanmí/! ZiF9kwįw46)g|骴n Y[￀GsZzᦦ(e{*R}?,m$L3;R(\73)yݚ59pyιJ/`endstream endobj 496 0 obj 6991 endobj 502 0 obj <> stream xYKaBGib#Xa> /!yUݕ= #@mOuVVߗURz_lq[g'W =&i sp4'6wF*E^TO1 +asV4pK&19O}AxNҾT.n(*ZE20d${f|afϽ@O!xGSw#I[8" \ r299[PrH4 omZ gLw,t<(3>G $4wޭ X/0Z>p vj%sL&X8d5d M/^WtIY#z5:1g4@O)#cMg+(O9_9ӕA}p$){"ۺdݳͶDaU\kT˦ @b^ VujyU 4.q*Rp_v-2{8O> )eMdP/83 ((:#¿#N1&cV^(R6E Lvg`^Kk@B"S7Ae7d)qЕo b%4J]H?Eח)f k\ AWfPi˺wјA:eۈ@fG|و&fuG߈*u]ĬxW~V\cJj,:8Y~Ge9%7/MB%JQD]I?F rJC ҤG8/a}<|\P["$-}1B-Fe턇EONJbs55+E! [V@йSr5YB(qQ.mA+ J/pw:+Iч3. ^{c5̱G ib"r 2a9_<;Xyؤ^;lG}|JKKОnk!oS9ZC,f致G1*+WZd^jt2ZPJK ҧ)1}IgU69a'f rۡ$FViGT6XF|$s7\hFJȢ ،Wfh ,ʴl&6<9-/+r> .8Qe/L ,BkpmI$I=S #W!!O. \DnS~.I_P3ܼ%'קI;z+⫋rKGg|G3.;ZgtրDTn#kS'j)Q[?*nJ gaAF%c70bb< O^*BN?TvwOtXrO"%7z:ãW2m%Vg(RCłN?.8 -|U΍@w=YZnF\[W9 h0-n/ avlNJv.fy 1fV>)1MW__U颭G26`ha8+ypӮ@Ewv (Syܹot.}BP].?j1Ln6=F^N1D))SUݔ0`rzxmU~І`JOx7pUU@6h|D,fqx gS>KSOH|$rO'rCpgW@XtG0%fT׵%w}Enٯ"~D/P6U(!݄J J;&/(ߋ Pendstream endobj 503 0 obj 2493 endobj 7 0 obj <> /Annots[35 0 R 36 0 R 37 0 R 38 0 R 39 0 R]/Contents 40 0 R >> endobj 4 0 obj <> /Annots[61 0 R 63 0 R 64 0 R 66 0 R 67 0 R 69 0 R 70 0 R 72 0 R 73 0 R 74 0 R 75 0 R 76 0 R 77 0 R 78 0 R 79 0 R 80 0 R 81 0 R 82 0 R 83 0 R 84 0 R 85 0 R 86 0 R]/Contents 87 0 R >> endobj 98 0 obj <> /Annots[97 0 R 99 0 R 100 0 R 101 0 R 102 0 R 103 0 R 104 0 R 105 0 R 106 0 R 107 0 R 108 0 R]/Contents 109 0 R >> endobj 9 0 obj <> /Annots[125 0 R 126 0 R 127 0 R 128 0 R 129 0 R 130 0 R]/Contents 131 0 R >> endobj 146 0 obj <> /Annots[145 0 R 147 0 R 148 0 R 149 0 R 150 0 R 151 0 R 152 0 R 153 0 R 154 0 R 156 0 R 157 0 R 158 0 R 159 0 R]/Contents 160 0 R >> endobj 11 0 obj <> /Annots[164 0 R 165 0 R 166 0 R 167 0 R 168 0 R 169 0 R 170 0 R 171 0 R 172 0 R 173 0 R 174 0 R 175 0 R 176 0 R 177 0 R]/Contents 178 0 R >> endobj 184 0 obj <> /Contents 185 0 R >> endobj 189 0 obj <> /Contents 190 0 R >> endobj 13 0 obj <> /Annots[194 0 R 195 0 R 196 0 R 197 0 R 198 0 R 199 0 R]/Contents 200 0 R >> endobj 155 0 obj <> /Contents 208 0 R >> endobj 16 0 obj <> /Annots[218 0 R 219 0 R 220 0 R 221 0 R]/Contents 222 0 R >> endobj 227 0 obj <> /Annots[226 0 R 228 0 R 229 0 R 230 0 R 231 0 R 232 0 R 233 0 R 234 0 R 235 0 R 236 0 R 237 0 R 238 0 R 239 0 R]/Contents 241 0 R >> endobj 240 0 obj <> /Annots[246 0 R 247 0 R 248 0 R 249 0 R 250 0 R 251 0 R 252 0 R 253 0 R 254 0 R 255 0 R 257 0 R 258 0 R 259 0 R 260 0 R 261 0 R]/Contents 263 0 R >> endobj 256 0 obj <> /Annots[267 0 R 268 0 R 269 0 R]/Contents 272 0 R >> endobj 262 0 obj <> /Annots[282 0 R]/Contents 283 0 R >> endobj 270 0 obj <> /Annots[291 0 R]/Contents 292 0 R >> endobj 18 0 obj <> /Annots[300 0 R 301 0 R 302 0 R 303 0 R 304 0 R 305 0 R 306 0 R 307 0 R 308 0 R 309 0 R 310 0 R 311 0 R 312 0 R 313 0 R 314 0 R 315 0 R 316 0 R 317 0 R]/Contents 318 0 R >> endobj 20 0 obj <> /Annots[322 0 R 323 0 R 324 0 R 325 0 R 326 0 R 327 0 R 328 0 R 329 0 R 330 0 R 331 0 R 332 0 R 333 0 R 334 0 R]/Contents 335 0 R >> endobj 340 0 obj <> /Annots[339 0 R 341 0 R 342 0 R 343 0 R 344 0 R 345 0 R 346 0 R]/Contents 347 0 R >> endobj 353 0 obj <> /Contents 354 0 R >> endobj 23 0 obj <> /Annots[358 0 R 360 0 R 361 0 R]/Contents 362 0 R >> endobj 359 0 obj <> /Contents 366 0 R >> endobj 27 0 obj <> /Annots[371 0 R 372 0 R]/Contents 373 0 R >> endobj 378 0 obj <> /Annots[377 0 R 379 0 R 380 0 R 382 0 R 383 0 R 384 0 R 385 0 R 386 0 R]/Contents 387 0 R >> endobj 31 0 obj <> /Annots[392 0 R 393 0 R 394 0 R 395 0 R 397 0 R 398 0 R 399 0 R 400 0 R 401 0 R]/Contents 402 0 R >> endobj 381 0 obj <> /Contents 406 0 R >> endobj 396 0 obj <> /Annots[413 0 R]/Contents 414 0 R >> endobj 33 0 obj <> /Annots[419 0 R 420 0 R 421 0 R 422 0 R 423 0 R 424 0 R 425 0 R 426 0 R 427 0 R 428 0 R 429 0 R 430 0 R 431 0 R 432 0 R 433 0 R 434 0 R 435 0 R 436 0 R 437 0 R 438 0 R 439 0 R 440 0 R 441 0 R 442 0 R 443 0 R 444 0 R 445 0 R 446 0 R 447 0 R 448 0 R]/Contents 449 0 R >> endobj 62 0 obj <> /Annots[453 0 R 454 0 R 455 0 R 456 0 R 457 0 R 458 0 R 459 0 R 460 0 R 461 0 R 462 0 R 463 0 R 464 0 R 465 0 R]/Contents 466 0 R >> endobj 71 0 obj <> /Annots[474 0 R 475 0 R 476 0 R 477 0 R 478 0 R 479 0 R 480 0 R]/Contents 481 0 R >> endobj 65 0 obj <> /Annots[485 0 R 486 0 R 487 0 R 488 0 R 489 0 R 490 0 R 491 0 R 492 0 R 493 0 R 494 0 R]/Contents 495 0 R >> endobj 68 0 obj <> /Annots[499 0 R 500 0 R 501 0 R]/Contents 502 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 7 0 R 4 0 R 98 0 R 9 0 R 146 0 R 11 0 R 184 0 R 189 0 R 13 0 R 155 0 R 16 0 R 227 0 R 240 0 R 256 0 R 262 0 R 270 0 R 18 0 R 20 0 R 340 0 R 353 0 R 23 0 R 359 0 R 27 0 R 378 0 R 31 0 R 381 0 R 396 0 R 33 0 R 62 0 R 71 0 R 65 0 R 68 0 R ] /Count 32 >> endobj 5 0 obj << /Count 4 /First 6 0 R /Last 34 0 R >> endobj 1 0 obj <> endobj 6 0 obj << /Title(Introduction) /Dest [4 0 R /XYZ 81.0 733.028 null] /Parent 5 0 R /Next 8 0 R >> endobj 10 0 obj << /Title(openBUGS implementation) /Dest [9 0 R /XYZ 81.0 248.006 null] /Parent 8 0 R /Next 12 0 R >> endobj 14 0 obj << /Title(Incorrect R implementation) /Dest [13 0 R /XYZ 81.0 682.015 null] /Parent 12 0 R >> endobj 12 0 obj << /Title(Two R implementations) /Dest [11 0 R /XYZ 81.0 733.028 null] /Count -1 /Parent 8 0 R /Prev 10 0 R /Next 15 0 R /First 14 0 R /Last 14 0 R >> endobj 15 0 obj << /Title(INLA implementation) /Dest [13 0 R /XYZ 81.0 423.225 null] /Parent 8 0 R /Prev 12 0 R /Next 17 0 R >> endobj 17 0 obj << /Title(Comparison of the implementations) /Dest [16 0 R /XYZ 81.0 163.409 null] /Parent 8 0 R /Prev 15 0 R /Next 19 0 R >> endobj 19 0 obj << /Title(Discussion, extensions, pitfalls) /Dest [18 0 R /XYZ 81.0 678.472 null] /Parent 8 0 R /Prev 17 0 R >> endobj 8 0 obj << /Title(Besag-York-Molli\351 model) /Dest [7 0 R /Fit] /Count -5 /Parent 5 0 R /Prev 6 0 R /Next 21 0 R /First 10 0 R /Last 19 0 R >> endobj 22 0 obj << /Title(R implementation) /Dest [20 0 R /XYZ 81.0 332.714 null] /Parent 21 0 R /Next 24 0 R >> endobj 25 0 obj << /Title(1 block, intercept) /Dest [23 0 R /XYZ 81.0 313.921 null] /Parent 24 0 R /Next 26 0 R >> endobj 26 0 obj << /Title(55 blocks, no intercept) /Dest [23 0 R /XYZ 81.0 178.064 null] /Parent 24 0 R /Prev 25 0 R /Next 28 0 R >> endobj 28 0 obj << /Title(55 blocks, intercept) /Dest [27 0 R /XYZ 81.0 494.145 null] /Parent 24 0 R /Prev 26 0 R >> endobj 24 0 obj << /Title(Three variations) /Dest [23 0 R /XYZ 81.0 451.288 null] /Count -3 /Parent 21 0 R /Prev 22 0 R /Next 29 0 R /First 25 0 R /Last 28 0 R >> endobj 29 0 obj << /Title(R package CARBayes) /Dest [27 0 R /XYZ 81.0 337.299 null] /Parent 21 0 R /Prev 24 0 R /Next 30 0 R >> endobj 30 0 obj << /Title(Comparison of the implementations) /Dest [27 0 R /XYZ 81.0 119.606 null] /Parent 21 0 R /Prev 29 0 R /Next 32 0 R >> endobj 32 0 obj << /Title(Discussion, extensions, pitfalls) /Dest [31 0 R /XYZ 81.0 343.777 null] /Parent 21 0 R /Prev 30 0 R >> endobj 21 0 obj << /Title(Leroux model) /Dest [20 0 R /XYZ 81.0 629.935 null] /Count -5 /Parent 5 0 R /Prev 8 0 R /Next 34 0 R /First 22 0 R /Last 32 0 R >> endobj 35 0 obj <> /Subtype/Link>>endobj 36 0 obj <>endobj 37 0 obj <>endobj 38 0 obj <> /Subtype/Link>>endobj 39 0 obj <> /Subtype/Link>>endobj 42 0 obj <>endobj 59 0 obj <> endobj 60 0 obj <> endobj 61 0 obj <>endobj 63 0 obj <>endobj 64 0 obj <>endobj 66 0 obj <>endobj 67 0 obj <>endobj 69 0 obj <>endobj 70 0 obj <>endobj 72 0 obj <>endobj 73 0 obj <>endobj 74 0 obj <>endobj 75 0 obj <>endobj 76 0 obj <>endobj 77 0 obj <>endobj 78 0 obj <>endobj 79 0 obj <>endobj 80 0 obj <>endobj 81 0 obj <>endobj 82 0 obj <>endobj 83 0 obj <>endobj 84 0 obj <>endobj 85 0 obj <>endobj 86 0 obj <>endobj 95 0 obj <> endobj 96 0 obj <> endobj 97 0 obj <>endobj 99 0 obj <>endobj 100 0 obj <>endobj 101 0 obj <>endobj 102 0 obj <>endobj 103 0 obj <>endobj 104 0 obj <> /Subtype/Link>>endobj 105 0 obj <>endobj 106 0 obj <>endobj 107 0 obj <>endobj 108 0 obj <>endobj 122 0 obj <> endobj 123 0 obj <> endobj 111 0 obj <>stream AdobedC    %,'..+'+*17F;14B4*+=S>BHJNON/;V\UL[FMNKC $$K2+2KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?Z( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( 8wB2@O~zuUmG]Qm=q(PĖFGf7@ڀycvF+qq7{g\6rH?Ȧڸfk:lArOO_ZP Z Tw!w2Pc#w1ۜ 9Egh\V!y_N8>v9ckm9}&U>(EPEPEPEPEPEPEPEPEPEPEPEPEPEPEWT2B9L/תP}*kح. '}O^1Ymœ{6>XApǒsqxS*Y3#p9U(=rWgQErq ]x<5kE 1Lc$s-x7NBUbW7.ͼ_&9^=X.{ $@ⷢ#6wJd,z{qqܨKbj((((((((((((((((^mK"-a*찆Vaހ c5 }7v mXI!anߗq$g8V]c`$O+^H^7jwstYjLYFUJ0g(,srMim6)m#[9Y]bDLmc$fx`$`.@tJ20UXx#*YH#i$`ILNUas؏Jn^ aPvV{nN߉ Gnqh79c@9;`xc< 0N<=ܢIW%F>v+`pI6a^ yaHQ GʺeC8Cq]^ƕQHaEWPOM9;Kz? Pnږ3U$+(xI2b6ONh썜2%c忖[@8?wv)*I۟x3nGd`A=qkVﭧ($G"xODB6.[I?NY$HPe-ܑ''ߚ2Ҋ(MŠ((((((((k,0E<1 "o9 =O`Ư@Qi_E$;09xUs#x`ްX`KDfe+p9 q*mXi3jVpٷD8q1a wWU2FA ڱ'}]~Sh09'Q='d)IE]%^/"!dB?V*J ( +:mj{w * lxO: j @1 x{vb[\vbGd܏+3K׼wEo[uby<11#9SU5=ԭyi 7C̺* r;sǠc3YJMlL$B28y$\$N\$8{p+H>s]LE^$ f2qWh7cܒFW73&G FU@Q$ET/9!rIo(H $^سXZ̲Qޮ)pxƌB{ bl%s{cA)v]C#F*:ԶܤWڌs8vq::̏/*>|78#Sj2 ]ߏҒLwm=ɅB2"(=;l#"5iQBy'_αa׷e69o힃=Etu7ެ(oNܱ ~c'TLȂ|#4 Kdc: &yR(׫5kZq23@#lW-0rCvY/ٞZ5HʝF>b0pF6p D'(y,ܥI&`>I^N0&>rwukG HC 1ڿNNrI]tI %1!qs*F:ԆF*J+SQ@v/2~kiZW1Cnۧ^Ǡ'<(nuBq{4QEAQEQEQEQEQEQEQEU}J9ow }M_jEg$QEs*?zASԉsy! Xx2̠ws į!HAj<*gvls2HX`y۞Fqs1$M,"44nDG%W ms~>2 .!mwSm )-F:=rK@L5Y*dg=דkivDFl}NO'>L'MXظbe %x}=:.}/TҊ[V\R! q'Ǧi*Z٢F꺥2,3L>S.BDI9מ)lmAmbsOy=z}k](Em */~y"i`BH!\`+nr9sR\I7w / v ?GڲR"# Þpno3\{olZ˸<89̃Vn5.pD$3 ʻU0yH.Pۣd۲8=\/!S;/?ϧ흵$fFp3֕HEarJ:&q23}K޾1`x6n*@ 9+=85qK"0O/9÷Ǯ;}9"* #*1c%'vS$Z%Ɍ/)=>g£eo>4FXp*Z9z*, 9#G-$' ";ӌ{5@@1`AG8a-o,D`.H?0P{:aJO$*}*fvE2GH⫻yQ10O1d^387$c VɾITDG˟A$h}̭,$&5\!@=y')+\FX;n#Įr8y[/stGy[>KAEc( \F!n;abk3FAq}HʑȻh+r-F;O;x jFⱉMq+HH$瓒I q)S&6*SzdMgTs̄aqp Isp6(,z+EF6ו6A ɷ`1%w~S!`3w I:#s#\rp[r_ZER C&Ej0dGNz{ Z|6R0I-(v@ְYs(+ǕO\^ t̑F3CIՠgYE!7sq֯ךՙ'uQEQEQEQEQEQQ@MS2%bm`duG`yI8c4X.hUE PA2@p8*~z{Պ\bvE`0̍HTzH|# .9kiR 칸mq0r7WQ0@K9 2봂19'8# ֌%Ψɸy[9#q,C2?1:9Qƹۏ\H-an0!I?CzV<4SOyhW~` ӒZ- KR^]nvY1p@:ڹn x st2G5J;m*!vwɬ3"YeuR؁ZSݙԓ[q,͌nbIԚz` #>=י@gZ(!ǚR0zc#9+imtgqK(xe+ rxw^;[߈MtM+lp@N~~p``P0K9'LԞ6zAVP:w>?iAi{YCoZb@^oވ. *?':9ɡ{H6`9=IInOS:1e"VM81۞֥%}O)rHu~|1,fI_g.#ldTl}=/Sy=G’3LO'0TI=1%I82M}l12>%\u5D,M4D4p qs' (=XqBRێOrБY9EW T:paL։½EUn-,.ڀ%st>HUaW!s@0p3 $nm~]R tsJiђ |eb\2GZJ9;p#8?'2:r;@ A3G*3rǗ_/o |%O?Z&8h1`2F,X]z@"m}S$s=!a"AE UQczw+7[9-L[H&vV#\kɼ'P9oTFkVػۜ:]eoe x-N}\wdVry$Rˈ\l0##zcaIN<Ϧ{d˔Q+]Pjm,K|\1P}85ROB&\4,qm`pzJΎftrC "}[)mi`UF9:zz$ V$$5{$]>TE3(Uݮ/S0(~GQrH#;4Tbgp 渥#,T_=NrO9[R30.Ud&NҋyfL+% p*0Gu(IUC,7yz "]IRm܆]*CޜlKڊZr$jXFA'ɹw<r=xڛ]ai2҂6 ##'=1Gs6v,1\#) "QGNMT`[*'f0H\t){Ջ%vC`A鎣 IY~t# "?F$sRA$([au0};*Ҳ [%r(X8:p$Qr:}'osi`A4!GaZPL'xV^H! 1.5+[,(MXGۦs)O|sq ^5XbLFsAG ݎ "+ "HGgHF;*J[#}$TՂ #gIzg|K!~W"[]/2PN8;l\ uRQm}pO>QV I2oĨW }cI.3Wr~>sI$Aip:(=:Ts> z>ne6¬$Hpq* X+[()i;?OVhN$tz{J!+&!PFGO]Jw \,!Kng߯L 2sۿZ]8c9BDeB ~=:[] K$!-stQd ^9o\U'. #W'Ԋ\y@0c8뎾^(͗zzg欬j3|04rHL`s_i&vUUPA*XI,3MO5Z_fs/xGݳ, =88" Ϩ8fxIQHt,:{v7fdfY2]| ?P9MYAG<^ltKx^W)ܰ_y<;/Qӝ_ff'#'B1qǙEބUij-2ۀc`v8sm4}}koė&)yqo9Psrqt\ە#$ֺ0Ya]JE'I88t J2K+r{wǧlY I dw8>³ Z|o !<d)b0OM:>b\2ca2!YzI#ߌ >"r;Uxur9QRCy+F6UY{]IĶzO 0ṟ8\0x'ҽ]WϖHʐ =&3Vf*pOf]i ( ( ( ( (#PpF{_ָ_AnڻĪ8B]' k7XӥU&LscϦ;VZºn??v2AhAU Q#gr1$s[:[ݡ*\̘ |y9zճKW@CAAfӖ+:k6vDq0Rn90&kVw^)Qnƒ+r{g<֥H#Y>Mnj.!qcEbpB#0BK| <ީc媟:Uu'iUF182V%BQhݞ6x׾07!;3nvAc': Q&ܶӇ;ߘbAiD."Y9@x88Tn窽2'X#2ǚbuvc>H{:HCHE u ]#'}:`b1ѭrv U p\iŚ;; ob0T25;n Ё44(vrD23&9qUEo5$a+g ߌґDT*6}F*K{3}3ƀQYP'8ߨ{v>d`$!'1=J9`BbpNG~kNC]fede2p~:cTv"m6>Nq=pqVF|ʨr3Hg8\Aqi"尤@2p1˞&f∢}cj*︋OT;w45]$j=Ģ8'v3d~aE%>#+M3znf[ԃz1?.{^lhHP^Xd{{vבrmH<U(P)vP8oU^tarC8\a|1qcmCXO^ ^$vPd`rgP$$ 矧m$ͳf`CӷOiʢu$vx`Sfn9H:2 ?#JM ow" S>wh/.xE'^C6WJ)%aEy#%byyxȩ涅rR }PG|qq16r:p3Ө_yVӂ]X8S?CTRfGK݆C0#$ӼFsg8t?aE=vsOU3  U9Z(qK\w09++od- ''vW75d KU%$SsN0OsV )Rk`Ƞ`gszֽZ4qq/GJȼ6c,fhȏ~$8=y*ܻb18~#gD{SH]]Q##r/V6̈˗twH\dϭ1x-bC ܌3Eg@nXF8#''AW\cz9cgfj禅6Icf_vYbrH:_*4{Œ䑌c_H&* Rp?Z4o <|!X98'S7f1gOIdJs`nޛGÊɧm(y'vҹwP8_#G'=9G{m:(]r̹Ĝdzf*]+ ( ( ( ( ("-mgTX=W> g w{ZZGoM%˟6A+:Tz+$H;t8#:mgE9GN}9< Ɏpsb{y gaOn8f1,$GF *>TU!.v{ r=z5U*A\JO] vԀm<_9! (xqP}UsL;,X<ŸHA1$2IҡDPep7FX~*&TD3rS>GYKo+k,q4PpV 9މ#EaO"ȧ}p=zcR 0HG20#֠ID{@=I0\4+wFBȣrݎw1o- pOn;{*X#@P1JFFIFAVT&Uhm \Tv,s3$QѐG\gorpT'r7[$2Gm r$rǧAb ."`9c0aa1!U@ w8zedDG5g d~㧨C#Yϖ0C+q; 鑉^a4 !18/ Yrpڼܤ<Nnps*YN J+$%ՔWa®8]Wf+>lu}+mST[DȪ5c~O*VCv>p-t UK]I,Cʹv eW,I*{~2; m߻hRN<J帒$9%+$X\=8:|{̭6PQO@KfPGȪ<͟ts}I䌫2%A GLuAR请3^\;oWUÿϥiښz:ahI7 iݒr03A銋TD1坤pBq$֢.dgpڊr@,qߞF*ű:4.`0wcVM;M5sETEDP:^t[4nȔpu'd# Xj(((((cP[*h" v";=PkwSfM6b!ruִ0++fN !r$GU;@XEBiX\yOP0? [bYAJ:G<3Vຂ䰆dv__?r$!y]B- _m18Nc$<9=B+MF^!ٜT+FOʻJ4Ȫ.O2O3;!t)]4grTd nK 4y`B:ttqƋ1&"_l`r@|;Sf{iaC hA>6ȈF F9u4wuEW|n`0[2{6 h2sǹ?\ZH^U'b}Gp:lX(S=fՙwEkVvޡ!ǩ>=7Z k)2ʥŶ$kT6`#dr1Sy7$@T=:vWe9b5+ vgN1 I5 0G$#4؀-Ԇm*33Wwn;Y\w0B8oOCV9b!ea?{xPJ#V V M;B/ʹ#gz{0ȉ>-8 [52䶃d:L#.OAujVv #PG:gcר(wN0:4$Q$p<=LrB!XLq$nyŅH-+䑎O!f8qrnҟA-JgP$m39p'#q8>% "" =Lܘu`z gU|YJ2Zū& -8+N&{Be&;#Up`zy!FIzYbp]G\c.KS"tx"T@\ uQڛ]F9TG"Rd$I vw/m8^PmKQ  b3,_kdB,ap?JyrL'k0ws|Cё Ȍ<Nzhe]\ky[S8HNX!'1ZD9PK |rn@E`شn@y#N?3RKOBv$a}zV2RVil.2.28#s֢Vt$#8ۥl\X2’1Pd Oӥb|ћm n؜A4i4x%һy`vۄ9`p9duPgCEW9QEQEQEQEj3 9 Nn'pN[Z Zy$3Jmh[L !,K2A†=_Lƒ&YdR5Ag,?032 8ynr+ ##VhiFG#>)%XylX={gew}K: TߟhVvE‰rX:$G -0E I-` ߃Fx#g=jTOr#*:0)eLqvn‘XeXE?8Hl๑ID=1K~T[Im< 2`e+4H!bK S̍l>=zGyisQy!yZED>Pcr pS>ܣ]wEqs;I9b+H>k/Tn{nRdSM12\H:Ee@ś=O#y5%R ]I}tӗ^o!d;1ݑF+ "<0 OD۽ȐDc0x I\pFss!?NBk6L߿^wM"-R yFf*V q؎<[Tb7<<>ԧWYlATߟTeGIEW1QEQEQEv(Y߁`n@N`*Ar?ޚvbj楶*h،RGG,/<<$N;Gc[Zf%Qm0:w SY3nk¬7|WDZ{[j-) GQ~tE qg@=5[ /a=錐r]X63FNG۽h-Kn u㜏J2~6`H細L"e7Od qk=Vor.w1 nF=)q=,iY|QNx~>E@BT?"x>aSGʄ= nv c*i<3 * A}xޘjќF]՜`600 gR[f3#FсN zѻ+U9DrUU9#O֭\-’ц7+Gk%e²BJ}i$b=U߸Th]4ٔCx޹3ZrKe;rF@$9䓑>GS$,$gڰA)Re'#u|ȟȷ$Ar^E89?˽QƂ K̑HۜrQIha Y*8=ܾ]K*8pe+ŵ`ĖNsZ>d^N 0>qZ#3m2(pUIgu:-\'b2 FLJYFQfe}gq* c3*!b#i\)h}1!2z?>LDTKpp1Dʪ s?CK YayQje숌T9ʁ@マ)FCJ:H3d]WM1 dT~=:rN3fjeN ()z#} &@F#jrr2=zsҵ+m5%cg@"Fen`Զ֖nۊ;?b.aduTdg8$7O_S̏c 97΃=fZ"nF:!~53F%IG8ͪGw&I!遞2;]+TDc+PTg'# Z( ( ( ( N|GJ.r gpc9ϵ\KG"+2b`,10*rzk:'8yMnP9%yywfmq\YF\0!0|9M7R+ Ϝ3tIɥ.Gʠdsa-]Etnr8#8+Nڇ7pg R? " 69+ 9$@dNΧի;N+.<#46 ]81z $]jy`۳=meq jdG|ryDͥIlQKsŎORI'5jNUbG~}s#ss2;EH#%㎠cgα% mxn@ _;@'֔o  zB>a8 o8[W.ҰDe;ibS.t[tG0ʧ# 234;!\ v bRjN)a}#!GVQs;Q[Xe#̀J6#gMMb7'n^rN=c%ݥ# >4 Dj:ӽkjohUrX':g=ͬ7sFS$N3'cJޖ3eVB=cۯz

    _Z>X *|ܟLg{W2?.2㞃ztiɴT@3Źzt1YՓoDoN 'v2*ц6q6 ׫w8Yi$3Ngzsrkp(NNA_8>^ؘAȲIte1=ZOHh[M6ш+gr{=8삊(0((("I#E$_2?̠w4ɓ݉Rlc$ n RIR* I&26pHbXtosۀzI}qͻҹ6g+ۑ֩ܽ+noy.I}S]*6G4viU-J5T8b9*S{}4^A&pG&\89*r9G$4F9w@-NG8L]6i|֘FHڒ|q$7Tf0B~S>s>pw2 I:Z47Sިx9&c ?{$G Gpvjz*ar,7mp{~tN7+o=)r]Im"s#O1l gҷ;h(P' $#xHK VwR;ˎ: FMRA:eFǮ1Q]nxb2G O n#7#U[ da+/Grs[#=[2[Mn l#ϗ"0>a8枉uT˂A*Xb?wcӊ al`v|U{7 wI;T )^xIvrm40?x'v6114eN s9sR[B#Ip?w7Si5$it V8t*t'-=Dvm@r^m8rUU@}:`|*X^Ky],yڬ%!P@n~@3rF20(v{-+ Tz_W9f_R;9 Ү[aȒ6!|3䁊sqPF2Ab>R8 xn*,|'u=ݜ0(e1*ϿCxݮW·R˨Iɒ3wR\Lj꫖jұME4QEAaEPEPECZK,,`CX {6qԏvDP.%\*+*7nǷ#KgK,sLvl&opiX]LCAJɸh0Z3*D:(V!K9_T d1_cZ]Y[]3%Б9!*h$.I?*C6dօō$ qOI'EH4 fh!ʾ*\)KCsE$LXt@wN1$b⼎x˒p3>9R+4-&uH@P*Ab,۹#'yY7ש"I 8>_ߌ'7TV˦ky$[~hV!;^V[L;Ll.0>'1Xv.wmH|[jic>l!Ѓ?Qg:̎PukfxHF{x湻zX,V4qMwH7tctxRTL$2FvNq7Qk Df AliZ~w!v?('ڈUVir9=GSk[FFןךE,2}m 1oe;Ɲ eV"Ns*r.ׅ&#,rGXiV64R%A8 N@QX,098(ۉ ہddqIye^ݤs4P2`@#>Kuo4!@W'ALud19Ā'Ҩ/"Ɵy8_ns+2r}+^RB9oJ%#`АOrGojqyr!Hqph])shGDc/>o8ږfёs0sצK؄܀v7n:t\n#=*emn$)ڜ vS!C8o00x42INo*k{v4C!͌ N~qPHmkZke;oc9ې=psӾk +{{i#psÆ\`dW\tz/fQEdlQEQEPhxb2.3pG<1Dl m`q:ϰ̚")VI`'YڅǒƤgp~@BTPYZK"\ 1\)*)`Wz袑cG0\&} "CxE00``?!Ugݶ,0q?Ny5疮XXMU]3ҮVcnmrr^QexbgHhpJ~l9SİDf'J9@ϿlIb~Rے6Ċ;d#M% Tszd֢Qzs-Lܓ]&QԂdAՇB T^F%$`^0N{N=֙HU1grAze ch$q9W{1]\K$b;)2YVscj˹P/0;BoSe^]Vt }1Z/v:o*n#a3!-#8o fEW`>ђsq i}0g#;q} w4\Vt9YszLj>ո~RUpA dgr"!nxb8ۧ@{k..ٸr;{<=:  Ll灎{Y\(wjo zbqInytVf={ŗ <;]IMUuʲM˒N8\:W ;jAJ6f׆t"aKy"CVcl$I 'ܩo;+6QE%Q@on˼  g5s<ј."sG9뻭hڭk ="GXuvf~an\gV&xUl zN}I;ݖG1yUe|9#zgIc@0`TW6S;[ac;N8?ZEh2x$hąX?SP1 d(fpA% |oV&Hf`vH% G=)Y .D )YPdM:usLr=d0PΠgћ ٝ&1E*xcqp 2 idD cڳCKuñ"o; .gn=NO+z tSIh$~H˒K:8ɉc6#lv܎zZ\]$_FK`` IܚVIjUna0AC>os)wg0F@V#9Fyu+]2 '^ y6`Oh=؟M6qMX}n˰1 \r9$ti7ogt2ϲ9~=5/voJܶAEVfEPW}A2qbw\Bmߖ ܍ݘukrhh)(U$p}s\I9VARN?uOs:&)6;)gŒc؞c5 +y_$09`%y<*'ӿ~ZyPn?*C{,RܨJ,RpO$I$=HrKr~l,+~T'm`c(*ė[Hņ&A> ǜ]U¯nNp?UЬ-R~Td۝*2c np11ZKn-y?>*" "~3 G=:s]Q'V.bXʀUt\g= њt7M$7dwp~S#(ܘ8Uf-aO>G|'#H";KQpfYQ=:sPi. '>63g{ ,2?9`=ӌlLq'hϙ"ukd-6A=h]i1'i9q;epHbIn,REc夨Վq߁f;r)tFxa(vad{rqVCt?+s>n:ZKkhH #*0}eEiDjmp\NFf˵v = 6:(Yh$vaJ 0@sЯ[l$=:R0qfjV |%&EWFM 7XWvftO "Hm _+|`j ӘI C l2Hە{v5>۳]'n?Rj/6uH$7^,:Xz`쉊V#S>"$[q@= 8ۥ`GmQ ۹8J$%9߸}`WMDc0!QF ZyL.cE&HzV^4HvCî =G$}kD46 )ּ,3#gsdTq[6A(nrpX{ޑk'BLnU#nLc|M$me*;mЯndxڳd[ح@?.OZ-QіRepEW2Ǹju_r.9U#9R38@B%sSW4h70*R#=*wVܖ$2Gpc'j$ .]Gğ? ٜ8#>=9T*ڞhM>?P+)"1`rJ8ogh@cq85(Jm6hyP[ AYZƷGoR:wG5'CrD,pX@REVqreϩ?#ͻzqeEKmz|`n͹$hb\I$o(T`Î'GE& +$6o5D’9q܎ӌn=0F}ĀHGnjnid̋>u7j<@-N:ƍ/Lܓ F@];YG'n09|vU[x;8Yb'̌n8I9\ cԷ65 aLhŀ0真R8ûz $˷I 8 y#kkuXcg#$ouY/m +e$SCL|2:CegujE$Qv+#$qG\c)KHKgh Orr>?/^5)[Hy6pIScorۄE#Hd '34JZ.HА + k{FSI+R2]NzX}ae`2AkI[P)Hێjvx'k 09gxIYԆ5=yN((kjƧ( s-m. wqGU;6ԁ-I 99`@^OƱ)62Kd|V< |:Īd@{%eROn_o}q+x6W*>ayGlTReʁ _S9q-ϖو#r0xpzzb-d՞w0Ug9 `:dU^(~ϹYg.B_1t4`ʐC9ic׫ wڥ_$=Pp?;LE"E$Z]@ 89B ynbz HBwf辤8zE z1,@ }1NdyTx! x枤snjXK}[T@f O$©o{y'& '[0;Upec[]Ix'?:-J8/t*́>`*=0YI*v`t'/uC+Mbzd@0"еfF\c+玽J46w "BX#|)u5QOu4j#3m=y'!Wb@$fM$i*ʭ=>`qX쵙'HLq(949Dw""gjNxөan%MCBW$}u/s}²)\%:ʝn2y<~-iUbR{|ßï^X. {m%S#o@aPڵbI-d/MvM,]Dz2T]c~"89 Ԇnh$R!f ^qIgۥ`ierR'?Q<2 Y$xʨFF#aPk*Qp$s~1s=DmV+6(|񎃜mn\P2AGݑA3Z:>4P$`66/8P1GNbB.. m0E E8 ԰^jK-ݼsˢ e8u}J5Ac nr}:rN1nh1^T1ŒZ^I)?qkZY>֌Cu95h~,8,02FOV'S4ۄt`=_:+濚 aQP:lZ*ax̠kwG0{պOOp(5ݣ²,TgؚϘ  r1~p[k+1I%p1KsJm Nd*vNNGNwo>Dfu7xz*瓻[[Hn0!hLF9n<βag|yC6M'<@sQقYI _0\`9 c>ӊɒ9ndb62=n-_dg+n;I, d(; deKcf *1mꥑ!W{Z|;VHcV'Yqƭ{%H=2׃ǭiXIGSfcBF}kOw9c ۣa'=}=)<].hckᱟ^9=PyP%G cojJȵk0w+0_oMà 68$AGpzUKo*IKОVEcLƌru'ד$4%"K)%7G$`UV 2[8X;ݴ냞=;$cf_7{e/n?=*IeUn2}4KvHmd89B03x{W^h=$e10N2BZFs6:{ϓD2H:=856+ĐrMbb>bI<Aқys$.: 1 o8c֗R9bI8͵$~$>)댃=)5ܨt-yn̼ylrrp08'D3 @V0Avרϡݗ^G7pF{Gn+RacI܀Ƿ\j|{jĞv%:ȢU NT1AaUO2NwȨA`IB׳\Ē$Js5d C$/ 2Qc #w!C l <Xz={6;n\ͱn$cm#|VP~0r:iyzDt `*;QZ;kS$*Ȅc8p8GYdnpqА`d}kj'y#Yݖ'`U@b6xc;YTg|O؛zq9<н0)$6s&3sIu 8{3!2'i:Vޓ#}RU4z~3gS|T7 .eX`qCz|[EEkxHrݽ?U c|FDeʶޘt'Svqs&@+|  KŊRdh݁8ǧ<B"KOCjhZB:zO~jaXtHP#,AB<|δGZ%a!iB`)#R}*ycBpsPP{!Tr=3ϥ",c@'F:@8En K *ۜ8NqIkF@dYNfILFinI@i-ٝ7I*9*hgi|"_BpcrjKNAUWw`~z8JLKhdH!_O\eMi3a>d(39f#kHH̤"eGC"C .zL]3q8٬|"]\18–=}zfc𺬹VC&PW2:99]ppPisV@8%iU`c FqVŬ(_ld:#qJ9eq=!Ll^8&ڿ#lf\Ϻ?/EūJ-nVԼ϶恊.SiFLUuHBâ)\-~Vߌ#VH98*n*rֳj%.۹FNGמ@k M,b5S^\nś!8S<8\=d"9Qq;2jb7"Cp}:Uh%bВFNF?ަJ|i,!n/ze bw n#pTcv5\؎[nPcf\ ʨ9=۷3 2i$*p$}J FD.<O GSJ%%岌P:{jtK-gvu[^dx_Fvwt#veyX$.BK@#O=Vvւ77y/PGc\--(*[UHE][B{a1q*qۧ$i.akJM>'\D2c 'Hzd9$ք3lŌ D 9;N69x;ؐLdPKwcԧLKH;!E61LOZ%H4(\N2N#׭6`KgӼ/5[XԖPP1&ҤG@7 *PǓ 帇l|\p; "] Hú8F_<{9[~ėL껀h'qm?R3O/jŵzdg8gv:to%Eh CvG1[p2WۭSv*=c8z_Dz2Yycg1IC Vqd%X# DJ1U\[OZiYօ4n lg]x ,ܮ3$ drGLJA8Du..n<G#j_^KwʙUY9NAxjf%d_U{gQzsӞG^:4C <*K LҸÞl?GcSMr98*v> 䱎ݡYeTi߮qy>cmZI亻H"Gɒb~NڭoXE=gp9LZ]F;fvP@ zsTYi̒$(4aCK1W,J99nrge2KmeخH90Qւ8q_82FB'[RH {43\;? ng'; zr䘷`"޽8sp6UgCe<(c֖]q["ʱ*|{'kF4Uخ*q{r!FW*F滒ki6*d\IK y3,^Q̈pܰ=~둏ZVYY8wle$8rytM 9k]E;`:;Igx.n $hY NASӡ# ޞY @sԎMk[Hq~`J bNI9'5&9cq 6F*6p%j9bBd8F,x)<$kl)l`cǽhZ=uq!2l39cW J;0H'㰬9nfǦ-L}pP8qc:ZB" Xdjj*l3ldBTGU m( OE QHaEP9ɒX,7政;z>ՙi7$rd$ 8xOҺFBݣ@}$r?8k'Up~l1o7t u Z=DеzcehY ppG#;WXFDɓKgxרLP! OG=LECqmoF02s;2zt횴d2t+& g ۏ)zVƙ Ĺʏ#(H<ʢ0ۉgvY۸qs?NIA&ٕ},L30sג*rzù-y.ʓn㹤u3( =M!Uydw'jHcppx> Uy ęD F6unx#_kks*.>S%"7gׄJ򪫀NFG<tN(P~H`uM$Oǀ ݓϮ}iy$ra8x<>ؓt.-NW5^`Rd*AU$яTZK@= f 2~0[=XΡ*ʒ:QP2cG)Wq w1p 1x"4LO^JaĮceP>cN{=sTC8I'b$!? y97 Epr?1*l]=M=9n'$$~^2yDN%S4C$'͊mm紒:m'lrǹVctI]$ڻ (yGHdYZƷ%W~U#2Ʋ?P2h'~l*/ DyM12y a4)Rĉ(9 =jF]AUX#JOxJڄV19F3;8_ʒ}JH֋ Il0W N Wy!ubX-99@#Uyu.¦0g9''NCoy O#dzp u m#U, C0UB~\wNE%yn4Y  A`wSvȺOBeY c 0A' nM\xc t TtGPOF}ܦ}Mqo*"6+±,sN`j9-l帖InPFYQG A' :%!nգEvq4Onȯ! ?( ~\\0孩ЅHYYFq3*F-nJgxQ!$30N )d2 갰9s2zRCR<Nh~VIܠ#dtt 2S'<1qdd# $Qٖ;sϦI6ڹsij OSq=?YcU;98SZm;Mhv0>ku6r3:z#:zjѧ\-1a\aIq8O#>GQ4)@Wln$cƞk*b"u|ǹ-l2Dcܩɷ$Gvap#U-(# d~xspV1he#.3PZiPG,lr o=#}ZnIBE=&3uZK+ys1R0Fn ƵC xI81.sQTda1;nn*}j{^P9MrEr9p>0gtSIhف9gsqbˑ"d--;߿Je^t62WU[{7>Ucb ;a@-3V[73vt[A"d󜑂IqqQ޳O%Ubd }F:uȤv7+oѳ$+&r8FrA)p$!P=?VӠE} p' 1^k}:!Y%P07>0= zSSd[U:BGtvY`IInB`p~<m"8*sI\)t]w)HPYBCgݻ M&m7(((/mV١sH`qA[k~$rdM)'s@{{mae1ݻgu'+]gKH 2 p#8w浧=5%M#BKc#$]R2~vw &XӴ3,0 eOP{xj7b 75ѷasیN8t2.Fi)l[s.wl\#=~;Z3jIl^ 8ڳ" ;a W,ػYB3&An.GiɡlgRv02(@Ww8JM@}qTYVħP}G3؈]I`G?R ~;9>9,I"E#D@SLE$x!X>> m2lʋ+|p:~ yը^KxQ]b:m2SH4(YIUNC}yǟR1KIg<}އc~5$wRXU ̀1AǡcV)8G9{wqF#Ҭ LmUR1p0k]7tG>>(1p_SH4iN|[[oF1%-#AA,qF.i0GXrpCYSocxy;Unef#YZEۻduROzN['YjR,S3duK#/,4|Crz6q\fFW#?ҵ,/% $銙.5EHW2+&cI"dC$Ws]7Grb7!y9'#?4ep%Um0t8< zdzNmPjֻbFcE˩|sВOi*I),; J6ߛwwy=EUP}ܒ@l?$MYDXE@L3($ڿtqu\lm4N".S9)Rg'#E%ͷjHd{y g }H8@Rs&e@n;Ӑkf=&.C>f$tk$1iH.!Ch92~^AֵI-%- 8$y p~6--2CF+c8Q裢NfRq I'y}ia{s lCM @O\dUS='ӳ tUK=Ne{mrWU|~F:[DWshnOΧS 6hj85-1"2#'a#:QEV.a.ɯ ciݜ`#mVV|+ #w>{LmLhcQxU *AfxL쨬N2>m}y^~iIte;O\ ӣ7C#V=0} 9]m-m;\ypcg8( E0V)~l;Uc$cԃrYLڌS ^n+n8]/$1sǷNODat`Ib-qDf2 9'Ӧ+kK4F)'ʒ@n1P:GFŞes.1NZC=.jI|y~~x,O 0˟9Sc~>N7b#*;;d1,[:v<ּ#S/2b@:>OL ricO΍yϡ91qєE0h!F31z}95:iֱeXwr}p))Sb<~BWi+2=/A$#&B%rkBգd29L#º#ctd " 9 8n vnv-Fat]A>QLo" ?9u@9MlXmqBl GT5;v0A*x@9O Z/vɵ2,]g^"̤qzDP[cw, pQCrGP1Ǩ.ح`$9kWMZwn6|p~&:۬@;IvrzV+!5Oة̥Hx'8Ěbm"ŲPK#:u95n{ :`Iߗ$PA\w gXԌiY#*$ĮpN=1O?@%FH ?jkގی9X䓴X'?)hY7mn+k7w9 %PpG8=UN@W?ђmB<ֆ=մ]8pA އЀypN:nk K:*Ǩ#aJJ8?AWhWAERQE|Eo^kq{kz/lVv>6{?ZVfgE+iW-޶ (Š(W.%vK1;ƼwǺSj~eY- x*~Ua-pboj(EGv$@{g$/EY`JA,x<ժ9|"+jŋ, ɘ=N79J̷{K+zngnw6=OOKBޘmsm]aPvԏL-E\[FT<9=#KL&I;: Lu$khvY~8<y\z}6H"A>@( & gdG xXRq}@ZW! cu;W==99vh.Qm㘀`y'ǽխ&%|@vz$u"Qœzc- ~WE^W_΃f?\+++L􏄣M|V\X8hD~E%pdr<m¡2Wq\uΚzT#x7`u^܅VFEP7J]㍙TsȻA,XԒrOk\[K bD(Hb0OTWU y('{qG#YnYmFF 0K =@0x.KY;(;9lP^LH?OJV8xEUb1c,MZ՝Hi߯OFzU]R;STw1ye $<8ےyu+M5PL>8>9k ][ b'|`1r@>y_[/6/#Ivc铎?uVRekMIJy6H$c9=e){"!T$Lg$2FGnH!~L[7*=8ĀN$_L3meڣ>{f]&Ycr_n2qsמ})H  x Q5mGއTC` X@e%}Q[uC&>NȫwƧM pd.rKqxVFbI>NI#zֶlaTʪCv:sM Tqu-W͸FR]".}@ӊHKJDb*v6{Ηn#1BDc uųI;'`?[=uHfMPێdjӭgyv#XI71L|\0=p3t4ES,qn\j֨o5)p3cߥ:M$R:]%ǙRsن dR~N#21tp>h== 쑃 \S㾜5* ( ȱה^u@5+scw$^+iPmq8^yM hamm‡S8>uqOd zU֊rJGE,(;FAS;TP1rīT4MF+{;(by\T*m]~'`^(aH̕e8 `Glir#ݜQ\ # ~S@!Vv&1O!Tc?@:ͼM&H,r*n9p{=k[O0K:IKζ=0pw?\Lr:Qky%=?\pI&8ɣZQ'YP@`ǯ*7n N?f1jr_Ob*zkDjAq; Oϳ]'Tz2KwOِr21*Q$W#fc=5[XZHG$OOZݱ:Cs$pn7g^ Z+3 BQ288RGAtn<ɏ$A|׳;F=װg'#=Dԭ+Iae2!3# a.s y1iO[8`IWdIpOukMy7yw;8%xdںt,BC#=sJw$(ayr̊?BWz- /xnʹ'/ʥx J_l`ޢ3Oo s9 `;G"?#Re`#XjsOs_baOÜ/U '@4w%8m|c+9yϗ2p8=1҄Y%0qE-[+:1y1#rBg1#;6,㿮^Y)7`q>~c--(S#0 Ϡ9Y]5'R0AX[BI^p"7ZE9 ?Z ,/.A68ȩ%`a&2>NhOP!̍d2d'Sb,CͽNN?J[S&KnPH!@3m=yhRdP9>wHDkLp{c#y1"ӿ8J j`Y7ãxs 8("276v8t4ߐ/2k ~UF6'jI@ <}?:*媑mU<~\l1NyqmNKRWgF%b "I7HxQ1Ky C:`0F͹3'O^I<4$g*̨Ywwrjyv`v.qr{}+㶳X[ le?Al{VǻBBVCyfYRNq<~CJhb 1_ m 3] Ơc['-c@{bXcX$>Z8,O>k˃4pFFN}$8?nQpI8 p3@zPoBe$ҺIs!r B=$~V!|q nU#e9z(8=2*}y)ZTeQ''מc|]6Hhqi6Jd~iɌ }y=1>Wc$ C@c:SaiEYѶ7@i$,QH$ca<zM;Fȥ 9*ssk<hP9%Ann@\`;UdEtkyn`03بtB]2·Aޙ(J澡.[hz%h$k۱ms Hvx<ANۿC\:%%tQEIGB\PײM\|xxO;yuQG[LHZC@Bӿ/UCAAKvz E29>\뵁QEW?\jRj6b\ٳ]p&QSVgQg O.PZfY2B+^ ү>Id'Gs\Uv}ʹd'WsE4yIM$,z{jgƥm(9$K φqw緽RKR2烟4+6F@C~ F@j80k;Q}l\Y!dcsTsAVv;[@3Ul% ܮS8<_n^<9X ~R>Y"D^~^qᦁm#G4vaJn_$xd3??[iȺZ%;Kg,SQJFG?)]ɐgJ͸iI mTcq=?A$ٕ;vs.WdWQ*Kq#ֳc12fId|+x?*nؿF_`1bU,z, zSW +d\׽='I"w(X9㿹*Wf1x zr;1خfd12ڹ0}:obx9m̒7(;;y<`\[1uRZ@^Xylv!H*I LU;T:|搱 `%H؟L[k \:DOg=8yTӣ_KH~yc'6OR08=@KLղO&fE`p1`3g fy3Eо8`@Il3WFʹg`BIrG9;w)Y(NY̍q]VP؛pr%U^yncZ6B)l!Txit︈6!#-؃~u<ɕf!`1%pU>5=ujF6¸iَ150Ilff4T)=ejszb3N@<WClVk"M@?ַ[E%~EϖX)#pdi->./ڕTsA Q̜W.|7t[oY$v@s}(\؞N~-dkBIF# !䑝r;p: [ri%EK#{~*V?+`8OR[;+ G#9<s|L7w_lj orpp͌pr=yZ*Rɷc ["HU&w9mד]{SW̎9-" ,/~zg2(D+ ?*1&zp{{J8EhfjM^kEbC{s '3ˏJӲ[KdՂ=;رETfxE[ yNoȷל38q a9mz}|]-JrN˙#k°;NI#ӕY>#Wbaw00sclr"0+ =Uy^dy%ʳF@=5&g ڟϨOӯ>/tDauDh;qbk~Ko>THƒ?9߰SD[CU֧$Eq5\zL㧿jqEb 4LDw.후 @,@BԖM0\,T#O).;Io#CI2[g瞽{[yHcr;uƘٞKVRH 1:Txi03㿾1YEs5*c.B$zgAo-̤ zE{ۅJ"+=~ >*f8($908!7b%l- oDcu>~q@{o"lrw:|ذg7GɑPLXC ]p d u%Y",ngnc4r4Fǖn=q<'\qJ[8v#8*1x4q[܈,RDwF2# ghwG~Wo|c&vٷ[KnmcxR*vO~uJKifye2ex18892<+8VVÃzvsWZZܴot ̢0'y<#59֧q~*(UG1;6K6N{=)rŇ<4<,‚~tڈ<تc 2Fzcodw2 ±zV1D[Dͫ0//3?quZV$v E\Ii6 spNzd=R Rrku9SЂG>b &wm@=s馔>KX6ڈ/= Kd/#8:okXL8U{32mCSJyAKraΛ6,zzgjŚcPYH_/#zߍiwJ$ `pO\uƛ!!YrWF4+6}ͅ9 uZ>IafI@ޤ9֍$vpC$qIIϯK}5 BEXFCc<)Jqzh_,fXxdjh׳)2$C3ic8#:3AlOA Z5u`AϿ\½iS&897Iho\'t9ge;r rNq횆42$lcz^,}98aa377TB?/H6`0Z(=#ZR-e NTzүWhmgr!ް7qH"j7mv|d }0{y*qzluҬ^&oU9^{J?ȹל5X7]1*onloc[BwVAUrn.˒16'o]s]Gw-ss4`uzfnޱedSCnfFH<n3PqYqm4G_Gqp^K*rX($0>=Jan,me.ry5gʏkh:>>(((((?kB{f(o&H q $ v5opnM 88$Oܓ?o`ݐz=}뢕'nfsUA/qn&1 9کJ ՍFdAls=:v9F VtFI9>*P#۵~\/lqj늹'dXj)L30UWdP̤rN ?i,$CYv8Gn4?{x[F`8#qb,Whin2p9AnGNs0U,I=+#Mj&cl3)qs=GҧDE2'U`vd`z0}M6aq? /qϩROtKjeX-4.ٔz) 5Z;}Q*N>eofC.rCNz3R+o2b, GlbViͥm t?6E̐G HoSK,w~P2٩Pcof_.VfU H##|?uTȽ9YC Ǡ^dîq棡/Q}\xsʃ,F@83*c, #?ur#Em,O8㏥=Hbr*ݏYEV1Wh Ēe$\}FCq d#7# z_QX&&P s֝hbUY'#tvZn >]#jdsVJ(0MOPLG!NO_›pKIZ4v_,28wQ GO*6'ӟʬ 2"1SzT11T%'6miBpYf ):dz8=Nꮤ8 :#֋ w+X-'T <[fKĦ/b,`|N| 6`d(ѫ`'iَ(ȍ3hxʽ,x&6(? KvJ2`F+=GNwDC5lBѶ$03{~TnIAf;NqOASh@wr n?.}vn, I>I8 IμӮ{շV@`{n0CT3*(8$z P o&F_,&#A1[(-Hd 3xm{da$HOT\t\lW=nq*I%IJ(cfCwm#p_N8 <8?2$cගEZtDB1u>xQP`:Vռ3ǶuT8*}A3XcݢP%|<7>8<2G7.#~bis0kJq\ e]yb29pf c%P*1pON}Ni"--MFPU9,x 뜚 +FG+$n8%E#HmE\I8uj9-IcxL`4=1Y[3[thMEaqŎ;c:ZtGn%1K|vq:8CFu?TIyY%A9q)j'SB"d( 2?hgHbcI8N@#UaDx;&J`uv6o A9')Z6B9kHBAp('82zP4McP,qZu2^9[>a30ƦP0#5m _VP팂e% +B*w_PGJ׿ྉđ*'k2ShThކ&p˜`ߐxm[F,#LvS ǡeqqJvd9%x,Sݺ03qE VZs$fMdEPIz>"{i`3Svpc+EQгgu$m]k9m1?ekyo5ţ}GႿS:msJƵShj7z_[%n] yoZ;v֮Б6 gg|Kc'<Ƴ+@(g]Ү595C lqz!8hRPbnz-Q@Q@Q@Q@Uj3L.@g@wx+&k{LFb~}J bMU yR XA>E$<6G cx}+yE&U =^k$%)C0FxO?FmQ`=mA.9Svzt I ~dcׯ=`J5ſ :l8ł%(V5 jUHd\zMUL$.т8x_?z|S>P=xQE*LBN 49w=E ɀ;' ¢y !Aҫ-th")Gg[lp81)INO9pG$q@$j"dd~#;Vڗm-F5,d;NNwNs'&(Q򖐂6Tdqd$fG9U6Ͳ|rc}cd.(& QeU7\tL.VL]FNd:>ٖE@{I:OQ[6R,q8bqNG=L.*}i%Ą;FBۑyZi$6|3$N@*4bّ*:=j9'mtBgjk%P0c8}*1!:@ozm_ b8Rp)S!veAFILNF֛B2@.Ii>mJXӧeC8L+wI'Rz mr?jHe  @NNOW"y|i9;8?x=*[#DBH=CV ܕ&qiGCttƑªF8l;ZԖF,ژ/onn 2O I*;n uCv)+gVUw c }ӎ3Vb,UC޹z:e@< Ajs1B$1%$Xe0aǡz\Ƽ%&Ɲ .p98Y36c9x+jn`7Md>LGqMMK?AtnJ/SE5dUcYۃ:W$c{h. B*YA}æۆivҮZJ1J3ֿR? 7Wsk܏?ZԴxeKKC*nWv;TT` ķ?DXfQ{{%c&R#$ ~7-d-n8UF?f(((( fIn. AqXus_St30< 0>57Sdm O@=s]ՑYD7,#l4Xl㟭N$VFPdU[2*(6YxDBcw;L9'Ҵnf=ݴ,;JyNyuf,1ַd C僘vdBP֙MI ( >qƪ "*Excp<]IA )Xΐo nnrTsm鰋1[p#[ `瓚w*eO4({sYXc{paa@*9.SnN*{:Onx8d2L-۷]`3YDcDJi38N9⨝M&daW;|nx:@ku FRTGִGG; ?&ze%Y`83oAx4ʦ{xgo-]!a#d9iZ1[42Sy|+T Q(]ą? i=Ixnxbz8S_JݼbJN撥SԧStGi"c͑߁t0+կ.u  _2< 1ӂNիshb]ݷh;Goq3R;;V yW*67P};*-FVjNPwIrI:DSPC2@8 OòZ@"rˆ oCOļ p{f( HQYI;ūsE-e,(߾MTfO/)F7u:jבy.rH3){tV50 qu7 @6&Ns1E6Io/rY("1*ۙӍ`sHq4Rv-E"J-n#Fͣа<8략V{s#{KXs9$tڶar T[sӚrC(-<NeCZ %U%1bcS䞸p:Z0k2ctNO *ň)e@ېOA󊬲2+I*9͞F IVEaQ_;}$ñ">0t&h+f}݌p V/7H.GIrܞ^jI5{ki56132pp~\0y;; ZS8er]OOXr6}*D\S' 18Hf!$1.0qG_iI^ivgJD,W= <L 6DZs0N}:k'#!Nz' w2C{{4EAdTQ* sliKzvKNӻ21w튳xt(fvT( iQ }-{9etp@nާWhݖ8PI8Ҫͼ?٨EUeh,p:wqYİ^NLؑ{d2lv&U3V|qgzGb'(p7(a9U,҅! *;AOOWfe dcf.w e8#sbD!*P.W:*}7E2)"/+O>zT0'lo Ids+>Q@GdY8'^tSQl1r9R39ٺq2CqY\qq XIR5fP!'{񞾞㹒V[*2pi>$tbe]O]D2>嶐II+OJbPEGw`Ue4v[3D9XJ&YddP#![؞Ii ۅwI&/CF ӌtw9n-o]m0x%O,#`6 \'FvBxu99,&M ܡg>I~}k1(甧{a|,d:W7'9Ѧb*QCH$9}G's}%8!G' [[^ \(^C3ϧ¨Uv,p@GSU餎5;`;j6 _Y e&?5*܎}zUKY]OJpʐW7EKo>`XsOjׂ|gzʌ"$1uçr׾1²d+:=+v2Z" Z= &(#ub (-^~m"<!EK $.0#C{6]6є ` N+]O4Qī#!A8s犝bV/rIts !X8vs}x8(ŽrMy<f~V-^4ٓn3qHp}((Pi/Ce Po3q9蠂+hVx(aQ*z"`2 GMzmмYv~G25Z58X+s;/j/jW|E"^Z@hPb<%GYܛVI~um4rmEB{[w9Œ1vRV)T61odmoŕđE ŹT X4eH<94ZU핽iqYA8`AyPPQEQEQEQEWr'uRYX~mp8'8y䯬[N#c0;\'ֶ$x0/]c;?P[i-H\\+Ԝ^ 've&[v|AʤijtۋMjs#%FK|$h- ėc#`m ם .4 9` !gqS\W7|0X9AtuoQmOP؛S(@ !.9%:qȒcup SG"T¬u_?r^"Me8# @zv'=uVԣmHXAlcdc1Y/uk+Әc`00Hv .;00J@w5FіmtI̞sl cp#uͨ+"f$l0qL H# K' z'tr,-;fE Av55ORdO#;}@B 9v?m5D bve !@;=:h!SbлRQi" No~瓞6Eԇ^4m:Jn0` b LF mX):Ꭶ? pb!f3N;0,M/Bzq T7ۅ3lR}:Vvw PbԮ q3Vbn.cA;埐r{iFH B0`GO˚ٟNlV d=yACܳ;ʩ$rsֲFȱ&9? $8uH"+FVSGZ,p"@epMnɦŻ1g=T]EI/QERfA6իJmhmj$Vipx#$@G rQe1±3";>Fr,I%=x%B :vekX3(MJFOEQEQEQEW#" 8rF@'?zr0['RY`8 {$4ٍtG9U=M2M< `OdjW6mk6#*Wpvq:&y8+ j9Ksk{zPF@y2+ŌLL&U$Is~ [NH<Ȣݴc9'$tT5=\:9fJ6@*]޸VG,т c#끊Rw&KNҌ92p~\>U.//9ןR1fRłpO'egP@ Of].!G"2ImmGucKFd\$ >qH)Mkr07 ']i/`3$Y6VROO=z qΠm$w#ڥHWjUWo<~֮GVN@Zzyہ23 `:}j%8.7У5ݱd,ÐUPYrI+w:ԬPd\ rO={j@})ʟauT:U9֋аC$2 /%@$86m:Α(p`zfo"[[ǁwSR03@d oh1q&)U]|Ǟ=x=Jz㆒EV& TeoLRjC2Ysޗm\^Ij6b٪Rq?jqsbK G 2z /rĴS]4gv 2N&$ Xe]2R%Q@Q@Q@dxW[x"#%՛h}oT[F_c;qz&Ẃs*R~e@ ztϡi9UJ.!)' TouQX;J'lѠSٜ#1Ot6hFP+C+ b dGQ:{6eit0݊$`z~X  ]|̺ 4{mCxkxn_0`Ė8+wc#$ TYOI#K8dw(dʌrF8 .K>3P7m8= u3isȯ, wVlO\5 *it:ߟKhۺF.ϟNrr=1[Zn-bHa0#wݰ 8@bFy@n;穮w]XB&c{{Vpљ8TGCUuPMB2S0N}=X8eJ3PaY89$hHh>J>vb1#9myfFd9<}Eii#,gm<y3ȻH~r=z5xB 06Ϸ{m͢Z eKbbpY0 ۟N3v F*J B,Iz{G9d`pFq B<XQ]q2:;fڎr#`$t'~^&hVrp{WQh#1eO''#>83 %g-=UtK*#+,(XFHPpz-% P7)ut9<1q۳Hm.@p1~<~u,l48T92Hrh¿hN% e@0J&4X/aR t,[sֳ|k>;f;Wg}18Ɛ3IX4ncf-̖&]a9Á]4>K'#irPu,q{gFqU5 }682F[knNpI,k`~w>\Og9saMttQEs&w__mzKm\IRA;EIS]kVעf$W)99I@qN$ӄi' 3ϕ%Wo`XMO+2l9XIKqcGR#xgPα@bsrG# ux< ,oeOEGyo{!w9bmNF?s kT%p,}R <EQEQEQEQEQEQEQES%91ʊUA)P JmL;s׌ʹu5ȮѾ܁9=γ{I-Y$"I]|w(JzsbkHMřTY5Pyqv炬{ԊZݠ 19ͣs\^%fNF ~z hQR\t3P~((b6a,7R0pFMUzGdt ̣+H%M7sOpn."+o"N{-aCgOyF*;QRPQEV;I1*`29<1$1$Q"(UO (#dfڂ{Cũ(\lb __"ڏT+ +m2)"8TUIRyk2K刂:?2qֺ&Ov{X3 IRIHplQEAQEGqdcvVqD]~9ɫP ()ߌe]zmGY5D{W!OB1 sU?.=߻o5M14[mYZ\joq,J sAӾ?Vɭ.绑 UպC9 k.eeK#v# TH (4FΤ]3@Q@Q@Q@Q@Q@Q@Q@Q@Q@io>:)<;9V^q8@cLf"2:FeaGNRVg =8 2o:HU% 30=qǵ2HHX| ܎zVhaZNjHƝ7+]i,'A9f}>{)Ee‚eT8#2{zv4Tn,SGӤBX8tgp9%88KO&v^Iԫ1 dzVJn[)lQEAQEU;}26)@~Uqr(5?@5gm{g=ʓѱ^d]{QvjbhbNͷҤ).D$PH#?")O~I(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( endstream endobj 124 0 obj <> endobj 125 0 obj <>endobj 126 0 obj <>endobj 127 0 obj <>endobj 128 0 obj <>endobj 129 0 obj <>endobj 130 0 obj <>endobj 143 0 obj <> endobj 144 0 obj <> endobj 145 0 obj <>endobj 147 0 obj <>endobj 148 0 obj <>endobj 149 0 obj <>endobj 150 0 obj <>endobj 151 0 obj <>endobj 152 0 obj <>endobj 153 0 obj <>endobj 154 0 obj <>endobj 156 0 obj <>endobj 157 0 obj <>endobj 158 0 obj <>endobj 159 0 obj <>endobj 162 0 obj <> endobj 163 0 obj <> endobj 164 0 obj <>endobj 165 0 obj <>endobj 166 0 obj <>endobj 167 0 obj <>endobj 168 0 obj <>endobj 169 0 obj <>endobj 170 0 obj <>endobj 171 0 obj <>endobj 172 0 obj <>endobj 173 0 obj <>endobj 174 0 obj <>endobj 175 0 obj <>endobj 176 0 obj <>endobj 177 0 obj <>endobj 182 0 obj <> endobj 183 0 obj <> endobj 187 0 obj <> endobj 188 0 obj <> endobj 192 0 obj <> endobj 193 0 obj <> endobj 194 0 obj <>endobj 195 0 obj <>endobj 196 0 obj <>endobj 197 0 obj <>endobj 198 0 obj <>endobj 199 0 obj <> /Subtype/Link>>endobj 206 0 obj <> endobj 207 0 obj <> endobj 210 0 obj <>stream HLinomntrRGB XYZ  1acspMSFTIEC sRGB-HP cprtP3desclwtptbkptrXYZgXYZ,bXYZ@dmndTpdmddvuedLview$lumimeas $tech0 rTRC< gTRC< bTRC< textCopyright (c) 1998 Hewlett-Packard CompanydescsRGB IEC61966-2.1sRGB IEC61966-2.1XYZ QXYZ XYZ o8XYZ bXYZ $descIEC http://www.iec.chIEC http://www.iec.chdesc.IEC 61966-2.1 Default RGB colour space - sRGB.IEC 61966-2.1 Default RGB colour space - sRGBdesc,Reference Viewing Condition in IEC61966-2.1,Reference Viewing Condition in IEC61966-2.1view_. \XYZ L VPWmeassig CRT curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km endstream endobj 211 0 obj [/ICCBased 210 0 R]endobj 215 0 obj <> endobj 216 0 obj <> endobj 217 0 obj <> endobj 218 0 obj <>endobj 219 0 obj <>endobj 220 0 obj <>endobj 221 0 obj <>endobj 224 0 obj <> endobj 225 0 obj <> endobj 226 0 obj <>endobj 228 0 obj <>endobj 229 0 obj <>endobj 230 0 obj <>endobj 231 0 obj <>endobj 232 0 obj <>endobj 233 0 obj <>endobj 234 0 obj <>endobj 235 0 obj <>endobj 236 0 obj <>endobj 237 0 obj <>endobj 238 0 obj <>endobj 239 0 obj <>endobj 243 0 obj <> endobj 244 0 obj <> endobj 245 0 obj <> endobj 246 0 obj <>endobj 247 0 obj <>endobj 248 0 obj <>endobj 249 0 obj <>endobj 250 0 obj <>endobj 251 0 obj <>endobj 252 0 obj <>endobj 253 0 obj <>endobj 254 0 obj <>endobj 255 0 obj <>endobj 257 0 obj <>endobj 258 0 obj <>endobj 259 0 obj <>endobj 260 0 obj <>endobj 261 0 obj <>endobj 265 0 obj <> endobj 266 0 obj <> endobj 267 0 obj <>endobj 268 0 obj <>endobj 269 0 obj <>endobj 279 0 obj <> endobj 280 0 obj <> endobj 278 0 obj <> /SMask 277 0 R/Length 846>>stream x-nUAѹZL15,AY MP`(xqssof&qw\DL1y"&O䉘<'bDL1y"&O䉘<'bDL1y"&O䉘<'bDL1y"&O䉘<'bDL1y"&O䉘<'bDL1y"&O䉘<'bDL1y"&O䉘<'bDL1y"&O䉘<'bDL1y"&O䉘<F,jUsEnp飇(Gof+{{f.m]1nOdbu#~9 3Wp"&O䉘<'bDL1y"&O䉘<'bDL1y"&O䉘<'bDL1y"&O䉘<'bDL1y"&O䉘<'bDL\[c|:3<51>٨woq|flk|5>٨t)_ƸwNƸ=5wcܽҘD<'bDL1y"&O䉘<'bDL1y"&O䉘<'bDL1y"&O䉘<'bDL1y"&O䉘<'bDL1y"&O䉘<'bDL1y"&O䉘<'bDL1y"&O䉘<'bDL1y"&O䉘<'bDL1y"&O䉘<'bDL1y"&O䉘<'bDL1y"&O䉘<'bDL1y"&O䉘<'bDL1y"&O䉘<'bDL1y"&O䉘<'b~& endstream endobj 277 0 obj <>/Length 3579>>stream xy@MB侼PTTEĪm=WUUyhU_ģzY}jzz)ZcDo99}3I\h eogٙfwvv5WUBd *DVYBd *DVYBd *DVYBd *DVYBd *DVYBd *DVYBd +(7ݤ,m ݞݴlRl9֎ ӲY6M3} Bd BdY~BdY.D!ٸFƻs(&m ehxm32iM$/<`$:${%]c^ fv(ip0:%VsWEMپS-oc(~9CVlX:>fk.͡tmSz&ԔU%dm!Uߠ>ȺpA*m=6E>oPgei5de4 4 9|7=%Y\9Sp"*~{yU?)pvűQ#!Գﯿ ZkuuC/bS;@PSIZޔu? 0Yڑ^ͣ)H=ABMT?U^WUlq|wS;v cʠ?[*p]#P K HO肏,mRlsFeREA_dp߁ك^?A.sQ'B@+օ~w[W?]UEu=O@&R]}Tʞ =t8MZ4w>7͙x6x!\g0r=T=7V%5*l+B{(*Fx ]@ry؁[_C YTq{̮zSԻ&ɃQ÷/P3xVY_ kA޾^NJ'ׅ>r63'IV`iYI6k={VґYNqv|}eY.D 'D Bd_2}ҪO4 7ښq ~}z5;MPdfᅬ[F)uu)o‡9CB둏8l yʨ#\FgBI^c=2= Ih hBĊ `ry1q;ϱwxт,/{6,NhrP.V3@v J'<<ĞV=jpA@'} Ae&B<e.ec9h;FkG.~tmCl1@[qc(fT aG\ҜӂZ[ rφEzr1xswzi9-t {hs$?עsXE51dt\&oz^MXfnp "~KdWY}&9#KJ\~uENuݔeKS 2ci[^:# S:<^G#m}錎F?EݑD Bd_3mPфY9 MRmB % FD[Uǫ ~Uݞ vf?*1S>RGv 0}[93`' exbf,⩍6jk;JwzjdwSR'kmїu!ƿRl1VJO֮tzYSx,.+I̲sjeaG-nOĠ7ͅGmv'dC,r>l%!5d[]rZt4?f,j4O6e/w x&[,ۇiJ1[;>/% {_!}̓n\JL i̞*լ⁙?d_D Bd Bd/;d+YbZ6WD0G[[lBZ8.*cP̧݆e֪AV֑zb2hdb0A̼R~?ٗTw>lT;Iig0lݙG`-]Jd{HSy=H4IlE$*A{LNvoFd]Kd_,ծkWDl-s=#B3}>;\7و!#yP=jv4,$ ۓvj,w7I T}T3]TmZ{7FI4X $mL{G;ʦBNV~ǹ̯(\g+[*kCZ fx? lZpŚ89EF_{-DW͙!ދ:_7 "˅r!r!\,?!\,K`KUt1[6*S6WRu}enzhY-XeILc:b>DVYBd *DVYBd *DVYBd *DVYBd *DVYBd *DVYBd *DVV^G endstream endobj 276 0 obj <>stream AdobedC    %,'..+'+*17F;14B4*+=S>BHJNON/;V\UL[FMNKC $$K2+2KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKsD" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (]s@` #=AKh9RZ+?NiS.AKh9RZ+?NiS.AKh9RZ+.g%<0D2ȿ>¸oFMȲmr!+d/\P+QE ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (hx]M>yh +?NiS.AKh9RZ+?NiS.AKj)is|-nǒQ^ ,s8EaeA j'Q^/6=<72 VIeU= ?=֩k!i4Y(ȼN6C࿩ZD`ӭhKq30嗡^J73 ?knPLmnFHmH"jgbIgbby$}HVNB}}|ea𝪠rqIX+3`((((((((-<=slNkhNjh}yo`$f";h 6Xp; vG?Vm4)igqpwL>52;EӴW_6d=rJ[p@ r}~鯡Ұoi_hR:44q[`[ns3zv&!FsRt-v1)S\KH q?J./w߯X̊\QXi#YT0$z㚁ݤmśԜJ-+n7*JWQv䉖3qƑI9DGE;;K\ZQࢊ)Q@Q@Q@Q@vrIQ ?{Q@Q@2xJ $4ҸVWK=+&YW,&X䜚|0AID唜Rd5;Ѭāwڭ+=ُAW-|9I{smn=kD|G,:ZKnkqF2$*O<(wgNwQJ"U$Owkz[Q8~8ힴjZNx6NӮ!HU$ț~sgzo%ƛoHqy<(4.>PO'N nJfI1,N%7ws(Q@Q@Q@Q@Q@Q@Q@1d[u@#Gb1q6'0g!f> ~)Yu H>0v[JM$za{TgOO=i5/\08\9A!X`^JVV%F[鷒u*y\c\ӝ&WXn#?/%,m4͖! @fK<"v1csE6MGl<{֩ں̗1?wʵw+t~Ub@^VԔOn:h4 Σ%F1cYݾnc]y.0k.zܛÖ׽@( (((((+>'R׏װ|N]AJ((K#wvdHbyeuHfcu$^!Vᕴ FelcS׵qECCmW^OwIϨA ;5 Actcǹ4io`X;MG+)#|ߧ^rMuzz"Y@zC`>@WE[_O+5ȫk_=AQEQEQEQEQEQEQETN[K!ªIк_,Z1Crz❄WN6X4LQ`l aTO 桿Zv=<6D[Uy?iv,/i,4qx]L&0zP]Fqy_Fj1f,Ēy$'ΚI_־^V,s,SҙEI[cRrw ((((((((_?9E\$UWkG(넟ʀ=֊(t|ǟJI{VDd''R׏װ|N]AJ(nSӝpҷ=KkZ,HN,ASW__Ko^~##A|zjyᾰtX?pDPAuos[ E&ffWrrI+Enb+hZmdc-]\x@=zk{t|Z|qc Թ\ڰ*MWנWjV@zZ( ( ( ( ( ( [لP8HEX;9]&sm#8DQV/#`%8ibF\?Z=CVRѴl,HcߟOny5V8 0{;k_"LzɌ?V]ewS]% e)5ߟA#ɍ͎qMmvQE ( ( ( ( ( ( ( ( ( ~pW]#FOO"O@UnnV *1\81ۧ7NV5.Uo4yHzGb1ڱ5/꺃fX#8'xhX%'wt-8PZ]}6,31iQFĶ (Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@{_ Կ4TQYZl>z{ "cZ>L9¨]e+X_:T5K>1ۨޢA)g\]^Fi$8Ȗ(0~f 2xBe 7ْDPL$nvMG{;k1;&2 s*Ϋ(H./9fe/tìS_/6ݿOP+S ( ( ( ( ( ( ( ( ( ( ( >9OSaqW']W?c/rgH y ӹ-LfOUo5[3r,S>qnTw}j+SMYRg>+[he0^N{v3n$IYtpIiFֶ̖rlҡslL>g'Qk}<5iĸ{{l} XmQlu4آ}g%={y+5ĝtLc+455)S2 ( ( Wxլȯ׌((=S]Cxf[knO㱁Fw콳#].]c߃%rxj4:*ǻ[Zc֋)/u7_J3 j(Z 7'QE ( ( ( ( ( ( ( ( ( ( ( ( ( (  Կ5ğZ]ޟmq ?yPCӼCMizIOqq'1!ެGEOy[}!Kky2߳~H1Ӄ1U,vla$ -ܤ\p1q]饱GZ+#y= 2X#XD >U 'ޝI4h)?ơEYVO% Ozo'(֢(?7Rh)?ƀ5+LI((eVEߋ+{i%MZfQ]G>j /Z\qެo̚;QEQEQEQEQEQEQEQEQEQEQEQEQE|)IGW][m\7A4 f6F1ց5sص_i1Iw$|Đ8{wlRU77F Y,e?BgK_sٛ9S l͖K0OSںM;Vgd3;IWi7M=P>y. =ЬJ4 G% OAEdQoM?(?7RkQY?h)?ƏJ4 @VO% Ozo'exE}cf '% ODÚP|Ig2-ġ<(+t Zx} >_li95E [hY69=Ns˃\j)Y" "*G'TE ~q&"\^&բiǕc~"($(((((((((((((((((((((((((((w˹pCt}6'ڰ_m%rAwHI6xz$܊ӵkGtnT*p?Z7Rnia؏- Nr%̓YYGhSbKIފQVEUKˢQTdQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQ]o<;rj`nNs3c@jݖ hEv֐7~~_Ӿ"O {gŞ$\#bA>? )׿QA!EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPS[ڼDyi\"rx?OQ[xC3pT}J ^AϿ3RtiVLlX9=Af_ZM[ZB ݈ӕkꂊ(N(((((((((((((((((((ZZZ/'sQ{@7b|#'51C+i˗EK O۴+yCh ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (o4jY݂~B0 1ӹPma'u1)fr ?j5}N}^o7H44$YmRm;(QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEWG<bdDcX#&_0Tߨ&,77ᗂR$x98)\[N/R(bؠ >\MzJ+أ~Cmѐ .{U:t43rM6-E^Q. ((((((((((((((((((((+sZ֣Gao^˜g[i.b4w&mv Qv%Ig!d`r {Fy{y>*E!H\RHM%[Š(@QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEU->[.FD0ϐ 'F=-溙a ?iXof2.x{26x<W!62 c3pz#׏y6ʨW9O}~ol/\O +IjvךaJWQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQ]_? ɪEWMnCr$q=9\֚Wv4|3eVo_me-c#=GEIY9f$$ڨ&4/??SRlm8:_ (QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQ֊`]o䭱Ӕܰ{uu'P/d..gi!t0W s=p  KB-qrS;UۭR+pq'?:NI'dyZ/x$ '9/?;+S((((((((((((((((((((Kw+E2 mwTTI1T,4&UN!T7N}9"?%Ӭ]$&? ,bIs&'IFJ)i]سI4QLͶQE(((((((((((((((((((((((((((RY pGO=k_NLPkYd>-m-˅9*ڽ u?إY>mђc xk/Ͽd;3v8⨾1rYNVGZp%)[{h;ݘcJ(N&Š(AEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPE5[DLuduDRMuL^ZH˯JsvVdh|7g$ޭ k0Ht87Z@'tLܓߞi9[55f+iGsy5Q#|_Sj ($DNr擻 (!EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPR}lgʓMGSn=KCZ~^{7;p3HYY[Ќ|7*FMqޒI@;3{r-hePKF!Az&%ĨQvSH3F#s)j6+cR<_mH523RpwKI5׈]89/%9=BrF(_{V4݌gSڹ`Wӻ}rKr#9Œ0I<6QvxLApzɫ޽߳4b06UBTa.iu}>D|̧EWQEQEQEQEWdun=w,NI ]~[{LvlX~hֺ$7\\f7-v9 q5oQ^VSF[dO'kt/u8tWZy_jj|C-qcqLng:qGb)e䶖)$E霎ST&]{ U1m#D=r@=}8{}R YΙÏF{/9M  4&wg]HXyՑ`~}1VrU2En]k:?sdZObeGI+TQE2BWנWjV@zZ( (ZV>Aej3`n8Ohyկ5{;fFY_;ksofbnG* qjͭ*(Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@iDdO-סN|NJih2||vۉ}}iL}(T/b}_/A[HYIs"";9¢Ae(A͘u޻HoY5̅aw?AC WjR_em}"g{Qĩ68ȷCxkgY״ Z1$fsv >t:YU+ eh_*+q=c-MGP9Б֨ cRJ]9/~bF>Uݮ㪟~ۥn[\wd3ё-se>EȕB\YFnn(wN?yƯm?ɪ|wjrF c}+,'mlqzP(8QE2ᕂY_k2Q^x 0OFirWbm-詾't}OU;>ع܆zC[:'=i<6CEWAEPEPEPEPEPEPEPEPEPEPE,0z/kFMBbm-Yc&l))$vjUd?1;Wp?t^%Q1ӿjIcI4is]Ow0 bH:;/zMb1֗-5|Q75FH ^C\*\XOZn{'rD~b77j>$|1v {z?a֦*˫y7)~!l:lajoS?T -ּS2OrryP=y-B|/fҴzo\|V5m,܋$?3 ?u ,DBHM.a_ʉxiz\EsxYJꔒ4?"s5/{{641,I'$W!Av GJ*PW>}Yqz!((((((+~m/QyˏCוW|MNHN|cs*#(L:}EC${H~?Zszr0=GjsG#i<Z3r=EAXɨyW2h3pn;QҥW)H=EKW.26ǬZf o zQs7An{V1+ F9x'VNm1M_Ju(Wl wtx5w6ύXc+6Ԯi:JZɸ]$_J֌Df{cRQ}$WvwRY"yRUu1?"Zs^,(9qm'^^Ek_OQEu tخui EO@qqV5Zx2kpbSOzԱšnk b8bIB`kWV}GmV+taUG=ފxZ[]=V9Cnr'YQS"םzaEUѺlUԂQ^/COQBHedq8SN<ǭyN+fHԞ =Im57)l|׷|8(?dQEd0(((((((((GH~Q):zRp6WK/8*r3s`!B M덱{vb,ri}ǭ_ק/`ʟoP[ɌrMX`<k.5Va)r?Jnu-  M&ڡ;B>> !Oz!oH1D[aBFr۞??MKƶJ,tKvԮRǸ/0WfМ+sϷLҬt<t?'>#S+D]3oZxVZ[\vQ6>ƳXxjbD@sm z'!oaNyDz^i{Ku3;-#]4W躿CJS.z֧rd| ,0,{ j#;aFMiye"w`?jQQݗvkiV+2$*!]Gn$ڠ߇֝8r}ElB.C=ج"dcs`+yp)k/ֈ#FRO)Hɏp.ON듙ē; Ā;{U&KR{;a0 *βL1!^]$Sɾ[ +s@((((`! K^?^CA:w_=ԡ_j“cޮ.o֪Ϡa,>^Z?$>ikCMn/"in̞»Q}N]篓nֳS Q'iӬ0DH=t-۵>_;4⏷j{Xi,4Y-G}X"i;boUrf#q?3Q,b]<,yWWdA6VЃXHvxԌMú~8)yoǰUk]:ӓCZRon| >㏡haj~D}Z{:E<}S^u˩+[ϸ/{W-O{;,,kxr;Gtl>ߟ~u4>lX:t3vcvkBX[ۘ-W9szgQ 3MDircEޑ'{8:-P{ ](ᴄd.3{WzpD24Rϻ>IRT\U)&ftU[yX| N:Al/E+%" n5.N:OLXi7, .@ tחhLvx۔r7yU"KI$4)=G%S,]5V$ (Q@Q@Q@Q@{_NH)#a7oy0~t>޾i?7oq4},%rݨ$y?7i_o3tϠ]6mxO4>gO*ԫ+ 5M^ǥ\=3?9c>Who܀ ϭwSXw~knE܏qrAϧkƧ~EG5…iTܰPhF]@xVuY~dg؝OV !ʪXWQis,NmdR82Pa%}U$fwrX>ɭ-vD7 *)pp1o?fT\kj*-CM?( ( ( (;ZĚma$Brs-E;-(DMqˎc:kzt2ti5 ]K6pSSԩG6YPWRVkNW]<(xJ2RWAZӚQTdQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQES㉤8QsV8J`*\݇w2Zoz(>G5pUF4[)&T#31¢F~W-2(iN{w& x2S4ڞ|3G~ KEKR5iq{oYP}EZCG_ҏ>D^ilrJVu}VA-)cyyqcu֢>!$aL8~ ?sS7/Փs]?A1ı|7?V^K 9 Z2\F/տ+5OO' EV[0O߿.wmJּCw;c)uGAX,sN֭5Հn&') _r.4[Zۨt܀ql՛("}Ӡ{ՙ46qup*cz tO`!r@_1;}\u1\; Zs?'-YV+ӱ` fyuoo2db•yt~fKG#ׁ*+F^+f{]:?C^<ʴVܛ ^Q*P09;U}IU12"f'wJy.fim7S=SF Yj3.J|PK6*'}-I]Inn@XцO6AanGOi: \9-mgD+ dH;"RI =)UF4QEh0(((((((((((0ʲ?}b`?}7ȿ^ 5 4F;Ƀ;"֖O.&|̃m#x{Ns569&錌rN3SRQOST3>(9((((&)beV~WGcM7K:=A?vN= pH#u+OM+Wdy,A{TUed^?R"!.aMBc yWh=*M@iv~Es.O&gw_ҩL.'yDInTTe'y=;[ͽI结}Č=vhI%dVES(((((((((((:eogb`gm.7:z+>lD~Ncn({_vD~N3wLsLuJo/q!u:Iixz)ujw~b|zp9F3-T[Y0]KߤNW4 %m N:z-wėJXļ"~M쳳31,ܳRTk/kEƗYwiXTŒ;fn[J^+pUyoj)*T*\~DHRB2)Uz`}j曣Kxcz%H@UA>ac~ˊ*_Hݐ4}FҮϦcUr;~ZǿקF$X"pC9d׊ՊmݎiQ&vRIlQEXŠ(((((((((((((9tm 7"oo f!嗈PaQ9{SN|-׏aG^wV7R+66™IQ׌ -NE9V+YQQ݆~F4<$,M2 4N)SVDQEQQEQEQEQEQEWwF״ˏYx"{m w`}Äɴ.lu8}CM;2d1>aİIftwF#Ն{ JX5Kx|O̎[P|Rq^'Q{Go6'+s}t-^<)hWES2 ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( )Ȍ l7JGWf[Ĺ$E CJ!P2[qU$ "oy~rB9bIQ5W) 14W}Myq"6_n9?bJ4M)TKDyj+h><*RkH4oZ-Pq2Ga&K ex~n!arެGSO|7I_Z qZB6@=dzh}r~3z"v"P3_>ܶ|Vv}9y\zobǁa*۽B[ZGvwcw9cTpWJnQ$Ը pǩ!c\zӡ3]ID]ZkgjuY؞9k˞/G;^G&ތ͒:4K=[֚^hB̛#^qN/\jdBؗ.W%q{su<Ӡ#Imh$7Zlndh#\nA$#F,Y$J+hS66QH*[kYd} C M{2 d׊5.Fo.lg. aFr ϿL溙yPOfZ\xNT R-}ʶ vyJvR\q:2ݙ^iXnx>jMzPӥ06q"Esc5Mg<,n5m;ONB[U=QEg(QEQEQEQEQEQEQEQEQEQEQEQEQE*9ŒqU RԩlHcl]=kإ{\f3roHdl zUW14ږ(Nz/cSZtli(DҶNһ x6}L,<'տ xZ(mΧ#xI8ou?ֺY{.K?--ju}JN~vzCdxRo/ۆdO7|}p={S=ƥ Zy1" ? *VeBq5o:gm ꓒwܕ}wo}x2Mvxp?7o\FY.#>}}O).N:jN$S?] >$!"9Œ;RyVŮ2򕷈 o^ {|t?EEǓ֯Zim:&NpO8yv)maf;&"R"u<ƚg[@*qsG˒~JM^T4H"Yc3PjE`zuBu&Ek+/F[Y\q>i%{μBrwKK}WP)fp$ }48ϘGf|L٧t3# Ԓv5lʋncI492yD'ګpF%ÝFl}[QEg8QEQEQEQEQEQEQEP R$#Pokmk)$GGTT:4\:d`bˍ>+IZ)m m'c9t767 |dJ3VTjϞ1氚tcpTϭV]7StbD}6GTlpG=VKI eog=+>giN:RæZw)QEQEQEQEQEQEQEQEQEQEQEQSEnAoZڍ M]Nz/N$ >"_.>򪇞ԭO.^ʆ:˷fa#HrƑFM= w#:-ҕCc1ާpz{~JV9hZCG Ojv:$_l^9gn.G;3Tگ4 Iqmmg>PK`%ߊ^tvHy/G\9xװտWY _^ɺcm4#nA  -9>ǧب3|tߝg\KKk8E[?Mϩ<1s95o/^.1,)Tti *AW40جku^۲  6>v$X#R7HAcOKl4kq8?8SgP{9"gҕGe.Z>G};ͷ'YZS1cĶU3壹ltiE{P| q'>#QMͬl$,"?s_=VJ|n]vAm,cc~v."r(ciG*OSP;b)?u-B]B2N}UQKcsZ%hXhrCCCV͖ۖ\68?e=Đ/3w)sʢޞ+l\LYXu`T%I2Jz94+H1wI-B(QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEoxr[ԕ <62sךK -P3Ӹ%切[z:&u8R#5;Ad .~v¢~mۇ NݒV((((((((((=Z"/mJ4ͽtO {psЀqpiIZ~HXF2yH#GjMIM1t}N V_&Y]'#wiMY3)ٜ\V&.#LĒc9PthܣVA5^T"G8,z=+HT!2nӎv;;bcv}n~~MmfK)r[Uj%%tsԧ:SpAES3 ( ( ( ( ( ( ( tq> '!}}jyD?ʽL6.1"RpHRB f>Q,,I4i8'D`-߫EʖQl(ɭW*D{bjn-ȹ,}= H/i|jvߜjQi9Imд As[#*J1-ܼ='jZ4,NiS辕1O yu~iI95b+lp=){Rhpp?+JxzXZ_Xj&B463k$Xo#QտՠOT}Yݳ7dž<zj[Wye.v9lב̪⤩-ߘNMm"kydpR؞[~?,zY(pGjo]jno/daz{©]NKU8>M(_A%ܰ3!To/ ;_«STܚ]:+b(((((((((((((((()B$((E8HU&"Ұxm |;M˅9ԗ,ٔY$z5BUu+DӬ"Tv3I9s&qPIqr9\qϽav#: M۹cN盼mEN\3֪QDb^uOvQEQQEQEQEQEQEQEQEQEQEQEQE8{j6[vyS}#01Zi_ \Y9@3 F}9z5QUCo ̈́$Öw,p*oǏP*ht))NՆc>߉xl|)oo[B 7NzVr8e*_ ޲*X~4;IDZ!wXutbF"~u⵭0Y{~~K3Hyz cK:5?CSV!k'@8$iX6\bqiEz(U.p&G B7FGRyjqn`O[VVo%&e {֥L.Un~e~ݹBK{\dz}IomqS1>eHQ"'YyrJ|W|]INz=ר׆[>c),=}qү ;+[SsK!G?87K(7N?QXb) f@ck(uetZ fƧ! kVFO}Pɀ+sӵ;Ҭ- ZEGNsXتbUzxwEzm QegKvbF7r1TQZRV (aEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPW!RF ɪtTnkNJWv, 4];ȲmY}cPO^侅`]ՊGQZ_5=%]lgHQH=y*MխY4Ҵ idYI?ouo\34gkO<ۿ៯pzuMeQ/TNBs&kif-"@hXD dW lLϚ*^m$#x#Nˆflx\>VmS0~T"}d8!֣ӡ\2׬Zj94p'ڊzJ0W\g;oϫZ5hM>ixjַ1\EHm$.xx?CX"܇#*>g$߳;~P1>_pK/y?xRX0p?k$}R.dL`d Vl f&nA:uƗjf=>[Š( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (? endstream endobj 275 0 obj <>/Length 34874>>stream x\l ( "v7v'vwwww|-*(*pvvms޽! egPuD A!2$B dI@$!#H"BFD A!2$B dI@$!#Iz_.{Nvb%`mA=ˊ?r*$K.Y^!Ԕw܍geYVG2] ƳL WLdH zrk}M8дv{5t 4gCѱYԯ/v˗$?9~$fo8r.d=Fv#Vi^~ˋ٣ǞZ9ޗvU00fL6Twc}Qq T {{9g:a bsEicWj*Xgu7T<@1>t &6}qc |7v#-|ySf|d*DsTWK3ش⚩DޡO9@K DW<ӳXs!*Q.ޏ<\xx=.0/;2 +{iD?Q}!lfGOH{.A.DwqU[#Fb>W,!0.-0mS`ƈJlۮj6, -/yVlE('( HJ1y`^8DH˕UKF~F%w,k|[2Oˊi~;[UWc꺁YmhGBYXfeEQDZL"vM<[BE*ewrᲗ-9Pf)B/coF\l1j|,2);ӢLzw|VJXR2O$㳺jV+:=. mj< ݾ\" xT-);X[ֵ'`Ã%p(?G:ͣSm:t<}OH$#6ط< `3LxEUe6BD=;Y~%WT.ctoM5 O͇^fiGyqwIJi@$!#H"BFD A!2$B dD*Ɔ"dIz&7":U#͕նަ =?RIGoIb<'v2Z!rz- V+O=:ݮ&AT)D/EɆ"$xI$> > >H.:I%p5^\-Є<] !~m{C+Ks]mCBߒ[%QmID:z6 2ͪ>dw'c%+L#vyf|r J|H$H"ah:WQ K-`BpD?h VF)k@A69 1De7ЩߨJ]Kv y) iYo\$Rήup{ RR>%Ae7G,W뼜&C( CsuD9i'⿥DrGˬN7/+|ԟf6I{XH"Ѷ]cks.D$'i$'L]AՋkgIjm ߃?|%ڪI$GLcaNS>|H م_$T2*ld_?M[H"yt^b,.9ˢ54I/ٺ|tEɉz[V}?$aySHuR!ʹ1=<'Yzv2CtXL&|qm`yӐDfF71&ihE<:G`H"RҵySO5}x't>urMM^b5?OxrjJ@$<}6سOҟOH"0tָ^'n>ϗ!ᩥ-h I~ψ+AL5 g_ QNֈH"pvR|38?ӯ{?l[٩Mx*($O$ѮDRnu3^vc;93V֠H"lֻWOw< *-9 ΀?!|/Hs$yԟ<? X7O~g"!,HjvmZT yo4SZE]ZQRw$" NNE7l;I$%jQP[xG~}-끐D?eEۑֲ;#/6H tIqLssBbH"q vc6~s=ce1$FGIAa3ω=}!v[W[=B I$3.ti-Sid*$ .؜[nɁ}OMz[C %I$+uoY;q@t4mg} ] H6tenQ" IDc0r \Ɲ1=\W$T=ˀ8{x_$H:NPA6D°Z07O6TBH")FK/*`a$ ;1juޑ&CI$!u!'޲IE$Cf5 $ 6nB$*kܶ¬3F $LalbE\pD%`,XToԤV+v+,H"dB?׫NIĥr0w/s[t H:b@_](Hb-멡O!H"L*p v5ؕvwe$*͎ 'L$"̴-ogwEIcqP% LH"?k+W A%$!ZÓfcrn*KqE=AQ$ (sv;$:H"Anx[erZ=)K=w"T^^ l/V^"殮W T]"pO>9 Z>TD6ZK*^dmdmwuqɅ§Ӷ)" @%j^0"WT$C?&EJ욙\$QZ! g1ZP.LaIF>Sp{O m-[* ( 9I`KJMUY)sTD>@(icgCNWD#(D+(C~Ctxy$*IlB4!֌oIT&5+J"P&R./DE$bWĦ\;w+K*H"9*RRD#4gT{-+H"`O=h$N$-@ 'H")-#eBFrPn!kCa[?,oDTRV6@z]m^s)ITzO$g\ǧK)ITHGړZmITHhUAZKe6H 5J0 mB%ℙqs5]5J_=[C6^Nvz*eG_m#K$D5a|AŇ6OLJWQ.0O٩PçUhZaUtH?j'gun[L^}@hsn>gF² #@ MEJ47vd :2ໝcǗO׋~dkxyB+fO2Vvw;JcKCyJ)>C1GSD݂T n@'MDf:IT;j͍?U|P>HiEaӕr0e/Q۵ $9+#.QK44׽ak޽ M$z\ꭐc) .b;jnﵒr4*xh{YGMl-?2zԜ+47&$z$YSh4y5 "t5΋xT!ioKnIQKnϓjR\ TWq{ ;:f&uK~ # Ux=XPR6(ۺ=Z3*;+DPU?ƦWz8G %^eATT %Id4AٙՔH7oW%T'ѝRq?(jJ>tW\::v9|c߬vk ATRrx4vR=M"Xx3˝ccD̯ y nv 6~ʌ-X On%CP5`U¨DA0er<P/tvOy!Id]iKɁjzIcR>-gBH76-P {h_KDNTSvJJr@DTj+<Q'QJ(*&QDI(TD$*l,6o)]lZ*byȮCIt#!&egE"TK2'8EQ_@0Q)8qٚCN%6eQV/+HJIt˽m\BSf7.>dRegEBTI'Gd*.9F`}4]eJ4x-TF]$ q;6|3C E$z`\96j"єmѶ9΄D^'?.QXݮ+;Ң23l"HKyC8);R*iG;8rP j.OL9TE[gTv$ӆBSY;xH5"7P.O|C\U"[.PrNdا JdsZ٠-KA]n9*{U9}2_cC2DGq6Tž_H4ykLڥ|U%jwr8ȏCKnw(+,qPG%IJ~T:Jh9z/ګjk֒PT-"HɎCC(f+dCMͷl84fr/t()ȃy?GR~TJvNX6SUGiv DV~TIT3cz`<ԥT(x?V0M:­Lh~GIY  J~RܢIˏC37ŋ]"_Ӧ'ITW~& zIT ªfB|+홄IdT=8^WJҖj1?;Nf~T:IӘ ǰSCp|9A56z)pBf~T:It-,_(&}HGšD՞/_IkI͎C'l{ ŷH%[PK+eE69HgRilyB)z],`€$GšDkψ`S׻)JЀ_U&jfp{rb,$Q@C6X2~`y3B($ѺUՇ8alw aJH4m $AsLu.&Fw?@wm#*Hd:Hbz}v@"wF1 $2n|/SwLEB^مc{wNaG 5$:0 B*[vxPmFyuG!GThrx8|h }m}a {q@@u5I}Pe9|R;g$Zgo$6DFmI:ۂ(_Imɹ *,~R˦Jhn$g>Dw57Γ%IPM[b85]NJWFWs@+TQ"ng\k+:ҾU-^Ɇ/0DPA:9NQowTV͇lgt Փ{*R PeJt`DE]A$.oܹ4j(O"6H>8P)G|ӳm \;<@E&Qz5I>8P-kÄpvVSH?EQD٫38$U˜yחzpPSHsUeąI>2-QqxYdZ ժ$bԿnyաFv(/ˠ[`iNͅ%x:vI>*mD z#{A&7·IepTkP!1dLƦx 5yahz|]|_"֡VRD7\tB@"N!"%m&.lwneY5+v2_Uu@ uTperzSK DVvt~ J.OZf/4 kkr8[zWTIL7J%DZtV{v&QjD'>aX=k OEfZV.h`hbs4-豳?NPwVf2[:%<}+vG x=~[ԙ/D/3cPqDXŕ`w15#G’J-]».-A6@>dťf[dC~nجi)ɉphs.ɷ$oSwgY%jw)"hvU*">Z)z9}α1[ݑRw;g]z%BDUJ#כwk’*z'#) D 3Q/"t'$r/zd $"~6243L%E)~{-[oH"RH;&E)ewT`ݐDIDu(]$:re)'<$p(rA&K44՝83 KYA'<%9͑`BD*koL8$@S%ElaU"I0v!ݐŒTq4T[Q|ꐌ.'3e"! gˆP4:T[$0$?./5$y9n$}(AjFް$*Auy',KB~П(^fq#)_Ȗ8Њ"hBK&y'Ipbu 8+ɭB$H>z>zիhEF atR]_fQ) $"$H $* S  %WP{ r=K\U%&cIŒ~З0:iɐU$t$'ךK ,, =*Ajt;mɫnJW&כm@2lyt0OzĒҮ.RFoA!2$B dI@$!#H"BFD-eWF\fLbWj zgcK<ZxX#?bRX̋.ȏۚxiIRFǫ aS h)7O<7 } Am^Č-e] l4в_H4}bԕps3˰+"#^K2 eZEU,S1=1CuU2n.]0}\9S 0?VƝ+ٚ@pCglo ]+> uuǔvߴ=n s:75 Č&Ẩ^h3i:ȑĴ`,Fzq#Mig=Mc(E&ƃyMmgpՄ3}^m_ :u0Դf9Dokcֲe͡`. ~w,M6m3 ̪hPgÑ&ʨ֓cۙ{kHXFA%s.mÞE Yk#X]  Js׾¶%(S7 IEw{q !v\'n ‰,Z‚,60~x'Mva\G:wpi$2`{cU*7u5 [VJ\*}u#آJI; D?7!Kk-pXFivmj "s.Rd2YM-Iq?}]~l .yI@t†K.@Ům^6 \KJѺi85\LJT1H ei@\"Fx/I&DxeW&SKT'I$9.\Y0vb}3pv5'> j5mƥʌ<0χ÷.m{~ wid߬-8h튙6HYYtwʪ `GNf {'M4ئksuHn역\"06lV9{IW|fdPY}@9B\LgX5~@q 6~m\ʋ\`cY`'T1Vك`wn'U^ɰ̣Wٻ5J'08cƮAtrNHm5iGTET$!#H"BFD A!2$B dI@IԨl0[eV%7T!H>[2lv2c=pOU!Lc/e܍]!mTr@ӷ8uoOٙ!Hi=^\ DsVM?$J}jx3(c}z\duNiR*(; jNNm$ A%6P`'#qI;#0!i=j\F06NV#JGOBIfr*t *;C$A/٣$E$H}] O=!Dy7z->パDd6{6 `Y3D4H'?t,XL"H"at, rC4/q1 ]iɇOlSv&Ȃubl| D3méP:J~\KerLDV汙ZHr%b AY <)3j@+fh"bW}hBz?B!T n4iGVվcnٚN"ݏ29IPcIH\U3Ww؎ V:=!T ^`Sݘ$`kÖ[dNn.UV38NTD!LT\?U!UA dI@$!#H"BFD J"|pr%AYwOI #vzH%ћ&5q}A4IdP*H"BFD14[I@cpD%!vdmir@(DzqbDz&zc0iWĤ@皣)Ll#9y!!_DZE"x+n7EV#!?bS&yFhR+z~NǤ de5;.2YZ\#fR6=HFGQ%5I\gΓ"$& F(; e`} {j XѦWD[*( ڼDMBi#v:R<`XLVdgvM>MJ IDqj>Dk`mUBɑ[Xi.L`%"E$r.Ǫy,EH$1LJNXXt%꽣b9  Cyl5Jh]ܾb6/?/> f6fa]7*\H$H"LNJrJIDgu~|/2A-ŋH"_3rgٳgw\9x$*jA=8$8i1҉;RQUc_  s_\VM*t9B) z؇eQfɭG}m"lHp~@A}!N1bډ)&t7NeL%D૥aL9kދbl]lP%,$iyO؍]v >At$R&:0[9zKm?/B`q?%D&ok<]Fm#g}Vhp˻ TsV狳fZ+rk1"Q9?x%YpޱeIo~mn!GEtkD1(*S=.V9bvD7-p?cvp/wzUᅑ"$4|ϐNB2a|5qnWwLaWp1p/6i>۬Lg~quud a«K{^VA1ˉN&nYѣ:|xTא9KLvk_ o,V㹨,Yv8SdUv#6R6Q$5Y Mӧ^c:4T?y,hVs&7( %: oƣU(K4~ch+;b,_mK0gm[;mU){gGg"O/hʶ?Zh$?& 1FgL_I`+zO|M_k~o9څ 2M9zT[5$t\7pC^IMU$ Sfv)~#+i p&_=R8_p F5$eAl-vaO`*WdvUUydX"f9-zYiHB$5wv:~~yE$ҽ vë651[^joK޴*;%|+?"}^^8D-;/+iV~7ߩ[:9HB:Ym3;3tEzMl`7m~+O:?NJH;ƿ~>K0xm%ba|I`۷xTrRHy(K33C_,x՟> pMW:ǍR!r$gɪwyDݼ] :F`^:9dDDڑL}1oObK|Dv'bӴ-3U-OFQH"1<+X|!g26]}6]%:nV~&4U%?,re$"č^'TX_̾_ZG D&_0pwfLT-J|5;;ܑdZ{jPp6es_9 MUJ" Tæ~}(n˄Dp lWԸrKd%%*JLAT]"FDpJB'læ~F.ٝ5V8,KIzؔA2:UH2@;cQH89Et*IT5@֔[ݵs]-:Jt+ˬowY#{QJ]¾!CPe΅ Tѩ%klza`}}+^!LZ[*lOdʻߝ"RtJanOvR='GTYE`TW A,/B}}IC&oǧY;' ~l`jZ)vtwXT+ױ{[w`vbGU3|dѩaVO5XJdx1Z=0vHh^*u@}(` XxmBGhBhaJiuU,"YתVaߪAD5?{Fs]h+?xWZ@_E3ez=U b֘ |[]нE": Yoy[= kqopkITN#mDRA!tWYVx>m6c5|U(U ^-" f1D+UL!u|[ eXtWDfƝSf>M`^´ZoMשM imj5?Ԇ\!?:JDVϠӥ?3ǦJJ9` Xmxe+`XJ?fnVmneqX_J5i]`CdV ى 2&.4б<=C)E\lGv7󭈽?jfET#XZDz~KJlSZ޹߁9-dB:b536,_e{%@ޜ͕k)C`-l߶e!MKIP( ށ,'DZ} L]"[Ai^{j6N]JYFHwNm'bV2c6 #_3Q@VYgp"`4{i# sST_1x~Flf.ރcB%r}VXc2fEUo)մM }@}J *ɓNPҋ'`/2[*E^x_q"Q{ºΨٗ;pڝ tJYpH#mÿ&Q K)*~/,AY=W(+Ҧ0HÑ2!["?ؼBd&" ~%cڑ3ʿV4{Oqno+P 7*@\SU:?!d[  B1n+]&~S j 놛úGx‡'׌$iz.rG"H"/l۴-cl-YeMku~ v[gФDt'؟납4c;[֑JI$$k)a] 5 qkDA۹eLڛ̟_G 4+^.h$"N؝ =Nڔ_j}˼V5hUpzЗj_Z>*Uc430zId́vH $? mG܅ s2UdԟWtf70o WD8_vVBĆ:23A *IT;~qB"I ߴӢSM!Gl?~Z?>,x;[D{įߚX pz\>2))K9Q%I5|Ő#c@6Y=B(Db|mP͊Z%/zvDN>'˛ VC^);N!IPW"[X4(DūPܿya"`\5!"xg-\¾ql[z/Ix}Js_-r1 e\Nڼntrq|XoCL"OC`9؉ի܁#EF"C~: {5XׄX+ôHcu gx^ iڙsKWPȭی3\dW.C PD6ݿ%B{N[Z2k,1 .ٛ׋’GNj^Tw- # E4nA*ƻ攉m6zbA [aPT"ؔi\7|8Tog oZ7Rì1C/Wwso0#:y ^T#F/)pG0g JweF$h'-`(*ѤACO>k`ͳ49OxwzWw%*>8b\ZgUs5"/1#Q$v\yv8}9mxO+::TQT"Ə^(0%e"]\KN ޺_kGY.^m __}/GR3mZpǔ|ūi#5m?SK[sw̯Μ-ɉ)%L}yA҆VOz} ւQ` y3-Uz#iWOK݄aĈ0)< m$Zݪ޷eW[!1!랮uqrxÄ)Jj1Ls%}(CR:J @rHV#!^qVI[ﷵ-"m$e V~w baݰ.i/T*+YH#a3VniGHRFkj!۷_{mtWT$HT'xC{v M ɉ'5H"!XXPzk_vƷFg>f5R·.07Zڪ6߳39I$%-d?#2LJ!^1qq *km1He,- lv@I$Vz`|>%J,S E#H͐Ʋ=sבHtӱDoq"oX0e6ɾ3߯ocnLa(OIy!QUtZG6P6HA'>h ZVQH|^ tK0` fY+DEz7q~cHDEXky5F_ z=0[͚ޚcƦ{DZ]RrI9c&;0a#%$ǔ;Hdto~oUU?hPJL~Zu&̰dXb;OElrѱr9w1NK$Utziy7΃zG&|$J.f_鋕Hh76wJ'N7"#i2n pw/WfOM-]J!'!c񗡵;}ZRx. ?ʎlH~xG'XeUr-"Y"PsJ]cE6عRA}c d,My=D@X2,D¨zSc߅*xs>pјz&߰ nweDM y,_?s{^mXZd ezYVAf;mcӴFMUj:}o!ki I BCk&rؿ!.E_8JD;{`Gc\irݲl6f+rKʵ>3-xNsG/EźƗ( $ 4 5;|Vj]we[ԘR{y\Pxz{MTrz3T_!DZIpd?(/T\_%~E}Izcr S-_ۢV2 ϫ1>:59HQCv X(Ѹ:#w]o{c ]vr8;IKtoh՞D6Nx1zMeA~4N޹!oc9G:>We'wdzP0`W}êS$iڅe鴬BPq9KN=n\{bd?V %Z_euHױ5hX\b_!*O|vws/{hZkۖep8A8q\F{] xqpu(2~I(m4-Imrih$gN hcG;80\Dծ,u*!$"Nft(6Do Ty%6<[I BS NjKo/"q/v@ü9Zo= ʉu$1Q:}cYt^ E9W퐻G$մ(7MZ$"Oy+HD6QoQ%3 gn;+<1ϖ_WXY̎H[a]s r#-7K!<n ơn"ea rB1}CDy8"~1D8߮}m_Uk=?3P|SsWP܈.<+Uda~rPDҁ.Y?!G<1{V~6@"bMA2>0 wxݜm젒kظG  ăp~L8q QRJor?Э/B>xOCPDiFh/?|§QS?< ³sw]eۻ^d<=4<(.;`{! םK%8l1 &.#Jj=U4ȇMtIQ;n wdFo3Q$,"L1}h&"ۻ:'N8/wl$LO{h =&pzAY1s&A-"3Ĝ(+8zQke(’lWD%0M!OcV-Z'\~n,Eֳw5=oT8y\ YND BlP3W6uɺ&OTpi^j+FX 5y17[&#-e7U}t};mdXaTvVpsLH; h̒)"G$d%L$YPlXly"OZ 4x.?$X4|X-4'J;]3>%O%QRPZYD>-1p~p0Ag&痾5RAnt$f 'hr=wC`ُ~ ,[)]ZqE4 6)jʙJalyiG@eFx%ᴵEᒬ `-\  tȳfȦI_ PDVݼ3 ^{,݀>FїWadONA] ʔCş3> zp>;.H$2(/oYe5ah4Lfc'PE%F'o4FGL-݂sE-m~Mte歺8aP4Պ(H$j:j4b {G=Sd7}~9ګqS쯤jp<!pl(&3 d7#bH3 }{v;qp^(쾇u /ӵ΢az G-sEtYARvv@oQ$|7rFFblDP2lnG .yYbGc qj96uIX; Y~Zr!,k<~#.t5(&CMW\ȩvo$DciWnOC:rק[]"zd&%RI\01{hEښJΎblM4+/]$)i]m||4GTeAxWs@w0VwtF߫)=12NtCo#N=kt˷Zyʑ)T2UD3 'c5 KP`Ԡ"r C6><0jw!!11y0 2x?IJ, Y*s&7'"QNqĮ'@Dv|C־38W|C+!K ұ=E /W)oPL`:9.'D1MwT>yQ{b\_Yf8,ll iq7\~~k.eC?UDzTzO1apA1{ Wԛd$\Ef'oU0c>^mn/,.l贈Z#\(|a|V'"L5y[KN.Z^G4`Z<@C7-!E/Ug 2md?/ aF-)h][-YELaXCf]bAj#Z꬀{:l.\%Z>Ay0NDw¢5vvmFBЀ/QL@S?>tM;_$4w:]1a)i" yve~eBYO".rE'Ǯq]xu_5XgͺKz)!*LцMFmWt kj"'Ί, } )nƉK6O#c1n<3OD)"%h N "r #D48bĺ$IZ#9~ؑtl;c&/ 5 -1g4k[yY&h:7N7ilAې ӝ6B-CGtYIqa>5T%_M3@D}B^mO\ל]#y-M]DTC$3#~5dh3 ]h5mkqk{_LdQ"b{x1̪K0lX$W zz Xmj>m;G`LM8>KJ_Ԉ==PiaFr|!Y25` lRh,"ζȟ?lc q 9]U^.xPˌM+Neǀxd D<#c,gq%WDES0VyCqp[ Ok/5 YEg,$"4AAkd-/t/P‡%]Eu]+Xu0lSWqNBleAQ$N2+;$"V - %zb˓"I k)UxAfl{J7;.ZggOeyៈϖ_IL`RM23Q~:,zXF5I׽ ZE:Xj n\`^]M v!"ysDX"R,CrCz U:hr87 ;_xKE9 \^ٓ1;w.YAS~GYQkI)oB<#t5Ԡ";QDz7퐞Pl8վkz'?sC㉥; ׁ$ƈ &w(IBCE'-PmEU@ډg69vo)|TN\eߔb0hW)Jb1FD.}a|Q_d16I75Պ8rƇ5شn"Ǚ},řW+CD 7;vmveZőGP;8K=@'}YnX]ZW㺀\T 0 ԠD /4y #4Nb4uiB#U`vX8 _zXF7EƑ 0&A|a3V!{Ɓv1Mf2A :R.GD*-Pw# z٘V,A7p=)K -Y:w NEuV("hDǚ֒g}k~ZYO+,&~Xl7aj Nz2?٦/L % FhAlQ,E- 2bIwCA},l\OjnF3Yݹ4iXhkr?t i6({f!"Ngɠ.hVnzA]vZC$y+.*yh]p*Qb!>d6>a;KaNlj[๡Аy+ |Gt|zʋcQ *!s_}1ALjFkd$u"BxtHB~7vS+ۑ" 00Rç&n +\{D\W&Tx(oo=VksW}8'vb ޼/]xGڝǥEduə ͦ:.N D fM?%6=;FWW:;愦F _DAEХ))B[\;U-"ZԞ-oRi15%LXbE pg7/L}c,\'Zψ:'G꡽ܔ`x(ԟ[5܅P"9cp8`3)5RK'NHLu٢٥X(5ɦ-"T4"8ψ+)L'~|FP"bF'ᢾq# ٖikTlTvwN-+#Cg$Rr.qTh>E^vTFRDבiJ"O!ȾЈ©KM̺t (9h.~牙ȟ˗ ΝT8GoX99@dJTod9,DsoaIP}ljٹcğkUBos[>[lAOr:/s_e"r u/_Q'6Rи=11xe8<9Ր(hUh$G^b4Qv;cA|r:퇍M%ރV"6v*qAhEP PZb@E֒-W{ p0qFW^|ѭ| 씆"Q1[5R$"N [ "S 2JZ%*] t-Ƭc,k%t`+:/TW--TTC_$#75R̢N{ZICNv[D*[`-nJ.X.|+fkFϊs94OcmFz!az'^9xi&&P5qdޕ$wr ]}/&VxN"'8 sBoB{_1;Q~hXS5Cq0zHs"w1p2aWMJh.sBfr3-z'`oo&#ul[ DdTc._bGڌŲgӚj >r, s@^ <~7*x 5|rPV\/P 5Yސ mD3o{qng:nVZD1-͊"e5<ț\IqxcE|vx˙dNCh""9g®+7lL-cUg d_JX9Av{D} Qj*2bk*Z =Dtv/¥vT7𖱈g-u$0@Kr?93抮[<5#.`ַ4Q/4ָ9%N ,VٿɐDi*2,.q {l{]@6"Id^Fr`HFK(TDlźՈ?n^/W","ۧKX@D': qb!;$a0{bp%}|ѡ"P:P#MwD~pPɏ8A\DXDE%HLDF%NՋ틳:wwhƖxS%+B\Dd \@GǶq5c}nz5ݒ3&3"Xj\Obȳ*N^NeAX-`.쒕C;@_/v 'l?$'d'l! .W6m'AWRM<{:ǀ'5/ݱ"됦DD] êԘZk'a?8G"v BkX5ʙoTB. F"2Z\oARNA~oa~Zޤ)ًacA0/"OD)ݥየ9cQ놄u6.Ɗ`q KkWQq$]Q~=4vdrN`vN 1Bc" u.%ݹCOr9G73ΑA\}W\n8A7gMb4JቅLˤhSo(ET><Α2/vyqg`7wMR2(ED{Ea#jr,ox|#K s&3_uRBA9hbJ5QS%o"ҥ|3is^y ߀~֢5C9UH2C)"#dW:-(19 WN gq^+?H9@DDƿ:Uj.*{_2v|I5wgOhso{T!k=sA]XD_$"/r|. ӟH0Wv ;z?$y93+AG‡%OJpՐO,y[ӐbZk s 12b:Av:vT7iFuPrpUt:^Jl^htY+ET`tODg]i*"&#/`U DQHuD6Ah:^W6pr LCh$SzsW(, Vs5H'BY{y'RNo/Um'э-= i$_ I/ fiεJ_99H}u/" J"܈'p lYXJv'\5ԫ$3{vy"jtyYɘnDi,DDz)l !zKk! *4u;;CD}.֢ M{nvݦPA7 ƛz{jѬ#?tqoRJ꧲xo$8^={UbS+"_&蜡"R-̃7n/]"=ϑjQԉS]'5с%0;<mKOwfe5&Lwֶ"5(ܮBb|J>87ju-sӟEn0Y_|}~b,\,L~y17T8rԊMcȕFE[- ~5%х~$ "T!SQıp0=Ҩ42 f!q'*[/U̹HΈh&eCDlBR$z_?zJ؝'ηGHfP)`g&fIޱ7ƩQ9$x0ԗ/Zdpgx2W\|JjE^CiQA})H/ X6u"# ZmRp8~ IJwćY~ <qhBO|`Z_/\uv~Ѝ'W2VgT6p8W6bCZZvݤUN·?~R&;UP5;˚dCKx9 _ڲZq,c"cZ'eT۶4Y'S=4 @FNHԆYoY)`/$2A0$z|`vYGO? r|Zbli eW=ʼha.:us/zoNtޤ~v"^F\ޯ>SBB/7p|;$TyƱuSWr N8,|a%geD0SIj:5.J%JD)"%JD)"%JD)"%JD)"%JD)"%JD)"%JD)"%JDDDU[%G(l|sCG&ȃ}:ZU#Ys0"d??_F20@`|-_'C) #"6#]SZj_֩(mv{_+O?},GDkLUB<4ڷ(몏Sga CFWYP"ܑ"o^U}BJh FA.=\*EQ?~QY*8^ѩR"DF։0"T74~eL}*ADk]AD+B3εIUE(p.k+EDKPuz߰8 N_HUE(~8 jXQn,~uN->P aV;t:[dd2e PC >G;|X'A("Ȏ 8DOC >%YU9PBn2lUHXs %D)"%JD)"%JD)"%JD)"%J*F/ endstream endobj 281 0 obj <> endobj 282 0 obj <>endobj 287 0 obj <> endobj 288 0 obj <> endobj 289 0 obj <> endobj 286 0 obj <>stream AdobedC    %,'..+'+*17F;14B4*+=S>BHJNON/;V\UL[FMNKC $$K2+2KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( )vOF(?[ktTmoʀ]Q*J)vF(?[ktTmoʀ]QcPQF ((((((((((((((((((((?/bǍr_*QEQERN3YI6_QG"e-R3ǝpF޶.0\|^97_1ǽlS"!c#QUzO)2QL(]ƥgXlI ÎgE4&Wb_Cu*ZNi博Ewvb# cWĺVw #PNsN:;} ƫxT? ?3{qŕi CT\ֵQsJMdx$F0FzF+Wx׷& +'8}j'-(5 ( ( ( ( ( ( ( ( ( ( +r/ m\ 6X׀Aqu:((((((((K,`S@FHU@Asy\ƛRWt$-VwL s`y9+cwlFGs<*}3fkKt{;>nda,Qr'y Qxs“j W2`qGO_dvF)|mz0Cpx# UƚS7$tw6y5o:v Qigr;uǮr}1]o/.GhhnR2|p#$W%R7-^ERQEQEQEQEQEQEQEx%BU{KX*6Uy+(Wu8\4*敞WrK`*NZ6ղʱQNkLL'Orj[kxm H-HAD{N ((A&Hm8¬H=OHzJEo)`3ZE6fmJ`I":%kV](LۑiNWskcs肭[TGs2ps>+zzSN-X|3nXqa( (9߈%f}DW¾w(((((((|&x@iF6L-k7Kw[ ]Z k|k5թ79ɸ ܨx((NnC]JH㺂I$DY2@[);nu;i!+6 gZPC[D)8V/mkӦ,̖T䒼gc ׳ʤi}d!no[#og9_c yR]])˻u?ӵG,4$#rXmfcQH(((((((((+KVG"u/ͳApc!W(1sJe,:ls6TsJb]4Y$T]Jy1i0A.%'>ޭQE42݅VO_iyuਉI_4ؗWOO %‚}OZoipm Yrv?L[k(Wԟs[{,mu 1ZJV/0+#((~!ȗWG?_ ހ ( ( ( ( ( ( (Rkciif\mF`ZBc#L&zsz+^͏\QWKr QՠhesE/ X}3N:{`MlsX zךX-&);۵id[U@E;K#,v,׼O,BDZҕ yG+DVS\ZW[+񽾪A+@<7#jJx۝zrwjFA, {sUhmR(EQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@LZ} Eg#cO'Z5^ etUPyx3BnKe.6n>ѵdv!@GC$OZ'4}[Y<-\pHVD<쾕zOKƂ4T^`S:(((wzqم|_D|C/U?0(((((-k%}sNUCn]MP#m 2,!^P˴ӀsLVѧm?=} iԔNpI;rqg\vp  c۵srI$o5gX'~DRr@=n|v]Cmq/گ'Ē:SyN6U}mWZ͌v318<U Œ޹(n%QEQEQEQEQEQEQEQEQEQEQEQE}Ea6^rn.!G:sp;[7H/[HjvțHGǎ 9 mCzځgdc+A!9\ES43I4#cےj:)7q((EQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@LVDL"_8\^Zz"; h%q~Y49+VB3 @=:+YD ;P`gֵ9-J`1w'|Ҷs+֧>t?ΣV.֭)J!ӅQEfnQEQEQEQEQEsK+z#zqم|@Q@Q@Q@*.U]c>"u\q8[6:v4..-!A@o[ƛquC"㼕l22Yٱh{׿' vҡJFt ,]Uq1Յ[AaᨊddlqrZ!ea-#g;$p0=3W-]̫TӼb쿭|CGqw-qrTo告p9 w3k&) +Q@Š(((((((((((((]g;{t(B$д߅nRt_s׉QW(sGğ (u,[K׀Ph{, Ls3x8ɮ%4-^Dymtfasf 8Sv>W$o FJߜg[_ԚU6GDgۥ\cȌu{YymPe w.ؗ`"5=y ]KW[t=/$Aƒ9}CPԮ ēp2N2O ՝vЗXn缽|E;yTQH[Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@U-CD?{up=&{NeQFGN{`--GRcX@95jQϬ_iТ[ؼ7zv3p*dšIkSP(gbzi)[%Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@U[:#yHR}`}&4NUMFa+Dr䍸ܣ}xtR.ml:8+%V?,1v&mĎ;D\:swS^qs!iYvt+k-R_J:|~bu%ԭ,򜻷ݪ(dQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQWt\;.)X=1x.9fYrŤÑ0P9'8xE[eIkfEqBq8Z{{>l6\f *%=p?xǰHH3ORM 5*$BK۹Sv۵CÊ(((((((((((((((((((((((((*V2y 1 ;ƄgpsOH;mf?gJFN2I<'*DhJ14ǘ;:V݀j&6@)eVc%],Al[$rM$ʩQY›|@*B(((((((((((((((((((((((((*ޛmayٜ{NtIE~#,o+eUCK` g'3U c,ҢpzqX F0Y"+aL::`y8*|3qkYiI]G%=I4%mX5$dI##I#rI=I4(fQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQVlg9"wwOQ c5*H?/dx{44 f!>76թ.5 [(gYUڱHyYB $9ۛ.eK3rbrx’_iiRi'J{ݿl<<K)؝܎3鞝6.9Tؖ:uo!FKq':ۮG,RŘBt<ҬDawdL-ۂqsoKgW.2Ip(K*SIrӺV?<\e吀 '袙QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEYӬXV##q&Weӧ*PՏӬM;9) c,zuo!o}FHG\0d3284c=3]YJcM-c qjΫy%܌9$ĄrNkB ֽW7N~pQQE30(((((((((((((((((((((((((|5[z ;lGy!py$BP3sv}C2y Pzjm4SHsK ^fgjpqN|Mr R۴pMqlm2FJZJQpI=<^O-&'j3J(QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEU:mJ ;e̳E{vOtY%V3$:$}wZKVTa)F;o 3ݪܰ^nnԜ;F@>/Length 6789>>stream xy`'ݶZZrS BDKAA" r*>EJ rܗr -$Lm=M&~&7|df23a@9 R(PH=z@!B R(PH=z@!B R(PH=z@!B R(PH=z@!B R(PH=z@!B R( old؍ڿFU HÍ;rBO"kXlj^-o($ xn{~h6ȹʝNSPH!&H#gbXaK3*HvŮuw0*9 2<ݸf( D^R#⒳F/ ^ؕX.'kB;QP@yfg' \g Z_Ǟzm{ё)s:Q~vf sz*ItcOB)_&d?5 <+(4^}ԊMEgPC+AMB/m^?#)Ҳ\qPh(sGx/_KrloM+ # ל^Bjg {2XPh$}ZXдe@ H<5.xs\ld*4G]-|8U/Q@vq)MBLeɺmkݰwe ÷npK)z/  v„7>3K=˵/(4 u YO}ީ8dPh "Uw (-p8\lb@\,J[ŔrQ,[7(4[ՖRoAW!0G(.Oƞyu vD;ntxagPQaiCqo# c*0P z c~ Dƞv+AaO Լǡ1|V^j cNrKG (5Iˎ* (1ӽEŻ`!AaOvM‚˜pU[jƊr5K0 cjHC" (:0ˆ1 cW;M׎ P|?@.MzxW'z/k}l0 G&t0^HznSGA" P_ZZ=,aP0$POނWW5ЙPP ThqpwH91א (ԑr'#P']_6v"{TzL(ו P'jU#X(ԅ/ ^^: ӘwiD<z؊&zF_Pו|yG/|$R@j?} S^koP'^zvF (ԉJNA s8)ߢjƳ$Ye{kղ[gg ( 4t4W4B0|#H}{;!(lDžT@#jfwj4GY}A~M @,|c=o]ZZүJ>ٜmN8-.EF! 駏H.Pu{8=)_㼶hvUx8ey̠?'c8'\NGk֖;vUxh&.:>F4z+,|ƷF&%00IeɩAUD+dpf؅b9Z@\wC&Iv2:5AH;/#!`t?k!C PEYDC\;ҼA (T=oا#,@˭OPht PB#j@!(4PB#j@! ϥ[ ՘^k/_ ՘^9ʭjLpyFցB5WjSYPn0(hx}}1inPgXMߚ Pi' 6WNIB W4: Q" { K㑌mtR" &f_ktR" [d<6oI+qŕY w&6WmȱByd5 ;bg)mPK@W ^7dVSpT ؠ9L@$BiI1k;NJtPX`, k޸| f1vI k=qoBJyF$ZD7gsr_|+\wbPh)L(ƇNH(Kܪ/dŮJR֫)E Wg5ot2GTXs!$+d;oBN& `TV(ht(LL;(W8Pՠs~FoQ B<]=5A!Uٮ;zؠUn l9.tA{)|f&rVHIΖIR{Qwu )l!b:}H!rpV4h+0ֺ"(ڠBa|A *d{BN&9 k)`v2/j Z o9{WWQ kB _E3F,Pnms:  `$*p_[XkT0Y.%F K(~΢` ` v͋P?\z_Q-ٴ4@œKm[P[+/}/B#G [hgPЖO|Xao7 I%*̮8 O]`bBQNEehU(GUO*Ъl']!nhTH<k%P0}->l 9>Xu Ō`wFu {RPՋƱ)D:;!zGQU S3>94)d[oEhI(bX$<=+N= S!qB~J %ī;$ #k녴{%Kr"TDm4f(,r1>u($Y5@aM4~xk{|H"An<—?>SIo=5qoS[4}rlIO# ~2%+cuF[4]~P憁\Hw) GA[4=v؏}+IaojH y9mP ~aoiB(̍K@ou]l6"U] Ua6[J\ n8 #PZs0B UȫjbjU ^K,6Hwռ)#^sJR&r )=:Wp`0ZTX ># +AF_HKjբ`p#rl~Eb/.3@B R(PH=z@!B ' 0B@b{` iqxoa/Dj|S`$u^ /vc; AߍCnOK18)ԡo> c Aa`@al0006訰VG鰑xL$?Ez@!B R(PH=z@!Bԣ..KݪO.#K4 O 2:_4C0IKcPK:)Uϱ}ṔI lݾv!zށB"$q,8W%7 ?Ydv6i)I yoY)*9]mrsL,`f>rWw0+!0E|&{Éჼh*JV"d]7q  WӅT g@ ?{t\,olߏp[I$t]y /z*6GQ=MDΉӦgeNN/uBFO OTCszr}eO4@B ;~o3Ah DbAONds; e H_B/ _H7'0񥭆H m$?P'E/O82> endobj 291 0 obj <>endobj 296 0 obj <> endobj 297 0 obj <> endobj 298 0 obj <> endobj 295 0 obj <>stream AdobedC    %,'..+'+*17F;14B4*+=S>BHJNON/;V\UL[FMNKC $$K2+2KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?Z(MdIwiw46424l6d@tV/nfyka,,B{`-^#E!E2r~QߏA@W%_\&1tHY/(*m)9 }itik# ʳLH5 ڭr.H3 8CDEtA"+č,;ր:/Jt  NA7#'OP?)?7\G%: ih?G4O @ @ޛq.?9OT ??*3zo4SoMƟ@}?S(sD>Jt  NA7#'OP?)?7\G%: ih?G4O @ @ޛq.?9OT ??*3zo4SoMƟ@}?S(sD>Jt  NA7#'OP?)?7\G%: ih?G4O @ @ޛq.?9OT ??*3zo4SoMƟ@}?S(sD>Jt  NA7#'OP?)?7\G%: ih?G4O @ @ޛq.?9OT ??*3zo4SoMƟ@}?S(sD>Jt  NA7#'OP?)?7\G%: ih?G4O @ @ޛq.?9OT ??*3zo4SoMƟ@}?S(sD>Jt  NA7#'OP?)?7\G%: ih?G4O @ @ޛq.?9OT ??*3zo4SoMƟ@}?S(sD>Jt  NA7#'OP?)?7\G%: ih?G4O @ @ޛq.?9OT ??*3zo4SoMƟ@}?S(sD>Jt  NA7#'OP?)?7\G%: ih?G4O @ @ޛq.?9OT ??*3zo4SoMƟ@}?S(sD>Jt  NA7#'OP?)?7\G%: ih?G4O @ @ޛq.?9OT ??*3zo4SoMƟ@}?S(sD>Jt  NA7!MeJel(c8q'OG4O @ @ޛq.?9OT ??*3zo4SoMƟ@}?S(sD>Jt  NA7#'OP?)?7\G%: ih?G4O @ @ޛq.?9OT ??*0xA$iğzOj>"]例lZ-G ʀ]ibKi㸖ىh 2hQ@:BXCsqI$_rKԓ?.*xbQ3g86ǿJEbs4A2#@Q~EW,S+]Mr%:?EQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE_\LujSڸ#/SUt '~>gD皞lxpVg'J+Oj~?+q6rMqC"5]Bi8_xڱ [st֢{7 }7᎟d3bϛZqq\r |䜯=j_Z"5*2C?@( O ̺DyJ v=q:_ZL]BFڅdsm݁v,QE|N'Pz-;DCjWS@U]GQ ^L"F`%rO^ TT6P^Gqk2M *ֺ֝w{%r\G=qpx8;+"M'bHy#zנg[G k)p(((((((((((((((((((((((((((((((((((( #B|cz}SwkxS$a-#B|cR_"͞8\~tkj ZO,*h\nuU*>(UZr\3kH8cޜKm+TVIJxK4H&@mx<LC-ΦlvҢ̻^+uSb# %2*k#H%#o;3z5E=󎚊('ȓJk"N?5+gh\ywF{'[Es$6ꎡ `xR!k8kOf +>fi[6{rݏ_=Hu9]"/wMh%ﺠ Sހ9ȺNLo $cjټ\2CyΡd("I%PSަ 쵷FW"ĢGa?Zñ qHtv!,1]r%:?EQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE! u PM.}@r2)h((((((((('H_1Zt pj ;)@@n~!g VG#v?RNqJ,d`6p#լ5/C.'k{K2?@8d<+FlțMۤZ7K t@")iS4 {U;W{Gzs^e*‚a\r8A*qn3Mִٌ>y%,/Ve~?vuJ}{ ܒ l60@8%/펢x)aGV$ӮiuvA͵[k1׶j]^R[^l)l͸$ч J. CSh2R ;=f-$tic."N{G.1Ī$ϯ^٬S\u ]IoI*@"A&ӎ0]Y}J K7=ēEc*~aM,h;o>۾f:62cȮ rnc]jdaWc@Q@Q@Q@r%:?,S+@MQ@Q@Q@Q@Q@Q@Q@Rɠ{4&"Dw<ï7)-+Rl =r2u< Un1?1Lubrz^R*^!vfOOI\TOyfp29*{ynJ !/iWqvRO?z:g?Ơ1Wutgc߈؎T9 c':"̞2]MG8^L: qNםm,`$*HTG1%  y8#_gdz@^@>zzqk,qFF@bvd^u./׮>[^^[{rH'SK-c[5P)ISSۥ9u[~8%ABr=⼱5<`ciX Ab;S*:J#u_mҍ# LV3Lcמ+~IWy<}x6-$~˗lK#WA-c=$Gǿ~+F4I}sH.R?AQzzw(B~zz\})s`s.mppXsMWpf?1 lJ#XB[L??(Ϝsn8W eܪ忉__1[#;U+(,]o=EXDd G sI. 2@y~ vDZl6ux54z˝Yl?NNjQZ>V;'H7c;[^`59JK8=sO䉯+wfuxKXQ''kPNҩ5^3~f;vN -2OϥWRG|PݑI=y?;Pp_LW3N18)'ܑ޵<:&Ew|=FH뎼SnXDџҙPgì Hb[ݽ>&lRA>U3T&h *O@F)d 8l3L=?3OX pgu8=^iR è4@GD1EV:>֊YUu3?Usin_QKTV_?tqxgP?,E̋TTJ(OGCN ֝qSw|ޔzQEs}3W iJG$OVI@M[[TP/$V)Q տUEbA'5oUI@M[[TP/$V)Q տUEbA'5oUI@M[[TP/$V)Q տUEp_u'K ~h(Hc]rI?އFu4VnMksigglW[ʉ%1cԨujҬ}b=?R{n,1N@8(8jCT3c-۶HU{qK g:oL')uޛFȤv׶*iu=W1%Aq=j2Cv&(t&E)0X$-p9 o.nNZja}—P܀ c崛=O$vW6&|ۃ"V&vsrp+Icc{a[xsEWm"I$bneOïUx_2W}7@)?-I7{Ms: ۧ':[hr-$?ܾ̃>Z q\ ⑯Q?t\4V2~C&x HU>]I~Wj_%rTO_W@wzu<(cynJ9<_쀜&;VP?2OVCl&b M Tg b*/ݵB_ns-OBAbKpV+vBy,B\_m+eQ_ЏX&4x*Ə7l[ផͷÛr-2 06o¹z<̖9>cSl OGT|}ܲ\?z/=>&;$p=G˼]ȡ>1?|#`,Mg)_]$v/Nd;:%u+*RPcgr?U*ysԗܿ̇>E?h +@norO)OH~ӽsgdˣ ~@sL>̻YPH`?/]jc 催t3~Dr18 HT4`I 'F1##f[C9Tm1c9t[F]01#umVD< ^;E*3'8gR[#?X-ήP=g0  ]e?L H__qO7b珧AҳLR);!FS} o XZZmS!Q#F0wN*/- &ӜAt ~ŮaϘ$y4=ԮŘj1@~CY1:qM8H=ڃpF k>r۠n|cyǥ(fֿWýA`:)rrOLf @.N: f5J@),NwYzLЩQ[!XN}h9FE{*=&Eѵ^iK19,s鹣"ZAf-.Hi9J={: 1?),F OAI:A—s9Z71I?ZC3>tY*N]=x)Gyh z rTtpwwHj gԓOOnpH>THm Wa$uX,?c'Д_H n< HmfFp94 YsXyt,Zm>[@X]%l~cUEyjTc=q=?޹kQ<'u'#-#+co܃<Z]̥V+\iʭvR=jN<˜c<bU1 3 b=;=y?P{F皌vTl1R{~w~ȿ">aӐsЯ̆a$xr@STyAϿ\!`TRd8rO9G8Y @'d ~<KWԫw_yEK)&?%wdG݌{r8ڥ_ȜL3mcIӌf?FҜ޻.pGҭø#hG=+6%/Qo$t+b]Ddc@^?*xze9W9ëF'|3m-Ϲot,Cd'}ޣ _r2] /?8$L֦M~ň_̸VzW,ӕ_'#aGqGB1w_}Ϊ=ZSs3R.l2ʥ[`=kOiFcl}qij&m>n<K:=iԜ} } k>Bĸ}2ORXdّc0j#s]Bj]Jչ<_خjOh˦@n* Cej_"qk:z0?:S:2v|1IBX7˟4Zw TV!NG=MH<1O)Z-kY#}.П_(O_ t1lW)FWuѩ]Mqt}6[iJHT0̨88ޡ۠QH((g[G k)p(M vS.3_F )P;L}{R4d*jo{)Xw 6 1gSFI2G%՝=_KQb8agR$R%sՔu*=:iXkPsJCL$lux9*͆ ~4eLl=r@* 65G*ƓqL92ac pYW ?U cc## "Vkי&efdM'@dt, 2'̲ͷzoʤ O%QjKlKC+ y N.ѬtڡGLr0G^y]&ԇ{hTn%s##t_c,B\CfIxYr {Gsמu7bIDQf=> v#L-䳘ݹHt9'Okᣔ:ץ8!^Q-8۲<#"v݆\ooO6;v7.zgN )[ E5+m8ϱ)dHGN9qԞLxUXyjTm:Qk=72їyg#GjvhQNv?+UWs=x̞2EL 3׷Lss>ppkc9F)}$fw$p 0M?T#|2q >iY2NFc>A| ?Z A8P靆5\pFGXv-dLeܫ9=y]}5?ב˯cYO0?0v[æ||2浈[ rG⣑>>iIO> _|WhS˨a>Q)b6 Ͽg_h_Qk鰳 9!#2'SGw198'wHڤ(@O^H>Q[ңyvp}ߊ-]zd g+G怨:az_&f "| l;㎹DJȖc>oŅTH T{y=j3v$] {OC'W{MjD (/?|i닯L^$2yNI7 F$cG=;p=*LJp@&$q=GJr3j~V+3$GЕGԑ:H售 '9SJӋORYG=A9>r{ۆT4EXQd2E*QvguۀjV-'%TX}j\:ǃw`95% xva@֭@%gbL?ݳ Q@ _ϏJTWp(裀i7w Z,F>""0vL#-a'|L\?5I%SrIdo'Qu[d_Ʀ!c4<;PnLS2+7$|ӮO\)sBȇ'{^ݩFyQ4e}9Ec DaC׵(|*<LFF=4v%ȮC**=3ǷӅ#v55X\g8SBRLWaEP ((("N?5+[w:Ԯ )<:jY$}}iڐ$4Mg(,^8 8vyDu꤀Oj!AbW6\s\mPw+pig\T̂6ܧ`=}3CH2:RjD߄p8~u`2OpON}*q+Hj6VU(H#@Lcr'[!֨X1&-8HT++ݾ3Kc&pg5IaT-Z2ɷ+[{|қ$}{8:g9@TǧힾZXbC=*sCԵcXMm]lbFXO }x$cLȅHyszc<6UC1$^u8VpgA䞙],Nˑ03_~^ 7fAl?qw ka%GGb3OGTb]J@HBofF}Qi&b0 _g9^= 3B" '# s9ye m`wN}8":a+:=Gl֡,k`1P?|JϷ(_r܎Y/~JW Oナ\}}{^):ryǯl4Գ sb9ǿ^~p0|1z+B@g,hzO?Eb#K+UQ9ORA8;IV#cw<8sKR Nz1<JQ'cќ@$'<8=3I X|91Zd8q G#˂aLP&!;\oO9[y "a|:u2nik*9d|}dY$¤kA9=x&!Xa_QV+i`f$N݉skYex1cOpU;#%qVKc;u vKrlRM `1b9ܺiHV0|@3?n~*^q?3#i'Ӷs3vMF(F$>c %=dJ+Dv xIۡ r11Q۠<w)8_M}q&Nі%};%qBh`J8ގ1#>`rcqlipt \Hcr3ӎ\ւ؊Ȣn",3u~?tFv֖І|*`F[; qMH5@):{x8_SAҦdLN6#8qqXVi*L O,cy3䚱oIo̱QrO$ߑVX[G}Qp)̛P Eb"%Fn}1OK\g̐=GL}iOb4]0OZxFb033GR*ju;HOc튐FcpԔQas1Bih!EPEPEPEPEPEPEP-;DCjWS\uѩ]Mi[k.Է ]eeEfiAⷎ+ɈI$|;In8F1ҫXxtZKjim,w}Ǘ+ul+<gw^dIYUC`2+:[4Q@r%:?,S+@MQ@Q@Q@Q@Q@Q@Q@ ֚PT>DNIRyʎ /όzIQ@):~TͰ ؎WflǷCO܎3yk@>-r]2aɉr~fRwz4k7~>jKx0V k9pp]9^ glPUIBeAx^/n#,Q&ON9>xy_ОԶ"ܭщ϶G=}HCF682xiq L2kVTCq>Գt4j6YwCxR0Y{ahfFy^xq,hѕs$aFWoyqp=jfW Yv03׾sp9[c2gV!]x#<ӁnFPRA#?^p?lbm,r|9ی2Qxx=BGYO9L:GL&v18܏ZlF:[! mQaׯ8r1HI'ґ-d1s6*m ?R9I<#˕y)#6TyjNJn z~[@̪|}8> p ĕIensSid0a226w88^Ւ(5N>Ppw ֝H>j 92; ݞ0Yʟ|w*X~ѐ$ &qNh3ӂREcB(R9P)$g'Ө+Q@(((((((((([w:Ԯo$CR(_ibҸPOS\“[ʒ*#"Dnh]%nb eG5za8_fYhͷ\U}O=$K`H?z(@ᘑg1L>NݷJ\vfETFp?@sێX#+6Fezuf, n1n>Թ [3 `PnA\Ϸcts=4T{@2~ӑ dt@ O k- 4ne@ {ԍov?[ya}ZѢ*3uٟ,, s9횜n@IKׯT'#oQбϩa:W6%c]1ץ#i0vqj%ܫvܮyP|횞,J*08(N3}}#6X`?­01{V6y}ҝ\|rz~QМ r 큁@_c*pԖ;HF=ZP,۱IE(dQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@uѩ]MrI?އFu4KĪ;h''.s=MJ!m+S"M1U;ttUݥ&x!'&9P:'aKiѧ%ΣtmjM:+OB%NZnO+um`_'l b, >_N8#A#HDcp3΀8ڵdSQnL|Az}̷0ZA# d5f2[2OH.`Hd}+ /JOvA D,56};Y\%Gvq +KI5BoX&gh.5&[Ya3^ ;;PkEs?iQ?ƏAt@5 }G?羣tW36=hKI4Q\ _:Om/{?'MEs?iQ?ƏAt@5 }G?羣tW36=hKI4Q\ _:Om/{?'MEs?iQ?ƏAt@5 }GtPYSnod=X_z(gm/{?'6=hAtG _:O羣iQ?ƀ:j+KI4 }G騮gm/{?'6=hAtG _:O羣iQ?ƀ:j+KI4 }G騮gm/{?'6=hAtG _:Ot?^I,ebAΫEh }G騮gm/{?'6=hAtG _:O羣iQ?ƀ:j+KI4 }G騮gm/{?'6=hAtG _:O羣iQ?ƀ:j+KI4 }G騮gm/{?'6=hs+I5#f\}L\V _:O羣iQ?ƀ:j+KI4 }G騮gm/{?'6=hAtG _:O羣iQ?ƀ:j+KI4 }G騮gm/{?'6=hAtG _:O羣iQ?ƀ:j+!agej3"7F5m/{?'>'ȓJkZ4f#؃Gb+Uo?6fp9OC:xV|$w_N5[$1|7h(((((((*XiLy1Fu.cg!GV!AŒO~ۻ3SjRniyRK°Gz=n=)hFU6d#n3:U=3\d1!7KYcR8Y@=k[tTZU7K2MT%ҍn;]?W}VItq 0T n_xEQEQEQEQEQEQEQER1 bijh/ x.x_+`d:l/mUfu${dj,dp]ShvU/`NNGexx-|`:GIdʣ$ žp4moJن# 1yQ`:.{m>QEQEQEQEQEBX1PYz9(((((((((C 7qPȮYC) PEQEQEQEQEQEQEQESB(rF0N9ԫ(*z84``tZ( ( ( ( ( ( ( ( k"7(lE-""v(\ QE:(((((((((!E.4Q@( endstream endobj 299 0 obj <> endobj 300 0 obj <>endobj 301 0 obj <>endobj 302 0 obj <>endobj 303 0 obj <>endobj 304 0 obj <>endobj 305 0 obj <>endobj 306 0 obj <>endobj 307 0 obj <>endobj 308 0 obj <>endobj 309 0 obj <>endobj 310 0 obj <>endobj 311 0 obj <>endobj 312 0 obj <>endobj 313 0 obj <>endobj 314 0 obj <>endobj 315 0 obj <>endobj 316 0 obj <>endobj 317 0 obj <>endobj 320 0 obj <> endobj 321 0 obj <> endobj 322 0 obj <>endobj 323 0 obj <>endobj 324 0 obj <>endobj 325 0 obj <>endobj 326 0 obj <>endobj 327 0 obj <>endobj 328 0 obj <>endobj 329 0 obj <>endobj 330 0 obj <>endobj 331 0 obj <>endobj 332 0 obj <>endobj 333 0 obj <>endobj 334 0 obj <>endobj 337 0 obj <> endobj 338 0 obj <> endobj 339 0 obj <>endobj 341 0 obj <>endobj 342 0 obj <>endobj 343 0 obj <>endobj 344 0 obj <>endobj 345 0 obj <>endobj 346 0 obj <>endobj 351 0 obj <> endobj 352 0 obj <> endobj 356 0 obj <> endobj 357 0 obj <> endobj 358 0 obj <>endobj 360 0 obj <>endobj 361 0 obj <>endobj 364 0 obj <> endobj 365 0 obj <> endobj 368 0 obj <> endobj 369 0 obj <> endobj 370 0 obj <> endobj 371 0 obj <>endobj 372 0 obj <>endobj 375 0 obj <> endobj 376 0 obj <> endobj 377 0 obj <>endobj 379 0 obj <>endobj 380 0 obj <>endobj 382 0 obj <>endobj 383 0 obj <>endobj 384 0 obj <>endobj 385 0 obj <>endobj 386 0 obj <>endobj 389 0 obj <> endobj 390 0 obj <> endobj 391 0 obj <> endobj 392 0 obj <>endobj 393 0 obj <>endobj 394 0 obj <>endobj 395 0 obj <>endobj 397 0 obj <>endobj 398 0 obj <>endobj 399 0 obj <>endobj 400 0 obj <>endobj 401 0 obj <>endobj 404 0 obj <> endobj 405 0 obj <> endobj 410 0 obj <> endobj 411 0 obj <> endobj 409 0 obj <> /SMask 408 0 R/Length 68397>>stream xƟá#(bv`V>+bGEE{튍b  *zEB97lOvݳLɤ'3OB!BJ  B!$B!Ġ%B!%%,!B)1(a !BHA K!BJ JXB!RbPB!B!B!Ġ%B!%%,!B)1(a !BHA K!BJ JXB!RbPB!B!B!Ġ%B!%%,!B)1(a !BHA K!BJ JXB!RbPB!B!B!Ġ%B!%%,!B)1(a !BHA K!BJ JXB!RbPB!B!B!Ġ%B!%%,!B)1(a !BHA K!BJ JXB!RbPB!B!B!Ġ%B!%%,!B)1(a !BHA K!BJ JXB!RbPB!B!B!Ġ%B!%%,!B)1(a !BHA K!BJ JXBa4XG_/v!~ %,!ү6À*FbWBJ&WXNBlڷO 6A0 9Kt5PSnU إ8U"!O%Ci!q 1@j5?Ma^(<F9Q!GW"%lXPB` Qa"T['NJW9% aCH ag"%,!JIՃ^uhw\vx Wkq4Y?EHA K$ Zp.ZF0rR$Kue, %,!a;`…n`7mNI1nE!<A KH37SRqp<ҵQ`E!,'-JP%҉6qDlAnWBJI;xu)7(a tgUDxY6)%,(€1T θ1SXt^N"ԐBJJ=$ >arܯ*UB,5~ʯ=$tPBHL?T4%%@OCB*#z I5a_%l%lb0VNTiʯ=$1$&~ ,TSRvN!HHb>̗T}=2T]l$ J $B1KʿmkF L(~}ؙ%lR$lc2(l x(r."PF o !9Xf'~dI[2&atΜF9 QHH%rB'<|g8L)a# ?=jذ p!T2(tjA{u:o)f]Hc>,o=Fb{HQrRT1p*7(aܸg%h5"eNL6qCbOsyUBJ ]Q!g&:%2!Jj`M:$&a)3ŅՎBJv>Т@5*C(a)ya&WsP;R5&S,OƲ0},F%PJbq0m*eV-݅VնI׿A_l {`PRV?TV= hzaf&0P =\2Qh;@n/iJXBʛQOWU<>+m~ %l-&+~Oy_)fJQd=g`IV(a(Z+q+Eʜ%ʇQZ^eh|%,!F= kh {` 豳b{|h]YӒ~Uܠ-%l̄# {X^p7=g>NJ)FbUzij{mL+LʡA K O] plLC)a )76XwۇJ>q "+|JSFPqxPE \k)s< k0`$o'&ai KH9SŹ2]v~ LMa^ʕT6:(a!>w{cWGX5RXc5qT)a )c:loJ8.f05 %޸N[SK"ֱdMž+ݺC;J\-A t?kD*e`򑰴%8u/~'=^qIXh2j-9ض9X*)JXB{g}gƾow#&(;I_G8&`+oEU`?>($b>},Tͫ9VBH.bTԘ$q<*}+hUd O69/OJ8JXBʎt|V&Qt5%l$^WyEHYSSOv쇱BxX: Bcnkܯ>\ JYλf}uI (a "@=r[-Rضng7!aW¬EթTR n ^#;q$,0!ZU~FXNT>hkTP-Tz6s0 ~~HcK3?FaBʊ.¡ۻcm'@J0WQ¾ vM2$#F!h:C[qlH/|C@ KHY2<[Z+n~/צ wv 485,-r I[$B^{!gP- %,!e<0_R a-atg W(lvr)*{vo6g9ClYq"c%PRFSy%nC :?UK¬XA!Th򑡔$28[8`(a )#\ k1k8 z>4W_᧳v w*S0+VfPJXR, "I*a'][Kr᨝1B`Xw1&ފMq \ûO=}dFtB(,a@!Thm!TTQF0R›Wa-%E KH>T E)vK]IM%>Q2U~)(};Uz$pvk D1 k`7UR$ދ$eՙ%;NsӡJxͤMAY)aI!y2췵zgZ/Bb݌zb>4Qy+t{VJy) ~c2HX5>@ܿZ|O:Z[1!pamKIX|8-#p!}i /~KA7RRl.ʮ`isz^ajWtQnxIMܖm̐oLƙҹ/m+T&M;K!%t~dLl 9RA®3-MU\ѕ}.aw>̷FRYš"a v$9bK[yX磄 y_om J؀Pp%.2@bw(a?۶!Az8 KHx80i,*v$X?is=ZΙz !4F/J4P%`Su,%,OLVaxgJxn (a )O)Xb/Z) wbk |**@ıxcWiNN/ ׳ -(8 x3ڐJ⅋qvJ?3b;q 4$ X*M2F*(&a N \T$$WW`=(RRPVtྼ M,6lHvR49=Bf,X TܑXӱ/a~S¦%"\8_z?Qwp|tTw\ˡ%9@GhK:)wcjD@Jdcp+^ j' {`Gx'ʖ6@mT)`1 !aԌo{E*`|`[$,툲u:l ь (a-zB K {NΫ(JXBJ41Zla!%lHŮ }90Oۤd@Gonu;`+=R@[XB'U B?ez9JR;oINSoXz*M"՞gH(a](!Jس5/)6^?Ø1띓퀌, MZI")GSMT:źeTIX9IeWnLS?an&,^ < "D ~ vN? {A7)a )4tէ?R¦IX[>* u(, .aK?IXz$ XqhPsI0@ OZ\`tt /)Zmocl AQ?M^3`sy4{8PH&kOi <\d]L)aS¦gֲf+m l'ׂ %,OLVoǵy~˿T,&>X#pX'&qFjgy'Uݚ~> _-wK®R0ZV-jA9ҡ)Kؽ*GH2^K9B0̷5pkCሔ;P)(ΓaE==}RQl!O  vWpHRn;Q>:]*}p^2|^ZI-a9 KH蒴v+%VR ,oY$RIsH^ v!U!q* _%%ljh{MD!%W2sAH:b!aÒ'}%,!1Lݜn @6x,p[B>Yz`T72gw1ɠMM0 +KPC¾/Q҇P’"=mO{NS cv7f|yκnxt&vH?Kow+7@Ґ #O2e>)aeC [(aIIv0:Y %,!IלdJ\2&&a t)(,%l*|uIKXEW săun`(3k(FP’t]νBx< {K8]⏿mGCJtk~bۚ"aΐ7*0[R-$ _T2)kPkC*V~-rWeƆu[88 j\ YW2_Wr}'>ztZ-r?쿍S&aghN~JX6DU*JJ.~ ׸aM͟"`0\DjVs`ǤQ͵IC kS΃,̪_G+sF0=B~)']OWiqD38hP6DQ’cKSܸSFP&%,!9K*:VE4?%pLP51T=GnW{`a)s N%aN]'!XC 9{+^Jb)aI:l {ců!sN KH$ijX.OkN HMU'd;ˆP^6זU0?%,qʞxJXBso'-wl!QTfc A=,Mb<HYi_+*V9RF%,)"I%gBG KHk#M- qi7Rm+՟z=c +[o %Ps;M rsePD%,)"I$l9%$LvJ6 fJ xER6lJRUhv - PonDns9- %l=;R-{B gp|]0TR\LHLRdb[5EˮƏՀ%K7zqhY0WK* [_&g kȧۉ}[D'aP L@š&B)G`SX2 ?="A'u!{aMtMJJ[2 LW;1T>B KK|o8R֜<,ْ>Ou`4$lLބiJXvi$)O* VPD!&j$+Cl~BHv|6w ȘLQo$W"} 84;-])<餄%l#5#%l~PDHUf ^S’?<_wC QXB]oydn66K'a-NW1jd5g=!4W']m"x (n]` uoC-w|$Waݗ#L F$ܿQXBpJZ9H>$G#` )%Vh~:R#[z0 vls?pJgGb$|IXȺ9W򉐨GI?vV}d-+!:^&wьAs)E<\L2K*e;-ڹXjRϳ>$lxFe@N?+a)3 %los膰%$i;ԇkKػܦ g Q3Uy*H=R~Viz!aJ&0|xM ` A [ 3x ( $b(=eX,,gh Bb'Iw9ܑzgf[iÖ7%e:)e@ kȷ1j_Awՠ%짚oJXLl$T z&QaޒL xr6+ tH\)%)k/c`QD.?9|%oŮ@9OA K1Ov,a-us`/&a RHQ k-۫H(a`qj{,R%9p8:̒܏FNZM KHD|&ےgK g ;M_4<1wPh %_SW%Jěfɞ#|I']9wT(,!$L79˩e0 jY%%l쫏/ |I:ڷO4M R'1 k锰DTq+eRYCo^o[`+'%cpR C$\ )?H؆2Ef1?}QRwo2IG,d8v"S>Ce;D:SiFa7[.r,.@#ԂZ ttMm4De_}P’R KCB0_(!,IE8fޒϪ@׀ O]$6e~&6 K GGFv "$m,({"a;q19\JXJXBZA]$ct602>ڗv3[W🇂HavwWRzx7 O$MbWT=ppJ_ DևtJYeA qja谎4d 0]Jڤv|VNI&*G_ucxx;K Z"Yi>2IXݐuO.WJˀE KH&̀Z5w]"aj-κ:H1z\µOG5XZdKT Ȓ?kJ=`jkd'uDd҈D KC>t_ʐ '\G:dئ9d[߰Z86$ a㕣$,84rʆ/M;YnLS%,*ZUGI.OBܮ幂sL| NMM/0̞ðV"io ljHVuQ>bM?NKBQk3gǡmOv*, F)>vR齓%o*M |QR 1Zp֐Vi~*{UASH&X/K~9sm0x:P+ӝ+uY;eru ֏6JS%|s TA [ $_$7+a_]MzSom:?۩<%cV-<||);w| GjiC\g/K,5 _IB%әJ5GBza)a Icz3|&07M(r;փOŗޱ->sVS KXǿ$A Jlv>tE} "~WذnFÞf3IQ2#20xuy; ++0smww Tt c9e.a~HYɤ³ɹ)J\+XUGCYP?œ5j"9'4IkHoɰ<){$x ()JXB"7ijTh;k%d=2eb%:_׿ɽf1 k_噳?Mn?$0.__yg;8>heJؐ kHө5GœgA$ ACҧr!C0g%ڹS3h–"pn:Fe"5bRZ(a(/^EQZ< *JؐyX[#zZb=یCo=Vj6bpL$q !%!fcM$&9,2nj5䞁ֈFL6Q6d ?&xTvNwzwVnGAkQO=MaȒ97Q#QLrȢbD9jf/a7onvӔÕZMJе$T !SD g,%O?GGX^Tnw8HNA KH6"Mltmm-{=ѠWCSa>QHOE:d ,o*#$n!S^R .=CNA贩S;Y+m+ppd eJ^w4@?j_@Ňc?$,4sJXB8QGxmGͅ|J XN=`Zx_ -YxmWWx:Ic)ac$پj ʙ*Jh LR$u%,ₜ7PW.-a8j}gՉ>fMHe1Am y2^P†n`([WJ"S 4@I<Hf%$=R85AVt=u!8KlgsMϫ<ڧ?}xf|T(aGR}4xD!a7ѼMܯUaRq7]"˭"8]ցp%˒ [0 FF.B*%ʤآyJV_㛛6<\5>}MGa=RL֔(a@ &+a/G.`x!y*etB9R[^l/ $85yI+tKۈTa)Zoⅲ3ZƖR劗ItMEQf64z;_0 ʞ+9QyԊ\ZBJbpx1K瑬mwJ'}{oSQ %(atQ [5䥄 2p)pcOv`-S2tQs-1 >ma eEG8w`/,K9$c~GK C 䥄D"JXh _kà/Fŧ@[ T ր5Yol%nKgSrO/}y7O}\Z=| v)J$)2rV2~[aP†SY IdäLkGѲO>1DX $ $ io:gsϽoV}Bs'" &CVO"P64f y 1?Q׵e⋵v`Lʼ#1l٠%$̀)*m}wi9ۅSٲ)r'6 {88&j0őtse0(aCL%l-@~I$Zmǻ 8s_uq=YR11`KX! 6&Ljp5/ꗼ%`lpVQ8 8Fǫէ_ &fk"ߔ-2 *h9O.Ub*6Q)q/Vo\_( kb{8EHITZNy,E; V^Ϛ`K_`D꧀e%b\\҇tfƞ?w`VZ0C3d- |OjkϗڑaA[iW?a珰Zm6ByiOt1ps(9 v\<;s$.%,!g%"ašZz.OA|8&2~Αh ni`vTR—0%tQL"#$o*]y8 y6)6PS>H lM O6IZw16}u$2PIP†@$~UwK/Dn /D8KtF[߃'DmOQn$it:pO~SMv;絘.J*<6N~XԓhOGH)M(~R{vtR*A";=;\hwc05%P ~#^pS쇭ˍ:"0js~'~R /fR!>鬜F:ޑ~pFI݄2x-mqH3WnD,_= ƑY2RyRBgq53c8fe>ƅ4ga%> n!a}QG$H1ˍ:W ?%WUگ3a]rCxWe]m˪M:p/!RYVm)-)JXBrDn! N3["ª1J!AWĜζQY1zsm3JȨˍOU`$ؐ U/ȈlG@D{2^x$1QbMp8XW9z^4>Rfm#7ϏSMƫ:Z]rpKўr$iT!ܥ5\ɋT|-(cy?"3g(a󥫼3ɴzQ$\= Uś"m\RY;+0,)?}!eVɟlV&g' .u֗yeʴt_zV1 [ +(Fka}ϊyN oZ~aUEeĖ{mxQO“h:4u-utCO4bnRsWs?eȱ%[O/1pX)c?S!(z 6 !>cشχ"quX RxC[g/@>sR'fgq +͡ue7UUtOKجaVK'>Śo JWTT[Jh;o! w-sɶj.6[c]oQXc~ke1YFCɦJFA)+FjW.yIgb qF[wHJXB5/'RsYqj2IjTImG36(a#;A5eGu#aU-\N$x2dY6g4F@)gwjr%)+9h]B:mi|t|':\RvMZ%Sf%v/3$lT$,$K磞ϭZ]Qa{9Tn\:ZnA/R08W1-w.J TG%T=6x\ :^& =\ \'~o O՗ŨUi$`\S vhg;1Iصb杨'mXT:'fZYc0@@Fミn.o~.r苸܊)U`ZN7~RLB\\s 6/.OVӀ6VЦqΐg49ߤp4dGŢ˽2;i_BJX B"s5 þOĪZގJ# dX!.G$^p9ZiHOi@6ߋ![YĆUVޘz$|)TSeܩ TySJ9/NWj(><ԙ22;:jLG-Xy}݄u]GK3mEֽGanz)a%- L3XҮ=q<,n_L>դoj`RSO9- 7W,S"Z~+]͝?a<f1pѰ;, / j(zum}_*oA:}eٖGŕQo* V)=OMTk{꘱|l*.+|?Ṉh#@?4^6'C=xŽK)a XMV)QZx,v.ae,=uɹԦ ^-H:c|lj)M+K[p${XpB;ʘoݰ(IK Xj4-B)*uC$l̘ꌳѣ9lm&b$13CEKX!nR94frx/>%l.1.;3ʡ|gG9xVCE7aW 7 2Sg'gSMa%sz9:w @oS$LXan'mϨX+m`RגyexmLuF 딺L΍9aB0%C*x:=EG]#%A]"qq;qñUve\f>WbWL2<zY:*;3ēTgo"o۷NWMZ5-\ _PՁa" =!QڑO.a7F,u4s>WB0uVgD Hn+J* R, k Uz-S(asXn]=B4j-)A&@lnELht2ա$aL fB $JCVxߴ'CѺBޝeQYiK`^,O7ř_c0]3x'<c*e7h[S4x/w_Q|%>tIi/DŪZd"pyeansWOa0cfI3{|Uh ү(҂X+}p s)FľZ3?R Jմz|[:|shmZ.GC9pm(!ptȵgVX7Vy&1\07m1- dv=Tںj1gh,L Փa\.sgO=TxUSXLVщ!a3˰%)2M; %l0Vsꀃ*ï2 .=@:y=jI" 7̫Q\^ aTw-&6D_6M1Mݗ/U=[8!D*|BYՇ#Kf1nM+-oXG,9zA `K(geh?G:튰B`PcO/f];~C Z౮m3cwڞDO!udK1wψg_)'jF$JLϖ=먄0'(ۿ"#$ T"馑8Btޏ406ZJؕۛ&*nbN\-&HL++ޘ{.^]J?gq-jWf}:T"'u 3n?TT8HS*2zop8p6$ow'?cP$7k1*{Ϩ|A/D%1/]*'Xi|1lXdUa%ʼzi iz7?!u'iJgڦ%Z%Vb;#VsVU a{:9)Q+F>ut nz氤lG†<2s&@\z5s[=i #1~ҋd)? 9jQ=g 򽲰-&uG2jz{- e[je[e%TVW-J&,>@aK.o4Ԕ\+ sZ{Q%,gU0)re zZ#.>ސر aƭ+ mtN1 h7CYKDOQ_,ù%_! ]q3_"Hy{{QvA,[[ yN+a!]LyKJbz``*vTp p2{%S#RI'$JMJ͕\(ê>8Y5z|us!q{o?Jm8bXB >ֽd;`6Nj}ofw> *I\sW3M)XiϊE[na ŋjuG}F.ġ+l zpZvL650UW(Y~올]S&"m3? !DsNd.wVcuRiiܼ3ִ;0.wW'x5KE2])R5)|"&bؤ:fҮe`|EKCl~8.cAX=TC K%^o蕒d6_h<g) {ѣ"|+1COw0N8ٟ]wy?KPƤKtFaM jSrYN cD,u'bWe}m_7` ?"SD(Xq >3>&in ,̧0dXZT ^q'27* k+hm޾gt +kUk֢|CI߮ʺL tB=2([W?Aw|F71m@ sÛj>~FIhRfS29lL+ʷWtwA 'Șjt J),2EžпWCR|pnpi74ILZt)H?"C @q-gr4;FtPat6>Ƥ|ULFirkWY,Z(BʈQ\TowsG?a%ě*-G~"i7QVx;tm (*v횀 T#aJic#'-/3mT FaZ¦lH-\xP.û*YmrFZ%Ōu0QDL,?g=2{ ?W7q, =c[ >x2*kn,JY$+N 0XleEPjMbc_ MN+v'dI߭C!v3_ .w?k$4G.cOH >^Ρk#8'j:t\$8PVzAܗmy[#*j>8!uX8ȕ!$'DE=#)OEcs+Y@F*`#1M]˾KT#C5.<7;v0M/wջyhV'%r/}EW9^S8=RP՜HxW{YxsBiCo'lUU~v]r+rxK3o*nKWO<]m53;RGڣ)+;d):\H-x y!$ ,V"yMrglB2\cJ4>99˿W,S4l,J{9ȥ0,7ĩ88C,ҤZ5^!,b^S[uCL{IWV^P&eq]lVfGh'a$_sE5G6߈nhXT"CW83;*!NjZBr0of|L|.[F)Faw!ri{LX_m͋Ö?7b $stn4LcV$ٻ>q$*CjfxH}ɫM4$$Dce=oqe Ŧk[ MӞdFhWMgqڃ,7 v`._'>k3D5dKm$DCH<lz\X$N#Y%=LW;}Ua`_=sC1s52A ~2ҏKx96qENf.&A?VJؓ]!s Sԣ6{VV[sH*|"ǐ0z/ XP )wP#qFG#MPd"`8Tɜ|b^.]9pKkmW, Y3 /M޻3A|hEֈqjA6 %lLfmb:y^$TՠcVjb:_V8S1X1%Z2.!+ SM4/p7hwhx]{7_nG;qd1-v@THdBz̋ŋb8c΄!cl7gȫ{*͉`gq/y#pil߫ ̒?եu{8\>P߉Ld𽌠uIy!$(-߭yc5Nw~k`ɱ\%/>O:m3O3{%F|9Ci6eyYu: 7'׸-7``$!EkgI,I_$Ɲ_ݘ9^ZT1[kh:A_uV<v:I5ZK-% oUQURs[ǖK6Kt:ڔҭr.v1Ă>KD>ի3%f|khq0 ¿eF21Gvߝr-%g<Z\"D YqCffgѻb?|A>3@wilYB[(Z,z!%pWj64a:#} lVI( H1df35 md6.{^KxeXCn߆jU{1/;)YbIp U& L$x7N-qW8#؅gyh)0ǩ4̜pBBZXgj]B-V^g`[a=Q`wYRIFR+=퀤CBJy <yl[0|0LKom^uKDx%d1G3% #d.У2|(C耎0};vLtE5cj(WNy_N,K2qN jNMJ5.keiLx08;7mTʏ/i.]uZ/>4Ev? Up&{c"iYl6~C9B J{2FƇcE0|tY} c,8ٻ(ߙٞ;%zQEvo4`ݜ$tףhxN qgݍ>:=cG\y>ﱏ/0F>"mKhOwߊ}a#{a܈_#o>q['*yoa'{)MwZNm{?{MIaB V$0f6\頫O AM~5Y=}c0mI"!jR WϫSIyNL XK'~Վ8շQUE  u}U>r8Mۥ2{ɥZuZ gmI\N .cq<ГlGN :4[Ƿ{44v|c?xt5m%b Ir` Cl) > :$[ĶW ߵmx;}7w^v̇Fmcp޺}A"#>hJYECW_-G[_5^#pLJٵny(_AsnO͌_y!f!"*$ 6 a`AW`!څ7^7A̩o%#Hbe]d~Fnh4$OW60_{hjpd&2U.|~O[+QexloTb6ʨߺ;p%hs :xT[L&gdLzCa%;H|CJG"P׹u{!?QR+i;3*&DȋHިNQdř󘦍4 ev{R'j}uE18$w% 3߻z'JUJNlQ4,Z" {ՑѲlq2bzw,P#(ص zCU2ڪLUJ'ꈲh&L&٨wY,LeҮm+mUjXHoQm&"Z%{^zjaW^[mdRUg -ſ-wiI1jx+vmgߒ4_ph{ ;&zGKmMވYUDMT<_Zc2x13|>RAT{p>(aXj ]USWvZ ,a=z)$_9vZX¶ȦK-I[NR׻EKWP1#AU#wDhaAeYJ*t:(ֽ$tZl2U bAqc u/DQ­fOTx~K{n-.㫒J+.kt^Qc bȽ;zUd-[Aj/1bWŎ06-:/61iƄ9Q.l(0^_Rt]{%喝Ez]NrSTNjY^p]XLUy 1.;bmLE !#kEBl5/J_ׂWabw9_caRmuf ] 7G34`͑ ;}3W1xwif] :7WvhS}jv{ATDIRO? ~_#5=OVWZ;FGZI"T=ohDžFQPCm-cp7RA݁> Ю |b>h2? xQE_esWk"XQr"w4%ڈ0 ZlEowOo1A姟NōSV[ꎨ &ٝABNw֝5<3"W uT&0N}P? T~5/_v=~WzU&(ae5,}Y&G;Tv*J@-Kƿ;.p7q25%o ;]\w>NnE1 I)qkFeѱ?`DaxQ?A8pUTco@|#EVZn0%EV뒴 Eko,V-*ۜP5[ڛ {SZx}`Bl|k95Ot^&L6 >W"k|RHe@`!:QzS+ hk eA[T݂Uwziw<܈QXʵ6|:Mp[ YQHB+V l p%תx}.c`BTżՍ갨N~G* cY2teђhյGǩx;0zAg%]Vʲ3Upͮuj]&YbuQ4FYI^PFWFak6l2F!T䫒D۷*A'j~mUJ+po@6Ӿb69߫NJ*#%Q]  |}{SdQPxmvŇ;B05 sPQ9EWr&vk_&*•* XDKFY3:ݢpжr ߧF`ӛ#Wۭ!G$ ɦW.ZOG?^i2}VcM u\{Umzy_MyY[T(#i( %Klpu&Uz|zj+b 5"1ig _aUV4[-G0` YBJ!V; e:^鴵EM5FٰWE5!Eo9b|*Ap݄Gv "!BHK!B EXB!d(B! CB!B!$P%B!A",!B 2a !BHK!B EXB!d(B! CB!B!$P%B!A",!B 2a !BHK!B EXB!d(B! CB!B!$P%B!A",!B 2a !BHK!B EXB!d(B! CB!B!$P%B!A",!B 2a !BHK!B EXB!d(B! CB!B!$P%B!A",!B 2a !BHK!B EXB!d(B! CB!B!$P%B!A",!B 2a !BHK!B EXB!d(B! CB!B!$P%B!A",!B 2a !BHK!B EXB!d(B! CB!B!$P%B!A",!B 2a !BHK!B EXB!d(B! CB!B!$P%B!A",!B 2a !BHK!B EXB!d(B! CB!B!$P%B!A",!B 2a !BHK!B EXB!d(B! CB!B!$P%B!A",!B 2a !BHK!B EXB!d(B! CB!B!$P%B!A",!B 2a !BHK!B EXB!d(B! CB!B!$P%B!A",!B 2a !BHK!B EXB!d(B! CB!B!$P%B!A",!B 2a !BHK!B EXB!d(B! CB9 >B(B!GJGX_K!uE؁~nw$X9RUՖBHc2,Yb6[zGN$A@i)"̚O0/{g0sY׹F׺ 11уMUܘA Qe"vP)KHKk]s]hQKEMOOWr RTTdZ[zGNݻ1e z=n7 gا.}|XAvK/t uS/ɔ3FܰC_-&}XОx"f`*n:BNC9"֭:0p=<2/|Knz>y D COgc+J-*m~@1qDnf9/ݚ]"lDwy^ !HP=TW{Q u"6>55 ghqO$EƯW9k[ mp6Q6DXKW8sR%EQ rZ`gO?۽t/BvDX :_u8+l+ d~ ǡV/ݔz! |,KKM9iav!6٭[_ǟSShiu9Ԛk^m*Am"z8# K_wҢ(5o(YYP92C.WT JVrHKO*QؒZC)Z% jd3Qn8}5H >_"]^a1Evґ'{W5;p;8sjW$/AagEBϯ[5O\ C -FGuC(šo >ʵs5vfDk&)ǰAۀ"m+jBBK/9P n7brVl￈WMȶX'RJmtnžM^N105  8%6oS-Jm( K\_qzo2ӭ3v %E^v>UZLEVQbԺB%'v 3N^HFr|= _Ĉ<{iQ!n [5zIrmdæn;sgɦ" 9u. W_oA fQ,Zi1Ė-lb 3w ۫TVWnĤ=7ĝUٖlVD+A:*Vt +̔+nWliɝV w)ѕ,Tm Av`Ape߁-2 ){xMm* ėȂ*Z\j h#XF={'xK&!Q?=6x~MCCZo7U~ tW~ 9u`}6Z9CKRAj];ja[?-ƧUm-YYkev{ aն@Oڥ3WvCC+S=IeJb1LN$6?1멅iT@u*\d- wJ]+c/뼝uR]>@dM{6>? ?J:WUY0y)zbt%&2PkK&,{ F*:tW;,S-0.P?oTjIWE[]Zq d 54?0nȥ?6+NM*Wd~7~ϋϰW_;.4o}o7 {%{qՙWoܴ4BN1Ըg_4Yy{[z E${'5{kVV;۸{+YxXsJ_lZx-.N$;nO v _~#|;ѩ>̓Rk{KsK*@d%tfkR~}:ɭz}E1WbPŰ24~1|涇XZ]Q;L~ȉtv ̝^xsniiŠ^s" o ]Ğ{:PalԶ}<=3337mtB^!ٝ{?ae'dxaibm=;Va[J[>g/2{3,eiU57QJBVhr'opgv}o%S Q-(,$j pɨ)c>]&t\Q;:2w*gb} 1ōooT (tlq*MZmK-~k}ϗ^ui~!9_$Ww̟ ( nn.۞aƆԍHɠވSUu6U˯ ̈~=N!W 㦳lk{Vdw޳@(>b-9QY1"dYյu\~KVw5&rbZl:mQ`/_ŊC!`ao+0BMB[GFqn5K6w׊ꐨ2KT^l"sg("sTVzKuxt숵kuucs^桁+C%Dİ0D7iӔ;n}T\-v = C5W?Q%[JJe)7yP ", "ú-xI$H]n8\F|x!3+1v*l޻" {gշ{r~^ٳ1{{z+n{,j<t$[!t ѥ,!uo0p(aO 4dTUg>-ISQ [9v+|wG*YN4W9Zaxみ°a0q(*˯#2~p]:кk_^ևǞ=[&65~fkW\%64 @q3 iM.IK俕'A(+_[B_V${řQö$[bgϵR]gm>wc,X,7{=P=Arʔc{˗ۤx]ǫ>xa+tfN7WhkgfTiAKnX&<+;#F!v,ynkW=o&Dk zt܅l"ul_~`s71r'tއwQ%AàhxX9xL\)]K܉Cxܘ7mx϶5s~!obY(j/ٳ9wϳ -ms/! ŗ6w_r L.̵9R=NZ]fMjj1Yg۹:$t-=oeR†d=jv=jUĚvSkn[ЩM]@Cjav?F 'r^*az)c:VҒ k>7 71q^vf FYy/Nr('º\|>gg\w~x4.QPa[^F mcd6U-y:ֽFzŸfܜÜaI[EY?E*Ǧ†xeޱw{Դ25g'v߽zON سk2gּ-ꎪE[63LBϑ{.Ƭ61 ,F7bJyM[_\:(: W']"fTE8yDS_Z߿WiBa8ݩ> s`BNӱq#'FLj^Jr5EzmhYOui_kE|"tk cBEXҺ=b_{9xMÈ%-k'E#yqGz65b^RŒѩ9Z.)3?հ!yd߼U:qR+=zmz+Q0؍nQ)sQ=NGaY^rOea\Xl-C?P Wqm.{{ ^ ȓ9XFX3g:p u}a8c޿v*KU}8 =̂91{ԟ_덙x]rdz KRK_x xo\C3Z[¼[=U5)#YvFRmʻ{lʫ ]H-W2ͫ쭫v 4W=ڡ^$5!Re,:N#H^ѨwYeW8"?F$8^^-}q .Pf!DX*ڳ{塼򕴀UUcTThE@+ UU\ތQ=>GXIl,Ɍ Վ6b2~J Xd#΋btxTBRVK~ʇ :كoFNML??Oq:'6ïWABY»r)Sv}| 1cTa]~~gDFt}4B3:$csg峏3j=M~㗡L|pGEXxl/",i.|sdKIBcX b?rMKթW8m&6N5YyR{GvUNfk49pLQ 5;V*|fS!Ɂ6ܜ>2!}P=>MGXA++~zwuSĂ{)<JHkp#h s@ZY{2Crs0; Q(’'G>~`1ɘr)T`w4 Rv\쬭r2wI-Z?ΐ~)]uڅYH߉+Y)(rk[mx*v\3ĺs{;uflӫT߽j0sh3 A#nhs[NYK/)։^W{iQݕrwcX`q|f^Wz #)_--'5믱j֮aUǏ5!BsԼ]ףv6.=뉫RsqlA$BW{xOVtry#%{Fd)>⟓_*oXyM.fBC4#݊1Csss)",c?xhٚ.Of# <ДX[#\=fǝ=&rп?ϯ?W_ŏ?KMJDދW>yv_zGF/yk<0Nj?sΞ^m|+[P&Y1k4^"#g 1oEXۯU&C|TFݘFKIڍ<t9:$m~fMyc^rvP27!?%¿;6Ҫ"eiëy z"; =´*R\j^зBC:?|?'ľ+awɽ`@|C4I㓕;?F}:vjV=\=22x|ILRxw+mNj omx֌\?B-7jbhL /\*t_vAaIk;`Ox '.z;x"V -.y?FVT=hF3;sa#eYpdi{x-hn&'3$8MUt:zWLUiz >"=O^E |jxx:ȡ~H8~(ž+ޅ瘅 ~ST4qk][g{>KZa_Ѷ-.א>0Wj[5gnYL/@onK˗kI}%۳E:3 ŐO׿P%F P`};xiҫa3wDآ"|aK1hY۔gUt2bL^XЫ( "uƆ/僼MElIWzoëN[2)a鰇Nɼ{د=lP|5Q*˄lzG]5Ul@ ^YWnqm= W0bp`%_m?bX ., yH;lf#aOSؽ}z bZvci3dm(-(’dDؚ|yב#7xelX/xju.aFs K[GIonc?G5K.nғIomJ(’Vńff_~#%{f"f8mvz^ΛO‹Fd 5e4"A5)ǣ񤯝nµ_ bbCLJu:V˓V㕯]W𹸴`j5>7M3Ud7yjy ZS9 ]Fߟcl,_ξȯ{S?txI<)kEX:h[no[ n1JIK)q:FZXj\ vd#?].Ѫ 4z@îj7A=:p*.ű0##W11OВhީ֪J%X졊bd@˯P4+: c2$P=O/jzE`8vDbbyCu>(’Fؚ|թ| dz_?LV\XɛM8c_@̱M^˖fɚ =z%sx+lM(({Xb> 5+p,rx) 20"]Y\Fݡ^hUЯDB"1" RMU9 #йŴg ".IM(’DEؼ<>&χQHLJ(0W !]{]ƵHJ_@_D3ۘNŢEs[P*lu?Lzϥi-0pP(’V`#@; c xE؂~ ǢZVD'N/:`mvrt$Qvt&#uߌڹb]x2Rۼ hrj%cqק/oS2›hIլ[ݪpK6 5+R!qB2={l.f.Ga f/>A"(áuP% Y`2ᦛñ}{]g.x)[/!IݞAD6V]>-b1jXayNyͣKZ? lZ>} #;x þkgK:'f@3b~ӥ&_R4|5z4mv"_<':ښ׺ԫ=]|*, a6_C/y NZIE{;ߎaEvkUg;;ɻA<+ˮ~QP<=]ypՊ5XTQ%G؆ĉ|"@]e Yݯu_-u,trk;d~y> ρU 1E;h#.5??5{Ē?.Xoӗ/GIiA"&N}K;in)pnuS0| O#/Uu[:v QW[Q_Wb*Q5n]B v~.˫c!|TWC$1Lt;6EأOJ~:oٽ8 jH,Y.f3]X3KZ㉰ݫ7ƯsA_CBxKyA握j]7sܪ#dǷn%m{ZR|-{9X"ĝ/%>Dic7+xxa'?޹nǼn-VFXƤITiÌ?ۖiZ%mqʮm*7LoL.$ WA^zTLK@+=(.lO|MCj绣 Lk^W$ߟ70Da]va?ba~~8jX{,e픶29(’#lU>؋/F><[> &oyl 18k<+vzh>hZ+xgQky~enZ)܏WGU"afYD"+M yQռ5Ib]n_װ)ejd$80m2CZ<}N0ҎcHv'0P=r5B<:~ظ7k}Q bjv}A|eK#åKZc+V`b>9`t+_{]77g^dй`5td>ml(at)~kj)xF65 ϯp%<_KZg!&mя o(LD-Jbk]<*㥗Wזsgf] ]ծ[]Sfp bJ8%ףp _\&(6fkzcO_隢ݼ浝 btt,k^C;"r> xHc}"ρ=W_:.04YaY5MoW,% aItTݺ:`|vN>t$_S#cJ$1P#ߜuiQל avزE D$fmnO=zEXB7 ?l ?2J<$֛j!{>}рdT;,SIX`hj| -eE}Bl >pċځ |0",im^*&'Jicq{(  (’/M]ny+W~`f{q{iSKcKhV5M޴J ?vԴѺmaː:kBRd\3=Gn輂 a5,fPZ |f)62Ad)̨Eblnϻl;W;zq|Ixܵ Zq;ۆ~&:jIB*Cp caF[|hY-5WU1 ~}L|o(zg"(_ CBQê*P[;{ZVa_nsKU}*2m'E5vfz)k XrMR+s1աBBK;0jT9n[Lz8,YhVuwx/tl g#>[KqC.lݸ)w.a:tl fml{0d.pwww^4rϻ'IKpJoz&~99=py+ P3d.rN>~ђ*>d|nĢ{z$xAu J x_F'u:*(#\BBp!nmtٟ]<˦BיX ^?9P%)1*߻{xUGQy b-?eGH(7zfyR䈎lh%Hj}`{LkCaQ gd|X1Kpu>gK0>:Vg(M#_Cɐ5MTzfT}֬@oY<|2t΁~]\N|o r^G؜38b9i>}V~Ӣroc RD@&o`肵dǧX{~VLW}Oب5^Ͷ\zUxUT qtk!Qo!5€^׮StBX+.<`9`=bJQY"C20 /[R ūz_؝[x䭻YlYWc5^VVݣKRm+?TT'2.~q/Jĭ[*+Ņ-؀- #/Vy`_.ܠ"#X\-]muk6kf,; gn.c 1Hۆ"qު`9 Gba/Km3A^E9_g+Cywx2)>ӏ5ftac_Q'y9#-L=8]-GҾ$6$Ű$11| W VS믺VVZZv+1#Jy@sAb+b3`}.+q-(8#e)>LaIJo~7/e řL(07FpMO]hiV_D)v&!BФ~4yhaDȵHt"INu(x|uY XQcLo!G{͓E9]|Q/ǡ5t, zKU 'ȗ<ź 5\ k?wc2C`9؜"]Z$DXiw/*j,g!rg>nesf >H@x ,E PP`}en͛XEDo"I/1ߔa6~$O =3(9L9#Vk9I ,Y7*Qxܞ}UJZeuW+T/aVUpvfvJYIA)Abhc T/0tL_ Tzmk`i -w3݀{EXPASod9oO#(5 " u}ꜳe*lj;Й7F+],1#D_L*aRrU{” uWaq9la㡬*T*Zso[Y^@6i:W!wusxf93Q[ ;xcIЋ~(bv)fke>ү@V OxG/d{Ɋ",yᕊ<-V [2iP(q&zr+>k"<ȼa" [>^zJ;DҞj5-y_B&@ Z>r@ȧh ]G}Ɋ"lh 1|/>wT5s{QEd62wN[g}O#j8v#X į%T`m l Y.ks~E>{ִtD]=,32hV_K1ƌ?qL vOUTX:{EX : Z310FWFTQJDz;"_h||HQ 떒k>)T웡 ߰;=\uq.BU{7d;m&$9 '8,䜹U*_vҢUgM/8Ph0_;BC1}:_Fʯ+W{f8TMWD^]Ǩl~|W5M~a#qׅZ^<"leXށcW"8UeUgdbQ/<>Du{_Z ׌U1Kaq|5c\N2@:] m(BYA"̘C٦’FgWI$|29ۿ& Q}]h7by.+r1^88=P%Hsa_6yۿ àrNESnp[]-lS'žnxRQi*1RTm yW/ϖ/7c~(2a%G 5wE@i0F'50ktAC`Iz`T*6+wAY4)\#ܫ@P%L`Q̗|WӱōBv IK(pVG6;8GX5j!tfX!3 !X Jt+W(;mEb+b||W#lfP!N{)&#|cV?9/,}B ɒtANh5jt˾E |"x~]ǎם;m>gMD ߍe@qmxaAbgG:Pp5\0t3?JX=zbMYG+@ O+4Rpip!OMxuCV mdL))Gπ)wޙ͞,or9[ uG9LHJ2h+cM^Hg(1kJbc7իŋϬ ~vV5_XHCY+EXTU֭T-9聒>f;_BI߻\jҟYT ԗO2FKDaԂ]mլ==1U= N C .T Jv$Kj6ヵ?]8o1r6fDCy斫U2\dkJwSHذJ\,ñ_9 "( )Q% ~*MJXŚ-pI77'%SY  MhR͘ZYXDhpKJP8F';X*_@Y h_|+MHVz՘u3݄:֐NP0דb;牤_<鈰񳵞DPe1 Y_Μڵu>,ϝ`2 GK2tMd,f~R%$=spDy;?[F3 u79r[~RUe񭵩0mBP[BD(V}@K+ 9ytJt BX*V (2R补ta%eeLdx |y}so.=el/!2xa_3 y`)5 x6a>jzyג~c_lCɼ aAjQ%GzI':W3O+buc"<yJꉰbUBF; C؝=yלQ|kG#_:"B.שGu oFl_{Ch`ɇ'^[l=+g Iy K(˄#+EL .kn=xW.~ߙ9{+_Y;^U<P%'+;3͟墳c3C_kD8Ԗ)5DXRl`S 1u V"Va(KvOWn:F[ņ#Kڜח>#U a @|]ג~<K{ GGH劰O 0dkY/%7x1< e͛g?ykK]tkQmVpK\O(~ V`w#pe~{|2fz6Rl)DږU-0:& G8S>0Z_^ XRv|yBj(<<"\4R6>f]d_OT_34K &#J4{W7ob>vxqygz?@leT",I>@26oF.H;z9 3Q\nrkWIEa-jlRh,fv Vcb?i?/ \&ԺlUd#O}>ɘE&"W0d(2.bfSŋؽIA9z%/|a"QԎ",I&C_#|5><:tMk:c4`Mu_naE/"U6>s+NFE%WUl`6G|a#>ޅmJ^g@ ~l)!EX}X58(-t췒%e'X~t֒%QW(b^s@v.XEG?VT`'@ M6d=#9KC&#w|jk5v<w(rD8*cMzRacDQ4h0shv/82hfw ~xQnt\vkb-J(|3{%m\Y\`SU%D^F2🦠W p,ŭ[ػ='Jo( |ʃ7 `=ߦW'$9یQ>x V.-Ce 71nmugnak)jm|AQm5h=͢:`UdE}_-/=.#K,.{BoG X'CғtaM1D 1tJvC<[&[k h 6^ ]|ŋsGuJhiWyr!^+nǗ@zGgOR\!sBm(B!%Q{LlS[ ]UiEC6ٮW v>~t(wE |XE÷F'*_è|ݧ~<: ]F5I`_a#N93CHcIyW.`6WWUzY4m0 f 4DOidJ(’b_V ]pc=L遣V "x7V¬4)uL+aUfoʮ j-/x(gB()|X]Fy?Bߕ[V>V7W]P]^IT{&FP(CՁi,I^am6:a0m{ \υs yJtGhK&G)s!ݫq3l`rtF<É45p+R}-^тY-}薑iET{OWL|ق2U+U\O<[/q.X ϳ!\wBS9[K;xQ={͊e_=²ey^~~?DיA*O,Z{@f嗻`,l6 jťHs#ɓ{EXu-mƭ!&fՖ/ }/BpU2GQW(=DX%[SK`l`k|BߡM6/[:Т#g qώa"<~,]/ض]{8z)(i`+ M(’h (ġʩK8:dj*\i.gCS 7uTfAC{ʜ-Rm>bhpqO'joNA`Cgq{!J7Ɣ*E S$Yc0"lek*!_xV,|U,"3N'p _sK׌}WG)}iT#Kz>lhxwű-w80KƦaڂ~^qc ƦhE>mTkQ6˘T*%=D؅ChD1*WB 0F'm}s"NCh"gk qOEX cV>mK#_{XqQyOuR\Ua̍?FHu?EX^r:җ-ؾQ6Naa 0-M=+ª+kPic4@ rE lyz5ow>Kvd4*ZQAg&e,~8_0NFudl,!nI |3x^~u}27/-&TL̓4XP%o;Sҹ9.ۧP.P͗Cqeke^V_S (Խ/cSf6 Gw!2B,J{'i>Neä};Dy9J9Il+,FEIx}tׯwMf=&R~Sݧ|A>x@u&dwoxdEXF93v`G>W66\,,WDB{ r_`D睯z#wgekrf_"aVމSj)!nǨM\#Gx~ {A,#a)Y59 -iBI? j[.Xa(XG xtCYVjuspꔔ_(>R~`9*@C_%zEXvդ zoWm!D cծ4(zWsA\{E:AOFGAdQ٬K_5T\%"p!(VBh̽en0!nŨRרaڷ/]3/ &$(Ga:R",yMR$(U+m #lu\aj8^ݹ׳U(y~}/KTF_!zaBU`z>,lk1~;$Ոuyt8U(L칫IeF8^ҹD3UuFbdR",y[R?Bɜ'\@cˮD;ye嬈JPGWA( |Jݴ!FXɍg?Gf0;&i,!O"=Ax Rx,kO'??0(W[qKQ%LpDXGuǛ s?]כ&ہ56ur[ |-)g_ zU7n J{v?>`BWm5zMJZp.| gk qOR+fkl~ hɁѽ7z<ܺבB.zhѢgΜ!$ೣ|MtRc@C8WX^ϙRy//P(mR"bllܭH~;}WK⬢ ?*?dv|m%čӗ_6 ,'~J )شAϟGH<} ]~㓺Stw_lM+_^i\RUt,0J1I!?>;!F!Ȉr_? ѵ$4B4҄pv %",qoZt ,FI`ˆ ]]+XK!2)lZՋtMԒ"fqIwys[}@-YjQ%nB@ekBeOkcQc[mGX!y|lgNR\᜸XNV (!>6)fnT",qk=3[`%6KPd.XiP!mO+? ABHzV8<x Y!FPwR bo9f+wa$ v6(>rvfPGBIG TZӦ[,."?J{qrf#n*'v; VAu/r\UaF?o,.B!r pQ}el`Z\ a s7 r(0֛KX??:{ -  I}hzjBq#oϛ]kl,\ JQ{[7ocb(r6I!;]m~ǒrB%Gȵq^xu)=g"ؗۡKܑ ]+ꚖFv (X.ح[Qc#(RBINAJu*wm.X&]/Ùr \ɩEXvTFuQWۡ<9xv0[++m8?`B![-`kY3{usBvj/ιn&ìn6F`EXv vA{|1wmsA,h0y/`q\YGJWEˎ0%I%)NpN.*c}H=*2ZR%a{[ w[{uv$`K]aD YQki!#+r(X+Å P[]WCF<Ʉ",q#Cch @eKb#~ɱ\BI1V kS|w Bߑ*w<7SJN\w!4ͱdew[]/I!"l&G,y*B/U$}+{Ÿh*ǰZ_}>`emuB0Fx(1&Ixo@^x!gk !c塋\YEvW?<`5g5H~ƅC&̇G\$BzבֿgЖ:[tbG6⺾^BIjۤ_7qDWCG"C fM|-I&a[|8~mi$| V%.*(,.B!rG^)']6;lAJXF<!ck&D~T7|1#^e6$.D#؈X}6}!s !KAi40PF JRA鮫2]gbNgpZVEa[ŊP#2B)`_/|<3TB!X`K9S?VZ3!3lt}Pc; KSq*fbWyN(X8^YcXLLF!=W p%kE @[olGQ]Ozo_*TD|42]ߝw'?EFBID鸤E}?lU~<!mG2xB?x} v%EwW"1?c߈[h(I!Lfv|c#%.IG.C1l$0$g6DN)[7"q5 dc"_9&n27BHhRVlڰZ_C`Πt"]\!TكHO)4>2yP(.G#j;dktAC*QMBۿw 72!m-ٚJ!$dhXrm'R֟x`|0K&a Nyu{X.B ]QGJ!$PJ2YjU0hc{RARfU@=Uh-bmd%("l=saxׄ Mn:7n?BRq5i҄8;5e=ZU\|\‹@]9ýF`g&]S,?UIA^EXҮvx\8: !W ;SՂ%jLҲeKQ \3ưx rv{,E 1c!X?OKRTঀh/|ҧؒst*DsSm#26BH*V?S5}誢%2U9T5Su>c|0EXrW[~ kBPkbB:xZ[}D!$=yTbtAP _q*f%טk|DZP= (’u,h~`mlxF.XvlP-XB!m"IPSw5gUd ƅN:דHU_6A}-KRN`2p6nBm `7"kE ]_V!$8JEqKu?ٽT0ZLVyˈKkVΛ<ʎ™٣ȫKRQvY}d5E.X(t.NECp%ʼYkL oeZjfU]s"] 4Z˃",I9RZ}'Tr`>n Q5q|7ODr6BHjfj:)Z#T6;upb̜{tRƍ5>!݂YBP7<(’r ( Lmwbr'q--AWtl+DZB!DXi.Ԯ[]E%6!JZ6Uy6j$ħ[YY˾qK.{' EXBAE6h,W5Zu++pBR׍GU }- >VVeݐ[0Mujj.^IaV]hvaBs jmYPy/4q`5vz7c0tBR׊60yn<]ԣ~)A fP+),29or7 _k]ZV\oשS"\(’w+d½lM%f֡O?J\ 1K8?.sE*E HOU([{fۏek'!4&! "#9st6hRB260հE%÷#0;v>/]aE$g-]Ƽ+XD`62+k섘89[K!$-I o٢޺M3c>u'*bB%SȒ6$LZM֨W/d!NaE$3)f5=vDtjk.X01"D|l*!4avq k5=kN j^ojiC?qaė F1C9+1K~PhN9[#|bvU+ʿB3I!$M"l-׭Vִ(dV:9r&rV9AAq@!ڵ2Pe'W(lK+(ʍ",INwgͪ %@cIk֬ڢDZ@V^aI28ա煢'ꂵ+Kխ:_qB;9J!$m9q䙭@?]rB,,.GǨ? ZTj,0v-!>=vma"(’x` 7bMgO{PEXVv/n4 !x!)1=-L\yK!$ 8sfܤpmYKnQf3 /PR~=Z;{6D 6(r ;ߪGku+/e'B)Zm3"r\+oY+[S !瀂sg e?-vEء]:ShL'  `s u뗿`ސo$fzd"(’71HZgM<) 4B҂X Z`|)1"@E ^vou9wNlἉ_O@hhm<+rf26"(’7LQJb0$kUrߜOBR.Xic; ̙__EDz%+:y%z0` ׆`o?6EXyQ%m=PiVmЊgw؍6@*`%9[K!$ՒaygViWi؎2z目C#<^=a`JUnw'g e2]+Vd%c~EXQ%8VyUS[-Μ 7Zykϋ|qzTB!VU6?#=tܒ0~8-y~]Y8op7 ` ׄR]6EXP%)`R!-r\Obn҇Cq斜% \ղa_7G&}ԓW@X:OD~`ljK)A08U ۰$EVZ=z4 8Ե.Tlv s[yZ-ek'!)nu=gMˮԨq>QG{?&9*k2^\/MUPڔ":v՝K^s_1 `WP\K۩,!7x` { DNaɋdƞQY A)W=g|^B!7Tgvֱ|A!>MB::cӃr*_@x MP%/28M],BX2&oѽ.ٱ4!B0]1IzuecbzL9$Შ Qs(Τ?7'/AHL!v&]-|@kBy&5x2WvؠIΕ_Ccكs@ĥ)ˤKg'&2Mrhe ?Bܓm*,/w>ęG0}yr zMO._a*Օ@wJѽ=j?D5 m _a>h[D<[05`veebEh:3D!k p]c; 6ƗJ?8xtK³-rDgz8Jh",y,ͧt69_+=/ۏ\-%Vw/QT3AH TAT[/j>|*_-bVj*jA|+KA!!<9;wٝlIo8{ffM3=s {O#Gr =x86Fߌ[o땣'ab ԌQs.u}`˯Z{f܅ [_zɸqԎ<m_1RYcf_tٻ >㵢]~؅2O Ӏuxz6o˞?B&f1Avܞ1]2޵O@Kҵ5u֥ߪ w9pY? <, ޜ;yG=5̹#WT4=[lW+*G)hAv핸1zizE;W>N[夤ojfmi]sӫzEVp1#QOqp\xu鬅Fl@go`hKkph b2OßP؄D/ⰿV&Ӭ8+#,  |ɧ]ur[fх 晾`@  xDDK -r /蠢lk@u~}=t5Sur6FXQ5 y)XW")#}7\xDDdkVqA 3~9 Pj<`>.*gec/:IN1+(w?_2zMD\χ%t7d<>pTMկ AU5%rh6ZKN8kM׿k~ #C^{Է0w  p#1caWCz.#bⲎ[xDDϜzsG1O?z&=UlÀis Okr2n%9*17 u_%3azD.Թ+?yd(Im﷔ mQ&KE!ɇn5^a5zO fxxn놑st|vgatuтn:~mÓ֬Y C#%"}Ðfg(j.D(ЖYub[r\3ϝmUT ?@LaFT^~/=|z"Yؚ`-y(ocOxDDKm&ړ;̀S 5Ilzrެg5֋uc`K/g{һ_,g /:BA ~kʘݺ*Wn_CPޕNp%0߾⠊M~#B XB d;+Ԭ̽ޛ~#p6W_>Sh\I|dk-""rrםoǔo\uoN3հ%׮&6c۹G;l[6`0^Hǥ>Oy _ ﶗ& ( =^""[C|ۄ|m?8+?Xlʈͮ3|_N!A m#8=b` ]G_@h +CeD&~jyDD7j/* t&szkW d|4mET .G"ڷajZI3畭jlR ;e!\צ㾫b,!)(o"7F>03+~b(-RjaKeӷ y:V""nl2Y.RԐi/>s'\ZVT3*5͌\k%ZYA*yX<=SܞiKPv6[bVB;z=F~bMbJ]/ݙ;gir<9 `V]١՟L:`Aʂ;0EMfM1kj"Vl:' ? 4X}da3}"(zAVh7-a|5Q?t+`"psWicPQȁ>I#狈 %1] U&`;P c2}waM Nx($6!`\fl#lߑπc/;߿95 wpC]uQZCU UM}*֍^>e ]q A_]i A-@ڸ'CdV]CgkXw\?_Q/`#![gy?Iۻ} C#˅e1qNoDd%lOpguimEQCu&3TZZWhbf;[Zef\VQjضbY?WOMm%{DB}z #M"(y{ f lJerԅ>UQߚ&"UvaHƱC>=jㆮ:4kdYZC PīnaC6ۺ`Q-6U5x>U=hFn.Q/FFX<`7;[^Qu]QT($~!& 4{hN bN7Z]Du7[6 ,n8pUClU !¨ѕVY۶ b0Df |&qg͈ ax1trm䭗dB#hpyOkxK[x;{5뜥Pc_2>/LD?ˑ OwAl⢾ƀs`юÖ0p}qAeE;˃G6Vn[ m62yu[/l>b>IX~>F0iِ(kQT{W?o]-O uDDZ:}nT|dEQC.ZU5`KqA芵"z;KbU5sEZBUR/*Oi6lXm ۑi^m&cP5cDP;Bը\:{Qeaݿjӳp}۰Qyzɖc߈aR]&> "}3?=dXTr0 xp_#"{ab%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""a%""""?5 % endstream endobj 408 0 obj <>/Length 44413>>stream x]g@\}m{Dʼn"F{O\(Pq/Tĉ8q * {k:6i)&/I޻s o8؁%NK808p`8-qpZ9āsi%NK808p`8-qpZ9āsi%NK808p`8-qpZ9āsi%NK808p`8-qpZ9āsi%NK808p`8-qpZ9āsi%:Z(I2m8$.8@ȹ7ӽ<BXLd,8"x_T\?5)bhvD3-/ZZV#=BҤ}!mV9hH$U+yV/>I-Z5+-@{B8F5-rnUAk2'ӲN'^Ԝ[OwXi!4ҭhFH>(EN4W-x~bll) ӲK 5ҞkbI`eeuZoFYGa%Ll^l9 2JCkr?\81o|E0ӲyӲLK;xukf]`o"iټirH6+!4S5uJ E0ӲyӲ倃kޒi'5;׌4:ZScZP-bs_Ӌ qZ Q9hٯ3"ݍM`T45 ^,/涫Ι{P7dv/c`*"NK@*էvPwZ׍6{,l Zbç~\ؒc䁟 6HY7>iLoZ} ,G$8-qbu;? k+DAreVї5:]jJ7HK2t E(WEtڠ|R-;?T$8-(ky1ÄaZyQN -'70H6pZbΔ [5"A2EC[u劷mNKL@t*Vqhءiڍ_d%&-Vo{a.LqI"%&0&*uFBKO쮡 kYzecL;.t ze;LJ}{ԭW4Zn`'fׁ~0}|ںdZJKJW>ޙQÆ_K'Naʈ%~^fefhIBNKL +!3BiZQk:ͷy٪#&._1mZE.K2-]m{|c}l+[q<w aڮ b_..XjMBZiZ*'+"adt.zS\}|\dWH K&Ӳ`_ՎbboĴg(5j&8SLGsYj?KV#8-αGdBZiA Eဇ^WtnLgNKzB &W^T# yj9{HR.I@_$oLJ P w]"};񇃐u- }emΑ boҒҡX,:rb0]L=Q>3!1.a߀q&ilB~de!ᴴע| ٘9* -lҬ"dEUiD²ٷ-!R8$ C`cD?MҘkidd2yH-]?89KhyYrNK,녹m"Ilr`O ZSQ#8-1{;NїpZb~:'NK 96s g#jFBi6yWU#S/f@G'O`׼lq Qئ2v4˅ -Ӂ̪p/[>w,֗;^SݨҾ+yv\9=1CˢgD18>C#Wq_ ؠ%1ٖPN_ wrLbr?ƾRetB y`Dȧ,M-79]"'DMZs 5GљԸA4h6HR]c pZ}(.R^14R ltTRjcP = */=tɸ`5aڣm$޸bѐJKҭKsLOft1/}ˠ`ԶmJKW y&-߷Uͷ./4''<%b1)ZN9zO= sN˿v56hI9춆oA5{7ٽxM#g_\_y [0'EG<΀GÆXTnH:zr/(6816˷ gvJDc56`$lВ<)N)ݯQ~FU"ó-ԉlv%Eh,*S:]4,!jmvhyx>e %  #&5hbj/00Ǽ#; ʍrLFݓ3ww6烼ɱߴ!2-~߼ K2:ћh>oORJ+PƵ9 1BK1סW+}  b 81Gä _RCdi)`WqiPz4FYmzΔZ>9Ev7(T`Y$ο[G1=-w9ɴV-i{" $YALܨO[TE0DKYhaay0>zs'Ya-b?Ho|\^#WYƉ*ZM`9 馩>`w>9#OFe*?ckw%;RKr@ȶ#<># {j5ؿ7:6 +,x`ZJ?=yϕ8SR(hi2aqyC!VV8UK;ζyHcu烎dN9zSv m.tʷNj l}vMC 2 !9#s9mAf$Fc yy=XI: cST D8?hH'N fW([3\fQQAZqF]Œr(Pg;`ՐwVaͫӵAs|~JmIC|ތr!MooAkt֖^O{Cl:>tsDuFe ԑn~Zn٬C|Gf$g%i=/Rl 4{/kBŪiF2\FOR>-d! | Yɂ}p?"G˱!'ffr,@ԑ6ը-&93LQu_= ʥL3߈pxLS3 2Y{]f9^OKdZr$PCؤAi"P Se U|DU4Zbw l!/ c i. ySBCKگ ! }'+ |a~C6;Lٛ _ }Dˣ0kJD*T@C/tcgaB/G˜eRw(IC@4y"2rɕw!lb(ߢKގ6y s,F(MpkZMԬ+9IrE BkZS-_\b/ FD&:z$8\غ / '$wZԵ[|i^m3Zv$`xgGjK2If@'ЬԠT:15ivۍG>#(ڻ`yvB"1[1}YoX{܁墲+-GܘpL&h(o5[wF7V{[C lԓ؁"BxNkۓ2 \o>WE﨨 l?M;G #ɢjeDخJՍ1\J+6n lA;A.'__aOc.y?s F׉xhIxBJ ;FJy?xɢehJ1Ql+41 Zk[]ɀx1-gK[3ɮmn ΦE rP ;hѡODWze{uK#Yh\_@_Ɛί pZ\k]a˗P9OqgZo@&p8c?#7hyc4mݸT q296=L$G|N]ٕ$ wqfqmݨQ%)#Db@V"%GD5Yh5U\3BKقXW1>}yERX ü%=9.:(ԭ3+C.]AQ[,BXS~CԒD KZr1a% aKhI+j(U.مG!Svq~~ "WoJD>f&[gE] UpF{&LѲSLnAOmWP'#Ch97Uk˶ "-xΩ%zB=_!u#֠ =lGEc؞JGJF%ԕib{hzv'S];eJ['Zs4jlD8-9 }ypIR oߘD2/}'UybES~B:uMF!1RCԥE3j`vz'v`,gPۅƕ$ZUXD̋k*Ew1dvW#LFhƝBO֪Rk"A!mSgb$Ѳu2 Vu~Bciv/ܴ~BhnUؖ%n &VI+ꠡBY[~=pܣ+Qۑ$ZN9o0el_-|cMI?1G:cL-Gʊ]~ KL ,H4C$ZL[k"x7h!hG []>,[MFPhr(3*e!.v8zH Zs4 oXG!Q ~k !$pZ+5>2!dWvK0DKقwF!}/1¿Ӓ3OX3Jaح#T%4h4s/ٰ,b0/:HhVw GtuԪ"-" %;UgLFk׸(?H5e$S/pJrQ0E}j  Ӓa]'݅'ώOzE]DheIBXDM5[t7Ӓqmyel~Z_ AiHh97<3gbGys#,?KK',,/fc[걇Od~Z[7h?Yhytz gYZBU4f5D;,̲?KKdvb̽vvzoҬdɔ=F~%<4dH-ܓ늮8Jbw#zc-474,9g;[ 5G>@`fwYɡtItx'v%PG6;0eɡmٕ$9sx!zk-KRzчWh WFLo۵J{" g޾`7ekC_ZI I5OÅ(Rl%2d'fJE[zvuJ>LGm©6fY4~ ɡ3+dӓ41tà*bQ zk-Z a׬T\LnqC[W$|̡Tz!o=PZfD\ ^)X20oy_%8c)i"k椼b>[3;,1nJwObh)Wwb.Ib$~48*Pe>򟣥NF_bEvE<]"}b|!gnIXTѤ&>Cn\J -&" K"ݸ&h>"埣L~r/ Mn?b;%u4I &T޵0Ksjmjqh,I -G^Gs.a&ZRˆ)ukꟌn&ឃ&[QlF}̽Mgr(۲Ih,I -7qBoZLbAr3BwhyMT s(m(J?`1+88ؑ3qԽc,Bbhy/ {9HX0~ڥb[DӢ*wgpIڈqp| ċUSG&/MPQuSR!!ө/2:Ĭ2 *i -%05*ZvK݆e_{Xk](Ξ߉e1hiPX⤥Ρ,p6x7熘;{KǟhIY^}Hsב|ƩT -']̤oU6zH.SU)TqAFz&ޖpK&·Nձ,- q ๮u0o]`hbGK|3FHx!. Z84O8;/((Vz%, Ă(NwVa.<`J#M4[2-@dk؞EosU3AG5[N;lhY.|`sAڤ E>- "g ukRYܺʠE ]3T e=zrk05Wgpt:=2TMv2-)KEz@ںtb zQ@rn/Ɔ1NQ|8{:zĿ@KZ$}8|/;]fy/ṡXOL%jQ7XU.\JL[(dc~- @*=?_=/ŧeHe.W0x>yAxfMOx9zx$Zj^w  'oG <۱FhKE{b=kC!BûM 'h 䉅h ]>vZw,hIH&p6e$e\،->?%C6h٦ H).;dܴ gQ4,f}UpaǓmjtCms=܁r(_oR쿽t EV'T4̐+|Tv1pВ0crϩfI>wuDї-ˏ͇Ggo\C3;;odE*&d Wa\)0=<6HPm5T6zn#5^&hU{ ke,C\v[y"!Ai*Mqy/ 'Q0Aˉs钘̶m^ShaϏYXA'&;)U l $.Cl'wR놔Z5~j{Q>6)op=#vl@hyCysdZ)~΃sp4@ r Y H$ClnЮlrm:ݑOto.JujWG~y~rjOifXM+2-QՔ rٰ'eF!EAܚN.%**{^rUL/|˜iтT̡7\$VBhܟuM 2EbXAVG'҉e h9k= v X^TfYkvۈտP'gml̪$Y¾"QwyOP,~|ҥla,c=>X𙭄h-E@5ǰ lS%a<-]BewQ@AztC]7on>?6l"ޚn"g⦃Z?#ZGlZ&\-@ˆxp޺0^7Z|j&@˝ E?wfT9?emʬ>^LWF/[F y$)^U~}{Ujx ka/#% w@BUV NVz]8-@~gZ zX%IwvJjpRKP`S8|2Joκ.LPL+=iAK =|$̈43ATzK$Z>B]\hIslz䑙r?`1pF_Ԅ0Ϙ NO]K/|BL$ \@2h/;$+><>_%cILYSj(^:?vJ~بY9P{fkQupGy+#ʜ勐!\pPVXb\ Z/\}T Lo8gjMŠ:%FQLQ]0C3xVV̪*Z2-S8֋Bz .q4$?PBzy榇M*#ab fxu=$m2ڈX'DM󿌛ݸ #%ʸ%Ӳ׎u╖@Q[ ui>yvl 4*VcOƹ0aQZWoyX[y1ޣNvh-^KUJhT* ~ Iݵ Ahѫ z=mF3(3oݢ+#ܻDߓ쾼8Z0-{g1MW%-fg]{m_[634t gCn3 ߘސګ13VMhk}C(7a}ܪsC ԇM#S20~1p|D~UںC fꦃd%s g4 elT)-R: -CWR rVس_"  } d exjyW5y $@7ߵ@'h4>${[DCa}[@y]5\5ۄ~ T`gG,]OQG|`GKԾ(Z0-/gH7?9XP(riWoj bӒZ&f!Tiy;G r(>,QZAwaz̭n8RN(s[0-i Ynjr΢r^g)I\-m`g }ZWۓM|ݟix e]˧%1s/=yQ׺ĊN סGÔ/--k'- N4#VĿ˝kyvdRjf~iu_tJ_ӆ;wQș"]%{Ā݌hdI*;4Iyi+/}ZVFҋxgjA| X( Kz -1NVh%zekdn)c~NCڂ֞,-a^A*0NKZs[?nfS*Jɯ kct-z'қ9fSd]8]QhOW. ]~'ǻi9먙@:mmo@|M(WW3eC% G9*6_&ƹkv. Vm6K_Kcڂ]ru'yDh߆^LLI?bCG~α4XH [ٖ#|oB~'jхexP̮$jbnfo='^I[sG߸ R]0븀tTZvcWmIdfϮv?/zGX)Zʯf9 ӌưAwa\mZRtC-*Pvy 'Q-+ IM/^M98;9iN m3'-7B2t-ywƟ̡q3L)7.Nr^U[/dQ"|olV_OMFt$9ظNE.e]KYKKY2A힪.?qTo#p7 ~{$E- o[eg!P-X]Vpe횙[k e:8:6FZϪz"6hYmkk.ܫ)?/70k&Y)2܎:k 76Y*VuSӳ[G %;"{XO>>qW[n ~,>@e eHN@+"qW?VsT|[޽yi~o z$W(W# 5lrG'hU]trf&ƼKfr,؆82;V~ځ@iFu 2-Yׁdk,P pߤ%mmNa>Lphz:xX B;Y.!ق聰] U.( 2d5"PSby`Mr].P@g7^jI=n馲h`.'e!SPV!@j N4{@ZtprN@h *n#/R-ba\ׇ2&^ yO&"u LzT &OD>5>2--EQcA;@$9W]GsW5aSs?攙aӖgeQ*X)6pOy3eST%4˜TvcRQ)HQ\ zM_n vk^5|ar;1 _1tj]HVڷM]58j&>·Q<#t^\bmˋ@c!gه&xVUZ~Bݨ%x)[[c!~5 T0U$j)Z(K-2&j0-5OBѝ/ofu6`18l*M+xxe3zs,q? ^h,X|,eˌ]/ZkYEwD`N"V^g\oAôv"Msl.0/,G ZD?:򛙈hՈuB_o9mc6&ceM}j(2iUGS* QR/@߱H_r(_tz]⚆dpm1ǸRtײ'VOô<3]Luڌ}O\]dT><%g4Ųt хǂA`Oץ %E=u]Csvp<(cU.KhTf<[d,8*!Y*'YUe%s PbحV{ûaَ2rz4h3=0-3u@C9 Wi1B? {v#okWdop! YPmLAѹ= Do oGjEFY|w&j!RmE䭡9vi_,3Ovʷ?2l$uS3~+t[Y\$kFV.BFLXb^ HZұ׀9v4$OM*`B˧gUmo].qvW6l`;y/7ܶ7`l;s:GP';~8'i ~̐|s?.!sK>wUhZyhS2 [e#<Cr-6cSt7!^3j9z]Zr~V=zJ8qY%A{nd '\(/{T{*]-fєW ܗ717tMC(̖h4DhM1qpYRZexח.-*A^O+*se|O_/"Gv?󟠖%% dukatD X PcQA=}׭dEӒ0<;52*Vf4aIHiHEQ^} K}*<~%&m5mZΟM \擶1RM{<>NMB_46/h1"i#L N\CtFSh!6)c9?Tp[To)Ҳ{KhA[ws93zmW]"4 ܿ|܊/r஻{-oYIĉF(7O}K -牆v l!}kCٔ3G,-/ᦿG<~&u]験pʭ,!i`{V1ȫU Z&-uZ&Ww]黤 'kօM^kmyf$Qn }`6.6잧EaT'HW᙭./{XKE*rȨtsH+Gę}: HO\$VbQ8 7< ,ǿWKeMW{dml8=q>uHq~1wQ.ħyŅT`GQ,a=zl[6 *-OD:Ll83f́ߺ,3Nr *[~2kg5wb&yNB B fA Y%V: [p5rMVi nxw 5^Oq 5Ϥ R8^,P QO.ydu`>5 R9g|1n()&S$AU:(RpEZ -DC9zytO&qM7 ,Q=EcML (@*.GPIe,(VR(-;z[^ECg ##~;J`hk?*O;ėإ|y{T9;Z - f^Rc3!%%rH\c=M/Q6ET 9/CcXH-P%Vp.\ˣ6E7C/G$ޟ =^ &M 0?S % )*TIaC(IR$e/ PO#xZG$ӊeƟ֨*g.)[0XLHeĹ4oMJ+cqvl܊!\ZV/>OONWKxn -z^FM3u8TspS-k" $qIK?RnC8Sm.*Ze8q<~VVQĉ^Oand`7{1=_nJϽf$|" Jtg\k -{F{SɨJ63N_`݈ (W,;HqV("yeͻGˣX2_0f:@ kF.ECi:@Ȧ<0EWĮ3!]&iuKh?5X:8_[Ker`볌C ]H'A! FYs*8ZʖG!w\.2p^Ui&]2eƝۑ->@ze3oH_\@(沨*_V;]*XrQ,-=_CSI/k Z}$JG~UtzoO'irtN%4GKRt5zC><_`C xnhJGJ7cZݭ *3`;r+\K(K]O<8G{imG죤E?F/>l]T&QN:FhJ668,j'G@6/78ZtaD.O5`[-dqIZ#"U\m!,@hL#UXHӓ?\uKMZa0%ee<Ԉ{|u왊+pg1hQ@qQ5Ҳͮ +n_7j8﹘H ޼z? iqz^"/xnds^Ova}7{w%ZO?)[!SrJR'9{U XEY#&u4'Kq`!]S.NcD?u7uHY}aj;MKVAa3OOE˦\~wmc}nC377߾7w3ww殌m$mڄݎm4/%yiW ]!,{R4I/W\YbR6qP oP k<Œ-ٹW}KII iݩ>/NB* G&,E0zaqyjn+Gjh{!ݕ`Zi방;+- X 2BYӔ>[yLV3K+nn<,%T攖v>?]|C$9V :{/MRMᓗJG,*qt뻰MϛԊoڰ4zxqLNj+FE"5k`įLv@<\3$So;C{J[5v7>u~r.TٗKZbWk+V}~_C>a1LDvK3?aLCon?7wO"#8CԟjΫ[@a<^XL%AÆe#"ZѓY† a]JDڲBQOqxB1O#}7jT)\ҲI)7a˩fƎ+XDNO`_IݵeNO0rD{'IǞږs?%)4sTix^]crR[sͰe OMovBOgq߱7r{{>Ԁ*I8mxK˅3%#V玴JuSrljg%t&9v im.KЂ qVۚ__;(Mjf4,-?M*h-6W޶b;st2V\`k[#*ܲ(}grawAΫzD!- Umc~P}u}:;Eu[!ML_16j0[^M:Qlv+C}VU7n9N[МR)/tp=Y:]6{ѕK4n\ܗ8JULXe௿g/.zWB)lS"DzB0p] l_g2~khXAkeyZʙ%R^7XroZ FL}.CFZæe&zvtCw=}qmo/RTiJˣ7^W(-BduZ%XǝQکj7xϋzœ]7]{Gшϼ)m Ub9 oN&?$(heխm) XyF {h-%B:4.nNҡQы^!*N+W?3ϴBl&oEOv39*;櫞ɇ ^6tӉJ5rN4(<{]wϟ>$̀P'yJa&ȏs~`-RLrk>WԢ˳M]mmoye&06qp-^A ZLޘ,3Yɮ= T^ٔ}SWS23mPxUo_KxFWK56zQ6v 2D)R~0(N[aw*Ԕ{V(6CYfňf HrOC=l^$Jl5 j&!u^'G$4yI)!&UL*0A_X['  v쩦՚j}zo"_. G7Q?hf\ jvu٠;w2Eђw;vߪ4Cey>85UVi'ۙET;zy}00z9w!M)u%dgW̉yX/ny.Dܪ?K);72A?%+YiP@ףQChDWx-2 p0iojl ˚+ 3D3DQ$-=59gLDT M;FŻ7G(.rNa_~,1MCNپIᣰ^|IHKi5ȻP*e-&3WBoZZ+*' 7}J6!8ؘV=ߪ24B-]B]Ư^b449ިE.bִ=u8xPjrw.ZCyi?X=f&G~XD.nu%sL滯ǯrI$'EDGB*e%F8d>Η~FA"&'UJ nr y $(roɫeDZ? د7EdapWJCH7Jv1. !=p,sQ<$qwLPu[,3N6xҏDD8_&K#J\\`,Iҽd/53 k"*2d:Jd<'B7G\ևI?j -BhY.ǠmfT *Ԏ'M NPsmɏJWX@14W(-K[>n/Dsz+_0y܈Z:-AWT-K^-˅v3XBŔ%ۜdi[G&/J[RFi*?Wj)su:[\>9[hT%o33dmo0~_kQT>sv;濖 ;j&sX)M7/6;]ؕZ`3SE?lH)WJEs1vShI2?@K-iZh=%M̿-ZjZq`<7ȹԁRikZ:2ORx;=x*iGQkqX.͇Ws|qkCIQnO4U&b$aIU\s.o8C*8h Z-s9@K%pm4M# 鵷]{yŸ(!g`C!rVC66E6LGY79/) e~cc^,22i: yÌ/3v;8L{o&"LD?H$}[+%GP=lnGh$/ =Q0[8mſXz"@iˊSKMv}Y0 x.5s.6S. >hLnfҥbg|z%p rR&yũ`)uKO/h8/2at"?W4rIxxA%9o=mכ\c4ilרZ;SP{0?*u;Tת ^6d rs>T9r [S hqC2sJk~e鯂 sCucf6/K)q%ZҸy:9vi}nOK%_?:3ŵYFh_g: W:M,[#aI[}nMlomqJSE{"{_ׯ/q‡%U:Z=b<'a붌j]\:1}xH8 ;bקrՇoF]f"tl n+Ts5]Uۧ C3}Q |¢[ZAƿ+?!?qp4^ۍ<*}cc\^,܆f7x7-Tj1x'Z}/=XXyxh>Y]dk&f"LkXUbP+~ EM~HCl8"2qNZA|h^8HJt?5m 5[Pi1GQt*ЦZ5rK)B(^12*J~`Tr%M28''r_," ^bs"KH}9{5\RǗba{p>Q,"u[N\rYZɔ iu?bHEnϼveBGݽ|/c툃iB-]bIo ZlSKwF}@ْi88Puz;7T=qʘo3LCR[- /nVbfҔ,9Y"e-g+6gY4fKu;+ө.wtvduQTzEwCsK` :{0ӽQc,JE%o]+ݯp^γmnm[BrsnԵ cUoK,N^6a_GJ0bǞ/Ώ 刮[{FRYRڽ^owxv*6w*_7 Q ~l)Q+}{K=wwrj`;^N,^xe22{'?wcS"ZZo9|/`Zv^{mhT3f̻ޔrȥ.,6SK=GJ;KKq/gjY-_nZF5ߺ"kTgYƹQ*ǾLVu2R(XCo}Z"(/\\l]bŪ]|tmt0m@ĈNӪNҜXC'S\ BmAԱ#jc:ZDB3nVK'=+rмvW?bmj&,[j wωڼtR-m^iȹ"+KjYƘ5oEIH=(m|^_wib>QíG8Qiha&_N".,9xiujDQђ8q@/zV/4ۄԥ:L+O\ BR-"?q^cQ +rvBl~v'KG[;U9u΄UKt-1KH$;o]+kzJ=دzFy@+L)t؎y'?- sFPo:?6;EdGKv nYz"8/ΟIz7v` p̓&!>ZhʾBoe%V"F9UQS)bpdT 4_/݀6!QklNC15C|cmZTO-"qWo#(&\+S6uV:S 3lB|Z(z( Zp/usT͈gN->jeP{@vgxx{Sרe:8u{d؝͎F-u(v LFEǃ[nMcsee@ Zn28%g2'Vy*19o[A%}ڏOT+xRnQ>*w)QA_J1pxTQ8&SV=<ՇP 4"cȚo-J"a$ -Y4zrAD(V|09zJL:9\xN^^/sC*O?MTڸ nRtr<`hBF##F =2B]Z-s9@K%p8h Zg$!} $%P`x׀ָQ(0 rŏr:k! FQ(fIq8ɮ{D =`ZDp os0}6Bk>wt=Oh9t-O@[Nvk~ot\)Yu{ V*{srBp/Phy2T_ P7#d a^]XP!C΄)ZV<<{N6lB -fG:=={J}ÂJm#hDaxeX~369DK4~j :ov>tN!roc:ڤCIy8а,Z:MD C֜iPˣ6ύvftJ!0̣,%^?K3vnt h ΈO*}y3[@K%p8h Z-s9@K%p8h Z-s9@K%p8h Z-s9hhwuoI"Mc0X/@PWAsknɨ}u\FJx&s[xPzG񋨅py4:lUk݃x d{<0ndv]$R=l^oudG9ͺqxRrzژv#܅1ǚ0 e-GN>A=Ф ;$^ˆוj9EKdCݬLd'f4rPn"ϸ[omb:DžZNhrj/(k(-91Tːm*mZP#'mشˮ9ob'A;K"8hlW5z6QnsOe>υZ}(R!H-.G~Gz/HV%\tԑe`bKړ*eBAA7ҍeYZ+#:9,Nhjw gʝBZ/+iYE)TK(G X 99bĵE7=QckM"~eOš%*ZFɟ7ާԲ#@l|7T RpWx3 =zMWSJN.$H7ʢDZutB -ktҸ\.}@ug}jasFhs'-ڍtvz[¡^GLbYӊvD_9be[~/bƔЍt -+6@1_הg {J^rbX_E x}Z :3RfE{VkU`r}k]gAh/gs9@K%p8h Z-sӲc 4[ un(g,f"drW gMzMA;x!"Bt׬32Y%`PKD- )%- )%- )%6$2y uS&hp fbcZ2 --AMXp4yb@j ,;ap, Wth V:P^ץ8Lk~n"Tqu9埚Mcd0-6z|BW~X14@K4@K4@K4i9 չբw-Kkz\C*Z0yty7Yw->5=WK߿TZr-u ߡBlQ޲Q'1"%L˛@K.4QQ'UL坧I2=(QgB"Q;u8s U6-i8]1K,w!g?4! ]Rx"m h|#-ȭ;7$A˂ơ8KRxvS2gC韮mTA8+>Q h8 s}>ܦ ,Xt8#lle_=Gi1?qqXκ+~mŨ ,Px2Go@KM8_ϽO@˂Qhs]闠&n%~Ri&MZ$f$|XE32RTia5leH/Y&PKY9w*Z ^$ U| ZjBZb3ҼeaPI+jBRK3Lw^sZ$L{RkɔHZZl^A~S91h R- GʈU*W-5AxdVJZ/V~+r RTj>L,`ʐZNzRTj9n3߂i[TFr }@e%3M:&r}@eA݅,,S\RVbZjhc WK'~-51rJkZ~Ol$ZCՒw\z&_sВ! Uj7̈́{Ԁ"*da X%}lOWU hR2x~c^%CN[65AKvwV@K0L-߽#Zed5ekI]ɤy;ʿ-ޫ -,؜ВHp9Ө#Yp"s_ aZc;Z Zrerk UG#hS(XB$9fѥt)vIʲMS`Вk=!aA4,A|0ާН [0һ1zZmP@Kt&INd<&-9FsVvv"T^O@R'J+kzW*r=T UU96В[ XMT]*^PR wߤv@KNqهi{T <%!EXM4Â*፛о_2ВK]&|yG^hs KvZrc'}uC70h-vqВCܷ% ˸&8Р*<{ߤyRЅe@KLk!l}@KULP6ɨuh5!뿈+K*?T3/ Ƭ3@K`rW) T Yg᯽sUGqÃʱl#sВ+='o]=/rG a.bZr1K;cQ G{ "-Y>^3"`Zr mkОZ*e&Xf$RjsH6%7(uϜ8l^Xa 4:x@Ke RSВ q$JkoP:aP肝ƚ-ka(VZrʼnVfy-c1-v*V@˼peY-3В8"&,Y2 "b{3^-9;uq35`,F:<@KyCCڣ$/4ƐLe"Gel0\\CZur|35Q,,w]NTa58"1XN5+&2Ƀv{-( }8EGiu5oc-/Қ <ɖX mt>,>%Ko' ˓-5 vAa*1,f6%̙Bo:K}yDeNʆ'?',c|8>c>v"&2' bkb3+-;Ԏ,,VÖhZ bN4d2ҍw0MTevwA(-Y ;>B>QZ*Ryhj h*}7vU㴊 TDa< -z{w}R T(A J d==M@hh?7|wbN4d"MXk}+]l0yvr6%{֒Alrj--49-[ľ`,l-#s=O\Y-e^-cd/#Zg[LT@K˯,K`1'ZFq[ n`6s!%[4>K:ѫoU̦M²#5krВ%>]V>}e6!-eAGh It{| h;Ϳ5ޓ]hi& q qDk5hҎؚad#1Fm-3a7 `1'W˿EH.W4jR w0~nFH-O2e^-͑.l$7t.HZgUlɣ&v"gTMAK̜! j01Y^-[o-our>chű V˅ ỶѲqG[ôTIG ;ӾyQ[LDW{붡QIߊεjE~eѥ`LBUd/?Siu̝@g+5>݀-Nޅk*qey9#-$eͺ7!n66|5ꆪ ݟkΘ-gRS$Y:^K=YXcž/5TŬi䑃M;oYX%}J<'.Hjޘ{G3WŞcgG26n19B/=%gUrwxfo3ܵ*h"dK0{7 f%Xk:fh;WŏӪiě2po}06P-aEhig\ -+-"ڍweE,7s&VO`Can !tK[5B͊dU_U?㕃 !c}g,YU%?*qkn-)+X$Z=avb3'ZZ2OSK0 ,hC6+Z2e-WL\1B^XdZ)%z->ɖwԬy@K桪F*ZΞ*/,of7CUhF-ZZTk3W5@K-Yiya?ͬh h<%+(6%Ō0h<%Թ*T\͊Вy@K68V^͜0h<% x$oJ͇.Z2h 0)^Sp{teZ2he3'Z2hwܟɴLtP8Z2hw͟fNdR߸s-'bNdRotdRܫ,ײM6s%zpPVX~a3':d e, !Ԇ~K-̉-|GX\+Z`X~e5ͬВlv̲K`h{4^ld3'd 2IЃDo{Z2AYkQK#ʀ3l {벏͜В/Ͳm`2]יZ0Rc|vW-g1#:Ԟ3"LF; RSxs'Ȗ6$@KmY8˭M?#>ށь"-+]Y^6)rZjFY8l,Ll+Ch[5D>][lfEGZs:BgFo7x-gZjIY;A7Hj{Q)4Zj*+,%%߳]ZjAu+Ǒ%)hgr_fEWcu\{z, ),Z]XVXfVth)~:f[y*,3 --gg9}6YR>Ɩ!]CPVrTH4 R#إlD4>]UeAX2pu5ƿSլВնݓQ'|b-_Phi9k }d3+>|!t#@oV[R0+{l hI#=f/ eU`#fy"7ײ沪Jx V[@KUDvTtff?cJeZL.߃׻fVt hI aGGaAKje]Ub^޲0x-.,.g$y-`TekW^.%1?${l^ǯ+e5e?A]ZQ* d'Bea[9q6p-M&N k̗ɤL?3=?:{|ǔH򦈁kkfE6lS'TbTm?ư,l/D-٫ӊѺbٟ$ĝfӄa ^}ZZB9}9$u^˪f\ZvY^rcZ#`3a1'TM!|egsj Cֲ*=E>-U`QorU$o}<j=쓈Kq!€=lcGc:RF[޹as­]M}^-PuRs$F^<#,z͆X2r,~"֛3wu h=+(^Q]O\]SF^Z`ZV$oG[+eJMojwDv=^0&vEKCS"v-K3z*ּiZe?1Ù9۟@4/;O~ 0즰2@l|*^k9fvkX,ړzNRx*GA$-)V^QuQd_C6lIIbZi'-*ާU_ȼt9Lض6H!e^B=R!jtlǤ׹Bءk) Ȏ0,Ή[j1@-˟r3Zr[Y#=wh$ *)Zi`xZ6o#;5&4٣j\~[J<~)گ}]٧xg'R*CcNM ߪlӦ$HxePҦ=xʳ P"[6\mMe ^t6r}5«@]rȞܿTtkE(0-^>-A}0%|-1c%su&7)ZbSSwWG;_"6S`8.IxuVdžъK~~Vቓv$8EDKSЅƦVN.EllL-AEx$-͇W))$ e.Wh]uqICYy:ƵENKX`$0101321NT~sO_?[\㛙XZ.@ϻ JGGKZvf`TZ0 `|/[f3k3SKS{S+Scccbi驿~DJm5Z^^W׳af@Go2?^, 甪tu.TOCEqA|s 6זm~W-9L;=|љa~ɫZ 嫃&s>>~AKWK7hZZr%|l^2"h_q"Q%)mb<w@N@KAZ^P,:let94D4^Z1؆ܣe j 藜mbCB78ҞpnV-u19ӨKKKw&1~O75mʥk~=Lo?mƩ]63uXT7]=I/x+fsɠ`4`E];0>$=O^960,L.fq;iM揷D0ukL*o" 2bGr>n)dΖq醉J7Ȑ5ŵQ;--cw *,^=Jϒ39O7ȅtrfliZֻܐ=0 j-Z@K6-AKlZ0--U'Sz}> 9Q;[ƍfTJ%ajaNK3m _l tpfqi@hϓvni9nA;-%p8h Z-s9@KZiTÙK>WB-y^k|#!M zFh( #3K4r*!_CǬ`?e{qen<"^jTzsV}[5fE\M֍7toLI;X#A枇3K=KI}D/(4m-¢ DA!vzz:X!C'&8ﹷrʢn1xܧurqMʤO5|>X:9cZG ~{F瓌K:eb%9;뷻~߭}O%ZаWb骳d:ds8Gu=vT?:puaH +Jt~ QUJR,B7RȕUEewwGXXbO@G4*VI~3WrOmvm78a#Ƀ0yaĶ̭ܥ3:h:c;r{h{nIR"oE^J{Fu/Qr9a*I1%yAzdۨ#س Wqm 掆D, zGÄP&sx@eEh哉"iP ."_QDZOuh-!n% ;#n)F7 }A?TTGk岭?[]>ܮ>Xx[ _bi}'OQ:?)}tEbqf.xH[ k0]g x(>}PQ )fDՐK!xì|ۣ' x'bt9)u595-í~WK0. ~axOclGdطM>5^GtB1/-@αbek=ok~lY8(T69kFqV]_Xr̅X1Wb7x %)Uu t?4# jH͸as`T둇ͼ4&̝[Jrlv^:&.LOGmEh%ofN" :Z>[!9-VgLVwrI=O._[{F :l.UVJV6E|.0efvs]Wgb-mmFF4JC /F,RO.Qe"4iSb1 \|Nz72`0OB(*9|j:鶩LPeu'2b`=u$tl3롇ZJSrwtY}Lyrtc!N!.hD7w%Tˁ.R_ z[e>t%0K=D.krc\} 4ӻ-4]C͘AX'rgKe/|bVPeVTum!D,CrR-\?ubv#f[򳮓(mB5#4{K4y]؋u&G3p-sEE]rf4j3b!,;m> uAoQho/Z1dt .V#T%V}:;#PBMNѽ%[Uz{Z -%:G'\y0T'j&#1舡N,A=Xر^9qӣKƬw~2گ(nu;w\2I&}kKd˫TTç;9zES n5W{mv=+u9dQeO{\ٿ 1}Y6^ȍ.Xb%pEOJ#9-p_L0G'8|maiW蕱j 蝶zn>CaDFgt^ͿG~,-Y9UOe r$M,1NڎƈR:P!eIb0Z08mu_l'ua.vU"{?C[=ͤX7u(嵥ivṟ@Xآ*e4M!L!uOHudYΨn.FŠ&g%h=469@K%p8h Z-s@P,Z!;/y %P`(yS΅>(ZԒ-6g6`Zb'}C8 ЄsΆ0x-EF"4q۹H Bsg;zDx+W-U y%ZdB%o0Q BMv.F6wLBKcgZ4n1ۙ=ByElg`E7d;Ph;hOߪug;PhBpg,eΆ)$ZZ=|~ Խ(z3<B!o{h$hqى HPFݳJ!rzO0A> endobj 413 0 obj <>endobj 416 0 obj <> endobj 417 0 obj <> endobj 418 0 obj <> endobj 419 0 obj <>endobj 420 0 obj <>endobj 421 0 obj <>endobj 422 0 obj <>endobj 423 0 obj <>endobj 424 0 obj <>endobj 425 0 obj <>endobj 426 0 obj <>endobj 427 0 obj <>endobj 428 0 obj <>endobj 429 0 obj <>endobj 430 0 obj <>endobj 431 0 obj <>endobj 432 0 obj <>endobj 433 0 obj <>endobj 434 0 obj <>endobj 435 0 obj <>endobj 436 0 obj <>endobj 437 0 obj <>endobj 438 0 obj <>endobj 439 0 obj <>endobj 440 0 obj <>endobj 441 0 obj <>endobj 442 0 obj <>endobj 443 0 obj <>endobj 444 0 obj <>endobj 445 0 obj <>endobj 446 0 obj <>endobj 447 0 obj <>endobj 448 0 obj <>endobj 451 0 obj <> endobj 452 0 obj <> endobj 453 0 obj <> /Subtype/Link>>endobj 454 0 obj <> /Subtype/Link>>endobj 455 0 obj <> /Subtype/Link>>endobj 456 0 obj <> /Subtype/Link>>endobj 457 0 obj <> /Subtype/Link>>endobj 458 0 obj <> /Subtype/Link>>endobj 459 0 obj <> /Subtype/Link>>endobj 460 0 obj <> /Subtype/Link>>endobj 461 0 obj <> /Subtype/Link>>endobj 462 0 obj <> /Subtype/Link>>endobj 463 0 obj <> /Subtype/Link>>endobj 464 0 obj <> /Subtype/Link>>endobj 465 0 obj <> /Subtype/Link>>endobj 472 0 obj <> endobj 473 0 obj <> endobj 474 0 obj <> /Subtype/Link>>endobj 475 0 obj <> /Subtype/Link>>endobj 476 0 obj <> /Subtype/Link>>endobj 477 0 obj <> /Subtype/Link>>endobj 478 0 obj <> /Subtype/Link>>endobj 479 0 obj <> /Subtype/Link>>endobj 480 0 obj <> /Subtype/Link>>endobj 483 0 obj <> endobj 484 0 obj <> endobj 485 0 obj <> /Subtype/Link>>endobj 486 0 obj <> /Subtype/Link>>endobj 487 0 obj <> /Subtype/Link>>endobj 488 0 obj <> /Subtype/Link>>endobj 489 0 obj <> /Subtype/Link>>endobj 490 0 obj <> /Subtype/Link>>endobj 491 0 obj <> /Subtype/Link>>endobj 492 0 obj <> /Subtype/Link>>endobj 493 0 obj <> /Subtype/Link>>endobj 494 0 obj <> /Subtype/Link>>endobj 497 0 obj <> endobj 498 0 obj <> endobj 499 0 obj <> /Subtype/Link>>endobj 500 0 obj <> /Subtype/Link>>endobj 501 0 obj <> /Subtype/Link>>endobj 504 0 obj <> endobj 505 0 obj <> endobj 274 0 obj <>endobj 271 0 obj <>endobj 470 0 obj <> endobj 294 0 obj <> endobj 133 0 obj <> endobj 533 0 obj <> endobj 120 0 obj <> endobj 534 0 obj <> endobj 47 0 obj <> endobj 55 0 obj <> endobj 135 0 obj <> endobj 535 0 obj <> endobj 89 0 obj <> endobj 141 0 obj <> endobj 91 0 obj <> endobj 536 0 obj <> endobj 116 0 obj <> endobj 49 0 obj <> endobj 537 0 obj <> endobj 538 0 obj <>stream x]O10 @EЅUqP(/ СY:ߝ|]FEehvK@Fˢ@[;'nʿ?`5]M$WBi )(I4E6ƴXI{`0mFU?M%K17MR{;RB|qT endstream endobj 213 0 obj <> endobj 539 0 obj <> endobj 57 0 obj <> endobj 468 0 obj <> endobj 212 0 obj <> endobj 540 0 obj <> endobj 541 0 obj <>stream x]=n0 wB786\%Cd 4DgCu'=?viݵ.E)JYLuHRxEuw_ i6Pߩ<=٭@⑪7Rp1}96f =641E(qd(2r 9c$hb$ƉL g2>,j|JymjS#Hfn endstream endobj 93 0 obj <> endobj 542 0 obj <> endobj 43 0 obj <> endobj 543 0 obj <> endobj 51 0 obj <> endobj 349 0 obj <> endobj 214 0 obj <> endobj 544 0 obj <> endobj 180 0 obj <> endobj 202 0 obj <> endobj 137 0 obj <> endobj 112 0 obj <> endobj 545 0 obj <> endobj 546 0 obj <>stream x]A E@VhM^а(%]x{Zc\I>g9Pv zBu:> endobj 547 0 obj <> endobj 45 0 obj <> endobj 548 0 obj <> endobj 53 0 obj <> endobj 204 0 obj <> endobj 139 0 obj <> endobj 549 0 obj <> endobj 114 0 obj <> endobj 550 0 obj <> endobj 471 0 obj <> endobj 506 0 obj <>stream xW TSg=1Ԟim㣝Z[աQPD0ElnãtPӏAB [0{!YP|B()ۤJYFZzAm̪'׮%'E$ H*HOI*â)ʰ r7Y#W'䯖6?*LQ"+J9C*)۝voIsr Rdaң)2 AKHbJse#GwEedf.E0x|6[rJ@#LGHX!*0j{ p<[L:[O- DS9Nk -c0 >X1|LZ'2a+$w=|(x2zcאOlπEa~26)}&chIk4rЙ(c^( pFlDӽ(vSKYpd:y^.L.QcYo3(*&54iC]VHj>5GQ4Jv=oB&3tS!-mPDdj, C;ownA/{lPNj(85A<$ Q:A׋j5ezDC!Kt;Pܢs^ GST&ͣQʿ˳ˤ B FZ^kdyNOUy<0\z2x˨9}H"DMZQ2zF,p"u -_}F?-OG>BM6QzDZqe{DD-Wash#6@)U C~!}Ƈ) j o& dkjk~=~l*DVGͽRBѦ?/Fsy݇?+>ri؁iht4yҶs!  ћquކ:p1-ELg;znwkʡDJՓS](-Ds Rq ohݷ\ʔc );[r i!̤lf8EfU钸]>?&;x:;m.ISS}$ "Їv;Bt[&@tN*[KoՎXm`'UR]J!=?QTMEפ+ u)23D;>S0j#2NAv7WګqbJ/l=5F5pE"8FVJ3/d/O䲦+au@v,~}oZ u?2VŌ̟NW[^OsuӮ"B.bاZ-rO~!V$f8/v!msZ' #!_=~$^6/atop|7QXRkZEyZUS'H2xuk+p(^(.I)NJg殐ȑSԔJe騬V,~cF~1?#]6d+`fQIl 2/GӞ/8؇%c@]PE dwbZY VhV2ZWR#$czjS4ȃP~_M(dҵS%j0&kjwuzlns+cJ[q_ꬑeݕ˯3ȟMJ#{QpJiݤ IņdyLX~)Ƚ{g:7N%01:j?d֛49Pci*ꉮZXf37:lݭ0HfەY12E ]d! M>\G*P5Qn=sQr::4]*1Gq{. Ggo8q2t2?/,L u<B}_u/7.KWu v lt*$S(Xㅒzij|)lhbX?o) 3SQʘi~N{SnYhqEY_fh  'g)_֩ͧ"΅|iv^k%Qf7u"2D]ne'~uKP JzmCxōkz{N6nZ?*.+P4+Dq v-\dR[Q߈FP)ۢv% @)\-a^XPSQ;jhc2Hi&Sޜw:hj6OF/7/mo&I-.6(IgVm6OYYO{{Z=ud?BEoiubj ;i@bCïS>vmnz^u}6? Bn jCq!%Fnh?Y=45R3-PTe yh-xNm(Ѻx%"yZnUXay˓HLv7i \j! (t6J5>bCxH4:9?"4 , BAB_,v+rR32s[<~WOf?\ll%)2T7Y-QW*c*h 'N2EuJU⇒\=?ŚȄ=,?J75Ժu$ٛ}/_N JAu(O$Oe͸`kəf]|vO4M/_μ4P0s>5)|wTʼnt,$J'! bl]~)~IT{k?!|}"6l/Z0쵟{(7 $Q3VOoJy~Mydr(Ti.C1)IQT|# > endobj 507 0 obj <>stream x]OQk1"֪M=H4V FE! [vج GݶQ1r!j4z,Ə'^ك M|PRd#R?pEQ5ȗ|-_n7W|.aWEK|?)m%/(Ry7㇮ KJ~4/Ibx#u/"I|gp?|յI+B]P꽂^z!:!BT*hԠiF2Bޓ_їt9Z) @~2YVb1ei. xgY&QflVeN*5y8T}mafciExTQS^@Z4K Gיale%4^Uv')$3b*U&>^'ΝnYfGNu!G endstream endobj 121 0 obj <> endobj 508 0 obj <>stream x-]LSgiBب94B&F1N#e[.'˱= ?JAZh5MQ4jwƯxcܢ7z{wCc$~4RP4MJ ejkZ.R(sչ}yVZ%bW!–%v;])8hbC |ZvcYY9Ƌfggdm4l`0-f$nw)gs q{ZmL>ɋ.AKƳ_Kt`s4Jz^sV;K|(R ):D,HڬX&5oYyE sE/qDpumՍНn}9Ld#ŋݸK7An]@ϦdZL$v`dSR:2pj+'o3~QJbк$Pt֐))dGX8HKȕ؟¿b^?^x^鯮#ߒb$:|$Pנwڇ@ǶB 7f`h dֲPw^';SnN/3i=.tq[oujg4;bL?*xJ94z}U;v|UQ\FRntv"tFi@)f`څ6HA/3;yZ}1#֛&f'm!f8ZS\N4 P||WWylL5?g endstream endobj 48 0 obj <> endobj 509 0 obj <>stream xuVyTgRN@ȢbԠD$7TDi HؚfE;&,$̼<`&q\|̙)7gx;{d8J&k6_0L:N&~:Qr:ClGd9dkca:>wKU/?zUd6|_`zC.,$2P'T5z_x.Y,LyF͋ֆ~>W SąhB뢣tꍁ!W{X Ѫ7Dh(rZ/d \xɻK)jFmj5ZCR먅;=@(zrޠ(gYeCRL-'yx LBi=JƏ!7eB'c'C̳]q}k\d3Aܬdby>5/k0 e p䝷)O0YJM&ޔe4r3y QaⲠ<`X`4J4v5# cPj)꼢F zXZphH'c?ݿqrKt~I[`=KKrӖt쩤cyfTݶ|8摢L2yNIS%|BWY .`sNkA VpfIYzEea_I ;9W+PCn7ܑVt X!"$n8Gz0)IESkjp&'TT?F#+5Vh^CXW‰Yq8*_sTq}4?I<sWsY"N?Y*u5쌊Kd ɶ`$/ l 棂vgD_>|Db9XkRc~%J+1"S ^8d=l4&FI u6LDx40,%uƴՇGG% AݻvIb}8S֎j8MN1$@&x@-{!N?y2Eip8hHb}!o !0 s^zV̶M[OgTv3Z,8HOLF;RЊ`'иȼ|Vx,qN̩ __ȸfnd)x(*Yi=VJ0H# J&MT|$l9g eY_ nmk{T U+񙄯>6bdH 1یq$l(lM̼__,UZg+ca:,z6?{G@2UQ&^R|0[\㔆QZ8܈jA|5EGϡ NBsc oht2,]D 8aY]_ݒ3:eLU#W0/ӑu4A#X\њjBp%rLKaW#GVxmB=3 ,Hup15hΊ/F fsN3^eiX95`OA2#-g*9k  r ;,#`99LfG t%NnCA\ |z|lp'v.L\Ԕ)"Zʉ%ն;lmQh;dkGQ3o endstream endobj 56 0 obj <> endobj 510 0 obj <>stream xX XSֽ1psU[A}RUVZPl(uQHc3HrA1a2 Pgš㫭VjBW{?xrOΰk}EM/J$IOlhaHKx;t/\mg& f %d) eۢ~ DZ9N=S'O# VAJfE9~ 6ߎ6I&7ncqO8|@f%apHMˢ7lY#_+Wz{rTմ3f3kl9sǎn oMԇlj$DI}LVRc(wjOyPP 5B-j-ZG-ަPSS(jJMR3eLʍzZN͢SAzj0%<(/^P%RèQ՛CA͡~ Z:(sГҹҍҝv~}!ُPMC>6oةa~f#T*7ov b0 ؤUF AJuUHR ( Ee37D"_7[IWDAըFբi;sԬpPg3KhM0܍C_ۈJ6s h,Tebn)y/XLK?rTCGnteX'pү>@QQLނ jΓS At5F AdI`l3i,?M^G0xv.]zu$|EYGtZ ^%G 'shz\Ma,>g%=A_JrXj) Dy%dKQMptZbJގq'a,P슗 }a(!IB|8M+&SY&Ӛx_v138A{ϯ]0}bsh?LuAq%wn-דm|l`S <;oTJ?-ZadR6AîM^^MG=q$ ;[g"e%wH?{TjKwidi2w^R%'-d]LgFN(@pg C`$ qlM&nЭ[&_YxSΥo/ E)"x J3VSj=!oҧ7sɾ4Jp 4 ,dzn=A=ݬk& _^~`{9h"b8ۊDb桓5v7[VF6#Ps.!YT'ܦ;}IkNqv7rP%z1'ڏh3/)7e ӀPajb52lIaU H -Xo`ܰտ4GiEZC 6s 6Jy,:oz{mܑџDB͘hh8aj ulEV>ejegU2tG3\SP3*ͮd50qc;Eʠcd;1'+ ɕUwG:eu9C⌝18ŋ5.'hF60 $ߑR%7%#mӞO[oQ|/} g>xWwzwk.y{OmkUwj-Bos"P= hle݅UI24?8_;w2"Q^&D(rMo~[U"6LVh+rIP5I'P+0?||Kx*+/e`ZPN?:dK&L }Ϝ>;e*e E*:tWYE+b\^TuE;3rU@LYUQ]UTê ЯbbZ4Ʋ(^eRxPW,/wDfw?yWNAb:šX5Z3w0ΎPyAc)-@hcڢ -ރ#AԜp /=25]k]#ZVJL*Gz~<_H{ |m܇ËKgWoRe(y#W\XWAoi$fx` #CGN}򓪸:NUC[Oϓ%|05[Vdp?+>i-}*m2YxLVWVFbKPziVSD͑޵޵\S)ruؾU7p ʋ1W_=ߴo[rFԩܻȧ u8z )y+( /Lv9K7[˴dnSӪ"Ob-˷aZfk+ә B8C:x.@1Rx- Pm>AL"Ǚ(+"1!è`w>~}%:f5͜+,0/)pPyX5q͊ԗ(R6gaHl,$2Kx-<7ojZEsd,HaS"׫%dJjדpc,Yxݷ<px9V:&n:aʅXeVy\R6>Vj"doyyZIܖC\dd["7,,>y/βIɩiHŘ^qlkeInyۑFq9gn'Ei;#GN#W-^0<"=:QvYbbC+o. `I$oIq('Hﱏ}qRhLiEQU4քۗE-Xp'lnR('VR(wB D< 0?Xl݋0R2 \V$%;ؠ'-J Q =.}LiZÝZpc%mb{?w}㫯o C<5290%'YXTgfVacP,YSI ̯WN#:C,n o lzfyu}/;]o}t/!PEx8;;g2y@Pあ0_WKvw>pNN+6ҋ& 8ZtŬK\* MÁٜbz0y4fam12#`$]H^-zmVwedqH`Nx=X'Z]İnF…BBaaWH> endobj 511 0 obj <>stream xUKSauE7Ŭ sNf)1Y2fQBF眝eB*ZWAEDD]wE³x謡9y#cS+;/TKګmjmZ =} / Q> #cghd;1yf.Eye[^;3̄yYF<EW"<όöz{^Яf{:!|wf`KXY`}Ԅ]Ƨ 3Upq1&',JBMm< XXce],1KsN+UJKtNR 9DZvsZ2B;QUEOE,j.]@Uz0\j_v,=M;m'ߵ9%(03Aݕn ,yԝ&[j=מL'5кFI~ыE΢-r>zOZJM((7] UHπ7DR[2d.o~h>%ٺRSpI/?9 'YmhVZ*KrV[cvd>_PZ7 endstream endobj 90 0 obj <> endobj 512 0 obj <>stream xW TSW>1xTDw%͡Zr}P[Z_T*VNJ(7$ s7 / Roڎv|w̴>fֺ;{tYZ$+g2o%FGY57u4Y&M%=.7 𗃿_ה_= O@'Rr,Sk*IIJ>+ha慆Z=>#hu&91=^C~dnOI OhωOϝA)u9y AQ5A}Dfgi59A3s2($#"32kiNT2rmwD'KIKMQS4*zzNPOQQ3,* "Hj2E-R+gWj<8edGX+o Ed1/9;V7uyxbb mtK+dݞ(TYkɤ/ 'g/^':YM!fRjpmo=V Y"'zs%=K(gz,COƊZёWUgJɮ<(N[RdRE9*D(ie4ZcVyN3\AE25iSvh~lnF Y}&qqyض#]{ߔ/+M+`5VRݶ{AuyS{ԜK P[&]'GƴZzAyЂ/ M\iq'Kiݿw;_f>"PB|I9̶NyTȟŤKCķ;fK;h5׆yC"B qemRK54\r })<`]~!R"4]AVԠQk t_/~=Wi^KLgy-C=yE鬰T8ռy~@K48Y״ D*쏞|}ٯ"Sey!hҵk__WH֚Ϡ~&G/:wCs!n4%ɤ()W,(V싻DfX<1el'T:D "2|)sJ.K JB clz%rGśqPB8:mߦk ٽ#-5LJ'6E7jl 47|9`b V&MjfkOʶRS ni %| pJR-,6rKG(=66! 2!K̄mn_#bgt~zXvF t{~8b`!QbbATonX.ÏU7lSҀmbheϡ{I&-[ֿ~Uv( CUNElm#.5ò @yZ&Gפ _/[DKE~-?b|BT^zUWg'Бg\9WBhKv3(t)ϕw5*kX{w .a3SXuwvjw.`vmި37q,/ <.0/~[tKNu[3M߭ԈN/)ƴɅlM8$Fj IګrtBCP̡[@h97%%GH?z dvĆ!Zi=vfƠ蘬7y!*VB0W?DwA"N~Æ8S~tPy}=܊(8+WRB$ԬU+mN' P~ {- "nߖ|jӹ`|wUޣL©#ğ&@<:n%R,_Pr;A(K۱9c#0 +ZhCcؾZHGQ6eem(Ed!bTlF Πὑx2Vb|&+(&Qې2R7w"CZYك[ M ,"s+F2[r{mj ]koJ\LLQe^Wk[CSS o0\㫆b8YUBZ%jI '^׎'>-oЯQ/'Q{M3 ڻYvq)6ɡS&0,4rlW g15o#(PÃy4=B_vUXyd6ұ4Z $8ȥR']?W.)j|;# %&>AH |$A)h) Doc*>Kt56C dCJJ 0qܡ˭b pZszv%7:5J,#,V5YUnrc>;`9\vy):ߗQGl)lILMh.lwwvx.^ΑygRgx o.VlɇV_z;/Q=n>T#G6TxLq!ԗ=;.={OcզK`_R-9gWɩQԅ7ewlPmZyq$V،Z4ohn8z&5cJCuI (ݣcS kqu endstream endobj 142 0 obj <> endobj 513 0 obj <>stream xcd`ab`dddu 21T~H3a!cO]nn?G ~(Ș[_PYQ`hii`d``ZXX('gT*hdX뗗%i(gd(((%*\"s JKR|SR Ab?M?o>҇]ޝ+ڝ͑¾lzٳTR> 7Qޔ=c<ȨߟgxwS?0X_4ѳժ?wk=9jʕ[u_.oߢfZ-Y1wºrxa[+'Woߍss$-<{ ~'Ncu[|>I<<20Fh endstream endobj 92 0 obj <> endobj 514 0 obj <>stream xV pgU[ pL;=+L3 % B 19bsY!lIe[$YaɖCl BC&†dkb̲m;LJ].~G$ob /cjbJ;8w#c(-$ibw-4LYQRT,O]t ry?Je|$5](/ Cij4D$W.[],V=\MM aY iEњ֔ȋSDjQAzDL:rWLV%UK DaXO$rBLX*,W TJ*DVyP_[ꪅz-#F 7L x{Z>}y?(]EH:ġ 0hKA5Аno`tw2AIw@"=Buem΢19V8FT4fDB:ܬ62Ք;niqG(޲E)ELɺB 75p0ISCGL⣗4j )@(!)ze4?```*߬w8 pc;Nέ2N`$E@⹂m؝-dg >iT٥WKjSEx^kF;m?a:Sl@4A0lu;9v`-2LG "2]?1~CXj61{A./ѽ3P!pd8x䌸3ݐ Zzns4458}E4xxs/NSm_}3 u?/vҝTK Lt%RqD,B'H&QI|G|(5~ӛoTo+Rfa?ny dw7ء|UUfmJݺN dNhQ4 ȝձm$=wGw:M\'t@[XSd_*,.WW$@.T4)kg_uHYZ2u½`9T;6&U2|wQӍk-&nVP? xۈ}j qOrZ"2yYM=xVR;9ԃ:auBR]?Vu&8GYPҬA{mVy@ZLYNb(q}nEq6үzLtc#jA;⢓Z (qEHA' sGF@Zi6mAo4veNBx[z>6hR1Z ʢ`G;6 HFqX̨՜7I9?]_磭'R"~gˑB/x 'W\X?L_>P:ɾaaЛz3-Gm] SvGMX93ᵻ_^ZFdF}SC@~ !>% 6B1}!B}ҪLi]y153?-J2WQOrkkp >8|He': $ވWQF;5V 4QI:QڎR^mlJO8Z`mERn{f҂m\+:e}5^Brn4IKX̅.zK9[A揿zǎJxVػ%檔Uvgrx cVnAgAYōΒRWE=~g88ùy@}??J7~&:=oؠ8V4ߪAFTgU2e0Jw.Ro6X:8a^y?Ŵ;>X(#rc=^SW;[r 2+T3 2KHmjE8jh MPy ?|2&XtqAa4~C>+wcc1svn=L=8R ИRR^ýG16i@r.(Sg)uV$j^F-z#Xj %Eq3 &ތkr< =?Q GGg낽:q&UG5PIw/NyC4nRv͜ƪblDe1-\H/28ӕ?h endstream endobj 117 0 obj <> endobj 515 0 obj <>stream xSSSWGZؾ*j_^붋-`+l)YQt,`0DB bHjH 4R(~V-ŵڭ{_zݙ}9w3=Ϲ$$IJ7 Ia% ȃ/F C8~>OP$-2' +vy.*g "[Tqk⼜.9WYs<_ER|ez,mR]K9}6JTe\R*.b.YCU\@DhVV_wQK uV"'"_/ 1``"a"O"%'s眥ަ|AIb%-[%LT{Pqw!o郔ƙcصk*ܞOJ ٳ;$;ovo ?L uM*j{UOeWU傯g^+ٲ}`O.#e&LW $:gp;0@{e;,VȄ:#5ֽ&0d2v&Mc$4ȱ* *.CCɔG8|+f[#5A[3F8,bWfl47~n5n. PSk(58 &Cdn*:H,2xCQ>qQ~':PO`rY{l&uH4Wm )46? '6v(z'.N+νC%6Oj4As5 zkZ~ FN؏S{0IcO2yY<$\?z8 Wv;iGcJ-{%ѠZ[TwA"u ]3ֆB6;gsI4Zi~*˵YF:d#݅,ԲhK`D?=~%O=F@3Ǽ 4k8W)ouɭ`b/U+!8T#&8HA!CJ}VS5P 4NF: 7y!'>Bwc_ݜqJ=ĻvvD?LFROϼT\ L,Vntt8wKcg힩;YJ6)#m>a yLQ)/dRf7TxIDbE̫Y^#mk SxjKֿ۠/7˞2"=7fb_<ťδ3uv1X_q>FI?w|=cpFf1~6E *?b GO_6_>v功=]EK_B>Go:tpUUKJСb5-FHJ/FHm]?:GmLK;o0SR-4梅>h4WWnM 0I8 -z&+4lUިR[&p!RG\(=(N :[mk-,Z8J$^܅.WRXࣄ$gRSV Jy(5x "W'H(uigʺkm67df.!43P/,a endstream endobj 50 0 obj <> endobj 516 0 obj <>stream xYtSW8#y!@P1` &Yt$Y]-`Nh2)d I2aԐ>WI 3_Z^ro rÖ۴zlS\fW t)`F mQБ4 rӲU Y!SYpg^4%6#1:25d]dVBlJd!9$,-:16+?d+ YYE/;+2%sVZFkf&f%l͌ȉ y3-5+ȔؐO7kmYZ8;+6#d]ZLlF*Y4e+2\*{uΚȷG+y;64n}|İM[R(h3gq88g99898LqlLlLlLl3g|*蕠F}T&rz`antǏ?=aބӿ:D6RT;U+! |b C$E۽̪YS< "^&dz} ڠplj/-ptijRv*AiԆx#W~F<]Y!+bgݰn/T AGEz$*HfyZfdH!@}rI"_"٠4R߷/ 诉Jr?ۡB$4 ev aog`ZL7ӧ/~B2AD\Ck<Ƃ? +`'S&_X9z #Y [#~pZOR[qiɢP*uӶہ'墝x8NPMQLf΀dR,Pcvz U/S :MckgZ =`(u:%- t $B)}Fe,+={Ǩ1A+M;WWIO/R?VN0Q ]tg?1]JKCuL]J0ZmxCxC|| % FMӀLA]quCE8(Vf&#mE\t!ZJƾʎ|kBף97 yth3PYB[hF˼e ʬRXM A ,ڃX ꣎'T4##S3;]As\Uu6K`k?= EbԷ⌈ۀ m3LFPsZ@ Od=GPJDEc{L1ƾjJ#;ٱSyQ7.\ 䇸[v΋ڹ5_Id#bB&罨=|Zm @PTUT,DaW(S̏6 `z`]9 M{aYYFfP#5[ նAs~1fh2Neyn*U#`5S RSvSq+m.v{41+PypNϔ1TxL--udjw}u6z}M"kif= \*.ch "LQ"+b'W&)@|UgW~} t:: `(bٽeМ#'gy vʼSA쁃}G*nP-ʳ-GhxUUst?Fly_'h-Y[}0@%a՚UddY'Y3Uwip/(߱=7Mbk5WQdD9m[(V_䗜_Uk<5wmo({qЈyne[-LD!ű MId ̎g*T:+:x"E鵲w%kr PPbC9ѐc)I9RIl<"kch\`%JrxL$b:[;*?ok+;!0A=TH uqѰH|N&-irX/CPF@ON< bV~h:zΟcsD$(Hr|о)kkuw>* R9c0ǧ@8R#nXc@,\XhD`(q␋)]T`gCg#O0kdQ[~jl e.;NM5pK1갭߻'Đ{a:?SuD7j.璆 2}B[h7y}tp4bu F1o-%H4} @UR0[-NfN-kp#;Yx! yo Pjb5H#|;+ jE@,l.el*GV3((d 靥8xN2%d<`UeT'ј:7T~; k=$4js75$ z|k)QM@IؠV_8R!hVȣ?f1 *.25P9pA)_1̀Kة:[.vNNSC fCJuހGv$tb$0`$k.4@G-zPebZeƿ4W:*#SU5[\HTfB.]%} 6jZ;&;;;$`ey}Ëɣ9BebxCIVb.“dd&a=8{%26; ApuNZ0zG4ΥE bg9TQ,ȿWˬ))ѫ?zg)Sd⦈Pv;8J;\%T&ɮQ~Gͺ-hU`^ +5ۧzSuz2{ai"K[kI}XZzµI񪄄d\l :2Tb3Z'ڼJI Z > Ф=Wčׯ#I0pOp U dVH(򈥽 ZYu"& RD@Ѝ :Se57JV@MBOz/A Y9'h?sl*W+]HzJ'É^G4Ld Zi(3ssq`QgWc0H`p4BHD;*Nv\_"A!)6pJ3u Nq8ItH-&~`{O/E guSsC(E r!;ʻ(o H">}.s}8hrPeOΚRrwAX5jФ*`E^dI~hܾXs<_6sEngfp/{:lcdJ6=US8]$ժخm;Q60dDӱ <{FE:g3h*@jpV;۽ho n>zU z`[XS Q7wKk7[jvߵ+T^ZBa{Rk5?w_\8\01pt&fhI1Էkjk fdzCCaەF51t\#I7Du2hM@üN-g}KszA|.f7(3 TSrZ̍涸[5܃EhZEE~-Ä-IOJKN)mlm6hŘ,g(55%9Dc^z?l/֎bjIeBOГmQtFBVp#|( d(TP2Z,/݊H/lPE+ 0˜(X᳑a'1t~͈y endstream endobj 58 0 obj <> endobj 517 0 obj <>stream xy\SW1먳WA({[guォ('aa[5:Pvs?$h$'<|s#:v x<^y+-_~8CvEbA}~DJB@ $H%!X3хJ /l'Hy-0~]k8NNIt~.گkiGJ_;==&(鹩e=w]}8śbL?컿߁~߅Li 凊wop@Ԁ;#yiKF :ۅ`&0A=|LpCx Wٝއ^ 7j1R9 %ݏkCII*Htց @y(ȢpA)I{A"sh~:Jy@9<C/su;|'I[Ѥ .r^tXo塷]iGp7 "`|+"7 74N5p倽ԙ^@+%tJo 'Ŷr'麀)-/lC557!cܴCQ&J)'N9, 7^Fimf>(``dyvlê|8S*鏥=R~~geu6uKĮa/uUm󆰯[aS%/W酷{ 3B+ ;κ>BPO"oav z?7=+||A%]uO#f1+R D:RYS+)m.?sh }45%l .I劽/1f>nz(W3;GU /dTJy0~od6@1hZ6!6";=v;Y!J6G$jo~3`C3 LSb51DcPݎS3]֔|P v`o[*Jeks׳),$ t,K%u9kpdAmTmL xT'5:v@`= lJ*5n>hsU @4W{SVw?] 0|Z;ybn2SH0ަD<^A$![JGJI@[ب͓-T]VVf`ux0f캤 vO<Ӿź RU!>Qgt*Ůc H 22B 8 {ywqtU̚Ұ9E[oA·$-L\378R* TN'Mרww`h9ځ#-5:VRZK\ pF9WW븊p$ g&7I+0c゙܅wY‹_/Y45#}}:P>3Z9!Qkz*]b}Fk|n~%w^$ð,)\G\nv26YH[[(} AC* du/&Nk2X0+OpN}bpC}qy2eAh#{kyU؄}F<.;-zCPgSwnEjŬ?tuk LM}*׿/_s8 h+c♘xbo9kapBՏ7҃ޛb{lw?Fٜ ha~$(S`EƃW|¢w;aљ4y6S-`l&@ߟrf숖Yc`bk[l˽P&jhaO;rk'DARci$./Aݲf aG|0LJI^OJ {#7Jo~PTJCoN֕ʚfDx@ꄱDeH&UtWƤ\I-l{&v%pބkVdOUavp P_}- %LqFT"/D5\Wϱ_T E[$e $43U"'|tY'2@eh ]ϯy_ H)?]k fKۨy_ 7Gr x0hZ>lJU G~3െ/1J$ 'q:TÚuAJ($hwN~ټ9jß<簶?]E aZ'AhԻ]4N+j(.}` CۍH`KP}$"Lah[wa|tMŠ,>VܐXC\5ob6~t̠% 0jE4d=X$+H|a\KMkD"!ў^P>:{ &炬"[e@as;YU¼W`1 qNb^0wGkܜjԄ L1_'d:fe|Qr]FϘ . !d?'80D.3. /um'"CNKz Ys&ڪ6*tң]%77 pSX?%C]$iǬf~|0<>،&rxˤo6wPU֜וbX-YF䦢V:HuV!Hpr7,lan%dB '0#e26ԧ%yᆓC10:4]]aEtCom9L4ƚN;j][v>mU{)R6\A 75TU7UE@onջuHʮȘdvwJ6^Z-lcd΅\wv䕋UB#ܓ [S4Y SRfMDK5&"&+(4:.m i?u(gx.yh  LPbt1܀bD([#9'נ_(-Њ`Nn~ qX άi7x4 )"#^5%JFʜy;;LKTQ $ؑpvY붳ClX~អIU3ZFo]uʞV^ .$ yc^4 Farbdfk$>|㮂Q "SSbTa3 X;|5 YynZYcpsJ(7j*e` T`dݰq@=wscs|LTCTƘha|2?8 Ps__~ߍ|n?nNPkYnܡ/*,k]Rb/b0&ܰi֤- Ν{4.P՞w4oس]N8Bґ5oL9S zV||0'K60ہٯ˥m bؑ,11 帏CaV(&ĕt*+uVYd| 7~ʻ%9.iƪ%'f&s}pQۧg} R_9_ ڒey61!8*W$ T,av+@YWZl5}+0Sh,ȬnId-N^ΌF42O<7>P5b6wx\7S~_)VyJSfHv۬r )՘MT9.ƙϬ{!7wLvK iT* 꺴 v``u;i8#F=G}gUY#43'[,: ٟWkd9 UEU"\ q%Q)nGEV륐<3J+ =/k1=k7,M:U"^9Pƕ!pf+U[χ?j%u Y z 8KeYI|-F Рt4XŒ q=}5%Pp*Q*u"%Ȧd%ٞ7aO~;!<=25vOlmVSLл=Q8Dh\lqQXӧg$ɹ=ӭ<si'Ծ┨REgi f+^nSax\uv,/bs7~s9l+/YDN.W2]::=+ endstream endobj 469 0 obj <> endobj 518 0 obj <>stream x=TkPSG77-D^%&A< ; a$V( Y BRdV*TDAEt-Lu칷Cݝ=go% IR[z=LrSDT a5'ȅB.SnP>hºqEٹl!3=è:[ Vfi jR6fhFaYOMY!Fc>ꬭ>zCG efưMQX3*W4w|ƠT7j : \CׄEl]64q 1&%|D  &Da IwKQt J*}P,j?fUπ $p'ӿ3x)O-$&%8NB7 slX4Txg 4B'NśhArhx5 , ~~s9j+^%&z7ffR[o9ha:3x{u"P"<$nG?-B bQZeY֚e9k(j%Il(WV5'slVkȬ [PA\4MJB'%eolSޖRAXv0 *GTp)P7Cvp8٩A%'$ܰk>69!B<> endobj 519 0 obj <>stream xeylgMnk+af-dRE%!ENc.@ӐXX{yox{k׋1LB!@!QDICR57$M'=XaxqeubE?wb"(@I =?E #*JƨkjhϬ]fWojU*ynT*h"IIiZW)ZԺVۛF.^kSVV|p^nhN^>ԩ-F!FhQ8PBaXԼ~dxj Ul7ۆ=w܏=,JbHi&Eɿ ESŇytԞ{@Lf^Q`%vͪO~sﲱ.ԯUTarrCCAnJN͠p{rZtw5hmj_pHȅ؛˿"g3:/37奌٭x*I(r4!s﷍#8OܓMͭ=!awzN7u `Z="cTPVA==Pp>:·"X7 D0 )tl^XN >gmK/2SR>ZҷLCQRXD;=6,jx*z lH6Q7;2qit(6[-Wr _wE ȸ inBb!J) 1+H?2s+pMˎ*5 ĂSs~+qf v3Xl\w١7ͥǗ DžTnKY{?KC/Q'Z9AdZ`;I;8AX́ݵץ#* ,)eL.8% 2YeSIK$ qɓ-HxxwD8#6;Yk&r]PfQEA^*l9.=p ^x~PZ-s\!2IF"g)*< S} @$~ PҶ _"MX-8E5%%%n= endstream endobj 44 0 obj <> endobj 520 0 obj <>stream xX TS־1$ *m !2d' 2O"CAVVjkdkomyRmv_-^6&nWtƒyWi jp(MWaO$%ޤے[&iv"m &,$?N6~6ڪ2X0g%I6OF?'ZȉD,2&~8LE-z hSOHM< lXs+6\j>(J?ppND Z0):&N4 cD)@hA({>D[s|P6yksl.9,0E;SܻX2}j;.`QxBS(t` #x:p5|:W:'h[{fg/촠ȉyc>EkYbf?q~γ>G|_Ry()RϸNh/nGh|(ycq.M"~s8рR8=p q݂K]ؤ.I9]捍8^s~!buI2s}_, 𕐟YVv&3[];/P2 qdts!Ә ӎG{b6)S2t@v>ДJvdPNqT :7VZUyVV w@5Ed36!Vn5 `$:C0v8n" 10'#gb=7#s+2J+) &|J](}ؕa!Zc1mIV,a/ $ {D* xdbrnj[zg ~AÓx;Qxo0̾cW.K<h*;j/u&~IL:k/0t<L@dPk2Ze5Gl>t>Y0k~·o =_[p8Ղ-_CMFT9&EVy4J: }Zp*CaGβB`_4M=g *$,K4C΋.c`%6'@RnZNFQ$d6[~K4Gi`Сx90*?.WSN|Ub#RVmT9yJLFkyFQ+mY2x]dW545VWj*ˌuP n],C$bWb}vD|7(~V@Mu$ j9"Ϝx;d8 |L{-Upt*>XX8 *Z^-5PMv2C1JS=,'͔ߺW9}~>JPL(:UʂM,Qˆ07f_?)?veUg7O9NeCLn>Da;ʝ4'%d|wCâ&D4-\9  o5 jNwZцeL 1̓&re׆\_HWO>*/Mx]vR<|_1Q\7Z:m-GkL ~ gwO&FR#-yx1Bz#5+3t{,q<,}23n7 ԥU|ZܖENC=%^oVQM|wSq:O>8֖\$o,-7dg)$9Cuq-J_L\̯οp3e!E~]*}qA#3<`= \ oqu%2ߺ0N:;!SOnLY/-><~\;u }5xl/I>AAgxe(6Øa7c̤KCvtt?H6ƘLhqco:h?7" y8ؐ7X38\zZk›Tt[A/sA7u5T}:MN%$F As5sL|B#%*Xc}q#/]8F1F=~!fUgSF]z^#2&r-aG9rSai34qa~ʰ0t}%ν{+Jss2qi{..{I kІ?~*zcQa/qd"]/n&YHjR$s"[Gj85I!e44O21el}.HN}ausFy6ACdž})M5D*ĝUE%R=5٠hj~uk-jm 1 endstream endobj 52 0 obj <> endobj 521 0 obj <>stream x%yTWƫ(Dl;:ݍȠQ@0(B4@-KClj gl֠'j E[> .&/\1&Q(_j2NPSHK*rVP3(jFQʑ/PjukWvc؝b?c`Ol'. aco E2%M>2([(͢y8Tr$pq,.2wRzzvi* eBF[a*߹NR6@`!QBpHf鼅HdBQ0FOMt_~đ8z:xw8)1AM0 FݻH%9v;3B|x.Ǖp &>O}a}J|?bA0^0 b$$53!qxBf Ga .RTdJGT~/#]˓7;[RUi{2S6u~6߆KKIiq) c(p8feSa;|h!aS733񫎥SȮX'F֗+ k74i$jOT7s1]2,ڿz!e׷隕27"Tcp0`vsW>0<E8u"S~ c.PPb{rHgX,壅@0t t-2;]WQnhI-H%$[Ҳl-44>fWCgd:hb)M Ňmr[= 6ClȌU V2Q\lHX!\ѹO̯v^hQ&J@ΓܕȊXOLdIݝ^'T^"lAp@(c cŊ[+ 7EOK{"ApF`6 c0)俰 jkQ;vaj EV\Hįƶѧz43yr7FͥEMOgQ>0 ۛkΨt|HȒ7{ׯ4kIW.GE S{n4CJ3} ,] .L+Ijr)I ID^r݁}TlReēDddĤ&Y·@߶ *G5*6֙ KT|RLՃת]T0 kZ߹'."V1 1x۠쏐C_?#@nϽE NV^,c;,x()p၁KAZanbD67>._Ĩ=5άiШή9_jz`Y_q!Q!}>(@u]ʮV^Y[^aް;{y7^>6^f@vsj## ų( m J!kH#ũ0i_`xП+BCfzjYab k5ù$Ϥ:HnabVbM$b!JYv^1+Y/9XG*},#v9:Z; endstream endobj 350 0 obj <> endobj 522 0 obj <>stream xcd`ab`dddsuH3a!SG8kc7s7˦{ ~.ȘW_PYQ`hii`d``ZXX('gT*hdX뗗%i(gd(((%*]&s JKR|SRKY~tiq|@pcSۇEXYu,'fVL%ooלxPΕ$-ݛa竝#`Sg̾;|έSyx-c`xX endstream endobj 181 0 obj <> endobj 523 0 obj <>stream xcd`ab`ddt v04qH3a!Skc7s7˚ﷄ ~O XX_PYQ`hii`d``ZXX('gT*hdX뗗%i(gd(((%*c8)槤1000103012ԽK2>}wy߯jcws~7yŞ>~nSg>;3wߛgO^-ym̾^];ǂXπ| wt\eXp~`: endstream endobj 203 0 obj <> endobj 524 0 obj <>stream xVkPS>!\Ȳi랓+U֭ e*$ ܯoC !$ DTש;]]mN;N;9ٶN;ms~|\ FLjFKIUw@._qL_ۛoQתRWZ&b-JflzM? yE*vGTƭ v6Ik?,lX__SY/,(y='*cpubv:JTratT~V3\aa U|FSXWT|o=eaX6a;T, K` ,K"~퉈aLw{QߊjfD?Ieۗ5ti7n2,k~2NRq GIP:@AfWVj5i O xuؼd _](xSnb8DP-+dWvssCJ*jɝԔ Mڤn#C0HqghvPTmj-g(%(8{QٛgPQ9daat]*76W[,eJ\&Ҫ7@? p%n57iM 뺔33X%bS_kiʽwޟ2ϣP$T-.6{nŢ{5%uv9nLOkf jPyiq`{$e6'f٧}1}uI,6ƃuV",XD;i"^g"{(EA/D c(h2hWuZTJhrtϢSqM=Hpu5/Yf48yf6['=8.DwC?`C ,ېzt;%KX_\(6,C) 9P6ۋ#RHlI%w@9 8cC6']Lb~-`2ɯ)eVZq9rU1x.DAPQI=L'Sr?7tk xXx;bz\|A5FNL~ۺYe@O} (z 1jlUFw+ Hpz֮+k*HZLVB5_ʹ"QڄV/$/.gh61lu蝧W^AO; -c b>1bdz\VM3J"7uGSsLbIUp{uЋ~H_}i5ΡJ_Mk_}eU݊^9FI5|>PNƣih̕Y&lnv6HxA[ hVJj =9~dO̩3OQk5 ;ۍ66xq pe$SqGx>}T_/ULbЃ..uYV1zuOaW"h@J@3vfd70&:no|PYD~4wC8=`?6=|al"x.3y^=27U(x*.gnh1VzMܡC^u=PF0M:Eц,^X>2~a<ԅ i $h^iN)~x ъҼ%Mۻ^+arG,>KXBz>"!wSnz:'l-_0C>Af@ަ4TApTIJ7'JBaILĒٝ\v#X^ zmzњO^ƟDMhX]c=@>PiBdT3ɟlK?rR*u=E;Y NdIib׶nPO}\Ȼ. :PM8b{yqq~0 endstream endobj 138 0 obj <> endobj 525 0 obj <>stream xKSqq^6VRShR(]M0an;dz6Rw\e41/e=A/Ѓ˗||Q$3AQ4["^=NGQX\\)_ ̜NÖ|(?B(j0H(h(V*K3UDd**X WAGܦTZ5;::zcŨ/ZVC"$c&[+%zG+W M,Rd  &3\G+H&u ?US|9J6F3 ?/ff6.KQbv)=&qs Guˁ3H846I_l{Pb0 &cѥ{d-mVo~}!kW ʛ2YcC@\<:U:{I^gE)_~X%0ZKs׮"Ղ2LA[=k:ٔ.2{{FGWSOrfI5g+l}\\L$|6 N'^>l>gkVi{vós_ Bn7m6g{9N`T?mh~ >)GZg079@ބ.2yIpdtK0'Y&BrK endstream endobj 113 0 obj <> endobj 526 0 obj <>stream x{LWПumMAEfo yYjȏB[ܤR2*BJD:n323.qf.c?ve?e[8{sI!H(ZHl8M2s8̫\I- Ҹ뙓42| _D OG Y7X$Β//[P+u F.LjNfb'ZV\0YY&᭜ٜ-Ug덪w,5&xZaUTWL2B+T:a~ƹhNAf3X,?-`iohT:hbSZ1sL+;Py}ğ#RMȤöp*Dlc֖PWËѢKl ) ۝N#k |dEVoV QhAĽ kdbM)!4yիP[|=P+sjZpX@ݽQ1՘s>ƚ[Ɔ2(o2Pq8lo;IXmlegKװ܄9#L ݗқ@!yfΖ<9,KnE n$x9g%x b{\r$㹀OѬgwOw3ӇDz: pehCan2P*4C".8}A tեj]wmMFV!0>ɈF;E՜^>xZ/9KP]gTÐ>}s.>% [DTzud<;S)iii@zڛ endstream endobj 119 0 obj <> endobj 527 0 obj <>stream xUOmHSa~ߦۜQ?Id 1rF-2 -]a~l#jFѦ} ȠYF*" #?!k,9smc̘-竎nuJ*VҶ)5@]B<4uɤq i u=0ܵ*ՙ!)?5'dECc?襁r-Q`eϗ-8<.03d+_.zDx/v9e_Uʢ[\WE9lvACtvA=e!_"6 11(ͣu|J^RIRrpEXt"I5%υx Fop%7 II~mX0YX.Naօ^e MRdY&enb'@Q3ZչPk`Zض{]ƧgDO$2DPҤ\4fԫ+jF-#>C_Pm~d H92G=F:!1h(8 epS3_D'X.vnvsm~ 銹 aX?G<%+e? LAb &@ ZJ)O)H?Y@ ?ؘz QjR5@?}ssCC3=0Chbt@eB?Z endstream endobj 46 0 obj <> endobj 528 0 obj <>stream xztSWz+/ ޽(@ Zz)F^;B7Eޑhп!%V@&%BE:mЩs̚0tڔ)s{rs %%1mGX1‚N>?tR`c' =tGGnK†qj^$@ iGՁ!Em غ0pۢ틃? Y4lt.+#\WEr_sz 6leӦϘ9Y}],;>'Zj5ZGͥFRw (j#5D쩱fjOmRm"j"ZLMvPQ%j)5ZFMSө j%5ZEGfQkԛ5[KMS֔ eK SC(KG1Tn~{W-E#D9nf0%}s_)wreof^5yVo x o[c-~ik+]g{nPൃY?sG%K$׆?҇=~xGi7Rջ~3jQG>4Ř1cZ\[:WXv$m3u;!?čhPSb[76[bU]>i#+kUG0B ZuZ#iADDuF!>8-fHz-fsXdoX`Ȓo#o,[^%ka =cq(eB6MT{2UOO^8kñ-= H}05Bpp\͈0->yVvQPѱAȏf;hvoCvW9(C v\ݏ>K! d6EJmJB1ފ~Z1UJ@ mls͚:hР0~: J [#O4 'iRxi)7+@Gw62[I/~E-|n-QߋE*Nʡ7Eۼr,,B!"d_̹y&uT7OZx˜K^!3Sh]!|XWx8 @4A~9Xgp* j 9CU-eV:W:zKNۀy1tミ6;V w?*^6g("\&KK\s@eÜ"rةv1' dEc4(rK=m)5vL4Z|ևOOoXS4;$ALd@s5x^&і/~.XU=\aj/84C`4/~ʚ*Omu3a>`aZA֏"+1gYB<Cb!~Vz>>ϡ頾"?72P5}~&#U|ֈ Аh7h B4UQ3%Ia "='1L8n*Ju>+BjS0Q ZtwK~p,꾵:z}Ţ^4xdVKDzUS kb7mmID~S! ,їjkj9,֙PftɀFvEXAJ w=%Hu6'Y >㹙(;"4 0G9Ԫ14}l-~fVz'1[:UW%ɑlCGArnZ]Zi4))=rXUFKc{$>Y.Yl]zP}e}+}S'fa!T򃹠S)RSծCglwQ`T"~X\-"cu(ȿk֗z[cG|\`!P?%rڤ'=2wZV)YI[qo,N \ף68x*oǷk{xv.h6H1WV3Vld4ZhN%4ԎɢF< H54~i|S!h^=b˘|bD{f?l&:Way+H Uw8܎?97i J>f [qEV6yZ"7٩4ka?JxP”0N٨ HTY67jl+C !j2 MoyHdjR!Ҳr+rӨ7(hBBta'o۸YN{qy{*u]Nv>r%,r n*NJxyy b%G$,)&+>2%n ζjST&PtPH.όSl& ]JYXZ]8fWG!O独6$P͏1Mf6](d(#W>Eo|}4b_inU.+-9^"NM,~Fۊv3gr]Teu2/nZRU$#ܧI@M·Bԝ6YhBĘ oߣ>۰_'HMX czcbϻ}YP:h: +lvupY=eёĬȕRP?y"CCpGvrmn?{pFߴPBzb7uiWrXbu ~ "/rIwEVKR"GtREZ"A#ʏQUEƸ2%~V`!ҧ(HV6B)ו߫$o4S`#n \RȰQbLCSQ.wl:zԩ Β_G:XݓFmyk0K}Pfi>}^UϹ*WW|`xdL79Kc]բ99 *WrV{#7O?fJ,]WCB$&dq ( pijˑZ%4+=.6YiH1FyYSU̳_UWT&/ P%Gγ60o ]6;$xL~Dr q3c"G$µeLtč&⾻0C+阶fRwrg=ű\io /὆Z.4!RQl"pe&)b5gk'Bct̍"8S-D1<:Q!TrZLgdNOQg6jU&0Y*U0[]>]E$\@wqο -[99btQ:3E.YT+k{g#@ ܠ`y Ks4)Jy9` k.BDZ1R@ܣ az"g< +R<MSGӑ#_QC>Xq ~gd%:m[4^^z_|@X_!m!$rq„W*=6alDFk WΛK,/BuwcHmYIkQbw Eh: v.k9p^9rkhve(}΀UB$+0`tX7&DFĸźMR`^t11\Ұ!ĴZ,5ELT~|QNifyq|{ՅssJdNznI\Lx3 =k|Y&dv>mk5z=!z jߴF e2_bG-i;ֲVrFt%o~qɀ5ɰF7xbB׊X{}PO!3qxګ.Z5,j l9Q`}L =0-OM/ckCAA`cvcJ WЏ 2.t?m??~z_g;fpj9sbl7$mG1U{=˂s2- fnqU*' =SyjTkr39Pkunj.x=$ ϭP/ <_~g@rXP3*nO_hJ &\gP1qʔ0 tPTF#à ç۠]v}jⱶ엍:IZȯp`ɀ&71[_0%ȑV[x0B/EMo M9RR/"3>h̔ ǃ%UDpR}^.ʺ+n9E.N]2އӦ6-88J8_R `/|uuoeg p1x)w-@|19a"T2fG.xH'@AW-4aȬ#jd: S9_'{@x|驊FVG_"]nX|}MA–nGA[\TY靤+xi`;m6MGfOBm/yZT$?)!&9i9Q1՗6U3ޏ' ^X1읪ӟL?9~Ԃ |5Fp#i:!\$߱KJR*!IF)eB1wHtqX;g^zK?#oD^R{eUKWM/⿡}lagȠ]AN1Z bS}Z-'+T0wD}943rS|4<vqݹ'u/3>m|–Ew1G"dک)M86;p!^q̠a?.{,sG3Q3څEo̯h5vn3s'wO^ '&W){.q(iX@V.WV9v+vǖvXxta3Qi,u_)YH:0!zg-.MkFZnЀMb-zc SSĖFJs Ox'^Vq]f< pmW=^2tj xB~"2mOע:QCD,pCFDމb!B3.>x9g++@zCoWK=z}51AD?l0LzbԏH%3U il2V|WTB`Y= a:U)hƧ2hϙMvpXa?^-uKMWFJOW9 Mn=Wi4j*ve'\NVj7mz2#.M/@4 }:-Mܝh;tcnr9Jw`uΝAuM:*/3^L^r TPS5DXq?yCP}e*HS "b%֞!AkӸd=MXS|*bR_?b(ŧ&h#*#zq?ܑn޻qGj и1= ق4Bؤ^Ȃ~v#Tt2ܴE"WT%* LSO꺳6S`G{H.E a @\x`*] ͋.Ia,z~Q1 Ћkm{׷,]>/XyJP endstream endobj 54 0 obj <> endobj 529 0 obj <>stream xW{TSg?1sDD=A~E>PԢ(HxR<#Fj+J;޻1ޏ̽kֺw'+Yg|޿Q6(H$]9oLaH:JxG x/~`/{%L@ЎX$R)jgw=-[2yy˜W#C+}#1GveH\2B]>wnRR2>|ջs"*y|8#aYTOۂ&(d˂mΝg/gșqؗ yefVࡻD٪pEQE  vfFf!a /= (Jjs;X*׃s$U=<AK^?s U'7-q]>WK>=y&<ӐVe RB,G.faEk',yKTۀAv?~CbA(GEO^X]&-Qb\&1E?."Ap#\"u]U5a3++bMʫC=ro$-O@T.410,/D^cD^~w#rE\0 :vӆ›JЩ@ *UKp\Tj{J}a8]XZitZ4;^Ed%mD2E*x~Р*VNGPADIDCȪ5T$9^Df^Gv$XA ag TcYɋ*-la0x=C_ú.[*xBQqi 쥑ǐKvjD'e`xv*dV/=VY -L:RH]ӥ|9,f FW9lVvF7H}v%v\4;c$lj#)>u2susɘLiOiuA7 hb?2|&0>P'ha9AQT裡yy& c$i VH LB]t 0"LXlM?&a=Z"T GSG6oM !pKl|UM8+sPbᙻ2 4`)pǠ5hz~{-w3sxLN_7jyno$gn+nӎd~QY Q[b G 8/t\fTc&64::#NnVM?vnjzdFQ-IK6WI@:^ן1"O/ǶfKKiG!/K-Jo NDʹ]JR~޿WrF-фWavC5lcv_X罞Op?>{2OZg >O-bR`BPkN<ޕP9 ۨ*p:%UUX\V3EH%+*8=ID7]BӉĂ?'3Y}8hb"%uߩ6V\9oxe;,_į;Ry#&WV@ۓ}Vϕxwa☒R} QAk\>v(PD)y;DlG[ b?Vo@Q kI endstream endobj 205 0 obj <> endobj 530 0 obj <>stream xcd`ab`ddp 44H3a!kc7s7'' ~O+XP_PYQ`hii`d``ZXX('gT*hdX뗗%i(gd(((%*@ݧs JKR|SRY~t^}33tG]}{zz&~7޳S!'~ n`׋>۹Y}}!?D+8h[Z_قG,w4\7Xpa` endstream endobj 140 0 obj <> endobj 531 0 obj <>stream xcd`ab`ddds 4H3a!=<<<, }=\19(3=DA#YS\GR17(391O7$#57QOL-Tа())///K-/JQ(,PJ-N-*KMQp+QKMUNL:)槤10002&FF|¾g.3%t/]Z]-pIly?헰Vξk?<<@ \ endstream endobj 115 0 obj <> endobj 532 0 obj <>stream xmU}TSB Y^ G uB/VX!B}[,-2--̩hOVY=hʑmٍ={y.I$حnқ-:>olah㓣Q3ڀ)lƁ/RօڡMn)GF4Za5Qƛ a /|v; 3`&?d…?ԅ/dfCH>oI zO>3GMP9$KC-:`hZ60w5c~ %a|b_1IF4!58a*P݆Fyfirg,?pW}uFbw唾H[P]Y*#s6MFnYeP2KN \'j:}{'99ZPGL^pwf6*#;MmE&Q$sTqP6ߤCSNG8all J;\yAA8lanS]@\q8kKd,xPޤ )SI%[FipK11?WY> endobj 551 0 obj <>stream GPL Ghostscript 9.10 MCMC, GMRF, R, openBUGS, geoBUGS, spam, INLA, CARBayes 2015-09-28T05:29:21+02:00 2015-09-28T05:29:21+02:00 David M. Jones CMBX12Florian Gerber, Reinhard Furrer() endstream endobj 2 0 obj <>endobj xref 0 552 0000000000 65535 f 0000487976 00000 n 0000936869 00000 n 0000487630 00000 n 0000480248 00000 n 0000487920 00000 n 0000488058 00000 n 0000480047 00000 n 0000488956 00000 n 0000480849 00000 n 0000488163 00000 n 0000481341 00000 n 0000488391 00000 n 0000481949 00000 n 0000488281 00000 n 0000488558 00000 n 0000482350 00000 n 0000488686 00000 n 0000483836 00000 n 0000488828 00000 n 0000484150 00000 n 0000490148 00000 n 0000489107 00000 n 0000484814 00000 n 0000489585 00000 n 0000489220 00000 n 0000489335 00000 n 0000485191 00000 n 0000489468 00000 n 0000489748 00000 n 0000489876 00000 n 0000485632 00000 n 0000490019 00000 n 0000486276 00000 n 0000935053 00000 n 0000490305 00000 n 0000490483 00000 n 0000490633 00000 n 0000490783 00000 n 0000490992 00000 n 0000000015 00000 n 0000005470 00000 n 0000491199 00000 n 0000851964 00000 n 0000903024 00000 n 0000855147 00000 n 0000918071 00000 n 0000846573 00000 n 0000863297 00000 n 0000849211 00000 n 0000884176 00000 n 0000852518 00000 n 0000908012 00000 n 0000855903 00000 n 0000927501 00000 n 0000846923 00000 n 0000866782 00000 n 0000850208 00000 n 0000891210 00000 n 0000491261 00000 n 0000491293 00000 n 0000491402 00000 n 0000486686 00000 n 0000491554 00000 n 0000491706 00000 n 0000487186 00000 n 0000491858 00000 n 0000492010 00000 n 0000487436 00000 n 0000492161 00000 n 0000492311 00000 n 0000486960 00000 n 0000492462 00000 n 0000492613 00000 n 0000492765 00000 n 0000492917 00000 n 0000493069 00000 n 0000493221 00000 n 0000493371 00000 n 0000493521 00000 n 0000493672 00000 n 0000493824 00000 n 0000493974 00000 n 0000494125 00000 n 0000494276 00000 n 0000494427 00000 n 0000494578 00000 n 0000005491 00000 n 0000014463 00000 n 0000847784 00000 n 0000874254 00000 n 0000848299 00000 n 0000878715 00000 n 0000851436 00000 n 0000900800 00000 n 0000494729 00000 n 0000494761 00000 n 0000494870 00000 n 0000480568 00000 n 0000495019 00000 n 0000495169 00000 n 0000495321 00000 n 0000495472 00000 n 0000495623 00000 n 0000495773 00000 n 0000495983 00000 n 0000496134 00000 n 0000496285 00000 n 0000496436 00000 n 0000014484 00000 n 0000020304 00000 n 0000496655 00000 n 0000853887 00000 n 0000915278 00000 n 0000856668 00000 n 0000932708 00000 n 0000848871 00000 n 0000882155 00000 n 0000854709 00000 n 0000917016 00000 n 0000846307 00000 n 0000862184 00000 n 0000496587 00000 n 0000496620 00000 n 0000580635 00000 n 0000580832 00000 n 0000580985 00000 n 0000581137 00000 n 0000581287 00000 n 0000581440 00000 n 0000581592 00000 n 0000020326 00000 n 0000028542 00000 n 0000845924 00000 n 0000861262 00000 n 0000847401 00000 n 0000873354 00000 n 0000853709 00000 n 0000914243 00000 n 0000856435 00000 n 0000932140 00000 n 0000848140 00000 n 0000877972 00000 n 0000581745 00000 n 0000581778 00000 n 0000582029 00000 n 0000481066 00000 n 0000582180 00000 n 0000582332 00000 n 0000582482 00000 n 0000582634 00000 n 0000582786 00000 n 0000582939 00000 n 0000583092 00000 n 0000583243 00000 n 0000482167 00000 n 0000583395 00000 n 0000583545 00000 n 0000583697 00000 n 0000583847 00000 n 0000028564 00000 n 0000035793 00000 n 0000583998 00000 n 0000584031 00000 n 0000584176 00000 n 0000584329 00000 n 0000584482 00000 n 0000584634 00000 n 0000584787 00000 n 0000584939 00000 n 0000585091 00000 n 0000585244 00000 n 0000585397 00000 n 0000585550 00000 n 0000585703 00000 n 0000585856 00000 n 0000586009 00000 n 0000586161 00000 n 0000035815 00000 n 0000044746 00000 n 0000853214 00000 n 0000910997 00000 n 0000586314 00000 n 0000586347 00000 n 0000481623 00000 n 0000044768 00000 n 0000048726 00000 n 0000586596 00000 n 0000586629 00000 n 0000481786 00000 n 0000048748 00000 n 0000050515 00000 n 0000586763 00000 n 0000586796 00000 n 0000586851 00000 n 0000587003 00000 n 0000587155 00000 n 0000587308 00000 n 0000587461 00000 n 0000587613 00000 n 0000050537 00000 n 0000057327 00000 n 0000853373 00000 n 0000911658 00000 n 0000856277 00000 n 0000931499 00000 n 0000587780 00000 n 0000587813 00000 n 0000057349 00000 n 0000143881 00000 n 0000588008 00000 n 0000591207 00000 n 0000851003 00000 n 0000850017 00000 n 0000853030 00000 n 0000591243 00000 n 0000591278 00000 n 0000591311 00000 n 0000591438 00000 n 0000591591 00000 n 0000591743 00000 n 0000591896 00000 n 0000143904 00000 n 0000148633 00000 n 0000592047 00000 n 0000592080 00000 n 0000592227 00000 n 0000482552 00000 n 0000592379 00000 n 0000592532 00000 n 0000592685 00000 n 0000592837 00000 n 0000592990 00000 n 0000593143 00000 n 0000593295 00000 n 0000593448 00000 n 0000593600 00000 n 0000593752 00000 n 0000593903 00000 n 0000594054 00000 n 0000482847 00000 n 0000148655 00000 n 0000165939 00000 n 0000594204 00000 n 0000594239 00000 n 0000594272 00000 n 0000594421 00000 n 0000594573 00000 n 0000594726 00000 n 0000594879 00000 n 0000595031 00000 n 0000595183 00000 n 0000595336 00000 n 0000595489 00000 n 0000595642 00000 n 0000595795 00000 n 0000483138 00000 n 0000595947 00000 n 0000596096 00000 n 0000596247 00000 n 0000596399 00000 n 0000596551 00000 n 0000483373 00000 n 0000165962 00000 n 0000173355 00000 n 0000596703 00000 n 0000596736 00000 n 0000596835 00000 n 0000596987 00000 n 0000597138 00000 n 0000483612 00000 n 0000845424 00000 n 0000173377 00000 n 0000178194 00000 n 0000845368 00000 n 0000633970 00000 n 0000602233 00000 n 0000598460 00000 n 0000597397 00000 n 0000597290 00000 n 0000597323 00000 n 0000669039 00000 n 0000669177 00000 n 0000178216 00000 n 0000186890 00000 n 0000680076 00000 n 0000669444 00000 n 0000669328 00000 n 0000669363 00000 n 0000669396 00000 n 0000687059 00000 n 0000687210 00000 n 0000186912 00000 n 0000213304 00000 n 0000845850 00000 n 0000687463 00000 n 0000687360 00000 n 0000687395 00000 n 0000687428 00000 n 0000709270 00000 n 0000709423 00000 n 0000709574 00000 n 0000709726 00000 n 0000709879 00000 n 0000710032 00000 n 0000710185 00000 n 0000710337 00000 n 0000710489 00000 n 0000710641 00000 n 0000710793 00000 n 0000710946 00000 n 0000711099 00000 n 0000711250 00000 n 0000711402 00000 n 0000711555 00000 n 0000711708 00000 n 0000711861 00000 n 0000712012 00000 n 0000213327 00000 n 0000222281 00000 n 0000712164 00000 n 0000712197 00000 n 0000712331 00000 n 0000712484 00000 n 0000712637 00000 n 0000712790 00000 n 0000712942 00000 n 0000713095 00000 n 0000713248 00000 n 0000713401 00000 n 0000713554 00000 n 0000713705 00000 n 0000713856 00000 n 0000714004 00000 n 0000714154 00000 n 0000222303 00000 n 0000229908 00000 n 0000714304 00000 n 0000714337 00000 n 0000714599 00000 n 0000484424 00000 n 0000714751 00000 n 0000714902 00000 n 0000715055 00000 n 0000715208 00000 n 0000715361 00000 n 0000715514 00000 n 0000229930 00000 n 0000236426 00000 n 0000852872 00000 n 0000910351 00000 n 0000715665 00000 n 0000715698 00000 n 0000484651 00000 n 0000236448 00000 n 0000239675 00000 n 0000715910 00000 n 0000715943 00000 n 0000716053 00000 n 0000485008 00000 n 0000716204 00000 n 0000716357 00000 n 0000239697 00000 n 0000245244 00000 n 0000716509 00000 n 0000716542 00000 n 0000245266 00000 n 0000333856 00000 n 0000716717 00000 n 0000716752 00000 n 0000716785 00000 n 0000716879 00000 n 0000717030 00000 n 0000333879 00000 n 0000339932 00000 n 0000717182 00000 n 0000717215 00000 n 0000717377 00000 n 0000485377 00000 n 0000717528 00000 n 0000717679 00000 n 0000485874 00000 n 0000717830 00000 n 0000717982 00000 n 0000718134 00000 n 0000718285 00000 n 0000718437 00000 n 0000339954 00000 n 0000357564 00000 n 0000718588 00000 n 0000718623 00000 n 0000718656 00000 n 0000718768 00000 n 0000718919 00000 n 0000719071 00000 n 0000719221 00000 n 0000486077 00000 n 0000719372 00000 n 0000719521 00000 n 0000719674 00000 n 0000719827 00000 n 0000719980 00000 n 0000357587 00000 n 0000366154 00000 n 0000720132 00000 n 0000720165 00000 n 0000366176 00000 n 0000370180 00000 n 0000788998 00000 n 0000720382 00000 n 0000720301 00000 n 0000720334 00000 n 0000833606 00000 n 0000833731 00000 n 0000370202 00000 n 0000447668 00000 n 0000833882 00000 n 0000833917 00000 n 0000833950 00000 n 0000834044 00000 n 0000834195 00000 n 0000834345 00000 n 0000834497 00000 n 0000834649 00000 n 0000834801 00000 n 0000834952 00000 n 0000835104 00000 n 0000835257 00000 n 0000835410 00000 n 0000835563 00000 n 0000835715 00000 n 0000835866 00000 n 0000836019 00000 n 0000836171 00000 n 0000836324 00000 n 0000836477 00000 n 0000836630 00000 n 0000836781 00000 n 0000836934 00000 n 0000837087 00000 n 0000837240 00000 n 0000837392 00000 n 0000837543 00000 n 0000837695 00000 n 0000837847 00000 n 0000838000 00000 n 0000838153 00000 n 0000838306 00000 n 0000838458 00000 n 0000447691 00000 n 0000456352 00000 n 0000838610 00000 n 0000838643 00000 n 0000838755 00000 n 0000838927 00000 n 0000839099 00000 n 0000839285 00000 n 0000839464 00000 n 0000839642 00000 n 0000839824 00000 n 0000840034 00000 n 0000840243 00000 n 0000840422 00000 n 0000840601 00000 n 0000840785 00000 n 0000840968 00000 n 0000456374 00000 n 0000463062 00000 n 0000850708 00000 n 0000899050 00000 n 0000845494 00000 n 0000857345 00000 n 0000841146 00000 n 0000841179 00000 n 0000841315 00000 n 0000841494 00000 n 0000841681 00000 n 0000841866 00000 n 0000842051 00000 n 0000842230 00000 n 0000842408 00000 n 0000463084 00000 n 0000470349 00000 n 0000842599 00000 n 0000842632 00000 n 0000842757 00000 n 0000842946 00000 n 0000843131 00000 n 0000843315 00000 n 0000843500 00000 n 0000843682 00000 n 0000843862 00000 n 0000844033 00000 n 0000844200 00000 n 0000844378 00000 n 0000470371 00000 n 0000477436 00000 n 0000844555 00000 n 0000844588 00000 n 0000844713 00000 n 0000844893 00000 n 0000845068 00000 n 0000477458 00000 n 0000480025 00000 n 0000845247 00000 n 0000845280 00000 n 0000857634 00000 n 0000861495 00000 n 0000862412 00000 n 0000863602 00000 n 0000867319 00000 n 0000873587 00000 n 0000874540 00000 n 0000878187 00000 n 0000879015 00000 n 0000882449 00000 n 0000884567 00000 n 0000891813 00000 n 0000899307 00000 n 0000901057 00000 n 0000903372 00000 n 0000908284 00000 n 0000910577 00000 n 0000911210 00000 n 0000911929 00000 n 0000914476 00000 n 0000915573 00000 n 0000917262 00000 n 0000918633 00000 n 0000927801 00000 n 0000931712 00000 n 0000932351 00000 n 0000933103 00000 n 0000846179 00000 n 0000846473 00000 n 0000847656 00000 n 0000848711 00000 n 0000849685 00000 n 0000849786 00000 n 0000850121 00000 n 0000851086 00000 n 0000851145 00000 n 0000851837 00000 n 0000852423 00000 n 0000853110 00000 n 0000854266 00000 n 0000854447 00000 n 0000855024 00000 n 0000855701 00000 n 0000856581 00000 n 0000857065 00000 n 0000935175 00000 n trailer << /Size 552 /Root 1 0 R /Info 2 0 R /ID [<38345C84968559D1364269A5F0B3F5C0><38345C84968559D1364269A5F0B3F5C0>] >> startxref 937150 %%EOF spam/inst/doc/spam.pdf0000644000176200001440000123522713574431374014416 0ustar liggesusers%PDF-1.5 % 56 0 obj << /Length 2130 /Filter /FlateDecode >> stream xX[o6~<,dͶu CeTq~}CRxYbâ8<߹;&7&,&I*dVBzO0XuX*.Ӳ]/eݰpH1)͓TLjaxv[4"-xY&~a/횲k}G$3۹^Ʌ] $OfJgRrr,Z1 kJ Ɇ"f2#AQxgAB,VʻPM@îl<@d.!hr9y4U̠HsSz&ޕU-ǾZ9䅅);U-]].LH( (&(y՟HU#atpN>6b˂ڷ]#ْv1Zmgg!";R)̱ZǕ A\I,HR)V6~^<-Z!hڛtm>W#)[, {hkIyI/EyZget,{upcOjK0;\7U;# Ao8-86զM4%?oC?-K3-P1pR`0UD$` vad@ l"8%8"@xn¯ޟvL4QUEZ}V(]XQ/*k:1h>P~"=ٔY0.'e3Hr[we]}"juu O5AfxNnt}JhInֹq+ [a4v9T-(aR& Ҋ=,8fk׵0< V5". .8D]w /V̱8,ckG=NG* FQ&(8Ș f(a*1aߐ%vaoafدhj890u11G= C4S党̩;6V΅"W>wO7l@~$P0aԉʹFǓ= nm !W{P|䳕oWi Ptg80ؙ* Oޑ0ܻH-.m:`A7NqdG2~;,{R > CQmnZG:\ f#H~lZ'bP*n*ԟjE\oeS%#}A5bknXfcFChVzjUyo,عg|~Z"\c0T<M<5Ҧ8»)RM ]\ze&,a袸 |MʞH`V9S`Bl&?زƕ1m)\*hjXiFDp}*!NL*C}|FԇEI+ʺ!׫Wj3iLr7c?]R/~YN ? Ea5Yq_MQ ʘ B')v _2PpaMA_#B R}@f3Wa#bC9eYQOu/gP_x~ƭFyj> stream xYMo6W( oIECzm 䠵DcP9;%pyb0ndv Ihb!98U LFd2#_XvJ)ia Sc.܃ Rx/g 6͇[L-ϋgߜ~*˗yץV'ꩵY#*tlh{^jK: 8@'b1.6Dn3Z(<1N~Ye-Zj,-mcEz 4exͤ?d->۽Tn`cAN69@|ޤ7nD.5]rQO*z:m2h󒵩^6̓fhQsq\_8okA k6^jYfeȽ|@Q}ՙS{yQdB@"&^"toeUzOiߗ+o^F'ppF+{UwaG5KHh Oّ endstream endobj 93 0 obj << /Length 3387 /Filter /FlateDecode >> stream xڭZݓ۶_>7L'鴝־LM$ϗEt$ˉbt[o^_RJMVw\rTmo6R*\56fs9VwjwV(3!T0JWUVXT==e;Fl;"jQeD%I "LbYf׹-U8ҤqnjMo6LxQvX1 mۇ;V#/Ǝ}?uСͬH<*R<0$w#i3  +| raY2y{>57}:oT쁌Dk10KshTOޭ>Lւ6} mZY**Ofcdwn` 'wLyxxcw$5|vsAd4u|- ,޷^'y e ݉j3> ГJ~Hm宪Lh I}֧-CHuO_I*E!%5z0?qqay҉װ#52B b;Q4*(œBbfg ǜ(s;1[$H= ꀪr6hb&D _!4E̟| 5}l'x!5@v R(8d`zOS;.iXe KClLC-7nC8: "=B&3)v +HQ W=~c :Lƪi=ߘRHg%~^EᙔvA r>. p>6[ʰ̎ZC0)%tmDEDJ >' ua~D!`!l_w~ą<=<-*Z6tR=}BѝZ$Xf Klh[$DOٲL2Qu4pxދy4'/*=q⪥q T Klv& A4y8$~82umo{|p?1l\W1>2{rg̭ȅ4z??tAqrQJÚv* xTGB\p6R ? ;Pf$4*.,3/͙ k= O`\eXtIr D0|ƠOxի ד t9ϥ.D@rg֔NMu nօ*:هyرIWDyZ7r6Sm! R@5􇊪쨃ltn.Wt4|$;ܦcxldӷrBjO!5 Bg.e)Q|%ufSmwgVW'ϲtr":t s>{s}UGq[wžEy&A ŤGIsd0H;"Z,ŹI{c)IJ6G(b : ]1icMm K?(zj㡬RN#rՐ\!"\,Idw|#1[[ V?7&$VoA%/еjP\8f<]t2`qtG#"wѲa.a2swɡ#٨䌰 q(GC_]2l30 ac`:dyӟ/@nnW [] e]oc[݀t#Z~')%LKơϹP؞yb.ؽs4m8ac %%W֮.O}㋨ R uw6vU^bU@aUVw/k ݵY]},IH@1dx̪W @wl[pk5=w'cwC &@V4 )ߎDjz͘艉`3&/=whL.|jgO aAeY7\"Sa2ynAW&cMEFe\ 7A|V.9 *?g.ۢk )< 4žUM& U@қ endstream endobj 103 0 obj << /Length 2884 /Filter /FlateDecode >> stream xZݏ ߿HQD '/}Т4WHRn>\A+˶zH%g8+yc)ڼF!!# EE,֋gY}zT\p3\EÃs&_ WɂűZb}ӧ8K)y37<"ei$zEFfxlú}|}7u<"R1 c`mI~uhWNg$J̀ܲBGV Cbͼ@a"9fI,bRVr~|g>W宨+E2/we#uXb)}ʛR$IhLg)->ߟWQS3R&Q-^czHdW\x!S}힔 z;Ncn r ނ x{xX##a`C=RjșҤ՟e) %&&7K$7*<+ӈ75xw@udrd6@I +K=Jf;枻=X+;o#:2x1 I4W~9?o, #lUv*^\+P(qzjҾ̓L U6`H0+ic5i%!ͶAӹ#^Mf?&/9MUЂ=!MFao"7G|^nHpJ5цN-C.5vt2rGܪxh]YR+5^J&&;5܎+/F4[i`b"uϵd)%Tɞy|qTo/u Hq0a*,Jt6;>L/k&25q+1|e%S_iug춺wXFTؙe-o,mLdB4QrQ2vFŀ>ؠ=#CTt]Q쨏 !k2+ ܩkCϮ,m!g :8:A^IFXBy;mwyD6Q>Cx.T3sv6Y!`Gl[Tui"wh)zie㖓H:U~D KQT6>.vN1ðxwdc}S23:Wչ~BmiV5m2WRYщ b̕}~^FC= oӪI5l.jMqڐY1B t-!@_?7KʟM^˺Z;~yg=;䮑C444OQkZyD#c!9F}5X຦.s )YGH:D Yz]du@CN~q]yᨧYwNRqm ,X/BƵC*_ O $ PA"dXqTNkv$fi4nW@]M(1!f hSq4ږ`&鎇ᆲYyeWx%!Cu!vTuԡT:OzM` >sPG#pn 8n"S" E* 8[0/*HiēzT!D#~I|6Vn&Ƒ/ZAjϜ<>|~TGnVbAkK7GormuΝ~J.u2&7{Uط<&mc:c3b03(k#cEb…gH]]$cu?3FhR"1JzoO m~[(m=WR9L8O?01 /#I %2!C+`Fj}h(v? S Pn. qA endstream endobj 111 0 obj << /Length 2282 /Filter /FlateDecode >> stream xYݏܶB@@DRG4='Z$*čwCi%y?! r+ř yU0oq/ ͪ+\8pswu}+/ei$"i D(Jʿ-6&_d"}]hJL1-HGX$v>H{ ]SdyPnyK1ᅠʻ@] YWCyH0L;|6E(]ﳜ{9aY^unMo^gi(*'`HF>I!jf DʝM}7$3循[z9m;m{,TԎ󶇐2"4ZO*&'Fd 9meS>҇ _5pq""gB2% ?p7YHEK_-)TK!V?<sHqEetwDjuy%S'!QS_38 YG#418a1'|s)RLq4E=WzJzi}QxOw}{Hz/uC-lGQҿqh!(E$Ra @" ",#.7+,ߐSA8<)@׀cR}캢%QLC1aF=8.$`wxo$k.,le^9_gHT:ǵX(1x݀m-I.Iw[SV- G3Kw5lw̹e;C1}(5yNh)r,"l gP%?]Q] /]ˢ~kqbm~Nh* &I2q.| D}-}lg28#WTlD41CTvaCQyx+)-44fsOnXŅ1GHTL% hM;};;brd@AhG엢shtyUhx23<$tb vlBw0rw=]Tvo(Mwb Xuq.]Nb|p xjy$ƪX;ڹRZt]׹9BueGb]Qͪ,ѧbkl w2]޷mʱ%KD(kn~tԊ4Qj$O"T? gqp`|t7R 2ʊxIM/:0:0|V͉rX.*WTC i7yf3w8u(CQRZ*x@Gr"XF=|̔i;oɪʋ]θ Nl%ԫhfr\R߸BS>:wqn?%wƵ=F?be; us>))V\rn`g˽m1$jsl;ӨC:lA *FQDx-i;7Rbv5=66a"yjɺ1Lxx#2S>=r 7>r8 FÆeo $:l-/h33U fsۣ}FVv,}NY>!P":k Ft.nz?loN(G" z:+wy+Xԛ7 Gv epSp:C0N P(|r|#5Me2bxS8<׳_V+/A,X A:FSϧ^  Ɔ7ˑ2dsIL\Z F@…z`?& endstream endobj 99 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (./spam_files/figure-latex/disp6-1.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 113 0 R /BBox [0 0 459 218] /Resources << /XObject << /Im1 114 0 R >>/ProcSet [ /PDF ] >> /Length 35 /Filter /FlateDecode >> stream x+2T0BC] 2WH5Tp Z endstream endobj 114 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (./spam_files/figure-latex/disp6-1.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 115 0 R /BBox [ 0 0 468 324] /Resources << /ProcSet [/PDF/Text] /Font << /F2 116 0 R >> /ExtGState << >> /ColorSpace << /sRGB 117 0 R >> >> /Length 26050 /Filter /FlateDecode >> stream xK.Kn=?b"ۀOA؂%uvTmzbefdd\Vp_??ʯk,??/ǿw_`~?}*ϵ_m׽~??>৫O7ze~/o?~~~_L=]ɗMV?~n0K7ߟcϱZԧHAEߴ>}9{/://y@W~~Q~_ꏿ~kzQ?3~2znO}~M_m'>gh~3Kz WW۟gn}\<pu9sO{?dXǟ]?faǟjЗ,ڞ*^MwO؞3]sb?9׿]6w);S_/ֿ1iוXyr]ϯկly]9d "{x53ݠtx5cawƳAݯ#c{(ލcݝ`9خ+Pu~+yte_^y7&}jP{TWA{Zn_zgU'ݠg_2ֻA{>2wyPԞ5{= U |LhFWߚcz` eOfy +kqCѷ捆u_0Aʳ+up㸗WLCz~5N6_TA=ގow=H*1x5?kǶFXުOi7VhP{; zJv|{h{edϚN(w׈>x7WMwak|u˛Cvvj_=W|aL=y+ePw nг縗㞼37^YG;4:wvgmۇnШ{ڽ\oL\Z#4=Ta(>Xp ł >Lgy `_v+ϪYVXP8p?2 zX `>70ޫ&&Ϧuyg+MFXކfAi|vޭNA7vXMcTb?#,o|sU'ADe4"^5X;L w|Cmԩ6yքg'+>!l@n(UF&pݠ΍Ww7Av{u57M@,a7w{t o '4陟UnSYjnK1ހ-a2a6c_q=WVqLF&.M&a d`6y`tFl=w}&RaРڍt7ހ?CWM7 ol} {ppVbq#n}zp;2~=ols{M4se&g7=&>yF8=F]'p?#!"=:avn ۃ|tnEwҕ7/ϖN3p9Ou<`%g{a89S?F&{V'`gUnli$wb"ǹFx&8pWKPyk``p9A݈0ހw߆>՘u }h.] @? xnVwu6F&G$g3N #`Lg6I9 aMj2 7ޫ}MV'3::3Lg3vzo Ѵ =R7~Y*W2] 3^[@0 G\;g4Yx Z:eDRNؤmNgĻ ȍH' v&tr:{0x;\@蛫A| 8kGo'X;ާҝw G|k:`*ݫq_l:DT6 eXKDexLF&S:q #a#DύMِFo9G2+R'@1n9?9,^MPXkp } Uu8th* M!^ZMn_M;439ˆDe_ HT>{v,oHTn1J?&w4&xog͘F'W#ACF`Kӑە!!Y2bj҈;V#g6O#]6W#|6yvdդi'ңFAMN"DeO04XJODm eCJp>7zkv*OD%}Jہ #9 G_δA7h}uaw/E^ 1Xx'δoԪJw u&o;'/=KlE-`BWX0 :<.~҉E >9 nw 025~V)#8sA7v/lUp?Q'^QΆ6[$*1ULK"*j]@MƻAϒ=ol:T-#8M&nr8W|:<aC@?C0C@}F NЛH{QdTk}j8NDep26i +UNώDO5Ɍ^'2Nt&ڑF _jFX>Kg M7bCOF O,R~"&F:=p{'ˍxZipϾpXRE ]3{imd]FK]@D#QvێD#㽚x Z 9cDTz`H|l"*]} G^"XZ ^ՠp9>b훜cF 3F - ?< p{P\ѕ <ѩaND.&5b{cN`:̥69p#pC~2 lG"giC.Xi{3 3Z_Ⱦ+/ܾ]y `K&܍CU;^ND=QaJSlV'25Z&ϫ=TGGV $Bu[p ݠOb G]I;G$kj-8EN5g$FXL{kIE=z6gD6ؑؽ-#a !Gt] ؤ-R3<}3bu#nUs @aG&@!cj_ud #6(;"P mbIKop/;[qo~l8DT:Tw#QHT#ҧ`!$*m8X"|6U*S1nm{(xލh5:a;9[ٝ5NhCgni) OM=;hNDHK_3?n ēZ&ej/C1AFd+̍pAF6񍜁ȸady7F@;3)2pjf7rz#g`;o.:5:*ľ[pJO ' ]I ?@}l&łDT:d>&0 >IQh??si3LYeFf:Es7BI׹p# jkFXo#ڍX?0=knU-`g[66M$$*+:I19rb!p w"kI"*;9t[pz&z]g$S~߯+M;9uTdX120O:%]%xK#88{-$*=!MX6 &Ok(Mx Q(U@m 6vު>9R%gѵ4,Cv<n?&EkhܖgTTp)X020wd0BZp}D D}̮%ʞ JG]M1ܽ6qd 8PdD8#3p2^aSLOFW}U o(MXlL)J+ |nbDdFD/7"*k^FD$l*nl ,F393&LJύ p)VI;]E} @kW! ng^qmSqµƻAG^v(2djw)]aYaG:Pr*d,)#`=DD?ay+ҡ"2RpZ766 .jMNmSd`E7ހ;4b"m3pTo~2pv雴M^ޯ{RdifoLũ{^% OCQlHTb6$*6G *4ވtlr"dXw;IsR=b&4& aII9Fo"fM4&Fnw_FM$]) ʓ:+'DQ鷭>rw 6YRiHT&89Xd&px<'@ʫg[6_SP:Kn.8p{8@cէ]ȈC ]DʃMFD#+T}OpGk#ҹxpi5"*SQ9WIr#E*Ѥ k#;Sd`U¸ >7!QH۴tr>wH@ndjuۢDmM{"*zN&!G|ѕ&' 7fW6yJ3olKMW$)Mv";8KTCȾGZ1R%p: FtoUTi}P2(2>v<ѷwQmC(ǢQ8>HTDQDeBRDTv-#n$rE4ECJH%Jgo҄Z{;}*j$ToE۴i*&&#ism&$*[ HTnKUcJ'I!Q#Kl2YߐVr;F4aDH[7=Fiy+Cv<]ZRfYx*Fw#66{ +wQ͟|݈DeБHTZ#<JQ82f`BiEy3P"fu&ͩJ%H=FvujܫoRX־B{эľ/#F; }21}E+w!"*}zO"*ߐ];ӖF䇰1kOtDe F*h93p+ύZ;`ڀ)n{ZE ̍-0.w$r}KrŸuP@FDe*gRaDFD­5*@T /ݠlfb뭔l3+6EQdԕcF*  W^;bIH"*2ʉmCs~Bz4J>xTv!QY{%8KhzE3ZKi" .tFU}6E3pQTI04VJT~ >Yd6Hs#DZeDxA7L% eDn-ܵh$+ "j2rw@Hta% ƻAl2G[(U"7.OY3og eWG6RpMܪ+fޱeOfm33X%' ӫAFC طIDTFNIX FD+A3P^0Md1Q;t&CQ3Qى}7ӹK[03J`Kņ ['g`]v$}+2R*r܈]&qei 2aTx"*C RΌ!Q٫:JfaySk TEk(]47QRQ-HT #&&QjU&cT4J*F** +̍pZV\6ඁ*]dUb߭?ThZj*l*>] @x7hBr)QӐ-8[}Opu*E#]G ~2 T^,) ( 9`*ʢY!=LPdwY!gJ!U `lXA}'D-ʘ-idQTkTǐ<* C(&,幬PdQX pےf`s"@{J'- V=( V7&꾪nLG71I`iśT$*+QMIiJ&DT#I'T"*CKOg`qErKʷn&1)Qʺ}SߓRq}޴`:ƁVZu3H\a'8Qu1Y=hnDi?E{2DTvM0IGnĊDPD IUTT%7FH. }葻GWRuad` u'8RE}KՄV ACJJ-⨐n]ľ(Fp@r +G}%2 $=#xpXܪ[[xW"j-8 #ȥX5&9h$LQ8]&,DEaѠ{Rp)^!7 p7i@CçnKv#[njD.AD$F,up~ `ߏ'ӕ&\:4?:hFXbKl'M!%JšDzb+>!ka,-oHT{W"*S%2&r69UǃN@_FXoo;ngvܹur#g`ˉX%ȫ:?tBwhAI#2m(wy?*?n dDTF Dq7Q)JDԩg`1EZcdnjpVSeцWPO&ߵު&)GҁנV.b+FAn r#ń*:]{5 \#z*]ңaijҫ@d3SaI6١Qdv0YPi1p/v#&.Wb Q5iWa8 U"*1 XyDeͳ`F30Ipoqe3K *F̣z`~u1LvVXNغS"iJE&qM#`^MCl3#4H c&Akh@n QQkP+ȍ12Pn—]We JtTk*NľhF+K0НmIDA!s+-ʢjJ?W- \p#9坔z3;H'GG nWוmi_Ù~0SӲ.v]4K(.-!Uq[#fՕg\ZpZ_J)"*#JO=䨈[!҉gr QȚH^J,҄ %QW)Mj[n#0G)Ot[pn)xkip{JDۄތE*]2=7$*?$*U ƍ_ʝJ\c "Q-\G/#lR[Ee3p(Oaa1{aDFhPӁpK{$g`Y0G[4ZUuZRL0Q"S.܍H6I[0܍.UV*K2fb SxM$N.T!}!񲵀M]gCDe2{Rr;r#Hʛ=DT:T"(?DTO% %t"*#]D @UFJQDTZ!2@)9"*ݗz*TMXŘAM$nQ(rmIS3؆񉑁R?]t$]UM1Rd$Q$LUvn}psXo(mcXF J# }DTF֟I5ʞP88HT(=r#u:gcpN^Rq$.w,j 2L%m1Ñw3Ɂ[g|SWCDe UpAr!ң) dc2!+1k ҽz(TAWg0bE,Ɲwt)u^FNGn Et d"U`*) 炁DV DrϕvQ:DKHLT* QyriMz%PG!n* ,5ra4rNQd ӄuLv#|HD ;i`̾= MJ!ˠgf0!2u%`*ʭBJZq 5%y 5r#gaa!^? y4bOѩp}#=pw@8FU2RҼru݈lS]U0Q9b6 E ^ʞFY =HTV89U 梨f}n# r8y#׸mmI[ {.N%nJؠg ቨ#S)gϘJ- L!gAkgEa0$*!2u$9MxTOYI{ª}[}>u)jT{[r*]&3p36%>FHi*Dw,*v:"*='>6M+!(!gCDMSSd܈+u2K}p>߳Jy$N(_yPX !@Xnd{Ppbϡ)G|:ϻ15! \-bk7G7U6QK} HTqʔhP"My3h>ˣŸ* zu}PWޡP%r MibU}L"*Xe]$7t6!&#`(MDeL!=WLFrMJo$* l$*  Mؤf`8?F!Uٛ@ޘ&,7)$6jnPbyS+}WIpc$rMHT:alREm"*#FI!pQ@3tq~ʦo#Q9Pb_ Rիㅩ#FhR{rϷ(^Q*Fhx+SC=;/{=rE==WpF]ұDT:MK&_ 6:l$*"7Brߤ .8)20@TFp>L̞ˣ= pw$=E%FVիPd*o^MœHTv6=S 7ME3XUMFrDT h$=8U@ыX*]ݧ'!zK$5P;AiMң{Hwyo Hq#4 #nSAU4Mg鶀M2~Q駎-8Jin"*{^7MDeH>7FXޔƫAYeo[5n*FT TOgh__ZU5rg3&H(Y" ]DTFN"2 T@Djʈ3>a"m-E ˈU}ig`掩҄ۯBdߓ)3T)#+W {(rrXwϢwB"JIW aʞlUZ@d$ReEY^^Ub ʪ9d͑yXUnLQ&tXwayS]yp7*<7UjJlQ7ȍ8қ&Ws ;C{n:d$0$2Hj"Q9T%`QRCFTAj-8ʢىDPJ 4&gS57t+T_J80zcGf~^)2,ω$B0g (7ӑ\ˣb/s}þ''Uv"QNʢؓJy%8M}vHTAIDeTm2VUkشgL$*'RUDTz؃JSfM2'Efٜ}T@DE˛bT͉qfs~S@d^ކ"UzOy$}(ҭn)>GDe2gI"Lh*a$R[JwE0QY{%a]sH΁$F*!_e_^oYO >ṢnZ)R4鳵=9*ŔŜʳ g`W9I+LQʮ$2҈q>1'ujDM4 'Ȇ ܳ; Xn78yPmg`qcvr6s3P/Hg'g<2'vF44u^ok}; [I*L&*s#} 28WQuf'QCVl2X(2p[|vDhg@l JƟ wS*9x%*}}OoǓ3o0'č&T|pAO$*3yQg^] ؤ5zZ{IVDT0 TDeM$*'M`7,mݠ]5}?5*YHN !lSq$K7+ivg}UfŊ}[P12PZ >?Y*FL-82_&Nj-`RlʸzI&L$*#DTi趠X;8; 2p܉x,xW"K{Y4a՟wW,^jk}gz? /30=Kd+4OP26r/ľ91:L&*^omB$a3}_EJ+GO@[tyZ I;Ȃ[B84 fɬDtyLR- VRsf~#*w]+ C}HTNHTmؤu6r "*m < 2b~ĺ*8FX޴͏q0MX!ZKg9ܫOqa߫Fnyu!cclEM[Ɛr~aQCFKZj>XFv&eQD)zl, $ zOpc3Pc3 _[;F@YJ|"xb\c_t5񔊣 e QY+HT7 "*=?@HT.qDʀ5 ?3M"TI݈MFrac!.hQ:S_"\./@(~Q[G$*RgejA8c30"cR*NR٘ RIN11XD7wo23p[β@Hs:90G)c$:c3I#4eo3}7eQTLPRkI3P@Ms?W`trvF@JJo'.Ҝ2kʡLHTWt+1M8@.sɈZ㑨nʨ RADU82:9f{a* 4ԍޘ 0wǂ0G=>7خ4>I8}>ShسZ gܾ^҄7TV-7S: 2$4; $*Sh QukF#l2,(2U 2hFdFC]=CãwW0ib ad6a : &CU9qij-k'C2UqoJu"*=.o * ADeH@y> ӄ76 +0GKpE +p7Ad+4 8M2c5 +n?Ĺ"lAD{ѷHTz%=QADlB6̗U T^ tG~Jޘ>-{|&}ЂQpjzS%"1*j*KR=ǽJ;P}jnDe c$2JwTMX7ʨQY/8\%2(lP!g`֋p#**`brNyG!g`Qy וc_F[$g"7r^*U*fSFG r߇E;yC'Ev"*DDTzk}HTfnG,҉C^Y, "~aa3p+IU{Y?sA?1uUPuykR~*`>:MdwgR[ʮ|ND-@5} lp-1ʖ*ʐVkIX1q^#8+XL&ۑ4-}۞px,o A"İSa \0nUFֿuQh˛E7HiDzD]FТQR1Q*]FX޴v"*ʣIDNʖND쩎g`Pc$nǹS@ J1LOc.RwS>"݈3&#U3o[5IF0KQ(2jmE*9Q雎$ؑdNDg7N'`@>X)'tq#4HܦLÕF<߈t;vw*`@ɓZ' jo'Az\i$%M]'2~{ #Qң*0ݙdQ'Il-`&ԑluW؍"8ЀmW[n*G}N$9 D}Og>*29 FSFXDZ=:g]Ͼtow} HQ+DTLkDTz:tӕMrf:Ujʖiʌ|D_o ^6F*pi,w@=Jd?0kRqƳZW#QJSgVDeDQ:dDʖRni"D+(Wp:Vt[E:"nM'{EgRFS#+-a^ poWJJ{@r#4"_SXWʖ5:YRւ]v㌋^"3h$NDǽH|S/B@Sؠe^U B85{yR.^(ZݳH[2iFؑ$^Չt-gRdpd'ҏU@҉lّDTiY&ޠ LnWVv)!0?gb'%E6YKiܦ0}ס#f;ӤȖ^{5iz&ڞn\L_ígfʐ ag`QXi##8L_&Oa#'o0҄g`moA*7mI[ Hlmc>FnM=҄ p7n)1JiDTZK9y3tdmHTFD{?b2Q{1y p64$*]T}*Ӑ:IUg^L6iNˊVu#0qc'c6}7ٹnPUXR„ۤ4"aT2=wҪAXnHTGo߈lYި!Qi1hDTF=@="MDvCTRm6#D6Am"rX@-/}*'E?bS3—4a94@@Uqrh&fQr?Fv4bʚ Jw@n1T1D{Ј F&wF _FTQ&MV|O{{+EōEΊA-mֿ) `}tp#Lun3QG/'I(QB^> \ FD; kդb#22_ޔw7B0MXZ"#و}Oƹ5 ӓ.?A6&?{(o#}T5U(>M8.r> hDT:4*&R6$*P|&2(>{6*SFlb1i*>(y3LRU;6t#]Ĝ7iad ]5@[8b@Ζ4$*SJ!Q9݈twӕFD } *P##QlFiMeEažrJ؍TX ndۖnP"Vp=F`UhUt*tUrfdw# !B-*PИd[ʥqKD= =ddM|f 8mՄ @SDM4cjK;oŊ} srXow30]GBg$ zoQ [xnD˔C` ʚ.="*[4"*=کI,tRkXL -XOQ+hJ4i 3P?&̾Y 8x黕 VA"r!_GVi!T`I>FDևQ(ՏFDeԔ0,=SYDeؐ|hK;pCURxfv2v`ȈJXM?a5C7B[AAޔԯWAz!QiBƆDV[ JSYcRsCW`DTzm҄9FXM 6F5ƻtg3PͶb y6Cz>23೵:_KG"xpVS sTi7 r9h=4PPC!Q9mHTn/^mDT6 #8Bla\n金u{8#[Ÿdg)TefP-MʹE, _sДv#r$F'{B'# jJ6)R^0$*W+3vLgHTHHTv7N*`#|!=!MX?m"Fw#&9L#9EO˱OrMs"ͷ<6}:[$FDe[u<8z `#;kAd`U̯Q, aJq lTƍ%s3ФFM}1lڶ'={`>I g`U̯ Th ,Uq.f{R>enHTnL3"*+0{<Ʃq5W!lt#ҧ`|q#x JFx3tBFpu::{%`JZ|" Qa pgnur)YaNlnHTvD aJ}2"*c4B ^yɒ!QiFKRu hh8(-w]t|~8HAxٝ( kt~H!h-W] {.$.OUZQRӈt䐑iDTjLTPUJ [pok}?5 lR]8-w QdD컔!}O3*!MXU=CÏˣfCxx9-|5DTFsJN{$*FD' e-!Q9`Xm]'tA ,#oFEanD8u.04eDu[p~*%LF8X"[DD|&Det'/DeN#ׄ6*6jHT*҄=XOLUrfc}][Qaַ}ouTJvI1 .~܍;G̊y 鉨SDzZԷr#DB~|GD#t[FDe>MYRTY֏-+ {ߓRqt.!) fC6Րq# Mݖc!(PXľ  #KGΦ!Q+V[n%`EF&KJDJd.z( H-OzX{5J>|n`NE׃XEvQ|S"pkM3sZ a~aV"*C{m5JnW$*SOQ'ےf:+[o[ #W4iYb&21V}57'Se}pE_FDoC{iG]yn)"Q9E[I$.r˛b14b0ٷ-KU}RK)"QY{[JZJ>&UQ]ʮIRLDeʘU$**F&Z)F铁3u }35`S}NMʣ 2&: pIem5&D-Nb߳<}~.5rU$*ΖJQH*FnQWɎ'lQ%ee%lҵIEuHD* :p 6׉[B8tܨ?섁t#y8S ܪE3sIUTȾ+ԼQȸ뙤X)GE9/ݖrT"*Clj W!2ʊdu g`U=t7H"ݒq#&:p#]se ֹ CYR*Ny_rkNJ} ש|".W6с"QUF&DTHDR*N0Bd`nsoU;9~$nŴe8H±v ̓k@9UjG]Yk'uLς*[y[ " pvn%DC)^cm>$*HDeӮZ%#8%Y0JU"*C3PWf8P3PA<3pJb6rGSg^5&鼻۷[}d}Up?äkT6[.ThE2+:V&*:\T *#&YiĬ8]1QH5L֡'O`j \fώ$y0r)U#})w9S:EX"34AQvm!'l*5W&*NDe,eTV"*x4aK#+MJgIbW& (P8^+V@5ZW3hΈRl&j!k_0*tK<]s%w' rV"*=+=dNDT:[j-QENJDe%{6Rr#Z(E- y, 'gBZ|(ߤ:'W,]wyr#D f-OraPd(hr(JC}.]ZG)iJwu-=U1Qɾ>&* tY:IޯD\ok*DT ,b􊉀DTC$2=锃Մ5>Lg˔Rݲ}xQ<Do*ƻAE(&g`U6tk1.DTF!@] $ $*) *MW6qٔF&\ -l pl T҇8yiEqeNT R[w#P }W6Ue>0d ," e3pt#|2[$*Y!ҙ6Y) QWBD; z"BDL=Eޏ(2Ѓ !+ +),, "T$Y:3~:"z e3pÄ+5)hq#o U aF&)AU K " \"*#K"[LD4Dl"Lrv-eb*N;EZˑM"*Sx}p>Rq$}Y&96묊{wHw1ZJw#35W<ѻQŵMF8z)/QG!$*L$*h^d|&<$XQL \xP<>s$neeA+U4 &ȣ2§ $gg~傎@vp#`uy!0iBT/HTE$*M>ƂDe%S읂DeUW!2ʑ&8)M#W::Utrnj#Gb nDj!&o'e2^oz -#t p8{N{Gu|OSgTBD/rq3_ A#aA2Uq D)#.o=w%&w#sojnEJ~v_.5 5ZF F-Fdct#H** +ɡ~(*6Iގ"BD?3 9WCxv8J#gǦjfK}U4#g1VVh1 ꝟ q1n @Tpˉ] Eu("^C-B Q9U QNli6Jv"*xJ$*gy i*:]Sb /?v5YϿ/ݿ}׿_?a@?= gKo9jqPQ c|5{].Ɏ.o]1G]6b:V~/z1& _E$_GߍMϯ=m= WVCs}|_>f~/& endstream endobj 119 0 obj << /Alternate /DeviceRGB /N 3 /Length 2596 /Filter /FlateDecode >> stream xwTSϽ7PkhRH H.*1 J"6DTpDQ2(C"QDqpId߼y͛~kg}ֺLX Xňg` lpBF|،l *?Y"1P\8=W%Oɘ4M0J"Y2Vs,[|e92<se'9`2&ctI@o|N6(.sSdl-c(2-yH_/XZ.$&\SM07#1ؙYrfYym";8980m-m(]v^DW~ emi]P`/u}q|^R,g+\Kk)/C_|Rax8t1C^7nfzDp 柇u$/ED˦L L[B@ٹЖX!@~(* {d+} G͋љς}WL$cGD2QZ4 E@@A(q`1D `'u46ptc48.`R0) @Rt CXCP%CBH@Rf[(t CQhz#0 Zl`O828.p|O×X ?:0FBx$ !i@ڐH[EE1PL ⢖V6QP>U(j MFkt,:.FW8c1L&ӎ9ƌaX: rbl1 {{{;}#tp8_\8"Ey.,X%%Gщ1-9ҀKl.oo/O$&'=JvMޞxǥ{=Vs\x ‰N柜>ucKz=s/ol|ϝ?y ^d]ps~:;/;]7|WpQoH!ɻVsnYs}ҽ~4] =>=:`;cܱ'?e~!ańD#G&}'/?^xI֓?+\wx20;5\ӯ_etWf^Qs-mw3+?~O~ endstream endobj 134 0 obj << /Length 3952 /Filter /FlateDecode >> stream xڵZY۸~PU©aJRI&ʃęaכOA 7O8}|`_o'W|Źe\Xmv)K_'MJ}gf3-$$bӿRRɰ)k[fjճϾŪdfneJsŔ)W7ֲPͫ?} 7\…`(v0[l|w#f[+ Z٦z}uxɜ]5OHSڈ.JD ^'i據w| Ǫm~j^Ztmkݝ0R`]s`SܰnzueVm6]m B@mD:+ PMq=q_AzOPá'w!m%ط A=UB*QFLAЭ7U B(lRWkvBY|ZrVX>_'x&Rv@OB4/+/29*~l9s {ZwXFشs'uk9|OJgQ2sH(m>1M`K' ik= mPX5r\\vFq=Cڬa5 0Nq̕Wg^8e­ZphoibBX< aVЏOl@=ڣBAH3۪_!W#4S3JUdq{4j8 Jiq%*}hLBy+fWp1jTs6~Y/S_笀ވg ڂb/`S NtISéxI!BKR!ԒآC6[$~ғ--9dIҏAB^ 9p ۚLM!X# ۂS(`"E>JR cȃB4ٽv\ .ӈ (T@*R@ډ$:ʾ\|TLSEkT6h =e?Rkd8jz]t4hfq4hfX}ہsyn-n|ab\CDW$y_raJQrؑ<`5?Gr~@M8سxd!`X]ӶatvNE|׵-"#r yv;-a{|nб\0K f`L~Ro9wkKzG d9 9]ާ[XVQz a9dQ_C@QB3@ xjZ`5wi 'k5Z 77PK84C0\Ô9b! SojЄhnﺯ Voyty-\_~¡R\ll"A 3rv'9w(Ţ;e麋ˑouF @ Mq0WpDӬTaM=DF]Y}+Hr ˂f(AF_DCWY<~D Zt³څS'Lo_8: ?H#7pL;n}䘹 | # 7pXn٧n7P_ϼTqhf01-q Ֆv aϽ6\VkBIDa!`ӆ okBwuŮ"k>T558TYBe~=-ڒ@iAr HN3  d:&T緱S|N GXyW nۦXP#6USWȢKbP0[9]pP 1Jv w %&*UVz_XLwjW< )7^BXP'ЬB#Iq"Ʀ[ߘ+$f*UTm=Dx@ӎ͡ =;v%~AU}_Sq~sU%Ȕ_#6^@vO@X1J!m7?סޠ~/7:nk/07C,׃KHO`KV% $DHz( aQۆ=MD$3w ĮgI SD]%ᵇ|$'!0[\G|vAp` Wkr߸:Þ@S 덏'4O f863v 5/R)J4p~|N?<׼E5]z`K!9yU3H`̵ @^\݀͆~A:N6ε6зI-h)M[~l\̧pA/&$ =B|5?ݿcS|c?<"|P,1L6\+Rr(J/xf3$ ݧv3v1߰L=fsLnkHNf?Bx*QyS"'~] /QyR*Z,[ UEmF#ֱ`/vbѧTg.L{|.8(9D"opˌ^u> ;wڇW.Mk\ud9=x  ^z }}glIsK 9_e KgX^Jei )cv٠xT̑e!\LK&a8ǵI_tFѨ]J_b넡&=u̟}y'XbR+D($䎖#,~z||v8ͮIn|7W)y c|,Ya|3DJpwyy2oîzX!zK[.ɲpiAd;֥ QBl¶ym ɐʋOSnۡkO;1]م&DP>jC'gO)s*F~}@.!r6O?g$@x/<)~;"Q=AV ơ17p =TnĻ9dW[zbQuGOw|+DC-1d,?~4bJuqf6W N endstream endobj 121 0 obj << /Type /XObject /Subtype /Image /Width 398 /Height 381 /BitsPerComponent 8 /ColorSpace /DeviceGray /SMask 139 0 R /Length 3071 /Filter /FlateDecode >> stream xv( D:}I1巙Nm B*%oOO& I,Cŗò'fvWz0#Ƽ<` 3y q<ʤy @j˟A 04\RkEh6v?֡9Hv|0PȜ͢Wt?yFr0?/ cyU?m!R? cD!_GP"̣_v|@̢A2#N PY&EC8ˣsV~~5 Pp`˲k ^/q -o3#oܙAP({SzgIX$|/\aTiщ=M@;,xy'YE07J9]FשS:ahաMݳ$% dGLX_1fwR؍W9f&wx3Z4^0^#ﴭiR}bplZSsENɔ*d=M@ y0A5;Gy;:y!F{`hU]gF`79Ɵj7|)Ʊ]du]Ø0shmQ8Ftϥ>A_vtT4Oz듍nhy4NC<;!6 OK-4*/밤=&Q%F=L47o|Id~I䧁4n*Fߜ|CwFQΣ>O;7Ish hyۛFiR4`}#캱w,QlR ۛ{M0ýK (Kˊh $DJ|}a|,DYH'^vgp@y{Bj8 C4`=tT 5Ge`xP 6c}*! HTzкy6FDс?8&pul#:6XXtߎ]{Ff#F^#|_\K)3c.#DtK xØqZ;3 sy.g|G3ynO; _4$nW~Q'RۑO-IN\(^\M,O,Hst0ؒSG -Q˕E|BRNx-rS4Tr(@@t\p6$ endstream endobj 139 0 obj << /Type /XObject /Subtype /Image /Width 398 /Height 381 /BitsPerComponent 8 /ColorSpace /DeviceGray /Length 5649 /Filter /FlateDecode >> stream x]=؂V*8!rNL#v"rN `ʡf 43gM#Ш;{ΌD}_]obNOb HcVJ[%”5}}?ߓS`daEM EJ] Gʑ>EB++hJCl8Ӥ[6 (j2F3Kh -i p 6(r;Rgd(Y\6VQL&2R VX"!1`er(-$FH^Ƌyiib1^ҿQZl]:%yR$-;)ڻOmӖKHΎ+z|dksq 2N}uQa'{f!:!եr- 6FFGnKY>?= .@', *Ve Nyp:7a\L5^rGhc;q 7B4FƜ/̨A3qa3w{4 AތP(R-b7 $ 'q"m45iAYAx 67z|mP׆!P*|mhU DT)!ڠa4U1`kFP Y> ˑh(Pea479HU(T }ԲCUѶLTx'wD͒kj6e0@#lt?9*n-oB˵![: .8M ֈ(uW MzpG(>Z#jM^SvS§ֈf' zdxGׄ-I"(N@XiA?Г(E2g> ֍*Kg@S³POY.ae;^ * lMXwamb,7񻩽YEuIZ`]1z#m=g݉M u=<2<]u?$\ //rhpe7f/1uqTvC(mճk# ,x:/HXR;ԖAX0W[c]>pdcc]6nzT+ĸ6rDA/7Xaw%ql+pU7}(Fme(m:Y XW£u@ENk~nXWea~3e&o9k Zmfد[KʅF}!MFE:] UfeX# |ER]˅N_0.׻oi.&Ԥ h)՟(uBVRHQXW,/xL~~!fsױMn*k6$)P`1؟yc5+C>:A:u버$ 8SNcbrpx*وĺ* ; Τ1C Ʈ\Yјf~kdL,dl~>ʄ: DSd$*ӭ%ޱ.)Dٖۛu%# _ZgHR͐0ִM"~/}Htn`y`]K!3nsX~Atԏ6]2c&iJT0(3_~B)#: ooW6t݄+2_y? AG8i3+le˳Ds6e|GKllЕ9vd>[s_zR%TX~e)_qN1)c|ۭ-`ؼʵK6A5B 4J)HіWwI}@X8Ddn{,&eB5H  Hd•复WeR[D-yդLڐW 0H4L6bVF7wC`8MaϿ퇊Z&&C ؀ϳ\<Դz__Ɠ- 0\N 5ܼN ?6!A)lo;)Go@MlbDFHxEז*rz PY`c_UPWjġYL6RD9M *=tuw| tB@_.}Q2X>rl,h#" t#ԂeS`B_ByՏoo"2PdcQ><$q!, #㍏PtZ23{be嘯8!E.0X;tm7$t>xav 7JF0ݔ|ʸ}Wi U ޣ }=3وjL".pgC( ⶝ã ΥF:*crZoŘlEHnOU/VPF+AobnkE鯠MvҖ=4QlCɚl ,Ӗ ׺2z)H].$CX')7xTEo|/ ꃺMz+ضM;'Blthie`mo6N(֧Ň>:GL{!+>7CO,E S uGjwJר` 1D&^ Bhmawc)W&lIq ѓXs3ћ}![;Te1J:Fɰ{O6y_.C5 y,4CݗCuVp+LH]SZ2Fر *ٸctaZ`<>5]0,0҂w_-Ty;RyN=c|V?c`?u ˺Q6w;VJ6ú`Ydf&;5qdDph H:ƕlTkv^ͭH^"\! KJ̨"G&'rgm*UO1S=IQl|PA$o7Md|6xbd4d0UUѽΉ7B6> dB =}sN~UF ,Q*|;7'܈ rr]܎lD<*/@8çLAA,F[=+O6RΝYp4H+5O(I6ϝhOt7 MT ;'*8)&Yn)㒍m :G6e:!qD1UӮ`ڣ{=4Q<|Fwȳv6С24ؽGlƺeTL6 Kdh@9,UEP;9llDq~ZSr- 7[z7^O1ZwwVQ#vJ^׬Zrү#k$+cXw=;1e:rCЌM.^&'U,^5 31vQ9xDkMT\efnٛ8W!}Y{Jw(}{zDyhK K~]'LHƶ"Oi\{נj#t Z׌߶x @xXuj%̨H u26fPAT|ޫٌ*3±jȉ-Z=X;Փxm7y`M* =V7Uscdvkof{WLjbRhkPd_a(us4(am c4B1q -m`U2z_['2ے6 M߼k&F4P(.y஌43J^o?ڐ-n` n121)óz'`PI69wgj7rU&m6 عsv=1Z^6)w)-{ i"TA7[$P9,gT@S6 qSyqc +5J<~:G #nX^@V 8S a E0 7}||fm|{NE Xl,0U\PVi\E碆K /l,kC].fMM1Ӄ )?78emL̮xp"TB͙6Xg] |j#TitnrbxaeTԭhs;;nw8]b$ku)膴|UeYmX7j7C4^Yxp]6wb7_R6vp%ʕG$nj)Al߻==B6(7xՆ8|m4^5zޖ(lN虢S# v̅.618P9(+R/e?;1*7K80$&(-68vM$&X/GkkD*tהs!֩Eosm9̷}*] vьm B*.y)U[@mٹ&]5s 6Uy+ agN[]5sr klhdz{6!emlm_e—vDBnaQ HOoކ#AiePa Nߔ 2mJvفuzy N"vZŠZsIݗ^ƾXO4 endstream endobj 123 0 obj << /Type /XObject /Subtype /Image /Width 432 /Height 432 /BitsPerComponent 8 /ColorSpace /DeviceRGB /SMask 140 0 R /Length 4460 /Filter /FlateDecode >> stream x?l[Xّ&_9BbGdT,c4S%3dp"UQDԭbUP&&*lnFmJE04qG8~n8"~sOlo13333333333333333333333333333333333+ѣGOjEbjjtN<(ǣO122Rw/Fbzz:w1;ى~:NKa5CPCPCPCPCPCPCPGxC)yCÈ:!yC<yCPP>ŭ[փ(޽(}bvn駟F?kkkjee%cccjUO0$t:я޽{яӮSJ}!yC!0C!!yxxQ CyXyCNbvxS63L>K5NCPNCPNCPNCPNCPNCP:ԡuCP:433333333333333333333333333333+Bљ<]_G:,]mrҡu8CNguBѡ}Rs;CzIW>?ԡa0v{PU0Kjѡu8mC#|:ԡ+aܫs>?Js:E:agsCJFqkZѧ:'OF?S'}$џL?_͟7$G4һeu_??==# ;pnnogg't:x:,uXByCyCyCyCyCyCyC<yCPѡuXϱBѡuj|_O:ԡutCP:ԡuCP:ԡuCP:ԡuCP:ԡuCP:ԡuCP:ԡuCP:ԡuCPocc#:SZ-P:,ݮeӡMСM:ԡM:ԡM:ԡM:ԡM:ԡM:ԡM:ԡM:ԡM:ԡM:a6uCaCtCtՊuC+uv-JI&KKKСfuC+WM2QPV3uCӡuCӡuCӡuCӡuCӡuCӡuCӡuCӡuCӡuCӡuCӡuCa...~f.]˩Q,//%W\>Ņ l~~ŋoh1;|ʫW'я-;k~ܖINfrW~~Z>yKZJ|ڛ7~F|b>sݒ߇⻋[r_63L>K5NCPNCPNCPNCPNCPNCP:ԡuCP:433333333333333333333333333333+Bљ<]_G:,]mrҡu8CNguBѡ}Rs;CzIW>?ԡa0v{PU0Kjѡu8mC#|:ԡ+aܫs>?Js:E:agsC̬ endstream endobj 140 0 obj << /Type /XObject /Subtype /Image /Width 432 /Height 432 /BitsPerComponent 8 /ColorSpace /DeviceGray /Length 2099 /Filter /FlateDecode >> stream xm`mA[قoA[L?Jk|)=L mp> ͋gڡsFx3LE&\\\\\xt.rsr/k}G|unpu7in7\gZrf52\ r|qqqqqqqqqqqqqqqqqqq)C嚄ܭ⚄kn{ܔ:7W#g7nUxF{=r\5cכǙ<\<>6Wx55W.&Z߬BrM"EQ [6Oר^o~u6s[7S"VH5Êkުor5c׫L 86sO|npMZ"CƸ q#r5WWQv=פQq%W2sr? \!Wkzw)ؗ\pP۲l[ˁk2Vޮk\b,z\MǮk2ު>~ iWrqqqqqqqqqqqqqqqqqqq}A/sW\7A&\\ޛZqJwtA-MqpqqqqqqqqqqqKDDDDDDDDDP-}2QP16BL>)aH*MTr~W&jft1&]1XwiחoL]rY>=)>NڏCzfSθv|uWL? >U16]bȆ$Ű8p}ӛ.jx+Uw\'p!Q!31γH \u/J͒6qh:1%|% d+x+x+x+]}j|Ce߾ɴfگfyz^[s뇫o -ٍ"pk52L\<2Wp?Wp++x;i߾ȴoe/e狋v,n uzյET\Sqrw]3X'5gW)G!~unUWٍsumʼw r\5cכǙ<\<>6Wx~^i}i_\\\\\\\\\\\\\\\\\\\\u՛،?ku*t-$\,B_0umt~^fW=o3z3u-nT31ﭪf .)\\\\\\\\\\\\\\\\\\\3va໋cs?W狋nפ\kk ,B1i>7<:q> ,_suesMjjWrqqqqqqqqqqqqqqqqqqq%0W,Wc`˥rqqqqqqqqqqqqqqqqqq~ռ暈w}5 W ź-˶嚊+}&`.6bǏ쯹t}:.&3תּ'q%t+x+9Wpo+Wݼ2 ~<ԊP plAh\""""""""""ҦhЖq]buLI CUUQmbT*7IWӇp4C\曆1ZN.gźKSfڟ$MrHIXiwu2~$6*5 uƵkӸ6fIX1jF6\'q-u}Ԏ`vǁ\U\tWsM[:k?' !5 qv5Fʶ/N{QjCsqe-DDDDN|R endstream endobj 147 0 obj << /Length 488 /Filter /FlateDecode >> stream xeSKs0+t ԝvƇ&@@5)]ϰo[/ '=N$$YD,g^8<+} (sKȝ=v CmwQN VH0uYJʆ;u{q,nwXHa1ÇQĢ, t\~3l?!-"G54;>L+_gUmMeOw7dFTATвs2s5VSY%ə UqNnZ6h<-LAwqAod1-rvY64@femF$iU;֯y$=Ϲm^ґ^a, 'vVF(2JY!U-Nz7Dg yH.ΙQ|Cf7"j^\'ٞ}8jH1.V$i_EvU endstream endobj 131 0 obj << /Type /XObject /Subtype /Image /Width 840 /Height 280 /BitsPerComponent 8 /ColorSpace [/Indexed /DeviceRGB 2 150 0 R] /Length 4634 /Filter /FlateDecode >> stream x흋*@vf` <$8ni:=I&AAAAAAAAAAAp[\҉VFK.D."xx삥˿8"rHh~/I. G#1W,˩?-Tj!<_ſ.sYe}G޶F}5ݧ[5Wɗ sfiqYߣ\3ޏd==5 ͹0gh.5ZӰ(7ĴG;˟G3Uwȍ{rHg,z$KOGR}za.v?ԛ Qw0+//.Y?"_ޥ{GqiG.Me cGŞG2#%=lg&r\xU]ſ=<+ا}>Gr5Ea֜G}+,$4QFbȣ\49DŐAfsQ,|.xKi>sQϺzs;#\菔8Hh $`{q-+#R`H+p8+ptۏi1U~wÒHs:|52ԣھ7K\Q 3r?tL4gھsgw/q9=C=^$O>)oW̕7xO ɗz.a=(F./c^w-'5継ɵs߯|@|NՔGAyG#=j~Gr8 =r.QnΜu6GG`.T-<ģ׉'pHǝ[r>#P..iSG- jK,8_Ƕ4ˣ"#%HxTΗ3Ϭ4q? '_G_ajqq76K"qEjѭ@~*^w=#i;m%ڢGVq>b%pyt'. xwhs]YcD?i+%*\IGߞ% |܍j.Q\Ci oOP8w8}o}i[pCV޸K6̥Iqgƣ|4~?eV~Gt'LEQHǣROM];o/IPʜ! NGq9glm]Rsn|o>LŭT jrߣ帼KOwc͗ދ iC.=ZޕOuٌe6̗˪\K% \ ̓hͺ\jU.Dڔ˓sGry\yd Eڑr Ҿ\%Efٕ_Eژ DyGژ eА/"  RS.{${ǣGg0ɼ#GR<ԂG2"UHsHGUwѷWȗK;\0lJAT|B|%GEG*7$E£B7 x .GM5\"(s\3$zja})4YG% .1<*Hp9v/yrJ{\CN\\_x.wHpIvp͗m3 \ȗ0pI0p͗c%+\e׾ \eɗ}?z9ȗm?7Q'\ fMH.p \.p!     ]I#W;~ٗs]zotӁO&B._>W]ڮ|epKo.qy/C__v;13KoZ2tm9eG._y3C\.5]U}ce.jo? AAAAAAAAa< endstream endobj 150 0 obj << /Length 17 /Filter /FlateDecode >> stream xc``طo%8 endstream endobj 161 0 obj << /Length 3477 /Filter /FlateDecode >> stream xڕZKsW%*%$|Trٵƥo*{3CCNVF78hD9Aht5xě}O_}!I7(Rn>6%7&,Eͧh[Y|s4Y4~y,ǾB@}%=y9n*nbbBenJ]<ӘYko7wxctT6ϟE7FąMw +nΣONQ=LO͝,`mNcsu)*2 t?eT&b#/qcB!m}M'nBqaS U$k7Eɝ2E3XhP} >rIrښ4U/Y?ƫ&$ 8e4r-`Rhp:|CV~rgy8lvM >HH-h<*'hR[YC%Bz)k%mG`0\@W52\[zn$4dWb76"X{*/t<`uwrPm9N.pBb6QjP_{ȉ&~%oLHBGTVʀc3jUC, @H^& qb8 z8B"ݱɾ0`=0)4-hZhR y ;DzYnqψRݔ 14@$U[ʏr)`QܡY]yp#.RP:;t-өH|%sa L{*Y7@Cͧ(95[b>=%D# ' -"Vш{p473.qX@Gfd4 ȎN' _k{nGż-q,1W/)ak$ӶP'7+!+nWʅKE|6f^n4B?U(@c{9#GSS ~ugȃ(Mz@ xBl2Ԡ`ztq[=} nL+i,g* pO1S :"r9V]8zv>@NEa%W!+ A GT# 98xiy`OЗtEzyXBKuLHVqF)Rptn5S;ҮDwhX\SNy: 0W*^^KLz{Yx \D?l~ޠy:y,96T:P]9[ҘzGK(3c+9sڧ ,0Qe` s3ؔU\|"8BϬIbtcw#T퇇5ѳŠ:(08I4gGw: iKHT '~] @@zVd]`Plr, t@da3hs-E?'<<2g&ۇtI*E# *jYˡ hl7w*{ P\˰Q7P[׺d`ޠFb-ܡ=5T"S?aI^x+nz'.C*ek/0iXW 0IV@%}:͡l_9W04‡gP8Wx$(L$0Zik!C3n?f>1c[٥d^jT"r++Z7K3/\gl ol>s]xKe1msd~F[!+\ eo]EpoF +?W!ApENDߔ߿CWos2T7|1毟S42 endstream endobj 2 0 obj << /Type /ObjStm /N 100 /First 817 /Length 2724 /Filter /FlateDecode >> stream xZ[o:~i[QIڞb{Cv7̓b+8v,gHbȈǙ\HK&eZ0ǤV,2)f*1( {f,,J2k|O)5cAJ" S)JkN2m$~T4E =z/0$HsRf0 LioPVDf#(ݳ\\t*@y6 :%DV=ϣ d1TA&ʳ eŪ<;L p=Lh"I "zXr4AbEJj1UUXCN@#ܜ*5 z!с$;͜1 m %w0$d%iO*BZZR'S VhirX&ipHB#ID GACd:xO$zICxS ( +h}m@ ư(!$ CbZQ"֐t>DOPS$HKH|Jދ,9eɛل%4d޳/;_'HQ#DŽf`D/jbw'[1u /960nl=>ηB}z>Ql0*9\!|\kѬ}W040:ôjYu֧R+O,]{,k%kِX[mq-!W3_6fMC:dv`ٴ_v0\Icr+1k%MCp޺Ŏem؂ߏ#|l8Cb ޶d@ַ 7T'Ho>bϑwv’yyAh_%gwK>Y/9l\NgdɬdS ՛0O'_ٹ Gq1!y^9GPM$jT1ucՍP75b[s5[s5[sT%˲]>NaVTEG69:AνSfȀlkp)y2H<$ = ePZnZmyTI{Bp4C,O+tx%`LWO+v*w8ɕxZ!; P90Qz #BC!vCQCFPEHLn$?]PC.!A( u^`7"e_ϊap;D(DA#vn`E6GTA:}Ca lsOAc\(( Qz*.,i>K9|[1JVQ,K <8ƳbUb 1 3APGNn Od'(iFW5]H2X=VO%fG^ܼDENRF5?%4fY\V`V֠%a}^{H}eqkq?"W%֣Ujz~ŏe+ΙR 9ix Gg#&Gݥc6[AOGb$rY $ @ɻ/LH0AhNH8,#6CE>蹋'j <"Js:$p-QZd JËb9.lk˱BN5Ggb@A"y!c@!]%d{5om\׳"n?8e m:Ĩ8]xCEK[Zl>6l;!Ѕن$eU,/3d2|9`ޥ4KKN\,VZZFN,&LYy7+yf|A[dK[^^!1]Nʀ?}V惴&||o'oza\,Mf|+O*ِ3c|/I{{5k ~zSLfw S鞺nݼ6ztE*s)1l%Gqv7+YMy cQ EaGfwxM∊ (J#vO8b(5Jh ![s6YwJҦ7)8nesʮe؃4v%"%j"j-'Mּ^D Bj1_Ѽ}+շ dr7;EE2M"=}DhzMa7f)"o[[yHmچ.F8wEO"4oc˳/:Q +Qt5X#")]OO~vz%#Rni( \<>PB"5 YRPOCti endstream endobj 178 0 obj << /Length 3040 /Filter /FlateDecode >> stream xڍYKs8ϯiW%斤'v6gjkzj[5-K.IL. (r/!-@刏C{#ǜv8K#1(q֣?Y΋.-=|:1VHnjtӯǼȠ)1fnTԮ2q[ۼ*_FZd"HQ2+]du>¯6!!+U5`7/U  093uqm]gfH4jC$J @ziӌEq"[W#ى1ppFݖO?U+#RUQ]U0kp)Sa^)*iZikTДWc™Ўv]Wrer)Y-F8&eB V~Qϴ߿ iZFBR%c!iO*8 5$\ jMl;e:_9. sМdӏZ[+SVnƉgUm4;k?ܹ٤ 2\6m;}H : 9} db "׽Oq>zI&q҂Idz2.JR# wˠ0y^7aac&a42/.ɫenVc%"O}2ٵM$o.40Uf We'c6G}R])RF>|tm9D.[~mt>.3$@P4Z}FMC 7ͫWk(',%cU=Xc9gg(8wOvmšOevyF%A[*]b'8+%sBhu3= /|#o1XV5h=Vt'׿\4 c[6udad[9dm:]Q87Dha 9rr`w)86 Oy_HbUTΪ) 3Dtvu&$ʂ6RɅp4`lѡ8 ]P<,a@1δ t8z=4I-އscL>M&\An#(+đ_!įӐW&Zd1ټ:| )BZ16VZ3+{W^S h}b} 9A+;rm=%K !<%QgA(72RxƾbΝ5%\a@A iZNis3Fce7E1av.A7-sO0"z±A(DtzGvZ Ϟ&1eyKe@1s$H:r0%]Av_-EF_ҫe!gΝ/ys77?/Ҧ+6f S(x1+W=6{j=(EʁOKP}BahSn$eFYW_hoԦUZ#̹Cgϭ/YUAH(MsW_{ةw~{e%k$ؖ&_]xW8 uKh >^N {)f<Ry/I"lrh6~=P!ՓDR ^s(Z$&³󽧸x]9마G9'e!0 fq|Qc79/cvψ[Rm6$nNN.-3 95R&.5Ң8 Z_`|C !,b$%oX"<_~? endstream endobj 206 0 obj << /Length1 2187 /Length2 25690 /Length3 0 /Length 26989 /Filter /FlateDecode >> stream xڴeT[6CpwH.=C h4$wwwww|3sz~\׮] QTa61J؀Xyr6 f+c+#33;<=$fp9<I h4䀎n@_@] 4.6nfb10[ c`di`i0d6.Bs `432ؘT5qe {`'[["&IWj*Uwyw<UUYp;I?(ߙjbocW-/ #)_T.6O{8hW?-ȚA?N6RZ]bp_ Ҙ8+( 609A wCGG'_?1տNr[e4.b~2+/cـ01ag栿dr* by/?dy̜vEmY;){mݘg-A6. MTɖI dn?w2S#]̘kRYKakc 01rz?= G{'?YFC~Q. 2Kߪk?_ۀ@x&yaO. '++yk  ͭL4R?$]ƊFfҎC/ 2w/ڟ{d>K0s},A@܀5&!L?8d `3+} duri$'I_ $70xLA\&'IoE?7b0[qlko ;@=iM̝sQ8d^'w:V\,A坙 LYީ]ww᯹?q,Js==b>8on=_k_Xan.?J@;7'~665׳~,r 4_^1 Hl.ϝ*a<.ДZNj#" 5RJzhRbYl/6V6&@TgTO[- 9*dImm!u>DN]&ꔴeCϱ4b[.,M;=`FG/cvwj%U,DVvXP\*oR ˥DIæYReiuVksͼaDgrԝJΓ:6.-&sR۽pxrs,+-yO.p(,/c!'+q}H`XnFpn!m*h/yQ!c m}rR9?b>y{k9}~\AH[ͫzw/jT -#[i,Q>i/[((q҇fk?bcK2YLLBlaH-U MmPpjr%0(FF-kJd]m3M(m? 9!Hh\^l4f (gғ 5|eFٹig9fQ&2}7KL~8z͛A4bT595qs;䩍>QTHŰMU cMHC|tpz}T-`vވ'Qd528d @8DMe)J& sQY5P"NE ͤQ7 <ޮi/w7,'g;bٳ錄'7tj#vү"W6kV:$,k9 UW|Yq/J}/j l1{vj1ŋ@3P&)s  &Ȝ +~&esH,ё<`VVM&i(&va&q}P&RxGЊ -'&{8Ё"|~ZEOlPp/6QMok֨xI6P4RWLaNז]H:&Plԫ)vx}ubwri~HzbԈO +!U6iwр2O3ǶSkn exD~v^o1$84((1(o -ㅭ:"|m Y8VTHpMeh&Ktt,cݙ=y:#'ts]U(rpA,3`UCvێ?ܩ(F76Q_}15 II#-d]73΢lL*a1-J9wnyO7J 'HFn"sE{fQfbu4ތ2<)#9 ƫ\1,3nW:|mDU>AܐnfS:AFC<fO 굤:AcqXxv B ߌTBy(>=˓A:Hnn֮UݯEʛX5FuIr9l(o>ή>%^KY=ńVh78AmꪝxҩԼMWI ~` D^g};aL[riř/m\xsdnBj'Uǿ5Ty:ryi"ڤ|$q4f0TfPIUФI/Ǩ0Ox%iQ޾qZS''։:{CF'UtyRC" @Bm tw=̛bĔy@j~bw[?NUM{!/N26Y([X~  L rE̘ HTY=+hmCzWc̅9 tNx! H!p*-/ߥyyˎP GDC+gn7Qad*{7?46'L""  j|)s 2u& nZ$z q~ا!^,೜=RXHH?H7C]گc!Q:zXU:Mcbe_’d+EEV-YXXPt.(qQ}iHj:+RLv O|=l[CRͥ:59j0!w D|ܮ{C&J;@HE29!eD#Y(ɖ AԠ ̈}-#>z 8;Ԭ #tTymWQanr< &d6C#nDFd$%FW_X%TY_^W=2s`iRlA5`ČsF/]O$6{ eаSt-vi[*G'&M\)`謴_ΰ U'آ.n ؤF)U9O)_^(< >%,Y53EM~K2 ˢs.{T0ryNvc;'T˻.sb+AMWT!zOyv Mw-\BF9UܱeW/M*VPִ3Oa(!]G⼾~:ҫ1+`)pn2×9.z}h8jHDI!D=x9;BQ_Pf(V%CqnLL~zy  -RCIfLH"=nPZ""J#C*r'LQ5=#B g*f1/!U0LaG FFYsцG쨞0R{*| vBmbjJh?7Iǣ1~s&ъ #׸`ͭOpK@ I˼;SWfMgYDu#Nmͯ;]}ɜи\}5k&EuArO0vuwBW!*1U|Km{)S0HKOa6_أRj,z/T".ZCŘd]~TӒCk;9(t2nHIG;$ .pX6rҦ:qrq4@ׄn)ҭ$ҙP;'&s.X!:\V;[L(E+?v燇Kg8X>MQqhAZyЍODS"Hz]/$%%@dgX*/Q`#OuD_nWZ^>$I/2}+Eh%)yA߅Qðc 8l[Zg›g/ rowx\A,OIZ{ĿW)bG1x%;:IF%Bk 棳DAQͰyV8M}?'#/Ƥ I)=zr`,V)Z0omL M ؈e4d-j0aPiSW)O̖opQWQ gTىV]l$nњSΈ\0ILcG_~2p޼񅺦YZx:/N葖8J!4.|rw8w,K  d( v,.~.HyeDٽ2(ZT>b.:fUNXfSb5cLoEf{Ǟ+]1_DfHt PU&(x5Md:$iJ`Eve78]H0g@\ XӥIPbhZ-!6D zdC;C%K.ggbN_`!1ڥʇeRU{T8:iI=ŴjBŋAX Lߝ̃h耯1 @/_!sfP(V'3Q#{6B˗Zn%{ ~w/T?| 4o|1#.~}_t\Rmh}zu19iܰ0l1:AEbjDByk^Aq-soRx%H?4 fqH0ߒ@ ]̀{\@?CR!}/*w,Z]gHEw4Ԝ&XaNsixyP.9c{6.#[[ifkU*>OFfRRoגBmw)X&oX;%F/`.\k4KSooŋv7%[TK`KqUQ 밡÷ɸvK8U 1CCGl4ve46>:g)8Iu)m\j->ު~>\Ki.Wȅ)[xQ}rtFܹ?}>:DZ+_@:NůfT۸li/ߖm GL@YO tl p/gpϥ[NϹobߡ: gC&pqbyQ@N0FM~nWf{]'/nfJ$DFI2b %TVVM$|*H1o-FCtċZCuٓ2oGۭRA(kz#i 4ptgR3S "|"2/3Jԟ>/…0)d7ڀR);1pUi%%UrCv,a/Ci*t,.Ys3.q<Tr%Js3q"s.TQ9Xe0ȳ6z& (?kR8X؎huzNTL *WbϯZ*WDSBw(3.@%5Z$"9* =f|3 EW%i4 -.!aVS~qr}L 䱓x aex:gs;Ulҷҟ&t7NO~kH0$ap+޽|< vSF (")ޤy{j ynm&d؛f:m|-|N(э90/[짤j k>K<{&s_!4'IHM\adf$՜T,<Խ (op*Y|Wϙэu#tx LB0bJۨ)ݠ$&̞zйu:Ʒ,|%܉J*]M7ߔWUB&Q8"@mNZVQb B*",~~}i4ot\[uRkMŽ> :?OfRp齥q;_Vk*U Ϥa\m‘ԶyPEh8fખ_Yb+}#  !-UiO&ǧ}S _7VLyCYHu' caIGiM.[msxe]v4:^pa KHJ,;e*lAʍZJ_?DXę1GvjD ha;Y*Z4Tt4-8%l!T#C3}B4_ q&\_!w^D4 ۈS_:91t!e@`5'w6@`y COESjr?MQQ:Ciᡒq3 o-}4Sf;&Q#fju޷$гܦO.L0N3K=JDwAt2 +.u~jfxJͳG1{0V& Exu&ep.sfv4z;B+}0"2^yJ2<}2L!nLI2@ WחO!Kߤ -=s ďH2~?AEظ}@-Dy^d$ZH8Wj!3 }UYeG^۸ !㈖6LsO2HID^FGI^)g|,m 3X,fn ." m<N>JZ7ް qiMU6s_#؜|I\Mʛ_US0{l`xF)WI>@-W!+$46Oz;fq]*2lD_|47;xVZj"KW $Yɶyuݏfk{բuG%Yˌ3YM$| ~}/y)݋w9?؞~l F73VDR"DtW# % RwN|&p\RBPcG`΅}{*8B Xx,˔D3;.ef9?v c._iAG׉(gUN{Etd见nu~+.\E6+lz| jl( Hȣk%IFU\fh/+5p1j4|l]G*\\FKM*SF_baWt/t,2]Nd8Y9 }MUfb*Q3+Dy"u}3z^ nQ`jH1rԝ^N$j| lZH*S6ca6Q >08-W \kE80\/W źVޒCبC!ujhI?vbUm`k_ׂrpzzG0q ,d? t@h0@Cn-c :D|YhMYp)e#7x5)ס;sJmQ_*[!Nq=gSGBJ;N\L2k7KCŽoB1d+cS|4'H65OVB]H9O"PnB7TTzso]$9X`*5+ir¿E]TNX%'}3}Ќ`= `j&<{"tGJV/z=yvc_Y SszQ+aгU ~Jv<Ϯt"}",;X)aڸk&aP._fǔn42#A vbp' Զm_# MRhwA͒u8$G5:!P>ZgLEwNS.`~')cBi ,❸JkVX:͏LvFf?5GytH'!B+'R+"عpKbà85\` V#zM'OTa3߶kNZ_!C?P^PYwoD2Kg* \6]8 0,O% b uTt_k(Ө+}qz$uF(Q@3:X}^o#?h%dbXĕp(w`h{°.P>@H9(HMq2\"j^TS,r~y7,)t8 1.y,LM+@PpQfk}g lY8꽵|+@a5 .U?@P4Bp̜h7؛SQ\Io`2W5Kg9F՜(UTU0d=9\4gvt)jA1pF ˌ<[=TQ2@k^)N8bqBudVT1Y-ǚ6wy8A㡧m=NވJd5<"QcY$S 3!Ka~1U}̛~XLLSN5xf9{uj"7/4hd;Wx/RC!ݷ!ɨIkYg4x́jpmld^d}Cdi`0w8rJ2iB.!~"]O;0ty]n[Vܴ{R7;ΖP6&ڕ]m^vTI@IfcrI6ToMZ΀b_Q&{W–Ȫ\hЖidr!Iȫ~W^j*1H4Yo%\ i3yS֞/?RO,%n'\ Ĝ?6]s;Fףzz~Zɯ%"N{Hy*zfVF ާUbS:GN5$T!@U$Rޑݿd/DDvP0 ׭.9N-J,ۂjbj녟hPYONnhR  _"sxk91O(wZ9ˈ6aS#r7`,rm0X@īyZm:xq߼WLkԝVco rg.]'8WH _Y'RN)񘍾") nl-`ḇkzLP-=ggWn^kK?-aȻGSƘqw#oBQ v NBf]];1~z"0i xE=6dޔԙ=.bC^7,JQ} CGx1c0tJ赈$1m!h:se'“xQGzYYZw,sG^ۺRj_qOb݃)sRIGy{c{َ3EcTNr߆dt, Na.~L {bAaEf;ҨNzϕz8SITP譶S}NW6WJqZ[t d#:>gɩU8G^ <ȕB-&UkÉw-n!RϹDV0[*A[P};`pʶMڂzlҶ?;yKf`ҷ(*>z;52N|7#(l <_mT1 nPi>6lq X"0 q (!+tD\a[(]flr3'''W%O$ ?!s'g_ű=0HCsh;/#t7u-ʡaY B?Q 6Vw<U= $`um}~ ]%]gmNͨqfegH CiPLde$%W1VdA4~F(Fcu?i9!^91%*TUa{c+T=!:پeE uoZ8cKo#~?TR ` t/lzj<#J%#טT޶BjB8[u_۔*v[ c4, '~6cTQFƧn3Fe)iX5齘턔$?jdM ]^LpέЇta8q{;:ȼDg`_Zrt+WoiC՛}((fK9:IНCoc~3hy QŒoG(s};`:^ !麗 !g2CE8(򻘶nP!XI~@Q J7}\:Rq|'dyB`%s%w*h`(kސc,ePw.=?J?|9zՓ ^cl{D_ѷhHq1Yn&'S l@PDc: Pa|N~xNRo8Iww$H7R97'cibnFڵPō]/?jToHEoљ&<^y%rLW6R "yܫ5v5lx~N?b2<ϥ^rgpč>1dű_r<q,qhV S}(Z$gjqihV#(jk|&ܒF_2z K7>2{>[sy=ɮ 1[ӑEq%ldN&h'߿_M!Ϲ{#vnimEYx J2f1UbSgB@9- !sI$؃H(H879JaCy>ьT|AwګZs`f%Wދi*#AAv":T_pLi,Uno-<ӷLޅ^T_9# A5I"'[tT|`Sf{4l/ Htײf)ޱj)S^.mD'gt ]~]JĀ=]Thev* mo-ycb:mb8NCL,[Bt)0ʰ[,cqc%f^5NΡ<׹-H٢q XXn{: }̴U~Xiv^녳m;w'<͸xF8Q*\wT+-)Dҭ5u>%EM>Ӎ}4O; Uf@bs:?m,rջ2 q*ss1#gK݇i[t/YW}*3u(4N坵0 ~(NM 3NbKFr%O'*UbG1|&v2{3>8-%)q@FGc{0뾪fQSs-/?Q,1w)prXu i T ee쀪ݒC@4AԺd6*ZƴJrI6BB"=5 |*{pi[mr`{ }xCh#T ZK:: W4B[z L%ɰOQa:b ] Q(9R͖ kjA2,Ge(m&xiMu/]UYȉ5HCsΣNjv>$xLyiJuPs^Sⴊ:DLF_z_T (T)ڳ9'؞/٘rqz vБLUs4?E܆:OֿWҨ;L=top2 D^X;%M  b*( +R2)2̤M9%zE+ Rʏ'w)>zDU%9J0x{K6I*#o}o"Qf2%8ݩ/[8!U7<$dzt$F⏾YJzcJȲ뉴$q }&nX`K"5r0M?rtwZ^u<컨wBTъumONpjG|۲]ZPaZX](3b{LlkI)B@8=\ 4OΙlU'+J>~ ,L8 q&XXKP4@嗀H1F Aw *G" GgfvְCL@-hO3=:x-YQ(zO6 Efx-(QYMgMքκ+G}-S1߶4WčY8?f O{xϏn $R6(xa.*Xr| ; "n?BiR\yu{Dž6[ k z>q!p 穀_=`t^}{WgVs\x}V"[Ж1`(gE3~! ~krPH؅á?tcO%Aև"5ړ[xBM7dXɈzz!#Kஎ7"8+ST6R/! O. N#6M *qhm혪fMyXWh]c* 0?S5I'Ok4(y@X1NrE+.oT!̡$*ē F{Peտ̲ouAC{5)4sc,bi=ZF\ f]kcE#wq}ޞ!K5.1Ca+VKG˓,wl髸6+`y㤿0 4u MD2IH)VmS[%E1dɮɶm4ٶmkNdcm{/o{?-yhȉ{VmU0y11_e-l/t~2*5(iL4Ť koL)-,x4=r9?,%j> 4(0}` ݘE띁8"qJ2l#{I7xrR,]Z6[ SP@t`XεY\پgO! %Th[_6[ pɐ8qWAbBR {GXGK85<}!iU 13TD' ̽wͫc=eHUӟP`{Oϗmx $[Io"zA呯v=VRRnArm jpM;;ƔLzô㥔*G\ }UW|C`=MwUQxa\#|(~nGtm( 0 *ƍg1խJq wkPIT}>>Jy:GL'/9b^mbR\PLn2G67`l,\YPV. sӲA=xӛZ#qX,ׅ= V1+?ZsV^YH6TƨA8f`PQ`!rUldN;G KzDHfhyK6WZxeYB'Ě-"PG3,ew㓤`3qҗ1B9@j =v;9e"=.+[g"G`j/O(|5 1GC9v&t!<҉=kʟB1ҹ6Ӷ:Y7@*#8"X-\]|V8drlPv<}dF2U5fmIH3ݜHLP9|󑱉=ͣlM dE wvi?yAuJeؕϻ-v|zݯ]*]X칈e&ɰ)x8х.Ƿ% R>BR^a_ ƈ,NFzCFo.Hre-tvp*d{_6#A#19.+ktG?@8v诩 [-<9 ĴD rK,U> ~D0 fʣW- iWhD%%4Hvse2 YW.3%3N;˂`!n|э;oE68~>VX[u.n,)3EI-+C.5@>[o1: ^?8_"3X~l1 rw2Ջ7}3&f]i ]L%$J{ p*A>y҇ yOL r@74lLlNw|4x;vqnGp~'Jfg濸=Zssmcl[?u &pp1/QmbIxr4BOp)^7mH#paa.)Y՜vs0goUCl1ney27E2b%taΠJ6 k hAߌS'XktLB""+ٰ ! gn_ Gu%I*@R2E[p6&ՎSuF܊#FV?.{삲d`B栲`ԯs_FVt~y1jf'NZR\L^׷l횥0b\XIf]'z8'k(pjߓ3j'a]UN>lPsrr%̩7qVTt[JQ2"eiFɇ'HCT*ejxɵ9/k2;`o9o?hMaDwK8I{? #?v +v+,QNVH얕&['8MBIn9i$Ҫ)Cr>fk߾o/':-Q/\-tP EB2,~26ϝ$a|0@qˡWXٰ̦Ɯɍ$`bCܾfnu.W6eINсJ b-pG5Ae Q th:6A}ߘu$1Pi}dDЅ_d߶ %A%t=ܰͯmhMO@l?)NSM4qdj@9"}ѯ<ۚiO$?!wzLG3#Q FĶ6,RVMi"eRG~ɏ!!cg6(T4#8&IK*t⤬5:~n1xr ud͸X!9;ԗ1fߧAhg2LL/ UIxre@B h CY I:`Z萈CОl8bMQo70foAz7ri{v4,AEۥ^b˩&Bup*xʠvCG{<;Xѩ/Ɠ,SɷIqߦGmŖj Yo/T6taRultRw@\,u&MՒf6×_}&f3C)Sڃlp\$&@}_3eL i 9 :A\9W:GEMJ }A899-^zEw\XqG4dGcpRt Bx[Ċ }vKu!\m>]IEUY pVCb'ENg6VÊs\~, KUzInnN . >\ɔw\8El@_v|N?G!1a0Um J|iBhyh TQB%{gYbb^F &A&FA4~Ȭ}Rh˗b XK 5^*=AWtsCw؈ ܲ޵Fx*/! `Zͥ`x͎є_w>b2<~"0t0% I:;GtB s*I #~6,HfcN W198EoP+gȑ) i=spFO["#Ȅg']1Q`aHIcؤ{sEGizXN|>Sv)P;ޅ#^uxUk߆G)= yT4ZQ-Xhr'{+Lr(h9ڤ`7 wcCn8bvfV.J0 ?Ѡ_FWן ۔!G;icJv[TW +E KOzHanb>{*g \JvgPBb jŤxxrxDl~ 9D~S~5&Ppa bAbjİWSN&N[Ե\>ExA0VGQ,L:9ѫMvj{RTdQ6p:qlǒ[ 7k9Hǖ50?>ˡ,3>9S7Z<:#L8?mO!*gip7Ww7Vt^r9ߟE ssTΖJ PN=۬ӫhb0Qx2O-H] }8RW~L* 'o-ĩ<FhB* JE \[ӧl'Ȝ[άsK"U*qyCkςHt! fυ.NCR%bI}ExBpU1N~K4I?ʱYMHtF+} k1Bzazz7CC!3lnSBAE1?2>.QM-5Ƌ;ŝ4Gܔ(+;5L5 [ l9'Ԧ}mz[ mkC"qT R 벿*`bg69C욄&--{Ha5C,a 1|~?~ ge vJG|QaHV"!jMX _`f"9Znvh<j1j R[!k4ؾ*a >@XюeBrO9Y-~;xrsWDٰnqo4Fx$mB.e\aS0 s"z3x4ƽGҧ91o-Bݽx;Ef:$1RVRl@CO ݣ7=P^=(.f='\cp14&P$x~qͅ-Vdr ύ#rmo8@/L3ZPA߁t)"6r,d\LAfŠ%KOv1`}9J"i)p./TGp j$nŵL[KN :;Λ5qd$UWˏk1ds# "yyRu.Tq[#JrC K>SCV]k'\8$QRƴ4Ոگ'MF~̒}(GlKIzr (THeX`u@aJLDgU)0i;i-bM! Ae]XySԘrhʐfo&QN?3"&"ĿFn{J`Jn=ݽ'fuvw*%zf9;)S%7ٝoy|6]trX+*6fr`-g>r<?ť12`xT #Du] xNw,X.2wzC{cd"mbh{jo+[l3sp{gvj |NTi#X^/<9vU@c-r GD&LM-XoX)4 7}<X#ҙübAi .2>S.XrS=sqʡ/all&,s5TE{7JI9J)چpAO!~B Ξ>P!Wٮ8cr~iOre2^R3 Xt"N+v.iDyX jfI ,mylO'a^&7%UhC &Zz vewmMU/K39yOǏl:c 4+W;'_ޥ $BY>71Z%_ݤSQڴ:ID^ՑTXke;Imet`Ѧ~e:2s 6. H*u ֚qzd7PI\+.^ ' x޽JUJCo2HFH+3Sуlp󌪜i6m8bKH (Dmo)h/ɃG .Cx:7Ԋm3aL_MN]W;29 <%8%Bw%h@W ymj3jWHXfJ W~opB]Ut*̎8g7^4 9sr՛w)$FC"ZR'ki[id~5Qiz }mMy+}(s ljZ⑝bm} =sE խֈ,'OC" wD,J$8Z2i ,up".\L]`=kQyzLUQ8Tn|i)y(ہn䥆A8alaY`3 vY#Vݤ2]zRS(d_TX{ R4&}ODҗ"Gϳw֜o

    U~bQ.;f}Cպlh?`eTW{&AY|iz.폿ȗ<.c^RK;"Y0In]r\H9@6k9mMW5H70u W|LTºSM+3e~)^=c~{8`y]%|]0 =졓 Úx7E;֛/"_^2*!W#x"rɚ#$(dЄy{sD DұOu5Qh5a_RICeSyyqidV䝄8k689 kEFLGZQx5hޛo?s3.9Mٝn* eC)pK]0=)D.=HGV TG$}:1Zh́L $u _ޒ79- FL#-o5AR /{!Dq`.E19]FGzq,kexIPt5+po5b:81:y3W4U$v0g&z ]`[x zuR_,_T"e-f~czQ X!1cc= ٓTےa_".f8C_'Wdy+UqֻH{.Gd{7e%Wmt;:,!={|HX2ܗ+</k*(Xoϒ6GScHU Jcq lBWKG/HnG"D;b}1 SW_a9OџyHzS +. tð7KԞP6 ;'X۠=])X91Pd5s_c t`(#|%)/6F%:>Y&5 +p!zPr; \lEԫMJ4/!Cfu̶|$kа?{*3ZSzOWC6zPS§H35:-9;ʿDNq3UIY#.Ӝfy]^vi 0WߊA>)Ϝ(5)bt>X͓Ǯ%n2f r%̢ݎoȡh^yC')]3o d-$P*/S hs}:6'k\{(Lq9ɦ}yW3f~~{Vl# RlrEz>tEȆc]%Ha7sPխ0wHa<ϰ6w+SԼ`SݢkjI_z7lޞ*Z[ 3kv!zGJkegyŊqX?khpV5u7u+%'Bx{M!]M}hi3iH 42R*-bKRW&2YR6b+elc=e8`y0;Sϴ$dOF?`7vG`Ϡfm%F.3>ؗu_!sRd"@n&W(2θ㫛 (ܐ.\;br-(酛L'q}}{ZRXIl`D7)8[Nk*J}F%1c\V ŘĨT10aR*T.sд+yN;%QYVpTTߢy{.s-هN Қ p鶯fԌw!m d 1@/,i#;!H_ջ6~JJ~{{H87J` endstream endobj 208 0 obj << /Length1 2238 /Length2 25497 /Length3 0 /Length 26820 /Filter /FlateDecode >> stream xڴeP[5;wiwwh Kܝ |3sLY}ՔJ"f $ޅ '3gecؘٚXX8()Ŝ.V {qc /h`caAHNN3'@bd@.&n==E dea;#JE2Ʀ6 wg+@I r7Zh@9dPjU%TTR*JLU]@NELUM] .&j0UUڿ`(y./&$g VOF 7Ts'_ 4..L.L ' &ۿYZ9AN6W'-ڛ ge wIi>wOMjciWholob 0 4A @OEA+ӳ1v3wuMAV.[wgVE>IJ1ʽ ϞQ>{&p|pXE*ao&{gg|Vsr9y2mA^k5733u3Wfu{+GW'}7!mX@GԒO>/ce|Ar6v\\>^t7B`Y U9/;oi:' do 0#0+\@^ v@FYzwhP$[9KZy͔\L-5?^##w_:V,#+޵hjctv| >>?l: {S#]l/w)= ppulGNӿG߈ ,70xA\,fɿ;车车轊{Yo^S?罊蝙车+{Q@V3 {s+ W$Xr-ߧiNߐ?;3 {,LYߩ8~ 􏥱sSw.l{],X;;w?g6wC4c{/o+X=ª.N !.NV,Wʿod<9ޅ`|%++;ו~6 h2 Ni )(.a:ԒZNn'! 7ePy}틵(l_7Zn̔w}} P$Dr42;hdrK8f2ZZcb<]lohWdzkyEsMNKK.o_{EfCd`zPI.S}.;' }zzJ/ )QhOn%,/k~{\mɑQF=ȐwD}kmEP( ],kίԞաi,mH8<7zB^Rpr I 2v٭䗶> J0!m-me0)MɼڋltWvĀx,\cԙYqB;DZ.9ZpXsc ^sfFPJz^E)g74Ke|j2śnhf,ozJ ̵i=!-kQSCӅ 2:2 |Lk\'IZNP/:ȑ"P|@@Ĝ2Sgv`6]YiZ{)$:sU !;6F4Υ ;UHw1yՍ,UrL pMNf( $yfBN=F, XRM,' o@ fGN];۳[ɯg:Q vjШ7Uv&n.~+8㩃'u/^FtPOőf5Tƍ[sVU#\Z'-Iu&]Wqm٘$Ɨq#k J-y@ rhF!IHδRݭ.f)r"mⳞ&{Ma@>)3aHNDI}o)J>ߘ;%A.utDW4$+Lqa(Fu`2_=vo+GsNь:JO 5Yx M<'bK}/ª8K?3=q|r?~eEeվg))큶i,+A kb '"m,ˣ gWgL"NkF.F8Kk+{֪<)c,)>D%de*>gz%uf$ "\dt(hG-]ښv?Ce̍Q2'Q"L,Q׶/#qn'6Q]uj)9A Z!Kdju7|GNdfTP8VSg 񲐧7q 4IS7U<378vgTtgGdLBKa`BlSV=šO7tqCx`ZZ!}+45EǛ^g$|Ր|-~SF[ Vׇ<&F6W{ F4NwDn?~aIpVh> ;㮰KAitJ0rA{@S >Y;}jGo*ñ&`?'{ow^qIK~)[˖#ͲqJY=R `P-n 2-'Uы4|wp%#+HFXOQ\*6%%Cƒ?!o vl=S:ZM==O?|;[dk׺#3hJ,Qie.a(Ni Ϗti3}doZ?$HubD~r҃Ju|Y:3-T}{Iݳp¸=FCОy~qk`b}Lek9wyT3#w lB`qv$a FKEQ3j#P9Si e:ˍwK j6M sHeyvZj+4)H}1"l*#+wnhl|&~<ܜ݉t _2#E)q0e{c*U=R|Z/nY a]b?bVfTĠx|aB)T|C%,#wd#=&܈'@e(%[`~,gji O+HmhF_/m; 9@))Bʾ 0<ص qDQd;P|u2M]sP*5ښ'O>B. ~v@7S߁JΞE1b & ,rEi#tl`(P04(bmLR*)ҷ7*jD`}KKB5q5rn6<^&oǴ`>;s7 իԶ}TJFw^} 'LTX|uaqi`4Ng-a%#f~] vʦy[u \"BAa^?꛳/5 zF 7co_yyt8qj"A+$6))df[Db*LFC\%S߮p#̡gu]S 5Ck|qóR-Lʔ/-?>"ywĂjw9by03r[GlcITkQ;xbQ`5?<6SH}1 ^hl(VOs3<DT }#$%cpBy 8<+0Y'u['yC70;ؕ=!pi6Xz&RFJ.s&,_9fޣ @cK3?۷4 $j-TVB7 w}yW^ -q:5+v{ІA+3C᱓0++KJ3{B[tc^sE/ E}\6АqY_: Jǣhsf]/ڙGB#*CwMTI+~fjBht~Uy{lrŏOݾf Y]>aӬҽV%XoWMǐT/V/\D[ <9U4Y"W"EkgW:/ \%{f?‘@;-J#?`%D)h jh*UC#Ʌja >ILYX# r ,]pIQʪq? Ea n߬Ϡt|^} ff8Occ/=Yz瘑ɟ7*we*e?oZ_D[>Ʀh6 z̢lIWKzY6)75y6E3cú\.ZX[ڝE Fv}߬q:[݆ "V{0SgKΟ~Aw`/\{n-nݸ6<+-e)gd\n!7" ~M;E|3x2b4"!̅Piq`Z%8G`tK&li)cQ~ t=p,&eh 9; Gu۝e4>aJyr{r *'-1[$ƫ)C}w Z }1ɉO'oew{aJ|ނ! BNlnIT$ mpIBaZ_Cmcl6OvTYX _ahpqt7b66xsǀ_S8FY0."QKsƬ-4|3=w4H~_Lch@m,V%dXBMϠ4SK] c1ݐ~!!>k,U;5ebxw48:x-]O'}l[B?!$<#$)!cmbrꊶӡ`w'WɞhM9f/AAc^RPQhSdxHEUȊɤM++TB.L$trWyCFջ\yeX8LG[;KMGhlRoȢ<wP3ISHx̨kyҋtBD)LImX ~r/Zl/>;{i#=Dҟ)GzxdaQb$rJ/^͍|-Jd9=|C7 &6 = +QEN{y=X)].6tfs楏"Z1($hPm ;VBh5?CP io-QPKŖ]rqMS8r)"͠Cb 2.޻ ϓ̤p7Tz/bT#6v^&!O8([#ZN 0v ]sn>fj~&R ﳴΓ@^t 'vAhAsj?DjB; !=A')b4!823PA8=\mpME]TcS䚃e<0i,{")xKF:6>y1?;|kZ+GD:߿+Ly pED Ґa% 599I3CoLY@)0&2urS1  `W<] rIKY^"nBr/b- eme5>hSzBE[邈סXO8j@VR@77n|)#CLfwL ߐ){١;.H߯ x55e3sXR)7A=3V}QҮ2mB*A:{)Ohm6tyH!n1|xt$] ͧWj!~b9Èm ~QIùn ~%>]VA Ia. mNPp-&XGE}]f 5}|A޼,/r,l$Y hb_u!,JqJdS(\$W5J !;5T[B#';8}F]h7!.M!Mپ&8\}'c<(QW/%2g||5!@5[a>( \Favو~2x+he}^ekp]Ҩa}|n곪{.M""[bE==Wbn_\ ^uC>d?#RŜm[f`*Ood4i<}3LwϿAHy&RA]0*pXM)8~Yݱ=@Mq.j7~JfNn5:޼>̟]Dz`TlB_,p+:i@n/vҞ1$R-E*(:4M=mw9=?0dR^8X@ &Xn CF I5c3AvV9I#\lߗY~Bhw 0xqK'&nc>|Os'573G|84$~HŝV8E=bn"D擂-J) )rTy) 7UIX4UTWͼT6:Ϻ,W/^عzFphפ93[֬Ղ~nDB<5[x*gL8ɠ Q#7+[UQZ=5Ic=Andsѯهe9ը+0G }QEdGSVء r44{dc"9֝9 $gŲdbRÂlZw 3yW5Q )oMCh`t_ A6'=l;RYivTyi-#"ic!)y&8`:[4~#ޠl֩4SPwd`BFl'&6xz#oQ4E5 ^j2HFA.À ߲b z貭¹*c&a(IŶCˉ^`+6^5!BYċ ;J.բɎtsMG)se(:<|,G۶^~u olԗG2~{ڈV#sr$٣:I+{`&h u QOh}^\9W@WJ )oZUR[uQGR;DŽYk?r!cpcȕ_'P:bJ!2&Blj[?kT@II| {G. #5s8y3[zꑣYE֡ƫA'_NV=5>ZtNj/!L~g*jAwE߶^~x?nMRKv63i@VJ99]kiE訇.뫨 FSHM_bk`7Qߒ iބ6o$ ߅uʲ~t7xd))M4g跇 * Z ӈa`)tUc~#ZqRz}Bj"(jy<3go;ן Uc&*#`(4&}]Ul!m:YsQdyS^ųzx]y+Шw[VCkȎL%8& ]k}%ZDL+8T" hp$x00EyyH& i4DvvJV;uZbEgnWDd3a/èsiVPI3Yng6CأLPLƔuv'nr'T-e*w?97%=Jws9 Gh{%L@lV*6Ҽ>*ɪ%<Pӡ(࿰"S`r,-^nCO .qd87k$Q'd`̴ƊC`b;!*]+r}׃_[kb{2Y\yH_fĹ ֣J+xC[vmU)TZ"_Mhyg"sT*9'$Y #e^?.u+h&;}APK 愔?9O qǶIyCYP/ aw}.>_= ꭇe:4 M =/[WA+}`.I|A6pЯ%C\#.8U4+ic5ň΀42r(JܟB|NEg{dP h, JBfyc%/< Q3 3mكrm "D_ґ΋{|w[N6SpȸGhC 6Jj".,W0|DZxa#fʂo g(gmgqWq,&=bMTw>h+ P,-1pbf=EPg| &ɶe` d;P"k\-@#]no3kK\ /O]̈́hܪohG!m9gܛ $ &l?=岪"2'I̵TTTXPgA]Hځ'M+"K~^2")2]CsM@ a9fZIu$8GX!hζLTjηBl7~ϤOzI:#P{TMB,!~snNKJ1ثi9Va3`6ILi ήV):$dsRv2X(ɷȄclZį ۮq[H蠻C, ^BjiڗtM{G h0GXboEAt˒RA.>oI# ,bbI_D"TG)PyF 𔓅"I 2NT6C % :cDc5l7p+Ow}ur8Nz߂,N^o"{FnK!<}B%NH(ɫ_]37I"MSiL)@1Lb/B9!@RhV$meEl`gW`KE-{_C9ۗ,!>~ ػ]) !&>h{G5)mfzKTNT+\wˆ~#P'>T /cpP#zO祎8eVeQ(y}jސdENժ(EM;ldwӬjz\ˁbV_ qnn^}.ɞ BM{LAm~o[u SApS$`8򀛌"*2@Z^4 6CUژ-@ҹί8O6)}ZPvHUܗ6ܮ_-*+!9B)y;/99ģ xD$P %sdZdb Cl<-#sZ*ൢ3kB9y~涀W{MCzSMDPpK&WW]zU0_pdUWkfk35>Gv[Yu.l ~s((J*io+L~a{胬D=0^cI2RpWՅYH.o4ȧ_Ѧ\0ꁳy\Ž5 bVG8Qp{ NUFHӞ_&[f/ ' 9Ď$Xe$XLȹ{5زbp 0σ$dY؆+TaƒI-g[F# _ 6grd;9a.<r6ܞ7`1M/6=j#œR %n ҄01< K=tr*EM3 ϻ;9ُփD맆.QTk1ˇP&^+,i!dzQZM$?z6D[6g:i4.;0W;Q S`'m$ qM+CQ~%\D۶5jbD|{:{SO˸Eľc5  Qrkdk ߰;}"[ԑ:`!桔أ̦7m8{(T@7+PmI|a"t<'N.'$+3_:^ k % BҒfӢ4$|KJ"AFvOaBވ͛b`&= ٚ(^ <5Jtor>if>wC/f WMX2NsK}D %4 SMK <Sj~Wk) 芉J͇FzQl4+dX+-bх-m/F|얀#"W)vos)G1>Q| _|VJ"*7<ۏ}>cZ#N':eg0F }ʼn]?9FzSteSMFf,0 JaPpYb TNN^ JMoU^Ïe[%ZЁߣc9HE||۰|aaY?[*|% l1mƕH5 Mc8%4ˣxlX5'[da+6KD -{, Ⱦ G$2N]cFd1|B[tݴ'%t72r8羚!n?*oחWSh/ߓ6Ra|c+"D(> +LhcSO іSc_e-H hV>@#^#T*V?2]riZD "HاvxƒS[vkvj͍~U6ůeH8|lzLX&B7z'>R[0/'>8 ?9YJ˽B{ypu梛 u,|]Wp.-_1pl ʕ n$6hQg _@2TUK2uY81]9c􅟵=l։a~dɴ[:DΦhG@ϟR10^I{.;H0j<[˺a-w@ȝj#ڏG&PBꆙֲziH7X9o 77^&b$U˶y61}]Xh=j`!l7p2V X1Qe?訌cA hۈ2aCl\ZROQ$|_Y:z\P6=j6D>7>Я`#reh*,0T$fբfw$\/7ya03&_pBfGvVO9mj8vj7l6|'wXXӠ2߈jLMMB̌WK~JfZEׄX_²#eG=x]Skh}9v${7OcgLڭ,-yL]'«ey6i7hۣjG\Yp 0?mĥHu1ۢTa&1 9Wq"!aمy:L`%p^OqAXV@֒iIGrkS `2j.?_UѸJX575myλAr7əB>䣹mN| L^v I|vz|7mK9ʒ8g6~*$[]it>~B +9gln m)^˖ykG;VO{GZtɁ)iU͈AY˚ XnM虍~_kHn'֩-4?\]|2ьreëq/ث'حьsDF\mt~dnG*|Jz=" 63kpՎQmiAEއ4U ]6(hA\+KMNO#zUcc;N_4ʴ|QN{7#O)<TkĴĞD8K/Czu҄nmK?Rs2NCZB~ iZvլ`> YˑtÖ91^X ?~hCSJ*ǝaS<ǹqZ@Q _i LR (F~w[+!Z+ V"֕Å̯M0+;W5j 7$4;~y 2XE5Z޵kFC6{K#;X%+PF~W X}"ɍ)MaJΖNFǛO4Uf*57]rNmD0x?" %WH5pWj7*=c)Ty-2 ls}W1Yr̈́{kT #66oD4saAU{1AMAqt?'o]85C81 Gbbg)=_ԕ @m۶m[_6'k&nm˾폸\3.,YUpK&3͒.Ιa½lh>K.0mk)kP5QP BKuf-l e{4^q0Wq*GHg3]8G2X#EE!?X$KۼLcQQqH$#d XSj k&룃`&&6P~P*=>YPkTĬӚ0 hݠJC9OZưoڞ[cI}2hj1.m{f4˖Iysgd" e8oEP=s+Xy59+E m{s,cܟmNJ`C=C[)-n{E ]除hdn+ l9D j51_?5 漭+qa+gȗ*&bѾ)ݖ9LGm鑿lߝ <*FQCMJON7)QM9 )d[~"2p{zq=ag"@3+ӨO"А`r!^sƪu߅:-_HLl/*G.@$g9?cB<`L%= ғ Ɔ/2b?Sb[E ]8 [M5%)%.~Gi|$@c"N=& 8S(U5[m}@o 4[cS*;SoKz},/ VMy o DLg9^Rd F"\m=F2#%`DXX+('7/N2^@9.'R bqmQQ`wQ' lv9l'KPγVVk$$s_eȀpX~IT}ѥT$ǯc^UP&Ȣwbd|"?P!Xf'?VVyqdėؽa019 %;8\ % O8/+ 5.V/iXWЌD?xkN7Nn7 W]z*t[E ~NvApIٓf.Urzoc RF+Q$JnphBs^J${(3qw'o9'&/y436c*ց9m֌MzS;:G#liuyMJgch 5m9Z.wTtd$ԬXٔİyQK{pF'JI `4f xƦ]GB R=e|IykvI_ɭYT=}NwVf]ٜؖ<2ulNXp<pu C8\Jݱ~PWӬ"ީSB2t!}3b~+U#֥arbE{;TOkUq .}q~T /X nY"xѰ)I.x5BHl\v'@H x%0,5(&<fo}OZ_$~̇j-ESN&QJ05dksS.fɭok^$M> g$;R6 q/š6 .&^B6h2v10&TO-&L+;Låc󏻧^tFbSf0*UĦIM`s}xyT1u#3[)y~ѩ6;:H*tʘ?q]hira׋ ]x[.Ƨ,Rps:R4Uy"Z-U>zq$1ؘt Dɖd&3C-ދ A9T~BKrRa u#n9U4CHNI =al>ړu'VQ[2n/!֮m̰exb-Zg#%Y㔍)j dk$]zd l;<,o%Icb='DSΓ1 J?|ti(;L} }up'Gs#M#FF2:,r ='^E0̗lup\{Fe-8-4||is9ʔ͇^ƬSA*Tڃ!hҮ搼xoHh.B=[Jebp>NݚbzUTNv{q5&a:wbKb*ؤaJK(j\vn.'vIRlkgPDWGƽ c!B E!A2CM?4>TA7(6?ż / !QglWzɬhͫ;Z~u& ޻_|9eP59&YV?lotGdgd%(;vU7}nog)ê巂 rJ猄p&T$H߆АzaZ`\*sW۱$.1Cunk~l*ߑԥPYk!3KK{<d&i= طngE1kL7o]1Ip#0Ŝ@(@/ovP hUBJۡ6N\Чfxp~'O5e;k kg GBMfœBLޛ .jT.O%'+הOMpV܆ĉc UrR2-G!H#壃1Wd\<YԬbچj:yhY I{p1ywMf3$3K b$ pNC쩪a ͒!͊`%ebgάx 96.}glG/QڤtN9߳:Ե{TIWK/w!Iޚ؄%P2'Vސ\cU m[\]بͪòvIb`{&L;N{GO@rn}^!I"\EHzQמqu*]FSA. Tǝu0&#幽Hc3vu_En;-f# Q!*;LdDᯕǫm)CJl[/ogyv-+Z>}DfϣlHP13BjN&T\~h8@lg&y4l !3INK> GHm{HPP#*m $7s(, Os96EAj s,xH>3>TgĮk|/QbijGzT+_ocj3 X*5Oιe6̬ԙcQfB:>KMOo00oB2"QqCgK+ۭKf ;*4v*O{nu_. s0 g5h/L{yg0!E&eOS"Œt($ChYm犊΀ffʒbveQ k&}Oc,`˼Q|a=kR;4U|h^< hs3N҅ Fg_kOAklYFih. eq<+4B +!Fl#l@rx ,Iףi_x%xiÞdYE Hh|zUkHtJ-z3v̸Bb+a{GPK̤&@q5'cǔ\ bM3G1 b=+$Hߎo+3\N % "|$eC)Üu{죧Bg i^Um@[++5FuחvG9 z %bWpKA"X"hAC0µjJoMSDUƽ%fFJ /m!s2P߶['ÓUl`,/.L|ʊ  =$8GJFIN̐Vr53h WvU^e߂)ujh6sCZ"g)*'Kj]ǚ5~~Yaj@ Z.ad2,#뽥Ҧ@BT(Hl@w-fc>JQrQY\n'iS@09iHXXZ*{EXKjC.7IfFrW0k⋪dDݮƘ]_RT e X0ԘkPS5h;JiAM*UacY/`>`y|UƨLv0[ˣ+VQvzrE[͉|Nm3[J WQX%+R=,j)JoUp(F@U ".l\VYR 4 ӻ9of\4q#ҋTPR?;N3C+Dk. * Mb*i* #NQ|B֋/.s)[3ka$5=F.<  kHe΅4'Ko\MV+3?+7u* 3KW!sCY,]dG}NES1aS[cʄ0/]m\e_z}1bƵǤamU(1I;L (AExݣeөa,~XOoha?yKDW/Oǁ1—V!D/ \MZO7 H{=SZrq:͆S\pF5^Xq}R>mLpGɥf!ޑ"F;@ٔ֝Lm؏xL0kN &d>4hwbY~TbKB"^kƓ&="KPopS¼vM\̅{wPپŮ$'PW%#Nd̔D~_}d*M*Ш'˃k4PǕm=7DpuǶ֢|Suai)j4* Eaݓ|1v*^(|NTڥh S #i'$9bx΀hdž>C6B|鳦 k)׃?QV ~1n3 /@T{ݲwp|,GjjI~MjN gowT|Dh(?zH VD58 T8rvPp{V雉qTsnTKCݓ jh3[DEu`ͫ'tQJ#{㻮͆H7&JߩC:u亀svm!JH=cѣ݅I?%jXG}]4O((m|PAvvXN#@AFM(ԵRX ؞fgLAq: D2줢exFYBK"w7٣2W4nݞ&uH!RzX8r sN  /D;"93tZ¯=8S)P&Mn &ܺ \g\7@GWX'i^K@BXt I[0[?{3zq*t[sU{Dƙ=MnAPdb9|Q{= |`|D'zØ/ļ2 ^jaPU즌-- ^x{U0^9QU!&!%huՠB9*#jTтk#f4{+[\sU8%oC|I)ٳY ù-ɏJjZ(e2;qeI)EDָo8%@dFG".k y7B2"Yi$iJ\bmHKRT`"Pjqi1x==8Y}?&a[g41PVGWQ:kyutKe\`>.t,k?XUZ^\kwp@uݽWJ.[R;b@_ 8G>7=- *X ]hs0GZ-n2=.:)&ߝµO"x0zn;)ڔO¡}(; _uu( =wQe)&' x,{jD0q~xs >UPlUc5B CNN}$ @;7רpS 0_.Zwm~ԥDUK5$Dzasy=y!V\׻?T% (6*:Sb,S+:ɲ#u?MB"P q_.\zʇt?/]P .\L3ݓ҄2dEL ǘ^w+&NG ך8g Vs]Y(\tG" 4}VʥGI/EbA=ǃH\b 2G$ô2M6%Rq CI*!qxS3+/'j4{S4b7)^no3ifqPߗ zX;=x6ɿ0)&l.#bݸNum}*j ` 6R~Cts^Csy~yϪ\e[`0VA7krө_K), ƻmSd}ǵyA^GN Kys:G/d)U 9dx a+'hTb0Ҝ?^iv9qЪ頻:߶Vd>4Yk2:c Mz;- \(6z ޽ ]Iӎ?p,]rkol^ȩ(Kl9kX=ǦOH _æQv.HO3]d?:.bK3"OEO]?b endstream endobj 210 0 obj << /Length1 1695 /Length2 1816 /Length3 0 /Length 2864 /Filter /FlateDecode >> stream xڵTy8@l hf0(  hgB (tፊ0R($0G`=<x1$$ɶ#7Ɗ"B8 O47E@(̃\rXLG_&pby3xaftT*Şr6tO?G2,FpaKt/ۑF@ ,%m`oT6DEYR(hFFa(/0o!,D#NOaDKIg$N%۱D`p  4DB|aEZ `$@G .mBC$&ASO BE q("0dEpX^$93>"1螮NL?=@qv2I%GSGcFFE }|' SE$G8\)p(,.vula0^86"i-ULqJ("8υ!QFI;~\hpCVwE(4HȁhDIZ(()O(&3SH DOT "'~cl$ɓRt$L̈́L563$&e_M|&MeG HLR33=~o/b;"lG€B(@bdj i9pTBBFP OQXBi4* P1yKFV@7_2隉 ؟oBpB~ܯT\>4܎~@˶CIFddjbR~dO^*R\~]K&p&tCV*Ov<\:Cۂ'~R~6[VZ݃ݟ{wīW꬐s;ZJZ7ʶ7 m'4:vfʘ\z7,uxyӋ oXzof[YOe7fm?Ul8CgAnJމ"3e3cPI٥Rx-I;Fxeu;U?UIeϵ r~}1.TsoJݶW3 k7+ҞR5t}ŏVl8px'GuCJ~2+?R-&no!/ȥ4nr"Osrb RK; k^%􉯖ɧi ԙa 04g V0kXfW++flr%KznjA mSeۿ4)&-\'bl[D.Q qF# OGkd {OXdt r?~Z!΀3u$JdncCC}ىVI4+(^vw=ʖ'yX]UӞoWG2]Q0%Oذ^O;>{; ,?QziF"eëOJĆ\[gn˪ Tv1][/I1M=+M/V8Z?Q"XH֌9\c8~alB1yi,qOřy&:[*B\b6:Ώ\߯d Lc捖ȎeZ'l04^ec(/0=6.͏?7o9d@8wK"8&;j?p{t{˞3 ֫pdT'at ,&Zhفʜ5c Lm.;\7,> 2LڛOԢw7/emcﺮ+d}` =Oż} N$?򑉥=UҬfPi<}޷Uusf.<% endstream endobj 212 0 obj << /Length1 1690 /Length2 1466 /Length3 0 /Length 2507 /Filter /FlateDecode >> stream xڵTiX RE)xEA$lB. (V}dHNȔd&L$A[VEAEQPXAв"U[ڙU?3Ofr[;S"B9pb9<PP Q2/\U!sx<{RJ5TC.,G 1Hи'H!Έa;!ib (]I&%pgLLt !Dm "-A05"@eP-R葤'`Zr;y2#Q"2B@UaO2gb[P$f8C(7O( J0Wi$iDD2IX(&W0g j1T CůCh-RRu2%)l c3f!  DEB=B" -ԧ bQab xi&obpvBT@,hi8&nX J%E:Qv628FT0 BuPR2PCX 6_{ !1̤hI\l4j%b$A/ӇPh^H?++d'@Ifhyyx>y9 Rz s3͘ +*T,d @[/2:"D8;.4s-vyo{ @\-xyʆ.l^Y3 A |Tɞ+F9zsXdže\ WUmwC|f bXۏg.3W$5"L"k'-iNMu+oAqv =w橋;*i5 Bb>M˕Fԟ26 gӯ[] 9sz|=]xj]䣴{vq(sy]xu{ƥ;luط3hKbWl)C~SȒG}!SzMOٸͲ_t׫$,e#앇[QiضhkFf4[_kM>p]Wpy8\sUo1]0.(XAS! pv s!>nIB8^u_Яbtȅ;B=v|"|Bj&_NoE.[ 4-gu[hu)lv!1gť3Oˬ59xEIO3MZlkhZQxҳO/Ϟ}v mF|y \$fx}ALc_2xzȽ̆Y[;&lwpYd_TiklEBA !kl<i \ujO_ [_1fL7sPHܻbxoÁArGMb$|jyiHj2Puw^+ooY\ej/u8^qfwœl/:jGK?5wJm.kK6O%t:p!f,q6W8jLg[Qp|cL6ھRVvQ䘰mbO ݽPL?s-+h_ `?h?;䁇yUfEN v.dϵVLQiG>NU_19U=z`'wWyjt+,39=dL&t?XwWdA5Umbij͋P "#-?jtsaXɜT^k굮?^jTktkT5`F kr7y2>rm+9V[S"nbॱW-ZshIa&OܰewQ'_,>nŧ]>$Âx|4◅&8؛![Y_9ŢyF.H ӏzY1~Ɇ_[ r˾58sAoٳG{>{(Re}v+tQf.D`sRp1LUY}W4:\.bxW5exޤrqn {L24֡y:p^Bg5>۪]oYxOo;˧YJ;7}Q>dELVow~#3XɧiYltҮj zcE^٩~сm? S endstream endobj 214 0 obj << /Length1 1762 /Length2 3476 /Length3 0 /Length 4583 /Filter /FlateDecode >> stream xڵUy8T'bw5k{bƖb3eafdɒ({YZ,Q*=Ke;{o=9~HﵱSBb1@QB(õK++ ˌ{ JD_,PVù H ' 1P @S;П$rL@HXX "9̦`C$S1d <P 1 IxO/ #%%F&F2`!R>xCVʀ5 )^_@(@&G6vPb@"o,v("`F"`C1Q X ;2B!QN6F Id&fc X/GhKH cJ(S5 /e0XKK'P@9R0@2ඩ+ HVH>:oH(0@rz=2L!8/@Of OY!͌PJJVD;e ȇ45U0xjD d.F P(D'vTBM8<cCp @Qt3 5Op_2ǁЋ+  ) W q=(ݡnFj? mPT pA5x/?%̸\=D({guJk*(ݭhRGqIPL|񰋧 Q|N){=zxf&r^i^@R\"ծ̚q2mYsJTI⚡VjKDNZpH_G3eΤsngv?z; XDF&mC63_cc2Yzg}B,f7 cuަ ւ{<=7:*s mhM0ބH6~q+*?Wr<sʲuX/eT̜KDkJ=w!wEjUu\k;vwo\_ ef8oUyqj47siOH؃Nu}'aw ,YzNXsJ_L=X֔bm1];9]sbbq9L,V0C Yza3ɚ-,,r½%iSRΗc7/ ?J{-v׽ơj+3.kH5.?es'Sv)ɲ|ĭFp*ZP@ˍzqOK4U1EX(PijnL<e4uzРsϽX*g.YH|IsgYWG]G=卫]no= Vw&+TAD:W;;.Jr *;$ɨӥh&!0G"Fu9H=u9qﶅߜ3O?wwj'3)Xu_zg)`[|c96J@7xSNX)O 4TYQ] Y®(ER#:Sg}Lے2ҫo^rGib+I \ H4m#fU?s V{⮜@pQsԩЋRv0ܦ',45¢R3=d̲vbr߬ y0Ryw:BEws-[H?j;j|1ϻ~ {ƕlE}\_bc$:!2wp蜮+IA6fK+_I ~rX(F]gF&ɍ'IHiB\|^4UlNVPI!ˍ8I!{&aŖ΅. 2:SRHn8o{&J4s؟1&GX^3!o'm_EەD,Z䭙 G\uW#D0LsSYю:b^г FWᖦpscĿxSc:W? t?c.rڜ%Poeێ>sg4ZkV'<+ԅ y+-T%+wz緯%1 f8Rƙ$0 -ϴkjYN&H=%73P@ϟC^A5G+;'ǖL\^R4P]"O&,/~Tֈ;3eE_[87Sh/f1~ AHT!ꎝC5iXWq ,F7 ʼn/Q&UCet*Ս͆7BNaU8N-n"Zys{ʞ:ZXGr1)ٱfZ5ٹf|b_09ZM/YJw֯"rgLG ٩p~n_֍pM8:5g `BpjlO7.x(C+͑B˶t^\74<556#?ߖЁ=zLLgF ;zbj֎i{#\|omx 1ZRb, eun 'uE{3ࡑ,*[+OeRj8pC!3IYeMwEg儎)Z AY,.I+O"dp;rt4$܂:n\nӺ*o>dDFjNuuQ훈R'VX~wZ(516[ 9^9(ee;ܛƌ{-3ڗG2/f9k,.o+0+KLv!ƿǔE T4$V k 8I%Wj?@/4ծcu{w,6woZP'u+'g];!.#Xb.{\+jh.7cB34 zUqmM[[9-fؐ3ָY(Te:šÚ"f"KHt3{J7⇵UE烌ßjO|A((YF6]7Z,UsݞёSNzY"#{px)x̝#LNr~X9ɪ"eMZۣpwJt3V(^OtVTk+vVU/ ;9Wt=zұ`wɷحs^xWp2ߍ).T_`d.pEFNN/nmw\A6Wami/eR=#q]OS}۽3E^~3I+Jr6gSi#6czXnXzʏ"Q6w'w aڧbC6Z 0ĔglNbZ| & ~p׹tk#0P=swlhkfHYxk܎=DM# k+<ܒ5>:Q_wIL4·rx^=ǡ>QK_5o] [WE/W7ċ PťU/bKTn ՚MVuѮf휜z/!/|Ԉf5R O8{xX%䩠)jՏ 9 aj%+9hn֕σ>bcR#bƤ lkzqLe j³ }F򤗵tDo 1XE:|Q7Z̗SFܘ״yFi endstream endobj 216 0 obj << /Length1 3061 /Length2 35549 /Length3 0 /Length 37170 /Filter /FlateDecode >> stream xڴuX[>Lww ҍtwJ CwHJtHtw ݂4H7x={qpkjruf1s) 7q`gcVZٙ88Xظ%& IW ?൫@ `cCH`9 t5rL* WfS`iH-\df闷8 @bk 0q0ȱ(@`50ZY@ @S]JM Nr u Mi&TSoPrWUbgUtvр~SZ8Jruuge`tsqe9[8Or_v`nV`mtprz[in% ,wbmp/_+ lj0KMpsvC*8\wf kW#v_]~_2E1%7R s`Vxb ^6; P/;)A1sjWWTc%(Uhw/Ֆ?^[-3̲MSC A w(W{;tvTg;p۰dDy5Rt*$şnRNySĆ/Zg雽R6x8\\~jr B+]ޞuȟ---ht撪`OjiҞ33o~Gl*~L&hnky!/(!hhq&W/DLzkX`@1>Ya{& rGOnrL<}B8Cպ{&>9hfH%w @cҖJ RzErڟq|\b젪k.pGWcOF,|&z u۲L>ʎ)ƃt> (?MCXB3]ΖdMU/ l-}-4w+t"6 UGm(Y; lCl%BXL"v]ީeIU X⦁1W[}=LXi'5PR0\!-Ej]0s˻y^o1V-4E Sr # B$w#"]ڏ!ۋ EA_EЕi"?o# 5ՅbWr?H2v7^Eߐ3;. b'1fL0{ֳY79NBNO '9*Jďƪݷ;'+_vv~.?aÅz~Qo$ouV4hQl YG (w"yz,tUBng XOCxw)=Vc4"][nrL6@2LL"8¿|{evyJ!k6TU%x"& b65U7ՖQƕڏeɊh.=%yddH.>0̡n3h390k!]+,&೒ˉVlpHSϽbc2?f=_7vF(UKXguf~Jن@|U~0^ X1_@ˊ:6m/&DG)jz$Oh{!cdbBڛݍz$/ 3i9O$4!IDj c]9B`֕7R.Ff|/4Sedo\oJvǎ5"f u4]p^ߺI uܑ#LJGtQ&=OUkE;aHo -%C[_! Obj^1IN:F g NJ Pc4~[>0bz W=%< ͦ]I?MW|GeEƎM.wsr]$^:Q?T+V7q #ˆ-훋y#fP(;H2YҘv7שR76Z#9h@0nbZ2=}I6S|H^^ψqP4Z-dI1Dh{8D #֌wo* Ի5GH ZpԉYZU堒‚RsFҜʆٺ6_u uV0u1sS)%vUFjjy3G00gDJej['aj zqet 7>-^T)<D-=`&W\E[6ЅҾ<__`DԺxs4e@w[(G8%N_amok|KՁ?;AhI8QP4 :%h{9n{mLJq\ٺ$ &ł"qi y4?xO sMdvs!6*'ofN+/)4)u5MWhs?<S`x^nj^˕"]F !j^%~QibR?+yBb`P)Q6F\qw U61Uc=aS{H0{OK:)·E=$ )M(}]0 5ހaOf5MW/IWO=gZ_Fly `5r3g20"_b`<o~YEss^(Hq4==@o0X/RgJatVQTȽ7h&qpm|ܣ~ CYZL9[OCmdݴ|UXmI`-Geb)H(?@F9s(93GAcTUJ-.%GH'Q?-y=uF0M>I8Lz['Yt[YfJD7kgjA(-Ky2Hoԋ=I zO\+_BKm# Ԉ ]2pˋT w /if: L ܸ9F (¯:%CdyQ}E:[hǧ:{~uqa`M0IĴ ߛqRV!< $:u|FX;Rk;Wڭj,Ό/񺛤J$pECFz֯ ݈tiioԲӈ$hA]>+!32T3uȯy~<bh% 3p̫Fj$uEQϪ3°|dL{NP͡qE NݚW!/mp±[';̎jV,o3:9klxDf {M+}uԇOP-sjf]#.T0׊abm鵜STIs-=ǁg,<]enxH? +Q~6,k g3*CyO\˜ɂB*5F -^ wEn!ތ}%g8*ˡbiXSpGEtM &zb{Ȅ /EFGd gә}*';0ɥP*h{FCgVnK/I5Aȋ;.N#,)ž*/2 y _/kFD{d$* }AUz=56V%U5Fpz GǤb(=١> i.uSf^S4džf x򳝦5>|,Dؚ]2hQg~H;S:2U -uekƑ2jޢQc$BgsūLcd+RGYbv'GEVBCe뉺pU>ߴgJJwe͇Eiȏm`+C}{ Z OM13hܳXB bSN" DٞiNtCS9S ز6# %vUUi6 Qk9)_Je?"1l&S@ (S|>\G;|Z-V[Xh3 eLqIQ+l{s!Yi[=l{1qlw텕's,Vh=Z&ah5y?%\S5+ RF \zi~m\g-M%/ ;-V n w`\hA|y7{b::\Õ @ǀ8j?Y}yjGXuVoE3ivp~q 7;{NrmnI wK6z68 QAC?r\U?CKu>Dm3D1#1"@5UIg3+Ó8F#KFqD/]1&< o=@Fsu*-6#»0BD $*zh1?v.%:aMf83Ij<\5Q!"Yov) ^ZFKrT=v\E׮'\Ļut+qT%I5G aQQyy*4QIhM-ǭ:@ DM QOBd}\4#zD>o_@up֍vڊ!_¨xy2+{"hKa CU_N"xO?g&7aJW.6ڻZ}¤H/A%YN:!Z00ľp&w4 XiDlXMn,lfI#-|&Mr\'uU"-9eR=S+*M1m+_['V,pz<%TY~ƕtߵuvۗJSi&ڛΉ@0@zǩftt^^E_,d멻%Hߨ,Ez][zL ghQG¾X-p|hA3+TB\pg0R;93 dBD%oDDAxd^K10ܩbt5;;ݨ6k*k 529Ƭ}lQѱ?ň}Y_|Dw5 4= )1h9odt$8N{q9$Z~ \(Px*Ǥ2Ws]˹3Qn.2A yѥvTN 3\ot၏4uZ7;(W'vlhzt;DYx\ c Voi}YYenтdBw GA?(qB #%dW[jaSZSBC%}!`^D<F{-mBlxb^iD,"s˛1 6 EQ!P0XMSa( VLP3ҋۺ վf&S)H0`]11|e.E,]i&Ч8<5u'] }U,o%jc^¶3Vg^#BlfS}F=I5YCZZF7P7@м߆UҒb ~tx.r*v+_M^|elNTb.!E|'bk鉩D 2@>cdnŰ>̯zբi~ W!V9$3*(i r9s2!S(K-Yfe>6ˈ=}>_/k#K =t-%_s ` tN VG |`G=Js=AJ"%OWVJTNJGfzjO;N6l ca~{g]Is_ļ=և3kwyħyNJFĆѢ Fi )$yg-[L -HzbT #xʲN3Q?7-R 7_SQz#]ax5nw*9~hx`:*7J-pQ.~n"Ob'*/.,~wbSf篯tO(mE\jAtБ}oEvք#9ֿe!;w{fqΑݹEl7ZH`#ZU5ɕ%yM&J3^Mbc 7t1; luݪ:j=k whP6wnr @A}ywĥz.g5:OQDN"V0Ѿ4RN^GYh74+f_vPO߯(s'mses(mݑYxSڋkMU";0䴮i}5)Gg/.:3%J]# =qcԗeiy6mxug-i`pŃ|xJgh'tk\$&M4Tb`S̟JSɑxx+S+7]ŎF3q3~vdb/ \ ЉK$H s Ttzp&mآU_Sunvo Q)5q1O X\>ERuaby<ؚ?5CB٩Ǣ9]zG2YNbR𱙂5iaX0ξZp4oҚu~GpDAN”zaA && ֻUvvoʤ|U,i8Ō2wϛ)OD$w VA+cmAg\Do}N#Tor Cӵ>aôFmRƖ6-xo&gV6R^N(ٱ`cJHWPDzN =kMh[ӴC`ʚUs҉&'C aD܀égH[Z7wMF"O1b)#5DݨPLE؛ܺ`;M?~ǁy#,w H9w(t^0yX21Gq XF74E}pzmD8Rϗ|&$NEެ6?ܙ["P,L#2_XR#&PY׸4H|3ubJ cTS?!] |672v*~+hvݱ%\pvSk|齏C݇:ut7p>MJAg+6Y-G[<mD1>%2WR.ueTޱkXt\o[b=( mXK IM,k8͌=.)l6~ݫG16\j䓸D+Q(>#5AY(1K /2 hϋ__2OEwAX$ӂ|sVv)B (09*e"*(!7yb|cXNFr)I^omKX4SS5z<]` aӰ_EV"QZS濶HxZ VibɯSN0yO <0n? .b2; 으h*i!=Vkm#RotKURjNg/w,dP7:OLk ոڞw=1y .P|O>֘sVݲ9^, y#MKFb'Ÿ+~5a7(_&\ !clWa %tYkK=j==Xx-`hIDDȾ29-.?# e*nf¸nHF׭V,Gfq$;,ޜn4{Ԃ%3nlë48X(gwһBΐ8X X,sU(N-yp _#{$db=82cJK?\ӑa&v=H~R EVeMW|t~GzbVY&DI{Y?GG=[سJ.Sb%$,OpSQcw~8[qV7˷9&168HIVjRbڴYY)kUӱs4gu~o7B{71̔ދc2k'l/e#qe~_`Vg03 # г0$k({t `zdjp¤(g]@iyPަ:V3,lG< QV& w~Zko+ͱO\xGIاxzSf}- J{m"GTq|#*qV)ff;ʇkh ooڵ3hLgW+L͝#VRDD)G-4ya̽}G^)j[8łW!vOsWT G5T2baM쥪 ߷ 8j9֨C=*< R]yK :=GػH?vΛ2)J⋹-YYϰ6Qv|{U(yY)vdR3yU+]V7j 3J{Bƻ3+-RpNӄ}Oٷ}ЙLNy!W- N2ɐ /. x:@fH?[ᴦvNqp8f%r8ÌIdSsf!0,ĦSÇ=-Mxр3ӰҺmV>]1Pj#Cc4QfDM#o5oFdPj;v>V F9+㾣fzT+}G$@xh'].-zscNk?󳅝+Ӂ E׈jO_uϬbGXtdIftbm ߁xGWϖhP$0rx[_'ҦY'Zz~9zJ݀rsq]@VF ?@0gOxKdVP"7[xJ@Ѣ\VF_˹.ћIy{Ԥc1fpplH޷_(_ӣDsbd@'~0ϰHf"=;ui(t 1tFY[%X ^`UpM|Zֳڗn}S&|3s >8,1xoz ȺIjSHM+!{rd 9x&NVjMO̳kvG+Z Sp!í[!Bj0b0=U#HU侏#$"p{HEljkdng/X!RW52ѥcW-rפ֧Cm$F!eVr! ]./KZ¯MH!3|[vFɿd2gaLo$MBCRҚ\KECGP*X+⣋JH]#R8@īJt|x!fdұY͹?B=i&1; dڞ,bYlmeqV㠚'u[J0]<`Ѹf+E!\fFa‡˸} MF3L5͜8}#*0lYn<^fL_hUqC saU)r5aQש,(܄Q"mT}: aH^}O뜓?sڦÖFI>51Qc] 'S?jsD}<{$i3jq66QMgqi~`^Sr,Rv"!jLPǃ>Bw)Y `Z:6<8b۰DrnjフhX#:GN_r7~GX1 I4ѷ]~SJY G*#jl|yRqKU r}g@V+ۄ jvjYJzU̽yygsy!<@ږ'}d JӖު 7Oq+4)z>hVeftÝOh7^ߡ'{~ßRAc뗞>Y:ZM<9ԁ`&UK7d uCQ8dm~Qgd]jz4SE TPH[HNdPu  -n?5ex@@pLl\rzPpѻ3e3NpkDpG(a>5C"r5zbw}Md$JrS0bv14pE9v؅"eEDbwq Y u^m7^IwD_I2ot?S"!&[`XbJv|%T@4@#YU ̴"b'RTc:62BHcSܫ޼oۑa-$Y_ X/X?*~>YPٚv®tuN8>mm۶m۶m۶m۶U;{5o/0eP~B7 . sqϕzM'}ŝv'nN.*FB?1bdӅsaM/ |"`.Yg%Z5i )UUpB֜3O܉(MW8Q#_oOVT0.UZhꨅi+W dR/D-sJwM\^G%G92jMf7)s =pNE\vhN"{*u.B"{[hGƻϯ|@ &A4캘4zeWqUX6Hs6TNVÒr5[^P sN"*cik̐5q$Q B"a FP4"t*38oT=]ގ"U 9a(fVzYqcMZ)߳&zQT̯j+\z~2f(HH&=FCr7ƪ&4g;xO6$È?X; ?o#0`L `cf,g#ZU}ҥskcr}7\36qzzz4[G5.P&1ŶC {e#cIPYДG-3{2TZ%,4"JNQp)1zCdd.x"WP>9Yx/a.x:W/QЉ,Է=}T\!`dg2e>Yfh)BC: sGx(jZōPf^cC$78*36k|6 1<(فLМd.5"N5̯@_,.M80ϡ͚j8X|` ]ת6K-l&0wdB/bA|*7C4@#w?S-/j6Acq/۵ok-/ʢ i؂ghg+=RT6+>@5-]MFO:(lYquR~A0z- 5<mr[\oFOd({?y,:idM󏴧w𩇢B>v7dY+Ι76ofܻ#TRa yV"oh.o#lfbi :6zww2R(LG0"X u!c8B& 3go"}pqZ|馪ǫjUw)0U#;֥ RΩ1Jj1%Ā~Bv2[F9Gyvz6r"ۧQvēo rv[-]#SO&  0a|NR6!:[yb#BNs_r/D\Pu]$Lw"Ҳ⧗0b™%KyrQ 7tʽ޽uoƴMoi|>`G5LrGf_-. wT^.흙J]@nC1 6 _+`^+0'>@H6a2bFg> )vJQA]-mgtȩ%ּH7Im_kV+:1B=B6:|hB | R2-[eϳֶ#.m4uT܁c?9_'ΧPI'LUp;^iU|=M, l9vk |jT4 LRTɍ%ɗh2-u⺜b8$&I9? ͻ^.j̱2V/4-VQϠQ\j4ϲ^ҤI $WMby 5d>vm i <σo L85x0#Ts\ցW0nnk,AݦL.-AHB5~w'pώVPީx QyiPz.)0s5(abj#J(Z~B05&Mv)-E@CĖ r:i|bN"K =֖kHʼnD &3i@*&LZpZSajS5wj+hX($1q\>XɶFn،m ō3. X]#'D6=x f>K0]JC$156i]v:~>>cM9LǐY¼; Gا僠l&̊ [h|)|QIMlc2{1Đ3lYր zkҺ$G^fG8€o'*k!A2>Y@g{R }pPnw)˾D/uB-]|^k?&&?ҧLDwr7z$,<Gm#n,mwh[[ފj!vC*}ZV͔XI"Nښ(*皮M)z0EƜ6e\a_ɩP=_l%9>Yw"Z' [=Fqtڪ<4E3} <`=ƮhQ2py2~G4내t~r+&Jz265a;~2|rM`}䁮ѪJ(-A2nځto??Rs` \= Hl{URI6|w xQ~mN < J\'Uc]ߛx56Ns NqԩLIW$A8l`: T~>=-νF >2J;7v{Ba!B\XY ]* va:#ԡ:Ai؏Zid`ţ O<:u߇R'x'?1 S見ZRX-x)fat*lFImwtҤVPU)ԇ[>~FL {ʸDw.w0]ȱFT%2c D02S,=,@篅ȵ@IM&htDOa|+qo=,󤇐H鱃4ŗ=%L~ kɂ}GQM`n{`,CQB$ ұdXS.w%>ےϱTϘD_p1ƔkȶDw#Ct1C{vxsCl6Q7-׷:?.~A7%TfWO6.iS![a23IS.6UаlK 3v v}2 A0hwM֤(/pG31ޛfgRpx5YN+tp٭{/}zЋAT34mے3' T-;@[;3X' LIg R/B5;v:Pbtmb<4CzU>n_*(qhb1%V6lVlMMtP]ʰ;3u5z:r~ZeK]jz M M.On*!%*=Qq&:sr18Dr\vjLmݮ-}v>$<  .bUnJ",hD?`{t~U׊sV##߷&P*cU #@wԖH1O?Seu+QmXTmRydUԵinU9?Sp|ܫj[w/#򘊵[-12b%L,*;Y%'5(͝iWv ezQiV-[i֍_=áVMIevlgԖ^?AK})R`,VӈR ֓S3iBs2 슑 o?+AE1F¦UB7HQklK K;[poJs^P[ZmL) rJJ&De`#{8G$ܢResWOl$/mCH=vkc'M/65I|%/n8(ըNɚltjU ؃gj]>drz;F9lj !-8"u9!n*O~MooڢCyMkO ר@(ź?7/r?uXp5~q7s JۃƌB+ C!Qң.TbȀC'WGY++dYͣ+ B&{iOޑ/)q?yuT$/MDN0igeL06# IoɗP9jSdxS rf4K #QsBcŠjya]W0s$(jFxqS/ݶU=K k7u>PKT$4 "#!| 4݊iv K dS>}Eޓ1I]UI;iȐ@.6$H"2yJI ,y[̷]?8fmbc4 0RVd ?i 7KK׌T<-$UdJ^FܫX Dt_ Ҏ70ޥ2=ڷ ig-yUf j7%H/Cy/hEf޻r .J:Y b WF`ﱨJr\\_Ete4I^*ȝ4-b­O|(zM >7Z_8v5鹳|C* .9״ nSi>z6/!A_rU `޵GCRqBE]EP+>پV%& ɢU~!I>~S {$!O{E3;eyL-arֻ[0g[1m,d$9'ZV4ׯ,Nn4F!\bm}bմ\Fǟ~\O9>-ЏRF<pwԘ]Jjסa: ]6 9e [ fTVc}IU a$V˫KxdX ARWCBcq ;!Mۤj"`ҋ9>p=wԽ]b¾A9Od6F㼶Eԟ?K'm{+q^ GWPЛB1<7QZhoK)r"y1Rq5Z9q+G_O&*b-M=dF^|y]/[ ;0˖/ gk R@.lp}Ipt@3"Pwɇ&ݒܱdbb|2Y־Rt&A4L->]e kUYA0OqױUVS@4XAw@=\SӿLw28`^QEid1j;#Dbe[-Ύϫx(v/$ߍH|W,FcHߤNv1ʖ?ōT1OexAZHXeXaU} :uk9`F}d+y)Ũt .kEse%(|XF`9ϒ Ϝ}LSM;{æ7U {~\R(-64iEfisqb3B)y X޳MR{ߍ'xx3"1 `;\}<[)oR\N3MԣWQSN{sPϨ"CCb|hats^ۖzthxϜu6[imo&0I41s)L&vd`6}0ߦU(>+ŜB*OTJ1˓|L.9 R8O }+E<%68jaXSj8J!},y_"ݰn-'LfҟߐpRps,rUz͢bSg9ãfBBA~H<ī_̈́r!B ?5ȴts#O'ANRaJhLYO.%;.|Eu׳J gRqVNL%TezQ50a<_,㞲@/3<ǵ+6.)WZ,P0K+g92>f/zH[yX"VNI{AԐ ¯53ȉ^ f8PV NÀktdU/r7_'&{mlz̡ujPi#)~ J(X'4^Qw"S.w+"ՄxpX1W)4:`v<1ι KdoZ+ cIY4x(xnWN6ۣ{ӵ2l,oPv0bjDT¸hbaOyg7 ʺ Vؿr JBNhCP}},RO_X[FGz{1{͂|E)*pm4Ծ`ٽf pdF[t4/%Y/  w ~I[Q3]rGgvc4.hw%/ ٢ rx;ݥK_p1IXBd_ȻNsn72=4?DfA&6ۼr~/ϗwDph.J@[ \%K.(X`]*y/]4,`2Pt٭Q\ot>Ds9iYXa%eKH?v%«WXg /Gj`lK>79-rd&xH|ީF|/Mϰ+'^GSu*]t&j2sqm} `ܳ؅wI kL[%|:忑/U-K2CכU3ۑXorѤJqJbAG?R>zzv-> Q|^.a0@LT$~aΐ@8vn [g|I[¥1E}\isҢS"O:ّc?ՁH;yM+єX%W*w(;^atyKGIi-77qIۙ an&֛e C:quP!DvCZ"->eԭZrzN*Cx=@n$΀EVT=|/brȓ;УuwL>ixȾn8Ì:nͣiZ:3T`k8J_1U"*LjdHgnm+xf$Y\V:YBݎpC"l)2 ΢*UQEPpXNVْ "P! EH+x>wfz=^t x;){@H-nbdPz-q'熢P뎕|RsGP?UZzqY>.鷎.OgV߰b]Q=5VjX=jgI MTX\`ܲ cia:an-6b ĵz]&Ff,kccwvrD#7HNa$7ady+ROyQ4A$kZœdEo$ӆʊ$.+ٱ蛊^ΜJt:U}H*e˹s5%#vΐAmNEc3~%DO` EDđG>LKanCbcCƆ5D>^)mи:G\ho5i8D&=VqM)Bb&e6;\z[J"qӨi[ZFWle?NRodn~9^ɘz\<fE2$vHF*> A,D6;S2׊QGPEd&^#O.!I- yՒ)vsE̋T=Sb4c%'c>Z⌴c6?]7~cRKZ $RY|bg$B`vnۡeMSb%vIwl~qWn_OV0CsXw8)~gz^VXA,zb@هo](ʼ6:j[{ڄud.$O4hK A 4CNz8 ۏFT#kvj5'\ b8`py%{NS1c&i0j,u'm,؀/C5ی+mG8'E(=*Le?%KA_Tփz$wڿa: 9N䡢U9>\&M?]FzBGZi_|; ?#Q:VG\9% CU3tE]EWB(\j[1#.0 X$ΕT.`縆 Ig1V?X:__)~U jTc(d,(eZЂ$9t ܱv3ZzUG'Ru0{^Hq5!~-r@Fu{hVܵluE +{]p@P$MA:%$Ӕe _Y}hwz(ۈ\1t,&"P#FJG2̆悇Q+)W3RVgcaĸ֢+|tOe ;X\tsG?p8hGW+d}@wJX&K |^ǢnI{_w&;wQS2CpB >=3aɋP:'.EdԠ=* U>CߒE<8I\W L>nё\,| *ѕCZųy1KMV4iI[o.}Λ&8 rI}#@OGo^Nߊ-vl Pqc?A'pK# ch2wdI,5Ql%UF[)F_jCf5yAu\ ,DHvs]~4_yyŝ s Oyض4~$߂G] eg BoTYtؽBAR/q7 t$hKl_ ; τH ϻӟ lBUTo_'cg_z ^*d% "q9Cq|~EJgo2X~zgnjOLʢib)54FPtU`_LI8n)A9>,*&J\p_0A;}ç~7A'[UjQF?[)prQ(f .2Фee?ȑ2`t= l6B6_&e9~n KHO9z5> T@vq V̜[h#tZyL#QR¡ ;k/lx(,IAP'A-ɢH !&/aA&*x<6[f< A,!/iPa#mw_F67xO$=:uޑt\O+A v0H$'R10  o~NhGvcyÊIC^#9Xq׈m۱z*HA*GZL?t^Rdu4H"`Dnx=;鹋cEUC\t1iQ/ _ UJV(OYޕa~>8ff R-CQO#ΛS@vC#[6⽔+n \QG6;?6w[5d cD< F* 0PZr w +xa m lEUz$M4sME0خ ))CUl;hwV[ B*?r2{-9HUp/`֧ռo'hPp盰ƚrLKO8xJ綸d zjho pV~&Qh/]q78l\>uLWUnmM-":U‡-$}df;g8*?T-V`Ywi0XZe79-: ڣFeO`Di,3{i,y~ (FGCAf[d/޶W؎9?`{P+UdתI!N:T-$k˞ gR3W(Tʏ.$"v-;yE(Ey&|bjO/ șo>^lv$KM`Tm8YGz(vDunCx&@ x_bPXpw>5:QWB* %>8˨[X{u[VX]g@X%NkX[^YRfAq /͑yMH0 "RY}ܥfތQqMkBw.-^=LE3vő4U-F!_Ժ*X֜ |?No %uP|=d,xh᩼a,AkEQYϡa Pg-pVn=)#)+ 8Xvr#% 4E3ǔ6Ae~2Hyk$u=l>MC.7_qb>9뗘!wɩx/gQu}~ H>J5&ۣiBFR7"~[?j6ׂ`We뭊(_yxh`z>dmzL.`AA-? )>fB\'My-SH$U)^vk4$Gl@8[~Efs\Y4YC3^cuWTc=B]vLX[[7c׉/V[FE|F#0L|6%Fe8tq &f2W?nqdxh?\x*ЊݶLܴ zKp0C!cr`X2IS?+a@^ymp+"'Qct +؋ṵE58"> O i?$SW}:X`HiY_OP>3zxޔr<UbiDNוXN|]I$It\&(Tc0ٰ50XX`*+R$9{o)-\9W==3D'_IB392Ӄx̓axui&f0->|a1ܹDh'C(E/8Iء@Ը~EI < #ElA,szzJ>5 [m0󯵂gh \Ռaau=űq&8OH;ZP0gS-\σm|xc|R#<<8h3_֎AN=epm~J%z Db{ i4v?n3M6B-)#"FMEC"%v/ܘ 6#U?xKppH-L?=j#x0S3͞{- uAF\F'? 9YwV~^+PוGb>=CرuT:UI>lnc0ۿ7ȚR-5+upfnBrVҒ-oQ5z* 9ܥ<m l\O(iu29 ^tuPu}ڝƀn2(=ڴu1p*IBXw.d+6Cp ,bkεZVm.bzj4?DF\RH`qXV2˪y endstream endobj 218 0 obj << /Length1 1864 /Length2 22366 /Length3 0 /Length 23556 /Filter /FlateDecode >> stream xڴxeT\ۚ-pwwwww  59}ϽߨQk~k+ ٛ%\xr*v̜*@ Wc' 9Nt(|~D01qÑ$v@ @b 2 (;Л;vVv@Q{/NV.j'[ cljmlm0303?V*{; `oPjUUT*J U]kQU5uI:8ATWU߂#O83{0܀NVl5G_ T..< . N 6ͧfi pw|\6q3w?29$I#?}g X;+$5sۙ~:}$AgG/ Wc[ ?ml{hLK`dkl>+g +mv1п cY2R68_zv} ; ALyj’ [6ʼnۙڛYYX9NN_>b/]>R.>s{'? `c qqs131@v?  G)R,F@6?G#@?̮,<ήҟ毭/ 8[5>>v"od{[md{xѳ}I`fes>k)מ?G-ۛ~R+7Y IpK@K&b)m G,{(No/'ţ`WEm9|LYhWI\x$KA=0]~ѿH&+Wm:%>r,2zDWڲ^0܈d汈׎8e#D3c5"݉^1N1(?& VU-8zo$>U3d7rK)@+I^gi͝Ҏ#IRH>6Q H5u

    T"Ol/mi;+wr%ߚBCl)[&4hWS'ai@ӊg5WHAb'ѠvimG0PJ r*,(:O#f!f(]%=ɱ̕)yo .JD2dPOEHL0sMցW1f㞶=Pm'R1%CmR03ǥxbv3:!tUgF]>Bn N3tT-uMװDvvhr8Q'hOv}jQPg@;s$WqLMNbMQ iSOV7k)7U1{x QbkS~qjPsQ妹{Lh:AHA+)9P4qnAhhB#bB)F3ƆII`N-ૢ6۴$$vg3O0%С7X|mAhi\6v']ug:Wt(1 bfiwOx,?aGDܵD{t9Rg)_0SSNF¬t7BԾG(y_\~!υv [JSTEI)%2ΗĔZ1\Tno ⩋"1WcaU=5# d^1]Տ)|j4Z=S.J&jdzG\XÝ#Y ]w:E! X`)BBdxu8FA݋y1*'ơqMϙҟiiԍYzb^Nd|h2y3/;mA-xU*ID:i@2+6RL} nTx۷SwǴUfSDs;wvr5͇fi^h.Eqyԧf]f)d9J]kyƧ*ɾ?y-x䭏grMes"$8+a%kii cAWGݚKKdzG~U_M>S|z?JFu:m7[5˜WJw2=DQ8P0l֋^ |ɞ!4 s+ 683^eq=_ȗ}2^Zn@Dg*'T ~2%asZ~*z*'9 H5ڦYќƘB &]" ZA7O3eAtbΕp6Nǃn\SL0 ž.ãTZuLX\2t::% CPwæ3bF@L0QF4mAZf6L06FW#Ud~hY`d϶UOՐO}(ذ2J3ٯp"a] 1ѴM">#Nk3Tz ^(rs)qO#Н'4P \zX4*QQ V͹ѳ{ ©ax NI5V0R9$TyFOWW^BEZ&0qpn@qm_uTJ6(&JE/~{ջ Mo~9,y>^&EORGժ`/&XLcspܗ?]nO,mSKP$r!#̋w)ť}+]hۇLm1h ${[̌-}0e26Dȁ(:fBrUwg9Β^qZ#GP3!]A A{ j]Q1REX^3] P[z$ u}`u(կvɇu3= R|oA>)2nh!$ѳE IhͲS{W B4J{'x/u)9e \SBs5Emm. 3G7 w,.#!F x+P-ҷ@]C>4VZ՟izNYό'6H9F)MM(Vyl,ƁB7괰6ܯsA AIՈGf UFPEECNKa+,w7;E5ύc9F*=# 65NCBs()j~d́(\N=fj 2PH.1/;CP%QmmhIU,.ڡ C !Bc{S*+hvd e*$.Q=V~tvWo \BAgú1&DNt_lzTa$!$*g+ X f:P\ _aJc99 LRWODrSTKjLSi2L^e}* &toa,%f`̔2HV|rgC (Ղ|(`ga QoL(S3_6.o.@z&SUrs^7uzSxZ 5XkXAZMCK9,P. 5Lw>E4xLź#PFQ&*^{@fP=^xe(m-_b1g57]:rʜ.:AQTa HڰO1\7yZ!C7t^2OE"{|OqGyk_;xaǔ]6S5r)j32 (O7I\f8`/([2zʺU>'(Nef˪dD2U!i$[6Ykp*X7GLXeKծ*tjK{:aR(k劌8f~,:(Fq;2+%*9"GJg2&lCcT,f/т dHwJZ4g\W x*Y' h7]!qb<-[b.qP%ShRqW‘Sgl`:N;1ToQ ckU 7UڮIDk) t<NQP{(~t?%!3[ÎT"K\æ%BE,oCfKZ:; ї0X֧'tOTUx=3HB۰eL]cwBTz/!V8IҏN)LT~TXR VF DjPo斈#k-=IL3@"71r$5\ʠƥj]׻I73BwBɀX23Xݛ#u&*p8?832 (GPrcyGgkEfkuP8Z~F.rȧS 1 0ghܣh篫WpLA7ԆpA>F8+qg/ۆ]_p9ı^Β>+@$wŷPyO$;IGҝToJ~m9UvXOwML^tB?1P1nzMhI]6 ,I,@xlA[dܮ#r O;? KjZDT^Σ[/|^blIh=Пpwغ:һW8_/ʢWGUUzk$Uĸ <)p*g ߐw[OMYD_6)䎈]$?CNtiJϛry{ݩ6~RO7#gO*.GT$FnTz\"#lo"B Ӟ)J ! lNHF1v_P7&j|%A/(#/v^E*2߲AV(BV2ceG*v*:2ńeS}>|tߟ2`?h GXEC!#ޗ41ʈ]5)a #)U];M%+Sd +K[”LUNGI;+Wc\ce ^*Ïnk_drasъ~bT2tWRxL >O9O  Nn9 +I_gf\:W溑Cm%Rꎆ!1 yK%~bd!/vH塹&yWlN-ipS0sNYz9H{XMrHQsz"Щ̳[/[)h:0M~ ΗC@O(]X4jSBl M#oS/ѽ];} ۉ@=lL3΍*}"xkj92O5~tB@TRRNm\ `e5H'>`IW:G07He5Aʙ, pF8IFϡ\`P2xhnbmpSYx$Z/87rb7C!R=JThꃉ]?<@8;@ՄxjEnJZo-feK0vJ﫵!hXaQ`@qbhwvP=\~]Xttfl?zg|!>dÖw QJG|A<I'x827ΆhQ}Sfa1,_% OxLJ%Nz<PaeR\Q]87P[:׵y@ bl9~""6+.I+ K og_v?Hoz"5vDQ θK*Rπ^;] ]CkFh((S+!yVA/|PF2 bMUDQ aXSo.3ރ&>ZVE8Hْ l"xVTߟ[ )*`c;2Nmj, itp$6s$VP(2]LZl=/_Ȉ R @i|JK~vͦ"# ݭsYȑVT%S"ݏ^H9'My&.j7RB,El0n'hJ.-bj{w 1jz(%"'/MyR)Zci tU;F͓!na`xbl 09gh<5:_$N|7gqs YVc7Ox0N% * 9 \efC^:+2X80oPU䫒--5 hA5daQp8ceGn2>bZIq(0ek~Ķ[иzd޴x#`!-\.^c=ӦR5Ǖqj*DrS.MUM5ByUz9l[+ WFٯtR|pf 6Z\ P* Ak(u͵4mĆ8ͻ+=?4K^[@=ASxO-d`~#˼M8J??%'M0H@J"Me#p Hd wkTmG޻懂, |OW"5EsIJBo_ahO΢pd}w4]q,ʝVF "6)גT}?u '/:5awɍJ\)#,D^b'(*n0A)B~wR ٧}1O=Sd# $-1?ӿ?x5[ i8r팡=Ҷ< K3ƟVJll7ۨ>{^*hڹVlj@FȻ# B1u#*QF@lET?G)چ{1o;=bqR5˕ \#Wׂi(^_na%1I!OSC!VNHUzi tr GXRe+HAѠ@Į)to0ߖ޾h3QK%\ĩc_rtåP 6l_e i8?].|+8At{.goW%1bM>ʈ+^I:yQ9qPUbQa-VVK"OaD`ӰGNlRUäԟcͨ\+ 3p^Uˢ>ȩǵ.G$RJj&zyY.oUg 9-RLlYuFEmB&b+d(C:QUUq4ScJu ՋGC;H֊!@H{}Pse3*4%{  V'^| RxCEH5J=$Ep8] X gQGPu؀V7ݠ5ֽ=af#JyڛR3HV0Gr6NѷH5SD~ n*f3~݌uJ 7L g|h JYhƞ+XEpCJ3''Jq282YxOzzH+T|G-rO`]]FEx_Hɂy 佒R$Z"6b:9J4`!p[}8^agjg1W lwd AAyMZDf9gUӒ5 y|r* #&:3P0K*䬷[TӚgghU`Ύ;L* TKfc_-$"lb[l ;ae `{5Q;~+ȋ3[擹!ê: O⑃@#w_uH7S4d퐖!ܸ}>3K+ ӄX?i? 17-j;oڢ.x~=}hc)PRKrfєJFK=Z}1ĚcQFURgy3=|; S[<,x}g!0ڨ;1p-QQt=j2@9_fon2kOHeP bA5XĐ-S^#YdqȧIa" N\_ek.?m/*MEW9 M]wʸvdT_ VF;n,s}}yx^<1\t*u6ʀ =Ke_4XCs\ 7meXQB-@)|/˱|#4Aǁ9P}3ĐKdyZg M}mda)[G "xAsCq5y[FcB%4:xj?-aH&PL}>󧱅B~'cETbo:or6vRڪ+XHSbüDE{}؊Fx)`EMIO01 J=uC ̔N-b䙩\WEfY2o!򂴭rHՠTFw+ N]*2ziᕸ];⾇‚fciYbcwhI ?m&JkX/: } G| T'ԑ0~p~܌k08(EyKq8ܫ8>0ѯ zmP Q7x7/Toy1+?|N 4 g|{/˝"q/ɖ>qHs]ǓV9QIxo EZ ӃHvJ+lZn *afP (>yTb>v0;;Jidw+&v[(G>n%ABo.jN>\/Ik:+(bͪ!C ȝ@sPln$ +8oBhnru_)r6ˡ*X+@;deˮ4 * atj*YgӨZ;DR6Z#sz8(h(Olͼ")?$0'W5򆞷C^ e9 ;2E?b@uz{YGEU9 ,u8iO LYNݶz R`Y!+*Yǝ={a|kd-=5H=j}L\~]Vh'5vj %޻`1 d:IZ:HbmK~Wy8b8Y,fkmYO\<.H2{=}Cs0Jo$ Q W>OHq)6 ]be[݆&tKWVS-<~kO/!;G/I'rt검[GJrHsF~Ś2toϵd8?!v#x}@GBt﬑K4TJ/Gn;y dC͐bѧN)}|ٺZU]lʵ^ذwPQ&Jo [_fh.Oӕ-\XimP֜Ut=8f-ĽT]Tk) c', ڹ0Ÿtf(n2AD1^ZT>hOc{%vowwNpnwVeOЭ#[mDFY#_Lr2EkL1WggYRNx01+9ɽ5W%$fUE>_w)91m%daq:M^ȋYWޝ 1=1gcybZr2wZ^HXZ9ٵ !R|R/If+? z[ HD$t u2| /"-߀[pŨ#9Mݥ{C3M,D'=wd!5jI?[1MS{^:ɥ}B" apǠf@ƗtTVApѠ'fW:C^4S_\ϸPYe2^W7~f̆2_ꚕZ%AM>'H"ZApɽ զb F7q$V%f&a/j$g'(v6mF(6o8JUe)]Clz?iCH0&i ww}Wawtcߏ̸^q[̍r̊R@žgA<,h[ho~+u*Q `1KŃns_A)I(˩}侚{cb-G5ȊHn}-[moxN93ih1iF\ѱDTzG1d],ikmbX2#%M@5G44SNT P.i!.a ZJGqus’]eWsd5{N_Cr(P_Z7U] jBzPI; kZ096ᓿIS!XwYM3FOW{ԲU1l.kg)"U{ ϫ; A8KX騲z±(gqKPZc7.vэMCP!a55z2G^,{B..DD6!Y@q>cwΠ"@- BvM'@ k KUP wŁ4uRnT Ø5("I% 6Z!!M Rű.R@u4m*HG::u}+;y#eF*Lϔ~ >#_۵LJ~Qր* .xEb7<ȑ)ɫo 7>bzq(X)B9i -8GY>2g58ZS7o6 qS47&[GwViBqqL03ۢMVSo0pEߘreXQaF8$~ܡu[6d v=(sPKw;t6Nb65CMR iosɒ#Tت}1" nP8boQ@)ioc,zJ:4/k>b΢nJg4X\hGR "-N\ A~yuˋ3Xu.;G@IaDk#ȯ{ҔQzPx;H$u3TI Tt6,d*2Y2껉N5Խ^GcZ%] rJܛJVƞIC`~i9L1ʘm-׉ӌd; ޛu/SG A; /Ϻ%rNa:H(QΓz04"aXYyɂ 3m~k- CďNE//(t @: 1Jf! h;x:/\$H^9̘rv-uF՝ŇduKwMޯ1Jh4'- -&Y4]U}^&̍|y#%;A2% eLJe}Xwc*Z=K^8 ! 3eD\Zf΋[zle4L]7 F/0 GrO}BPaO[Y5팪`ќPvࠔ,QDZ0v鞗iZ5hK![rZD&]ZOa?QKEAf/9zTLJ(wUe `£䈌]YQ%/T.Y@leo8?aeQȳ %( RuNRݱ:=4M%A!7.uWYu?pY%ҶN#F:3"f<.)D?/r苬T0L<m9'8޾O8e> {M'fh2^{'BoInIS$ a2EkE"*ROvO5V(#\ur}( !*Y`<vDqV$A$G0PJǪr )̎gi~WƵy*mNGQsY1Cr+bǓ~ca,#-:tdu:5N>Ob' (Ji$LQ.D!WCʘ yKmfl4 x}YI.?[ d[ҧO~P)/''$R+GԵhi#lq\ûa 5dQ/dm) A잰;Wmyxݪk'3N6uC[Gq$F/3t!lD7s+AX9˜|.LX\̅NIˋmj03/?lZ]/q4cqB\W1ϰ9:bvKh-8U%F*#R:5CS -zǘ/ ybS}1wXVQNe31Z}1'rhD%u#^5bףDF)Y7SOqwqJ0U`7֍s Y}cZG;*Fs$C`;qeK:);S,zu@ZޯE*jBHS xeU~`w|m@⥬F{_#7Yͮ)11QXK%qs 00,V `VI5|o(`bJ0 7Dj_Si*1[:j^Rz_3SE~>m@vQmqF,LgҼ6r}ڝƀnWHD>&ȴV08 G|pkwۋؽV%:z^UV,:4INtw\Ji}M9BPf3IːV;9<<ʒ.ʨIasħ^Pjk\NHl0P4&tN]j7;bY8Tf6fhjǜ(~#aiqdO"V=26+fYr:ir) xB!MRxícÇґ6ic b ʀ%T*dյ uAMHo./KW|xG-nAؗYx/@ fMҽ1-7NܩX丗|[}@u0x8"##bH)`uz ^AP ruEjgX3!t[Q Q}f1ӯ-(~;6xlQk\?A@vS0IXhηJxy~8Hڲzy Ń!2C%qpa|^9 Y%LvJaK—gb&qA <G So\nG]:thWQmpg_}wjYrfX¿UъF PQ%x: |4GLqQh|P%¿yʴ4PgDKm( L|>SOr\k>J4,(nvUsmԯu6*(;XE!Pܝ^Fν}A \sj1|¤%X u@֊a9kfi5@x2[*F"ߓ[ xR((5da찆h+-SOGWR'RZ8,%8JB[lOzl\(ߪ=2&s1NLcવj %+"@$=#Mttzabo,RސU5 &21_\2687zn6@eR8`I՚)J^S2c\!~k2e7BiFWu7B.Q3X(1sjp:sAtj dėh:UyqɷjMQfXvЇTso!om<cM45Ǻ&-H%^`bms#&'4u痵=Td Nag4M̱Voʅ yEṽH>_`M_Kr:7r*V!2a5; +ynz2V@y)y#/h]ʞY&C-hC,&6>ю P3XoJBX'VF;'d|o=4xl35%L ¶E7%%1̢׌QG, Cۯ4qɥV<`dG&,,~ E, H sq~J P3Krm&m>,4C|Gʿ{8?4;stm!d>l֒&<_Z̀.>2ud!wzK? l)"r}ܲ ?XrMa}-U;I0kyHhۍGŤGW\TwK\jnfM}P05q31j_b宅I1y !QUEӈt|@{<> |?4+#GH21eZ1n$<[_EYLH5H:@=[oR] $Qgu M,2w}Gea⫴w%} #lf34ż2p }fx%zI(V++OS.cfj­*~+̇VwV-rsS| G?ZwVDaf` n_kᘤ*jH)ys~zw#j/f+KZ1} -yӱDJJǢӨ= Y8 ӫQka #co5`!cA[EJ;/PÏ3'EhC7sc2jQkj(_㚇<tTqQܯNXms_C埬-ː2[xGb4%yQ3 A015Lf^1Vӯ(VXirƒO!!$Y`GX'cPx&/0r}KXZkwQ.N\~&un!NN, endstream endobj 220 0 obj << /Length1 1671 /Length2 17423 /Length3 0 /Length 18534 /Filter /FlateDecode >> stream xڴeT\ͺ-{ii $Hp .C[ȻϹ}o赺cUc1TEQ (bdeb((99:r3M]lL,,@S)YA,,i#h0(A@V?'7ۇhewrv7h1&  ǤPrm4N3%hKՔ5Ui>;;;qu Mi$T{:~b(i|p(!"wVoF ?>B-])===@LNVLӰqx:>@{?qwh'`ctt rᣕA8hoN܀+cmOt4u4p&`_k(obN3373utw_i;9ٸewlEd$5>ȨG&D%<,\V^ˇH%-ĝ>X!mG@N<}oo-ܝ5m\܁!fX@ܚof `ij~|L=;} 1}c ] /K4lTڏ]jh Z"0+9>A>ZRJ@l:{xhrQrru0Bdn ~h_(@n?G?l4s91??z.YLCW]J?nN6V6N.7ˇ89z3#X:"]M^#/Ϙ v/tg U?grujX|Ej߿ E9y2rx\V65)j?z[z~-:ڦ6}) ,.e:ґ>N'M. nʠ*tR3 Hv,֡ ŶޒT5uk*c@"):ŤTIF{$[1J ;mzf|GN!3(o]̓,gjᵌA<zŠf+n$ ΘsO~vжSQ3G*!_ϋX.=} FɄ Ʋ"`KˮCdƟnϠ~|\w.;0yGb$rk? B3&P}ӻq7ATH|93_A8 Z+ AawFĀ/&'e{dT!S vSɘM<>Ci(6QEZHu1 9\z)G:W6B *窄LiR}S,}HAn4=en`j\۰0zNîfGF^=7f˸|rXWݤ3,)DK\~~;juF/`=ExVx){̎+TՎ `}W3u:e%P[nRp/:&ԿͣPQvEˊ+,>9΀E£;`R)Wp+#\4 _w 0xm`# *A=}΢ ?كixo;~AiB]<;*މDYC}ӤRJɯJ4 Kg ?j&&Ʌ$ySŒܕTŔk. !(nmqܼ챵p^P0NKBw6_&؃r^yfp+A:xYJ`P &8anv ,cw_/"+L|O՗T*KU 5^𔹍Mvҷtz.@B[Aw%day :®̸-_[\>7;c<^#8LݴN/Ɓ{?,Nj:"gU4BϺXaQj@b݁)m֩~Pq&'=ݔRK {1!2`W1z080x,f'$ " ~ "[&l@C,#Sw'gXvv,oc -p%&V~W!@ ߵ01"^*vI5V HOn+x:Y1t^UH ќuy5?;j1NQgU .,)|xch=As+HRIQi`"B8+%Up }^:Ok&PKc/G9O<2H2MXP-#;i;ӫ +-ge:m'!24)|fDwu6q/`Uӥ'zGAio' n@3xqzX1t#tߖ#=#5/ѬwR3{_BrKu ~{,K}4g ewF{!HhImӢVvTNt;@1Vs9i/7f c!1uu%3y-CvL1NxatJA6r_}k3j. Q ~;xyG oŵG OB늣r~:r\xO*tU? 2"A0G >LL}h9f ]6ƒ/5ʛRm`?⿘o~Md''2cbkyʹ#n&gL鋻\1Nl^X@B[rӑ~^ 1@2W^\I*!T1ؘ ŶC s0?P[;ҧ᷄ؾaj1 f(yŎ_qbhp.| 4epE"  NW^yߟw6‰ U.a'\n,sziA8.I+)KPy4Z B,P7s8MoȦqvec蹀;hܑS*@#Ɓ{)k*qHubʽHoA za6>^k*yi"P$-V*(m5o=U7$Ov@K7>+g=NߘzO4g"Fs /N&~0:/jV*w‰^]{ }RqR{8,ecW᱿ I6佔f*Gt:'qڸ:O%?*a)#溷S=7 9)Y#g QѨpnpeŶv|o+J0'(b_xzF1zGMγX;ZXtb#"aQ6 +Pɕz^%-ìQu:}Si`#$xu,#ܚj#_4pM@n%[{I5 $zJlYt5Es,؃F]/AFA+ gN~o-Ra!zoPE݄?YVmyW{k|ktK9[߸$bVjB8:,P?]*mصHf:7k~3IC){=fB;b a?{I6,,p.n9j HR{Q(uCW^`  t[${t%ڍ0^κ'>=YwnCw4V&9Y"0̋tɰVoͥd1l&j7 d7ѓ"KS\'ʱg4 h'u'Z.=mIpq($MG W[ 7&Hc`X@^TKhy"f #1't֎lsF9}5Z^Tj0kURTȓ=Y+~8Ō@FӀθCl e uwUJ hߏ5|\}+bUwvOS?{UMJHF) eW=,ZgH_WsaXz.$2y+5;}%A{v~7[U6,1%l3&X|RɁZcOZm)aL?ΥPN+3Z÷Q\ʎf҇?a7Z~QU~V͝Bpn Y]m)E_~;yX$<nj(E*d9 XЉMiSz!*.azd('>+&?/ #]G+e)"nC#YviΑ3a<`wΊ_LU%Mto"Ը#ޥu#ZFWd[ |N]oX5" ިvSЌL(R" R?r:Ʀ}XJzP&̞.*Zv*aN瘻Kjdmcgs! }[%|Y `JL\xfZ\-kWfvש;o d4 /wCMsa^Jȼ~9:0M)RT m'SdMiQYa~!].6Kl.k쌺`11w[vY$i:\8PG 3yE*u<^bEMGΟ+Z*iH7UWZw|}Y\lOyVu`ܻPO"(\y&0Yƒ KH{S>N`˭]ZD͈^[=Gd:Ž~mǷ*fB9e_l?V1~a=8dL/aY%;U J*ͫȵ[{bgIh&:?gVl4}-mFg.ռR#x_W4ˍff{\n^=RTo ҩ&gHn={,i29ޑ5ݺk bVP# wqb!%:R3E7R5]_k6.O',I]"8IShgR0SO^!C*yFf9Fle_ |$RD6  ȉA%]^;ꞵU3ç/G2BD뽮,)&)ܯQsGfڝ/X^PEPSq3%7)ghٝ[*__c9GmAxj,~;Rڃ&GܴQv_}D7H| 7_tU-`؃wQ)NMQ6$Sу4dd=ZØscl뀟g'm3@u[w\FL; Txwxlf OIMB\>@ֱ\NF7YE E92a6H[dLQ‘艣9inl[AIR`2+6XBh=!7 )oOm7Рx+G#[S-0 eU,OS'T[Ǘa3hW>' $G"?, F/I_ tlllĹ(99*z%r'^*ɔ"Ԗovɧ x\̅Q:#?{l' @ZO CNRwʅ/ˎy7 cː[Y1YjB)VEw%l[_9>aZ ,Lk- (6)2lٚ%3l[`QNڬY1-jBrmZ]O%?{<~^n K2:=Rw) 7YtɴAA[L B+vYJNHkXDңf-azD3^1sqڀ/iCt٢k@Z'oj{ Ğkmgub'E[7!q]b:70ŪbT<xb1-S ΃1ǿ~U&=xQT#M:woV3DG1@SmCp  z%2/7xMZx@Yqz+f:[^ck߿֊+lIh JBQ^9cx eh%,'/$&FAGu]ϲJA`Õ60"J-2ןQ MЂ]$ٗraJm*C LUh¤LF-ԍ-#Tk@L~]^+rl+w)yAO ÅOzRG~뷢W6oq 2P4"Z֗$uKEsL.Eq5'k$.BrԈ*7Z?j#윇j*laշEkYAuD6b HWt\`1Y&ϻ㔠gQ'^5duo > H4rDKC,g-oG=`e`=صI_4 :aۏ01BVpQuIZ&z}*A:[1 wXk՚"t2zoө 5K^ސq'MIJӬSʚ&,UFө\l>xR[ŀ|Srp|Vo$6q- J污ku!%tlJ< (0cA.=`8ۼ\t#T} & D'Ł '<+e{W kVLݝHC\ mw fnmYtL`Յ#+ZA 2$}.2|kԻshMXBO)tǤ\}I ΆFi????[o8P ]o$O1<^^qP1fJ]dޜf,9&w}iJЛ@e΃|BACT5wQp wG쐶a"epC_v7-Qxۮ7E,^ܻL/bA:+3ysl˫:U$YO bIpA,b}%D )vͶ/)i 5T⌘XB{$i9V)`S3Cjgkc⩟$?h쁾r U@}q)rk2L䮲<^1Y) 5؏|當%WXW Ԏ{$X?@Iv h\!N?,ڄjO_抇 OA9H`yScpjoD 0T|.U)X2iZ²%xN8 w5fQavra7ٰ_PMz^E0v3eYRrWN|T6i4!@xd{^x"eZṕ%96j8+gIDŽ 0n?WlJkXs^:Zu$ z#k]uub6UaQX)Q3怰C+C3z ֢]g%Uо?ILo۾kҚa*FC7/ ˳o@ a/|+"y #:/M^HM6,RҎњ{J7xzX*ߍx _'V*,I\V>X2&AYƟHd<gUNI5X)ז'OPwRѥ ˤ=7:a"y]$e5H̓] (&CL^r5I){^ⲗFmPAܹWF!U ]g@)Knd>lQTсnRp~-fr-AXS2/Ĕ"򏘘޹TϛD7[L[C=ܗAi̵U'8j6d Q fx,>ǀETTޭKl.1;>*rXT:`R xGMcx5fErd9NsB "b`z*(yK?"ÈW̶2[m\r^f6{:HiҿypH*}6}a CTb-n;? ) J o!CBa#A9]*fƣo~a F1tSe'Hä8YulVl9.'Ÿ WPbvRd |GĊ5> HIYjf+Q탞<żSO~X}+t 7rSbySjc1&)fm]@YeɛLԪ+|7qĝM]-=ȩF資/:;Dݭ[jQ&q SLu_Zh(an߶0C9>Ȩ o GH#Unb(+:zG/ѮءCDR@mb?IC-8SY|3Is pa7l'yJL~wփxMI5s2_1iJ+5!/JWLתꩡbLP-82-(iEF3%/xLKP3Gy{>榞5qf"}){fUT^1v,߄ao`TJsŁ`kJy9wE'Q'M~yǁ㟸VuT UĦxkUL\vJHw꫾azJ%7 bX;{ELj+lS;z%~V & 8,x2SUG*> Jww?yrl|@R.ZΡJIU~4lH?Gi<ޖ}c'9=G_l;FgMH݂τ&'f Z#yǓi%q/hBKy-añL.̷%. 9:h4 &c,_}~埱͇/2Z[MJUnPd k֙eE^#"9H~Fٮfoօ/dV]SvQmWި4lAiܘhgn` ퟟ)9=@+9崼Up(/f%.M{s%P$lտَ 2 /l+*x`r6r Iܬ@qA?3]E ަ; &.$4@a- ޲qp->T&R_-\ԞfCKyk]Q$d?9i+&EuQEnY1G= bcG4 mHŅp_PMyw"A,gGUM4NWGk"Qxl1@kUu: ypND>oSaɊӀ@PHIq C ux%$K~TEw9<AH~̎3m`p{8$d1zˀ.=)*&ıӏS3|谨-],SW4[g\(PQR^ 0+~ KϾ&(Rl~M6}ģ>eR>ꊈ)Bmd_P0 o8lHz3Et/_^_L1CHf-(t{1I1#O.mSÍ~~-K8CK6T4ȋ:~ȽdZxʮ--fr_ 0ɔ9?&ZQ"4GK~Ůvq시Ɗ PWD0gh,݇;b 7DsF۪YM",- HDge Sp]{*uS pvVMMih⥋~~!h2~gX lw(B_1H?5LNc~xCէfM-+&/ӵ܍pS0ŝU/,-_|ZNl4pRΫIu`zݔtm?[ 3S2u"!4G8_Y6ks/Nu?R{~[-"{[- v*$+&=O`U֞ɥ!ЏЃ8Uq*R cI7Rd.fv"ylzuPḓDFR]>&m]kE( JST_{:hzQhڌ&N`LwnEJǎP.ŎqHќ/e8;?3}[ǻWM #f1} *(yACAYڗKEbVRqt+nl(:x 3 |'p^6/pC4ql,ƟoOX1fv}Rb9^T#F$bi;wYY/ӳ*$^COuu& yX{]:M|rTC.Ynqe0wq%WƥxxŌH"&&M:j݃;{4gi~oJ5fSu zUtPq ;"Kƈ-Yn@͵?}m3D&^̸pL]}=Cs$J')¼8Z~2tt}ק +YOeh R;;+󻆓kn EZc94pj \F&HL+6,P[4o:j w 䁱_.Gf{3JPߚT'W%WN.6H{@ % b|IaXZw^JHޯįDD,S!h3k^^poIM wKc NHڞZ:{݈͞IBMEҖvTOA>P|)FU9Xvi:`!ي`+OEzjcNzY{ )'lׄ'S/K5s3tRw,RG=Ŧk1~.RuƸ*=Lb..!6W]ȻR\7ȗDuL[p Kz_G,uJ2VbZb (=֐I*1ҒO hB7(ݻw-Զj\dߦ+ ڡl%w1KCifVE2R+1#[\`(z4+42?v]a{H2)MZ kZKNPvsG޾m0#nr 7ڈ ],h2aeFM"vAr2{jc/M d}o,n@!)rTjLQD&{k e_bgWR9p;ȉ&Gw*ymі1 |[Szf,k}r ~ NSjXp#\5;zZrЪ5ßPE6`GTɆ{"LsPIry]UZ˦[A5뀗02T!z7sU4Ct~yR8'%Y/8ikX|n\Psc*MA?3&c Ԙ:J9 @S r ilp{b34D^[FEޯr[E9p`"TJ f rƮL81`PrC-Bjsw qJ f^UtܜzlNZhq`RR= nH_lY!%N(Cn92$y;ճ;"sEYߘ?aJ\% [콮=| DNzq["ZA_ɧ}lNZhq`RR= o|y?ezbl/r[9=Gἐaz&#mN@Sh,V\\1 .jUPI%+5aLҶuUb4F5zӷT},="YX/0kD_c}alpK& $ݖ5$k8nvn{R^rtUOƦa}Te[oya/K:6?QVMѰgif,_/!HlYaVX" RԥGwt0DiӨܥ_Ɩ:6t2 2^ee9Yo'}zf ./fVHg!KYCXT30Ɗ]ȨNA\(cՠ<{AHYʡg:(pQ/bSGAՁ[}='X)m3jKT߲0"vIVO9㻊xgƃ؈BکA°܍^\fأə+E*d(9Vn 4UݪNy}G$fˆJGX#1bkpVÏP.Źbt(t:ptbLFRlHPv#HYB\)Ssќ=iKjƇW)bun4~EWY5*/L+fٞ TEx\c?"󶎇d yoK E|BT i5GQ3aLO y`[jk,cU"]U֟9HҖ \QGS֯&}@ WIkcMh 3=2#!x{e*?yC Ҁ8M+, x c\#VW3 -'XpF'cMI#^6s"r$q4} H_('b"* FIfmM /LIvUINZ1h>h;Ѧ;{)b%mqO@S7V[E.X˷Aʫ> stream xڴeT[5 pww']\ (!;ݝw95b.sj%*PƉ 'bkmh(dh21p PR; @6N@>9@=‹@ :;MFy@cPutb42t|wm@6@q[;wӟ쌌*c[ں:Z6&&y& L5@]UREQEQ]I齰iWUSUP5Um1xK}Vde+C?ڨޕj`kɎՕщ/}j G%h16&t2Mȁ6?IRrZ=apS_G h ʕSRXl66NNΎl@ ĝpK}_?z6q9:9"` Qg@6E$UφQ;6LNnNE'*!arXއTD]#ŸId̵k7٘鼉 (-&mf@' h3kZYigk05rzL.@3FKۘxe~Wo_XL NAs?\RVV @mZ;B4(:XZ(r(%jcf0r0sˣXYss}4-m\v=#,ӧO&iclk1qr  X>&@&dcsv: U.Nӿ7Yo`f0KXFfYo`3Ff w>YoΧ7zS}g04|3zߓ[XYiL|5W3] {ḱd{3]?<w6!b}WjoX; h:1d>/]?{?2ߗ ]?&ҟ_7aU'[K&?B @n,tbbns~yrj|? hdkdR#Y0SMtR#%j5}DPп/VO7- l׭e}CyI & .2_2992ھǏy;٦Яt6]X0V; Vf:b DW Cpe`z1#i2X~a!ֱl'BD^I?6jj .P`\` ߘ~sT[гpc yOZ)t3~7.3lNSD\DVi(cg:Xrv#mWh|L==3m0LGAd*TpA鏢zqo֧τL3n) - U2 gG ++RnƥY$ĈÂH  2іkK˅1K >+[&z.!`=1kec 򋊱p$W7VKGB&?>=TtM+}?0؁XEGu dof!;7ߖ, wm| ~Kk[V_#L|-J_{M[Ǝ~xP`mEBkq&Hc><5 z^"N6&RYFj\Gˑ"F<Xa"b~dSʎvv'o }n6@DEe˫yiVmeY J.ȮgQ 9KAザP'W6E4y^׌|.BiG\(0g{9]A6"/T#-\yD5cY$%ކmEB7rlƙ>qoglȳi")sL ##oUCRkiPE) 5k .\^C 8GJt8ڦ5~閲@M1k\B,Ïp:eAY~OcIj Т"G@M}}-abCƣ.TyL} dl=ԉKQzZ׏#f8q/l."HVYcgT{ǘ`H__&K 7-ú(IOn#;/~AJq-ALh)-3ULTS}8g ;쪥=6ZCs \%01uoz%yw\zb\ )^^=gW]n@ɒ*EUttEO$?h9Ә"\D%dpߊUudݾC8fH=po.lc2I`v mVH,I%h>]Vy(.#L4/|SI*s wv3W+}?ýʿWGxЕuI!w @Hiq BP#/;x'͞-(i>e;nG3ZeJ]@'xԇTȇ] L|;=S9Ktz[r 3_i"͙hfr6ihht#XHR5,FBVf}3ɇb3J5li)Lʯo9R9R^`K#I&~ꈷ[ʉtXaXcRc"{S H)"0°95 \'4& h7)elj_"~Ad#%AES> 2[o%6[̩d6. Kr-wdsR=º_I`=R:] #a2Wseެ.cq~o.' K#=zϾQsH;脍km.^2nXєɊ2Fz:Ю/4 |b%~vv,":ٟ4'CRG >SF" ?*}>d#sѣ{{ѨgߕsP$^=ۦHcתɆ@c{#-4DM|BG9>?D"0mFv Ljn!Cb}MY}:G7U0@ј~"f =|9YI}dus^m ByDi`@sd]WmOi]$^kրÔǦ|A$|J'PxX'Kȇz{8JqЫ}Ϟӽȯ/ur72k4V-!{ju_B|&R{lj#l丁#ӂhML-Q &׎Fd zFDAܑ\Б0eyjyb hF΋JF8geWR3jf):ߚI?2g-2Ȯ )/Ks:>)gn*,hdڞc`F,0j=3.Ohk57D,'ȕO?H5E;v3MzfNu>fCH/.zzi^,=NN2q\F (vYB+Bpa]xH5J&TcDXF7EMH @]?yGI FU؋3?%mʾFj]+Wl0k.6=:ҟf~0Ko]Q\uSiz  (J!rDH;5i6g> b!v1t*Ve&xŢ7U "G#ic~'d%Y7s]My]_miu,۱P͢ޗḶ2dLo\beC#DYV-O VC+*gPYXB)N!'B \%-w>9s'1 l/tԣJ6hI-*=V?Pǒ}yѲx 5>4z۔@ӓ l`t(|X6.utumQs`a,3)7b.RBzZLPIPA 30g.M4V!v,㯑FЃDYZy;k-R7E}5qg"+8nnSgTDS c ؟cw)ϖ4wZIϪhԿz%a_g{`M Z֚}&eU[K JXȱNՕ/5$@)l t0`0V샟MSzgS1f+kـ]BZ rGD\zatDOl|Vpar`݁nP\2 G$`.L@j2tXD Q@ {d1i+x%22jJwCu6%sGIC "D\`ɦLuw\`N[QK%k6M1Dj+l|s֎XsЧޱn\cT /9s/5#g _AU }V8oX99zWx7[I|Zkl{c.=fE%twNFL  hh_$nu}: Fl}ɛ9?j qD o:y3` I?~|*Ϋ5V] xMφjېOPZ U[ Uu {~ݓ/ƗRTM!{2'%ʱ6 mʹ@(5V(>FVElaF{ bN rWK/t4VOսMD*ڕ$jMN;vF`{&_D~81-\(ਘWRj,m)FׇDŽ(m6+X᠍(u@ynOИfvbڅXJXyxUt̘ޕ.`τ24QEqѠ;SG(1u]SGqijYFx)RQٹ,P!G[W7്HվC\ƅ(Ϟ]@w)ذ:9bb%ĝ V<'WDJ o7oɕnӫeLf7B焋Y+xV$hTĤVn#`7雾ݘ~~\[}>IDGkُj(>u;֣`c/.|J4&A .%_thM}pcK1)[``DCkc x`.a@Gc~}s+#bФpjҽ #ZHJ_dc^Kt-yuVL %zG@6Xo-rCİ'236yQvG='0gfo{1}x \LEhlpf tՅ7׵1;y.lqQ`swICi[1ұ):mq=\$ yHITjL yIECܕT0&XΖͪl U(ʶ\ԇG q;ISU!aLN4:.hpԤy^16{ۦȯLߣiEjde;gCF4v;˙PDqV">ݧlZx[vwPђn.M8WC Q-a8(Y6,}V`q?(+.mjS`s&|3Y׭ԃʬ x Rm¹8 AeKj]y)yIzDi ]:>,Cq62Z Z]][#.olJ]Q-m qjVq2^s-YC 7 >PՁnh/ t!$6}6-o%o; Y ɂcI(jl35ܠn'ѩN,&HFH1, ],>Kp/ 3/:J2kJhD78 {,{1(< ϥ)n@JNAZMBu>dTՖc:{oB]t 2ġ:-')4ptS޵֣:r~+Բ˧98m.Vԭ=#* 7Pgڔ|!ì&=u7AdFE^p@ȶrȫBcʆe*{L5Ntruʥ[&=֧ '^FIw[c|lM،߸~$(1tZm)D_.Wr5-_(y;/џ=}~kqP_tLu4)u5{S/ 2,#AEACH+k(2V[  6i7gm5+ ОNTctCDtWnqm4|{ܨOl f ZR"t&lNtс;6@kP3+Ak'L`n2ںzqOuҶZ]/cZ(Е:3gAimA_u ӏX#y=d=tp kxJo!&-b]sz 5ߟ &N fmg+k"7_*ywܽio|%,ͬeW5K1h{{Yxk;?0̛M,z 9.AjdX;hm!SrO)lG6%"_"f<΄~3X [d Ǫ>V`"2FzAebRo9 ԣNsc8f b"ƪPCq¨_t4˴NMkZ^ w zENxVXkDX>.G^/_2v`?fSaa`%OJ`c-)?zp~s|%ϖPzs0Žrg"Re=/U/D|ͩ[[;h(`p7޾U®6 !) >!{pryi.IerOIrxA&G) \?%>Y7A6&YTISJ+ r/\K៶šG^jhEg1[Zem=Yl@UnWxI =KȄ+PIő΍A%\\ 2Y[y[C֭Y J.?! ~&%\,-WaaSUWc]\M2dJ(f{ΣyN- Oҷ s)]4A iT3(g?Dqe5)] ݈Q;rmiT ;3`Sn\~ )%Yl r/YV 9q&WP sW4PۭM {i&X;.FQy>ᓁ؊OilMg@m#E/,u*9)5 d*mV. )j-9az;دX#Ke!KS ."sh-VזIx'Ȕ\]EƗ6Hj'+Ew*up~@N+MH$_?I!uE}]FuxPx-$hu1cʡJ+49]=a -կc¯4 j<^38zܥH3* z.{-j\Z{vl/P>M;(g]ס'jmueJ2hQrXs!b`AS2W?аFEZ^ =?HTf,kNxǟ GT\rKx'cQ)+D>5Ų\\lW ,Y{%;#GzM889jj;#cXǰ먥l͗N*/LG*n Dn॰6ꇤl=-\ Q2y&yl|^,T 5wӋ3S /Cgq˙./-}ğ'ADh0'])3ͤipAr3*Ө9 :,7^J/Q&Jl9x3#E]v,rR[tރ\`%PIC3,R?&L~ HU(Ew4]^ђ\ePR"ZE&Kd\n.>$MVn,6 yhn57h4B% ^ՙ?(̅jkztt.;s'1< 悥Ժ.)Jp8b}c@:L<͋ߝ޹aa5>P0FN7|V&KWɵ!(M=6 T!|٬)!:kƌ·$%Z/\hLAHw~K.h4 wE&7$ Qd7t\3Cda pVfqu7zEY&fb2u$cS_Z \cd-0 $xRL_U#M ؗcQ:.N'`dܘ8*s_ದ[`-l3}ᬯPr*"^q4eUXIvBDܠf I"Ϩ7K=:oKF!_An@ q3T'0Hv1.Lty|w[IPt-k fΣ!l2M+6,_8kN$) 7 nL 5X2?hE!<]z;+[a ew5[nfi=uB_Gy8,zכ=/u:n- rSnUfgx̩ai XF{ȏ3ҸZuѳ[}&nVJ%E Qw2?; сXg[u} 54m_c޼* ݢKp̊dן$|p6ڥ`ښ䶎/%Jև(3.:1auH P]7qM_BhqU_K3EUX~zw[~ּ]tL>$-"0Ǻa ^+>˃EwISv8Z"2 3A!v( Sn3 p)g)/"OuTsP% Zp\nTaKMnڈx>'ƅ?Qѩ@sc6`<=Z+;irD6~R|D2=(ؐ#_lmh>Xr[Nl&I+ļA7I"HGU>COHԃ^)?1'B6Dˑ%}uƠi"}@E+k.KYC9>άK_)nڇU3Vx+їL\/8Jۡ4lM6c섯qSTI&K w+ŌѠ@[]9L7mTGV/=TzhՏ_E T\Cq-*{r \ݫGzXC{z{=y$x*F\n5-Z<[WOB0 9Gk{YQ#7@$87cf=RA^M#O:Tkd<;*0WM1Obx}xA k ~Wk"Rb*mnj? BfmIа9pd0`P7D1w: '&d&RDJsvYtg ۤ%7U6Ŏ]y'x1ؽcH oGjPߛ~ܖQK)n!p'mV#CT)bລP~S OyR.iQ\{d{rz+{ʞCq K} `YܝlN[Z?Cs97GJI,Ԁ?3ކ7+Ayf@"cό*0&Fƙ=qPoPiGP84;|[|(=߬yxwr2S( 8>Zᔷ%5ʴD5Hx)U*8i3T # l@EAEL0/y|Md|%n8CD"Cʰe86 Ly LT^grYL4R=EjM)`37ix7 q|ԸV⺂k5˻[I=NEogJp9,,*aih9b̬DѸ9P(7Pqep*( ׄcvl SuJ;Yɔ*w`s2\FM ?*'.͊0[;;k@a;o ^ oY7)JF,bz{1HE7BbD] ~?=.A}rLh&mr4،%] 4<eyR$Yr]:!! GE9jAK%Xud-)ݔ[~}LTՈg u~sW P!-K44MWD^eQ ^ w./q^QJ)͕Ca?-̗C̲>;̇ Ha!E_nicè,#o>LhCcJS6$0ݠ$}z/Ac+$T]A-U!/rLhl"$v8z~w(i."W͹X|E#u3fu:\Vg'E? |̿,*s0iN!ؙ #}7U[9)ivS]:V4(QH)-@ ֖=@(g6sd@,^'pumdɑPvgC+>Ӥ'He.Ua(~,W+})\\IX2Ldr'_+H<~#NpNV|U3T`M:%=LV -'1JM= =[C)FW<ɧt>@/9Ԏو" R1eq&x߁#Ok[5+HW( hK1$F]y)d("'͘7 FQLV IUi&J]E)>s;%e18;W\Vo{r|E+'㸢V[ R\Kɏ,/"_,;HW`FCRJBcC$^QS2׉gA(Gw؝9p_{AsoJH^f ^f*Zm r \iojQ- 9 "z}u8}63-F2Mx&_ͤfQPct\6ˍ&To&=R Jﳼ'X6S\)t܌cqvJKI!Z=Uzl'\>Eaai!iʭX%=8lQ7߾fHbgB 8ju"?{3&D{tS': L`|tv˪+XգcHP`Ӄ_h s[F)4="<7PB:>Q>.HNpt)j~AN?+Ht[iޛ {틕7ECT[w^$0Q*MRB7Ɱvu͛1htn@jSR;JGH\I3д S.~nV!?LDM9715:5#$9 \Vdσy fu1]\VsBI|Fž5}29Ñ&}~a~zBKrTu6gيj{AgRo=2U-Duo DդMwZqkY5h7|eoY7 XT9OQr)0?oaOZ4heӰWٖ/D1Vޙ$w~~T8l}Tr1M/ZW-Up_);[uj<>U?IM+!u, 1qz23x1kM5Og]"J4W.N7|}ܗ7(n0t%4RGLU3E9Sǃ&mgo~>]~?ZS175E3u(B>f$nV5\^3h{ذJuY3_T57p|o0^X8饚S<D3x밂7k| )Y0:Y|p_gW-akhړ=7k~/ VByʊ9ܻ(VN=y$-S*"D 6iH2֏oP%4}J*jۤG}rR`8Yc|Kg΀L1|O%ګ G!B?Cc\+qsk$'^Q CVqn#ၹ QU\YgrvH ~5ڼo0_346kZE6!ݻQ5:`[򗅞,7s,.h^3 h#r2dݳկkhDg26#w\M3!NwI'v(Ա07Rۇ :Uu8P7V\I y -'sO ߏD3uU>e?lUڀE>y§|F9GE?e?uFJz%&+-qA4@E9Oo@cs`uYȅ3b %sW ;ȡ?e⃕ D9ұ2 LyPȻEvnurO3DGs< SEPfHl<%۞lu=JmʝOC/WFcɒ&@>UF~.܂%d Քez@QZLw 묐;ɓ`׋SeHb?@'jQthiWB$J"7l`Z "\*˖$M[ (@s@:#KaܢR ma>Zgh6ȷڣ@jUũx;{Ҙ#m"З@O!1$)qAE"~mt}=W]p [#5Yy\Ԥa{O2:Skg/|޾>Oʲ+CBJ OҬECL3 AH2lרfS(0GS1pNQ0I$tPrF7w@a)%!/~Ce#:lHC*2/8'-?%+2?x79|c29:# N EQ[NEY14\CN'{bpV˿$uOm72FK\VV*:Fl)I0Ҁʀ=wL^نɩ I,SU 24:0Sk5 6Ҏ.cL3Z ;D̿zN=9h \Y)+!/ihCk84Jm!*hܳ+zp 4-I#2hˌy Gf=4FW^sn;Šl(!އD ]pKI[[4`ll@BixćHۛ2|нsizP wSD9EWcwp.a`]$/Q|D(ڡ$fˆ _,PEZs']7O6v/3fА5X9/^*QKQe6B$Hk2h,&9RZfPʘN9twgd"%.B{*!d.2~TI {G}_ ;&AcW>e"JTa[ T1:=vE;84ScoW꼅׉53QA>JpZ1x*Z4"5yfe4!k;%-wT@RQ]"$>`W$] P[!OU\|3i# ?67bдXʔ`[u¼uw.hZSd<˷|17V4 ,;=$gv/Ǹ{Q®Ɩ(#B&2z̆M/;땵QT"E\:-{RznuUpZV;0 y"! mPzٵlZTW§Om#X֓J;'M\;x @\_Q5OD?#Vsx9N"Mm&H_tl@?!vIXp|b 1v4R[#5߬ D;(d0Y\S 7+FMgh v$Albs-?N_?g`%quEƿ:0rq^E4tnM#sx zU`L6.2'I Q| G:c5'}X`d(7ksۄ -Y3߃dfx5{JQaV{x_sbܗb$:k:A '<(]F*3`@ak|u+c 5q߀ѡ'DJ1<{FJSVRLlP!P̛~ˮ=2S:fqzZ)]6"kde)nAuTN2ѳ:૆sk72^njF_H3 l^9&oB3v~-;R#?y/f(u\Ȑn# 8BDYU_5xވsڜL&: C8 DOVp;aT cKk`ْ K~?Hga#?ܖ|\}K Br,i+CK qwU/S ^< 7QCƴCc//,:j1e,,wy0܄/?=&QCpIߟjփ჏KB5cx\zM6Cp~"/7(ԔZ+0K][Dps]\+3H#@Q[386^3{nY50^~J+y/Q81LJ7'~ EٍpX[u=Er {Zrq@U]֔`*,N>ׯE-==$5$G޳з|PZCjXyr<:]'VL 8h-P[*}ŘEQ!n=O!^T.lKRd'mљ6y?|_.J[7~,gULUhۥ䜕b·|eSB|fWٰ!1`4\/r,Ju]J@OxgjY|XcaFcd)cCNi_#5hSOtЩZ̵ɫ "0*C~I魴wCҚ~ǸR81bTojlC (Aƭȁ :1~ԇ\T35 [$icp@ޞ6ψr cUl*؅H2=.>9}x*ĜId F`-JDv+~:e5:Fs/pwۡ3l-xPc¹^S5ML$-;02McW;eD1\mS endstream endobj 224 0 obj << /Length1 1939 /Length2 13869 /Length3 0 /Length 15119 /Filter /FlateDecode >> stream xڵeXk6ww!;E{kKqZ|tZɝs暙BUYl;1 @Gvf979 Ft;J@^7kƏD9\ތ3o bTnf@73;yXY'8 @hnt-,J,e@v%@ ҐRȨhj0pwr M-& r|oP|$)* vOF 7 zk77'VVOOO+wW7_4m\`;d0otϥmA? iFRnGnbp#5/"hr:9] ..r(/uq }}c@GwW?mvtqus;"`icϝ8SSdV|kD~?"[o /[v?0q/[<D`{#r?oI϶kYn.`;Oؿ\n.6^loS{7H@Z\vHf>~;'78kFk? y̑Mo /4]KrR'+5@`$RM[ V0 H vKǗ+ 5m`R1x6VHRPE%á|~^)lv{b;@kHk},+EaEZ!g<{+=Q't'=N| OlݜiQ8޸n:*+@~8a5m(\^5]ZzqQZW$ hۆ'ā2cgڠr2eN.~HA8O=(уџ-i ьG >_ؐE Ē Uʢ!!Ʉk|#LTU$aq5D&3 HPS-j~X70WޗݹHIwggUГ!( /,/HĢF[I? fN RF0&;o[sUl"[>7PwDH覴r-T]Si#j <<dN;}tN<>"lo k\N/#S7LUR5p#Q nPgK,ahug#z"N ?qH eb_]p^#B+(!TYFU)6nL[61fCt/0tWZb[-+@%TLSԥQ5*_k?=:?\Pv]IIr y3%3̠T{ I 4::r M(T\$Uj#މSZt_P.D9EDd ֲ4!P6X4%|zB0žl(c^fxng1>C{\ aNi/DŽK֦M6Sਈ_j?g7xG,|3_ P))ǖ#$h#.FբYqX~eٹFX['6a'r!Dkl;rTPȱ Uŵs:)mL\XmW)S' c%Rçǻ jnp{4V )M.s `zV8pbOp1?ҍHQ^džH:/@?\?To袻7v͌P AېbB!tfc,gw,6C (e=O0bc7`+BϘ\]m)G8xvL Ca"^'^ "J[\Re9CVȰDs_Yeh|OMunzZ;U 0_,U!& ٵTf{%Al?%y;lD.g0Íqb"K2(ף'QdDY!ǜnE|{::[Jm݆N_8Cw&ߟTj`%i˜-yTֳ, ײ ս(usBac5Y(|>կćv'᱑^0&2xNcY_ؾJ?"+3^;(WC8nF8`7˾uy_#I/Q 'OS¾S`#\3Elny7UMY"A+sPbM:͈:G}ʛϦ֦r\s eqQ:_FZi#T =}tbDZ{7.!ynqYuP/U`6l΃L?g5ّ2HS:Wc<}z.~z@l]4^:[|Ae=V١W'yٺL<0`285ٕ硞 +07DQ743ӫKlCA<[cŷv%'(|дSU6-$"sR㽭9+Ш:f?v_!'!KXY_=muۆFDeGڧ@" Uq@-^Gg֕Fe,N$38A:1 l茇8+@h2£E+G7iům@|@x"O [J#n4f-T猠-A1qQ;xsa\b' ώGiHy;(%%>Rxzov\rLh=()~Sa Gt؈v>T}ub +9x)YHvو\0HCugs"4տY WJ#N9_D0$mz B.7JJ}b½P k:h0zي'% 5Ur5,J9uYs@rD ZSrm1iesyajՀ[n~EƂFx W_5[g$>ΨX5u˞ltv{ʉl,;0ʩ2F"K%h!^k!ۄ8s.׏Hiu?- cfjHQEdDG+w*?8_Ǔe"ώ.(X=yN9ߵ¦-,v?ЩuQ,!ǝ(ĬLFpC7?& oI|OA<~#7VS*_.ua'Dxbv?2ąʴ7pal.˨Ixӵ~6 ` ve9 {7b|X0֑Ȥ́٢AHRkIK4"]} eoyq+Jg) UydƐ2B5PMi  x\vPYK"d"!67G(=2jshb_6rx"Ly=ɋVN\UHOBNy|jBZ-r7>n* m{~;%\ZI Ni#jnL!EQ*t'm*c mC"۠G\\]ы@-[6AaRuP(qwrdF-֬R֬xcQA~8]+gh!3Nidw=j)R^* q/tL0# 4fBݯL\ &ODø4xDuy#Î+Sf|]N1ɓT5(0xLzu&gD7x"=Fp5!B'?%R]Z\!Zln6K}JO8"t9*u6!I T6. u-.{\/Ƙpe$~^7-6UnV6^𧸴n&snQ5-Q?nD ka:vgqņFݜ"duKaq8A)`8Лa7V)7hئ&< 9Wla!6XK7ʈX"WMU~?#.fR P)Q^H\#g'"V%MUb;Ly{UH.v SO`>g*_>>쥟a yS3ɲ%r Erɴ!2ڱ]_d?M .8e8{!d2:k{T(w!ByB в\@n^lbXVQNZ12 b`U[l"n3(TQeٿfYj5K8 :ϙcH/}| 'Я~11b-mxcHGKWfV?GC0|ԵΈ6Yn':`WZM>me%dJz>h2gHz^݇ʶShe/!sBZQ-pMZ(6;_e9e FsC3.r*x :R[)T| '- 0a xb^] yZH·, 4ܴwAW_#?>;՝OyX\X 5ha%/ry&Q\x(6Od8Jtyo*TK@Fi3L,& I0jXmFPǦu2XeOso]GM/*D|U* RbT.|1)fPTNN>Ų&:(Ota)A4~dYzR@PkM.o-')Wr sT% oɖ짭5rwoMgޞ2dS]n1GTqT`gCAHEco"Ze#xy' $ZWY?;K'>d/kJm :,}ޕ4Wɬ˶UXI32d^>ZSF<'vFvovdݍdx)j}ɉw>NM6TPR]:U/O Q&#ZZi5m9,)5@[_3?ЄdRh! ng26B.(-"O$PLbpt.f|c{g]6aH: V?9 . xwr54TyҊӂ#T 9k5Xu&rdLɑ1~2aqI<^ߙ?=V.!4&A~ v E}Yhhȃih5G.5xߞ ț*=j %r֎tI'JUi~۶{rL(HK L2,;}. H]20)&nv9 Oh+3@ {4BhZ|1!e|<4BӦO2ӄבa{_ZTH\ӷ;j7ο(H'!yn[:>򗤏۞cDL(か; ~U[I~ K 6@~cOg5nb=^\7{/[ȂQ csXюNu]?}@Xu@me!;lLќ$BH;ѓ@'j} 3پ Ark:-4±UYRvZRDk-k(Nj䷵ȞTn:l Ւ"z[AcڲIFckW^`nKdA4̲>P_Z'JCh'E!/u_2yApIp&.p1"-[qY9mtӟ QgֱTu-fE`-7.T%8P `^eNshZtFJ"+l@GhSRe܏uE;@UpBؙ6P0QN:h@vC0Κٸ&q̞<1nHV0Z)5tVy=yXiJKZAV&[J*F9IDӡJ/Yb(ڥAYD%C"VuiV"z/SmF3:$T[vլLRMl+ G%̎`owF)l@) ާf"62jIDAMgH7cݥ͛c͂mmoaܨDT> *SÿP-ȏ-Q:>{׺MFyia~$!JU+l@eWJC3$(?1Q)ZBSOi8h/hK21;pg+h]Zndu~l`r4v`p0i](8t˚y4!<_rrb^ptgy!92N̯Fn6%:QʙuQˆ\٨()WS؈zψb3G9$M 'ytǦpGra+x,'LTr=*؎%'TŒӏ*#"%5Nye܊xj{7 ]M޶s`20'Bb@ _y#ڇ_ƸW~t'*$(Oc$^ԛ5PϓT >}\HI/S|Sd;`f<ԟKmXڇWz3{ [kC4ɠ$}w.3(cil;N?D>"v2)I]iV$0ִDŽ Z\(BHaͥf,lR$U%&6U AfPɃ9dAfarj]B|]U% Itcop> Z=Z`uX﹑9*X _;'Dsa uk`"j>}0 1E9U]b!ڂMxg+/1Ѯ8ģ1zr.j1Ix= Eme~uu8?G`p /x;G-5qv &0;Sޤh% @Oځ _[7 #'ϬCKoy:9~Xz_]7 (%h#-felsV2Nw+=V6~KFm_ɓ3&vIA"CX˷K0/|xɆWT8Pה%!yWQ.'s!L`U]/ 1"ảzj&׮:W5DV]эN_vY")/-'H=ئ)iPy#.]$^a? QYWRyj,2ܚ.WЋ١.Mj =avnlC:5EziGR spҷ .IF' J.EH!j!7=@ԉ)J\jgl Y i'QI0+5sq2c:;%!= [^7ۧ1bW0.%7^#^2'E77"r{Y<wn$)b7\NpdIJ5ҸN"!,Չ FsP*WfQ(\ ~"AQGp1_BKB۽nQ\jl]YG3wc1ܻFdӿ_^4Lg$>Mٝ=f_1^&%(!hĶ,1/}jHwg1q=_p%vRWQЧ :/p}%\VhVm/j8/% $~޳i5- ݥ ~C1TjCoFX# Sʕ{ ـaǰKoNy*/WJ?ؐd˯o35Rdtn^Œ:E{ZR&z~CXh2wAЯŽp dl⊫NơkRmOZ/ٷ!֗ye\R qϕRn}:"] 䏻]U&T>5 "SÎ>?$1Wcocsw"Ҿ<.Ni$Z"*v r^|x*Ic D+" /rvSlBSEr hw}YYכCÊt\P|ڲ{xeZ_ yG9(V-$& a=8qg ~8[W{VVρyMͮH-#-.ZE߿AQv,I*lnVGv2AZ{7r3F'jL&[wB7̒l.1s=t3k@_J۟A 'u !A f(rF+Kqc*wTŧ+Ҧnڌ#IemK"{n}N\WdOкQ&/IY6Flwf19!^X0cpc71&Fq/|z.J]cF<"˩D$M3M3v|CVщő$#isbp,T7elY(3%[ 6%AcĠBVs>EoTu$3]+=[,t[}TnIʖt- ~wIqJqdo rqnz ԛei̳+-5yN|k+YV2(Í LTudED4ypK@("P9;OmcWti$VyLD-y}Q=|83[BUTd);|a+4?#vgV|!lA4Z0UC˯$"ؒ m'nb]YJu\flB+@ܢ$.yV.^?ۣ, UO۟ 2%q_@!%:f C<<闥˹iL} endstream endobj 226 0 obj << /Length1 1707 /Length2 1466 /Length3 0 /Length 2516 /Filter /FlateDecode >> stream xڵTiX b`Ū"PT@`˄@2f&AR*E .Z* ֢X@ZPE-q;*}Lfm;k+å0(B!B%3R\Ar]XPV ]]\ P( 'PEAvځ Aˀ4!H2T BKbrNt? PypcLL# )LA@0[aQc@ E"FH B "ENl:XRK.bId3 \ "_1Ih;Svd…$F$r=.H2eqDW $R9FÖIrJ'IBI@ ƨ1N* %` #!t+ &F7br* [eR*%b,vJMxF?P0F5A05Le^Q)f!|7oo;Hȱ$ Ȱ'3C1& [(KX0tJ O;S&ǕJ5iȴ/DD] Op Ns"sUH MUå/h5&p0$S\20m WDDAB-aA@jzʐdhE˞C]X"xc0 ]D9c+1EDCNNpLݸZj" QBwtv;D+`cd;Qd e"JHkB X\w%8-mzB {ѪMH Iw ҽG><ĄKDt,zx CZ$ K_u*6StP)-H C椽xt+W( Ulmj"fzuRty嵦[)OQphz #.ӿW_+*`zވӳX!'vܹjIPJk=ɏAd5B,?7<2ϫs#*G̽*lrtsV05E^T /]tM=2~ۗ~`? iɌo}㔾#{/ghA71V'os떃u:OцWM|Rp~kqCS:E%{ ,sbU5!8ӞTcZOYcg]> V>Ik+=> stream xڵTiX.\ jED԰@X[i @AC TdcLKEEu(Z.B\r.׺-rgVi'O29ߡq4KC01 ͆~< |i<8Y-ApwPAJ eA8>x 'J@Q Fa% qH  %A*  ;)A"C$d ODfA8$b*t6p0 aD$8I&8<>rt0_P`WXabbrZ B|+Qb~HLA,7F`4XBȶS9hDDu S +4 =Y2 R`J) JXQbN<,@ND "UdR6TI AN֔M &Rr# Q8U Qg#q J%كڥkflH3ubVeͻ-PUa Ad0^E Au66"46Ft\Mc"NQq&U>Bc 4h?y%*SnBIUaW9Ɩ Nu! LP@Tp6"%KW쬷( _ FD8!zbq(a~fk+98yЉ}r&V %7pܔ^!ja'vj4$Gd?%.&q;q0M!$s\2I= `2^twOI6!kjBˍOIQX^:L03=1;p ft#h2R eP xx{,!|1pNLI!nrX-NyS {u|\IhDL\ohHz;a'>%ӀFoebY47y3.~'S4yJL1tXDu-]j穼C5T?Ze1vw4Zc*֯PE|⟐}-ZC]o!{wȏvi0<.\ݽ欽Vyui(nXA~z\h}|MCCko͕9ݳ7Yww4?/\Y).bw>׼{H g|U?ֵFFdd8qSٮ9z{gڧ PM/ f|ewkǥǫKggYf(lW$n:4׌/T~V6y(m]^4/N2-=_H Ԇ:UGn7,~Y3mcתS\>YqrME%7ee_Vz R %imAqPo7!7ڌFy:a_ЦfmS|{%KZ>DiR{}II&7lDrwA+R͑v^ .lؒGk찎2A^VCnftcZx;D֒^k~Ľ9O)k/i6Q۟f}3:`OSUciA >yf ˴!2+Śu83Bsjؾty+m?zW5p;cf907u]/ab3 uG?m=h43F10늏-6!1Zm36RZw~)]F {hQ}o) >ooXc53Dw6C鋽Ĭݳ,nwM//e[ /-Ǥ1OE@d $-zM{g&er MHez7d}]w;/~d~w WI:YAx9ˆ*`:h`vA㋀5ӓ VwEV d7X̓w uÂ[.[>]?toӟ.w%9m夛-5rfsߒP~Øy?:`aUws{JrNr9P~YFy=F+^ȶTѯi7bU uX(ZQwx*GQi άXAMߜ(i4ly[6PإWSYln4ŁeC|{kUKBGiұ[;;{n9s48u2E#Sy>3 gi> stream xڴeX۲5;{!hq n݃ww -G>g=O(fUKE$j6J휙ؘY `;3+ʉDE%4q$LV^f6VfvVV>$*4&6z&@6_@djYto.`{G3-ӟHŘr&f`7'k Ǭ P AZhebc[4:MuI5u:[`u{{pWДfH*iHZiMu?@;S%#@IM'ϛwEI Q ]I6?g\N?i?\-%Z9;󳰸1[893-maroߎ@_q3: 6 3_J۷R9ɝMbW+|TT& ;gٛ/hN/@rw.~;?ooc@NNXl;3_2EQ%Y)Iu &cRUǎ/?D%<v6n[{JڙmmX;!)N`G6#ٙ[=(+?o",Vt7b^#f#~+=`abY߾L\gGx 36Y|1_4_J6`;9E L?rI(iQ؂l)_2?9ۼ-y7ڷoY\  %YpM/n6_Xl ;[D6zlo2T{1qrq8_; t!-/>4HLR1W,O#ē& ePd }um^~~6WiC&):ŬWINw [9F;>qLnPֶV4֌h} pi+6ʤWt~8?gLξ ]!%_C7})^G ^f ^<`~EjÐ0Jr<ִ^,3*%+@~oɿĿxX0[^2iIe5λnX CT`Fj,4Ž.|rb0CX'aa}o't x\ ΀duקVsDiw :)TyW( ;@#:x@DCL#?ul\^; M]!LvoM6<_k(PD&p lwzP诛)άH`6eYCGVR?㈥?x*'A\PH$^HhO`@^媻8){XԸ11/})&7;ڬK,f(Ԝ 0K4,muS!bC)ti|d^jеY\Q zOiGw){~Z3 Ѕ\L#Ë>>}f p۩~%Ӷw[@ `&KW jVv1S#\Vy%4p凟 >]M Bǂ:ϻ'~\fFe!̖$W>ѾV4}fq< >U-oƼ?z30,1 q0҆+`}[-J0(f~4'`u>ZtLhFnf!HVv$lƊ71~b0~M0F^c$0/i9.x蓠tnfjٰkÍ46T ȵ:k [K\eX#|nJJFwtko8 Jj^1kh{gnB)kq^-֋{KH䂊ưX^P(Pgv>|I\T0/m. ʇu|G r|Xw-೙&p"1Q݋{qiju1p҅=2wx@7{&D+'.ܝ 䥪hȊĥ|=@n(I\NA`D!! 4W,|7l=ϻ1ތ8qh\jd6d C1ww`Zݵ@LR[=<`ʦ+$?A\S|}Axޭ ^2éx+ >U2zICO]ҳtDZ)ZUM)5e4ɁJ.9qS'8&K? xQ|EcKh7x_o'{{:³ b^-O >ƴV41cg)] &-^>AeNt5UI߄TT1pg[&z͢nCDթ9GoU-ŐOOqjt+Z6>zН00ZE"~Ebs睂`'cN;L)U-eE`XGFF.`bkDƑe1>&@TL+Lxn?SVŔDf)IwH`lEAwPΖ`"a*@AV qϴ(-No!$vX2D"CKh̿Wr]qsJ}+rV*) !> {>WXTp\Q0G5]mc$7w?: >Mc6AT9'zy$Ҋ!s8w\]nB\_PNEn?8,gC2AS@fc{%GbJӋb! AܟĿXWA>(xvEj";"?z܅t`YyȾRpr(dɅ E'!lZ"=?* [F>McMr'Ys?6Gc Hk@VlOx*NٟnG~Dt3@FdWjJ^VJ\@E)‚OquN2^ [rƇ;x1șl1Bљު:nz^Nt 9rsswy@9P2 J'R*IbɘP}!' 9Kd?&YN_:UcmG_~DBy6h2}n݆χ&o T=`M.{ЎPӿo5czs&}B6+UZNSon!TS)ӕꘐpBe?1*{>S$6IYLf2|j8b"M Sc&x$ 9[Dbpc49/O~*T^1g'UZ %; ^'9+\B߻T/Ff,&c`8]2(C{(dvpq{dID7.kCѸx*)mzji]!mY9uW JGg)g]+;on*ԋ""A9j`<͗nmU^F{9,>3cpwO9!7B_%lU]!@VxssR@4y8DĈ1 [׾ AkQ #)x"! 0fauizޭ 6Q/ރhsp.F*4X[ܳT @VEž]'sÍH'4Ԛ DG~r"=ZghCV(%g1}9Y)ȜaR,+ )̝F*J0]Ȉs ͛nX_Flozve[R|B>_cl՘7f0 Ʋ(pgRxwҊCۅ2Cb~dxZ|T}M)2cĕ3̋a]'9{Ċ&.l|q )KdB6A zc:AR_WFf@]Y^f֕Q,5K6jPeDc-[7- \2N-;܆ܜ<8[0J DiDQоER/{WmΈ/B< Mo)G4䚹{Iht3&}}%pجzѢWOz~k`Uo!!@J@(]ϒɧ! guq>gwwbe:ϾM¾-xmEFت(,?[-EwX'G%֤=B[Sӵ5$wQaZWAv cZhBE<x#4}\ZM42{~7n jG8ˎ>?Drm5!,*} ·";x q#OG{.J caB߳NH"ds% sM52)NvI,m4w7E)Z{;h:)&ơH̓OM(&BY82S2&RrT"T7u\c[')%mߥ{jֿRe,Y#ZHB](Ү kS6c&O4*pg-sܯRE2`mߧEʎw5O,?y55-dlv׌G˜X&MSE"{ xV&xWsh!vDQd|an#Rwf%)RO_w>D;֒*^6p? _ an^2 >۫^IY-c&XeaY5 yh±c8m/ j[01(q1Y3`V$<݋EWVN'GiA{edp&^1/FmG62 tpX$lGIګm]Ct"S[f 0SesJ8O&ҽRrP𚼔1Jչ2JANE pVi|+UjJT9!Z{)pˑ#=-kidF.U1|/EAK*E?qH4iu}(W y/BA@lM7a/6Z#,xk3tñt9)'uVZYvŻV{tiMR"% jf7 ቑHwe"Aۖ-!thЇt UK4(˘5פNLS ĉl=exjW\,xUJU1ID]"ss_X?120KhR[C4*A㍽r &BC9;I7toɎKٓ0Ɖ⋛tJF<8-A:c:gTzͼB)W:j ~M#x>C7JP"`mAo`|<y8^*m$g$i-Oo@ e #x}d|uM9+Q\bf:>DtѶq_=Fm[g%)f^PTuc0sO2`T)l^Xk[uоSmW2Jp~Ѡ75*q$ߞ -r0Y!^)hJJcw{ ۣ Gu e-Sd,DCJ@kňf7r_ȡ Ko[N}L6BnxOj!+޳f6WKBmfd%UƚH$miZT㾍$E^!lM Xӟ>>1HN:2eE?w?}+ѩeC'Q͜5!\jMS4<ˏ]C L Wbd:c9Lb$s[G,hXaί0c4T*2=E"nTRpsQ|QJ/W7n#$dmve!a_8!~`(ʾ?97 |pb=S?N;Hg`e!7#P|M<ѾY>eʉ,k .m2vLvŸK>n8޽\/ƪx_/.E> u9V#S-7Ă&&rs[)239/>qcX{I؁ue-,JpYcTEF.,kzՔ4 Iq`$fL6=Rx@3>(<2^KuT($R`Yy–]O@I>H 8_LW 0 S)$t۫C" yH͘W AETBb' E%ulvY) vX5L {?A} lHI`-ZOR[sd(q{{姪)I1/.VfT rk_,,׶uj&W,ؑ<zAz(c=zF:l!$\ c!:t">|uSRȄr EnUu#ݾ3}r˝iv4sS3HC&!͎:~E4.?U.W浉SKvgޔjuZ l-}hlqz}v۹$."c֩d0/:I67Ȳ]Ud '?ndFb艎M3J&$q4~! Ml>L M#L=HRJuw^Zޠ{FKZ|$Ld+v69dn^bɧk?14 w_|ZN@$~WH|ͻ=Z̛kG[o-Jm"nM/5p) KKݦI$Vh9@]q|K*ǖ6L8:W|3Ձc@/@O5Ϋl! WN_&Z֢Bp}RPzƍQԳ=%L{4gkZrĠS6>Zw6I҂27B"CdW72'HK5#!}2fsVڽ{|G^ HvүC 鍲ڐe4$orƉRHz꼴\Ӣ4W4FdXnTzTrd[kN\VϽ*QF̣?B>!8S,y@~jr&$֬cmďO@)GI4Jc(5r",zظߏr9jw5,@k)OeE2W9I9mԵ?n } Z&%鱣A\ԕ]` ځ^vxgT_xNR/ T];wA-9R4@ulm#ٷ]%3I"2D b* \@Mл}l+̪eڎ!DW;T)C5ЃT-Ju;d! g.3f\yaJ-aDOb0i5ƹ >( X7s@S&\ kzovlдqeJAH'ܦ]$ >ljYqN}π=;=gSF$ + wRPoJ#TsbミhTnb5&0+J Ys#mWsZ Ӱ W6^Qx E4mKu I ?H&+P sG .~fEؿ)򙰺cI*%wc*۸ֈdasy+Kɳkl6+ჹ(Ti.29.۸JLYUs}%~Ǚ1"]ҕ yz|t @6Ttqv,TР'k&L&Ti¶JX9<*yFJdx+d#)0̳bCT8V26bK?;NWLo¦]ƋL*k8cSJr cRB07ZeVNMZspKӪp~aȺ8;,<'MvTlV/tYR n8) F&G] Hn(=>#=\SeCjWUW3W~6A(ZpXkRsDK8$ ۲ϙ!#dz}/ht+9tUI㉾{MsYm< \0djc_ 3 @$r;s[3 !t7=>j#u.DOyc>IʸXisA/`bVB΃}/7ވ:E OC)'ꟕBQw5?5~Wp6L|E)5NRo!/+q*#ĖB$_ 3 W,>x2.W`Ey,3qH]"ɲOy!$T)~ΨGl_+4Fp>_3k都"oHsbo@n#JTQd'9B͉J(b^ȼeW O$E }9Ģ/i<byL`h_8زk;nVr3/J[#¢[wVG5i}s%HoHcP#N ba[]l0B~b~^d6( 7>*Z ^‚FJt"Ca=d/`^TK|gWa!Bp͇nrFukZ3D>kLT`Q4sӢvaxNhs}  -Y/]Ua̦a/aq)˞Zp"l2D lc^$Kz%JPR0E˃;h6~uޚ 9zk*=5tZ^&vZHȜdmrs.{@D@mrH'M7ǶWٸ;AAw*;V7qߘ7(ae} G-I!:0Ѝs'7nB̵4C{G$MMxuӐn|(`1PmEQYǵ B6U<(Zg捵o_1֖*M{%I!xJr eutRthe(~t4_Ñ{u:!H&64X̍Ȍ],lgp=)L!uK 晳-xSqdS×1;ʃdJ&g;x W }hf6@&,%z,\ai֎j0p&v A-4L~Bć%:Bܺܤ[jڮyFvek.xEO}iC6>gΟaeeӨw dZ6WyI8Wqu󡣧pPPDr,6P|oc} t|'R2ᄐ'kkFך58ce]V0fg4 %>5JF274aq9t<x'2q:k& )W6t-:ifhp]?Q#OW.Y^F.uSZRbV\^(7e$4*W+lÒ\j969]9N+ʷ[B.t!F&P0J`)-U@fT _VzzJǝ{oR2>$#r]킡ԖLK^;頫}9ukq! HEF *Qa(fE5 Ž-t^L^ %qLkm2`}݃"֦u8Q W~8A}\q#_(h`W)`3+~KP5R4mZ1b@nJ6WuYC(,m'(nY?B3xEqΛux\tTwK*j5)#c]./ Q 'M##Kdzcg%Wn:G66j%G@j]ƫW7S9WqKT}Et9Q7.yzܧŦ;m`^Mdvw/$c kq{2ݠb+F5Vx|z0l dL#fEk{gKgк@q^H-V.[iERybKj8Pn7M7/ݤ^]+rL[)TZsL ;5Czpx5#yŗpľХsgJ $3ۂqsIBjР#̠#~̒qf,őPQ떰xגԻLj|$ ;OצVAڼs2&o+p,־c~B B9!<#V"=<]΃<@GY4L2!Iӑboೃ.)][ӭNQ EC{zX@]*]cX.IhݏgRGN);0I Ekdbd~t%U޲dZ9[ӫˍlt*YKC4~b |rBW:Wr7}mЭ/-k7)fJ."$y!bUz@j_dRiFOwJɎ7 ʀn)g5K],ۊ8ՐFA|ϟ$ua  3Z=vBc|x./8SRj]B?)GS|u0vYYheYbT͜.}Tъ4m#^WVud S$rޥd=p&jY/P&Ğ.֑`_P8Y87JJ&DOqW}h:8 QY )[S~ch|+ -oٷMYͩ"X& .(#.d\Rk< }5;"NV2V؆??Ec6bޢg}A⧗9dgl%hwT|<4j'njlu<Q w½9cg8 F_cY뱓;1-裚jxMOq‒l+֦*:pEx#EH_VPm{^*Zl3?^_հ x[gϹ m,ŷ,]xJPM)'aPҲu)IN nnxK{\!PCA)aI-&d]Օrg-Ľa+c簾4yCeo%dh):T%n6?ej™.&,~[^{!p{ +ȍup3VhDhA NB׮'fa=U g.xe Ӕ{5[Mg㔼5W2ȅg1Љ^XY{fXErE&G+ eUAoq%0¦s8w%? ]kSϹ3m,Ћ;ʭ5slpkq.T:LWk߈]=Ĩl'|aݫIK#yRZ ȸ9A8Xw=!*Y? &MנA-z)Vd6$ fYʘqP儶rB%cyOL}J}ߺйK9~c,3.U*=%@#&.W<~';1'c~Cu^2QwF3{%tN/.Gܳ,&x,Y*8: (6cKIv: VW3 -'XpF'cMI# s = -I50O` -IDoVAPF t}{*y3[2ǽh6T{⹋\}}Gz'V/N8p1lnu} ҁ ]lvTJGdJ~OMxg!F Ѳ:Z22dVy5HyM2U|9LcΈQ P7̓st5 qoM5XcGߓn;Ӝ)~w9/Uu+R2P:@ N⏋=1\P%Lv+ŕ>*Rv64N jF3_ Dֱ\P5SV#-CAZtc2o-l½DJNhLbI)NљB k)kҔ*O aru<`Lu-zmfu[|tcUdUs78gfl0 언UйͭivwȥBw\*HWcemr7*JBBʹa^,ESR˯pO*'@Ρ+YS?aHz|AV 0ɡU__> pKEP;ܽ@pqü7fD w @NNlm\ V0 :xv+ -pHv"J6/dA}R"P1s&M7y \Gޭcwl7VBZb`[ 7.d{2| Oe-SRU2U<yL+6.9q>\MڠsKc7$(#vȚUx"Y-'u:ǏdnxN8TFд>g7جTR*~32O1޶&OIiF̑&ߨI5 5+0Kv PKlRϽVb1}ٕ_aM9ƈ4`7Ia{Vs&B:I` /,%Uߨ Dj_L1β`ҳ!|Пf ;~<5LSP?MR712>?ְu /xF6%Ѱ^fY)7MBԞaQ-1F"ύ~#g} 6*#Kל{dQdZ{Y*m8E=Xc$b58܀zКJ-6ԏ`pi} ]|=W d/=w1}y>Aehgǚ,_6(oAXBWtΞ C_)5u x$dK>ĉ3Uia?됐rҦ컡USq9Ȏ8X+tӵWif~

    6%rPZrԝ `R$;9(f cAc /wEe;x%)'UCRޛaFm`ӯ:[k\)Ev4~ !*R: -ZE9c2?}.Yd X;CzC9ǙEg`Y&TRzAɄȜ peM0R( /}L RY{ 8K ?Cu^!y?>yAO$o Z*6@q>EH Q@ W2UL^9#FNmn? e'*ZrBYv3b/TW2:уHVw)Q`Iؖ14YdIՇnF^Wyu܉@3dvU]gcn Y73~΂41;q97>:ty5 _Oo񚪹(`5WC7t@BrYT4dtV'UQW9ѩl)n}6Uf8@lAzXzm% D"o,ũ2MO?%([T/10](耝ul!q>y XfFsxt 0q`3V aa }}=d6)pNTvZzxA*x&Ij"Ch^zE\0Fg Lٍ΃#d}ylKZvK5}T׽NjRZ#8'vw~Bs[U[/~(qcHNyn|R 4|\h$?~3 IT]&QhHb;m _%8o#ZW;U`נBQCܝáT 8)"1}s۞,v>%鬮睁N!U8X?%Ѥ봭Zqn (Lx`ݝȖCÉ^;~YPKFDa QtKu?}اREj?eY+ۙ cAq  _KeE(jɘ#8S*KDOkEy/(%WYńb*+͟:M"]9j<f> "Z+Q5KG.~v mFJ%oFV U\pWF-]#ow\zWa,/Gܨ@e׈t\ S+Dぎ}O:AIdž%ko~U$*yU/$F[$lq%dhi1p`pLn]ErUCBm>Ys*x0>4J!k<eMLE'-97-ɞ@"ull3Q1%lYIEdn磩iYF˩R 5`yXdޣ(P cIptIf/I jR)N醕ӰjcsXRW|5. | \} gQM$7R׹b:+YŭCF5 P 0?p[9BK 80F(;>IRӈkǃof 3y#uRkUHjy="bpWxNK ]ݳEr|9* d!)')~{iԟzŽQ@ dTw?fnciF 2WpAKg7`ZOeU9X}DzYࡢ@dta Pњʅ"CS1BcӴ `.kì"7= dn.,g{G5o-|'4#3Alvg/V.t.?2ꢿQ}ɟ30mLMzQhݺ72A:ٯ8,u.1u90Il) LS`=eMki/S*XJ1VP*'$4a]2 "3`*>G wR. 2 `--l4aṼ:: $n}f$ PϵXM!wJ 20}}r`NP&z,lp*Z=)*KՉj0M?xT!b!~AՔ^-aYWil٘,R0uWM4~uXe 5KпD"xLf/t#i λz (,ր0 !:'3OH!,t1wSVpFڍ寕e|ʣbf-cE^jbQ)wH5 K6QnP_F_zs<Ǎ$NhH1gTQ{*&m򉵻 '* 0bxp<\i=5 tYt@/2a?ݏSD(/2#c0+eHQ⍠*iET:L'> ;-'ڧ1lwqsIQ{lv K\ ߷;m"/> stream xڴeT\ͺ5wiw;BpwwBA,8v}N>;GgzV/JRuFQ P PPT9XYՀV.6&xJJq Q v(S,,i#ynN@V?@hf vlq쌌+cșہ<]l9&E&lЀf@kS{KhKՔ5Uiݝ@.E\]CS !! j155~:[14}%5D5tU$Y n_ܨS-]@4X913{zz2Y1\am .@{?¸;ZtM(ؘ]@r:'n&wM\hcmO hht3uswc-EwwqC].n@z:.j@=7{{fMQTIVJR]QD9]]\`/Xl2Rgd t4Y8Z8..,9`GϠAn?{38̢MB\f#n`y7Y0+AkAf?\S߈\߈|J]l\dA 3@ڛZ.`3hW.;w4?XY+ 0M 7 rw+bSfN@ǿ"6 xSm`]`/Xj ^p,?np)n9Xi:]y; `5A/Yֿd גXewv`n\`_q?.:eRE6;>Z?$دuTTWVbA {lgI`pO $ qyeZ9}(1Xo]t4G*7"?e O|:/8ߔz*9Q12HXvDfW/-75$7UJ)0qPG C61Ǔ ].0]o; EgHCJ%vÄ(Zs>F$1;uH´z=/%Z}4.L:iНk(҆QzyNs_Vo['x?\_'z-qUP2 J~~A$tW7b/Y"יmT3 +g^PJzdYY᥄GU2.ٶ+qj( D xRJ;ceEU _p%Jdۂ%7bvT^ۖw߃h (:tՀ`D`4Li*\rDk7a3}.ݷ]dALH"U;ۍ,ÁjZhČ?Fk]cBS)9o} =8AG1vuSI > 0F((%;Y ZIH]Og6X~*Q^Ma,ǯr7mu "n$9>\ELN.0! ě"wGf/fEKN򥵲*M Lw~UmPt>Opuӿ)& Q-m ، 6]GYG\!&!,SH! qs`WΪISdJn;(&ŰCoX44[2jg}awKъeҶ3fMbv8VZUcv::.a>5vf4 %Rt%b_)bBX ~VJZWJ;GW,.H̏IKX•7`)V=b&/"[>>g/SL5FZ=pSqp:MAsZyp9O0U5Κ ~ ?庇l)pgC:j$cbӧ'1alK"3W&.qfFAXĒ|wǤl-L=-]onQQ;zpkUĵy0~QHe\!>ơJ ^Å, )k=8ORpvH>#_fפ~  Jb"\svdA =kuGc8]7 ^:eXumd ]8g(|P€Z88tdQJ*,}EcJ6sR(R>eX_f8+k"#ɛ7Qkb!_%'J[|5#) F^ʐ}%؆y*.d>r~0 Ԙ:KlZ-_p"?/7!dz [>T(ߋmi9ݦֹa׫o&l鳇Apa (! KyM̄^˵h`+UCuaXmww5W 1éu6YxDXۓK}]bhN~.fX5M] LHZ 1j\)Iਚt_- YQ&S?rcKPjCojWy6 bX%"XnkŞY6.tަNeЃDE+/V,?1YWiݢޥ6 bX׊;Zb1EVe#NM,ZOXӥÉvJ]\M73e1zJ|DٹF#o!LʜՖ1R RIG'gv1(rw_2| *$]tp| Vw_ͼWAL0zICx`0F&pZ.jqǯnӫD&ՈꐾQP0B<E[SSmdkĀ$h̩L]AS}c> ]1f`m+ҥC uHo4aRZm<ݼg_a'4 ,DCG⦯|a P>Ud51Е(-Yk@1SB}.}6=p{CRUv&K9康Pˈ' @GȘ7xWLǩP/]ҵ|xVo% oN 3ú󙼡,eʛJ2:#r8FېSʽQ `Q[mZRra,#w-8"ִhn LN y|~Ğ~gy; tm L-Tl ҿdm)=N=)w11 5%ae}dt<RVYχ]ڎVrgwWOԡTM *B]wռ8KG'R yV~Efp|ZIF؞^8trxTe} ǃ7m2(_TѾvSv!g2'ؖA¡h&C 0vt/nA"Gaht +@(bhӷ>0 YȘz:0Mi>z -/nsI#4]5~-9CW_vp/~"d}:VRk얨G#|}l8D䌷pϯ륌"A}ӮCݝbz/T|-Dj{hMu"c8%3ZƟhن5¶>8/5\JBUr[ S3# tܠ36@V}[f%FP~C`]E-OG=fm9d&/ I%$itDfo,ʢ0Uq |5x"~D)L59fH8ūJK:Ig!ZFY[M iAkRh mrH'Czo%V/K|o;޺r y\tozaU˭,8f9m, P~:þ[8s2_[w?[m!%MѺ Hy Aiw!s==5"Jȴ;6ȉR9>9PDn>Hvm/^/BolA?P$f#>HwhPמhӜK,ퟫdx m3ڸ^KK?"؞?\\>"yKhr3*aTD4,6cROjņcJ ߯BJ?%ƙ01v'=ۛ[ 1Ggn9ntީ/7 ,8 AY_Oa*ՒTmO#%@CJ7کM-F̶dk 3$8g Q&?+J3\~s"(GRV]QJ\n]{ztJEˋNpZH&D1V3V=nXن6bP4(\$(^Uygn[2+}uPhK,?WZ߻y=Ṅb,[ԈX{($5U΃HD }ECoGrwV&x'Uԫ쀞]*JOsGByT:*.2rlYAJWno܆]i2TAj#<+ )E`+>Ϛ!oL2=̓y>Ք*AJ/eq+M)h&0А&)<c>>KD*to?NԐ'\$FhM3tt)? siU<Њb=\'|v-Ӓ܄dT{juv݅Ebx"H%J`y) z~`IXc-c0ˋ5)vDOnqIo|j~ -߷uϐ`ؘ#Y!p.Ls)\N(_{S?+=[P}mTSIU1$ #|;HRq5[Z'{ŒB$16ZI,׭f }!es4x9=Ƨ .w=k$ rJ6ݹVe$#a8.?>a clfC VAߕ`RQlӿ}ǚBuM"Twn tGrzȢ 7ܷ֚0 r|EO1]q.~qI$U@А{e:Z%/cEkЙV> }R׬\5 lI"W _iLQ_?1חÚN&.Dz67fV`Zz_Ɣ_6B&sN_ )92C o[5E p{nROlmz7&ۯ"Oգ*b'LgI.S=025wζT ~Gnlu\}RKT\#\<%gU5m|J)-I5K kt¤4.zbkm9"vށL44yt@tᆾ88%Lffb;KRVQa&gD(V$1m=v4#ENV1A#Q-/:4g (a;B&ڽà._YhZމv71"Jإ*P<NOбMkWiB/l.wf$FodFKe&umt^ʞn#Y0MZǟWH T uL f(,9L^Vԗ0͊מsfח̭nP6J$ųƩ1n>c@h} '^BPJbdH crQkNQsȠ"%@]WE*gEAX?V F4e|ӏMr u58|AҌ2wlU? w4/q)l%iá1݉b\X%f'˳MT1ѭMa]jpٜ捰TS4|WMf'd mpk扩RO t3r+$NKbpeofF#̓\+B[{]VVlW₭] C|9`m$@3K0>1e>Lk&$7VC PrN}<^<;Z |8J^ $fK.$zZP1 m6i/Ovh]V#;!ؚG&`h!c:1,K\h5-6Q2%d 1(IW)־R˸bb fu/P ]X#?`52zu|S]瘋j!+)BN$|^X><}'$ڤ-r@1{κ'prHφ|ЖVa+f<ͪt~9a(Q_c`6$&e&P{CD9W跪z)`Bn2ܦx6 }|.Jlxpר$`SEg9bx0#!_xc ri-y=_(ߑhhjwDlMr L l4)ԃ$(w-4%ͳB9_Zd2/8Ͼjvq!A`T{$k^}Q SL1r2i{+Fؽ#*QXj|WdW؋^lvX-٭Oo#Gia^b*̳ЙH4>O~z5tKTAMwGt( fh4hmCoa–ф\Fon#_ {a&_Xs1NdM^g} iqrF:҉m_վ'b6cO2-jj P3N}^HF\o\l<~{~Kf梽Y.>i L$9&$`ʹc`?Ux6q'vUpg杴.VS wUBi[dy!9-JP,wp}bvηo趬X e9 .QWv!-.;75>Б7[g^TLّJClM~oNS ;V&<`Yaʉ=$W鹆۸z.zaF'QJ^ E@3fJ۽c$-`\Nښ4ijFI?2`u4oˡl^gR8ϑ߱b, u : RQz F KOhBÖ{qRt?vk whFƪ_W~|"['ad]׌8ԩmҭM%F{{^! ̨El]EmY<86nqFn2U]?Z6\>;1T}`L}Ir0~"eJeᥛ}^}ZDe OA=#e~#um7-ȇLk[%v\wi&2]s)_ a͎S%{;n}xi>v!a?"@}+߸F7_. 4Oǃ/J"Qݵ}( HI0Cjk{k& /Gq` u~^$/W!):QPjMB8ܠ yD{>p>0q`HD}8hÐ,$oCgj/tQT"x8SȂ~@Im|~ã",>xZj^TB]M% :HȚ3J1tޙRj=?vP@/35k/X6b%4#hoe+4V#j"#ciO=@Q*=hZR;\ B׼C [^_CwwC,x눌wGVl1 SToMrNJĘ1'˳? 7󞊏.7,ڇ_iu{t*gI"_! A[=t3b ҶnEC@HW65M+9i9P@d|o\YFh_[햌>egA "ww\ +y^ްUO@ ֹh gps l_ ȆsO[YSƁǨ=+QsA_<$2:X{#tY4C65K@XFcqQ!aJ)t̢z`O9J]btd(,^ky1w)4\⍧(FNJ+a jw+P] }{ꇒn=dc;Tk( nrP0ZY&G_5G2(t- ?)虌PT0;xѸg_S?4QSJ!/!įS((BXX8+ SB.$IªLBq)aϽo fѝ6`JUGŞ5/ϔ$|!6N B4-:Nh0AcByH䍍"ﶱw;)inTo~U1RB!On|UUOmg+* V[Y>Ԇڰr\<_L*k!rTSz篳޸SШwwsqnĞIeyoeUu`ɦ'Dl6n0=PX cd6H±c=Q7rtf#3Z ]A=l>G|駹v,`[w?.{>BI=n_6-˥o׌aꓩ.WɅkRq}C&+W=<6:`Z43M,q+z%z,Oe0]|ݶVMխ>p܏!s \BU뤈Y .aeBl@Lb$s"gJϦoQV*ܫxe"QjvstJȡ܅F9>RZ/Sh^p&\fO~}s} cfNI&4VϚ`N@:WJx>EctK)w6+J*Oz VdٖgjKԯȆ >4E9CL%W]˷G÷ 8?w?0f#MƝ/c/WZXJT[Qְt&-ڝڳrڵ6ڕA1M4cK\3p;su4_u&*VB+̷ <h&Q ,* }`X,(GuS]?$I&g;Ճ!z^G5bYP)aeue3dLrN͜|9T4m4d{"Ү ^&jLwr* ~ mwC[N]/oV&zNݺЕ2ʥG#o<(!_ջ +HIJ 3C'8@:S* )qs54iXN>{I{UP .U, CƩҁAd# ރm%eToW~Ȃ.M/AljQK0j=(.@uh b(sCGrHZV d(Zqq~i%$Tky:RQ~`1=7duL8&ŭkYeͬ5hIN86l<Ž $q E7;9Zh8ɻTn mNH؁Eyd˾ WGLU Pן%[M\ľ{.*C#c3cfb8ao~yI}K]1*ƃCm|yp樫`daceC/X 9TL,Lxߣl$n"78oͮVl{Mt^pDPYghʴ5f S 1K7ϔ >S6Iw N¦v^6E?D\4 SיT7 1r? Xݺ QcC]FkW{qg@K}o]$cSiJ뼒9MV|i9`5=<(_]뜣AylibaV=2&s_ڈ$ 2G< bOk}# OGv OtXXK>RXk(2ȐIQ7{aC7fn~1 YtO6uzbW0azٓ062$c}8tx}D;]gc?_^y9݄\ߍɖ_iY{XZ@\$kyH} 0O t!e%}]BY=[Ϊ934kSJ1j6ҍFB{q*dݧkhsZlҕx#CA<Ñ(JbdB ,CTnjԞ82H}<ʧfr$ocn4/2/4E= %[oY&W"dm#])1M|4>lƅU$-MmjaJf V#> vWoG MleyWf1zFX U (Y+)}a$[֘SwEn]Ub9%*aҁr u&O84n+6h<:ⷪF )Q&vM5#Ɛ+oĩΞl# YEC]~ 9OpG_]+a1|^1JϐM@rrrMz&5>R]@:+sdS11TDc+ J:&cXb_$M"?P/PbXg%׊ R\iR!1%qhIˇU@49%dCim'&_ilU1Zt#SPVd3!= hp^:{7Gk xۧhyW4(C }Wto^6c De`9!UU?[#R}-.Ţņ:\ ?m;R.($M|O:S&s7`t80H~c`ihIo6="zQ1OdӢFﵔ̱fنntj0l)9}g x;_eNrϩuJq6KlIG 6dլJ&wgދH?de<4F) ΍M~#;M}e'aUU'UvhpGgd3qzI3y*N|-<`z'hx(J _ m[n)!G 7T zi0 uz?4ƍznMP?Lt7[[BDNc>'RrttKQė٣%D1{JVF1ذ>wEh8=9)dYѽ{򽶗I[7 z+"IHxi¿5] GeM~_J߄?~ÒK|0k\{Skؕ`^VN,'f ыƎλ:J&O3=hv^Hure#3ۆQ5v-L,$fNmooHd,} J}yGCr"Ag5!m{1^&W@ՇwEazkDPm\9__^6$v}OؘOirR_̡">ltҫ*͈}zgD}W|rx>s(+_euwՓk㞚+-m۶ݱmvl;۶m۶m0o/vjÖ"x ~ڤ|jkI,zD]R.HƳx$o$R81ij U~H*W甐(#ѳ{~a9"<ixԱ}ԣ)R9դo^y1S#NaFJ>{R7kuskY[n)P[F |X!H ґTd~ۮ0ǟZYV<\LBa AB>sc JRg 8uO6Y`\_%h2iyףrsR.L5rą[頸 cBXۜuiA-BZڷ xF@_\$nU˺_rCF.Dxeui-(Sߑ@liP_~͍#CMQ T7- Ac-ڟcG^I;S`K< Ro@(@GĠ$2 >p_5̄W|==}V Zm;05T@Xڿ sk>?Miݫõ_EIYxS%{0|tY,V&Ōsaū;X& B׃}9ϥC {9,qdMrk%$K9wfO;ni ݽ,* z7e;W꩐rCs orfHxx'̞|NO<{CC aU68ȳQGfM'aZMXV{w?Al,?Vo(}v7ƌz.J8|!sI)HAOd][]KI+PͶMKN[ ?H7JfIyŌ+TꋿS̝^Ͳ[K;moi4Բ(\t)f?yyYc*5c C'/ܤM[SȝE},DFL$\g١`|/P@卝* k,.*jJA)sh%cZf)^.R0Pk$}stkUUط@^eHzl4}:$g&jސ ,I}-(w`O"`-h_7ZS/OqnJ&Z2}$xP0&޿db!|{HRq.xı%;^RbR0xҐ̈́9gPR6FX:/!~M)nu&x Qz1#ڎ[ULBir7~Mɠb'SF8iá,0|=~ΞoqmY^|Phu=sSX`OFCqv}$mF琊XhGJvbw3fCDLviHTQ5Q }''\!l]dx >e1Őc.Hn9_Df;贤٢xڷKhu3g˛$p #{p-i:X 2f ם4;rMMͮ6I'"w. ꗋCьM27.~uK .%In4tuC0=!"YXWYiM̟f[_K|ܧMCF}XVv/¿-8ɨ?HqdDUclm$ejxRVi"W@wxWM"[[u,4B˓c+WRFҫ`F/Fwt[xSmlD^GB=|2:AupJ Nmn-Y/q?8'mpzP$% _'꺾D <"e˨nRQ5C/ƃxe( ixZL+ړIi4BrQ6gg= nf5ڶ򻋋6dmmAw!xGI #aȕSZpɔpf7:#כKa=*cS ȃ=Tu@tCG~Gp/7boGp2FG{m ^D|GPٍCh(ƶQN=gWmÒRp)B 8@+8(Q24!@vZeʯvMX?l]ud)iB2d]:? Sey2 CLii Ȣ@EVo-b12ReR"0Uѐ5A:P_ȭW0ꋁQ{U3 83e}B˾!W 5JE /_@/>z(Y~ܚ@g3Ŋ^uFOr8"sءy~ܐ' 5C`vG!|v|$"(5ԎxE- rqwgPny$\UlV2J3j'ZeJ%YS.Z'XOuu 38Bޜ5z2E V-YsW" S M N.8ߍd/FJ&͚o a[~?aEK/~^D's+ppV` K@ja,!x{5Tj!kK ؕPqճĎ2s.oS8ќ,})1;eV-=d^[SIl''-_7~4M$@5ԭwt5Ą'nlָe?h?ANi4^Vycu|ZR< µ0tg.]Iu`+Yd`v7u?@'޾ 5ذORc8W9*Hqtʚ,D+" Ɓ툳};YjNRQxD[,Pm7O6,lߨ[EjMJ^vC4N#FʬA88y=hqJ]`"~u埏iGRwR:H&1$P$U,H^lLmrq:2Cs7ZaR[E+C`]OY$*I^*oz3a36Qث,ܲ^IP)‰ƒK// L%ZXl;,y%]1m0;H%{![? oQ/)( bVzơYs=8h;i_̞iQ3M]^˛R)v v题=Oc{υ#Q7YBXq=58sF?w |d;R$Pc|1ᑷnlO}؅7@uy?\j}9g S@4D z/3ۑ-{>O[9S(M-@C߸ܒ=ΫyxERHb &WC_3cnzLfyMD~x[M|O˓FTAFv~.eXaH! 6.qگq2@p f4zW[< wL,:V;n`<2t >gq#  1{ +WJK綊$3įn1 \&x\4̪wJ;J g=MUfB꼵; $Rq 12nO!IVxqvlJ^aS2%7$;2Y#jNh@~l/W%!I%/#WY6eْzKL41JtjRG̏nuGtiWEۉ4pxXR A~j*׉07҆>i'#w!6!ޑLX@xp:JggDF?2C}MMIVaAҪ[9Ъ/2՚9I#upqm[J<0A>tRFjXyK.n4O`EbWo(R10; ޞ208wb̀0Dr]Y]4>HWgƗ/tٳ࢐ai[8oOgTң96nYW2ʄ-{fμYEK+F؞D yXu.)L"I<:֘ގvrwXl6vD.^̐=u0N\JW:Id Kۥl\Ν$(/ovD @F>KeV4ɶ6& <3Ν:#;d%r*H3^Ub6% t*-Ua* y\ȉ`lPswA,sR0edZb;_4bEYLOKEV/4A(%b&GfPʫp\9YSr;0؎TSٞa_"l}? Loqa 5L_5NF$[/ 1δ0ߥirw brOWoL)YkLg'=k嚏e= nF3߁zmUQHqGaSv9]PmA̒hƜZieOЉěhh/!/ 1`` Wa>A^Y͗* &>=Z;/+_"/~ݎ2=QD*r(Լ XwUN?rڮפ"NT@PIGԟ5 kϥobpf̓edq[`C):x.Bސw.q5$]Rdg@V 7vtvLP z= zZ*W3a@_Q\񲽦X3V#e@ x^5LC84K/^/G͒fYtʅ l.1>s\R!U Z-ue!2kR^ז۲aW,䒑@k/G5#mxu]۬}% {q&sj rpEs׺<VMGlټL~k >?hhJh0g+Zŋj B iܥRY9ʒxKu|VyhEr-*[꜁3?n K,>zn.TPϡJcW;e@V֣y)򑑣^-pFdKu\ E?1;7SrA5nR&7:WULeDp]zFj O!V.iYji Ix9MC? Uxo#R^+HO't Bkԣ!?a˻)#`Ɏ~X4}'a1M!^h't9%$gnSkD>G -c‘ 9_Wq?2[oJH#$%\F=}r8{e6H[K؍~UѲqଔ vyi` ZH9H9zfXKRhne=VlGֱtW~70uqj4K oz|dZv 7LA%tOb]+ HK,X3jص*D ~ /t Fz7A)ΠY4#\VEC}K\vQ"h?ߛ .cw fJQWaЁ&J6!| jߊZ=?rIeV |˕ʼG.s`YgPQPKA*1Z\4V&]k\NWiG HVDfm9W !$:񮭫t>2>2 ɶp<*Fsg^pMw;'Yek;^t*k빛&s=²d)yjp7=wBt2CmECъ[ (Hέ-ҍrrE$ǔpD]{MܵQ1`qY7+:F3aF_ !y ?5ạLBb%oÄ A^1Kr_##c@m*"Oe?l›(໼{?muCL ۭ%mK^Oj`r=\#>^lAIޘ'S!#S=|{o- ]-$t-/q v7E} aŝ)xkvCW 6xYMJsm攣D$@ "JPili(|h'I^[ɮw9Urȯzj,Yz`PkD QTbaŒ=&{rmP!܆6;@ [Ǡiޑ1ZMg*B/XH x|4| $f /oǝיw/]O(;"`؍E:+'c.\7{0/8#/%zW'tweQ[L@ e>UD538 )r5?̮Z_RقigZCp>=D5Fds ]BZT|Yhc~ii;Gw TPEmĭyDD;%DmZTKa{5V],= uS02@(X{2vnYvb;, e j4 y+ TUB&a]u2dqz5f"ĜL6ٴыB#[,T& s>r!|h%׶ p[ !g%bmL_beFY#䧍1 /f8whQί : w1v- j)Ro<; ླྀE.;,iYJfaؔ/ԩј (_[J Ep2R1ib X9?2䉇|ru+3-|=ɓWگ *Nn߶-wj&ЭkRۆV^Х%+"0z$_զ@ ɴ?Y3LcޡP뷿kz]h?b?LO%J}7Ѱtwx BI@żܑ إ&1AQ96(mB,WmBhiw`$jc|5f?JN噞MLYw#bі8u(=4>)V/Xڄgop]T6|w֘o[b ~1YkΊ|햀rW>"?YDRDV;=o_/q`"AI=]nP|eTbɅ3FCHwzuX|Y~A ߟ,N^ ,ss،(ѽJ]$'5 OϝC7.F B:#R`/m(ɩPloV%g\Un^99]44ܷg„ _G1: .s aLW+xb?߃jR1> $0K[k3tz8 A-`zӁ&uteߌo[_*_p*pq)tw6Md4;>?IN2x,ԨFU3/bq{PIGP>7/Z1=~dW /Om+ZЏZ560:zh-ytEP=ҥkeF%~ϖ5 %PeaTǤ_Ht{$ endstream endobj 234 0 obj << /Length1 2436 /Length2 18184 /Length3 0 /Length 19643 /Filter /FlateDecode >> stream xڴeTK;w`!6;]K$%gsf{W/ُTVS*0 ;gFV&^(ldci`cba@q9[Dng {# :;M9=@cP9939vv@쌌*fHXܜ-Fvi&9&FncFv.N濗mstrvWE ӟ=&'$/%.(>xvrwu옜ݝSOHT}?,C*fg*}gG>QwA;v 7;.jv.@) ~7!m3:X@ĂOf叙]/{= ci|@r2r]>^t7B`Z8QA/;oh:gdg0!0˃ǁS?]lll4ZxWDhP9Ihhlb2 /ڟe>׏?4:9xrߵ4YBXDLI(1;9 `h> l/65-f&;{ `rDĘE>EYH wdw;r^ol4G8x&AL@62bkwVw-lf 5t rqG{߫{yNoJhw? ]@UK`7d}_ߕ ۹9hjߔK2v7zkkO8X;NPlug~c-o ?t|wtG{r3tpcWG;[w!l^]$Ͽ+@өq'_Xd ԰4}9iway:Y_ (-, rbx?R||W}ع|+_пnk MfA&|VMebДy/Yuq+h}s1I S՟%?ByPk /;_T^`Wr1sJQnNz4 '$Y%<9Lme+v}5Y)gp77DG|o׈5&tY?elMlJy܋dI oam[?b7 susne q76)Gb{qN+qIjÊTl4&v<`|JU%]DZx]T* Z2NaC]h 9KjB|$]0- ,C._$ɛeqn5g QUH^CR RzP6q~LZEAրIڙ&C1$X?q q>q&%]8x |X(3`FM>tc *EkdΞ—!jJy%~JKF 'Y#] ~KsO}Ȕ# ,WBk,CN%-;X1Ųp:?c/1G˅,$E7=grz(I{Qq7(3S^,u#+.8yqqּ+ E!W, rY5Uw涋±cZMCPу ,,VGZIC7- Fڗu<3z6_KJY1'JZ%],dp $Wc3PXTZXB݆Y<\%yuE73u#_G[(( 2#*("-^F9R@5ʟY$up!t>{ [QnqM i2oN'0yopcI>W>|g>;6% ɗ`{r& ʯؖ=ե_S`?j&B hj>Gtz;2^u$X)M) :,\ďüum,c _UT^rVCRǂ5D!F3e.LD;^}{+% VHgs~j?RLUn)P:d`Z泬Gn/<FmêsN:MrNg[GIIuehvU1Nmnx{5,%>yɐMټ;Uzlߢ:g/}]?O?5\h.6OQhrR/X˰)2# P ]i!h"qa}I #@^؍nݵMY>z3(.yhj G_  9xyD/*]"t%[ 2AhB!uԗ@{lM{go[Jib,E?+a jpk?K]" +Dx6kY(! /0؞~BTcʽ%!N<'9 Ӎt8=vg]SН) )3Wtn ؒ ߺSr4̮ROⵑBr| u{JO1`"ɋ|}~!_&$~a3.3MD` &j G+f0WebI>FVn˹(Dș=eu]^( 10@nIVVh])3(I@ԁK-aD˕ W6COzhF!BDVS"ŜBwRrLd\tzG ß1ݕuU\XChy:^  jdY_ZM@x& m8D4$F!]ͭZ>m{B5hTjIk*%21{?}'z 51o' AJ̖. 9(7ǵ2d=oj)"\@?C阌 @5Ӿ/Z&29uts*ƖW2_= kv( ґbeE|1)Imc"!ũ![0mP7%*OGz KH#.Js ~bN1M`x (a[-0f:># =݇GV|+\嬚۱Zl8dLc/dB $jvWkb]Adoc|BQlqʊ!z~$bHꦺG_(04UE Fzh}Z~fIu}[|A(.ڒRST%de c?h?Ƴ_z9_mVOV`؋m [eio-鴱M>s~ʯEb(N@~puD >Oϟx{2SqGk`NqP@`g2c!%To͍,IUQe+ B#RIȮ,vc(@B1|/J;PY9 svTzn2]~W'ʗ}@}4_A4eq5!.:v*#D &iOjUG8sߵrz,]@(|R_gOsA҄Yq_C*%zFlѿEl?(B} 1_#2S|%nbi8%Z*si }A 36fLes-Oqt$)mѮ\CZոˮt[g&\zPal[U] aE3T炝GcګMЍ M]APcUE/8ۂ-F绡8sRJ +xN1F$`ފƑіx3d呗nuO:%;$YĻ*5)~%e!Z^Cmղl04j1p{* <W.Hߞ>ĴM8]8}NuY]5<ɘ\g)85RذLn{v즩'U?C.`bDtuJ*9y ú[i2+r"8M~;=6.9Z`cJ ތZ͌Q皕CAd bq<9R[6'&<,QE<'f];o`]OpjtI|DS}Uaj[yu\|]]p"+_Y#3,("kj|2nk6E"@^ע3"4F95gaiQXy3n#{' }Og2b!1MũcL)ൃg|Qs_s}>#P ݵBؽNlJ@w|k2::i`u}3(zbJ9g \w蒊F\=<,jNP3C=QM\uc<]i-Tu8^&g@tq7蠨J,>)-6>"6%rmX~e<*-\Q w}0eAk~Nܥr\|:)O峎)iQA*>o1:2pe"=NV/ȍmјZ,9mr6]Q6iF!:H 4%[NULv| 9j^}fxjm0HW8Z~VS^)\'x] 9΍&ǯk7 Jt#(M/݋ѬΔq!X" 5R#ɱY#%xe;7pq9_q 2ҵ¤L=oeXNI(&p^58h%劎kvHwᬡ"Z / ɌMTi-fߗzoCj~Ɉ zń#=HZ'Xsg4藥OxP"d1 }}L-as4E.>:SUc0\b_-H\4lp|q%g2W_ &]`h>Vը~ep3$(v!feXkjA;S0ֺk'SA@ Fg X 6gHj,CN>NhCֳ-PKglkЪaփtGA ` @Vzlw3˂,QE;#Qn[3 }9SHH{6wcyF69NC6 2R͓RZĥG-;!4 K*QAāCPӧ3qF8sO:c  `@}zFjdIXG=?#"K֪>_3'i-r9u9r/3szv(#xa8i{$ebrP1M E **o>^(*+iFue&UFQdBԠ1@YvB[QjAC̠3>tԘ(gh f>% b2|h ܶO1Xz{4g᭬'wGxSX{&w7Fp@L>'ԀrS%Z7^S [$;>0k NkؓǤؒ? U? 9YQ-+uOLK#ę.ؘed^*x`e ]!fBԞ" DxA( :Ms _G ;Vѹ3·$'1ݤB,WYGS"^)MCǙ(Wy:'R]ҞuM>6&--03H|щ0jU/ӆi*H &w1W}$%jS"p p_@O,{ϱ F|SD"n2JߡnC@5>WLL2GIVc:tSH"w蓔 TeD!$Dc c(k> =Ii Zr|HPJ `{햎Ǻ}a"*vhNg+?cZ5%=o~ۤyq{!z4cϷg=m!mEiF0*~\5f7"ÐO?L^2H2NJ~gw)x)-K7^deBIޓrPWEy8\斯-.G@\IfEwj~)>qY&FdhZ?M w&p 3A| ݮDJߏT 5+M̽]:z)ghq'8q0Հ,^I tk'6}Y {|n{)y1l)g_%J ^iO:Uh0)P Zo>> 3Lw9_2 T1F9Ԇn:=@}Y yb̦FbEY=lG?hfQ1n StFbo6T֩R0n2%KA _ʣošcb󵤲,wwxlDq'ۜGj$ӣJUbj\?Qw/PsrOXѪC#NyjrQ @‘uY湨c~62,KpJ cx4 YzSS/$j52*c)ne &q:MMpm ־4};#$?R}IyD_D}9bGL5 b~~E$(߱t#+JS''V:7yԧ&?=K֜Kr}OFGeKOohxqY2Fr|*ѯ5!@-*cnD+ŏP tOg8m A~[+Iq^s݈50X:f"ޭzn+&C^UR<"vlt1jШP Ya hDT"E T4.(T9.9^T8j4_QT⼍uyeW>l1Α\G,^9g"%NK_ΘE3J7FHt?dI0^<\x.MD_gH΃uctKiv -:pݚZ'-aK/ĝGX-$b3+ޒ=;8RwE9Ca~An*_0=J*HH蔼{ûDc?G7d$Offue{lVa(x!L8`fR%)k?H%G*?eUjy:8f3 K>h;C$CUL251s>Vh7;L-jPwޘ}kAg4PEA1mei6unts^W3؏9tb ̖lNt͢J8 )= Ctk|4IW2`l+nLٍd9wij5{FK|l38a3#p Z ]; >}i&qzL Ե 5Wle3E9tPz,r< ͟.>/F!zJd[+k~;A.Oͼg"Zkp'TY{%<,;Aβ0L>U}u'P{ 7˘:ז`Y\AA=|(;P>󐿴:*pb} 13- 5RT"O xfN=߶a'1M`O~hYpQ=RBWKB4 }kP FP]M޲}vR<\ӧAbiװ-r7ψ2.,42hǫDok5 7c^CpmxE7y#W˹g~l:KoJ.M3oF&v~֫.@t&I8|0J]0@U_سvp؁=@ބ}D-wUw>8 i,9'6J2w _fUEgh~Z/»1!8)6#aYp¦m[j/}V>siE&b'c'ճ'I524d*jЮzR10*o.4X!Sm.C+;߸Gssq;6SI7J{>/!}Ow1nx&4T<Ao+3%_`M p1:1m:tL扊o@@pEA]| ~1bnQR {#o`!0_?mW8@}gfXs金xRAJP;wP63T(((w"sE@(.o9yML82bq3wbs̖0=V-.+GUKAy~2qƃª af2ǯ^p QKAە'؊ !k; Il`j_:oSѭsIʹQ.pLp)T#rn,[J)FRw3|L"]OI`&8L7v&>{>EF YÙM.vu#AOa>{~`흔|>DiQp[*귻3"<{NW?-* oGoZ^E{NC nnFfu~mq`}wq\ƷTGg}?~z-iA'!qGE2qKҸnUfYOPSsIm7mi.m(OF9KEɗPƹڧnK6\ V}":NL0ylUB"[9AgM̳Q /%l\z/w0iލ[luϫ&ȚND 5Bz4~._8ӄDΫ?fI{}XpRO`&qn-_jG-eg.H*c73ф{"hgy8CPl4p7Hhu5}‘˚^w89AmhU C|AV9j&|P~KpA6 ̌h_#5HGs]굱8aiٿ1N+,`HK/6骉N] Я;)DcW4~2_^ G`O v@!`ǐfX*@n]oe7).kd. g2/.S>bEhHq98$8U6 *(`ͪKj&E}zhRh+/t(qKJuMZox-wtt:TXCҮ=ߤ7K4Qq,5RpiD^,1U P1zq=_\T᧌eֳÃ5!;Wau*7҇7*!&u/=A͵׏!-3OLLCY:T8E?lx^ضVזt4YCOGD}|. f26 6fԵẲygiޭaT_\E8SjDL" )ߋ<ǀbxFe*L!G 9wv~DPհ$ɩ֕@6ŗ8+W+bw{/mH#ju= 3yz9tYp݊aKC/֎O}+V`Nlb^z >G;+幑q/'6t`_Ne*|c_b"p{ۺj F I'4Y8rjřx*E#lHk\åۺU5w dXZEޚdvO  - \+e<"ܰLB+!im!*zSS-īHఫdy-6{&sՕag̾`'ڈVj|yCVLISvǾ\pEE+QZ}.ݽ@'f'$g6PaE. 5_VRX??$Ad~:?쬓̄z?x)vbs{\p9I45:4s، r XoaT?!lF3~zl>-C[n-&p\9TfL2"k!?{¨Ĩ6ljDia7t)xI@];_Ah B>)/b) ڄl7DN.7IJFA=J7ګG7 )јC@qwt=k.ޭA0pt^%6}@PҺ-t*9LyChZxDt˝${%'}`^7L]Q}9 e&/8vU~MD=3^2XK'k^W=@Ig׵Eg7amN )ʵWYqQ>~2 VjNH3C WŽ$ay:\f8zxϯs_2<ǃM@q:hj@ZD7G8 IfIL?ws:ç0_j[ N$u_㰘5~*pYi$eZ_S"nh#>{ސ!!K["ksW?ۏ{ahH]jRpNǬ M0WEQ9|rUn8G9W$&8b??jK_T/仄nXIUj + `2Do&HӂLkAяFvb_A9& d_h@&xp{Z}YG[{XTRnзAѵXM5"!8rES:Ġ ͨXg6\a{bg\!u٬ÉA?(hb3:M{x ]^u-IS d~W9m1]3\{vp?͕_p s;z2|nY9z6j:r)xAʋ wMnC!NٵYkE P" s(ӊ,,-$@"Zg6 G~=2_ﻴfd!Pg:qKdBT{`#V j{֜B+@k$xuB>DQYrN:ӟ?1۹_=iI1p$cZs݃ZvpH?DjZV㴭g䁭/w v/A<*bX/k0WZ;x]"zcB HZ(1{!,lUl[w*z} `7|=K'A\yU< >SH 7w鈺aи]qgAIdd7ˆV:O^ssB qDDGTEA;/2a!s z9<10ֶ Qn O*b!cj[rJ`| *+\db`|TXbEkgS3f~c82lXͬf<&|= 1Y.\9hedI?2,x6=E3`:t/5K& bc=V>+RK&YK endstream endobj 170 0 obj << /Type /ObjStm /N 100 /First 896 /Length 4505 /Filter /FlateDecode >> stream x[Yo~\ 88gOؚȒG"Ւ,YJ4-6KWUlI9_BPV3 utUHp**\Ehe=bU!S|_F^BinGszM7(Ѣ:@ܞIjWDOǕ*RPAc>*0jH <1XAX rp>J4FwGoF_rҟ/Z_{yaME.)}I&Wҿ-$AhHB>)Fs.oGV*wx5lX [FM\%v+ U"`nng0^X`42~U.MR*aF7/^G'5,U 6-wV{N'@ē0msճ߻;VSxXV~/qAj4<,<Ϥ-Nx7~ (=/aph a_\ǷBϿߖ~wbbUJ7ɪXCV f<2A/,L/V [X- OP/m!~Z1ѧi9/ƋG+q4iYzԕDU:,کc1k`ޔj~Hd4,W'e}z%=c1'uo|r.&<c-+$`x+F?׎7`E!pp'4eZ7ikC,u6n6l\$e0+f 3Ko6,̆}Hif" d?z9ͫ1IH*V8J0Da"^QH*U5-\k}j(r9=kU5$J6XOVPa'geۙJɓցLx?Ϡ#a %_cq5^4H\r],+eۺ.T)ɖJ ina[@Ó;(d,=H銶yELH!z[+ꋬ!'P -djB c;M$`$*nK0u_LeO ӹ? CTgFlaFq-uyY.v'%{{:T>?u7:W͒ƧvWR;кrW V8[621{"jl6h T؋MJvp߼fYM>6t-S6X5`U9uǕS΃lN==euE^h%sEGK*:ClY1\ɐXP*a(,6ǺOܒ"WE Gc4F/G$ N-|ԎA$PB9V}Qt`i K"@k@OQ#4ZJ(Tӽ*EC" LL"#qy҄ELFDvC!FaHJAA3j@Xe8 |Ob8!N`H\NX5jז T̿OOg N}|ڔE2<^2HiR 5K!䣥TuӿQJ״s^xL5)!is(Sz !MQ*d;&\7" ZJ%ZygHΑdC[451{[ت6^V>׶R,SGٳOiys4NfTMG{y Xj뉌+_ɻ`u$a yL䯤96.0mfXnG+zCJgֲqz޽'ϴD (ȴ5TŬmznbg T+ًvD:[^:H*qG*1ҝLR2[{^u\Z =ӷgSeSgFR;ft>I 9ϴ\g֥lѕ51Â2ZԞj}V{p%Ik'͎hluK0'!S B9"'f/.eFYSy8mcr)n"XGYIJΑH ;mR\Dj(MQM8ˬӜPsNGɸ9ӑ}<}zt*yhp٤]~v_K)c^Ľ壺voiBzvKE xOg{pZ_nO;a1g"=q_<x&^Cʼn8 FCq*jI|j,Ĺ苁C1a-.şWDLTLu-_GJ|_}ez8b5to>:/Ce:;nkۂ{!^v z2xa^y={֛'|볫Ao|=FCN,Z 4 EN@Q] 9F{rNjv*+.Jވɠ79WPoO>ZP.맕A?~JVk"x _tTeQvrđD}#fJ3v!G_9G+7@x/ 7<I?NkgћI=?MSiLss=mQN>>]\XXRQ_D=L^D9G3zC|T4색Z>o\JC!D Mӏnܤ|lE??`vb:N%ǣyonxEM7peDX6p&77uV-MM?ɄaoZoEwoI`(4}fV9Wk9VG=Dd.do,u;t CbRR5;ް* Ta"9[-.G"%bHܛ+WvGb-^lkˎ5w+cPMK 8e:b<&.2uBOI\yp:G-A<KqvoƠ 6"Ou:\,. W fv!ؚhj^6ߑMEٖp.d[\MEtXaRMD[Q[-y]mv̴$3jQ2S-$V纋-̃; ݢdn vj7/X%b[)a\[(mG/P opKne]Hw",# ]F/n/M--].΅]([]}Z)d~ w%3o 4l4J6~g;^!SYm2O;ϏE?3(Wyfje_R+6}_.tyq5`0ɐZXd[囎}l_ yJ܎/Iiڞru|(Ϸ_a".z^#@z($_jad$dnU3~~)t=YsQ-ʮGwǑ׌q` endstream endobj 252 0 obj << /Author(\376\377\000R\000e\000i\000n\000h\000a\000r\000d\000\040\000F\000u\000r\000r\000e\000r\000,\000\040\000R\000o\000m\000a\000n\000\040\000F\000l\000u\000r\000y)/Title(\376\377\000I\000l\000l\000u\000s\000t\000r\000a\000t\000i\000o\000n\000s\000\040\000a\000n\000d\000\040\000E\000x\000a\000m\000p\000l\000e\000s)/Subject()/Creator(LaTeX with hyperref)/Producer(pdfTeX-1.40.19)/Keywords() /CreationDate (D:20191212133051+01'00') /ModDate (D:20191212133051+01'00') /Trapped /False /PTEX.Fullbanner (This is pdfTeX, Version 3.14159265-2.6-1.40.19 (TeX Live 2018) kpathsea version 6.3.0) >> endobj 238 0 obj << /Type /ObjStm /N 15 /First 121 /Length 792 /Filter /FlateDecode >> stream x}Un0+x (Ȃ@R7HSm36-EwFjINCgyofIOB),",IDpf!#<{@eH(eKQ>c!'4 V# A ƑO%4l[\ <W$>@޵|y) l/N B߳j=͜D9^}.=.P gǗ2ZYg~<ى"K9IcG{+T`̩h]r/Ń*px0޵y4,TQt'+q (JRHuxPMDh)lʇ>Cw&ťq$|jdCotRUnz/t-Bֲ6l}.`Xm^ն|-FU9~20?Ѕ:vX1'`[j[&5B.UF\ho%w0vFSxbU5Ƴ^X~{;w(@ Iw#n? }W}QwDcQ\ bCd]fOb;WJoT)WFY -rlW1']3jƷoXȘtH3{J &YHhD{~D~}-3;(u媔PPYap|6߬NI!`@' #Vy;4k9N'4j0.V2++ï_3t!WG޷#ܽ<%Y#jq `ݹ}ٶ ݧ[şZv඗U˃JV endstream endobj 253 0 obj << /Type /XRef /Index [0 254] /Size 254 /W [1 3 1] /Root 251 0 R /Info 252 0 R /ID [<42586C188CD152460ECA26AAF17B06D0> <42586C188CD152460ECA26AAF17B06D0>] /Length 634 /Filter /FlateDecode >> stream x%9STAFcA\@}Q\ED`lj斓r)#&FFV5R"w{V !/Լd$!i5E``Nʁb0 v2p{r!O +@%C .<0 Ԁ}`?8CuAhG@Px088 3DnK ]r6d'ݠV 6//  U)J\٭U6'5͍q u6N,4S'j8N3`‹ZXҼO8~mp]E ~U7,l4j ͑θdF N$ȲMfu٬XLILʮK;;;z+?\IH2]>K`\rqܑg:4Iv9)Zatz h2_ #w5h/=fϊzͶf,PXӮ4`ҠJCռSlЙ^R{n̲?-*Q“'/)X)s$BⓑhECG[Ӓh@r]ru? endstream endobj startxref 341789 %%EOF spam/inst/demodata/0000755000176200001440000000000013440250504013742 5ustar liggesusersspam/inst/demodata/germany.adjacency0000644000176200001440000004127213440250504017255 0ustar liggesusers544 0 1 11 1 2 9 10 2 4 5 7 14 386 3 3 9 10 12 4 4 6 10 11 13 5 7 2 14 15 37 39 384 389 6 2 4 11 22 8 16 18 19 26 490 491 493 494 23 6 20 21 24 31 32 141 24 5 20 21 23 529 542 25 5 16 17 19 30 31 26 6 16 17 21 22 31 490 27 1 30 28 8 33 45 46 58 59 60 63 105 29 5 30 31 32 34 104 7 4 2 9 12 14 8 4 12 13 15 43 9 5 1 3 7 10 12 10 7 1 3 4 9 11 12 13 11 4 0 4 6 10 12 8 3 7 8 9 10 13 14 15 13 5 4 8 10 12 43 14 5 2 5 7 12 15 15 6 5 8 12 14 37 43 16 5 17 19 22 25 26 17 5 16 21 25 26 31 18 2 19 22 19 9 16 18 22 25 30 35 44 493 497 20 7 23 24 138 141 144 520 542 21 8 17 23 24 26 31 490 502 529 30 9 19 25 27 29 31 33 34 35 42 31 8 17 21 23 25 26 29 30 32 32 5 23 29 31 103 104 33 6 28 30 34 42 45 105 34 5 29 30 33 104 105 69 3 77 78 88 70 4 66 67 71 76 71 5 66 67 70 79 92 72 4 73 74 89 90 73 4 72 74 76 90 74 5 72 73 76 89 112 75 3 78 79 95 76 11 65 66 67 70 73 74 77 82 83 90 112 77 10 65 66 68 69 76 78 82 85 86 88 78 6 68 69 75 77 79 88 79 8 66 68 71 75 78 92 95 97 80 1 84 81 2 91 146 82 6 76 77 83 86 90 91 83 3 76 82 90 84 4 80 85 87 88 85 5 77 84 86 87 88 86 5 77 82 85 87 91 87 6 84 85 86 91 146 159 88 5 69 77 78 84 85 89 8 72 74 90 91 112 114 115 147 90 7 72 73 76 82 83 89 91 91 9 81 82 86 87 89 90 146 147 152 92 4 67 71 79 97 93 4 67 97 107 111 94 3 96 98 99 95 6 56 75 79 96 97 98 96 7 94 95 97 98 99 110 118 97 10 67 79 92 93 95 96 107 108 111 118 98 8 49 54 56 59 94 95 96 99 99 7 59 94 96 98 101 110 117 100 3 101 102 104 101 7 59 99 100 102 104 106 117 102 5 59 100 101 104 105 103 6 32 104 106 113 141 143 104 9 29 32 34 100 101 102 103 105 106 105 6 28 33 34 59 102 104 106 5 101 103 104 113 117 107 6 67 93 97 108 111 112 108 5 97 107 109 112 118 109 4 108 112 114 118 110 4 96 99 117 118 111 3 93 97 107 112 8 67 74 76 89 107 108 109 114 113 7 103 106 114 115 116 117 143 114 7 89 109 112 113 115 117 118 115 5 89 113 114 116 147 35 4 19 30 42 44 36 5 40 41 43 61 64 37 6 5 15 39 41 42 43 38 7 39 44 361 389 390 495 497 39 6 5 37 38 42 44 389 40 5 36 41 45 61 63 41 6 36 37 40 42 43 45 42 8 30 33 35 37 39 41 44 45 43 6 8 13 15 36 37 41 44 6 19 35 38 39 42 497 45 6 28 33 40 41 42 63 46 4 28 58 61 63 47 2 52 57 48 3 51 58 61 49 2 59 98 50 1 55 51 6 48 53 55 57 58 61 52 3 47 57 62 53 6 51 54 57 58 59 60 54 5 53 56 57 59 98 55 5 50 51 57 61 62 56 3 54 95 98 57 7 47 51 52 53 54 55 62 58 7 28 46 48 51 53 60 61 59 10 28 49 53 54 60 98 99 101 102 105 60 4 28 53 58 59 61 9 36 40 46 48 51 55 58 63 64 62 3 52 55 57 63 5 28 40 45 46 61 64 2 36 61 65 3 66 76 77 66 7 65 68 70 71 76 77 79 67 8 70 71 76 92 93 97 107 112 68 4 66 77 78 79 116 7 113 115 134 136 143 147 155 117 7 99 101 106 110 113 114 118 118 7 96 97 108 109 110 114 117 119 2 124 130 120 7 121 125 126 127 128 130 132 121 3 120 127 130 122 5 125 128 131 165 179 123 7 124 125 129 169 178 199 201 124 6 119 123 125 129 130 298 125 9 120 122 123 124 128 130 165 171 179 126 6 120 128 131 132 134 135 127 9 120 121 130 132 137 139 298 299 304 128 5 120 122 125 126 131 129 5 123 124 200 201 303 130 7 119 120 121 124 125 127 298 131 6 122 126 128 135 154 179 132 6 120 126 127 133 134 137 133 4 132 134 136 137 134 7 116 126 132 133 135 136 155 135 5 126 131 134 154 155 136 6 116 133 134 137 142 143 137 7 127 132 133 136 139 140 142 138 2 20 141 139 7 127 137 140 299 300 513 526 140 6 137 139 142 144 513 514 141 7 20 23 103 138 142 143 144 142 6 136 137 140 141 143 144 143 6 103 113 116 136 141 142 144 7 20 140 141 142 514 520 527 145 3 151 154 155 146 6 81 87 91 151 152 159 147 6 89 91 115 116 152 155 148 6 149 153 171 173 176 179 149 6 148 153 157 160 176 326 150 4 151 153 157 159 151 8 145 146 150 152 153 154 155 159 152 5 91 146 147 151 155 153 7 148 149 150 151 154 157 179 154 7 131 135 145 151 153 155 179 155 8 116 134 135 145 147 151 152 154 156 1 160 157 6 149 150 153 158 159 160 158 3 157 159 160 159 6 87 146 150 151 157 158 160 6 149 156 157 158 322 326 161 3 164 178 199 162 2 175 180 163 3 172 177 180 164 3 161 178 199 165 3 122 125 179 166 2 172 177 167 1 180 168 3 178 196 201 169 4 123 171 172 178 170 2 180 325 171 6 125 148 169 172 173 179 172 9 163 166 169 171 173 175 177 178 180 173 5 148 171 172 175 176 174 5 177 178 195 196 197 175 5 162 172 173 176 180 176 7 148 149 173 175 323 325 326 177 6 163 166 172 174 178 180 178 11 123 161 164 168 169 172 174 177 196 199 201 179 8 122 125 131 148 153 154 165 171 180 8 162 163 167 170 172 175 177 325 181 4 182 183 185 186 182 6 181 183 185 203 204 217 183 5 181 182 184 186 216 184 5 183 186 192 193 220 185 5 181 182 186 188 204 186 7 181 183 184 185 188 190 193 187 1 188 188 9 185 186 187 189 190 196 200 201 204 189 4 188 190 191 200 190 6 186 188 189 191 193 288 191 8 189 190 200 288 292 303 304 306 192 6 184 193 220 313 314 319 193 6 184 186 190 192 288 319 194 1 197 195 2 174 196 196 9 168 174 178 188 195 197 201 203 204 197 6 174 194 196 203 205 209 198 2 199 201 199 6 123 161 164 178 198 201 200 6 129 188 189 191 201 303 201 9 123 129 168 178 188 196 198 199 200 202 2 203 204 203 7 182 196 197 202 204 205 217 204 6 182 185 188 196 202 203 205 6 197 203 209 210 217 218 206 2 207 208 207 5 206 208 211 214 215 208 4 206 207 209 211 209 5 197 205 208 210 211 210 5 205 209 211 212 218 211 7 207 208 209 210 212 213 215 212 5 210 211 213 218 224 213 4 211 212 222 224 214 2 207 215 215 3 207 211 214 216 6 183 217 218 220 221 224 217 5 182 203 205 216 218 218 6 205 210 212 216 217 224 219 2 220 315 220 7 184 192 216 219 221 314 315 221 7 216 220 223 224 310 315 318 222 4 213 223 224 316 223 7 221 222 224 310 316 318 320 224 7 212 213 216 218 221 222 223 225 3 233 242 243 226 3 231 236 241 227 1 244 228 3 240 246 257 229 1 246 230 5 237 239 241 245 247 231 6 226 235 236 241 243 311 232 4 234 240 241 244 233 8 225 242 243 253 265 293 294 319 234 5 232 235 240 241 254 235 6 231 234 241 243 253 254 236 6 226 231 238 241 245 311 237 3 230 247 317 238 6 236 245 247 311 312 317 239 3 230 241 244 240 7 228 232 234 244 246 254 257 241 10 226 230 231 232 234 235 236 239 244 245 242 5 225 233 243 311 319 243 6 225 231 233 235 242 253 244 6 227 232 239 240 241 246 245 5 230 236 238 241 247 246 4 228 229 240 244 247 5 230 237 238 245 317 248 1 254 249 1 255 250 1 258 251 6 252 255 256 257 258 259 252 3 251 255 256 253 6 233 235 243 254 265 267 254 9 234 235 240 248 253 257 258 259 267 255 4 249 251 252 257 256 4 251 252 258 264 257 6 228 240 251 254 255 259 258 7 250 251 254 256 259 264 267 259 4 251 254 257 258 260 1 263 261 1 267 262 1 266 263 6 260 265 266 268 275 291 264 4 256 258 267 268 265 7 233 253 263 267 268 291 293 266 5 262 263 268 269 275 267 7 253 254 258 261 264 265 268 268 5 263 264 265 266 267 269 3 266 275 282 270 1 274 271 1 275 272 1 276 273 1 278 274 10 270 275 276 277 281 289 292 301 302 305 275 10 263 266 269 271 274 277 278 280 282 291 276 7 272 274 279 281 301 521 538 277 4 274 275 289 291 278 9 273 275 279 280 282 447 450 525 533 279 8 276 278 280 281 525 528 532 538 280 4 275 278 279 281 281 4 274 276 279 280 282 3 269 275 278 283 1 288 284 3 285 286 289 285 3 284 286 290 286 7 284 285 287 289 290 291 293 287 2 286 293 288 9 190 191 193 283 290 292 293 294 319 289 7 274 277 284 286 290 291 292 290 6 285 286 288 289 292 293 291 7 263 265 275 277 286 289 293 292 7 191 274 288 289 290 302 306 293 8 233 265 286 287 288 290 291 294 294 4 233 288 293 319 295 2 298 303 296 1 305 297 1 306 298 6 124 127 130 295 303 304 299 5 127 139 300 304 305 300 6 139 299 301 305 521 526 301 5 274 276 300 305 521 302 4 274 292 305 306 303 6 129 191 200 295 298 304 304 7 127 191 298 299 303 305 306 305 8 274 296 299 300 301 302 304 306 306 6 191 292 297 302 304 305 307 2 311 312 308 1 317 309 1 320 310 3 221 223 318 311 7 231 236 238 242 307 312 319 312 8 238 307 311 313 314 317 318 319 313 4 192 312 314 319 314 6 192 220 312 313 315 318 315 5 219 220 221 314 318 316 3 222 223 320 317 7 237 238 247 308 312 318 320 318 8 221 223 310 312 314 315 317 320 319 9 192 193 233 242 288 294 311 312 313 320 5 223 309 316 317 318 321 3 323 324 325 322 3 160 324 326 323 5 176 321 324 325 326 324 4 321 322 323 326 325 5 170 176 180 321 323 326 6 149 160 176 322 323 324 327 7 328 333 353 358 360 362 372 328 6 327 340 348 353 360 369 329 2 341 365 330 1 343 331 1 345 332 3 345 348 366 333 2 327 362 334 1 335 335 5 334 344 363 370 396 336 4 340 344 366 369 337 7 346 351 367 436 448 452 457 338 6 343 345 348 350 353 355 339 7 341 352 357 362 470 471 472 340 7 328 336 344 349 360 369 370 341 8 329 339 358 362 365 472 487 489 342 6 343 346 355 356 367 368 343 7 330 338 342 347 350 355 368 344 4 335 336 340 370 345 5 331 332 338 348 350 346 5 337 342 351 356 367 347 3 343 350 368 348 7 328 332 338 345 353 366 369 349 5 340 359 360 370 394 350 4 338 343 345 347 351 6 337 346 352 356 457 468 352 6 339 351 356 357 468 471 353 6 327 328 338 348 355 372 354 7 358 359 361 364 365 371 492 355 6 338 342 343 353 356 372 356 7 342 346 351 352 355 357 372 357 5 339 352 356 362 372 358 7 327 341 354 359 360 362 365 359 6 349 354 358 360 371 394 360 6 327 328 340 349 358 359 361 7 38 354 364 390 395 492 495 362 7 327 333 339 341 357 358 372 363 5 335 370 394 396 404 364 5 354 361 371 391 395 365 6 329 341 354 358 489 492 366 4 332 336 348 369 367 7 337 342 346 368 436 439 440 368 6 342 343 347 367 439 458 369 5 328 336 340 348 366 370 6 335 340 344 349 363 394 371 6 354 359 364 391 394 398 372 6 327 353 355 356 357 362 373 1 385 374 3 393 394 407 375 2 381 399 376 1 401 377 3 387 400 403 378 1 408 379 5 380 383 392 393 407 380 6 379 383 385 393 406 409 381 4 375 382 399 408 382 5 381 388 399 402 408 383 5 379 380 385 387 392 384 4 5 386 389 401 385 5 373 380 383 387 409 386 4 2 384 401 408 387 7 377 383 385 392 397 403 405 388 6 382 391 399 402 405 407 389 6 5 38 39 384 390 401 390 5 38 361 389 395 401 391 7 364 371 388 395 398 402 407 392 5 379 383 387 405 407 393 7 374 379 380 394 404 406 407 394 10 349 359 363 370 371 374 393 398 404 407 395 6 361 364 390 391 401 402 396 4 335 363 404 406 397 4 387 399 403 405 398 4 371 391 394 407 399 6 375 381 382 388 397 405 400 1 377 401 8 376 384 386 389 390 395 402 408 402 6 382 388 391 395 401 408 403 3 377 387 397 404 5 363 393 394 396 406 405 6 387 388 392 397 399 407 406 4 380 393 396 404 407 9 374 379 388 391 392 393 394 398 405 408 6 378 381 382 386 401 402 409 2 380 385 410 2 423 429 411 3 427 431 449 412 1 434 413 1 442 414 2 447 450 415 2 459 463 416 4 417 444 454 462 417 6 416 418 441 454 456 463 418 6 417 441 447 450 451 463 419 7 420 434 439 440 443 446 455 420 4 419 427 440 455 421 6 432 435 442 477 485 509 422 4 425 429 430 444 423 8 410 429 433 437 438 453 456 462 424 4 428 442 466 482 425 4 422 430 431 449 426 6 435 437 445 448 452 453 427 8 411 420 431 436 440 445 449 455 428 6 424 442 457 460 467 471 429 7 410 422 423 430 437 444 462 430 6 422 425 429 431 437 445 431 6 411 425 427 430 445 449 432 4 421 435 453 509 433 7 423 438 453 459 463 509 535 434 5 412 419 443 446 461 435 7 421 426 432 442 448 453 460 436 6 337 367 427 440 445 452 437 6 423 426 429 430 445 453 438 4 423 433 456 463 439 6 367 368 419 440 446 458 440 6 367 419 420 427 436 439 441 3 417 418 447 442 10 413 421 424 428 435 460 477 478 482 484 443 3 419 434 461 444 4 416 422 429 462 445 7 426 427 430 431 436 437 452 446 4 419 434 439 458 447 5 278 414 418 441 450 448 6 337 426 435 452 457 460 449 5 411 425 427 431 455 450 8 278 414 418 447 451 519 533 543 451 5 418 450 459 463 519 452 5 337 426 436 445 448 453 6 423 426 432 433 435 437 454 2 416 417 455 4 419 420 427 449 456 5 417 423 438 462 463 457 7 337 351 428 448 460 468 471 458 3 368 439 446 459 7 415 433 451 463 517 519 535 460 5 428 435 442 448 457 461 2 434 443 462 5 416 423 429 444 456 463 8 415 417 418 433 438 451 456 459 464 4 466 467 469 470 465 6 469 474 476 482 498 499 466 5 424 464 467 469 482 467 5 428 464 466 470 471 468 4 351 352 457 471 469 7 464 465 466 470 472 482 498 470 6 339 464 467 469 471 472 471 7 339 352 428 457 467 468 470 472 6 339 341 469 470 487 498 473 2 478 482 474 6 465 476 490 494 496 499 475 4 476 481 482 483 476 6 465 474 475 482 483 496 477 5 421 442 479 484 485 478 6 442 473 480 481 482 484 479 8 477 480 484 485 510 515 523 536 480 6 478 479 481 484 512 536 481 6 475 478 480 482 483 512 482 10 424 442 465 466 469 473 475 476 478 481 483 8 475 476 481 496 502 512 529 537 484 5 442 477 478 479 480 485 7 421 477 479 509 515 517 535 486 4 487 498 501 503 487 7 341 472 486 489 498 500 503 488 6 491 493 495 497 500 503 489 5 341 365 487 492 500 490 7 21 22 26 474 494 496 502 491 6 22 488 493 494 501 503 492 6 354 361 365 489 495 500 493 5 19 22 488 491 497 494 6 22 474 490 491 499 501 495 6 38 361 488 492 497 500 496 5 474 476 483 490 502 497 6 19 38 44 488 493 495 498 7 465 469 472 486 487 499 501 499 5 465 474 494 498 501 500 6 487 488 489 492 495 503 501 6 486 491 494 498 499 503 502 5 21 483 490 496 529 503 6 486 487 488 491 500 501 504 2 511 516 505 1 517 506 2 523 541 507 2 522 540 508 1 541 509 5 421 432 433 485 535 510 4 479 523 536 541 511 7 504 516 518 522 531 540 541 512 5 480 481 483 536 537 513 6 139 140 514 518 526 534 514 6 140 144 513 518 524 527 515 5 479 485 517 523 539 516 6 504 511 518 524 536 541 517 9 459 485 505 515 519 530 535 539 543 518 7 511 513 514 516 524 534 540 519 5 450 451 459 517 543 520 4 20 144 527 542 521 8 276 300 301 522 526 528 538 540 522 6 507 511 521 528 531 540 523 8 479 506 510 515 530 531 539 541 524 6 514 516 518 527 536 537 525 5 278 279 530 532 533 526 6 139 300 513 521 534 540 527 6 144 514 520 524 537 542 528 6 279 521 522 531 532 538 529 6 21 24 483 502 537 542 530 8 517 523 525 531 532 533 539 543 531 7 511 522 523 528 530 532 541 532 5 279 525 528 530 531 533 5 278 450 525 530 543 534 4 513 518 526 540 535 5 433 459 485 509 517 536 8 479 480 510 512 516 524 537 541 537 7 483 512 524 527 529 536 542 538 4 276 279 521 528 539 4 515 517 523 530 540 7 507 511 518 521 522 526 534 541 8 506 508 510 511 516 523 531 536 542 6 20 24 520 527 529 537 543 5 450 517 519 530 533 spam/inst/CITATION0000644000176200001440000000500213537626553013340 0ustar liggesuserscitHeader("To cite `spam` in publications use:") citEntry(entry = "Article", title = "{spam}: A Sparse Matrix {R} Package with Emphasis on {MCMC} Methods for {G}aussian {M}arkov Random Fields", author = personList(as.person("Reinhard Furrer"), as.person("Stephan R. Sain")), journal = "Journal of Statistical Software", year = "2010", volume = "36", number = "10", pages = "1--25", url = "http://www.jstatsoft.org/v36/i10/", doi = "10.18637/jss.v036.i10", textVersion = paste("Reinhard Furrer, Stephan R. Sain (2010).", "spam: A Sparse Matrix R Package with Emphasis on MCMC Methods for Gaussian Markov Random Fields.", "Journal of Statistical Software, 36(10), 1-25.", "URL http://www.jstatsoft.org/v36/i10/."), ) citEntry(entry = "Article", title = "Pitfalls in the Implementation of {B}ayesian Hierarchical Modeling of Areal Count Data: An Illustration Using {BYM} and {L}eroux Models", author = personList(as.person("Florian Gerber"), as.person("Reinhard Furrer")), journal = "Journal of Statistical Software, Code Snippets", year = "2015", volume = "63", number = "1", pages = "1--32", url = "http://www.jstatsoft.org/v63/c01/", doi = "10.18637/jss.v063.c01", textVersion = paste("Florian Gerber, Reinhard Furrer (2015).", "Pitfalls in the Implementation of Bayesian Hierarchical Modeling of Areal Count Data: An Illustration Using BYM and Leroux Models.", "Journal of Statistical Software, Code Snippets, 63(1), 1-32.", "URL http://www.jstatsoft.org/v63/c01/."), ) citEntry(entry = "Article", title = "Extending {R} packages to support 64-bit compiled code: An illustration with spam64 and {GIMMS} {NDVI3g} data", author = personList(as.person("Florian Gerber"), as.person("Kaspar Moesinger"), as.person("Reinhard Furrer")), journal = "Computer & Geoscience", year = "2017", volume = "104", number = "", pages = "109--119", issn = "0098-3004", doi = "10.1016/j.cageo.2016.11.015", textVersion = paste("F. Gerber, K. Moesinger, R. Furrer (2017),", "Extending R packages to support 64-bit compiled code: An illustration with spam64 and GIMMS NDVI3g data.", "Computer & Geoscience 104, 109-119, https://doi.org/10.1016/j.cageo.2016.11.015.") ) spam/inst/0LICENSE0000644000176200001440000000301313440250504013246 0ustar liggesusersAll R code and documentation in this package is licensed under the terms of the GPL license. The Fortran functions in spammodified.f were written by Reinhard Furrer. The Fortran functions in bckslvmodified.f cholmod.f are modifications of Fortran functions provided by the SparseM package. The code in cholesky.f is a modified version of code originally written by Esmond Ng and Barry Peyton. The modified version is distributed as part of PCx by Czyzyk, Mehrotra, Wagner, and Wright and is copywrite by the University of Chicago. The PCx distribution makes the following stipulation: This software discloses material protectable under copyright laws of the United States. Permission is hereby granted to use, reproduce, prepare derivative works, and redistribute to others at no charge, provided that the original PCx copyright notice, Government license and disclaimer are retained and any changes are clearly documented; however, any entity desiring permission to use this software within a commercial organization or to incorporate this software or a work based on the software into a product for sale must contact Paul Betten at the Industrial Technology Development Center, Argonne National Laboratory. PAUL BETTEN betten@anl.gov Industrial Technology Development Center, Argonne National Laboratory, Argonne, IL 60439 (630) 252-4962 FAX: (630) 252-5230 All other Fortran functions are from http://www-users.cs.umn.edu/~saad/software/SPARSKIT/index.html (GNU Lesser General Public License)