import get from 'lodash-es/get.js'
import map from 'lodash-es/map.js'
import times from 'lodash-es/times.js'
import isNumber from 'lodash-es/isNumber.js'
import isnum from 'wsemi/src/isnum.mjs'
import cdbl from 'wsemi/src/cdbl.mjs'
import cint from 'wsemi/src/cint.mjs'
import jt from './jStat.mjs'
/**
* 依照指定統計分布隨機產生值或陣列
*
* Unit Test: {@link https://github.com/yuda-lyu/w-statistic/blob/master/test/sampleRandom.test.js Github}
* @memberOf w-statistic
* @param {String} name 輸入統計分布名稱
* @param {Object} [opt={}] 輸入設定物件,預設{}
* @param {Number} [opt.num=1] 輸入產生亂數數量整數,若有給予需大於等於1,預設1
* @param {Number} [opt.low=null] 輸入亂數之最小限制值數字,預設null
* @param {Number} [opt.up=null] 輸入亂數之最大限制值數字,預設null
* @returns {Number|Array} 回傳亂數值或亂數值陣列
* @example
*
* async function test() {
*
* let r
*
* r = await sampleRandom('normal', { mu: 100, sigma: 50 })
* console.log(r)
* // => maybe: 94.99873795683716 136.81783120735003 49.94186751166804,...
*
* r = await sampleRandom('normal', { mu: 100, sigma: 50, low: 90 })
* console.log(r)
* // => maybe: 143.11557161592685 95.05143199643211 103.90352980637562,...
*
* r = await sampleRandom('normal', { mu: 100, sigma: 50, low: 90, up: 110 })
* console.log(r)
* // => maybe: 99.45744560964987 95.98664948248341 95.69403830457458,...
*
* r = await sampleRandom('normal', { mu: 0, sigma: 1, num: 5 })
* console.log(r)
* // => maybe: [
* // 0.28480054449658343,
* // -1.6656082612520913,
* // -1.4973558587107332,
* // 0.9279728382322514,
* // 0.4704840133724234
* // ]
*
* }
* test()
* .catch((err) => {
* console.log(err)
* })
*
*/
async function sampleRandom(name, opt = {}) {
//fun, sample
let fun = null
if (name === 'beta') {
let alpha = get(opt, 'alpha')
if (!isNumber(alpha)) {
return Promise.reject(`opt.alpha is not a number`)
}
let beta = get(opt, 'beta')
if (!isNumber(beta)) {
return Promise.reject(`opt.beta is not a number`)
}
fun = () => {
return jt[name].sample(alpha, beta)
}
}
else if (name === 'centralF') {
let df1 = get(opt, 'df1')
if (!isNumber(df1)) {
return Promise.reject(`opt.df1 is not a number`)
}
let df2 = get(opt, 'df2')
if (!isNumber(df2)) {
return Promise.reject(`opt.df2 is not a number`)
}
fun = () => {
return jt[name].sample(df1, df2)
}
}
else if (name === 'cauchy') {
let local = get(opt, 'local')
if (!isNumber(local)) {
return Promise.reject(`opt.local is not a number`)
}
let scale = get(opt, 'scale')
if (!isNumber(scale)) {
return Promise.reject(`opt.scale is not a number`)
}
fun = () => {
return jt[name].sample(local, scale)
}
}
else if (name === 'chisquare') {
let dof = get(opt, 'dof')
if (!isNumber(dof)) {
return Promise.reject(`opt.dof is not a number`)
}
fun = () => {
return jt[name].sample(dof)
}
}
else if (name === 'exponential') {
let rate = get(opt, 'rate')
if (!isNumber(rate)) {
return Promise.reject(`opt.rate is not a number`)
}
fun = () => {
return jt[name].sample(rate)
}
}
else if (name === 'gamma') {
let shape = get(opt, 'shape')
if (!isNumber(shape)) {
return Promise.reject(`opt.shape is not a number`)
}
let scale = get(opt, 'scale')
if (!isNumber(scale)) {
return Promise.reject(`opt.scale is not a number`)
}
fun = () => {
return jt[name].sample(shape, scale)
}
}
else if (name === 'invgamma') {
let shape = get(opt, 'shape')
if (!isNumber(shape)) {
return Promise.reject(`opt.shape is not a number`)
}
let scale = get(opt, 'scale')
if (!isNumber(scale)) {
return Promise.reject(`opt.scale is not a number`)
}
fun = () => {
return jt[name].sample(shape, scale)
}
}
else if (name === 'kumaraswamy') {
let alpha = get(opt, 'alpha')
if (!isNumber(alpha)) {
return Promise.reject(`opt.alpha is not a number`)
}
let beta = get(opt, 'beta')
if (!isNumber(beta)) {
return Promise.reject(`opt.beta is not a number`)
}
fun = () => {
return jt[name].sample(alpha, beta)
}
}
else if (name === 'lognormal') {
let mu = get(opt, 'mu')
if (!isNumber(mu)) {
return Promise.reject(`opt.mu is not a number`)
}
let sigma = get(opt, 'sigma')
if (!isNumber(sigma)) {
return Promise.reject(`opt.sigma is not a number`)
}
fun = () => {
return jt[name].sample(mu, sigma)
}
}
else if (name === 'normal') {
let mu = get(opt, 'mu')
if (!isNumber(mu)) {
return Promise.reject(`opt.mu is not a number`)
}
let sigma = get(opt, 'sigma')
if (!isNumber(sigma)) {
return Promise.reject(`opt.sigma is not a number`)
}
fun = () => {
return jt[name].sample(mu, sigma)
}
}
else if (name === 'pareto') {
return Promise.reject(`invalid pareto.sample`)
}
else if (name === 'studentt') {
let dof = get(opt, 'dof')
if (!isNumber(dof)) {
return Promise.reject(`opt.dof is not a number`)
}
fun = () => {
return jt[name].sample(dof)
}
}
else if (name === 'tukey') {
return Promise.reject(`invalid tukey.sample`)
}
else if (name === 'weibull') {
let scale = get(opt, 'scale')
if (!isNumber(scale)) {
return Promise.reject(`opt.scale is not a number`)
}
let shape = get(opt, 'shape')
if (!isNumber(shape)) {
return Promise.reject(`opt.shape is not a number`)
}
fun = () => {
return jt[name].sample(scale, shape)
}
}
else if (name === 'uniform') {
let a = get(opt, 'a')
if (!isNumber(a)) {
return Promise.reject(`opt.a is not a number`)
}
let b = get(opt, 'b')
if (!isNumber(b)) {
return Promise.reject(`opt.b is not a number`)
}
fun = () => {
return jt[name].sample(a, b)
}
}
else if (name === 'binomial') {
return Promise.reject(`invalid binomial.sample`)
}
else if (name === 'negbin') {
return Promise.reject(`invalid negbin.sample`)
}
else if (name === 'hypgeom') {
return Promise.reject(`invalid hypgeom.sample`)
}
else if (name === 'poisson') {
let l = get(opt, 'l')
if (!isNumber(l)) {
return Promise.reject(`opt.l is not a number`)
}
fun = () => {
return jt[name].sample(l)
}
}
else if (name === 'triangular') {
let a = get(opt, 'a')
if (!isNumber(a)) {
return Promise.reject(`opt.a is not a number`)
}
let b = get(opt, 'b')
if (!isNumber(b)) {
return Promise.reject(`opt.b is not a number`)
}
let c = get(opt, 'c')
if (!isNumber(c)) {
return Promise.reject(`opt.c is not a number`)
}
fun = () => {
return jt[name].sample(a, b, c)
}
}
else if (name === 'arcsine') {
let a = get(opt, 'a')
if (!isNumber(a)) {
return Promise.reject(`opt.a is not a number`)
}
let b = get(opt, 'b')
if (!isNumber(b)) {
return Promise.reject(`opt.b is not a number`)
}
fun = () => {
return jt[name].sample(a, b)
}
}
else {
return Promise.reject(`invalid name[${name}]`)
}
//num
let num = get(opt, 'num')
num = cint(num)
if (num <= 0) {
num = 1
}
//low
let low = get(opt, 'low')
if (!isnum(low)) {
low = null
}
else {
low = cdbl(low)
}
//up
let up = get(opt, 'up')
if (!isnum(up)) {
up = null
}
else {
up = cdbl(up)
}
//check low>=up
if (low !== null && up !== null) {
if (low >= up) {
throw new Error(`low[${low}] >= up[${up}]`)
}
}
//getNum
let getNum = () => {
let r = fun()
if (low !== null) {
if (r < low) {
r = getNum()
}
}
if (up !== null) {
if (r > up) {
r = getNum()
}
}
return r
}
//rs
let rs = map(times(num), () => {
return getNum()
})
if (num === 1) {
rs = rs[0]
}
return rs
}
export default sampleRandom