Skip to content

Commit

Permalink
fix: add type coverage through JSDoc
Browse files Browse the repository at this point in the history
  • Loading branch information
kenany committed Nov 24, 2021
1 parent 2919624 commit 1da099b
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 13 deletions.
5 changes: 4 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
{
"extends": "@kenan"
"extends": "@kenan",
"rules": {
"no-var": 0
}
}
4 changes: 1 addition & 3 deletions .renovaterc.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
{
"extends": [
"@kenan"
]
"extends": ["@kenan/renovate-config"]
}
99 changes: 92 additions & 7 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,52 @@ var assign = require('lodash.assign');
var map = require('lodash.map');
var reduce = require('lodash.reduce');

/** @typedef {[rating: number, rd: number, vol: number]} Opponent */

/**
* @typedef {object} ScaledOpponent
* @property {number} muj
* @property {number} phij
* @property {number} gphij
* @property {number} emmp
* @property {number} score
*/

/**
* @param {number} rating
* @param {number} rd
* @param {{ rating: number; }} options
*/
function scale(rating, rd, options) {
var mu = (rating - options.rating) / 173.7178;
var phi = rd / 173.7178;
return { mu: mu, phi: phi };
}

/**
* @param {number} phi
* @returns {number}
*/
function g(phi) {
return 1 / Math.sqrt(1 + 3 * Math.pow(phi, 2) / Math.pow(Math.PI, 2));
}

/**
* @param {number} mu
* @param {number} muj
* @param {number} phij
* @returns {number}
*/
function e(mu, muj, phij) {
return 1 / (1 + Math.exp(-g(phij) * (mu - muj)));
}

