# Definition of price.
price <- function(rating, age) {
	peakAge <- rating- 50
	price <- rating / 2
	price <- sapply(1:length(rating), function(i){
				if (age[i] > peakAge[i]) {
					p <- price[i] * (5 - (age[i] - peakAge[i]))
				} else {
					p <- price[i] * 5 * (age[i] + 1) / peakAge[i]
				}
				return(ifelse(p<0, 0, p))
			})
	return(price)
}

# Create a price dataset.
createSet <- function(n=300) {
	randVector <- runif(n * 2)
	rating <- randVector[1:n] * 50 + 50
	age <- randVector[(n+1):(n*2)] * 50
	price <- price(rating, age) * (runif(1) * 0.2 + 0.9)
	data <- cbind(rating, age, price)
	return(data)
}

getDistances <- function(data, v1) {
	distances <- apply(data[,c(1,2)], 1, function(v2) sqrt(sum((v2 - v1) ^ 2)))
	distanceFrame <- data.frame(distance=distances, index=1:nrow(data))
	ord=order(distanceFrame[,'distance'])
	return(distanceFrame[ord,])
}

# KNN estimate. 
knnEstimate <- function(data, v1, k=3) {
	distances <- getDistances(data[,c(1,2)], v1)[1:k,]
	ret <- mean(data[distances[,'index'], 'price'])
	return(ret)
}

# Divide data set into training set and test set.
divideData <- function(data, test = 0.1) {
	testIndices <- which(runif(nrow(data)) < test)
	return(list(test=data[testIndices,], train=data[-testIndices,]))
}

testAlgorithm <- function(algF, trainSet, testSet) {
	errorVector <- apply(testSet, 1, function(i) {
				return(testSet[3] - algF(trainSet, testSet[c(1,2)]))
			} )
	return(mean(errorVector ^ 2))
}

crossValidate <- function(algF, data, trials=100, test=0.1) {
	errorVector <- sapply(1:trials, function(i) {
				print(paste('Trail', i))
				dataSets <- divideData(data, test)
				return(testAlgorithm(algF, dataSets[['train']], dataSets[['test']]))
			})
	return(sum(errorVector) / trials)
}

data <- createSet()
print(crossValidate(knnEstimate, data))
