Source code for RCAIDE.Library.Methods.Utilities.latin_hypercube_sampling

# latin_hypercube_sampling.py
#
# Created:  Jul 2016, R. Fenrich (outside of RCAIDE code)
# Modified: Apr 2017, T. MacDonald


# ----------------------------------------------------------------------
#   Imports
# ----------------------------------------------------------------------

import numpy as np

## If needed for mapping to normal distribution:
#from scipy.stats.distributions import norm 


# ----------------------------------------------------------------------
#   Latin Hypercube Sampling
# ----------------------------------------------------------------------
[docs] def latin_hypercube_sampling(num_dimensions,num_samples,bounds=None,criterion='random'): """Provides an array of chosen dimensionality and number of samples taken according to latin hypercube sampling. Bounds can be optionally specified. Assumptions: None Source: None Inputs: num_dimensions [-] num_samples [-] bounds (optional) [-] Default is 0 to 1. Input value should be in the form (with numpy arrays) (array([low_bnd_1,low_bnd_2,..]), array([up_bnd_1,up_bnd_2,..])) criterion <string> Possible values: random and center. Determines if samples are taken at the center of a bucket or randomly from within it. Outputs: lhd [-] Array of samples Properties Used: N/A """ n = num_dimensions samples = num_samples segsize = 1./samples lhd = np.zeros((samples,n)) if( criterion == "random" ): # sample is randomly chosen from within segment segment_starts = np.arange(samples)*segsize lhd_base = np.transpose(np.tile(segment_starts,(n,1))) lhd = lhd_base + np.random.rand(samples,n)*segsize elif( criterion == "center" ): # sample is chosen as center of segment segment_starts = np.arange(samples)*segsize lhd_base = np.transpose(np.tile(segment_starts,(n,1))) lhd = lhd_base + 0.5*segsize else: raise NotImplementedError("Other sampling criterion not implemented") # Randomly switch values around to create Latin Hypercube for jj in range(n): np.random.shuffle(lhd[:,jj]) ## Map samples to the standard normal distribution (if needed for future functionality) #lhd = norm(loc=0,scale=1).ppf(lhd) if bounds != None: lower_bounds = bounds[0] upper_bounds = bounds[1] lhd = lhd*(upper_bounds-lower_bounds) + lower_bounds return lhd
# ---------------------------------------------------------------------- # Functionality Test and Use Example # ---------------------------------------------------------------------- if __name__ == '__main__': # 2D test is performed with samples chosen randomly in segment # 3D test is performed with samples chosen at the center of the segment num_2d_samples = 5 num_3d_samples = 5 # Imports for display from mpl_toolkits.mplot3d import Axes3D import matplotlib.pyplot as plt np.random.seed(0) # 2D Test Case fig = plt.figure("2D Test Case",figsize=(8,6)) axes = plt.gca() lhd = latin_hypercube_sampling(2,num_2d_samples) x = lhd[:,0] y = lhd[:,1] axes.scatter(x,y) axes.set_xticks(np.linspace(0,1,num_2d_samples+1)) axes.set_yticks(np.linspace(0,1,num_2d_samples+1)) axes.grid() # 3D Test Case fig = plt.figure("3D Test Case",figsize=(8,6)) axes = plt.gca(projection='3d') lhd = latin_hypercube_sampling(3,num_3d_samples,'center') x = lhd[:,0] y = lhd[:,1] z = lhd[:,2] axes.scatter(x,y,z) axes.set_xticks(np.linspace(0,1,num_3d_samples+1)) axes.set_yticks(np.linspace(0,1,num_3d_samples+1)) axes.set_zticks(np.linspace(0,1,num_3d_samples+1)) # Display plots for both cases plt.show() import time ti = time.time() latin_hypercube_sampling(40,10000) tf = time.time() print('Time for 40D, 10000 samples: ' + str(tf-ti) + ' s') # 0.12 s on Surface Pro 3 pass