Skip to content

Commit 3ab9bc1

Browse files
dvd101xDavid Contrerasjosdejong
authored
Extend quantileSeq with support for a dimension (#3002)
* Included math to syntax when missing * Included solveODE * renamed initialStep as firstStep * Included tests for solveODE * Test the full state instead of the final state * Fixed issue with tolerance * Added unit signature for y0 * Included units test also for y0 * Included embedded docs and more tests * Included error for tspan * It works with bignumbers * reduced calling bignumber * extended the search for bignumbers * The jsdocs is less ambiguous * included tests for step options * Allowed for 0 minStep * Optimization to avoid checking the sign every step * added dim to quantile * Included transform * Removed modification of the docs I made an unwanted modification --------- Co-authored-by: David Contreras <[email protected]> Co-authored-by: Jos de Jong <[email protected]>
1 parent 49c793b commit 3ab9bc1

File tree

4 files changed

+95
-21
lines changed

4 files changed

+95
-21
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { factory } from '../../utils/factory.js'
2+
import { createQuantileSeq } from '../../function/statistics/quantileSeq.js'
3+
import { lastDimToZeroBase } from './utils/lastDimToZeroBase.js'
4+
5+
const name = 'quantileSeq'
6+
const dependencies = ['typed', 'add', 'multiply', 'partitionSelect', 'compare', 'isInteger']
7+
8+
/**
9+
* Attach a transform function to math.quantileSeq
10+
* Adds a property transform containing the transform function.
11+
*
12+
* This transform changed the `dim` parameter of function std
13+
* from one-based to zero based
14+
*/
15+
export const createQuantileSeqTransform = /* #__PURE__ */ factory(name, dependencies, ({ typed, add, multiply, partitionSelect, compare, isInteger }) => {
16+
const quantileSeq = createQuantileSeq({ typed, add, multiply, partitionSelect, compare, isInteger })
17+
18+
return typed('quantileSeq', {
19+
'Array|Matrix, number|BigNumber|Array, number': (arr, prob, dim) => quantileSeq(arr, prob, dimToZeroBase(dim)),
20+
'Array|Matrix, number|BigNumber|Array, boolean, number': (arr, prob, sorted, dim) => quantileSeq(arr, prob, sorted, dimToZeroBase(dim))
21+
})
22+
23+
function dimToZeroBase (dim) {
24+
// TODO: find a better way, maybe lastDimToZeroBase could apply to more cases.
25+
return lastDimToZeroBase([[], dim])[1]
26+
}
27+
}, { isTransformFunction: true })

src/factoriesAny.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,5 +352,6 @@ export { createConcatTransform } from './expression/transform/concat.transform.j
352352
export { createDiffTransform } from './expression/transform/diff.transform.js'
353353
export { createStdTransform } from './expression/transform/std.transform.js'
354354
export { createSumTransform } from './expression/transform/sum.transform.js'
355+
export { createQuantileSeqTransform } from './expression/transform/quantileSeq.transform.js'
355356
export { createCumSumTransform } from './expression/transform/cumsum.transform.js'
356357
export { createVarianceTransform } from './expression/transform/variance.transform.js'

src/function/statistics/quantileSeq.js

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import { isBigNumber, isCollection, isNumber } from '../../utils/is.js'
2-
import { isInteger } from '../../utils/number.js'
32
import { flatten } from '../../utils/array.js'
43
import { factory } from '../../utils/factory.js'
4+
import { createApply } from '../matrix/apply.js'
55

66
const name = 'quantileSeq'
7-
const dependencies = ['typed', 'add', 'multiply', 'partitionSelect', 'compare']
7+
const dependencies = ['typed', 'add', 'multiply', 'partitionSelect', 'compare', 'isInteger']
88

9-
export const createQuantileSeq = /* #__PURE__ */ factory(name, dependencies, ({ typed, add, multiply, partitionSelect, compare }) => {
9+
export const createQuantileSeq = /* #__PURE__ */ factory(name, dependencies, ({ typed, add, multiply, partitionSelect, compare, isInteger }) => {
1010
/**
1111
* Compute the prob order quantile of a matrix or a list with values.
1212
* The sequence is sorted and the middle value is returned.
@@ -41,6 +41,32 @@ export const createQuantileSeq = /* #__PURE__ */ factory(name, dependencies, ({
4141
* @param {Boolean} sorted=false is data sorted in ascending order
4242
* @return {Number, BigNumber, Unit, Array} Quantile(s)
4343
*/
44+
45+
const apply = createApply({ typed, isInteger })
46+
/**
47+
* Check if array value types are valid, throw error otherwise.
48+
* @param {number | BigNumber | Unit} x
49+
* @param {number | BigNumber | Unit} x
50+
* @private
51+
*/
52+
const validate = typed({
53+
'number | BigNumber | Unit': function (x) {
54+
return x
55+
}
56+
})
57+
58+
return typed(name, {
59+
'Array|Matrix, number|BigNumber|Array': (data, prob) => quantileSeq(data, prob, false),
60+
'Array|Matrix, number|BigNumber|Array, boolean': quantileSeq,
61+
'Array|Matrix, number|BigNumber|Array, number': (data, prob, dim) => _quantileSeqDim(data, prob, false, dim),
62+
'Array|Matrix, number|BigNumber|Array, boolean, number': (data, prob, sorted, dim) => _quantileSeqDim(data, prob, sorted, dim)
63+
})
64+
65+
function _quantileSeqDim (data, prob, sorted, dim) {
66+
// return [1.3, 1.2]
67+
return apply(data, dim, x => quantileSeq(x, prob, sorted))
68+
}
69+
4470
function quantileSeq (data, probOrN, sorted) {
4571
let probArr, dataArr, one
4672

@@ -238,18 +264,4 @@ export const createQuantileSeq = /* #__PURE__ */ factory(name, dependencies, ({
238264
const one = new fracPart.constructor(1)
239265
return add(multiply(left, one.minus(fracPart)), multiply(right, fracPart))
240266
}
241-
242-
/**
243-
* Check if array value types are valid, throw error otherwise.
244-
* @param {number | BigNumber | Unit} x
245-
* @param {number | BigNumber | Unit} x
246-
* @private
247-
*/
248-
const validate = typed({
249-
'number | BigNumber | Unit': function (x) {
250-
return x
251-
}
252-
})
253-
254-
return quantileSeq
255267
})

test/unit-tests/function/statistics/quantileSeq.test.js

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,40 @@ describe('quantileSeq', function () {
2323
assert.strictEqual(quantileSeq(lst, 1), 3.7)
2424
})
2525

26+
it('should return the quantileSeq from a multidimensional array in the specified dimension', function () {
27+
const arr = [
28+
[3.7, 2.7, 3.3, 1.3, 2.2, 3.1],
29+
[3.8, 2.5, 3.2, 1.2, 3.2, 4.1]
30+
]
31+
assert.deepStrictEqual(quantileSeq(arr, 0, 1), [1.3, 1.2])
32+
assert.deepStrictEqual(quantileSeq(arr, 0.25, 1), [2.325, 2.675])
33+
assert.deepStrictEqual(quantileSeq(arr, 0.5, 1), [2.9000000000000004, 3.2])
34+
assert.deepStrictEqual(quantileSeq(arr, 0.75, 1), [3.2499999999999996, 3.6499999999999995])
35+
assert.deepStrictEqual(quantileSeq(arr, 1, 1), [3.7, 4.1])
36+
assert.deepStrictEqual(quantileSeq(arr, 0, false, 1), [1.3, 1.2])
37+
assert.deepStrictEqual(quantileSeq(arr, 0.25, false, 1), [2.325, 2.675])
38+
assert.deepStrictEqual(quantileSeq(arr, 0.5, false, 1), [2.9000000000000004, 3.2])
39+
assert.deepStrictEqual(quantileSeq(arr, 0.75, false, 1), [3.2499999999999996, 3.6499999999999995])
40+
assert.deepStrictEqual(quantileSeq(arr, 1, false, 1), [3.7, 4.1])
41+
})
42+
43+
it('should return the quantileSeq from a multidimensional array in the specified dimension in the parser', function () {
44+
const arr = [
45+
[3.7, 2.7, 3.3, 1.3, 2.2, 3.1],
46+
[3.8, 2.5, 3.2, 1.2, 3.2, 4.1]
47+
]
48+
assert.deepStrictEqual(math.evaluate('quantileSeq(arr, 0, 2)', { arr }), [1.3, 1.2])
49+
assert.deepStrictEqual(quantileSeq(arr, 0.25, 1), [2.325, 2.675])
50+
assert.deepStrictEqual(quantileSeq(arr, 0.5, 1), [2.9000000000000004, 3.2])
51+
assert.deepStrictEqual(quantileSeq(arr, 0.75, 1), [3.2499999999999996, 3.6499999999999995])
52+
assert.deepStrictEqual(quantileSeq(arr, 1, 1), [3.7, 4.1])
53+
assert.deepStrictEqual(quantileSeq(arr, 0, false, 1), [1.3, 1.2])
54+
assert.deepStrictEqual(quantileSeq(arr, 0.25, false, 1), [2.325, 2.675])
55+
assert.deepStrictEqual(quantileSeq(arr, 0.5, false, 1), [2.9000000000000004, 3.2])
56+
assert.deepStrictEqual(quantileSeq(arr, 0.75, false, 1), [3.2499999999999996, 3.6499999999999995])
57+
assert.deepStrictEqual(quantileSeq(arr, 1, false, 1), [3.7, 4.1])
58+
})
59+
2660
it('should return the quantileSeq from an ascending array with number probability', function () {
2761
const lst = [1.3, 2.2, 2.7, 3.1, 3.3, 3.7]
2862
assert.strictEqual(quantileSeq(lst, 0, true), 1.3)
@@ -78,7 +112,7 @@ describe('quantileSeq', function () {
78112
assert.deepStrictEqual(quantileSeq([math.unit('5mm'), math.unit('15mm'), math.unit('10mm')], 0.5), math.unit('10mm'))
79113
})
80114

81-
it('should return the quantileSeq from an 1d matrix', function () {
115+
it('should return the quantileSeq from a 1d matrix', function () {
82116
assert.strictEqual(quantileSeq(math.matrix([2, 4, 6, 8, 10, 12, 14]), 0.25), 5)
83117
})
84118

@@ -151,9 +185,9 @@ describe('quantileSeq', function () {
151185
})
152186

153187
it('should throw an error if called with invalid number of arguments', function () {
154-
assert.throws(function () { quantileSeq() }, SyntaxError)
155-
assert.throws(function () { quantileSeq(2) }, SyntaxError)
156-
assert.throws(function () { quantileSeq([], 2, 3, 1) }, SyntaxError)
188+
assert.throws(function () { quantileSeq() }, TypeError)
189+
assert.throws(function () { quantileSeq(2) }, TypeError)
190+
assert.throws(function () { quantileSeq([], 2, 3, 1) }, TypeError)
157191
})
158192

159193
it('should throw an error if called with unsupported type of arguments', function () {

0 commit comments

Comments
 (0)