source: src/kLHC.R @ 1

Last change on this file since 1 was 1, checked in by fairhead, 8 years ago

Initial import of HighTune project files

File size: 8.6 KB
Line 
1#This R file can be sourced to provide all of the functions necessary to produce k-extended LHCs.
2#The last two lines in this file can be uncommented out and they will generate the same type of orthogonal maximin LHC used to compare performance against sliced LHCs in section 3.1. For further information on how to use the code, please contact the author.
3
4require(lhs)
5require(DoE.wrapper)
6require(DiceDesign)
7require(parallel)
8toInts <- function(LH){
9  n <- length(LH[,1])
10  ceiling(n*LH)
11}
12
13# The correlation component criterion
14RhoSq <- function(LH){
15  A <- cor(LH)
16  m <- dim(LH)[2]
17  2*sum(A[upper.tri(A)]^2)/(m*(m-1))
18}
19# The inter-site distance for column j of MC
20oneColDist <- function(LH, whichCol, k){
21  D <- dist(LH[,whichCol],method="manhattan")
22  D[D==0] <- 1/k
23  D
24}
25
26# The coverage criterion
27newphiP <- function(LH, k, p){
28  tD <- oneColDist(LH,1,k)
29  for(i in 2:(dim(LH)[2])){
30    tD <- tD + oneColDist(LH,i,k)
31  }
32  sum(tD^(-p))^(1/p)
33}
34
35dbar <- function(n,m,k,tc){
36  (m*n*tc*(tc*k*(n^2-1) + 3*(tc-1)))/(6*k*choose(tc*n,2))
37}
38
39# The coverage criterion lower band
40newphiPL <- function(n, k, bard, p){
41  choose(k*n,2)^(1/p)/bard
42}
43
44# The coverage criterion upper band
45newphiPU <- function(n, m, k, p, tc){
46  ((n*k^(p)*tc*(tc-1))/(2*m) + sum( tc^2*(n-c(1:(n-1)))/(m*c(1:(n-1))^p)))^(1/p)
47}
48
49# The final criterion
50objectiveFun <- function(LH, w, p, phiU, phiL, k){
51  rho <- RhoSq(LH)
52  phiP <- newphiP(LH, k, p)
53  w*rho + (1-w)*(phiP - phiL)/(phiU-phiL)
54}
55
56newphiL1 <- function(n, bard, p){
57  upp <- ceiling(bard)
58  low <- floor(bard)
59  (choose(n,2)*(((upp - bard)/low^p) + ((bard - low)/upp^p)))^(1/p)
60}
61
62Sim.anneal.k <- function(tLHS, tc, k, n, m, w, p, Imax=1000, FAC_t=0.9, t0=NULL){
63  Dcurrent <- tLHS
64  tbard <- dbar(n=n,m=m,k=k,tc=tc)
65  phiU <- newphiPU(n=n, m=m, k=k, p=p, tc=tc)
66  if(tc<2)
67    phiL <- newphiL1(n=n, bard=tbard, p=p)
68  else
69    phiL <- newphiPL(n=n, k=k, bard=tbard, p=p)
70  # Deriving the initial temperature value
71  if(is.null(t0)){
72    delta <- 1/k
73    rdis <- runif(n=choose(tc*n,2), min = 0.5*tbard, max=1.5*tbard)
74    t0curr <- sum(rdis^(-p))^(1/p)
75    rdis[which.min(rdis)] <- rdis[which.min(rdis)] - delta
76    t0new <- sum(rdis^(-p))^(1/p)
77    t0 <- (-1)*(t0new - t0curr)/log(0.99)
78  }
79  # Calculate the psi criterion value for the current LHC
80  psiDcurrent <- objectiveFun(Dcurrent, w=w, p=p, phiU=phiU, phiL=phiL, k=k)
81  Dbest <- Dcurrent
82  psiDbest <- psiDcurrent
83  FLAG <- 1
84  t <- t0
85  while(FLAG==1){
86    FLAG <- 0
87    I <- 1
88    while(I < Imax){ # Repeating the simulated annealing algorithm
89      Dtry <- Dcurrent
90      # Randomly select column in (c-1)n+1,..., cn
91      j <- sample(1:m, 1)
92      i12 <- sample(c(((tc-1)*n+1):(tc*n)),2,replace=FALSE)
93      # Permute elements of the rows within randomly selected column
94      Dtry[i12,j] <- Dcurrent[c(i12[2],i12[1]),j]
95      # Calculate the psi criterion value for the newly generated LHC
96      psiDtry <- objectiveFun(Dtry, w=w, p=p, phiU=phiU, phiL=phiL, k=k)
97      if(psiDtry < psiDcurrent){
98        Dcurrent <- Dtry
99        psiDcurrent <- psiDtry
100        FLAG <- 1
101      }
102      # Accept with acceptance probability
103      else if((runif(1) < exp(-(psiDtry - psiDcurrent)/t))&(psiDtry!=psiDcurrent)){
104        Dcurrent <- Dtry
105        psiDcurrent <- psiDtry
106        FLAG <- 1
107      }
108      if(psiDtry < psiDbest){
109        Dbest <- Dtry
110        psiDbest <- psiDtry
111        #print(paste("New Dbest with psi = ", psiDbest, " found, reset I from I = ", I, sep=""))
112        I <- 1
113      }
114      else{
115        I <- I + 1
116      }
117    }
118    # Reducing t (temperature)
119    t <- t*FAC_t
120    #print(t)
121  }
122  Dbest
123}
124# Draw a Latin Hypercube Sample from a set of uniform distributions for use in creating a Latin Hypercube
125#design. This sample is taken in a random manner without regard to optimization
126### Inputs
127# n: number of points
128# m: number of inputs
129# p: (not sure)
130# w: weights
131
132### Output
133# n by m dimension matrix of integers
134FirstRankLHS <- function(n, m, p, w){
135  tLHS <- randomLHS(n,m)
136  # Provide order of rows in each column
137  tLHS <- apply(tLHS, 2, order)
138  Sim.anneal.k(tLHS=tLHS, tc=1, k=1, n=n, m=m, w=w, p=p, Imax=1000, FAC_t=0.8, t0=NULL)
139}
140
141###Generate a new integer LHC
142### Input:
143# CurrentBig: the original n-integer LHC
144# n: numeber of points
145# m: number of inputs
146# k: number of extensions
147
148### Output
149# n by m dimension matrix of integers
150MakeValidNewLHS <- function(CurrentBig, n, m, k){
151  if(k*n <= n^m){
152    Found <- FALSE
153    while(!Found){
154      anLHC <- apply(randomLHS(n,m),2,order)
155      if(!any(dist(rbind(CurrentBig,anLHC), method="manhattan")==0))
156        Found <- TRUE
157    }
158  }
159  else{
160    anLHC <- apply(randomLHS(n,m),2,order)
161  }
162  return(anLHC)
163}
164### Produce k n-point integer LHC with desirable properties (orthonormal maximin LHC)
165### Inputs:
166# n: number of points
167# m: number of inputs
168# k: number of extensions
169# w: weights
170# p: (?)
171# FAC_t: simulated annealing parameter (temperature increment)
172# startLHS: first n-point integer LHS
173
174### Output:
175# k n-point integer LHC
176MakeRankExtensionCubes <- function(n, m, k, w, p=50, FAC_t=0.8, startLHS=NULL, Imax){
177  # Generate n-point integer LHC
178  if(is.null(startLHS))
179    lhs1 <- FirstRankLHS(n, m, p, w)
180  else
181    lhs1 <- as.matrix(toInts(startLHS))
182  BigExtendedMatrix <- matrix(NA, nrow=k*n, ncol=m)
183  # Assign first n-point integer LHC
184  BigExtendedMatrix[1:n,] <- lhs1
185  # Generate k extension to original n-point integer LHC
186  for(i in 2:k){
187    print(paste("Current extension = ", i, " of ", k, sep=""))
188    newLHC <- MakeValidNewLHS(BigExtendedMatrix[1:((i-1)*n),],n=n,m=m,k=i)
189    BigExtendedMatrix[((i-1)*n + 1):(i*n),] <- newLHC
190    BigExtendedMatrix[1:(i*n),] <- Sim.anneal.k(tLHS=BigExtendedMatrix[1:(i*n),], tc=i, k=k, n=n, m=m, w=w, p=p, Imax=1000, FAC_t=FAC_t, t0=NULL)
191  }
192  lapply(1:k, function(e) BigExtendedMatrix[(1+(e-1)*n):(e*n),])
193}
194
195oneIN <- function(LHcolumn,left,right){
196  any(which(LHcolumn>=left)%in%which(LHcolumn<right))
197}
198manyIN <- Vectorize(oneIN, c("left","right"))
199
200### Produce a list of sub-solid for which the members of current
201### ExtendedLHC falls within this sub-solid
202### Inputs:
203# rankLHCrow: rectangular solid representation
204# currentExtendedLHC: currently constructed cn-point LHC
205# n: number of points
206# d:number of dimensions
207# increment: sub-solid parameter
208# k: number of sub-solids
209
210### Output:
211# list
212getPointers <- function(rankLHCrow,currentExtendedLHC, n, d, increment,k){
213  leftmostedges <- (rankLHCrow-1)/n
214  tleftmosts <- matrix(leftmostedges,nrow=k+1,ncol=d,byrow=T)
215  leftedges <- matrix(rep(0:k,d),nrow=k+1,ncol=d)
216  leftedges <- leftedges*increment + tleftmosts
217  rightedges <- leftedges+increment
218  sapply(1:d, function(j) which(manyIN(currentExtendedLHC[,j],leftedges[,j],rightedges[,j])))
219}
220
221### Sample sub-solid at random and return its value
222### Inputs
223# pointersRow: a list of sub-solid for which the members of current
224# ExtendedLHC falls within this sub-solid
225# rankLHCrow: solid of which pointersRow sub-solid is part of
226# increment: sub-solid parameter
227# n: number of points
228# d: number of inputs
229# k: number of subsolids
230
231###Output
232# a vector of sampled value
233sampleNewPoint <- function(pointersRow, rankLHCrow, increment, n, d, k){
234  location <- runif(d)
235  if(length(pointersRow[,1]) < k)
236    newPoint <- sapply(1:d, function(j) sample(c(1:(k+1))[-pointersRow[,j]],1))
237  else
238    newPoint <- sapply(1:d, function(j) c(1:(k+1))[-pointersRow[,j]])
239  (rankLHCrow-1)/n + (newPoint-1)*increment  + increment*location
240}
241
242### Function to generate K-extended Latin Hypercube
243### Input:
244# rankLHClist: a k list of n by m integer LHC
245# LHCmaster: n-point LHC
246
247###Output:
248# a kn by m matrix, K-extended Latin Hypercube
249
250NewExtendingLHS <- function(rankLHClist, LHCmaster=NULL){
251  #there are k+1 rank LHCs in rankLHClist, which can be constructed using MakeRankExtensionCubes
252  k <- length(rankLHClist) -1
253  tdims <- dim(rankLHClist[[1]])
254  n <- tdims[1]
255  d <- tdims[2]
256  increment=1/(n*(k+1))
257  if(is.null(LHCmaster)){
258    LHCmaster <- rankLHClist[[1]]
259    LHCmaster <- (LHCmaster + runif(n*d) - 1)/n
260  }
261  pointers <- mclapply(1:n, function(e) {getPointers(rankLHClist[[2]][e,], LHCmaster,n=n,d=d,increment=increment,k=k)})
262  pointers <- lapply(pointers, function(e) {dim(e) <- c(1,d);e})
263  NewLHC1 <- t(sapply(1:n, function(l) sampleNewPoint(pointers[[l]], rankLHClist[[2]][l,], increment, n, d, k)))
264  ExtendedLHC <- matrix(NA, nrow=n*(k+1), ncol=d)
265  ExtendedLHC[1:n,] <- LHCmaster
266  ExtendedLHC[(n+1):(2*n),] <- NewLHC1
267  for(l in 3:(k+1)){
268    pointers <- mclapply(1:n, function(e) getPointers(rankLHClist[[l]][e,],na.omit(ExtendedLHC),n=n,d=d,increment=increment,k=k))
269    newLHC <- t(sapply(1:n, function(j) sampleNewPoint(pointers[[j]],rankLHClist[[l]][j,], increment, n,d,k)))
270    ExtendedLHC[((l-1)*n+1):(l*n),] <- newLHC
271  }
272  ExtendedLHC
273}
274
Note: See TracBrowser for help on using the repository browser.