hasard
Version:
Random variables and random nested objects manipulation in javascript
507 lines (394 loc) • 11.5 kB
Markdown
[](https://travis-ci.com/piercus/hasard)
[](https://codecov.io/gh/piercus/hasard)
## Installation
```
npm install hasard
```
## Description
Random variables and random nested objects manipulation in javascript
Inspired by :
* [probability-distributions](https://github.com/Mattasher/probability-distributions)
* [imgaug](https://github.com/aleju/imgaug)
Features:
* Generate basic types randomly (string, number, boolean, integer)
* Nested random object (array, object, matrix)
* Use distribution to generate numbers (normal, uniform, truncated-normal) and integers (poisson, uniform)
* Add reference + context to fix a random variable value in a local context
* Easy-to-use common operators on random variable (add, substract, divide, multiply, round, ceil, floor)
* Create custom operators
* Change the Pseudorandom number generator
* Stream API
## Simple Usage
```javascript
const h = require('hasard');
const v = h.object({
color: h.value(['white', 'yellow']), // randomly choose between 2 values
size: h.integer(10, 20) // randomly choose an integer between 10 and 20
});
const values = v.run(3);
console.log(values);
// [{color: 'white', size: 12}, {color: 'yellow', size: 18}, {color: 'yellow', size: 17}]
const value = v.runOnce();
console.log(value);
// {color: 'white', size: 13}
```
## Prng
You can customize the [Pseudorandom number generator](https://en.wikipedia.org/wiki/Pseudorandom_number_generator) which is `Math.random` by default.
```javascript
const n = h.value({choices: ['white', 'yellow'], prng: <custom prng>})
```
## Basic types
### h.value
#### h.value(Array.<Hasard> | Hasard.<Array>)
```javascript
const v = h.value(['white', 'yellow']);
```
#### h.value({choices: Array.<Hasard> | Hasard.<Array>, weights}) -> Hasard
```javascript
const v = h.value({
choices: ['white', 'yellow'],
weights: [0.75, 0.25]
});
```
## h.boolean
### h.boolean({Hasard.<Number>} probability) -> Hasard.<Boolean>
```javascript
const v = h.boolean(0.2); // will be true 20% of the time
```
### h.boolean({prob: Hasard.<Number>}) -> Hasard.<Boolean>
```javascript
const v = h.boolean({prob: 0.3}); // will be true 30% of the time
```
### h.number
#### h.number({Hasard.<Number>} start, {Hasard.<Number>} end) -> Hasard.<Number>
```javascript
const v = h.number(0, 1);
```
#### h.number([{Hasard.<Number>} start, {Hasard.<Number>} end]) -> Hasard.<Number>
```javascript
const v = h.number([0, 1]);
```
#### h.number({type: String, ...}) -> Hasard.<Number>
Available distribution for numbers are
* **normal**
* **uniform**
* **truncated-normal**
Please [Open an issue](https://github.com/piercus/hasard/issues/new) if you need another distribution
```javascript
const v = h.number({
type: 'uniform',
start: 0,
end: 1
});
```
```javascript
const v = h.number({
type: 'normal',
mean: -2,
std: 3
});
```
### h.integer
#### h.integer({Hasard.<Integer>} start,{Hasard.<Integer>} end) -> Hasard.<Integer>
```javascript
const v = h.integer(0, 10);
```
#### h.integer([{Hasard.<Integer>} start,{Hasard.<Integer>} end]) -> Hasard.<Integer>
```javascript
const v = h.integer([0, 10]);
```
#### h.integer({type: String, ...}) -> Hasard.<Integer>
For now, the only available distribution for integer is `poisson`, please [Open an issue](https://github.com/piercus/hasard/issues/new)
```javascript
const v = h.integer({
type: 'poisson',
lambda: 3
});
```
### h.string
#### h.string({value: Hasard, size: Hasard.<integer>}) -> Hasard.<String>
```javascript
const v = h.string({
value: h.value(["a", "b", "c", "d"]),
size: h.integer([5, 10])
});
```
### h.array
#### h.array({value: Hasard, size: Hasard.<Integer>}) -> Hasard.<Array>
```javascript
const v = h.array({
value: h.integer([0, 255]),
size: h.integer([5, 10]),
});
```
#### h.array(Array.<Hasard>) -> Hasard.<Array>
```javascript
const v = h.array([
h.integer([0, 255]),
h.integer([0, 255]),
h.integer([0, 255])
]);
```
#### h.array({values: Array.<Hasard>, size: Hasard.<Integer>, randomOrder: Hasard.<Boolean>}) -> Hasard.<Array>
```javascript
// pick 5 digits in a randomOrder
const v = h.array({
values: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
size: 5,
randomOrder: true
});
```
### h.object
#### h.object(Object.<String, Hasard>) -> Hasard.<Object>
```javascript
const obj = h.object({
color1 : h.value(['white', 'yellow']),
color2 : h.value(['black', 'grey'])
});
```
#### h.object(Hasard.<Array.<String>>, Hasard) -> Hasard.<Object>
```javascript
const phoneNumber = hasard.array({
value: hasard.add(
new hasard.Value(['+33', '+32', '+1']),
new hasard.String({
value: new hasard.Value(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']),
size: 9 // 9 digits in phone numbers
})
),
size : 5 // 5 keys
});
const fullName = hasard.add(
new hasard.Value(['Mr ', 'M ']),
new hasard.Value(['Thomas ', 'Nicolas ', 'Julien ', 'Quentin ', 'Maxime ']),
new hasard.Value(['DURAND', 'DUBOIS', 'LEFEBVRE', 'MOREAU', 'MOREL', 'FOURNIER'])
);
const randomPhoneDirectory = h.object(phoneNumber, fullName);
randomPhoneDirectory.run(2) // run 2 times
//
// {
// '+33236972292': 'M Julien FOURNIER',
// '+1833509762': 'Mr Quentin DURAND',
// '+33210149263': 'Mr Maxime MOREAU',
// '+1807872258': 'Mr Julien DURAND',
// '+32215961607': 'M Julien DUBOIS'
// }
//
// {
// '+32067043361': 'Mr Nicolas MOREL',
// '+33898861064': 'Mr Thomas DURAND',
// '+33730685919': 'Mr Nicolas MOREL',
// '+33723780566': 'M Nicolas FOURNIER',
// '+33515400984': 'Mr Quentin DUBOIS'
// }
```
### h.matrix
#### h.matrix({value: Hasard, shape: Hasard.<Array.<Integer>>}) -> Hasard.<Matrix>
create matrix with a specific shape
```javascript
const v = h.matrix({
value: h.integer([0, 255]),
shape: [128, 128, 3]
});
```
create random matrix with random values and random size
```javascript
const v = h.matrix({
value: h.integer([0, 255]),
shape: h.array({
value: h.integer([5, 10]),
size: h.integer([1, 4])
})
});
```
### h.reference
#### h.reference(Hasard) -> Hasard
A reference is generated only once per objet per run.
Let's take an example of how it can be used
```javascript
const value = h.integer([0, 255]);
const v = h.array([
value,
value,
value
]);
v.run(2);
// all values are randomized independently
// [[22, 128, 54], [250, 134, 12]]
const ref = h.reference(h.Integer([0, 255]));
const v = h.array([
ref,
ref,
ref
]);
v.run(2);
// reference is reused inside the same run
// [[72, 72, 72], [114, 114, 114]]
```
#### h.reference({source: Hasard, context: Hasard.<String>}) -> Hasard
When defined with a context, the reference is related to a context.
You can define a context with any Hasard tool, by using `{contextName: <name of the context>}`
```javascript
// we will create a grey image in RGB so R = G = B
const ref = h.reference({
source: h.Integer([0, 255]),
context: 'pixel'
});
// Here we need to use the form h.array({values, contextName})
const pixel = h.array({
values: [
ref,
ref,
ref
],
contextName: 'pixel'
});
const img = h.matrix({
value: pixel,
shape: [2,2]
})
v.run(2);
// reference is reused inside the same pixel
// [
// [[[12, 12, 12],[145, 145, 145]],[[251, 251, 251],[88, 88, 88]]], // first run,
// [[[212, 212, 212],[2, 2, 2]],[[78, 78, 78],[130, 130, 130]]] // second run,
//]
```
## Helpers
#### h.isHasard(Any) -> Boolean
Check if the object is an instance of the hasard library
```javascript
const value = h.integer([0, 255]);
h.isHasard(value); // true
h.isHasard([0, 255]); // false
```
#### h.fn(Function(Any, ...)) -> Function(Hasard.<Any>, ...)
Example of use
```javascript
const refA = h.reference(h.number(0, 1));
const refB = h.reference(h.number(0, 1));
const addHasard = h.fn((a, b) => {
return a + b;
});
const obj = h.object({
a: refA,
b: refB,
sum: addHasard(refA, refB)
});
```
## Shortcuts
Hasard provides shortcuts for most common operations
#### h.add(Hasard.<Number>, Hasard.<Number>, ...) -> Hasard.<Number>
```javascript
const refA = h.reference(h.number(0, 1));
const refB = h.reference(h.number(0, 1));
const obj = h.object({
a: refA,
b: refB,
sum: h.add(refA, refB)
});
```
#### h.add(Hasard.<String>, Hasard.<String>, ...) -> Hasard.<String>
```javascript
const a = h.value(['M. ', 'Mme ']);
const b = h.value(['DUPONT', 'DURANT']);
h.add(a, b).run(2)
// ['M. DUPONT', 'M. DURANT']
```
#### h.substract(Hasard.<Number>, Hasard.<Number>) -> Hasard.<Number>
```javascript
const refA = h.reference(h.number(0, 1));
const refB = h.reference(h.number(0, 1));
const obj = h.object({
a: refA,
b: refB,
diff: h.substract(refA, refB)
});
```
#### h.multiply(Hasard.<Number>, Hasard.<Number>) -> Hasard.<Number>
```javascript
const refA = h.reference(h.number(0, 1));
const refB = h.reference(h.number(0, 1));
const obj = h.object({
a: refA,
b: refB,
mul: h.multiply(refA, refB)
});
```
#### h.divide(Hasard.<Number>, Hasard.<Number>) -> Hasard.<Number>
```javascript
const refA = h.reference(h.number(0, 1));
const refB = h.reference(h.number(1, 2));
const obj = h.object({
a: refA,
b: refB,
ratio: h.divide(refA, refB)
});
```
#### h.if(Hasard.<Boolean>, Hasard, Hasard) -> Hasard
```javascript
const test = h.boolean(0.5);
const poisson = h.reference(h.integer({type: 'poisson', lambda: '3'}));
const signedPoisson = h.multiply(h.if(test, -1, 1), poisson)
```
#### h.round(Hasard.<Number>) -> Hasard.<Integer>
```javascript
const int = h.round(h.number(0, 10));
```
#### h.floor(Hasard.<Number>) -> Hasard.<Integer>
```javascript
const int = h.floor(h.number(0, 10));
```
#### h.ceil(Hasard.<Number>) -> Hasard.<Integer>
```javascript
const int = h.ceil(h.number(0, 10));
```
#### h.concat(Hasard.<Array>, Hasard.<Array>) -> Hasard.<Array>
```javascript
const int = h.concat([1,2], h.array({value: h.integer([0, 10]), size: 3}));
```
#### h.getProperty(Hasard.<Number>, Hasard.<Object> | Hasard.<Array>) -> Hasard
```javascript
const int = h.getProperty(0, h.array({value: h.integer([0, 10]), size: 3}));
```
## Nested randomness
Using `set` method, object properties can be set afterward
### Generate a random nested Object
```javascript
const randomValue = h.value();
const randomInteger = h.integer({type: 'poisson', lambda: 4});
const randomString = h.string({
size: h.add(randomInteger, 5),
value: h.value('abcdefghijklmnopkrstuvw'.split(''))
});
const randomNumber = h.number(0, 100);
const randomKeys = h.array({
size: randomInteger,
value: randomString
});
const randomObject = h.object(
randomKeys,
randomValue
);
randomValue.set({
choices: [
randomString,
randomObject,
randomNumber,
randomInteger
]
});
console.log(randomObject.run(1));
```
## Stream API
```javascript
const h = require('hasard');
const v = h.object({
color: h.value(['white', 'yellow']), // randomly choose between 2 values
size: h.integer(10, 20) // randomly choose an integer between 10 and 20
});
const streamValue = v.stream(3);
streamValue.on('data', d => {
console.log(d);
})
```