Installation
npm install hasard
Description
Random variables and random nested objects manipulation in javascript
Inspired by :
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
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 which is Math.random
by default.
const n = h.value({choices: ['white', 'yellow'], prng: <custom prng>})
Basic types
h.value
h.value(Array.<Hasard> | Hasard.<Array>)
const v = h.value(['white', 'yellow']);
h.value({choices: Array.<Hasard> | Hasard.<Array>, weights}) -> Hasard
const v = h.value({
choices: ['white', 'yellow'],
weights: [0.75, 0.25]
});
h.boolean
h.boolean({Hasard.<Number>} probability) -> Hasard.<Boolean>
const v = h.boolean(0.2); // will be true 20% of the time
h.boolean({prob: Hasard.<Number>}) -> Hasard.<Boolean>
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>
const v = h.number(0, 1);
h.number([{Hasard.<Number>} start, {Hasard.<Number>} end]) -> Hasard.<Number>
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 if you need another distribution
const v = h.number({
type: 'uniform',
start: 0,
end: 1
});
const v = h.number({
type: 'normal',
mean: -2,
std: 3
});
h.integer
h.integer({Hasard.<Integer>} start,{Hasard.<Integer>} end) -> Hasard.<Integer>
const v = h.integer(0, 10);
h.integer([{Hasard.<Integer>} start,{Hasard.<Integer>} end]) -> Hasard.<Integer>
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
const v = h.integer({
type: 'poisson',
lambda: 3
});
h.string
h.string({value: Hasard, size: Hasard.<integer>}) -> Hasard.<String>
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>
const v = h.array({
value: h.integer([0, 255]),
size: h.integer([5, 10]),
});
h.array(Array.<Hasard>) -> Hasard.<Array>
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>
// 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>
const obj = h.object({
color1 : h.value(['white', 'yellow']),
color2 : h.value(['black', 'grey'])
});
h.object(Hasard.<Array.>, Hasard) -> Hasard.<Object>
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
const v = h.matrix({
value: h.integer([0, 255]),
shape: [128, 128, 3]
});
create random matrix with random values and random size
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
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>}
// 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
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
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>
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>
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>
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>
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>
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
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>
const int = h.round(h.number(0, 10));
h.floor(Hasard.<Number>) -> Hasard.<Integer>
const int = h.floor(h.number(0, 10));
h.ceil(Hasard.<Number>) -> Hasard.<Integer>
const int = h.ceil(h.number(0, 10));
h.concat(Hasard.<Array>, Hasard.<Array>) -> Hasard.<Array>
const int = h.concat([1,2], h.array({value: h.integer([0, 10]), size: 3}));
h.getProperty(Hasard.<Number>, Hasard.<Object> | Hasard.<Array>) -> Hasard
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
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
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);
})