# lhsmdu Release 1.1

This is an implementation of Latin Hypercube Sampling with Multi-Dimensional Uniformity (LHS-MDU) from Deutsch and Deutsch, "Latin hypercube sampling with multidimensional uniformity.

Keywords
latin-hypercube, latin-hypercube-sampling, python, python3, sampling, statistics
MIT
Install
``` pip install lhsmdu==1.1 ```

# LHS-MDU

## Installation

You can install lhsmdu using pip:

```\$ pip install lhsmdu
```

Alternatively, you can clone on github and then install the package locally:

```\$ git clone https://github.com/sahilm89/lhsmdu
\$ cd lhsmdu
\$ python setup.py install --user   # for this user only.
```

or:

```\$ pip install git+https://github.com/sahilm89/lhsmdu --user
```

## Basics

This is a package for generating latin hypercube samples with multi-dimensional uniformity.

To use, simply do:

```>>> import lhsmdu
>>> k = lhsmdu.sample(2, 20) # Latin Hypercube Sampling with multi-dimensional uniformity
```

This will generate a nested list with 2 variables, with 20 samples each.

To plot and see the difference between Monte Carlo and LHS-MDU sampling for a 2 dimensional system:

```>>> l = lhsmdu.createRandomStandardUniformMatrix(2, 20) # Monte Carlo sampling
>>> k = lhsmdu.sample(2, 20) # Latin Hypercube Sampling with multi-dimensional uniformity
>>> k = np.array(k)
>>> l = np.array(l)
>>> import matplotlib.pyplot as plt
>>> fig = plt.figure()
>>> ax = fig.gca()
>>> ax.set_xticks(numpy.arange(0,1,0.1))
>>> ax.set_yticks(numpy.arange(0,1,0.1))
>>> plt.scatter(k, k, color="g", label="LHS-MDU")
>>> plt.scatter(l, l, color="r", label="MC")
>>> plt.grid()
>>> plt.show()
```

You can use the strata generated by the algorithm to sample again, if you so desire. For this, you can do:

```>>> m = lhsmdu.resample()
>>> n = lhsmdu.resample()
>>> o = lhsmdu.resample()
```

This will again generate the same number of samples as before, a nested list with 2 variables, with 20 samples each.

You can plot these together and see the sampling from the strata::
```>>> m = np.array(m)
>>> n = np.array(n)
>>> o = np.array(o)```
```>>> fig = plt.figure()
>>> ax = fig.gca()
>>> ax.set_xticks(numpy.arange(0,1,0.1))
>>> ax.set_yticks(numpy.arange(0,1,0.1))
>>> plt.title("LHS-MDU")
>>> plt.scatter(k, k, c="g", label="sample 1")
>>> plt.scatter(m, m, c="r", label="resample 2")
>>> plt.scatter(n, n, c="b", label="resample 3")
>>> plt.scatter(o, o, c="y", label="resample 4")
>>> plt.grid()
>>> plt.show()```

Alternatively, you can choose to get new strata each time, and see the sampling hence:

```>>> p = lhsmdu.sample(2, 20) # Latin Hypercube Sampling with multi-dimensional uniformity
>>> q = lhsmdu.sample(2, 20) # Latin Hypercube Sampling with multi-dimensional uniformity
>>> r = lhsmdu.sample(2, 20) # Latin Hypercube Sampling with multi-dimensional uniformity

>>> p = np.array(p)
>>> q = np.array(q)
>>> r = np.array(r)

>>> fig = plt.figure()
>>> ax = fig.gca()
>>> ax.set_xticks(numpy.arange(0,1,0.1))
>>> ax.set_yticks(numpy.arange(0,1,0.1))
>>> plt.title("LHS-MDU")
>>> plt.scatter(k, k, c="g", label="sample 1")
>>> plt.scatter(p, p, c="r", label="sample 2")
>>> plt.scatter(q, q, c="b", label="sample 3")
>>> plt.scatter(r, r, c="y", label="sample 4")
>>> plt.grid()
>>> plt.show()
```

## Changing the random seed

You will notice that the strata generated are the same each time you run the program again. This is because the random seed is a global constant set to a default value by design, so that simulations can be replicated. In order to change this behavior, you can set a new random seed using the following code:

```>>> randSeed = 11 # random number of choice
>>> lhsmdu.setRandomSeed(randSeed) # Latin Hypercube Sampling with multi-dimensional uniformity
>>> lhsmdu.sample(2, 20) # Latin Hypercube Sampling with multi-dimensional uniformity
```

Alternatively, you can also set the seed by using sample with a new seed:

```>>> lhsmdu.sample(2, 20, randomSeed=randSeed) # Latin Hypercube Sampling with multi-dimensional uniformity
```

To change the random seed in every run, you can set on top of the program:

```>>> lhsmdu.setRandomSeed(None)
```

## Sampling from arbitrary CDFs

After uniformly distributed samples have been generated from LHSMDU, you can convert these to samples from arbitrary distributions using inverse tranform sampling. In this, the CDF [0,1] of the distribution of interest is inverted, and then data points corresponding to the uniformly sampled points are picked up. To do this, you must have a rv_contiuous or rv_discrete distribution instance taken from scipy.stats. You can also use frozen distributions (after setting loc and scale parameters). Following is an example for normal distribution.:

```>>> import scipy.stats.distributions as ssd
>>> p = ssd.norm
>>> new_samples = lhsmdu.inverseTransformSample(p, k)
>>> plt.hist(new_samples)
>>> plt.show()
```

## Citing this repository

To cite, please cite both the original paper from Deutsch and Deutsch: http://dx.doi.org/10.1016%2Fj.jspi.2011.09.016. and the repository: https://doi.org/10.5281/zenodo.2578781