/**
* @param {number} mu
* @param {readonly Opponent[]} opponents
* @param {{ rating: number; }} options
* @returns {ScaledOpponent[]}
*/
function scaleOpponents(mu, opponents, options) {
return map(opponents, function(opp) {
var scaled = scale(opp[0], opp[1], options);
Expand All @@ -31,21 +63,41 @@ function scaleOpponents(mu, opponents, options) {
});
}

/**
* @param {readonly ScaledOpponent[]} opponents
* @returns {number}
*/
function updateRating(opponents) {
return 1 / reduce(opponents, function(sum, opp) {
return sum + Math.pow(opp.gphij, 2) * opp.emmp * (1 - opp.emmp);
}, 0);
}

/**
* @param {number} v
* @param {readonly ScaledOpponent[]} opponents
* @returns {number}
*/
function computeDelta(v, opponents) {
return v * reduce(opponents, function(sum, opp) {
return sum + opp.gphij * (opp.score - opp.emmp);
}, 0);
}

/**
* @param {number} phi
* @param {number} v
* @param {number} delta
* @param {number} a
* @param {{ tau: number; }} options
*/
function volF(phi, v, delta, a, options) {
var phi2 = Math.pow(phi, 2);
var d2 = Math.pow(delta, 2);

/**
* @param {number} x
*/
return function(x) {
var ex = Math.exp(x);
var a2 = phi2 + v + ex;
Expand All @@ -55,12 +107,21 @@ function volF(phi, v, delta, a, options) {
};
}

/**
* @param {number} sigma
* @param {number} phi
* @param {number} v
* @param {number} delta
* @param {{ tau: number; }} options
* @returns {number}
*/
function computeVolatility(sigma, phi, v, delta, options) {
// 5.1
var a = Math.log(Math.pow(sigma, 2));
var f = volF(phi, v, delta, a, options);

// 5.2
/** @type {number} */
var b;
if (Math.pow(delta, 2) > Math.pow(phi, 2) + v) {
b = Math.log(Math.pow(delta, 2) - Math.pow(phi, 2) - v);
Expand All @@ -79,6 +140,7 @@ function computeVolatility(sigma, phi, v, delta, options) {

// 5.4
while (Math.abs(b - a) > 0.000001) {
/** @type {number} */
var c = a + (a - b) * fa / (fb - fa);
var fc = f(c);

Expand All @@ -98,10 +160,21 @@ function computeVolatility(sigma, phi, v, delta, options) {
return Math.exp(a / 2);
}

/**
* @param {number} sigmap
* @param {number} phi
* @returns {number}
*/
function phiStar(sigmap, phi) {
return Math.sqrt(Math.pow(sigmap, 2) + Math.pow(phi, 2));
}

/**
* @param {number} phis
* @param {number} mu
* @param {number} v
* @param {readonly ScaledOpponent[]} opponents
*/
function newRating(phis, mu, v, opponents) {
var phip = 1 / Math.sqrt(1 / Math.pow(phis, 2) + 1 / v);
var mup = mu + Math.pow(phip, 2) * reduce(opponents, function(sum, opp) {
Expand All @@ -110,18 +183,32 @@ function newRating(phis, mu, v, opponents) {
return { mu: mup, phi: phip };
}

/**
* @param {number} mup
* @param {number} phip
* @param {{ rating: number; }} options
*/
function unscale(mup, phip, options) {
var rating = 173.7178 * mup + options.rating;
var rd = 173.7178 * phip;
return { rating: rating, rd: rd };
}

/**
* @param {number} rating
* @param {number} rd
* @param {number} sigma
* @param {readonly Opponent[]} opponents
* @param {{ rating?: number; tau?: number; }} [options]
* @returns {{ rating: number; rd: number; vol: number; }}
*/
function rate(rating, rd, sigma, opponents, options) {
options = assign({}, { rating: 1500, tau: 0.5 }, options || {});
/** @type {{ rating: number; tau: number; }} */
var opts = assign({}, { rating: 1500, tau: 0.5 }, options || {});

// Step 2
var scaled = scale(rating, rd, options);
var scaledOpponents = scaleOpponents(scaled.mu, opponents, options);
var scaled = scale(rating, rd, opts);
var scaledOpponents = scaleOpponents(scaled.mu, opponents, opts);

// Step 3
var v = updateRating(scaledOpponents);
Expand All @@ -130,17 +217,15 @@ function rate(rating, rd, sigma, opponents, options) {
var delta = computeDelta(v, scaledOpponents);

// Step 5
var sigmap = computeVolatility(sigma, scaled.phi, v, delta, options);
var sigmap = computeVolatility(sigma, scaled.phi, v, delta, opts);

// Step 6
var phis = phiStar(sigmap, scaled.phi);

// Step 7
var updated = newRating(phis, scaled.mu, v, scaledOpponents);

var unscaled = unscale(updated.mu, updated.phi, options);
unscaled.vol = sigmap;
return unscaled;
return assign({}, unscale(updated.mu, updated.phi, opts), { vol: sigmap });
}

module.exports = rate;
16 changes: 14 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,11 @@
},
"scripts": {
"release": "semantic-release",
"pretest": "npm run -s lint",
"type-check": "tsc",
"type-coverage": "type-coverage --at-least 100 --detail --strict",
"pretest": "npm run -s type-check && npm run -s type-coverage",
"test": "tape test/index.js",
"posttest": "npm run -s lint",
"lint": "eslint index.js test/index.js bench/index.js"
},
"dependencies": {
Expand All @@ -36,6 +39,13 @@
"@kenan/renovate-config": "^1.5.1",
"@semantic-release/changelog": "^6.0.1",
"@semantic-release/git": "^10.0.1",
"@tsconfig/node12": "^1.0.9",
"@types/almost-equal": "^1.1.0",
"@types/lodash.assign": "^4.2.6",
"@types/lodash.isfunction": "^3.0.6",
"@types/lodash.map": "^4.6.13",
"@types/lodash.reduce": "^4.6.6",
"@types/tape": "^4.13.2",
"almost-equal": "^1.1.0",
"beautify-benchmark": "^0.2.4",
"benchmark": "^2.1.4",
Expand All @@ -44,6 +54,8 @@
"glicko2": "^0.8.6",
"lodash.isfunction": "^3.0.9",
"semantic-release": "^18.0.0",
"tape": "^5.3.2"
"tape": "^5.3.2",
"type-coverage": "^2.19.0",
"typescript": "^4.5.2"
}
}
9 changes: 9 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"extends": "@tsconfig/node12/tsconfig.json",
"compilerOptions": {
"allowJs": true,
"checkJs": true,
"noEmit": true
},
"include": ["*.js", "test/**/*.js"]
}

0 comments on commit 1da099b

Please sign in to comment.