Skip to content

Commit

Permalink
Extend quantileSeq with support for a dimension (#3002)
Browse files Browse the repository at this point in the history
* 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]>
  • Loading branch information
3 people authored Aug 23, 2023
1 parent 49c793b commit 3ab9bc1
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 21 deletions.
27 changes: 27 additions & 0 deletions src/expression/transform/quantileSeq.transform.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { factory } from '../../utils/factory.js'
import { createQuantileSeq } from '../../function/statistics/quantileSeq.js'
import { lastDimToZeroBase } from './utils/lastDimToZeroBase.js'

const name = 'quantileSeq'
const dependencies = ['typed', 'add', 'multiply', 'partitionSelect', 'compare', 'isInteger']

/**
* Attach a transform function to math.quantileSeq
* Adds a property transform containing the transform function.
*
* This transform changed the `dim` parameter of function std
* from one-based to zero based
*/
export const createQuantileSeqTransform = /* #__PURE__ */ factory(name, dependencies, ({ typed, add, multiply, partitionSelect, compare, isInteger }) => {
const quantileSeq = createQuantileSeq({ typed, add, multiply, partitionSelect, compare, isInteger })

return typed('quantileSeq', {
'Array|Matrix, number|BigNumber|Array, number': (arr, prob, dim) => quantileSeq(arr, prob, dimToZeroBase(dim)),
'Array|Matrix, number|BigNumber|Array, boolean, number': (arr, prob, sorted, dim) => quantileSeq(arr, prob, sorted, dimToZeroBase(dim))
})

function dimToZeroBase (dim) {
// TODO: find a better way, maybe lastDimToZeroBase could apply to more cases.
return lastDimToZeroBase([[], dim])[1]
}
}, { isTransformFunction: true })
1 change: 1 addition & 0 deletions src/factoriesAny.js
Original file line number Diff line number Diff line change
Expand Up @@ -352,5 +352,6 @@ export { createConcatTransform } from './expression/transform/concat.transform.j
export { createDiffTransform } from './expression/transform/diff.transform.js'
export { createStdTransform } from './expression/transform/std.transform.js'
export { createSumTransform } from './expression/transform/sum.transform.js'
export { createQuantileSeqTransform } from './expression/transform/quantileSeq.transform.js'
export { createCumSumTransform } from './expression/transform/cumsum.transform.js'
export { createVarianceTransform } from './expression/transform/variance.transform.js'
46 changes: 29 additions & 17 deletions src/function/statistics/quantileSeq.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { isBigNumber, isCollection, isNumber } from '../../utils/is.js'
import { isInteger } from '../../utils/number.js'
import { flatten } from '../../utils/array.js'
import { factory } from '../../utils/factory.js'
import { createApply } from '../matrix/apply.js'

const name = 'quantileSeq'
const dependencies = ['typed', 'add', 'multiply', 'partitionSelect', 'compare']
const dependencies = ['typed', 'add', 'multiply', 'partitionSelect', 'compare', 'isInteger']

