# Big Data Exercise08 Spatial Smoothing at Scale
# Yanxin Li
# Nov 17 2017
rm(list=ls())
setwd("D:/2017 UT Austin/Statistical Models for Big Data/R")
options(warn = -1)
# Kernel smoothing
library(fields)
## Loading required package: spam
## Loading required package: dotCall64
## Loading required package: grid
## Spam version 2.1-1 (2017-07-02) 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
# Read in data
co2 <- read.csv("co2.csv", header = TRUE)
summary(co2)
## day lon lat co2avgret
## Min. : 1.000 Min. :-180.00 Min. :-60.000 Min. :347.8
## 1st Qu.: 4.000 1st Qu.:-100.22 1st Qu.:-25.120 1st Qu.:373.1
## Median : 8.000 Median : -18.57 Median : -4.390 Median :375.1
## Mean : 7.971 Mean : -13.39 Mean : 1.924 Mean :375.5
## 3rd Qu.:12.000 3rd Qu.: 62.47 3rd Qu.: 27.380 3rd Qu.:377.7
## Max. :15.000 Max. : 180.00 Max. : 89.140 Max. :403.7
# A quick look at the observations with world map
# png("co2.png")
quilt.plot(co2[,2:3], co2[,4])
world(add=TRUE)

# dev.off()
# Plot 2-D Gaussian distribution
library(rgl)
x <- seq(-3, 3, length=100)
y <- seq(-3, 3, length=100)
z <- outer(x,y, function(x,y) 0.5/pi*exp(-0.5*(x^2+y^2)))
persp3d(x, y, z,col = rainbow(100))
# Laplacian smoothing
library(Matrix)
library(gplots)
##
## Attaching package: 'gplots'
## The following object is masked from 'package:stats':
##
## lowess
# Constructs the oriented edge matrix D for a 2-d grid of size nx by ny.
# This fuction is provided by Prof. James Scott
makeD2_sparse <- function (dim1, dim2) {
require(Matrix)
D1 <- bandSparse(dim1 * dim2, m = dim1 * dim2, k = c(0, 1),
diagonals = list(rep(-1, dim1 * dim2),
rep(1, dim1 * dim2 - 1)))
D1 <- D1[(seq(1, dim1 * dim2)%%dim1) != 0, ]
D2 <- bandSparse(dim1 * dim2 - dim1, m = dim1 * dim2,
k = c(0, dim1), diagonals = list(rep(-1, dim1 * dim2),
rep(1, dim1 * dim2 - 1)))
return(rBind(D1, D2))
}
# Direct solver for Ax=b.
direct.sparse.solver <- function(A,b){
x <- solve(A,y,sparse=T)
return(x)
}
# Cholesky decomposition
chol.solver <- function (A,b){
U <- chol(A) # Upper Cholesky decomposition of A and U'U = A.
decomp <- as(U, "sparseMatrix")
# Replace Ax=b with U'Ux=b, solve U'z=b for z.
z <- forwardsolve(t(decomp), b)
# Solve Ux = z for x.
x <- backsolve(decomp, z)
return(x)
}
# Jacobi iterative solver for Ax=b.
jacobi.solver <- function(A,b,x0 = rep(1,length(b)),maxiter=100,tol=1E-14){
# x0: Initial guess for vector x solution.
# A: input matrix
# b: input vector
# maxiter: maximum iterations
# Initialize values.
xold <- x0
Dinv <- 1/diag(A) # Diagonal of matrix A.
R <- A # Remainder; A with diagonal set to 0.
diag(R) <- 0
for (i in 1:maxiter){
# Update x values.
xnew <- Dinv * (b - crossprod(R,xold))
# Check convergence.
if(max(abs(xnew-xold)) < tol) { break; }
# Update xold.
xold <- xnew
}
return(xnew)
}
# Read in data. data.
data <- as.matrix(read.csv("fmri_z.csv", header = T))
data.mat <- Matrix(data)
# Heat map of noisy MRI data.
image(t(data.mat), sub='', xlab='',ylab='',cuts=80)

# Represent signal values as a vector.
y <- as.vector(data.mat)
# Oriented edge matrix.
D <- makeD2_sparse(128,128)
# Laplacian matrix.
L <- crossprod(D)
# Lambda penalty.
lambda <- 10
# Set up A = I + lambda*L
A <- lambda*L
diag(A) <- diag(A) + 1
# DIRECT SOLVER
xD <- direct.sparse.solver(A,y)
xD.grid <- Matrix(as.vector(xD),128,128,byrow=T) # Reconstruct de-noised grid.
xD.grid[which(data.mat==0)] <- 0 # Set values which were 0 in original grid to 0.
# CHOLESKY SOLVER
xC <- chol.solver(A,y)
xC.grid <- Matrix(as.vector(xC),128,128,byrow=T) # Reconstruct de-noised grid.
xC.grid[which(data.mat==0)] <- 0 # Set values which were 0 in original grid to 0.
# JACOBI SOLVER
xJ <- jacobi.solver(A,y,maxiter=1000)
## Note: method with signature 'dsparseMatrix#dgeMatrix' chosen for function 'crossprod',
## target signature 'dsCMatrix#dgeMatrix'.
## "CsparseMatrix#ddenseMatrix" would also be valid
xJ.grid <- Matrix(as.vector(xJ),128,128,byrow=T) #Reconstruct de-noised grid.
xJ.grid[which(data.mat==0)] <- 0 # Set values which were 0 in original grid to 0.
# Quick comparison of Jacobi and Direct solver methods.
DJC <- cbind(xD, xJ, xC)
# Side by side heat maps of noisy and de-noised data.
# jpeg('lp.smoothing.noisey.jpg')
image(t(data.mat), sub='', xlab='',ylab='',cuts=80)

# dev.off()
# jpeg('lp.smoothing.jacobismoothed.jpg')
image(t(xJ.grid), sub='', xlab='',ylab='',cuts=80)

# dev.off()
# jpeg('lp.smoothing.directsmoothed.jpg')
image(t(xD.grid), sub='', xlab='',ylab='',cuts=80)

# dev.off()
image(t(xC.grid), sub='', xlab='',ylab='',cuts=80)
