Skip to content

Commit

Permalink
Fatigue distribution added (#12)
Browse files Browse the repository at this point in the history
* 2.8.3 - Fatigue life distribution added, tests added

* 2.8.4 - Remove node version requirement, minor fixes
  • Loading branch information
AlexeySKiselev authored Jul 19, 2020
1 parent 5789ab3 commit dae7700
Show file tree
Hide file tree
Showing 7 changed files with 432 additions and 6 deletions.
3 changes: 2 additions & 1 deletion Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# Unirand
A JavaScript module for generating seeded random distributions and its statistical analysis.

Implemented in pure JavaScript with no dependencies, designed to work in Node.js and fully asynchronous, tested *with 780+ tests*.
Implemented in pure JavaScript with no dependencies, designed to work in Node.js and fully asynchronous, tested *with 800+ tests*.

#### [Supported distributions](./core/methods/)

Expand All @@ -25,6 +25,7 @@ Implemented in pure JavaScript with no dependencies, designed to work in Node.js
| Erlang distribution | `k` - integer, `k` > 0, `mu` - float value, `mu` > 0 | `unirand.erlang(k, mu).random()` |
| Exponential distribution | `lambda` - float value, `lambda` > 0 | `unirand.exponential(lambda).random()` |
| Extreme (Gumbel-type) Value distribution | `mu` - any value, `sigma` - float number, `sigma` > 0 | `unirand.extremevalue(mu, sigma).random()` |
| Fatigue life distribution | `alpha` > 0, `beta` > 0 | `unirand.fatigue(alpha, beta).random()` |
| Gamma distribution | `alpha` - float value, `alpha` > 0, `beta` - integer, `beta` > 0 | `unirand.gamma(alpha, beta).random()` |
| Geometric distribution | `p` - float value, 0 <= `p` <= 1 | `unirand.geometric(p).random()` |
| Irwin-Hall distribution | `n` - integer, `n` > 0 | `unirand.irwinhall(n).random()` |
Expand Down
32 changes: 32 additions & 0 deletions core/methods/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
| Name | Parameters | Usage |
| --- | --- | --- |
| Uniform distribution | `min` - any value, `max` - any value, `min` < `max` | `unirand.uniform(min, max).random()` |
| Normal (Gaussian) distribution | `mu` - any value, `sigma` > 0 | `unirand.normal(mu, sigma).random()` |
| Bates distribution | `n` - integer, `n` >= 1, `a` - any value, `b` - any value, `b` > `a` | `unirand.bates(n, a, b).random()` |
| Bernoulli distribution | `p` - float number, 0 <= `p` <= 1 | `unirand.bernoulli(p).random()` |
| Beta distribution | `alpha` - integer, `alpha` > 0, `beta` > integer, `beta` > 0 | `unirand.beta(alpha, beta).random()` |
| BetaPrime distribution | `alpha` - integer, `alpha` > 0, `beta` > integer, `beta` > 0 | `unirand.betaprime(alpha, beta).random()` |
| Binomial distribution | `n` - integer, `n` > 0, `p` - float number, 0 <= `p` <= 1 | `unirand.binomial(n, p).random()` |
| Cauchy (Lorenz) distribution | `x` - any value, `gamma` > 0 | `unirand.cauchy(x, gamma).random()` |
| Chi distribution | `k` - integer, `k` > 0 | `unirand.chi(k).random()` |
| Chi Square distribution | `k` - integer, `k` > 0 | `unirand.chisquare(k).random()` |
| Compertz distribution | `nu` > 0 - float value, `b` > 0 - float value | `unirand.compertz(nu, b).random()` |
| Delaporte distribution | `alpha` > 0 - float value, `beta` > 0 - float value, `lambda` > 0 - float value | `unirand.delaporte(alpha, beta, lambda).random()` |
| Erlang distribution | `k` - integer, `k` > 0, `mu` - float value, `mu` > 0 | `unirand.erlang(k, mu).random()` |
| Exponential distribution | `lambda` - float value, `lambda` > 0 | `unirand.exponential(lambda).random()` |
| Extreme (Gumbel-type) Value distribution | `mu` - any value, `sigma` - float number, `sigma` > 0 | `unirand.extremevalue(mu, sigma).random()` |
| Fatigue life distribution | `alpha` > 0, `beta` > 0 | `unirand.fatigue(alpha, beta).random()` |
| Gamma distribution | `alpha` - float value, `alpha` > 0, `beta` - integer, `beta` > 0 | `unirand.gamma(alpha, beta).random()` |
| Geometric distribution | `p` - float value, 0 <= `p` <= 1 | `unirand.geometric(p).random()` |
| Irwin-Hall distribution | `n` - integer, `n` > 0 | `unirand.irwinhall(n).random()` |
| Laplace distribution | `mu` - any value, `b` - float value, `b` > 0 | `unirand.laplace(mu, b).random()` |
| Logistic distribution | `mu` - any value, `s` - float value, `s` > 0 | `unirand.logistic(mu, s).random()` |
| Lognormal distribution | `mu` - any value, `sigma` - float value, `sigma` > 0 | `unirand.lognormal(mu, sigma).random()` |
| Negative Binomial distribution | `r` - integer, `r` > 0, `p` - float value, 0 <= `p` <= 1 | `unirand.negativebinomial(r, p).random()` |
| Pareto distribution | `xm` - float value, `xm` > 0, `alpha` - float value, `alpha` > 0 | `unirand.pareto(xm, alpha).random()` |
| Poisson distribution | `lambda` - integer, `lambda` > 0 | `unirand.poisson(lambda).random()` |
| Rayleigh distribution | `sigma` - float value, `sigma` > 0 | `unirand.rayleigh(sigma).random()` |
| Student's t-distribution | `v` - integer, `v` > 0 | `unirand.student(v).random()` |
| Triangular distribution | `a`, `b`, `c` - any number, `b` > `a`, `a` <= `c` <= `b` | `unirand.triangular(a, b, c).random()` |
| Weibull distribution | `k` - float value, `k` > 0, `lambda` - float value, `lambda` > 0 | `unirand.weibull(k, lambda).random()` |
| Zipf distribution | `alpha` - float value, `alpha` >= 0, `shape` - integer, `shape` > 1 | `unirand.zipf(alpha, shape).random()` |
160 changes: 160 additions & 0 deletions core/methods/fatigue.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
// @flow
/**
* Fatigue life Distribution, also known as Birnbaum–Saunders distribution
* Continuous distribution
* https://en.wikipedia.org/wiki/Birnbaum-Saunders_distribution
* @param alpha: number - shape parameter, alpha > 0
* @param beta: number - scale parameter, beta > 0
* @returns Fatigue Distributed value
* Created by Alexey S. Kiselev
*/

import type { MethodError, RandomArray } from '../types';
import type { IDistribution } from '../interfaces';

const Normal = require('./normal');

class Fatigue implements IDistribution {
alpha: number;
beta: number;
normal: Normal;

constructor(alpha: number, beta: number): void {
this.alpha = Number(alpha);
this.beta = Number(beta);
this.normal = new Normal(0, 1);
}

_random(norm: number): number {
return this.beta * Math.pow(this.alpha * norm + Math.sqrt(Math.pow(this.alpha * norm, 2) + 4), 2) / 4;
}

/**
* Generates a random number
* @returns {number} a Fatigue distributed number
*/
random(): number {
return this._random(this.normal.random());
}

/**
* Generates next seeded random number
* @returns {number} a Fatigue distributed number
*/
next(): number {
return this._random(this.normal.next());
}

/**
* Generates Fatigue distributed numbers
* @param n: number - Number of elements in resulting array, n > 0
* @returns Array<number> - Fatigue distributed numbers
*/
distribution(n: number): RandomArray {
let fatigueArray: RandomArray = [],
random: RandomArray = this.normal.distribution(n);
for (let i: number = 0; i < n; i += 1){
fatigueArray[i] = this._random(random[i]);
}
return fatigueArray;
}

/**
* Error handling
* @returns {boolean}
*/
isError(): MethodError {
if (!this.alpha || !this.beta) {
return {error: 'Fatigue distribution: you should point parameters "alpha" and "beta" as numerical values'};
}
if (this.alpha <= 0 || this.beta <= 0) {
return {error: 'Fatigue distribution: parameters "alpha" and "beta" must be a positive numbers'};
}

return { error: false };
}

/**
* Refresh method
* @param newAlpha: number - new parameter "alpha"
* @param newBeta: number - new parameter "beta"
* This method does not return values
*/
refresh(newAlpha: number, newBeta: number): void {
this.alpha = Number(newAlpha);
this.beta = Number(newBeta);
}

/**
* Class .toString method
* @returns {string}
*/
toString(): string {
let info = [
'Fatigue Distribution',
`Usage: unirand.fatigue(${this.alpha}, ${this.beta}).random()`
];
return info.join('\n');
}

/**
* Mean value
* Information only
* For calculating real mean value use analyzer
*/
get mean(): number {
return this.beta * (Math.pow(this.alpha, 2) + 2) /2;
}

/**
* Median value
* Information only
* For calculating real mean value use analyzer
*/
get median(): number {
return this.beta;
}

/**
* Variance value
* Information only
* For calculating real variance value use analyzer
*/
get variance(): number {
return Math.pow(this.alpha * this.beta, 2) * (5 * Math.pow(this.alpha, 2) + 4) / 4;
}

/**
* Skewness value
* Information only
* For calculating real skewness value use analyzer
*/
get skewness(): number {
return 4 * this.alpha * (11 * Math.pow(this.alpha, 2) + 6) / Math.pow(5 * this.alpha * this.alpha + 4, 1.5);
}

/**
* Kurtosis value
* Information only
* For calculating real kurtosis value use analyzer
*/
get kurtosis(): number {
return 3 + Math.pow(this.alpha, 2) * (558 * this.alpha * this.alpha + 240) / Math.pow(5 * this.alpha * this.alpha + 4, 2);
}

/**
* All parameters of distribution in one object
* Information only
*/
get parameters(): {} {
return {
mean: this.mean,
median: this.median,
variance: this.variance,
skewness: this.skewness,
kurtosis: this.kurtosis
};
}
}

module.exports = Fatigue;
2 changes: 2 additions & 0 deletions core/methods/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const delaporte = require('./delaporte');
const erlang = require('./erlang');
const exponential = require('./exponential');
const extremevalue = require('./extremevalue');
const fatigue = require('./fatigue');
const gamma = require('./gamma');
const geometric = require('./geometric');
const irwinhall = require('./irwinhall');
Expand Down Expand Up @@ -42,6 +43,7 @@ module.exports = {
erlang,
exponential,
extremevalue,
fatigue,
gamma,
geometric,
irwinhall,
Expand Down
5 changes: 1 addition & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "unirand",
"version": "2.8.2",
"version": "2.8.4",
"description": "Random numbers and Distributions generation",
"main": "./lib/index.js",
"scripts": {
Expand Down Expand Up @@ -45,9 +45,6 @@
],
"author": "Alexey S. Kiselev <alexeys.kiselev@yahoo.com>",
"license": "ISC",
"engines": {
"node": "^8.12"
},
"devDependencies": {
"babel-core": "^6.26.0",
"babel-eslint": "^8.1.1",
Expand Down
31 changes: 31 additions & 0 deletions test/distributions.seed.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,37 @@ describe('Random distributions with seed', () => {
done();
});
});
describe('Fatigue distribution (alpha = 1, beta = 2)', () => {
const Fatigue = require('../lib/methods/fatigue');
it('should return same value each time', () => {
const fatigue = new Fatigue(1, 2);
prng.seed('first fatigue seed test');
const fatigueFirst = fatigue.random();
for(let i = 0; i < 1000; i += 1) {
expect(fatigue.random()).to.be.closeTo(fatigueFirst, 0.000001);
}
prng.seed('second fatigue seed test');
const fatigueSecond = fatigue.random();
for(let i = 0; i < 1000; i += 1) {
expect(fatigue.random()).to.be.closeTo(fatigueSecond, 0.000001);
}
});
it('should return same distribution each time', function(done) {
this.timeout(480000);
const fatigue = new Fatigue(1, 2);
prng.seed('first fatigue seed test');
const fatigueFirst = fatigue.distribution(10000);
for(let i = 0; i < 10; i += 1) {
compareDistributions(fatigue.distribution(10000), fatigueFirst);
}
prng.seed('second fatigue seed test');
const fatigueSecond = fatigue.distribution(10000);
for(let i = 0; i < 10; i += 1) {
compareDistributions(fatigue.distribution(10000), fatigueSecond);
}
done();
});
});
describe('Erlang distribution (k = 2, mu = 2)', () => {
const Erlang = require('../lib/methods/erlang');
it('should return same value each time', () => {
Expand Down
Loading

0 comments on commit dae7700

Please sign in to comment.