export const createQuantileSeq = /* #__PURE__ */ factory(name, dependencies, ({ typed, add, multiply, partitionSelect, compare }) => {
export const createQuantileSeq = /* #__PURE__ */ factory(name, dependencies, ({ typed, add, multiply, partitionSelect, compare, isInteger }) => {
/**
* Compute the prob order quantile of a matrix or a list with values.
* The sequence is sorted and the middle value is returned.
Expand Down Expand Up @@ -41,6 +41,32 @@ export const createQuantileSeq = /* #__PURE__ */ factory(name, dependencies, ({
* @param {Boolean} sorted=false is data sorted in ascending order
* @return {Number, BigNumber, Unit, Array} Quantile(s)
*/

const apply = createApply({ typed, isInteger })
/**
* Check if array value types are valid, throw error otherwise.
* @param {number | BigNumber | Unit} x
* @param {number | BigNumber | Unit} x
* @private
*/
const validate = typed({
'number | BigNumber | Unit': function (x) {
return x
}
})

return typed(name, {
'Array|Matrix, number|BigNumber|Array': (data, prob) => quantileSeq(data, prob, false),
'Array|Matrix, number|BigNumber|Array, boolean': quantileSeq,
'Array|Matrix, number|BigNumber|Array, number': (data, prob, dim) => _quantileSeqDim(data, prob, false, dim),
'Array|Matrix, number|BigNumber|Array, boolean, number': (data, prob, sorted, dim) => _quantileSeqDim(data, prob, sorted, dim)
})

function _quantileSeqDim (data, prob, sorted, dim) {
// return [1.3, 1.2]
return apply(data, dim, x => quantileSeq(x, prob, sorted))
}

function quantileSeq (data, probOrN, sorted) {
let probArr, dataArr, one

Expand Down Expand Up @@ -238,18 +264,4 @@ export const createQuantileSeq = /* #__PURE__ */ factory(name, dependencies, ({
const one = new fracPart.constructor(1)
return add(multiply(left, one.minus(fracPart)), multiply(right, fracPart))
}

/**
* Check if array value types are valid, throw error otherwise.
* @param {number | BigNumber | Unit} x
* @param {number | BigNumber | Unit} x
* @private
*/
const validate = typed({
'number | BigNumber | Unit': function (x) {
return x
}
})

return quantileSeq
})
42 changes: 38 additions & 4 deletions test/unit-tests/function/statistics/quantileSeq.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,40 @@ describe('quantileSeq', function () {
assert.strictEqual(quantileSeq(lst, 1), 3.7)
})

it('should return the quantileSeq from a multidimensional array in the specified dimension', function () {
const arr = [
[3.7, 2.7, 3.3, 1.3, 2.2, 3.1],
[3.8, 2.5, 3.2, 1.2, 3.2, 4.1]
]
assert.deepStrictEqual(quantileSeq(arr, 0, 1), [1.3, 1.2])
assert.deepStrictEqual(quantileSeq(arr, 0.25, 1), [2.325, 2.675])
assert.deepStrictEqual(quantileSeq(arr, 0.5, 1), [2.9000000000000004, 3.2])
assert.deepStrictEqual(quantileSeq(arr, 0.75, 1), [3.2499999999999996, 3.6499999999999995])
assert.deepStrictEqual(quantileSeq(arr, 1, 1), [3.7, 4.1])
assert.deepStrictEqual(quantileSeq(arr, 0, false, 1), [1.3, 1.2])
assert.deepStrictEqual(quantileSeq(arr, 0.25, false, 1), [2.325, 2.675])
assert.deepStrictEqual(quantileSeq(arr, 0.5, false, 1), [2.9000000000000004, 3.2])
assert.deepStrictEqual(quantileSeq(arr, 0.75, false, 1), [3.2499999999999996, 3.6499999999999995])
assert.deepStrictEqual(quantileSeq(arr, 1, false, 1), [3.7, 4.1])
})

it('should return the quantileSeq from a multidimensional array in the specified dimension in the parser', function () {
const arr = [
[3.7, 2.7, 3.3, 1.3, 2.2, 3.1],
[3.8, 2.5, 3.2, 1.2, 3.2, 4.1]
]
assert.deepStrictEqual(math.evaluate('quantileSeq(arr, 0, 2)', { arr }), [1.3, 1.2])
assert.deepStrictEqual(quantileSeq(arr, 0.25, 1), [2.325, 2.675])
assert.deepStrictEqual(quantileSeq(arr, 0.5, 1), [2.9000000000000004, 3.2])
assert.deepStrictEqual(quantileSeq(arr, 0.75, 1), [3.2499999999999996, 3.6499999999999995])
assert.deepStrictEqual(quantileSeq(arr, 1, 1), [3.7, 4.1])
assert.deepStrictEqual(quantileSeq(arr, 0, false, 1), [1.3, 1.2])
assert.deepStrictEqual(quantileSeq(arr, 0.25, false, 1), [2.325, 2.675])
assert.deepStrictEqual(quantileSeq(arr, 0.5, false, 1), [2.9000000000000004, 3.2])
assert.deepStrictEqual(quantileSeq(arr, 0.75, false, 1), [3.2499999999999996, 3.6499999999999995])
assert.deepStrictEqual(quantileSeq(arr, 1, false, 1), [3.7, 4.1])
})

it('should return the quantileSeq from an ascending array with number probability', function () {
const lst = [1.3, 2.2, 2.7, 3.1, 3.3, 3.7]
assert.strictEqual(quantileSeq(lst, 0, true), 1.3)
Expand Down Expand Up @@ -78,7 +112,7 @@ describe('quantileSeq', function () {
assert.deepStrictEqual(quantileSeq([math.unit('5mm'), math.unit('15mm'), math.unit('10mm')], 0.5), math.unit('10mm'))
})

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

Expand Down Expand Up @@ -151,9 +185,9 @@ describe('quantileSeq', function () {
})

it('should throw an error if called with invalid number of arguments', function () {
assert.throws(function () { quantileSeq() }, SyntaxError)
assert.throws(function () { quantileSeq(2) }, SyntaxError)
assert.throws(function () { quantileSeq([], 2, 3, 1) }, SyntaxError)
assert.throws(function () { quantileSeq() }, TypeError)
assert.throws(function () { quantileSeq(2) }, TypeError)
assert.throws(function () { quantileSeq([], 2, 3, 1) }, TypeError)
})

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

0 comments on commit 3ab9bc1

Please sign in to comment.