queryCase2 <- c(-0.117, 0.31)
if(plotPDFs == TRUE){ pdf("svmQueriesImage.pdf", width=7, height=7) }
plot(features[, 2], features[, 3], xlim = c(-0.5, 0.5), ylim = c(-0.45, 0.48), pch = diagramClasses, xlab = "RPM", ylab = "Vibration", cex = 1.6, cex.axis = 1.6, cex.lab = 1.6, cex.main = 1.6, lwd = 4)
lines(seq(min(features[, 2]) - (max(features[, 2]) - min(features[, 2]))*0.25, max(features[, 2])  + (max(features[, 2]) - min(features[, 2]))*0.25, ((max(features[, 2]) - min(features[, 2]))*1.5)/1000),
generateLine(boundaryParams[1], boundaryParams[2], seq(min(features[, 2]) - (max(features[, 2]) - min(features[, 2]))*0.25, max(features[, 2])  + (max(features[, 2]) - min(features[, 2]))*0.25, ((max(features[, 2]) - min(features[, 2]))*1.5)/1000)),
lty = 1, lwd = 3)
lines(seq(min(features[, 2]) - (max(features[, 2]) - min(features[, 2]))*0.25, max(features[, 2])  + (max(features[, 2]) - min(features[, 2]))*0.25, ((max(features[, 2]) - min(features[, 2]))*1.5)/1000),
generateLine(nearestNegLine[1], nearestNegLine[2], seq(min(features[, 2]) - (max(features[, 2]) - min(features[, 2]))*0.25, max(features[, 2])  + (max(features[, 2]) - min(features[, 2]))*0.25, ((max(features[, 2]) - min(features[, 2]))*1.5)/1000)),
lty = 2, lwd = 2, col = gray(0.4))
lines(seq(min(features[, 2]) - (max(features[, 2]) - min(features[, 2]))*0.25, max(features[, 2])  + (max(features[, 2]) - min(features[, 2]))*0.25, ((max(features[, 2]) - min(features[, 2]))*1.5)/1000),
generateLine(nearestPosLine[1], nearestPosLine[2], seq(min(features[, 2]) - (max(features[, 2]) - min(features[, 2]))*0.25, max(features[, 2])  + (max(features[, 2]) - min(features[, 2]))*0.25, ((max(features[, 2]) - min(features[, 2]))*1.5)/1000)),
lty = 2, lwd = 2, col = gray(0.4))
points(nearestPosPoint[1], nearestPosPoint[2], pch = 3, lwd = 5, cex = 1.8)
points(nearestPosPoint[1], nearestPosPoint[2], pch = 1, lwd = 2, cex = 3.8, col = gray(0.5))
points(nearestNegPoint[1], nearestNegPoint[2], pch = 2, lwd = 5, cex = 1.8)
points(nearestNegPoint[1], nearestNegPoint[2], pch = 1, lwd = 2, cex = 3.8, col = gray(0.5))
points(features[9, 2], features[9, 3], pch = 2, lwd = 5, cex = 1.8)
points(features[9, 2], features[9, 3], pch = 1, lwd = 2, cex = 3.8, col = gray(0.4))
points(queryCase1[1], queryCase1[2], pch = 19, lwd = 5, cex = 1.5)
points(queryCase1[1], queryCase1[2], pch = 1, lwd = 3, cex = 2.9)
points(queryCase2[1], queryCase2[2], pch = 19, lwd = 5, cex = 1.5)
points(queryCase2[1], queryCase2[2], pch = 1, lwd = 3, cex = 2.9)
if(plotPDFs == TRUE){ dev.off(); }
plotPDFs <- TRUE
plotPDFs <- FALSE
require(fields)
library(rgl)
library(akima)
library(fields)
library(lattice)
library(latticeExtra)
# A function that generates a plot shoiwing the decision boundary because it is too hard to figure out!
plotDecisionBoundary <- function(weights){
x1Start = -1
x1End = 1
x1Step = 0.1
x2Start = -1
x2End = 1
x2Step = 0.1
surface = NULL
for(x1 in seq(x1Start, x1End, by = x1Step)){
for(x2 in seq(x2Start, x2End, by = x2Step)){
basisFeatures <- applyBasisFunctions(c(1, x1, x2))
prediction <- 0;
for(j in 1:length(weights)){
prediction <- prediction + weights[j]*basisFeatures[j]
}
prediction = 1/(1+exp(-1*prediction))
if(prediction > 0.5){
class <- 1
}else{
class <- 0
}
surface = rbind(surface, c(x1, x2, class))
}
}
lines(surface[, 1], surface[, 2], col = surface[, 3]+2, type = "p", cex = 1.6, cex.axis = 1.6, cex.lab = 1.6, cex.main = 1.6)
}
# A function that generates a plot shoiwing the decision boundary because it is too hard to figure out!
plotDecisionBoundaryOneColour <- function(weights){
x1Start = -1
x1End = 1
x1Step = 0.05
x2Start = -1
x2End = 1
x2Step = 0.05
surface = NULL
for(x1 in seq(x1Start, x1End, by = x1Step)){
for(x2 in seq(x2Start, x2End, by = x2Step)){
basisFeatures <- applyBasisFunctions(c(1, x1, x2))
prediction <- 0;
for(j in 1:length(weights)){
prediction <- prediction + weights[j]*basisFeatures[j]
}
prediction = 1/(1+exp(-1*prediction))
if(prediction > 0.5){
class <- 1
}else{
class <- 0
}
if(class == 1){
surface = rbind(surface, c(x1, x2, class))
}
}
}
lines(surface[, 1], surface[, 2], pch = 16, col = rgb(0.7, 0.7, 0.7), type = "p", cex = 1.6, cex.axis = 1.6, cex.lab = 1.6, cex.main = 1.6)
}
plotDecisionBoundaryLine <- function(weights, lineWeight){
x1Start = -1
x1End = 1
x1Step = 0.01
x2Start = -1
x2End = 1
x2Step = 0.01
line = NULL
firstTime = TRUE
prediction <- 0;
for(x1 in seq(x1Start, x1End, by = x1Step)){
firstTime = TRUE
prediction <- 0;
for(x2 in seq(x2Start, x2End, by = x2Step)){
basisFeatures <- applyBasisFunctions(c(1, x1, x2))
prediction <- 0;
for(j in 1:length(weights)){
prediction <- prediction + weights[j]*basisFeatures[j]
}
prediction = 1/(1+exp(-1*prediction))
if(prediction > 0.5){
class <- 1
}else{
class <- 0
}
if(firstTime){
firstTime = FALSE
}else{
if(class != lastClass){
decisionPoint <- (x2 + lastX2)/2
line = rbind(line, c(x1, decisionPoint))
}
}
lastClass <- class
lastX2 <- x2
}
}
lines(line[, 1], line[, 2], type = "l", lwd = lineWeight, cex = 1.6, cex.axis = 1.6, cex.lab = 1.6, cex.main = 1.6)
}
plotDecisionBoundaryPoints <- function(weights, lineWeight){
x1Start = -1
x1End = 1
x1Step = 0.005
x2Start = -1
x2End = 1
x2Step = 0.005
line = NULL
firstTime = TRUE
prediction <- 0;
for(x1 in seq(x1Start, x1End, by = x1Step)){
firstTime = TRUE
prediction <- 0;
for(x2 in seq(x2Start, x2End, by = x2Step)){
basisFeatures <- applyBasisFunctions(c(1, x1, x2))
prediction <- 0;
for(j in 1:length(weights)){
prediction <- prediction + weights[j]*basisFeatures[j]
}
prediction = 1/(1+exp(-1*prediction))
if(prediction > 0.5){
class <- 1
}else{
class <- 0
}
if(firstTime){
firstTime = FALSE
}else{
if(class != lastClass){
decisionPoint <- (x2 + lastX2)/2
line = rbind(line, c(x1, decisionPoint))
}
}
lastClass <- class
lastX2 <- x2
}
}
points(line[, 1], line[, 2], type = "p", pch = 20, lwd = lineWeight, cex = 1.6, cex.axis = 1.6, cex.lab = 1.6, cex.main = 1.6)
}
# A function that generates an error surface for a simple linear regression problem
generateErrorSurface  <- function(targets, features, w0Start,w0End, w0Step, w1Start, w1End, w1Step){
surface = NULL
for(w0 in seq(w0Start, w0End, by = w0Step)){
for(w1 in seq(w1Start, w1End, by = w1Step)){
sumOfSquaredErrors = 0
for(i in 1:length(features)){
prediction = w0 + w1*features[i]
error = targets[i] - prediction
sumOfSquaredErrors = sumOfSquaredErrors + (error^2)
}
surface = rbind(surface, c(w0, w1, sumOfSquaredErrors))
}
}
surface
}
# A function that generates an error surface for a simple linear regression problem
generateDecisionSurface  <- function(weights, decisionType, f1Start, f1End, f1Step, f2Start, f2End, f2Step){
surface = NULL
for(f1 in seq(f1Start, f1End, by = f1Step)){
for(f2 in seq(f2Start, f2End, by = f2Step)){
basisFeatures <- applyBasisFunctions(c(1, f1, f2))
prediction <- 0;
for(j in 1:length(weights)){
prediction <- prediction + weights[j]*basisFeatures[j]
}
prediction = 1/(1+exp(-1*prediction))
surface = rbind(surface, c(f1, f2, prediction))
}
}
surface
}
makeAClassification <- function(weights, features, decisionType){
if(decisionType == "linear"){
classification <- makeALinearClassification(weights, features)
}else if(decisionType == "logistic"){
classification <- makeALogisticClassification(weights, features)
}
classification
}
makeALogisticClassification  <- function(weights, features){
prediction <- 0;
for(j in 1:length(weights)){
prediction <- prediction + weights[j]*features[j]
}
logPrediction = 1/(1+exp(-1*prediction))
logPrediction
}
makeALinearClassification  <- function(weights, features){
# Sum the regression function
prediction <- 0;
for(j in 1:length(weights)){
prediction <- prediction + weights[j]*features[j]
}
#Apply the threshold function
outputClass <- 0
if(prediction >= 0){
outputClass <- 1
}else{
outputClass <- 0
}
outputClass
}
normaliseFeatures <- function(features, targetMin, targetMax){
featuresDim <- dim(features)
for(cols in 1:featuresDim[2]){
columnMax = max(features[, cols])
columnMin = min(features[, cols])
if(columnMax != columnMin){
for(rows in 1:featuresDim[1]){
features[rows, cols] <- (features[rows, cols] - columnMin) / (columnMax - columnMin)
features[rows, cols] <- (features[rows, cols] * (targetMax - targetMin)) + targetMin
}
}
}
features
}
gradientDescentStepBatchLogisticClassification  <- function(weights, targets, features, alpha){
predictions = c(1:length(targets))
logPredictions = c(1:length(targets))
errorDeltas <- matrix(data=NA,nrow=length(targets),ncol=length(weights))
weightStep = c(1:length(weights))
sumOfSquaredErrors <- 0
for(i in 1:length(targets)){
#Work out the prediction for this training example
basisFeatures <- applyBasisFunctions(features[i, ])
predictions[i] <- 0;
for(j in 1:length(weights)){
predictions[i] <- predictions[i] + weights[j]*basisFeatures[j]
}
logPredictions[i] = 1/(1+exp(-1*predictions[i]))
# Determine the delta for each wieght based on this training example
for(j in 1:length(weights)){
errorDeltas[i, j] <- (targets[i] - logPredictions[i])*logPredictions[i]*(1 - logPredictions[i])*basisFeatures[j]
#errorDeltas[i, j] <- (targets[i] - logPredictions[i])*features[i, j]
}
# Adjust the overall sum of squared errors to take account of this example
sumOfSquaredErrors <- sumOfSquaredErrors + (targets[i] - logPredictions[i])^2
}
#   print("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%")
#   print(targets)
#   print(predictions)
#   print(logPredictions)
#   print(sumOfSquaredErrors)
#   print("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%")
for(j in 1:length(weights)){
weightStep[j] = weights[j] + alpha*sum(errorDeltas[, j])
}
weightsAndError <- c(sumOfSquaredErrors, weightStep)
weightsAndError
}
gradientDescentStepBatchClassification  <- function(weights, targets, features, alpha){
predictions = c(1:length(targets))
outputClass = c(1:length(targets))
errorDeltas <- matrix(data=NA,nrow=length(targets),ncol=length(weights))
weightStep = c(1:length(weights))
sumOfSquaredErrors <- 0
for(i in 1:length(targets)){
#Work out the prediction for this training example
basisFeatures <- applyBasisFunctions(features[i, ])
predictions[i] <- 0;
for(j in 1:length(weights)){
predictions[i] <- predictions[i] + weights[j]*basisFeatures[j]
}
#Apply the threshold function
outputClass[i] <- 0
if(predictions[i] >= 0){
outputClass[i] <- 1
}else{
outputClass[i] <- 0
}
# Determine the delta for each wieght based on this training example
for(j in 1:length(weights)){
errorDeltas[i, j] <- (targets[i] - outputClass[i])*basisFeatures[j]
}
# Adjust the overall sum of squared errors to take account of this example
sumOfSquaredErrors <- sumOfSquaredErrors + (targets[i] - outputClass[i])^2
}
#   print("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%")
#   print(targets)
#   print(outputClass)
#   print(predictions)
#   print(sumOfSquaredErrors)
#   print("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%")
for(j in 1:length(weights)){
weightStep[j] = weights[j] + alpha*sum(errorDeltas[, j])
}
weightsAndError <- c(sumOfSquaredErrors, weightStep)
weightsAndError
}
# gradientDescentStepStochastic  <- function(weights, targets, features, alpha){
#
#   predictions = c(1:length(targets))
#   errors1 = c(1:length(targets))
#   errors2 = c(1:length(targets))
#   weightStep = c(weights[1], weights[2])
#
#   for(i in 1:length(features)){
#     predictions[i] = weightStep[1] + weightStep[2]*features[i]
#     errors1[i] = targets[i] - predictions[i]
#     errors2[i] = (targets[i] - predictions[i])*features[i]
#     weightStep[1] = weightStep[1] + alpha*errors1[i]
#     weightStep[2] = weightStep[2] + alpha*errors2[i]
#   }
#
#   ## Value returned is value of last expression: s in this case
#   weightStep
# }
generateLine <- function(weights, xValues){
predictions = c(1:length(xValues))
for(i in 1:length(xValues)){
predictions[i] = (-1*(weights[1] + weights[2] * xValues[i]))/weights[3];
}
predictions
}
applyBasisFunctions <- function(xValues){
#   newValues <- applySimpleBasisFunctions(xValues)
#   newValues
newValues <- c(1:8)
newValues[1] <- xValues[1]
newValues[2] <- xValues[2]
newValues[3] <- xValues[3]
newValues[4] <- xValues[2]^2
newValues[5] <- xValues[3]^2
newValues[6] <- xValues[2]^3
newValues[7] <- xValues[3]^3
newValues[8] <- xValues[2]*xValues[3]
newValues
}
applySimpleBasisFunctions <- function(xValues){
newValues <- c(1:3)
newValues[1] <- 1
newValues[2] <- xValues[1]
newValues[3] <- xValues[2]
newValues
}
# Set the parametes for the learning algorithm - EEG Book Demo Parameters
ClassificationData <- read.csv("~/Dropbox/ml/Book/Questions/ErrorBasedLearningExercisesStuff/ErrorBasedNonLinearDataClean.csv")
#ClassificationData <- ClassificationData[sample(nrow(ClassificationData), 0.25*nrow(ClassificationData)), ]
decisionType = "logistic" #either "linear" or "logistic"
#Extract fetures and normalise the data
features <- cbind(rep(1, length(ClassificationData[,1])), as.matrix(ClassificationData[,1:length(ClassificationData[1,]) - 1]))
classes <- c(ClassificationData[,3])
features <- normaliseFeatures(features, -1, 1)
featuresXLabel <- "Dose1"
featuresYLabel <- "Dose2"
weights <- runif(length(applyBasisFunctions(features[1, ])), -0.2, 0.2)
# fixed starting weights for good sep logistic demo graphs
#weights <- c(0.19347417, 0.10127419, -0.10965878, -0.06893720, -0.15795418,  0.16903120, -0.09358322, 0.12165501)
learningRate <- 0.002
stoppingErrorDelta <- 0.00001
# Set the paraemters around the stopping criteria
error <- 100
errorZeroCount <- 0
lastError <- 0
weightJourney <- NULL
errorJourney <- NULL
# Plot the data
if(plotPDFs == TRUE){ pdf("basisfunctionLogisticClassificationDemoDataset.pdf", width=7, height=7) }
plot(features[, 2], features[, 3], pch = classes+2, xlab = featuresXLabel, ylab = featuresYLabel, cex = 1.6, cex.axis = 1.6, cex.lab = 1.6, cex.main = 1.6, lwd = 4)
if(plotPDFs == TRUE){ dev.off(); }
i = 0
# Iterate through the gradient descent process
while(abs(lastError - error) > stoppingErrorDelta){
lastError <- error
if(decisionType == "linear"){
weightsAndError <- gradientDescentStepBatchClassification(weights, classes, features, learningRate)
}else if(decisionType == "logistic"){
weightsAndError <- gradientDescentStepBatchLogisticClassification(weights, classes, features, learningRate)
}
error <- weightsAndError[1]
weights <- weightsAndError[2:length(weightsAndError)]
weightJourney <- rbind(weightJourney, c(weights))
errorJourney <- rbind(errorJourney, error)
print(i)
print(weightsAndError)
# Draw the current candidate model
if(plotPDFs == TRUE){ pdf(paste("basisfunctionLogisticClassificationDemo", i, ".pdf", sep=""), width=7, height=7) }
plot(features[, 2], features[, 3], pch = classes+2, xlab = featuresXLabel, ylab = featuresYLabel, cex = 1.6, cex.axis = 1.6, cex.lab = 1.6, cex.main = 1.6, lwd = 4)
plotDecisionBoundaryLine(weights, 2);
if(plotPDFs == TRUE){ dev.off(); }
#if(plotPDFs == TRUE){ pdf(paste("basisfunctionLogisticClassificationDemoColour", i, ".pdf", sep=""), width=7, height=7) }
#plot(features[, 2], features[, 3], pch = classes+2, xlab = featuresXLabel, ylab = featuresYLabel, cex = 1.6, cex.axis = 1.6, cex.lab = 1.6, cex.main = 1.6, lwd = 4)
#plotDecisionBoundary(weights);
#plotDecisionBoundaryLine(weights, 2);
#if(plotPDFs == TRUE){ dev.off(); }
# Draw the current canidadtae decision surface
#   decisionSurface <- generateDecisionSurface(weights, decisionType, -1, 1, 0.1, -1, 1, 0.1)
#   s=interp(decisionSurface[,1], decisionSurface[, 2], decisionSurface[, 3])
#   plot3d(decisionSurface[,1], decisionSurface[, 2], decisionSurface[, 3], col = "red", xlab="f1", ylab="f2", zlab="Prediction")
#   zlim <- range(decisionSurface[, 2])
#   zlen <- zlim[2] - zlim[1] + 1
#   colorlut <- terrain.colors(zlen) # height color lookup table
#   col <- colorlut[ decisionSurface[, 3] - zlim[1]+1 ] # assign colors to heights for each point
#   if(plotPDFs == TRUE){ pdf(paste("basisfunctionLogisticClassificationDemoDecisionSurface", i, ".pdf", sep=""), width=7, height=7) }
#   surface3d(s$x,s$y,s$z, color=col, back="lines")
#   if(plotPDFs == TRUE){ dev.off(); }
if(plotPDFs == TRUE){
Sys.sleep(0.5)
}
#Stop the process once we hit a load of zeros
#   if(error == 0){
#     errorZeroCount = errorZeroCount + 1
#   }
#   if(errorZeroCount >= 8){
#     break;
#   }
i <- i + 1
}
plot(ClassificationData)
plot(ClassificationData[1:2, ])
plot(ClassificationData[, 1:2 ])
ClassificationData <- read.csv("~/Dropbox/ml/Book/Questions/ErrorBasedLearningExercisesStuff/ErrorBasedNonLinearDataCleanSample.csv")
ClassificationData <- read.csv("~/Dropbox/ml/Book/Questions ver0.2/ErrorBasedLearningExercisesStuff/ErrorBasedNonLinearDataClean.csv")
plot(ClassificationData[, 1:2 ])\
plot(ClassificationData[, 1:2 ])
ClassificationData <- read.csv("~/Dropbox/ml/Book/Questions ver0.2/ErrorBasedLearningExercisesStuff/ErrorBasedNonLinearDataClean.csv")
decisionType = "logistic" #either "linear" or "logistic"
#Extract fetures and normalise the data
features <- cbind(rep(1, length(ClassificationData[,1])), as.matrix(ClassificationData[,1:length(ClassificationData[1,]) - 1]))
classes <- c(ClassificationData[,3])
features <- normaliseFeatures(features, -1, 1)
featuresXLabel <- "Dose1"
featuresYLabel <- "Dose2"
weights <- runif(length(applyBasisFunctions(features[1, ])), -0.2, 0.2)
# fixed starting weights for good sep logistic demo graphs
#weights <- c(0.19347417, 0.10127419, -0.10965878, -0.06893720, -0.15795418,  0.16903120, -0.09358322, 0.12165501)
learningRate <- 0.002
stoppingErrorDelta <- 0.00001
# Set the paraemters around the stopping criteria
error <- 100
errorZeroCount <- 0
lastError <- 0
weightJourney <- NULL
errorJourney <- NULL
# Plot the data
if(plotPDFs == TRUE){ pdf("basisfunctionLogisticClassificationDemoDataset.pdf", width=7, height=7) }
plot(features[, 2], features[, 3], pch = classes+2, xlab = featuresXLabel, ylab = featuresYLabel, cex = 1.6, cex.axis = 1.6, cex.lab = 1.6, cex.main = 1.6, lwd = 4)
if(plotPDFs == TRUE){ dev.off(); }
i = 0
# Iterate through the gradient descent process
while(abs(lastError - error) > stoppingErrorDelta){
lastError <- error
if(decisionType == "linear"){
weightsAndError <- gradientDescentStepBatchClassification(weights, classes, features, learningRate)
}else if(decisionType == "logistic"){
weightsAndError <- gradientDescentStepBatchLogisticClassification(weights, classes, features, learningRate)
}
error <- weightsAndError[1]
weights <- weightsAndError[2:length(weightsAndError)]
weightJourney <- rbind(weightJourney, c(weights))
errorJourney <- rbind(errorJourney, error)
print(i)
print(weightsAndError)
# Draw the current candidate model
if(plotPDFs == TRUE){ pdf(paste("basisfunctionLogisticClassificationDemo", i, ".pdf", sep=""), width=7, height=7) }
plot(features[, 2], features[, 3], pch = classes+2, xlab = featuresXLabel, ylab = featuresYLabel, cex = 1.6, cex.axis = 1.6, cex.lab = 1.6, cex.main = 1.6, lwd = 4)
plotDecisionBoundaryLine(weights, 2);
if(plotPDFs == TRUE){ dev.off(); }
#if(plotPDFs == TRUE){ pdf(paste("basisfunctionLogisticClassificationDemoColour", i, ".pdf", sep=""), width=7, height=7) }
#plot(features[, 2], features[, 3], pch = classes+2, xlab = featuresXLabel, ylab = featuresYLabel, cex = 1.6, cex.axis = 1.6, cex.lab = 1.6, cex.main = 1.6, lwd = 4)
#plotDecisionBoundary(weights);
#plotDecisionBoundaryLine(weights, 2);
#if(plotPDFs == TRUE){ dev.off(); }
# Draw the current canidadtae decision surface
#   decisionSurface <- generateDecisionSurface(weights, decisionType, -1, 1, 0.1, -1, 1, 0.1)
#   s=interp(decisionSurface[,1], decisionSurface[, 2], decisionSurface[, 3])
#   plot3d(decisionSurface[,1], decisionSurface[, 2], decisionSurface[, 3], col = "red", xlab="f1", ylab="f2", zlab="Prediction")
#   zlim <- range(decisionSurface[, 2])
#   zlen <- zlim[2] - zlim[1] + 1
#   colorlut <- terrain.colors(zlen) # height color lookup table
#   col <- colorlut[ decisionSurface[, 3] - zlim[1]+1 ] # assign colors to heights for each point
#   if(plotPDFs == TRUE){ pdf(paste("basisfunctionLogisticClassificationDemoDecisionSurface", i, ".pdf", sep=""), width=7, height=7) }
#   surface3d(s$x,s$y,s$z, color=col, back="lines")
#   if(plotPDFs == TRUE){ dev.off(); }
if(plotPDFs == TRUE){
Sys.sleep(0.5)
}
#Stop the process once we hit a load of zeros
#   if(error == 0){
#     errorZeroCount = errorZeroCount + 1
#   }
#   if(errorZeroCount >= 8){
#     break;
#   }
i <- i + 1
}
